topologicpy 0.7.12__py3-none-any.whl → 0.7.14__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/Cell.py +16 -14
- topologicpy/CellComplex.py +24 -1
- topologicpy/Edge.py +205 -95
- topologicpy/Face.py +43 -15
- topologicpy/Grid.py +1 -1
- topologicpy/Polyskel.py +157 -12
- topologicpy/Shell.py +3 -4
- topologicpy/Sun.py +6 -6
- topologicpy/Topology.py +632 -8
- topologicpy/Vector.py +109 -2
- topologicpy/Vertex.py +28 -3
- topologicpy/Wire.py +46 -18
- topologicpy/version.py +1 -1
- {topologicpy-0.7.12.dist-info → topologicpy-0.7.14.dist-info}/METADATA +1 -1
- topologicpy-0.7.14.dist-info/RECORD +33 -0
- topologicpy-0.7.12.dist-info/RECORD +0 -33
- {topologicpy-0.7.12.dist-info → topologicpy-0.7.14.dist-info}/LICENSE +0 -0
- {topologicpy-0.7.12.dist-info → topologicpy-0.7.14.dist-info}/WHEEL +0 -0
- {topologicpy-0.7.12.dist-info → topologicpy-0.7.14.dist-info}/top_level.txt +0 -0
topologicpy/Topology.py
CHANGED
@@ -855,6 +855,34 @@ class Topology():
|
|
855
855
|
See Topology.Boolean()
|
856
856
|
|
857
857
|
"""
|
858
|
+
from topologicpy.Vertex import Vertex
|
859
|
+
from topologicpy.Face import Face
|
860
|
+
from topologicpy.Shell import Shell
|
861
|
+
|
862
|
+
if Topology.IsInstance(topologyA, "Face") and Topology.IsInstance(topologyB, "Face"):
|
863
|
+
if Face.IsCoplanar(topologyA, topologyB):
|
864
|
+
topologyC = Topology.Boolean(topologyA, topologyB, operation="merge", tranDict=tranDict, tolerance=tolerance)
|
865
|
+
if Topology.IsInstance(topologyC, "Cluster"):
|
866
|
+
return topologyC
|
867
|
+
elif Topology.IsInstance(topologyC, "Shell"):
|
868
|
+
eb_list = Shell.ExternalBoundary(topologyC)
|
869
|
+
if Topology.IsInstance(eb_list, "Cluster"):
|
870
|
+
eb_list = Topology.Wires(eb_list)
|
871
|
+
else:
|
872
|
+
eb_list = [eb_list]
|
873
|
+
topologyA_wire = Face.ExternalBoundary(topologyA)
|
874
|
+
topologyB_wire = Face.ExternalBoundary(topologyB)
|
875
|
+
internal_boundaries = []
|
876
|
+
found = False
|
877
|
+
for i, eb in enumerate(eb_list):
|
878
|
+
v = Topology.Vertices(eb)[0]
|
879
|
+
if found == False:
|
880
|
+
if Vertex.IsInternal(v, topologyA_wire) or Vertex.IsInternal(v, topologyB_wire):
|
881
|
+
external_boundary = eb
|
882
|
+
found = True
|
883
|
+
else:
|
884
|
+
internal_boundaries.append(eb)
|
885
|
+
return Face.ByWires(external_boundary, internal_boundaries)
|
858
886
|
return Topology.Boolean(topologyA, topologyB, operation="union", tranDict=tranDict, tolerance=tolerance)
|
859
887
|
|
860
888
|
@staticmethod
|
@@ -865,6 +893,59 @@ class Topology():
|
|
865
893
|
"""
|
866
894
|
return Topology.Boolean(topologyA=topologyA, topologyB=topologyB, operation="difference", tranDict=tranDict, tolerance=tolerance)
|
867
895
|
|
896
|
+
@staticmethod
|
897
|
+
def ExternalBoundary(topology):
|
898
|
+
"""
|
899
|
+
Returns the external boundary of the input topology.
|
900
|
+
|
901
|
+
Parameters
|
902
|
+
----------
|
903
|
+
topology : topologic_core.Topology
|
904
|
+
The input topology.
|
905
|
+
|
906
|
+
Returns
|
907
|
+
-------
|
908
|
+
topologic_core.Topology
|
909
|
+
The external boundary of the input topology.
|
910
|
+
|
911
|
+
"""
|
912
|
+
from topologicpy.Topology import Topology
|
913
|
+
from topologicpy.Vertex import Vertex
|
914
|
+
from topologicpy.Edge import Edge
|
915
|
+
from topologicpy.Wire import Wire
|
916
|
+
from topologicpy.Face import Face
|
917
|
+
from topologicpy.Shell import Shell
|
918
|
+
from topologicpy.Cell import Cell
|
919
|
+
from topologicpy.CellComplex import CellComplex
|
920
|
+
from topologicpy.Cluster import Cluster
|
921
|
+
|
922
|
+
if not Topology.IsInstance(topology, "Topology"):
|
923
|
+
print("Topology.ExternalBoundary - Error: The input topology parameter is not a valid topology. Returning None.")
|
924
|
+
return None
|
925
|
+
|
926
|
+
if Topology.IsInstance(topology, "Vertex"):
|
927
|
+
return Vertex.ExternalBoundary(topology)
|
928
|
+
elif Topology.IsInstance(topology, "Edge"):
|
929
|
+
return Edge.ExternalBoundary(topology)
|
930
|
+
elif Topology.IsInstance(topology, "Wire"):
|
931
|
+
return Wire.ExternalBoundary(topology)
|
932
|
+
elif Topology.IsInstance(topology, "Face"):
|
933
|
+
return Face.ExternalBoundary(topology)
|
934
|
+
elif Topology.IsInstance(topology, "Shell"):
|
935
|
+
return Shell.ExternalBoundary(topology)
|
936
|
+
elif Topology.IsInstance(topology, "Cell"):
|
937
|
+
return Cell.ExternalBoundary(topology)
|
938
|
+
elif Topology.IsInstance(topology, "CellComplex"):
|
939
|
+
return CellComplex.ExternalBoundary(topology)
|
940
|
+
elif Topology.IsInstance(topology, "Cluster"):
|
941
|
+
eb_list = Cluster.CellComplexes(topology) + Cluster.FreeCells(topology) + Cluster.FreeShells(topology) + Cluster.FreeFaces(topology) + Cluster.FreeWires(topology) + Cluster.FreeEdges(topology) + Cluster.FreeVertices(topology)
|
942
|
+
return_list = []
|
943
|
+
for item in eb_list:
|
944
|
+
return_list.append(Topology.ExternalBoundary(item))
|
945
|
+
return Cluster.ByTopologies(return_list)
|
946
|
+
else:
|
947
|
+
return None
|
948
|
+
|
868
949
|
@staticmethod
|
869
950
|
def Intersect(topologyA, topologyB, tranDict=False, tolerance=0.0001):
|
870
951
|
"""
|
@@ -1475,7 +1556,265 @@ class Topology():
|
|
1475
1556
|
topDict = Dictionary.ByKeysValues(keys, values)
|
1476
1557
|
Topology.SetDictionary(returnTopology, topDict)
|
1477
1558
|
return returnTopology
|
1559
|
+
|
1560
|
+
@staticmethod
|
1561
|
+
def ByBIMPath(path, guidKey: str = "guid", colorKey: str = "color", typeKey: str = "type",
|
1562
|
+
defaultColor: list = [255,255,255,1], defaultType: str = "Structure",
|
1563
|
+
authorKey="author", dateKey="date", mantissa: int = 6, angTolerance: float = 0.001, tolerance: float = 0.0001):
|
1564
|
+
"""
|
1565
|
+
Imports topologies from the input BIM file. See https://dotbim.net/
|
1566
|
+
|
1567
|
+
Parameters
|
1568
|
+
----------
|
1569
|
+
path :str
|
1570
|
+
The path to the .bim file.
|
1571
|
+
path : str
|
1572
|
+
The input file path.
|
1573
|
+
overwrite : bool , optional
|
1574
|
+
If set to True the ouptut file will overwrite any pre-existing file. Otherwise, it won't. The default is False.
|
1575
|
+
version : str , optional
|
1576
|
+
The desired version number for the BIM file. The default is "1.0.0".
|
1577
|
+
guidKey : str , optional
|
1578
|
+
The key to use to store the the guid of the topology. The default is "guid".
|
1579
|
+
colorKey : str , optional
|
1580
|
+
The key to use to find the the color of the topology. The default is "color". If no color is found, the defaultColor parameter is used.
|
1581
|
+
typeKey : str , optional
|
1582
|
+
The key to use to find the the type of the topology. The default is "type". If no type is found, the defaultType parameter is used.
|
1583
|
+
defaultColor : list , optional
|
1584
|
+
The default color to use for the topology. The default is [255,255,255,1] which is opaque white.
|
1585
|
+
defaultType : str , optional
|
1586
|
+
The default type to use for the topology. The default is "Structure".
|
1587
|
+
authorKey : str , optional
|
1588
|
+
The key to use to store the author of the topology. The default is "author".
|
1589
|
+
dateKey : str , optional
|
1590
|
+
The key to use to store the creation date of the topology. This should be in the formate "DD.MM.YYYY". If no date is found the date of import is used.
|
1591
|
+
mantissa : int , optional
|
1592
|
+
The desired length of the mantissa. The default is 6.
|
1593
|
+
angTolerance : float , optional
|
1594
|
+
The angle tolerance in degrees under which no rotation is carried out. The default is 0.001 degrees.
|
1595
|
+
tolerance : float , optional
|
1596
|
+
The desired tolerance. The default is 0.0001.
|
1597
|
+
|
1598
|
+
Returns
|
1599
|
+
-------
|
1600
|
+
list
|
1601
|
+
The list of imported topologies
|
1602
|
+
|
1603
|
+
"""
|
1604
|
+
import json
|
1605
|
+
if not path:
|
1606
|
+
print("Topology.ByBIMPath - Error: the input path parameter is not a valid path. Returning None.")
|
1607
|
+
return None
|
1608
|
+
topologies = None
|
1609
|
+
with open(path, "r") as bim_file:
|
1610
|
+
json_string = str(bim_file.read())
|
1611
|
+
topologies = Topology.ByBIMString(string=json_string, guidKey=guidKey, colorKey=colorKey, typeKey=typeKey,
|
1612
|
+
defaultColor=defaultColor, defaultType=defaultType,
|
1613
|
+
authorKey=authorKey, dateKey=dateKey, mantissa=mantissa, angTolerance=angTolerance, tolerance=tolerance)
|
1614
|
+
try:
|
1615
|
+
with open(path, "r") as bim_file:
|
1616
|
+
json_string = str(bim_file.read())
|
1617
|
+
topologies = Topology.ByBIMString(string=json_string, guidKey=guidKey, colorKey=colorKey, typeKey=typeKey,
|
1618
|
+
defaultColor=defaultColor, defaultType=defaultType,
|
1619
|
+
authorKey=authorKey, dateKey=dateKey, mantissa=mantissa, angTolerance=angTolerance, tolerance=tolerance)
|
1620
|
+
except:
|
1621
|
+
print("Topology.ByBIMPath - Error: the BIM file is not a valid file. Returning None.")
|
1622
|
+
return topologies
|
1623
|
+
|
1624
|
+
@staticmethod
|
1625
|
+
def ByBIMString(string, guidKey: str = "guid", colorKey: str = "color", typeKey: str = "type",
|
1626
|
+
defaultColor: list = [255,255,255,1], defaultType: str = "Structure",
|
1627
|
+
authorKey: str = "author", dateKey: str = "date", mantissa: int = 6, angTolerance: float = 0.001, tolerance: float = 0.0001):
|
1628
|
+
"""
|
1629
|
+
Imports topologies from the input BIM file. See https://dotbim.net/
|
1630
|
+
|
1631
|
+
Parameters
|
1632
|
+
----------
|
1633
|
+
string :str
|
1634
|
+
The input dotbim str (in JSON format).
|
1635
|
+
path : str
|
1636
|
+
The input file path.
|
1637
|
+
overwrite : bool , optional
|
1638
|
+
If set to True the ouptut file will overwrite any pre-existing file. Otherwise, it won't. The default is False.
|
1639
|
+
version : str , optional
|
1640
|
+
The desired version number for the BIM file. The default is "1.0.0".
|
1641
|
+
guidKey : str , optional
|
1642
|
+
The key to use to store the the guid of the topology. The default is "guid".
|
1643
|
+
colorKey : str , optional
|
1644
|
+
The key to use to find the the color of the topology. The default is "color". If no color is found, the defaultColor parameter is used.
|
1645
|
+
typeKey : str , optional
|
1646
|
+
The key to use to find the the type of the topology. The default is "type". If no type is found, the defaultType parameter is used.
|
1647
|
+
defaultColor : list , optional
|
1648
|
+
The default color to use for the topology. The default is [255,255,255,1] which is opaque white.
|
1649
|
+
defaultType : str , optional
|
1650
|
+
The default type to use for the topology. The default is "Structure".
|
1651
|
+
authorKey : str , optional
|
1652
|
+
The key to use to store the author of the topology. The default is "author".
|
1653
|
+
dateKey : str , optional
|
1654
|
+
The key to use to store the creation date of the topology. This should be in the formate "DD.MM.YYYY". If no date is found the date of import is used.
|
1655
|
+
mantissa : int , optional
|
1656
|
+
The desired length of the mantissa. The default is 6.
|
1657
|
+
angTolerance : float , optional
|
1658
|
+
The angle tolerance in degrees under which no rotation is carried out. The default is 0.001 degrees.
|
1659
|
+
tolerance : float , optional
|
1660
|
+
The desired tolerance. The default is 0.0001.
|
1661
|
+
|
1662
|
+
Returns
|
1663
|
+
-------
|
1664
|
+
list
|
1665
|
+
The list of imported topologies
|
1666
|
+
|
1667
|
+
"""
|
1668
|
+
@staticmethod
|
1669
|
+
def convert_JSON_to_file(json_dictionary):
|
1670
|
+
import dotbimpy
|
1671
|
+
schema_version = json_dictionary["schema_version"]
|
1672
|
+
elements = json_dictionary["elements"]
|
1673
|
+
meshes = json_dictionary["meshes"]
|
1674
|
+
created_info = json_dictionary["info"]
|
1675
|
+
|
1676
|
+
created_meshes = []
|
1677
|
+
for i in meshes:
|
1678
|
+
created_meshes.append(dotbimpy.Mesh(
|
1679
|
+
mesh_id=i["mesh_id"],
|
1680
|
+
coordinates=i["coordinates"],
|
1681
|
+
indices=i["indices"]
|
1682
|
+
))
|
1683
|
+
|
1684
|
+
created_elements = []
|
1685
|
+
for i in elements:
|
1686
|
+
new_element = dotbimpy.Element(
|
1687
|
+
mesh_id=i["mesh_id"],
|
1688
|
+
vector=dotbimpy.Vector(x=i["vector"]["x"],
|
1689
|
+
y=i["vector"]["y"],
|
1690
|
+
z=i["vector"]["z"]),
|
1691
|
+
rotation=dotbimpy.Rotation(qx=i["rotation"]["qx"],
|
1692
|
+
qy=i["rotation"]["qy"],
|
1693
|
+
qz=i["rotation"]["qz"],
|
1694
|
+
qw=i["rotation"]["qw"]),
|
1695
|
+
info=i["info"],
|
1696
|
+
color=dotbimpy.Color(r=i["color"]["r"],
|
1697
|
+
g=i["color"]["g"],
|
1698
|
+
b=i["color"]["b"],
|
1699
|
+
a=i["color"]["a"]),
|
1700
|
+
type=i["type"],
|
1701
|
+
guid=i["guid"]
|
1702
|
+
)
|
1703
|
+
try:
|
1704
|
+
new_element.face_colors = i["face_colors"]
|
1705
|
+
except KeyError as e:
|
1706
|
+
if str(e) == "'face_colors'":
|
1707
|
+
pass
|
1708
|
+
else:
|
1709
|
+
raise
|
1710
|
+
created_elements.append(new_element)
|
1711
|
+
|
1712
|
+
file = dotbimpy.File(schema_version=schema_version, meshes=created_meshes, elements=created_elements, info=created_info)
|
1713
|
+
return file
|
1714
|
+
json_dictionary = json.loads(string)
|
1715
|
+
file = convert_JSON_to_file(json_dictionary)
|
1716
|
+
return Topology.ByBIMFile(file, guidKey=guidKey, colorKey=colorKey, typeKey=typeKey,
|
1717
|
+
defaultColor=defaultColor, defaultType=defaultType,
|
1718
|
+
authorKey=authorKey, dateKey=dateKey,
|
1719
|
+
mantissa=mantissa, angTolerance=angTolerance, tolerance=tolerance)
|
1720
|
+
@staticmethod
|
1721
|
+
def ByBIMFile(file, guidKey: str = "guid", colorKey: str = "color", typeKey: str = "type",
|
1722
|
+
defaultColor: list = [255,255,255,1], defaultType: str = "Structure",
|
1723
|
+
authorKey="author", dateKey="date", mantissa: int = 6, angTolerance: float = 0.001, tolerance: float = 0.0001):
|
1724
|
+
"""
|
1725
|
+
Imports topologies from the input BIM (dotbimpy.file.File) file object. See https://dotbim.net/
|
1726
|
+
|
1727
|
+
Parameters
|
1728
|
+
----------
|
1729
|
+
file : dotbimpy.file.File
|
1730
|
+
The input dotbim file.
|
1731
|
+
path : str
|
1732
|
+
The input file path.
|
1733
|
+
overwrite : bool , optional
|
1734
|
+
If set to True the ouptut file will overwrite any pre-existing file. Otherwise, it won't. The default is False.
|
1735
|
+
version : str , optional
|
1736
|
+
The desired version number for the BIM file. The default is "1.0.0".
|
1737
|
+
guidKey : str , optional
|
1738
|
+
The key to use to store the the guid of the topology. The default is "guid".
|
1739
|
+
colorKey : str , optional
|
1740
|
+
The key to use to find the the color of the topology. The default is "color". If no color is found, the defaultColor parameter is used.
|
1741
|
+
typeKey : str , optional
|
1742
|
+
The key to use to find the the type of the topology. The default is "type". If no type is found, the defaultType parameter is used.
|
1743
|
+
defaultColor : list , optional
|
1744
|
+
The default color to use for the topology. The default is [255,255,255,1] which is opaque white.
|
1745
|
+
defaultType : str , optional
|
1746
|
+
The default type to use for the topology. The default is "Structure".
|
1747
|
+
authorKey : str , optional
|
1748
|
+
The key to use to store the author of the topology. The default is "author".
|
1749
|
+
dateKey : str , optional
|
1750
|
+
The key to use to store the creation date of the topology. This should be in the formate "DD.MM.YYYY". If no date is found the date of import is used.
|
1751
|
+
mantissa : int , optional
|
1752
|
+
The desired length of the mantissa. The default is 6.
|
1753
|
+
angTolerance : float , optional
|
1754
|
+
The angle tolerance in degrees under which no rotation is carried out. The default is 0.001 degrees.
|
1755
|
+
tolerance : float , optional
|
1756
|
+
The desired tolerance. The default is 0.0001.
|
1757
|
+
|
1758
|
+
Returns
|
1759
|
+
-------
|
1760
|
+
list
|
1761
|
+
The list of imported topologies
|
1762
|
+
|
1763
|
+
"""
|
1764
|
+
from topologicpy.Vertex import Vertex
|
1765
|
+
from topologicpy.Topology import Topology
|
1766
|
+
from topologicpy.Dictionary import Dictionary
|
1767
|
+
import datetime
|
1478
1768
|
|
1769
|
+
file_info = file.info
|
1770
|
+
elements = file.elements
|
1771
|
+
meshes = file.meshes
|
1772
|
+
final_topologies = []
|
1773
|
+
topologies = []
|
1774
|
+
id_list = []
|
1775
|
+
for mesh in meshes:
|
1776
|
+
id_list.append(mesh.mesh_id)
|
1777
|
+
coordinates = mesh.coordinates
|
1778
|
+
indices = mesh.indices
|
1779
|
+
coordinates = [coordinates[i:i + 3] for i in range(0, len(coordinates),3)]
|
1780
|
+
indices = [indices[i:i + 3] for i in range(0, len(indices),3)]
|
1781
|
+
topology = Topology.ByGeometry(vertices=coordinates, faces=indices, tolerance=tolerance)
|
1782
|
+
topologies.append(topology)
|
1783
|
+
|
1784
|
+
for element in elements:
|
1785
|
+
element_info = element.info
|
1786
|
+
element_info[typeKey] = element.type
|
1787
|
+
element_info[colorKey] = [element.color.r, element.color.g, element.color.b, float(element.color.a)/float(255)]
|
1788
|
+
try:
|
1789
|
+
element_info[guidKey] = element.guid
|
1790
|
+
except:
|
1791
|
+
element_info[guidKey] = str(uuid.uuid4())
|
1792
|
+
try:
|
1793
|
+
element_info[authorKey] = file_info['author']
|
1794
|
+
except:
|
1795
|
+
element_info[authorKey] = "topologicpy"
|
1796
|
+
# Get the current date
|
1797
|
+
current_date = datetime.datetime.now()
|
1798
|
+
# Format the date as a string in DD.MM.YYYY format
|
1799
|
+
formatted_date = current_date.strftime("%d.%m.%Y")
|
1800
|
+
try:
|
1801
|
+
element_info[dateKey] = file_info['date']
|
1802
|
+
except:
|
1803
|
+
element_info[dateKey] = formatted_date
|
1804
|
+
d = Dictionary.ByPythonDictionary(element_info)
|
1805
|
+
mesh_id = element.mesh_id
|
1806
|
+
quat = element.rotation
|
1807
|
+
quaternion = [quat.qx, quat.qy, quat.qz, quat.qw]
|
1808
|
+
#roll, pitch, yaw = quaternion_to_euler([rot.qx, rot.qy, rot.qz, rot.qw])
|
1809
|
+
vector = element.vector
|
1810
|
+
topology = topologies[mesh_id]
|
1811
|
+
if Topology.IsInstance(topology, "Topology"):
|
1812
|
+
topology = Topology.RotateByQuaternion(topology=topology, origin=Vertex.Origin(), quaternion=quaternion, angTolerance=angTolerance, tolerance=tolerance)
|
1813
|
+
topology = Topology.Translate(topology, vector.x, vector.y, vector.z)
|
1814
|
+
topology = Topology.SetDictionary(topology, d)
|
1815
|
+
final_topologies.append(topology)
|
1816
|
+
return final_topologies
|
1817
|
+
|
1479
1818
|
@staticmethod
|
1480
1819
|
def ByBREPFile(file):
|
1481
1820
|
"""
|
@@ -3317,6 +3656,157 @@ class Topology():
|
|
3317
3656
|
newTopologies.append(newTopology)
|
3318
3657
|
return Cluster.ByTopologies(newTopologies)
|
3319
3658
|
|
3659
|
+
@staticmethod
|
3660
|
+
def ExportToBIM(topologies, path : str, overwrite: bool = False, version: str = "1.0.0",
|
3661
|
+
guidKey: str = "guid", colorKey: str = "color", typeKey: str = "type",
|
3662
|
+
defaultColor: list = [255,255,255,1], defaultType: str = "Structure",
|
3663
|
+
author: str = "topologicpy", date: str = None, mantissa: int = 6, tolerance: float = 0.0001):
|
3664
|
+
"""
|
3665
|
+
Exports the input topology to a BIM file. See https://dotbim.net/
|
3666
|
+
|
3667
|
+
Parameters
|
3668
|
+
----------
|
3669
|
+
topologies : list or topologic_core.Topology
|
3670
|
+
The input list of topologies or a single topology. The .bim format is restricted to triangulated meshes. No wires, edges, or vertices are supported.
|
3671
|
+
path : str
|
3672
|
+
The input file path.
|
3673
|
+
overwrite : bool , optional
|
3674
|
+
If set to True the ouptut file will overwrite any pre-existing file. Otherwise, it won't. The default is False.
|
3675
|
+
version : str , optional
|
3676
|
+
The desired version number for the BIM file. The default is "1.0.0".
|
3677
|
+
guidKey : str , optional
|
3678
|
+
The key to use to find the the guid of the topology. It is case insensitive. The default is "guid". If no guid is found, one is generated automatically.
|
3679
|
+
colorKey : str , optional
|
3680
|
+
The key to use to find the the color of the topology. It is case insensitive. The default is "color". If no color is found, the defaultColor parameter is used.
|
3681
|
+
typeKey : str , optional
|
3682
|
+
The key to use to find the the type of the topology. It is case insensitive. The default is "type". If no type is found, the defaultType parameter is used.
|
3683
|
+
defaultColor : list , optional
|
3684
|
+
The default color to use for the topology. The default is [255,255,255,1] which is opaque white.
|
3685
|
+
defaultType : str , optional
|
3686
|
+
The default type to use for the topology. The default is "Structure".
|
3687
|
+
author : str , optional
|
3688
|
+
The author of the topology. The default is "topologicpy".
|
3689
|
+
date : str , optional
|
3690
|
+
The creation date of the topology. This should be in the formate "DD.MM.YYYY". The default is None which uses the date of export.
|
3691
|
+
mantissa : int , optional
|
3692
|
+
The desired length of the mantissa. The default is 6.
|
3693
|
+
tolerance : float , optional
|
3694
|
+
The desired tolerance. The default is 0.0001.
|
3695
|
+
|
3696
|
+
Returns
|
3697
|
+
-------
|
3698
|
+
bool
|
3699
|
+
True if the export operation is successful. False otherwise.
|
3700
|
+
|
3701
|
+
"""
|
3702
|
+
from topologicpy.Topology import Topology
|
3703
|
+
from topologicpy.Helper import Helper
|
3704
|
+
from topologicpy.Dictionary import Dictionary
|
3705
|
+
from topologicpy.Cluster import Cluster
|
3706
|
+
import datetime
|
3707
|
+
from os.path import exists
|
3708
|
+
|
3709
|
+
try:
|
3710
|
+
import dotbimpy
|
3711
|
+
except:
|
3712
|
+
print("Topology - Installing required dotbimpy library.")
|
3713
|
+
try:
|
3714
|
+
os.system("pip install dotbimpy")
|
3715
|
+
except:
|
3716
|
+
os.system("pip install dotbimpy --user")
|
3717
|
+
try:
|
3718
|
+
import dotbimpy
|
3719
|
+
print("Topology - dotbimpy library installed successfully.")
|
3720
|
+
except:
|
3721
|
+
warnings.warn("Topology - Error: Could not import dotbimpy. Please install the dotbimpy library manually. Returning None.")
|
3722
|
+
return None
|
3723
|
+
# Make sure the file extension is .brep
|
3724
|
+
ext = path[len(path)-4:len(path)]
|
3725
|
+
if ext.lower() != ".bim":
|
3726
|
+
path = path+".bim"
|
3727
|
+
if not overwrite and exists(path):
|
3728
|
+
print("Topology.ExportToBIM - Error: a file already exists at the specified path and overwrite is set to False. Returning None.")
|
3729
|
+
return None
|
3730
|
+
# Get the current date
|
3731
|
+
current_date = datetime.datetime.now()
|
3732
|
+
|
3733
|
+
# Format the date as a string in DD.MM.YYYY format
|
3734
|
+
formatted_date = current_date.strftime("%d.%m.%Y")
|
3735
|
+
|
3736
|
+
if Topology.IsInstance(topologies, "Topology"):
|
3737
|
+
topologies = [topologies]
|
3738
|
+
# Prepare input data
|
3739
|
+
final_topologies = []
|
3740
|
+
for topology in topologies:
|
3741
|
+
d = Topology.Dictionary(topology)
|
3742
|
+
topology = Topology.SelfMerge(Topology.Triangulate(topology, tolerance=tolerance), tolerance=tolerance)
|
3743
|
+
topology = Topology.SetDictionary(topology, d)
|
3744
|
+
if Topology.IsInstance(topology, "Cluster"):
|
3745
|
+
final_topologies += Cluster.CellComplexes(topology) + Cluster.FreeCells(topology, tolerance=tolerance) + Cluster.FreeShells(topology, tolerance=tolerance) + Cluster.FreeFaces(topology, tolerance=tolerance)
|
3746
|
+
elif Topology.IsInstance(topology, "CellComplex") or Topology.IsInstance(topology, "Cell") or Topology.IsInstance(topology, "Shell") or Topology.IsInstance(topology, "Face"):
|
3747
|
+
final_topologies.append(topology)
|
3748
|
+
elements = []
|
3749
|
+
meshes = []
|
3750
|
+
for i, topology in enumerate(final_topologies):
|
3751
|
+
geo_dict = Topology.Geometry(topology, mantissa=mantissa)
|
3752
|
+
coordinates = Helper.Flatten(geo_dict['vertices'])
|
3753
|
+
indices = Helper.Flatten(geo_dict['faces'])
|
3754
|
+
d = Topology.Dictionary(topology)
|
3755
|
+
color = Dictionary.ValueAtKey(d, colorKey)
|
3756
|
+
r, g, b, a = defaultColor
|
3757
|
+
if isinstance(color, list):
|
3758
|
+
if len(color) > 2:
|
3759
|
+
r = color[0]
|
3760
|
+
g = color[1]
|
3761
|
+
b = color[2]
|
3762
|
+
if len(color) == 3:
|
3763
|
+
a = color[3]
|
3764
|
+
color = dotbimpy.Color(r=r, g=g, b=b, a=int(a*255))
|
3765
|
+
guid = Dictionary.ValueAtKey(d, guidKey)
|
3766
|
+
if not guid:
|
3767
|
+
guid = str(uuid.uuid4())
|
3768
|
+
|
3769
|
+
type = Dictionary.ValueAtKey(d, typeKey)
|
3770
|
+
if not type:
|
3771
|
+
type = defaultType
|
3772
|
+
info = Dictionary.PythonDictionary(d)
|
3773
|
+
info['color'] = str([r,g,b,a])
|
3774
|
+
info['guid'] = guid
|
3775
|
+
info['type'] = type
|
3776
|
+
print("info", info)
|
3777
|
+
rotation = dotbimpy.Rotation(qx=0, qy=0, qz=0, qw=1.0)
|
3778
|
+
vector = dotbimpy.Vector(x=0, y=0, z=0)
|
3779
|
+
|
3780
|
+
# Instantiate Mesh object
|
3781
|
+
mesh = dotbimpy.Mesh(mesh_id=i, coordinates=coordinates, indices=indices)
|
3782
|
+
meshes.append(mesh)
|
3783
|
+
# Instantiate Element object
|
3784
|
+
element = dotbimpy.Element(mesh_id=i,
|
3785
|
+
vector=vector,
|
3786
|
+
guid=guid,
|
3787
|
+
info=info,
|
3788
|
+
rotation=rotation,
|
3789
|
+
type=type,
|
3790
|
+
color=color)
|
3791
|
+
elements.append(element)
|
3792
|
+
|
3793
|
+
# File meta data
|
3794
|
+
file_info = {
|
3795
|
+
"Author": author,
|
3796
|
+
"Date": formatted_date
|
3797
|
+
}
|
3798
|
+
|
3799
|
+
print("Meshes:", meshes)
|
3800
|
+
print("Elements:", elements)
|
3801
|
+
|
3802
|
+
# Instantiate and save File object
|
3803
|
+
file = dotbimpy.File(version, meshes=meshes, elements=elements, info=file_info)
|
3804
|
+
try:
|
3805
|
+
file.save(path)
|
3806
|
+
return True
|
3807
|
+
except:
|
3808
|
+
return False
|
3809
|
+
|
3320
3810
|
@staticmethod
|
3321
3811
|
def ExportToBREP(topology, path, overwrite=False, version=3):
|
3322
3812
|
"""
|
@@ -4261,11 +4751,11 @@ class Topology():
|
|
4261
4751
|
"""
|
4262
4752
|
from topologicpy.Vertex import Vertex
|
4263
4753
|
from topologicpy.Vector import Vector
|
4264
|
-
|
4754
|
+
|
4265
4755
|
if not Topology.IsInstance(topology, "Topology"):
|
4266
4756
|
print("Topology.Flatten - Error: the input topology parameter is not a valid topology. Returning None.")
|
4267
4757
|
return None
|
4268
|
-
if origin
|
4758
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
4269
4759
|
origin = Topology.Centroid(topology)
|
4270
4760
|
up = Vector.Up()
|
4271
4761
|
flat_topology = Topology.Translate(topology, -Vertex.X(origin, mantissa=mantissa), -Vertex.Y(origin, mantissa=mantissa), -Vertex.Z(origin, mantissa=mantissa))
|
@@ -5417,12 +5907,13 @@ class Topology():
|
|
5417
5907
|
if not Topology.IsInstance(topology, "Topology"):
|
5418
5908
|
print("Topology.Rotate - Error: The input topology parameter is not a valid topologic topology. Returning None.")
|
5419
5909
|
return None
|
5420
|
-
if not origin:
|
5910
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
5421
5911
|
origin = Vertex.ByCoordinates(0, 0, 0)
|
5422
5912
|
if not Topology.IsInstance(origin, "Vertex"):
|
5423
5913
|
print("Topology.Rotate - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
5424
5914
|
return None
|
5425
5915
|
returnTopology = topology
|
5916
|
+
d = Topology.Dictionary(topology)
|
5426
5917
|
if abs(angle) >= angTolerance:
|
5427
5918
|
try:
|
5428
5919
|
x, y, z = axis
|
@@ -5437,9 +5928,141 @@ class Topology():
|
|
5437
5928
|
rot_vertices = [Vertex.ByCoordinates(rot_v) for rot_v in rot_vertices]
|
5438
5929
|
new_topology = Topology.ReplaceVertices(topology, verticesA=Topology.Vertices(topology), verticesB=rot_vertices)
|
5439
5930
|
new_topology = Topology.SelfMerge(new_topology, tolerance=tolerance)
|
5931
|
+
if len(Dictionary.Keys(d) > 0):
|
5932
|
+
new_topology = Topology.SetDictionary(new_topology, d)
|
5440
5933
|
return new_topology
|
5934
|
+
if len(Dictionary.Keys(d)) > 0:
|
5935
|
+
returnTopology = Topology.SetDictionary(returnTopology, d)
|
5441
5936
|
return returnTopology
|
5442
5937
|
|
5938
|
+
@staticmethod
|
5939
|
+
def RotateByEulerAngles(topology, origin = None, roll: float = 0, pitch: float = 0, yaw: float = 0, angTolerance: float = 0.001, tolerance: float = 0.0001):
|
5940
|
+
"""
|
5941
|
+
Rotates the input topology using Euler angles (roll, pitch, yaw). See https://en.wikipedia.org/wiki/Aircraft_principal_axes
|
5942
|
+
|
5943
|
+
Parameters
|
5944
|
+
----------
|
5945
|
+
topology : topologic_core.Topology
|
5946
|
+
The input topology.
|
5947
|
+
origin : topologic_core.Vertex , optional
|
5948
|
+
The origin (center) of the rotation. If set to None, the world origin (0, 0, 0) is used. The default is None.
|
5949
|
+
roll : float , optional
|
5950
|
+
The rotation angle in degrees around the X-axis. The default is 0.
|
5951
|
+
pitch = float , optional
|
5952
|
+
The rotation angle in degrees around the Y-axis. The default is 0.
|
5953
|
+
yaw = float , optional
|
5954
|
+
The rotation angle in degrees around the Z-axis. The default is 0.
|
5955
|
+
angTolerance : float , optional
|
5956
|
+
The angle tolerance in degrees under which no rotation is carried out. The default is 0.001 degrees.
|
5957
|
+
tolerance : float , optional
|
5958
|
+
The desired tolerance. The default is 0.0001.
|
5959
|
+
|
5960
|
+
Returns
|
5961
|
+
-------
|
5962
|
+
topologic_core.Topology
|
5963
|
+
The rotated topology.
|
5964
|
+
|
5965
|
+
"""
|
5966
|
+
from topologicpy.Vertex import Vertex
|
5967
|
+
from topologicpy.Dictionary import Dictionary
|
5968
|
+
|
5969
|
+
if not Topology.IsInstance(topology, "Topology"):
|
5970
|
+
print("Topology.RotateByEulerAngles - Error: The input topology parameter is not a valid topologic topology. Returning None.")
|
5971
|
+
return None
|
5972
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
5973
|
+
origin = Vertex.ByCoordinates(0, 0, 0)
|
5974
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
5975
|
+
print("Topology.RotateByEulerAngles - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
5976
|
+
return None
|
5977
|
+
d = Topology.Dictionary(topology)
|
5978
|
+
return_topology = Topology.Copy(topology)
|
5979
|
+
return_topology = Topology.Rotate(return_topology, origin=origin, axis=[1,0,0], angle=roll, angTolerance=angTolerance, tolerance=tolerance)
|
5980
|
+
return_topology = Topology.Rotate(return_topology, origin=origin, axis=[0,1,0], angle=pitch, angTolerance=angTolerance, tolerance=tolerance)
|
5981
|
+
return_topology = Topology.Rotate(return_topology, origin=origin, axis=[0,0,1], angle=yaw, angTolerance=angTolerance, tolerance=tolerance)
|
5982
|
+
if len(Dictionary.Keys(d)) > 0:
|
5983
|
+
return_topology = Topology.SetDictionary(return_topology, d)
|
5984
|
+
return return_topology
|
5985
|
+
|
5986
|
+
@staticmethod
|
5987
|
+
def RotateByQuaternion(topology, origin=None, quaternion: list = [0,0,0,1], angTolerance: float = 0.001, tolerance: float = 0.0001):
|
5988
|
+
"""
|
5989
|
+
Rotates the input topology using Quaternion rotations. See https://en.wikipedia.org/wiki/Quaternion
|
5990
|
+
|
5991
|
+
Parameters
|
5992
|
+
----------
|
5993
|
+
topology : topologic_core.Topology
|
5994
|
+
The input topology.
|
5995
|
+
origin : topologic_core.Vertex , optional
|
5996
|
+
The origin (center) of the rotation. If set to None, the world origin (0, 0, 0) is used. The default is None.
|
5997
|
+
quaternion : list or numpy array of size 4
|
5998
|
+
The input Quaternion list. It should be in the form [x, y, z, w].
|
5999
|
+
angTolerance : float , optional
|
6000
|
+
The angle tolerance in degrees under which no rotation is carried out. The default is 0.001 degrees.
|
6001
|
+
tolerance : float , optional
|
6002
|
+
The desired tolerance. The default is 0.0001.
|
6003
|
+
|
6004
|
+
Returns
|
6005
|
+
-------
|
6006
|
+
topologic_core.Topology
|
6007
|
+
The rotated topology.
|
6008
|
+
|
6009
|
+
"""
|
6010
|
+
from topologicpy.Vertex import Vertex
|
6011
|
+
from topologicpy.Dictionary import Dictionary
|
6012
|
+
|
6013
|
+
def quaternion_to_euler(quaternion):
|
6014
|
+
"""
|
6015
|
+
Convert a quaternion into Euler angles (roll, pitch, yaw)
|
6016
|
+
Roll is rotation around x-axis, Pitch is rotation around y-axis, and Yaw is rotation around z-axis.
|
6017
|
+
Quaternion should be in the form [x, y, z, w]
|
6018
|
+
|
6019
|
+
Args:
|
6020
|
+
quaternion: list or numpy array of size 4
|
6021
|
+
|
6022
|
+
Returns:
|
6023
|
+
A list of Euler angles in degrees [roll, pitch, yaw]
|
6024
|
+
"""
|
6025
|
+
import numpy as np
|
6026
|
+
x, y, z, w = quaternion
|
6027
|
+
|
6028
|
+
# Roll (x-axis rotation)
|
6029
|
+
sinr_cosp = 2 * (w * x + y * z)
|
6030
|
+
cosr_cosp = 1 - 2 * (x * x + y * y)
|
6031
|
+
roll = np.arctan2(sinr_cosp, cosr_cosp)
|
6032
|
+
|
6033
|
+
# Pitch (y-axis rotation)
|
6034
|
+
sinp = 2 * (w * y - z * x)
|
6035
|
+
if abs(sinp) >= 1:
|
6036
|
+
pitch = np.sign(sinp) * np.pi / 2 # use 90 degrees if out of range
|
6037
|
+
else:
|
6038
|
+
pitch = np.arcsin(sinp)
|
6039
|
+
|
6040
|
+
# Yaw (z-axis rotation)
|
6041
|
+
siny_cosp = 2 * (w * z + x * y)
|
6042
|
+
cosy_cosp = 1 - 2 * (y * y + z * z)
|
6043
|
+
yaw = np.arctan2(siny_cosp, cosy_cosp)
|
6044
|
+
|
6045
|
+
# Convert radians to degrees
|
6046
|
+
roll = np.degrees(roll)
|
6047
|
+
pitch = np.degrees(pitch)
|
6048
|
+
yaw = np.degrees(yaw)
|
6049
|
+
return [roll, pitch, yaw]
|
6050
|
+
|
6051
|
+
if not Topology.IsInstance(topology, "Topology"):
|
6052
|
+
print("Topology.RotateByQuaternion - Error: The input topology parameter is not a valid topologic topology. Returning None.", topology)
|
6053
|
+
return None
|
6054
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
6055
|
+
origin = Vertex.ByCoordinates(0, 0, 0)
|
6056
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
6057
|
+
print("Topology.RotateByQuaternion - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
6058
|
+
return None
|
6059
|
+
roll, pitch, yaw = quaternion_to_euler(quaternion)
|
6060
|
+
d = Topology.Dictionary(topology)
|
6061
|
+
return_topology = Topology.RotateByEulerAngles(topology=topology, origin=origin, roll=roll, pitch=pitch, yaw=yaw, angTolerance=angTolerance, tolerance=tolerance)
|
6062
|
+
if len(Dictionary.Keys(d)) > 0:
|
6063
|
+
return_topology = Topology.SetDictionary(return_topology, d)
|
6064
|
+
return return_topology
|
6065
|
+
|
5443
6066
|
@staticmethod
|
5444
6067
|
def Scale(topology, origin=None, x=1, y=1, z=1):
|
5445
6068
|
"""
|
@@ -5467,7 +6090,7 @@ class Topology():
|
|
5467
6090
|
from topologicpy.Vertex import Vertex
|
5468
6091
|
if not Topology.IsInstance(topology, "Topology"):
|
5469
6092
|
return None
|
5470
|
-
if not origin:
|
6093
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
5471
6094
|
origin = Vertex.ByCoordinates(0, 0, 0)
|
5472
6095
|
if not Topology.IsInstance(origin, "Vertex"):
|
5473
6096
|
return None
|
@@ -6216,7 +6839,7 @@ class Topology():
|
|
6216
6839
|
from topologicpy.CellComplex import CellComplex
|
6217
6840
|
from topologicpy.Cluster import Cluster
|
6218
6841
|
|
6219
|
-
if not origin:
|
6842
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
6220
6843
|
origin = Vertex.ByCoordinates(0, 0, 0)
|
6221
6844
|
if not Topology.IsInstance(topology, "Topology"):
|
6222
6845
|
if not silent:
|
@@ -6336,7 +6959,7 @@ class Topology():
|
|
6336
6959
|
return topology
|
6337
6960
|
if triangulate == True:
|
6338
6961
|
topology = Topology.Triangulate(topology)
|
6339
|
-
if origin
|
6962
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
6340
6963
|
origin = Topology.Centroid(topology)
|
6341
6964
|
vertices = Topology.Vertices(topology)
|
6342
6965
|
zList = [Vertex.Z(v, mantissa=mantissa) for v in vertices]
|
@@ -6389,7 +7012,7 @@ class Topology():
|
|
6389
7012
|
return topology
|
6390
7013
|
if triangulate == True:
|
6391
7014
|
topology = Topology.Triangulate(topology)
|
6392
|
-
if origin
|
7015
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
6393
7016
|
origin = Topology.Centroid(topology)
|
6394
7017
|
|
6395
7018
|
vertices = Topology.Vertices(topology)
|
@@ -6433,7 +7056,7 @@ class Topology():
|
|
6433
7056
|
if not Topology.IsInstance(topology, "Topology"):
|
6434
7057
|
print("Topology.Unflatten - Error: the input topology parameter is not a valid topology. Returning None.")
|
6435
7058
|
return None
|
6436
|
-
if origin
|
7059
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
6437
7060
|
origin = Vertex.Origin()
|
6438
7061
|
up = Vector.Up()
|
6439
7062
|
tran_mat = Vector.TransformationMatrix(up, direction)
|
@@ -7029,6 +7652,7 @@ class Topology():
|
|
7029
7652
|
if transferDictionaries:
|
7030
7653
|
selectors.append(Topology.SetDictionary(Face.Centroid(triFace), Topology.Dictionary(aFace)))
|
7031
7654
|
faceTriangles.append(triFace)
|
7655
|
+
return_topology = None
|
7032
7656
|
if t == Topology.TypeID("Face") or t == Topology.TypeID("Shell"): # Face or Shell
|
7033
7657
|
return_topology = Shell.ByFaces(faceTriangles, tolerance=tolerance)
|
7034
7658
|
if transferDictionaries and not return_topology == None:
|