面積の自動計算

面積のアプレットを作り始めました
手始めに、図形の面積を自動で求めるソフトを作りました。
色々な形の面積を求めてみるだけでも面白い。
そこから、何かの法則を発見できれば、算数になります。
現在アプレットは動きませんが、プログラムを残しておきます。

ピックの公式

ピックの公式(1899年)というのがあります。
任意の格子多角形の面積が以下の式で表されるというものです。
面積=内部の点の数+境界線上の点/2-1
おもしろいですね。こんなことで面積が求まるなんて不思議ですね。

自動計算プログラム ジャヴァアプレット

/*
*/
import java.awt.*;
import java.applet.*;
public class Menseki1 extends Applet {
int x0=50;
int y0=40;
int xw=40;
int yw=40;
int xsu=5;
int ysu=5;
int pointMax=6;
int pointsu=4;
int pointx[]=new int[6];
int pointy[]=new int[6];
int xp=1;//ポイントの位置
int yp=1;
int pno=0;
int pointSu0=0;
int naibuten=0;
double menseki;
int kx[]=new int[50];
int ky[]=new int[50];
public void init() {
super.init();
setBackground(Color.black);
setForeground(Color.white);
//{{INIT_CONtrOLS
setLayout(null);
resize(500,280);
//}}
pointx[0]=1;
pointx[1]=2;
pointx[2]=2;
pointx[3]=1;
pointx[4]=pointx[0];
pointy[0]=1;
pointy[1]=1;
pointy[2]=2;
pointy[3]=2;
pointy[4]=pointx[0];
}
public boolean handleEvent(Event event) {
if(event.id==Event.MOUSE_DOWN){
int x1=event.x;
int y1=event.y;
//位置を判断して近くのボタンを探す
x1=(x1-x0+xw/2)/xw;
y1=(y1-y0+yw/2)/yw;
//ボタン決定だったらボタンの色を変える
for(int ino=0;ino<4;ino++){
if(pointx[ino]==x1 && pointy[ino]==y1){
pointx[ino]=x1;
pointy[ino]=y1;
pno=ino;
pointx[4]=pointx[0];
pointy[4]=pointy[0];
repaint();
return true;
}
}
//ボタン位置移動だったらボタンを移動する
if(x1>=0 && x1<=4 && y1>=0 && y1<=4){
if(itihantei(x1,y1)==false){
return true;//位置が交差するか線分上の場合終了
}else{
pointx[pno]=x1;
pointy[pno]=y1;
pointx[4]=pointx[0];
pointy[4]=pointy[0];
menseki();
repaint();
return true;
}
}
}
return super.handleEvent(event);
}
public boolean itihantei(int x1,int y1){
int x[]=new int[5];
int y[]=new int[5];
for(int i=0;i<4;i++){
x[i]=pointx[i];
y[i]=pointy[i];
}
x[pno]=x1;
y[pno]=y1;
x[4]=x[0];
y[4]=y[0];
//N角形のときはここと線分上の判断をかえると良い//////////////////
int b;
b=kousahantei(x[0],y[0],x[1],y[1],x[2],y[2],x[3],y[3]);
if (b<=1)return false;
b=kousahantei(x[1],y[1],x[2],y[2],x[3],y[3],x[0],y[0]);
if (b<=1)return false;
b=kousahantei(x[2],y[2],x[3],y[3],x[0],y[0],x[1],y[1]);
if (b<=1)return false;
return true;
}
public int kousahantei(int x0,int y0,int x1,int y1,int x2,int y2,int x3,int y3 ){
//交差判断//
double xx0=(double)x0;
double yy0=(double)y0;
double xx1=(double)x1;
double yy1=(double)y1;
double xx2=(double)x2;
double yy2=(double)y2;
double xx3=(double)x3;
double yy3=(double)y3;
double b0=(xx0-xx1)*(yy2-yy0)-(yy0-yy1)*(xx2-xx0);//2
double b1=(xx0-xx1)*(yy3-yy0)-(yy0-yy1)*(xx3-xx0);//3
double b2=b0*b1;
double b3=(xx2-xx3)*(yy0-yy3)-(yy2-yy3)*(xx0-xx3);//0
double b4=(xx2-xx3)*(yy1-yy3)-(yy2-yy3)*(xx1-xx3);//1
double b5=b3*b4;
if (b2<0.0 && b5<0.0){
return -1;//交差している
}
//線分上の判断
if (b0==0){//x2.y2が線分上にある
if( (xx1-xx0)*(xx2-xx0)<=0 && (yy1-yy0)*(yy2-yy0)<=0 ){//x0外部
return 1;//点打ち不可
}else if( (xx0-xx1)*(xx2-xx1)<=0 && (yy0-yy1)*(yy2-yy1)<=0 ){//x1外部
if((xx0-xx1)*(xx2-xx1)==0 || (yy0-yy1)*(yy2-yy1)==0){
return 5;//点打ち可 数え上げ不可
}else{
return 2;//点打ち可
}
}else{
return 0;//線上 点打ち不可 数え上げ不可
}
}
if (b1==0){//x3 y3が線分上にある
if( (xx1-xx0)*(xx3-xx0)<=0 && (yy1-yy0)*(yy3-yy0)<=0 ){//x0外部
if( (xx1-xx0)*(xx3-xx0)==0 || (yy1-yy0)*(yy3-yy0)==0 ){
return 5;
}else{
return 2;
}
}else if( (xx0-xx1)*(xx3-xx1)<=0 && (yy0-yy1)*(yy3-yy1)<=0 ){//x1外部点打ち不可
return 1;
}else{
return 0;
}
}
if (b3==0){//x0が23線上にある //以下は点の移動には関係ない 内部点数え上げに関係
if( (xx2-xx0)*(xx3-xx0)<=0 && (yy2-yy0)*(yy3-yy0)<=0 )return 10;
}
if (b4==0){
// if( (xx1-xx2)*(xx3-xx2)>=0 && (yy1-yy2)*(yy3-yy2)>=0 )return 1;
}
return 3;
}
public boolean menseki(){
//線上の点の数え上げ
pointSu0=0;
for( int i=0;i<4;i++){
int xl=pointx[i]-pointx[i+1];
if (xl<0)xl=-xl;
int yl=pointy[i]-pointy[i+1];
if (yl<0)yl=-yl;
if(xl*yl==0 ){//xlとylとの一方が0だったらもう一方の数が通過点数
pointSu0=pointSu0+xl+yl;
} else {//xl とyl との公約数で大きい方の数字を割った数が通過点数
if(xl<yl){
int i1=xl;
xl=yl;
yl=i1;
}
int a1=xl;
int a2=yl;
int a3=1;
while(a3 != 0){
a3=a1 % a2;
a1=a2;
a2=a3;
}//a2が公約数として出現する
pointSu0=pointSu0+a1;
}
}
//内部点の数え上げ
naibuten=0;
for( int px=0;px<5;px++){
for( int py=0;py<5;py++){
//内部ならnaibten=naibten++
int n=naibuhantei(px,py);
if(n==1){
kx[naibuten]=px;
ky[naibuten]=py;
naibuten=naibuten+1;
}
}
}
//面積の計算
menseki=(double)(pointSu0-2)/2+(double)naibuten;
return true;
}
public int naibuhantei(int ix,int iy){
int kosakaisu=0;
pointx[4]=pointx[0];
pointy[4]=pointy[0];
for (int i=0;i<4;i++){
int b=kousahantei(ix,iy,27,19,pointx[i],pointy[i],pointx[i+1],pointy[i+1] );
if( b==0 || b==10 || b==5)return 0;
if( b==-1)kosakaisu++;
}
return (kosakaisu % 2);
}
public void paint(Graphics g){
g.drawString("移動したい頂点をクリックし、移動したい場所をクリックすると面積が表示される。",18,20);
//図形を書く
int x[]=new int[6];
int y[]=new int[6];
for( int i=0;i<=4;i++){
x[i]=pointx[i]*xw+x0;
y[i]=pointy[i]*yw+y0;
}
g.setColor(Color.yellow);
pointx[4]=pointx[0];
pointy[4]=pointy[0];
g.fillPolygon(x,y,4);
g.setColor(Color.white);
g.drawPolygon(x,y,5);
//目印の点を書く
g.setColor(Color.blue);
for( int ix=0;ix<xsu;ix++){
for( int iy=0;iy<ysu;iy++){
g.fillOval(ix*xw-2+x0,iy*yw-2+y0,4,4);
}
}
//内部点を書く
g.setColor(Color.white);
for(int i=0;i<naibuten;i++){
g.fillOval(kx[i]*xw-2+x0,ky[i]*yw-2+y0,4,4);
}
//頂点を書く
for(int i=0;i<4;i++){
g.setColor(Color.pink);
if(i==pno)g.setColor(Color.red);
g.fillOval(pointx[i]*xw-2+x0,pointy[i]*yw-2+y0,4,4);
//g.drawString(""+i,pointx[i]*xw-2+x0+10,pointy[i]*yw-2+y0);
}
g.setColor(Color.white);
g.drawString("面積: "+menseki+"Cm2",250,100);
//g.drawString(""+pointSu0+" "+naibuten,250,140);
}
//{{DECLARE_CONtrOLS
Label label1;
//}}
}

「まわりの長さと面積」