Skip to content

Commit

Permalink
(BreakMap) Subclasses may or may not prove useful
Browse files Browse the repository at this point in the history
- Using subclasses like this, we can ask for a `BreakMap[Int,
Int]` in `Tile`, keep a clean implementation of `BreakMap`
(and the binary search logic), and only take a ~3%
performance hit. This 3% might be due to `Tile.map` or
because of the inheritance, I'm not sure yet.

- Implementing a sexier `foreach` which allows us more
fine-grained access when writing the target array might
overcome that 3%.
  • Loading branch information
fosskers committed Oct 31, 2016
1 parent ea690b1 commit 9bfa92c
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 8 deletions.
27 changes: 23 additions & 4 deletions raster/src/main/scala/geotrellis/raster/Tile.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,40 @@

package geotrellis.raster

import geotrellis.raster.render.{ BreakMap, I2IBreakMap, I2DBreakMap, D2DBreakMap, D2IBreakMap }

import spire.syntax.cfor._
import com.typesafe.scalalogging._

import java.util.Locale

import math.BigDecimal

import collection.mutable.ArrayBuffer
import scala.collection.mutable.ArrayBuffer
import scala.math.BigDecimal
import scala.specialized


/**
* Base trait for a Tile.
*/
trait Tile extends CellGrid with IterableTile with MappableTile[Tile] with LazyLogging {

/** Map cell values according to buckets they fall into from a given
* [[ValueMap]].
*
* This is akin to `Tile.color(ColorMap)`, except generalized
* across more types.
*/
/*
def mapWith[
@specialized(Int, Double) A,
@specialized(Int, Double) B
](bm: BreakMap[A, B]): Tile = bm match {
case b: I2IBreakMap => map(z => b.map(z))
case b: D2DBreakMap => mapDouble(z => b.map(z))
}
*/

def mapWith(bm: BreakMap[Int, Int]): Tile = map(z => bm.map(z))

/**
* Execute a function at each pixel of a [[Tile]]. Two functions
* are given: an integer version which is used if the tile is an
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package geotrellis.raster.render

import geotrellis.raster._
import geotrellis.util._

import spire.algebra._
Expand All @@ -16,18 +17,20 @@ import scala.specialized
* with breaks and a break strategy.
*
* {{{
* val vm: ValueMap = ...
* val bm: BreakMap = ...
* val t: Tile = ...
*
* // Map all the cells of `t` to a target bin value in O(klogn).
* val newT: Tile = t.mapWith(vm)
* }}}
*
* '''Note:''' `A` and `B` are specialized on `Int` and `Double`.
*/
abstract class ValueMap[
abstract class BreakMap[
@specialized(Int, Double) A: Order,
@specialized(Int, Double) B: Order
](
valMap: Map[A, B],
breakMap: Map[A, B],
boundary: ClassBoundaryType,
noDataValue: B,
fallbackValue: B,
Expand All @@ -39,7 +42,7 @@ abstract class ValueMap[

/* A Binary Tree of the mappable values */
private lazy val vmTree: BTree[(A, B)] = {
val a: Array[(A, B)] = valMap.toArray
val a: Array[(A, B)] = breakMap.toArray

Sorting.quickSort(a)

Expand Down Expand Up @@ -93,3 +96,39 @@ abstract class ValueMap[
}
}
}

// TODO Clean up inheritance mechanism.
class I2IBreakMap(breakMap: Map[Int, Int]) extends BreakMap[Int, Int](
breakMap, LessThanOrEqualTo, 0x00000000, 0x00000000, false
) {
def noDataCheck(a: Int): Boolean = isNoData(a)
}

class I2DBreakMap(breakMap: Map[Int, Double]) extends BreakMap[Int, Double](
breakMap, LessThanOrEqualTo, Double.NaN, Double.NaN, false
) {
def noDataCheck(a: Int): Boolean = isNoData(a)
}

class D2DBreakMap(breakMap: Map[Double, Double]) extends BreakMap[Double, Double](
breakMap, LessThanOrEqualTo, Double.NaN, Double.NaN, false
) {
def noDataCheck(a: Double): Boolean = isNoData(a)
}

class D2IBreakMap(breakMap: Map[Double, Int]) extends BreakMap[Double, Int](
breakMap, LessThanOrEqualTo, 0x00000000, 0x00000000, false
) {
def noDataCheck(a: Double): Boolean = isNoData(a)
}

/** Helper methods for constructing BreakMaps. */
object BreakMap {
def i2i(m: Map[Int, Int]): BreakMap[Int, Int] = new I2IBreakMap(m)

def i2d(m: Map[Int, Double]): BreakMap[Int, Double] = new I2DBreakMap(m)

def d2d(m: Map[Double, Double]): BreakMap[Double, Double] = new D2DBreakMap(m)

def d2i(m: Map[Double, Int]): BreakMap[Double, Int] = new D2IBreakMap(m)
}

0 comments on commit 9bfa92c

Please sign in to comment.