ruby-grads 1.0.0 → 1.0.7

Sign up to get free protection for your applications and to get access to all the features.
data/lib/grads/command.rb CHANGED
@@ -75,8 +75,15 @@ class GrADS::Command
75
75
  return @expr
76
76
  end
77
77
  alias to_str to_s
78
- def [] (hash)
79
- spec = ["(",hash.map{ |k,v| [k,"=",v].join("") }.join(","),")"].join("")
78
+ def [] (expr)
79
+ case expr
80
+ when Hash
81
+ spec = ["(",hash.map{ |k,v| [k,"=",v].join("") }.join(","),")"].join("")
82
+ when String
83
+ spec = "("+expr+")"
84
+ else
85
+ raise "unknown expression"
86
+ end
80
87
  return Expression.new([@expr,spec].join(""))
81
88
  end
82
89
  def method_missing (id, *argv)
@@ -176,7 +183,11 @@ class GrADS::Command
176
183
  attr_reader :log
177
184
 
178
185
  def method_missing (id, *argv)
179
- return id, *argv
186
+ if argv.empty?
187
+ return id
188
+ else
189
+ super
190
+ end
180
191
  end
181
192
 
182
193
  def quit
@@ -402,7 +413,6 @@ class GrADS::Command
402
413
  "reinit",
403
414
  "reset",
404
415
  "run",
405
- "sdfwrite",
406
416
  "swap",
407
417
  "undefine",
408
418
  ].each do |name|
@@ -413,9 +423,21 @@ class GrADS::Command
413
423
  }
414
424
  end
415
425
 
426
+ [
427
+ "sdfwrite",
428
+ ].each do |name|
429
+ class_eval %{
430
+ def #{name} (*argv)
431
+ if argv.empty?
432
+ return :#{name}
433
+ else
434
+ put "#{name} " + argv.join(" ")
435
+ end
436
+ end
437
+ }
438
+ end
439
+
416
440
  def clear (*argv)
417
- @ccols = nil
418
- @clevs = nil
419
441
  put "clear " + argv.join(" ")
420
442
  end
421
443
 
@@ -518,13 +540,20 @@ class GrADS::Command
518
540
  end
519
541
 
520
542
  def set_clevs (*argv)
521
- @clevs = argv
522
543
  set :clevs, *argv
523
544
  end
524
545
 
525
546
  def set_ccols (*argv)
526
- @ccols = argv
527
- set :ccols, *argv
547
+ list = []
548
+ argv.each do |arg|
549
+ case arg
550
+ when RGB
551
+ list << set_rgb(arg)
552
+ else
553
+ list << arg
554
+ end
555
+ end
556
+ set :ccols, *list
528
557
  end
529
558
 
530
559
  def import (*args)
@@ -646,7 +675,7 @@ class GrADS::Command
646
675
  end
647
676
 
648
677
  begin
649
- require "netcdflib"
678
+ require "simple-netcdf"
650
679
  def get_var (expr)
651
680
  @var_id ||= 0
652
681
  @var_id += 1
@@ -730,6 +759,395 @@ class GrADS::Command
730
759
  end
731
760
  end
732
761
 
