topologicpy 0.8.33__py3-none-any.whl → 0.8.36__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/Plotly.py CHANGED
@@ -300,6 +300,8 @@ class Plotly:
300
300
  edgeColorKey: str = None,
301
301
  edgeWidth: float = 1,
302
302
  edgeWidthKey: str = None,
303
+ edgeDash: bool = False,
304
+ edgeDashKey: str = None,
303
305
  edgeLabelKey: str = None,
304
306
  edgeGroupKey: str = None,
305
307
  edgeGroups: list = [],
@@ -378,6 +380,10 @@ class Plotly:
378
380
  The dictionary key under which to find the edge width. The default is None.
379
381
  edgeLabelKey : str , optional
380
382
  The dictionary key to use to display the edge label. The default is None.
383
+ edgeDash : bool , optional
384
+ If set to True, the edges are drawn as dashed lines. The default is False.
385
+ edgeDashKey : str , optional
386
+ The key under which to find the boolean flag to draw edges as dashed lines. The default is None.
381
387
  edgeGroupKey : str , optional
382
388
  The dictionary key to use to display the edge group. The default is None.
383
389
  edgeGroups : list , optional
@@ -391,7 +397,7 @@ class Plotly:
391
397
  colorScale : str , optional
392
398
  The desired type of plotly color scales to use (e.g. "Viridis", "Plasma"). The default is "Viridis". For a full list of names, see https://plotly.com/python/builtin-colorscales/.
393
399
  silent : bool , optional
394
- If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
400
+ If set to True, error and warning messages are suppressed. The default is False.
395
401
 
396
402
  Returns
397
403
  -------
@@ -473,7 +479,7 @@ class Plotly:
473
479
  geo = Topology.Geometry(e_cluster, mantissa=mantissa)
474
480
  vertices = geo['vertices']
475
481
  edges = geo['edges']
476
- data.extend(Plotly.edgeData(vertices, edges, dictionaries=e_dictionaries, color=edgeColor, colorKey=edgeColorKey, width=edgeWidth, widthKey=edgeWidthKey, labelKey=edgeLabelKey, showEdgeLabel=showEdgeLabel, groupKey=edgeGroupKey, minGroup=edgeMinGroup, maxGroup=edgeMaxGroup, groups=edgeGroups, legendLabel=edgeLegendLabel, legendGroup=edgeLegendGroup, legendRank=edgeLegendRank, showLegend=showEdgeLegend, colorScale=colorScale))
482
+ data.extend(Plotly.edgeData(vertices, edges, dictionaries=e_dictionaries, color=edgeColor, colorKey=edgeColorKey, width=edgeWidth, widthKey=edgeWidthKey, dash=edgeDash, dashKey=edgeDashKey, labelKey=edgeLabelKey, showEdgeLabel=showEdgeLabel, groupKey=edgeGroupKey, minGroup=edgeMinGroup, maxGroup=edgeMaxGroup, groups=edgeGroups, legendLabel=edgeLegendLabel, legendGroup=edgeLegendGroup, legendRank=edgeLegendRank, showLegend=showEdgeLegend, colorScale=colorScale))
477
483
  return data
478
484
 
479
485
  @staticmethod
@@ -632,7 +638,7 @@ class Plotly:
632
638
  return return_value
633
639
 
634
640
  @staticmethod
635
- def edgeData(vertices, edges, dictionaries=None, color="black", colorKey=None, width=1, widthKey=None, labelKey=None, showEdgeLabel = False, groupKey=None, minGroup=None, maxGroup=None, groups=[], legendLabel="Topology Edges", legendGroup=2, legendRank=2, showLegend=True, colorScale="Viridis"):
641
+ def edgeData(vertices, edges, dictionaries=None, color="black", colorKey=None, width=1, widthKey=None, dash=False, dashKey=None, labelKey=None, showEdgeLabel = False, groupKey=None, minGroup=None, maxGroup=None, groups=[], legendLabel="Topology Edges", legendGroup=2, legendRank=2, showLegend=True, colorScale="Viridis"):
636
642
 
