Download as a PDF

3 downloads 0 Views 146KB Size Report
normals until they become tangent to P. The convex hull of the touching points determine .... In the file plane_oracle.h the function void plane_touch_polyhedron.
ACS Algorithms for Complex Shapes with Certified Numerics and Topology

PL-approximation of convex surfaces in 3D by the sandwich algorithm

Darko Dimitrov

G¨ unter Rote

Astrid Sturm

ACS Technical Report No.: ACS-TR-242403-01 Part of deliverable: Site: Month:

WP-II/D5 FUB 36

Project co-funded by the European Commission within FP6 (2002–2006) under contract nr. IST-006413

Abstract Approximating a given three-dimensional object in order to simplify its handling is a classical topic in computational geometry and related fields. While the pl-approximation of general curves in 2D has been investigated extensively in the past, the 3D case - pl-approximation of surfaces - still holds many open questions. In this experimental implementation we extend the well known sandwich algorithm form the 2D case for convex functions to an algorithm for convex surfaces in 3D. Our version of the sandwich algorithm approximates a given convex object by an inner and outer polytope. The algorithm is based optional on an ray or plane oracle. The plane oracle returns for a given plane a point, edge or facet on the original object which is tangent to the plane, while the ray oracle returns the intersection point of the original object with the ray. The answers of the oracle are the basis on which the inner and outer polytopes are built. The approximation is refined until a predefined tolerance is met. An additional goal of the implementation was to analyze with which basic, geometric elements (e.g. intersections and projections) such an algorithm is feasible.

1

Introduction

The sandwich algorithm in 2D is a fast and simple algorithm with a good performance guarantee, therefore we try to extend the algorithm to 3D. Let us first expalin the basic details of the algorithm in 2D. The required input is a convex function of a single variable over an interval. The sandwich algorithm acquires information about the function step by step by evaluating the function and its derivative at a sequence of points. The sandwich algorithm and its evaluation was introduced by Rote in [1]. The algorithm starts by evaluating the function and its one-sided derivatives at the endpoints of the interval. An initial upper bound is given by the line connecting the two endpoints of the graph of the function, and a lower bound by the two supporting lines described by the derivatives at the endpoints. After selecting a point in the interval (depending on the partition rule), the function and its derivative is evaluated. The problem is now split in two subintervals and the interval with the larger error is split in the same way as before. This process is continued for a given number of iterations or until a specified error bound is met. The algorithm can handle various error measures (e.g. maximum vertical distance, Hausdorff distance, ). There are distinct versions of the algorithm depending on how they partition their intervals into subintervals. The four main partition rules are: • The interval bisections rule: The interval is partitioned into two equal parts. • The slope bisection rule: Find the supporting line whose slope is the mean value of the slopes of the tangents at the endpoints and partition the interval at the point where this line touches the function. • The maximum error rule: The interval is partitioned at the breakpoint of the lower approximation (the point where the error between the two approximation is maximum). 1

• The chord rule: Take the slope of the line connecting the two endpoints as the slope of the supporting line. For all four-partition rules the maximum error decreases quadratically with the number of iterations: The sandwich algorithm uses the best approximation to be obtained from the known information. The gain of the sandwich algorithm is, that the partition rules can be chosen depending on the application, and availability of the derivatives of the function. To find an approximation of a function for a given error bound with minimum number of linear pieces, there are more direct methods than the sandwich algorithm. If the goal is to find a good approximation with as few function evaluations as possible, the sandwich algorithm is an ideal candidate. For the 3D case of the algorithm there are many open questions of which we could answer only a few till now. In the next chapter we give an overview of our new algorithm, in which we try to carry the basic ideas of the sandwich algorithm to 3D. The evaluation of the 3D sandwich algorithm is still ongoing work.The code of the implemented classes and functions is available at http://www.inf.fu-berlin.de/groups/ag-ti/index.php?id=90.

2

Description of the algorithm in 3D

Given: a convex polyhedron P in R3 Find: an inner and an outer polyhedral approximation that ”sandwiched” P The outline of the algorithm: 1. Perform ray-shooting. The source of the ray-shooting could be any point in the interior of P . We use ray-oracle to determine the intersection points of the rays and P . The convex hull of these points determine I1 - the initial inner polyhedral approximation of P . See Figure 1 for an illustration in R2 . P i1

I1

i2

c

i4 i3

Figure 1: An initial inner approximation I1 of the polygon P obtained by rayshooting.

Alternatively, instead of ray shooting, we can compute the points of I1 by ”plane-shooting”, i.e., we move randomly chosen planes along their normals until they become tangent to P . The convex hull of the touching points determine I1 . 2

2. Each vertex i of I1 touches P . We denoted by planei a supporting plane of i that do not intersect P . We compute all planei ’s and store them in a list named outerP lanesList. The halfspaces of all planes of outerP lanesList determines the initial outer approximation O1 (see Figure 2). Note that to each vertex of O1 corresponds a facet from I1 . o1 O1

P I1

o4 o2

o3

Figure 2: An initial outer approximation O1 of the polygon P .

3. For each vertex v ∈ O1 , we compute the distance to its corresponding plane in I1 , and store in distanceList. We sort the distance by decreasing order. 4. We repeat the following steps until the biggest distance in distanceList is smaller than some threshold value, or when the number of iterations exceed some threshold value. The number of iteration is denote by n, and In and On denote the inner and outer approximation in the n-th iteration. (a) let ok be the vertex of On whose distance to its corresponding facet fk is the biggest in distanceList. Consider the ray rk defined by ok and fk . Let ik be the intersection of rk and P . The point ik is the new vertex of the inner approximation Inew . See Figure 3 for an illustration. (b) Compute the plane pk , that is parallel to the supporting plane of fk and tangent to P . Let denote the touching point tk . Store pk in outerP lanesList. If the touching area is bigger than one point then we choose tk to be the centroid of the touching area. Note that we can also choose pk to be a supporting plane of the facet of P containing ik , but since in general pk will not be parallel to the supporting plane of fk , this variant may result in more ”unbalanced” approximation. (c) Compute the intersection points of the edges incident to ok and pk . These intersection points, denoted by {ok 0 }, are new vertices of the outer approximation Onew . The point ok does not contribute anymore to outer approximation, so we can discard it.

3

ok O1 i0k1

tk ik

P

i0k2

pk

fk I1

Figure 3: An iterative construction of an inner and an outer approximation of P.

(d) For each point in {ok 0 } we compute: the closest facet of Inew , the distance to it, and the edges of the Onew incident to that point. The edges of Onew incident to a point of {ok 0 } are the edges that connect that vertex to point of the visible part of Inew . This way, we avoid to compute Onew at each iteration. We also do not compute Inew each iteration. The part of interest of Inew is obtained by connecting ik and with the part of the inner approximation visible from ik . (e) Delete the first value in distanceList, insert the distances computed in the step (d) and resort the distanceList by decreasing order. 5. Compute the final inner and outer approximation polyhedron from the points of innerV ertices and outerV ertices, respectively. The outer approximation can be computed also as intersection of the halfspaces of the planes of outerP lanesList. The algorithm could be adapted to work for convex objects different than convex polyhedra.

3

Implementation

In this section we give a short overview on the main functions of the implementation. In the file ray_oracle.h we have two functions computing the intersection of a ray with the polyhedron. The main difference between the functions is the returned data, once we return the intersection point and once we return the plane which is tangent to the polyhedron in the intersection point of the polyhedron and the ray. Point intersection_ray_polyhedron(Polyhedron& P, Ray& R) {

4

typedef Polyhedron::Facet::Plane_3 Plane_3; CGAL::Object result; Point ipoint; Point rpoint(DOUBLE_MAX, DOUBLE_MAX, DOUBLE_MAX); for (Facet_iterator it = P.facets_begin(); it != P.facets_end(); ++it) { Plane_3 plane=it->plane(); result = CGAL::intersection(R, plane); if (CGAL::assign(ipoint, result)) { if (CGAL::has_smaller_distance_to_point(R.source(), ipoint, rpoint)) { rpoint = ipoint; } } } return rpoint; } The function returns the intersection point, which is of CGAL type Point_3, of the ray and the polyhedron. Plane intersection_ray_polyhedron2(Polyhedron& P, Ray& R) { typedef Polyhedron::Facet::Plane_3 Plane_3; CGAL::Object result; Plane rplane; Point ipoint(DOUBLE_MAX, DOUBLE_MAX, DOUBLE_MAX); Point rpoint(DOUBLE_MAX, DOUBLE_MAX, DOUBLE_MAX); for (Facet_iterator it = P.facets_begin(); it != P.facets_end(); ++it) { Plane_3 plane=it->plane(); result = CGAL::intersection(R, plane); if (CGAL::assign(ipoint, result)) { if (CGAL::has_smaller_distance_to_point(R.source(), ipoint, rpoint)) { rpoint = ipoint; rplane = plane; } } } return rplane; } The function returns the tangent plane of the intersection point, which is of CGAL type Plane_3, of the ray and the polyhedron. 5

