ruby-grads 1.0.0 → 1.0.7

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.
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)