Skip to content

Commit

Permalink
Draft: remove old DraftFillet class, and make it a redirect
Browse files Browse the repository at this point in the history
Remove the make function that creates the old object,
its corresponding Gui Command, and the old `DraftFillet.Fillet`
proxy class, which now is a redirection to the new `Fillet`
class defined in `draftobjects.fillet`.

Also change the unit test, and the `draft_test_object` script
to run `Draft.make_fillet`.
  • Loading branch information
vocx-fc authored and yorikvanhavre committed May 13, 2020
1 parent 68e6d8d commit d438aec
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 332 deletions.
4 changes: 0 additions & 4 deletions src/Mod/Draft/Draft.py
Expand Up @@ -76,10 +76,6 @@
from DraftLayer import ViewProviderLayer as _ViewProviderVisGroup
from DraftLayer import makeLayer

# import DraftFillet
# Fillet = DraftFillet.Fillet
# makeFillet = DraftFillet.makeFillet

# ---------------------------------------------------------------------------
# General functions
# ---------------------------------------------------------------------------
Expand Down
377 changes: 67 additions & 310 deletions src/Mod/Draft/DraftFillet.py
@@ -1,319 +1,76 @@
"""This module provides the Draft fillet tool.
# ***************************************************************************
# * Copyright (c) 2020 Eliud Cabrera Castillo <e.cabrera-castillo@tum.de> *
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU Lesser General Public License (LGPL) *
# * as published by the Free Software Foundation; either version 2 of *
# * the License, or (at your option) any later version. *
# * for detail see the LICENCE text file. *
# * *
# * This program is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU Library General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with this program; if not, write to the Free Software *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
# * USA *
# * *
# ***************************************************************************
"""Provides the Fillet class for objects created with a prototype version.
The original Fillet object and Gui Command was introduced
in the development cycle of 0.19, in commit d5ca09c77b, 2019-08-22.
However, when this class was implemented, the reorganization
of the workbench was not advanced.
When the reorganization was on its way it was clear that this tool
also needed to be broken into different modules; however, this was done
only at the end of the reorganization.
In commit 01df7c0a63, 2020-02-10, the Gui Command was removed from
the graphical interface so that the user cannot create this object
graphically any more. The object class was still kept
so that previous objects created between August 2019 and February 2020
would open correctly.
Now in this module the older class is redirected to the new class
in order to migrate the object.
A new Gui Command in `draftguitools` and new make function in `draftmake`
are now used to create `Fillet` objects. Therefore, this module
is only required to migrate old objects created in that time
with the 0.19 development version.
Since this module is only used to migrate older objects, it is only temporary,
and will be removed after one year of the original introduction of the tool,
that is, in August 2020.
"""
## @package DraftFillet
# \ingroup DRAFT
# \brief This module provides the Draft fillet tool.
# \brief Provides Fillet class for objects created with a prototype version.
#
# This module is only required to migrate old objects created
# from August 2019 to February 2020. It will be removed definitely
# in August 2020, as the new Fillet object should be available.

import FreeCAD
from FreeCAD import Console as FCC
import Draft
import DraftGeomUtils
import Part
import draftobjects.fillet

if FreeCAD.GuiUp:
import FreeCADGui
from PySide.QtCore import QT_TRANSLATE_NOOP
from PySide import QtCore
import DraftTools
import draftguitools.gui_trackers as trackers
from DraftGui import translate
else:
def QT_TRANSLATE_NOOP(context, text):
return text
# -----------------------------------------------------------------------------
# Removed definitions
# def _extract_edges(objs):

def translate(context, text):
return text
# def makeFillet(objs, radius=100, chamfer=False, delete=False):

# class Fillet(Draft._DraftObject):

def _extract_edges(objs):
"""Extract the edges from the given objects (Draft lines or Edges).
# class CommandFillet(DraftTools.Creator):
# -----------------------------------------------------------------------------

