DYT/Tool/OpenSceneGraph-3.6.5/include/geos/algorithm/RayCrossingCounter.h
2024-12-25 07:49:36 +08:00

174 lines
5.5 KiB
C++

/**********************************************************************
*
* GEOS - Geometry Engine Open Source
* http://geos.osgeo.org
*
* Copyright (C) 2006 Refractions Research Inc.
*
* 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.
*
*
**********************************************************************
*
* Last port: algorithm/RayCrossingCounter.java rev. 1.2 (JTS-1.9)
*
**********************************************************************/
#pragma once
#include <geos/export.h>
#include <geos/geom/Location.h>
#include <array>
#include <vector>
// forward declarations
namespace geos {
namespace geom {
class Coordinate;
class CoordinateXY;
class CoordinateSequence;
class CircularArc;
class Curve;
}
}
namespace geos {
namespace algorithm {
/** \brief
* Counts the number of segments crossed by a horizontal ray extending to the
* right from a given point, in an incremental fashion.
*
* This can be used to determine whether a point lies in a polygonal geometry.
* The class determines the situation where the point lies exactly on a segment.
* When being used for Point-In-Polygon determination, this case allows
* short-circuiting the evaluation.
*
* This class handles polygonal geometries with any number of shells and holes.
* The orientation of the shell and hole rings is unimportant.
* In order to compute a correct location for a given polygonal geometry,
* it is essential that **all** segments are counted which
*
* - touch the ray
* - lie in in any ring which may contain the point
*
* The only exception is when the point-on-segment situation is detected, in
* which case no further processing is required.
* The implication of the above rule is that segments which can be a priori
* determined to *not* touch the ray (i.e. by a test of their bounding box or
* Y-extent) do not need to be counted. This allows for optimization by indexing.
*
* @author Martin Davis
*/
class GEOS_DLL RayCrossingCounter {
private:
const geom::CoordinateXY& point;
std::size_t crossingCount;
// true if the test point lies on an input segment
bool isPointOnSegment;
// Declare type as noncopyable
RayCrossingCounter(const RayCrossingCounter& other) = delete;
RayCrossingCounter& operator=(const RayCrossingCounter& rhs) = delete;
public:
/** \brief
* Determines the [Location](@ref geom::Location) of a point in a ring.
*
* This method is an exemplar of how to use this class.
*
* @param p the point to test
* @param ring an array of Coordinates forming a ring
* @return the location of the point in the ring
*/
static geom::Location locatePointInRing(const geom::CoordinateXY& p,
const geom::CoordinateSequence& ring);
/// Semantically equal to the above, just different args encoding
static geom::Location locatePointInRing(const geom::CoordinateXY& p,
const std::vector<const geom::Coordinate*>& ring);
static geom::Location locatePointInRing(const geom::CoordinateXY& p,
const geom::Curve& ring);
RayCrossingCounter(const geom::CoordinateXY& p_point)
: point(p_point),
crossingCount(0),
isPointOnSegment(false)
{ }
/** \brief
* Counts a segment
*
* @param p1 an endpoint of the segment
* @param p2 another endpoint of the segment
*/
void countSegment(const geom::CoordinateXY& p1,
const geom::CoordinateXY& p2);
void countArc(const geom::CoordinateXY& p1,
const geom::CoordinateXY& p2,
const geom::CoordinateXY& p3);
/** \brief
* Counts all segments or arcs in the sequence
*/
void processSequence(const geom::CoordinateSequence& seq, bool isLinear);
/** \brief
* Reports whether the point lies exactly on one of the supplied segments.
*
* This method may be called at any time as segments are processed.
* If the result of this method is `true`, no further segments need
* be supplied, since the result will never change again.
*
* @return `true` if the point lies exactly on a segment
*/
bool
isOnSegment() const
{
return isPointOnSegment;
}
/** \brief
* Gets the [Location](@ref geom::Location) of the point relative to
* the ring, polygon or multipolygon from which the processed
* segments were provided.
*
* This method only determines the correct location
* if **all** relevant segments must have been processed.
*
* @return the Location of the point
*/
geom::Location getLocation() const;
/** \brief
* Tests whether the point lies in or on the ring, polygon or
* multipolygon from which the processed segments were provided.
*
* This method only determines the correct location if **all** relevant
* segments must have been processed.
*
* @return `true` if the point lies in or on the supplied polygon
*/
bool isPointInPolygon() const;
std::size_t getCount() const { return crossingCount; };
static bool shouldCountCrossing(const geom::CircularArc& arc, const geom::CoordinateXY& q);
static std::array<geom::CoordinateXY, 2>
pointsIntersectingHorizontalRay(const geom::CircularArc& arc, const geom::CoordinateXY& origin);
};
} // geos::algorithm
} // geos