fc2ブログ

2点と直線の位置関係をベクトルの内積の符号で判断する

2008-02-15 | 20:21



点Aから直線に下ろした垂線と直線の交点をPとすると、任意の点Bに対してベクトルPAとベクトルPBの内積の符号は、
点Aと点Bが直線に対して同じ側にあればプラス
点Aと点Bが直線に対して別な側にあればマイナス
となる。

下はこのことを利用したデモ。直線をはさんで赤いボールと同じ側にあるボールは青、反対側にあるボールは緑にしてある。


package
{
    import flash.display.*;
    import flash.geom.*;
    import flash.events.*;
    import flash.utils.*;

    [SWF(width="500", height="500", framerate="30", backgroundColor="#ffffff")]
        public class Dot extends Sprite
        {
            public var theta:Number = 0;

            private var balls:Array = [];

            public function Dot()
            {
                for(var i:int = 0 ; i < 150 ; i++){
                    var b:Ball = new Ball(0xff00, 5);
                    b.x = Math.random()*500;
                    b.y = Math.random()*500;
                    b.vx = Math.random()*3+1;
                    b.vy = Math.random()*3+1;
                    addChild(b);
                    balls.push(b);
                }

                balls[0].color = 0xff0000;

                var t:Timer = new Timer(20);
                t.addEventListener(TimerEvent.TIMER, loop);
                t.start();
            }

            private function loop(event:*):void
            {
                theta += 0.01;

                for each (var b:Ball in balls){
                    b.move();
                }

                // 直線の始点
                var lFrom:Point = new Point(250*(1 - Math.cos(theta)), 250*(1 + Math.sin(theta)));
                // 直線の終点
                var lTo:Point = new Point(250*(1 + Math.cos(theta)), 250*(1 - Math.sin(theta)));

                var len:Number = 500;

                // 直線の始点と、赤い点を結ぶベクトル
                var vRed:Point = new Point(balls[0].x - lFrom.x, balls[0].y - lFrom.y);

                var vLine:Point = new Point(lTo.x - lFrom.x, lTo.y - lFrom.y);

                // 直線の始点と赤い点を結ぶベクトル と 直線の内積
                var dot:Number = vRed.x * vLine.x + vRed.y * vLine.y;

                // 赤い点から直線におろした垂線と直線との交点
                var v:Point =
                    new Point(lFrom.x + (dot/len)*Math.cos(theta), lFrom.y - (dot/len)*Math.sin(theta));

                for(var i:int = 1 ; i < balls.length ; i++){
                    var bdot:Number = (balls[i].x - v.x) * (balls[0].x - v.x) +
                        (balls[i].y - v.y) * (balls[0].y - v.y);

                    if(bdot > 0)
                        balls[i].color = 0xff;
                    else
                        balls[i].color = 0xff00;
                }

                graphics.clear();
                graphics.beginFill(0xff, 0.2);
                graphics.lineStyle(2, 0xff, 0.5);
                graphics.moveTo(lFrom.x, lFrom.y);
                graphics.lineTo(lTo.x, lTo.y);

                graphics.endFill();
            }
        }
}

import flash.display.*;
internal class Ball extends Sprite{
    public var vx:int = 2;
    public var vy:int = 2;
    public var radius:int;
    public var currentColor:int;
    public function Ball(c:Number=0, radius:Number = 0){
        graphics.lineStyle(1, 0, 0.5);
        graphics.beginFill(c);
        graphics.drawCircle(0,0,radius);
        graphics.endFill();
        this.radius = radius;
    }

    public function set color(c:int):void{
        if(currentColor != c){
            currentColor = c;
            graphics.clear();
            graphics.lineStyle(1, 0, 0.5);
            graphics.beginFill(currentColor);
            graphics.drawCircle(0,0,radius);
            graphics.endFill();
        }
    }

    public function move():void{
        x += vx;
        y += vy;
        if(x < 0 || x > 500)
            vx *= -1;
        if(y < 0 || y > 500)
            vy *= -1;
    }
}


スポンサーサイト



Comment

Post a comment

Secret