In the file plane_oracle.h the function void plane_touch_polyhedron (Vector n_vec, Polyhedron P, std::vector& vec_touch_pnt) computs the tangent plane on the polyhedron for a given normal direction. The parameter Vector n_vec of CGAL type Vector_3 defines the normal of the plane, that is suppose to be tangent to the poylhedron P . The tangent points of the computet plane and the poylhedron are stored in a standard vector container std::vector& vec_touch_pnt. void plane_touch_polyhedron(Vector n_vec, Polyhedron P, std::vector& vec_touch_pnt) { Line line(CGAL::ORIGIN, n_vec); Point proj_pnt; RT k_min = DOUBLE_MAX; RT k_max = DOUBLE_MIN; RT k = DOUBLE_MAX; std::vector vec_up_pnt; std::vector vec_low_pnt; for (Vertex_iterator it = P.vertices_begin(); it != P.vertices_end(); ++it) { proj_pnt=line.projection(it->point()); k = approximate_division (proj_pnt.hx(), n_vec.hx()); if (k > k_max) { k_max = k; vec_up_pnt.clear(); vec_up_pnt.push_back(it->point()); } else if (k < k_min){ k_min = k; vec_low_pnt.clear(); vec_low_pnt.push_back(it->point()); } else if (k == k_max){ vec_up_pnt.push_back(it->point()); } else if (k == k_min){ vec_low_pnt.push_back(it->point()); } } for (std::vector::iterator it_up = vec_up_pnt.begin(); it_up != vec_up_pnt.end(); ++it_up) { vec_touch_pnt.push_back(*it_up); } for (std::vector::iterator it_low = vec_low_pnt.begin(); it_low != vec_low_pnt.end(); ++it_low) { vec_touch_pnt.push_back(*it_low); 6

} } This are the main classes we need to determine the approximations, they can be all found in the file intersect_structure.h: class S_approx

{

public: S_approx(): dist(0.0), vec_incid_edges(), outer_point (DOUBLE_MIN, DOUBLE_MIN, DOUBLE_MIN), inner_facet() {}; ~S_approx() {}; K::FT std::vector Point S_Facet std::vector

dist; vec_incid_edges; outer_point; inner_facet; vec_facet_visible;

}; class S_Edge { public: S_Edge():source(),target() {};

S_Edge (Point& src, Point& trg) { source=Point(src); target=Point(trg); } ~S_Edge() {} Point source; Point target; };

7

class S_Facet { public: S_Facet() : vec_edges() {}; S_Facet(std::vector vec_edges_tmp) { std::vector::iterator it_e; for (it_e = vec_edges_tmp.begin(); it_e != vec_edges_tmp.end(); ++it_e) { vec_edges.push_back(*it_e); } }; ~S_Facet() {}; std::vector vec_edges; };

This is the part of main() funciton where the main computation of the inner and outer approx is done: /*-----------------------------------------------------------------------------// for each p of outer_approx_P // distance_point_S_facet(Point& p, std::vector& vec_facet_inner, // Point& inner_p, S_Facet& facet) // store p, inner_point, inner_facet, edges of p in s_approx_tmp // put s_approx_tmp in vec_s_approx /-----------------------------------------------------------------------------*/ Vertex_iterator it_v; std::vector vec_e; S_approx s_approx_tmp; std::vector vec_facet_inner_visible; for (it_v=outer_approx_P.vertices_begin(); it_v != outer_approx_P.vertices_end(); ++it_v) { S_Facet facet; vec_e.clear(); vec_facet_inner_visible.clear();

8

s_approx_tmp.dist = distance_point_S_facet3(it_v->point(), vec_facet_inner,facet,vec_facet_inner_visible, vec_e, ray_src); s_approx_tmp.outer_point = it_v->point(); s_approx_tmp.inner_facet = facet; s_approx_tmp.vec_incid_edges = vec_e; s_approx_tmp.vec_facet_visible = vec_facet_inner_visible; std::cout