Attempt to fix nightly build.
[AROS-Contrib.git] / gfx / povray / polygon.c
blob37a5bdf147410e2710a1f1985dd3bff0e3c9fc8f
1 /****************************************************************************
2 * polygon.c
4 * This module implements functions that manipulate polygons.
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 * Syntax:
32 * ---
34 * The "inside polygon"-test was taken from:
36 * E. Haines, "An Introduction to Ray-Tracing", ..., pp. 53-59
38 * ---
40 * May 1994 : Creation. [DB]
42 * Oct 1994 : Changed polygon structure. Polygon points are now stored
43 * in a seperate structure. This - together with the use of
44 * a transformation - allows to keep just one point definition
45 * for multiple copies of one polygon. [DB]
47 *****************************************************************************/
49 #include "frame.h"
50 #include "vector.h"
51 #include "povproto.h"
52 #include "matrices.h"
53 #include "objects.h"
54 #include "polygon.h"
55 #include "povray.h"
60 /*****************************************************************************
61 * Local preprocessor defines
62 ******************************************************************************/
64 /* Minimal intersection depth for a valid intersection. */
66 #define DEPTH_TOLERANCE 1.0e-8
68 /* If |x| < ZERO_TOLERANCE x is assumed to be 0. */
70 #define ZERO_TOLERANCE 1.0e-10
75 /*****************************************************************************
76 * Static functions
77 ******************************************************************************/
79 static int intersect_poylgon (RAY *Ray, POLYGON *Polyg, DBL *Depth);
80 static int in_polygon (int Number, UV_VECT *Points, DBL u, DBL v);
81 static int All_Polygon_Intersections (OBJECT *Object, RAY *Ray, ISTACK *Depth_Stack);
82 static int Inside_Polygon (VECTOR point, OBJECT *Object);
83 static void Polygon_Normal (VECTOR Result, OBJECT *Object, INTERSECTION *Inter);
84 static POLYGON *Copy_Polygon (OBJECT *Object);
85 static void Translate_Polygon (OBJECT *Object, VECTOR Vector, TRANSFORM *Trans);
86 static void Rotate_Polygon (OBJECT *Object, VECTOR Vector, TRANSFORM *Trans);
87 static void Scale_Polygon (OBJECT *Object, VECTOR Vector, TRANSFORM *Trans);
88 static void Transform_Polygon (OBJECT *Object, TRANSFORM *Trans);
89 static void Invert_Polygon (OBJECT *Object);
90 static void Destroy_Polygon (OBJECT *Object);
91 static void Compute_Polygon_BBox (POLYGON *Polyg);
95 /*****************************************************************************
96 * Local variables
97 ******************************************************************************/
99 static METHODS Polygon_Methods =
101 All_Polygon_Intersections,
102 Inside_Polygon, Polygon_Normal,
103 (COPY_METHOD)Copy_Polygon,
104 Translate_Polygon, Rotate_Polygon,
105 Scale_Polygon, Transform_Polygon, Invert_Polygon, Destroy_Polygon
110 /*****************************************************************************
112 * FUNCTION
114 * All_Polygon_Intersections
116 * INPUT
118 * Object - Object
119 * Ray - Ray
120 * Depth_Stack - Intersection stack
122 * OUTPUT
124 * Depth_Stack
126 * RETURNS
128 * int - TRUE, if a intersection was found
130 * AUTHOR
132 * Dieter Bayer
134 * DESCRIPTION
136 * Determine ray/polygon intersection and clip intersection found.
138 * CHANGES
140 * May 1994 : Creation.
142 ******************************************************************************/
144 static int All_Polygon_Intersections(OBJECT *Object, RAY *Ray, ISTACK *Depth_Stack)
146 DBL Depth;
147 VECTOR IPoint;
149 if (intersect_poylgon(Ray, (POLYGON *)Object, &Depth))
151 VEvaluateRay(IPoint, Ray->Initial, Depth, Ray->Direction);
153 if (Point_In_Clip(IPoint, Object->Clip))
155 push_entry(Depth, IPoint, Object, Depth_Stack);
157 return(TRUE);
161 return(FALSE);
166 /*****************************************************************************
168 * FUNCTION
170 * intersect_poylgon
172 * INPUT
174 * Ray - Ray
175 * Polyg - Polygon
176 * Depth - Depth of intersection found
178 * OUTPUT
180 * Depth
182 * RETURNS
184 * int - TRUE if intersection found
186 * AUTHOR
188 * Dieter Bayer
190 * DESCRIPTION
192 * Determine ray/polygon intersection.
194 * CHANGES
196 * May 1994 : Creation.
198 ******************************************************************************/
200 static int intersect_poylgon(RAY *Ray, POLYGON *Polyg, DBL *Depth)
202 DBL x, y, len;
203 VECTOR p, d;
205 /* Don't test degenerate polygons. */
207 if (Test_Flag(Polyg, DEGENERATE_FLAG))
209 return(FALSE);
212 Increase_Counter(stats[Ray_Polygon_Tests]);
214 /* Transform the ray into the polygon space. */
216 MInvTransPoint(p, Ray->Initial, Polyg->Trans);
218 MInvTransDirection(d, Ray->Direction, Polyg->Trans);
220 VLength(len, d);
222 VInverseScaleEq(d, len);
224 /* Intersect ray with the plane in which the polygon lies. */
226 if (fabs(d[Z]) < ZERO_TOLERANCE)
228 return(FALSE);
231 *Depth = -p[Z] / d[Z];
233 if ((*Depth < DEPTH_TOLERANCE) || (*Depth > Max_Distance))
235 return(FALSE);
238 /* Does the intersection point lie inside the polygon? */
240 x = p[X] + *Depth * d[X];
241 y = p[Y] + *Depth * d[Y];
243 if (in_polygon(Polyg->Data->Number, Polyg->Data->Points, x, y))
245 Increase_Counter(stats[Ray_Polygon_Tests_Succeeded]);
247 *Depth /= len;
249 return (TRUE);
251 else
253 return (FALSE);
259 /*****************************************************************************
261 * FUNCTION
263 * Inside_Polygon
265 * INPUT
267 * IPoint - Intersection point
268 * Object - Object
270 * OUTPUT
272 * RETURNS
274 * int - always FALSE
276 * AUTHOR
278 * Dieter Bayer
280 * DESCRIPTION
282 * Polygons can't be used in CSG.
284 * CHANGES
286 * May 1994 : Creation.
288 ******************************************************************************/
290 static int Inside_Polygon(VECTOR IPoint, OBJECT *Object)
292 return(FALSE);
297 /*****************************************************************************
299 * FUNCTION
301 * Polygon_Normal
303 * INPUT
305 * Result - Normal vector
306 * Object - Object
307 * Inter - Intersection found
309 * OUTPUT
311 * Result
313 * RETURNS
315 * AUTHOR
317 * Dieter Bayer
319 * DESCRIPTION
321 * Calculate the normal of the polygon in a given point.
323 * CHANGES
325 * May 1994 : Creation.
327 ******************************************************************************/
329 static void Polygon_Normal(VECTOR Result, OBJECT *Object, INTERSECTION *Inter)
331 Assign_Vector(Result, ((POLYGON *)Object)->S_Normal);
336 /*****************************************************************************
338 * FUNCTION
340 * Translate_Polygon
342 * INPUT
344 * Object - Object
345 * Vector - Translation vector
347 * OUTPUT
349 * Object
351 * RETURNS
353 * AUTHOR
355 * Dieter Bayer
357 * DESCRIPTION
359 * Translate a polygon.
361 * CHANGES
363 * May 1994 : Creation.
365 ******************************************************************************/
367 static void Translate_Polygon(OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)
369 Transform_Polygon(Object, Trans);
374 /*****************************************************************************
376 * FUNCTION
378 * Rotate_Polygon
380 * INPUT
382 * Object - Object
383 * Vector - Rotation vector
385 * OUTPUT
387 * Object
389 * RETURNS
391 * AUTHOR
393 * Dieter Bayer
395 * DESCRIPTION
397 * Rotate a polygon.
399 * CHANGES
401 * May 1994 : Creation.
403 ******************************************************************************/
405 static void Rotate_Polygon(OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)
407 Transform_Polygon(Object, Trans);
412 /*****************************************************************************
414 * FUNCTION
416 * Scale_Polygon
418 * INPUT
420 * Object - Object
421 * Vector - Scaling vector
423 * OUTPUT
425 * Object
427 * RETURNS
429 * AUTHOR
431 * Dieter Bayer
433 * DESCRIPTION
435 * Scale a polygon.
437 * CHANGES
439 * May 1994 : Creation.
441 ******************************************************************************/
443 static void Scale_Polygon(OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)
445 Transform_Polygon(Object, Trans);
450 /*****************************************************************************
452 * FUNCTION
454 * Transform_Polygon
456 * INPUT
458 * Object - Object
459 * Trans - Transformation to apply
461 * OUTPUT
463 * Object
465 * RETURNS
467 * AUTHOR
469 * Dieter Bayer
471 * DESCRIPTION
473 * Transform a polygon by transforming all points
474 * and recalculating the polygon.
476 * CHANGES
478 * May 1994 : Creation.
480 ******************************************************************************/
482 static void Transform_Polygon(OBJECT *Object, TRANSFORM *Trans)
484 VECTOR N;
485 POLYGON *Polyg = (POLYGON *)Object;
487 Compose_Transforms(Polyg->Trans, Trans);
489 Make_Vector(N, 0.0, 0.0, 1.0);
490 MTransNormal(Polyg->S_Normal, N, Polyg->Trans);
492 VNormalizeEq(Polyg->S_Normal);
494 Compute_Polygon_BBox(Polyg);
499 /*****************************************************************************
501 * FUNCTION
503 * Invert_Polygon
505 * INPUT
507 * Object - Object
509 * OUTPUT
511 * Object
513 * RETURNS
515 * AUTHOR
517 * Dieter Bayer
519 * DESCRIPTION
521 * Invert a polygon.
523 * CHANGES
525 * May 1994 : Creation.
527 ******************************************************************************/
529 static void Invert_Polygon(OBJECT *Object)
535 /*****************************************************************************
537 * FUNCTION
539 * Create_Polygon
541 * INPUT
543 * OUTPUT
545 * RETURNS
547 * POLYGON * - new polygon
549 * AUTHOR
551 * Dieter Bayer
553 * DESCRIPTION
555 * Create a new polygon.
557 * CHANGES
559 * May 1994 : Creation.
561 ******************************************************************************/
563 POLYGON *Create_Polygon()
565 POLYGON *New;
567 New = (POLYGON *)POV_MALLOC(sizeof(POLYGON), "polygon");
569 INIT_OBJECT_FIELDS(New,POLYGON_OBJECT,&Polygon_Methods)
571 New->Trans = Create_Transform();
573 Make_Vector(New->S_Normal, 0.0, 0.0, 1.0);
575 New->Data = NULL;
577 return (New);
582 /*****************************************************************************
584 * FUNCTION
586 * Copy_Polygon
588 * INPUT
590 * Object - Object
592 * OUTPUT
594 * RETURNS
596 * void * - New polygon
598 * AUTHOR
600 * Dieter Bayer
602 * DESCRIPTION
604 * Copy a polygon structure.
606 * CHANGES
608 * May 1994 : Creation.
610 ******************************************************************************/
612 static POLYGON *Copy_Polygon(OBJECT *Object)
614 POLYGON *New, *Polyg = (POLYGON *)Object;
616 New = Create_Polygon ();
618 /* Get rid of the transformation created in Create_Polygon(). */
620 Destroy_Transform(New->Trans);
622 /* Copy polygon. */
624 *New = *Polyg;
626 New->Trans = Copy_Transform(Polyg->Trans);
628 New->Data->References++;
630 return (New);
635 /*****************************************************************************
637 * FUNCTION
639 * Destroy_Polygon
641 * INPUT
643 * Object - Object
645 * OUTPUT
647 * Object
649 * RETURNS
651 * AUTHOR
653 * Dieter Bayer
655 * DESCRIPTION
657 * Destroy a polygon.
659 * CHANGES
661 * May 1994 : Creation.
663 * Dec 1994 : Fixed memory leakage. [DB]
665 ******************************************************************************/
667 static void Destroy_Polygon(OBJECT *Object)
669 POLYGON *Polyg = (POLYGON *)Object;
671 if (--(Polyg->Data->References) == 0)
673 POV_FREE (Polyg->Data->Points);
675 POV_FREE (Polyg->Data);
678 Destroy_Transform(Polyg->Trans);
680 POV_FREE (Object);
685 /*****************************************************************************
687 * FUNCTION
689 * Compute_Polygon
691 * INPUT
693 * Polyg - Polygon
694 * Points - 3D points describing the polygon
696 * OUTPUT
698 * Polyg
700 * RETURNS
702 * AUTHOR
704 * Dieter Bayer
706 * DESCRIPTION
708 * Compute the following things for a given polygon:
710 * - Polygon transformation
712 * - Array of 2d points describing the shape of the polygon
714 * CHANGES
716 * May 1994 : Creation.
718 ******************************************************************************/
720 void Compute_Polygon(POLYGON *Polyg, int Number, VECTOR *Points)
722 int i;
723 DBL x, y, z, d;
724 VECTOR o, u = {}, v = {}, w = {}, N;
725 MATRIX a, b;
727 /* Create polygon data. */
729 if (Polyg->Data == NULL)
731 Polyg->Data = (POLYGON_DATA *)POV_MALLOC(sizeof(POLYGON_DATA), "polygon points");
733 Polyg->Data->References = 1;
735 Polyg->Data->Number = Number;
737 Polyg->Data->Points = (UV_VECT *)POV_MALLOC(Number*sizeof(UV_VECT), "polygon points");
739 else
741 Error("Polygon data already computed.");
744 /* Get polygon's coordinate system (one of the many possible) */
746 Assign_Vector(o, Points[0]);
748 /* Find valid, i.e. non-zero u vector. */
750 for (i = 1; i < Number; i++)
752 VSub(u, Points[i], o);
754 if (VSumSqr(u) > EPSILON)
756 break;
760 if (i == Number)
762 Set_Flag(Polyg, DEGENERATE_FLAG);
764 Warning(0.0, "Points in polygon are co-linear. Ignoring polygon.\n");
767 /* Find valid, i.e. non-zero v and w vectors. */
769 for (i++; i < Number; i++)
771 VSub(v, Points[i], o);
773 VCross(w, u, v);
775 if ((VSumSqr(v) > EPSILON) && (VSumSqr(w) > EPSILON))
777 break;
781 if (i == Number)
783 Set_Flag(Polyg, DEGENERATE_FLAG);
785 Warning(0.0, "Points in polygon are co-linear. Ignoring polygon.\n");
788 VCross(u, v, w);
789 VCross(v, w, u);
791 VNormalize(u, u);
792 VNormalize(v, v);
793 VNormalize(w, w);
795 MIdentity(a);
796 MIdentity(b);
798 a[3][0] = -o[X];
799 a[3][1] = -o[Y];
800 a[3][2] = -o[Z];
802 b[0][0] = u[X];
803 b[1][0] = u[Y];
804 b[2][0] = u[Z];
806 b[0][1] = v[X];
807 b[1][1] = v[Y];
808 b[2][1] = v[Z];
810 b[0][2] = w[X];
811 b[1][2] = w[Y];
812 b[2][2] = w[Z];
814 MTimes(Polyg->Trans->inverse, a, b);
816 MInvers(Polyg->Trans->matrix, Polyg->Trans->inverse);
818 /* Project points onto the u,v-plane (3D --> 2D) */
820 for (i = 0; i < Number; i++)
822 x = Points[i][X] - o[X];
823 y = Points[i][Y] - o[Y];
824 z = Points[i][Z] - o[Z];
826 d = x * w[X] + y * w[Y] + z * w[Z];
828 if (fabs(d) > ZERO_TOLERANCE)
830 Set_Flag(Polyg, DEGENERATE_FLAG);
832 Warning(0.0, "Points in polygon are not co-planar. Ignoring polygons.\n");
835 Polyg->Data->Points[i][X] = x * u[X] + y * u[Y] + z * u[Z];
836 Polyg->Data->Points[i][Y] = x * v[X] + y * v[Y] + z * v[Z];
839 Make_Vector(N, 0.0, 0.0, 1.0);
840 MTransNormal(Polyg->S_Normal, N, Polyg->Trans);
842 VNormalizeEq(Polyg->S_Normal);
844 Compute_Polygon_BBox(Polyg);
849 /*****************************************************************************
851 * FUNCTION
853 * Compute_Polygon_BBox
855 * INPUT
857 * Polyg - Polygon
859 * OUTPUT
861 * Polyg
863 * RETURNS
865 * AUTHOR
867 * Dieter Bayer
869 * DESCRIPTION
871 * Calculate the bounding box of a polygon.
873 * CHANGES
875 * May 1994 : Creation.
877 ******************************************************************************/
879 static void Compute_Polygon_BBox(POLYGON *Polyg)
881 int i;
882 VECTOR p, Puv, Min, Max;
884 Min[X] = Min[Y] = Min[Z] = BOUND_HUGE;
885 Max[X] = Max[Y] = Max[Z] = -BOUND_HUGE;
887 for (i = 0; i < Polyg->Data->Number; i++)
889 Puv[X] = Polyg->Data->Points[i][X];
890 Puv[Y] = Polyg->Data->Points[i][Y];
891 Puv[Z] = 0.0;
893 MTransPoint(p, Puv, Polyg->Trans);
895 Min[X] = min(Min[X], p[X]);
896 Min[Y] = min(Min[Y], p[Y]);
897 Min[Z] = min(Min[Z], p[Z]);
898 Max[X] = max(Max[X], p[X]);
899 Max[Y] = max(Max[Y], p[Y]);
900 Max[Z] = max(Max[Z], p[Z]);
903 Make_BBox_from_min_max(Polyg->BBox, Min, Max);
905 if (fabs(Polyg->BBox.Lengths[X]) < Small_Tolerance)
907 Polyg->BBox.Lower_Left[X] -= Small_Tolerance;
908 Polyg->BBox.Lengths[X] += 2.0 * Small_Tolerance;
911 if (fabs(Polyg->BBox.Lengths[Y]) < Small_Tolerance)
913 Polyg->BBox.Lower_Left[Y] -= Small_Tolerance;
914 Polyg->BBox.Lengths[Y] += 2.0 * Small_Tolerance;
917 if (fabs(Polyg->BBox.Lengths[Z]) < Small_Tolerance)
919 Polyg->BBox.Lower_Left[Z] -= Small_Tolerance;
920 Polyg->BBox.Lengths[Z] += 2.0 * Small_Tolerance;
926 /*****************************************************************************
928 * FUNCTION
930 * in_polygon
932 * INPUT
934 * Number - Number of points
935 * Points - Points describing polygon's shape
936 * u, v - 2D-coordinates of the point to test
938 * OUTPUT
940 * RETURNS
942 * int - TRUE, if inside
944 * AUTHOR
946 * Eric Haines, 3D/Eye Inc, erich@eye.com
948 * DESCRIPTION
950 * ======= Crossings Multiply algorithm ===================================
952 * This version is usually somewhat faster than the original published in
953 * Graphics Gems IV; by turning the division for testing the X axis crossing
954 * into a tricky multiplication test this part of the test became faster,
955 * which had the additional effect of making the test for "both to left or
956 * both to right" a bit slower for triangles than simply computing the
957 * intersection each time. The main increase is in triangle testing speed,
958 * which was about 15% faster; all other polygon complexities were pretty much
959 * the same as before. On machines where division is very expensive (not the
960 * case on the HP 9000 series on which I tested) this test should be much
961 * faster overall than the old code. Your mileage may (in fact, will) vary,
962 * depending on the machine and the test data, but in general I believe this
963 * code is both shorter and faster. This test was inspired by unpublished
964 * Graphics Gems submitted by Joseph Samosky and Mark Haigh-Hutchinson.
965 * Related work by Samosky is in:
967 * Samosky, Joseph, "SectionView: A system for interactively specifying and
968 * visualizing sections through three-dimensional medical image data",
969 * M.S. Thesis, Department of Electrical Engineering and Computer Science,
970 * Massachusetts Institute of Technology, 1993.
973 * Shoot a test ray along +X axis. The strategy is to compare vertex Y values
974 * to the testing point's Y and quickly discard edges which are entirely to one
975 * side of the test ray.
977 * CHANGES
981 ******************************************************************************/
983 static int in_polygon(int Number, UV_VECT *Points, DBL u, DBL v)
985 register int i, yflag0, yflag1, inside_flag;
986 register DBL ty, tx;
987 register DBL *vtx0, *vtx1, *first;
989 tx = u;
990 ty = v;
992 vtx0 = &Points[0][X];
993 vtx1 = &Points[1][X];
995 first = vtx0;
997 /* get test bit for above/below X axis */
999 yflag0 = (vtx0[Y] >= ty);
1001 inside_flag = FALSE;
1003 for (i = 1; i < Number; )
1005 yflag1 = (vtx1[Y] >= ty);
1008 * Check if endpoints straddle (are on opposite sides) of X axis
1009 * (i.e. the Y's differ); if so, +X ray could intersect this edge.
1010 * The old test also checked whether the endpoints are both to the
1011 * right or to the left of the test point. However, given the faster
1012 * intersection point computation used below, this test was found to
1013 * be a break-even proposition for most polygons and a loser for
1014 * triangles (where 50% or more of the edges which survive this test
1015 * will cross quadrants and so have to have the X intersection computed
1016 * anyway). I credit Joseph Samosky with inspiring me to try dropping
1017 * the "both left or both right" part of my code.
1020 if (yflag0 != yflag1)
1023 * Check intersection of pgon segment with +X ray.
1024 * Note if >= point's X; if so, the ray hits it.
1025 * The division operation is avoided for the ">=" test by checking
1026 * the sign of the first vertex wrto the test point; idea inspired
1027 * by Joseph Samosky's and Mark Haigh-Hutchinson's different
1028 * polygon inclusion tests.
1031 if (((vtx1[Y]-ty) * (vtx0[X]-vtx1[X]) >= (vtx1[X]-tx) * (vtx0[Y]-vtx1[Y])) == yflag1)
1033 inside_flag = !inside_flag;
1037 /* Move to the next pair of vertices, retaining info as possible. */
1039 if ((i < Number-2) && (vtx1[X] == first[X]) && (vtx1[Y] == first[Y]))
1041 vtx0 = &Points[++i][X];
1042 vtx1 = &Points[++i][X];
1044 yflag0 = (vtx0[Y] >= ty);
1046 first = vtx0;
1048 else
1050 vtx0 = vtx1;
1051 vtx1 = &Points[++i][X];
1053 yflag0 = yflag1;
1057 return(inside_flag);