Module: Miyako::Utility

Defined in:
lib/Miyako/API/utility.rb

Overview

ユーティリティモジュール

Class Method Summary collapse

Class Method Details

.get_step_array_f(v1, v2, amount, skip_even = false) ⇒ Object

:nodoc:



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/Miyako/API/utility.rb', line 26

def Utility.get_step_array_f(v1, v2, amount, skip_even = false) #:nodoc:
  steps = []
  amount = amount.abs
  val = v1
  if v1 < v2
    loop do
      val = val + amount
      break if (skip_even && (v2-val).abs < Float::EPSILON)
      break if val > v2
      steps << val
    end
  else
    loop do
      val = val - amount
      break if (skip_even && (v2-val).abs < Float::EPSILON)
      break if val < v2
      steps << val
    end
  end
  return steps
end

.in_bounds?(mini_segment, big_segment, d, flag = false) ⇒ Boolean

小線分を移動させたとき、大線分が範囲内かどうかを判別する

移動後の小線分が大線分の範囲内にあるかどうかをtrue/falseで取得する

mini_segment

小線分の範囲。で構成された2要素の配列

big_segment

大線分の範囲。で構成された2要素の配列

d

mini_segmentの移動量

flag

大線分の端いっぱいも範囲外に含めるときはtrueを設定する。デフォルトはfalse

返却値

範囲内のときはtrue、範囲外の時はfalseを返す

Returns:

  • (Boolean)


272
273
274
275
276
277
# File 'lib/Miyako/API/utility.rb', line 272

def Utility.in_bounds?(mini_segment, big_segment, d, flag = false)
  nx = mini_segment[0] + d
  nx2 = mini_segment[1] + d
  nx, nx2 = nx2, nx if nx > nx2
  return flag ? (nx >= big_segment[0] && nx2 <= big_segment[1]) : (nx > big_segment[0] && (nx2 - 1) < big_segment[1])
end

.in_bounds_by_size?(pos1, size1, pos2, size2, d, flag = false) ⇒ Boolean

小線分を移動させたとき、大線分が範囲内かどうかを判別する

移動後の小線分が大線分の範囲内にあるかどうかをtrue/falseで取得する

mini_pos

小線分の開始点の位置

mini_size

小線分の幅。0以上の整数

big_pos

大線分の開始点の位置

big_size

大線分の幅。1以上の整数

d

mini_segmentの移動量

flag

大線分の端いっぱいも範囲外に含めるときはtrueを設定する。デフォルトはfalse

返却値

範囲内のときはtrue、範囲外の時はfalseを返す

Returns:

  • (Boolean)

Raises:



341
342
343
344
345
346
347
348
349
# File 'lib/Miyako/API/utility.rb', line 341

def Utility.in_bounds_by_size?(pos1, size1, pos2, size2, d, flag = false)
  raise MiyakoValueError, "illegal size1! #{size1}" if size1 < 0
  raise MiyakoValueError, "illegal size2! #{size2}" if size2 <= 0
  raise MiyakoValueError, "size1 is more than size2! #{size1}, #{size2}" if size1 > size2
  min_x1 = pos1 + d
  min_x2 = pos1 + size1 + d
  min_x1, min_x2 = min_x2, min_x1 if min_x1 > min_x2
  return flag ? (min_x1 >= pos2 && min_x2 <= pos2+size2) : (minx_x1 > pos2 && min_x2 < pos2+size2)
end

.in_bounds_ex?(mini_segment, big_segment, d, flag = false) ⇒ Boolean

小線分を移動させたとき、大線分が範囲内かどうかを判別して、その状態によって値を整数で返す

移動後の小線分の範囲が大線分の範囲内のときは0、 マイナス方向で範囲外に出るときは-1、 プラス方向で出るときは1を返す

mini_segment

小線分の範囲。で構成された2要素の配列

big_segment

大線分の範囲。で構成された2要素の配列

d

mini_segmentの移動量

flag

大線分の端いっぱいも範囲外に含めるときはtrueを設定する。デフォルトはfalse

返却値

判別の結果

Returns:

  • (Boolean)


288
289
290
291
292
293
294
# File 'lib/Miyako/API/utility.rb', line 288

