Curve Tools 2: Update addon to Blender 2.80
authorSpivak Vladimir (cwolf3d) <cwolf3d@gmail.com>
Sat, 25 May 2019 22:19:10 +0000 (01:19 +0300)
committerSpivak Vladimir (cwolf3d) <cwolf3d@gmail.com>
Sat, 25 May 2019 22:19:10 +0000 (01:19 +0300)
curve_tools/CurveIntersections.py
curve_tools/Operators.py
curve_tools/Surfaces.py
curve_tools/__init__.py
curve_tools/curve_outline.py
curve_tools/curve_remove_doubles.py [new file with mode: 0644]

index 0c8da2a..0625470 100644 (file)
@@ -49,14 +49,14 @@ class BezierSegmentsIntersector:
         for iSample1 in range(nrSamples1):
             segPar10 = float(iSample1) / fltNrSamples1
             segPar11 = float(iSample1 + 1) / fltNrSamples1
-            P0 = self.worldMatrix1 * self.segment1.CalcPoint(parameter=segPar10)
-            P1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter=segPar11)
+            P0 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar10)
+            P1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar11)
 
             for iSample2 in range(nrSamples2):
                 segPar20 = float(iSample2) / fltNrSamples2
                 segPar21 = float(iSample2 + 1) / fltNrSamples2
-                Q0 = self.worldMatrix2 * self.segment2.CalcPoint(parameter=segPar20)
-                Q1 = self.worldMatrix2 * self.segment2.CalcPoint(parameter=segPar21)
+                Q0 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar20)
+                Q1 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar21)
 
                 intersectionPointData = Math.CalcIntersectionPointLineSegments(P0, P1, Q0, Q1, limitDistance)
                 if intersectionPointData is None:
@@ -85,14 +85,14 @@ class BezierSegmentsIntersector:
         for iSample1 in range(nrSamples1):
             segPar10 = float(iSample1) / fltNrSamples1
             segPar11 = float(iSample1 + 1) / fltNrSamples1
-            P0 = self.worldMatrix1 * self.segment1.CalcPoint(parameter=segPar10)
-            P1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter=segPar11)
+            P0 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar10)
+            P1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar11)
 
             for iSample2 in range(nrSamples2):
                 segPar20 = float(iSample2) / fltNrSamples2
                 segPar21 = float(iSample2 + 1) / fltNrSamples2
-                Q0 = self.worldMatrix2 * self.segment2.CalcPoint(parameter=segPar20)
-                Q1 = self.worldMatrix2 * self.segment2.CalcPoint(parameter=segPar21)
+                Q0 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar20)
+                Q1 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar21)
 
                 intersectionPointData = Math.CalcIntersectionPointLineSegments(P0, P1, Q0, Q1, limitDistance)
                 if intersectionPointData is None:
@@ -100,7 +100,7 @@ class BezierSegmentsIntersector:
 
                 # intersection point can't be an existing point
                 intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / (fltNrSamples1))
-                worldPoint1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter=intersectionSegment1Parameter)
+                worldPoint1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=intersectionSegment1Parameter)
                 if (Math.IsSamePoint(P0, worldPoint1, limitDistance)) or \
                    (Math.IsSamePoint(P1, worldPoint1, limitDistance)):
 
@@ -111,7 +111,7 @@ class BezierSegmentsIntersector:
                                                                         worldPoint1)
 
                 intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / (fltNrSamples2))
-                worldPoint2 = self.worldMatrix2 * self.segment2.CalcPoint(parameter=intersectionSegment2Parameter)
+                worldPoint2 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=intersectionSegment2Parameter)
                 if (Math.IsSamePoint(Q0, worldPoint2, limitDistance)) or \
                    (Math.IsSamePoint(Q1, worldPoint2, limitDistance)):
 
@@ -134,27 +134,27 @@ class BezierSegmentsIntersector:
         for iSample1 in range(nrSamples1):
             segPar10 = float(iSample1) / fltNrSamples1
             segPar11 = float(iSample1 + 1) / fltNrSamples1
-            P0 = self.worldMatrix1 * self.segment1.CalcPoint(parameter=segPar10)
-            P1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter=segPar11)
+            P0 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar10)
+            P1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar11)
 
             for iSample2 in range(nrSamples2):
                 segPar20 = float(iSample2) / fltNrSamples2
                 segPar21 = float(iSample2 + 1) / fltNrSamples2
-                Q0 = self.worldMatrix2 * self.segment2.CalcPoint(parameter=segPar20)
-                Q1 = self.worldMatrix2 * self.segment2.CalcPoint(parameter=segPar21)
+                Q0 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar20)
+                Q1 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar21)
 
                 intersectionPointData = Math.CalcIntersectionPointsLineSegmentsDIR(P0, P1, Q0, Q1, algoDIR)
                 if intersectionPointData is None:
                     continue
 
                 intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / fltNrSamples1)
