///|
fn number_from_value(value : Value) -> Double? {
value.as_double()
}
///|
fn optional_double(value : Value?) -> Double? {
match value {
Some(item) => number_from_value(item)
None => None
}
}
///|
fn coordinates_from_value(value : Value) -> Array[Double] {
match value {
List(values) =>
values.fold(init=Array::new(), (result, item) => {
match number_from_value(item) {
Some(number) => {
result.push(number)
result
}
None => result
}
})
Typed(name~, value~) => {
ignore(name)
coordinates_from_value(value)
}
_ => []
}
}
///|
fn point_from_coordinates(values : Array[Double]) -> Point3 {
{
x: values.get(0).unwrap_or(0.0),
y: values.get(1).unwrap_or(0.0),
z: values.get(2).unwrap_or(0.0),
}
}
///|
fn point_from_entity(index : ModelIndex, id : Int) -> Point3? {
match index.entity(id) {
Some(entity) if entity.name.to_upper() == "IFCCARTESIANPOINT" =>
match entity_value(entity, 0) {
Some(value) =>
Some(point_from_coordinates(coordinates_from_value(value)))
None => None
}
_ => None
}
}
///|
fn points_from_entity(index : ModelIndex, entity : Entity) -> Array[Point3] {
let upper = entity.name.to_upper()
if upper == "IFCCARTESIANPOINT" {
match entity_value(entity, 0) {
Some(value) => [point_from_coordinates(coordinates_from_value(value))]
None => []
}
} else if upper == "IFCCARTESIANPOINTLIST3D" ||
upper == "IFCCARTESIANPOINTLIST2D" {
match entity_value(entity, 0) {
Some(List(rows)) =>
rows.fold(init=Array::new(), (result, row) => {
result.push(point_from_coordinates(coordinates_from_value(row)))
result
})
_ => []
}
} else if upper == "IFCPOLYLINE" {
match entity_value(entity, 0) {
Some(value) =>
references(value).fold(init=Array::new(), (result, id) => {
match point_from_entity(index, id) {
Some(point) => {
result.push(point)
result
}
None => result
}
})
None => []
}
} else {
[]
}
}
///|
fn polygon_count(value : Value) -> Int {
match value {
List(values) =>
values.fold(init=0, (count, item) => count + polygon_count(item))
_ => 1
}
}
///|
fn geometry_for_entity(index : ModelIndex, entity : Entity) -> Geometry {
let upper = entity.name.to_upper()
if upper == "IFCEXTRUDEDAREASOLID" {
let profile_id = optional_reference_argument(entity, 0)
let profile = match profile_id {
Some(id) => index.entity(id)
None => None
}
let profile_width = match profile {
Some(profile_entity) if profile_entity.name.to_upper() ==
"IFCRECTANGLEPROFILEDEF" =>
optional_double(entity_value(profile_entity, 3))
_ => None
}
let profile_height = match profile {
Some(profile_entity) if profile_entity.name.to_upper() ==
"IFCRECTANGLEPROFILEDEF" =>
optional_double(entity_value(profile_entity, 4))
_ => None
}
{
source_id: entity.id,
kind: Extrusion,
points: match profile {
Some(profile_entity) => points_from_entity(index, profile_entity)
None => []
},
references: entity_references(entity),
depth: optional_double(entity_value(entity, 3)),
profile_width,
profile_height,
profile_radius: None,
face_count: 0,
triangle_count: 0,
}
} else if upper == "IFCFACETEDBREP" || upper == "IFCMANIFOLDSOLIDBREP" {
let outer = optional_reference_argument(entity, 0)
let face_count = match outer {
Some(outer_id) =>
match index.entity(outer_id) {
Some(shell) =>
match entity_value(shell, 0) {
Some(value) => references(value).length()
None => 0
}
None => 0
}
None => 0
}
{
source_id: entity.id,
kind: FacetedBrep,
points: [],
references: entity_references(entity),
depth: None,
profile_width: None,
profile_height: None,
profile_radius: None,
face_count,
triangle_count: 0,
}
} else if upper == "IFCTRIANGULATEDFACESET" || upper == "IFCPOLYGONALFACESET" {
let coordinate_ref = optional_reference_argument(entity, 0)
let points = match coordinate_ref {
Some(id) =>
match index.entity(id) {
Some(coordinates) => points_from_entity(index, coordinates)
None => []
}
None => []
}
let triangle_count = match entity_value(entity, 2) {
Some(value) => polygon_count(value) / 3
None => 0
}
{
source_id: entity.id,
kind: TriangulatedMesh,
points,
references: entity_references(entity),
depth: None,
profile_width: None,
profile_height: None,
profile_radius: None,
face_count: 0,
triangle_count,
}
} else if upper == "IFCCSGSOLID" || upper == "IFCBOOLEANCLIPPINGRESULT" {
{
source_id: entity.id,
kind: CsgSolid,
points: [],
references: entity_references(entity),
depth: None,
profile_width: None,
profile_height: None,
profile_radius: None,
face_count: 0,
triangle_count: 0,
}
} else if upper == "IFCRECTANGLEPROFILEDEF" {
{
source_id: entity.id,
kind: Profile,
points: [],
references: entity_references(entity),
depth: None,
profile_width: optional_double(entity_value(entity, 3)),
profile_height: optional_double(entity_value(entity, 4)),
profile_radius: None,
face_count: 0,
triangle_count: 0,
}
} else if upper == "IFCCIRCLEPROFILEDEF" {
{
source_id: entity.id,
kind: Profile,
points: [],
references: entity_references(entity),
depth: None,
profile_width: None,
profile_height: None,
profile_radius: optional_double(entity_value(entity, 3)),
face_count: 0,
triangle_count: 0,
}
} else if upper == "IFCPOLYLINE" {
{
source_id: entity.id,
kind: Polyline,
points: points_from_entity(index, entity),
references: entity_references(entity),
depth: None,
profile_width: None,
profile_height: None,
profile_radius: None,
face_count: 0,
triangle_count: 0,
}
} else if upper == "IFCCARTESIANPOINT" || upper == "IFCCARTESIANPOINTLIST3D" {
{
source_id: entity.id,
kind: PointCloud,
points: points_from_entity(index, entity),
references: entity_references(entity),
depth: None,
profile_width: None,
profile_height: None,
profile_radius: None,
face_count: 0,
triangle_count: 0,
}
} else {
{
source_id: entity.id,
kind: Unknown,
points: [],
references: entity_references(entity),
depth: None,
profile_width: None,
profile_height: None,
profile_radius: None,
face_count: 0,
triangle_count: 0,
}
}
}
///|
pub fn geometry(index : ModelIndex, id : Int) -> Geometry raise ParseError {
let entity = index.require(id)
geometry_for_entity(index, entity)
}
///|
fn representation_items(
index : ModelIndex,
representation_id : Int,
) -> Array[Int] {
match index.entity(representation_id) {
Some(shape) if shape.name.to_upper() == "IFCPRODUCTDEFINITIONSHAPE" =>
match entity_value(shape, 2) {
Some(value) =>
references(value).fold(init=Array::new(), (result, shape_id) => {
for item_id in representation_items(index, shape_id) {
result.push(item_id)
}
result
})
None => []
}
Some(shape) if shape.name.to_upper() == "IFCSHAPEREPRESENTATION" =>
reference_list(entity_value(shape, 3))
_ => [representation_id]
}
}
///|
pub fn geometries_for_product(
index : ModelIndex,
product : Product,
) -> Array[Geometry] {
match product.representation {
Some(representation_id) =>
representation_items(index, representation_id).fold(init=Array::new(), (
result,
id,
) => {
match index.entity(id) {
Some(entity) => result.push(geometry_for_entity(index, entity))
None => ()
}
result
})
None => []
}
}
///|
pub fn geometry_for_product(index : ModelIndex, product : Product) -> Geometry? {
geometries_for_product(index, product).get(0)
}
///|
pub fn geometry_entities(index : ModelIndex) -> Array[Entity] {
index
.all()
.filter(entity => {
let upper = entity.name.to_upper()
upper == "IFCEXTRUDEDAREASOLID" ||
upper == "IFCFACETEDBREP" ||
upper == "IFCTRIANGULATEDFACESET" ||
upper == "IFCPOLYGONALFACESET" ||
upper == "IFCCSGSOLID" ||
upper == "IFCBOOLEANCLIPPINGRESULT"
})
}