objs : list of Draft Lines or Part.Edges
The list of edges from which to create the fillet.
"""
o1, o2 = objs
if hasattr(o1, "PropertiesList"):
if "Proxy" in o1.PropertiesList:
if hasattr(o1.Proxy, "Type"):
if o1.Proxy.Type in ("Wire", "Fillet"):
e1 = o1.Shape.Edges[0]
elif "Shape" in o1.PropertiesList:
if o1.Shape.ShapeType in ("Wire", "Edge"):
e1 = o1.Shape
elif hasattr(o1, "ShapeType"):
if o1.ShapeType in "Edge":
e1 = o1

if hasattr(o1, "Label"):
FCC.PrintMessage("o1: " + o1.Label)
else:
FCC.PrintMessage("o1: 1")
FCC.PrintMessage(", length: " + str(e1.Length) + "\n")

if hasattr(o2, "PropertiesList"):
if "Proxy" in o2.PropertiesList:
if hasattr(o2.Proxy, "Type"):
if o2.Proxy.Type in ("Wire", "Fillet"):
e2 = o2.Shape.Edges[0]
elif "Shape" in o2.PropertiesList:
if o2.Shape.ShapeType in ("Wire", "Edge"):
e2 = o2.Shape
elif hasattr(o2, "ShapeType"):
if o2.ShapeType in "Edge":
e2 = o2

if hasattr(o2, "Label"):
FCC.PrintMessage("o2: " + o2.Label)
else:
FCC.PrintMessage("o2: 2")
FCC.PrintMessage(", length: " + str(e2.Length) + "\n")

return e1, e2


def makeFillet(objs, radius=100, chamfer=False, delete=False):
"""Create a fillet between two lines or edges.
Parameters
----------
objs : list
List of two objects of type wire, or edges.
radius : float, optional
It defaults to 100 mm. The curvature of the fillet.
chamfer : bool, optional
It defaults to `False`. If it is `True` it no longer produces
a rounded fillet but a chamfer (straight edge)
with the value of the `radius`.
delete : bool, optional
It defaults to `False`. If it is `True` it will delete
the pair of objects that are used to create the fillet.
Otherwise, the original objects will still be there.
Returns
-------
Part::Part2DObject
The object of type `'Fillet'`.
It returns `None` if it fails producing the object.
"""
if len(objs) != 2:
FCC.PrintError("makeFillet: "
+ translate("draft", "two elements needed") + "\n")
return None

e1, e2 = _extract_edges(objs)

edges = DraftGeomUtils.fillet([e1, e2], radius, chamfer)
if len(edges) < 3:
FCC.PrintError("makeFillet: "
+ translate("draft", "radius too large"))
FCC.PrintError(", r=" + str(radius) + "\n")
return None

_d = translate("draft", "length: ")
FCC.PrintMessage("e1, " + _d + str(edges[0].Length) + "\n")
FCC.PrintMessage("e2, " + _d + str(edges[1].Length) + "\n")
FCC.PrintMessage("e3, " + _d + str(edges[2].Length) + "\n")

try:
wire = Part.Wire(edges)
except Part.OCCError:
return None

obj = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython",
"Fillet")
Fillet(obj)
obj.Shape = wire
obj.Length = wire.Length
obj.Start = wire.Vertexes[0].Point
obj.End = wire.Vertexes[-1].Point
obj.FilletRadius = radius

if delete:
FreeCAD.ActiveDocument.removeObject(objs[0].Name)
FreeCAD.ActiveDocument.removeObject(objs[1].Name)
_r = translate("draft", "removed original objects")
FCC.PrintMessage("makeFillet: " + _r + "\n")
if FreeCAD.GuiUp:
Draft._ViewProviderWire(obj.ViewObject)
Draft.formatObject(obj)
Draft.select(obj)
return obj


class Fillet(Draft._DraftObject):
"""The fillet object"""

def __init__(self, obj):
Draft._DraftObject.__init__(self, obj, "Fillet")
obj.addProperty("App::PropertyVectorDistance", "Start", "Draft", QT_TRANSLATE_NOOP("App::Property", "The start point of this line"))
obj.addProperty("App::PropertyVectorDistance", "End", "Draft", QT_TRANSLATE_NOOP("App::Property", "The end point of this line"))
obj.addProperty("App::PropertyLength", "Length", "Draft", QT_TRANSLATE_NOOP("App::Property", "The length of this line"))
obj.addProperty("App::PropertyLength", "FilletRadius", "Draft", QT_TRANSLATE_NOOP("App::Property", "Radius to use to fillet the corners"))
obj.setEditorMode("Start", 1)
obj.setEditorMode("End", 1)
obj.setEditorMode("Length", 1)
# Change to 0 to make it editable
obj.setEditorMode("FilletRadius", 1)

def execute(self, obj):
if hasattr(obj, "Length"):
obj.Length = obj.Shape.Length
if hasattr(obj, "Start"):
obj.Start = obj.Shape.Vertexes[0].Point
if hasattr(obj, "End"):
obj.End = obj.Shape.Vertexes[-1].Point

def onChanged(self, obj, prop):
# Change the radius of fillet. NOT IMPLEMENTED.
if prop in "FilletRadius":
pass


class CommandFillet(DraftTools.Creator):
"""The Fillet GUI command definition"""

def __init__(self):
DraftTools.Creator.__init__(self)
self.featureName = "Fillet"

def GetResources(self):
return {'Pixmap': 'Draft_Fillet.svg',
'MenuText': QT_TRANSLATE_NOOP("draft", "Fillet"),
'ToolTip': QT_TRANSLATE_NOOP("draft", "Creates a fillet between two wires or edges.")
}

def Activated(self, name=translate("draft", "Fillet")):
DraftTools.Creator.Activated(self, name)
if not self.doc:
FCC.PrintWarning(translate("draft", "No active document") + "\n")
return
if self.ui:
self.rad = 100
self.chamfer = False
self.delete = False
label = translate("draft", "Fillet radius")
tooltip = translate("draft", "Radius of fillet")

# Call the Task panel for a radius
# The graphical widgets are defined in DraftGui
self.ui.taskUi(title=name, icon="Draft_Fillet")
self.ui.radiusUi()
self.ui.sourceCmd = self
self.ui.labelRadius.setText(label)
self.ui.radiusValue.setToolTip(tooltip)
self.ui.setRadiusValue(self.rad, "Length")
self.ui.check_delete = self.ui._checkbox("isdelete",
self.ui.layout,
checked=self.delete)
self.ui.check_delete.setText(translate("draft",
"Delete original objects"))
self.ui.check_delete.show()
self.ui.check_chamfer = self.ui._checkbox("ischamfer",
self.ui.layout,
checked=self.chamfer)
self.ui.check_chamfer.setText(translate("draft",
"Create chamfer"))
self.ui.check_chamfer.show()

QtCore.QObject.connect(self.ui.check_delete,
QtCore.SIGNAL("stateChanged(int)"),
self.set_delete)
QtCore.QObject.connect(self.ui.check_chamfer,
QtCore.SIGNAL("stateChanged(int)"),
self.set_chamfer)
self.linetrack = trackers.lineTracker(dotted=True)
self.arctrack = trackers.arcTracker()
# self.call = self.view.addEventCallback("SoEvent", self.action)
FCC.PrintMessage(translate("draft", "Enter radius") + "\n")

def action(self, arg):
"""Scene event handler. CURRENTLY NOT USED.
Here the displaying of the trackers (previews)
should be implemented by considering the current value of the
`ui.radiusValue`.
"""
if arg["Type"] == "SoKeyboardEvent":
if arg["Key"] == "ESCAPE":
self.finish()
elif arg["Type"] == "SoLocation2Event":
self.point, ctrlPoint, info = DraftTools.getPoint(self, arg)
DraftTools.redraw3DView()

def set_delete(self):
"""This function is called when the delete checkbox changes"""
self.delete = self.ui.check_delete.isChecked()
FCC.PrintMessage(translate("draft", "Delete original objects: ")
+ str(self.delete) + "\n")

def set_chamfer(self):
"""This function is called when the chamfer checkbox changes"""
self.chamfer = self.ui.check_chamfer.isChecked()
FCC.PrintMessage(translate("draft", "Chamfer mode: ")
+ str(self.chamfer) + "\n")

def numericRadius(self, rad):
"""This function is called when a valid radius is entered"""
self.rad = rad
self.draw_arc(rad, self.chamfer, self.delete)
self.finish()

def draw_arc(self, rad, chamfer, delete):
"""Processes the selection and draws the actual object"""
wires = FreeCADGui.Selection.getSelection()
_two = translate("draft", "two elements needed")
if not wires:
FCC.PrintError("CommandFillet: " + _two + "\n")
return
if len(wires) != 2:
FCC.PrintError("CommandFillet: " + _two + "\n")
return

for o in wires:
FCC.PrintMessage("CommandFillet: " + Draft.getType(o) + "\n")

_test = translate("draft", "Test object")
_test_off = translate("draft", "Test object removed")
_cant = translate("draft", "fillet cannot be created")

FCC.PrintMessage(4*"=" + _test + "\n")
arc = makeFillet(wires, rad)
if not arc:
FCC.PrintError("CommandFillet: " + _cant + "\n")
return
self.doc.removeObject(arc.Name)
FCC.PrintMessage(4*"=" + _test_off + "\n")

doc = 'FreeCAD.ActiveDocument.'
_wires = '[' + doc + wires[0].Name + ', ' + doc + wires[1].Name + ']'

FreeCADGui.addModule("DraftFillet")
name = translate("draft", "Create fillet")

args = _wires + ', radius=' + str(rad)
if chamfer:
args += ', chamfer=' + str(chamfer)
if delete:
args += ', delete=' + str(delete)
func = ['arc = DraftFillet.makeFillet(' + args + ')']
func.append('Draft.autogroup(arc)')

# Here we could remove the old objects, but the makeFillet()
# command already includes an option to remove them.
# Therefore, the following is not necessary
# rems = [doc + 'removeObject("' + o.Name + '")' for o in wires]
# func.extend(rems)
func.append('FreeCAD.ActiveDocument.recompute()')
self.commit(name, func)

def finish(self, close=False):
"""Terminates the operation."""
DraftTools.Creator.finish(self)
if self.ui:
self.linetrack.finalize()
self.arctrack.finalize()
self.doc.recompute()


if FreeCAD.GuiUp:
FreeCADGui.addCommand('Draft_Fillet', CommandFillet())
# When an old object is opened it will reconstruct the object
# by searching for the class `DraftFillet.Fillet`.
# So we redirect this class to the new class in the new module.
# This migrates the old object to the new object.
Fillet = draftobjects.fillet.Fillet

0 comments on commit d438aec

Please sign in to comment.