ArchWall_DraftGeomUtils Multi-Width support added

Discussion:- https://forum.freecadweb.org/viewtopic.php?f=23&t=36772&p=319829#p319829
This commit is contained in:
paullee0
2019-07-12 03:08:00 +08:00
committed by Yorik van Havre
parent bbdbe0e491
commit b7907e0fd8
2 changed files with 83 additions and 16 deletions

View File

@@ -534,6 +534,11 @@ class _Wall(ArchComponent.Component):
obj.addProperty("App::PropertyLength","Length","Wall",QT_TRANSLATE_NOOP("App::Property","The length of this wall. Not used if this wall is based on an underlying object"))
if not "Width" in lp:
obj.addProperty("App::PropertyLength","Width","Wall",QT_TRANSLATE_NOOP("App::Property","The width of this wall. Not used if this wall is based on a face"))
# To be combined into Width when PropertyLengthList is available
if not "WidthsOfWall" in lp:
obj.addProperty("App::PropertyFloatList","WidthsOfWall","Wall",QT_TRANSLATE_NOOP("App::Property","The widths of each segment of wall (The 1st value override 'Width' attribute for 1st segment of wall; if a value is zero, 1st value of 'WidthsOfWall' attribute will be followed)")) # see DraftGeomUtils.offsetwire()
if not "Height" in lp:
obj.addProperty("App::PropertyLength","Height","Wall",QT_TRANSLATE_NOOP("App::Property","The height of this wall. Keep 0 for automatic. Not used if this wall is based on a solid"))
if not "Align" in lp:
@@ -790,7 +795,19 @@ class _Wall(ArchComponent.Component):
# multifuses not considered here
return data
length = obj.Length.Value
width = obj.Width.Value
# TODO currently layers were not supported when len(basewires) > 0
width = 0
if obj.WidthsOfWall:
if obj.WidthsOfWall[0]:
width = obj.WidthsOfWall[0]
if not width:
if obj.Width:
width = obj.Width.Value
else:
print("Width or Widths Of Wall [0] should not be 0")
return
height = obj.Height.Value
if not height:
for p in obj.InList:
@@ -861,7 +878,8 @@ class _Wall(ArchComponent.Component):
for c in Part.sortEdges(cluster):
self.basewires.append(Part.Wire(c))
if self.basewires and width:
if self.basewires: # and width: # width already tested earlier...
if (len(self.basewires) == 1) and layers:
self.basewires = [self.basewires[0] for l in layers]
layeroffset = 0
@@ -886,7 +904,9 @@ class _Wall(ArchComponent.Component):
if off:
dvec2 = DraftVecUtils.scaleTo(dvec,off)
wire = DraftGeomUtils.offsetWire(wire,dvec2)
w2 = DraftGeomUtils.offsetWire(wire,dvec)
w2 = DraftGeomUtils.offsetWire(wire,dvec,False, False, obj.WidthsOfWall)
w1 = Part.Wire(Part.__sortEdges__(wire.Edges))
sh = DraftGeomUtils.bind(w1,w2)
elif obj.Align == "Right":
@@ -901,7 +921,9 @@ class _Wall(ArchComponent.Component):
if off:
dvec2 = DraftVecUtils.scaleTo(dvec,off)
wire = DraftGeomUtils.offsetWire(wire,dvec2)
w2 = DraftGeomUtils.offsetWire(wire,dvec)
w2 = DraftGeomUtils.offsetWire(wire,dvec,False, False, obj.WidthsOfWall)
w1 = Part.Wire(Part.__sortEdges__(wire.Edges))
sh = DraftGeomUtils.bind(w1,w2)
elif obj.Align == "Center":
@@ -914,10 +936,13 @@ class _Wall(ArchComponent.Component):
d1 = Vector(dvec).multiply(off)
w2 = DraftGeomUtils.offsetWire(wire,d1)
else:
dvec.multiply(width/2)
w1 = DraftGeomUtils.offsetWire(wire,dvec)
dvec.multiply(width/2) ## TODO width Value should be of no use (width/2), width Direction remains 'in use'
widthsOfWallHalfen = [i/2 for i in obj.WidthsOfWall]
w1 = DraftGeomUtils.offsetWire(wire,dvec,False, False, widthsOfWallHalfen)
dvec = dvec.negative()
w2 = DraftGeomUtils.offsetWire(wire,dvec)
w2 = DraftGeomUtils.offsetWire(wire,dvec,False, False, widthsOfWallHalfen)
sh = DraftGeomUtils.bind(w1,w2)
if sh:
sh.fix(0.1,0,1) # fixes self-intersecting wires

