go-hep.org/x/hep@v0.38.1/fastjet/internal/delaunay/triangle.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 delaunay 6 7 import ( 8 "fmt" 9 "math" 10 11 "go-hep.org/x/hep/fastjet/internal/predicates" 12 ) 13 14 // Triangle is a set of three points that make up a triangle. It stores hierarchical information to find triangles. 15 type Triangle struct { 16 // children are triangles that lead to the removal of this triangle. 17 // When a point is inserted the triangle that contains the point is found by going down the hierarchical tree. 18 // The tree's root is the root triangle and the children slice contains the children triangles. 19 children []*Triangle 20 // A,B,C are the CCW-oriented points that make up the triangle 21 A, B, C *Point 22 // isInTriangulation holds whether a triangle is part of the triangulation 23 isInTriangulation bool 24 } 25 26 // NewTriangle returns a triangle formed out of the three given points. 27 func NewTriangle(a, b, c *Point) *Triangle { 28 // order the points counter clockwise 29 o := predicates.Orientation(a.x, a.y, b.x, b.y, c.x, c.y) 30 switch o { 31 case predicates.CW: 32 a, b = b, a 33 case predicates.Colinear: 34 panic(fmt.Errorf("delaunay: Can't form triangle, because Points a%v, b%v and c%v are colinear", a, b, c)) 35 } 36 return &Triangle{ 37 A: a, 38 B: b, 39 C: c, 40 } 41 } 42 43 // add is used when the triangle t is added to the delaunay triangulation. 44 // It updates the information of the points in t. 45 // It returns all points whose nearest neighbor was updated. 46 func (t *Triangle) add() []*Point { 47 t.isInTriangulation = true 48 // update the adjacent lists 49 t.A.adjacentTriangles = append(t.A.adjacentTriangles, t) 50 t.B.adjacentTriangles = append(t.B.adjacentTriangles, t) 51 t.C.adjacentTriangles = append(t.C.adjacentTriangles, t) 52 // update nearest neighbor if one of the points is closer than current nearest. 53 // First find the nearest neighbor in t. 54 // Then check whether local min distance is smaller than current min distance. 55 updated := make([]*Point, 0, 3) 56 distAB := t.A.distance(t.B) 57 distBC := t.B.distance(t.C) 58 distCA := t.C.distance(t.A) 59 var localMin float64 60 var localNearest *Point 61 if distAB < distCA { 62 localMin = distAB 63 localNearest = t.B 64 } else { 65 localMin = distCA 66 localNearest = t.C 67 } 68 if localMin < t.A.dist2 { 69 t.A.dist2 = localMin 70 t.A.nearest = localNearest 71 updated = append(updated, t.A) 72 } 73 if distAB < distBC { 74 localMin = distAB 75 localNearest = t.A 76 } else { 77 localMin = distBC 78 localNearest = t.C 79 } 80 if localMin < t.B.dist2 { 81 t.B.dist2 = localMin 82 t.B.nearest = localNearest 83 updated = append(updated, t.B) 84 } 85 if distBC < distCA { 86 localMin = distBC 87 localNearest = t.B 88 } else { 89 localMin = distCA 90 localNearest = t.A 91 } 92 if localMin < t.C.dist2 { 93 t.C.dist2 = localMin 94 t.C.nearest = localNearest 95 updated = append(updated, t.C) 96 } 97 return updated 98 } 99 100 // remove is used when the triangle t is removed from the delaunay triangulation. 101 // It updates the information of the points in t. 102 // It returns all points whose nearest neighbor was updated. 103 func (t *Triangle) remove() []*Point { 104 t.isInTriangulation = false 105 t.A.adjacentTriangles = t.A.adjacentTriangles.remove(t) 106 t.B.adjacentTriangles = t.B.adjacentTriangles.remove(t) 107 t.C.adjacentTriangles = t.C.adjacentTriangles.remove(t) 108 // update the nearest neighbor if the nearest neighbor is in t. 109 updated := make([]*Point, 0, 3) 110 if t.A.nearest.Equals(t.B) || t.A.nearest.Equals(t.C) { 111 t.A.findNearest() 112 updated = append(updated, t.A) 113 } 114 if t.B.nearest.Equals(t.A) || t.B.nearest.Equals(t.C) { 115 t.B.findNearest() 116 updated = append(updated, t.B) 117 } 118 if t.C.nearest.Equals(t.A) || t.C.nearest.Equals(t.B) { 119 t.C.findNearest() 120 updated = append(updated, t.C) 121 } 122 return updated 123 } 124 125 // circumcenter returns the x,y coordinates of the circumcenter of the triangle 126 func (t *Triangle) circumcenter() (x, y float64) { 127 // TODO: there are few divisions by the same value, store the inverse of these delta values and use that instead 128 m1 := (t.A.x - t.B.x) / (t.B.y - t.A.y) 129 m2 := (t.A.x - t.C.x) / (t.C.y - t.A.y) 130 b1 := (t.A.y+t.B.y)*0.5 - m1*(t.A.x+t.B.x)*0.5 131 b2 := (t.A.y+t.C.y)*0.5 - m2*(t.A.x+t.C.x)*0.5 132 x = (b2 - b1) / (m1 - m2) 133 y = m1*x + b1 134 if math.IsNaN(y) { 135 m1 = (t.B.x - t.A.x) / (t.A.y - t.B.y) 136 m2 = (t.B.x - t.C.x) / (t.C.y - t.B.y) 137 b1 = (t.B.y+t.A.y)*0.5 - m1*(t.B.x+t.A.x)*0.5 138 b2 = (t.B.y+t.C.y)*0.5 - m2*(t.B.x+t.C.x)*0.5 139 x = (b2 - b1) / (m1 - m2) 140 y = m1*x + b1 141 if math.IsNaN(y) { 142 m1 = (t.C.x - t.A.x) / (t.A.y - t.C.y) 143 m2 = (t.C.x - t.B.x) / (t.B.y - t.C.y) 144 b1 = (t.C.y+t.A.y)*0.5 - m1*(t.C.x+t.A.x)*0.5 145 b2 = (t.C.y+t.B.y)*0.5 - m2*(t.C.x+t.B.x)*0.5 146 x = (b2 - b1) / (m1 - m2) 147 y = m1*x + b1 148 if math.IsNaN(y) { 149 // Should never reach this point. To reach this point either all three y or x coordinates 150 // would have to be the same, which is impossible since there are no collinear triangles. 151 // Or two y variables and two x variables would have to be the same. That is impossible, 152 // because of the way this is set up. The variables with the same x coordinates would have to 153 // be the same as the variables with the same y coordinates and triangles are not made up 154 // of duplicates. 155 panic(fmt.Errorf("delaunay: error calculating the circumcenter of %v", t)) 156 } 157 } 158 } 159 return x, y 160 } 161 162 // Equals checks whether two triangles are the same. 163 func (t *Triangle) Equals(s *Triangle) bool { 164 return t == s || 165 (t.A.Equals(s.A) || t.A.Equals(s.B) || t.A.Equals(s.C)) && 166 (t.B.Equals(s.A) || t.B.Equals(s.B) || t.B.Equals(s.C)) && 167 (t.C.Equals(s.A) || t.C.Equals(s.B) || t.C.Equals(s.C)) 168 } 169 170 func (t *Triangle) String() string { 171 return fmt.Sprintf("{A%s, B%s, C%s}", t.A, t.B, t.C) 172 } 173 174 type triangles []*Triangle 175 176 // remove removes given triangles from a slice of triangles. 177 // 178 // remove may modify the content of the input slice of triangles to remove from the receiver. 179 // remove assumes there are no duplicate triangles in the receiver list of triangles. 180 // remove will fail to remove the duplicates if that assumption does not hold. 181 func (ts triangles) remove(triangles ...*Triangle) triangles { 182 k := len(triangles) - 1 183 for i := len(ts) - 1; i >= 0; i-- { 184 if k < 0 { 185 break 186 } 187 for j := k; j >= 0; j-- { 188 if triangles[j].Equals(ts[i]) { 189 n := len(ts) - 1 190 ts[i], ts[n] = ts[n], nil 191 ts = ts[:n] 192 triangles[j] = triangles[k] 193 k-- 194 break 195 } 196 } 197 } 198 return ts 199 } 200 201 // keepCurrentTriangles returns all triangles that are in the current triangulation. 202 func (ts triangles) keepCurrentTriangles() triangles { 203 triangles := make(triangles, 0, len(ts)) 204 for _, t := range ts { 205 if t.isInTriangulation { 206 triangles = append(triangles, t) 207 } 208 } 209 return triangles 210 }