Есть несколько проблем с кодом в его нынешнем виде. Во-первых, как указано в комментариях, уравнение параметри c для переводов необходимо повернуть на 90 градусов:
let deg: Float = (Float(i) * 60) - 90.0
Следующая проблема заключается в том, что центр ограничительной рамки треугольника и Центр тяжести треугольника не совпадают. Это важно, потому что уравнение параметри c вычисляет, где должны располагаться центроиды треугольников, а не центры их ограничивающих прямоугольников. Итак, нам нужен способ расчета центроида. Это можно сделать, добавив следующий метод расширения к TrianglePlane
:
extension TrianglePlane {
/// Calculates the centroid of the triangle
func centroid() -> CGPoint
{
let max: CGFloat = self.size
let min: CGFloat = 0
let peak = UIBezierPath.middlePeak(height: max)
let xAvg = (min + max / CGFloat(2.0) + max) / CGFloat(3.0)
let yAvg = (min + peak + min) / CGFloat(3.0)
return CGPoint(x: xAvg, y: yAvg)
}
}
. Это позволяет вычислить правильное radius
для уравнения параметрирования c:
let height = Float(UIBezierPath.middlePeak(height: tri.size))
let centroid = tri.centroid()
let radius = height - Float(centroid.y)
Окончательная поправка заключается в расчете смещения между началом треугольника и центроидом. Это исправление зависит от того, был ли треугольник перевернут поворотом или нет:
let x1 = radius * cos(radians)
let y1 = radius * sin(radians)
let dx = Float(-centroid.x)
let dy = (i % 2 == 0) ? Float(centroid.y) - height : Float(-centroid.y)
tri.position.x = x1 + dx
tri.position.y = y1 + dy
Соединение всего этого вместе дает желаемый результат.
Полный рабочий ViewController можно найти в этом gist
Примечание код можно значительно упростить, сделав начало треугольника центром тяжести.