637
643
  from topologicpy.Color import Color
638
644
  from topologicpy.Dictionary import Dictionary
@@ -670,8 +676,8 @@ class Plotly:
670
676
  maxGroup = 1
671
677
 
672
678
 
673
- if colorKey or widthKey or labelKey or groupKey:
674
- keys = [x for x in [colorKey, widthKey, labelKey, groupKey] if not x == None]
679
+ if colorKey or widthKey or labelKey or groupKey or dashKey:
680
+ keys = [x for x in [colorKey, widthKey, labelKey, groupKey, dashKey] if not x == None]
675
681
  temp_dict = Helper.ClusterByKeys(edges, dictionaries, keys, silent=False)
676
682
  dict_clusters = temp_dict["dictionaries"]
677
683
  elements_clusters = temp_dict['elements']
@@ -684,6 +690,8 @@ class Plotly:
684
690
  if not colorKey == None:
685
691
  d_color = Dictionary.ValueAtKey(d, key=colorKey) or color
686
692
  d_color = Color.AnyToHex(d_color)
693
+ if not dashKey == None:
694
+ d_dash = Dictionary.ValueAtKey(d, key=dashKey) or dash
687
695
  if not labelKey == None:
688
696
  labels.append(str(Dictionary.ValueAtKey(d, labelKey, "")))
689
697
  if not widthKey == None:
@@ -719,6 +727,10 @@ class Plotly:
719
727
  marker_width = width[0]*0.25
720
728
  else:
721
729
  marker_width = width*0.25
730
+ if dash:
731
+ dot = "dot"
732
+ else:
733
+ dot = "solid"
722
734
  trace = go.Scatter3d(x=x,
723
735
  y=y,
724
736
  z=z,
@@ -726,7 +738,7 @@ class Plotly:
726
738
  showlegend=showLegend,
727
739
  marker=dict(symbol="circle", size=marker_width, color=color),
728
740
  mode=mode,
729
- line=dict(color=d_color, width=width),
741
+ line=dict(color=d_color, width=width, dash=dot),
730
742
  legendgroup=legendGroup,
731
743
  legendrank=legendRank,
732
744
  text=labels,
@@ -747,6 +759,10 @@ class Plotly:
747
759
  mode = "lines+text"
748
760
  else:
749
761
  mode = "lines"
762
+ if dash:
763
+ dot = "dot"
764
+ else:
765
+ dot = "solid"
750
766
  trace = go.Scatter3d(x=x,
751
767
  y=y,
752
768
  z=z,
@@ -754,7 +770,7 @@ class Plotly:
754
770
  showlegend=showLegend,
755
771
  marker_size=0,
756
772
  mode=mode,
757
- line=dict(color=color, width=width),
773
+ line=dict(color=color, width=width, dash=dot),
758
774
  legendgroup=legendGroup,
759
775
  legendrank=legendRank,
760
776
  text=label,
@@ -788,6 +804,8 @@ class Plotly:
788
804
  edgeWidthKey=None,
789
805
  edgeColor="black",
790
806
  edgeColorKey=None,
807
+ edgeDash=False,
808
+ edgeDashKey=None,
791
809
  edgeLabelKey=None,
792
810
  showEdgeLabel=False,
793
811
  edgeGroupKey=None,
@@ -883,6 +901,10 @@ class Plotly:
883
901
  The default is "black".
884
902
  edgeColorKey : str , optional
885
903
  The dictionary key under which to find the edge color.The default is None.
904
+ edgeDash : bool , optional
905
+ If set to True, the edges are drawn as dashed lines. The default is False.
906
+ edgeDashKey : str , optional
907
+ The key under which to find the boolean flag to draw edges as dashed lines. The default is None.
886
908
  edgeLabelKey : str , optional
887
909
  The dictionary key to use to display the edge label. The default is None.
888
910
  edgeGroupKey : str , optional
@@ -150,7 +150,7 @@ class ShapeGrammar:
150
150
  matrix : list
151
151
  The 4x4 transformation matrix that tranforms the output topology to the input topology. If set to None, no transformation is applied. The default is None.
152
152
  silent : bool, optional
153
- If True, suppresses error/warning messages. Default is False.
153
+ If set to True, error and warning messages are suppressed. Default is False.
154
154
 
155
155
  Returns
156
156
  -------
@@ -205,7 +205,7 @@ class ShapeGrammar:
205
205
  keys : list , optional
206
206
  The list of dictionary keys to semantically match the rules. The default is None which means dictionaries are not considered.
207
207
  silent : bool, optional
208
- If True, suppresses error/warning messages. Default is False.
208
+ If set to True, error and warning messages are suppressed. Default is False.
209
209
 
210
210
  Returns
211
211
  -------
@@ -258,7 +258,7 @@ class ShapeGrammar:
258
258
  tolerance : float, optional
259
259
  The desired Tolerance. Not used here but included for API compatibility. Default is 0.0001.
260
260
  silent : bool, optional
261
- If True, suppresses error/warning messages. Default is False.
261
+ If set to True, error and warning messages are suppressed. Default is False.
262
262
 
263
263
  Returns
264
264
  -------
@@ -395,7 +395,7 @@ class ShapeGrammar:
395
395
  output : topologic_core.Topology
396
396
  The output topology
397
397
  silent : bool, optional
398
- If True, suppresses error/warning messages. Default is False.
398
+ If set to True, error and warning messages are suppressed. Default is False.
399
399
 
400
400
  Returns
401
401
  -------
@@ -473,7 +473,7 @@ class ShapeGrammar:
473
473
  rule : dict
474
474
  The input rule
475
475
  silent : bool, optional
476
- If True, suppresses error/warning messages. Default is False.
476
+ If set to True, error and warning messages are suppressed. Default is False.
477
477
 
478
478
  Returns
479
479
  -------
@@ -500,7 +500,7 @@ class ShapeGrammar:
500
500
  output : topologic_core.Topology
501
501
  The output topology
502
502
  silent : bool, optional
503
- If True, suppresses error/warning messages. Default is False.
503
+ If set to True, error and warning messages are suppressed. Default is False.
504
504
 
505
505
  Returns
506
506
  -------
@@ -534,7 +534,7 @@ class ShapeGrammar:
534
534
  rule : dict
535
535
  The input rule
536
536
  silent : bool, optional
537
- If True, suppresses error/warning messages. Default is False.
537
+ If set to True, error and warning messages are suppressed. Default is False.
538
538
 
539
539
  Returns
540
540
  -------
topologicpy/Shell.py CHANGED
@@ -280,7 +280,7 @@ class Shell():
280
280
  tolerance : float , optional
281
281
  The desired tolerance. The default is 0.0001.
282
282
  silent : bool , optional
283
- If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
283
+ If set to True, error and warning messages are suppressed. The default is False.
284
284
 
285
285
  Returns
286
286
  -------
@@ -392,7 +392,7 @@ class Shell():
392
392
  tolerance : float , optional
393
393
  The desired tolerance. The default is 0.0001.
394
394
  silent : bool , optional
395
- If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
395
+ If set to True, error and warning messages are suppressed. The default is False.
396
396
 
397
397
  Returns
398
398
  -------
@@ -528,7 +528,7 @@ class Shell():
528
528
  tolerance : float , optional
529
529
  The desired tolerance. The default is 0.0001.
530
530
  silent : bool , optional
531
- If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
531
+ If set to True, error and warning messages are suppressed. The default is False.
532
532
 
533
533
  Returns
534
534
  -------
@@ -739,42 +739,6 @@ class Shell():
739
739
  _ = shell.Faces(None, faces)
740
740
  return faces
741
741
 
742
- @staticmethod
743
- def IsOnBoundary(shell, vertex, tolerance: float = 0.0001) -> bool:
744
- """
745
- Returns True if the input vertex is on the boundary of the input shell. Returns False otherwise. On the boundary is defined as being on the boundary of one of the shell's external or internal boundaries
746
-
747
- Parameters
748
- ----------
749
- shell : topologic_core.Shell
750
- The input shell.
751
- vertex : topologic_core.Vertex
752
- The input vertex.
753
- tolerance : float , optional
754
- The desired tolerance. The default is 0.0001.
755
-
756
- Returns
757
- -------
758
- bool
759
- Returns True if the input vertex is inside the input shell. Returns False otherwise.
760
-
761
- """
762
- from topologicpy.Vertex import Vertex
763
- from topologicpy.Topology import Topology
764
-
765
- if not Topology.IsInstance(shell, "Shell"):
766
- return None
767
- if not Topology.IsInstance(vertex, "Vertex"):
768
- return None
769
- boundary = Shell.ExternalBoundary(shell, tolerance=tolerance)
770
- if Vertex.IsInternal(vertex, boundary, tolerance=tolerance):
771
- return True
772
- internal_boundaries = Shell.InternalBoundaries(shell, tolerance=tolerance)
773
- for ib in internal_boundaries:
774
- if Vertex.IsInternal(vertex, ib, tolerance=tolerance):
775
- return True
776
- return False
777
-
778
742
  @staticmethod
779
743
  def HyperbolicParaboloidRectangularDomain(origin= None,
780
744
  llVertex= None,
@@ -1097,6 +1061,41 @@ class Shell():
1097
1061
  """
1098
1062
  return shell.IsClosed()
1099
1063
 
1064
+ @staticmethod
1065
+ def IsOnBoundary(shell, vertex, tolerance: float = 0.0001) -> bool:
1066
+ """
1067
+ Returns True if the input vertex is on the boundary of the input shell. Returns False otherwise. On the boundary is defined as being on the boundary of one of the shell's external or internal boundaries
1068
+
1069
+ Parameters
1070
+ ----------
1071
+ shell : topologic_core.Shell
1072
+ The input shell.
1073
+ vertex : topologic_core.Vertex
1074
+ The input vertex.
1075
+ tolerance : float , optional
1076
+ The desired tolerance. The default is 0.0001.
1077
+
1078
+ Returns
1079
+ -------
1080
+ bool
1081
+ Returns True if the input vertex is inside the input shell. Returns False otherwise.
1082
+
1083
+ """
1084
+ from topologicpy.Vertex import Vertex
1085
+ from topologicpy.Topology import Topology
1086
+
1087
+ if not Topology.IsInstance(shell, "Shell"):
1088
+ return None
1089
+ if not Topology.IsInstance(vertex, "Vertex"):
1090
+ return None
1091
+ boundary = Shell.ExternalBoundary(shell, tolerance=tolerance)
1092
+ if Vertex.IsInternal(vertex, boundary, tolerance=tolerance):
1093
+ return True
1094
+ internal_boundaries = Shell.InternalBoundaries(shell, tolerance=tolerance)
1095
+ for ib in internal_boundaries:
1096
+ if Vertex.IsInternal(vertex, ib, tolerance=tolerance):
1097
+ return True
1098
+ return False
1100
1099
 
1101
1100
  @staticmethod
1102
1101
  def Paraboloid(origin= None, focalLength=0.125, width: float = 1, length: float = 1, uSides: int = 16, vSides: int = 16,
@@ -1127,7 +1126,7 @@ class Shell():
1127
1126
  tolerance : float , optional
1128
1127
  The desired tolerance. The default is 0.0001.
1129
1128
  silent : bool , optional
1130
- If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
1129
+ If set to True, error and warning messages are suppressed. The default is False.
1131
1130
 
1132
1131
  Returns
1133
1132
  -------
@@ -1644,62 +1643,6 @@ class Shell():
1644
1643
  else:
1645
1644
  return None
1646
1645
 
1647
- def Skeleton(face, tolerance: float = 0.001):
1648
- """
1649
- Creates a shell through a straight skeleton. This method is contributed by 高熙鹏 xipeng gao <gaoxipeng1998@gmail.com>
1650
- This algorithm depends on the polyskel code which is included in the library. Polyskel code is found at: https://github.com/Botffy/polyskel
1651
-
1652
- Parameters
1653
- ----------
1654
- face : topologic_core.Face
1655
- The input face.
1656
- tolerance : float , optional
1657
- The desired tolerance. The default is 0.001. (This is set to a larger number as it was found to work better)
1658
-
1659
- Returns
1660
- -------
1661
- topologic_core.Shell
1662
- The created straight skeleton.
1663
-
1664
- """
1665
- from topologicpy.Wire import Wire
1666
- from topologicpy.Face import Face
1667
- from topologicpy.Topology import Topology
1668
- import topologic_core as topologic
1669
- import math
1670
-
1671
- if not Topology.IsInstance(face, "Face"):
1672
- return None
1673
- roof = Wire.Skeleton(face, tolerance=tolerance)
1674
- if not (Topology.IsInstance(roof, "Wire") or Topology.IsInstance(roof, "Cluster")):
1675
- print("Shell.Skeleton - Error: Could not create base skeleton wire. Returning None.")
1676
- return None
1677
- br = Wire.BoundingRectangle(roof) #This works even if it is a Cluster not a Wire
1678
- if not Topology.IsInstance(br, "Wire"):
1679
- print("Shell.Skeleton - Error: Could not create a bounding rectangle wire. Returning None.")
1680
- return None
1681
- br = Topology.Scale(br, Topology.Centroid(br), 1.5, 1.5, 1)
1682
- bf = Face.ByWire(br, tolerance=tolerance)
1683
- if not Topology.IsInstance(bf, "Face"):
1684
- print("Shell.Skeleton - Error: Could not create a bounding rectangle face. Returning None.")
1685
- return None
1686
- large_shell = Topology.Boolean(bf, roof, operation="slice", tolerance=tolerance)
1687
- if not large_shell:
1688
- return None
1689
- faces = Topology.Faces(large_shell)
1690
- if not faces:
1691
- return None
1692
- final_faces = []
1693
- for f in faces:
1694
- internalBoundaries = Face.InternalBoundaries(f)
1695
- if len(internalBoundaries) == 0:
1696
- final_faces.append(f)
1697
- shell = Shell.ByFaces(final_faces, tolerance=tolerance)
1698
- if not Topology.IsInstance(shell, "Shell"):
1699
- print("Shell.Skeleton - Error: Could not create shell. Returning None.")
1700
- return None
1701
- return shell
1702
-
1703
1646
  @staticmethod
1704
1647
  def Simplify(shell, simplifyBoundary: bool = True, mantissa: int = 6, tolerance: float = 0.0001):
1705
1648
  """
@@ -1846,6 +1789,63 @@ class Shell():
1846
1789
  final_result = Shell.ByFaces(final_faces, tolerance=tolerance)
1847
1790
  return final_result
1848
1791
 
1792
+ @staticmethod
1793
+ def Skeleton(face, tolerance: float = 0.001):
1794
+ """
1795
+ Creates a shell through a straight skeleton. This method is contributed by 高熙鹏 xipeng gao <gaoxipeng1998@gmail.com>
1796
+ This algorithm depends on the polyskel code which is included in the library. Polyskel code is found at: https://github.com/Botffy/polyskel
1797
+
1798
+ Parameters
1799
+ ----------
1800
+ face : topologic_core.Face
1801
+ The input face.
1802
+ tolerance : float , optional
1803
+ The desired tolerance. The default is 0.001. (This is set to a larger number as it was found to work better)
1804
+
1805
+ Returns
1806
+ -------
1807
+ topologic_core.Shell
1808
+ The created straight skeleton.
1809
+
1810
+ """
1811
+ from topologicpy.Wire import Wire
1812
+ from topologicpy.Face import Face
1813
+ from topologicpy.Topology import Topology
1814
+ import topologic_core as topologic
1815
+ import math
1816
+
1817
+ if not Topology.IsInstance(face, "Face"):
1818
+ return None
1819
+ roof = Wire.Skeleton(face, tolerance=tolerance)
1820
+ if not (Topology.IsInstance(roof, "Wire") or Topology.IsInstance(roof, "Cluster")):
1821
+ print("Shell.Skeleton - Error: Could not create base skeleton wire. Returning None.")
1822
+ return None
1823
+ br = Wire.BoundingRectangle(roof) #This works even if it is a Cluster not a Wire
1824
+ if not Topology.IsInstance(br, "Wire"):
1825
+ print("Shell.Skeleton - Error: Could not create a bounding rectangle wire. Returning None.")
1826
+ return None
1827
+ br = Topology.Scale(br, Topology.Centroid(br), 1.5, 1.5, 1)
1828
+ bf = Face.ByWire(br, tolerance=tolerance)
1829
+ if not Topology.IsInstance(bf, "Face"):
1830
+ print("Shell.Skeleton - Error: Could not create a bounding rectangle face. Returning None.")
1831
+ return None
1832
+ large_shell = Topology.Boolean(bf, roof, operation="slice", tolerance=tolerance)
1833
+ if not large_shell:
1834
+ return None
1835
+ faces = Topology.Faces(large_shell)
1836
+ if not faces:
1837
+ return None
1838
+ final_faces = []
1839
+ for f in faces:
1840
+ internalBoundaries = Face.InternalBoundaries(f)
1841
+ if len(internalBoundaries) == 0:
1842
+ final_faces.append(f)
1843
+ shell = Shell.ByFaces(final_faces, tolerance=tolerance)
1844
+ if not Topology.IsInstance(shell, "Shell"):
1845
+ print("Shell.Skeleton - Error: Could not create shell. Returning None.")
1846
+ return None
1847
+ return shell
1848
+
1849
1849
  @staticmethod
1850
1850
  def Square(origin= None, size: float = 1.0,
1851
1851
  uSides: int = 2, vSides: int = 2, direction: list = [0, 0, 1],
@@ -1882,6 +1882,33 @@ class Shell():
1882
1882
  uSides=uSides, vSides=vSides, direction=direction,
1883
1883
  placement=placement, tolerance=tolerance)
1884
1884
 
1885
+ @staticmethod
1886
+ def _grow_connected_group(seed_idx, group_size, adjacency, visited_global):
1887
+ """
1888
+ Attempts to grow a group of the given size starting from seed_idx using adjacency.
1889
+ Returns a list of indices if successful, else None.
1890
+ """
1891
+ from collections import deque
1892
+ import random
1893
+
1894
+ group = [seed_idx]
1895
+ visited = set(group)
1896
+ queue = deque([seed_idx])
1897
+
1898
+ while queue and len(group) < group_size:
1899
+ current = queue.popleft()
1900
+ neighbors = adjacency.get(current, [])
1901
+ random.shuffle(neighbors)
1902
+ for neighbor in neighbors:
1903
+ if neighbor not in visited and neighbor not in visited_global:
1904
+ group.append(neighbor)
1905
+ visited.add(neighbor)
1906
+ queue.append(neighbor)
1907
+ if len(group) >= group_size:
1908
+ break
1909
+
1910
+ return group if len(group) == group_size else None
1911
+
1885
1912
  @staticmethod
1886
1913
  def Vertices(shell) -> list:
1887
1914
  """