Class: NSWTopo::GeoJSON::MultiPolygon

Inherits:
Object
  • Object
show all
Includes:
StraightSkeleton
Defined in:
lib/nswtopo/gis/geojson/multi_polygon.rb

Constant Summary

Constants included from StraightSkeleton

StraightSkeleton::DEFAULT_ROUNDING_ANGLE

Instance Method Summary collapse

Instance Method Details

#areaObject



15
16
17
# File 'lib/nswtopo/gis/geojson/multi_polygon.rb', line 15

def area
  rings.sum(&:signed_area)
end

#buffer(*margins, **options) ⇒ Object



102
103
104
# File 'lib/nswtopo/gis/geojson/multi_polygon.rb', line 102

def buffer(*margins, **options)
  rings.offset(*margins.map(&:-@), **options).to_multipolygon
end

#centrelines(**options) ⇒ Object



98
99
100
# File 'lib/nswtopo/gis/geojson/multi_polygon.rb', line 98

def centrelines(**options)
  centres(**options, interval: nil, lines: true)
end

#centrepoints(interval:, **options) ⇒ Object



94
95
96
# File 'lib/nswtopo/gis/geojson/multi_polygon.rb', line 94

def centrepoints(interval:, **options)
  centres(**options, interval: interval, lines: false)
end

#centres(fraction: 0.5, min_width: nil, interval:, lines: true) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/nswtopo/gis/geojson/multi_polygon.rb', line 31

def centres(fraction: 0.5, min_width: nil, interval:, lines: true)
  neighbours = Hash.new { |neighbours, node| neighbours[node] = [] }
  samples, tails, node1 = {}, {}, nil

  nodes.progress(interval: interval) do |event, *args|
    case event
    when :nodes
      node0, node1 = *args
      neighbours[node0] << node1
      neighbours[node1] << node0
    when :interval
      travel, rings = *args
      samples[travel] = rings.flat_map do |ring|
        LineString.new(ring).sample_at(interval)
      end
    end
  end

  samples[node1.travel] = [node1.point.to_f]
  max_travel = neighbours.keys.map(&:travel).max
  min_travel = [fraction * max_travel, min_width && 0.5 * min_width].compact.max

  features = samples.select do |travel, points|
    travel > min_travel
  end.map do |travel, points|
    MultiPoint.new points, @properties
  end.reverse
  return features unless lines

  loop do
    break unless neighbours.reject do |node, (neighbour, *others)|
      others.any? || neighbours[neighbour].one?
    end.each do |node, (neighbour, *)|
      next if neighbours[neighbour].one?
      neighbours.delete node
      neighbours[neighbour].delete node
      nodes, length = tails.delete(node) || [[node], 0]
      candidate = [nodes << neighbour, length + (node.point - neighbour.point).norm]
      tails[neighbour] = [tails[neighbour], candidate].compact.max_by(&:last)
    end.any?
  end

  lengths, lines, candidates = Hash.new(0), Hash.new, tails.values
  while candidates.any?
    (*nodes, node), length = candidates.pop
    next if (neighbours[node] - nodes).each do |neighbour|
      candidates << [[*nodes, node, neighbour], length + (node.point - neighbour.point).norm]
    end.any?
    index = nodes.find(&:index).index
    tail_nodes, tail_length = tails[node] || [[node], 0]
    lengths[index], lines[index] = length + tail_length, nodes + tail_nodes.reverse if length + tail_length > lengths[index]
  end

  linestrings = lines.values.flat_map do |nodes|
    nodes.chunk do |node|
      node.travel >= min_travel
    end.select(&:first).map(&:last).reject(&:one?).map do |nodes|
      nodes.map(&:point).map(&:to_f)
    end
  end
  features.prepend MultiLineString.new(linestrings, @properties)
end

#centroidsObject



106
107
108
# File 'lib/nswtopo/gis/geojson/multi_polygon.rb', line 106

def centroids
  map(&:centroid).inject(empty_points, &:+)
end

#dissolve_pointsObject



117
118
119
# File 'lib/nswtopo/gis/geojson/multi_polygon.rb', line 117

def dissolve_points
  MultiPoint.new @coordinates.flatten(2), @properties
end

#freeze!Object



6
7
8
9
# File 'lib/nswtopo/gis/geojson/multi_polygon.rb', line 6

def freeze!
  each { }
  freeze
end

#nodesObject



19
20
21
# File 'lib/nswtopo/gis/geojson/multi_polygon.rb', line 19

def nodes
  Nodes.new rings
end

#remove_holes(&block) ⇒ Object



121
122
123
124
125
# File 'lib/nswtopo/gis/geojson/multi_polygon.rb', line 121

def remove_holes(&block)
  map do |polygon|
    polygon.remove_holes(&block)
  end.inject(empty_polygons, &:+)
end

#ringsObject



11
12
13
# File 'lib/nswtopo/gis/geojson/multi_polygon.rb', line 11

def rings
  MultiLineString.new @coordinates.flatten(1), @properties
end

#samples(interval) ⇒ Object



110
111
112
113
114
115
# File 'lib/nswtopo/gis/geojson/multi_polygon.rb', line 110

def samples(interval)
  points = rings.flat_map do |coordinates|
    linestring.sample_at(interval)
  end
  MultiPoint.new points, @properties
end

#skeletonObject



23
24
25
26
27
28
29
# File 'lib/nswtopo/gis/geojson/multi_polygon.rb', line 23

def skeleton
  segments = []
  nodes.progress do |event, node0, node1|
    segments << [node0.point.to_f, node1.point.to_f]
  end
  MultiLineString.new segments, @properties
end