nswtopo 3.0 → 3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/nswtopo +19 -4
- data/docs/contours.md +2 -0
- data/docs/relief.md +2 -3
- data/docs/spot-heights.md +2 -0
- data/lib/nswtopo/archive.rb +6 -3
- data/lib/nswtopo/chrome.rb +16 -8
- data/lib/nswtopo/commands/layers.rb +2 -2
- data/lib/nswtopo/config.rb +1 -0
- data/lib/nswtopo/formats/gemf.rb +1 -0
- data/lib/nswtopo/formats/kmz.rb +16 -10
- data/lib/nswtopo/formats/mbtiles.rb +1 -0
- data/lib/nswtopo/formats/pdf.rb +34 -4
- data/lib/nswtopo/formats/svg.rb +4 -4
- data/lib/nswtopo/formats/svgz.rb +1 -0
- data/lib/nswtopo/formats/zip.rb +5 -4
- data/lib/nswtopo/formats.rb +35 -36
- data/lib/nswtopo/geometry/r_tree.rb +24 -23
- data/lib/nswtopo/geometry/straight_skeleton/node.rb +4 -4
- data/lib/nswtopo/geometry/straight_skeleton/nodes.rb +51 -40
- data/lib/nswtopo/geometry/straight_skeleton/split.rb +2 -2
- data/lib/nswtopo/geometry/vector.rb +55 -49
- data/lib/nswtopo/geometry.rb +0 -5
- data/lib/nswtopo/gis/arcgis/layer/map.rb +11 -10
- data/lib/nswtopo/gis/arcgis/layer/query.rb +8 -10
- data/lib/nswtopo/gis/arcgis/layer.rb +7 -11
- data/lib/nswtopo/gis/dem.rb +3 -2
- data/lib/nswtopo/gis/gdal_glob.rb +3 -3
- data/lib/nswtopo/gis/geojson/collection.rb +59 -13
- data/lib/nswtopo/gis/geojson/line_string.rb +142 -1
- data/lib/nswtopo/gis/geojson/multi_line_string.rb +49 -7
- data/lib/nswtopo/gis/geojson/multi_point.rb +87 -0
- data/lib/nswtopo/gis/geojson/multi_polygon.rb +35 -23
- data/lib/nswtopo/gis/geojson/point.rb +16 -1
- data/lib/nswtopo/gis/geojson/polygon.rb +69 -7
- data/lib/nswtopo/gis/geojson.rb +92 -46
- data/lib/nswtopo/gis/projection.rb +5 -1
- data/lib/nswtopo/helpers/thread_pool.rb +39 -0
- data/lib/nswtopo/helpers.rb +44 -5
- data/lib/nswtopo/layer/arcgis_raster.rb +3 -3
- data/lib/nswtopo/layer/contour.rb +24 -26
- data/lib/nswtopo/layer/control.rb +5 -3
- data/lib/nswtopo/layer/declination.rb +14 -10
- data/lib/nswtopo/layer/feature.rb +5 -5
- data/lib/nswtopo/layer/grid.rb +19 -18
- data/lib/nswtopo/layer/labels/barriers.rb +23 -0
- data/lib/nswtopo/layer/labels/convex_hull.rb +12 -0
- data/lib/nswtopo/layer/labels/convex_hulls.rb +86 -0
- data/lib/nswtopo/layer/labels/label.rb +63 -0
- data/lib/nswtopo/layer/labels.rb +192 -315
- data/lib/nswtopo/layer/overlay.rb +11 -12
- data/lib/nswtopo/layer/raster.rb +1 -0
- data/lib/nswtopo/layer/relief.rb +6 -4
- data/lib/nswtopo/layer/spot.rb +11 -17
- data/lib/nswtopo/layer/{vector → vector_render}/cutout.rb +1 -1
- data/lib/nswtopo/layer/{vector → vector_render}/knockout.rb +2 -3
- data/lib/nswtopo/layer/{vector.rb → vector_render.rb} +20 -45
- data/lib/nswtopo/layer.rb +2 -1
- data/lib/nswtopo/map.rb +62 -60
- data/lib/nswtopo/svg.rb +5 -0
- data/lib/nswtopo/tiled_web_map.rb +3 -3
- data/lib/nswtopo/tree_indenter.rb +2 -2
- data/lib/nswtopo/version.rb +1 -1
- data/lib/nswtopo.rb +8 -0
- metadata +15 -17
- data/lib/nswtopo/geometry/overlap.rb +0 -47
- data/lib/nswtopo/geometry/segment.rb +0 -27
- data/lib/nswtopo/geometry/vector_sequence.rb +0 -180
- data/lib/nswtopo/helpers/array.rb +0 -19
- data/lib/nswtopo/helpers/concurrently.rb +0 -27
- data/lib/nswtopo/helpers/dir.rb +0 -7
- data/lib/nswtopo/helpers/hash.rb +0 -15
- data/lib/nswtopo/helpers/tar_writer.rb +0 -11
- 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
|