///|
fn integer_value(value : Value) -> Int? {
value.as_int()
}
///|
fn indices_from_value(value : Value) -> Array[Int] {
match value {
List(values) =>
values.fold(init=Array::new(), (result, item) => {
match integer_value(item) {
Some(index) => {
result.push(index)
result
}
None => {
for nested in indices_from_value(item) {
result.push(nested)
}
result
}
}
})
Typed(name~, value~) => {
ignore(name)
indices_from_value(value)
}
_ => []
}
}
///|
fn triangle_array(indices : Array[Int]) -> Array[(Int, Int, Int)] {
let triangles : Array[(Int, Int, Int)] = []
let mut i = 0
while i + 2 < indices.length() {
let a = indices[i] - 1
let b = indices[i + 1] - 1
let c = indices[i + 2] - 1
if a >= 0 && b >= 0 && c >= 0 {
triangles.push((a, b, c))
}
i += 3
}
triangles
}
///|
fn polygon_points(index : ModelIndex, loop_id : Int) -> Array[Point3] {
match index.entity(loop_id) {
Some(loop_entity) if loop_entity.name.to_upper() == "IFCPOLYLOOP" =>
reference_list(entity_value(loop_entity, 0)).fold(init=Array::new(), (
result,
point_id,
) => {
match point_from_entity(index, point_id) {
Some(point) => {
result.push(point)
result
}
None => result
}
})
_ => []
}
}
///|
fn add_fan_triangles(points : Array[Point3], mesh : Mesh) -> Unit {
if points.length() >= 3 {
let mut i = 1
while i + 1 < points.length() {
let offset = mesh.points.length()
mesh.points.append(points)
mesh.triangles.push((offset, offset + i, offset + i + 1))
i += 1
}
}
}
///|
fn faceted_brep_mesh(index : ModelIndex, entity : Entity) -> Mesh {
let mesh : Mesh = { points: [], triangles: [] }
let outer_id = optional_reference_argument(entity, 0)
match outer_id {
Some(shell_id) =>
match index.entity(shell_id) {
Some(shell) =>
for face_id in reference_list(entity_value(shell, 0)) {
match index.entity(face_id) {
Some(face) => {
let bound_id = optional_reference_argument(face, 0)
match bound_id {
Some(bound_id) =>
match index.entity(bound_id) {
Some(bound) => {
let loop_id = optional_reference_argument(bound, 1)
match loop_id {
Some(id) =>
add_fan_triangles(polygon_points(index, id), mesh)
None => ()
}
}
None => ()
}
None => ()
}
}
None => ()
}
}
None => ()
}
None => ()
}
mesh
}
///|
pub fn mesh_for_geometry(index : ModelIndex, id : Int) -> Mesh raise ParseError {
let entity = index.require(id)
let upper = entity.name.to_upper()
if upper == "IFCTRIANGULATEDFACESET" {
let points = match optional_reference_argument(entity, 0) {
Some(coordinate_id) =>
match index.entity(coordinate_id) {
Some(coordinates) => points_from_entity(index, coordinates)
None => []
}
None => []
}
let indices = match entity_value(entity, 2) {
Some(value) => indices_from_value(value)
None => []
}
{ points, triangles: triangle_array(indices) }
} else if upper == "IFCFACETEDBREP" || upper == "IFCMANIFOLDSOLIDBREP" {
faceted_brep_mesh(index, entity)
} else {
{ points: [], triangles: [] }
}
}
///|
pub fn mesh_point_count(mesh : Mesh) -> Int {
mesh.points.length()
}
///|
pub fn mesh_triangle_count(mesh : Mesh) -> Int {
mesh.triangles.length()
}
///|
pub fn topology_face_count(
index : ModelIndex,
id : Int,
) -> Int raise ParseError {
let entity = index.require(id)
match entity.name.to_upper() {
"IFCFACETEDBREP" | "IFCMANIFOLDSOLIDBREP" =>
match optional_reference_argument(entity, 0) {
Some(shell_id) =>
match index.entity(shell_id) {
Some(shell) => reference_list(entity_value(shell, 0)).length()
None => 0
}
None => 0
}
"IFCTRIANGULATEDFACESET" =>
match entity_value(entity, 2) {
Some(value) => indices_from_value(value).length() / 3
None => 0
}
_ => 0
}
}