Class: Geos::STRtree

Inherits:
Object
  • Object
show all
Includes:
Enumerable, Tools
Defined in:
lib/ffi-geos/strtree.rb

Defined Under Namespace

Classes: AlreadyBuiltError

Constant Summary

Constants included from GeomTypes

GeomTypes::GEOS_GEOMETRYCOLLECTION, GeomTypes::GEOS_LINEARRING, GeomTypes::GEOS_LINESTRING, GeomTypes::GEOS_MULTILINESTRING, GeomTypes::GEOS_MULTIPOINT, GeomTypes::GEOS_MULTIPOLYGON, GeomTypes::GEOS_POINT, GeomTypes::GEOS_POLYGON

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Tools

#bool_result, #bool_to_int, #cast_geometry_ptr, #check_enum_value, #check_geometry, #extract_options!, #pick_srid_according_to_policy, #pick_srid_from_geoms, #symbol_for_enum

Constructor Details

#initialize(*args) ⇒ STRtree

:call-seq:

new(capacity)
new(geoms_and_objects)

Raises:

  • (ArgumentError)


22
23
24
25
26
27
28
29
30
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
# File 'lib/ffi-geos/strtree.rb', line 22

def initialize(*args)
  geoms_and_objects = nil # forward declaration
  capacity = 10

  case args.first
    when Integer
      capacity = args.first
    when Array
      geoms_and_objects = if args.first.first.is_a?(Array)
        args.first
      else
        args
      end

      geoms_and_objects.each do |geom, _obj|
        check_geometry(geom)
      end
  end

  raise ArgumentError, 'STRtree capacity must be greater than 0' if capacity <= 0

  ptr = FFIGeos.GEOSSTRtree_create_r(Geos.current_handle_pointer, capacity)

  @ptr = FFI::AutoPointer.new(
    ptr,
    self.class.method(:release)
  )

  @storage = {}
  @ptrs = {}

  @storage_key = 0
  @built = false

  return unless geoms_and_objects

  geoms_and_objects.each do |geom, obj|
    insert(geom, obj)
  end
end

Instance Attribute Details

#ptrObject (readonly)

Returns the value of attribute ptr.



8
9
10
# File 'lib/ffi-geos/strtree.rb', line 8

def ptr
  @ptr
end

Class Method Details

.release(ptr) ⇒ Object

:nodoc:



63
64
65
# File 'lib/ffi-geos/strtree.rb', line 63

def self.release(ptr) # :nodoc:
  FFIGeos.GEOSSTRtree_destroy_r(Geos.current_handle_pointer, ptr)
end

Instance Method Details

#built!Object



71
72
73
# File 'lib/ffi-geos/strtree.rb', line 71

def built!
  @built = true
end

#built?Boolean

Returns:

  • (Boolean)


67
68
69
# File 'lib/ffi-geos/strtree.rb', line 67

def built?
  @built
end

#insert(geom, item = nil) ⇒ Object

Raises:



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/ffi-geos/strtree.rb', line 80

def insert(geom, item = nil)
  raise AlreadyBuiltError if built?

  check_geometry(geom)

  key = next_key
  key_ptr = FFI::MemoryPointer.new(:pointer)
  key_ptr.write_int(key)

  @storage[key] = {
    item: item,
    geometry: geom
  }
  @ptrs[key] = key_ptr

  FFIGeos.GEOSSTRtree_insert_r(Geos.current_handle_pointer, ptr, geom.ptr, key_ptr)
end

#iterate(&block) ⇒ Object



169
170
171
# File 'lib/ffi-geos/strtree.rb', line 169

def iterate(&block)
  @storage.each_value(&block)
end

#nearest(geom) ⇒ Object Also known as: nearest_geometry



205
206
207
208
# File 'lib/ffi-geos/strtree.rb', line 205

def nearest(geom)
  item = nearest_generic(geom)
  item[:geometry] if item
end

#nearest_generic(geom) ⇒ Object



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/ffi-geos/strtree.rb', line 174

def nearest_generic(geom)
  check_geometry(geom)

  built!

  return nil if @storage.empty?

  callback = proc { |item, _item_2, distance_ptr|
    key = item.read_int
    geom_from_storage = @storage[key][:geometry]

    next 0 if geom_from_storage.empty?

    distance = geom.distance(geom_from_storage)
    distance_ptr.write_double(distance)

    next 1
  }

  key_ptr = FFIGeos.GEOSSTRtree_nearest_generic_r(
    Geos.current_handle_pointer,
    ptr,
    geom.ptr,
    geom.envelope.ptr,
    callback,
    nil
  )

  @storage[key_ptr.read_int] unless key_ptr.null?
end

#nearest_item(geom) ⇒ Object



211
212
213
214
# File 'lib/ffi-geos/strtree.rb', line 211

def nearest_item(geom)
  item = nearest_generic(geom)
  item[:item] if item
end

#query(geom, ret = :item) ⇒ Object



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/ffi-geos/strtree.rb', line 139

def query(geom, ret = :item)
  query_all(geom).collect { |storage|
    item = case ret
      when Array
        storage.inject({}) do |memo, k|
          memo.tap do
            memo[k] = storage[k]
          end
        end
      when :all
        storage
      else
        storage[ret]
    end

    item.tap do
      yield(item) if block_given?
    end
  }.compact
end

#query_all(geom) ⇒ Object



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/ffi-geos/strtree.rb', line 114

def query_all(geom)
  check_geometry(geom)

  built!
  retval = []

  callback = proc { |*args|
    key = args.first.read_int
    storage = @storage[key]
    retval << storage

    yield(storage) if block_given?
  }

  FFIGeos.GEOSSTRtree_query_r(
    Geos.current_handle_pointer,
    ptr,
    geom.ptr,
    callback,
    nil
  )

  retval
end

#query_geometries(geom) ⇒ Object Also known as: query_geoms



160
161
162
163
164
165
166
# File 'lib/ffi-geos/strtree.rb', line 160

def query_geometries(geom)
  query_all(geom).collect { |storage|
    storage[:geometry].tap do |val|
      yield(val) if block_given?
    end
  }.compact
end

#remove(geom, item) ⇒ Object



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/ffi-geos/strtree.rb', line 98

def remove(geom, item)
  check_geometry(geom)

  key = if (storage = @storage.detect { |_k, v| v[:item] == item })
    storage[0]
  end

  return unless key

  key_ptr = @ptrs[key]
  result = FFIGeos.GEOSSTRtree_remove_r(Geos.current_handle_pointer, ptr, geom.ptr, key_ptr)
  built!

  @storage.delete(key) if result == 1
end