disable the unrecognized nls and x flags
[AROS-Contrib.git] / gfx / povray / prism.c
blob919a6b52527598300edefa4ade540841c2d70007
1 /****************************************************************************
2 * prism.c
4 * This module implements functions that manipulate prisms.
6 * This module was written by Dieter Bayer [DB].
8 * from Persistence of Vision(tm) Ray Tracer
9 * Copyright 1996,1999 Persistence of Vision Team
10 *---------------------------------------------------------------------------
11 * NOTICE: This source code file is provided so that users may experiment
12 * with enhancements to POV-Ray and to port the software to platforms other
13 * than those supported by the POV-Ray Team. There are strict rules under
14 * which you are permitted to use this file. The rules are in the file
15 * named POVLEGAL.DOC which should be distributed with this file.
16 * If POVLEGAL.DOC is not available or for more info please contact the POV-Ray
17 * Team Coordinator by email to team-coord@povray.org or visit us on the web at
18 * http://www.povray.org. The latest version of POV-Ray may be found at this site.
20 * This program is based on the popular DKB raytracer version 2.12.
21 * DKBTrace was originally written by David K. Buck.
22 * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
24 *****************************************************************************/
26 /****************************************************************************
28 * Explanation:
30 * The prism primitive is defined by a set of points in 2d space which
31 * are interpolated by linear, quadratic, or cubic splines. The resulting
32 * 2d curve is swept along a straight line to form the final prism object.
34 * All calculations are done in the object's (u,v,w)-coordinate system
35 * with the (w)-axis being the sweep axis.
37 * One spline segment in the (u,v)-plane is given by the equations
39 * fu(t) = Au * t * t * t + Bu * t * t + Cu * t + Du and
40 * fv(t) = Av * t * t * t + Bv * t * t + Cv * t + Dv,
42 * with the parameter t ranging from 0 to 1.
44 * To intersect a ray R = P + k * D transformed into the object's
45 * coordinate system with the linear swept prism object, the equation
47 * Dv * fu(t) - Du * fv(t) - (Pu * Dv - Pv * Du) = 0
49 * has to be solved for t. For valid intersections (0 <= t <= 1)
50 * the corresponding k can be calculated from equation
52 * Pu + k * Du = fu(t) or Pv + k * Dv = fv(t).
54 * In the case of conic sweeping the equation
56 * (Pv * Dw - Pw * Dv) * fu(t) - (Pu * Dw - Pw * Du) * fv(t)
57 * + (Pu * Dv - Pv * Du) = 0
59 * has to be solved for t. For valid intersections (0 <= t <= 1)
60 * the corresponding k can be calculated from equation
62 * Pu + k * Du = (Pw + k * Dw) * fu(t) or
63 * Pv + k * Dv = (Pw + k * Dw) * fv(t).
65 * Note that the polynomal to solve has the same degree as the
66 * spline segments used.
68 * Note that Pu, Pv, Pw and Du, Dv, Dw denote the coordinates
69 * of the vectors P and D.
71 * Syntax:
73 * prism {
74 * [ linear_sweep | cubic_sweep ]
75 * [ linear_spline | quadratic_spline | cubic_spline ]
77 * height1, height2,
78 * number_of_points
80 * <P(0)>, <P(1)>, ..., <P(n-1)>
82 * [ open ]
83 * [ sturm ]
84 * }
86 * Note that the P(i) are 2d vectors.
88 * ---
90 * Ideas for the prism was taken from:
92 * James T. Kajiya, "New techniques for ray tracing procedurally
93 * defined objects", Computer Graphics, 17(3), July 1983, pp. 91-102
95 * Kirk ...
97 * ---
99 * May 1994 : Creation. [DB]
101 *****************************************************************************/
103 #include "frame.h"
104 #include "povray.h"
105 #include "vector.h"
106 #include "povproto.h"
107 #include "bbox.h"
108 #include "matrices.h"
109 #include "objects.h"
110 #include "polysolv.h"
111 #include "prism.h"
115 /*****************************************************************************
116 * Local preprocessor defines
117 ******************************************************************************/
119 /* Minimal intersection depth for a valid intersection. */
121 #define DEPTH_TOLERANCE 1.0e-4
123 /* |Coefficients| < COEFF_LIMIT are regarded to be 0. */
125 /*#define COEFF_LIMIT 1.0e-20 */
127 #define COEFF_LIMIT 1.0e-16 /*changed by CEY 11/18/95 */
129 /* Part of the prism hit. */
131 #define BASE_HIT 1
132 #define CAP_HIT 2
133 #define SPLINE_HIT 3
137 /*****************************************************************************
138 * Local typedefs
139 ******************************************************************************/
143 /*****************************************************************************
144 * Static functions
145 ******************************************************************************/
147 static int intersect_prism (RAY *Ray, PRISM *Prism, PRISM_INT *Intersection);
148 static int in_curve (PRISM *Prism, DBL u, DBL v);
149 static int test_rectangle (VECTOR P, VECTOR D, DBL x1, DBL y1, DBL x2, DBL y2);
150 static int All_Prism_Intersections (OBJECT *Object, RAY *Ray, ISTACK *Depth_Stack);
151 static int Inside_Prism (VECTOR point, OBJECT *Object);
152 static void Prism_Normal (VECTOR Result, OBJECT *Object, INTERSECTION *Inter);
153 static PRISM *Copy_Prism (OBJECT *Object);
154 static void Translate_Prism (OBJECT *Object, VECTOR Vector, TRANSFORM *Trans);
155 static void Rotate_Prism (OBJECT *Object, VECTOR Vector, TRANSFORM *Trans);
156 static void Scale_Prism (OBJECT *Object, VECTOR Vector, TRANSFORM *Trans);
157 static void Transform_Prism (OBJECT *Object, TRANSFORM *Trans);
158 static void Invert_Prism (OBJECT *Object);
159 static void Destroy_Prism (OBJECT *Object);
162 /*****************************************************************************
163 * Local variables
164 ******************************************************************************/
166 static METHODS Prism_Methods =
168 All_Prism_Intersections,
169 Inside_Prism, Prism_Normal,
170 (COPY_METHOD)Copy_Prism,
171 Translate_Prism, Rotate_Prism,
172 Scale_Prism, Transform_Prism, Invert_Prism, Destroy_Prism
177 /*****************************************************************************
179 * FUNCTION
181 * All_Prism_Intersections
183 * INPUT
185 * Object - Object
186 * Ray - Ray
187 * Depth_Stack - Intersection stack
189 * OUTPUT
191 * Depth_Stack
193 * RETURNS
195 * int - TRUE, if a intersection was found
197 * AUTHOR
199 * Dieter Bayer
201 * DESCRIPTION
203 * Determine ray/prism intersection and clip intersection found.
205 * CHANGES
207 * May 1994 : Creation.
209 ******************************************************************************/
211 static int All_Prism_Intersections(OBJECT *Object, RAY *Ray, ISTACK *Depth_Stack)
213 int i, max_i, Found;
214 PRISM_INT *Inter;
215 VECTOR IPoint;
217 Found = FALSE;
219 Inter = ((PRISM *)Object)->Intersections;
221 max_i = intersect_prism(Ray, (PRISM *)Object, Inter);
223 if (max_i)
225 for (i = 0; i < max_i; i++)
227 if ((Inter[i].d > DEPTH_TOLERANCE) && (Inter[i].d < Max_Distance))
229 VEvaluateRay(IPoint, Ray->Initial, Inter[i].d, Ray->Direction);
231 if (Point_In_Clip(IPoint, Object->Clip))
233 push_entry_i1_i2_d1(Inter[i].d,IPoint,Object,Inter[i].t,Inter[i].n,Inter[i].w,Depth_Stack);
235 Found = TRUE;
241 return(Found);
246 /*****************************************************************************
248 * FUNCTION
250 * intersect_prism
252 * INPUT
254 * Ray - Ray
255 * Prism - Prism
256 * Int - Prism intersection structure
258 * OUTPUT
260 * Int
262 * RETURNS
264 * int - Number of intersections found
266 * AUTHOR
268 * Dieter Bayer
270 * DESCRIPTION
272 * Determine ray/prism intersection.
274 * NOTE: Order reduction cannot be used.
276 * CHANGES
278 * May 1994 : Creation.
280 ******************************************************************************/
282 static int intersect_prism(RAY *Ray, PRISM *Prism, PRISM_INT *Intersection)
284 int i, j, n;
285 DBL k, u, v, w, h, len;
286 DBL x[4], y[3];
287 DBL k1, k2, k3;
288 VECTOR P, D;
289 PRISM_SPLINE_ENTRY Entry;
291 /* Don't test degenerate prisms. */
293 if (Test_Flag(Prism, DEGENERATE_FLAG))
295 return(FALSE);
298 Increase_Counter(stats[Ray_Prism_Tests]);
300 /* Init intersection structure. */
302 Intersection->d =
303 Intersection->w = 0.0;
304 Intersection->n =
305 Intersection->t = 0;
307 /* Transform the ray into the prism space */
309 MInvTransPoint(P, Ray->Initial, Prism->Trans);
311 MInvTransDirection(D, Ray->Direction, Prism->Trans);
313 VLength(len, D);
315 VInverseScaleEq(D, len);
317 /* Test overall bounding rectangle. */
319 #ifdef PRISM_EXTRA_STATS
320 Increase_Counter(stats[Prism_Bound_Tests]);
321 #endif
323 if (((D[X] >= 0.0) && (P[X] > Prism->x2)) ||
324 ((D[X] <= 0.0) && (P[X] < Prism->x1)) ||
325 ((D[Z] >= 0.0) && (P[Z] > Prism->y2)) ||
326 ((D[Z] <= 0.0) && (P[Z] < Prism->y1)))
328 return(FALSE);
331 #ifdef PRISM_EXTRA_STATS
332 Increase_Counter(stats[Prism_Bound_Tests_Succeeded]);
333 #endif
335 /* Number of intersections found. */
337 i = 0;
339 /* What kind of sweep is used? */
341 switch (Prism->Sweep_Type)
343 /*************************************************************************
344 * Linear sweep.
345 **************************************************************************/
347 case LINEAR_SWEEP :
349 if (fabs(D[Y]) < EPSILON)
351 if ((P[Y] < Prism->Height1) || (P[Y] > Prism->Height2))
353 return(FALSE);
356 else
358 if (Test_Flag(Prism, CLOSED_FLAG))
360 /* Intersect ray with the cap-plane. */
362 k = (Prism->Height2 - P[Y]) / D[Y];
364 if ((k > DEPTH_TOLERANCE) && (k < Max_Distance))
366 u = P[X] + k * D[X];
367 v = P[Z] + k * D[Z];
369 if (in_curve(Prism, u, v))
371 Intersection[i].t = CAP_HIT;
372 Intersection[i++].d = k / len;
376 /* Intersect ray with the base-plane. */
378 k = (Prism->Height1 - P[Y]) / D[Y];
380 if ((k > DEPTH_TOLERANCE) && (k < Max_Distance))
382 u = P[X] + k * D[X];
383 v = P[Z] + k * D[Z];
385 if (in_curve(Prism, u, v))
387 Intersection[i].t = BASE_HIT;
388 Intersection[i++].d = k / len;
394 /* Intersect ray with all spline segments. */
396 if ((fabs(D[X]) > EPSILON) || (fabs(D[Z]) > EPSILON))
398 for (j = 0; j < Prism->Number; j++)
400 Entry = Prism->Spline->Entry[j];
402 /* Test spline's bounding rectangle (modified Cohen-Sutherland). */
404 #ifdef PRISM_EXTRA_STATS
405 Increase_Counter(stats[Prism_Bound_Tests]);
406 #endif
408 if (((D[X] >= 0.0) && (P[X] > Entry.x2)) ||
409 ((D[X] <= 0.0) && (P[X] < Entry.x1)) ||
410 ((D[Z] >= 0.0) && (P[Z] > Entry.y2)) ||
411 ((D[Z] <= 0.0) && (P[Z] < Entry.y1)))
413 continue;
416 /* Number of roots found. */
418 n = 0;
420 switch (Prism->Spline_Type)
422 case LINEAR_SPLINE :
424 #ifdef PRISM_EXTRA_STATS
425 Increase_Counter(stats[Prism_Bound_Tests_Succeeded]);
426 #endif
428 /* Solve linear equation. */
430 x[0] = Entry.C[X] * D[Z] - Entry.C[Y] * D[X];
432 x[1] = D[Z] * (Entry.D[X] - P[X]) - D[X] * (Entry.D[Y] - P[Z]);
434 if (fabs(x[0]) > EPSILON)
436 y[n++] = -x[1] / x[0];
439 break;
441 case QUADRATIC_SPLINE :
443 #ifdef PRISM_EXTRA_STATS
444 Increase_Counter(stats[Prism_Bound_Tests_Succeeded]);
445 #endif
447 /* Solve quadratic equation. */
449 x[0] = Entry.B[X] * D[Z] - Entry.B[Y] * D[X];
451 x[1] = Entry.C[X] * D[Z] - Entry.C[Y] * D[X];
453 x[2] = D[Z] * (Entry.D[X] - P[X]) - D[X] * (Entry.D[Y] - P[Z]);
455 n = Solve_Polynomial(2, x, y, FALSE, 0.0);
457 break;
459 case CUBIC_SPLINE :
460 case BEZIER_SPLINE :
462 if (test_rectangle(P, D, Entry.x1, Entry.y1, Entry.x2, Entry.y2))
464 #ifdef PRISM_EXTRA_STATS
465 Increase_Counter(stats[Prism_Bound_Tests_Succeeded]);
466 #endif
468 /* Solve cubic equation. */
470 x[0] = Entry.A[X] * D[Z] - Entry.A[Y] * D[X];
472 x[1] = Entry.B[X] * D[Z] - Entry.B[Y] * D[X];
474 x[2] = Entry.C[X] * D[Z] - Entry.C[Y] * D[X];
476 x[3] = D[Z] * (Entry.D[X] - P[X]) - D[X] * (Entry.D[Y] - P[Z]);
478 n = Solve_Polynomial(3, x, y, Test_Flag(Prism, STURM_FLAG), 0.0);
481 break;
484 /* Test roots for valid intersections. */
486 while (n--)
488 w = y[n];
490 if ((w >= 0.0) && (w <= 1.0))
492 if (fabs(D[X]) > EPSILON)
494 k = (w * (w * (w * Entry.A[X] + Entry.B[X]) + Entry.C[X]) + Entry.D[X] - P[X]) / D[X];
496 else
498 k = (w * (w * (w * Entry.A[Y] + Entry.B[Y]) + Entry.C[Y]) + Entry.D[Y] - P[Z]) / D[Z];
501 /* Verify that intersection height is valid. */
503 h = P[Y] + k * D[Y];
505 if ((h >= Prism->Height1) && (h <= Prism->Height2))
507 Intersection[i].t = SPLINE_HIT;
508 Intersection[i].n = j;
509 Intersection[i].w = w;
510 Intersection[i++].d = k / len;
517 break;
519 /*************************************************************************
520 * Conic sweep.
521 **************************************************************************/
523 case CONIC_SWEEP :
525 if (fabs(D[Y]) < EPSILON)
527 if ((P[Y] < Prism->Height1) || (P[Y] > Prism->Height2))
529 return(FALSE);
532 else
534 if (Test_Flag(Prism, CLOSED_FLAG))
536 /* Intersect ray with the cap-plane. */
538 if (fabs(Prism->Height2) > EPSILON)
540 k = (Prism->Height2 - P[Y]) / D[Y];
542 if ((k > DEPTH_TOLERANCE) && (k < Max_Distance))
544 u = (P[X] + k * D[X]) / Prism->Height2;
545 v = (P[Z] + k * D[Z]) / Prism->Height2;
547 if (in_curve(Prism, u, v))
549 Intersection[i].t = CAP_HIT;
550 Intersection[i++].d = k / len;
555 /* Intersect ray with the base-plane. */
557 if (fabs(Prism->Height1) > EPSILON)
559 k = (Prism->Height1 - P[Y]) / D[Y];
561 if ((k > DEPTH_TOLERANCE) && (k < Max_Distance))
563 u = (P[X] + k * D[X]) / Prism->Height1;
564 v = (P[Z] + k * D[Z]) / Prism->Height1;
566 if (in_curve(Prism, u, v))
568 Intersection[i].t = BASE_HIT;
569 Intersection[i++].d = k / len;
576 /* Precompute ray-only dependant constants. */
578 k1 = P[Z] * D[Y] - P[Y] * D[Z];
580 k2 = P[Y] * D[X] - P[X] * D[Y];
582 k3 = P[X] * D[Z] - P[Z] * D[X];
584 /* Intersect ray with the spline segments. */
586 if ((fabs(D[X]) > EPSILON) || (fabs(D[Z]) > EPSILON))
588 for (j = 0; j < Prism->Number; j++)
590 Entry = Prism->Spline->Entry[j];
592 /* Test spline's bounding rectangle (modified Cohen-Sutherland). */
594 if (((D[X] >= 0.0) && (P[X] > Entry.x2)) ||
595 ((D[X] <= 0.0) && (P[X] < Entry.x1)) ||
596 ((D[Z] >= 0.0) && (P[Z] > Entry.y2)) ||
597 ((D[Z] <= 0.0) && (P[Z] < Entry.y1)))
599 continue;
602 /* Number of roots found. */
604 n = 0;
606 switch (Prism->Spline_Type)
608 case LINEAR_SPLINE :
610 /* Solve linear equation. */
612 x[0] = Entry.C[X] * k1 + Entry.C[Y] * k2;
614 x[1] = Entry.D[X] * k1 + Entry.D[Y] * k2 + k3;
616 if (fabs(x[0]) > EPSILON)
618 y[n++] = -x[1] / x[0];
621 break;
623 case QUADRATIC_SPLINE :
625 /* Solve quadratic equation. */
627 x[0] = Entry.B[X] * k1 + Entry.B[Y] * k2;
629 x[1] = Entry.C[X] * k1 + Entry.C[Y] * k2;
631 x[2] = Entry.D[X] * k1 + Entry.D[Y] * k2 + k3;
633 n = Solve_Polynomial(2, x, y, FALSE, 0.0);
635 break;
637 case CUBIC_SPLINE :
638 case BEZIER_SPLINE :
640 /* Solve cubic equation. */
642 x[0] = Entry.A[X] * k1 + Entry.A[Y] * k2;
644 x[1] = Entry.B[X] * k1 + Entry.B[Y] * k2;
646 x[2] = Entry.C[X] * k1 + Entry.C[Y] * k2;
648 x[3] = Entry.D[X] * k1 + Entry.D[Y] * k2 + k3;
650 n = Solve_Polynomial(3, x, y, Test_Flag(Prism, STURM_FLAG), 0.0);
652 break;
655 /* Test roots for valid intersections. */
657 while (n--)
659 w = y[n];
661 if ((w >= 0.0) && (w <= 1.0))
663 k = w * (w * (w * Entry.A[X] + Entry.B[X]) + Entry.C[X]) + Entry.D[X];
665 h = D[X] - k * D[Y];
667 if (fabs(h) > EPSILON)
669 k = (k * P[Y] - P[X]) / h;
671 else
673 k = w * (w * (w * Entry.A[Y] + Entry.B[Y]) + Entry.C[Y]) + Entry.D[Y];
675 h = D[Z] - k * D[Y];
677 if (fabs(h) > EPSILON)
679 k = (k * P[Y] - P[Z]) / h;
681 else
683 /* This should never happen! */
684 continue;
688 /* Verify that intersection height is valid. */
690 h = P[Y] + k * D[Y];
692 if ((h >= Prism->Height1) && (h <= Prism->Height2))
694 Intersection[i].t = SPLINE_HIT;
695 Intersection[i].n = j;
696 Intersection[i].w = w;
697 Intersection[i++].d = k / len;
704 break;
706 default:
708 Error("Unknown sweep type in intersect_prism().\n");
711 if (i)
713 Increase_Counter(stats[Ray_Prism_Tests_Succeeded]);
716 return(i);
721 /*****************************************************************************
723 * FUNCTION
725 * Inside_Prism
727 * INPUT
729 * IPoint - Intersection point
730 * Object - Object
732 * OUTPUT
734 * RETURNS
736 * int - TRUE if inside
738 * AUTHOR
740 * Dieter Bayer
742 * DESCRIPTION
744 * Test if point lies inside a prism.
746 * CHANGES
748 * May 1994 : Creation.
750 ******************************************************************************/
752 static int Inside_Prism(VECTOR IPoint, OBJECT *Object)
754 VECTOR P;
755 PRISM *Prism = (PRISM *)Object;
757 /* Transform the point into the prism space. */
759 MInvTransPoint(P, IPoint, Prism->Trans);
761 if ((P[Y] >= Prism->Height1) && (P[Y] < Prism->Height2))
763 if (Prism->Sweep_Type == CONIC_SWEEP)
765 /* Scale x and z coordinate. */
767 if (fabs(P[Y]) > EPSILON)
769 P[X] /= P[Y];
770 P[Z] /= P[Y];
772 else
774 P[X] = P[Z] = HUGE_VAL;
778 if (in_curve(Prism, P[X], P[Z]))
780 return(!Test_Flag(Prism, INVERTED_FLAG));
784 return(Test_Flag(Prism, INVERTED_FLAG));
789 /*****************************************************************************
791 * FUNCTION
793 * Prism_Normal
795 * INPUT
797 * Result - Normal vector
798 * Object - Object
799 * Inter - Intersection found
801 * OUTPUT
803 * Result
805 * RETURNS
807 * AUTHOR
809 * Dieter Bayer
811 * DESCRIPTION
813 * Calculate the normal of the prism in a given point.
815 * CHANGES
817 * May 1994 : Creation.
819 * Jul 1997 : Fixed bug as reported by Darko Rozic. [DB]
821 ******************************************************************************/
823 static void Prism_Normal(VECTOR Result, OBJECT *Object, INTERSECTION *Inter)
825 VECTOR P;
826 PRISM_SPLINE_ENTRY Entry;
827 PRISM *Prism = (PRISM *)Object;
828 VECTOR N;
830 Make_Vector(N, 0.0, 1.0, 0.0);
832 if (Inter->i1 == SPLINE_HIT)
834 Entry = Prism->Spline->Entry[Inter->i2];
836 switch (Prism->Sweep_Type)
838 case LINEAR_SWEEP:
840 N[X] = Inter->d1 * (3.0 * Entry.A[Y] * Inter->d1 + 2.0 * Entry.B[Y]) + Entry.C[Y];
841 N[Y] = 0.0;
842 N[Z] = -(Inter->d1 * (3.0 * Entry.A[X] * Inter->d1 + 2.0 * Entry.B[X]) + Entry.C[X]);
844 break;
846 case CONIC_SWEEP:
848 /* Transform the point into the prism space. */
850 MInvTransPoint(P, Inter->IPoint, Prism->Trans);
852 if (fabs(P[Y]) > EPSILON)
854 N[X] = Inter->d1 * (3.0 * Entry.A[Y] * Inter->d1 + 2.0 * Entry.B[Y]) + Entry.C[Y];
855 N[Z] = -(Inter->d1 * (3.0 * Entry.A[X] * Inter->d1 + 2.0 * Entry.B[X]) + Entry.C[X]);
856 N[Y] = -(P[X] * N[X] + P[Z] * N[Z]) / P[Y];
859 break;
861 default:
863 Error("Unknown sweep type in Prism_Normal().\n");
867 /* Transform the normalt out of the prism space. */
869 MTransNormal(Result, N, Prism->Trans);
871 VNormalize(Result, Result);
876 /*****************************************************************************
878 * FUNCTION
880 * Translate_Prism
882 * INPUT
884 * Object - Object
885 * Vector - Translation vector
887 * OUTPUT
889 * Object
891 * RETURNS
893 * AUTHOR
895 * Dieter Bayer
897 * DESCRIPTION
899 * Translate a prism.
901 * CHANGES
903 * May 1994 : Creation.
905 ******************************************************************************/
907 static void Translate_Prism(OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)
909 Transform_Prism(Object, Trans);
914 /*****************************************************************************
916 * FUNCTION
918 * Rotate_Prism
920 * INPUT
922 * Object - Object
923 * Vector - Rotation vector
925 * OUTPUT
927 * Object
929 * RETURNS
931 * AUTHOR
933 * Dieter Bayer
935 * DESCRIPTION
937 * Rotate a prism.
939 * CHANGES
941 * May 1994 : Creation.
943 ******************************************************************************/
945 static void Rotate_Prism(OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)
947 Transform_Prism(Object, Trans);
952 /*****************************************************************************
954 * FUNCTION
956 * Scale_Prism
958 * INPUT
960 * Object - Object
961 * Vector - Scaling vector
963 * OUTPUT
965 * Object
967 * RETURNS
969 * AUTHOR
971 * Dieter Bayer
973 * DESCRIPTION
975 * Scale a prism.
977 * CHANGES
979 * May 1994 : Creation.
981 ******************************************************************************/
983 static void Scale_Prism(OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)
985 Transform_Prism(Object, Trans);
990 /*****************************************************************************
992 * FUNCTION
994 * Transform_Prism
996 * INPUT
998 * Object - Object
999 * Trans - Transformation to apply
1001 * OUTPUT
1003 * Object
1005 * RETURNS
1007 * AUTHOR
1009 * Dieter Bayer
1011 * DESCRIPTION
1013 * Transform a prism and recalculate its bounding box.
1015 * CHANGES
1017 * May 1994 : Creation.
1019 ******************************************************************************/
1021 static void Transform_Prism(OBJECT *Object, TRANSFORM *Trans)
1023 Compose_Transforms(((PRISM *)Object)->Trans, Trans);
1025 Compute_Prism_BBox((PRISM *)Object);
1030 /*****************************************************************************
1032 * FUNCTION
1034 * Invert_Prism
1036 * INPUT
1038 * Object - Object
1040 * OUTPUT
1042 * Object
1044 * RETURNS
1046 * AUTHOR
1048 * Dieter Bayer
1050 * DESCRIPTION
1052 * Invert a prism.
1054 * CHANGES
1056 * May 1994 : Creation.
1058 ******************************************************************************/
1060 static void Invert_Prism(OBJECT *Object)
1062 Invert_Flag(Object, INVERTED_FLAG);
1067 /*****************************************************************************
1069 * FUNCTION
1071 * Create_Prism
1073 * INPUT
1075 * OUTPUT
1077 * RETURNS
1079 * PRISM * - new prism
1081 * AUTHOR
1083 * Dieter Bayer
1085 * DESCRIPTION
1087 * Create a new prism.
1089 * CHANGES
1091 * May 1994 : Creation.
1093 ******************************************************************************/
1095 PRISM *Create_Prism()
1097 PRISM *New;
1099 New = (PRISM *)POV_MALLOC(sizeof(PRISM), "prism");
1101 INIT_OBJECT_FIELDS(New,PRISM_OBJECT,&Prism_Methods)
1103 New->Trans = Create_Transform();
1105 New->x1 =
1106 New->x2 =
1107 New->y1 =
1108 New->y2 =
1109 New->u1 =
1110 New->u2 =
1111 New->v1 =
1112 New->v2 =
1113 New->Height1 =
1114 New->Height2 = 0.0;
1116 New->Number = 0;
1118 New->Spline_Type = LINEAR_SPLINE;
1119 New->Sweep_Type = LINEAR_SWEEP;
1121 New->Spline = NULL;
1123 New->Intersections = NULL;
1125 Set_Flag(New, CLOSED_FLAG);
1127 return(New);
1132 /*****************************************************************************
1134 * FUNCTION
1136 * Copy_Prism
1138 * INPUT
1140 * Object - Object
1142 * OUTPUT
1144 * RETURNS
1146 * void * - New prism
1148 * AUTHOR
1150 * Dieter Bayer
1152 * DESCRIPTION
1154 * Copy a prism structure.
1156 * NOTE: The splines are not copied, only the number of references is
1157 * counted, so that Destray_Prism() knows if they can be destroyed.
1159 * CHANGES
1161 * May 1994 : Creation.
1163 * Sep 1994 : fixed memory leakage [DB]
1165 ******************************************************************************/
1167 static PRISM *Copy_Prism(OBJECT *Object)
1169 PRISM *New, *Prism = (PRISM *)Object;
1171 New = Create_Prism();
1173 /* Get rid of the transformation created in Create_Prism(). */
1175 Destroy_Transform(New->Trans);
1177 /* Copy prism. */
1179 *New = *Prism;
1181 New->Trans = Copy_Transform(((PRISM *)Object)->Trans);
1183 New->Spline->References++;
1185 Prism->Intersections = (PRISM_INT *)POV_MALLOC((Prism->Number+2)*sizeof(PRISM_INT), "prism intersection list");
1187 return(New);
1192 /*****************************************************************************
1194 * FUNCTION
1196 * Destroy_Prism
1198 * INPUT
1200 * Object - Object
1202 * OUTPUT
1204 * Object
1206 * RETURNS
1208 * AUTHOR
1210 * Dieter Bayer
1212 * DESCRIPTION
1214 * Destroy a prism.
1216 * NOTE: The splines are destroyed if they are no longer used by any copy.
1218 * CHANGES
1220 * May 1994 : Creation.
1222 ******************************************************************************/
1224 static void Destroy_Prism (OBJECT *Object)
1226 PRISM *Prism = (PRISM *)Object;
1228 Destroy_Transform(Prism->Trans);
1230 POV_FREE(Prism->Intersections);
1232 if (--(Prism->Spline->References) == 0)
1234 POV_FREE(Prism->Spline->Entry);
1236 POV_FREE(Prism->Spline);
1239 POV_FREE(Object);
1244 /*****************************************************************************
1246 * FUNCTION
1248 * Compute_Prism_BBox
1250 * INPUT
1252 * Prism - Prism
1254 * OUTPUT
1256 * Prism
1258 * RETURNS
1260 * AUTHOR
1262 * Dieter Bayer
1264 * DESCRIPTION
1266 * Calculate the bounding box of a prism.
1268 * CHANGES
1270 * May 1994 : Creation.
1272 ******************************************************************************/
1274 void Compute_Prism_BBox(PRISM *Prism)
1276 Make_BBox(Prism->BBox, Prism->x1, Prism->Height1, Prism->y1,
1277 Prism->x2 - Prism->x1, Prism->Height2 - Prism->Height1, Prism->y2 - Prism->y1);
1279 Recompute_BBox(&Prism->BBox, Prism->Trans);
1284 /*****************************************************************************
1286 * FUNCTION
1288 * in_curve
1290 * INPUT
1292 * Prism - Prism to test
1293 * u, v - Coordinates
1295 * OUTPUT
1297 * RETURNS
1299 * int - TRUE if inside
1301 * AUTHOR
1303 * Dieter Bayer, June 1994
1305 * DESCRIPTION
1307 * Test if a 2d point lies inside a prism's spline curve.
1309 * We travel from the current point in positive u direction
1310 * and count the number of crossings with the curve.
1312 * CHANGES
1314 * May 1994 : Creation.
1316 ******************************************************************************/
1318 static int in_curve(PRISM *Prism, DBL u, DBL v)
1320 int i, n, NC;
1321 DBL k, w;
1322 DBL x[4], y[3];
1323 PRISM_SPLINE_ENTRY Entry;
1325 NC = 0;
1327 /* First test overall bounding rectangle. */
1329 if ((u >= Prism->u1) && (u <= Prism->u2) &&
1330 (v >= Prism->v1) && (v <= Prism->v2))
1332 for (i = 0; i < Prism->Number; i++)
1334 Entry = Prism->Spline->Entry[i];
1336 /* Test if current segment can be hit. */
1338 if ((v >= Entry.v1) && (v <= Entry.v2) && (u <= Entry.u2))
1340 x[0] = Entry.A[Y];
1341 x[1] = Entry.B[Y];
1342 x[2] = Entry.C[Y];
1343 x[3] = Entry.D[Y] - v;
1345 n = Solve_Polynomial(3, x, y, Test_Flag(Prism, STURM_FLAG), 0.0);
1347 while (n--)
1349 w = y[n];
1351 if ((w >= 0.0) && (w <= 1.0))
1353 k = w * (w * (w * Entry.A[X] + Entry.B[X]) + Entry.C[X]) + Entry.D[X] - u;
1355 if (k >= 0.0)
1357 NC++;
1365 return(NC & 1);
1370 /*****************************************************************************
1372 * FUNCTION
1374 * test_rectangle
1376 * INPUT
1378 * OUTPUT
1380 * RETURNS
1382 * AUTHOR
1384 * Dieter Bayer, July 1994
1386 * DESCRIPTION
1388 * Test if the 2d ray (= P + t * D) intersects a rectangle.
1390 * CHANGES
1392 * May 1994 : Creation.
1394 ******************************************************************************/
1396 static int test_rectangle(VECTOR P, VECTOR D, DBL x1, DBL z1, DBL x2, DBL z2)
1398 DBL dmin, dmax, tmin, tmax;
1400 if (fabs(D[X]) > EPSILON)
1402 if (D[X] > 0.0)
1404 dmin = (x1 - P[X]) / D[X];
1405 dmax = (x2 - P[X]) / D[X];
1407 if (dmax < EPSILON)
1409 return(FALSE);
1412 else
1414 dmax = (x1 - P[X]) / D[X];
1416 if (dmax < EPSILON)
1418 return(FALSE);
1421 dmin = (x2 - P[X]) / D[X];
1424 if (dmin > dmax)
1426 return(FALSE);
1429 else
1431 if ((P[X] < x1) || (P[X] > x2))
1433 return(FALSE);
1435 else
1437 dmin = -BOUND_HUGE;
1438 dmax = BOUND_HUGE;
1442 if (fabs(D[Z]) > EPSILON)
1444 if (D[Z] > 0.0)
1446 tmin = (z1 - P[Z]) / D[Z];
1447 tmax = (z2 - P[Z]) / D[Z];
1449 else
1451 tmax = (z1 - P[Z]) / D[Z];
1452 tmin = (z2 - P[Z]) / D[Z];
1455 if (tmax < dmax)
1457 if (tmax < EPSILON)
1459 return(FALSE);
1462 if (tmin > dmin)
1464 if (tmin > tmax)
1466 return(FALSE);
1469 dmin = tmin;
1471 else
1473 if (dmin > tmax)
1475 return(FALSE);
1479 /*dmax = tmax; */ /*not needed CEY[1/95]*/
1481 else
1483 if (tmin > dmin)
1485 if (tmin > dmax)
1487 return(FALSE);
1490 /* dmin = tmin; */ /*not needed CEY[1/95]*/
1494 else
1496 if ((P[Z] < z1) || (P[Z] > z2))
1498 return(FALSE);
1502 return(TRUE);
1507 /*****************************************************************************
1509 * FUNCTION
1511 * Compute_Prism
1513 * INPUT
1515 * Prism - Prism
1516 * P - Points defining prism
1518 * OUTPUT
1520 * Prism
1522 * RETURNS
1524 * AUTHOR
1526 * Dieter Bayer, June 1994
1528 * DESCRIPTION
1530 * Calculate the spline segments of a prism from a set of points.
1532 * CHANGES
1534 * May 1994 : Creation.
1536 ******************************************************************************/
1538 void Compute_Prism(PRISM *Prism, UV_VECT *P)
1540 int i, n, number_of_splines;
1541 int i1, i2, i3;
1543 DBL x[4], xmin, xmax;
1544 DBL y[4], ymin, ymax;
1545 DBL c[3], r[2];
1547 UV_VECT A, B, C, D, First;
1549 /* Allocate Object->Number segments. */
1551 if (Prism->Spline == NULL)
1553 Prism->Spline = (PRISM_SPLINE *)POV_MALLOC(sizeof(PRISM_SPLINE), "spline segments of prism");
1555 Prism->Spline->References = 1;
1557 Prism->Spline->Entry = (PRISM_SPLINE_ENTRY *)POV_MALLOC(Prism->Number*sizeof(PRISM_SPLINE_ENTRY), "spline segments of prism");
1559 else
1561 /* This should never happen! */
1563 Error("Prism segments are already defined.\n");
1566 /* Allocate prism intersections list. */
1568 Prism->Intersections = (PRISM_INT *)POV_MALLOC((Prism->Number+2)*sizeof(PRISM_INT), "prism intersection list");
1570 /***************************************************************************
1571 * Calculate segments.
1572 ****************************************************************************/
1574 /* We want to know the size of the overall bounding rectangle. */
1576 xmax = ymax = -BOUND_HUGE;
1577 xmin = ymin = BOUND_HUGE;
1579 /* Get first segment point. */
1581 switch (Prism->Spline_Type)
1583 case LINEAR_SPLINE:
1585 Assign_UV_Vect(First, P[0]);
1587 break;
1589 case QUADRATIC_SPLINE:
1590 case CUBIC_SPLINE:
1592 Assign_UV_Vect(First, P[1]);
1594 break;
1597 for (i = number_of_splines = 0; i < Prism->Number-1; i++)
1599 /* Get indices of previous and next two points. */
1601 i1 = i + 1;
1602 i2 = i + 2;
1603 i3 = i + 3;
1605 switch (Prism->Spline_Type)
1607 /*************************************************************************
1608 * Linear spline (nothing more than a simple polygon).
1609 **************************************************************************/
1611 case LINEAR_SPLINE :
1613 if (i1 >= Prism->Number)
1615 Error("Too few points in prism. Prism not closed? Control points missing?\n");
1618 /* Use linear interpolation. */
1620 A[X] = 0.0;
1621 B[X] = 0.0;
1622 C[X] = -1.0 * P[i][X] + 1.0 * P[i1][X];
1623 D[X] = 1.0 * P[i][X];
1625 A[Y] = 0.0;
1626 B[Y] = 0.0;
1627 C[Y] = -1.0 * P[i][Y] + 1.0 * P[i1][Y];
1628 D[Y] = 1.0 * P[i][Y];
1630 x[0] = x[2] = P[i][X];
1631 x[1] = x[3] = P[i1][X];
1633 y[0] = y[2] = P[i][Y];
1634 y[1] = y[3] = P[i1][Y];
1636 break;
1638 /*************************************************************************
1639 * Quadratic spline.
1640 **************************************************************************/
1642 case QUADRATIC_SPLINE :
1644 if (i2 >= Prism->Number)
1646 Error("Too few points in prism.\n");
1649 /* Use quadratic interpolation. */
1651 A[X] = 0.0;
1652 B[X] = 0.5 * P[i][X] - 1.0 * P[i1][X] + 0.5 * P[i2][X];
1653 C[X] = -0.5 * P[i][X] + 0.5 * P[i2][X];
1654 D[X] = 1.0 * P[i1][X];
1656 A[Y] = 0.0;
1657 B[Y] = 0.5 * P[i][Y] - 1.0 * P[i1][Y] + 0.5 * P[i2][Y];
1658 C[Y] = -0.5 * P[i][Y] + 0.5 * P[i2][Y];
1659 D[Y] = 1.0 * P[i1][Y];
1661 x[0] = x[2] = P[i1][X];
1662 x[1] = x[3] = P[i2][X];
1664 y[0] = y[2] = P[i1][Y];
1665 y[1] = y[3] = P[i2][Y];
1667 break;
1669 /*************************************************************************
1670 * Cubic spline.
1671 **************************************************************************/
1673 case CUBIC_SPLINE :
1675 if (i3 >= Prism->Number)
1677 Error("Too few points in prism.\n");
1680 /* Use cubic interpolation. */
1682 A[X] = -0.5 * P[i][X] + 1.5 * P[i1][X] - 1.5 * P[i2][X] + 0.5 * P[i3][X];
1683 B[X] = P[i][X] - 2.5 * P[i1][X] + 2.0 * P[i2][X] - 0.5 * P[i3][X];
1684 C[X] = -0.5 * P[i][X] + 0.5 * P[i2][X];
1685 D[X] = P[i1][X];
1687 A[Y] = -0.5 * P[i][Y] + 1.5 * P[i1][Y] - 1.5 * P[i2][Y] + 0.5 * P[i3][Y];
1688 B[Y] = P[i][Y] - 2.5 * P[i1][Y] + 2.0 * P[i2][Y] - 0.5 * P[i3][Y];
1689 C[Y] = -0.5 * P[i][Y] + 0.5 * P[i2][Y];
1690 D[Y] = P[i1][Y];
1692 x[0] = x[2] = P[i1][X];
1693 x[1] = x[3] = P[i2][X];
1695 y[0] = y[2] = P[i1][Y];
1696 y[1] = y[3] = P[i2][Y];
1698 break;
1700 /*************************************************************************
1701 * Bezier spline.
1702 **************************************************************************/
1704 case BEZIER_SPLINE :
1706 if (i3 >= Prism->Number)
1708 Error("Too few points in prism. Prism not closed? Control points missing?\n");
1711 /* Use Bernstein blending function interpolation. */
1713 A[X] = P[i][X] - 3.0 * P[i1][X] + 3.0 * P[i2][X] - P[i3][X];
1714 B[X] = 3.0 * P[i1][X] - 6.0 * P[i2][X] + 3.0 * P[i3][X];
1715 C[X] = 3.0 * P[i2][X] - 3.0 * P[i3][X];
1716 D[X] = P[i3][X];
1718 A[Y] = P[i][Y] - 3.0 * P[i1][Y] + 3.0 * P[i2][Y] - P[i3][Y];
1719 B[Y] = 3.0 * P[i1][Y] - 6.0 * P[i2][Y] + 3.0 * P[i3][Y];
1720 C[Y] = 3.0 * P[i2][Y] - 3.0 * P[i3][Y];
1721 D[Y] = P[i3][Y];
1723 x[0] = P[i][X];
1724 x[1] = P[i1][X];
1725 x[2] = P[i2][X];
1726 x[3] = P[i3][X];
1728 y[0] = P[i][Y];
1729 y[1] = P[i1][Y];
1730 y[2] = P[i2][Y];
1731 y[3] = P[i3][Y];
1733 break;
1735 default:
1737 Error("Unknown spline type in Compute_Prism().\n");
1740 Assign_UV_Vect(Prism->Spline->Entry[number_of_splines].A, A);
1741 Assign_UV_Vect(Prism->Spline->Entry[number_of_splines].B, B);
1742 Assign_UV_Vect(Prism->Spline->Entry[number_of_splines].C, C);
1743 Assign_UV_Vect(Prism->Spline->Entry[number_of_splines].D, D);
1745 if ((Prism->Spline_Type == QUADRATIC_SPLINE) ||
1746 (Prism->Spline_Type == CUBIC_SPLINE))
1748 /* Get maximum coordinates in current segment. */
1750 c[0] = 3.0 * A[X];
1751 c[1] = 2.0 * B[X];
1752 c[2] = C[X];
1754 n = Solve_Polynomial(2, c, r, FALSE, 0.0);
1756 while (n--)
1758 if ((r[n] >= 0.0) && (r[n] <= 1.0))
1760 x[n] = r[n] * (r[n] * (r[n] * A[X] + B[X]) + C[X]) + D[X];
1764 c[0] = 3.0 * A[Y];
1765 c[1] = 2.0 * B[Y];
1766 c[2] = C[Y];
1768 n = Solve_Polynomial(2, c, r, FALSE, 0.0);
1770 while (n--)
1772 if ((r[n] >= 0.0) && (r[n] <= 1.0))
1774 y[n] = r[n] * (r[n] * (r[n] * A[Y] + B[Y]) + C[Y]) + D[Y];
1779 /* Set current segment's bounding rectangle. */
1781 Prism->Spline->Entry[number_of_splines].x1 = min(min(x[0], x[1]), min(x[2], x[3]));
1783 Prism->Spline->Entry[number_of_splines].x2 =
1784 Prism->Spline->Entry[number_of_splines].u2 = max(max(x[0], x[1]), max(x[2], x[3]));
1786 Prism->Spline->Entry[number_of_splines].y1 =
1787 Prism->Spline->Entry[number_of_splines].v1 = min(min(y[0], y[1]), min(y[2], y[3]));
1789 Prism->Spline->Entry[number_of_splines].y2 =
1790 Prism->Spline->Entry[number_of_splines].v2 = max(max(y[0], y[1]), max(y[2], y[3]));
1792 /* Keep track of overall bounding rectangle. */
1794 xmin = min(xmin, Prism->Spline->Entry[number_of_splines].x1);
1795 xmax = max(xmax, Prism->Spline->Entry[number_of_splines].x2);
1797 ymin = min(ymin, Prism->Spline->Entry[number_of_splines].y1);
1798 ymax = max(ymax, Prism->Spline->Entry[number_of_splines].y2);
1800 number_of_splines++;
1802 /* Advance to next segment. */
1804 switch (Prism->Spline_Type)
1806 case LINEAR_SPLINE:
1808 if ((fabs(P[i1][X] - First[X]) < EPSILON) &&
1809 (fabs(P[i1][Y] - First[Y]) < EPSILON))
1811 i++;
1813 if (i+1 < Prism->Number)
1815 Assign_UV_Vect(First, P[i+1]);
1819 break;
1821 case QUADRATIC_SPLINE:
1823 if ((fabs(P[i2][X] - First[X]) < EPSILON) &&
1824 (fabs(P[i2][Y] - First[Y]) < EPSILON))
1826 i += 2;
1828 if (i+2 < Prism->Number)
1830 Assign_UV_Vect(First, P[i+2]);
1834 break;
1836 case CUBIC_SPLINE:
1838 if ((fabs(P[i2][X] - First[X]) < EPSILON) &&
1839 (fabs(P[i2][Y] - First[Y]) < EPSILON))
1841 i += 3;
1843 if (i+2 < Prism->Number)
1845 Assign_UV_Vect(First, P[i+2]);
1849 break;
1851 case BEZIER_SPLINE:
1853 i += 3;
1855 break;
1859 Prism->Number = number_of_splines;
1861 /* Set overall bounding rectangle. */
1863 Prism->x1 =
1864 Prism->u1 = xmin;
1865 Prism->x2 =
1866 Prism->u2 = xmax;
1868 Prism->y1 =
1869 Prism->v1 = ymin;
1870 Prism->y2 =
1871 Prism->v2 = ymax;
1873 if (Prism->Sweep_Type == CONIC_SWEEP)
1875 /* Recalculate bounding rectangles. */
1877 for (i = 0; i < Prism->Number; i++)
1879 x[0] = Prism->Spline->Entry[i].x1 * Prism->Height1;
1880 x[1] = Prism->Spline->Entry[i].x1 * Prism->Height2;
1881 x[2] = Prism->Spline->Entry[i].x2 * Prism->Height1;
1882 x[3] = Prism->Spline->Entry[i].x2 * Prism->Height2;
1884 xmin = min(min(x[0], x[1]), min(x[2], x[3]));
1885 xmax = max(max(x[0], x[1]), max(x[2], x[3]));
1887 Prism->Spline->Entry[i].x1 = xmin;
1888 Prism->Spline->Entry[i].x2 = xmax;
1890 y[0] = Prism->Spline->Entry[i].y1 * Prism->Height1;
1891 y[1] = Prism->Spline->Entry[i].y1 * Prism->Height2;
1892 y[2] = Prism->Spline->Entry[i].y2 * Prism->Height1;
1893 y[3] = Prism->Spline->Entry[i].y2 * Prism->Height2;
1895 ymin = min(min(y[0], y[1]), min(y[2], y[3]));
1896 ymax = max(max(y[0], y[1]), max(y[2], y[3]));
1898 Prism->Spline->Entry[i].y1 = ymin;
1899 Prism->Spline->Entry[i].y2 = ymax;
1902 /* Recalculate overall bounding rectangle. */
1904 x[0] = Prism->x1 * Prism->Height1;
1905 x[1] = Prism->x1 * Prism->Height2;
1906 x[2] = Prism->x2 * Prism->Height1;
1907 x[3] = Prism->x2 * Prism->Height2;
1909 xmin = min(min(x[0], x[1]), min(x[2], x[3]));
1910 xmax = max(max(x[0], x[1]), max(x[2], x[3]));
1912 Prism->x1 = xmin;
1913 Prism->x2 = xmax;
1915 y[0] = Prism->y1 * Prism->Height1;
1916 y[1] = Prism->y1 * Prism->Height2;
1917 y[2] = Prism->y2 * Prism->Height1;
1918 y[3] = Prism->y2 * Prism->Height2;
1920 ymin = min(min(y[0], y[1]), min(y[2], y[3]));
1921 ymax = max(max(y[0], y[1]), max(y[2], y[3]));
1923 Prism->y1 = ymin;
1924 Prism->y2 = ymax;