initial setup of thesis repository
[cluster_expansion_thesis.git] / little_helpers / tikz / sketch-0.2.161 / bsp.c
blob257c6932a872a2f15bf59796d0da9fcafcbdce47
1 /* bsp.c
2 Copyright (C) 2005,2006,2007,2008 Eugene K. Ressler, Jr.
4 This file is part of Sketch, a small, simple system for making
5 3d drawings with LaTeX and the PSTricks or TikZ package.
7 Sketch is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
12 Sketch is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Sketch; see the file COPYING.txt. If not, see
19 http://www.gnu.org/copyleft */
21 #include <stdio.h>
22 #include "bsp.h"
23 #include "geomio.h"
25 DECLARE_DYNAMIC_ARRAY_FUNCS (BSP_POLYGON_ATTR, BSP_VERTEX_ATTR,
26 polygon_attr, elt, n_elts, NO_OTHER_INIT)
27 // ---- polylines --------------------------------------------------------------
29 static BSP_POLYLINE_NODE *
30 new_bsp_polyline_node (void *attr)
32 BSP_POLYLINE_NODE *n = safe_malloc (sizeof *n);
33 n->tag = BSP_POLYLINE;
34 n->attr = attr;
35 n->prev = n->next = n->mark = n->in = n->on = n->out = NULL;
36 n->first_p = n->last_p = 0;
37 init_box_3d (n->extent);
38 init_polyline_3d (n->polyline);
39 return n;
42 static void
43 delete_bsp_polyline_node (BSP_POLYLINE_NODE * node)
45 clear_polyline_3d (node->polyline);
46 safe_free (node);
49 static void
50 set_bsp_polyline_extent (BSP_POLYLINE_NODE * node)
52 // set extent
53 init_box_3d (node->extent);
54 fold_min_max_polyline_3d (node->extent, node->polyline);
57 static void
58 init_bsp_polyline (BSP_POLYLINE_NODE * node, POLYLINE_3D * polyline)
60 // initial polyline contains first and last points; split ones don't
61 node->first_p = node->last_p = 1;
62 copy_polyline_3d (node->polyline, polyline);
63 set_bsp_polyline_extent (node);
66 static void
67 split_polyline_with_plane (BSP_POLYLINE_NODE * node,
68 PLANE * plane,
69 BSP_POLYLINE_NODE ** in_nodes,
70 BSP_POLYLINE_NODE ** on_nodes,
71 BSP_POLYLINE_NODE ** out_nodes)
73 int i, j, i_side, current_side;
74 BSP_POLYLINE_NODE *current, **list;
75 VECTOR_3D v, dp;
76 POINT_3D isect;
77 FLOAT t;
79 // initialize all the output lists to empty
80 *in_nodes = *on_nodes = *out_nodes = NULL;
82 // initialize the current polyline that's being "built", copying attributes
83 // of the original
84 current = new_bsp_polyline_node (node->attr);
86 // copy source polygon's first_ attribute
87 current->first_p = node->first_p;
89 // j is the trail index as we step through vertices with head i
90 j = 0;
92 // copy first vertex of polyline onto current output polyline
93 copy_pt_3d (pushed_polyline_3d_v (current->polyline), node->polyline->v[j]);
95 // find side of cutting plane that first vertex is on.
96 current_side =
97 (S_IN | S_ON | S_OUT) & pt_side_of_plane (plane, node->polyline->v[j]);
99 // loop through all directed segments j->i
100 for (i = 1; i < node->polyline->n_vertices; j = i++)
102 i_side =
103 (S_IN | S_ON | S_OUT) & pt_side_of_plane (plane,
104 node->polyline->v[i]);
106 #define HASH(Current, I) ((Current << 3) | I)
108 switch (HASH (current_side, i_side))
111 case HASH (S_OUT, S_IN):
112 case HASH (S_IN, S_OUT):
114 // vertices straddle the plane; compute the intersection
115 sub_pts_3d (v, node->polyline->v[i], node->polyline->v[j]); // direction vector
116 sub_pts_3d (dp, plane->p, node->polyline->v[j]); // P - L
117 t = dot_3d (dp, plane->n) / dot_3d (v, plane->n); // parameter of intersect
118 add_scaled_vec_to_pt_3d (isect, node->polyline->v[j], v, t); // intersect
120 // finish current polyline and add to current list
121 copy_pt_3d (pushed_polyline_3d_v (current->polyline), isect);
122 set_bsp_polyline_extent (current);
123 list = current_side == S_IN ? in_nodes : out_nodes;
124 current->in = (BSP_NODE *) * list;
125 *list = current;
127 // start a new one by adding the isect and new point
128 current = new_bsp_polyline_node (node->attr);
129 copy_pt_3d (pushed_polyline_3d_v (current->polyline), isect);
130 copy_pt_3d (pushed_polyline_3d_v (current->polyline),
131 node->polyline->v[i]);
132 current_side = i_side;
133 break;
135 case HASH (S_OUT, S_ON):
136 case HASH (S_IN, S_ON):
138 // line that was away from the plane joins it;
139 // finish current polyline and add to current list
140 copy_pt_3d (pushed_polyline_3d_v (current->polyline),
141 node->polyline->v[i]);
142 set_bsp_polyline_extent (current);
143 list = current_side == S_IN ? in_nodes : out_nodes;
144 current->in = (BSP_NODE *) * list;
145 *list = current;
147 // start a new one if there are still vertices left to process
148 if (i < node->polyline->n_vertices - 1)
150 current = new_bsp_polyline_node (node->attr);
151 copy_pt_3d (pushed_polyline_3d_v (current->polyline),
152 node->polyline->v[i]);
153 current_side = S_ON;
155 else
157 // copy last_p attribute from source
158 current->last_p = node->last_p;
159 current = NULL;
160 current_side = 0;
162 break;
164 case HASH (S_ON, S_OUT):
165 case HASH (S_ON, S_IN):
167 // line that was on the plane springs away from it;
168 // if there is more than one point in the current polyline,
169 // complete it and start a new one
170 if (current->polyline->n_vertices > 1)
172 FLOAT *last_vertex = current->polyline->v[current->polyline->n_vertices - 1]; //remember last vertex
173 set_bsp_polyline_extent (current);
174 current->in = (BSP_NODE *) * on_nodes;
175 *on_nodes = current;
176 current = new_bsp_polyline_node (node->attr);
177 copy_pt_3d (pushed_polyline_3d_v (current->polyline),
178 last_vertex);
180 // add the new vertex to the current polyline
181 copy_pt_3d (pushed_polyline_3d_v (current->polyline),
182 node->polyline->v[i]);
183 current_side = i_side; // now either in or out
184 break;
186 default:
188 // nothing has changed, so just add the new point
189 // to the ccurrent polygon
190 copy_pt_3d (pushed_polyline_3d_v (current->polyline),
191 node->polyline->v[i]);
192 break;
195 // finish the final polyline
196 if (current)
198 // copy last_p attribute from source
199 current->last_p = node->last_p;
201 set_bsp_polyline_extent (current);
202 list = (current_side & S_IN) ? in_nodes :
203 (current_side & S_OUT) ? out_nodes : on_nodes;
204 current->in = (BSP_NODE *) * list;
205 *list = current;
209 static void
210 insert_polyline (BSP_TREE * bsp, BSP_POLYLINE_NODE * node)
212 if (*bsp == NULL)
214 *bsp = (BSP_NODE *) node;
216 else if ((*bsp)->tag == BSP_POLYLINE)
218 BSP_POLYLINE_NODE *bsp_node = (BSP_POLYLINE_NODE *) * bsp;
219 #ifdef EXPERIMENTAL_OPTIMIZATION
220 node->in = bsp_node;
221 *bsp = (BSP_NODE *) node;
222 #else
223 insert_polyline ((BSP_TREE *) & bsp_node->in, node);
224 #endif
226 else
227 { // BSP_POLYGON
228 BSP_POLYGON_NODE *bsp_node = (BSP_POLYGON_NODE *) * bsp;
229 int side = polyline_side_of_plane (node->polyline, bsp_node->plane);
230 if (side == S_IN)
231 insert_polyline (&bsp_node->in, node);
232 else if (side == S_ON)
233 insert_polyline (&bsp_node->on, node);
234 else if (side == S_OUT)
235 insert_polyline (&bsp_node->out, node);
236 else
237 { // S_SPLIT
238 BSP_POLYLINE_NODE *in_polylines, *on_polylines, *out_polylines,
239 *p, *p_next;
240 split_polyline_with_plane (node, bsp_node->plane, &in_polylines,
241 &on_polylines, &out_polylines);
242 // remove polylines from lists and add to respective bsp subtrees recursively
243 for (p = in_polylines; p; p = p_next)
245 p_next = (BSP_POLYLINE_NODE *) p->in;
246 p->in = NULL;
247 insert_polyline (&bsp_node->in, p);
249 for (p = on_polylines; p; p = p_next)
251 p_next = (BSP_POLYLINE_NODE *) p->in;
252 p->in = NULL;
253 insert_polyline (&bsp_node->on, p);
255 for (p = out_polylines; p; p = p_next)
257 p_next = (BSP_POLYLINE_NODE *) p->in;
258 p->in = NULL;
259 insert_polyline (&bsp_node->out, p);
261 delete_bsp_polyline_node (node);
266 void
267 add_polyline_to_bsp (BSP_TREE * bsp, POLYLINE_3D * polyline, void *attr)
269 BSP_POLYLINE_NODE *node = new_bsp_polyline_node (attr);
270 init_bsp_polyline (node, polyline);
271 insert_polyline (bsp, node);
274 // ---- polygons ---------------------------------------------------------------
276 static BSP_POLYGON_NODE *
277 new_bsp_polygon_node (void *attr)
279 BSP_POLYGON_NODE *n = safe_malloc (sizeof *n);
280 n->tag = BSP_POLYGON;
281 n->attr = attr;
282 n->prev = n->next = n->mark = n->in = n->on = n->out = NULL;
283 init_box_3d (n->extent);
284 init_polygon_3d (n->polygon);
285 init_polygon_attr (n->polygon_attr);
286 return n;
289 static void
290 set_bsp_polygon_extent (BSP_POLYGON_NODE * node)
292 // set extent
293 init_box_3d (node->extent);
294 fold_min_max_polygon_3d (node->extent, node->polygon);
297 static void
298 init_bsp_polygon_node (BSP_POLYGON_NODE * node, POLYGON_3D * polygon)
300 int i;
302 // fill in the polygon verticies
303 copy_polygon_3d (node->polygon, polygon);
305 // fill in the plane
306 find_polygon_plane (node->plane, polygon);
308 // mark all edges as border edges
309 setup_polygon_attr (node->polygon_attr, polygon->n_sides);
310 for (i = 0; i < polygon->n_sides; i++)
311 node->polygon_attr->elt[i].border_p = 1;
312 node->polygon_attr->n_elts = polygon->n_sides;
314 // fill in the extent
315 set_bsp_polygon_extent (node);
318 static void
319 delete_bsp_polygon_node (BSP_POLYGON_NODE * node)
321 clear_polygon_3d (node->polygon);
322 clear_polygon_attr (node->polygon_attr);
323 safe_free (node);
326 // decide whether a j->i edge of the the new polygon that has
327 // been split from parent is part of the border.
328 static int
329 is_new_border_p (BSP_VERTEX_ATTR * i_attr,
330 BSP_VERTEX_ATTR * j_attr,
331 BSP_POLYGON_ATTR * parent_attr, int parent_n_sides)
333 int parent_is_border_p;
335 if (parent_attr->n_elts != parent_n_sides)
336 die (no_line, "failed assumption on attribute size");
337 parent_is_border_p = parent_attr->elt[j_attr->parent_vtx].border_p;
338 if (!parent_is_border_p)
339 return 0;
341 if (i_attr->cut_p)
343 if (j_attr->cut_p)
345 return 0;
347 else
349 return i_attr->parent_vtx == j_attr->parent_vtx;
352 return (i_attr->parent_vtx - j_attr->parent_vtx +
353 parent_n_sides) % parent_n_sides == 1;
356 static void
357 decide_boundaries (BSP_POLYGON_NODE * new_node, BSP_POLYGON_NODE * node)
359 int i, j, last_border_p;
361 i = 0;
362 j = new_node->polygon->n_sides - 1;
363 last_border_p =
364 is_new_border_p (&new_node->polygon_attr->elt[i],
365 &new_node->polygon_attr->elt[j],
366 node->polygon_attr, node->polygon->n_sides);
367 for (j = i++; i < new_node->polygon->n_sides; j = i++)
369 new_node->polygon_attr->elt[j].border_p =
370 is_new_border_p (&new_node->polygon_attr->elt[i],
371 &new_node->polygon_attr->elt[j],
372 node->polygon_attr, node->polygon->n_sides);
374 new_node->polygon_attr->elt[j].border_p = last_border_p;
377 static void
378 push_polygon_attr (BSP_POLYGON_NODE * node, int parent_vtx, int cut_p)
380 BSP_VERTEX_ATTR *vertex_attr = pushed_polygon_attr_elt (node->polygon_attr);
381 vertex_attr->border_p = 0;
382 vertex_attr->parent_vtx = parent_vtx;
383 vertex_attr->cut_p = cut_p;
386 static void
387 split_polygon_with_plane (BSP_POLYGON_NODE * node,
388 PLANE * plane,
389 BSP_POLYGON_NODE * in_node,
390 BSP_POLYGON_NODE * out_node)
392 int i, j, i_side, j_side;
393 VECTOR_3D v, dp;
394 POINT_3D isect;
395 FLOAT t;
397 // reset fill pointers
398 in_node->polygon->n_sides = out_node->polygon->n_sides = 0;
399 in_node->polygon_attr->n_elts = out_node->polygon_attr->n_elts = 0;
401 // process all pairs of vertices
402 j = node->polygon->n_sides - 1;
403 i_side = pt_side_of_plane (plane, node->polygon->v[j]);
404 for (i = 0; i < node->polygon->n_sides; j = i++)
406 j_side = i_side;
407 i_side = pt_side_of_plane (plane, node->polygon->v[i]);
409 if ((i_side | j_side) == (S_IN | S_OUT))
412 // the two most recent points straddle the the plane
413 // compute the intersection
414 sub_pts_3d (v, node->polygon->v[i], node->polygon->v[j]); // direction vector
415 sub_pts_3d (dp, plane->p, node->polygon->v[j]); // P - L
416 t = dot_3d (dp, plane->n) / dot_3d (v, plane->n); // parameter of intersect
417 add_scaled_vec_to_pt_3d (isect, node->polygon->v[j], v, t); // intersect
419 // put intersect in both polygons
420 copy_pt_3d (pushed_polygon_3d_v (in_node->polygon), isect);
421 copy_pt_3d (pushed_polygon_3d_v (out_node->polygon), isect);
423 if (i_side == S_IN)
425 // edge traversed from outside to in
426 push_polygon_attr (out_node, j, 1);
427 push_polygon_attr (in_node, j, 1);
428 copy_pt_3d (pushed_polygon_3d_v (in_node->polygon),
429 node->polygon->v[i]);
430 push_polygon_attr (in_node, i, 0);
432 else
434 // edge traversed from inside to out
435 push_polygon_attr (out_node, j, 1);
436 push_polygon_attr (in_node, j, 1);
437 copy_pt_3d (pushed_polygon_3d_v (out_node->polygon),
438 node->polygon->v[i]);
439 push_polygon_attr (out_node, i, 0);;
442 else if (i_side & S_ON)
445 // the current vertex is on the plane
446 // put it in both polygons
447 copy_pt_3d (pushed_polygon_3d_v (in_node->polygon),
448 node->polygon->v[i]);
449 copy_pt_3d (pushed_polygon_3d_v (out_node->polygon),
450 node->polygon->v[i]);
451 push_polygon_attr (in_node, i, 0);
452 push_polygon_attr (out_node, i, 0);
454 else
457 // the new vertex is not straddling nor on the plane
458 // so we output it to the correct polygon
459 if (i_side == S_IN)
461 copy_pt_3d (pushed_polygon_3d_v (in_node->polygon),
462 node->polygon->v[i]);
463 push_polygon_attr (in_node, i, 0);
465 else
467 copy_pt_3d (pushed_polygon_3d_v (out_node->polygon),
468 node->polygon->v[i]);
469 push_polygon_attr (out_node, i, 0);
473 // fill in the planes
474 find_polygon_plane (in_node->plane, in_node->polygon);
475 find_polygon_plane (out_node->plane, out_node->polygon);
477 // set up extents
478 set_bsp_polygon_extent (in_node);
479 set_bsp_polygon_extent (out_node);
481 // make a pass around the in and out polygons to fill in boundardy_p
482 decide_boundaries (in_node, node);
483 decide_boundaries (out_node, node);
486 static void
487 insert_polygon (BSP_TREE * bsp, BSP_POLYGON_NODE * node)
489 if (*bsp == NULL)
490 *bsp = (BSP_NODE *) node;
491 else
493 BSP_POLYGON_NODE *bsp_node = (BSP_POLYGON_NODE *) * bsp;
494 int side = polygon_side_of_plane (node->polygon, bsp_node->plane);
495 if (side & (S_IN | S_ON))
496 insert_polygon (&bsp_node->in, node);
497 else if (side == S_OUT)
498 insert_polygon (&bsp_node->out, node);
499 else
501 BSP_POLYGON_NODE *in_node = new_bsp_polygon_node (node->attr);
502 BSP_POLYGON_NODE *out_node = new_bsp_polygon_node (node->attr);
503 split_polygon_with_plane (node, bsp_node->plane, in_node, out_node);
504 insert_polygon (&bsp_node->in, in_node);
505 insert_polygon (&bsp_node->out, out_node);
506 delete_bsp_polygon_node (node);
511 void
512 add_polygon_to_bsp (BSP_TREE * bsp, POLYGON_3D * polygon, void *attr)
514 BSP_POLYGON_NODE *node = new_bsp_polygon_node (attr);
515 init_bsp_polygon_node (node, polygon);
516 insert_polygon (bsp, node);
519 static struct
521 BSP_NODE_FUNC func;
522 void *env;
524 traverse_closure[1];
526 static void
527 walk_bsp (BSP_NODE * bsp)
529 if (bsp == NULL)
530 return;
531 if (bsp->tag == BSP_POLYGON)
533 BSP_POLYGON_NODE *node = (BSP_POLYGON_NODE *) bsp;
534 if (node->plane->n[Z] < 0)
536 walk_bsp (node->out);
537 traverse_closure->func (bsp, traverse_closure->env);
538 walk_bsp (node->on);
539 walk_bsp (node->in);
541 else
543 walk_bsp (node->in);
544 traverse_closure->func (bsp, traverse_closure->env);
545 walk_bsp (node->on);
546 walk_bsp (node->out);
549 else
550 { // BSP_POLYLINE
551 BSP_POLYLINE_NODE *node = (BSP_POLYLINE_NODE *) bsp;
552 traverse_closure->func (bsp, traverse_closure->env);
553 walk_bsp ((BSP_NODE *) node->in);
557 void
558 traverse_bsp (BSP_NODE * bsp, BSP_NODE_FUNC func, void *env)
560 traverse_closure->func = func;
561 traverse_closure->env = env;
562 walk_bsp (bsp);
565 void
566 traverse_depth_sort (BSP_NODE * bsp, BSP_NODE_FUNC func, void *env)
568 traverse_closure->func = func;
569 traverse_closure->env = env;
570 for (; bsp; bsp = bsp->next)
571 walk_bsp (bsp);
574 static void
575 indent (FILE * f, int n)
577 while (n-- > 0)
578 fprintf (f, " ");
581 static void
582 print_bsp_internal (FILE * f, BSP_NODE * bsp, int n)
584 if (bsp == NULL)
585 return;
587 indent (f, 2 * n);
588 if (bsp->tag == BSP_POLYGON)
591 BSP_POLYGON_NODE *node = (BSP_POLYGON_NODE *) bsp;
592 fprintf (f, "BSPpolygon\n");
594 indent (f, 2 * n + 1);
595 print_plane (f, node->plane);
597 indent (f, 2 * n + 1);
598 print_polygon_3d (f, node->polygon);
600 indent (f, 2 * n + 1);
601 fprintf (f, "in\n");
602 print_bsp_internal (f, node->in, n + 1);
604 indent (f, 2 * n + 1);
605 fprintf (f, "on\n");
606 print_bsp_internal (f, node->on, n + 1);
608 indent (f, 2 * n + 1);
609 fprintf (f, "out\n");
610 print_bsp_internal (f, node->out, n + 1);
612 else
613 { // BSP_POLYLINE
614 BSP_POLYLINE_NODE *node = (BSP_POLYLINE_NODE *) bsp;
615 fprintf (f, "BSPpolyline ");
616 print_polyline_3d (f, node->polyline);
617 print_bsp_internal (f, (BSP_NODE *) node->in, n);
621 void
622 print_bsp (FILE * f, BSP_NODE * bsp)
624 print_bsp_internal (f, bsp, 0);
627 void
628 add_polygon_to_sort (BSP_TREE * bsp, POLYGON_3D * polygon, void *attr)
630 BSP_POLYGON_NODE *node = new_bsp_polygon_node (attr);
631 init_bsp_polygon_node (node, polygon);
632 node->next = *bsp;
633 *bsp = (BSP_NODE *) node;
636 void
637 add_polyline_to_sort (BSP_TREE * bsp, POLYLINE_3D * polyline, void *attr)
639 BSP_POLYLINE_NODE *node = new_bsp_polyline_node (attr);
640 init_bsp_polyline (node, polyline);
641 node->next = *bsp;
642 *bsp = (BSP_NODE *) node;
645 // quicksort of linked list
646 #define FAR_DEPTH(Node) (-(Node)->extent->min[Z])
647 #define NEAR_DEPTH(Node) (-(Node)->extent->max[Z])
649 // leq provides ascending sort, so reverse to get max depth at head of list
650 #define LEQ(A,B) (FAR_DEPTH(A) >= FAR_DEPTH(B))
652 static void
653 qs (BSP_NODE * hd, BSP_NODE * tl, BSP_NODE ** rtn)
655 int nlo, nhi;
656 BSP_NODE *lo, *hi, *q, *p;
658 /* Invariant: Return head sorted with `tl' appended. */
659 while (hd != NULL)
662 nlo = nhi = 0;
663 lo = hi = NULL;
664 q = hd;
665 p = hd->next;
667 /* Reverse ascending prefix onto hi. This gives
668 O(n) behavior on sorted and reverse-sorted inputs. */
669 while (p != NULL && LEQ (p, hd))
671 hd->next = hi;
672 hi = hd;
673 ++nhi;
674 hd = p;
675 p = p->next;
678 /* If entire list was ascending, we're done. */
679 if (p == NULL)
681 *rtn = hd;
682 hd->next = hi;
683 q->next = tl;
684 return;
687 /* Partition and count sizes. */
688 while (p != NULL)
690 q = p->next;
691 if (LEQ (p, hd))
693 p->next = lo;
694 lo = p;
695 ++nlo;
697 else
699 p->next = hi;
700 hi = p;
701 ++nhi;
703 p = q;
706 /* Recur to establish invariant for sublists of hd,
707 choosing shortest list first to limit stack. */
708 if (nlo < nhi)
710 qs (lo, hd, rtn);
711 rtn = &hd->next;
712 hd = hi; /* Eliminated tail-recursive call. */
714 else
716 qs (hi, tl, &hd->next);
717 tl = hd;
718 hd = lo; /* Eliminated tail-recursive call. */
721 /* Base case of recurrence. Invariant is easy here. */
722 *rtn = tl;
725 static int
726 xy_intersect_p (BOX_3D * a, BOX_3D * b)
728 if (a->max[X] < b->min[X]) // a left of b
729 return 0;
730 if (a->min[X] > b->max[X]) // a right of b
731 return 0;
732 if (a->max[Y] < b->min[Y]) // a below b
733 return 0;
734 if (a->min[Y] > b->max[Y]) // a above b
735 return 0;
736 return 1;
739 #define SHORTEST_ALLOWABLE_SIDE 1e-4
741 static void
742 make_polygon_projection (POLYGON_2D * projection,
743 BSP_POLYGON_NODE * polygon_node)
745 int i, j;
747 clear_polygon_2d (projection);
748 if (polygon_node->plane->n[Z] >= 0)
750 for (i = 0, j = polygon_node->polygon->n_sides - 1;
751 i < polygon_node->polygon->n_sides; j = i++)
753 if (dist_2d
754 (polygon_node->polygon->v[i],
755 polygon_node->polygon->v[j]) > SHORTEST_ALLOWABLE_SIDE)
756 copy_pt_2d (pushed_polygon_2d_v (projection),
757 polygon_node->polygon->v[i]);
760 else
762 for (i = polygon_node->polygon->n_sides - 1, j = 0; i >= 0; j = i--)
764 if (dist_2d
765 (polygon_node->polygon->v[i],
766 polygon_node->polygon->v[j]) > SHORTEST_ALLOWABLE_SIDE)
767 copy_pt_2d (pushed_polygon_2d_v (projection),
768 polygon_node->polygon->v[i]);
773 #define OVERLAP_EPS 1e-3
776 projections_overlap_p (BSP_POLYGON_NODE * p, BSP_POLYGON_NODE * q)
778 int r;
779 POLYGON_2D p_projection[1], q_projection[1], cso[1];
781 init_polygon_2d (p_projection);
782 init_polygon_2d (q_projection);
783 init_polygon_2d (cso);
785 make_polygon_projection (p_projection, p);
786 make_polygon_projection (q_projection, q);
787 if (p_projection->n_sides < 2 && q_projection->n_sides < 2)
789 r = 0;
791 else if (p_projection->n_sides < 2)
793 r = point_near_convex_polygon_2d_p (p->polygon->v[0], q_projection,
794 OVERLAP_EPS);
796 else if (q_projection->n_sides < 2)
798 r = point_near_convex_polygon_2d_p (q->polygon->v[0], p_projection,
799 OVERLAP_EPS);
801 else
803 make_cso_polygon_2d (cso, p_projection, origin_2d, q_projection);
804 r = point_near_convex_polygon_2d_p (origin_2d, cso, OVERLAP_EPS);
807 clear_polygon_2d (p_projection);
808 clear_polygon_2d (q_projection);
809 clear_polygon_2d (cso);
810 return r;
813 #define OVERLAP_TOLERANCE 1e-3
816 polyline_projection_overlaps_polygon (BSP_POLYLINE_NODE * polyline_node,
817 BSP_POLYGON_NODE * polygon_node)
819 int i, r;
820 POLYGON_2D polygon_projection[1], line_seg_projection[1], cso[1];
822 init_polygon_2d (polygon_projection);
823 init_polygon_2d (line_seg_projection);
824 init_polygon_2d (cso);
826 make_polygon_projection (polygon_projection, polygon_node);
827 if (polygon_projection->n_sides < 2)
829 // a point can't obscure a line
830 r = 0;
832 else if (polyline_node->polyline->n_vertices == 1)
834 // polyline is single vertex; just check to see if it lies in projection
835 r = point_near_convex_polygon_2d_p (polyline_node->polyline->v[0],
836 polygon_projection,
837 OVERLAP_TOLERANCE);
839 else
842 // use a two-sided polygon to model each edge;
843 setup_polygon_2d (line_seg_projection, 2);
844 line_seg_projection->n_sides = 2;
845 r = 0;
846 for (i = 0; i < polyline_node->polyline->n_vertices - 1; i++)
848 copy_pt_2d (line_seg_projection->v[0],
849 polyline_node->polyline->v[i]);
850 copy_pt_2d (line_seg_projection->v[1],
851 polyline_node->polyline->v[i + 1]);
852 make_cso_polygon_2d (cso, line_seg_projection, origin_2d,
853 polygon_projection);
854 r |= point_near_convex_polygon_2d_p (origin_2d, cso,
855 OVERLAP_TOLERANCE);
856 if (r)
857 break;
860 clear_polygon_2d (polygon_projection);
861 clear_polygon_2d (line_seg_projection);
862 clear_polygon_2d (cso);
863 return r;
866 static void
867 debug_print (BSP_NODE * p)
869 fprintf (stderr, "\nlist:\n");
870 while (p)
872 fprintf (stderr, " %p:%sprev=%p near=%.4g far=%.4g\n",
874 p->mark ? "*" : " ", p->prev, NEAR_DEPTH (p), FAR_DEPTH (p));
875 p = p->next;
879 typedef struct make_list_of_bsp_env_t
881 BSP_NODE *head, *tail;
882 int n;
884 MAKE_LIST_OF_BSP_ENV;
886 static void
887 make_list_of_bsp (BSP_NODE * bsp, void *v_env)
889 MAKE_LIST_OF_BSP_ENV *env = (MAKE_LIST_OF_BSP_ENV *) v_env;
890 if (env->tail)
892 env->tail->next = bsp;
893 bsp->prev = env->tail;
894 bsp->next = NULL;
895 env->tail = bsp;
897 else
899 env->head = env->tail = bsp;
901 ++env->n;
904 // check invariants in the depth sort list
905 static void
906 check_consistency (BSP_TREE hd)
908 int n_marks, n_other;
909 BSP_NODE *p, *q;
911 n_marks = 0;
912 for (q = NULL, p = hd; p && p->mark; q = p, p = p->next)
914 n_marks++;
915 if (p->prev != q)
917 debug_print (hd);
918 die (no_line, "broken prev pointer @ %d (%p != %p)", n_marks,
919 p->prev, q);
921 if (p->extent->min[X] == 0 && p->extent->max[X] == 0 &&
922 p->extent->min[Y] == 0 && p->extent->max[Y] == 0 &&
923 p->extent->min[Z] == 0 && p->extent->max[Z] == 0)
924 die (no_line, "unset extent");
927 n_other = 0;
928 for (; p; q = p, p = p->next)
930 n_other++;
931 if (p->mark)
932 die (no_line, "unexpected mark");
933 if (p->prev != q)
935 debug_print (hd);
936 die (no_line, "broken prev pointer @ %d (%p != %p)",
937 n_marks + n_other, p->prev, q);
939 if (p->extent->min[X] > p->extent->max[X])
940 die (no_line, "unset extent");
941 if (q && !q->mark && FAR_DEPTH (p) > FAR_DEPTH (q))
943 debug_print (hd);
944 die (no_line, "far depth out of order @ %d", n_marks + n_other);
949 void
950 insert_by_depth (BSP_TREE * hd, BSP_NODE * node)
952 BSP_NODE *p, *q;
954 // place p after insert point and q before
955 for (q = NULL, p = *hd;
956 p && (p->mark || FAR_DEPTH (p) > FAR_DEPTH (node)); q = p, p = p->next)
957 /* skip */ ;
959 // insert
960 node->prev = q;
961 node->next = p;
962 if (q)
963 q->next = node;
964 else
965 *hd = node;
966 if (p)
967 p->prev = node;
970 // this is taken almost directly from Newell's 1972 paper except that
971 // a BSP is used to resolve intersections and cyclic overlaps and it
972 // incorporates polyline objects
973 void
974 sort_by_depth (BSP_TREE * bsp)
976 int side,
977 n_probes, n_swaps, n_nodes,
978 n_bsps, n_in, n_out, n_ppos, n_plos, n_bsp_in_nodes, n_bsp_out_nodes;
979 BSP_NODE *p, *p_next, *q, *prev, *t, *t_next, *r;
980 BSP_POLYGON_NODE *polygon_node;
981 BSP_POLYLINE_NODE *polyline_node;
982 PLANE *plane;
983 BSP_TREE sub_bsp;
984 MAKE_LIST_OF_BSP_ENV env[1];
986 // quicksort on deepest vertex, back-to-front
987 qs (*bsp, NULL, &p);
989 // hook up prev pointers and make sure marks are clear
990 n_nodes = 0;
991 for (prev = NULL, q = p; q; prev = q, q = q->next)
993 q->prev = prev;
994 q->mark = NULL;
995 ++n_nodes;
998 // keep some stats just for fun
999 n_probes = n_swaps = n_bsps = n_bsp_in_nodes = n_bsp_out_nodes =
1000 n_ppos = n_plos = 0;
1002 // debug_print(p);
1004 // this is now output list
1005 r = NULL;
1007 // goto here whenever the current check fails
1008 // for "p", the hopeful deepest polygon
1009 restart_overlap_check:
1011 while (p)
1014 if (n_nodes < 1000)
1015 check_consistency (p);
1017 // check overlapping objects for necessary swaps.
1018 for (q = p->next;
1019 q && (q->mark || FAR_DEPTH (q) > NEAR_DEPTH (p)); q = q->next)
1022 ++n_probes;
1024 // rectangular x-y extents don't overlap, so a moo point (utterly meaningless)
1025 if (!xy_intersect_p (p->extent, q->extent))
1026 continue;
1028 // two polylines don't matter
1029 // DEBUG: it really does if they're different colors
1030 if (p->tag == BSP_POLYLINE && q->tag == BSP_POLYLINE)
1031 continue;
1033 // two polygons
1034 if (p->tag == BSP_POLYGON && q->tag == BSP_POLYGON)
1037 // p is contained wholly in the back halfspace of q
1038 polygon_node = (BSP_POLYGON_NODE *) p;
1039 plane = ((BSP_POLYGON_NODE *) q)->plane;
1040 side = polygon_side_of_plane (polygon_node->polygon, plane);
1041 if (side == S_ON ||
1042 (plane->n[Z] >= 0 && side == S_IN) ||
1043 (plane->n[Z] <= 0 && side == S_OUT))
1044 continue;
1046 // q is contained wholly in the front halfspace of p
1047 polygon_node = (BSP_POLYGON_NODE *) q;
1048 plane = ((BSP_POLYGON_NODE *) p)->plane;
1049 side = polygon_side_of_plane (polygon_node->polygon, plane);
1050 if (side == S_ON ||
1051 (plane->n[Z] >= 0 && side == S_OUT) ||
1052 (plane->n[Z] <= 0 && side == S_IN))
1053 continue;
1055 // projections do not overlap
1056 ++n_ppos;
1057 if (!projections_overlap_p
1058 ((BSP_POLYGON_NODE *) p, (BSP_POLYGON_NODE *) q))
1059 continue;
1062 if (p->tag == BSP_POLYLINE)
1063 { // and q is a polygon
1064 polyline_node = (BSP_POLYLINE_NODE *) p;
1065 plane = ((BSP_POLYGON_NODE *) q)->plane;
1066 side = polyline_side_of_plane (polyline_node->polyline, plane);
1068 // line is contained wholly in the back halfspace of plane
1069 // lines lying on plane should be swapped so plane is drawn first
1070 if ((plane->n[Z] >= 0 && side == S_IN) ||
1071 (plane->n[Z] <= 0 && side == S_OUT))
1072 continue;
1074 // projections do not overlap
1075 ++n_plos;
1076 if (!polyline_projection_overlaps_polygon
1077 (polyline_node, (BSP_POLYGON_NODE *) q))
1078 continue;
1081 if (q->tag == BSP_POLYLINE)
1082 { // and p is a polygon
1083 polyline_node = (BSP_POLYLINE_NODE *) q;
1084 plane = ((BSP_POLYGON_NODE *) p)->plane;
1085 side = polyline_side_of_plane (polyline_node->polyline, plane);
1087 // line is on or contained wholly in the front halfspace of the plane
1088 // a line lying on the plane can stay where it is
1089 if (side == S_ON ||
1090 (plane->n[Z] >= 0 && side == S_OUT) ||
1091 (plane->n[Z] <= 0 && side == S_IN))
1092 continue;
1094 // projections do not overlap
1095 ++n_plos;
1096 if (!polyline_projection_overlaps_polygon
1097 (polyline_node, (BSP_POLYGON_NODE *) p))
1098 continue;
1101 if (q->mark)
1104 // we've discovered an intersection or cyclic overlap; break it by
1105 // putting all the marked nodes in a bsp, then pulling them
1106 // out and inserting them back on the list; remember our bsps
1107 // need all polygons inserted before all polylines
1109 ++n_bsps;
1110 sub_bsp = NULL;
1111 n_in = 0;
1112 t = NULL; // use t to hold polylines temporarily
1113 while (p && p->mark)
1115 p_next = p->next;
1117 if (p->tag == BSP_POLYGON)
1119 p->next = p->prev = NULL;
1120 insert_polygon (&sub_bsp, (BSP_POLYGON_NODE *) p);
1122 else
1123 { // save polyline temporarily
1124 p->next = t;
1125 t = p;
1127 ++n_in;
1128 p = p_next;
1129 if (p)
1130 p->prev = NULL;
1132 // insert the polylines now that all polygons are complete
1133 while (t)
1135 t_next = t->next;
1136 t->next = t->prev = NULL;
1137 insert_polyline (&sub_bsp, (BSP_POLYLINE_NODE *) t);
1138 t = t_next;
1141 // now traverse the bsp to get the objects back out, including split ones
1142 env->n = 0;
1143 env->head = env->tail = NULL;
1144 traverse_bsp (sub_bsp, make_list_of_bsp, env);
1145 n_out = env->n;
1147 // splitting should always increase the number of primitives, but
1148 // polygons very close in depth can cause split to fail; just shovel
1149 // the result polygons to the output with a warning.
1150 if (n_out <= n_in)
1152 warn (no_line, "split failed in=%d, out=%d", n_in, n_out);
1153 remark (no_line,
1154 "if hidden surfaces are wrong, try -b option");
1155 for (t = env->head; t; t = t_next)
1157 t_next = t->next;
1158 t->next = r;
1159 t->in = t->out = t->on = t->prev = t->mark = NULL;
1160 r = t;
1162 goto restart_overlap_check;
1164 // re-insert in the sorted list
1165 for (t = env->head; t; t = t_next)
1167 t_next = t->next;
1168 t->in = t->out = t->on = t->prev = t->next = t->mark = NULL;
1169 insert_by_depth (&p, t);
1172 n_bsp_in_nodes += n_in;
1173 n_bsp_out_nodes += n_out;
1175 goto restart_overlap_check;
1177 else
1180 // no overlap, so pull q forward to head of list
1182 // unlink q
1183 if (q->next)
1184 q->next->prev = q->prev;
1185 q->prev->next = q->next;
1187 // mark
1188 q->mark = p;
1190 // push
1191 q->prev = NULL;
1193 q->next = p;
1194 p->prev = q;
1195 p = q;
1197 ++n_swaps;
1199 goto restart_overlap_check;
1203 // overlap check saw no problems; pop head onto return list
1204 p_next = p->next;
1205 if (p_next)
1206 p_next->prev = NULL;
1208 // push on output
1209 p->next = r;
1210 p->prev = NULL;
1211 r = p;
1213 // move to next item
1214 p = p_next;
1216 // pop from q and push onto q until q is empty
1217 q = r;
1218 r = NULL;
1219 while (q)
1221 t = q;
1222 q = q->next; // pop
1223 t->next = r;
1224 r = t; // push
1228 int n_probes_possible = n_nodes + n_bsp_out_nodes - n_bsp_in_nodes;
1230 remark (no_line,
1231 "node=%d probe=%.1lf swap=%d split=%d (in=%d out=%d) ols=%d/%d",
1232 n_nodes,
1233 (n_probes_possible >
1234 0) ? (double) n_probes / n_probes_possible : 0.0, n_swaps,
1235 n_bsps, n_bsp_in_nodes, n_bsp_out_nodes, n_ppos, n_plos);
1238 *bsp = r;