Class: Charta::Geometry

Inherits:
Object
  • Object
show all
Defined in:
lib/charta/geometry.rb

Overview

Represents a Geometry with SRID

Direct Known Subclasses

GeometryCollection, LineString, Point, Polygon

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(feature, properties = {}) ⇒ Geometry

Returns a new instance of Geometry.



9
10
11
12
# File 'lib/charta/geometry.rb', line 9

def initialize(feature, properties = {})
  self.feature = feature
  @properties = properties
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object



291
292
293
294
295
296
297
298
# File 'lib/charta/geometry.rb', line 291

def method_missing(name, *args, &block)
  target = to_rgeo
  if target.respond_to? name
    target.send name, *args
  else
    raise StandardError.new("Method #{name} does not exist for #{self.class.name}")
  end
end

Class Method Details

.factory(srid = 4326) ⇒ Object



311
312
313
314
315
# File 'lib/charta/geometry.rb', line 311

def factory(srid = 4326)
  return projected_factory(srid) if srid.to_i == 4326

  geos_factory(srid)
end

.feature(ewkt_or_rgeo) ⇒ Object



317
318
319
320
321
# File 'lib/charta/geometry.rb', line 317

def feature(ewkt_or_rgeo)
  return from_rgeo(ewkt_or_rgeo) if ewkt_or_rgeo.is_a? RGeo::Feature::Instance

  from_ewkt(ewkt_or_rgeo)
end

.from_ewkt(ewkt) ⇒ Object



328
329
330
331
332
333
334
335
336
337
338
# File 'lib/charta/geometry.rb', line 328

def from_ewkt(ewkt)
  # Cleans empty geometries
  ewkt = ewkt.gsub(/(GEOMETRYCOLLECTION|GEOMETRY|((MULTI)?(POINT|LINESTRING|POLYGON)))\(\)/, '\1 EMPTY')
  srs = ewkt.split(/[\=\;]+/)[0..1]
  srid = nil
  srid = srs[1] if srs[0] =~ /srid/i
  srid ||= 4326
  factory(srid).parse_wkt(ewkt)
rescue RGeo::Error::ParseError => e
  raise "Invalid EWKT (#{e.class.name}: #{e.message}): #{ewkt}"
end

.from_rgeo(rgeo) ⇒ Object



323
324
325
326
# File 'lib/charta/geometry.rb', line 323

def from_rgeo(rgeo)
  srid = rgeo.srid
  RGeo::Feature.cast(rgeo, factory: Geometry.factory(srid))
end

.srs_databaseObject



307
308
309
# File 'lib/charta/geometry.rb', line 307

def srs_database
  @srs_database ||= RGeo::CoordSys::SRSDatabase::Proj4Data.new('epsg', authority: 'EPSG', cache: true)
end

Instance Method Details

#!=(other) ⇒ Object

Test if the other measure is equal to self



105
106
107
108
109
110
111
# File 'lib/charta/geometry.rb', line 105

def !=(other)
  other_geometry = Charta.new_geometry(other).transform(srid)
  return true if empty? && other_geometry.empty?
  return inspect == other_geometry.inspect if collection? && other_geometry.collection?

  !feature.equals?(other_geometry.feature)
end

#==(other) ⇒ Object

Test if the other measure is equal to self



96
97
98
99
100
101
102
# File 'lib/charta/geometry.rb', line 96

def ==(other)
  other_geometry = Charta.new_geometry(other).transform(srid)
  return true if empty? && other_geometry.empty?
  return inspect == other_geometry.inspect if collection? && other_geometry.collection?

  feature.equals?(other_geometry.feature)
end

#areaObject

Returns area in unit corresponding to the SRS



123
124
125
126
127
128
129
130
131
132
133
# File 'lib/charta/geometry.rb', line 123

def area
  if surface?
    if collection?
      feature.sum { |geometry| Charta.new_geometry(geometry).area }
    else
      feature.area
    end
  else
    0
  end
end

#bounding_boxObject



244
245
246
247
248
249
250
251
252
253
254
# File 'lib/charta/geometry.rb', line 244

def bounding_box
  unless defined? @bounding_box
    bbox = RGeo::Cartesian::BoundingBox.create_from_geometry(feature)
    instance_variable_set('@x_min', bbox.min_x || 0)
    instance_variable_set('@y_min', bbox.min_y || 0)
    instance_variable_set('@x_max', bbox.max_x || 0)
    instance_variable_set('@y_max', bbox.max_y || 0)
    @bounding_box = BoundingBox.new(@y_min, @x_min, @y_max, @x_max)
  end
  @bounding_box
end

#buffer(radius) ⇒ Object

Produces buffer



216
217
218
# File 'lib/charta/geometry.rb', line 216

def buffer(radius)
  feature.buffer(radius)
end

#centroidObject

Computes the geometric center of a geometry, or equivalently, the center of mass of the geometry as a POINT.



