Draft: move functions to draftgeoutils.wires

This commit is contained in:
vocx-fc
2020-05-22 21:40:38 -05:00
committed by Yorik van Havre
parent 7b94a6122b
commit e7b586ead1
3 changed files with 324 additions and 214 deletions

View File

@@ -36,6 +36,7 @@ SET (Draft_geoutils
draftgeoutils/sort_edges.py
draftgeoutils/faces.py
draftgeoutils/geometry.py
draftgeoutils/wires.py
)
SET(Draft_tests

View File

@@ -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):

View 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])