add support for 2d elements and instances
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,394 @@
|
||||
User Data: [
|
||||
{'id': '34fdb59ab62f3e0780d0d6e674ed8048', 'name': 'Grasshopper Model', 'version': 3, 'elements': [
|
||||
{'__closure': None, 'referencedId': '3613b6aed1da75447a79a5aa08fe0373', 'speckle_type': 'reference'
|
||||
}
|
||||
], '__closure': {'02fd4e9236aa8203e3e9893645d23e8e': 2, '2b52c8e3ff01006ec2c709122a634dbd': 2, '3613b6aed1da75447a79a5aa08fe0373': 1, '52a623ceb08d87797a7f7ba36434da18': 2, '68c358f888cb5fa565279bff9e9f0ad2': 2, '8337f3f819140b460131af3f17367500': 2, 'a7b19942ff5bbe5dcfce155eddacf14d': 2, 'a8429dd57aed90750d47d036a77f8ada': 2, 'c8811f6522b169f1993f78a1b79e354f': 2, 'eb574c7da4393c988c49bf09c92ce8b8': 2, 'f5263a6bf3d83aafffa4af92fafdd00d': 2
|
||||
}, 'properties': {}, 'colorProxies': [], 'speckle_type': 'Speckle.Core.Models.Collections.Collection:Speckle.Core.Models.Collections.RootCollection', 'applicationId': '315b8e08-bd7a-4468-b8f4-ddcb58eb2f24', 'collectionType': None, 'renderMaterialProxies': [
|
||||
{'id': '243c8308077386e1b37cab7d72e85493', 'value': {'id': '4450546a61be09e86ae2b22b99f78c36', 'name': None, 'shine': 0, 'diffuse': -2994608, 'opacity': 1, 'emissive': -16777216, 'specular': -1, 'metalness': 0, 'roughness': 1, 'speckle_type': 'Objects.Other.RenderMaterial', 'applicationId': 'material_0_Color [A=255, R=210, G=78, B=80
|
||||
]_Color [Black
|
||||
]_0_Color [White
|
||||
]'
|
||||
}, 'objects': ['f9eea996-6497-483e-9425-9eba17cc0792', '14afade6-a327-45a4-80be-7cdf479fda67', '48984c1b-c587-47cd-b53d-224a764db435', '1ff5e839-9939-4f11-9441-7ee69084366c', '8db8e229-ea79-42e6-8b95-5c97ef673444', '6bb9c86b-7028-4471-bdae-3304c15382e7', '0212fc75-9106-4932-b695-66bafb41a791', '7b0f464b-9077-462f-8c19-f9bd73beeb55', '6d0ef043-0882-4d73-80e0-d36bff7f89b1'
|
||||
], 'speckle_type': 'Objects.Other.RenderMaterialProxy', 'applicationId': 'material_0_Color [A=255, R=210, G=78, B=80
|
||||
]_Color [Black
|
||||
]_0_Color [White
|
||||
]'
|
||||
}
|
||||
], 'instanceDefinitionProxies': [
|
||||
{'id': '045f42290314ef67fc1482cf18637d51', 'name': '2dstuff', 'objects': ['001bbd8e-b5a6-4747-b8fa-b002c352a113'
|
||||
], 'maxDepth': 0, 'speckle_type': 'Speckle.Core.Models.Instances.InstanceDefinitionProxy', 'applicationId': 'f480a3ac-572e-45d6-b92c-3fe2d88ff609'
|
||||
}
|
||||
], 'totalChildrenCount': None
|
||||
},
|
||||
{'id': '02fd4e9236aa8203e3e9893645d23e8e', 'name': '', 'units': 'cm', 'maxDepth': 0, 'transform': [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
], 'properties': {'Attributes': {'id': '2341', 'Tag': '414482', 'Name': 'M_Concrete-Sq-Column', 'type': 'IfcColumn', 'GlobalId': '3lIj7B0LnBjf0mvxk2zuuc', 'ObjectType': 'Square-C40'
|
||||
}, 'Quantities': {'Qto_ColumnBaseQuantities': {'id': 'M_40', 'Length': 3000, 'GrossVolumn': 0.27
|
||||
}
|
||||
}, 'Property Sets': {'Pset_ColumnCommon': {'Reference': 'M_40', 'IsExternal': 'True', 'LoadBearing': 'False'
|
||||
}
|
||||
}, 'Building Storey': 'Level0', 'Element Type Property Sets': {'Pset_ColumnCommon': {'IsExternal': 'True'
|
||||
}
|
||||
}
|
||||
}, 'definitionId': 'f480a3ac-572e-45d6-b92c-3fe2d88ff609', 'speckle_type': 'Speckle.Core.Models.Instances.InstanceProxy', 'applicationId': 'f9eea996-6497-483e-9425-9eba17cc0792'
|
||||
},
|
||||
{'id': '2b52c8e3ff01006ec2c709122a634dbd', 'name': '', 'units': 'cm', 'maxDepth': 0, 'transform': [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
800,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
1600,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
3000,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
], 'properties': {'Attributes': {'id': '2341', 'Tag': '414482', 'Name': 'M_Concrete-Sq-Column', 'type': 'IfcColumn', 'GlobalId': '3lIj7B0LnBjf0mvxk2zuuc', 'ObjectType': 'Square-C40'
|
||||
}, 'Quantities': {'Qto_ColumnBaseQuantities': {'id': 'M_40', 'Length': 3000, 'GrossVolumn': 0.27
|
||||
}
|
||||
}, 'Property Sets': {'Pset_ColumnCommon': {'Reference': 'M_40', 'IsExternal': 'True', 'LoadBearing': 'False'
|
||||
}
|
||||
}, 'Building Storey': 'Level1', 'Element Type Property Sets': {'Pset_ColumnCommon': {'IsExternal': 'True'
|
||||
}
|
||||
}
|
||||
}, 'definitionId': 'f480a3ac-572e-45d6-b92c-3fe2d88ff609', 'speckle_type': 'Speckle.Core.Models.Instances.InstanceProxy', 'applicationId': '6bb9c86b-7028-4471-bdae-3304c15382e7'
|
||||
},
|
||||
{'id': '3613b6aed1da75447a79a5aa08fe0373', 'name': 'Sub-Collection 1', 'elements': [
|
||||
{'__closure': None, 'referencedId': '02fd4e9236aa8203e3e9893645d23e8e', 'speckle_type': 'reference'
|
||||
},
|
||||
{'__closure': None, 'referencedId': '8337f3f819140b460131af3f17367500', 'speckle_type': 'reference'
|
||||
},
|
||||
{'__closure': None, 'referencedId': 'a7b19942ff5bbe5dcfce155eddacf14d', 'speckle_type': 'reference'
|
||||
},
|
||||
{'__closure': None, 'referencedId': 'f5263a6bf3d83aafffa4af92fafdd00d', 'speckle_type': 'reference'
|
||||
},
|
||||
{'__closure': None, 'referencedId': '68c358f888cb5fa565279bff9e9f0ad2', 'speckle_type': 'reference'
|
||||
},
|
||||
{'__closure': None, 'referencedId': 'eb574c7da4393c988c49bf09c92ce8b8', 'speckle_type': 'reference'
|
||||
},
|
||||
{'__closure': None, 'referencedId': '2b52c8e3ff01006ec2c709122a634dbd', 'speckle_type': 'reference'
|
||||
},
|
||||
{'__closure': None, 'referencedId': 'a8429dd57aed90750d47d036a77f8ada', 'speckle_type': 'reference'
|
||||
},
|
||||
{'__closure': None, 'referencedId': 'c8811f6522b169f1993f78a1b79e354f', 'speckle_type': 'reference'
|
||||
},
|
||||
{'__closure': None, 'referencedId': '52a623ceb08d87797a7f7ba36434da18', 'speckle_type': 'reference'
|
||||
}
|
||||
], 'topology': '0-3 1-3 2-3 ', '__closure': {'02fd4e9236aa8203e3e9893645d23e8e': 1, '2b52c8e3ff01006ec2c709122a634dbd': 1, '52a623ceb08d87797a7f7ba36434da18': 1, '68c358f888cb5fa565279bff9e9f0ad2': 1, '8337f3f819140b460131af3f17367500': 1, 'a7b19942ff5bbe5dcfce155eddacf14d': 1, 'a8429dd57aed90750d47d036a77f8ada': 1, 'c8811f6522b169f1993f78a1b79e354f': 1, 'eb574c7da4393c988c49bf09c92ce8b8': 1, 'f5263a6bf3d83aafffa4af92fafdd00d': 1
|
||||
}, 'speckle_type': 'Speckle.Core.Models.Collections.Collection', 'applicationId': '0d054742-8287-4956-a0ba-bcebdadaa7ee', 'collectionType': None
|
||||
},
|
||||
{'id': '52a623ceb08d87797a7f7ba36434da18', 'name': '', 'units': 'cm', 'maxDepth': 0, 'transform': [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1600,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
1600,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
6000,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
], 'properties': {'Attributes': {'id': '2341', 'Tag': '414482', 'Name': 'M_Concrete-Sq-Column', 'type': 'IfcColumn', 'GlobalId': '3lIj7B0LnBjf0mvxk2zuuc', 'ObjectType': 'Square-C40'
|
||||
}, 'Quantities': {'Qto_ColumnBaseQuantities': {'id': 'M_40', 'Length': 3000, 'GrossVolumn': 0.27
|
||||
}
|
||||
}, 'Property Sets': {'Pset_ColumnCommon': {'Reference': 'M_40', 'IsExternal': 'True', 'LoadBearing': 'False'
|
||||
}
|
||||
}, 'Building Storey': 'Level2', 'Element Type Property Sets': {'Pset_ColumnCommon': {'IsExternal': 'True'
|
||||
}
|
||||
}
|
||||
}, 'definitionId': 'f480a3ac-572e-45d6-b92c-3fe2d88ff609', 'speckle_type': 'Speckle.Core.Models.Instances.InstanceProxy', 'applicationId': '6d0ef043-0882-4d73-80e0-d36bff7f89b1'
|
||||
},
|
||||
{'id': '68c358f888cb5fa565279bff9e9f0ad2', 'name': '', 'units': 'cm', 'maxDepth': 0, 'transform': [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
800,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
3000,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
], 'properties': {'Attributes': {'id': '2341', 'Tag': '414482', 'Name': 'M_Concrete-Sq-Column', 'type': 'IfcColumn', 'GlobalId': '3lIj7B0LnBjf0mvxk2zuuc', 'ObjectType': 'Square-C40'
|
||||
}, 'Quantities': {'Qto_ColumnBaseQuantities': {'id': 'M_40', 'Length': 3000, 'GrossVolumn': 0.27
|
||||
}
|
||||
}, 'Property Sets': {'Pset_ColumnCommon': {'Reference': 'M_40', 'IsExternal': 'True', 'LoadBearing': 'False'
|
||||
}
|
||||
}, 'Building Storey': 'Level1', 'Element Type Property Sets': {'Pset_ColumnCommon': {'IsExternal': 'True'
|
||||
}
|
||||
}
|
||||
}, 'definitionId': 'f480a3ac-572e-45d6-b92c-3fe2d88ff609', 'speckle_type': 'Speckle.Core.Models.Instances.InstanceProxy', 'applicationId': '1ff5e839-9939-4f11-9441-7ee69084366c'
|
||||
},
|
||||
{'id': '8337f3f819140b460131af3f17367500', 'area': 0, 'bbox': None, 'name': '', 'units': 'cm', 'closed': True, 'domain': {'id': 'd8d1433909fb59a39f68add928b6c6cb', 'end': 1452.3539364174444, 'start': 0, 'speckle_type': 'Objects.Primitive.Interval', 'applicationId': None
|
||||
}, 'length': 1452.3539364174444, 'segments': [
|
||||
{'id': '2a53ab8190fdfd471a4fc40de8b7cfd1', 'end': {'x': 314, 'y': 0, 'z': 0, 'id': '5e36a92a5b1bd770e3b3498afee7a020', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'bbox': None, 'start': {'x': 86, 'y': 0, 'z': 0, 'id': '13f192aab1715fe46ce1e9894f559c47', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'units': 'cm', 'domain': {'id': 'cd1e347341b2fdfe05cdc7e162030d0b', 'end': 228, 'start': 0, 'speckle_type': 'Objects.Primitive.Interval', 'applicationId': None
|
||||
}, 'length': 228, 'speckle_type': 'Objects.Geometry.Line', 'applicationId': None
|
||||
},
|
||||
{'id': 'c53395b2b10123431324d2ba4dda7b50', 'bbox': {'id': '646491fbda16d7c6e87bebace9bca820', 'area': 14792, 'plane': {'id': 'b9661b771cb4091c7985e24072bb8f99', 'xdir': {'x': 1, 'y': 0, 'z': 0, 'id': 'e5642698411042d5b4f01740c0181175', 'bbox': None, 'units': 'cm', 'speckle_type': 'Objects.Geometry.Vector', 'applicationId': None
|
||||
}, 'ydir': {'x': 0, 'y': 1, 'z': 0, 'id': 'a74c24ffed0ab761ca0850152d74f103', 'bbox': None, 'units': 'cm', 'speckle_type': 'Objects.Geometry.Vector', 'applicationId': None
|
||||
}, 'units': 'cm', 'normal': {'x': 0, 'y': 0, 'z': 1, 'id': 'b914dfcf182d58607a97f9818496691d', 'bbox': None, 'units': 'cm', 'speckle_type': 'Objects.Geometry.Vector', 'applicationId': None
|
||||
}, 'origin': {'x': 0, 'y': 0, 'z': 0, 'id': '6c70614c9f2ebd32c169f52e23a04fbf', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'speckle_type': 'Objects.Geometry.Plane', 'applicationId': None
|
||||
}, 'units': 'cm', 'xSize': {'id': '67575b21c01426dbb7db1e401d5c6ce0', 'end': 400, 'start': 314, 'speckle_type': 'Objects.Primitive.Interval', 'applicationId': None
|
||||
}, 'ySize': {'id': '139092bcab18d041bc2b3b4f07908b5a', 'end': 86, 'start': 0, 'speckle_type': 'Objects.Primitive.Interval', 'applicationId': None
|
||||
}, 'zSize': {'id': '000e6a5831ce9aa0b9612614601aa86b', 'end': 0, 'start': 0, 'speckle_type': 'Objects.Primitive.Interval', 'applicationId': None
|
||||
}, 'volume': 0, 'speckle_type': 'Objects.Geometry.Box', 'applicationId': None
|
||||
}, 'plane': {'id': 'c1d272cc9d1efbb010363524cbeb59c2', 'xdir': {'x': -1.3219399735071649e-15, 'y': -1, 'z': 0, 'id': 'cc8bd0226417fd5e1e9943d9addb5b4a', 'bbox': None, 'units': 'cm', 'speckle_type': 'Objects.Geometry.Vector', 'applicationId': None
|
||||
}, 'ydir': {'x': 1, 'y': -1.3219399735071649e-15, 'z': 0, 'id': '99f13453930320d90244bf0f0d933b0d', 'bbox': None, 'units': 'cm', 'speckle_type': 'Objects.Geometry.Vector', 'applicationId': None
|
||||
}, 'units': 'cm', 'normal': {'x': 0, 'y': 0, 'z': 1, 'id': 'b914dfcf182d58607a97f9818496691d', 'bbox': None, 'units': 'cm', 'speckle_type': 'Objects.Geometry.Vector', 'applicationId': None
|
||||
}, 'origin': {'x': 314.0000000000001, 'y': 85.99999999999989, 'z': 0, 'id': '2a24b4c76322b3aacea562c7077736ed', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'speckle_type': 'Objects.Geometry.Plane', 'applicationId': None
|
||||
}, 'units': 'cm', 'domain': {'id': 'ff31a8e0e7b84dbc2852b2c632835e33', 'end': 135.08848410436116, 'start': 0, 'speckle_type': 'Objects.Primitive.Interval', 'applicationId': None
|
||||
}, 'length': 135.08848410436116, 'radius': 85.99999999999989, 'measure': 1.5707963267948992, 'endPoint': {'x': 400, 'y': 86, 'z': 0, 'id': 'f1f5727576aa37fb893e127e51c696bf', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'midPoint': {'x': 374.8111831820431, 'y': 25.18881681795688, 'z': 0, 'id': 'f66a1cc7820a970053afdb0cfe150c2b', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'startPoint': {'x': 314, 'y': 0, 'z': 0, 'id': '5e36a92a5b1bd770e3b3498afee7a020', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'speckle_type': 'Objects.Geometry.Arc', 'applicationId': None
|
||||
},
|
||||
{'id': '5d79cd7f50d6da7f4f03a9d73ec3d9f0', 'end': {'x': 400, 'y': 314, 'z': 0, 'id': '972e682e64e39316165bccdd7064af49', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'bbox': None, 'start': {'x': 400, 'y': 86, 'z': 0, 'id': 'f1f5727576aa37fb893e127e51c696bf', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'units': 'cm', 'domain': {'id': 'cd1e347341b2fdfe05cdc7e162030d0b', 'end': 228, 'start': 0, 'speckle_type': 'Objects.Primitive.Interval', 'applicationId': None
|
||||
}, 'length': 228, 'speckle_type': 'Objects.Geometry.Line', 'applicationId': None
|
||||
},
|
||||
{'id': 'ddddb9cd7b47422856043378ffa25f55', 'bbox': {'id': '70b70d5c45803b52c7e32bff23541843', 'area': 14791.99999999998, 'plane': {'id': 'b9661b771cb4091c7985e24072bb8f99', 'xdir': {'x': 1, 'y': 0, 'z': 0, 'id': 'e5642698411042d5b4f01740c0181175', 'bbox': None, 'units': 'cm', 'speckle_type': 'Objects.Geometry.Vector', 'applicationId': None
|
||||
}, 'ydir': {'x': 0, 'y': 1, 'z': 0, 'id': 'a74c24ffed0ab761ca0850152d74f103', 'bbox': None, 'units': 'cm', 'speckle_type': 'Objects.Geometry.Vector', 'applicationId': None
|
||||
}, 'units': 'cm', 'normal': {'x': 0, 'y': 0, 'z': 1, 'id': 'b914dfcf182d58607a97f9818496691d', 'bbox': None, 'units': 'cm', 'speckle_type': 'Objects.Geometry.Vector', 'applicationId': None
|
||||
}, 'origin': {'x': 0, 'y': 0, 'z': 0, 'id': '6c70614c9f2ebd32c169f52e23a04fbf', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'speckle_type': 'Objects.Geometry.Plane', 'applicationId': None
|
||||
}, 'units': 'cm', 'xSize': {'id': '67575b21c01426dbb7db1e401d5c6ce0', 'end': 400, 'start': 314, 'speckle_type': 'Objects.Primitive.Interval', 'applicationId': None
|
||||
}, 'ySize': {'id': '0937eb18914c0839931b4ee8344cc743', 'end': 399.9999999999999, 'start': 314, 'speckle_type': 'Objects.Primitive.Interval', 'applicationId': None
|
||||
}, 'zSize': {'id': '000e6a5831ce9aa0b9612614601aa86b', 'end': 0, 'start': 0, 'speckle_type': 'Objects.Primitive.Interval', 'applicationId': None
|
||||
}, 'volume': 0, 'speckle_type': 'Objects.Geometry.Box', 'applicationId': None
|
||||
}, 'plane': {'id': '33b44853350b90ba826ed4bff07f74ac', 'xdir': {'x': 1, 'y': 0, 'z': 0, 'id': 'e5642698411042d5b4f01740c0181175', 'bbox': None, 'units': 'cm', 'speckle_type': 'Objects.Geometry.Vector', 'applicationId': None
|
||||
}, 'ydir': {'x': 0, 'y': 1, 'z': 0, 'id': 'a74c24ffed0ab761ca0850152d74f103', 'bbox': None, 'units': 'cm', 'speckle_type': 'Objects.Geometry.Vector', 'applicationId': None
|
||||
}, 'units': 'cm', 'normal': {'x': 0, 'y': 0, 'z': 1, 'id': 'b914dfcf182d58607a97f9818496691d', 'bbox': None, 'units': 'cm', 'speckle_type': 'Objects.Geometry.Vector', 'applicationId': None
|
||||
}, 'origin': {'x': 314.0000000000001, 'y': 314, 'z': 0, 'id': '1edc94b63286f3263f6cd319cdea6874', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'speckle_type': 'Objects.Geometry.Plane', 'applicationId': None
|
||||
}, 'units': 'cm', 'domain': {'id': '0e17bec00b0fb71de25bd620542528a8', 'end': 135.08848410436104, 'start': 0, 'speckle_type': 'Objects.Primitive.Interval', 'applicationId': None
|
||||
}, 'length': 135.08848410436104, 'radius': 85.99999999999989, 'measure': 1.570796326794898, 'endPoint': {'x': 314, 'y': 399.9999999999999, 'z': 0, 'id': 'aa73c80f7099f766508c429ca7f7c049', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'midPoint': {'x': 374.81118318204307, 'y': 374.81118318204307, 'z': 0, 'id': '916d7ecb5cc11c292653678f366a0dce', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'startPoint': {'x': 400, 'y': 314, 'z': 0, 'id': '972e682e64e39316165bccdd7064af49', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'speckle_type': 'Objects.Geometry.Arc', 'applicationId': None
|
||||
},
|
||||
{'id': '4c6a78b95e5fcb80c22add2ab203d174', 'end': {'x': 86, 'y': 400, 'z': 0, 'id': 'c38190449d3f935a16c05385f5dd9ff0', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'bbox': None, 'start': {'x': 314, 'y': 399.9999999999999, 'z': 0, 'id': 'aa73c80f7099f766508c429ca7f7c049', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'units': 'cm', 'domain': {'id': 'cd1e347341b2fdfe05cdc7e162030d0b', 'end': 228, 'start': 0, 'speckle_type': 'Objects.Primitive.Interval', 'applicationId': None
|
||||
}, 'length': 228, 'speckle_type': 'Objects.Geometry.Line', 'applicationId': None
|
||||
},
|
||||
{'id': '528a313951093db36dd2b3cfcf10ac03', 'bbox': {'id': '4f07082d6f71610f6b9430af98539864', 'area': 14791.999999999995, 'plane': {'id': 'b9661b771cb4091c7985e24072bb8f99', 'xdir': {'x': 1, 'y': 0, 'z': 0, 'id': 'e5642698411042d5b4f01740c0181175', 'bbox': None, 'units': 'cm', 'speckle_type': 'Objects.Geometry.Vector', 'applicationId': None
|
||||
}, 'ydir': {'x': 0, 'y': 1, 'z': 0, 'id': 'a74c24ffed0ab761ca0850152d74f103', 'bbox': None, 'units': 'cm', 'speckle_type': 'Objects.Geometry.Vector', 'applicationId': None
|
||||
}, 'units': 'cm', 'normal': {'x': 0, 'y': 0, 'z': 1, 'id': 'b914dfcf182d58607a97f9818496691d', 'bbox': None, 'units': 'cm', 'speckle_type': 'Objects.Geometry.Vector', 'applicationId': None
|
||||
}, 'origin': {'x': 0, 'y': 0, 'z': 0, 'id': '6c70614c9f2ebd32c169f52e23a04fbf', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'speckle_type': 'Objects.Geometry.Plane', 'applicationId': None
|
||||
}, 'units': 'cm', 'xSize': {'id': '60fb5c265c45c1e742293a1408eebd5e', 'end': 86, 'start': 2.842170943040401e-14, 'speckle_type': 'Objects.Primitive.Interval', 'applicationId': None
|
||||
}, 'ySize': {'id': '67575b21c01426dbb7db1e401d5c6ce0', 'end': 400, 'start': 314, 'speckle_type': 'Objects.Primitive.Interval', 'applicationId': None
|
||||
}, 'zSize': {'id': '000e6a5831ce9aa0b9612614601aa86b', 'end': 0, 'start': 0, 'speckle_type': 'Objects.Primitive.Interval', 'applicationId': None
|
||||
}, 'volume': 0, 'speckle_type': 'Objects.Geometry.Box', 'applicationId': None
|
||||
}, 'plane': {'id': 'e6309b915773b4760040b0780d39ae6a', 'xdir': {'x': -3.304849933767908e-16, 'y': 1, 'z': 0, 'id': '516786f30ebb560fd0d0d4a08f5480d6', 'bbox': None, 'units': 'cm', 'speckle_type': 'Objects.Geometry.Vector', 'applicationId': None
|
||||
}, 'ydir': {'x': -1, 'y': -3.304849933767908e-16, 'z': 0, 'id': '86c78a2b248f5657eca66f25da703e27', 'bbox': None, 'units': 'cm', 'speckle_type': 'Objects.Geometry.Vector', 'applicationId': None
|
||||
}, 'units': 'cm', 'normal': {'x': 0, 'y': 0, 'z': 1, 'id': 'b914dfcf182d58607a97f9818496691d', 'bbox': None, 'units': 'cm', 'speckle_type': 'Objects.Geometry.Vector', 'applicationId': None
|
||||
}, 'origin': {'x': 86.00000000000003, 'y': 314, 'z': 0, 'id': '46c1110cbfb32dcd6d7b4ad36a6ea5e6', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'speckle_type': 'Objects.Geometry.Plane', 'applicationId': None
|
||||
}, 'units': 'cm', 'domain': {'id': 'ee46a19db905bc93fb0a8488442584b6', 'end': 135.08848410436107, 'start': 0, 'speckle_type': 'Objects.Primitive.Interval', 'applicationId': None
|
||||
}, 'length': 135.08848410436107, 'radius': 86, 'measure': 1.5707963267948961, 'endPoint': {'x': 2.842170943040401e-14, 'y': 314, 'z': 0, 'id': '6b544465d25084da5ec0c9d1b6fb59f8', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'midPoint': {'x': 25.188816817956933, 'y': 374.81118318204307, 'z': 0, 'id': '6145f8f80ede99159cd28c09c8407812', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'startPoint': {'x': 86, 'y': 400, 'z': 0, 'id': 'c38190449d3f935a16c05385f5dd9ff0', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'speckle_type': 'Objects.Geometry.Arc', 'applicationId': None
|
||||
},
|
||||
{'id': '074ecdc4702d62925874ad44572b94dd', 'end': {'x': 0, 'y': 86, 'z': 0, 'id': '8ce2dde674d79cf97e354a21760c06a3', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'bbox': None, 'start': {'x': 2.842170943040401e-14, 'y': 314, 'z': 0, 'id': '6b544465d25084da5ec0c9d1b6fb59f8', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'units': 'cm', 'domain': {'id': 'cd1e347341b2fdfe05cdc7e162030d0b', 'end': 228, 'start': 0, 'speckle_type': 'Objects.Primitive.Interval', 'applicationId': None
|
||||
}, 'length': 228, 'speckle_type': 'Objects.Geometry.Line', 'applicationId': None
|
||||
},
|
||||
{'id': 'd9416cf401551630fde7e1a438c5704b', 'bbox': {'id': '338bb17957daa275067666c2e8e5612c', 'area': 14792, 'plane': {'id': 'b9661b771cb4091c7985e24072bb8f99', 'xdir': {'x': 1, 'y': 0, 'z': 0, 'id': 'e5642698411042d5b4f01740c0181175', 'bbox': None, 'units': 'cm', 'speckle_type': 'Objects.Geometry.Vector', 'applicationId': None
|
||||
}, 'ydir': {'x': 0, 'y': 1, 'z': 0, 'id': 'a74c24ffed0ab761ca0850152d74f103', 'bbox': None, 'units': 'cm', 'speckle_type': 'Objects.Geometry.Vector', 'applicationId': None
|
||||
}, 'units': 'cm', 'normal': {'x': 0, 'y': 0, 'z': 1, 'id': 'b914dfcf182d58607a97f9818496691d', 'bbox': None, 'units': 'cm', 'speckle_type': 'Objects.Geometry.Vector', 'applicationId': None
|
||||
}, 'origin': {'x': 0, 'y': 0, 'z': 0, 'id': '6c70614c9f2ebd32c169f52e23a04fbf', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'speckle_type': 'Objects.Geometry.Plane', 'applicationId': None
|
||||
}, 'units': 'cm', 'xSize': {'id': '139092bcab18d041bc2b3b4f07908b5a', 'end': 86, 'start': 0, 'speckle_type': 'Objects.Primitive.Interval', 'applicationId': None
|
||||
}, 'ySize': {'id': '139092bcab18d041bc2b3b4f07908b5a', 'end': 86, 'start': 0, 'speckle_type': 'Objects.Primitive.Interval', 'applicationId': None
|
||||
}, 'zSize': {'id': '000e6a5831ce9aa0b9612614601aa86b', 'end': 0, 'start': 0, 'speckle_type': 'Objects.Primitive.Interval', 'applicationId': None
|
||||
}, 'volume': 0, 'speckle_type': 'Objects.Geometry.Box', 'applicationId': None
|
||||
}, 'plane': {'id': 'c5c55636af89e2ef88a1ce8bac726ff1', 'xdir': {'x': -1, 'y': 3.304849933767909e-16, 'z': 0, 'id': '792ae2f3f2a9c57b079976754ad2cc1a', 'bbox': None, 'units': 'cm', 'speckle_type': 'Objects.Geometry.Vector', 'applicationId': None
|
||||
}, 'ydir': {'x': -3.304849933767909e-16, 'y': -1, 'z': 0, 'id': '92b8a48e36b6af9e0891a69526ad565b', 'bbox': None, 'units': 'cm', 'speckle_type': 'Objects.Geometry.Vector', 'applicationId': None
|
||||
}, 'units': 'cm', 'normal': {'x': 0, 'y': 0, 'z': 1, 'id': 'b914dfcf182d58607a97f9818496691d', 'bbox': None, 'units': 'cm', 'speckle_type': 'Objects.Geometry.Vector', 'applicationId': None
|
||||
}, 'origin': {'x': 85.99999999999997, 'y': 85.99999999999997, 'z': 0, 'id': 'd3ec5dd9ffac610686d8287f8b1b4299', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'speckle_type': 'Objects.Geometry.Plane', 'applicationId': None
|
||||
}, 'units': 'cm', 'domain': {'id': '12280f5df1a216096d7649924b4a0a32', 'end': 135.08848410436113, 'start': 0, 'speckle_type': 'Objects.Primitive.Interval', 'applicationId': None
|
||||
}, 'length': 135.08848410436113, 'radius': 85.99999999999997, 'measure': 1.5707963267948974, 'endPoint': {'x': 86, 'y': 0, 'z': 0, 'id': '13f192aab1715fe46ce1e9894f559c47', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'midPoint': {'x': 25.188816817956898, 'y': 25.188816817956905, 'z': 0, 'id': 'd5c3c7f3a7c664bfe4d112859002b56b', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'startPoint': {'x': 0, 'y': 86, 'z': 0, 'id': '8ce2dde674d79cf97e354a21760c06a3', 'units': 'cm', 'speckle_type': 'Objects.Geometry.Point', 'applicationId': None
|
||||
}, 'speckle_type': 'Objects.Geometry.Arc', 'applicationId': None
|
||||
}
|
||||
], 'properties': {}, 'speckle_type': 'Objects.Geometry.Polycurve', 'applicationId': '001bbd8e-b5a6-4747-b8fa-b002c352a113'
|
||||
},
|
||||
{'id': 'a7b19942ff5bbe5dcfce155eddacf14d', 'name': '', 'units': 'cm', 'maxDepth': 0, 'transform': [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
800,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
], 'properties': {'Attributes': {'id': '2341', 'Tag': '414482', 'Name': 'M_Concrete-Sq-Column', 'type': 'IfcColumn', 'GlobalId': '3lIj7B0LnBjf0mvxk2zuuc', 'ObjectType': 'Square-C40'
|
||||
}, 'Quantities': {'Qto_ColumnBaseQuantities': {'id': 'M_40', 'Length': 3000, 'GrossVolumn': 0.27
|
||||
}
|
||||
}, 'Property Sets': {'Pset_ColumnCommon': {'Reference': 'M_40', 'IsExternal': 'True', 'LoadBearing': 'False'
|
||||
}
|
||||
}, 'Building Storey': 'Level0', 'Element Type Property Sets': {'Pset_ColumnCommon': {'IsExternal': 'True'
|
||||
}
|
||||
}
|
||||
}, 'definitionId': 'f480a3ac-572e-45d6-b92c-3fe2d88ff609', 'speckle_type': 'Speckle.Core.Models.Instances.InstanceProxy', 'applicationId': '14afade6-a327-45a4-80be-7cdf479fda67'
|
||||
},
|
||||
{'id': 'a8429dd57aed90750d47d036a77f8ada', 'name': '', 'units': 'cm', 'maxDepth': 0, 'transform': [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1600,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
6000,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
], 'properties': {'Attributes': {'id': '2341', 'Tag': '414482', 'Name': 'M_Concrete-Sq-Column', 'type': 'IfcColumn', 'GlobalId': '3lIj7B0LnBjf0mvxk2zuuc', 'ObjectType': 'Square-C40'
|
||||
}, 'Quantities': {'Qto_ColumnBaseQuantities': {'id': 'M_40', 'Length': 3000, 'GrossVolumn': 0.27
|
||||
}
|
||||
}, 'Property Sets': {'Pset_ColumnCommon': {'Reference': 'M_40', 'IsExternal': 'True', 'LoadBearing': 'False'
|
||||
}
|
||||
}, 'Building Storey': 'Level2', 'Element Type Property Sets': {'Pset_ColumnCommon': {'IsExternal': 'True'
|
||||
}
|
||||
}
|
||||
}, 'definitionId': 'f480a3ac-572e-45d6-b92c-3fe2d88ff609', 'speckle_type': 'Speckle.Core.Models.Instances.InstanceProxy', 'applicationId': '0212fc75-9106-4932-b695-66bafb41a791'
|
||||
},
|
||||
{'id': 'c8811f6522b169f1993f78a1b79e354f', 'name': '', 'units': 'cm', 'maxDepth': 0, 'transform': [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1600,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
800,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
6000,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
], 'properties': {'Attributes': {'id': '2341', 'Tag': '414482', 'Name': 'M_Concrete-Sq-Column', 'type': 'IfcColumn', 'GlobalId': '3lIj7B0LnBjf0mvxk2zuuc', 'ObjectType': 'Square-C40'
|
||||
}, 'Quantities': {'Qto_ColumnBaseQuantities': {'id': 'M_40', 'Length': 3000, 'GrossVolumn': 0.27
|
||||
}
|
||||
}, 'Property Sets': {'Pset_ColumnCommon': {'Reference': 'M_40', 'IsExternal': 'True', 'LoadBearing': 'False'
|
||||
}
|
||||
}, 'Building Storey': 'Level2', 'Element Type Property Sets': {'Pset_ColumnCommon': {'IsExternal': 'True'
|
||||
}
|
||||
}
|
||||
}, 'definitionId': 'f480a3ac-572e-45d6-b92c-3fe2d88ff609', 'speckle_type': 'Speckle.Core.Models.Instances.InstanceProxy', 'applicationId': '7b0f464b-9077-462f-8c19-f9bd73beeb55'
|
||||
},
|
||||
{'id': 'eb574c7da4393c988c49bf09c92ce8b8', 'name': '', 'units': 'cm', 'maxDepth': 0, 'transform': [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
800,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
800,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
3000,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
], 'properties': {'Attributes': {'id': '2341', 'Tag': '414482', 'Name': 'M_Concrete-Sq-Column', 'type': 'IfcColumn', 'GlobalId': '3lIj7B0LnBjf0mvxk2zuuc', 'ObjectType': 'Square-C40'
|
||||
}, 'Quantities': {'Qto_ColumnBaseQuantities': {'id': 'M_40', 'Length': 3000, 'GrossVolumn': 0.27
|
||||
}
|
||||
}, 'Property Sets': {'Pset_ColumnCommon': {'Reference': 'M_40', 'IsExternal': 'True', 'LoadBearing': 'False'
|
||||
}
|
||||
}, 'Building Storey': 'Level1', 'Element Type Property Sets': {'Pset_ColumnCommon': {'IsExternal': 'True'
|
||||
}
|
||||
}
|
||||
}, 'definitionId': 'f480a3ac-572e-45d6-b92c-3fe2d88ff609', 'speckle_type': 'Speckle.Core.Models.Instances.InstanceProxy', 'applicationId': '8db8e229-ea79-42e6-8b95-5c97ef673444'
|
||||
},
|
||||
{'id': 'f5263a6bf3d83aafffa4af92fafdd00d', 'name': '', 'units': 'cm', 'maxDepth': 0, 'transform': [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
1600,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
], 'properties': {'Attributes': {'id': '2341', 'Tag': '414482', 'Name': 'M_Concrete-Sq-Column', 'type': 'IfcColumn', 'GlobalId': '3lIj7B0LnBjf0mvxk2zuuc', 'ObjectType': 'Square-C40'
|
||||
}, 'Quantities': {'Qto_ColumnBaseQuantities': {'id': 'M_40', 'Length': 3000, 'GrossVolumn': 0.27
|
||||
}
|
||||
}, 'Property Sets': {'Pset_ColumnCommon': {'Reference': 'M_40', 'IsExternal': 'True', 'LoadBearing': 'False'
|
||||
}
|
||||
}, 'Building Storey': 'Level0', 'Element Type Property Sets': {'Pset_ColumnCommon': {'IsExternal': 'True'
|
||||
}
|
||||
}
|
||||
}, 'definitionId': 'f480a3ac-572e-45d6-b92c-3fe2d88ff609', 'speckle_type': 'Speckle.Core.Models.Instances.InstanceProxy', 'applicationId': '48984c1b-c587-47cd-b53d-224a764db435'
|
||||
}
|
||||
]
|
||||
+357
@@ -0,0 +1,357 @@
|
||||
# =============================================================================
|
||||
# curves.py
|
||||
# Converts Speckle 2D curve geometry (Polycurve, Line, Arc, Circle, Polyline)
|
||||
# into IFC IfcIndexedPolyCurve representations.
|
||||
#
|
||||
# Curve types in segments:
|
||||
# - Objects.Geometry.Line → start/end Points → IfcLineIndex
|
||||
# - Objects.Geometry.Arc → startPoint/midPoint/endPoint → IfcArcIndex
|
||||
# - Objects.Geometry.Circle → converted to arc segments
|
||||
# - Objects.Geometry.Polyline → point sequence → IfcLineIndex chains
|
||||
#
|
||||
# The result is an IfcIndexedPolyCurve with IfcCartesianPointList3D.
|
||||
# =============================================================================
|
||||
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
from specklepy.objects.base import Base
|
||||
from utils.helpers import _get, MM_SCALES
|
||||
from utils.geometry import _get_shared, _make_placement
|
||||
|
||||
|
||||
# Speckle types that are curve geometry
|
||||
_CURVE_TYPES = {"Line", "Arc", "Circle", "Ellipse", "Polycurve", "Polyline", "Curve"}
|
||||
|
||||
|
||||
def is_curve(obj) -> bool:
|
||||
"""Return True if this object is a Speckle curve type."""
|
||||
speckle_type = _get(obj, "speckle_type") or ""
|
||||
return any(ct in speckle_type for ct in _CURVE_TYPES)
|
||||
|
||||
|
||||
def _resolve_scale(obj, fallback: float) -> float:
|
||||
"""Resolve unit scale for a curve object."""
|
||||
units = _get(obj, "units")
|
||||
if units and isinstance(units, str):
|
||||
return MM_SCALES.get(units.lower().strip(), fallback)
|
||||
return fallback
|
||||
|
||||
|
||||
def _point_coords(pt, scale: float) -> tuple:
|
||||
"""Extract (x, y, z) from a Speckle Point, scaled to mm."""
|
||||
x = float(_get(pt, "x") or 0) * scale
|
||||
y = float(_get(pt, "y") or 0) * scale
|
||||
z = float(_get(pt, "z") or 0) * scale
|
||||
return x, y, z
|
||||
|
||||
|
||||
def _extract_polycurve(obj, scale: float) -> tuple:
|
||||
"""
|
||||
Extract points and segment indices from a Polycurve.
|
||||
|
||||
Returns (points_3d, segments) where:
|
||||
points_3d: list of [x, y, z] coordinate lists
|
||||
segments: list of IfcLineIndex/IfcArcIndex-compatible tuples
|
||||
("line", [i, j]) or ("arc", [i, mid, j]) (1-based)
|
||||
"""
|
||||
segments_raw = _get(obj, "segments") or []
|
||||
if not isinstance(segments_raw, list):
|
||||
segments_raw = list(segments_raw)
|
||||
if not segments_raw:
|
||||
return [], []
|
||||
|
||||
obj_scale = _resolve_scale(obj, scale)
|
||||
points = [] # list of [x, y, z]
|
||||
point_map = {} # (rounded_x, rounded_y, rounded_z) → 1-based index
|
||||
ifc_segments = []
|
||||
|
||||
def _add_point(pt, seg_scale: float) -> int:
|
||||
"""Add a point and return its 1-based index (deduplicating nearby points)."""
|
||||
x, y, z = _point_coords(pt, seg_scale)
|
||||
# Snap to 0.01mm grid for deduplication
|
||||
key = (round(x * 100), round(y * 100), round(z * 100))
|
||||
if key in point_map:
|
||||
return point_map[key]
|
||||
idx = len(points) + 1 # 1-based for IFC
|
||||
points.append([x, y, z])
|
||||
point_map[key] = idx
|
||||
return idx
|
||||
|
||||
for seg in segments_raw:
|
||||
if seg is None:
|
||||
continue
|
||||
seg_type = (_get(seg, "speckle_type") or "").split(".")[-1]
|
||||
seg_scale = _resolve_scale(seg, obj_scale)
|
||||
|
||||
if seg_type == "Line":
|
||||
start_pt = _get(seg, "start")
|
||||
end_pt = _get(seg, "end")
|
||||
if start_pt is None or end_pt is None:
|
||||
continue
|
||||
i = _add_point(start_pt, seg_scale)
|
||||
j = _add_point(end_pt, seg_scale)
|
||||
if i != j:
|
||||
ifc_segments.append(("line", [i, j]))
|
||||
|
||||
elif seg_type == "Arc":
|
||||
start_pt = _get(seg, "startPoint")
|
||||
mid_pt = _get(seg, "midPoint")
|
||||
end_pt = _get(seg, "endPoint")
|
||||
if start_pt is None or mid_pt is None or end_pt is None:
|
||||
continue
|
||||
i = _add_point(start_pt, seg_scale)
|
||||
m = _add_point(mid_pt, seg_scale)
|
||||
j = _add_point(end_pt, seg_scale)
|
||||
if i != j and i != m and m != j:
|
||||
ifc_segments.append(("arc", [i, m, j]))
|
||||
|
||||
elif seg_type == "Polyline":
|
||||
raw_value = _get(seg, "value") or []
|
||||
if not raw_value:
|
||||
continue
|
||||
values = list(raw_value) if not isinstance(raw_value, list) else raw_value
|
||||
indices = []
|
||||
for vi in range(0, len(values) - 2, 3):
|
||||
x = float(values[vi]) * seg_scale
|
||||
y = float(values[vi + 1]) * seg_scale
|
||||
z = float(values[vi + 2]) * seg_scale
|
||||
key = (round(x * 100), round(y * 100), round(z * 100))
|
||||
if key in point_map:
|
||||
idx = point_map[key]
|
||||
else:
|
||||
idx = len(points) + 1
|
||||
points.append([x, y, z])
|
||||
point_map[key] = idx
|
||||
indices.append(idx)
|
||||
if len(indices) >= 2:
|
||||
ifc_segments.append(("line", indices))
|
||||
|
||||
return points, ifc_segments
|
||||
|
||||
|
||||
def _extract_single_line(obj, scale: float) -> tuple:
|
||||
"""Extract a single Line as points + segment."""
|
||||
obj_scale = _resolve_scale(obj, scale)
|
||||
start_pt = _get(obj, "start")
|
||||
end_pt = _get(obj, "end")
|
||||
if start_pt is None or end_pt is None:
|
||||
return [], []
|
||||
sx, sy, sz = _point_coords(start_pt, obj_scale)
|
||||
ex, ey, ez = _point_coords(end_pt, obj_scale)
|
||||
return [[sx, sy, sz], [ex, ey, ez]], [("line", [1, 2])]
|
||||
|
||||
|
||||
def _extract_single_arc(obj, scale: float) -> tuple:
|
||||
"""Extract a single Arc as points + segment."""
|
||||
obj_scale = _resolve_scale(obj, scale)
|
||||
start_pt = _get(obj, "startPoint")
|
||||
mid_pt = _get(obj, "midPoint")
|
||||
end_pt = _get(obj, "endPoint")
|
||||
if start_pt is None or mid_pt is None or end_pt is None:
|
||||
return [], []
|
||||
sx, sy, sz = _point_coords(start_pt, obj_scale)
|
||||
mx, my, mz = _point_coords(mid_pt, obj_scale)
|
||||
ex, ey, ez = _point_coords(end_pt, obj_scale)
|
||||
return [[sx, sy, sz], [mx, my, mz], [ex, ey, ez]], [("arc", [1, 2, 3])]
|
||||
|
||||
|
||||
def extract_curve_data(obj, scale: float = 1.0) -> tuple:
|
||||
"""
|
||||
Extract curve points and segments from any supported curve type.
|
||||
Returns (points_3d, segments) or ([], []) if not a curve.
|
||||
"""
|
||||
speckle_type = (_get(obj, "speckle_type") or "").split(".")[-1]
|
||||
|
||||
if speckle_type == "Polycurve":
|
||||
return _extract_polycurve(obj, scale)
|
||||
elif speckle_type == "Line":
|
||||
return _extract_single_line(obj, scale)
|
||||
elif speckle_type == "Arc":
|
||||
return _extract_single_arc(obj, scale)
|
||||
return [], []
|
||||
|
||||
|
||||
def build_ifc_curve(ifc, points: list, segments: list):
|
||||
"""
|
||||
Build an IfcIndexedPolyCurve from points and segment descriptors.
|
||||
|
||||
points: list of [x, y, z] coordinates
|
||||
segments: list of ("line", [indices]) or ("arc", [indices])
|
||||
|
||||
Returns IfcIndexedPolyCurve or None.
|
||||
"""
|
||||
if not points or not segments:
|
||||
return None
|
||||
|
||||
point_list = ifc.createIfcCartesianPointList3D(points)
|
||||
|
||||
ifc_segments = []
|
||||
for seg_type, indices in segments:
|
||||
if seg_type == "arc":
|
||||
ifc_segments.append(ifc.create_entity("IfcArcIndex", indices))
|
||||
else:
|
||||
ifc_segments.append(ifc.create_entity("IfcLineIndex", indices))
|
||||
|
||||
if not ifc_segments:
|
||||
return None
|
||||
|
||||
return ifc.createIfcIndexedPolyCurve(
|
||||
Points=point_list,
|
||||
Segments=ifc_segments,
|
||||
SelfIntersect=False,
|
||||
)
|
||||
|
||||
|
||||
def get_display_curves(obj) -> list:
|
||||
"""
|
||||
Collect curve objects from an object's displayValue, or the object itself.
|
||||
Returns a list of curve objects (Polycurve, Line, Arc, etc.).
|
||||
"""
|
||||
curves = []
|
||||
for key in ["displayValue", "@displayValue", "_displayValue"]:
|
||||
display = _get(obj, key)
|
||||
if display is None:
|
||||
continue
|
||||
items = display if isinstance(display, list) else [display]
|
||||
for item in items:
|
||||
if item is not None and is_curve(item):
|
||||
curves.append(item)
|
||||
if curves:
|
||||
break
|
||||
|
||||
# Fallback: the object itself is a curve
|
||||
if not curves and is_curve(obj):
|
||||
curves.append(obj)
|
||||
|
||||
return curves
|
||||
|
||||
|
||||
def curve_to_ifc(
|
||||
ifc: ifcopenshell.file,
|
||||
body_context,
|
||||
obj: Base,
|
||||
scale: float = 1.0,
|
||||
material_manager=None,
|
||||
) -> tuple:
|
||||
"""
|
||||
Convert a Speckle object with curve geometry → (IfcShapeRepresentation, IfcLocalPlacement).
|
||||
Looks for curves in displayValue first, then checks the object itself.
|
||||
Creates one IfcIndexedPolyCurve per curve item.
|
||||
Returns (None, None) if no usable curve geometry.
|
||||
"""
|
||||
curves = get_display_curves(obj)
|
||||
if not curves:
|
||||
return None, None
|
||||
|
||||
obj_app_id = _get(obj, "applicationId")
|
||||
obj_scale = _resolve_scale(obj, scale)
|
||||
|
||||
# Collect curve data and compute origin incrementally (no all_points accumulation)
|
||||
curve_cache = [] # list of (points, segments) or None
|
||||
xmin = ymin = zmin = float("inf")
|
||||
xmax = ymax = float("-inf")
|
||||
has_points = False
|
||||
|
||||
for curve_obj in curves:
|
||||
points, segments = extract_curve_data(curve_obj, obj_scale)
|
||||
if points and segments:
|
||||
curve_cache.append((points, segments))
|
||||
has_points = True
|
||||
for p in points:
|
||||
x, y, z = p[0], p[1], p[2]
|
||||
if x < xmin: xmin = x
|
||||
if x > xmax: xmax = x
|
||||
if y < ymin: ymin = y
|
||||
if y > ymax: ymax = y
|
||||
if z < zmin: zmin = z
|
||||
else:
|
||||
curve_cache.append(None)
|
||||
|
||||
if not has_points:
|
||||
return None, None
|
||||
|
||||
ox = (xmin + xmax) / 2.0
|
||||
oy = (ymin + ymax) / 2.0
|
||||
oz = zmin
|
||||
|
||||
# Build IFC curve entities
|
||||
geom_items = []
|
||||
for i, cached in enumerate(curve_cache):
|
||||
if cached is None:
|
||||
continue
|
||||
points, segments = cached
|
||||
|
||||
offset_points = [
|
||||
[p[0] - ox, p[1] - oy, p[2] - oz] for p in points
|
||||
]
|
||||
|
||||
curve_entity = build_ifc_curve(ifc, offset_points, segments)
|
||||
if curve_entity is None:
|
||||
continue
|
||||
|
||||
# Apply material
|
||||
if material_manager:
|
||||
curve_app_id = _get(curves[i], "applicationId") or obj_app_id
|
||||
if curve_app_id:
|
||||
material_manager.apply_to_item(curve_entity, str(curve_app_id))
|
||||
|
||||
geom_items.append(curve_entity)
|
||||
|
||||
if not geom_items:
|
||||
return None, None
|
||||
|
||||
rep = ifc.createIfcShapeRepresentation(
|
||||
ContextOfItems=body_context,
|
||||
RepresentationIdentifier="Body",
|
||||
RepresentationType="Curve3D",
|
||||
Items=geom_items,
|
||||
)
|
||||
placement = _make_placement(ifc, ox, oy, oz)
|
||||
return rep, placement
|
||||
|
||||
|
||||
def build_curve_rep_map(ifc, body_context, obj, scale: float = 1.0,
|
||||
material_manager=None, fallback_app_ids: list = None,
|
||||
definition_id: str = None):
|
||||
"""
|
||||
Build an IfcRepresentationMap from a curve definition object.
|
||||
Used for instance-based curve geometry (shared across instances).
|
||||
Returns IfcRepresentationMap or None.
|
||||
"""
|
||||
points, segments = extract_curve_data(obj, scale)
|
||||
if not points or not segments:
|
||||
return None
|
||||
|
||||
curve_entity = build_ifc_curve(ifc, points, segments)
|
||||
if curve_entity is None:
|
||||
return None
|
||||
|
||||
# Apply material (3-tier: object app_id → fallbacks → definition)
|
||||
if material_manager:
|
||||
app_id = _get(obj, "applicationId")
|
||||
style = material_manager.get_style_with_fallbacks(
|
||||
primary_app_id=str(app_id) if app_id else None,
|
||||
fallback_app_ids=fallback_app_ids,
|
||||
definition_id=definition_id,
|
||||
)
|
||||
if style:
|
||||
try:
|
||||
ifcopenshell.api.run(
|
||||
"style.assign_item_style", ifc,
|
||||
item=curve_entity, style=style,
|
||||
)
|
||||
material_manager._apply_count += 1
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
shared = _get_shared(ifc)
|
||||
a2p = ifc.createIfcAxis2Placement3D(shared["origin_0"], None, None)
|
||||
|
||||
mapped_rep = ifc.createIfcShapeRepresentation(
|
||||
ContextOfItems=body_context,
|
||||
RepresentationIdentifier="Body",
|
||||
RepresentationType="Curve3D",
|
||||
Items=[curve_entity],
|
||||
)
|
||||
|
||||
return ifc.createIfcRepresentationMap(a2p, mapped_rep)
|
||||
+4
-5
@@ -348,7 +348,7 @@ def mesh_to_ifc(
|
||||
# Pass 1: unpack and scale vertices once per mesh, compute origin
|
||||
# incrementally without accumulating all vertices in memory.
|
||||
# ------------------------------------------------------------------ #
|
||||
mesh_cache = [] # [(verts_list, ms, scaled)] or None per mesh
|
||||
mesh_cache = [] # [scaled_verts_list] or None per mesh
|
||||
xmin = ymin = zmin = float("inf")
|
||||
xmax = ymax = float("-inf")
|
||||
has_verts = False
|
||||
@@ -361,7 +361,7 @@ def mesh_to_ifc(
|
||||
continue
|
||||
ms = _resolve_scale(mesh, obj_scale)
|
||||
scaled = [float(v) * ms for v in verts]
|
||||
mesh_cache.append((verts, ms, scaled))
|
||||
mesh_cache.append(scaled)
|
||||
has_verts = True
|
||||
|
||||
# Update bounding box from this mesh's scaled vertices
|
||||
@@ -385,10 +385,9 @@ def mesh_to_ifc(
|
||||
# ------------------------------------------------------------------ #
|
||||
geom_items = []
|
||||
|
||||
for mesh, cached in zip(meshes, mesh_cache):
|
||||
if cached is None:
|
||||
for mesh, scaled in zip(meshes, mesh_cache):
|
||||
if scaled is None:
|
||||
continue
|
||||
verts, ms, scaled = cached
|
||||
raw_faces = _get(mesh, "faces") or []
|
||||
faces_raw = unwrap_chunks(raw_faces if isinstance(raw_faces, list) else list(raw_faces))
|
||||
|
||||
|
||||
+50
-39
@@ -24,7 +24,8 @@ import math
|
||||
import ifcopenshell.api
|
||||
from specklepy.objects.base import Base
|
||||
from utils.helpers import _get, MM_SCALES
|
||||
from utils.geometry import unwrap_chunks, decode_faces, build_ifc_facesets, _get_shared
|
||||
from utils.geometry import unwrap_chunks, decode_faces, build_ifc_facesets, _get_shared, _is_mesh
|
||||
from utils.curves import is_curve, build_curve_rep_map
|
||||
|
||||
|
||||
def is_instance(obj) -> bool:
|
||||
@@ -129,6 +130,21 @@ def _collect_all(obj, by_id: dict, by_app_id: dict, depth: int):
|
||||
continue
|
||||
|
||||
|
||||
def _get_definition_source_object(definition_id: str, definition_map: dict):
|
||||
"""Resolve the first source object referenced by a definition proxy."""
|
||||
ifc_proxies = definition_map.get("ifc_proxies", {})
|
||||
proxy = ifc_proxies.get(definition_id) or ifc_proxies.get(definition_id.lower())
|
||||
if proxy is None:
|
||||
return None
|
||||
object_ids = _get(proxy, "objects") or []
|
||||
if not isinstance(object_ids, list):
|
||||
object_ids = list(object_ids)
|
||||
if not object_ids:
|
||||
return None
|
||||
by_app_id = definition_map.get("by_app_id", {})
|
||||
return by_app_id.get(str(object_ids[0]).lower())
|
||||
|
||||
|
||||
def _get_revit_meshes(definition_id: str, definition_map: dict) -> tuple:
|
||||
"""
|
||||
Revit format:
|
||||
@@ -176,8 +192,8 @@ def _get_revit_meshes(definition_id: str, definition_map: dict) -> tuple:
|
||||
found_meshes = get_display_meshes(obj)
|
||||
if found_meshes:
|
||||
meshes.extend(found_meshes)
|
||||
else:
|
||||
# It IS the mesh directly
|
||||
elif _is_mesh(obj):
|
||||
# Object itself is a mesh (no displayValue wrapping)
|
||||
meshes.append(obj)
|
||||
return meshes, encountered_app_ids
|
||||
|
||||
@@ -287,16 +303,11 @@ def _build_rep_map(ifc, body_context, meshes: list, ifc_format: bool,
|
||||
# Try: mesh applicationId → fallback IDs → definitionId mapping
|
||||
if material_manager:
|
||||
mesh_app_id = _get(mesh, "applicationId")
|
||||
style = None
|
||||
if mesh_app_id:
|
||||
style = material_manager.get_style(str(mesh_app_id))
|
||||
if not style and fallback_app_ids:
|
||||
for fid in fallback_app_ids:
|
||||
style = material_manager.get_style(fid)
|
||||
if style:
|
||||
break
|
||||
if not style and definition_id:
|
||||
style = material_manager.get_style_by_definition(definition_id)
|
||||
style = material_manager.get_style_with_fallbacks(
|
||||
primary_app_id=str(mesh_app_id) if mesh_app_id else None,
|
||||
fallback_app_ids=fallback_app_ids,
|
||||
definition_id=definition_id,
|
||||
)
|
||||
if style:
|
||||
for fs in mesh_facesets:
|
||||
try:
|
||||
@@ -433,12 +444,6 @@ def instance_to_ifc(ifc, body_context, obj: Base, definition_map: dict,
|
||||
else:
|
||||
meshes, extra_app_ids = _get_revit_meshes(definition_id, definition_map)
|
||||
|
||||
if not meshes:
|
||||
_stats["not_found"] += 1
|
||||
_rep_map_cache[definition_id] = None
|
||||
return None, placement
|
||||
|
||||
_stats["found"] += 1
|
||||
# Build fallback app_id list: instance's own + definition chain IDs
|
||||
instance_app_id = _get(obj, "applicationId")
|
||||
fallback_ids = []
|
||||
@@ -446,11 +451,31 @@ def instance_to_ifc(ifc, body_context, obj: Base, definition_map: dict,
|
||||
fallback_ids.append(str(instance_app_id))
|
||||
fallback_ids.extend(extra_app_ids)
|
||||
|
||||
_rep_map_cache[definition_id] = _build_rep_map(
|
||||
ifc, body_context, meshes, ifc_format, material_manager,
|
||||
fallback_app_ids=fallback_ids,
|
||||
definition_id=definition_id,
|
||||
)
|
||||
rep_map_result = None
|
||||
if meshes:
|
||||
rep_map_result = _build_rep_map(
|
||||
ifc, body_context, meshes, ifc_format, material_manager,
|
||||
fallback_app_ids=fallback_ids,
|
||||
definition_id=definition_id,
|
||||
)
|
||||
|
||||
# If no mesh geometry produced, try curve geometry from the definition object
|
||||
if rep_map_result is None:
|
||||
curve_obj = _get_definition_source_object(definition_id, definition_map)
|
||||
if curve_obj and is_curve(curve_obj):
|
||||
curve_scale = _resolve_instance_scale(curve_obj, 1.0)
|
||||
rep_map_result = build_curve_rep_map(
|
||||
ifc, body_context, curve_obj, scale=curve_scale,
|
||||
material_manager=material_manager,
|
||||
fallback_app_ids=fallback_ids,
|
||||
definition_id=definition_id,
|
||||
)
|
||||
|
||||
_rep_map_cache[definition_id] = rep_map_result
|
||||
if rep_map_result is not None:
|
||||
_stats["found"] += 1
|
||||
else:
|
||||
_stats["not_found"] += 1
|
||||
else:
|
||||
# Track stats even for cached definitions
|
||||
if _rep_map_cache[definition_id] is not None:
|
||||
@@ -488,21 +513,7 @@ def get_definition_object(obj: Base, definition_map: dict):
|
||||
definition_id = _get(obj, "definitionId") or ""
|
||||
if not definition_id:
|
||||
return None
|
||||
|
||||
ifc_proxies = definition_map.get("ifc_proxies", {})
|
||||
proxy = ifc_proxies.get(definition_id) or ifc_proxies.get(definition_id.lower())
|
||||
if proxy is None:
|
||||
return None
|
||||
|
||||
object_ids = _get(proxy, "objects") or []
|
||||
if not isinstance(object_ids, list):
|
||||
object_ids = list(object_ids)
|
||||
if not object_ids:
|
||||
return None
|
||||
|
||||
by_app_id = definition_map.get("by_app_id", {})
|
||||
source = by_app_id.get(str(object_ids[0]).lower())
|
||||
return source
|
||||
return _get_definition_source_object(definition_id, definition_map)
|
||||
|
||||
|
||||
def is_definition_source(obj, definition_map: dict) -> bool:
|
||||
|
||||
@@ -122,6 +122,22 @@ class MaterialManager:
|
||||
self._style_map[key] = style
|
||||
return style
|
||||
|
||||
def get_style_with_fallbacks(self, primary_app_id: str = None,
|
||||
fallback_app_ids: list = None,
|
||||
definition_id: str = None):
|
||||
"""3-tier style lookup: primary → fallbacks → definition mapping."""
|
||||
style = None
|
||||
if primary_app_id:
|
||||
style = self.get_style(primary_app_id)
|
||||
if not style and fallback_app_ids:
|
||||
for fid in fallback_app_ids:
|
||||
style = self.get_style(fid)
|
||||
if style:
|
||||
break
|
||||
if not style and definition_id:
|
||||
style = self.get_style_by_definition(definition_id)
|
||||
return style
|
||||
|
||||
def apply_to_item(self, item, mesh_app_id: str):
|
||||
"""Assign the material style to a single IFC geometry item (e.g. IfcPolygonalFaceSet)."""
|
||||
style = self.get_style(mesh_app_id)
|
||||
|
||||
Reference in New Issue
Block a user