Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Scrunchify Angles?

Crunch crunch.

Using the calculations from Getting End Point in ArcSegment with Start X/Y and Start+Sweep Angles, how could I scrunchify or inflate(-ify) angles.

See images below. Green box is original. The yellow lines depict what the scrunchy or inflated start/end angle should become, but red line is if the original angle of start=169, end=293 is maintained on the scrunched or inflated elliptical arcs.

I need a way to figure out how to create the new angles of start/end based off the original values in the green box and the height/width/xRadius/yRadius values in the blue and orange boxes.

originalwidth-scrunchedheight-scrunched

Does anyone know the calculation to figure out what the new angle should be?

like image 959
Stan Avatar asked Apr 01 '11 15:04

Stan


2 Answers

If you think about what this code is actually doing, it's very similar to a vertical or horizontal scale (which, by the way, would that work?). I think that gives us the clue to solving this, without really diving into ellipse-specific geometry.

The general approach is to figure out the endpoints in x,y coordinates based on the angle and radius settings, apply the scale factors, and then convert back to angles. The first thing we also need to know is the center of the ellipse. What we do know are the start and end points, as well as the start and end angles. With that info, we can set up a really simple set of equations and solve: ((x,y) is the center of the ellipse)

(yEnd-y)/(xEnd-x) = tan(endAngle) = slope of line from center to endpoint (yStart-y)/(xStart-x) = tan(startAngle) = slope of line from center to startpoint

With that handy bit of information, we can now compute the new center (x',y'), x and y radii, and endpoint (xEnd', yEnd') by the scale factors. (I believe start point is 0,0 by definition, but change as needed).

x' = x * xScale, y' = y*yScale xEnd' = xEnd * xScale, yEnd' = yEnd * yScale

xRadius' = xRadius * xScale, yRadius' = yRadius * yScale

Now we need to figure out the new angles.

Math.Atan2(yStart', xStart') = new start angle Math.Atan2(yEnd', xEnd') = new end angle

Does that strategy make sense?

like image 130
J Trana Avatar answered Oct 02 '22 09:10

J Trana


I wrote a spreadsheet to calculate this. You can see it at https://skydrive.live.com/redir?resid=23B7BEDE6527529E!529&authkey=!AGboDW72AySsnK8 if you want. (That should produce an online working version, but you should also be able to download it.)

The basic technique works like this:

  1. Work out the X and Y coordinate for the unscrunched endpoints
  2. Scrunch those using simple scaling, to get the X and Y coordinates for the desired endpoints
  3. Work back from those to the angles

This involves quite a few calculations. You can follow it through in that spreadsheet, but here are all the steps:

First, I convert your angles to use coordinate geometry conventions - as far as I can tell, you're measuring clockwise from 3 o'clock, but in coordinate geometry it's more normal for a positive angle to be counterclockwise. So your start and end angles become 191 and 67 degrees respectively. (I did this because I find the maths less confusing this way round.))

Next, the spreadsheet works out the radius at the start and end points. Here are the formulae I'm using for the start and end points:

=D2*D3/SQRT(POWER(D3*COS(RADIANS(D4)),2) + POWER(D2*SIN(RADIANS(D4)),2))
=D2*D3/SQRT(POWER(D3*COS(RADIANS(D5)),2) + POWER(D2*SIN(RADIANS(D5)),2))

D2 and D3 are the X and Y radius. D4 is the start angle, and D5 is the end angle (as adjusted to be 'convential' angles). I got this formula from the Wikipedia item on Ellipses in the section titled "Polar form relative to center". That equation takes an angle and tells you what the ellipse's radius will be at that angle.

Next I use this to calculate the X and Y coordinates for the start and end points. Here are the formulae for the Start X and Y:

=$B$8*COS(RADIANS(D4)) + D2
=D3-$B8*SIN(RADIANS(D4))

As mentioned before, D2 and D3 are the X and Y radius, while D4 is the start angle. (The formulae for the end X and Y look the same only with D5. The reason for adding the X radius is that without this numbers range from -Xradius to +Xradius. Adding this means they range from 0 to width. The Y axis does something similar, but I've inverted it to get screen coordinates because computer graphics systems often tend to have this upside down (where increasing Y goes down the page). Yes, it's not entirely consistent that I inverted this but corrected the angle...sorry!

Next we calculate the scrunched X and Y. Here are the formulae for the start point:

=B9/B2*B13
=B10/B3*B14

B9 and B10 are the pre-stretch X and Y calculated in the previous step. B2 and B3 are the original width and height, while B13 and B14 are the scrunched width and height. (The end formulae look pretty similar of course.) So this is just a simple scaling operation.

Finally, we calculate the angle from these. Here's the start angle formula (and the end angle is almost identical)

=MOD(DEGREES(ATAN2(B16 - $D$13, $D$14-B17)), 360)

The ATAN2 function takes an X and a Y coordinate and tells you the angle of the line from the origin to that X,Y point. Excel works in radians so we have to convert this back to degrees (just like I was converting from degrees to radians in earlier formulae). And then I'm taking it MOD 360 to avoid getting any negative angles. ATAN2 doesn't ever produce values greater than PI (i.e., 180 degrees), and produces negative values for angles beyond that. Taking that modulo 360 wraps it back to a positive number.

And then the final step is to convert this back to your clockwise angle system:

= 360 - B19

Feeding in your stretched 1.88/3.4 dimensions, we get 165.51 and 287.70 degrees. That doesn't quite line up with your numbers, but I'm trying to work out where you got those from. Are they done by eye? And feeding in 2.5/2.55, I get 171.71 and 299.51. Again, very slightly different from yours, but not off by much.

like image 35
Ian Griffiths Avatar answered Oct 02 '22 10:10

Ian Griffiths