GeoRuby 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,38 @@
1
+ require 'geo_ruby/simple_features/geometry_collection'
2
+
3
+
4
+ module GeoRuby
5
+ module SimpleFeatures
6
+ #Represents a group of polygons (see Polygon).
7
+ class MultiPolygon < GeometryCollection
8
+ def initialize(srid = DEFAULT_SRID)
9
+ super(srid)
10
+ end
11
+ def binary_geometry_type
12
+ 6
13
+ end
14
+ #Text representation of a MultiPolygon
15
+ def text_representation(dimension=2)
16
+ @geometries.collect{|polygon| "(" + polygon.text_representation(dimension) + ")"}.join(",")
17
+ end
18
+ #WKT geometry type
19
+ def text_geometry_type
20
+ "MULTIPOLYGON"
21
+ end
22
+
23
+ #Creates a multi polygon from an array of polygons
24
+ def self.from_polygons(polygons,srid=DEFAULT_SRID)
25
+ multi_polygon = MultiPolygon::new(srid)
26
+ multi_polygon.concat(polygons)
27
+ multi_polygon
28
+ end
29
+ #Creates a multi polygon from sequences of points : ((((x,y)...(x,y)),((x,y)...(x,y)),((x,y)...(x,y)))
30
+ def self.from_raw_point_sequences(point_sequences, srid= DEFAULT_SRID)
31
+ multi_polygon = MultiPolygon::new(srid)
32
+ multi_polygon.concat( point_sequences.collect {|point_sequence| Polygon.from_raw_point_sequences(point_sequence,srid) } )
33
+ multi_polygon
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,85 @@
1
+ require "geo_ruby/simple_features/geometry"
2
+
3
+ module GeoRuby
4
+ module SimpleFeatures
5
+ #Represents a point. It is in 3D if the Z coordinate is not +nil+.
6
+ class Point < Geometry
7
+ #Coordinates of the point
8
+ attr_accessor :x,:y,:z
9
+
10
+ def initialize(srid=DEFAULT_SRID)
11
+ super(srid)
12
+ @x=0.0
13
+ @y=0.0
14
+ @z=nil
15
+ end
16
+ #sets all coordinates in one call
17
+ def set_x_y_z(x,y,z)
18
+ @x=x
19
+ @y=y
20
+ @z=z
21
+ end
22
+ #sets all coordinates of a 2D point in one call
23
+ def set_x_y(x,y)
24
+ @x=x
25
+ @y=y
26
+ end
27
+ #tests the equality of points
28
+ def ==(other_point)
29
+ if other_point.class != self.class
30
+ false
31
+ else
32
+ @x == other_point.x and @y == other_point.y and @z == other_point.z
33
+ end
34
+ end
35
+ #binary representation of a point. It lacks some headers to be a valid EWKB representation.
36
+ def binary_representation(dimension=2)
37
+ if dimension == 2
38
+ [@x,@y].pack("EE")
39
+ else
40
+ [@x,@y,@z || 0].pack("EEE")
41
+ end
42
+ end
43
+ #WKB geometry type of a point
44
+ def binary_geometry_type
45
+ 1
46
+ end
47
+
48
+ #text representation of a point
49
+ def text_representation(dimension=2)
50
+ if dimension == 2
51
+ "#{@x} #{@y}"
52
+ else
53
+ "#{@x} #{@y} #{@z || 0}"
54
+ end
55
+ end
56
+ #WKT geometry type of a point
57
+ def text_geometry_type
58
+ "POINT"
59
+ end
60
+
61
+ #creates a point from an array of coordinates
62
+ def self.from_coordinates(coords,srid=DEFAULT_SRID)
63
+ point= Point::new(srid)
64
+ if coords.length == 2
65
+ point.set_x_y(*coords)
66
+ else
67
+ point.set_x_y_z(*coords)
68
+ end
69
+ point
70
+ end
71
+ #creates a point from the X and Y coordinates
72
+ def self.from_x_y(x,y,srid=DEFAULT_SRID)
73
+ point= Point::new(srid)
74
+ point.set_x_y(x,y)
75
+ point
76
+ end
77
+ #creates a point from the X, Y and Z coordinates
78
+ def self.from_x_y_z(x,y,z,srid=DEFAULT_SRID)
79
+ point= Point::new(srid)
80
+ point.set_x_y_z(x,y,z)
81
+ point
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,103 @@
1
+ require 'geo_ruby/simple_features/geometry'
2
+
3
+ module GeoRuby
4
+ module SimpleFeatures
5
+ #Represents a polygon as an array of linear rings (see LinearRing). No check is performed regarding the validity of the geometries forming the polygon.
6
+ class Polygon < Geometry
7
+ #the list of rings forming the polygon
8
+ attr_reader :rings
9
+
10
+ def initialize(srid = DEFAULT_SRID)
11
+ super(srid)
12
+ @rings = []
13
+ end
14
+ #add one to the polygon
15
+ def <<(ring)
16
+ @rings << ring
17
+ end
18
+ #add one or more rings to the polygon
19
+ def concat(rings)
20
+ @rings.concat rings
21
+ end
22
+ #number of linear rings in the polygon
23
+ def length
24
+ @rings.length
25
+ end
26
+ #access the nth linear ring
27
+ def [](n)
28
+ @rings[n]
29
+ end
30
+ #modifies the value of the nth linear ring
31
+ def []=(n,ring)
32
+ @rings[n]=ring
33
+ end
34
+ #iterates over the linear rings
35
+ def each(&proc)
36
+ @rings.each(&proc)
37
+ end
38
+ #iterates over the linear rings, passing their indices to the bloc
39
+ def each_index(&proc)
40
+ @rings.each_index(&proc)
41
+ end
42
+ #insert linear rings at the nth position
43
+ def insert(n,*ring)
44
+ @rings.insert(n,*ring)
45
+ end
46
+ #index of the linear_ring
47
+ def index(ring)
48
+ @rings.index(ring)
49
+ end
50
+ #remove linear rings. Arguments can be of the same type as Array#slice
51
+ def remove(*slice)
52
+ @rings.slice(*slice)
53
+ end
54
+ #tests for other equality. The SRID is not taken into account.
55
+ def ==(other_polygon)
56
+ if other_polygon.class != self.class or
57
+ length != other_polygon.length
58
+ false
59
+ else
60
+ index=0
61
+ while index<length
62
+ return false if self[index] != other_polygon[index]
63
+ index+=1
64
+ end
65
+ true
66
+ end
67
+ end
68
+ #binary representation of a polygon, without the headers neccessary for a valid WKB string
69
+ def binary_representation(dimension=2)
70
+ rep = [length].pack("V")
71
+ each {|linear_ring| rep << linear_ring.binary_representation(dimension) }
72
+ rep
73
+ end
74
+ #WKB geometry type
75
+ def binary_geometry_type
76
+ 3
77
+ end
78
+ #Text representation of a polygon
79
+ def text_representation(dimension=2)
80
+ @rings.collect{|line_string| "(" + line_string.text_representation(dimension) + ")" }.join(",")
81
+ end
82
+ #WKT geometry type
83
+ def text_geometry_type
84
+ "POLYGON"
85
+ end
86
+ #creates a new polygon. Accepts an array of linear strings as argument
87
+ def self.from_linear_rings(linear_rings,srid = DEFAULT_SRID)
88
+ polygon = Polygon::new(srid)
89
+ polygon.concat(linear_rings)
90
+ polygon
91
+ end
92
+
93
+ #creates a new polygon. Accepts a sequence of points as argument : ((x,y)....(x,y)),((x,y).....(x,y))
94
+ def self.from_raw_point_sequences(point_sequences,srid=DEFAULT_SRID)
95
+ polygon = Polygon::new(srid)
96
+ polygon.concat( point_sequences.collect {|point_sequence| LinearRing.from_raw_point_sequence(point_sequence,srid) } )
97
+ polygon
98
+ end
99
+
100
+
101
+ end
102
+ end
103
+ end
data/lib/geo_ruby.rb ADDED
@@ -0,0 +1,12 @@
1
+ require 'geo_ruby/simple_features/geometry'
2
+ require 'geo_ruby/simple_features/point'
3
+ require 'geo_ruby/simple_features/line_string'
4
+ require 'geo_ruby/simple_features/linear_ring'
5
+ require 'geo_ruby/simple_features/polygon'
6
+ require 'geo_ruby/simple_features/multi_point'
7
+ require 'geo_ruby/simple_features/multi_line_string'
8
+ require 'geo_ruby/simple_features/multi_polygon'
9
+ require 'geo_ruby/simple_features/geometry_collection'
10
+ require 'geo_ruby/simple_features/ewkb_parser'
11
+ require 'geo_ruby/simple_features/geometry_factory'
12
+
data/rakefile.rb ADDED
@@ -0,0 +1,50 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ require 'rake/gempackagetask'
5
+
6
+ task :default => :test
7
+
8
+ desc "Run the tests"
9
+ Rake::TestTask::new do |t|
10
+ t.test_files = FileList['test/test*.rb']
11
+ t.verbose = true
12
+ end
13
+
14
+ desc "Generate the documentation"
15
+ Rake::RDocTask::new do |rdoc|
16
+ rdoc.rdoc_dir = 'doc/'
17
+ rdoc.title = "GeoRuby Documentation"
18
+ rdoc.options << '--line-numbers' << '--inline-source'
19
+ rdoc.rdoc_files.include('README')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ spec = Gem::Specification::new do |s|
24
+ s.platform = Gem::Platform::RUBY
25
+
26
+ s.name = 'GeoRuby'
27
+ s.version = "0.0.1"
28
+ s.summary = "Ruby data holder for OGC Simple Features"
29
+ s.description = <<EOF
30
+ GeoRuby is intended as a holder for data returned from PostGIS queries. Therefore, the data model roughly follows the OGC "Simple Features for SQL" specification (see www.opengis.org/docs/99-049.pdf), although without any kind of advanced functionalities (such as geometric operators or reprojections)
31
+ EOF
32
+ s.author = 'Guilhem Vellut'
33
+ s.email = 'guilhem.vellut+georuby@gmail.com'
34
+ s.homepage = "http://thepochisuperstarmegashow.com"
35
+
36
+ s.requirements << 'none'
37
+ s.require_path = 'lib'
38
+ s.files = FileList["lib/**/*.rb", "test/**/*.rb", "README","MIT-LICENSE","rakefile.rb"]
39
+ s.test_files = FileList['test/test*.rb']
40
+
41
+ s.has_rdoc = true
42
+ s.extra_rdoc_files = ["README"]
43
+ s.rdoc_options.concat ['--main', 'README']
44
+ end
45
+
46
+ desc "Package the library as a gem"
47
+ Rake::GemPackageTask.new(spec) do |pkg|
48
+ pkg.need_zip = true
49
+ pkg.need_tar = true
50
+ end
@@ -0,0 +1,91 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
2
+
3
+ require 'geo_ruby'
4
+ require 'test/unit'
5
+
6
+ include GeoRuby::SimpleFeatures
7
+
8
+ class TestEWKBParser < Test::Unit::TestCase
9
+
10
+ def setup
11
+ @factory = GeometryFactory::new
12
+ @hex_ewkb_parser = HexEWKBParser::new(@factory)
13
+ end
14
+
15
+ def test_point2d
16
+ @hex_ewkb_parser.parse("01010000207B000000CDCCCCCCCCCC28406666666666A64640")
17
+ point = @factory.geometry
18
+ assert(point.instance_of?(Point))
19
+ assert_equal(Point.from_x_y(12.4,45.3,123),point)
20
+ end
21
+
22
+ def test_point3d
23
+ @hex_ewkb_parser.parse("01010000A07B000000CDCCCCCCCCCC28406666666666A646400000000000000CC0")
24
+ point = @factory.geometry
25
+ assert(point.instance_of?(Point))
26
+ assert_equal(Point.from_x_y_z(12.4,45.3,-3.5,123),point)
27
+ end
28
+
29
+ def test_line_string
30
+ @hex_ewkb_parser.parse("01020000200001000002000000CDCCCCCCCCCC28406666666666A646C03333333333B34640CDCCCCCCCCCC4440")
31
+ line_string = @factory.geometry
32
+ assert(line_string.instance_of?(LineString))
33
+ assert_equal(LineString.from_raw_point_sequence([[12.4,-45.3],[45.4,41.6]],256),line_string)
34
+ end
35
+
36
+ def test_polygon
37
+ @hex_ewkb_parser.parse("0103000020000100000200000005000000000000000000000000000000000000000000000000001040000000000000000000000000000010400000000000001040000000000000000000000000000010400000000000000000000000000000000005000000000000000000F03F000000000000F03F0000000000000840000000000000F03F00000000000008400000000000000840000000000000F03F0000000000000840000000000000F03F000000000000F03F")
38
+ polygon = @factory.geometry
39
+ assert(polygon.instance_of?(Polygon))
40
+ assert_equal(Polygon.from_raw_point_sequences([[[0,0],[4,0],[4,4],[0,4],[0,0]],[[1,1],[3,1],[3,3],[1,3],[1,1]]],256),polygon)
41
+ end
42
+
43
+ def test_geometry_collection
44
+ @hex_ewkb_parser.parse("010700002000010000020000000101000000AE47E17A14AE12403333333333B34640010200000002000000CDCCCCCCCCCC16406666666666E628403333333333E350400000000000004B40")
45
+ geometry_collection = @factory.geometry
46
+ assert(geometry_collection.instance_of?(GeometryCollection))
47
+ assert_equal(GeometryCollection.from_geometries([Point.from_x_y(4.67,45.4,256),LineString.from_raw_point_sequence([[5.7,12.45],[67.55,54]],256)],256),geometry_collection)
48
+ assert_equal(256,geometry_collection[0].srid)
49
+ end
50
+
51
+ def test_multi_point
52
+ @hex_ewkb_parser.parse("0104000020BC010000030000000101000000CDCCCCCCCCCC28403333333333D35EC0010100000066666666664650C09A99999999D95E4001010000001F97DD388EE35E400000000000C05E40")
53
+ multi_point = @factory.geometry
54
+ assert(multi_point.instance_of?(MultiPoint))
55
+ assert_equal(MultiPoint.from_raw_point_sequence([[12.4,-123.3],[-65.1,123.4],[123.55555555,123]],444),multi_point)
56
+ assert_equal(444,multi_point.srid)
57
+ assert_equal(444,multi_point[0].srid)
58
+ end
59
+
60
+ def test_multi_line_string
61
+ @hex_ewkb_parser.parse("01050000200001000002000000010200000002000000000000000000F83F9A99999999994640E4BD6A65C20F4BC0FA7E6ABC749388BF010200000003000000000000000000F83F9A99999999994640E4BD6A65C20F4BC0FA7E6ABC749388BF39B4C876BE8F46403333333333D35E40")
62
+ multi_line_string = @factory.geometry
63
+ assert(multi_line_string.instance_of?(MultiLineString))
64
+ assert_equal(MultiLineString.from_line_strings([LineString.from_raw_point_sequence([[1.5,45.2],[-54.12312,-0.012]],256),LineString.from_raw_point_sequence([[1.5,45.2],[-54.12312,-0.012],[45.123,123.3]],256)],256),multi_line_string)
65
+ assert_equal(256,multi_line_string.srid)
66
+ assert_equal(256,multi_line_string[0].srid)
67
+ end
68
+
69
+ def test_multi_polygon
70
+ @hex_ewkb_parser.parse("0106000020000100000200000001030000000200000004000000CDCCCCCCCCCC28406666666666A646C03333333333B34640CDCCCCCCCCCC44406DE7FBA9F1D211403D2CD49AE61DF13FCDCCCCCCCCCC28406666666666A646C004000000333333333333034033333333333315409A999999999915408A8EE4F21FD2F63FEC51B81E85EB2C40F6285C8FC2F5F03F3333333333330340333333333333154001030000000200000005000000000000000000000000000000000000000000000000001040000000000000000000000000000010400000000000001040000000000000000000000000000010400000000000000000000000000000000005000000000000000000F03F000000000000F03F0000000000000840000000000000F03F00000000000008400000000000000840000000000000F03F0000000000000840000000000000F03F000000000000F03F")
71
+ multi_polygon = @factory.geometry
72
+ assert(multi_polygon.instance_of?(MultiPolygon))
73
+ assert_equal(MultiPolygon.from_polygons([Polygon.from_raw_point_sequences([[[12.4,-45.3],[45.4,41.6],[4.456,1.0698],[12.4,-45.3]],[[2.4,5.3],[5.4,1.4263],[14.46,1.06],[2.4,5.3]]],256),Polygon.from_raw_point_sequences([[[0,0],[4,0],[4,4],[0,4],[0,0]],[[1,1],[3,1],[3,3],[1,3],[1,1]]],256)],256),multi_polygon)
74
+ assert_equal(256,multi_polygon.srid)
75
+ assert_equal(256,multi_polygon[0].srid)
76
+ end
77
+ def test_failure_trailing_data
78
+ #added A345 at the end
79
+ assert_raise(StandardError){@hex_ewkb_parser.parse("01010000207B000000CDCCCCCCCCCC28406666666666A64640A345")}
80
+ end
81
+ def test_failure_unknown_geometry_type
82
+ assert_raise(StandardError){@hex_ewkb_parser.parse("01090000207B000000CDCCCCCCCCCC28406666666666A64640")}
83
+ end
84
+ def test_failure_m
85
+ assert_raise(StandardError){@hex_ewkb_parser.parse("01010000607B000000CDCCCCCCCCCC28406666666666A64640")}
86
+ end
87
+ def test_failure_truncated_data
88
+ assert_raise(StandardError){@hex_ewkb_parser.parse("01010000207B000000CDCCCCCCCCCC2840666666")}
89
+ end
90
+
91
+ end