475 lines
25 KiB
Text
475 lines
25 KiB
Text
//----------------------------------------
|
||
//geometory関係
|
||
//----------------------------------------
|
||
//各クラスはそれぞれ独立しています。
|
||
//例えばRectは各頂点をPosクラスで持つ…ということはしません。
|
||
//(ただしPolygonクラスだけ、Polylineクラスを継承します)
|
||
//頂点などをはじめ各データは基本、辞書配列%[x:x,y:y]で保持する方針です。
|
||
//なのでこれらのクラスは自作クラス内で使うだけに留めて、他へ渡すことはなるべくしないよう心がけます
|
||
//----------------------------------------
|
||
function distance(x1,y1,x2,y2)
|
||
{
|
||
return (int)Math.sqrt(Math.pow(Math.abs(x2-x1),2)+Math.pow(Math.abs(y2-y1),2));
|
||
}
|
||
//---------------------------------------
|
||
//Posクラス
|
||
//---------------------------------------
|
||
class Pos
|
||
{
|
||
var x,y;
|
||
function Pos(_x=void,_y=void){set(_x,_y);}
|
||
function clear(){x=void;y=void;}
|
||
function set(_x,_y){x=_x;y=_y;}
|
||
function assign(_src)
|
||
{
|
||
if((typeof _src)=="String"){
|
||
var p = str.split("(), []",,true);
|
||
if( p.count < 2 ) return false;
|
||
x=+p[0];y=+p[1];
|
||
}
|
||
else{
|
||
x=_src.x;y=_src.y;
|
||
}
|
||
}
|
||
function dist(pos){return distance(x,y,pos.x,pos.y);}
|
||
function dist_x(pos){return pos.x-x;}
|
||
function dist_y(pos){return pos.y-y;}
|
||
}
|
||
//---------------------------------------
|
||
//rectクラス
|
||
//---------------------------------------
|
||
class Rect
|
||
{
|
||
var rect; //[x1,y1,x2,y2]
|
||
|
||
property x1{setter(rhs){rect[0]=rhs;}getter(){return rect[0];}}
|
||
property y1{setter(rhs){rect[1]=rhs;}getter(){return rect[1];}}
|
||
property x2{setter(rhs){rect[2]=rhs;}getter(){return rect[2];}}
|
||
property y2{setter(rhs){rect[3]=rhs;}getter(){return rect[3];}}
|
||
property left{setter(rhs){rect[0]=rhs;}getter(){return rect[0];}}
|
||
property top{setter(rhs){rect[1]=rhs;}getter(){return rect[1];}}
|
||
property right{setter(rhs){rect[2]=rhs;}getter(){return rect[2];}}
|
||
property bottom{setter(rhs){rect[3]=rhs;}getter(){return rect[3];}}
|
||
property width{setter(rhs){rect[2]=rect[0]+rhs;}getter(){return (rect[2]-rect[0]);}}
|
||
property height{setter(rhs){rect[3]=rect[1]+rhs;}getter(){return (rect[3]-rect[1]);}}
|
||
property center_x{setter(rhs){var w=rect[2]-rect[0];rect[0]=rhs-w\2;rect[2]=rect[0]+w;}getter(){return (rect[0]+rect[2])\2;}}
|
||
property center_y{setter(rhs){var h=rect[3]-rect[1];rect[1]=rhs-h\2;rect[3]=rect[1]+h;}getter(){return (rect[1]+rect[3])\2;}}
|
||
property str{getter(){return @"[${rect[0]},${rect[1]},${rect[2]},${rect[3]}]";}}
|
||
property str_polygon{getter(){return @"(${rect[0]},${rect[1]})(${rect[2]},${rect[1]})(${rect[2]},${rect[3]})(${rect[0]},${rect[3]})";}}
|
||
|
||
function Rect(_p1=void,_p2=void,_p3=void,_p4=void,_p5=void){
|
||
//引数の渡し方で解釈が変わる
|
||
//(string,void,void,void,void)
|
||
//(left,top,void,width,height)
|
||
//(x1,y1,x2,y2,void)
|
||
rect=new Array();
|
||
set(_p1,_p2,_p3,_p4,_p5);
|
||
}
|
||
function clear(){_x1=void;_y1=void;_x2=void;_y2=void;}
|
||
function set(_p1=void,_p2=void,_p3=void,_p4=void,_p5=void){
|
||
//引数の渡し方で解釈が変わる
|
||
//(string,,,,)
|
||
//(left,top,,width,height)
|
||
//(x1,y1,x2,y2,)
|
||
if(_p1!==void&&_p2===void&&_p3===void&&_p4===void&&_p5===void){
|
||
//stringの場合の変換
|
||
var arr = _p1.split(',',,false);
|
||
_p1 = (arr[0]=='')? void:+arr[0];
|
||
_p2 = (arr[1]=='')? void:+arr[1];
|
||
_p3 = (arr[2]=='')? void:+arr[2];
|
||
_p4 = (arr[3]=='')? void:+arr[3];
|
||
_p5 = (arr[4]=='')? void:+arr[4];
|
||
}
|
||
if(_p3===void&&_p4!==void&&_p5!==void){
|
||
//(left,top,,width,height)の場合
|
||
//xyを0とする(,,,width,height)とした場合を考慮しp1,p2はvoidを0とする
|
||
rect[0] = (_p1===void)? 0:_p1;
|
||
rect[1] = (_p2===void)? 0:_p2;
|
||
width=_p4;
|
||
height=_p5;
|
||
}
|
||
else{
|
||
rect[0]=_p1;rect[1]=_p2;rect[2]=_p3;rect[3]=_p4;
|
||
}
|
||
}
|
||
function assign(src)
|
||
{
|
||
rect.assignStruct(src.rect);
|
||
}
|
||
function move(_x,_y) //移動させます(加算します)
|
||
{
|
||
rect[0]+=_x;rect[2]+=_x;
|
||
rect[1]+=_y;rect[3]+=_y;
|
||
}
|
||
|
||
function contains(x,y) //rectの中にその点は入っているか判定
|
||
{
|
||
if(x>=rect[0]&&x<=rect[2]&&y>=rect[1]&&y<=rect[3]) return true;
|
||
return false;
|
||
}
|
||
function cross_x(_x) //ラインがrectの中にあるか判定
|
||
{
|
||
if(_x>=rect[0]&&_x<=rect[2]) return true;
|
||
return false;
|
||
}
|
||
function cross_y(_y) //ラインがrectの中にあるか判定
|
||
{
|
||
if(_y>=rect[1]&&_y<=rect[3]) return true;
|
||
return false;
|
||
}
|
||
function intersect(_rect) //rectの重なり判定
|
||
{
|
||
if(contains(_rect.x1,_rect.y1)) return true;
|
||
if(contains(_rect.x2,_rect.y2)) return true;
|
||
if(contains(_rect.x1,_rect.y2)) return true;
|
||
if(contains(_rect.x2,_rect.y1)) return true;
|
||
return false;
|
||
}
|
||
|
||
function inside_x(_x){//範囲内に収まるようにxの値を調整する
|
||
if(_x<x1) _x=x1;
|
||
if(_x>x2) _x=x2;
|
||
return _x;
|
||
}
|
||
function inside_y(_y){//範囲内に収まるようにyの値を調整する
|
||
if(_y<y1) _y=y1;
|
||
if(_y>y2) _y=y2;
|
||
return _y;
|
||
}
|
||
function into(_rect){ //_rectの中に自分を収める
|
||
if(left<_rect.left){
|
||
var w = width;
|
||
left=_rect.left;
|
||
right=left+w;
|
||
if(right>_rect.right) right=_rect.right;
|
||
}
|
||
if(top<_rect.top){
|
||
var h = height;
|
||
top=_rect.top;
|
||
bottom=top+h;
|
||
if(bottom>_rect.bottom) bottom=_rect.bottom;
|
||
}
|
||
if(right>_rect.right){
|
||
var w = width;
|
||
right=_rect.right;
|
||
left=right-w;
|
||
if(left<_rect.left) left=_rect.left;
|
||
}
|
||
if(bottom>_rect.bottom){
|
||
var h = height;
|
||
bottom=_rect.bottom;
|
||
top=bottom-h;
|
||
if(top<_rect.top) top=_rect.top;
|
||
}
|
||
}
|
||
|
||
function getdist(src) //srcと自分の距離を測定(中心で計算します)戻り値はすべて正
|
||
{
|
||
return distance(center_x,center_y,src.center_x,src.center_y);
|
||
}
|
||
function getdist_x(src) //srcと自分の距離を測定(中心で計算します)
|
||
{
|
||
return src.center_x-center_x;
|
||
}
|
||
function getdist_y(src) //srcと自分の距離を測定(中心で計算します)
|
||
{
|
||
return src.center_y-center_y;
|
||
}
|
||
|
||
function pileupon(dest) //二つのrectを重ねる(中心で重ねます)destの方に自分を合わせます
|
||
{
|
||
var dcx=dest.center_x;
|
||
var dcy=dest.center_y;
|
||
var w=width,h=height;
|
||
left=dest.left+dcx-center_x;top=dest.top+dcy-center_y;
|
||
right=left+w;bottom=top+h;
|
||
}
|
||
|
||
function outway10key(_x,_y)//_x,_yの位置はrectから見てどの方向か(10キー方向を返します)
|
||
//_x,_yはvoidにも対応。xがvoidだと、yは2,5,8のみを、yがvoidだとxは4,5,6のみを返します
|
||
{
|
||
if(_x===void){
|
||
if(_y===void) return 5;
|
||
if(_y<=top) return 8;
|
||
if(_y>=bottom) return 2;
|
||
}
|
||
if(_x<=left){
|
||
if(_y===void) return 4;
|
||
if(_y<=top) return 7;
|
||
if(_y>=bottom) return 1;
|
||
return 4;
|
||
}
|
||
else if(_x>=right){
|
||
if(_y===void) return 6;
|
||
if(_y<=top) return 9;
|
||
if(_y>=bottom) return 3;
|
||
return 6;
|
||
}
|
||
else{
|
||
if(_y===void) return 5;
|
||
if(_y<=top) return 8;
|
||
if(_y>=bottom) return 2;
|
||
}
|
||
return 5;
|
||
}
|
||
}
|
||
//---------------------------------------
|
||
//Polylineクラス 折れ線クラス
|
||
//---------------------------------------
|
||
class Polyline
|
||
{
|
||
var _vertex; //各頂点を配列で所持。各頂点は辞書配列%[x:*,y:*]
|
||
var _length; //全体の長さ(いちいち計算させるのもあれなので、線を追加させるときに計算
|
||
|
||
property count{getter(){return _vertex.count;}}
|
||
property left{getter(){return getLeftVertex().x;}}
|
||
property top{getter(){return getTopVertex().y;}}
|
||
property right{getter(){return getRightVertex().x;}}
|
||
property bottom{getter(){return getBottomVertex().y;}}
|
||
property width{getter(){return right-left;}}
|
||
property height{getter(){return bottom-top;}}
|
||
property length{getter(){return _length;}}
|
||
|
||
function Polyline(str=void,originx=void,originy=void)
|
||
{
|
||
_vertex = new Array();
|
||
_length = void;
|
||
if(str!==void){
|
||
assign(str);
|
||
if(originx!==void && originy!==void)
|
||
{
|
||
move(originx,originy);
|
||
}
|
||
}
|
||
}
|
||
function set(_x,_y=void)//set(100,200)またはset("100,200")
|
||
{
|
||
if((_y===void)&&(typeof _x=="String")){
|
||
var p = _x.split("(), []",,true);
|
||
if(p.count<2) return void;
|
||
_x = +p[0];
|
||
_y = +p[1];
|
||
}
|
||
var ret = _vertex.add(%[x:_x,y:_y]);
|
||
_length = getLength();
|
||
return ret;
|
||
}
|
||
function assign(_src)//Polygonクラスか文字列から頂点を再セットする
|
||
{//文字列の場合は"(0,0)(1,2)(3,4)(5,6)"←こんな感じで指定
|
||
if((typeof _src)=="String"){
|
||
_vertex.clear();
|
||
var p = _src.split("(), []",,true);
|
||
for( var i=2 ; i<=p.count ; i+=2 ){
|
||
set(+p[i-2],+p[i-1]);
|
||
}
|
||
}
|
||
else _vertex.assignStruct(_src);
|
||
_length = getLength();
|
||
return _vertex.count;
|
||
}
|
||
function clear(){return _vertex.clear();}
|
||
function vertex(_index) //頂点を返す。当然、連続性は保証しない
|
||
{
|
||
return _vertex[_index];
|
||
}
|
||
function getTopVertex()
|
||
{
|
||
if(count==0) return void;
|
||
var v = _vertex[0];
|
||
for( var i=1 ; i<count ; i++ ){
|
||
if(v.y>_vertex[i].y) v=_vertex[i];
|
||
}
|
||
return v;
|
||
}
|
||
function getBottomVertex()
|
||
{
|
||
if(count==0) return void;
|
||
var v = _vertex[0];
|
||
for( var i=1 ; i<count ; i++ ){
|
||
if(v.y<_vertex[i].y) v=_vertex[i];
|
||
}
|
||
return v;
|
||
}
|
||
function getLeftVertex()
|
||
{
|
||
if(count==0) return void;
|
||
var v = _vertex[0];
|
||
for( var i=1 ; i<count ; i++ ){
|
||
if(v.x>_vertex[i].x) v=_vertex[i];
|
||
}
|
||
return v;
|
||
}
|
||
function getRightVertex()
|
||
{
|
||
if(count==0) return void;
|
||
var v = _vertex[0];
|
||
for( var i=1 ; i<count ; i++ ){
|
||
if(v.x<_vertex[i].x) v=_vertex[i];
|
||
}
|
||
return v;
|
||
}
|
||
function move(_x,_y)
|
||
{
|
||
for( var i=0 ; i<count ; i++ ){
|
||
_vertex[i].x += _x;
|
||
_vertex[i].y += _y;
|
||
}
|
||
}
|
||
//function getCenter() centerに統合
|
||
//function setCenter(_x,_y) centerに統合
|
||
function center(_x=void,_y=void) //_x,_yを指定すると指定位置に中心を合わせます 指定しないと中心位置を返します
|
||
{
|
||
if(count==0) return void;
|
||
var tx = 0;
|
||
var ty = 0;
|
||
for( var i=0 ; i<count ; i++ ){
|
||
tx+=_vertex[i].x;
|
||
ty+=_vertex[i].y;
|
||
}
|
||
var cx = tx \ count; //中心
|
||
var cy = ty \ count;
|
||
|
||
if(_x!==void&&_y!==void){
|
||
move(_x - cx,_y - cy);
|
||
cx=_x;cy=_y;
|
||
}
|
||
return %[x:cx,y:cy];
|
||
}
|
||
function middle(_index) //指定線の中点を返す index~index+1の線
|
||
{
|
||
if( (+_index+2) > _vertex.count ) return void;
|
||
var current = _vertex[_index];
|
||
var next = _vertex[_index+1];
|
||
return %[x:(current.x+next.x)\2,y:(current.y+next.y)\2];
|
||
}
|
||
function near(_index,_x,_y) //点から見た指定線の最も近似の点を返す
|
||
{
|
||
if( (+_index+2) > _vertex.count ) return void;
|
||
var a = _vertex[_index];
|
||
var b = _vertex[_index+1];
|
||
var p = %[x:_x,y:_y];
|
||
var vec_p = %[x:(p.x-a.x),y:(p.y-a.y)];
|
||
var vec_b = %[x:(b.x-a.x),y:(b.y-a.y)];
|
||
var r = (vec_b.x*vec_p.x + vec_b.y*vec_p.y) / (vec_b.x*vec_b.x + vec_b.y*vec_b.y);
|
||
if( r <= 0.0 ) return a;
|
||
if( r >= 1.0 ) return b;
|
||
return %[x:(a.x + r * vec_b.x), y:(a.y + r * vec_b.y)];
|
||
}
|
||
function nearest(_x,_y)
|
||
{
|
||
var p;
|
||
var dist;
|
||
var short=void;
|
||
var result;
|
||
for(var i=0 ; i<_vertex.count-1 ; i++){
|
||
p = near(i,_x,_y);
|
||
if(short===void){
|
||
short=distance(_x,_y,p.x,p.y);
|
||
result=p;
|
||
result['_line_index']=i; //本当はやりたくないけど、どこの線上にあるかindexをこっそり入れる
|
||
}
|
||
else{
|
||
dist = distance(_x,_y,p.x,p.y);
|
||
if(dist<short){
|
||
short=dist;
|
||
result=p;
|
||
result['_line_index']=i;
|
||
}
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
function getLength(i=void) //各ラインの長さの取得
|
||
{
|
||
var dist = 0;
|
||
if(i===void){
|
||
for(i=0 ; i<_vertex.count-1 ; i++){
|
||
dist += distance(_vertex[i].x,_vertex[i].y,_vertex[i+1].x,_vertex[i+1].y);
|
||
}
|
||
}
|
||
else{
|
||
dist = distance(_vertex[i].x,_vertex[i].y,_vertex[i+1].x,_vertex[i+1].y);
|
||
}
|
||
return dist;
|
||
}
|
||
function measure(_x,_y) //最始点から見て、その点までの道のりを計算
|
||
{
|
||
var p = nearest(_x,_y); //線上に乗ってない可能性を考慮、近似を出してこれで計算
|
||
var dist = 0;
|
||
for(var i=0 ; i<_vertex.count-1 ; i++){
|
||
if(i==p._line_index){ //この線上にある
|
||
dist+=distance(_vertex[i].x,_vertex[i].y,p.x,p.y);
|
||
break;
|
||
}
|
||
else dist += getLength(i);
|
||
}
|
||
return dist;
|
||
}
|
||
function findLine(dist) //長さから、どのライン上の点かを割り出します indexと残りの長さを返します
|
||
{
|
||
var d;
|
||
for(var i=0 ; i<_vertex.count-1 ; i++){
|
||
d = distance(_vertex[i].x,_vertex[i].y,_vertex[i+1].x,_vertex[i+1].y);
|
||
if((dist-d)<=0){
|
||
return %[index:i,lastlength:dist];
|
||
}
|
||
dist-=d;
|
||
}
|
||
return void;
|
||
}
|
||
function pointing(dist) //長さからライン上の点を割り出します
|
||
{
|
||
var r = findLine(dist);
|
||
if(r!==void){
|
||
var begin = _vertex[r.index];
|
||
var end = _vertex[r.index+1];
|
||
var sita = Math.atan2(end.y-begin.y,end.x-begin.x);
|
||
var _x = r.lastlength * Math.cos(sita) + _vertex[0].x;
|
||
var _y = r.lastlength * Math.sin(sita) + _vertex[0].y;
|
||
return %[x:_x,y:_y];
|
||
}
|
||
return void;
|
||
}
|
||
property str_polygon{
|
||
getter(){
|
||
var str = "";
|
||
for( var i=0 ; i<count ; i++ ){
|
||
str += "(%d,%d)".sprintf(_vertex[i].x,_vertex[i].y);
|
||
}
|
||
return str;
|
||
}
|
||
}
|
||
}
|
||
//---------------------------------------
|
||
//polygonクラス 多角形クラス Polylineクラスを継承します
|
||
//---------------------------------------
|
||
class Polygon extends Polyline
|
||
{
|
||
function Polygon(str=void,originx=void,originy=void){
|
||
super.Polyline(str,originx,originy);
|
||
}
|
||
|
||
function vertex(_n) //頂点を返す。ただし連続性を保証する
|
||
{
|
||
if(count==0) return void;
|
||
while(_n>=count){_n-=count;}
|
||
while(_n<0){_n+=count;}
|
||
return _vertex[_n];
|
||
}
|
||
function contains(_x,_y) //指定した点が多角形の中に入っているか
|
||
{
|
||
var cross=0;
|
||
for( var i=0 ; i<count ; i++ ){
|
||
if(
|
||
( (vertex(i).y <= _y) && (vertex(i+1).y > _y) )
|
||
|| ( (vertex(i).y > _y) && (vertex(i+1).y <= _y ) )
|
||
){
|
||
var vt = (_y-vertex(i).y) / (vertex(i+1).y - vertex(i).y);
|
||
if( _x < (vertex(i).x + (vt * (vertex(i+1).x - vertex(i).x))) ){
|
||
++cross;
|
||
}
|
||
}
|
||
}
|
||
return (cross%2==0)? false:true;
|
||
}
|
||
}
|