mako-ver/data/system/geometry.tjs
2023-11-23 19:40:13 -06:00

475 lines
25 KiB
Text
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//----------------------------------------
//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) //指定線の中点を返す indexindex+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;
}
}