Skip to content

Commit e7b94de

Browse files
committed
merged AIRCAPs feature ForceInterpolate and sortEdges
1 parent 9366272 commit e7b94de

6 files changed

+82
-95
lines changed

CurvedSegment.py

+58-50
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ def __init__(self,
3434
DistributionReverse = False,
3535
LoftMaxDegree=5,
3636
MaxLoftSize=16,
37-
Path=None):
37+
Path=None,
38+
ForceInterpolated = False):
3839
CurvedShapes.addObjectProperty(fp,"App::PropertyLink", "Shape1", "CurvedSegment", "The first object of the segment").Shape1 = shape1
3940
CurvedShapes.addObjectProperty(fp,"App::PropertyLink", "Shape2", "CurvedSegment", "The last object of the segment").Shape2 = shape2
4041
CurvedShapes.addObjectProperty(fp,"App::PropertyLinkList", "Hullcurves", "CurvedSegment", "Bounding curves").Hullcurves = hullcurves
@@ -51,6 +52,7 @@ def __init__(self,
5152
CurvedShapes.addObjectProperty(fp,"App::PropertyInteger", "LoftMaxDegree", "CurvedSegment", "Max Degree for Surface or Solid").LoftMaxDegree = LoftMaxDegree
5253
CurvedShapes.addObjectProperty(fp,"App::PropertyInteger", "MaxLoftSize", "CurvedSegment", "Max Size of a Loft in Segments.").MaxLoftSize = MaxLoftSize
5354
CurvedShapes.addObjectProperty(fp,"App::PropertyLink", "Path", "CurvedSegment", "Sweep path").Path = Path
55+
CurvedShapes.addObjectProperty(fp,"App::PropertyBool", "ForceInterpolated","CurvedSegment", "Force Interpolation of sketches").ForceInterpolated = ForceInterpolated
5456
fp.Distribution = ['linear', 'parabolic', 'x³', 'sinusoidal', 'asinusoidal', 'elliptic']
5557
fp.Distribution = Distribution
5658
self.doScaleXYZ = []
@@ -71,52 +73,57 @@ def execute(self, fp):
7173

7274
if fp.InterpolationPoints <= 1:
7375
return
76+
77+
try:
78+
self.update = False
79+
if fp.NormalShape1 == Vector(0,0,0):
80+
fp.NormalShape1 = CurvedShapes.getNormal(fp.Shape1)
7481

75-
self.update = False
76-
if fp.NormalShape1 == Vector(0,0,0):
77-
fp.NormalShape1 = CurvedShapes.getNormal(fp.Shape1)
78-
79-
if fp.NormalShape2 == Vector(0,0,0):
80-
fp.NormalShape2 = CurvedShapes.getNormal(fp.Shape2)
81-
82-
self.doScaleXYZ = []
83-
self.doScaleXYZsum = [False, False, False]
84-
for h in fp.Hullcurves:
85-
bbox = h.Shape.BoundBox
86-
doScale = [False, False, False]
82+
if fp.NormalShape2 == Vector(0,0,0):
83+
fp.NormalShape2 = CurvedShapes.getNormal(fp.Shape2)
8784

88-
if bbox.XLength > epsilon:
89-
doScale[0] = True
90-
self.doScaleXYZsum[0] = True
91-
92-
if bbox.YLength > epsilon:
93-
doScale[1] = True
94-
self.doScaleXYZsum[1] = True
95-
96-
if bbox.ZLength > epsilon:
97-
doScale[2] = True
98-
self.doScaleXYZsum[2] = True
99-
100-
self.doScaleXYZ.append(doScale)
101-
102-
if fp.Items > 0:
103-
self.makeRibs(fp)
104-
105-
self.update = True
85+
self.doScaleXYZ = []
86+
self.doScaleXYZsum = [False, False, False]
87+
for h in fp.Hullcurves:
88+
bbox = h.Shape.BoundBox
89+
doScale = [False, False, False]
90+
91+
if bbox.XLength > epsilon:
92+
doScale[0] = True
93+
self.doScaleXYZsum[0] = True
94+
95+
if bbox.YLength > epsilon:
96+
doScale[1] = True
97+
self.doScaleXYZsum[1] = True
98+
99+
if bbox.ZLength > epsilon:
100+
doScale[2] = True
101+
self.doScaleXYZsum[2] = True
102+
103+
self.doScaleXYZ.append(doScale)
104+
105+
if fp.Items > 0:
106+
self.makeRibs(fp)
107+
self.update = True
108+
except Exception as ex:
109+
self.update = True
110+
raise ex
106111

107112

108-
def onChanged(self, fp, prop):
109-
#backwards compatiblity
113+
def onChanged(self, fp, prop):
110114
if not hasattr(fp, 'LoftMaxDegree'):
111115
CurvedShapes.addObjectProperty(fp, "App::PropertyInteger", "LoftMaxDegree", "CurvedSegment", "Max Degree for Surface or Solid", init_val=5) # backwards compatibility - this upgrades older documents
112116
if not hasattr(fp, 'MaxLoftSize'):
113117
CurvedShapes.addObjectProperty(fp,"App::PropertyInteger", "MaxLoftSize", "CurvedSegment", "Max Size of a Loft in Segments.", init_val=-1) # backwards compatibility - this upgrades older documents
114118
if not hasattr(fp, 'Path'):
115119
CurvedShapes.addObjectProperty(fp,"App::PropertyLink", "Path", "CurvedSegment", "Sweep path", init_val=None) # backwards compatibility - this upgrades older documents
116-
120+
if not hasattr(fp, 'ForceInterpolated'):
121+
CurvedShapes.addObjectProperty(fp,"App::PropertyBool", "ForceInterpolated","CurvedSegment", "Force Interpolation of sketches", init_val=False) # backwards compatibility - this upgrades older documents
122+
123+
117124
def makeRibs(self, fp):
118125
interpolate = False
119-
if len(fp.Shape1.Shape.Edges) != len(fp.Shape2.Shape.Edges):
126+
if fp.ForceInterpolated or len(fp.Shape1.Shape.Edges) != len(fp.Shape2.Shape.Edges):
120127
interpolate = True
121128
else:
122129
for e in range(0, len(fp.Shape1.Shape.Edges)):
@@ -305,14 +312,16 @@ def makeRibsSameShape(fp, items, alongNormal, makeStartEnd = False):
305312
return ribs
306313

307314

308-
def makeRibsInterpolate(fp, items, alongNormal, makeStartEnd = False):
309-
len1 = len(fp.Shape1.Shape.Edges)
310-
len2 = len(fp.Shape2.Shape.Edges)
315+
def makeRibsInterpolate(fp, items, alongNormal, makeStartEnd = False):
316+
s1=fp.Shape1.Shape.toNurbs()
317+
s2=fp.Shape2.Shape.toNurbs()
318+
len1 = len(s1.Edges)
319+
len2 = len(s2.Edges)
311320

312321
nr_edges = int(len1 * len2 / math.gcd(len1, len2))
313322

314-
pointslist1 = EdgesToPoints(fp.Shape1.Shape, int(nr_edges / len1), int(fp.InterpolationPoints))
315-
pointslist2 = EdgesToPoints(fp.Shape2.Shape, int(nr_edges / len2), int(fp.InterpolationPoints), fp.TwistReverse)
323+
pointslist1 = EdgesToPoints(s1, int(nr_edges / len1), int(fp.InterpolationPoints))
324+
pointslist2 = EdgesToPoints(s2, int(nr_edges / len2), int(fp.InterpolationPoints), fp.TwistReverse)
316325

317326
ribs = []
318327
if makeStartEnd:
@@ -322,8 +331,8 @@ def makeRibsInterpolate(fp, items, alongNormal, makeStartEnd = False):
322331
start = 1
323332
end = items + 1
324333

325-
base1=fp.Shape1.Placement.Base
326-
base2=fp.Shape2.Placement.Base
334+
base1=s1.Placement.Base
335+
base2=s2.Placement.Base
327336
offset=base2-base1
328337
for i in range(start, end):
329338
if hasattr(fp, "Distribution"):
@@ -336,6 +345,8 @@ def makeRibsInterpolate(fp, items, alongNormal, makeStartEnd = False):
336345
for l in range(0, len(pointslist1)):
337346
points1 = pointslist1[l]
338347
points2 = pointslist2[l]
348+
if(fp.TwistReverse):
349+
points2.reverse()
339350

340351
newpoles = []
341352
for p in range(0, fp.InterpolationPoints):
@@ -344,10 +355,7 @@ def makeRibsInterpolate(fp, items, alongNormal, makeStartEnd = False):
344355
else:
345356
newpoles.append(vectorMiddlePlane(points1[p], points2[p], fraction, plane)-fraction*offset)
346357
# coordinate has fraction*offset substracted to force the shape to be centered on itself, important for later rotation on path
347-
348-
if fp.TwistReverse:
349-
newpoles.reverse()
350-
358+
351359
bc = Part.BSplineCurve()
352360
bc.approximate(newpoles)
353361
newshape.append(bc)
@@ -377,14 +385,14 @@ def makeRibsInterpolate(fp, items, alongNormal, makeStartEnd = False):
377385

378386
def EdgesToPoints(shape, nr_frac, points_per_edge, twistReverse = False):
379387
edges = []
380-
redges = shape.Edges.copy()
388+
sortedEdges=sum(Part.sortEdges(shape.Edges),[])
381389
if twistReverse:
382-
redges.reverse()
390+
sortedEdges.reverse()
383391

384392
if nr_frac == 1:
385-
edges = redges
393+
edges = sortedEdges
386394
else:
387-
for edge in redges:
395+
for edge in sortedEdges:
388396
edge1 = edge
389397
for f in range(0, nr_frac - 1):
390398
wires1 = edge1.split(edge1.FirstParameter + (edge1.LastParameter - edge1.FirstParameter) / nr_frac)

CurvedShapes.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -390,10 +390,11 @@ def makeCurvedSegment(Shape1 = None,
390390
DistributionReverse = False,
391391
LoftMaxDegree=5,
392392
MaxLoftSize=16,
393-
Path = None):
393+
Path = None,
394+
ForceInterpolated=False):
394395
import CurvedSegment
395396
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","CurvedSegment")
396-
CurvedSegment.CurvedSegment(obj, Shape1, Shape2, Hullcurves, NormalShape1, NormalShape2, Items, Surface, Solid, InterpolationPoints, Twist, TwistReverse, Distribution, DistributionReverse, LoftMaxDegree, MaxLoftSize, Path)
397+
CurvedSegment.CurvedSegment(obj, Shape1, Shape2, Hullcurves, NormalShape1, NormalShape2, Items, Surface, Solid, InterpolationPoints, Twist, TwistReverse, Distribution, DistributionReverse, LoftMaxDegree, MaxLoftSize, Path, ForceInterpolated)
397398
if FreeCAD.GuiUp:
398399
CurvedSegment.CurvedSegmentViewProvider(obj.ViewObject)
399400
FreeCAD.ActiveDocument.recompute()

