pipe2.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,160 行 · 第 1/3 页

C
1,160
字号
        start = rend_obj_get_pt( other, 0 );
        end = rend_obj_get_pt( other, 1 );
        a = point_diff( start, end );
        norm = cross_prod( a, Yvect );
        if( _is_zero_norm( norm ) ) {
            norm = cross_prod( a, Xvect );
        }
        break;
    case REND_OBJ_POLY:
        norm = rend_obj_get_norm( other );
        break;
    }

    pt = rend_obj_get_pt( obj, 0 );
    norm.v[3] = 0 - (norm.v[0]*pt.p[0] + norm.v[1]*pt.p[1] +
                    norm.v[2]*pt.p[2]);

    return( norm );
}

static vector calc_line_norm(
/***************************/
    rend_obj *  obj,            // a line object
    rend_obj *  other
) {
    vector      norm;
    vector      line_vect;
    vector      other_vect;
    point       start;
    point       end;
    point       pt1;
    polygon *   poly;
    int         pt_num;

    pt1 = rend_obj_get_pt( obj, 0 );
    end = rend_obj_get_pt( obj, 1 );
    line_vect = point_diff( pt1, end );

    switch( _rend_obj_get_type( other ) ) {
    case REND_OBJ_PT:
        norm = cross_prod( line_vect, Yvect );
        if( _is_zero_norm( norm ) ) {
            norm = cross_prod( line_vect, Xvect );
        }
        break;
    case REND_OBJ_LINE:
        start = rend_obj_get_pt( other, 0 );
        end = rend_obj_get_pt( other, 1 );
        other_vect = point_diff( start, end );
        norm = cross_prod( line_vect, other_vect );
        if( _is_zero_norm( norm ) ) {
            norm = cross_prod( line_vect, Yvect );
            if( _is_zero_norm( norm ) ) {
                norm = cross_prod( line_vect, Xvect );
            }
        }
        break;
    case REND_OBJ_POLY:
        poly = rend_obj_get_poly( other );
        start = _polygon_get_pt( *poly, _polygon_get_num_pts( *poly ) - 1 );
        for( pt_num = 0; pt_num < _polygon_get_num_pts( *poly ); pt_num++ ) {
            end = _polygon_get_pt( *poly, pt_num );
            other_vect = point_diff( start, end );
            norm = cross_prod( line_vect, other_vect );
            if( !_is_zero_norm( norm ) ) {
        /**/    break;
            }
            start = end;
        }
        if( _is_zero_norm( norm ) ) {
            norm = cross_prod( line_vect, Yvect );
            if( _is_zero_norm( norm ) ) {
                norm = cross_prod( line_vect, Xvect );
            }
        }
        break;
    }

    norm.v[3] = 0 - (norm.v[0]*pt1.p[0] + norm.v[1]*pt1.p[1] +
                    norm.v[2]*pt1.p[2]);

    return( norm );
}

static vector calculate_object_norm(
/**********************************/
/* Calculates the normal for the plane of a given object. See */
/* check_half_space for how this is determined */
    rend_obj *  obj,
    rend_obj *  other
) {
    vector      norm;

    switch (_rend_obj_get_type( obj )) {
    case REND_OBJ_PT:
        norm = calc_pt_norm( obj, other );
        break;
    case REND_OBJ_LINE:
        norm = calc_line_norm( obj, other );
        break;
    case REND_OBJ_POLY:
        norm = rend_obj_get_norm( obj );
        break;
    }

    return( norm );
}

enum {
    SUB_PLANE_UNKNOWN,
    SUB_PLANE_NEG,
    SUB_PLANE_ZERO,
    SUB_PLANE_POS,
    SUB_PLANE_NONE                  // for objects that cross the plane
};
typedef unsigned sub_plane_rc;

/* sign should be the result of a _fuzzy_sign macro */
#define _get_sub_plane_rc( sign ) (((sign) == 0) ? SUB_PLANE_ZERO : \
                    (((sign) == -1) ? SUB_PLANE_NEG : SUB_PLANE_POS ))

static int sub_pt_in_plane(
/*************************/
/* subsitute pt into the plane defined by norm and return the sign of the */
/* result */
    point       pt,
    vector      norm
) {
    float       result;

    result = _dot_prod_vp( norm, pt );
    return( _fuzzy_sign( result, FUZZY_ZERO ) );
}

