esri_shapefile 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +22 -0
  3. data/README.md +51 -0
  4. data/Rakefile +2 -0
  5. data/lib/esri_shapefile/byte_model/field.rb +48 -0
  6. data/lib/esri_shapefile/byte_model.rb +43 -0
  7. data/lib/esri_shapefile/models/main_file_header.rb +47 -0
  8. data/lib/esri_shapefile/models/record_header.rb +28 -0
  9. data/lib/esri_shapefile/models/shapes/multi_patch.rb +33 -0
  10. data/lib/esri_shapefile/models/shapes/multi_point.rb +21 -0
  11. data/lib/esri_shapefile/models/shapes/multi_point_m.rb +25 -0
  12. data/lib/esri_shapefile/models/shapes/multi_point_z.rb +29 -0
  13. data/lib/esri_shapefile/models/shapes/null.rb +19 -0
  14. data/lib/esri_shapefile/models/shapes/point.rb +19 -0
  15. data/lib/esri_shapefile/models/shapes/point_m.rb +20 -0
  16. data/lib/esri_shapefile/models/shapes/point_z.rb +21 -0
  17. data/lib/esri_shapefile/models/shapes/poly_line.rb +43 -0
  18. data/lib/esri_shapefile/models/shapes/poly_line_m.rb +50 -0
  19. data/lib/esri_shapefile/models/shapes/poly_line_z.rb +63 -0
  20. data/lib/esri_shapefile/models/shapes/polygon.rb +38 -0
  21. data/lib/esri_shapefile/models/shapes/polygon_m.rb +52 -0
  22. data/lib/esri_shapefile/models/shapes/polygon_z.rb +65 -0
  23. data/lib/esri_shapefile/models/shapes.rb +33 -0
  24. data/lib/esri_shapefile/reader.rb +44 -0
  25. data/lib/esri_shapefile/version.rb +3 -0
  26. data/lib/esri_shapefile.rb +29 -0
  27. data/spec/esri_shapefile/field_spec.rb +95 -0
  28. data/spec/esri_shapefile/model_spec.rb +26 -0
  29. data/spec/esri_shapefile/models/main_file_header_spec.rb +72 -0
  30. data/spec/esri_shapefile/models/record_header_spec.rb +26 -0
  31. data/spec/esri_shapefile/models/shapes/point_spec.rb +24 -0
  32. data/spec/spec_helper.rb +105 -0
  33. metadata +123 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1eea7f296a0ef93cc09b8fe87fa30a3c01c67e61