145
146
147
148
149
150
# File 'lib/charta/geometry.rb', line 145

def centroid
  return nil unless surface? && !feature.is_empty?

  point = feature.centroid
  [point.y, point.x]
end

#collection?Boolean

Returns the type of the geometry as a string. EG: ‘ST_Linestring’, ‘ST_Polygon’, ‘ST_MultiPolygon’ etc. This function differs from GeometryType(geometry) in the case of the string and ST in front that is returned, as well as the fact that it will not indicate whether the geometry is measured.

Returns:

  • (Boolean)


28
29
30
# File 'lib/charta/geometry.rb', line 28

def collection?
  feature.geometry_type == RGeo::Feature::GeometryCollection
end

#convert_to(new_type) ⇒ Object



160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/charta/geometry.rb', line 160

def convert_to(new_type)
  case new_type
  when type
    self
  when :multi_point
    flatten_multi(:point)
  when :multi_line_string
    flatten_multi(:line_string)
  when :multi_polygon
    flatten_multi(:polygon)
  else
    self
  end
end

#difference(other) ⇒ Object Also known as: -



237
238
239
240
# File 'lib/charta/geometry.rb', line 237

def difference(other)
  other_geometry = Charta.new_geometry(other).transform(srid)
  feature.difference(other_geometry.feature)
end

#empty?Boolean Also known as: blank?

Returns true if this Geometry is an empty geometrycollection, polygon, point etc.

Returns:

  • (Boolean)


137
138
139
# File 'lib/charta/geometry.rb', line 137

def empty?
  feature.is_empty?
end

#ewktObject



53
54
55
56
# File 'lib/charta/geometry.rb', line 53

def ewkt
  puts 'DEPRECATION WARNING: Charta::Geometry.ewkt is deprecated. Please use Charta::Geometry.to_ewkt instead'
  to_ewkt
end

#featureObject

Returns the underlaying object managed by Charta: the RGeo feature



267
268
269
270
271
272
273
274
275
276
277
# File 'lib/charta/geometry.rb', line 267

def feature
  unless defined? @feature
    if defined? @ewkt
      @feature = ::Charta::Geometry.from_ewkt(@ewkt)
      @properties = @options.dup if @options
    else
      raise StandardError.new('Invalid geometry (no feature, no EWKT)')
    end
  end
  @feature.dup
end

#feature=(new_feature) ⇒ Object

Raises:

  • (ArgumentError)


281
282
283
284
285
# File 'lib/charta/geometry.rb', line 281

def feature=(new_feature)
  raise ArgumentError.new("Feature can't be nil") if new_feature.nil?

  @feature = new_feature
end

#find_srid(name_or_srid) ⇒ Object



262
263
264
# File 'lib/charta/geometry.rb', line 262

def find_srid(name_or_srid)
  Charta.find_srid(name_or_srid)
end

#flatten_multi(as_type) ⇒ Object



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/charta/geometry.rb', line 175

def flatten_multi(as_type)
  items = []
  as_multi_type = "multi_#{as_type}".to_sym
  if type == as_type
    items << feature
  elsif type == :geometry_collection
    feature.each do |geom|
      type_name = Charta.underscore(geom.geometry_type.type_name).to_sym
      if type_name == as_type
        items << geom
      elsif type_name == as_multi_type
        geom.each do |item|
          items << item
        end
      end
    end
  end
  Charta.new_geometry(feature.factory.send(as_multi_type, items))
end

#inspectObject



14
15
16
# File 'lib/charta/geometry.rb', line 14

def inspect
  "<#{self.class.name}(#{to_ewkt})>"
end

#intersection(other) ⇒ Object



227
228
229
230
# File 'lib/charta/geometry.rb', line 227

def intersection(other)
  other_geometry = Charta.new_geometry(other).transform(srid)
  feature.intersection(other_geometry.feature)
end

#intersects?(other) ⇒ Boolean

Returns:

  • (Boolean)


232
233
234
235
# File 'lib/charta/geometry.rb', line 232

def intersects?(other)
  other_geometry = Charta.new_geometry(other).transform(srid)
  feature.intersects?(other_geometry.feature)
end

#merge(other) ⇒ Object Also known as: +



220
221
222
223
# File 'lib/charta/geometry.rb', line 220

def merge(other)
  other_geometry = Charta.new_geometry(other).transform(srid)
  feature.union(other_geometry.feature)
end

#point_on_surfaceObject

Returns a POINT guaranteed to lie on the surface.



153
154
155
156
157
158
# File 'lib/charta/geometry.rb', line 153

def point_on_surface
  return nil unless surface?

  point = feature.point_on_surface
  [point.y, point.x]
end

#respond_to_missing?(name, include_private = false) ⇒ Boolean

Returns:

  • (Boolean)


300
301
302
303
304
# File 'lib/charta/geometry.rb', line 300

