topologicpy 0.8.10__py3-none-any.whl → 0.8.12__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
topologicpy/Matrix.py CHANGED
@@ -141,6 +141,192 @@ class Matrix:
141
141
  [0,0,1,translateZ],
142
142
  [0,0,0,1]]
143
143
 
144
+ @staticmethod
145
+ def ByVectors(vectorA: list, vectorB: list, orientationA: list = [1, 0, 0], orientationB: list = [1, 0, 0]):
146
+ """
147
+ Creates a rotation matrix that aligns vectorA with vectorB and adjusts orientationA to match orientationB.
148
+
149
+ Parameters
150
+ ----------
151
+ vectorA : list
152
+ The first input vector.
153
+ vectorB : list
154
+ The second input vector to align with.
155
+ orientationA : list
156
+ The orientation vector associated with vectorA.
157
+ orientationB : list
158
+ The orientation vector associated with vectorB.
159
+
160
+ Returns
161
+ -------
162
+ list
163
+ The 4x4 transformation matrix.
164
+ """
165
+ from topologicpy.Vector import Vector
166
+ import numpy as np
167
+
168
+ def to_numpy(vector):
169
+ """Converts a list or array-like to a numpy array."""
170
+ return np.array(vector, dtype=np.float64)
171
+
172
+ # Normalize input vectors and convert them to numpy arrays
173
+ vectorA = to_numpy(Vector.Normalize(vectorA))
174
+ vectorB = to_numpy(Vector.Normalize(vectorB))
175
+ orientationA = to_numpy(Vector.Normalize(orientationA))
176
+ orientationB = to_numpy(Vector.Normalize(orientationB))
177
+
178
+ # Step 1: Compute rotation matrix to align vectorA with vectorB
179
+ axis = np.cross(vectorA, vectorB)
180
+ angle = np.arccos(np.clip(np.dot(vectorA, vectorB), -1.0, 1.0))
181
+
182
+ if np.isclose(angle, 0): # Vectors are already aligned
183
+ rotation_matrix_normal = np.eye(3)
184
+ elif np.isclose(angle, np.pi): # Vectors are anti-parallel
185
+ # Choose a perpendicular axis for rotation
186
+ axis = to_numpy([1, 0, 0]) if not np.isclose(vectorA[0], 0) else to_numpy([0, 1, 0])
187
+ rotation_matrix_normal = (
188
+ np.eye(3)
189
+ - 2 * np.outer(vectorA, vectorA) # Reflect through the plane perpendicular to vectorA
190
+ )
191
+ else:
192
+ axis = axis / np.linalg.norm(axis)
193
+ K = np.array([
194
+ [0, -axis[2], axis[1]],
195
+ [axis[2], 0, -axis[0]],
196
+ [-axis[1], axis[0], 0]
197
+ ])
198
+ rotation_matrix_normal = (
199
+ np.eye(3) + np.sin(angle) * K + (1 - np.cos(angle)) * np.dot(K, K)
200
+ )
201
+
202
+ # Step 2: Rotate orientationA using the first rotation matrix
203
+ rotated_orientationA = np.dot(rotation_matrix_normal, orientationA)
204
+
205
+ # Step 3: Compute rotation to align rotated_orientationA with orientationB in the plane of vectorB
206
+ projected_orientationA = rotated_orientationA - np.dot(rotated_orientationA, vectorB) * vectorB
207
+ projected_orientationB = orientationB - np.dot(orientationB, vectorB) * vectorB
208
+
209
+ if np.linalg.norm(projected_orientationA) < 1e-6 or np.linalg.norm(projected_orientationB) < 1e-6:
210
+ # If either projected vector is near zero, skip secondary rotation
211
+ rotation_matrix_orientation = np.eye(3)
212
+ else:
213
+ projected_orientationA = projected_orientationA / np.linalg.norm(projected_orientationA)
214
+ projected_orientationB = projected_orientationB / np.linalg.norm(projected_orientationB)
215
+ axis = np.cross(projected_orientationA, projected_orientationB)
216
+ angle = np.arccos(np.clip(np.dot(projected_orientationA, projected_orientationB), -1.0, 1.0))
217
+ if np.isclose(angle, 0): # Already aligned
218
+ rotation_matrix_orientation = np.eye(3)
219
+ else:
220
+ axis = axis / np.linalg.norm(axis)
221
+ K = np.array([
222
+ [0, -axis[2], axis[1]],
223
+ [axis[2], 0, -axis[0]],
224
+ [-axis[1], axis[0], 0]
225
+ ])
226
+ rotation_matrix_orientation = (
227
+ np.eye(3) + np.sin(angle) * K + (1 - np.cos(angle)) * np.dot(K, K)
228
+ )
229
+
230
+ # Step 4: Combine the two rotation matrices
231
+ rotation_matrix = np.dot(rotation_matrix_orientation, rotation_matrix_normal)
232
+
233
+ # Convert to 4x4 transformation matrix
234
+ transform_matrix = np.eye(4)
235
+ transform_matrix[:3, :3] = rotation_matrix
236
+
237
+ return transform_matrix.tolist()
238
+
239
+ def ByVectors_old(vectorA: list, vectorB: list, orientationA: list = [1,0,0], orientationB: list = [1,0,0]):
240
+ """
241
+ Creates a rotation matrix that aligns vectorA with vectorB and adjusts orientationA to match orientationB.
242
+
243
+ Parameters
244
+ ----------
245
+ vectorA : list
246
+ The first input vector.
247
+ vectorB : list
248
+ The second input vector to align with.
249
+ orientationA : list
250
+ The orientation vector associated with vectorA.
251
+ orientationB : list
252
+ The orientation vector associated with vectorB.
253
+
254
+ Returns
255
+ -------
256
+ list
257
+ The 4x4 transformation matrix.
258
+ """
259
+ from topologicpy.Vector import Vector
260
+ import numpy as np
261
+
262
+ # Normalize input vectors
263
+ vectorA = Vector.Normalize(vectorA)
264
+ vectorB = Vector.Normalize(vectorB)
265
+ orientationA = Vector.Normalize(orientationA)
266
+ orientationB = Vector.Normalize(orientationB)
267
+
268
+ # Step 1: Compute rotation matrix to align vectorA with vectorB
269
+ axis = np.cross(vectorA, vectorB)
270
+ angle = np.arccos(np.clip(np.dot(vectorA, vectorB), -1.0, 1.0))
271
+
272
+ if np.isclose(angle, 0): # Vectors are already aligned
273
+ rotation_matrix_normal = np.eye(3)
274
+ elif np.isclose(angle, np.pi): # Vectors are anti-parallel
275
+ # Choose a perpendicular axis for rotation
276
+ axis = np.array([1, 0, 0]) if not np.isclose(vectorA[0], 0) else np.array([0, 1, 0])
277
+ rotation_matrix_normal = (
278
+ np.eye(3)
279
+ - 2 * np.outer(vectorA, vectorA) # Reflect through the plane perpendicular to vectorA
280
+ )
281
+ else:
282
+ axis = Vector.Normalize(axis)
283
+ K = np.array([
284
+ [0, -axis[2], axis[1]],
285
+ [axis[2], 0, -axis[0]],
286
+ [-axis[1], axis[0], 0]
287
+ ])
288
+ rotation_matrix_normal = (
289
+ np.eye(3) + np.sin(angle) * K + (1 - np.cos(angle)) * np.dot(K, K)
290
+ )
291
+
292
+ # Step 2: Rotate orientationA using the first rotation matrix
293
+ rotated_orientationA = np.dot(rotation_matrix_normal, orientationA)
294
+
295
+ # Step 3: Compute rotation to align rotated_orientationA with orientationB in the plane of vectorB
296
+ projected_orientationA = rotated_orientationA - np.dot(rotated_orientationA, vectorB) * vectorB
297
+ projected_orientationB = orientationB - np.dot(orientationB, vectorB) * vectorB
298
+
299
+ if np.linalg.norm(projected_orientationA) < 1e-6 or np.linalg.norm(projected_orientationB) < 1e-6:
300
+ # If either projected vector is near zero, skip secondary rotation
301
+ rotation_matrix_orientation = np.eye(3)
302
+ else:
303
+ projected_orientationA = Vector.Normalize(projected_orientationA)
304
+ projected_orientationB = Vector.Normalize(projected_orientationB)
305
+ axis = np.cross(projected_orientationA, projected_orientationB)
306
+ angle = np.arccos(np.clip(np.dot(projected_orientationA, projected_orientationB), -1.0, 1.0))
307
+ if np.isclose(angle, 0): # Already aligned
308
+ rotation_matrix_orientation = np.eye(3)
309
+ else:
310
+ axis = Vector.Normalize(axis)
311
+ K = np.array([
312
+ [0, -axis[2], axis[1]],
313
+ [axis[2, 0, -axis[0]]],
314
+ [-axis[1], axis[0], 0]
315
+ ])
316
+ rotation_matrix_orientation = (
317
+ np.eye(3) + np.sin(angle) * K + (1 - np.cos(angle)) * np.dot(K, K)
318
+ )
319
+
320
+ # Step 4: Combine the two rotation matrices
321
+ rotation_matrix = np.dot(rotation_matrix_orientation, rotation_matrix_normal)
322
+
323
+ # Convert to 4x4 transformation matrix
324
+ transform_matrix = np.eye(4)
325
+ transform_matrix[:3, :3] = rotation_matrix
326
+
327
+ return transform_matrix.tolist()
328
+
329
+
144
330
  @staticmethod
