2017-04-26 17:20:15 +02:00
|
|
|
/*************************************************************************/
|
|
|
|
/* */
|
|
|
|
/* Copyright (c) 1994 Stanford University */
|
|
|
|
/* */
|
|
|
|
/* All rights reserved. */
|
|
|
|
/* */
|
|
|
|
/* Permission is given to use, copy, and modify this software for any */
|
|
|
|
/* non-commercial purpose as long as this copyright notice is not */
|
|
|
|
/* removed. All other uses, including redistribution in whole or in */
|
|
|
|
/* part, are forbidden without prior written permission. */
|
|
|
|
/* */
|
|
|
|
/* This software is provided with absolutely no warranty and no */
|
|
|
|
/* support. */
|
|
|
|
/* */
|
|
|
|
/*************************************************************************/
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
*
|
|
|
|
* Patch management.
|
|
|
|
*
|
|
|
|
* This module has the following functions:
|
|
|
|
* (1) Create/initialize a new instance of the patch object.
|
|
|
|
* (2) Management of BSP tree (insertion,traversal)
|
|
|
|
*
|
|
|
|
*************************************************************************/
|
|
|
|
|
2017-04-26 18:03:02 +02:00
|
|
|
#include <stdio.h>
|
2017-04-26 17:20:15 +02:00
|
|
|
|
|
|
|
EXTERN_ENV;
|
|
|
|
|
|
|
|
include(radiosity.h)
|
|
|
|
|
|
|
|
static void _foreach_patch(Patch *node, void (*func)(), long arg1, long process_id);
|
|
|
|
static void _foreach_d_s_patch(Vertex *svec, Patch *node, void (*func)(), long arg1, long process_id);
|
|
|
|
static void split_into_3(Patch *patch, ElemVertex *ev1, ElemVertex *ev2, ElemVertex *ev3, Edge *e12, Edge *e23, Edge *e31, Patch *parent, long process_id);
|
|
|
|
static void split_into_2(Patch *patch, ElemVertex *ev1, ElemVertex *ev2, ElemVertex *ev3, Edge *e12, Edge *e23, Edge *e31, Patch *parent, long process_id);
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
****************************************************************************
|
|
|
|
*
|
|
|
|
* Methods of Patch object
|
|
|
|
*
|
|
|
|
****************************************************************************
|
|
|
|
****************************************************************************
|
|
|
|
****************************************************************************
|
|
|
|
*
|
|
|
|
* foreach_patch_in_bsp()
|
|
|
|
*
|
|
|
|
* General purpose driver. For each patch in the BSP tree, apply specified
|
|
|
|
* function. The function is passed a pointer to the patch.
|
|
|
|
* Traversal is in-order, that is, subtree(-) -> node -> subtree(+).
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
void foreach_patch_in_bsp(void (*func)(), long arg1, long process_id)
|
|
|
|
{
|
|
|
|
_foreach_patch( global->bsp_root, func, arg1, process_id ) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void _foreach_patch(Patch *node, void (*func)(), long arg1, long process_id)
|
|
|
|
{
|
2017-04-26 18:03:02 +02:00
|
|
|
if( node == 0 )
|
2017-04-26 17:20:15 +02:00
|
|
|
return ;
|
|
|
|
|
|
|
|
/* Process subtree(-) */
|
2017-04-26 18:03:02 +02:00
|
|
|
if( node->bsp_negative )
|
2017-04-26 17:20:15 +02:00
|
|
|
_foreach_patch( node->bsp_negative, func, arg1, process_id ) ;
|
|
|
|
|
|
|
|
/* Apply function to this node */
|
|
|
|
func( node, arg1, process_id ) ;
|
|
|
|
|
|
|
|
/* Process subtree(+) */
|
2017-04-26 18:03:02 +02:00
|
|
|
if( node->bsp_positive )
|
2017-04-26 17:20:15 +02:00
|
|
|
_foreach_patch( node->bsp_positive, func, arg1, process_id ) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
*
|
|
|
|
* foreach_depth_sorted_patch()
|
|
|
|
*
|
|
|
|
* For each patch in the BSP tree, apply specified function. In the depth
|
|
|
|
* sorted order along the given vector (from tail to arrow head of the
|
|
|
|
* vector).
|
|
|
|
* The function is passed a pointer to the patch.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
void foreach_depth_sorted_patch(Vertex *sort_vec, void (*func)(), long arg1, long process_id)
|
|
|
|
{
|
|
|
|
_foreach_d_s_patch( sort_vec, global->bsp_root, func, arg1, process_id ) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void _foreach_d_s_patch(Vertex *svec, Patch *node, void (*func)(), long arg1, long process_id)
|
|
|
|
{
|
|
|
|
float sign ;
|
|
|
|
|
2017-04-26 18:03:02 +02:00
|
|
|
if( node == 0 )
|
2017-04-26 17:20:15 +02:00
|
|
|
return ;
|
|
|
|
|
|
|
|
/* Compute inner product */
|
|
|
|
sign = inner_product( svec, &node->plane_equ.n ) ;
|
|
|
|
|
2017-04-26 18:03:02 +02:00
|
|
|
if( sign >= 0.0 )
|
2017-04-26 17:20:15 +02:00
|
|
|
{
|
|
|
|
/* The vector is approaching from the negative side of the patch */
|
|
|
|
|
|
|
|
/* Process subtree(-) */
|
2017-04-26 18:03:02 +02:00
|
|
|
if( node->bsp_negative )
|
2017-04-26 17:20:15 +02:00
|
|
|
_foreach_d_s_patch( svec, node->bsp_negative, func, arg1, process_id ) ;
|
|
|
|
|
|
|
|
/* Apply function to this node */
|
|
|
|
func( node, arg1, process_id ) ;
|
|
|
|
|
|
|
|
/* Process subtree(+) */
|
2017-04-26 18:03:02 +02:00
|
|
|
if( node->bsp_positive )
|
2017-04-26 17:20:15 +02:00
|
|
|
_foreach_d_s_patch( svec, node->bsp_positive, func, arg1, process_id ) ;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Process subtree(+) */
|
2017-04-26 18:03:02 +02:00
|
|
|
if( node->bsp_positive )
|
2017-04-26 17:20:15 +02:00
|
|
|
_foreach_d_s_patch( svec, node->bsp_positive, func, arg1, process_id ) ;
|
|
|
|
|
|
|
|
/* Apply function to this node */
|
|
|
|
func( node, arg1, process_id ) ;
|
|
|
|
|
|
|
|
/* Process subtree(-) */
|
2017-04-26 18:03:02 +02:00
|
|
|
if( node->bsp_negative )
|
2017-04-26 17:20:15 +02:00
|
|
|
_foreach_d_s_patch( svec, node->bsp_negative, func, arg1, process_id ) ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
*
|
|
|
|
* define_patch()
|
|
|
|
*
|
|
|
|
* Insert a new patch in the BSP tree and put refinement task in the queue.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
void define_patch(Patch *patch, Patch *root, long process_id)
|
|
|
|
{
|
|
|
|
Patch *parent = root ;
|
|
|
|
long xing_code ;
|
|
|
|
|
|
|
|
/* Lock the BSP tree */
|
|
|
|
LOCK(global->bsp_tree_lock);
|
|
|
|
|
|
|
|
/* If this is the first patch, link directly */
|
2017-04-26 18:03:02 +02:00
|
|
|
if( parent == 0 )
|
2017-04-26 17:20:15 +02:00
|
|
|
{
|
2017-04-26 18:03:02 +02:00
|
|
|
if( global->bsp_root == 0 )
|
2017-04-26 17:20:15 +02:00
|
|
|
{
|
|
|
|
/* This is really the first patch */
|
|
|
|
global->bsp_root = patch ;
|
|
|
|
patch->bsp_positive = 0 ;
|
|
|
|
patch->bsp_negative = 0 ;
|
|
|
|
patch->bsp_parent = 0 ;
|
|
|
|
attach_element( patch, process_id ) ;
|
|
|
|
UNLOCK(global->bsp_tree_lock);
|
|
|
|
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
/* Race condition. The root was NULL when the task was
|
|
|
|
created */
|
|
|
|
parent = global->bsp_root ;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Traverse the BSP tree and get to the leaf node */
|
2017-04-26 18:03:02 +02:00
|
|
|
while( 1 )
|
2017-04-26 17:20:15 +02:00
|
|
|
{
|
|
|
|
/* Check the sign */
|
|
|
|
xing_code = patch_intersection( &parent->plane_equ, &patch->p1,
|
|
|
|
&patch->p2, &patch->p3, process_id ) ;
|
|
|
|
|
|
|
|
/* Traverse down the tree according to the sign */
|
2017-04-26 18:03:02 +02:00
|
|
|
if( POSITIVE_SIDE( xing_code ) )
|
2017-04-26 17:20:15 +02:00
|
|
|
{
|
2017-04-26 18:03:02 +02:00
|
|
|
if( parent->bsp_positive == 0 )
|
2017-04-26 17:20:15 +02:00
|
|
|
{
|
|
|
|
/* Insert the patch */
|
|
|
|
parent->bsp_positive = patch ;
|
|
|
|
patch->bsp_parent = parent ;
|
|
|
|
attach_element( patch, process_id ) ;
|
|
|
|
UNLOCK(global->bsp_tree_lock);
|
|
|
|
|
|
|
|
foreach_patch_in_bsp( refine_newpatch, (long)patch, process_id ) ;
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
/* Traverse down to the subtree(+) */
|
|
|
|
parent = parent->bsp_positive ;
|
|
|
|
}
|
2017-04-26 18:03:02 +02:00
|
|
|
else if( NEGATIVE_SIDE( xing_code ) )
|
2017-04-26 17:20:15 +02:00
|
|
|
{
|
2017-04-26 18:03:02 +02:00
|
|
|
if( parent->bsp_negative == 0 )
|
2017-04-26 17:20:15 +02:00
|
|
|
{
|
|
|
|
/* Insert the patch */
|
|
|
|
parent->bsp_negative = patch ;
|
|
|
|
patch->bsp_parent = parent ;
|
|
|
|
attach_element( patch, process_id ) ;
|
|
|
|
UNLOCK(global->bsp_tree_lock);
|
|
|
|
|
|
|
|
foreach_patch_in_bsp( refine_newpatch, (long)patch, process_id ) ;
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
/* Traverse down to the subtree(-) */
|
|
|
|
parent = parent->bsp_negative ;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* The patch must be split. Insertion is taken care of by
|
|
|
|
split_patch(). */
|
|
|
|
UNLOCK(global->bsp_tree_lock);
|
|
|
|
split_patch( patch, parent, xing_code, process_id ) ;
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
*
|
|
|
|
* split_patch()
|
|
|
|
* split_into_3()
|
|
|
|
* split_into_2()
|
|
|
|
*
|
|
|
|
* Split a patch and insert in the BSP tree.
|
|
|
|
* split_into_3() Split a patch into 3 patches. The routine assumes both
|
|
|
|
* P1-P2 and P1-P3 intersect the plane.
|
|
|
|
* split_into_2() Split a patch into 2 patches. The routine assuems P1 is
|
|
|
|
* on the plane and P2-P3 intersects the plane.
|
|
|
|
* split_patch() Classify intersection type, rename vertices, and
|
|
|
|
* call split_into_X().
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
void split_patch(Patch *patch, Patch *node, long xing_code, long process_id)
|
|
|
|
{
|
|
|
|
long c1, c2, c3 ;
|
|
|
|
|
|
|
|
|
|
|
|
c1 = P1_CODE( xing_code ) ;
|
|
|
|
c2 = P2_CODE( xing_code ) ;
|
|
|
|
c3 = P3_CODE( xing_code ) ;
|
|
|
|
|
|
|
|
/* Classify intersection type */
|
2017-04-26 18:03:02 +02:00
|
|
|
if( c1 == c2 )
|
2017-04-26 17:20:15 +02:00
|
|
|
/* P3 is on the oposite side */
|
|
|
|
split_into_3( patch, patch->ev3, patch->ev1, patch->ev2,
|
|
|
|
patch->e31, patch->e12, patch->e23, node, process_id) ;
|
2017-04-26 18:03:02 +02:00
|
|
|
else if( c1 == c3 )
|
2017-04-26 17:20:15 +02:00
|
|
|
/* P2 is on the oposite side */
|
|
|
|
split_into_3( patch, patch->ev2, patch->ev3, patch->ev1,
|
|
|
|
patch->e23, patch->e31, patch->e12, node, process_id ) ;
|
2017-04-26 18:03:02 +02:00
|
|
|
else if( c2 == c3 )
|
2017-04-26 17:20:15 +02:00
|
|
|
/* P1 is on the oposite side */
|
|
|
|
split_into_3( patch, patch->ev1, patch->ev2, patch->ev3,
|
|
|
|
patch->e12, patch->e23, patch->e31, node, process_id ) ;
|
2017-04-26 18:03:02 +02:00
|
|
|
else if( c1 == POINT_ON_PLANE )
|
2017-04-26 17:20:15 +02:00
|
|
|
/* P1 is on the plane. P2 and P3 are on the oposite side */
|
|
|
|
split_into_2( patch, patch->ev1, patch->ev2, patch->ev3,
|
|
|
|
patch->e12, patch->e23, patch->e31, node, process_id ) ;
|
2017-04-26 18:03:02 +02:00
|
|
|
else if( c2 == POINT_ON_PLANE )
|
2017-04-26 17:20:15 +02:00
|
|
|
/* P2 is on the plane. P3 and P1 are on the oposite side */
|
|
|
|
split_into_2( patch, patch->ev2, patch->ev3, patch->ev1,
|
|
|
|
patch->e23, patch->e31, patch->e12, node, process_id ) ;
|
|
|
|
else
|
|
|
|
/* P3 is on the plane. P1 and P2 are on the oposite side */
|
|
|
|
split_into_2( patch, patch->ev3, patch->ev1, patch->ev2,
|
|
|
|
patch->e31, patch->e12, patch->e23, node, process_id ) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void split_into_3(Patch *patch, ElemVertex *ev1, ElemVertex *ev2, ElemVertex *ev3, Edge *e12, Edge *e23, Edge *e31, Patch *parent, long process_id)
|
|
|
|
{
|
|
|
|
ElemVertex *ev_a ; /* Intersection of P1-P2 & the patch */
|
|
|
|
ElemVertex *ev_b ; /* Intersection of P1-P3 & the patch */
|
|
|
|
float h1, h2, h3 ;
|
|
|
|
float u2, u3 ;
|
|
|
|
Patch *new ;
|
|
|
|
Edge *e_ab, *e_3a ;
|
|
|
|
long rev_e12, rev_e31 ;
|
|
|
|
|
|
|
|
|
|
|
|
/* Compute intersection in terms of parametarized distance from P1 */
|
|
|
|
h1 = plane_equ( &parent->plane_equ, &ev1->p, process_id ) ;
|
|
|
|
h2 = plane_equ( &parent->plane_equ, &ev2->p, process_id ) ;
|
|
|
|
h3 = plane_equ( &parent->plane_equ, &ev3->p, process_id ) ;
|
|
|
|
|
|
|
|
/* NOTE: Length of P1-P2 and P1-P3 are at least 2*F_COPLANAR.
|
|
|
|
So, no check is necessary before division */
|
|
|
|
u2 = h1 / (h1 - h2) ;
|
2017-04-26 18:03:02 +02:00
|
|
|
if( (rev_e12 = EDGE_REVERSE( e12, ev1, ev2 )) )
|
2017-04-26 17:20:15 +02:00
|
|
|
subdivide_edge( e12, u2, process_id ) ;
|
|
|
|
else
|
|
|
|
subdivide_edge( e12, (float)1.0 - u2, process_id ) ;
|
|
|
|
ev_a = e12->ea->pb ;
|
|
|
|
|
|
|
|
u3 = h1 / (h1 - h3) ;
|
2017-04-26 18:03:02 +02:00
|
|
|
if( (rev_e31 = EDGE_REVERSE( e31, ev3, ev1 )) )
|
2017-04-26 17:20:15 +02:00
|
|
|
subdivide_edge( e31, (float)1.0 - u3, process_id ) ;
|
|
|
|
else
|
|
|
|
subdivide_edge( e31, u3, process_id ) ;
|
|
|
|
ev_b = e31->ea->pb ;
|
|
|
|
|
|
|
|
/* Now insert patches in the tree */
|
|
|
|
|
|
|
|
/* (1) Put P1-Pa-Pb */
|
|
|
|
new = get_patch(process_id) ;
|
|
|
|
new->p1 = ev1->p ;
|
|
|
|
new->p2 = ev_a->p ;
|
|
|
|
new->p3 = ev_b->p ;
|
|
|
|
|
|
|
|
new->ev1 = ev1 ;
|
|
|
|
new->ev2 = e12->ea->pb ;
|
|
|
|
new->ev3 = e31->ea->pb ;
|
|
|
|
|
|
|
|
new->e12 = (!rev_e12)? e12->ea : e12->eb ;
|
|
|
|
new->e23 = e_ab = create_edge(ev_a, ev_b, process_id ) ;
|
|
|
|
new->e31 = (!rev_e31)? e31->eb : e31->ea ;
|
|
|
|
|
|
|
|
new->plane_equ = patch->plane_equ ;
|
|
|
|
new->area = u2 * u3 * patch->area ;
|
|
|
|
new->color = patch->color ;
|
|
|
|
new->emittance = patch->emittance ;
|
|
|
|
define_patch( new, parent, process_id ) ;
|
|
|
|
|
|
|
|
/* (2) Put Pa-P2-P3 */
|
|
|
|
new = get_patch(process_id) ;
|
|
|
|
new->p1 = ev_a->p ;
|
|
|
|
new->p2 = ev2->p ;
|
|
|
|
new->p3 = ev3->p ;
|
|
|
|
|
|
|
|
new->ev1 = ev_a ;
|
|
|
|
new->ev2 = ev2 ;
|
|
|
|
new->ev3 = ev3 ;
|
|
|
|
|
|
|
|
new->e12 = (!rev_e12)? e12->eb : e12->ea ;
|
|
|
|
new->e23 = e23 ;
|
|
|
|
new->e31 = e_3a = create_edge( ev3, ev_a, process_id ) ;
|
|
|
|
|
|
|
|
new->plane_equ = patch->plane_equ ;
|
|
|
|
new->area = (1.0 - u2) * patch->area ;
|
|
|
|
new->color = patch->color ;
|
|
|
|
new->emittance = patch->emittance ;
|
|
|
|
define_patch( new, parent, process_id ) ;
|
|
|
|
|
|
|
|
/* (3) Put Pa-P3-Pb. Reuse the original patch */
|
|
|
|
patch->p1 = ev_a->p ;
|
|
|
|
patch->p2 = ev3->p ;
|
|
|
|
patch->p3 = ev_b->p ;
|
|
|
|
|
|
|
|
patch->ev1 = ev_a ;
|
|
|
|
patch->ev2 = ev3 ;
|
|
|
|
patch->ev3 = ev_b ;
|
|
|
|
|
|
|
|
patch->e12 = e_3a ;
|
|
|
|
patch->e23 = (!rev_e31)? e31->ea : e31->eb ;
|
|
|
|
patch->e31 = e_ab ;
|
|
|
|
|
|
|
|
patch->area = u2 * (1.0 - u3) * patch->area ;
|
|
|
|
define_patch( patch, parent, process_id ) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void split_into_2(Patch *patch, ElemVertex *ev1, ElemVertex *ev2, ElemVertex *ev3, Edge *e12, Edge *e23, Edge *e31, Patch *parent, long process_id)
|
|
|
|
{
|
|
|
|
ElemVertex *ev_a ;
|
|
|
|
Edge *e_a1 ;
|
|
|
|
float h2, h3 ;
|
|
|
|
float u2 ;
|
|
|
|
Patch *new ;
|
|
|
|
long rev_e23 ;
|
|
|
|
|
|
|
|
/* Compute intersection in terms of parameterized distance from P2 */
|
|
|
|
h2 = plane_equ( &parent->plane_equ, &ev2->p, process_id ) ;
|
|
|
|
h3 = plane_equ( &parent->plane_equ, &ev3->p, process_id ) ;
|
|
|
|
|
|
|
|
/* NOTE: Length of P2-P3 is at least 2*F_COPLANAR.
|
|
|
|
So, no check is necessary before division */
|
|
|
|
u2 = h2 / (h2 - h3) ;
|
2017-04-26 18:03:02 +02:00
|
|
|
if( (rev_e23 = EDGE_REVERSE( e23, ev2, ev3 )) )
|
2017-04-26 17:20:15 +02:00
|
|
|
subdivide_edge( e23, u2, process_id ) ;
|
|
|
|
else
|
|
|
|
subdivide_edge( e23, (float)1.0 - u2, process_id ) ;
|
|
|
|
ev_a = e23->ea->pb ;
|
|
|
|
|
|
|
|
|
|
|
|
/* Now put patches in the tree */
|
|
|
|
|
|
|
|
/* (1) Put P1-P2-Pa */
|
|
|
|
new = get_patch(process_id) ;
|
|
|
|
|
|
|
|
new->p1 = ev1->p ;
|
|
|
|
new->p2 = ev2->p ;
|
|
|
|
new->p3 = ev_a->p ;
|
|
|
|
|
|
|
|
new->ev1 = ev1 ;
|
|
|
|
new->ev2 = ev2 ;
|
|
|
|
new->ev3 = ev_a ;
|
|
|
|
|
|
|
|
new->e12 = e12 ;
|
|
|
|
new->e23 = (!rev_e23)? e23->ea : e23->eb ;
|
|
|
|
new->e31 = e_a1 = create_edge( ev_a, ev1, process_id ) ;
|
|
|
|
|
|
|
|
new->plane_equ = patch->plane_equ ;
|
|
|
|
new->area = u2 * patch->area ;
|
|
|
|
new->color = patch->color ;
|
|
|
|
new->emittance = patch->emittance ;
|
|
|
|
define_patch( new, parent, process_id ) ;
|
|
|
|
|
|
|
|
/* (2) Put P1-Pa-P3. Reuse the original patch */
|
|
|
|
patch->p1 = ev1->p ;
|
|
|
|
patch->p2 = ev_a->p ;
|
|
|
|
patch->p3 = ev3->p ;
|
|
|
|
|
|
|
|
patch->ev1 = ev1 ;
|
|
|
|
patch->ev2 = ev_a ;
|
|
|
|
patch->ev3 = ev3 ;
|
|
|
|
|
|
|
|
patch->e12 = e_a1 ;
|
|
|
|
patch->e23 = (!rev_e23)? e23->eb : e23->ea ;
|
|
|
|
patch->e31 = e31 ;
|
|
|
|
|
|
|
|
patch->area = (1.0 - u2) * patch->area ;
|
|
|
|
define_patch( patch, parent, process_id ) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
*
|
|
|
|
* attach_element()
|
|
|
|
*
|
|
|
|
* Attach an element to the patch. This element becomes the
|
|
|
|
* root of the quad tree.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
void attach_element(Patch *patch, long process_id)
|
|
|
|
{
|
|
|
|
Element *pelem ;
|
|
|
|
|
|
|
|
/* Create and link an element to the patch */
|
|
|
|
pelem = get_element(process_id) ;
|
|
|
|
patch->el_root = pelem ;
|
|
|
|
|
|
|
|
/* Initialization of the element */
|
|
|
|
pelem->patch = patch ;
|
|
|
|
pelem->ev1 = patch->ev1 ;
|
|
|
|
pelem->ev2 = patch->ev2 ;
|
|
|
|
pelem->ev3 = patch->ev3 ;
|
|
|
|
|
|
|
|
pelem->e12 = patch->e12 ;
|
|
|
|
pelem->e23 = patch->e23 ;
|
|
|
|
pelem->e31 = patch->e31 ;
|
|
|
|
|
|
|
|
pelem->area = patch->area ;
|
|
|
|
pelem->rad = patch->emittance ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
*
|
|
|
|
* refine_newpatch()
|
|
|
|
*
|
|
|
|
* Recursively subdivide
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
void refine_newpatch(Patch *patch, long newpatch, long process_id)
|
|
|
|
{
|
|
|
|
long cc ;
|
|
|
|
Patch *new_patch = (Patch *)newpatch ;
|
|
|
|
|
|
|
|
/* Check sequence number */
|
2017-04-26 18:03:02 +02:00
|
|
|
if( patch->seq_no >= new_patch->seq_no )
|
2017-04-26 17:20:15 +02:00
|
|
|
/* Racing condition due to multiprocessing */
|
|
|
|
return ;
|
|
|
|
|
|
|
|
/* Check visibility */
|
|
|
|
cc = patch_intersection( &patch->plane_equ,
|
|
|
|
&new_patch->p1, &new_patch->p2, &new_patch->p3, process_id ) ;
|
2017-04-26 18:03:02 +02:00
|
|
|
if( NEGATIVE_SIDE(cc) )
|
2017-04-26 17:20:15 +02:00
|
|
|
/* If negative or on the plane, then do nothing */
|
|
|
|
return ;
|
|
|
|
|
|
|
|
cc = patch_intersection( &new_patch->plane_equ,
|
|
|
|
&patch->p1, &patch->p2, &patch->p3, process_id ) ;
|
2017-04-26 18:03:02 +02:00
|
|
|
if( NEGATIVE_SIDE(cc) )
|
2017-04-26 17:20:15 +02:00
|
|
|
/* If negative or on the plane, then do nothing */
|
|
|
|
return ;
|
|
|
|
|
|
|
|
/* Create a new task or do it by itself */
|
|
|
|
create_ff_refine_task( patch->el_root, new_patch->el_root, 0, process_id ) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
*
|
|
|
|
* get_patch()
|
|
|
|
*
|
|
|
|
* Returns a new instance of the Patch object.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
Patch *get_patch(long process_id)
|
|
|
|
{
|
|
|
|
Patch *p ;
|
|
|
|
|
|
|
|
/* LOCK the free list */
|
|
|
|
LOCK(global->free_patch_lock);
|
|
|
|
|
|
|
|
/* Test pointer */
|
2017-04-26 18:03:02 +02:00
|
|
|
if( global->free_patch == 0 )
|
2017-04-26 17:20:15 +02:00
|
|
|
{
|
|
|
|
printf( "Fatal: Ran out of patch buffer\n" ) ;
|
|
|
|
UNLOCK(global->free_patch_lock);
|
|
|
|
exit( 1 ) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get a patch data structure */
|
|
|
|
p = global->free_patch ;
|
|
|
|
global->free_patch = p->bsp_positive ;
|
|
|
|
global->n_total_patches++ ;
|
|
|
|
global->n_free_patches-- ;
|
|
|
|
|
|
|
|
/* Unlock the list */
|
|
|
|
UNLOCK(global->free_patch_lock);
|
|
|
|
|
|
|
|
/* Clear pointers just in case.. */
|
|
|
|
p->el_root = 0 ;
|
|
|
|
p->bsp_positive = 0 ;
|
|
|
|
p->bsp_negative = 0 ;
|
|
|
|
p->bsp_parent = 0 ;
|
|
|
|
|
|
|
|
return( p ) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
*
|
|
|
|
* init_patchlist()
|
|
|
|
*
|
|
|
|
* Initialize patch free list.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
void init_patchlist(long process_id)
|
|
|
|
{
|
|
|
|
long i ;
|
|
|
|
|
|
|
|
/* Initialize Patch free list */
|
2017-04-26 18:03:02 +02:00
|
|
|
for( i = 0 ; i < MAX_PATCHES-1 ; i++ )
|
2017-04-26 17:20:15 +02:00
|
|
|
{
|
|
|
|
global->patch_buf[i].bsp_positive = &global->patch_buf[i+1] ;
|
|
|
|
global->patch_buf[i].seq_no = i ;
|
|
|
|
}
|
|
|
|
global->patch_buf[ MAX_PATCHES-1 ].bsp_positive = 0 ;
|
|
|
|
global->patch_buf[ MAX_PATCHES-1 ].seq_no = MAX_PATCHES - 1 ;
|
|
|
|
|
|
|
|
global->free_patch = global->patch_buf ;
|
|
|
|
global->n_total_patches = 0 ;
|
|
|
|
global->n_free_patches = MAX_PATCHES ;
|
|
|
|
LOCKINIT(global->free_patch_lock) ;
|
|
|
|
|
|
|
|
#if PATCH_ASSIGNMENT == PATCH_ASSIGNMENT_COSTBASED
|
|
|
|
/* Initialize Patch_Cost structure */
|
2017-04-26 18:03:02 +02:00
|
|
|
for( i = 0 ; i < MAX_PATCHES ; i++ )
|
2017-04-26 17:20:15 +02:00
|
|
|
{
|
|
|
|
global->patch_cost[i].patch = &global->patch_buf[i] ;
|
|
|
|
global->patch_cost[i].cost_lock
|
|
|
|
= get_sharedlock( SHARED_LOCK_SEGANY, process_id ) ;
|
|
|
|
global->patch_cost[i].n_bsp_node = 0 ;
|
|
|
|
global->patch_cost[i].n_total_inter = 0 ;
|
|
|
|
global->patch_cost[i].cost_estimate = 0 ;
|
|
|
|
global->patch_cost[i].cost_history[0] = 0 ;
|
|
|
|
global->patch_cost[i].cost_history[1] = 0 ;
|
|
|
|
global->patch_cost[i].cost_history[2] = 0 ;
|
|
|
|
global->patch_cost[i].cost_history[3] = 0 ;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
*
|
|
|
|
* print_patch()
|
|
|
|
*
|
|
|
|
* Print patch information.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
void print_patch(Patch *patch, long process_id)
|
|
|
|
{
|
|
|
|
printf( "Patch (%ld)\n", (long)patch ) ;
|
|
|
|
print_point( &patch->p1 ) ;
|
|
|
|
print_point( &patch->p2 ) ;
|
|
|
|
print_point( &patch->p3 ) ;
|
|
|
|
print_plane_equ( &patch->plane_equ, process_id ) ;
|
|
|
|
printf( "\tArea %f\n", patch->area ) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
*
|
|
|
|
* print_bsp_tree()
|
|
|
|
*
|
|
|
|
* Print BSP tree
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
void print_bsp_tree(long process_id)
|
|
|
|
{
|
|
|
|
printf( "**** BSP TREE ***\n" ) ;
|
|
|
|
foreach_patch_in_bsp( _pr_patch, 0, process_id ) ;
|
|
|
|
printf( "\n\n" ) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
void _pr_patch(Patch *patch, long dummy, long process_id)
|
|
|
|
{
|
|
|
|
print_patch( patch, process_id ) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
****************************************************************************
|
|
|
|
*
|
|
|
|
* Methods for PlaneEqu object
|
|
|
|
*
|
|
|
|
****************************************************************************
|
|
|
|
****************************************************************************
|
|
|
|
****************************************************************************
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* plane_equ()
|
|
|
|
*
|
|
|
|
* Returns the value H(Px, Py, Pz) where H is the equation of the plane
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
float plane_equ(PlaneEqu *plane, Vertex *point, long process_id)
|
|
|
|
{
|
|
|
|
float h ;
|
|
|
|
h = plane->c + point->x * plane->n.x
|
|
|
|
+ point->y * plane->n.y
|
|
|
|
+ point->z * plane->n.z ;
|
|
|
|
|
|
|
|
return( h ) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
*
|
|
|
|
* comp_plane_equ()
|
|
|
|
*
|
|
|
|
* Compute plane equation from the three vertices on the plane.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
float comp_plane_equ(PlaneEqu *pln, Vertex *p1, Vertex *p2, Vertex *p3, long process_id)
|
|
|
|
{
|
|
|
|
float length ;
|
|
|
|
|
|
|
|
/* Compute normal vector */
|
|
|
|
length = plane_normal( &pln->n, p1, p2, p3 ) ;
|
|
|
|
|
|
|
|
/* Calculate constant factor */
|
|
|
|
pln->c = -inner_product( &pln->n, p1 ) ;
|
|
|
|
|
|
|
|
return( length ) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
*
|
|
|
|
* point_intersection()
|
|
|
|
* patch_intersection()
|
|
|
|
*
|
|
|
|
* Returns the intersection code according to the relationship between the
|
|
|
|
* point/patch and the plane.
|
|
|
|
* point_intersection() returns 2 bits code that represents:
|
|
|
|
* 01: Point is on the positive side (H(x,y,z) > 0)
|
|
|
|
* 10: Point is on the negative side (H(x,y,z) < 0)
|
|
|
|
* 00: Point is on the plane (H(x,y,z) = 0)
|
|
|
|
*
|
|
|
|
* patch_intersection() returns 3 sets of 2 bits code each represents the
|
|
|
|
* relationship of each vertex of the triangle patch.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
long point_intersection(PlaneEqu *plane, Vertex *point, long process_id)
|
|
|
|
{
|
|
|
|
float h ;
|
|
|
|
long result_code = 0 ;
|
|
|
|
|
|
|
|
/* Compare H(x,y,z) against allowance */
|
2017-04-26 18:03:02 +02:00
|
|
|
if( (h = plane_equ( plane, point, process_id )) < -F_COPLANAR )
|
2017-04-26 17:20:15 +02:00
|
|
|
result_code |= POINT_NEGATIVE_SIDE ;
|
2017-04-26 18:03:02 +02:00
|
|
|
if( h > F_COPLANAR )
|
2017-04-26 17:20:15 +02:00
|
|
|
result_code |= POINT_POSITIVE_SIDE ;
|
|
|
|
|
|
|
|
return( result_code ) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
long patch_intersection(PlaneEqu *plane, Vertex *p1, Vertex *p2, Vertex *p3, long process_id)
|
|
|
|
{
|
|
|
|
long c1, c2, c3 ;
|
|
|
|
|
|
|
|
c1 = point_intersection( plane, p1, process_id ) ;
|
|
|
|
c2 = point_intersection( plane, p2, process_id ) ;
|
|
|
|
c3 = point_intersection( plane, p3, process_id ) ;
|
|
|
|
|
|
|
|
return( (c3 << 4) | (c2 << 2) | c1 ) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
*
|
|
|
|
* print_plane_equ()
|
|
|
|
*
|
|
|
|
* Print plane equation
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
void print_plane_equ(PlaneEqu *peq, long process_id)
|
|
|
|
{
|
|
|
|
printf( "\tPLN: %.3f x + %.3f y + %.3f z + %.3f\n",
|
|
|
|
peq->n.x, peq->n.y, peq->n.z, peq->c ) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|