topologicpy 0.5.4__py3-none-any.whl → 0.5.5__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/Graph.py CHANGED
@@ -527,6 +527,370 @@ class Graph:
527
527
  lcc = Graph.LocalClusteringCoefficient(graph, vertices)
528
528
  acc = round(sum(lcc)/float(len(lcc)), mantissa)
529
529
  return acc
530
+
531
+ @staticmethod
532
+ def BOTGraph(graph,
533
+ bidirectional=False,
534
+ includeAttributes=False,
535
+ includeLabel=False,
536
+ siteLabel = "Site_0001",
537
+ siteDictionary = None,
538
+ buildingLabel = "Building_0001",
539
+ buildingDictionary = None ,
540
+ storeyPrefix = "Storey",
541
+ floorLevels =[],
542
+ labelKey="label",
543
+ typeKey="type",
544
+ sourceKey="source",
545
+ targetKey="target",
546
+ xKey = "x",
547
+ yKey = "y",
548
+ zKey = "z",
549
+ spaceType = "space",
550
+ wallType = "wall",
551
+ slabType = "slab",
552
+ doorType = "door",
553
+ windowType = "window",
554
+ contentType = "content"
555
+ ):
556
+ """
557
+ Creates an RDF graph according to the BOT ontology. See https://w3c-lbd-cg.github.io/bot/.
558
+
559
+ Parameters
560
+ ----------
561
+ graph : topologic.Graph
562
+ The input graph.
563
+ bidirectional : bool , optional
564
+ If set to True, reverse relationships are created wherever possible. Otherwise, they are not. The default is False.
565
+ includeAttributes : bool , optional
566
+ If set to True, the attributes associated with vertices in the graph are written out. Otherwise, they are not. The default is False.
567
+ includeLabel : bool , optional
568
+ If set to True, a label is attached to each node. Otherwise, it is not. The default is False.
569
+ siteLabel : str , optional
570
+ The desired site label. The default is "Site_0001".
571
+ siteDictionary : dict , optional
572
+ The dictionary of site attributes to include in the output. The default is None.
573
+ buildingLabel : str , optional
574
+ The desired building label. The default is "Building_0001".
575
+ buildingDictionary : dict , optional
576
+ The dictionary of building attributes to include in the output. The default is None.
577
+ storeyPrefix : str , optional
578
+ The desired prefixed to use for each building storey. The default is "Storey".
579
+ floorLevels : list , optional
580
+ The list of floor levels. This should be a numeric list, sorted from lowest to highest.
581
+ If not provided, floorLevels will be computed automatically based on the nodes' 'z' attribute.
582
+ typeKey : str , optional
583
+ The dictionary key to use to look up the type of the node. The default is "type".
584
+ labelKey : str , optional
585
+ The dictionary key to use to look up the label of the node. The default is "label".
586
+ sourceKey : str , optional
587
+ The desired dictionary key to use to store the source vertex. The default is "source".
588
+ targetKey : str , optional
589
+ The desired dictionary key to use to store the target vertex. The default is "target".
590
+ xKey : str , optional
591
+ The dictionary key to use to look up the x-coordinate of the node. The default is "x".
592
+ yKey : str , optional
593
+ The dictionary key to use to look up the y-coordinate of the node. The default is "y".
594
+ zKey : str , optional
595
+ The dictionary key to use to look up the z-coordinate of the node. The default is "z".
596
+ spaceType : str , optional
597
+ The dictionary string value to use to look up nodes of type "space". The default is "space".
598
+ wallType : str , optional
599
+ The dictionary string value to use to look up nodes of type "wall". The default is "wall".
600
+ slabType : str , optional
601
+ The dictionary string value to use to look up nodes of type "slab". The default is "slab".
602
+ doorType : str , optional
603
+ The dictionary string value to use to look up nodes of type "door". The default is "door".
604
+ windowType : str , optional
605
+ The dictionary string value to use to look up nodes of type "window". The default is "window".
606
+ contentType : str , optional
607
+ The dictionary string value to use to look up nodes of type "content". The default is "contents".
608
+
609
+ Returns
610
+ -------
611
+ rdflib.graph.Graph
612
+ The rdf graph using the BOT ontology.
613
+ """
614
+
615
+ from topologicpy.Helper import Helper
616
+ import os
617
+ import warnings
618
+
619
+ try:
620
+ from rdflib import Graph as RDFGraph
621
+ from rdflib import URIRef, Literal, Namespace
622
+ from rdflib.namespace import RDF, RDFS
623
+ except:
624
+ print("Graph.BOTGraph - Installing required rdflib library.")
625
+ try:
626
+ os.system("pip install rdflib")
627
+ except:
628
+ os.system("pip install rdflib --user")
629
+ try:
630
+ from rdflib import Graph as RDFGraph
631
+ from rdflib import URIRef, Literal, Namespace
632
+ from rdflib.namespace import RDF, RDFS
633
+ print("Graph.BOTGraph - rdflib library installed correctly.")
634
+ except:
635
+ warnings.warn("Graph.BOTGraph - Error: Could not import rdflib. Please try to install rdflib manually. Returning None.")
636
+ return None
637
+
638
+ if floorLevels == None:
639
+ floorLevels = []
640
+ json_data = Graph.JSONData(graph, vertexLabelKey=labelKey)
641
+ # Create an empty RDF graph
642
+ rdf_graph = RDFGraph()
643
+
644
+ # Define namespaces
645
+ rdf = Namespace("http://www.w3.org/1999/02/22-rdf-syntax-ns#")
646
+ rdfs = Namespace("http://www.w3.org/2000/01/rdf-schema#")
647
+ bot = Namespace("https://w3id.org/bot#")
648
+
649
+ # Define a custom prefix mapping
650
+ rdf_graph.namespace_manager.bind("bot", bot)
651
+
652
+ # Add site
653
+ site_uri = URIRef(siteLabel)
654
+ rdf_graph.add((site_uri, rdf.type, bot.Site))
655
+ if includeLabel:
656
+ rdf_graph.add((site_uri, RDFS.label, Literal("Site_0001")))
657
+ if isinstance(siteDictionary, topologic.Dictionary):
658
+ keys = Dictionary.Keys(siteDictionary)
659
+ for key in keys:
660
+ value = Dictionary.ValueAtKey(siteDictionary, key)
661
+ if key == labelKey:
662
+ if includeLabel:
663
+ rdf_graph.add((site_uri, RDFS.label, Literal(value)))
664
+ elif key != typeKey:
665
+ rdf_graph.add((site_uri, bot[key], Literal(value)))
666
+ # Add building
667
+ building_uri = URIRef(buildingLabel)
668
+ rdf_graph.add((building_uri, rdf.type, bot.Building))
669
+ if includeLabel:
670
+ rdf_graph.add((building_uri, RDFS.label, Literal(buildingLabel)))
671
+ if isinstance(buildingDictionary, topologic.Dictionary):
672
+ keys = Dictionary.Keys(buildingDictionary)
673
+ for key in keys:
674
+ value = Dictionary.ValueAtKey(buildingDictionary, key)
675
+ if key == labelKey:
676
+ if includeLabel:
677
+ rdf_graph.add((building_uri, RDFS.label, Literal(value)))
678
+ elif key != typeKey:
679
+ rdf_graph.add((building_uri, bot[key], Literal(value)))
680
+ # Add stories
681
+ # if floor levels are not given, then need to be computed
682
+ if len(floorLevels) == 0:
683
+ for node, attributes in json_data['nodes'].items():
684
+ if slabType.lower() in attributes[typeKey].lower():
685
+ floorLevels.append(attributes[zKey])
686
+ floorLevels = list(set(floorLevels))
687
+ floorLevels.sort()
688
+ storey_uris = []
689
+ n = max(len(str(len(floorLevels))),4)
690
+ for i, floor_level in enumerate(floorLevels):
691
+ storey_uri = URIRef(storeyPrefix+"_"+str(i+1).zfill(n))
692
+ rdf_graph.add((storey_uri, rdf.type, bot.Storey))
693
+ if includeLabel:
694
+ rdf_graph.add((storey_uri, RDFS.label, Literal(storeyPrefix+"_"+str(i+1).zfill(n))))
695
+ storey_uris.append(storey_uri)
696
+
697
+ # Add triples to relate building to site and stories to building
698
+ rdf_graph.add((site_uri, bot.hasBuilding, building_uri))
699
+ if bidirectional:
700
+ rdf_graph.add((building_uri, bot.isPartOf, site_uri)) # might not be needed
701
+
702
+ for storey_uri in storey_uris:
703
+ rdf_graph.add((building_uri, bot.hasStorey, storey_uri))
704
+ if bidirectional:
705
+ rdf_graph.add((storey_uri, bot.isPartOf, building_uri)) # might not be needed
706
+
707
+ # Add vertices as RDF resources
708
+ for node, attributes in json_data['nodes'].items():
709
+ node_uri = URIRef(node)
710
+ if spaceType.lower() in attributes[typeKey].lower():
711
+ rdf_graph.add((node_uri, rdf.type, bot.Space))
712
+ # Find the storey it is on
713
+ z = attributes[zKey]
714
+ level = Helper.Position(z, floorLevels)
715
+ if level > len(storey_uris):
716
+ level = len(storey_uris)
717
+ storey_uri = storey_uris[level-1]
718
+ rdf_graph.add((storey_uri, bot.hasSpace, node_uri))
719
+ if bidirectional:
720
+ rdf_graph.add((node_uri, bot.isPartOf, storey_uri)) # might not be needed
721
+ elif windowType.lower() in attributes[typeKey].lower():
722
+ rdf_graph.add((node_uri, rdf.type, bot.Window))
723
+ elif doorType.lower() in attributes[typeKey].lower():
724
+ rdf_graph.add((node_uri, rdf.type, bot.Door))
725
+ elif wallType.lower() in attributes[typeKey].lower():
726
+ rdf_graph.add((node_uri, rdf.type, bot.Wall))
727
+ elif slabType.lower() in attributes[typeKey].lower():
728
+ rdf_graph.add((node_uri, rdf.type, bot.Slab))
729
+ else:
730
+ rdf_graph.add((node_uri, rdf.type, bot.Element))
731
+
732
+ if includeAttributes:
733
+ for key, value in attributes.items():
734
+ if key == labelKey:
735
+ if includeLabel:
736
+ rdf_graph.add((node_uri, RDFS.label, Literal(value)))
737
+ elif key != typeKey:
738
+ rdf_graph.add((node_uri, bot[key], Literal(value)))
739
+ if includeLabel:
740
+ for key, value in attributes.items():
741
+ if key == labelKey:
742
+ rdf_graph.add((node_uri, RDFS.label, Literal(value)))
743
+
744
+ # Add edges as RDF triples
745
+ for edge, attributes in json_data['edges'].items():
746
+ source = attributes[sourceKey]
747
+ target = attributes[targetKey]
748
+ source_uri = URIRef(source)
749
+ target_uri = URIRef(target)
750
+ if spaceType.lower() in json_data['nodes'][source][typeKey].lower() and spaceType.lower() in json_data['nodes'][target][typeKey].lower():
751
+ rdf_graph.add((source_uri, bot.adjacentTo, target_uri))
752
+ if bidirectional:
753
+ rdf_graph.add((target_uri, bot.adjacentTo, source_uri))
754
+ elif spaceType.lower() in json_data['nodes'][source][typeKey].lower() and wallType.lower() in json_data['nodes'][target][typeKey].lower():
755
+ rdf_graph.add((target_uri, bot.interfaceOf, source_uri))
756
+ elif spaceType.lower() in json_data['nodes'][source][typeKey].lower() and slabType.lower() in json_data['nodes'][target][typeKey].lower():
757
+ rdf_graph.add((target_uri, bot.interfaceOf, source_uri))
758
+ elif spaceType.lower() in json_data['nodes'][source][typeKey].lower() and contentType.lower() in json_data['nodes'][target][typeKey].lower():
759
+ rdf_graph.add((source_uri, bot.containsElement, target_uri))
760
+ if bidirectional:
761
+ rdf_graph.add((target_uri, bot.isPartOf, source_uri))
762
+ else:
763
+ rdf_graph.add((source_uri, bot.connectsTo, target_uri))
764
+ if bidirectional:
765
+ rdf_graph.add((target_uri, bot.connectsTo, source_uri))
766
+ #for key, value in attributes.items():
767
+ #rdf_graph.add((source_uri, bot[key], Literal(value)))
768
+ # Return serialized RDF graph
769
+ #rdf_serialized = rdf_graph.serialize(format=format)
770
+ return rdf_graph
771
+
772
+ @staticmethod
773
+ def BOTString(graph,
774
+ format="turtle",
775
+ bidirectional=False,
776
+ includeAttributes=False,
777
+ includeLabel=False,
778
+ siteLabel = "Site_0001",
779
+ siteDictionary = None,
780
+ buildingLabel = "Building_0001",
781
+ buildingDictionary = None ,
782
+ storeyPrefix = "Storey",
783
+ floorLevels =[],
784
+ labelKey="label",
785
+ typeKey="type",
786
+ sourceKey="source",
787
+ targetKey="target",
788
+ xKey = "x",
789
+ yKey = "y",
790
+ zKey = "z",
791
+ spaceType = "space",
792
+ wallType = "wall",
793
+ slabType = "slab",
794
+ doorType = "door",
795
+ windowType = "window",
796
+ contentType = "content",
797
+ ):
798
+
799
+ """
800
+ Returns an RDF graph serialized string according to the BOT ontology. See https://w3c-lbd-cg.github.io/bot/.
801
+
802
+ Parameters
803
+ ----------
804
+ graph : topologic.Graph
805
+ The input graph.
806
+ format : str , optional
807
+ The desired output format, the options are listed below. Thde default is "turtle".
808
+ turtle, ttl or turtle2 : Turtle, turtle2 is just turtle with more spacing & linebreaks
809
+ xml or pretty-xml : RDF/XML, Was the default format, rdflib < 6.0.0
810
+ json-ld : JSON-LD , There are further options for compact syntax and other JSON-LD variants
811
+ ntriples, nt or nt11 : N-Triples , nt11 is exactly like nt, only utf8 encoded
812
+ n3 : Notation-3 , N3 is a superset of Turtle that also caters for rules and a few other things
813
+ trig : Trig , Turtle-like format for RDF triples + context (RDF quads) and thus multiple graphs
814
+ trix : Trix , RDF/XML-like format for RDF quads
815
+ nquads : N-Quads , N-Triples-like format for RDF quads
816
+ bidirectional : bool , optional
817
+ If set to True, reverse relationships are created wherever possible. Otherwise, they are not. The default is False.
818
+ includeAttributes : bool , optional
819
+ If set to True, the attributes associated with vertices in the graph are written out. Otherwise, they are not. The default is False.
820
+ includeLabel : bool , optional
821
+ If set to True, a label is attached to each node. Otherwise, it is not. The default is False.
822
+ siteLabel : str , optional
823
+ The desired site label. The default is "Site_0001".
824
+ siteDictionary : dict , optional
825
+ The dictionary of site attributes to include in the output. The default is None.
826
+ buildingLabel : str , optional
827
+ The desired building label. The default is "Building_0001".
828
+ buildingDictionary : dict , optional
829
+ The dictionary of building attributes to include in the output. The default is None.
830
+ storeyPrefix : str , optional
831
+ The desired prefixed to use for each building storey. The default is "Storey".
832
+ floorLevels : list , optional
833
+ The list of floor levels. This should be a numeric list, sorted from lowest to highest.
834
+ If not provided, floorLevels will be computed automatically based on the nodes' 'z' attribute.
835
+ typeKey : str , optional
836
+ The dictionary key to use to look up the type of the node. The default is "type".
837
+ labelKey : str , optional
838
+ The dictionary key to use to look up the label of the node. The default is "label".
839
+ sourceKey : str , optional
840
+ The desired dictionary key to use to store the source vertex. The default is "source".
841
+ targetKey : str , optional
842
+ The desired dictionary key to use to store the target vertex. The default is "target".
843
+ xKey : str , optional
844
+ The dictionary key to use to look up the x-coordinate of the node. The default is "x".
845
+ yKey : str , optional
846
+ The dictionary key to use to look up the y-coordinate of the node. The default is "y".
847
+ zKey : str , optional
848
+ The dictionary key to use to look up the z-coordinate of the node. The default is "z".
849
+ spaceType : str , optional
850
+ The dictionary string value to use to look up nodes of type "space". The default is "space".
851
+ wallType : str , optional
852
+ The dictionary string value to use to look up nodes of type "wall". The default is "wall".
853
+ slabType : str , optional
854
+ The dictionary string value to use to look up nodes of type "slab". The default is "slab".
855
+ doorType : str , optional
856
+ The dictionary string value to use to look up nodes of type "door". The default is "door".
857
+ windowType : str , optional
858
+ The dictionary string value to use to look up nodes of type "window". The default is "window".
859
+ contentType : str , optional
860
+ The dictionary string value to use to look up nodes of type "content". The default is "contents".
861
+
862
+
863
+ Returns
864
+ -------
865
+ str
866
+ The rdf graph serialized string using the BOT ontology.
867
+ """
868
+
869
+ bot_graph = Graph.BOTGraph(graph,
870
+ bidirectional=bidirectional,
871
+ includeAttributes=includeAttributes,
872
+ includeLabel=includeLabel,
873
+ siteLabel=siteLabel,
874
+ siteDictionary=siteDictionary,
875
+ buildingLabel=buildingLabel,
876
+ buildingDictionary=buildingDictionary,
877
+ storeyPrefix=storeyPrefix,
878
+ floorLevels=floorLevels,
879
+ labelKey=labelKey,
880
+ typeKey=typeKey,
881
+ sourceKey=sourceKey,
882
+ targetKey=targetKey,
883
+ xKey=xKey,
884
+ yKey=yKey,
885
+ zKey=zKey,
886
+ spaceType = spaceType,
887
+ wallType = wallType,
888
+ slabType = slabType,
889
+ doorType = doorType,
890
+ windowType = windowType,
891
+ contentType = contentType
892
+ )
893
+ return bot_graph.serialize(format=format)
530
894
 
