diff --git a/src/Mod/Path/CMakeLists.txt b/src/Mod/Path/CMakeLists.txt index e92a43661..8c52a7fc3 100644 --- a/src/Mod/Path/CMakeLists.txt +++ b/src/Mod/Path/CMakeLists.txt @@ -26,7 +26,6 @@ SET(PathScripts_SRCS PathScripts/PathCopy.py PathScripts/PathCustom.py PathScripts/PathDressup.py - PathScripts/PathDressupHoldingTags.py PathScripts/PathDrilling.py PathScripts/PathEngrave.py PathScripts/PathFacePocket.py @@ -73,7 +72,6 @@ SET(PathScripts_SRCS PathScripts/opensbp_pre.py PathScripts/rml_post.py PathScripts/slic3r_pre.py - PathTests/TestPathDressupHoldingTags.py PathTests/TestPathGeom.py PathTests/TestPathPost.py PathTests/__init__.py diff --git a/src/Mod/Path/Gui/Resources/Path.qrc b/src/Mod/Path/Gui/Resources/Path.qrc index 5be33f8ea..bb147e140 100644 --- a/src/Mod/Path/Gui/Resources/Path.qrc +++ b/src/Mod/Path/Gui/Resources/Path.qrc @@ -53,7 +53,6 @@ panels/DogboneEdit.ui panels/DrillingEdit.ui panels/EngraveEdit.ui - panels/HoldingTagsEdit.ui panels/JobEdit.ui panels/MillFaceEdit.ui panels/PocketEdit.ui diff --git a/src/Mod/Path/Gui/Resources/panels/HoldingTagsEdit.ui b/src/Mod/Path/Gui/Resources/panels/HoldingTagsEdit.ui deleted file mode 100644 index 465b0ad6e..000000000 --- a/src/Mod/Path/Gui/Resources/panels/HoldingTagsEdit.ui +++ /dev/null @@ -1,240 +0,0 @@ - - - TaskPanel - - - - 0 - 0 - 352 - 387 - - - - Holding Tags - - - - - - QFrame::NoFrame - - - 0 - - - - - 0 - 0 - 334 - 311 - - - - Tags - - - - - - - 0 - 0 - - - - true - - - 80 - - - false - - - - X - - - - - Y - - - - - Width - - - - - Height - - - - - Angle - - - - - - - - - - - Delete - - - - - - - Disable - - - - - - - Add - - - - - - - - - - - - 0 - 0 - 334 - 311 - - - - Generate - - - - - - Width - - - - - - - <html><head/><body><p>Width of each tag.</p></body></html> - - - - - - - Height - - - - - - - <html><head/><body><p>The height of the holding tag measured from the bottom of the path. By default this is set to the (estimated) height of the path.</p></body></html> - - - - - - - true - - - Angle - - - - - - - true - - - <html><head/><body><p>Angle of tag walls.</p></body></html> - - - - - - - QDialogButtonBox::Apply|QDialogButtonBox::Ok - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Layout - - - - - - Count - - - - - - - <html><head/><body><p>Enter the number of tags you wish to have.</p><p><br/></p><p>Note that sometimes it's necessary to enter a larger than desired count number and disable the ones tags you don't want in order to get the holding tag layout you want.</p></body></html> - - - - - - - Spacing - - - - - - - - - - - - - Auto Apply - - - - - - - - - - - - diff --git a/src/Mod/Path/InitGui.py b/src/Mod/Path/InitGui.py index e2b69f6b7..7c34fd592 100644 --- a/src/Mod/Path/InitGui.py +++ b/src/Mod/Path/InitGui.py @@ -74,7 +74,6 @@ class PathWorkbench (Workbench): from PathScripts import PathProfileEdges from PathScripts import DogboneDressup from PathScripts import PathMillFace - from PathScripts import PathDressupHoldingTags import PathCommands # build commands list @@ -84,7 +83,7 @@ class PathWorkbench (Workbench): twodopcmdlist = ["Path_Contour", "Path_Profile", "Path_Profile_Edges", "Path_Pocket", "Path_Drilling", "Path_Engrave", "Path_MillFace"] threedopcmdlist = ["Path_Surfacing"] modcmdlist = ["Path_Copy", "Path_CompoundExtended", "Path_Array", "Path_SimpleCopy" ] - dressupcmdlist = ["Dogbone_Dressup", "DragKnife_Dressup", "PathDressup_HoldingTags"] + dressupcmdlist = ["Dogbone_Dressup", "DragKnife_Dressup"] extracmdlist = ["Path_SelectLoop"] #modcmdmore = ["Path_Hop",] #remotecmdlist = ["Path_Remote"] diff --git a/src/Mod/Path/PathScripts/PathDressupHoldingTags.py b/src/Mod/Path/PathScripts/PathDressupHoldingTags.py deleted file mode 100644 index b88ae712d..000000000 --- a/src/Mod/Path/PathScripts/PathDressupHoldingTags.py +++ /dev/null @@ -1,1011 +0,0 @@ -# -*- coding: utf-8 -*- - -# *************************************************************************** -# * * -# * Copyright (c) 2016 sliptonic * -# * * -# * 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 * -# * * -# *************************************************************************** -import FreeCAD -import FreeCADGui -import Path -from PathScripts import PathUtils -from PySide import QtCore, QtGui -import math -import Part -import DraftGeomUtils - -"""Holding Tags Dressup object and FreeCAD command""" - -# Qt tanslation handling -try: - _encoding = QtGui.QApplication.UnicodeUTF8 - - def translate(context, text, disambig=None): - return QtGui.QApplication.translate(context, text, disambig, _encoding) - -except AttributeError: - - def translate(context, text, disambig=None): - return QtGui.QApplication.translate(context, text, disambig) - -debugDressup = True - -def debugMarker(vector, label, color = None, radius = 0.5): - if debugDressup: - obj = FreeCAD.ActiveDocument.addObject("Part::Sphere", label) - obj.Label = label - obj.Radius = radius - obj.Placement = FreeCAD.Placement(vector, FreeCAD.Rotation(FreeCAD.Vector(0,0,1), 0)) - if color: - obj.ViewObject.ShapeColor = color - -movecommands = ['G0', 'G00', 'G1', 'G01', 'G2', 'G02', 'G3', 'G03'] -movestraight = ['G1', 'G01'] -movecw = ['G2', 'G02'] -moveccw = ['G3', 'G03'] -movearc = movecw + moveccw - -slack = 0.0000001 - -def isAbout(v1, v2): - return math.fabs(v1 - v2) < slack - -def pointsCoincide(p1, p2): - return isAbout(p1.x, p2.x) and isAbout(p1.y, p2.y) and isAbout(p1.z, p2.z) - -def getAngle(v): - a = v.getAngle(FreeCAD.Vector(1,0,0)) - if v.y < 0: - return -a - return a - -class Side: - Left = +1 - Right = -1 - Straight = 0 - On = 0 - - @classmethod - def toString(cls, side): - if side == cls.Left: - return 'Left' - if side == cls.Right: - return 'Right' - return 'On' - - @classmethod - def of(cls, ptRef, pt): - d = -ptRef.x*pt.y + ptRef.y*pt.x - if d < 0: - return cls.Left - if d > 0: - return cls.Right - return cls.Straight - -def pathCommandForEdge(edge): - pt = edge.Curve.EndPoint - params = {'X': pt.x, 'Y': pt.y, 'Z': pt.z} - if type(edge.Curve) == Part.Line: - return Part.Command('G1', params) - - p1 = edge.Curve.StartPoint - p2 = edge.valueAt((edge.FirstParameter + edge.LastParameter)/2) - p3 = pt - if Side.Left == Side.of(p2 - p1, p3 - p2): - cmd = 'G3' - else: - cmd = 'G2' - offset = pt1 - edge.Curve.Center - params.update({'I': offset.x, 'J': offset.y, 'K': offset.z}) - return Part.Command(cmd, params) - - -class Tag: - - @classmethod - def FromString(cls, string): - try: - t = eval(string) - return Tag(t[0], t[1], t[2], t[3], t[4], t[5]) - except: - return None - - def __init__(self, x, y, width, height, angle, enabled=True, z=None): - self.x = x - self.y = y - self.width = math.fabs(width) - self.height = math.fabs(height) - self.actualHeight = self.height - self.angle = math.fabs(angle) - self.enabled = enabled - if z is not None: - self.createSolidsAt(z) - - def toString(self): - return str((self.x, self.y, self.width, self.height, self.angle, self.enabled)) - - def originAt(self, z): - return FreeCAD.Vector(self.x, self.y, z) - - def bottom(self): - return self.z - - def top(self): - return self.z + self.actualHeight - - def centerLine(self): - return Part.Line(self.originAt(self.bottom()), self.originAt(self.top())) - - def createSolidsAt(self, z): - self.z = z - r1 = self.width / 2 - height = self.height - if self.angle == 90 and height > 0: - self.solid = Part.makeCylinder(r1, height) - self.core = self.solid.copy() - elif self.angle > 0.0 and height > 0.0: - tangens = math.tan(math.radians(self.angle)) - dr = height / tangens - if dr < r1: - r2 = r1 - dr - self.core = Part.makeCylinder(r2, height) - else: - r2 = 0 - height = r1 * tangens - self.core = None - self.actualHeight = height - self.solid = Part.makeCone(r1, r2, height) - else: - # degenerated case - no tag - self.solid = Part.makeSphere(r1 / 10000) - self.core = None - self.solid.translate(self.originAt(z)) - if self.core: - self.core.translate(self.originAt(z)) - - class Intersection: - # An intersection with a tag has 4 markant points, where one might be optional. - # - # P1---P2 P1---P2 P2 - # | | / \ /\ - # | | / \ / \ - # | | / \ / \ - # ---P0 P3--- ---P0 P3--- ---P0 P3--- - # - # If no intersection occured the Intersection can be viewed as being - # at P3 with no additional edges. - P0 = 2 - P1 = 3 - P2 = 4 - P3 = 5 - - def __init__(self, tag): - self.tag = tag - self.state = self.P3 - self.edges = [] - self.tail = None - - def isComplete(self): - return self.state == self.P3 - - def moveEdgeToPlateau(self, edge): - if type(edge.Curve) is Part.Line: - pt1 = edge.Curve.StartPoint - pt2 = edge.Curve.EndPoint - pt1.z = self.tag.top() - pt2.z = self.tag.top() - #print("\nplateau= %s - %s" %(pt1, pt2)) - return Part.Edge(Part.Line(pt1, pt2)) - - def intersectP0Core(self, edge): - #print("----- P0 (%s - %s)" % (edge.Curve.StartPoint, edge.Curve.EndPoint)) - - i = self.tag.nextIntersectionClosestTo(edge, self.tag.core, edge.Curve.StartPoint) - if i: - if pointsCoincide(i, edge.Curve.StartPoint): - # if P0 and P1 are the same, we need to insert a segment for the rise - #print("------- insert vertical rise (%s)" % i) - self.edges.append(Part.Edge(Part.Line(i, FreeCAD.Vector(i.x, i.y, self.tag.top())))) - self.p1 = i - self.state = self.P1 - return edge - if pointsCoincide(i, edge.Curve.EndPoint): - #print("------- consumed (%s)" % i) - e = edge - tail = None - else: - #print("------- split at (%s)" % i) - e, tail = self.tag.splitEdgeAt(edge, i) - self.p1 = e.Curve.EndPoint - self.edges.append(self.tag.mapEdgeToSolid(e)) - self.state = self.P1 - return tail - # no intersection, the entire edge fits between P0 and P1 - #print("------- no intersection") - self.edges.append(self.tag.mapEdgeToSolid(edge)) - return None - - def intersectP0(self, edge): - if self.tag.core: - return self.intersectP0Core(edge) - # if we have no core the tip is the origin of the Tag - line = Part.Edge(self.tag.centerLine()) - i = DraftGeomUtils.findIntersection(line, edge) - if i: - if pointsCoincide(i[0], edge.Curve.EndPoint): - e = edge - tail = None - else: - e, tail = self.tag.splitEdgeAt(edge, i[0]) - self.state = self.P2 # P1 and P2 are identical for triangular tags - self.p1 = i[0] - self.p2 = i[0] - else: - e = edge - tail = None - self.edges.append(self.tag.mapEdgeToSolid(e)) - return tail - - - - def intersectP1(self, edge): - #print("----- P1 (%s - %s)" % (edge.Curve.StartPoint, edge.Curve.EndPoint)) - i = self.tag.nextIntersectionClosestTo(edge, self.tag.core, edge.Curve.EndPoint) - if i: - if pointsCoincide(i, edge.Curve.StartPoint): - self.edges.append(self.tag.mapEdgeToSolid(edge)) - return self - if pointsCoincide(i, edge.Curve.EndPoint): - e = edge - tail = None - else: - e, tail = self.tag.splitEdgeAt(edge, i) - self.p2 = e.Curve.EndPoint - self.state = self.P2 - else: - e = edge - tail = None - self.edges.append(self.moveEdgeToPlateau(e)) - return tail - - def intersectP2(self, edge): - #print("----- P2 (%s - %s)" % (edge.Curve.StartPoint, edge.Curve.EndPoint)) - i = self.tag.nextIntersectionClosestTo(edge, self.tag.solid, edge.Curve.EndPoint) - if i: - if pointsCoincide(i, edge.Curve.StartPoint): - #print("------- insert exit plunge (%s)" % i) - self.edges.append(Part.Edge(Part.Line(FreeCAD.Vector(i.x, i.y, self.tag.top()), i))) - e = None - tail = edge - elif pointsCoincide(i, edge.Curve.EndPoint): - #print("------- entire segment added (%s)" % i) - e = edge - tail = None - else: - e, tail = self.tag.splitEdgeAt(edge, i) - #if tail: - # print("----- P3 (%s - %s)" % (tail.Curve.StartPoint, tail.Curve.EndPoint)) - #else: - # print("----- P3 (---)") - self.state = self.P3 - self.tail = tail - else: - e = edge - tail = None - if e: - self.edges.append(self.tag.mapEdgeToSolid(e)) - return tail - - def intersect(self, edge): - #print("") - #print(" >>> (%s - %s)" % (edge.Curve.StartPoint, edge.Curve.EndPoint)) - if edge and self.state == self.P0: - edge = self.intersectP0(edge) - if edge and self.state == self.P1: - edge = self.intersectP1(edge) - if edge and self.state == self.P2: - edge = self.intersectP2(edge) - return self - - - def splitEdgeAt(self, edge, pt): - p = edge.Curve.parameter(pt) - wire = edge.split(p) - return wire.Edges - - def mapEdgeToSolid(self, edge): - #print("mapEdgeToSolid: (%s %s)" % (edge.Curve.StartPoint, edge.Curve.EndPoint)) - p1a = edge.Curve.StartPoint - p1b = FreeCAD.Vector(p1a.x, p1a.y, p1a.z + self.height) - e1 = Part.Edge(Part.Line(p1a, p1b)) - p1 = self.nextIntersectionClosestTo(e1, self.solid, p1b) # top most intersection - #print(" p1: (%s %s) -> %s" % (p1a, p1b, p1)) - - p2a = edge.Curve.EndPoint - p2b = FreeCAD.Vector(p2a.x, p2a.y, p2a.z + self.height) - e2 = Part.Edge(Part.Line(p2a, p2b)) - p2 = self.nextIntersectionClosestTo(e2, self.solid, p2b) # top most intersection - #print(" p2: (%s %s) -> %s" % (p2a, p2b, p2)) - - if type(edge.Curve) == Part.Line: - return Part.Edge(Part.Line(p1, p2)) - - def filterIntersections(self, pts, face): - if type(face.Surface) == Part.Cone or type(face.Surface) == Part.Cylinder: - return filter(lambda pt: pt.z >= self.bottom() and pt.z <= self.top(), pts) - if type(face.Surface) == Part.Plane: - c = face.Edges[0].Curve - if (type(c) == Part.Circle): - return filter(lambda pt: (pt - c.Center).Length <= c.Radius, pts) - print("==== we got a %s" % face.Surface) - - - def nextIntersectionClosestTo(self, edge, solid, refPt): - pts = [] - for index, face in enumerate(solid.Faces): - i = edge.Curve.intersect(face.Surface)[0] - ps = self.filterIntersections([FreeCAD.Vector(p.X, p.Y, p.Z) for p in i], face) - pts.extend(ps) - if pts: - closest = sorted(pts, key=lambda pt: (pt - refPt).Length)[0] - #print("--pts: %s -> %s" % (pts, closest)) - return closest - return None - - def intersect(self, edge): - inters = self.Intersection(self) - if edge.Curve.StartPoint.z < self.top() or edge.Curve.EndPoint.z < self.top(): - i = self.nextIntersectionClosestTo(edge, self.solid, edge.Curve.StartPoint) - if i: - inters.state = self.Intersection.P0 - inters.p0 = i - if pointsCoincide(i, edge.Curve.EndPoint): - inters.edges.append(edge) - return inters - if pointsCoincide(i, edge.Curve.StartPoint): - tail = edge - else: - e,tail = self.splitEdgeAt(edge, i) - inters.edges.append(e) - return inters.intersect(tail) - # if we get here there is no intersection with the tag - inters.state = self.Intersection.P3 - inters.tail = edge - return inters - -class PathData: - def __init__(self, obj): - self.obj = obj - self.edges = [] - lastPt = FreeCAD.Vector(0, 0, 0) - for cmd in obj.Base.Path.Commands: - if cmd.Name in movecommands: - pt = self.point(cmd, lastPt) - if cmd.Name in movestraight: - self.edges.append(Part.Edge(Part.Line(lastPt, pt))) - elif cmd.Name in movearc: - center = lastPt + self.point(cmd, FreeCAD.Vector(0,0,0), 'I', 'J', 'K') - A = lastPt - center - B = pt - center - d = -B.x * A.y + B.y * A.x - - if d == 0: - # we're dealing with half an circle here - angle = getAngle(A) + math.pi/2 - if cmd.Name in movecw: - angle -= math.pi - else: - #print("(%.2f, %.2f) (%.2f, %.2f)" % (A.x, A.y, B.x, B.y)) - C = A + B - angle = getAngle(C) - - R = (lastPt - center).Length - ptm = center + FreeCAD.Vector(math.cos(angle), math.sin(angle), 0) * R - - self.edges.append(Part.Edge(Part.Arc(lastPt, ptm, pt))) - lastPt = pt - self.base = self.findBottomWire(self.edges) - # determine overall length - self.length = self.base.Length - - def point(self, cmd, pt, X='X', Y='Y', Z='Z'): - x = cmd.Parameters.get(X, pt.x) - y = cmd.Parameters.get(Y, pt.y) - z = cmd.Parameters.get(Z, pt.z) - return FreeCAD.Vector(x, y, z) - - def findBottomWire(self, edges): - (minZ, maxZ) = self.findZLimits(edges) - self.minZ = minZ - self.maxZ = maxZ - bottom = [e for e in edges if e.Vertexes[0].Point.z == minZ and e.Vertexes[1].Point.z == minZ] - wire = Part.Wire(bottom) - if wire.isClosed(): - return Part.Wire(self.sortedBase(bottom)) - # if we get here there are already holding tags, or we're not looking at a profile - # let's try and insert the missing pieces - another day - raise ValueError("Selected path doesn't seem to be a Profile operation.") - - def sortedBase(self, base): - # first find the exit point, where base wire is closed - edges = [e for e in self.edges if e.Curve.StartPoint.z == self.minZ and e.Curve.EndPoint.z != self.maxZ] - exit = sorted(edges, key=lambda e: -e.Curve.EndPoint.z)[0] - pt = exit.Curve.StartPoint - # then find the first base edge, and sort them until done - ordered = [] - while base: - edge = [e for e in base if e.Curve.StartPoint == pt][0] - ordered.append(edge) - base.remove(edge) - pt = edge.Curve.EndPoint - return ordered - - - def findZLimits(self, edges): - # not considering arcs and spheres in Z direction, find the highes and lowest Z values - minZ = edges[0].Vertexes[0].Point.z - maxZ = minZ - for e in edges: - for v in e.Vertexes: - if v.Point.z < minZ: - minZ = v.Point.z - if v.Point.z > maxZ: - maxZ = v.Point.z - return (minZ, maxZ) - - def shortestAndLongestPathEdge(self): - edges = sorted(self.base.Edges, key=lambda e: e.Length) - return (edges[0], edges[-1]) - - def generateTags(self, obj, count=None, width=None, height=None, angle=90, spacing=None): - #print("generateTags(%s, %s, %s, %s, %s)" % (count, width, height, angle, spacing)) - #for e in self.base.Edges: - # debugMarker(e.Vertexes[0].Point, 'base', (0.0, 1.0, 1.0), 0.2) - - if spacing: - tagDistance = spacing - else: - if count: - tagDistance = self.base.Length / count - else: - tagDistance = self.base.Length / 4 - if width: - W = width - else: - W = self.tagWidth() - if height: - H = height - else: - H = self.tagHeight() - - - # start assigning tags on the longest segment - (shortestEdge, longestEdge) = self.shortestAndLongestPathEdge() - startIndex = 0 - for i in range(0, len(self.base.Edges)): - edge = self.base.Edges[i] - if edge.Length == longestEdge.Length: - startIndex = i - break - - startEdge = self.base.Edges[startIndex] - startCount = int(startEdge.Length / tagDistance) - if (longestEdge.Length - shortestEdge.Length) > shortestEdge.Length: - startCount = int(startEdge.Length / tagDistance) + 1 - - lastTagLength = (startEdge.Length + (startCount - 1) * tagDistance) / 2 - currentLength = startEdge.Length - - minLength = min(2. * W, longestEdge.Length) - - #print("length=%.2f shortestEdge=%.2f(%.2f) longestEdge=%.2f(%.2f)" % (self.base.Length, shortestEdge.Length, shortestEdge.Length/self.base.Length, longestEdge.Length, longestEdge.Length / self.base.Length)) - #print(" start: index=%-2d count=%d (length=%.2f, distance=%.2f)" % (startIndex, startCount, startEdge.Length, tagDistance)) - #print(" -> lastTagLength=%.2f)" % lastTagLength) - #print(" -> currentLength=%.2f)" % currentLength) - - edgeDict = { startIndex: startCount } - - for i in range(startIndex + 1, len(self.base.Edges)): - edge = self.base.Edges[i] - (currentLength, lastTagLength) = self.processEdge(i, edge, currentLength, lastTagLength, tagDistance, minLength, edgeDict) - for i in range(0, startIndex): - edge = self.base.Edges[i] - (currentLength, lastTagLength) = self.processEdge(i, edge, currentLength, lastTagLength, tagDistance, minLength, edgeDict) - - tags = [] - - for (i, count) in edgeDict.iteritems(): - edge = self.base.Edges[i] - #print(" %d: %d" % (i, count)) - #debugMarker(edge.Vertexes[0].Point, 'base', (1.0, 0.0, 0.0), 0.2) - #debugMarker(edge.Vertexes[1].Point, 'base', (0.0, 1.0, 0.0), 0.2) - distance = (edge.LastParameter - edge.FirstParameter) / count - for j in range(0, count): - tag = edge.Curve.value((j+0.5) * distance) - tags.append(Tag(tag.x, tag.y, W, H, angle, True)) - - return tags - - def processEdge(self, index, edge, currentLength, lastTagLength, tagDistance, minLength, edgeDict): - tagCount = 0 - currentLength += edge.Length - if edge.Length > minLength: - while lastTagLength + tagDistance < currentLength: - tagCount += 1 - lastTagLength += tagDistance - if tagCount > 0: - #print(" index=%d -> count=%d" % (index, tagCount)) - edgeDict[index] = tagCount - #else: - #print(" skipping=%-2d (%.2f)" % (index, edge.Length)) - - return (currentLength, lastTagLength) - - def tagHeight(self): - return self.maxZ - self.minZ - - def tagWidth(self): - return self.shortestAndLongestPathEdge()[1].Length / 10 - - def tagAngle(self): - return 90 - - def pathLength(self): - return self.base.Length - - def sortedTags(self, tags): - ordered = [] - for edge in self.base.Edges: - ts = [t for t in tags if DraftGeomUtils.isPtOnEdge(t.originAt(self.minZ), edge)] - for t in sorted(ts, key=lambda t: (t.originAt(self.minZ) - edge.Curve.StartPoint).Length): - tags.remove(t) - ordered.append(t) - if tags: - raise ValueError("There's something really wrong here") - return ordered - - -class ObjectDressup: - - def __init__(self, obj): - self.obj = obj - obj.addProperty("App::PropertyLink", "Base","Base", QtCore.QT_TRANSLATE_NOOP("PathDressup_HoldingTags", "The base path to modify")) - obj.addProperty("App::PropertyStringList", "Tags", "Tag", QtCore.QT_TRANSLATE_NOOP("PathDressup_holdingTags", "Inserted tags")) - obj.setEditorMode("Tags", 2) - obj.Proxy = self - - def __getstate__(self): - return None - - def __setstate__(self, state): - return None - - def generateTags(self, obj, count=None, width=None, height=None, angle=90, spacing=None): - return self.pathData.generateTags(obj, count, width, height, angle, spacing) - - - def tagIntersection(self, face, edge): - p1 = edge.Curve.StartPoint - pts = edge.Curve.intersect(face.Surface) - if pts[0]: - closest = sorted(pts[0], key=lambda pt: (pt - p1).Length)[0] - return closest - return None - - def createPath(self, edges, tagSolids): - commands = [] - i = 0 - while i != len(edges): - edge = edges[i] - while edge: - for solid in tagSolids: - for face in solid.Faces: - pt = self.tagIntersection(face, edge) - if pt: - if pt == edge.Curve.StartPoint: - pt - elif pt != edge.Curve.EndPoint: - parameter = edge.Curve.parameter(pt) - wire = edge.split(parameter) - commands.append(pathCommandForEdge(wire.Edges[0])) - edge = wire.Edges[1] - break; - else: - commands.append(pathCommandForEdge(edge)) - edge = None - i += 1 - break - if not edge: - break - if edge: - commands.append(pathCommandForEdge(edge)) - edge = None - return self.obj.Path - - - def execute(self, obj): - if not obj.Base: - return - if not obj.Base.isDerivedFrom("Path::Feature"): - return - if not obj.Base.Path: - return - if not obj.Base.Path.Commands: - return - - pathData = self.setup(obj) - if not pathData: - print("execute - no pathData") - return - - if hasattr(obj, 'Tags') and obj.Tags: - if self.fingerprint == obj.Tags: - print("execute - cache valid") - return - print("execute - tags from property") - tags = [Tag.FromString(tag) for tag in obj.Tags] - else: - print("execute - default tags") - tags = self.generateTags(obj, 4.) - - if not tags: - print("execute - no tags") - self.tags = [] - obj.Path = obj.Base.Path - return - - tagID = 0 - for tag in tags: - tagID += 1 - if tag.enabled: - #print("x=%s, y=%s, z=%s" % (tag.x, tag.y, pathData.minZ)) - debugMarker(FreeCAD.Vector(tag.x, tag.y, pathData.minZ), "tag-%02d" % tagID , (1.0, 0.0, 1.0), 0.5) - - tags = pathData.sortedTags(tags) - for tag in tags: - tag.createSolidsAt(pathData.minZ) - - self.fingerprint = [tag.toString() for tag in tags] - self.tags = tags - - #obj.Path = self.createPath(pathData.edges, tags) - obj.Path = self.Base.Path - - def setTags(self, obj, tags): - obj.Tags = [tag.toString() for tag in tags] - self.execute(obj) - - def getTags(self, obj): - if hasattr(self, 'tags'): - return self.tags - return self.setup(obj).generateTags(obj, 4) - - def setup(self, obj): - if not hasattr(self, "pathData") or not self.pathData: - try: - pathData = PathData(obj) - except ValueError: - FreeCAD.Console.PrintError(translate("PathDressup_HoldingTags", "Cannot insert holding tags for this path - please select a Profile path\n")) - return None - - ## setup the object's properties, in case they're not set yet - #obj.Count = self.tagCount(obj) - #obj.Angle = self.tagAngle(obj) - #obj.Blacklist = self.tagBlacklist(obj) - - # if the heigt isn't set, use the height of the path - #if not hasattr(obj, "Height") or not obj.Height: - # obj.Height = pathData.maxZ - pathData.minZ - # try and take an educated guess at the width - #if not hasattr(obj, "Width") or not obj.Width: - # width = sorted(pathData.base.Edges, key=lambda e: -e.Length)[0].Length / 10 - # while obj.Count > len([e for e in pathData.base.Edges if e.Length > 3*width]): - # width = widht / 2 - # obj.Width = width - - # and the tool radius, not sure yet if it's needed - #self.toolRadius = 5 - #toolLoad = PathUtils.getLastToolLoad(obj) - #if toolLoad is None or toolLoad.ToolNumber == 0: - # self.toolRadius = 5 - #else: - # tool = PathUtils.getTool(obj, toolLoad.ToolNumber) - # if not tool or tool.Diameter == 0: - # self.toolRadius = 5 - # else: - # self.toolRadius = tool.Diameter / 2 - self.pathData = pathData - return self.pathData - - def getHeight(self, obj): - return self.pathData.tagHeight() - - def getWidth(self, obj): - return self.pathData.tagWidth() - - def getAngle(self, obj): - return self.pathData.tagAngle() - - def getPathLength(self, obj): - return self.pathData.pathLength() - -class TaskPanel: - DataTag = QtCore.Qt.ItemDataRole.UserRole - DataValue = QtCore.Qt.ItemDataRole.DisplayRole - - def __init__(self, obj): - self.obj = obj - self.form = FreeCADGui.PySideUic.loadUi(":/panels/HoldingTagsEdit.ui") - FreeCAD.ActiveDocument.openTransaction(translate("PathDressup_HoldingTags", "Edit HoldingTags Dress-up")) - - def reject(self): - FreeCAD.ActiveDocument.abortTransaction() - FreeCADGui.Control.closeDialog() - FreeCAD.ActiveDocument.recompute() - FreeCADGui.Selection.removeObserver(self.s) - - def accept(self): - FreeCAD.ActiveDocument.commitTransaction() - FreeCADGui.ActiveDocument.resetEdit() - FreeCADGui.Control.closeDialog() - FreeCAD.ActiveDocument.recompute() - FreeCADGui.Selection.removeObserver(self.s) - FreeCAD.ActiveDocument.recompute() - - def open(self): - self.s = SelObserver() - # install the function mode resident - FreeCADGui.Selection.addObserver(self.s) - - def tableWidgetItem(self, tag, val): - item = QtGui.QTableWidgetItem() - item.setTextAlignment(QtCore.Qt.AlignRight) - item.setData(self.DataTag, tag) - item.setData(self.DataValue, val) - return item - - def getFields(self): - tags = [] - for row in range(0, self.form.twTags.rowCount()): - x = self.form.twTags.item(row, 0).data(self.DataValue) - y = self.form.twTags.item(row, 1).data(self.DataValue) - w = self.form.twTags.item(row, 2).data(self.DataValue) - h = self.form.twTags.item(row, 3).data(self.DataValue) - a = self.form.twTags.item(row, 4).data(self.DataValue) - tags.append(Tag(x, y, w, h, a, True)) - print("getFields: %d" % (len(tags))) - self.obj.Proxy.setTags(self.obj, tags) - - def updateTags(self): - self.tags = self.obj.Proxy.getTags(self.obj) - self.form.twTags.blockSignals(True) - self.form.twTags.setSortingEnabled(False) - self.form.twTags.clearSpans() - print("updateTags: %d" % (len(self.tags))) - self.form.twTags.setRowCount(len(self.tags)) - for row, tag in enumerate(self.tags): - self.form.twTags.setItem(row, 0, self.tableWidgetItem(tag, tag.x)) - self.form.twTags.setItem(row, 1, self.tableWidgetItem(tag, tag.y)) - self.form.twTags.setItem(row, 2, self.tableWidgetItem(tag, tag.width)) - self.form.twTags.setItem(row, 3, self.tableWidgetItem(tag, tag.height)) - self.form.twTags.setItem(row, 4, self.tableWidgetItem(tag, tag.angle)) - self.form.twTags.setSortingEnabled(True) - self.form.twTags.blockSignals(False) - - def cleanupUI(self): - print("cleanupUI") - if debugDressup: - for obj in FreeCAD.ActiveDocument.Objects: - if obj.Name.startswith('tag'): - FreeCAD.ActiveDocument.removeObject(obj.Name) - - def updateUI(self): - print("updateUI") - self.cleanupUI() - self.getFields() - if debugDressup: - FreeCAD.ActiveDocument.recompute() - - - def whenApplyClicked(self): - print("whenApplyClicked") - self.cleanupUI() - - count = self.form.sbCount.value() - spacing = self.form.dsbSpacing.value() - width = self.form.dsbWidth.value() - height = self.form.dsbHeight.value() - angle = self.form.dsbAngle.value() - - tags = self.obj.Proxy.generateTags(self.obj, count, width, height, angle, spacing * 0.99) - - self.obj.Proxy.setTags(self.obj, tags) - self.updateTags() - if debugDressup: - # this causes a big of an echo and a double click on the spin buttons, don't know why though - FreeCAD.ActiveDocument.recompute() - - def autoApply(self): - print("autoApply") - if self.form.cbAutoApply.checkState() == QtCore.Qt.CheckState.Checked: - self.whenApplyClicked() - - def updateTagSpacing(self, count): - print("updateTagSpacing") - if count == 0: - spacing = 0 - else: - spacing = self.pathLength / count - self.form.dsbSpacing.blockSignals(True) - self.form.dsbSpacing.setValue(spacing) - self.form.dsbSpacing.blockSignals(False) - - def whenCountChanged(self): - print("whenCountChanged") - self.updateTagSpacing(self.form.sbCount.value()) - self.autoApply() - - def whenSpacingChanged(self): - print("whenSpacingChanged") - if self.form.dsbSpacing.value() == 0: - count = 0 - else: - count = int(self.pathLength / self.form.dsbSpacing.value()) - self.form.sbCount.blockSignals(True) - self.form.sbCount.setValue(count) - self.form.sbCount.blockSignals(False) - self.autoApply() - - def whenOkClicked(self): - print("whenOkClicked") - self.whenApplyClicked() - self.form.toolBox.setCurrentWidget(self.form.tbpTags) - - def setupSpinBox(self, widget, val, decimals = 2): - widget.setMinimum(0) - if decimals: - widget.setDecimals(decimals) - widget.setValue(val) - - def setFields(self): - self.pathLength = self.obj.Proxy.getPathLength(self.obj) - vHeader = self.form.twTags.verticalHeader() - vHeader.setResizeMode(QtGui.QHeaderView.Fixed) - vHeader.setDefaultSectionSize(20) - self.updateTags() - self.setupSpinBox(self.form.sbCount, self.form.twTags.rowCount(), None) - self.setupSpinBox(self.form.dsbSpacing, 0) - self.setupSpinBox(self.form.dsbHeight, self.obj.Proxy.getHeight(self.obj)) - self.setupSpinBox(self.form.dsbWidth, self.obj.Proxy.getWidth(self.obj)) - self.setupSpinBox(self.form.dsbAngle, self.obj.Proxy.getAngle(self.obj)) - self.updateTagSpacing(self.form.twTags.rowCount()) - - def setupUi(self): - self.setFields() - self.form.sbCount.valueChanged.connect(self.whenCountChanged) - self.form.dsbSpacing.valueChanged.connect(self.whenSpacingChanged) - self.form.dsbHeight.valueChanged.connect(self.autoApply) - self.form.dsbWidth.valueChanged.connect(self.autoApply) - self.form.dsbAngle.valueChanged.connect(self.autoApply) - #self.form.pbAdd.clicked.connect(self.) - self.form.buttonBox.button(QtGui.QDialogButtonBox.Apply).clicked.connect(self.whenApplyClicked) - self.form.buttonBox.button(QtGui.QDialogButtonBox.Ok).clicked.connect(self.whenOkClicked) - self.form.twTags.itemChanged.connect(self.updateUI) - -class SelObserver: - def __init__(self): - import PathScripts.PathSelection as PST - PST.eselect() - - def __del__(self): - import PathScripts.PathSelection as PST - PST.clear() - - def addSelection(self, doc, obj, sub, pnt): - FreeCADGui.doCommand('Gui.Selection.addSelection(FreeCAD.ActiveDocument.' + obj + ')') - FreeCADGui.updateGui() - -class ViewProviderDressup: - - def __init__(self, vobj): - vobj.Proxy = self - - def attach(self, vobj): - self.Object = vobj.Object - return - - def claimChildren(self): - for i in self.Object.Base.InList: - if hasattr(i, "Group"): - group = i.Group - for g in group: - if g.Name == self.Object.Base.Name: - group.remove(g) - i.Group = group - print i.Group - #FreeCADGui.ActiveDocument.getObject(obj.Base.Name).Visibility = False - return [self.Object.Base] - - def setEdit(self, vobj, mode=0): - FreeCADGui.Control.closeDialog() - panel = TaskPanel(vobj.Object) - FreeCADGui.Control.showDialog(panel) - panel.setupUi() - return True - - def __getstate__(self): - return None - - def __setstate__(self, state): - return None - - def onDelete(self, arg1=None, arg2=None): - '''this makes sure that the base operation is added back to the project and visible''' - FreeCADGui.ActiveDocument.getObject(arg1.Object.Base.Name).Visibility = True - PathUtils.addToJob(arg1.Object.Base) - return True - -class CommandPathDressupHoldingTags: - - def GetResources(self): - return {'Pixmap': 'Path-Dressup', - 'MenuText': QtCore.QT_TRANSLATE_NOOP("PathDressup_HoldingTags", "HoldingTags Dress-up"), - 'ToolTip': QtCore.QT_TRANSLATE_NOOP("PathDressup_HoldingTags", "Creates a HoldingTags Dress-up object from a selected path")} - - def IsActive(self): - if FreeCAD.ActiveDocument is not None: - for o in FreeCAD.ActiveDocument.Objects: - if o.Name[:3] == "Job": - return True - return False - - def Activated(self): - - # check that the selection contains exactly what we want - selection = FreeCADGui.Selection.getSelection() - if len(selection) != 1: - FreeCAD.Console.PrintError(translate("PathDressup_HoldingTags", "Please select one path object\n")) - return - baseObject = selection[0] - if not baseObject.isDerivedFrom("Path::Feature"): - FreeCAD.Console.PrintError(translate("PathDressup_HoldingTags", "The selected object is not a path\n")) - return - if baseObject.isDerivedFrom("Path::FeatureCompoundPython"): - FreeCAD.Console.PrintError(translate("PathDressup_HoldingTags", "Please select a Profile object")) - return - - # everything ok! - FreeCAD.ActiveDocument.openTransaction(translate("PathDressup_HoldingTags", "Create HoldingTags Dress-up")) - FreeCADGui.addModule("PathScripts.PathDressupHoldingTags") - FreeCADGui.addModule("PathScripts.PathUtils") - FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", "HoldingTagsDressup")') - FreeCADGui.doCommand('dbo = PathScripts.PathDressupHoldingTags.ObjectDressup(obj)') - FreeCADGui.doCommand('obj.Base = FreeCAD.ActiveDocument.' + selection[0].Name) - FreeCADGui.doCommand('PathScripts.PathDressupHoldingTags.ViewProviderDressup(obj.ViewObject)') - FreeCADGui.doCommand('PathScripts.PathUtils.addToJob(obj)') - FreeCADGui.doCommand('Gui.ActiveDocument.getObject(obj.Base.Name).Visibility = False') - FreeCADGui.doCommand('dbo.setup(obj)') - FreeCAD.ActiveDocument.commitTransaction() - FreeCAD.ActiveDocument.recompute() - -if FreeCAD.GuiUp: - # register the FreeCAD command - FreeCADGui.addCommand('PathDressup_HoldingTags', CommandPathDressupHoldingTags()) - -FreeCAD.Console.PrintLog("Loading PathDressupHoldingTags... done\n") diff --git a/src/Mod/Path/PathScripts/PathGeom.py b/src/Mod/Path/PathScripts/PathGeom.py index e4d176717..4ce9b08ab 100644 --- a/src/Mod/Path/PathScripts/PathGeom.py +++ b/src/Mod/Path/PathScripts/PathGeom.py @@ -65,11 +65,12 @@ class Side: class PathGeom: """Class to transform Path Commands into Edges and Wire and back again. The interface might eventuallly become part of Path itself.""" + CmdMoveFast = ['G0', 'G00'] CmdMoveStraight = ['G1', 'G01'] - CmdMoveCW = ['G2', 'G02'] - CmdMoveCCW = ['G3', 'G03'] - CmdMoveArc = CmdMoveCW + CmdMoveCCW - CmdMove = CmdMoveStraight + CmdMoveArc + CmdMoveCW = ['G2', 'G02'] + CmdMoveCCW = ['G3', 'G03'] + CmdMoveArc = CmdMoveCW + CmdMoveCCW + CmdMove = CmdMoveStraight + CmdMoveArc @classmethod def getAngle(cls, vertex): @@ -108,11 +109,11 @@ class PathGeom: return Vector(pt.x, pt.y, 0) @classmethod - def edgeForCmd(cls, cmd, startPoint): + def edgeForCmd(cls, cmd, startPoint, includeFastMoves = False): """Returns a Curve representing the givne command, assuming a given startinPoint.""" endPoint = cls.commandEndPoint(cmd, startPoint) - if cmd.Name in cls.CmdMoveStraight: + if (cmd.Name in cls.CmdMoveStraight) or (includeFastMoves and cmd.Name in cls.CmdMoveFast): return Part.Edge(Part.Line(startPoint, endPoint)) if cmd.Name in cls.CmdMoveArc: @@ -155,5 +156,35 @@ class PathGeom: e = helix.Edges[0] helix.translate(startPoint - e.valueAt(e.FirstParameter)) return helix.Edges[0] + return None + @classmethod + def wireForPath(cls, path, startPoint = FreeCAD.Vector(0, 0, 0)): + """Returns a wire representing all move commands found in the given path.""" + edges = [] + if hasattr(path, "Commands"): + for cmd in path.Commands: + edge = cls.edgeForCmd(cmd, startPoint, True) + if edge: + edges.append(edge) + startPoint = cls.commandEndPoint(cmd, startPoint) + return Part.Wire(edges) + + @classmethod + def wiresForPath(cls, path, startPoint = FreeCAD.Vector(0, 0, 0)): + """Returns a collection of wires, each representing a continuous cutting Path in path.""" + wires = [] + if hasattr(path, "Commands"): + edges = [] + for cmd in path.Commands: + if cmd.Name in cls.CmdMove: + edges.append(cls.edgeForCmd(cmd, startPoint, False)) + startPoint = cls.commandEndPoint(cmd, startPoint) + elif cmd.Name in cls.CmdMoveFast: + wires.append(Part.Wire(edges)) + edges = [] + startPoint = cls.commandEndPoint(cmd, startPoint) + if edges: + wires.append(Part.Wire(edges)) + return wires diff --git a/src/Mod/Path/PathTests/TestPathDressupHoldingTags.py b/src/Mod/Path/PathTests/TestPathDressupHoldingTags.py deleted file mode 100644 index d6adb06d0..000000000 --- a/src/Mod/Path/PathTests/TestPathDressupHoldingTags.py +++ /dev/null @@ -1,639 +0,0 @@ -# -*- coding: utf-8 -*- - -# *************************************************************************** -# * * -# * Copyright (c) 2016 sliptonic * -# * * -# * 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 * -# * * -# *************************************************************************** - -import FreeCAD -import Part -import Path -import PathScripts -import math -import unittest - -from FreeCAD import Vector -from PathScripts.PathDressupHoldingTags import * - -def pointsCoincide(pt1, pt2): - pt = pt1 - pt2 - if math.fabs(pt.x) > slack: - return False - if math.fabs(pt.y) > slack: - return False - if math.fabs(pt.z) > slack: - return False - return True - -class TagTestCaseBase(unittest.TestCase): - """Base class for all tag test cases providing additional assert functions.""" - - def assertCylinderAt(self, solid, pt, r, h): - """Verify that solid is a cylinder at the specified location.""" - self.assertEqual(len(solid.Edges), 3) - - lid = solid.Edges[0] - hull = solid.Edges[1] - base = solid.Edges[2] - - self.assertCircle(lid, Vector(pt.x, pt.y, pt.z+h), r) - self.assertLine(hull, Vector(pt.x+r, pt.y, pt.z), Vector(pt.x+r, pt.y, pt.z+h)) - self.assertCircle(base, Vector(pt.x, pt.y, pt.z), r) - - def assertConeAt(self, solid, pt, r1, r2, h): - """Verify that solid is a cone at the specified location.""" - self.assertEqual(len(solid.Edges), 3) - - lid = solid.Edges[0] - hull = solid.Edges[1] - base = solid.Edges[2] - - self.assertCircle(lid, Vector(pt.x, pt.y, pt.z+h), r2) - self.assertLine(hull, Vector(pt.x+r1, pt.y, pt.z), Vector(pt.x+r2, pt.y, pt.z+h)) - self.assertCircle(base, Vector(pt.x, pt.y, pt.z), r1) - - def assertCircle(self, edge, pt, r): - """Verivy that edge is a circle at given location.""" - curve = edge.Curve - self.assertIs(type(curve), Part.Circle) - self.assertCoincide(curve.Center, Vector(pt.x, pt.y, pt.z)) - self.assertAbout(curve.Radius, r) - - def assertLine(self, edge, pt1, pt2): - """Verify that edge is a line from pt1 to pt2.""" - curve = edge.Curve - self.assertIs(type(curve), Part.Line) - self.assertCoincide(curve.StartPoint, pt1) - self.assertCoincide(curve.EndPoint, pt2) - - def assertCoincide(self, pt1, pt2): - """Verify that 2 points coincide (with tolerance).""" - self.assertAbout(pt1.x, pt2.x) - self.assertAbout(pt1.y, pt2.y) - self.assertAbout(pt1.z, pt2.z) - - def assertAbout(self, v1, v2): - """Verify that 2 values are the same (accounting for float imprecision).""" - if math.fabs(v1 - v2) > slack: - self.fail("%f != %f" % (v1, v2)) - - def assertLines(self, edgs, tail, points): - """Check that there are 5 edges forming a trapezoid.""" - edges = list(edgs) - if tail: - edges.append(tail) - self.assertEqual(len(edges), len(points) - 1) - - for i in range(0, len(edges)): - self.assertLine(edges[i], points[i], points[i+1]) - -class TestTag00BasicHolding(TagTestCaseBase): - """Some basid test cases.""" - - def test00(self,x=1, y=1): - """Test getAngle.""" - self.assertAbout(getAngle(FreeCAD.Vector( 1*x, 0*y, 0)), 0) - self.assertAbout(getAngle(FreeCAD.Vector( 1*x, 1*y, 0)), math.pi/4) - self.assertAbout(getAngle(FreeCAD.Vector( 0*x, 1*y, 0)), math.pi/2) - self.assertAbout(getAngle(FreeCAD.Vector(-1*x, 1*y, 0)), 3*math.pi/4) - self.assertAbout(getAngle(FreeCAD.Vector(-1*x, 0*y, 0)), math.pi) - self.assertAbout(getAngle(FreeCAD.Vector(-1*x,-1*y, 0)), -3*math.pi/4) - self.assertAbout(getAngle(FreeCAD.Vector( 0*x,-1*y, 0)), -math.pi/2) - self.assertAbout(getAngle(FreeCAD.Vector( 1*x,-1*y, 0)), -math.pi/4) - - def test01(self): - """Test class Side.""" - self.assertEqual(Side.of(FreeCAD.Vector( 1, 0, 0), FreeCAD.Vector( 1, 0, 0)), Side.On) - self.assertEqual(Side.of(FreeCAD.Vector( 1, 0, 0), FreeCAD.Vector(-1, 0, 0)), Side.On) - self.assertEqual(Side.of(FreeCAD.Vector( 1, 0, 0), FreeCAD.Vector( 0, 1, 0)), Side.Left) - self.assertEqual(Side.of(FreeCAD.Vector( 1, 0, 0), FreeCAD.Vector( 0,-1, 0)), Side.Right) - - -class TestTag01BasicTag(TagTestCaseBase): # ============= - """Unit tests for the HoldingTags dressup.""" - - def test00(self): - """Check Tag origin, serialization and de-serialization.""" - tag = Tag(77, 13, 4, 5, 90, True) - self.assertCoincide(tag.originAt(3), Vector(77, 13, 3)) - s = tag.toString() - tagCopy = Tag.FromString(s) - self.assertEqual(tag.x, tagCopy.x) - self.assertEqual(tag.y, tagCopy.y) - self.assertEqual(tag.height, tagCopy.height) - self.assertEqual(tag.width, tagCopy.width) - self.assertEqual(tag.enabled, tagCopy.enabled) - - - def test01(self): - """Verify solid and core for a 90 degree tag are identical cylinders.""" - tag = Tag(100, 200, 4, 5, 90, True) - tag.createSolidsAt(17) - - self.assertIsNotNone(tag.solid) - self.assertCylinderAt(tag.solid, Vector(100, 200, 17), 2, 5) - - self.assertIsNotNone(tag.core) - self.assertCylinderAt(tag.core, Vector(100, 200, 17), 2, 5) - - def test02(self): - """Verify trapezoidal tag has a cone shape with a lid, and cylinder core.""" - tag = Tag(0, 0, 18, 5, 45, True) - tag.createSolidsAt(0) - - self.assertIsNotNone(tag.solid) - self.assertConeAt(tag.solid, Vector(0,0,0), 9, 4, 5) - - self.assertIsNotNone(tag.core) - self.assertCylinderAt(tag.core, Vector(0,0,0), 4, 5) - - def test03(self): - """Verify pointy cone shape of tag with pointy end if width, angle and height match up.""" - tag = Tag(0, 0, 10, 5, 45, True) - tag.createSolidsAt(0) - self.assertIsNotNone(tag.solid) - self.assertConeAt(tag.solid, Vector(0,0,0), 5, 0, 5) - - self.assertIsNone(tag.core) - - def test04(self): - """Verify height adjustment if tag isn't wide eough for angle.""" - tag = Tag(0, 0, 5, 17, 60, True) - tag.createSolidsAt(0) - self.assertIsNotNone(tag.solid) - self.assertConeAt(tag.solid, Vector(0,0,0), 2.5, 0, 2.5 * math.tan((60/180.0)*math.pi)) - - self.assertIsNone(tag.core) - -class TestTag02SquareTag(TagTestCaseBase): # ============= - """Unit tests for square tags.""" - - def test00(self): - """Verify no intersection.""" - tag = Tag( 0, 0, 4, 7, 90, True, 0) - pt1 = Vector(+5, 5, 0) - pt2 = Vector(-5, 5, 0) - edge = Part.Edge(Part.Line(pt1, pt2)) - - i = tag.intersect(edge) - self.assertIsNotNone(i) - self.assertTrue(i.isComplete()) - self.assertIsNotNone(i.edges) - self.assertFalse(i.edges) - self.assertLine(i.tail, pt1, pt2) - - def test01(self): - """Verify intersection of square tag with line ending at tag start.""" - tag = Tag( 0, 0, 8, 3, 90, True, 0) - edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(4, 0, 0))) - - i = tag.intersect(edge) - self.assertEqual(i.state, Tag.Intersection.P0) - self.assertEqual(len(i.edges), 1) - self.assertLine(i.edges[0], edge.Curve.StartPoint, edge.Curve.EndPoint) - self.assertIsNone(i.tail) - - def test02(self): - """Verify intersection of square tag with line ending between P1 and P2.""" - tag = Tag( 0, 0, 8, 3, 90, True, 0) - edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(1, 0, 0))) - - i = tag.intersect(edge) - self.assertEqual(i.state, Tag.Intersection.P1) - self.assertEqual(len(i.edges), 3) - p1 = Vector(4, 0, 0) - p2 = Vector(4, 0, 3) - p3 = Vector(1, 0, 3) - self.assertLine(i.edges[0], edge.Curve.StartPoint, p1) - self.assertLine(i.edges[1], p1, p2) - self.assertLine(i.edges[2], p2, p3) - self.assertIsNone(i.tail) - - # verify we stay in P1 if we add another segment - edge = Part.Edge(Part.Line(edge.Curve.EndPoint, Vector(0, 0, 0))) - i = i.intersect(edge) - self.assertEqual(i.state, Tag.Intersection.P1) - self.assertEqual(len(i.edges), 4) - p4 = Vector(0, 0, 3) - self.assertLine(i.edges[3], p3, p4) - self.assertIsNone(i.tail) - - def test03(self): - """Verify intesection of square tag with line ending on P2.""" - tag = Tag( 0, 0, 8, 3, 90, True, 0) - edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(-4, 0, 0))) - - i = tag.intersect(edge) - self.assertEqual(i.state, Tag.Intersection.P2) - self.assertEqual(len(i.edges), 3) - p0 = edge.Curve.StartPoint - p1 = Vector( 4, 0, 0) - p2 = Vector( 4, 0, 3) - p3 = Vector(-4, 0, 3) - self.assertLine(i.edges[0], p0, p1) - self.assertLine(i.edges[1], p1, p2) - self.assertLine(i.edges[2], p2, p3) - self.assertIsNone(i.tail) - - # make sure it also works if we get there not directly - edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(0, 0, 0))) - i = tag.intersect(edge) - edge = Part.Edge(Part.Line(edge.Curve.EndPoint, Vector(-4, 0, 0))) - i = i.intersect(edge) - self.assertEqual(i.state, Tag.Intersection.P2) - self.assertEqual(len(i.edges), 4) - p2a = Vector( 0, 0, 3) - self.assertLine(i.edges[0], p0, p1) - self.assertLine(i.edges[1], p1, p2) - self.assertLine(i.edges[2], p2, p2a) - self.assertLine(i.edges[3], p2a, p3) - self.assertIsNone(i.tail) - - def test04(self): - """Verify plunge down is inserted for square tag on exit.""" - tag = Tag( 0, 0, 8, 3, 90, True, 0) - edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(-5, 0, 0))) - - i = tag.intersect(edge) - self.assertEqual(i.state, Tag.Intersection.P3) - self.assertTrue(i.isComplete()) - self.assertEqual(len(i.edges), 4) - p0 = edge.Curve.StartPoint - p1 = Vector( 4, 0, 0) - p2 = Vector( 4, 0, 3) - p3 = Vector(-4, 0, 3) - p4 = Vector(-4, 0, 0) - p5 = edge.Curve.EndPoint - self.assertLine(i.edges[0], p0, p1) - self.assertLine(i.edges[1], p1, p2) - self.assertLine(i.edges[2], p2, p3) - self.assertLine(i.edges[3], p3, p4) - self.assertIsNotNone(i.tail) - self.assertLine(i.tail, p4, p5) - - def test05(self): - """Verify all lines between P0 and P3 are added.""" - tag = Tag( 0, 0, 4, 7, 90, True, 0) - e0 = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(+2, 0, 0))) - e1 = Part.Edge(Part.Line(e0.Curve.EndPoint, Vector(+1, 0, 0))) - e2 = Part.Edge(Part.Line(e1.Curve.EndPoint, Vector(+0.5, 0, 0))) - e3 = Part.Edge(Part.Line(e2.Curve.EndPoint, Vector(-0.5, 0, 0))) - e4 = Part.Edge(Part.Line(e3.Curve.EndPoint, Vector(-1, 0, 0))) - e5 = Part.Edge(Part.Line(e4.Curve.EndPoint, Vector(-2, 0, 0))) - e6 = Part.Edge(Part.Line(e5.Curve.EndPoint, Vector(-5, 0, 0))) - - i = tag - for e in [e0, e1, e2, e3, e4, e5]: - i = i.intersect(e) - self.assertFalse(i.isComplete()) - i = i.intersect(e6) - self.assertTrue(i.isComplete()) - - pt0 = Vector(2, 0, 0) - pt1 = Vector(2, 0, 7) - pt2 = Vector(1, 0, 7) - pt3 = Vector(0.5, 0, 7) - pt4 = Vector(-0.5, 0, 7) - pt5 = Vector(-1, 0, 7) - pt6 = Vector(-2, 0, 7) - - self.assertEqual(len(i.edges), 8) - self.assertLines(i.edges, i.tail, [e0.Curve.StartPoint, pt0, pt1, pt2, pt3, pt4, pt5, pt6, e6.Curve.StartPoint, e6.Curve.EndPoint]) - self.assertIsNotNone(i.tail) - - def test06(self): - """Verify intersection of different z levels.""" - tag = Tag( 0, 0, 4, 7, 90, True, 0) - # for all lines below 7 we get the trapezoid - for i in range(0, 7): - p0 = Vector(5, 0, i) - p1 = Vector(2, 0, i) - p2 = Vector(2, 0, 7) - p3 = Vector(-2, 0, 7) - p4 = Vector(-2, 0, i) - p5 = Vector(-5, 0, i) - edge = Part.Edge(Part.Line(p0, p5)) - s = tag.intersect(edge) - self.assertTrue(s.isComplete()) - self.assertLines(s.edges, s.tail, [p0, p1, p2, p3, p4, p5]) - - # for all edges at height or above the original line is used - for i in range(7, 9): - edge = Part.Edge(Part.Line(Vector(5, 0, i), Vector(-5, 0, i))) - s = tag.intersect(edge) - self.assertTrue(s.isComplete()) - self.assertLine(s.tail, edge.Curve.StartPoint, edge.Curve.EndPoint) - -class TestTag03TrapezoidTag(TagTestCaseBase): # ============= - """Unit tests for trapezoid tags.""" - - def test00(self): - """Verify no intersection.""" - tag = Tag( 0, 0, 8, 3, 45, True, 0) - pt1 = Vector(+5, 5, 0) - pt2 = Vector(-5, 5, 0) - edge = Part.Edge(Part.Line(pt1, pt2)) - - i = tag.intersect(edge) - self.assertIsNotNone(i) - self.assertTrue(i.isComplete()) - self.assertIsNotNone(i.edges) - self.assertFalse(i.edges) - self.assertLine(i.tail, pt1, pt2) - - def test01(self): - """Veify intersection of trapezoid tag with line ending before P1.""" - tag = Tag( 0, 0, 8, 3, 45, True, 0) - edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(4, 0, 0))) - - i = tag.intersect(edge) - self.assertEqual(i.state, Tag.Intersection.P0) - self.assertEqual(len(i.edges), 1) - self.assertLine(i.edges[0], edge.Curve.StartPoint, edge.Curve.EndPoint) - self.assertIsNone(i.tail) - - # now add another segment that doesn't reach the top of the cone - edge = Part.Edge(Part.Line(edge.Curve.EndPoint, Vector(3, 0, 0))) - i = i.intersect(edge) - # still a P0 and edge fully consumed - p1 = Vector(edge.Curve.StartPoint) - p1.z = 0 - p2 = Vector(edge.Curve.EndPoint) - p2.z = 1 # height of cone @ (3,0) - self.assertEqual(i.state, Tag.Intersection.P0) - self.assertEqual(len(i.edges), 2) - self.assertLine(i.edges[1], p1, p2) - self.assertIsNone(i.tail) - - # add another segment to verify starting point offset - edge = Part.Edge(Part.Line(edge.Curve.EndPoint, Vector(2, 0, 0))) - i = i.intersect(edge) - # still a P0 and edge fully consumed - p3 = Vector(edge.Curve.EndPoint) - p3.z = 2 # height of cone @ (2,0) - self.assertEqual(i.state, Tag.Intersection.P0) - self.assertEqual(len(i.edges), 3) - self.assertLine(i.edges[2], p2, p3) - self.assertIsNone(i.tail) - - def test02(self): - """Verify intersection of trapezoid tag with line ending between P1 and P2""" - tag = Tag( 0, 0, 8, 3, 45, True, 0) - edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(1, 0, 0))) - - i = tag.intersect(edge) - self.assertEqual(i.state, Tag.Intersection.P1) - self.assertEqual(len(i.edges), 2) - p1 = Vector(4, 0, 0) - p2 = Vector(1, 0, 3) - self.assertLine(i.edges[0], edge.Curve.StartPoint, p1) - self.assertLine(i.edges[1], p1, p2) - self.assertIsNone(i.tail) - - # verify we stay in P1 if we add another segment - edge = Part.Edge(Part.Line(edge.Curve.EndPoint, Vector(0, 0, 0))) - i = i.intersect(edge) - self.assertEqual(i.state, Tag.Intersection.P1) - self.assertEqual(len(i.edges), 3) - p3 = Vector(0, 0, 3) - self.assertLine(i.edges[2], p2, p3) - self.assertIsNone(i.tail) - - def test03(self): - """Verify intersection of trapezoid tag with edge ending on P2.""" - tag = Tag( 0, 0, 8, 3, 45, True, 0) - edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(-1, 0, 0))) - - i = tag.intersect(edge) - self.assertEqual(i.state, Tag.Intersection.P2) - p0 = Vector(edge.Curve.StartPoint) - p1 = Vector(4, 0, 0) - p2 = Vector(1, 0, 3) - p3 = Vector(-1, 0, 3) - self.assertLines(i.edges, i.tail, [p0, p1, p2, p3]) - self.assertIsNone(i.tail) - - # make sure we get the same result if there's another edge - edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(1, 0, 0))) - i = tag.intersect(edge) - edge = Part.Edge(Part.Line(edge.Curve.EndPoint, Vector(-1, 0, 0))) - i = i.intersect(edge) - self.assertEqual(i.state, Tag.Intersection.P2) - self.assertLines(i.edges, i.tail, [p0, p1, p2, p3]) - self.assertIsNone(i.tail) - - # and also if the last segment doesn't cross the entire plateau - edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(0.5, 0, 0))) - i = tag.intersect(edge) - edge = Part.Edge(Part.Line(edge.Curve.EndPoint, Vector(-1, 0, 0))) - i = i.intersect(edge) - self.assertEqual(i.state, Tag.Intersection.P2) - p2a = Vector(0.5, 0, 3) - self.assertLines(i.edges, i.tail, [p0, p1, p2, p2a, p3]) - self.assertIsNone(i.tail) - - def test04(self): - """Verify proper down plunge on trapezoid tag exit.""" - tag = Tag( 0, 0, 8, 3, 45, True, 0) - edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(-2, 0, 0))) - - i = tag.intersect(edge) - self.assertEqual(i.state, Tag.Intersection.P2) - p0 = Vector(5, 0, 0) - p1 = Vector(4, 0, 0) - p2 = Vector(1, 0, 3) - p3 = Vector(-1, 0, 3) - p4 = Vector(-2, 0, 2) - self.assertLines(i.edges, i.tail, [p0, p1, p2, p3, p4]) - self.assertIsNone(i.tail) - - # make sure adding another segment doesn't change the state - edge = Part.Edge(Part.Line(edge.Curve.EndPoint, Vector(-3, 0, 0))) - i = i.intersect(edge) - self.assertEqual(i.state, Tag.Intersection.P2) - self.assertEqual(len(i.edges), 5) - p5 = Vector(-3, 0, 1) - self.assertLine(i.edges[4], p4, p5) - self.assertIsNone(i.tail) - - # now if we complete to P3 .... - edge = Part.Edge(Part.Line(edge.Curve.EndPoint, Vector(-4, 0, 0))) - i = i.intersect(edge) - self.assertEqual(i.state, Tag.Intersection.P3) - self.assertTrue(i.isComplete()) - self.assertEqual(len(i.edges), 6) - p6 = Vector(-4, 0, 0) - self.assertLine(i.edges[5], p5, p6) - self.assertIsNone(i.tail) - - # verify proper operation if there is a single edge going through all - edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(-4, 0, 0))) - i = tag.intersect(edge) - self.assertEqual(i.state, Tag.Intersection.P3) - self.assertTrue(i.isComplete()) - self.assertLines(i.edges, i.tail, [p0, p1, p2, p3, p6]) - self.assertIsNone(i.tail) - - # verify tail is added as well - edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(-5, 0, 0))) - i = tag.intersect(edge) - self.assertEqual(i.state, Tag.Intersection.P3) - self.assertTrue(i.isComplete()) - self.assertLines(i.edges, i.tail, [p0, p1, p2, p3, p6, edge.Curve.EndPoint]) - self.assertIsNotNone(i.tail) - - def test05(self): - """Verify all lines between P0 and P3 are added.""" - tag = Tag( 0, 0, 8, 3, 45, True, 0) - e0 = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(+4, 0, 0))) - e1 = Part.Edge(Part.Line(e0.Curve.EndPoint, Vector(+2, 0, 0))) - e2 = Part.Edge(Part.Line(e1.Curve.EndPoint, Vector(+0.5, 0, 0))) - e3 = Part.Edge(Part.Line(e2.Curve.EndPoint, Vector(-0.5, 0, 0))) - e4 = Part.Edge(Part.Line(e3.Curve.EndPoint, Vector(-1, 0, 0))) - e5 = Part.Edge(Part.Line(e4.Curve.EndPoint, Vector(-2, 0, 0))) - e6 = Part.Edge(Part.Line(e5.Curve.EndPoint, Vector(-5, 0, 0))) - - i = tag - for e in [e0, e1, e2, e3, e4, e5]: - i = i.intersect(e) - self.assertFalse(i.isComplete()) - i = i.intersect(e6) - self.assertTrue(i.isComplete()) - - p0 = Vector(4, 0, 0) - p1 = Vector(2, 0, 2) - p2 = Vector(1, 0, 3) - p3 = Vector(0.5, 0, 3) - p4 = Vector(-0.5, 0, 3) - p5 = Vector(-1, 0, 3) - p6 = Vector(-2, 0, 2) - p7 = Vector(-4, 0, 0) - - self.assertLines(i.edges, i.tail, [e0.Curve.StartPoint, p0, p1, p2, p3, p4, p5, p6, p7, e6.Curve.EndPoint]) - self.assertIsNotNone(i.tail) - - def test06(self): - """Verify intersection for different z levels.""" - tag = Tag( 0, 0, 8, 3, 45, True, 0) - # for all lines below 3 we get the trapezoid - for i in range(0, 3): - p0 = Vector(5, 0, i) - p1 = Vector(4-i, 0, i) - p2 = Vector(1, 0, 3) - p3 = Vector(-1, 0, 3) - p4 = Vector(-4+i, 0, i) - p5 = Vector(-5, 0, i) - edge = Part.Edge(Part.Line(p0, p5)) - s = tag.intersect(edge) - self.assertTrue(s.isComplete()) - self.assertLines(s.edges, s.tail, [p0, p1, p2, p3, p4, p5]) - - # for all edges at height or above the original line is used - for i in range(3, 5): - edge = Part.Edge(Part.Line(Vector(5, 0, i), Vector(-5, 0, i))) - s = tag.intersect(edge) - self.assertTrue(s.isComplete()) - self.assertLine(s.tail, edge.Curve.StartPoint, edge.Curve.EndPoint) - - -class TestTag04TriangularTag(TagTestCaseBase): # ======================== - """Unit tests for tags that take on a triangular shape.""" - - def test00(self): - """Verify intersection of triangular tag with line ending at tag start.""" - tag = Tag( 0, 0, 8, 7, 45, True, 0) - edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(4, 0, 0))) - - i = tag.intersect(edge) - self.assertEqual(i.state, Tag.Intersection.P0) - self.assertEqual(len(i.edges), 1) - self.assertLine(i.edges[0], edge.Curve.StartPoint, edge.Curve.EndPoint) - self.assertIsNone(i.tail) - - def test01(self): - """Verify intersection of triangular tag with line ending between P0 and P1.""" - tag = Tag( 0, 0, 8, 7, 45, True, 0) - edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(3, 0, 0))) - - i = tag.intersect(edge) - self.assertEqual(i.state, Tag.Intersection.P0) - p1 = Vector(4, 0, 0) - p2 = Vector(3, 0, 1) - self.assertLines(i.edges, i.tail, [edge.Curve.StartPoint, p1, p2]) - self.assertIsNone(i.tail) - - # verify we stay in P1 if we add another segment - edge = Part.Edge(Part.Line(edge.Curve.EndPoint, Vector(1, 0, 0))) - i = i.intersect(edge) - self.assertEqual(i.state, Tag.Intersection.P0) - self.assertEqual(len(i.edges), 3) - p3 = Vector(1, 0, 3) - self.assertLine(i.edges[2], p2, p3) - self.assertIsNone(i.tail) - - def test02(self): - """Verify proper down plunge on exit of triangular tag.""" - tag = Tag( 0, 0, 8, 7, 45, True, 0) - - p0 = Vector(5, 0, 0) - p1 = Vector(4, 0, 0) - p2 = Vector(0, 0, 4) - edge = Part.Edge(Part.Line(p0, FreeCAD.Vector(0,0,0))) - i = tag.intersect(edge) - self.assertEqual(i.state, Tag.Intersection.P2) - self.assertEqual(len(i.edges), 2) - self.assertLines(i.edges, i.tail, [p0, p1, p2]) - - # adding another segment doesn't make a difference - edge = Part.Edge(Part.Line(edge.Curve.EndPoint, FreeCAD.Vector(-3,0,0))) - i = i.intersect(edge) - self.assertEqual(i.state, Tag.Intersection.P2) - self.assertEqual(len(i.edges), 3) - p3 = Vector(-3, 0, 1) - self.assertLines(i.edges, i.tail, [p0, p1, p2, p3]) - - # same result if all is one line - edge = Part.Edge(Part.Line(p0, edge.Curve.EndPoint)) - i = tag.intersect(edge) - self.assertEqual(i.state, Tag.Intersection.P2) - self.assertLines(i.edges, i.tail, [p0, p1, p2, p3]) - - def test03(self): - """Verify triangular tag shap on intersection.""" - tag = Tag( 0, 0, 8, 7, 45, True, 0) - - p0 = Vector(5, 0, 0) - p1 = Vector(4, 0, 0) - p2 = Vector(0, 0, 4) - p3 = Vector(-4, 0, 0) - edge = Part.Edge(Part.Line(p0, p3)) - i = tag.intersect(edge) - self.assertTrue(i.isComplete()) - self.assertLines(i.edges, i.tail, [p0, p1, p2, p3]) - self.assertIsNone(i.tail) - - # this should also work if there is some excess, aka tail - p4 = Vector(-5, 0, 0) - edge = Part.Edge(Part.Line(p0, p4)) - i = tag.intersect(edge) - self.assertTrue(i.isComplete()) - self.assertLines(i.edges, i.tail, [p0, p1, p2, p3, p4]) - self.assertIsNotNone(i.tail) - diff --git a/src/Mod/Path/PathTests/TestPathGeom.py b/src/Mod/Path/PathTests/TestPathGeom.py index fbbc5def3..720857bc5 100644 --- a/src/Mod/Path/PathTests/TestPathGeom.py +++ b/src/Mod/Path/PathTests/TestPathGeom.py @@ -121,3 +121,27 @@ class TestPathGeom(PathTestBase): PathGeom.edgeForCmd( Path.Command('G3', {'X': p2.x, 'Y': p2.y, 'Z': p2.z, 'I': 1, 'J': 0, 'K': -1}), p1), p1, Vector(-1/math.sqrt(2), -1/math.sqrt(2), 1), p2) + + def test50(self): + """Verify proper wire(s) aggregation from a Path.""" + commands = [] + commands.append(Path.Command('G1', {'X': 1})) + commands.append(Path.Command('G1', {'Y': 1})) + commands.append(Path.Command('G0', {'X': 0})) + commands.append(Path.Command('G1', {'Y': 0})) + + wire = PathGeom.wireForPath(Path.Path(commands)) + self.assertEqual(len(wire.Edges), 4) + self.assertLine(wire.Edges[0], Vector(0,0,0), Vector(1,0,0)) + self.assertLine(wire.Edges[1], Vector(1,0,0), Vector(1,1,0)) + self.assertLine(wire.Edges[2], Vector(1,1,0), Vector(0,1,0)) + self.assertLine(wire.Edges[3], Vector(0,1,0), Vector(0,0,0)) + + wires = PathGeom.wiresForPath(Path.Path(commands)) + self.assertEqual(len(wires), 2) + self.assertEqual(len(wires[0].Edges), 2) + self.assertLine(wires[0].Edges[0], Vector(0,0,0), Vector(1,0,0)) + self.assertLine(wires[0].Edges[1], Vector(1,0,0), Vector(1,1,0)) + self.assertEqual(len(wires[1].Edges), 1) + self.assertLine(wires[1].Edges[0], Vector(0,1,0), Vector(0,0,0)) + diff --git a/src/Mod/Path/TestPathApp.py b/src/Mod/Path/TestPathApp.py index 83e8a2bc0..5f246e8c7 100644 --- a/src/Mod/Path/TestPathApp.py +++ b/src/Mod/Path/TestPathApp.py @@ -26,10 +26,4 @@ import TestApp from PathTests.TestPathPost import PathPostTestCases -from PathTests.TestPathDressupHoldingTags import TestTag00BasicHolding -from PathTests.TestPathDressupHoldingTags import TestTag01BasicTag -from PathTests.TestPathDressupHoldingTags import TestTag02SquareTag -from PathTests.TestPathDressupHoldingTags import TestTag03TrapezoidTag -from PathTests.TestPathDressupHoldingTags import TestTag04TriangularTag - from PathTests.TestPathGeom import TestPathGeom