def Utility.in_bounds_ex?(mini_segment, big_segment, d, flag = false)
  nx = mini_segment[0] + d
  nx2 = mini_segment[1] + d - 1
  nx, nx2 = nx2, nx if nx > nx2
  return -1 if (nx < big_segment[0]) || (flag && (nx == big_segment[0]))
  return (nx2 > big_segment[1]) || (flag && (nx2 == big_segment[1])) ? 1 : 0
end

.in_bounds_ex_by_size?(pos1, size1, pos2, size2, d, flag = false) ⇒ Boolean

小線分を移動させたとき、大線分が範囲内かどうかを判別して、その状態によって値を整数で返す

移動後の小線分の範囲が大線分の範囲内のときは0、 マイナス方向で範囲外に出るときは-1、 プラス方向で出るときは1を返す

mini_pos

小線分の開始点の位置

mini_size

小線分の幅。0以上の整数

big_pos

大線分の開始点の位置

big_size

大線分の幅。1以上の整数

d

mini_segmentの移動量

flag

大線分の端いっぱいも範囲外に含めるときはtrueを設定する。デフォルトはfalse

返却値

判別の結果

Returns:

  • (Boolean)

Raises:



362
363
364
365
366
367
368
369
370
371
# File 'lib/Miyako/API/utility.rb', line 362

def Utility.in_bounds_ex_by_size?(pos1, size1, pos2, size2, d, flag = false)
  raise MiyakoValueError, "illegal size1! #{size1}" if size1 < 0
  raise MiyakoValueError, "illegal size2! #{size2}" if size2 <= 0
  raise MiyakoValueError, "size1 is more than size2! #{size1}, #{size2}" if size1 > size2
  min_x1 = pos1 + d
  min_x2 = pos1 + size1 + d
  min_x1, min_x2 = min_x2, min_x1 if min_x1 > min_x2
  return -1 if (min_x1 < pos2) || (flag && (min_x1 == pos2))
  return (min_x2 > pos2+size2) || (flag && (min_x2 == pos2+size2)) ? 1 : 0
end

.in_bounds_rev?(mini_segment, big_segment, d, flag = false) ⇒ Boolean

移動先が表示範囲内かどうかを判別して、その状態によって値を整数で返す

移動後の小線分の範囲が大線分の範囲内のときは0、 マイナス方向で範囲外に出るときは1、 プラス方向で出るときは-1を返す

mini_segment

小線分の範囲。で構成された2要素の配列

big_segment

大線分の範囲。で構成された2要素の配列

d

mini_segmentの移動量

flag

大線分の端いっぱいも範囲外に含めるときはtrueを設定する。デフォルトはfalse

返却値

判別の結果

Returns:

  • (Boolean)


305
306
307
308
309
310
311
# File 'lib/Miyako/API/utility.rb', line 305

def Utility.in_bounds_rev?(mini_segment, big_segment, d, flag = false)
  nx = mini_segment[0] + d
  nx2 = mini_segment[1] + d - 1
  nx, nx2 = nx2, nx if nx > nx2
  return 1 if (nx < big_segment[0]) || (flag && (nx == big_segment[0]))
  return (nx2 > big_segment[1]) || (flag && (nx2 == big_segment[1])) ? -1 : 0
end

.in_bounds_rev_by_size?(pos1, size1, pos2, size2, d, flag = false) ⇒ Boolean

移動先が表示範囲内かどうかを判別して、その状態によって値を整数で返す

移動後の小線分の範囲が大線分の範囲内のときは0、 マイナス方向で範囲外に出るときは1、 プラス方向で出るときは-1を返す

mini_pos

小線分の開始点の位置

mini_size

小線分の幅。0以上の整数

big_pos

大線分の開始点の位置

big_size

大線分の幅。1以上の整数

d

mini_segmentの移動量

flag

大線分の端いっぱいも範囲外に含めるときはtrueを設定する。デフォルトはfalse

返却値

判別の結果

Returns:

  • (Boolean)

Raises:



384
385
386
387
388
389
390
391
392
393
# File 'lib/Miyako/API/utility.rb', line 384

