-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathgrid.ml
1170 lines (979 loc) · 36 KB
/
grid.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
(* Copyright (C) 2014, Marco Stronati, All Rights Reserved.
This file is distributed under the terms of the
GNU General Public License version 3 or later. *)
open Geo
(**
Geographic data structures.
*)
(**
A geographic location, intended as a squared area, with a weight.
*)
module Node : sig
type t
val hash : t -> int
val equal : t -> t -> bool
val compare : t -> t -> int
val make : int -> Geo.Utm.t -> float -> t
val coord : t -> Geo.Utm.t
val weight : t -> float
val id : t -> int
val set_id : t -> int -> unit
val set_weight : t -> float -> unit
val geojson_of : ?properties:string -> float -> t -> string
end
= struct
type t = {
coord : Utm.t;
mutable id : int;
mutable weight : float;
}
let hash n = Hashtbl.hash n.id
let equal n1 n2 = n1.id = n2.id
let compare a b =
if equal a b then 0
else compare a b
let make id coord weight = {
id = id;
coord = coord;
weight = weight;
}
let coord n = n.coord
let weight n = n.weight
let id n = n.id
let set_id n id = n.id <- id
let set_weight n w = n.weight <- w
let string_of n =
Printf.sprintf "\"%s\"" (Utm.string_of n.coord)
let geojson_point_of ?(properties = "") radius n =
let (lat,lon) = Wgs.tuple (Wgs.of_xy n.coord) in
Printf.sprintf
"{\"type\": \"Feature\",
\"geometry\": {\"type\": \"Point\", \"coordinates\": [%f, %f]},
\"properties\": {
%s
\"id\": %i,
\"radius\": %f,
\"weight\": %f
}
}" lon lat
properties
n.id
radius
n.weight
let geojson_region_of ?(properties = "") radius n =
let string_of_coo coord =
let (lat,lon) = Wgs.tuple (Wgs.of_xy coord) in
Printf.sprintf "[%f, %f]" lon lat (* inversion for geojson *)
in
let dist_center_edge = radius *. (sqrt 2.) in
let p1 = Utm.destination n.coord 45. dist_center_edge in
let p2 = Utm.destination n.coord 135. dist_center_edge in
let p3 = Utm.destination n.coord 225. dist_center_edge in
let p4 = Utm.destination n.coord 315. dist_center_edge in
Printf.sprintf
"{\"type\": \"Feature\",
\"geometry\": {
\"type\": \"Polygon\",
\"coordinates\": [[ %s, %s, %s, %s, %s]]
},
\"properties\": {
%s
\"id\": %i,
\"coord\": %s,
\"radius\": %f,
\"weight\": %f
}
}"
(string_of_coo p1) (string_of_coo p2)
(string_of_coo p3) (string_of_coo p4)
(string_of_coo p1)
properties
n.id
(string_of_coo n.coord)
radius
n.weight
let geojson_of = geojson_region_of
end
(**
Locations arranged in a squared grid.
Locations are layed from left to right, top to bottom in a z-like fashion.
e.g. in a grid with 100 points, north-west has id 0, north-east 9, south-west 90, south-east 99.
Locations can be also referenced by position in a matrix style (x,y) with x the row and y the column.
e.g. north-west is (0,0), south-west (9,0) *)
module Grid : sig
type t
type box_in = int * int
type pos = int * int
val copy : t -> t
val length: t -> int
val radius: t -> float
val iter : t -> (Node.t -> unit) -> unit
val iter_box : t -> box_in -> (Node.t -> unit) -> unit
val get: t -> int * int -> Node.t
val get_id: t -> int -> Node.t
val pos_of_id : t -> int -> pos
val id_of_pos : t -> pos -> int
val make : Geo.Utm.t -> float -> int -> t
val make_parallel : Geo.Utm.t -> float -> int -> int -> t
val carve: t -> box_in -> t
val find: t -> Geo.Utm.t -> pos
val to_geojson : t -> string -> unit
val to_geojson_box : t -> box_in -> ?max_weight:float -> string -> unit
val to_file_boxes : t -> box_in list -> string -> unit
val of_file_boxes : t -> string -> box_in list
val to_file : t -> string -> unit
val of_file : string -> t
val next_by_distance : t -> int -> pos -> pos
val stat : t -> Util.values
val diag_of_box: t -> Geo.box -> box_in
val full_box : t -> box_in
val is_in_box : t -> box_in -> int -> bool
val is_in_any_box : t -> box_in list -> int -> bool
val normalize: t -> Node.t -> t
val pp_of_ball: t -> int -> float -> float
val to_numbers_grid: t -> unit
(* val of_warped: string -> t *)
end
= struct
type t = Node.t array array
type box_in = int * int
type pos = int * int
let length g = Array.length g
let get g (x,y) = g.(x).(y)
let set g (x,y) n = g.(x).(y) <- n
(** Convert ids into positions *)
let pos_of_id g id =
let l = length g in
if id < 0 || id >= (l * l)
then raise (Invalid_argument (Printf.sprintf "invalid id: %i" id))
else
((id / l), (id mod l))
(** Convert positions into ids *)
let id_of_pos g (x,y) =
if x <0 || x >= length g ||
y <0 || y >= length g
then raise (Invalid_argument (Printf.sprintf "invalid pos: (%i,%i)" x y))
else
let l = length g in
(x * l) + y
(** [get_id g i] returns the node with id [i] in [g] *)
let get_id g id =
let p = pos_of_id g id in
get g p
(** [set_id g i n] sets the id of node [i] to [n] *)
let set_id g id n =
if (Node.id n) <> id then failwith "Id mismatch" else
let p = pos_of_id g id in
set g p n
(* note: this is double the radius, or the diameter of the cirle *)
let step g =
Utm.distance
(Node.coord (get g (0,0)))
(Node.coord (get g (0,1)))
(** Return the radius of the grid. That is the horizontal or vertical distance between two adjacent locations or the size of a location cell. *)
let radius g = step g /. 2.
(* TODO maybe this center and the center of the iter_box and carve don't coincide *)
(* if (length g) is odd we get the perfect center otherwise we get the top-left corner of the 2x2 square in the center*)
let get_center g =
let x = (length g) / 2 in
id_of_pos g (x,x)
(** Apply a function on all the nodes of the grid, in id order. *)
let iter g f =
let l = length g in
for x=0 to l-1 do
for y=0 to l-1 do
f g.(x).(y)
done
done
let fold_box g (nw,se) f init =
let nw_x,nw_y = pos_of_id g nw in
let se_x,se_y = pos_of_id g se in
let x_min = nw_x in
let x_max = se_x in
let y_min = nw_y in
let y_max = se_y in
let tmp = ref init in
for x=x_min to x_max do
for y=y_min to y_max do
tmp := f !tmp g.(x).(y)
done
done;
tmp
let fold g f init =
let l = length g in
fold_box g (0,l*l-1) f init
(* (\* TODO inefficient but safe *\) *)
(* (\* TODO this shoudl also raise Not_found, now if the elemtn is not in the grid, the closest is reported anyway!!! *\) *)
(* let find_slow g coord = *)
(* let id = ref (-1) in *)
(* let d = ref infinity in *)
(* iter g (fun n -> *)
(* let d2 = Utm.distance (Node.coord n) coord in *)
(* if d2 < !d then (d := d2; id := Node.id n) else ()); *)
(* pos_of_id g !id *)
(* pay attention to difference between xy coordinates and xy position in the grid *)
(** Find the closest location to the given cartesian coordinates
@raise Not_found if the location is outside the grid
*)
(* TODO this could be improved with a binary search on each direction *)
let find g coord =
let (x,y) = Utm.tuple coord in
let r = radius g in
let visited = Hashtbl.create 10 in
let _ = Hashtbl.add visited (0,0) true in
let rec find_in now_pos =
let i,j = now_pos in
let now_x,now_y =
try Utm.tuple (Node.coord (get g now_pos))
with _ -> raise Not_found
in
let dx,dy = abs_float(x-.now_x),abs_float(y-.now_y) in
let sx,sy = Util.sign_float (x-.now_x),Util.sign_float (y-.now_y) in
let next_i = if dy > r then i - sy else i in
let next_j = if dx > r then j + sx else j in
let next = (next_i,next_j) in
(* Printf.printf "%.0f,%.0f r %.0f now_pos %i,%i now_xy %.0f,%.0f\n" x y r i j now_x now_y; *)
(* Printf.printf "dx %.0f dy%.0f sx%i sy%i next %i,%i\n" dx dy sx sy next_i next_j; *)
if next = now_pos
then now_pos
else
let known = try Hashtbl.find visited next with _ -> false in
if known
then raise Not_found
else let _ = Hashtbl.add visited now_pos true in find_in next
in
find_in (0,0)
let to_file_boxes m boxes file =
let oc = open_out file in
let dump_box (nw,se) =
Printf.fprintf oc "%05i,%05i\n" nw se;
in
List.iter dump_box boxes;
close_out oc
let of_file_boxes m file =
let boxes = ref [] in
let ic = Pervasives.open_in file in
let rec loop () =
let maybe_s =
try
Some (Pervasives.input_line ic)
with End_of_file -> None
in
match maybe_s with
| Some s ->
let _ = Scanf.sscanf s "%i,%i"
(fun nw se ->
(* Printf.printf "reading node %i at pos %i\n" i (Pervasives.pos_in ic); *)
boxes := !boxes@((nw,se)::[]))
in
loop ()
| None -> Pervasives.close_in ic
in
loop ();
!boxes
(** Apply a function on all nodes inside a box, in id order. *)
let iter_box g (nw,se) f =
let nw_x,nw_y = pos_of_id g nw in
let se_x,se_y = pos_of_id g se in
let x_min = nw_x in
let x_max = se_x in
let y_min = nw_y in
let y_max = se_y in
for x=x_min to x_max do
for y=y_min to y_max do
f g.(x).(y)
done
done
(* let iter_rev g f = *)
(* let l = length g in *)
(* for x=l-1 downto 0 do *)
(* for y=l-1 downto 0 do *)
(* f g.(x).(y) *)
(* done *)
(* done *)
(* let next_pos g (x,y) = *)
(* let l = Array.length g in *)
(* if y = l-1 *)
(* then *)
(* (if x = l-1 *)
(* then None *)
(* else Some (x+1,0)) *)
(* else Some (x,y+1) *)
(* let rec iter_from f g (i,j) = *)
(* f (get g (i,j)); *)
(* match next_pos g (i,j) with *)
(* None -> () *)
(* | Some pos -> iter_from f g pos *)
let iteri g f =
let l = length g in
for x=0 to l-1 do
for y=0 to l-1 do
f g.(x).(y) ((x*l) + y)
done
done
let split start1 step length =
if length mod 2 <> 0 then raise (Invalid_argument "odd length");
let half = (length / 2) in
let start2 = Utm.destination start1 0. (step *. (float half)) in
let start3 = Utm.destination start1 270. (step *. (float half)) in
let start4 = Utm.destination start3 0. (step *. (float half)) in
(start1,start2,start3,start4,half)
let merge l =
match l with
| [g1;g2;g3;g4] ->
if (length g1) <> (length g2) ||
(length g2) <> (length g3) ||
(length g3) <> (length g4)
then raise (Invalid_argument "incompatible lengths");
let m_left = Array.append g1 g3 in
let m_right = Array.append g2 g4 in
let m = Array.mapi (fun i row_l ->
Array.append row_l m_right.(i)
) m_left
in
iteri m (fun n i -> Node.set_id n i);
m
| _ -> raise (Invalid_argument "incompatible lengths")
let make_nw start step length =
let radius = step /. 2. in
let w0 = Query.get_weight 0 start radius in
let n0 = Node.make 0 start w0 in
let m = Array.make_matrix length length n0 in
for x=0 to length-1 do (* rows *)
for y=0 to length-1 do (* columns *)
if x=0 && y=0 then () else
let prev = if y=0 then m.(x-1).(y) else m.(x).(y-1) in
let coo = if y=0
then Utm.destination (Node.coord prev) 270. step
else Utm.destination (Node.coord prev) 0. step
in
let id = ((x * length) + y) in
let w = Query.get_weight id coo radius in
let n = Node.make id coo w in
m.(x).(y) <- n
done
done;
m
let copy g =
let length = length g in
let n0 = Node.make 0 (Node.coord g.(0).(0)) (Node.weight g.(0).(0)) in
let m = Array.make_matrix length length n0 in
iter g (fun n ->
let (i,j) = pos_of_id g (Node.id n) in
let n_copy = Node.make (Node.id n) (Node.coord n) (Node.weight n) in
m.(i).(j) <- n_copy
);
m
(*
if length is even the center is actually slightly south est of the ideal center
*)
(**
[make center step length] creates a grid from a central location
[center], in cartesian coordinates, where [step] is the distance
between adjacent location and [length] the number of locations in a
side of the grid.
*)
let make center step length =
let center_west = Utm.destination center 180. (step *. (float (length /2))) in
let nw = Utm.destination center_west 90. (step *. (float (length /2))) in
make_nw nw step length
(* Fixed at 4 cores *)
(** Same as [make] but uses Parmap to parallelize over [n] cores
@see <https://github.com/rdicosmo/parmap/> Parmap
*)
let make_parallel center step length cores =
if length mod 2 <> 0 then raise (Invalid_argument "odd length");
let half = (length / 2) in
let center_west = Utm.destination center 180. (step *. (float (length /2))) in
let start1 = Utm.destination center_west 90. (step *. (float (length /2))) in
let start2 = Utm.destination start1 0. (step *. (float half)) in
let start3 = Utm.destination start1 270. (step *. (float half)) in
let start4 = Utm.destination start3 0. (step *. (float half)) in
Parmap.set_default_ncores cores;
let grids = Parmap.parmap
(fun start -> make_nw start step half)
(Parmap.L [start1;start2;start3;start4])
in
merge grids
(* this is expensive, contains a find *)
let diag_of_box g (Central (coo,size)) =
let cx,cy = find g coo in
let steps = int_of_float (ceil (size /. step g)) in
Printf.printf "c (%i,%i) size %f step %f steps %i\n" cx cy size (step g) steps;
let half = steps / 2 in
let nw_pos = cx-half, cy-half in
let se_pos =
if steps mod 2 = 0
then (* center is bottom-right of the 2x2 square in the center ?? *)
cx+half-1, cy+half-1
else (* center is at the center *)
cx+half, cy+half
in
Printf.printf "c (%i,%i) size %f step %f steps %i\n" cx cy size (step g) steps;
Printf.printf "nw (%i,%i) se (%i,%i)\n" (fst nw_pos) (snd nw_pos) (fst se_pos) (snd se_pos);
Printf.printf "nw %i se %i\n" (id_of_pos g nw_pos) (id_of_pos g se_pos);
(* let dx= fst se_pos - fst nw_pos in *)
(* let dy = snd se_pos - snd nw_pos in *)
(* if dx <> steps || dy <> steps then failwith (Printf.sprintf "dx %i dy %i\n" dx dy); *)
(id_of_pos g nw_pos, id_of_pos g se_pos)
let full_box g =
let l = length g in
(0,l*l-1)
(** Create a new grid of a grid of larger size. Each node id is updated. *)
let carve g (nw,se) =
let nw_x,nw_y = pos_of_id g nw in
let se_x,se_y = pos_of_id g se in
let l_carved = se_x-nw_x+1 in
let cx,cy = nw_x + l_carved/2,nw_y+l_carved/2 in
(* Printf.printf "c (%i,%i) l %i\n" cx cy l_carved; *)
let new_of_old_pos (x,y) = (x - cx + (l_carved/2),
y - cy + (l_carved/2))
in
let n0 = Node.make 0 (Utm.of_latlon Geo.rio) 0. in
let g_carved = Array.make_matrix l_carved l_carved n0 in
iter_box g (nw,se)
(fun n ->
let (x,y) = pos_of_id g (Node.id n) in
let (x_new,y_new) = new_of_old_pos (x,y) in
(* Printf.printf "xy (%i,%i) xynew (%i,%i)\n" x y x_new y_new; *)
let id_new = id_of_pos g_carved (x_new,y_new) in
g_carved.(x_new).(y_new) <- n;
Node.set_id g_carved.(x_new).(y_new) id_new
);
(* let cnt = ref 0 in *)
(* iter g (fun n -> *)
(* if Node.coord n = Geo.rio then cnt := !cnt +1; *)
(* ); *)
(* if !cnt > 1 then failwith "too many n0"; *)
g_carved
(* http://stackoverflow.com/questions/16571362/how-to-iterate-over-rings-in-a-raster-grid *)
let rec next_by_distance_continuous g center_id state =
let now_id,ring_idx = state in
let cx,cy = pos_of_id g center_id in
let dist dx dy = int_of_float (sqrt (((float dx) ** 2.) +. ((float dy) ** 2.))) in
let generate_ring d =
let dx = d in
let dy = 0 in
let rec loop tmp =
let (dx,dy) = List.hd tmp in
let nx = - (Util.sign dy) in
let ny = (Util.sign dx) in
(* Printf.printf "Got: (%f,%f) and nx,ny = (%.0f,%f.0)\n" dx dy nx ny; *)
let dx,dy =
if nx <> 0 && (dist (dx+nx) dy) = d
then (dx + nx),dy
else if ny <> 0 && (dist dx (dy+ny)) = d
then dx,(dy + ny)
else (dx + nx),(dy + ny)
in
(* Printf.printf "Made: (%f,%f)\n" dx dy; *)
if dx <> d || dy <> 0
then loop ((dx,dy)::tmp)
else (* List.rev *) tmp
in
let relative_ring = loop ((dx,dy)::[]) in
let l = length g in
List.fold_left (fun tmp (x,y) -> let ax,ay = (cx+x,cy+y) in
if 0 <= ax && ax < l && 0 <= ay && ay < l
then (id_of_pos g (ax,ay))::tmp
else tmp)
[] relative_ring
in
let rec find_next ring =
let ids_ring = generate_ring ring in
let current_ring id =
let nx,ny = pos_of_id g id in
dist (cx-nx) (cy-ny)
in
List.iter (fun id -> if (current_ring id) <> ring then failwith "buuuu") ids_ring;
let rec loop l =
match l with
[] -> find_next (ring+1)
| id::rest -> if id = now_id then
try Some ((List.hd rest),-1)
with _ ->
(* Printf.printf "reached end, generating new ring\n\n"; *)
try Some ((List.hd (generate_ring (ring+1))),-1)
with _ ->
(* Printf.printf "reached end of new ring\n\n"; *)
None
else loop rest
in
loop ids_ring
in
let current_ring =
let nx,ny = pos_of_id g now_id in
dist (cx-nx) (cy-ny)
in
find_next current_ring
(* let ring_visited = ref [] *)
let rec next_by_distance_jumps g center_id state =
let now_id,ring_idx = state in
let cx,cy = pos_of_id g center_id in
let dist dx dy = int_of_float (sqrt (((float dx) ** 2.) +. ((float dy) ** 2.))) in
let sign x = if x = 0 then 0 else if x < 0 then -1 else 1 in
let generate_ring d =
let dx = d in
let dy = 0 in
let ring = BatDynArray.create () in
BatDynArray.add ring (dx,dy);
let rec loop () =
let (dx,dy) = BatDynArray.last ring in
let nx = - (sign dy) in
let ny = (sign dx) in
(* Printf.printf "Got: (%f,%f) and nx,ny = (%.0f,%f.0)\n" dx dy nx ny; *)
let dx,dy =
if nx <> 0 && (dist (dx+nx) dy) = d
then (dx + nx),dy
else if ny <> 0 && (dist dx (dy+ny)) = d
then dx,(dy + ny)
else (dx + nx),(dy + ny)
in
(* Printf.printf "Made: (%f,%f)\n" dx dy; *)
if dx <> d || dy <> 0
then (BatDynArray.add ring (dx,dy); loop ())
else ()
in
loop ();
ring
in
(* idx = i*s mod l *)
(* r = i*s / l *)
(* while i < l *)
(* i*s = r*l + idx *)
(* idx_n = (i+1)*s mod l = (i*s + s) mod l = (i*s mod l) + (s mod l) mod l = idx + (s mod l) mod l *)
(* idx=4 => i*3 mod 10 = a,4 -> i=8 *)
(* i = (idx + (l * r)) / s *)
(* idx = root + (i*s) *)
(* idx_n = root + (i+1) * s = root + is + s *)
(* if idx_n >= l then *)
(* root+1 *)
(* root = idx_n / s *)
let next_idx ring idx =
if idx = -1
then
(* let _ = Printf.printf "Case idx = -1\n" in *)
Some 0
else
let l = BatDynArray.length ring in
let step = 4 in
if l <= step
then
(* let _ = Printf.printf "Case l<step\n" in *)
if idx+1 < l
then
(* let _ = Printf.printf "length %2i idx %2i next %2i\n" l idx (idx+1) in *)
Some (idx+1)
else None
else
(* let _ = Printf.printf "Case regular \n" in *)
(* let _ = Printf.printf "idx %2i step %2i l %2i " idx step l in *)
let idx_n =
if idx + step >= l
then
let root = idx mod step in
if root = step-1
then None
else Some (root+1)
else Some (idx + step)
in
(* (match idx_n with *)
(* None -> Printf.printf "next _\n%!"; *)
(* | Some next_idx -> *)
(* Printf.printf "next %2i\n%!" next_idx); *)
idx_n
in
(* let sprint_dynarray l = *)
(* let core = BatDynArray.fold_left (fun tmp (x,y) -> Printf.sprintf "%s(%i,%i)," tmp x y) "" l in *)
(* ("["^core^"]") *)
(* in *)
(* let check_ring_visited ring = *)
(* let l = BatDynArray.length ring in *)
(* let sorted = List.sort compare !ring_visited in *)
(* Printf.printf "ring_visited \n %s \n%!" (Util.string_of_int_list !ring_visited); *)
(* Printf.printf "sorted \n %s \n%!" (Util.string_of_int_list sorted); *)
(* Printf.printf "ring \n %s \n%!" (sprint_dynarray ring); *)
(* if List.length sorted <> l then failwith (Printf.sprintf "different length ring_visited %2i ring %2i center_if %i now_id %i\n" (List.length sorted) l center_id now_id); *)
(* let rec loop i idxs = *)
(* match idxs with *)
(* [] -> if i <> l then failwith (Printf.sprintf "ring_visited_end i %i l %i \n %s \n" i l (Util.string_of_int_list sorted)) *)
(* | e::rest -> if i <> e *)
(* then failwith (Printf.sprintf "ring_visited_in i %i e %i \n %s \n" i e (Util.string_of_int_list sorted)) *)
(* else loop (i+1) rest *)
(* in *)
(* loop 0 sorted; *)
(* ring_visited := [] *)
(* in *)
let filter (x,y) =
let ax,ay = (cx+x,cy+y) in
id_of_pos g (ax,ay)
in
(* find next node in the current ring or generate new rings *)
let rec find_next ring_n idx =
let l = length g in
if ring_n > (BatList.max [(l-cx);(l-cy);cx;cy]) (* TODO check if this test is too loose or strict *)
then
failwith "No more rings! Grid exhausted."
else
let ring = generate_ring ring_n in
(* let current_ring nx ny = *)
(* dist (cx-nx) (cy-ny) *)
(* in *)
(* BatDynArray.iter (fun (x,y) -> try let _ = filter (x,y) in if (current_ring x y) <> ring_n then failwith "ring mismatch" with _ -> ()) ring; *)
(* find next node in the current ring *)
let rec loop idx =
match idx with
None ->
(* check_ring_visited ring; *)
find_next (ring_n+1) (-1) (* finished ring *)
| Some idx ->
try (filter (BatDynArray.get ring idx),idx)
with
Invalid_argument _ ->
(* let _ = Printf.printf "failed filter \n%!" in *)
let idx_n = next_idx ring idx in
(* (match idx_n with None -> () | Some i -> ring_visited := i::!ring_visited); *)
loop idx_n (* filter failed, this loop may never end! *)
in
let idx_n = next_idx ring idx in
(* (match idx_n with None -> () | Some i -> ring_visited := i::!ring_visited); *)
loop idx_n
in
let current_ring =
let nx,ny = pos_of_id g now_id in
dist (cx-nx) (cy-ny)
in
find_next current_ring ring_idx
(* This can't be tested twice on the same point.
To test just pick a grid and run:
let _ = Grid.iter grid (fun n -> let _ = Grid.ball grid (Node.id n) 1000. in ()) in
*)
(* let center_old = ref (-1) *)
(* let check_wrapper g center_id state = *)
(* if !center_old <> center_id *)
(* then ( *)
(* let _ = Printf.printf "\nchanged id from %i to %i\n" !center_old center_id in *)
(* center_old := center_id; *)
(* ring_visited:=[]); *)
(* let now_id,ring_idx = state in *)
(* let _ = Printf.printf "\ncenter:%i state (idx:%i, ring_idx:%i)\n" center_id now_id ring_idx in *)
(* let res = next_by_distance_jumps g center_id state in *)
(* match res with *)
(* | None -> let _ = Printf.printf "\ncenter:%i generated NONE\n" in None *)
(* | Some (id,idx) -> *)
(* let _ = Printf.printf "\ncenter:%i generated id:%i idx:%i\n" center_id id idx in *)
(* res *)
(* let rec next_by_distance_old g center_id state = *)
(* let cx,cy = pos_of_id g center_id in *)
(* let now_id,outer_ring,neighbors = state in *)
(* let new_ring diff = *)
(* let norths = List.map (fun y -> ((cx-diff),y)) (Util.sweep (cy-diff) (cy+diff-1)) in *)
(* let easts = List.map (fun x -> (x,(cy+diff))) (Util.sweep (cx-diff) (cx+diff-1)) in *)
(* let souths = List.map (fun y -> ((cx+diff),y)) (Util.sweep (cy-diff+1) (cy+diff)) in *)
(* let wests = List.map (fun x -> (x,(cy-diff))) (Util.sweep (cx-diff+1) (cx+diff)) in *)
(* let neighbors_pos = norths @ wests @ souths @ easts in *)
(* let l = length g in *)
(* let filtered = List.filter (fun (x,y) -> *)
(* if 0 <= x && x < l && 0 <= y && y < l *)
(* then true else false) neighbors_pos *)
(* in *)
(* List.map (fun pos -> id_of_pos g pos) filtered *)
(* in *)
(* let add_neighbors neighbors = *)
(* let ids = new_ring (outer_ring+1) in *)
(* let id_dists = List.map *)
(* (fun id -> *)
(* let coo1 = Node.coord (get_id g center_id) in *)
(* let coo2 = Node.coord (get_id g id) in *)
(* (id, Geo.distance coo1 coo2)) ids *)
(* in *)
(* match id_dists with *)
(* | [] -> ((now_id,outer_ring+1,neighbors),false) *)
(* | _ -> *)
(* let sorted = List.sort (fun (_,a) (_,b) -> *)
(* let c = my_float_compare a b in *)
(* if c = 0 *)
(* then if Random.bool () then -1 else 1 *)
(* else c *)
(* ) (neighbors@id_dists) in *)
(* (\* Printf.printf "\nSorted %!"; *\) *)
(* (\* List.iter (fun (x,w) -> let (x,y) = pos_of_id g x in *\) *)
(* (\* Printf.printf "((%i,%i),%f);%!" x y w) sorted; *\) *)
(* (\* Printf.printf "\n%!"; *\) *)
(* ((now_id,outer_ring+1,sorted),true) *)
(* in *)
(* match neighbors with *)
(* | [] -> *)
(* let (new_state,updated) = add_neighbors [] in *)
(* if updated *)
(* then next_by_distance_old g center_id new_state *)
(* else (None,new_state) *)
(* | (x,d)::rest -> *)
(* let next_outer_closer = (float (outer_ring+1)) *. (step g) in *)
(* if (d > next_outer_closer) *)
(* then *)
(* let (new_state,updated) = add_neighbors neighbors in *)
(* if updated *)
(* then (next_by_distance_old g center_id new_state) *)
(* else *)
(* let _,outer_ring,neighbors = new_state in *)
(* (Some x,(x,outer_ring,neighbors)) *)
(* else *)
(* (Some x,(x,outer_ring,rest)) *)
(** Starting from a location return the id and distance of the next closest location
*)
let next_by_distance = next_by_distance_jumps
let stat g =
let l = ref [] in
iter g (fun n ->
let w = Node.weight n in
l := w::!l
);
Util.stat !l
let to_geojson_box g box ?(max_weight=(-. 1.)) file =
let max_weight =
if max_weight = (-. 1.)
then
let tmp = ref (-. 1.) in
iter_box g box (fun n -> tmp := max !tmp (Node.weight n));
!tmp
else max_weight
in
let radius = radius g in
let string = ref "" in
iter_box g box
(fun n ->
let w_norm = if max_weight > 0. then (Node.weight n) /. max_weight else (Node.weight n) in
let w_norm_s = Printf.sprintf "\"weight_n\" : %f," w_norm in
let pos = let (i,j) = pos_of_id g (Node.id n) in Printf.sprintf "\"pos\" : [%i,%i]," i j in
let prop = w_norm_s^"\n"^pos in
string := Printf.sprintf "%s%s,\n" !string (Node.geojson_of ~properties:prop radius n));
let nodes_string = !string in
(* remove last ,\n *)
let cleaned = String.sub nodes_string 0 (String.length nodes_string -2) in
let s = Printf.sprintf
"{ \"type\": \"FeatureCollection\",
\"features\": [\
%s
]
}" cleaned
in
Formats.geojson_to_file s file
let to_geojson g file =
let l = length g in
to_geojson_box g (0,l*l-1) file
(* save to file *)
let to_numbers_grid g =
let oc = open_out "weights.dat" in
let st = stat g in
(* (\* there should be a frame of sea !!!!! with the mean *\) *)
let l = length g in
let f = 20 in
for x=0 to l-1 do
for y=0 to l-1 do
if x < f || x > l-f ||
y < f || y > l-f
then
let open Util in
Printf.fprintf oc "%f " st.avg
else
Printf.fprintf oc "%f " (Node.weight g.(x).(y))
done;
Printf.fprintf oc "\n";
done;
close_out oc;
let oc = open_out "coords.dat" in
(* there should be a frame of sea !!!!! with the mean *)
let l = length g in
for x=0 to l-1 do
for y=0 to l-1 do
let (x,y) = Utm.tuple (Node.coord g.(x).(y)) in
Printf.fprintf oc "%f %f\n" x y;
done;
done;
close_out oc
(* (\* load from file *\) *)
(* let of_warped file = *)
(* let open Geo in *)
(* let count_lines filename = *)
(* let ic = Pervasives.open_in filename in *)
(* let rec loop i = *)
(* let continue = *)
(* try *)
(* let _ = Pervasives.input_line ic in *)
(* true *)
(* with End_of_file -> false *)
(* in *)
(* if continue *)
(* then loop (i+1) *)
(* else i *)
(* in *)
(* let res = loop 0 in *)
(* Pervasives.close_in ic; *)
(* res *)
(* in *)
(* let number_of_lines = float (count_lines file) in *)
(* let ic = Pervasives.open_in file in *)
(* let icw = Pervasives.open_in "warped.dat" in *)
(* Printf.printf "number_of_lines %f\n" number_of_lines; *)
(* let size = int_of_float (sqrt number_of_lines) in *)
(* let dummy_node = Node.make (-1) (Utm.of_latlon Geo.paris) (-1.) in *)
(* let m = Array.make_matrix size size dummy_node in *)
(* let rec loop () = *)
(* let maybe_s = *)
(* try *)
(* Some (Pervasives.input_line ic) *)
(* with End_of_file -> None *)
(* in *)
(* match maybe_s with *)
(* | Some s -> *)
(* let warped_pos = Scanf.sscanf (Pervasives.input_line icw) "%f %f" *)
(* (fun x y -> Utm.make x y) *)
(* in *)
(* let _ = Scanf.sscanf s "%i,%f,%f,%f" *)
(* (fun i lat lon weight -> *)
(* Printf.printf "reading node %i at pos %i\n" i (Pervasives.pos_in ic); *)
(* let n = Node.make i warped_pos weight in *)
(* set_id m i n) *)
(* in *)
(* loop () *)
(* | None -> (Pervasives.close_in ic; Pervasives.close_in icw) *)
(* in *)
(* loop (); *)
(* m *)