Draft: reordered supported edit objects and support for PartCylinder

This commit is contained in:
carlopav
2020-05-24 12:06:29 +02:00
committed by Yorik van Havre
parent 89d4a6e00c
commit cdbc11e2ad
6 changed files with 202 additions and 126 deletions

View File

@@ -233,6 +233,7 @@ SET(Draft_GUI_tools
draftguitools/gui_edit_draft_objects.py
draftguitools/gui_edit_arch_objects.py
draftguitools/gui_edit_part_objects.py
draftguitools/gui_edit_sketcher_objects.py
draftguitools/gui_edit.py
draftguitools/gui_lineops.py
draftguitools/gui_togglemodes.py

View File

@@ -53,6 +53,7 @@ import draftguitools.gui_trackers as trackers
import draftguitools.gui_edit_draft_objects as edit_draft
import draftguitools.gui_edit_arch_objects as edit_arch
import draftguitools.gui_edit_part_objects as edit_part
import draftguitools.gui_edit_sketcher_objects as edit_sketcher
COLORS = {
@@ -241,22 +242,17 @@ class Edit(gui_base_original.Modifier):
# preview
self.ghost = None
#list of supported Draft and Arch objects
self.supportedObjs = ["BezCurve","Wire","BSpline","Circle","Rectangle",
"Polygon","Ellipse","Dimension","LinearDimension","Space",
"Structure","PanelCut","PanelSheet","Wall", "Window"]
#list of supported objects
self.supportedObjs = edit_draft.get_supported_draft_objects() + \
edit_arch.get_supported_arch_objects()
self.supportedPartObjs = edit_part.get_supported_part_objects() + \
edit_sketcher.get_supported_sketcher_objects()
#list of supported Part objects (they don't have a proxy)
#TODO: Add support for "Part::Circle" "Part::RegularPolygon" "Part::Plane" "Part::Ellipse" "Part::Vertex" "Part::Spiral"
self.supportedPartObjs = ["Sketch", "Sketcher::SketchObject",
"Part", "Part::Line", "Part::Box"]
def GetResources(self):
tooltip = ("Edits the active object.\n"
"Press E or ALT+LeftClick to display context menu\n"
"on supported nodes and on supported objects.")
return {'Pixmap': 'Draft_Edit',
'Accel': "D, E",
'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Edit", "Edit"),
@@ -649,8 +645,8 @@ class Edit(gui_base_original.Modifier):
self.ghost.on()
self.ghost.setCenter(obj.getGlobalPlacement().Base)
self.ghost.setRadius(obj.Radius)
if self.obj.FirstAngle == self.obj.LastAngle:
# self.obj is a circle
if obj.FirstAngle == obj.LastAngle:
# obj is a circle
self.ghost.circle = True
if self.editing == 0:
self.ghost.setCenter(pt)
@@ -662,15 +658,15 @@ class Edit(gui_base_original.Modifier):
# edit by 3 points
if self.editing == 0:
# center point
p1 = self.relativize_vector(self.obj, self.obj.Shape.Vertexes[0].Point)
p2 = self.relativize_vector(self.obj, self.obj.Shape.Vertexes[1].Point)
p0 = DraftVecUtils.project(self.relativize_vector(self.obj, pt),
self.relativize_vector(self.obj, (edit_draft.getArcMid(obj, global_placement=True))))
p1 = self.relativize_vector(obj, obj.Shape.Vertexes[0].Point)
p2 = self.relativize_vector(obj, obj.Shape.Vertexes[1].Point)
p0 = DraftVecUtils.project(self.relativize_vector(obj, pt),
self.relativize_vector(obj, (edit_draft.getArcMid(obj, global_placement=True))))
self.ghost.autoinvert=False
self.ghost.setRadius(p1.sub(p0).Length)
self.ghost.setStartPoint(self.obj.Shape.Vertexes[1].Point)
self.ghost.setEndPoint(self.obj.Shape.Vertexes[0].Point)
self.ghost.setCenter(self.globalize_vector(self.obj, p0))
self.ghost.setStartPoint(obj.Shape.Vertexes[1].Point)
self.ghost.setEndPoint(obj.Shape.Vertexes[0].Point)
self.ghost.setCenter(self.globalize_vector(obj, p0))
return
else:
p1 = edit_draft.getArcStart(obj, global_placement=True)
@@ -694,7 +690,7 @@ class Edit(gui_base_original.Modifier):
elif self.editing == 2:
self.ghost.setEndPoint(pt)
elif self.editing == 3:
self.ghost.setRadius(self.relativize_vector(self.obj, pt).Length)
self.ghost.setRadius(self.relativize_vector(obj, pt).Length)
gui_tool_utils.redraw_3d_view()
def finalizeGhost(self):
@@ -712,7 +708,7 @@ class Edit(gui_base_original.Modifier):
"""Add point to obj and reset trackers.
"""
pos = event.getPosition()
# self.setSelectState(self.obj, True)
# self.setSelectState(obj, True)
selobjs = Gui.ActiveDocument.ActiveView.getObjectsInfo((pos[0],pos[1]))
if not selobjs:
return
@@ -722,20 +718,20 @@ class Edit(gui_base_original.Modifier):
for o in self.edited_objects:
if o.Name != info["Object"]:
continue
self.obj = o
obj = o
break
if utils.get_type(self.obj) == "Wire" and 'Edge' in info["Component"]:
if utils.get_type(obj) == "Wire" and 'Edge' in info["Component"]:
pt = App.Vector(info["x"], info["y"], info["z"])
self.addPointToWire(self.obj, pt, int(info["Component"][4:]))
elif utils.get_type(self.obj) in ["BSpline", "BezCurve"]: #to fix double vertex created
self.addPointToWire(obj, pt, int(info["Component"][4:]))
elif utils.get_type(obj) in ["BSpline", "BezCurve"]: #to fix double vertex created
# pt = self.point
if "x" in info:# prefer "real" 3D location over working-plane-driven one if possible
pt = App.Vector(info["x"], info["y"], info["z"])
else:
continue
self.addPointToCurve(pt, info)
self.obj.recompute()
self.resetTrackers(self.obj)
self.addPointToCurve(pt, obj, info)
obj.recompute()
self.resetTrackers(obj)
return
def addPointToWire(self, obj, newPoint, edgeIndex):
@@ -746,25 +742,25 @@ class Edit(gui_base_original.Modifier):
elif obj.ChamferSize > 0 or obj.FilletRadius > 0:
edgeIndex = (edgeIndex + 1) / 2
for index, point in enumerate(self.obj.Points):
for index, point in enumerate(obj.Points):
if index == edgeIndex:
newPoints.append(self.relativize_vector(self.obj, newPoint))
newPoints.append(self.relativize_vector(obj, newPoint))
newPoints.append(point)
if obj.Closed and edgeIndex == len(obj.Points):
# last segment when object is closed
newPoints.append(self.relativize_vector(self.obj, newPoint))
newPoints.append(self.relativize_vector(obj, newPoint))
obj.Points = newPoints
def addPointToCurve(self, point, info=None):
def addPointToCurve(self, point, obj, info=None):
import Part
if not (utils.get_type(self.obj) in ["BSpline", "BezCurve"]):
if not (utils.get_type(obj) in ["BSpline", "BezCurve"]):
return
pts = self.obj.Points
if utils.get_type(self.obj) == "BezCurve":
pts = obj.Points
if utils.get_type(obj) == "BezCurve":
if not info['Component'].startswith('Edge'):
return # clicked control point
edgeindex = int(info['Component'].lstrip('Edge')) - 1
wire = self.obj.Shape.Wires[0]
wire = obj.Shape.Wires[0]
bz = wire.Edges[edgeindex].Curve
param = bz.parameter(point)
seg1 = wire.Edges[edgeindex].copy().Curve
@@ -781,31 +777,31 @@ class Edit(gui_base_original.Modifier):
pts = edges[0].Curve.getPoles()[0:1]
for edge in edges:
pts.extend(edge.Curve.getPoles()[1:])
if self.obj.Closed:
if obj.Closed:
pts.pop()
c = self.obj.Continuity
c = obj.Continuity
# assume we have a tangent continuity for an arbitrarily split
# segment, unless it's linear
cont = 1 if (self.obj.Degree >= 2) else 0
self.obj.Continuity = c[0:edgeindex] + [cont] + c[edgeindex:]
cont = 1 if (obj.Degree >= 2) else 0
obj.Continuity = c[0:edgeindex] + [cont] + c[edgeindex:]
else:
if (utils.get_type(self.obj) in ["BSpline"]):
if (self.obj.Closed == True):
curve = self.obj.Shape.Edges[0].Curve
if (utils.get_type(obj) in ["BSpline"]):
if (obj.Closed == True):
curve = obj.Shape.Edges[0].Curve
else:
curve = self.obj.Shape.Curve
curve = obj.Shape.Curve
uNewPoint = curve.parameter(point)
uPoints = []
for p in self.obj.Points:
for p in obj.Points:
uPoints.append(curve.parameter(p))
for i in range(len(uPoints) - 1):
if ( uNewPoint > uPoints[i] ) and ( uNewPoint < uPoints[i+1] ):
pts.insert(i + 1, self.relativize_vector(self.obj, point))
pts.insert(i + 1, self.relativize_vector(obj, point))
break
# DNC: fix: add points to last segment if curve is closed
if self.obj.Closed and (uNewPoint > uPoints[-1]):
pts.append(self.relativize_vector(self.obj, point))
self.obj.Points = pts
if obj.Closed and (uNewPoint > uPoints[-1]):
pts.append(self.relativize_vector(obj, point))
obj.Points = pts
def delPoint(self, event):
pos = event.getPosition()
@@ -818,25 +814,25 @@ class Edit(gui_base_original.Modifier):
return
doc = App.getDocument(str(node.documentName.getValue()))
self.obj = doc.getObject(str(node.objectName.getValue()))
if self.obj is None:
obj = doc.getObject(str(node.objectName.getValue()))
if obj is None:
return
if not (utils.get_type(self.obj) in ["Wire", "BSpline", "BezCurve"]):
if not (utils.get_type(obj) in ["Wire", "BSpline", "BezCurve"]):
return
if len(self.obj.Points) <= 2:
if len(obj.Points) <= 2:
_msg = translate("draft", "Active object must have more than two points/nodes")
App.Console.PrintWarning(_msg + "\n")
return
pts = self.obj.Points
pts = obj.Points
pts.pop(ep)
self.obj.Points = pts
if utils.get_type(self.obj) == "BezCurve":
self.obj.Proxy.resetcontinuity(self.obj)
self.obj.recompute()
obj.Points = pts
if utils.get_type(obj) == "BezCurve":
obj.Proxy.resetcontinuity(obj)
obj.recompute()
# don't do tan/sym on DWire/BSpline!
self.resetTrackers(self.obj)
self.resetTrackers(obj)
# ------------------------------------------------------------------------
@@ -911,7 +907,7 @@ class Edit(gui_base_original.Modifier):
elif action_label == "invert arc":
pos = self.event.getPosition()
obj = self.get_selected_obj_at_position(pos)
self.arcInvert(obj)
edit_draft.arcInvert(obj)
del self.event
@@ -975,14 +971,17 @@ class Edit(gui_base_original.Modifier):
elif objectType == "PanelSheet":
eps = edit_arch.getPanelSheetPts(obj)
elif objectType == "Part" and obj.TypeId == "Part::Box":
eps = edit_part.getPartBoxPts(obj)
elif objectType == "Part::Line" and obj.TypeId == "Part::Line":
eps = edit_part.getPartLinePts(obj)
elif objectType == "Part" and obj.TypeId == "Part::Box":
eps = edit_part.getPartBoxPts(obj)
elif objectType == "Part" and obj.TypeId == "Part::Cylinder":
eps = edit_part.getPartCylinderPts(obj)
elif objectType == "Sketch":
eps = edit_arch.getSketchPts(obj)
eps = edit_sketcher.getSketchPts(obj)
if eps:
return self.globalize_vectors(obj, eps)
@@ -991,7 +990,7 @@ class Edit(gui_base_original.Modifier):
def update(self, obj, nodeIndex, v):
"""Apply the App.Vector to the modified point and update self.obj."""
"""Apply the App.Vector to the modified point and update obj."""
v = self.relativize_vector(obj, v)
@@ -1032,7 +1031,7 @@ class Edit(gui_base_original.Modifier):
edit_draft.updateDimension(obj, nodeIndex, v)
elif objectType == "Sketch":
edit_arch.updateSketch(obj, nodeIndex, v)
edit_sketcher.updateSketch(obj, nodeIndex, v)
elif objectType == "Wall":
if nodeIndex == 0:
@@ -1058,12 +1057,15 @@ class Edit(gui_base_original.Modifier):
elif objectType == "PanelSheet":
edit_arch.updatePanelSheet(obj, nodeIndex, v)
elif objectType == "Part::Line" and self.obj.TypeId == "Part::Line":
elif objectType == "Part::Line" and obj.TypeId == "Part::Line":
edit_part.updatePartLine(obj, nodeIndex, v)
elif objectType == "Part" and self.obj.TypeId == "Part::Box":
elif objectType == "Part" and obj.TypeId == "Part::Box":
edit_part.updatePartBox(obj, nodeIndex, v)
elif objectType == "Part" and obj.TypeId == "Part::Cylinder":
edit_part.updatePartCylinder(obj, nodeIndex, v)
obj.recompute()

View File

@@ -38,41 +38,8 @@ import DraftVecUtils
from draftutils.translate import translate
import draftutils.utils as utils
# SKETCH: just if it's composed by a single segment-----------------------
def getSketchPts(obj):
"""Return the list of edipoints for the given single line sketch.
(WallTrace)
0 : startpoint
1 : endpoint
"""
editpoints = []
if obj.GeometryCount == 1:
editpoints.append(obj.getPoint(0,1))
editpoints.append(obj.getPoint(0,2))
return editpoints
else:
_wrn = translate("draft", "Sketch is too complex to edit: "
"it is suggested to use sketcher default editor")
App.Console.PrintWarning(_wrn + "\n")
return None
def updateSketch(obj, nodeIndex, v):
"""Move a single line sketch vertex a certain displacement.
(single segment sketch object, node index as Int, App.Vector)
move a single line sketch (WallTrace) vertex according to a given App.Vector
0 : startpoint
1 : endpoint
"""
if nodeIndex == 0:
obj.movePoint(0, 1, v)
elif nodeIndex == 1:
obj.movePoint(0, 2, v)
obj.recompute()
def get_supported_arch_objects():
return ["Wall", "Window", "Structure", "Space", "PanelCut", "PanelSheet"]
# WALL---------------------------------------------------------------------

View File

@@ -50,6 +50,11 @@ import DraftVecUtils
from draftutils.translate import translate
import draftutils.utils as utils
def get_supported_draft_objects():
return ["BezCurve", "Wire", "BSpline", "Rectangle",
"Circle", "Ellipse", "Polygon",
"Dimension", "LinearDimension"]
# -------------------------------------------------------------------------
# EDIT OBJECT TOOLS : Line/Wire/Bspline/Bezcurve
@@ -315,28 +320,25 @@ def getCirclePts(obj):
3 : midpoint
"""
editpoints = []
editpoints.append(obj.getGlobalPlacement().Base)
editpoints.append(App.Vector(0, 0, 0))
if obj.FirstAngle == obj.LastAngle:
# obj is a circle
editpoints.append(obj.getGlobalPlacement().multVec(App.Vector(obj.Radius,0,0)))
editpoints.append(App.Vector(obj.Radius,0,0))
else:
# obj is an arc
editpoints.append(getArcStart(obj, global_placement=True))#First endpoint
editpoints.append(getArcEnd(obj, global_placement=True))#Second endpoint
editpoints.append(getArcMid(obj, global_placement=True))#Midpoint
editpoints.append(getArcStart(obj))#First endpoint
editpoints.append(getArcEnd(obj))#Second endpoint
editpoints.append(getArcMid(obj))#Midpoint
return editpoints
def updateCircle(obj, nodeIndex, v, alt_edit_mode=0):
delta = obj.getGlobalPlacement().inverse().multVec(v)
local_v = obj.Placement.multVec(delta)
if obj.FirstAngle == obj.LastAngle:
# object is a circle
if nodeIndex == 0:
obj.Placement.Base = local_v
obj.Placement.Base = obj.Placement.multVec(v)
elif nodeIndex == 1:
obj.Radius = delta.Length
obj.Radius = v.Length
else:
# obj is an arc
@@ -347,7 +349,7 @@ def updateCircle(obj, nodeIndex, v, alt_edit_mode=0):
# center point
p1 = getArcStart(obj)
p2 = getArcEnd(obj)
p0 = DraftVecUtils.project(delta, getArcMid(obj))
p0 = DraftVecUtils.project(v, getArcMid(obj))
obj.Radius = p1.sub(p0).Length
obj.FirstAngle = -math.degrees(DraftVecUtils.angle(p1.sub(p0)))
obj.LastAngle = -math.degrees(DraftVecUtils.angle(p2.sub(p0)))
@@ -356,36 +358,39 @@ def updateCircle(obj, nodeIndex, v, alt_edit_mode=0):
else:
if nodeIndex == 1: # first point
p1 = v
p2 = getArcMid(obj, global_placement=True)
p3 = getArcEnd(obj, global_placement=True)
p2 = getArcMid(obj)
p3 = getArcEnd(obj)
elif nodeIndex == 3: # midpoint
p1 = getArcStart(obj, global_placement=True)
p1 = getArcStart(obj)
p2 = v
p3 = getArcEnd(obj, global_placement=True)
p3 = getArcEnd(obj)
elif nodeIndex == 2: # second point
p1 = getArcStart(obj, global_placement=True)
p2 = getArcMid(obj, global_placement=True)
p1 = getArcStart(obj)
p2 = getArcMid(obj)
p3 = v
arc=Part.ArcOfCircle(p1,p2,p3)
obj.Placement.Base = obj.Placement.multVec(obj.getGlobalPlacement().inverse().multVec(arc.Location))
obj.Placement.Base = arc.Center
obj.Radius = arc.Radius
'''obj.Placement.Base = obj.Placement.multVec(obj.getGlobalPlacement().inverse().multVec(arc.Location))
obj.Radius = arc.Radius
delta = obj.Placement.inverse().multVec(p1)
obj.FirstAngle = math.degrees(math.atan2(delta[1],delta[0]))
delta = obj.Placement.inverse().multVec(p3)
obj.LastAngle = math.degrees(math.atan2(delta[1],delta[0]))
obj.LastAngle = math.degrees(math.atan2(delta[1],delta[0]))'''
elif alt_edit_mode == 1:
# edit arc by center radius FirstAngle LastAngle
if nodeIndex == 0:
obj.Placement.Base = local_v
obj.Placement.Base = obj.Placement.multVec(v)
else:
dangle = math.degrees(math.atan2(delta[1],delta[0]))
dangle = math.degrees(math.atan2(v[1],v[0]))
if nodeIndex == 1:
obj.FirstAngle = dangle
elif nodeIndex == 2:
obj.LastAngle = dangle
elif nodeIndex == 3:
obj.Radius = delta.Length
obj.Radius = v.Length
obj.recompute()
@@ -441,7 +446,10 @@ def updateEllipse(obj, nodeIndex, v):
if nodeIndex == 0:
obj.Placement.Base = obj.Placement.multVec(v)
elif nodeIndex == 1:
obj.MajorRadius = v.Length
if v.Length >= obj.MinorRadius:
obj.MajorRadius = v.Length
else:
obj.MajorRadius = obj.MinorRadius
elif nodeIndex == 2:
if v.Length <= obj.MajorRadius:
obj.MinorRadius = v.Length

View File

@@ -32,6 +32,9 @@ __url__ = "https://www.freecadweb.org"
import FreeCAD as App
import DraftVecUtils
def get_supported_part_objects():
return ["Part", "Part::Line", "Part::Box", "Part::Cylinder"
]
# PART::LINE--------------------------------------------------------------
@@ -74,3 +77,21 @@ def updatePartBox(obj, nodeIndex, v):
elif nodeIndex == 3:
_vector = DraftVecUtils.project(v, App.Vector(0, 0, 1))
obj.Height = _vector.Length
# Part::Cylinder --------------------------------------------------------------
def getPartCylinderPts(obj):
editpoints = []
editpoints.append(App.Vector(0, 0, 0))
editpoints.append(App.Vector(obj.Radius, 0, 0))
editpoints.append(App.Vector(0, 0, obj.Height))
return editpoints
def updatePartCylinder(obj, nodeIndex, v):
if nodeIndex == 0:
obj.Placement.Base = obj.Placement.Base + v
elif nodeIndex == 1:
obj.Radius = v.Length
elif nodeIndex == 2:
_vector = DraftVecUtils.project(v, App.Vector(0, 0, 1))
obj.Height = _vector.Length

View File

@@ -0,0 +1,77 @@
# ***************************************************************************
# * Copyright (c) 2009, 2010 Yorik van Havre <yorik@uncreated.net> *
# * Copyright (c) 2009, 2010 Ken Cline <cline@frii.com> *
# * Copyright (c) 2019, 2020 Carlo Pavan <carlopav@gmail.com> *
# * *
# * 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 *
# * *
# ***************************************************************************
"""Provide the support functions to Draft_Edit for Arch objects."""
## @package gui_edit_arch_objects
# \ingroup DRAFT
# \brief Provide the support functions to Draft_Edit for Arch objects.
__title__ = "FreeCAD Draft Edit Tool"
__author__ = ("Yorik van Havre, Werner Mayer, Martin Burbaum, Ken Cline, "
"Dmitry Chigrin, Carlo Pavan")
__url__ = "https://www.freecadweb.org"
import math
import FreeCAD as App
from draftutils.translate import translate
def get_supported_sketcher_objects():
return ["Sketch", "Sketcher::SketchObject",
]
# SKETCH: just if it's composed by a single segment-----------------------
def getSketchPts(obj):
"""Return the list of edipoints for the given single line sketch.
(WallTrace)
0 : startpoint
1 : endpoint
"""
editpoints = []
if obj.GeometryCount == 1:
editpoints.append(obj.getPoint(0,1))
editpoints.append(obj.getPoint(0,2))
return editpoints
else:
_wrn = translate("draft", "Sketch is too complex to edit: "
"it is suggested to use sketcher default editor")
App.Console.PrintWarning(_wrn + "\n")
return None
def updateSketch(obj, nodeIndex, v):
"""Move a single line sketch vertex a certain displacement.
(single segment sketch object, node index as Int, App.Vector)
move a single line sketch (WallTrace) vertex according to a given App.Vector
0 : startpoint
1 : endpoint
"""
if nodeIndex == 0:
obj.movePoint(0, 1, v)
elif nodeIndex == 1:
obj.movePoint(0, 2, v)
obj.recompute()