145
331
  def EigenvaluesAndVectors(matrix, mantissa: int = 6, silent: bool = False):
146
332
  import numpy as np
@@ -203,6 +389,25 @@ class Matrix:
203
389
  e_vectors.append([round(x, mantissa) for x in eigenvector])
204
390
  e_vectors = Helper.Sort(e_vectors, list(eigenvalues))
205
391
  return e_values, e_vectors
392
+
393
+ @staticmethod
394
+ def Identity():
395
+ """
396
+ Creates a 4x4 identity translation matrix.
397
+
398
+ Parameters
399
+ ----------
400
+
401
+ Returns
402
+ -------
403
+ list
404
+ The created 4X4 identity matrix.
405
+
406
+ """
407
+ return [[1,0,0,0],
408
+ [0,1,0,0],
409
+ [0,0,1,0],
410
+ [0,0,0,1]]
206
411
 
207
412
  @staticmethod
208
413
  def Invert(matA, silent: bool = False):
@@ -226,12 +431,13 @@ class Matrix:
226
431
 
227
432
  if not isinstance(matA, list):
228
433
  if not silent:
229
- print("Matrix.Invert - Error: The input matA parameter is not a valid 4X4 matrix. Returning None.")
434
+ print(matA, matA.__class__)
435
+ print("1. Matrix.Invert - Error: The input matA parameter is not a valid 4X4 matrix. Returning None.")
230
436
  return None
