First Commit

This commit is contained in:
2026-05-31 10:17:09 +07:00
commit 17a9c69379
4547 changed files with 1170384 additions and 0 deletions
@@ -0,0 +1,100 @@
## python-mvdxml
A mvdXML checker and w3c SPARQL converter, as an IfcOpenShell submodule or stand-alone.
WARNING: While this repository has many useful building blocks to build software around mvdXML and IFC, there are many mvdXML dialects and not all variants are likely to be fully supported.
### Quickstart
#### Extraction
```python
import ifcopenshell
from ifcopenshell.mvd import mvd
mvd_concept = mvd.open_mvd("examples/wall_extraction.mvdxml")
file = ifcopenshell.open("Duplex_A_20110505.ifc")
all_data = mvd.get_data(mvd_concept, file, spreadsheet_export=True)
non_respecting_entities = mvd.get_non_respecting_entities(file, all_data[1])
respecting_entities = mvd.get_respecting_entities(file, all_data[1])
```
```python
# Create a new file
new_file = ifcopenshell.file(schema=file.schema)
proj = file.by_type("IfcProject")[0]
new_file.add(proj)
for e in respecting_entities:
new_file.add(e)
new_file.write("new_file.ifc")
```
```python
# Visualize results
mvd.visualize(file, non_respecting_entities)
```
##### Validation
~~~py
import ifcopenshell
from ifcopenshell.mvd import mvd
from colorama import Fore
from colorama import Style
concept_roots = list(ifcopenshell.mvd.concept_root.parse(MVDXML_FILENAME))
file = ifcopenshell.open(IFC_FILENAME)
tt = 0 # total number of tests
ts = 0 # total number of successful tests
for concept_root in concept_roots:
print("ConceptRoot: ", concept_root.entity)
for concept in concept_root.concepts():
tt = tt + 1
print("Concept: ", concept.name)
try:
if len(concept.template().rules) > 1:
attribute_rules = []
for rule in concept.template().rules:
attribute_rules.append(rule)
rules_root = ifcopenshell.mvd.rule("EntityRule", concept_root.entity, attribute_rules)
else:
rules_root = concept.template().rules[0]
ts = ts + 1
finst = 0 #failed instances
for inst in file.by_type(concept_root.entity):
try:
data = mvd.extract_data(rules_root, inst)
valid, output = mvd.validate_data(concept, data)
if not valid:
finst = finst + 1
print("[VALID]" if valid else Fore.RED +"[failure]"+Style.RESET_ALL, inst)
print(output)
except Exception as e:
print(Fore.RED+"EXCEPTION: ", e, Style.RESET_ALL,inst)
print ()
print (int(finst), "out of", int(len(file.by_type(concept_root.entity))), "instances failed the check")
print ("---------------------------------")
except Exception as e:
print("EXCEPTION: "+Fore.RED,e,Style.RESET_ALL)
print("---------------------------------")
print("---------------------------------")
print("---------------------------------")
tf = tt-ts # total number of failed tests
print ("\nRESULTS OVERVIEW")
print ("Total number of tests: ",tt)
print ("Total number of executed tests: ", ts)
print ("Total number of failed tests: ", tf)
~~~
@@ -0,0 +1,199 @@
from . import mvdxml_expression
from xml.dom.minidom import parse, Element
class rule(object):
"""
A class for representing an mvdXML EntityRule or AttributeRule
"""
def __init__(self, tag, attribute, nodes, bind=None, optional=False):
self.tag, self.attribute, self.nodes, self.bind = tag, attribute, nodes, bind
self.optional = optional
def to_string(self, indent=0):
# return "%s%s%s[%s](%s%s)%s" % ("\n" if indent else "", " "*indent, self.tag, self.attribute, "".join(n.to_string(indent+2) for n in self.nodes), ("\n" + " "*indent) if len(self.nodes) else "", (" -> %s" % self.bind) if self.bind else "")
return "<%s %s%s>" % (self.tag, f"{self.bind}=" if self.bind else "", self.attribute)
def __repr__(self):
return self.to_string()
class template(object):
"""
Representation of an mvdXML template
"""
def __init__(self, concept, root, constraints=None, rules=None, parent=None):
self.concept, self.root, self.constraints, self.parent = concept, root, (constraints or []), parent
self.rules = rules or []
self.entity = str(root.attributes['applicableEntity'].value)
try:
self.name = root.attributes['name'].value
except:
self.name = None
def bind(self, constraints):
return template(self.concept, self.root, constraints, self.rules)
def parse(self, visited=None):
for rules in self.root.getElementsByTagNameNS("*", "Rules"):
for r in rules.childNodes:
if not isinstance(r, Element): continue
self.rules.append(self.parse_rule(r, visited=visited))
def traverse(self, fn, root=None, with_parents=False):
def visit(n, p=root, ps=[root]):
if with_parents:
close = fn(rule=n, parents=ps)
else:
close = fn(rule=n, parent=p)
for s in n.nodes:
visit(s, n, ps + [n])
if close:
close()
for r in self.rules:
visit(r)
def parse_rule(self, root, visited=None):
def visit(node, prefix="", visited=None, parent=None):
r = None
n = node
nm = None
p = prefix
optional = False
visited = set() if visited is None else visited
if node.localName == "AttributeRule":
r = node.attributes["AttributeName"].value
try:
nm = node.attributes["RuleID"].value
except:
# without binding, it's wrapped in a SPARQL OPTIONAL {} clause
# Aim is to insert this clause once as high in the stack as possible
# All topmost attribute rules are optional anyway as in the binding requirements on existence is specified
def child_has_ruleid_or_prefix(node):
if type(node).__name__ == "Element":
if "RuleID" in node.attributes or "IdPrefix" in node.attributes:
return True
for n in node.childNodes:
if child_has_ruleid_or_prefix(n): return True
optional = node.parentNode.localName == "Rules" or not child_has_ruleid_or_prefix(node)
elif node.localName == "EntityRule":
r = node.attributes["EntityName"].value
elif node.localName == "Template":
ref = node.attributes['ref'].value
# we break infinite recursion using this set
if ref not in visited:
n = self.concept.template(ref, visited=visited | {ref}).root
try:
p = p + node.attributes["IdPrefix"].value
except:
pass
elif node.localName == "Constraint":
r = mvdxml_expression.parse(node.attributes["Expression"].value)
elif node.localName == "EntityRules": pass
elif node.localName == "AttributeRules": pass
elif node.localName == "Rules": pass
elif node.localName == "Constraints": pass
elif node.localName == "References": pass
elif node.localName == "Definitions": return
elif node.localName == "SubTemplates": return # @todo perhaps just traverse them?
else:
raise ValueError(node.localName)
def _(n):
for subnode in n.childNodes:
if not isinstance(subnode, Element): continue
for x in visit(subnode, p, visited=visited): yield x
if r:
R = rule(node.localName, r, list(_(n)), (p + nm) if nm else nm, optional=optional)
for rr in R.nodes:
rr.parent = R
yield R
else:
for subnode in n.childNodes:
if not isinstance(subnode, Element): continue
for x in visit(subnode, p, visited=visited): yield x
return list(visit(root, visited=visited))[0]
class concept_or_applicability(object):
"""
Representation of either a mvdXML Concept or the Applicability node. Basically a structure
for the hierarchical TemplateRule
"""
def __init__(self, root, c):
self.root = root
self.concept_node = c
try:
self.name = c.attributes["name"].value
except:
# probably applicability and not concept
self.name = "Applicability"
def template(self, id=None, visited=None):
if id is None:
id = self.concept_node.getElementsByTagNameNS("*","Template")[0].attributes['ref'].value
for node in self.root.dom.getElementsByTagNameNS('*',"ConceptTemplate"):
if node.attributes["uuid"].value == id:
t = template(self, node)
t.parse(visited=visited)
t_with_rules = t.bind(self.rules())
return t_with_rules
def rules(self):
# Get the top most TemplateRule and traverse
try:
rules = self.concept_node.getElementsByTagNameNS("*","TemplateRules")[0]
except:
return []
def visit(rules):
def _():
for i, r in enumerate([c for c in rules.childNodes if isinstance(c, Element)]):
if i:
yield rules.attributes["operator"].value
if r.localName == "TemplateRules":
yield visit(r)
elif r.localName == "TemplateRule":
yield mvdxml_expression.parse(r.attributes["Parameters"].value)
else:
raise Exception()
return list(_())
return visit(rules)
class concept_root(object):
def __init__(self, dom, root):
self.dom, self.root = dom, root
self.name = root.attributes['name'].value
self.entity = str(root.attributes['applicableRootEntity'].value)
def applicability(self):
return concept_or_applicability(self, self.root.getElementsByTagNameNS("*","Applicability")[0])
def concepts(self):
for c in self.root.getElementsByTagNameNS("*","Concept"):
yield concept_or_applicability(self, c)
@staticmethod
def parse(fn):
dom = parse(fn)
if len(dom.getElementsByTagNameNS("*","ConceptRoot")):
for root in dom.getElementsByTagNameNS("*","ConceptRoot"):
CR = concept_root(dom, root)
yield CR
else:
for templ in dom.getElementsByTagNameNS("*","ConceptTemplate"):
t = template(None, templ)
t.parse()
yield t
@@ -0,0 +1,35 @@
from __future__ import print_function
if __name__ == "__main__":
import sys
from . import concept_root
if len(sys.argv) == 2:
mvdfn = sys.argv[1]
for mvd in concept_root.parse(mvdfn):
def dump(rule, parents):
print(" " * len(parents), rule.tag, rule.attribute)
for c in mvd.concepts():
print(c.name)
print()
t = c.template()
print("RootEntity", t.entity)
t.traverse(dump, with_parents=True)
print(" ".join(map(str, t.constraints)))
print()
elif len(sys.argv) == 3:
from . import sparql
mvdfn,ttlfn = sys.argv[1:]
sparql.derive_prefix(ttlfn)
ttlfn = sparql.infer_subtypes(ttlfn)
for mvd in concept_root.parse(mvdfn):
sparql.executor.run(mvd, mvdfn, ttlfn)
else:
print(sys.executable, "ifcopenshell.mvd", "<.mvdxml>")
print(sys.executable, "ifcopenshell.mvd", "<.mvdxml>", "<.ifc>")
@@ -0,0 +1,489 @@
import ifcopenshell
import ifcopenshell.geom
import itertools
import os
import xlsxwriter
import csv
def is_applicability(concept):
"""
Check whether the Concept created has a filtering purpose.
Actually, MvdXML has a specific Applicability node.
:param concept: mvdXML Concept object
"""
return concept.name.startswith("AP")
def merge_dictionaries(dicts):
d = {}
for e in dicts:
d.update(e)
return d
def extract_data(mvd_node, ifc_data):
"""
Recursively traverses mvdXML Concept tree structure.
This tree is made of different mvdXML Rule nodes: AttributesRule
and EntityRule.
:param mvd_node: an mvdXML Concept
:param ifc_data: an IFC instance or an IFC value
"""
to_combine = []
return_value = []
if len(mvd_node.nodes) == 0:
if mvd_node.tag == "AttributeRule":
try:
values_from_attribute = getattr(ifc_data, mvd_node.attribute)
return [{mvd_node: values_from_attribute}]
except:
return [{mvd_node: "Invalid Attribute"}]
else:
return [{mvd_node: ifc_data}]
if mvd_node.tag == 'AttributeRule':
data_from_attribute = []
try:
values_from_attribute = getattr(ifc_data, mvd_node.attribute)
if values_from_attribute is None:
return [{mvd_node:"Nonexistent value"}]
except:
return [{mvd_node:"Invalid attribute rule"}]
if isinstance(values_from_attribute, (list, tuple)):
if len(values_from_attribute) == 0:
return [{mvd_node: 'empty data structure'}]
data_from_attribute.extend(values_from_attribute)
else:
data_from_attribute.append(values_from_attribute)
for child in mvd_node.nodes:
for data in data_from_attribute:
child_values = extract_data(child, data)
if isinstance(child_values, (list, tuple)):
return_value.extend(child_values)
else:
return_value.append(child_values)
return return_value
elif mvd_node.tag == 'EntityRule':
# Avoid things like Quantities on Psets
if len(mvd_node.nodes):
if isinstance(ifc_data, ifcopenshell.entity_instance) and not ifc_data.is_a(mvd_node.attribute):
return []
for child in mvd_node.nodes:
if child.tag == "Constraint":
on_node = child.attribute[0].c
on_node = on_node.replace("'", "")
if isinstance(ifc_data, ifcopenshell.entity_instance):
ifc_type = type(ifc_data[0])
typed_node = (ifc_type)(on_node)
if ifc_data[0] == typed_node:
return [{mvd_node: ifc_data}]
elif ifc_data == on_node:
return [{mvd_node: ifc_data}]
else:
to_combine.append(extract_data(child, ifc_data))
if len(to_combine):
return_value = list(map(merge_dictionaries, itertools.product(*to_combine)))
return return_value
def open_mvd(filename):
"""
Open an mvdXML file.
:param filename: Path of the mvdXML file.
:return: mvdXML Concept instance.
"""
my_concept_object = list(ifcopenshell.mvd.concept_root.parse(filename))[0]
return my_concept_object
def format_data_from_nodes(recurse_output):
"""
Enable to format data collected such that the value to be exported is extracted.
:param recurse_output: Data extracted from the recursive function
"""
if len(recurse_output) > 1:
output = []
for resulting_dict in recurse_output:
intermediate_storing = []
for value in resulting_dict.values():
intermediate_storing.append(value)
output.extend(intermediate_storing)
return output
elif len(recurse_output) == 1:
return_list = []
intermediate_list = list(recurse_output[0].values())
if len(intermediate_list) > 1:
returned_value = intermediate_list
for element in intermediate_list:
# In case of a property that comes with all its path
# (like ['PSet_WallCommon, 'IsExternal', IfcBoolean(.F.)
# return only the list element which is not of string type
# todo: check above condition with ifcopenshell type
if not isinstance(element, str):
returned_value = element
if returned_value != intermediate_list:
return returned_value
else:
return intermediate_list
else:
return intermediate_list[0]
else:
return []
def get_data_from_mvd(entities, tree, filtering=False):
"""
Apply the recursive function on the entities to return
the values extracted.
:param entities: IFC instances to be processed.
:param tree: mvdXML Concept instance tree root.
:param filtering: Indicates whether the mvdXML tree is an applicability.
"""
filtered_entities = []
extracted_entities_data = {}
for entity in entities:
entity_id = entity.GlobalId
combinations = extract_data(tree, entity)
desired_results = []
for dictionary in combinations:
desired_results.append(dictionary)
output = format_data_from_nodes(desired_results)
if filtering:
if len(output):
extracted_entities_data[entity_id] = output
else:
extracted_entities_data[entity_id] = output
return extracted_entities_data
def correct_for_export(all_data):
"""
Process the data for spreadsheet export.
"""
for d in all_data:
for k, v in d.items():
if isinstance(v, list) or isinstance(v, tuple):
if len(v):
new_list = []
for data in v:
new_list.append(str(data))
d[k] = ','.join(new_list)
if len(v) == 0:
d[k] = 0
elif isinstance(v, ifcopenshell.entity_instance):
d[k] = v[0]
return all_data
def export_to_xlsx(xlsx_name, concepts, all_data):
"""
Export data towards XLSX spreadsheet format.
:param xlsx_name: Name of the outputted file.
:param concepts: List of mvdXML Concept instances.
:param all_data: Data extracted.
"""
if not os.path.isdir("spreadsheet_output/"):
os.mkdir("spreadsheet_output/")
workbook = xlsxwriter.Workbook("spreadsheet_output/" + xlsx_name)
worksheet = workbook.add_worksheet()
# Formats
bold_format = workbook.add_format()
bold_format.set_bold()
bold_format.set_center_across()
# Write first row
column_index = 0
for concept in concepts:
worksheet.write(0, column_index, concept.name, bold_format)
column_index += 1
col = 0
for feature in all_data:
row = 1
for d in feature.values():
worksheet.write(row, col, d)
row += 1
col += 1
workbook.close()
def export_to_csv(csv_name, concepts, all_data):
"""
Export data towards CSV spreadsheet format.
:param csv_name: Name of the file outputted file.
:param concepts: List of mvdXML Concept instances.
:param all_data: Data extracted.
"""
if not os.path.isdir("spreadsheet_output/"):
os.mkdir("spreadsheet_output/")
with open('spreadsheet_output/' + csv_name, 'w', newline='') as f:
writer = csv.writer(f)
header = [concept.name for concept in concepts]
first_row = writer.writerow(header)
values_by_row = []
for val in all_data:
values_by_row.append(list(val.values()))
entities_number = len(all_data[0].keys())
for i in range(0, entities_number):
row_to_write = []
for r in values_by_row:
row_to_write.append(r[i])
f = writer.writerow(row_to_write)
def get_data(mvd_concept, ifc_file, spreadsheet_export=True):
"""
Use the majority of all the other functions to return the data
queried by the mvdXML file in python format.
:param mvd_concept: mvdXML Concept instance.
:param ifc_file: IFC file from any schema.
:param spreadsheet_export: The spreadsheet export is carried out when set to True.
"""
# Check if IFC entities have been filtered at least once
filtered = 0
entities = ifc_file.by_type(mvd_concept.entity)
selected_entities = entities
verification_matrix = {}
for entity in selected_entities:
verification = dict()
verification_matrix[entity.GlobalId] = verification
# For each Concept(ConceptTemplate) in the ConceptRoot
concepts = sorted(mvd_concept.concepts(), key=is_applicability, reverse=True)
all_data = []
counter = 0
for concept in concepts:
if is_applicability(concept):
filtering = True
else:
filtering = False
# Access all the Rules of the ConceptTemplate
if len(concept.template().rules) > 1:
attribute_rules = []
for rule in concept.template().rules:
attribute_rules.append(rule)
rules_root = ifcopenshell.mvd.rule("EntityRule", mvd_concept.entity, attribute_rules)
else:
rules_root = concept.template().rules[0]
extracted_data = get_data_from_mvd(selected_entities, rules_root, filtering=filtering)
all_data.append(extracted_data)
if filtering:
filtered = 1
new_entities = []
for entity_id in all_data[counter].keys():
if len(all_data[counter][entity_id]) != 0:
entity = ifc_file.by_id(entity_id)
new_entities.append(entity)
selected_entities = new_entities
not_respecting_entities = [item for item in entities if item not in selected_entities]
for entity in entities:
val = 0
if entity in not_respecting_entities:
val = 1
verification_matrix[entity.GlobalId].update({concept.name: val})
counter += 1
all_data = correct_for_export(all_data)
if spreadsheet_export:
if filtered != 0:
export_name = "output_filtered"
else:
export_name = "output_non_filtered"
export_to_xlsx(export_name + '.xlsx', concepts, all_data)
export_to_csv(export_name + '.csv', concepts, all_data)
return all_data, verification_matrix
def get_non_respecting_entities(file, verification_matrix):
non_respecting = []
for k, v in verification_matrix.items():
entity = file.by_id(k)
print(list(v.values()))
if sum(v.values()) != 0:
non_respecting.append(entity)
return non_respecting
def get_respecting_entities(file, verification_matrix):
respecting = []
for k, v in verification_matrix.items():
entity = file.by_id(k)
print(list(v.values()))
if sum(v.values()) == 0:
respecting.append(entity)
return respecting
def visualize(file, not_respecting_entities):
"""
Visualize the instances of the entity type targeted by the mvdXML ConceptRoot.
At display, a color differentiation is made between the entities which comply with
mvdXML requirements and the ones which don't.
:param file: IFC file from any schema.
:param not_respecting_entities: Entities which don't comply with mvdXML requirements.
"""
s = ifcopenshell.geom.main.settings()
s.set(s.USE_PYTHON_OPENCASCADE, True)
s.set(s.DISABLE_OPENING_SUBTRACTIONS, False)
viewer = ifcopenshell.geom.utils.initialize_display()
entity_type = not_respecting_entities[0].is_a()
other_entities = [x for x in file.by_type("IfcBuildingElement") if x.is_a() != str(entity_type)]
set_of_entities = set(not_respecting_entities) | set(file.by_type(entity_type))
set_to_display = set_of_entities.union(set(other_entities))
for el in set_to_display:
if el in not_respecting_entities:
c = (1, 0, 0, 1)
elif el in other_entities:
c = (1, 1, 1, 0)
else:
c = (0, 1, 0.5, 1)
try:
shape = ifcopenshell.geom.create_shape(s, el)
# OCC.BRepTools.breptools_Write(shape.geometry, "test.brep")
ds = ifcopenshell.geom.utils.display_shape(shape, clr=c)
except:
pass
viewer.FitAll()
ifcopenshell.geom.utils.main_loop()
def validate_data(concept, data):
import io
import ast
import operator
from functools import reduce, partial
rules = [x[0] for x in concept.rules() if not isinstance(x, str)]
def transform_data(d):
"""
Transform dictionary keys from tree nodes to rule ids
"""
return {(k.parent if k.bind is None and k.parent.bind is not None else k).bind: v for k, v in d.items()}
def parse_mvdxml_token(v):
# @todo make more permissive and tolerant
return ast.literal_eval(v)
data = list(map(transform_data, data))
output = io.StringIO()
# https://stackoverflow.com/a/70227259
def operation_reduce(x, y):
"""
Takes alternating value and function as input and
reduces while applying function
"""
if callable(x):
return x(y)
else:
return partial(y, x)
def apply_rules():
for r in rules:
def apply_data():
for d in data:
def translate(v):
if isinstance(v, str):
return getattr(operator, v.lower() + "_")
else:
if v.b == "Value":
return d.get(v.a) == parse_mvdxml_token(v.c)
elif v.b == "Type":
return d.get(v.a) and d.get(v.a).is_a(parse_mvdxml_token(v.c))
r2 = list(map(translate, r))
yield reduce(operation_reduce, r2)
v = any(list(apply_data()))
print(("Met:" if v else "Not met:"), r, file=output)
yield v
valid = all(list(apply_rules()))
return valid, output.getvalue()
if __name__ == '__main__':
print('functions to parse MVD rules and extract IFC data/filter IFC entities from them')
@@ -0,0 +1,190 @@
<?xml version="1.0" encoding="UTF-8"?>
<mvdXML name="mvdXML examples" uuid="4afb1a8b-0b61-4ff8-9863-c10690fe06f2" xmlns="http://buildingsmart-tech.org/mvdXML/mvdXML1-1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://buildingsmart-tech.org/mvdXML/mvdXML1-1 ../xsd/mvdXML_V1-1_draft.xsd">
<Templates>
<ConceptTemplate uuid="4b385464-b99a-42bc-a17a-a0a647a1ab5b" name="Association" code="" status="" applicableSchema="IFC4" applicableEntity="IfcObjectDefinition">
<Definitions>
<Definition>
<Body><![CDATA[]]></Body>
</Definition>
</Definitions>
<SubTemplates>
<ConceptTemplate uuid="ea2a63be-fd0d-426d-863b-52c3970ca585" name="Material" code="" status="" applicableSchema="IFC4" applicableEntity="IfcObjectDefinition">
<Definitions>
<Definition>
<Body><![CDATA[<p class="std">
Any product or product type can have associated materials indicating the physical composition of an object.
Materials can have representations for surface styles indicating colors, textures, and light reflectance for 3D
rendering. Materials can have representations for fill styles indicating colors, tiles, and hatch patterns for
2D rendering. Materials can have properties such as density, elasticity, thermal resistance, and others as
defined in this specification. Materials can also be classified according to a referenced industry standard.
</p>
<p class="std">
An object can be comprised of a single material or a set of materials with a particular layout. Several
examples include:
</p>
<ul class="std">
<li class="std">a slab may have an associated layer of concrete;
</li>
<li class="std">a beam may have an associated I-Shape profile of steel;
</li>
<li class="std">a door may have associated constituents for framing and glazing;
</li>
<li class="std">a port may have an associated profile and/or material flowing through it such as hot water.
</li>
</ul>
]]></Body>
</Definition>
</Definitions>
<SubTemplates>
<ConceptTemplate uuid="6d5fb86f-3f2d-49fb-9528-077855ddcc47" name="Material Layer Set Usage" code="" status="" applicableSchema="IFC4" applicableEntity="IfcProduct">
<Definitions>
<Definition>
<Body><![CDATA[<p>Material layer set usage defines layout at occurrences to indicate a direction and offset from the 'Axis' reference curve, and a reference extent such as for a default wall height. </p>]]></Body>
</Definition>
</Definitions>
<Rules>
<AttributeRule AttributeName="HasAssociations" Cardinality="One">
<EntityRules>
<EntityRule EntityName="IfcRelAssociatesMaterial" Cardinality="_asSchema">
<AttributeRules>
<AttributeRule AttributeName="RelatingMaterial" Cardinality="_asSchema">
<EntityRules>
<EntityRule EntityName="IfcMaterialLayerSetUsage" Cardinality="_asSchema">
<AttributeRules>
<AttributeRule AttributeName="ForLayerSet" Cardinality="_asSchema">
<EntityRules>
<EntityRule EntityName="IfcMaterialLayerSet" Cardinality="_asSchema">
<AttributeRules>
<AttributeRule AttributeName="MaterialLayers" Cardinality="_asSchema">
<EntityRules>
<EntityRule EntityName="IfcMaterialLayer" Cardinality="_asSchema">
<AttributeRules>
<AttributeRule AttributeName="Name" Cardinality="_asSchema">
<EntityRules>
<EntityRule EntityName="IfcLabel" Cardinality="_asSchema">
</EntityRule>
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="Material" Cardinality="_asSchema">
<EntityRules>
<EntityRule EntityName="IfcMaterial" Cardinality="_asSchema">
<AttributeRules>
<AttributeRule AttributeName="Name" Cardinality="_asSchema">
<EntityRules>
<EntityRule EntityName="IfcLabel" Cardinality="_asSchema">
</EntityRule>
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="Description" Cardinality="_asSchema">
<EntityRules>
<EntityRule EntityName="IfcText" Cardinality="_asSchema">
</EntityRule>
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="Category" Cardinality="_asSchema">
<EntityRules>
<EntityRule EntityName="IfcLabel" Cardinality="_asSchema">
</EntityRule>
</EntityRules>
</AttributeRule>
</AttributeRules>
</EntityRule>
</EntityRules>
</AttributeRule>
<AttributeRule RuleID="" AttributeName="LayerThickness" Cardinality="_asSchema">
<EntityRules>
<EntityRule EntityName="IfcNonNegativeLengthMeasure" Cardinality="_asSchema">
</EntityRule>
</EntityRules>
</AttributeRule>
</AttributeRules>
</EntityRule>
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="LayerSetName" Cardinality="_asSchema">
<EntityRules>
<EntityRule EntityName="IfcLabel" Cardinality="_asSchema">
</EntityRule>
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="Description" Cardinality="_asSchema">
<EntityRules>
<EntityRule EntityName="IfcText" Cardinality="_asSchema">
</EntityRule>
</EntityRules>
</AttributeRule>
</AttributeRules>
</EntityRule>
</EntityRules>
</AttributeRule>
<AttributeRule RuleID="DirectionSense" AttributeName="DirectionSense" Cardinality="_asSchema">
<EntityRules>
<EntityRule EntityName="IfcDirectionSenseEnum" Cardinality="_asSchema">
</EntityRule>
</EntityRules>
</AttributeRule>
<AttributeRule RuleID="LayerSetDirection" AttributeName="LayerSetDirection" Cardinality="_asSchema">
<EntityRules>
<EntityRule EntityName="IfcLayerSetDirectionEnum" Cardinality="_asSchema">
</EntityRule>
</EntityRules>
</AttributeRule>
</AttributeRules>
</EntityRule>
</EntityRules>
</AttributeRule>
</AttributeRules>
</EntityRule>
</EntityRules>
</AttributeRule>
</Rules>
</ConceptTemplate>
</SubTemplates>
</ConceptTemplate>
</SubTemplates>
</ConceptTemplate>
</Templates>
<Views>
<ModelView uuid="f935ce4c-b52e-4175-ac7f-cca0dc638871" name="CoordinationView" version="2014" applicableSchema="IFC4">
<ExchangeRequirements>
<ExchangeRequirement uuid="9a71e977-a156-426b-8599-c7cf6dc463c1" name="Examples" applicability="export">
</ExchangeRequirement>
</ExchangeRequirements>
<Roots>
<ConceptRoot uuid="30188bbe-5eea-4cd6-a8ee-3414148d3a50" name= "Slab" applicableRootEntity="IfcSlab">
<Concepts>
<Concept uuid="59b515d0-d057-45c3-acbb-851dd9ba14a2" name="Material Layer Set Usage" Override="false">
<Template ref="6d5fb86f-3f2d-49fb-9528-077855ddcc47" />
<Requirements>
<Requirement applicability="export" requirement="mandatory" exchangeRequirement="9a71e977-a156-426b-8599-c7cf6dc463c1" />
</Requirements>
<Rules>
<TemplateRule Parameters="DirectionSense[Value]='POSITIVE' AND LayerSetDirection[Value]='AXIS3' " />
</Rules>
</Concept>
</Concepts>
</ConceptRoot>
</Roots>
</ModelView>
</Views>
</mvdXML>
@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8"?>
<mvdXML name="mvdXML examples" uuid="4afb1a8b-0b61-4ff8-9863-c10690fe06f2" xmlns="http://buildingsmart-tech.org/mvdXML/mvdXML1-1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://buildingsmart-tech.org/mvdXML/mvdXML1-1 ../xsd/mvdXML_V1-1_draft.xsd">
<Templates>
<ConceptTemplate uuid="252a5fa6-cc5b-4d30-bd0c-35e22e336499" name="Connectivity" code="" status="" applicableSchema="IFC4" applicableEntity="IfcObject">
<Definitions>
<Definition>
<Body><![CDATA[<p class="std">
Objects may participate in various connectivity
relationships with other objects.
</p>
]]></Body>
</Definition>
</Definitions>
<SubTemplates>
<ConceptTemplate uuid="06674893-7a2c-493b-8eb5-e85a058707b3" name="Filling" status="" applicableSchema="IFC4" applicableEntity="IfcElement">
<Definitions>
<Definition>
<Body><![CDATA[<p>Elements such as doors and windows may be placed inside openings of walls, slabs, or other elements.</p>]]></Body>
</Definition>
</Definitions>
<Rules>
<AttributeRule AttributeName="FillsVoids" Cardinality="_asSchema">
<EntityRules>
<EntityRule EntityName="IfcRelFillsElement" Cardinality="_asSchema">
<AttributeRules>
<AttributeRule AttributeName="RelatingOpeningElement" Cardinality="_asSchema">
<EntityRules>
<EntityRule EntityName="IfcOpeningElement" Cardinality="_asSchema">
<AttributeRules>
<AttributeRule AttributeName="VoidsElements" Cardinality="_asSchema">
<EntityRules>
<EntityRule EntityName="IfcRelVoidsElement" Cardinality="_asSchema">
<AttributeRules>
<AttributeRule RuleID="Type" AttributeName="RelatingElement" Cardinality="_asSchema">
<EntityRules>
<EntityRule EntityName="IfcElement" Cardinality="_asSchema">
</EntityRule>
</EntityRules>
</AttributeRule>
</AttributeRules>
</EntityRule>
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="HasFillings" Cardinality="ZeroToOne">
</AttributeRule>
</AttributeRules>
</EntityRule>
</EntityRules>
</AttributeRule>
</AttributeRules>
</EntityRule>
</EntityRules>
</AttributeRule>
</Rules>
</ConceptTemplate>
</SubTemplates>
</ConceptTemplate>
</Templates>
<Views>
<ModelView uuid="f935ce4c-b52e-4175-ac7f-cca0dc638871" name="CoordinationView" version="2014" applicableSchema="IFC4">
<ExchangeRequirements>
<ExchangeRequirement uuid="9a71e977-a156-426b-8599-c7cf6dc463c1" name="Examples" applicability="export">
</ExchangeRequirement>
</ExchangeRequirements>
<Roots>
<ConceptRoot uuid="d2b8f47b-36b7-48a2-b248-f9d7a921f6e1" name="Door" applicableRootEntity="IfcDoor">
<Concepts>
<Concept uuid="8329cb90-1062-401f-b965-8fa07202225a" name="Filling">
<Template ref="06674893-7a2c-493b-8eb5-e85a058707b3" />
<Requirements>
<Requirement applicability="export" requirement="optional" exchangeRequirement="9a71e977-a156-426b-8599-c7cf6dc463c1" />
</Requirements>
</Concept>
</Concepts>
</ConceptRoot>
<ConceptRoot uuid="f1013c14-f631-4a05-99f7-73f772025997" name="Window" applicableRootEntity="IfcWindow">
<Concepts>
<Concept uuid="7dca33ea-2faf-43b3-9f09-4bf8aa06d43d" name="Filling">
<Template ref="06674893-7a2c-493b-8eb5-e85a058707b3" />
<Requirements>
<Requirement applicability="export" requirement="optional" exchangeRequirement="9a71e977-a156-426b-8599-c7cf6dc463c1" />
</Requirements>
</Concept>
</Concepts>
</ConceptRoot>
</Roots>
</ModelView>
</Views>
</mvdXML>
@@ -0,0 +1,111 @@
<?xml version="1.0" encoding="UTF-8"?>
<mvdXML name="mvdXML examples" uuid="4afb1a8b-0b61-4ff8-9863-c10690fe06f2" xmlns="http://buildingsmart-tech.org/mvdXML/mvdXML1-1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://buildingsmart-tech.org/mvdXML/mvdXML1-1 ../xsd/mvdXML_V1-1_draft.xsd">
<Templates>
<ConceptTemplate uuid="805deb96-2684-4bc5-a9ad-3a29199dc023" name="Project" status="" applicableSchema="IFC4" applicableEntity="IfcContext">
<Definitions>
<Definition>
<Body><![CDATA[<p>All files contain a single <i>IfcProject</i> instance indicating overall context and a directory of objects contained within.</p>]]></Body>
</Definition>
</Definitions>
<SubTemplates>
<ConceptTemplate uuid="38dac6f0-997c-4544-9bca-b6326b9a3e4b" name="Project Context" status="" applicableSchema="IFC4" applicableEntity="IfcContext">
<Definitions>
<Definition>
<Body><![CDATA[ <p class="std">
A project representation context indicates the coordinate system orientation, direction of true north,
precision, and other values that apply to all geometry within a project or project library.
</p>
]]></Body>
</Definition>
</Definitions>
<Rules>
<AttributeRule RuleID="RepresentationContext" AttributeName="RepresentationContexts" Cardinality="_asSchema">
<EntityRules>
<EntityRule EntityName="IfcGeometricRepresentationContext" Cardinality="_asSchema">
<AttributeRules>
<AttributeRule AttributeName="ContextIdentifier" Cardinality="_asSchema">
<EntityRules>
<EntityRule EntityName="IfcLabel" Cardinality="_asSchema">
</EntityRule>
</EntityRules>
</AttributeRule>
<AttributeRule RuleID="ContextType" AttributeName="ContextType" Cardinality="_asSchema">
<EntityRules>
<EntityRule EntityName="IfcLabel" Cardinality="_asSchema">
</EntityRule>
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="CoordinateSpaceDimension" Cardinality="_asSchema">
<EntityRules>
<EntityRule EntityName="IfcDimensionCount" Cardinality="_asSchema">
</EntityRule>
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="WorldCoordinateSystem" Cardinality="_asSchema">
<EntityRules>
<EntityRule EntityName="IfcAxis2Placement3D" Cardinality="_asSchema">
</EntityRule>
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="TrueNorth" Cardinality="_asSchema">
<EntityRules>
<EntityRule EntityName="IfcDirection" Cardinality="_asSchema">
</EntityRule>
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="HasSubContexts" Cardinality="_asSchema">
<EntityRules>
<EntityRule EntityName="IfcGeometricRepresentationSubContext" Cardinality="_asSchema">
<AttributeRules>
<AttributeRule RuleID="SubContextIdentifier" AttributeName="ContextIdentifier" Cardinality="_asSchema">
<EntityRules>
<EntityRule EntityName="IfcLabel" Cardinality="_asSchema">
</EntityRule>
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="ContextType" Cardinality="_asSchema">
<EntityRules>
<EntityRule EntityName="IfcLabel" Cardinality="_asSchema">
</EntityRule>
</EntityRules>
</AttributeRule>
</AttributeRules>
</EntityRule>
</EntityRules>
</AttributeRule>
</AttributeRules>
</EntityRule>
</EntityRules>
</AttributeRule>
</Rules>
</ConceptTemplate>
</SubTemplates>
</ConceptTemplate>
</Templates>
<Views>
<ModelView uuid="f935ce4c-b52e-4175-ac7f-cca0dc638871" name="CoordinationView" version="2014" applicableSchema="IFC4">
<ExchangeRequirements>
<ExchangeRequirement uuid="9a71e977-a156-426b-8599-c7cf6dc463c1" name="Examples" applicability="export">
</ExchangeRequirement>
</ExchangeRequirements>
<Roots>
<ConceptRoot uuid="dc78525e-b86d-45e1-a3fc-aaf15d1624f9" name="Project" applicableRootEntity="IfcProject">
<Concepts>
<Concept uuid="2f343b21-7a22-4674-af0b-48144a075fc9" name="Project Context">
<Template ref="38dac6f0-997c-4544-9bca-b6326b9a3e4b" />
<Requirements>
<Requirement applicability="export" requirement="mandatory" exchangeRequirement="9a71e977-a156-426b-8599-c7cf6dc463c1" />
</Requirements>
<Rules>
<TemplateRule Parameters="RepresentationContext[Size]&lt;3 AND ContextType[Value]='Model' AND SubContextIdentifier[Value]='Body' " />
</Rules>
</Concept>
</Concepts>
</ConceptRoot>
</Roots>
</ModelView>
</Views>
</mvdXML>
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,213 @@
<?xml version="1.0"?>
<mvdXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" uuid="b4b7c35a-f8e7-468f-ab57-822fc0750dc8" name="" status="sample" xsi:schemaLocation="http://www.buildingsmart-tech.org/mvd/XML/1.1 http://www.buildingsmart-tech.org/mvd/XML/1.1/mvdXML_V1.1_add1.xsd" xmlns="http://buildingsmart-tech.org/mvd/XML/1.1">
<Templates>
<ConceptTemplate uuid="d862db8a-fdc4-4d1d-9934-cddee2ae2a88" name="IsExternal" status="sample" applicableSchema="IFC4" applicableEntity="IfcWall">
<Rules>
<AttributeRule AttributeName="IsDefinedBy">
<EntityRules>
<EntityRule EntityName="IfcRelDefinesByProperties">
<AttributeRules>
<AttributeRule AttributeName="RelatingPropertyDefinition">
<EntityRules>
<EntityRule EntityName="IfcPropertySet">
<AttributeRules>
<AttributeRule AttributeName="Name">
<EntityRules>
<EntityRule EntityName="IfcLabel">
<Constraints>
<Constraint Expression="[Value] = 'Pset_WallCommon'" />
</Constraints>
</EntityRule>
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="HasProperties">
<EntityRules>
<EntityRule EntityName="IfcPropertySingleValue">
<AttributeRules>
<AttributeRule AttributeName="Name">
<EntityRules>
<EntityRule EntityName="IfcIdentifier">
<Constraints>
<Constraint Expression="[Value] = 'IsExternal'" />
</Constraints>
</EntityRule>
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="NominalValue">
<EntityRules>
<EntityRule EntityName="IfcBoolean">
<Constraints>
<Constraint Expression="[Value] = 'True'" />
</Constraints>
</EntityRule>
</EntityRules>
</AttributeRule>
</AttributeRules>
</EntityRule>
</EntityRules>
</AttributeRule>
</AttributeRules>
</EntityRule>
</EntityRules>
</AttributeRule>
</AttributeRules>
</EntityRule>
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="Name">
<EntityRules>
<EntityRule EntityName="IfcLabel" />
</EntityRules>
</AttributeRule>
</Rules>
</ConceptTemplate>
<ConceptTemplate uuid="57879083-3675-4fe0-b0f1-9d17a6a4dcb6" name="Name" status="sample" applicableSchema="IFC4" applicableEntity="IfcRoot">
<Rules>
<AttributeRule AttributeName="Name">
<EntityRules>
<EntityRule EntityName="IfcLabel" />
</EntityRules>
</AttributeRule>
</Rules>
</ConceptTemplate>
<ConceptTemplate uuid="f99fe764-9732-4029-955e-08c51dd854e3" name="MaterialLayer" status="sample" applicableSchema="IFC4" applicableEntity="IfcWall">
<Rules>
<AttributeRule AttributeName="HasAssociations">
<EntityRules>
<EntityRule EntityName="IfcRelAssociatesMaterial">
<AttributeRules>
<AttributeRule AttributeName="RelatingMaterial">
<EntityRules>
<EntityRule EntityName="IfcMaterialLayerSetUsage">
<AttributeRules>
<AttributeRule AttributeName="ForLayerSet">
<EntityRules>
<EntityRule EntityName="IfcMaterialLayerSet">
<AttributeRules>
<AttributeRule AttributeName="MaterialLayers">
<EntityRules>
<EntityRule EntityName="IfcMaterialLayer">
<AttributeRules>
<AttributeRule AttributeName="LayerThickness">
<EntityRules>
<EntityRule EntityName="IfcNonNegativeLengthMeasure" />
</EntityRules>
</AttributeRule>
</AttributeRules>
</EntityRule>
</EntityRules>
</AttributeRule>
</AttributeRules>
</EntityRule>
</EntityRules>
</AttributeRule>
</AttributeRules>
</EntityRule>
</EntityRules>
</AttributeRule>
</AttributeRules>
</EntityRule>
</EntityRules>
</AttributeRule>
</Rules>
</ConceptTemplate>
<ConceptTemplate uuid="96ae8928-8f91-4768-bd40-89a89d6c6fc8" name="HasOpenings" status="sample" applicableSchema="IFC4" applicableEntity="IfcWall">
<Rules>
<AttributeRule AttributeName="HasOpenings">
<EntityRules>
<EntityRule EntityName="IfcRelVoidsElement">
<AttributeRules>
<AttributeRule AttributeName="GlobalId">
<EntityRules>
<EntityRule EntityName="IfcGloballyUniqueId" />
</EntityRules>
</AttributeRule>
</AttributeRules>
</EntityRule>
</EntityRules>
</AttributeRule>
</Rules>
</ConceptTemplate>
<ConceptTemplate uuid="b6b5f23a-efc8-4b0a-96d5-f8adbddc8796" name="TemplateDefinition2" status="sample" applicableSchema="IFC4" applicableEntity="IfcWall">
<Rules>
<AttributeRule AttributeName="IsDefinedBy">
<EntityRules>
<EntityRule EntityName="IfcRelDefinesByProperties">
<AttributeRules>
<AttributeRule AttributeName="RelatingPropertyDefinition">
<EntityRules>
<EntityRule EntityName="IfcPropertySet">
<AttributeRules>
<AttributeRule AttributeName="HasProperties">
<EntityRules>
<EntityRule EntityName="IfcPropertySingleValue">
<AttributeRules>
<AttributeRule AttributeName="NominalValue">
<EntityRules>
<EntityRule EntityName="IfcAreaMeasure" />
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="Name">
<EntityRules>
<EntityRule EntityName="IfcIdentifier">
<Constraints>
<Constraint Expression="[Value] = 'Area'" />
</Constraints>
</EntityRule>
</EntityRules>
</AttributeRule>
</AttributeRules>
</EntityRule>
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="Name">
<EntityRules>
<EntityRule EntityName="IfcLabel">
<Constraints>
<Constraint Expression="[Value] = 'PSet_Revit_Dimensions'" />
</Constraints>
</EntityRule>
</EntityRules>
</AttributeRule>
</AttributeRules>
</EntityRule>
</EntityRules>
</AttributeRule>
</AttributeRules>
</EntityRule>
</EntityRules>
</AttributeRule>
</Rules>
</ConceptTemplate>
</Templates>
<Views>
<ModelView uuid="cb00b001-d3d4-4e6a-8c1a-f97526c8d227" name="Wall_Extraction" status="sample" applicableSchema="IFC4">
<ExchangeRequirements />
<Roots>
<ConceptRoot uuid="9c5337ac-83db-4ef3-92fc-086d03dfc521" name="IfcWall" status="proposal" applicableRootEntity="IfcWall">
<Applicability uuid="00000000-0000-0000-0000-000000000000" status="sample">
<Template ref="96ae8928-8f91-4768-bd40-89a89d6c6fc8" />
<TemplateRules operator="and" />
</Applicability>
<Concepts>
<Concept uuid="eaf87838-a06e-4b64-bbd7-bed4d455e825" name="APexternal" status="sample" override="false">
<Template ref="d862db8a-fdc4-4d1d-9934-cddee2ae2a88" />
</Concept>
<Concept uuid="e2f1ffad-4509-489c-a294-81909060e2e9" name="voids" status="sample" override="false">
<Template ref="96ae8928-8f91-4768-bd40-89a89d6c6fc8" />
</Concept>
<Concept uuid="9325e5cb-45d1-4c35-8925-d70409fe6685" name="mat" status="sample" override="false">
<Template ref="f99fe764-9732-4029-955e-08c51dd854e3" />
</Concept>
<Concept uuid="ecb11482-1b53-4853-9674-d3069b45a7ca" name="name" status="sample" override="false">
<Template ref="57879083-3675-4fe0-b0f1-9d17a6a4dcb6" />
</Concept>
<Concept uuid="c93399aa-c032-4f0e-883b-2d41783fa94d" name="area" status="sample" override="false">
<Template ref="b6b5f23a-efc8-4b0a-96d5-f8adbddc8796" />
</Concept>
</Concepts>
</ConceptRoot>
</Roots>
</ModelView>
</Views>
</mvdXML>
@@ -0,0 +1,513 @@
<?xml version="1.0"?>
<mvdXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" uuid="9cad09cc-c9b9-4425-85cb-0a371405013b" name="" status="sample" xsi:schemaLocation="http://www.buildingsmart-tech.org/mvd/XML/1.1 http://www.buildingsmart-tech.org/mvd/XML/1.1/mvdXML_V1.1_add1.xsd" xmlns="http://buildingsmart-tech.org/mvd/XML/1.1">
<Templates>
<ConceptTemplate uuid="33e0be15-e301-4858-9f4b-18b2eb5488ba" name="Object Definition" status="sample" applicableSchema="IFC4" applicableEntity="IfcObjectDefinition">
<Definitions>
<Definition>
<Body><![CDATA[<p>The concept templates of <em>Object Definition</em> provides the means to define an object occurrence by its object type and attached property and quantity sets.</p>]]></Body>
</Definition>
</Definitions>
<SubTemplates>
<ConceptTemplate uuid="36984334-3ac8-4e59-85a6-f68d65e379c7" name="Property Sets" status="sample" applicableSchema="IFC4" applicableEntity="IfcRoot">
<Definitions>
<Definition>
<Body><![CDATA[<p>The concept template <em>Property Sets</em> describes how sets of properties (usually defined by a name, value, unit triple) are associated to objects or object types.</p>]]></Body>
</Definition>
</Definitions>
<SubTemplates>
<ConceptTemplate uuid="f74255a6-0c0e-4f31-84ad-24981db62461" name="Property Sets for Objects" version="1" status="sample" applicableSchema="IFC4" applicableEntity="IfcObject">
<Definitions>
<Definition>
<Body><![CDATA[<p>The concept template <em>Property Sets for Objects</em> describes how an object occurrence can be related to a single or multiple property sets. A property set
contains a single or multiple properties. The data types of
an individual property are single value, enumerated value,
bounded value, table value, reference value, list value,
and combination of property occurrences.
</p>
<p>Property sets can also be related to an object type, see concept <em>Property Sets for Types</em>. They then define the common properties for all occurrences of the same type. If the same property (by name) is provided by the same property set (by name), then the properties directly assigned to the object occurrence override the properties assigned to the object type.</p>
]]></Body>
</Definition>
</Definitions>
<Rules>
<AttributeRule RuleID="PredefinedType" AttributeName="PredefinedType" />
<AttributeRule AttributeName="IsDefinedBy">
<EntityRules>
<EntityRule EntityName="IfcRelDefinesByProperties">
<AttributeRules>
<AttributeRule AttributeName="RelatingPropertyDefinition">
<EntityRules>
<EntityRule EntityName="IfcPropertySet">
<AttributeRules>
<AttributeRule RuleID="PsetName" AttributeName="Name" />
<AttributeRule RuleID="Properties" AttributeName="HasProperties">
<EntityRules>
<EntityRule EntityName="IfcPropertySingleValue">
<References>
<Template ref="6655f6d0-29a8-47b8-8f3d-c9fce9c9a620" />
</References>
</EntityRule>
<EntityRule EntityName="IfcPropertyBoundedValue">
<References>
<Template ref="3d67a2d2-761d-44d9-a09e-b7fbb1fa5632" />
</References>
</EntityRule>
<EntityRule EntityName="IfcPropertyEnumeratedValue">
<References>
<Template ref="c148a099-c351-43a8-9266-5f3de0b45a95" />
</References>
</EntityRule>
<EntityRule EntityName="IfcPropertyListValue">
<References>
<Template ref="8e10b688-9179-4e3a-8db2-6abcaafe952d" />
</References>
</EntityRule>
<EntityRule EntityName="IfcPropertyTableValue">
<References>
<Template ref="35c947b0-6abc-4b13-8ec7-696ef2041721" />
</References>
</EntityRule>
</EntityRules>
</AttributeRule>
</AttributeRules>
</EntityRule>
</EntityRules>
</AttributeRule>
</AttributeRules>
</EntityRule>
</EntityRules>
</AttributeRule>
</Rules>
</ConceptTemplate>
</SubTemplates>
</ConceptTemplate>
<ConceptTemplate uuid="6652398e-6579-4460-8cb4-26295acfacc7" name="Quantity Sets" version="1" status="sample" applicableSchema="IFC4" applicableEntity="IfcObject">
<Definitions>
<Definition>
<Body><![CDATA[
<p>
Any specialization of object can be related to multiple quantity set occurrences. A quantity set
contains multiple quantity occurrences. The data type of
quantity occurrence values are count, length, area, volume, weight, time, or a combination of quantities. Each quantity is defined by its name, value, and optionally a description and a formula.</p>
<p>The quantity set is expressed by instances of <em>IfcElementQuantity</em>, where the <em>Name</em> attribute determines the common designator of the quantity set. This specification contains a number of predefined quantity sets, a template definition is provided for each of them. The name of the template has to be used as the value of the <em>Name</em> attribute. The <em>MethodOfMeasurement</em> attribute specifies the method, by which the values of the individual quantities are calculated. For the quantity set templates included in this specification, the value of <em>MethodOfMeasurement</em> shall be "BaseQuantities".</p>]]></Body>
</Definition>
</Definitions>
<Rules>
<AttributeRule AttributeName="IsDefinedBy">
<EntityRules>
<EntityRule EntityName="IfcRelDefinesByProperties">
<AttributeRules>
<AttributeRule AttributeName="RelatingPropertyDefinition">
<EntityRules>
<EntityRule EntityName="IfcElementQuantity">
<AttributeRules>
<AttributeRule RuleID="QsetName" AttributeName="Name">
<EntityRules>
<EntityRule EntityName="IfcLabel" />
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="Description">
<EntityRules>
<EntityRule EntityName="IfcText" />
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="MethodOfMeasurement">
<EntityRules>
<EntityRule EntityName="IfcLabel" />
</EntityRules>
</AttributeRule>
<AttributeRule RuleID="Quantities" AttributeName="Quantities">
<EntityRules>
<EntityRule EntityName="IfcQuantityLength">
<References>
<Template ref="dd8678e1-e300-4f70-9d63-e539db4bd11c" />
</References>
</EntityRule>
<EntityRule EntityName="IfcQuantityArea">
<References>
<Template ref="65ac4747-6eff-437e-94e2-643fd4e3bf86" />
</References>
</EntityRule>
<EntityRule EntityName="IfcQuantityVolume">
<References>
<Template ref="6491a3b0-b7e9-412a-8226-bcd91c2b0b0e" />
</References>
</EntityRule>
<EntityRule EntityName="IfcQuantityWeight">
<References>
<Template ref="e1016e56-3c89-4f42-9679-07e1db3c0afb" />
</References>
</EntityRule>
<EntityRule EntityName="IfcQuantityCount">
<References>
<Template ref="8aaeff32-572c-4f6a-ac64-e2151663cbf1" />
</References>
</EntityRule>
<EntityRule EntityName="IfcQuantityTime">
<References>
<Template ref="43c4c050-04de-4b0f-9e43-708bd98201a8" />
</References>
</EntityRule>
</EntityRules>
</AttributeRule>
</AttributeRules>
</EntityRule>
</EntityRules>
</AttributeRule>
</AttributeRules>
</EntityRule>
</EntityRules>
</AttributeRule>
</Rules>
</ConceptTemplate>
</SubTemplates>
</ConceptTemplate>
<ConceptTemplate uuid="a322fdd7-cd28-4ea7-8797-f6cf124ab3d6" name="Partial Templates" status="sample" applicableSchema="IFC4">
<Definitions>
<Definition>
<Body><![CDATA[<p>Partial concept templates are described herein to indicate usage of common data types, which are then incorporated into other templates.</p>]]></Body>
</Definition>
</Definitions>
<SubTemplates>
<ConceptTemplate uuid="88b4aaa9-0925-447c-b009-fe357b7c754e" name="Values" status="sample" applicableSchema="IFC4" applicableEntity="IfcSimpleProperty">
<Definitions>
<Definition>
<Body><![CDATA[<p>Properties may contain user-defined data, where data types are open-ended.</p>]]></Body>
</Definition>
</Definitions>
<Rules>
<AttributeRule RuleID="PropertyName" AttributeName="Name">
<EntityRules>
<EntityRule EntityName="IfcIdentifier" />
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="Description">
<EntityRules>
<EntityRule EntityName="IfcText" />
</EntityRules>
</AttributeRule>
</Rules>
<SubTemplates>
<ConceptTemplate uuid="6655f6d0-29a8-47b8-8f3d-c9fce9c9a620" name="Single Value" status="sample" owner="System" applicableSchema="IFC4" applicableEntity="IfcPropertySingleValue">
<Rules>
<AttributeRule RuleID="PropertyName" AttributeName="Name">
<EntityRules>
<EntityRule EntityName="IfcIdentifier" />
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="Description">
<EntityRules>
<EntityRule EntityName="IfcText" />
</EntityRules>
</AttributeRule>
<AttributeRule RuleID="Value" AttributeName="NominalValue">
<EntityRules>
<EntityRule EntityName="IfcValue" />
</EntityRules>
</AttributeRule>
</Rules>
</ConceptTemplate>
<ConceptTemplate uuid="3d67a2d2-761d-44d9-a09e-b7fbb1fa5632" name="Bounded Value" status="sample" owner="System" applicableSchema="IFC4" applicableEntity="IfcPropertyBoundedValue">
<Rules>
<AttributeRule RuleID="PropertyName" AttributeName="Name">
<EntityRules>
<EntityRule EntityName="IfcIdentifier" />
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="Description">
<EntityRules>
<EntityRule EntityName="IfcText" />
</EntityRules>
</AttributeRule>
<AttributeRule RuleID="UpperValue" AttributeName="UpperBoundValue">
<EntityRules>
<EntityRule EntityName="IfcValue" />
</EntityRules>
</AttributeRule>
<AttributeRule RuleID="LowerValue" AttributeName="LowerBoundValue">
<EntityRules>
<EntityRule EntityName="IfcValue" />
</EntityRules>
</AttributeRule>
<AttributeRule RuleID="SetValue" AttributeName="SetPointValue">
<EntityRules>
<EntityRule EntityName="IfcValue" />
</EntityRules>
</AttributeRule>
</Rules>
</ConceptTemplate>
<ConceptTemplate uuid="c148a099-c351-43a8-9266-5f3de0b45a95" name="Enumerated Value" status="sample" owner="System" applicableSchema="IFC4" applicableEntity="IfcPropertyEnumeratedValue">
<Rules>
<AttributeRule RuleID="PropertyName" AttributeName="Name">
<EntityRules>
<EntityRule EntityName="IfcIdentifier" />
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="Description">
<EntityRules>
<EntityRule EntityName="IfcText" />
</EntityRules>
</AttributeRule>
<AttributeRule RuleID="Value" AttributeName="EnumerationValues">
<EntityRules>
<EntityRule EntityName="IfcValue" />
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="EnumerationReference">
<EntityRules>
<EntityRule EntityName="IfcPropertyEnumeration">
<AttributeRules>
<AttributeRule RuleID="Reference" AttributeName="Name">
<EntityRules>
<EntityRule EntityName="IfcLabel" />
</EntityRules>
</AttributeRule>
</AttributeRules>
</EntityRule>
</EntityRules>
</AttributeRule>
</Rules>
</ConceptTemplate>
<ConceptTemplate uuid="8e10b688-9179-4e3a-8db2-6abcaafe952d" name="List Value" status="sample" applicableSchema="IFC4" applicableEntity="IfcPropertyListValue">
<Rules>
<AttributeRule RuleID="PropertyName" AttributeName="Name">
<EntityRules>
<EntityRule EntityName="IfcIdentifier" />
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="Description">
<EntityRules>
<EntityRule EntityName="IfcText" />
</EntityRules>
</AttributeRule>
<AttributeRule RuleID="Value" AttributeName="ListValues">
<EntityRules>
<EntityRule EntityName="IfcValue" />
</EntityRules>
</AttributeRule>
</Rules>
</ConceptTemplate>
<ConceptTemplate uuid="35c947b0-6abc-4b13-8ec7-696ef2041721" name="Table Value" status="sample" applicableSchema="IFC4" applicableEntity="IfcPropertyTableValue">
<Rules>
<AttributeRule RuleID="PropertyName" AttributeName="Name">
<EntityRules>
<EntityRule EntityName="IfcIdentifier" />
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="Description">
<EntityRules>
<EntityRule EntityName="IfcText" />
</EntityRules>
</AttributeRule>
<AttributeRule RuleID="Value" AttributeName="DefiningValues">
<EntityRules>
<EntityRule EntityName="IfcValue" />
</EntityRules>
</AttributeRule>
<AttributeRule RuleID="Reference" AttributeName="DefinedValues">
<EntityRules>
<EntityRule EntityName="IfcValue" />
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="Expression">
<EntityRules>
<EntityRule EntityName="IfcText" />
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="CurveInterpolation">
<EntityRules>
<EntityRule EntityName="IfcCurveInterpolationEnum" />
</EntityRules>
</AttributeRule>
</Rules>
</ConceptTemplate>
</SubTemplates>
</ConceptTemplate>
<ConceptTemplate uuid="6c03e465-c5dd-42ce-9412-bebacabd2f3b" name="Quantities" status="sample" applicableSchema="IFC4" applicableEntity="IfcPhysicalSimpleQuantity">
<Rules>
<AttributeRule RuleID="QuantityName" AttributeName="Name">
<EntityRules>
<EntityRule EntityName="IfcLabel" />
</EntityRules>
</AttributeRule>
</Rules>
<SubTemplates>
<ConceptTemplate uuid="dd8678e1-e300-4f70-9d63-e539db4bd11c" name="Length Quantity" status="sample" applicableSchema="IFC4" applicableEntity="IfcQuantityLength">
<Rules>
<AttributeRule RuleID="QuantityName" AttributeName="Name">
<EntityRules>
<EntityRule EntityName="IfcLabel" />
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="Description">
<EntityRules>
<EntityRule EntityName="IfcText" />
</EntityRules>
</AttributeRule>
<AttributeRule RuleID="LengthValue" AttributeName="LengthValue">
<EntityRules>
<EntityRule EntityName="IfcLengthMeasure" />
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="Formula">
<EntityRules>
<EntityRule EntityName="IfcLabel" />
</EntityRules>
</AttributeRule>
</Rules>
</ConceptTemplate>
<ConceptTemplate uuid="65ac4747-6eff-437e-94e2-643fd4e3bf86" name="Area Quantity" status="sample" applicableSchema="IFC4" applicableEntity="IfcQuantityArea">
<Rules>
<AttributeRule RuleID="QuantityName" AttributeName="Name">
<EntityRules>
<EntityRule EntityName="IfcLabel" />
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="Description">
<EntityRules>
<EntityRule EntityName="IfcText" />
</EntityRules>
</AttributeRule>
<AttributeRule RuleID="AreaValue" AttributeName="AreaValue">
<EntityRules>
<EntityRule EntityName="IfcAreaMeasure" />
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="Formula">
<EntityRules>
<EntityRule EntityName="IfcLabel" />
</EntityRules>
</AttributeRule>
</Rules>
</ConceptTemplate>
<ConceptTemplate uuid="6491a3b0-b7e9-412a-8226-bcd91c2b0b0e" name="Volume Quantity" status="sample" applicableSchema="IFC4" applicableEntity="IfcQuantityVolume">
<Rules>
<AttributeRule RuleID="QuantityName" AttributeName="Name">
<EntityRules>
<EntityRule EntityName="IfcLabel" />
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="Description">
<EntityRules>
<EntityRule EntityName="IfcText" />
</EntityRules>
</AttributeRule>
<AttributeRule RuleID="VolumeValue" AttributeName="VolumeValue">
<EntityRules>
<EntityRule EntityName="IfcVolumeMeasure" />
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="Formula">
<EntityRules>
<EntityRule EntityName="IfcLabel" />
</EntityRules>
</AttributeRule>
</Rules>
</ConceptTemplate>
<ConceptTemplate uuid="e1016e56-3c89-4f42-9679-07e1db3c0afb" name="Weight Quantity" status="sample" applicableSchema="IFC4" applicableEntity="IfcQuantityWeight">
<Rules>
<AttributeRule RuleID="QuantityName" AttributeName="Name">
<EntityRules>
<EntityRule EntityName="IfcLabel" />
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="Description">
<EntityRules>
<EntityRule EntityName="IfcText" />
</EntityRules>
</AttributeRule>
<AttributeRule RuleID="WeightValue" AttributeName="WeightValue">
<EntityRules>
<EntityRule EntityName="IfcMassMeasure" />
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="Formula">
<EntityRules>
<EntityRule EntityName="IfcLabel" />
</EntityRules>
</AttributeRule>
</Rules>
</ConceptTemplate>
<ConceptTemplate uuid="8aaeff32-572c-4f6a-ac64-e2151663cbf1" name="Count Quantity" status="sample" applicableSchema="IFC4" applicableEntity="IfcQuantityCount">
<Rules>
<AttributeRule RuleID="QuantityName" AttributeName="Name">
<EntityRules>
<EntityRule EntityName="IfcLabel" />
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="Description">
<EntityRules>
<EntityRule EntityName="IfcText" />
</EntityRules>
</AttributeRule>
<AttributeRule RuleID="CountValue" AttributeName="CountValue">
<EntityRules>
<EntityRule EntityName="IfcCountMeasure" />
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="Formula">
<EntityRules>
<EntityRule EntityName="IfcLabel" />
</EntityRules>
</AttributeRule>
</Rules>
</ConceptTemplate>
<ConceptTemplate uuid="43c4c050-04de-4b0f-9e43-708bd98201a8" name="Time Quantity" status="sample" applicableSchema="IFC4" applicableEntity="IfcQuantityTime">
<Rules>
<AttributeRule RuleID="QuantityName" AttributeName="Name">
<EntityRules>
<EntityRule EntityName="IfcLabel" />
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="Description">
<EntityRules>
<EntityRule EntityName="IfcText" />
</EntityRules>
</AttributeRule>
<AttributeRule RuleID="TimeValue" AttributeName="TimeValue">
<EntityRules>
<EntityRule EntityName="IfcTimeMeasure" />
</EntityRules>
</AttributeRule>
<AttributeRule AttributeName="Formula">
<EntityRules>
<EntityRule EntityName="IfcLabel" />
</EntityRules>
</AttributeRule>
</Rules>
</ConceptTemplate>
</SubTemplates>
</ConceptTemplate>
</SubTemplates>
</ConceptTemplate>
<ConceptTemplate uuid="00000000-0000-0000-0000-000000000000" name="_xset" code="eead5b95-7b55-4d1c-8b71-dac234adfe38" status="sample" applicableSchema="IFC4">
<SubTemplates>
<ConceptTemplate uuid="be6755a6-b9b6-4884-b820-ea6a73a7402f" status="sample" applicableSchema="IFC4" applicableEntity="IfcObject" />
</SubTemplates>
</ConceptTemplate>
</Templates>
<Views>
<ModelView uuid="eead5b95-7b55-4d1c-8b71-dac234adfe38" name="xset" status="sample" applicableSchema="IFC4">
<ExchangeRequirements />
<Roots>
<ConceptRoot uuid="8ad3fd6c-547b-47d7-8a8b-e68d92da2566" name="IfcObject" status="sample" applicableRootEntity="IfcObject">
<Applicability uuid="00000000-0000-0000-0000-000000000000" status="sample">
<Template ref="be6755a6-b9b6-4884-b820-ea6a73a7402f" />
<TemplateRules operator="and" />
</Applicability>
<Concepts>
<Concept uuid="50ea6466-6555-424f-9179-ee5f7c0dbf62" name="qset" status="sample" override="false">
<Template ref="6652398e-6579-4460-8cb4-26295acfacc7" />
</Concept>
<Concept uuid="9e3151ca-7c3c-4c1b-b155-e13d30d86b2d" name="pset" status="sample" override="false">
<Template ref="f74255a6-0c0e-4f31-84ad-24981db62461" />
</Concept>
</Concepts>
</ConceptRoot>
</Roots>
</ModelView>
</Views>
</mvdXML>
@@ -0,0 +1,29 @@
import pyparsing as pp
class node(object):
def __init__(self, args):
if len(args) == 3 and args[1] == '=':
self.a, self.b, self.c = args[0], None, args[2]
elif (args[1], args[3], args[4]) == ('[', ']', '='):
self.a, self.b, self.c = args[0], args[2], args[5]
else:
self.a, self.b, self.c = None, args[1], args[4]
def __repr__(self): return "{%s[%s]=%s}" % (self.a, self.b, self.c)
word = pp.Word(pp.alphanums+"_"+" "+"/"+"#")
quoted = pp.Combine("'" + word + "'")
bool_value = pp.CaselessLiteral("TRUE") | pp.CaselessLiteral("FALSE")
ref_val = word + "[" + word + "]"
rhs = quoted | bool_value | ref_val | word
stmt = (pp.Optional(word) + pp.Optional("[" + word + "]") + "=" + rhs).setParseAction(node)
bool_op = pp.CaselessLiteral("AND") | pp.CaselessLiteral("OR")
grammar = stmt + pp.Optional(pp.OneOrMore(bool_op + stmt))
def parse(exprs):
def _():
for expr in exprs.split(";"):
expr = "".join(c for c in expr if c not in "\r\n")
if not expr: continue
yield grammar.parseString(expr)
return list(_())
@@ -0,0 +1,609 @@
import io
import os
import csv
import platform
import tabulate
import operator
import itertools
import subprocess
import ifcopenshell
from collections import defaultdict
import mvdxml_expression
def camel(s):
"""
Camel case conversion function
:param s: str
:return: camel case formatted string
"""
s = s.title().replace(" ", "")
if s.endswith("s"): s = s[:-1]
return s[0].lower() + s[1:]
STANDARD_PREFIXES = {
'rdf': '<http://www.w3.org/1999/02/22-rdf-syntax-ns#>',
'owl': '<http://www.w3.org/2002/07/owl#>',
'xsd': '<http://www.w3.org/2001/XMLSchema#>',
'list': '<https://w3id.org/list#>',
'ifcowl': '',
'express': '<https://w3id.org/express#>',
}
def derive_prefix(ttlfn):
with open(ttlfn, "r") as f:
for ln in f:
ln.strip()
if ln.startswith("@prefix ifcowl"):
uri = ln.split(':', 1)[1].strip()[:-1].strip()
print("Detected ifcowl prefix", uri)
STANDARD_PREFIXES['ifcowl'] = uri
break
def withschema(fn):
"""
Decorator that takes a function and adds an IFC latebound schema definition
in the first parameter. The schema identifier is looked up based on the
global ifcOwl prefix.
:param fn: input function
:return: decorated function
"""
def _(*args, **kwargs):
schema_name = STANDARD_PREFIXES['ifcowl'].split('/')[-1][:-2]
if "_" in schema_name:
schema_name = schema_name.split('_')[0]
S = ifcopenshell.ifcopenshell_wrapper.schema_by_name(schema_name)
return fn(S, *args, **kwargs)
return _
noop = lambda *args: None
class rule_binding(object):
"""
Object for mapping rules to generated SPARQL variables
"""
def __init__(self):
pass
class builder(object):
"""
A helper class for dealing with SPARQL query statements
"""
def __init__(self):
self.prefixes = {"express": "", "ifcowl": ""}
self.statements = []
def append(self, *stmt):
if len(stmt) == 3:
for i, pos in enumerate(stmt[1:]):
for po in pos.split("/"):
if ":" in pos:
a, b = po.split(':')
self.prefixes[a] = ''
self.statements.append(stmt)
def bind(self, di):
for k in set(self.prefixes.keys()) & set(di.keys()):
self.prefixes[k] = di[k]
def x(self):
return len(self.statements)
def __repr__(self):
def f(s):
S = " ".join(s)
if len(s) == 3: S += ' .'
return S
def g(s):
return "PREFIX %s: %s" % s
return "\n".join(itertools.chain(
(g(s) for s in self.prefixes.items()),
(f(s) for s in self.statements)
))
class ifcOwl(object):
"""
Helper class with static function for dealing with ifcOwl attribute names
"""
@staticmethod
@withschema
def supertypes(S, entity):
"""
Yields ifcOwl subtypes for the supplied entity name
:param S: schema definition (from decorator)
:param entity: entity name string
:return:
"""
a, b = entity.split('#')
try:
en = S.declaration_by_name(b)
if en.__class__.__name__ == "entity":
while en.supertype():
yield "%s#%s" % (a, en.supertype().name())
en = en.supertype()
except: pass
@staticmethod
def get_names(e, c):
"""
Returns inverse or forward attribute names for latebound entity definition
:param e: latebound entity definition
:param c: either 'all_attributes' or 'all_inverse_attributes'
:return: set of attribute names
"""
return set(map(lambda a: a.name(), getattr(e, c)()))
@staticmethod
@withschema
def is_boxed(S, entity, attribute, predCount=0):
"""
Returns whether the entity attribute should be boxed in ifcOwl. Which means
that there is an additional indirection.
inst:IfcRelDefinesByType_21937
ifcowl:globalId_IfcRoot inst:IfcGloballyUniqueId_117684 ;
inst:IfcGloballyUniqueId_117684
rdf:type ifcowl:IfcGloballyUniqueId ;
express:hasString "2P9FPkykn0r8rCpmBxZH0w" .
:param S: schema definition (from decorator)
:param entity: entity name string
:param attribute: attribute name string
:param predCount: numeric identifier to postfix predicate identifier in case of SELECT types
:return: either a predicate from the express namespace or a variable postfixed with predCount
"""
en = S.declaration_by_name(entity)
attr = [a for a in en.all_attributes() if a.name() == attribute][0]
ty = attr.type_of_attribute()
is_boxed = False
while isinstance(ty, ifcopenshell.ifcopenshell_wrapper.named_type):
ty = ty.declared_type()
if isinstance(ty, ifcopenshell.ifcopenshell_wrapper.select_type):
# Just assume there is going to be some boxed type in here.
# It could be all instance references, but fact is we don't know at this moment.
# It's likely that mvdXML will only bind to literals?
return "?pred%d" % predCount
else:
while isinstance(ty, ifcopenshell.ifcopenshell_wrapper.type_declaration):
is_boxed = True
ty = ty.declared_type()
if is_boxed and isinstance(ty, ifcopenshell.ifcopenshell_wrapper.simple_type):
ty = ty.declared_type()
return "express:has%s%s" % (ty[0].upper(), ty[1:])
return False
@staticmethod
@withschema
def name(S, entity, attribute):
"""
Names the entity attribute according to ifcOwl
:param S:
:param entity:
:param attribute:
:return:
"""
en = S.declaration_by_name(entity)
while True:
st = en.supertype()
attribute_names = ifcOwl.get_names(en, "all_attributes") | \
ifcOwl.get_names(en, "all_inverse_attributes")
if st:
attribute_names -= ifcOwl.get_names(st, "all_attributes") | \
ifcOwl.get_names(st, "all_inverse_attributes")
if attribute in attribute_names:
return "ifcowl:" + attribute[0].lower() + attribute[1:] + "_" + en.name()
en = st
if en is None:
raise AttributeError("%s not found on %s" % (attribute, entity))
@staticmethod
@withschema
def is_select(S, decl_name):
"""
Returns True when the declaration is a select type
:param S:
:param decl_name:
:return:
"""
decl = S.declaration_by_name(decl_name)
return isinstance(decl, ifcopenshell.ifcopenshell_wrapper.select_type)
@staticmethod
@withschema
def is_inverse(S, entity, attribute):
"""
When entity attribute is an INVERSE attribute, returns the opposite
forward entity and attribute name. Otherwise returns (False, False)
:param S:
:param entity:
:param attribute:
:return:
"""
en = S.declaration_by_name(entity)
attrs = [a for a in en.all_inverse_attributes() if a.name() == attribute]
if not attrs: return False, False
a = attrs[0]
assert a.type_of_aggregation_string() == "set"
entity = a.entity_reference().name()
attr = a.attribute_reference().name()
return "ifcowl:" + entity, ifcOwl.name(entity, attr)
class convertor(object):
@staticmethod
def convert(item, *args, **kwargs):
return getattr(convertor, item.__class__.__name__)(item, *args, **kwargs)
@staticmethod
def concept_or_applicability(concept):
"""
Convert the Template (SELECT ... WHERE {}) structure and TemplateRule (FILTER)
:param qtype: 0 or 1, 0 for a general query matching the applicableRootEntity
:return:
"""
bld = builder()
t = concept.template()
bld.append("# %s" % camel(concept.root.name))
convertor.template(t, bld, concept.root.entity)
bld.bind(STANDARD_PREFIXES)
return bld
@staticmethod
def root(rootEntity):
args = ["URI", "GlobalId"]
b = builder()
b.args = args
b.append("SELECT " + " ".join("?" + a for a in args) + " WHERE {")
b.append("?URI", "rdf:type", "ifcowl:%s" % rootEntity)
b.append("?URI", "ifcowl:globalId_IfcRoot/express:hasString", "?GlobalId")
b.append("}")
b.bind(STANDARD_PREFIXES)
return b
@staticmethod
def template(template, bld = None, rootEntity = None):
if bld is None:
bld = builder()
if rootEntity is None:
rootEntity = template.entity
args = ["URI", "GlobalId"]
def enumerate(rule, **kwargs):
if rule.bind:
args.append(rule.bind)
template.traverse(enumerate)
bld.args = args
bld.append("SELECT " + " ".join("?" + a for a in args) + " WHERE {")
args = set(args)
bld.append("?URI", "rdf:type", "ifcowl:%s" % rootEntity)
bld.append("?URI", "ifcowl:globalId_IfcRoot/express:hasString", "?GlobalId")
nm = "?URI"
ROOT = type('_', (), {'attribute': rootEntity})()
# rule_stack = [ROOT]
# name_stack = [nm]
# callback_stack = [noop]
# G = type('_', (object,), dict(indent = 0, nm = nm, next_nm=None, first=True))
rule_mapping = defaultdict(rule_binding)
rule_mapping[ROOT].name = nm
def build(rule, parents):
# print "AAA", rule.tag, parent.tag if parent else parent
# print map(id, rule_stack)
# print name_stack
INDENT = " " * (len(parents) * 2)
return_value = None
if rule.optional:
bld.append(INDENT + "OPTIONAL {")
return_value = lambda: bld.append(INDENT + "}")
if rule.tag == "EntityRule":
# G.nm = G.next_nm
if not ifcOwl.is_select(rule.attribute):
# SELECT types should never be qualified as they cannot be inferred
bld.append(INDENT + rule_mapping[parents[-1]].name, "rdf:type", "ifcowl:" + rule.attribute)
# propagate binding name
rule_mapping[rule].name = rule_mapping[parents[-1]].name
else:
# if rule_stack[-1] is parent:
# # print "sl", id(parent), id(rule)
# # same level
# pass
# elif parent in rule_stack:
# # print "up", id(parent), id(rule)
# while rule_stack[-1] is not parent:
# # rule_stack.pop()
# name_stack.pop()
# callback_stack.pop()()
# else:
# # print "dn", id(parent), id(rule)
# pass
indirect = False
if rule.bind:
if len(rule.nodes) == 1:
indirect = ifcOwl.is_boxed(parents[-1].attribute, rule.attribute, predCount=bld.x())
if rule.bind and not indirect:
next_nm = "?" + rule.bind
else:
next_nm = "?var%d" % bld.x()
rule_mapping[rule].name = next_nm
inventy, invattr = ifcOwl.is_inverse(parents[-1].attribute, rule.attribute)
if invattr:
# This seems not to be necessary, because the entity name is also stated in mvdXML
# q.append(
# next_nm,
# "rdf:type",
# inventy
# )
bld.append(
INDENT + next_nm,
invattr,
rule_mapping[parents[-1]].name
)
else:
bld.append(
INDENT + rule_mapping[parents[-1]].name,
ifcOwl.name(parents[-1].attribute, rule.attribute),
next_nm
)
if rule.bind and indirect:
# For boxed literals, only strings atm
bld.append(INDENT + next_nm, indirect, "?" + rule.bind)
# rule_stack.append(rule)
# name_stack.append(next_nm)
# if rule.optional:
# callback_stack.append(lambda: q.append(INDENT+"}"))
# else:
# callback_stack.append(noop)
# print(q.statements[-1])
return return_value
template.traverse(build, root=ROOT, with_parents=True)
# while callback_stack:
# callback_stack.pop()()
if template.params:
bld.append(convertor.build_filter(template))
bld.append("}")
return bld
@staticmethod
def build_filter(self):
def v(p):
if isinstance(p, mvdxml_expression.node):
if p.b == "Value":
if p.c.lower() in {'true', 'false'}:
yield "(%s?%s)" % ("!" if p.c.lower() == "false" else "", p.a)
else:
yield "(?%s = %s)" % (p.a, p.c)
elif p.b == "Exists":
yield "(!isBLANK(?%s))" % p.a
else:
raise Exception("Unsupported " + p.b)
elif isinstance(p, str):
yield {
"and": "&&",
"or": "||",
"not": "&& !"
}[p.lower()]
else:
yield "("
for q in p:
yield from v(q)
yield ")"
return "FILTER(%s)" % " ".join(v(self.params))
def infer_subtypes(ttlfn):
# Disabled currently
return ttlfn
if not os.path.exists(ttlfn + ".subclass.nt"):
print("Inferring supertype relationships")
import hashlib
import rdflib
a = rdflib.namespace.RDF.type
# Hardly possible on Windows
# graph = rdflib.Graph("Sleepycat")
# graph.open("store", create=True)
# graph.parse(ttlfn)
from sqlalchemy import create_engine
from rdflib_sqlalchemy.store import SQLAlchemy
if os.path.exists("db.sqlite"):
os.unlink("db.sqlite")
uri = rdflib.Literal("sqlite:///%(here)s/db.sqlite" % {"here": os.getcwd()})
ident = rdflib.URIRef(hashlib.sha1(ttlfn.encode()).hexdigest())
engine = create_engine(uri)
store = SQLAlchemy(
identifier=ident,
engine=engine,
)
graph = rdflib.Graph(
store,
identifier=ident,
)
graph.open(uri, create=True)
graph.parse(ttlfn, format="ttl")
# print out all the triples in the graph
def _():
for subject, predicate, object in graph:
if predicate == a:
for sup in ifcOwl.supertypes(object):
yield subject, a, rdflib.URIRef(sup)
for stmt in list(_()):
graph.add(stmt)
graph.serialize(destination=ttlfn + ".subclass.nt", format="nt")
ttlfn += ".subclass.nt"
if platform.system() == "Windows":
JENA_SPARQL = os.path.join(os.environ.get("JENA_HOME"), "bat", "sparql.bat")
else:
JENA_SPARQL = "sparql"
class executor(object):
@staticmethod
def run(CR, fn, ttlfn):
"""
Generates SPARQL queries for the parsed MVD and executes on the building model
:param CR: A parsed concept root
:param fn: A filename used as the prefix to store generate SPARQL queries to disk
:param ttlfn: A filename for the LD representation of an IFC model
:return:
"""
def dict_to_list(headers):
return lambda di: [di[h] for h in headers]
def execute(query, *args):
sparqlfn = ".".join(itertools.chain([fn], map(str, args))) + ".sparql"
with open(sparqlfn, "w") as f:
print(query, file=f)
proc = subprocess.Popen(
[JENA_SPARQL, "--data=" + ttlfn, "--query=" + sparqlfn, "--results=CSV"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout, stderr = proc.communicate()
csvf = io.StringIO(stdout.decode('utf-8'))
return list(csv.DictReader(csvf))
root_query = convertor.root(CR.entity)
roots = execute(root_query, 0)
print("\nFile contains %d elements of type %s" % (len(roots), CR.entity))
passing_all = {}
# for summary below
num_columns = 0
try:
# Full MVD with multiple concepts
is_template = False
concept_enumerator = list(itertools.chain([CR.applicability()], CR.concepts()))
except:
is_template = True
concept_enumerator = [CR]
for ci, C in enumerate(concept_enumerator):
num_columns += 1
if is_template or ci > 1:
print("\n%s" % C.name)
else:
print("\nApplicability")
query = convertor.convert(C)
print("\nSPARQL query")
print("============")
print(query)
passing = execute(query, ci, 1)
passing_guids = set(r['GlobalId'] for r in passing)
print("\nElements passing")
print(tabulate.tabulate(list(map(dict_to_list(query.args), passing)), query.args, tablefmt="grid"))
print("\nElements failing concept")
hd = ["URI", "GlobalId"]
print(tabulate.tabulate(
list(map(dict_to_list(hd), [r for r in roots if r["GlobalId"] not in passing_guids])), hd,
tablefmt="grid"))
passing_all[ci] = passing_guids
print("\nSummary")
for ci, C in enumerate(concept_enumerator):
print("(%d) %s" % (ci+(0 if is_template else 0), C.name))
def get_stats(guid):
v = lambda i: guid in passing_all[i]
st = [guid] + ["x" if v(i) else "" for i in range(num_columns)]
if not is_template:
st += ["x" if not v(0) or all(v(i) for i in range(1, num_columns)) else " "]
return st
hd = ["GlobalId"] + list(map(str, range(num_columns)))
if not is_template:
hd += ["Valid"]
print(tabulate.tabulate(list(map(get_stats, map(operator.itemgetter("GlobalId"), roots))), hd, tablefmt="grid"))