Draft: Hold snapping points

When drawing (snapping) using the Draft module, it is now possible
to press the Q key to record points. Additional snap locations then
become available orthogonally to these hold points.
This commit is contained in:
Yorik van Havre
2017-04-05 19:04:05 -03:00
parent 0b398559ab
commit 10ad6c6d02
4 changed files with 116 additions and 8 deletions

View File

@@ -1252,10 +1252,28 @@ def findDistance(point,edge,strict=False):
'''
findDistance(vector,edge,[strict]) - Returns a vector from the point to its
closest point on the edge. If strict is True, the vector will be returned
only if its endpoint lies on the edge.
only if its endpoint lies on the edge. Edge can also be a list of 2 points.
'''
if isinstance(point, FreeCAD.Vector):
if geomType(edge) == "Line":
if isinstance(edge,list):
segment = edge[1].sub(edge[0])
chord = edge[0].sub(point)
norm = segment.cross(chord)
perp = segment.cross(norm)
dist = DraftVecUtils.project(chord,perp)
if not dist: return None
newpoint = point.add(dist)
if (dist.Length == 0):
return None
if strict:
s1 = newpoint.sub(edge[0])
s2 = newpoint.sub(edge[1])
if (s1.Length <= segment.Length) and (s2.Length <= segment.Length):
return dist
else:
return None
else: return dist
elif geomType(edge) == "Line":
segment = vec(edge)
chord = edge.Vertexes[0].Point.sub(point)
norm = segment.cross(chord)

View File

@@ -1462,6 +1462,10 @@ class DraftToolBar:
elif txt.endswith("]"):
self.toggleradius(-1)
spec = True
elif txt.endswith("q"):
if hasattr(FreeCADGui,"Snapper"):
FreeCADGui.Snapper.addHoldPoint()
spec = True
elif txt.endswith("x"):
self.constrain("x")
self.displayPoint()

View File

