topologicpy 0.7.0__py3-none-any.whl → 0.7.3__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/Edge.py CHANGED
@@ -597,9 +597,10 @@ class Edge():
597
597
 
598
598
 
599
599
  @staticmethod
600
- def IsCollinear(edgeA, edgeB, mantissa: int = 6, angTolerance: float = 0.1, tolerance: float = 0.0001) -> bool:
600
+ def IsCollinear(edgeA, edgeB, mantissa: int = 6, tolerance: float = 0.0001) -> bool:
601
601
  """
602
602
  Return True if the two input edges are collinear. Returns False otherwise.
603
+ This code is based on a contribution by https://github.com/gaoxipeng
603
604
 
604
605
  Parameters
605
606
  ----------
@@ -609,8 +610,6 @@ class Edge():
609
610
  The second input edge.
610
611
  mantissa : int , optional
611
612
  The desired length of the mantissa. The default is 6.
612
- angTolerance : float , optional
613
- The angular tolerance used for the test. The default is 0.1.
614
613
  tolerance : float , optional
615
614
  The desired tolerance. The default is 0.0001.
616
615
 
@@ -622,25 +621,62 @@ class Edge():
622
621
  """
623
622
  from topologicpy.Vertex import Vertex
624
623
  from topologicpy.Topology import Topology
624
+ import numpy as np
625
625
 
626
626
  if not Topology.IsInstance(edgeA, "Edge"):
627
- print("Edge.IsCollinear - Error: The input edgeA parameter is not a valid topologic edge. Returning None.")
627
+ print("Edge.IsCollinear - Error: The input parameter edgeA is not a valid edge. Returning None")
628
628
  return None
629
629
  if not Topology.IsInstance(edgeB, "Edge"):
630
- print("Edge.IsCollinear - Error: The input edgeB parameter is not a valid topologic edge. Returning None.")
630
+ print("Edge.IsCollinear - Error: The input parameter edgeB is not a valid edge. Returning None")
631
631
  return None
632
- ang = Edge.Angle(edgeA, edgeB, mantissa=mantissa, bracket=True)
633
- svA = Edge.StartVertex(edgeA)
634
- evA = Edge.EndVertex(edgeA)
635
- svB = Edge.StartVertex(edgeB)
636
- evB = Edge.EndVertex(edgeB)
637
- d1 = Vertex.Distance(svA, svB)
638
- d2 = Vertex.Distance(svA, evB)
639
- d3 = Vertex.Distance(evA, svB)
640
- d4 = Vertex.Distance(evA, evB)
641
- if (d1 < tolerance or d2 < tolerance or d3 < tolerance or d4 < tolerance) and (abs(ang) < angTolerance or (abs(180 - ang) < angTolerance)):
642
- return True
643
- return False
632
+ if Edge.Length(edgeA) < tolerance:
633
+ print("Edge.IsCollinear - Error: The length of edgeA is less than the tolerance. Returning None")
634
+ return None
635
+ if Edge.Length(edgeB) < tolerance:
636
+ print("Edge.IsCollinear - Error: The length of edgeB is less than the tolerance. Returning None")
637
+ return None
638
+
639
+ # Get start and end points of the first edge
640
+ start_a = Edge.StartVertex(edgeA)
641
+ end_a = Edge.EndVertex(edgeA)
642
+ start_a_coords = np.array([Vertex.X(start_a), Vertex.Y(start_a), Vertex.Z(start_a)])
643
+ end_a_coords = np.array(
644
+ [Vertex.X(end_a, mantissa=mantissa), Vertex.Y(end_a, mantissa=mantissa), Vertex.Z(end_a, mantissa=mantissa)])
645
+
646
+ # Calculate the direction vector of the first edge
647
+ direction_a = end_a_coords - start_a_coords
648
+
649
+ # Normalize the direction vector
650
+ norm_a = np.linalg.norm(direction_a)
651
+ if norm_a == 0:
652
+ print("Edge.IsCollinear - Error: Division by zero. Returning None.")
653
+ return None
654
+ direction_a /= norm_a
655
+
656
+ # Function to calculate perpendicular distance from a point to the line defined by a point and direction vector
657
+ def distance_from_line(point, line_point, line_dir):
658
+ point = np.array([Vertex.X(point, mantissa=mantissa), Vertex.Y(point, mantissa=mantissa),
659
+ Vertex.Z(point, mantissa=mantissa)])
660
+ line_point = np.array(line_point)
661
+ diff = point - line_point
662
+ cross_product = np.cross(diff, line_dir)
663
+ line_dir_norm = np.linalg.norm(line_dir)
664
+ if line_dir_norm == 0:
665
+ print("Edge.IsCollinear - Error: Division by zero. Returning None.")
666
+ return None
667
+ distance = np.linalg.norm(cross_product) / np.linalg.norm(line_dir)
668
+ return distance
669
+
670
+ # Get start and end points of the second edge
671
+ start_b = Edge.StartVertex(edgeB)
672
+ end_b = Edge.EndVertex(edgeB)
673
+
674
+ # Calculate distances for start and end vertices of the second edge to the line defined by the first edge
675
+ distance_start = distance_from_line(start_b, start_a_coords, direction_a)
676
+ distance_end = distance_from_line(end_b, start_a_coords, direction_a)
677
+
678
+ # Check if both distances are within tolerance
679
+ return bool(distance_start < tolerance) and bool(distance_end < tolerance)
644
680
 
