polygon.cpp

Go to the documentation of this file.
00001 /* file name  : staticinit.cpp
00002  * author     : Michael Brailsford
00003  * created    : Sun Oct 14 17:29:40 -0500 2007
00004  * copyright  : 2007 Michael Brailsford
00005  */
00006 
00007 #include "polygon.h"
00008 #include "scene.h"
00009 #include <math.h>
00010 #include <algorithm>
00011 
00012 // This actually makes the static init work.
00013 Polygon::StaticInit Polygon::m_init;
00014 
00015 //{{{
00016 Polygon::Polygon(std::string color, std::string material, std::string bumpmap)
00017     : m_normal(),
00018       m_vertices()
00019 {
00020     Scene * scene = Scene::get_instance();
00021     m_material    = scene->get_material(material);
00022     m_bumpmap     = scene->get_bumpmap(bumpmap);
00023 }
00024 //}}}
00025 
00026 //{{{
00027 bool Polygon::add_vertex(Point3D vertex) {
00028     if(find(m_vertices.begin(), m_vertices.end(), vertex) == m_vertices.end()) {
00029         if(m_vertices.size() >= 3) {
00030             // From http://mathworld.wolfram.com/Coplanar.html:
00031             // Coplanarity is equivalent to the statement that the pair of lines
00032             // determined by the four points are not skew, and can be equivalently
00033             // stated in vector form as
00034             // (x_2-x_0).[(x_1-x_0)x(x_3-x_2)]==0.
00035             //
00036             // [where x_3 is the new vertex to be checked for coplanarity]
00037             if(dot_product(m_vertices[2] - m_vertices[0], cross_product((m_vertices[1] - m_vertices[0]), (vertex - m_vertices[2]))) == 0) {
00038                 return false;
00039             }
00040             else {
00041                 log_warn("mbrt does not support Polygons with more than 3 vertices.");
00042             }
00043         }
00044 
00045         m_vertices.push_back(vertex);
00046 
00047         // Calcluate the normal as soon as we can.
00048         if(m_vertices.size() == 3) {
00049             m_normal = Ray(m_vertices[0], cross_product((m_vertices[1] - m_vertices[0]), (m_vertices[2] - m_vertices[0])));
00050             m_d      = dot_product(m_vertices[0], m_normal.direction());
00051         }
00052         return true;
00053     }
00054     else {
00055         // The vertex already exists in the vertex list.
00056         return false;
00057     }
00058 }
00059 //}}}
00060 
00061 //{{{
00062 bool Polygon::collides_with(const Ray &ray, double &t) const {
00063     // Start by testing the ray to see if it intersects with plane which
00064     // contains the polygon.
00065     Point3D orig = ray.origin();
00066     Vector dir = ray.direction();
00067 
00068     double denominator = dot_product(dir, m_normal.direction());
00069     if(denominator > -0.0001 && denominator < 0.0001) {
00070         return false;
00071     }
00072 
00073     double numerator = m_d - dot_product(orig, m_normal.direction());
00074     if(numerator > -0.0001 && numerator < 0.0001) {
00075         return false;
00076     }
00077 
00078     t = numerator / denominator;
00079     if(t <= 0) {
00080         return false;
00081     }
00082 
00083     // Now we need to project the polygon onto a 2D plane to apply the Jordan
00084     // Curve Theorem, which is a really fancy way of saying we shoot a ray in
00085     // an arbitrary direction from the point of intersection and count how many
00086     // times that ray intersects the polygon boundary.  If the number is odd,
00087     // the point is inside the polygon, if the number is even then the point
00088     // is outside the polygon.
00089 
00090     // We first need to point the point where the intersects the plane.
00091     Point3D intersection_point = ray.origin() + (ray.direction() * t);
00092 
00093     // This portion of the code was lifted from
00094     //    http://www.softsurfer.com/Archive/algorithm_0105/algorithm_0105.htm
00095     // And is subject to the following copyright notice:
00096     // Copyright 2001, softSurfer (www.softsurfer.com)
00097     // This code may be freely used and modified for any purpose
00098     // providing that this copyright notice is included with it.
00099     // SoftSurfer makes no warranty for this code, and cannot be held
00100     // liable for any real or imagined damage resulting from its use.
00101     // Users of this code must verify correctness for their application.
00102     //
00103     // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00104     // THIS CODE IS ONLY VALID FOR TRIANGLES, IT DOES NOT GENERLIZE TO N SIDED
00105     // POLYGONS WHERE N > 3
00106     // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00107     
00108     // is intersection_point inside the triangle?
00109     // get triangle edge vectors and plane normal
00110     Vector u, v, n;
00111     u = m_vertices[1] - m_vertices[0];   // This is an edge vector of the polygon
00112     v = m_vertices[2] - m_vertices[0];   // This is another edge vector of the polygon
00113     n = cross_product(u, v);                           // normal 
00114 
00115     float uu, uv, vv, wu, wv, D;
00116     uu = dot_product(u,u);
00117     uv = dot_product(u,v);
00118     vv = dot_product(v,v);
00119     Vector w = intersection_point - m_vertices[0];
00120     wu = dot_product(w,u);
00121     wv = dot_product(w,v);
00122     D = uv * uv - uu * vv;
00123 
00124     // get and test parametric coords
00125     float s, _t;
00126     s = (uv * wv - vv * wu) / D;
00127     if (s < 0.0 || s > 1.0)         // intersection_point is outside T
00128         return false;
00129     _t = (uv * wu - uu * wv) / D;
00130     if (_t < 0.0 || (s + _t) > 1.0) // intersection_point is outside T
00131         return false;
00132 
00133     return true;                    // intersection_point is in T
00134 
00135 }
00136 //}}}
00137 // This is an incomplete general solution to determine if a point is inside an N sided polygon, where N > 3      {{{
00138 #if 0
00139     // Determine the coordinate with greatest magnitude and "project" the
00140     // polygon onto the 2D plane by dropping that largest coord from
00141     // intersection_point and all the vertices.  This is odd, but correct.
00142     // We also transform all vertices and the intersection to the origin,
00143     // where the intersection point will be at the origin.
00144     Point3D projected_intersection(0, 0, 0);
00145     vector<Point3D> projection;
00146     vector<Point3D>::iterator iter = m_vertices.begin();
00147     vector<Point3D>::iterator end  = m_vertices.end();
00148     if( fabs(intersection_point.x) > fabs(intersection_point.y) && fabs(intersection_point.x) > fabs(intersection_point.z)) {
00149         for(; iter != end; ++iter) {
00150             projection.push_back(Point3D(iter->y - intersection_point.y , iter->z - intersection_point.z, 0));
00151         }
00152     }
00153     else if( fabs(intersection_point.y) > fabs(intersection_point.x) && fabs(intersection_point.y) > fabs(intersection_point.z)) {
00154         for(; iter != end; ++iter) {
00155             projection.push_back(Point3D(iter->x - intersection_point.x, iter->z - intersection_point.z, 0));
00156         }
00157     }
00158     else if( fabs(intersection_point.z) > fabs(intersection_point.x) && fabs(intersection_point.z) > fabs(intersection_point.y)) {
00159         for(; iter != end; ++iter) {
00160             projection.push_back(Point3D(iter->x - intersection_point.x, iter->y - intersection_point.y, 0));
00161         }
00162     }
00163 
00164     // Our polygon is now projected onto the XY plane, and the intersection
00165     // point is at (0, 0), now determine how many times the ray from the
00166     // origin along the +X axis intersects the polygon.  This amounts to
00167     // counting the number of times the line segments which make up the
00168     // polygon cross the X axis.
00169     int ncross = 0;
00170     vector<Point3D>::iterator iter = projection.begin();
00171     vector<Point3D>::iterator end  = projection.end();
00172     Point3D prev_vertex = *(iter++);
00173     for(; iter != end; ++iter) {
00174         // the line segment goes from prev_vertex --> *iter
00175         // We have to account for the following cases
00176         // 1)  prev_vertex's x and y coords are both < 0
00177         //
00178         // 2)  prev_vertex's x and y coords are both > 0
00179         // 3)  prev_vertex's x coord is < 0 and y coord > 0
00180         // 3)  prev_vertex's x coord is < 0 and y coord > 0
00181         if(prev_vertex.y > 0)
00182 
00183                 prev_vertex = *iter;
00184     }
00185 
00186     return true;
00187 #endif
00188     //}}}
00189 
00190 //{{{
00191 Ray Polygon::get_normal(const Point3D &p) const {
00192     return Ray(p, m_normal.direction() );
00193 }
00194 //}}}

Generated on Tue Oct 30 22:12:15 2007 for mbrt by  doxygen 1.5.2