hook VTP code (edgar?)

Recommended Posts

I have tried to write some code to add hooks to my VTP lines yesterday. I know Edgar has written a small program, but since I use different BGLC macros and also want to fully automate the process from a GIS interface, I need the algorithm.I tried this for the start hook coordinates (point2):a = atan( (y2-y1)/(x2-x1) )x' = x1 - cos(90-a) * width/2 / 111000y' = y1 + sin(90-a) * width/2 / 111000(and swapping the +/- for point1)for the 2 end points (again) I'm swapping all +/- to set the hook into the other direction.x1/y1 x2/y2 are the two existing starting / end points.x'/y' is the new two starting points (new point 2 substitutes old point 1)111000 is my rough 1degree = 111km conversion, but that only controls the hook length, so that number is not 100% crucial.For some reason this algorithm doesn't work 100%. I have some ideas, but since someone (Edgar and possibly others) have the right algorithms already, can you please share them? I spent 2 hours yesterday on a stupid bug involving std:list::iterators and rather then waste my time with this I'd rather spend it on making some nice scenery...Thanks for any help.Cheers, Christian

Share on other sites

Hello Chisthian,I hope you can follow my Visual Basic implementation of inserting VTP ends. I use an array of VTP lines designated by VTPs(). The data structures are as follows:Private Type VTPPoint X As Long ' VTP X coordinate Y As Long ' VTP Y coordinate W As Single ' Width of point in single format C As Byte ' Counter for child points WB As Byte ' Width in Byte formatEnd TypePrivate Type VTP I As Integer ' texture index L As Integer ' layer X As Integer ' X index of cell Y As Integer ' Y index of cell NOP As Integer ' number of points P() As VTPPoint ' array of pointsEnd TypePrivate VTPs() As VTP ' array declarationPrivate NoOfVTPs As Integer ' number of VTP lines in arrayThen I use the following procedure:Private Sub MakeVTPEnds()Dim N As IntegerDim NP As IntegerDim W As SingleDim UX As Single, UY As Single, U As SingleDim XP As Long, YP As Long' the procedure takes every VTP line and changes' the X and Y coordinates of Points P1 and P2 and of' points PN and PN-1For N = 1 To NoOfVTPs ' get the versor of coordinates (UX UY) pointing ' from point P2 to point P3 XP = VTPs(N).P(2).X YP = VTPs(N).P(2).Y UX = CSng(VTPs(N).P(3).X - XP) UY = CSng(VTPs(N).P(3).Y - YP) U = UX * UX + UY * UY ' normalization U = Sqr(U) UX = UX / U UY = UY / U ' use width of point P2 as the starting width; divide ' this starting width by 2 and put the result in W W = VTPs(N).P(2).W * 0.10425 ' change the magnitude of (UX UY) to be W UX = CLng(W * UX) UY = CLng(W * UY) ' change coordinates of P1 and P2 so ' that, after changing, the segment P1 to P2 is ' perpendicular to (UX UY) and the direction of the ' vector product P1P2 x (UX UY) is correct! VTPs(N).P(2).X = XP + UY VTPs(N).P(2).Y = YP - UX VTPs(N).P(1).X = XP - UY VTPs(N).P(1).Y = YP + UX VTPs(N).P(1).W = VTPs(N).P(2).W ' also change points NP and NP-1. Start by getting the ' direction from point N-2 to point N-1, and so on ... NP = VTPs(N).NOP XP = VTPs(N).P(NP - 1).X YP = VTPs(N).P(NP - 1).Y UX = CSng(XP - VTPs(N).P(NP - 2).X) UY = CSng(YP - VTPs(N).P(NP - 2).Y) U = UX * UX + UY * UY U = Sqr(U) UX = UX / U UY = UY / U W = VTPs(N).P(NP - 1).W * 0.10425 UX = CLng(W * UX) UY = CLng(W * UY) VTPs(N).P(NP).X = XP + UY VTPs(N).P(NP).Y = YP - UX VTPs(N).P(NP - 1).X = XP - UY VTPs(N).P(NP - 1).Y = YP + UX VTPs(N).P(NP).W = VTPs(N).P(NP - 1).W Next NEnd SubHope this helps, Luis

Share on other sites

Thanks Luis,I understand the VB code (basicaly, you seem to use Pythagoras instead of trigenometry, which also works).The only bit I don't understand is this bit:> W = VTPs(N).P(2).W * 0.10425where did you get 0.10425 from?Cheers, Christian

