Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- class CSquareSerializer extends CSquareHelpers {
- case class RelativePoint(val x: Int, val y: Int)
- implicit def tuple2relpoint(t: (Int, Int)) = RelativePoint(t._1, t._2)
- sealed trait Component
- case class CoarseComponent(val q: Int) extends Component
- case class FineComponent(val q: Int, val x: Int, val y: Int) extends Component
- case class TopComponent(val q: Int, val x: Int, val y: Int) extends Component
- def serialize(square: CSquare) = {
- val size = square.size
- val disp = square.displacement
- val lastGranularity = round(10 * size / pow(10, round(log(size) / log(10.0)))) / 10.0
- val normalizedSize = if (lastGranularity == 0.5) size / 5 else size
- // compute list of square component sizes: e.g. [10, 1, 0.1, 0.01, 0.001])
- val sizes = from(-1).map(a => pow(10, -a)).takeWhile(_ >= normalizedSize)
- val x = disp(0) / 10
- val y = disp(1) / 10
- val decX = x - x.floor
- val decY = y - y.floor
- // clear rounding issues
- def clean(x: Double) = round(x * 100000) / 100000.0
- // create a stream of digits
- def digits(x: Double) = clean(x).toString.slice(2, 1 + sizes.size).map(_.toString.toInt).padTo(sizes.size - 1, 0)
- def format(q: Component): String = q match {
- case CoarseComponent(q) => "%s".format(q)
- case FineComponent(q, x, y) => "%s%s%s".format(q, y, x)
- case TopComponent(q, x, y) => "%s%d%02d".format(q, y, x)
- }
- // handle last quadrant when the final granularity is 0.5
- def smartQuadrantTuple(a: ((Int, Int), Int)): Component = smartQuadrant(a._1, a._2)
- def smartQuadrant(relPoint: RelativePoint, n: Int): Component = {
- val q = quadrant(relPoint)
- if ((lastGranularity == 0.5) && (n == sizes.size - 2))
- CoarseComponent(q.q)
- else
- q
- }
- def quadrant(a: RelativePoint): FineComponent = a match {
- case RelativePoint(x, y) if x < 5 && y < 5 => FineComponent(1, x, y)
- case RelativePoint(x, y) if x >= 5 && y < 5 => FineComponent(2, x, y)
- case RelativePoint(x, y) if x < 5 && y >= 5 => FineComponent(3, x, y)
- case RelativePoint(x, y) if x >= 5 && y >= 5 => FineComponent(4, x, y)
- }
- def topQuadrant = {
- val v = square.quadrant * DenseVector(1, 1)
- (v(0), v(1)) match {
- case (x, y) if x > 0 && y > 0 => 1
- case (x, y) if x > 0 && y < 0 => 3
- case (x, y) if x < 0 && y < 0 => 5
- case (x, y) if x < 0 && y > 0 => 7
- }
- }
- // the first component is computed differently, using specifi codes for top level quadrants
- val topComponent = TopComponent(topQuadrant, floor(x).toInt, floor(y).toInt)
- // the rest is more regular, we just have to stream the x,y digits
- // and generate code components for the subquadrant
- val rest = (digits(decX) zip digits(decY)).zipWithIndex.map(smartQuadrantTuple).toList
- // and then glue the formatted components together
- (topComponent :: rest).map(format).mkString(":")
- }
- }
Add Comment
Please, Sign In to add comment