-                worldPoint1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter=intersectionSegment1Parameter)
+                worldPoint1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=intersectionSegment1Parameter)
                 intersectionPoint1 = BezierSegmentIntersectionPoint(self.segment1,
                                                                     intersectionSegment1Parameter,
                                                                     worldPoint1)
 
                 intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / fltNrSamples2)
-                worldPoint2 = self.worldMatrix2 * self.segment2.CalcPoint(parameter=intersectionSegment2Parameter)
+                worldPoint2 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=intersectionSegment2Parameter)
                 intersectionPoint2 = BezierSegmentIntersectionPoint(self.segment2,
                                                                     intersectionSegment2Parameter,
                                                                     worldPoint2)
@@ -174,14 +174,14 @@ class BezierSegmentsIntersector:
         for iSample1 in range(nrSamples1):
             segPar10 = float(iSample1) / fltNrSamples1
             segPar11 = float(iSample1 + 1) / fltNrSamples1
-            P0 = self.worldMatrix1 * self.segment1.CalcPoint(parameter=segPar10)
-            P1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter=segPar11)
+            P0 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar10)
+            P1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar11)
 
             for iSample2 in range(nrSamples2):
                 segPar20 = float(iSample2) / fltNrSamples2
                 segPar21 = float(iSample2 + 1) / fltNrSamples2
-                Q0 = self.worldMatrix2 * self.segment2.CalcPoint(parameter=segPar20)
-                Q1 = self.worldMatrix2 * self.segment2.CalcPoint(parameter=segPar21)
+                Q0 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar20)
+                Q1 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar21)
 
                 intersectionPointData = Math.CalcIntersectionPointsLineSegmentsDIR(P0, P1, Q0, Q1, algoDIR)
                 if intersectionPointData is None:
@@ -189,7 +189,7 @@ class BezierSegmentsIntersector:
 
                 # intersection point can't be an existing point
                 intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / (fltNrSamples1))
-                worldPoint1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter=intersectionSegment1Parameter)
+                worldPoint1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=intersectionSegment1Parameter)
                 if (Math.IsSamePoint(P0, worldPoint1, limitDistance)) or \
                    (Math.IsSamePoint(P1, worldPoint1, limitDistance)):
 
@@ -200,7 +200,7 @@ class BezierSegmentsIntersector:
                                                                         worldPoint1)
 
                 intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / (fltNrSamples2))
-                worldPoint2 = self.worldMatrix2 * self.segment2.CalcPoint(parameter=intersectionSegment2Parameter)
+                worldPoint2 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=intersectionSegment2Parameter)
                 if (Math.IsSamePoint(Q0, worldPoint2, limitDistance)) or \
                    (Math.IsSamePoint(Q1, worldPoint2, limitDistance)):
 
@@ -223,27 +223,27 @@ class BezierSegmentsIntersector:
         for iSample1 in range(nrSamples1):
             segPar10 = float(iSample1) / fltNrSamples1
             segPar11 = float(iSample1 + 1) / fltNrSamples1
-            P0 = self.worldMatrix1 * self.segment1.CalcPoint(parameter=segPar10)
-            P1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter=segPar11)
+            P0 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar10)
+            P1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar11)
 
             for iSample2 in range(nrSamples2):
                 segPar20 = float(iSample2) / fltNrSamples2
                 segPar21 = float(iSample2 + 1) / fltNrSamples2
-                Q0 = self.worldMatrix2 * self.segment2.CalcPoint(parameter=segPar20)
-                Q1 = self.worldMatrix2 * self.segment2.CalcPoint(parameter=segPar21)
+                Q0 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar20)
+                Q1 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar21)
 
                 intersectionPointData = Math.CalcIntersectionPointsLineSegmentsPOV(P0, P1, Q0, Q1, algoPOV)
                 if intersectionPointData is None:
                     continue
 
                 intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / fltNrSamples1)
-                worldPoint1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter=intersectionSegment1Parameter)
+                worldPoint1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=intersectionSegment1Parameter)
                 intersectionPoint1 = BezierSegmentIntersectionPoint(self.segment1,
                                                                     intersectionSegment1Parameter,
                                                                     worldPoint1)
 
                 intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / fltNrSamples2)
-                worldPoint2 = self.worldMatrix2 * self.segment2.CalcPoint(parameter=intersectionSegment2Parameter)
+                worldPoint2 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=intersectionSegment2Parameter)
                 intersectionPoint2 = BezierSegmentIntersectionPoint(self.segment2,
                                                                     intersectionSegment2Parameter,
                                                                     worldPoint2)
