topologicpy 0.8.39__py3-none-any.whl → 0.8.40__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/Color.py CHANGED
@@ -55,7 +55,80 @@ class Color:
55
55
 
56
56
  return return_hex.upper()
57
57
 
58
-
58
+ @staticmethod
59
+ def AverageHex(*colors, silent: bool = False):
60
+ """
61
+ Averages the input list of hex colors.
62
+
63
+ Parameters
64
+ ----------
65
+ colors : *list or str
66
+ The input color parameter which can be any of RGB, CMYK, CSS Named Color, or Hex
67
+
68
+ Returns
69
+ -------
70
+ str
71
+ A hexadecimal color string in the format '#RRGGBB'.
72
+ """
73
+ from topologicpy.Helper import Helper
74
+ import inspect
75
+
76
+ def avg(hex1, hex2):
77
+ # Remove leading "#" if present
78
+ hex1 = hex1.lstrip('#')
79
+ hex2 = hex2.lstrip('#')
80
+
81
+ # Convert to RGB components
82
+ r1, g1, b1 = int(hex1[0:2], 16), int(hex1[2:4], 16), int(hex1[4:6], 16)
83
+ r2, g2, b2 = int(hex2[0:2], 16), int(hex2[2:4], 16), int(hex2[4:6], 16)
84
+
85
+ # Compute average for each channel
86
+ r_avg = (r1 + r2) // 2
87
+ g_avg = (g1 + g2) // 2
88
+ b_avg = (b1 + b2) // 2
89
+
90
+ # Return as hex string
91
+ return f"#{r_avg:02X}{g_avg:02X}{b_avg:02X}"
92
+
93
+ if len(colors) == 0:
94
+ if not silent:
95
+ print("Color.AverageColors - Error: The input colors parameter is an empty list. Returning None.")
96
+ curframe = inspect.currentframe()
97
+ calframe = inspect.getouterframes(curframe, 2)
98
+ print('caller name:', calframe[1][3])
99
+ return None
100
+ if len(colors) == 1:
101
+ colorList = colors[0]
102
+ if isinstance(colorList, list):
103
+ if len(colorList) == 0:
104
+ if not silent:
105
+ print("Color.AverageHex - Error: The input colors parameter is an empty list. Returning None.")
106
+ curframe = inspect.currentframe()
107
+ calframe = inspect.getouterframes(curframe, 2)
108
+ print('caller name:', calframe[1][3])
109
+ return None
110
+ else:
111
+ if not silent:
112
+ print("Color.AverageHex - Warning: The input colors parameter contains only one color. Returning the same topology.")
113
+ curframe = inspect.currentframe()
114
+ calframe = inspect.getouterframes(curframe, 2)
115
+ print('caller name:', calframe[1][3])
116
+ return colorList
117
+ else:
118
+ colorList = Helper.Flatten(list(colors))
119
+ colorList = [x for x in colorList if isinstance(x, str)]
120
+ if len(colorList) == 0:
121
+ if not silent:
122
+ print("Color.AverageHex - Error: The input parameters do not contain any valid colors. Returning None.")
123
+ curframe = inspect.currentframe()
124
+ calframe = inspect.getouterframes(curframe, 2)
125
+ print('caller name:', calframe[1][3])
126
+ return None
127
+ final_color = Color.AnyToHex(colorList[0])
128
+ for clr in colorList[1:]:
129
+ final_color = avg(final_color, Color.AnyToHex(clr))
130
+ return final_color
131
+
59
132
  @staticmethod
60
133
  def ByCSSNamedColor(color, alpha: float = None):
61
134
  """
topologicpy/Graph.py CHANGED
@@ -12914,38 +12914,49 @@ class Graph:
12914
12914
  return round(numerator / denominator, mantissa) if denominator != 0 else 0.0
12915
12915
 
12916
12916
  @staticmethod
12917
- def _vertex_is_same(v1, v2, key=None):
12917
+ def _vertex_is_same(v1, v2, keys=None, tolerance=0.0001):
12918
+ from topologicpy.Vertex import Vertex
12918
12919
  from topologicpy.Topology import Topology
12919
12920
  from topologicpy.Dictionary import Dictionary
12921
+
12922
+ if keys == None or keys == [] or keys == "":
12923
+ return Vertex.Distance(v1, v2) <= tolerance
12924
+
12925
+ if isinstance(keys, str):
12926
+ if "loc" in keys.lower() or "coord" in keys.lower() or "xyz" in keys.lower():
12927
+ return Vertex.Distance(v1, v2) <= tolerance
12928
+ if not isinstance(keys, list):
12929
+ keys = [keys]
12930
+
12920
12931
  d1 = Topology.Dictionary(v1)
12921
12932
  d2 = Topology.Dictionary(v2)
12922
- a = Dictionary.ValueAtKey(d1, key, "0")
12923
- b = Dictionary.ValueAtKey(d2, key, "1")
12933
+ a = [Dictionary.ValueAtKey(d1, k, "0") for k in keys]
12934
+ b = [Dictionary.ValueAtKey(d2, k, "1") for k in keys]
12924
12935
  return a == b
12925
12936
 
12926
12937
  @staticmethod
12927
- def _vertex_in_list(vertex, vertex_list, key=None):
12938
+ def _vertex_in_list(vertex, vertex_list, keys=None, tolerance=0.0001):
12928
12939
  for i, v1 in enumerate(vertex_list):
12929
- if Graph._vertex_is_same(vertex, v1, key=key):
12940
+ if Graph._vertex_is_same(vertex, v1, keys=keys, tolerance=tolerance):
12930
12941
  return i+1
12931
12942
  return False
12932
12943
 
12933
12944
  @staticmethod
12934
- def _edge_in_list(edge, edge_list, vertices_a, vertices_b, key=None):
12945
+ def _edge_in_list(edge, edge_list, vertices_a, vertices_b, keys=None, tolerance=0.0001):
12935
12946
  sv1 = vertices_a[edge[0]]
12936
12947
  ev1 = vertices_a[edge[1]]
12937
12948
  for i, e in enumerate(edge_list):
12938
12949
  sv2 = vertices_b[e[0]]
12939
12950
  ev2 = vertices_b[e[1]]
12940
- if (Graph._vertex_is_same(sv1, sv2, key=key) and Graph._vertex_is_same(ev1, ev2, key=key)) or \
12941
- (Graph._vertex_is_same(sv1, ev2, key=key) and Graph._vertex_is_same(ev1, sv2, key=key)):
12951
+ if (Graph._vertex_is_same(sv1, sv2, keys=keys, tolerance=tolerance) and Graph._vertex_is_same(ev1, ev2, keys=keys, tolerance=tolerance)) or \
12952
+ (Graph._vertex_is_same(sv1, ev2, keys=keys, tolerance=tolerance) and Graph._vertex_is_same(ev1, sv2, keys=keys, tolerance=tolerance)):
12942
12953
  return i+1
12943
12954
  return False
12944
12955
 
12945
12956
  @staticmethod
12946
- def Union(graphA, graphB, vertexKey: str, silent: bool = False):
12957
+ def Union(graphA, graphB, vertexKeys=None, useCentroid: bool = False, tolerance: float = 0.0001, silent: bool = False):
12947
12958
  """
