opencv-ffi 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. data/.gitignore +7 -0
  2. data/Gemfile +15 -0
  3. data/README.md +126 -0
  4. data/Rakefile +52 -0
  5. data/docs/DocsIndex.md +1 -0
  6. data/docs/examples/load_image.rb +25 -0
  7. data/ext/Rakefile +13 -0
  8. data/ext/aishack-sift/.gitignore +4 -0
  9. data/ext/aishack-sift/Descriptor.h +34 -0
  10. data/ext/aishack-sift/KeyPoint.h +38 -0
  11. data/ext/aishack-sift/README +20 -0
  12. data/ext/aishack-sift/SIFT.cpp +1036 -0
  13. data/ext/aishack-sift/SIFT.h +84 -0
  14. data/ext/aishack-sift/example/.gitignore +2 -0
  15. data/ext/aishack-sift/example/Makefile +24 -0
  16. data/ext/aishack-sift/example/MySIFT.cpp +29 -0
  17. data/ext/aishack-sift/mkrf_conf.rb +13 -0
  18. data/ext/aishack-sift/siftlib.cpp +85 -0
  19. data/ext/eigen/.gitignore +4 -0
  20. data/ext/eigen/eigen_polynomial.cpp +41 -0
  21. data/ext/eigen/eigen_svd.cpp +100 -0
  22. data/ext/eigen/mkrf_conf.rb +14 -0
  23. data/ext/mkrf-monkey.rb +85 -0
  24. data/ext/mkrf-rakehelper-monkey.rb +52 -0
  25. data/ext/mkrf_conf.rb +3 -0
  26. data/ext/opencv-ffi/.gitignore +4 -0
  27. data/ext/opencv-ffi/matcher_helper.cpp +56 -0
  28. data/ext/opencv-ffi/mkrf_conf.rb +12 -0
  29. data/ext/opencv-ffi/vector_math.cpp +39 -0
  30. data/ext/opensurf/.gitignore +4 -0
  31. data/ext/opensurf/README +38 -0
  32. data/ext/opensurf/fasthessian.cpp +376 -0
  33. data/ext/opensurf/fasthessian.h +108 -0
  34. data/ext/opensurf/integral.cpp +58 -0
  35. data/ext/opensurf/integral.h +55 -0
  36. data/ext/opensurf/ipoint.cpp +108 -0
  37. data/ext/opensurf/ipoint.h +76 -0
  38. data/ext/opensurf/kmeans.h +172 -0
  39. data/ext/opensurf/mkrf_conf.rb +10 -0
  40. data/ext/opensurf/responselayer.h +92 -0
  41. data/ext/opensurf/surf.cpp +317 -0
  42. data/ext/opensurf/surf.h +66 -0
  43. data/ext/opensurf/surflib.cpp +98 -0
  44. data/ext/opensurf/surflib.h +96 -0
  45. data/ext/opensurf/utils.cpp +357 -0
  46. data/ext/opensurf/utils.h +63 -0
  47. data/lib/.gitignore +1 -0
  48. data/lib/opencv-ffi-ext/eigen.rb +84 -0
  49. data/lib/opencv-ffi-ext/features2d.rb +4 -0
  50. data/lib/opencv-ffi-ext/matcher_helper.rb +24 -0
  51. data/lib/opencv-ffi-ext/opensurf.rb +217 -0
  52. data/lib/opencv-ffi-ext/sift.rb +118 -0
  53. data/lib/opencv-ffi-ext/vector_math.rb +115 -0
  54. data/lib/opencv-ffi-wrappers.rb +7 -0
  55. data/lib/opencv-ffi-wrappers/core.rb +24 -0
  56. data/lib/opencv-ffi-wrappers/core/iplimage.rb +50 -0
  57. data/lib/opencv-ffi-wrappers/core/mat.rb +268 -0
  58. data/lib/opencv-ffi-wrappers/core/misc_draw.rb +44 -0
  59. data/lib/opencv-ffi-wrappers/core/point.rb +286 -0
  60. data/lib/opencv-ffi-wrappers/core/rect.rb +40 -0
  61. data/lib/opencv-ffi-wrappers/core/scalar.rb +104 -0
  62. data/lib/opencv-ffi-wrappers/core/size.rb +88 -0
  63. data/lib/opencv-ffi-wrappers/enumerable.rb +10 -0
  64. data/lib/opencv-ffi-wrappers/features2d.rb +17 -0
  65. data/lib/opencv-ffi-wrappers/features2d/image_patch.rb +322 -0
  66. data/lib/opencv-ffi-wrappers/features2d/star.rb +111 -0
  67. data/lib/opencv-ffi-wrappers/features2d/surf.rb +115 -0
  68. data/lib/opencv-ffi-wrappers/highgui.rb +10 -0
  69. data/lib/opencv-ffi-wrappers/imgproc.rb +4 -0
  70. data/lib/opencv-ffi-wrappers/imgproc/features.rb +35 -0
  71. data/lib/opencv-ffi-wrappers/imgproc/geometric.rb +39 -0
  72. data/lib/opencv-ffi-wrappers/matcher.rb +297 -0
  73. data/lib/opencv-ffi-wrappers/matrix.rb +37 -0
  74. data/lib/opencv-ffi-wrappers/misc.rb +41 -0
  75. data/lib/opencv-ffi-wrappers/misc/params.rb +34 -0
  76. data/lib/opencv-ffi-wrappers/sequence.rb +37 -0
  77. data/lib/opencv-ffi-wrappers/vectors.rb +38 -0
  78. data/lib/opencv-ffi.rb +12 -0
  79. data/lib/opencv-ffi/calib3d.rb +26 -0
  80. data/lib/opencv-ffi/core.rb +15 -0
  81. data/lib/opencv-ffi/core/draw.rb +68 -0
  82. data/lib/opencv-ffi/core/dynamic.rb +13 -0
  83. data/lib/opencv-ffi/core/library.rb +5 -0
  84. data/lib/opencv-ffi/core/operations.rb +122 -0
  85. data/lib/opencv-ffi/core/point.rb +22 -0
  86. data/lib/opencv-ffi/core/types.rb +172 -0
  87. data/lib/opencv-ffi/cvffi.rb +8 -0
  88. data/lib/opencv-ffi/features2d.rb +7 -0
  89. data/lib/opencv-ffi/features2d/library.rb +6 -0
  90. data/lib/opencv-ffi/features2d/star.rb +30 -0
  91. data/lib/opencv-ffi/features2d/surf.rb +38 -0
  92. data/lib/opencv-ffi/highgui.rb +31 -0
  93. data/lib/opencv-ffi/imgproc.rb +9 -0
  94. data/lib/opencv-ffi/imgproc/features.rb +37 -0
  95. data/lib/opencv-ffi/imgproc/geometric.rb +42 -0
  96. data/lib/opencv-ffi/imgproc/library.rb +6 -0
  97. data/lib/opencv-ffi/imgproc/misc.rb +39 -0
  98. data/lib/opencv-ffi/version.rb +3 -0
  99. data/opencv-ffi.gemspec +26 -0
  100. data/test/core/test_draw.rb +46 -0
  101. data/test/core/test_operations.rb +135 -0
  102. data/test/core/test_size.rb +14 -0
  103. data/test/core/test_text.rb +52 -0
  104. data/test/ext/test_eigen.rb +105 -0
  105. data/test/ext/test_opensurf.rb +35 -0
  106. data/test/ext/test_sift.rb +26 -0
  107. data/test/ext/test_vector_math.rb +85 -0
  108. data/test/features2d/test_surf.rb +63 -0
  109. data/test/imgproc/test_goodfeatures.rb +18 -0
  110. data/test/setup.rb +65 -0
  111. data/test/test_calib3d.rb +38 -0
  112. data/test/test_core.rb +26 -0
  113. data/test/test_ext.rb +8 -0
  114. data/test/test_features2d.rb +9 -0
  115. data/test/test_files/images/IMG_7088.JPG +0 -0
  116. data/test/test_files/images/IMG_7088_small.JPG +0 -0
  117. data/test/test_files/images/IMG_7089.JPG +0 -0
  118. data/test/test_highgui.rb +26 -0
  119. data/test/test_imgproc.rb +35 -0
  120. data/test/test_wrappers.rb +8 -0
  121. data/test/wrappers/core/test_draw.rb +41 -0
  122. data/test/wrappers/core/test_mat.rb +40 -0
  123. data/test/wrappers/core/test_operations.rb +35 -0
  124. data/test/wrappers/core/test_types.rb +235 -0
  125. data/test/wrappers/features2d/test_image_patch.rb +108 -0
  126. data/test/wrappers/test_imgproc.rb +87 -0
  127. data/test/wrappers/test_matcher.rb +96 -0
  128. data/test/wrappers/test_star.rb +28 -0
  129. data/test/wrappers/test_surf.rb +36 -0
  130. metadata +234 -0
@@ -0,0 +1,115 @@
1
+
2
+ require 'opencv-ffi/features2d'
3
+ require 'opencv-ffi-wrappers/core/iplimage'
4
+ require 'opencv-ffi-wrappers/core/misc_draw'
5
+ require 'opencv-ffi-wrappers/sequence'
6
+ require 'opencv-ffi-wrappers/enumerable'
7
+ require 'opencv-ffi-wrappers/vectors'
8
+ require 'opencv-ffi-ext/vector_math'
9
+
10
+ module CVFFI
11
+
12
+
13
+ module SURF
14
+
15
+ class Result
16
+ attr_accessor :kp, :desc
17
+ def initialize( kp, desc )
18
+ @kp = CVFFI::CvSURFPoint.new(kp)
19
+ @desc = desc
20
+ end
21
+
22
+ def pt; @kp.pt; end
23
+ def x; pt.x; end
24
+ def y; pt.y; end
25
+
26
+ def distance_to( q )
27
+ # Here's the pure-Ruby way to do it
28
+ # @desc.inject_with_index(0.0) { |x,d,i| x + (d-q.desc.d[i])**2 }
29
+
30
+ CVFFI::VectorMath::L2distance( @desc, q.desc )
31
+ end
32
+
33
+ def to_vector
34
+ Vector.[]( x, y, 1 )
35
+ end
36
+
37
+ def to_Point
38
+ pt.to_Point
39
+ end
40
+ end
41
+
42
+ class ResultsArray
43
+ include Enumerable
44
+
45
+ attr_accessor :kp, :desc, :pool
46
+ attr_accessor :desc_type
47
+
48
+ def initialize( kp, desc, pool, desc_type = Float64 )
49
+ @kp = Sequence.new(kp)
50
+ @desc = Sequence.new(desc)
51
+ @pool = pool
52
+ @desc_type = desc_type
53
+ @results = Array.new( @kp.length )
54
+
55
+ raise RuntimeError "SURF Keypoint and descriptor sequences different length (#{@kp.size} != #{@desc.size})" unless (@kp.size == @desc.size)
56
+
57
+ destructor = Proc.new { poolPtr = FFI::MemoryPointer.new :pointer; poolPtr.putPointer( 0, @pool ); cvReleaseMemStorage( poolPtr ) }
58
+ ObjectSpace.define_finalizer( self, destructor )
59
+ end
60
+
61
+ def result(i)
62
+ @results[i] ||= Result.new( @kp[i], @desc_type.new( @desc[i] ) )
63
+ end
64
+
65
+ def each
66
+ @results.each_index { |i|
67
+ yield result(i)
68
+ }
69
+ end
70
+
71
+ def [](i)
72
+ result(i)
73
+ end
74
+
75
+ def size
76
+ @kp.size
77
+ end
78
+ alias :length :size
79
+
80
+ def mark_on_image( img, opts )
81
+ each { |r|
82
+ CVFFI::draw_circle( img, r.kp.pt, opts )
83
+ }
84
+ end
85
+ end
86
+
87
+ def self.detect( img, params )
88
+
89
+ raise ArgumentError unless params.is_a?( CvSURFParams ) || params.is_a?( Params )
90
+
91
+ img = CVFFI::IplImage.new img.to_IplImage
92
+
93
+ if img.nChannels == 3
94
+ greyImg = CVFFI::cvCreateImage( CVFFI::CvSize.new( :height => img.height,
95
+ :width => img.width ),
96
+ :IPL_DEPTH_8U, 1 )
97
+ CVFFI::cvCvtColor( img, greyImg, :CV_RGB2GRAY )
98
+ else
99
+ greyImg = img
100
+ end
101
+
102
+ kp_ptr = FFI::MemoryPointer.new :pointer
103
+ desc_ptr = FFI::MemoryPointer.new :pointer
104
+
105
+ mem_storage = CVFFI::cvCreateMemStorage( 0 )
106
+
107
+ CVFFI::cvExtractSURF( greyImg, nil, kp_ptr, desc_ptr, mem_storage, params, :false )
108
+
109
+ keypoints = CVFFI::CvSeq.new( kp_ptr.read_pointer() )
110
+ descriptors = CVFFI::CvSeq.new( desc_ptr.read_pointer() )
111
+
112
+ ResultsArray.new( keypoints, descriptors, mem_storage )
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,10 @@
1
+
2
+
3
+ require 'opencv-ffi/highgui'
4
+
5
+ module CVFFI
6
+
7
+ def self.save_image( fname, img )
8
+ CVFFI::cvSaveImage( fname, img.to_IplImage )
9
+ end
10
+ end
@@ -0,0 +1,4 @@
1
+
2
+ require 'opencv-ffi-wrappers/imgproc/features'
3
+ require 'opencv-ffi-wrappers/imgproc/geometric'
4
+
@@ -0,0 +1,35 @@
1
+
2
+ require 'opencv-ffi'
3
+ require 'opencv-ffi-wrappers/misc/params'
4
+
5
+ module CVFFI
6
+
7
+ class GoodFeaturesParams < Params
8
+
9
+ param :max_corners, 1000,
10
+ :quality_level, 0.5,
11
+ :min_distance, 5,
12
+ :block_size, 3,
13
+ :use_harris, false,
14
+ :k, 0.04,
15
+ :mask, nil
16
+
17
+ end
18
+
19
+
20
+ def self.goodFeaturesToTrack( image, params = GoodFeaturesParams.new )
21
+
22
+ # TODO, technically, cvGoodFeaturesToTrack can also take 32FC1 data as well,
23
+ # doesn't necessarily need to be cast to 8UC1 greyscale
24
+ img = image.to_IplImage.ensure_greyscale
25
+ eig_image = img.twin( :IPL_DEPTH_32F )
26
+ temp_image = eig_image.twin
27
+
28
+ CVFFI::cvGoodFeaturesToTrack( img, eig_image, temp_image, params.max_corners,
29
+ params.quality_level, params.min_distance, params.mask,
30
+ params.block_size, params.use_harris, params.k )
31
+ end
32
+
33
+
34
+
35
+ end
@@ -0,0 +1,39 @@
1
+
2
+
3
+ require 'opencv-ffi'
4
+
5
+ module CVFFI
6
+
7
+ # Might be the simplest way to do this
8
+ class GetAffineTransformPoints < NiceFFI::Struct
9
+ layout :a, [ CvPoint2D32f, 3 ]
10
+ end
11
+
12
+ def self.get_affine_transform( src, dst )
13
+ result = CVFFI::cvCreateMat( 2, 3, :CV_32F )
14
+
15
+ srcPts = GetAffineTransformPoints.new '\0'
16
+ dstPts = GetAffineTransformPoints.new '\0'
17
+
18
+ 0.upto(2) { |i|
19
+ srcPts.a[i].x = src[i].x
20
+ srcPts.a[i].y = src[i].y
21
+ dstPts.a[i].x = dst[i].x
22
+ dstPts.a[i].y = dst[i].y
23
+ }
24
+
25
+ CVFFI::cvGetAffineTransform( srcPts, dstPts, result )
26
+ end
27
+
28
+ def self.warp_affine( src, dst, mat, opts={} )
29
+ flags = opts[:flags] || [ :CV_INTER_LINEAR, :CV_WARP_FILL_OUTLIERS ]
30
+ flags << :CV_WARP_INVERSE_MAP if opts[:inverse]
31
+
32
+ flags = flags.inject(0) { |x,i| x + cv_warp_flags_to_i( i ) }
33
+ CVFFI::cvWarpAffine( src.to_IplImage, dst, mat, flags,
34
+ CVFFI::CvScalar.new( [ 0.0, 0.0, 0.0, 0.0 ] ) )
35
+
36
+
37
+ dst
38
+ end
39
+ end
@@ -0,0 +1,297 @@
1
+
2
+
3
+ require 'opencv-ffi-wrappers'
4
+
5
+ module AddMapWithIndex
6
+
7
+ def map_with_index( &blk )
8
+ a = []
9
+ each_with_index { |k,i| a << blk.yield( k,i ) }
10
+ a
11
+ end
12
+ end
13
+
14
+ module CVFFI
15
+
16
+ class Match < NiceFFI::Struct
17
+ layout :train, CvPoint2D32f,
18
+ :query, CvPoint2D32f,
19
+ :distance, :double
20
+ end
21
+
22
+ class MatchSet < NiceFFI::Struct
23
+ layout :length, :int,
24
+ :d, :pointer,
25
+ :err, :pointer
26
+ end
27
+
28
+ class MatchResult
29
+ attr_accessor :train_idx, :query_idx
30
+ attr_accessor :distance
31
+
32
+ alias :tidx :train_idx
33
+ alias :qidx :query_idx
34
+ alias :dist :distance
35
+
36
+ def initialize( t, q, d )
37
+ @train_idx = t
38
+ @query_idx = q
39
+ @distance = d
40
+ end
41
+
42
+ def to_s
43
+ "Match t=#{@train_idx} q=#{@query_idx} distance=#{@distance}"
44
+ end
45
+
46
+ def train
47
+ @train_set[@train_idx]
48
+ end
49
+
50
+ def query
51
+ @query_set[@query_idx]
52
+ end
53
+
54
+ end
55
+
56
+ class MatchResults
57
+ include Enumerable
58
+
59
+ attr_accessor :train_set, :query_set
60
+ attr_accessor :results
61
+
62
+ def initialize( tset, qset )
63
+ @train_set = tset
64
+ @query_set = qset
65
+
66
+ @results = []
67
+ @match_cache = []
68
+
69
+ @by_train = []
70
+ @by_train.extend( AddMapWithIndex )
71
+
72
+ @by_query = []
73
+
74
+ @mask = []
75
+ end
76
+
77
+ def add_result(r)
78
+ raise RuntimeError "index greater than size of training set (#{r.train_idx} > #{train_set.size})" if r.train_idx >= train_set.size
79
+ raise RuntimeError "index greater than size of query set (#{r.query_idx} > #{query_set.size})" if r.query_idx >= query_set.size
80
+ @results << r
81
+ (@by_train[r.train_idx] ||= Array.new) << r
82
+ (@by_query[r.query_idx] ||= Array.new) << r
83
+ r
84
+ end
85
+
86
+ def add( tidx, qidx, dist )
87
+ add_result MatchResult.new( tidx, qidx, dist )
88
+ end
89
+
90
+ def to_s
91
+ [ "Total matches: #{@results.size}" ] +
92
+ @by_train.map_with_index { |r,tidx|
93
+ "Tidx #{tidx} (#{r.nil? ? 0 : r.length}): #{r.nil? ? "" : r.map {|r| sprintf "%d(%.2e)", r.query_idx, r.dist }.join(' ') }"
94
+ }
95
+ end
96
+
97
+ def to_a
98
+ Array.new( size ) { |i|
99
+ [ @results[i].tidx, @results[i].qidx, @results[i].dist ]
100
+ }
101
+ end
102
+
103
+ def length( include_masked = false )
104
+ if( include_masked )
105
+ @results.length
106
+ else
107
+ num_unmasked
108
+ end
109
+ end
110
+
111
+ alias :size :length
112
+
113
+ def [](i)
114
+ if @match_cache[i]
115
+ @match_cache[i]
116
+ else
117
+ m=Match.new( '\0' )
118
+ m.distance = @results[i].distance
119
+
120
+ # This is a bit awkward with nested FFI structs
121
+ m.train.x = @train_set[@results[i].tidx].x
122
+ m.train.y = @train_set[@results[i].tidx].y
123
+ m.query.x = @query_set[@results[i].qidx].x
124
+ m.query.y = @query_set[@results[i].qidx].y
125
+ @match_cache[i] = m
126
+ m
127
+ end
128
+ end
129
+ alias :element :[]
130
+
131
+ # Experiment
132
+ def match_set
133
+ if @match_set
134
+ @match_set
135
+ else
136
+ m = FFI::MemoryPointer.new( Match, length )
137
+ results_each_with_index { |r,i|
138
+ match = Match.new( m + i*Match.size )
139
+ match.distance = r.distance
140
+
141
+ # This is a bit awkward with nested FFI structs
142
+ match.train.x = @train_set[r.tidx].x
143
+ match.train.y = @train_set[r.tidx].y
144
+ match.query.x = @query_set[r.qidx].x
145
+ match.query.y = @query_set[r.qidx].y
146
+ }
147
+ ms = MatchSet.new( :length => length,
148
+ :d => m,
149
+ :err => FFI::MemoryPointer.new( :double, length ) )
150
+ @match_set = ms
151
+ end
152
+ end
153
+
154
+ def invalidate_match_set; @match_set = nil; end
155
+
156
+ # The "public" each yields a Match to the block
157
+ def each( include_masked = false, &blk )
158
+ @results.length.times { |i|
159
+ if !include_masked and !masked?(i)
160
+ blk.yield( element(i) )
161
+ end
162
+ }
163
+ end
164
+
165
+ # the "private" each yelds a MatchResult to the block
166
+ def results_each_with_index( include_masked = false, &blk )
167
+ @results.each_with_index { |r,i|
168
+ if !include_masked and !masked?(i)
169
+ blk.yield( r,i )
170
+ end
171
+ }
172
+ end
173
+
174
+ def results_each( include_masked = false, &blk )
175
+ results_each_with_index { |r,i| blk.yield(r) }
176
+ end
177
+
178
+ def num_masked
179
+ @mask.inject(0) { |m,s| s ? m+1 : m }
180
+ end
181
+
182
+ def num_unmasked
183
+ @results.length - num_masked
184
+ end
185
+
186
+ def masked?( i )
187
+ @mask[i] == true
188
+ end
189
+
190
+ def mask( i )
191
+ invalidate_match_set
192
+ @mask[i] = true
193
+ end
194
+
195
+ def unmask(i)
196
+ invalidate_match_set
197
+ @mask[i] = false
198
+ end
199
+
200
+ def clear_mask(i)
201
+ invalidate_match_set
202
+ @mask = []
203
+ end
204
+
205
+ def get_mask
206
+ @mask
207
+ end
208
+
209
+ def set_mask(m)
210
+ invalidate_match_set
211
+ @mask = m
212
+ end
213
+
214
+ def merge_mask(m)
215
+ invalidate_match_set
216
+ old_mask = @mask
217
+ @mask = Array.new( [old_mask.length, m.length].max ) { |i|
218
+ old_mask[i] or m[i]
219
+ }
220
+ end
221
+
222
+ def to_Points( include_masked = false )
223
+ pointsOne = []
224
+ pointsTwo = []
225
+
226
+ results_each( include_masked ) { |r|
227
+ pointsOne << @train_set[r.tidx].to_Point
228
+ pointsTwo << @query_set[r.qidx].to_Point
229
+ }
230
+
231
+ [pointsOne, pointsTwo]
232
+ end
233
+
234
+
235
+ def to_CvMats( include_masked = false )
236
+ pointsOne = CVFFI::cvCreateMat( num_unmasked, 2, :CV_32F )
237
+ pointsTwo = CVFFI::cvCreateMat( num_unmasked, 2, :CV_32F )
238
+
239
+ results_each_with_index( include_masked ) { |r,i|
240
+ CVFFI::cvSetReal2D( pointsOne, i, 0, @train_set[r.tidx].x )
241
+ CVFFI::cvSetReal2D( pointsOne, i, 1, @train_set[r.tidx].y )
242
+ CVFFI::cvSetReal2D( pointsTwo, i, 0, @query_set[r.qidx].x )
243
+ CVFFI::cvSetReal2D( pointsTwo, i, 1, @query_set[r.qidx].y )
244
+ }
245
+
246
+ [pointsOne, pointsTwo]
247
+ end
248
+
249
+ end
250
+
251
+ class BruteForceMatcher
252
+
253
+ def self.euclidian_distance( a, b )
254
+
255
+
256
+ end
257
+
258
+ def self.bestMatch( train, query, opts = {})
259
+ maxDistance = opts[:max_distance] || nil
260
+ k = opts[:k] || nil
261
+
262
+ results = MatchResults.new( train, query )
263
+ query.each_with_index { |q,qidx|
264
+
265
+ this_result = []
266
+ train.each_with_index { |t,tidx|
267
+ distance = block_given? ? yield( t,q ) : t.distance_to(q)
268
+
269
+ ## Non-optimized algorithms...
270
+ if maxDistance
271
+ if distance < maxDistance
272
+ this_result << MatchResult.new( tidx, qidx, distance )
273
+ end
274
+ elsif k
275
+ if this_result.length < k
276
+ this_result << MatchResult.new( tidx, qidx, distance )
277
+ else
278
+ this_result.sort! { |a,b| a.distance <=> b.distance }
279
+ if distance < this_result[0].distance
280
+ this_result[0] = MatchResult.new( tidx, qidx, distance )
281
+ end
282
+ end
283
+ else
284
+ if this_result.length == 0 or distance < this_result[0].distance
285
+ this_result = [ MatchResult.new( tidx, qidx, distance ) ]
286
+ end
287
+ end
288
+
289
+ }
290
+ this_result.each { |r| results.add_result( r ) }
291
+ }
292
+
293
+ results
294
+ end
295
+
296
+ end
297
+ end