@@ -263,14 +263,14 @@ class BezierSegmentsIntersector:
         for iSample1 in range(nrSamples1):
             segPar10 = float(iSample1) / fltNrSamples1
             segPar11 = float(iSample1 + 1) / fltNrSamples1
-            P0 = self.worldMatrix1 * self.segment1.CalcPoint(parameter=segPar10)
-            P1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter=segPar11)
+            P0 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar10)
+            P1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar11)
 
             for iSample2 in range(nrSamples2):
                 segPar20 = float(iSample2) / fltNrSamples2
                 segPar21 = float(iSample2 + 1) / fltNrSamples2
-                Q0 = self.worldMatrix2 * self.segment2.CalcPoint(parameter=segPar20)
-                Q1 = self.worldMatrix2 * self.segment2.CalcPoint(parameter=segPar21)
+                Q0 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar20)
+                Q1 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar21)
 
                 intersectionPointData = Math.CalcIntersectionPointsLineSegmentsPOV(P0, P1, Q0, Q1, algoPOV)
                 if intersectionPointData is None:
@@ -278,7 +278,7 @@ class BezierSegmentsIntersector:
 
                 # intersection point can't be an existing point
                 intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / fltNrSamples1)
-                worldPoint1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter=intersectionSegment1Parameter)
+                worldPoint1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=intersectionSegment1Parameter)
                 if (Math.IsSamePoint(P0, worldPoint1, limitDistance)) or \
                    (Math.IsSamePoint(P1, worldPoint1, limitDistance)):
 
@@ -289,7 +289,7 @@ class BezierSegmentsIntersector:
                                                                         worldPoint1)
 
                 intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / fltNrSamples2)
-                worldPoint2 = self.worldMatrix2 * self.segment2.CalcPoint(parameter=intersectionSegment2Parameter)
+                worldPoint2 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=intersectionSegment2Parameter)
                 if (Math.IsSamePoint(Q0, worldPoint2, limitDistance)) or \
                    (Math.IsSamePoint(Q1, worldPoint2, limitDistance)):
 
@@ -332,28 +332,28 @@ class BezierSegmentsIntersector:
         for iSample1 in range(nrSamples1):
             segPar10 = float(iSample1) / fltNrSamples1
             segPar11 = float(iSample1 + 1) / fltNrSamples1
-            P0 = self.worldMatrix1 * self.segment1.CalcPoint(parameter=segPar10)
-            P1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter=segPar11)
+            P0 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar10)
+            P1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar11)
 
             for iSample2 in range(nrSamples2):
                 segPar20 = float(iSample2) / fltNrSamples2
                 segPar21 = float(iSample2 + 1) / fltNrSamples2
-                Q0 = self.worldMatrix2 * self.segment2.CalcPoint(parameter=segPar20)
-                Q1 = self.worldMatrix2 * self.segment2.CalcPoint(parameter=segPar21)
+                Q0 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar20)
+                Q1 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar21)
 
                 intersectionPointData = Math.CalcIntersectionPointLineSegments(P0, P1, Q0, Q1, limitDistance)
                 if intersectionPointData is None:
                     continue
 
                 intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / fltNrSamples1)
-                worldPoint1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter=intersectionSegment1Parameter)
+                worldPoint1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=intersectionSegment1Parameter)
                 intersectionPoint1 = BezierSegmentIntersectionPoint(self.segment1,
                                                                     intersectionSegment1Parameter,
                                                                     worldPoint1)
                 rvIntersections1.append(intersectionPoint1)
 
                 intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / fltNrSamples2)
-                worldPoint2 = self.worldMatrix2 * self.segment2.CalcPoint(parameter=intersectionSegment2Parameter)
+                worldPoint2 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=intersectionSegment2Parameter)
                 intersectionPoint2 = BezierSegmentIntersectionPoint(self.segment2,
                                                                     intersectionSegment2Parameter,
                                                                     worldPoint2)
@@ -373,28 +373,28 @@ class BezierSegmentsIntersector:
         for iSample1 in range(nrSamples1):
             segPar10 = float(iSample1) / fltNrSamples1
             segPar11 = float(iSample1 + 1) / fltNrSamples1
-            P0 = self.worldMatrix1 * self.segment1.CalcPoint(parameter=segPar10)
-            P1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter=segPar11)
+            P0 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar10)
+            P1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar11)
 
             for iSample2 in range(nrSamples2):
                 segPar20 = float(iSample2) / fltNrSamples2
                 segPar21 = float(iSample2 + 1) / fltNrSamples2