12948
- Union the two input graphs based on an input vertex key. See https://en.wikipedia.org/wiki/Boolean_operation.
12959
+ Union the two input graphs based on the input vertex keys. See https://en.wikipedia.org/wiki/Boolean_operation.
12949
12960
 
12950
12961
  Parameters
12951
12962
  ----------
@@ -12953,11 +12964,18 @@ class Graph:
12953
12964
  The first input graph.
12954
12965
  graphB : topologic_core.Graph
12955
12966
  The second input graph.
12956
- vertexKey : str
12957
- The vertex dictionary key to use to determine if two vertices are the same.
12967
+ vertexKeys : list or str , optional
12968
+ The vertex dictionary key (str) or keys (list of str) to use to determine if two vertices are the same.
12969
+ If the vertexKeys are set to None or "loc" or "coord" or "xyz" (case insensitive), the distance between the
12970
+ vertices (within the tolerance) will be used to determine sameness. The default is None.
12971
+ useCentroid : bool , optional
12972
+ If set to True, the coordinates of identical vertices from each graph are averaged to located the new merged vertex of the resulting graph.
12973
+ Otherwise, the coordinates of the vertex of the first input graph are used. The default is False.
12974
+ tolerance : float , optional
12975
+ The desired tolerance. The default is 0.0001.
12958
12976
  silent : bool , optional
12959
12977
  If set to True, error and warning messages are suppressed. The default is False.
12960
-
12978
+
12961
12979
  Returns
12962
12980
  -------
12963
12981
  topologic_core.Graph
@@ -12968,6 +12986,7 @@ class Graph:
12968
12986
  from topologicpy.Edge import Edge
12969
12987
  from topologicpy.Topology import Topology
12970
12988
  from topologicpy.Dictionary import Dictionary
12989
+ from topologicpy.Cluster import Cluster
12971
12990
 
12972
12991
  if not Topology.IsInstance(graphA, "graph"):
12973
12992
  if not silent:
@@ -12977,10 +12996,6 @@ class Graph:
12977
12996
  if not silent:
12978
12997
  print("Graph.Union - Error: The graphB input parameter is not a valid graph. Returning None.")
12979
12998
  return None
12980
- if not isinstance(vertexKey, str):
12981
- if not silent:
12982
- print("Graph.Union - Error: The vertexKey input parameter is not a valid string. Returning None.")
12983
- return None
12984
12999
  vertices_a = Graph.Vertices(graphA)
12985
13000
  vertices_a_new = []
12986
13001
  for v in vertices_a:
@@ -13008,11 +13023,16 @@ class Graph:
13008
13023
 
13009
13024
  def _add_vertex(v):
13010
13025
  for i, uv in enumerate(union_vertices):
13011
- if Graph._vertex_is_same(v, uv, key=vertexKey):
13026
+ if Graph._vertex_is_same(v, uv, keys=vertexKeys):
13012
13027
  d_a = Topology.Dictionary(v)
13013
13028
  d_b = Topology.Dictionary(uv)
13014
13029
  d_c = Dictionary.ByMergedDictionaries(d_a, d_b)
13015
- uv = Topology.SetDictionary(uv, d_c)
13030
+ if useCentroid:
13031
+ c = Topology.Centroid(Cluster.ByTopologies([v, uv]))
13032
+ else:
13033
+ c = uv
13034
+ c = Topology.SetDictionary(c, d_c)
13035
+ union_vertices[i] = c
13016
13036
  return i
13017
13037
  union_vertices.append(v)
13018
13038
  return len(union_vertices) - 1
@@ -13029,8 +13049,8 @@ class Graph:
13029
13049
  for k, e in enumerate(union_edges):
13030
13050
  svi = Edge.StartVertex(e)
13031
13051
  evi = Edge.EndVertex(e)
13032
- if (Graph._vertex_is_same(svi, vi, key=vertexKey) and Graph._vertex_is_same(evi, vj, key=vertexKey)) or \
13033
- (Graph._vertex_is_same(svi, vj, key=vertexKey) and Graph._vertex_is_same(evi, vi, key=vertexKey)):
13052
+ if (Graph._vertex_is_same(svi, vi, keys=vertexKeys, tolerance=tolerance) and Graph._vertex_is_same(evi, vj, keys=vertexKeys, tolerance=tolerance)) or \
13053
+ (Graph._vertex_is_same(svi, vj, keys=vertexKeys, tolerance=tolerance) and Graph._vertex_is_same(evi, vi, keys=vertexKeys, tolerance=tolerance)):
13034
13054
  # Merge dictionaries
13035
13055
  d_a = Topology.Dictionary(e)
13036
13056
  d_c = Dictionary.ByMergedDictionaries([d_a, dictionary], silent=True)
@@ -13047,20 +13067,145 @@ class Graph:
13047
13067
  for idx, e in enumerate(edges_a):
13048
13068
  i = index_map_a[e[0]]
13049
13069
  j = index_map_a[e[1]]
13050
- _add_edge(i, j, Dictionary.ByPythonDictionary(edges_a_dicts[idx]))
13070
+ if not i == j:
13071
+ _add_edge(i, j, Dictionary.ByPythonDictionary(edges_a_dicts[idx]))
13051
13072
 
