天体の基本理解に、「Illustratorで星図と星座を描くスクリプト」 constellation_boundary.txt
constellation_line.txt
star_map.txt
をそのまま利用。
java なので さらにアンドロイドアプリへ発展。...▼
Star.java (星データの読み込み + 星クラス)
前出のデータとコンパイル済のファイルを同じディレクトリに配置して
java Star
で起動。
●参考情報
阿南市科学センターで公開される星座早見PDF
http://ananscience.jp/science/tenmonkan/gallery.htm
http://ananscience.jp/science/tenmonkan/hayamiban/ASC_hayami_201803ver.pdf
星空PDF生成
https://hoshifuru.jp/pdf/
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.List;
import java.awt.Point;
/*
* 星データ構造体
*/
class Star{
int hip; //ヒッパルコスHIP番号:1~120416
int vmag; //視等級 索引0~8に収める変換 冗長ロジック
Point prd; //100倍 赤経right ascension,赤緯declination
String proper;//星名
int getRas(){ return prd.x; };//赤経
int getDsc(){ return prd.y; };//赤緯
/**
* コンストラクタ
* @param s 初期化配列
* s[0] ヒッパルコスHIP番号:1~120416
* s[1] 赤経
* s[2] 赤緯
* s[3] 視等級
* 0.5未満 明るい
* 0.5~1未満
* 1~1.5未満
* 1.5~2未満
* 2
* 3
* 4
* 5
* 6 暗い
* s[4] 星名
*/
Star( String[] s )throws java.lang.NumberFormatException{
hip = Tool.IntegerParseInt( s[0] );
prd = new Point( Tool.FloatParseFloatx100( s[1] ), Tool.FloatParseFloatx100( s[2] ) );
vmag= Tool.FloatParseFloatx100( s[3] );
proper= ( 4 < s.length ) ? s[4] : null;
if( 0 < Tool.listMessages.size() ){
String str= Tool.listMessages.toString();
Tool.listMessages.clear();
throw new java.lang.NumberFormatException( str );
}
}
/**
* @param s 入力ファイル名
* @return List<星>
*/
static List<Star> load( String s ){
List<Star> list= new java.util.ArrayList<Star>();
int i= 0;
BufferedReader reader= null;
try{
reader= new BufferedReader( new InputStreamReader(
new FileInputStream( s ), Charset.forName( "UTF-8" ) ) );//Shift-JIS
String line;
while( ( null != ( line = reader.readLine() ) ) ){
// System.out.print( String.format( "[%s]", line ) );
try{
list.add( new Star( line.split( "\t" ) ) );
}catch( Exception e ){
System.err.println( String.format( "Skip:%d %s", i, e.getMessage() ) );
}
i++;
}
}catch( IOException e ){
e.printStackTrace();
}finally{
try{
if( reader != null )reader.close();
}catch( IOException e ){
System.err.println( e );
}
}
System.out.println( String.format( "ok:%5d / in:%5d [%s]", list.size(), i, s ) );
return list;
}
public static List<Star> loadFile(){
return load( "star_map.txt" );
}
public static void main( String[] args ){
List<Star> list= loadFile();
}
}
ConstellationLine (ラインデータの読み込み + ラインクラス)
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.List;
import java.awt.Point;
/*
* 星座線 境界線 データ構造体
*/
class ConstellationLine{
int id; //星座ID
Point ps;//100倍 赤経right ascension,赤緯declination 開点
Point pe;//100倍 赤経right ascension,赤緯declination 終点
int getRasStart(){ return ps.x; };
int getDscStart(){ return ps.y; };
int getRasEnd(){ return pe.x; };
int getDscEnd(){ return pe.y; };
/**
* コンストラクタ
* @param s 初期化配列
* s[0] 星座ID
* s[1] 赤経始点
* s[2] 赤緯始点
* s[3] 赤経終点
* s[4] 赤緯終点
*/
ConstellationLine( String[] s )throws java.lang.NumberFormatException{
id = Tool.IntegerParseInt( s[0] );
ps = new Point( Tool.FloatParseFloatx100( s[1] ), Tool.FloatParseFloatx100( s[2] ) );
pe = new Point( Tool.FloatParseFloatx100( s[3] ), Tool.FloatParseFloatx100( s[4] ) );
if( 0 < Tool.listMessages.size() ){
String str= Tool.listMessages.toString();
Tool.listMessages.clear();
throw new java.lang.NumberFormatException( str );
}
}
/**
* @param s 入力ファイル名
* @return List<線分>
*/
static List<ConstellationLine> load( String s ){
List<ConstellationLine> list= new java.util.ArrayList<ConstellationLine>();
int i= 0;
BufferedReader reader= null;
try{
reader= new BufferedReader( new InputStreamReader(
new FileInputStream( s ), Charset.forName( "UTF-8" ) ) );//Shift-JIS
String line;
while( ( null != ( line = reader.readLine() ) ) ){
try{
list.add( new ConstellationLine( line.split( "\t" ) ) );
}catch( Exception e ){
System.err.println( String.format( "Skip:%d %s", i, e.getMessage() ) );
}
i++;
}
}catch( IOException e ){
e.printStackTrace();
}finally{
try{
if( reader != null )reader.close();
}catch( IOException e ){
System.err.println( e );
}
}
System.out.println( String.format( "ok:%5d / in:%5d [%s]", list.size(), i, s ) );
return list;
}
public static List<ConstellationLine> loadFile(){
return load( "constellation_line.txt" );
}
public static List<ConstellationLine> loadFileBoundary(){
return load( "constellation_boundary.txt" );
}
public static void main( String[] args ){
List<ConstellationLine> list= loadFile();
List<ConstellationLine> list2= loadFileBoundary();
}
}
Tool.java (読込データパース共通メソッド)
import java.util.List;
class Tool{
static java.util.List<String> listMessages= new java.util.ArrayList<String>();
static int IntegerParseInt( String s ){
int i= 0;
try{
i= Integer.parseInt( s );
}catch( java.lang.NumberFormatException e ){
listMessages.add( e.getMessage() );
}
return i;
}
static int FloatParseFloatx100( String s ){
int i= 0;
try{
i= (int)( 100F * Float.parseFloat( s ) );
}catch( java.lang.NumberFormatException e ){
listMessages.add( e.getMessage() );
}
return i;
}
}
Astro.java (描画フレーム)
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
class Astro extends Frame{
static enum TYPE{
Mercator //全天(赤緯-60~60の範囲のみ)メルカトル図法
, North //北天 正距方位図法
, South //南天 正距方位図法
};
static double DEG2RAD = Math.PI / 180;//度数からラジアンに変換
static int ZOOM = 4;//座標倍率
static List<Star> listStar;//星データ
static List<ConstellationLine> listConstellationLine;//星座線
static List<ConstellationLine> listConstellationBoundary;//星座境界線
MyCanvas canvas;//複数ウィンドウ可能
TYPE type= TYPE.Mercator;
public static void main( String[] args ){
listStar= Star.loadFile();
listConstellationLine= ConstellationLine.loadFile();
listConstellationBoundary= ConstellationLine.loadFileBoundary();
new Astro();
}
/** constructor */
Astro(){
addWindowListener( new java.awt.event.WindowAdapter(){
public void windowClosing( java.awt.event.WindowEvent e ){
System.exit( 0 );
}
} );
Button button1= new Button( "Mercator" );
button1.addActionListener( new ActionListener(){
@Override
public void actionPerformed( ActionEvent e ){
type= TYPE.Mercator;
canvas.repaint();
}
});
Button button2= new Button( "North" );
button2.addActionListener( new ActionListener(){
@Override
public void actionPerformed( ActionEvent e ){
type= TYPE.North;
canvas.repaint();
}
});
Button button3= new Button( "South" );
button3.addActionListener( new ActionListener(){
@Override
public void actionPerformed( ActionEvent e ){
type= TYPE.South;
canvas.repaint();
}
});
Panel panel= new Panel();
panel.setBackground( Color.BLACK );
panel.setLayout( new FlowLayout( FlowLayout.CENTER ) );
panel.add( button1 );
panel.add( button2 );
panel.add( button3 );
add( "South", panel );
canvas = new MyCanvas();
add( "Center", canvas );
setVisible( true );
pack();
}
class MyCanvas extends Canvas{
public MyCanvas(){
setBackground( Color.BLACK );
setPreferredSize( new Dimension( 800, 600 ) );
}
public void paint( Graphics graphics ){
super.paint( graphics );
Dimension dim= getSize();
graphics.setColor( Color.GRAY.darker() );
System.out.println( String.format( "%dx%d", dim.width, dim.height ) );
switch( type ){
case Mercator:
graphics.translate( dim.width/2+(ZOOM*180), dim.height/2 );
drawGrid( graphics );
drawStar( graphics, type );//星 描画
drawConstellation( graphics, type, listConstellationLine, Color.YELLOW.darker().darker().darker() );
drawConstellation( graphics, type, listConstellationBoundary, Color.BLUE.darker() );
break;
case North:
case South:
graphics.translate( dim.width/2, dim.height/2 );
drawGrid2( graphics );
drawStar( graphics, type );//星 描画
drawConstellation( graphics, type, listConstellationLine, Color.YELLOW.darker().darker().darker() );
drawConstellation( graphics, type, listConstellationBoundary, Color.BLUE.darker() );
break;
}
}
}
/**
* メルカトル図法用グリッド線
* @param graphics
*/
static void drawGrid( Graphics graphics ){
graphics.setColor( Color.RED.darker().darker() /*.darker()*/ );
//横ライン 赤緯(北天60°~南天-60°)
for( int y= 60; y >= -60; y-=10 ){
graphics.drawLine( -360 * ZOOM, -y * ZOOM, 0, -y * ZOOM );
graphics.drawString( String.format( "%4d", y ), 0, -y * ZOOM );//scale
}
//縦ライン 赤経(左端-360°~0°右端)
for( int x= -360; x <= 0; x+=10 ){
graphics.drawLine( x * ZOOM, -60 * ZOOM, x * ZOOM, 60 * ZOOM );
}
}
/**
* 正距方位図法(円形)グリッド線 北天/南天 共通
* @param graphics
*/
static void drawGrid2( Graphics graphics ){
graphics.setColor( Color.RED.darker().darker() /*.darker()*/ );
//同心円 中央ゼロ座標 赤緯(±90°~0°)
for( int r= 0; r <= 90; r+=10 ){
drawCircle( graphics, 0, 0, r * ZOOM );
}
//放射状ライン 赤経(0° ~ 360°)
int r= 90 * ZOOM;//最大半径←90度
for( int k= 0; k <= 360; k+= 10 ){//10°毎
int x= (int)( Math.cos( k * DEG2RAD ) * r );
int y= (int)( Math.sin( k * DEG2RAD ) * r );
graphics.drawLine( 0, 0, x, y );
}
}
static void drawCircle( Graphics graphics, int x, int y, int r ){
int top = y - r;
int left = x - r;
int width = r * 2;
int height = r * 2;
graphics.drawArc( top, left, width, height, 0, 360 );
}
/**
* (赤経,赤緯) → 正距方位図法(x,y)座標変換
* @param iRas 赤経x100
* @param iDsc 赤緯x100
* @return (x,y)座標
*/
static int calcNorthX( int iRas, int iDsc ){//(円形)北天 正距方位図法 ↓0h ←6h
return (int)( Math.cos( ( iRas-27000 )/100 * DEG2RAD ) * ( 9000-iDsc )/100 );
}
static int calcNorthY( int iRas, int iDsc ){// * 中心からの距離
return (int)( Math.sin( ( iRas-27000 )/100 * DEG2RAD ) * ( 9000-iDsc )/100 );
}
static int calcSouthX( int iRas, int iDsc ){//(円形)南天 正距方位図法 ↑0h ←6h
return (int)( Math.cos( ( iRas-9000 )/100 * DEG2RAD ) * (-9000-iDsc )/100);
}
static int calcSouthY( int iRas, int iDsc ){
return (int)(-Math.sin( ( iRas-9000 )/100 * DEG2RAD ) * (-9000-iDsc )/100);
}
/**
* 星座線 境界線
* @param graphics
* @param list Data List
* @param c Line Color
*/
static void drawConstellation( Graphics graphics, TYPE type, List<ConstellationLine> list, Color c ){
graphics.setColor( c );
int xS= 0;
int yS= 0;
int xE= 0;
int yE= 0;
int tp= 0;
for( ConstellationLine line: list ){
xS= line.getRasStart();
yS= line.getDscStart();
xE= line.getRasEnd();
yE= line.getDscEnd();
switch( type ){
case Mercator:
if( -6000 > yS || yS > 6000 || -6000 > yE || yE > 6000 ) continue;//緯度±60°超スキップ
if( 27000 < ( (xS < xE) ? xE - xS : xS - xE ) ) continue;//270°超7個スキップ
xS= -xS * ZOOM / 100;
yS= -yS * ZOOM / 100;
xE= -xE * ZOOM / 100;
yE= -yE * ZOOM / 100;
break;
case North://(円形)北天 正距方位図法 ↓0h ←6h
if( 0 > line.getDscStart() ) continue;
tp= calcNorthX( xS, yS ) * ZOOM;
yS= calcNorthY( xS, yS ) * ZOOM;
xS= tp;
tp= calcNorthX( xE, yE ) * ZOOM;
yE= calcNorthY( xE, yE ) * ZOOM;
xE= tp;
break;
case South://(円形)南天 正距方位図法 ↑0h ←6h
if( 0 < line.getDscStart() ) continue;
tp= calcSouthX( xS, yS ) * ZOOM;
yS= calcSouthY( xS, yS ) * ZOOM;
xS= tp;
tp= calcSouthX( xE, yE ) * ZOOM;
yE= calcSouthY( xE, yE ) * ZOOM;
xE= tp;
break;
}
graphics.drawLine( xS, yS, xE, yE );
}
}
/**
* 星 描画
* @param graphics
*/
static void drawStar( Graphics graphics, TYPE type ){
graphics.setColor( Color.WHITE );
int v;
for( Star s: listStar ){
int x= 0;
int y= 0;
switch( type ){
case Mercator://全天(赤緯-60~60の範囲のみ)メルカトル図法
x= -s.getRas() * ZOOM / 100;//赤経★逆さま?
y= -s.getDsc() * ZOOM / 100;//赤緯逆さま?
break;
case North://(円形)北天 正距方位図法 ↓0h ←6h
if( 0 > s.getDsc() ) continue;
x= calcNorthX( s.getRas(), s.getDsc() ) * ZOOM;
y= calcNorthY( s.getRas(), s.getDsc() ) * ZOOM;
break;
case South://(円形)南天 正距方位図法 ↑0h ←6h
if( 0 < s.getDsc() ) continue;
x= calcSouthX( s.getRas(), s.getDsc() ) * ZOOM;
y= calcSouthY( s.getRas(), s.getDsc() ) * ZOOM;
break;
}
if( null != s.proper ){//星名 TODO:座標補正
graphics.setColor( Color.BLUE.darker() );
graphics.drawString( s.proper, x, y );
}
if( 300 < s.vmag ){//暗い
v= 1;
// graphics.setColor( Color.WHITE.darker().darker() ); //Color.GRAY.brighter() );
graphics.setColor( Color.GRAY );
}else if( 200 < s.vmag ){
v= 1;
graphics.setColor( Color.WHITE );
}else if( 40 < s.vmag ){
v= 3;
graphics.setColor( Color.WHITE );
}else{
v= 5;
graphics.setColor( Color.WHITE );
}//明るい
graphics.fillOval( x, y, v, v );
}
}
}
javac -encoding UTF8 Star.java
前出のデータとコンパイル済のファイルを同じディレクトリに配置して
java Star
で起動。
●参考情報
阿南市科学センターで公開される星座早見PDF
http://ananscience.jp/science/tenmonkan/gallery.htm
http://ananscience.jp/science/tenmonkan/hayamiban/ASC_hayami_201803ver.pdf
星空PDF生成
https://hoshifuru.jp/pdf/