231
437
  np_matrix = np.array(matA)
232
438
  if np_matrix.shape != (4, 4):
233
439
  if not silent:
234
- print("Matrix.Invert - Error: The input matA parameter is not a valid 4X4 matrix. Returning None.")
440
+ print("2. Matrix.Invert - Error: The input matA parameter is not a valid 4X4 matrix. Returning None.")
235
441
  return None
236
442
 
237
443
  # Check if the matrix is invertible
@@ -264,9 +470,9 @@ class Matrix:
264
470
 
265
471
  """
266
472
  # Input validation
267
- if not (isinstance(matA, list) and all(isinstance(row, list) for row in matA) and
268
- isinstance(matB, list) and all(isinstance(row, list) for row in matB)):
269
- raise ValueError("Both inputs must be 2D lists representing matrices.")
473
+ # if not (isinstance(matA, list) and all(isinstance(row, list) for row in matA) and
474
+ # isinstance(matB, list) and all(isinstance(row, list) for row in matB)):
475
+ # raise ValueError("Both inputs must be 2D lists representing matrices.")
270
476
 
271
477
  # Check matrix dimension compatibility
272
478
  if len(matA[0]) != len(matB):
topologicpy/Plotly.py CHANGED
@@ -492,11 +492,10 @@ class Plotly:
492
492
  x = []
493
493
  y = []
494
494
  z = []
495
- sizes = []
496
- labels = []
497
- colors = []
498
- label = ""
499
- group = None
495
+ n = len(str(len(vertices)))
496
+ sizes = [size for i in range(len(vertices))]
497
+ labels = ["Vertex_"+str(i+1).zfill(n) for i in range(len(vertices))]
498
+ colors = [Color.AnyToHex(color) for i in range(len(vertices))]
500
499
  if colorKey or sizeKey or labelKey or groupKey:
501
500
  if groups:
502
501
  if len(groups) > 0:
@@ -516,9 +515,9 @@ class Plotly:
516
515
  x.append(v[0])
517
516
  y.append(v[1])
518
517
  z.append(v[2])
519
- colors.append(Color.AnyToHex(color))
520
- labels.append("Vertex_"+str(m+1).zfill(n))
521
- sizes.append(max(size, 1.1))
518
+ #colors.append(Color.AnyToHex(color))
519
+ #labels.append("Vertex_"+str(m+1).zfill(n))
520
+ #sizes.append(max(size, 1.1))
522
521
  if len(dictionaries) > 0:
523
522
  d = dictionaries[m]
524
523
  if d:
@@ -677,7 +676,7 @@ class Plotly:
677
676
  z=z,
678
677
  name=legendLabel,
679
678
  showlegend=showLegend,
680
- marker=dict(symbol="circle", size=marker_width),
679
+ marker=dict(symbol="circle", size=marker_width, color=color),
681
680
  mode=mode,
682
681
  line=dict(color=d_color, width=width),
683
682
  legendgroup=legendGroup,