macro_rules! impl_contour_wrapper {
() => {
#[pyo3::pymethods]
impl PyContour {
#[new]
#[pyo3(signature = (vertices, /))]
fn new(
vertices: &pyo3::Bound<'_, pyo3::types::PySequence>,
) -> pyo3::PyResult<Self> {
super::packing::try_pack_vertices(
super::conversion::extract_from_py_sequence::<
Point,
PyPoint,
>(vertices)?,
)
}
#[getter]
fn bounding_box(&self) -> Box {
crate::bounded::Bounded::to_bounding_box(&self.0).cloned()
}
#[getter]
fn segments(slf: pyo3::PyRef<'_, Self>) -> PyContourSegments {
let segments_count =
crate::traits::Lengthsome::len(&(&slf.0).segments());
PyContourSegments {
contour: PyContourReference::from_py_ref(slf),
start: 0isize,
stop: segments_count as isize,
step: 1isize,
}
}
#[getter]
fn vertices(slf: pyo3::PyRef<'_, Self>) -> PyContourVertices {
let vertices_count =
crate::traits::Lengthsome::len(&(&slf.0).vertices());
PyContourVertices {
contour: PyContourReference::from_py_ref(slf),
start: 0isize,
stop: vertices_count as isize,
step: 1isize,
}
}
#[getter]
fn orientation<'py>(
&self,
py: pyo3::Python<'py>,
) -> pyo3::PyResult<pyo3::Bound<'py, pyo3::PyAny>> {
crate::oriented::Oriented::to_orientation(&self.0)
.try_to_py_any(py)
}
fn is_valid(&self) -> bool {
crate::bentley_ottmann::is_contour_valid(&self.0)
}
#[pyo3(signature = (point, /))]
fn locate<'py>(
&self,
point: &pyo3::Bound<'_, PyPoint>,
py: pyo3::Python<'py>,
) -> pyo3::PyResult<pyo3::Bound<'py, pyo3::PyAny>> {
crate::python_binding::traits::TryToPyAny::try_to_py_any(
crate::locatable::Locatable::locate(
&self.0,
&point.borrow().0,
),
py,
)
}
#[pyo3(signature = (other, /))]
fn relate_to<'py>(
&self,
other: &pyo3::Bound<'_, pyo3::PyAny>,
py: pyo3::Python<'py>,
) -> pyo3::PyResult<pyo3::Bound<'py, pyo3::PyAny>> {
use pyo3::types::PyAnyMethods;
if other.is_instance_of::<PyEmpty>() {
crate::python_binding::traits::TryToPyAny::try_to_py_any(
crate::relatable::Relatable::relate_to(
&self.0,
&other
.extract::<pyo3::Bound<'_, PyEmpty>>()?
.borrow()
.0,
),
py,
)
} else if other.is_instance_of::<PyMultisegment>() {
crate::python_binding::traits::TryToPyAny::try_to_py_any(
crate::relatable::Relatable::relate_to(
&self.0,
&other
.extract::<pyo3::Bound<'_, PyMultisegment>>()?
.borrow()
.0,
),
py,
)
} else if other.is_instance_of::<Self>() {
crate::python_binding::traits::TryToPyAny::try_to_py_any(
crate::relatable::Relatable::relate_to(
&self.0,
&other
.extract::<pyo3::Bound<'_, Self>>()?
.borrow()
.0,
),
py,
)
} else if other.is_instance_of::<PySegment>() {
crate::python_binding::traits::TryToPyAny::try_to_py_any(
crate::relatable::Relatable::relate_to(
&self.0,
&other
.extract::<pyo3::Bound<'_, PySegment>>()?
.borrow()
.0,
),
py,
)
} else if other.is_instance_of::<PyPolygon>() {
crate::python_binding::traits::TryToPyAny::try_to_py_any(
crate::relatable::Relatable::relate_to(
&self.0,
&other
.extract::<pyo3::Bound<'_, PyPolygon>>()?
.borrow()
.0,
),
py,
)
} else if other.is_instance_of::<PyMultipolygon>() {
crate::python_binding::traits::TryToPyAny::try_to_py_any(
crate::relatable::Relatable::relate_to(
&self.0,
&other
.extract::<pyo3::Bound<'_, PyMultipolygon>>()?
.borrow()
.0,
),
py,
)
} else {
Err(pyo3::exceptions::PyTypeError::new_err(format!(
"Expected compound geometry, but got {}.",
other.get_type().repr()?
)))
}
}
fn __and__(
&self,
other: &pyo3::Bound<'_, pyo3::PyAny>,
py: pyo3::Python<'_>,
) -> pyo3::PyResult<pyo3::Py<pyo3::PyAny>> {
use pyo3::types::PyAnyMethods;
if other.is_instance(
&<PyEmpty as pyo3::type_object::PyTypeInfo>::type_object(py),
)? {
let other = other.extract::<pyo3::Bound<'_, PyEmpty>>()?.borrow();
pyo3::IntoPyObject::into_pyobject(
PyEmpty(crate::traits::Intersection::intersection(
&self.0, &other.0,
)),
py,
)
.map(pyo3::Bound::into_any)
.map(pyo3::Bound::unbind)
} else if other.is_instance(
&<PyContour as pyo3::type_object::PyTypeInfo>::type_object(py),
)? {
let other = other.extract::<pyo3::Bound<'_, PyContour>>()?.borrow();
let segments =
crate::traits::Intersection::intersection(&self.0, &other.0);
super::unpacking::try_unpack_maybe_empty_segments::<PyEmpty, PyMultisegment, Segment, _>(
segments,
py,
)
} else if other.is_instance(
&<PyMultisegment as pyo3::type_object::PyTypeInfo>::type_object(py),
)? {
let other = other.extract::<pyo3::Bound<'_, PyMultisegment>>()?.borrow();
let segments =
crate::traits::Intersection::intersection(&self.0, &other.0);
super::unpacking::try_unpack_maybe_empty_segments::<PyEmpty, PyMultisegment, Segment, _>(
segments,
py,
)
} else if other.is_instance(
&<PySegment as pyo3::type_object::PyTypeInfo>::type_object(py),
)? {
let other = other.extract::<pyo3::Bound<'_, PySegment>>()?.borrow();
let segments =
crate::traits::Intersection::intersection(&self.0, &other.0);
super::unpacking::try_unpack_maybe_empty_segments::<PyEmpty, PyMultisegment, Segment, _>(
segments,
py,
)
} else if other.is_instance(
&<PyMultipolygon as pyo3::type_object::PyTypeInfo>::type_object(py),
)? {
let other = other.extract::<pyo3::Bound<'_, PyMultipolygon>>()?.borrow();
let segments =
crate::traits::Intersection::intersection(&self.0, &other.0);
super::unpacking::try_unpack_maybe_empty_segments::<PyEmpty, PyMultisegment, Segment, _>(
segments,
py,
)
} else if other.is_instance(
&<PyPolygon as pyo3::type_object::PyTypeInfo>::type_object(py),
)? {
let other = other.extract::<pyo3::Bound<'_, PyPolygon>>()?.borrow();
let segments =
crate::traits::Intersection::intersection(&self.0, &other.0);
super::unpacking::try_unpack_maybe_empty_segments::<PyEmpty, PyMultisegment, Segment, _>(
segments,
py,
)
} else {
Ok(py.NotImplemented())
}
}
fn __contains__(&self, point: &pyo3::Bound<'_, PyPoint>) -> bool {
crate::locatable::Locatable::locate(&self.0, &point.borrow().0)
!= crate::locatable::Location::Exterior
}
fn __hash__(&self, py: pyo3::Python<'_>) -> pyo3::PyResult<isize> {
let mut vertices =
(&self.0).vertices().into_iter().collect::<Vec<_>>();
let min_vertex_index = unsafe {
crate::operations::to_arg_min(&vertices).unwrap_unchecked()
};
vertices.rotate_left(min_vertex_index);
if crate::oriented::Oriented::to_orientation(&self.0)
== crate::oriented::Orientation::Clockwise
{
vertices[1..].reverse();
}
pyo3::types::PyAnyMethods::hash(
pyo3::types::PyTuple::new(
py,
vertices.into_iter().cloned(),
)?
.as_any(),
)
}
fn __or__(
&self,
other: &pyo3::Bound<'_, pyo3::PyAny>,
py: pyo3::Python<'_>,
) -> pyo3::PyResult<pyo3::Py<pyo3::PyAny>> {
use pyo3::types::PyAnyMethods;
if other.is_instance(
&<PyEmpty as pyo3::type_object::PyTypeInfo>::type_object(py),
)? {
let other = other.extract::<pyo3::Bound<'_, PyEmpty>>()?.borrow();
pyo3::IntoPyObject::into_pyobject(
Self(crate::traits::Union::union(&self.0, &other.0)),
py,
)
.map(pyo3::Bound::into_any)
.map(pyo3::Bound::unbind)
} else if other.is_instance(
&<Self as pyo3::type_object::PyTypeInfo>::type_object(py),
)? {
let other = other.extract::<pyo3::Bound<'_, Self>>()?.borrow();
let segments = crate::traits::Union::union(&self.0, &other.0);
super::unpacking::try_unpack_non_empty_segments::<PyMultisegment, Segment, _>(
segments,
py,
)
} else if other.is_instance(
&<PyMultisegment as pyo3::type_object::PyTypeInfo>::type_object(py),
)? {
let other = other.extract::<pyo3::Bound<'_, PyMultisegment>>()?.borrow();
let segments = crate::traits::Union::union(&self.0, &other.0);
super::unpacking::try_unpack_non_empty_segments::<PyMultisegment, Segment, _>(
segments,
py,
)
} else if other.is_instance(
&<PySegment as pyo3::type_object::PyTypeInfo>::type_object(py),
)? {
let other = other.extract::<pyo3::Bound<'_, PySegment>>()?.borrow();
let segments = crate::traits::Union::union(&self.0, &other.0);
super::unpacking::try_unpack_non_empty_segments::<PyMultisegment, Segment, _>(
segments,
py,
)
} else {
Ok(py.NotImplemented())
}
}
fn __repr__(
&self,
py: pyo3::Python<'_>,
) -> pyo3::PyResult<String> {
use pyo3::types::PyTypeMethods;
Ok(format!(
"{}([{}])",
<Self as pyo3::type_object::PyTypeInfo>::type_object(py).name()?,
(&self.0)
.vertices()
.into_iter()
.cloned()
.map(|vertex| PyPoint(vertex).__repr__(py))
.collect::<pyo3::PyResult<Vec<String>>>()?
.join(", ")
))
}
fn __richcmp__(
&self,
other: &pyo3::Bound<'_, pyo3::PyAny>,
op: pyo3::basic::CompareOp,
) -> pyo3::PyResult<pyo3::Py<pyo3::PyAny>> {
use pyo3::types::PyAnyMethods;
let py = other.py();
if other.is_instance(
&<PyContour as pyo3::type_object::PyTypeInfo>::type_object(
py,
),
)? {
let other = other
.extract::<pyo3::Bound<'_, PyContour>>()?
.borrow();
match op {
pyo3::basic::CompareOp::Eq => {
Ok(pyo3::BoundObject::into_bound(
pyo3::IntoPyObject::into_pyobject(self.0 == other.0, py)
.unwrap()
)
.into_any()
.unbind())
}
pyo3::basic::CompareOp::Ne => {
Ok(pyo3::BoundObject::into_bound(
pyo3::IntoPyObject::into_pyobject(self.0 != other.0, py)
.unwrap()
)
.into_any()
.unbind())
}
_ => Ok(py.NotImplemented()),
}
} else {
Ok(py.NotImplemented())
}
}
fn __str__(&self, py: pyo3::Python<'_>) -> pyo3::PyResult<String> {
Ok(format!(
"Contour([{}])",
(&self.0)
.vertices()
.into_iter()
.cloned()
.map(|vertex| PyPoint(vertex).__str__(py))
.collect::<pyo3::PyResult<Vec<String>>>()?
.join(", ")
))
}
fn __sub__(
&self,
other: &pyo3::Bound<'_, pyo3::PyAny>,
py: pyo3::Python<'_>,
) -> pyo3::PyResult<pyo3::Py<pyo3::PyAny>> {
use pyo3::types::PyAnyMethods;
if other.is_instance(
&<PyEmpty as pyo3::type_object::PyTypeInfo>::type_object(py),
)? {
let other = other.extract::<pyo3::Bound<'_, PyEmpty>>()?.borrow();
pyo3::IntoPyObject::into_pyobject(
Self(crate::traits::Difference::difference(&self.0, &other.0)),
py,
)
.map(pyo3::Bound::into_any)
.map(pyo3::Bound::unbind)
} else if other.is_instance(
&<Self as pyo3::type_object::PyTypeInfo>::type_object(py),
)? {
let other = other.extract::<pyo3::Bound<'_, Self>>()?.borrow();
let segments =
crate::traits::Difference::difference(&self.0, &other.0);
super::unpacking::try_unpack_maybe_empty_segments::<PyEmpty, PyMultisegment, Segment, _>(
segments,
py,
)
} else if other.is_instance(
&<PyMultisegment as pyo3::type_object::PyTypeInfo>::type_object(py),
)? {
let other = other.extract::<pyo3::Bound<'_, PyMultisegment>>()?.borrow();
let segments =
crate::traits::Difference::difference(&self.0, &other.0);
super::unpacking::try_unpack_maybe_empty_segments::<PyEmpty, PyMultisegment, Segment, _>(
segments,
py,
)
} else if other.is_instance(
&<PySegment as pyo3::type_object::PyTypeInfo>::type_object(py),
)? {
let other = other.extract::<pyo3::Bound<'_, PySegment>>()?.borrow();
let segments =
crate::traits::Difference::difference(&self.0, &other.0);
super::unpacking::try_unpack_maybe_empty_segments::<PyEmpty, PyMultisegment, Segment, _>(
segments,
py,
)
} else if other.is_instance(
&<PyPolygon as pyo3::type_object::PyTypeInfo>::type_object(py),
)? {
let other = other.extract::<pyo3::Bound<'_, PyPolygon>>()?.borrow();
let segments =
crate::traits::Difference::difference(&self.0, &other.0);
super::unpacking::try_unpack_maybe_empty_segments::<PyEmpty, PyMultisegment, Segment, _>(
segments,
py,
)
} else if other.is_instance(
&<PyMultipolygon as pyo3::type_object::PyTypeInfo>::type_object(py),
)? {
let other = other.extract::<pyo3::Bound<'_, PyMultipolygon>>()?.borrow();
let segments =
crate::traits::Difference::difference(&self.0, &other.0);
super::unpacking::try_unpack_maybe_empty_segments::<PyEmpty, PyMultisegment, Segment, _>(
segments,
py,
)
} else {
Ok(py.NotImplemented())
}
}
fn __xor__(
&self,
other: &pyo3::Bound<'_, pyo3::PyAny>,
py: pyo3::Python<'_>,
) -> pyo3::PyResult<pyo3::Py<pyo3::PyAny>> {
use pyo3::types::PyAnyMethods;
if other.is_instance(
&<PyEmpty as pyo3::type_object::PyTypeInfo>::type_object(py),
)? {
let other = other.extract::<pyo3::Bound<'_, PyEmpty>>()?.borrow();
pyo3::IntoPyObject::into_pyobject(
Self(
crate::traits::SymmetricDifference::symmetric_difference(
&self.0, &other.0,
),
),
py,
)
.map(pyo3::Bound::into_any)
.map(pyo3::Bound::unbind)
} else if other.is_instance(
&<Self as pyo3::type_object::PyTypeInfo>::type_object(py),
)? {
let other = other.extract::<pyo3::Bound<'_, Self>>()?.borrow();
let segments =
crate::traits::SymmetricDifference::symmetric_difference(
&self.0, &other.0,
);
super::unpacking::try_unpack_maybe_empty_segments::<PyEmpty, PyMultisegment, Segment, _>(
segments,
py,
)
} else if other.is_instance(
&<PyMultisegment as pyo3::type_object::PyTypeInfo>::type_object(py),
)? {
let other = other.extract::<pyo3::Bound<'_, PyMultisegment>>()?.borrow();
let segments =
crate::traits::SymmetricDifference::symmetric_difference(
&self.0, &other.0,
);
super::unpacking::try_unpack_maybe_empty_segments::<PyEmpty, PyMultisegment, Segment, _>(
segments,
py,
)
} else if other.is_instance(
&<PySegment as pyo3::type_object::PyTypeInfo>::type_object(py),
)? {
let other = other.extract::<pyo3::Bound<'_, PySegment>>()?.borrow();
let segments =
crate::traits::SymmetricDifference::symmetric_difference(
&self.0, &other.0,
);
super::unpacking::try_unpack_maybe_empty_segments::<PyEmpty, PyMultisegment, Segment, _>(
segments,
py,
)
} else {
Ok(py.NotImplemented())
}
}
}
};
}
pub(super) use impl_contour_wrapper;