diff --git a/src/Mod/Draft/CMakeLists.txt b/src/Mod/Draft/CMakeLists.txt index fe4611298c..23dd1c9f9b 100644 --- a/src/Mod/Draft/CMakeLists.txt +++ b/src/Mod/Draft/CMakeLists.txt @@ -90,6 +90,7 @@ SET(Creator_tools draftguitools/gui_rectangles.py draftguitools/gui_arcs.py draftguitools/gui_circles.py + draftguitools/gui_polygons.py ) SET(Draft_GUI_tools diff --git a/src/Mod/Draft/DraftTools.py b/src/Mod/Draft/DraftTools.py index 94d3fee2ee..c5cbaab806 100644 --- a/src/Mod/Draft/DraftTools.py +++ b/src/Mod/Draft/DraftTools.py @@ -159,193 +159,7 @@ from draftguitools.gui_rectangles import Rectangle from draftguitools.gui_arcs import Arc from draftguitools.gui_arcs import Draft_Arc_3Points from draftguitools.gui_circles import Circle - - -class Polygon(Creator): - """the Draft_Polygon FreeCAD command definition""" - - def GetResources(self): - return {'Pixmap' : 'Draft_Polygon', - 'Accel' : "P, G", - 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Polygon", "Polygon"), - 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_Polygon", "Creates a regular polygon. CTRL to snap, SHIFT to constrain")} - - def Activated(self): - name = translate("draft","Polygon") - Creator.Activated(self,name) - if self.ui: - self.step = 0 - self.center = None - self.rad = None - self.tangents = [] - self.tanpoints = [] - self.ui.pointUi(name) - self.ui.extUi() - self.ui.numFaces.show() - self.ui.numFacesLabel.show() - self.altdown = False - self.ui.sourceCmd = self - self.arctrack = trackers.arcTracker() - self.call = self.view.addEventCallback("SoEvent",self.action) - FreeCAD.Console.PrintMessage(translate("draft", "Pick center point")+"\n") - - def finish(self,closed=False,cont=False): - """finishes the arc""" - Creator.finish(self) - if self.ui: - self.arctrack.finalize() - self.doc.recompute() - if self.ui.continueMode: - self.Activated() - - def action(self,arg): - """scene event handler""" - import DraftGeomUtils - if arg["Type"] == "SoKeyboardEvent": - if arg["Key"] == "ESCAPE": - self.finish() - elif arg["Type"] == "SoLocation2Event": - self.point,ctrlPoint,info = getPoint(self,arg) - # this is to make sure radius is what you see on screen - if self.center and DraftVecUtils.dist(self.point,self.center) > 0: - viewdelta = DraftVecUtils.project(self.point.sub(self.center), plane.axis) - if not DraftVecUtils.isNull(viewdelta): - self.point = self.point.add(viewdelta.negative()) - if (self.step == 0): # choose center - if hasMod(arg,MODALT): - if not self.altdown: - self.altdown = True - self.ui.switchUi(True) - else: - if self.altdown: - self.altdown = False - self.ui.switchUi(False) - else: # choose radius - if len(self.tangents) == 2: - cir = DraftGeomUtils.circleFrom2tan1pt(self.tangents[0], self.tangents[1], self.point) - self.center = DraftGeomUtils.findClosestCircle(self.point,cir).Center - self.arctrack.setCenter(self.center) - elif self.tangents and self.tanpoints: - cir = DraftGeomUtils.circleFrom1tan2pt(self.tangents[0], self.tanpoints[0], self.point) - self.center = DraftGeomUtils.findClosestCircle(self.point,cir).Center - self.arctrack.setCenter(self.center) - if hasMod(arg,MODALT): - if not self.altdown: - self.altdown = True - snapped = self.view.getObjectInfo((arg["Position"][0],arg["Position"][1])) - if snapped: - ob = self.doc.getObject(snapped['Object']) - num = int(snapped['Component'].lstrip('Edge'))-1 - ed = ob.Shape.Edges[num] - if len(self.tangents) == 2: - cir = DraftGeomUtils.circleFrom3tan(self.tangents[0], self.tangents[1], ed) - cl = DraftGeomUtils.findClosestCircle(self.point,cir) - self.center = cl.Center - self.rad = cl.Radius - self.arctrack.setCenter(self.center) - else: - self.rad = self.center.add(DraftGeomUtils.findDistance(self.center,ed).sub(self.center)).Length - else: - self.rad = DraftVecUtils.dist(self.point,self.center) - else: - if self.altdown: - self.altdown = False - self.rad = DraftVecUtils.dist(self.point,self.center) - self.ui.setRadiusValue(self.rad,'Length') - self.arctrack.setRadius(self.rad) - - redraw3DView() - - elif arg["Type"] == "SoMouseButtonEvent": - if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"): - if self.point: - if (self.step == 0): # choose center - if (not self.node) and (not self.support): - getSupport(arg) - self.point,ctrlPoint,info = getPoint(self,arg) - if hasMod(arg,MODALT): - snapped=self.view.getObjectInfo((arg["Position"][0],arg["Position"][1])) - if snapped: - ob = self.doc.getObject(snapped['Object']) - num = int(snapped['Component'].lstrip('Edge'))-1 - ed = ob.Shape.Edges[num] - self.tangents.append(ed) - if len(self.tangents) == 2: - self.arctrack.on() - self.ui.radiusUi() - self.step = 1 - FreeCAD.Console.PrintMessage(translate("draft", "Pick radius")+"\n") - else: - if len(self.tangents) == 1: - self.tanpoints.append(self.point) - else: - self.center = self.point - self.node = [self.point] - self.arctrack.setCenter(self.center) - self.arctrack.on() - self.ui.radiusUi() - self.step = 1 - FreeCAD.Console.PrintMessage(translate("draft", "Pick radius")+"\n") - if self.planetrack: - self.planetrack.set(self.point) - elif (self.step == 1): # choose radius - self.drawPolygon() - - def drawPolygon(self): - """actually draws the FreeCAD object""" - rot,sup,pts,fil = self.getStrings() - FreeCADGui.addModule("Draft") - if Draft.getParam("UsePartPrimitives",False): - FreeCADGui.addModule("Part") - self.commit(translate("draft","Create Polygon"), - ['pl=FreeCAD.Placement()', - 'pl.Rotation.Q=' + rot, - 'pl.Base=' + DraftVecUtils.toString(self.center), - 'pol = FreeCAD.ActiveDocument.addObject("Part::RegularPolygon","RegularPolygon")', - 'pol.Polygon = ' + str(self.ui.numFaces.value()), - 'pol.Circumradius = ' + str(self.rad), - 'pol.Placement = pl', - 'Draft.autogroup(pol)', - 'FreeCAD.ActiveDocument.recompute()']) - else: - # building command string - self.commit(translate("draft","Create Polygon"), - ['pl=FreeCAD.Placement()', - 'pl.Rotation.Q = ' + rot, - 'pl.Base = ' + DraftVecUtils.toString(self.center), - 'pol = Draft.makePolygon(' + str(self.ui.numFaces.value()) + ',radius=' + str(self.rad) + ',inscribed=True,placement=pl,face=' + fil + ',support=' + sup + ')', - 'Draft.autogroup(pol)', - 'FreeCAD.ActiveDocument.recompute()']) - self.finish(cont=True) - - def numericInput(self,numx,numy,numz): - """this function gets called by the toolbar when valid x, y, and z have been entered there""" - self.center = Vector(numx,numy,numz) - self.node = [self.center] - self.arctrack.setCenter(self.center) - self.arctrack.on() - self.ui.radiusUi() - self.step = 1 - self.ui.radiusValue.setFocus() - FreeCAD.Console.PrintMessage(translate("draft", "Pick radius")+"\n") - - def numericRadius(self,rad): - """this function gets called by the toolbar when valid radius have been entered there""" - import DraftGeomUtils - self.rad = rad - if len(self.tangents) == 2: - cir = DraftGeomUtils.circleFrom2tan1rad(self.tangents[0], self.tangents[1], rad) - if self.center: - self.center = DraftGeomUtils.findClosestCircle(self.center,cir).Center - else: - self.center = cir[-1].Center - elif self.tangents and self.tanpoints: - cir = DraftGeomUtils.circleFrom1tan1pt1rad(self.tangents[0],self.tanpoints[0],rad) - if self.center: - self.center = DraftGeomUtils.findClosestCircle(self.center,cir).Center - else: - self.center = cir[-1].Center - self.drawPolygon() +from draftguitools.gui_polygons import Polygon class Ellipse(Creator): @@ -3738,8 +3552,6 @@ from draftguitools.gui_snaps import ShowSnapBar # drawing commands FreeCADGui.addCommand('Draft_Text',Text()) FreeCADGui.addCommand('Draft_Dimension',Dimension()) -FreeCADGui.addCommand('Draft_Polygon',Polygon()) - FreeCADGui.addCommand('Draft_Point',Point()) FreeCADGui.addCommand('Draft_Ellipse',Ellipse()) FreeCADGui.addCommand('Draft_ShapeString',ShapeString()) diff --git a/src/Mod/Draft/draftguitools/gui_polygons.py b/src/Mod/Draft/draftguitools/gui_polygons.py new file mode 100644 index 0000000000..c8306c77fa --- /dev/null +++ b/src/Mod/Draft/draftguitools/gui_polygons.py @@ -0,0 +1,293 @@ +# *************************************************************************** +# * (c) 2009 Yorik van Havre * +# * (c) 2010 Ken Cline * +# * (c) 2020 Eliud Cabrera Castillo * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * 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. * +# * * +# * FreeCAD 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 FreeCAD; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** +"""Provides tools for creating regular polygons with the Draft Workbench. + +Minimum number of sides is three (equilateral triangles). +""" +## @package gui_polygons +# \ingroup DRAFT +# \brief Provides tools for creating regular polygons with the Draft Workbench. + +from PySide.QtCore import QT_TRANSLATE_NOOP + +import FreeCAD as App +import FreeCADGui as Gui +import DraftVecUtils +import draftutils.utils as utils +import draftguitools.gui_base_original as gui_base_original +import draftguitools.gui_tool_utils as gui_tool_utils +import draftguitools.gui_trackers as trackers +from draftutils.messages import _msg +from draftutils.translate import translate + + +class Polygon(gui_base_original.Creator): + """Gui command for the Polygon tool.""" + + def GetResources(self): + """Set icon, menu and tooltip.""" + _tip = ("Creates a regular polygon (triangle, square, " + "pentagon, ...), by defining the number of sides " + "and the circumscribed radius.\n" + "CTRL to snap, SHIFT to constrain") + + return {'Pixmap': 'Draft_Polygon', + 'Accel': "P, G", + 'MenuText': QT_TRANSLATE_NOOP("Draft_Polygon", "Polygon"), + 'ToolTip': QT_TRANSLATE_NOOP("Draft_Polygon", _tip)} + + def Activated(self): + """Execute when the command is called.""" + name = translate("draft", "Polygon") + super().Activated(name) + if self.ui: + self.step = 0 + self.center = None + self.rad = None + self.tangents = [] + self.tanpoints = [] + self.ui.pointUi(name) + self.ui.extUi() + self.ui.numFaces.show() + self.ui.numFacesLabel.show() + self.altdown = False + self.ui.sourceCmd = self + self.arctrack = trackers.arcTracker() + self.call = self.view.addEventCallback("SoEvent", self.action) + _msg(translate("draft", "Pick center point")) + + def finish(self, closed=False, cont=False): + """Terminate the operation.""" + super().finish(self) + if self.ui: + self.arctrack.finalize() + self.doc.recompute() + if self.ui.continueMode: + self.Activated() + + def action(self, arg): + """Handle the 3D scene events. + + This is installed as an EventCallback in the Inventor view. + + Parameters + ---------- + arg: dict + Dictionary with strings that indicates the type of event received + from the 3D view. + """ + import DraftGeomUtils + + if arg["Type"] == "SoKeyboardEvent": + if arg["Key"] == "ESCAPE": + self.finish() + elif arg["Type"] == "SoLocation2Event": # mouse movement detection + self.point, ctrlPoint, info = gui_tool_utils.getPoint(self, arg) + + # this is to make sure radius is what you see on screen + if self.center and DraftVecUtils.dist(self.point, self.center) > 0: + viewdelta = DraftVecUtils.project(self.point.sub(self.center), + App.DraftWorkingPlane.axis) + if not DraftVecUtils.isNull(viewdelta): + self.point = self.point.add(viewdelta.negative()) + if self.step == 0: # choose center + if gui_tool_utils.hasMod(arg, gui_tool_utils.MODALT): + if not self.altdown: + self.altdown = True + self.ui.switchUi(True) + else: + if self.altdown: + self.altdown = False + self.ui.switchUi(False) + else: # choose radius + if len(self.tangents) == 2: + cir = DraftGeomUtils.circleFrom2tan1pt(self.tangents[0], + self.tangents[1], + self.point) + _c = DraftGeomUtils.findClosestCircle(self.point, cir) + self.center = _c.Center + self.arctrack.setCenter(self.center) + elif self.tangents and self.tanpoints: + cir = DraftGeomUtils.circleFrom1tan2pt(self.tangents[0], + self.tanpoints[0], + self.point) + _c = DraftGeomUtils.findClosestCircle(self.point, cir) + self.center = _c.Center + self.arctrack.setCenter(self.center) + if gui_tool_utils.hasMod(arg, gui_tool_utils.MODALT): + if not self.altdown: + self.altdown = True + snapped = self.view.getObjectInfo((arg["Position"][0], + arg["Position"][1])) + if snapped: + ob = self.doc.getObject(snapped['Object']) + num = int(snapped['Component'].lstrip('Edge')) - 1 + ed = ob.Shape.Edges[num] + if len(self.tangents) == 2: + cir = DraftGeomUtils.circleFrom3tan(self.tangents[0], + self.tangents[1], + ed) + cl = DraftGeomUtils.findClosestCircle(self.point, cir) + self.center = cl.Center + self.rad = cl.Radius + self.arctrack.setCenter(self.center) + else: + self.rad = self.center.add(DraftGeomUtils.findDistance(self.center,ed).sub(self.center)).Length + else: + self.rad = DraftVecUtils.dist(self.point, self.center) + else: + if self.altdown: + self.altdown = False + self.rad = DraftVecUtils.dist(self.point, self.center) + self.ui.setRadiusValue(self.rad, 'Length') + self.arctrack.setRadius(self.rad) + + gui_tool_utils.redraw3DView() + + elif (arg["Type"] == "SoMouseButtonEvent" + and arg["State"] == "DOWN" + and arg["Button"] == "BUTTON1"): # mouse click + if self.point: + if self.step == 0: # choose center + if (not self.node) and (not self.support): + gui_tool_utils.getSupport(arg) + (self.point, + ctrlPoint, info) = gui_tool_utils.getPoint(self, arg) + if gui_tool_utils.hasMod(arg, gui_tool_utils.MODALT): + snapped = self.view.getObjectInfo((arg["Position"][0], + arg["Position"][1])) + if snapped: + ob = self.doc.getObject(snapped['Object']) + num = int(snapped['Component'].lstrip('Edge')) - 1 + ed = ob.Shape.Edges[num] + self.tangents.append(ed) + if len(self.tangents) == 2: + self.arctrack.on() + self.ui.radiusUi() + self.step = 1 + _msg(translate("draft", "Pick radius")) + else: + if len(self.tangents) == 1: + self.tanpoints.append(self.point) + else: + self.center = self.point + self.node = [self.point] + self.arctrack.setCenter(self.center) + self.arctrack.on() + self.ui.radiusUi() + self.step = 1 + _msg(translate("draft", "Pick radius")) + if self.planetrack: + self.planetrack.set(self.point) + elif self.step == 1: # choose radius + self.drawPolygon() + + def drawPolygon(self): + """Draw the actual object.""" + rot, sup, pts, fil = self.getStrings() + Gui.addModule("Draft") + if utils.getParam("UsePartPrimitives", False): + # Insert a Part::Primitive object + Gui.addModule("Part") + _cmd = 'FreeCAD.ActiveDocument.' + _cmd += 'addObject("Part::RegularPolygon","RegularPolygon")' + _cmd_list = ['pl = FreeCAD.Placement()', + 'pl.Rotation.Q = ' + rot, + 'pl.Base = ' + DraftVecUtils.toString(self.center), + 'pol = ' + _cmd, + 'pol.Polygon = ' + str(self.ui.numFaces.value()), + 'pol.Circumradius = ' + str(self.rad), + 'pol.Placement = pl', + 'Draft.autogroup(pol)', + 'FreeCAD.ActiveDocument.recompute()'] + self.commit(translate("draft", "Create Polygon (Part)"), + _cmd_list) + else: + # Insert a Draft polygon + _cmd = 'Draft.makePolygon' + _cmd += '(' + _cmd += str(self.ui.numFaces.value()) + ', ' + _cmd += 'radius=' + str(self.rad) + ', ' + _cmd += 'inscribed=True, ' + _cmd += 'placement=pl, ' + _cmd += 'face=' + fil + ', ' + _cmd += 'support=' + sup + _cmd += ')' + _cmd_list = ['pl = FreeCAD.Placement()', + 'pl.Rotation.Q = ' + rot, + 'pl.Base = ' + DraftVecUtils.toString(self.center), + 'pol = ' + _cmd, + 'Draft.autogroup(pol)', + 'FreeCAD.ActiveDocument.recompute()'] + self.commit(translate("draft", "Create Polygon"), + _cmd_list) + self.finish(cont=True) + + def numericInput(self, numx, numy, numz): + """Validate the entry fields in the user interface. + + This function is called by the toolbar or taskpanel interface + when valid x, y, and z have been entered in the input fields. + """ + self.center = App.Vector(numx, numy, numz) + self.node = [self.center] + self.arctrack.setCenter(self.center) + self.arctrack.on() + self.ui.radiusUi() + self.step = 1 + self.ui.radiusValue.setFocus() + _msg(translate("draft", "Pick radius")) + + def numericRadius(self, rad): + """Validate the entry radius in the user interface. + + This function is called by the toolbar or taskpanel interface + when a valid radius has been entered in the input field. + """ + import DraftGeomUtils + + self.rad = rad + if len(self.tangents) == 2: + cir = DraftGeomUtils.circleFrom2tan1rad(self.tangents[0], + self.tangents[1], + rad) + if self.center: + _c = DraftGeomUtils.findClosestCircle(self.center, cir) + self.center = _c.Center + else: + self.center = cir[-1].Center + elif self.tangents and self.tanpoints: + cir = DraftGeomUtils.circleFrom1tan1pt1rad(self.tangents[0], + self.tanpoints[0], + rad) + if self.center: + _c = DraftGeomUtils.findClosestCircle(self.center, cir) + self.center = _c.Center + else: + self.center = cir[-1].Center + self.drawPolygon() + + +Gui.addCommand('Draft_Polygon', Polygon())