use crate::types::{Color, Handle, Matrix4, Vector2, Vector3};
pub trait StubObject {
fn new_stub() -> Self;
fn set_handle(&mut self, handle: Handle);
fn set_owner(&mut self, owner: Handle);
fn handle(&self) -> Handle;
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum VisualStylePropertyValue {
Short(i16),
Long(i32),
Double(f64),
Bool(bool),
Color(Color),
Text(String),
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct VisualStyleProperty {
pub value: VisualStylePropertyValue,
pub enabled: i16,
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(default))]
pub struct VisualStyle {
pub handle: Handle,
pub owner: Handle,
pub reactors: Vec<Handle>,
pub xdictionary_handle: Option<Handle>,
pub description: String,
pub style_type: i16,
pub face_lighting_model: i16,
pub face_lighting_quality: i16,
pub face_color_mode: i16,
pub face_modifier: i32,
pub edge_model: i32,
pub edge_style: i32,
pub internal_use_only: bool,
pub extended_lighting_model: i16,
pub properties: Vec<VisualStyleProperty>,
}
impl VisualStyle {
pub fn new() -> Self {
VisualStyle {
handle: Handle::NULL,
owner: Handle::NULL,
reactors: Vec::new(),
xdictionary_handle: None,
description: String::new(),
style_type: 0,
face_lighting_model: 0,
face_lighting_quality: 0,
face_color_mode: 0,
face_modifier: 0,
edge_model: 0,
edge_style: 0,
internal_use_only: false,
extended_lighting_model: 2,
properties: Vec::new(),
}
}
pub(crate) fn core_properties(&self) -> Vec<VisualStyleProperty> {
let long = |value| VisualStyleProperty {
value: VisualStylePropertyValue::Long(value),
enabled: 1,
};
let double = |value| VisualStyleProperty {
value: VisualStylePropertyValue::Double(value),
enabled: 1,
};
let bool_value = |value| VisualStyleProperty {
value: VisualStylePropertyValue::Bool(value),
enabled: 1,
};
let color = |value| VisualStyleProperty {
value: VisualStylePropertyValue::Color(value),
enabled: 1,
};
let mut values = vec![
long(self.face_lighting_model as i32),
long(self.face_lighting_quality as i32),
long(self.face_color_mode as i32),
long(self.face_modifier),
double(0.6),
double(30.0),
color(Color::Index(7)),
long(self.edge_model),
long(self.edge_style),
color(Color::ByLayer),
color(Color::ByBlock),
long(1),
long(1),
double(1.0),
long(0),
color(Color::ByLayer),
double(1.0),
long(1),
long(6),
long(2),
color(Color::ByLayer),
long(5),
long(0),
long(0),
bool_value(false),
long(1),
double(0.0),
long(0),
];
if self.properties.len() >= 28 {
values.clone_from_slice(&self.properties[..28]);
} else if self.properties.len() == 24 {
for (legacy, modern) in [
(0, 4),
(1, 5),
(2, 6),
(3, 9),
(4, 10),
(5, 11),
(6, 13),
(7, 14),
(8, 15),
(9, 16),
(10, 17),
(11, 18),
(12, 19),
(13, 20),
(14, 21),
(15, 22),
(16, 23),
(17, 24),
(19, 12),
(20, 25),
(21, 26),
(22, 27),
] {
let source = &self.properties[legacy];
let number = match &source.value {
VisualStylePropertyValue::Short(v) => Some(*v as f64),
VisualStylePropertyValue::Long(v) => Some(*v as f64),
VisualStylePropertyValue::Double(v) => Some(*v),
VisualStylePropertyValue::Bool(v) => Some(*v as u8 as f64),
_ => None,
};
let value = match (&values[modern].value, number) {
(VisualStylePropertyValue::Long(_), Some(n)) => {
VisualStylePropertyValue::Long(n as i32)
}
(VisualStylePropertyValue::Double(_), Some(n))
if modern == 4 || modern == 5 =>
{
VisualStylePropertyValue::Double(n.abs())
}
(VisualStylePropertyValue::Double(_), Some(n)) => {
VisualStylePropertyValue::Double(n)
}
(VisualStylePropertyValue::Bool(_), Some(n)) => {
VisualStylePropertyValue::Bool(n != 0.0)
}
_ => source.value.clone(),
};
values[modern] = VisualStyleProperty {
value,
enabled: source.enabled,
};
}
} else {
for (index, property) in self.properties.iter().take(28).enumerate() {
values[index] = property.clone();
}
}
values[0].value = VisualStylePropertyValue::Long(self.face_lighting_model as i32);
values[1].value = VisualStylePropertyValue::Long(self.face_lighting_quality as i32);
values[2].value = VisualStylePropertyValue::Long(self.face_color_mode as i32);
values[3].value = VisualStylePropertyValue::Long(self.face_modifier);
values[7].value = VisualStylePropertyValue::Long(self.edge_model);
values[8].value = VisualStylePropertyValue::Long(self.edge_style);
values
}
pub(crate) fn extended_properties(&self) -> Vec<VisualStyleProperty> {
if self.properties.len() >= 58 {
return self.properties[28..58].to_vec();
}
let long = |value| VisualStyleProperty {
value: VisualStylePropertyValue::Long(value),
enabled: 1,
};
let double = |value| VisualStyleProperty {
value: VisualStylePropertyValue::Double(value),
enabled: 1,
};
let bool_value = |value| VisualStyleProperty {
value: VisualStylePropertyValue::Bool(value),
enabled: 1,
};
let color = |value, enabled| VisualStyleProperty {
value: VisualStylePropertyValue::Color(value),
enabled,
};
let text = |value: &str| VisualStyleProperty {
value: VisualStylePropertyValue::Text(value.to_string()),
enabled: 1,
};
vec![
bool_value(false),
bool_value(true),
bool_value(true),
bool_value(false),
bool_value(false),
bool_value(false),
bool_value(false),
bool_value(false),
bool_value(false),
long(50),
double(0.0),
double(1.0),
long(0),
color(Color::Rgb { r: 0, g: 0, b: 0 }, 1),
long(50),
long(3),
color(Color::Rgb { r: 0, g: 0, b: 255 }, 1),
bool_value(false),
long(50),
long(50),
long(50),
bool_value(false),
long(50),
color(Color::ByLayer, 0),
VisualStyleProperty {
value: VisualStylePropertyValue::Double(1.0),
enabled: 0,
},
long(2),
text("strokes_ogs.tif"),
bool_value(false),
double(1.0),
double(1.0),
]
}
pub(crate) fn legacy_properties(&self) -> Vec<VisualStyleProperty> {
if self.properties.len() == 24 {
return self.properties.clone();
}
let core = self.core_properties();
let short = |value| VisualStyleProperty {
value: VisualStylePropertyValue::Short(value),
enabled: 1,
};
let double = |value| VisualStyleProperty {
value: VisualStylePropertyValue::Double(value),
enabled: 1,
};
let signed = |property: &VisualStyleProperty, bit: i32| {
let mut property = property.clone();
if let VisualStylePropertyValue::Double(value) = &mut property.value {
*value = if self.face_modifier & bit != 0 {
value.abs()
} else {
-value.abs()
};
}
property
};
vec![
signed(&core[4], 1),
signed(&core[5], 2),
core[6].clone(),
core[9].clone(),
core[10].clone(),
core[11].clone(),
core[13].clone(),
core[14].clone(),
core[15].clone(),
core[16].clone(),
core[17].clone(),
core[18].clone(),
core[19].clone(),
core[20].clone(),
core[21].clone(),
core[22].clone(),
core[23].clone(),
core[24].clone(),
short(0),
core[12].clone(),
core[25].clone(),
core[26].clone(),
core[27].clone(),
double(0.0),
]
}
pub(crate) fn restore_post_2010_properties(
&mut self,
entries: &[crate::objects::XRecordEntry],
) -> bool {
use crate::objects::XRecordValue;
if self.properties.len() != 24 {
return false;
}
let mut properties = self.core_properties();
properties.extend(self.extended_properties());
let mut color_index = None;
let mut found = false;
for pair in entries.windows(2) {
let (Some(key), value) = (pair[0].value.as_string(), &pair[1].value) else {
continue;
};
let flag = match value {
XRecordValue::Int16(v) => Some(*v),
_ => None,
};
if let Some(index) = key.strip_prefix("RTVSPropertyOp") {
if let (Ok(index), Some(flag)) = (index.parse::<usize>(), flag) {
if let Some(property) = properties.get_mut(index) {
property.enabled = flag;
found = true;
}
}
continue;
}
if let Some(index) = key.strip_prefix("RTVSPost2010PropOp") {
if let (Ok(index), Some(flag)) = (index.parse::<usize>(), flag) {
if let Some(property) = properties.get_mut(index) {
property.enabled = flag;
found = true;
}
}
continue;
}
let Some(rest) = key.strip_prefix("RTVSPost2010Prop") else {
continue;
};
let digits = rest.bytes().take_while(u8::is_ascii_digit).count();
let Ok(index) = rest[..digits].parse::<usize>() else {
continue;
};
let Some(property) = properties.get_mut(index) else {
continue;
};
let number = match value {
XRecordValue::Byte(v) => Some(*v as f64),
XRecordValue::Int16(v) => Some(*v as f64),
XRecordValue::Int32(v) => Some(*v as f64),
XRecordValue::Double(v) => Some(*v),
XRecordValue::Bool(v) => Some(*v as u8 as f64),
_ => None,
};
let new_value = match (&rest[digits..], &property.value, number) {
("ColorIndex", _, Some(n)) => {
color_index = Some(n as i16);
continue;
}
("ColorRGB", _, Some(n)) => {
let raw = n as i64 as i32;
let index = color_index.take().unwrap_or(256);
VisualStylePropertyValue::Color(match index {
0 | 256 | 257 => Color::from_index(index),
_ if (raw as u32) >> 24 == 0 => Color::from_true_color_value(raw),
_ => Color::from_index(index),
})
}
("", VisualStylePropertyValue::Bool(_), Some(n)) => {
VisualStylePropertyValue::Bool(n != 0.0)
}
("", VisualStylePropertyValue::Long(_), Some(n)) => {
VisualStylePropertyValue::Long(n as i32)
}
("", VisualStylePropertyValue::Double(_), Some(n)) => {
VisualStylePropertyValue::Double(n)
}
("", VisualStylePropertyValue::Text(_), _) => match value.as_string() {
Some(text) => VisualStylePropertyValue::Text(text.to_string()),
None => continue,
},
_ => continue,
};
property.value = new_value;
found = true;
}
if found {
self.properties = properties;
}
found
}
}
pub(crate) fn store_visual_style_roundtrip(document: &mut crate::document::CadDocument) {
use crate::objects::{ObjectType, XRecordEntry, XRecordValue};
use crate::types::DxfVersion;
if !(DxfVersion::AC1018..DxfVersion::AC1024).contains(&document.version) {
return;
}
let mut styles: Vec<_> = document
.objects
.iter()
.filter_map(|(handle, object)| match object {
ObjectType::VisualStyle(style) if style.properties.len() >= 58 => {
Some((*handle, style.properties.clone()))
}
_ => None,
})
.collect();
styles.sort_by_key(|style| style.0);
let key = |text: String| XRecordEntry {
code: 102,
value: XRecordValue::String(text),
};
for (handle, properties) in styles {
let mut group = Vec::new();
for (index, property) in properties.iter().enumerate().take(58).skip(28) {
let name = format!("RTVSPost2010Prop{index}");
match &property.value {
VisualStylePropertyValue::Color(color) => {
let (aci, rgb) = match color {
Color::Rgb { .. } => (
color.approximate_index() as i32,
color.to_true_color_value().unwrap_or_default(),
),
_ => (color.approximate_index() as i32, 0xFF00_0000_u32 as i32),
};
group.push(key(format!("{name}ColorIndex")));
group.push(XRecordEntry {
code: 90,
value: XRecordValue::Int32(aci),
});
group.push(key(format!("{name}ColorRGB")));
group.push(XRecordEntry {
code: 90,
value: XRecordValue::Int32(rgb),
});
}
value => {
group.push(key(name));
group.push(match value {
VisualStylePropertyValue::Bool(v) => XRecordEntry {
code: 280,
value: XRecordValue::Byte(*v as u8),
},
VisualStylePropertyValue::Short(v) => XRecordEntry {
code: 90,
value: XRecordValue::Int32(*v as i32),
},
VisualStylePropertyValue::Long(v) => XRecordEntry {
code: 90,
value: XRecordValue::Int32(*v),
},
VisualStylePropertyValue::Double(v) => XRecordEntry {
code: 140,
value: XRecordValue::Double(*v),
},
VisualStylePropertyValue::Text(v) => XRecordEntry {
code: 1,
value: XRecordValue::String(v.clone()),
},
VisualStylePropertyValue::Color(_) => unreachable!(),
});
}
}
group.push(key(format!("RTVSPost2010PropOp{index}")));
group.push(XRecordEntry {
code: 70,
value: XRecordValue::Int16(property.enabled),
});
}
for index in 0..63 {
group.push(key(format!("RTVSPropertyOp{index}")));
group.push(XRecordEntry {
code: 70,
value: XRecordValue::Int16(properties.get(index).map_or(1, |p| p.enabled)),
});
}
let record = document.ensure_xrecord(handle, "ACAD_XREC_ROUNDTRIP");
let Some(ObjectType::XRecord(record)) = document.objects.get_mut(&record) else {
continue;
};
let mut kept = Vec::with_capacity(record.entries.len());
let mut entries = std::mem::take(&mut record.entries).into_iter();
while let Some(entry) = entries.next() {
if entry.code == 102
&& entry
.value
.as_string()
.is_some_and(|text| text.starts_with("RTVS"))
{
entries.next();
continue;
}
kept.push(entry);
}
kept.extend(group);
record.entries = kept;
}
}
pub(crate) fn restore_visual_style_roundtrip(document: &mut crate::document::CadDocument) {
use crate::objects::ObjectType;
let records: Vec<_> = document
.objects
.iter()
.filter_map(|(handle, object)| {
let ObjectType::VisualStyle(style) = object else {
return None;
};
if style.properties.len() != 24 {
return None;
}
let Some(ObjectType::Dictionary(dictionary)) =
document.objects.get(&style.xdictionary_handle?)
else {
return None;
};
let (_, record) = dictionary
.entries
.iter()
.find(|(name, _)| name == "ACAD_XREC_ROUNDTRIP")?;
let Some(ObjectType::XRecord(record)) = document.objects.get(record) else {
return None;
};
Some((*handle, record.entries.clone()))
})
.collect();
for (handle, entries) in records {
if let Some(ObjectType::VisualStyle(style)) = document.objects.get_mut(&handle) {
style.restore_post_2010_properties(&entries);
}
}
}
impl Default for VisualStyle {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MaterialColor {
pub flag: u8,
pub factor: f64,
pub rgb: Option<i32>,
}
impl Default for MaterialColor {
fn default() -> Self {
Self {
flag: 0,
factor: 1.0,
rgb: None,
}
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum MaterialProceduralValue {
Bool(bool),
Integer(i16),
Real(f64),
Color(Color),
Text(String),
Table(Vec<(String, MaterialTexture)>),
}
#[derive(Debug, Clone, PartialEq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MaterialTexture {
pub mode: i16,
pub color1: MaterialColor,
pub color2: MaterialColor,
pub procedural: Option<MaterialProceduralValue>,
pub table_end: bool,
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MaterialMap {
pub blend_factor: f64,
pub projection: u8,
pub tiling: u8,
pub auto_transform: u8,
pub transform: [f64; 16],
pub source: u8,
pub file_name: String,
pub texture: Option<MaterialTexture>,
}
impl Default for MaterialMap {
fn default() -> Self {
let mut transform = [0.0; 16];
transform[0] = 1.0;
transform[5] = 1.0;
transform[10] = 1.0;
transform[15] = 1.0;
Self {
blend_factor: 1.0,
projection: 2,
tiling: 1,
auto_transform: 1,
transform,
source: 0,
file_name: String::new(),
texture: None,
}
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(default))]
pub struct Material {
pub handle: Handle,
pub owner: Handle,
pub reactors: Vec<Handle>,
pub xdictionary_handle: Option<Handle>,
pub name: String,
pub description: String,
pub ambient_color: MaterialColor,
pub diffuse_color: MaterialColor,
pub diffuse_map: MaterialMap,
pub specular_color: MaterialColor,
pub specular_map: MaterialMap,
pub specular_gloss_factor: f64,
pub reflection_map: MaterialMap,
pub opacity_percent: f64,
pub opacity_map: MaterialMap,
pub bump_map: MaterialMap,
pub refraction_index: f64,
pub refraction_map: MaterialMap,
pub translucence: f64,
pub self_illumination: f64,
pub reflectivity: f64,
pub illumination_model: i32,
pub channel_flags: i32,
pub mode: i32,
pub indirect_bump_scale: f64,
pub reflectance_scale: f64,
pub transmittance_scale: f64,
pub two_sided_material: bool,
pub luminance: f64,
pub luminance_mode: i16,
pub normal_map_method: i16,
pub normal_map_strength: f64,
pub normal_map: MaterialMap,
pub is_anonymous: bool,
pub global_illumination: i16,
pub final_gather: i16,
pub color_bleed_scale: f64,
pub advanced_data_present: bool,
}
impl Material {
pub fn new() -> Self {
Material {
handle: Handle::NULL,
owner: Handle::NULL,
reactors: Vec::new(),
xdictionary_handle: None,
name: String::new(),
description: String::new(),
ambient_color: MaterialColor::default(),
diffuse_color: MaterialColor::default(),
diffuse_map: MaterialMap::default(),
specular_color: MaterialColor::default(),
specular_map: MaterialMap::default(),
specular_gloss_factor: 0.5,
reflection_map: MaterialMap::default(),
opacity_percent: 1.0,
opacity_map: MaterialMap::default(),
bump_map: MaterialMap::default(),
refraction_index: 1.0,
refraction_map: MaterialMap::default(),
translucence: 0.0,
self_illumination: 0.0,
reflectivity: 0.0,
illumination_model: 0,
channel_flags: 127,
mode: 0,
indirect_bump_scale: 1.0,
reflectance_scale: 1.0,
transmittance_scale: 1.0,
two_sided_material: false,
luminance: 0.0,
luminance_mode: 0,
normal_map_method: 0,
normal_map_strength: 1.0,
normal_map: MaterialMap::default(),
is_anonymous: false,
global_illumination: 0,
final_gather: 0,
color_bleed_scale: 1.0,
advanced_data_present: false,
}
}
pub(crate) fn has_advanced_data(&self) -> bool {
self.advanced_data_present
|| self.indirect_bump_scale != 1.0
|| self.reflectance_scale != 1.0
|| self.transmittance_scale != 1.0
|| self.two_sided_material
|| self.luminance != 0.0
|| self.luminance_mode != 0
|| self.normal_map_method != 0
|| self.normal_map_strength != 1.0
|| self.normal_map != MaterialMap::default()
|| self.is_anonymous
|| self.global_illumination != 0
|| self.final_gather != 0
|| self.color_bleed_scale != 1.0
}
}
impl Default for Material {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct GeoDataMeshPoint {
pub source: Vector2,
pub destination: Vector2,
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct GeoDataMeshFace {
pub first: i32,
pub second: i32,
pub third: i32,
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(default))]
pub struct GeoData {
pub handle: Handle,
pub owner: Handle,
pub reactors: Vec<Handle>,
pub xdictionary_handle: Option<Handle>,
pub version: i32,
pub host_block: Handle,
pub coordinate_type: i16,
pub design_point: Vector3,
pub reference_point: Vector3,
pub obsolete_observation_point: Vector3,
pub obsolete_scale_vector: Vector3,
pub north_direction: Vector2,
pub up_direction: Vector3,
pub horizontal_unit_scale: f64,
pub vertical_unit_scale: f64,
pub horizontal_units: i32,
pub vertical_units: i32,
pub scale_estimation_method: i32,
pub user_scale_factor: f64,
pub sea_level_correction: bool,
pub sea_level_elevation: f64,
pub coordinate_projection_radius: f64,
pub coordinate_system_definition: String,
pub coordinate_system_datum: String,
pub coordinate_system_wkt: String,
pub geo_rss_tag: String,
pub observation_from_tag: String,
pub observation_to_tag: String,
pub observation_coverage_tag: String,
pub mesh_points: Vec<GeoDataMeshPoint>,
pub mesh_faces: Vec<GeoDataMeshFace>,
pub civil_data_present: bool,
pub civil_obsolete_flag: bool,
pub civil_reference_point1: Vector2,
pub civil_reference_point2: Vector2,
pub civil_unknown1: i32,
pub civil_unknown2: i32,
pub civil_unknown_flag1: bool,
pub civil_zero_point1: Vector2,
pub civil_zero_point2: Vector2,
pub civil_unknown_flag2: bool,
pub civil_north_angle_degrees: f64,
pub civil_north_angle_radians: f64,
}
impl GeoData {
pub fn new() -> Self {
GeoData {
handle: Handle::NULL,
owner: Handle::NULL,
reactors: Vec::new(),
xdictionary_handle: None,
version: 2,
host_block: Handle::NULL,
coordinate_type: 0,
design_point: Vector3::default(),
reference_point: Vector3::default(),
obsolete_observation_point: Vector3::default(),
obsolete_scale_vector: Vector3::new(1.0, 1.0, 1.0),
north_direction: Vector2::default(),
up_direction: Vector3::default(),
horizontal_unit_scale: 1.0,
vertical_unit_scale: 1.0,
horizontal_units: 0,
vertical_units: 0,
scale_estimation_method: 0,
user_scale_factor: 1.0,
sea_level_correction: false,
sea_level_elevation: 0.0,
coordinate_projection_radius: 0.0,
coordinate_system_definition: String::new(),
coordinate_system_datum: String::new(),
coordinate_system_wkt: String::new(),
geo_rss_tag: String::new(),
observation_from_tag: String::new(),
observation_to_tag: String::new(),
observation_coverage_tag: String::new(),
mesh_points: Vec::new(),
mesh_faces: Vec::new(),
civil_data_present: false,
civil_obsolete_flag: false,
civil_reference_point1: Vector2::default(),
civil_reference_point2: Vector2::default(),
civil_unknown1: 0,
civil_unknown2: 0,
civil_unknown_flag1: false,
civil_zero_point1: Vector2::default(),
civil_zero_point2: Vector2::default(),
civil_unknown_flag2: false,
civil_north_angle_degrees: 0.0,
civil_north_angle_radians: 0.0,
}
}
}
impl Default for GeoData {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SpatialFilter {
pub handle: Handle,
pub owner: Handle,
pub boundary_points: Vec<Vector2>,
pub normal: Vector3,
pub origin: Vector3,
pub display_enabled: bool,
pub front_clip: Option<f64>,
pub back_clip: Option<f64>,
pub inverse_block_transform: Matrix4,
pub clip_bound_transform: Matrix4,
}
impl SpatialFilter {
pub fn new() -> Self {
SpatialFilter {
handle: Handle::NULL,
owner: Handle::NULL,
boundary_points: Vec::new(),
normal: Vector3::new(0.0, 0.0, 1.0),
origin: Vector3::new(0.0, 0.0, 0.0),
display_enabled: true,
front_clip: None,
back_clip: None,
inverse_block_transform: Matrix4::identity(),
clip_bound_transform: Matrix4::identity(),
}
}
}
impl Default for SpatialFilter {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct RasterVariables {
pub handle: Handle,
pub owner: Handle,
pub class_version: i32,
pub display_image_frame: i16,
pub image_quality: i16,
pub units: i16,
}
impl RasterVariables {
pub fn new() -> Self {
RasterVariables {
handle: Handle::NULL,
owner: Handle::NULL,
class_version: 0,
display_image_frame: 1,
image_quality: 1,
units: 0,
}
}
}
impl Default for RasterVariables {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct BookColor {
pub handle: Handle,
pub owner: Handle,
#[cfg_attr(feature = "serde", serde(default))]
pub color: Color,
pub color_name: String,
pub book_name: String,
}
impl BookColor {
pub fn new() -> Self {
BookColor {
handle: Handle::NULL,
owner: Handle::NULL,
color: Color::default(),
color_name: String::new(),
book_name: String::new(),
}
}
}
impl Default for BookColor {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PlaceHolder {
pub handle: Handle,
pub owner: Handle,
}
impl PlaceHolder {
pub fn new() -> Self {
PlaceHolder {
handle: Handle::NULL,
owner: Handle::NULL,
}
}
}
impl Default for PlaceHolder {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct DictionaryWithDefault {
pub handle: Handle,
pub owner: Handle,
pub entries: Vec<(String, Handle)>,
pub default_handle: Handle,
pub duplicate_cloning: i16,
pub hard_owner: bool,
}
impl DictionaryWithDefault {
pub fn new() -> Self {
DictionaryWithDefault {
handle: Handle::NULL,
owner: Handle::NULL,
entries: Vec::new(),
default_handle: Handle::NULL,
duplicate_cloning: 1,
hard_owner: false,
}
}
}
impl Default for DictionaryWithDefault {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct WipeoutVariables {
pub handle: Handle,
pub owner: Handle,
pub display_frame: i16,
}
impl WipeoutVariables {
pub fn new() -> Self {
WipeoutVariables {
handle: Handle::NULL,
owner: Handle::NULL,
display_frame: 1,
}
}
}
impl Default for WipeoutVariables {
fn default() -> Self {
Self::new()
}
}
macro_rules! impl_stub_object {
($ty:ident) => {
impl StubObject for $ty {
fn new_stub() -> Self {
Self::new()
}
fn set_handle(&mut self, handle: Handle) {
self.handle = handle;
}
fn set_owner(&mut self, owner: Handle) {
self.owner = owner;
}
fn handle(&self) -> Handle {
self.handle
}
}
};
}
impl_stub_object!(GeoData);
impl_stub_object!(PlaceHolder);