nswtopo 3.0.1 → 3.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/bin/nswtopo +20 -4
  3. data/docs/contours.md +2 -0
  4. data/docs/relief.md +2 -3
  5. data/docs/spot-heights.md +2 -0
  6. data/lib/nswtopo/archive.rb +6 -3
  7. data/lib/nswtopo/chrome.rb +9 -6
  8. data/lib/nswtopo/commands/layers.rb +2 -2
  9. data/lib/nswtopo/config.rb +1 -0
  10. data/lib/nswtopo/formats/gemf.rb +1 -0
  11. data/lib/nswtopo/formats/kmz.rb +16 -10
  12. data/lib/nswtopo/formats/mbtiles.rb +1 -0
  13. data/lib/nswtopo/formats/pdf.rb +4 -3
  14. data/lib/nswtopo/formats/svg.rb +5 -13
  15. data/lib/nswtopo/formats/svgz.rb +1 -0
  16. data/lib/nswtopo/formats/zip.rb +5 -4
  17. data/lib/nswtopo/formats.rb +35 -36
  18. data/lib/nswtopo/geometry/r_tree.rb +24 -23
  19. data/lib/nswtopo/geometry/straight_skeleton/node.rb +4 -4
  20. data/lib/nswtopo/geometry/straight_skeleton/nodes.rb +51 -40
  21. data/lib/nswtopo/geometry/straight_skeleton/split.rb +2 -2
  22. data/lib/nswtopo/geometry/vector.rb +55 -49
  23. data/lib/nswtopo/geometry.rb +0 -5
  24. data/lib/nswtopo/gis/arcgis/layer/map.rb +11 -10
  25. data/lib/nswtopo/gis/arcgis/layer/query.rb +8 -10
  26. data/lib/nswtopo/gis/arcgis/layer.rb +7 -11
  27. data/lib/nswtopo/gis/dem.rb +3 -2
  28. data/lib/nswtopo/gis/gdal_glob.rb +3 -3
  29. data/lib/nswtopo/gis/geojson/collection.rb +60 -14
  30. data/lib/nswtopo/gis/geojson/line_string.rb +142 -1
  31. data/lib/nswtopo/gis/geojson/multi_line_string.rb +49 -7
  32. data/lib/nswtopo/gis/geojson/multi_point.rb +87 -0
  33. data/lib/nswtopo/gis/geojson/multi_polygon.rb +35 -23
  34. data/lib/nswtopo/gis/geojson/point.rb +16 -1
  35. data/lib/nswtopo/gis/geojson/polygon.rb +69 -7
  36. data/lib/nswtopo/gis/geojson.rb +92 -46
  37. data/lib/nswtopo/gis/projection.rb +5 -1
  38. data/lib/nswtopo/helpers/thread_pool.rb +39 -0
  39. data/lib/nswtopo/helpers.rb +44 -5
  40. data/lib/nswtopo/layer/arcgis_raster.rb +4 -6
  41. data/lib/nswtopo/layer/contour.rb +24 -26
  42. data/lib/nswtopo/layer/control.rb +5 -3
  43. data/lib/nswtopo/layer/declination.rb +14 -10
  44. data/lib/nswtopo/layer/feature.rb +5 -5
  45. data/lib/nswtopo/layer/grid.rb +19 -18
  46. data/lib/nswtopo/layer/labels/barriers.rb +23 -0
  47. data/lib/nswtopo/layer/labels/convex_hull.rb +12 -0
  48. data/lib/nswtopo/layer/labels/convex_hulls.rb +86 -0
  49. data/lib/nswtopo/layer/labels/label.rb +63 -0
  50. data/lib/nswtopo/layer/labels.rb +192 -315
  51. data/lib/nswtopo/layer/overlay.rb +11 -12
  52. data/lib/nswtopo/layer/raster.rb +1 -0
  53. data/lib/nswtopo/layer/relief.rb +6 -4
  54. data/lib/nswtopo/layer/spot.rb +11 -17
  55. data/lib/nswtopo/layer/{vector → vector_render}/cutout.rb +1 -1
  56. data/lib/nswtopo/layer/{vector → vector_render}/knockout.rb +2 -3
  57. data/lib/nswtopo/layer/{vector.rb → vector_render.rb} +20 -45
  58. data/lib/nswtopo/layer.rb +2 -1
  59. data/lib/nswtopo/map.rb +70 -56
  60. data/lib/nswtopo/svg.rb +5 -0
  61. data/lib/nswtopo/tiled_web_map.rb +3 -3
  62. data/lib/nswtopo/tree_indenter.rb +2 -2
  63. data/lib/nswtopo/version.rb +1 -1
  64. data/lib/nswtopo.rb +4 -0
  65. metadata +15 -17
  66. data/lib/nswtopo/geometry/overlap.rb +0 -47
  67. data/lib/nswtopo/geometry/segment.rb +0 -27
  68. data/lib/nswtopo/geometry/vector_sequence.rb +0 -180
  69. data/lib/nswtopo/helpers/array.rb +0 -19
  70. data/lib/nswtopo/helpers/concurrently.rb +0 -27
  71. data/lib/nswtopo/helpers/dir.rb +0 -7
  72. data/lib/nswtopo/helpers/hash.rb +0 -15
  73. data/lib/nswtopo/helpers/tar_writer.rb +0 -11
  74. data/lib/nswtopo/layer/labels/barrier.rb +0 -39
