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.



11
12
13
14
# File 'lib/charta/geometry.rb', line 11

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

Class Method Details

.factory(srid = 4326) ⇒ Object



265
266
267
268
# File 'lib/charta/geometry.rb', line 265

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

.feature(ewkt_or_rgeo) ⇒ Object



270
271
272
273
# File 'lib/charta/geometry.rb', line 270

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



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

def from_ewkt(ewkt)
  # Cleans empty geometries
  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



275
276
277
278
# File 'lib/charta/geometry.rb', line 275

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

.srs_databaseObject



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

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



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

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



99
100
101
102
103
104
# File 'lib/charta/geometry.rb', line 99

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



120
121
122
# File 'lib/charta/geometry.rb', line 120

def area
  surface? ? feature.area : 0
end

#bounding_boxObject



215
216
217
218
219
220
221
222
223
224
225
# File 'lib/charta/geometry.rb', line 215

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



194
195
196
# File 'lib/charta/geometry.rb', line 194

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.



133
134
135
136
137
# File 'lib/charta/geometry.rb', line 133

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)


30
31
32
# File 'lib/charta/geometry.rb', line 30

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

#convert_to(new_type) ⇒ Object



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

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

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



209
210
211
212
# File 'lib/charta/geometry.rb', line 209

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)


126
127
128
# File 'lib/charta/geometry.rb', line 126

def empty?
  feature.is_empty?
end

#ewktObject



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

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

#featureObject

TODO: Manage YAML domain type to ensure maintainability of YAML serialization in time.



239
240
241
242
243
244
245
246
247
248
249
# File 'lib/charta/geometry.rb', line 239

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

#feature=(new_feature) ⇒ Object

Raises:

  • (ArgumentError)


251
252
253
254
# File 'lib/charta/geometry.rb', line 251

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

#find_srid(name_or_srid) ⇒ Object



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

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

#flatten_multi(as_type) ⇒ Object



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

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



16
17
18
# File 'lib/charta/geometry.rb', line 16

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

#intersection(other) ⇒ Object



204
205
206
207
# File 'lib/charta/geometry.rb', line 204

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

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



198
199
200
201
# File 'lib/charta/geometry.rb', line 198

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.



140
141
142
143
144
# File 'lib/charta/geometry.rb', line 140

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)


342
343
344
345
# File 'lib/charta/geometry.rb', line 342

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



35
36
37
# File 'lib/charta/geometry.rb', line 35

def srid
  feature.srid.to_i
end

#surface?Boolean

Returns true if Geometry is a Surface

Returns:

  • (Boolean)


115
116
117
# File 'lib/charta/geometry.rb', line 115

def surface?
  [RGeo::Feature::Polygon, RGeo::Feature::MultiPolygon].include? feature.geometry_type
end

#to_binaryObject Also known as: to_ewkb

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



64
65
66
67
# File 'lib/charta/geometry.rb', line 64

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



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

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.



88
89
90
# File 'lib/charta/geometry.rb', line 88

def to_geojson
  to_json_object.to_json
end

#to_json_feature(properties = {}) ⇒ Object



256
257
258
# File 'lib/charta/geometry.rb', line 256

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

#to_json_objectObject

Returns object in JSON (Hash)



94
95
96
# File 'lib/charta/geometry.rb', line 94

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

#to_rgeoObject

Returns the underlaying object managed by Charta: the RGeo feature



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

def to_rgeo
  feature
end

#to_svg(options = {}) ⇒ Object

Pas bien compris le fonctionnement



71
72
73
74
75
76
77
78
79
80
# File 'lib/charta/geometry.rb', line 71

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.



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

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



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

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



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

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…



22
23
24
# File 'lib/charta/geometry.rb', line 22

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