-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[feature] add Visibility methods based on CGAL Visibility_2 package
- Loading branch information
1 parent
fc4dc56
commit 21dabff
Showing
3 changed files
with
431 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,201 @@ | ||
// Copyright (c) 2023-2023, Oslandia. | ||
// SPDX-License-Identifier: LGPL-2.0-or-later | ||
#include <SFCGAL/Polygon.h> | ||
#include <SFCGAL/algorithm/visibility.h> | ||
|
||
#include <SFCGAL/algorithm/isValid.h> | ||
|
||
#include <SFCGAL/Exception.h> | ||
|
||
#include <CGAL/Arr_segment_traits_2.h> | ||
#include <CGAL/Arrangement_2.h> | ||
#include <CGAL/Triangular_expansion_visibility_2.h> | ||
|
||
#include <CGAL/Arr_naive_point_location.h> | ||
#include <memory> | ||
|
||
namespace SFCGAL { | ||
namespace algorithm { | ||
|
||
using Point_2 = Kernel::Point_2; | ||
using Polygon_2 = CGAL::Polygon_2<Kernel>; | ||
|
||
using Segment_2 = Kernel::Segment_2; | ||
using Traits_2 = CGAL::Arr_segment_traits_2<Kernel>; | ||
using Arrangement_2 = CGAL::Arrangement_2<Traits_2>; | ||
using Face_handle = Arrangement_2::Face_handle; | ||
using Halfedge_const_handle = Arrangement_2::Halfedge_const_handle; | ||
using TEV = | ||
CGAL::Triangular_expansion_visibility_2<Arrangement_2, CGAL::Tag_true>; | ||
|
||
using PolygonWithHoles = CGAL::Polygon_with_holes_2<Kernel>; | ||
/// | ||
/// | ||
/// | ||
auto | ||
visibility(const Geometry &polygon, const Geometry &point) | ||
-> std::unique_ptr<Polygon> | ||
{ | ||
SFCGAL_ASSERT_GEOMETRY_VALIDITY_2D(polygon); | ||
|
||
std::unique_ptr<Polygon> result( | ||
visibility(polygon, point, NoValidityCheck())); | ||
propagateValidityFlag(*result, true); | ||
return result; | ||
} | ||
|
||
auto | ||
visibility(const Geometry &polygon, const Geometry &point, NoValidityCheck) | ||
-> std::unique_ptr<Polygon> | ||
{ | ||
|
||
Point_2 queryPoint{point.as<Point>().toPoint_2()}; | ||
std::unique_ptr<LineString> extRing{new LineString()}; | ||
|
||
// insert geometry into the arrangement | ||
CGAL::Polygon_with_holes_2 pwh{ | ||
polygon.as<Polygon>().toPolygon_with_holes_2()}; | ||
Arrangement_2 arr; | ||
|
||
CGAL::insert(arr, pwh.outer_boundary().edges_begin(), | ||
pwh.outer_boundary().edges_end()); | ||
|
||
for (PolygonWithHoles::Hole_const_iterator hit = pwh.holes_begin(); | ||
hit != pwh.holes_end(); ++hit) | ||
CGAL::insert(arr, hit->edges_begin(), hit->edges_end()); | ||
|
||
// Find the face | ||
Arrangement_2::Face_const_handle *face; | ||
CGAL::Arr_naive_point_location<Arrangement_2> pl(arr); | ||
CGAL::Arr_point_location_result<Arrangement_2>::Type obj = | ||
pl.locate(queryPoint); | ||
|
||
// The query point locates in the interior of a face | ||
face = boost::get<Arrangement_2::Face_const_handle>(&obj); | ||
Arrangement_2 output_arr; | ||
Face_handle fh; | ||
Halfedge_const_handle he = Halfedge_const_handle(); | ||
|
||
// Create Triangular Expansion Visibility object. | ||
TEV tev(arr); | ||
|
||
// If the point is within a face, we can compute the visbility that way | ||
if (face != NULL) { | ||
fh = tev.compute_visibility(queryPoint, *face, output_arr); | ||
} else { | ||
// If the point in a boundary segment, find the corresponding half edge | ||
he = arr.halfedges_begin(); | ||
bool cont = !Segment_2(he->source()->point(), he->target()->point()) | ||
.has_on(queryPoint) || | ||
he->source()->point() == queryPoint || | ||
he->face()->is_unbounded(); | ||
// While we are not in the right half edge, or while q is the source, | ||
// continue | ||
while (cont) { | ||
he++; | ||
if (he == arr.halfedges_end()) { | ||
throw(std::exception()); | ||
} | ||
|
||
cont = !Segment_2(he->source()->point(), he->target()->point()) | ||
.has_on(queryPoint) || | ||
he->source()->point() == queryPoint || he->face()->is_unbounded(); | ||
} | ||
|
||
// Use the half edge to compute the visibility | ||
fh = tev.compute_visibility(queryPoint, he, output_arr); | ||
} | ||
// Make sure the visibility polygon we find has an outer boundary | ||
if (fh->has_outer_ccb()) { | ||
Arrangement_2::Ccb_halfedge_circulator curr = fh->outer_ccb(); | ||
|
||
// find the right halfedge first | ||
if (he != Halfedge_const_handle()) | ||
while (++curr != fh->outer_ccb()) | ||
if (curr->source()->point() == he->source()->point()) | ||
break; | ||
|
||
Arrangement_2::Ccb_halfedge_circulator first = curr; | ||
extRing->addPoint(Point(curr->source()->point())); | ||
|
||
// Save the points from the visibility polygon | ||
while (++curr != first) { | ||
extRing->addPoint(Point(curr->source()->point())); | ||
} | ||
} | ||
|
||
std::unique_ptr<Polygon> result{new Polygon(extRing.release())}; | ||
|
||
return result; | ||
} | ||
/// | ||
/// | ||
/// | ||
auto | ||
visibility(const Geometry &polygon, const Geometry &pointA, | ||
const Geometry &pointB) -> std::unique_ptr<Polygon> | ||
{ | ||
SFCGAL_ASSERT_GEOMETRY_VALIDITY_2D(polygon); | ||
|
||
std::unique_ptr<Polygon> result( | ||
visibility(polygon, pointA, pointB, NoValidityCheck())); | ||
propagateValidityFlag(*result, true); | ||
return result; | ||
} | ||
|
||
auto | ||
visibility(const Geometry &polygon, const Geometry &pointA, | ||
const Geometry &pointB, NoValidityCheck) -> std::unique_ptr<Polygon> | ||
{ | ||
|
||
Point_2 startPoint{pointA.as<Point>().toPoint_2()}; | ||
Point_2 endPoint{pointB.as<Point>().toPoint_2()}; | ||
|
||
// insert geometry into the arrangement | ||
CGAL::Polygon_with_holes_2 pwh{ | ||
polygon.as<Polygon>().toPolygon_with_holes_2()}; | ||
Arrangement_2 arr; | ||
|
||
CGAL::insert(arr, pwh.outer_boundary().edges_begin(), | ||
pwh.outer_boundary().edges_end()); | ||
for (PolygonWithHoles::Hole_const_iterator hit = pwh.holes_begin(); | ||
hit != pwh.holes_end(); ++hit) | ||
CGAL::insert(arr, hit->edges_begin(), hit->edges_end()); | ||
|
||
// If the point in a boundary segment, find the corresponding half edge | ||
Halfedge_const_handle he = arr.halfedges_begin(); | ||
bool cont = !Segment_2(he->source()->point(), he->target()->point()) | ||
.has_on(startPoint) || | ||
he->source()->point() == startPoint || he->face()->is_unbounded(); | ||
// While we are not in the right half edge, or while q is the source, continue | ||
while (cont) { | ||
he++; | ||
if (he == arr.halfedges_end()) { | ||
throw(std::exception()); | ||
} | ||
|
||
cont = !Segment_2(he->source()->point(), he->target()->point()) | ||
.has_on(startPoint) || | ||
he->source()->point() == startPoint || he->face()->is_unbounded(); | ||
} | ||
|
||
// visibility query | ||
Arrangement_2 output_arr; | ||
TEV tev(arr); | ||
Face_handle fh = tev.compute_visibility(startPoint, he, output_arr); | ||
// print out the visibility region. | ||
Arrangement_2::Ccb_halfedge_circulator curr = fh->outer_ccb(); | ||
// print_arrangement(arr); | ||
// print_arrangement(output_arr); | ||
std::unique_ptr<LineString> extRing{new LineString()}; | ||
extRing->addPoint(Point(curr->target()->point())); | ||
while (++curr != fh->outer_ccb()) { | ||
extRing->addPoint(Point(curr->target()->point())); | ||
} | ||
std::unique_ptr<Polygon> result{new Polygon(extRing.release())}; | ||
|
||
return result; | ||
} | ||
|
||
} // namespace algorithm | ||
} // namespace SFCGAL |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// Copyright (c) 2023-2023, Oslandia. | ||
// SPDX-License-Identifier: LGPL-2.0-or-later | ||
|
||
#ifndef _SFCGAL_ALGORITHM_VISIBILITY2D_H_ | ||
#define _SFCGAL_ALGORITHM_VISIBILITY2D_H_ | ||
|
||
#include <SFCGAL/config.h> | ||
|
||
#include <memory> | ||
|
||
namespace SFCGAL { | ||
class Geometry; | ||
class Polygon; | ||
} // namespace SFCGAL | ||
|
||
namespace SFCGAL { | ||
namespace algorithm { | ||
struct NoValidityCheck; | ||
|
||
/** | ||
* @brief build the visibility polygon of a Point inside a Polygon | ||
* @param polygon input geometry | ||
* @param point input geometry | ||
* @ingroup public_api | ||
* @pre polygon is a valid geometry | ||
*/ | ||
SFCGAL_API auto | ||
visibility(const Geometry &polygon, const Geometry &point) | ||
-> std::unique_ptr<Polygon>; | ||
|
||
/** | ||
* @brief build the visibility polygon of a Point inside a Polygon | ||
* @param polygon input geometry | ||
* @param point input geometry | ||
* @ingroup public_api | ||
* @pre polygon is a valid geometry | ||
* @warning No actual validity check is done | ||
*/ | ||
SFCGAL_API auto | ||
visibility(const Geometry &polygon, const Geometry &point, NoValidityCheck) | ||
-> std::unique_ptr<Polygon>; | ||
|
||
/** | ||
* @brief build the visibility polygon of the segment [pointA ; pointB] on a | ||
* Polygon | ||
* @param polygon input geometry | ||
* @param pointA input geometry | ||
* @param pointB input geometry | ||
* @ingroup public_api | ||
* @pre polygon is a valid geometry | ||
* @pre pointA and pointB must be vertices of poly and adjacents | ||
*/ | ||
SFCGAL_API auto | ||
visibility(const Geometry &polygon, const Geometry &pointA, | ||
const Geometry &pointB) -> std::unique_ptr<Polygon>; | ||
|
||
/** | ||
* @brief build the visibility polygon of a Point inside a Polygon | ||
* @param polygon input geometry | ||
* @param pointA input geometry | ||
* @param pointB input geometry | ||
* @ingroup public_api | ||
* @pre polygon is a valid geometry | ||
* @warning No actual validity check is done | ||
* @pre pointA and pointB must be vertices of poly and adjacents | ||
*/ | ||
SFCGAL_API auto | ||
visibility(const Geometry &polygon, const Geometry &pointA, | ||
const Geometry &pointB, NoValidityCheck) -> std::unique_ptr<Polygon>; | ||
|
||
} // namespace algorithm | ||
} // namespace SFCGAL | ||
|
||
#endif |
Oops, something went wrong.