4
+ data.tar.gz: 5f2f82a3facd9330fde2125598c443c529103551
5
+ SHA512:
6
+ metadata.gz: a5e5a80ef2d2665e3f608229da92f49ae671d29dc74f2e9b222fb9eacb48f93eddcfd5b4edda8c4e9ff3328d013590fee16bc2bd2a09cf6b4dc0b5e8db308108
7
+ data.tar.gz: 53354693c75d1f5f68c040462b343456d598eae0bbcd603373a1a0f20c3c6b2c29b89a9a8a8f1cfb29a4bbd1bbdb4823730cbd25c4cb413e393cc39a5d3a3848
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2016 Joe Karayusuf
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # EsriShapefile
2
+
3
+ Ruby library to read an [ESRI Shapefile](https://www.esri.com/library/whitepapers/pdfs/shapefile.pdf)
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'esri_shapefile'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install esri_shapefile
20
+
21
+ ## Usage
22
+
23
+ ### Read the header of a shapefile
24
+
25
+ ```ruby
26
+ require 'esri_shapefile'
27
+ reader = EsriShapefile::Reader.new("/path/to/shapefile")
28
+ reader.main_file_header # => Instance of EsriShapefile::MainFileHeader
29
+ ```
30
+
31
+ ### Read all of the records in a shapefile
32
+
33
+ Supported shapes can be found [here](lib/esri_shapefile/models/shapes)
34
+
35
+ ```ruby
36
+ require 'esri_shapefile'
37
+ reader = EsriShapefile::Reader.new("path/to/shapefile")
38
+ reader.each_record do |header, shape|
39
+ # Iterate over each record with access to the header and shape.
40
+ # The header will be an instance of the EsriShapefile::RecordHeader class.
41
+ # The shape will be one of the shape models found in the models/shapes directory. Example: EsriShapefile::Shapes::Polygon
42
+ end
43
+ ```
44
+
45
+ ## Contributing
46
+
47
+ 1. Fork it ( https://github.com/karayusuf/esri_shapefile/fork )
48
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
49
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
50
+ 4. Push to the branch (`git push origin my-new-feature`)
51
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,48 @@
1
+ module EsriShapefile
2
+ module ByteModel
3
+ class Field
4
+ attr_reader :name, :position, :type, :byte_order, :number
5
+
6
+ TYPES = {
7
+ integer: { bytesize: 4, unpack: { big: 'l>', little: 'l<' } },
8
+ double: { bytesize: 8, unpack: { big: 'G', little: 'E' } },
9
+ point: { bytesize: 16, unpack: { big: 'G', little: 'E', multiplier: 2 } },
10
+ }
11
+
12
+ def initialize(name, position:, type:, byte_order:, number: nil)
13
+ @name = name
14
+ @position = position
15
+ @type = type
16
+ @number = number
17
+ @byte_order = byte_order
18
+ end
19
+
20
+ def list?
21
+ !@number.nil?
22
+ end
23
+
24
+ def number
25
+ @number.nil? ? 1 : @number
26
+ end
27
+
28
+ def number_depends_on_field?
29
+ @number.is_a?(Symbol)
30
+ end
31
+
32
+ def unused?
33
+ name == :unused
34
+ end
35
+
36
+ def bytesize
37
+ TYPES[@type][:bytesize]
38
+ end
39
+
40
+ def unpack_format(values = {})
41
+ number_of_consecutive_values = number_depends_on_field? ? values[number] : number
42
+ multiplier = TYPES[@type][:unpack][:multiplier] || 1
43
+ unpack_format = TYPES[@type][:unpack][@byte_order]
44
+ "#{unpack_format}#{number_of_consecutive_values * multiplier}"
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,43 @@
1
+ module EsriShapefile
2
+ module ByteModel
3
+
4
+ def field(name, number: nil, position:, type:, byte_order:)
5
+ attr_accessor name unless name == :unused
6
+ fields << Field.new(name, position: position, type: type, byte_order: byte_order, number: number)
7
+ end
8
+
9
+ def fields
10
+ @fields ||= []
11
+ end
12
+
13
+ def from_bytes(bytes)
14
+ field_values = {}
15
+ fields.reduce(0) do |offset, field|
16
+ if !field.unused?
17
+ unpack_format = field.unpack_format(field_values)
18
+ field_value = bytes.unpack("@#{offset}#{unpack_format}")
19
+
20
+ if field.type == :point
21
+ field_value = field_value.each_slice(2).map do |x, y|
22
+ point = Shapes::Point.new
23
+ point.x = x
24
+ point.y = y
25
+ point
26
+ end
27
+ end
28
+
29
+ field_values[field.name] = field.list? ? field_value : field_value.first
30
+ end
31
+
32
+ offset += field.bytesize
33
+ (offset < bytes.size) ? offset : break
34
+ end
35
+
36
+ field_values.reduce(self.new) do |model, (field, value)|
37
+ model.send("#{field}=", value)
38
+ model
39
+ end
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,47 @@
1
+ require 'esri_shapefile/byte_model'
2
+
3
+ module EsriShapefile
4
+ #
5
+ # The main file header is 100 bytes long. The fields in the file header are
6
+ # listed below with their byte position, type, and byte order. Position is
7
+ # with respect to the start of the file.
8
+ #
9
+ class MainFileHeader
10
+ extend EsriShapefile::ByteModel
11
+
12
+ field :file_code, position: 0, type: :integer, byte_order: :big
13
+ field :unused, position: 4, type: :integer, byte_order: :big
14
+ field :unused, position: 8, type: :integer, byte_order: :big
15
+ field :unused, position: 12, type: :integer, byte_order: :big
16
+ field :unused, position: 16, type: :integer, byte_order: :big
17
+ field :unused, position: 20, type: :integer, byte_order: :big
18
+
19
+ field :file_length, position: 24, type: :integer, byte_order: :big
20
+ field :version, position: 28, type: :integer, byte_order: :little
21
+ field :shape_type, position: 32, type: :integer, byte_order: :little
22
+
23
+ field :x_min, position: 36, type: :double, byte_order: :little
24
+ field :y_min, position: 44, type: :double, byte_order: :little
25
+ field :x_max, position: 52, type: :double, byte_order: :little
26
+ field :y_max, position: 60, type: :double, byte_order: :little
27
+
28
+ field :z_min, position: 68, type: :double, byte_order: :little
29
+ field :z_max, position: 76, type: :double, byte_order: :little
30
+ field :m_min, position: 84, type: :double, byte_order: :little
31
+ field :m_max, position: 92, type: :double, byte_order: :little
32
+
33
+ # The value for file length is the total length of the file in 16-bit words
34
+ # (including the fifty 16-bit words that make up the header). This means
35
+ # that we need to multiply the value by 2 in order to know the size of the
36
+ # file in bytes
37
+ def file_length_bytes
38
+ file_length * 2
39
+ end
40
+
41
+ def shape
42
+ Shapes.from_type(shape_type)
43
+ end
44
+
45
+ end
46
+ end
47
+
@@ -0,0 +1,28 @@
1
+ require 'esri_shapefile/byte_model'
2
+
3
+ module EsriShapefile
4
+ #
5
+ # The header for each record stores the record number and content length for
6
+ # the record. Record headers have a fixed length of 8 bytes. The list of
7
+ # fields shows the fields in the record header with their byte position, type,
8
+ # and byte order. The field position is with respect to the start of the
9
+ # record.
10
+ #
11
+ class RecordHeader
12
+ extend EsriShapefile::ByteModel
13
+
14
+ # Record numbers begin at 1.
15
+ field :record_number, position: 0, type: :integer, byte_order: :big
16
+
17
+ # The content length for a record is the length of the record contents
18
+ # section measured in 16-bit words. Each record, therefore, contributes (4 +
19
+ # content_length) 16-bit words toward the total length of the file, as
20
+ # stored as Byte 24 in the file header.
21
+ field :content_length, position: 4, type: :integer, byte_order: :big
22
+
23
+ def content_length_bytes
24
+ content_length * 2
25
+ end
26
+ end
27
+ end
28
+
@@ -0,0 +1,33 @@
1
+ require 'esri_shapefile/byte_model'
2
+
3
+ module EsriShapefile
4
+ module Shapes
5
+ #
6
+ #
7
+ #
8
+ class MultiPatch
9
+ extend EsriShapefile::ByteModel
10
+
11
+ field :shape_type, position: 0, type: :integer, byte_order: :little
12
+ field :x_min, position: 4, type: :double, byte_order: :little
13
+ field :y_min, position: 12, type: :double, byte_order: :little
14
+ field :x_max, position: 20, type: :double, byte_order: :little
15
+ field :y_max, position: 28, type: :double, byte_order: :little
16
+
17
+ field :num_parts, position: 36, type: :integer, byte_order: :little
18
+ field :num_points, position: 40, type: :integer, byte_order: :little
19
+ field :parts, position: 44, type: :integer, byte_order: :little, number: :num_parts
20
+ field :part_types, position: :w, type: :integer, byte_order: :little, number: :num_parts
21
+ field :points, position: :x, type: :point, byte_order: :little, number: :num_points
22
+
23
+ field :z_min, position: :x, type: :double, byte_order: :little
24
+ field :z_max, position: :x_plus_8, type: :double, byte_order: :little
25
+ field :z_array, position: :x_plus_16, type: :double, byte_order: :little, number: :num_points
26
+
27
+ field :m_min, position: :y, type: :double, byte_order: :little
28
+ field :m_max, position: :y_plus_8, type: :double, byte_order: :little
29
+ field :m_array, position: :y_plus_16, type: :double, byte_order: :little, number: :num_points
30
+ end
31
+ end
32
+ end
33
+
@@ -0,0 +1,21 @@
1
+ require 'esri_shapefile/byte_model'
2
+
3
+ module EsriShapefile
4
+ module Shapes
5
+ #
6
+ # A MultiPoint represents a set of points.
7
+ #
8
+ class MultiPoint
9
+ extend EsriShapefile::ByteModel
10
+
11
+ field :shape_type, position: 0, type: :integer, byte_order: :little
12
+ field :x_min, position: 4, type: :double, byte_order: :little
13
+ field :y_min, position: 12, type: :double, byte_order: :little
14
+ field :x_max, position: 20, type: :double, byte_order: :little
15
+ field :y_max, position: 28, type: :double, byte_order: :little
16
+ field :num_points, position: 36, type: :integer, byte_order: :little
17
+ field :points, position: 40, type: :point, byte_order: :little, number: :num_points
18
+ end
19
+ end
20
+ end
21
+
@@ -0,0 +1,25 @@
1
+ require 'esri_shapefile/byte_model'
2
+
3
+ module EsriShapefile
4
+ module Shapes
5
+ #
6
+ # A MultiPoint represents a set of points.
7
+ #
8
+ class MultiPointM
9
+ extend EsriShapefile::ByteModel
10
+
11
+ field :shape_type, position: 0, type: :integer, byte_order: :little
12
+ field :x_min, position: 4, type: :double, byte_order: :little
13
+ field :y_min, position: 12, type: :double, byte_order: :little
14
+ field :x_max, position: 20, type: :double, byte_order: :little
15
+ field :y_max, position: 28, type: :double, byte_order: :little
16
+ field :num_points, position: 36, type: :integer, byte_order: :little
17
+ field :points, position: 40, type: :point, byte_order: :little, number: :num_points
18
+
19
+ field :m_min, position: :x, type: :double, byte_order: :little
20
+ field :m_max, position: :x_plus_8, type: :double, byte_order: :little
21
+ field :m_array, position: :x_plus_16, type: :double, byte_order: :little, number: :num_points
22
+ end
23
+ end
24
+ end
25
+
@@ -0,0 +1,29 @@
1
+ require 'esri_shapefile/byte_model'
2
+
3
+ module EsriShapefile
4
+ module Shapes
5
+ #
6
+ # A MultiPoint represents a set of points.
7
+ #
8
+ class MultiPointZ
9
+ extend EsriShapefile::ByteModel
10
+
11
+ field :shape_type, position: 0, type: :integer, byte_order: :little
12
+ field :x_min, position: 4, type: :double, byte_order: :little
13
+ field :y_min, position: 12, type: :double, byte_order: :little
14
+ field :x_max, position: 20, type: :double, byte_order: :little
15
+ field :y_max, position: 28, type: :double, byte_order: :little
16
+ field :num_points, position: 36, type: :integer, byte_order: :little
17
+ field :points, position: 40, type: :point, byte_order: :little, number: :num_points
18
+
19
+ field :z_min, position: :x, type: :double, byte_order: :little
20
+ field :z_max, position: :x_plus_8, type: :double, byte_order: :little
21
+ field :z_array, position: :x_plus_16, type: :double, byte_order: :little, number: :num_points
22
+
23
+ field :m_min, position: :y, type: :double, byte_order: :little
24
+ field :m_max, position: :y_plus_8, type: :double, byte_order: :little
25
+ field :m_array, position: :y_plus_16, type: :double, byte_order: :little, number: :num_points
26
+ end
27
+ end
28
+ end
29
+
@@ -0,0 +1,19 @@
1
+ require 'esri_shapefile/byte_model'
2
+
3
+ module EsriShapefile
4
+ module Shapes
5
+ #
6
+ # A shape type of 0 indicates a null shape, with no geometric data for the
7
+ # shape. Each feature type (point, lie, polygon, etc.) supports nulls - it
8
+ # is valid to have points and null points in the same shapefile. Often null
9
+ # shapes are place holders; they are used during shapefile creation and are
10
+ # populated with geometric data soon after they are created.
11
+ #
12
+ class Null
13
+ extend EsriShapefile::ByteModel
14
+
15
+ field :shape_type, position: 0, type: :integer, byte_order: :little
16
+ end
17
+ end
18
+ end
19
+
@@ -0,0 +1,19 @@
1
+ require 'esri_shapefile/byte_model'
2
+
3
+ module EsriShapefile
4
+ module Shapes
5
+ #
6
+ # A point consists of a pair of double-precision coordinates
7
+ # in the order X,Y.
8
+ #
9
+ class Point
10
+ extend EsriShapefile::ByteModel
11
+
12
+ field :shape_type, position: 0, type: :integer, byte_order: :little
13
+ field :x, position: 4, type: :double, byte_order: :little
14
+ field :y, position: 12, type: :double, byte_order: :little
15
+
16
+ end
17
+ end
18
+ end
19
+
@@ -0,0 +1,20 @@
1
+ require 'esri_shapefile/byte_model'
2
+
3
+ module EsriShapefile
4
+ module Shapes
5
+ #
6
+ # A point consists of a pair of double-precision coordinates
7
+ # in the order X,Y,Z plus a measure.
8
+ #
9
+ class PointM
10
+ extend EsriShapefile::ByteModel
11
+
12
+ field :shape_type, position: 0, type: :integer, byte_order: :little
13
+ field :x, position: 4, type: :double, byte_order: :little
14
+ field :y, position: 12, type: :double, byte_order: :little
15
+ field :measure, position: 28, type: :double, byte_order: :little
16
+
17
+ end
18
+ end
19
+ end
20
+
@@ -0,0 +1,21 @@
1
+ require 'esri_shapefile/byte_model'
2
+
3
+ module EsriShapefile
4
+ module Shapes
5
+ #
6
+ # A point consists of a pair of double-precision coordinates
7
+ # in the order X,Y,Z plus a measure.
8
+ #
9
+ class PointZ
10
+ extend EsriShapefile::ByteModel
11
+
12
+ field :shape_type, position: 0, type: :integer, byte_order: :little
13
+ field :x, position: 4, type: :double, byte_order: :little
14
+ field :y, position: 12, type: :double, byte_order: :little
15
+ field :z, position: 20, type: :double, byte_order: :little
16
+ field :measure, position: 28, type: :double, byte_order: :little
17
+
18
+ end
19
+ end
20
+ end
21
+
@@ -0,0 +1,43 @@
1
+ require 'esri_shapefile/byte_model'
2
+
3
+ module EsriShapefile
4
+ module Shapes
5
+ #
6
+ # A PolyLine is an ordered set of vertices that consists of one or more
7
+ # parts. A part is a connected sequence of two or more points. Parts may or
8
+ # may not be connected to one another. Parts may or may not intersect one
9
+ # another.
10
+ #
11
+ # Because this specification does not forbid consecutive points with
12
+ # identical coordinates, shapefile readers must handle such cases. On the
13
+ # other hand, the degenerate, zero length parts that might result are not
14
+ # allowed.
15
+ #
16
+ class PolyLine
17
+ extend EsriShapefile::ByteModel
18
+
19
+ field :shape_type, position: 0, type: :integer, byte_order: :little
20
+ field :x_min, position: 4, type: :double, byte_order: :little
21
+ field :y_min, position: 12, type: :double, byte_order: :little
22
+ field :x_max, position: 20, type: :double, byte_order: :little
23
+ field :y_max, position: 28, type: :double, byte_order: :little
24
+
25
+ # The number of parts in the PolyLine
26
+ field :num_parts, position: 36, type: :integer, byte_order: :little
27
+
28
+ # The total number of points for all parts.
29
+ field :num_points, position: 40, type: :integer, byte_order: :little
30
+
31
+ # An array of length num_parts. Stores, for each PolyLine, the index of
32
+ # its first point in the points array. Array indexes are with respect to 0.
33
+ field :parts, position: 44, type: :integer, byte_order: :little, number: :num_parts
34
+
35
+ # An array of length NumPoints. The points for each part in the PolyLine
36
+ # are stored end to end. The points for Part 2 follow the points for
37
+ # Part 1, and so on. The parts array holds the array index of the starting
38
+ # point for each part. There is no delimiter in the points array between parts.
39
+ field :points, position: :x, type: :point, byte_order: :little, number: :num_points
40
+ end
41
+ end
42
+ end
43
+
@@ -0,0 +1,50 @@
1
+ require 'esri_shapefile/byte_model'
2
+
3
+ module EsriShapefile
4
+ module Shapes
5
+ #
6
+ # A PolyLineM consists of one or more parts. A part is a connected sequence
7
+ # of two or more points. Parts may or may not be connected to one another.
8
+ # Parts may or may not intersect one another.
9
+ #
10
+ class PolyLineM
11
+ extend EsriShapefile::ByteModel
12
+
13
+ field :shape_type, position: 0, type: :integer, byte_order: :little
14
+ field :x_min, position: 4, type: :double, byte_order: :little
15
+ field :y_min, position: 12, type: :double, byte_order: :little
16
+ field :x_max, position: 20, type: :double, byte_order: :little
17
+ field :y_max, position: 28, type: :double, byte_order: :little
18
+
19
+ # The number of parts in the PolyLine
20
+ field :num_parts, position: 36, type: :integer, byte_order: :little
21
+
22
+ # The total number of points for all parts.
23
+ field :num_points, position: 40, type: :integer, byte_order: :little
24
+
25
+ # An array of length num_parts. Stores, for each PolyLine, the index of
26
+ # its first point in the points array. Array indexes are with respect to 0.
27
+ field :parts, position: 44, type: :integer, byte_order: :little, number: :num_parts
28
+
29
+ # An array of length NumPoints. The points for each part in the PolyLine
30
+ # are stored end to end. The points for Part 2 follow the points for
31
+ # Part 1, and so on. The parts array holds the array index of the starting
32
+ # point for each part. There is no delimiter in the points array between parts.
33
+ field :points, position: :x, type: :point, byte_order: :little, number: :num_points
34
+
35
+ # The minimum measure for the PolyLineZ
36
+ field :m_min, position: :z, type: :double, byte_order: :little
37
+
38
+ # The maximum measure for the PolyLineZ
39
+ field :m_max, position: :z_plus_8, type: :double, byte_order: :little
40
+
41
+ # An array of length num_points. The measures for each part in the
42
+ # PolyLineZ are stored end to end. The measures for Part 2 follow the
43
+ # measures for Part 1, and so on. The parts array holds the array index of
44
+ # the starting measure for each part. There is no delimited in the measure
45
+ # array between parts.
46
+ field :m_array, position: :z_plus_16, type: :double, byte_order: :little, number: :num_points
47
+ end
48
+ end
49
+ end
50
+
@@ -0,0 +1,63 @@
1
+ require 'esri_shapefile/byte_model'
2
+
3
+ module EsriShapefile
4
+ module Shapes
5
+ #
6
+ # A PolyLineZ consists of one or more parts. A part is a connected sequence
7
+ # of two or more points. Parts may or may not be connected to one another.
8
+ # Parts may or may not intersect one another.
9
+ #
10
+ class PolyLineZ
11
+ extend EsriShapefile::ByteModel
12
+
13
+ field :shape_type, position: 0, type: :integer, byte_order: :little
14
+ field :x_min, position: 4, type: :double, byte_order: :little
15
+ field :y_min, position: 12, type: :double, byte_order: :little
16
+ field :x_max, position: 20, type: :double, byte_order: :little
17
+ field :y_max, position: 28, type: :double, byte_order: :little
18
+
19
+ # The number of parts in the PolyLine
20
+ field :num_parts, position: 36, type: :integer, byte_order: :little
21
+
22
+ # The total number of points for all parts.
23
+ field :num_points, position: 40, type: :integer, byte_order: :little
24
+
25
+ # An array of length num_parts. Stores, for each PolyLine, the index of
26
+ # its first point in the points array. Array indexes are with respect to 0.
27
+ field :parts, position: 44, type: :integer, byte_order: :little, number: :num_parts
28
+
29
+ # An array of length NumPoints. The points for each part in the PolyLine
30
+ # are stored end to end. The points for Part 2 follow the points for
31
+ # Part 1, and so on. The parts array holds the array index of the starting
32
+ # point for each part. There is no delimiter in the points array between parts.
33
+ field :points, position: :x, type: :point, byte_order: :little, number: :num_points
34
+
35
+ # The minimum Z value for the PolyLineZ
36
+ field :z_min, position: :y, type: :double, byte_order: :little
37
+
38
+ # The maximum Z value for the PoliyLineZ
39
+ field :z_max, position: :y_plus_8, type: :double, byte_order: :little
40
+
41
+ # An array of length num_points. the Z values for each part in the
42
+ # PolyLineZ are stored end to end. The Z values for Part 2 follow the Z
43
+ # values for Part 1, and so on. The parts array holds the array index of
44
+ # the starting point for each part. There is no delimited in the Z array
45
+ # between parts.
46
+ field :z_array, position: :y_plus_16, type: :double, byte_order: :little, number: :num_points
47
+
48
+ # The minimum measure for the PolyLineZ
49
+ field :m_min, position: :z, type: :double, byte_order: :little
50
+
51
+ # The maximum measure for the PolyLineZ
52
+ field :m_max, position: :z_plus_8, type: :double, byte_order: :little
53
+
54
+ # An array of length num_points. The measures for each part in the
55
+ # PolyLineZ are stored end to end. The measures for Part 2 follow the
56
+ # measures for Part 1, and so on. The parts array holds the array index of
57
+ # the starting measure for each part. There is no delimited in the measure
58
+ # array between parts.
59
+ field :m_array, position: :z_plus_16, type: :double, byte_order: :little, number: :num_points
60
+ end
61
+ end
62
+ end
63
+
@@ -0,0 +1,38 @@
1
+ require 'esri_shapefile/byte_model'
2
+
3
+ module EsriShapefile
4
+ module Shapes
5
+ #
6
+ # A polygon consists of one or more rings. A ring is a connected sequence of
7
+ # four or more points that form a closed, non-self-intersecting loop. A
8
+ # polygon may contain multiple outer rings. The order of vertices or
9
+ # orientation for a ring indicates which side of the ring is the interior of
10
+ # the polygon. The neighborhood to the right of an observer walking along
11
+ # the ring in vertex order is the neighborhood inside the polygon. Vertices
12
+ # of rings defining holes in polygons are in counterclockwise direction.
13
+ # Vertices for a single, ringed polygon are, therefore, always in clockwise
14
+ # order. The rings of a polygon are referred to as its parts.
15
+ #
16
+ # Because this specification does not forbid consecutive points with
17
+ # identical coordinates, shapefile readers must handle such cases. On the
18
+ # other hand, the degenerate, zero length or zero area parts that might
19
+ # result are not allowed.
20
+ #
21
+ # The Polygon structure is identical to the PolyLine structure.
22
+ #
23
+ class Polygon
24
+ extend EsriShapefile::ByteModel
25
+
26
+ field :shape_type, position: 0, type: :integer, byte_order: :little
27
+ field :x_min, position: 4, type: :double, byte_order: :little
28
+ field :y_min, position: 12, type: :double, byte_order: :little
29
+ field :x_max, position: 20, type: :double, byte_order: :little
30
+ field :y_max, position: 28, type: :double, byte_order: :little
31
+ field :num_parts, position: 36, type: :integer, byte_order: :little
32
+ field :num_points, position: 40, type: :integer, byte_order: :little
33
+ field :parts, position: 44, type: :integer, byte_order: :little, number: :num_parts
34
+ field :points, position: :x, type: :point, byte_order: :little, number: :num_points
35
+ end
36
+ end
37
+ end
38
+