-                Q0 = self.worldMatrix2 * self.segment2.CalcPoint(parameter=segPar20)
-                Q1 = self.worldMatrix2 * self.segment2.CalcPoint(parameter=segPar21)
+                Q0 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar20)
+                Q1 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar21)
 
                 intersectionPointData = Math.CalcIntersectionPointsLineSegmentsDIR(P0, P1, Q0, Q1, algoDIR)
                 if intersectionPointData is None:
                     continue
 
                 intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / fltNrSamples1)
-                worldPoint1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter=intersectionSegment1Parameter)
+                worldPoint1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=intersectionSegment1Parameter)
                 intersectionPoint1 = BezierSegmentIntersectionPoint(self.segment1,
                                                                     intersectionSegment1Parameter,
                                                                     worldPoint1)
                 rvIntersections1.append(intersectionPoint1)
 
                 intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / fltNrSamples2)
-                worldPoint2 = self.worldMatrix2 * self.segment2.CalcPoint(parameter=intersectionSegment2Parameter)
+                worldPoint2 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=intersectionSegment2Parameter)
                 intersectionPoint2 = BezierSegmentIntersectionPoint(self.segment2,
                                                                     intersectionSegment2Parameter,
                                                                     worldPoint2)
@@ -414,28 +414,28 @@ class BezierSegmentsIntersector:
         for iSample1 in range(nrSamples1):
             segPar10 = float(iSample1) / fltNrSamples1
             segPar11 = float(iSample1 + 1) / fltNrSamples1
-            P0 = self.worldMatrix1 * self.segment1.CalcPoint(parameter=segPar10)
-            P1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter=segPar11)
+            P0 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar10)
+            P1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=segPar11)
 
             for iSample2 in range(nrSamples2):
                 segPar20 = float(iSample2) / fltNrSamples2
                 segPar21 = float(iSample2 + 1) / fltNrSamples2
-                Q0 = self.worldMatrix2 * self.segment2.CalcPoint(parameter=segPar20)
-                Q1 = self.worldMatrix2 * self.segment2.CalcPoint(parameter=segPar21)
+                Q0 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar20)
+                Q1 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar21)
 
                 intersectionPointData = Math.CalcIntersectionPointsLineSegmentsPOV(P0, P1, Q0, Q1, algoPOV)
                 if intersectionPointData is None:
                     continue
 
                 intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / fltNrSamples1)
-                worldPoint1 = self.worldMatrix1 * self.segment1.CalcPoint(parameter=intersectionSegment1Parameter)
+                worldPoint1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=intersectionSegment1Parameter)
                 intersectionPoint1 = BezierSegmentIntersectionPoint(self.segment1,
                                                                     intersectionSegment1Parameter,
                                                                     worldPoint1)
                 rvIntersections1.append(intersectionPoint1)
 
                 intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / fltNrSamples2)
-                worldPoint2 = self.worldMatrix2 * self.segment2.CalcPoint(parameter=intersectionSegment2Parameter)
+                worldPoint2 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=intersectionSegment2Parameter)
                 intersectionPoint2 = BezierSegmentIntersectionPoint(self.segment2,
                                                                     intersectionSegment2Parameter,
                                                                     worldPoint2)
index c7c7b40..9eca61c 100644 (file)
@@ -186,7 +186,7 @@ class OperatorOriginToSpline0Start(bpy.types.Operator):
     def execute(self, context):
         blCurve = context.active_object
         blSpline = blCurve.data.splines[0]
-        newOrigin = blCurve.matrix_world * blSpline.bezier_points[0].co
+        newOrigin = blCurve.matrix_world @ blSpline.bezier_points[0].co
 
         origOrigin = bpy.context.scene.cursor.location.copy()
         print("--", "origOrigin: %.6f, %.6f, %.6f" % (origOrigin.x, origOrigin.y, origOrigin.z))
index f2a1399..22b5119 100644 (file)
@@ -20,8 +20,8 @@ class LoftedSplineSurface:
         #deltaPar = 1.0 / float(self.resolution - 1)
 
         par = 0.0
-        pointA = worldMatrixA * self.splineA.CalcPoint(par)
-        pointO = worldMatrixO * self.splineO.CalcPoint(par)
+        pointA = worldMatrixA @ self.splineA.CalcPoint(par)
+        pointO = worldMatrixO @ self.splineO.CalcPoint(par)
         self.bMesh.verts[self.vert0Index].co = pointA
         self.bMesh.verts[self.vert0Index + 1].co = pointO
 
@@ -29,8 +29,8 @@ class LoftedSplineSurface:
         for i in range(1, self.resolution):
             par = float(i) / fltResm1
 
