use ifc_lite_geometry::Mesh;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub struct MeshDataJs {
express_id: u32,
ifc_type: String, positions: Vec<f32>,
normals: Vec<f32>,
indices: Vec<u32>,
color: [f32; 4], shading_color: Option<[f32; 4]>,
uvs: Vec<f32>,
texture_rgba: Vec<u8>,
texture_width: u32,
texture_height: u32,
texture_repeat_s: bool,
texture_repeat_t: bool,
geometry_class: u8,
origin: [f64; 3],
}
#[wasm_bindgen]
impl MeshDataJs {
#[wasm_bindgen(getter, js_name = expressId)]
pub fn express_id(&self) -> u32 {
self.express_id
}
#[wasm_bindgen(getter, js_name = ifcType)]
pub fn ifc_type(&self) -> String {
self.ifc_type.clone()
}
#[wasm_bindgen(getter)]
pub fn positions(&self) -> js_sys::Float32Array {
js_sys::Float32Array::from(&self.positions[..])
}
#[wasm_bindgen(getter)]
pub fn normals(&self) -> js_sys::Float32Array {
js_sys::Float32Array::from(&self.normals[..])
}
#[wasm_bindgen(getter)]
pub fn indices(&self) -> js_sys::Uint32Array {
js_sys::Uint32Array::from(&self.indices[..])
}
#[wasm_bindgen(getter)]
pub fn color(&self) -> Vec<f32> {
self.color.to_vec()
}
#[wasm_bindgen(getter, js_name = shadingColor)]
pub fn shading_color(&self) -> Option<Vec<f32>> {
self.shading_color.map(|c| c.to_vec())
}
#[wasm_bindgen(getter, js_name = vertexCount)]
pub fn vertex_count(&self) -> usize {
self.positions.len() / 3
}
#[wasm_bindgen(getter, js_name = triangleCount)]
pub fn triangle_count(&self) -> usize {
self.indices.len() / 3
}
#[wasm_bindgen(getter, js_name = hasTexture)]
pub fn has_texture(&self) -> bool {
!self.texture_rgba.is_empty()
}
#[wasm_bindgen(getter)]
pub fn uvs(&self) -> js_sys::Float32Array {
js_sys::Float32Array::from(&self.uvs[..])
}
#[wasm_bindgen(getter, js_name = textureRgba)]
pub fn texture_rgba(&self) -> js_sys::Uint8Array {
js_sys::Uint8Array::from(&self.texture_rgba[..])
}
#[wasm_bindgen(getter, js_name = textureWidth)]
pub fn texture_width(&self) -> u32 {
self.texture_width
}
#[wasm_bindgen(getter, js_name = textureHeight)]
pub fn texture_height(&self) -> u32 {
self.texture_height
}
#[wasm_bindgen(getter, js_name = textureRepeatS)]
pub fn texture_repeat_s(&self) -> bool {
self.texture_repeat_s
}
#[wasm_bindgen(getter, js_name = textureRepeatT)]
pub fn texture_repeat_t(&self) -> bool {
self.texture_repeat_t
}
#[wasm_bindgen(getter, js_name = geometryClass)]
pub fn geometry_class(&self) -> u8 {
self.geometry_class
}
#[wasm_bindgen(getter)]
pub fn origin(&self) -> js_sys::Float64Array {
js_sys::Float64Array::from(&self.origin[..])
}
}
impl MeshDataJs {
pub fn new(express_id: u32, ifc_type: String, mut mesh: Mesh, color: [f32; 4]) -> Self {
for chunk in mesh.positions.chunks_exact_mut(3) {
let y = chunk[1];
let z = chunk[2];
chunk[1] = z; chunk[2] = -y; }
for chunk in mesh.normals.chunks_exact_mut(3) {
let y = chunk[1];
let z = chunk[2];
chunk[1] = z;
chunk[2] = -y;
}
let remainder = mesh.indices.len() % 3;
let end = mesh.indices.len() - remainder;
for i in (0..end).step_by(3) {
mesh.indices.swap(i + 1, i + 2);
}
let origin = [mesh.origin[0], mesh.origin[2], -mesh.origin[1]];
Self {
express_id,
ifc_type,
positions: mesh.positions,
normals: mesh.normals,
indices: mesh.indices,
color,
shading_color: None,
uvs: Vec::new(),
texture_rgba: Vec::new(),
texture_width: 0,
texture_height: 0,
texture_repeat_s: true,
texture_repeat_t: true,
geometry_class: 0,
origin,
}
}
pub fn set_geometry_class(&mut self, class: u8) {
self.geometry_class = class;
}
pub fn set_shading_color(&mut self, shading: Option<[f32; 4]>) {
self.shading_color = shading;
}
pub fn set_texture(
&mut self,
uvs: Vec<f32>,
rgba: Vec<u8>,
width: u32,
height: u32,
repeat_s: bool,
repeat_t: bool,
) {
self.uvs = uvs;
self.texture_rgba = rgba;
self.texture_width = width;
self.texture_height = height;
self.texture_repeat_s = repeat_s;
self.texture_repeat_t = repeat_t;
}
pub fn from_mesh_data(m: ifc_lite_processing::MeshData) -> Self {
let mesh = Mesh {
positions: m.positions,
normals: m.normals,
indices: m.indices,
rtc_applied: true,
origin: m.origin,
};
let mut js = Self::new(m.express_id, m.ifc_type, mesh, m.color);
js.set_geometry_class(m.geometry_class);
if let (Some(uvs), Some(tex)) = (m.uvs, m.texture) {
js.set_texture(
uvs,
tex.rgba,
tex.width,
tex.height,
tex.repeat_s,
tex.repeat_t,
);
}
js
}
}
#[wasm_bindgen]
pub struct MeshCollection {
meshes: Vec<MeshDataJs>,
rtc_offset_x: f64,
rtc_offset_y: f64,
rtc_offset_z: f64,
building_rotation: Option<f64>,
geometry_hash_ids: Vec<u32>,
geometry_hash_values: Vec<u64>,
}
#[wasm_bindgen]
impl MeshCollection {
#[wasm_bindgen(getter)]
pub fn length(&self) -> usize {
self.meshes.len()
}
#[wasm_bindgen]
pub fn get(&self, index: usize) -> Option<MeshDataJs> {
self.meshes.get(index).map(|m| MeshDataJs {
express_id: m.express_id,
ifc_type: m.ifc_type.clone(),
positions: m.positions.clone(),
normals: m.normals.clone(),
indices: m.indices.clone(),
color: m.color,
shading_color: m.shading_color,
uvs: m.uvs.clone(),
texture_rgba: m.texture_rgba.clone(),
texture_width: m.texture_width,
texture_height: m.texture_height,
texture_repeat_s: m.texture_repeat_s,
texture_repeat_t: m.texture_repeat_t,
geometry_class: m.geometry_class,
origin: m.origin,
})
}
#[wasm_bindgen(js_name = takeMesh)]
pub fn take_mesh(&mut self, index: usize) -> Option<MeshDataJs> {
self.meshes.get_mut(index).map(|m| MeshDataJs {
express_id: m.express_id,
ifc_type: std::mem::take(&mut m.ifc_type),
positions: std::mem::take(&mut m.positions),
normals: std::mem::take(&mut m.normals),
indices: std::mem::take(&mut m.indices),
color: m.color,
shading_color: m.shading_color,
uvs: std::mem::take(&mut m.uvs),
texture_rgba: std::mem::take(&mut m.texture_rgba),
texture_width: m.texture_width,
texture_height: m.texture_height,
texture_repeat_s: m.texture_repeat_s,
texture_repeat_t: m.texture_repeat_t,
geometry_class: m.geometry_class,
origin: m.origin,
})
}
#[wasm_bindgen(getter, js_name = totalVertices)]
pub fn total_vertices(&self) -> usize {
self.meshes.iter().map(|m| m.positions.len() / 3).sum()
}
#[wasm_bindgen(getter, js_name = totalTriangles)]
pub fn total_triangles(&self) -> usize {
self.meshes.iter().map(|m| m.indices.len() / 3).sum()
}
#[wasm_bindgen(getter, js_name = rtcOffsetX)]
pub fn rtc_offset_x(&self) -> f64 {
self.rtc_offset_x
}
#[wasm_bindgen(getter, js_name = rtcOffsetY)]
pub fn rtc_offset_y(&self) -> f64 {
self.rtc_offset_y
}
#[wasm_bindgen(getter, js_name = rtcOffsetZ)]
pub fn rtc_offset_z(&self) -> f64 {
self.rtc_offset_z
}
#[wasm_bindgen(js_name = hasRtcOffset)]
pub fn has_rtc_offset(&self) -> bool {
const THRESHOLD: f64 = 10000.0;
self.rtc_offset_x.abs() > THRESHOLD
|| self.rtc_offset_y.abs() > THRESHOLD
|| self.rtc_offset_z.abs() > THRESHOLD
}
#[wasm_bindgen(getter, js_name = buildingRotation)]
pub fn building_rotation(&self) -> Option<f64> {
self.building_rotation
}
#[wasm_bindgen(getter, js_name = geometryHashIds)]
pub fn geometry_hash_ids(&self) -> js_sys::Uint32Array {
js_sys::Uint32Array::from(&self.geometry_hash_ids[..])
}
#[wasm_bindgen(getter, js_name = geometryHashValues)]
pub fn geometry_hash_values(&self) -> js_sys::BigUint64Array {
js_sys::BigUint64Array::from(&self.geometry_hash_values[..])
}
#[wasm_bindgen(getter, js_name = geometryHashCount)]
pub fn geometry_hash_count(&self) -> usize {
self.geometry_hash_ids.len()
}
}
impl MeshCollection {
pub fn new() -> Self {
Self {
meshes: Vec::new(),
rtc_offset_x: 0.0,
rtc_offset_y: 0.0,
rtc_offset_z: 0.0,
building_rotation: None,
geometry_hash_ids: Vec::new(),
geometry_hash_values: Vec::new(),
}
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
meshes: Vec::with_capacity(capacity),
rtc_offset_x: 0.0,
rtc_offset_y: 0.0,
rtc_offset_z: 0.0,
building_rotation: None,
geometry_hash_ids: Vec::new(),
geometry_hash_values: Vec::new(),
}
}
#[inline]
pub fn add(&mut self, mesh: MeshDataJs) {
self.meshes.push(mesh);
}
#[inline]
pub fn push_geometry_hash(&mut self, express_id: u32, hash: u64) {
self.geometry_hash_ids.push(express_id);
self.geometry_hash_values.push(hash);
}
pub fn from_vec(meshes: Vec<MeshDataJs>) -> Self {
Self {
meshes,
rtc_offset_x: 0.0,
rtc_offset_y: 0.0,
rtc_offset_z: 0.0,
building_rotation: None,
geometry_hash_ids: Vec::new(),
geometry_hash_values: Vec::new(),
}
}
pub fn len(&self) -> usize {
self.meshes.len()
}
pub fn is_empty(&self) -> bool {
self.meshes.is_empty()
}
pub fn set_rtc_offset(&mut self, x: f64, y: f64, z: f64) {
self.rtc_offset_x = x;
self.rtc_offset_y = y;
self.rtc_offset_z = z;
}
pub fn set_building_rotation(&mut self, rotation: Option<f64>) {
self.building_rotation = rotation;
}
pub fn apply_rtc_offset(&mut self, x: f64, y: f64, z: f64) {
self.rtc_offset_x = x;
self.rtc_offset_y = y;
self.rtc_offset_z = z;
for mesh in &mut self.meshes {
for chunk in mesh.positions.chunks_exact_mut(3) {
chunk[0] = (chunk[0] as f64 - x) as f32;
chunk[1] = (chunk[1] as f64 - y) as f32;
chunk[2] = (chunk[2] as f64 - z) as f32;
}
}
}
}
impl Clone for MeshCollection {
fn clone(&self) -> Self {
Self {
meshes: self
.meshes
.iter()
.map(|m| MeshDataJs {
express_id: m.express_id,
ifc_type: m.ifc_type.clone(),
positions: m.positions.clone(),
normals: m.normals.clone(),
indices: m.indices.clone(),
color: m.color,
shading_color: m.shading_color,
uvs: m.uvs.clone(),
texture_rgba: m.texture_rgba.clone(),
texture_width: m.texture_width,
texture_height: m.texture_height,
texture_repeat_s: m.texture_repeat_s,
texture_repeat_t: m.texture_repeat_t,
geometry_class: m.geometry_class,
origin: m.origin,
})
.collect(),
rtc_offset_x: self.rtc_offset_x,
rtc_offset_y: self.rtc_offset_y,
rtc_offset_z: self.rtc_offset_z,
building_rotation: self.building_rotation,
geometry_hash_ids: self.geometry_hash_ids.clone(),
geometry_hash_values: self.geometry_hash_values.clone(),
}
}
}
impl Default for MeshCollection {
fn default() -> Self {
Self::new()
}
}
#[wasm_bindgen]
pub struct SymbolicPolyline {
express_id: u32,
ifc_type: String,
points: Vec<f32>,
is_closed: bool,
world_y: f32,
rep_identifier: String,
}
#[wasm_bindgen]
impl SymbolicPolyline {
#[wasm_bindgen(getter, js_name = expressId)]
pub fn express_id(&self) -> u32 {
self.express_id
}
#[wasm_bindgen(getter, js_name = ifcType)]
pub fn ifc_type(&self) -> String {
self.ifc_type.clone()
}
#[wasm_bindgen(getter)]
pub fn points(&self) -> js_sys::Float32Array {
js_sys::Float32Array::from(&self.points[..])
}
#[wasm_bindgen(getter, js_name = pointCount)]
pub fn point_count(&self) -> usize {
self.points.len() / 2
}
#[wasm_bindgen(getter, js_name = isClosed)]
pub fn is_closed(&self) -> bool {
self.is_closed
}
#[wasm_bindgen(getter, js_name = repIdentifier)]
pub fn rep_identifier(&self) -> String {
self.rep_identifier.clone()
}
#[wasm_bindgen(getter, js_name = worldY)]
pub fn world_y(&self) -> f32 {
self.world_y
}
}
impl SymbolicPolyline {
#[allow(clippy::too_many_arguments)]
pub fn new(
express_id: u32,
ifc_type: String,
points: Vec<f32>,
is_closed: bool,
world_y: f32,
rep_identifier: String,
) -> Self {
Self {
express_id,
ifc_type,
points,
is_closed,
world_y,
rep_identifier,
}
}
}
#[wasm_bindgen]
pub struct SymbolicCircle {
express_id: u32,
ifc_type: String,
center_x: f32,
center_y: f32,
radius: f32,
world_y: f32,
start_angle: f32,
end_angle: f32,
rep_identifier: String,
}
#[wasm_bindgen]
impl SymbolicCircle {
#[wasm_bindgen(getter, js_name = expressId)]
pub fn express_id(&self) -> u32 {
self.express_id
}
#[wasm_bindgen(getter, js_name = ifcType)]
pub fn ifc_type(&self) -> String {
self.ifc_type.clone()
}
#[wasm_bindgen(getter, js_name = centerX)]
pub fn center_x(&self) -> f32 {
self.center_x
}
#[wasm_bindgen(getter, js_name = centerY)]
pub fn center_y(&self) -> f32 {
self.center_y
}
#[wasm_bindgen(getter)]
pub fn radius(&self) -> f32 {
self.radius
}
#[wasm_bindgen(getter, js_name = startAngle)]
pub fn start_angle(&self) -> f32 {
self.start_angle
}
#[wasm_bindgen(getter, js_name = endAngle)]
pub fn end_angle(&self) -> f32 {
self.end_angle
}
#[wasm_bindgen(getter, js_name = repIdentifier)]
pub fn rep_identifier(&self) -> String {
self.rep_identifier.clone()
}
#[wasm_bindgen(getter, js_name = isFullCircle)]
pub fn is_full_circle(&self) -> bool {
(self.end_angle - self.start_angle - std::f32::consts::TAU).abs() < 0.001
}
#[wasm_bindgen(getter, js_name = worldY)]
pub fn world_y(&self) -> f32 {
self.world_y
}
}
impl SymbolicCircle {
#[allow(clippy::too_many_arguments)]
pub fn new(
express_id: u32,
ifc_type: String,
center_x: f32,
center_y: f32,
radius: f32,
world_y: f32,
start_angle: f32,
end_angle: f32,
rep_identifier: String,
) -> Self {
Self {
express_id,
ifc_type,
center_x,
center_y,
radius,
world_y,
start_angle,
end_angle,
rep_identifier,
}
}
pub fn full_circle(
express_id: u32,
ifc_type: String,
center_x: f32,
center_y: f32,
radius: f32,
world_y: f32,
rep_identifier: String,
) -> Self {
Self::new(
express_id,
ifc_type,
center_x,
center_y,
radius,
world_y,
0.0,
std::f32::consts::TAU,
rep_identifier,
)
}
}
#[wasm_bindgen]
pub struct SymbolicText {
express_id: u32,
ifc_type: String,
x: f32,
y: f32,
dir_x: f32,
dir_y: f32,
height: f32,
content: String,
alignment: String,
world_y: f32,
color_r: f32,
color_g: f32,
color_b: f32,
color_a: f32,
target_px: f32,
rep_identifier: String,
}
#[wasm_bindgen]
impl SymbolicText {
#[wasm_bindgen(getter, js_name = expressId)]
pub fn express_id(&self) -> u32 { self.express_id }
#[wasm_bindgen(getter, js_name = ifcType)]
pub fn ifc_type(&self) -> String { self.ifc_type.clone() }
#[wasm_bindgen(getter)]
pub fn x(&self) -> f32 { self.x }
#[wasm_bindgen(getter)]
pub fn y(&self) -> f32 { self.y }
#[wasm_bindgen(getter, js_name = dirX)]
pub fn dir_x(&self) -> f32 { self.dir_x }
#[wasm_bindgen(getter, js_name = dirY)]
pub fn dir_y(&self) -> f32 { self.dir_y }
#[wasm_bindgen(getter)]
pub fn height(&self) -> f32 { self.height }
#[wasm_bindgen(getter)]
pub fn content(&self) -> String { self.content.clone() }
#[wasm_bindgen(getter)]
pub fn alignment(&self) -> String { self.alignment.clone() }
#[wasm_bindgen(getter, js_name = worldY)]
pub fn world_y(&self) -> f32 { self.world_y }
#[wasm_bindgen(getter, js_name = colorR)]
pub fn color_r(&self) -> f32 { self.color_r }
#[wasm_bindgen(getter, js_name = colorG)]
pub fn color_g(&self) -> f32 { self.color_g }
#[wasm_bindgen(getter, js_name = colorB)]
pub fn color_b(&self) -> f32 { self.color_b }
#[wasm_bindgen(getter, js_name = colorA)]
pub fn color_a(&self) -> f32 { self.color_a }
#[wasm_bindgen(getter, js_name = targetPx)]
pub fn target_px(&self) -> f32 { self.target_px }
#[wasm_bindgen(getter, js_name = repIdentifier)]
pub fn rep_identifier(&self) -> String { self.rep_identifier.clone() }
}
impl SymbolicText {
#[allow(clippy::too_many_arguments)]
pub fn new(
express_id: u32,
ifc_type: String,
x: f32,
y: f32,
dir_x: f32,
dir_y: f32,
height: f32,
content: String,
alignment: String,
world_y: f32,
rep_identifier: String,
) -> Self {
Self::new_styled(
express_id, ifc_type, x, y, dir_x, dir_y,
height, content, alignment, world_y,
[0.05, 0.05, 0.05, 1.0], 0.0, rep_identifier,
)
}
#[allow(clippy::too_many_arguments)]
pub fn new_styled(
express_id: u32,
ifc_type: String,
x: f32,
y: f32,
dir_x: f32,
dir_y: f32,
height: f32,
content: String,
alignment: String,
world_y: f32,
rgba: [f32; 4],
target_px: f32,
rep_identifier: String,
) -> Self {
Self {
express_id,
ifc_type,
x,
y,
dir_x,
dir_y,
height,
content,
alignment,
world_y,
color_r: rgba[0],
color_g: rgba[1],
color_b: rgba[2],
color_a: rgba[3],
target_px,
rep_identifier,
}
}
}
#[wasm_bindgen]
pub struct SymbolicFillArea {
express_id: u32,
ifc_type: String,
points: Vec<f32>,
holes_offsets: Vec<u32>,
fill_r: f32,
fill_g: f32,
fill_b: f32,
fill_a: f32,
has_hatching: bool,
hatch_spacing: f32,
hatch_angle: f32,
hatch_angle_secondary: f32,
hatch_line_width: f32,
world_y: f32,
rep_identifier: String,
}
#[wasm_bindgen]
impl SymbolicFillArea {
#[wasm_bindgen(getter, js_name = expressId)]
pub fn express_id(&self) -> u32 { self.express_id }
#[wasm_bindgen(getter, js_name = ifcType)]
pub fn ifc_type(&self) -> String { self.ifc_type.clone() }
#[wasm_bindgen(getter)]
pub fn points(&self) -> js_sys::Float32Array {
js_sys::Float32Array::from(&self.points[..])
}
#[wasm_bindgen(getter, js_name = pointCount)]
pub fn point_count(&self) -> usize { self.points.len() / 2 }
#[wasm_bindgen(getter, js_name = holesOffsets)]
pub fn holes_offsets(&self) -> js_sys::Uint32Array {
js_sys::Uint32Array::from(&self.holes_offsets[..])
}
#[wasm_bindgen(getter, js_name = holeCount)]
pub fn hole_count(&self) -> usize { self.holes_offsets.len() }
#[wasm_bindgen(getter, js_name = fillR)]
pub fn fill_r(&self) -> f32 { self.fill_r }
#[wasm_bindgen(getter, js_name = fillG)]
pub fn fill_g(&self) -> f32 { self.fill_g }
#[wasm_bindgen(getter, js_name = fillB)]
pub fn fill_b(&self) -> f32 { self.fill_b }
#[wasm_bindgen(getter, js_name = fillA)]
pub fn fill_a(&self) -> f32 { self.fill_a }
#[wasm_bindgen(getter, js_name = hasHatching)]
pub fn has_hatching(&self) -> bool { self.has_hatching }
#[wasm_bindgen(getter, js_name = hatchSpacing)]
pub fn hatch_spacing(&self) -> f32 { self.hatch_spacing }
#[wasm_bindgen(getter, js_name = hatchAngle)]
pub fn hatch_angle(&self) -> f32 { self.hatch_angle }
#[wasm_bindgen(getter, js_name = hatchAngleSecondary)]
pub fn hatch_angle_secondary(&self) -> f32 { self.hatch_angle_secondary }
#[wasm_bindgen(getter, js_name = hatchLineWidth)]
pub fn hatch_line_width(&self) -> f32 { self.hatch_line_width }
#[wasm_bindgen(getter, js_name = worldY)]
pub fn world_y(&self) -> f32 { self.world_y }
#[wasm_bindgen(getter, js_name = repIdentifier)]
pub fn rep_identifier(&self) -> String { self.rep_identifier.clone() }
}
impl SymbolicFillArea {
#[allow(clippy::too_many_arguments)]
pub fn new(
express_id: u32,
ifc_type: String,
points: Vec<f32>,
holes_offsets: Vec<u32>,
fill_rgba: [f32; 4],
world_y: f32,
rep_identifier: String,
) -> Self {
Self {
express_id,
ifc_type,
points,
holes_offsets,
fill_r: fill_rgba[0],
fill_g: fill_rgba[1],
fill_b: fill_rgba[2],
fill_a: fill_rgba[3],
has_hatching: false,
hatch_spacing: 0.0,
hatch_angle: 0.0,
hatch_angle_secondary: f32::NAN,
hatch_line_width: 0.0,
world_y,
rep_identifier,
}
}
pub fn with_hatching(
mut self,
spacing: f32,
angle: f32,
angle_secondary: Option<f32>,
line_width: f32,
) -> Self {
self.has_hatching = true;
self.hatch_spacing = spacing;
self.hatch_angle = angle;
self.hatch_angle_secondary = angle_secondary.unwrap_or(f32::NAN);
self.hatch_line_width = line_width;
self
}
}
#[wasm_bindgen]
pub struct SymbolicRepresentationCollection {
polylines: Vec<SymbolicPolyline>,
circles: Vec<SymbolicCircle>,
texts: Vec<SymbolicText>,
fills: Vec<SymbolicFillArea>,
}
#[wasm_bindgen]
impl SymbolicRepresentationCollection {
#[wasm_bindgen(js_name = getExpressIds)]
pub fn get_express_ids(&self) -> Vec<u32> {
let mut ids: Vec<u32> = self
.polylines
.iter()
.map(|p| p.express_id)
.chain(self.circles.iter().map(|c| c.express_id))
.chain(self.texts.iter().map(|t| t.express_id))
.chain(self.fills.iter().map(|f| f.express_id))
.collect();
ids.sort_unstable();
ids.dedup();
ids
}
#[wasm_bindgen(getter, js_name = polylineCount)]
pub fn polyline_count(&self) -> usize {
self.polylines.len()
}
#[wasm_bindgen(getter, js_name = circleCount)]
pub fn circle_count(&self) -> usize {
self.circles.len()
}
#[wasm_bindgen(getter, js_name = textCount)]
pub fn text_count(&self) -> usize { self.texts.len() }
#[wasm_bindgen(getter, js_name = fillCount)]
pub fn fill_count(&self) -> usize { self.fills.len() }
#[wasm_bindgen(getter, js_name = totalCount)]
pub fn total_count(&self) -> usize {
self.polylines.len() + self.circles.len() + self.texts.len() + self.fills.len()
}
#[wasm_bindgen(getter, js_name = isEmpty)]
pub fn is_empty(&self) -> bool {
self.polylines.is_empty()
&& self.circles.is_empty()
&& self.texts.is_empty()
&& self.fills.is_empty()
}
#[wasm_bindgen(js_name = getPolyline)]
pub fn get_polyline(&self, index: usize) -> Option<SymbolicPolyline> {
self.polylines.get(index).map(|p| SymbolicPolyline {
express_id: p.express_id,
ifc_type: p.ifc_type.clone(),
points: p.points.clone(),
is_closed: p.is_closed,
world_y: p.world_y,
rep_identifier: p.rep_identifier.clone(),
})
}
#[wasm_bindgen(js_name = getCircle)]
pub fn get_circle(&self, index: usize) -> Option<SymbolicCircle> {
self.circles.get(index).map(|c| SymbolicCircle {
express_id: c.express_id,
ifc_type: c.ifc_type.clone(),
center_x: c.center_x,
center_y: c.center_y,
radius: c.radius,
world_y: c.world_y,
start_angle: c.start_angle,
end_angle: c.end_angle,
rep_identifier: c.rep_identifier.clone(),
})
}
#[wasm_bindgen(js_name = getText)]
pub fn get_text(&self, index: usize) -> Option<SymbolicText> {
self.texts.get(index).map(|t| SymbolicText {
express_id: t.express_id,
ifc_type: t.ifc_type.clone(),
x: t.x,
y: t.y,
dir_x: t.dir_x,
dir_y: t.dir_y,
height: t.height,
content: t.content.clone(),
alignment: t.alignment.clone(),
world_y: t.world_y,
color_r: t.color_r,
color_g: t.color_g,
color_b: t.color_b,
color_a: t.color_a,
target_px: t.target_px,
rep_identifier: t.rep_identifier.clone(),
})
}
#[wasm_bindgen(js_name = getFill)]
pub fn get_fill(&self, index: usize) -> Option<SymbolicFillArea> {
self.fills.get(index).map(|f| SymbolicFillArea {
express_id: f.express_id,
ifc_type: f.ifc_type.clone(),
points: f.points.clone(),
holes_offsets: f.holes_offsets.clone(),
fill_r: f.fill_r,
fill_g: f.fill_g,
fill_b: f.fill_b,
fill_a: f.fill_a,
has_hatching: f.has_hatching,
hatch_spacing: f.hatch_spacing,
hatch_angle: f.hatch_angle,
hatch_angle_secondary: f.hatch_angle_secondary,
hatch_line_width: f.hatch_line_width,
world_y: f.world_y,
rep_identifier: f.rep_identifier.clone(),
})
}
}
impl SymbolicRepresentationCollection {
pub fn new() -> Self {
Self {
polylines: Vec::new(),
circles: Vec::new(),
texts: Vec::new(),
fills: Vec::new(),
}
}
pub fn with_capacity(polyline_capacity: usize, circle_capacity: usize) -> Self {
Self {
polylines: Vec::with_capacity(polyline_capacity),
circles: Vec::with_capacity(circle_capacity),
texts: Vec::new(),
fills: Vec::new(),
}
}
pub fn add_polyline(&mut self, polyline: SymbolicPolyline) {
self.polylines.push(polyline);
}
pub fn add_circle(&mut self, circle: SymbolicCircle) {
self.circles.push(circle);
}
pub fn add_text(&mut self, text: SymbolicText) {
self.texts.push(text);
}
pub fn add_fill(&mut self, fill: SymbolicFillArea) {
self.fills.push(fill);
}
pub fn from_data(data: ifc_lite_processing::SymbolicData) -> Self {
let mut collection = Self::with_capacity(data.polylines.len(), data.circles.len());
for p in data.polylines {
collection.add_polyline(SymbolicPolyline::new(
p.express_id,
p.ifc_type,
p.points,
p.closed,
p.world_y,
p.representation,
));
}
for c in data.circles {
collection.add_circle(SymbolicCircle::new(
c.express_id,
c.ifc_type,
c.center_x,
c.center_y,
c.radius,
c.world_y,
c.start_angle,
c.end_angle,
c.representation,
));
}
for t in data.texts {
collection.add_text(SymbolicText::new_styled(
t.express_id,
t.ifc_type,
t.x,
t.y,
t.dir_x,
t.dir_y,
t.height,
t.content,
t.alignment,
t.world_y,
t.color,
t.target_px,
t.representation,
));
}
for f in data.fills {
collection.add_fill(SymbolicFillArea::new(
f.express_id,
f.ifc_type,
f.points,
f.holes_offsets,
f.fill_color,
f.world_y,
f.representation,
));
}
collection
}
}
impl Default for SymbolicRepresentationCollection {
fn default() -> Self {
Self::new()
}
}
#[wasm_bindgen]
pub fn get_memory() -> JsValue {
wasm_bindgen::memory()
}