Files
ResInsight/ThirdParty/Ert/lib/geometry/geo_util.cpp
Magne Sjaastad 04091ad77d #4266 Update libecl
Use commit 0e1e780fd6f18ce93119061e36a4fca9711bc020

Excluded multibuild folder, as this caused git issues
2019-05-09 08:40:32 +02:00

252 lines
6.3 KiB
C++

/*
Copyright (C) 2011 Equinor ASA, Norway.
The file 'geo_util.c' is part of ERT - Ensemble based Reservoir Tool.
ERT 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 3 of the License, or
(at your option) any later version.
ERT 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 at <http://www.gnu.org/licenses/gpl.html>
for more details.
*/
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
#include <ert/util/util.h>
#include <ert/geometry/geo_util.hpp>
#define EPSILON 0.000001
static bool between(double v1, double v2 , double v) {
return ((( v > v1) && (v < v2)) || (( v < v1) && (v > v2)));
}
static bool interval_overlap(double a1,double a2, double b1, double b2) {
if (between(a1,a2,b1) || between(a1,a2,b2))
return true;
if ((a1 == b1) && (a2 == b2))
return true;
return false;
}
static bool on_edge(double _x1 , double _y1 , double _x2 , double _y2 , double x0 , double y0) {
double x1 = util_double_min( _x1 , _x2 );
double x2 = util_double_max( _x1 , _x2 );
double y1 = util_double_min( _y1 , _y2 );
double y2 = util_double_max( _y1 , _y2 );
{
/* Vertical line */
if (((x1 == x2) && (x0 == x1)) && ((y1 <= y0) && (y0 <= y2)))
return true;
/* Horizontal line */
if (((x1 <= x0) && (x0 <= x2)) && ((y1 == y2) && (y0 == y1)))
return true;
/* General slope */
{
double a = (y2 - y1) / (x2 - x1);
double yc = a*(x0 - x1) + y1;
if (yc == y0) {
if ((x1 <= x0) && (x0 <= x2))
return true;
}
}
return false;
}
}
/*
If the bool force_edge_inside is set to true, points exactly on the
edge will be identified as inside. If the force_edge_inside variable
is set to false the behaviour on the edges is undefined.
*/
bool geo_util_inside_polygon__(const double * xlist , const double * ylist , int num_points , double x0 , double y0 , bool force_edge_inside) {
bool inside = false;
int point_num;
double y = y0;
double xc = 0;
for (point_num = 0; point_num < num_points; point_num++) {
int next_point = ((point_num + 1) % num_points);
double x1 = xlist[point_num]; double y1 = ylist[point_num];
double x2 = xlist[next_point]; double y2 = ylist[next_point];
double ymin = util_double_min(y1,y2);
double ymax = util_double_max(y1,y2);
double xmax = util_double_max(x1,x2);
if (force_edge_inside) {
if (on_edge(x1,y1,x2,y2,x0,y0)) {
inside = true;
break;
}
}
if ((x1 == x2) && (y1 == y2))
continue;
if ((y0 > ymin) && (y <= ymax)) {
if (x0 <= xmax) {
if (y1 != y2)
xc = (y0 - y1) * (x2 - x1) / (y2 - y1) + x1;
if ((x1 == x2) || (x0 <= xc))
inside = !inside;
}
}
}
return inside;
}
bool geo_util_inside_polygon(const double * xlist , const double * ylist , int num_points , double x0 , double y0) {
return geo_util_inside_polygon__(xlist , ylist , num_points , x0 , y0 , false );
}
/*
This function will cross to infinitely long lines which go through
the points given by the points pointer; this function does not
consider line segments of finite length.
*/
geo_util_xlines_status_enum geo_util_xlines( const double ** points , double * x0, double * y0 ) {
double x1 = points[0][0];
double x2 = points[1][0];
double x3 = points[2][0];
double x4 = points[3][0];
double y1 = points[0][1];
double y2 = points[1][1];
double y3 = points[2][1];
double y4 = points[3][1];
double dx1 = (x2 - x1);
double dx2 = (x4 - x3);
double dy1 = (y2 - y1);
double dy2 = (y4 - y3);
if ((dx1 == 0 && dy1 == 0) ||
(dx2 == 0 && dy2 == 0))
return GEO_UTIL_LINES_DEGENERATE;
if ((dx1 != 0) && (dx2 != 0)) {
// Both lines have a finite slope.
double a1 = dy1 / dx1;
double a2 = dy2 / dx2;
if (a1 != a2) {
// The two lines are not parallell and we will have a normal solution.
double x = ((y3 - y1) - a2*x3 + a1*x1) / (a1 - a2);
double y = a1*(x - x1) + y1;
*x0 = x;
*y0 = y;
return GEO_UTIL_LINES_CROSSING;
} else {
// The two lines are parallell - potentially overlapping.
double ytest = a1*(x3 - x1) + y1;
if (ytest == y3)
return GEO_UTIL_LINES_OVERLAPPING;
else
return GEO_UTIL_LINES_PARALLELL;
}
} else {
double x,y;
if ((dx1 == dx2) && (dx1 == 0)) {
if (x1 == x3)
return GEO_UTIL_LINES_OVERLAPPING;
else
return GEO_UTIL_LINES_PARALLELL;
}
// Only one of the lines is vertical - this will be a normal crossing.
if (dx1 == 0) {
double a2 = dy2 / dx2;
y = y3 + a2*(x1 - x3);
x = x1;
} else {
double a1 = dy1 / dx1;
y = y1 + a1*(x3 - x1);
x = x3;
}
*x0 = x;
*y0 = y;
return GEO_UTIL_LINES_CROSSING;
}
}
geo_util_xlines_status_enum geo_util_xsegments( const double ** points , double * x0, double * y0 ) {
double x1 = points[0][0];
double x2 = points[1][0];
double x3 = points[2][0];
double x4 = points[3][0];
double y1 = points[0][1];
double y2 = points[1][1];
double y3 = points[2][1];
double y4 = points[3][1];
double denominator = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
double numerator_a = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3);
double numerator_b = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3);
// coincident?
if ((fabs(numerator_a) < EPSILON) &&
(fabs(numerator_b) < EPSILON) &&
(fabs(denominator) < EPSILON)) {
if (interval_overlap( x1,x2,x3,x4) && interval_overlap(y1,y2,y3,y4))
return GEO_UTIL_LINES_OVERLAPPING;
else
return GEO_UTIL_NOT_CROSSING;
}
// Parallell
if (fabs(denominator) < EPSILON)
return GEO_UTIL_NOT_CROSSING;
// Normal intersection
{
double mua = numerator_a / denominator;
double mub = numerator_b / denominator;
if ((mua < 0.0) || (mua > 1.0) || (mub < 0.0) || (mub > 1.0))
return GEO_UTIL_NOT_CROSSING;
*x0 = x1 + mua * (x2 - x1);
*y0 = y1 + mua * (y2 - y1 );
return GEO_UTIL_LINES_CROSSING;
}
}