Share on other sites

Hello,I interpret the unsigned byte VTPs(N).P(2).W as the width in meters. Widths for lines can vary between 0 and 255 meters. In the formula I convert the value in meters to the value (W) in VTP coordinates.255 VTP units correspond to the side of a LOD13 area. This LOD13 area is a rectangle with 1221 x 1628 meters at the Equator (http://www.ptsim.com/downloads/sdk_lod.htm). I assumed the side of LOD13 area to be allways 1221 meters independently of location and of NS or EW orientation.The width of a line of X meters width, in VTP units, is W given by: 1221 meters = 255 VTPs X meters = W VTPsW = X * ( 255 / 1221 ) = X * 0.2088 If I want to get half of the width in VTPs units (which is what I need) I multiply the width in meters, X, by 0.1044Note that (XP YP) is the initial P2 point and that I get the new P1 and P2 by adding and subtracting a vector to the initial (XP YP). The vector in question is perpendicular to P2P3 and should have a norm of 1/2 of the width od the line (width found in P2).Regards, Luis

Share on other sites

Thanks Luis,Makes complete and utter sense. I was thinking in degrees, since I was adding the hooks before conversion to VTP. (I thought this was smart since the new point could fall into a neighbouring VTP quad. Further thoughts reveal, I'm not really that smart, because I can't just add the new point to a different quad. This makes no sense.)Thanks for your algorithm and your thorough explanation, Luis. I understand it now, and you also helped me avoiding potential trouble!Cheers, Christian

Share on other sites

Hello Christian,I think I used a quite similar approach to your algorithm. Maybe not so elegant and short like yours :) (I want to see more in the debugger...)In short it goes like this:item0 - added hook-point (new coordinates)item1 - Point 1 (coordinates will change)item2 - Point 2 x_off = item2->X - item1->X; y_off = item2->Y - item1->Y; // snipp.... // calculation of x_hook/y_hook (either -1, 0 or 1 - its the basic direction of the hook - pointing in the next quadrant depending of the VTP line) // snipp.... // Dicks suggestion: width = 1/5 width dHookDistance = ((float)item1->width / 5.0); // calculate a 90 degree hooks winkel = atan((float)x_off / (float)y_off); dXhook = dHookDistance * cos(winkel); dYhook = dHookDistance * sin(winkel); // convert float Hook-Values into integers x_hook = x_hook * (fabs(dXhook) + 0.5); y_hook = y_hook * (fabs(dYhook) + 0.5); // calculate new coordinates item0->X = item0->X - (int)(((float)x_hook/2.0)+0.5); item0->Y = item0->Y - (int)(((float)y_hook/2.0)+0.5); item1->X = item1->X + (int)(((float)x_hook/2.0)+0.5); item1->Y = item1->Y + (int)(((float)y_hook/2.0)+0.5);The only problem I had and you might have with your approach:What if x_off or y_off equals 0 ??? (item1 == item2 or the VTP line is streigth north, east, etc.) You must catch this condition or the atan-function will fail.On the other hand, hooks and other lines can stretch into neighbouring cells - no problem. They just get clipped at the border. See samples in the default sceneries.BTW: Why do you operate with the 111km-related constant for the length of the hook?If you want, I can sent you the whole code, but its not straigth forward and full of german comments :)Cheers,Edgar

Share on other sites