762
+ class Area
763
+
764
+ def initialize (x1, x2, y1, y2)
765
+ @x1 = x1
766
+ @x2 = x2
767
+ @y1 = y1
768
+ @y2 = y2
769
+ end
770
+
771
+ attr_reader :x1, :x2, :y1, :y2
772
+
773
+ def w
774
+ return @x2 - @x1
775
+ end
776
+
777
+ def h
778
+ return @y2 - @y1
779
+ end
780
+
781
+ def center
782
+ return @x1 + w/2
783
+ end
784
+
785
+ def mid
786
+ return @y1 + h/2
787
+ end
788
+
789
+ end
790
+
791
+ def len (str)
792
+ ans = query("string #{str}")
793
+ return subwrd(ans, 4).to_f
794
+ end
795
+
796
+ def parea (x1, x2, y1, y2)
797
+ set :parea, x1, x2, y1, y2
798
+ set :clip, x1, x2, y1, y2
799
+ yield Area.new(x1, x2, y1, y2)
800
+ end
801
+
802
+ def vpage (x1, x2, y1, y2)
803
+ set :vpage, x1, x2, y1, y2
804
+ yield Area.new(x1, x2, y1, y2)
805
+ end
806
+
807
+ def display_nothing (dummy)
808
+ ans = query("dims")
809
+ case ans.scan("varying").size
810
+ when 2
811
+ set :gxout, :contour
812
+ set :clevs, -9.99e99
813
+ set :ccolor, -1
814
+ set :clab, :off
815
+ set :cmark, 0
816
+ when 1
817
+ set :gxout, :line
818
+ set :line, -1
819
+ set :ylab, :off
820
+ set :vrange, -9.99e99, -9.99e98
821
+ end
822
+ if block_given?
823
+ yield
824
+ end
825
+ case dummy
826
+ when String
827
+ put "display #{dummy}"
828
+ else
829
+ display dummy
830
+ end
831
+ end
832
+
833
+ def axis_off
834
+ set :frame, :off
835
+ set :xlab, :off
836
+ set :ylab, :off
837
+ set :grid, :off
838
+ set :grads, :off
839
+ set :mpdraw, :off
840
+ end
841
+
842
+ def axis_on
843
+ set :frame, :on
844
+ set :xlab, :on
845
+ set :ylab, :on
846
+ set :grid, :on
847
+ set :grads, :on
848
+ set :mpdraw, :on
849
+ end
850
+
851
+ def plot (var, *args)
852
+ begin
853
+ axis_off
854
+ if block_given?
855
+ yield
856
+ end
857
+ set :gxout, *args
858
+ case var
859
+ when String
860
+ put "display #{var}"
861
+ else
862
+ display var
863
+ end
864
+ ensure
865
+ axis_on
866
+ end
867
+ end
868
+
869
+ def axis (dummy, &block)
870
+ begin
871
+ axis_on
872
+ display_nothing(dummy, &block)
873
+ ensure
874
+ axis_off
875
+ end
876
+ end
877
+
878
+ def draw_ylabel (text, area:, color: 1, just: "bc", thickness: 3, rot: 90, offset: "M", side: "l")
879
+ set :string, color, just, thickness, rot
880
+ case side
881
+ when "l"
882
+ draw :string, area.x1-len(offset), area.mid, text
883
+ when "r"
884
+ draw :string, area.x2+len(offset), area.mid, text
885
+ else
886
+ raise "invalid side sepecification"
887
+ end
888
+ end
889
+
890
+ def draw_xlabel (text, area:, color: 1, just: "bc", thickness: 3, rot: 0, offset: "M", side: "b")
891
+ set :string, color, just, thickness, rot
892
+ case side
893
+ when "b"
894
+ draw :string, area.center, area.y1-len(offset), text
895
+ when "t"
896
+ draw :string, area.center, area.y2+len(offset), text
897
+ else
898
+ raise "invalid side sepecification"
899
+ end
900
+ end
901
+
902
+ COLOR_TABLE = {
903
+ "background" => 0,
904
+ "foregraound" => 1,
905
+ "red" => 2,
906
+ "green" => 3,
907
+ "dark blue" => 4,
908
+ "light blue" => 5,
909
+ "magenta" => 6,
910
+ "yellow" => 7,
911
+ "orange" => 8,
912
+ "purple" => 9,
913
+ "yellow green" => 10,
914
+ "medium blue" => 11,
915
+ "dark yellow" => 12,
916
+ "aqua" => 13,
917
+ "dark purple" => 14,
918
+ "gray" => 15,
919
+ }
920
+
921
+ def COLOR (name)
922
+ if COLOR_TABLE.has_key?(name)
923
+ COLOR_TABLE[name]
924
+ else
925
+ -1
926
+ end
927
+ end
928
+
929
+ class LINE
930
+
931
+ def initialize (type = 1, color: 1, thickness: 3)
932
+ case type
933
+ when "","solid"
934
+ @type = 1
935
+ when "--", "long dash"
936
+ @type = 2
937
+ when "-", "short dash"
938
+ @type = 3
939
+ when "-- -", "long dash short dash"
940
+ @type = 4
941
+ when ".", "dotted"
942
+ @type = 5
943
+ when ". -", "dot dash"
944
+ @type = 6
945
+ when ". . -", "dot dot dash"
946
+ @type = 7
947
+ else
948
+ @type = type
949
+ end
950
+ @color = color
951
+ @thickness = thickness
952
+ end
953
+
954
+ attr_reader :type, :color
955
+
956
+ def to_a
957
+ return [@color, @type, @thickness]
958
+ end
959
+
960
+ end
961
+
962
+ class TILE
963
+
964
+ def self.reset
965
+ @@number = 0
966
+ end
967
+
968
+ def self.next_number
969
+ @@number += 1
970
+ if @@number > 2047
971
+ reset
972
+ end
973
+ return @@number
974
+ end
975
+
976
+ reset
977
+
978
+ def initialize (type, width: 6, height: nil, thickness: 3, color: 1, bgcolor: -1)
979
+ case type
980
+ when "."
981
+ @type = 2
982
+ when "\\"
983
+ @type = 3
984
+ when "/"
985
+ @type = 4
986
+ when "x"
987
+ @type = 5
988
+ when "|"
989
+ @type = 6
990
+ when "-"
991
+ @type = 7
992
+ when "#", "+"
993
+ @type = 8
994
+ else
995
+ @type = type
996
+ end
997
+ @width = width
998
+ @height = height || width
999
+ @thickness = thickness
1000
+ @color = color
1001
+ @bgcolor = bgcolor
1002
+ end
1003
+
1004
+ attr_reader :type, :color
1005
+
1006
+ def to_a
1007
+ return [@type, @width, @height, @thickness, @color, @bgcolor]
1008
+ end
1009
+
1010
+ end
1011
+
1012
+ class RGB
1013
+
1014
+ @@number = nil
1015
+ @@table = {}
1016
+
1017
+ def self.reset
1018
+ @@number = 100
1019
+ end
1020
+
1021
+ def self.next_number
1022
+ @@number += 1
1023
+ if @@number > 2047
1024
+ reset
1025
+ end
1026
+ return @@number
1027
+ end
1028
+
1029
+ reset
1030
+
1031
+ def initialize (r, g, b, a=255)
1032
+ @r = r
1033
+ @g = g
1034
+ @b = b
1035
+ @a = a
1036
+ end
1037
+
1038
+ attr_reader :r, :g, :b, :a
1039
+
1040
+ def to_s
1041
+ return format("%i %i %i %i", @r, @g, @b, @a)
1042
+ end
1043
+
1044
+ def to_a
1045
+ return [@r, @g, @b, @a]
1046
+ end
1047
+
1048
+ def % (alpha)
1049
+ if alpha >= 0 and alpha <= 1
1050
+ a = (@a*alpha).to_i
1051
+ else
1052
+ raise "invalid alpha value"
1053
+ end
1054
+ return RGB.new(@r, @g, @b, a)
1055
+ end
1056
+
1057
+ def * (scale)
1058
+ if scale >= 0 and scale <= 1
1059
+ return RGB.new((@r*scale).to_i, (@g*scale).to_i, (@b*scale).to_i, @a)
1060
+ else
1061
+ raise "invalid scale value"
1062
+ end
1063
+ end
1064
+
1065
+ def / (scale)
1066
+ if scale >= 1
1067
+ return RGB.new((@r/scale).to_i, (@g/scale).to_i, (@b/scale).to_i, @a)
1068
+ else
1069
+ raise "invalid scale value"
1070
+ end
1071
+ end
1072
+
1073
+ def + (other)
1074
+ r = [self.r, other.r].max
1075
+ g = [self.g, other.g].max
1076
+ b = [self.b, other.b].max
1077
+ a = [self.a, other.a].max
1078
+ return RGB.new(r,g,b,a)
1079
+ end
1080
+
1081
+ end
1082
+
1083
+ def LINE (*argv)
1084
+ return LINE.new(*argv)
1085
+ end
1086
+
1087
+ def TILE (*argv)
1088
+ return TILE.new(*argv)
1089
+ end
1090
+
1091
+ def RGB (*argv)
1092
+ case argv.size
1093
+ when 1
1094
+ return GrADS::Command::RGB_TABLE[argv[0]]
1095
+ else
1096
+ return GrADS::Command::RGB.new(*argv)
1097
+ end
1098
+ end
1099
+
1100
+ def self.RGB (*argv)
1101
+ case argv.size
1102
+ when 1
1103
+ return GrADS::Command::RGB_TABLE[argv[0]]
1104
+ else
1105
+ return GrADS::Command::RGB.new(*argv)
1106
+ end
1107
+ end
1108
+
1109
+ RGB_TABLE = {
1110
+ "red" => RGB(255,0,0),
1111
+ "green" => RGB(0,255,0),
1112
+ "blue" => RGB(0,0,255),
1113
+ }
1114
+ RGB_TABLE.update({
1115
+ "cyan" => RGB("green") + RGB("blue"),
1116
+ })
1117
+
1118
+ def set_line (obj)
1119
+ args = obj.to_a
1120
+ if obj.color.is_a?(RGB)
1121
+ args[0] = set_rgb(obj.color)
1122
+ end
1123
+ set :line, *args
1124
+ set :ccolor, args[0]
1125
+ set :cstyle, args[1]
1126
+ set :cthick, args[2]
1127
+ end
1128
+
1129
+ def set_rgb (*argv)
1130
+ list = []
1131
+ argv.each do |obj|
1132
+ num = RGB.next_number
1133
+ case obj
1134
+ when TILE
1135
+ nt = TILE.next_number
1136
+ args = obj.to_a
1137
+ if obj.color.is_a?(RGB)
1138
+ c = set_rgb(obj.color)
1139
+ args[4] = c
1140
+ end
1141
+ set :tile, nt, *args.to_a
1142
+ set :rgb, num, :tile, nt
1143
+ when RGB
1144
+ set :rgb, num, *obj.to_a
1145
+ end
1146
+ list << num
1147
+ end
1148
+ return list
1149
+ end
1150
+
733
1151
  end
