Draft: remove old DraftFillet class, and make it a redirect

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`.
This commit is contained in:
vocx-fc
2020-05-04 22:03:36 -05:00
committed by Yorik van Havre
parent 103533de73
commit 7ff41b51a9
6 changed files with 73 additions and 332 deletions

View File

@@ -76,10 +76,6 @@ from DraftLayer import Layer as _VisGroup
from DraftLayer import ViewProviderLayer as _ViewProviderVisGroup
from DraftLayer import makeLayer
# import DraftFillet
# Fillet = DraftFillet.Fillet
# makeFillet = DraftFillet.makeFillet
# ---------------------------------------------------------------------------
# General functions
# ---------------------------------------------------------------------------

View File

@@ -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

View File

@@ -201,4 +201,4 @@ class Fillet(gui_base_original.Creator):
self.doc.recompute()
Gui.addCommand('Draft_Fillet_new', Fillet())
Gui.addCommand('Draft_Fillet', Fillet())

View File

@@ -35,11 +35,11 @@ import math
import FreeCAD as App
import Draft
from FreeCAD import Vector
from draftutils.messages import _msg, _wrn
from FreeCAD import Vector
if App.GuiUp:
import DraftFillet
import FreeCADGui as Gui
@@ -141,13 +141,7 @@ def create_test_file(file_name="draft_test_objects",
line_h_2.ViewObject.DrawStyle = "Dotted"
App.ActiveDocument.recompute()
try:
DraftFillet.makeFillet([line_h_1, line_h_2], 400)
except Exception:
_wrn("Fillet could not be created")
_wrn("Possible cause: at this moment it may need the interface")
rect = Draft.makeRectangle(500, 100)
rect.Placement.Base = Vector(14000, 500)
Draft.make_fillet([line_h_1, line_h_2], 400)
t_xpos += 900
_t = Draft.makeText(["Fillet"], Vector(t_xpos, t_ypos, 0))

View File

@@ -88,16 +88,10 @@ class DraftCreation(unittest.TestCase):
L2 = Draft.makeLine(b, c)
self.doc.recompute()
if not App.GuiUp:
aux._no_gui("DraftFillet")
self.assertTrue(True)
return
import DraftFillet
radius = 4
_msg(" Fillet")
_msg(" radius={}".format(radius))
obj = DraftFillet.makeFillet([L1, L2], radius)
obj = Draft.make_fillet([L1, L2], radius)
self.assertTrue(obj, "'{}' failed".format(operation))
def test_circle(self):

View File

@@ -38,7 +38,7 @@ from PySide.QtCore import QT_TRANSLATE_NOOP
def get_draft_drawing_commands():
"""Return the drawing commands list."""
return ["Draft_Line", "Draft_Wire", "Draft_Fillet", "Draft_Fillet_new",
return ["Draft_Line", "Draft_Wire", "Draft_Fillet",
"Draft_ArcTools",
"Draft_Circle", "Draft_Ellipse", "Draft_Rectangle",
"Draft_Polygon", "Draft_BSpline", "Draft_BezierTools",