@@ -0,0 +1,86 @@
1
+ module NSWTopo
2
+ module Labels
3
+ class ConvexHulls < GeoJSON::MultiLineString
4
+ def initialize(feature, buffer, &block)
5
+ coordinates = case feature
6
+ when GeoJSON::Polygon then feature.rings
7
+ when GeoJSON::MultiPolygon then feature.rings
8
+ else feature
9
+ end.explode.flat_map do |feature|
10
+ case feature
11
+ when GeoJSON::Point # a point feature barrier
12
+ x, y = *feature
13
+ [[Vector[x-buffer, y-buffer], Vector[x+buffer, y-buffer], Vector[x+buffer, y+buffer], Vector[x-buffer, y+buffer]]]
14
+ when GeoJSON::LineString # a linestring label to be broken down into segment hulls
15
+ offsets = feature.each_cons(2).map do |p0, p1|
16
+ (p1 - p0).perp.normalised * buffer
17
+ end
18
+ corners = offsets.then do |offsets|
19
+ feature.closed? ? [offsets.last, *offsets, offsets.first] : [offsets.first, *offsets, offsets.last]
20
+ end.each_cons(2).map do |o01, o12|
21
+ next if o12.cross(o01) == 0
22
+ (o01 + o12).normalised * buffer * (o12.cross(o01) <=> 0)
23
+ end.each_cons(2)
24
+ feature.each_cons(2).zip(corners, offsets).map do |(p0, p1), (c0, c1), offset|
25
+ if c0 then [p0 + offset, p0 + c0, p0 - offset] else [p0 + offset, p0 - offset] end +
26
+ if c1 then [p1 - offset, p1 + c1, p1 + offset] else [p1 - offset, p1 + offset] end
27
+ end
28
+ end
29
+ end
30
+ super coordinates, &block
31
+ end
32
+
33
+ delegate :length => :@coordinates
34
+
35
+ def each(&block)
36
+ enum = Enumerator.new do |yielder|
37
+ @coordinates.each do |coordinates|
38
+ yielder << ConvexHull.new(self, coordinates)
39
+ end
40
+ end
41
+ block_given? ? enum.each(&block) : enum
42
+ end
43
+
44
+ def self.overlap?(ring0, ring1, buffer)
45
+ # implements Gilbert–Johnson–Keerthi
46
+ simplex = [ring0.first - ring1.first]
47
+ perp = simplex[0].perp
48
+ loop do
49
+ return true unless case
50
+ when simplex.one? then simplex[0].norm
51
+ when simplex.inject(&:-).dot(simplex[1]) > 0 then simplex[1].norm
52
+ when simplex.inject(&:-).dot(simplex[0]) < 0 then simplex[0].norm
53
+ else simplex.inject(&:cross).abs / simplex.inject(&:-).norm
54
+ end > buffer
55
+ max = ring0.max_by { |point| perp.cross point }
56
+ min = ring1.min_by { |point| perp.cross point }
57
+ support = max - min
58
+ return false unless (simplex[0] - support).cross(perp) > 0
59
+ rays = simplex.map { |point| point - support }
60
+ case simplex.length
61
+ when 1
62
+ case
63
+ when rays[0].dot(support) > 0
64
+ simplex, perp = [support], support.perp
65
+ when rays[0].cross(support) < 0
66
+ simplex, perp = [support, *simplex], rays[0]
67
+ else
68
+ simplex, perp = [*simplex, support], -rays[0]
69
+ end
70
+ when 2
71
+ case
72
+ when rays[0].cross(support) > 0 && rays[0].dot(support) < 0
73
+ simplex, perp = [simplex[0], support], -rays[0]
74
+ when rays[1].cross(support) < 0 && rays[1].dot(support) < 0
75
+ simplex, perp = [support, simplex[1]], rays[1]
76
+ when rays[0].cross(support) <= 0 && rays[1].cross(support) >= 0
77
+ return true
78
+ else
79
+ simplex, perp = [support], support.perp
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,63 @@
1
+ module NSWTopo
2
+ module Labels
3
+ class Label < ConvexHulls
4
+ def self.knockout(value)
5
+ Float(Numeric === value ? value : value ? Config.fetch("knockout", 0.3) : 0)
6
+ end
7
+
8
+ def initialize(baselines, feature, priority, elements, along: nil, fixed: nil, &block)
9
+ super baselines, 0.5 * feature["font-size"] do
10
+ @categories, @text, @dual, @layer_name, @label_index, @feature_index = feature.values_at(:categories, :text, :dual, :layer_name, :label_index, :feature_index)
11
+ @indices = [@label_index, @feature_index]
12
+ @priority, @elements, @along, @fixed = priority, elements, along, fixed
13
+ @hull = dissolve_points.convex_hull
14
+ @optional, @coexist, knockout = feature.values_at("optional", "coexist", "knockout")
15
+ @barrier_count = each.with_object(Label.knockout(knockout)).map(&block).inject(&:merge).size
16
+ @ordinal = [@barrier_count, @priority]
17
+ @separation = feature.fetch("separation", {})
18
+ end
19
+ end
20
+
21
+ attr_reader :categories, :text, :dual, :layer_name, :label_index, :feature_index, :indices
22
+ attr_reader :priority, :elements, :along, :fixed, :hull, :barrier_count, :ordinal, :separation
23
+
24
+ def point?
25
+ @along.nil?
26
+ end
27
+
28
+ def barriers?
29
+ @barrier_count > 0
30
+ end
31
+
32
+ def optional?
33
+ @optional
34
+ end
35
+
36
+ def coexists_with?(other)
37
+ Array(@coexist).include? other.layer_name
38
+ end
39
+
40
+ def <=>(other)
41
+ self.ordinal <=> other.ordinal
42
+ end
43
+
44
+ def self.overlaps(labels, group = labels, &block)
45
+ return Set[] unless group.any?(&block)
46
+ index = RTree.load(labels.flat_map(&:explode), &:bounds)
47
+ group.each.with_object Set[] do |label, overlaps|
48
+ next unless buffer = yield(label)
49
+ index.search(label.bounds, buffer).each do |other|
50
+ next if label == other.source
51
+ next if overlaps === [label, other.source]
52
+ next if overlaps === [other.source, label]
53
+ next unless label.length < 3 || ConvexHulls.overlap?(label.hull, other, buffer)
54
+ next unless label.any? do |hull|
55
+ ConvexHulls.overlap?(hull, other, buffer)
56
+ end
57
+ overlaps << [label, other.source]
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end