topologicpy 0.7.12__py3-none-any.whl → 0.7.15__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 +628 -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.15.dist-info}/METADATA +1 -1
- topologicpy-0.7.15.dist-info/RECORD +33 -0
- topologicpy-0.7.12.dist-info/RECORD +0 -33
- {topologicpy-0.7.12.dist-info → topologicpy-0.7.15.dist-info}/LICENSE +0 -0
- {topologicpy-0.7.12.dist-info → topologicpy-0.7.15.dist-info}/WHEEL +0 -0
- {topologicpy-0.7.12.dist-info → topologicpy-0.7.15.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
|
1478
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
|
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,153 @@ 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) == 4:
|
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
|
+
rotation = dotbimpy.Rotation(qx=0, qy=0, qz=0, qw=1.0)
|
3777
|
+
vector = dotbimpy.Vector(x=0, y=0, z=0)
|
3778
|
+
|
3779
|
+
# Instantiate Mesh object
|
3780
|
+
mesh = dotbimpy.Mesh(mesh_id=i, coordinates=coordinates, indices=indices)
|
3781
|
+
meshes.append(mesh)
|
3782
|
+
# Instantiate Element object
|
3783
|
+
element = dotbimpy.Element(mesh_id=i,
|
3784
|
+
vector=vector,
|
3785
|
+
guid=guid,
|
3786
|
+
info=info,
|
3787
|
+
rotation=rotation,
|
3788
|
+
type=type,
|
3789
|
+
color=color)
|
3790
|
+
elements.append(element)
|
3791
|
+
|
3792
|
+
# File meta data
|
3793
|
+
file_info = {
|
3794
|
+
"Author": author,
|
3795
|
+
"Date": formatted_date
|
3796
|
+
}
|
3797
|
+
|
3798
|
+
# Instantiate and save File object
|
3799
|
+
file = dotbimpy.File(version, meshes=meshes, elements=elements, info=file_info)
|
3800
|
+
try:
|
3801
|
+
file.save(path)
|
3802
|
+
return True
|
3803
|
+
except:
|
3804
|
+
return False
|
3805
|
+
|
3320
3806
|
@staticmethod
|
3321
3807
|
def ExportToBREP(topology, path, overwrite=False, version=3):
|
3322
3808
|
"""
|
@@ -4261,11 +4747,11 @@ class Topology():
|
|
4261
4747
|
"""
|
4262
4748
|
from topologicpy.Vertex import Vertex
|
4263
4749
|
from topologicpy.Vector import Vector
|
4264
|
-
|
4750
|
+
|
4265
4751
|
if not Topology.IsInstance(topology, "Topology"):
|
4266
4752
|
print("Topology.Flatten - Error: the input topology parameter is not a valid topology. Returning None.")
|
4267
4753
|
return None
|
4268
|
-
if origin
|
4754
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
4269
4755
|
origin = Topology.Centroid(topology)
|
4270
4756
|
up = Vector.Up()
|
4271
4757
|
flat_topology = Topology.Translate(topology, -Vertex.X(origin, mantissa=mantissa), -Vertex.Y(origin, mantissa=mantissa), -Vertex.Z(origin, mantissa=mantissa))
|
@@ -5417,12 +5903,13 @@ class Topology():
|
|
5417
5903
|
if not Topology.IsInstance(topology, "Topology"):
|
5418
5904
|
print("Topology.Rotate - Error: The input topology parameter is not a valid topologic topology. Returning None.")
|
5419
5905
|
return None
|
5420
|
-
if not origin:
|
5906
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
5421
5907
|
origin = Vertex.ByCoordinates(0, 0, 0)
|
5422
5908
|
if not Topology.IsInstance(origin, "Vertex"):
|
5423
5909
|
print("Topology.Rotate - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
5424
5910
|
return None
|
5425
5911
|
returnTopology = topology
|
5912
|
+
d = Topology.Dictionary(topology)
|
5426
5913
|
if abs(angle) >= angTolerance:
|
5427
5914
|
try:
|
5428
5915
|
x, y, z = axis
|
@@ -5437,9 +5924,141 @@ class Topology():
|
|
5437
5924
|
rot_vertices = [Vertex.ByCoordinates(rot_v) for rot_v in rot_vertices]
|
5438
5925
|
new_topology = Topology.ReplaceVertices(topology, verticesA=Topology.Vertices(topology), verticesB=rot_vertices)
|
5439
5926
|
new_topology = Topology.SelfMerge(new_topology, tolerance=tolerance)
|
5927
|
+
if len(Dictionary.Keys(d) > 0):
|
5928
|
+
new_topology = Topology.SetDictionary(new_topology, d)
|
5440
5929
|
return new_topology
|
5930
|
+
if len(Dictionary.Keys(d)) > 0:
|
5931
|
+
returnTopology = Topology.SetDictionary(returnTopology, d)
|
5441
5932
|
return returnTopology
|
5442
5933
|
|
5934
|
+
@staticmethod
|
5935
|
+
def RotateByEulerAngles(topology, origin = None, roll: float = 0, pitch: float = 0, yaw: float = 0, angTolerance: float = 0.001, tolerance: float = 0.0001):
|
5936
|
+
"""
|
5937
|
+
Rotates the input topology using Euler angles (roll, pitch, yaw). See https://en.wikipedia.org/wiki/Aircraft_principal_axes
|
5938
|
+
|
5939
|
+
Parameters
|
5940
|
+
----------
|
5941
|
+
topology : topologic_core.Topology
|
5942
|
+
The input topology.
|
5943
|
+
origin : topologic_core.Vertex , optional
|
5944
|
+
The origin (center) of the rotation. If set to None, the world origin (0, 0, 0) is used. The default is None.
|
5945
|
+
roll : float , optional
|
5946
|
+
The rotation angle in degrees around the X-axis. The default is 0.
|
5947
|
+
pitch = float , optional
|
5948
|
+
The rotation angle in degrees around the Y-axis. The default is 0.
|
5949
|
+
yaw = float , optional
|
5950
|
+
The rotation angle in degrees around the Z-axis. The default is 0.
|
5951
|
+
angTolerance : float , optional
|
5952
|
+
The angle tolerance in degrees under which no rotation is carried out. The default is 0.001 degrees.
|
5953
|
+
tolerance : float , optional
|
5954
|
+
The desired tolerance. The default is 0.0001.
|
5955
|
+
|
5956
|
+
Returns
|
5957
|
+
-------
|
5958
|
+
topologic_core.Topology
|
5959
|
+
The rotated topology.
|
5960
|
+
|
5961
|
+
"""
|
5962
|
+
from topologicpy.Vertex import Vertex
|
5963
|
+
from topologicpy.Dictionary import Dictionary
|
5964
|
+
|
5965
|
+
if not Topology.IsInstance(topology, "Topology"):
|
5966
|
+
print("Topology.RotateByEulerAngles - Error: The input topology parameter is not a valid topologic topology. Returning None.")
|
5967
|
+
return None
|
5968
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
5969
|
+
origin = Vertex.ByCoordinates(0, 0, 0)
|
5970
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
5971
|
+
print("Topology.RotateByEulerAngles - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
5972
|
+
return None
|
5973
|
+
d = Topology.Dictionary(topology)
|
5974
|
+
return_topology = Topology.Copy(topology)
|
5975
|
+
return_topology = Topology.Rotate(return_topology, origin=origin, axis=[1,0,0], angle=roll, angTolerance=angTolerance, tolerance=tolerance)
|
5976
|
+
return_topology = Topology.Rotate(return_topology, origin=origin, axis=[0,1,0], angle=pitch, angTolerance=angTolerance, tolerance=tolerance)
|
5977
|
+
return_topology = Topology.Rotate(return_topology, origin=origin, axis=[0,0,1], angle=yaw, angTolerance=angTolerance, tolerance=tolerance)
|
5978
|
+
if len(Dictionary.Keys(d)) > 0:
|
5979
|
+
return_topology = Topology.SetDictionary(return_topology, d)
|
5980
|
+
return return_topology
|
5981
|
+
|
5982
|
+
@staticmethod
|
5983
|
+
def RotateByQuaternion(topology, origin=None, quaternion: list = [0,0,0,1], angTolerance: float = 0.001, tolerance: float = 0.0001):
|
5984
|
+
"""
|
5985
|
+
Rotates the input topology using Quaternion rotations. See https://en.wikipedia.org/wiki/Quaternion
|
5986
|
+
|
5987
|
+
Parameters
|
5988
|
+
----------
|
5989
|
+
topology : topologic_core.Topology
|
5990
|
+
The input topology.
|
5991
|
+
origin : topologic_core.Vertex , optional
|
5992
|
+
The origin (center) of the rotation. If set to None, the world origin (0, 0, 0) is used. The default is None.
|
5993
|
+
quaternion : list or numpy array of size 4
|
5994
|
+
The input Quaternion list. It should be in the form [x, y, z, w].
|
5995
|
+
angTolerance : float , optional
|
5996
|
+
The angle tolerance in degrees under which no rotation is carried out. The default is 0.001 degrees.
|
5997
|
+
tolerance : float , optional
|
5998
|
+
The desired tolerance. The default is 0.0001.
|
5999
|
+
|
6000
|
+
Returns
|
6001
|
+
-------
|
6002
|
+
topologic_core.Topology
|
6003
|
+
The rotated topology.
|
6004
|
+
|
6005
|
+
"""
|
6006
|
+
from topologicpy.Vertex import Vertex
|
6007
|
+
from topologicpy.Dictionary import Dictionary
|
6008
|
+
|
6009
|
+
def quaternion_to_euler(quaternion):
|
6010
|
+
"""
|
6011
|
+
Convert a quaternion into Euler angles (roll, pitch, yaw)
|
6012
|
+
Roll is rotation around x-axis, Pitch is rotation around y-axis, and Yaw is rotation around z-axis.
|
6013
|
+
Quaternion should be in the form [x, y, z, w]
|
6014
|
+
|
6015
|
+
Args:
|
6016
|
+
quaternion: list or numpy array of size 4
|
6017
|
+
|
6018
|
+
Returns:
|
6019
|
+
A list of Euler angles in degrees [roll, pitch, yaw]
|
6020
|
+
"""
|
6021
|
+
import numpy as np
|
6022
|
+
x, y, z, w = quaternion
|
6023
|
+
|
6024
|
+
# Roll (x-axis rotation)
|
6025
|
+
sinr_cosp = 2 * (w * x + y * z)
|
6026
|
+
cosr_cosp = 1 - 2 * (x * x + y * y)
|
6027
|
+
roll = np.arctan2(sinr_cosp, cosr_cosp)
|
6028
|
+
|
6029
|
+
# Pitch (y-axis rotation)
|
6030
|
+
sinp = 2 * (w * y - z * x)
|
6031
|
+
if abs(sinp) >= 1:
|
6032
|
+
pitch = np.sign(sinp) * np.pi / 2 # use 90 degrees if out of range
|
6033
|
+
else:
|
6034
|
+
pitch = np.arcsin(sinp)
|
6035
|
+
|
6036
|
+
# Yaw (z-axis rotation)
|
6037
|
+
siny_cosp = 2 * (w * z + x * y)
|
6038
|
+
cosy_cosp = 1 - 2 * (y * y + z * z)
|
6039
|
+
yaw = np.arctan2(siny_cosp, cosy_cosp)
|
6040
|
+
|
6041
|
+
# Convert radians to degrees
|
6042
|
+
roll = np.degrees(roll)
|
6043
|
+
pitch = np.degrees(pitch)
|
6044
|
+
yaw = np.degrees(yaw)
|
6045
|
+
return [roll, pitch, yaw]
|
6046
|
+
|
6047
|
+
if not Topology.IsInstance(topology, "Topology"):
|
6048
|
+
print("Topology.RotateByQuaternion - Error: The input topology parameter is not a valid topologic topology. Returning None.", topology)
|
6049
|
+
return None
|
6050
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
6051
|
+
origin = Vertex.ByCoordinates(0, 0, 0)
|
6052
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
6053
|
+
print("Topology.RotateByQuaternion - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
6054
|
+
return None
|
6055
|
+
roll, pitch, yaw = quaternion_to_euler(quaternion)
|
6056
|
+
d = Topology.Dictionary(topology)
|
6057
|
+
return_topology = Topology.RotateByEulerAngles(topology=topology, origin=origin, roll=roll, pitch=pitch, yaw=yaw, angTolerance=angTolerance, tolerance=tolerance)
|
6058
|
+
if len(Dictionary.Keys(d)) > 0:
|
6059
|
+
return_topology = Topology.SetDictionary(return_topology, d)
|
6060
|
+
return return_topology
|
6061
|
+
|
5443
6062
|
@staticmethod
|
5444
6063
|
def Scale(topology, origin=None, x=1, y=1, z=1):
|
5445
6064
|
"""
|
@@ -5467,7 +6086,7 @@ class Topology():
|
|
5467
6086
|
from topologicpy.Vertex import Vertex
|
5468
6087
|
if not Topology.IsInstance(topology, "Topology"):
|
5469
6088
|
return None
|
5470
|
-
if not origin:
|
6089
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
5471
6090
|
origin = Vertex.ByCoordinates(0, 0, 0)
|
5472
6091
|
if not Topology.IsInstance(origin, "Vertex"):
|
5473
6092
|
return None
|
@@ -6216,7 +6835,7 @@ class Topology():
|
|
6216
6835
|
from topologicpy.CellComplex import CellComplex
|
6217
6836
|
from topologicpy.Cluster import Cluster
|
6218
6837
|
|
6219
|
-
if not origin:
|
6838
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
6220
6839
|
origin = Vertex.ByCoordinates(0, 0, 0)
|
6221
6840
|
if not Topology.IsInstance(topology, "Topology"):
|
6222
6841
|
if not silent:
|
@@ -6336,7 +6955,7 @@ class Topology():
|
|
6336
6955
|
return topology
|
6337
6956
|
if triangulate == True:
|
6338
6957
|
topology = Topology.Triangulate(topology)
|
6339
|
-
if origin
|
6958
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
6340
6959
|
origin = Topology.Centroid(topology)
|
6341
6960
|
vertices = Topology.Vertices(topology)
|
6342
6961
|
zList = [Vertex.Z(v, mantissa=mantissa) for v in vertices]
|
@@ -6389,7 +7008,7 @@ class Topology():
|
|
6389
7008
|
return topology
|
6390
7009
|
if triangulate == True:
|
6391
7010
|
topology = Topology.Triangulate(topology)
|
6392
|
-
if origin
|
7011
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
6393
7012
|
origin = Topology.Centroid(topology)
|
6394
7013
|
|
6395
7014
|
vertices = Topology.Vertices(topology)
|
@@ -6433,7 +7052,7 @@ class Topology():
|
|
6433
7052
|
if not Topology.IsInstance(topology, "Topology"):
|
6434
7053
|
print("Topology.Unflatten - Error: the input topology parameter is not a valid topology. Returning None.")
|
6435
7054
|
return None
|
6436
|
-
if origin
|
7055
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
6437
7056
|
origin = Vertex.Origin()
|
6438
7057
|
up = Vector.Up()
|
6439
7058
|
tran_mat = Vector.TransformationMatrix(up, direction)
|
@@ -7029,6 +7648,7 @@ class Topology():
|
|
7029
7648
|
if transferDictionaries:
|
7030
7649
|
selectors.append(Topology.SetDictionary(Face.Centroid(triFace), Topology.Dictionary(aFace)))
|
7031
7650
|
faceTriangles.append(triFace)
|
7651
|
+
return_topology = None
|
7032
7652
|
if t == Topology.TypeID("Face") or t == Topology.TypeID("Shell"): # Face or Shell
|
7033
7653
|
return_topology = Shell.ByFaces(faceTriangles, tolerance=tolerance)
|
7034
7654
|
if transferDictionaries and not return_topology == None:
|