| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | """Provides GUI tools to create regular Polygon objects. |
| | |
| | Minimum number of sides is three (equilateral triangles). |
| | """ |
| | |
| | |
| | |
| |
|
| | |
| | |
| | from PySide.QtCore import QT_TRANSLATE_NOOP |
| |
|
| | import FreeCAD as App |
| | import FreeCADGui as Gui |
| | import DraftVecUtils |
| | from draftguitools import gui_base_original |
| | from draftguitools import gui_tool_utils |
| | from draftguitools import gui_trackers as trackers |
| | from draftutils import params |
| | from draftutils import utils |
| | from draftutils.messages import _toolmsg |
| | 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.""" |
| |
|
| | return { |
| | "Pixmap": "Draft_Polygon", |
| | "Accel": "P, G", |
| | "MenuText": QT_TRANSLATE_NOOP("Draft_Polygon", "Polygon"), |
| | "ToolTip": QT_TRANSLATE_NOOP( |
| | "Draft_Polygon", "Creates a regular polygon (triangle, square, pentagon…)" |
| | ), |
| | } |
| |
|
| | def Activated(self, numVertices=None): |
| | """Execute when the command is called.""" |
| | super().Activated(name="Polygon") |
| | if self.ui: |
| | self.step = 0 |
| | self.center = None |
| | self.rad = None |
| | self.tangents = [] |
| | self.tanpoints = [] |
| | self.ui.pointUi(title=translate("draft", "Polygon"), icon="Draft_Polygon") |
| | self.ui.extUi() |
| | self.ui.isRelative.hide() |
| | self.ui.numFaces.show() |
| | self.ui.numFacesLabel.show() |
| | self.altdown = False |
| | self.numVertices = numVertices if numVertices is not None else 3 |
| | self.ui.numFaces.setValue(self.numVertices) |
| | self.ui.sourceCmd = self |
| | self.polygonTrack = trackers.polygonTracker(sides=self.numVertices) |
| | self.call = self.view.addEventCallback("SoEvent", self.action) |
| | _toolmsg(translate("draft", "Pick center point")) |
| |
|
| | def finish(self, cont=False): |
| | """Terminate the operation. |
| | |
| | Parameters |
| | ---------- |
| | cont: bool or None, optional |
| | Restart (continue) the command if `True`, or if `None` and |
| | `ui.continueMode` is `True`. |
| | """ |
| | self.end_callbacks(self.call) |
| | if self.ui: |
| | self.polygonTrack.finalize() |
| | super().finish() |
| | if cont or (cont is None and self.ui and self.ui.continueMode): |
| | self.Activated(self.numVertices) |
| |
|
| | 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 self.ui.numFaces.value() != self.numVertices: |
| | self.polygonTrack.setNumVertices(self.ui.numFaces.value()) |
| | self.numVertices = self.ui.numFaces.value() |
| | if arg["Type"] == "SoKeyboardEvent": |
| | if arg["Key"] == "ESCAPE": |
| | self.finish() |
| | elif not self.ui.mouse: |
| | pass |
| | elif arg["Type"] == "SoLocation2Event": |
| | self.point, ctrlPoint, info = gui_tool_utils.getPoint(self, arg) |
| | self.polygonTrack.update(ctrlPoint) |
| |
|
| | |
| | if self.center and DraftVecUtils.dist(self.point, self.center) > 0: |
| | viewdelta = DraftVecUtils.project(self.point.sub(self.center), self.wp.axis) |
| | if not DraftVecUtils.isNull(viewdelta): |
| | self.point = self.point.add(viewdelta.negative()) |
| | if self.step == 0: |
| | if gui_tool_utils.hasMod(arg, gui_tool_utils.get_mod_alt_key()): |
| | if not self.altdown: |
| | self.altdown = True |
| | self.ui.switchUi(True) |
| | else: |
| | if self.altdown: |
| | self.altdown = False |
| | self.ui.switchUi(False) |
| | else: |
| | 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 |
| | 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 |
| | if gui_tool_utils.hasMod(arg, gui_tool_utils.get_mod_alt_key()): |
| | 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 |
| | 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") |
| |
|
| | gui_tool_utils.redraw3DView() |
| |
|
| | elif ( |
| | arg["Type"] == "SoMouseButtonEvent" |
| | and arg["State"] == "DOWN" |
| | and arg["Button"] == "BUTTON1" |
| | ): |
| | if self.point: |
| | if self.step == 0: |
| | 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.get_mod_alt_key()): |
| | 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.polygonTrack.on() |
| | self.ui.radiusUi() |
| | self.step = 1 |
| | _toolmsg(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.polygonTrack.setOrigin(self.center) |
| | self.polygonTrack.on() |
| | self.ui.radiusUi() |
| | self.step = 1 |
| | _toolmsg(translate("draft", "Pick radius")) |
| | if self.planetrack: |
| | self.planetrack.set(self.point) |
| | self.update_hints() |
| | elif self.step == 1: |
| | self.drawPolygon() |
| |
|
| | def drawPolygon(self): |
| | """Draw the actual object.""" |
| | rot, sup, pts, fil = self.getStrings() |
| | Gui.addModule("Draft") |
| | if params.get_param("UsePartPrimitives"): |
| | |
| | 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)", |
| | "Draft.select(pol)", |
| | "FreeCAD.ActiveDocument.recompute()", |
| | ] |
| | self.commit(translate("draft", "Create Polygon (Part)"), _cmd_list) |
| | else: |
| | |
| | _cmd = "Draft.make_polygon" |
| | _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=None) |
| |
|
| | 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.polygonTrack.on() |
| | self.ui.radiusUi() |
| | self.step = 1 |
| | self.ui.radiusValue.setFocus() |
| | _toolmsg(translate("draft", "Pick radius")) |
| | self.update_hints() |
| |
|
| | 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() |
| |
|
| | def get_hints(self): |
| | if self.step == 0: |
| | hints = [Gui.InputHint(translate("draft", "%1 pick center"), Gui.UserInput.MouseLeft)] |
| | else: |
| | hints = [Gui.InputHint(translate("draft", "%1 pick radius"), Gui.UserInput.MouseLeft)] |
| | return ( |
| | hints |
| | + gui_tool_utils._get_hint_xyz_constrain() |
| | + gui_tool_utils._get_hint_mod_constrain() |
| | + gui_tool_utils._get_hint_mod_snap() |
| | ) |
| |
|
| |
|
| | Gui.addCommand("Draft_Polygon", Polygon()) |
| |
|
| | |
| |
|