def respond_to_missing?(name, include_private = false)
  return false if name == :init_with

  super
end

#sridObject

Return the spatial reference identifier for the ST_Geometry



33
34
35
# File 'lib/charta/geometry.rb', line 33

def srid
  feature.srid.to_i
end

#surface?Boolean

Returns true if Geometry is a Surface

Returns:

  • (Boolean)


114
115
116
117
118
119
120
# File 'lib/charta/geometry.rb', line 114

def surface?
  if collection?
    feature.any? { |geometry| Charta.new_geometry(geometry).surface? }
  else
    [RGeo::Feature::Polygon, RGeo::Feature::MultiPolygon].include? feature.geometry_type
  end
end

#to_binaryObject Also known as: to_ewkb

Return the Well-Known Binary (WKB) representation of the geometry with SRID meta data.



59
60
61
62
# File 'lib/charta/geometry.rb', line 59

def to_binary
  generator = RGeo::WKRep::WKBGenerator.new(tag_format: :ewkbt, emit_ewkbt_srid: true)
  generator.generate(feature)
end

#to_ewktObject Also known as: to_s

Returns EWKT: WKT with its SRID



47
48
49
# File 'lib/charta/geometry.rb', line 47

def to_ewkt
  Charta.generate_ewkt(feature).to_s
end

#to_geojsonObject Also known as: to_json

Return the geometry as a Geometry Javascript Object Notation (GeoJSON) element.



84
85
86
# File 'lib/charta/geometry.rb', line 84

def to_geojson
  to_json_object.to_json
end

#to_json_feature(properties = {}) ⇒ Object



287
288
289
# File 'lib/charta/geometry.rb', line 287

def to_json_feature(properties = {})
  { type: 'Feature', properties: properties, geometry: to_json_object }
end

#to_json_objectObject

Returns object in JSON (Hash)



91
92
93
# File 'lib/charta/geometry.rb', line 91

def to_json_object
  RGeo::GeoJSON.encode(feature)
end

#to_rgeoObject

Returns the underlaying object managed by Charta: the RGeo feature



279
280
281
282
283
284
285
286
287
288
289
# File 'lib/charta/geometry.rb', line 279

def feature
  unless defined? @feature
    if defined? @ewkt
      @feature = ::Charta::Geometry.from_ewkt(@ewkt)
      @properties = @options.dup if @options
    else
      raise StandardError.new('Invalid geometry (no feature, no EWKT)')
    end
  end
  @feature.dup
end

#to_svg(options = {}) ⇒ Object

Pas bien compris le fonctionnement



67
68
69
70
71
72
73
74
75
76
# File 'lib/charta/geometry.rb', line 67

def to_svg(options = {})
  svg = '<svg xmlns="http://www.w3.org/2000/svg" version="1.1"'
  { preserve_aspect_ratio: 'xMidYMid meet',
    width: 180, height: 180,
    view_box: bounding_box.svg_view_box.join(' ') }.merge(options).each do |attr, value|
    svg << " #{Charta.camelcase(attr.to_s, :lower)}=\"#{value}\""
  end
  svg << "><path d=\"#{to_svg_path}\"/></svg>"
  svg
end

#to_svg_pathObject

Return the geometry as Scalar Vector Graphics (SVG) path data.



79
80
81
# File 'lib/charta/geometry.rb', line 79

def to_svg_path
  RGeo::SVG.encode(feature)
end

#to_textObject Also known as: as_text, to_wkt

Returns the Well-Known Text (WKT) representation of the geometry/geography without SRID metadata



39
40
41
# File 'lib/charta/geometry.rb', line 39

def to_text
  feature.as_text.match(/\ASRID=.*;(.*)/)[1]
end

#transform(new_srid) ⇒ Object

Returns a new geometry with the coordinates converted into the new SRS



196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/charta/geometry.rb', line 196

def transform(new_srid)
  return self if new_srid == srid
  raise 'Proj is not supported. Cannot tranform' unless RGeo::CoordSys::Proj4.supported?

  new_srid = Charta::SRS[new_srid] || new_srid
  database = self.class.srs_database
  new_proj_entry = database.get(new_srid)
  raise "Cannot find proj for SRID: #{new_srid}" if new_proj_entry.nil?

  new_feature = RGeo::CoordSys::Proj4.transform(
    database.get(srid).proj4,
    feature,
    new_proj_entry.proj4,
    self.class.factory(new_srid)
  )
  generator = RGeo::WKRep::WKTGenerator.new(tag_format: :ewkt, emit_ewkt_srid: true)
  Charta.new_geometry(generator.generate(new_feature))
end

#typeObject

Returns the type of the geometry as a string. Example: point, multi_polygon, geometry_collection…



20
21
22
# File 'lib/charta/geometry.rb', line 20

def type
  Charta.underscore(feature.geometry_type.type_name).to_sym
end