645
681
  @staticmethod
646
682
  def IsParallel(edgeA, edgeB, mantissa: int = 6, angTolerance: float = 0.1) -> bool:
topologicpy/Face.py CHANGED
@@ -927,7 +927,19 @@ class Face():
927
927
  The external boundary of the input face.
928
928
 
929
929
  """
930
- return face.ExternalBoundary()
930
+ from topologicpy.Vector import Vector
931
+ from topologicpy.Wire import Wire
932
+ from topologicpy.Topology import Topology
933
+
934
+ eb = face.ExternalBoundary()
935
+ f_dir = Face.Normal(face)
936
+ faceVertices = Topology.Vertices(eb)
937
+ temp_face = Face.ByWire(eb)
938
+ temp_dir = Face.Normal(temp_face)
939
+ if Vector.IsAntiParallel(f_dir, temp_dir):
940
+ faceVertices.reverse()
941
+ eb = Wire.ByVertices(faceVertices)
942
+ return eb
931
943
 
932
944
  @staticmethod
933
945
  def FacingToward(face, direction: list = [0,0,-1], asVertex: bool = False, tolerance: float = 0.0001) -> bool:
@@ -2313,7 +2325,7 @@ class Face():
2313
2325
  The external boundary of the input face.
2314
2326
 
2315
2327
  """
2316
- return face.ExternalBoundary()
2328
+ return Face.ExternalBoundary(face)
2317
2329
 
2318
2330
  @staticmethod
2319
2331
  def Wires(face) -> list:
topologicpy/Topology.py CHANGED
@@ -3199,6 +3199,146 @@ class Topology():
3199
3199
  return True
3200
3200
  return False
3201
3201
 
