module Turf
Ruby port of Turf.js, an advance geospatial analysis library. @see turfjs.org/
Constants
- AREA_RADIUS
- EARTH_RADIUS
- FACTORS
- VERSION
Version of turf-ruby
Public Instance Methods
Takes a LineString and returns a Point at a specified distance along the line. @see turfjs.org/docs/#along @param line [Feature<LineString>] input line @param distance [number] distance along the line @param units [string] can be degrees, radians, miles, or kilometers (optional, default “kilometers”) @return [Feature<Point>] Point distance units along the line
# File lib/turf/along.rb, line 13 def along(line, distance, units: "kilometers") line = deep_symbolize_keys line travelled = 0 geom = get_geom line coords = geom[:coordinates] coords.each_with_index do |coord, i| break if distance >= travelled && i == coords.length - 1 if travelled >= distance overshot = distance - travelled return point(coord) if overshot.zero? direction = bearing(coord, coords[i - 1]) - 180 interpolated = destination(coord, overshot, direction, units: units) return interpolated else travelled += distance(coords[i], coords[i + 1], units: units) end end point(coords.last) end
Takes one or more features and returns their area in square meters. @see turfjs.org/docs/#area @param geojson [GeoJSON] input GeoJSON feature(s) @return [number] aria in square meters
# File lib/turf/area.rb, line 9 def area(geojson) geom_reduce(geojson, initial_value: 0) do |value, geom| value + area_calculate_area(geom) end end
Takes two points and finds the geographic bearing between them, i.e. the angle measured in degrees from the north line (0 degrees) @see turfjs.org/docs/#bearing @param from [Coord] starting Point @param to [Coord] ending Point @param final boolean calculates the final bearing if true @return [number] bearing in decimal degrees, between -180 and 180 degrees (positive clockwise)
# File lib/turf/bearing.rb, line 14 def bearing(from, to, final: false) return calculate_final_bearing(from, to) if final coordinates1 = get_coord from coordinates2 = get_coord to lon1 = degrees_to_radians(coordinates1[0]) lon2 = degrees_to_radians(coordinates2[0]) lat1 = degrees_to_radians(coordinates1[1]) lat2 = degrees_to_radians(coordinates2[1]) a = Math.sin(lon2 - lon1) * Math.cos(lat2) b = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1) radians_to_degrees(Math.atan2(a, b)) end
Takes a Point and a Polygon or MultiPolygon and determines if the point resides inside the polygon. The polygon can be convex or concave. The function accounts for holes. @see turfjs.org/docs/#booleanPointInPolygon @param point [Coord] input point @param polygon [Feature<(Polygon | MultiPolygon)>] input polygon or multipolygon @param ignore_boundary [boolean] True if polygon boundary should be ignored when determining if the point is inside the polygon otherwise false. @return [boolean] true if the Point is inside the Polygon; false if the Point is not inside the Polygon
# File lib/turf/boolean_point_in_polygon.rb, line 16 def boolean_point_in_polygon(point, polygon, ignore_boundary: false) polygon = deep_symbolize_keys(polygon) pt = get_coord(point) geom = get_geom(polygon) type = geom.fetch(:type) bbox = polygon[:bbox] polys = geom.fetch(:coordinates) # Quick elimination if point is not inside bbox return false if bbox && !in_bbox(pt, bbox) # normalize to multipolygon polys = [polys] if type == "Polygon" inside_poly = false polys.each do |poly| # check if it is in the outer ring first next unless in_ring(pt, poly[0], ignore_boundary) in_hole = false # check for the point in any of the holes poly.slice(1, poly.size - 1).each do |hole| if in_ring(pt, hole, !ignore_boundary) in_hole = true end end if !in_hole inside_poly = true end end inside_poly end
Takes one or more features and calculates the centroid using the mean of all vertices. This lessens the effect of small islands and artifacts when calculating the centroid of a set of polygons. @see turfjs.org/docs/#centroid @param geojson [GeoJSON] GeoJSON to be centered @param properties [Hash] a [Hash] that is used as the Feature's properties @return [Feature<Point>] the centroid of the input features
# File lib/turf/centroid.rb, line 13 def centroid(geojson, properties: {}) x_sum = 0 y_sum = 0 len = 0 coord_each geojson, exclude_wrap_coord: true do |coord| x_sum += coord[0] y_sum += coord[1] len += 1 end point( [x_sum / len, y_sum / len], properties: properties, ) end
Get all coordinates from any GeoJSON object. @see turfjs.org/docs/#coordAll @param geojson [FeatureCollection|Feature|Geometry] any GeoJSON object @param exclude_wrap_coord [boolean] whether or not to include the final coordinate of LinearRings that wraps the ring in its iteration @return [Array<Array<number>>] coordinate position array
# File lib/turf/meta.rb, line 25 def coord_all(geojson, exclude_wrap_coord: false) geometries = self.geometries(geojson) geometries.flat_map do |geometry| next [] if geometry.nil? case geometry[:type] when "Point" [geometry[:coordinates]] when "LineString", "MultiPoint" geometry[:coordinates] when "Polygon", "MultiLineString" geometry[:coordinates].flat_map do |line_coords| ( exclude_wrap_coord ? line_coords.slice(0...-1) : line_coords ) end when "MultiPolygon" geometry[:coordinates].flat_map do |polygon_coords| polygon_coords.flat_map do |line_coords| ( exclude_wrap_coord ? line_coords.slice(0...-1) : line_coords ) end end when "Feature" [].tap do |feature_coords| coord_each geometry, exclude_wrap_coord: exclude_wrap_coord do |coord| feature_coords.push coord end end else raise Error, "Unknown Geometry Type: #{geometry[:type]}" end end end
Iterate over coordinates in any GeoJSON object, similar to Array.forEach() @see turfjs.org/docs/#coordEach @param geojson [FeatureCollection|Feature|Geometry] any GeoJSON object @param exclude_wrap_coord [boolean] whether or not to include the final coordinate of LinearRings that wraps the ring in its iteration @yield [current_coord, coord_index] given any coordinate @yieldparam current_coord [Array<number>] The current coordinate being processed. @yieldparam coord_index [number] The current index of the coordinate being processed.
# File lib/turf/meta.rb, line 15 def coord_each(geojson, exclude_wrap_coord: false, &block) coord_all(geojson, exclude_wrap_coord: exclude_wrap_coord).each_with_index(&block) end
Reduce coordinates in any GeoJSON object, similar to Array.reduce() @see turfjs.org/docs/#coordReduce @param geojson [FeatureCollection|Geometry|Feature] any GeoJSON object @param initial_value [*] Value to use as the first argument to the first call of the callback. @param exclude_wrap_coord [Boolean] whether or not to include the final coordinate of LinearRings that wraps the ring in its iteration. @return [*] The value that results from the reduction.
# File lib/turf/meta.rb, line 68 def coord_reduce(geojson, initial_value: nil, exclude_wrap_coord: false) previous_value = initial_value coord_each( geojson, exclude_wrap_coord: exclude_wrap_coord, ) do |current_coord, coord_index| previous_value = if coord_index.zero? && initial_value.nil? current_coord else yield( previous_value, current_coord, coord_index ) end end previous_value end
Converts an angle in degrees to radians @see turfjs.org/docs/#degreesToRadians @param degrees [number] angle between 0 and 360 degrees @return [number] angle in radians
# File lib/turf/helpers.rb, line 201 def degrees_to_radians(degrees) radians = degrees.remainder(360) radians * Math::PI / 180 end
Takes a Point and calculates the location of a destination point given a distance in degrees, radians, miles, or kilometers; and bearing in degrees. This uses the Haversine formula to account for global curvature. @see turfjs.org/docs/#destination @param origin [Coord] starting point @param distance [number] distance from the origin point @param bearing [number] ranging from -180 to 180 @param units [string] miles, kilometers, degrees, or radians @param properties [Hash] Translate properties to Point @return [Feature<Point>] destination point
# File lib/turf/destination.rb, line 16 def destination(origin, distance, bearing, units: "kilometers", properties: {}) coordinates1 = get_coord origin longitude1 = degrees_to_radians coordinates1[0] latitude1 = degrees_to_radians coordinates1[1] bearing_radians = degrees_to_radians bearing radians = length_to_radians distance, units latitude2 = Math.asin(Math.sin(latitude1) * Math.cos(radians) + Math.cos(latitude1) * Math.sin(radians) * Math.cos(bearing_radians)) longitude2 = longitude1 + Math.atan2( Math.sin(bearing_radians) * Math.sin(radians) * Math.cos(latitude1), Math.cos(radians) - Math.sin(latitude1) * Math.sin(latitude2), ) lng = radians_to_degrees(longitude2) lat = radians_to_degrees(latitude2) point([lng, lat], properties: properties) end
Calculates the distance between two points in degrees, radians, miles, or kilometers. This uses the Haversine formula to account for global curvature. @see turfjs.org/docs/#distance @param from [Coord] origin point @param to [Coord] destination point @param units [string] can be degrees, radians, miles, or kilometers @return [number] distance between the two points
# File lib/turf/distance.rb, line 14 def distance(from, to, units: "kilometers") coordinates1 = get_coord from coordinates2 = get_coord to d_lat = degrees_to_radians coordinates2[1] - coordinates1[1] d_lon = degrees_to_radians coordinates2[0] - coordinates1[0] lat1 = degrees_to_radians coordinates1[1] lat2 = degrees_to_radians coordinates2[1] a = ( (Math.sin(d_lat / 2)**2) + (Math.sin(d_lon / 2)**2) * Math.cos(lat1) * Math.cos(lat2) ) radians_to_length( 2 * Math.atan2( Math.sqrt(a), Math.sqrt(1 - a), ), units, ) end
Wraps a GeoJSON Geometry in a GeoJSON Feature. @see turfjs.org/docs/#feature @param geom [Geometry] input geometry @param properties [Hash] an Object of key-value pairs to add as properties @param bbox [Array<number>] Bounding Box Array [west, south, east, north] associated with the Feature @param id [string | number] Identifier associated with the Feature @return [Feature] a GeoJSON Feature
# File lib/turf/helpers.rb, line 35 def feature(geom, properties: {}, bbox: nil, id: nil) feat = { type: "Feature", properties: properties, geometry: geom } feat[:id] = options[:id] if id feat[:bbox] = options[:bbox] if bbox feat end
Takes one or more Features and creates a FeatureCollection. @see turfjs.org/docs/#featureCollection @param features [Array<Feature>] input features @param bbox [Array<number>] Bounding Box Array [west, south, east, north] associated with the Feature @param id [string | number] Identifier associated with the Feature @return [FeatureCollection] FeatureCollection of Features
# File lib/turf/helpers.rb, line 53 def feature_collection(features, bbox: nil, id: nil) fc = { type: "FeatureCollection" } fc[:id] = options[:id] if id fc[:bbox] = options[:bbox] if bbox fc[:features] = features fc end
Iterate over features in any GeoJSON object, similar to Array.forEach. @see turfjs.org/docs/#featureEach @param geojson [FeatureCollection|Feature|Geometry] any GeoJSON object @yield [feature] given any coordinate @yieldparam feature [Feature<any>] currentFeature The current Feature being processed. @yieldparam feature_index [number] The current index of the Feature being processed.
# File lib/turf/meta.rb, line 187 def feature_each(geojson, &block) return unless geojson features = [] geojson = deep_symbolize_keys geojson case geojson[:type] when "Feature" features.push geojson when "FeatureCollection" features.push(*geojson[:features]) end features.each_with_index(&block) end
Reduce features in any GeoJSON object, similar to Array.reduce(). @see turfjs.org/docs/#featureReduce @param geojson [FeatureCollection|Feature|Geometry] any GeoJSON object @param initial_value [*] Value to use as the first argument to the first call of the callback. @yieldparam previous_value [*] Result of previous reduction @yieldparam feature [Feature<any>] The current Feature being processed. @yieldparam feature_index [number] The current index of the Feature being processed. @return [*] The value that results from the reduction.
# File lib/turf/meta.rb, line 210 def feature_reduce(geojson, initial_value: nil) previous_value = initial_value feature_each( geojson, ) do |feature, feature_index| previous_value = if feature_index.zero? && initial_value.nil? feature else yield( previous_value, feature, feature_index ) end end previous_value end
Iterate over flattened features in any GeoJSON object, similar to Array.forEach. @see turfjs.org/docs/#flattenEach @param geojson [FeatureCollection|Feature|Geometry] any GeoJSON object @yieldparam feature [Feature<any>] The current Feature being processed. @yieldparam feature_index [number] The current index of the Feature being processed. @yieldparam multi_feature_index [number] The current index of the Feature in the multi-Feature
# File lib/turf/meta.rb, line 237 def flatten_each(geojson) geom_each(geojson) do |geometry, feature_index, properties, bbox, id| if geometry.nil? next yield( feature(nil, properties: properties, bbox: bbox, id: id), feature_index, 0 ) end case geometry[:type] when "Point", "LineString", "Polygon" yield( feature(geometry, properties: properties, bbox: bbox, id: id), feature_index, 0 ) when "MultiPoint", "MultiLineString", "MultiPolygon" geom_type = geometry[:type].sub(/^Multi/, "") geometry[:coordinates].each_with_index do |coordinate, multi_feature_index| geom = { type: geom_type, coordinates: coordinate } yield( feature(geom, properties: properties), feature_index, multi_feature_index ) end end end end
Reduce flattened features in any GeoJSON object, similar to Array.reduce(). @see turfjs.org/docs/#flattenEach @param geojson [FeatureCollection|Feature|Geometry] any GeoJSON object @param initial_value [*] Value to use as the first argument to the first call of the callback. @yieldparam previous_value [*] Result of previous reduction @yieldparam feature [Feature<any>] The current Feature being processed. @yieldparam feature_index [number] The current index of the Feature being processed. @yieldparam multi_feature_index [number] The current index of the Feature in the multi-Feature @return [*] The value that results from the reduction.
# File lib/turf/meta.rb, line 280 def flatten_reduce(geojson, initial_value: nil) previous_value = initial_value flatten_each( geojson, ) do |feature, feature_index, multi_feature_index| previous_value = if feature_index.zero? && multi_feature_index.zero? && initial_value.nil? feature else yield( previous_value, feature, feature_index, multi_feature_index ) end end previous_value end
Iterate over each geometry in any GeoJSON object, similar to Array.forEach() @see turfjs.org/docs/#geomReduce @param geojson [FeatureCollection|Feature|Geometry] any GeoJSON object @yieldparam geom [Geometry] The current Feature being processed. @yieldparam feature_index [number] The current index of the Feature being processed. @yieldparam properties [Hash] an Object of key-value pairs to add as properties @yieldparam bbox [Array<number>] Bounding Box Array [west, south, east, north] associated with the Feature @yieldparam id [string|number] Identifier associated with the Feature
# File lib/turf/meta.rb, line 98 def geom_each(geojson) return unless geojson geojson = deep_symbolize_keys geojson # [geometry, properties, bbox, id] entries = [] case geojson[:type] when "FeatureCollection" geojson[:features].each do |feature| entries.push [feature[:geometry], feature[:properties], feature[:bbox], feature[:id]] end when "Feature" entries.push [geojson[:geometry], geojson[:properties], geojson[:bbox], geojson[:id]] else entries.push [geojson, {}, nil, nil] end # flatten GeometryCollection entries = entries.flat_map do |entry| geometry, properties, bbox, id = entry next [entry] if geometry.nil? next [entry] unless geometry[:type] == "GeometryCollection" geometry[:geometries].map do |sub_geometry| [sub_geometry, properties, bbox, id] end end entries.each_with_index do |entry, entry_index| geometry, properties, bbox, id = entry yield geometry, entry_index, properties, bbox, id end end
Reduce geometry in any GeoJSON object, similar to Array.reduce(). @see turfjs.org/docs/#geomReduce @param geojson [FeatureCollection|Feature|Geometry] any GeoJSON object @param initial_value [*] Value to use as the first argument to the first call of the callback. @yieldparam previous_value [*] Result of previous reduction @yieldparam geom [Geometry] The current Feature being processed. @yieldparam geom_index [number] The current index of the Feature being processed. @yieldparam properties [Hash] an Object of key-value pairs to add as properties @yieldparam bbox [Array<number>] Bounding Box Array [west, south, east, north] associated with the Feature @yieldparam id [string|number] Identifier associated with the Feature @return [*] The value that results from the reduction.
# File lib/turf/meta.rb, line 146 def geom_reduce(geojson, initial_value: nil) previous_value = initial_value geom_each( geojson, ) do |geom, geom_index, properties, bbox, id| previous_value = if geom_index.zero? && initial_value.nil? geom else yield( previous_value, geom, geom_index, properties, bbox, id ) end end previous_value end
Get all Geometry @param geojson [FeatureCollection|Feature|Geometry] any GeoJSON object @return [Array<Geometry>] list of Geometry
# File lib/turf/meta.rb, line 173 def geometries(geojson) [].tap do |geometries| geom_each(geojson) do |geometry| geometries.push(geometry) end end end
Creates a Feature based on a coordinate array. Properties can be added optionally. @see turfjs.org/docs/#geometryCollection @param geometries [Array<Geometry>] an array of GeoJSON Geometries @param properties [Hash] a Hash of key-value pairs to add as properties @param bbox [Array<number>] Bounding Box Array [west, south, east, north] associated with the Feature @param id [string|number] Identifier associated with the Feature @return [Feature<GeometryCollection>] a GeoJSON GeometryCollection Feature
# File lib/turf/helpers.rb, line 69 def geometry_collection(geometries, bbox: nil, id: nil, properties: {}) geom = { type: "GeometryCollection", geometries: geometries } feature(geom, properties: properties, bbox: bbox, id: id) end
Unwrap a coordinate from a Point Feature, Geometry or a single coordinate. @see turfjs.org/docs/#getCoord @param coord [Array|Geometry<Point>|Feature<Point>] GeoJSON Point or an Array of numbers @return [Array] coordinates
# File lib/turf/invariant.rb, line 11 def get_coord(coord) if !coord raise Error, "coord is required" end is_numeric = ->(i) { i.is_a? Numeric } if coord.is_a?(Array) && coord.length >= 2 && coord.all?(&is_numeric) return coord end if coord.is_a? Hash coord = deep_symbolize_keys(coord) is_feature = coord[:type] == "Feature" if is_feature && coord.fetch(:geometry, {})[:type] == "Point" return coord[:geometry][:coordinates] end if coord[:type] == "Point" return coord[:coordinates] end end raise Error, "coord must be GeoJSON Point or an Array of numbers" end
Get Geometry from Feature or Geometry Object @see turfjs.org/docs/#getGeom @param geojson [Feature|Geometry] GeoJSON Feature or Geometry Object @return [Geometry|null] GeoJSON Geometry Object
# File lib/turf/invariant.rb, line 41 def get_geom(geojson) geojson = deep_symbolize_keys geojson return geojson[:geometry] if geojson[:type] == "Feature" geojson end
Convert a distance measurement (assuming a spherical Earth) from a real-world unit into radians Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet @see turfjs.org/docs/#lengthToRadians @param distance [number] in real units @param units [string] can be degrees, radians, miles, inches, yards, metres, meters, kilometres, kilometers. @return [number] radians
# File lib/turf/helpers.rb, line 225 def length_to_radians(distance, units = "kilometers") factor = FACTORS[units] raise Error, "#{units} units is invalid" unless factor distance / factor end
Creates a LineString Feature from an Array of Positions. @see turfjs.org/docs/#lineString @param coordinates [Array<Array<number>>] an array of Positions @param properties [Hash] an Hash of key-value pairs to add as properties @param bbox [Array<number>] Bounding Box Array [west, south, east, north] associated with the Feature @param id [string|number] Identifier associated with the Feature @return [Feature<LineString>] LineString Feature
# File lib/turf/helpers.rb, line 100 def line_string(coordinates, properties: {}, bbox: nil, id: nil) if coordinates.size < 2 raise Error, "coordinates must be an array of two or more positions" end geom = { type: "LineString", coordinates: coordinates } feature(geom, properties: properties, bbox: bbox, id: id) end
Creates a Feature<MultiLineString> based on a coordinate array. Properties can be added optionally. @see turfjs.org/docs/#multiLineString @param coordinates [Array<Array<Array<number>>>] coordinates an array of LineStrings @param properties [Hash] a Hash of key-value pairs to add as properties @param bbox [Array<number>] Bounding Box Array [west, south, east, north] associated with the Feature @param id [string|number] Identifier associated with the Feature @return [Feature<MultiLineString>] a MultiLineString feature
# File lib/turf/helpers.rb, line 178 def multi_line_string(coordinates, properties: {}, bbox: nil, id: nil) geom = { type: "MultiLineString", coordinates: coordinates } feature(geom, properties: properties, id: id, bbox: bbox) end
Creates a Feature based on a coordinate array. Properties can be added optionally. @param coordinates [Array<Array<number>>] an array of Positions @param properties [Hash] a Hash of key-value pairs to add as properties @param bbox [Array<number>] Bounding Box Array [west, south, east, north] associated with the Feature @param id [string|number] Identifier associated with the Feature @return [Feature<MultiPoint>] a MultiPoint feature
# File lib/turf/helpers.rb, line 84 def multi_point(coordinates, properties: {}, bbox: nil, id: nil) geom = { type: "MultiPoint", coordinates: coordinates } feature(geom, properties: properties, bbox: bbox, id: id) end
Creates a Feature<MultiPolygon> based on a coordinate array. Properties can be added optionally. @see turfjs.org/docs/#multiPolygon @param coordinates [Array<Array<Array<Array<number>>>>] an array of Polygons @param properties [Hash] an Hash of key-value pairs to add as properties @param bbox [Array<number>] Bounding Box Array [west, south, east, north] associated with the Feature @param id [string|number] Identifier associated with the Feature @return [Feature<MultiPolygon>] a multipolygon feature
# File lib/turf/helpers.rb, line 163 def multi_polygon(coordinates, properties: {}, bbox: nil, id: nil) geom = { type: "MultiPolygon", coordinates: coordinates } feature(geom, properties: properties, id: id, bbox: bbox) end
Creates a Point Feature from a Position. @see turfjs.org/docs/#point @param coordinates [Array<number>] longitude, latitude position (each in decimal degrees) @param properties [Hash] an Hash of key-value pairs to add as properties @param bbox [Array<number>] Bounding Box Array [west, south, east, north] associated with the Feature @param id [string | number] Identifier associated with the Feature @return [Feature<Point>] a Point feature
# File lib/turf/helpers.rb, line 119 def point(coordinates, properties: {}, id: nil, bbox: nil) geom = { type: "Point", coordinates: coordinates } feature(geom, properties: properties, id: id, bbox: bbox) end
Creates a Polygon Feature from an Array of LinearRings. @see turfjs.org/docs/#polygon @param coordinates [Array<Array<Array<number>>>] an array of LinearRings @param properties [Hash] an Hash of key-value pairs to add as properties @param bbox [Array<number>] Bounding Box Array [west, south, east, north] associated with the Feature @param id [string | number] Identifier associated with the Feature @return [Feature<Polygon>] Polygon feature
# File lib/turf/helpers.rb, line 134 def polygon(coordinates, properties: {}, bbox: nil, id: nil) coordinates.each do |ring| if ring.size < 4 raise( Error, "Each LinearRing of a Polygon must have 4 or more Positions.", ) end ring.last.each_with_index do |number, idx| if ring.first[idx] != number raise Error, "First and last Position are not equivalent." end end end geom = { type: "Polygon", coordinates: coordinates } feature(geom, properties: properties, id: id, bbox: bbox) end
Converts an angle in radians to degrees @see turfjs.org/docs/#radiansToDegrees @param radians [number] angle in radians @return [number] degrees between 0 and 360 degrees
# File lib/turf/helpers.rb, line 192 def radians_to_degrees(radians) degrees = radians.remainder(2 * Math::PI) degrees * 180 / Math::PI end
Convert a distance measurement (assuming a spherical Earth) from radians to a more friendly unit. Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet @see turfjs.org/docs/#radiansToLength @param radians [number] in radians across the sphere @param units [string] can be degrees, radians, miles, inches, yards, metres, meters, kilometres, kilometers. @return [number] distance
# File lib/turf/helpers.rb, line 212 def radians_to_length(radians, units = "kilometers") factor = FACTORS[units] raise Error, "#{units} units is invalid" unless factor radians * factor end
Private Instance Methods
# File lib/turf/area.rb, line 17 def area_calculate_area(geom) case geom[:type] when "Polygon" area_polygon_area(geom[:coordinates]) when "MultiPolygon" geom[:coordinates].map do |coordinate| area_polygon_area(coordinate) end.sum else 0 end end
# File lib/turf/area.rb, line 30 def area_polygon_area(coords) outline, *holes = coords total = area_ring_area(outline).abs holes.each do |hole| total -= area_ring_area(hole).abs end total end
# File lib/turf/area.rb, line 77 def area_rad(num) num * Math::PI / 180 end
# File lib/turf/area.rb, line 41 def area_ring_area(coords) return 0 if coords.size <= 2 total = 0 coords.each_with_index do |_coord, index| lower_index, middle_index, upper_index = case index when coords.size - 2 [ coords.size - 2, coords.size - 1, 0, ] when coords.size - 1 [ coords.size - 1, 0, 1, ] else [ index, index + 1, index + 2, ] end p1 = coords[lower_index] p2 = coords[middle_index] p3 = coords[upper_index] total += (area_rad(p3[0]) - area_rad(p1[0])) * Math.sin(area_rad(p2[1])) end total * AREA_RADIUS * AREA_RADIUS / 2 end
# File lib/turf/bearing.rb, line 33 def calculate_final_bearing(from, to) bear = bearing(to, from) (bear + 180) % 360 end
A non-intrusive implemenation of Rails' Hash#deep_symbolize_keys
# File lib/turf.rb, line 16 def deep_symbolize_keys(input) case input when Hash input.transform_keys(&:to_sym).transform_values do |value| deep_symbolize_keys(value) end when Array input.map do |value| deep_symbolize_keys value end else input end end
# File lib/turf/boolean_point_in_polygon.rb, line 52 def in_bbox(point, bbox) bbox[0] <= point[0] && bbox[1] <= point[1] && bbox[2] >= point[0] && bbox[3] >= point[1] end
# File lib/turf/boolean_point_in_polygon.rb, line 59 def in_ring(point, ring, ignore_boundary) is_inside = false is_ring_valid = ring[0][0] == ring[ring.size - 1][0] is_ring_valid &&= ring[0][1] == ring[ring.size - 1][1] if is_ring_valid ring = ring.slice(0, ring.size - 1) end ring.each_with_index do |ring_pt, ring_pt_index| ring_pt2 = ring[(ring_pt_index + 1) % ring.size] xi = ring_pt[0] yi = ring_pt[1] xj = ring_pt2[0] yj = ring_pt2[1] on_boundary = ( point[1] * (xi - xj) + yi * (xj - point[0]) + yj * (point[0] - xi) ).zero? on_boundary &&= ((xi - point[0]) * (xj - point[0]) <= 0) on_boundary &&= ((yi - point[1]) * (yj - point[1]) <= 0) if on_boundary return !ignore_boundary end intersect = ((yi > point[1]) != (yj > point[1])) && (point[0] < (xj - xi) * (point[1] - yi) / (yj - yi) + xi) if intersect is_inside = !is_inside end end is_inside end