InterpolatedMiddle.py

+13-10
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,20 @@ def execute(self, fp):
5757

5858
if fp.InterpolationPoints <= 1:
5959
return
60-
61-
self.update = False
62-
if fp.NormalShape1 == Vector(0,0,0):
63-
fp.NormalShape1 = CurvedShapes.getNormal(fp.Shape1)
64-
65-
if fp.NormalShape2 == Vector(0,0,0):
66-
fp.NormalShape2 = CurvedShapes.getNormal(fp.Shape2)
67-
68-
self.makeRibs(fp)
6960

70-
self.update = True
61+
try:
62+
self.update = False
63+
if fp.NormalShape1 == Vector(0,0,0):
64+
fp.NormalShape1 = CurvedShapes.getNormal(fp.Shape1)
65+
66+
if fp.NormalShape2 == Vector(0,0,0):
67+
fp.NormalShape2 = CurvedShapes.getNormal(fp.Shape2)
68+
69+
self.makeRibs(fp)
70+
self.update = True
71+
except Exception as ex:
72+
self.update = True
73+
raise ex
7174

7275

7376
def onChanged(self, fp, prop):

LIESMICH.md

+2-15
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ Wenn Hullcurves verwendet werden und die Objekte nicht rechtwinklig zum Path ang
104104

105105
### ![](./Resources/icons/curvedSegment.svg) Curved Segment
106106
Interpoliert zwischen zwei 2D Kurven. Die interpolieren Kurven können innerhalb von Hüllkurven angeordnet werden.
107+
Dieses tool funktioniert nicht mit allen beliebigen Kurven. Die Parameter TwistReverse und ForceInterploate können das Ergebis evtl. verbessern.
107108

108109
![CurvedSegment](Examples/CurvedSegment.jpg)
109110
![CurvedSegment2](Examples/CurvedSegment2.jpg)
@@ -135,21 +136,7 @@ Interpoliert zwischen zwei 2D Kurven und ordnet diese rechwinklig zu einer Kurve
135136
Zuerst zwei 2D Kurven auswählen, dann eine Kurve, die als Path verwendet wird, dann optional noch eine oder mehrere Hüllkurven. Danach das Curved Segment Werkzeug verwenden.
136137

137138
#### Parameters
138-
- Shape1: Das erste Object des Segments
139-
- Shape2: Das letzte Object des Segments
140-
- Hullcurves: Keine, eine oder mehrere Hüllkurven. Alle Hüllkurven sollten in der XY, XZ oder YZ Raumebene liegen.
141-
- NormalShape1: Richtung, in der die Array Elemente von Shape1 aus aufgebaut werden (wird automatisch berechnet)
142-
- NormalShape2: Richtung, in der die Array Elemente von Shape2 aus aufgebaut werden (wird automatisch berechnet)
143-
- Items: Anzahl der Array Elemente
144-
- makeSurface: Eine Oberfläche erstellen
145-
- makeSolid: Einen Festkörper erstellen (funktioniert nur, wenn Base eine geschlossene Form ist)
146-
- InterpolationPoints: Wenn Shape1 und Shape2 verschiedenartige Objekte sind, werden die Kurven in diese Anzahl von Einzelpunkten zerlegt
147-
- Twist: (Winkel in Grad) kann eine Rotation zwischen Shape1 unf Shape2 kompensieren
148-
- TwistReverse: wenn True, wird die Drehrichtung geändert
149-
- Distribution: Algorithmus zur Berechnung der Distanz zwischen den Elementen. Default ist 'linear'. Weitere Möglichkeiten: parabolic (x²), x³, sinusoidal, elliptic
150-
- DistributionReverse: Kehrt die Richtung des Distrubution Algorithmus um
151-
- LoftMaxDegree: Gradzahl für die Erstellung von Oberflächen und Festkörpern.
152-
- MaxLoftSize: Maximale Anzahl von Elementen für die Erstellung von Oberfächen und Festkörpern
139+
wie bei Curved Segment
153140
- Path: Kurve, an der die Segmente rechtwinkling ausgerichtet werden.
154141