13052
13073
  # Add edges from B, merging duplicates
13053
13074
  for idx, e in enumerate(edges_b):
13054
13075
  i = index_map_b[e[0]]
13055
13076
  j = index_map_b[e[1]]
13056
- _add_edge(i, j, Dictionary.ByPythonDictionary(edges_b_dicts[idx]))
13077
+ if not i == j:
13078
+ _add_edge(i, j, Dictionary.ByPythonDictionary(edges_b_dicts[idx]))
13057
13079
 
13058
13080
  return Graph.ByVerticesEdges(union_vertices, union_edges)
13081
+
13082
+ @staticmethod
13083
+ def Impose(graphA, graphB, vertexKeys=None, useCentroid: bool = False, tolerance: float = 0.0001, silent: bool = False):
13084
+ """
13085
+ Imposes the second input graph on the first input graph based on the input vertex keys. See https://en.wikipedia.org/wiki/Boolean_operation.
13059
13086
 
13087
+ Parameters
13088
+ ----------
13089
+ graphA : topologic_core.Graph
13090
+ The first input graph.
13091
+ graphB : topologic_core.Graph
13092
+ The second input graph.
13093
+ vertexKeys : list or str , optional
13094
+ The vertex dictionary key (str) or keys (list of str) to use to determine if two vertices are the same.
13095
+ If the vertexKeys are set to None or "loc" or "coord" or "xyz" (case insensitive), the distance between the
13096
+ vertices (within the tolerance) will be used to determine sameness. The default is None.
13097
+ useCentroid : bool , optional
13098
+ If set to True, the coordinates of identical vertices from each graph are averaged to located the new merged vertex of the resulting graph.
13099
+ Otherwise, the coordinates of the vertex of the second input graph are used. The default is False.
13100
+ tolerance : float , optional
13101
+ The desired tolerance. The default is 0.0001.
13102
+ silent : bool , optional
13103
+ If set to True, error and warning messages are suppressed. The default is False.
13104
+
13105
+
13106
+ Returns
13107
+ -------
13108
+ topologic_core.Graph
13109
+ the resultant graph. Vertex and edge dictionaries are merged.
13110
+
13111
+ """
13112
+ from topologicpy.Vertex import Vertex
13113
+ from topologicpy.Edge import Edge
13114
+ from topologicpy.Topology import Topology
13115
+ from topologicpy.Dictionary import Dictionary
13116
+ from topologicpy.Cluster import Cluster
13117
+
13118
+ if not Topology.IsInstance(graphA, "graph"):
13119
+ if not silent:
13120
+ print("Graph.Impose - Error: The graphA input parameter is not a valid graph. Returning None.")
13121
+ return None
13122
+ if not Topology.IsInstance(graphB, "graph"):
13123
+ if not silent:
13124
+ print("Graph.Impose - Error: The graphB input parameter is not a valid graph. Returning None.")
13125
+ return None
13126
+ vertices_a = Graph.Vertices(graphA)
13127
+ vertices_a_new = []
13128
+ for v in vertices_a:
13129
+ d = Topology.Dictionary(v)
13130
+ v_new = Vertex.ByCoordinates(Vertex.Coordinates(v))
13131
+ v_new = Topology.SetDictionary(v_new, d)
13132
+ vertices_a_new.append(v_new)
13133
+ vertices_a = vertices_a_new
13134
+ vertices_b = Graph.Vertices(graphB)
13135
+ vertices_b_new = []
13136
+ for v in vertices_b:
13137
+ d = Topology.Dictionary(v)
13138
+ v_new = Vertex.ByCoordinates(Vertex.Coordinates(v))
13139
+ v_new = Topology.SetDictionary(v_new, d)
13140
+ vertices_b_new.append(v_new)
13141
+ vertices_b = vertices_b_new
13142
+ mesh_data_a = Graph.MeshData(graphA)
13143
+ mesh_data_b = Graph.MeshData(graphB)
13144
+ edges_a = mesh_data_a['edges']
13145
+ edges_b = mesh_data_b['edges']
13146
+ edges_a_dicts = mesh_data_a['edgeDictionaries']
13147
+ edges_b_dicts = mesh_data_b['edgeDictionaries']
13148
+
13149
+ union_vertices = []
13150
+
13151
+ def _add_vertex(v):
13152
+ for i, uv in enumerate(union_vertices):
13153
+ if Graph._vertex_is_same(v, uv, keys=vertexKeys):
13154
+ d_c = Topology.Dictionary(v) # Dictionaries of graphB are imposed.
13155
+ if useCentroid:
13156
+ c = Topology.Centroid(Cluster.ByTopologies([v, uv]))
13157
+ else:
13158
+ c = v
13159
+ c = Topology.SetDictionary(c, d_c)
13160
+ union_vertices[i] = c
13161
+ return i
13162
+ union_vertices.append(v)
13163
+ return len(union_vertices) - 1
13164
+
13165
+ # Map original vertices to indices in union list
13166
+ index_map_a = [_add_vertex(v) for v in vertices_a]
13167
+ index_map_b = [_add_vertex(v) for v in vertices_b]
13168
+
13169
+ union_edges = []
13170
+
13171
+ def _add_edge(i, j, dictionary):
13172
+ vi = union_vertices[i]
13173
+ vj = union_vertices[j]
13174
+ for k, e in enumerate(union_edges):
13175
+ svi = Edge.StartVertex(e)
13176
+ evi = Edge.EndVertex(e)
13177
+ if (Graph._vertex_is_same(svi, vi, keys=vertexKeys, tolerance=tolerance) and Graph._vertex_is_same(evi, vj, keys=vertexKeys, tolerance=tolerance)) or \
13178
+ (Graph._vertex_is_same(svi, vj, keys=vertexKeys, tolerance=tolerance) and Graph._vertex_is_same(evi, vi, keys=vertexKeys, tolerance=tolerance)):
13179
+ # Impose edge dictionary from graphB
13180
+ new_edge = Edge.ByVertices(vi, vj)
13181
+ new_edge = Topology.SetDictionary(new_edge, dictionary, silent=True)
13182
+ union_edges[k] = new_edge
13183
+ return
13184
+ # If not found, add new edge
13185
+ edge = Edge.ByVertices(vi, vj)
13186
+ edge = Topology.SetDictionary(edge, dictionary)
13187
+ union_edges.append(edge)
13188
+
13189
+ # Add edges from A
13190
+ for idx, e in enumerate(edges_a):
13191
+ i = index_map_a[e[0]]
13192
+ j = index_map_a[e[1]]
13193
+ if not i == j:
13194
+ _add_edge(i, j, Dictionary.ByPythonDictionary(edges_a_dicts[idx]))
13195
+
13196
+ # Add edges from B, merging duplicates
13197
+ for idx, e in enumerate(edges_b):
13198
+ i = index_map_b[e[0]]
13199
+ j = index_map_b[e[1]]
13200
+ if not i == j:
13201
+ _add_edge(i, j, Dictionary.ByPythonDictionary(edges_b_dicts[idx]))
13202
+
13203
+ return Graph.ByVerticesEdges(union_vertices, union_edges)
13204
+
13060
13205
  @staticmethod
