I need to limit an angle so it fits into a segment. I have drawn and links to a diagram below to better describe what I am after.
I am trying to calculate this for a computer program, where I have an angle (slope), and a point (the mouse pointer). The distance 开发者_如何学Godoes not matter to me, just the angles. If the point is within b1 (green area) then that's fine. But if the point is within b2 or b3 (red or orange) areas, then the angle should snap back to the limit of the green area (along the line s).
(source: adamharte.com)The main problem I am having in figuring this out, is snapping the angle to the correct side e.g. If the point is in the red area, then the angle should snap to the angle s on the red side and vice versa.
I am also having trouble because s could be any angle, so I am being tripped up because I can't just do something like this:
if a(radians) is greater than s(radians) then set a to the value of s
or I will get errors when the angle goes between zero and 2Pi.
So How would I work this out? Do I have to rotate everything back to a zero point or something then put it back when I have made my calculations?
Thanks for reading my questing.
First code in an ATAN2() function, to calculate the absolute angle for the point relative to horizontal plane. Then subtract the angle of the slope. if the result is <0 then snap to 0 and if the result is >180 snap to 180. The add the angle of the slope back to get your final angle
psi = (angle of slope)
a = atan2(x,y)
th = a-psi
if( th<0 ) { th=0; }
if( th>pi ) { th=pi; }
a = th+psi
try it.
I'd have to make some assumptions since you don't specify how you define slope. Either way you should be able to get a theta from the equation.
Here is an example that does what you require. It was a fun challenge to get it to work and it should get you started. Note: one thing that helped me was always keeping angles between -pi and pi. I also use vector projection to get the line that is drawn to look like it correctly lies on the slope.
package
{
import flash.display.Graphics;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
public class CircleSnap extends Sprite
{
private static const DEG_TO_RAD:Number = (Math.PI / 180);
private static const RAD_TO_DEG:Number = (180 / Math.PI);
private static const centerPoint:Point = new Point(200, 200);
private static const RADIUS:int = 100;
private var slope:Number;
private var circle:Sprite;
private var line:Sprite;
public function CircleSnap()
{
addEventListener(Event.ADDED_TO_STAGE, addedToStage);
}
private function addedToStage(event:Event):void
{
// choose a random slope (between -Math.PI to Math.PI)
slope = (Math.random()*Math.PI*2) - Math.PI;
// draw the circle
circle = makeColoredCircle();
addChild(circle);
circle.x = centerPoint.x;
circle.y = centerPoint.y;
circle.rotation = slope * RAD_TO_DEG;
line = new Sprite();
addChild(line);
stage.addEventListener(MouseEvent.MOUSE_MOVE, drawLine);
}
private function drawLine(event:MouseEvent):void
{
line.graphics.clear();
// calculate the angle of the line
var lineAngle:Number = Math.atan2(
stage.mouseY - centerPoint.y,
stage.mouseX - centerPoint.x);
var angleDiff:Number = (lineAngle - slope);
if(Math.abs(angleDiff) > Math.PI)
{
// wrap the angle between -pi and pi
var angleDir:int = angleDiff > 0 ? -1 : 1;
angleDiff = (Math.PI*2 - Math.abs(angleDiff)) * angleDir;
}
// assume we just draw to the mouse position
var destX:Number = stage.mouseX;
var destY:Number = stage.mouseY;
// if we are in the top area of the circle
if(angleDiff < 0)
{
// calculate the length
var xDiff:Number = stage.mouseX - centerPoint.x;
var yDiff:Number = stage.mouseY - centerPoint.y;
// we use Math.cos here to project the new line onto the slope
var len:Number = Math.cos(angleDiff) * Math.sqrt(xDiff*xDiff+yDiff*yDiff);
destX = Math.cos(slope) * len + centerPoint.x;
destY = Math.sin(slope) * len + centerPoint.y;
}
// draw the line
line.graphics.lineStyle(3, 0x00FFFF);
line.graphics.moveTo(centerPoint.x, centerPoint.y);
line.graphics.lineTo(destX, destY);
}
private function makeColoredCircle():Sprite
{
var circle:Sprite = new Sprite();
var bottomHalf:Sprite = new Sprite();
circle.addChild(bottomHalf);
bottomHalf.graphics.beginFill(0xFF0000);
halfCircle(bottomHalf.graphics, 0, 0, RADIUS);
var topLeftQuarter:Sprite = new Sprite();
circle.addChild(topLeftQuarter);
topLeftQuarter.graphics.beginFill(0x00FF00);
quarterCircle(topLeftQuarter.graphics, 0, 0, RADIUS);
topLeftQuarter.rotation = 180
var topRightQuarter:Sprite = new Sprite();
circle.addChild(topRightQuarter);
topRightQuarter.graphics.beginFill(0x0000FF);
quarterCircle(topRightQuarter.graphics, 0, 0, RADIUS);
topRightQuarter.rotation = -90;
return circle;
}
// found this here: http://actionsnippet.com/?p=1515
private function halfCircle(g:Graphics, x:Number,y:Number,r:Number):void
{
var c1:Number=r * (Math.SQRT2 - 1);
var c2:Number=r * Math.SQRT2 / 2;
g.moveTo(x+r,y);
g.curveTo(x+r,y+c1,x+c2,y+c2);
g.curveTo(x+c1,y+r,x,y+r);
g.curveTo(x-c1,y+r,x-c2,y+c2);
g.curveTo(x-r,y+c1,x-r,y);
}
// modified from halfCircle found here: http://actionsnippet.com/?p=1515
private function quarterCircle(g:Graphics, x:Number,y:Number,r:Number):void
{
var c1:Number=r * (Math.SQRT2 - 1);
var c2:Number=r * Math.SQRT2 / 2;
g.moveTo(x+r,y);
g.curveTo(x+r,y+c1,x+c2,y+c2);
g.curveTo(x+c1,y+r,x,y+r);
g.lineTo(x, y);
}
}
}
精彩评论