00001 //$Header: /home/ben/Mapper/c++/RCS/delaunay.cpp,v 6.8 2002/06/14 22:28:47 ben Exp $
00002 // Copyright Benedict Adamson 2002.
00003 // This file is part of Mapper.
00004
00005 // Mapper is free software; you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation; either version 2 of the License, or
00008 // (at your option) any later version.
00009
00010 // Mapper is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00013 // GNU General Public License for more details.
00014
00015 // You should have received a copy of the GNU General Public License
00016 // along with Mapper; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00018
00029 #include <algorithm>
00030 #include <cassert>
00031 #include <cstdlib>
00032
00033 #include "delaunay.h"
00034 #include "matrix2x2.h"
00035
00036
00037
00038 delaunay::triangle::triangle(
00039 const vector2 &v0,
00040 const vector2 &v1,
00041 const vector2 &v2
00042 )
00043 {
00044 this->vertex_[0] = v0;
00045 this->vertex_[1] = v1;
00046 this->vertex_[2] = v2;
00047 this->calculate_circumcircle();
00048 {//Postconditions:
00049 assert( this->vertex(0) == v0 );
00050 assert( this->vertex(1) == v1 );
00051 assert( this->vertex(2) == v2 );
00052 };
00053 };
00054
00055
00056
00057 delaunay::triangle::triangle(
00058 const delaunay::triangle::triangle &t
00059 )
00060 :
00061 circumcentre_( t.circumcentre_ ),
00062 circumradius2( t.circumradius2 )
00063 {
00064 this->vertex_[0] = t.vertex_[0];
00065 this->vertex_[1] = t.vertex_[1];
00066 this->vertex_[2] = t.vertex_[2];
00067 }
00068
00069 const double delaunay::triangle::circumradius(void) const
00070 {
00071 return sqrt(this->circumradius2);
00072 }
00073
00074
00075
00076 bool delaunay::triangle::circumcircle_contains(
00077 const vector2 &p
00078 ) const
00079 {
00080 const vector2 rp( p - this->circumcentre_ );
00081 return rp*rp <= this->circumradius2;
00082 }
00083
00084
00085
00086 void delaunay::triangle::calculate_circumcircle(void)
00087 {
00088 const vector2 &v0( this->vertex(0) );
00089 const vector2 &v1( this->vertex(1) );
00090 const vector2 &v2( this->vertex(2) );
00091 {//Calculate the circumcentre
00092 const vector2 d01( v1 - v0 );
00093 const vector2 d02( v2 - v0 );
00094 const vector2 d12( v2 - v1 );
00095 const vector2 m01( 0.5*(v0 + v1) );
00096 const vector2 m02( 0.5*(v0 + v2) );
00097 const vector2 r01( -d01.y, d01.x );
00098 const vector2 r02( -d02.y, d02.x );
00099 const matrix2x2 M(
00100 r01.x, d02.y,
00101 d01.x, -r02.y
00102 );
00103 const vector2 y( 0.5*d12 );
00104 const vector2 a( matrix2x2::solve( M, y ) );
00105 const vector2 c01 = m01 + a[0] * r01;
00106 const vector2 c02 = m02 + a[1] * r02;
00107 this->circumcentre_ = 0.5*(c01 + c02);
00108 };
00109 {//Calculate the square of the circumradius
00110 const vector2 r0 = v0 - this->circumcentre_;
00111 this->circumradius2 = r0*r0;
00112 };
00113 }
00114
00115
00116
00117 delaunay::triangulation::triangulation(
00118 const double l,
00119 const double r,
00120 const double t,
00121 const double b
00122 )
00123 :
00124 left( l ),
00125 right( r ),
00126 top( t ),
00127 bottom( b ),
00128 tl( l, t ),
00129 tr( r, t ),
00130 br( r, b ),
00131 bl( l, b )
00132 {
00133 this->triangles_.reserve( 2 );
00134 this->triangles_.push_back( triangle( tl, tr, bl ) );
00135 this->triangles_.push_back( triangle( bl, tr, br ) );
00136 }
00137
00138
00139
00140 delaunay::triangulation::~triangulation(void)
00141 {
00142 //Do nothing
00143 }
00144
00145
00146
00147 void delaunay::triangulation::add_point(
00148 const vector2 &p
00149 )
00150 {
00151 {//Preconditions:
00152 assert( this->left <= p.x && p.x <= this->right );
00153 assert( this->bottom <= p.y && p.y <= this->top );
00154 assert( !this->contains( p ) );
00155 };
00156 vector< delaunay::triangle > new_triangles;
00157 vector< delaunay::edge > edges;
00158 {//heuristic: reserve space
00159 static const unsigned expected_intersect = 10u;
00160 new_triangles.reserve( this->triangles_.size() + expected_intersect );
00161 edges.reserve( expected_intersect * 3u );
00162 };
00163 for( vector< delaunay::triangle >::iterator i = this->triangles_.begin();
00164 i != this->triangles_.end();
00165 i++ ){//scan existing triangles
00166 if( (*i).circumcircle_contains( p ) ){
00167 //triangle will be changed
00168 edges.push_back( edge( (*i).vertex(0), (*i).vertex(1) ) );
00169 edges.push_back( edge( (*i).vertex(1), (*i).vertex(2) ) );
00170 edges.push_back( edge( (*i).vertex(2), (*i).vertex(0) ) );
00171 }else{
00172 //triangle not changed
00173 new_triangles.push_back( *i );
00174 };
00175 };
00176 {//eliminate edges that are duplicated
00177 vector< delaunay::edge > new_edges;
00178 new_edges.reserve( edges.size() ); //heuristic
00179 vector< delaunay::edge >::iterator begin = edges.begin();
00180 vector< delaunay::edge >::iterator end = edges.end();
00181 for( vector< delaunay::edge >::iterator i = begin;
00182 i != end;
00183 i++ ){
00184 edge &e( *i );
00185 bool duplicate = false;
00186 {//determine whether duplicate
00187 //Not efficient, but N is usually small
00188 vector< delaunay::edge >::iterator j = begin;
00189 while( !duplicate && j != end ){
00190 if( j != i ){
00191 duplicate = (e == *j);
00192 };//else skip self
00193 j++;
00194 };
00195 };
00196 if( !duplicate ){
00197 new_edges.push_back( e );
00198 };
00199 };
00200 edges.swap( new_edges );
00201 };
00202 {//create the new triangles
00203 for( vector< delaunay::edge >::iterator i = edges.begin();
00204 i != edges.end();
00205 i++ ){
00206 edge &e( *i );
00207 new_triangles.push_back(
00208 triangle( e.vertex(0), e.vertex(1), p )
00209 );
00210 };
00211 }
00212 this->triangles_.swap( new_triangles );
00213 {//Postconditions:
00214 assert( this->contains( p ) );
00215 };
00216 }
00217
00218
00219
00220 bool delaunay::triangulation::contains(
00221 const vector2 &p
00222 ) const
00223 {
00224 //assert( this->contains( this->tl ) );
00225 //assert( this->contains( this->tr ) );
00226 //assert( this->contains( this->br ) );
00227 //assert( this->contains( this->bl ) );
00228 //Indicates whether the given point is a vertex
00229 //of any of the traingles of the triangulation.
00230 register bool c = false;
00231 vector< triangle >::const_iterator i = this->triangles_.begin();
00232 const vector< triangle >::const_iterator end = this->triangles_.end();
00233 while( !c && i != end ){
00234 const triangle &t( *i );
00235 c = (t.vertex(0) == p) ||
00236 (t.vertex(1) == p ) ||
00237 (t.vertex(2) == p);
00238 i++;
00239 };
00240 return c;
00241 }