I have a shape like in code below:
import SwiftUI
struct ContentView: View {
var body: some View {
let myCustomInsettableShape = HexagonShape(thickness: 100.0)
ZStack {
myCustomInsettableShape
.fill(Color.blue)
myCustomInsettableShape
.strokeBorder(Color.black.opacity(0.5), style: StrokeStyle(lineWidth: 50.0, lineCap: .round, lineJoin: .miter))
}
.background(Color.red)
.padding(50)
}
}
struct HexagonShape: InsettableShape {
var thickness: CGFloat
var insetAmount: CGFloat = CGFloat.zero
func path(in rect: CGRect) -> Path {
var path: Path = Path()
let halfThickness: CGFloat = thickness/2.0
let dx: CGFloat
let dy: CGFloat
if (insetAmount > .zero) && (halfThickness > .zero) {
let diagonal = sqrt((halfThickness * halfThickness) + (halfThickness * halfThickness))
dx = insetAmount * diagonal / halfThickness
dy = insetAmount * diagonal / halfThickness
} else {
dx = .zero
dy = .zero
}
path.move(to: CGPoint(x: rect.minX + dx, y: rect.minY + halfThickness))
path.addLine(to: CGPoint(x: rect.midX, y: rect.minY + dy))
path.addLine(to: CGPoint(x: rect.maxX - dx, y: rect.minY + halfThickness))
path.addLine(to: CGPoint(x: rect.maxX - dx, y: rect.maxY - halfThickness))
path.addLine(to: CGPoint(x: rect.midX, y: rect.maxY - dy))
path.addLine(to: CGPoint(x: rect.minX + dx, y: rect.maxY - halfThickness))
path.closeSubpath()
return path
}
func inset(by amount: CGFloat) -> some InsettableShape {
var myShape: Self = self
myShape.insetAmount += amount
return myShape
}
}
The result of shape is like this:
The blue filled shape is what I want, and i want my strokeBorder have the same shape, but I do not know how to implement insetAmount, thickness is a value that can be changed showing and telling the form of shape.
I think the geometry is like this:
When this is used as the basis for implementation, it seems to work:
func path(in rect: CGRect) -> Path {
var path: Path = Path()
let halfThickness: CGFloat = thickness/2.0
let dyTop: CGFloat
let dySide: CGFloat
if insetAmount > 0 && rect.width > 0 && rect.height > 0 {
let alpha = atan2(thickness, rect.width)
dyTop = insetAmount / cos(alpha)
let sideAngle = alpha + (Double.pi / 2)
let beta = sideAngle / 2
dySide = insetAmount / tan(beta)
} else {
dyTop = 0
dySide = 0
}
path.move(to: CGPoint(x: rect.minX + insetAmount, y: rect.minY + halfThickness + dySide))
path.addLine(to: CGPoint(x: rect.midX, y: rect.minY + dyTop))
path.addLine(to: CGPoint(x: rect.maxX - insetAmount, y: rect.minY + halfThickness + dySide))
path.addLine(to: CGPoint(x: rect.maxX - insetAmount, y: rect.maxY - halfThickness - dySide))
path.addLine(to: CGPoint(x: rect.midX, y: rect.maxY - dyTop))
path.addLine(to: CGPoint(x: rect.minX + insetAmount, y: rect.maxY - halfThickness - dySide))
path.closeSubpath()
return path
}