1 /****************************************************************************
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 /****************************************************************************
34 * The "inside polygon"-test was taken from:
36 * E. Haines, "An Introduction to Ray-Tracing", ..., pp. 53-59
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 *****************************************************************************/
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 /*****************************************************************************
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 /*****************************************************************************
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 /*****************************************************************************
114 * All_Polygon_Intersections
120 * Depth_Stack - Intersection stack
128 * int - TRUE, if a intersection was found
136 * Determine ray/polygon intersection and clip intersection found.
140 * May 1994 : Creation.
142 ******************************************************************************/
144 static int All_Polygon_Intersections(OBJECT
*Object
, RAY
*Ray
, ISTACK
*Depth_Stack
)
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
);
166 /*****************************************************************************
176 * Depth - Depth of intersection found
184 * int - TRUE if intersection found
192 * Determine ray/polygon intersection.
196 * May 1994 : Creation.
198 ******************************************************************************/
200 static int intersect_poylgon(RAY
*Ray
, POLYGON
*Polyg
, DBL
*Depth
)
205 /* Don't test degenerate polygons. */
207 if (Test_Flag(Polyg
, DEGENERATE_FLAG
))
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
);
222 VInverseScaleEq(d
, len
);
224 /* Intersect ray with the plane in which the polygon lies. */
226 if (fabs(d
[Z
]) < ZERO_TOLERANCE
)
231 *Depth
= -p
[Z
] / d
[Z
];
233 if ((*Depth
< DEPTH_TOLERANCE
) || (*Depth
> Max_Distance
))
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
]);
259 /*****************************************************************************
267 * IPoint - Intersection point
282 * Polygons can't be used in CSG.
286 * May 1994 : Creation.
288 ******************************************************************************/
290 static int Inside_Polygon(VECTOR IPoint
, OBJECT
*Object
)
297 /*****************************************************************************
305 * Result - Normal vector
307 * Inter - Intersection found
321 * Calculate the normal of the polygon in a given point.
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 /*****************************************************************************
345 * Vector - Translation vector
359 * Translate a polygon.
363 * May 1994 : Creation.
365 ******************************************************************************/
367 static void Translate_Polygon(OBJECT
*Object
, VECTOR Vector
, TRANSFORM
*Trans
)
369 Transform_Polygon(Object
, Trans
);
374 /*****************************************************************************
383 * Vector - Rotation vector
401 * May 1994 : Creation.
403 ******************************************************************************/
405 static void Rotate_Polygon(OBJECT
*Object
, VECTOR Vector
, TRANSFORM
*Trans
)
407 Transform_Polygon(Object
, Trans
);
412 /*****************************************************************************
421 * Vector - Scaling vector
439 * May 1994 : Creation.
441 ******************************************************************************/
443 static void Scale_Polygon(OBJECT
*Object
, VECTOR Vector
, TRANSFORM
*Trans
)
445 Transform_Polygon(Object
, Trans
);
450 /*****************************************************************************
459 * Trans - Transformation to apply
473 * Transform a polygon by transforming all points
474 * and recalculating the polygon.
478 * May 1994 : Creation.
480 ******************************************************************************/
482 static void Transform_Polygon(OBJECT
*Object
, TRANSFORM
*Trans
)
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 /*****************************************************************************
525 * May 1994 : Creation.
527 ******************************************************************************/
529 static void Invert_Polygon(OBJECT
*Object
)
535 /*****************************************************************************
547 * POLYGON * - new polygon
555 * Create a new polygon.
559 * May 1994 : Creation.
561 ******************************************************************************/
563 POLYGON
*Create_Polygon()
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);
582 /*****************************************************************************
596 * void * - New polygon
604 * Copy a polygon structure.
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
);
626 New
->Trans
= Copy_Transform(Polyg
->Trans
);
628 New
->Data
->References
++;
635 /*****************************************************************************
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
);
685 /*****************************************************************************
694 * Points - 3D points describing the polygon
708 * Compute the following things for a given polygon:
710 * - Polygon transformation
712 * - Array of 2d points describing the shape of the polygon
716 * May 1994 : Creation.
718 ******************************************************************************/
720 void Compute_Polygon(POLYGON
*Polyg
, int Number
, VECTOR
*Points
)
724 VECTOR o
, u
= {}, v
= {}, w
= {}, N
;
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");
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
)
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
);
775 if ((VSumSqr(v
) > EPSILON
) && (VSumSqr(w
) > EPSILON
))
783 Set_Flag(Polyg
, DEGENERATE_FLAG
);
785 Warning(0.0, "Points in polygon are co-linear. Ignoring polygon.\n");
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 /*****************************************************************************
853 * Compute_Polygon_BBox
871 * Calculate the bounding box of a polygon.
875 * May 1994 : Creation.
877 ******************************************************************************/
879 static void Compute_Polygon_BBox(POLYGON
*Polyg
)
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
];
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 /*****************************************************************************
934 * Number - Number of points
935 * Points - Points describing polygon's shape
936 * u, v - 2D-coordinates of the point to test
942 * int - TRUE, if inside
946 * Eric Haines, 3D/Eye Inc, erich@eye.com
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.
981 ******************************************************************************/
983 static int in_polygon(int Number
, UV_VECT
*Points
, DBL u
, DBL v
)
985 register int i
, yflag0
, yflag1
, inside_flag
;
987 register DBL
*vtx0
, *vtx1
, *first
;
992 vtx0
= &Points
[0][X
];
993 vtx1
= &Points
[1][X
];
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
);
1051 vtx1
= &Points
[++i
][X
];
1057 return(inside_flag
);