-            pointA = worldMatrixA * self.splineA.CalcPoint(par)
-            pointO = worldMatrixO * self.splineO.CalcPoint(par)
+            pointA = worldMatrixA @ self.splineA.CalcPoint(par)
+            pointO = worldMatrixO @ self.splineO.CalcPoint(par)
             self.bMesh.verts[self.vert0Index + 2 * i].co = pointA
             self.bMesh.verts[self.vert0Index + 2 * i + 1].co = pointO
 
@@ -151,7 +151,7 @@ class SweptSplineSurface:
             par = float(i) / fltResOm1
 
             pointO = self.splineO.CalcPoint(par)
-            worldPointsO.append(worldMatrixO * pointO)
+            worldPointsO.append(worldMatrixO @ pointO)
 
             derivativeO = self.splineO.CalcDerivative(par)
             localDerivativesO.append(derivativeO)
@@ -164,12 +164,12 @@ class SweptSplineSurface:
             currDerivativeO = localDerivativesO[iO]
             localRotMatO = Math.CalcRotationMatrix(prevDerivativeO, currDerivativeO)
 
-            currLocalAToLocalO = worldMatrixOInv * currWorldMatrixA
+            currLocalAToLocalO = worldMatrixOInv @ currWorldMatrixA
             worldPointsA = []
             for iA in range(self.resolutionA):
-                pointALocalToO = currLocalAToLocalO * localPointsA[iA]
-                rotatedPointA = localRotMatO * pointALocalToO
-                worldPointsA.append(worldMatrixO * rotatedPointA)
+                pointALocalToO = currLocalAToLocalO @ localPointsA[iA]
+                rotatedPointA = localRotMatO @ pointALocalToO
+                worldPointsA.append(worldMatrixO @ rotatedPointA)
 
             worldOffsetsA = []
             worldPoint0A = worldPointsA[0]
@@ -182,7 +182,7 @@ class SweptSplineSurface:
                 self.bMesh.verts[iVert].co = currVert
 
             prevDerivativeO = currDerivativeO
-            currWorldMatrixA = worldMatrixO * localRotMatO * currLocalAToLocalO
+            currWorldMatrixA = worldMatrixO @ localRotMatO @ currLocalAToLocalO
 
 
     def AddFaces(self):
@@ -301,13 +301,13 @@ class BirailedSplineSurface:
             par = float(i) / fltResRailsm1
 
             pointRail1 = self.rail1Spline.CalcPoint(par)
-            worldPointsRail1.append(worldMatrixRail1 * pointRail1)
+            worldPointsRail1.append(worldMatrixRail1 @ pointRail1)
 
             derivativeRail1 = self.rail1Spline.CalcDerivative(par)
             localDerivativesRail1.append(derivativeRail1)
 
             pointRail2 = self.rail2Spline.CalcPoint(par)
-            worldPointsRail2.append(worldMatrixRail2 * pointRail2)
+            worldPointsRail2.append(worldMatrixRail2 @ pointRail2)
 
 
         currWorldMatrixProfile = worldMatrixProfile
@@ -317,12 +317,12 @@ class BirailedSplineSurface:
             currDerivativeRail1 = localDerivativesRail1[iRail]
             localRotMatRail1 = Math.CalcRotationMatrix(prevDerivativeRail1, currDerivativeRail1)
 
-            currLocalProfileToLocalRail1 = worldMatrixRail1Inv * currWorldMatrixProfile
+            currLocalProfileToLocalRail1 = worldMatrixRail1Inv @ currWorldMatrixProfile
             worldPointsProfileRail1 = []
             for iProfile in range(self.resolutionProfile):
-                pointProfileLocalToRail1 = currLocalProfileToLocalRail1 * localPointsProfile[iProfile]
-                rotatedPointProfile = localRotMatRail1 * pointProfileLocalToRail1
-                worldPointsProfileRail1.append(worldMatrixRail1 * rotatedPointProfile)
+                pointProfileLocalToRail1 = currLocalProfileToLocalRail1 @ localPointsProfile[iProfile]
+                rotatedPointProfile = localRotMatRail1 @ pointProfileLocalToRail1
+                worldPointsProfileRail1.append(worldMatrixRail1 @ rotatedPointProfile)
 
             worldOffsetsProfileRail1 = []
             worldPoint0ProfileRail1 = worldPointsProfileRail1[0]
@@ -332,13 +332,16 @@ class BirailedSplineSurface:
             worldEndPointProfileRail1 = worldStartPointProfileRail1 + worldOffsetsProfileRail1[-1]
             v3From = worldEndPointProfileRail1 - worldStartPointProfileRail1
             v3To = worldPointsRail2[iRail] - worldStartPointProfileRail1