531
895
  @staticmethod
532
896
  def BetweenessCentrality(graph, vertices=None, sources=None, destinations=None, tolerance=0.001):
@@ -1469,6 +1833,7 @@ class Graph:
1469
1833
  from topologicpy.Edge import Edge
1470
1834
  from topologicpy.Cluster import Cluster
1471
1835
  from topologicpy.Topology import Topology
1836
+ from topologicpy.Aperture import Aperture
1472
1837
 
1473
1838
  def mergeDictionaries(sources):
1474
1839
  if isinstance(sources, list) == False:
@@ -1687,7 +2052,7 @@ class Graph:
1687
2052
 
1688
2053
  cells = []
1689
2054
  _ = topology.Cells(None, cells)
1690
- if (viaSharedTopologies == True) or (viaSharedApertures == True) or (toExteriorTopologies == True) or (toExteriorApertures == True) or (toContents == True):
2055
+ if any([viaSharedTopologies, viaSharedApertures, toExteriorTopologies, toExteriorApertures, toContents]):
1691
2056
  for aCell in cells:
1692
2057
  if useInternalVertex == True:
1693
2058
  vCell = Topology.InternalVertex(aCell, tolerance=tolerance)
@@ -1710,9 +2075,9 @@ class Graph:
1710
2075
  contents = []
