/* Determine what side of a splitter a seg lies on. Copyright (C) 2002-2006 Randy Heit This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "zdbsp.h" #include "nodebuild.h" #define FAR_ENOUGH 17179869184.f // 4<<32 int FNodeBuilder::ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2) { const FPrivVert *v1 = &Vertices[seg->v1]; const FPrivVert *v2 = &Vertices[seg->v2]; double d_x1 = double(node.x); double d_y1 = double(node.y); double d_dx = double(node.dx); double d_dy = double(node.dy); double d_xv1 = double(v1->x); double d_xv2 = double(v2->x); double d_yv1 = double(v1->y); double d_yv2 = double(v2->y); double s_num1 = (d_y1 - d_yv1) * d_dx - (d_x1 - d_xv1) * d_dy; double s_num2 = (d_y1 - d_yv2) * d_dx - (d_x1 - d_xv2) * d_dy; int nears = 0; if (s_num1 <= -FAR_ENOUGH) { if (s_num2 <= -FAR_ENOUGH) { sidev1 = sidev2 = 1; return 1; } if (s_num2 >= FAR_ENOUGH) { sidev1 = 1; sidev2 = -1; return -1; } nears = 1; } else if (s_num1 >= FAR_ENOUGH) { if (s_num2 >= FAR_ENOUGH) { sidev1 = sidev2 = -1; return 0; } if (s_num2 <= -FAR_ENOUGH) { sidev1 = -1; sidev2 = 1; return -1; } nears = 1; } else { nears = 2 | int(fabs(s_num2) < FAR_ENOUGH); } if (nears) { double l = 1.f / (d_dx*d_dx + d_dy*d_dy); if (nears & 2) { double dist = s_num1 * s_num1 * l; if (dist < SIDE_EPSILON*SIDE_EPSILON) { sidev1 = 0; } else { sidev1 = s_num1 > 0.0 ? -1 : 1; } } else { sidev1 = s_num1 > 0.0 ? -1 : 1; } if (nears & 1) { double dist = s_num2 * s_num2 * l; if (dist < SIDE_EPSILON*SIDE_EPSILON) { sidev2 = 0; } else { sidev2 = s_num2 > 0.0 ? -1 : 1; } } else { sidev2 = s_num2 > 0.0 ? -1 : 1; } } else { sidev1 = s_num1 > 0.0 ? -1 : 1; sidev2 = s_num2 > 0.0 ? -1 : 1; } if ((sidev1 | sidev2) == 0) { // seg is coplanar with the splitter, so use its orientation to determine // which child it ends up in. If it faces the same direction as the splitter, // it goes in front. Otherwise, it goes in back. if (node.dx != 0) { if ((node.dx > 0 && v2->x > v1->x) || (node.dx < 0 && v2->x < v1->x)) { return 0; } else { return 1; } } else { if ((node.dy > 0 && v2->y > v1->y) || (node.dy < 0 && v2->y < v1->y)) { return 0; } else { return 1; } } } else if (sidev1 <= 0 && sidev2 <= 0) { return 0; } else if (sidev1 >= 0 && sidev2 >= 0) { return 1; } return -1; }