-            scaleFactorRail2 = v3To.magnitude / v3From.magnitude
+            if not v3From.magnitude == 0:
+                scaleFactorRail2 = v3To.magnitude / v3From.magnitude
+            else:
+                scaleFactorRail2 = 1
             rotMatRail2 = Math.CalcRotationMatrix(v3From, v3To)
 
             worldOffsetsProfileRail2 = []
             for iProfile in range(self.resolutionProfile):
                 offsetProfileRail1 = worldOffsetsProfileRail1[iProfile]
-                worldOffsetsProfileRail2.append(rotMatRail2 * (offsetProfileRail1 * scaleFactorRail2))
+                worldOffsetsProfileRail2.append(rotMatRail2 @ (offsetProfileRail1 * scaleFactorRail2))
 
 
             for iProfile in range(self.resolutionProfile):
@@ -347,7 +350,7 @@ class BirailedSplineSurface:
                 self.bMesh.verts[iVert].co = currVert
 
             prevDerivativeRail1 = currDerivativeRail1
-            currWorldMatrixProfile = worldMatrixRail1 * localRotMatRail1 * currLocalProfileToLocalRail1
+            currWorldMatrixProfile = worldMatrixRail1 @ localRotMatRail1 @ currLocalProfileToLocalRail1
 
 
     def AddFaces(self):
