#!/usr/bin/ruby
#
# isin(), icos() を作るためのスクリプト
# Satofumi KAMIMURA
# $Id: create_isincos.rb 1203 2009-08-03 01:53:16Z satofumi $

# 絶対値の最大値、角度分割数の設定
angle_div = 65536               # [0, 65535]
divid_shift = 15                # [-32767, +32767]
divid_max = 1 << divid_shift
angle_quad = angle_div >> 2

# 分割具合の設定 (0で誤差なし)
#table_shift_value = 5
table_shift_value = 0

if ARGV[0] == "header"
print <<-"EOB"
#ifndef I_SIN_COS_H
#define I_SIN_COS_H

/*!
  \\file
  \\brief 整数型の sin(), cos()

  整数型の三角関数(sin(), cos())を提供
  角度の細かさ、最大値はコンパイル時に指定

  \\author Satofumi KAMIMURA

  $Id: create_isincos.rb 1203 2009-08-03 01:53:16Z satofumi $
*/


enum {
  ISINCOS_ANGLE_DIVIDED = #{angle_div}, /* [0, #{angle_div}] */
  ISINCOS_VALUE_MAX = #{divid_max},	/* [-#{divid_max}, +#{divid_max}] */
  ISINCOS_VALUE_SHIFT = #{divid_shift},
};


extern int isin(unsigned short dir16);
extern int icos(unsigned short dir16);

#endif /* !I_SIN_COS_H */

EOB
  exit
end

# テーブル部分の出力

# get this file name
__FILE__ =~ /\/*(.+)$/
thisFile = $1

print <<-"EOB"
/*
  \\brief 整数型の sin, cos 関数

  This program generated by #{thisFile}

  \\author Satofumi KAMIMURA

  $Id: create_isincos.rb 1203 2009-08-03 01:53:16Z satofumi $

  angle_max = #{angle_div-1}
  divid_max = #{divid_max}
*/

#include "isincos.h"


static unsigned short sin_table[] = {
EOB

# 中の数値の表示
for i in 0 .. angle_div.to_i
  if i > (angle_quad.to_i >> table_shift_value)
    break
  end
  sin_val = divid_max.to_i \
  * Math::sin((2.0 * Math::PI * (i << table_shift_value).to_f / angle_div.to_f))
  print ' ', sin_val.round, ','
  if (i+1) % 10 == 0
    print "\n"
  end
end
print "};\n\n"

# isin(), icos() の部分の出力
print <<-"EOB"

static int sin_table_func(int n) {
EOB
if table_shift_value == 0
  print "  return sin_table[n];\n"
else
  print "  return sin_table[n >> #{table_shift_value}];\n"
end
print <<-"EOB"
}

/*!
  \\brief 整数型の sin()

  整数型の sin()

  \\param dir16 [i] 角度[dir16]
  \\retval divid_max * sin(2.0 * M_PI * dir16 / 65536.0)
*/
int isin(unsigned short dir16) {
  int ret;

  if (dir16 <= #{angle_quad}) {
    ret = sin_table_func(dir16);
  } else if (dir16 <= #{2 * angle_quad}) {
    ret = sin_table_func(#{2 * angle_quad} - dir16);
  } else if (dir16 <= #{3 * angle_quad}) {
    ret = -sin_table_func(dir16 -#{2 * angle_quad});
  } else {
    ret = -sin_table_func(#{4 * angle_quad} - dir16);
  }
  return ret;
}


/*!
  \\brief 整数型の cos()

  整数型の cos()。

  \\param dir16 [i] 角度[dir16]
  \\retval divid_max * cos(2.0 * M_PI * dir16 / 65536.0)
*/
int icos(unsigned short dir16) {
  dir16 += #{3 * angle_quad};
EOB
if angle_div-1 != 0xffff
  print "  dir16 &= #{angle_div - 1};\n"
end
print <<-"EOB"
  return -isin(dir16);
}
EOB
