mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-30 01:27:26 +08:00
1 parent
64f9ec4241
commit
0be872691d
76 files changed
+1926
-1307
No files matched your search
@@ -0,0 +1,87 @@
|
||||
// Copyright 2025-2026 肖其顿 (XIAO QI DUN)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package geom
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
// ConvexContains 判断单个非退化凸直线区域是否包含另一闭合直线区域
|
||||
// 入参: outer 外部区域, inner 内部区域
|
||||
// 返回: bool 是否完全包含,曲线及多轮廓返回false
|
||||
func ConvexContains(outer, inner Path) bool {
|
||||
a, b := geometryPolygonPoints(outer), geometryPolygonPoints(inner)
|
||||
if len(a) < 3 || len(b) < 3 {
|
||||
return false
|
||||
}
|
||||
nondegenerate := false
|
||||
for i, start := range a {
|
||||
end := a[(i+1)%len(a)]
|
||||
dx, dy := end.X-start.X, end.Y-start.Y
|
||||
length := math.Hypot(dx, dy)
|
||||
if !finite(length) {
|
||||
return false
|
||||
}
|
||||
if length == 0 {
|
||||
continue
|
||||
}
|
||||
dx, dy = dx/length, dy/length
|
||||
distance := func(point Point) float64 {
|
||||
x, y := point.X-start.X, point.Y-start.Y
|
||||
value := math.FMA(dx, y, -dy*x)
|
||||
bound := (math.Abs(dx*y) + math.Abs(dy*x) + math.Abs(dx)*(math.Abs(point.Y)+math.Abs(start.Y)) + math.Abs(dy)*(math.Abs(point.X)+math.Abs(start.X))) * 0x1p-49
|
||||
if finite(bound) && math.Abs(value) <= bound {
|
||||
return 0
|
||||
}
|
||||
return value
|
||||
}
|
||||
sign := 0.0
|
||||
for _, point := range a {
|
||||
value := distance(point)
|
||||
if !finite(value) || sign*value < 0 {
|
||||
return false
|
||||
}
|
||||
if value != 0 {
|
||||
sign, nondegenerate = math.Copysign(1, value), true
|
||||
}
|
||||
}
|
||||
for _, point := range b {
|
||||
value := distance(point)
|
||||
if !finite(value) || sign*value < 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return nondegenerate
|
||||
}
|
||||
|
||||
// geometryPolygonPoints 读取单个显式闭合直线轮廓的顶点,不修改原路径
|
||||
// 入参: path 直线轮廓
|
||||
// 返回: []Point 独立顶点,其他路径返回nil
|
||||
func geometryPolygonPoints(path Path) []Point {
|
||||
if len(path) < 4 || path[0].Verb != Move || path[len(path)-1].Verb != ClosePath {
|
||||
return nil
|
||||
}
|
||||
for i, segment := range path[:len(path)-1] {
|
||||
if i > 0 && segment.Verb != Line || !finite(segment.End.X) || !finite(segment.End.Y) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
points := make([]Point, len(path)-1)
|
||||
for i := range points {
|
||||
points[i] = path[i].End
|
||||
}
|
||||
return points
|
||||
}
|
||||
Reference in new issue
Block a user