func EdgeInterpolateAtDistance(ax s1.Angle, a, b Point, ab s1.Angle) Point { axRad := ax.Radians() abRad := ab.Radians() f := math.Sin(axRad) / math.Sin(abRad) e := math.Cos(axRad) - f*math.Cos(abRad) v0 := a.Mul(e) v1 := b.Mul(f) return Point{v0.Add(v1).Normalize()} }
// radiusToHeight converts an s1.Angle into the height of the cap. func radiusToHeight(r s1.Angle) float64 { if r.Radians() < 0 { return emptyHeight } if r.Radians() >= math.Pi { return fullHeight } // The height of the cap can be computed as 1 - cos(r), but this isn't very // accurate for angles close to zero (where cos(r) is almost 1). The // formula below has much better precision. d := math.Sin(0.5 * r.Radians()) return 2 * d * d }
func (p *Polygon) InternalClipPolyline(invert bool, a *Polyline, out *[]*Polyline, mergeRadius s1.Angle) { // Clip the polyline A to the interior of this polygon. // The resulting polyline(s) will be appended to "out". // If invert is true, we clip A to the exterior of this polygon // instead. Vertices will be dropped such that adjacent vertices // will not be closer than "mergeRadius". // // We do the intersection/subtraction by walking the polyline edges. // For each edge, we compute all intersections with the polygon // boundary and sort them in increasing order of distance along that // edge. We then divide the intersection points into pairs, and // output a clipped polyline segment for each one. // We keep track of whether we're inside or outside of the polygon // at all times to decide which segments to output. var intersections IntersectionSet var vertices []Point index := NewPolygonIndex(p, false) n := a.NumVertices() inside := p.ContainsPoint(a.Vertex(0)) != invert for j := 0; j < n-1; j++ { a0 := a.Vertex(j) a1 := a.Vertex(j + 1) ClipEdge(a0, a1, index, true, &intersections) if inside { intersections = append(intersections, FloatPointPair{0, a0}) } inside = (len(intersections) & 1) != 0 if inside { intersections = append(intersections, FloatPointPair{1, a1}) } sort.Sort(intersections) // At this point we have a sorted array of vertex pairs // representing the edge(s) obtained after clipping (a0,a1) // against the polygon. for k := 0; k < len(intersections); k += 2 { if intersections[k] == intersections[k+1] { continue } v0 := intersections[k].second v1 := intersections[k+1].second // If the gap from the previous vertex to this one is // large enough, start a new polyline. if len(vertices) > 0 && vertices[len(vertices)-1].Angle(v0.Vector).Radians() > mergeRadius.Radians() { *out = append(*out, PolylineFromPoints(vertices)) vertices = []Point{} } // Append this segment to the current polyline, // ignoring any vertices that are too close to the // previous vertex. if len(vertices) == 0 { vertices = append(vertices, v0) } if vertices[len(vertices)-1].Angle(v1.Vector).Radians() > mergeRadius.Radians() { vertices = append(vertices, v1) } } intersections = IntersectionSet{} } if len(vertices) > 0 { *out = append(*out, PolylineFromPoints(vertices)) } }