Fix error in rigify property generation
[blender-addons.git] / curve_tools / surfaces.py
blob7fa484a70c92bb600d68a11bdf05031b1bdeaa66
1 import bpy
2 import bmesh
4 from . import mathematics
5 from . import curves
9 class LoftedSplineSurface:
10 def __init__(self, activeSpline, otherSpline, bMesh, vert0Index, resolution):
11 self.splineA = activeSpline
12 self.splineO = otherSpline
14 self.bMesh = bMesh
15 self.vert0Index = vert0Index
16 self.resolution = resolution
19 def Apply(self, worldMatrixA, worldMatrixO):
20 #deltaPar = 1.0 / float(self.resolution - 1)
22 par = 0.0
23 pointA = worldMatrixA @ self.splineA.CalcPoint(par)
24 pointO = worldMatrixO @ self.splineO.CalcPoint(par)
25 self.bMesh.verts[self.vert0Index].co = pointA
26 self.bMesh.verts[self.vert0Index + 1].co = pointO
28 fltResm1 = float(self.resolution - 1)
29 for i in range(1, self.resolution):
30 par = float(i) / fltResm1
32 pointA = worldMatrixA @ self.splineA.CalcPoint(par)
33 pointO = worldMatrixO @ self.splineO.CalcPoint(par)
34 self.bMesh.verts[self.vert0Index + 2 * i].co = pointA
35 self.bMesh.verts[self.vert0Index + 2 * i + 1].co = pointO
38 def AddFaces(self):
39 currIndexA = self.vert0Index
40 currIndexO = self.vert0Index + 1
42 bmVerts = self.bMesh.verts
43 bmVerts.ensure_lookup_table()
45 for i in range(1, self.resolution):
46 nextIndexA = self.vert0Index + 2 * i
47 nextIndexO = nextIndexA + 1
49 self.bMesh.faces.new([bmVerts[currIndexA], bmVerts[currIndexO], bmVerts[nextIndexO], bmVerts[nextIndexA]])
51 currIndexA = nextIndexA
52 currIndexO = nextIndexO
55 class LoftedSurface:
56 @staticmethod
57 def FromSelection():
58 selObjects = bpy.context.selected_objects
59 if len(selObjects) != 2: raise Exception("len(selObjects) != 2") # shouldn't be possible
61 blenderActiveCurve = bpy.context.active_object
62 blenderOtherCurve = selObjects[0]
63 if blenderActiveCurve == blenderOtherCurve: blenderOtherCurve = selObjects[1]
65 aCurve = curves.Curve(blenderActiveCurve)
66 oCurve = curves.Curve(blenderOtherCurve)
68 name = "TODO: autoname"
70 return LoftedSurface(aCurve, oCurve, name)
73 def __init__(self, activeCurve, otherCurve, name = "LoftedSurface"):
74 self.curveA = activeCurve
75 self.curveO = otherCurve
76 self.name = name
78 self.nrSplines = self.curveA.nrSplines
79 if self.curveO.nrSplines < self.nrSplines: self.nrSplines = self.curveO.nrSplines
81 self.bMesh = bmesh.new()
83 self.splineSurfaces = self.SetupSplineSurfaces()
85 self.Apply()
88 def SetupSplineSurfaces(self):
89 rvSplineSurfaces = []
91 currV0Index = 0
92 for i in range(self.nrSplines):
93 splineA = self.curveA.splines[i]
94 splineO = self.curveO.splines[i]
96 res = splineA.resolution
97 if splineO.resolution < res: res = splineO.resolution
99 for iv in range(2 * res): self.bMesh.verts.new()
101 splSurf = LoftedSplineSurface(splineA, splineO, self.bMesh, currV0Index, res)
102 splSurf.AddFaces()
103 rvSplineSurfaces.append(splSurf)
105 currV0Index += 2 * res
107 return rvSplineSurfaces
110 def Apply(self):
111 for splineSurface in self.splineSurfaces: splineSurface.Apply(self.curveA.worldMatrix, self.curveO.worldMatrix)
114 def AddToScene(self):
115 mesh = bpy.data.meshes.new("Mesh" + self.name)
117 self.bMesh.to_mesh(mesh)
118 mesh.update()
120 meshObject = bpy.data.objects.new(self.name, mesh)
122 bpy.context.collection.objects.link(meshObject)
126 # active spline is swept over other spline (rail)
127 class SweptSplineSurface:
128 def __init__(self, activeSpline, otherSpline, bMesh, vert0Index, resolutionA, resolutionO):
129 self.splineA = activeSpline
130 self.splineO = otherSpline
132 self.bMesh = bMesh
133 self.vert0Index = vert0Index
134 self.resolutionA = resolutionA
135 self.resolutionO = resolutionO
138 def Apply(self, worldMatrixA, worldMatrixO):
139 localPointsA = []
140 fltResAm1 = float(self.resolutionA - 1)
141 for i in range(self.resolutionA):
142 par = float(i) / fltResAm1
143 pointA = self.splineA.CalcPoint(par)
144 localPointsA.append(pointA)
147 worldPointsO = []
148 localDerivativesO = []
149 fltResOm1 = float(self.resolutionO - 1)
150 for i in range(self.resolutionO):
151 par = float(i) / fltResOm1
153 pointO = self.splineO.CalcPoint(par)
154 worldPointsO.append(worldMatrixO @ pointO)
156 derivativeO = self.splineO.CalcDerivative(par)
157 localDerivativesO.append(derivativeO)
160 currWorldMatrixA = worldMatrixA
161 worldMatrixOInv = worldMatrixO.inverted()
162 prevDerivativeO = localDerivativesO[0]
163 for iO in range(self.resolutionO):
164 currDerivativeO = localDerivativesO[iO]
165 localRotMatO = mathematics.CalcRotationMatrix(prevDerivativeO, currDerivativeO)
167 currLocalAToLocalO = worldMatrixOInv @ currWorldMatrixA
168 worldPointsA = []
169 for iA in range(self.resolutionA):
170 pointALocalToO = currLocalAToLocalO @ localPointsA[iA]
171 rotatedPointA = localRotMatO @ pointALocalToO
172 worldPointsA.append(worldMatrixO @ rotatedPointA)
174 worldOffsetsA = []
175 worldPoint0A = worldPointsA[0]
176 for i in range(self.resolutionA): worldOffsetsA.append(worldPointsA[i] - worldPoint0A)
179 for iA in range(self.resolutionA):
180 iVert = self.vert0Index + (self.resolutionA * iO) + iA
181 currVert = worldPointsO[iO] + worldOffsetsA[iA]
182 self.bMesh.verts[iVert].co = currVert
184 prevDerivativeO = currDerivativeO
185 currWorldMatrixA = worldMatrixO @ localRotMatO @ currLocalAToLocalO
188 def AddFaces(self):
189 bmVerts = self.bMesh.verts
190 bmVerts.ensure_lookup_table()
192 for iO in range(self.resolutionO - 1):
193 for iA in range(self.resolutionA - 1):
194 currIndexA1 = self.vert0Index + (self.resolutionA * iO) + iA
195 currIndexA2 = currIndexA1 + 1
196 nextIndexA1 = self.vert0Index + (self.resolutionA * (iO + 1)) + iA
197 nextIndexA2 = nextIndexA1 + 1
199 self.bMesh.faces.new([bmVerts[currIndexA1], bmVerts[currIndexA2], bmVerts[nextIndexA2], bmVerts[nextIndexA1]])
203 class SweptSurface:
204 @staticmethod
205 def FromSelection():
206 selObjects = bpy.context.selected_objects
207 if len(selObjects) != 2: raise Exception("len(selObjects) != 2") # shouldn't be possible
209 blenderActiveCurve = bpy.context.active_object
210 blenderOtherCurve = selObjects[0]
211 if blenderActiveCurve == blenderOtherCurve: blenderOtherCurve = selObjects[1]
213 aCurve = curves.Curve(blenderActiveCurve)
214 oCurve = curves.Curve(blenderOtherCurve)
216 name = "TODO: autoname"
218 return SweptSurface(aCurve, oCurve, name)
221 def __init__(self, activeCurve, otherCurve, name = "SweptSurface"):
222 self.curveA = activeCurve
223 self.curveO = otherCurve
224 self.name = name
226 self.nrSplines = self.curveA.nrSplines
227 if self.curveO.nrSplines < self.nrSplines: self.nrSplines = self.curveO.nrSplines
229 self.bMesh = bmesh.new()
231 self.splineSurfaces = self.SetupSplineSurfaces()
233 self.Apply()
236 def SetupSplineSurfaces(self):
237 rvSplineSurfaces = []
239 currV0Index = 0
240 for i in range(self.nrSplines):
241 splineA = self.curveA.splines[i]
242 splineO = self.curveO.splines[i]
244 resA = splineA.resolution
245 resO = splineO.resolution
247 for iv in range(resA * resO): self.bMesh.verts.new()
249 splSurf = SweptSplineSurface(splineA, splineO, self.bMesh, currV0Index, resA, resO)
250 splSurf.AddFaces()
251 rvSplineSurfaces.append(splSurf)
253 currV0Index += resA * resO
255 return rvSplineSurfaces
258 def Apply(self):
259 for splineSurface in self.splineSurfaces: splineSurface.Apply(self.curveA.worldMatrix, self.curveO.worldMatrix)
262 def AddToScene(self):
263 mesh = bpy.data.meshes.new("Mesh" + self.name)
265 self.bMesh.to_mesh(mesh)
266 mesh.update()
268 meshObject = bpy.data.objects.new(self.name, mesh)
270 bpy.context.collection.objects.link(meshObject)
274 # profileSpline is swept over rail1Spline and scaled/rotated to have its endpoint on rail2Spline
275 class BirailedSplineSurface:
276 def __init__(self, rail1Spline, rail2Spline, profileSpline, bMesh, vert0Index, resolutionRails, resolutionProfile):
277 self.rail1Spline = rail1Spline
278 self.rail2Spline = rail2Spline
279 self.profileSpline = profileSpline
281 self.bMesh = bMesh
282 self.vert0Index = vert0Index
283 self.resolutionRails = resolutionRails
284 self.resolutionProfile = resolutionProfile
287 def Apply(self, worldMatrixRail1, worldMatrixRail2, worldMatrixProfile):
288 localPointsProfile = []
289 fltResProfilem1 = float(self.resolutionProfile - 1)
290 for i in range(self.resolutionProfile):
291 par = float(i) / fltResProfilem1
292 pointProfile = self.profileSpline.CalcPoint(par)
293 localPointsProfile.append(pointProfile)
296 worldPointsRail1 = []
297 localDerivativesRail1 = []
298 worldPointsRail2 = []
299 fltResRailsm1 = float(self.resolutionRails - 1)
300 for i in range(self.resolutionRails):
301 par = float(i) / fltResRailsm1
303 pointRail1 = self.rail1Spline.CalcPoint(par)
304 worldPointsRail1.append(worldMatrixRail1 @ pointRail1)
306 derivativeRail1 = self.rail1Spline.CalcDerivative(par)
307 localDerivativesRail1.append(derivativeRail1)
309 pointRail2 = self.rail2Spline.CalcPoint(par)
310 worldPointsRail2.append(worldMatrixRail2 @ pointRail2)
313 currWorldMatrixProfile = worldMatrixProfile
314 worldMatrixRail1Inv = worldMatrixRail1.inverted()
315 prevDerivativeRail1 = localDerivativesRail1[0]
316 for iRail in range(self.resolutionRails):
317 currDerivativeRail1 = localDerivativesRail1[iRail]
318 localRotMatRail1 = mathematics.CalcRotationMatrix(prevDerivativeRail1, currDerivativeRail1)
320 currLocalProfileToLocalRail1 = worldMatrixRail1Inv @ currWorldMatrixProfile
321 worldPointsProfileRail1 = []
322 for iProfile in range(self.resolutionProfile):
323 pointProfileLocalToRail1 = currLocalProfileToLocalRail1 @ localPointsProfile[iProfile]
324 rotatedPointProfile = localRotMatRail1 @ pointProfileLocalToRail1
325 worldPointsProfileRail1.append(worldMatrixRail1 @ rotatedPointProfile)
327 worldOffsetsProfileRail1 = []
328 worldPoint0ProfileRail1 = worldPointsProfileRail1[0]
329 for iProfile in range(self.resolutionProfile): worldOffsetsProfileRail1.append(worldPointsProfileRail1[iProfile] - worldPoint0ProfileRail1)
331 worldStartPointProfileRail1 = worldPointsRail1[iRail]
332 worldEndPointProfileRail1 = worldStartPointProfileRail1 + worldOffsetsProfileRail1[-1]
333 v3From = worldEndPointProfileRail1 - worldStartPointProfileRail1
334 v3To = worldPointsRail2[iRail] - worldStartPointProfileRail1
335 if not v3From.magnitude == 0:
336 scaleFactorRail2 = v3To.magnitude / v3From.magnitude
337 else:
338 scaleFactorRail2 = 1
339 rotMatRail2 = mathematics.CalcRotationMatrix(v3From, v3To)
341 worldOffsetsProfileRail2 = []
342 for iProfile in range(self.resolutionProfile):
343 offsetProfileRail1 = worldOffsetsProfileRail1[iProfile]
344 worldOffsetsProfileRail2.append(rotMatRail2 @ (offsetProfileRail1 * scaleFactorRail2))
347 for iProfile in range(self.resolutionProfile):
348 iVert = self.vert0Index + (self.resolutionProfile * iRail) + iProfile
349 currVert = worldPointsRail1[iRail] + worldOffsetsProfileRail2[iProfile]
350 self.bMesh.verts[iVert].co = currVert
352 prevDerivativeRail1 = currDerivativeRail1
353 currWorldMatrixProfile = worldMatrixRail1 @ localRotMatRail1 @ currLocalProfileToLocalRail1
356 def AddFaces(self):
357 bmVerts = self.bMesh.verts
358 bmVerts.ensure_lookup_table()
360 for iRail in range(self.resolutionRails - 1):
361 for iProfile in range(self.resolutionProfile - 1):
362 currIndex1 = self.vert0Index + (self.resolutionProfile * iRail) + iProfile
363 currIndex2 = currIndex1 + 1
364 nextIndex1 = self.vert0Index + (self.resolutionProfile * (iRail + 1)) + iProfile
365 nextIndex2 = nextIndex1 + 1
367 self.bMesh.faces.new([bmVerts[currIndex1], bmVerts[currIndex2], bmVerts[nextIndex2], bmVerts[nextIndex1]])
371 class BirailedSurface:
372 @staticmethod
373 def FromSelection():
374 selectedObjects = bpy.context.selected_objects
376 rail1Curve = curves.Curve(selectedObjects[0])
377 rail2Curve = curves.Curve(selectedObjects[1])
378 profileCurve = curves.Curve(selectedObjects[2])
380 name = "BirailedSurface"
382 return BirailedSurface(rail1Curve, rail2Curve, profileCurve, name)
385 def __init__(self, rail1Curve, rail2Curve, profileCurve, name = "BirailedSurface"):
386 self.rail1Curve = rail1Curve
387 self.rail2Curve = rail2Curve
388 self.profileCurve = profileCurve
389 self.name = name
391 self.nrSplines = self.rail1Curve.nrSplines
392 if self.rail2Curve.nrSplines < self.nrSplines: self.nrSplines = self.rail2Curve.nrSplines
393 if self.profileCurve.nrSplines < self.nrSplines: self.nrSplines = self.profileCurve.nrSplines
395 self.bMesh = bmesh.new()
397 self.splineSurfaces = self.SetupSplineSurfaces()
399 self.Apply()
402 def SetupSplineSurfaces(self):
403 rvSplineSurfaces = []
405 currV0Index = 0
406 for i in range(self.nrSplines):
407 splineRail1 = self.rail1Curve.splines[i]
408 splineRail2 = self.rail2Curve.splines[i]
409 splineProfile = self.profileCurve.splines[i]
411 resProfile = splineProfile.resolution
412 resRails = splineRail1.resolution
413 if splineRail2.resolution < resRails: resRails = splineRail2.resolution
415 for iv in range(resProfile * resRails): self.bMesh.verts.new()
417 splSurf = BirailedSplineSurface(splineRail1, splineRail2, splineProfile, self.bMesh, currV0Index, resRails, resProfile)
418 splSurf.AddFaces()
419 rvSplineSurfaces.append(splSurf)
421 currV0Index += resProfile * resRails
423 return rvSplineSurfaces
426 def Apply(self):
427 for splineSurface in self.splineSurfaces: splineSurface.Apply(self.rail1Curve.worldMatrix, self.rail2Curve.worldMatrix, self.profileCurve.worldMatrix)
430 def AddToScene(self):
431 mesh = bpy.data.meshes.new("Mesh" + self.name)
433 self.bMesh.to_mesh(mesh)
434 mesh.update()
436 meshObject = bpy.data.objects.new(self.name, mesh)
438 bpy.context.collection.objects.link(meshObject)