| /*************************************************************************/ |
| /* */ |
| /* 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) |
| * |
| *************************************************************************/ |
| |
| #include <stdio.h> |
| |
| 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) |
| { |
| if( node == 0 ) |
| return ; |
| |
| /* Process subtree(-) */ |
| if( node->bsp_negative ) |
| _foreach_patch( node->bsp_negative, func, arg1, process_id ) ; |
| |
| /* Apply function to this node */ |
| func( node, arg1, process_id ) ; |
| |
| /* Process subtree(+) */ |
| if( node->bsp_positive ) |
| _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 ; |
| |
| if( node == 0 ) |
| return ; |
| |
| /* Compute inner product */ |
| sign = inner_product( svec, &node->plane_equ.n ) ; |
| |
| if( sign >= 0.0 ) |
| { |
| /* The vector is approaching from the negative side of the patch */ |
| |
| /* Process subtree(-) */ |
| if( node->bsp_negative ) |
| _foreach_d_s_patch( svec, node->bsp_negative, func, arg1, process_id ) ; |
| |
| /* Apply function to this node */ |
| func( node, arg1, process_id ) ; |
| |
| /* Process subtree(+) */ |
| if( node->bsp_positive ) |
| _foreach_d_s_patch( svec, node->bsp_positive, func, arg1, process_id ) ; |
| } |
| else |
| { |
| /* Process subtree(+) */ |
| if( node->bsp_positive ) |
| _foreach_d_s_patch( svec, node->bsp_positive, func, arg1, process_id ) ; |
| |
| /* Apply function to this node */ |
| func( node, arg1, process_id ) ; |
| |
| /* Process subtree(-) */ |
| if( node->bsp_negative ) |
| _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 */ |
| if( parent == 0 ) |
| { |
| if( global->bsp_root == 0 ) |
| { |
| /* 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 */ |
| while( 1 ) |
| { |
| /* 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 */ |
| if( POSITIVE_SIDE( xing_code ) ) |
| { |
| if( parent->bsp_positive == 0 ) |
| { |
| /* 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 ; |
| } |
| else if( NEGATIVE_SIDE( xing_code ) ) |
| { |
| if( parent->bsp_negative == 0 ) |
| { |
| /* 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 */ |
| if( c1 == c2 ) |
| /* 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) ; |
| else if( c1 == c3 ) |
| /* 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 ) ; |
| else if( c2 == c3 ) |
| /* 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 ) ; |
| else if( c1 == POINT_ON_PLANE ) |
| /* 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 ) ; |
| else if( c2 == POINT_ON_PLANE ) |
| /* 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) ; |
| if( (rev_e12 = EDGE_REVERSE( e12, ev1, ev2 )) ) |
| 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) ; |
| if( (rev_e31 = EDGE_REVERSE( e31, ev3, ev1 )) ) |
| 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) ; |
| if( (rev_e23 = EDGE_REVERSE( e23, ev2, ev3 )) ) |
| 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 */ |
| if( patch->seq_no >= new_patch->seq_no ) |
| /* 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 ) ; |
| if( NEGATIVE_SIDE(cc) ) |
| /* 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 ) ; |
| if( NEGATIVE_SIDE(cc) ) |
| /* 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 */ |
| if( global->free_patch == 0 ) |
| { |
| 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 */ |
| for( i = 0 ; i < MAX_PATCHES-1 ; i++ ) |
| { |
| 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 */ |
| for( i = 0 ; i < MAX_PATCHES ; i++ ) |
| { |
| 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 */ |
| if( (h = plane_equ( plane, point, process_id )) < -F_COPLANAR ) |
| result_code |= POINT_NEGATIVE_SIDE ; |
| if( h > F_COPLANAR ) |
| 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 ) ; |
| } |
| |
| |