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  }