def Utility.in_bounds_rev_by_size?(pos1, size1, pos2, size2, d, flag = false)
  raise MiyakoValueError, "illegal size1! #{size1}" if size1 < 0
  raise MiyakoValueError, "illegal size2! #{size2}" if size2 <= 0
  raise MiyakoValueError, "size1 is more than size2! #{size1}, #{size2}" if size1 > size2
  min_x1 = pos1 + d
  min_x2 = pos1 + size1 + d
  min_x1, min_x2 = min_x2, min_x1 if min_x1 > min_x2
  return 1 if (min_x1 < pos2) || (flag && (min_x1 == pos2))
  return (min_x2 > pos2+size2) || (flag && (min_x2 == pos2+size2)) ? -1 : 0
end

.in_bounds_rev_ex?(mini_segment, big_segment, d, flag = false) ⇒ Boolean

移動先が表示範囲内かどうかを判別して、その状態によって値を整数で返す

移動量が0のときは0、 移動後の小線分の範囲が大線分の範囲内のときは1、 範囲外に出るときは-1を返す

mini_segment

小線分の範囲。で構成された2要素の配列

big_segment

大線分の範囲。で構成された2要素の配列

d

mini_segmentの移動量

flag

大線分の端いっぱいも範囲外に含めるときはtrueを設定する。デフォルトはfalse

返却値

判別の結果

Returns:

  • (Boolean)


322
323
324
325
326
327
328
329
330
# File 'lib/Miyako/API/utility.rb', line 322

def Utility.in_bounds_rev_ex?(mini_segment, big_segment, d, flag = false)
  return 0 if d == 0
  dir = (d <=> 0)
  nx = mini_segment[0] + d
  nx2 = mini_segment[1] + d - 1
  nx, nx2 = nx2, nx if nx > nx2
  return -dir if (nx < big_segment[0]) || (flag && (nx == big_segment[0]))
  return (nx2 > big_segment[1]) || (flag && (nx2 == big_segment[1])) ? -dir : dir
end

.in_bounds_rev_ex_by_size?(pos1, size1, pos2, size2, d, flag = false) ⇒ Boolean

移動先が表示範囲内かどうかを判別して、その状態によって値を整数で返す

移動量が0のときは0、 移動後の小線分の範囲が大線分の範囲内のときは1、 範囲外に出るときは-1を返す

mini_pos

小線分の開始点の位置

mini_size

小線分の幅。0以上の整数

big_pos

大線分の開始点の位置

big_size

大線分の幅。1以上の整数

d

mini_segmentの移動量

flag

大線分の端いっぱいも範囲外に含めるときはtrueを設定する。デフォルトはfalse

返却値

判別の結果

Returns:

  • (Boolean)

Raises:



406
407
408
409
410
411
412
413
414
415
416
417
# File 'lib/Miyako/API/utility.rb', line 406

def Utility.in_bounds_rev_ex_by_size?(pos1, size1, pos2, size2, d, flag = false)
  return 0 if d == 0
  raise MiyakoValueError, "illegal size1! #{size1}" if size1 < 0
  raise MiyakoValueError, "illegal size2! #{size2}" if size2 <= 0
  raise MiyakoValueError, "size1 is more than size2! #{size1}, #{size2}" if size1 > size2
  dir = (d <=> 0)
  min_x1 = pos1 + d
  min_x2 = pos1 + size1 + d
  min_x1, min_x2 = min_x2, min_x1 if min_x1 > min_x2
  return -dir if (min_x1 < pos2) || (flag && (min_x1 == pos2))
  return (min_x2 > pos2+size2) || (flag && (min_x2 == pos2+size2)) ? -dir : dir
end

.interval(point1, point2) ⇒ Object

2点間の距離を算出する

2点(点1、点2)がどの程度離れているかを算出する。 返ってくる値は、正の実数で返ってくる

point1

点1の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)

point2

点2の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)

返却値

2点間の距離



240
241
242
243
244
245
# File 'lib/Miyako/API/utility.rb', line 240

def Utility.interval(point1, point2)
  #2点間の距離を求める
  d = Math.sqrt(((point1[0].to_f - point2[0].to_f) ** 2) +
                ((point1[1].to_f - point2[1].to_f) ** 2))
  return d < Float::EPSILON ? 0.0 : d
end

.product_inner(x1, y1, x2, y2, size) ⇒ Object

:nodoc:



