module NSWTopo::Spot
Constants
- CREATE
- DEFAULTS
- NOISE_MM
Public Instance Methods
candidates()
click to toggle source
# File lib/nswtopo/layer/spot.rb, line 75 def candidates @candidates ||= Dir.mktmppath do |temp_dir| raw_path = temp_dir / "raw.tif" dem_path = temp_dir / "dem.tif" aspect_path = temp_dir / "aspect.bil" if @smooth.zero? get_dem temp_dir, dem_path else get_dem temp_dir, raw_path blur_dem raw_path, dem_path end log_update "%s: calculating aspect map" % @name OS.gdaldem "aspect", dem_path, aspect_path, "-trigonometric" Enumerator.new do |yielder| aspect = ESRIHdr.new aspect_path, -9999 indices = [-1, 0, 1].map do |row| [-1, 0, 1].map do |col| row * aspect.ncols + col - 1 end end.flatten.values_at(0,3,6,7,8,5,2,1,0) aspect.nrows.times do |i| log_update "%s: finding flat areas: %.1f%%" % [@name, 100.0 * i / aspect.nrows] aspect.ncols.times do |j| indices.map!(&:next) next if i < 1 || j < 1 || i > aspect.nrows - 2 || j > aspect.ncols - 2 ring = aspect.values.values_at *indices next if ring.any?(&:nil?) anticlockwise = ring.each_cons(2).map do |a1, a2| (a2 - a1) % 360 < 180 end yielder << [[j + 1, i + 1], true] if anticlockwise.all? yielder << [[j + 1, i + 1], false] if anticlockwise.none? end end end.group_by(&:last).flat_map do |knoll, group| pixels = group.map(&:first) locations = raster_locations dem_path, pixels elevations = raster_values dem_path, pixels locations.zip(elevations).map do |coordinates, elevation| GeoJSON::Point.new coordinates, "knoll" => knoll, "elevation" => elevation end.each do |feature| feature.extend Candidate, ordering end end end end
get_features()
click to toggle source
# File lib/nswtopo/layer/spot.rb, line 127 def get_features selected, rejected, remaining = [], Set[], AVLTree.new index = RTree.load(candidates, &:bounds) log_update "%s: choosing candidates" % @name candidates.to_set.each do |candidate| buffer = NOISE_MM * @map.scale / 1000.0 index.search(candidate.bounds(buffer)).each do |other| next unless candidate["knoll"] ^ other["knoll"] next if [candidate, other].map(&:coordinates).distance > buffer rejected << candidate << other end end.difference(rejected).each do |candidate| buffer = @spacing * @map.scale / 1000.0 index.search(candidate.bounds(buffer)).each do |other| next if other == candidate next if rejected === other next if [candidate, other].map(&:coordinates).distance > buffer candidate.conflicts << other end end.each do |candidate| remaining << candidate end while chosen = remaining.first log_update "%s: choosing candidates: %i remaining" % [@name, remaining.count] selected << chosen removals = Set[chosen] | chosen.conflicts removals.each do |candidate| remaining.delete candidate end.map(&:conflicts).inject(&:|).subtract(removals).each do |other| remaining.delete other other.conflicts.subtract removals remaining.insert other end end selected.each do |feature| feature.properties.replace "label" => feature["elevation"].round end.yield_self do |features| GeoJSON::Collection.new @map.projection, features end end
margin()
click to toggle source
# File lib/nswtopo/layer/spot.rb, line 21 def margin { mm: 3 * @smooth } end
ordering()
click to toggle source
# File lib/nswtopo/layer/spot.rb, line 67 def ordering @ordering ||= case @prefer when "knolls" then Candidate::PreferKnolls when "saddles" then Candidate::PreferSaddles else Candidate::PreferNeither end end
raster_locations(path, pixels)
click to toggle source
# File lib/nswtopo/layer/spot.rb, line 33 def raster_locations(path, pixels) OS.gdaltransform "-output_xy", path do |stdin| pixels.each { |pixel| stdin.puts "%i %i" % pixel } end.each_line.map do |line| line.chomp.split(?\s).map(&:to_f) end end
raster_values(path, pixels)
click to toggle source
# File lib/nswtopo/layer/spot.rb, line 25 def raster_values(path, pixels) OS.gdallocationinfo "-valonly", path do |stdin| pixels.each { |pixel| stdin.puts "%i %i" % pixel } end.each_line.map do |line| Float(line) rescue nil end end