use bounding_box::{BoundingBox, ToBoundingBox};
pub mod arc_segment;
pub mod line_segment;
pub use arc_segment::*;
pub use line_segment::*;
#[cfg(feature = "serde")]
use serde::Serialize;
#[cfg(feature = "serde")]
use deserialize_untagged_verbose_error::DeserializeUntaggedVerboseError;
use crate::{
primitive::{Primitive, PrimitiveIntersections},
{CentroidData, Transformation},
};
#[doc = ""]
#[cfg_attr(feature = "doc-images", doc = "![Segments example][example_segments]")]
#[cfg_attr(
feature = "doc-images",
embed_doc_image::embed_doc_image("example_segments", "docs/img/example_segments.svg")
)]
#[cfg_attr(
not(feature = "doc-images"),
doc = "**Doc images not enabled**. Compile docs with
`cargo doc --features 'doc-images'` and Rust version >= 1.54."
)]
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, DeserializeUntaggedVerboseError))]
#[cfg_attr(feature = "serde", serde(untagged))]
pub enum Segment {
LineSegment(LineSegment),
ArcSegment(ArcSegment),
}
impl Segment {
pub fn start(&self) -> [f64; 2] {
match self {
Segment::LineSegment(line_segment) => line_segment.start(),
Segment::ArcSegment(arc_segment) => arc_segment.start(),
}
}
pub fn end(&self) -> [f64; 2] {
match self {
Segment::LineSegment(line_segment) => line_segment.stop(),
Segment::ArcSegment(arc_segment) => arc_segment.stop(),
}
}
pub fn stop(&self) -> [f64; 2] {
return self.end();
}
pub fn number_points(&self) -> usize {
match self {
Segment::LineSegment(line_segment) => line_segment.number_points(),
Segment::ArcSegment(arc_segment) => arc_segment.number_points(),
}
}
pub fn length(&self) -> f64 {
match self {
Segment::LineSegment(line_segment) => line_segment.length(),
Segment::ArcSegment(arc_segment) => arc_segment.length(),
}
}
pub fn reverse(&mut self) {
match self {
Segment::LineSegment(line_segment) => line_segment.reverse(),
Segment::ArcSegment(arc_segment) => arc_segment.reverse(),
}
}
pub fn segment_point(&self, normalized: f64) -> [f64; 2] {
match self {
Segment::LineSegment(line_segment) => line_segment.segment_point(normalized),
Segment::ArcSegment(arc_segment) => arc_segment.segment_point(normalized),
}
}
pub fn polygonize<'a>(&'a self, polygonizer: SegmentPolygonizer) -> PolygonPointsIterator<'a> {
match self {
Segment::LineSegment(line_segment) => line_segment.polygonize(polygonizer),
Segment::ArcSegment(arc_segment) => arc_segment.polygonize(polygonizer),
}
}
pub fn centroid(&self) -> [f64; 2] {
return CentroidData::from(self).into();
}
pub fn invert(&mut self) {
match self {
Segment::LineSegment(s) => s.invert(),
Segment::ArcSegment(s) => s.invert(),
}
}
pub fn touches_segment<'a, T: Into<SegmentRef<'a>>>(
&self,
other: T,
epsilon: f64,
max_ulps: u32,
) -> bool {
match self {
Segment::LineSegment(line_segment) => {
line_segment.touches_segment(other, epsilon, max_ulps)
}
Segment::ArcSegment(arc_segment) => {
arc_segment.touches_segment(other, epsilon, max_ulps)
}
}
}
}
impl Transformation for Segment {
fn translate(&mut self, shift: [f64; 2]) {
match self {
Segment::LineSegment(obj) => obj.translate(shift),
Segment::ArcSegment(obj) => obj.translate(shift),
}
}
fn rotate(&mut self, center: [f64; 2], angle: f64) {
match self {
Segment::LineSegment(obj) => obj.rotate(center, angle),
Segment::ArcSegment(obj) => obj.rotate(center, angle),
}
}
fn scale(&mut self, factor: f64) {
match self {
Segment::LineSegment(obj) => obj.scale(factor),
Segment::ArcSegment(obj) => obj.scale(factor),
}
}
fn line_reflection(&mut self, start: [f64; 2], stop: [f64; 2]) -> () {
match self {
Segment::LineSegment(obj) => obj.line_reflection(start, stop),
Segment::ArcSegment(obj) => obj.line_reflection(start, stop),
}
}
}
impl crate::primitive::private::Sealed for Segment {}
impl Primitive for Segment {
fn covers_point(&self, point: [f64; 2], epsilon: f64, max_ulps: u32) -> bool {
match self {
Segment::LineSegment(s) => s.covers_point(point, epsilon, max_ulps),
Segment::ArcSegment(s) => s.covers_point(point, epsilon, max_ulps),
}
}
fn covers_arc_segment(&self, arc_segment: &ArcSegment, epsilon: f64, max_ulps: u32) -> bool {
match self {
Segment::LineSegment(_) => return false,
Segment::ArcSegment(this) => {
return this.covers_arc_segment(arc_segment, epsilon, max_ulps);
}
}
}
fn covers_line_segment(&self, line_segment: &LineSegment, epsilon: f64, max_ulps: u32) -> bool {
match self {
Segment::LineSegment(this) => {
return this.covers_line_segment(line_segment, epsilon, max_ulps);
}
Segment::ArcSegment(_) => return false,
}
}
fn covers_line(&self, _line: &crate::line::Line, _epsilon: f64, _max_ulps: u32) -> bool {
return false;
}
fn intersections_line(
&self,
line: &crate::line::Line,
epsilon: f64,
max_ulps: u32,
) -> PrimitiveIntersections {
match self {
Segment::LineSegment(s) => s.intersections_line(line, epsilon, max_ulps),
Segment::ArcSegment(s) => s.intersections_line(line, epsilon, max_ulps),
}
}
fn intersections_line_segment(
&self,
line_segment: &LineSegment,
epsilon: f64,
max_ulps: u32,
) -> PrimitiveIntersections {
match self {
Segment::LineSegment(s) => {
s.intersections_line_segment(line_segment, epsilon, max_ulps)
}
Segment::ArcSegment(s) => s.intersections_line_segment(line_segment, epsilon, max_ulps),
}
}
fn intersections_arc_segment(
&self,
arc_segment: &ArcSegment,
epsilon: f64,
max_ulps: u32,
) -> PrimitiveIntersections {
match self {
Segment::LineSegment(s) => s.intersections_arc_segment(arc_segment, epsilon, max_ulps),
Segment::ArcSegment(s) => s.intersections_arc_segment(arc_segment, epsilon, max_ulps),
}
}
fn intersections_primitive<T: Primitive>(
&self,
other: &T,
epsilon: f64,
max_ulps: u32,
) -> PrimitiveIntersections {
other.intersections_segment(self, epsilon, max_ulps)
}
}
impl ToBoundingBox for Segment {
fn bounding_box(&self) -> BoundingBox {
match self {
Segment::LineSegment(s) => s.bounding_box(),
Segment::ArcSegment(s) => s.bounding_box(),
}
}
}
impl From<&Segment> for CentroidData {
fn from(value: &Segment) -> Self {
match value {
Segment::LineSegment(line_segment) => line_segment.into(),
Segment::ArcSegment(arc_segment) => arc_segment.into(),
}
}
}
impl From<LineSegment> for Segment {
fn from(value: LineSegment) -> Self {
return Self::LineSegment(value);
}
}
impl From<ArcSegment> for Segment {
fn from(value: ArcSegment) -> Self {
return Self::ArcSegment(value);
}
}
#[doc = ""]
#[cfg_attr(feature = "doc-images", doc = "![Polygonized arc][polygonized_arc]")]
#[cfg_attr(
feature = "doc-images",
embed_doc_image::embed_doc_image("polygonized_arc", "docs/img/polygonized_arc.svg")
)]
#[cfg_attr(
not(feature = "doc-images"),
doc = "**Doc images not enabled**. Compile docs with
`cargo doc --features 'doc-images'` and Rust version >= 1.54."
)]
#[derive(Debug, Clone, Copy)]
pub enum SegmentPolygonizer {
InnerSegments(usize),
MaximumSegmentLength(f64),
MaximumAngle(f64),
}
impl Default for SegmentPolygonizer {
fn default() -> Self {
return SegmentPolygonizer::InnerSegments(1);
}
}
#[derive(Clone, Debug)]
pub enum SegmentRef<'a> {
LineSegment(&'a LineSegment),
ArcSegment(&'a ArcSegment),
}
impl<'a> From<&'a Segment> for SegmentRef<'a> {
fn from(value: &'a Segment) -> Self {
match value {
Segment::LineSegment(v) => v.into(),
Segment::ArcSegment(v) => v.into(),
}
}
}
impl<'a> From<&'a LineSegment> for SegmentRef<'a> {
fn from(value: &'a LineSegment) -> Self {
return Self::LineSegment(value);
}
}
impl<'a> From<&'a ArcSegment> for SegmentRef<'a> {
fn from(value: &'a ArcSegment) -> Self {
return Self::ArcSegment(value);
}
}
impl<'a> ToBoundingBox for SegmentRef<'a> {
fn bounding_box(&self) -> BoundingBox {
match self {
SegmentRef::LineSegment(s) => s.bounding_box(),
SegmentRef::ArcSegment(s) => s.bounding_box(),
}
}
}
impl<'a> SegmentRef<'a> {
pub fn start(&self) -> [f64; 2] {
match self {
SegmentRef::LineSegment(line_segment) => line_segment.start(),
SegmentRef::ArcSegment(arc_segment) => arc_segment.start(),
}
}
pub fn end(&self) -> [f64; 2] {
match self {
SegmentRef::LineSegment(line_segment) => line_segment.stop(),
SegmentRef::ArcSegment(arc_segment) => arc_segment.stop(),
}
}
pub fn stop(&self) -> [f64; 2] {
return self.end();
}
pub fn number_points(&self) -> usize {
match self {
SegmentRef::LineSegment(line_segment) => line_segment.number_points(),
SegmentRef::ArcSegment(arc_segment) => arc_segment.number_points(),
}
}
pub fn length(&self) -> f64 {
match self {
SegmentRef::LineSegment(line_segment) => line_segment.length(),
SegmentRef::ArcSegment(arc_segment) => arc_segment.length(),
}
}
pub fn segment_point(&self, normalized: f64) -> [f64; 2] {
match self {
SegmentRef::LineSegment(line_segment) => line_segment.segment_point(normalized),
SegmentRef::ArcSegment(arc_segment) => arc_segment.segment_point(normalized),
}
}
pub fn polygonize(&self, polygonizer: SegmentPolygonizer) -> PolygonPointsIterator<'a> {
match self {
SegmentRef::LineSegment(line_segment) => line_segment.polygonize(polygonizer),
SegmentRef::ArcSegment(arc_segment) => arc_segment.polygonize(polygonizer),
}
}
pub fn centroid(&self) -> [f64; 2] {
return CentroidData::from(self).into();
}
pub fn touches_segment<'b, T: Into<SegmentRef<'b>>>(
&self,
other: T,
epsilon: f64,
max_ulps: u32,
) -> bool {
match self {
SegmentRef::LineSegment(line_segment) => {
line_segment.touches_segment(other, epsilon, max_ulps)
}
SegmentRef::ArcSegment(arc_segment) => {
arc_segment.touches_segment(other, epsilon, max_ulps)
}
}
}
}
impl From<SegmentRef<'_>> for CentroidData {
fn from(value: SegmentRef<'_>) -> Self {
match value {
SegmentRef::LineSegment(line_segment) => line_segment.into(),
SegmentRef::ArcSegment(arc_segment) => arc_segment.into(),
}
}
}
impl From<&SegmentRef<'_>> for CentroidData {
fn from(value: &SegmentRef) -> Self {
match value {
SegmentRef::LineSegment(line_segment) => (*line_segment).into(),
SegmentRef::ArcSegment(arc_segment) => (*arc_segment).into(),
}
}
}
impl<'a> crate::primitive::private::Sealed for SegmentRef<'a> {}
impl<'a> Primitive for SegmentRef<'a> {
fn covers_point(&self, point: [f64; 2], epsilon: f64, max_ulps: u32) -> bool {
match self {
SegmentRef::LineSegment(s) => s.covers_point(point, epsilon, max_ulps),
SegmentRef::ArcSegment(s) => s.covers_point(point, epsilon, max_ulps),
}
}
fn covers_arc_segment(&self, arc_segment: &ArcSegment, epsilon: f64, max_ulps: u32) -> bool {
match self {
SegmentRef::LineSegment(_) => return false,
SegmentRef::ArcSegment(this) => {
return this.covers_arc_segment(arc_segment, epsilon, max_ulps);
}
}
}
fn covers_line_segment(&self, line_segment: &LineSegment, epsilon: f64, max_ulps: u32) -> bool {
match self {
SegmentRef::LineSegment(this) => {
return this.covers_line_segment(line_segment, epsilon, max_ulps);
}
SegmentRef::ArcSegment(_) => return false,
}
}
fn covers_line(&self, _line: &crate::line::Line, _epsilon: f64, _max_ulps: u32) -> bool {
return false;
}
fn intersections_line(
&self,
line: &crate::line::Line,
epsilon: f64,
max_ulps: u32,
) -> PrimitiveIntersections {
match self {
SegmentRef::LineSegment(s) => s.intersections_line(line, epsilon, max_ulps),
SegmentRef::ArcSegment(s) => s.intersections_line(line, epsilon, max_ulps),
}
}
fn intersections_line_segment(
&self,
line_segment: &LineSegment,
epsilon: f64,
max_ulps: u32,
) -> PrimitiveIntersections {
match self {
SegmentRef::LineSegment(s) => {
s.intersections_line_segment(line_segment, epsilon, max_ulps)
}
SegmentRef::ArcSegment(s) => {
s.intersections_line_segment(line_segment, epsilon, max_ulps)
}
}
}
fn intersections_arc_segment(
&self,
arc_segment: &ArcSegment,
epsilon: f64,
max_ulps: u32,
) -> PrimitiveIntersections {
match self {
SegmentRef::LineSegment(s) => {
s.intersections_arc_segment(arc_segment, epsilon, max_ulps)
}
SegmentRef::ArcSegment(s) => {
s.intersections_arc_segment(arc_segment, epsilon, max_ulps)
}
}
}
fn intersections_primitive<T: Primitive>(
&self,
other: &T,
epsilon: f64,
max_ulps: u32,
) -> PrimitiveIntersections {
other.intersections_segment(self.clone(), epsilon, max_ulps)
}
}
#[derive(Clone, Debug)]
pub struct PolygonPointsIterator<'a> {
index: usize,
num_segs: usize,
segment: SegmentRef<'a>,
}
impl<'a> PolygonPointsIterator<'a> {
pub(super) fn start_at_second_point(&mut self) {
self.index = 1;
}
pub(super) fn skip_last_vertex(&mut self) {
if self.num_segs > 0 {
self.num_segs -= 1;
}
}
}
impl<'a> Iterator for PolygonPointsIterator<'a> {
type Item = [f64; 2];
fn next(&mut self) -> Option<Self::Item> {
if self.index == self.num_segs + 1 {
return None;
}
let point = match self.segment {
SegmentRef::LineSegment(segment) => {
let x = segment.start()[0]
+ self.index as f64 / self.num_segs as f64
* (segment.stop()[0] - segment.start()[0]);
let y = segment.start()[1]
+ self.index as f64 / self.num_segs as f64
* (segment.stop()[1] - segment.start()[1]);
[x, y]
}
SegmentRef::ArcSegment(segment) => {
let angle = segment.start_angle()
+ self.index as f64 / self.num_segs as f64 * segment.offset_angle();
let mut center = segment.center();
center.translate([
segment.radius() * angle.cos(),
segment.radius() * angle.sin(),
]);
center
}
};
self.index += 1;
return Some(point);
}
fn size_hint(&self) -> (usize, Option<usize>) {
let length = self.num_segs + 1;
(length, Some(length))
}
}