///|
pub fn attributes(entity : Entity) -> Array[EntityAttribute] {
let result : Array[EntityAttribute] = []
for index in 0.. EntityAttribute? {
match entity_value(entity, index) {
Some(value) => Some(EntityAttribute::{ index, value })
None => None
}
}
///|
pub fn attribute_text(entity : Entity, index : Int) -> String? {
match attribute(entity, index) {
Some(item) => Some(item.value.to_step())
None => None
}
}
///|
pub fn entities_referencing(index : ModelIndex, id : Int) -> Array[Entity] {
index.all().filter(entity => entity_references(entity).contains(id))
}
///|
/// Follow generic STEP references without imposing an IFC schema.
pub fn reachable_entities(
index : ModelIndex,
roots : Array[Int],
) -> Array[Entity] {
let queue = roots.copy()
let visited : Map[Int, Bool] = Map([])
let result : Array[Entity] = []
let mut cursor = 0
while cursor < queue.length() {
let id = queue[cursor]
cursor += 1
if !visited.contains(id) {
visited[id] = true
match index.entity(id) {
Some(entity) => {
result.push(entity)
for target in entity_references(entity) {
if !visited.contains(target) {
queue.push(target)
}
}
}
None => ()
}
}
}
result
}
///|
pub fn type_histogram(index : ModelIndex) -> Map[String, Int] {
let result : Map[String, Int] = Map([])
for entity in index.all() {
result.update_or_default(entity.name.to_upper(), 1, count => count + 1)
}
result
}
///|
pub fn graph_stats(index : ModelIndex) -> GraphStats {
let targets : Map[Int, Bool] = Map([])
let mut reference_count = 0
let mut max_out_degree = 0
let mut orphan_reference_count = 0
for entity in index.all() {
let refs = entity_references(entity)
reference_count += refs.length()
if refs.length() > max_out_degree {
max_out_degree = refs.length()
}
for target in refs {
targets[target] = true
if !index.has(target) {
orphan_reference_count += 1
}
}
}
{
entity_count: index.all().length(),
reference_count,
distinct_targets: targets.length(),
max_out_degree,
orphan_reference_count,
}
}
///|
pub fn dependency_layers(
index : ModelIndex,
roots : Array[Int],
) -> Array[Array[Int]] {
let current = roots
let visited : Map[Int, Bool] = Map([])
let layers : Array[Array[Int]] = []
for root in roots {
visited[root] = true
}
let mut layer = current
while layer.length() > 0 {
layers.push(layer)
let next : Array[Int] = []
for id in layer {
match index.entity(id) {
Some(entity) =>
for target in entity_references(entity) {
if !visited.contains(target) {
visited[target] = true
next.push(target)
}
}
None => ()
}
}
layer = next
}
layers
}