mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 16:59:27 +08:00
71 lines
2.3 KiB
Go
71 lines
2.3 KiB
Go
// 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 ofdgo
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/binary"
|
|
"math"
|
|
|
|
"github.com/tdewolff/canvas"
|
|
)
|
|
|
|
// canvasGeometryDigest 按完整坐标、路径顺序及几何容差计算摘要
|
|
// 入参: paths 非空路径序列
|
|
// 返回: [32]byte 几何摘要
|
|
func canvasGeometryDigest(paths ...*canvas.Path) [32]byte {
|
|
hash := sha256.New()
|
|
var data [512]byte
|
|
binary.LittleEndian.PutUint64(data[:8], math.Float64bits(canvas.Tolerance))
|
|
binary.LittleEndian.PutUint64(data[8:16], math.Float64bits(canvas.Epsilon))
|
|
binary.LittleEndian.PutUint64(data[16:24], math.Float64bits(canvas.BentleyOttmannEpsilon))
|
|
hash.Write(data[:24])
|
|
for _, path := range paths {
|
|
values := path.Data()
|
|
binary.LittleEndian.PutUint64(data[:8], uint64(len(values)))
|
|
hash.Write(data[:8])
|
|
for len(values) > 0 {
|
|
count := min(len(values), len(data)/8)
|
|
for i, value := range values[:count] {
|
|
binary.LittleEndian.PutUint64(data[i*8:], math.Float64bits(value))
|
|
}
|
|
hash.Write(data[:count*8])
|
|
values = values[count:]
|
|
}
|
|
}
|
|
var key [32]byte
|
|
hash.Sum(key[:0])
|
|
return key
|
|
}
|
|
|
|
// settleCanvasPath 复用复杂路径的填充规范化结果,返回独立副本
|
|
// 入参: path 页面坐标路径, rule 填充规则
|
|
// 返回: *canvas.Path 规范化填充轮廓
|
|
func (r *Renderer) settleCanvasPath(path *canvas.Path, rule canvas.FillRule) *canvas.Path {
|
|
if len(path.Data()) < 256 {
|
|
return path.Settle(rule)
|
|
}
|
|
key := canvasFillKey{digest: canvasGeometryDigest(path), rule: rule}
|
|
cache := r.canvasSettledPaths()
|
|
if result, ok := cache.get(key); ok {
|
|
return result.Copy()
|
|
}
|
|
result := path.Settle(rule)
|
|
if cost := len(result.Data())*8 + 256; cost <= cache.limit {
|
|
cache.put(key, result.Copy(), cost)
|
|
}
|
|
return result
|
|
}
|