home *** CD-ROM | disk | FTP | other *** search
/ Photo CD Demo 1 / Demo.bin / graphtal / cone.c < prev    next >
C/C++ Source or Header  |  1992-10-22  |  5KB  |  228 lines

  1. /*
  2.  * Cone.C - methods for cone manipulations.
  3.  *
  4.  * Copyright (C) 1992, Christoph Streit (streit@iam.unibe.ch)
  5.  * All rights reserved.
  6.  *
  7.  * This software may be freely copied, modified, and redistributed
  8.  * provided that this copyright notice is preserved on all copies.
  9.  *
  10.  * You may not distribute this software, in whole or in part, as part of
  11.  * any commercial product without the express consent of the authors.
  12.  *
  13.  * There is no warranty or other guarantee of fitness of this software
  14.  * for any purpose.  It is provided solely "as is".
  15.  *
  16.  */
  17.  
  18. #include "Cone.h"
  19. #include "Cylinder.h"
  20. #include "transform.h"
  21.  
  22. //___________________________________________________________ Cone
  23.  
  24. Cone::Cone(real r1, const Vector& bottom, 
  25.        real r2, const Vector& top)
  26. {
  27.   /*
  28.    * Find the axis and axis length.
  29.    */
  30.   Vector axis = top - bottom;
  31.   real len = axis.normalize();
  32.  
  33.   /*
  34.    * To render a cone, we transform the desired cone into
  35.    * a canonical, Z-axis aligned, unit length, unit radius
  36.    * at the apex cone.
  37.    */
  38.  
  39.   /*
  40.    * "tantheta" is the change in radius per unit length along
  41.    * the cone axis.
  42.    */
  43.   real tantheta = (r2-r1)/len;
  44.  
  45.   /*
  46.    * lprime defines the distance along the axis where the cone starts
  47.    */
  48.   real lprime = r1/tantheta;
  49.  
  50.   /*
  51.    * Find the true base (origin) of the cone.
  52.    */
  53.   Vector base = (-lprime)*axis + bottom;
  54.  
  55.   /*
  56.    * tlen is the total length of the cone.
  57.    */
  58.   real totalLengthOfCone = lprime+len;
  59.  
  60.   startDistance = lprime/totalLengthOfCone;
  61.  
  62.   trans = new TransMatrix(coordSystemTransform(base, axis, 
  63.                      r2, totalLengthOfCone));
  64.   itrans = new TransMatrix(*trans);
  65.   itrans->invert();
  66. }
  67.  
  68. GeoObject* Cone::create(real r1, const Vector& bottom, 
  69.             real r2, const Vector& top)
  70. {
  71.   /*
  72.    * Check the arguments.
  73.    */
  74.   if (equal(r1, r2))
  75.     return Cylinder::create(r1, bottom, top);
  76.       
  77.   if ((top-bottom).length() < EPSILON)
  78.     return NULL;
  79.  
  80.   if ((r1 < 0) || r2 < 0)
  81.     return NULL;
  82.  
  83.   /*
  84.    * The passed basepoint must be closer to the origin of the
  85.    * cone than the apex point, implying that the base radius
  86.    * must be smaller than the apex radius.  If the values passed
  87.    * reflect the opposite, we switch everything.
  88.    */
  89.   if (r2 < r1) 
  90.     return new Cone(r2, top, r1, bottom);
  91.   else
  92.     return new Cone(r1, bottom, r2, top);
  93. }
  94.  
  95. /*
  96.  * Ray cone intersection.
  97.  *
  98.  * The code is adapted from Craig Kolbs rayshade.
  99.  */
  100.  
  101. int Cone::intersect(const Ray& ray, real minDist, real& maxDist)
  102. {
  103.   real t1, t2, a, b, c, disc, zpos;
  104.  
  105.   intersectionTests++;
  106.  
  107.   a = ray.getDir()[0]*ray.getDir()[0] + ray.getDir()[1]*ray.getDir()[1] 
  108.     - ray.getDir()[2]*ray.getDir()[2];
  109.   b = ray.getDir()[0]*ray.getOrig()[0] + ray.getDir()[1]*ray.getOrig()[1] 
  110.     - ray.getDir()[2]*ray.getOrig()[2];
  111.   c = ray.getOrig()[0]*ray.getOrig()[0] + ray.getOrig()[1]*ray.getOrig()[1]
  112.     - ray.getOrig()[2]*ray.getOrig()[2];
  113.  
  114.   if (fabs(a) < EPSILON) {
  115.     /*
  116.      * Only one intersection point...
  117.      */
  118.     t1 = -0.5*c / b;
  119.     zpos = ray.getOrig()[2] + t1*ray.getDir()[2];
  120.     if (t1 < minDist || zpos < startDistance || zpos > 1.)
  121.       return FALSE;
  122.  
  123.     if (t1 < maxDist) {
  124.       maxDist = t1;
  125.       intersections++;
  126.       return TRUE;
  127.     }
  128.     return FALSE;
  129.   }
  130.   else {
  131.     disc = b*b - a*c;
  132.     if (disc < 0.)
  133.       return FALSE;        /* No possible intersection */
  134.  
  135.     disc = sqrt(disc);
  136.     t1 = (-b + disc) / a;
  137.     t2 = (-b - disc) / a;
  138.  
  139.     /*
  140.      * Clip intersection points.
  141.      */
  142.     zpos = ray.getOrig()[2] + t1*ray.getDir()[2];
  143.     if (t1 < minDist || zpos < startDistance || zpos > 1.) {
  144.       zpos = ray.getOrig()[2] + t2*ray.getDir()[2];
  145.       if (t2 < minDist || zpos < startDistance || zpos > 1.)
  146.     return FALSE;
  147.       else
  148.     t1 = t2;
  149.     } 
  150.     else {
  151.       zpos = ray.getOrig()[2] + t2*ray.getDir()[2];
  152.       if (t2 >= minDist && zpos >= startDistance && zpos <= 1. && t2 < t1)
  153.     t1 = t2;
  154.     }
  155.     if (t1 < maxDist) {
  156.       maxDist = t1;
  157.       intersections++;
  158.       return TRUE;
  159.     }
  160.     return FALSE;
  161.   }
  162. }
  163.  
  164. /*
  165.  * Compute cone normal at point p.
  166.  */
  167.  
  168. Vector Cone::normal(const Vector& p) const
  169. {
  170.   /*
  171.    * If p is on the z-axis, return the cone axis (0,0,1)
  172.    */
  173.   if (equal(p[0], 0) && equal(p[1], 0))
  174.     return Vector(0,0,1);
  175.  
  176.   /*
  177.    * The following is equal to (p*(0, 0, 1))*p
  178.    */
  179.   return Vector(p[0]*p[2], p[1]*p[2], -p[0]*p[0] - p[1]*p[1]);
  180. }
  181.  
  182.  
  183. /*
  184.  * Split the cone into polygon (rectangles)
  185.  */
  186.  
  187. PolygonList* Cone::tesselate(const BoundingBox&)
  188. {
  189.   const real resolution = 10;
  190.   real delta = 2*M_PI/resolution;
  191.   real lastX = 1;
  192.   real lastY = 0;
  193.   real x, y;
  194.  
  195.   Polygon* p;
  196.   PolygonList* polys = new PolygonList(resolution);
  197.  
  198.   /* 
  199.    * Generate points on the edge of the disc.
  200.    */
  201.   for (real alpha=delta; alpha <= 2*M_PI; alpha += delta) {
  202.     x = cos(alpha); y = sin(alpha);
  203.     p = new Polygon(Vector(lastX*startDistance, 
  204.                lastY*startDistance, startDistance),
  205.             Vector(x*startDistance, y*startDistance, startDistance),
  206.             Vector(x, y, 1), Vector(lastX, lastY, 1));
  207.     p->transform(*trans);
  208.     polys->append(p);
  209.     lastX = x; lastY = y;
  210.   }
  211.  
  212.   return polys;
  213. }
  214.  
  215. /*
  216.  * If a transformation is given for the defined cone, postmultiply
  217.  * it to the already computed transformations.
  218.  */
  219.  
  220. int Cone::setTransform(TransMatrix* tmat)
  221. {
  222.   TransMatrix* matMul = new TransMatrix((*trans) * (*tmat));
  223.   delete itrans;
  224.   delete trans;
  225.  
  226.   return GeoObject::setTransform(matMul);
  227. }
  228.