ifc_style/authoring/
fill.rs1use ifc_model::{EntityId, Model, Transaction, Value};
7use ifc_schema::Schema;
8
9use crate::error::StyleResult;
10
11use super::{build_named, invalid_authoring, validate_ref};
12
13#[derive(Debug, Clone, Copy)]
15pub enum HatchLineDistance {
16 Length(f64),
18 Vector(EntityId),
20}
21
22pub fn create_fill_area_style_hatching(
33 tx: &mut Transaction,
34 model: &Model,
35 schema: &Schema,
36 appearance: EntityId,
37 distance: HatchLineDistance,
38 reference: (Option<EntityId>, Option<EntityId>),
39 angle: f64,
40) -> StyleResult<EntityId> {
41 const ENTITY: &str = "IfcFillAreaStyleHatching";
42 let (point_of_reference, pattern_start) = reference;
43 validate_ref(tx, model, schema, appearance, "IfcCurveStyle")?;
44 if !angle.is_finite() {
45 return Err(invalid_authoring(ENTITY, "HatchLineAngle", "not finite"));
46 }
47 let start = match distance {
48 HatchLineDistance::Length(value) => {
49 if !value.is_finite() || value <= 0.0 {
50 return Err(invalid_authoring(
51 ENTITY,
52 "StartOfNextHatchLine",
53 format!("expected a positive length, got {value}"),
54 ));
55 }
56 Value::Real(value)
57 }
58 HatchLineDistance::Vector(id) => {
59 validate_ref(tx, model, schema, id, "IfcVector")?;
60 Value::Ref(id)
61 }
62 };
63 for point in [point_of_reference, pattern_start].into_iter().flatten() {
64 validate_ref(tx, model, schema, point, "IfcCartesianPoint")?;
65 }
66 let mut values = vec![
67 ("HatchLineAppearance", Value::Ref(appearance)),
68 ("StartOfNextHatchLine", start),
69 ];
70 if let Some(point) = point_of_reference {
71 values.push(("PointOfReferenceHatchLine", Value::Ref(point)));
72 }
73 if let Some(point) = pattern_start {
74 values.push(("PatternStart", Value::Ref(point)));
75 }
76 values.push(("HatchLineAngle", Value::Real(angle)));
77 Ok(tx.create(build_named(schema, ENTITY, values)?))
78}
79
80pub fn create_fill_area_style_tiles(
92 tx: &mut Transaction,
93 model: &Model,
94 schema: &Schema,
95 tiling_pattern: &[EntityId],
96 tiles: &[EntityId],
97 tiling_scale: f64,
98) -> StyleResult<EntityId> {
99 const ENTITY: &str = "IfcFillAreaStyleTiles";
100 if tiling_pattern.len() != 2 {
101 return Err(invalid_authoring(
102 ENTITY,
103 "TilingPattern",
104 format!("expected exactly two vectors, got {}", tiling_pattern.len()),
105 ));
106 }
107 if tiles.is_empty() {
108 return Err(invalid_authoring(ENTITY, "Tiles", "empty"));
109 }
110 if !tiling_scale.is_finite() || tiling_scale <= 0.0 {
111 return Err(invalid_authoring(
112 ENTITY,
113 "TilingScale",
114 format!("expected a positive ratio, got {tiling_scale}"),
115 ));
116 }
117 for vector in tiling_pattern {
118 validate_ref(tx, model, schema, *vector, "IfcVector")?;
119 }
120 for tile in tiles {
121 validate_ref(tx, model, schema, *tile, "IfcStyledItem")?;
122 }
123 let values = vec![
124 (
125 "TilingPattern",
126 Value::List(tiling_pattern.iter().copied().map(Value::Ref).collect()),
127 ),
128 (
129 "Tiles",
130 Value::List(tiles.iter().copied().map(Value::Ref).collect()),
131 ),
132 ("TilingScale", Value::Real(tiling_scale)),
133 ];
134 Ok(tx.create(build_named(schema, ENTITY, values)?))
135}