Draft: Added stretch tool - fixes #1163

This commit is contained in:
Yorik van Havre 2017-01-13 11:25:25 -02:00
parent 5929ad3957
commit c704c28920
7 changed files with 445 additions and 6 deletions

View File

@ -56,7 +56,7 @@ class ArchWorkbench(Workbench):
"Draft_Shape2DView","Draft_Draft2Sketch","Draft_Array",
"Draft_Clone"]
self.draftextratools = ["Draft_WireToBSpline","Draft_AddPoint","Draft_DelPoint","Draft_ShapeString",
"Draft_PathArray","Draft_Mirror"]
"Draft_PathArray","Draft_Mirror","Draft_Stretch"]
self.draftcontexttools = ["Draft_ApplyStyle","Draft_ToggleDisplayMode","Draft_AddToGroup",
"Draft_SelectGroup","Draft_SelectPlane",
"Draft_ShowSnapBar","Draft_ToggleGrid","Draft_UndoLine",

View File

@ -96,10 +96,14 @@ def isNull(something):
def isPtOnEdge(pt,edge) :
'''isPtOnEdge(Vector,edge): Tests if a point is on an edge'''
v = Part.Vertex(pt)
d = v.distToShape(edge)
if d:
if round(d[0],precision()) == 0:
return True
try:
d = v.distToShape(edge)
except:
return False
else:
if d:
if round(d[0],precision()) == 0:
return True
return False
def hasCurves(shape):

View File

@ -2670,6 +2670,149 @@ class Offset(Modifier):
self.finish()
class Stretch(Modifier):
"The Draft_Stretch FreeCAD command definition"
def GetResources(self):
return {'Pixmap' : 'Draft_Stretch',
'Accel' : "S, H",
'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Stretch", "Stretch"),
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_Stretch", "Stretches the selected objects")}
def Activated(self):
Modifier.Activated(self,"Stretch")
if self.ui:
if not FreeCADGui.Selection.getSelection():
self.ui.selectUi()
msg(translate("draft", "Select an object to stretch\n"))
self.call = self.view.addEventCallback("SoEvent",selectObject)
else:
self.proceed()
def proceed(self):
if self.call:
self.view.removeEventCallback("SoEvent",self.call)
self.sel = FreeCADGui.Selection.getSelection()
if self.ui and self.sel:
self.step = 1
self.refpoint = None
self.ui.pointUi("Stretch")
self.ui.extUi()
self.call = self.view.addEventCallback("SoEvent",self.action)
self.rectracker = rectangleTracker()
self.nodetracker = []
self.displacement = None
msg(translate("draft", "Pick first point of selection rectangle:\n"))
def action(self,arg):
"scene event handler"
if arg["Type"] == "SoKeyboardEvent":
if arg["Key"] == "ESCAPE":
self.finish()
elif arg["Type"] == "SoLocation2Event": #mouse movement detection
point,ctrlPoint,info = getPoint(self,arg) #,mobile=True) #,noTracker=(self.step < 3))
if self.step == 2:
self.rectracker.update(point)
elif arg["Type"] == "SoMouseButtonEvent":
if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"):
if (arg["Position"] == self.pos):
# clicked twice on the same point
self.finish()
else:
point,ctrlPoint,info = getPoint(self,arg) #,mobile=True) #,noTracker=(self.step < 3))
self.addPoint(point)
def addPoint(self,point):
if self.step == 1:
# first rctangle point
msg(translate("draft", "Pick opposite point of selection rectangle:\n"))
self.ui.setRelative()
self.rectracker.setorigin(point)
self.rectracker.on()
if self.planetrack:
self.planetrack.set(point)
self.step = 2
elif self.step == 2:
# second rectangle point
msg(translate("draft", "Pick start point of displacement:\n"))
self.rectracker.off()
nodes = []
self.ops = []
for o in self.sel:
tp = Draft.getType(o)
if tp in ["Wire","BSpline","BezCurve"]:
np = []
iso = False
for p in o.Points:
p = o.Placement.multVec(p)
isi = self.rectracker.isInside(p)
np.append(isi)
if isi:
iso = True
nodes.append(p)
if iso:
self.ops.append([o,np])
elif tp == "Circle":
self.ops.append([o])
nodes.append(o.Placement.Base)
else:
print "Draft Stretch: Skipping unsupported object: ",o.Label
for n in nodes:
nt = editTracker(n)
nt.on()
self.nodetracker.append(nt)
self.step = 3
elif self.step == 3:
# first point of displacement line
msg(translate("draft", "Pick end point of displacement:\n"))
self.displacement = point
self.node = [point]
self.step = 4
elif self.step == 4:
self.displacement = point.sub(self.displacement)
self.doStretch()
if self.point:
self.ui.redraw()
def numericInput(self,numx,numy,numz):
"this function gets called by the toolbar when valid x, y, and z have been entered there"
point = Vector(numx,numy,numz)
self.addPoint(point)
def finish(self,closed=False):
if self.rectracker:
self.rectracker.finalize()
if self.nodetracker:
for n in self.nodetracker:
n.finalize()
Modifier.finish(self)
def doStretch(self):
"does the actual stretching"
commitops = []
if self.displacement:
if self.displacement.Length > 0:
for ops in self.ops:
tp = Draft.getType(ops[0])
if tp in ["Wire","BSpline","BezCurve"]:
pts = []
for i in range(len(ops[1])):
if ops[1][i] == False:
pts.append(ops[0].Points[i])
else:
pts.append(ops[0].Points[i].add(self.displacement))
pts = str(pts).replace("Vector","FreeCAD.Vector")
commitops.append("FreeCAD.ActiveDocument."+ops[0].Name+".Points="+pts)
elif tp == "Circle":
commitops.append("FreeCAD.ActiveDocument."+ops[0].Name+".Placement.Base=FreeCAD."+str(ops[0].Placement.Base.add(self.displacement)))
if commitops:
commitops.append("FreeCAD.ActiveDocument.recompute()")
FreeCADGui.addModule("Draft")
self.commit(translate("draft","Stretch"),commitops)
self.finish()
class Upgrade(Modifier):
'''The Draft_Upgrade FreeCAD command definition.'''
@ -4923,6 +5066,7 @@ FreeCADGui.addCommand('Draft_Heal',Heal())
FreeCADGui.addCommand('Draft_VisGroup',VisGroup())
FreeCADGui.addCommand('Draft_Mirror',Mirror())
FreeCADGui.addCommand('Draft_Slope',Draft_Slope())
FreeCADGui.addCommand('Draft_Stretch',Stretch())
# context commands
FreeCADGui.addCommand('Draft_FinishLine',FinishLine())

View File

@ -246,6 +246,20 @@ class rectangleTracker(Tracker):
"returns the normal of the rectangle"
return (self.u.cross(self.v)).normalize()
def isInside(self,point):
"returns True if the given point is inside the rectangle"
vp = point.sub(self.p1())
uv = self.p2().sub(self.p1())
vv = self.p4().sub(self.p1())
uvp = DraftVecUtils.project(vp,uv)
vvp = DraftVecUtils.project(vp,vv)
if uvp.getAngle(uv) < 1:
if vvp.getAngle(vv) < 1:
if uvp.Length <= uv.Length:
if vvp.Length <= vv.Length:
return True
return False
class dimTracker(Tracker):
"A Dimension tracker, used by the dimension tool"
def __init__(self,dotted=False,scolor=None,swidth=None):

View File

@ -76,7 +76,7 @@ class DraftWorkbench (Workbench):
"Draft_Trimex", "Draft_Upgrade", "Draft_Downgrade", "Draft_Scale",
"Draft_Edit","Draft_WireToBSpline","Draft_AddPoint",
"Draft_DelPoint","Draft_Shape2DView","Draft_Draft2Sketch","Draft_Array",
"Draft_PathArray","Draft_Clone","Draft_Drawing","Draft_Mirror"]
"Draft_PathArray","Draft_Clone","Draft_Drawing","Draft_Mirror","Draft_Stretch"]
self.treecmdList = ["Draft_ApplyStyle","Draft_ToggleDisplayMode","Draft_AddToGroup",
"Draft_SelectGroup","Draft_SelectPlane",
"Draft_ShowSnapBar","Draft_ToggleGrid"]

