/*! \file polygontriangulation.h \brief Interface to the polygon triangulation library */ // $Id: polygontriangulation.h,v 1.3 2005/04/09 13:44:19 mbickel Exp $ /* This file is part of Advanced Strategic Command; http://www.asc-hq.de Copyright (C) 1994-1999 Martin Bickel and Marc Schellenberger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef polygontriangulationH #define polygontriangulationH #include #include #include #include namespace PolygonTriangulationLibrary { #include "libs/triangul/interfac.h" #include "libs/triangul/triangul.h" }; template class PolygonPainter { public: bool paintPolygon ( const Poly& poly ); protected: virtual void sortpolygon ( Poly& a ); virtual void painttriangle ( typename Poly::Point p[] ); virtual void painthorizline ( int x1, int x2, int y ); virtual void paintline ( int x1, int y1, int x2, int y2 ); virtual void setpoint ( int x, int y ) = 0; virtual int getpolydir ( const Poly& a); virtual double getsegmentdir ( int dx, int dy ); //! returns true if polygon correct virtual bool checkpolygon ( const Poly& poly ); //! returns true if lines a-b and c-d don't intersect virtual bool checkline ( typename Poly::Point a, typename Poly::Point b, typename Poly::Point d, typename Poly::Point e ); }; template bool PolygonPainter::paintPolygon ( const Poly& poly ) { if ( !poly.vertex.size() ) return true; // displayLogMessage ( 10, "pp1 "); if (checkpolygon ( poly )) { if ( poly.vertex.size() == 1 ) { setpoint ( poly.vertex[0].x, poly.vertex[0].y ); return true; } if ( poly.vertex.size() == 2 ) { paintline ( poly.vertex[0].x, poly.vertex[0].y, poly.vertex[1].x, poly.vertex[1].y ); return true; } // displayLogMessage ( 10, "pp2 "); Poly pol2 = poly; sortpolygon ( pol2 ); typedef double double2[2]; double2* floatpoints = new double2 [ pol2.vertex.size()+1 ]; for ( int i=0; i bool PolygonPainter::checkline( typename Poly::Point a, typename Poly::Point b, typename Poly::Point d, typename Poly::Point e ) { double r,s,t; b.x -= a.x; b.y -= a.y; e.x -= d.x; e.y -= d.y; /* if ( b.y != 0 && e.y != 0 ) { if ( abs( b.x / b.y - e.x / e.y ) < 1e-6 ) return false; } else if ( b.y == 0 && e.y == 0 ) return false; */ t = b.x * e.y - b.y * e.x; if (t != 0) { double m = ( a.x * b.y - a.y * b.x + d.y * b.x - d.x * b.y ); r = m / -t; double n = ( a.y * e.x - a.x * e.y + d.x * e.y - d.y * e.x ); s = n / t; if ( s>=0 && s <= 1 && r>=0 && r <= 1) return false; } /* endif */ return true; } template bool PolygonPainter::checkpolygon ( const Poly& poly ) { if ( poly.vertex.size() > 1 && poly.vertex.size() < 3 ) return true; else { size_t i,j,k; for ( i = 0; i < poly.vertex.size(); i++ ) for ( j = 0; j < poly.vertex.size(); j++ ) if ( i != j ) if ( poly.vertex[i].x == poly.vertex[j].x && poly.vertex[i].y == poly.vertex[j].y ) return false; k = poly.vertex.size() -1; for (i=0; i < k ; i++) { for (j = i +2; j < k ; j++) if (checkline ( poly.vertex[i], poly.vertex[i+1], poly.vertex[j], poly.vertex[j+1] ) == false) return false; if (i > 0 && j == k) if (checkline ( poly.vertex[i], poly.vertex[i+1], poly.vertex[j], poly.vertex[0] ) == false) return false; } /* endfor */ return true; } } template double PolygonPainter::getsegmentdir ( int dx, int dy ) { double alpha; if (dx) { alpha = atan ( (double) dy / (double) dx ); if ( dy < 0 ) { if ( dx < 0) alpha = -pi + alpha; } else if ( dx < 0) alpha = pi - alpha; } else { if (dy > 0) alpha = pi/2; else alpha = -pi/2; } /* endif */ return alpha; } template int PolygonPainter::getpolydir ( const Poly& a) { int p ; double alpha, beta, gamma; int r = 0; for (p=0; p< a.vertex.size(); p++) { if (p == 0) alpha = getsegmentdir( a.vertex[p].x - a.vertex[a.vertex.size()-1].x , a.vertex[p].y - a.vertex[a.vertex.size()-1].y ); else alpha = getsegmentdir( a.vertex[p].x - a.vertex[p-1].x, a.vertex[p].y - a.vertex[p-1].y ); if (p+1 >= a.vertex.size()) beta = getsegmentdir( a.vertex[0].x - a.vertex[p].x , a.vertex[0].y - a.vertex[p].y ); else beta = getsegmentdir( a.vertex[p+1].x - a.vertex[p].x, a.vertex[p+1].y - a.vertex[p].y ); gamma = beta - alpha ; if (gamma > pi) gamma = pi - gamma; if (gamma < -pi) gamma = -pi - gamma; r+= (int) ( gamma * 1000 ); } return r; } template void PolygonPainter::sortpolygon ( Poly& a ) { if ( a.vertex.size() >= 3 ) if ( getpolydir(a) < 0 ) { for ( int i=0;i< a.vertex.size()/2 ;i++ ) { typename Poly::Point p = a.vertex[i]; a.vertex[i] = a.vertex[a.vertex.size()-i-1]; a.vertex[a.vertex.size()-i-1] = p; } /* endfor */ } } template void PolygonPainter::painttriangle ( typename Poly::Point p[] ) { int x,y,dx1,dx2,dy1,dy2; for ( int i=0; i<2 ; ) { if ( p[i+1].y < p[i].y || ( p[i+1].y == p[i].y && p[i+1].x < p[i].x )) { x = p[i].x; p[i].x = p[i+1].x; p[i+1].x = x; y = p[i].y; p[i].y = p[i+1].y; p[i+1].y = y; i = 0; } else i++; } /* endfor */ if ( p[0].y < p[1].y ) { dx1 = p[1].x - p[0].x; dx2 = p[2].x - p[0].x; dy1 = p[1].y - p[0].y; dy2 = p[2].y - p[0].y; for (y=p[0].y; y<=p[1].y ; y++) painthorizline ( p[0].x + dx1 * (y - p[0].y) / dy1 , p[0].x + dx2 * (y - p[0].y) / dy2, y ); if (p[1].y < p[2].y) { dx1 = p[2].x - p[1].x; dy1 = p[2].y - p[1].y; for ( ; y<=p[2].y ; y++) painthorizline ( p[1].x + dx1 * (y - p[1].y) / dy1 , p[0].x + dx2 * (y - p[0].y) / dy2, y ); } } else { if ( p[1].y < p[2].y ) { dx1 = p[2].x - p[1].x; dx2 = p[2].x - p[0].x; dy1 = p[2].y - p[0].y; for (y=p[0].y; y<=p[2].y ; y++) painthorizline ( p[1].x + dx1 * (y - p[0].y) / dy1 , p[0].x + dx2 * (y - p[0].y) / dy1, y ); } else painthorizline ( p[0].x, p[2].x, p[0].y ); } } template void PolygonPainter::painthorizline ( int x1, int x2, int y ) { int dx; if (x1 > x2) dx = -1; else if (x1 < x2) dx = 1; else { setpoint ( x2, y ); return; } int x= x1; do { setpoint ( x, y ); x += dx; } while ( x != x2 ); /* enddo */ setpoint ( x, y ); } template void PolygonPainter::paintline ( int x1, int y1, int x2, int y2 ) { float m, b; int w; float yy1, yy2, xx1, xx2; if ( x1 == x2) { for (w=y1;w<=y2 ;w++ ) setpoint ( x1, w ); } else { if ( y1 == y2) { for (w=x1;w<=x2 ;w++ ) setpoint( w, y1 ); } else { yy1 = y1; yy2 = y2; xx1 = x1; xx2 = x2; m = (yy2 - yy1) / (xx2 - xx1); b = y1 - m * x1; if ((m <= 1) && (m >= -1)) { if (x2 < x1) { w = x2; x2 = x1; x1 = w; w = y2; y2 = y1; y1 = w; } for (w = x1; w <= x2; w++) setpoint(w, (int) (m * w + b) ); } else { if (y2 < y1) { w = x2; x2 = x1; x1 = w; w = y2; y2 = y1; y1 = w; } for (w = y1; w <= y2; w++) { setpoint( (int) ((w - b) / m), w ); } } } /* endif */ } } #endif