summaryrefslogtreecommitdiff
path: root/include/geometry/seg.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/geometry/seg.h')
-rw-r--r--include/geometry/seg.h384
1 files changed, 384 insertions, 0 deletions
diff --git a/include/geometry/seg.h b/include/geometry/seg.h
new file mode 100644
index 0000000..164457b
--- /dev/null
+++ b/include/geometry/seg.h
@@ -0,0 +1,384 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2013 CERN
+ * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
+ *
+ * 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
+
+#include <cstdio>
+#include <climits>
+
+#include <math/vector2d.h>
+
+#include <boost/optional/optional.hpp>
+
+typedef boost::optional<VECTOR2I> OPT_VECTOR2I;
+
+class SEG
+{
+private:
+ typedef VECTOR2I::extended_type ecoord;
+
+public:
+ friend inline std::ostream& operator<<( std::ostream& aStream, const SEG& aSeg );
+
+ /* Start and the of the segment. Public, to make access simpler. These are references
+ * to an object the segment belongs to (e.g. a line chain) or references to locally stored
+ * points (m_a, m_b).
+ */
+ VECTOR2I A;
+ VECTOR2I B;
+
+ /** Default constructor
+ * Creates an empty (0, 0) segment, locally-referenced
+ */
+ SEG()
+ {
+ m_index = -1;
+ }
+
+ /**
+ * Constructor
+ * Creates a segment between (aX1, aY1) and (aX2, aY2), locally referenced
+ */
+ SEG( int aX1, int aY1, int aX2, int aY2 ) :
+ A ( VECTOR2I( aX1, aY1 ) ),
+ B ( VECTOR2I( aX2, aY2 ) )
+ {
+ m_index = -1;
+ }
+
+ /**
+ * Constructor
+ * Creates a segment between (aA) and (aB), locally referenced
+ */
+ SEG( const VECTOR2I& aA, const VECTOR2I& aB ) : A( aA ), B( aB )
+ {
+ m_index = -1;
+ }
+
+ /**
+ * Constructor
+ * Creates a segment between (aA) and (aB), referenced to a multi-segment shape
+ * @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
+ */
+ SEG( const VECTOR2I& aA, const VECTOR2I& aB, int aIndex ) : A( aA ), B( aB )
+ {
+ m_index = aIndex;
+ }
+
+ /**
+ * Copy constructor
+ */
+ SEG( const SEG& aSeg ) : A( aSeg.A ), B( aSeg.B ), m_index( aSeg.m_index )
+ {
+ }
+
+ SEG& operator=( const SEG& aSeg )
+ {
+ A = aSeg.A;
+ B = aSeg.B;
+ m_index = aSeg.m_index;
+
+ return *this;
+ }
+
+ /**
+ * Function LineProject()
+ *
+ * Computes the perpendicular projection point of aP on a line passing through
+ * ends of the segment.
+ * @param aP point to project
+ * @return projected point
+ */
+ VECTOR2I LineProject( const VECTOR2I& aP ) const;
+
+ /**
+ * Function Side()
+ *
+ * Determines on which side of directed line passing via segment ends point aP lies.
+ * @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 );
+
+ return det < 0 ? -1 : ( det > 0 ? 1 : 0 );
+ }
+
+ /**
+ * Function LineDistance()
+ *
+ * Returns the closest Euclidean distance between point aP and the line defined by
+ * the ends of segment (this).
+ * @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;
+
+ /**
+ * Function NearestPoint()
+ *
+ * Computes a point on the segment (this) that is closest to point aP.
+ * @return: nearest point
+ */
+ const VECTOR2I NearestPoint( const VECTOR2I &aP ) const;
+
+ /**
+ * Function Intersect()
+ *
+ * Computes intersection point of segment (this) with segment aSeg.
+ * @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;
+
+ /**
+ * Function IntersectLines()
+ *
+ * Computes the intersection point of lines passing through ends of (this) and aSeg
+ * @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 );
+ }
+
+ bool Collide( const SEG& aSeg, int aClearance ) const;
+
+ ecoord SquaredDistance( const SEG& aSeg ) const;
+
+ /**
+ * Function Distance()
+ *
+ * Computes minimum Euclidean distance to segment aSeg.
+ * @param aSeg other segment
+ * @return minimum distance
+ */
+ int Distance( const SEG& aSeg ) const
+ {
+ return sqrt( SquaredDistance( aSeg ) );
+ }
+
+ ecoord SquaredDistance( const VECTOR2I& aP ) const
+ {
+ return ( NearestPoint( aP ) - aP ).SquaredEuclideanNorm();
+ }
+
+ /**
+ * Function Distance()
+ *
+ * Computes minimum Euclidean distance to point aP.
+ * @param aP the point
+ * @return minimum distance
+ */
+ int Distance( const VECTOR2I& aP ) const
+ {
+ return sqrt( SquaredDistance( aP ) );
+ }
+
+ void CanonicalCoefs( ecoord& qA, ecoord& qB, ecoord& qC ) const
+ {
+ qA = A.y - B.y;
+ qB = B.x - A.x;
+ qC = -qA * A.x - qB * A.y;
+ }
+
+ /**
+ * Function Collinear()
+ *
+ * Checks if segment aSeg lies on the same line as (this).
+ * @param aSeg the segment to chech colinearity with
+ * @return true, when segments are collinear.
+ */
+ bool Collinear( const SEG& aSeg ) const
+ {
+ ecoord qa, qb, qc;
+ CanonicalCoefs( qa, qb, qc );
+
+ 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 );
+ }
+
+ bool ApproxCollinear( const SEG& aSeg ) const
+ {
+ ecoord p, q, r;
+ 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 );
+
+ return std::abs( dist1 ) <= 1 && std::abs( dist2 ) <= 1;
+ }
+
+ bool ApproxParallel ( const SEG& aSeg ) const
+ {
+ ecoord p, q, r;
+ 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 );
+
+ return std::abs( dist1 - dist2 ) <= 1;
+ }
+
+
+ bool Overlaps( const SEG& aSeg ) const
+ {
+ if( aSeg.A == aSeg.B ) // single point corner case
+ {
+ if( A == aSeg.A || B == aSeg.A )
+ return false;
+
+ return Contains( aSeg.A );
+ }
+
+ if( !Collinear( aSeg ) )
+ return false;
+
+ if( Contains( aSeg.A ) || Contains( aSeg.B ) )
+ return true;
+ if( aSeg.Contains( A ) || aSeg.Contains( B ) )
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Function Length()
+ *
+ * Returns the length (this)
+ * @return length
+ */
+ int Length() const
+ {
+ return ( A - B ).EuclideanNorm();
+ }
+
+ ecoord SquaredLength() const
+ {
+ return ( A - B ).SquaredEuclideanNorm();
+ }
+
+ ecoord TCoef( const VECTOR2I& aP ) const;
+
+ /**
+ * Function Index()
+ *
+ * Return the index of this segment in its parent shape (applicable only to non-local segments)
+ * @return index value
+ */
+ int Index() const
+ {
+ return m_index;
+ }
+
+ bool Contains( const VECTOR2I& aP ) const;
+
+ bool PointCloserThan( const VECTOR2I& aP, int aDist ) const;
+
+ void Reverse()
+ {
+ std::swap( A, B );
+ }
+
+private:
+ bool ccw( const VECTOR2I& aA, const VECTOR2I& aB, const VECTOR2I &aC ) const;
+
+ ///> index withing the parent shape (used when m_is_local == false)
+ int m_index;
+};
+
+inline VECTOR2I SEG::LineProject( const VECTOR2I& aP ) const
+{
+ VECTOR2I d = B - A;
+ ecoord l_squared = d.Dot( d );
+
+ if( l_squared == 0 )
+ return A;
+
+ ecoord t = d.Dot( aP - A );
+
+ int xp = rescale( t, (ecoord)d.x, l_squared );
+ int yp = rescale( t, (ecoord)d.y, l_squared );
+
+ return A + VECTOR2I( xp, yp );
+}
+
+inline int SEG::LineDistance( const VECTOR2I& aP, bool aDetermineSide ) const
+{
+ ecoord p = A.y - B.y;
+ ecoord q = B.x - A.x;
+ ecoord r = -p * A.x - q * A.y;
+
+ ecoord dist = ( p * aP.x + q * aP.y + r ) / sqrt( p * p + q * q );
+
+ return aDetermineSide ? dist : std::abs( dist );
+}
+
+inline SEG::ecoord SEG::TCoef( const VECTOR2I& aP ) const
+{
+ VECTOR2I d = B - A;
+ return d.Dot( aP - A);
+}
+
+inline const VECTOR2I SEG::NearestPoint( const VECTOR2I& aP ) const
+{
+ VECTOR2I d = B - A;
+ ecoord l_squared = d.Dot( d );
+
+ if( l_squared == 0 )
+ return A;
+
+ ecoord t = d.Dot( aP - A );
+
+ if( t < 0 )
+ return A;
+ else if( t > l_squared )
+ return B;
+
+ int xp = rescale( t, (ecoord)d.x, l_squared );
+ int yp = rescale( t, (ecoord)d.y, l_squared );
+
+ return A + VECTOR2I( xp, yp );
+}
+
+inline std::ostream& operator<<( std::ostream& aStream, const SEG& aSeg )
+{
+ aStream << "[ " << aSeg.A << " - " << aSeg.B << " ]";
+
+ return aStream;
+}
+
+#endif // __SEG_H