View File

@ -71,6 +71,7 @@
<file>icons/Draft_Grid.svg</file>
<file>icons/Draft_Slope.svg</file>
<file>icons/DraftWorkbench.svg</file>
<file>icons/Draft_Stretch.svg</file>
<file>patterns/concrete.svg</file>
<file>patterns/cross.svg</file>
<file>patterns/line.svg</file>

View File

@ -0,0 +1,276 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
id="svg2766"
sodipodi:version="0.32"
inkscape:version="0.91 r13725"
sodipodi:docname="Draft_Stretch.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.1">
<defs
id="defs2768">
<linearGradient
inkscape:collect="always"
id="linearGradient3856">
<stop
style="stop-color:#3465a4;stop-opacity:1"
offset="0"
id="stop3858" />
<stop
style="stop-color:#729fcf;stop-opacity:1"
offset="1"
id="stop3860" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient3824">
<stop
style="stop-color:#729fcf;stop-opacity:1"
offset="0"
id="stop3826" />
<stop
style="stop-color:#204a87;stop-opacity:1"
offset="1"
id="stop3828" />
</linearGradient>
<linearGradient
id="linearGradient3787">
<stop
id="stop3789"
offset="0"
style="stop-color:#0619c0;stop-opacity:1;" />
<stop
id="stop3791"
offset="1"
style="stop-color:#379cfb;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient3864">
<stop
id="stop3866"
offset="0"
style="stop-color:#0619c0;stop-opacity:1;" />
<stop
id="stop3868"
offset="1"
style="stop-color:#379cfb;stop-opacity:1;" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 32 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="64 : 32 : 1"
inkscape:persp3d-origin="32 : 21.333333 : 1"
id="perspective2774" />
<linearGradient
gradientTransform="matrix(0,-1.4500001,1.4705882,0,-15.05882,91.45)"
y2="36.079998"
x2="21.689653"
y1="29.279999"
x1="56.172409"
gradientUnits="userSpaceOnUse"
id="linearGradient3036"
xlink:href="#linearGradient3895"
inkscape:collect="always" />
<linearGradient
id="linearGradient3895">
<stop
style="stop-color:#729fcf;stop-opacity:1;"
offset="0"
id="stop3897" />
<stop
style="stop-color:#204a87;stop-opacity:1;"
offset="1"
id="stop3899" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3824"
id="linearGradient3830-3"
x1="591.59064"
y1="103.1946"
x2="599.1272"
y2="128.1946"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.1400105,0,0,2.3311849,-82.179086,-167.4987)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3856"
id="linearGradient3862-9"
x1="613.25824"
y1="135.1946"
x2="595.35895"
y2="68.194603"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0614931,0,0,1,-614.9391,-71.223999)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3856"
id="linearGradient4383"
x1="47.999996"
y1="88"
x2="51.999996"
y2="6"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="3.6040039"
inkscape:cx="28.028062"
inkscape:cy="35.916866"
inkscape:current-layer="g3518"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1920"
inkscape:window-height="1051"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:snap-global="true"
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid2997"
empspacing="2"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<g
id="g3518"
transform="matrix(1.0614931,0,0,1,-612.96941,-69.194602)">
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#linearGradient4383);fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 34.731889,6.0502044 -5.334903,1.8009819 3.623047,7.0859367 4.748965,-2.947466 z m 4.447265,8.6992186 -4.748965,2.945513 2.791016,5.458984 4.748965,-2.945513 z m 4.201172,8.216797 -4.748965,2.947466 2.91211,5.695312 4.748965,-2.945513 z m 4.322266,8.455078 -4.748965,2.947466 2.900391,5.673828 4.748964,-2.945513 z m 4.3125,8.433594 -4.750918,2.945512 2.458984,4.810547 1.560547,0 0,0.16211 3.645449,-2.216998 z m 4.322265,8.458984 -4.748964,2.947466 0.804687,2.528743 -2.219252,0.832408 0,5.901721 7.667969,0 c 3.037635,-4.1e-5 4.050557,-2.254652 2.731889,-4.832608 z M 32,54.622493 l 0,5.901721 5.541016,0 0,-5.901721 z m 8.619141,0 0,5.901721 6.476562,0 0,-5.901721 z"
transform="matrix(0.94206924,0,0,1,577.45963,69.194602)"
id="path4267"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccc" />
<path
style="fill:none;stroke:#729fcf;stroke-width:1.94120502;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 616.67369,125.79029 4.17121,0"
id="path3834"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#729fcf;stroke-width:1.94120502;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 607.69908,125.80763 4.17121,0"
id="path3834-6"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#0b1521;stroke-width:7.76482012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 583.66838,75.458122 0,51.362428 23.4309,0 0,-51.362428 z"
id="path3018-5"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:url(#linearGradient3830-3);stroke-width:3.88241006;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 583.64878,75.3982 0,46.47494 0,4.81114 23.6273,0 0,-51.28608 z"
id="path3018-1-3"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<path
style="fill:none;stroke:#729fcf;stroke-width:1.94120502;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 587.56202,125.6418 18.65048,0 0,-46.450484 m 1.84625,-4.711707 -25.38962,0 0,53.115551"
id="path3018-1-7-5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<path
style="fill:none;stroke:#729fcf;stroke-width:1.94120502;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 625.30428,111.15089 1.85491,3.6514"
id="path3834-2"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#729fcf;stroke-width:1.94120502;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 621.20619,102.68491 1.85491,3.6514"
id="path3834-2-6"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#729fcf;stroke-width:1.94120502;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 617.14912,94.29804 1.85491,3.6514"
id="path3834-2-1"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#729fcf;stroke-width:1.94120502;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 613.21276,85.997004 1.79715,3.516512"
id="path3834-2-8"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#729fcf;stroke-width:1.94120502;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 625.6855,125.52981 c 0,0 1.91811,-0.40021 2.46967,-0.86591 0.27577,-0.23286 0.82382,-0.84479 0.70224,-1.8277 -0.12158,-0.98291 -0.86646,-2.3859 -0.86646,-2.3859"
id="path3834-2-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cssc" />
</g>
</g>
<metadata
id="metadata5370">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<cc:license
rdf:resource="" />
<dc:date>Mon Oct 10 13:44:52 2011 +0000</dc:date>
<dc:creator>
<cc:Agent>
<dc:title>[wmayer]</dc:title>
</cc:Agent>
</dc:creator>
<dc:rights>
<cc:Agent>
<dc:title>FreeCAD LGPL2+</dc:title>
</cc:Agent>
</dc:rights>
<dc:publisher>
<cc:Agent>
<dc:title>FreeCAD</dc:title>
</cc:Agent>
</dc:publisher>
<dc:identifier>FreeCAD/src/Mod/Draft/Resources/icons/Draft_Scale.svg</dc:identifier>
<dc:relation>http://www.freecadweb.org/wiki/index.php?title=Artwork</dc:relation>
<dc:contributor>
<cc:Agent>
<dc:title>[agryson] Alexander Gryson</dc:title>
</cc:Agent>
</dc:contributor>
<dc:subject>
<rdf:Bag>
<rdf:li>square</rdf:li>
<rdf:li>arrow</rdf:li>
<rdf:li>dotted line</rdf:li>
<rdf:li />
</rdf:Bag>
</dc:subject>
<dc:description>A small square in the bottom left corner of a large dotted box ith an arrow pointing from the top left corner of the inner box to the top left corner of the outer box</dc:description>
</cc:Work>
</rdf:RDF>
</metadata>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB