trollio_maps 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +73 -0
- data/README.md +5 -0
- data/assets/Inter-Regular.ttf +0 -0
- data/bin/trollio-maps +32 -0
- data/mapreversegeocode.gif +0 -0
- data/src/config.rb +13 -0
- data/src/map/control.rb +79 -0
- data/src/map/error.rb +3 -0
- data/src/map/geo/crs/EPSG3857.rb +18 -0
- data/src/map/geo/crs/earth.rb +25 -0
- data/src/map/geo/crs.rb +51 -0
- data/src/map/geo/lat_lng.rb +57 -0
- data/src/map/geo/lat_lng_bounds.rb +59 -0
- data/src/map/geo/projections/lon_lat.rb +0 -0
- data/src/map/geo/projections/mercator.rb +0 -0
- data/src/map/geo/projections/spherical_mercator.rb +32 -0
- data/src/map/geo.rb +4 -0
- data/src/map/geometry/bounds.rb +101 -0
- data/src/map/geometry/bounds_collection.rb +61 -0
- data/src/map/geometry/point.rb +105 -0
- data/src/map/geometry/tile_bounds.rb +110 -0
- data/src/map/geometry/transform.rb +26 -0
- data/src/map/geometry.rb +5 -0
- data/src/map/layers/marker_layer.rb +30 -0
- data/src/map/layers/tile_layer.rb +176 -0
- data/src/map/layers.rb +2 -0
- data/src/map.rb +239 -0
- metadata +95 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 92688303a3b5c3353ac85142ccd4a61b17a22ad0c5889ccdac2e85252bcc3b71
|
4
|
+
data.tar.gz: f23a95aa6540a93d639e58bb6a0c26c995c691d388782922af1d504c83fe874f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 39f419c0b08bceeedb88b44fe70767a653e878a1f3e42c9b362ac1b98547ccf9eaac0b4ef571f73948ea9281a06340e60a24dd6e5b2d0a3c9828158891716648
|
7
|
+
data.tar.gz: d919e1909473b20332e170c31c3c3796f67e8a2d8e238d80c4fe167d94a9e4c935c2812d973dac5cf7c5b09a4b998a499affd2676856af135109fb43a9dd9224
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
src/map/layers/downloads/
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://www.rubygems.org/
|
3
|
+
specs:
|
4
|
+
concurrent-ruby (1.3.5)
|
5
|
+
domain_name (0.6.20240107)
|
6
|
+
ffi (1.17.2)
|
7
|
+
ffi (1.17.2-aarch64-linux-gnu)
|
8
|
+
ffi (1.17.2-aarch64-linux-musl)
|
9
|
+
ffi (1.17.2-arm-linux-gnu)
|
10
|
+
ffi (1.17.2-arm-linux-musl)
|
11
|
+
ffi (1.17.2-arm64-darwin)
|
12
|
+
ffi (1.17.2-x86-linux-gnu)
|
13
|
+
ffi (1.17.2-x86-linux-musl)
|
14
|
+
ffi (1.17.2-x86_64-darwin)
|
15
|
+
ffi (1.17.2-x86_64-linux-gnu)
|
16
|
+
ffi (1.17.2-x86_64-linux-musl)
|
17
|
+
hokusai-zero (0.1.9)
|
18
|
+
concurrent-ruby (~> 1.3.4)
|
19
|
+
ffi (~> 1.16)
|
20
|
+
memory_profiler
|
21
|
+
mini_portile2
|
22
|
+
raylib-bindings (~> 0.7.9)
|
23
|
+
sdl2-bindings (~> 0.2.3)
|
24
|
+
http-accept (1.7.0)
|
25
|
+
http-cookie (1.0.8)
|
26
|
+
domain_name (~> 0.5)
|
27
|
+
logger (1.7.0)
|
28
|
+
memory_profiler (1.1.0)
|
29
|
+
mime-types (3.7.0)
|
30
|
+
logger
|
31
|
+
mime-types-data (~> 3.2025, >= 3.2025.0507)
|
32
|
+
mime-types-data (3.2025.0520)
|
33
|
+
mini_portile2 (2.8.9)
|
34
|
+
netrc (0.11.0)
|
35
|
+
raylib-bindings (0.7.12)
|
36
|
+
ffi (~> 1.16)
|
37
|
+
raylib-bindings (0.7.12-aarch64-linux)
|
38
|
+
ffi (~> 1.16)
|
39
|
+
raylib-bindings (0.7.12-arm64-darwin)
|
40
|
+
ffi (~> 1.16)
|
41
|
+
raylib-bindings (0.7.12-x86_64-darwin)
|
42
|
+
ffi (~> 1.16)
|
43
|
+
raylib-bindings (0.7.12-x86_64-linux)
|
44
|
+
ffi (~> 1.16)
|
45
|
+
rest-client (2.1.0)
|
46
|
+
http-accept (>= 1.7.0, < 2.0)
|
47
|
+
http-cookie (>= 1.0.2, < 2.0)
|
48
|
+
mime-types (>= 1.16, < 4.0)
|
49
|
+
netrc (~> 0.8)
|
50
|
+
sdl2-bindings (0.2.3)
|
51
|
+
ffi (~> 1.15)
|
52
|
+
|
53
|
+
PLATFORMS
|
54
|
+
aarch64-linux
|
55
|
+
aarch64-linux-gnu
|
56
|
+
aarch64-linux-musl
|
57
|
+
arm-linux-gnu
|
58
|
+
arm-linux-musl
|
59
|
+
arm64-darwin
|
60
|
+
ruby
|
61
|
+
x86-linux-gnu
|
62
|
+
x86-linux-musl
|
63
|
+
x86_64-darwin
|
64
|
+
x86_64-linux
|
65
|
+
x86_64-linux-gnu
|
66
|
+
x86_64-linux-musl
|
67
|
+
|
68
|
+
DEPENDENCIES
|
69
|
+
hokusai-zero (= 0.1.9)
|
70
|
+
rest-client
|
71
|
+
|
72
|
+
BUNDLED WITH
|
73
|
+
2.6.8
|
data/README.md
ADDED
Binary file
|
data/bin/trollio-maps
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'mini_portile2'
|
3
|
+
require "pathname"
|
4
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
5
|
+
Pathname.new(__FILE__).realpath)
|
6
|
+
|
7
|
+
require 'rubygems'
|
8
|
+
require 'bundler/setup'
|
9
|
+
|
10
|
+
if MiniPortile.darwin?
|
11
|
+
ENV["RAYLIB_PATH"] = "libraylib.dylib"
|
12
|
+
elsif MiniPortile.linux?
|
13
|
+
ENV["RAYLIB_PATH"] = "libraylib.so"
|
14
|
+
elsif MiniPortile.windows?
|
15
|
+
ENV["RAYLIB_PATH"] = "raylib.dll"
|
16
|
+
end
|
17
|
+
|
18
|
+
require_relative "../src/map"
|
19
|
+
|
20
|
+
Hokusai::Backends::RaylibBackend.run(App) do |config|
|
21
|
+
config.title = "Trollio Maps"
|
22
|
+
config.width = 800
|
23
|
+
config.height = 800
|
24
|
+
|
25
|
+
config.after_load do
|
26
|
+
pp TrollioConfig.asset("Inter-Regular.ttf")
|
27
|
+
Hokusai.fonts.register "inter", Hokusai::Backends::RaylibBackend::Font.from(TrollioConfig.asset("Inter-Regular.ttf"))
|
28
|
+
Hokusai.fonts.activate "inter"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
Binary file
|
data/src/config.rb
ADDED
data/src/map/control.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
module Mapa
|
2
|
+
class Control < Hokusai::Block
|
3
|
+
style <<~EOF
|
4
|
+
[style]
|
5
|
+
container {
|
6
|
+
background: rgb(206, 206, 206);
|
7
|
+
outline: outline(1.0, 1.0, 1.0, 1.0);
|
8
|
+
outline_color: rgb(136, 136, 136);
|
9
|
+
rounding: 0.2;
|
10
|
+
}
|
11
|
+
|
12
|
+
border {
|
13
|
+
outline: outline(0.0, 0.0, 1.0, 0.0);
|
14
|
+
outline_color: rgb(136, 136, 136);
|
15
|
+
}
|
16
|
+
|
17
|
+
zoomIn {
|
18
|
+
content: "+";
|
19
|
+
size: 20;
|
20
|
+
padding: padding(10.0, 0.0, 0.0, 12.5);
|
21
|
+
}
|
22
|
+
|
23
|
+
zoomOut {
|
24
|
+
content: "-";
|
25
|
+
size: 20;
|
26
|
+
padding: padding(10.0, 0.0, 0.0, 12.5);
|
27
|
+
}
|
28
|
+
EOF
|
29
|
+
|
30
|
+
template <<~EOF
|
31
|
+
[template]
|
32
|
+
vblock {
|
33
|
+
@mousedown="stop"
|
34
|
+
@mouseup="stop"
|
35
|
+
...container
|
36
|
+
}
|
37
|
+
rect.zoomin {
|
38
|
+
@click="emit_zoom_in"
|
39
|
+
...border
|
40
|
+
}
|
41
|
+
label { ...zoomIn }
|
42
|
+
rect.zoomout {
|
43
|
+
@click="emit_zoom_out"
|
44
|
+
}
|
45
|
+
label { ...zoomOut }
|
46
|
+
EOF
|
47
|
+
|
48
|
+
uses(
|
49
|
+
vblock: Hokusai::Blocks::Vblock,
|
50
|
+
rect: Hokusai::Blocks::Rect,
|
51
|
+
label: Hokusai::Blocks::Label
|
52
|
+
)
|
53
|
+
|
54
|
+
def stop(event)
|
55
|
+
# pp ["stopping", event.captures.map(&:class)]
|
56
|
+
event.stop
|
57
|
+
end
|
58
|
+
|
59
|
+
def emit_zoom_in(event)
|
60
|
+
pp ["clicked zoomin"]
|
61
|
+
event.stop
|
62
|
+
emit("zoomin")
|
63
|
+
end
|
64
|
+
|
65
|
+
def emit_zoom_out(event)
|
66
|
+
pp ["clicked zoomout"]
|
67
|
+
event.stop
|
68
|
+
emit("zoomout")
|
69
|
+
end
|
70
|
+
|
71
|
+
def render(canvas)
|
72
|
+
canvas.x += 10.0
|
73
|
+
canvas.y += 10.0
|
74
|
+
canvas.width = 35.0
|
75
|
+
|
76
|
+
yield canvas
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/src/map/error.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative "./earth"
|
2
|
+
|
3
|
+
module Mapa
|
4
|
+
class EPSG3857 < Earth
|
5
|
+
class << self
|
6
|
+
def projection
|
7
|
+
SphericalMercator
|
8
|
+
end
|
9
|
+
|
10
|
+
def transformation
|
11
|
+
@transformation ||= begin
|
12
|
+
scale = 0.5 / (Math::PI * SphericalMercator::R)
|
13
|
+
Transformation.new(scale, 0.5, -scale, 0.5)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Mapa
|
2
|
+
class Earth < CRS
|
3
|
+
WRAP_LNG = [-180, 180]
|
4
|
+
R = 6371000
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def distance(a, b)
|
8
|
+
rad = Math::PI / 180
|
9
|
+
lat1 = a.lat * rad
|
10
|
+
lat2 = b.lat * rad
|
11
|
+
|
12
|
+
sin_d_lat = Math.sin((b.lat - a.lat) * rad / 2)
|
13
|
+
sin_d_lon = Math.sin((b.lng - a.lng) * rad / 2)
|
14
|
+
|
15
|
+
a = sin_d_lat * sin_d_lat + Math.cos(lat1) * Math.cos(lat2) * sin_d_lon * sin_d_lon
|
16
|
+
c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
|
17
|
+
|
18
|
+
Earth::R * c
|
19
|
+
end
|
20
|
+
|
21
|
+
def wrap_lat_lng(latlng)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/src/map/geo/crs.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
module Mapa
|
2
|
+
class CRS
|
3
|
+
class << self
|
4
|
+
def get(code)
|
5
|
+
{
|
6
|
+
"EPSG3857" => EPSG3857,
|
7
|
+
}
|
8
|
+
end
|
9
|
+
|
10
|
+
def lat_lng_to_point(latlng, zoom)
|
11
|
+
point = projection.project(latlng)
|
12
|
+
scale = scale(zoom)
|
13
|
+
|
14
|
+
transformation.transform(point, scale)
|
15
|
+
end
|
16
|
+
|
17
|
+
def point_to_lat_lng(point, zoom)
|
18
|
+
scale = scale(zoom)
|
19
|
+
untransformed = transformation.untransform(point, scale)
|
20
|
+
|
21
|
+
projection.unproject(untransformed)
|
22
|
+
end
|
23
|
+
|
24
|
+
def project(latlng)
|
25
|
+
end
|
26
|
+
|
27
|
+
def unproject(point)
|
28
|
+
end
|
29
|
+
|
30
|
+
def scale(zoom)
|
31
|
+
256 * 2 ** zoom;
|
32
|
+
end
|
33
|
+
|
34
|
+
def zoom(scale)
|
35
|
+
end
|
36
|
+
|
37
|
+
def projected_bounds(zoom)
|
38
|
+
b = projection.bounds
|
39
|
+
s = scale(zoom)
|
40
|
+
min = transformation.transform(b.min, s)
|
41
|
+
max = transformation.transform(b.max, s)
|
42
|
+
Bounds.new(min, max)
|
43
|
+
end
|
44
|
+
|
45
|
+
def wrap_lat_lng(latlng)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
require_relative "./crs/EPSG3857"
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "json"
|
2
|
+
|
3
|
+
module Mapa
|
4
|
+
class LatLng
|
5
|
+
def self.from(array)
|
6
|
+
new(array[0], array[1])
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_accessor :lat, :lng, :alt
|
10
|
+
|
11
|
+
def initialize(lat, lng, altitude = nil)
|
12
|
+
@lat = lat
|
13
|
+
@lng = lng
|
14
|
+
@alt = altitude
|
15
|
+
end
|
16
|
+
|
17
|
+
def ==(latlng, max_margin = nil)
|
18
|
+
margin = [(lat - latlng.lat).abs, (lng - latlng.lng).abs].max
|
19
|
+
|
20
|
+
margin <= (max_margin || 1.0E-9)
|
21
|
+
end
|
22
|
+
|
23
|
+
def reverse_geo
|
24
|
+
pp ["latlng", lat, lng]
|
25
|
+
body = JSON.parse(RestClient.get("https://geoffrey.skinnyjames.net/api/v1/us/reverse-geocode?lat=#{lat}&lng=#{lng}").body, symbolize_names: true)
|
26
|
+
body[0]
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_point(crs, zoom)
|
30
|
+
crs.lat_lng_to_point(self, zoom)
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_s(precision = 4)
|
34
|
+
"LatLng(#{lat.round(precision)}, #{lng.round(precision)})"
|
35
|
+
end
|
36
|
+
|
37
|
+
def distance_to(other)
|
38
|
+
Earth.distance(self, other)
|
39
|
+
end
|
40
|
+
|
41
|
+
def wrap
|
42
|
+
Earth.wrap_lat_lng(self)
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_bounds(meters)
|
46
|
+
lat_accuracy = 100 * meters / 40075017
|
47
|
+
lng_accuracy = lat_accuracy / Math.cos((Math::PI / 180) * lat)
|
48
|
+
|
49
|
+
LatLngBounds.new(
|
50
|
+
lat - lat_accuracy,
|
51
|
+
lng - lng_accuracy,
|
52
|
+
lat + lat_accuracy,
|
53
|
+
lng + lng_accuracy
|
54
|
+
)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Mapa
|
2
|
+
class LatLngBounds
|
3
|
+
attr_accessor :south_west, :north_east
|
4
|
+
|
5
|
+
def initialize(bl, tr)
|
6
|
+
sw_lat = bl.is_a?(Array) ? bl[0] : bl.lat
|
7
|
+
sw_lng = tr.is_a?(Array) ? bl[1] : bl.lng
|
8
|
+
ne_lat = bl.is_a?(Array) ? tr[0] : tr.lat
|
9
|
+
ne_lng = tr.is_a?(Array) ? tr[1] : tr.lng
|
10
|
+
|
11
|
+
@south_west = LatLng.new(sw_lat, sw_lng)
|
12
|
+
@north_east = LatLng.new(ne_lat, ne_lng)
|
13
|
+
end
|
14
|
+
|
15
|
+
def pad(buffer_ratio)
|
16
|
+
height_buffer = Math.abs(south_west.lat - north_east.lat) * buffer_ratio
|
17
|
+
width_buffer = Math.abs(south_west.lng - north_east.lng) * buffer_ratio
|
18
|
+
|
19
|
+
LatLngBounds.new(
|
20
|
+
LatLng.new(south_west.lat - height_buffer, south_west.lng - width_buffer),
|
21
|
+
LatLng.new(north_east.lat + height_buffer, north_east.lng + width_buffer)
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
def center
|
26
|
+
LatLng.new(
|
27
|
+
(south_west.lat + north_east.lat) / 2,
|
28
|
+
(south_west.lng + north_east.lng) / 2
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
def north_west
|
33
|
+
LatLng.new(north_east.lat, south_west.lng)
|
34
|
+
end
|
35
|
+
|
36
|
+
def south_east
|
37
|
+
LatLng.new(south_west.lat, north_east.lng)
|
38
|
+
end
|
39
|
+
|
40
|
+
def contains(obj)
|
41
|
+
case obj
|
42
|
+
when LatLng
|
43
|
+
(obj.lat >= south_west.lat) && (obj.lat <= north_east.lat) &&
|
44
|
+
(obj.lng >= south_west.lng) && (obj.lng <= north_east.lng)
|
45
|
+
when LatLngBounds
|
46
|
+
(obj.south_west.lat >= south_west.lat) && (obj.north_east.lat <= north_east.lat) &&
|
47
|
+
(obj.south_west.lng >= south_west.lng) && (obj.south_west.lng <= north_east.lng)
|
48
|
+
else
|
49
|
+
raise Error.new("Must pass LatLng or LatLngBounds")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def intersects(bounds)
|
54
|
+
end
|
55
|
+
|
56
|
+
def overlaps(bounds)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
File without changes
|
File without changes
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Mapa
|
2
|
+
class SphericalMercator
|
3
|
+
R = 6378137
|
4
|
+
MAX_LATITUDE = 85.0511287798
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def project(latlng)
|
8
|
+
d = Math::PI / 180
|
9
|
+
lat = [[MAX_LATITUDE, latlng.lat].min, -MAX_LATITUDE].max
|
10
|
+
sin = Math.sin(lat * d)
|
11
|
+
|
12
|
+
Point.new(
|
13
|
+
SphericalMercator::R * latlng.lng * d,
|
14
|
+
SphericalMercator::R * Math.log((1 + sin) / (1 - sin)) / 2)
|
15
|
+
end
|
16
|
+
|
17
|
+
def unproject(point)
|
18
|
+
d = 180 / Math::PI
|
19
|
+
|
20
|
+
LatLng.new(
|
21
|
+
(2 * Math.atan(Math.exp(point.y / SphericalMercator::R)) - (Math::PI / 2)) * d,
|
22
|
+
point.x * d / R
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
def bounds
|
27
|
+
d = MAX_LATITUDE * Math::PI
|
28
|
+
Bounds.new([-d,-d], [d, d])
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/src/map/geo.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
module Mapa
|
2
|
+
class Bounds
|
3
|
+
attr_accessor :min, :max
|
4
|
+
|
5
|
+
def initialize(tl, br)
|
6
|
+
min_x = tl.is_a?(Array) ? tl[0] : tl.x
|
7
|
+
max_x = br.is_a?(Array) ? br[0] : br.x
|
8
|
+
min_y = tl.is_a?(Array) ? tl[1] : tl.y
|
9
|
+
max_y = br.is_a?(Array) ? br[1] : br.y
|
10
|
+
|
11
|
+
@min = Point.new(min_x, min_y)
|
12
|
+
@max = Point.new(max_x, max_y)
|
13
|
+
end
|
14
|
+
|
15
|
+
def extend(point_or_bounds)
|
16
|
+
case point_or_bounds
|
17
|
+
when Point
|
18
|
+
self.min.x = [point_or_bounds.x, min.x].min
|
19
|
+
self.min.y = [point_or_bounds.y, min.y].min
|
20
|
+
self.max.x = [point_or_bounds.x, max.x].max
|
21
|
+
self.max.y = [point_or_bounds.y, max.y].max
|
22
|
+
when Bounds
|
23
|
+
self.min.x = [point_or_bounds.min.x, min.x].min
|
24
|
+
self.min.y = [point_or_bounds.min.y, min.y].min
|
25
|
+
self.max.x = [point_or_bounds.max.x, max.x].max
|
26
|
+
self.max.y = [point_or_bounds.max.y, max.y].max
|
27
|
+
else
|
28
|
+
raise Error.new("Extends requires a Point or Bounds")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_lat_lng_bounds(crs, zoom)
|
33
|
+
pp [crs.point_to_lat_lng(min, zoom), min]
|
34
|
+
|
35
|
+
tl = crs.point_to_lat_lng(min, zoom)
|
36
|
+
br = crs.point_to_lat_lng(max, zoom)
|
37
|
+
|
38
|
+
sw = LatLng.new(tl.lat, br.lng)
|
39
|
+
ne = LatLng.new(br.lat, tl.lng)
|
40
|
+
LatLngBounds.new(sw, ne)
|
41
|
+
end
|
42
|
+
|
43
|
+
def center(round = false)
|
44
|
+
Point.new(
|
45
|
+
(min.x + max.x) / 2,
|
46
|
+
(min.y + max.y )/ 2,
|
47
|
+
round
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
def bottom_left
|
52
|
+
Point.new(min.x, max.y)
|
53
|
+
end
|
54
|
+
|
55
|
+
def top_right
|
56
|
+
Point.new(max.x, min.y)
|
57
|
+
end
|
58
|
+
|
59
|
+
def top_left
|
60
|
+
min
|
61
|
+
end
|
62
|
+
|
63
|
+
def bottom_right
|
64
|
+
max
|
65
|
+
end
|
66
|
+
|
67
|
+
def size
|
68
|
+
max - min
|
69
|
+
end
|
70
|
+
|
71
|
+
def contains(point_or_bounds)
|
72
|
+
case point_or_bounds
|
73
|
+
when Point
|
74
|
+
(point_or_bounds.x >= min.x) &&
|
75
|
+
(point_or_bounds.x <= max.x) &&
|
76
|
+
(point_or_bounds.y >= min.y) &&
|
77
|
+
(point_or_bounds.y <= max.y)
|
78
|
+
when Bounds
|
79
|
+
(point_or_bounds.min.x >= min.x) &&
|
80
|
+
(point_or_bounds.max.x <= max.x) &&
|
81
|
+
(point_or_bounds.min.y >= min.y) &&
|
82
|
+
(point_or_bounds.max.y <= max.y)
|
83
|
+
else
|
84
|
+
raise Error.new("contains requires a Point or Bounds")
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def intersects(bounds)
|
89
|
+
end
|
90
|
+
|
91
|
+
def overlaps(bounds)
|
92
|
+
end
|
93
|
+
|
94
|
+
def pad(buffer)
|
95
|
+
end
|
96
|
+
|
97
|
+
def ==(bounds)
|
98
|
+
min == bounds.top_left && max == bounds.bottom_right
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Mapa
|
2
|
+
class BoundsProxy
|
3
|
+
attr_reader :map, :screen
|
4
|
+
|
5
|
+
def initialize(screen, map)
|
6
|
+
@map = map
|
7
|
+
@screen = screen
|
8
|
+
end
|
9
|
+
|
10
|
+
def top_left
|
11
|
+
screen.top_left
|
12
|
+
end
|
13
|
+
|
14
|
+
def bottom_right
|
15
|
+
screen.bottom_right
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class BoundsProxyCollection
|
20
|
+
include Enumerable
|
21
|
+
|
22
|
+
attr_reader :bounds
|
23
|
+
|
24
|
+
attr_accessor :offset
|
25
|
+
|
26
|
+
def initialize
|
27
|
+
@bounds = []
|
28
|
+
@offset = Point.new(0, 0)
|
29
|
+
end
|
30
|
+
|
31
|
+
def each
|
32
|
+
bounds.each do |b|
|
33
|
+
yield b
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def <<(proxy)
|
38
|
+
@bounds << proxy
|
39
|
+
end
|
40
|
+
|
41
|
+
def top_left
|
42
|
+
bounds.map(&:top_left).min
|
43
|
+
end
|
44
|
+
|
45
|
+
def bottom_right
|
46
|
+
bounds.map(&:bottom_right).max
|
47
|
+
end
|
48
|
+
|
49
|
+
def map_contains(point)
|
50
|
+
bounds.find do |b|
|
51
|
+
b.map.contains(point)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def contains(point)
|
56
|
+
bounds.find do |b|
|
57
|
+
b.screen.contains(point)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|