├── apt.txt
├── img
└── ifcmapconversion-relationship.png
├── utils
├── __pycache__
│ ├── IfcGraphViz.cpython-310.pyc
│ ├── IfcGraphViz.cpython-39.pyc
│ └── JupyterIFCRenderer.cpython-39.pyc
├── _JupyterIFCRenderer.py
├── IfcGraphViz.py
└── JupyterIFCRenderer.py
├── helpful docs
└── User-Guide-for-Geo-referencing-in-IFC-v2.0.pdf
├── postBuild
├── README.MD
├── environment.yml
├── models
└── ifc4 geolocation.ifc
└── 1. geolocation.ipynb
/apt.txt:
--------------------------------------------------------------------------------
1 | libgl1-mesa-glx
--------------------------------------------------------------------------------
/img/ifcmapconversion-relationship.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vulevukusej/Jupyter-IfcOpenShell/HEAD/img/ifcmapconversion-relationship.png
--------------------------------------------------------------------------------
/utils/__pycache__/IfcGraphViz.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vulevukusej/Jupyter-IfcOpenShell/HEAD/utils/__pycache__/IfcGraphViz.cpython-310.pyc
--------------------------------------------------------------------------------
/utils/__pycache__/IfcGraphViz.cpython-39.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vulevukusej/Jupyter-IfcOpenShell/HEAD/utils/__pycache__/IfcGraphViz.cpython-39.pyc
--------------------------------------------------------------------------------
/utils/__pycache__/JupyterIFCRenderer.cpython-39.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vulevukusej/Jupyter-IfcOpenShell/HEAD/utils/__pycache__/JupyterIFCRenderer.cpython-39.pyc
--------------------------------------------------------------------------------
/helpful docs/User-Guide-for-Geo-referencing-in-IFC-v2.0.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vulevukusej/Jupyter-IfcOpenShell/HEAD/helpful docs/User-Guide-for-Geo-referencing-in-IFC-v2.0.pdf
--------------------------------------------------------------------------------
/postBuild:
--------------------------------------------------------------------------------
1 | jupyter labextension install jupyter-threejs
2 | jupyter labextension install jupyter-datawidgets
3 | jupyter labextension install ipycanvas
4 | jupyter serverextension enable nbgitpuller --sys-prefix
--------------------------------------------------------------------------------
/README.MD:
--------------------------------------------------------------------------------
1 | Welcome to this repository, dedicated to providing interactive use-cases for IfcOpenShell.
2 |
3 | I'll be adding more examples over time, so check back periodically. Otherwise, if you have an idea please submit an issue ;)
4 |
--------------------------------------------------------------------------------
/environment.yml:
--------------------------------------------------------------------------------
1 | name: base
2 | channels:
3 | - conda-forge
4 | dependencies:
5 | - jupyterlab=3.1
6 | - jupyter-offlinenotebook=0.2
7 | - nodejs=12
8 | - nbconvert=6
9 | # RTC
10 | - jupyterlab-link-share=0.2
11 | # Python Kernel
12 | - ipykernel=5.1
13 | - xeus-python=0.9
14 | - ipywidgets=7.6
15 | - widgetsnbextension=3.5
16 | - ipyleaflet=0.13
17 | - pythonocc-core
18 | - pythreejs
19 | - ifcopenshell
20 | - python-graphviz
21 | - shapely
22 | - ipycanvas
23 | - lxml
24 | - sidecar
25 | - ipycytoscape
26 | - networkx
27 | - nbgitpuller
28 | - altair=4.1
29 | - bqplot=0.12.20
30 | - dask=2020.12
31 | - matplotlib=3.1
32 | - pandas=1
33 | - python=3.7
34 | - scikit-image=0.15
35 | - scikit-learn=0.21
36 | - seaborn=0.11
37 | - tensorflow=1.13
38 | - sympy=1.4
39 | - pyyaml
40 | - traittypes==0.2.1
41 | - invoke=1.2
42 | - rdflib
43 | - sparqlwrapper
44 | - python-graphviz
45 | - pydotplus
46 |
--------------------------------------------------------------------------------
/utils/_JupyterIFCRenderer.py:
--------------------------------------------------------------------------------
1 | import os
2 | import random
3 | from OCC.Display.WebGl.jupyter_renderer import JupyterRenderer, format_color, NORMAL
4 | import OCC.Core, OCC.Core.gp
5 | import ifcopenshell, ifcopenshell.geom
6 |
7 |
8 | class JupyterIFCRenderer(JupyterRenderer):
9 | colors_dict = { "IfcWall": (50,50,50)}
10 |
11 |
12 | def __init__(self,
13 | model,
14 | display_ents = ["IfcProduct", "IfcWall"],
15 | hide_ents = ["IfcOpening", "IfcFurnitureElement"],
16 | size=(640, 480),
17 | compute_normals_mode=NORMAL.CLIENT_SIDE,
18 | default_shape_color=format_color(166, 166, 166), # light grey
19 | default_edge_color=format_color(32, 32, 32), # dark grey
20 | default_vertex_color=format_color(8, 8, 8), # darker grey
21 | pick_color=format_color(232, 176, 36), # orange
22 | background_color='white'):
23 | """ Creates a jupyter renderer for IFCFiles.
24 | model: the ifcopenshell model to be displayed
25 | size: a tuple (width, height). Must be a square, or shapes will look like deformed
26 | compute_normals_mode: optional, set to SERVER_SIDE by default. This flag lets you choose the
27 | way normals are computed. If SERVER_SIDE is selected (default value), then normals
28 | will be computed by the Tesselator, packed as a python tuple, and send as a json structure
29 | to the client. If, on the other hand, CLIENT_SIDE is chose, then the computer only compute vertex
30 | indices, and let the normals be computed by the client (the web js machine embedded in the webrowser).
31 | * SERVER_SIDE: higher server load, loading time increased, lower client load. Poor performance client will
32 | choose this option (mobile terminals for instance)
33 | * CLIENT_SIDE: lower server load, loading time decreased, higher client load. Higher performance clients will
34 | choose this option (laptops, desktop machines).
35 | * default_shape_color
36 | * default_e1dge_color:
37 | * default_pick_color:
38 | * background_color:
39 | """
40 | print("fresh init")
41 | settings = ifcopenshell.geom.settings()
42 | settings.set(settings.USE_PYTHON_OPENCASCADE, True)
43 | super().__init__(size=size,compute_normals_mode=compute_normals_mode)
44 | self.register_select_callback(self.ifc_element_click)
45 |
46 | # to_display = list(map(m.by_type for p in display_ents))
47 | to_display = []
48 | # print(display_ents)
49 | for ent in display_ents:
50 | to_display.extend(model.by_type(ent))
51 | self.shapedict = {}
52 | # print(to_display)
53 | for product in to_display:
54 | if (product.Representation is not None and
55 | product.is_a() not in hide_ents) : # some IfcProducts don't have any 3d representation
56 |
57 |
58 | pdct_shape = ifcopenshell.geom.create_shape(settings, inst=product)
59 | r,g,b,alpha = pdct_shape.styles[0] # the shape color
60 |
61 | color = format_color(int(abs(random.random())*255), int(abs(random.random())*255), int(abs(random.random())*255))
62 | # color = format_color(int(r),int(g),int(b))
63 |
64 | # self.shapedict[pdct_shape.geometry]=product
65 | # any renderer (threejs, x3dom, jupyter, qt5 based etc.)
66 | self.DisplayShape(pdct_shape.geometry, shape_color = color, transparency=False, opacity=0.5)
67 |
68 |
69 |
70 | def ifc_element_click(self, value):
71 | # ("element click")
72 | # self.html.value(self, value)
73 |
74 | self.html.value += f"Nested Relative: The Element id:{self.shapedict}
{value}"
75 | # self.html.value += f"
{str(self.shapedict[self._current_shape_selection])}
"
76 |
77 | def setColorSelected(self, color):
78 | # for key, val in self.shapedict.items():
79 | # if val == element:
80 | # TODO : multiple selection
81 | # for shp in self._current_shape_selection:
82 | shp = self._current_shape_selection
83 | # print(self._current_shape_selection.colors)
84 | print(self._current_mesh_selection.material.color)
85 | self._current_mesh_selection.material.color = color
86 | # self.DisplayShape(shp, shape_color = format_color(*color), transparency=False, opacity=0.5)
87 |
88 |
89 | def __repr__(self):
90 | self.Display()
91 | return ""
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/models/ifc4 geolocation.ifc:
--------------------------------------------------------------------------------
1 | ISO-10303-21;
2 | HEADER;
3 | FILE_DESCRIPTION(('ViewDefinition [CoordinationView]'),'2;1');
4 | FILE_NAME('geolocation.blend.ifc','2020-05-12T12:09:46+10:00',(),(),'IfcOpenShell 0.6.0b0','BlenderBIM 0.0.200413','Moult');
5 | FILE_SCHEMA(('IFC4'));
6 | ENDSEC;
7 | DATA;
8 | #1=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.);
9 | #2=IFCSIUNIT(*,.AREAUNIT.,$,.SQUARE_METRE.);
10 | #3=IFCSIUNIT(*,.VOLUMEUNIT.,$,.CUBIC_METRE.);
11 | #4=IFCUNITASSIGNMENT((#1,#2,#3));
12 | #5=IFCACTORROLE(.ARCHITECT.,$,'Draws the pretty pictures');
13 | #6=IFCPOSTALADDRESS(.OFFICE.,'Headquarters',$,'Cupboard under the stairs',('221B Baker Street'),$,'MyTown','Middle-Earth','42','Narnia');
14 | #7=IFCTELECOMADDRESS(.OFFICE.,'Headquarters',$,('0123456789'),$,$,('dion@thinkmoult.com'),'https://thinkmoult.com',('irc://irc.freenode.net##architect'));
15 | #8=IFCPERSON('Moult','Moult','Dion',('Sebastian','Isan','Tan'),('Mr'),('UE'),(#5),(#6,#7));
16 | #9=IFCACTORROLE(.USERDEFINED.,'CONTRIBUTOR',$);
17 | #10=IFCTELECOMADDRESS(.USERDEFINED.,'The main webpage of the software collection.','WEBPAGE',$,$,$,$,'https://ifcopenshell.org',$);
18 | #11=IFCTELECOMADDRESS(.USERDEFINED.,'The BlenderBIM webpage of the software collection.','WEBPAGE',$,$,$,$,'https://blenderbim.org',$);
19 | #12=IFCTELECOMADDRESS(.USERDEFINED.,'The source code repository of the software collection.','REPOSITORY',$,$,$,$,'https://github.com/IfcOpenShell/IfcOpenShell.git',$);
20 | #13=IFCORGANIZATION($,'IfcOpenShell','IfcOpenShell is an open source (LGPL) software library that helps users and software developers to work with the IFC file format.',(#9),(#10,#11,#12));
21 | #14=IFCCARTESIANPOINT((0.,0.,0.));
22 | #15=IFCDIRECTION((0.,0.,1.));
23 | #16=IFCDIRECTION((1.,0.,0.));
24 | #17=IFCAXIS2PLACEMENT3D(#14,#15,#16);
25 | #18=IFCPERSONANDORGANIZATION(#8,#13,$);
26 | #19=IFCAPPLICATION(#13,'0.0.200413','BlenderBIM','BlenderBIM');
27 | #20=IFCOWNERHISTORY(#18,#19,.READWRITE.,.NOTDEFINED.,1589249386,#18,#19,1589249386);
28 | #21=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,1.E-05,#17,$);
29 | #22=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Body','Model',*,*,*,*,#21,$,.MODEL_VIEW.,$);
30 | #23=IFCPROJECT('0z0$6As99Fg8k_xxjb4gTX',$,'My Project',$,$,$,$,(#21),#4);
31 | #24=IFCOBJECTIVE('Beauty','The built form should be beautiful',.HARD.,$,$,$,$,$,$,.DESIGNINTENT.,$);
32 | #25=IFCOBJECTIVE('Safety','No facilities exist to generate killer artificial intelligence',.HARD.,$,$,$,$,$,$,.HEALTHANDSAFETY.,$);
33 | #26=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.);
34 | #27=IFCPROJECTEDCRS('EPSG:7856','','','EPSG:5111','','',#26);
35 | #28=IFCMAPCONVERSION(#21,#27,334871.85,6252295.02,12.,2.59808,-1.5,1.);
36 | #29=IFCCARTESIANPOINT((-1.,0.,-1.));
37 | #30=IFCCARTESIANPOINT((1.,0.,1.));
38 | #31=IFCCARTESIANPOINT((-1.,0.,1.));
39 | #32=IFCCARTESIANPOINT((1.,0.,-1.));
40 | #33=IFCCARTESIANPOINT((0.,1.,-1.));
41 | #34=IFCCARTESIANPOINT((0.333333313465118,-1.,1.));
42 | #35=IFCCARTESIANPOINT((-0.333333313465118,-1.,1.));
43 | #36=IFCCARTESIANPOINT((-0.333333313465118,-1.,-1.));
44 | #37=IFCCARTESIANPOINT((0.333333313465118,-1.,-1.));
45 | #38=IFCCARTESIANPOINT((0.,1.,1.));
46 | #39=IFCCARTESIANPOINT((0.333333313465118,0.,-1.));
47 | #40=IFCCARTESIANPOINT((-0.333333313465118,0.,-1.));
48 | #41=IFCCARTESIANPOINT((-0.333333313465118,0.,1.));
49 | #42=IFCCARTESIANPOINT((0.333333313465118,0.,1.));
50 | #43=IFCPOLYLOOP((#40,#41,#31,#29));
51 | #44=IFCFACEOUTERBOUND(#43,.T.);
52 | #45=IFCFACE((#44));
53 | #46=IFCPOLYLOOP((#39,#32,#30,#42));
54 | #47=IFCFACEOUTERBOUND(#46,.T.);
55 | #48=IFCFACE((#47));
56 | #49=IFCPOLYLOOP((#29,#31,#38,#33));
57 | #50=IFCFACEOUTERBOUND(#49,.T.);
58 | #51=IFCFACE((#50));
59 | #52=IFCPOLYLOOP((#33,#38,#30,#32));
60 | #53=IFCFACEOUTERBOUND(#52,.T.);
61 | #54=IFCFACE((#53));
62 | #55=IFCPOLYLOOP((#39,#42,#34,#37));
63 | #56=IFCFACEOUTERBOUND(#55,.T.);
64 | #57=IFCFACE((#56));
65 | #58=IFCPOLYLOOP((#42,#30,#38,#31,#41,#35,#34));
66 | #59=IFCFACEOUTERBOUND(#58,.T.);
67 | #60=IFCFACE((#59));
68 | #61=IFCPOLYLOOP((#40,#36,#35,#41));
69 | #62=IFCFACEOUTERBOUND(#61,.T.);
70 | #63=IFCFACE((#62));
71 | #64=IFCPOLYLOOP((#39,#37,#36,#40,#29,#33,#32));
72 | #65=IFCFACEOUTERBOUND(#64,.T.);
73 | #66=IFCFACE((#65));
74 | #67=IFCPOLYLOOP((#37,#34,#35,#36));
75 | #68=IFCFACEOUTERBOUND(#67,.T.);
76 | #69=IFCFACE((#68));
77 | #70=IFCCLOSEDSHELL((#45,#48,#51,#54,#57,#60,#63,#66,#69));
78 | #71=IFCFACETEDBREP(#70);
79 | #72=IFCSHAPEREPRESENTATION(#22,'Body','Brep',(#71));
80 | #73=IFCREPRESENTATIONMAP(#17,#72);
81 | #74=IFCCOLOURRGB($,0.800000011920929,0.800000011920929,0.800000011920929);
82 | #75=IFCCOLOURRGB($,0.800000011920929,0.800000011920929,0.800000011920929);
83 | #76=IFCSURFACESTYLERENDERING(#74,-0.,#75,$,$,$,$,$,.NOTDEFINED.);
84 | #77=IFCSURFACESTYLE('Material',.BOTH.,(#76));
85 | #78=IFCSTYLEDITEM($,(#77),'Material');
86 | #79=IFCSTYLEDREPRESENTATION(#22,$,$,(#78));
87 | #80=IFCMATERIAL('Material',$,$);
88 | #81=IFCMATERIALDEFINITIONREPRESENTATION('Material',$,(#79),#80);
89 | #82=IFCLOCALPLACEMENT($,#17);
90 | #83=IFCSITE('2Naya6vn181f_Nk1xMGM7f',#20,'My Site',$,$,#82,$,$,$,$,$,$,$,$);
91 | #84=IFCLOCALPLACEMENT(#82,#17);
92 | #85=IFCBUILDING('3FllR6gD94WuJroKZKsPAi',#20,'My Building',$,$,#84,$,$,$,$,$,$);
93 | #86=IFCLOCALPLACEMENT(#84,#17);
94 | #87=IFCBUILDINGSTOREY('05Sow4VP9EL9wRKG9jYu2v',#20,'Ground Floor',$,$,#86,$,$,$,$);
95 | #88=IFCRELAGGREGATES('0XzNn$s_P0php3tNg$s_uY',#20,$,$,#85,(#87));
96 | #89=IFCRELAGGREGATES('2qe5dYAKv88xk$E7tgxcZP',#20,$,$,#83,(#85));
97 | #90=IFCRELAGGREGATES('396Tik8RT9jxX7h7TbB34l',#20,$,$,#23,(#83));
98 | #91=IFCCARTESIANPOINT((0.,0.,0.));
99 | #92=IFCDIRECTION((0.,0.,1.));
100 | #93=IFCDIRECTION((1.,0.,0.));
101 | #94=IFCAXIS2PLACEMENT3D(#91,#92,#93);
102 | #95=IFCLOCALPLACEMENT(#86,#94);
103 | #96=IFCDIRECTION((1.,0.,0.));
104 | #97=IFCDIRECTION((0.,1.,0.));
105 | #98=IFCCARTESIANPOINT((0.,0.,0.));
106 | #99=IFCDIRECTION((0.,0.,1.));
107 | #100=IFCCARTESIANTRANSFORMATIONOPERATOR3D(#96,#97,#98,1.,#99);
108 | #101=IFCMAPPEDITEM(#73,#100);
109 | #102=IFCSHAPEREPRESENTATION(#22,'Body','MappedRepresentation',(#101));
110 | #103=IFCPRODUCTDEFINITIONSHAPE($,$,(#102));
111 | #104=IFCWALL('2NJ_23i9r0G8LCrcGX2cKW',#20,'Cube',$,$,#95,#103,$,.MOVABLE.);
112 | #105=IFCRELCONTAINEDINSPATIALSTRUCTURE('0cvb6qaDLAvxNHVTrO2Zi4',#20,$,$,(#104),#87);
113 | #106=IFCRELASSOCIATESMATERIAL('1ek21YIpT0EBJYIkVxAYc7',#20,$,$,(#104),#80);
114 | ENDSEC;
115 | END-ISO-10303-21;
--------------------------------------------------------------------------------
/utils/IfcGraphViz.py:
--------------------------------------------------------------------------------
1 | import ifcopenshell
2 | import uuid
3 | from graphviz import Digraph
4 |
5 | ## If you are reading this, and are interested, please helpme to reimplement this in networkx!
6 | ## TODO Jakob
7 |
8 | class IfcGraphViz():
9 | node_attr = dict(
10 | shape='record',
11 | align='left',
12 | fontsize='8',
13 | fontname='Arial',
14 | ranksep='0.1',
15 | height='0.2',
16 | width='1'
17 | )
18 | edge_attr = dict(
19 | fontsize='8',
20 | fontname='Arial',
21 | )
22 |
23 |
24 | nodes = None
25 | edges = None
26 | graph = None
27 |
28 |
29 | def plot_graph(self, model, node, forward=10, graph=None, direction="LR"):
30 | if not self.graph:
31 | self.graph = Digraph(node_attr=self.node_attr, edge_attr=self.edge_attr)
32 | self.graph.attr(rankdir=direction, fontname="Arial", fontsize="8")
33 | self.nodes = []
34 | self.edges = []
35 |
36 | info_str = """"""
37 | if forward >= 0:
38 | for attr, val in node.get_info().items():
39 | if type(val) == ifcopenshell.entity_instance:
40 |
41 | self.graph = self.plot_graph(model, val, forward=forward-1, graph=self.graph)
42 | self.graph.edge(str(node.id()), str(val.id()), label=attr)
43 | elif type(val) == tuple:
44 | if len(val) == 0:
45 | self.graph = self.plot_graph(model, val[0], forward=forward-1, graph=self.graph)
46 | self.graph.edge(str(node.id()), str(val[0].id()), label=attr)
47 |
48 |
49 | else:
50 | if attr == "id":
51 | info_str += str(f"#{val} \\n")
52 | elif attr == "type":
53 | info_str += str(f"({val}) \\n\\n")
54 | else:
55 | info_str+= str(f"{attr} : {val} \\l")
56 |
57 | #print(info_str)
58 | node = self.graph.node(name=str(node.id()), label=info_str)
59 |
60 |
61 |
62 | return self.graph
63 |
64 |
65 |
66 | def plot_reverse_graph(self, model, node, reverse=3, graph=None, direction="LR"):
67 |
68 | ## TODO: backwards
69 | if not graph:
70 | self.graph = Digraph(node_attr=self.node_attr, edge_attr=self.edge_attr)
71 | self.graph.attr(rankdir=direction, fontname="Arial", fontsize="8")
72 | info_str = f"#{node.id()}"
73 | #self.graph = self.plot_graph(model, node, forward=1, graph=self.graph)
74 | if reverse >= 0 and node:
75 | inverse_rels = model.get_inverse(node)
76 | for inverse in inverse_rels:
77 | #print (f"{type(inverse)}: {inverse}")
78 | if type(inverse) == ifcopenshell.entity_instance:
79 |
80 | for attr, value in inverse.get_info().items():
81 | if type(value) == ifcopenshell.entity_instance:
82 | if value.id() == inverse.id():
83 | #self.graph = self.plot_graph(model, inverse, forward=1, graph=self.graph)
84 |
85 | self.graph.node(name=str(value.id()), label=info_str)
86 | self.graph.edge(str(reverse.id()), str(value.id()), label=attr )
87 | if type(value) == tuple:
88 | for item in value:
89 | if type(item) == ifcopenshell.entity_instance:
90 | if item.id() == node.id():
91 | #self.graph = self.plot_graph(model, node, forward=1, graph=self.graph)
92 | self.graph.node(name=str(item.id()), label=info_str)
93 | self.graph.edge(str(inverse.id()), str(item.id()), label=attr)
94 |
95 |
96 | #print(info_str)
97 | node = self.graph.node(name=str(node.id()), label=info_str)
98 | return self.graph
99 |
100 |
101 |
102 |
103 |
104 | def plot_relation_graph(self, m, node, relationships=["IfcRelContainedInSpatialStructure", "IfcRelVoidsElement", "IfcRelFillsElement", "IfcRelAggregates"],
105 | depth=1):
106 | dot = Digraph(node_attr=self.node_attr, edge_attr=self.edge_attr)
107 | dot.attr(rankdir='TD', fontname="Arial", fontsize="8")
108 | # relations = m.by_type("IfcRelationship")
109 | temp_relations = m.get_inverse(node)
110 |
111 | relations = []
112 | for rel in temp_relations:
113 | #print(rel)
114 | if rel.is_a().startswith("IfcRel"):
115 | #print(f"added {rel}")
116 | relations.append(rel)
117 |
118 | for relation in relations:
119 |
120 | if relation.is_a() in relationships or len(relationships)==0:
121 | relatedNodeId = None
122 |
123 | # dot.node(relation.GlobalId)
124 | for key, value in relation.get_info().items():
125 | if key.startswith("Relating") and value.id == node.id:
126 | # print("Relating"))
127 | dot.node( getattr(value, "GlobalId", f'#{value.id}'), f'name:{getattr(value, "Name", value.id )} ‚\n {value.is_a()}')
128 | relatedNodeId = getattr(value, "GlobalId", f"#{value.id}")
129 |
130 |
131 | if key.startswith("Related"):
132 | # print (type(value))
133 | if type(value) == ifcopenshell.entity_instance:
134 |
135 | dot.node( getattr(value, "GlobalId", "No Id"), getattr(value, "Name", "NaN"))
136 | elif type (value) == tuple:
137 | for related in value:
138 | # print (value)
139 | dot.node(getattr(related, "GlobalId", "No GlobalId"), f'name:{getattr(related, "Name", "no name")}\n {related.is_a()} ')
140 |
141 | for key, value in relation.get_info().items():
142 |
143 |
144 | if key.startswith("Related"):
145 | # print (type(value))
146 | if type(value) == ifcopenshell.entity_instance and relatedNodeId:
147 | dot.edge(relatedNodeId, getattr(value, "GlobalId", "none"))
148 | elif relatedNodeId:
149 | for related in value:
150 |
151 | dot.edge(relatedNodeId, getattr(related, "GlobalId", "none"))
152 |
153 |
154 | # print (f'\t\t{key} : \t\t\t{value}')
155 | return dot
--------------------------------------------------------------------------------
/utils/JupyterIFCRenderer.py:
--------------------------------------------------------------------------------
1 | import os
2 | import random
3 | from OCC.Display.WebGl.jupyter_renderer import JupyterRenderer, format_color, NORMAL, BoundingBox
4 | from ipywidgets import interact, interactive, fixed, interact_manual, IntSlider, Layout, FloatSlider
5 | import ipywidgets as widgets
6 |
7 | import OCC.Core, OCC.Core.gp
8 | import ifcopenshell, ifcopenshell.geom
9 | from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox, BRepPrimAPI_MakeSphere
10 | from pythreejs import Plane
11 |
12 |
13 | class JupyterIFCRenderer(JupyterRenderer):
14 | colors_dict = { "IfcWall": (50,50,50)}
15 |
16 |
17 | def __init__(self,
18 | model,
19 | display_ents = ["IfcProduct"],
20 | hide_ents = ["IfcOpeningElement", "IfcSpace"],
21 | size=(640, 480),
22 | compute_normals_mode=NORMAL.CLIENT_SIDE,
23 | default_shape_color=format_color(166, 166, 166), # light grey
24 | default_edge_color=format_color(32, 32, 32), # dark grey
25 | default_vertex_color=format_color(8, 8, 8), # darker grey
26 | pick_color=format_color(232, 176, 36), # orange
27 | background_color='white'):
28 | """ Creates a jupyter renderer for IFCFiles.
29 | model: the ifcopenshell model to be displayed
30 | size: a tuple (width, height). Must be a square, or shapes will look like deformed
31 | compute_normals_mode: optional, set to SERVER_SIDE by default. This flag lets you choose the
32 | way normals are computed. If SERVER_SIDE is selected (default value), then normals
33 | will be computed by the Tesselator, packed as a python tuple, and send as a json structure
34 | to the client. If, on the other hand, CLIENT_SIDE is chose, then the computer only compute vertex
35 | indices, and let the normals be computed by the client (the web js machine embedded in the webrowser).
36 | * SERVER_SIDE: higher server load, loading time increased, lower client load. Poor performance client will
37 | choose this option (mobile terminals for instance)
38 | * CLIENT_SIDE: lower server load, loading time decreased, higher client load. Higher performance clients will
39 | choose this option (laptops, desktop machines).
40 | * default_shape_color
41 | * default_e1dge_color:
42 | * default_pick_color:
43 | * background_color:
44 | """
45 |
46 | settings = ifcopenshell.geom.settings()
47 | settings.set(settings.USE_PYTHON_OPENCASCADE, True)
48 | super().__init__(size=size,compute_normals_mode=compute_normals_mode)
49 | self.register_select_callback(self.ifc_element_click)
50 |
51 |
52 | to_display = []
53 | for ent in display_ents:
54 | to_display.extend(model.by_type(ent, True))
55 | # print(display_ents)
56 | self.shapedict = {}
57 | self.elementdict = {}
58 | self._meshdict = {}
59 | self.colorcache = {}
60 | self.highlight_color = "#EE2222"
61 | schema = model.wrapped_data.schema
62 | # print(to_display)
63 |
64 | for product in to_display:
65 | # some IfcProducts don't have any 3d representation
66 | if (product.Representation is not None ) :
67 |
68 | pdct_shape = ifcopenshell.geom.create_shape(settings, inst=product)
69 | r,g,b,alpha = pdct_shape.styles[0] # the shape color
70 | # Styles come as floats 0 <= style <= 1
71 | if r == g == b == -1:
72 | r = b = g = 0.7
73 | color = format_color(int(abs(r)*255),int(abs(g*255)),int(abs(b)*255))
74 |
75 | self.shapedict[pdct_shape.geometry]=product
76 | self.elementdict[product] = pdct_shape.geometry
77 | self.colorcache[pdct_shape.geometry] = color
78 |
79 | # any renderer (threejs, x3dom, jupyter, qt5 based etc.)
80 | self.DisplayShape(pdct_shape.geometry, shape_color = color, transparency=False, opacity=0.5)
81 | #
82 | for ent in hide_ents:
83 | to_hide = model.by_type(ent)
84 | for p in to_hide:
85 | self.setVisible(p, False)
86 |
87 | for meshid, shape in self._shapes.items():
88 | product = self.shapedict[shape]
89 | #self._meshdict[product] = meshid
90 | self._meshdict[product] = list(filter(lambda mesh: mesh.name == meshid, self._displayed_pickable_objects.children))[0]
91 |
92 | if self._shapes:
93 | self._bb = BoundingBox([self._shapes.values()])
94 | else: # if nothing registered yet, create a fake bb
95 | self._bb = BoundingBox([[BRepPrimAPI_MakeSphere(5.).Shape()]])
96 |
97 | self._sectionXSlider = FloatSlider(name = "section plane X", layout=Layout(width='200px'), min=self._bb.ymin-1, max=self._bb.ymax+1, value=self._bb.ymax+1,step=0.1)
98 | self._sectionXSlider.observe(self._sectionPlaneX, "value")
99 | self._controls.append(self._sectionXSlider)
100 |
101 | self._sectionZSlider = FloatSlider(name = "section plane Z", layout=Layout(width='200px'), min=self._bb.zmin-1, max=self._bb.zmax+1, value=self._bb.zmax+1,step=0.1)
102 | self._sectionZSlider.observe(self._sectionPlaneZ, "value")
103 | self._controls.append(self._sectionZSlider)
104 |
105 | def ifc_element_click(self, value):
106 | # ("element click")
107 | # self.html.value(self, value)
108 | #print("click")
109 | product = self.shapedict[value]
110 | self.html.value += f"{product.is_a()}
"
111 | self.html.value += "
| {str(key)}: | {str(value)} |