Hi Edgar,looks pretty much like my algorithm.> // calculation of x_hook/y_hook (either -1, 0 or 1 - its the>basic direction of the hook - pointing in the next quadrant>depending of the VTP line)> // convert float Hook-Values into integers> x_hook = x_hook * (fabs(dXhook) + 0.5);> y_hook = y_hook * (fabs(dYhook) + 0.5);> // calculate new coordinates> item0->X = item0->X - (int)(((float)x_hook/2.0)+0.5);> item0->Y = item0->Y - (int)(((float)y_hook/2.0)+0.5);> item1->X = item1->X + (int)(((float)x_hook/2.0)+0.5);> item1->Y = item1->Y + (int)(((float)y_hook/2.0)+0.5);This may be the crucial stuff that's different. Are you checking directions here (something I don't do)? The 'interesting bit is missing' :). Something that I was thinking about is that atan will only produce values between -90 and 90, whereas I want a full rotation, which may corrupt my calculation for half of the cases. > // snipp....> // Dicks suggestion: width = 1/5 width> dHookDistance = ((float)item1->width / 5.0);>BTW: Why do you operate with the 111km-related constant for>the length of the hook?>On the other hand, hooks and other lines can stretch into>neighbouring cells - no problem. They just get clipped at the>border. See samples in the default sceneries.I use 111km (as an approximate), because I was adding the hooks already in lat/long space, not in VTP space. I realised that that's wrong as soon as I saw Luis' example. I thought I was being smart (preventing hooks to become 'invisible' on cell borders), when in fact I wasn't (as you said: it doesn't matter, and actually my thinking is just plain wrong and will cause complications).>The only problem I had and you might have with your approach:>What if x_off or y_off equals 0 ??? (item1 == item2 or the VTP>line is streigth north, east, etc.) >You must catch this condition or the atan-function will fail.I'm fully aware of that :) I think I may adapt Luis' code. It does the same thing and as it doesn't use trigonometrical functions, it should be faster and you don't have the infinity hassle (although there may be a dividing by zero one, I'll have to double check his code...)>If you want, I can sent you the whole code, but its not>straigth forward and full of german comments :)The German comments won't bother me, since I lived in Hamburg for my first 27 years, so I should understand them pretty well :) You don't have to post the lot though, the only thing I'm interested in is if you do the straight atan/cos/sin thing or if you check directions somewhere and change signs. If our code is identical, you must be getting errors too, since in some cases my lines don't join 100% (and rather go wild). Cheers, Christian

Share on other sites

Hi Christian,in the missing part is indeed the calculation of the hook direction. Its a rather boring series of if-then-else, which gives in the end in x_hook/y_hook a base-hook of 1-unit length pointing away left from the VTP line into the neighbouring quadrant. if (x_off == 0) { y_hook = 0; if (y_off > 0) x_hook = 1; // def. 1 else x_hook = -1; // def. -1 } else if (y_off == 0) { x_hook = 0; if (x_off > 0) y_hook = -1; // def. -1 else y_hook = 1; // def. 1 }***etc.Later the 1-unit hook is extended to the calculated lentgh>>> // convert float Hook-Values into integers>> x_hook = x_hook * (fabs(dXhook) + 0.5);>> y_hook = y_hook * (fabs(dYhook) + 0.5);>>> // calculate new coordinates>> item0->X = item0->X - (int)(((float)x_hook/2.0)+0.5);>> item0->Y = item0->Y - (int)(((float)y_hook/2.0)+0.5);>> item1->X = item1->X + (int)(((float)x_hook/2.0)+0.5);>> item1->Y = item1->Y + (int)(((float)y_hook/2.0)+0.5);>>This may be the crucial stuff that's different. Are you>checking directions here (something I don't do)? The>'interesting bit is missing' :). Something that I was thinking>about is that atan will only produce values between -90 and>90, whereas I want a full rotation, which may corrupt my>calculation for half of the cases. >I think, this part is equivalent to yourx' = x1 - cos(90-a) * width/2 / 111000y' = y1 + sin(90-a) * width/2 / 111000>>The German comments won't bother me, since I lived in Hamburg>for my first 27 years, so I should understand them pretty well>:) You don't have to post the lot though, the only thing I'm>interested in is if you do the straight atan/cos/sin thing or>if you check directions somewhere and change signs. If our>code is identical, you must be getting errors too, since in>some cases my lines don't join 100% (and rather go wild). >>Cheers, ChristianI had the going-wild appearance, when I didn't checked for divide-by-0 conditions correctly, which I hopefully solved.The problem of lines which don't join is a rounding problem, I think. It lies in the calculation of the virtual endpoint of the line, displayed in the middle between point 0 and point 1. Sample: Line A is bend down and adjoining line B is bend upwards - in most cases their displayed endpoints differ by one VTP unit.Cheers,Edgar

Share on other sites

Thanks again, Luis and Edgar.I finally implemented Luis' code and it works like a charm. The advantage of Luis' code is that you don't have to check for special conditions, and it's simpler than the trigonometry solution.Cheers, Christian

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

×   Pasted as rich text.   Paste as plain text instead

Only 75 emoji are allowed.

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×

• Tom Allensworth,
Founder of AVSIM Online

• Hot Spots

• Flight Simulation's Premier Resource!

AVSIM is a free service to the flight simulation community. AVSIM is staffed completely by volunteers and all funds donated to AVSIM go directly back to supporting the community. Your donation here helps to pay our bandwidth costs, emergency funding, and other general costs that crop up from time to time. Thank you for your support!