1711
2076
  _ = aCell.Contents(contents)
1712
2077
  for aFace in faces:
1713
- cells = []
1714
- _ = aFace.Cells(topology, cells)
1715
- if len(cells) > 1:
2078
+ cells1 = []
2079
+ _ = aFace.Cells(topology, cells1)
2080
+ if len(cells1) > 1:
1716
2081
  sharedTopologies.append(aFace)
1717
2082
  apertures = []
1718
2083
  _ = aFace.Apertures(apertures)
@@ -1724,6 +2089,7 @@ class Graph:
1724
2089
  _ = aFace.Apertures(apertures)
1725
2090
  for anAperture in apertures:
1726
2091
  exteriorApertures.append(anAperture)
2092
+
1727
2093
  if viaSharedTopologies:
1728
2094
  for sharedTopology in sharedTopologies:
1729
2095
  if useInternalVertex == True:
@@ -1746,6 +2112,8 @@ class Graph:
1746
2112
  contents = []
1747
2113
  _ = sharedTopology.Contents(contents)
1748
2114
  for content in contents:
2115
+ if isinstance(content, topologic.Aperture):
2116
+ content = Aperture.Topology(content)
1749
2117
  if useInternalVertex == True:
1750
2118
  vst2 = Topology.InternalVertex(content, tolerance)