3202
+
3203
+ def ExportToDXF(topologies, path, overwrite=False):
3204
+ """
3205
+ Exports the input topology to a DXF file. See https://en.wikipedia.org/wiki/AutoCAD_DXF.
3206
+ THe DXF version is 'R2010'
3207
+ This is experimental and only geometry is exported.
3208
+
3209
+ Parameters
3210
+ ----------
3211
+ topologies : list or topologic_core.Topology
3212
+ The input list of topologies. This can also be a single topologic_core.Topology.
3213
+ path : str
3214
+ The input file path.
3215
+ overwrite : bool , optional
3216
+ If set to True the ouptut file will overwrite any pre-existing file. Otherwise, it won't. The default is False.
3217
+
3218
+ Returns
3219
+ -------
3220
+ bool
3221
+ True if the export operation is successful. False otherwise.
3222
+
3223
+ """
3224
+ import os
3225
+ import warnings
3226
+
3227
+ try:
3228
+ import ezdxf
3229
+ except:
3230
+ print("Topology.ExportToDXF - Information: Installing required ezdxf library.")
3231
+ try:
3232
+ os.system("pip install ezdxf")
3233
+ except:
3234
+ os.system("pip install ezdxf --user")
3235
+ try:
3236
+ import ezdxf
3237
+ print("Topology.ExportToDXF - Information: ezdxf library installed successfully.")
3238
+ except:
3239
+ warnings.warn("Topology.ExportToDXF - Error: Could not import ezdxf library. Please install it manually. Returning None.")
3240
+ return None
3241
+
3242
+ from topologicpy.Vertex import Vertex
3243
+ from topologicpy.Edge import Edge
3244
+ from topologicpy.Cluster import Cluster
3245
+ from topologicpy.Topology import Topology
3246
+
3247
+ from os.path import exists
3248
+ if not isinstance(topologies, list):
3249
+ topologies = [topologies]
3250
+ topologies = [topology for topology in topologies if Topology.IsInstance(topology, "Topology")]
3251
+ if len(topologies) < 1:
3252
+ print("Topology.ExportToDXF - Error: The inupt list parameter topologies does not contain any valid topologies. Returning None.")
3253
+ # Make sure the file extension is .brep
3254
+ ext = path[len(path)-4:len(path)]
3255
+ if ext.lower() != ".dxf":
3256
+ path = path+".dxf"
3257
+ if not overwrite and exists(path):
3258
+ print("Topology.ExportToDXF - Error: a file already exists at the specified path and overwrite is set to False. Returning None.")
3259
+ return None
3260
+
3261
+ def add_vertices(vertices, msp):
3262
+ for v in vertices:
3263
+ if Topology.IsInstance(v, "Vertex"):
3264
+ msp.add_point((Vertex.X(v), Vertex.Y(v), Vertex.Z(v)))
3265
+ def add_edges(edges, msp):
3266
+ for e in edges:
3267
+ if Topology.IsInstance(e, "Edge"):
3268
+ sv = Edge.StartVertex(e)
3269
+ ev = Edge.EndVertex(e)
3270
+ start = (Vertex.X(sv), Vertex.Y(sv), Vertex.Z(sv))
3271
+ end = (Vertex.X(ev), Vertex.Y(ev), Vertex.Z(ev))
3272
+ msp.add_line(start, end)
3273
+ def add_wires(wires, msp):
3274
+ for i, w in enumerate(wires):
3275
+ if Topology.IsInstance(w, "Wire"):
3276
+ block_name = "Wire_"+str(i+1).zfill(3)
3277
+ block = doc.blocks.new(name=block_name)
3278
+ # Add edges to the block
3279
+ edges = Topology.Edges(w)
3280
+ for edge in edges:
3281
+ sv = Edge.StartVertex(edge)
3282
+ ev = Edge.EndVertex(edge)
3283
+ start = (Vertex.X(sv), Vertex.Y(sv), Vertex.Z(sv))
3284
+ end = (Vertex.X(ev), Vertex.Y(ev), Vertex.Z(ev))
3285
+ block.add_line(start, end)
3286
+ # Insert the block into the model space
3287
+ msp.add_blockref(block_name, insert=(0, 0, 0))
3288
+ def add_meshes(meshes, msp):
3289
+ for m in meshes:
3290
+ data = Topology.Geometry(m)
3291
+ vertices = data['vertices']
3292
+ faces = data['faces']
3293
+ mesh = msp.add_mesh()
3294
+ mesh.dxf.subdivision_levels = 0
3295
+ with mesh.edit_data() as mesh_data:
3296
+ mesh_data.vertices = vertices
3297
+ mesh_data.faces = faces
3298
+ # Create a new DXF document
3299
+ doc = ezdxf.new(dxfversion='R2010')
3300
+ msp = doc.modelspace()
3301
+ i = 1
3302
+ for topology in topologies:
3303
+ if Topology.IsInstance(topology, "Vertex"):
3304
+ add_vertices([topology], msp)
3305
+ elif Topology.IsInstance(topology, "Edge"):
3306
+ add_edges([topology], msp)
3307
+ elif Topology.IsInstance(topology, "Wire"):
3308
+ add_wires([topology], msp)
3309
+ elif Topology.IsInstance(topology, "Face"):
3310
+ add_meshes([topology], msp)
3311
+ elif Topology.IsInstance(topology, "Shell"):
3312
+ add_meshes([topology], msp)
3313
+ elif Topology.IsInstance(topology, "Cell"):
3314
+ add_meshes([topology], msp)
3315
+ elif Topology.IsInstance(topology, "CellComplex"):
3316
+ add_meshes([topology], msp)
3317
+ elif Topology.IsInstance(topology, "Cluster"):
3318
+ cellComplexes = Topology.CellComplexes(topology)
3319
+ add_meshes(cellComplexes, msp)
3320
+ cells = Cluster.FreeCells(topology)
3321
+ add_meshes(cells, msp)
3322
+ shells = Cluster.FreeShells(topology)
3323
+ add_meshes(shells, msp)
3324
+ faces = Cluster.FreeFaces(topology)
3325
+ add_meshes(faces, msp)
3326
+ wires = Cluster.FreeWires(topology)
3327
+ add_wires(wires, msp)
3328
+ edges = Cluster.FreeEdges(topology)
3329
+ add_edges(edges, msp)
3330
+ vertices = Cluster.FreeVertices(topology)
3331
+ add_vertices(vertices, msp)
3332
+
3333
+ # Save the DXF document
3334
+ status = False
3335
+ try:
3336
+ doc.saveas(path)
3337
+ status = True
3338
+ except:
3339
+ status = False
3340
+ return status
3341
+
3202
3342
  '''
3203
3343
  @staticmethod
3204
3344
  def ExportToIPFS(topology, url, port, user, password):
@@ -3979,6 +4119,8 @@ class Topology():
3979
4119
 
3980
4120
  """
3981
4121
  from topologicpy.Vertex import Vertex
4122
+ from topologicpy.Face import Face
4123
+ from topologicpy.Vector import Vector
3982
4124
 
3983
4125
  def getSubTopologies(topology, subTopologyClass):
3984
4126
  topologies = []
@@ -4053,6 +4195,7 @@ class Topology():
4053
4195
  elif (Topology.Type(topology) > Topology.TypeID("Face")):
4054
4196
  _ = topology.Faces(None, topFaces)
4055
4197
  for aFace in topFaces:
4198
+ f_dir = Face.Normal(aFace)
4056
4199
  ib = []
4057
4200
  _ = aFace.InternalBoundaries(ib)
4058
4201
  if(len(ib) > 0):
@@ -4060,6 +4203,10 @@ class Topology():
4060
4203
  for aTriFace in triFaces:
4061
4204
  wire = aTriFace.ExternalBoundary()
4062
4205
  faceVertices = getSubTopologies(wire, topologic.Vertex)
4206
+ temp_face = Face.ByWire(wire)
4207
+ temp_dir = Face.Normal(temp_face)
4208
+ if Vector.IsAntiParallel(f_dir, temp_dir):
4209
+ faceVertices.reverse()
4063
4210
  f = []
4064
4211
  for aVertex in faceVertices:
4065
4212
  try:
@@ -4073,6 +4220,10 @@ class Topology():
4073
4220
  wire = aFace.ExternalBoundary()
4074
4221
  #wire = topologic.WireUtility.RemoveCollinearEdges(wire, 0.1) #This is an angle Tolerance
4075
4222
  faceVertices = getSubTopologies(wire, topologic.Vertex)
4223
+ temp_face = Face.ByWire(wire)
4224
+ temp_dir = Face.Normal(temp_face)
4225
+ if Vector.IsAntiParallel(f_dir, temp_dir):
4226
+ faceVertices.reverse()
4076
4227
  f = []
4077
4228
  for aVertex in faceVertices:
4078
4229
  try:
topologicpy/Vector.py CHANGED
@@ -526,7 +526,6 @@ class Vector(list):
526
526
  if np.isclose(dot_product, 1.0) or np.isclose(dot_product, -1.0):
527
527
  return True
528
528
  else:
529
- # Compute bisecting vector
530
529
  return False
531
530
 
532
531
  @staticmethod
topologicpy/Wire.py CHANGED
@@ -485,7 +485,7 @@ class Wire(Topology):
485
485
  if len(st) > 1:
486
486
  e1 = st[0]
487
487
  e2 = st[1]
488
- if not Edge.IsCollinear(e1, e2, angTolerance=angTolerance, tolerance=tolerance):
488
+ if not Edge.IsCollinear(e1, e2, tolerance=tolerance):
489
489
  e1 = Edge.Reverse(e1, tolerance=tolerance)
490
490
  bisector = Edge.ByVertices([vertices[i], newVertices[i]], tolerance=tolerance)
491
491
  nv = Edge.VertexByDistance(bisector, distance=finalMiterThreshold, origin=Edge.StartVertex(bisector), tolerance=0.0001)
@@ -510,7 +510,7 @@ class Wire(Topology):
510
510
  for v in vertices:
511
511
  edges = Topology.SuperTopologies(v, c, topologyType="edge")
512
512
  if len(edges) == 2:
513
- if not Edge.IsCollinear(edges[0], edges[1], angTolerance=angTolerance, tolerance=tolerance):
513
+ if not Edge.IsCollinear(edges[0], edges[1], tolerance=tolerance):
514
514
  adjacentVertices = Topology.AdjacentTopologies(v, c)
515
515
  total = 0
516
516
  for adjV in adjacentVertices:
@@ -2210,7 +2210,7 @@ class Wire(Topology):
2210
2210
  edges = []
2211
2211
  _ = aVertex.Edges(wire, edges)
2212
2212
  if len(edges) > 1:
2213
- if not Edge.IsCollinear(edges[0], edges[1], angTolerance=angTolerance, tolerance=tolerance):
2213
+ if not Edge.IsCollinear(edges[0], edges[1], tolerance=tolerance):
2214
2214
  wire_verts.append(aVertex)
2215
2215
  else:
2216
2216
  wire_verts.append(aVertex)
topologicpy/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = '0.7.0'
1
+ __version__ = '0.7.3'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: topologicpy
3
- Version: 0.7.0
3
+ Version: 0.7.3
4
4
  Summary: An Advanced Spatial Modelling and Analysis Software Library for Architecture, Engineering, and Construction.
5
5
  Author-email: Wassim Jabi <wassim.jabi@gmail.com>
6
6
  License: GNU AFFERO GENERAL PUBLIC LICENSE
@@ -6,9 +6,9 @@ topologicpy/Color.py,sha256=UlmRcCSOhqcM_OyMWz4t3Kr75KcgXDhz3uctAJ2n7Ic,18031
6
6
  topologicpy/Context.py,sha256=ppApYKngZZCQBFWaxIMi2z2dokY23c935IDCBosxDAE,3055
7
7
  topologicpy/DGL.py,sha256=RpkLnAzjg6arY7cEMs2pDFYzRdkerVg1Wbm9hcE3QaM,138991
8
8
  topologicpy/Dictionary.py,sha256=pMbfE2RYGCNpVr2x58qiHRc-aBWnp1jLlyzwS9nz6-w,25891
9
- topologicpy/Edge.py,sha256=1Kg1-xkz1_9SVF9M2UuSf04uMuearTfhXMhM9XD3poA,49477
9
+ topologicpy/Edge.py,sha256=jbJHyPHlLF94RkUKL479B4dPC202K0Xd7bQsPcFwoHc,51296
10
10
  topologicpy/EnergyModel.py,sha256=UBLim01lZLikVQmJAHEeja-KvF4tgzTxsSxwNDaezz4,52500
11
- topologicpy/Face.py,sha256=AgCtQ96QRb5Vej1fpiYp4S_GSDtxu50SKV0XgTVgnqQ,96750
11
+ topologicpy/Face.py,sha256=BOU6hN-4uCaXW_lbvuOlntrz_Q0jEiL5tIHAFuqWw_U,97195
12
12
  topologicpy/Graph.py,sha256=GsWySXL-cTd7bl-QWpl3Aw9Hr0KyACzIa4iRenTB63s,368030
13
13
  topologicpy/Grid.py,sha256=XM0iQtQbMQoYHf7S0ppSe-dxy93Y9VpI_vUkElWqnYA,17050
14
14
  topologicpy/Helper.py,sha256=07V9IFu5ilMpvAdZVhIbdBOjBJSRTtJ0BfR1IoRaRXU,17743
@@ -20,14 +20,14 @@ topologicpy/Polyskel.py,sha256=MYHKFOQBlUNqoUhAdOcKRIHpSk0dWWVrZgXK34NkvFM,15936
20
20
  topologicpy/Shell.py,sha256=6hidTQ6MW5q_es-WbTeI_yt7Sd7BMxWU_qfoherVZhE,74343
21
21
  topologicpy/Speckle.py,sha256=rUS6PCaxIjEF5_fUruxvMH47FMKg-ohcoU0qAUb-yNM,14267
22
22
  topologicpy/Sun.py,sha256=3tYb8kssU882lE1gEWg2mxDvCCY_LAVElkyUT6wa-ZU,36935
23
- topologicpy/Topology.py,sha256=t8Zc25xRNsJWu2e4n_hQ08WjRFBVRm1ujuSueBYauiU,292372
24
- topologicpy/Vector.py,sha256=4mvvValXDCXFzLupjC_lpsr7LxKVXLmVZUe6H3Fo7f8,29604
23
+ topologicpy/Topology.py,sha256=limcBROvZgD5xanXLi57WgOvR9e93-MkYZcFtFgctu0,298938
24
+ topologicpy/Vector.py,sha256=FHbrCb9GVLOUV_kqcplh4D88CVxlID6qX_wEQOw4rD0,29565
25
25
  topologicpy/Vertex.py,sha256=YgbbCcqABvb97z2-yEytpp5T3yoZPlQplR_vMQkQ9OA,65180
26
- topologicpy/Wire.py,sha256=Q8jpH797oSkjso-ipAxsCs6ta2BxTHrYuBbSLewmV0w,138505
26
+ topologicpy/Wire.py,sha256=MUEboxo11kMgwnZySSkwiyzBG2wv0wPiinf2cW4UVv8,138424
27
27
  topologicpy/__init__.py,sha256=D7ky87CAQMiS2KE6YLvcTLkTgA2PY7rASe6Z23pjp9k,872
28
- topologicpy/version.py,sha256=09hol5ovL6ArILJIJZ-MiscnOjKa6RjaETmtdgJpW2c,22
29
- topologicpy-0.7.0.dist-info/LICENSE,sha256=TfPDBt3ar0uv_f9cqCDMZ5rIzW3CY8anRRd4PkL6ejs,34522
30
- topologicpy-0.7.0.dist-info/METADATA,sha256=zHBR-EYUrl66gK-J54RV5KYBg_h2bxXX5tfQMXJ4El0,46950
31
- topologicpy-0.7.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
32
- topologicpy-0.7.0.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
33
- topologicpy-0.7.0.dist-info/RECORD,,
28
+ topologicpy/version.py,sha256=i5zhgfscuWC8vabp6pP1S6z_O5355x2aIv0so00_cmo,22
29
+ topologicpy-0.7.3.dist-info/LICENSE,sha256=TfPDBt3ar0uv_f9cqCDMZ5rIzW3CY8anRRd4PkL6ejs,34522
30
+ topologicpy-0.7.3.dist-info/METADATA,sha256=TdJMT-64j4LX5i_DSX8qg-5jNgUSETUla-Mi9AMjkic,46950
31
+ topologicpy-0.7.3.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
32
+ topologicpy-0.7.3.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
33
+ topologicpy-0.7.3.dist-info/RECORD,,