2022-03-20 16:28:34 -07:00
|
|
|
///
|
|
|
|
/// Functionality for reading/writing elements (geometry, text labels,
|
|
|
|
/// structure references) and associated properties.
|
|
|
|
///
|
2021-12-18 21:05:00 -08:00
|
|
|
|
2022-05-08 16:41:43 -07:00
|
|
|
use crate::records::{BOX, BOUNDARY, NODE, PATH, TEXT, SREF, AREF,
|
2022-05-20 19:44:17 -07:00
|
|
|
DATATYPE, PATHTYPE, BOXTYPE, NODETYPE, TEXTTYPE,
|
|
|
|
LAYER, XY, WIDTH, COLROW, PRESENTATION, STRING,
|
|
|
|
STRANS, MAG, ANGLE, PROPATTR, PROPVALUE,
|
|
|
|
ENDEL, BGNEXTN, ENDEXTN, SNAME,
|
|
|
|
};
|
2021-12-18 21:05:00 -08:00
|
|
|
|
2022-05-08 16:41:43 -07:00
|
|
|
use crate::records;
|
|
|
|
use crate::record::{RecordHeader, Record};
|
|
|
|
use crate::basic::{OResult, IResult, fail};
|
2021-12-18 21:05:00 -08:00
|
|
|
|
|
|
|
use std::collections::HashMap;
|
|
|
|
use std::io::Write;
|
2022-03-20 16:28:34 -07:00
|
|
|
|
|
|
|
|
|
|
|
///
|
|
|
|
/// Read element properties.
|
|
|
|
///
|
|
|
|
/// Assumes PROPATTR records have unique values.
|
|
|
|
/// Stops reading after consuming ENDEL record.
|
|
|
|
///
|
|
|
|
/// Args:
|
|
|
|
/// stream: Stream to read from.
|
|
|
|
///
|
|
|
|
/// Returns:
|
|
|
|
/// propattr: -> propvalue mapping
|
|
|
|
///
|
|
|
|
pub fn read_properties(input: &[u8]) -> IResult<HashMap::<i16, Vec<u8>>> {
|
|
|
|
let mut properties = HashMap::new();
|
|
|
|
|
|
|
|
let (mut input, mut header) = RecordHeader::read(input)?;
|
2021-12-18 21:05:00 -08:00
|
|
|
while header.tag != ENDEL::tag() {
|
|
|
|
if header.tag == PROPATTR::tag() {
|
2022-03-20 16:28:34 -07:00
|
|
|
let result = PROPATTR::read_data(input, header.data_size)?;
|
|
|
|
input = result.0;
|
|
|
|
let key = result.1;
|
|
|
|
let result = PROPVALUE::read(input)?;
|
|
|
|
input = result.0;
|
|
|
|
let value = result.1;
|
|
|
|
assert!(!properties.contains_key(&key), "Duplicate property key: {}", key);
|
2021-12-18 21:05:00 -08:00
|
|
|
properties.insert(key, value);
|
|
|
|
}
|
2022-03-20 16:28:34 -07:00
|
|
|
(input, header) = RecordHeader::read(input)?;
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
|
|
|
Ok((input, properties))
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-03-20 16:28:34 -07:00
|
|
|
///
|
|
|
|
/// Write element properties.
|
|
|
|
///
|
|
|
|
/// This is does _not_ write the ENDEL record.
|
|
|
|
///
|
|
|
|
/// Args:
|
|
|
|
/// stream: Stream to write to.
|
|
|
|
///
|
|
|
|
pub fn write_properties<W: Write>(ww: &mut W, properties: &HashMap::<i16, Vec<u8>>) -> OResult {
|
2021-12-18 21:05:00 -08:00
|
|
|
let mut size = 0;
|
2022-03-20 16:28:34 -07:00
|
|
|
for (key, value) in properties {
|
2021-12-18 21:05:00 -08:00
|
|
|
size += PROPATTR::write(ww, key)?;
|
|
|
|
size += PROPVALUE::write(ww, value)?;
|
|
|
|
}
|
|
|
|
Ok(size)
|
|
|
|
}
|
|
|
|
|
2022-03-20 16:28:34 -07:00
|
|
|
pub trait Element {
|
|
|
|
///
|
|
|
|
/// Read from a stream to construct this object.
|
|
|
|
/// Consumes up to (and including) the ENDEL record.
|
|
|
|
///
|
|
|
|
fn read(input: &[u8]) -> IResult<Self> where Self: Sized;
|
|
|
|
|
|
|
|
///
|
|
|
|
/// Write this element to a stream.
|
|
|
|
/// Finishes with an ENDEL record.
|
|
|
|
///
|
|
|
|
fn write<W: Write>(&self, ww: &mut W) -> OResult;
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
|
|
|
|
2022-03-20 16:28:34 -07:00
|
|
|
///
|
|
|
|
/// Datastructure representing
|
|
|
|
/// an instance of a structure (SREF / structure reference) or
|
|
|
|
/// an array of instances (AREF / array reference).
|
|
|
|
/// Type is determined by the presence of the `colrow` tuple.
|
|
|
|
///
|
|
|
|
/// Transforms are applied to each individual instance (_not_
|
|
|
|
/// to the instance's origin location || array vectors).
|
|
|
|
///
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct Reference {
|
|
|
|
/// Name of the structure being referenced.
|
|
|
|
struct_name: Vec<u8>,
|
|
|
|
/// Whether to mirror the pattern (negate y-values / flip across x-axis). Default false.
|
|
|
|
invert_y: bool,
|
|
|
|
/// Scaling factor (default 1)
|
|
|
|
mag: f64,
|
|
|
|
/// Rotation (degrees counterclockwise)
|
|
|
|
angle_deg: f64,
|
|
|
|
|
|
|
|
/// (For SREF) Location in the parent structure corresponding to the instance's origin (0, 0).
|
|
|
|
/// (For AREF) 3 locations:
|
|
|
|
/// [`offset`,
|
|
|
|
/// `offset + col_basis_vector * colrow[0]`,
|
|
|
|
/// `offset + row_basis_vector * colrow[1]`]
|
|
|
|
/// which define the first instance's offset and the array's basis vectors.
|
|
|
|
/// Note that many GDS implementations only support manhattan basis vectors, and some
|
|
|
|
/// assume a certain axis mapping (e.g. x->columns, y->rows) and "reinterpret" the
|
|
|
|
/// basis vectors to match it.
|
2021-12-18 21:05:00 -08:00
|
|
|
xy: Vec<i32>,
|
2022-03-20 16:28:34 -07:00
|
|
|
|
|
|
|
/// Number of columns and rows (AREF) || None (SREF)
|
|
|
|
colrow: Option<(i16, i16)>,
|
|
|
|
/// Properties associated with this reference.
|
|
|
|
properties: HashMap::<i16, Vec<u8>>,
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Element for Reference {
|
2022-03-20 16:28:34 -07:00
|
|
|
fn read(input: &[u8]) -> IResult<Self> {
|
2021-12-18 21:05:00 -08:00
|
|
|
let mut invert_y = false;
|
2022-03-20 16:28:34 -07:00
|
|
|
let mut mag = 1.0;
|
|
|
|
let mut angle_deg = 0.0;
|
2021-12-18 21:05:00 -08:00
|
|
|
let mut colrow = None;
|
2022-03-20 16:28:34 -07:00
|
|
|
let (input, struct_name) = SNAME::skip_and_read(input)?;
|
2021-12-18 21:05:00 -08:00
|
|
|
|
2022-03-20 16:28:34 -07:00
|
|
|
let (mut input, mut header) = RecordHeader::read(input)?;
|
2021-12-18 21:05:00 -08:00
|
|
|
while header.tag != records::RTAG_XY {
|
|
|
|
match header.tag {
|
2022-03-20 16:28:34 -07:00
|
|
|
records::RTAG_STRANS => {
|
|
|
|
let result = STRANS::read_data(input, header.data_size)?;
|
|
|
|
input = result.0;
|
|
|
|
invert_y = result.1[0];
|
|
|
|
},
|
2021-12-18 21:05:00 -08:00
|
|
|
records::RTAG_MAG =>
|
2022-03-20 16:28:34 -07:00
|
|
|
{(input, mag) = MAG::read_data(input, header.data_size)?;},
|
2021-12-18 21:05:00 -08:00
|
|
|
records::RTAG_ANGLE =>
|
2022-03-20 16:28:34 -07:00
|
|
|
{(input, angle_deg) = ANGLE::read_data(input, header.data_size)?;},
|
|
|
|
records::RTAG_COLROW => {
|
|
|
|
let result = COLROW::read_data(input, header.data_size)?;
|
|
|
|
input = result.0;
|
|
|
|
colrow = Some((result.1[0], result.1[1]));
|
|
|
|
},
|
2021-12-18 21:05:00 -08:00
|
|
|
_ =>
|
2022-03-20 16:28:34 -07:00
|
|
|
return fail(input, format!("Unexpected tag {:04x}", header.tag)),
|
2021-12-18 21:05:00 -08:00
|
|
|
};
|
2022-03-20 16:28:34 -07:00
|
|
|
(input, header) = RecordHeader::read(input)?;
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
|
|
|
let (input, xy) = XY::read_data(input, header.data_size)?;
|
|
|
|
let (input, properties) = read_properties(input)?;
|
2022-03-20 16:28:34 -07:00
|
|
|
Ok((input, Reference{
|
2021-12-18 21:05:00 -08:00
|
|
|
struct_name: struct_name,
|
|
|
|
xy: xy,
|
|
|
|
properties: properties,
|
|
|
|
colrow: colrow,
|
|
|
|
invert_y: invert_y,
|
|
|
|
mag: mag,
|
|
|
|
angle_deg: angle_deg
|
2022-03-20 16:28:34 -07:00
|
|
|
}))
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
|
|
|
|
2022-03-20 16:28:34 -07:00
|
|
|
fn write<W: Write>(&self, ww: &mut W) -> OResult {
|
2021-12-18 21:05:00 -08:00
|
|
|
let mut size = 0;
|
|
|
|
size += match self.colrow {
|
2022-03-20 16:28:34 -07:00
|
|
|
None => SREF::write(ww, &())?,
|
|
|
|
Some(_) => AREF::write(ww, &())?,
|
2021-12-18 21:05:00 -08:00
|
|
|
};
|
|
|
|
|
2022-03-20 16:28:34 -07:00
|
|
|
size += SNAME::write(ww, &self.struct_name)?;
|
|
|
|
if self.angle_deg != 0.0 || self.mag != 1.0 || self.invert_y {
|
|
|
|
let strans = {
|
|
|
|
let mut arr = [false; 16];
|
|
|
|
arr[0] = self.invert_y;
|
|
|
|
arr
|
|
|
|
};
|
|
|
|
size += STRANS::write(ww, &strans)?;
|
|
|
|
if self.mag != 1.0 {
|
|
|
|
size += MAG::write(ww, &self.mag)?;
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
2022-03-20 16:28:34 -07:00
|
|
|
if self.angle_deg != 0.0 {
|
|
|
|
size += ANGLE::write(ww, &self.angle_deg)?;
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-20 16:28:34 -07:00
|
|
|
if let Some(cr) = self.colrow {
|
|
|
|
size += COLROW::write(ww, &vec!{cr.0, cr.1})?;
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
|
|
|
|
2022-03-20 16:28:34 -07:00
|
|
|
size += XY::write(ww, &self.xy)?;
|
|
|
|
size += write_properties(ww, &self.properties)?;
|
|
|
|
size += ENDEL::write(ww, &())?;
|
2021-12-18 21:05:00 -08:00
|
|
|
Ok(size)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Reference {
|
|
|
|
pub fn check(&self) {
|
|
|
|
if self.colrow.is_some() {
|
2022-03-20 16:28:34 -07:00
|
|
|
assert!(self.xy.len() != 6, "colrow is Some, so expected size-6 xy. Got {:?}", self.xy);
|
2021-12-18 21:05:00 -08:00
|
|
|
} else {
|
2022-03-20 16:28:34 -07:00
|
|
|
assert!(self.xy.len() != 2, "Expected size-2 xy. Got {:?}", self.xy);
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-03-20 16:28:34 -07:00
|
|
|
///
|
|
|
|
/// Datastructure representing a Boundary element.
|
|
|
|
///
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct Boundary {
|
|
|
|
/// (layer, data_type) tuple
|
|
|
|
layer: (i16, i16),
|
|
|
|
/// Ordered vertices of the shape. First and last points should be identical. Order x0, y0, x1,...
|
|
|
|
xy: Vec<i32>,
|
|
|
|
/// Properties for the element.
|
|
|
|
properties: HashMap::<i16, Vec<u8>>,
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Element for Boundary {
|
2022-03-20 16:28:34 -07:00
|
|
|
fn read(input: &[u8]) -> IResult<Self> {
|
2021-12-18 21:05:00 -08:00
|
|
|
let (input, layer) = LAYER::skip_and_read(input)?;
|
|
|
|
let (input, dtype) = DATATYPE::read(input)?;
|
|
|
|
let (input, xy) = XY::read(input)?;
|
|
|
|
let (input, properties) = read_properties(input)?;
|
2022-03-20 16:28:34 -07:00
|
|
|
Ok((input, Boundary{
|
2021-12-18 21:05:00 -08:00
|
|
|
layer: (layer, dtype),
|
|
|
|
xy: xy,
|
|
|
|
properties: properties,
|
2022-03-20 16:28:34 -07:00
|
|
|
}))
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
|
|
|
|
2022-03-20 16:28:34 -07:00
|
|
|
fn write<W: Write>(&self, ww: &mut W) -> OResult {
|
2021-12-18 21:05:00 -08:00
|
|
|
let mut size = 0;
|
2022-03-20 16:28:34 -07:00
|
|
|
size += BOUNDARY::write(ww, &())?;
|
|
|
|
size += LAYER::write(ww, &self.layer.0)?;
|
|
|
|
size += DATATYPE::write(ww, &self.layer.1)?;
|
|
|
|
size += XY::write(ww, &self.xy)?;
|
|
|
|
size += write_properties(ww, &self.properties)?;
|
|
|
|
size += ENDEL::write(ww, &())?;
|
2021-12-18 21:05:00 -08:00
|
|
|
Ok(size)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-03-20 16:28:34 -07:00
|
|
|
///
|
|
|
|
/// Datastructure representing a Path element.
|
|
|
|
///
|
|
|
|
/// If `path_type < 4`, `extension` values are not written.
|
|
|
|
/// During read, `exension` defaults to (0, 0) even if unused.
|
|
|
|
///
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct Path {
|
|
|
|
/// (layer, data_type) tuple
|
|
|
|
layer: (i16, i16),
|
|
|
|
/// End-cap type (0: flush, 1: circle, 2: square, 4: custom)
|
|
|
|
path_type: i16,
|
|
|
|
/// Path width
|
|
|
|
width: i32,
|
|
|
|
/// Extension when using path_type=4. Ignored otherwise.
|
|
|
|
extension: (i32, i32),
|
|
|
|
/// Path centerline coordinates. [x0, y0, x1, y1,...]
|
|
|
|
xy: Vec<i32>,
|
|
|
|
/// Properties for the element.
|
|
|
|
properties: HashMap::<i16, Vec<u8>>,
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Element for Path {
|
2022-03-20 16:28:34 -07:00
|
|
|
fn read(input: &[u8]) -> IResult<Self> {
|
2021-12-18 21:05:00 -08:00
|
|
|
let mut path_type = 0;
|
|
|
|
let mut width = 0;
|
|
|
|
let mut bgn_ext = 0;
|
|
|
|
let mut end_ext = 0;
|
2022-03-20 16:28:34 -07:00
|
|
|
let (input, layer) = LAYER::skip_and_read(input)?;
|
|
|
|
let (input, dtype) = DATATYPE::read(input)?;
|
2021-12-18 21:05:00 -08:00
|
|
|
|
2022-03-20 16:28:34 -07:00
|
|
|
let (mut input, mut header) = RecordHeader::read(&input)?;
|
2021-12-18 21:05:00 -08:00
|
|
|
while header.tag != records::RTAG_XY {
|
|
|
|
match header.tag {
|
|
|
|
records::RTAG_PATHTYPE =>
|
2022-03-20 16:28:34 -07:00
|
|
|
{(input, path_type) = PATHTYPE::read_data(input, header.data_size)?;},
|
2021-12-18 21:05:00 -08:00
|
|
|
records::RTAG_WIDTH =>
|
2022-03-20 16:28:34 -07:00
|
|
|
{(input, width) = WIDTH::read_data(input, header.data_size)?;},
|
2021-12-18 21:05:00 -08:00
|
|
|
records::RTAG_BGNEXTN =>
|
2022-03-20 16:28:34 -07:00
|
|
|
{(input, bgn_ext) = BGNEXTN::read_data(input, header.data_size)?;},
|
2021-12-18 21:05:00 -08:00
|
|
|
records::RTAG_ENDEXTN =>
|
2022-03-20 16:28:34 -07:00
|
|
|
{(input, end_ext) = ENDEXTN::read_data(input, header.data_size)?;},
|
2021-12-18 21:05:00 -08:00
|
|
|
_ =>
|
2022-03-20 16:28:34 -07:00
|
|
|
return fail(input, format!("Unexpected tag {:04x}", header.tag)),
|
2021-12-18 21:05:00 -08:00
|
|
|
};
|
2022-03-20 16:28:34 -07:00
|
|
|
(input, header) = RecordHeader::read(&input)?;
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
|
|
|
let (input, xy) = XY::read_data(input, header.data_size)?;
|
|
|
|
let (input, properties) = read_properties(input)?;
|
2022-03-20 16:28:34 -07:00
|
|
|
Ok((input, Path{
|
2021-12-18 21:05:00 -08:00
|
|
|
layer: (layer, dtype),
|
|
|
|
xy: xy,
|
|
|
|
properties: properties,
|
|
|
|
extension: (bgn_ext, end_ext),
|
|
|
|
path_type: path_type,
|
|
|
|
width: width,
|
2022-03-20 16:28:34 -07:00
|
|
|
}))
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
|
|
|
|
2022-03-20 16:28:34 -07:00
|
|
|
fn write<W: Write>(&self, ww: &mut W) -> OResult {
|
2021-12-18 21:05:00 -08:00
|
|
|
let mut size = 0;
|
2022-03-20 16:28:34 -07:00
|
|
|
size += PATH::write(ww, &())?;
|
|
|
|
size += LAYER::write(ww, &self.layer.0)?;
|
|
|
|
size += DATATYPE::write(ww, &self.layer.1)?;
|
2021-12-18 21:05:00 -08:00
|
|
|
if self.path_type != 0 {
|
2022-03-20 16:28:34 -07:00
|
|
|
size += PATHTYPE::write(ww, &self.path_type)?;
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
|
|
|
if self.width != 0 {
|
2022-03-20 16:28:34 -07:00
|
|
|
size += WIDTH::write(ww, &self.width)?;
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if self.path_type < 4 {
|
|
|
|
let (bgn_ext, end_ext) = self.extension;
|
|
|
|
if bgn_ext != 0 {
|
2022-03-20 16:28:34 -07:00
|
|
|
size += BGNEXTN::write(ww, &bgn_ext)?;
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
|
|
|
if end_ext != 0 {
|
2022-03-20 16:28:34 -07:00
|
|
|
size += ENDEXTN::write(ww, &end_ext)?;
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
|
|
|
}
|
2022-03-20 16:28:34 -07:00
|
|
|
size += XY::write(ww, &self.xy)?;
|
|
|
|
size += write_properties(ww, &self.properties)?;
|
|
|
|
size += ENDEL::write(ww, &())?;
|
2021-12-18 21:05:00 -08:00
|
|
|
Ok(size)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-03-20 16:28:34 -07:00
|
|
|
///
|
|
|
|
/// Datastructure representing a Box element. Rarely used.
|
|
|
|
///
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct GDSBox {
|
|
|
|
/// (layer, box_type) tuple
|
|
|
|
layer: (i16, i16),
|
|
|
|
/// Box coordinates (5 pairs)
|
|
|
|
xy: Vec<i32>,
|
|
|
|
/// Properties for the element.
|
|
|
|
properties: HashMap::<i16, Vec<u8>>,
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Element for GDSBox {
|
2022-03-20 16:28:34 -07:00
|
|
|
fn read(input: &[u8]) -> IResult<Self> {
|
2021-12-18 21:05:00 -08:00
|
|
|
let (input, layer) = LAYER::skip_and_read(input)?;
|
|
|
|
let (input, dtype) = BOXTYPE::read(input)?;
|
|
|
|
let (input, xy) = XY::read(input)?;
|
|
|
|
let (input, properties) = read_properties(input)?;
|
2022-03-20 16:28:34 -07:00
|
|
|
Ok((input, GDSBox{
|
2021-12-18 21:05:00 -08:00
|
|
|
layer: (layer, dtype),
|
|
|
|
xy: xy,
|
|
|
|
properties: properties,
|
2022-03-20 16:28:34 -07:00
|
|
|
}))
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
|
|
|
|
2022-03-20 16:28:34 -07:00
|
|
|
fn write<W: Write>(&self, ww: &mut W) -> OResult {
|
2021-12-18 21:05:00 -08:00
|
|
|
let mut size = 0;
|
2022-03-20 16:28:34 -07:00
|
|
|
size += BOX::write(ww, &())?;
|
|
|
|
size += LAYER::write(ww, &self.layer.0)?;
|
|
|
|
size += BOXTYPE::write(ww, &self.layer.1)?;
|
|
|
|
size += XY::write(ww, &self.xy)?;
|
|
|
|
size += write_properties(ww, &self.properties)?;
|
|
|
|
size += ENDEL::write(ww, &())?;
|
2021-12-18 21:05:00 -08:00
|
|
|
Ok(size)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-03-20 16:28:34 -07:00
|
|
|
///
|
|
|
|
/// Datastructure representing a Node element. Rarely used.
|
|
|
|
///
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct Node {
|
|
|
|
/// (layer, box_type) tuple
|
|
|
|
layer: (i16, i16),
|
|
|
|
/// 1-50 pairs of coordinates.
|
|
|
|
xy: Vec<i32>,
|
|
|
|
/// Properties for the element.
|
|
|
|
properties: HashMap::<i16, Vec<u8>>,
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Element for Node {
|
2022-03-20 16:28:34 -07:00
|
|
|
fn read(input: &[u8]) -> IResult<Self> {
|
2021-12-18 21:05:00 -08:00
|
|
|
let (input, layer) = LAYER::skip_and_read(input)?;
|
|
|
|
let (input, dtype) = NODETYPE::read(input)?;
|
|
|
|
let (input, xy) = XY::read(input)?;
|
|
|
|
let (input, properties) = read_properties(input)?;
|
2022-03-20 16:28:34 -07:00
|
|
|
Ok((input, Node{
|
2021-12-18 21:05:00 -08:00
|
|
|
layer: (layer, dtype),
|
|
|
|
xy: xy,
|
|
|
|
properties: properties,
|
2022-03-20 16:28:34 -07:00
|
|
|
}))
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
|
|
|
|
2022-03-20 16:28:34 -07:00
|
|
|
fn write<W: Write>(&self, ww: &mut W) -> OResult {
|
2021-12-18 21:05:00 -08:00
|
|
|
let mut size = 0;
|
2022-03-20 16:28:34 -07:00
|
|
|
size += NODE::write(ww, &())?;
|
|
|
|
size += LAYER::write(ww, &self.layer.0)?;
|
|
|
|
size += NODETYPE::write(ww, &self.layer.1)?;
|
|
|
|
size += XY::write(ww, &self.xy)?;
|
|
|
|
size += write_properties(ww, &self.properties)?;
|
|
|
|
size += ENDEL::write(ww, &())?;
|
2021-12-18 21:05:00 -08:00
|
|
|
Ok(size)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-20 16:28:34 -07:00
|
|
|
///
|
|
|
|
/// Datastructure representing a text label.
|
|
|
|
///
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct Text {
|
|
|
|
/// (layer, node_type) tuple
|
|
|
|
layer: (i16, i16),
|
|
|
|
|
|
|
|
/// Bit array. Default all zeros.
|
|
|
|
/// bits 0-1: 00 left/01 center/10 right
|
|
|
|
/// bits 2-3: 00 top/01 middle/10 bottom
|
|
|
|
/// bits 4-5: font number
|
2021-12-18 21:05:00 -08:00
|
|
|
presentation: [bool; 16],
|
2022-03-20 16:28:34 -07:00
|
|
|
|
|
|
|
/// Default 0
|
|
|
|
path_type: i16,
|
|
|
|
/// Default 0
|
|
|
|
width: i32,
|
|
|
|
/// Vertical inversion. Default false.
|
|
|
|
invert_y: bool,
|
|
|
|
/// Scaling factor. Default 1.
|
|
|
|
mag: f64,
|
|
|
|
/// Rotation (ccw). Default 0.
|
|
|
|
angle_deg: f64,
|
|
|
|
/// Position (1 pair only)
|
|
|
|
xy: Vec<i32>,
|
|
|
|
/// Text content
|
|
|
|
string: Vec<u8>,
|
|
|
|
/// Properties for the element.
|
|
|
|
properties: HashMap::<i16, Vec<u8>>
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Element for Text {
|
2022-03-20 16:28:34 -07:00
|
|
|
fn read(input: &[u8]) -> IResult<Self> {
|
2021-12-18 21:05:00 -08:00
|
|
|
let mut path_type = 0;
|
2022-03-20 16:28:34 -07:00
|
|
|
let mut presentation = [false; 16];
|
2021-12-18 21:05:00 -08:00
|
|
|
let mut invert_y = false;
|
|
|
|
let mut width = 0;
|
2022-03-20 16:28:34 -07:00
|
|
|
let mut mag = 1.0;
|
|
|
|
let mut angle_deg = 0.0;
|
2021-12-18 21:05:00 -08:00
|
|
|
let (input, layer) = LAYER::skip_and_read(input)?;
|
|
|
|
let (input, dtype) = TEXTTYPE::read(input)?;
|
|
|
|
|
2022-03-20 16:28:34 -07:00
|
|
|
let (mut input, mut header) = RecordHeader::read(input)?;
|
2021-12-18 21:05:00 -08:00
|
|
|
while header.tag != records::RTAG_XY {
|
|
|
|
match header.tag {
|
|
|
|
records::RTAG_PRESENTATION =>
|
2022-03-20 16:28:34 -07:00
|
|
|
{(input, presentation) = PRESENTATION::read_data(input, header.data_size)?;},
|
2021-12-18 21:05:00 -08:00
|
|
|
records::RTAG_PATHTYPE =>
|
2022-03-20 16:28:34 -07:00
|
|
|
{(input, path_type) = PATHTYPE::read_data(input, header.data_size)?;},
|
2021-12-18 21:05:00 -08:00
|
|
|
records::RTAG_WIDTH =>
|
2022-03-20 16:28:34 -07:00
|
|
|
{(input, width) = WIDTH::read_data(input, header.data_size)?;},
|
2021-12-18 21:05:00 -08:00
|
|
|
records::RTAG_STRANS => {
|
2022-03-20 16:28:34 -07:00
|
|
|
let result = STRANS::read_data(input, header.data_size)?;
|
|
|
|
input = result.0;
|
|
|
|
invert_y = result.1[0];
|
2021-12-18 21:05:00 -08:00
|
|
|
},
|
|
|
|
records::RTAG_MAG =>
|
2022-03-20 16:28:34 -07:00
|
|
|
{(input, mag) = MAG::read_data(input, header.data_size)?;},
|
2021-12-18 21:05:00 -08:00
|
|
|
records::RTAG_ANGLE =>
|
2022-03-20 16:28:34 -07:00
|
|
|
{(input, angle_deg) = ANGLE::read_data(input, header.data_size)?;},
|
2021-12-18 21:05:00 -08:00
|
|
|
_ =>
|
2022-03-20 16:28:34 -07:00
|
|
|
return fail(input, format!("Unexpected tag {:04x}", header.tag)),
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
2022-03-20 16:28:34 -07:00
|
|
|
(input, header) = RecordHeader::read(input)?;
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
|
|
|
let (input, xy) = XY::read_data(input, header.data_size)?;
|
|
|
|
|
|
|
|
let (input, string) = STRING::read(input)?;
|
|
|
|
let (input, properties) = read_properties(input)?;
|
2022-03-20 16:28:34 -07:00
|
|
|
Ok((input, Text{
|
2021-12-18 21:05:00 -08:00
|
|
|
layer: (layer, dtype),
|
|
|
|
xy: xy,
|
|
|
|
properties: properties,
|
|
|
|
string: string,
|
|
|
|
presentation: presentation,
|
|
|
|
path_type: path_type,
|
|
|
|
width: width,
|
|
|
|
invert_y: invert_y,
|
|
|
|
mag: mag,
|
|
|
|
angle_deg: angle_deg,
|
2022-03-20 16:28:34 -07:00
|
|
|
}))
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
|
|
|
|
2022-03-20 16:28:34 -07:00
|
|
|
fn write<W: Write>(&self, ww: &mut W) -> OResult {
|
2021-12-18 21:05:00 -08:00
|
|
|
let mut size = 0;
|
2022-03-20 16:28:34 -07:00
|
|
|
size += TEXT::write(ww, &())?;
|
|
|
|
size += LAYER::write(ww, &self.layer.0)?;
|
|
|
|
size += TEXTTYPE::write(ww, &self.layer.1)?;
|
|
|
|
if self.presentation.iter().any(|&x| x) {
|
|
|
|
size += PRESENTATION::write(ww, &self.presentation)?;
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
|
|
|
if self.path_type != 0 {
|
2022-03-20 16:28:34 -07:00
|
|
|
size += PATHTYPE::write(ww, &self.path_type)?;
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
|
|
|
if self.width != 0 {
|
2022-03-20 16:28:34 -07:00
|
|
|
size += WIDTH::write(ww, &self.width)?
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
2022-03-20 16:28:34 -07:00
|
|
|
if self.angle_deg != 0.0 || self.mag != 1.0 || self.invert_y {
|
|
|
|
let strans = {
|
|
|
|
let mut arr = [false; 16];
|
|
|
|
arr[0] = self.invert_y;
|
|
|
|
arr
|
|
|
|
};
|
|
|
|
size += STRANS::write(ww, &strans)?;
|
|
|
|
if self.mag != 1.0 {
|
|
|
|
size += MAG::write(ww, &self.mag)?;
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
2022-03-20 16:28:34 -07:00
|
|
|
if self.angle_deg != 0.0 {
|
|
|
|
size += ANGLE::write(ww, &self.angle_deg)?;
|
2021-12-18 21:05:00 -08:00
|
|
|
}
|
|
|
|
}
|
2022-03-20 16:28:34 -07:00
|
|
|
size += XY::write(ww, &self.xy)?;
|
|
|
|
size += STRING::write(ww, &self.string)?;
|
|
|
|
size += write_properties(ww, &self.properties)?;
|
|
|
|
size += ENDEL::write(ww, &())?;
|
2021-12-18 21:05:00 -08:00
|
|
|
Ok(size)
|
|
|
|
}
|
|
|
|
}
|