155142

README.md

+4-16
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ The first curve that you select for Curved Path Array creation will be the base
110110
The parameters ScaleX, ScaleY and ScaleZ have been added because you may want to rescale the items only in one direction, but the hullcurves normally cover 2 or three room directions.
111111

112112
### ![curvedSegmentIcon](./Resources/icons/curvedSegment.svg) Curved Segment
113-
Interpolates between two 2D curves. The interpolated curves can be resized in the bounds of some hullcurves.
113+
Interpolates between two 2D curves. The interpolated curves can be resized in the bounds of some hullcurves.
114+
This does not work for all kinds of shapes. The result may look distorted if the two shapes are too different. The parameters TwistReverse and ForceInterpolated may help to get better results.
114115

115116
![CurvedSegment](Examples/CurvedSegment.jpg)
116117
![CurvedSegment2](Examples/CurvedSegment2.jpg)
@@ -134,29 +135,16 @@ Select two 2D shapes first. The curved segment will be created between them. If
134135
- DistributionReverse: Reverses the direction of the Distribution algorithm
135136
- LoftMaxDegree: degree for surface or solid creation. Play with this parameter if your surface or solid looks distorted
136137
- MaxLoftSize: Maximum size of a loft segment. The surface is created by creating a loft over many array items, however OpenCascade gets very slow and produces artefacts towards the end of the loft when the array gets too large. Therefore the array gets split up intp sub-arrays of up to MaxLoftSize items. Play with this value if a split between segements ends up in a inconvenient spot. Sensible values are between 10 and 50.
138+
- ForceInterpolated: By default, CurvedSegment tries a more direct transition from the first to the second object if the objects have the same number of points and lines and interpolates intermediate shapes if they don't. In case the direct approach does not work because the type or order of lines does not match, interpolation can be forced with this parameter even if the number of points is equal. This should only be needed in rare cases.
137139

