mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-14 02:03:12 +02:00
Finally remove other_math routines
Replace with standard SEG and VECTOR2 alternatives. Add QA test for additional SEG-line intersection routine
This commit is contained in:
parent
0459c54a92
commit
4c03ab8ebb
@ -52,7 +52,6 @@ add_library( kimath STATIC
|
||||
target_link_libraries( kimath
|
||||
core
|
||||
clipper2
|
||||
othermath
|
||||
rtree
|
||||
Boost::headers
|
||||
${wxWidgets_LIBRARIES} # wxLogDebug, wxASSERT
|
||||
|
@ -222,6 +222,16 @@ public:
|
||||
return Intersect( aSeg, false, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this segment intersects a line defined by slope \a aSlope and offset \a aOffset.
|
||||
*
|
||||
* @param aSlope slope of the line
|
||||
* @param aOffset offset of the line
|
||||
* @param aIntersection output intersection point, if exists
|
||||
* @return true if the segment intersects the line, false otherwise
|
||||
*/
|
||||
bool IntersectsLine( double aSlope, double aOffset, VECTOR2I& aIntersection ) const;
|
||||
|
||||
/**
|
||||
* Compute a segment perpendicular to this one, passing through point \a aP.
|
||||
*
|
||||
|
@ -447,6 +447,76 @@ OPT_VECTOR2I SEG::Intersect( const SEG& aSeg, bool aIgnoreEndpoints, bool aLines
|
||||
}
|
||||
|
||||
|
||||
bool SEG::IntersectsLine( double aSlope, double aOffset, VECTOR2I& aIntersection ) const
|
||||
{
|
||||
const VECTOR2L segA( A );
|
||||
const VECTOR2L segB( B );
|
||||
const VECTOR2L segDir = segB - segA;
|
||||
|
||||
// Handle vertical segment case
|
||||
if( segDir.x == 0 )
|
||||
{
|
||||
// Vertical segment: x = A.x, find y on the line
|
||||
const double intersect_y = aSlope * A.x + aOffset;
|
||||
const int intersect_y_int = KiROUND( intersect_y );
|
||||
|
||||
// Check if intersection is within segment's y-range
|
||||
const int seg_min_y = std::min( A.y, B.y );
|
||||
const int seg_max_y = std::max( A.y, B.y );
|
||||
|
||||
if( intersect_y_int >= seg_min_y && intersect_y_int <= seg_max_y )
|
||||
{
|
||||
aIntersection = VECTOR2I( A.x, intersect_y_int );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const VECTOR2L lineDir( 1000, static_cast<ecoord>( aSlope * 1000 ) );
|
||||
const ecoord cross_product = segDir.Cross( lineDir );
|
||||
|
||||
if( cross_product == 0 )
|
||||
{
|
||||
// Parallel lines - check if segment lies on the line
|
||||
const double expected_y = aSlope * A.x + aOffset;
|
||||
const double diff = std::abs( A.y - expected_y );
|
||||
|
||||
if( diff < 0.5 )
|
||||
{
|
||||
// Collinear: segment lies on the line, return midpoint
|
||||
aIntersection = ( A + B ) / 2;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; // Parallel but not collinear
|
||||
}
|
||||
|
||||
// Find intersection using parametric equations
|
||||
// Segment: P = segA + t * segDir
|
||||
// Line: y = aSlope * x + aOffset
|
||||
//
|
||||
// At intersection: segA.y + t * segDir.y = aSlope * (segA.x + t * segDir.x) + aOffset
|
||||
// Solving for t: t = (aSlope * segA.x + aOffset - segA.y) / (segDir.y - aSlope * segDir.x)
|
||||
|
||||
const double numerator = aSlope * segA.x + aOffset - segA.y;
|
||||
const double denominator = segDir.y - aSlope * segDir.x;
|
||||
|
||||
const double t = numerator / denominator;
|
||||
|
||||
// Check if intersection is within segment bounds
|
||||
if( t >= 0.0 && t <= 1.0 )
|
||||
{
|
||||
const double intersect_x = segA.x + t * segDir.x;
|
||||
const double intersect_y = segA.y + t * segDir.y;
|
||||
|
||||
aIntersection = VECTOR2I( KiROUND( intersect_x ), KiROUND( intersect_y ) );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
SEG SEG::PerpendicularSeg( const VECTOR2I& aP ) const
|
||||
{
|
||||
VECTOR2I slope( B - A );
|
||||
@ -616,13 +686,8 @@ int SEG::Distance( const VECTOR2I& aP ) const
|
||||
|
||||
SEG::ecoord SEG::SquaredDistance( const VECTOR2I& aP ) const
|
||||
{
|
||||
// Using the VECTOR2L() reflexive c'tor is a performance hit.
|
||||
// Even sticking these in a lambda still invokes it.
|
||||
VECTOR2L ab, ap;
|
||||
ab.x = static_cast<int64_t>( B.x ) - A.x;
|
||||
ab.y = static_cast<int64_t>( B.y ) - A.y;
|
||||
ap.x = static_cast<int64_t>( aP.x ) - A.x;
|
||||
ap.y = static_cast<int64_t>( aP.y ) - A.y;
|
||||
VECTOR2<ecoord> ab( ecoord( B.x ) - A.x, ecoord( B.y ) - A.y );
|
||||
VECTOR2<ecoord> ap( ecoord( aP.x ) - A.x, ecoord( aP.y ) - A.y );
|
||||
|
||||
ecoord e = ap.Dot( ab );
|
||||
|
||||
@ -633,9 +698,8 @@ SEG::ecoord SEG::SquaredDistance( const VECTOR2I& aP ) const
|
||||
|
||||
if( e >= f )
|
||||
{
|
||||
VECTOR2L bp;
|
||||
bp.x = static_cast<int64_t>( aP.x ) - B.x;
|
||||
bp.y = static_cast<int64_t>( aP.y ) - B.y;
|
||||
VECTOR2<ecoord> bp( ecoord( aP.x ) - B.x, ecoord( aP.y ) - B.y );
|
||||
|
||||
return bp.Dot( bp );
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include <clipper2/clipper.h>
|
||||
#include <math_for_graphics.h>
|
||||
#include <geometry/geometry_utils.h>
|
||||
#include <geometry/polygon_triangulation.h>
|
||||
#include <geometry/seg.h> // for SEG, OPT_VECTOR2I
|
||||
@ -3203,15 +3202,23 @@ const std::vector<SEG> SHAPE_POLY_SET::GenerateHatchLines( const std::vector<dou
|
||||
for( int64_t a = min_a; a < max_a; a += aSpacing )
|
||||
{
|
||||
pointbuffer.clear();
|
||||
SEG hatch_line( VECTOR2I( 0, a ), VECTOR2I( 1, a + slope ) );
|
||||
|
||||
// Iterate through all vertices
|
||||
for( auto iterator = CIterateSegmentsWithHoles(); iterator; iterator++ )
|
||||
{
|
||||
const SEG seg = *iterator;
|
||||
double x, y;
|
||||
VECTOR2I pt;
|
||||
|
||||
if( FindLineSegmentIntersection( a, slope, seg.A.x, seg.A.y, seg.B.x, seg.B.y, x, y ) )
|
||||
pointbuffer.emplace_back( KiROUND( x ), KiROUND( y ) );
|
||||
if( seg.IntersectsLine( slope, a, pt ) )
|
||||
{
|
||||
// If the intersection point is outside the polygon, skip it
|
||||
if( pt.x < min_x || pt.x > max_x || pt.y < min_y || pt.y > max_y )
|
||||
continue;
|
||||
|
||||
// Add the intersection point to the buffer
|
||||
pointbuffer.emplace_back( KiROUND( pt.x ), KiROUND( pt.y ) );
|
||||
}
|
||||
}
|
||||
|
||||
// sort points in order of descending x (if more than 2) to
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include "ar_matrix.h"
|
||||
#include <lset.h>
|
||||
#include <math/util.h> // for KiROUND
|
||||
#include <math_for_graphics.h>
|
||||
#include <trigo.h>
|
||||
|
||||
#include <pcb_shape.h>
|
||||
@ -407,7 +406,10 @@ void AR_MATRIX::traceCircle( int ux0, int uy0, int ux1, int uy1, int lg, int lay
|
||||
int x1, y1; // End point.
|
||||
int ii;
|
||||
|
||||
radius = KiROUND( Distance( ux0, uy0, ux1, uy1 ) );
|
||||
VECTOR2I pt1( ux0, uy0 );
|
||||
VECTOR2I pt2( ux1, uy1 );
|
||||
|
||||
radius = pt1.Distance( pt2 );
|
||||
|
||||
x0 = x1 = radius;
|
||||
y0 = y1 = 0;
|
||||
@ -567,7 +569,10 @@ void AR_MATRIX::traceArc( int ux0, int uy0, int ux1, int uy1, const EDA_ANGLE& a
|
||||
int ii;
|
||||
EDA_ANGLE angle, startAngle;
|
||||
|
||||
radius = KiROUND( Distance( ux0, uy0, ux1, uy1 ) );
|
||||
VECTOR2I pt1( ux0, uy0 );
|
||||
VECTOR2I pt2( ux1, uy1 );
|
||||
|
||||
radius = pt1.Distance( pt2 );
|
||||
|
||||
x0 = ux1 - ux0;
|
||||
y0 = uy1 - uy0;
|
||||
@ -632,7 +637,9 @@ void AR_MATRIX::TraceFilledRectangle( int ux0, int uy0, int ux1, int uy1, double
|
||||
|
||||
cx = ( ux0 + ux1 ) / 2;
|
||||
cy = ( uy0 + uy1 ) / 2;
|
||||
radius = KiROUND( Distance( ux0, uy0, cx, cy ) );
|
||||
VECTOR2I pt1( ux0, uy0 );
|
||||
VECTOR2I pt2( cx, cy );
|
||||
radius = pt1.Distance( pt2 );
|
||||
|
||||
// Calculating coordinate limits belonging to the rectangle.
|
||||
row_max = ( cy + radius ) / m_GridRouting;
|
||||
|
@ -22,7 +22,6 @@
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <math_for_graphics.h>
|
||||
#include <board_design_settings.h>
|
||||
#include <footprint.h>
|
||||
#include <layer_range.h>
|
||||
@ -1263,8 +1262,10 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones()
|
||||
if( ax2 < bx1 )
|
||||
break;
|
||||
|
||||
actual = GetClearanceBetweenSegments( bx1, by1, bx2, by2, 0, ax1, ay1, ax2, ay2, 0,
|
||||
clearance, &pt.x, &pt.y );
|
||||
int64_t dist_sq = 0;
|
||||
VECTOR2I other_pt;
|
||||
refSegment.NearestPoints( testSegment, pt, other_pt, dist_sq );
|
||||
actual = std::floor( std::sqrt( dist_sq ) + 0.5 );
|
||||
|
||||
if( actual < clearance )
|
||||
{
|
||||
|
@ -1225,4 +1225,354 @@ BOOST_AUTO_TEST_CASE( IntersectZeroLengthSegments )
|
||||
BOOST_CHECK_EQUAL( *intersection6, VECTOR2I( 100, 100 ) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test cases for segment-line intersection
|
||||
*/
|
||||
struct SEG_LINE_INTERSECT_CASE : public KI_TEST::NAMED_CASE
|
||||
{
|
||||
SEG m_seg;
|
||||
double m_slope;
|
||||
double m_offset;
|
||||
bool m_exp_intersect;
|
||||
VECTOR2I m_exp_point;
|
||||
};
|
||||
|
||||
/**
|
||||
* Predicate to check expected intersection between a segment and an infinite line
|
||||
* @param aSeg the segment
|
||||
* @param aSlope the line slope
|
||||
* @param aOffset the line y-intercept
|
||||
* @param aExpIntersect expected intersection result
|
||||
* @param aExpPoint expected intersection point (if intersection occurs)
|
||||
* @return does the intersection calculated agree?
|
||||
*/
|
||||
bool SegLineIntersectCorrect( const SEG& aSeg, double aSlope, double aOffset,
|
||||
bool aExpIntersect, const VECTOR2I& aExpPoint = VECTOR2I() )
|
||||
{
|
||||
VECTOR2I intersection;
|
||||
const bool intersects = aSeg.IntersectsLine( aSlope, aOffset, intersection );
|
||||
|
||||
bool ok = ( intersects == aExpIntersect );
|
||||
|
||||
if( !ok )
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "Line intersection incorrect: expected " << aExpIntersect << ", got " << intersects;
|
||||
BOOST_TEST_INFO( ss.str() );
|
||||
}
|
||||
|
||||
// Check intersection point if intersection was expected
|
||||
if( ok && aExpIntersect && aExpPoint != VECTOR2I() )
|
||||
{
|
||||
// Allow some tolerance for intersection point calculation
|
||||
const int tolerance = 1;
|
||||
|
||||
bool pointOk = ( std::abs( intersection.x - aExpPoint.x ) <= tolerance &&
|
||||
std::abs( intersection.y - aExpPoint.y ) <= tolerance );
|
||||
|
||||
if( !pointOk )
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "Intersection point incorrect: expected " << aExpPoint.Format()
|
||||
<< ", got " << intersection.Format();
|
||||
BOOST_TEST_INFO( ss.str() );
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
static const std::vector<SEG_LINE_INTERSECT_CASE> seg_line_intersect_cases = {
|
||||
// Basic intersection cases
|
||||
{
|
||||
"Horizontal segment, diagonal line",
|
||||
{ { 0, 5 }, { 10, 5 } },
|
||||
1.0, 0.0, // y = x
|
||||
true,
|
||||
{ 5, 5 }
|
||||
},
|
||||
{
|
||||
"Vertical segment, horizontal line",
|
||||
{ { 5, 0 }, { 5, 10 } },
|
||||
0.0, 3.0, // y = 3
|
||||
true,
|
||||
{ 5, 3 }
|
||||
},
|
||||
{
|
||||
"Diagonal segment, horizontal line crossing",
|
||||
{ { 0, 0 }, { 10, 10 } },
|
||||
0.0, 5.0, // y = 5
|
||||
true,
|
||||
{ 5, 5 }
|
||||
},
|
||||
{
|
||||
"Diagonal segment, vertical line (steep slope)",
|
||||
{ { 0, 0 }, { 10, 10 } },
|
||||
1000.0, -5000.0, // Very steep line: y = 1000x - 5000, crosses at x=5
|
||||
true,
|
||||
{ 5, 5 }
|
||||
},
|
||||
|
||||
// Non-intersecting cases
|
||||
{
|
||||
"Horizontal segment, parallel horizontal line",
|
||||
{ { 0, 5 }, { 10, 5 } },
|
||||
0.0, 10.0, // y = 10 (parallel to y = 5)
|
||||
false,
|
||||
{ 0, 0 }
|
||||
},
|
||||
{
|
||||
"Diagonal segment, parallel line",
|
||||
{ { 0, 0 }, { 10, 10 } },
|
||||
1.0, 5.0, // y = x + 5 (parallel to y = x)
|
||||
false,
|
||||
{ 0, 0 }
|
||||
},
|
||||
{
|
||||
"Segment above line",
|
||||
{ { 0, 10 }, { 10, 10 } },
|
||||
0.0, 5.0, // y = 5
|
||||
false,
|
||||
{ 0, 0 }
|
||||
},
|
||||
{
|
||||
"Segment to left of steep line",
|
||||
{ { 0, 0 }, { 2, 2 } },
|
||||
1.0, 10.0, // y = x + 10
|
||||
false,
|
||||
{ 0, 0 }
|
||||
},
|
||||
|
||||
// Collinear cases (segment lies on line)
|
||||
{
|
||||
"Horizontal segment on horizontal line",
|
||||
{ { 0, 5 }, { 10, 5 } },
|
||||
0.0, 5.0, // y = 5
|
||||
true,
|
||||
{ 5, 5 } // Midpoint
|
||||
},
|
||||
{
|
||||
"Diagonal segment on diagonal line",
|
||||
{ { 0, 0 }, { 10, 10 } },
|
||||
1.0, 0.0, // y = x
|
||||
true,
|
||||
{ 5, 5 } // Midpoint
|
||||
},
|
||||
{
|
||||
"Vertical segment, any line slope (collinear impossible)",
|
||||
{ { 5, 0 }, { 5, 10 } },
|
||||
2.0, -5.0, // y = 2x - 5, passes through (5, 5)
|
||||
true,
|
||||
{ 5, 5 }
|
||||
},
|
||||
|
||||
// Edge cases
|
||||
{
|
||||
"Zero-length segment (point) on line",
|
||||
{ { 3, 7 }, { 3, 7 } },
|
||||
2.0, 1.0, // y = 2x + 1, point (3,7) should be on this line
|
||||
true,
|
||||
{ 3, 7 }
|
||||
},
|
||||
{
|
||||
"Zero-length segment (point) not on line",
|
||||
{ { 3, 5 }, { 3, 5 } },
|
||||
2.0, 1.0, // y = 2x + 1, point (3,5) not on line (should be y=7)
|
||||
false,
|
||||
{ 0, 0 }
|
||||
},
|
||||
{
|
||||
"Line with zero slope (horizontal)",
|
||||
{ { 0, 0 }, { 10, 5 } },
|
||||
0.0, 2.5, // y = 2.5
|
||||
true,
|
||||
{ 5, 2 } // Intersection at x=5, y=2.5 rounded to y=2 or 3
|
||||
},
|
||||
{
|
||||
"Very steep positive slope",
|
||||
{ { 0, 0 }, { 10, 1 } },
|
||||
100.0, -250.0, // y = 100x - 250, intersects at x=2.5
|
||||
true,
|
||||
{ 2, 0 } // Approximately (2.5, 0)
|
||||
},
|
||||
{
|
||||
"Very steep negative slope",
|
||||
{ { 0, 0 }, { 10, 10 } },
|
||||
-100.0, 505.0, // y = -100x + 505, intersects at x=5.05, y≈0
|
||||
true,
|
||||
{ 5, 5 } // Approximately (5.05, 0) but segment has y=5 at x=5
|
||||
},
|
||||
{
|
||||
"Fractional slope",
|
||||
{ { 0, 0 }, { 12, 8 } },
|
||||
0.5, 1.0, // y = 0.5x + 1
|
||||
true,
|
||||
{ 6, 4 } // Intersection where segment y = 2x/3 meets line y = 0.5x + 1
|
||||
},
|
||||
|
||||
// Endpoint intersections
|
||||
{
|
||||
"Line passes through segment start point",
|
||||
{ { 2, 3 }, { 80, 90 } },
|
||||
1.0, 1.0, // y = x + 1, passes through (2,3)
|
||||
true,
|
||||
{ 2, 3 }
|
||||
},
|
||||
{
|
||||
"Line passes through segment end point",
|
||||
{ { 20, 30 }, { 8, 9 } },
|
||||
1.0, 1.0, // y = x + 1, passes through (8,9)
|
||||
true,
|
||||
{ 8, 9 }
|
||||
},
|
||||
{
|
||||
"Line intersects near endpoint",
|
||||
{ { 0, 0 }, { 10, 0 } },
|
||||
0.0, 0.0, // y = 0, same as segment
|
||||
true,
|
||||
{ 5, 0 } // Collinear, returns midpoint
|
||||
},
|
||||
|
||||
// Precision edge cases
|
||||
{
|
||||
"Nearly parallel lines",
|
||||
{ { 0, 0 }, { 1000, 1 } },
|
||||
0.0011, -0.05, // Very slightly different slope
|
||||
true,
|
||||
{ 500, 1 } // At 500, y will round up to 1 in both cases
|
||||
},
|
||||
{
|
||||
"Line intersection outside segment bounds",
|
||||
{ { 5, 5 }, { 10, 10 } },
|
||||
1.0, -10.0, // y = x - 10, would intersect extended line at (15, 5)
|
||||
false,
|
||||
{ 0, 0 }
|
||||
},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
BOOST_DATA_TEST_CASE( SegLineIntersection, boost::unit_test::data::make( seg_line_intersect_cases ), c )
|
||||
{
|
||||
BOOST_CHECK_PREDICATE( SegLineIntersectCorrect, ( c.m_seg )( c.m_slope )( c.m_offset )( c.m_exp_intersect )( c.m_exp_point ) );
|
||||
}
|
||||
|
||||
// Additional focused test cases for specific scenarios
|
||||
BOOST_AUTO_TEST_CASE( IntersectLineVerticalSegments )
|
||||
{
|
||||
// Test vertical segments with various line slopes
|
||||
SEG verticalSeg( { 5, 0 }, { 5, 10 } );
|
||||
VECTOR2I intersection;
|
||||
|
||||
// Horizontal line intersecting vertical segment
|
||||
bool intersects1 = verticalSeg.IntersectsLine( 0.0, 7.0, intersection );
|
||||
BOOST_CHECK( intersects1 );
|
||||
BOOST_CHECK_EQUAL( intersection, VECTOR2I( 5, 7 ) );
|
||||
|
||||
// Diagonal line intersecting vertical segment
|
||||
bool intersects2 = verticalSeg.IntersectsLine( 2.0, -5.0, intersection ); // y = 2x - 5
|
||||
BOOST_CHECK( intersects2 );
|
||||
BOOST_CHECK_EQUAL( intersection, VECTOR2I( 5, 5 ) ); // At x=5: y = 2*5 - 5 = 5
|
||||
|
||||
// Line that misses vertical segment
|
||||
bool intersects3 = verticalSeg.IntersectsLine( 1.0, 20.0, intersection ); // y = x + 20
|
||||
BOOST_CHECK( !intersects3 );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( IntersectLineVerticalSegmentsCorrection )
|
||||
{
|
||||
// Corrected test for vertical segments
|
||||
SEG verticalSeg( { 5, 0 }, { 5, 10 } );
|
||||
VECTOR2I intersection;
|
||||
|
||||
// Line that misses vertical segment (intersection outside y-range)
|
||||
bool intersects1 = verticalSeg.IntersectsLine( 1.0, 20.0, intersection ); // y = x + 20
|
||||
BOOST_CHECK( !intersects1 ); // At x=5: y = 25, which is outside [0,10]
|
||||
|
||||
// Line that intersects within segment bounds
|
||||
bool intersects2 = verticalSeg.IntersectsLine( 0.5, 2.0, intersection ); // y = 0.5x + 2
|
||||
BOOST_CHECK( intersects2 );
|
||||
BOOST_CHECK_EQUAL( intersection, VECTOR2I( 5, 5 ) ); // At x=5: y = 0.5*5 + 2 = 4.5 ≈ 5 (round up)
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( IntersectLineParallelDetection )
|
||||
{
|
||||
// Test parallel line detection using cross products
|
||||
|
||||
// Horizontal segment with horizontal line
|
||||
SEG horizontalSeg( { 0, 5 }, { 10, 5 } );
|
||||
VECTOR2I intersection;
|
||||
|
||||
// Parallel but not collinear
|
||||
bool intersects1 = horizontalSeg.IntersectsLine( 0.0, 8.0, intersection ); // y = 8
|
||||
BOOST_CHECK( !intersects1 );
|
||||
|
||||
// Collinear (segment lies on line)
|
||||
bool intersects2 = horizontalSeg.IntersectsLine( 0.0, 5.0, intersection ); // y = 5
|
||||
BOOST_CHECK( intersects2 );
|
||||
BOOST_CHECK_EQUAL( intersection, VECTOR2I( 5, 5 ) ); // Midpoint
|
||||
|
||||
// Diagonal segment with parallel line
|
||||
SEG diagonalSeg( { 0, 0 }, { 10, 10 } );
|
||||
|
||||
// Parallel but offset
|
||||
bool intersects3 = diagonalSeg.IntersectsLine( 1.0, 3.0, intersection ); // y = x + 3
|
||||
BOOST_CHECK( !intersects3 );
|
||||
|
||||
// Collinear
|
||||
bool intersects4 = diagonalSeg.IntersectsLine( 1.0, 0.0, intersection ); // y = x
|
||||
BOOST_CHECK( intersects4 );
|
||||
BOOST_CHECK_EQUAL( intersection, VECTOR2I( 5, 5 ) ); // Midpoint
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( IntersectLinePrecisionEdgeCases )
|
||||
{
|
||||
// Test precision-sensitive cases
|
||||
|
||||
// Very shallow segment with steep line
|
||||
SEG shallowSeg( { 0, 100 }, { 1000000, 101 } ); // Almost horizontal
|
||||
VECTOR2I intersection;
|
||||
|
||||
bool intersects = shallowSeg.IntersectsLine( 1000.0, -499900.0, intersection );
|
||||
// Line: y = 1000x - 499900
|
||||
// This should intersect around x = 500, y ≈ 100.001
|
||||
|
||||
if( intersects )
|
||||
{
|
||||
BOOST_CHECK( intersection.x >= 0 && intersection.x <= 1000000 );
|
||||
BOOST_CHECK( intersection.y >= 100 && intersection.y <= 101 );
|
||||
}
|
||||
|
||||
// Test with very large coordinates
|
||||
SEG largeSeg( { 1000000, 1000000 }, { 2000000, 2000000 } );
|
||||
bool intersects2 = largeSeg.IntersectsLine( 1.0, 0.0, intersection ); // y = x
|
||||
BOOST_CHECK( intersects2 );
|
||||
BOOST_CHECK_EQUAL( intersection, VECTOR2I( 1500000, 1500000 ) ); // Midpoint
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( IntersectLineZeroLengthSegments )
|
||||
{
|
||||
// Test with zero-length segments (points)
|
||||
|
||||
VECTOR2I point( 10, 20 );
|
||||
SEG pointSeg( point, point );
|
||||
VECTOR2I intersection;
|
||||
|
||||
// Point lies on line
|
||||
bool intersects1 = pointSeg.IntersectsLine( 2.0, 0.0, intersection ); // y = 2x
|
||||
BOOST_CHECK( intersects1 ); // Point (10, 20) is on line y = 2x
|
||||
BOOST_CHECK_EQUAL( intersection, point );
|
||||
|
||||
// Point does not lie on line
|
||||
bool intersects2 = pointSeg.IntersectsLine( 3.0, 0.0, intersection ); // y = 3x
|
||||
BOOST_CHECK( !intersects2 ); // Point (10, 20) not on line y = 3x (would be y = 30)
|
||||
|
||||
// Point on horizontal line
|
||||
bool intersects3 = pointSeg.IntersectsLine( 0.0, 20.0, intersection ); // y = 20
|
||||
BOOST_CHECK( intersects3 );
|
||||
BOOST_CHECK_EQUAL( intersection, point );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
1
thirdparty/CMakeLists.txt
vendored
1
thirdparty/CMakeLists.txt
vendored
@ -58,7 +58,6 @@ add_subdirectory( magic_enum )
|
||||
add_subdirectory( markdown2html )
|
||||
add_subdirectory( nanodbc )
|
||||
add_subdirectory( nanosvg )
|
||||
add_subdirectory( other_math )
|
||||
add_subdirectory( rectpack2d )
|
||||
add_subdirectory( rtree )
|
||||
add_subdirectory( tinyspline_lib )
|
||||
|
16
thirdparty/other_math/CMakeLists.txt
vendored
16
thirdparty/other_math/CMakeLists.txt
vendored
@ -1,16 +0,0 @@
|
||||
|
||||
add_library( othermath OBJECT
|
||||
math_for_graphics.cpp
|
||||
)
|
||||
|
||||
target_include_directories( othermath
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
# kiround is needed
|
||||
target_include_directories( othermath
|
||||
PRIVATE
|
||||
${PROJECT_BINARY_DIR}
|
||||
${PROJECT_SOURCE_DIR}/libs/kimath/include
|
||||
)
|
339
thirdparty/other_math/LICENSE.GPLv2
vendored
339
thirdparty/other_math/LICENSE.GPLv2
vendored
@ -1,339 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
5
thirdparty/other_math/README.txt
vendored
5
thirdparty/other_math/README.txt
vendored
@ -1,5 +0,0 @@
|
||||
This directory contains miscellaneous mathematical functions from various libraries.
|
||||
|
||||
math_for_graphics.cpp/h is from FreePCB (https://www.freepcb.com/) and is licensed under GPLv2.
|
||||
|
||||
SutherlandHodgmanClipPoly is licensed under GPLv2.
|
273
thirdparty/other_math/SutherlandHodgmanClipPoly.h
vendored
273
thirdparty/other_math/SutherlandHodgmanClipPoly.h
vendored
@ -1,273 +0,0 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2004 Sjaak Priester
|
||||
*
|
||||
* This 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 file 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 Tinter; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
********************************************************************************/
|
||||
|
||||
// SutherlandHodgman
|
||||
// Class to perform polygon clipping against an upright rectangular boundary window.
|
||||
// Implementation of Sutherland-Hodgman algorithm (1974).
|
||||
//
|
||||
// Version 1.0 (C) 2004, Sjaak Priester, Amsterdam.
|
||||
// mailto:sjaak@sjaakpriester.nl
|
||||
// http://www.sjaakpriester.nl
|
||||
|
||||
#ifndef __SUTHERLAND_HODGMAN_H__
|
||||
#define __SUTHERLAND_HODGMAN_H__
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
#ifndef _GDIPLUS_H
|
||||
|
||||
// I designed this with GDI+ in mind. However, this particular code doesn't
|
||||
// use GDI+ at all, only some of it's variable types.
|
||||
// These definitions are substitutes for those of GDI+.
|
||||
typedef double REAL;
|
||||
class PointF
|
||||
{
|
||||
public:
|
||||
REAL X;
|
||||
REAL Y;
|
||||
|
||||
PointF() : X( 0 )
|
||||
, Y( 0 ) { }
|
||||
PointF( const PointF& p ) : X( p.X )
|
||||
, Y( p.Y ) { }
|
||||
PointF( REAL x, REAL y ) : X( x )
|
||||
, Y( y ) { }
|
||||
PointF operator+( const PointF& p ) const { return PointF( X + p.X, Y + p.Y ); }
|
||||
PointF operator-( const PointF& p ) const { return PointF( X - p.X, Y - p.Y ); }
|
||||
bool Equals( const PointF& p ) { return (X == p.X) && (Y == p.Y); }
|
||||
};
|
||||
|
||||
class RectF
|
||||
{
|
||||
public:
|
||||
REAL X;
|
||||
REAL Y;
|
||||
REAL Width;
|
||||
REAL Height;
|
||||
|
||||
RectF() { X = 0, Y = 0, Height = 0, Width = 0; }
|
||||
RectF( const RectF& r )
|
||||
{
|
||||
X = r.X; Y = r.Y; Height = r.Height, Width = r.Width;
|
||||
}
|
||||
|
||||
|
||||
RectF( REAL x, REAL y, REAL w, REAL h ) : X( x ), Y( y ),Width( w ), Height( h )
|
||||
{ }
|
||||
REAL GetLeft() const { return X; }
|
||||
REAL GetTop() const { return Y; }
|
||||
REAL GetRight() const { return X + Width; }
|
||||
REAL GetBottom() const { return Y + Height; }
|
||||
};
|
||||
|
||||
#endif // _GDIPLUS_H
|
||||
|
||||
typedef std::vector<PointF> pointVector;
|
||||
typedef std::vector<PointF>::iterator pointIterator;
|
||||
typedef std::vector<PointF>::const_iterator cpointIterator;
|
||||
|
||||
class SutherlandHodgman
|
||||
{
|
||||
public:
|
||||
|
||||
// Constructor. Parameter is the boundary rectangle.
|
||||
// SutherlandHodgman expects a 'normalized' boundary rectangle, meaning
|
||||
// that boundaries.GetRight() > boundaries.GetLeft() and
|
||||
// boundaries.GetBottom() > boundaries.GetTop().
|
||||
// In other words: boundary.Width > 0 and boundaries.Height > 0.
|
||||
// If this is violated, nothing will be output.
|
||||
SutherlandHodgman( RectF& boundaries ) :
|
||||
m_stageBottom( m_stageOut, boundaries.GetBottom() )
|
||||
, /* Initialize each stage */ m_stageLeft( m_stageBottom, boundaries.GetLeft() )
|
||||
, /* with its next stage and */ m_stageTop( m_stageLeft, boundaries.GetTop() )
|
||||
, /* the boundary position. */ m_stageRight( m_stageTop, boundaries.GetRight() )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void Clip( pointVector& input, pointVector& clipped )
|
||||
{
|
||||
clipped.clear();
|
||||
m_stageOut.SetDestination( &clipped );
|
||||
|
||||
// Clip each input vertex.
|
||||
for( cpointIterator it = input.begin(); it != input.end(); ++it )
|
||||
m_stageRight.HandleVertex( *it );
|
||||
|
||||
// Do the final step.
|
||||
m_stageRight.Finalize();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// Implementation of a horizontal boundary (top or bottom).
|
||||
// Comp is a std::binary_function object, comparing its two parameters, f.i. std::less.
|
||||
|
||||
template <class Comp>
|
||||
|
||||
class BoundaryHor
|
||||
{
|
||||
public:
|
||||
BoundaryHor( REAL y ) : m_Y( y ) { }
|
||||
bool IsInside( const PointF& pnt ) const
|
||||
{
|
||||
return Comp ()( pnt.Y, m_Y );
|
||||
} // return true if pnt.Y is at the inside of the boundary
|
||||
PointF Intersect( const PointF& p0, const PointF& p1 ) const // return intersection point of line p0...p1 with boundary
|
||||
{ // assumes p0...p1 is not strictly horizontal
|
||||
PointF d = p1 - p0;
|
||||
REAL xslope = d.X / d.Y;
|
||||
|
||||
PointF r;
|
||||
|
||||
r.Y = m_Y;
|
||||
r.X = p0.X + xslope * (m_Y - p0.Y);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
REAL m_Y;
|
||||
};
|
||||
|
||||
// Implementation of a vertical boundary (left or right).
|
||||
template <class Comp>
|
||||
class BoundaryVert
|
||||
{
|
||||
public:
|
||||
BoundaryVert( REAL x ) : m_X( x )
|
||||
{ }
|
||||
bool IsInside( const PointF& pnt ) const
|
||||
{
|
||||
return Comp() ( pnt.X, m_X );
|
||||
}
|
||||
PointF Intersect( const PointF& p0, const PointF& p1 ) const // assumes p0...p1 is not strictly vertical
|
||||
{
|
||||
PointF d = p1 - p0;
|
||||
REAL yslope = d.Y / d.X;
|
||||
|
||||
PointF r;
|
||||
|
||||
r.X = m_X;
|
||||
r.Y = p0.Y + yslope * (m_X - p0.X);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
REAL m_X;
|
||||
};
|
||||
|
||||
// This template class is the workhorse of the algorithm. It handles the clipping against one boundary.
|
||||
// Boundary is either BoundaryHor or BoundaryVert, Stage is the next ClipStage, or the output stage.
|
||||
template <class Boundary, class Stage>
|
||||
class ClipStage : private Boundary
|
||||
{
|
||||
public:
|
||||
ClipStage( Stage& nextStage, REAL position ) :
|
||||
Boundary( position ) , m_NextStage( nextStage ), m_bFirst( true ), m_bPreviousInside( false )
|
||||
{ }
|
||||
|
||||
// Function to handle one vertex
|
||||
void HandleVertex( const PointF& pntCurrent )
|
||||
{
|
||||
bool bCurrentInside = this->IsInside( pntCurrent ); // See if vertex is inside the boundary.
|
||||
|
||||
if( m_bFirst ) // If this is the first vertex...
|
||||
{
|
||||
m_pntFirst = pntCurrent; // ... just remember it,...
|
||||
|
||||
m_bFirst = false;
|
||||
}
|
||||
else // Common cases, not the first vertex.
|
||||
{
|
||||
if( bCurrentInside ) // If this vertex is inside...
|
||||
{
|
||||
if( !m_bPreviousInside ) // ... and the previous one was outside
|
||||
m_NextStage.HandleVertex( this->Intersect( m_pntPrevious, pntCurrent ) );
|
||||
|
||||
// ... first output the intersection point.
|
||||
|
||||
m_NextStage.HandleVertex( pntCurrent ); // Output the current vertex.
|
||||
}
|
||||
else if( m_bPreviousInside ) // If this vertex is outside, and the previous one was inside...
|
||||
m_NextStage.HandleVertex( this->Intersect( m_pntPrevious, pntCurrent ) );
|
||||
|
||||
// ... output the intersection point.
|
||||
|
||||
// If neither current vertex nor the previous one are inside, output nothing.
|
||||
}
|
||||
m_pntPrevious = pntCurrent; // Be prepared for next vertex.
|
||||
m_bPreviousInside = bCurrentInside;
|
||||
}
|
||||
|
||||
|
||||
void Finalize()
|
||||
{
|
||||
HandleVertex( m_pntFirst ); // Close the polygon.
|
||||
m_NextStage.Finalize(); // Delegate to the next stage.
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
Stage& m_NextStage; // the next stage
|
||||
bool m_bFirst; // true if no vertices have been handled
|
||||
PointF m_pntFirst; // the first vertex
|
||||
PointF m_pntPrevious; // the previous vertex
|
||||
bool m_bPreviousInside; // true if the previous vertex was inside the Boundary
|
||||
};
|
||||
|
||||
class OutputStage
|
||||
{
|
||||
public:
|
||||
OutputStage() : m_pDest( 0 ) { }
|
||||
void SetDestination( pointVector* pDest ) { m_pDest = pDest; }
|
||||
void HandleVertex( const PointF& pnt ) { m_pDest->push_back( pnt ); } // Append the vertex to the output container.
|
||||
void Finalize() { } // Do nothing.
|
||||
private:
|
||||
pointVector* m_pDest;
|
||||
};
|
||||
|
||||
// These typedefs define the four boundaries. In keeping up with the GDI/GDI+ interpretation of
|
||||
// rectangles, we include the left and top boundaries, but not the right and bottom boundaries.
|
||||
// In other words: a vertex on the left boundary is considered to be inside, but a vertex
|
||||
// on the right boundary is considered to be outside.
|
||||
typedef BoundaryVert<std::less<REAL> > BoundaryRight;
|
||||
typedef BoundaryHor<std::greater_equal<REAL> > BoundaryTop;
|
||||
typedef BoundaryVert<std::greater_equal<REAL> > BoundaryLeft;
|
||||
typedef BoundaryHor<std::less<REAL> > BoundaryBottom;
|
||||
|
||||
// Next typedefs define the four stages. First template parameter is the boundary,
|
||||
// second template parameter is the next stage.
|
||||
typedef ClipStage<BoundaryBottom, OutputStage> ClipBottom;
|
||||
typedef ClipStage<BoundaryLeft, ClipBottom> ClipLeft;
|
||||
typedef ClipStage<BoundaryTop, ClipLeft> ClipTop;
|
||||
typedef ClipStage<BoundaryRight, ClipTop> ClipRight;
|
||||
|
||||
// Our data members.
|
||||
OutputStage m_stageOut;
|
||||
ClipBottom m_stageBottom;
|
||||
ClipLeft m_stageLeft;
|
||||
ClipTop m_stageTop;
|
||||
ClipRight m_stageRight;
|
||||
};
|
||||
|
||||
#endif
|
497
thirdparty/other_math/math_for_graphics.cpp
vendored
497
thirdparty/other_math/math_for_graphics.cpp
vendored
@ -1,497 +0,0 @@
|
||||
// math for graphics utility routines and RC, from FreePCB
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <cmath>
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
#include <cstdlib> // for abs function on ints
|
||||
#include <algorithm>
|
||||
#include <math_for_graphics.h>
|
||||
|
||||
#include <math/util.h>
|
||||
|
||||
static bool InRange( double x, double xi, double xf );
|
||||
|
||||
|
||||
/* 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* 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 true;
|
||||
}
|
||||
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<xf) )
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// oblique line
|
||||
if( (xx>=xi && xx>xf) || (xx<=xi && xx<xf)
|
||||
|| (yy>yi && yy>yf) || (yy<yi && yy<yf) )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// vertical line segment
|
||||
if( bVert )
|
||||
return false;
|
||||
|
||||
xx = xi;
|
||||
yy = a + b * xx;
|
||||
|
||||
if( (yy>=yi && yy>yf) || (yy<=yi && yy<yf) )
|
||||
return false;
|
||||
}
|
||||
|
||||
x1 = xx;
|
||||
y1 = yy;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Function TestForIntersectionOfStraightLineSegments
|
||||
* Test for intersection of line segments
|
||||
* If lines are parallel, returns false
|
||||
* If true, returns also intersection coords in x, y
|
||||
* if false, returns min. distance in dist (may be 0.0 if parallel)
|
||||
*/
|
||||
bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y1f,
|
||||
int x2i, int y2i, int x2f, int y2f,
|
||||
int* x, int* y, double* d )
|
||||
{
|
||||
double a, b, dist;
|
||||
|
||||
// first, test for intersection
|
||||
if( x1i == x1f && x2i == x2f )
|
||||
{
|
||||
// both segments are vertical, can't intersect
|
||||
}
|
||||
else if( y1i == y1f && y2i == y2f )
|
||||
{
|
||||
// both segments are horizontal, can't intersect
|
||||
}
|
||||
else if( x1i == x1f && y2i == y2f )
|
||||
{
|
||||
// first seg. vertical, second horizontal, see if they cross
|
||||
if( InRange( x1i, x2i, x2f )
|
||||
&& InRange( y2i, y1i, y1f ) )
|
||||
{
|
||||
if( x )
|
||||
*x = x1i;
|
||||
|
||||
if( y )
|
||||
*y = y2i;
|
||||
|
||||
if( d )
|
||||
*d = 0.0;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if( y1i == y1f && x2i == x2f )
|
||||
{
|
||||
// first seg. horizontal, second vertical, see if they cross
|
||||
if( InRange( y1i, y2i, y2f )
|
||||
&& InRange( x2i, x1i, x1f ) )
|
||||
{
|
||||
if( x )
|
||||
*x = x2i;
|
||||
|
||||
if( y )
|
||||
*y = y1i;
|
||||
|
||||
if( d )
|
||||
*d = 0.0;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if( x1i == x1f )
|
||||
{
|
||||
// first segment vertical, second oblique
|
||||
// get a and b for second line segment, so that y = a + bx;
|
||||
b = double( y2f - y2i ) / (x2f - x2i);
|
||||
a = (double) y2i - b * x2i;
|
||||
|
||||
double x1, y1;
|
||||
bool test = FindLineSegmentIntersection( a, b, x1i, y1i, x1f, y1f,
|
||||
x1, y1 );
|
||||
|
||||
if( test )
|
||||
{
|
||||
if( InRange( y1, y1i, y1f ) && InRange( x1, x2i, x2f ) && InRange( y1, y2i, y2f ) )
|
||||
{
|
||||
if( x )
|
||||
*x = KiROUND( x1 );
|
||||
|
||||
if( y )
|
||||
*y = KiROUND( y1 );
|
||||
|
||||
if( d )
|
||||
*d = 0.0;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( y1i == y1f )
|
||||
{
|
||||
// first segment horizontal, second oblique
|
||||
// get a and b for second line segment, so that y = a + bx;
|
||||
b = double( y2f - y2i ) / (x2f - x2i);
|
||||
a = (double) y2i - b * x2i;
|
||||
|
||||
double x1, y1;
|
||||
bool test = FindLineSegmentIntersection( a, b, x1i, y1i, x1f, y1f, x1, y1 );
|
||||
|
||||
if( test )
|
||||
{
|
||||
if( InRange( x1, x1i, x1f ) && InRange( x1, x2i, x2f ) && InRange( y1, y2i, y2f ) )
|
||||
{
|
||||
if( x )
|
||||
*x = KiROUND( x1 );
|
||||
|
||||
if( y )
|
||||
*y = KiROUND( y1 );
|
||||
|
||||
if( d )
|
||||
*d = 0.0;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( x2i == x2f )
|
||||
{
|
||||
// second segment vertical, first oblique
|
||||
// get a and b for first line segment, so that y = a + bx;
|
||||
b = double( y1f - y1i ) / (x1f - x1i);
|
||||
a = (double) y1i - b * x1i;
|
||||
|
||||
double x1, y1;
|
||||
bool test = FindLineSegmentIntersection( a, b, x2i, y2i, x2f, y2f, x1, y1 );
|
||||
|
||||
if( test )
|
||||
{
|
||||
if( InRange( x1, x1i, x1f ) && InRange( y1, y1i, y1f ) && InRange( y1, y2i, y2f ) )
|
||||
{
|
||||
if( x )
|
||||
*x = KiROUND( x1 );
|
||||
|
||||
if( y )
|
||||
*y = KiROUND( y1 );
|
||||
|
||||
if( d )
|
||||
*d = 0.0;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( y2i == y2f )
|
||||
{
|
||||
// second segment horizontal, first oblique
|
||||
// get a and b for second line segment, so that y = a + bx;
|
||||
b = double( y1f - y1i ) / (x1f - x1i);
|
||||
a = (double) y1i - b * x1i;
|
||||
|
||||
double x1, y1;
|
||||
bool test = FindLineSegmentIntersection( a, b, x2i, y2i, x2f, y2f, x1, y1 );
|
||||
|
||||
if( test )
|
||||
{
|
||||
if( InRange( x1, x1i, x1f ) && InRange( y1, y1i, y1f ) )
|
||||
{
|
||||
if( x )
|
||||
*x = KiROUND( x1 );
|
||||
|
||||
if( y )
|
||||
*y = KiROUND( y1 );
|
||||
|
||||
if( d )
|
||||
*d = 0.0;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// both segments oblique
|
||||
if( long( y1f - y1i ) * (x2f - x2i) != long( y2f - y2i ) * (x1f - x1i) )
|
||||
{
|
||||
// not parallel, get a and b for first line segment, so that y = a + bx;
|
||||
b = double( y1f - y1i ) / (x1f - x1i);
|
||||
a = (double) y1i - b * x1i;
|
||||
|
||||
double x1, y1;
|
||||
bool test = FindLineSegmentIntersection( a, b, x2i, y2i, x2f, y2f, x1, y1 );
|
||||
|
||||
// both segments oblique
|
||||
if( test )
|
||||
{
|
||||
if( InRange( x1, x1i, x1f ) && InRange( y1, y1i, y1f ) )
|
||||
{
|
||||
if( x )
|
||||
*x = KiROUND( x1 );
|
||||
|
||||
if( y )
|
||||
*y = KiROUND( y1 );
|
||||
|
||||
if( d )
|
||||
*d = 0.0;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// don't intersect, get shortest distance between each endpoint and the other line segment
|
||||
dist = GetPointToLineSegmentDistance( x1i, y1i, x2i, y2i, x2f, y2f );
|
||||
|
||||
double xx = x1i;
|
||||
double yy = y1i;
|
||||
double dd = GetPointToLineSegmentDistance( x1f, y1f, x2i, y2i, x2f, y2f );
|
||||
|
||||
if( dd < dist )
|
||||
{
|
||||
dist = dd;
|
||||
xx = x1f;
|
||||
yy = y1f;
|
||||
}
|
||||
|
||||
dd = GetPointToLineSegmentDistance( x2i, y2i, x1i, y1i, x1f, y1f );
|
||||
|
||||
if( dd < dist )
|
||||
{
|
||||
dist = dd;
|
||||
xx = x2i;
|
||||
yy = y2i;
|
||||
}
|
||||
|
||||
dd = GetPointToLineSegmentDistance( x2f, y2f, x1i, y1i, x1f, y1f );
|
||||
|
||||
if( dd < dist )
|
||||
{
|
||||
dist = dd;
|
||||
xx = x2f;
|
||||
yy = y2f;
|
||||
}
|
||||
|
||||
if( x )
|
||||
*x = KiROUND( xx );
|
||||
|
||||
if( y )
|
||||
*y = KiROUND( yy );
|
||||
|
||||
if( d )
|
||||
*d = dist;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* Function GetClearanceBetweenSegments
|
||||
* Get clearance between 2 segments
|
||||
* Returns coordinates of the closest point between these 2 segments in x, y
|
||||
* If clearance > 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;
|
||||
}
|
71
thirdparty/other_math/math_for_graphics.h
vendored
71
thirdparty/other_math/math_for_graphics.h
vendored
@ -1,71 +0,0 @@
|
||||
#ifndef MATH_FOR_GRAPHICS_H
|
||||
#define MATH_FOR_GRAPHICS_H
|
||||
// math stuff for graphics, from FreePCB
|
||||
|
||||
/* 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
|
||||
* 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 * dist=NULL );
|
||||
|
||||
/* 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 );
|
||||
|
||||
/**
|
||||
* Function TestForIntersectionOfStraightLineSegments
|
||||
* Test for intersection of line segments
|
||||
* If lines are parallel, returns false
|
||||
* If true, returns also intersection coords in x, y
|
||||
* if false, returns min. distance in dist (may be 0.0 if parallel)
|
||||
* and coords on nearest point in one of the segments in (x,y)
|
||||
* @param x1i, y1i, x1f, y1f = integer coordinates of the first segment
|
||||
* @param x2i, y2i, x2f, y2f = integer coordinates of the other segment
|
||||
* @param x, y = pointers on 2 integer to store the intersection coordinates (can be NULL)
|
||||
* @param dist = pointeur on a double to store the dist.
|
||||
* @return true if intersect.
|
||||
*/
|
||||
bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y1f,
|
||||
int x2i, int y2i, int x2f, int y2f,
|
||||
int * x=NULL, int * y=NULL, double * dist=NULL );
|
||||
|
||||
/* Function GetClearanceBetweenSegments
|
||||
* Get clearance between 2 segments
|
||||
* Returns coordinates of the closest point between these 2 segments in x, y
|
||||
* If clearance > 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 );
|
||||
|
||||
/**
|
||||
* Function GetPointToLineSegmentDistance
|
||||
* Get distance between line segment and point
|
||||
* @param x,y = point
|
||||
* @param xi,yi, xf,yf = the end-points of the line segment
|
||||
* @return the distance
|
||||
*/
|
||||
double GetPointToLineSegmentDistance( int x, int y, int xi, int yi, int xf, int yf );
|
||||
|
||||
/* 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 * xp=NULL, double * yp=NULL );
|
||||
|
||||
inline double Distance( double x1, double y1, double x2, double y2 )
|
||||
{
|
||||
return hypot( x1 - x2, y1 - y2 );
|
||||
}
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user