static sub_plane_rc sub_line_in_plane(
/************************************/
    rend_obj    *obj,
    vector      norm
) {
    int         start_sign;
    int         end_sign;

    start_sign = sub_pt_in_plane( rend_obj_get_pt( obj, 0 ), norm );
    end_sign = sub_pt_in_plane( rend_obj_get_pt( obj, 1 ), norm );

    if (start_sign == end_sign || end_sign == 0) {
        return( _get_sub_plane_rc( start_sign ) );
    } else if (start_sign == 0) {
        return( _get_sub_plane_rc( end_sign ) );
    } else {
        return( SUB_PLANE_NONE );
    }
}

static sub_plane_rc sub_poly_in_plane(
/************************************/
    rend_obj    *obj,
    vector      norm
) {
    int         old_sign;
    int         sign;
    int         curr_pt;
    int         num_pts;
    polygon     *poly;

    poly = rend_obj_get_poly( obj );
    num_pts = _polygon_get_num_pts( *poly );
    old_sign = 0;

    for (curr_pt = 0; curr_pt < num_pts; curr_pt++) {
        sign = sub_pt_in_plane( _polygon_get_pt( *poly, curr_pt ), norm );
        if (sign != 0) {
            if (old_sign == 0) {
                /* this is the first non-zero sign */
                old_sign = sign;
            } else if (sign != old_sign) {
                /* this sign does not agree with the first non-zero sign */
                return( SUB_PLANE_NONE );
            }
        }
    }

    return( _get_sub_plane_rc( old_sign ) );
}

static sub_plane_rc sub_obj_in_plane(
/***********************************/
/*
Subsitute the points of obj into the plane defined by norm and determine the
resulting sign. If the sign of all pts is 0 (they all lie in the plane) return
0. If the sign of all the pts is the same (and non-zero) return it. Otherwise
return 0. Since norm contains the equation of a plane dot_prod_vp of norm
and a pt substitutes that pt into the equation.
*/
    rend_obj *  obj,
    vector      norm
) {
    int         sign;

    switch (_rend_obj_get_type( obj )) {
    case REND_OBJ_PT:
        sign = sub_pt_in_plane( rend_obj_get_pt( obj, 0 ), norm );
        return( _get_sub_plane_rc( sign ) );
        break;
    case REND_OBJ_LINE:
        return( sub_line_in_plane( obj, norm ) );
        break;
    case REND_OBJ_POLY:
        return( sub_poly_in_plane( obj, norm ) );
        break;
    default:
        /* This case should not happen */
        return( SUB_PLANE_UNKNOWN );
    }
}

enum {
    HALF_SPACE_NEAR,
    HALF_SPACE_FAR,
    HALF_SPACE_SAME,            // the objects lie in the same plane
    HALF_SPACE_NONE
};
typedef unsigned check_half_space_rc;

static check_half_space_rc check_half_space(
/******************************************/
    rend_obj *  obj1,
    rend_obj *  obj2
/*
This procedure checks if obj1 is completly in one of the half spaces of
the plane of obj2. The plane of obj2 could be any plane that contains obj2
and is defined differently for different types of objects:
    point:      plane is parallel to x-y plane (i.e. norm is (0,0,1))
    line:       let  a  be vector from start to end of line
                then n (the normal vector) is give by  a x (0,1,0) or
                a x (1,0,0) if the first one = 0  (x is the vector
                cross product).
    polygon:    norm is given
The plane normal is used in homogeneous coordinates as described at the top of
pipe.h, so the D parameter is calculated after A B and C are known.

Once the plane of obj2 is known each point associated with obj1 is substituted
into the plane equation and the resulting sign is noted. If all the signs agree
then the object is completely in one or the other of the half spaces. If the
common sign agrees with the sign of the z-component of the norm then obj1 is
in the near half space; if the signs are opposite then obj1 is in the far
half space.

NOTE: This implimentation was suggested by exercise 15.6 on p. 718.
*/
) {
    vector          norm;
    sub_plane_rc    rel1;       /* relationship of obj1 to plane of obj2 */
    int             sign2_z;    /* sign of z-component of norm of obj2 */

    norm = calculate_object_norm( obj2, obj1 );

    sign2_z = _fuzzy_sign( norm.v[2], FUZZY_ZERO );
    if (sign2_z == 0) {
        /* the plane of obj2 is perpendicular to the x-y plane so has no */
        /* near or far half spaces */
        return( HALF_SPACE_NONE );
    }

    rel1 = sub_obj_in_plane( obj1, norm );

    switch (rel1) {
    case SUB_PLANE_NONE:
        return( HALF_SPACE_NONE );
        break;
    case SUB_PLANE_ZERO:
        return( HALF_SPACE_SAME );
        break;
    case SUB_PLANE_NEG:
        if (sign2_z == -1) {
            return( HALF_SPACE_NEAR );
        } else {
            return( HALF_SPACE_FAR );
        }
        break;
    case SUB_PLANE_POS:
        if (sign2_z == -1) {
            return( HALF_SPACE_FAR );
        } else {
            return( HALF_SPACE_NEAR );
        }
        break;
    default:
        /* this case should not happen */
        return( HALF_SPACE_NONE );
        break;
    }
}

