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)
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 */
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
;
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
);
43 delete_bsp_polyline_node (BSP_POLYLINE_NODE
* node
)
45 clear_polyline_3d (node
->polyline
);
50 set_bsp_polyline_extent (BSP_POLYLINE_NODE
* node
)
53 init_box_3d (node
->extent
);
54 fold_min_max_polyline_3d (node
->extent
, node
->polyline
);
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
);
67 split_polyline_with_plane (BSP_POLYLINE_NODE
* node
,
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
;
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
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
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.
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
++)
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
;
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
;
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
;
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
]);
157 // copy last_p attribute from source
158 current
->last_p
= node
->last_p
;
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
;
176 current
= new_bsp_polyline_node (node
->attr
);
177 copy_pt_3d (pushed_polyline_3d_v (current
->polyline
),
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
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
]);
195 // finish the final polyline
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
;
210 insert_polyline (BSP_TREE
* bsp
, BSP_POLYLINE_NODE
* node
)
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
221 *bsp
= (BSP_NODE
*) node
;
223 insert_polyline ((BSP_TREE
*) & bsp_node
->in
, node
);
228 BSP_POLYGON_NODE
*bsp_node
= (BSP_POLYGON_NODE
*) * bsp
;
229 int side
= polyline_side_of_plane (node
->polyline
, bsp_node
->plane
);
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
);
238 BSP_POLYLINE_NODE
*in_polylines
, *on_polylines
, *out_polylines
,
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
;
247 insert_polyline (&bsp_node
->in
, p
);
249 for (p
= on_polylines
; p
; p
= p_next
)
251 p_next
= (BSP_POLYLINE_NODE
*) p
->in
;
253 insert_polyline (&bsp_node
->on
, p
);
255 for (p
= out_polylines
; p
; p
= p_next
)
257 p_next
= (BSP_POLYLINE_NODE
*) p
->in
;
259 insert_polyline (&bsp_node
->out
, p
);
261 delete_bsp_polyline_node (node
);
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
;
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
);
290 set_bsp_polygon_extent (BSP_POLYGON_NODE
* node
)
293 init_box_3d (node
->extent
);
294 fold_min_max_polygon_3d (node
->extent
, node
->polygon
);
298 init_bsp_polygon_node (BSP_POLYGON_NODE
* node
, POLYGON_3D
* polygon
)
302 // fill in the polygon verticies
303 copy_polygon_3d (node
->polygon
, polygon
);
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
);
319 delete_bsp_polygon_node (BSP_POLYGON_NODE
* node
)
321 clear_polygon_3d (node
->polygon
);
322 clear_polygon_attr (node
->polygon_attr
);
326 // decide whether a j->i edge of the the new polygon that has
327 // been split from parent is part of the border.
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
)
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;
357 decide_boundaries (BSP_POLYGON_NODE
* new_node
, BSP_POLYGON_NODE
* node
)
359 int i
, j
, last_border_p
;
362 j
= new_node
->polygon
->n_sides
- 1;
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
;
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
;
387 split_polygon_with_plane (BSP_POLYGON_NODE
* node
,
389 BSP_POLYGON_NODE
* in_node
,
390 BSP_POLYGON_NODE
* out_node
)
392 int i
, j
, i_side
, j_side
;
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
++)
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
);
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);
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);
457 // the new vertex is not straddling nor on the plane
458 // so we output it to the correct polygon
461 copy_pt_3d (pushed_polygon_3d_v (in_node
->polygon
),
462 node
->polygon
->v
[i
]);
463 push_polygon_attr (in_node
, i
, 0);
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
);
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
);
487 insert_polygon (BSP_TREE
* bsp
, BSP_POLYGON_NODE
* node
)
490 *bsp
= (BSP_NODE
*) node
;
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
);
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
);
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
);
527 walk_bsp (BSP_NODE
* bsp
)
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
);
544 traverse_closure
->func (bsp
, traverse_closure
->env
);
546 walk_bsp (node
->out
);
551 BSP_POLYLINE_NODE
*node
= (BSP_POLYLINE_NODE
*) bsp
;
552 traverse_closure
->func (bsp
, traverse_closure
->env
);
553 walk_bsp ((BSP_NODE
*) node
->in
);
558 traverse_bsp (BSP_NODE
* bsp
, BSP_NODE_FUNC func
, void *env
)
560 traverse_closure
->func
= func
;
561 traverse_closure
->env
= env
;
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
)
575 indent (FILE * f
, int n
)
582 print_bsp_internal (FILE * f
, BSP_NODE
* bsp
, int 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);
602 print_bsp_internal (f
, node
->in
, n
+ 1);
604 indent (f
, 2 * n
+ 1);
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);
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
);
622 print_bsp (FILE * f
, BSP_NODE
* bsp
)
624 print_bsp_internal (f
, bsp
, 0);
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
);
633 *bsp
= (BSP_NODE
*) node
;
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
);
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))
653 qs (BSP_NODE
* hd
, BSP_NODE
* tl
, BSP_NODE
** rtn
)
656 BSP_NODE
*lo
, *hi
, *q
, *p
;
658 /* Invariant: Return head sorted with `tl' appended. */
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
))
678 /* If entire list was ascending, we're done. */
687 /* Partition and count sizes. */
706 /* Recur to establish invariant for sublists of hd,
707 choosing shortest list first to limit stack. */
712 hd
= hi
; /* Eliminated tail-recursive call. */
716 qs (hi
, tl
, &hd
->next
);
718 hd
= lo
; /* Eliminated tail-recursive call. */
721 /* Base case of recurrence. Invariant is easy here. */
726 xy_intersect_p (BOX_3D
* a
, BOX_3D
* b
)
728 if (a
->max
[X
] < b
->min
[X
]) // a left of b
730 if (a
->min
[X
] > b
->max
[X
]) // a right of b
732 if (a
->max
[Y
] < b
->min
[Y
]) // a below b
734 if (a
->min
[Y
] > b
->max
[Y
]) // a above b
739 #define SHORTEST_ALLOWABLE_SIDE 1e-4
742 make_polygon_projection (POLYGON_2D
* projection
,
743 BSP_POLYGON_NODE
* polygon_node
)
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
++)
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
]);
762 for (i
= polygon_node
->polygon
->n_sides
- 1, j
= 0; i
>= 0; j
= i
--)
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
)
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)
791 else if (p_projection
->n_sides
< 2)
793 r
= point_near_convex_polygon_2d_p (p
->polygon
->v
[0], q_projection
,
796 else if (q_projection
->n_sides
< 2)
798 r
= point_near_convex_polygon_2d_p (q
->polygon
->v
[0], p_projection
,
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
);
813 #define OVERLAP_TOLERANCE 1e-3
816 polyline_projection_overlaps_polygon (BSP_POLYLINE_NODE
* polyline_node
,
817 BSP_POLYGON_NODE
* polygon_node
)
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
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],
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;
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
,
854 r
|= point_near_convex_polygon_2d_p (origin_2d
, cso
,
860 clear_polygon_2d (polygon_projection
);
861 clear_polygon_2d (line_seg_projection
);
862 clear_polygon_2d (cso
);
867 debug_print (BSP_NODE
* p
)
869 fprintf (stderr
, "\nlist:\n");
872 fprintf (stderr
, " %p:%sprev=%p near=%.4g far=%.4g\n",
874 p
->mark
? "*" : " ", p
->prev
, NEAR_DEPTH (p
), FAR_DEPTH (p
));
879 typedef struct make_list_of_bsp_env_t
881 BSP_NODE
*head
, *tail
;
884 MAKE_LIST_OF_BSP_ENV
;
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
;
892 env
->tail
->next
= bsp
;
893 bsp
->prev
= env
->tail
;
899 env
->head
= env
->tail
= bsp
;
904 // check invariants in the depth sort list
906 check_consistency (BSP_TREE hd
)
908 int n_marks
, n_other
;
912 for (q
= NULL
, p
= hd
; p
&& p
->mark
; q
= p
, p
= p
->next
)
918 die (no_line
, "broken prev pointer @ %d (%p != %p)", n_marks
,
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");
928 for (; p
; q
= p
, p
= p
->next
)
932 die (no_line
, "unexpected mark");
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
))
944 die (no_line
, "far depth out of order @ %d", n_marks
+ n_other
);
950 insert_by_depth (BSP_TREE
* hd
, BSP_NODE
* node
)
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
)
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
974 sort_by_depth (BSP_TREE
* bsp
)
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
;
984 MAKE_LIST_OF_BSP_ENV env
[1];
986 // quicksort on deepest vertex, back-to-front
989 // hook up prev pointers and make sure marks are clear
991 for (prev
= NULL
, q
= p
; q
; prev
= q
, q
= q
->next
)
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;
1004 // this is now output list
1007 // goto here whenever the current check fails
1008 // for "p", the hopeful deepest polygon
1009 restart_overlap_check
:
1015 check_consistency (p
);
1017 // check overlapping objects for necessary swaps.
1019 q
&& (q
->mark
|| FAR_DEPTH (q
) > NEAR_DEPTH (p
)); q
= q
->next
)
1024 // rectangular x-y extents don't overlap, so a moo point (utterly meaningless)
1025 if (!xy_intersect_p (p
->extent
, q
->extent
))
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
)
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
);
1042 (plane
->n
[Z
] >= 0 && side
== S_IN
) ||
1043 (plane
->n
[Z
] <= 0 && side
== S_OUT
))
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
);
1051 (plane
->n
[Z
] >= 0 && side
== S_OUT
) ||
1052 (plane
->n
[Z
] <= 0 && side
== S_IN
))
1055 // projections do not overlap
1057 if (!projections_overlap_p
1058 ((BSP_POLYGON_NODE
*) p
, (BSP_POLYGON_NODE
*) q
))
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
))
1074 // projections do not overlap
1076 if (!polyline_projection_overlaps_polygon
1077 (polyline_node
, (BSP_POLYGON_NODE
*) q
))
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
1090 (plane
->n
[Z
] >= 0 && side
== S_OUT
) ||
1091 (plane
->n
[Z
] <= 0 && side
== S_IN
))
1094 // projections do not overlap
1096 if (!polyline_projection_overlaps_polygon
1097 (polyline_node
, (BSP_POLYGON_NODE
*) p
))
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
1112 t
= NULL
; // use t to hold polylines temporarily
1113 while (p
&& p
->mark
)
1117 if (p
->tag
== BSP_POLYGON
)
1119 p
->next
= p
->prev
= NULL
;
1120 insert_polygon (&sub_bsp
, (BSP_POLYGON_NODE
*) p
);
1123 { // save polyline temporarily
1132 // insert the polylines now that all polygons are complete
1136 t
->next
= t
->prev
= NULL
;
1137 insert_polyline (&sub_bsp
, (BSP_POLYLINE_NODE
*) t
);
1141 // now traverse the bsp to get the objects back out, including split ones
1143 env
->head
= env
->tail
= NULL
;
1144 traverse_bsp (sub_bsp
, make_list_of_bsp
, env
);
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.
1152 warn (no_line
, "split failed in=%d, out=%d", n_in
, n_out
);
1154 "if hidden surfaces are wrong, try -b option");
1155 for (t
= env
->head
; t
; t
= t_next
)
1159 t
->in
= t
->out
= t
->on
= t
->prev
= t
->mark
= NULL
;
1162 goto restart_overlap_check
;
1164 // re-insert in the sorted list
1165 for (t
= env
->head
; t
; t
= 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
;
1180 // no overlap, so pull q forward to head of list
1184 q
->next
->prev
= q
->prev
;
1185 q
->prev
->next
= q
->next
;
1199 goto restart_overlap_check
;
1203 // overlap check saw no problems; pop head onto return list
1206 p_next
->prev
= NULL
;
1213 // move to next item
1216 // pop from q and push onto q until q is empty
1228 int n_probes_possible
= n_nodes
+ n_bsp_out_nodes
- n_bsp_in_nodes
;
1231 "node=%d probe=%.1lf swap=%d split=%d (in=%d out=%d) ols=%d/%d",
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
);