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#include <math/wide_int.h>
33
34namespace KIGEOM
35{
36
38inline int OrientationSign( const VECTOR2I& a, const VECTOR2I& b, const VECTOR2I& c )
39{
40 // Widen before subtracting; a 32-bit coordinate difference overflows past ~2.1e9 nm.
41 int64_t abX = static_cast<int64_t>( b.x ) - a.x;
42 int64_t abY = static_cast<int64_t>( b.y ) - a.y;
43 int64_t acX = static_cast<int64_t>( c.x ) - a.x;
44 int64_t acY = static_cast<int64_t>( c.y ) - a.y;
45
46 const KI_INT128 cross = CrossWide( VECTOR2L( abX, abY ), VECTOR2L( acX, acY ) );
47
48 return cross > KI_INT128( 0 ) ? 1 : ( cross < KI_INT128( 0 ) ? -1 : 0 );
49}
50
51
52namespace detail
53{
56inline bool inCircleLegalDouble( const VECTOR2I& a, const VECTOR2I& b, const VECTOR2I& c,
57 const VECTOR2I& p )
58{
59 double paX = static_cast<double>( a.x ) - p.x, paY = static_cast<double>( a.y ) - p.y;
60 double pbX = static_cast<double>( b.x ) - p.x, pbY = static_cast<double>( b.y ) - p.y;
61 double pcX = static_cast<double>( c.x ) - p.x, pcY = static_cast<double>( c.y ) - p.y;
62
63 double paSq = paX * paX + paY * paY;
64 double pbSq = pbX * pbX + pbY * pbY;
65 double pcSq = pcX * pcX + pcY * pcY;
66
67 double det = paX * ( pbY * pcSq - pbSq * pcY ) - paY * ( pbX * pcSq - pbSq * pcX )
68 + paSq * ( pbX * pcY - pbY * pcX );
69 double sumSq = paSq + pbSq + pcSq;
70
71 return det <= 1e-13 * sumSq * sumSq;
72}
73} // namespace detail
74
75
78inline bool InCircleDelaunayLegal( const VECTOR2I& a, const VECTOR2I& b, const VECTOR2I& c,
79 const VECTOR2I& p )
80{
81 // Widen before subtracting; an int32 difference overflows past ~2.1e9 nm.
82 int64_t paX = static_cast<int64_t>( a.x ) - p.x, paY = static_cast<int64_t>( a.y ) - p.y;
83 int64_t pbX = static_cast<int64_t>( b.x ) - p.x, pbY = static_cast<int64_t>( b.y ) - p.y;
84 int64_t pcX = static_cast<int64_t>( c.x ) - p.x, pcY = static_cast<int64_t>( c.y ) - p.y;
85
86 // Beyond this the degree-4 determinant (~12*M^4) can exceed signed int128.
87 constexpr int64_t kMaxSafeDiff = 1500000000LL;
88
89 if( std::abs( paX ) > kMaxSafeDiff || std::abs( paY ) > kMaxSafeDiff
90 || std::abs( pbX ) > kMaxSafeDiff || std::abs( pbY ) > kMaxSafeDiff
91 || std::abs( pcX ) > kMaxSafeDiff || std::abs( pcY ) > kMaxSafeDiff )
92 {
93 return detail::inCircleLegalDouble( a, b, c, p );
94 }
95
96 const KI_INT128 paX128( paX ), paY128( paY ), pbX128( pbX ), pbY128( pbY ), pcX128( pcX ), pcY128( pcY );
97
98 const KI_INT128 paSq = paX128 * paX128 + paY128 * paY128;
99 const KI_INT128 pbSq = pbX128 * pbX128 + pbY128 * pbY128;
100 const KI_INT128 pcSq = pcX128 * pcX128 + pcY128 * pcY128;
101
102 const KI_INT128 det = paX128 * ( pbY128 * pcSq - pbSq * pcY128 ) - paY128 * ( pbX128 * pcSq - pbSq * pcX128 )
103 + paSq * ( pbX128 * pcY128 - pbY128 * pcX128 );
104
105 return det <= KI_INT128( 0 );
106}
107
108
110inline bool IsSliverTriangle( const VECTOR2I& a, const VECTOR2I& b, const VECTOR2I& c )
111{
112 double abX = static_cast<double>( b.x ) - a.x, abY = static_cast<double>( b.y ) - a.y;
113 double bcX = static_cast<double>( c.x ) - b.x, bcY = static_cast<double>( c.y ) - b.y;
114 double caX = static_cast<double>( a.x ) - c.x, caY = static_cast<double>( a.y ) - c.y;
115
116 double abSquared = abX * abX + abY * abY;
117 double bcSquared = bcX * bcX + bcY * bcY;
118 double caSquared = caX * caX + caY * caY;
119
120 double longestSquared = std::max( { abSquared, bcSquared, caSquared } );
121 double shortestSquared = std::min( { abSquared, bcSquared, caSquared } );
122
123 return shortestSquared > 0.0 && longestSquared > 100.0 * shortestSquared;
124}
125
126} // 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...
Construction helpers for the interactive arc drawing modes.
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:437
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
VECTOR2< int64_t > VECTOR2L
Definition vector2d.h:709
128-bit integers for exact products of 64-bit coordinate deltas.
constexpr KI_INT128 CrossWide(const VECTOR2L &aA, const VECTOR2L &aB)
Exact aA.x * aB.y - aA.y * aB.x.
Definition wide_int.h:104
__int128 KI_INT128
Definition wide_int.h:91