1751
2119
  else:
@@ -1767,38 +2135,38 @@ class Graph:
1767
2135
  for sharedAperture in sharedApertures:
1768
2136
  sharedAp = sharedAperture.Topology()
1769
2137
  if useInternalVertex == True:
1770
- vst = Topology.InternalVertex(sharedAp, tolerance)
2138
+ vsa = Topology.InternalVertex(sharedAp, tolerance)
1771
2139
  else:
1772
- vst = sharedAp.CenterOfMass()
2140
+ vsa = sharedAp.CenterOfMass()
1773
2141
  d1 = sharedAp.GetDictionary()
1774
- vst = topologic.Vertex.ByCoordinates(vst.X()+(tolerance*100), vst.Y()+(tolerance*100), vst.Z()+(tolerance*100))
2142
+ vsa = topologic.Vertex.ByCoordinates(vsa.X()+(tolerance*100), vsa.Y()+(tolerance*100), vsa.Z()+(tolerance*100))
1775
2143
  if storeBRep:
1776
2144
  d2 = Dictionary.ByKeysValues(["brep", "brepType", "brepTypeString"], [Topology.BREPString(sharedAperture), Topology.Type(sharedAperture), Topology.TypeAsString(sharedAperture)])
1777
2145
  d3 = mergeDictionaries2([d1, d2])
1778
- _ = vst.SetDictionary(d3)
2146
+ _ = vsa.SetDictionary(d3)
1779
2147
  else:
1780
- _ = vst.SetDictionary(d1)
1781
- vertices.append(vst)
1782
- tempe = Edge.ByStartVertexEndVertex(vCell, vst, tolerance=tolerance)
2148
+ _ = vsa.SetDictionary(d1)
2149
+ vertices.append(vsa)
2150
+ tempe = Edge.ByStartVertexEndVertex(vCell, vsa, tolerance=tolerance)
1783
2151
  tempd = Dictionary.ByKeysValues(["relationship"],["Via Shared Apertures"])
1784
2152
  _ = tempe.SetDictionary(tempd)
1785
2153
  edges.append(tempe)
1786
2154
  if toExteriorTopologies:
1787
2155
  for exteriorTopology in exteriorTopologies:
1788
2156
  if useInternalVertex == True:
1789
- vst = Topology.InternalVertex(exteriorTopology, tolerance)
2157
+ vet = Topology.InternalVertex(exteriorTopology, tolerance)
1790
2158
  else:
1791
- vst = exteriorTopology.CenterOfMass()
1792
- _ = vst.SetDictionary(exteriorTopology.GetDictionary())
2159
+ vet = exteriorTopology.CenterOfMass()
2160
+ _ = vet.SetDictionary(exteriorTopology.GetDictionary())
1793
2161
  d1 = exteriorTopology.GetDictionary()
1794
2162
  if storeBRep:
1795
2163
  d2 = Dictionary.ByKeysValues(["brep", "brepType", "brepTypeString"], [Topology.BREPString(exteriorTopology), Topology.Type(exteriorTopology), Topology.TypeAsString(exteriorTopology)])
1796
2164
  d3 = mergeDictionaries2([d1, d2])
1797
- _ = vst.SetDictionary(d3)
2165
+ _ = vet.SetDictionary(d3)
1798
2166
  else:
