1 Attachment(s)

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 poly-line (mouse clicks will determine the relevant points along the poly-line). The app currently extends a guide line from the last click point and shows a line that re-orientates 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 line-up 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 poly-line 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 rubber-band.

Attachment 25989

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 (Bow)

Re: Emulating snaps points by using angles?

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 end-point

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.(Bow)

Regards,