734
1152
 
735
1153
  def GrADS.start (*argv, &block)
@@ -748,4 +1166,3 @@ def GrADS.script (name, definition)
748
1166
  end
749
1167
 
750
1168
 
751
-
data/lib/grads/gridded.rb CHANGED
@@ -34,6 +34,16 @@
34
34
  require "carray"
35
35
  require "strscan"
36
36
 
37
+ begin
38
+ require "simple-proj"
39
+ require "simple-proj-carray"
40
+ rescue LoadError
41
+ begin
42
+ require "proj4r"
43
+ rescue LoadError
44
+ end
45
+ end
46
+
37
47
  module GrADS
38
48
  end
39
49
 
@@ -128,9 +138,10 @@ end
128
138
 
129
139
  class GrADS::Gridded
130
140
 
131
- def initialize (ctl_file)
141
+ def initialize (ctl_file, radius: nil)
132
142
  @ctl_file = ctl_file
133
143
  @entries = scan_ctl_file(ctl_file)
144
+ @radius = radius
134
145
  parse_entries(@entries)
135
146
  end
136
147
 
@@ -319,7 +330,13 @@ class GrADS::Gridded
319
330
  end
320
331
 
321
332
  def parse_pdef_lcc (args)
322
- require "proj4r"
333
+ if defined? PROJ4 and defined? PROJ4::Proj
334
+ projlib = "proj4r"
335
+ elsif defined? PROJ
336
+ projlib = "simple-proj"
337
+ else
338
+ raise "can't find proj related library"
339
+ end
323
340
  rlat = args[1].to_f