161
162
163
164
165
# File 'lib/Miyako/API/utility.rb', line 161

def Utility.product_inner(x1, y1, x2, y2, size) #:nodoc:
  x_array = ((x1 / size[0])..(x2 / size[0])).to_a.map{|e| e * size[0]}
  y_array = ((y1 / size[1])..(y2 / size[1])).to_a.map{|e| e * size[1]}
  return x_array.product(y_array)
end

.product_inner_f(x1, y1, x2, y2, size, skip_even = false) ⇒ Object

:nodoc:



195
196
197
198
199
200
201
202
203
# File 'lib/Miyako/API/utility.rb', line 195

def Utility.product_inner_f(x1, y1, x2, y2, size, skip_even = false) #:nodoc:
  sz = size[0].to_f
  min = (x1.to_f/sz).floor.to_f * sz
  x_array = [min] + get_step_array_f(min, x2.to_f, sz, skip_even)
  sz = size[1].to_f
  min = (y1.to_f/sz).floor.to_f * sz
  y_array = [min] + get_step_array_f(min, y2.to_f, sz, skip_even)
  return x_array.uniq.product(y_array.uniq)
end

.product_liner(rect, amount = 1) ⇒ Object

矩形内の対角線の座標リストを取得する

矩形内の対角線の座標リストを取得する 引数には、Rect(x,y,w,h)形式のインスタンスを渡す 幅・高さはマイナスの値の設定が可能。 幅・高さのどちらかの値が0の場合は[]が返る 刻みの値は1以上の整数を渡す。0以下の場合は例外が発生する。 結果はの配列となるが、正確さを優先したため、必ず刻みの値の間隔で並んでいない (刻みの値より小さいことがある)ことがある

rect

矩形情報

amount

配列を作成する座標の刻み。デフォルトは1

返却値

矩形左上位置の配列(指定の矩形に掛かる位置の組み合わせ)

Raises:



134
135
136
137
138
139
140
141
142
# File 'lib/Miyako/API/utility.rb', line 134

def Utility.product_liner(rect, amount = 1)
  raise MiyakoValueError, "Illegal amount! #{amount}" if amount <= 0
  return [] if rect[2] == 0 || rect[3] == 0
  x1 = rect[0]
  y1 = rect[1]
  x2 = x1 + rect[2] - 1
  y2 = y1 + rect[3] - 1
  return product_liner_inner(x1, y1, x2, y2, amount)
end

.product_liner_by_square(square, amount = 1) ⇒ Object

矩形内の対角線の座標リストを取得する

矩形内の対角線の座標リストを取得する 引数には、Rect(x,y,w,h)形式のインスタンスを渡す 幅・高さはマイナスの値の設定が可能。 幅・高さのどちらかの値が0の場合は[]が返る 刻みの値は1以上の整数を渡す。0以下の場合は例外が発生する。 結果はの配列となるが、正確さを優先したため、必ず刻みの値の間隔で並んでいない (刻みの値より小さいことがある)ことがある

rect

矩形情報

amount

配列を作成する座標の刻み。デフォルトは1

返却値

矩形左上位置の配列(指定の矩形に掛かる位置の組み合わせ)

Raises:



155
156
157
158
159
# File 'lib/Miyako/API/utility.rb', line 155

def Utility.product_liner_by_square(square, amount = 1)
  raise MiyakoValueError, "Illegal amount! #{amount}" if amount <= 0
  return [] if (square[2] - square[0]) == 0 || (square[3] - square[1]) == 0
  return product_liner_inner(*square, amount)
end

.product_liner_by_square_f(square, amount = 1.0) ⇒ Object

矩形内の対角線の座標リストを実数で取得する

(互換性維持のために残している) 矩形内の対角線の座標リストを取得する 引数には、Rect(x,y,w,h)形式のインスタンスを渡す 幅・高さはマイナスの値の設定が可能。 幅・高さのどちらかの値が0(Float::EPSILON未満)の場合は[]が返る 刻みの値は1以上の整数を渡す。0(Float::EPSILON未満)以下の場合は例外が発生する。 結果はの配列となるが、正確さを優先したため、必ず刻みの値の間隔で並んでいない (刻みの値より小さい)ことがある

rect

矩形情報

amount