static bool near_half_space(
/**************************/
/* This tests whether obj1 is completly in the near half space (as seen by */
/* the viewer) of the plane of obj2. */
    rend_obj                *obj1,
    rend_obj                *obj2
) {
    check_half_space_rc     rc;

    rc = check_half_space( obj1, obj2 );
    return( rc == HALF_SPACE_NEAR || rc == HALF_SPACE_SAME );
}

static bool far_half_space(
/*************************/
/* This tests whether obj1 is completly in the far half space (as seen by */
/* the viewer) of the plane of obj2. */
    rend_obj                *obj1,
    rend_obj                *obj2
) {
    check_half_space_rc     rc;

    rc = check_half_space( obj1, obj2 );
    return( rc == HALF_SPACE_FAR || rc == HALF_SPACE_SAME );
}

static bool proj_overlap_ln_ln(
/*****************************/
/* Tests whether 2 line objects overlap in their projection into the x-y plane*/
    rend_obj *  obj1,
    rend_obj *  obj2
) {
    point       line1[2];
    point       line2[2];

    line1[0] = rend_obj_get_pt( obj1, 0 );
    line1[1] = rend_obj_get_pt( obj1, 1 );
    line2[0] = rend_obj_get_pt( obj2, 0 );
    line2[1] = rend_obj_get_pt( obj2, 1 );

    return( proj_line_intersection( line1, line2 ) );
}

static bool proj_overlap_ln_poly(
/*******************************/
/* Test whether a line and a poly overlap in their projections */
    rend_obj *  line,
    rend_obj *  obj_poly
) {
    point       ln[2];
    point       edge[2];
    int         num_pts;
    int         curr_pt;
    polygon     *poly;

    ln[0] = rend_obj_get_pt( line, 0 );
    ln[1] = rend_obj_get_pt( line, 1 );
    poly = rend_obj_get_poly( obj_poly );

    num_pts = _polygon_get_num_pts( *poly );
    /* start with the edge between point 0 and point (num_pts-1) */
    edge[0] = _polygon_get_pt( *poly, num_pts-1 );
    for (curr_pt = 0; curr_pt < num_pts; curr_pt++) {
        edge[1] = _polygon_get_pt( *poly, curr_pt );
        if (proj_line_intersection( ln, edge )) {
            return( TRUE );
        }
        edge[0] = edge[1];
    }
    return( FALSE );
}

static bool proj_overlap_poly_poly(
/*********************************/
/* Test whether the projection into the x-y plane of two polygons overlap */
/*
    NOTE: This routine does not work the way it is supposed to. What it is
    supposed to do is to check if the intersection of the two polygons is
    non-empty. What it actually test for is whether the intersection of the
    edges is non-empty. The cases that get missed are the ones in which one
    polygon is contained in the other. One possible way to fix this would be
    to test one vertex from each polygon against the other polygon. If this
    test is performed after the edge test then a point in the other polygon
    means that the entire polygon is contained.

    One posible source of a method to carry out this testing could be
        Preparata, F. P., and M. I. Shamos. "Computational Geometry:
                An Introduction". Springer-Verlag, New York, 1985.
    I have not seen this book but the title suggests that it may contain
    what we need.

    S.Bosnick
*/

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?