From 1fa449fed953fa11f6bd0ea82cc2d3b115ee0781 Mon Sep 17 00:00:00 2001 From: saurabhb17 Date: Wed, 26 Feb 2020 16:36:01 +0530 Subject: Remaining files transfered --- polygon/math_for_graphics.cpp | 520 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 520 insertions(+) create mode 100644 polygon/math_for_graphics.cpp (limited to 'polygon/math_for_graphics.cpp') diff --git a/polygon/math_for_graphics.cpp b/polygon/math_for_graphics.cpp new file mode 100644 index 0000000..c43f323 --- /dev/null +++ b/polygon/math_for_graphics.cpp @@ -0,0 +1,520 @@ +// math for graphics utility routines and RC, from FreePCB + +#include + +#include +#include +#include +#include +#include + +#include +#include + +static bool InRange( double x, double xi, double xf ); + +/* Function FindSegmentIntersections + * find intersections between line segment (xi,yi) to (xf,yf) + * and line segment (xi2,yi2) to (xf2,yf2) + * returns true if intersection found + */ +bool FindSegmentIntersections( int xi, int yi, int xf, int yf, + int xi2, int yi2, int xf2, int yf2 ) +{ + if( std::max( xi, xf ) < std::min( xi2, xf2 ) + || std::min( xi, xf ) > std::max( xi2, xf2 ) + || std::max( yi, yf ) < std::min( yi2, yf2 ) + || std::min( yi, yf ) > std::max( yi2, yf2 ) ) + return false; + + return TestForIntersectionOfStraightLineSegments( xi, yi, xf, yf, + xi2, yi2, xf2, yf2 ); +} + + +/* Function FindLineSegmentIntersection + * find intersection between line y = a + bx and line segment (xi,yi) to (xf,yf) + * if b > DBL_MAX/10, assume vertical line at x = a + * return false if no intersection or true if intersect + * return coords of intersections in *x1, *y1, *x2, *y2 + * if no intersection, returns min distance in dist + */ +bool FindLineSegmentIntersection( double a, double b, int xi, int yi, int xf, int yf, + double* x1, double* y1, double* x2, double* y2, + double* dist ) +{ + double xx = 0, yy = 0; // Init made to avoid C compil "uninitialized" warning + bool bVert = false; + + if( b > DBL_MAX / 10.0 ) + bVert = true; + + if( xf != xi ) // non-vertical segment, get intersection + { + // horizontal or oblique straight segment + // put into form y = c + dx; + double d = (double) (yf - yi) / (double) (xf - xi); + double c = yf - d * xf; + + if( bVert ) + { + // if vertical line, easy + if( InRange( a, xi, xf ) ) + { + *x1 = a; + *y1 = c + d * a; + return 1; + } + else + { + if( dist ) + *dist = std::min( std::abs( a - xi ), std::abs( a - xf ) ); + + return false; + } + } + + if( std::abs( b - d ) < 1E-12 ) + { + // parallel lines + if( dist ) + { + *dist = GetPointToLineDistance( a, b, xi, xf ); + } + + return false; // lines parallel + } + + // calculate intersection + xx = (c - a) / (b - d); + yy = a + b * (xx); + + // see if intersection is within the line segment + if( yf == yi ) + { + // horizontal line + if( (xx>=xi && xx>xf) || (xx<=xi && xx=xi && xx>xf) || (xx<=xi && xxyi && yy>yf) || (yy=yi && yy>yf) || (yy<=yi && yy max_cl, just returns max_cl+1 and doesn't return x,y + */ +int GetClearanceBetweenSegments( int x1i, int y1i, int x1f, int y1f, int w1, + int x2i, int y2i, int x2f, int y2f, int w2, + int max_cl, int* x, int* y ) +{ + // check clearance between bounding rectangles + int min_dist = max_cl + ( (w1 + w2) / 2 ); + + if( std::min( x1i, x1f ) - std::max( x2i, x2f ) > min_dist ) + return max_cl+1; + + if( std::min( x2i, x2f ) - std::max( x1i, x1f ) > min_dist ) + return max_cl+1; + + if( std::min( y1i, y1f ) - std::max( y2i, y2f ) > min_dist ) + return max_cl+1; + + if( std::min( y2i, y2f ) - std::max( y1i, y1f ) > min_dist ) + return max_cl+1; + + int xx, yy; + double dist; + TestForIntersectionOfStraightLineSegments( x1i, y1i, x1f, y1f, + x2i, y2i, x2f, y2f, &xx, &yy, &dist ); + int d = KiROUND( dist ) - ((w1 + w2) / 2); + if( d < 0 ) + d = 0; + + if( x ) + *x = xx; + + if( y ) + *y = yy; + + return d; +} + + +/* Function GetPointToLineDistance + * Get min. distance from (x,y) to line y = a + bx + * if b > DBL_MAX/10, assume vertical line at x = a + * returns closest point on line in xpp, ypp + */ +double GetPointToLineDistance( double a, double b, int x, int y, double* xpp, double* ypp ) +{ + if( b > DBL_MAX / 10 ) + { + // vertical line + if( xpp && ypp ) + { + *xpp = a; + *ypp = y; + } + + return std::abs( a - x ); + } + + // find c,d such that (x,y) lies on y = c + dx where d=(-1/b) + double d = -1.0 / b; + double c = (double) y - d * x; + + // find nearest point to (x,y) on line through (xi,yi) to (xf,yf) + double xp = (a - c) / (d - b); + double yp = a + b * xp; + + if( xpp && ypp ) + { + *xpp = xp; + *ypp = yp; + } + + // find distance + return Distance( x, y, xp, yp ); +} + + +/** + * Function GetPointToLineSegmentDistance + * Get distance between line segment and point + * @param x,y = point + * @param xi,yi Start point of the line segament + * @param xf,yf End point of the line segment + * @return the distance + */ +double GetPointToLineSegmentDistance( int x, int y, int xi, int yi, int xf, int yf ) +{ + // test for vertical or horizontal segment + if( xf==xi ) + { + // vertical line segment + if( InRange( y, yi, yf ) ) + return std::abs( x - xi ); + else + return std::min( Distance( x, y, xi, yi ), Distance( x, y, xf, yf ) ); + } + else if( yf==yi ) + { + // horizontal line segment + if( InRange( x, xi, xf ) ) + return std::abs( y - yi ); + else + return std::min( Distance( x, y, xi, yi ), Distance( x, y, xf, yf ) ); + } + else + { + // oblique segment + // find a,b such that (xi,yi) and (xf,yf) lie on y = a + bx + double b = (double) (yf - yi) / (xf - xi); + double a = (double) yi - b * xi; + + // find c,d such that (x,y) lies on y = c + dx where d=(-1/b) + double d = -1.0 / b; + double c = (double) y - d * x; + + // find nearest point to (x,y) on line through (xi,yi) to (xf,yf) + double xp = (a - c) / (d - b); + double yp = a + b * xp; + + // find distance + if( InRange( xp, xi, xf ) && InRange( yp, yi, yf ) ) + return Distance( x, y, xp, yp ); + else + return std::min( Distance( x, y, xi, yi ), Distance( x, y, xf, yf ) ); + } +} + + +// test for value within range +bool InRange( double x, double xi, double xf ) +{ + if( xf > xi ) + { + if( x >= xi && x <= xf ) + return true; + } + else + { + if( x >= xf && x <= xi ) + return true; + } + + return false; +} -- cgit