配列を作成する座標の刻み。デフォルトは1

返却値

矩形左上位置の配列(指定の矩形に掛かる位置の組み合わせ)

Raises:



95
96
97
98
99
# File 'lib/Miyako/API/utility.rb', line 95

def Utility.product_liner_by_square_f(square, amount = 1.0)
  raise MiyakoValueError, "Illegal amount! #{amount}" if amount < Float::EPSILON
  return [] if (square[2] - square[0]) < Float::EPSILON || (square[3] - square[1]) < Float::EPSILON
  return product_liner_inner_f(*square, amount)
end

.product_liner_f(rect, amount = 1.0) ⇒ Object

矩形内の対角線の座標リストを実数で取得する

(互換性維持のために残している) 矩形内の対角線の座標リストを取得する 引数には、Rect(x,y,w,h)形式のインスタンスを渡す 幅・高さはマイナスの値の設定が可能。 幅・高さのどちらかの値が0(Float::EPSILON未満)の場合は[]が返る 刻みの値は1以上の整数を渡す。0(Float::EPSILON未満)以下の場合は例外が発生する。 結果はの配列となるが、正確さを優先したため、必ず刻みの値の間隔で並んでいない (刻みの値より小さい)ことがある

rect

矩形情報

amount

配列を作成する座標の刻み。デフォルトは1.0

返却値

矩形左上位置の配列(指定の矩形に掛かる位置の組み合わせ)

Raises:



73
74
75
76
77
78
79
80
81
# File 'lib/Miyako/API/utility.rb', line 73

def Utility.product_liner_f(rect, amount = 1.0)
  raise MiyakoValueError, "Illegal amount! #{amount}" if amount < Float::EPSILON
  return [] if rect[2] < Float::EPSILON || rect[3] < Float::EPSILON
  x1 = rect[0]
  y1 = rect[1]
  x2 = x1 + rect[2] - 1
  y2 = y1 + rect[3] - 1
  return product_liner_inner_f(x1, y1, x2, y2, amount)
end

.product_liner_inner(x1, y1, x2, y2, amount) ⇒ Object

:nodoc:



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/Miyako/API/utility.rb', line 101

def Utility.product_liner_inner(x1, y1, x2, y2, amount) #:nodoc:
  array = nil
  step_x = []
  step_y = []
  dx = x2 - x1
  dy = y2 - y1
  a  = 0.0
  if [x1, y1, x2, y2, amount].all?{|v| v.methods.include?(:step)}
    step_x = x1 < x2 ? x1.step(x2, amount).to_a : x1.step(x2, -amount).to_a
    step_y = y1 < y2 ? y1.step(y2, amount).to_a : y1.step(y2, -amount).to_a
    a = dx == 0 ? dy.to_f : dy.to_f / dx.to_f
  else
    step_x = get_step_array_f(x1, x2, amount)
    step_y = get_step_array_f(y1, y2, amount)
    a = dx < Float::EPSILON ? dy.to_f : dy.to_f / dx.to_f
  end
  b = y1.to_f - a * x1.to_f
  array = [[x1,y1] , [x2,y2]] + step_x.map{|x| [x, (a * x.to_f + b).to_i]}
  array += step_y.map{|y| [((y.to_f - b) / a).to_i, y]} if (a.abs >= Float::EPSILON)
  return array.uniq
end

.product_liner_inner_f(x1, y1, x2, y2, amount) ⇒ Object

:nodoc:



48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/Miyako/API/utility.rb', line 48

def Utility.product_liner_inner_f(x1, y1, x2, y2, amount) #:nodoc:
  array = nil
  step_x = get_step_array_f(x1, x2, amount)
  step_y = get_step_array_f(y1, y2, amount)
  dx = x2 - x1
  dy = y2 - y1
  a = dx < Float::EPSILON ? dy.to_f : dy.to_f / dx.to_f
  b = y1.to_f - a * x1.to_f
  array = [[x1,y1] , [x2,y2]] + step_x.map{|x| [x, (a * x.to_f + b).to_i]}
  array += step_y.map{|y| [((y.to_f - b) / a).to_i, y]} if (a.abs >= Float::EPSILON)
  return array.uniq
end

.product_position(position, rect, size) ⇒ Object

