Skip to main content

ifc_lite_processing/appearance/
types.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6
7#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize, Serialize)]
8#[serde(rename_all = "camelCase")]
9pub enum RepresentationPolicy {
10    #[default]
11    Preserve,
12    EvaluatedOccurrence,
13}
14
15#[derive(Debug, Clone, Deserialize, Serialize)]
16#[serde(rename_all = "camelCase", deny_unknown_fields)]
17pub struct AppearanceRequest {
18    /// Parametric conversion is never implicit.
19    #[serde(default)]
20    pub representation_policy: RepresentationPolicy,
21    pub schema: String,
22    pub source_revision: String,
23    pub next_express_id: u32,
24    pub product_ids: Vec<u32>,
25    pub image_uri: String,
26    pub repeat_s: bool,
27    pub repeat_t: bool,
28    pub mapping: Mapping,
29}
30#[derive(Debug, Clone, Deserialize, Serialize)]
31#[serde(tag = "kind", rename_all = "camelCase", deny_unknown_fields)]
32pub enum Mapping {
33    #[serde(rename_all = "camelCase")]
34    ExistingUv {
35        scale: [f64; 2],
36        offset: [f64; 2],
37        rotation_radians: f64,
38    },
39    #[serde(rename_all = "camelCase")]
40    Planar {
41        frame: MappingFrame,
42        origin: [f64; 3],
43        axis_u: [f64; 3],
44        axis_v: [f64; 3],
45        metres_per_tile: [f64; 2],
46    },
47    #[serde(rename_all = "camelCase")]
48    Box {
49        frame: MappingFrame,
50        origin: [f64; 3],
51        metres_per_tile: [f64; 3],
52    },
53}
54#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
55#[serde(rename_all = "camelCase")]
56pub enum MappingFrame {
57    Item,
58    World,
59}
60#[derive(Debug, Clone, Serialize)]
61#[serde(rename_all = "camelCase")]
62pub struct CreatedEntity {
63    pub express_id: u32,
64    pub r#type: String,
65    /// StoreEditor wire values: '#N' references, '.ENUM.' tokens, JSON lists/numbers/null.
66    pub attributes: Vec<Value>,
67}
68#[derive(Debug, Clone, Serialize)]
69#[serde(rename_all = "camelCase")]
70pub struct PositionalEdit {
71    pub express_id: u32,
72    pub index: usize,
73    pub value: Value,
74}
75#[derive(Debug, Clone, Serialize)]
76#[serde(rename_all = "camelCase")]
77pub struct AppearanceItem {
78    pub product_id: u32,
79    pub geometry_item_id: u32,
80    /// Source IFC bottom-left texture coordinates, before mesher seam expansion.
81    pub tex_coords: Vec<[f64; 2]>,
82    /// 1-based, parallel to source CoordIndex (before winding correction).
83    pub tex_coord_index: Vec<[u32; 3]>,
84    /// Actual final source topology after canonical placement and welding.
85    pub source_indices: Vec<u32>,
86    /// Final canonical target topology; becomes provenance after Apply.
87    pub target_indices: Vec<u32>,
88    /// Canonical target vertex pool size; removed degenerate triangles can leave
89    /// unused vertices, so the maximum index is not bounded by corner count.
90    pub target_vertex_count: usize,
91    /// UV pairs in triangle-corner order, with GPU V flip. Fragment consumers
92    /// remap canonical corner slots and expand seams without moving geometry.
93    pub preview_corner_uvs: Vec<f32>,
94    /// Final canonical shading normals in triangle-corner order, converted from
95    /// IFC Z-up to renderer Y-up as [nx, nz, -ny], matching MeshDataJs.
96    /// UV-dependent welding may choose a different normal representative.
97    pub target_corner_normals: Vec<f32>,
98}
99#[derive(Debug, Clone, Serialize)]
100#[serde(rename_all = "camelCase")]
101pub struct Exclusion {
102    pub product_id: u32,
103    pub reason: String,
104}
105#[derive(Debug, Clone, Default, Serialize)]
106#[serde(rename_all = "camelCase")]
107pub struct AppearancePlan {
108    /// Explicit occurrence-local conversions, with original renderer provenance.
109    pub conversions: Vec<AppearanceConversion>,
110    pub source_revision: String,
111    pub next_express_id: u32,
112    pub next_available_express_id: u32,
113    pub created: Vec<CreatedEntity>,
114    pub edits: Vec<PositionalEdit>,
115    pub removed: Vec<u32>,
116    pub items: Vec<AppearanceItem>,
117    pub exclusions: Vec<Exclusion>,
118}
119
120#[derive(Debug, Clone, Serialize)]
121#[serde(rename_all = "camelCase")]
122pub struct AppearanceConversion {
123    pub product_id: u32,
124    pub representation_id: u32,
125    pub source_geometry_item_id: u32,
126    pub geometry_item_id: u32,
127    pub source_indices: Vec<u32>,
128    /// Canonical evaluated IFC Z-up geometry, before any appearance replacement.
129    /// Coordinates are local f32 values plus source_origin and rtc_offset in metres.
130    pub source_positions: Vec<f32>,
131    pub source_normals: Vec<f32>,
132    pub source_origin: [f64; 3],
133    pub source_color: [f32; 4],
134    pub rtc_offset: [f64; 3],
135    /// Canonical opening meshes removed when their Body becomes Reference.
136    /// Inner fields use the shared MeshData wire contract; origin + rtc_offset
137    /// restores IFC Z-up metres. These owners are companion dependency roots.
138    #[serde(skip_serializing_if = "Vec::is_empty")]
139    pub source_removed_meshes: Vec<crate::types::mesh::MeshData>,
140}