点と多角形との囲み判定
-------------------------------------------------
点と多角形との囲み判定
画面をドラッグし続けると多角形を描画できます。
マウスを離すと、マウスカーソルとのあたり判定を確認できます。
囲みが2重に重なった場合、Flashの描画と同様に
判定を反転しています。
取りこぼしが多かったので+0.0000001したりしてみましたが
形状によっては計算が失敗します。
-------------------------------------------------
/**
* Copyright Hakuhin ( http://wonderfl.net/user/Hakuhin )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/kiGA
*/
// -------------------------------------------------
//
// 点と多角形との囲み判定
//
// 画面をドラッグし続けると多角形を描画できます。
// マウスを離すと、マウスカーソルとのあたり判定を確認できます。
//
// 囲みが2重に重なった場合、Flashの描画と同様に
// 判定を反転しています。
// 取りこぼしが多かったので+0.0000001したりしてみましたが
// 形状によっては計算が失敗します。
//
// -------------------------------------------------
package {
import flash.events.*;
import flash.display.*;
import flash.net.*;
import flash.text.*;
import flash.utils.*;
import flash.system.*;
import flash.geom.*;
import flash.ui.*;
import flash.media.*;
public class Main extends Sprite {
public function Main() {
// -------------------------------------------------
// コンストラクタ
// -------------------------------------------------
// キャプチャタイミング
Wonderfl.capture_delay( 1000 );
// フレームレート
stage.frameRate = 60;
// 100%表示
stage.scaleMode = StageScaleMode.NO_SCALE;
// 左上
stage.align = StageAlign.TOP_LEFT;
stage.align = "TL";
var vertex:Object = null; // 頂点データ
var mouse_left:Boolean = false; // 左マウスボタン状態
var tf:TextField = new TextField();
tf.width = 400;
tf.height = 400;
tf.selectable = false;
tf.multiline = true;
tf.wordWrap = true;
addChild(tf);
var shape:Shape = new Shape(); // 描画用シェイプ
addChild(shape);
var graphic:Graphics = shape.graphics;
// マウスが押されたときに実行されるイベント
stage.addEventListener(MouseEvent.MOUSE_DOWN,function(e:MouseEvent):void{
mouse_left = true;
vertex = VertexCreate(new Point(e.localX+0.0000001,e.localY+0.0000001));
});
// マウスが離されたときに実行されるイベント
stage.addEventListener(MouseEvent.MOUSE_UP,function(e:MouseEvent):void{
mouse_left = false;
VertexClose(vertex);
});
// マウスが移動したときに実行されるイベント
stage.addEventListener(MouseEvent.MOUSE_MOVE,function(e:MouseEvent):void{
if(!vertex) return;
var str:String = "";
str += "頂点数:" + vertex.count + "\n";
// マウス押しっぱなし
if(mouse_left){
var pos:Point = new Point(e.localX+0.0000001,e.localY+0.0000001);
var vec:Point = pos.subtract(VertexGetPushPoint(vertex));
if(vec.length > 2){
VertexPushPoint(vertex,pos);
}
// マウスを離した
}else{
if(VertexHittest(vertex,new Point(e.localX,e.localY))){
VertexSetFillColor(vertex,0xFF8080);
}else{
VertexSetFillColor(vertex,0x8080FF);
}
str += "走査 y 座標:" + e.localY + "\n";
str += "交差検出:" + VertexHittestDebug(vertex,new Point(e.localX,e.localY));
}
// 描画
graphic.clear();
if(mouse_left) VertexDrawLine(vertex,graphic);
else VertexDraw(vertex,graphic);
tf.text = str;
});
// バーテックス作成
function VertexCreate(p:Point):Object{
var pos:Vector.<Point> = new Vector.<Point>();
pos.push(p);
return {
count:1,
pos:pos,
fill_color:0x000000
};
}
// バーテックスに座標を積む
function VertexPushPoint(obj:Object,p:Point):void{
obj.pos.push(p);
obj.count ++;
}
// バーテックスに積んだ座標を取得
function VertexGetPushPoint(obj:Object):Point{
return obj.pos[obj.count-1];
}
// バーテックスを閉じる
function VertexClose(obj:Object):void{
if(obj.count > 0){
obj.pos.push(obj.pos[0]);
obj.count ++;
}
}
// バーテックスの面の色
function VertexSetFillColor(obj:Object,color:uint):void{
obj.fill_color = color;
}
// バーテックスのライン描画
function VertexDrawLine(obj:Object,g:Graphics):void{
if(obj.count < 1) return;
var i:int;
var num:int = obj.count;
g.lineStyle(2.0,0x606060,1.0);
for(i=1;i<num;i++){
g.moveTo(obj.pos[i-1].x,obj.pos[i-1].y);
g.lineTo(obj.pos[i].x,obj.pos[i].y);
}
}
// バーテックスの描画
function VertexDraw(obj:Object,g:Graphics):void{
if(obj.count < 1) return;
var i:int;
var num:int = obj.count;
g.lineStyle(2.0,0x606060,1.0);
g.beginFill(obj.fill_color,0.6);
g.moveTo(obj.pos[0].x,obj.pos[0].y);
for(i=1;i<num;i++){
g.lineTo(obj.pos[i].x,obj.pos[i].y);
}
g.endFill();
}
// バーテックスとあたり判定
function VertexHittest(obj:Object,p:Point):Boolean{
if(obj.count < 2) return false;
var i:int;
var j:int;
var pos:Vector.<Point> = obj.pos;
var num:int = pos.length;
// 双方向リスト構築
var count:Number = 0;
var list:Object;
var prev:Object;
var next:Object;
var pref:Object = new Object();
var post:Object = new Object();
pref.pref = post;
pref.post = post;
post.pref = pref;
post.post = pref;
var py:Number = p.y;
// 水平ラインと線との交差チェック
for(i=0;i<num;i++){
var b:int = i;
var e:int = i+1;
if(e >= num) e = 0;
// 交差判定
var nx:Number = -(pos[e].y - pos[b].y);
var ny:Number = (pos[e].x - pos[b].x);
if(nx == 0.0) continue;
// 交点
var px:Number = -(ny * py -(pos[b].x * nx + pos[b].y * ny)) / (nx);
// 線分交差か調べる
var ax:Number = px - pos[b].x;
var ay:Number = py - pos[b].y;
var bx:Number = px - pos[e].x;
var by:Number = py - pos[e].y;
if((ax * bx) + (ay * by) >= 0) continue;
// 格納位置を検索(ソート)
list = pref.post;
while(true){
if(list == post) break;
if(list.pos >= px){
break;
}
list = list.post;
}
var front:Boolean = (nx >= 0) ? true : false;
// 一致すれば登録しない
if(list.pos == px){
if(list.front == front){
continue;
}
}
// リストに挿入
prev = list.pref;
next = list;
list = new Object();
list.pref = prev;
list.post = next;
prev.post = list;
next.pref = list;
list.pos = px;
list.front = front;
count ++;
}
// 開始地点
pref.front = false;
// 反転検索
list = pref;
while(true){
next = list.post;
if(next == post) break;
// 次のデータと裏表が一致するなら逆転
if(next.front == list.front){
next.front = (next.front) ? false:true;
}
list = next;
}
list = pref.post;
while(true){
if(list == post) break;
if(list.pos < p.x){
list = list.post;
continue;
}
break;
}
if(list.pref.front){
return true;
}
return false;
};
// バーテックスとあたり判定のデバッグ
function VertexHittestDebug(obj:Object,p:Point):String{
if(obj.count < 2) return "";
var str:String = "";
var i:int;
var j:int;
var pos:Vector.<Point> = obj.pos;
var num:int = pos.length;
// 双方向リスト構築
var count:Number = 0;
var list:Object;
var prev:Object;
var next:Object;
var pref:Object = new Object();
var post:Object = new Object();
pref.pref = post;
pref.post = post;
post.pref = pref;
post.post = pref;
var py:Number = p.y;
// 水平ラインと線との交差チェック
for(i=0;i<num;i++){
var b:int = i;
var e:int = i+1;
if(e >= num) e = 0;
// 交差判定
var nx:Number = -(pos[e].y - pos[b].y);
var ny:Number = (pos[e].x - pos[b].x);
if(nx == 0.0) continue;
// 交点
var px:Number = -(ny * py -(pos[b].x * nx + pos[b].y * ny)) / (nx);
// 線分交差か調べる
var ax:Number = px - pos[b].x;
var ay:Number = py - pos[b].y;
var bx:Number = px - pos[e].x;
var by:Number = py - pos[e].y;
if((ax * bx) + (ay * by) >= 0) continue;
// 格納位置を検索(ソート)
list = pref.post;
while(true){
if(list == post) break;
if(list.pos >= px){
break;
}
list = list.post;
}
var front:Boolean = (nx >= 0) ? true : false;
// 一致すれば除去
if(list.pos == px){
if(list.front == front){
continue;
}
}
// リストに挿入
prev = list.pref;
next = list;
list = new Object();
list.pref = prev;
list.post = next;
prev.post = list;
next.pref = list;
list.pos = px;
list.front = front;
count ++;
}
if(!count) return "";
// 開始地点
pref.front = false;
// 反転検索
list = pref;
while(true){
next = list.post;
if(next == post) break;
// 次のデータと裏表が一致するなら逆転
if(next.front == list.front){
next.front = (next.front) ? false:true;
}
list = next;
}
var hit:Boolean = false;
list = pref.post;
while(true){
if(list == post) break;
if(list.pos > p.x){
if(!hit) str += "★";
hit = true;
}
str += "[x:" + (Math.floor(list.pos * 10) / 10) + ((list.front)?"開":"閉") + "]";
list = list.post;
}
if(!hit) str += "★";
return str;
};
// リサイズ時にフィット
stage.addEventListener(Event.RESIZE,ResizeFunc);
function ResizeFunc(e:Event):void{
var w:uint = stage.stageWidth;
var h:uint = stage.stageHeight;
tf.width = w;
tf.height = h;
}
ResizeFunc(null);
}
}
}
// -------------------------------------------------
// 外部画像をサムネイルとしてキャプチャ
// -------------------------------------------------
import flash.net.*;
import flash.events.*;
import flash.display.*;
import flash.geom.*;
function ThumbnailCapture(url:String,time:uint,stage:Stage):void{
// キャプチャタイミング
Wonderfl.capture_delay( time );
// スプライト作成
var sprite : Sprite = new Sprite();
// ステージ最前面に配置
stage.addChildAt(sprite,stage.numChildren);
// ローダー
var loader_obj : Loader = new Loader();
loader_obj.contentLoaderInfo.addEventListener (Event.INIT,function(e:Event):void{
// メモリからインスタンス化
var loader_memory : Loader = new Loader();
loader_memory.contentLoaderInfo.addEventListener (Event.INIT,function(e:Event):void{
// キャプチャ
var bmp : BitmapData = new BitmapData(loader_memory.width,loader_memory.height,true,0);
sprite.addChild(loader_memory);
bmp.draw(sprite);
sprite.removeChild(loader_memory);
loader_memory.unload();
loader_obj.unload();
loader_memory = null;
loader_obj = null;
// 画像を配置
var bmp_obj : Bitmap = new Bitmap(bmp);
bmp_obj .width = stage.stageWidth;
bmp_obj .height = stage.stageHeight;
stage.addChild(bmp_obj );
});
// 読み込み開始
loader_memory.loadBytes(loader_obj.contentLoaderInfo.bytes);
});
// 読み込み開始
loader_obj.load(new URLRequest(url));
}