
Emulating snaps points by using angles?
I am developing a graphics application (JavaScript browser based) and one function of the app is to draw a polyline (mouse clicks will determine the relevant points along the polyline). The app currently extends a guide line from the last click point and shows a line that reorientates itself on screen as the user moves the mouse to a next click point (I think this is termed a rubber band type effect).
The geometric problem I am trying to solve is to make sure that the rubber band line between one point (the last point clicked) and the next point (still to clicked) is forced to subtend a certain angle. For example if a complete rotation is divided into 12 (30 degree segments from the horizontal and vertical axis with 0,0 at the top left) then the guide line (rubber band) is forced to be drawn so as to maintain a subtended angle of 30 degrees. The affect of this will be that the guide line will show a line between the last point clicked and the possible next point to be clicked which has been adjusted from the actual point where the mouse pointer is located to maintain and lineup with the imposed 30 degree segment lines.
I appreciate that there is probably a reasonably detailed amount of geometry (trigonometry) to perform this task but it boils down to finding the desired point (for the end of the rubber band line) given the last clicked point and the current mouse cursor position point where this desired point maintains the required angle as the user moves the mouse through the various segments that fan out around the last clicked point. This desired point will form the next point on the polyline if the user clicks the mouse. The rubber band will give the impression of snapping to snap points as the user moves through segments but snap points that are based on the subtended angle determined by which fixed segment lines are closest. See diagram
The red line represents the actual position of the mouse as a user moves from the last clicked point and the blue lines represents the lines of a 30 degree segment that will represent the guide line to be drawn (which ever is closest blue line to the current mouse position)  only a blue line is to be shown as the rubberband.
RubberBand.png
Is it best to work in angles or radians to solve this problem.
Sorry for such a long winded post I hope my meaning is reasonably clear.
Any ideas/pointers will be much appreciated. Thanks in advance

For those who read this thread and like me were disappointed by the complete lack of response I eventually worked out a solution myself. Here is my (coded with comments) solution to the problem. I am not a expert and it may not be the best solution but it works.
Geometry/Trigonometry purist may frown about the conversions from radians to degrees but this is essential for this solution which works on the use of sectors determined by splitting a full rotation into a equal set of sectors.
If anyone has any improvements to this function I would appreciate any feedback.
Call the function with the last point plotted (fromX, fromY) and the current mouse position (toX, toY) as input parameters. The function returns a structure (DD.coords) that contains the coordinates of the end point of the rubber band line. You can use these coords along with the last point plotted to construct the rubber band line. (DD.RotationDivider can be set to any whole number number that is a divisor of 360 and represent sectors the edge lines of which are possible rubber band lines).
function determineAdjustedCoords(fromX, fromY, toX, toY) {
// this function uses the last point plotted, the length of the lines to the new x and y coords (using toX and toY) to determine an adjusted rubber band endpoint
if (DD.ctrlPressed) {// if control is pressed then use toX and toY point for the coords of the end point of the rubber band line
DD.coords.x = toX;
DD.coords.y = toY;
return;
}
// find the angle subtended by the current rubber band line i.e. unadjusted (as dictated by the actual mouse coords) and the x axis
var xLen = toX  fromX;
var yLen = toY  fromY;
// if x or y difference is zero then no action needed so return
if (xLen == 0 && yLen == 0)
return;
var theta = Math.atan((yLen / xLen)) * (180 / Math.PI);
// find the hypontenuse of the triangle bounded by the x axis and the actual rubber band line  this will also be the hypontenuse of the adjusted rubber band line
var hyp;
// verify if any of the components are zero
if (Math.sin(theta * (Math.PI / 180)) == 0)
hyp = xLen;
else {
if (yLen == 0)
hyp == xLen;
else
hyp = yLen / ((Math.sin(theta * (Math.PI / 180))));
}
// find which sector the angle lies in and round it to the nearest sector
var sector = Math.round((theta / DD.RotationDivider));
// find the angle subtended by the adjusted rubber band line (as dictated by the coords we are trying to determine)
var thetaNew = sector * DD.RotationDivider;
// find new x and y coords of the adjusted rubber band line end points
var xNew = Math.cos(thetaNew * (Math.PI / 180)) * hyp;
var yNew = Math.sin(thetaNew * (Math.PI / 180)) * hyp;
// required coords equal the new coords added to the last point plotted (fromX,fromY)
DD.coords.x = fromX + Math.round(xNew);
DD.coords.y = fromY + Math.round(yNew);
return DD.coords;
}
As a challenge to all the experts on this forum please try to improve this solution.
Regards,
Last edited by MayaWalker; 12082012 at 10:23 AM.
Thread Information
Users Browsing this Thread
There are currently 1 users browsing this thread. (0 members and 1 guests)
Tags for this Thread
Posting Permissions
 You may not post new threads
 You may not post replies
 You may not post attachments
 You may not edit your posts

Forum Rules