1799
- _ = vst.SetDictionary(d1)
1800
- vertices.append(vst)
1801
- tempe = Edge.ByStartVertexEndVertex(vCell, vst, tolerance=tolerance)
2167
+ _ = vet.SetDictionary(d1)
2168
+ vertices.append(vet)
2169
+ tempe = Edge.ByStartVertexEndVertex(vCell, vet, tolerance=tolerance)
1802
2170
  tempd = Dictionary.ByKeysValues(["relationship"],["To Exterior Topologies"])
1803
2171
  _ = tempe.SetDictionary(tempd)
1804
2172
  edges.append(tempe)
@@ -1806,6 +2174,8 @@ class Graph:
1806
2174
  contents = []
1807
2175
  _ = exteriorTopology.Contents(contents)
1808
2176
  for content in contents:
2177
+ if isinstance(content, topologic.Aperture):
2178
+ content = Aperture.Topology(content)
1809
2179
  if useInternalVertex == True:
1810
2180
  vst2 = Topology.InternalVertex(content, tolerance)
1811
2181
  else:
@@ -1819,7 +2189,7 @@ class Graph:
1819
2189
  else:
1820
2190
  _ = vst2.SetDictionary(d1)
1821
2191
  vertices.append(vst2)
1822
- tempe = Edge.ByStartVertexEndVertex(vst, vst2, tolerance=tolerance)
2192
+ tempe = Edge.ByStartVertexEndVertex(vet, vst2, tolerance=tolerance)
1823
2193
  tempd = Dictionary.ByKeysValues(["relationship"],["To Contents"])
1824
2194
  _ = tempe.SetDictionary(tempd)
1825
2195
  edges.append(tempe)
@@ -1827,19 +2197,19 @@ class Graph:
1827
2197
  for exteriorAperture in exteriorApertures:
1828
2198
  extTop = exteriorAperture.Topology()
1829
2199
  if useInternalVertex == True:
1830
- vst = Topology.InternalVertex(extTop, tolerance)
2200
+ vea = Topology.InternalVertex(extTop, tolerance)
1831
2201
  else:
1832
- vst = exteriorAperture.Topology().CenterOfMass()
2202
+ vea = exteriorAperture.Topology().CenterOfMass()
1833
2203
  d1 = exteriorAperture.Topology().GetDictionary()
1834
- vst = topologic.Vertex.ByCoordinates(vst.X()+(tolerance*100), vst.Y()+(tolerance*100), vst.Z()+(tolerance*100))
2204
+ vea = topologic.Vertex.ByCoordinates(vea.X()+(tolerance*100), vea.Y()+(tolerance*100), vea.Z()+(tolerance*100))
1835
2205
  if storeBRep:
1836
2206
  d2 = Dictionary.ByKeysValues(["brep", "brepType", "brepTypeString"], [Topology.BREPString(exteriorAperture), Topology.Type(exteriorAperture), Topology.TypeAsString(exteriorAperture)])
1837
2207
  d3 = mergeDictionaries2([d1, d2])
1838
- _ = vst.SetDictionary(d3)
2208
+ _ = vea.SetDictionary(d3)
1839
2209
  else:
1840
- _ = vst.SetDictionary(d1)
1841
- vertices.append(vst)
1842
- tempe = Edge.ByStartVertexEndVertex(vCell, vst, tolerance=tolerance)
2210
+ _ = vea.SetDictionary(d1)
2211
+ vertices.append(vea)
2212
+ tempe = Edge.ByStartVertexEndVertex(vCell, vea, tolerance=tolerance)
1843
2213
  tempd = Dictionary.ByKeysValues(["relationship"],["To Exterior Apertures"])
1844
2214
  _ = tempe.SetDictionary(tempd)
1845
2215
  edges.append(tempe)
@@ -1847,20 +2217,22 @@ class Graph:
1847
2217
  contents = []
1848
2218
  _ = aCell.Contents(contents)
1849
2219
  for content in contents:
2220
+ if isinstance(content, topologic.Aperture):
2221
+ content = Aperture.Topology(content)
1850
2222
  if useInternalVertex == True:
1851
- vst = Topology.InternalVertex(content, tolerance)
2223
+ vcn = Topology.InternalVertex(content, tolerance)
1852
2224
  else:
1853
- vst = content.CenterOfMass()
1854
- vst = topologic.Vertex.ByCoordinates(vst.X()+(tolerance*100), vst.Y()+(tolerance*100), vst.Z()+(tolerance*100))
2225
+ vcn = content.CenterOfMass()
2226
+ vcn = topologic.Vertex.ByCoordinates(vcn.X()+(tolerance*100), vcn.Y()+(tolerance*100), vcn.Z()+(tolerance*100))
1855
2227
  d1 = content.GetDictionary()
1856
2228
  if storeBRep:
1857
2229
  d2 = Dictionary.ByKeysValues(["brep", "brepType", "brepTypeString"], [Topology.BREPString(content), Topology.Type(content), Topology.TypeAsString(content)])
1858
2230
  d3 = mergeDictionaries2([d1, d2])
1859
- _ = vst.SetDictionary(d3)
2231
+ _ = vcn.SetDictionary(d3)
1860
2232
  else:
1861
- _ = vst.SetDictionary(d1)
1862
- vertices.append(vst)
1863
- tempe = Edge.ByStartVertexEndVertex(vCell, vst, tolerance=tolerance)
2233
+ _ = vcn.SetDictionary(d1)
2234
+ vertices.append(vcn)
2235
+ tempe = Edge.ByStartVertexEndVertex(vCell, vcn, tolerance=tolerance)
1864
2236
  tempd = Dictionary.ByKeysValues(["relationship"],["To Contents"])
1865
2237
  _ = tempe.SetDictionary(tempd)
1866
2238
  edges.append(tempe)
@@ -1885,7 +2257,7 @@ class Graph:
1885
2257
  vertices = []
1886
2258
  edges = []
1887
2259
  if useInternalVertex == True:
1888
- vCell = Topology.InternalVertex(Topology.Copy(topology), tolerance=tolerance)
2260
+ vCell = Topology.InternalVertex(topology, tolerance=tolerance)
1889
2261
  else:
1890
2262
  vCell = topology.CenterOfMass()
1891
2263
  d1 = topology.GetDictionary()
@@ -1920,7 +2292,7 @@ class Graph:
1920
2292
  tempd = Dictionary.ByKeysValues(["relationship"],["To Outposts"])
1921
2293
  _ = tempe.SetDictionary(tempd)
1922
2294
  edges.append(tempe)
1923
- if (toExteriorTopologies == True) or (toExteriorApertures == True) or (toContents == True):
2295
+ if any([toExteriorTopologies, toExteriorApertures, toContents]):
1924
2296
  faces = Topology.Faces(topology)
1925
2297
  exteriorTopologies = []
1926
2298
  exteriorApertures = []
@@ -1951,6 +2323,8 @@ class Graph:
1951
2323
  contents = []
1952
2324
  _ = exteriorTopology.Contents(contents)
1953
2325
  for content in contents:
2326
+ if isinstance(content, topologic.Aperture):
2327
+ content = Aperture.Topology(content)
1954
2328
  if useInternalVertex == True:
1955
2329
  vst2 = Topology.InternalVertex(content, tolerance)
1956
2330
  else:
@@ -1992,6 +2366,8 @@ class Graph:
1992
2366
  contents = []
1993
2367
  _ = topology.Contents(contents)
1994
2368
  for content in contents:
2369
+ if isinstance(content, topologic.Aperture):
2370
+ content = Aperture.Topology(content)
1995
2371
  if useInternalVertex == True:
1996
2372
  vst = Topology.InternalVertex(content, tolerance)
1997
2373
  else:
@@ -2094,7 +2470,7 @@ class Graph:
2094
2470
 
2095
2471
  topFaces = []
2096
2472
  _ = topology.Faces(None, topFaces)
2097
- if (viaSharedTopologies == True) or (viaSharedApertures == True) or (toExteriorTopologies == True) or (toExteriorApertures == True) or (toContents == True):
2473
+ if any([viaSharedTopologies, viaSharedApertures, toExteriorTopologies, toExteriorApertures, toContents == True]):
2098
2474
  for aFace in topFaces:
2099
2475
  if useInternalVertex == True:
2100
2476
  vFace = Topology.InternalVertex(aFace, tolerance=tolerance)
@@ -2145,6 +2521,8 @@ class Graph:
2145
2521
  contents = []
2146
2522
  _ = sharedTopology.Contents(contents)
2147
2523
  for content in contents:
2524
+ if isinstance(content, topologic.Aperture):
2525
+ content = Aperture.Topology(content)
2148
2526
  if useInternalVertex == True:
2149
2527
  vst2 = Topology.InternalVertex(content, tolerance)
2150
2528
  else:
@@ -2203,6 +2581,8 @@ class Graph:
2203
2581
  contents = []
2204
2582
  _ = exteriorTopology.Contents(contents)
2205
2583
  for content in contents:
2584
+ if isinstance(content, topologic.Aperture):
2585
+ content = Aperture.Topology(content)
2206
2586
  if useInternalVertex == True:
2207
2587
  vst2 = Topology.InternalVertex(content, tolerance)
2208
2588
  else:
@@ -2244,6 +2624,8 @@ class Graph:
2244
2624
  contents = []
2245
2625
  _ = aFace.Contents(contents)
2246
2626
  for content in contents:
2627
+ if isinstance(content, topologic.Aperture):
2628
+ content = Aperture.Topology(content)
2247
2629
  if useInternalVertex == True:
2248
2630
  vst = Topology.InternalVertex(content, tolerance)
2249
2631
  else:
@@ -2388,6 +2770,8 @@ class Graph:
2388
2770
  contents = []
2389
2771
  _ = exteriorTopology.Contents(contents)
2390
2772
  for content in contents:
2773
+ if isinstance(content, topologic.Aperture):
2774
+ content = Aperture.Topology(content)
2391
2775
  if useInternalVertex == True:
2392
2776
  vst2 = Topology.InternalVertex(content, tolerance)
2393
2777
  else:
@@ -2429,6 +2813,8 @@ class Graph:
2429
2813
  contents = []
2430
2814
  _ = topology.Contents(contents)
2431
2815
  for content in contents:
2816
+ if isinstance(content, topologic.Aperture):
2817
+ content = Aperture.Topology(content)
2432
2818
  if useInternalVertex == True:
2433
2819
  vst = Topology.InternalVertex(content, tolerance)
2434
2820
  else:
@@ -2590,6 +2976,8 @@ class Graph:
2590
2976
  contents = []
2591
2977
  _ = sharedTopology.Contents(contents)
2592
2978
  for content in contents:
2979
+ if isinstance(content, topologic.Aperture):
2980
+ content = Aperture.Topology(content)
2593
2981
  if useInternalVertex == True:
2594
2982
  vst2 = Topology.InternalVertex(content, tolerance)
2595
2983
  else:
@@ -2639,6 +3027,8 @@ class Graph:
2639
3027
  contents = []
2640
3028
  _ = vst.Contents(contents)
2641
3029
  for content in contents:
3030
+ if isinstance(content, topologic.Aperture):
3031
+ content = Aperture.Topology(content)
2642
3032
  if useInternalVertex == True:
2643
3033
  vst2 = Topology.InternalVertex(content, tolerance)
2644
3034
  else:
@@ -2680,6 +3070,8 @@ class Graph:
2680
3070
  contents = []
2681
3071
  _ = anEdge.Contents(contents)
2682
3072
  for content in contents:
3073
+ if isinstance(content, topologic.Aperture):
3074
+ content = Aperture.Topology(content)
2683
3075
  if useInternalVertex == True:
2684
3076
  vst = Topology.InternalVertex(content, tolerance)
2685
3077
  else:
@@ -2830,6 +3222,8 @@ class Graph:
2830
3222
  contents = []
2831
3223
  _ = vst.Contents(contents)
2832
3224
  for content in contents:
3225
+ if isinstance(content, topologic.Aperture):
3226
+ content = Aperture.Topology(content)
2833
3227
  if useInternalVertex == True:
2834
3228
  vst2 = Topology.InternalVertex(content, tolerance)
2835
3229
  else:
@@ -2880,6 +3274,8 @@ class Graph:
2880
3274
  contents = []
2881
3275
  _ = topology.Contents(contents)
2882
3276
  for content in contents:
3277
+ if isinstance(content, topologic.Aperture):
3278
+ content = Aperture.Topology(content)
2883
3279
  if useInternalVertex == True:
2884
3280
  vst = Topology.InternalVertex(content, tolerance)
2885
3281
  else:
@@ -2929,7 +3325,6 @@ class Graph:
2929
3325
  if not isinstance(topology, topologic.Topology):
2930
3326
  print("Graph.ByTopology - Error: The input topology is not a valid topology. Returning None.")
2931
3327
  return None
2932
- topology = Topology.Copy(topology)
2933
3328
  graph = None
2934
3329
  item = [topology, None, None, None, direct, directApertures, viaSharedTopologies, viaSharedApertures, toExteriorTopologies, toExteriorApertures, toContents, None, useInternalVertex, storeBRep, tolerance]
2935
3330
  vertices = []
@@ -3699,6 +4094,177 @@ class Graph:
3699
4094
  except:
3700
4095
  return False
3701
4096
 
4097
+ @staticmethod
4098
+ def ExportToBOT(graph,
4099
+ path,
4100
+ format="turtle",
4101
+ overwrite = False,
4102
+ bidirectional=False,
4103
+ includeAttributes=False,
4104
+ includeLabel=False,
4105
+ siteLabel = "Site_0001",
4106
+ siteDictionary = None,
4107
+ buildingLabel = "Building_0001",
4108
+ buildingDictionary = None ,
4109
+ storeyPrefix = "Storey",
4110
+ floorLevels =[],
4111
+ labelKey="label",
4112
+ typeKey="type",
4113
+ sourceKey="source",
4114
+ targetKey="target",
4115
+ xKey = "x",
4116
+ yKey = "y",
4117
+ zKey = "z",
4118
+ spaceType = "space",
4119
+ wallType = "wall",
4120
+ slabType = "slab",
4121
+ doorType = "door",
4122
+ windowType = "window",
4123
+ contentType = "content",
4124
+ ):
4125
+
4126
+ """
4127
+ Returns an RDF graph serialized string according to the BOT ontology. See https://w3c-lbd-cg.github.io/bot/.
4128
+
4129
+ Parameters
4130
+ ----------
4131
+ graph : topologic.Graph
4132
+ The input graph.
4133
+ format : str , optional
4134
+ The desired output format, the options are listed below. Thde default is "turtle".
4135
+ turtle, ttl or turtle2 : Turtle, turtle2 is just turtle with more spacing & linebreaks
4136
+ xml or pretty-xml : RDF/XML, Was the default format, rdflib < 6.0.0
4137
+ json-ld : JSON-LD , There are further options for compact syntax and other JSON-LD variants
4138
+ ntriples, nt or nt11 : N-Triples , nt11 is exactly like nt, only utf8 encoded
4139
+ n3 : Notation-3 , N3 is a superset of Turtle that also caters for rules and a few other things
4140
+ trig : Trig , Turtle-like format for RDF triples + context (RDF quads) and thus multiple graphs
4141
+ trix : Trix , RDF/XML-like format for RDF quads
4142
+ nquads : N-Quads , N-Triples-like format for RDF quads
4143
+ path : str
4144
+ The desired path to where the RDF/BOT file will be saved.
4145
+ overwrite : bool , optional
4146
+ If set to True, any existing file is overwritten. Otherwise, it is not. The default is False.
4147
+ bidirectional : bool , optional
4148
+ If set to True, reverse relationships are created wherever possible. Otherwise, they are not. The default is False.
4149
+ includeAttributes : bool , optional
4150
+ If set to True, the attributes associated with vertices in the graph are written out. Otherwise, they are not. The default is False.
4151
+ includeLabel : bool , optional
4152
+ If set to True, a label is attached to each node. Otherwise, it is not. The default is False.
4153
+ siteLabel : str , optional
4154
+ The desired site label. The default is "Site_0001".
4155
+ siteDictionary : dict , optional
4156
+ The dictionary of site attributes to include in the output. The default is None.
4157
+ buildingLabel : str , optional
4158
+ The desired building label. The default is "Building_0001".
4159
+ buildingDictionary : dict , optional
4160
+ The dictionary of building attributes to include in the output. The default is None.
4161
+ storeyPrefix : str , optional
4162
+ The desired prefixed to use for each building storey. The default is "Storey".
4163
+ floorLevels : list , optional
4164
+ The list of floor levels. This should be a numeric list, sorted from lowest to highest.
4165
+ If not provided, floorLevels will be computed automatically based on the nodes' 'z' attribute.
4166
+ typeKey : str , optional
4167
+ The dictionary key to use to look up the type of the node. The default is "type".
4168
+ labelKey : str , optional
4169
+ The dictionary key to use to look up the label of the node. The default is "label".
4170
+ sourceKey : str , optional
4171
+ The desired dictionary key to use to store the source vertex. The default is "source".
4172
+ targetKey : str , optional
4173
+ The desired dictionary key to use to store the target vertex. The default is "target".
4174
+ xKey : str , optional
4175
+ The dictionary key to use to look up the x-coordinate of the node. The default is "x".
4176
+ yKey : str , optional
4177
+ The dictionary key to use to look up the y-coordinate of the node. The default is "y".
4178
+ zKey : str , optional
4179
+ The dictionary key to use to look up the z-coordinate of the node. The default is "z".
4180
+ spaceType : str , optional
4181
+ The dictionary string value to use to look up nodes of type "space". The default is "space".
4182
+ wallType : str , optional
4183
+ The dictionary string value to use to look up nodes of type "wall". The default is "wall".
4184
+ slabType : str , optional
4185
+ The dictionary string value to use to look up nodes of type "slab". The default is "slab".
4186
+ doorType : str , optional
4187
+ The dictionary string value to use to look up nodes of type "door". The default is "door".
4188
+ windowType : str , optional
4189
+ The dictionary string value to use to look up nodes of type "window". The default is "window".
4190
+ contentType : str , optional
4191
+ The dictionary string value to use to look up nodes of type "content". The default is "contents".
4192
+ format : str , optional
4193
+ The desired output format, the options are listed below. Thde default is "turtle".
4194
+ turtle, ttl or turtle2 : Turtle, turtle2 is just turtle with more spacing & linebreaks
4195
+ xml or pretty-xml : RDF/XML, Was the default format, rdflib < 6.0.0
4196
+ json-ld : JSON-LD , There are further options for compact syntax and other JSON-LD variants
4197
+ ntriples, nt or nt11 : N-Triples , nt11 is exactly like nt, only utf8 encoded
4198
+ n3 : Notation-3 , N3 is a superset of Turtle that also caters for rules and a few other things
4199
+ trig : Trig , Turtle-like format for RDF triples + context (RDF quads) and thus multiple graphs
4200
+ trix : Trix , RDF/XML-like format for RDF quads
4201
+ nquads : N-Quads , N-Triples-like format for RDF quads
4202
+
4203
+ Returns
4204
+ -------
4205
+ str
4206
+ The rdf graph serialized string using the BOT ontology.
4207
+ """
4208
+ from os.path import exists
4209
+ bot_graph = Graph.BOTGraph(graph,
4210
+ bidirectional=bidirectional,
4211
+ includeAttributes=includeAttributes,
4212
+ includeLabel=includeLabel,
4213
+ siteLabel=siteLabel,
4214
+ siteDictionary=siteDictionary,
4215
+ buildingLabel=buildingLabel,
4216
+ buildingDictionary=buildingDictionary,
4217
+ storeyPrefix=storeyPrefix,
4218
+ floorLevels=floorLevels,
4219
+ labelKey=labelKey,
4220
+ typeKey=typeKey,
4221
+ sourceKey=sourceKey,
4222
+ targetKey=targetKey,
4223
+ xKey=xKey,
4224
+ yKey=yKey,
4225
+ zKey=zKey,
4226
+ spaceType = spaceType,
4227
+ wallType = wallType,
4228
+ slabType = slabType,
4229
+ doorType = doorType,
4230
+ windowType = windowType,
4231
+ contentType = contentType
4232
+ )
4233
+ if "turtle" in format.lower() or "ttl" in format.lower() or "turtle2" in format.lower():
4234
+ ext = ".ttl"
4235
+ elif "xml" in format.lower() or "pretty=xml" in format.lower() or "rdf/xml" in format.lower():
4236
+ ext = ".xml"
4237
+ elif "json" in format.lower():
4238
+ ext = ".json"
4239
+ elif "ntriples" in format.lower() or "nt" in format.lower() or "nt11" in format.lower():
4240
+ ext = ".nt"
4241
+ elif "n3" in format.lower() or "notation" in format.lower():
4242
+ ext = ".n3"
4243
+ elif "trig" in format.lower():
4244
+ ext = ".trig"
4245
+ elif "trix" in format.lower():
4246
+ ext = ".trix"
4247
+ elif "nquads" in format.lower():
4248
+ ext = ".nquads"
4249
+ else:
4250
+ format = "turtle"
4251
+ ext = ".ttl"
4252
+ n = len(ext)
4253
+ # Make sure the file extension is .brep
4254
+ ext = path[len(path)-n:len(path)]
4255
+ if ext.lower() != ext:
4256
+ path = path+ext
4257
+ if not overwrite and exists(path):
4258
+ print("Graph.ExportToBOT - Error: a file already exists at the specified path and overwrite is set to False. Returning None.")
4259
+ return None
4260
+ status = False
4261
+ try:
4262
+ bot_graph.serialize(destination=path, format=format)
4263
+ status = True
4264
+ except:
4265
+ status = False
4266
+ return status
4267
+
3702
4268
  @staticmethod
