KiCad PCB EDA Suite
Loading...
Searching...
No Matches
geometry_predicates.h
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#pragma once
21
26
27#include <algorithm>
28#include <cmath>
29#include <cstdint>
30
31#include <math/vector2d.h>
32
33namespace KIGEOM
34{
35
37inline int OrientationSign( const VECTOR2I& a, const VECTOR2I& b, const VECTOR2I& c )
38{
39 // Widen before subtracting; a 32-bit coordinate difference overflows past ~2.1e9 nm.
40 int64_t abX = static_cast<int64_t>( b.x ) - a.x;
41 int64_t abY = static_cast<int64_t>( b.y ) - a.y;
42 int64_t acX = static_cast<int64_t>( c.x ) - a.x;
43 int64_t acY = static_cast<int64_t>( c.y ) - a.y;
44
45#if defined( __SIZEOF_INT128__ )
46 __int128 cross = static_cast<__int128>( abX ) * acY - static_cast<__int128>( abY ) * acX;
47#else
48 double cross = static_cast<double>( abX ) * static_cast<double>( acY )
49 - static_cast<double>( abY ) * static_cast<double>( acX );
50#endif
51
52 return cross > 0 ? 1 : ( cross < 0 ? -1 : 0 );
53}
54
55
56namespace detail
57{
60inline bool inCircleLegalDouble( const VECTOR2I& a, const VECTOR2I& b, const VECTOR2I& c,
61 const VECTOR2I& p )
62{
63 double paX = static_cast<double>( a.x ) - p.x, paY = static_cast<double>( a.y ) - p.y;
64 double pbX = static_cast<double>( b.x ) - p.x, pbY = static_cast<double>( b.y ) - p.y;
65 double pcX = static_cast<double>( c.x ) - p.x, pcY = static_cast<double>( c.y ) - p.y;
66
67 double paSq = paX * paX + paY * paY;
68 double pbSq = pbX * pbX + pbY * pbY;
69 double pcSq = pcX * pcX + pcY * pcY;
70
71 double det = paX * ( pbY * pcSq - pbSq * pcY ) - paY * ( pbX * pcSq - pbSq * pcX )
72 + paSq * ( pbX * pcY - pbY * pcX );
73 double sumSq = paSq + pbSq + pcSq;
74
75 return det <= 1e-13 * sumSq * sumSq;
76}
77} // namespace detail
78
79
82inline bool InCircleDelaunayLegal( const VECTOR2I& a, const VECTOR2I& b, const VECTOR2I& c,
83 const VECTOR2I& p )
84{
85#if defined( __SIZEOF_INT128__ )
86 // Widen before subtracting; an int32 difference overflows past ~2.1e9 nm.
87 int64_t paX = static_cast<int64_t>( a.x ) - p.x, paY = static_cast<int64_t>( a.y ) - p.y;
88 int64_t pbX = static_cast<int64_t>( b.x ) - p.x, pbY = static_cast<int64_t>( b.y ) - p.y;
89 int64_t pcX = static_cast<int64_t>( c.x ) - p.x, pcY = static_cast<int64_t>( c.y ) - p.y;
90
91 // Beyond this the degree-4 determinant (~12*M^4) can exceed signed int128.
92 constexpr int64_t kMaxSafeDiff = 1500000000LL;
93
94 if( std::abs( paX ) > kMaxSafeDiff || std::abs( paY ) > kMaxSafeDiff
95 || std::abs( pbX ) > kMaxSafeDiff || std::abs( pbY ) > kMaxSafeDiff
96 || std::abs( pcX ) > kMaxSafeDiff || std::abs( pcY ) > kMaxSafeDiff )
97 {
98 return detail::inCircleLegalDouble( a, b, c, p );
99 }
100
101 __int128 paSq = static_cast<__int128>( paX ) * paX + static_cast<__int128>( paY ) * paY;
102 __int128 pbSq = static_cast<__int128>( pbX ) * pbX + static_cast<__int128>( pbY ) * pbY;
103 __int128 pcSq = static_cast<__int128>( pcX ) * pcX + static_cast<__int128>( pcY ) * pcY;
104
105 __int128 det = static_cast<__int128>( paX ) * ( pbY * pcSq - pbSq * pcY )
106 - static_cast<__int128>( paY ) * ( pbX * pcSq - pbSq * pcX )
107 + paSq * ( static_cast<__int128>( pbX ) * pcY - static_cast<__int128>( pbY ) * pcX );
108
109 return det <= 0;
110#else
111 return detail::inCircleLegalDouble( a, b, c, p );
112#endif
113}
114
115
117inline bool IsSliverTriangle( const VECTOR2I& a, const VECTOR2I& b, const VECTOR2I& c )
118{
119 double abX = static_cast<double>( b.x ) - a.x, abY = static_cast<double>( b.y ) - a.y;
120 double bcX = static_cast<double>( c.x ) - b.x, bcY = static_cast<double>( c.y ) - b.y;
121 double caX = static_cast<double>( a.x ) - c.x, caY = static_cast<double>( a.y ) - c.y;
122
123 double abSquared = abX * abX + abY * abY;
124 double bcSquared = bcX * bcX + bcY * bcY;
125 double caSquared = caX * caX + caY * caY;
126
127 double longestSquared = std::max( { abSquared, bcSquared, caSquared } );
128 double shortestSquared = std::min( { abSquared, bcSquared, caSquared } );
129
130 return shortestSquared > 0.0 && longestSquared > 100.0 * shortestSquared;
131}
132
133} // namespace KIGEOM
bool inCircleLegalDouble(const VECTOR2I &a, const VECTOR2I &b, const VECTOR2I &c, const VECTOR2I &p)
Filtered-double legality test; the tie margin treats a near-cocircular quad as legal to keep a flip l...
int OrientationSign(const VECTOR2I &a, const VECTOR2I &b, const VECTOR2I &c)
Orientation of triangle (a, b, c): +1 counter-clockwise, -1 clockwise, 0 collinear.
bool InCircleDelaunayLegal(const VECTOR2I &a, const VECTOR2I &b, const VECTOR2I &c, const VECTOR2I &p)
True when p is outside the circumcircle of CCW triangle (a, b, c): the shared edge is already Delauna...
bool IsSliverTriangle(const VECTOR2I &a, const VECTOR2I &b, const VECTOR2I &c)
A triangle is a sliver when its longest edge exceeds ten times its shortest.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683