ifccityjson conversion support for MultiLineString and MultiPoint

This commit is contained in:
LaurensJN
2021-08-09 13:10:26 +02:00
parent 4c67137d47
commit 4bf074f97a
5 changed files with 546 additions and 23 deletions
+4 -4
View File
@@ -19,8 +19,8 @@ The example file that could be used is example/3D_BAG_example.json
python ifccityjson.py -i example/3DBAG_example.json -o example/3DBAG_example.ifc -n identificatie
## Implemented geometries
- [ ] "MultiPoint"
- [ ] "MultiLineString"
- [x] "MultiPoint"
- [x] "MultiLineString"
- [x] "MultiSurface"
- [x] "CompositeSurface"
- [x] "Solid": exterior shell
@@ -34,5 +34,5 @@ The example file that could be used is example/3D_BAG_example.json
- [x] Implement georeferencing
- [x] Do not use template IFC for new IFC file, but make IFC file from scratch
- [x] Create mapping to IFC for all CityJSON object types & semantic surfaces
- [ ] Implement conversion of all geometries
- [ ] Implement conversion of all LODs instead of online the most detailed
- [ ] Implement conversion of all CitYJSON geometries
- [ ] Implement conversion of all LODs instead of only the most detailed
+15 -12
View File
@@ -106,15 +106,14 @@ class Cityjson2ifc:
def create_new_file(self):
self.IFC_model = ifcopenshell.api.run("project.create_file")
self.IFC_project = ifcopenshell.api.run("root.create_entity", self.IFC_model, **{"ifc_class": "IfcProject"})
ifcopenshell.api.run("unit.assign_unit", self.IFC_model, length={"is_metric": True, "raw": "METERS"})
self.properties["owner_history"] = self.create_owner_history()
ifcopenshell.api.run("unit.assign_unit", self.IFC_model)
self.IFC_representation_context = ifcopenshell.api.run("context.add_context", self.IFC_model,
**{"context": "Model"})
self.IFC_representation_sub_context = ifcopenshell.api.run("context.add_context", self.IFC_model,
**{"context": "Model",
"subcontext": "Body", # LODs as subcontext
"target_view": "MODEL_VIEW"})
self.IFC_site = ifcopenshell.api.run("root.create_entity", self.IFC_model,
**{"ifc_class": "IfcSite",
"name": "My Site"})
@@ -150,7 +149,7 @@ class Cityjson2ifc:
data.update(mapping[1])
# attributes
IFC_name = None
IFC_name = obj_id
if "name_attribute" in self.properties and self.properties["name_attribute"] in obj.attributes:
IFC_name = obj.attributes[self.properties["name_attribute"]]
@@ -175,25 +174,26 @@ class Cityjson2ifc:
child_data = {"GlobalId": ifcopenshell.guid.new(),
"Name": IFC_child_class
}
# CREATE ENTITY
surface_geometry = self.geometry.create_IFC_surface(self.IFC_model, geometry, surface_id)
if surface_geometry:
child_data["Representation"] = self.create_IFC_representation(surface_geometry)
child_data["Representation"] = self.create_IFC_representation(surface_geometry, 'brep')
IFC_children.append(self.IFC_model.create_entity(IFC_child_class, **child_data))
else:
IFC_geometry = self.geometry.create_IFC_geometry(self.IFC_model, geometry)
IFC_geometry, shape_representation_type = self.geometry.create_IFC_geometry(self.IFC_model, geometry)
if IFC_geometry:
data["Representation"] = self.create_IFC_representation(IFC_geometry)
data["Representation"] = self.create_IFC_representation(IFC_geometry, shape_representation_type)
data["GlobalId"] = ifcopenshell.guid.new()
data["Name"] = IFC_name
IFC_object = self.IFC_model.create_entity(IFC_class, **data)
# Define aggregation
self.IFC_model.create_entity("IfcRelAggregates",
self.IFC_model.create_entity("IfcRelContainedInSpatialStructure",
**{"GlobalId": ifcopenshell.guid.new(),
"RelatedObjects": [IFC_object],
"RelatingObject": self.IFC_site}
"RelatedElements": [IFC_object],
"RelatingStructure": self.IFC_site}
)
if IFC_children:
self.IFC_model.create_entity("IfcRelAggregates",
@@ -203,10 +203,13 @@ class Cityjson2ifc:
self.create_property_set(obj.attributes, IFC_object)
def create_IFC_representation(self, IFC_geometry):
def create_IFC_representation(self, IFC_geometry, shape_representation_type):
if not isinstance(IFC_geometry, list):
IFC_geometry = [IFC_geometry]
shape_representation = self.IFC_model.create_entity("IfcShapeRepresentation",
self.IFC_representation_sub_context, 'Body', 'Brep',
[IFC_geometry])
self.IFC_representation_sub_context, 'Body', shape_representation_type,
IFC_geometry)
product_representation = self.IFC_model.create_entity("IfcProductDefinitionShape",
Representations=[shape_representation])
return product_representation
+485
View File
@@ -0,0 +1,485 @@
{
"CityObjects": {
"multipoint": {
"geometry": [
{
"type": "MultiPoint",
"lod": 1,
"boundaries": [
2,
3,
5,
7
]
}
],
"attributes": {
"function": "Being a MultiPoint geometry"
},
"type": "GenericCityObject"
},
"multiline": {
"geometry": [
{
"type": "MultiLineString",
"lod": 1,
"boundaries": [
[
2,
3,
9
],
[
10,
8,
10
]
]
}
],
"attributes": {
"function": "Being a MultiLineString"
},
"type": "GenericCityObject"
},
"multisurface": {
"geometry": [
{
"type": "MultiSurface",
"lod": 1,
"boundaries": [
[
[
0,
3,
2,
1
]
],
[
[
4,
5,
6,
7
]
],
[
[
0,
1,
5,
4
]
]
]
}
],
"attributes": {
"function": "Being a MultiSurface without holes"
},
"type": "GenericCityObject"
},
"CompositeSurface": {
"geometry": [
{
"type": "CompositeSurface",
"lod": 1,
"boundaries": [
[
[
0,
3,
2,
1
]
],
[
[
4,
5,
6,
7
]
],
[
[
0,
1,
5,
4
]
]
]
}
],
"attributes": {
"function": "Being a CompositeSurface without holes"
},
"type": "GenericCityObject"
},
"cube": {
"geometry": [
{
"boundaries": [
[
[
[
0,
1,
2,
3
]
],
[
[
7,
4,
0,
3
]
],
[
[
4,
5,
1,
0
]
],
[
[
5,
6,
2,
1
]
],
[
[
3,
2,
6,
7
]
],
[
[
6,
5,
4,
7
]
]
]
],
"lod": 1,
"type": "Solid"
}
],
"attributes": {
"function": "being a Solid geometry cube"
},
"type": "GenericCityObject"
},
"multicube": {
"geometry": [
{
"boundaries": [[
[
[
[
0,
1,
2,
3
]
],
[
[
7,
4,
0,
3
]
],
[
[
4,
5,
1,
0
]
],
[
[
5,
6,
2,
1
]
],
[
[
3,
2,
6,
7
]
],
[
[
6,
5,
4,
7
]
]
]
],[
[
[
[
0,
1,
2,
3
]
],
[
[
7,
4,
0,
3
]
],
[
[
4,
5,
1,
0
]
],
[
[
5,
6,
2,
1
]
],
[
[
3,
2,
6,
7
]
],
[
[
6,
5,
4,
7
]
]
]
]],
"lod": 1,
"type": "MultiSolid"
}
],
"attributes": {
"function": "being a MultiSolid geometry cube that is twice the same geometry"
},
"type": "GenericCityObject"
},
"compositecube": {
"geometry": [
{
"boundaries": [[
[
[
[
0,
1,
2,
3
]
],
[
[
7,
4,
0,
3
]
],
[
[
4,
5,
1,
0
]
],
[
[
5,
6,
2,
1
]
],
[
[
3,
2,
6,
7
]
],
[
[
6,
5,
4,
7
]
]
]
],[
[
[
[
0,
1,
2,
3
]
],
[
[
7,
4,
0,
3
]
],
[
[
4,
5,
1,
0
]
],
[
[
5,
6,
2,
1
]
],
[
[
3,
2,
6,
7
]
],
[
[
6,
5,
4,
7
]
]
]
]],
"lod": 1,
"type": "CompositeSolid"
}
],
"attributes": {
"function": "being a CompositeSolid geometry cube that is twice the same geometry"
},
"type": "GenericCityObject"
}
},
"type": "CityJSON",
"version": "1.0",
"vertices": [
[
1.0,
0.0,
1.0
],
[
0.0,
1.0,
1.0
],
[
-1.0,
0.0,
1.0
],
[
0.0,
-1.0,
1.0
],
[
1.0,
0.0,
0.0
],
[
0.0,
1.0,
0.0
],
[
-1.0,
0.0,
0.0
],
[
0.0,
-1.0,
0.0
],
[
5.0,
30,
2.0
],
[
6.0,
-1.0,
2.0
],
[
8.0,
7.0,
-1.0
]
],
"metadata": {
"geographicalExtent": [
-1.0,
-1.0,
0.0,
1.0,
1.0,
1.0
]
}
}
+41 -7
View File
@@ -35,16 +35,50 @@ class GeometryIO:
IFC_cartesian_point = IFC_model.create_entity("IfcCartesianPoint", IFC_vertex)
self.vertices[tuple(coord)] = IFC_cartesian_point
# See for CityJSON geometries:
# https://www.cityjson.org/dev/geom-arrays/
# https://www.cityjson.org/specs/1.0.3/#geometry-objects
def create_IFC_geometry(self, IFC_model, geometry):
if geometry.type == "Solid":
return self.create_IFC_closed_shell(IFC_model, geometry)
elif geometry.type in ["CompositeSolid", "MultiSolid"]:
return self.create_IFC_composite_closed_shell(IFC_model, geometry)
IFC_Geometry = None
geometry_type = 'brep'
if geometry.type in ["MultiPoint"]:
IFC_geometry = self.create_IFC_cartesian_point_list3D(IFC_model, geometry)
geometry_type = 'PointCloud'
elif geometry.type in ["MultiLineString"]:
IFC_geometry = self.create_IFC_composite_curve(IFC_model, geometry)
geometry_type = 'Curve3D'
elif geometry.type in ["CompositeSurface", "MultiSurface"]:
return self.create_IFC_surface(IFC_model, geometry)
IFC_geometry = self.create_IFC_surface(IFC_model, geometry)
elif geometry.type == "Solid":
IFC_geometry = self.create_IFC_closed_shell(IFC_model, geometry)
elif geometry.type in ["CompositeSolid", "MultiSolid"]:
IFC_geometry = self.create_IFC_composite_closed_shell(IFC_model, geometry)
elif geometry.type in ["GeometryInstance"]:
warnings.warn("GeometryInstance is not supported.")
return None, None
else:
warnings.warn("Types other than solids are not yet supported")
return
warnings.warn("Custom CityJSON geometries are not supported.")
return None, None
return IFC_geometry, geometry_type
def create_IFC_cartesian_point_list3D(self, IFC_model, geometry):
# https://www.cityjson.org/dev/geom-arrays/
# https://standards.buildingsmart.org/IFC/DEV/IFC4_2/FINAL/HTML/schema/ifcgeometricmodelresource/lexical/ifccartesianpointlist3d.htm
IFC_geometry = IFC_model.create_entity("IfcCartesianPointList3D", geometry.boundaries)
return IFC_geometry
def create_IFC_composite_curve(self, IFC_model, geometry):
# https://www.cityjson.org/dev/geom-arrays/
# https://standards.buildingsmart.org/IFC/DEV/IFC4_2/FINAL/HTML/schema/ifcgeometryresource/lexical/ifccompositecurve.htm
# https://standards.buildingsmart.org/IFC/DEV/IFC4_2/FINAL/HTML/schema/ifcgeometryresource/lexical/ifccompositecurvesegment.htm
IFC_geometry = []
for line in geometry.boundaries:
vertices = []
for vertex in line:
vertices.append(self.vertices[tuple(vertex)])
polyline = IFC_model.create_entity("IfcPolyLine", vertices)
IFC_geometry.append(polyline)
return IFC_geometry
def create_IFC_composite_closed_shell(self, IFC_model, geometry):
shells = []
+1
View File
@@ -25,6 +25,7 @@ from cityjson2ifc import Cityjson2ifc
if __name__ == '__main__':
# Example:
# python ifccityjson.py -i example/3DBAG_example.json -o example/output.ifc -n identificatie
# python ifccityjson.py -i example/geometries.json -o example/geometry_output.ifc
parser = argparse.ArgumentParser(description="")
parser.add_argument("-i", "--input", type=str, help="input CityJSON file", required=True)
parser.add_argument("-o", "--output", type=str, help="output IFC file. Standard is output.ifc")