mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
Merge branch 'v0.7.0' of https://github.com/c4rlosdias/IfcOpenShell into v0.7.0
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
ISO-10303-21;
|
||||
HEADER;
|
||||
FILE_DESCRIPTION(('ViewDefinition [CoordinationView]'),'2;1');
|
||||
FILE_NAME('','2023-09-28T23:00:50',(),(),'IfcOpenShell v0.7.0-fbd8ea1ed','IfcOpenShell v0.7.0-fbd8ea1ed','');
|
||||
FILE_SCHEMA(('IFC4'));
|
||||
ENDSEC;
|
||||
DATA;
|
||||
#1=IFCPROPERTYSETTEMPLATE('1TLQmgUKf0I8Zi07bm9Jqn',$,'ePSet_ProjectedCRS','',.PSET_OCCURRENCEDRIVEN.,'IfcProject',(#2,#3,#4,#5,#6,#7));
|
||||
#2=IFCSIMPLEPROPERTYTEMPLATE('2cH53PtVT3v88uf_uGFblG',$,'Name','',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
|
||||
#3=IFCSIMPLEPROPERTYTEMPLATE('3JsReA6vXDqR7aNC$haRYW',$,'Description','',.P_SINGLEVALUE.,'IfcText',$,$,$,$,$,.READWRITE.);
|
||||
#4=IFCSIMPLEPROPERTYTEMPLATE('0u0uEsT5HFtuX5GvozO9ba',$,'GeodeticDatum','',.P_SINGLEVALUE.,'IfcIdentifier',$,$,$,$,$,.READWRITE.);
|
||||
#5=IFCSIMPLEPROPERTYTEMPLATE('1JgEX9Fsf0$ggxYltdkqiY',$,'VerticalDatum','',.P_SINGLEVALUE.,'IfcIdentifier',$,$,$,$,$,.READWRITE.);
|
||||
#6=IFCSIMPLEPROPERTYTEMPLATE('3ahTZjYrD0MAOo5IH6QuGH',$,'MapProjection','',.P_SINGLEVALUE.,'IfcIdentifier',$,$,$,$,$,.READWRITE.);
|
||||
#7=IFCSIMPLEPROPERTYTEMPLATE('3hqJR2ghD0GAti7q4sXKj7',$,'MapZone','',.P_SINGLEVALUE.,'IfcIdentifier',$,$,$,$,$,.READWRITE.);
|
||||
#8=IFCPROPERTYSETTEMPLATE('1jGHTycOj0vA8xHfRl4TNs',$,'ePSet_MapConversion','',.PSET_OCCURRENCEDRIVEN.,'IfcProject',(#9,#10,#11,#12,#13,#15));
|
||||
#9=IFCSIMPLEPROPERTYTEMPLATE('0nxsULXo17JRrAvNteYtNR',$,'Eastings','',.P_SINGLEVALUE.,'IfcLengthMeasure',$,$,$,$,$,.READWRITE.);
|
||||
#10=IFCSIMPLEPROPERTYTEMPLATE('26RfaGJs5CqemN0Xin12XL',$,'Northings','',.P_SINGLEVALUE.,'IfcLengthMeasure',$,$,$,$,$,.READWRITE.);
|
||||
#11=IFCSIMPLEPROPERTYTEMPLATE('0ziCn3nZv3m850VEUwWH42',$,'OrthogonalHeight','',.P_SINGLEVALUE.,'IfcLengthMeasure',$,$,$,$,$,.READWRITE.);
|
||||
#12=IFCSIMPLEPROPERTYTEMPLATE('3d4BOt4In8WR119ms1SaAe',$,'XAxisAbscissa','',.P_SINGLEVALUE.,'IfcReal',$,$,$,$,$,.READWRITE.);
|
||||
#13=IFCSIMPLEPROPERTYTEMPLATE('1Q4Voqj2j84RQRI8l67m28',$,'XAxisOrdinate','',.P_SINGLEVALUE.,'IfcReal',$,$,$,$,$,.READWRITE.);
|
||||
#15=IFCSIMPLEPROPERTYTEMPLATE('0O1Hc0$XnDNOG_jPBmbW5r',$,'Scale','',.P_SINGLEVALUE.,'IfcReal',$,$,$,$,$,.READWRITE.);
|
||||
ENDSEC;
|
||||
END-ISO-10303-21;
|
||||
@@ -748,7 +748,6 @@ class EditOpenings(Operator, tool.Ifc.Operator):
|
||||
building_objs = set()
|
||||
model = tool.Ifc.get()
|
||||
all_openings = model.by_type("IfcOpeningElement")
|
||||
similar_openings = []
|
||||
|
||||
for obj in context.selected_objects:
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
@@ -756,9 +755,7 @@ class EditOpenings(Operator, tool.Ifc.Operator):
|
||||
continue
|
||||
openings = [r.RelatedOpeningElement for r in element.HasOpenings]
|
||||
for opening in openings:
|
||||
for all_opening in all_openings:
|
||||
if all_opening.ObjectPlacement == opening.ObjectPlacement:
|
||||
similar_openings.append(all_opening)
|
||||
similar_openings = [o for o in all_openings if o.ObjectPlacement == opening.ObjectPlacement]
|
||||
opening_obj = tool.Ifc.get_object(opening)
|
||||
if opening_obj:
|
||||
if tool.Ifc.is_edited(opening_obj):
|
||||
|
||||
@@ -81,8 +81,9 @@ def update_simple_openings(element, opening_width, opening_height):
|
||||
has_replaced_opening_representation = True
|
||||
|
||||
tool.Model.reload_body_representation(voided_objs)
|
||||
with bpy.context.temp_override(selected_objects=[tool.Ifc.get_object(f) for f in fillings]):
|
||||
bpy.ops.bim.recalculate_fill()
|
||||
if fillings:
|
||||
with bpy.context.temp_override(selected_objects=[tool.Ifc.get_object(f) for f in fillings]):
|
||||
bpy.ops.bim.recalculate_fill()
|
||||
|
||||
|
||||
def update_window_modifier_representation(context, obj):
|
||||
|
||||
@@ -37,6 +37,7 @@ classes = (
|
||||
operator.LoadProjectElements,
|
||||
operator.NewProject,
|
||||
operator.RefreshLibrary,
|
||||
operator.RevertProject,
|
||||
operator.RewindLibrary,
|
||||
operator.SaveLibraryFile,
|
||||
operator.SelectLibraryFile,
|
||||
|
||||
@@ -676,6 +676,24 @@ class UnloadProject(bpy.types.Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class RevertProject(bpy.types.Operator, IFCFileSelector):
|
||||
bl_idname = "bim.revert_project"
|
||||
bl_label = "Revert IFC Project"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Reload currently opened IFC project discarding all unsaved changes"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not context.scene.BIMProperties.ifc_file:
|
||||
cls.poll_message_set("IFC project need to be loaded and saved on the disk.")
|
||||
return False
|
||||
return True
|
||||
|
||||
def execute(self, context):
|
||||
bpy.ops.bim.load_project(should_start_fresh_session=True, filepath=context.scene.BIMProperties.ifc_file)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class LoadProjectElements(bpy.types.Operator):
|
||||
bl_idname = "bim.load_project_elements"
|
||||
bl_label = "Load Project Elements"
|
||||
|
||||
@@ -73,6 +73,8 @@ def file_menu(self, context):
|
||||
op = self.layout.operator("export_ifc.bim", text="Save IFC Project As...")
|
||||
op.should_save_as = True
|
||||
self.layout.separator()
|
||||
self.layout.operator("bim.revert_project")
|
||||
self.layout.separator()
|
||||
|
||||
|
||||
class BIM_PT_project(Panel):
|
||||
|
||||
@@ -147,14 +147,12 @@ class RemoveOpening(bpy.types.Operator, tool.Ifc.Operator):
|
||||
for building_element in decomposed_building_elements:
|
||||
building_obj = tool.Ifc.get_object(building_element)
|
||||
if building_obj and building_obj.data:
|
||||
body = ifcopenshell.util.representation.get_representation(
|
||||
building_element, "Model", "Body", "MODEL_VIEW"
|
||||
)
|
||||
representation = tool.Geometry.get_active_representation(building_obj)
|
||||
blenderbim.core.geometry.switch_representation(
|
||||
tool.Ifc,
|
||||
tool.Geometry,
|
||||
obj=building_obj,
|
||||
representation=body,
|
||||
representation=representation,
|
||||
should_reload=True,
|
||||
is_global=True,
|
||||
should_sync_changes_first=False,
|
||||
|
||||
@@ -212,7 +212,7 @@ class FileAssociate(bpy.types.Operator):
|
||||
self.layout.label(text="On the next step to create file association ")
|
||||
self.layout.label(text="the system console will be opened ")
|
||||
self.layout.label(text=f"and you will be asked to type command")
|
||||
self.layout.label(text=f'"{command}"')
|
||||
self.layout.label(text=f"{command}")
|
||||
self.layout.label(text="to create an association.")
|
||||
|
||||
def invoke(self, context, event):
|
||||
@@ -241,7 +241,7 @@ class FileAssociate(bpy.types.Operator):
|
||||
|
||||
ps_script_path = os.path.join(src_dir, "windows_bbim_association.ps1")
|
||||
# NOTE: call powershell with RunAs to get admin rights from user
|
||||
subprocess.run(["powershell", "-file", ps_script_path, binary_path], shell=True)
|
||||
subprocess.run(["powershell", "-ExecutionPolicy", "Bypass", "-File", ps_script_path, binary_path], shell=True)
|
||||
|
||||
def install_desktop_linux(self, src_dir=None, destdir="/tmp", binary_path="/usr/bin/blender"):
|
||||
"""Creates linux file assocations and launcher icon"""
|
||||
|
||||
@@ -125,7 +125,9 @@ def select_decomposed_elements(spatial):
|
||||
#HERE STARTS SPATIAL TOOL
|
||||
|
||||
def generate_spaces_from_walls(ifc, spatial, collector):
|
||||
container, active_obj = spatial.get_container_and_active_obj()
|
||||
active_obj = bpy.context.active_object
|
||||
element = ifc.get_entity(active_obj)
|
||||
container = spatial.get_container(element)
|
||||
|
||||
if not active_obj:
|
||||
self.report({"ERROR"}, "No active object. Please select a wall")
|
||||
@@ -147,12 +149,12 @@ def generate_spaces_from_walls(ifc, spatial, collector):
|
||||
h = active_obj.dimensions.z
|
||||
selected_objects = bpy.context.selected_objects
|
||||
|
||||
union = spatial.get_union_shape_from_selected_objects(selected_objects)
|
||||
union = spatial.get_union_shape_from_selected_objects()
|
||||
|
||||
for i, linear_ring in enumerate(union.interiors):
|
||||
poly = spatial.get_buffered_poly_from_linear_ring(linear_ring)
|
||||
|
||||
bm = spatial.get_bmesh_from_polygon(poly, mat, h)
|
||||
bm = spatial.get_bmesh_from_polygon(poly, h)
|
||||
|
||||
name = "Space" + str(i)
|
||||
mesh = bpy.data.meshes.new(name=name)
|
||||
|
||||
@@ -810,8 +810,7 @@ class Spatial:
|
||||
def set_relative_object_matrix(cls, target_obj, relative_to_obj, matrix): pass
|
||||
def show_scene_objects(cls): pass
|
||||
#HERE STARTS SPATIAL TOOL
|
||||
# def get_container_and_active_obj(cls): pass
|
||||
def get_union_shape_from_selected_objects(cls, selected_objects): pass
|
||||
def get_union_shape_from_selected_objects(cls): pass
|
||||
def get_boundary_elements(cls, selected_objects): pass
|
||||
def get_polygons(cls, boundary_elements): pass
|
||||
def get_obj_base_points(cls, obj): pass
|
||||
|
||||
@@ -416,7 +416,7 @@ class Drawing(blenderbim.core.tool.Drawing):
|
||||
@classmethod
|
||||
def get_drawing_group(cls, drawing):
|
||||
for rel in drawing.HasAssignments or []:
|
||||
if rel.is_a("IfcRelAssignsToGroup"):
|
||||
if rel.is_a("IfcRelAssignsToGroup") and rel.RelatingGroup.ObjectType == "DRAWING":
|
||||
return rel.RelatingGroup
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -20,6 +20,8 @@ import csv
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.unit
|
||||
import ifcopenshell.util.selector
|
||||
import ifcopenshell.util.element
|
||||
import locale
|
||||
|
||||
|
||||
@@ -67,11 +69,21 @@ class Csv2Ifc:
|
||||
identification = row[self.headers["Identification"]] if "Identification" in self.headers else None
|
||||
quantity = row[self.headers["Quantity"]]
|
||||
unit = row[self.headers["Unit"]]
|
||||
if not self.is_schedule_of_rates:
|
||||
assignments = {
|
||||
"PropertyName": row[self.headers["Property"]],
|
||||
"Query": row[self.headers["Query"]],
|
||||
}
|
||||
else:
|
||||
assignments = {
|
||||
"PropertyName": None,
|
||||
"Query": None,
|
||||
}
|
||||
if self.has_categories:
|
||||
cost_values = {
|
||||
k: locale.atof(row[v])
|
||||
for k, v in self.headers.items()
|
||||
if k not in ["Hierarchy", "Identification", "Name", "Quantity", "Unit", "Subtotal"] and row[v]
|
||||
if k not in ["Hierarchy", "Identification", "Name", "Quantity", "Unit", "Subtotal", "Property", "Query"] and row[v]
|
||||
}
|
||||
else:
|
||||
cost_values = row[self.headers["Value"]]
|
||||
@@ -82,6 +94,7 @@ class Csv2Ifc:
|
||||
"Quantity": float(quantity) if quantity else None,
|
||||
"Unit": str(unit) if unit else None,
|
||||
"CostValues": cost_values,
|
||||
"assignments": assignments,
|
||||
"children": [],
|
||||
}
|
||||
|
||||
@@ -107,7 +120,7 @@ class Csv2Ifc:
|
||||
cost_item["ifc"].Name = cost_item["Name"]
|
||||
cost_item["ifc"].Identification = cost_item["Identification"]
|
||||
|
||||
if not cost_item["CostValues"]:
|
||||
if not cost_item["CostValues"] and cost_item["children"]:
|
||||
if not self.is_schedule_of_rates:
|
||||
cost_value = ifcopenshell.api.run("cost.add_cost_value", self.file, parent=cost_item["ifc"])
|
||||
cost_value.Category = "*"
|
||||
@@ -115,7 +128,11 @@ class Csv2Ifc:
|
||||
for category, value in cost_item["CostValues"].items():
|
||||
cost_value = ifcopenshell.api.run("cost.add_cost_value", self.file, parent=cost_item["ifc"])
|
||||
cost_value.AppliedValue = self.file.createIfcMonetaryMeasure(value)
|
||||
cost_value.Category = category
|
||||
if category != "Rate" or category != "Price":
|
||||
if "Rate" in category or"Price" in category:
|
||||
category = category.replace("Rate","")
|
||||
category = category.strip()
|
||||
cost_value.Category = category
|
||||
else:
|
||||
cost_value = ifcopenshell.api.run("cost.add_cost_value", self.file, parent=cost_item["ifc"])
|
||||
cost_value.AppliedValue = self.file.createIfcMonetaryMeasure(cost_item["CostValues"])
|
||||
@@ -144,6 +161,15 @@ class Csv2Ifc:
|
||||
"cost.add_cost_item_quantity", self.file, cost_item=cost_item["ifc"], ifc_class=quantity_class
|
||||
)
|
||||
quantity[3] = cost_item["Quantity"]
|
||||
|
||||
if cost_item["assignments"]["PropertyName"] and cost_item["assignments"]["Query"]:
|
||||
print("for query",cost_item["assignments"]["Query"])
|
||||
results = ifcopenshell.util.selector.filter_elements(self.file, cost_item["assignments"]["Query"])
|
||||
|
||||
results = [r for r in results if has_property(self.file, r, cost_item["assignments"]["PropertyName"])]
|
||||
if results:
|
||||
ifcopenshell.api.run("cost.assign_cost_item_quantity", self.file, cost_item=cost_item["ifc"], products=results, prop_name=cost_item["assignments"]["PropertyName"])
|
||||
|
||||
self.create_cost_items(cost_item["children"], cost_item["ifc"])
|
||||
|
||||
def create_unit(self, symbol):
|
||||
@@ -158,3 +184,11 @@ class Csv2Ifc:
|
||||
|
||||
def create_boilerplate_ifc(self):
|
||||
self.file = ifcopenshell.file(schema="IFC4")
|
||||
|
||||
def has_property(self, product, property_name):
|
||||
qtos = ifcopenshell.util.element.get_psets(product, qtos_only=True)
|
||||
for qset, quantities in qtos.items():
|
||||
for quantity, value in quantities.items():
|
||||
if quantity == property_name:
|
||||
return True
|
||||
return False
|
||||
@@ -0,0 +1,147 @@
|
||||
Hierarchy,Identification,Name,Quantity,Unit,Contract,Rate,Material Rate,Labor Rate,Subtotal,Property,Query
|
||||
1,DB,Design and build,,,,,,,,,
|
||||
2,DB.1,Design,,,,,,,,,
|
||||
3,DB.1.1,Architecte,1,unit,40000,,,,40000,,
|
||||
3,DB.1.2,Bet structure,1,unit,10000,,,,10000,,
|
||||
3,DB.1.3,Bet lots techniques,1,unit,8000,,,,8000,,
|
||||
2,DB.2,Construction,,,,,,,,,
|
||||
3,DB.2.1,Go & etancheite,,,,,,,,,
|
||||
4,DB.2.1.1,Gros oeuvre,,,,,,,,,
|
||||
4,DB.2.1.2,Etancheite,,,,,,,,,
|
||||
5,DB.2.1.2.1,Forme de pente et chape de lissage,,,,97,,,,NetArea,"IfcSlab, location=Roof"
|
||||
5,DB.2.1.2.2,Ecran pare-vapeur et isolation thermique,,,,47,,,,NetArea,"IfcSlab, location=Roof"
|
||||
5,DB.2.1.2.3,Systeme d’etancheite bicouche,,,,23,,,,NetArea,"IfcCovering, type=Etancheite_H"
|
||||
5,DB.2.1.2.4,Reliefs d’etancheite bicouche,,,,7,,,,Length,"IfcWall, type=”BLK150”, location=Roof"
|
||||
5,DB.2.1.2.5,Protection horizontales d’etancheite par carreaux de ciment,,,,,,,,NetArea,"IfcCovering, type=Etancheite_H"
|
||||
5,DB.2.1.2.6,Protection des reliefs d’etancheite,,,,,,,,,
|
||||
5,DB.2.1.2.7,Etancheite legere,,,,,,,,,
|
||||
5,DB.2.1.2.8,Fourniture et pose de gargouilles y compris crapaudines,3,unit,,,,,,,
|
||||
,,,,,,,,,,,
|
||||
4,DB.2.1.3,Gros oeuvre piscine,,,,,,,,,
|
||||
5,DB.2.1.3.1,Fouilles en pleine masse dans tous terrains y compris rocher,,,,,,,,,
|
||||
5,DB.2.1.3.2,Remblaiement ou evacuation aux decharges publiques,,,,,,,,,
|
||||
5,DB.2.1.3.3,Beton de proprete,,,,,,,,,
|
||||
5,DB.2.1.3.4,Beton hydrofuge pour tous les ouvrages en fondation et elevation,,,,,,,,,
|
||||
5,DB.2.1.3.5,Aciers a haute limite elastique fe500 pour les ouvrages en fondation et elevation,,,,,,,,,
|
||||
,,,,,,,,,,,
|
||||
4,DB.2.1.4,Maconnerie et briquetage en elevation,,,,,,,,,
|
||||
5,DB.2.1.5.1,Cloisons en briques creuses 7t,,,,,,,,,
|
||||
5,DB.2.1.5.2,Doubles cloisons en briques creuses 7t+vide10+7t,,,,,,,,,
|
||||
,,,,,,,,,,,
|
||||
,,,,,,,,,,,
|
||||
4,DB.2.1.5,Enduits interieurs et exterieurs,,,,,,,,,
|
||||
5,DB.2.1.5.1,"Enduit interieur au mortier de ciment sur murs et plafonds y
|
||||
Compris baguettes d'angles",,,,,,,,,
|
||||
5,DB.2.1.5.1.1,Enduit interieur au platre,,,,,,,,,
|
||||
5,DB.2.1.5.1.2,"Enduit projete exterieur au mortier de ciment y compris baguettes
|
||||
D'angles",,,,,,,,,
|
||||
5,DB.2.1.5.1.3,Enduit de couronnement d'acroteres y compris facon de larmier,,,,,,,,,
|
||||
,,,,,,,,,,,
|
||||
4,DB.2.1.5,Reseaux sous dallage,,,,,,,,,
|
||||
5,DB.2.1.5.1,Canalisation en buse pvc type assainissement serie i,,,,,,,,,
|
||||
6,DB.2.1.5.1.1,Tranchee ,,,,,,,,,
|
||||
6,DB.2.1.5.1.2,P.v.c diametre de 200 mm,,,,,,,,,
|
||||
,,,,,,,,,,,
|
||||
5,DB.2.1.5.2,Regards en beton arme ,,,,,,,,,
|
||||
6,DB.2.1.5.2.1,Regards visitable de 50x50 cm,,,,,,,,,
|
||||
6,DB.2.1.5.2.2,Regards non visitable de 40x40 cm,,,,,,,,,
|
||||
4,DB.2.1.5,Divers,,,,,,,,,
|
||||
5,DB.2.1.5.1,Gaine technique d’aeration et habillage des descentes des eaux ,,,,,,,,,
|
||||
,,,,,,,,,,,
|
||||
3,DB.2.2,Fluides,,,,,,,,,
|
||||
4,DB.2.2.1,Plomberie,,,,,,,,,
|
||||
4,DB.2.2.2,Climatisation,,,,,,,,,
|
||||
4,DB.2.2.3,Sanitaire,,,,,,,,,
|
||||
3,DB.2.3,Electricite,,,,,,,,,
|
||||
4,DB.2.3.1,Eclairage et appareillage,,,,,,,,,
|
||||
4,DB.2.3.2,Panneaux solaires,,,,,,,,,
|
||||
3,DB.2.4,Architecture interieure,,,,,,,,,
|
||||
4,DB.2.4.1,Menuiserie metallique,,,,,,,,,
|
||||
5,DB.2.4.1.1,G.c 1 en vitrage bord àbord 10*10*2(1unite) rail en alu encastre,,,,,,,,,
|
||||
5,DB.2.4.1.2,G.c 2 en vitrage bord àbord 10*10*2(1unite) rail en alu encastre,,,,,,,,,
|
||||
,,,,,,,,,,,
|
||||
4,DB.2.4.2,Menuiserie bois,,,,,,,,,
|
||||
5,DB.2.4.2.1,Portes,,,,,,,,,
|
||||
6,DB.2.4.2.1.1,P1,,,,,,,,Count,"IfcDoor, type=P1"
|
||||
6,DB.2.4.2.1.2,P2,,,,,,,,Count,"IfcDoor, type=P2-LEFT + IfcDoor, type=P2-RIGHT"
|
||||
6,DB.2.4.2.1.3,P3,,,,,,,,Count,"IfcDoor, type=P3-LEFT + IfcDoor, type=P3-RIGHT"
|
||||
,,,,,,,,,,,
|
||||
5,DB.2.4.2.2,Placards et habillage,,,,,,,,,
|
||||
6,DB.2.4.2.2.1,Fourniture placard type 1,,,,,,,,,
|
||||
6,DB.2.4.2.2.2,Fourniture placard type 2,,,,,,,,,
|
||||
6,DB.2.4.2.2.3,Fourniture placard type 3 ,,,,,,,,,
|
||||
6,DB.2.4.2.2.3,Fourniture placard type 4,,,,,,,,,
|
||||
,,,,,,,,,,,
|
||||
4,DB.2.4.3,Revetement sol parquet,,,,,,,,,
|
||||
5,DB.2.4.3.1,Fourniture parquet contrecolle 18mm dont epaisseur noyer americain 3mm,,,,,300,,,NetArea,"IfcCovering, type=RS-2"
|
||||
5,DB.2.4.3.2,Fournitur basic underlay,,,,,50,,,NetArea,"IfcCovering, type=RS-2"
|
||||
5,DB.2.4.3.3,"Fourniture profilpas finition laiton 2,5mm",,,,,20,,,Width,IfcDoor
|
||||
5,DB.2.4.3.4,"Pose du parquet y compris isolant acoustique, chappe de ciment, sous-couche et barre de seuil",,,,,,74,,NetArea,"IfcCovering, type=RS-2"
|
||||
,,,,,,,,,,,
|
||||
4,DB.2.4.4,Revetement sol marbre,,,,,,,,,
|
||||
5,DB.2.4.4.1,Fourniture marbre sols,,,,,,,,NetArea,"IfcCovering, type=RS-5"
|
||||
5,DB.2.4.4.2,Fourniture marbre- sols sdb,,,,,,,,NetArea,"IfcCovering, type=RS-2"
|
||||
5,DB.2.4.4.3,Fourniture marbre murs sdb ,,,,,,,,,
|
||||
5,DB.2.4.4.4,Fourniture marbre marche escalier y/c nez,,,,,,,,,
|
||||
5,DB.2.4.4.5,Pose marbre sols y compris chappe de ciment,,,,,,,,,
|
||||
5,DB.2.4.4.6,Pose marbre murs,,,,,,,,,
|
||||
5,DB.2.4.4.7,Pose marbre marches,,,,,,,,,
|
||||
,,,,,,,,,,,
|
||||
4,DB.2.4.5,Revetement carreaux,,,,,,,,,
|
||||
5,DB.2.4.5.1,Revetements,,,,,,,,,
|
||||
6,DB.2.4.5.1.1,Revêtement sol: cuisine - carreaux - gres cerame (30*60cm) - choix sous validation d'echantillons par l'architecte et le maitre d'ouvrage,,,,,,,,,
|
||||
6,DB.2.4.5.1.2,Revêtement sol: salle de jeux - carreaux - gres cerame (30*60cm) - choix sous validation d'echantillons par l'architecte et le maitre d'ouvrage,,,,,,,,,
|
||||
6,DB.2.4.5.1.3,Revêtement sol: (reserve) - gres cerame (30*60cm) - choix sous validation d'echantillons par l'architecte et le maitre d'ouvrage - ,,,,,,,,,
|
||||
6,DB.2.4.5.1.4,Revêtement mural cuisine - carreaux - effet vitrage noir,,,,,,,,,
|
||||
5,DB.2.4.5.2,Plinthes,,,,,,,,,
|
||||
6,DB.2.4.5.2.1,Plinthes - duropolymer orac decor ref : sx157,,,,,,,,,
|
||||
6,DB.2.4.5.2.2,Plinthes marches - - duropolymer orac decor ref : sx157,,,,,,,,,
|
||||
,,,,,,,,,,,
|
||||
4,DB.2.4.6,Peinture,,,,,,,,,
|
||||
5,DB.2.4.6.1,Fourniture et pose peinture murs - marmorex astral y/c preparation (5 couches),,,,,,,,,
|
||||
5,DB.2.4.6.2,Fourniture et pose peinture contremarche escalier - marmorex astral y/c preparation (5 couches,,,,,,,,,
|
||||
5,DB.2.4.6.3,Fourniture et pose peinture murs cuisine - alpha tacto astral y/c preparation (5 couches),,,,,,,,,
|
||||
5,DB.2.4.6.4,Foruniture et pose peinture faux-plafond - jotun acrylique mate blanc y/c preparation (5 couches),,,,,,,,,
|
||||
5,DB.2.4.6.5,Fourniture et pose peinture murs sdb - jotun acrylique semi-brillant blanc special piece humide y/c preparation (5 couches),,,,,,,,,
|
||||
5,DB.2.4.6.6,Fourniture et pose peinture faux-plafond sdb + cuisine - jotun acrylique semi-brillant blanc special piece humide y/c preparation (5 couches),,,,,,,,,
|
||||
,,,,,,,,,,,
|
||||
4,DB.2.4.7,Faux plafonds,,,,,,,,,
|
||||
5,DB.2.4.7.1,Type 1,,,,,,,,,
|
||||
5,DB.2.4.7.2,Type 2,,,,,,,,,
|
||||
5,DB.2.4.7.3,Type 3 – hydrofuge – exterieur,,,,,,,,,
|
||||
5,DB.2.4.7.4,Trappes d’acces,,,,,,,,,
|
||||
,,,,,,,,,,,
|
||||
4,DB.2.4.8,Cuisine,1,unit,,,,,,,
|
||||
,,,,,,,,,,,
|
||||
3,DB.2.5,Facade,,,,,,,,,
|
||||
4,DB.2.5.1,Revetement exterieur ,,,,,,,,,
|
||||
5,DB.2.5.1.1,Revetement mural: plus value enduit mural hydrofuge (monocouche),,,,,,,,,
|
||||
5,DB.2.5.1.2,Revetement mural: pierre volcanique grise ,,,,,,,,,
|
||||
5,DB.2.5.1.3,Revetement mural: bardage en bois iroko ou tole alu section carre ou rectangulaire avec habillage bois technowood (voir detail architecte),,,,,,,,,
|
||||
5,DB.2.5.1.4,Revêtement sol: terrasses et cour - tech - choix sous validation d'echantillons par l'architecte et le maitre d'ouvrage ,,,,,,,,,
|
||||
5,DB.2.5.1.5,Revetement sol: seuill entree en pierre de taza,,,,,,,,,
|
||||
5,DB.2.5.1.6,Revetement sol: sous bassement perimetre villa en pierre de taza ,,,,,,,,,
|
||||
,,,,,,,,,,,
|
||||
4,DB.2.5.2,Menuiserie aluminium,,,,,,,,,
|
||||
5,DB.2.5.2.1,Fenetres,,,,,,,,,
|
||||
6,DB.2.5.2.1.1,F1,,,,,,,,,
|
||||
6,DB.2.5.2.1.2,F2,,,,,,,,,
|
||||
,,,,,,,,,,,
|
||||
5,DB.2.5.2.2,Chassis ouvrants,,,,,,,,,
|
||||
6,DB.2.5.2.2.1,Ch1,,,,,,,,,
|
||||
6,DB.2.5.2.2.2,Ch2,,,,,,,,,
|
||||
6,DB.2.5.2.2.3,Ch3,,,,,,,,,
|
||||
,,,,,,,,,,,
|
||||
5,DB.2.5.2.3,Portes coulissantes/ mur rideau,,,,,,,,,
|
||||
6,DB.2.5.2.3.1,P4,,,,,,,,,
|
||||
6,DB.2.5.2.3.2,P5,,,,,,,,,
|
||||
6,DB.2.5.2.3.3,P6,,,,,,,,,
|
||||
,,,,,,,,,,,
|
||||
5,DB.2.5.2.4,Volets roulants,,,,,,,,,
|
||||
6,DB.2.5.2.4.1,Type 1,,,,,,,,,
|
||||
6,DB.2.5.2.4.2,Type 2,,,,,,,,,
|
||||
6,DB.2.5.2.4.3,Type 3,,,,,,,,,
|
||||
3,DB.2.6,Exterieur,,,,,,,,,
|
||||
4,DB.2.6.1,Cloture,,,,,,,,,
|
||||
4,DB.2.6.2,Piscine,,,,,,,,,
|
||||
4,DB.2.6.3,Jardin,,,,,,,,,
|
||||
|
Binary file not shown.
@@ -57,7 +57,7 @@ class Parser:
|
||||
else:
|
||||
self.config = preset
|
||||
|
||||
def parse(self, ifc_file):
|
||||
def parse(self, ifc_file, name=None):
|
||||
for category_name, category_config in self.config["categories"].items():
|
||||
self.categories.setdefault(category_name, {})
|
||||
for element in category_config["get_category_elements"](ifc_file):
|
||||
@@ -81,12 +81,29 @@ class Parser:
|
||||
data.update(custom_data)
|
||||
|
||||
if data:
|
||||
key = data["key"]
|
||||
del data["key"]
|
||||
key = "-".join([str(data[k]) for k in category_config["keys"]])
|
||||
if key in self.categories[category_name]:
|
||||
self.duplicate_keys.append((self.categories[category_name][key], data))
|
||||
self.categories[category_name][key] = data
|
||||
|
||||
def federate(self, paths):
|
||||
for path in paths:
|
||||
spreadsheet = pd.ExcelFile(path)
|
||||
sheet_names = spreadsheet.sheet_names
|
||||
|
||||
for category_name, category_config in self.config["categories"].items():
|
||||
self.categories.setdefault(category_name, {})
|
||||
if category_name not in sheet_names:
|
||||
continue
|
||||
|
||||
self.categories.setdefault(category_name, {})
|
||||
df = pd.read_excel(spreadsheet, sheet_name=category_name, keep_default_na=False)
|
||||
for _, row in df.iterrows():
|
||||
key = "-".join([str(row[k]) for k in category_config["keys"]])
|
||||
if key in self.categories[category_name]:
|
||||
continue
|
||||
self.categories[category_name][key] = row.to_dict()
|
||||
|
||||
def exclude_categories(self, names):
|
||||
for name in names:
|
||||
if name in self.config["categories"]:
|
||||
@@ -148,7 +165,7 @@ class Writer:
|
||||
if isinstance(value, str):
|
||||
convert = lambda text: int(text) if text.isdigit() else text.lower()
|
||||
return [convert(c) for c in re.split("([0-9]+)", value)]
|
||||
return value
|
||||
return [str(value)]
|
||||
|
||||
# Sort least important keys first, then more important keys.
|
||||
# https://stackoverflow.com/questions/11476371/sort-by-multiple-keys-using-different-orderings
|
||||
|
||||
@@ -61,7 +61,6 @@ def get_systems(ifc_file):
|
||||
|
||||
def get_facility_data(ifc_file, element):
|
||||
return {
|
||||
"key": element.Name,
|
||||
"Name": element.Name,
|
||||
"ProjectName": ifc_file.by_type("IfcProject")[0].Name,
|
||||
"SiteName": getattr(get_facility_parent(element, "IfcSite"), "Name", None),
|
||||
@@ -80,7 +79,6 @@ def get_facility_data(ifc_file, element):
|
||||
|
||||
def get_storey_data(ifc_file, element):
|
||||
return {
|
||||
"key": element.Name,
|
||||
"Name": element.Name,
|
||||
"Category": "Level",
|
||||
"AuthorOrganizationName": get_owner_name(element),
|
||||
@@ -95,7 +93,6 @@ def get_storey_data(ifc_file, element):
|
||||
def get_space_data(ifc_file, element):
|
||||
psets = ifcopenshell.util.element.get_psets(element)
|
||||
return {
|
||||
"key": element.Name,
|
||||
"Name": element.Name,
|
||||
"Description": element.LongName,
|
||||
"Category": get_classification(element),
|
||||
@@ -112,7 +109,6 @@ def get_space_data(ifc_file, element):
|
||||
def get_zone_data(ifc_file, element):
|
||||
zone, space = element
|
||||
return {
|
||||
"key": (zone.Name or "Unnamed") + (space.Name or "Unnamed"),
|
||||
"Name": zone.Name,
|
||||
"SpaceName": space.Name,
|
||||
"AuthorOrganizationName": get_owner_name(zone),
|
||||
@@ -125,7 +121,6 @@ def get_zone_data(ifc_file, element):
|
||||
def get_element_type_data(ifc_file, element):
|
||||
psets = ifcopenshell.util.element.get_psets(element)
|
||||
return {
|
||||
"key": element.Name,
|
||||
"Name": element.Name,
|
||||
"Description": element.Description,
|
||||
"Category": get_classification(element),
|
||||
@@ -150,7 +145,6 @@ def get_element_data(ifc_file, element):
|
||||
system = systems[0].Name if systems else None
|
||||
psets = ifcopenshell.util.element.get_psets(element)
|
||||
return {
|
||||
"key": element.Name,
|
||||
"Name": element.Name,
|
||||
"TypeName": ifcopenshell.util.element.get_type(element).Name,
|
||||
"SpaceName": space_name,
|
||||
@@ -173,7 +167,6 @@ def get_element_data(ifc_file, element):
|
||||
|
||||
def get_system_data(ifc_file, element):
|
||||
return {
|
||||
"key": element.Name,
|
||||
"Name": element.Name,
|
||||
"Description": element.Description,
|
||||
"Category": get_classification(element),
|
||||
@@ -241,6 +234,7 @@ config = {
|
||||
},
|
||||
"categories": {
|
||||
"Facilities": {
|
||||
"keys": ["Name"],
|
||||
"headers": [
|
||||
"Name",
|
||||
"ProjectName",
|
||||
@@ -262,6 +256,7 @@ config = {
|
||||
"get_element_data": get_facility_data,
|
||||
},
|
||||
"Storeys": {
|
||||
"keys": ["Name"],
|
||||
"headers": [
|
||||
"Name",
|
||||
"Category",
|
||||
@@ -278,6 +273,7 @@ config = {
|
||||
"get_element_data": get_storey_data,
|
||||
},
|
||||
"Spaces": {
|
||||
"keys": ["Name"],
|
||||
"headers": [
|
||||
"Name",
|
||||
"Description",
|
||||
@@ -296,6 +292,7 @@ config = {
|
||||
"get_element_data": get_space_data,
|
||||
},
|
||||
"Zones": {
|
||||
"keys": ["Name", "SpaceName"],
|
||||
"headers": ["Name", "SpaceName", "AuthorOrganizationName", "AuthorDate", "ModelSoftware", "ModelID"],
|
||||
"colours": "prreee",
|
||||
"sort": [{"name": "Name", "order": "ASC"}],
|
||||
@@ -303,6 +300,7 @@ config = {
|
||||
"get_element_data": get_zone_data,
|
||||
},
|
||||
"ElementTypes": {
|
||||
"keys": ["Name"],
|
||||
"headers": [
|
||||
"Name",
|
||||
"Description",
|
||||
@@ -325,6 +323,7 @@ config = {
|
||||
"get_element_data": get_element_type_data,
|
||||
},
|
||||
"Elements": {
|
||||
"keys": ["Name"],
|
||||
"headers": [
|
||||
"Name",
|
||||
"TypeName",
|
||||
@@ -350,6 +349,7 @@ config = {
|
||||
"get_element_data": get_element_data,
|
||||
},
|
||||
"Systems": {
|
||||
"keys": ["Name"],
|
||||
"headers": [
|
||||
"Name",
|
||||
"Description",
|
||||
|
||||
+68
-68
@@ -35,7 +35,7 @@ import ifcopenshell.util.classification
|
||||
|
||||
|
||||
def get_contacts(ifc_file):
|
||||
return ifc_file.by_type("IfcPersonAndOrganization")
|
||||
return ifc_file.by_type("IfcActor")
|
||||
|
||||
|
||||
def get_facilities(ifc_file):
|
||||
@@ -245,7 +245,6 @@ def get_attributes(ifc_file):
|
||||
allowed_values = get_property_unit(props["id"], name)
|
||||
|
||||
data = {
|
||||
"key": str(val(name)) + str(sheet_name) + str(val(element.Name)),
|
||||
"Name": val(name),
|
||||
"CreatedBy": pset_created_by,
|
||||
"CreatedOn": pset_created_on,
|
||||
@@ -265,51 +264,54 @@ def get_attributes(ifc_file):
|
||||
|
||||
|
||||
def get_contact_data(ifc_file, element):
|
||||
email = get_email_from_pao(element)
|
||||
the_actor = element.Theactor
|
||||
|
||||
history = get_history(ifc_file)
|
||||
if the_actor.is_a("IfcPerson"):
|
||||
pao = None
|
||||
person = the_actor
|
||||
organization = None
|
||||
elif the_actor.is_a("IfcOrganization"):
|
||||
pao = None
|
||||
person = None
|
||||
organization = the_actor
|
||||
elif the_actor.is_a("IfcPersonAndOrganization"):
|
||||
pao = the_actor
|
||||
person = the_actor.ThePerson
|
||||
organization = the_actor.TheOrganization
|
||||
|
||||
roles = []
|
||||
for actor in [element, element.ThePerson, element.TheOrganization]:
|
||||
email = get_email_from_pao(person, organization)
|
||||
|
||||
roles = set()
|
||||
for actor in [pao, person, organization]:
|
||||
if not actor:
|
||||
continue
|
||||
for role in actor.Roles or []:
|
||||
if role.Role == "USERDEFINED":
|
||||
if role.UserDefinedRole:
|
||||
roles.append(role.UserDefinedRole)
|
||||
roles.add(role.UserDefinedRole)
|
||||
else:
|
||||
roles.append(role.Role)
|
||||
|
||||
organization = element.TheOrganization
|
||||
person = element.ThePerson
|
||||
|
||||
department = get_pao_address(element, "InternalLocation")
|
||||
if not department:
|
||||
for rel in organization.Relates:
|
||||
for org in rel.RelatedOrganizations:
|
||||
if val(org.Name):
|
||||
department = org.Name
|
||||
roles.add(role.Role)
|
||||
|
||||
return {
|
||||
"key": email,
|
||||
"Email": email,
|
||||
"CreatedBy": get_email_from_history(history) if history else None,
|
||||
"CreatedOn": ifcopenshell.util.date.ifc2datetime(history.CreationDate).isoformat() if history else None,
|
||||
"CreatedBy": get_created_by(element),
|
||||
"CreatedOn": get_created_on(element),
|
||||
"Category": ",".join(roles),
|
||||
"Company": getattr(organization, "Name", None),
|
||||
"Phone": get_pao_address(element, "TelephoneNumbers"),
|
||||
"ExternalSystem": history.OwningApplication.ApplicationFullName if history else None,
|
||||
"Phone": get_pao_address(person, organisation, "TelephoneNumbers"),
|
||||
"ExternalSystem": get_external_system(element),
|
||||
"ExternalObject": element.is_a(),
|
||||
"ExternalIdentifier": email,
|
||||
"Department": department,
|
||||
"OrganizationCode": getattr(organization, "Id", getattr(organization, "Identification", None))
|
||||
or organization.Name,
|
||||
"ExternalIdentifier": element.GlobalId,
|
||||
"Department": get_pao_address(person, organisation, "InternalLocation"),
|
||||
"OrganizationCode": getattr(organization, "Id", getattr(organization, "Identification", None)),
|
||||
"GivenName": getattr(person, "GivenName", None),
|
||||
"FamilyName": getattr(person, "FamilyName", None),
|
||||
"Street": get_pao_address(element, "AddressLines"),
|
||||
"PostalBox": get_pao_address(element, "PostalBox"),
|
||||
"Town": get_pao_address(element, "Town"),
|
||||
"StateRegion": get_pao_address(element, "Region"),
|
||||
"PostalCode": get_pao_address(element, "PostalCode"),
|
||||
"Country": get_pao_address(element, "Country"),
|
||||
"Street": get_pao_address(person, organisation, "AddressLines"),
|
||||
"PostalBox": get_pao_address(person, organisation, "PostalBox"),
|
||||
"Town": get_pao_address(person, organisation, "Town"),
|
||||
"StateRegion": get_pao_address(person, organisation, "Region"),
|
||||
"PostalCode": get_pao_address(person, organisation, "PostalCode"),
|
||||
"Country": get_pao_address(person, organisation, "Country"),
|
||||
}
|
||||
|
||||
|
||||
@@ -338,7 +340,6 @@ def get_facility_data(ifc_file, element):
|
||||
name = val(site.Name) or val(site.LongName)
|
||||
|
||||
return {
|
||||
"key": name,
|
||||
"Name": name,
|
||||
"CreatedBy": get_created_by(element),
|
||||
"CreatedOn": get_created_on(element),
|
||||
@@ -394,7 +395,6 @@ def get_floor_data(ifc_file, element):
|
||||
elevation = "" if elevation is None else str(elevation)
|
||||
|
||||
return {
|
||||
"key": val(element.Name),
|
||||
"Name": val(element.Name),
|
||||
"CreatedBy": get_created_by(element),
|
||||
"CreatedOn": get_created_on(element),
|
||||
@@ -434,7 +434,6 @@ def get_space_data(ifc_file, element):
|
||||
net_area = str(value)
|
||||
|
||||
return {
|
||||
"key": val(element.Name),
|
||||
"Name": val(element.Name),
|
||||
"CreatedBy": get_created_by(element),
|
||||
"CreatedOn": get_created_on(element),
|
||||
@@ -458,7 +457,6 @@ def get_zone_data(ifc_file, element):
|
||||
name, category = zone
|
||||
history = get_history(ifc_file)
|
||||
return {
|
||||
"key": "-".join([str(name), str(category), str(space)]),
|
||||
"Name": name,
|
||||
"CreatedBy": get_email_from_history(history) if history else None,
|
||||
"CreatedOn": ifcopenshell.util.date.ifc2datetime(history.CreationDate).isoformat() if history else None,
|
||||
@@ -479,7 +477,6 @@ def get_zone_data(ifc_file, element):
|
||||
space_name = val(space.Name) if space else None
|
||||
|
||||
return {
|
||||
"key": "-".join([str(name), str(category), str(space_name)]),
|
||||
"Name": name,
|
||||
"CreatedBy": get_created_by(zone),
|
||||
"CreatedOn": get_created_on(zone),
|
||||
@@ -588,7 +585,6 @@ def get_type_data(ifc_file, element):
|
||||
asset_type = "Moveable"
|
||||
|
||||
return {
|
||||
"key": val(element.Name),
|
||||
"Name": val(element.Name),
|
||||
"CreatedBy": get_created_by(element),
|
||||
"CreatedOn": get_created_on(element),
|
||||
@@ -664,7 +660,6 @@ def get_component_data(ifc_file, element):
|
||||
asset_identifier = str(value)
|
||||
|
||||
return {
|
||||
"key": element.Name,
|
||||
"Name": element.Name,
|
||||
"CreatedBy": get_created_by(element),
|
||||
"CreatedOn": get_created_on(element),
|
||||
@@ -688,7 +683,6 @@ def get_system_data(ifc_file, element):
|
||||
category = get_category(system)
|
||||
component_name = val(component.Name)
|
||||
return {
|
||||
"key": str(val(system.Name)) + str(category) + str(component_name),
|
||||
"Name": val(system.Name),
|
||||
"CreatedBy": get_created_by(system),
|
||||
"CreatedOn": get_created_on(system),
|
||||
@@ -723,7 +717,6 @@ def get_assembly_data(ifc_file, element):
|
||||
history = get_history(ifc_file)
|
||||
|
||||
return {
|
||||
"key": str(name) + str(sheet_name) + str(parent_name),
|
||||
"Name": name,
|
||||
"CreatedBy": get_email_from_history(history) if history else None,
|
||||
"CreatedOn": ifcopenshell.util.date.ifc2datetime(history.CreationDate).isoformat() if history else None,
|
||||
@@ -749,7 +742,6 @@ def get_connection_data(ifc_file, element):
|
||||
row_name1 = val(ifcopenshell.util.system.get_port_element(element.RelatingPort).Name)
|
||||
row_name2 = val(ifcopenshell.util.system.get_port_element(element.RelatedPort).Name)
|
||||
return {
|
||||
"key": str(name) + str(connection_type) + str(row_name1) + str(row_name2),
|
||||
"Name": name,
|
||||
"CreatedBy": get_created_by(element),
|
||||
"CreatedOn": get_created_on(element),
|
||||
@@ -787,7 +779,6 @@ def get_spare_data(ifc_file, element):
|
||||
part_number = str(value)
|
||||
|
||||
return {
|
||||
"key": val(element),
|
||||
"Name": val(element.Name),
|
||||
"CreatedBy": get_created_by(element),
|
||||
"CreatedOn": get_created_on(element),
|
||||
@@ -805,7 +796,6 @@ def get_spare_data(ifc_file, element):
|
||||
|
||||
def get_resource_data(ifc_file, element):
|
||||
return {
|
||||
"key": val(element.Name),
|
||||
"Name": val(element.Name),
|
||||
"CreatedBy": get_created_by(element),
|
||||
"CreatedOn": get_created_on(element),
|
||||
@@ -866,7 +856,6 @@ def get_job_data(ifc_file, element):
|
||||
priors = ",".join(priors) if priors else task_number
|
||||
|
||||
return {
|
||||
"key": str(val(element.Name)) + str(type_name) + str(task_number),
|
||||
"Name": val(element.Name),
|
||||
"CreatedBy": get_created_by(element),
|
||||
"CreatedOn": get_created_on(element),
|
||||
@@ -908,7 +897,6 @@ def get_document_data(ifc_file, element):
|
||||
sheet_name = get_sheet_name(related_object)
|
||||
row_name = val(related_object.Name)
|
||||
return {
|
||||
"key": str(name) + str(stage) + str(sheet_name) + str(row_name),
|
||||
"Name": name,
|
||||
"CreatedBy": get_created_by(rel),
|
||||
"CreatedOn": get_created_on(rel),
|
||||
@@ -961,28 +949,23 @@ def get_created_by(element):
|
||||
def get_email_from_history(element):
|
||||
pao = element.OwningUser
|
||||
if pao.is_a("IfcPersonAndOrganization"):
|
||||
return get_email_from_pao(pao)
|
||||
return get_email_from_pao(pao.ThePerson, pao.TheOrganization)
|
||||
elif pao.is_a("IfcPerson"):
|
||||
return get_email_from_pao(pao, None)
|
||||
elif pao.is_a("IfcOrganization"):
|
||||
return get_email_from_pao(None, pao)
|
||||
|
||||
|
||||
def get_email_from_pao(pao):
|
||||
for address in pao.ThePerson.Addresses or []:
|
||||
if address.is_a("IfcTelecomAddress") and address.ElectronicMailAddresses:
|
||||
return address.ElectronicMailAddresses[0]
|
||||
def get_email_from_pao(person, organization):
|
||||
if organization:
|
||||
for address in organization.Addresses or []:
|
||||
if address.is_a("IfcTelecomAddress") and address.ElectronicMailAddresses:
|
||||
return address.ElectronicMailAddresses[0]
|
||||
|
||||
for address in pao.TheOrganization.Addresses or []:
|
||||
if address.is_a("IfcTelecomAddress") and address.ElectronicMailAddresses:
|
||||
return address.ElectronicMailAddresses[0]
|
||||
|
||||
person_id = getattr(pao.ThePerson, "Identification", getattr(pao.ThePerson, "Id", None))
|
||||
if person_id:
|
||||
return person_id
|
||||
|
||||
organization_id = getattr(pao.TheOrganization, "Identification", getattr(pao.TheOrganization, "Id", None))
|
||||
if organization_id:
|
||||
return organization_id
|
||||
|
||||
if pao.ThePerson.GivenName and pao.ThePerson.FamilyName and pao.TheOrganization.Name:
|
||||
return pao.ThePerson.GivenName + pao.ThePerson.FamilyName + "@" + pao.TheOrganization.Name + ".com"
|
||||
if person:
|
||||
for address in person.Addresses or []:
|
||||
if address.is_a("IfcTelecomAddress") and address.ElectronicMailAddresses:
|
||||
return address.ElectronicMailAddresses[0]
|
||||
|
||||
|
||||
def get_owner_name(element):
|
||||
@@ -1076,8 +1059,10 @@ def get_category(element):
|
||||
return val(getattr(element, "ObjectType", None))
|
||||
|
||||
|
||||
def get_pao_address(element, name):
|
||||
for actor in [element.ThePerson, element.TheOrganization]:
|
||||
def get_pao_address(person, organization, name):
|
||||
for actor in [organization, person]:
|
||||
if not actor:
|
||||
continue
|
||||
for address in actor.Addresses or []:
|
||||
if hasattr(address, name) and getattr(address, name, None):
|
||||
result = getattr(address, name)
|
||||
@@ -1158,6 +1143,7 @@ config = {
|
||||
"bool_false": "No",
|
||||
"categories": {
|
||||
"Contact": {
|
||||
"keys": ["Email"],
|
||||
"headers": [
|
||||
"Email",
|
||||
"CreatedBy",
|
||||
@@ -1185,6 +1171,7 @@ config = {
|
||||
"get_element_data": get_contact_data,
|
||||
},
|
||||
"Facility": {
|
||||
"keys": ["Name"],
|
||||
"headers": [
|
||||
"Name",
|
||||
"CreatedBy",
|
||||
@@ -1215,6 +1202,7 @@ config = {
|
||||
"get_element_data": get_facility_data,
|
||||
},
|
||||
"Floor": {
|
||||
"keys": ["Name"],
|
||||
"headers": [
|
||||
"Name",
|
||||
"CreatedBy",
|
||||
@@ -1233,6 +1221,7 @@ config = {
|
||||
"get_element_data": get_floor_data,
|
||||
},
|
||||
"Space": {
|
||||
"keys": ["Name"],
|
||||
"headers": [
|
||||
"Name",
|
||||
"CreatedBy",
|
||||
@@ -1254,6 +1243,7 @@ config = {
|
||||
"get_element_data": get_space_data,
|
||||
},
|
||||
"Zone": {
|
||||
"keys": ["Name", "Category", "SpaceNames"],
|
||||
"headers": [
|
||||
"Name",
|
||||
"CreatedBy",
|
||||
@@ -1271,6 +1261,7 @@ config = {
|
||||
"get_element_data": get_zone_data,
|
||||
},
|
||||
"Type": {
|
||||
"keys": ["Name"],
|
||||
"headers": [
|
||||
"Name",
|
||||
"CreatedBy",
|
||||
@@ -1314,6 +1305,7 @@ config = {
|
||||
"get_element_data": get_type_data,
|
||||
},
|
||||
"Component": {
|
||||
"keys": ["Name"],
|
||||
"headers": [
|
||||
"Name",
|
||||
"CreatedBy",
|
||||
@@ -1341,6 +1333,7 @@ config = {
|
||||
"get_element_data": get_component_data,
|
||||
},
|
||||
"System": {
|
||||
"keys": ["Name", "Category", "ComponentNames"],
|
||||
"headers": [
|
||||
"Name",
|
||||
"CreatedBy",
|
||||
@@ -1358,6 +1351,7 @@ config = {
|
||||
"get_element_data": get_system_data,
|
||||
},
|
||||
"Assembly": { # Note that this is technically "not required"
|
||||
"keys": ["Name", "SheetName", "ParentName"],
|
||||
"headers": [
|
||||
"Name",
|
||||
"CreatedBy",
|
||||
@@ -1377,6 +1371,7 @@ config = {
|
||||
"get_element_data": get_assembly_data,
|
||||
},
|
||||
"Connection": { # Note that this is technically "not required"
|
||||
"keys": ["Name", "ConnectionType", "RowName1", "RowName2"],
|
||||
"headers": [
|
||||
"Name",
|
||||
"CreatedBy",
|
||||
@@ -1399,6 +1394,7 @@ config = {
|
||||
"get_element_data": get_connection_data,
|
||||
},
|
||||
"Spare": {
|
||||
"keys": ["Name"],
|
||||
"headers": [
|
||||
"Name",
|
||||
"CreatedBy",
|
||||
@@ -1419,6 +1415,7 @@ config = {
|
||||
"get_element_data": get_spare_data,
|
||||
},
|
||||
"Resource": {
|
||||
"keys": ["Name"],
|
||||
"headers": [
|
||||
"Name",
|
||||
"CreatedBy",
|
||||
@@ -1435,6 +1432,7 @@ config = {
|
||||
"get_element_data": get_resource_data,
|
||||
},
|
||||
"Job": {
|
||||
"keys": ["Name", "TypeName", "TaskNumber"],
|
||||
"headers": [
|
||||
"Name",
|
||||
"CreatedBy",
|
||||
@@ -1462,6 +1460,7 @@ config = {
|
||||
"get_element_data": get_job_data,
|
||||
},
|
||||
"Document": {
|
||||
"keys": ["Name", "Stage", "SheetName", "RowName"],
|
||||
"headers": [
|
||||
"Name",
|
||||
"CreatedBy",
|
||||
@@ -1485,6 +1484,7 @@ config = {
|
||||
"get_element_data": get_document_data,
|
||||
},
|
||||
"Attribute": {
|
||||
"keys": ["Name", "SheetName", "RowName"],
|
||||
"headers": [
|
||||
"Name",
|
||||
"CreatedBy",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -82,8 +82,8 @@ class Usecase:
|
||||
# Create 2 ports, one for either end of both the duct and fitting.
|
||||
duct_port1 = ifcopenshell.api.run("system.add_port", model, element=duct)
|
||||
duct_port2 = ifcopenshell.api.run("system.add_port", model, element=duct)
|
||||
fitting_port1 = ifcopenshell.api.run("system.add_port", model, element=duct)
|
||||
fitting_port2 = ifcopenshell.api.run("system.add_port", model, element=duct)
|
||||
fitting_port1 = ifcopenshell.api.run("system.add_port", model, element=fitting)
|
||||
fitting_port2 = ifcopenshell.api.run("system.add_port", model, element=fitting)
|
||||
|
||||
# Connect the duct and fitting together. At this point, we have not
|
||||
# yet determined the direction of the flow, so we leave direction as
|
||||
|
||||
@@ -52,8 +52,8 @@ class Usecase:
|
||||
# Create 2 ports, one for either end of both the duct and fitting.
|
||||
duct_port1 = ifcopenshell.api.run("system.add_port", model, element=duct)
|
||||
duct_port2 = ifcopenshell.api.run("system.add_port", model, element=duct)
|
||||
fitting_port1 = ifcopenshell.api.run("system.add_port", model, element=duct)
|
||||
fitting_port2 = ifcopenshell.api.run("system.add_port", model, element=duct)
|
||||
fitting_port1 = ifcopenshell.api.run("system.add_port", model, element=fitting)
|
||||
fitting_port2 = ifcopenshell.api.run("system.add_port", model, element=fitting)
|
||||
|
||||
# Connect the duct and fitting together. At this point, we have not
|
||||
# yet determined the direction of the flow, so we leave direction as
|
||||
|
||||
@@ -1022,7 +1022,13 @@ def copy_deep(ifc_file, element, exclude=None, exclude_callback=None, copied_ent
|
||||
elif exclude_callback and exclude_callback(attribute):
|
||||
pass
|
||||
else:
|
||||
attribute = copy_deep(ifc_file, attribute, exclude=exclude, copied_entities=copied_entities)
|
||||
attribute = copy_deep(
|
||||
ifc_file,
|
||||
attribute,
|
||||
exclude=exclude,
|
||||
copied_entities=copied_entities,
|
||||
exclude_callback=exclude_callback,
|
||||
)
|
||||
elif isinstance(attribute, tuple) and attribute and isinstance(attribute[0], ifcopenshell.entity_instance):
|
||||
if exclude and any([attribute[0].is_a(e) for e in exclude]):
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user