pgadmin3/hotdraw/utilities/hdGeometry.cpp
2020-07-07 22:19:12 +05:00

190 lines
4.2 KiB
C++

//////////////////////////////////////////////////////////////////////////
//
// pgAdmin III - PostgreSQL Tools
//
// Copyright (C) 2002 - 2016, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
// hdGeometry.cpp - Utility Geometric Functions Shared between classes
//
//////////////////////////////////////////////////////////////////////////
#include "pgAdmin3.h"
// wxWindows headers
#include <wx/wx.h>
// App headers
#include "hotdraw/utilities/hdGeometry.h"
#include "hotdraw/utilities/hdMultiPosRect.h"
#include "hotdraw/utilities/hdPoint.h"
//
// Warning when using it: typecasting to avoid miscalculations functions need double values not int
//
bool hdGeometry::lineContainsPoint(double x1, double y1, double x2, double y2, double px, double py)
{
hdPoint p = hdPoint(x1, y1);
hdRect r = hdRect(p);
r.add(x2, y2);
r.Inflate(2, 2);
if(!r.Contains(px, py))
{
return false;
}
double a, b, x, y;
double val1, val2;
val1 = px - x1;
if( x1 == x2 )
{
return (ddabs(val1) < 3);
}
val2 = py - y1;
if( y1 == y2 )
{
return (ddabs(val2) < 3);
}
a = (y1 - y2) / (x1 - x2);
b = y1 - a * x1;
x = (py - b) / a;
y = a * px + b;
val1 = x - px;
val2 = y - py;
bool out = (min( ddabs(val1), ddabs(val2)) < 4);
return out;
}
int hdGeometry::min(double a, double b)
{
return(a <= b) ? a : b;
}
int hdGeometry::max(double a, double b)
{
return(a >= b) ? a : b;
}
int hdGeometry::min(int a, int b)
{
return(a <= b) ? a : b;
}
int hdGeometry::max(int a, int b)
{
return(a >= b) ? a : b;
}
//Gets the angle of a point relative to a rectangle.
double hdGeometry::angleFromPoint(int posIdx, hdMultiPosRect r, hdPoint point)
{
return angleFromPoint(r.gethdRect(posIdx), point);
}
double hdGeometry::angleFromPoint(hdRect r, hdPoint point)
{
double rx = point.x - r.center().x;
double ry = point.y - r.center().y;
return atan2 (ry * r.width, rx * r.height);
}
hdPoint hdGeometry::edgePointFromAngle(int posIdx, hdMultiPosRect r, double angle)
{
return edgePointFromAngle(r.gethdRect(posIdx), angle);
}
//Gets the point on a rectangle that corresponds to the given angle.
hdPoint hdGeometry::edgePointFromAngle(hdRect r, double angle)
{
static hdPoint locationPoint; //Hack to allow bug in linux & ddabs
double sinv = sin(angle);
double cosv = cos(angle);
double e = 0.0001;
double x = 0.0;
double y = 0.0;
double width = r.width;
double height = r.height;
if( ddabs(sinv) > e )
{
x = (1.0 + cosv / ddabs (sinv)) / 2.0 * width;
x = range(0.0, width, x);
}
else if ( cosv >= 0.0 )
{
x = width;
}
if ( ddabs(cosv) > e )
{
y = (1.0 + sinv / ddabs (cosv)) / 2.0 * height;
y = range (0.0, height, y);
}
else if ( sinv >= 0.0 )
{
y = height;
}
int xx = r.x + x;
int yy = r.y + y;
locationPoint = hdPoint(xx, yy);
return locationPoint;
}
double hdGeometry::range(double min, double max, double num)
{
return num < min ? min : (num > max ? max : num);
}
double hdGeometry::ddabs(double value)
{
return value < 0 ? (value * -1) : value;
}
int hdGeometry::ddabs(int value)
{
return value < 0 ? (value * -1) : value;
}
double hdGeometry::lineSize (hdPoint p1, hdPoint p2)
{
int w = p1.x - p2.x;
int h = p1.y - p2.y;
double perimeter = w * w + h * h;
return sqrt (perimeter);
}
// source: http://vision.dai.ed.ac.uk/andrewfg/c-g-a-faq.html
// Standard line intersection algorithm, Return true intersection if it exists, else false.
bool hdGeometry::intersection(hdPoint p1, hdPoint p2, hdPoint p3, hdPoint p4)
{
// Store the values for fast access and easy
// equations-to-code conversion
float x1 = p1.x, x2 = p2.x, x3 = p3.x, x4 = p4.x;
float y1 = p1.y, y2 = p2.y, y3 = p3.y, y4 = p4.y;
float d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
// If d is zero, there is no intersection
if (d == 0) return false;
// Get the x and y
float pre = (x1 * y2 - y1 * x2), post = (x3 * y4 - y3 * x4);
// point of intersection
float x = ( pre * (x3 - x4) - (x1 - x2) * post ) / d;
float y = ( pre * (y3 - y4) - (y1 - y2) * post ) / d;
// Check if the x and y coordinates are within both lines
if ( x < min(x1, x2) || x > max(x1, x2) || x < min(x3, x4) || x > max(x3, x4) )
return false;
if ( y < min(y1, y2) || y > max(y1, y2) || y < min(y3, y4) || y > max(y3, y4) )
return false;
return true;
}