324
341
  rlon = args[2].to_f
325
342
  xi = args[3].to_f
@@ -330,21 +347,61 @@ class GrADS::Gridded
330
347
  dx = args[8].to_f
331
348
  dy = args[9].to_f
332
349
  slat0 = slat1 > 0 ? 90 : -90
333
- proj = PROJ4::Proj.new %{
334
- +ellps=sphere +proj=lcc \
335
- +lat_1=#{slat1} +lat_2=#{slat2} +lat_0=90 +lon_0=#{slon}
336
- }
350
+ case projlib
351
+ when "proj4r"
352
+ if @radius
353
+ proj = PROJ4::Proj.new %{
354
+ +ellps=sphere +a=#{@radius} +b=#{@radius} +proj=lcc \
355
+ +lat_1=#{slat1} +lat_2=#{slat2} +lon_0=#{slon}
356
+ }
357
+ else
358
+ proj = PROJ4::Proj.new %{
359
+ +ellps=sphere +proj=lcc \
360
+ +lat_1=#{slat1} +lat_2=#{slat2} +lon_0=#{slon}
361
+ }
362
+ end
363
+ when "simple-proj"
364
+ if @radius
365
+ proj = PROJ.new %{
366
+ +ellps=sphere +a=#{@radius} +b=#{@radius} +proj=lcc \
367
+ +lat_1=#{slat1} +lat_2=#{slat2} +lon_0=#{slon}
368
+ }
369
+ else
370
+ proj = PROJ.new %{
371
+ +ellps=sphere +proj=lcc \
372
+ +lat_1=#{slat1} +lat_2=#{slat2} +lon_0=#{slon}
373
+ }
374
+ end
375
+ end
337
376
  rx, ry = proj.forward(rlon, rlat)
