2013-09-10 11:43:09 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2013 CERN
|
2021-01-06 01:40:23 +00:00
|
|
|
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
|
2013-09-10 11:43:09 +00:00
|
|
|
*
|
2021-01-25 12:42:36 +00:00
|
|
|
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
|
|
|
*
|
2013-09-10 11:43:09 +00:00
|
|
|
* 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, you may find one here:
|
|
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef __SEG_H
|
|
|
|
#define __SEG_H
|
|
|
|
|
2020-01-07 17:12:59 +00:00
|
|
|
#include <math.h> // for sqrt
|
|
|
|
#include <stdlib.h> // for abs
|
|
|
|
#include <ostream> // for operator<<, ostream, basic_os...
|
|
|
|
#include <type_traits> // for swap
|
2013-09-10 11:43:09 +00:00
|
|
|
|
2017-11-01 11:14:16 +00:00
|
|
|
#include <core/optional.h>
|
2020-01-07 17:12:59 +00:00
|
|
|
#include <math/util.h> // for rescale
|
|
|
|
#include <math/vector2d.h>
|
2013-09-10 11:43:09 +00:00
|
|
|
|
2017-11-01 11:14:16 +00:00
|
|
|
typedef OPT<VECTOR2I> OPT_VECTOR2I;
|
2013-09-10 11:43:09 +00:00
|
|
|
|
2013-09-27 16:51:21 +00:00
|
|
|
class SEG
|
|
|
|
{
|
2013-10-14 14:13:35 +00:00
|
|
|
public:
|
2018-11-28 12:11:43 +00:00
|
|
|
using ecoord = VECTOR2I::extended_type;
|
2013-10-14 14:13:35 +00:00
|
|
|
friend inline std::ostream& operator<<( std::ostream& aStream, const SEG& aSeg );
|
2013-10-14 11:43:57 +00:00
|
|
|
|
2017-04-14 12:42:57 +00:00
|
|
|
/* Start and the of the segment. Public, to make access simpler.
|
2013-10-14 14:13:35 +00:00
|
|
|
*/
|
2017-04-14 12:42:57 +00:00
|
|
|
VECTOR2I A;
|
|
|
|
VECTOR2I B;
|
2013-10-14 11:43:57 +00:00
|
|
|
|
2021-01-25 12:42:36 +00:00
|
|
|
/**
|
|
|
|
* Create an empty (0, 0) segment.
|
2013-10-14 14:13:35 +00:00
|
|
|
*/
|
2017-04-14 12:42:57 +00:00
|
|
|
SEG()
|
2013-10-14 14:13:35 +00:00
|
|
|
{
|
|
|
|
m_index = -1;
|
|
|
|
}
|
2013-10-14 11:43:57 +00:00
|
|
|
|
2013-10-14 14:13:35 +00:00
|
|
|
/**
|
2021-01-25 12:42:36 +00:00
|
|
|
* Create a segment between (aX1, aY1) and (aX2, aY2).
|
2013-10-14 14:13:35 +00:00
|
|
|
*/
|
2014-11-14 19:19:00 +00:00
|
|
|
SEG( int aX1, int aY1, int aX2, int aY2 ) :
|
2020-12-12 03:43:16 +00:00
|
|
|
A( VECTOR2I( aX1, aY1 ) ),
|
|
|
|
B( VECTOR2I( aX2, aY2 ) )
|
2013-10-14 14:13:35 +00:00
|
|
|
{
|
|
|
|
m_index = -1;
|
|
|
|
}
|
2013-10-14 11:43:57 +00:00
|
|
|
|
2013-10-14 18:40:36 +00:00
|
|
|
/**
|
2021-01-25 12:42:36 +00:00
|
|
|
* Create a segment between (aA) and (aB).
|
2013-10-14 18:40:36 +00:00
|
|
|
*/
|
2020-12-12 03:43:16 +00:00
|
|
|
SEG( const VECTOR2I& aA, const VECTOR2I& aB ) :
|
|
|
|
A( aA ),
|
|
|
|
B( aB )
|
2013-10-14 18:40:36 +00:00
|
|
|
{
|
|
|
|
m_index = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-01-25 12:42:36 +00:00
|
|
|
* Create a segment between (aA) and (aB), referenced to a multi-segment shape.
|
|
|
|
*
|
2013-10-14 18:40:36 +00:00
|
|
|
* @param aA reference to the start point in the parent shape
|
|
|
|
* @param aB reference to the end point in the parent shape
|
|
|
|
* @param aIndex index of the segment within the parent shape
|
|
|
|
*/
|
2020-12-12 03:43:16 +00:00
|
|
|
SEG( const VECTOR2I& aA, const VECTOR2I& aB, int aIndex ) :
|
|
|
|
A( aA ),
|
|
|
|
B( aB )
|
2013-10-14 18:40:36 +00:00
|
|
|
{
|
|
|
|
m_index = aIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-01-25 12:42:36 +00:00
|
|
|
* Copy constructor.
|
2013-10-14 18:40:36 +00:00
|
|
|
*/
|
2020-12-12 03:43:16 +00:00
|
|
|
SEG( const SEG& aSeg ) :
|
|
|
|
A( aSeg.A ),
|
|
|
|
B( aSeg.B ),
|
|
|
|
m_index( aSeg.m_index )
|
2013-10-14 18:40:36 +00:00
|
|
|
{
|
|
|
|
}
|
2013-10-14 11:43:57 +00:00
|
|
|
|
2013-10-14 18:40:36 +00:00
|
|
|
SEG& operator=( const SEG& aSeg )
|
|
|
|
{
|
|
|
|
A = aSeg.A;
|
|
|
|
B = aSeg.B;
|
|
|
|
m_index = aSeg.m_index;
|
2014-11-14 19:19:00 +00:00
|
|
|
|
2013-10-14 18:40:36 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2013-10-14 11:43:57 +00:00
|
|
|
|
2017-11-23 16:20:27 +00:00
|
|
|
bool operator==( const SEG& aSeg ) const
|
|
|
|
{
|
|
|
|
return (A == aSeg.A && B == aSeg.B) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=( const SEG& aSeg ) const
|
|
|
|
{
|
|
|
|
return (A != aSeg.A || B != aSeg.B);
|
|
|
|
}
|
|
|
|
|
2020-04-28 21:43:29 +00:00
|
|
|
static SEG::ecoord Square( int a )
|
|
|
|
{
|
|
|
|
return ecoord( a ) * a;
|
|
|
|
}
|
|
|
|
|
2013-10-14 18:40:36 +00:00
|
|
|
/**
|
2021-01-25 12:42:36 +00:00
|
|
|
* Compute the perpendicular projection point of aP on a line passing through
|
2013-10-14 18:40:36 +00:00
|
|
|
* ends of the segment.
|
2021-01-25 12:42:36 +00:00
|
|
|
*
|
2013-10-14 18:40:36 +00:00
|
|
|
* @param aP point to project
|
|
|
|
* @return projected point
|
|
|
|
*/
|
|
|
|
VECTOR2I LineProject( const VECTOR2I& aP ) const;
|
2013-10-14 11:43:57 +00:00
|
|
|
|
2013-10-14 18:40:36 +00:00
|
|
|
/**
|
2021-01-25 12:42:36 +00:00
|
|
|
* Determine on which side of directed line passing via segment ends point aP lies.
|
2013-10-14 18:40:36 +00:00
|
|
|
*
|
|
|
|
* @param aP point to determine the orientation wrs to self
|
|
|
|
* @return: < 0: left, 0 : on the line, > 0 : right
|
|
|
|
*/
|
|
|
|
int Side( const VECTOR2I& aP ) const
|
|
|
|
{
|
|
|
|
const ecoord det = ( B - A ).Cross( aP - A );
|
2013-10-14 11:43:57 +00:00
|
|
|
|
2013-10-14 18:40:36 +00:00
|
|
|
return det < 0 ? -1 : ( det > 0 ? 1 : 0 );
|
|
|
|
}
|
2013-10-14 11:43:57 +00:00
|
|
|
|
2013-10-14 18:40:36 +00:00
|
|
|
/**
|
2021-01-25 12:42:36 +00:00
|
|
|
* Return the closest Euclidean distance between point aP and the line defined by
|
2013-10-14 18:40:36 +00:00
|
|
|
* the ends of segment (this).
|
2021-01-25 12:42:36 +00:00
|
|
|
*
|
2017-06-18 07:04:42 +00:00
|
|
|
* @param aP the point to test
|
2013-10-14 18:40:36 +00:00
|
|
|
* @param aDetermineSide: when true, the sign of the returned value indicates
|
|
|
|
* the side of the line at which we are (negative = left)
|
|
|
|
* @return the distance
|
|
|
|
*/
|
|
|
|
int LineDistance( const VECTOR2I& aP, bool aDetermineSide = false ) const;
|
|
|
|
|
2021-03-31 20:13:08 +00:00
|
|
|
/**
|
|
|
|
* Determine the smallest angle between two segments (result in degrees)
|
|
|
|
*
|
|
|
|
* @param aOther point to determine the orientation wrs to self
|
|
|
|
* @return smallest angle between this and aOther (degrees)
|
|
|
|
*/
|
|
|
|
double AngleDegrees( const SEG& aOther ) const;
|
|
|
|
|
2013-10-14 18:40:36 +00:00
|
|
|
/**
|
2021-01-25 12:42:36 +00:00
|
|
|
* Compute a point on the segment (this) that is closest to point \a aP.
|
2013-10-14 18:40:36 +00:00
|
|
|
*
|
2017-06-18 07:04:42 +00:00
|
|
|
* @return the nearest point
|
2013-10-14 18:40:36 +00:00
|
|
|
*/
|
|
|
|
const VECTOR2I NearestPoint( const VECTOR2I &aP ) const;
|
|
|
|
|
2018-11-28 12:11:43 +00:00
|
|
|
/**
|
2021-01-25 12:42:36 +00:00
|
|
|
* Compute a point on the segment (this) that is closest to any point on \a aSeg.
|
|
|
|
*
|
2018-11-28 12:11:43 +00:00
|
|
|
* @return the nearest point
|
|
|
|
*/
|
|
|
|
const VECTOR2I NearestPoint( const SEG &aSeg ) const;
|
|
|
|
|
2021-04-11 12:28:32 +00:00
|
|
|
/**
|
|
|
|
* Reflect a point using this segment as axis.
|
|
|
|
*
|
|
|
|
* @return the reflected point
|
|
|
|
*/
|
|
|
|
const VECTOR2I ReflectPoint( const VECTOR2I& aP ) const;
|
|
|
|
|
2013-10-14 18:40:36 +00:00
|
|
|
/**
|
2021-01-25 12:42:36 +00:00
|
|
|
* Compute intersection point of segment (this) with segment \a aSeg.
|
2013-10-14 18:40:36 +00:00
|
|
|
*
|
|
|
|
* @param aSeg: segment to intersect with
|
|
|
|
* @param aIgnoreEndpoints: don't treat corner cases (i.e. end of one segment touching the
|
|
|
|
* other) as intersections.
|
|
|
|
* @param aLines: treat segments as infinite lines
|
|
|
|
* @return intersection point, if exists
|
|
|
|
*/
|
|
|
|
OPT_VECTOR2I Intersect( const SEG& aSeg, bool aIgnoreEndpoints = false,
|
|
|
|
bool aLines = false ) const;
|
|
|
|
|
|
|
|
/**
|
2021-01-25 12:42:36 +00:00
|
|
|
* Compute the intersection point of lines passing through ends of (this) and \a aSeg.
|
2013-10-14 18:40:36 +00:00
|
|
|
*
|
|
|
|
* @param aSeg segment defining the line to intersect with
|
|
|
|
* @return intersection point, if exists
|
|
|
|
*/
|
|
|
|
OPT_VECTOR2I IntersectLines( const SEG& aSeg ) const
|
|
|
|
{
|
|
|
|
return Intersect( aSeg, false, true );
|
|
|
|
}
|
2013-10-14 11:43:57 +00:00
|
|
|
|
2021-01-03 01:21:20 +00:00
|
|
|
/**
|
2021-01-25 12:42:36 +00:00
|
|
|
* Compute a segment perpendicular to this one, passing through point \a aP.
|
|
|
|
*
|
2021-01-03 01:21:20 +00:00
|
|
|
* @param aP Point through which the new segment will pass
|
|
|
|
* @return SEG perpendicular to this passing through point aP
|
|
|
|
*/
|
|
|
|
SEG PerpendicularSeg( const VECTOR2I& aP ) const;
|
|
|
|
|
|
|
|
/**
|
2021-01-25 12:42:36 +00:00
|
|
|
* Compute a segment parallel to this one, passing through point \a aP.
|
|
|
|
*
|
2021-01-03 01:21:20 +00:00
|
|
|
* @param aP Point through which the new segment will pass
|
|
|
|
* @return SEG parallel to this passing through point aP
|
|
|
|
*/
|
|
|
|
SEG ParallelSeg( const VECTOR2I& aP ) const;
|
|
|
|
|
2020-07-02 16:06:09 +00:00
|
|
|
bool Collide( const SEG& aSeg, int aClearance, int* aActual = nullptr ) const;
|
2013-10-14 11:43:57 +00:00
|
|
|
|
2014-03-12 09:05:09 +00:00
|
|
|
ecoord SquaredDistance( const SEG& aSeg ) const;
|
|
|
|
|
2013-10-14 18:40:36 +00:00
|
|
|
/**
|
2021-01-25 12:42:36 +00:00
|
|
|
* Compute minimum Euclidean distance to segment \a aSeg.
|
2013-10-14 18:40:36 +00:00
|
|
|
*
|
|
|
|
* @param aSeg other segment
|
|
|
|
* @return minimum distance
|
|
|
|
*/
|
|
|
|
int Distance( const SEG& aSeg ) const
|
|
|
|
{
|
|
|
|
return sqrt( SquaredDistance( aSeg ) );
|
|
|
|
}
|
2013-10-14 11:43:57 +00:00
|
|
|
|
2014-03-12 09:05:09 +00:00
|
|
|
ecoord SquaredDistance( const VECTOR2I& aP ) const
|
|
|
|
{
|
|
|
|
return ( NearestPoint( aP ) - aP ).SquaredEuclideanNorm();
|
|
|
|
}
|
|
|
|
|
2013-10-14 18:40:36 +00:00
|
|
|
/**
|
2021-01-25 12:42:36 +00:00
|
|
|
* Compute minimum Euclidean distance to point \a aP.
|
2013-10-14 18:40:36 +00:00
|
|
|
*
|
|
|
|
* @param aP the point
|
|
|
|
* @return minimum distance
|
|
|
|
*/
|
|
|
|
int Distance( const VECTOR2I& aP ) const
|
|
|
|
{
|
|
|
|
return sqrt( SquaredDistance( aP ) );
|
|
|
|
}
|
2013-10-14 11:43:57 +00:00
|
|
|
|
2015-02-18 16:53:46 +00:00
|
|
|
void CanonicalCoefs( ecoord& qA, ecoord& qB, ecoord& qC ) const
|
2015-02-17 23:40:11 +00:00
|
|
|
{
|
2020-10-05 10:41:14 +00:00
|
|
|
qA = ecoord{ A.y } - B.y;
|
|
|
|
qB = ecoord{ B.x } - A.x;
|
2015-02-17 23:40:11 +00:00
|
|
|
qC = -qA * A.x - qB * A.y;
|
|
|
|
}
|
|
|
|
|
2013-10-14 18:40:36 +00:00
|
|
|
/**
|
2021-01-25 12:42:36 +00:00
|
|
|
* Check if segment aSeg lies on the same line as (this).
|
2013-10-14 18:40:36 +00:00
|
|
|
*
|
2021-01-25 12:42:36 +00:00
|
|
|
* @param aSeg the segment to check colinearity with
|
2013-10-14 18:40:36 +00:00
|
|
|
* @return true, when segments are collinear.
|
|
|
|
*/
|
|
|
|
bool Collinear( const SEG& aSeg ) const
|
|
|
|
{
|
2015-02-17 23:40:11 +00:00
|
|
|
ecoord qa, qb, qc;
|
2015-02-18 16:53:46 +00:00
|
|
|
CanonicalCoefs( qa, qb, qc );
|
|
|
|
|
2014-11-14 18:18:31 +00:00
|
|
|
ecoord d1 = std::abs( aSeg.A.x * qa + aSeg.A.y * qb + qc );
|
|
|
|
ecoord d2 = std::abs( aSeg.B.x * qa + aSeg.B.y * qb + qc );
|
|
|
|
|
|
|
|
return ( d1 <= 1 && d2 <= 1 );
|
|
|
|
}
|
|
|
|
|
2015-02-17 23:40:11 +00:00
|
|
|
bool ApproxCollinear( const SEG& aSeg ) const
|
|
|
|
{
|
|
|
|
ecoord p, q, r;
|
2015-02-18 16:53:46 +00:00
|
|
|
CanonicalCoefs( p, q, r );
|
|
|
|
|
|
|
|
ecoord dist1 = ( p * aSeg.A.x + q * aSeg.A.y + r ) / sqrt( p * p + q * q );
|
|
|
|
ecoord dist2 = ( p * aSeg.B.x + q * aSeg.B.y + r ) / sqrt( p * p + q * q );
|
2015-02-17 23:40:11 +00:00
|
|
|
|
2015-02-18 16:53:46 +00:00
|
|
|
return std::abs( dist1 ) <= 1 && std::abs( dist2 ) <= 1;
|
2015-02-17 23:40:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ApproxParallel ( const SEG& aSeg ) const
|
|
|
|
{
|
|
|
|
ecoord p, q, r;
|
2015-02-18 16:53:46 +00:00
|
|
|
CanonicalCoefs( p, q, r );
|
|
|
|
|
|
|
|
ecoord dist1 = ( p * aSeg.A.x + q * aSeg.A.y + r ) / sqrt( p * p + q * q );
|
|
|
|
ecoord dist2 = ( p * aSeg.B.x + q * aSeg.B.y + r ) / sqrt( p * p + q * q );
|
2015-02-17 23:40:11 +00:00
|
|
|
|
2015-02-18 16:53:46 +00:00
|
|
|
return std::abs( dist1 - dist2 ) <= 1;
|
2015-02-17 23:40:11 +00:00
|
|
|
}
|
|
|
|
|
2021-01-05 20:02:20 +00:00
|
|
|
bool ApproxPerpendicular( const SEG& aSeg ) const
|
|
|
|
{
|
|
|
|
SEG perp = PerpendicularSeg( A );
|
|
|
|
|
|
|
|
return aSeg.ApproxParallel( perp );
|
|
|
|
}
|
|
|
|
|
2014-11-14 19:19:00 +00:00
|
|
|
bool Overlaps( const SEG& aSeg ) const
|
2014-11-14 18:18:31 +00:00
|
|
|
{
|
|
|
|
if( aSeg.A == aSeg.B ) // single point corner case
|
|
|
|
{
|
2014-11-14 19:19:00 +00:00
|
|
|
if( A == aSeg.A || B == aSeg.A )
|
2014-11-14 18:18:31 +00:00
|
|
|
return false;
|
|
|
|
|
2014-11-14 19:19:00 +00:00
|
|
|
return Contains( aSeg.A );
|
2014-11-14 18:18:31 +00:00
|
|
|
}
|
|
|
|
|
2014-11-14 19:19:00 +00:00
|
|
|
if( !Collinear( aSeg ) )
|
2014-11-14 18:18:31 +00:00
|
|
|
return false;
|
|
|
|
|
2014-11-14 19:19:00 +00:00
|
|
|
if( Contains( aSeg.A ) || Contains( aSeg.B ) )
|
2014-11-14 18:18:31 +00:00
|
|
|
return true;
|
2020-12-12 03:43:16 +00:00
|
|
|
|
2014-11-14 19:19:00 +00:00
|
|
|
if( aSeg.Contains( A ) || aSeg.Contains( B ) )
|
2014-11-14 18:18:31 +00:00
|
|
|
return true;
|
2014-11-14 19:19:00 +00:00
|
|
|
|
2014-11-14 18:18:31 +00:00
|
|
|
return false;
|
2013-10-14 18:40:36 +00:00
|
|
|
}
|
2013-10-14 11:43:57 +00:00
|
|
|
|
2020-02-19 17:10:45 +00:00
|
|
|
|
|
|
|
bool Contains( const SEG& aSeg ) const
|
|
|
|
{
|
|
|
|
if( aSeg.A == aSeg.B ) // single point corner case
|
|
|
|
return Contains( aSeg.A );
|
|
|
|
|
|
|
|
if( !Collinear( aSeg ) )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if( Contains( aSeg.A ) && Contains( aSeg.B ) )
|
2020-02-19 17:38:31 +00:00
|
|
|
return true;
|
2020-02-19 17:10:45 +00:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-10-14 18:40:36 +00:00
|
|
|
/**
|
2021-01-25 12:42:36 +00:00
|
|
|
* Return the length (this).
|
2013-10-14 18:40:36 +00:00
|
|
|
*
|
|
|
|
* @return length
|
|
|
|
*/
|
|
|
|
int Length() const
|
|
|
|
{
|
|
|
|
return ( A - B ).EuclideanNorm();
|
|
|
|
}
|
2013-10-14 11:43:57 +00:00
|
|
|
|
2013-10-14 18:40:36 +00:00
|
|
|
ecoord SquaredLength() const
|
|
|
|
{
|
|
|
|
return ( A - B ).SquaredEuclideanNorm();
|
|
|
|
}
|
2013-10-14 11:43:57 +00:00
|
|
|
|
2015-02-18 16:53:46 +00:00
|
|
|
ecoord TCoef( const VECTOR2I& aP ) const;
|
2015-02-17 23:40:11 +00:00
|
|
|
|
2013-10-14 18:40:36 +00:00
|
|
|
/**
|
2021-01-25 12:42:36 +00:00
|
|
|
* Return the index of this segment in its parent shape (applicable only to non-local
|
|
|
|
* segments).
|
2013-10-14 18:40:36 +00:00
|
|
|
*
|
|
|
|
* @return index value
|
|
|
|
*/
|
|
|
|
int Index() const
|
|
|
|
{
|
|
|
|
return m_index;
|
|
|
|
}
|
2013-10-14 11:43:57 +00:00
|
|
|
|
2013-10-14 18:40:36 +00:00
|
|
|
bool Contains( const VECTOR2I& aP ) const;
|
2013-10-14 11:43:57 +00:00
|
|
|
|
2015-02-17 23:40:11 +00:00
|
|
|
void Reverse()
|
|
|
|
{
|
2015-02-18 16:53:46 +00:00
|
|
|
std::swap( A, B );
|
2015-02-17 23:40:11 +00:00
|
|
|
}
|
|
|
|
|
2020-12-31 18:03:52 +00:00
|
|
|
SEG Reversed() const
|
|
|
|
{
|
|
|
|
return SEG( B, A );
|
|
|
|
}
|
|
|
|
|
2021-01-25 12:42:36 +00:00
|
|
|
///< Returns the center point of the line
|
2018-03-28 13:49:02 +00:00
|
|
|
VECTOR2I Center() const
|
|
|
|
{
|
|
|
|
return A + ( B - A ) / 2;
|
|
|
|
}
|
|
|
|
|
2013-10-14 18:40:36 +00:00
|
|
|
private:
|
|
|
|
bool ccw( const VECTOR2I& aA, const VECTOR2I& aB, const VECTOR2I &aC ) const;
|
2013-10-14 11:43:57 +00:00
|
|
|
|
2020-12-12 03:43:16 +00:00
|
|
|
private:
|
2021-01-25 12:42:36 +00:00
|
|
|
///< index withing the parent shape (used when m_is_local == false)
|
2013-10-14 18:40:36 +00:00
|
|
|
int m_index;
|
2013-09-10 11:43:09 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
inline VECTOR2I SEG::LineProject( const VECTOR2I& aP ) const
|
|
|
|
{
|
2015-02-17 23:40:11 +00:00
|
|
|
VECTOR2I d = B - A;
|
|
|
|
ecoord l_squared = d.Dot( d );
|
|
|
|
|
|
|
|
if( l_squared == 0 )
|
|
|
|
return A;
|
|
|
|
|
|
|
|
ecoord t = d.Dot( aP - A );
|
|
|
|
|
2020-10-05 10:41:14 +00:00
|
|
|
int xp = rescale( t, ecoord{ d.x }, l_squared );
|
|
|
|
int yp = rescale( t, ecoord{ d.y }, l_squared );
|
2015-02-17 23:40:11 +00:00
|
|
|
|
|
|
|
return A + VECTOR2I( xp, yp );
|
2013-09-10 11:43:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline int SEG::LineDistance( const VECTOR2I& aP, bool aDetermineSide ) const
|
|
|
|
{
|
2020-10-05 10:41:14 +00:00
|
|
|
ecoord p = ecoord{ A.y } - B.y;
|
|
|
|
ecoord q = ecoord{ B.x } - A.x;
|
2013-10-14 18:40:36 +00:00
|
|
|
ecoord r = -p * A.x - q * A.y;
|
2013-09-10 11:43:09 +00:00
|
|
|
|
2013-09-27 16:51:21 +00:00
|
|
|
ecoord dist = ( p * aP.x + q * aP.y + r ) / sqrt( p * p + q * q );
|
2013-09-10 11:43:09 +00:00
|
|
|
|
2015-03-09 10:06:54 +00:00
|
|
|
return aDetermineSide ? dist : std::abs( dist );
|
2013-09-27 16:51:21 +00:00
|
|
|
}
|
2013-09-10 11:43:09 +00:00
|
|
|
|
2015-02-18 16:53:46 +00:00
|
|
|
inline SEG::ecoord SEG::TCoef( const VECTOR2I& aP ) const
|
2015-02-17 23:40:11 +00:00
|
|
|
{
|
|
|
|
VECTOR2I d = B - A;
|
2015-02-18 16:53:46 +00:00
|
|
|
return d.Dot( aP - A);
|
2015-02-17 23:40:11 +00:00
|
|
|
}
|
2013-10-14 18:40:36 +00:00
|
|
|
|
2013-09-27 16:51:21 +00:00
|
|
|
inline const VECTOR2I SEG::NearestPoint( const VECTOR2I& aP ) const
|
2013-09-10 11:43:09 +00:00
|
|
|
{
|
2013-10-14 18:40:36 +00:00
|
|
|
VECTOR2I d = B - A;
|
2013-09-27 16:51:21 +00:00
|
|
|
ecoord l_squared = d.Dot( d );
|
2013-09-10 11:43:09 +00:00
|
|
|
|
|
|
|
if( l_squared == 0 )
|
2013-10-14 18:40:36 +00:00
|
|
|
return A;
|
2013-10-14 11:43:57 +00:00
|
|
|
|
2013-10-14 18:40:36 +00:00
|
|
|
ecoord t = d.Dot( aP - A );
|
2013-10-14 11:43:57 +00:00
|
|
|
|
2013-09-10 11:43:09 +00:00
|
|
|
if( t < 0 )
|
2013-10-14 18:40:36 +00:00
|
|
|
return A;
|
2013-09-10 11:43:09 +00:00
|
|
|
else if( t > l_squared )
|
2013-10-14 18:40:36 +00:00
|
|
|
return B;
|
2013-10-14 11:43:57 +00:00
|
|
|
|
2013-09-27 16:51:21 +00:00
|
|
|
int xp = rescale( t, (ecoord)d.x, l_squared );
|
|
|
|
int yp = rescale( t, (ecoord)d.y, l_squared );
|
2013-09-10 11:43:09 +00:00
|
|
|
|
2013-10-14 18:40:36 +00:00
|
|
|
return A + VECTOR2I( xp, yp );
|
2013-09-10 11:43:09 +00:00
|
|
|
}
|
|
|
|
|
2021-04-11 12:28:32 +00:00
|
|
|
inline const VECTOR2I SEG::ReflectPoint( const VECTOR2I& aP ) const
|
|
|
|
{
|
|
|
|
VECTOR2I d = B - A;
|
|
|
|
VECTOR2I::extended_type l_squared = d.Dot( d );
|
|
|
|
VECTOR2I::extended_type t = d.Dot( aP - A );
|
|
|
|
VECTOR2I c;
|
|
|
|
|
|
|
|
if( !l_squared )
|
|
|
|
c = aP;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
c.x = A.x + rescale( t, static_cast<VECTOR2I::extended_type>( d.x ), l_squared );
|
|
|
|
c.y = A.y + rescale( t, static_cast<VECTOR2I::extended_type>( d.y ), l_squared );
|
|
|
|
}
|
|
|
|
|
|
|
|
return 2 * c - aP;
|
|
|
|
}
|
|
|
|
|
2013-09-10 11:43:09 +00:00
|
|
|
inline std::ostream& operator<<( std::ostream& aStream, const SEG& aSeg )
|
|
|
|
{
|
2014-05-14 11:52:29 +00:00
|
|
|
aStream << "[ " << aSeg.A << " - " << aSeg.B << " ]";
|
2013-09-27 16:51:21 +00:00
|
|
|
|
2013-09-10 11:43:09 +00:00
|
|
|
return aStream;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // __SEG_H
|