@@ -89,9 +89,11 @@ class Snapper:
self.forceGridOff = False
self.lastExtensions = []
# the trackers are stored in lists because there can be several views, each with its own set
self.trackers = [[],[],[],[],[],[],[],[],[]] # view, grid, snap, extline, radius, dim1, dim2, trackLine, extline2
self.trackers = [[],[],[],[],[],[],[],[],[],[]] # view, grid, snap, extline, radius, dim1, dim2, trackLine, extline2, crosstrackers
self.polarAngles = [90,45]
self.selectMode = False
self.holdTracker = None
self.holdPoints = []
# the snapmarker has "dot","circle" and "square" available styles
if self.snapStyle:
@@ -145,7 +147,8 @@ class Snapper:
global Part, DraftGeomUtils
import Part, DraftGeomUtils
self.spoint = None
if not hasattr(self,"toolbar"):
self.makeSnapToolBar()
mw = FreeCADGui.getMainWindow()
@@ -243,6 +246,7 @@ class Snapper:
# set the arch point tracking
if self.lastArchPoint:
self.setArchDims(self.lastArchPoint,fp)
self.spoint = fp
return fp
else:
@@ -251,13 +255,15 @@ class Snapper:
obj = FreeCAD.ActiveDocument.getObject(self.snapInfo['Object'])
if not obj:
return cstr(point)
self.spoint = cstr(point)
return self.spoint
self.lastSnappedObject = obj
if hasattr(obj.ViewObject,"Selectable"):
if not obj.ViewObject.Selectable:
return cstr(point)
self.spoint = cstr(point)
return self.spoint
if not active:
@@ -347,7 +353,8 @@ class Snapper:
self.lastObj[1] = obj.Name
if not snaps:
return cstr(point)
self.spoint = cstr(point)
return self.spoint
# calculating the nearest snap point
shortest = 1000000000000000000
@@ -394,7 +401,8 @@ class Snapper:
self.lastArchPoint = None
# return the final point
return fp
self.spoint = fp
return self.spoint
def toWP(self,point):
"projects the given point on the working plane, if needed"
@@ -421,6 +429,18 @@ class Snapper:
def snapToExtensions(self,point,last,constrain,eline):
"returns a point snapped to extension or parallel line to last object, if any"
tsnap = self.snapToHold(point)
if tsnap:
if self.tracker and not self.selectMode:
self.tracker.setCoords(tsnap[2])
self.tracker.setMarker(self.mk[tsnap[1]])
self.tracker.on()
if self.extLine:
self.extLine.p1(tsnap[0])
self.extLine.p2(tsnap[2])
self.extLine.on()
self.setCursor(tsnap[1])
return tsnap[2],eline
if self.isEnabled("extension"):
tsnap = self.snapToExtOrtho(last,constrain,eline)
if tsnap:
@@ -686,6 +706,46 @@ class Snapper:
except:
return None
return None
def snapToHold(self,point):
"returns a snap location that is orthogonal to hold points or, if possible, at crossings"
if not self.holdPoints:
return None
if hasattr(FreeCAD,"DraftWorkingPlane"):
u = FreeCAD.DraftWorkingPlane.u
v = FreeCAD.DraftWorkingPlane.v
else:
u = FreeCAD.Vector(1,0,0)
v = FreeCAD.Vector(0,1,0)
if len(self.holdPoints) > 1:
# first try int points
ipoints = []
l = list(self.holdPoints)
while len(l) > 1:
p1 = l.pop()
for p2 in l:
i1 = DraftGeomUtils.findIntersection(p1,p1.add(u),p2,p2.add(v),True,True)
if i1:
ipoints.append([p1,i1[0]])
i2 = DraftGeomUtils.findIntersection(p1,p1.add(v),p2,p2.add(u),True,True)
if i2:
ipoints.append([p1,i2[0]])
for p in ipoints:
if (p[1].sub(point)).Length < self.radius:
return [p[0],'ortho',p[1]]
# then try to stick to a line
for p in self.holdPoints:
d = DraftGeomUtils.findDistance(point,[p,p.add(u)])
if d:
if d.Length < self.radius:
fp = point.add(d)
return [p,'extension',fp]
d = DraftGeomUtils.findDistance(point,[p,p.add(v)])
if d:
if d.Length < self.radius:
fp = point.add(d)
return [p,'extension',fp]
return None
def snapToExtPerpendicular(self,last):
"returns a perpendicular X extension snap location"
@@ -912,6 +972,9 @@ class Snapper:
if self.grid:
if not Draft.getParam("alwaysShowGrid",True):
self.grid.off()
if self.holdTracker:
self.holdTracker.clear()
self.holdTracker.off()
self.unconstrain()
self.radius = 0
self.setCursor()
@@ -1257,6 +1320,7 @@ class Snapper:
self.dim2 = self.trackers[6][i]
self.trackLine = self.trackers[7][i]
self.extLine2 = self.trackers[8][i]
self.holdTracker = self.trackers[9][i]
else:
if Draft.getParam("grid",True):
self.grid = DraftTrackers.gridTracker()
@@ -1274,6 +1338,9 @@ class Snapper:
self.radiusTracker = DraftTrackers.radiusTracker()
self.dim1 = DraftTrackers.archDimTracker(mode=2)
self.dim2 = DraftTrackers.archDimTracker(mode=3)
self.holdTracker = DraftTrackers.snapTracker()
self.holdTracker.setMarker("cross")
self.holdTracker.clear()
self.trackers[0].append(v)
self.trackers[1].append(self.grid)
self.trackers[2].append(self.tracker)
@@ -1283,8 +1350,16 @@ class Snapper:
self.trackers[6].append(self.dim2)
self.trackers[7].append(self.trackLine)
self.trackers[8].append(self.extLine2)
self.trackers[9].append(self.holdTracker)
if self.grid and (not self.forceGridOff):
self.grid.set()
def addHoldPoint(self):
if self.spoint:
if self.holdTracker:
self.holdTracker.addCoords(self.spoint)
self.holdTracker.on()
self.holdPoints.append(self.spoint)
if not hasattr(FreeCADGui,"Snapper"):
FreeCADGui.Snapper = Snapper()

View File

@@ -133,11 +133,22 @@ class snapTracker(Tracker):
self.marker.markerIndex = coin.SoMarkerSet.SQUARE_FILLED_9_9
elif (style == "empty"):
self.marker.markerIndex = coin.SoMarkerSet.SQUARE_LINE_9_9
elif (style == "cross"):
self.marker.markerIndex = coin.SoMarkerSet.CROSS_9_9
else:
self.marker.markerIndex = coin.SoMarkerSet.CIRCLE_FILLED_9_9
def setCoords(self,point):
self.coords.point.setValue((point.x,point.y,point.z))
def addCoords(self,point):
l = self.coords.point.getValues()
l.append(coin.SbVec3f(point.x,point.y,point.z))
self.coords.point.setValues(l)
def clear(self):
self.coords.point.deleteValues(0)
class lineTracker(Tracker):
"A Line tracker, used by the tools that need to draw temporary lines"