指定の矩形が格子状のどこに重なっているかを返す

position(Point()形式)を基準として、矩形rect(Rect()形式)が、格子状の並べた矩形 (基準を[0,0]とした、大きさの矩形をタイル状に並べた物)にある場合、 どの格子状の矩形が重なっているかを、矩形の左上座標の配列として渡す(x座標とy座標の組み合わせ)。

position

基準位置

rect

矩形情報

返却値

矩形左上位置の配列(指定の矩形に掛かる位置の組み合わせ)



175
176
177
178
179
180
181
182
183
# File 'lib/Miyako/API/utility.rb', line 175

def Utility.product_position(position, rect, size)
  return product_inner(
           position[0] + rect[0],
           position[1] + rect[1],
           position[0] + rect[0] + rect[2] - 1,
           position[1] + rect[1] + rect[3] - 1,
           size
         )
end

.product_position_by_square(square, size) ⇒ Object

指定の矩形が格子状のどこに重なっているかを返す

矩形square(Square()形式)が、格子状の並べた矩形 (基準を[0,0]とした、大きさの矩形をタイル状に並べた物)にある場合、 どの格子状の矩形が重なっているかを、矩形の左上座標の配列として渡す(x座標とy座標の組み合わせ)。

square

矩形情報

返却値

矩形左上位置の配列(指定の矩形に掛かる位置の組み合わせ)



191
192
193
# File 'lib/Miyako/API/utility.rb', line 191

def Utility.product_position_by_square(square, size)
  return product_inner(*square.to_a, size)
end

.product_position_by_square_f(square, size) ⇒ Object

指定の矩形が格子状のどこに重なっているかを返す(実数で指定)

矩形square(Square()形式)が、格子状の並べた矩形 (基準を[0.0,0.0]とした、大きさの矩形をタイル状に並べた物)にある場合、 どの格子状の矩形が重なっているかを、矩形の左上座標の配列として渡す(x座標とy座標の組み合わせ)。

square

矩形情報

返却値

矩形左上位置の配列(指定の矩形に掛かる位置の組み合わせ)



230
231
232
# File 'lib/Miyako/API/utility.rb', line 230

def Utility.product_position_by_square_f(square, size)
  return product_inner_f(*square.to_a, size)
end

.product_position_f(position, rect, size) ⇒ Object

指定の矩形が格子状のどこに重なっているかを返す(実数で指定)

position(Point()形式)を基準として、矩形rect(Rect()形式)が、格子状の並べた矩形 (基準を[0.0,0.0]とした、大きさの矩形をタイル状に並べた物)にある場合、 どの格子状の矩形が重なっているかを、矩形の左上座標の配列として渡す(x座標とy座標の組み合わせ)。

position

基準位置

rect

矩形情報

返却値

矩形左上位置の配列(指定の矩形に掛かる位置の組み合わせ)



213
214
215
216
217
218
219
220
221
222
# File 'lib/Miyako/API/utility.rb', line 213

def Utility.product_position_f(position, rect, size)
  return product_inner_f(
           position[0] + rect[0],
           position[1] + rect[1],
           position[0] + rect[0] + rect[2],
           position[1] + rect[1] + rect[3],
           size,
           true
         )
end

.theta(point1, point2) ⇒ Object

2点間の傾きを角度で算出する

2点(点1、点2)がどの程度傾いているか算出する。傾きの中心は点1とする。 角度の単位は度(0.0<=θ<360.0) 返ってくる値は、正の実数で返ってくる

point1

点1の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)

point2

点2の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)

返却値

2点間の傾き



254
255
256
257
258
259
260
261
262
263
# File 'lib/Miyako/API/utility.rb', line 254

def Utility.theta(point1, point2)
  #2点間の距離を求める
  d = Math.sqrt(((point1[0].to_f - point2[0].to_f) ** 2) +
                ((point1[1].to_f - point2[1].to_f) ** 2))
  x = point2[0].to_f - point[1].to_f
  # 傾き・幅が0のときは傾きは0度
  return 0.0 if (x.abs < Float::EPSILON or d < Float::EPSILON)
  theta = (Math.acos(x / d) / (2 * Math::PI)) * 360.0
  return theta < Float::EPSILON ? 0.0 : theta
end