 	}
 }
 
-typealias Result = (bestPoint: Vertex, bestDistance: Double)
+typealias Result = (bestPoint: PointForm, bestDistance: Double)
 
-func kdFindNearest(query q: Vertex, node: KDNode,
+func kdFindNearest<T:PointForm>(query q: T, node: KDNode<T>,
 									 d: SplitDirection, aabb: CGRect,
 									 result: Result) -> Result {
 	switch node {

}

// MARK: Helpers
fileprivate func kdCompare(u: Vertex, v: Vertex, d: SplitDirection) -> Bool {
	switch d {
	case .x: return u.x < v.x
	case .y: return u.y < v.y
	}
}

fileprivate func sqDist(v: Vertex, q: Vertex) -> Double {
	return Double(pow(v.x - q.x, 2.0) + pow(v.y - q.y, 2.0))
}

fileprivate func bbDist(v: Vertex, bb: CGRect) -> Double {
	let dx = max(abs(CGFloat(v.x) - bb.midX) - bb.width / 2.0, 0.0)
	let dy = max(abs(CGFloat(v.y) - bb.midY) - bb.height / 2.0, 0.0)
	return Double(dx * dx + dy * dy)
}


}

// MARK: Algoritm
func kdInsert<T:PointForm>(v: T, n: KDNode<T>, d: SplitDirection = .x) -> KDNode<T> {
	switch n {
	case .Empty: return KDNode(left: .Empty, v, right: .Empty, d)
	case .Split(let left, let a, let right, let d):
		guard a.p != v.p else { return n }
		if kdCompare(u: v, v: a, d: d) {
			return n.replaceLeft(newLeft: kdInsert(v: v, n: left, d: d.flip()))
		} else {