13061
- def Intersect(graphA, graphB, vertexKey: str, silent: bool = False):
13206
+ def Imprint(graphA, graphB, vertexKeys, useCentroid: bool = False, tolerance: float = 0.0001, silent: bool = False):
13062
13207
  """
13063
- Intersect the two input graphs based on an input vertex key. See https://en.wikipedia.org/wiki/Boolean_operation.
13208
+ Imprints the second input graph on the first input graph based on the input vertex keys. See https://en.wikipedia.org/wiki/Boolean_operation.
13064
13209
 
13065
13210
  Parameters
13066
13211
  ----------
@@ -13068,8 +13213,15 @@ class Graph:
13068
13213
  The first input graph.
13069
13214
  graphB : topologic_core.Graph
13070
13215
  The second input graph.
13071
- vertexKey : str
13072
- The vertex dictionary key to use to determine if two vertices are the same.
13216
+ vertexKeys : list or str , optional
13217
+ The vertex dictionary key (str) or keys (list of str) to use to determine if two vertices are the same.
13218
+ If the vertexKeys are set to None or "loc" or "coord" or "xyz" (case insensitive), the distance between the
13219
+ vertices (within the tolerance) will be used to determine sameness. The default is None.
13220
+ useCentroid : bool , optional
13221
+ If set to True, the coordinates of identical vertices from each graph are averaged to located the new merged vertex of the resulting graph.
13222
+ Otherwise, the coordinates of the vertex of the first input graph are used. The default is False.
13223
+ tolerance : float , optional
13224
+ The desired tolerance. The default is 0.0001.
13073
13225
  silent : bool , optional
13074
13226
  If set to True, error and warning messages are suppressed. The default is False.
13075
13227
 
@@ -13081,20 +13233,126 @@ class Graph:
13081
13233
  """
13082
13234
  from topologicpy.Vertex import Vertex
13083
13235
  from topologicpy.Edge import Edge
13236
+ from topologicpy.Cluster import Cluster
13084
13237
  from topologicpy.Topology import Topology
13085
13238
  from topologicpy.Dictionary import Dictionary
13086
13239
 
13087
13240
  if not Topology.IsInstance(graphA, "graph"):
13088
13241
  if not silent:
13089
- print("Graph.Intersect - Error: The graphA input parameter is not a valid graph. Returning None.")
13242
+ print("Graph.Imprint - Error: The graphA input parameter is not a valid graph. Returning None.")
13090
13243
  return None
13091
13244
  if not Topology.IsInstance(graphB, "graph"):
13092
13245
  if not silent:
13093
- print("Graph.Intersect - Error: The graphB input parameter is not a valid graph. Returning None.")
13246
+ print("Graph.Imprint - Error: The graphB input parameter is not a valid graph. Returning None.")
13247
+ return None
13248
+
13249
+ vertices_a = Graph.Vertices(graphA)
13250
+ vertices_a_new = []
13251
+ for v in vertices_a:
13252
+ d = Topology.Dictionary(v)
13253
+ v_new = Vertex.ByCoordinates(Vertex.Coordinates(v))
13254
+ v_new = Topology.SetDictionary(v_new, d)
13255
+ vertices_a_new.append(v_new)
13256
+ vertices_a = vertices_a_new
13257
+ vertices_b = Graph.Vertices(graphB)
13258
+ vertices_b_new = []
13259
+ for v in vertices_b:
13260
+ d = Topology.Dictionary(v)
13261
+ v_new = Vertex.ByCoordinates(Vertex.Coordinates(v))
13262
+ v_new = Topology.SetDictionary(v_new, d)
13263
+ vertices_b_new.append(v_new)
13264
+ vertices_b = vertices_b_new
13265
+ mesh_data_a = Graph.MeshData(graphA)
13266
+ mesh_data_b = Graph.MeshData(graphB)
13267
+ topo_edges_a = Graph.Edges(graphA)
13268
+ edges_a = mesh_data_a['edges']
13269
+ edges_b = mesh_data_b['edges']
13270
+ edges_b_dicts = mesh_data_b['edgeDictionaries']
13271
+
13272
+ final_vertices = []
13273
+ vertex_map = {}
13274
+ for i, a in enumerate(vertices_a):
13275
+ j = Graph._vertex_in_list(a, vertices_b, keys=vertexKeys, tolerance=tolerance)
13276
+ if j:
13277
+ b = vertices_b[j-1]
13278
+ if useCentroid:
13279
+ c = Topology.Centroid(Cluster.ByTopologies([a, b]))
13280
+ else:
13281
+ c = a
13282
+ d_c = Topology.Dictionary(b)
13283
+ c = Topology.SetDictionary(c, d_c, silent=True)
13284
+ vertex_map[i] = c
13285
+ final_vertices.append(c)
13286
+ else:
13287
+ final_vertices.append(a)
13288
+ if len(final_vertices) < 1:
13289
+ if not silent:
13290
+ print("Graph.Imprint - Warning: graphA and graphB do not intersect. Returning None.")
13094
13291
  return None
13095
- if not isinstance(vertexKey, str):
13292
+
13293
+ final_edges = []
13294
+
13295
+ for i, e in enumerate(edges_a):
13296
+ j = Graph._edge_in_list(e, edges_b, vertices_a, vertices_b, keys=vertexKeys, tolerance=tolerance)
13297
+ if j:
13298
+ # Merge the dictionaries
13299
+ d_c = Dictionary.ByPythonDictionary(edges_b_dicts[j-1]) # We added 1 to j to avoid 0 which can be interpreted as False.
13300
+ # Create the edge
13301
+ #final_edge = Edge.ByVertices(vertices_a[e[0]], vertices_a[e[1]])
13302
+ sv = vertex_map[e[0]]
13303
+ ev = vertex_map[e[1]]
13304
+ final_edge = Edge.ByVertices(sv, ev)
13305
+ # Set the edge's dictionary
13306
+ final_edge = Topology.SetDictionary(final_edge, d_c, silent=True)
13307
+ # Add the final edge to the list
13308
+ final_edges.append(final_edge)
13309
+ else:
13310
+ final_edges.append(topo_edges_a[i])
13311
+
13312
+ return Graph.ByVerticesEdges(final_vertices, final_edges)
13313
+
13314
+ @staticmethod
13315
+ def Intersect(graphA, graphB, vertexKeys, vertexColorKey="color", useCentroid: bool = False, tolerance: float = 0.0001, silent: bool = False):
13316
+ """
13317
+ Intersect the two input graphs based on the input vertex keys. See https://en.wikipedia.org/wiki/Boolean_operation.
13318
+
13319
+ Parameters
13320
+ ----------
13321
+ graphA : topologic_core.Graph
13322
+ The first input graph.
13323
+ graphB : topologic_core.Graph
13324
+ The second input graph.
13325
+ vertexKeys : list or str , optional
13326
+ The vertex dictionary key (str) or keys (list of str) to use to determine if two vertices are the same.
13327
+ If the vertexKeys are set to None or "loc" or "coord" or "xyz" (case insensitive), the distance between the
13328
+ vertices (within the tolerance) will be used to determine sameness. The default is None.
13329
+ useCentroid : bool , optional
13330
+ If set to True, the coordinates of identical vertices from each graph are averaged to located the new merged vertex of the resulting graph.
13331
+ Otherwise, the coordinates of the vertex of the first input graph are used. The default is False.
13332
+ tolerance : float , optional
13333
+ The desired tolerance. The default is 0.0001.
13334
+ silent : bool , optional
13335
+ If set to True, error and warning messages are suppressed. The default is False.
13336
+
13337
+ Returns
13338
+ -------
13339
+ topologic_core.Graph
13340
+ the resultant graph. Vertex and edge dictionaries are merged.
13341
+
13342
+ """
13343
+ from topologicpy.Vertex import Vertex
13344
+ from topologicpy.Edge import Edge
13345
+ from topologicpy.Cluster import Cluster
13346
+ from topologicpy.Topology import Topology
13347
+ from topologicpy.Dictionary import Dictionary
13348
+
13349
+ if not Topology.IsInstance(graphA, "graph"):
13350
+ if not silent:
13351
+ print("Graph.Intersect - Error: The graphA input parameter is not a valid graph. Returning None.")
13352
+ return None
13353
+ if not Topology.IsInstance(graphB, "graph"):
13096
13354
  if not silent:
13097
- print("Graph.Intersect - Error: The vertexKey input parameter is not a valid string. Returning None.")
13355
+ print("Graph.Intersect - Error: The graphB input parameter is not a valid graph. Returning None.")
13098
13356
  return None
13099
13357
 
13100
13358
  vertices_a = Graph.Vertices(graphA)
@@ -13121,27 +13379,40 @@ class Graph:
13121
13379
  edges_b_dicts = mesh_data_b['edgeDictionaries']
13122
13380
 
13123
13381
  common_vertices = []
13124
- for i, v in enumerate(vertices_a):
13125
- j = Graph._vertex_in_list(v, vertices_b, key=vertexKey)
13382
+ vertex_map = {}
13383
+ for i, a in enumerate(vertices_a):
13384
+ j = Graph._vertex_in_list(a, vertices_b, keys=vertexKeys, tolerance=tolerance)
13126
13385
  if j:
13127
- d_a = Topology.Dictionary(v)
13128
- d_b = Topology.Dictionary(vertices_b[j-1])
13386
+ b = vertices_b[j-1]
13387
+ if useCentroid:
13388
+ c = Topology.Centroid(Cluster.ByTopologies([a, b]))
13389
+ else:
13390
+ c = a
13391
+ d_a = Topology.Dictionary(a)
13392
+ d_b = Topology.Dictionary(b)
13129
13393
  d_c = Dictionary.ByMergedDictionaries([d_a, d_b], silent=True)
13130
- v = Topology.SetDictionary(v, d_c, silent=True)
13131
- common_vertices.append(v)
13394
+ c = Topology.SetDictionary(c, d_c, silent=True)
13395
+ vertex_map[i] = c
13396
+ common_vertices.append(c)
13397
+ if len(common_vertices) < 1:
13398
+ if not silent:
13399
+ print("Graph.Intersect - Warning: graphA and graphB do not intersect. Returning None.")
13400
+ return None
13401
+
13132
13402
  common_edges = []
13133
13403
 
13134
13404
  for i, e in enumerate(edges_a):
13135
- j = Graph._edge_in_list(e, edges_b, vertices_a, vertices_b, key=vertexKey)
13405
+ j = Graph._edge_in_list(e, edges_b, vertices_a, vertices_b, keys=vertexKeys, tolerance=tolerance)
13136
13406
  if j:
13137
13407
  # Merge the dictionaries
13138
13408
  d_a = Dictionary.ByPythonDictionary(edges_a_dicts[i])
13139
13409
  d_b = Dictionary.ByPythonDictionary(edges_b_dicts[j-1]) # We added 1 to j to avoid 0 which can be interpreted as False.
13140
13410
  d_c = Dictionary.ByMergedDictionaries([d_a, d_b], silent=True)
13141
- print("Intersect - d_c:", d_c)
13142
- print(Dictionary.Keys(d_c), Dictionary.Values(d_c))
13143
13411
  # Create the edge
13144
- final_edge = Edge.ByVertices(vertices_a[e[0]], vertices_a[e[1]])
13412
+ #final_edge = Edge.ByVertices(vertices_a[e[0]], vertices_a[e[1]])
13413
+ sv = vertex_map[e[0]]
13414
+ ev = vertex_map[e[1]]
13415
+ final_edge = Edge.ByVertices(sv, ev)
13145
13416
  # Set the edge's dictionary
13146
13417
  final_edge = Topology.SetDictionary(final_edge, d_c, silent=True)
13147
13418
  # Add the final edge to the list
@@ -13150,9 +13421,9 @@ class Graph:
13150
13421
  return Graph.ByVerticesEdges(common_vertices, common_edges)
13151
13422
 
13152
13423
  @staticmethod
13153
- def Difference(graphA, graphB, vertexKey: str, silent: bool = False):
13424
+ def Difference(graphA, graphB, vertexKeys, useCentroid: bool = False, tolerance: float = 0.0001, silent: bool = False):
13154
13425
  """
13155
- Intersect the two input graphs based on an input vertex key. See https://en.wikipedia.org/wiki/Boolean_operation.
13426
+ Intersect the two input graphs based on the input vertex keys. See https://en.wikipedia.org/wiki/Boolean_operation.
13156
13427
 
13157
13428
  Parameters
13158
13429
  ----------
@@ -13160,8 +13431,14 @@ class Graph:
13160
13431
  The first input graph.
13161
13432
  graphB : topologic_core.Graph
13162
13433
  The second input graph.
13163
- vertexKey : str
13164
- The vertex dictionary key to use to determine if two vertices are the same.
13434
+ vertexKeys : list or str , optional
13435
+ The vertex dictionary key (str) or keys (list of str) to use to determine if two vertices are the same.
13436
+ If the vertexKeys are set to None or "loc" or "coord" or "xyz" (case insensitive), the distance between the
13437
+ vertices (within the tolerance) will be used to determine sameness. The default is None.
13438
+ useCentroid : bool , optional
13439
+ This is not used here, but included for API consistency for boolean operations.
13440
+ tolerance : float , optional
13441
+ The desired tolerance. The default is 0.0001.
13165
13442
  silent : bool , optional
13166
13443
  If set to True, error and warning messages are suppressed. The default is False.
13167
13444
 
@@ -13184,25 +13461,36 @@ class Graph:
13184
13461
  if not silent:
13185
13462
  print("Graph.Difference - Error: The graphB input parameter is not a valid graph. Returning None.")
13186
13463
  return None
13187
- if not isinstance(vertexKey, str):
13188
- if not silent:
13189
- print("Graph.Difference - Error: The vertexKey input parameter is not a valid string. Returning None.")
13190
- return None
13464
+
13191
13465
  vertices_a = Graph.Vertices(graphA)
13466
+ vertices_a_new = []
13467
+ for v in vertices_a:
13468
+ d = Topology.Dictionary(v)
13469
+ v_new = Vertex.ByCoordinates(Vertex.Coordinates(v))
13470
+ v_new = Topology.SetDictionary(v_new, d)
13471
+ vertices_a_new.append(v_new)
13472
+ vertices_a = vertices_a_new
13192
13473
  vertices_b = Graph.Vertices(graphB)
13474
+ vertices_b_new = []
13475
+ for v in vertices_b:
13476
+ d = Topology.Dictionary(v)
13477
+ v_new = Vertex.ByCoordinates(Vertex.Coordinates(v))
13478
+ v_new = Topology.SetDictionary(v_new, d)
13479
+ vertices_b_new.append(v_new)
13480
+ vertices_b = vertices_b_new
13193
13481
  mesh_data_a = Graph.MeshData(graphA)
13194
13482
  mesh_data_b = Graph.MeshData(graphB)
13195
13483
  edges_a = mesh_data_a['edges']
13196
13484
  edges_b = mesh_data_b['edges']
13197
13485
  edges_a_dicts = mesh_data_a['edgeDictionaries']
13198
13486
 
13199
- diff_vertices = [v for v in vertices_a if not Graph._vertex_in_list(v, vertices_b, key=vertexKey)]
13487
+ diff_vertices = [v for v in vertices_a if not Graph._vertex_in_list(v, vertices_b, keys=vertexKeys, tolerance=tolerance)]
13200
13488
  diff_edges = []
13201
13489
 
13202
13490
  for i, e in enumerate(edges_a):
13203
- if not Graph._edge_in_list(e, edges_b, vertices_a, vertices_b, key=vertexKey):
13491
+ if not Graph._edge_in_list(e, edges_b, vertices_a, vertices_b, keys=vertexKeys, tolerance=tolerance):
13204
13492
  # Create the edge
13205
- if Graph._vertex_in_list(vertices_a[e[0]], diff_vertices, key=vertexKey) and Graph._vertex_in_list(vertices_a[e[1]], diff_vertices, key=vertexKey):
13493
+ if Graph._vertex_in_list(vertices_a[e[0]], diff_vertices, keys=vertexKeys, tolerance=tolerance) and Graph._vertex_in_list(vertices_a[e[1]], diff_vertices, keys=vertexKeys, tolerance=tolerance):
13206
13494
  final_edge = Edge.ByVertices(vertices_a[e[0]], vertices_a[e[1]])
13207
13495
  # Set the edge's dictionary
13208
13496
  final_edge = Topology.SetDictionary(final_edge, Dictionary.ByPythonDictionary(edges_a_dicts[i]), silent=True)
@@ -13212,9 +13500,52 @@ class Graph:
13212
13500
  return Graph.ByVerticesEdges(diff_vertices, diff_edges)
13213
13501
 
13214
13502
  @staticmethod
13215
- def SymmetricDifference(graphA, graphB, vertexKey: str, silent: bool = False):
13503
+ def Merge(graphA, graphB, vertexKeys=None, vertexColorKey="color", useCentroid: bool = False, tolerance: float = 0.0001, silent: bool = False):
13504
+ """
13505
+ Merges the two input graphs based on the input vertex keys. This is an alias for Graph.Union. See https://en.wikipedia.org/wiki/Boolean_operation.
13506
+
13507
+ Parameters
13508
+ ----------
13509
+ graphA : topologic_core.Graph
13510
+ The first input graph.
13511
+ graphB : topologic_core.Graph
13512
+ The second input graph.
13513
+ vertexKeys : list or str , optional
13514
+ The vertex dictionary key (str) or keys (list of str) to use to determine if two vertices are the same.
13515
+ If the vertexKeys are set to None or "loc" or "coord" or "xyz" (case insensitive), the distance between the
13516
+ vertices (within the tolerance) will be used to determine sameness. The default is None.
13517
+ vertexColorKey : str , optional
13518
+ The dictionary key that is storing the vertex's color. The final colors will be averaged. The default is "color".
13519
+ useCentroid : bool , optional
13520
+ If set to True, the coordinates of identical vertices from each graph are averaged to located the new merged vertex of the resulting graph.
13521
+ Otherwise, the coordinates of the vertex of the first input graph are used. The default is False.
13522
+ tolerance : float , optional
13523
+ The desired tolerance. The default is 0.0001.
13524
+ silent : bool , optional
13525
+ If set to True, error and warning messages are suppressed. The default is False.
13526
+
13527
+ Returns
13528
+ -------
13529
+ topologic_core.Graph
13530
+ the resultant graph. Vertex and edge dictionaries are merged.
13531
+
13532
+ """
13533
+ from topologicpy.Topology import Topology
13534
+
13535
+ if not Topology.IsInstance(graphA, "graph"):
13536
+ if not silent:
13537
+ print("Graph.Union - Error: The graphA input parameter is not a valid graph. Returning None.")
13538
+ return None
13539
+ if not Topology.IsInstance(graphB, "graph"):
13540
+ if not silent:
13541
+ print("Graph.Union - Error: The graphB input parameter is not a valid graph. Returning None.")
13542
+ return None
13543
+ return Graph.Union(graphA, graphB, vertexKeys=vertexKeys, vertexColorKey=vertexColorKey, useCentroid=useCentroid, tolerance=tolerance, silent=silent)
13544
+
13545
+ @staticmethod
13546
+ def SymmetricDifference(graphA, graphB, vertexKeys, useCentroid: bool = False, tolerance: float = 0.001, silent: bool = False):
13216
13547
  """
13217
- Find the symmetric difference pf the two input graphs based on an input vertex key. See https://en.wikipedia.org/wiki/Boolean_operation.
13548
+ Find the symmetric difference (exclusive OR / XOR) of the two input graphs based on the input vertex keys. See https://en.wikipedia.org/wiki/Boolean_operation.
13218
13549
 
13219
13550
  Parameters
13220
13551
  ----------
@@ -13222,8 +13553,14 @@ class Graph:
13222
13553
  The first input graph.
13223
13554
  graphB : topologic_core.Graph
13224
13555
  The second input graph.
13225
- vertexKey : str
13226
- The vertex dictionary key to use to determine if two vertices are the same.
13556
+ vertexKeys : list or str , optional
13557
+ The vertex dictionary key (str) or keys (list of str) to use to determine if two vertices are the same.
13558
+ If the vertexKeys are set to None or "loc" or "coord" or "xyz" (case insensitive), the distance between the
13559
+ vertices (within the tolerance) will be used to determine sameness. The default is None.
13560
+ useCentroid : bool , optional
13561
+ This is not used here, but included for API consistency for boolean operations.
13562
+ tolerance : float , optional
13563
+ The desired tolerance. The default is 0.0001.
13227
13564
  silent : bool , optional
13228
13565
  If set to True, error and warning messages are suppressed. The default is False.
13229
13566
 
@@ -13244,10 +13581,49 @@ class Graph:
13244
13581
  if not silent:
13245
13582
  print("Graph.SymmetricDifference - Error: The graphB input parameter is not a valid graph. Returning None.")
13246
13583
  return None
13247
- if not isinstance(vertexKey, str):
13584
+ diffAB = Graph.Difference(graphA, graphB, vertexKeys=vertexKeys, useCentroid=useCentroid, tolerance=tolerance, silent=True)
13585
+ diffBA = Graph.Difference(graphB, graphA, vertexKeys=vertexKeys, useCentroid=useCentroid, tolerance=tolerance, silent=True)
13586
+ return Graph.Union(diffAB, diffBA, vertexKeys=vertexKeys, useCentroid=useCentroid, tolerance=tolerance, silent=True)
13587
+
13588
+ @staticmethod
13589
+ def XOR(graphA, graphB, vertexKeys, useCentroid: bool = False, tolerance: float = 0.001, silent: bool = False):
13590
+ """
13591
+ Find the symmetric difference (exclusive OR / XOR) of the two input graphs based on an input vertex key. See https://en.wikipedia.org/wiki/Boolean_operation.
13592
+
13593
+ Parameters
13594
+ ----------
13595
+ graphA : topologic_core.Graph
13596
+ The first input graph.
13597
+ graphB : topologic_core.Graph
13598
+ The second input graph.
13599
+ vertexKeys : list or str , optional
13600
+ The vertex dictionary key (str) or keys (list of str) to use to determine if two vertices are the same.
13601
+ If the vertexKeys are set to None or "loc" or "coord" or "xyz" (case insensitive), the distance between the
13602
+ vertices (within the tolerance) will be used to determine sameness. The default is None.
13603
+ useCentroid : bool , optional
13604
+ This is not used here, but included for API consistency for boolean operations.
13605
+ tolerance : float , optional
13606
+ The desired tolerance. The default is 0.0001.
13607
+ silent : bool , optional
13608
+ If set to True, error and warning messages are suppressed. The default is False.
13609
+
13610
+ Returns
13611
+ -------
13612
+ topologic_core.Graph
13613
+ the resultant graph. Vertex and edge dictionaries are not merged.
13614
+
13615
+ """
13616
+
13617
+ from topologicpy.Topology import Topology
13618
+
13619
+ if not Topology.IsInstance(graphA, "graph"):
13620
+ if not silent:
13621
+ print("Graph.XOR - Error: The graphA input parameter is not a valid graph. Returning None.")
13622
+ return None
13623
+ if not Topology.IsInstance(graphB, "graph"):
13248
13624
  if not silent:
13249
- print("Graph.SymmetricDifference - Error: The vertexKey input parameter is not a valid string. Returning None.")
13625
+ print("Graph.XOR - Error: The graphB input parameter is not a valid graph. Returning None.")
13250
13626
  return None
