github.com/richardwilkes/toolbox@v1.121.0/xmath/geom/poly/polygon_node.go (about) 1 // Copyright (c) 2016-2024 by Richard A. Wilkes. All rights reserved. 2 // 3 // This Source Code Form is subject to the terms of the Mozilla Public 4 // License, version 2.0. If a copy of the MPL was not distributed with 5 // this file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 // 7 // This Source Code Form is "Incompatible With Secondary Licenses", as 8 // defined by the Mozilla Public License, version 2.0. 9 10 package poly 11 12 import ( 13 "github.com/richardwilkes/toolbox/xmath/geom" 14 "golang.org/x/exp/constraints" 15 ) 16 17 type vertexNode[T constraints.Float] struct { 18 pt geom.Point[T] 19 next *vertexNode[T] 20 } 21 22 type polygonNode[T constraints.Float] struct { 23 left *vertexNode[T] 24 right *vertexNode[T] 25 next *polygonNode[T] 26 proxy *polygonNode[T] 27 active bool 28 } 29 30 func (p *polygonNode[T]) addLeft(pt geom.Point[T]) { 31 p.proxy.left = &vertexNode[T]{ 32 pt: pt, 33 next: p.proxy.left, 34 } 35 } 36 37 func (p *polygonNode[T]) addRight(pt geom.Point[T]) { 38 v := &vertexNode[T]{pt: pt} 39 if p.proxy.right != nil { 40 p.proxy.right.next = v 41 } 42 p.proxy.right = v 43 } 44 45 func (p *polygonNode[T]) mergeLeft(other, list *polygonNode[T]) { 46 if p.proxy != other.proxy { 47 p.proxy.right.next = other.proxy.left 48 other.proxy.left = p.proxy.left 49 for target := p.proxy; list != nil; list = list.next { 50 if list.proxy == target { 51 list.active = false 52 list.proxy = other.proxy 53 } 54 } 55 } 56 } 57 58 func (p *polygonNode[T]) mergeRight(other, list *polygonNode[T]) { 59 if p.proxy != other.proxy { 60 other.proxy.right.next = p.proxy.left 61 other.proxy.right = p.proxy.right 62 for target := p.proxy; list != nil; list = list.next { 63 if list.proxy == target { 64 list.active = false 65 list.proxy = other.proxy 66 } 67 } 68 } 69 } 70 71 func (p *polygonNode[T]) generate() Polygon[T] { 72 contourCount := 0 73 ptCounts := make([]int, 0, 32) 74 75 // Count the points of each contour and disable any that don't have enough points. 76 for poly := p; poly != nil; poly = poly.next { 77 if poly.active { 78 var prev *vertexNode[T] 79 ptCount := 0 80 for v := poly.proxy.left; v != nil; v = v.next { 81 if prev == nil || prev.pt != v.pt { 82 ptCount++ 83 } 84 prev = v 85 } 86 if ptCount > 2 { 87 ptCounts = append(ptCounts, ptCount) 88 contourCount++ 89 } else { 90 poly.active = false 91 } 92 } 93 } 94 if contourCount == 0 { 95 return Polygon[T]{} 96 } 97 98 // Create the polygon 99 result := make([]Contour[T], contourCount) 100 ci := 0 101 for poly := p; poly != nil; poly = poly.next { 102 if !poly.active { 103 continue 104 } 105 var prev *vertexNode[T] 106 result[ci] = make([]geom.Point[T], ptCounts[ci]) 107 v := len(result[ci]) - 1 108 for vtx := poly.proxy.left; vtx != nil; vtx = vtx.next { 109 if prev == nil || prev.pt != vtx.pt { 110 result[ci][v] = vtx.pt 111 v-- 112 } 113 prev = vtx 114 } 115 ci++ 116 } 117 return result 118 }