138140
### ![curvedSegmentIcon](./Resources/icons/CurvedPathSegment.svg) Curved Path Segment
139141
Interpolates between two 2D curves and sweeps the elements around a path curve. The interpolated curves can be resized in the bounds of some hullcurves.
140142

141143
Select two 2D shapes first, then a sweep path curve. The curved segment will be created between them. If you want to use hullcurves, select them also. Then create the Curved Segment.
142144

143145
#### Parameters
144-
- Shape1: The first object of the segment
145-
- Shape2: The last object of the segment
146-
- Hullcurves: List of one or more bounding curves in XY, XZ or YZ plane (optional)
147-
- NormalShape1: Direction axis of Shape1 (auto computed)
148-
- NormalShape2: Direction axis of Shape2 (auto computed)
149-
- Items: Nr. of items between the segments
150-
- makeSurface: make a surface over the array items
151-
- makeSolid: make a solid if Base is a closed shape
152-
- InterpolationPoints: ignored if Shape1 and Shape2 have the same number of edges and poles. Otherwise all edges will be split (discretized) into this number of points
153-
- Twist: twist into the shape around the profiles normal axis. Useful for example for threaded parts.
154-
- TwistReverse: Reverses the rotation of one Shape. This is for correcting misalignment between the shapes, use this if the entire shape is inversed on itself (wasp-tail)
146+
same as in Curved Segment
155147
- Path: Sweep path - similar to "Path" in CurvedPathArray. If a path is specified, it supersedes the position and orientation of Shape1 and Shape2. CurvedSegment then behaves like CurvedPathArray but with a blend between a beginning and end profile.
156-
- Distribution: Algorithm for distance between array elements. Default is 'linear'. Also selectable: parabolic (x²), x³, sinusoidal, elliptic
157-
- DistributionReverse: Reverses the direction of the Distribution algorithm
158-
- LoftMaxDegree: degree for surface or solid creation. Play with this parameter if your surface or solid looks distorted
159-
- MaxLoftSize: Maximum size of a loft segment. The surface is created by creating a loft over many array items, however OpenCascade gets very slow and produces artefacts towards the end of the loft when the array gets too large. Therefore the array gets split up intp sub-arrays of up to MaxLoftSize items. Play with this value if a split between segements ends up in a inconvenient spot. Sensible values are between 10 and 50.
160148

161149

162150
### ![CornerShapeIcon](./Resources/icons/CornerShape.svg) Interpolated Middle

package.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
<package format="1" xmlns="https://wiki.freecad.org/Package_Metadata">
33
<name>Curved Shapes</name>
44
<description>Create 3D shapes from 2D curves.</description>
5-
<version>1.00.11</version>
6-
<date>2024-10-13</date>
5+
<version>1.00.12</version>
6+
<date>2024-10-14</date>
77
<maintainer email="[email protected]">Christi</maintainer>
88
<license file="LICENSE">LGPL-2.1</license>
99
<url type="repository" branch="master">https://github.com/chbergmann/CurvedShapesWorkbench</url>

0 commit comments

Comments
 (0)