go-hep.org/x/hep@v0.38.1/fastjet/internal/predicates/incircle.go (about) 1 // Copyright ©2017 The go-hep Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package predicates 6 7 import ( 8 "fmt" 9 "math/big" 10 11 "gonum.org/v1/gonum/mat" 12 ) 13 14 // RelativePosition is the position of a point relative to a circle 15 type RelativePosition int 16 17 const ( 18 // Inside the circle 19 Inside RelativePosition = iota 20 // On the circle 21 On 22 // Outside the circle 23 Outside 24 IndeterminatePosition 25 ) 26 27 func (p RelativePosition) String() string { 28 switch p { 29 case Inside: 30 return "Inside Circle" 31 case On: 32 return "On Circle" 33 case Outside: 34 return "Outside Circle" 35 case IndeterminatePosition: 36 return "Indeterminate" 37 default: 38 panic(fmt.Errorf("predicates: unknown RelativePosition %d", int(p))) 39 } 40 } 41 42 // Incircle determines the relative position of the point (x,y) in relation to the circle formed 43 // by the three points (x1,y1),(x2,y2) and (x3,y3). The three points have to be ordered counterclockwise or 44 // Outside and Inside will be reversed. 45 func Incircle(x1, y1, x2, y2, x3, y3, x, y float64) RelativePosition { 46 pos := simpleIncircle(x1, y1, x2, y2, x3, y3, x, y) 47 if pos == IndeterminatePosition { 48 pos = matIncircle(x1, y1, x2, y2, x3, y3, x, y) 49 } 50 return pos 51 } 52 53 // simpleIncircle determines the relative position using the simple float64 type. 54 // Its accuracy can't be guaranteed, therefore close decisions 55 // return IndeterminatePosition which signals Incircle that further 56 // testing is necessary. 57 // 58 // It computes the determinant of the matrix and returns the relative position 59 // based on the value of the determinant. 60 // |x1 y1 x1^2+y1^2 1| 61 // |x2 y2 x2^2+y2^2 1| 62 // |x3 y3 x3^2+y3^2 1| 63 // |x y x^2 +y^2 1| 64 func simpleIncircle(x1, y1, x2, y2, x3, y3, x, y float64) RelativePosition { 65 m := []float64{ 66 x1, y1, x1*x1 + y1*y1, 1, 67 x2, y2, x2*x2 + y2*y2, 1, 68 x3, y3, x3*x3 + y3*y3, 1, 69 x, y, x*x + y*y, 1, 70 } 71 p := rowFloat(3, 2, 1, 0, false, m).addFloat64Pred(rowFloat(3, 1, 2, 0, true, m)).addFloat64Pred( 72 rowFloat(2, 1, 3, 0, false, m)).addFloat64Pred(rowFloat(3, 2, 0, 1, true, m)).addFloat64Pred( 73 rowFloat(3, 0, 2, 1, false, m)).addFloat64Pred(rowFloat(2, 0, 3, 1, true, m)).addFloat64Pred( 74 rowFloat(3, 1, 0, 2, false, m)).addFloat64Pred(rowFloat(3, 0, 1, 2, true, m)).addFloat64Pred( 75 rowFloat(1, 0, 3, 2, false, m)).addFloat64Pred(rowFloat(2, 1, 0, 3, true, m)).addFloat64Pred( 76 rowFloat(2, 0, 1, 3, false, m)).addFloat64Pred(rowFloat(1, 0, 2, 3, true, m)) 77 // det := m[0][3]*m[1][2]*m[2][1]*m[3][0] - m[0][2]*m[1][3]*m[2][1]*m[3][0] - 78 // m[0][3]*m[1][1]*m[2][2]*m[3][0] + m[0][1]*m[1][3]*m[2][2]*m[3][0] + 79 // m[0][2]*m[1][1]*m[2][3]*m[3][0] - m[0][1]*m[1][2]*m[2][3]*m[3][0] - 80 // m[0][3]*m[1][2]*m[2][0]*m[3][1] + m[0][2]*m[1][3]*m[2][0]*m[3][1] + 81 // m[0][3]*m[1][0]*m[2][2]*m[3][1] - m[0][0]*m[1][3]*m[2][2]*m[3][1] - 82 // m[0][2]*m[1][0]*m[2][3]*m[3][1] + m[0][0]*m[1][2]*m[2][3]*m[3][1] + 83 // m[0][3]*m[1][1]*m[2][0]*m[3][2] - m[0][1]*m[1][3]*m[2][0]*m[3][2] - 84 // m[0][3]*m[1][0]*m[2][1]*m[3][2] + m[0][0]*m[1][3]*m[2][1]*m[3][2] + 85 // m[0][1]*m[1][0]*m[2][3]*m[3][2] - m[0][0]*m[1][1]*m[2][3]*m[3][2] - 86 // m[0][2]*m[1][1]*m[2][0]*m[3][3] + m[0][1]*m[1][2]*m[2][0]*m[3][3] + 87 // m[0][2]*m[1][0]*m[2][1]*m[3][3] - m[0][0]*m[1][2]*m[2][1]*m[3][3] - 88 // m[0][1]*m[1][0]*m[2][2]*m[3][3] + m[0][0]*m[1][1]*m[2][2]*m[3][3] 89 det := p.n 90 // e determines when the determinant in simpleIncircle is too close to 0 to rely on floating point operations. 91 e := p.e 92 if det < -e { 93 return Outside 94 } 95 if det > e { 96 return Inside 97 } 98 return IndeterminatePosition 99 } 100 101 // rowFloat is a helper function for robustIncircle 102 // If m[row][col] then each row in the determinant calculation is either 103 // m[0][a]*m[1][b]*m[2][c]*m[3][d] - m[0][b]*m[1][a]*m[2][c]*m[3][d] or 104 // - m[0][a]*m[1][b]*m[2][c]*m[3][d] + m[0][b]*m[1][a]*m[2][c]*m[3][d] 105 func rowFloat(a, b, c, d int, plus bool, m []float64) float64Pred { 106 if plus { 107 return newFloat64Pred(m[b]).mulFloat64(m[a+4]).mulFloat64(m[c+8]).mulFloat64(m[d+12]).subFloat64Pred( 108 newFloat64Pred(m[a]).mulFloat64(m[b+4]).mulFloat64(m[c+8]).mulFloat64(m[d+12])) 109 } 110 return newFloat64Pred(m[a]).mulFloat64(m[b+4]).mulFloat64(m[c+8]).mulFloat64(m[d+12]).subFloat64Pred( 111 newFloat64Pred(m[b]).mulFloat64(m[a+4]).mulFloat64(m[c+8]).mulFloat64(m[d+12])) 112 } 113 114 // robustIncircle determines the relative position using the accurate big/Rat type. 115 // 116 // It computes the determinant of the matrix and returns the relative position 117 // based on the value of the determinant. 118 // |x1 y1 x1^2+y1^2 1| 119 // |x2 y2 x2^2+y2^2 1| 120 // |x3 y3 x3^2+y3^2 1| 121 // |x y x^2 +y^2 1| 122 func robustIncircle(x1, y1, x2, y2, x3, y3, x, y *big.Rat) RelativePosition { 123 m := []*big.Rat{ 124 x1, y1, bigAdd(bigMul(x1, x1), bigMul(y1, y1)), one, 125 x2, y2, bigAdd(bigMul(x2, x2), bigMul(y2, y2)), one, 126 x3, y3, bigAdd(bigMul(x3, x3), bigMul(y3, y3)), one, 127 x, y, bigAdd(bigMul(x, x), bigMul(y, y)), one, 128 } 129 // det := m[0][3]*m[1][2]*m[2][1]*m[3][0] - m[0][2]*m[1][3]*m[2][1]*m[3][0] - 130 // m[0][3]*m[1][1]*m[2][2]*m[3][0] + m[0][1]*m[1][3]*m[2][2]*m[3][0] + 131 // m[0][2]*m[1][1]*m[2][3]*m[3][0] - m[0][1]*m[1][2]*m[2][3]*m[3][0] - 132 // m[0][3]*m[1][2]*m[2][0]*m[3][1] + m[0][2]*m[1][3]*m[2][0]*m[3][1] + 133 // m[0][3]*m[1][0]*m[2][2]*m[3][1] - m[0][0]*m[1][3]*m[2][2]*m[3][1] - 134 // m[0][2]*m[1][0]*m[2][3]*m[3][1] + m[0][0]*m[1][2]*m[2][3]*m[3][1] + 135 // m[0][3]*m[1][1]*m[2][0]*m[3][2] - m[0][1]*m[1][3]*m[2][0]*m[3][2] - 136 // m[0][3]*m[1][0]*m[2][1]*m[3][2] + m[0][0]*m[1][3]*m[2][1]*m[3][2] + 137 // m[0][1]*m[1][0]*m[2][3]*m[3][2] - m[0][0]*m[1][1]*m[2][3]*m[3][2] - 138 // m[0][2]*m[1][1]*m[2][0]*m[3][3] + m[0][1]*m[1][2]*m[2][0]*m[3][3] + 139 // m[0][2]*m[1][0]*m[2][1]*m[3][3] - m[0][0]*m[1][2]*m[2][1]*m[3][3] - 140 // m[0][1]*m[1][0]*m[2][2]*m[3][3] + m[0][0]*m[1][1]*m[2][2]*m[3][3] 141 det := bigAdd( 142 bigAdd( 143 bigAdd( 144 bigAdd(rowBig(3, 2, 1, 0, false, m), rowBig(3, 1, 2, 0, true, m)), 145 rowBig(2, 1, 3, 0, false, m), 146 ), 147 bigAdd( 148 bigAdd(rowBig(3, 2, 0, 1, true, m), rowBig(3, 0, 2, 1, false, m)), 149 rowBig(2, 0, 3, 1, true, m), 150 ), 151 ), 152 bigAdd( 153 bigAdd( 154 bigAdd(rowBig(3, 1, 0, 2, false, m), rowBig(3, 0, 1, 2, true, m)), 155 rowBig(1, 0, 3, 2, false, m), 156 ), 157 bigAdd( 158 bigAdd(rowBig(2, 1, 0, 3, true, m), rowBig(2, 0, 1, 3, false, m)), 159 rowBig(1, 0, 2, 3, true, m), 160 ), 161 ), 162 ) 163 sign := det.Sign() 164 switch sign { 165 case 1: 166 return Inside 167 case -1: 168 return Outside 169 case 0: 170 return On 171 } 172 return IndeterminatePosition 173 } 174 175 // rowBig is a helper function for robustIncircle 176 // If m[row][col] then each row in the determinant calculation is either 177 // m[0][a]*m[1][b]*m[2][c]*m[3][d] - m[0][b]*m[1][a]*m[2][c]*m[3][d] or 178 // - m[0][a]*m[1][b]*m[2][c]*m[3][d] + m[0][b]*m[1][a]*m[2][c]*m[3][d] 179 func rowBig(a, b, c, d int, plus bool, m []*big.Rat) *big.Rat { 180 if plus { 181 return bigSub( 182 bigMul(bigMul(m[b], m[a+4]), bigMul(m[c+8], m[d+12])), 183 bigMul(bigMul(m[a], m[b+4]), bigMul(m[c+8], m[d+12])), 184 ) 185 } 186 return bigSub( 187 bigMul(bigMul(m[a], m[b+4]), bigMul(m[c+8], m[d+12])), 188 bigMul(bigMul(m[b], m[a+4]), bigMul(m[c+8], m[d+12])), 189 ) 190 } 191 192 // matIncircle determines the relative position using the mat package. 193 // 194 // It first computes the conditional number of the matrix. When the condition number 195 // is higher than the Condition Tolerance, then we assume the matrix is singular and 196 // the determinant is 0. If the determinant is not 0 the sign of the determinant is computed. 197 // |x1 y1 x1^2+y1^2 1| 198 // |x2 y2 x2^2+y2^2 1| 199 // |x3 y3 x3^2+y3^2 1| 200 // |x y x^2 +y^2 1| 201 func matIncircle(x1, y1, x2, y2, x3, y3, x, y float64) RelativePosition { 202 m := mat.NewDense(4, 4, []float64{x1, y1, x1*x1 + y1*y1, 1, x2, y2, x2*x2 + y2*y2, 1, x3, y3, x3*x3 + y3*y3, 1, x, y, x*x + y*y, 1}) 203 var lu mat.LU 204 lu.Factorize(m) 205 cond := lu.Cond() 206 if cond > mat.ConditionTolerance { 207 return On 208 } 209 // Since only the sign is needed LogDet achieves the result in faster time. 210 _, sign := lu.LogDet() 211 switch sign { 212 case 1: 213 return Inside 214 case -1: 215 return Outside 216 } 217 return IndeterminatePosition 218 }