mirror of https://github.com/CGAL/cgal
721 lines
26 KiB
Plaintext
721 lines
26 KiB
Plaintext
@
|
|
\section{Walking on the SNC structure}
|
|
Given a SNC structure and segment $s$, with source in a known face $o$ of the SNC structure, it is possible to walk along $s$ and report the face where the target point of the segment lays on.
|
|
|
|
<<SNC\_walker.h>>=
|
|
#ifndef SNC_WALKER_H
|
|
#define SNC_WALKER_H
|
|
|
|
#include <CGAL/basic.h>
|
|
#include <CGAL/Nef_3/SNC_decorator.h>
|
|
#include <CGAL/Nef_3/SNC_SM_decorator.h>
|
|
#include <CGAL/Nef_3/SNC_SM_point_locator.h>
|
|
#include <CGAL/Nef_3/SNC_intersection.h>
|
|
|
|
#undef _DEBUG
|
|
#define _DEBUG 151
|
|
#include <CGAL/Nef_2/debug.h>
|
|
|
|
CGAL_BEGIN_NAMESPACE
|
|
|
|
template <typename SNC_structure_>
|
|
class SNC_walker : SNC_decorator<SNC_structure_>
|
|
{
|
|
<<type definitions>>
|
|
|
|
public:
|
|
SNC_walker(SNC_structure& snc) : Base(snc), I(snc) {}
|
|
|
|
Object_handle locate( Point_3 tgt) {
|
|
CGAL_nef3_assertion( vertices_begin() != vertices_end());
|
|
Vertex_handle v = vertices_begin();
|
|
return locate( Object_handle(v), point(v), tgt);
|
|
}
|
|
|
|
Object_handle locate( Object_handle start, Point_3 src, Point_3 tgt) {
|
|
TRACEN( "SNC_walker: locating " << tgt << " from " << src);
|
|
Object_handle o(start);
|
|
Segment_3 s( src, tgt);
|
|
while( s.source() != s.target()) {
|
|
TRACEN( "current segment is " << s);
|
|
Object_handle o_incident = locate_next_object_on_local_view( o, s);
|
|
Point_3 p; // next point on the walk
|
|
Object_handle o_next = find_next_intersected_object( o_incident, s, p);
|
|
<<move segment origin to the intersection point>>
|
|
}
|
|
return o;
|
|
}
|
|
private:
|
|
SNC_intersection I;
|
|
<<shell visitors>>
|
|
|
|
Object_handle locate_next_object_on_local_view( Object_handle o,
|
|
Segment_3 s) {
|
|
<<locate segment target on local view>>
|
|
return o;
|
|
}
|
|
|
|
Object_handle find_next_intersected_object( Object_handle o, Segment_3 s,
|
|
Point_3& p) {
|
|
<<find next intersected object>>
|
|
return o;
|
|
}
|
|
};
|
|
|
|
CGAL_END_NAMESPACE
|
|
|
|
#endif // SNC_WALKER_H
|
|
|
|
<<type definitions>>=
|
|
typedef SNC_structure_ SNC_structure;
|
|
|
|
protected:
|
|
typedef SNC_walker<SNC_structure> Self;
|
|
typedef CGAL::SNC_decorator<SNC_structure> Base;
|
|
|
|
public:
|
|
typedef CGAL::SNC_decorator<SNC_structure> SNC_decorator;
|
|
typedef CGAL::SNC_SM_decorator<SNC_structure> SM_decorator;
|
|
typedef CGAL::SNC_SM_point_locator<SNC_structure> SM_point_locator;
|
|
typedef CGAL::SNC_intersection<SNC_structure> SNC_intersection;
|
|
|
|
#define USING(t) typedef typename SNC_structure::t t;
|
|
USING(Vertex_handle);
|
|
USING(Halfedge_handle);
|
|
USING(Halffacet_handle);
|
|
USING(Volume_handle);
|
|
USING(SFace_handle);
|
|
USING(SHalfedge_handle);
|
|
USING(SHalfloop_handle);
|
|
USING(SVertex_handle);
|
|
USING(Object_handle);
|
|
|
|
USING(SHalfedge_around_svertex_circulator);
|
|
USING(SHalfedge_around_facet_circulator);
|
|
USING(Halffacet_cycle_iterator);
|
|
USING(Shell_entry_iterator);
|
|
|
|
USING(Kernel);
|
|
USING(RT);
|
|
USING(FT);
|
|
USING(Point_3);
|
|
USING(Segment_3);
|
|
USING(Direction_3);
|
|
USING(Vector_3);
|
|
#undef USING
|
|
|
|
@
|
|
Given the face $o$ where the source point of $s$ is located, it is possible to find out the face where the segment continues the walking, by getting the sphere face where the target point of $s$ belongs to in the local view of $o$.
|
|
|
|
When the source is located in a volume, the walking continues in the interior of the volume, independently of the direction $s$.
|
|
|
|
<<locate segment target on local view>>=
|
|
Vertex_handle v;
|
|
Halfedge_handle e;
|
|
Halffacet_handle f;
|
|
Volume_handle c;
|
|
if( assign( v, o)) {
|
|
<<locate point on vertex local view>>
|
|
}
|
|
else if( assign( e, o)) {
|
|
<<locate point on edge local view>>
|
|
}
|
|
else if( assign( f, o)) {
|
|
<<locate point on facet local view>>
|
|
}
|
|
else if( assign( c, o)) {
|
|
// do nothing, next face is the volume c
|
|
TRACEN("current object is a volume");
|
|
}
|
|
else
|
|
CGAL_nef3_assertion_msg( 0, "damn wrong handle");
|
|
|
|
@
|
|
When $o$ is a vertex, the next face is determined via point location on the local sphere map.
|
|
|
|
<<locate point on vertex local view>>=
|
|
TRACEN("current object is a vertex");
|
|
SM_point_locator point_locator(v);
|
|
TRACEN("locating sphere point " << s.target() - s.source());
|
|
Object_handle so = point_locator.locate_mutable( s.target() - s.source());
|
|
SFace_handle sf;
|
|
SHalfedge_handle sh;
|
|
SHalfloop_handle sl;
|
|
SVertex_handle sv;
|
|
if( assign( sv, so)) {
|
|
TRACEN("incident object is an edge");
|
|
o = Object_handle(Halfedge_handle(sv));
|
|
}
|
|
else if( assign( sh, so)) {
|
|
TRACEN("incident object is a facet");
|
|
o = Object_handle(Halffacet_handle(facet(sh)));
|
|
}
|
|
else if( assign( sl, so)) {
|
|
TRACEN("incident object is an facet");
|
|
o = Object_handle(Halffacet_handle(facet(sl)));
|
|
}
|
|
else if( assign( sf, so)) {
|
|
TRACEN("incident object is an volume");
|
|
o = Object_handle(Volume_handle(volume(sf)));
|
|
}
|
|
else
|
|
CGAL_nef3_assertion_msg( 0, "wrong handle");
|
|
|
|
@
|
|
In the case when $o$ is an edge or a facet, the local view is simple and the process of constructing the local view and locating the next face via point location on the sphere map could be avoided. Instead, a point location query can be performed in a \emph{virtual} local view of the object.
|
|
|
|
If $o$ is an edge, the visible object in the direction of the segment is obtained by looking at the facets incident to the edge (if any). The edge could not have any incident facet at all in which case the next face in the walking becomes its incident volume. When there is one or more incident facets, the next face on the walking becomes a facet when the segment continues in its plane, or the incident volume to the next facet to the segment in the clockwise order, when looking at the edge source from the edge target.
|
|
|
|
<<locate point on edge local view (alternative)>>=
|
|
TRACEN("current object is an edge");
|
|
SM_decorator SD;
|
|
if( SD.is_isolated(e))
|
|
o = Object_handle(Volume_handle(volume(sface(e))));
|
|
else {
|
|
Vector_3 ed(segment(e).direction()); // edge direction
|
|
Vector_3 sd(s.direction()); // segment direction
|
|
SHalfedge_around_svertex_circulator sc(SD.first_out_edge(e)),
|
|
sc_next(sc), sc_end(sc);
|
|
sc_next++;
|
|
CGAL_For_all( sc, sc_end) {
|
|
Vector_3 n_curr(plane(facet(sc)).orthogonal_vector());
|
|
Vector_3 n_next(plane(facet(sc_next)).orthogonal_vector());
|
|
Vector_3 v_curr(cross_product( ed, n_curr));
|
|
Vector_3 v_next(cross_product( ed, n_next));
|
|
if( v_curr == ed) {
|
|
o = Object_handle(Halffacet_handle(facet(sc)));
|
|
break;
|
|
}
|
|
else if( v_next == ed) {
|
|
o = Object_handle(Halffacet_handle(facet(sc_next)));
|
|
break;
|
|
}
|
|
else if( are_ccw_ordered_3( v_curr, sd, v_next, ed)) {
|
|
o = Object_handle(Volume_handle(volume(sface(sc))));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
@
|
|
When the segment does not follow a facet, the problem of locating the visible volume on direction $s$ from an edge, is a 2-dimensional problem. The source of the halfedge is visualized from its target and so, the incident facets look like segments outgoing from the source of the halfedge. The problem is then to determine which two facets is $s$ located in between. This query can be performed using at most three side-of-plane predicates over a construction with the direction of the two facets, their common edge and the segment.
|
|
|
|
This operation can be performed by comparing the result of three side-of-plane tests with the plane of a facet, and the end point of $s$ and a point in the next facet in the incidence order.
|
|
|
|
<<are vectors counterclockwise ordered relative to a plane>>=
|
|
template <class Vector_3>
|
|
bool are_ccw_order_3( Vector_3 a, Vector_3 b, Vector_3 c, Vector_3 n) {
|
|
if( a == c)
|
|
return true;
|
|
else if( a == b || b == c)
|
|
return true;
|
|
Orientation aoc = orientation( a, ORIGIN, n, c);
|
|
Orientation aob = orientation( a, ORIGIN, n, b);
|
|
if( aoc == ON_ORIENTED_BOUNDARY)
|
|
return (aob == ON_NEGATIVE_SIDE);
|
|
Orientation boc = orientation( b, ORIGIN, n, c);
|
|
if( aoc == POSITIVE)
|
|
return (aob != POSITIVE && boc != ON_POSITIVE_SIDE);
|
|
else {
|
|
CGAL_assertion( aoc == ON_NEGATIVE_SIDE);
|
|
return (aob == ON_NEGATIVE_SIDE && boc == ON_NEGATIVE_SIDE);
|
|
}
|
|
return false; // never reached
|
|
}
|
|
|
|
@
|
|
As an alternative method, the next face when hitting an edge could be found using the inner product between normalized vectors for the incident facets and $s$, pointing out of the source of the edge. Here, one of the two visible facets to the segment is chosen by taking the one which vector has the greatest inner product with the direction of $s$, what means the facet which form the minimum angle with $s$. Still it is necessary to pick the volume incident to one of the two halffacets forming the chosen facet. Then the halffacet which plane normal vector as a positive inner product with the direction of $s$ is taken.
|
|
|
|
<<locate point on edge local view>>=
|
|
TRACEN("current object is an edge");
|
|
SM_decorator SD;
|
|
if( SD.is_isolated(e)) {
|
|
TRACEN("the incident object is a volume (no indicent facets)");
|
|
o = Object_handle(Volume_handle(volume(sface(e))));
|
|
}
|
|
else {
|
|
SHalfedge_around_svertex_circulator sc(SD.first_out_edge(e)),
|
|
sc_end(sc);
|
|
CGAL_nef3_assertion( sc != SHalfedge_around_svertex_circulator());
|
|
|
|
Vector_3 edge_vector(segment(e).direction());
|
|
Vector_3 segm_vector(s.direction());
|
|
Vector_3 curr_vector(-segm_vector);
|
|
|
|
TRACEN( " edge vector: " << edge_vector);
|
|
TRACEN( " segm vector: " << segm_vector);
|
|
|
|
do {
|
|
Vector_3 facet_normal(orthogonal_vector(facet(sc)));
|
|
Vector_3 facet_vector(cross_product( edge_vector, facet_normal));
|
|
|
|
TRACEN( " facet normal: " << facet_normal);
|
|
TRACEN( " facet vector: " << facet_vector);
|
|
|
|
if( CGAL_NTS is_zero( facet_normal * segm_vector) &&
|
|
CGAL_NTS is_positive(facet_vector*segm_vector)) {
|
|
TRACEN("the incident object is a facet (the segment goes along a facet)");
|
|
o = Object_handle(Halffacet_handle(facet(sc)));
|
|
break;
|
|
}
|
|
else {
|
|
#define len2(v) v.x()*v.x()+v.y()*v.y()+v.z()*v.z()
|
|
|
|
// choose the vector with greatest projection on the segment direction
|
|
FT facet_proj = segm_vector * facet_vector;
|
|
FT curr_proj = segm_vector * curr_vector;
|
|
|
|
bool closer;
|
|
if( CGAL_NTS sign(facet_proj) < CGAL_NTS sign(curr_proj)) {
|
|
closer = false;
|
|
}
|
|
else if( CGAL_NTS sign(facet_proj) > CGAL_NTS sign(curr_proj)) {
|
|
TRACEN( " projection changed from null or negative to positive. choosed");
|
|
closer = true;
|
|
}
|
|
else { // CGAL_NTS sign(facet_proj) == CGAL_NTS sign(curr_proj)
|
|
FT len2_facet = len2(facet_vector);
|
|
FT len2_curr = len2(curr_vector);
|
|
FT diff = (len2_facet * curr_proj * curr_proj) - (len2_curr * facet_proj * facet_proj);
|
|
if( ! CGAL_NTS is_negative(diff)) {
|
|
TRACEN( " larger projection value found. choosed");
|
|
closer = true;
|
|
}
|
|
else {
|
|
closer = false;
|
|
}
|
|
}
|
|
|
|
if( closer) {
|
|
TRACEN( " new closest vector is " << facet_vector << ", previous was " << curr_vector);
|
|
curr_vector = facet_vector;
|
|
if( CGAL_NTS is_negative( segm_vector * orthogonal_vector(facet(sc))))
|
|
o = Object_handle(Volume_handle(volume(sface(sc))));
|
|
else
|
|
o = Object_handle(Volume_handle(volume(sface(twin(sc)))));
|
|
}
|
|
}
|
|
}
|
|
while( ++sc != sc_end);
|
|
}
|
|
|
|
@
|
|
To locate the next volume when hitting a facet is pretty easy since $s$ continues in one of the of the two volumes incident to the facet. Note that the walking cannot continue in a lower dimensional face in this case. The next volume is obtained by performing one side-of-plane test over the facet plane and the end point of $s$.
|
|
|
|
<<locate point on facet local view>>=
|
|
TRACEN("current object is a facet");
|
|
Oriented_side side = plane(f).oriented_side(s.target());
|
|
CGAL_nef3_warning( side != ON_ORIENTED_BOUNDARY); // could it happen?
|
|
if( side == ON_ORIENTED_BOUNDARY) {
|
|
TRACEN( "the incident object is a facet");
|
|
o = Object_handle(f);
|
|
}
|
|
else if( side == ON_POSITIVE_SIDE) {
|
|
o = Object_handle(Volume_handle(volume(f)));
|
|
TRACEN( "the incident object is a volume");
|
|
}
|
|
else { // side == ON_NEGATIVE_SIDE
|
|
o = Object_handle(Volume_handle(volume(twin(f))));
|
|
TRACEN( "the incident object is a volume");
|
|
}
|
|
|
|
@
|
|
So far, the next object on the walking is known, and for each type of object a different action should be performed in order to continue (or end) the walking.
|
|
|
|
<<find next intersected object>>=
|
|
Vertex_handle v;
|
|
Halfedge_handle e;
|
|
Halffacet_handle f;
|
|
Volume_handle c;
|
|
if( assign( v, o)) {
|
|
CGAL_nef3_assertion_msg( 0, "next object in the walking cannot be a vertex");
|
|
}
|
|
else if( assign( e, o)) {
|
|
<<find intersection with edge>>
|
|
}
|
|
else if( assign( f, o)) {
|
|
<<find intersection with facet>>
|
|
}
|
|
else if( assign( c, o)) {
|
|
<<find intersection with volume>>
|
|
}
|
|
else
|
|
CGAL_nef3_assertion_msg( 0, "damn, wrong handle");
|
|
|
|
@
|
|
For the first case, one must determine the intersection (if any) of $s$ with the shells bounding $volume(sf)$. For this action one try to find $target(s)$ first on the vertices in the boundary, then in the interior of its halfedges, and finally in the interior of all its facets. If the search is successful the local view on $target(s)$ is returned, otherwise the search continues in the same order of features looking for an intersection between the boundary of the volume and the interior of $s$. If no intersection is found then $target(s)$ is inside of the volume and the volume handle is returned. If $s$ intersects the boundary, the object intersected is saved and the algorithm continues from this location.
|
|
|
|
<<find intersection with volume>>=
|
|
bool is_target_on_boundary = false;
|
|
<<find segment target on volume boundary>>
|
|
if( !is_target_on_boundary) {
|
|
bool does_segment_intersect_boundary = false;
|
|
<<find segment intersection with volume boundary>>
|
|
if( !does_segment_intersect_boundary) {
|
|
// segment target is inside the volume
|
|
TRACEN( "the target is inside a volume");
|
|
o = Object_handle(c);
|
|
p = s.target();
|
|
}
|
|
}
|
|
|
|
<<find segment target on volume boundary>>=
|
|
// check if s.target() belongs to the volume boundary
|
|
Shell_point_locator spl( I, s.target());
|
|
Shell_entry_iterator si;
|
|
CGAL_nef3_forall_shells_of( si, c) {
|
|
SFace_handle sf(si);
|
|
visit_shell_objects( sf, spl );
|
|
}
|
|
is_target_on_boundary = spl.found;
|
|
if( is_target_on_boundary) {
|
|
TRACEN("the target is on the volume boundary");
|
|
o = spl.o;
|
|
p = s.target();
|
|
}
|
|
|
|
<<find segment intersection with volume boundary>>=
|
|
// check if the interior of r intersects the volume boundary
|
|
Shell_intersection_locator sil( I, s);
|
|
Shell_entry_iterator si;
|
|
CGAL_nef3_forall_shells_of( si, c) {
|
|
SFace_handle sf(si);
|
|
visit_shell_objects( sf, sil );
|
|
}
|
|
does_segment_intersect_boundary = sil.found;
|
|
if( does_segment_intersect_boundary) {
|
|
o = sil.o;
|
|
p = sil.p;
|
|
TRACEN("the segment intersects the volume boundary on " << p);
|
|
}
|
|
|
|
<<shell visitors>>=
|
|
struct Shell_point_locator {
|
|
SNC_intersection I;
|
|
Point_3 p; // point to locate
|
|
Object_handle o; // object where the wanted point is located
|
|
bool found;
|
|
|
|
Shell_point_locator(const SNC_intersection& Ii, Point_3 pi) :
|
|
I(Ii), p(pi), found(false) {}
|
|
|
|
void visit(SFace_handle h) { /* empty */ }
|
|
|
|
void visit(Vertex_handle h) {
|
|
if( !found && I.point(h) == p) {
|
|
TRACEN("the target is on vertex " << I.point(h));
|
|
o = Object_handle(h);
|
|
found = true;
|
|
}
|
|
}
|
|
void visit(Halfedge_handle h) {
|
|
if( !found && I.does_contain_internally( I.segment(h), p)) {
|
|
TRACEN("the target is on edge " << I.segment(h));
|
|
o = Object_handle(h);
|
|
found = true;
|
|
}
|
|
}
|
|
void visit(Halffacet_handle h) {
|
|
if( !found && I.does_contain_internally( h, p)) {
|
|
TRACEN("the target is on a facet");
|
|
o = Object_handle(h);
|
|
found = true;
|
|
}
|
|
}
|
|
};
|
|
|
|
struct Shell_intersection_locator {
|
|
SNC_intersection I;
|
|
Segment_3 s; // segment to intersect with the shell
|
|
Object_handle o; // object on the shell that intersects s
|
|
// in the farthest point from its source
|
|
Point_3 p; // intersection point
|
|
bool found;
|
|
|
|
Shell_intersection_locator(const SNC_intersection& Ii, Segment_3 si) :
|
|
I(Ii), s(si), found(false) {}
|
|
|
|
void visit(SFace_handle h) { /* empty */ }
|
|
|
|
void visit(Vertex_handle h) {
|
|
if( !found && I.does_contain_internally( s, I.point(h))) {
|
|
TRACEN("the segment intersects with the vertex on " << I.point(h));
|
|
s = Segment_3( I.point(h), s.target());
|
|
o = Object_handle(h);
|
|
p = I.point(h);
|
|
found = true;
|
|
}
|
|
}
|
|
void visit(Halfedge_handle h) {
|
|
Point_3 ip;
|
|
if( !found && I.does_intersect_internally( s, I.segment(h), ip)) {
|
|
TRACEN("the segment intersects the edge " << I.segment(h));
|
|
s = Segment_3( ip, s.target());
|
|
o = Object_handle(h);
|
|
p = ip;
|
|
found = true;
|
|
}
|
|
}
|
|
void visit(Halffacet_handle h) {
|
|
Point_3 ip;
|
|
if( !found && I.does_intersect_internally( s, h, ip)) {
|
|
TRACEN("the segment intersects a facet on " << ip);
|
|
s = Segment_3( ip, s.target());
|
|
o = Object_handle(h);
|
|
p = ip;
|
|
found = true;
|
|
}
|
|
}
|
|
};
|
|
|
|
@
|
|
For the case 2, a similar approach is taken. First, it is determined if $target(s)$ lays on the boundary of $facet(se)$, and if so, the local view on $target(s)$ is returned and the walking ends. Then, the interior of $s$ is checked for intersection with the boundary of the facet, and if an intersection is found, the algorithm continues from the local view of the intersection point. If no intersection is found, $target(s)$ lays on the interior of the facet and the facet is returned.
|
|
|
|
<<find intersection with facet>>=
|
|
bool is_target_on_boundary = false;
|
|
<<find segment target on facet boundary>>
|
|
if( !is_target_on_boundary) {
|
|
bool does_segment_intersect_boundary = false;
|
|
<<find segment intersection with facet boundary>>
|
|
if( !does_segment_intersect_boundary) {
|
|
// segment target lays on the interior of the facet
|
|
TRACEN("the target is inside a facet");
|
|
o = Object_handle(f);
|
|
p = s.target();
|
|
}
|
|
}
|
|
|
|
<<find segment target on facet boundary>>=
|
|
// check if s.target() belongs to the edges in the boundary of the face
|
|
Halffacet_cycle_iterator ci;
|
|
CGAL_nef3_forall_facet_cycles_of( ci, f) {
|
|
SHalfedge_handle se;
|
|
SHalfloop_handle sl;
|
|
if( assign( se, ci)) {
|
|
SHalfedge_around_facet_circulator hc(se), hend(hc);
|
|
CGAL_For_all( hc, hend) {
|
|
if( point(vertex(hc)) == s.target()) {
|
|
TRACEN("the target is a facet vertex");
|
|
o = Object_handle(Vertex_handle(vertex(hc)));
|
|
p = point(vertex(hc));
|
|
is_target_on_boundary = true;
|
|
break;
|
|
}
|
|
else if( I.does_contain_internally( segment(starget(hc)),
|
|
s.target())) {
|
|
TRACEN("the target is inside a facet edge");
|
|
o = Object_handle(Halfedge_handle(starget(hc)));
|
|
p = s.target();
|
|
is_target_on_boundary = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if( assign( sl, ci)) {
|
|
if( point(vertex(sl)) == s.target()) {
|
|
TRACEN("the target is on an isolated vertex inside a facet");
|
|
o = Object_handle(Vertex_handle(vertex(sl)));
|
|
p = point(vertex(sl));
|
|
is_target_on_boundary = true;
|
|
}
|
|
}
|
|
else
|
|
CGAL_nef3_assertion_msg( 0, "what is this facet cycle?");
|
|
|
|
if(is_target_on_boundary)
|
|
break;
|
|
}
|
|
|
|
<<find segment intersection with facet boundary>>=
|
|
// check if s intersects the boundary of the facet
|
|
Segment_3 st(s);
|
|
Halffacet_cycle_iterator ci;
|
|
CGAL_nef3_forall_facet_cycles_of( ci, f) {
|
|
SHalfedge_handle se;
|
|
SHalfloop_handle sl;
|
|
if( assign( se, ci)) {
|
|
SHalfedge_around_facet_circulator hc(se), hend(hc);
|
|
CGAL_For_all( hc, hend) {
|
|
Segment_3 edge = segment(starget(hc));
|
|
Point_3 ip;
|
|
if( I.does_contain_internally( st, point(vertex(hc)))) {
|
|
TRACEN("the segment intersects a facet vertex");
|
|
st = Segment_3( point(vertex(hc)), s.target());
|
|
o = Object_handle(Vertex_handle(vertex(hc)));
|
|
p = point(vertex(hc));
|
|
does_segment_intersect_boundary = true;
|
|
break;
|
|
}
|
|
else if( I.does_intersect_internally( st, edge, ip)) {
|
|
TRACEN("the segment intersects a facet edge on " << ip);
|
|
st = Segment_3( ip, s.target());
|
|
o = Object_handle(Halfedge_handle(starget(hc)));
|
|
p = ip;
|
|
does_segment_intersect_boundary = true;
|
|
}
|
|
}
|
|
}
|
|
else if( assign( sl, ci)) {
|
|
if( I.does_contain_internally( st, point(vertex(sl)))) {
|
|
TRACEN("the segment intersects an isolated vertex inside a facet");
|
|
st = Segment_3( point(vertex(sl)), s.target());
|
|
o = Object_handle(Vertex_handle(vertex(sl)));
|
|
p = point(vertex(sl));
|
|
does_segment_intersect_boundary = true;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
@
|
|
On the case 3, the segment follows an edge $sv$. The location of $target(s)$ is compared with $target(sv)$ and the vertex is returned if they have the same coordinates, so the walking ends. Then, $target(s)$ is tested for inclusion on $sv$, and if so, the edge $sv$ is returned and the walking ends. At this point, it is known $s$ goes farther on $sv$ so the next element on the walking is $vertex(target(sv))$ and the algorithm continues from this location.
|
|
|
|
<<find intersection with edge>>=
|
|
if( point(target(e)) == s.target()) {
|
|
TRACEN("the target is on a vertex walking along an edge");
|
|
o = Object_handle(Vertex_handle(target(e)));
|
|
p = s.target();
|
|
}
|
|
else if( I.does_contain_internally( segment(e), s.target())) {
|
|
TRACEN("the target is on an edge walking along it");
|
|
o = Object_handle(e);
|
|
p = s.target();
|
|
}
|
|
else {
|
|
TRACEN("the segment follows and edge and goes farther");
|
|
o = Object_handle(Vertex_handle(target(e)));
|
|
p = point(target(e));
|
|
}
|
|
|
|
@
|
|
Finally, the segment source is located on the intersection found. If there is not such a intersection, the local view is located on the segment target, ending in this way the walking.
|
|
|
|
<<move segment origin to the intersection point>>=
|
|
s = Segment_3( p, s.target());
|
|
o = o_next;
|
|
|
|
@
|
|
\subsection{Test program}
|
|
|
|
<<SNC\_walker\_demo.C>>=
|
|
// Copyright (c) 2003 Max-Planck-Institute Saarbruecken (Germany).
|
|
// All rights reserved.
|
|
//
|
|
// This file is part of CGAL (www.cgal.org); you may redistribute it under
|
|
// the terms of the Q Public License version 1.0.
|
|
// See the file LICENSE.QPL distributed with CGAL.
|
|
//
|
|
// Licensees holding a valid commercial license may use this file in
|
|
// accordance with the commercial license agreement provided with the software.
|
|
//
|
|
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
|
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
// $URL$
|
|
// $Id$
|
|
//
|
|
//
|
|
// Author(s) : Miguel Granados <granados@mpi-sb.mpg.de>
|
|
|
|
#include <CGAL/basic.h>
|
|
#include <CGAL/Gmpz.h>
|
|
#include <CGAL/Simple_homogeneous.h>
|
|
#include <CGAL/Extended_homogeneous_3.h>
|
|
#include <CGAL/Polyhedron_3.h>
|
|
#include <CGAL/IO/Polyhedron_iostream.h>
|
|
#include <CGAL/Nef_polyhedron_3.h>
|
|
#include <CGAL/Nef_3/SNC_walker.h>
|
|
|
|
#undef _DEBUG
|
|
#define _DEBUG 157
|
|
#include <CGAL/Nef_2/debug.h>
|
|
|
|
typedef CGAL::Gmpz NT;
|
|
typedef CGAL::Extended_homogeneous_3<NT> Kernel;
|
|
typedef Kernel::Point_3 Point_3;
|
|
typedef Kernel::Segment_3 Segment_3;
|
|
typedef CGAL::Polyhedron_3<Kernel> Polyhedron;
|
|
|
|
typedef CGAL::SNC_items<Kernel, bool> SNC_items;
|
|
typedef CGAL::SNC_structure<SNC_items> SNC_structure;
|
|
typedef CGAL::Nef_polyhedron_3<SNC_items> Nef_polyhedron;
|
|
typedef CGAL::SNC_walker<SNC_structure> SNC_walker;
|
|
|
|
typedef SNC_structure::Vertex_handle Vertex_handle;
|
|
typedef SNC_structure::Halfedge_handle Halfedge_handle;
|
|
typedef SNC_structure::Halffacet_handle Halffacet_handle;
|
|
typedef SNC_structure::Volume_handle Volume_handle;
|
|
typedef SNC_structure::Object_handle Object_handle;
|
|
|
|
int main() {
|
|
CGAL::set_pretty_mode(std::cerr);
|
|
SETDTHREAD(151*157);
|
|
|
|
Point_3 source, target;
|
|
std::cin >> source;
|
|
TRACEN( "source:" << source);
|
|
std::cin >> target;
|
|
TRACEN( "target:" << target);
|
|
|
|
Point_3 p0( 0, 0, 0, 1);
|
|
Point_3 p1( 4, 0, 0, 1);
|
|
Point_3 p2( 0, 4, 0, 1);
|
|
Point_3 p3( 0, 0, 4, 1);
|
|
Point_3 p4( 4, 4, 4, 1);
|
|
Polyhedron P1, P2;
|
|
P1.make_tetrahedron( p1, p2, p3, p0);
|
|
P2.make_tetrahedron( p3, p2, p1, p4);
|
|
//TRACEN( P1 << P2);
|
|
|
|
TRACEN("constructing model...");
|
|
Nef_polyhedron NP1(P1), NP2(P2), NP(NP1^NP2);
|
|
TRACEN("locating source...");
|
|
Object_handle o_src = NP.locate( source);
|
|
TRACEN("walking to target...");
|
|
Object_handle o = NP.locate( o_src, source, target);
|
|
TRACEN("comparing result with ray shooting...");
|
|
CGAL_assertion_code(Object_handle oref = NP.locate(target));
|
|
|
|
Vertex_handle v;
|
|
Halfedge_handle e;
|
|
Halffacet_handle f;
|
|
Volume_handle c;
|
|
if( assign( v, o)) { // TODO: enable ostream operator for nef faces
|
|
std::cout << "The point is located in a vertex " << std::endl;
|
|
CGAL_assertion_code(Vertex_handle vref);
|
|
CGAL_assertion( assign( vref, oref));
|
|
CGAL_assertion( v == vref);
|
|
}
|
|
else if( assign( e, o)) {
|
|
std::cout << "The point is located in an edge " << std::endl;
|
|
CGAL_assertion_code(Halfedge_handle eref);
|
|
CGAL_assertion( assign( eref, oref));
|
|
CGAL_assertion( e == eref || NP.SNCexplorer().twin(eref) == e);
|
|
}
|
|
else if( assign( f, o)) {
|
|
std::cout << "The point is located in a facet " << std::endl;
|
|
CGAL_assertion_code(Halffacet_handle fref);
|
|
CGAL_assertion( assign( fref, oref));
|
|
CGAL_assertion( f == fref || NP.SNCexplorer().twin(fref) == f);
|
|
}
|
|
else if( assign( c, o)) {
|
|
std::cout << "The point is located in a volume " << std::endl;
|
|
CGAL_assertion_code( Volume_handle cref);
|
|
CGAL_assertion( assign( cref, oref));
|
|
CGAL_assertion( c == cref);
|
|
}
|
|
else
|
|
CGAL_assertion_msg( 0, "wrong handle");
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
@
|
|
% LocalWords: snc Nef const Halfedge Halffacet CGAL nef msg sface shalfedge SM
|
|
% LocalWords: svertex halfedge SFace sf SHalfedge sh SHalfloop sl SVertex sv
|
|
% LocalWords: halfedges struct bool Ii intersection si ip segment forall ci SD
|
|
% LocalWords: facet se circulator hc hend sc sd snext curr ccw aoc aob boc NT
|
|
% LocalWords: typename undef halffacets halffacet ifndef namespace endif int
|
|
% LocalWords: iostream NP
|