topologicpy 0.7.21__py3-none-any.whl → 0.7.23__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 +380 -180
- 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.23.dist-info}/METADATA +1 -1
- topologicpy-0.7.23.dist-info/RECORD +34 -0
- {topologicpy-0.7.21.dist-info → topologicpy-0.7.23.dist-info}/WHEEL +1 -1
- topologicpy-0.7.21.dist-info/RECORD +0 -34
- {topologicpy-0.7.21.dist-info → topologicpy-0.7.23.dist-info}/LICENSE +0 -0
- {topologicpy-0.7.21.dist-info → topologicpy-0.7.23.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,303 @@ 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 specified in the file. The default is [255, 255, 255] (white).
|
2781
|
+
defaultOpacity : float , optional
|
2782
|
+
The default opacity to use if none is specified 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 specified in the string. The default is [255, 255, 255] (white).
|
2845
|
+
defaultOpacity : float , optional
|
2846
|
+
The default opacity to use if none is specified 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
|
+
groups = obj_data['groups']
|
2959
|
+
vertices = obj_data['vertices']
|
2960
|
+
groups = obj_data['groups']
|
2961
|
+
materials = obj_data['materials']
|
2962
|
+
names = list(groups.keys())
|
2963
|
+
return_topologies = []
|
2964
|
+
for i in range(len(names)):
|
2965
|
+
object_faces = []
|
2966
|
+
face_selectors = []
|
2967
|
+
object_name = names[i]
|
2968
|
+
faces = groups[object_name]
|
2969
|
+
f = faces[0] # Get object material from first face. Assume it is the material of the group
|
2970
|
+
object_color = defaultColor
|
2971
|
+
object_opacity = defaultOpacity
|
2972
|
+
object_material = None
|
2973
|
+
if len(f) >= 2:
|
2974
|
+
object_material = f[1]
|
2975
|
+
if object_material in materials.keys():
|
2976
|
+
object_color = materials[object_material]['Kd']
|
2977
|
+
object_color = [int(round(c*255,0)) for c in object_color]
|
2978
|
+
object_opacity = materials[object_material]['d']
|
2979
|
+
for f in faces:
|
2980
|
+
indices = f[0]
|
2981
|
+
face_material = f[1]
|
2982
|
+
face_indices = []
|
2983
|
+
for coordinate in indices:
|
2984
|
+
face_indices.append(coordinate[0])
|
2985
|
+
face = Topology.ByGeometry(vertices=vertices, faces=[face_indices])
|
2986
|
+
object_faces.append(face)
|
2987
|
+
if not face_material == object_material:
|
2988
|
+
if face_material in materials.keys():
|
2989
|
+
face_color = materials[face_material]['Kd']
|
2990
|
+
face_color = [int(round(c*255,0)) for c in face_color]
|
2991
|
+
face_opacity = materials[face_material]['d']
|
2992
|
+
selector = Face.InternalVertex(face)
|
2993
|
+
d = Dictionary.ByKeysValues(['color', 'opacity'], [face_color, face_opacity])
|
2994
|
+
selector = Topology.SetDictionary(selector, d)
|
2995
|
+
face_selectors.append(selector)
|
2996
|
+
|
2997
|
+
topology = Topology.SelfMerge(Cluster.ByTopologies(object_faces), tolerance=tolerance)
|
2998
|
+
if removeCoplanarFaces:
|
2999
|
+
topology = Topology.RemoveCoplanarFaces(topology, tolerance=tolerance)
|
3000
|
+
d = Dictionary.ByKeysValues(['name', 'color', 'opacity'], [object_name, object_color, object_opacity])
|
3001
|
+
topology = Topology.SetDictionary(topology, d)
|
3002
|
+
if len(face_selectors) > 0:
|
3003
|
+
topology = Topology.TransferDictionariesBySelectors(topology, selectors=face_selectors, tranFaces=True, tolerance=tolerance)
|
3004
|
+
return_topologies.append(topology)
|
3005
|
+
return return_topologies
|
2844
3006
|
|
2845
3007
|
@staticmethod
|
2846
3008
|
def ByOCCTShape(occtShape):
|
@@ -3854,7 +4016,6 @@ class Topology():
|
|
3854
4016
|
return True
|
3855
4017
|
return False
|
3856
4018
|
|
3857
|
-
|
3858
4019
|
def ExportToDXF(topologies, path: str, overwrite: bool = False, mantissa: int = 6):
|
3859
4020
|
"""
|
3860
4021
|
Exports the input topology to a DXF file. See https://en.wikipedia.org/wiki/AutoCAD_DXF.
|
@@ -4373,7 +4534,6 @@ class Topology():
|
|
4373
4534
|
returnDict['dictionary'] = Dictionary.PythonDictionary(Topology.Dictionary(topology))
|
4374
4535
|
return returnDict
|
4375
4536
|
|
4376
|
-
|
4377
4537
|
def getApertureData(topology, topLevel="False", uuidKey="uuid"):
|
4378
4538
|
json_data = []
|
4379
4539
|
if Topology.IsInstance(topology, "Vertex"):
|
@@ -4512,7 +4672,7 @@ class Topology():
|
|
4512
4672
|
return json_string
|
4513
4673
|
|
4514
4674
|
@staticmethod
|
4515
|
-
def OBJString(topology, transposeAxes: bool = True, mode: int = 0, meshSize: float = None, mantissa: int = 6, tolerance: float = 0.0001):
|
4675
|
+
def OBJString(topology, color, vertexIndex, transposeAxes: bool = True, mode: int = 0, meshSize: float = None, mantissa: int = 6, tolerance: float = 0.0001):
|
4516
4676
|
"""
|
4517
4677
|
Returns the Wavefront string of the input topology. This is very experimental and outputs a simple solid topology.
|
4518
4678
|
|
@@ -4520,6 +4680,10 @@ class Topology():
|
|
4520
4680
|
----------
|
4521
4681
|
topology : topologic_core.Topology
|
4522
4682
|
The input topology.
|
4683
|
+
color : list
|
4684
|
+
The desired color to assign to the topology
|
4685
|
+
vertexIndex : int
|
4686
|
+
The vertex index to use as the starting index.
|
4523
4687
|
transposeAxes : bool , optional
|
4524
4688
|
If set to True the Z and Y coordinates are transposed so that Y points "up"
|
4525
4689
|
mode : int , optional
|
@@ -4548,17 +4712,16 @@ class Topology():
|
|
4548
4712
|
The Wavefront OBJ string of the input topology
|
4549
4713
|
|
4550
4714
|
"""
|
4715
|
+
|
4551
4716
|
from topologicpy.Helper import Helper
|
4552
|
-
from topologicpy.Vertex import Vertex
|
4553
|
-
from topologicpy.Face import Face
|
4554
4717
|
|
4555
4718
|
if not Topology.IsInstance(topology, "Topology"):
|
4556
4719
|
print("Topology.ExportToOBJ - Error: the input topology parameter is not a valid topology. Returning None.")
|
4557
4720
|
return None
|
4558
|
-
|
4721
|
+
|
4559
4722
|
lines = []
|
4560
|
-
version = Helper.Version()
|
4561
|
-
lines.append("# topologicpy "+version)
|
4723
|
+
#version = Helper.Version()
|
4724
|
+
#lines.append("# topologicpy " + version)
|
4562
4725
|
topology = Topology.Triangulate(topology, mode=mode, meshSize=meshSize, tolerance=tolerance)
|
4563
4726
|
d = Topology.Geometry(topology, mantissa=mantissa)
|
4564
4727
|
vertices = d['vertices']
|
@@ -4569,32 +4732,42 @@ class Topology():
|
|
4569
4732
|
tVertices.append([v[0], v[2], v[1]])
|
4570
4733
|
vertices = tVertices
|
4571
4734
|
for v in vertices:
|
4572
|
-
lines.append("v "+str(v[0])+" "+str(v[1])+" "+str(v[2]))
|
4735
|
+
lines.append("v " + str(v[0]) + " " + str(v[1]) + " " + str(v[2]))
|
4573
4736
|
for f in faces:
|
4574
|
-
line = "
|
4737
|
+
line = "usemtl " + str(color) + "\nf" # reference the material name
|
4575
4738
|
for j in f:
|
4576
|
-
line = line+" "+str(j+
|
4739
|
+
line = line + " " + str(j + vertexIndex)
|
4577
4740
|
lines.append(line)
|
4578
4741
|
finalLines = lines[0]
|
4579
|
-
for i in range(1,len(lines)):
|
4580
|
-
finalLines = finalLines+"\n"+lines[i]
|
4581
|
-
return finalLines
|
4742
|
+
for i in range(1, len(lines)):
|
4743
|
+
finalLines = finalLines + "\n" + lines[i]
|
4744
|
+
return finalLines, len(vertices)
|
4582
4745
|
|
4583
4746
|
@staticmethod
|
4584
|
-
def ExportToOBJ(
|
4747
|
+
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
4748
|
"""
|
4586
4749
|
Exports the input topology to a Wavefront OBJ file. This is very experimental and outputs a simple solid topology.
|
4587
4750
|
|
4588
4751
|
Parameters
|
4589
4752
|
----------
|
4590
|
-
|
4591
|
-
The input
|
4753
|
+
topologies : list or comma separated topologies
|
4754
|
+
The input list of topologies.
|
4592
4755
|
path : str
|
4593
4756
|
The input file path.
|
4757
|
+
nameKey : str , optional
|
4758
|
+
The topology dictionary key under which to find the name of the topology. The default is "name".
|
4759
|
+
colorKey : str, optional
|
4760
|
+
The topology dictionary key under which to find the color of the topology. The default is "color".
|
4761
|
+
opacityKey : str , optional
|
4762
|
+
The topology dictionary key under which to find the opacity of the topology. The default is "opacity".
|
4763
|
+
defaultColor : list , optional
|
4764
|
+
The default color to use if no color is stored in the topology dictionary. The default is [255,255, 255] (white).
|
4765
|
+
defaultOpacity : float , optional
|
4766
|
+
The default opacity to use of no opacity is stored in the topology dictionary. This must be between 0 and 1. The default is 1 (fully opaque).
|
4594
4767
|
transposeAxes : bool , optional
|
4595
4768
|
If set to True the Z and Y coordinates are transposed so that Y points "up"
|
4596
4769
|
mode : int , optional
|
4597
|
-
The desired mode of meshing algorithm. Several options are available:
|
4770
|
+
The desired mode of meshing algorithm (for triangulation). Several options are available:
|
4598
4771
|
0: Classic
|
4599
4772
|
1: MeshAdapt
|
4600
4773
|
3: Initial Mesh Only
|
@@ -4621,11 +4794,21 @@ class Topology():
|
|
4621
4794
|
True if the export operation is successful. False otherwise.
|
4622
4795
|
|
4623
4796
|
"""
|
4797
|
+
from topologicpy.Helper import Helper
|
4798
|
+
from topologicpy.Dictionary import Dictionary
|
4624
4799
|
from os.path import exists
|
4625
4800
|
|
4626
|
-
if
|
4627
|
-
|
4801
|
+
if isinstance(topologies, tuple):
|
4802
|
+
topologies = Helper.Flatten(list(topologies))
|
4803
|
+
if isinstance(topologies, list):
|
4804
|
+
new_topologies = [d for d in topologies if Topology.IsInstance(d, "Topology")]
|
4805
|
+
if len(new_topologies) == 0:
|
4806
|
+
print("Topology.ExportToOBJ - Error: the input topologies parameter does not contain any valid topologies. Returning None.")
|
4628
4807
|
return None
|
4808
|
+
if not isinstance(new_topologies, list):
|
4809
|
+
print("Dictionary.ByMergedDictionaries - Error: The input dictionaries parameter is not a valid list. Returning None.")
|
4810
|
+
return None
|
4811
|
+
|
4629
4812
|
if not overwrite and exists(path):
|
4630
4813
|
print("Topology.ExportToOBJ - Error: a file already exists at the specified path and overwrite is set to False. Returning None.")
|
4631
4814
|
return None
|
@@ -4635,10 +4818,39 @@ class Topology():
|
|
4635
4818
|
if ext.lower() != ".obj":
|
4636
4819
|
path = path+".obj"
|
4637
4820
|
status = False
|
4638
|
-
|
4639
|
-
|
4640
|
-
|
4641
|
-
|
4821
|
+
|
4822
|
+
mtl_path = path[:-4] + ".mtl"
|
4823
|
+
|
4824
|
+
# Write out the material file
|
4825
|
+
n = max(len(str(len(topologies))), 3)
|
4826
|
+
with open(mtl_path, "w") as mtl_file:
|
4827
|
+
for i in range(len(new_topologies)):
|
4828
|
+
d = Topology.Dictionary(new_topologies[i])
|
4829
|
+
name = Dictionary.ValueAtKey(d, nameKey) or "Untitled_"+str(i).zfill(n)
|
4830
|
+
color = Dictionary.ValueAtKey(d, colorKey) or defaultColor
|
4831
|
+
color = [c/255 for c in color]
|
4832
|
+
opacity = Dictionary.ValueAtKey(d, opacityKey) or defaultOpacity
|
4833
|
+
mtl_file.write("newmtl color_" + str(i).zfill(n) + "\n")
|
4834
|
+
mtl_file.write("Kd " + ' '.join(map(str, color)) + "\n")
|
4835
|
+
mtl_file.write("d " + str(opacity) + "\n")
|
4836
|
+
|
4837
|
+
# Write out the obj file
|
4838
|
+
with open(path, "w") as obj_file:
|
4839
|
+
vertex_index = 1 # global vertex index counter
|
4840
|
+
obj_file.writelines("# topologicpy "+Helper.Version()+"\n")
|
4841
|
+
obj_file.writelines("mtllib " + mtl_path.split('/')[-1]) # reference the MTL file
|
4842
|
+
for i in range(len(topologies)):
|
4843
|
+
d = Topology.Dictionary(topologies[i])
|
4844
|
+
name = Dictionary.ValueAtKey(d, nameKey) or "Untitled_"+str(i).zfill(n)
|
4845
|
+
name = name.replace(" ", "_")
|
4846
|
+
obj_file.writelines("\ng "+name+"\n")
|
4847
|
+
result = Topology.OBJString(topologies[i], "color_" + str(i).zfill(n), vertex_index, transposeAxes=transposeAxes, mode=mode,
|
4848
|
+
meshSize=meshSize,
|
4849
|
+
mantissa=mantissa, tolerance=tolerance)
|
4850
|
+
|
4851
|
+
obj_file.writelines(result[0])
|
4852
|
+
vertex_index += result[1]
|
4853
|
+
obj_file.close()
|
4642
4854
|
status = True
|
4643
4855
|
return status
|
4644
4856
|
|
@@ -4779,25 +4991,6 @@ class Topology():
|
|
4779
4991
|
"""
|
4780
4992
|
from topologicpy.Vertex import Vertex
|
4781
4993
|
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
4994
|
|
4802
4995
|
vertices = []
|
4803
4996
|
edges = []
|
@@ -4850,7 +5043,7 @@ class Topology():
|
|
4850
5043
|
triFaces = Face.Triangulate(aFace)
|
4851
5044
|
for aTriFace in triFaces:
|
4852
5045
|
wire = Face.ExternalBoundary(aTriFace)
|
4853
|
-
faceVertices =
|
5046
|
+
faceVertices = Topology.Vertices(wire)
|
4854
5047
|
f = []
|
4855
5048
|
for aVertex in faceVertices:
|
4856
5049
|
try:
|
@@ -4862,7 +5055,7 @@ class Topology():
|
|
4862
5055
|
faces.append(f)
|
4863
5056
|
else:
|
4864
5057
|
wire = Face.ExternalBoundary(aFace)
|
4865
|
-
faceVertices =
|
5058
|
+
faceVertices = Topology.Vertices(wire)
|
4866
5059
|
f = []
|
4867
5060
|
for aVertex in faceVertices:
|
4868
5061
|
try:
|
@@ -5121,7 +5314,6 @@ class Topology():
|
|
5121
5314
|
The resulting merged Topology
|
5122
5315
|
|
5123
5316
|
"""
|
5124
|
-
|
5125
5317
|
from topologicpy.Cluster import Cluster
|
5126
5318
|
|
5127
5319
|
if not isinstance(topologies, list):
|
@@ -5207,6 +5399,7 @@ class Topology():
|
|
5207
5399
|
The input topology.
|
5208
5400
|
tolerance : float , optional
|
5209
5401
|
The desired tolerance. The default is 0.0001.
|
5402
|
+
|
5210
5403
|
Returns
|
5211
5404
|
-------
|
5212
5405
|
list
|
@@ -6302,7 +6495,6 @@ class Topology():
|
|
6302
6495
|
A dictionary with the list of vertices, edges, wires, and faces. The keys are "vertices", "edges", "wires", and "faces".
|
6303
6496
|
|
6304
6497
|
"""
|
6305
|
-
|
6306
6498
|
if not Topology.IsInstance(topologyA, "Topology"):
|
6307
6499
|
print("Topology.SharedTopologies - Error: the input topologyA parameter is not a valid topology. Returning None.")
|
6308
6500
|
return None
|
@@ -6429,9 +6621,10 @@ class Topology():
|
|
6429
6621
|
l = None
|
6430
6622
|
return l
|
6431
6623
|
|
6432
|
-
|
6433
6624
|
@staticmethod
|
6434
6625
|
def Show(*topologies,
|
6626
|
+
colorKey = "color",
|
6627
|
+
opacityKey = "opacity",
|
6435
6628
|
showVertices=True, vertexSize=1.1, vertexColor="black",
|
6436
6629
|
vertexLabelKey=None, vertexGroupKey=None, vertexGroups=[],
|
6437
6630
|
vertexMinGroup=None, vertexMaxGroup=None,
|
@@ -6466,7 +6659,10 @@ class Topology():
|
|
6466
6659
|
----------
|
6467
6660
|
topologies : topologic_core.Topology or list
|
6468
6661
|
The input topology. This must contain faces and or edges. If the input is a list, a cluster is first created
|
6469
|
-
|
6662
|
+
colorKey : str , optional
|
6663
|
+
The key under which to find the color of the topology. The default is "color".
|
6664
|
+
opacityKey : str , optional
|
6665
|
+
The key under which to find the opacity of the topology. The default is "opacity".
|
6470
6666
|
showVertices : bool , optional
|
6471
6667
|
If set to True the vertices will be drawn. Otherwise, they will not be drawn. The default is True.
|
6472
6668
|
vertexSize : float , optional
|
@@ -6630,10 +6826,11 @@ class Topology():
|
|
6630
6826
|
|
6631
6827
|
"""
|
6632
6828
|
|
6633
|
-
from topologicpy.
|
6829
|
+
from topologicpy.Dictionary import Dictionary
|
6634
6830
|
from topologicpy.Plotly import Plotly
|
6635
6831
|
from topologicpy.Helper import Helper
|
6636
6832
|
from topologicpy.Graph import Graph
|
6833
|
+
from topologicpy.Color import Color
|
6637
6834
|
|
6638
6835
|
if isinstance(topologies, tuple):
|
6639
6836
|
topologies = Helper.Flatten(list(topologies))
|
@@ -6644,30 +6841,38 @@ class Topology():
|
|
6644
6841
|
if len(new_topologies) == 0:
|
6645
6842
|
print("Topology.Show - Error: the input topologies parameter does not contain any valid topology. Returning None.")
|
6646
6843
|
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
|
-
|
6844
|
+
# if len(new_topologies) == 1:
|
6845
|
+
# topology = new_topologies[0]
|
6846
|
+
# else:
|
6847
|
+
# topology = Cluster.ByTopologies(new_topologies)
|
6848
|
+
# if not Topology.IsInstance(topology, "Topology"):
|
6849
|
+
# print("Topology.Show - Error: the input topology parameter is not a valid topology. Returning None.")
|
6850
|
+
# return None
|
6851
|
+
data = []
|
6852
|
+
for topology in new_topologies:
|
6853
|
+
d = Topology.Dictionary(topology)
|
6854
|
+
if isinstance(colorKey, str):
|
6855
|
+
f_color = Dictionary.ValueAtKey(d, colorKey)
|
6856
|
+
if f_color:
|
6857
|
+
faceColor = Color.PlotlyColor(f_color, alpha=1.0, useAlpha=False)
|
6858
|
+
faceOpacity = Dictionary.ValueAtKey(d, opacityKey) or faceOpacity
|
6859
|
+
data += Plotly.DataByTopology(topology=topology,
|
6860
|
+
showVertices=showVertices, vertexSize=vertexSize, vertexColor=vertexColor,
|
6861
|
+
vertexLabelKey=vertexLabelKey, vertexGroupKey=vertexGroupKey, vertexGroups=vertexGroups,
|
6862
|
+
vertexMinGroup=vertexMinGroup, vertexMaxGroup=vertexMaxGroup,
|
6863
|
+
showVertexLegend=showVertexLegend, vertexLegendLabel=vertexLegendLabel, vertexLegendRank=vertexLegendRank,
|
6864
|
+
vertexLegendGroup=vertexLegendGroup,
|
6865
|
+
showEdges=showEdges, edgeWidth=edgeWidth, edgeColor=edgeColor,
|
6866
|
+
edgeLabelKey=edgeLabelKey, edgeGroupKey=edgeGroupKey, edgeGroups=edgeGroups,
|
6867
|
+
edgeMinGroup=edgeMinGroup, edgeMaxGroup=edgeMaxGroup,
|
6868
|
+
showEdgeLegend=showEdgeLegend, edgeLegendLabel=edgeLegendLabel, edgeLegendRank=edgeLegendRank,
|
6869
|
+
edgeLegendGroup=edgeLegendGroup,
|
6870
|
+
showFaces=showFaces, faceOpacity=faceOpacity, faceColor=faceColor,
|
6871
|
+
faceLabelKey=faceLabelKey, faceGroupKey=faceGroupKey, faceGroups=faceGroups,
|
6872
|
+
faceMinGroup=faceMinGroup, faceMaxGroup=faceMaxGroup,
|
6873
|
+
showFaceLegend=showFaceLegend, faceLegendLabel=faceLegendLabel, faceLegendRank=faceLegendRank,
|
6874
|
+
faceLegendGroup=faceLegendGroup,
|
6875
|
+
intensityKey=intensityKey, intensities=intensities, colorScale=colorScale, mantissa=mantissa, tolerance=tolerance)
|
6671
6876
|
figure = Plotly.FigureByData(data=data, width=width, height=height,
|
6672
6877
|
xAxis=xAxis, yAxis=yAxis, zAxis=zAxis, axisSize=axisSize,
|
6673
6878
|
backgroundColor=backgroundColor,
|
@@ -6700,8 +6905,8 @@ class Topology():
|
|
6700
6905
|
A dictionary containing the list of sorted and unsorted topologies. The keys are "sorted" and "unsorted".
|
6701
6906
|
|
6702
6907
|
"""
|
6703
|
-
|
6704
6908
|
from topologicpy.Vertex import Vertex
|
6909
|
+
|
6705
6910
|
usedTopologies = []
|
6706
6911
|
sortedTopologies = []
|
6707
6912
|
unsortedTopologies = []
|
@@ -6925,6 +7130,7 @@ class Topology():
|
|
6925
7130
|
|
6926
7131
|
"""
|
6927
7132
|
from topologicpy.Vertex import Vertex
|
7133
|
+
|
6928
7134
|
ratioRange = [min(1,ratioRange[0]), min(1,ratioRange[1])]
|
6929
7135
|
if ratioRange == [0, 0]:
|
6930
7136
|
return topology
|
@@ -7263,7 +7469,6 @@ class Topology():
|
|
7263
7469
|
The list of supertopologies connected to the input topology.
|
7264
7470
|
|
7265
7471
|
"""
|
7266
|
-
|
7267
7472
|
if not Topology.IsInstance(topology, "Topology"):
|
7268
7473
|
print("Topology.SuperTopologies - Error: the input topology parameter is not a valid topology. Returning None.")
|
7269
7474
|
return None
|
@@ -7394,7 +7599,6 @@ class Topology():
|
|
7394
7599
|
The input topology with the dictionaries transferred to its subtopologies.
|
7395
7600
|
|
7396
7601
|
"""
|
7397
|
-
|
7398
7602
|
if not Topology.IsInstance(topology, "Topology"):
|
7399
7603
|
print("Topology.TransferDictionariesBySelectors - Error: The input topology parameter is not a valid topology. Returning None.")
|
7400
7604
|
return None
|
@@ -7664,9 +7868,6 @@ class Topology():
|
|
7664
7868
|
The type of the input topology.
|
7665
7869
|
|
7666
7870
|
"""
|
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
7871
|
return topology.Type()
|
7671
7872
|
|
7672
7873
|
@staticmethod
|
@@ -7721,7 +7922,6 @@ class Topology():
|
|
7721
7922
|
The type id of the input topologyType string.
|
7722
7923
|
|
7723
7924
|
"""
|
7724
|
-
|
7725
7925
|
if not isinstance(name, str):
|
7726
7926
|
print("Topology.TypeID - Error: The input topologyType parameter is not a valid string. Returning None.")
|
7727
7927
|
return None
|