Arch: Fix baseface generation for walls with a trace that self-intersects, has T-connections or that overlaps

This commit is contained in:
Roy-043
2022-09-03 09:06:51 +02:00
parent 3362e64adc
commit 38bccb31fa
2 changed files with 51 additions and 27 deletions

View File

@@ -1351,7 +1351,7 @@ class _Wall(ArchComponent.Component):
if not DraftVecUtils.isNull(dvec):
dvec.normalize()
sh = None
face = None
curAligns = aligns[0]
off = obj.Offset.Value
@@ -1399,7 +1399,7 @@ class _Wall(ArchComponent.Component):
normal=normal,
basewireOffset=off)
sh = DraftGeomUtils.bind(w1,w2)
face = DraftGeomUtils.bind(w1, w2, per_segment=True)
elif curAligns == "Right":
dvec = dvec.negative()
@@ -1440,7 +1440,7 @@ class _Wall(ArchComponent.Component):
normal=normal,
basewireOffset=off)
sh = DraftGeomUtils.bind(w1,w2)
face = DraftGeomUtils.bind(w1, w2, per_segment=True)
#elif obj.Align == "Center":
elif curAligns == "Center":
@@ -1473,18 +1473,16 @@ class _Wall(ArchComponent.Component):
alignList=aligns,
normal=normal,
basewireOffset=off)
sh = DraftGeomUtils.bind(w1,w2)
face = DraftGeomUtils.bind(w1, w2, per_segment=True)
del widths[0:edgeNum]
del aligns[0:edgeNum]
if sh:
if face:
if layers and (layers[i] < 0):
# layers with negative values are not drawn
continue
sh.fix(0.1,0,1) # fixes self-intersecting wires
f = Part.Face(sh)
if baseface:
# To allow exportIFC.py to work properly on
@@ -1505,14 +1503,14 @@ class _Wall(ArchComponent.Component):
# - 1st finding : if a rectangle + 1 line, can't removesSplitter properly...
# - 2nd finding : if 2 faces do not touch, can't form a shell; then, subsequently for remaining faces even though touch each faces, can't form a shell
baseface.append(f)
baseface.append(face)
# The above make Refine methods below (in else) useless, regardless removeSpitters yet to be improved for cases do not work well
''' Whether layers or not, all baseface.append(f) '''
''' Whether layers or not, all baseface.append(face) '''
else:
baseface = [f]
baseface = [face]
''' Whether layers or not, all baseface = [f] '''
''' Whether layers or not, all baseface = [face] '''
if baseface:
base,placement = self.rebase(baseface)

View File

@@ -110,32 +110,58 @@ def is_coplanar(faces, tol=-1):
isCoplanar = is_coplanar
def bind(w1, w2):
"""Bind 2 wires by their endpoints and returns a face."""
if not w1 or not w2:
print("DraftGeomUtils: unable to bind wires")
return None
def bind(w1, w2, per_segment=False):
"""Bind 2 wires by their endpoints and returns a face.
if w1.isClosed() and w2.isClosed():
d1 = w1.BoundBox.DiagonalLength
d2 = w2.BoundBox.DiagonalLength
if d1 > d2:
# w2.reverse()
return Part.Face([w1, w2])
else:
# w1.reverse()
return Part.Face([w2, w1])
else:
If per_segment is True and the wires have the same number of edges, the
wires are processed per segment: a separate face is created for each pair
of edges (one from w1 and one from w2), and the faces are then fused. This
avoids problems with walls based on wires that selfintersect, or that have
a loop that ends in a T-connection (f.e. a wire shaped like a number 6).
"""
def create_face(w1, w2):
try:
w3 = Part.LineSegment(w1.Vertexes[0].Point,
w2.Vertexes[0].Point).toShape()
w4 = Part.LineSegment(w1.Vertexes[-1].Point,
w2.Vertexes[-1].Point).toShape()
return Part.Face(Part.Wire(w1.Edges+[w3] + w2.Edges+[w4]))
return Part.Face(Part.Wire(w1.Edges + [w3] + w2.Edges + [w4]))
except Part.OCCError:
print("DraftGeomUtils: unable to bind wires")
return None
if not w1 or not w2:
print("DraftGeomUtils: unable to bind wires")
return None
if (per_segment
and len(w1.Edges) > 1
and len(w1.Edges) == len(w2.Edges)):
faces = []
for (edge1, edge2) in zip(w1.Edges, w2.Edges):
face = create_face(edge1, edge2)
if face is None:
return None
faces.append(face)
# return concatenate(faces[0].fuse(faces[1:])) # Also works.
return faces[0].fuse(faces[1:]).removeSplitter().Faces[0]
elif w1.isClosed() and w2.isClosed():
d1 = w1.BoundBox.DiagonalLength
d2 = w2.BoundBox.DiagonalLength
if d1 < d2:
w1, w2 = w2, w1
# return Part.Face(w1).cut(Part.Face(w2)).Faces[0] # Only works if wires do not self-intersect.
try:
face = Part.Face([w1, w2])
face.fix(1e-7, 0, 1)
return face
except Part.OCCError:
print("DraftGeomUtils: unable to bind wires")
return None
else:
return create_face(w1, w2)
def cleanFaces(shape):
"""Remove inner edges from coplanar faces."""