13251
- diffAB = Graph.Difference(graphA, graphB, vertexKey=vertexKey, silent=True)
13252
- diffBA = Graph.Difference(graphB, graphA, vertexKey=vertexKey, silent=True)
13253
- return Graph.Union(diffAB, diffBA, vertexKey=vertexKey, silent=True)
13627
+ diffAB = Graph.Difference(graphA, graphB, vertexKeys=vertexKeys, useCentroid=useCentroid, tolerance=tolerance, silent=True)
13628
+ diffBA = Graph.Difference(graphB, graphA, vertexKeys=vertexKeys, useCentroid=useCentroid, tolerance=tolerance, silent=True)
13629
+ return Graph.Union(diffAB, diffBA, vertexKeys=vertexKeys, useCentroid=useCentroid, tolerance=tolerance, silent=True)
topologicpy/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = '0.8.39'
1
+ __version__ = '0.8.40'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: topologicpy
3
- Version: 0.8.39
3
+ Version: 0.8.40
4
4
  Summary: An AI-Powered Spatial Modelling and Analysis Software Library for Architecture, Engineering, and Construction.
5
5
  Author-email: Wassim Jabi <wassim.jabi@gmail.com>
6
6
  License: AGPL v3 License
@@ -5,14 +5,14 @@ topologicpy/CSG.py,sha256=uDkOSmc8m1V_k7T3UCerODhOSyYNO4FRDzoOqt0kEt8,15590
5
5
  topologicpy/Cell.py,sha256=3et98bv27m1-7OqFCeD4cLMBgC_BAsSGyxHi_4PgJ4Y,176072
6
6
  topologicpy/CellComplex.py,sha256=NP6yptbkGXYmlfBv9fRimOnNle0mkjV8Yo_ug5NKpKE,60877
7
7
  topologicpy/Cluster.py,sha256=wvfMAx6aPrSAt5nQ4--KnqD4EK9MGjch6Dg985WF7JQ,58748
8
- topologicpy/Color.py,sha256=ZVVQRKGjebY9aOU1gpN_AbssdRRiVKlZV3f8TrsTNgg,20307
8
+ topologicpy/Color.py,sha256=FcR0-__giyGQqvgiOrG8GkA65arHbiS33Si-QbUADPI,23362
9
9
  topologicpy/Context.py,sha256=G3CwMvN8Jw2rnQRwB-n4MaQq_wLS0vPimbXKwsdMJ80,3055
10
10
  topologicpy/DGL.py,sha256=HQXy9iDnrvWGDxaBfe5pRbweQ2zLBvAf6UdjfhKkQYI,139041
11
11
  topologicpy/Dictionary.py,sha256=2Sxm8twR1W4ksZho0YXQB_EltK2qbZWK4UHskP3jvFQ,40846
12
12
  topologicpy/Edge.py,sha256=CPdQKaE7ft6zgh0vxekkfGRRUY_yEqkEJ14NvjSgJOA,73190
13
13
  topologicpy/EnergyModel.py,sha256=Pyb28gDDwhzlQIH0xqAygqS0P3SJxWyyV7OWS_AAfRs,53856
14
14
  topologicpy/Face.py,sha256=BT_5ymb7-s-Wb1tuaBtkopJpeNg-RbooTUk_-KInQ6c,201618
15
- topologicpy/Graph.py,sha256=YLigYjWAAhMMtUurYngjK9NUMLkDM08BmYWYjxYwMcs,620455
15
+ topologicpy/Graph.py,sha256=z_9TeMkmwFXlCfVDW9Z56PX0sHxGj8iVKlCdJLreMo0,639785
16
16
  topologicpy/Grid.py,sha256=EbI2NcYhQDpD5mItd7A1Lpr8Puuf87vZPWuoh7_gChQ,18483
17
17
  topologicpy/Helper.py,sha256=qEsE4yaboEGW94q9lFCff0I_JwwTTQnDAFXw006yHaQ,31203
18
18
  topologicpy/Honeybee.py,sha256=yctkwfdupKnp7bAOjP1Z4YaYpRrWoMEb4gz9Z5zaWwE,21751
@@ -30,9 +30,9 @@ topologicpy/Vector.py,sha256=X12eqskn28bdB7sLY1EZhq3noPYzPbNEgHPb4a959ss,42302
30
30
  topologicpy/Vertex.py,sha256=epBfbD7fm87T-TZ0WuwrioXdYqg9NgRlHn_qUFtVbkc,84562
31
31
  topologicpy/Wire.py,sha256=vE6IoObVucOZVTFMPiHuNN4DDezRHHyFbwhF5WRBm3s,231547
32
32
  topologicpy/__init__.py,sha256=RMftibjgAnHB1vdL-muo71RwMS4972JCxHuRHOlU428,928
33
- topologicpy/version.py,sha256=krvNarxqLr-1e4M5aYKlWbcRZoZxDYVlZehTgEbpBTg,23
34
- topologicpy-0.8.39.dist-info/licenses/LICENSE,sha256=FK0vJ73LuE8PYJAn7LutsReWR47-Ooovw2dnRe5yV6Q,681
35
- topologicpy-0.8.39.dist-info/METADATA,sha256=l1XGyTl1wZZ-G4PgjDEzyZ_kitEAFGAGhcgW8wV1Jos,10535
36
- topologicpy-0.8.39.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
37
- topologicpy-0.8.39.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
38
- topologicpy-0.8.39.dist-info/RECORD,,
33
+ topologicpy/version.py,sha256=9UtSkYQrOL8TXxQBwLoy5jvQKNWp84nSX32fmM7V0Ac,23
34
+ topologicpy-0.8.40.dist-info/licenses/LICENSE,sha256=FK0vJ73LuE8PYJAn7LutsReWR47-Ooovw2dnRe5yV6Q,681
35
+ topologicpy-0.8.40.dist-info/METADATA,sha256=8YuR3I1XDjArnIbbajaveZEDc7Q8eVk4aBOvtaLhULA,10535
36
+ topologicpy-0.8.40.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
37
+ topologicpy-0.8.40.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
38
+ topologicpy-0.8.40.dist-info/RECORD,,