View File

@@ -1171,14 +1171,24 @@ def calculatePlacement(shape):
pla.Rotation = r
return pla
def offsetWire(wire,dvec,bind=False,occ=False):
def offsetWire(wire,dvec,bind=False,occ=False,widthList=None):
'''
offsetWire(wire,vector,[bind]): offsets the given wire along the
given vector. The vector will be applied at the first vertex of
the wire. If bind is True (and the shape is open), the original
wire and the offsetted one are bound by 2 edges, forming a face.
If widthList is provided (values only, not lengths - i.e. no unit),
each value will be used to offset each corresponding edge in the wire
(The 1st value override 'dvec' for 1st segement of wire;
if a value is zero, value of 'widthList[0]' will follow;
if widthList[0]' == 0, but dvec still provided, dvec will be followed)
'''
## TODO In future, 'vector' direction to offset could be 'calculated' in this function - if 'direction' in dvec is not / need not be provided 'outside' the function
## 'dvec' to be obsolete in future ?
edges = wire.Edges # Seems has repeatedly sortEdges, remark out here - edges = Part.__sortEdges__(wire.Edges)
norm = getNormal(wire)
closed = isReallyClosed(wire)
@@ -1206,14 +1216,39 @@ def offsetWire(wire,dvec,bind=False,occ=False):
for i in range(len(edges)):
curredge = edges[i]
delta = dvec
if widthList:
try:
if widthList[i] > 0:
delta = DraftVecUtils.scaleTo(dvec, widthList[i])
elif widthList[0] > 0:
delta = DraftVecUtils.scaleTo(dvec, widthList[0]) # to follow widthList[0]
# i.e. if widthList[0] == 0, though widthList is not False
# but if dev is provided still, fallback to dvec
elif dvec:
delta = dvec
else:
return None
except:
if widthList[0] > 0:
delta = DraftVecUtils.scaleTo(dvec, widthList[0]) # to follow widthList[0]
delta = dvec
else:
delta = dvec
if i != 0:
if isinstance(curredge.Curve,Part.Circle):
v = curredge.tangentAt(curredge.FirstParameter)
else:
v = vec(curredge)
## TODO - 2019.6.16 - 'calculate' 'offset' direction (in vector) edge by edge instead of rotating previous vector based on dvec in future
angle = DraftVecUtils.angle(firstVec,v,norm) # use vec deduced depending on geometry instead of - angle = DraftVecUtils.angle(vec(edges[0]),v,norm)
delta = DraftVecUtils.rotate(delta,angle,norm)
#print("edge ",i,": ",curredge.Curve," ",curredge.Orientation," parameters:",curredge.ParameterRange," vector:",delta)
nedge = offset(curredge,delta,trim=True)
if not nedge:
@@ -1259,16 +1294,23 @@ def connect(edges,closed=False):
if prev:
#print("debug: DraftGeomUtils.connect prev : ",prev.Vertexes[0].Point,prev.Vertexes[-1].Point)
# If prev v2 had been calculated, do not calculate again, just use it as current v1 - avoid chance of slight difference in result
if v2:
v1 = v2
# If the edge pairs has intersection
# ... and if there is prev v2 (prev v2 was caculated intersection), do not calculate again, just use it as current v1 - avoid chance of slight difference in result
# Otherwise, if edge pairs has no intersection (parallel edges, line - arc do no intersect, etc.), so just just current edge endpoints as v1
# ... and connect these 2 non-intersecting edges
else:
i = findIntersection(curr,prev,True,True)
if i:
# seem have chance that 2 parallel edges offset same width, result in 2 colinear edges - Wall / DraftGeomUtils seem make them 1 edge and thus 1 vertical plane
i = findIntersection(curr,prev,True,True)
if i:
if v2:
v1 = v2
else:
v1 = i[DraftVecUtils.closest(curr.Vertexes[0].Point,i)]
else:
else:
v1 = curr.Vertexes[0].Point
nedges.append(Part.LineSegment(v2,v1).toShape())
else:
v1 = curr.Vertexes[0].Point
if next: