+ 404 Not Found +
+ ++ This page is unavailable in this version of the API docs. +
+ ++ You can use the sidebar to search for your page, or try a different + Crystal version. +
+ +diff --git a/404.html b/404.html new file mode 100644 index 0000000..5626f91 --- /dev/null +++ b/404.html @@ -0,0 +1,117 @@ + + +
+ + + + + + + + + + + + + ++ This page is unavailable in this version of the API docs. +
+ ++ You can use the sidebar to search for your page, or try a different + Crystal version. +
+ +{{ (`shards version /__w/geo/geo/src`).chomp.stringify }}
+ A Coord
is a point in geographical coordinates: latitude and longitude.
{/%(#{FLOATUFLAGS})?lats/ => ->(m : Regex::MatchData) do
+ "%<lats>#{m[1]? || "0."}f"
+end, "%latm" => "%<latm>i", /%(#{INTFLAGS})?latds/ => ->(m : Regex::MatchData) do
+ "%<latds>#{m[1]}i"
+end, "%latd" => "%<latd>i", "%lath" => "%<lath>s", /%(#{FLOATFLAGS})?lat/ => ->(m : Regex::MatchData) do
+ "%<lat>#{m[1]}f"
+end, /%(#{FLOATUFLAGS})?lngs/ => ->(m : Regex::MatchData) do
+ "%<lngs>#{m[1]? || "0."}f"
+end, "%lngm" => "%<lngm>i", /%(#{INTFLAGS})?lngds/ => ->(m : Regex::MatchData) do
+ "%<lngds>#{m[1]}i"
+end, "%lngd" => "%<lngd>i", "%lngh" => "%<lngh>s", /%(#{FLOATFLAGS})?lng/ => ->(m : Regex::MatchData) do
+ "%<lng>#{m[1]}f"
+end}
+ /\+?#{FLOATUFLAGS}?/
+ /0\.\d+/
+ /\+?/
+ The comparison operator.
Calculates initial and final bearings between two points using great-circle distance formulas
Calculates distance to other
.
Returns a geohash representing coordinates.
Returns latitude degrees
Returns latitude hemisphere
Returns latitude minutes
Returns latitude seconds
Returns longitude degrees
Returns longitude hemisphere
Returns longitude minutes
Returns longitude seconds
Formats coordinates according to directives in formatstr
.
Returns a string representing coordinates.
The comparison operator. Returns 0
if the two objects are equal,
+a negative number if this object is considered less than other,
+a positive number if this object is considered greater than other,
+or nil
if the two objects are not comparable.
Subclasses define this method to provide class-specific ordering.
+The comparison operator is usually used to sort values:
+# Sort in a descending way:
+[3, 1, 2].sort { |x, y| y <=> x } # => [3, 2, 1]
+
+# Sort in an ascending way:
+[3, 1, 2].sort { |x, y| x <=> y } # => [1, 2, 3]
+ Calculates initial and final bearings between two points using great-circle distance formulas
+Calculates distance to other
.
+Haversine formula is used.
Returns a geohash representing coordinates.
+Formats coordinates according to directives in formatstr
.
Each directive starts with %
and can contain some modifiers before its name.
Acceptable modifiers:
++
for mandatory sign printing;0.3
.List of directives:
+%lat
- Full latitude, floating point, signed%latds
- Latitude degrees, integer, signed%latd
- Latitude degrees, integer, unsigned%latm
- Latitude minutes, integer, unsigned%lats
- Latitude seconds, floating point, unsigned%lath
- Latitude hemisphere, "N" or "S"%lng
- Full longitude, floating point, signed%lngds
- Longitude degrees, integer, signed%lngd
- Longitude degrees, integer, unsigned%lngm
- Longitude minutes, integer, unsigned#lngs
- Longitude seconds, floating point, unsignedExamples:
+g = Geo::Coord.new(50.004444, 36.231389)
+g.strfcoord('%+lat, %+lng')
+# => "+50.004444, +36.231389"
+g.strfcoord("%latd°%latm'%lath -- %lngd°%lngm'%lngh")
+# => "50°0'N -- 36°13'E"
+#strfcoord
handles seconds rounding implicitly:
pos = Geo::Coord.new(0.033333, 91.333333)
+pos.strfcoord('%latd %latm %0.5lats') # => "0 1 59.99880"
+pos.strfcoord('%latd %latm %lats') # => "0 2 0"
+ Returns a string representing coordinates.
+g.to_s # => "50°0'16\"N 36°13'53\"E"
+g.to_s(dms: false) # => "50.004444,36.231389"
+ Float32 | Float64 | Int32
+
+
+
+
+
+
+
+
+
+
+
+
+ A Polygon
is a fixed-size, immutable, stack-allocated sequence of Geo::Coord
.
+Coordinates are in lexicographical order.
+Additionally, polygons form a closed loop and define a filled region.
Evaluate area of a polygon using shoelace formula
Returns the number of elements in this container.
Returns the element at the given index, without doing any bounds check.
Returns the number of elements in this container.
+Returns the element at the given index, without doing any bounds check.
+Indexable
makes sure to invoke this method with index in 0...size
,
+so converting negative indices to positive ones is not needed here.
Clients never invoke this method directly. Instead, they access
+elements with #[](index)
and #[]?(index)
.
This method should only be directly invoked if you are absolutely +sure the index is in bounds, to avoid a bounds check for a small boost +of performance.
+Orientation of ordered triplet (p, q, r)
Orientation of ordered triplet (p, q, r)
+Orientation of an ordered triplet of points in the plane can be
+The function returns following values +0 --> p, q and r are colinear +1 --> Clockwise +2 --> Counterclockwise
+Geospatial primitives, algorithms, and utilities for Crystal.
+Add this to your application's shard.yml
:
dependencies:
+ geo:
+ github: geocrystal/geo
+Run shards install
A Geo::Coord
is a point in geographical coordinates: latitude and longitude.
require "geo"
+
+c = Geo::Coord.new(50.004444, 36.231389)
+
+c.strfcoord(%{%latd %latm' %0.1lats" %lath, %lngd %lngm' %0.1lngs" %lngh})
+# => "50 0' 16.0" N, 36 13' 53.0" E"
+
+c.strfcoord("%lat,%lng")
+# => "-50.004444,-36.231389"
+
+c.to_s
+# => "50°0'16"N 36°13'53"E"
+
+pos = Geo::Coord.new(50.004444, 36.231389)
+
+pos.geohash
+# => "ubcu2rnbuxcx"
+
+pos.geohash(5)
+# => "ubcu2"
+A polygon represents an area enclosed by a closed path (or loop), which is defined by a series of coordinates.
+require "geo"
+
+pos1 = Geo::Coord.new(45.3142533036254, -93.47527313511819)
+pos2 = Geo::Coord.new(45.31232182518015, -93.34893036168069)
+pos3 = Geo::Coord.new(45.23694281999268, -93.35167694371194)
+pos4 = Geo::Coord.new(45.23500870841669, -93.47801971714944)
+
+polygon = Geo::Polygon.new([pos1, pos2, pos3, pos4])
+The Polygon in the example above consists of four sets of Geo::Coord
coordinates, but notice that the first and last sets define the same location, which completes the loop. In practice, however, since polygons define closed areas, you don't need to specify the last set of coordinates. Ot will automatically complete the polygon by connecting the last location back to the first location.
The following example is identical to the previous one, except that the last Geo::Coord
is omitted:
require "geo"
+
+pos1 = Geo::Coord.new(45.3142533036254, -93.47527313511819)
+pos2 = Geo::Coord.new(45.31232182518015, -93.34893036168069)
+pos3 = Geo::Coord.new(45.23694281999268, -93.35167694371194)
+
+polygon = Geo::Polygon.new([pos1, pos2, pos3])
+Additional actions:
+coord_inside = Geo::Coord.new(45.27428243796789, -93.41648483416066)
+coord_outside = Geo::Coord.new(45.45411010558687, -93.78151703160256)
+
+polygon.contains?(coord_inside) # => true
+polygon.contains?(coord_outside) # => false
+
+polygon.centroid # => Geo::Coord(@lat=45.27463866133501, @lng=-93.41400121829719)
+Additionally you can initialize polygon as convex hull from coordinates of points.
+points = [
+ {1.0, 1.0},
+ {1.0, 0.0},
+ {1.0, -1.0},
+ {0.0, -1.0},
+ {-1.0, -1.0},
+ {-1.0, 0.0},
+ {-1.0, 1.0},
+ {0.0, 1.0},
+ {0.0, 0.0},
+].map { |point| Geo::Coord.new(point[0], point[1]) }
+
+polygon = Geo::Polygon.new(points, convex_hull: true)
+polygon.coords
+# => {-1.0, -1.0}, {1.0, -1.0}, {1.0, 1.0}, {-1.0, 1.0}, {-1.0, -1.0}
+The convex hull is computed using the convex_hull library.
+Geo::Coord#strfcoord
formats coordinates according to directives.
Each directive starts with %
and can contain some modifiers before its name.
Acceptable modifiers:
++
for mandatory sign printing;0.3
.List of directives:
+| Directive | Description |
+| --------- | ------------------------------------------- |
+| %lat
| Full latitude, floating point, signed |
+| %latds
| Latitude degrees, integer, signed |
+| %latd
| Latitude degrees, integer, unsigned |
+| %latm
| Latitude minutes, integer, unsigned |
+| %lats
| Latitude seconds, floating point, unsigned |
+| %lath
| Latitude hemisphere, "N" or "S" |
+| %lng
| Full longitude, floating point, signed |
+| %lngds
| Longitude degrees, integer, signed |
+| %lngd
| Longitude degrees, integer, unsigned |
+| %lngm
| Longitude minutes, integer, unsigned |
+| lngs
| Longitude seconds, floating point, unsigned |
+| %lngh
| Longitude hemisphere, "E" or "W" |
Examples:
+g = Geo::Coord.new(50.004444, 36.231389)
+g.strfcoord('%+lat, %+lng')
+# => "+50.004444, +36.231389"
+g.strfcoord("%latd°%latm'%lath -- %lngd°%lngm'%lngh")
+# => "50°0'N -- 36°13'E"
+strfcoord
handles seconds rounding implicitly:
pos = Geo::Coord.new(0.033333, 91.333333)
+pos.strfcoord('%latd %latm %0.5lats') # => "0 1 59.99880"
+pos.strfcoord('%latd %latm %lats') # => "0 2 0"
+Haversine formula from haversine shard is used.
+require "geo"
+require "geo/distance"
+
+london = Geo::Coord.new(51.500153, -0.126236)
+new_york = Geo::Coord.new(40.714268, -74.005974)
+
+new_york.distance(london).to_kilometers
+# => 5570.4744596620685
+git checkout -b my-new-feature
)git commit -am 'Add some feature'
)git push origin my-new-feature
)A Coord
is a point in geographical coordinates: latitude and longitude.
The comparison operator.
","abstract":false,"args":[{"name":"other","external_name":"other","restriction":"Geo::Coord"}],"args_string":"(other : Geo::Coord)","args_html":"(other : Geo::Coord)","location":{"filename":"src/geo/coord.cr","line_number":173,"url":null},"def":{"name":"<=>","args":[{"name":"other","external_name":"other","restriction":"Geo::Coord"}],"visibility":"Public","body":"ll <=> other.ll"}},{"html_id":"bearing(to:Geo::Coord,final=false):Float64-instance-method","name":"bearing","doc":"Calculates initial and final bearings between two points using great-circle distance formulas","summary":"Calculates initial and final bearings between two points using great-circle distance formulas
","abstract":false,"args":[{"name":"to","external_name":"to","restriction":"Geo::Coord"},{"name":"final","default_value":"false","external_name":"final","restriction":""}],"args_string":"(to : Geo::Coord, final = false) : Float64","args_html":"(to : Geo::Coord, final = false) : Float64","location":{"filename":"src/geo/bearing.cr","line_number":4,"url":null},"def":{"name":"bearing","args":[{"name":"to","external_name":"to","restriction":"Geo::Coord"},{"name":"final","default_value":"false","external_name":"final","restriction":""}],"return_type":"Float64","visibility":"Public","body":"Geo::Bearing.bearing(lat, lng, to.lat, to.lng, final)"}},{"html_id":"between?(p1:Geo::Coord,p2:Geo::Coord)-instance-method","name":"between?","abstract":false,"args":[{"name":"p1","external_name":"p1","restriction":"Geo::Coord"},{"name":"p2","external_name":"p2","restriction":"Geo::Coord"}],"args_string":"(p1 : Geo::Coord, p2 : Geo::Coord)","args_html":"(p1 : Geo::Coord, p2 : Geo::Coord)","location":{"filename":"src/geo/coord.cr","line_number":177,"url":null},"def":{"name":"between?","args":[{"name":"p1","external_name":"p1","restriction":"Geo::Coord"},{"name":"p2","external_name":"p2","restriction":"Geo::Coord"}],"visibility":"Public","body":"min, max = [p1, p2].minmax\nif cmp = self <=> min\n if cmp < 0\n return false\n end\nend\nif cmp = self <=> max\n if cmp > 0\n return false\n end\nend\ntrue\n"}},{"html_id":"distance(other:Geo::Coord):Haversine::Distance-instance-method","name":"distance","doc":"Calculates distance to `other`.\nHaversine formula is used.","summary":"Calculates distance to other
.
Returns a geohash representing coordinates.
","abstract":false,"args":[{"name":"precision","default_value":"12","external_name":"precision","restriction":""}],"args_string":"(precision = 12)","args_html":"(precision = 12)","location":{"filename":"src/geo/coord.cr","line_number":155,"url":null},"def":{"name":"geohash","args":[{"name":"precision","default_value":"12","external_name":"precision","restriction":""}],"visibility":"Public","body":"Geohash.encode(lat.to_f, lng.to_f, precision)"}},{"html_id":"lat:Float32|Float64|Int32-instance-method","name":"lat","abstract":false,"location":{"filename":"src/geo/coord.cr","line_number":8,"url":null},"def":{"name":"lat","visibility":"Public","body":"@lat"}},{"html_id":"latd:Int32-instance-method","name":"latd","doc":"Returns latitude degrees","summary":"Returns latitude degrees
","abstract":false,"location":{"filename":"src/geo/coord.cr","line_number":36,"url":null},"def":{"name":"latd","return_type":"Int32","visibility":"Public","body":"lat.abs.to_i"}},{"html_id":"latds-instance-method","name":"latds","abstract":false,"location":{"filename":"src/geo/coord.cr","line_number":75,"url":null},"def":{"name":"latds","visibility":"Public","body":"lat.to_i"}},{"html_id":"lath:String-instance-method","name":"lath","doc":"Returns latitude hemisphere","summary":"Returns latitude hemisphere
","abstract":false,"location":{"filename":"src/geo/coord.cr","line_number":51,"url":null},"def":{"name":"lath","return_type":"String","visibility":"Public","body":"lat > 0 ? \"N\" : \"S\""}},{"html_id":"latm:Int32-instance-method","name":"latm","doc":"Returns latitude minutes","summary":"Returns latitude minutes
","abstract":false,"location":{"filename":"src/geo/coord.cr","line_number":41,"url":null},"def":{"name":"latm","return_type":"Int32","visibility":"Public","body":"(lat.abs * 60).to_i % 60"}},{"html_id":"lats:Number-instance-method","name":"lats","doc":"Returns latitude seconds","summary":"Returns latitude seconds
","abstract":false,"location":{"filename":"src/geo/coord.cr","line_number":46,"url":null},"def":{"name":"lats","return_type":"Number","visibility":"Public","body":"(lat.abs * 3600) % 60"}},{"html_id":"ll-instance-method","name":"ll","abstract":false,"location":{"filename":"src/geo/coord.cr","line_number":169,"url":null},"def":{"name":"ll","visibility":"Public","body":"{lat, lng}"}},{"html_id":"lng:Float32|Float64|Int32-instance-method","name":"lng","abstract":false,"location":{"filename":"src/geo/coord.cr","line_number":9,"url":null},"def":{"name":"lng","visibility":"Public","body":"@lng"}},{"html_id":"lngd:Int32-instance-method","name":"lngd","doc":"Returns longitude degrees","summary":"Returns longitude degrees
","abstract":false,"location":{"filename":"src/geo/coord.cr","line_number":56,"url":null},"def":{"name":"lngd","return_type":"Int32","visibility":"Public","body":"lng.abs.to_i"}},{"html_id":"lngds-instance-method","name":"lngds","abstract":false,"location":{"filename":"src/geo/coord.cr","line_number":79,"url":null},"def":{"name":"lngds","visibility":"Public","body":"lng.to_i"}},{"html_id":"lngh:String-instance-method","name":"lngh","doc":"Returns longitude hemisphere","summary":"Returns longitude hemisphere
","abstract":false,"location":{"filename":"src/geo/coord.cr","line_number":71,"url":null},"def":{"name":"lngh","return_type":"String","visibility":"Public","body":"lng > 0 ? \"E\" : \"W\""}},{"html_id":"lngm:Int32-instance-method","name":"lngm","doc":"Returns longitude minutes","summary":"Returns longitude minutes
","abstract":false,"location":{"filename":"src/geo/coord.cr","line_number":61,"url":null},"def":{"name":"lngm","return_type":"Int32","visibility":"Public","body":"(lng.abs * 60).to_i % 60"}},{"html_id":"lngs:Number-instance-method","name":"lngs","doc":"Returns longitude seconds","summary":"Returns longitude seconds
","abstract":false,"location":{"filename":"src/geo/coord.cr","line_number":66,"url":null},"def":{"name":"lngs","return_type":"Number","visibility":"Public","body":"(lng.abs * 3600) % 60"}},{"html_id":"shoelace(other:Geo::Coord)-instance-method","name":"shoelace","abstract":false,"args":[{"name":"other","external_name":"other","restriction":"Geo::Coord"}],"args_string":"(other : Geo::Coord)","args_html":"(other : Geo::Coord)","location":{"filename":"src/geo/coord.cr","line_number":191,"url":null},"def":{"name":"shoelace","args":[{"name":"other","external_name":"other","restriction":"Geo::Coord"}],"visibility":"Public","body":"(lat * other.lng) - (lng * other.lat)"}},{"html_id":"strfcoord(formatstr):String-instance-method","name":"strfcoord","doc":"Formats coordinates according to directives in `formatstr`.\n\nEach directive starts with `%` and can contain some modifiers before its name.\n\nAcceptable modifiers:\n- unsigned integers: none;\n- signed integers: `+` for mandatory sign printing;\n- floats: same as integers and number of digits modifier, like `0.3`.\n\nList of directives:\n\n- `%lat` - Full latitude, floating point, signed\n- `%latds` - Latitude degrees, integer, signed\n- `%latd` - Latitude degrees, integer, unsigned\n- `%latm` - Latitude minutes, integer, unsigned\n- `%lats` - Latitude seconds, floating point, unsigned\n- `%lath` - Latitude hemisphere, \"N\" or \"S\"\n- `%lng` - Full longitude, floating point, signed\n- `%lngds` - Longitude degrees, integer, signed\n- `%lngd` - Longitude degrees, integer, unsigned\n- `%lngm` - Longitude minutes, integer, unsigned\n- `lngs` - Longitude seconds, floating point, unsigned\n- `%lngh`` - Longitude hemisphere, \"E\" or \"W\"\n\nExamples:\n\n```\ng = Geo::Coord.new(50.004444, 36.231389)\ng.strfcoord('%+lat, %+lng')\n# => \"+50.004444, +36.231389\"\ng.strfcoord(\"%latd°%latm'%lath -- %lngd°%lngm'%lngh\")\n# => \"50°0'N -- 36°13'E\"\n```\n\n`strfcoord` handles seconds rounding implicitly:\n\n```\npos = Geo::Coord.new(0.033333, 91.333333)\npos.strfcoord('%latd %latm %0.5lats') # => \"0 1 59.99880\"\npos.strfcoord('%latd %latm %lats') # => \"0 2 0\"\n```","summary":"Formats coordinates according to directives in formatstr
.
Returns a string representing coordinates.
","abstract":false,"args":[{"name":"io","external_name":"io","restriction":""}],"args_string":"(io)","args_html":"(io)","location":{"filename":"src/geo/coord.cr","line_number":165,"url":null},"def":{"name":"to_s","args":[{"name":"io","external_name":"io","restriction":""}],"visibility":"Public","body":"io << (strfcoord(\"%latd°%latm'%lats\\\"%lath %lngd°%lngm'%lngs\\\"%lngh\"))"}}],"types":[{"html_id":"geo/Geo/Coord/Number","path":"Geo/Coord/Number.html","kind":"alias","full_name":"Geo::Coord::Number","name":"Number","abstract":false,"locations":[{"filename":"src/geo/coord.cr","line_number":6,"url":null}],"repository_name":"geo","program":false,"enum":false,"alias":true,"aliased":"(Float32 | Float64 | Int32)","aliased_html":"Float32 | Float64 | Int32","const":false,"namespace":{"html_id":"geo/Geo/Coord","kind":"struct","full_name":"Geo::Coord","name":"Coord"}}]},{"html_id":"geo/Geo/Polygon","path":"Geo/Polygon.html","kind":"struct","full_name":"Geo::Polygon","name":"Polygon","abstract":false,"superclass":{"html_id":"geo/Struct","kind":"struct","full_name":"Struct","name":"Struct"},"ancestors":[{"html_id":"geo/Indexable","kind":"module","full_name":"Indexable","name":"Indexable"},{"html_id":"geo/Enumerable","kind":"module","full_name":"Enumerable","name":"Enumerable"},{"html_id":"geo/Iterable","kind":"module","full_name":"Iterable","name":"Iterable"},{"html_id":"geo/Struct","kind":"struct","full_name":"Struct","name":"Struct"},{"html_id":"geo/Value","kind":"struct","full_name":"Value","name":"Value"},{"html_id":"geo/Object","kind":"class","full_name":"Object","name":"Object"}],"locations":[{"filename":"src/geo/polygon.cr","line_number":5,"url":null}],"repository_name":"geo","program":false,"enum":false,"alias":false,"const":false,"included_modules":[{"html_id":"geo/Indexable","kind":"module","full_name":"Indexable","name":"Indexable"}],"namespace":{"html_id":"geo/Geo","kind":"module","full_name":"Geo","name":"Geo"},"doc":"A `Polygon` is a fixed-size, immutable, stack-allocated sequence of `Geo::Coord`.\nCoordinates are in lexicographical order.\nAdditionally, polygons form a closed loop and define a filled region.","summary":"A Polygon
is a fixed-size, immutable, stack-allocated sequence of Geo::Coord
.
Evaluate area of a polygon using shoelace formula
","abstract":false,"location":{"filename":"src/geo/polygon.cr","line_number":29,"url":null},"def":{"name":"area","visibility":"Public","body":"@coords.each_cons_pair.sum do |lat, lng|\n lat.shoelace(lng)\nend.abs.fdiv(2)"}},{"html_id":"centroid:Geo::Coord-instance-method","name":"centroid","abstract":false,"location":{"filename":"src/geo/polygon.cr","line_number":81,"url":null},"def":{"name":"centroid","return_type":"Geo::Coord","visibility":"Public","body":"@centroid || (@centroid = calculate_centroid)"}},{"html_id":"contains?(coord:Geo::Coord):Bool-instance-method","name":"contains?","abstract":false,"args":[{"name":"coord","external_name":"coord","restriction":"Geo::Coord"}],"args_string":"(coord : Geo::Coord) : Bool","args_html":"(coord : Geo::Coord) : Bool","location":{"filename":"src/geo/polygon.cr","line_number":61,"url":null},"def":{"name":"contains?","args":[{"name":"coord","external_name":"coord","restriction":"Geo::Coord"}],"return_type":"Bool","visibility":"Public","body":"last_coord = @coords.last\nodd_nodes = false\ny, x = coord.ll\n@coords.each do |iter_coord|\n yi, xi = iter_coord.ll\n yj, xj = last_coord.ll\n if (yi < y && yj >= y) || (yj < y && yi >= y)\n if (xi + (((y - yi) / (yj - yi)) * (xj - xi))) < x\n odd_nodes = !odd_nodes\n end\n end\n last_coord = iter_coord\nend\nodd_nodes\n"}},{"html_id":"coords:Array(Geo::Coord)-instance-method","name":"coords","abstract":false,"location":{"filename":"src/geo/polygon.cr","line_number":24,"url":null},"def":{"name":"coords","visibility":"Public","body":"@coords"}},{"html_id":"size:Int32-instance-method","name":"size","doc":"Returns the number of elements in this container.","summary":"Returns the number of elements in this container.
","abstract":false,"location":{"filename":"src/geo/polygon.cr","line_number":9,"url":null},"def":{"name":"size","return_type":"Int32","visibility":"Public","body":"@size"}},{"html_id":"unsafe_fetch(index:Int)-instance-method","name":"unsafe_fetch","doc":"Returns the element at the given *index*, without doing any bounds check.\n\n`Indexable` makes sure to invoke this method with *index* in `0...size`,\nso converting negative indices to positive ones is not needed here.\n\nClients never invoke this method directly. Instead, they access\nelements with `#[](index)` and `#[]?(index)`.\n\nThis method should only be directly invoked if you are absolutely\nsure the index is in bounds, to avoid a bounds check for a small boost\nof performance.","summary":"Returns the element at the given index, without doing any bounds check.
","abstract":false,"args":[{"name":"index","external_name":"index","restriction":"Int"}],"args_string":"(index : Int)","args_html":"(index : Int)","location":{"filename":"src/geo/polygon.cr","line_number":87,"url":null},"def":{"name":"unsafe_fetch","args":[{"name":"index","external_name":"index","restriction":"Int"}],"visibility":"Public","body":"@coords[index]"}}]},{"html_id":"geo/Geo/Utils","path":"Geo/Utils.html","kind":"module","full_name":"Geo::Utils","name":"Utils","abstract":false,"locations":[{"filename":"src/geo/utils.cr","line_number":2,"url":null}],"repository_name":"geo","program":false,"enum":false,"alias":false,"const":false,"extended_modules":[{"html_id":"geo/Geo/Utils","kind":"module","full_name":"Geo::Utils","name":"Utils"}],"namespace":{"html_id":"geo/Geo","kind":"module","full_name":"Geo","name":"Geo"},"instance_methods":[{"html_id":"orientation(p:Geo::Coord,q:Geo::Coord,r:Geo::Coord)-instance-method","name":"orientation","doc":"Orientation of ordered triplet (p, q, r)\n\nOrientation of an ordered triplet of points in the plane can be\n\n* counterclockwise\n* clockwise\n* colinear\n\nThe function returns following values\n0 --> p, q and r are colinear\n1 --> Clockwise\n2 --> Counterclockwise","summary":"Orientation of ordered triplet (p, q, r)
","abstract":false,"args":[{"name":"p","external_name":"p","restriction":"Geo::Coord"},{"name":"q","external_name":"q","restriction":"Geo::Coord"},{"name":"r","external_name":"r","restriction":"Geo::Coord"}],"args_string":"(p : Geo::Coord, q : Geo::Coord, r : Geo::Coord)","args_html":"(p : Geo::Coord, q : Geo::Coord, r : Geo::Coord)","location":{"filename":"src/geo/utils.cr","line_number":17,"url":null},"def":{"name":"orientation","args":[{"name":"p","external_name":"p","restriction":"Geo::Coord"},{"name":"q","external_name":"q","restriction":"Geo::Coord"},{"name":"r","external_name":"r","restriction":"Geo::Coord"}],"visibility":"Public","body":"val = ((q.lng - p.lng) * (r.lat - q.lat)) - ((q.lat - p.lat) * (r.lng - q.lng))\nif val == 0\n return 0\nend\nval > 0 ? 1 : 2\n"}}]}]}]}} \ No newline at end of file diff --git a/js/doc.js b/js/doc.js new file mode 100644 index 0000000..45d38b9 --- /dev/null +++ b/js/doc.js @@ -0,0 +1,1099 @@ +window.CrystalDocs = (window.CrystalDocs || {}); + +CrystalDocs.base_path = (CrystalDocs.base_path || ""); + +CrystalDocs.searchIndex = (CrystalDocs.searchIndex || false); +CrystalDocs.MAX_RESULTS_DISPLAY = 140; + +CrystalDocs.runQuery = function(query) { + function searchType(type, query, results) { + var matches = []; + var matchedFields = []; + var name = type.full_name; + var i = name.lastIndexOf("::"); + if (i > 0) { + name = name.substring(i + 2); + } + var nameMatches = query.matches(name); + if (nameMatches){ + matches = matches.concat(nameMatches); + matchedFields.push("name"); + } + + var namespaceMatches = query.matchesNamespace(type.full_name); + if(namespaceMatches){ + matches = matches.concat(namespaceMatches); + matchedFields.push("name"); + } + + var docMatches = query.matches(type.doc); + if(docMatches){ + matches = matches.concat(docMatches); + matchedFields.push("doc"); + } + if (matches.length > 0) { + results.push({ + id: type.html_id, + result_type: "type", + kind: type.kind, + name: name, + full_name: type.full_name, + href: type.path, + summary: type.summary, + matched_fields: matchedFields, + matched_terms: matches + }); + } + + if (type.instance_methods) { + type.instance_methods.forEach(function(method) { + searchMethod(method, type, "instance_method", query, results); + }) + } + if (type.class_methods) { + type.class_methods.forEach(function(method) { + searchMethod(method, type, "class_method", query, results); + }) + } + if (type.constructors) { + type.constructors.forEach(function(constructor) { + searchMethod(constructor, type, "constructor", query, results); + }) + } + if (type.macros) { + type.macros.forEach(function(macro) { + searchMethod(macro, type, "macro", query, results); + }) + } + if (type.constants) { + type.constants.forEach(function(constant){ + searchConstant(constant, type, query, results); + }); + } + if (type.types) { + type.types.forEach(function(subtype){ + searchType(subtype, query, results); + }); + } + }; + + function searchMethod(method, type, kind, query, results) { + var matches = []; + var matchedFields = []; + var nameMatches = query.matchesMethod(method.name, kind, type); + if (nameMatches){ + matches = matches.concat(nameMatches); + matchedFields.push("name"); + } + + if (method.args) { + method.args.forEach(function(arg){ + var argMatches = query.matches(arg.external_name); + if (argMatches) { + matches = matches.concat(argMatches); + matchedFields.push("args"); + } + }); + } + + var docMatches = query.matches(type.doc); + if(docMatches){ + matches = matches.concat(docMatches); + matchedFields.push("doc"); + } + + if (matches.length > 0) { + var typeMatches = query.matches(type.full_name); + if (typeMatches) { + matchedFields.push("type"); + matches = matches.concat(typeMatches); + } + results.push({ + id: method.html_id, + type: type.full_name, + result_type: kind, + name: method.name, + full_name: type.full_name + "#" + method.name, + args_string: method.args_string, + summary: method.summary, + href: type.path + "#" + method.html_id, + matched_fields: matchedFields, + matched_terms: matches + }); + } + } + + function searchConstant(constant, type, query, results) { + var matches = []; + var matchedFields = []; + var nameMatches = query.matches(constant.name); + if (nameMatches){ + matches = matches.concat(nameMatches); + matchedFields.push("name"); + } + var docMatches = query.matches(constant.doc); + if(docMatches){ + matches = matches.concat(docMatches); + matchedFields.push("doc"); + } + if (matches.length > 0) { + var typeMatches = query.matches(type.full_name); + if (typeMatches) { + matchedFields.push("type"); + matches = matches.concat(typeMatches); + } + results.push({ + id: constant.id, + type: type.full_name, + result_type: "constant", + name: constant.name, + full_name: type.full_name + "#" + constant.name, + value: constant.value, + summary: constant.summary, + href: type.path + "#" + constant.id, + matched_fields: matchedFields, + matched_terms: matches + }); + } + } + + var results = []; + searchType(CrystalDocs.searchIndex.program, query, results); + return results; +}; + +CrystalDocs.rankResults = function(results, query) { + function uniqueArray(ar) { + var j = {}; + + ar.forEach(function(v) { + j[v + "::" + typeof v] = v; + }); + + return Object.keys(j).map(function(v) { + return j[v]; + }); + } + + results = results.sort(function(a, b) { + var matchedTermsDiff = uniqueArray(b.matched_terms).length - uniqueArray(a.matched_terms).length; + var aHasDocs = b.matched_fields.includes("doc"); + var bHasDocs = b.matched_fields.includes("doc"); + + var aOnlyDocs = aHasDocs && a.matched_fields.length == 1; + var bOnlyDocs = bHasDocs && b.matched_fields.length == 1; + + if (a.result_type == "type" && b.result_type != "type" && !aOnlyDocs) { + if(CrystalDocs.DEBUG) { console.log("a is type b not"); } + return -1; + } else if (b.result_type == "type" && a.result_type != "type" && !bOnlyDocs) { + if(CrystalDocs.DEBUG) { console.log("b is type, a not"); } + return 1; + } + if (a.matched_fields.includes("name")) { + if (b.matched_fields.includes("name")) { + var a_name = (CrystalDocs.prefixForType(a.result_type) || "") + ((a.result_type == "type") ? a.full_name : a.name); + var b_name = (CrystalDocs.prefixForType(b.result_type) || "") + ((b.result_type == "type") ? b.full_name : b.name); + a_name = a_name.toLowerCase(); + b_name = b_name.toLowerCase(); + for(var i = 0; i < query.normalizedTerms.length; i++) { + var term = query.terms[i].replace(/^::?|::?$/, ""); + var a_orig_index = a_name.indexOf(term); + var b_orig_index = b_name.indexOf(term); + if(CrystalDocs.DEBUG) { console.log("term: " + term + " a: " + a_name + " b: " + b_name); } + if(CrystalDocs.DEBUG) { console.log(a_orig_index, b_orig_index, a_orig_index - b_orig_index); } + if (a_orig_index >= 0) { + if (b_orig_index >= 0) { + if(CrystalDocs.DEBUG) { console.log("both have exact match", a_orig_index > b_orig_index ? -1 : 1); } + if(a_orig_index != b_orig_index) { + if(CrystalDocs.DEBUG) { console.log("both have exact match at different positions", a_orig_index > b_orig_index ? 1 : -1); } + return a_orig_index > b_orig_index ? 1 : -1; + } + } else { + if(CrystalDocs.DEBUG) { console.log("a has exact match, b not"); } + return -1; + } + } else if (b_orig_index >= 0) { + if(CrystalDocs.DEBUG) { console.log("b has exact match, a not"); } + return 1; + } + } + } else { + if(CrystalDocs.DEBUG) { console.log("a has match in name, b not"); } + return -1; + } + } else if ( + !a.matched_fields.includes("name") && + b.matched_fields.includes("name") + ) { + return 1; + } + + if (matchedTermsDiff != 0 || (aHasDocs != bHasDocs)) { + if(CrystalDocs.DEBUG) { console.log("matchedTermsDiff: " + matchedTermsDiff, aHasDocs, bHasDocs); } + return matchedTermsDiff; + } + + var matchedFieldsDiff = b.matched_fields.length - a.matched_fields.length; + if (matchedFieldsDiff != 0) { + if(CrystalDocs.DEBUG) { console.log("matched to different number of fields: " + matchedFieldsDiff); } + return matchedFieldsDiff > 0 ? 1 : -1; + } + + var nameCompare = a.name.localeCompare(b.name); + if(nameCompare != 0){ + if(CrystalDocs.DEBUG) { console.log("nameCompare resulted in: " + a.name + "<=>" + b.name + ": " + nameCompare); } + return nameCompare > 0 ? 1 : -1; + } + + if(a.matched_fields.includes("args") && b.matched_fields.includes("args")) { + for(var i = 0; i < query.terms.length; i++) { + var term = query.terms[i]; + var aIndex = a.args_string.indexOf(term); + var bIndex = b.args_string.indexOf(term); + if(CrystalDocs.DEBUG) { console.log("index of " + term + " in args_string: " + aIndex + " - " + bIndex); } + if(aIndex >= 0){ + if(bIndex >= 0){ + if(aIndex != bIndex){ + return aIndex > bIndex ? 1 : -1; + } + }else{ + return -1; + } + }else if(bIndex >= 0) { + return 1; + } + } + } + + return 0; + }); + + if (results.length > 1) { + // if we have more than two search terms, only include results with the most matches + var bestMatchedTerms = uniqueArray(results[0].matched_terms).length; + + results = results.filter(function(result) { + return uniqueArray(result.matched_terms).length + 1 >= bestMatchedTerms; + }); + } + return results; +}; + +CrystalDocs.prefixForType = function(type) { + switch (type) { + case "instance_method": + return "#"; + + case "class_method": + case "macro": + case "constructor": + return "."; + + default: + return false; + } +}; + +CrystalDocs.displaySearchResults = function(results, query) { + function sanitize(html){ + return html.replace(/<(?!\/?code)[^>]+>/g, ""); + } + + // limit results + if (results.length > CrystalDocs.MAX_RESULTS_DISPLAY) { + results = results.slice(0, CrystalDocs.MAX_RESULTS_DISPLAY); + } + + var $frag = document.createDocumentFragment(); + var $resultsElem = document.querySelector(".search-list"); + $resultsElem.innerHTML = ""; + + results.forEach(function(result, i) { + var url = CrystalDocs.base_path + result.href; + var type = false; + + var title = query.highlight(result.result_type == "type" ? result.full_name : result.name); + + var prefix = CrystalDocs.prefixForType(result.result_type); + if (prefix) { + title = "" + prefix + "" + title; + } + + title = "" + title + ""; + + if (result.args_string) { + title += + "" + query.highlight(result.args_string) + ""; + } + + $elem = document.createElement("li"); + $elem.className = "search-result search-result--" + result.result_type; + $elem.dataset.href = url; + $elem.setAttribute("title", result.full_name + " docs page"); + + var $title = document.createElement("div"); + $title.setAttribute("class", "search-result__title"); + var $titleLink = document.createElement("a"); + $titleLink.setAttribute("href", url); + + $titleLink.innerHTML = title; + $title.appendChild($titleLink); + $elem.appendChild($title); + $elem.addEventListener("click", function() { + $titleLink.click(); + }); + + if (result.result_type !== "type") { + var $type = document.createElement("div"); + $type.setAttribute("class", "search-result__type"); + $type.innerHTML = query.highlight(result.type); + $elem.appendChild($type); + } + + if(result.summary){ + var $doc = document.createElement("div"); + $doc.setAttribute("class", "search-result__doc"); + $doc.innerHTML = query.highlight(sanitize(result.summary)); + $elem.appendChild($doc); + } + + $elem.appendChild(document.createComment(JSON.stringify(result))); + $frag.appendChild($elem); + }); + + $resultsElem.appendChild($frag); + + CrystalDocs.toggleResultsList(true); +}; + +CrystalDocs.toggleResultsList = function(visible) { + if (visible) { + document.querySelector(".types-list").classList.add("hidden"); + document.querySelector(".search-results").classList.remove("hidden"); + } else { + document.querySelector(".types-list").classList.remove("hidden"); + document.querySelector(".search-results").classList.add("hidden"); + } +}; + +CrystalDocs.Query = function(string) { + this.original = string; + this.terms = string.split(/\s+/).filter(function(word) { + return CrystalDocs.Query.stripModifiers(word).length > 0; + }); + + var normalized = this.terms.map(CrystalDocs.Query.normalizeTerm); + this.normalizedTerms = normalized; + + function runMatcher(field, matcher) { + if (!field) { + return false; + } + var normalizedValue = CrystalDocs.Query.normalizeTerm(field); + + var matches = []; + normalized.forEach(function(term) { + if (matcher(normalizedValue, term)) { + matches.push(term); + } + }); + return matches.length > 0 ? matches : false; + } + + this.matches = function(field) { + return runMatcher(field, function(normalized, term) { + if (term[0] == "#" || term[0] == ".") { + return false; + } + return normalized.indexOf(term) >= 0; + }); + }; + + function namespaceMatcher(normalized, term){ + var i = term.indexOf(":"); + if(i >= 0){ + term = term.replace(/^::?|::?$/, ""); + var index = normalized.indexOf(term); + if((index == 0) || (index > 0 && normalized[index-1] == ":")){ + return true; + } + } + return false; + } + this.matchesMethod = function(name, kind, type) { + return runMatcher(name, function(normalized, term) { + var i = term.indexOf("#"); + if(i >= 0){ + if (kind != "instance_method") { + return false; + } + }else{ + i = term.indexOf("."); + if(i >= 0){ + if (kind != "class_method" && kind != "macro" && kind != "constructor") { + return false; + } + }else{ + //neither # nor . + if(term.indexOf(":") && namespaceMatcher(normalized, term)){ + return true; + } + } + } + + var methodName = term; + if(i >= 0){ + var termType = term.substring(0, i); + methodName = term.substring(i+1); + + if(termType != "") { + if(CrystalDocs.Query.normalizeTerm(type.full_name).indexOf(termType) < 0){ + return false; + } + } + } + return normalized.indexOf(methodName) >= 0; + }); + }; + + this.matchesNamespace = function(namespace){ + return runMatcher(namespace, namespaceMatcher); + }; + + this.highlight = function(string) { + if (typeof string == "undefined") { + return ""; + } + function escapeRegExp(s) { + return s.replace(/[.*+?\^${}()|\[\]\\]/g, "\\$&").replace(/^[#\.:]+/, ""); + } + return string.replace( + new RegExp("(" + this.normalizedTerms.map(escapeRegExp).join("|") + ")", "gi"), + "$1" + ); + }; +}; +CrystalDocs.Query.normalizeTerm = function(term) { + return term.toLowerCase(); +}; +CrystalDocs.Query.stripModifiers = function(term) { + switch (term[0]) { + case "#": + case ".": + case ":": + return term.substr(1); + + default: + return term; + } +} + +CrystalDocs.search = function(string) { + if(!CrystalDocs.searchIndex) { + console.log("CrystalDocs search index not initialized, delaying search"); + + document.addEventListener("CrystalDocs:loaded", function listener(){ + document.removeEventListener("CrystalDocs:loaded", listener); + CrystalDocs.search(string); + }); + return; + } + + document.dispatchEvent(new Event("CrystalDocs:searchStarted")); + + var query = new CrystalDocs.Query(string); + var results = CrystalDocs.runQuery(query); + results = CrystalDocs.rankResults(results, query); + CrystalDocs.displaySearchResults(results, query); + + document.dispatchEvent(new Event("CrystalDocs:searchPerformed")); +}; + +CrystalDocs.initializeIndex = function(data) { + CrystalDocs.searchIndex = data; + + document.dispatchEvent(new Event("CrystalDocs:loaded")); +}; + +CrystalDocs.loadIndex = function() { + function loadJSON(file, callback) { + var xobj = new XMLHttpRequest(); + xobj.overrideMimeType("application/json"); + xobj.open("GET", file, true); + xobj.onreadystatechange = function() { + if (xobj.readyState == 4 && xobj.status == "200") { + callback(xobj.responseText); + } + }; + xobj.send(null); + } + + function loadScript(file) { + script = document.createElement("script"); + script.src = file; + document.body.appendChild(script); + } + + function parseJSON(json) { + CrystalDocs.initializeIndex(JSON.parse(json)); + } + + for(var i = 0; i < document.scripts.length; i++){ + var script = document.scripts[i]; + if (script.src && script.src.indexOf("js/doc.js") >= 0) { + if (script.src.indexOf("file://") == 0) { + // We need to support JSONP files for the search to work on local file system. + var jsonPath = script.src.replace("js/doc.js", "search-index.js"); + loadScript(jsonPath); + return; + } else { + var jsonPath = script.src.replace("js/doc.js", "index.json"); + loadJSON(jsonPath, parseJSON); + return; + } + } + } + console.error("Could not find location of js/doc.js"); +}; + +// Callback for jsonp +function crystal_doc_search_index_callback(data) { + CrystalDocs.initializeIndex(data); +} + +Navigator = function(sidebar, searchInput, list, leaveSearchScope){ + this.list = list; + var self = this; + + var performingSearch = false; + + document.addEventListener('CrystalDocs:searchStarted', function(){ + performingSearch = true; + }); + document.addEventListener('CrystalDocs:searchDebounceStarted', function(){ + performingSearch = true; + }); + document.addEventListener('CrystalDocs:searchPerformed', function(){ + performingSearch = false; + }); + document.addEventListener('CrystalDocs:searchDebounceStopped', function(event){ + performingSearch = false; + }); + + function delayWhileSearching(callback) { + if(performingSearch){ + document.addEventListener('CrystalDocs:searchPerformed', function listener(){ + document.removeEventListener('CrystalDocs:searchPerformed', listener); + + // add some delay to let search results display kick in + setTimeout(callback, 100); + }); + }else{ + callback(); + } + } + + function clearMoveTimeout() { + clearTimeout(self.moveTimeout); + self.moveTimeout = null; + } + + function startMoveTimeout(upwards){ + /*if(self.moveTimeout) { + clearMoveTimeout(); + } + + var go = function() { + if (!self.moveTimeout) return; + self.move(upwards); + self.moveTimeout = setTimeout(go, 600); + }; + self.moveTimeout = setTimeout(go, 800);*/ + } + + function scrollCenter(element) { + var rect = element.getBoundingClientRect(); + var middle = sidebar.clientHeight / 2; + sidebar.scrollTop += rect.top + rect.height / 2 - middle; + } + + var move = this.move = function(upwards){ + if(!this.current){ + this.highlightFirst(); + return true; + } + var next = upwards ? this.current.previousElementSibling : this.current.nextElementSibling; + if(next && next.classList) { + this.highlight(next); + scrollCenter(next); + return true; + } + return false; + }; + + this.moveRight = function(){ + }; + this.moveLeft = function(){ + }; + + this.highlight = function(elem) { + if(!elem){ + return; + } + this.removeHighlight(); + + this.current = elem; + this.current.classList.add("current"); + }; + + this.highlightFirst = function(){ + this.highlight(this.list.querySelector('li:first-child')); + }; + + this.removeHighlight = function() { + if(this.current){ + this.current.classList.remove("current"); + } + this.current = null; + } + + this.openSelectedResult = function() { + if(this.current) { + this.current.click(); + } + } + + this.focus = function() { + searchInput.focus(); + searchInput.select(); + this.highlightFirst(); + } + + function handleKeyUp(event) { + switch(event.key) { + case "ArrowUp": + case "ArrowDown": + case "i": + case "j": + case "k": + case "l": + case "c": + case "h": + case "t": + case "n": + event.stopPropagation(); + clearMoveTimeout(); + } + } + + function handleKeyDown(event) { + switch(event.key) { + case "Enter": + event.stopPropagation(); + event.preventDefault(); + leaveSearchScope(); + self.openSelectedResult(); + break; + case "Escape": + event.stopPropagation(); + event.preventDefault(); + leaveSearchScope(); + break; + case "j": + case "c": + case "ArrowUp": + if(event.ctrlKey || event.key == "ArrowUp") { + event.stopPropagation(); + self.move(true); + startMoveTimeout(true); + } + break; + case "k": + case "h": + case "ArrowDown": + if(event.ctrlKey || event.key == "ArrowDown") { + event.stopPropagation(); + self.move(false); + startMoveTimeout(false); + } + break; + case "k": + case "t": + case "ArrowLeft": + if(event.ctrlKey || event.key == "ArrowLeft") { + event.stopPropagation(); + self.moveLeft(); + } + break; + case "l": + case "n": + case "ArrowRight": + if(event.ctrlKey || event.key == "ArrowRight") { + event.stopPropagation(); + self.moveRight(); + } + break; + } + } + + function handleInputKeyUp(event) { + switch(event.key) { + case "ArrowUp": + case "ArrowDown": + event.stopPropagation(); + event.preventDefault(); + clearMoveTimeout(); + } + } + + function handleInputKeyDown(event) { + switch(event.key) { + case "Enter": + event.stopPropagation(); + event.preventDefault(); + delayWhileSearching(function(){ + self.openSelectedResult(); + leaveSearchScope(); + }); + break; + case "Escape": + event.stopPropagation(); + event.preventDefault(); + // remove focus from search input + leaveSearchScope(); + sidebar.focus(); + break; + case "ArrowUp": + event.stopPropagation(); + event.preventDefault(); + self.move(true); + startMoveTimeout(true); + break; + + case "ArrowDown": + event.stopPropagation(); + event.preventDefault(); + self.move(false); + startMoveTimeout(false); + break; + } + } + + sidebar.tabIndex = 100; // set tabIndex to enable keylistener + sidebar.addEventListener('keyup', function(event) { + handleKeyUp(event); + }); + sidebar.addEventListener('keydown', function(event) { + handleKeyDown(event); + }); + searchInput.addEventListener('keydown', function(event) { + handleInputKeyDown(event); + }); + searchInput.addEventListener('keyup', function(event) { + handleInputKeyUp(event); + }); + this.move(); +}; + +CrystalDocs.initializeVersions = function () { + function loadJSON(file, callback) { + var xobj = new XMLHttpRequest(); + xobj.overrideMimeType("application/json"); + xobj.open("GET", file, true); + xobj.onreadystatechange = function() { + if (xobj.readyState == 4 && xobj.status == "200") { + callback(xobj.responseText); + } + }; + xobj.send(null); + } + + function parseJSON(json) { + CrystalDocs.loadConfig(JSON.parse(json)); + } + + $elem = document.querySelector("html > head > meta[name=\"crystal_docs.json_config_url\"]") + if ($elem == undefined) { + return + } + jsonURL = $elem.getAttribute("content") + if (jsonURL && jsonURL != "") { + loadJSON(jsonURL, parseJSON); + } +} + +CrystalDocs.loadConfig = function (config) { + var projectVersions = config["versions"] + var currentVersion = document.querySelector("html > head > meta[name=\"crystal_docs.project_version\"]").getAttribute("content") + + var currentVersionInList = projectVersions.find(function (element) { + return element.name == currentVersion + }) + + if (!currentVersionInList) { + projectVersions.unshift({ name: currentVersion, url: '#' }) + } + + $version = document.querySelector(".project-summary > .project-version") + $version.innerHTML = "" + + $select = document.createElement("select") + $select.classList.add("project-versions-nav") + $select.addEventListener("change", function () { + window.location.href = this.value + }) + projectVersions.forEach(function (version) { + $item = document.createElement("option") + $item.setAttribute("value", version.url) + $item.append(document.createTextNode(version.name)) + + if (version.name == currentVersion) { + $item.setAttribute("selected", true) + $item.setAttribute("disabled", true) + } + $select.append($item) + }); + $form = document.createElement("form") + $form.setAttribute("autocomplete", "off") + $form.append($select) + $version.append($form) +} + +document.addEventListener("DOMContentLoaded", function () { + CrystalDocs.initializeVersions() +}) + +var UsageModal = function(title, content) { + var $body = document.body; + var self = this; + var $modalBackground = document.createElement("div"); + $modalBackground.classList.add("modal-background"); + var $usageModal = document.createElement("div"); + $usageModal.classList.add("usage-modal"); + $modalBackground.appendChild($usageModal); + var $title = document.createElement("h3"); + $title.classList.add("modal-title"); + $title.innerHTML = title + $usageModal.appendChild($title); + var $closeButton = document.createElement("span"); + $closeButton.classList.add("close-button"); + $closeButton.setAttribute("title", "Close modal"); + $closeButton.innerText = '×'; + $usageModal.appendChild($closeButton); + $usageModal.insertAdjacentHTML("beforeend", content); + + $modalBackground.addEventListener('click', function(event) { + var element = event.target || event.srcElement; + + if(element == $modalBackground) { + self.hide(); + } + }); + $closeButton.addEventListener('click', function(event) { + self.hide(); + }); + + $body.insertAdjacentElement('beforeend', $modalBackground); + + this.show = function(){ + $body.classList.add("js-modal-visible"); + }; + this.hide = function(){ + $body.classList.remove("js-modal-visible"); + }; + this.isVisible = function(){ + return $body.classList.contains("js-modal-visible"); + } +} + + +document.addEventListener('DOMContentLoaded', function() { + var sessionStorage; + try { + sessionStorage = window.sessionStorage; + } catch (e) { } + if(!sessionStorage) { + sessionStorage = { + setItem: function() {}, + getItem: function() {}, + removeItem: function() {} + }; + } + + var repositoryName = document.querySelector('[name=repository-name]').getAttribute('content'); + var typesList = document.querySelector('.types-list'); + var searchInput = document.querySelector('.search-input'); + var parents = document.querySelectorAll('.types-list li.parent'); + + var scrollSidebarToOpenType = function(){ + var openTypes = typesList.querySelectorAll('.current'); + if (openTypes.length > 0) { + var lastOpenType = openTypes[openTypes.length - 1]; + lastOpenType.scrollIntoView(!(window.matchMedia('only screen and (max-width: 635px)')).matches); + } + } + + scrollSidebarToOpenType(); + + var setPersistentSearchQuery = function(value){ + sessionStorage.setItem(repositoryName + '::search-input:value', value); + } + + for(var i = 0; i < parents.length; i++) { + var _parent = parents[i]; + _parent.addEventListener('click', function(e) { + e.stopPropagation(); + + if(e.target.tagName.toLowerCase() == 'li') { + if(e.target.className.match(/open/)) { + sessionStorage.removeItem(e.target.getAttribute('data-id')); + e.target.className = e.target.className.replace(/ +open/g, ''); + } else { + sessionStorage.setItem(e.target.getAttribute('data-id'), '1'); + if(e.target.className.indexOf('open') == -1) { + e.target.className += ' open'; + } + } + } + }); + + if(sessionStorage.getItem(_parent.getAttribute('data-id')) == '1') { + _parent.className += ' open'; + } + } + + var leaveSearchScope = function(){ + CrystalDocs.toggleResultsList(false); + window.focus(); + } + + var navigator = new Navigator(document.querySelector('.types-list'), searchInput, document.querySelector(".search-results"), leaveSearchScope); + + CrystalDocs.loadIndex(); + var searchTimeout; + var lastSearchText = false; + var performSearch = function() { + document.dispatchEvent(new Event("CrystalDocs:searchDebounceStarted")); + + clearTimeout(searchTimeout); + searchTimeout = setTimeout(function() { + var text = searchInput.value; + + if(text == "") { + CrystalDocs.toggleResultsList(false); + }else if(text == lastSearchText){ + document.dispatchEvent(new Event("CrystalDocs:searchDebounceStopped")); + }else{ + CrystalDocs.search(text); + navigator.highlightFirst(); + searchInput.focus(); + } + lastSearchText = text; + setPersistentSearchQuery(text); + }, 200); + }; + + if(location.hash.length > 3 && location.hash.substring(0,3) == "#q="){ + // allows directly linking a search query which is then executed on the client + // this comes handy for establishing a custom browser search engine with https://crystal-lang.org/api/#q=%s as a search URL + // TODO: Add OpenSearch description + var searchQuery = location.hash.substring(3); + history.pushState({searchQuery: searchQuery}, "Search for " + searchQuery, location.href.replace(/#q=.*/, "")); + searchInput.value = searchQuery; + document.addEventListener('CrystalDocs:loaded', performSearch); + } + + if (searchInput.value.length == 0) { + var searchText = sessionStorage.getItem(repositoryName + '::search-input:value'); + if(searchText){ + searchInput.value = searchText; + } + } + searchInput.addEventListener('keyup', performSearch); + searchInput.addEventListener('input', performSearch); + + var usageModal = new UsageModal('Keyboard Shortcuts', '' + + 'A Coord
is a point in geographical coordinates: latitude and longitude.
The comparison operator.
","abstract":false,"args":[{"name":"other","external_name":"other","restriction":"Geo::Coord"}],"args_string":"(other : Geo::Coord)","args_html":"(other : Geo::Coord)","location":{"filename":"src/geo/coord.cr","line_number":173,"url":null},"def":{"name":"<=>","args":[{"name":"other","external_name":"other","restriction":"Geo::Coord"}],"visibility":"Public","body":"ll <=> other.ll"}},{"html_id":"bearing(to:Geo::Coord,final=false):Float64-instance-method","name":"bearing","doc":"Calculates initial and final bearings between two points using great-circle distance formulas","summary":"Calculates initial and final bearings between two points using great-circle distance formulas
","abstract":false,"args":[{"name":"to","external_name":"to","restriction":"Geo::Coord"},{"name":"final","default_value":"false","external_name":"final","restriction":""}],"args_string":"(to : Geo::Coord, final = false) : Float64","args_html":"(to : Geo::Coord, final = false) : Float64","location":{"filename":"src/geo/bearing.cr","line_number":4,"url":null},"def":{"name":"bearing","args":[{"name":"to","external_name":"to","restriction":"Geo::Coord"},{"name":"final","default_value":"false","external_name":"final","restriction":""}],"return_type":"Float64","visibility":"Public","body":"Geo::Bearing.bearing(lat, lng, to.lat, to.lng, final)"}},{"html_id":"between?(p1:Geo::Coord,p2:Geo::Coord)-instance-method","name":"between?","abstract":false,"args":[{"name":"p1","external_name":"p1","restriction":"Geo::Coord"},{"name":"p2","external_name":"p2","restriction":"Geo::Coord"}],"args_string":"(p1 : Geo::Coord, p2 : Geo::Coord)","args_html":"(p1 : Geo::Coord, p2 : Geo::Coord)","location":{"filename":"src/geo/coord.cr","line_number":177,"url":null},"def":{"name":"between?","args":[{"name":"p1","external_name":"p1","restriction":"Geo::Coord"},{"name":"p2","external_name":"p2","restriction":"Geo::Coord"}],"visibility":"Public","body":"min, max = [p1, p2].minmax\nif cmp = self <=> min\n if cmp < 0\n return false\n end\nend\nif cmp = self <=> max\n if cmp > 0\n return false\n end\nend\ntrue\n"}},{"html_id":"distance(other:Geo::Coord):Haversine::Distance-instance-method","name":"distance","doc":"Calculates distance to `other`.\nHaversine formula is used.","summary":"Calculates distance to other
.
Returns a geohash representing coordinates.
","abstract":false,"args":[{"name":"precision","default_value":"12","external_name":"precision","restriction":""}],"args_string":"(precision = 12)","args_html":"(precision = 12)","location":{"filename":"src/geo/coord.cr","line_number":155,"url":null},"def":{"name":"geohash","args":[{"name":"precision","default_value":"12","external_name":"precision","restriction":""}],"visibility":"Public","body":"Geohash.encode(lat.to_f, lng.to_f, precision)"}},{"html_id":"lat:Float32|Float64|Int32-instance-method","name":"lat","abstract":false,"location":{"filename":"src/geo/coord.cr","line_number":8,"url":null},"def":{"name":"lat","visibility":"Public","body":"@lat"}},{"html_id":"latd:Int32-instance-method","name":"latd","doc":"Returns latitude degrees","summary":"Returns latitude degrees
","abstract":false,"location":{"filename":"src/geo/coord.cr","line_number":36,"url":null},"def":{"name":"latd","return_type":"Int32","visibility":"Public","body":"lat.abs.to_i"}},{"html_id":"latds-instance-method","name":"latds","abstract":false,"location":{"filename":"src/geo/coord.cr","line_number":75,"url":null},"def":{"name":"latds","visibility":"Public","body":"lat.to_i"}},{"html_id":"lath:String-instance-method","name":"lath","doc":"Returns latitude hemisphere","summary":"Returns latitude hemisphere
","abstract":false,"location":{"filename":"src/geo/coord.cr","line_number":51,"url":null},"def":{"name":"lath","return_type":"String","visibility":"Public","body":"lat > 0 ? \"N\" : \"S\""}},{"html_id":"latm:Int32-instance-method","name":"latm","doc":"Returns latitude minutes","summary":"Returns latitude minutes
","abstract":false,"location":{"filename":"src/geo/coord.cr","line_number":41,"url":null},"def":{"name":"latm","return_type":"Int32","visibility":"Public","body":"(lat.abs * 60).to_i % 60"}},{"html_id":"lats:Number-instance-method","name":"lats","doc":"Returns latitude seconds","summary":"Returns latitude seconds
","abstract":false,"location":{"filename":"src/geo/coord.cr","line_number":46,"url":null},"def":{"name":"lats","return_type":"Number","visibility":"Public","body":"(lat.abs * 3600) % 60"}},{"html_id":"ll-instance-method","name":"ll","abstract":false,"location":{"filename":"src/geo/coord.cr","line_number":169,"url":null},"def":{"name":"ll","visibility":"Public","body":"{lat, lng}"}},{"html_id":"lng:Float32|Float64|Int32-instance-method","name":"lng","abstract":false,"location":{"filename":"src/geo/coord.cr","line_number":9,"url":null},"def":{"name":"lng","visibility":"Public","body":"@lng"}},{"html_id":"lngd:Int32-instance-method","name":"lngd","doc":"Returns longitude degrees","summary":"Returns longitude degrees
","abstract":false,"location":{"filename":"src/geo/coord.cr","line_number":56,"url":null},"def":{"name":"lngd","return_type":"Int32","visibility":"Public","body":"lng.abs.to_i"}},{"html_id":"lngds-instance-method","name":"lngds","abstract":false,"location":{"filename":"src/geo/coord.cr","line_number":79,"url":null},"def":{"name":"lngds","visibility":"Public","body":"lng.to_i"}},{"html_id":"lngh:String-instance-method","name":"lngh","doc":"Returns longitude hemisphere","summary":"Returns longitude hemisphere
","abstract":false,"location":{"filename":"src/geo/coord.cr","line_number":71,"url":null},"def":{"name":"lngh","return_type":"String","visibility":"Public","body":"lng > 0 ? \"E\" : \"W\""}},{"html_id":"lngm:Int32-instance-method","name":"lngm","doc":"Returns longitude minutes","summary":"Returns longitude minutes
","abstract":false,"location":{"filename":"src/geo/coord.cr","line_number":61,"url":null},"def":{"name":"lngm","return_type":"Int32","visibility":"Public","body":"(lng.abs * 60).to_i % 60"}},{"html_id":"lngs:Number-instance-method","name":"lngs","doc":"Returns longitude seconds","summary":"Returns longitude seconds
","abstract":false,"location":{"filename":"src/geo/coord.cr","line_number":66,"url":null},"def":{"name":"lngs","return_type":"Number","visibility":"Public","body":"(lng.abs * 3600) % 60"}},{"html_id":"shoelace(other:Geo::Coord)-instance-method","name":"shoelace","abstract":false,"args":[{"name":"other","external_name":"other","restriction":"Geo::Coord"}],"args_string":"(other : Geo::Coord)","args_html":"(other : Geo::Coord)","location":{"filename":"src/geo/coord.cr","line_number":191,"url":null},"def":{"name":"shoelace","args":[{"name":"other","external_name":"other","restriction":"Geo::Coord"}],"visibility":"Public","body":"(lat * other.lng) - (lng * other.lat)"}},{"html_id":"strfcoord(formatstr):String-instance-method","name":"strfcoord","doc":"Formats coordinates according to directives in `formatstr`.\n\nEach directive starts with `%` and can contain some modifiers before its name.\n\nAcceptable modifiers:\n- unsigned integers: none;\n- signed integers: `+` for mandatory sign printing;\n- floats: same as integers and number of digits modifier, like `0.3`.\n\nList of directives:\n\n- `%lat` - Full latitude, floating point, signed\n- `%latds` - Latitude degrees, integer, signed\n- `%latd` - Latitude degrees, integer, unsigned\n- `%latm` - Latitude minutes, integer, unsigned\n- `%lats` - Latitude seconds, floating point, unsigned\n- `%lath` - Latitude hemisphere, \"N\" or \"S\"\n- `%lng` - Full longitude, floating point, signed\n- `%lngds` - Longitude degrees, integer, signed\n- `%lngd` - Longitude degrees, integer, unsigned\n- `%lngm` - Longitude minutes, integer, unsigned\n- `lngs` - Longitude seconds, floating point, unsigned\n- `%lngh`` - Longitude hemisphere, \"E\" or \"W\"\n\nExamples:\n\n```\ng = Geo::Coord.new(50.004444, 36.231389)\ng.strfcoord('%+lat, %+lng')\n# => \"+50.004444, +36.231389\"\ng.strfcoord(\"%latd°%latm'%lath -- %lngd°%lngm'%lngh\")\n# => \"50°0'N -- 36°13'E\"\n```\n\n`strfcoord` handles seconds rounding implicitly:\n\n```\npos = Geo::Coord.new(0.033333, 91.333333)\npos.strfcoord('%latd %latm %0.5lats') # => \"0 1 59.99880\"\npos.strfcoord('%latd %latm %lats') # => \"0 2 0\"\n```","summary":"Formats coordinates according to directives in formatstr
.
Returns a string representing coordinates.
","abstract":false,"args":[{"name":"io","external_name":"io","restriction":""}],"args_string":"(io)","args_html":"(io)","location":{"filename":"src/geo/coord.cr","line_number":165,"url":null},"def":{"name":"to_s","args":[{"name":"io","external_name":"io","restriction":""}],"visibility":"Public","body":"io << (strfcoord(\"%latd°%latm'%lats\\\"%lath %lngd°%lngm'%lngs\\\"%lngh\"))"}}],"types":[{"html_id":"geo/Geo/Coord/Number","path":"Geo/Coord/Number.html","kind":"alias","full_name":"Geo::Coord::Number","name":"Number","abstract":false,"locations":[{"filename":"src/geo/coord.cr","line_number":6,"url":null}],"repository_name":"geo","program":false,"enum":false,"alias":true,"aliased":"(Float32 | Float64 | Int32)","aliased_html":"Float32 | Float64 | Int32","const":false,"namespace":{"html_id":"geo/Geo/Coord","kind":"struct","full_name":"Geo::Coord","name":"Coord"}}]},{"html_id":"geo/Geo/Polygon","path":"Geo/Polygon.html","kind":"struct","full_name":"Geo::Polygon","name":"Polygon","abstract":false,"superclass":{"html_id":"geo/Struct","kind":"struct","full_name":"Struct","name":"Struct"},"ancestors":[{"html_id":"geo/Indexable","kind":"module","full_name":"Indexable","name":"Indexable"},{"html_id":"geo/Enumerable","kind":"module","full_name":"Enumerable","name":"Enumerable"},{"html_id":"geo/Iterable","kind":"module","full_name":"Iterable","name":"Iterable"},{"html_id":"geo/Struct","kind":"struct","full_name":"Struct","name":"Struct"},{"html_id":"geo/Value","kind":"struct","full_name":"Value","name":"Value"},{"html_id":"geo/Object","kind":"class","full_name":"Object","name":"Object"}],"locations":[{"filename":"src/geo/polygon.cr","line_number":5,"url":null}],"repository_name":"geo","program":false,"enum":false,"alias":false,"const":false,"included_modules":[{"html_id":"geo/Indexable","kind":"module","full_name":"Indexable","name":"Indexable"}],"namespace":{"html_id":"geo/Geo","kind":"module","full_name":"Geo","name":"Geo"},"doc":"A `Polygon` is a fixed-size, immutable, stack-allocated sequence of `Geo::Coord`.\nCoordinates are in lexicographical order.\nAdditionally, polygons form a closed loop and define a filled region.","summary":"A Polygon
is a fixed-size, immutable, stack-allocated sequence of Geo::Coord
.
Evaluate area of a polygon using shoelace formula
","abstract":false,"location":{"filename":"src/geo/polygon.cr","line_number":29,"url":null},"def":{"name":"area","visibility":"Public","body":"@coords.each_cons_pair.sum do |lat, lng|\n lat.shoelace(lng)\nend.abs.fdiv(2)"}},{"html_id":"centroid:Geo::Coord-instance-method","name":"centroid","abstract":false,"location":{"filename":"src/geo/polygon.cr","line_number":81,"url":null},"def":{"name":"centroid","return_type":"Geo::Coord","visibility":"Public","body":"@centroid || (@centroid = calculate_centroid)"}},{"html_id":"contains?(coord:Geo::Coord):Bool-instance-method","name":"contains?","abstract":false,"args":[{"name":"coord","external_name":"coord","restriction":"Geo::Coord"}],"args_string":"(coord : Geo::Coord) : Bool","args_html":"(coord : Geo::Coord) : Bool","location":{"filename":"src/geo/polygon.cr","line_number":61,"url":null},"def":{"name":"contains?","args":[{"name":"coord","external_name":"coord","restriction":"Geo::Coord"}],"return_type":"Bool","visibility":"Public","body":"last_coord = @coords.last\nodd_nodes = false\ny, x = coord.ll\n@coords.each do |iter_coord|\n yi, xi = iter_coord.ll\n yj, xj = last_coord.ll\n if (yi < y && yj >= y) || (yj < y && yi >= y)\n if (xi + (((y - yi) / (yj - yi)) * (xj - xi))) < x\n odd_nodes = !odd_nodes\n end\n end\n last_coord = iter_coord\nend\nodd_nodes\n"}},{"html_id":"coords:Array(Geo::Coord)-instance-method","name":"coords","abstract":false,"location":{"filename":"src/geo/polygon.cr","line_number":24,"url":null},"def":{"name":"coords","visibility":"Public","body":"@coords"}},{"html_id":"size:Int32-instance-method","name":"size","doc":"Returns the number of elements in this container.","summary":"Returns the number of elements in this container.
","abstract":false,"location":{"filename":"src/geo/polygon.cr","line_number":9,"url":null},"def":{"name":"size","return_type":"Int32","visibility":"Public","body":"@size"}},{"html_id":"unsafe_fetch(index:Int)-instance-method","name":"unsafe_fetch","doc":"Returns the element at the given *index*, without doing any bounds check.\n\n`Indexable` makes sure to invoke this method with *index* in `0...size`,\nso converting negative indices to positive ones is not needed here.\n\nClients never invoke this method directly. Instead, they access\nelements with `#[](index)` and `#[]?(index)`.\n\nThis method should only be directly invoked if you are absolutely\nsure the index is in bounds, to avoid a bounds check for a small boost\nof performance.","summary":"Returns the element at the given index, without doing any bounds check.
","abstract":false,"args":[{"name":"index","external_name":"index","restriction":"Int"}],"args_string":"(index : Int)","args_html":"(index : Int)","location":{"filename":"src/geo/polygon.cr","line_number":87,"url":null},"def":{"name":"unsafe_fetch","args":[{"name":"index","external_name":"index","restriction":"Int"}],"visibility":"Public","body":"@coords[index]"}}]},{"html_id":"geo/Geo/Utils","path":"Geo/Utils.html","kind":"module","full_name":"Geo::Utils","name":"Utils","abstract":false,"locations":[{"filename":"src/geo/utils.cr","line_number":2,"url":null}],"repository_name":"geo","program":false,"enum":false,"alias":false,"const":false,"extended_modules":[{"html_id":"geo/Geo/Utils","kind":"module","full_name":"Geo::Utils","name":"Utils"}],"namespace":{"html_id":"geo/Geo","kind":"module","full_name":"Geo","name":"Geo"},"instance_methods":[{"html_id":"orientation(p:Geo::Coord,q:Geo::Coord,r:Geo::Coord)-instance-method","name":"orientation","doc":"Orientation of ordered triplet (p, q, r)\n\nOrientation of an ordered triplet of points in the plane can be\n\n* counterclockwise\n* clockwise\n* colinear\n\nThe function returns following values\n0 --> p, q and r are colinear\n1 --> Clockwise\n2 --> Counterclockwise","summary":"Orientation of ordered triplet (p, q, r)
","abstract":false,"args":[{"name":"p","external_name":"p","restriction":"Geo::Coord"},{"name":"q","external_name":"q","restriction":"Geo::Coord"},{"name":"r","external_name":"r","restriction":"Geo::Coord"}],"args_string":"(p : Geo::Coord, q : Geo::Coord, r : Geo::Coord)","args_html":"(p : Geo::Coord, q : Geo::Coord, r : Geo::Coord)","location":{"filename":"src/geo/utils.cr","line_number":17,"url":null},"def":{"name":"orientation","args":[{"name":"p","external_name":"p","restriction":"Geo::Coord"},{"name":"q","external_name":"q","restriction":"Geo::Coord"},{"name":"r","external_name":"r","restriction":"Geo::Coord"}],"visibility":"Public","body":"val = ((q.lng - p.lng) * (r.lat - q.lat)) - ((q.lat - p.lat) * (r.lng - q.lng))\nif val == 0\n return 0\nend\nval > 0 ? 1 : 2\n"}}]}]}]}}) \ No newline at end of file