topologicpy 0.7.21__py3-none-any.whl → 0.7.22__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/ANN.py +3 -6
- topologicpy/Cell.py +5 -3
- topologicpy/Cluster.py +0 -4
- topologicpy/DGL.py +1 -9
- topologicpy/Dictionary.py +24 -13
- topologicpy/Edge.py +0 -6
- topologicpy/Face.py +35 -26
- topologicpy/Graph.py +2 -19
- topologicpy/Grid.py +0 -1
- topologicpy/Helper.py +0 -2
- topologicpy/Honeybee.py +27 -2
- topologicpy/Plotly.py +0 -1
- topologicpy/Polyskel.py +0 -21
- topologicpy/Shell.py +2 -4
- topologicpy/Sun.py +14 -5
- topologicpy/Topology.py +372 -179
- topologicpy/Vector.py +21 -13
- topologicpy/Vertex.py +8 -5
- topologicpy/Wire.py +53 -35
- topologicpy/version.py +1 -1
- {topologicpy-0.7.21.dist-info → topologicpy-0.7.22.dist-info}/METADATA +1 -1
- topologicpy-0.7.22.dist-info/RECORD +34 -0
- {topologicpy-0.7.21.dist-info → topologicpy-0.7.22.dist-info}/WHEEL +1 -1
- topologicpy-0.7.21.dist-info/RECORD +0 -34
- {topologicpy-0.7.21.dist-info → topologicpy-0.7.22.dist-info}/LICENSE +0 -0
- {topologicpy-0.7.21.dist-info → topologicpy-0.7.22.dist-info}/top_level.txt +0 -0
topologicpy/Topology.py
CHANGED
@@ -330,8 +330,8 @@ class Topology():
|
|
330
330
|
The input topology with the input dictionary added to it.
|
331
331
|
|
332
332
|
"""
|
333
|
-
|
334
333
|
from topologicpy.Dictionary import Dictionary
|
334
|
+
|
335
335
|
if not Topology.IsInstance(topology, "Topology"):
|
336
336
|
print("Topology.AddDictionary - Error: the input topology parameter is not a valid topology. Returning None.")
|
337
337
|
return None
|
@@ -820,7 +820,6 @@ class Topology():
|
|
820
820
|
apertures += Topology.Apertures(subTopology, subTopologyType=None)
|
821
821
|
return apertures
|
822
822
|
|
823
|
-
|
824
823
|
@staticmethod
|
825
824
|
def ApertureTopologies(topology, subTopologyType=None):
|
826
825
|
"""
|
@@ -2139,6 +2138,7 @@ class Topology():
|
|
2139
2138
|
The list of IFC object types to include. It is case insensitive. If set to an empty list, all types are included. The default is [].
|
2140
2139
|
excludeTypes : list , optional
|
2141
2140
|
The list of IFC object types to exclude. It is case insensitive. If set to an empty list, no types are excluded. The default is [].
|
2141
|
+
|
2142
2142
|
Returns
|
2143
2143
|
-------
|
2144
2144
|
list
|
@@ -2706,141 +2706,305 @@ class Topology():
|
|
2706
2706
|
return data
|
2707
2707
|
|
2708
2708
|
@staticmethod
|
2709
|
-
def
|
2709
|
+
def ByOBJFile(objFile, mtlFile = None,
|
2710
|
+
defaultColor: list = [255,255,255],
|
2711
|
+
defaultOpacity: float = 1.0,
|
2712
|
+
transposeAxes: bool = True,
|
2713
|
+
removeCoplanarFaces: bool = True,
|
2714
|
+
|
2715
|
+
mantissa : int = 6,
|
2716
|
+
tolerance: float = 0.0001):
|
2710
2717
|
"""
|
2711
|
-
|
2718
|
+
Imports a topology from an OBJ file and an associated materials file.
|
2719
|
+
This method is basic and does not support textures and vertex normals.
|
2712
2720
|
|
2713
2721
|
Parameters
|
2714
2722
|
----------
|
2715
|
-
|
2716
|
-
The
|
2723
|
+
objFile : file object
|
2724
|
+
The OBJ file.
|
2725
|
+
mtlFile : file object , optional
|
2726
|
+
The MTL file. The default is None.
|
2727
|
+
defaultColor : list , optional
|
2728
|
+
The default color to use if none is specified in the file. The default is [255, 255, 255] (white).
|
2729
|
+
defaultOpacity : float , optional
|
2730
|
+
The default opacity to use if none is specified in the file. The default is 1.0 (fully opaque).
|
2717
2731
|
transposeAxes : bool , optional
|
2718
|
-
If set to True the Z and Y
|
2719
|
-
|
2720
|
-
If set to True
|
2732
|
+
If set to True the Z and Y axes are transposed. Otherwise, they are not. The default is True.
|
2733
|
+
removeCoplanarFaces : bool , optional
|
2734
|
+
If set to True, coplanar faces are merged. The default is True.
|
2735
|
+
mantissa : int , optional
|
2736
|
+
The desired length of the mantissa. The default is 6.
|
2721
2737
|
tolerance : float , optional
|
2722
|
-
The desired tolerance. The default is 0.0001
|
2738
|
+
The desired tolerance. The default is 0.0001
|
2723
2739
|
|
2724
2740
|
Returns
|
2725
2741
|
-------
|
2726
|
-
|
2727
|
-
The
|
2742
|
+
list
|
2743
|
+
The imported topologies.
|
2728
2744
|
|
2729
2745
|
"""
|
2730
|
-
from
|
2731
|
-
from tqdm.auto import tqdm
|
2746
|
+
from os.path import dirname, join, exists
|
2732
2747
|
|
2733
|
-
|
2734
|
-
|
2735
|
-
|
2736
|
-
for i in
|
2737
|
-
|
2738
|
-
|
2739
|
-
|
2740
|
-
|
2741
|
-
|
2742
|
-
|
2743
|
-
|
2744
|
-
|
2745
|
-
|
2746
|
-
|
2747
|
-
|
2748
|
-
|
2749
|
-
|
2750
|
-
|
2751
|
-
def parsetqdm(lines):
|
2752
|
-
vertices = []
|
2753
|
-
faces = []
|
2754
|
-
for i in tqdm(range(len(lines))):
|
2755
|
-
s = lines[i].split()
|
2756
|
-
if isinstance(s, list):
|
2757
|
-
if len(s) > 3:
|
2758
|
-
if s[0].lower() == "v":
|
2759
|
-
vertices.append([float(s[1]), float(s[2]), float(s[3])])
|
2760
|
-
elif s[0].lower() == "f":
|
2761
|
-
temp_faces = []
|
2762
|
-
for j in range(1,len(s)):
|
2763
|
-
f = s[j].split("/")[0]
|
2764
|
-
temp_faces.append(int(f)-1)
|
2765
|
-
faces.append(temp_faces)
|
2766
|
-
return [vertices, faces]
|
2767
|
-
|
2768
|
-
|
2769
|
-
lines = string.split("\n")
|
2770
|
-
if lines:
|
2771
|
-
if progressBar:
|
2772
|
-
vertices, faces = parsetqdm(lines)
|
2773
|
-
else:
|
2774
|
-
vertices, faces = parse(lines)
|
2775
|
-
if vertices or faces:
|
2776
|
-
topology = Topology.ByGeometry(vertices = vertices, faces = faces, outputMode="default", tolerance=tolerance)
|
2777
|
-
if transposeAxes == True:
|
2778
|
-
topology = Topology.Rotate(topology, origin=Vertex.Origin(), axis=[1, 0, 0], angle=90)
|
2779
|
-
return Topology.SelfMerge(topology)
|
2780
|
-
print("Topology.ByOBJString - Error: Could not find vertices or faces. Returning None.")
|
2781
|
-
return None
|
2748
|
+
|
2749
|
+
def find_next_word_after_mtllib(text):
|
2750
|
+
words = text.split()
|
2751
|
+
for i, word in enumerate(words):
|
2752
|
+
if word == 'mtllib' and i + 1 < len(words):
|
2753
|
+
return words[i + 1]
|
2754
|
+
return None
|
2755
|
+
|
2756
|
+
obj_string = objFile.read()
|
2757
|
+
mtl_filename = find_next_word_after_mtllib(obj_string)
|
2758
|
+
mtl_string = None
|
2759
|
+
if mtlFile:
|
2760
|
+
mtl_string = mtlFile.read()
|
2761
|
+
return Topology.ByOBJString(obj_string, mtl_string,
|
2762
|
+
defaultColor=defaultColor, defaultOpacity=defaultOpacity,
|
2763
|
+
transposeAxes=transposeAxes, removeCoplanarFaces=removeCoplanarFaces,
|
2764
|
+
mantissa=mantissa, tolerance=tolerance)
|
2782
2765
|
|
2783
2766
|
@staticmethod
|
2784
|
-
def
|
2767
|
+
def ByOBJPath(objPath,
|
2768
|
+
defaultColor: list = [255,255,255], defaultOpacity: float = 1.0,
|
2769
|
+
transposeAxes: bool = True, removeCoplanarFaces: bool = True,
|
2770
|
+
mantissa : int = 6, tolerance: float = 0.0001):
|
2785
2771
|
"""
|
2786
|
-
Imports
|
2772
|
+
Imports a topology from an OBJ file path and an associated materials file.
|
2773
|
+
This method is basic and does not support textures and vertex normals.
|
2787
2774
|
|
2788
2775
|
Parameters
|
2789
2776
|
----------
|
2790
|
-
|
2791
|
-
The
|
2777
|
+
objPath : str
|
2778
|
+
The path to the OBJ file.
|
2779
|
+
defaultColor : list , optional
|
2780
|
+
The default color to use if none is pecified in the file. The default is [255, 255, 255] (white).
|
2781
|
+
defaultOpacity : float , optional
|
2782
|
+
The default opacity to use if none is pecified in the file. The default is 1.0 (fully opaque).
|
2792
2783
|
transposeAxes : bool , optional
|
2793
|
-
If set to True the Z and Y
|
2794
|
-
|
2795
|
-
If set to True
|
2784
|
+
If set to True the Z and Y axes are transposed. Otherwise, they are not. The default is True.
|
2785
|
+
removeCoplanarFaces : bool , optional
|
2786
|
+
If set to True, coplanar faces are merged. The default is True.
|
2787
|
+
mantissa : int , optional
|
2788
|
+
The desired length of the mantissa. The default is 6.
|
2796
2789
|
tolerance : float , optional
|
2797
|
-
The desired tolerance. The default is 0.0001
|
2790
|
+
The desired tolerance. The default is 0.0001
|
2798
2791
|
|
2799
2792
|
Returns
|
2800
2793
|
-------
|
2801
|
-
|
2802
|
-
The imported
|
2794
|
+
list
|
2795
|
+
The imported topologies.
|
2803
2796
|
|
2804
2797
|
"""
|
2805
|
-
|
2806
|
-
|
2798
|
+
from os.path import dirname, join, exists
|
2799
|
+
|
2800
|
+
if not objPath:
|
2801
|
+
print("Topology.ByOBJPath - Error: the input OBJ path parameter is not a valid path. Returning None.")
|
2807
2802
|
return None
|
2808
|
-
|
2809
|
-
|
2810
|
-
|
2811
|
-
|
2812
|
-
|
2803
|
+
if not exists(objPath):
|
2804
|
+
print("Topology.ByOBJPath - Error: the input OBJ path does not exist. Returning None.")
|
2805
|
+
return None
|
2806
|
+
|
2807
|
+
def find_next_word_after_mtllib(text):
|
2808
|
+
words = text.split()
|
2809
|
+
for i, word in enumerate(words):
|
2810
|
+
if word == 'mtllib' and i + 1 < len(words):
|
2811
|
+
return words[i + 1]
|
2812
|
+
return None
|
2813
|
+
|
2814
|
+
with open(objPath, 'r') as obj_file:
|
2815
|
+
obj_string = obj_file.read()
|
2816
|
+
mtl_filename = find_next_word_after_mtllib(obj_string)
|
2817
|
+
mtl_string = None
|
2818
|
+
if mtl_filename:
|
2819
|
+
parent_folder = dirname(objPath)
|
2820
|
+
mtl_path = join(parent_folder, mtl_filename)
|
2821
|
+
if exists(mtl_path):
|
2822
|
+
with open(mtl_path, 'r') as mtl_file:
|
2823
|
+
mtl_string = mtl_file.read()
|
2824
|
+
return Topology.ByOBJString(obj_string, mtl_string,
|
2825
|
+
defaultColor=defaultColor, defaultOpacity=defaultOpacity,
|
2826
|
+
transposeAxes=transposeAxes, removeCoplanarFaces=removeCoplanarFaces,
|
2827
|
+
mantissa=mantissa, tolerance=tolerance)
|
2828
|
+
|
2813
2829
|
@staticmethod
|
2814
|
-
def
|
2830
|
+
def ByOBJString(objString: str, mtlString: str = None,
|
2831
|
+
defaultColor: list = [255,255,255], defaultOpacity: float = 1.0,
|
2832
|
+
transposeAxes: bool = True, removeCoplanarFaces: bool = False,
|
2833
|
+
mantissa = 6, tolerance = 0.0001):
|
2815
2834
|
"""
|
2816
|
-
Imports
|
2835
|
+
Imports a topology from OBJ and MTL strings.
|
2817
2836
|
|
2818
2837
|
Parameters
|
2819
2838
|
----------
|
2820
|
-
|
2821
|
-
The
|
2839
|
+
objString : str
|
2840
|
+
The string of the OBJ file.
|
2841
|
+
mtlString : str , optional
|
2842
|
+
The string of the MTL file. The default is None.
|
2843
|
+
defaultColor : list , optional
|
2844
|
+
The default color to use if none is pecified in the string. The default is [255, 255, 255] (white).
|
2845
|
+
defaultOpacity : float , optional
|
2846
|
+
The default opacity to use if none is pecified in the string. The default is 1.0 (fully opaque).
|
2822
2847
|
transposeAxes : bool , optional
|
2823
|
-
If set to True the Z and Y
|
2824
|
-
|
2825
|
-
If set to True
|
2848
|
+
If set to True the Z and Y axes are transposed. Otherwise, they are not. The default is True.
|
2849
|
+
removeCoplanarFaces : bool , optional
|
2850
|
+
If set to True, coplanar faces are merged. The default is True.
|
2851
|
+
mantissa : int , optional
|
2852
|
+
The desired length of the mantissa. The default is 6.
|
2826
2853
|
tolerance : float , optional
|
2827
|
-
The desired tolerance. The default is 0.0001
|
2854
|
+
The desired tolerance. The default is 0.0001
|
2828
2855
|
|
2829
2856
|
Returns
|
2830
2857
|
-------
|
2831
|
-
|
2832
|
-
The imported
|
2858
|
+
list
|
2859
|
+
The imported topologies.
|
2833
2860
|
|
2834
2861
|
"""
|
2835
|
-
|
2836
|
-
|
2837
|
-
|
2838
|
-
|
2839
|
-
|
2840
|
-
|
2841
|
-
|
2842
|
-
|
2843
|
-
|
2862
|
+
from topologicpy.Vertex import Vertex
|
2863
|
+
from topologicpy.Edge import Edge
|
2864
|
+
from topologicpy.Wire import Wire
|
2865
|
+
from topologicpy.Face import Face
|
2866
|
+
from topologicpy.Shell import Shell
|
2867
|
+
from topologicpy.Cell import Cell
|
2868
|
+
from topologicpy.Cluster import Cluster
|
2869
|
+
from topologicpy.Topology import Topology
|
2870
|
+
from topologicpy.Dictionary import Dictionary
|
2871
|
+
from topologicpy.Helper import Helper
|
2872
|
+
|
2873
|
+
def load_materials(mtl_string):
|
2874
|
+
materials = {}
|
2875
|
+
if not mtl_string:
|
2876
|
+
return materials
|
2877
|
+
current_material = None
|
2878
|
+
lines = mtlString.split('\n')
|
2879
|
+
for line in lines:
|
2880
|
+
line = line.strip()
|
2881
|
+
if line.startswith('#') or not line:
|
2882
|
+
continue
|
2883
|
+
parts = line.split()
|
2884
|
+
if not parts:
|
2885
|
+
continue
|
2886
|
+
if parts[0] == 'newmtl':
|
2887
|
+
current_material = parts[1]
|
2888
|
+
materials[current_material] = {}
|
2889
|
+
elif current_material:
|
2890
|
+
if parts[0] == 'Kd': # Diffuse color
|
2891
|
+
materials[current_material]['Kd'] = list(map(float, parts[1:4]))
|
2892
|
+
elif parts[0] == 'Ka': # Ambient color
|
2893
|
+
materials[current_material]['Ka'] = list(map(float, parts[1:4]))
|
2894
|
+
elif parts[0] == 'Ks': # Specular color
|
2895
|
+
materials[current_material]['Ks'] = list(map(float, parts[1:4]))
|
2896
|
+
elif parts[0] == 'Ns': # Specular exponent
|
2897
|
+
materials[current_material]['Ns'] = float(parts[1])
|
2898
|
+
elif parts[0] == 'd': # Transparency
|
2899
|
+
materials[current_material]['d'] = float(parts[1])
|
2900
|
+
elif parts[0] == 'map_Kd': # Diffuse texture map
|
2901
|
+
materials[current_material]['map_Kd'] = parts[1]
|
2902
|
+
# Add more properties as needed
|
2903
|
+
return materials
|
2904
|
+
|
2905
|
+
materials = load_materials(mtlString)
|
2906
|
+
vertices = []
|
2907
|
+
textures = []
|
2908
|
+
normals = []
|
2909
|
+
groups = {}
|
2910
|
+
current_group = None
|
2911
|
+
current_material = None
|
2912
|
+
lines = objString.split('\n')
|
2913
|
+
for line in lines:
|
2914
|
+
line = line.strip()
|
2915
|
+
if line.startswith('#'):
|
2916
|
+
continue
|
2917
|
+
|
2918
|
+
parts = line.split()
|
2919
|
+
if not parts:
|
2920
|
+
continue
|
2921
|
+
|
2922
|
+
if parts[0] == 'v':
|
2923
|
+
vertex = list(map(float, parts[1:4]))
|
2924
|
+
vertex = [round(coord, mantissa) for coord in vertex]
|
2925
|
+
if transposeAxes == True:
|
2926
|
+
vertex = [vertex[0], vertex[2], vertex[1]]
|
2927
|
+
vertices.append(vertex)
|
2928
|
+
elif parts[0] == 'vt':
|
2929
|
+
texture = list(map(float, parts[1:3]))
|
2930
|
+
textures.append(texture)
|
2931
|
+
elif parts[0] == 'vn':
|
2932
|
+
normal = list(map(float, parts[1:4]))
|
2933
|
+
normals.append(normal)
|
2934
|
+
elif parts[0] == 'f':
|
2935
|
+
face = []
|
2936
|
+
for part in parts[1:]:
|
2937
|
+
indices = part.split('/')
|
2938
|
+
vertex_index = int(indices[0]) - 1 if indices[0] else None
|
2939
|
+
texture_index = int(indices[1]) - 1 if len(indices) > 1 and indices[1] else None
|
2940
|
+
normal_index = int(indices[2]) - 1 if len(indices) > 2 and indices[2] else None
|
2941
|
+
face.append((vertex_index, texture_index, normal_index))
|
2942
|
+
|
2943
|
+
if current_group not in groups:
|
2944
|
+
groups[current_group] = []
|
2945
|
+
groups[current_group].append((face, current_material))
|
2946
|
+
elif parts[0] == 'usemtl':
|
2947
|
+
current_material = parts[1]
|
2948
|
+
elif parts[0] == 'g' or parts[0] == 'o':
|
2949
|
+
current_group = parts[1] if len(parts) > 1 else None
|
2950
|
+
|
2951
|
+
obj_data = {
|
2952
|
+
'vertices': vertices,
|
2953
|
+
'textures': textures,
|
2954
|
+
'normals': normals,
|
2955
|
+
'materials': materials,
|
2956
|
+
'groups': groups
|
2957
|
+
}
|
2958
|
+
keys = obj_data.keys()
|
2959
|
+
groups = obj_data['groups']
|
2960
|
+
group_keys = groups.keys()
|
2961
|
+
vertices = obj_data['vertices']
|
2962
|
+
groups = obj_data['groups']
|
2963
|
+
materials = obj_data['materials']
|
2964
|
+
names = list(groups.keys())
|
2965
|
+
return_topologies = []
|
2966
|
+
for i in range(len(names)):
|
2967
|
+
object_faces = []
|
2968
|
+
face_selectors = []
|
2969
|
+
object_name = names[i]
|
2970
|
+
faces = groups[object_name]
|
2971
|
+
f = faces[0] # Get object material from first face. Assume it is the material of the group
|
2972
|
+
object_color = defaultColor
|
2973
|
+
object_opacity = defaultOpacity
|
2974
|
+
object_material = None
|
2975
|
+
if len(f) >= 2:
|
2976
|
+
object_material = f[1]
|
2977
|
+
if object_material in materials.keys():
|
2978
|
+
object_color = materials[object_material]['Kd']
|
2979
|
+
object_color = [int(round(c*255,0)) for c in object_color]
|
2980
|
+
object_opacity = materials[object_material]['d']
|
2981
|
+
for f in faces:
|
2982
|
+
indices = f[0]
|
2983
|
+
face_material = f[1]
|
2984
|
+
face_indices = []
|
2985
|
+
for coordinate in indices:
|
2986
|
+
face_indices.append(coordinate[0])
|
2987
|
+
face = Topology.ByGeometry(vertices=vertices, faces=[face_indices])
|
2988
|
+
object_faces.append(face)
|
2989
|
+
if not face_material == object_material:
|
2990
|
+
if face_material in materials.keys():
|
2991
|
+
face_color = materials[face_material]['Kd']
|
2992
|
+
face_color = [int(round(c*255,0)) for c in face_color]
|
2993
|
+
face_opacity = materials[face_material]['d']
|
2994
|
+
selector = Face.InternalVertex(face)
|
2995
|
+
d = Dictionary.ByKeysValues(['color', 'opacity'], [face_color, face_opacity])
|
2996
|
+
selector = Topology.SetDictionary(selector, d)
|
2997
|
+
face_selectors.append(selector)
|
2998
|
+
|
2999
|
+
topology = Topology.SelfMerge(Cluster.ByTopologies(object_faces), tolerance=tolerance)
|
3000
|
+
if removeCoplanarFaces:
|
3001
|
+
topology = Topology.RemoveCoplanarFaces(topology, tolerance=tolerance)
|
3002
|
+
d = Dictionary.ByKeysValues(['name', 'color', 'opacity'], [object_name, object_color, object_opacity])
|
3003
|
+
topology = Topology.SetDictionary(topology, d)
|
3004
|
+
if len(face_selectors) > 0:
|
3005
|
+
topology = Topology.TransferDictionariesBySelectors(topology, selectors=face_selectors, tranFaces=True, tolerance=tolerance)
|
3006
|
+
return_topologies.append(topology)
|
3007
|
+
return return_topologies
|
2844
3008
|
|
2845
3009
|
@staticmethod
|
2846
3010
|
def ByOCCTShape(occtShape):
|
@@ -3854,7 +4018,6 @@ class Topology():
|
|
3854
4018
|
return True
|
3855
4019
|
return False
|
3856
4020
|
|
3857
|
-
|
3858
4021
|
def ExportToDXF(topologies, path: str, overwrite: bool = False, mantissa: int = 6):
|
3859
4022
|
"""
|
3860
4023
|
Exports the input topology to a DXF file. See https://en.wikipedia.org/wiki/AutoCAD_DXF.
|
@@ -4373,7 +4536,6 @@ class Topology():
|
|
4373
4536
|
returnDict['dictionary'] = Dictionary.PythonDictionary(Topology.Dictionary(topology))
|
4374
4537
|
return returnDict
|
4375
4538
|
|
4376
|
-
|
4377
4539
|
def getApertureData(topology, topLevel="False", uuidKey="uuid"):
|
4378
4540
|
json_data = []
|
4379
4541
|
if Topology.IsInstance(topology, "Vertex"):
|
@@ -4512,7 +4674,7 @@ class Topology():
|
|
4512
4674
|
return json_string
|
4513
4675
|
|
4514
4676
|
@staticmethod
|
4515
|
-
def OBJString(topology, transposeAxes: bool = True, mode: int = 0, meshSize: float = None, mantissa: int = 6, tolerance: float = 0.0001):
|
4677
|
+
def OBJString(topology, color, vertexIndex, transposeAxes: bool = True, mode: int = 0, meshSize: float = None, mantissa: int = 6, tolerance: float = 0.0001):
|
4516
4678
|
"""
|
4517
4679
|
Returns the Wavefront string of the input topology. This is very experimental and outputs a simple solid topology.
|
4518
4680
|
|
@@ -4520,6 +4682,10 @@ class Topology():
|
|
4520
4682
|
----------
|
4521
4683
|
topology : topologic_core.Topology
|
4522
4684
|
The input topology.
|
4685
|
+
color : list
|
4686
|
+
The desired color to assign to the topology
|
4687
|
+
vertexIndex : int
|
4688
|
+
The vertex index to use as the starting index.
|
4523
4689
|
transposeAxes : bool , optional
|
4524
4690
|
If set to True the Z and Y coordinates are transposed so that Y points "up"
|
4525
4691
|
mode : int , optional
|
@@ -4548,17 +4714,16 @@ class Topology():
|
|
4548
4714
|
The Wavefront OBJ string of the input topology
|
4549
4715
|
|
4550
4716
|
"""
|
4717
|
+
|
4551
4718
|
from topologicpy.Helper import Helper
|
4552
|
-
from topologicpy.Vertex import Vertex
|
4553
|
-
from topologicpy.Face import Face
|
4554
4719
|
|
4555
4720
|
if not Topology.IsInstance(topology, "Topology"):
|
4556
4721
|
print("Topology.ExportToOBJ - Error: the input topology parameter is not a valid topology. Returning None.")
|
4557
4722
|
return None
|
4558
|
-
|
4723
|
+
|
4559
4724
|
lines = []
|
4560
|
-
version = Helper.Version()
|
4561
|
-
lines.append("# topologicpy "+version)
|
4725
|
+
#version = Helper.Version()
|
4726
|
+
#lines.append("# topologicpy " + version)
|
4562
4727
|
topology = Topology.Triangulate(topology, mode=mode, meshSize=meshSize, tolerance=tolerance)
|
4563
4728
|
d = Topology.Geometry(topology, mantissa=mantissa)
|
4564
4729
|
vertices = d['vertices']
|
@@ -4569,26 +4734,26 @@ class Topology():
|
|
4569
4734
|
tVertices.append([v[0], v[2], v[1]])
|
4570
4735
|
vertices = tVertices
|
4571
4736
|
for v in vertices:
|
4572
|
-
lines.append("v "+str(v[0])+" "+str(v[1])+" "+str(v[2]))
|
4737
|
+
lines.append("v " + str(v[0]) + " " + str(v[1]) + " " + str(v[2]))
|
4573
4738
|
for f in faces:
|
4574
|
-
line = "
|
4739
|
+
line = "usemtl " + str(color) + "\nf" # reference the material name
|
4575
4740
|
for j in f:
|
4576
|
-
line = line+" "+str(j+
|
4741
|
+
line = line + " " + str(j + vertexIndex)
|
4577
4742
|
lines.append(line)
|
4578
4743
|
finalLines = lines[0]
|
4579
|
-
for i in range(1,len(lines)):
|
4580
|
-
finalLines = finalLines+"\n"+lines[i]
|
4581
|
-
return finalLines
|
4744
|
+
for i in range(1, len(lines)):
|
4745
|
+
finalLines = finalLines + "\n" + lines[i]
|
4746
|
+
return finalLines, len(vertices)
|
4582
4747
|
|
4583
4748
|
@staticmethod
|
4584
|
-
def ExportToOBJ(
|
4749
|
+
def ExportToOBJ(*topologies, path, nameKey="name", colorKey="color", opacityKey="opacity", defaultColor=[256,256,256], defaultOpacity=0.5, transposeAxes: bool = True, mode: int = 0, meshSize: float = None, overwrite: bool = False, mantissa: int = 6, tolerance: float = 0.0001):
|
4585
4750
|
"""
|
4586
4751
|
Exports the input topology to a Wavefront OBJ file. This is very experimental and outputs a simple solid topology.
|
4587
4752
|
|
4588
4753
|
Parameters
|
4589
4754
|
----------
|
4590
|
-
|
4591
|
-
The input
|
4755
|
+
topologies : list or comma separated topologies
|
4756
|
+
The input list of topologies.
|
4592
4757
|
path : str
|
4593
4758
|
The input file path.
|
4594
4759
|
transposeAxes : bool , optional
|
@@ -4621,11 +4786,21 @@ class Topology():
|
|
4621
4786
|
True if the export operation is successful. False otherwise.
|
4622
4787
|
|
4623
4788
|
"""
|
4789
|
+
from topologicpy.Helper import Helper
|
4790
|
+
from topologicpy.Dictionary import Dictionary
|
4624
4791
|
from os.path import exists
|
4625
4792
|
|
4626
|
-
if
|
4627
|
-
|
4793
|
+
if isinstance(topologies, tuple):
|
4794
|
+
topologies = Helper.Flatten(list(topologies))
|
4795
|
+
if isinstance(topologies, list):
|
4796
|
+
new_topologies = [d for d in topologies if Topology.IsInstance(d, "Topology")]
|
4797
|
+
if len(new_topologies) == 0:
|
4798
|
+
print("Topology.ExportToOBJ - Error: the input topologies parameter does not contain any valid topologies. Returning None.")
|
4628
4799
|
return None
|
4800
|
+
if not isinstance(new_topologies, list):
|
4801
|
+
print("Dictionary.ByMergedDictionaries - Error: The input dictionaries parameter is not a valid list. Returning None.")
|
4802
|
+
return None
|
4803
|
+
|
4629
4804
|
if not overwrite and exists(path):
|
4630
4805
|
print("Topology.ExportToOBJ - Error: a file already exists at the specified path and overwrite is set to False. Returning None.")
|
4631
4806
|
return None
|
@@ -4635,10 +4810,40 @@ class Topology():
|
|
4635
4810
|
if ext.lower() != ".obj":
|
4636
4811
|
path = path+".obj"
|
4637
4812
|
status = False
|
4638
|
-
|
4639
|
-
|
4640
|
-
|
4641
|
-
|
4813
|
+
|
4814
|
+
mtl_path = path[:-4] + ".mtl"
|
4815
|
+
|
4816
|
+
|
4817
|
+
# Write out the material file
|
4818
|
+
n = max(len(str(len(topologies))), 3)
|
4819
|
+
with open(mtl_path, "w") as mtl_file:
|
4820
|
+
for i in range(len(new_topologies)):
|
4821
|
+
d = Topology.Dictionary(new_topologies[i])
|
4822
|
+
name = Dictionary.ValueAtKey(d, nameKey) or "Untitled_"+str(i).zfill(n)
|
4823
|
+
color = Dictionary.ValueAtKey(d, colorKey) or defaultColor
|
4824
|
+
color = [c/255 for c in color]
|
4825
|
+
opacity = Dictionary.ValueAtKey(d, opacityKey) or defaultOpacity
|
4826
|
+
mtl_file.write("newmtl color_" + str(i).zfill(n) + "\n")
|
4827
|
+
mtl_file.write("Kd " + ' '.join(map(str, color)) + "\n")
|
4828
|
+
mtl_file.write("d " + str(opacity) + "\n")
|
4829
|
+
|
4830
|
+
# Write out the obj file
|
4831
|
+
with open(path, "w") as obj_file:
|
4832
|
+
vertex_index = 1 # global vertex index counter
|
4833
|
+
obj_file.writelines("# topologicpy "+Helper.Version()+"\n")
|
4834
|
+
obj_file.writelines("mtllib " + mtl_path.split('/')[-1]) # reference the MTL file
|
4835
|
+
for i in range(len(topologies)):
|
4836
|
+
d = Topology.Dictionary(topologies[i])
|
4837
|
+
name = Dictionary.ValueAtKey(d, nameKey) or "Untitled_"+str(i).zfill(n)
|
4838
|
+
name = name.replace(" ", "_")
|
4839
|
+
obj_file.writelines("\ng "+name+"\n")
|
4840
|
+
result = Topology.OBJString(topologies[i], "color_" + str(i).zfill(n), vertex_index, transposeAxes=transposeAxes, mode=mode,
|
4841
|
+
meshSize=meshSize,
|
4842
|
+
mantissa=mantissa, tolerance=tolerance)
|
4843
|
+
|
4844
|
+
obj_file.writelines(result[0])
|
4845
|
+
vertex_index += result[1]
|
4846
|
+
obj_file.close()
|
4642
4847
|
status = True
|
4643
4848
|
return status
|
4644
4849
|
|
@@ -4779,25 +4984,6 @@ class Topology():
|
|
4779
4984
|
"""
|
4780
4985
|
from topologicpy.Vertex import Vertex
|
4781
4986
|
from topologicpy.Face import Face
|
4782
|
-
from topologicpy.Vector import Vector
|
4783
|
-
|
4784
|
-
def getSubTopologies(topology, subTopologyClass):
|
4785
|
-
topologies = []
|
4786
|
-
if subTopologyClass == topologic.Vertex:
|
4787
|
-
_ = topology.Vertices(None, topologies)
|
4788
|
-
elif subTopologyClass == topologic.Edge:
|
4789
|
-
_ = topology.Edges(None, topologies)
|
4790
|
-
elif subTopologyClass == topologic.Wire:
|
4791
|
-
_ = topology.Wires(None, topologies)
|
4792
|
-
elif subTopologyClass == topologic.Face:
|
4793
|
-
_ = topology.Faces(None, topologies)
|
4794
|
-
elif subTopologyClass == topologic.Shell:
|
4795
|
-
_ = topology.Shells(None, topologies)
|
4796
|
-
elif subTopologyClass == topologic.Cell:
|
4797
|
-
_ = topology.Cells(None, topologies)
|
4798
|
-
elif subTopologyClass == topologic.CellComplex:
|
4799
|
-
_ = topology.CellComplexes(None, topologies)
|
4800
|
-
return topologies
|
4801
4987
|
|
4802
4988
|
vertices = []
|
4803
4989
|
edges = []
|
@@ -4850,7 +5036,7 @@ class Topology():
|
|
4850
5036
|
triFaces = Face.Triangulate(aFace)
|
4851
5037
|
for aTriFace in triFaces:
|
4852
5038
|
wire = Face.ExternalBoundary(aTriFace)
|
4853
|
-
faceVertices =
|
5039
|
+
faceVertices = Topology.Vertices(wire)
|
4854
5040
|
f = []
|
4855
5041
|
for aVertex in faceVertices:
|
4856
5042
|
try:
|
@@ -4862,7 +5048,7 @@ class Topology():
|
|
4862
5048
|
faces.append(f)
|
4863
5049
|
else:
|
4864
5050
|
wire = Face.ExternalBoundary(aFace)
|
4865
|
-
faceVertices =
|
5051
|
+
faceVertices = Topology.Vertices(wire)
|
4866
5052
|
f = []
|
4867
5053
|
for aVertex in faceVertices:
|
4868
5054
|
try:
|
@@ -5121,7 +5307,6 @@ class Topology():
|
|
5121
5307
|
The resulting merged Topology
|
5122
5308
|
|
5123
5309
|
"""
|
5124
|
-
|
5125
5310
|
from topologicpy.Cluster import Cluster
|
5126
5311
|
|
5127
5312
|
if not isinstance(topologies, list):
|
@@ -5207,6 +5392,7 @@ class Topology():
|
|
5207
5392
|
The input topology.
|
5208
5393
|
tolerance : float , optional
|
5209
5394
|
The desired tolerance. The default is 0.0001.
|
5395
|
+
|
5210
5396
|
Returns
|
5211
5397
|
-------
|
5212
5398
|
list
|
@@ -6302,7 +6488,6 @@ class Topology():
|
|
6302
6488
|
A dictionary with the list of vertices, edges, wires, and faces. The keys are "vertices", "edges", "wires", and "faces".
|
6303
6489
|
|
6304
6490
|
"""
|
6305
|
-
|
6306
6491
|
if not Topology.IsInstance(topologyA, "Topology"):
|
6307
6492
|
print("Topology.SharedTopologies - Error: the input topologyA parameter is not a valid topology. Returning None.")
|
6308
6493
|
return None
|
@@ -6429,9 +6614,10 @@ class Topology():
|
|
6429
6614
|
l = None
|
6430
6615
|
return l
|
6431
6616
|
|
6432
|
-
|
6433
6617
|
@staticmethod
|
6434
6618
|
def Show(*topologies,
|
6619
|
+
colorKey = "color",
|
6620
|
+
opacityKey = "opacity",
|
6435
6621
|
showVertices=True, vertexSize=1.1, vertexColor="black",
|
6436
6622
|
vertexLabelKey=None, vertexGroupKey=None, vertexGroups=[],
|
6437
6623
|
vertexMinGroup=None, vertexMaxGroup=None,
|
@@ -6466,7 +6652,10 @@ class Topology():
|
|
6466
6652
|
----------
|
6467
6653
|
topologies : topologic_core.Topology or list
|
6468
6654
|
The input topology. This must contain faces and or edges. If the input is a list, a cluster is first created
|
6469
|
-
|
6655
|
+
colorKey : str , optional
|
6656
|
+
The key under which to find the color of the topology. The default is "color".
|
6657
|
+
opacityKey : str , optional
|
6658
|
+
The key under which to find the opacity of the topology. The default is "opacity".
|
6470
6659
|
showVertices : bool , optional
|
6471
6660
|
If set to True the vertices will be drawn. Otherwise, they will not be drawn. The default is True.
|
6472
6661
|
vertexSize : float , optional
|
@@ -6630,10 +6819,11 @@ class Topology():
|
|
6630
6819
|
|
6631
6820
|
"""
|
6632
6821
|
|
6633
|
-
from topologicpy.
|
6822
|
+
from topologicpy.Dictionary import Dictionary
|
6634
6823
|
from topologicpy.Plotly import Plotly
|
6635
6824
|
from topologicpy.Helper import Helper
|
6636
6825
|
from topologicpy.Graph import Graph
|
6826
|
+
from topologicpy.Color import Color
|
6637
6827
|
|
6638
6828
|
if isinstance(topologies, tuple):
|
6639
6829
|
topologies = Helper.Flatten(list(topologies))
|
@@ -6644,30 +6834,38 @@ class Topology():
|
|
6644
6834
|
if len(new_topologies) == 0:
|
6645
6835
|
print("Topology.Show - Error: the input topologies parameter does not contain any valid topology. Returning None.")
|
6646
6836
|
return None
|
6647
|
-
if len(new_topologies) == 1:
|
6648
|
-
|
6649
|
-
else:
|
6650
|
-
|
6651
|
-
if not Topology.IsInstance(topology, "Topology"):
|
6652
|
-
|
6653
|
-
|
6654
|
-
data =
|
6655
|
-
|
6656
|
-
|
6657
|
-
|
6658
|
-
|
6659
|
-
|
6660
|
-
|
6661
|
-
|
6662
|
-
|
6663
|
-
|
6664
|
-
|
6665
|
-
|
6666
|
-
|
6667
|
-
|
6668
|
-
|
6669
|
-
|
6670
|
-
|
6837
|
+
# if len(new_topologies) == 1:
|
6838
|
+
# topology = new_topologies[0]
|
6839
|
+
# else:
|
6840
|
+
# topology = Cluster.ByTopologies(new_topologies)
|
6841
|
+
# if not Topology.IsInstance(topology, "Topology"):
|
6842
|
+
# print("Topology.Show - Error: the input topology parameter is not a valid topology. Returning None.")
|
6843
|
+
# return None
|
6844
|
+
data = []
|
6845
|
+
for topology in new_topologies:
|
6846
|
+
d = Topology.Dictionary(topology)
|
6847
|
+
if isinstance(colorKey, str):
|
6848
|
+
f_color = Dictionary.ValueAtKey(d, colorKey)
|
6849
|
+
if f_color:
|
6850
|
+
faceColor = Color.PlotlyColor(f_color, alpha=1.0, useAlpha=False)
|
6851
|
+
faceOpacity = Dictionary.ValueAtKey(d, opacityKey) or faceOpacity
|
6852
|
+
data += Plotly.DataByTopology(topology=topology,
|
6853
|
+
showVertices=showVertices, vertexSize=vertexSize, vertexColor=vertexColor,
|
6854
|
+
vertexLabelKey=vertexLabelKey, vertexGroupKey=vertexGroupKey, vertexGroups=vertexGroups,
|
6855
|
+
vertexMinGroup=vertexMinGroup, vertexMaxGroup=vertexMaxGroup,
|
6856
|
+
showVertexLegend=showVertexLegend, vertexLegendLabel=vertexLegendLabel, vertexLegendRank=vertexLegendRank,
|
6857
|
+
vertexLegendGroup=vertexLegendGroup,
|
6858
|
+
showEdges=showEdges, edgeWidth=edgeWidth, edgeColor=edgeColor,
|
6859
|
+
edgeLabelKey=edgeLabelKey, edgeGroupKey=edgeGroupKey, edgeGroups=edgeGroups,
|
6860
|
+
edgeMinGroup=edgeMinGroup, edgeMaxGroup=edgeMaxGroup,
|
6861
|
+
showEdgeLegend=showEdgeLegend, edgeLegendLabel=edgeLegendLabel, edgeLegendRank=edgeLegendRank,
|
6862
|
+
edgeLegendGroup=edgeLegendGroup,
|
6863
|
+
showFaces=showFaces, faceOpacity=faceOpacity, faceColor=faceColor,
|
6864
|
+
faceLabelKey=faceLabelKey, faceGroupKey=faceGroupKey, faceGroups=faceGroups,
|
6865
|
+
faceMinGroup=faceMinGroup, faceMaxGroup=faceMaxGroup,
|
6866
|
+
showFaceLegend=showFaceLegend, faceLegendLabel=faceLegendLabel, faceLegendRank=faceLegendRank,
|
6867
|
+
faceLegendGroup=faceLegendGroup,
|
6868
|
+
intensityKey=intensityKey, intensities=intensities, colorScale=colorScale, mantissa=mantissa, tolerance=tolerance)
|
6671
6869
|
figure = Plotly.FigureByData(data=data, width=width, height=height,
|
6672
6870
|
xAxis=xAxis, yAxis=yAxis, zAxis=zAxis, axisSize=axisSize,
|
6673
6871
|
backgroundColor=backgroundColor,
|
@@ -6700,8 +6898,8 @@ class Topology():
|
|
6700
6898
|
A dictionary containing the list of sorted and unsorted topologies. The keys are "sorted" and "unsorted".
|
6701
6899
|
|
6702
6900
|
"""
|
6703
|
-
|
6704
6901
|
from topologicpy.Vertex import Vertex
|
6902
|
+
|
6705
6903
|
usedTopologies = []
|
6706
6904
|
sortedTopologies = []
|
6707
6905
|
unsortedTopologies = []
|
@@ -6925,6 +7123,7 @@ class Topology():
|
|
6925
7123
|
|
6926
7124
|
"""
|
6927
7125
|
from topologicpy.Vertex import Vertex
|
7126
|
+
|
6928
7127
|
ratioRange = [min(1,ratioRange[0]), min(1,ratioRange[1])]
|
6929
7128
|
if ratioRange == [0, 0]:
|
6930
7129
|
return topology
|
@@ -7263,7 +7462,6 @@ class Topology():
|
|
7263
7462
|
The list of supertopologies connected to the input topology.
|
7264
7463
|
|
7265
7464
|
"""
|
7266
|
-
|
7267
7465
|
if not Topology.IsInstance(topology, "Topology"):
|
7268
7466
|
print("Topology.SuperTopologies - Error: the input topology parameter is not a valid topology. Returning None.")
|
7269
7467
|
return None
|
@@ -7394,7 +7592,6 @@ class Topology():
|
|
7394
7592
|
The input topology with the dictionaries transferred to its subtopologies.
|
7395
7593
|
|
7396
7594
|
"""
|
7397
|
-
|
7398
7595
|
if not Topology.IsInstance(topology, "Topology"):
|
7399
7596
|
print("Topology.TransferDictionariesBySelectors - Error: The input topology parameter is not a valid topology. Returning None.")
|
7400
7597
|
return None
|
@@ -7664,9 +7861,6 @@ class Topology():
|
|
7664
7861
|
The type of the input topology.
|
7665
7862
|
|
7666
7863
|
"""
|
7667
|
-
#if not Topology.IsInstance(topology, "Topology"):
|
7668
|
-
#print("Topology.Type - Error: The input topology parameter is not a valid topology. Returning None.")
|
7669
|
-
#return None
|
7670
7864
|
return topology.Type()
|
7671
7865
|
|
7672
7866
|
@staticmethod
|
@@ -7721,7 +7915,6 @@ class Topology():
|
|
7721
7915
|
The type id of the input topologyType string.
|
7722
7916
|
|
7723
7917
|
"""
|
7724
|
-
|
7725
7918
|
if not isinstance(name, str):
|
7726
7919
|
print("Topology.TypeID - Error: The input topologyType parameter is not a valid string. Returning None.")
|
7727
7920
|
return None
|