3703
4269
  def ExportToCSV(graph, path, graphLabel, graphFeatures="",
3704
4270
  graphIDHeader="graph_id", graphLabelHeader="label", graphFeaturesHeader="feat",
@@ -5113,7 +5679,7 @@ class Graph:
5113
5679
  return vertices
5114
5680
 
5115
5681
  @staticmethod
5116
- def JSONData(graph, vertexLabelKey="", edgeLabelKey="", mantissa=6):
5682
+ def JSONData(graph, vertexLabelKey="", edgeLabelKey="", sourceKey="source", targetKey="target", mantissa=6):
5117
5683
  """
5118
5684
  Converts the input graph into JSON data.
5119
5685
 
@@ -5127,6 +5693,10 @@ class Graph:
5127
5693
  edgeLabelKey : str , optional
5128
5694
  If set to a valid string, the edge label will be set to the value at this key. Otherwise it will be set to Edge_XXXX where XXXX is a sequential unique number.
5129
5695
  Note: If edge labels are not unique, they will be forced to be unique.
5696
+ sourceKey : str , optional
5697
+ The dictionary key used to store the source vertex. The default is "source".
5698
+ targetKey : str , optional
5699
+ The dictionary key used to store the target vertex. The default is "source".
5130
5700
  mantissa : int , optional
5131
5701
  The desired length of the mantissa. The default is 6.
5132
5702
 
@@ -5179,8 +5749,8 @@ class Graph:
5179
5749
  ev_label = v_labels[evi]
5180
5750
  d = Topology.Dictionary(e)
5181
5751
 
5182
- d = Dictionary.SetValueAtKey(d, "source", sv_label)
5183
- d = Dictionary.SetValueAtKey(d, "target", ev_label)
5752
+ d = Dictionary.SetValueAtKey(d, sourceKey, sv_label)
5753
+ d = Dictionary.SetValueAtKey(d, targetKey, ev_label)
5184
5754
  e_dict = Dictionary.PythonDictionary(d)
5185
5755
  e_label = Dictionary.ValueAtKey(d, edgeLabelKey)
5186
5756
  if isinstance(e_label, str):