georuby-ext 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/.jrubyrc +1 -0
  2. data/.travis.yml +23 -0
  3. data/Gemfile +6 -0
  4. data/Guardfile +12 -2
  5. data/MIT-LICENSE +20 -0
  6. data/README.rdoc +2 -28
  7. data/georuby-ext.gemspec +14 -11
  8. data/lib/georuby-ext.rb +17 -2
  9. data/lib/georuby-ext/core_ext.rb +11 -0
  10. data/lib/georuby-ext/geokit.rb +10 -3
  11. data/lib/georuby-ext/georuby/envelope.rb +36 -1
  12. data/lib/georuby-ext/georuby/ewkb_parser.rb +11 -0
  13. data/lib/georuby-ext/georuby/ewkt_parser.rb +11 -0
  14. data/lib/georuby-ext/georuby/geometry.rb +46 -2
  15. data/lib/georuby-ext/georuby/line_string.rb +19 -7
  16. data/lib/georuby-ext/georuby/linear_ring.rb +15 -0
  17. data/lib/georuby-ext/georuby/locators.rb +30 -17
  18. data/lib/georuby-ext/georuby/multi_polygon.rb +15 -1
  19. data/lib/georuby-ext/georuby/point.rb +148 -24
  20. data/lib/georuby-ext/georuby/polygon.rb +38 -27
  21. data/lib/georuby-ext/georuby/rtree.rb +133 -0
  22. data/lib/georuby-ext/georuby/srid.rb +17 -0
  23. data/lib/georuby-ext/proj4.rb +15 -2
  24. data/lib/georuby-ext/rgeo/cartesian/feature_methods.rb +58 -0
  25. data/lib/georuby-ext/rgeo/feature/geometry.rb +11 -0
  26. data/lib/georuby-ext/rgeo/feature/geometry_collection.rb +11 -0
  27. data/lib/georuby-ext/rgeo/feature/rgeo.rb +157 -0
  28. data/lib/georuby-ext/rgeo/geos/ffi_feature_methods.rb +265 -0
  29. data/lib/georuby-ext/rspec_helper.rb +47 -8
  30. data/spec/lib/geokit_spec.rb +44 -0
  31. data/spec/lib/georuby/envelope_spec.rb +46 -0
  32. data/spec/lib/georuby/geometry_spec.rb +81 -0
  33. data/spec/{georuby → lib/georuby}/line_string_spec.rb +29 -14
  34. data/spec/lib/georuby/linear_ring_spec.rb +52 -0
  35. data/spec/lib/georuby/locators_spec.rb +123 -0
  36. data/spec/lib/georuby/multi_polygon_spec.rb +69 -0
  37. data/spec/lib/georuby/point_spec.rb +248 -0
  38. data/spec/lib/georuby/polygon_spec.rb +175 -0
  39. data/spec/lib/georuby/rtree_spec.rb +132 -0
  40. data/spec/lib/proj4_spec.rb +24 -0
  41. data/spec/lib/rgeo/cartesian/feature_methods_spec.rb +110 -0
  42. data/spec/lib/rgeo/geos/ffi_feature_methods_spec.rb +234 -0
  43. data/spec/spec_helper.rb +12 -8
  44. metadata +224 -189
  45. data/lib/georuby-ext/rgeo.rb +0 -23
  46. data/spec/georuby/linear_ring_spec.rb +0 -33
  47. data/spec/georuby/locators_spec.rb +0 -120
  48. data/spec/georuby/multi_polygon_spec.rb +0 -29
  49. data/spec/georuby/point_spec.rb +0 -44
  50. data/spec/georuby/polygon_spec.rb +0 -134
  51. data/spec/rgeo_spec.rb +0 -81
@@ -0,0 +1 @@
1
+ compat.version=1.8
@@ -0,0 +1,23 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 1.8.7
5
+ - jruby-18mode
6
+ jdk:
7
+ - oraclejdk7
8
+ - openjdk7
9
+ - openjdk6
10
+ matrix:
11
+ exclude:
12
+ - rvm: 1.8.7
13
+ jdk: openjdk7
14
+ - rvm: 1.9.3
15
+ jdk: openjdk7
16
+ - rvm: 1.8.7
17
+ jdk: oraclejdk7
18
+ - rvm: 1.9.3
19
+ jdk: oraclejdk7
20
+ before_install:
21
+ - sudo apt-get update
22
+ - sudo apt-get install libproj-dev libgeos-dev libffi-dev libsparsehash-dev
23
+ script: "rake spec"
data/Gemfile CHANGED
@@ -2,3 +2,9 @@ source "http://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in georuby-ext.gemspec
4
4
  gemspec
5
+
6
+ group :development do
7
+ gem 'rb-inotify', ">= 0.8.8", :require => RUBY_PLATFORM.include?('linux') && 'rb-inotify'
8
+ gem 'libnotify', ">= 0.8.0", :require => RUBY_PLATFORM.include?('linux') && 'libnotify'
9
+ gem 'rb-fsevent', ">= 0.9.3", :require => RUBY_PLATFORM.include?('darwin') && 'rb-fsevent'
10
+ end
data/Guardfile CHANGED
@@ -6,8 +6,18 @@ guard 'bundler' do
6
6
  watch(/^.+\.gemspec/)
7
7
  end
8
8
 
9
- guard 'rspec', :version => 2 do
9
+ guard 'rspec', :version => 2, :notification => false do
10
10
  watch(%r{^spec/.+_spec\.rb$})
11
- watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
11
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
12
12
  watch('spec/spec_helper.rb') { "spec" }
13
+
14
+ # Rails example
15
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
16
+ watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
17
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
18
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
19
+ watch('config/routes.rb') { "spec/routing" }
20
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
21
+ # Capybara request specs
22
+ watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
13
23
  end
@@ -0,0 +1,20 @@
1
+ Copyright 2012 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -1,4 +1,4 @@
1
- == georuby-ext
1
+ == Georuby-ext {<img src="https://travis-ci.org/dryade/georuby-ext.png?branch=master" alt="Build Status" />}[https://travis-ci.org/dryade/georuby-ext] {<img src="https://codeclimate.com/badge.png" />}[https://codeclimate.com/github/dryade/georuby-ext]
2
2
 
3
3
  georuby-ext is an extension to Ruby geometry libraries
4
4
 
@@ -8,30 +8,4 @@ GeoRuby, rgeo, geokit, proj4j (...) are nice ruby libraries which cover the same
8
8
 
9
9
  === License
10
10
 
11
- Copyright 2011 Dryade SAS
12
-
13
- All rights reserved.
14
-
15
- Redistribution and use in source and binary forms, with or without
16
- modification, are permitted provided that the following conditions are met:
17
-
18
- * Redistributions of source code must retain the above copyright notice,
19
- this list of conditions and the following disclaimer.
20
- * Redistributions in binary form must reproduce the above copyright notice,
21
- this list of conditions and the following disclaimer in the documentation
22
- and/or other materials provided with the distribution.
23
- * Neither the name of the copyright holder, nor the names of any other
24
- contributors to this software, may be used to endorse or promote products
25
- derived from this software without specific prior written permission.
26
-
27
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31
- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36
- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37
- POSSIBILITY OF SUCH DAMAGE.
11
+ This project uses MIT-LICENSE.
@@ -3,15 +3,13 @@ $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "georuby-ext"
6
- s.version = "0.0.1"
6
+ s.version = "0.0.2"
7
7
  s.authors = ["Marc Florisson", "Luc Donnet", "Alban Peignier"]
8
- s.email = ["marc@dryade.net", "luc@dryade.net", "alban@dryade.net"]
8
+ s.email = ["mflorisson@cityway.fr", "ldonnet@cityway.fr", "alban@tryphon.eu"]
9
9
  s.homepage = "http://github.com/dryade/georuby-ext"
10
10
  s.summary = %q{Extension to Ruby geometry libraries}
11
11
  s.description = %q{Use together GeoRuby, rgeo, geokit, proj4j (and others)}
12
12
 
13
- s.rubyforge_project = "georuby-ext"
14
-
15
13
  s.files = `git ls-files`.split("\n")
16
14
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
15
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
@@ -19,13 +17,18 @@ Gem::Specification.new do |s|
19
17
 
20
18
  s.add_development_dependency "rspec"
21
19
  s.add_development_dependency "rake"
22
- s.add_development_dependency "guard"
23
- s.add_development_dependency "rcov"
20
+ s.add_development_dependency "guard", ">= 1.3.3"
21
+ s.add_development_dependency "guard-rspec"
22
+ s.add_development_dependency "guard-bundler"
24
23
 
25
- s.add_runtime_dependency "GeoRuby"
26
- s.add_runtime_dependency "geokit"
27
- s.add_runtime_dependency "rgeo"
28
- s.add_runtime_dependency "proj4rb"
24
+ s.add_dependency "georuby", "1.9.8"
25
+ s.add_dependency "dbf"
26
+ s.add_dependency "nokogiri"
27
+ s.add_dependency "geokit"
28
+ s.add_dependency "rgeo", "0.3.20"
29
+ s.add_dependency "json_pure"
30
+ s.add_dependency "ffi-geos", "0.1.1"
31
+ s.add_dependency "dr-ffi-proj4", "0.0.1"
29
32
 
30
- s.add_runtime_dependency "activesupport"
33
+ s.add_dependency "activesupport"
31
34
  end
@@ -1,17 +1,32 @@
1
+ require 'ffi-proj4'
1
2
  require 'geo_ruby'
2
3
  require 'geokit'
3
4
  require 'rgeo'
4
- require 'proj4'
5
5
 
6
6
  require 'active_support/core_ext/enumerable'
7
+ require 'active_support/core_ext/module/delegation'
8
+ require 'active_support/core_ext/object/blank'
9
+ require 'active_support/deprecation'
10
+ require 'active_support/memoizable'
11
+
12
+ require 'georuby-ext/core_ext'
13
+
14
+ require 'georuby-ext/rgeo/feature/geometry'
15
+ require 'georuby-ext/rgeo/feature/geometry_collection'
16
+ require 'georuby-ext/rgeo/geos/ffi_feature_methods'
7
17
 
8
- require 'georuby-ext/rgeo'
9
18
  require 'georuby-ext/geokit'
10
19
  require 'georuby-ext/proj4'
11
20
 
21
+ require 'georuby-ext/georuby/rtree'
22
+ require 'georuby-ext/georuby/srid'
23
+ require 'georuby-ext/georuby/geometry'
12
24
  require 'georuby-ext/georuby/point'
13
25
  require 'georuby-ext/georuby/line_string'
26
+ require 'georuby-ext/georuby/linear_ring'
14
27
  require 'georuby-ext/georuby/polygon'
15
28
  require 'georuby-ext/georuby/multi_polygon'
16
29
  require 'georuby-ext/georuby/envelope'
17
30
  require 'georuby-ext/georuby/locators'
31
+
32
+ require 'georuby-ext/georuby/ewkt_parser'
@@ -0,0 +1,11 @@
1
+ class Numeric
2
+
3
+ def deg2rad
4
+ to_f / 180.0 * Math::PI
5
+ end
6
+
7
+ def rad2deg
8
+ to_f * 180.0 / Math::PI
9
+ end
10
+
11
+ end
@@ -2,15 +2,22 @@ module GeoKit
2
2
  class LatLng
3
3
 
4
4
  def valid?
5
- self.lat and self.lng
5
+ self.lat and self.lng and
6
+ self.lat >= -90 and self.lat <= 90 and
7
+ self.lng >= -180 and self.lng <= 180
6
8
  end
7
9
 
10
+ # DEPRECATED
11
+ # Use Point geometry which supports srid
12
+
8
13
  def wgs84_to_google
9
- self.class.from_pro4j Proj4::Projection.wgs84.transform Proj4::Projection.google, self.proj4_point(Math::PI / 180)
14
+ ActiveSupport::Deprecation.warn "use Point geometry which supports srid"
15
+ self.class.from_pro4j Proj4::Projection.wgs84.transform Proj4::Projection.google, self.proj4_point(Math::PI / 180).x, self.proj4_point(Math::PI / 180).y
10
16
  end
11
17
 
12
18
  def google_to_wgs84
13
- self.class.from_pro4j Proj4::Projection.google.transform(Proj4::Projection.wgs84, self.proj4_point), 180 / Math::PI
19
+ ActiveSupport::Deprecation.warn "use Point geometry which supports srid"
20
+ self.class.from_pro4j Proj4::Projection.google.transform(Proj4::Projection.wgs84, self.proj4_point.x, self.proj4_point.y), 180 / Math::PI
14
21
  end
15
22
 
16
23
  def proj4_point(ratio = 1)
@@ -1,10 +1,45 @@
1
1
  class GeoRuby::SimpleFeatures::Envelope
2
+
3
+ def contains_point?(point)
4
+ (lower_corner.x...upper_corner.x).include?(point.x) and
5
+ (lower_corner.y...upper_corner.y).include?(point.y)
6
+ end
7
+
8
+ def overlaps?(bound)
9
+ contains_point?(bound.upper_corner) or contains_point?(bound.lower_corner) or bound.contains_point?(upper_corner) or bound.contains_point?(lower_corner)
10
+ end
11
+
12
+ def self.bounds(geometries)
13
+ return nil if geometries.blank?
14
+
15
+ geometries.inject(geometries.first.envelope) do |envelope, geometry|
16
+ envelope.extend!(geometry.envelope)
17
+ end
18
+ end
19
+
20
+ alias_method :contains?, :contains_point?
21
+
22
+ def sql_box
23
+ "SetSRID('BOX3D(#{upper_corner.lng} #{upper_corner.lat}, #{lower_corner.lng} #{lower_corner.lat})'::box3d, #{srid})"
24
+ end
25
+
26
+ alias_method :to_sql, :sql_box
27
+
2
28
  def to_openlayers
3
29
  OpenLayers::Bounds.new lower_corner.x, lower_corner.y, upper_corner.x, upper_corner.y
4
30
  end
5
31
 
6
32
  def to_google
7
- Envelope.from_points [lower_corner.to_google, upper_corner.to_google],srid, with_z
33
+ GeoRuby::SimpleFeatures::Envelope.from_points [lower_corner.to_google, upper_corner.to_google], 900913, with_z
34
+ end
35
+
36
+ def to_polygon
37
+ GeoRuby::SimpleFeatures::Polygon.from_coordinates( [ [ [lower_corner.x, lower_corner.y], [lower_corner.x, upper_corner.y], [upper_corner.x, upper_corner.y], [upper_corner.x, lower_corner.y] ] ] )
38
+ end
39
+
40
+ def to_rgeo
41
+ self.to_polygon.to_rgeo
8
42
  end
43
+
9
44
  end
10
45
 
@@ -0,0 +1,11 @@
1
+ class GeoRuby::SimpleFeatures::EWKBParser
2
+
3
+ private
4
+
5
+ def parse_linear_ring_with_close_support
6
+ parse_linear_ring_without_close_support
7
+ @factory.geometry.close!
8
+ end
9
+ alias_method_chain :parse_linear_ring, :close_support
10
+
11
+ end
@@ -0,0 +1,11 @@
1
+ class GeoRuby::SimpleFeatures::EWKTParser
2
+
3
+ private
4
+
5
+ def parse_linear_ring_with_close_support
6
+ parse_linear_ring_without_close_support
7
+ @factory.geometry.close!
8
+ end
9
+ alias_method_chain :parse_linear_ring, :close_support
10
+
11
+ end
@@ -1,9 +1,53 @@
1
- module GeoRuby::SimpleFeatures::Geometry
1
+ class GeoRuby::SimpleFeatures::Geometry
2
2
 
3
3
  def inspect
4
- "#<#{self.class}:#{object_id} \"#{as_ewkt}>\""
4
+ "#<#{self.class}:#{object_id} \"#{to_ewkt}>\""
5
5
  end
6
6
 
7
7
  alias_method :to_ewkt, :as_ewkt
8
8
 
9
+ def wgs84?
10
+ srid == 4326
11
+ end
12
+
13
+ def to_wgs84
14
+ project_to 4326
15
+ end
16
+
17
+ def to_google
18
+ project_to 900913
19
+ end
20
+
21
+ def to_geometry
22
+ self
23
+ end
24
+
25
+ def self.srid!(geometries)
26
+ geometries.first.srid.tap do |srid|
27
+ raise "SRIDs are not uniq in #{geometries.inspect}" if geometries.any? { |geometry| geometry.srid != srid }
28
+ end unless geometries.blank?
29
+ end
30
+
31
+ def srid_instance
32
+ @srid_instance ||= GeoRuby::SimpleFeatures::Srid.new(srid)
33
+ end
34
+ delegate :rgeo_factory, :to => :srid_instance
35
+
36
+ alias_method :bounds, :envelope
37
+
38
+ def self.to_kml(*geometries)
39
+ <<EOF
40
+ <?xml version="1.0" encoding="UTF-8"?>
41
+ <kml xmlns="http://www.opengis.net/kml/2.2">
42
+ <Document>
43
+ <Placemark>
44
+ <MultiGeometry>
45
+ #{geometries.map(&:kml_representation).join("\n")}
46
+ </MultiGeometry>
47
+ </Placemark>
48
+ </Document>
49
+ </kml>
50
+ EOF
51
+ end
52
+
9
53
  end
@@ -12,30 +12,42 @@ class GeoRuby::SimpleFeatures::LineString
12
12
  change :points => points.reverse
13
13
  end
14
14
 
15
- def to_wgs84
16
- change :points => points.map(&:to_wgs84), :srid => 4326
15
+ def project_to(target_srid)
16
+ return self if srid == target_srid
17
+ change :points => points.map { |point| point.project_to(target_srid) }, :srid => target_srid
17
18
  end
18
19
 
19
20
  def self.merge(lines)
21
+ # FIXME flatten.uniq can break crossing lines
20
22
  merged_points = lines.map(&:points).flatten.uniq
21
23
  if merged_points.size > 1
22
- from_points merged_points, lines.first.srid, lines.first.with_z, lines.first.with_m
24
+ from_points merged_points, srid!(lines), lines.first.with_z, lines.first.with_m
23
25
  end
24
26
  end
25
27
 
26
28
  def to_rgeo
27
- RGeo::Geos::factory(:srid => srid).line_string(points.collect(&:to_rgeo))
29
+ rgeo_factory.line_string(points.collect(&:to_rgeo))
30
+ end
31
+
32
+ def side_count
33
+ size - 1
28
34
  end
29
35
 
30
36
  def ==(other)
31
37
  other.respond_to?(:points) and points == other.points
32
38
  end
33
39
 
34
- alias_method :closed?, :is_closed
40
+ def close!
41
+ points << points.first unless closed?
42
+ self
43
+ end
35
44
 
36
45
  def to_ring
37
- ring_points = closed? ? points : points + [first]
38
- GeoRuby::SimpleFeatures::LinearRing.from_points ring_points, srid, with_z, with_m
46
+ GeoRuby::SimpleFeatures::LinearRing.from_points points, srid, with_z, with_m
47
+ end
48
+
49
+ def to_kml
50
+ GeoRuby::SimpleFeatures::Geometry.to_kml self
39
51
  end
40
52
 
41
53
  end
@@ -0,0 +1,15 @@
1
+ class GeoRuby::SimpleFeatures::LinearRing
2
+
3
+ class << self
4
+ def from_points_with_close_support(*arguments)
5
+ from_points_without_close_support(*arguments).close!
6
+ end
7
+ alias_method_chain :from_points, :close_support
8
+
9
+ def from_coordinates_with_close_support(*arguments)
10
+ from_coordinates_without_close_support(*arguments).close!
11
+ end
12
+ alias_method_chain :from_coordinates, :close_support
13
+ end
14
+
15
+ end
@@ -1,6 +1,3 @@
1
- require 'active_support/memoizable'
2
- require 'active_support/core_ext/module/delegation'
3
-
4
1
  class GeoRuby::SimpleFeatures::MultiLineString
5
2
 
6
3
  alias_method :lines, :geometries
@@ -12,7 +9,9 @@ class GeoRuby::SimpleFeatures::MultiLineString
12
9
 
13
10
  def interpolate_point(location)
14
11
  line_index, line_location = location.to_i, location % 1
15
- lines[line_index].interpolate_point(line_location)
12
+ if line = lines[line_index]
13
+ line.interpolate_point(line_location)
14
+ end
16
15
  end
17
16
 
18
17
  def nearest_locator(target)
@@ -56,7 +55,7 @@ end
56
55
  class GeoRuby::SimpleFeatures::LineString
57
56
 
58
57
  def locate_point(target)
59
- distance_on_line(target) / distance
58
+ distance_on_line(target) / spherical_distance
60
59
  end
61
60
 
62
61
  def distance_on_line(target)
@@ -76,14 +75,17 @@ class GeoRuby::SimpleFeatures::LineString
76
75
  segments.collect { |segment| segment.locator(point) }
77
76
  end
78
77
 
79
- def segments
78
+ def segments_without_cache
80
79
  previous_point = nil
81
80
  distance_from_departure = 0
82
81
 
82
+
83
83
  points.inject([]) do |segments, point|
84
84
  Segment.new(previous_point, point).tap do |segment|
85
85
  segment.line = self
86
- segment.line_distance_at_departure = segments.sum(&:distance)
86
+ segment.line_distance_at_departure = distance_from_departure
87
+
88
+ distance_from_departure += segment.distance
87
89
 
88
90
  segments << segment
89
91
  end if previous_point
@@ -93,15 +95,16 @@ class GeoRuby::SimpleFeatures::LineString
93
95
  end
94
96
  end
95
97
 
96
- def distance
97
- segments.sum(&:distance)
98
+ def segments_with_cache
99
+ @segments ||= segments_without_cache
98
100
  end
101
+ alias_method :segments, :segments_with_cache
99
102
 
100
103
  def interpolate_point(location)
101
104
  return points.last if location >= 1
102
105
  return points.first if location <= 0
103
106
 
104
- distance_on_line = location * distance
107
+ distance_on_line = location * spherical_distance
105
108
 
106
109
  segment = segments.find do |segment|
107
110
  segment.line_distance_at_arrival > distance_on_line
@@ -138,11 +141,11 @@ class GeoRuby::SimpleFeatures::LineString
138
141
  end
139
142
 
140
143
  def square_of_distance
141
- (arrival.x - departure.x)**2 + (arrival.y - departure.y)**2
144
+ distance**2
142
145
  end
143
146
 
144
147
  def distance
145
- departure.euclidian_distance(arrival)
148
+ @distance ||= departure.spherical_distance(arrival)
146
149
  end
147
150
 
148
151
  def to_s
@@ -177,6 +180,8 @@ class GeoRuby::SimpleFeatures::LineString
177
180
  end
178
181
 
179
182
  def distance_from_segment
183
+ return 0 if [segment.departure, segment.arrival].include?(target)
184
+
180
185
  sin_angle * target_distance_from_departure
181
186
  end
182
187
 
@@ -190,8 +195,16 @@ class GeoRuby::SimpleFeatures::LineString
190
195
  scalar_product / square_of_segment_distance
191
196
  end
192
197
 
198
+ # def scalar_product
199
+ # (target.x-departure.x)*(arrival.x-departure.x) + (target.y-departure.y)*(arrival.y-departure.y).to_f
200
+ # end
201
+
193
202
  def scalar_product
194
- (target.x-departure.x)*(arrival.x-departure.x) + (target.y-departure.y)*(arrival.y-departure.y).to_f
203
+ departure_target_metric_delta = departure.metric_delta(target)
204
+ departure_arrival_metric_delta = departure.metric_delta(arrival)
205
+
206
+ departure_target_metric_delta[0]*departure_arrival_metric_delta[0] +
207
+ departure_target_metric_delta[1]*departure_arrival_metric_delta[1]
195
208
  end
196
209
  memoize :scalar_product
197
210
 
@@ -204,20 +217,20 @@ class GeoRuby::SimpleFeatures::LineString
204
217
  end
205
218
 
206
219
  def cos_angle
207
- scalar_product / segment_distance / target_distance_from_departure
220
+ [-1, [1, scalar_product / segment_distance / target_distance_from_departure].min].max
208
221
  end
209
222
 
210
223
  def square_of_segment_distance
211
- (arrival.x - departure.x)**2 + (arrival.y - departure.y)**2
224
+ segment_distance ** 2
212
225
  end
213
226
  memoize :square_of_segment_distance
214
227
 
215
228
  def segment_distance
216
- sqrt square_of_segment_distance
229
+ segment.distance
217
230
  end
218
231
 
219
232
  def target_distance_from_departure
220
- sqrt((target.x - departure.x)**2 + (target.y - departure.y)**2)
233
+ departure.spherical_distance target
221
234
  end
222
235
 
223
236
  end