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)


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
62
# File 'lib/ffi-geos/strtree.rb', line 22

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

  if args.first.is_a?(Integer)
    capacity = args.first
  elsif args.first.is_a?(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

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

  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:



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

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

Instance Method Details

#built!Object



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

def built!
  @built = true
end

#built?Boolean

Returns:

  • (Boolean)


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

def built?
  @built
end

#insert(geom, item = nil) ⇒ Object

Raises:



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

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

#iterateObject



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

def iterate
  @storage.each_value do |v|
    yield(v)
  end
end

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



207
208
209
210
# File 'lib/ffi-geos/strtree.rb', line 207

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

#nearest_generic(geom) ⇒ Object



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
204
205
# File 'lib/ffi-geos/strtree.rb', line 176

def nearest_generic(geom)
  check_geometry(geom)

  built!

  return nil if @storage.empty?

  callback = proc { |item, _item2, 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



213
214
215
216
# File 'lib/ffi-geos/strtree.rb', line 213

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

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



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 140

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

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

#query_all(geom) ⇒ Object



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

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



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

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