CircularArc.h
/**********************************************************************
*
* GEOS - Geometry Engine Open Source
* http://geos.osgeo.org
*
* Copyright (C) 2024 ISciences, LLC
*
* This is free software; you can redistribute and/or modify it under
* the terms of the GNU Lesser General Public Licence as published
* by the Free Software Foundation.
* See the COPYING file for more information.
*
**********************************************************************/
#pragma once
#include <geos/export.h>
#include <geos/geom/Coordinate.h>
#include <geos/geom/Quadrant.h>
#include <geos/algorithm/CircularArcs.h>
#include <geos/algorithm/Orientation.h>
#include <geos/triangulate/quadedge/TrianglePredicate.h>
namespace geos {
namespace geom {
class GEOS_DLL CircularArc {
public:
using CoordinateXY = geom::CoordinateXY;
CircularArc(const CoordinateXY& q0, const CoordinateXY& q1, const CoordinateXY& q2)
: p0(q0)
, p1(q1)
, p2(q2)
, m_center_known(false)
, m_radius_known(false)
, m_orientation_known(false)
{}
const CoordinateXY& p0;
const CoordinateXY& p1;
const CoordinateXY& p2;
int orientation() const {
if (!m_orientation_known) {
m_orientation = algorithm::Orientation::index(p0, p1, p2);
m_orientation_known = true;
}
return m_orientation;
}
const CoordinateXY& getCenter() const {
if (!m_center_known) {
m_center = algorithm::CircularArcs::getCenter(p0, p1, p2);
m_center_known = true;
}
return m_center;
}
double getRadius() const {
if (!m_radius_known) {
m_radius = getCenter().distance(p0);
m_radius_known = true;
}
return m_radius;
}
bool isCircle() const {
return p0.equals(p2);
}
bool isLinear() const {
return std::isnan(getRadius());
}
double getAngle() const {
if (isCircle()) {
return 2*MATH_PI;
}
auto t0 = theta0();
auto t2 = theta2();
if (orientation() == algorithm::Orientation::COUNTERCLOCKWISE) {
std::swap(t0, t2);
}
if (t0 < t2) {
t0 += 2*MATH_PI;
}
auto diff = t0-t2;
return diff;
}
double getLength() const {
if (isLinear()) {
return p0.distance(p2);
}
return getAngle()*getRadius();
}
double getArea() const {
if (isLinear()) {
return 0;
}
auto R = getRadius();
auto theta = getAngle();
return R*R/2*(theta - std::sin(theta));
}
double theta0() const {
return std::atan2(p0.y - getCenter().y, p0.x - getCenter().x);
}
double theta2() const {
return std::atan2(p2.y - getCenter().y, p2.x - getCenter().x);
}
bool containsPointOnCircle(const CoordinateXY& q) const {
double theta = std::atan2(q.y - getCenter().y, q.x - getCenter().x);
return containsAngle(theta);
}
bool containsPoint(const CoordinateXY& q) {
if (q == p0 || q == p1 || q == p2) {
return true;
}
auto dist = std::abs(q.distance(getCenter()) - getRadius());
if (dist > 1e-8) {
return false;
}
if (triangulate::quadedge::TrianglePredicate::isInCircleNormalized(p0, p1, p2, q) != geom::Location::BOUNDARY) {
return false;
}
return containsPointOnCircle(q);
}
bool containsAngle(double theta) const {
auto t0 = theta0();
auto t2 = theta2();
if (theta == t0 || theta == t2) {
return true;
}
if (orientation() == algorithm::Orientation::COUNTERCLOCKWISE) {
std::swap(t0, t2);
}
t2 -= t0;
theta -= t0;
if (t2 < 0) {
t2 += 2*MATH_PI;
}
if (theta < 0) {
theta += 2*MATH_PI;
}
return theta >= t2;
}
bool isUpwardAtPoint(const CoordinateXY& q) const {
auto quad = geom::Quadrant::quadrant(getCenter(), q);
bool isUpward;
if (orientation() == algorithm::Orientation::CLOCKWISE) {
isUpward = (quad == geom::Quadrant::SW || quad == geom::Quadrant::NW);
} else {
isUpward = (quad == geom::Quadrant::SE || quad == geom::Quadrant::NE);
}
return isUpward;
}
class Iterator {
public:
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = geom::CoordinateXY;
using pointer = const geom::CoordinateXY*;
using reference = const geom::CoordinateXY&;
Iterator(const CircularArc& arc, int i) : m_arc(arc), m_i(i) {}
reference operator*() const {
return m_i == 0 ? m_arc.p0 : (m_i == 1 ? m_arc.p1 : m_arc.p2);
}
Iterator& operator++() {
m_i++;
return *this;
}
Iterator operator++(int) {
Iterator ret = *this;
m_i++;
return ret;
}
bool operator==(const Iterator& other) const {
return m_i == other.m_i;
}
bool operator!=(const Iterator& other) const {
return !(*this == other);
}
private:
const CircularArc& m_arc;
int m_i;
};
Iterator begin() const {
return Iterator(*this, 0);
}
Iterator end() const {
return Iterator(*this, 3);
}
private:
mutable CoordinateXY m_center;
mutable double m_radius;
mutable int m_orientation;
mutable bool m_center_known = false;
mutable bool m_radius_known = false;
mutable bool m_orientation_known = false;
};
}
}
geos::algorithm::Orientation::index
static int index(const geom::CoordinateXY &p1, const geom::CoordinateXY &p2, const geom::CoordinateXY &q)
Returns the orientation index of the direction of the point q relative to a directed infinite line sp...
geos::geom::CircularArc
Definition CircularArc.h:29
geos::geom::CircularArc::containsPointOnCircle
bool containsPointOnCircle(const CoordinateXY &q) const
Definition CircularArc.h:149
geos::geom::CircularArc::isUpwardAtPoint
bool isUpwardAtPoint(const CoordinateXY &q) const
Definition CircularArc.h:203
geos::geom::CircularArc::isCircle
bool isCircle() const
Return whether this arc forms a complete circle.
Definition CircularArc.h:80
geos::geom::CircularArc::containsAngle
bool containsAngle(double theta) const
Check to see if a given angle lies on this arc.
Definition CircularArc.h:175
geos::geom::CircularArc::getCenter
const CoordinateXY & getCenter() const
Return the center point of the circle associated with this arc.
Definition CircularArc.h:60
geos::geom::CircularArc::orientation
int orientation() const
Definition CircularArc.h:51
geos::geom::CircularArc::isLinear
bool isLinear() const
Returns whether this arc forms a straight line (p0, p1, and p2 are collinear).
Definition CircularArc.h:85
geos::geom::CircularArc::getAngle
double getAngle() const
Return the inner angle of the sector associated with this arc.
Definition CircularArc.h:90
geos::geom::CircularArc::containsPoint
bool containsPoint(const CoordinateXY &q)
Definition CircularArc.h:156
geos::geom::CircularArc::getLength
double getLength() const
Return the length of the arc.
Definition CircularArc.h:117
geos::geom::CircularArc::getArea
double getArea() const
Return the area enclosed by the arc p0-p1-p2 and the line segment p2-p0.
Definition CircularArc.h:126
geos::geom::CircularArc::getRadius
double getRadius() const
Return the radius of the circle associated with this arc.
Definition CircularArc.h:70
geos::geom::CircularArc::theta0
double theta0() const
Return the angle of p0.
Definition CircularArc.h:137
geos::geom::CircularArc::theta2
double theta2() const
Return the angle of p2.
Definition CircularArc.h:142
geos::geom::Quadrant::quadrant
static int quadrant(double dx, double dy)
Definition Quadrant.h:67
geos::triangulate::quadedge::TrianglePredicate::isInCircleNormalized
static geom::Location isInCircleNormalized(const CoordinateXY &a, const CoordinateXY &b, const CoordinateXY &c, const CoordinateXY &p)
geos::geom
Definition Angle.h:26
geos::geom::Location::BOUNDARY
@ BOUNDARY
Definition Location.h:50
geos
Basic namespace for all GEOS functionalities.
Definition geos.h:38