use crate::ids::{CurveId, PcurveId, ProceduralCurveId, ProceduralSurfaceId, SurfaceId, UnknownId};
use crate::math::{Point2, Point3, Vector3};
use crate::provenance::SourceObjectAssociation;
use crate::transform::Transform;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct NurbsSurface {
pub u_degree: u32,
pub v_degree: u32,
pub u_knots: Vec<f64>,
pub v_knots: Vec<f64>,
pub u_count: u32,
pub v_count: u32,
pub control_points: Vec<Point3>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub weights: Option<Vec<f64>>,
pub u_periodic: bool,
pub v_periodic: bool,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct NurbsCurve {
pub degree: u32,
pub knots: Vec<f64>,
pub control_points: Vec<Point3>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub weights: Option<Vec<f64>>,
pub periodic: bool,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum SurfaceGeometry {
Plane {
origin: Point3,
normal: Vector3,
u_axis: Vector3,
},
Cylinder {
origin: Point3,
axis: Vector3,
ref_direction: Vector3,
radius: f64,
},
Cone {
origin: Point3,
axis: Vector3,
ref_direction: Vector3,
radius: f64,
ratio: f64,
half_angle: f64,
},
Sphere {
center: Point3,
axis: Vector3,
ref_direction: Vector3,
radius: f64,
},
Torus {
center: Point3,
axis: Vector3,
ref_direction: Vector3,
major_radius: f64,
minor_radius: f64,
},
Nurbs(NurbsSurface),
Procedural {
construction: ProceduralSurfaceId,
},
Polygonal {
vertices: Vec<Point3>,
triangles: Vec<[u32; 3]>,
chordal_deflection: f64,
},
Transformed {
basis: Box<SurfaceGeometry>,
transform: Transform,
},
Unknown {
#[serde(default, skip_serializing_if = "Option::is_none")]
record: Option<UnknownId>,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct Surface {
pub id: SurfaceId,
pub geometry: SurfaceGeometry,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub source_object: Option<SourceObjectAssociation>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum CurveGeometry {
Line {
origin: Point3,
direction: Vector3,
},
Circle {
center: Point3,
axis: Vector3,
ref_direction: Vector3,
radius: f64,
},
Ellipse {
center: Point3,
axis: Vector3,
major_direction: Vector3,
major_radius: f64,
minor_radius: f64,
},
Parabola {
vertex: Point3,
axis: Vector3,
major_direction: Vector3,
focal_distance: f64,
},
Hyperbola {
center: Point3,
axis: Vector3,
major_direction: Vector3,
major_radius: f64,
minor_radius: f64,
},
Degenerate {
point: Point3,
},
Composite {
segments: Vec<CompositeCurveSegment>,
self_intersect: Option<bool>,
},
Nurbs(NurbsCurve),
Procedural {
construction: ProceduralCurveId,
},
Polyline {
points: Vec<Point3>,
#[serde(default, skip_serializing_if = "Option::is_none")]
parameters: Option<Vec<f64>>,
chordal_deflection: f64,
},
Transformed {
basis: Box<CurveGeometry>,
transform: Transform,
},
Unknown {
#[serde(default, skip_serializing_if = "Option::is_none")]
record: Option<UnknownId>,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct CompositeCurveSegment {
pub curve: CurveId,
pub same_sense: bool,
pub transition: CompositeCurveTransition,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum CompositeCurveTransition {
Discontinuous,
Continuous,
ContSameGradient,
ContSameGradientSameCurvature,
}
pub fn derive_reference_direction(axis: Vector3) -> Vector3 {
let norm = axis.norm();
if !norm.is_finite() || norm == 0.0 {
return Vector3::new(1.0, 0.0, 0.0);
}
let axis = Vector3::new(axis.x / norm, axis.y / norm, axis.z / norm);
let basis = if axis.x.abs() <= axis.y.abs() && axis.x.abs() <= axis.z.abs() {
Vector3::new(1.0, 0.0, 0.0)
} else if axis.y.abs() <= axis.z.abs() {
Vector3::new(0.0, 1.0, 0.0)
} else {
Vector3::new(0.0, 0.0, 1.0)
};
let dot = axis.x * basis.x + axis.y * basis.y + axis.z * basis.z;
let projected = Vector3::new(
basis.x - dot * axis.x,
basis.y - dot * axis.y,
basis.z - dot * axis.z,
);
let projected_norm = projected.norm();
Vector3::new(
projected.x / projected_norm,
projected.y / projected_norm,
projected.z / projected_norm,
)
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct Curve {
pub id: CurveId,
pub geometry: CurveGeometry,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub source_object: Option<SourceObjectAssociation>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct ProceduralSurface {
pub id: ProceduralSurfaceId,
pub surface: SurfaceId,
pub definition: ProceduralSurfaceDefinition,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub cache_fit_tolerance: Option<f64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub record_bounds: Option<[Option<f64>; 4]>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum SplineSurfaceParameters {
OrderedRanges {
ranges: [[f64; 2]; 2],
},
RevisionValues {
values: [Option<f64>; 4],
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum ProceduralSurfaceDefinition {
Exact {
parameters: SplineSurfaceParameters,
extension: i64,
#[serde(default, skip_serializing_if = "Option::is_none")]
revision_form: Option<RevisionSurfaceForm>,
},
Compound {
parameters: Vec<f64>,
components: Vec<SurfaceId>,
},
SubSurface {
support: SurfaceId,
parameter_ranges: [[f64; 2]; 2],
},
Taper {
support: SurfaceId,
reference: CurveId,
#[serde(default, skip_serializing_if = "Option::is_none")]
pcurve: Option<PcurveGeometry>,
parameter: f64,
taper: TaperSurfaceKind,
#[serde(default, skip_serializing_if = "Option::is_none")]
revision_form: Option<RevisionSurfaceForm>,
},
Loft {
sections: [LoftSection; 2],
parameters: SplineSurfaceParameters,
closures: [i64; 2],
singularities: [i64; 2],
mode: i64,
bridge: Vec<LoftBridgeToken>,
#[serde(default, skip_serializing_if = "Option::is_none")]
revision_form: Option<LoftRevisionForm>,
},
CompoundLoft {
construction: Box<CompoundLoftConstruction>,
},
RevisionCompoundLoft {
construction: Box<RevisionCompoundLoftConstruction>,
},
ScaledCompoundLoft {
construction: Box<ScaledCompoundLoftConstruction>,
},
Skin {
construction: Box<SkinSurfaceConstruction>,
},
Law {
construction: Box<LawSurfaceConstruction>,
},
Net {
construction: Box<NetSurfaceConstruction>,
},
G2Blend {
construction: Box<G2BlendConstruction>,
},
RevisionG2Blend {
construction: Box<RevisionG2BlendConstruction>,
},
VariableBlend {
construction: Box<VariableBlendConstruction>,
},
VertexBlend {
construction: Box<VertexBlendConstruction>,
},
Extrusion {
directrix: CurveId,
#[serde(default, skip_serializing_if = "Option::is_none")]
parameter_interval: Option<[f64; 2]>,
direction: Vector3,
#[serde(default, skip_serializing_if = "Option::is_none")]
native_position: Option<Point3>,
},
LinearSweep {
directrix: CurveId,
direction: Vector3,
},
Revolution {
directrix: CurveId,
axis_origin: Point3,
axis_direction: Vector3,
angular_interval: [f64; 2],
#[serde(default, skip_serializing_if = "Option::is_none")]
parameter_interval: Option<[f64; 2]>,
transposed: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
revision_form: Option<RevisionSurfaceForm>,
},
AxisRevolution {
directrix: CurveId,
axis_origin: Point3,
axis_direction: Vector3,
},
Sum {
first: CurveId,
second: CurveId,
basepoint: Vector3,
#[serde(default, skip_serializing_if = "Option::is_none")]
revision_form: Option<RevisionSurfaceForm>,
},
Sweep {
profile: CurveId,
spine: CurveId,
#[serde(default, skip_serializing_if = "Option::is_none")]
native: Option<Box<SweepSurfaceConstruction>>,
},
TSpline {
construction: Box<TSplineSurfaceConstruction>,
},
Helix {
construction: Box<HelixSurfaceConstruction>,
},
Deformable {
construction: Box<DeformableSurfaceConstruction>,
},
Offset {
support: SurfaceId,
distance: f64,
#[serde(default, skip_serializing_if = "Option::is_none")]
u_sense: Option<i64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
v_sense: Option<i64>,
extension_flags: Vec<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
revision_form: Option<RevisionSurfaceForm>,
},
Subset {
support: SurfaceId,
parameter_ranges: [[f64; 2]; 2],
},
ParallelOffset {
support: SurfaceId,
distance: f64,
self_intersect: Option<bool>,
},
DegenerateTorus {
select_outer: bool,
},
CurveBounded {
support: SurfaceId,
boundaries: Vec<CurveId>,
implicit_outer: bool,
},
Ruled {
first: CurveId,
second: CurveId,
},
Blend {
supports: [Option<BlendSupport>; 2],
#[serde(default, skip_serializing_if = "Option::is_none")]
spine: Option<CurveId>,
radius: BlendRadiusLaw,
cross_section: BlendCrossSection,
#[serde(default, skip_serializing_if = "Option::is_none")]
native: Option<Box<RollingBallConstruction>>,
},
RollingBallJet {
degree: u32,
knots: Vec<f64>,
multiplicities: Vec<u32>,
sites: Vec<RollingBallJetSite>,
},
Unknown {
#[serde(default, skip_serializing_if = "Option::is_none")]
record: Option<UnknownId>,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum DeformableSurfaceData {
Full {
leading_vectors: [Vector3; 4],
leading_parameter: f64,
leading_flags: [bool; 3],
selector: i64,
surface: SurfaceId,
native_id: i64,
flag: bool,
first_parameter: f64,
version_value: Option<i64>,
second_parameter: f64,
curve: CurveId,
frames: Box<[DeformableVectorFrame; 2]>,
trailing_value: i64,
},
SurfaceCurve {
surface: SurfaceId,
native_id: i64,
flag: bool,
first_parameter: f64,
selector: i64,
second_parameter: f64,
curve: CurveId,
vectors: [Vector3; 4],
frame_parameter: f64,
flags: [bool; 3],
parameter_triples: Vec<[f64; 3]>,
},
Plain {
frame: Box<DeformableSurfaceFrame>,
parameter_triples: Vec<[f64; 3]>,
},
Guided {
frame: Box<DeformableSurfaceFrame>,
selector: i64,
guide_parameter: f64,
},
Minimal {
vectors: [Vector3; 4],
selector: i64,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct DeformableVectorFrame {
pub vectors: [Vector3; 4],
pub parameter: f64,
pub flags: [bool; 3],
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct DeformableSurfaceFrame {
pub leading_vectors: [Vector3; 4],
pub leading_parameter: f64,
pub leading_flags: [bool; 3],
pub secondary_vectors: [Vector3; 3],
pub secondary_parameter: f64,
pub secondary_flags: [bool; 2],
pub point: Point3,
pub trailing_flags: [bool; 5],
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct DeformableSurfaceConstruction {
pub support: SurfaceId,
pub data: DeformableSurfaceData,
pub discontinuities: [Vec<f64>; 6],
pub discontinuity_flag: bool,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct HelixPathConstruction {
pub angle_range: [f64; 2],
pub center: Point3,
pub major: Vector3,
pub minor: Vector3,
pub pitch: Vector3,
pub apex_factor: f64,
pub axis: Vector3,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum HelixSurfaceProfile {
Circle {
length: f64,
radius: f64,
},
Line {
direction: Vector3,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct HelixSurfaceConstruction {
pub angle_range: [f64; 2],
pub dimension_range: [f64; 2],
pub path: HelixPathConstruction,
pub profile: HelixSurfaceProfile,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum TSplineSubtransform {
Inline {
program: String,
separator: Option<bool>,
values: String,
},
Reference {
index: i64,
#[serde(default, skip_serializing_if = "Option::is_none")]
resolved: Option<Box<TSplineSubtransform>>,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct TSplineSurfaceConstruction {
pub parameter_ranges: [[f64; 2]; 2],
pub type_code: i64,
pub subtransform: TSplineSubtransform,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub program_graph: Option<TSplineProgram>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub values_graph: Option<TSplineProgram>,
pub trailing_value: i64,
pub discontinuities: [Vec<f64>; 6],
pub discontinuity_flag: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub revision_form: Option<RevisionSurfaceForm>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct TSplineProgram {
pub headers: Vec<TSplineProgramLine>,
pub records: Vec<TSplineProgramLine>,
pub unparsed_lines: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct TSplineProgramLine {
pub kind: String,
pub fields: Vec<String>,
}
impl TSplineProgram {
#[must_use]
pub fn parse(program: &str) -> Self {
const HEADERS: &[&str] = &[
"degree",
"cap_type",
"units",
"end_conditions",
"star_knot_rule",
"star_smoothness",
"tol",
"ver",
"behavior_version",
"geom_tol",
"compat_version",
];
const RECORDS: &[&str] = &[
"f",
"e",
"v",
"l",
"ec",
"0m",
"0g",
"100edges",
"100verts",
"105sym",
"105plane",
"105a",
"106ek",
"50000grip",
];
let mut parsed = Self {
headers: Vec::new(),
records: Vec::new(),
unparsed_lines: Vec::new(),
};
for line in program.lines() {
let line = line.trim();
if line.is_empty() || line.starts_with('#') {
continue;
}
let mut fields = line.split_whitespace();
let Some(kind) = fields.next() else { continue };
let parsed_line = TSplineProgramLine {
kind: kind.into(),
fields: fields.map(String::from).collect(),
};
if HEADERS.contains(&kind) {
parsed.headers.push(parsed_line);
} else if RECORDS.contains(&kind) {
parsed.records.push(parsed_line);
} else {
parsed.unparsed_lines.push(line.into());
}
}
parsed
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct BlendSupport {
pub surface: SurfaceId,
#[serde(default)]
pub reversed: bool,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct RollingBallJetSite {
pub first_limit: Point3,
pub second_limit: Point3,
pub center: Point3,
pub angle: f64,
pub first_derivative: RollingBallJetDerivative,
pub second_derivative: RollingBallJetDerivative,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct RollingBallJetDerivative {
pub first_limit: Vector3,
pub second_limit: Vector3,
pub center: Vector3,
pub angle: f64,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum BlendCrossSection {
Circular,
Conic,
Polynomial,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Default)]
pub struct RevisionSurfaceForm {
pub revision: i64,
#[serde(default)]
pub support_bounds: [Option<f64>; 4],
#[serde(default)]
pub reference_endpoints: [Option<f64>; 2],
#[serde(default)]
pub second_endpoints: [Option<f64>; 2],
#[serde(default)]
pub flags: Vec<bool>,
pub tail_enum: i64,
#[serde(default)]
pub discontinuities: [Vec<f64>; 6],
pub tail_flag: bool,
#[serde(default)]
pub trailing_flags: Vec<bool>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum TaperSurfaceKind {
Standard,
Orthogonal {
sense: bool,
},
Edge {
draft: Vector3,
},
Shadow {
draft: Vector3,
sine: f64,
cosine: f64,
},
Ruled {
draft: Vector3,
sine: f64,
cosine: f64,
factor: f64,
},
Swept {
draft: Vector3,
sine: f64,
cosine: f64,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct LoftSubdataRow {
pub parameters: [f64; 2],
pub columns: Vec<[f64; 2]>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extra: Option<[f64; 2]>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct LoftSubdata {
pub type_code: i64,
pub row_count: i64,
pub column_count: i64,
pub rows: Vec<LoftSubdataRow>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct LoftProfileData {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub surface: Option<SurfaceId>,
#[serde(default)]
pub support_bounds: [Option<f64>; 4],
#[serde(default, skip_serializing_if = "Option::is_none")]
pub pcurve: Option<PcurveGeometry>,
pub first_flag: bool,
pub asm_extension: i64,
pub subdata: LoftSubdata,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub direction: Option<Vector3>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct LoftProfileMember {
pub type_code: i64,
pub curve: CurveId,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub endpoints: Option<[Option<f64>; 2]>,
pub data: LoftProfileData,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct LoftPath {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub curve: Option<CurveId>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub endpoints: Option<[Option<f64>; 2]>,
pub auxiliaries: Vec<CurveId>,
pub flag: i64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct LoftSectionEntry {
pub parameter: f64,
pub profile: Vec<LoftProfileMember>,
pub path: LoftPath,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Default)]
pub struct LoftRevisionForm {
pub revision: i64,
#[serde(default)]
pub flags: [bool; 4],
#[serde(default)]
pub ints: [i64; 2],
pub tail_enum: i64,
#[serde(default)]
pub discontinuities: [Vec<f64>; 6],
pub tail_flag: bool,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct LoftSection {
pub entries: Vec<LoftSectionEntry>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", content = "value", rename_all = "snake_case")]
pub enum LoftBridgeToken {
Boolean(bool),
Integer(i64),
Double(f64),
Text(String),
Enum(i64),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct G2BlendSide {
pub label: String,
pub surface: SurfaceId,
pub curve: CurveId,
pub pcurves: [Option<PcurveGeometry>; 2],
pub direction: Vector3,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum G2BlendFirstShape {
Full {
#[serde(default, skip_serializing_if = "Option::is_none")]
surface: Option<SurfaceId>,
#[serde(default, skip_serializing_if = "Option::is_none")]
tolerance: Option<f64>,
},
None {
coefficients: [f64; 9],
tolerance: f64,
#[serde(default, skip_serializing_if = "Option::is_none")]
extension: Option<LoftBridgeToken>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pcurve: Option<PcurveGeometry>,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct G2BlendConstruction {
pub first: G2BlendSide,
pub singularity: i64,
pub first_shape: G2BlendFirstShape,
pub second: G2BlendSide,
pub second_exact_surface: SurfaceId,
pub center_curve: CurveId,
pub center_parameters: [f64; 2],
pub center_flag: i64,
pub parameter_ranges: [[f64; 2]; 2],
pub trailing_parameters: [f64; 4],
pub discontinuities: [Vec<f64>; 3],
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct RollingBallSide {
pub support_kind: VariableBlendSupportKind,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub surface: Option<SurfaceId>,
#[serde(default)]
pub surface_ranges: [[Option<f64>; 2]; 2],
#[serde(default, skip_serializing_if = "Option::is_none")]
pub curve: Option<CurveId>,
#[serde(default)]
pub curve_range: [Option<f64>; 2],
#[serde(default, skip_serializing_if = "Option::is_none")]
pub pcurve: Option<PcurveGeometry>,
pub location: Point3,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub secondary_pcurve: Option<PcurveGeometry>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extension: Option<i64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub tertiary_pcurve: Option<PcurveGeometry>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct RollingBallThirdSide {
pub label: String,
pub surface: SurfaceId,
pub curve: CurveId,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub pcurve: Option<PcurveGeometry>,
pub direction: Vector3,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub secondary_pcurve: Option<PcurveGeometry>,
pub extension: i64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub tertiary_pcurve: Option<PcurveGeometry>,
pub flag: bool,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum RollingBallRadiusSelector {
None,
Value {
value: f64,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct RollingBallConstruction {
pub definition_index: i64,
pub sides: Box<[RollingBallSide; 2]>,
pub slice: CurveId,
#[serde(default)]
pub slice_range: [Option<f64>; 2],
pub offsets: [f64; 2],
pub radius_selector: RollingBallRadiusSelector,
pub u_range: [Option<f64>; 2],
pub v_range: [Option<f64>; 2],
pub shape_prefix: i64,
pub parameters: [f64; 2],
pub tail: i64,
pub cache_selector: i64,
pub discontinuities: [Vec<f64>; 3],
#[serde(default, skip_serializing_if = "Option::is_none")]
pub third: Option<Box<RollingBallThirdSide>>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum VariableBlendSupportKind {
CosineCurve,
Curve,
PointCurve,
Surface,
ZeroCurve,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum VariableBlendConvexity {
Convex,
Concave,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum VariableBlendRenderMode {
RollingBallEnvelope,
RollingBallSnapshot,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum VariableBlendRadiusKind {
SingleRadius,
TwoRadii,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct VariableBlendInterpolationPoint {
pub parameter: f64,
pub radius: f64,
pub tangents: [f64; 2],
pub location: Point3,
pub normal: Vector3,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct VariableBlendValue {
pub name: String,
pub modern_flag: bool,
pub discriminator: i64,
pub calibrated: i64,
pub payload: VariableBlendValuePayload,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum VariableBlendValuePayload {
TwoEnds {
parameters: [f64; 2],
radii: [f64; 2],
},
FixedWidth {
parameters: [f64; 2],
width: f64,
},
EdgeOffset {
scalars: Vec<f64>,
lengths: Vec<f64>,
},
Functional {
parameter: f64,
radius: f64,
function: PcurveGeometry,
terminal: LoftBridgeToken,
},
Constant {
parameters: [f64; 2],
radius: f64,
variable_chamfer: i64,
chamfer_type: i64,
nested: Box<VariableBlendValue>,
},
Interpolated {
parameter: f64,
radius: f64,
function: PcurveGeometry,
enum_count: i64,
#[serde(default)]
enum_tagged: bool,
points: Vec<VariableBlendInterpolationPoint>,
#[serde(default, skip_serializing_if = "Option::is_none")]
tail: Option<[f64; 2]>,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct VariableBlendSingleRadiusTail {
pub selector: LoftBridgeToken,
pub parameters: [f64; 2],
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum VariableBlendChamferKind {
Rounded,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct VariableBlendChamfer {
pub kind: VariableBlendChamferKind,
pub chamfer_type: i64,
pub value: VariableBlendValue,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct VariableBlendConstruction {
#[serde(alias = "definition_index")]
pub revision: i64,
pub sides: Box<[RollingBallSide; 2]>,
pub slice: CurveId,
#[serde(default)]
pub slice_range: [Option<f64>; 2],
pub offsets: [f64; 2],
pub radius_kind: VariableBlendRadiusKind,
pub first_value: VariableBlendValue,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub second_value: Option<VariableBlendValue>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub chamfer_selector: Option<i64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub chamfer: Option<Box<VariableBlendChamfer>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub single_radius_selector: Option<i64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub single_radius_tail: Option<VariableBlendSingleRadiusTail>,
pub u_range: [Option<f64>; 2],
pub v_range: [Option<f64>; 2],
pub shape_prefix: i64,
pub shape_parameter: f64,
pub shape_length: f64,
pub shape_tail: i64,
pub cache_selector: i64,
pub discontinuities: [Vec<f64>; 6],
pub tail_flag: bool,
pub tail_extensions: [i64; 3],
#[serde(default, skip_serializing_if = "Option::is_none")]
pub secondary_curve: Option<CurveId>,
#[serde(default)]
pub secondary_range: [Option<f64>; 2],
pub convexity: VariableBlendConvexity,
pub render_mode: VariableBlendRenderMode,
pub post_range: [Option<f64>; 2],
#[serde(default, skip_serializing_if = "Option::is_none")]
pub post_curve: Option<CurveId>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub post_pcurve: Option<PcurveGeometry>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct RevisionG2BlendConstruction {
pub revision: i64,
pub leading_parameters: [f64; 2],
pub sides: Box<[RollingBallSide; 2]>,
pub center: CurveId,
#[serde(default)]
pub center_range: [Option<f64>; 2],
pub radii: [f64; 2],
pub radius_selector: i64,
pub u_range: [Option<f64>; 2],
pub v_range: [Option<f64>; 2],
pub shape_prefix: i64,
pub shape_parameter: f64,
pub shape_length: f64,
pub shape_tail: i64,
pub tail_enum: i64,
#[serde(default)]
pub discontinuities: [Vec<f64>; 6],
pub tail_flag: bool,
pub tail_extensions: [i64; 3],
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct RevisionCompoundLoftConstruction {
pub revision: i64,
pub tail_enum: i64,
#[serde(default)]
pub discontinuities: [Vec<f64>; 6],
pub tail_flag: bool,
pub base_profile: Vec<LoftProfileMember>,
pub base_path: LoftPath,
pub entries: Vec<LoftSectionEntry>,
pub flags: [bool; 2],
pub kind: i64,
pub kind_flags: [bool; 2],
pub selector: i64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub direction: Option<Vector3>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub direction_curve: Option<CurveId>,
#[serde(default)]
pub interval: [Option<f64>; 2],
#[serde(default, skip_serializing_if = "Option::is_none")]
pub trailing_curve: Option<CurveId>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct VertexBlendBoundary {
pub boundary_type: i64,
pub magic: Point3,
pub u_smoothing: i64,
pub v_smoothing: i64,
pub fullness: f64,
pub geometry: VertexBlendBoundaryGeometry,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum VertexBlendBoundaryGeometry {
Circle {
curve: CurveId,
#[serde(default)]
curve_endpoints: [Option<f64>; 2],
form: i64,
twists: Vec<Point3>,
parameters: [f64; 2],
sense: i64,
},
Degenerate {
location: Point3,
normals: [Vector3; 2],
},
Pcurve {
surface: SurfaceId,
#[serde(default)]
support_bounds: [Option<f64>; 4],
#[serde(default, skip_serializing_if = "Option::is_none")]
pcurve: Option<PcurveGeometry>,
sense: i64,
fit_tolerance: f64,
},
Plane {
normal: Vector3,
parameters: [f64; 2],
curve: CurveId,
#[serde(default)]
curve_endpoints: [Option<f64>; 2],
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct VertexBlendConstruction {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub revision: Option<i64>,
pub boundaries: Vec<VertexBlendBoundary>,
pub grid_size: i64,
pub fit_tolerance: f64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct CompoundLoftScaleMember {
pub type_code: i64,
pub curve: CurveId,
pub data: LoftProfileData,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct CompoundLoftScale {
pub members: Vec<CompoundLoftScaleMember>,
pub path: CurveId,
pub auxiliaries: Vec<CurveId>,
pub tail: [i64; 2],
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum CompoundLoftDirection {
Vector {
value: Vector3,
},
Curve {
curve: CurveId,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum CompoundLoftTail {
Six {
flags: [bool; 2],
scale: Box<CompoundLoftScale>,
selector: i64,
direction: Vector3,
parameter_range: [f64; 2],
curve: CurveId,
},
Seven {
first_flag: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
first_scale: Option<Box<CompoundLoftScale>>,
second_flag: bool,
second_scale: Box<CompoundLoftScale>,
selector: i64,
direction: Vector3,
trailing_flags: [bool; 2],
},
Zero {
flags: [bool; 2],
selector: i64,
direction: CompoundLoftDirection,
trailing_flags: [bool; 2],
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct CompoundLoftConstruction {
pub scales: Box<[Option<CompoundLoftScale>; 4]>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub fifth_scale: Option<Box<CompoundLoftScale>>,
pub flags: [bool; 2],
pub tail: CompoundLoftTail,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum ScaledCompoundLoftShape {
Full,
None {
parameter_ranges: [[f64; 2]; 2],
parameters: [Vec<f64>; 2],
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum ScaledCompoundLoftBranch {
ExtendedVector {
#[serde(default, skip_serializing_if = "Option::is_none")]
first_scale: Option<Box<CompoundLoftScale>>,
second_scale: Box<CompoundLoftScale>,
selector: i64,
direction: Vector3,
},
ExtendedCurve {
#[serde(default, skip_serializing_if = "Option::is_none")]
scale: Option<Box<CompoundLoftScale>>,
flag: bool,
singularity: i64,
curve: CurveId,
},
Direct {
flag: bool,
selector: i64,
direction: CompoundLoftDirection,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct ScaledCompoundLoftConstruction {
pub singularity: i64,
pub shape: ScaledCompoundLoftShape,
pub discontinuities: [Vec<f64>; 6],
pub discontinuity_flag: bool,
pub scales: Box<[Option<CompoundLoftScale>; 3]>,
pub flags: [bool; 2],
pub selector: i64,
pub branch: ScaledCompoundLoftBranch,
pub trailing_flags: [bool; 2],
pub tail_kind: i64,
pub tail_directions: [Vector3; 2],
pub tail_singularity: i64,
pub tail_curve: CurveId,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct LawFormula {
pub name: String,
pub variables: Vec<LawExpression>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct LawSurfaceConstruction {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub parameter_ranges: Option<[[f64; 2]; 2]>,
pub primary: LawFormula,
pub additional: Vec<LawFormula>,
pub tail: LawSurfaceTail,
pub discontinuities: [Vec<f64>; 6],
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum LawSurfaceTail {
Full,
Summary {
parameters: [Vec<f64>; 2],
fit_tolerance: f64,
closures: [i64; 2],
singularities: [i64; 2],
},
None {
parameter_ranges: [[f64; 2]; 2],
closures: [i64; 2],
singularities: [i64; 2],
},
Historical,
Optimal,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum LawExpression {
Null,
Integer {
value: i64,
},
Double {
value: f64,
},
Point {
value: Point3,
},
Vector {
value: Vector3,
},
Transform {
scalars: [f64; 13],
enums: [i64; 3],
},
Edge {
curve: CurveId,
#[serde(default, skip_serializing_if = "Option::is_none")]
endpoints: Option<[Option<f64>; 2]>,
parameters: [f64; 2],
},
Spline {
native_id: i64,
knots: Vec<f64>,
controls: Vec<f64>,
point: Point3,
},
Algebraic {
operator: String,
operands: Vec<LawExpression>,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct SkinSurfaceProfile {
pub type_code: i64,
pub curve: CurveId,
pub data: LoftProfileData,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum SkinSurfaceLayout {
Profiles {
profiles: Vec<SkinSurfaceProfile>,
path: CurveId,
tail: [i64; 2],
},
Compact {
curve: CurveId,
subdata: LoftSubdata,
first_tail: i64,
secondary_curve: CurveId,
second_tail: i64,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct SkinSurfaceConstruction {
pub surface_boolean: i64,
pub surface_normal: i64,
pub surface_direction: i64,
pub count: i64,
pub parameter: f64,
pub inner_count: i64,
pub layout: SkinSurfaceLayout,
pub direction: Vector3,
pub trailing_parameter: f64,
pub formula: LawFormula,
pub parameter_curve: CurveId,
pub discontinuities: [Vec<f64>; 6],
pub discontinuity_flag: bool,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct NetSurfaceConstruction {
pub sections: Box<[LoftSection; 2]>,
pub frame_parameters: [f64; 12],
pub flag: i64,
pub directions: [Vector3; 4],
pub formulas: Box<[LawFormula; 4]>,
pub discontinuities: [Vec<f64>; 6],
pub discontinuity_flag: bool,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum SweepSurfaceLayout {
ProfileFirst {
secondary_kind: i64,
directions: [Vector3; 5],
origin: Point3,
parameters: [f64; 4],
formulas: Box<[LawFormula; 3]>,
},
ExplicitFormula {
mode: i64,
profile_range: [f64; 2],
profile_frame: Option<(Point3, Vector3)>,
origin: Point3,
directions: [Vector3; 3],
trajectory_flag: bool,
path_range: [f64; 2],
path_parameter: f64,
formula_flag: bool,
formula: LawFormula,
trailing_flag: bool,
},
ExplicitGuide {
mode: i64,
profile_range: [f64; 2],
profile_frame: Option<(Point3, Vector3)>,
origin: Point3,
directions: [Vector3; 3],
trajectory_flag: bool,
path_range: [f64; 2],
path_parameter: f64,
guide_flags: [bool; 2],
guide_curve: CurveId,
guide_range: [f64; 2],
guide_modes: [i64; 2],
guide_parameters: [f64; 6],
trailing_flags: [bool; 3],
},
ExplicitSurface {
mode: i64,
profile_range: [f64; 2],
profile_frame: Option<(Point3, Vector3)>,
origin: Point3,
directions: [Vector3; 3],
trajectory_flag: bool,
path_range: [f64; 2],
path_parameter: f64,
singularity: i64,
support_surface: SurfaceId,
auxiliary_curve: Option<CurveId>,
support_flag: bool,
legacy_flag: Option<bool>,
},
LawDriven {
mode: i64,
profile_range: [f64; 2],
profile_frame: Option<(Point3, Vector3)>,
origin: Point3,
directions: [Vector3; 3],
first_law: Box<LawExpression>,
first_mode: i64,
first_range: [f64; 2],
law_direction: Vector3,
path_mode: i64,
path_flag: bool,
path_range: [f64; 2],
path_parameter: f64,
second_law_flag: bool,
second_law: Box<LawExpression>,
formula_mode: i64,
formula: LawFormula,
trailing_flag: bool,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Default)]
pub struct SweepRevisionForm {
pub revision: i64,
pub primary_flag: bool,
#[serde(default)]
pub profile_endpoints: [Option<f64>; 2],
#[serde(default)]
pub path_endpoints: [Option<f64>; 2],
pub tail_enum: i64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct SweepSurfaceConstruction {
pub primary_kind: i64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub revision_form: Option<SweepRevisionForm>,
pub layout: SweepSurfaceLayout,
pub discontinuities: [Vec<f64>; 6],
pub discontinuity_flag: bool,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum BlendRadiusLaw {
Constant {
signed_radius: f64,
},
Linear {
start: f64,
end: f64,
},
Law {
curve: NurbsCurve,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct ProceduralCurve {
pub id: ProceduralCurveId,
pub curve: CurveId,
pub definition: ProceduralCurveDefinition,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub cache_fit_tolerance: Option<f64>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct IntcurveSupportSide {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub surface: Option<SurfaceId>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub pcurve: Option<PcurveGeometry>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub pcurve_parameter_range: Option<[f64; 2]>,
}
impl IntcurveSupportSide {
#[must_use]
pub fn pcurve_parameter(
&self,
solved_parameter_range: [f64; 2],
parameter: f64,
) -> Option<f64> {
self.pcurve.as_ref()?;
let Some(pcurve_range) = self.pcurve_parameter_range else {
return Some(parameter);
};
let solved_span = solved_parameter_range[1] - solved_parameter_range[0];
if solved_span == 0.0 {
return None;
}
let fraction = (parameter - solved_parameter_range[0]) / solved_span;
Some(pcurve_range[0] + fraction * (pcurve_range[1] - pcurve_range[0]))
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct IntcurveSupportContext {
pub sides: [IntcurveSupportSide; 2],
pub parameter_range: [f64; 2],
pub discontinuities: [Vec<f64>; 3],
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Default)]
pub struct CacheFirstCurveForm {
pub revision: i64,
#[serde(default)]
pub support_bounds: [[Option<f64>; 4]; 2],
#[serde(default)]
pub solved_range: [Option<f64>; 2],
pub extension: i64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct SurfaceCurveTail {
pub extension: i64,
pub flag: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub second_flag: Option<bool>,
#[serde(default)]
pub revision: i64,
#[serde(default)]
pub support_bounds: [[Option<f64>; 4]; 2],
#[serde(default)]
pub solved_range: [Option<f64>; 2],
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum ProjectionTail {
EarlyClose {
flag: bool,
},
Ranged {
flag: bool,
parameter_range: [f64; 2],
role: String,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum SurfaceCurveFamily {
Blend,
SurfaceConstrained,
Parametric,
Skin,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum SilhouetteKind {
Standard,
Parametric,
Taper {
draft_factor: f64,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum DeformableCurveData {
VectorField {
vectors: [Vector3; 4],
parameter_pairs: Vec<[f64; 2]>,
},
Surface {
surface: SurfaceId,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum ProceduralCurveDefinition {
Exact,
Law {
context: IntcurveSupportContext,
extension: i64,
primary: LawFormula,
additional: Vec<LawFormula>,
},
Compound {
parameters: Vec<f64>,
component_parameters: Vec<f64>,
components: Vec<CurveId>,
},
Helix {
angle_range: [f64; 2],
center: Point3,
major: Vector3,
minor: Vector3,
pitch: Vector3,
apex_factor: f64,
axis: Vector3,
},
Intersection {
context: IntcurveSupportContext,
discontinuity_flag: bool,
},
ThreeSurfaceIntersection {
context: IntcurveSupportContext,
selector: i64,
third: IntcurveSupportSide,
},
SurfaceCurve {
family: SurfaceCurveFamily,
context: IntcurveSupportContext,
#[serde(default, skip_serializing_if = "Option::is_none")]
tail: Option<SurfaceCurveTail>,
},
Silhouette {
context: IntcurveSupportContext,
silhouette: SilhouetteKind,
cast_surface: SurfaceId,
light_direction: Vector3,
},
SurfaceOffset {
context: IntcurveSupportContext,
discontinuity_flag: bool,
base_u_range: [f64; 2],
base_v_range: [f64; 2],
base: CurveId,
base_range: [f64; 2],
#[serde(default)]
base_endpoints: [Option<f64>; 2],
#[serde(default, skip_serializing_if = "Option::is_none")]
cache_first: Option<CacheFirstCurveForm>,
distance: f64,
shift: f64,
scale: f64,
},
Spring {
context: IntcurveSupportContext,
surface_parameter_ranges: [Option<[[f64; 2]; 2]>; 2],
#[serde(default, skip_serializing_if = "Option::is_none")]
first_pcurve_parameter_range: Option<[f64; 2]>,
discontinuity_flag: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
cache_first: Option<CacheFirstCurveForm>,
direction: i64,
},
Deformable {
extension: i64,
bend: CurveId,
data: DeformableCurveData,
},
Projection {
context: IntcurveSupportContext,
discontinuity_flag: bool,
source: CurveId,
tail: ProjectionTail,
},
Offset {
source: CurveId,
distance: f64,
#[serde(default, skip_serializing_if = "Option::is_none")]
direction: Option<Vector3>,
#[serde(default, skip_serializing_if = "Option::is_none")]
support: Option<SurfaceId>,
#[serde(default, skip_serializing_if = "Option::is_none")]
normal: Option<Vector3>,
#[serde(default, skip_serializing_if = "Option::is_none")]
parameter_range: Option<[f64; 2]>,
#[serde(default, skip_serializing_if = "Option::is_none")]
distance_law: Option<CurveOffsetDistanceLaw>,
},
SpatialOffset {
source: CurveId,
distance: f64,
reference_direction: Vector3,
self_intersect: Option<bool>,
},
TwoSidedOffset {
context: IntcurveSupportContext,
discontinuity_flag: bool,
offsets: [f64; 2],
},
VectorOffset {
source: CurveId,
parameter_range: [f64; 2],
offset: Vector3,
labels: [String; 2],
codes: [i64; 2],
},
Subset {
source: CurveId,
parameter_range: [f64; 2],
},
BlendSpine {
#[serde(default, skip_serializing_if = "Option::is_none")]
blend_surface: Option<SurfaceId>,
},
Unknown {
#[serde(default, skip_serializing_if = "Option::is_none")]
native_kind: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
record: Option<UnknownId>,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum CurveOffsetLawBasis {
ArcLength,
Parameter,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum CurveOffsetDistanceLaw {
Linear {
basis: CurveOffsetLawBasis,
distances: [f64; 2],
control_range: [f64; 2],
},
Coordinate {
function: CurveId,
coordinate: u8,
basis: CurveOffsetLawBasis,
function_parameter_offset: f64,
function_parameter_scale: f64,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum PcurveGeometry {
Line {
origin: Point2,
direction: Point2,
},
PolarHarmonic {
radial_center: Point2,
radial_cos: Point2,
radial_sin: Point2,
axial_origin: f64,
axial_cos: f64,
axial_sin: f64,
},
PolarNurbs {
degree: u32,
knots: Vec<f64>,
radial_control_points: Vec<Point2>,
axial_control_points: Vec<f64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
weights: Option<Vec<f64>>,
#[serde(default)]
periodic: bool,
},
Circle {
center: Point2,
x_axis: Point2,
y_axis: Point2,
radius: f64,
},
Ellipse {
center: Point2,
x_axis: Point2,
y_axis: Point2,
major_radius: f64,
minor_radius: f64,
},
Parabola {
vertex: Point2,
x_axis: Point2,
y_axis: Point2,
focal_distance: f64,
},
Hyperbola {
center: Point2,
x_axis: Point2,
y_axis: Point2,
major_radius: f64,
minor_radius: f64,
},
Nurbs {
degree: u32,
knots: Vec<f64>,
control_points: Vec<Point2>,
#[serde(default, skip_serializing_if = "Option::is_none")]
weights: Option<Vec<f64>>,
#[serde(default)]
periodic: bool,
},
Trimmed {
parameter_range: [f64; 2],
basis: Box<PcurveGeometry>,
},
Offset {
distance: f64,
basis: Box<PcurveGeometry>,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct Pcurve {
pub id: PcurveId,
pub geometry: PcurveGeometry,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub wrapper_reversed: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub native_tail_flags: Option<[bool; 4]>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub parameter_range: Option<[f64; 2]>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub fit_tolerance: Option<f64>,
}