use crate::records::{DesignParameter, DesignParameterScope, DesignSketchPlacement};
pub(crate) const SCHEME_PREFIX: &str = "f3d:";
pub(crate) const DEFAULT_STREAM: &str = "f3d:design";
pub(crate) fn native_stream(id: &str) -> Option<&str> {
id.rsplit_once(':').map(|(stream, _)| stream)
}
pub(crate) const FILE_SOURCE_IMAGE_ID: &str = "f3d:file:source-image#0";
fn identity_key_component(value: &str) -> String {
use std::fmt::Write as _;
let mut encoded = String::with_capacity(value.len());
for character in value.chars() {
if character == '#' || character == '%' || character.is_whitespace() {
let mut bytes = [0; 4];
for byte in character.encode_utf8(&mut bytes).as_bytes() {
write!(encoded, "%{byte:02X}").expect("writing to a String cannot fail");
}
} else {
encoded.push(character);
}
}
encoded
}
pub(crate) fn brep_entity_id(index: impl std::fmt::Display) -> String {
format!("f3d:brep:entity#{index}")
}
pub(crate) fn configuration_entry_id(entry_name: &str) -> String {
format!("f3d:configuration:entry#{entry_name}")
}
pub(crate) fn neutral_configuration_id(
entry_name: &str,
variant_name: &str,
) -> cadmpeg_ir::features::ConfigurationId {
cadmpeg_ir::features::ConfigurationId(format!(
"f3d:configuration:variant#{}:{}{}:{}",
entry_name.len(),
entry_name,
variant_name.len(),
variant_name,
))
}
pub(crate) fn neutral_feature_id(scope: &DesignParameterScope) -> cadmpeg_ir::features::FeatureId {
neutral_feature_id_parts(
native_stream(&scope.id).unwrap_or(DEFAULT_STREAM),
&scope.kind,
scope.feature_ordinal,
scope.record_index,
)
}
pub(crate) fn neutral_feature_id_parts(
stream: &str,
kind: &str,
feature_ordinal: u32,
scope_record_index: u32,
) -> cadmpeg_ir::features::FeatureId {
let stream = identity_key_component(stream);
let kind = identity_key_component(kind);
cadmpeg_ir::features::FeatureId(format!(
"f3d:model:feature#{}:{}{}:{}{}:{}",
stream.len(),
stream,
kind.len(),
kind,
feature_ordinal,
scope_record_index,
))
}
pub(crate) fn neutral_parameter_id(
parameter: &DesignParameter,
) -> cadmpeg_ir::features::ParameterId {
neutral_parameter_id_parts(
native_stream(¶meter.id).unwrap_or(DEFAULT_STREAM),
parameter.source_ordinal,
)
}
pub(crate) fn neutral_parameter_id_parts(
stream: &str,
source_ordinal: u32,
) -> cadmpeg_ir::features::ParameterId {
let stream = identity_key_component(stream);
cadmpeg_ir::features::ParameterId(format!(
"f3d:model:parameter#{}:{}{}",
stream.len(),
stream,
source_ordinal,
))
}
pub(crate) fn neutral_sketch_id(
placement: &DesignSketchPlacement,
) -> cadmpeg_ir::sketches::SketchId {
cadmpeg_ir::sketches::SketchId(sketch_placement_id("sketch", placement))
}
pub(crate) fn neutral_spatial_sketch_id(
placement: &DesignSketchPlacement,
) -> cadmpeg_ir::sketches::SpatialSketchId {
cadmpeg_ir::sketches::SpatialSketchId(sketch_placement_id("spatial-sketch", placement))
}
fn sketch_placement_id(segment: &str, placement: &DesignSketchPlacement) -> String {
let stream = identity_key_component(native_stream(&placement.id).unwrap_or(DEFAULT_STREAM));
format!("f3d:model:{segment}#{stream}@{}", placement.entity_suffix)
}
pub(crate) fn neutral_sketch_point_id(
sketch: &cadmpeg_ir::sketches::SketchId,
persistent_id: u64,
) -> cadmpeg_ir::sketches::SketchEntityId {
cadmpeg_ir::sketches::SketchEntityId(sketch_entity_tagged(
"sketch-entity",
&sketch.0,
'p',
persistent_id,
))
}
pub(crate) fn neutral_sketch_curve_id(
sketch: &cadmpeg_ir::sketches::SketchId,
primary_id: u64,
secondary_id: u64,
) -> cadmpeg_ir::sketches::SketchEntityId {
cadmpeg_ir::sketches::SketchEntityId(sketch_entity_curve(
"sketch-entity",
&sketch.0,
primary_id,
secondary_id,
))
}
pub(crate) fn neutral_sketch_text_id(
sketch: &cadmpeg_ir::sketches::SketchId,
persistent_id: u64,
) -> cadmpeg_ir::sketches::SketchEntityId {
cadmpeg_ir::sketches::SketchEntityId(sketch_entity_tagged(
"sketch-entity",
&sketch.0,
't',
persistent_id,
))
}
pub(crate) fn neutral_spatial_sketch_curve_id(
sketch: &cadmpeg_ir::sketches::SpatialSketchId,
primary_id: u64,
secondary_id: u64,
) -> cadmpeg_ir::sketches::SpatialSketchEntityId {
cadmpeg_ir::sketches::SpatialSketchEntityId(sketch_entity_curve(
"spatial-sketch-entity",
&sketch.0,
primary_id,
secondary_id,
))
}
pub(crate) fn neutral_spatial_sketch_point_id(
sketch: &cadmpeg_ir::sketches::SpatialSketchId,
persistent_id: u64,
) -> cadmpeg_ir::sketches::SpatialSketchEntityId {
cadmpeg_ir::sketches::SpatialSketchEntityId(sketch_entity_tagged(
"spatial-sketch-entity",
&sketch.0,
'p',
persistent_id,
))
}
pub(crate) fn neutral_spatial_sketch_surface_id(
sketch: &cadmpeg_ir::sketches::SpatialSketchId,
persistent_id: u64,
) -> cadmpeg_ir::sketches::SpatialSketchEntityId {
cadmpeg_ir::sketches::SpatialSketchEntityId(sketch_entity_tagged(
"spatial-sketch-entity",
&sketch.0,
's',
persistent_id,
))
}
fn sketch_entity_tagged(segment: &str, sketch_key: &str, tag: char, id: u64) -> String {
let sketch = identity_key_component(sketch_key);
format!("f3d:model:{segment}#{}:{}{tag}{id}", sketch.len(), sketch)
}
fn sketch_entity_curve(
segment: &str,
sketch_key: &str,
primary_id: u64,
secondary_id: u64,
) -> String {
let sketch = identity_key_component(sketch_key);
format!(
"f3d:model:{segment}#{}:{}c{primary_id}:{secondary_id}",
sketch.len(),
sketch,
)
}
pub(crate) fn neutral_sketch_constraint_id(
native_ref: &str,
record_index: u32,
) -> cadmpeg_ir::sketches::SketchConstraintId {
let stream = identity_key_component(native_stream(native_ref).unwrap_or(DEFAULT_STREAM));
cadmpeg_ir::sketches::SketchConstraintId(format!(
"f3d:model:sketch-constraint#{stream}@{record_index}"
))
}
pub(crate) fn neutral_dimension_constraint_id(
parameter: &cadmpeg_ir::features::ParameterId,
form: &str,
) -> cadmpeg_ir::sketches::SketchConstraintId {
let parameter_key = parameter
.0
.split_once('#')
.map_or(parameter.0.as_str(), |(_, key)| key);
cadmpeg_ir::sketches::SketchConstraintId(format!(
"f3d:model:sketch-constraint#dimension:{}:{}{}:{}",
parameter_key.len(),
parameter_key,
form.len(),
form,
))
}
pub(crate) fn history_input_prefix(
feature_key: &str,
previous_state_id: impl std::fmt::Display,
) -> String {
format!("{}:{feature_key}:{previous_state_id}", feature_key.len())
}
pub(crate) fn history_input_state_id(prefix: &str) -> cadmpeg_ir::ids::FeatureInputTopologyId {
cadmpeg_ir::ids::FeatureInputTopologyId(format!("f3d:history-input:state#{prefix}"))
}
pub(crate) fn history_input_edge_id(
prefix: &str,
slot: impl std::fmt::Display,
) -> cadmpeg_ir::ids::HistoricalEdgeId {
cadmpeg_ir::ids::HistoricalEdgeId(format!("f3d:history-input:edge#{prefix}:{slot}"))
}
pub(crate) fn history_input_face_id(
prefix: &str,
slot: impl std::fmt::Display,
) -> cadmpeg_ir::ids::HistoricalFaceId {
cadmpeg_ir::ids::HistoricalFaceId(format!("f3d:history-input:face#{prefix}:{slot}"))
}
pub(crate) fn history_input_body_id(
prefix: &str,
slot: impl std::fmt::Display,
) -> cadmpeg_ir::ids::HistoricalBodyId {
cadmpeg_ir::ids::HistoricalBodyId(format!("f3d:history-input:body#{prefix}:{slot}"))
}
pub(crate) fn native_scope(name: &str) -> String {
format!("f3d:{name}")
}
pub(crate) fn native_scope_prefix(name: &str) -> String {
format!("f3d:{name}:")
}
macro_rules! native_record_id {
($(#[$meta:meta])* $name:ident, $kind:literal) => {
$(#[$meta])*
pub(crate) fn $name(scope: &str, offset: impl std::fmt::Display) -> String {
format!(concat!("f3d:{scope}:", $kind, "#{offset}"), scope = scope, offset = offset)
}
};
}
native_record_id!(
native_design_parameter_id,
"design-parameter"
);
native_record_id!(
native_design_parameter_owner_id,
"design-parameter-owner"
);
native_record_id!(
native_design_parameter_companion_id,
"design-parameter-companion"
);
native_record_id!(
native_design_parameter_scope_id,
"design-parameter-scope"
);
native_record_id!(
native_design_dimension_recipe_record_id,
"design-dimension-recipe-record"
);
native_record_id!(
native_design_dimension_locus_pair_id,
"design-dimension-locus-pair"
);
native_record_id!(
native_design_dimension_null_locus_pair_id,
"design-dimension-null-locus-pair"
);
native_record_id!(
native_design_dimension_annotation_frame_id,
"design-dimension-annotation-frame"
);
native_record_id!(
native_design_dimension_locus_group_id,
"design-dimension-locus-group"
);
native_record_id!(
native_design_edge_identity_operand_id,
"design-edge-identity-operand"
);
native_record_id!(
native_design_extrude_selection_group_id,
"design-extrude-selection-group"
);
native_record_id!(
native_design_extrude_selection_member_id,
"design-extrude-selection-member"
);
native_record_id!(
native_design_construction_operand_group_id,
"design-construction-operand-group"
);
native_record_id!(
native_design_construction_operand_identity_id,
"design-construction-operand-identity"
);
native_record_id!(
native_design_entity_selection_operand_id,
"design-entity-selection-operand"
);
native_record_id!(
native_design_body_recipe_operand_id,
"design-body-recipe-operand"
);
native_record_id!(
native_design_edge_operand_id,
"design-edge-operand"
);
native_record_id!(
native_design_face_operand_id,
"design-face-operand"
);
native_record_id!(
native_design_sketch_placement_id,
"design-sketch-placement"
);
native_record_id!(
native_persistent_reference_id,
"persistent-reference"
);
native_record_id!(
native_lost_edge_reference_id,
"lost-edge-reference"
);
native_record_id!(
native_design_object_id,
"design-object"
);
native_record_id!(
native_design_entity_header_id,
"design-entity-header"
);
native_record_id!(
native_design_record_header_id,
"design-record-header"
);
native_record_id!(
native_sketch_relation_id,
"sketch-relation"
);
native_record_id!(
native_sketch_point_id,
"sketch-point"
);
native_record_id!(
native_sketch_text_id,
"sketch-text"
);
native_record_id!(
native_sketch_curve_identity_id,
"sketch-curve-identity"
);
native_record_id!(
native_sketch_surface_id,
"sketch-surface"
);
native_record_id!(
native_design_body_member_id,
"design-body-member"
);
native_record_id!(
native_design_body_bounds_id,
"design-body-bounds"
);
native_record_id!(
native_construction_recipe_id,
"construction-recipe"
);
native_record_id!(
native_design_body_binding_id,
"design-body-binding"
);