Draft: move functions to draftgeoutils.wires
This commit is contained in:
@@ -36,6 +36,7 @@ SET (Draft_geoutils
|
||||
draftgeoutils/sort_edges.py
|
||||
draftgeoutils/faces.py
|
||||
draftgeoutils/geometry.py
|
||||
draftgeoutils/wires.py
|
||||
)
|
||||
|
||||
SET(Draft_tests
|
||||
|
||||
@@ -262,141 +262,16 @@ from draftgeoutils.sort_edges import sortEdgesOld
|
||||
from draftgeoutils.edges import invert
|
||||
|
||||
|
||||
def flattenWire(wire):
|
||||
"""flattenWire(wire): forces a wire to get completely flat
|
||||
along its normal."""
|
||||
import WorkingPlane
|
||||
n = getNormal(wire)
|
||||
if not n:
|
||||
return
|
||||
o = wire.Vertexes[0].Point
|
||||
plane = WorkingPlane.plane()
|
||||
plane.alignToPointAndAxis(o,n,0)
|
||||
verts = [o]
|
||||
for v in wire.Vertexes[1:]:
|
||||
verts.append(plane.projectPoint(v.Point))
|
||||
if wire.isClosed():
|
||||
verts.append(o)
|
||||
w = Part.makePolygon(verts)
|
||||
return w
|
||||
from draftgeoutils.wires import flattenWire
|
||||
|
||||
|
||||
def findWires(edgeslist):
|
||||
return [ Part.Wire(e) for e in Part.sortEdges(edgeslist)]
|
||||
from draftgeoutils.wires import findWires
|
||||
|
||||
|
||||
def findWiresOld2(edgeslist):
|
||||
"""Find connected wires in the given list of edges."""
|
||||
|
||||
def touches(e1,e2):
|
||||
if len(e1.Vertexes) < 2:
|
||||
return False
|
||||
if len(e2.Vertexes) < 2:
|
||||
return False
|
||||
if DraftVecUtils.equals(e1.Vertexes[0].Point,e2.Vertexes[0].Point):
|
||||
return True
|
||||
if DraftVecUtils.equals(e1.Vertexes[0].Point,e2.Vertexes[-1].Point):
|
||||
return True
|
||||
if DraftVecUtils.equals(e1.Vertexes[-1].Point,e2.Vertexes[0].Point):
|
||||
return True
|
||||
if DraftVecUtils.equals(e1.Vertexes[-1].Point,e2.Vertexes[-1].Point):
|
||||
return True
|
||||
return False
|
||||
|
||||
edges = edgeslist[:]
|
||||
wires = []
|
||||
lost = []
|
||||
while edges:
|
||||
e = edges[0]
|
||||
if not wires:
|
||||
# create first group
|
||||
edges.remove(e)
|
||||
wires.append([e])
|
||||
else:
|
||||
found = False
|
||||
for w in wires:
|
||||
if not found:
|
||||
for we in w:
|
||||
if touches(e,we):
|
||||
edges.remove(e)
|
||||
w.append(e)
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
if e in lost:
|
||||
# we already tried this edge, and still nothing
|
||||
edges.remove(e)
|
||||
wires.append([e])
|
||||
lost = []
|
||||
else:
|
||||
# put to the end of the list
|
||||
edges.remove(e)
|
||||
edges.append(e)
|
||||
lost.append(e)
|
||||
nwires = []
|
||||
for w in wires:
|
||||
try:
|
||||
wi = Part.Wire(w)
|
||||
except:
|
||||
print("couldn't join some edges")
|
||||
else:
|
||||
nwires.append(wi)
|
||||
return nwires
|
||||
from draftgeoutils.wires import findWiresOld2
|
||||
|
||||
|
||||
def superWire(edgeslist, closed=False):
|
||||
"""superWire(edges,[closed]): forces a wire between edges that don't necessarily
|
||||
have coincident endpoints. If closed=True, wire will always be closed"""
|
||||
def median(v1,v2):
|
||||
vd = v2.sub(v1)
|
||||
vd.scale(.5,.5,.5)
|
||||
return v1.add(vd)
|
||||
edges = Part.__sortEdges__(edgeslist)
|
||||
print(edges)
|
||||
newedges = []
|
||||
for i in range(len(edges)):
|
||||
curr = edges[i]
|
||||
if i == 0:
|
||||
if closed:
|
||||
prev = edges[-1]
|
||||
else:
|
||||
prev = None
|
||||
else:
|
||||
prev = edges[i-1]
|
||||
if i == (len(edges)-1):
|
||||
if closed:
|
||||
next = edges[0]
|
||||
else:
|
||||
next = None
|
||||
else:
|
||||
next = edges[i+1]
|
||||
print(i,prev,curr,next)
|
||||
if prev:
|
||||
if curr.Vertexes[0].Point == prev.Vertexes[-1].Point:
|
||||
p1 = curr.Vertexes[0].Point
|
||||
else:
|
||||
p1 = median(curr.Vertexes[0].Point,prev.Vertexes[-1].Point)
|
||||
else:
|
||||
p1 = curr.Vertexes[0].Point
|
||||
if next:
|
||||
if curr.Vertexes[-1].Point == next.Vertexes[0].Point:
|
||||
p2 = next.Vertexes[0].Point
|
||||
else:
|
||||
p2 = median(curr.Vertexes[-1].Point,next.Vertexes[0].Point)
|
||||
else:
|
||||
p2 = curr.Vertexes[-1].Point
|
||||
if geomType(curr) == "Line":
|
||||
print("line",p1,p2)
|
||||
newedges.append(Part.LineSegment(p1,p2).toShape())
|
||||
elif geomType(curr) == "Circle":
|
||||
p3 = findMidpoint(curr)
|
||||
print("arc",p1,p3,p2)
|
||||
newedges.append(Part.Arc(p1,p3,p2).toShape())
|
||||
else:
|
||||
print("Cannot superWire edges that are not lines or arcs")
|
||||
return None
|
||||
print(newedges)
|
||||
return Part.Wire(newedges)
|
||||
from draftgeoutils.wires import superWire
|
||||
|
||||
|
||||
from draftgeoutils.edges import findMidpoint
|
||||
@@ -430,30 +305,7 @@ def offset(edge, vector, trim=False):
|
||||
return None
|
||||
|
||||
|
||||
def isReallyClosed(wire):
|
||||
"""Check if a wire is really closed."""
|
||||
## TODO yet to find out why not use wire.isClosed() direct, in isReallyClosed(wire)
|
||||
|
||||
# Remark out below - Found not true if a vertex is used again in a wire in sketch ( e.g. wire with shape like 'd', 'b', 'g'... )
|
||||
#if len(wire.Edges) == len(wire.Vertexes): return True
|
||||
|
||||
# Found cases where Wire[-1] are not 'last' vertexes (e.g. Part.Wire( Part.__sortEdges__( <Rectangle Geometries>.toShape() ) )
|
||||
# aboveWire.isClosed() == True, but Wire[-1] are the 3rd vertex for the rectangle
|
||||
# - use Edges[i].Vertexes[0/1] instead
|
||||
length = len(wire.Edges)
|
||||
|
||||
# Test if it is full circle / ellipse first
|
||||
if length == 1:
|
||||
if len(wire.Edges[0].Vertexes) == 1:
|
||||
return True # This is a closed wire - full circle / ellipse
|
||||
else:
|
||||
return False # TODO Should be False if 1 edge but not single vertex, correct? No need to test further below.
|
||||
|
||||
# If more than 1 edge, further test below
|
||||
v1 = wire.Edges[0].Vertexes[0].Point #v1 = wire.Vertexes[0].Point
|
||||
v2 = wire.Edges[length-1].Vertexes[1].Point #v2 = wire.Vertexes[-1].Point
|
||||
if DraftVecUtils.equals(v1,v2): return True
|
||||
return False
|
||||
from draftgeoutils.wires import isReallyClosed
|
||||
|
||||
|
||||
from draftgeoutils.geometry import getSplineNormal
|
||||
@@ -766,37 +618,7 @@ from draftgeoutils.faces import isCoplanar
|
||||
from draftgeoutils.geometry import isPlanar
|
||||
|
||||
|
||||
def findWiresOld(edges):
|
||||
"""finds connected edges in the list, and returns a list of lists containing edges
|
||||
that can be connected"""
|
||||
raise DeprecationWarning("This function shouldn't be called anymore - use findWires() instead")
|
||||
def verts(shape):
|
||||
return [shape.Vertexes[0].Point,shape.Vertexes[-1].Point]
|
||||
def group(shapes):
|
||||
shapesIn = shapes[:]
|
||||
shapesOut = [shapesIn.pop()]
|
||||
changed = False
|
||||
for s in shapesIn:
|
||||
if len(s.Vertexes) < 2:
|
||||
continue
|
||||
else:
|
||||
clean = True
|
||||
for v in verts(s):
|
||||
for i in range(len(shapesOut)):
|
||||
if clean and (v in verts(shapesOut[i])):
|
||||
shapesOut[i] = Part.Wire(shapesOut[i].Edges+s.Edges)
|
||||
changed = True
|
||||
clean = False
|
||||
if clean:
|
||||
shapesOut.append(s)
|
||||
return(changed,shapesOut)
|
||||
working = True
|
||||
edgeSet = edges
|
||||
while working:
|
||||
result = group(edgeSet)
|
||||
working = result[0]
|
||||
edgeSet = result[1]
|
||||
return result[1]
|
||||
from draftgeoutils.wires import findWiresOld
|
||||
|
||||
|
||||
def getTangent(edge, frompoint=None):
|
||||
@@ -1277,15 +1099,7 @@ def getCircleFromSpline(edge):
|
||||
return circle
|
||||
|
||||
|
||||
def curvetowire(obj, steps):
|
||||
points = obj.copy().discretize(steps)
|
||||
p0 = points[0]
|
||||
edgelist = []
|
||||
for p in points[1:]:
|
||||
edge = Part.makeLine((p0.x,p0.y,p0.z),(p.x,p.y,p.z))
|
||||
edgelist.append(edge)
|
||||
p0 = p
|
||||
return edgelist
|
||||
from draftgeoutils.wires import curvetowire
|
||||
|
||||
|
||||
def cleanProjection(shape, tessellate=True, seglength=0.05):
|
||||
@@ -1333,15 +1147,7 @@ def cleanProjection(shape, tessellate=True, seglength=0.05):
|
||||
return Part.makeCompound(newedges)
|
||||
|
||||
|
||||
def curvetosegment(curve, seglen):
|
||||
points = curve.discretize(seglen)
|
||||
p0 = points[0]
|
||||
edgelist = []
|
||||
for p in points[1:]:
|
||||
edge = Part.makeLine((p0.x,p0.y,p0.z),(p.x,p.y,p.z))
|
||||
edgelist.append(edge)
|
||||
p0 = p
|
||||
return edgelist
|
||||
from draftgeoutils.wires import curvetosegment
|
||||
|
||||
|
||||
def tessellateProjection(shape, seglen):
|
||||
@@ -1366,18 +1172,7 @@ def tessellateProjection(shape, seglen):
|
||||
return Part.makeCompound(newedges)
|
||||
|
||||
|
||||
def rebaseWire(wire, vidx):
|
||||
"""rebaseWire(wire,vidx): returns a new wire which is a copy of the
|
||||
current wire, but where the first vertex is the vertex indicated by the given
|
||||
index vidx, starting from 1. 0 will return an exact copy of the wire."""
|
||||
|
||||
if vidx < 1:
|
||||
return wire
|
||||
if vidx > len(wire.Vertexes):
|
||||
#print("Vertex index above maximum\n")
|
||||
return wire
|
||||
#This can be done in one step
|
||||
return Part.Wire(wire.Edges[vidx-1:] + wire.Edges[:vidx-1])
|
||||
from draftgeoutils.wires import rebaseWire
|
||||
|
||||
|
||||
def removeSplitter(shape):
|
||||
|
||||
314
src/Mod/Draft/draftgeoutils/wires.py
Normal file
314
src/Mod/Draft/draftgeoutils/wires.py
Normal file
@@ -0,0 +1,314 @@
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2009, 2010 Yorik van Havre <yorik@uncreated.net> *
|
||||
# * Copyright (c) 2009, 2010 Ken Cline <cline@frii.com> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
# * *
|
||||
# * 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. *
|
||||
# * *
|
||||
# * FreeCAD 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 FreeCAD; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
"""Provides various functions for working with wires."""
|
||||
## @package wires
|
||||
# \ingroup DRAFTGEOUTILS
|
||||
# \brief Provides various functions for working with wires.
|
||||
|
||||
import lazy_loader.lazy_loader as lz
|
||||
|
||||
import DraftVecUtils
|
||||
import WorkingPlane
|
||||
|
||||
from draftgeoutils.general import geomType
|
||||
from draftgeoutils.edges import findMidpoint
|
||||
from draftgeoutils.geometry import getNormal
|
||||
|
||||
# Delay import of module until first use because it is heavy
|
||||
Part = lz.LazyLoader("Part", globals(), "Part")
|
||||
|
||||
|
||||
def findWires(edgeslist):
|
||||
"""Find wires in a list of edges."""
|
||||
return [Part.Wire(e) for e in Part.sortEdges(edgeslist)]
|
||||
|
||||
|
||||
def findWiresOld2(edgeslist):
|
||||
"""Find connected wires in the given list of edges."""
|
||||
|
||||
def touches(e1, e2):
|
||||
"""Return True if two edges connect at the edges."""
|
||||
if len(e1.Vertexes) < 2:
|
||||
return False
|
||||
if len(e2.Vertexes) < 2:
|
||||
return False
|
||||
if DraftVecUtils.equals(e1.Vertexes[0].Point,
|
||||
e2.Vertexes[0].Point):
|
||||
return True
|
||||
if DraftVecUtils.equals(e1.Vertexes[0].Point,
|
||||
e2.Vertexes[-1].Point):
|
||||
return True
|
||||
if DraftVecUtils.equals(e1.Vertexes[-1].Point,
|
||||
e2.Vertexes[0].Point):
|
||||
return True
|
||||
if DraftVecUtils.equals(e1.Vertexes[-1].Point,
|
||||
e2.Vertexes[-1].Point):
|
||||
return True
|
||||
return False
|
||||
|
||||
edges = edgeslist[:]
|
||||
wires = []
|
||||
lost = []
|
||||
while edges:
|
||||
e = edges[0]
|
||||
if not wires:
|
||||
# create first group
|
||||
edges.remove(e)
|
||||
wires.append([e])
|
||||
else:
|
||||
found = False
|
||||
for w in wires:
|
||||
if not found:
|
||||
for we in w:
|
||||
if touches(e, we):
|
||||
edges.remove(e)
|
||||
w.append(e)
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
if e in lost:
|
||||
# we already tried this edge, and still nothing
|
||||
edges.remove(e)
|
||||
wires.append([e])
|
||||
lost = []
|
||||
else:
|
||||
# put to the end of the list
|
||||
edges.remove(e)
|
||||
edges.append(e)
|
||||
lost.append(e)
|
||||
nwires = []
|
||||
for w in wires:
|
||||
try:
|
||||
wi = Part.Wire(w)
|
||||
except Part.OCCError:
|
||||
print("couldn't join some edges")
|
||||
else:
|
||||
nwires.append(wi)
|
||||
return nwires
|
||||
|
||||
|
||||
def findWiresOld(edges):
|
||||
"""Return a list of lists containing edges that can be connected.
|
||||
|
||||
Find connected edges in the list.
|
||||
"""
|
||||
raise DeprecationWarning("This function shouldn't be called anymore. "
|
||||
"Use findWires() instead")
|
||||
|
||||
def verts(shape):
|
||||
return [shape.Vertexes[0].Point,
|
||||
shape.Vertexes[-1].Point]
|
||||
|
||||
def group(shapes):
|
||||
shapesIn = shapes[:]
|
||||
shapesOut = [shapesIn.pop()]
|
||||
changed = False
|
||||
for s in shapesIn:
|
||||
if len(s.Vertexes) < 2:
|
||||
continue
|
||||
else:
|
||||
clean = True
|
||||
for v in verts(s):
|
||||
for i in range(len(shapesOut)):
|
||||
if clean and (v in verts(shapesOut[i])):
|
||||
shapesOut[i] = Part.Wire(shapesOut[i].Edges
|
||||
+ s.Edges)
|
||||
changed = True
|
||||
clean = False
|
||||
if clean:
|
||||
shapesOut.append(s)
|
||||
return changed, shapesOut
|
||||
|
||||
working = True
|
||||
edgeSet = edges
|
||||
|
||||
while working:
|
||||
result = group(edgeSet)
|
||||
working = result[0]
|
||||
edgeSet = result[1]
|
||||
|
||||
return result[1]
|
||||
|
||||
|
||||
def flattenWire(wire):
|
||||
"""Force a wire to get completely flat along its normal."""
|
||||
n = getNormal(wire)
|
||||
if not n:
|
||||
return
|
||||
|
||||
o = wire.Vertexes[0].Point
|
||||
plane = WorkingPlane.plane()
|
||||
plane.alignToPointAndAxis(o, n, 0)
|
||||
verts = [o]
|
||||
|
||||
for v in wire.Vertexes[1:]:
|
||||
verts.append(plane.projectPoint(v.Point))
|
||||
|
||||
if wire.isClosed():
|
||||
verts.append(o)
|
||||
w = Part.makePolygon(verts)
|
||||
|
||||
return w
|
||||
|
||||
|
||||
def superWire(edgeslist, closed=False):
|
||||
"""Force a wire between edges that don't have coincident endpoints.
|
||||
|
||||
Forces a wire between edges that don't necessarily
|
||||
have coincident endpoints. If closed=True, the wire will always be closed.
|
||||
"""
|
||||
def median(v1, v2):
|
||||
vd = v2.sub(v1)
|
||||
vd.scale(0.5, 0.5, 0.5)
|
||||
return v1.add(vd)
|
||||
|
||||
edges = Part.__sortEdges__(edgeslist)
|
||||
print(edges)
|
||||
newedges = []
|
||||
|
||||
for i in range(len(edges)):
|
||||
curr = edges[i]
|
||||
if i == 0:
|
||||
if closed:
|
||||
prev = edges[-1]
|
||||
else:
|
||||
prev = None
|
||||
else:
|
||||
prev = edges[i - 1]
|
||||
|
||||
if i == (len(edges) - 1):
|
||||
if closed:
|
||||
_next = edges[0]
|
||||
else:
|
||||
_next = None
|
||||
else:
|
||||
_next = edges[i+1]
|
||||
|
||||
print(i, prev, curr, _next)
|
||||
|
||||
if prev:
|
||||
if curr.Vertexes[0].Point == prev.Vertexes[-1].Point:
|
||||
p1 = curr.Vertexes[0].Point
|
||||
else:
|
||||
p1 = median(curr.Vertexes[0].Point, prev.Vertexes[-1].Point)
|
||||
else:
|
||||
p1 = curr.Vertexes[0].Point
|
||||
|
||||
if _next:
|
||||
if curr.Vertexes[-1].Point == _next.Vertexes[0].Point:
|
||||
p2 = _next.Vertexes[0].Point
|
||||
else:
|
||||
p2 = median(curr.Vertexes[-1].Point, _next.Vertexes[0].Point)
|
||||
else:
|
||||
p2 = curr.Vertexes[-1].Point
|
||||
|
||||
if geomType(curr) == "Line":
|
||||
print("line", p1, p2)
|
||||
newedges.append(Part.LineSegment(p1, p2).toShape())
|
||||
elif geomType(curr) == "Circle":
|
||||
p3 = findMidpoint(curr)
|
||||
print("arc", p1, p3, p2)
|
||||
newedges.append(Part.Arc(p1, p3, p2).toShape())
|
||||
else:
|
||||
print("Cannot superWire edges that are not lines or arcs")
|
||||
return None
|
||||
|
||||
print(newedges)
|
||||
return Part.Wire(newedges)
|
||||
|
||||
|
||||
def isReallyClosed(wire):
|
||||
"""Check if a wire is really closed."""
|
||||
# TODO yet to find out why not use wire.isClosed() direct,
|
||||
# in isReallyClosed(wire)
|
||||
|
||||
# Remark out below - Found not true if a vertex is used again
|
||||
# in a wire in sketch (e.g. wire with shape like 'd', 'b', 'g', ...)
|
||||
# if len(wire.Edges) == len(wire.Vertexes): return True
|
||||
|
||||
# Found cases where Wire[-1] are not 'last' vertexes
|
||||
# e.g. Part.Wire( Part.__sortEdges__(<Rectangle Geometries>.toShape()))
|
||||
# aboveWire.isClosed() == True, but Wire[-1] are the 3rd vertex
|
||||
# for the rectangle - use Edges[i].Vertexes[0/1] instead
|
||||
length = len(wire.Edges)
|
||||
|
||||
# Test if it is full circle / ellipse first
|
||||
if length == 1:
|
||||
if len(wire.Edges[0].Vertexes) == 1:
|
||||
return True # This is a closed wire - full circle/ellipse
|
||||
else:
|
||||
# TODO Should be False if 1 edge but not single vertex, correct?
|
||||
# No need to test further below.
|
||||
return False
|
||||
|
||||
# If more than 1 edge, further test below
|
||||
v1 = wire.Edges[0].Vertexes[0].Point # v1 = wire.Vertexes[0].Point
|
||||
v2 = wire.Edges[length-1].Vertexes[1].Point # v2 = wire.Vertexes[-1].Point
|
||||
if DraftVecUtils.equals(v1, v2):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def curvetowire(obj, steps):
|
||||
"""Discretize the object and return a list of edges."""
|
||||
points = obj.copy().discretize(steps)
|
||||
p0 = points[0]
|
||||
edgelist = []
|
||||
for p in points[1:]:
|
||||
edge = Part.makeLine((p0.x, p0.y, p0.z), (p.x, p.y, p.z))
|
||||
edgelist.append(edge)
|
||||
p0 = p
|
||||
return edgelist
|
||||
|
||||
|
||||
def curvetosegment(curve, seglen):
|
||||
"""Discretize the curve and return a list of edges."""
|
||||
points = curve.discretize(seglen)
|
||||
p0 = points[0]
|
||||
edgelist = []
|
||||
for p in points[1:]:
|
||||
edge = Part.makeLine((p0.x, p0.y, p0.z), (p.x, p.y, p.z))
|
||||
edgelist.append(edge)
|
||||
p0 = p
|
||||
return edgelist
|
||||
|
||||
|
||||
def rebaseWire(wire, vidx=0):
|
||||
"""Return a copy of the wire with the first vertex indicated by the index.
|
||||
|
||||
Return a new wire which is a copy of the current wire,
|
||||
but where the first vertex is the vertex indicated by the given
|
||||
index vidx, starting from 1.
|
||||
0 will return an exact copy of the wire.
|
||||
"""
|
||||
if vidx < 1:
|
||||
return wire
|
||||
|
||||
if vidx > len(wire.Vertexes):
|
||||
# print("Vertex index above maximum")
|
||||
return wire
|
||||
|
||||
# This can be done in one step
|
||||
return Part.Wire(wire.Edges[vidx-1:] + wire.Edges[:vidx-1])
|
||||
Reference in New Issue
Block a user