338
377
  rx0 = rx - (xi-1)*dx
339
378
  ry0 = ry - (yi-1)*dy
340
- @forward = lambda { |lon, lat|
341
- mx, my = proj.forward(lon, lat)
342
- [(mx - rx0)/dx, (my - ry0)/dy]
343
- }
344
- @inverse = lambda { |fi, fj|
345
- mx = fi*dx + rx0
346
- my = fj*dy + ry0
347
- proj.inverse(mx, my)
379
+ case projlib
380
+ when "proj4r"
381
+ @forward = lambda { |lon, lat|
382
+ mx, my = proj.forward(lon, lat)
383
+ [(mx - rx0)/dx, (my - ry0)/dy]
384
+ }
385
+ @inverse = lambda { |fi, fj|
386
+ mx = fi*dx + rx0
387
+ my = fj*dy + ry0
388
+ proj.inverse(mx, my)
389
+ }
390
+ when "simple-proj"
391
+ @forward = lambda { |lon, lat|
392
+ mx, my = proj.forward_carray(lon, lat)
393
+ [(mx - rx0)/dx, (my - ry0)/dy]
394
+ }
395
+ @inverse = lambda { |fi, fj|
396
+ mx = fi*dx + rx0
397
+ my = fj*dy + ry0
398
+ proj.inverse_carray(mx, my)
399
+ }
400
+ end
401
+ @xy = lambda {
402
+ x = CArray.float(xsize).seq(rx0, dx)
403
+ y = CArray.float(ysize).seq(ry0, dy)
404
+ [x, y]
348
405
  }
349
406
  end
350
407
 
@@ -495,6 +552,18 @@ class GrADS::Gridded
495
552
  def forward (rlon, rlat)
496
553
  return @forward[rlon, rlat]
497
554
  end
555
+
556
+ def lonlat
557
+ fi = CArray.float(xsize).seq
558
+ fj = CArray.float(ysize).seq
559
+ ii = fi[ysize,:%]
560
+ jj = fj[:%,xsize]
561
+ return @inverse[ii, jj]
562
+ end
563
+
564
+ def xy
565
+ return @xy[]
566
+ end
498
567
 
499
568
  def var (name)
500
569
  unless @varnames.include?(name)