index 370e1dc..c1e6128 100644 (file)
@@ -20,8 +20,8 @@ bl_info = {
     "name": "Curve Tools 2",
     "description": "Adds some functionality for bezier/nurbs curve/surface modeling",
     "author": "Mackraken, guy lateur",
-    "version": (0, 2, 1),
-    "blender": (2, 71, 0),
+    "version": (0, 3, 0),
+    "blender": (2, 80, 0),
     "location": "View3D > Tool Shelf > Addons Tab",
     "warning": "WIP",
     "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/"
@@ -48,6 +48,7 @@ from . import Properties
 from . import Operators
 from . import auto_loft
 from . import curve_outline
+from . import curve_remove_doubles
 
 
 from bpy.types import (
@@ -185,10 +186,10 @@ class CurveTools2Settings(PropertyGroup):
             )
 
 
-class CurvePanel(Panel):
+class VIEW3D_PT_CurvePanel(Panel):
     bl_label = "Curve Tools 2"
     bl_space_type = "VIEW_3D"
-    bl_region_type = "TOOLS"
+    bl_region_type = "UI"
     bl_options = {'DEFAULT_CLOSED'}
     bl_category = "Tools"
 
@@ -284,7 +285,7 @@ class CurvePanel(Panel):
             layout.operator("curvetools2.create_auto_loft")
             lofters = [o for o in scene.objects if "autoloft" in o.keys()]
             for o in lofters:
-                layout.label(o.name)
+                layout.label(text=o.name)
             # layout.prop(o, '["autoloft"]', toggle=True)
             layout.prop(wm, "auto_loft", toggle=True)
 
@@ -300,6 +301,8 @@ class CurvePanel(Panel):
             row = col.row(align=True)
             row.operator("object.sep_outline", text="Separate Outline")
             row = col.row(align=True)
+            row.operator("curve.remove_doubles", text="Remove Doubles")
+            row = col.row(align=True)
             vertex = []
             selected = []
             n = 0
@@ -311,16 +314,16 @@ class CurvePanel(Panel):
                             n += 1
                             if j.select_control_point:
                                 selected.append(n)
-                                vertex.append(obj.matrix_world * j.co)
+                                vertex.append(obj.matrix_world @ j.co)
 
                 if len(vertex) > 0 and n > 2:
                     row = col.row(align=True)
                     row.operator("curve.bezier_points_fillet", text='Fillet')
-                """
+
                 if len(vertex) == 2 and abs(selected[0] - selected[1]) == 1:
                     row = col.row(align=True)
                     row.operator("curve.bezier_spline_divide", text='Divide')
-                """
+
             row = col.row(align=True)
             row.operator("curvetools2.operatorbirail", text="Birail")
         # Utils Curve options
@@ -363,7 +366,7 @@ class CurvePanel(Panel):
 
 # Define Panel classes for updating
 panels = (
-        CurvePanel,
+        VIEW3D_PT_CurvePanel,
         )
 
 
@@ -403,6 +406,28 @@ class CurveAddonPreferences(AddonPreferences):
         col.label(text="Tab Category:")
         col.prop(self, "category", text="")
 
+# REGISTER
+classes = (
+    Properties.CurveTools2SelectedObject,
+    CurveAddonPreferences,
+    CurveTools2Settings,
+    Operators.OperatorSelectionInfo,
+    Operators.OperatorCurveInfo,
+    Operators.OperatorCurveLength,
+    Operators.OperatorSplinesInfo,
+    Operators.OperatorSegmentsInfo,
+    Operators.OperatorOriginToSpline0Start,
+    Operators.OperatorIntersectCurves,
+    Operators.OperatorLoftCurves,
+    Operators.OperatorSweepCurves,
+    Operators.OperatorBirail,
+    Operators.OperatorSplinesSetResolution,
+    Operators.OperatorSplinesRemoveZeroSegment,
+    Operators.OperatorSplinesRemoveShort,
+    Operators.OperatorSplinesJoinNeighbouring,
+    VIEW3D_PT_CurvePanel,
+    SeparateOutline
+    )
 
 def register():
     bpy.types.Scene.UTSingleDrop = BoolProperty(
@@ -430,38 +455,18 @@ def register():
             default=False,
             description="Curves Utils"
             )
+    
+    for cls in classes:
+        bpy.utils.register_class(cls)
+    
     auto_loft.register()
+    
     curve_outline.register()
-    bpy.utils.register_class(Properties.CurveTools2SelectedObject)
-    bpy.utils.register_class(CurveAddonPreferences)
-    bpy.utils.register_class(CurveTools2Settings)
+    
+    curve_remove_doubles.register()
+    
     bpy.types.Scene.curvetools = bpy.props.PointerProperty(type=CurveTools2Settings)
 
-    bpy.utils.register_class(Operators.OperatorSelectionInfo)
-    # bpy.utils.register_class(Properties.CurveTools2SelectedObjectHeader)
-
-    bpy.utils.register_class(Operators.OperatorCurveInfo)
-    bpy.utils.register_class(Operators.OperatorCurveLength)
-    bpy.utils.register_class(Operators.OperatorSplinesInfo)
-    bpy.utils.register_class(Operators.OperatorSegmentsInfo)
-    bpy.utils.register_class(Operators.OperatorOriginToSpline0Start)
-
-    bpy.utils.register_class(Operators.OperatorIntersectCurves)
-    bpy.utils.register_class(Operators.OperatorLoftCurves)
-    bpy.utils.register_class(Operators.OperatorSweepCurves)
-
-    bpy.utils.register_class(Operators.OperatorBirail)
-
-    bpy.utils.register_class(Operators.OperatorSplinesSetResolution)
-    bpy.utils.register_class(Operators.OperatorSplinesRemoveZeroSegment)
-    bpy.utils.register_class(Operators.OperatorSplinesRemoveShort)
-    bpy.utils.register_class(Operators.OperatorSplinesJoinNeighbouring)
-
-    # bpy.app.handlers.scene_update_pre.append(SceneUpdatePreHandler)
-
-    bpy.utils.register_class(CurvePanel)
-    bpy.utils.register_class(SeparateOutline)
-
 
 def unregister():
     del bpy.types.Scene.UTSingleDrop
@@ -470,35 +475,16 @@ def unregister():
     del bpy.types.Scene.UTTripleDrop
     del bpy.types.Scene.UTUtilsDrop
 
+    # bpy.app.handlers.scene_update_pre.remove(SceneUpdatePreHandler)
+    
     auto_loft.unregister()
+    
     curve_outline.unregister()
-    bpy.utils.unregister_class(CurveAddonPreferences)
-    # bpy.app.handlers.scene_update_pre.remove(SceneUpdatePreHandler)
-    bpy.utils.unregister_class(CurvePanel)
-    bpy.utils.unregister_class(SeparateOutline)
-    bpy.utils.unregister_class(Operators.OperatorSplinesJoinNeighbouring)
-    bpy.utils.unregister_class(Operators.OperatorSplinesRemoveShort)
-    bpy.utils.unregister_class(Operators.OperatorSplinesRemoveZeroSegment)
-    bpy.utils.unregister_class(Operators.OperatorSplinesSetResolution)
-
-    bpy.utils.unregister_class(Operators.OperatorBirail)
-
-    bpy.utils.unregister_class(Operators.OperatorSweepCurves)
-    bpy.utils.unregister_class(Operators.OperatorLoftCurves)
-    bpy.utils.unregister_class(Operators.OperatorIntersectCurves)
-
-    bpy.utils.unregister_class(Operators.OperatorOriginToSpline0Start)
-    bpy.utils.unregister_class(Operators.OperatorSegmentsInfo)
-    bpy.utils.unregister_class(Operators.OperatorSplinesInfo)
-    bpy.utils.unregister_class(Operators.OperatorCurveLength)
-    bpy.utils.unregister_class(Operators.OperatorCurveInfo)
-
-    # bpy.utils.unregister_class(Operators.CurveTools2SelectedObjectHeader)
-    bpy.utils.unregister_class(Operators.OperatorSelectionInfo)
-
-    bpy.utils.unregister_class(CurveTools2Settings)
-
-    bpy.utils.unregister_class(Properties.CurveTools2SelectedObject)
+    
+    curve_remove_doubles.unregister()
+    
+    for cls in classes:
+        bpy.utils.unregister_class(cls)
 
 
 if __name__ == "__main__":
index dbf223b..6847e3c 100644 (file)
@@ -85,7 +85,7 @@ class CurveOutline(bpy.types.Operator):
     bl_idname = "object._curve_outline"
     bl_label = "Create Outline"
     bl_options = {'REGISTER', 'UNDO'}
-    outline: bpy.props.FloatProperty(name="Amount", default=0.1, min=-10, max=10)
+    outline: bpy.props.FloatProperty(name="Amount", default=0.1)
 
     @classmethod
     def poll(cls, context):
diff --git a/curve_tools/curve_remove_doubles.py b/curve_tools/curve_remove_doubles.py
new file mode 100644 (file)
index 0000000..ca26895
--- /dev/null
@@ -0,0 +1,110 @@
+import bpy, mathutils
+
+
+bl_info = {
+    'name': 'Curve Remove Doubles',
+    'author': 'Michael Soluyanov',
+    'version': (1, 1),
+    'blender': (2, 80, 0),
+    'location': 'View3D > Context menu (W/RMB) > Remove Doubles',
+    'description': 'Adds comand "Remove Doubles" for curves',
+    'category': 'Object'
+}
+
+def main(context, distance = 0.01):
+    
+    obj = context.active_object
+    dellist = []
+    
+    if bpy.ops.object.mode_set.poll():
+        bpy.ops.object.mode_set(mode='EDIT')
+    
+    for spline in obj.data.splines: 
+        if len(spline.bezier_points) > 1:
+            for i in range(0, len(spline.bezier_points)): 
+                
+                if i == 0:
+                    ii = len(spline.bezier_points) - 1
+                else:        
+                    ii = i - 1
+                    
+                dot = spline.bezier_points[i];
+                dot1 = spline.bezier_points[ii];   
+                    
+                while dot1 in dellist and i != ii:
+                    ii -= 1
+                    if ii < 0: 
+                        ii = len(spline.bezier_points)-1
+                    dot1 = spline.bezier_points[ii]
+                    
+                if dot.select_control_point and dot1.select_control_point and (i!=0 or spline.use_cyclic_u):   
+                    
+                    if (dot.co-dot1.co).length < distance:
+                        # remove points and recreate hangles
+                        dot1.handle_right_type = "FREE"
+                        dot1.handle_right = dot.handle_right
+                        dot1.co = (dot.co + dot1.co) / 2
+                        dellist.append(dot)
+                        
+                    else:
+                        # Handles that are on main point position converts to vector,
+                        # if next handle are also vector
+                        if dot.handle_left_type == 'VECTOR' and (dot1.handle_right - dot1.co).length < distance:
+                            dot1.handle_right_type = "VECTOR"
+                        if dot1.handle_right_type == 'VECTOR' and (dot.handle_left - dot.co).length < distance:
+                            dot.handle_left_type = "VECTOR"  
+                      
+                            
+    
+    bpy.ops.curve.select_all(action = 'DESELECT')
+
+    for dot in dellist:
+        dot.select_control_point = True
+        
+    count = len(dellist)
+    
+    bpy.ops.curve.delete(type = 'VERT')
+    
+    bpy.ops.curve.select_all(action = 'SELECT')
+    
+    return count
+    
+
+
+class CurveRemvDbs(bpy.types.Operator):
+    """Merge consecutive points that are near to each other"""
+    bl_idname = 'curve.remove_doubles'
+    bl_label = 'Remove Doubles'
+    bl_options = {'REGISTER', 'UNDO'}
+
+    distance: bpy.props.FloatProperty(name = 'Distance', default = 0.01)
+
+    @classmethod
+    def poll(cls, context):
+        obj = context.active_object
+        return (obj and obj.type == 'CURVE')
+
+    def execute(self, context):
+        removed=main(context, self.distance)
+        self.report({'INFO'}, "Removed %d bezier points" % removed)
+        return {'FINISHED'}
+
+
+
+
+def menu_func(self, context):
+    self.layout.operator(CurveRemvDbs.bl_idname, text='Remove Doubles')
+
+def register():
+    bpy.utils.register_class(CurveRemvDbs)
+    bpy.types.VIEW3D_MT_edit_curve_context_menu.append(menu_func)
+
+def unregister():
+    bpy.utils.unregister_class(CurveRemvDbs)
+    bpy.types.VIEW3D_MT_edit_curve_context_menu.remove(menu_func)
+
+if __name__ == "__main__":
+    register()
+
+
+