1 /****************************************************************************
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 /****************************************************************************
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.
74 * [ linear_sweep | cubic_sweep ]
75 * [ linear_spline | quadratic_spline | cubic_spline ]
80 * <P(0)>, <P(1)>, ..., <P(n-1)>
86 * Note that the P(i) are 2d vectors.
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
99 * May 1994 : Creation. [DB]
101 *****************************************************************************/
106 #include "povproto.h"
108 #include "matrices.h"
110 #include "polysolv.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. */
137 /*****************************************************************************
139 ******************************************************************************/
143 /*****************************************************************************
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 /*****************************************************************************
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 /*****************************************************************************
181 * All_Prism_Intersections
187 * Depth_Stack - Intersection stack
195 * int - TRUE, if a intersection was found
203 * Determine ray/prism intersection and clip intersection found.
207 * May 1994 : Creation.
209 ******************************************************************************/
211 static int All_Prism_Intersections(OBJECT
*Object
, RAY
*Ray
, ISTACK
*Depth_Stack
)
219 Inter
= ((PRISM
*)Object
)->Intersections
;
221 max_i
= intersect_prism(Ray
, (PRISM
*)Object
, Inter
);
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
);
246 /*****************************************************************************
256 * Int - Prism intersection structure
264 * int - Number of intersections found
272 * Determine ray/prism intersection.
274 * NOTE: Order reduction cannot be used.
278 * May 1994 : Creation.
280 ******************************************************************************/
282 static int intersect_prism(RAY
*Ray
, PRISM
*Prism
, PRISM_INT
*Intersection
)
285 DBL k
, u
, v
, w
, h
, len
;
289 PRISM_SPLINE_ENTRY Entry
;
291 /* Don't test degenerate prisms. */
293 if (Test_Flag(Prism
, DEGENERATE_FLAG
))
298 Increase_Counter(stats
[Ray_Prism_Tests
]);
300 /* Init intersection structure. */
303 Intersection
->w
= 0.0;
307 /* Transform the ray into the prism space */
309 MInvTransPoint(P
, Ray
->Initial
, Prism
->Trans
);
311 MInvTransDirection(D
, Ray
->Direction
, Prism
->Trans
);
315 VInverseScaleEq(D
, len
);
317 /* Test overall bounding rectangle. */
319 #ifdef PRISM_EXTRA_STATS
320 Increase_Counter(stats
[Prism_Bound_Tests
]);
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
)))
331 #ifdef PRISM_EXTRA_STATS
332 Increase_Counter(stats
[Prism_Bound_Tests_Succeeded
]);
335 /* Number of intersections found. */
339 /* What kind of sweep is used? */
341 switch (Prism
->Sweep_Type
)
343 /*************************************************************************
345 **************************************************************************/
349 if (fabs(D
[Y
]) < EPSILON
)
351 if ((P
[Y
] < Prism
->Height1
) || (P
[Y
] > Prism
->Height2
))
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
))
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
))
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
]);
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
)))
416 /* Number of roots found. */
420 switch (Prism
->Spline_Type
)
424 #ifdef PRISM_EXTRA_STATS
425 Increase_Counter(stats
[Prism_Bound_Tests_Succeeded
]);
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];
441 case QUADRATIC_SPLINE
:
443 #ifdef PRISM_EXTRA_STATS
444 Increase_Counter(stats
[Prism_Bound_Tests_Succeeded
]);
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);
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
]);
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);
484 /* Test roots for valid intersections. */
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
];
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. */
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
;
519 /*************************************************************************
521 **************************************************************************/
525 if (fabs(D
[Y
]) < EPSILON
)
527 if ((P
[Y
] < Prism
->Height1
) || (P
[Y
] > Prism
->Height2
))
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
)))
602 /* Number of roots found. */
606 switch (Prism
->Spline_Type
)
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];
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);
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);
655 /* Test roots for valid intersections. */
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
];
667 if (fabs(h
) > EPSILON
)
669 k
= (k
* P
[Y
] - P
[X
]) / h
;
673 k
= w
* (w
* (w
* Entry
.A
[Y
] + Entry
.B
[Y
]) + Entry
.C
[Y
]) + Entry
.D
[Y
];
677 if (fabs(h
) > EPSILON
)
679 k
= (k
* P
[Y
] - P
[Z
]) / h
;
683 /* This should never happen! */
688 /* Verify that intersection height is valid. */
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
;
708 Error("Unknown sweep type in intersect_prism().\n");
713 Increase_Counter(stats
[Ray_Prism_Tests_Succeeded
]);
721 /*****************************************************************************
729 * IPoint - Intersection point
736 * int - TRUE if inside
744 * Test if point lies inside a prism.
748 * May 1994 : Creation.
750 ******************************************************************************/
752 static int Inside_Prism(VECTOR IPoint
, OBJECT
*Object
)
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
)
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 /*****************************************************************************
797 * Result - Normal vector
799 * Inter - Intersection found
813 * Calculate the normal of the prism in a given point.
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
)
826 PRISM_SPLINE_ENTRY Entry
;
827 PRISM
*Prism
= (PRISM
*)Object
;
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
)
840 N
[X
] = Inter
->d1
* (3.0 * Entry
.A
[Y
] * Inter
->d1
+ 2.0 * Entry
.B
[Y
]) + Entry
.C
[Y
];
842 N
[Z
] = -(Inter
->d1
* (3.0 * Entry
.A
[X
] * Inter
->d1
+ 2.0 * Entry
.B
[X
]) + Entry
.C
[X
]);
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
];
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 /*****************************************************************************
885 * Vector - Translation vector
903 * May 1994 : Creation.
905 ******************************************************************************/
907 static void Translate_Prism(OBJECT
*Object
, VECTOR Vector
, TRANSFORM
*Trans
)
909 Transform_Prism(Object
, Trans
);
914 /*****************************************************************************
923 * Vector - Rotation vector
941 * May 1994 : Creation.
943 ******************************************************************************/
945 static void Rotate_Prism(OBJECT
*Object
, VECTOR Vector
, TRANSFORM
*Trans
)
947 Transform_Prism(Object
, Trans
);
952 /*****************************************************************************
961 * Vector - Scaling vector
979 * May 1994 : Creation.
981 ******************************************************************************/
983 static void Scale_Prism(OBJECT
*Object
, VECTOR Vector
, TRANSFORM
*Trans
)
985 Transform_Prism(Object
, Trans
);
990 /*****************************************************************************
999 * Trans - Transformation to apply
1013 * Transform a prism and recalculate its bounding box.
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 /*****************************************************************************
1056 * May 1994 : Creation.
1058 ******************************************************************************/
1060 static void Invert_Prism(OBJECT
*Object
)
1062 Invert_Flag(Object
, INVERTED_FLAG
);
1067 /*****************************************************************************
1079 * PRISM * - new prism
1087 * Create a new prism.
1091 * May 1994 : Creation.
1093 ******************************************************************************/
1095 PRISM
*Create_Prism()
1099 New
= (PRISM
*)POV_MALLOC(sizeof(PRISM
), "prism");
1101 INIT_OBJECT_FIELDS(New
,PRISM_OBJECT
,&Prism_Methods
)
1103 New
->Trans
= Create_Transform();
1118 New
->Spline_Type
= LINEAR_SPLINE
;
1119 New
->Sweep_Type
= LINEAR_SWEEP
;
1123 New
->Intersections
= NULL
;
1125 Set_Flag(New
, CLOSED_FLAG
);
1132 /*****************************************************************************
1146 * void * - New prism
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.
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
);
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");
1192 /*****************************************************************************
1216 * NOTE: The splines are destroyed if they are no longer used by any copy.
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
);
1244 /*****************************************************************************
1248 * Compute_Prism_BBox
1266 * Calculate the bounding box of a prism.
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 /*****************************************************************************
1292 * Prism - Prism to test
1293 * u, v - Coordinates
1299 * int - TRUE if inside
1303 * Dieter Bayer, June 1994
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.
1314 * May 1994 : Creation.
1316 ******************************************************************************/
1318 static int in_curve(PRISM
*Prism
, DBL u
, DBL v
)
1323 PRISM_SPLINE_ENTRY Entry
;
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
))
1343 x
[3] = Entry
.D
[Y
] - v
;
1345 n
= Solve_Polynomial(3, x
, y
, Test_Flag(Prism
, STURM_FLAG
), 0.0);
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
;
1370 /*****************************************************************************
1384 * Dieter Bayer, July 1994
1388 * Test if the 2d ray (= P + t * D) intersects a rectangle.
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
)
1404 dmin
= (x1
- P
[X
]) / D
[X
];
1405 dmax
= (x2
- P
[X
]) / D
[X
];
1414 dmax
= (x1
- P
[X
]) / D
[X
];
1421 dmin
= (x2
- P
[X
]) / D
[X
];
1431 if ((P
[X
] < x1
) || (P
[X
] > x2
))
1442 if (fabs(D
[Z
]) > EPSILON
)
1446 tmin
= (z1
- P
[Z
]) / D
[Z
];
1447 tmax
= (z2
- P
[Z
]) / D
[Z
];
1451 tmax
= (z1
- P
[Z
]) / D
[Z
];
1452 tmin
= (z2
- P
[Z
]) / D
[Z
];
1479 /*dmax = tmax; */ /*not needed CEY[1/95]*/
1490 /* dmin = tmin; */ /*not needed CEY[1/95]*/
1496 if ((P
[Z
] < z1
) || (P
[Z
] > z2
))
1507 /*****************************************************************************
1516 * P - Points defining prism
1526 * Dieter Bayer, June 1994
1530 * Calculate the spline segments of a prism from a set of points.
1534 * May 1994 : Creation.
1536 ******************************************************************************/
1538 void Compute_Prism(PRISM
*Prism
, UV_VECT
*P
)
1540 int i
, n
, number_of_splines
;
1543 DBL x
[4], xmin
, xmax
;
1544 DBL y
[4], ymin
, ymax
;
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");
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
)
1585 Assign_UV_Vect(First
, P
[0]);
1589 case QUADRATIC_SPLINE
:
1592 Assign_UV_Vect(First
, P
[1]);
1597 for (i
= number_of_splines
= 0; i
< Prism
->Number
-1; i
++)
1599 /* Get indices of previous and next two points. */
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. */
1622 C
[X
] = -1.0 * P
[i
][X
] + 1.0 * P
[i1
][X
];
1623 D
[X
] = 1.0 * P
[i
][X
];
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
];
1638 /*************************************************************************
1640 **************************************************************************/
1642 case QUADRATIC_SPLINE
:
1644 if (i2
>= Prism
->Number
)
1646 Error("Too few points in prism.\n");
1649 /* Use quadratic interpolation. */
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
];
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
];
1669 /*************************************************************************
1671 **************************************************************************/
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
];
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
];
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
];
1700 /*************************************************************************
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
];
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
];
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. */
1754 n
= Solve_Polynomial(2, c
, r
, FALSE
, 0.0);
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
];
1768 n
= Solve_Polynomial(2, c
, r
, FALSE
, 0.0);
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
)
1808 if ((fabs(P
[i1
][X
] - First
[X
]) < EPSILON
) &&
1809 (fabs(P
[i1
][Y
] - First
[Y
]) < EPSILON
))
1813 if (i
+1 < Prism
->Number
)
1815 Assign_UV_Vect(First
, P
[i
+1]);
1821 case QUADRATIC_SPLINE
:
1823 if ((fabs(P
[i2
][X
] - First
[X
]) < EPSILON
) &&
1824 (fabs(P
[i2
][Y
] - First
[Y
]) < EPSILON
))
1828 if (i
+2 < Prism
->Number
)
1830 Assign_UV_Vect(First
, P
[i
+2]);
1838 if ((fabs(P
[i2
][X
] - First
[X
]) < EPSILON
) &&
1839 (fabs(P
[i2
][Y
] - First
[Y
]) < EPSILON
))
1843 if (i
+2 < Prism
->Number
)
1845 Assign_UV_Vect(First
, P
[i
+2]);
1859 Prism
->Number
= number_of_splines
;
1861 /* Set overall bounding rectangle. */
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]));
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]));