diff --git a/main/Scene-load.cc b/main/Scene-load.cc index a8d077a..29714aa 100644 --- a/main/Scene-load.cc +++ b/main/Scene-load.cc @@ -642,15 +642,19 @@ refptr Scene::processNGon(refptr node) refptr p = new Polygon(); double radius = node->getChildren()[0]->getNumber(); int n = node->getInteger(); + int step = n < 0 ? -1 : 1; + n = abs(n); if (n < 3) n = 3; + int pos = 0; double astep = 2.0 * M_PI / n; for (int i = 0; i < n; i++) { p->push_back(new Vector( - radius * cos(i * astep), - radius * sin(i * astep), + radius * cos(pos * astep), + radius * sin(pos * astep), 0.0)); + pos += step; } return p; } diff --git a/shapes/Extrude.cc b/shapes/Extrude.cc index e249f73..9d5eadc 100644 --- a/shapes/Extrude.cc +++ b/shapes/Extrude.cc @@ -4,6 +4,7 @@ #include #include "Extrude.h" +#include "util/Polygon.h" #include "util/Solver.h" using namespace std; @@ -19,6 +20,63 @@ Shape::IntersectionList Extrude::intersect(refptr _this, const Ray & ray) Ray ray_inv = m_inverse.transform_ray(ray); IntersectionList res; + int n_polygons = m_polygons.size(), n_offsets = m_offsets.size(); + for (int p = 0; p < n_polygons; p++) + { + refptr polygon = m_polygons[p]; + double distance = 0.0; + Vector scale(1.0, 1.0, 1.0); + Vector shift(0.0, 0.0, 0.0); + for (int o = 0; o < n_offsets; o++) + { + Offset & offset = m_offsets[o]; + for (int pt = 0, n_pts = polygon->size(); pt < n_pts; pt++) + { + Vector p1 = *(*polygon)[pt] * scale + shift; + Vector p2 = *(*polygon)[(pt+1) % n_pts] * scale + shift; + Vector p3 = *(*polygon)[(pt+1) % n_pts] + * offset.scale + offset.shift; + Vector p4 = *(*polygon)[pt] * offset.scale + offset.shift; + p3[2] += offset.distance; + p4[2] += offset.distance; + Vector e1 = p2 - p1; + Vector e2 = p3 - p2; + Vector normal = (e1 * e2).normalize(); + double a = normal[0], b = normal[1], c = normal[2]; + double d = -a * p1[0] - b * p1[1] - c * p1[2]; + if (ray_inv.getDirection() % normal < 0) /* skip backfaces */ + { + LinearSolver solver( a * ray_inv.getDirection()[0] + + b * ray_inv.getDirection()[1] + + c * ray_inv.getDirection()[2], + a * ray_inv.getOrigin()[0] + + b * ray_inv.getOrigin()[1] + + c * ray_inv.getOrigin()[2] + + d); + Solver::Result solutions = solver.solve(); + if (solutions.numResults > 0) + { + if (solutions.results[0] > 0.0) + { + Vector ipoint = ray_inv[solutions.results[0]]; + Polygon quad; + quad.add(p1).add(p2).add(p3).add(p4); + if (quad.containsPoint(ipoint)) + { + res.add(Intersection(_this, + m_transform.transform_point(ipoint), + m_transform.transform_normal(normal))); + } + } + } + } + } + distance += offset.distance; + scale = offset.scale; + shift = offset.shift; + } + } + return res; } diff --git a/util/Polygon.cc b/util/Polygon.cc index ccf9415..b57ac67 100644 --- a/util/Polygon.cc +++ b/util/Polygon.cc @@ -1,2 +1,20 @@ +#include /* acos(), M_PI */ + #include "Polygon.h" + +#define FP_EQUAL(x,y) (fabs((x)-(y)) < 1E-6) + +bool Polygon::containsPoint(const Vector & v) +{ + double angle_sum = 0.0; + for (int i = 0, sz = size(); i < sz; i++) + { + Vector v1 = *(*this)[i] - v; + Vector v2 = *(*this)[(i+1) % sz] - v; + double cosine = (v1 % v2) / (v1.mag() * v2.mag()); + double angle = acos(cosine); + angle_sum += angle; + } + return FP_EQUAL(angle_sum, 2.0 * M_PI); +} diff --git a/util/Polygon.h b/util/Polygon.h index 3226d99..ffb00fd 100644 --- a/util/Polygon.h +++ b/util/Polygon.h @@ -9,6 +9,18 @@ class Polygon : public std::vector< refptr > { + public: + Polygon & add(const Vector & v) + { + push_back(new Vector(v)); + return *this; + } + Polygon & add(refptr v) + { + push_back(v); + return *this; + } + bool containsPoint(const Vector & v); }; #endif