Skip to content

Instantly share code, notes, and snippets.

@sketchytech
Created November 26, 2014 17:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sketchytech/25aeebf42d8a298c3f3e to your computer and use it in GitHub Desktop.
Save sketchytech/25aeebf42d8a298c3f3e to your computer and use it in GitHub Desktop.
Swift: Cube with 2D hexagon on top face
import UIKit
class ViewController: UIViewController {
var topOfCube:CAShapeLayer!
var leftOfCube:CAShapeLayer!
var frontOfCube:CAShapeLayer!
var topHex:CAShapeLayer!
override func viewDidLoad() {
super.viewDidLoad()
frontOfCube = CAShapeLayer()
frontOfCube.fillColor = UIColor(hue: 117/360, saturation: 29/100, brightness: 96/100, alpha: 1.0).CGColor
self.view.layer.addSublayer(frontOfCube)
topOfCube = CAShapeLayer()
self.view.layer.addSublayer(topOfCube)
topOfCube.fillColor = UIColor(hue: 117/360, saturation: 29/100, brightness: 76/100, alpha: 1.0).CGColor
leftOfCube = CAShapeLayer()
leftOfCube.fillColor = UIColor(hue: 117/360, saturation: 29/100, brightness: 56/100, alpha: 1.0).CGColor
leftOfCube.lineWidth = 3
leftOfCube.zPosition = 3
self.view.layer.addSublayer(leftOfCube)
topHex = CAShapeLayer()
topHex.lineWidth = 1
topHex.strokeColor = UIColor.whiteColor().CGColor
topHex.fillColor = UIColor(hue: 117/360, saturation: 29/100, brightness: 76/100, alpha: 1.0).CGColor
self.view.layer.addSublayer(topHex)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidAppear(animated: Bool) {
let positionX:CGFloat = 200
let positionY:CGFloat = 200
let radius:CGFloat = 100
// cube top
var path0 = cubeTopRotatedOntoRightFrontFace(x: positionX, y: positionY, radius: radius, sides: 6, adjustment: 90, newangle: 0)
topOfCube.path = path0
// // cube topHex
let HexPoints0 = HexagonRotatedPoints(sides: 6, x: positionX, y: positionY, radius: radius, adjustment: 90, direction: HexagonRollOntoDirection.RightFront, newangle: 0)
// +/- 1 is inset because of hexagon strokeWidth
let C2Y0 = HexPoints0.index0.y + ((HexPoints0.index1.y-HexPoints0.index0.y)/4)*2 + 1
let C2X0 = HexPoints0.index1.x + ((HexPoints0.index0.x-HexPoints0.index1.x)/4)*2 - 1
let D1Y0 = HexPoints0.index1.y + ((HexPoints0.origin.y-HexPoints0.index1.y)/4)*1 - 1
let D1X0 = HexPoints0.index1.x + ((HexPoints0.origin.x-HexPoints0.index1.x)/4)*1 - 1
let D3Y0 = HexPoints0.index1.y + ((HexPoints0.origin.y-HexPoints0.index1.y)/4)*3 - 1
let D3X0 = HexPoints0.index1.x + ((HexPoints0.origin.x-HexPoints0.index1.x)/4)*3 - 1
let A2Y0 = HexPoints0.index5.y + ((HexPoints0.origin.y-HexPoints0.index5.y)/4)*2 - 1
let A2X0 = HexPoints0.origin.x + ((HexPoints0.index5.x-HexPoints0.origin.x)/4)*2 - 1
let B3Y0 = HexPoints0.index0.y + ((HexPoints0.index5.y-HexPoints0.index0.y)/4)*3 + 1
let B3X0 = HexPoints0.index0.x + ((HexPoints0.index5.x-HexPoints0.index0.x)/4)*3 - 1
let B1Y0 = HexPoints0.index0.y + ((HexPoints0.index5.y-HexPoints0.index0.y)/4)*1 + 1
let B1X0 = HexPoints0.index0.x + ((HexPoints0.index5.x-HexPoints0.index0.x)/4)*1 - 1
var HexPoints0Path = CGPathCreateMutable()
CGPathMoveToPoint(HexPoints0Path, nil, C2X0, C2Y0)
CGPathAddLineToPoint(HexPoints0Path, nil, D1X0, D1Y0)
CGPathAddLineToPoint(HexPoints0Path, nil, D3X0, D3Y0)
CGPathAddLineToPoint(HexPoints0Path, nil, A2X0, A2Y0)
CGPathAddLineToPoint(HexPoints0Path, nil, B3X0, B3Y0)
CGPathAddLineToPoint(HexPoints0Path, nil, B1X0, B1Y0)
CGPathCloseSubpath(HexPoints0Path)
topHex.path = HexPoints0Path
// cube left
var path10 = cubeLeftRotated(x: positionX, y: positionY, radius: radius, sides: 6, adjustment: 90, newangle: 0)
leftOfCube.path = path10
// front of cube
var path110 = cubeFrontRotated(x: positionX, y: positionY, radius: radius, sides: 6, adjustment: 90, newangle: 0)
frontOfCube.path = path110
}
}
func cubeTopRotatedOntoRightFrontFace(#x:CGFloat, #y:CGFloat, #radius:CGFloat, #sides:Int, #adjustment:CGFloat, #newangle:CGFloat) -> CGPathRef {
let path = CGPathCreateMutable()
// HexagonRotatedPoints class takes details and returns new points at rotation angle
let points = HexagonRotatedPoints(sides: sides,x: x,y: y,radius: radius,adjustment: adjustment, direction:.RightFront,newangle:newangle)
CGPathMoveToPoint(path, nil, points.origin.x, points.origin.y)
CGPathAddLineToPoint(path, nil, points.index1.x, points.index1.y)
CGPathAddLineToPoint(path, nil, points.index0.x, points.index0.y)
CGPathAddLineToPoint(path, nil, points.index5.x, points.index5.y)
CGPathCloseSubpath(path)
return path
}
func cubeLeftRotated(#x:CGFloat, #y:CGFloat, #radius:CGFloat, #sides:Int, #adjustment:CGFloat, #newangle:CGFloat) -> CGPathRef {
let path = CGPathCreateMutable()
var points = HexagonRotatedPoints(sides: sides,x: x,y: y,radius: radius,adjustment: adjustment,direction: .RightFront,newangle:newangle)
CGPathMoveToPoint(path, nil, points.index1.x, points.index1.y)
CGPathAddLineToPoint(path, nil, points.origin.x, points.origin.y)
CGPathAddLineToPoint(path, nil, points.index3.x, points.index3.y)
CGPathAddLineToPoint(path, nil, points.index2.x, points.index2.y)
// CGPathAddLineToPoint(path, nil, points[3].x, points[3].y)
CGPathCloseSubpath(path)
return path
}
func cubeBaseRotated(#x:CGFloat, #y:CGFloat, #radius:CGFloat, #sides:Int, #adjustment:CGFloat, #newangle:CGFloat) -> CGPathRef {
let path = CGPathCreateMutable()
var points = HexagonRotatedPoints(sides: sides,x: x,y: y,radius: radius,adjustment: adjustment,direction: .RightFront,newangle:newangle)
CGPathMoveToPoint(path, nil, points.index4.x, points.index1.y)
CGPathAddLineToPoint(path, nil, points.originrear.x, points.originrear.y)
CGPathAddLineToPoint(path, nil, points.index2.x, points.index2.y)
CGPathAddLineToPoint(path, nil, points.index3.x, points.index3.y)
CGPathCloseSubpath(path)
return path
}
func cubeBackRotated(#x:CGFloat, #y:CGFloat, #radius:CGFloat, #sides:Int, #adjustment:CGFloat, #newangle:CGFloat) -> CGPathRef {
let path = CGPathCreateMutable()
var points = HexagonRotatedPoints(sides: sides,x: x,y: y,radius: radius,adjustment: adjustment,direction: .RightFront,newangle:newangle)
CGPathMoveToPoint(path, nil, points.originrear.x, points.originrear.y)
CGPathAddLineToPoint(path, nil, points.index0.x, points.index0.y)
CGPathAddLineToPoint(path, nil, points.index1.x, points.index1.y)
CGPathAddLineToPoint(path, nil, points.index2.x, points.index2.y)
CGPathCloseSubpath(path)
return path
}
func cubeFrontRotated(#x:CGFloat, #y:CGFloat, #radius:CGFloat, #sides:Int, #adjustment:CGFloat, #newangle:CGFloat) -> CGPathRef {
let path = CGPathCreateMutable()
let points = HexagonRotatedPoints(sides: sides,x: x,y: y,radius: radius,adjustment: adjustment, direction:.RightFront,newangle:newangle)
CGPathMoveToPoint(path, nil, points.origin.x, points.origin.y)
CGPathAddLineToPoint(path, nil, points.index5.x, points.index5.y)
CGPathAddLineToPoint(path, nil, points.index4.x, points.index4.y)
CGPathAddLineToPoint(path, nil, points.index3.x, points.index3.y)
// CGPathAddLineToPoint(path, nil, points[3].x, points[3].y)
CGPathCloseSubpath(path)
return path
}
enum HexagonIndex:Int {
case Zero, One, Two, Three, Four, Five
}
func degree2radian(a:CGFloat)->CGFloat {
let b = CGFloat(M_PI) * a/180
return b
}
enum HexagonRollOntoDirection {
case RightFront, LeftFront, RightRear, LeftRear, ClockwiseSpin, AntiClockwiseSpin
}
func polygonPointArray(sides:Int,x:CGFloat,y:CGFloat,radius:CGFloat,adjustment:CGFloat=0)->[CGPoint] {
let angle = degree2radian(360/CGFloat(sides))
let cx = x // x origin
let cy = y // y origin
let r = radius // radius of circle
var i = sides
var points = [CGPoint]()
while points.count <= sides {
let xpo = cx - r * cos(angle * CGFloat(i)+degree2radian(adjustment))
let ypo = cy - r * sin(angle * CGFloat(i)+degree2radian(adjustment))
points.append(CGPoint(x: xpo, y: ypo))
i--;
}
return points
}
class HexagonRotatedPoints {
let origin:CGPoint, index0:CGPoint, index1:CGPoint, index2:CGPoint, index3:CGPoint, index4:CGPoint, index5:CGPoint, originrear:CGPoint
init (sides:Int,x:CGFloat,y:CGFloat,radius:CGFloat,adjustment:CGFloat, direction:HexagonRollOntoDirection, newangle:CGFloat) {
// Currently these points supply the points for a HexagonRollOntoDirection.RightFront
let points = polygonPointArray(sides,x,y,radius,adjustment: adjustment)
// cube is pivoting on index 3, so the x position never changes
let originX = points[2].x - radius * cos(degree2radian(newangle) + degree2radian(adjustment) + degree2radian(60))
// origin is at a point 60 degrees from the 0 line of index 2, it pivots on the arc of the circle from index 2 (to index 3)
let originY = points[2].y - radius * sin(degree2radian(newangle) + degree2radian(adjustment) + degree2radian(60))
origin = CGPoint(x: originX, y: originY)
// index 0 on the hexagon
let index0X = x - radius * cos(degree2radian(newangle) + degree2radian(adjustment))
let index0Y = y - radius * sin(degree2radian(newangle) + degree2radian(adjustment))
index0 = CGPoint(x: index0X, y: index0Y)
// index 1 is at the position 90 degrees (the adjustment) to index 2 and follows the arc of the index 2 circle (to the origin)
let index1X = points[2].x - radius * cos(degree2radian(newangle) + degree2radian(adjustment))
let index1Y = points[2].y - radius * sin(degree2radian(newangle) + degree2radian(adjustment))
index1 = CGPoint(x: index1X, y: index1Y)
// index 2 at 240 degrees to the 12 o'clock position of a circle about index 3
let index2x = x - radius * cos(degree2radian(newangle) + degree2radian(adjustment) + degree2radian(240))
let index2y = y - radius * sin(degree2radian(newangle) + degree2radian(adjustment) + degree2radian(240))
index2 = CGPoint(x: index2x, y: index2y)
// index 3 on hexagon (moves to index 2) [AJL: not entirely confident index 3 is correct)
let index3X = x - radius * cos(degree2radian(newangle) + degree2radian(adjustment) + degree2radian(180))
let index3Y = y - radius * sin(degree2radian(newangle) + degree2radian(adjustment) + degree2radian(180))
index3 = CGPoint(x: index3X, y: index3Y)
// index 4 on hexagon (moves to rear origin)
let index4X = points[5].x - radius * cos(degree2radian(180) + degree2radian(newangle) + degree2radian(adjustment))
let index4Y = points[5].y - radius * sin(degree2radian(180) + degree2radian(newangle) + degree2radian(adjustment))
index4 = CGPoint(x: index4X, y: index4Y)
// index 5 at 60 degrees to the top position
let index5X = x - radius * cos(degree2radian(newangle) + degree2radian(adjustment) + degree2radian(60))
let index5Y = y - radius * sin(degree2radian(newangle) + degree2radian(adjustment) + degree2radian(60))
index5 = CGPoint(x: index5X, y: index5Y)
// rear origin
let originrearX = points[5].x - radius * cos(degree2radian(240) + degree2radian(newangle) + degree2radian(adjustment))
let originrearY = points[5].y - radius * sin(degree2radian(240) + degree2radian(newangle) + degree2radian(adjustment))
originrear = CGPoint(x: originrearX, y: originrearY)
}
}
enum CubeRelativePosition:Int {
case Above = 0, LeftBehind, LeftFront, Underneath, RightFront, RightBehind
}
func positionNextCubeRotated(#x:CGFloat, #y:CGFloat, #radius:CGFloat, #sides:Int, #adjustment:CGFloat, #spaces:Int, #position:CubeRelativePosition, newangle:CGFloat) -> CGPoint {
// block rolls along slope, if HexagonRotatedPoints.origin taken would look like steps at 60 degrees
var points = HexagonRotatedPoints(sides: sides,x: x,y: y,radius: radius*CGFloat(spaces),adjustment: adjustment,direction:HexagonRollOntoDirection.RightFront,newangle:newangle).index5
// var newpoints = polygonPointArray(sides, points.x, points.y, radius, adjustment: adjustment)
return points
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment