acm-6.0_20200416/0000755000000000000000000000000013175511504011575 5ustar rootrootacm-6.0_20200416/doc/0000755000000000000000000000000013260345311012336 5ustar rootrootacm-6.0_20200416/doc/manual/0000755000000000000000000000000013646045022013617 5ustar rootrootacm-6.0_20200416/doc/manual/acmdoc_html-an_approach.obj0000644000000000000000000000773710644355520021056 0ustar rootroot%TGIF 4.1.43-QPL state(0,37,100.000,59,10,1,4,0,9,1,1,0,0,1,0,1,0,'Helvetica',0,63360,0,5,0,10,0,1,1,1,0,16,0,0,1,1,1,1,1088,1408,1,0,2880,0). % % @(#)$Header$ % %W% % unit("1 pixel/pixel"). color_info(11,65535,0,[ "magenta", 65535, 0, 65535, 65535, 0, 65535, 1, "red", 65535, 0, 0, 65535, 0, 0, 1, "green", 0, 65535, 0, 0, 65535, 0, 1, "blue", 0, 0, 65535, 0, 0, 65535, 1, "yellow", 65535, 65535, 0, 65535, 65535, 0, 1, "pink", 65535, 49344, 52171, 65535, 49344, 52171, 1, "cyan", 0, 65535, 65535, 0, 65535, 65535, 1, "CadetBlue", 24415, 40606, 41120, 24415, 40606, 41120, 1, "white", 65535, 65535, 65535, 65535, 65535, 65535, 1, "black", 0, 0, 0, 0, 0, 0, 1, "DarkSlateGray", 12079, 20303, 20303, 12079, 20303, 20303, 1 ]). script_frac("0.6"). fg_bg_colors('black','white'). dont_reencode("FFDingbests:ZapfDingbats"). page(1,"",1,''). poly('black','',2,[ 192,32,192,234],2,2,1,0,0,0,0,0,0,0,0,'2',0,0, "0","",[ 0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[ ]). poly('black','',2,[ 100,204,132,172],1,3,1,3,0,0,0,0,0,0,0,'3',0,0, "0","",[ 0,12,5,0,'12','5','0'],[0,12,5,0,'12','5','0'],[ ]). poly('black','',2,[ 284,204,252,172],1,3,1,7,0,0,0,0,0,0,0,'3',0,0, "0","",[ 0,12,5,0,'12','5','0'],[0,12,5,0,'12','5','0'],[ ]). polygon('black','',14,[ 104,200,96,203,87,196,84,200,93,208,88,216,80,216,91,225, 90,218,98,212,107,220,111,216,102,208,104,200],2,1,1,0,16,0,0,0,0,0,'1',0, "0000",[ ]). polygon('black','',14,[ 279,200,287,203,296,196,299,200,290,208,295,216,303,216,292,225, 293,218,285,212,276,220,272,216,281,208,279,200],2,1,1,0,28,0,0,0,0,0,'1',0, "0000",[ ]). text('black',88,172,1,0,1,11,17,31,14,3,2,0,0,0,2,11,17,0,0,"",0,0,0,0,186,'',[ minilines(11,17,0,0,0,0,0,[ mini_line(11,14,3,0,0,0,[ str_block(0,11,14,3,0,-1,0,0,0,[ str_seg('black','Helvetica',0,80640,11,14,3,0,-1,0,0,0,0,0, "A")]) ]) ])]). text('black',288,174,1,0,1,9,17,33,14,3,2,0,0,0,2,9,17,0,0,"",0,0,0,0,188,'',[ minilines(9,17,0,0,0,0,0,[ mini_line(9,14,3,0,0,0,[ str_block(0,9,14,3,0,-1,0,0,0,[ str_seg('black','Helvetica',0,80640,9,14,3,0,-1,0,0,0,0,0, "B")]) ]) ])]). text('black',200,46,1,0,1,29,17,42,14,3,2,0,0,0,2,29,17,0,0,"",0,0,0,0,60,'',[ minilines(29,17,0,0,0,0,0,[ mini_line(29,14,3,0,0,0,[ str_block(0,29,14,3,0,-1,0,0,0,[ str_seg('black','Helvetica',0,80640,29,14,3,0,-1,0,0,0,0,0, "OBS")]) ]) ])]). arc('black','',0,1,1,0,128,48,192,112,192,176,148,156,1,128,128,-5760,-2880,44,0,1,8,3,0,0,0,'1','8','3',0,[ ]). arc('black','',0,1,1,0,128,48,192,112,192,176,236,156,0,128,128,-5760,2880,55,0,1,8,3,0,0,0,'1','8','3',0,[ ]). text('black',156,178,1,0,1,16,17,56,14,3,0,0,0,0,2,16,17,0,0,"",0,0,0,0,192,'',[ minilines(16,17,0,0,0,0,0,[ mini_line(16,14,3,0,0,0,[ str_block(0,16,14,3,0,-1,0,0,0,[ str_seg('black','Helvetica',0,80640,16,14,3,0,-1,0,0,0,0,0, "45")]) ]) ])]). text('black',208,178,1,0,1,16,17,58,14,3,0,0,0,0,2,16,17,0,0,"",0,0,0,0,192,'',[ minilines(16,17,0,0,0,0,0,[ mini_line(16,14,3,0,0,0,[ str_block(0,16,14,3,0,-1,0,0,0,[ str_seg('black','Helvetica',0,80640,16,14,3,0,-1,0,0,0,0,0, "45")]) ]) ])]). text('black',172,173,1,0,1,6,13,60,11,2,0,0,0,0,2,6,13,0,0,"",0,0,0,0,184,'',[ minilines(6,13,0,0,0,0,0,[ mini_line(6,11,2,0,0,0,[ str_block(0,6,11,2,0,-1,0,0,0,[ str_seg('black','Helvetica',0,63360,6,11,2,0,-1,0,0,0,0,0, "o")]) ]) ])]). text('black',224,173,1,0,1,6,13,64,11,2,0,0,0,0,2,6,13,0,0,"",0,0,0,0,184,'',[ minilines(6,13,0,0,0,0,0,[ mini_line(6,11,2,0,0,0,[ str_block(0,6,11,2,0,-1,0,0,0,[ str_seg('black','Helvetica',0,63360,6,11,2,0,-1,0,0,0,0,0, "o")]) ]) ])]). group([ poly('black','',2,[ 158,147,112,192],0,1,1,1,0,0,5,0,0,0,0,'1',0,0, "0","",[ 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ ]), poly('black','',2,[ 226,146,272,192],0,1,1,2,0,0,5,0,0,0,0,'1',0,0, "0","",[ 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ ]), arc('black','',0,1,1,5,192,-52,308,64,226,146,196,97,1,232,232,-8640,-1792,74,0,1,8,3,0,0,0,'1','8','3',0,[ ]), arc('black','',0,1,1,5,-40,-52,76,64,158,146,188,97,0,232,232,-2880,1792,89,0,1,8,3,0,0,0,'1','8','3',0,[ ]) ], 96,0,0,[ ]). acm-6.0_20200416/doc/manual/acmdoc_html_hsi_rnav-usage.png0000644000000000000000000000230710666003515021574 0ustar rootrootPNG  IHDRtPLTEٟ|IDATxٽoECW"Ii{"Q KmA)Rb \ _$ e X-C, c.>wy;8kY.XTT@O,ZB'DK(TNZ>tJ:%)CC'ŁX%lЁTӂ ̥:-k3s !RRZ K A@^ `ڸ{7݇pU|kFOP{^ʙ*H+ȫ2M^ĈGugAC"*u\M.9Y '\ZSŸ>^$*cFSY&6vhf_.;4w$蛶[,w9X.hXhq~V{"[z.OW}KK4Dwr# xw]U { #UzKA:Uq6Q}:*W/" uAnP@LKhԧ5Ai{& F {"K"D_ ׹Y\?fGFԳYqdz1? sP$N9sŶ8%WJ KE}a+!y%ZW"CLaՈP*i b1E|ľXDGՏBgbX,8E~㝏h^Q sYN?IENDB`acm-6.0_20200416/doc/manual/acmdoc_html_radar-coverage.png0000644000000000000000000000651410371201070021534 0ustar rootrootPNG  IHDR  #]^gAMAPLTE@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 000PPP```pppxxxU pHYs+ IDATx 0*s⣭wBhK)!eJ]xJ@()J@()J@()J@()\P-%B):ĕO Щ*t)Еf#p>K)/rw+uf{DF:d/k]pʙ$zF>gf}@ jany{ZhDѹSEϲ%(@;v^YO yC7DͤnOۆI{:r#cX+m _zX>c$1W'9Mp!n8i P Pǀ|Ⓚ4yP= e@b3 s@X`1x|&S@'[@ PH>B:%d((3@V[Z Оpc@51#@k[54.m qj쇲cPY _|b d6겅DX%ט*@Vq.g;N’-2⬾ӄВ. kB=q,QH.ad]떼rȂ׾Ю $U5Qt.ԶP>YTNÓ0qZE[Gcq$(:?2Hu^ONiwNNNG `8ntb/~uY]#;Y.[U~绪OoB,輘ftcAek>g3 dƿƓiBDY dA!eg- NKF⚐G}(`Ef:YSC2d9YQPd (eEPR%Y dYOQTd(e-WEY.YPNdB9+xD8NU ՀB P'"Ąˬ (y aBBk&[ +!_@mĢ1(rv>Vqyt x t*.QG*y |恜BRR?h54BjؕjbX9_ %Sqپ Ry/v-,Rխ4=La%離.šA* ?MGI  S6 _oOt Pydh6 خT{ w~bHl0 ,`¨]ڷnf^7 fD<%.3P> i9:6KX{ #ֹ&!(=HͷWc:GP^R,ww!BO:t[\j A1 (85y `'*"(rP()ASW)`YEUXRd (e 3UY&PQRJY* n+6B33KF1Q,7&mpbVK"р"R׭byLy%f0&9=٤(Ħ2aq ^e&8B(.ZeqK%mBY vZu޲G@X!. 'J ZBdIqJ'mIR'֖o)@&JVܖ 8[ep]bK ~˺D캍bA6eJ<09"8{&͝S}ө'4S6P40{ fBtd. h#No!3O8 Q8`NVC}_i.AkIYw@%3quc@|YKD5(0z)Tq@K'qg~.D%\Z`ŝk`K u@ hG L׭rOw̼?(> ( YI>y@x2M^( @2?(RL#<ҀCP\ȴ̢ PT'brH"C@1,G=+LEtݡP@AD"k@,)Bs(%+ɲ""@L(gEP(rrnE9}"7@Q P#N( y aBB+| $C}Z΀Pd7va:UAZйP~"Еȗ1w@\.4r(i@#+)J@ŋW6|IENDB`acm-6.0_20200416/doc/manual/acmdoc-poh.html0000644000000000000000000015206013646045022016523 0ustar rootroot ACM - Pilot's Operating Handbook

ACM - Pilot's Operating Handbook

by Riley Rainey
updated by Umberto Salsi

Contents

Back to general contents
Tutorial
Take-off
Landing
The Magnetic Compass
The Classic Instruments Panel
The Head-Up Display
The HSI
The ADF
The Auto Pilot System
The Auto-pilot
The Auto-throttle
The Auto-coordinator
The Auto-navigator
The Auto-landing
The Auto-turn
Lights Panel
The Radar System
Electronic Countermeasures
Weapon Systems
Drones
Stealth Mode

Tutorial

Take-off

Start the launcher program acm.tcl. The first thing to do is checking the whole program be properly configured. Open the Configure panel and make sure the executable program and the objects directory be set. Set a frame rate of 20 Hz, mouse mode normal, window size of 700 x 500. It may need to exit the launcher (press the the Quit button) and start it again in order to see the list of the available planes in the You panel.

In the Plane panel choose the Cessna 172 retractable gear C-172 with about 200 lb of fuel and 200 lb of payload (your body). Select the classic instruments panel view. Set the eye to screen distance to something like 50 cm and 10 degrees of downward view angle.

In the Departure panel choose the Dallas scene and the ADS airport, runway 15.

In the DIS panel disable the DIS protocol.

Press the Run button to start the actual ACM program. Your mouse is the control stick. The neutral position is the center of the window. Moving the mouse away from you pitches the plane down, moving it back pitches the plane up. Left and right inputs roll the aircraft in the corresponding direction and turn the nose wheel.

Press F9 to cage the attitude indicator: this will speed-up the alignment process that would take several minutes otherwise.

Hint. Controlling the aircraft is much simpler by enabling the rate control mode (press SHIFT-E).

Press the full throttle key (the "4" key on the main keyboard, NOT the numeric keypad!). Keep the mouse in the neutral position until you are moving at about 55 KT, then gently pull the mouse about two-thirds of the way down the view window. You should pitch up and lift off the ground fairly easily. Maintain a pitch angle between 7 and 10 degrees by gently moving the mouse and leave your airspeed build.

When the vertical speed indicator indicates a stable positive climb rate (500 fpm or so), you may retract the landing gear by pressing the "g" key. Level the plane at a safe altitude of about 2000 ft and throttle down to about 80% of the engine RPM (use the "2" and "3" keys of the main keyboard, NOT those of the numeric keypad).

Hint. Move the mouse very gently around the center of the window, looking at the attitude indicator for changes. For normal level flight you should keep about +3 degrees of pitch and zero bank angle.

Congratulation, you successfully made your first take-off!

Landing

We are still flying the C-172 and now it's time to land. Set engine RPM to about 50% (keys "2" and "3") and deploy the landing gear by pressing the "g" key. Reduce the pitch and try to keep the airspeed at 75 kt and the descending rate at -400 fpm. Keep wings level. In this our first attempt we will land randomly somewhere on the green field and will not attempt to actually land on a runway.

Rule. The normal glide slope for landing should be around -3 degrees. In order to keep a glide slope near to this value, the descent speed should be about 5 times the airspeed. For example, if the airspeed is 100 kt, then the descent rate should be around 5 x 100 = 500 fpm.

Look at the radar altimeter. When it indicates 50 ft from ground it's time to start the flare maneuver by reducing the sink rate to about -200 fpm or less, trying to touch the ground as gently as you can. But do not hesitate to much because the speed decreases very rapidly and you risk to stall! As the radar altimeter indicates zero, put the engine to idle power (key "1") and gently lower the nose gear. Leave the plane to slow down, or press "b" to engage the brakes.

Congratulation, you successfully made your first landing!

The Magnetic Compass

The upper-right corner of the window displays the magnetic compass, simulated by the program mostly for didactical purposes. The compass card contains the magnets and it is mounted on a small pivot point located above its center of mass. This allows the compass card to rotate freely and to float as a pendulum by a maximum of +/−18° in pitch and roll following the direction of the apparent vertical line. Above this angular limit the compass hits violently the side of the casing and its indication becomes unreliable for some time.


The magnetic compass.


The magnetic compass does not simply indicate the magnetic heading (MH) of the aircraft, but instead it moves and rotates under the dynamic and magnetic effects. By definition, the magnetic north is the direction of the magnetic field vector projected over the local horizontal plane. That's why the magnetic compass card has to be as close as possible to the horizontal plane in order to align its magnets with the horizontal component of the magnetic field.

When the aircraft is at rest on the runway, or it is flying in straight, level flight at constant speed, the compass card is perfectly parallel to the horizon and it rotates until it is perfectly aligned with the horizontal component of the Earth magnetic field. On the contrary, when the aircraft is turning or otherwise accelerating, the compass card deviates from the expected MH even more than 30 degrees under the effect of the vertical component of the magnetic field. The compass cards displayed by the others instruments (HSI, ADF and HUD) are feed by the flux gate sensor and each stabilized by its own gyroscope. The MH indicated by these instruments does not suffer from the the deviations of the magnetic compass.

In case of instruments failure, turns based on the magnetic compass have to be timed, because the magnetic compass cannot provide a valid reference for the final heading. For example, starting from MH=east and having to rotate at MH=north, the pilot shall perform a timed standard left turn at 3°/s for exactly 30 seconds.

The magnetic field on the Earth is calculated using the World Magnetic Model library from NOAA (https://www.ngdc.noaa.gov/geomag/WMM/soft.shtml) and it is used to display the current magnetic heading of the aircraft, to rotate the magnetic compass, and to calculate the magnetic bearing at each VOR station. The file of the coefficients objects/WMM.COF provided along the package is valid for dates in the range from year 2015 up to year 2019 included; beyond this range, a warning is displayed and a new updated file coefficients should be installed.

It is important to note that the components of the Earth's magnetic field are calculated respect to the current year and day, so updated navigation charts may be needed. The navigation charts provided along this package are outdated, so magnetic bearings there indicated may differ more or less from the calculated values.

The Classic Instruments Panel

Press Shift-H to alternate between the HUD and the classic instruments panel. The classic instruments panel mimics the instrumental equipment of a typical light aircraft, as the Cessna 172-RG. The program does not simply reproduce the same informations already shown by the HUD, but it tries to emulate also errors and limitations introduced by these instruments and that make the job of the pilot harder (and then, more interesting for us). In the following we will describe each instrument and its properties. The interested reader should refer to the aeronautical literature for more informations about their proper usage.


Instruments of the classic panel.


In the classic instrument mode the HSI and ADF always indicate the MH, as the compass card of these instruments is driven by the flux gate sensor. In the HUD mode, on the contrary, the HSI and ADF are driven by the inertial platform and are able to indicate both TH and MH.

Turn and slip indicator

The pointer moves indicating the rate of turn around the vertical axis of the aircraft. Normally the aircraft z axis is very close to the geodetic vertical, so that the indicated value is nearly equal to the actual yaw rate. At high roll angles or high bank angles, this is not strictly true and small differences between the actual yaw rate and the indicated value may arise.

The central mark of the turn indicator indicates zero turn rate, while the other marks indicates 1.5°/s and 3°/s turn to the left or to the right.

Below the turn rate indicator there is a curved glass containing a little ball. This ball moves from the central position under the action of a lateral acceleration, typically as a consequence of an uncoordinated turn.

Airspeed indicator

It indicates IAS on a non-linear scale (kt). This value is calculated using the formula below:

IAS = TAS * sqrt(rho/rho0) * (1 + 1/8*(1 - delta)*M^2)

being TAS the true airspeed along the x axis, rho is the air density at the current altitude, rho0 the air density at sea level, delta is the ratio P/P0 between the current air pressure and the pressure at sea level, and M is the Mach number.

The digital number indicates the Mach number in the range 0.00 - 9.99.

Attitude indicator

Also known as artificial horizon, it provides to the pilot the pitch and the bank angles. Inside this instrument there is a gyro whose axis is parallel to the local apparent vertical direction.

An erection system (slowly) forces the axis to follow this vertical, but this alignment process can take some time, typically from 2 to 5 minutes, depending on the amplitude of the misalignment. Accelerations produced by speed changes (takeoff) and prolonged turns can misalign the gyro. To prevent that misalignment, the erection system gets disabled if the measured acceleration differs from the expected "g" value +/-2%. That it means, for example, that turning with angles of bank greater than 12° will not disturb the alignment.

The gyro can follow the aircraft movements up to +/-70° angles of bank and pitch. Above this limit the gyro will hit the internal lock, tumbling abruptly and loosing its alignment. For this reason the pilots has also a "cage" knob (F9) that forces the alignment of the gyro with its case, speeding-up the following fine alignment performed by the erection system. The "cage" knob is also useful to fast align the gyro at the start of the program.

The orientation of the gyro is represented to the pilot as a ball. Over this ball are drawn the horizon line and several pitch marks separated by 5° up to +/-30°. The stylized figure of a little aircraft's wings can be moved up and down by the pilot (F11, F12) so that it becomes aligned with the line of the horizon. This adjustment should be performed in level flight at constant speed so to indicate zero pitch. Once so adjusted, the indicated pitch will match the angle of climb as indicated by the flight path marker of the HUD, provided that these maneuvers are performed at the same airspeed at which that adjustments was made.

A triangle indicates the angle of bank, at steps of 10, 20, 30, 60 and 90 degrees. This triangle moves in the opposite direction of the horizon, so to indicate the actual direction of the turn.

Flying with the classic instruments panel may be challenging at first because there is some delay between pilot's input and the actual feedback from the instruments. Things get simpler if you accurately plan every maneuver before starting any action. The two rules below should help:

Bank rule. To attain the standard rate of turn of 3°/s in a coordinated turn, first calculate the required angle of bank as given by this approximated formula:

bank = 0.15 * airspeed

Bank angle versus TAS.


For example, at 100 kt the angle of bank is 15°. You can calculate easily this value taking the airspeed, dropping the last digit and then adding half of its value. Then roll-in at this angle of bank looking at the attitude indicator: once the aircraft starts to turn, adjust the rate looking at the turn indicator.

Pitch rule. At constant airspeed, changes in vertical speed are related to changes in pitch angle by this approximated formula:

vertical_speed_change = 2 * pitch_change * airspeed

For example, flying at 100 kt, every degree of pitch change will result in a change of about 200 fpm of vertical speed. Use the pitch scale of the attitude indicator to move the aircraft's nose to the expected pitch angle. Then, some seconds later, the VSI will indicate the actual vertical speed so achieved allowing to fine-tuning the pitch.

Altitude indicator

This instruments indicates the altitude. The digital display shows the flight level (bigger digits) followed by the two less significant digits of the current altitude. The pointer indicated tens feet. Since in ACM the atmospheric conditions are always stable and equal to the standard atmosphere, the indicated altitude is also the actual altitude above the sea level (MSL).

By default the altimeter indicates the standard pressure altitude (29.92 inHg) but you can change the isobaric level of reference pressing F7 and F8.

For negative altitudes, the instrument passes from 0 to 99990 ft, then 99980 ft and so on.

Vertical speed indicator (VSI)

It indicates the rate of change of the altitude from −4000 ft/min up to +4000 ft/min. This instrument has a lag of about 3 seconds, so it takes some time before it stabilizes to the actual vertical speed. Changes in altitude should then be made with the aid of the attitude indicator: first, move the aircraft to the expected pitch, then look at the VSI for fine adjustment of the desired vertical speed rate.

The Head-Up Display

The Head-Up Display (HUD) is a collection of indicators that permits pilots to focus their attention on what's going on outside of the cockpit. These indicators are projected onto a flat pane of glass located near the windscreen. Much of the information is displayed graphically to give the pilot a quicker understanding of the immediate situation.


The Heads-Up Display.


Ladders

Four tape-style "ladders" display basic flight information. On the left, is the aircraft true airspeed (TAS). Each minor tick on the airspeed ladder represents 10 nautical miles per hour (also known as knots and abbreviated "kt").

On the right is the altitude over the sea level (MSL). Each tick represents 100 feet. A rate-of-climb readout is located just below this ladder; rate-of-climb is expressed in feet per minute.

In the lower center is a horizontal heading ladder. Each tick represents five degrees.

In the center is an attitude ladder. Each line corresponds to ten degrees of aircraft pitch. The ladder rolls as the aircraft does, providing an artificial horizon.

HUD Compass

The compass displays the the true heading (TH, default) or the magnetic heading (MH). Press Shift-M to switch between the two modes. The HSI displays the mode currently selected. Implementation note: the local magnetic variation is that of the nearest NAVAID station or ILS station.

Angle of Attack

The ACM HUD has two indicators to give the pilot cues as to the planes current angle of attack and sideslip. First, above the altitude ladder, is a readout of the plane's current angle of attack in degrees. The ACM F-16 will stall at a positive angle of 30 degrees and a negative angle of -30 degrees.

Additionally, a plane-shaped "flight path marker" indicates the aircraft's current direction of travel. Level flight occurs when the flight path marker is aligned with the zero- degree artificial horizon line.

The G-Meter

A readout of the current vertical G-force on the pilot is located above the airspeed ladder.

Weapon State

Below the throttle indicator are discretes that show the state of the currently selected weapon system.

Turn and slip indicator


The turn and slip indicator.


The turn and slip indicator displays the yaw rate and the lateral acceleration. The triangle indicates the standard rates of turn of 1.5°/s and 3°/s. The vertical bar indicates the lateral acceleration, every tick being 0.25 g. The left part of the figure above illustrates a left turn at 3°/s with about 0.4 g of lateral acceleration (uncoordinated turn). The right part of the figure illustrates a coordinated turn without lateral acceleration. Coordinated turns are obtained combining ailerons and rudder.

Mach-meter

The Mach number is the ratio between the airspeed and the speed of the sound at the current altitude. The table below shows the speed of the sound at some typical altitudes:


Altitude (ft) Speed of the sound (kt)
0659
10000640
20000615
30000590

The Mach number appears only when the speed is at least 0.20 Mach at the current altitude.

Radar altimeter

At low altitude, below 2500 ft over the terrain, the radar altimeter scale is displayed. The radar altimeter shows the distance in hundreds of feet between the terrain and the wheels of the main gear.

The HSI

The Horizontal Situation Indicator, or HSI, is a nifty device to aid in instrument flying. It receives and displays VOR/DME stations and ILS stations. The compass card of the instrument gets automatically oriented toward the magnetic north. A sensor of the earth magnetic field (also known as flux gate) detects the orientation of the magnetic north. A gyroscope provides short term stability while the aircraft is maneuvering and, when in level flight, the flux gate provides the correction to the gyroscope drift. The result is an instrument that provides highly accurate aircraft heading in both turning and straight flight, without a requirement for the pilot to manually adjust for drift as in a standard directional gyro.

NOTE. Instruments mounted on the real aircraft have both the slave mode (as described here) and the free mode. When the pilot selects this latter mode, the flux gate gets disabled (for example because a failure) and the HSI operates simply as a directional gyro that needs to be manually aligned with the magnetic compass.

In ACM the HSI system occupies two slots of the instrument panel: the left slot is the control panel and the right slot is the HSI display. The HSI panel receives radio signals from VOR, DME, LOCATOR and GS stations, it elaborates all these informations and then it feed the HSI display.

To save space on the screen, these two panels share the same area with the ADF receiver and the radar system. Use the r key to change radar/ADF modes until the HSI is displayed.

The HSI control panel. It displays several informations. Mode can be NAV1, NAV2, RNAV1, ..., RNAV5. These modes will be described below in separated paragraph. There are two independent NAV1 and NAV2 receivers and five RNAV calculators. Use the SPACE to switch between NAV and RNAV modes.

FRQ is the frequency of the station, as selected by pilot (9, 0).

Once the station has been selected and properly tuned, the receiver starts listening for the signal emitted from the station that can provide also its name displayed in STA (station name).

If the station provides also a distance measurement equipment (DME) this distance gets displayed.

The RAD and DST fields are meaningful only in RNAV mode and are described in the respective paragraph.

The HSI display. In the TH mode (the default, as shown in the figures below) the indicated north is the geographic north. In the MH mode (Shift-M) the indicated north is the magnetic north. The TH mode is mainly useful for estimated navigation based on geographic charts, since these maps are always oriented toward the geographic north pole. The MH mode is the preferred mode for aeronautical navigation, since all the angular indications (VOR, ILS and runways headings) are always referred to the local magnetic north.

The curse deviation indicator (the purple segment at the center of the display) gets displayed only if the corresponding radio signal is correctly received. The slope deviation indicator (the purple arrow to the right of the display) gets displayed only if the corresponding signal is correctly received.

Use the 7 and 8 keys to orient the Omni Bearing Selector (OBS). The OBS displays the digital value of the selected direction.

HSI for VOR stations

In NAV mode the HSI displays the VOR/DME bearing, angular deviation (CDI) from the selected radial (OBS) and distance DME.


The HSI tuned on a VOR/DME station in NAV mode.


Having two NAV receivers is very useful, both for navigation and to approach the runway. For example, we can tune NAV1 on the VOR station we are leaving and NAV2 on the station we are going to. Or, we can tune NAV1 on the terminal-VOR of the airport, and NAV2 on the ILS station.

The frequency of a VOR station ranges from 108.x0 MHz up to 111.x5 MHz with x being an even digit 0, 2, 4, 6, 8 for terminal VOR, and from 112.00 MHz to 117.95 MHz for en-route VOR.

The signal range of a terminal VOR is about 40 NM, and the range of an en-route VOR is about 200 NM due to the limited power emitted by these stations. Moreover, electromagnetic signals at hight frequency (100 MHz and more, as those emitted from VOR stations are) propagates in a direct line of sight. Because of the curvature of the Earth, the range at which the signal can be received may be even more limited depending on the current altitude of the aircraft:

range = K * (sqrt(station_altitude) + sqrt(aircraft_altitude))

where the altitudes are expressed in feet and the resulting distance in NM. The value of the constant K in the formula above is K=1.064 as you can easily prove with simple geometrical considerations assuming the Earth to be a sphere of radius R=3438 NM. Then, for example, if the altitude of the station is 500 ft and the altitude of the aircraft is 4000 ft, the signal cannot be received beyond the distance of 91 NM.


The Earth is round and radio signals at high frequency (100+ MHz) propagate in stright line.

Every dot of the CDI scale indicates a deviation of 1.7° from the selected radial. For stations providing a DME, the distance from the selected radial is given by this simple formula:

distance_from_radial = distance_from_DME / 100 * 3 * CDI

For example, if the distance from the DME station is 20.0 NM and the CDI indicates 2 dots, then the distance from the selected radial is 20/100*3*2=1.2 NM.

HSI for ILS stations

In NAV mode, also ILS stations can be tuned.


The HSI tuned on a ILS station.


The frequency of ILS stations ranges from 108.x0 MHz up to 111.x5 MHz, with x being an odd digit 1, 3, 5, 7, 9.

An ILS station can be received up to the distance of about 18 NM and in a range of +/-50° from its bearing angle.

Every dot of the CDI scale indicates a deviation of 0.4° from the LOCATOR plane (not the deviation from the OBS, but the pilot can still select an OBS for its own reference). Every tick of the glide slope scale indicates a deviation of 1° from the glide path angle of the ILS station (typically 3°).

HSI for RNAV calculator

The RNAV calculator can store up to 5 waypoints (WP). The pilot enters the WP in the RNAV calculator in polar coordinates (radial RAD and distance DST) referred to some VOR/DME station, along the frequency of the VOR/DME station itself.


The HSI tuned on a VOR/DME station in RNAV mode.
The waypoint is set at radial 75, distance 24.5 NM from the VOR/DME.


NOTE: bare VOR stations and ILS stations cannot be tuned in RNAV mode.

Once the control panel has been set, the RNAV calculator feeds the HSI display with angular deviation and distance from the selected waypoint (WP). Then the pilot can fly toward the WP just like if it were a "phantom" VOR/DME station. The DME field of the control panel displays the distance from the WP (not the distance from the VOR/DME station used as a reference).


A "phantom" VOR/DME guides the aircraft along the route from A to WP and then from WP to B.


The ADF

Press the r several times until the ADF receiver gets displayed. The compass card of this instrument is automatically aligned with the magnetic north tanks to the signal provided by the flux gate, and stabilized with a gyroscope.

The ADF occupies two slots of the instrument panel: the left slot is the ADF panel were the frequency and the ID of the NDB station gets displayed; the right slot is the ADF display that shows the magnetic bearing of the NDB station.


The ADF control panel (left) and bearing indicator (right).


Tune the desired station pressing 9 and 0.

In the real world the range of the NDB signal depends on many factors. In ACM this range is set to 100 NM for navigation NDB stations, and 20 NM for instrumental approach stations (OMARKER, MMARKER, IMARKER).

The Auto Pilot System

The auto-pilot system (APS) consists of several functional blocks, each one taking control of some flight parameter. The relations between blocks are indicated in the diagram below. Every block can be engaged or disengaged by the pilot independently from the others blocks, with the only exception of AW and AP that might be required by AN and AL.

In a emergency, the APS can be disabled pressing the key Home.


Block diagram of the Auto Pilot System (APS).


A note about the terminology: "APS" is the whole system of auto-piloting, while the "AP" is the sub-block that control the altitude or the climb rate. Perhaps the AP should had been split in two independent blocks performing "hold altitude" and "hold climb rate", so resolving the ambiguity. This can be a change left to the future releases of the program.

The Auto-pilot

The auto-pilot (AP) helps the pilot keeping a given rate of climb or a given altitude. When engaged, the AP adds a correction term to the current elevator control that can grow up to the 50% of the full elevator control range:

elevator_setting = pilot_setting + AP_correction_term

Even when the AP is engaged, the pilot preserve the ability to control the aircraft, while the AP will try to do its best to keep constant the controlled parameter. Press Shift-A to engage/disengage the AP. When engaged, the "AUTOPILOT" word is displayed on the HUD.

Engaging the AP to hold the rate of climb. Once the desired rate of climb has been attained, engage the AP. The AP will grab the current rate of climb and will use this value as a reference to calculate the elevator correction. The rate of climb must be greater than +100 ft/min or less that −100 ft/min.

Engaging the AP to hold the altitude. Once the desired altitude has been attained, engage the AP. The AP will capture the current altitude and will use this value as a reference to calculate the elevator correction. The rate of climb must be near to zero +/− 100 ft/min. As an alternative, press Shift-Z: in this case the AP grabs the current altitude and keeps this value as reference.

Disengaging the AP. Press Shift-A or Shift-Z. The elevator correction term will be released smoothly within 3 seconds, restoring the full control of the elevator.

AP alarm. When the AP correction grow beyond the 25% of the full elevator control range, the "AUTOPILOT" displayed in the HUD (or the "Pilot" light in classic instruments mode) will blink. In this case the intervention of the pilot is required. Adjust the pitch or the engine power until the alarm disappear.

AP limitations:

- max vertical acceleration: +/- 0.1 g
- hold altitude mode, max vertical speed: +100 fpm
- hold altitude mode, min vertical speed: -1000 fpm
- disengaging the AP, smooth release of the elevator within 3 s

The Auto-throttle

The auto-throttle (AT) controls the engine thrust in order to hold a given IAS limiting the acceleration to the range -0.5g .. +0.1g. When the selected TAS cannot be attained, the pilot is warned by the blinking "ATxxx" in the HUD (or the blinking light "Thr" in classic instruments mode).

The AT can be engaged/disengaged pressing Shift-T. When enabled, the current TAS is grabbed and used by the AT as the target speed. The value of the current target speed is displayed in the HUD to the right of the speed scale. For example, the indication "AT120" means that the target TAS is 120 kt.

When the AT is enabled, the buttons that normally control the engine change their meaning as follow:

1 disable the AT device and sets the minimum thrust (20% RPM).

2 decrease the target TAS by 5 kt.

3 increase the target TAS by 5 kt.

4 disable the AT device and the AP and sets the maximum thrust (100% RPM).

Press Shift-T again to disengage the AT keeping the current throttle setting.

The Auto-coordinator

Controlling the rudder through the keyboard and without a physical feedback of the lateral acceleration is really difficult, so often compromising the precision of the maneuver on coordinated standard turns.

The auto-coordinator (AC) feature allows the rudder to be controlled by the program in order to cancel the lateral acceleration, indicated by the slip indicator. The AC can be enabled/disabled pressing Shift-X. Once enabled, a little "AC" gets displayed to the side of the slip indicator (or the "Coord" light in classic instruments mode) and all the turns are automatically coordinated.

A good way to do a standard turn in AC mode is bringing the aircraft to the expected bank angle, then checking the turn rate indicator for the expected turn rate. The figure below plots the expected bank angle vs. the current true air speed for 1.5°/s and 3.0°/s standard rates of turn.

The arrows keys are very useful to do little heading corrections in AC mode, for example to align the aircraft to the runway. Larger turns can be done simply moving the mouse.

The keys z c that control the rudder are still enabled, but not really effective. You may use them for even finer heading corrections.

The Auto-navigator

The auto-navigator (AN) allows to follow the radial indicated by the OBS set into the HSI panel. Once enabled, the AN automatically compute a proper approaching route bringing to the radial, then it maintain this radial. Ailerons and rudder are controlled in order to correct the magnetic heading of the aircraft according to an algorithm explained below.

Enabling the AN. To enable the AN follow these steps:

  1. Tune the HSI on the chosen VOR station or WP.
  2. Turn the OBS to the chosen VOR radial.
  3. Enable the AN (Shift-N). The word "AutoNav" gets displayed in the HUD (or the "Nav" light in the classic instruments panel).

The approaching path. The AN computes the path bringing to the chosen radial. Normally an approaching angle of OBS+45° gets chosen if the aircraft is located to the left of the radial (point A of the figure) otherwise an heading of OBS−45° gets chosen (point B of the figure). The aircraft then turns toward the heading so computed, either clockwise or counter-clockwise depending on the current heading. For example, if the target heading is 360° (north) and the aircraft is currently directed toward east, then the aircraft will begin to turn counter-clockwise 90°; if the current heading is west, then the aircraft will turn clock-wise. Every turn gets performed with angular speed up to +/−3°/s and a bank angle up to +/−25°.

When the CDI (angular deviation from the OBS) becomes less than 2°, or when the CDI starts moving (indicating that we are very close to the VOR station) the approaching angle gets diminished smoothly so that the aircraft reach the radial with a single turn. This simple strategy works well when the aircraft is far from the VOR, but for short distances (say, 5 NM or less) the aircraft gets forced in a sequence of rough turns, waving around the radial. Because of this limitation the AN should always be disabled below 5 NM from the VOR.

Disabling the AN. The AN can be disabled intentionally pressing Shift-N again. The AN gets also disabled if any of these events occurs:

  • The auto-pilot system gets disabled.
  • Engine shoot-off of engine max power.
  • The HSI frequency gets changed.
  • The OBS setting gets changed.
  • Switching between NAV/RNAV receivers.
  • Switching between HSI/ADF/radar display.
  • Loosing the signal from the VOR station.

The Auto-landing

The auto-landing takes control of the aircraft controlling heading and pitch following the approaching path to the LOC+GS station currently tuned. The heading gets corrected in order to smoothly reach the LOCATOR plane. If also the GS is available, then the pitch gets controlled in order to attain the indicated descending path. The AL also performs the flare maneuver, deploys the thrust reverse (if available), deploys the speed brakes, enable the wheel brakes and finally stops the aircraft on the runway.

Enabling the AL. To enable the AL follow these steps:

  1. Tune a LOC or LOC+GS=ILS station.
  2. Turn the aircraft so that it is roughly oriented toward the runway. An approaching angle of no more than 30° from a distance of at least 5 NM gives the better results.
  3. Enable the AL (Shift-L). The word "AutoLanding" gets displayed in the HUD (or the "Land" light will lighted in classic instruments mode).

Once enabled, the AL compute a proper, smooth approach to the plane of the LOCATOR, then it will attain this route up to the runway threshold. Turns are performed with a maximum bank angle of +/-25°.

For ILS stations providing also the GS signal, the AL can follow the glide path. In this case, the AL takes control of the elevator, maintaining the current altitude until the glide slope plane is reached. Once the GS has being reached, the AL sets a descending rate suitable to maintain the alignment with the glide slope plane (typically -3°).

The AL behave pretty well and it can recover from situations that would be very hard for an human to handle. However, in order to ensure the best results, these restrictions should be respected:

  • Initial distance from the runway: greater than 5 NM.
  • Angle of incidence with the LOCATOR plane: less than 90°.
  • Initial distance d from the locator plane: possibly not less than the distance required to attain the LOCATOR alignment with a single turn at the rate of 1.5°/s.

Requirements of the auto-landing.


The figure above illustrate the final approach to the runway. The optimal distance from the LOCATOR plane should be large enough to allow to the aircraft to attain the alignment to the LOCATOR with only a turn at the rate of 1.5°/s:

d ≥ (1 - cos(A)) v / 94

where v is the current TAS (knots). For example, with an angle of incidence of A=30° and v=170 kt the distance would be 0.24 NM. By the contrary, crossing the LOCATOR plane with an angle near to 90° at little distance from the runway, would force the AL to do several turn maneuvers, often ending with a misalignment and a missing approach.

Disabling the AL. The AL can be disabled intentionally pressing Shift-L again. The AL gets also disabled automatically when any of these events occurs:

  • Engine shut-down or engine max power required.
  • Loosing signal from the radio station (too far or outside the allowed cone).
  • Changing the frequency on the HSI.
  • Switching between NAV/RNAV receivers.
  • Switching between HSI/ADF/radar display.

Detailed description on how the AL works. The exact sequence of the events depends on several factors. For brevity we will indicate with FLARE_ALT the altitude over the runway at which the flare maneuver starts, V is the current speed, :

FLARE_ALT = 0.375 ft/kt * V

so, for example, landing at 160 kt the flare maneuver starts when the radar altimeter indicates 60 ft from the terrain. We will also indicate with V_TOUCHDOWN the airspeed indicated when the main gear hit the runway. The exact sequence of events is as follow:

1. Keep current altitude until the GS path is intercepted. Adjust heading according to the CDI.

2. Once the GS has been intercepted, start descending at the standard rate of −3 DEG. If the GS has a different angle, the resulting GS error will guide the AL to the correct descending ratio. Continue to follow the LOCATOR, adjusting the heading.

3. When the altitude as indicated by the radar altimeter becomes less than 250 ft, the GS signal is assumed to be unreliable and the aircraft keeps its attitude and continues following a ballistic descent at the standard descending rate of −3 DEG.

4. When the altitude indicated by the radar altimeter becomes less than FLARE_ALT, the flare maneuver starts. Raise nose so to keep a descending rate of −1 DEG. Ensure wheel brakes are disabled.

5. When the altitude as indicated by the radar altimeter is less than 0.5*FLARE_ALT disable engine auto-throttle and hold current power setting. The speed begins to reduce.

6. When both the wheels of the main landing gear hit the ground, grab current airspeed V_TOUCHDOWN, as it will used for reference in the rest of the procedure. The speed brakes are fully extended, if available. If the thrust reverse device is available, deploy and set engine power to 75%. Otherwise, set engine idle. Disable auto-pilot and keep current pitch angle.

7. For tricycle landing gear, immediately lower nose wheel. For bicycle landing gear, hold current pitch until speed drops under 85% V_TOUCHDOWN, then begins lowering the tail wheel.

8. For tricycle landing gears, when all the wheels are in contact with the terrain, enable wheel brakes. If thrust reverse available, brakes are enabled only below 50% V_TOUCHDOWN.

9. At 40% V_TOUCHDOWN, if thrust reverse device available, set engine idle.

10. At 20% V_TOUCHDOWN disable AP, AL, AW and retract thrust reverser, leaving only the brakes on.

The Auto-turn

The auto-turn block (AW) control the rate of the turn and it is mostly used by the AN and AL. The pilot can engage manually the AW to perform standard turns at 1.5 and 3°/s or also 0°/s to keep the current heading. The involved keys are:

< turn left at 3°/s

, (comma) turn left at 1.5°/s

| (vertical bar) stop turning and hold heading

. (dot) turn right at 1.5°/s

> turn right at 3°/s

/ disengage the AW

The "MAX BANK" knob set the maximum bank limiter, chosen between 5, 10, 15, 20 and 25 degrees. The AW will never exceed this value.

When the AW is enabled, a little round circle gets displays into the turn-and-sleep indicator giving the feedback of the turn speed the AW is aiming to (see the figure to the right).

Lights Panel

The status panel displays 14 lights. The alarm lights blinks alerting the pilot about some serius sub-system failure or other urgent danger:

OIL, HYD1, HYD2: hydraulic subsystem failures.
GEN1, GEN2: power sources failure.
FLAP: flaps failure.
SPBRK: speed brake failure.
RADAR: radar failure.
TEWS: TEWS failure.
HUD: HUD failure.
G-LOAD: above 75% maximum positive or negative wings load.

Status and warning lights does not blink and are alerts to the pilot:

FUEL: fuel tank below 15% maximum capacity.
SPD BRK: speed brakes engaged.
BRAKES: wheel brakes are on.

The Radar System

The ACM radar system has a field of view in Normal mode of 120 degrees laterally and vertically from the front of the aircraft. The F-16 radar set's range is about 80 NM. All aircraft within that range and field of view will appear as a box on the radar display


Radar coverage.


The ACM radar display presents a forward looking view of radar targets. Think of it as a television monitor connected to a forward-pointing TV camera that has a very wide angle lens.

If any objects are close enough to be radar-visible, the set will automatically lock onto the nearest threat. With radar lock acquired, your display will provide detailed information about the locked, or "primary", target's disposition. A primary target appears as a filled diamond on the radar display -- the display provides information on the primary target's range and altitude, as well as it's current heading, your desired relative heading to intercept and the rate of closure of your two aircraft.


The ACM radar display.


The radar set's ability to establish a positive lock on a target extends for a shorter range than the radar's maximum detection range -- radar lock is limited to about 60 NM on the F-16 and 30 NM on the MiG-29.

If multiple targets are plotted on your radar display, you can lock onto other targets by pressing the target reject key (q).

The radar on/standby key (R) can be used to toggle your radar set between its normal operating mode and a standby state. When your radar is in standby mode, your aircraft emits no radar energy and can be more difficult to detect.

Electronic Countermeasures

Fighters are Equipped with a special device called a Radar Warning Receiver (RWR). It's display is the round "CRT" to the left of the radar display. It works much like a radar detector that you can buy for your car. The receiver can detect radar emissions from other aircraft and will plot a box on the RWR display representing the relative direction of that radar threat. Opposing team’s radar emissions appear as filled boxes. Friendly aircraft appear as open boxes. This receiver cannot detect aircraft that have their radar emissions directed away from your aircraft, nor is it capable of detecting aircraft that have their radar sets turned completely off.

Weapon Systems

Your aircraft is equipped with heat-seeking missiles and a 20-millimeter cannon. Weapon information is displayed in the lower left-hand corner of your HUD. Different weapons may be selected by pressing mouse button 3. The currently selected weapon is fired by pressing mouse button 2.

Air-to-Air Missiles

The missiles are patterned after U.S. AIM-9M Sidewinders and AIM-120 AMRAAM. They can detect infrared (IR) targets at any aspect (not just from the rear).

The range of these missiles varies dramatically with the altitude and closure rate. The missile subsystem couples with your radar set to provide time-to-impact information.

This missile has a solid rocket motor that burns for about 8 seconds (AIM-9M) or 15 seconds (AIM-120). After burn-out, it will still track towards its intended target but may lose speed too rapidly to catch it. Your heat seeking missiles don't arm themselves until one second (AIM9M) or three seconds (AIM-120) after launch. Because of that, you should not fire at a target for which the flight time is less than the arm time.

Beware! clouds are opaque to IR. If the target hides in the clouds, the missile loses lock and continues flying ballistically, possibly missing the target.

Missile status discretes and their meanings:

ARM --
No target acquired on the radar.

ARM 125
Missile's seeker has not yet acquired the target in its field of view; time to target 125 seconds.

LOCKED 18
Missile locked on target and ready to fire; time to target 18 seconds.

IN RANGE 2
Target too close; time to target smaller than arm time.

Cannon

Cannon can be used to engage targets at closer range. Your cannon is modeled after the U.S. M61-A1 Vulcan. Aircraft typically begin a mission with 500 rounds of ammunition; the cannon fires at 3000 rounds per minute so you only have enough ammunition for a ten-second continuous burst -- use it carefully.

When cannons are selected, the HUD is in Lead Computing Optical Sight (LCOS) mode. On the HUD, a circular aiming reticle is displayed. The HUD couples with the radar set to provide a visible cue of the target's current range. The aiming reticle is surrounded by 12 ticks. An inner arc represents the current range to the target: each arc tick represents 1000 feet of distance. The aiming reticle moves across the HUD to show a good aiming point based on the target's range and your aircraft's pitch and turn rate. If the range is large and or your pitch and turn rates are fast, you may see no reticle at all: the aiming point is simply out of the HUD's field of view.

An unmoving cross (a "+") will be displayed on the HUD in LCOS mode. This marker denotes the boresight of the cannon -- the direction that the cannon's barrel is actually pointing.

Figure 6 (missing!) shows another example of what you might see in a dogfight. All planes are turning hard to the left at a relatively low speed. You are in LCOS mode and see that the reticle is positioned ahead of the intended target. To get the kill, simply relax the turn long enough to get into position and then take the shot.

Drop bombs

You fighter may be equipped with one or more standard Mark 82 (MK-82) drop bombs. If so, then selecting that weapon with the right mouse button displays the CCIP sighter. The circle indicates the estimated hit point if the bomb get dropped right now with the left button of the mouse. A line joinging the flight path marker to the circle helps aligning the target point while the aircraft dives.

Currently only the SU-30 model is equipped with drop bombs; you may change this setting by adding drop bombs to any other fighter by changing its configuration file as explained in this manual.

Drones

Drones are automated opponent aircraft. They are created by pressing the l key. Drones aggressiveness setting (see option -da) controls how hard a drone aircraft will attempt to maneuver to attack other planes. For example, a setting of 0.7 means the drone will maneuver pulling "G" up to the 70% of its maximum structural vertical limit (see the parameters MaxLoadZPositive and MaxLoadZNegative); if the fighter supports up to 10g of positive vertical acceleration with nearly empty tank, it will reach 7g of positive vertical acceleration.

With an aggressiveness factor too low (probably 0.2 or less) the aircraft will hardly sustain its own weight and will crash on the ground without even try to fly. With a value near 1.0 or greater your opponent drone will fly very close to its structural limit and may suffer a sudden tragic fatal structural failure... Values between 0.7 and 0.9 will usually make for an interesting opponent.

Stealth Mode

I don't really know what this "stealth" mode is and what it is intended to do, but apparently it is not working anymore. Any help appreciated. - U.S.

ACM’s stealth mode allows users to monitor out-the-window views for any aircraft active in an exercise.

$ acm -stealth

In stealth mode, the radar display is used to display DIS entity id’s of aircraft participating in the exercise. To select and aircraft to follow, use the mouse to click on one of these identifiers. The entity id of the aircraft you are following will be highlighted in magenta.

DIS Entity ID
  50,1,1
  50,1,2
* 50,6,1

If there is a large number of entities in an exercise, use the PAGE UP and PAGE DOWN keys to scroll through the list.

acm-6.0_20200416/doc/manual/acmdoc_html_hsi-rnav.png0000644000000000000000000000733110666003515020412 0ustar rootrootPNG  IHDRx+IDATx[z) FyNe)Y<a"@9ďx{B@o^i׏~|<46}d~V@XXP7e;ptf *K1gA$j:^D?}^`Bh`|Xcg'h+B'PoJ^LiM1`4:.sytw4YHX#)-'ؒ׽yb6~+fL)+t?,:e c]ChDjߋ༬MEkjl^δRsYLڒA2V:H64`GeJ&ՒT\DUD>BB8v>3Khx7EMy⏓v9k[@#vCϷ7%&|CCWz5`%INVbꚒYD}`!KգqwIf I;~>'3Ӯ&J6b&q02}.:Zp:c'<4Nmh|ؗ lExJ✷mU4Chup{H}\u1[_Ŵ7i&Ԥ4D 6jJ^gbĞ`"&fdr6i"5]e֚Zo?hM"~Kܻ_hͭ_XI˖ԓ̿sk_¾y+hf oi|Ԟq ߂UB;+8 W +Iz$;WbUP*cgɠ7协GhMN:C|׌53o;lGgTp#J >nYF ״H%\[<Xϯ#S6S??ЀR)ݑ_7~3Qe rZkF.zWЀju>9P"{萒 Es6Z! 4kDk}tV\uƕl|ؼ{t\u]z7끦<1 f\5R\2cڙiO,GIf j Yãi9ǯTRWFQf LR.v|itIuJ1߆YB;+Ϥr#_nr76xib뷮%z4 uűoBu©Yq,'sg=kz? Bs ͐[p2,B' JLJ9ߔ *ƶ`>r V!]J(}>r&s&Xܙ̭LWJ&?{\ FF>wYl-%ȓsWx8?/ݖ'&4#bSr %FW3)1S>ɦA1uҿP k4zJ/BЩhFr˸M3'C:"SB]QNB'X62> ȫFl?u{Ѐ `9arq9vK]M+׫0Hx˩ß׊ߢ"EG,* 9T@>M"m&Z4+4uJAZS ȡMӳfv`S+DluV[}$h艰bũ,?]K:Y{1)aS&#s;|NBvvt4ԥϩJ%"h_"/#41DA y!2 *{ 8Iju ]#W_qgɕG" 4hJ([w&-%E ЗS9|95HФ-1GB e&hIks|Yyu w"ԇNa%Shux4 рIf{h`h4\\ 4ƍ3w*HDΩ_h@ )y LғLa ѝ6bP>.Fh2dVebAhz9j BB3AF+t,kjo_WV ˵PcXV:WU Sd3+@U>JJW%)g3X54-t&m?_ Mdkd^$D;ۯҹ.~n_ilКknXF ʙV>rJtl7 S_ :':ʝ~$#aq2ך횟nAV&uL|31\*[ `(:p]0BI{6B2R 4z|9޲}p!4{ *pqk*C T~j82$ZZ s$8w6Fn4vxz+NN=hV0"4a@wr"4t> .W%C+n=ՍNnL[rT쑑jo2B]Ú8M2:69Ӳ9+PY*s \a)SU)#ϱ1&\WaaI2Z7F5LASѱJ2f@ά}{Ոumo798 :Pc=>K$/AqmrcTlM T+D*Wm׽P{T$S]%GmJ&GGMRkpN46 75j`S1MtgZXwfz=] U//}nlxqQ!4Я59dOet"(o-'םH'>8\ LX*`nĀkPB|ʌ:`jPdko&Cq+sClGkVqjfٟ`}E?Y>ںK8Ί2jo~v ,%⩙! 4KzR p8Bȃ@ ӢJ#{ţ@hh@h`y_Xԁ IENDB`acm-6.0_20200416/doc/manual/acmdoc_html-aw.obj0000644000000000000000000002514510644355520017203 0ustar rootroot%TGIF 4.1.43-QPL state(0,37,100.000,177,48,2,4,0,8,1,1,0,0,0,0,1,2,'Helvetica-Bold',1,46080,0,0,0,10,0,1,1,1,0,16,0,0,1,1,1,1,1088,1408,1,0,2880,1). % % @(#)$Header$ % %W% % unit("1 pixel/pixel"). color_info(129,65535,0,[ "magenta", 65535, 0, 65535, 65535, 0, 65535, 1, "red", 65535, 0, 0, 65535, 0, 0, 1, "green", 0, 65535, 0, 0, 65535, 0, 1, "blue", 0, 0, 65535, 0, 0, 65535, 1, "yellow", 65535, 65535, 0, 65535, 65535, 0, 1, "pink", 65535, 49344, 52171, 65535, 49344, 52171, 1, "cyan", 0, 65535, 65535, 0, 65535, 65535, 1, "CadetBlue", 24415, 40606, 41120, 24415, 40606, 41120, 1, "white", 65535, 65535, 65535, 65535, 65535, 65535, 1, "black", 0, 0, 0, 0, 0, 0, 1, "DarkSlateGray", 12079, 20303, 20303, 12079, 20303, 20303, 1, "#7B9493", 31611, 38036, 37779, 31488, 37888, 37632, 1, "#8AA2A8", 35466, 41634, 43176, 35328, 41472, 43008, 1, "#9AB0BE", 39578, 45232, 48830, 39424, 45056, 48640, 1, "#7F9799", 32639, 38807, 39321, 32512, 38656, 39168, 1, "#7C99B6", 31868, 39321, 46774, 31744, 39168, 46592, 1, "#9EB4C3", 40606, 46260, 50115, 40448, 46080, 49920, 1, "#6F8984", 28527, 35209, 33924, 28416, 35072, 33792, 1, "#839B9E", 33667, 39835, 40606, 33536, 39680, 40448, 1, "#92A9B3", 37522, 43433, 46003, 37376, 43264, 45824, 1, "#A6BBCD", 42662, 48059, 52685, 42496, 47872, 52480, 1, "#77908E", 30583, 37008, 36494, 30464, 36864, 36352, 1, "#8EA6AE", 36494, 42662, 44718, 36352, 42496, 44544, 1, "#6B857E", 27499, 34181, 32382, 27392, 34048, 32256, 1, "#738D89", 29555, 36237, 35209, 29440, 36096, 35072, 1, "#879FA3", 34695, 40863, 41891, 34560, 40704, 41728, 1, "#96ADB8", 38550, 44461, 47288, 38400, 44288, 47104, 1, "#B1B1B1", 45489, 45489, 45489, 45312, 45312, 45312, 1, "gray68", 44461, 44461, 44461, 44461, 44461, 44461, 1, "#7C99B5", 31868, 39321, 46517, 31744, 39168, 46336, 1, "dark grey", 43433, 43433, 43433, 43433, 43433, 43433, 1, "#A7A7A7", 42919, 42919, 42919, 42752, 42752, 42752, 1, "#A5A5A5", 42405, 42405, 42405, 42240, 42240, 42240, 1, "#B4B7B7", 46260, 47031, 47031, 46080, 46848, 46848, 1, "gray64", 41891, 41891, 41891, 41891, 41891, 41891, 1, "#8EA1A5", 36494, 41377, 42405, 36352, 41216, 42240, 1, "#869DB4", 34438, 40349, 46260, 34304, 40192, 46080, 1, "#8FA2A5", 36751, 41634, 42405, 36608, 41472, 42240, 1, "#FEFEFE", 65278, 65278, 65278, 65024, 65024, 65024, 1, "#95A8AE", 38293, 43176, 44718, 38144, 43008, 44544, 1, "#B2B6BA", 45746, 46774, 47802, 45568, 46592, 47616, 1, "gray99", 64764, 64764, 64764, 64764, 64764, 64764, 1, "gray98", 64250, 64250, 64250, 64250, 64250, 64250, 1, "#F8F8F8", 63736, 63736, 63736, 63488, 63488, 63488, 1, "#F6F6F6", 63222, 63222, 63222, 62976, 62976, 62976, 1, "#F4F4F4", 62708, 62708, 62708, 62464, 62464, 62464, 1, "gray95", 62194, 62194, 62194, 62194, 62194, 62194, 1, "gray94", 61680, 61680, 61680, 61680, 61680, 61680, 1, "#EEEEEE", 61166, 61166, 61166, 60928, 60928, 60928, 1, "#ECECEC", 60652, 60652, 60652, 60416, 60416, 60416, 1, "#EAEAEA", 60138, 60138, 60138, 59904, 59904, 59904, 1, "gray91", 59624, 59624, 59624, 59624, 59624, 59624, 1, "#E6E6E6", 59110, 59110, 59110, 58880, 58880, 58880, 1, "#E2E2E2", 58082, 58082, 58082, 57856, 57856, 57856, 1, "gray88", 57568, 57568, 57568, 57568, 57568, 57568, 1, "#798D88", 31097, 36237, 34952, 30976, 36096, 34816, 1, "gray87", 57054, 57054, 57054, 57054, 57054, 57054, 1, "#788D87", 30840, 36237, 34695, 30720, 36096, 34560, 1, "gainsboro", 56540, 56540, 56540, 56540, 56540, 56540, 1, "#D8D8D8", 55512, 55512, 55512, 55296, 55296, 55296, 1, "#8EA6AD", 36494, 42662, 44461, 36352, 42496, 44288, 1, "gray84", 54998, 54998, 54998, 54998, 54998, 54998, 1, "gray83", 54484, 54484, 54484, 54484, 54484, 54484, 1, "#D2D2D2", 53970, 53970, 53970, 53760, 53760, 53760, 1, "#D0D0D0", 53456, 53456, 53456, 53248, 53248, 53248, 1, "#A3AEB1", 41891, 44718, 45489, 41728, 44544, 45312, 1, "#CECECE", 52942, 52942, 52942, 52736, 52736, 52736, 1, "#A1ACAF", 41377, 44204, 44975, 41216, 44032, 44800, 1, "gray80", 52428, 52428, 52428, 52428, 52428, 52428, 1, "#C8C8C8", 51400, 51400, 51400, 51200, 51200, 51200, 1, "#C6C6C6", 50886, 50886, 50886, 50688, 50688, 50688, 1, "#91A5A9", 37265, 42405, 43433, 37120, 42240, 43264, 1, "gray77", 50372, 50372, 50372, 50372, 50372, 50372, 1, "#6C857E", 27756, 34181, 32382, 27648, 34048, 32256, 1, "gray76", 49858, 49858, 49858, 49858, 49858, 49858, 1, "gray", 48830, 48830, 48830, 48830, 48830, 48830, 1, "gray73", 47802, 47802, 47802, 47802, 47802, 47802, 1, "#B4B4B4", 46260, 46260, 46260, 46080, 46080, 46080, 1, "#B2B2B2", 45746, 45746, 45746, 45568, 45568, 45568, 1, "#859DB4", 34181, 40349, 46260, 34048, 40192, 46080, 1, "gray69", 45232, 45232, 45232, 45232, 45232, 45232, 1, "#ACACAC", 44204, 44204, 44204, 44032, 44032, 44032, 1, "#A4A4A4", 42148, 42148, 42148, 41984, 41984, 41984, 1, "#A2A2A2", 41634, 41634, 41634, 41472, 41472, 41472, 1, "#9BA8B5", 39835, 43176, 46517, 39680, 43008, 46336, 1, "#B0B3B2", 45232, 46003, 45746, 45056, 45824, 45568, 1, "#8AA2A7", 35466, 41634, 42919, 35328, 41472, 42752, 1, "#A0AAAC", 41120, 43690, 44204, 40960, 43520, 44032, 1, "#A6BACC", 42662, 47802, 52428, 42496, 47616, 52224, 1, "#FDFDFD", 65021, 65021, 65021, 64768, 64768, 64768, 1, "#94A7AD", 38036, 42919, 44461, 37888, 42752, 44288, 1, "#FBFBFB", 64507, 64507, 64507, 64256, 64256, 64256, 1, "#F9F9F9", 63993, 63993, 63993, 63744, 63744, 63744, 1, "gray97", 63479, 63479, 63479, 63479, 63479, 63479, 1, "white smoke", 62965, 62965, 62965, 62965, 62965, 62965, 1, "#F3F3F3", 62451, 62451, 62451, 62208, 62208, 62208, 1, "#F1F1F1", 61937, 61937, 61937, 61696, 61696, 61696, 1, "#EFEFEF", 61423, 61423, 61423, 61184, 61184, 61184, 1, "gray93", 60909, 60909, 60909, 60909, 60909, 60909, 1, "gray92", 60395, 60395, 60395, 60395, 60395, 60395, 1, "#E9E9E9", 59881, 59881, 59881, 59648, 59648, 59648, 1, "#E7E7E7", 59367, 59367, 59367, 59136, 59136, 59136, 1, "gray90", 58853, 58853, 58853, 58853, 58853, 58853, 1, "#939F9B", 37779, 40863, 39835, 37632, 40704, 39680, 1, "#E1E1E1", 57825, 57825, 57825, 57600, 57600, 57600, 1, "#DFDFDF", 57311, 57311, 57311, 57088, 57088, 57088, 1, "#DDDDDD", 56797, 56797, 56797, 56576, 56576, 56576, 1, "#B5B8B9", 46517, 47288, 47545, 46336, 47104, 47360, 1, "gray86", 56283, 56283, 56283, 56283, 56283, 56283, 1, "gray85", 55769, 55769, 55769, 55769, 55769, 55769, 1, "#D7D7D7", 55255, 55255, 55255, 55040, 55040, 55040, 1, "#D5D5D5", 54741, 54741, 54741, 54528, 54528, 54528, 1, "light grey", 54227, 54227, 54227, 54227, 54227, 54227, 1, "gray82", 53713, 53713, 53713, 53713, 53713, 53713, 1, "gray81", 53199, 53199, 53199, 53199, 53199, 53199, 1, "#CDCDCD", 52685, 52685, 52685, 52480, 52480, 52480, 1, "gray79", 51657, 51657, 51657, 51657, 51657, 51657, 1, "gray78", 51143, 51143, 51143, 51143, 51143, 51143, 1, "#C5C5C5", 50629, 50629, 50629, 50432, 50432, 50432, 1, "#91A4A9", 37265, 42148, 43433, 37120, 41984, 43264, 1, "#C3C3C3", 50115, 50115, 50115, 49920, 49920, 49920, 1, "#C1C1C1", 49601, 49601, 49601, 49408, 49408, 49408, 1, "gray75", 49087, 49087, 49087, 49087, 49087, 49087, 1, "gray74", 48573, 48573, 48573, 48573, 48573, 48573, 1, "#BBBBBB", 48059, 48059, 48059, 47872, 47872, 47872, 1, "#B9B9B9", 47545, 47545, 47545, 47360, 47360, 47360, 1, "#B7B7B7", 47031, 47031, 47031, 46848, 46848, 46848, 1, "gray71", 46517, 46517, 46517, 46517, 46517, 46517, 1, "gray70", 46003, 46003, 46003, 46003, 46003, 46003, 1 ]). script_frac("0.6"). fg_bg_colors('white','white'). dont_reencode("FFDingbests:ZapfDingbats"). page(1,"",1,''). box('#7C99B5','',138,68,350,156,1,1,1,47,0,0,0,0,0,'1',0,[ ]). text('black',228,20,2,2,1,52,30,4,12,3,0,0,0,0,2,52,30,0,0,"",0,0,0,0,32,'',[ minilines(52,30,0,0,2,0,0,[ mini_line(44,12,3,0,0,0,[ str_block(0,44,12,3,0,0,0,0,0,[ str_seg('black','Helvetica-Bold',1,69120,44,12,3,0,0,0,0,0,0,0, "Current")]) ]), mini_line(52,12,3,0,0,0,[ str_block(0,52,12,3,0,-1,0,0,0,[ str_seg('black','Helvetica-Bold',1,69120,52,12,3,0,-1,0,0,0,0,0, "turn rate")]) ]) ])]). text('black',252,180,2,2,1,78,30,10,12,3,0,0,0,0,2,78,30,0,0,"",0,0,0,0,192,'',[ minilines(78,30,0,0,2,0,0,[ mini_line(58,12,3,0,0,0,[ str_block(0,58,12,3,0,0,0,0,0,[ str_seg('black','Helvetica-Bold',1,69120,58,12,3,0,0,0,0,0,0,0, "AW target")]) ]), mini_line(78,12,3,0,0,0,[ str_block(0,78,12,3,0,-1,0,0,0,[ str_seg('black','Helvetica-Bold',1,69120,78,12,3,0,-1,0,0,0,0,0, "turn rate 3 /s")]) ]) ])]). poly('white','',2,[ 172,116,316,116],0,1,1,26,0,0,0,0,0,0,0,'1',0,0, "0","",[ 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ ]). poly('white','',2,[ 172,108,172,116],0,1,1,28,0,0,0,0,0,0,0,'1',0,0, "0","",[ 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ ]). poly('white','',2,[ 208,108,208,116],0,1,1,29,0,0,0,0,0,0,0,'1',0,0, "0","",[ 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ ]). poly('white','',2,[ 244,108,244,116],0,1,1,30,0,0,0,0,0,0,0,'1',0,0, "0","",[ 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ ]). poly('white','',2,[ 280,108,280,116],0,1,1,31,0,0,0,0,0,0,0,'1',0,0, "0","",[ 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ ]). poly('white','',2,[ 316,108,316,116],0,1,1,32,0,0,0,0,0,0,0,'1',0,0, "0","",[ 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ ]). poly('white','',4,[ 261,111,256,104,276,104,271,111],0,1,1,34,0,0,0,0,0,0,0,'1',0,0, "0","",[ 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ ]). oval('white','',311,111,321,121,0,1,1,35,0,0,0,0,0,'1',0,[ ]). text('black',237,192,1,0,1,5,11,62,9,2,0,0,0,0,2,5,11,0,0,"",0,0,0,0,201,'',[ minilines(5,11,0,0,0,0,0,[ mini_line(5,9,2,0,0,0,[ str_block(0,5,9,2,0,-1,0,0,0,[ str_seg('black','Helvetica-Bold',1,46080,5,9,2,0,-1,0,0,0,0,0, "o")]) ]) ])]). poly('black','',2,[ 232,24,232,48],0,1,1,73,0,0,0,0,0,0,0,'1',0,0, "0","",[ 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ ]). poly('black','',2,[ 256,208,256,184],0,1,1,74,0,0,0,0,0,0,0,'1',0,0, "0","",[ 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ ]). poly('black','',4,[ 256,196,288,192,316,164,316,124],1,1,1,75,1,0,0,0,0,0,0,'1',0,0, "6","",[ 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ ]). poly('black','',4,[ 232,36,268,44,280,76,272,100],1,1,1,78,1,0,0,0,0,0,0,'1',0,0, "6","",[ 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ ]). poly('white','',2,[ 244,118,244,126],0,1,1,105,0,0,0,0,0,0,0,'1',0,0, "0","",[ 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ ]). poly('white','',3,[ 171,130,175,120,179,130],0,1,1,106,0,0,0,0,0,0,0,'1',1,0, "0","",[ 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ ]). poly('white','',2,[ 172,127,178,127],0,1,1,126,0,0,0,0,0,0,0,'1',1,0, "0","",[ 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ ]). poly('white','',6,[ 190,123,187,120,183,121,182,126,184,130,190,129],0,1,1,128,0,0,0,0,0,0,0,'1',1,0, "00","",[ 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ ]). acm-6.0_20200416/doc/manual/acmtcl-drones.png0000644000000000000000000002257113175033707017073 0ustar rootrootPNG  IHDRpx IDATx}X\/ں/m A}2jkCE-$1ƔmilT65Z [bi14#+G."gܠr?h휷 y㍿Kfq\^\ %/"@5m 9t5~%p釖=oE\|™B7p+~>h./?'`K0 OSwғw⓵mؽ˩?UP2yg8*9׳oCwġ[-qq7eJ߭]dABgwa﹘? ?˛o{>x/9LgcJ~[Ɠ)|>Yoſ<;oUH+,r' poϷC@dÎ%x?^|l~-R/#iUo97^ϿB߈-yVƓ @w%q#\WXpkk앷}7^};8@6\,WT+CY|W/l[O+$9cz圸3xI9_zzs9{=9o¼esh盿xE25+&ep>=Yn q5_K=v+;WQse_>KaLbx˫ʼuĒ|2x .V\qk*GdQ>5k>@ `.\ozǿGj aO&JwaUs{#k|#\O՞SϞb8*~u]p.0V*[_|{/*՞>>@ΐfQ~*Q8CF'8 xo[qĽ&^uc:[s 1|"%{>r꺟Õ[C9w9qq 0 W0󣿝#.$~eS9y׎%/ P k?8M\!x_xeR/o,FC^^Mu[^##>I&6/1%ǟo;h_#pՒ2]9{ 3\6e)o𗿼;el楱?;."I7x?~r ŸSjї/šHNҜW^+ڷک;-߉8IE熪/R}M%~DYӫs ϯZ/wp{!z-/GFuL9cెC({~7\?q=@ݴ?˿;Ώ'"οiMxוe^wuL/tKWNQ 's<=#Lgytg͆Gdxc}$E)%?ܛ>^BEsob<?~x7 듾ooPw0pj!江GVQHͷ_7w` m d1#]䶮#k_*a2hlo,gGc6<7-S}\5q^i+UvUu{__I[mONjɧ0o-y YCJܐs%d2K Ν}2"}Q/#;}wӧ/R/G=忀ȑ#Ӛ3Qˬ|G쁏iHtƇ̡oӧY0ٟ3]NLC("3wDfJNNμ?(E[zED =[6VDř 2lX$;;{Qkuu m_=wO7aP?/S_,Ζjtww/u5lNf:EbHH })"(EDF&66R,}Wi@( ZzkM'5>YTVK$;i4Ʊ)n5Ԛ)x?T 0f^uo#h?Py\W_-h9Okk\weiXb{ŸSe*%NK8eaׁc/$m&oָ I.\OoM-~]"\k;BȢxp$Zƭ{VCd),e)*DZ']K/c4lwtΚFYMm`ד0 ngв&ԩ+~Zz^7k7ԡoQӰm NcqZl;rz{R?NLNTH1v@U[U@Xg>{'|5ǁL=]i$b|@tr0TLKAپ iۄ~#lytlƥLja Qq 302`xin ikI ;ۄDώw8E+V  -7,y1 ψ2bcl7 5n ]@fv!Tg}MU`9?dCKMm݀'|MUĸ1V)U{Nj,u?0T1er+vVj4>bșC(ưMfRs],Nq!3CЍ32neZ9rzh&!6^~;ߌng4YN寎|gK̽)lk!cL|N@:YtM.,C; 2Ĵ=lڂuꭩwqFŃuG 8P:ekᙱ\B|uMwwNvLas =C 3>o})u Ւڝ}ۧou8J8, ?@~0W;>& WjKfe1)%# JDD.""s)BzF<=p\?999 fҺh;\=}1?4u+,J32_4."(ED""\DD""\DD""Q\DD""Q\DD"" pQ\DD"" pQ\DD."" pQ(EDD."" pQ,I D"[r*arrr.U\dx1U,8BQ\DD"" n̚F 6~֭4ED>V`r_͖Xdu:66ᚉjIjM7G˔EiFL~>tAFVmޓ%{i@eۛpe` e;:S]z+$fcJ}BrT]Pc-pܫdTz~.*8`h*2}'4,k`iZaO)5pF:}7Qߘu_EYp 'S[^JwZްa |*OSn1{ޡT"ug5:aӖRI ra砃u4Ǵ!536>|RHn,9͈̥[{ct g.Bd!2Pf~.z{ik#(6Ve;`8y)yo.ٰsuD42oagd` Dƻ$Y3< @b[)~_AڄD;a+#א|Q̤ h_,lupQ\ARIqoY3:3bgb杂/LI'Fyq-?Q7IAW_amLYWظ p5Γ/~E=r0>p[Fyl+K\dd`h+KPDD."" pE&?l"d\DD""Q\DD"" pQ\DD"" pQ\DD."" pQ\DD."" pQ(EDD."" pQ(EDD."" p(EDD."(EDD."(ED""(ED""nlc.jy fc]6M@sҀi[Fq;,YVBO9WL%O ֏AJ}핧)FWO')EfD^06_mytloTPmՄmE [&0`8{!gija FsѰe;Έu6E`}.yv_>h 7PuCZFXiv0T_Hs|?5[ֱu!B(/4D=:K".1JUu"-4L7=.NYl~VֺzwT[7|2@?$8u)Zi +dM@ydfROuF:ݧTe3&ˎt2C6G*sd&V"sGUaieCAˈujjI9J0pY4T|fena =;sBrKFue G:Hi5'{!%;;{h{tA2J:C/t,saVʚH93.k!y1[Bf{z!P4cN)ucza :,eoVϩ՘gM>tuCR{ϚtxˏPfKbj 14e,+mTLԅ7(cjrs6BLOP2Է]:kQҏ2{H-%x;oJ4R黝aw{{ܑH)|{H-H6r='Su#lsƇYo;MQVE@8q@M)+=mPӭ I"R<z ťmS躬0U®Fێgx񯛍Pu^↜g\ʼngSm,-ݭY"" pQ\Dd:WU 򕫖vP]ڡ pnHC("" pQ\DD>_jbB12" O{jG>-c4m(Ƨ̷p_+l^_غct },H 6BoCڶ3S'hɂhZ`hGz녞XT=^y>kOw3/C4^@X0AAC}<noeP424>[3@oM2$*}=cPur? nn١:c11/#aي 'gk*׻6y?3g13hpq\m`z.瘹t ŃUb,%q?E[&< \1n "#bzh6<$\b # 4?`x54<l+ WctPA25TkJLfR}`)8Nqv:5ޫM # v %9}Rk4D!4dz<|U Yxx54C'+k &v?-2CܬLE< ~֭m[NS#hOhk-+ϣ14'|n`? 0n$BAR qZCO+4߹moht.3,s%gq]eZ="]]mSD6XZNNΜoAow+̣8If[ߕ\uCzrmE􌱡4 P KڔNbͿ\=8/p՜k=-HH_"XA~*d3}៌z:qmmE+ji =u?I!{D4W}K*2}=4>4MDDC(T®Nօ2;MDD>̥*}RQ\CE&1T#4IDATN* (EDD."" p(EDD."(EDD."(ED""(ED""\DD""\DD""Q\DD"" pQ\DD"" pQ\DD."" pQ\DD."" pQ(EDd;w3._J7rrr%-j/ZTs`90pT%Mj/9sF<'C'߅y"Q\DD"" pQ(we4R16jWajc*ո?oY4Imjoǹ|%- 9r^ iyR1d9m`͆Csqhwp4~v:jS39N&\ E|fh]\ZM+ijC*2}ZT¶"e襩MͰtrN}=4՘yM >%F: ۽ZMXfv!p0F3uKCsf ?Ƨ7Ԍi]+5zdN:φ6K6o\-On"r:(tnc.pA1xPԏ>KvS v&潋F߅"K߄t6W6&^W;j}0(]ɜhbb@Il&,Kc.x^v޹]RYW|^Ww[vۀdo5ܭW^\tG%5yyoR6{*Q:0kc;S[P s5Iqm 주Os۟qCNoRG)8/_(*l4.o o-Z)["r1?X4Zlw>ܑ>~}p,dw3]4^溺d*WqM;mR^?t 9,_*/lQ\DD"" pQ\DD."" pQ\Dd9n&DD3n=9zNIENDB`acm-6.0_20200416/doc/manual/acmdoc_html_hsi-ils.png0000644000000000000000000000767010666003515020241 0ustar rootrootPNG  IHDRv="IDATx;v9E8HfY/i 96=5F $ }UË uJx P `HiP_n|/PՃǿ>2/_:w+@1J__aad" %Pqt8NNZW0$70 aMpŀl4(>La(< E4M+ %s:[bqF ut@7sPjHkNYX {5-]kس_|5|!XHc=ygR,#BY|vTQ;i#OMY//ݪ%[/ƩS̋&AXw /mMƩ= Q݁/lp1#%M > =bT?wHVը)Qf:C~<5b7:J-/m#L8)8LrG ҤYLLV2𲢣֞sY;C1@)(a# PJ-&%S%2<ܞ_~ԱuT.qw5ŀat Bfz{KT c ܀`뱕hˇeО_́6_D$ς}YIiaҖJf|o_T,e[Դn@4A(QjM[ vv;"U~V>Wet(̪mHY5;$Ry98YAV2P/WV;q&ֵZםo[_39۝/|Xrq7ńkd}\cRb2 X,>a J, xԷ@ZX^j_2󡋄QRAـ"+Nl R/Qc4P) U;}%=KIzg>^ɢ_.G M(#>,u6}fc[~>g$e"J˜:"Zb_|"J cJ^ ӊ|{r35S1{<bjlQp5X$I8"3YIyǪ3-34JYu>4+uDQ,ׄ6cI?+Ul鈉" @G8Mm5 YguQ!`D@%X(I2hTy%CLxoWZGI馔%p=N4X9q׷μaİtव7*!Qʓ6(Nzp*RMRLESu$'X-o=CA0ڬQB)ID0Qs>b8kσRV 5:L8wv۶?t2 C |6$p@ŀͦE}6j?/(Y9ۙJ~MP//egw[㲌dION@~Nq(PjL( &Ҫg b%spҺo9"U^,miT3v6X`)lAPLtiLA 0kdi9 $R!ZRy_rJV;R|R{kr8[ $j֪4Y|a~!r$sL)a2[OqMs4}Y0vĠcKIۘhnbCcqpɔK2_rYk!fb|RoK2AY%Y$8we'Q-P5(Π~"#9"b|#~;T뾑˫ψ$)۹?|fA!3GG a {-sbO~&MJK]]isLb.i#||2:dɪ]p21y̱f-VrYFOlm!ZT1] O<9zzʓࢆbXe&R~jt(Yf[3뚎5 |smn\D[@!' ŀ֣vf'of(p9Xc (PȶضrP f^K=EG[Kev_3JrJ ՜_OF0(mR_P $/AD 3pQ̏LB ?wCǾ`ϦSQz)kV 5iy5o_,HYg +^IZ4˖=adS42*X:JhڬPwGn:PG WA #tFҍe2@v}ݠL+[b8<(/PP 5mpB^,{@]HUYUA1[iݶ?ܶm{vmO'4MT /1 $颛2Ӎ1vB4ki1Q KM Z1?HSP13 o&mkhx j!AM ۋBb`X"Ho4;X _vHYaˌ`'D-+"veC,vlп-[>l5 EB_!D淪oNN=܊/쵸#BX /}מW7>V~;}~?lN}?7<#]B`/XSVo9Rx?_G/7?^l~1|׿_,} н{/}o|[3:\|[Mc|׾xcs;?aOYg4H"-k?i!P?/.~M~𖷿Wg'x߲`}kWӼ_y=\z -䗛i;6;~SQj xO>탟 jwc>M/3=+_#C[x˯@GRimps+ǯfU;Q~c?Å/ @|Ƒ_;^J|gR HMtOl$IQʘ峟6fDrT6]Hb3\)%裼oC~# _^-GoL ozKG< k;ÿ@/[m;쏟o9s/{8^kз{m<ooeG̯񷮬מ/NA?WOG>`ٵ?Ƙ"CsQ|x'v ;9wviFΏ_ȗLh#>q,x!~#e%{ !¥i8 _|< :w~ȧGO<Χ y_9;^]:ɽ:/?j`᭘'?_ife>rЧ~]3f9~seһ/@f}ćs{y7?~H|iBsKES=M};ݟe^M XƨzwQ?}>Or_< | +|zf9?rq$s6Tk9+;b绾 HxOfK_{H{gqk9W<+6=`%z7fLlبL@NNκo;~!XHO*~yBXL"ĆW }mV2vVm5''Cm>_+"N{eRϭ&k嫹-с_![]B B B B$JzU !~OAϟnbt<]K: ckTZrai˳^}4hq.l_=5m6k0tr:p/5LUnу\O'җ\|&#x+5jtq  n;R_,e']8?BspTJd_[a= Q\ :4EE[ >;n6F3S[Oاa텴iI ~࿧O7[z~Wpl_pQ?g  K}|܅LźAb<Oa/  LsS|CZ Od˒S"~z E@&f,\d%Nvö)pP!g'`tMݩ:03;)FOD?߆)R/Bjeb6pu8W*8uΟ\FqnLZH1+YA~SXn*'NP?Pԓq>5#`4'{8p"$h#i)<E,;7Ci^Nw:n?ZFUKixaUNL`O,`|̦ͪ>蹌 >;k :┷grQΈDOݱzӎp0y~k=c!nn50 mv&В˨ R'_i"顡{ȠG]iO}PjND&ϯ ?3܈u` YnǛX?w]Tp|5c[NdlN;qKOSyN?KeeS\y='Yf I Hi1}+k^MA?g?nBl6Y+_:tO>C~AߌTU9aX1Lڋ ~ O?=\\mN,&'3+ ];:\NX$hG(7~$?&NltBr!ĒmLl:~!%p˩2B?FETzX0m$_TOzZ__C+bcEP_!$B!$B!$B!$B!$B!$B!$B!$B!$B!$B!$B!$B!$B!B!B!B!B!B!B!B!B!B!BR!ɞ}^NNQJ;}מUcJ!"~ڌpG $j DyyAl9^}U5&@!PĿPZЂs \d:N!`_yn ]-623poVx > ? Y%ԥ68Uł%`hY~WQќq|b OeM4c71_fOfOf5UNX;cM 9~f[!'E6S=al?2zBREZxժ=8~Ժmo?Md!ߓP4nN BnpM&MvCTSS}ӁBq_ '5M8JIB8s>ߡ ,LnNUsv5 mn_̬"s> 凸icWjy(})#oZPEAd/bea="F׿bM[fvipmc\ln#ӿ.b_ 9궧ctS7Pǁ6{ٙg4(deSi06BoZ OJNST; I$3;1XSQ6NU4"A='d> zǩZ~#J"۠oV3ݗ|945:ˏF:&v5yz;c(|9yxZ{sTnܴ*[ґR#䫵j<`;hy?j`94mGj6W5q5l}GT+T73SW9>5N5b3/,asƙB@Id!³3n ŴOO UxWϺ [`A^Gh]MjjoY>\2VZg5jwy(nȳеNʏuv5jv[n-RNG޼_ir)7\e~ߘ= Zmqn=,w~V·P\X5qlXVkZ3Iuq"KG)'=9Aswg?c4WoG+WwW9>2[Ëز!RK>v}gec_ jD*_geS<3ƺF334m6*܆MѺ}#בZ5 yVF*º jAUnI0tNULXg$'rs=W,}/f?jlGiEV>v.R@0V}ʗˏ"xz(8o!Ꮭ j w= x]V&JKбeٷFǺ S e\=~*Ӆ׼Alթ>Vq|̶T:Zq.V' K> n ̋\Nm/C: o Z9|NݳocTOrڎ`y1h:ۋ͈tx{,nQL`u/Y=62O0 ׎.L ,}6qulo׋W_}Gy$eㄿ=dzz<=7 t<]{t3l:Z0KI|D;VuloTrW𥠠@BH֬AlYy5_лr%BmDNNA/Nˍ^(~!~!~!~!~!~!~!~!~!~!~!~!~! ! ! ! ! !蝻B= >b BD;/Nߵg7TBm"~l_F[ (//W#-ǫTBl36{z(c | `tmz0A ]B"]ǚ4>p/V:@'q$`n#3 jmVf5Fx1GWg?!U`-4=ìn󉃻Llsǭ<`)}BV0V,a?p(8lk{ -_<ܘ,ph=)ɛ6==5Pf+NmTfCc:Ɖ g6u QzS^^/^ {S3eb|*H0ca+S^V\q8A_(iUuc^zK׃ii)$M$]/꽟 ӁBjsQ]e5`kݜ-|H) 0U(` L4tS7O=Y>&hZ\N;Fd?;p98O_۶[i*0 "2O`1 0s<.Ň28pHam}Tٛ#YgkyF i|3 lý rZ]abWm_,4^UXOwTdFuD51eԭ"fh9CF Q4ZX7|FmrӖD9^ќR[¿)(.?A.ቨ3g c#vh4d/;4Tr639ξzf4kʦ7Ӟ0e&fϭg\a/.߈^ǫH6dZ]W y+$b[ƍY桠jA=Y~vS Qzsq "̇A8UX v>t,F:&v5yz;c(|9yxZMn|oG^H=^\(ә M=S;NB6kQo :}rX2t{#@ڣ&},eϠ,ͮ8`֔4L\fsّP[Rk(qw^c0Nc|Q7Gm?/]$߈::еNʏ-c`I{LE{vPԓ d0Q0ѧb!q ݨ,V7ubi`оAHO~p}c;Zgq^zK׋4(|޴#Lw/ž#B;Mw)f 3eTHoe;in7ξ.<=<<`&oQxf'^uRy!w 3^c\ {}~vFHڜS#2h>BfV[:#B|]Vu$VDcM7CSN#顣R$拫YOL:E[Szd(؝9ǿ&& f~nuskDјu5W]~ub4¹*!~b?jA>ZPE5JdX9f=q,7#\a| GG}q[ٸlȪ _X(5M={m_{8ydk/u~; ; 䦵T΃) IDATvY'> v Lv5s3A/.nWrvG:ژNǎxU+odSdZPΠ7H+%:5 lR-վѤuTbOU p||:`W*eDu r͒J&SWPOmhVEե^:hZ+LZ"utڎ[_zo,.ûgcq{a"🸶J _p혗uy .Iס , lv]UW_}Gy$e^ꉞ (;Qϵrm7_[]^Z [v]ծaK>s w!Durl~ N 9D`ob||}]ؔ۫]o &un$Ēw+((B/|KOL[GyD/ۍ\ B"999b;޷^&zBl3$B!B!B!B!B!B!B!B!B!BNmB/F&gfG! !5J|ib#Mƺ\ $ 9t gm!akLls+,`H-%$BlazzU C`,ju_!A5PI5'*K۔>jN'!`'J4ट3ty/g19$ߋz?c#ŮOe=Ab%l99Ț.p?Ź5LMN/WĿdf[}ӱӱ#o =dQVC`]]e4t|hqbq_Ci )'?vhQy K444$@b&y8[F  ZHmwr:p[i*%?AC~OstՀasE׽7ilOj]4>4TS/s8ۺ)՘ FmĨҲ&3Q!\1279r2E!YoW#dl3΍yI%)4 @a(.@;i߉Dul޴0kd Bz;{ kݜݝt)cxlJ.lKjs6#̖$<LLK!y~N&GA[(nwPeV&3n %ΫX Yjx:k70z*%x{#LH2<(h>eEu=>CIL"u"Ϗa*-'B'`fÃɽLxN˯W6qQ8$ J*I+'o.''Gm*6V^gf@ 8eLr> xM~ X8j34MOTTxMqe ό> f/ ~q&΢`%(3{dnɄ*>7 J ) \01'j_N/`i=il4-/i b|5z/?t q!Yb&ɷ`/*aq9=cgΏTVJ3MFߵgֳzb!B B B B͉^."蟟_mnY[ zB/B/B/B/B/B/B/B/B/B/B/B/B/~!~!5b1[D±<JoK~.Wrk&bC {,d~ }$K瘾DHs|Z҂i*uP; }"#'1E 9|.S^rԓB$R֘_gJK!Dv FM;Đ 6{6ӱ5I-9i &{ [Yb.˜>1'` I{V&AUveDlXbsֿ>4"m\&B¿pLNّI ̅#7J \8 񘠡v.nzM3Ruv+MMܽ73 i{qc  nL 3@dE@Q Y~nFdBj/&]N.MplHk[dP?PB;/p21L"ڏV?8p |٧X3/%5w&%[qgX^|(#S (9;YB OdicYP, gSo}Yfa7Ge07 'fLDj>2={sF<ܘ)4œ7y~w: $F (X#O9Chdf&t$.\:;\4δsNL3*1ɛ)VB! ! !62-, K&mw QX^-_Men4-3>C#XVS j>mr|ʋ;hTn`"}˧Z]W!էAw*+Xƍ߾`9ߝwg<[l.?o$Rw߈us,Ϸz8]qG\ 2$x}˟4vsj*.>.'^rBHW +U縗jLSrR ^ h݅=b]I%8_tKtR .ҎNDfBjZʛvݪ~ pO LܴeR]1Bl;.TvO-WcV.Ug4sKhەSmJXwa]Mڞ:WoeXy'׆r۶ +/ *Ե0Ue*x֫ܭWM:ZL``?Sȹckrx:/1GWY S}g%p e= ^>>Oݍ+#zM۩~||\FkS[O!$W1 ?(,"aиTr§)"hjK*h&X8UB¿ 9p"P;ԫi[=A!ѹG)4¿^Y^!?PG!$B!$B!$B!$B!$B!$B!$B!$B!$B!$B!$B!$B!$B!B!B!B!B!Byh#;w%m___ϋw^P !f~ᘶkoL <= :,9ʊxP>+\Tz0A";.p2qi{6sHnW M'H9'?{E-_X[}{ 4iN!6.>oXԋ ,SXII .oHPjo 6{:6{:sǚmtl7/$"nhb4?A坡kuFF {)kY4_P@:tl c=>6Lu.B#"<7)$ܠӁgs!P4TSbOal!/3stՀacٲf# kyVovӺE%opވ6"#WjSy{}Vg&Fɠ>`ß..B-,^w  A 0m;Mo)^\x"xƹ1YaFRi'o|Ĉ.f_2ż/nc|#ol޴0qfz,OH$JԜ~vBC~DI/3h/u6Mޱ^462wR#xfq6i&/~3n eX>K+;J!{5hk7ppşr_wHIYd2׮lⰳ)'#`r/;_dP2YrE[/5}(-6,ȁvfO}Ab&i3 &.zz(t21TLvFnvf]!+}1r)eݔƊ.BY臦)nwP-b*.(_z wMoO7A4j Oc+HidD^+53[mfmP ?|s3Mk 곢",.ûgcQ}מc~C!6o숿^=%qfC w!?z,BHBHBHBHBHBHBHBHBHBHBHBDgC?ڳKھ^vB,1m,x_{mWJb(a"]==LS^\V4؃NƱCm/]9W--=ܢ釾u{*[\ \Y8~~ޱ&lMBmϠgswŊfDO6mc?deSl~B¿,Ʉーtl^ >dK{n>5oat¤H ZpЗ͗`~!yY e&?mԿp/ǹ1YHES ,"c#VG JIdg]Kәkݜ-aִu\R" amIdw;wtj/$ؓP@H9v+MM1d/Jffq~0 bƧxbDTERi'o) -.?A!ԇwx"ͱzjxlsINTkr u;JeycN,_3hY̢ri b@ 47,юB¿Py0iРH3Pw];Ld$ưnAA/׿h#4vK ]h?$uBHx-4Ҍ|wM=$%[*c /1ܴ~:=Vg@;u !_64Tc-]x4jN#顣RHt~ّgeS<3u"X]+!> i\D'ހIR!"iG84+U~;e-znB&ߞwbO%2^^[C1͢B!|ԚInZ Mg,]eM8ڄLƧqbIVf-[O:V|KcM ZӁ` i[`DLQKp `YOL]HaJI(:ӿKӓ=Ja$Pi5 L"hQ}ـ^&'gsQ`|TPԁ}Q#kv$ QʦpM<=wLց] nϊH_5R8Mt5E6L{tL;ul2c`q9=[&eY˚7ӱoug-tڳ oW/exzU%zѿ 9nBli6! ! ! !؜bA¯Ax53+{IDAT.$:Acc"",k. !_!_!_!_!_!_!_!_!_!_!ĒyA-!ˡCj!>nȌI\IENDB`acm-6.0_20200416/doc/manual/acmdoc_al.png0000644000000000000000000000256110516705052016232 0ustar rootrootPNG  IHDR+PLTEٟ&IDATx1o#E psb/!DC$҉Eq D ] 㓋͹pj C9 QzsFn-2Îy<霍xxfGl p_#O$ MŌDtx@–?=*0)4%4q4`>f}8#"(OLi Qy{L7D^y)Ԛ_E嬱>#Z>!O[/ k=|[  ` vh8[`l C KR|aY/8ׁ1(3~z\w$7 O5mWt|BOM-pg/l5itE ;l\oo [PQ| $[Pl I D&8$ů-Hb)0(& zdu#]c 1p Ұ<,k*@Q [`yft b"wNq\ .G,K2Jo}"p6'-,[S@igIC@q6VGHG WV@@ -=Uu&{MH adhm@Z#%;B@Wٙ,n** AMo>D9¼+Ѐ~ճa qYc.ͰҳA J㖅m=l&@Wφ'U-@^3r*H@#X`ztꀪAU@B _oD@N2" &6+ ;~-"`MB,bI"vJT\{ oqPz/GVG |x3NG:$땝,GΜ {=Z=ۑ}=* v>_qF]4 'd?+|T E`縼ၙ$ohs05qгj[ ?zI3 @L']g ?U?P'@ 8w6Ïxe9_{Uj#lj5 L ?^yXOfJdIENDB`acm-6.0_20200416/doc/manual/acmdoc_html-aw.png0000644000000000000000000000162410644355520017211 0ustar rootrootPNG  IHDR%i PLTE| FIDATxˎ0PY!E~* Hdb+,/gѝ)WBB(-\MalqvِI ʎl`R "%2NHEiri\VIʁ1|Ob G6&٧0^Q!Xb 33JuT DeE9U8t$-s4dTS/ ϗlZXl@8rE< 4Zҙj+ 959fF}ҟeo gd<a61oD0c}I5xUe̝{(`)[5I]C_^+(Ae088AM>#+,7+%8X O!1pycwM3SJps0kW"1p.yb(KXXnE r릳+`K!tg(8;<ɔp*8ӡֽkI1 b7I8nG ^J?x䩑C0q!S>G339ZtZ5tN@ xՒ$Ztmy0,RԩCb:"JZ&pHEhӏ$25nt4(T^'y4e΋ Wp^)̿q4g|pqJ:p$(zg#C$f1}Ab`J3UVU>F,SM59n_`Ώz;+Wy1`Beb{bI2Yb΢/]ene̦(6Bo/ ĀuGF:nH*Xhx_߷DH ls {K^la<&Ab1כ&j΅t/L+sdBӫsl*#r@~_ 10pXc(H^+Ew`Ze7N 1xRrZF~N;IhF˼o;.ɰر#LSy[BM4Jp Ӻ4cx"0R׀S<,֩۬@\6ԗuNuos MS TEs6hI VGS}='A ij[靈0齡M y ["{ - WC!T=?zc Tճ 0F*TZX޼=1D~q$UWJz"UROd#KBWbaԗ]q&8P.DS!PzA5#ҽK1Z4L%„c|8\2̋G+ܕʌQ=;.{E{3Ȋdd Q˃W7@Y(8fSys11xкAe5GH pLȗq&I|􈞐dIޫ2 [o ^/{#:; UDҳZ_z syCdUVbޤ,ز0R5ษ@_HO`aH 1p[x/y1,(.P)WY͍ R*'NW3~ԵLk$@.rho(\"199~MHa Qeqd9|&!ǟ hjQl.,]M߳FnEU87I#u،z\+V l2j+IѺ.>Bn0˛08:܊22eũ6(Pʪ!_{ӽC|c{vly@h:jb@IJmֽϽ O@b`mcOZ^n|!1tR0gzIDcOYn2Nua RqYnZzh~«}*d[4d34!Qdn=J".y~>=:n=ݹ@y`AΐCbV[~cW^rݥێPzl;ՠ7SV/znmXאDCd|.%RpK`ms, * c%&VUG:O̖s8lXGL$Ӿ.&XZ[Eji}(Zc_1,w2\(8[vE)]dU21TD;z"T:0T^X]w:^FΊY0XJbb#~nZu0kĿ420c~GMY _mn#֛NoDIAbV"_$@'W*yIgUbρI}]RuJLTfZ\G)މ& o +f4Y>%tFq}Y!H$FƬ79k>B_PAIJ$-"WHf-;5uA.,BT/­.11)8[mYfѐ\Fb$fP09$RaDb&ӗL$S>)m8̜MI:;+v< |ͪ㏂ ]5By;LwbZS|6EtKc"1`wҪO IPcFgn WJL8"e[eHϑ.җO*vP2+&zaNLsELkz;3vټ̏٫u^kwqYMkaQPD^Iq"E0 ԴvwY귍QKьKs՚DF%z1(rWY.FR%㮲e3*18j$6`e| %4'5 *3Le_[5rVm*%1E ,t G|x3/S'7R0E'p_R.A3cwHHu"y pI°qܣ;AJ^n;Q0gVSH PWFbp",BbZ:@bf61C;lAb$$$,apL5LY4TIENDB`acm-6.0_20200416/doc/manual/acmdoc_html_bank.gif0000644000000000000000000000152610374531732017562 0ustar rootrootGIF87aM,MLڋ޼A&ʶ~~ DL*LhJ+Fj ąF봛Mzr.7(XRV8Ȃ' YiA i)uZhC*zZgZJ*9:X+;yR< '<جhM=x-͌0ͷaN~=~}N?:_掟~P$@€G ‡Ơ2%$\h[CC#b#Fy%;R-2ON7дFBH;$ P͢rڔiM*k08('X2Efv Rqԅi[<ʜ[pDWla|θ1 &xh㭛ffٹ篒Gl88vb*ӔivnHu˕85j}]<-k77t[99s{! ?o8zKY5xIW^V߷yE``>aDHa>n!ubf#b&ډ*8,#Hc6ވc:c>dBIdFd;d: #NN)3JIe9^Ge_7IfMn&uoir҉'rqZgkryn9 zih/6.(|iJV_")~z(Jj? (%Κ㭐룝"k4R8k겊:blT֤jm nͷ{ .5Ңmn oX;acm-6.0_20200416/doc/manual/acmdoc_html-an_approach.png0000644000000000000000000000162610644355520021057 0ustar rootrootPNG  IHDRJPLTEٟKIDATxn0pO;pAcaW$A8vh o}q3CXVu#4KHD+ Z%N4EaC- y#mqiG8^v_Ⱥ؋x7kD?Bƴ3tcwk\WOpzmqG(z؋ QSL$b0$J!$o)E62fWTJ y `ęȉO% ے:0Țtb,&Le$%%l --}bQtH{yR?#j,[rp&FS0 `Tn#Zt=;hAN\xfp*3Z (=B @8_cQǟَE y yw&ɦש$(A ,^A{ }3 Vz1! &ʍ:_GT վ &j)>ԁ $`ӒR~P]hPQt r1C= wJKc`&Nt4<-Oiln:Yvc"u Y]Ve!ސ: QTGuep"9EiXYK(EDžs0$*ȃ8FY:.!?'> #]( $n$\PTሻ&i Ӈ ZƄI:C0 SJsSYiv*Sx;shp.@}rBs R4b e6C\]fXWCQΤtZ>.m^Ipϊo`mk_b6nIENDB`acm-6.0_20200416/doc/manual/acmdoc_html-steer.svg0000644000000000000000000006402613345467201017745 0ustar rootroot image/svg+xml R r MinRadius Q MaxNWDef acm-6.0_20200416/doc/manual/acmdoc_html_scale.png0000644000000000000000000002300210753331133017740 0ustar rootrootPNG  IHDRFSPLTE{c}n,_yj[wf;\6GeO(OjP[wi]vaj{fw9W- 9U-̪r};Y2 xˆ%E3$?/3K* %l|  fvVoYTmWz#B0 @p|/H%|6 NkWLiUKiThwwRo^ɡpl~}hzt!G4S)qo= {; 9 7 op'I5QlY+HfPFdNNfBLd@OlZ_zm^zlryZvhyyc~tC_Dџ: Wq^ȍ,.N%8(LCaJer$+% ( $YufiyWsdfvD`Db}r_{omNhQk~.uVp\3s1YtbVr_EcAA]=^xjJhS\u^Sp_d~sQn]sa|p !gywn~l\C IDATx흋_SG[WW[AH#X]ek-Zle"7bAul-jHZkx5miX93y̜3_~&4.* <R艔0z"cHbs/: P 0jTxrU/H|o ?,Q&F= i{s+],_~ZDtn!\G|u_j'`Ij/!6bWc.Ja&w퍚+ ➡0yR!I0Zkk^|ʣ|*uz15XdFvf6L͑R_QHZ&:/Q?ui%-K4ި HkFz ^յ_"bT쑻0[BBeڇ{t:FKv8RPyƓyD?k 9zv~a G_]Ogatޮdo}n.9/OU~Ʒn{w72O5Re61!<8cY m,yXMo~bt>ۖ[a6AV0yBgPTu4 9F]Zyce֋э: yU(>,B,t>҅-7":1,0eV1/-˞ZRhՑK6.YDH:d1P)_#GaTt#]HpGK#m^Xv(bakz7U;;x1/PibЈՑ֯SLad W7J{Ŧ6$XtcT]DGb`,>Eߴ0bر(@0Ma? Pi n-=U45FkXpQ7&pT_#_Ҥ)10=g/Ha18bpvC1[m<9WDFbc(:xxœE!0c(Z(6R21h`ڢ4GўQҔ"` =Q-XYygy+wftkhy}G:`ʇ;e) ^rgHQQ$3=#_<h;3bMp0!TόQiJA\ܙ X@)j0!VLB,%-`tJ$:&Y3)F:4M)#1qsĪUb ,E1B ʝ=Eh\c Ь.4:0Νݟ/hcA%IV_H St160v8>2^૒M)FyatDDZP,a8HoE'l1OCn$"ΜI;{#*2XM)>"qeѾob0v">ƽ ֣øHxJ"?K9$&HTCoK1 #ʳѸnƖ"Fk},#T 5ut ?P#a _4:(=d~_:'F ,t;;WvԫRKb/vv:ω[r"`d|αQ{s;upc,9"JQ䘀" -,LR4;t2=9|]:^\RcOOMw*zS $bXÈ oZYF}AOwslQ7$}wa, V8d'F'9 DngG o0j}M"}w8'"X; F+m>q%Z:l W#e Q1A<*f??p7.}ݯh<91"_}-.ݭhK1VC?c9F]hh5Z-$X9N ~mߺdbѡ68 *|KtT_ /4)iSѫc\}mPS!^P 6|$aPMcBR$s"ğ lRpSswJr<*+ Ш/&WBk6=`m'ad78 !5](8`Hdțz=E(J ƻwNA!~'(0АF ~b8 n__ۡUX]]ܧ 1t"l`7&Z@3gw[w$0Q["O;xywۊ ?dh@I v%0Yg!ȦBpKF+qL NYަ7޽C~sɓ'uͰAPgHgc<ܫSXzSq  ʘfeh&g1uXDnWh쮃~X19"r,?W#g A uaK,Go0bEW `ݸym͛7O o_! xD5CC"ġM@x% "APwwӛ]ڰa_6pzdO@h cRpӚQʑq`#|?m''׮IF`wW(xuPteKG5kk=/M΢Zؙil ĻMUO?E)>vl OG&~ ŖDK5 xe -i !H9w!;/cȞѦ F?֌ztU'F_U30Pz 0{EĞ ke j70&8 b"*`H?ofgiFL!&"0zf2.b0/y(çvT3|fMU>y.xU{~TAsK{j. vnjnn:t)P"dpq񇿞o@lhhn7Z{e ?xR:˳[uю8|BiV y6,JZpд@ ǓPdMf=^ƻ-I,`Acpuhf"0݈6,( ŵ<~I)F8*ўQ#eh!gSS)B7~Zh~Mk*hDB=G ~UkhH7n|tAQǜ*Ҋ;R1m #t/be?6Β`ϒo}N!L+[g q\ -k#9QYD0Pls;o1{3 g/ʌ)w5pWs;8yq2.|޸pOTŷbW%grq%mLSs7B啱scTWJ\ VE _bkr27E(64TQ"̟kn~bM)[ʸWج-`L's3(6TAM@S/*@p{e2%o=VGS"4 ?g܏CyԮbA|A<~ !chDggA?"x "\A{/"_V`sr‚ژXEysb3YT5gy2FK9_VYACYc=}TiCm$G+fa=7Dg= OA<)=j`u4Ĩ@v磖査) gaEEԹeBS/we =< U!u ."*nNlz^͔hc_one!DdϤHJkQ ˲ < y3!q7ZR@KbEFb #}W6(,6ϸΞY:h^Ob,e/PuF"pcUQUU(pUe,7 D<΢mr wIY,yjEqS+WL0lU9mL q ilG]6 r>|, V_ķR#T(m:*(B6 Q%4NI 1[Đ*.TQO1v -ۋU{>!\(+"gRކߓާs.m3L]L#V_TG:gIR}7N廕(gDP+JTqm h1ڨS":ħ* úovWVnL-*hêh9g-hϷjxcwVr&]+,WUQqQWt q+ϒ6UE01vzU'5F kߎhFh_Ñ0¼OmS0{W=yq)& cU$?]Rh݌ [iHmln7NpWO,FLO0U+8Q3HjLO"_طns<*49%I8ƭ_u ";w}czW*Y8oU zO0]ht! 5>bh4! ij+o+=T!NE_-o"@f;1*FܭO ϐMBU gJ8"'8U qAR1b":y9%GNqӫeMא=/)=4V!#J^@-#7Ez𘩢@7/<6#U<@ĭ=NG=5fV"= *weQ#ܲ 53Ax> /ݬdQ?1{rwXGͮ5hEf^VŴS)2{>uJ_ۢ[XQgdWhzcc1b@oj왏q E栯vUm}F>5-Qj(ىOo12DM09A?7yoFKȨw-dS1=7SŊF"%2q|*썳ki/ :mMo~2J%h{%&Saxb]MɼXHcU׳:0/A-SOqZc>/;Ze=?QT&ѵ 3MU $pL+UcA*N̠Ӡw~j lO ^ k㇫B^m"1Ȉё 9x~*++zQw cZÿ]TqqUDoD?N1SA&\yU.CUd$Yu&SW Qqb!m~xQ=_!J0 8Mo*{Ek mNE(P^>w>7f?A"SC1cӧVKir5xZw /n Qk䟖 Q&H Iu GQE1>X\]`}b-NIE^O`ܫ"‰sN%6Ȯm=A=ǯU1‘JcԢb0"@Ě xef+c:} {硿A#;\OF+&)F'Fz/xj$5"dc20e$a#ȆA}}M3&Eh̻{—G{I-f_?!G}߄tO s FBdp(8QC1{'{@.d )tZ)6¨6 rz[.iO 4Ҋst< cԹ`Xݫ/jKQ0bCzxZX.D Q :… HpO)yoRH>zuqx!2543jbr$Qm6ӆZ ),Kk[k_ڍQM»dd:T7nEA- kʤ5 S[]IDAT+C+ĘKF֘gfZQܘPd> :MQVL?he*<{ybyc: 1Nqna`]yj$`wQmYԜOōX6 c+d$\6 DH.)` jJvXmo IDATx}\\WSZ-3j ! ٴ*m MXh:"ɊҮi5MmVXR~bBxSL] aV}j1fgys==s&9B=j 66"Ehjj 8O=ZB*UB&WoxGũ%=` dM&E>&B^&oc8Os3cE?yy77wz}K*/E^{ko9Rs/3Df !\[޼Ǹ]-Ӣ|௽\{??#k*|v[GYBGxO[x$h >7;"^_׾Q3{^;}<~#|PVjwuek zv!yDz D۾ b~UoW/^ox՛̳Qz])wwo8g>x~ϸ? oÓ n85x-~kz2MNopG3H3bY؉ u @D|E^E83ïylͯMϦ۱O&J6q׆ot}Vh_<| M}[N\7ÛW­/ٛ>W+mz mc:=퍾=Q-܁ĖBqמG`4';NPz;i>1n>2.s~-r/l |x?s\<ޅ { \5w~;A}sx:ɋ.xm=R>i<|w7l27xAQQpx[sI'ViOp%&L~_p+J^Ksx=_K6PupVx_rRם|έYȢ_<. |%݋&L/g]ŗfp_!{5s>c0=?p+myWOx—8y`O٢ (WSr̛ӓ?^Kul:Y\KUpR='tkp \3lɿg^yeq^,ez#$C2yg Œk ~/y= a_0 !M|{r56SPgxǭ~ysӿ﯏~u5|諟CAW|"z{? z׿xn+{>xOqvO)o:}[x3|&^ǭ6*z5/mu1R\GnbmY 2o|>5y/2/%SXx}.?|v]xJds ޏC- 0N6iwּnrv9qB]2Xv*N-Koz;B֐}\ o5,i9p9(Qj9,9颔g V9 &p΀%eka(EPMӴeYFKaumG Fvʧp~OszB (Me\tS~# CZ@,҅RPDdH0&B$ST6Im!ӳC66{r::oˉ5C1W9q($]ڱ`dE/KH9rڊnvxΊP lN魟9 밵Mpq_XVg,{}Q~rrɅ45|WE3Qׇw1C|{fc!} 2gvNYO6ecw>~7jR8͋qx=M۰)͆'B!a!kcY]Ȱܘ.jy#P Lʩ 46 /}؎ 2'+ju͚5u%epY,\Dl\腇 Z,2q} H'$0 iTqkaEEJ7AA͡$c=*x;C;kVrH/ƶ_*t9id&[uyOY ph 2t8BI.xe^:EVrp_=2 ?_l!gLӺ3 =`-ϒ%kddk%l~\. ֱE$mV~oM>DX%(/qzh)3\6.(r <,>ep<7A` j5>$ OSQF>/VQc":[7.:z( )Z[co`$yoвsԕޅz&c}u$S !A.! ! ! !|%vPc#М4E74 _!dY97yxNFlj;!'fSR}SP:4Me-2u5PktSUXrt`tuFBXuBhv<Q\W9{`H4HC v TN<;ԜDZu NQciGK`7DC'9]g]!D/1[)  Ea6JSV'nwk6-e(M]7kiv!~x"3a7,'pCBC44,JU$Kopz}-?]arQ^[-ݳwt껩3<,˘R[O"/EG9uMBrXn}r0$.kf;뭗2 +Fٺ 7ҰTB Kϯmpx;)kaȕE.UtX;Ʌ[f}2M2~rel#3B+ۼ!Ij]w]j 3lj͉墙$BHWm5AIQFDkSSGn s/¡lv*`)GAs҅Y( `tT:i< r.bbr36m֒ d݁{>&^Ụ h-!HU$B!B!B!BtEA~,#(R'X-BB BD.֌!ȅ"p!po5!}y"D›(MKQ6!ܗiۭ{𤡜.b1`R,&L[`Z ɄT٣lB0 iǻb~B 333領lBHPK(;}ߜm(.(<Ps5]I[iqVs[ma2QR}PdNX9 Fi:MekR]'iB;A{ }ܖ(MerZ.O1zzMiȵs¯b`@ד{{ǻ= 鼜Eˉ H|iN-,ޥipQ,oB#{=?{TM呓M+<ӴCwxQSUs:vE#Ҋ@Tz 4*ht*,ՠ@d_qq1>B8r`6; XUv%q,[?EsA".T`ĕ.f88s@7Fa`׽vl]'iK؞$r\GOHrmya}}5ӡL=^PsxH hæ\ Ue./<CM c20Lϲ ET2` R v;-ca XN.'rN1o֢mz'Fa Yd}p =}ٴ \o}a9 cgEwtSg|`ȍdA#֧HO$wSgf PO9j2[R,lʩ[껩S!BY{~JʄtNܮjl۶-8", s\օBW:CG)ًnH333"qO\^ 9SsO B8&qnf;q[)1e"iS(1QgoF:_8|V;{  o5/.@sp閭~|w1F6c꫗g~kÅ2T`Blv?7ySFѯPs?wgP RѰTBnY-D. 8:ip-;5eDG-KY?Px-|16>] }:=ߗ|8#73sN߷eej}w\"(6'ps|[ǎk \D|#i]z'k@ n"JlQL.'lE_1'84cݰ?=rZ ) >/N!;Q"? θ1qHb|Mʮ#svn⽇9#@s^`! IDATeq1\h1{m,$ICx &#􍕳 oR}7c\C[/$@A7>^-/B}htYo5|7oj(ccb"Hgfa[4#_=9>v=\x9[qFמBdpsF:|gB"-=Sit9@ab1ç&qY qͬ_6z篃p}ogff-[g|p0HO/r#9>(7#̂%3;At>/,lcLre`/Z#?:Q%;s)gcNxa.&sak8wc|/;JSs𨝴`4Wqڥκ4veG>K[|׌w;DZ_sZ t5RȅOcXE!aB:~zzf"JD_H껂+걃 xR2bvTc߇[݁'j8p9b$w̓ѭ"'Ppb]GH;B?e9JD}pNmVG deG)$K0ć=4V&S`O$,/:*}F4>wD1|0y?28BYd &+zOԔS3 Prssa8,PsL,0qםuľ&/W$O$OdzGN<s>_TzS-gVslఇ{=ٿ+>۱z $竵W ǎ^YD:.cS jaYE!>xlZ8O 7m _w"ױkJHlŔs/Cq͛r!7%JO vk#a/}:oiOJElur`J=3 ƺٟ]c4 T`Vjp2ZƲF|oG`{ė{D~ODE9a+>3÷ddeJO|MҶ#*O)`QEu "IbvPc吨V.ԘҲT8}ceO@Gy%u99]<ҴA%h9ԁGO`sᆳT7`Z?:j0p9pI]UV]'JSZb^sa[+ÃtX撍@7 C݁u}Cˮ!p Sĕ(C``Ai`h57_ sO%j{okmE%35@N%3D}׎-8d["eQlv:.A嘃x`)w`y2}1Cvs]u7H6{ SPD3gt炷]CFF%2I l'V.;]V;kYoMLY <:ǩ`pK\ sD*+ Zlbz7_oу4"*W߈oƶ64.Y^ t@ao3V | [앭a3RYK柤@} {JW|[aۧ3.RVF.o,Ff 9ORoǺ}};|<'/9}H}j}:oC,Vx;u]Q|9M-܇X e {o1׷bׇ/}O?7zn j <19yl<g~_)|XW G13҅G_ͷ; "m闪`8ւ_|?O7 ߉q+^rOO߭g߃]k$^3z+ƿ^~¾s@f|s?_Wwɏ) @c?(-BaЪ;~_&P41Wx E}C1~xߎc[qCz^ѿz 80n_;WM"^Y]c7k1m.r@ .!wC28x.C\ ? >bo֋O-Ѳ[&VqVvG1>26ߍg?\ˈ5UGX#č~{X{ax?X |m-x,AEZ/]ӯ㋽:%}翎qwdOs/+./-_x5W-Q9#_?YF@d|yb &P$; o('P=Uh|ݨmlOtq=?_Ë^=)<şwe ߇Re(kI==/| @mq5:[g-A7g D!H\M`96i o>17+Q@~`x%>?g4O7wgG0!c7xl ^IaGKWm3>"4>hu o`qwpbF}/h\#W}Gd5S yD0O%?x(~X?:XLH@!<*ll}^Wg?~*Tgxewu\_Q{^N%~o?? P˰{OIC\?M@>}yyAh9ӘA.wn W|{nn?? ߟ|M]'1 X QP?8eP]|~<`-NнBX<~7T'Ϙgq zQ|Tw! isԨ="| eQ7k7b}5]|u~ /m3סjӋcƇtp>_CP'opu}츱c%o<| 'P{p&ZD _=g?Oͼp =ޣC~}@_?:w*f~0CB]1|=k(߾ ~o}/#0񧘹2WUWd 7}' xo끅O|@ous)Fy\\!xznKF~?n.q@+_:Wj}SsT]@}Z]עNMڿ|Q ~/}EL衷~$R:boE])7y?.? {^_U\;=) "b^>+cZbO t >a|0v|^#/<8q(;?}4ZoZ|PTz5iƱl?Fcc/#b7 qS?*R|Ã|{_ߊ=DM >4b) <řxCwoW Ƨŭ[t'#؏Ŏg/D4!8!1u#L/aMdZ~t DGT,Bv]ӡB<~Rc' #cV!$T%Q}҂cǎ%p:eU;N+}hiiSg/v/z~iXBa'%)jR(<% ;! ;! ;!$z&m |h$~؅*iJYv}vIwIq}Fb7Xp? 8c% v #@n,3vWg"zc/Ƣ)[rtet`|Y&1>ZWrd~`4( s:TkRH( R(i+DoH/P6!$qB-$z\I-Gr sCXrhBא+Ybr6<\etk Q%j{ٱ ;n=Ӷ!?'ӤA g]ذtެU{&q4]y`9Q(moI鳶 X<˯MjQ7@yGQ^2Ս`^JzAJήHt#^-Wt8.dB'՟g n9XD/VYf x1{>-ꗮv#]C@]qda>mn\ݖI/<m0e85y[>m}1w±EqsE6J)R |># ˒ނZR$!)F\+\XiT3lKN{@r3 u0CF%G&Mң'' HJt/(`Tʹ1gq'&H->gAThhQdU_؋MM^ 9aKuf{ FF ɳMja+!Gm_1Q+V㍨9me̢74)/dx_Go7% 4xrD]56#Tt<Mƅ:B\ʭze;sT9Eo> _my8sWkj+ˡM:NU5] { /S=di~ޫߥz.x8dxY^TAV/)sZ!йaqȄ>d#F^yLH-O#`Ba'RʨbJi½"+ߩrPRLJ,t%qTY@ wJy#Bv !N!N!N!N!N!vB!vB!vB!vB!vBBBBBBBBBBB*}4~#b !&It!lc257M;(^W|B8dB'ɂ"ʝ׃+-V ¾4:v^l5vۍ [εN'٬bv#uvmUlʭ,ڞ ;)*Jq.1`u8-rBJN1h4Ao4AotaQ 0#W~KO7OF{l7~]FRCWMc{z1ZPUU_ }u|ơ̈́o`XC_$"Ka~g?a Xϕ4798 qQi:xgAӁ;`T٬Cl3~brA|ʐqv>R% ŏӰ-v\P[#AN!t/Ͱͨ͒x`,+#eZ׾L8%?ecFq:IKSVp_ىbYqO}sss:^LH{e}bItϣu&q47^ђǖOF9ʭ-;KH/9V4nd"vMA8A/w-.;Up[D1s!rPLumnmɍҹ )_J|rnk͝pq 0K8d'P}W|RϋLi>VvGdq,FQBZjao4!B`s$WK˥ʵ܄T2e.SH!'t;BBBBBB(B(B(B(B(Ba'Ba'Ba'G}c=&gst/u"ؐ5g, zk،Bae}xTk4W#SV߲quge;2 YkQm\  0yvNBauͰ!t: kړCkkV,zak=tS&a{'^z4SFsAo4Iz1U m&By~ !`}R"ԢF99yT]sv] `LxJ4ҳ/z!ݢ2MOC0 1@P 8R׹ԊBAak qSe#,.[4ØT ܞ[CE)-AQF/S|\sH6| 645,Yh:(x#nBN8e 'pT@ZiSZeRPQ8!ӳ\I2*G[DF@5t!PKjmmw#iĺN !\'k7l[# @R ]A4t_8w0x8F Ø٨ !b#:Kjuqb,mJ254l,'zK!zҪt絨_m_i;BԑBCP)B Of!r$:&8Bu7'`BEi:i;MȦǭp# V}B}G״ Ki&$eH\R( kmBh3ow8s khհ W{rSnԟIOǧy'҇Y4 JT2a2 zB(B(B(B(GRp#NH:!wɚ![֭[4 !C1Ba'Ba'Ba'R¾FFW6}.[=V=*]m)}j[R!W .ø_#/ nǞ)ihW%\>`8_J#6 Gl=gS WNhٓB' gKzyG[Tl_q.0Aށ,q5vnJ+N+ɣKR <:Z e 9V왶\@wȖr^6Oquxc=) JbqAn+vF|g=cGW z@3m&L0aCH>ܼw`|$$_:!MGwa8-waC~s<}-QqȄ=yL=<\ẝFs7\&s?s2C IDAT7]ۓ*(6:{֨@<\IU^08 ]3bDlOzR>DBm!)P +'ZtP:nB5h{R0C!vB!vB!vB!vB!vBBBKD&z؂60֓שׂ%ٽ(`.D7Z'/:>Kpnu t,[wdaL\@gƟ%;s\i:f;!v='1>eh,$yivWÛH;)}teeTܫ I6PNOR=. Ȏ璧bA_PMaL,TV}vZPr/-q`nI%1ؿ&b;ʟyFJvXC_$";ӫ3ìm]UtاKw},ݛ.6yZXo4p&@Sy*vwܗӘ3n#ax"kgXUu>i*럆-fkf3C ׽v ٛ%#{a̎D7zsK浝lgbFS^N'Iiwy:GdqȄ;fc;Jel?~_}f0)o!y{DM:BQb4P `5Ae!Jlop m[Җ]"[`5ȼxΔO"Lff|\l|剄f OCB(56 q~=5 FUt25*eȼ=k||. aTP[ }b$t5uűkgj0;ItPAA|rJ$.zv.{,58fT$v܇mL ےW}YF4" П"ĕD=S;l "B豫7}4!QGBз;W|x,;n2bL&gK)C> $Y\q;$dיSuvV tk#Li6@M`Æ}y2"ɓF`nɂjh:0.Ͱ-㶔PB*CшV`5,쑅yV`nA:^hlx098&y~ O6@P`vZbKE.Mg 4ac=v vzb(ҹ.,J -e7RWHjNߧc!r-.9EH 8\.]r|`mM;HmӤ `Ol< [Zo=k!S^y4SٴqHQy^% [0*Hƴw,;u5t7!d;jt0D傶BXy<u4^˹\õ=TrGs%rܰF=qpg !{G5GЊyrA[C(xnhkrmvW fp)8h%BsinqH=XܥX|=qh+ )爹%7J+\"r_$"M/m/iP *v"vg3:+垄Gd2w#cMƯc'R !q:%d_),---yl]"lB1---?B)q=rR!;! ;!P !P !P !^%RA;EB*cw:9}BH;D!SBBBBhaX z zk6[Ft]2fg)GvVj60b,ZG^vn.ϤJ{[$dj#z2)NT/Y:FP`:!i7pU,[P xڢv70AP`um2{쬭IJ #up^K<ұ1$8J38bTLH2+}2iv$.}udsq ؁xTqF@I;5}.4{45;8j`Ui;OUdzVKM4.;fs3lXC(Z\{-df$/O[S :0,c=\%$1ퟆmāb{YHں܊}2)=HD=*ꠋUFzY#رP%`‰㡕6W=[՜ƬI]) ^ʣ9V4n"'X2;dK9+}2橬+YC)dj[g\r"cqbq;؉aZq wK )Qca/9J" 8f)=sEO,C6Jwdmde{yK;AaЃ2ÊSwowC4Ji&Ǯڪ )qe>WC59} .i9{tl&bjt_c 04$ \1# Hǽ9dLq'myEiO>VަzbmDMSOB`\B)s7G\J B(B1 TT[S)t#NJ'p"M]"[ ^kn@_>xr>de:Źv7GT~jObQ1 ݨ?ӑcSv@) h'1*R*(6:{(wjl D/,>t֑RTّQ/U~F&`pG5^8Qau6WWptњeW'+ )N6 8.tT\F&1ډʫ8/s͑vCЋ:^LӁq{eչx;V^iyQ:qTBR2Xg*SVΑ@_ 2yUdCg{gkE<7=ThwC4bW+.coq2\OKvC6WW!i= W+y}s4iEsAo4kbC$lL`V% ]%2o3CҖo=;95ʶI=;5H 蝆jpWi2DD4Fۉ˲:\lc& t# @9k:pvqPB(칣m>Ra zcͰyd/dK hmf o V:N"=R1 .e +"-11(AhPk$[Tl3Zw'=6+!)7ZK];iv7,#c0{φDŽ<_~gLM<2RKWv?#:H) *"a;PG'OsDfؖq[:8ƮP4X o(8 -Hkm4w[@DǏiFĝga*P~ݍp-_B:M"F8;_F&} SsBA 9FϕDG!{i;/cT:<etf;o`3u:POrPtc҈ma;p$]ӁxZ u[T-e+eKCʦJȞvq.F|q5u "W}MFȽ|;NOi"kSH0;֑9vv&vgEN!YImxNJC.dviq}dlt Z \rICwZі2 ǃ {`\ k)x Hx-"^+l.#!MC4FbQ3LyeE.dEz}iONLy\,AAٖvS®9V/_B)sC[SkX_nћ!$:yB[1B #vk5ވbڪ} ,5:|| 6+:?B˘\&׽K07öUL\Ictb70G'ѕqmlx+Cd^c߫Nt;dJPdeO <1}2٪ǭӸ9qs-qm,RW4_cFZ-]07waHB.w!p!Wnm5)eF5YȢ}39d%԰KN'm_[Oe{*UA!ya<ܳF1hڙ\ (D',_L 8Ŋ%f'd\ߊ)X@CrX$ 0!%&4K,Eoф0S:h: v& a|c74.ng$:+%& BHP !T(J!Rtdc_),---yl]"lB1---?B)q=rI^BBB(B(B(BIIGB "N!;ΜyJ!L_B")!P !P !P !To`G_MiO}_$"de{a[hږ=+6S¾8dA!Q4-9h@Z{(~ !-eٖD[ԏH{-0eYlðph.4Zc (,6L 4QsB'ulKg%C12b} 'OΝCȽPTAa[G4W=2^* R|P8vN0Dmu-}leB8Tlb؝-)cƁ2ؕ1-e̋%]pݚo3eiq2\OKvC6}m\kkN(Ŋmm)7x"^m,B1Mݰ{Q/a h3 N--z~m$=1KnņC|ڔ",63ᚴ8?6-)!^פ5upjt_I^<)[6Ǡю))ܰ-3}  b.[`B|?T1jmi8O`Rr[1d2kĩL vݚԡS)y~0#D#x{d v^ȯ.ʨϊ3y噼ya /+B5*C{sGvi4; ~>e[s3l;p*:.c/Ƣ= 5ʢw:bNQz*iNF+d :IC'-Ǿ R)%H##`ɍ'&6p[šsaw0!Y|ʛ$.zXOa:)<12qE\.'˳>(;ϓ!F@!sq iQ6x, ' 6a*X\K4;0jM6\@5lSNl9+7/>* ACM - First look and basic usage

ACM - First look and basic usage

by Riley Rainey
updated by Umberto Salsi

Contents

Back to general contents
Introduction
Features
Limitations
Support
Acknowledgments
Launcher interface
Command line options
Keyboard Commands
Abbreviations
Units of measurement

Introduction

ACM is a distributed multi-player air combat simulation program that runs on Linux and Windows. Players engage in air-to-air combat with infrared missiles and cannon, but civil aircraft are available too. Users can add more aircraft models and more sceneries, and this manual explains how to do that.

Aircraft are simulated as 6 degrees of freedom bodies, and every model gets described by its aerodynamic properties. Landing gear dynamics, engines, atmosphere properties and wind are also simulated, so you can experiment the different behaviors of the aircraft in different flight conditions.

The "world" of ACM is round, but the terrain is uniformly green and lacking of any detail apart the fog and some runway here and there. This poor rendering is intentional because it makes the program so light and fast, performing 25 frames per second with a CPU load nearly zero, without the need for an accelerated video-card nor specialized graphical library. ACM is also suitable for instrumental flight, since it provides many airports and related radio-navigation aids, including NDB, VOR, DME and ILS.

Screen shot (landing with the C-172 RG).

Features

Summary of the main features currently implemented:

  • Multiplayer interaction via DIS protocol.
  • The Earth is the WGS-84 ellipsoid.
  • Current Earth magnetic field (NOAA World Magnetic Model).
  • Environment: Sun ephemeris, standard atmosphere with fog, wind, gusts, clouds.
  • Simulation with 6 degrees of freedom.
  • Landing gear simulation.
  • Limited vertical positive/negative load.
  • Classic instruments: magnetic compass, turn and slip indicator, airspeed indicator, attitude indicator, altitude indicator, vertical speed indicator.
  • Navigation: HSI with RNAV calculator, ADF.
  • Head-up display (HUD) and inertial reference system.
  • Auto-pilots: hold altitude, hold climb rate, hold speed, follow VOR radial, follow ILS glide path, rudder/ailerons coordination.
  • Several aircraft models implemented, both civil and military.
  • Several sceneries provided with PDF navigation charts.
  • Source code provided with GPL license.

Limitations

  • The source code of ACM is known to compile and run on these platforms: Linux Slackware 14.1 32-bits; Linux Slackware 14.2 64-bits; Windows 7 32-bits with MinGW; Windows 7 64-bits with MinGW. A binary executable package for Windows 32-bits is also available; that package runs on Windows 64-bits in compatibility mode.

  • The maximum number of local and remote players at any given time is 32. Beyond this limit, the program warns it cannot store nor display further remote players and cannot generate further drones.
  • The maximum number of local and remote munitions and explosion at any given time is 32, including missiles, cannon bursts, drop bombs and explosions. Beyond this limit, the program warns it cannot store nor display further munitions. In spite of this limitation, explosions of missiles and bombs are effective although these might not be displayed on the screen.
  • Although the DIS specifications enumerates more than 6000 entity types, only a tiny subset of these are actually supported by ACM -- see the inventory files in the objects directory for the current list. Only the aircraft currently defined can be generated and simulated as local entities. Unknown remote entities that might enter the simulation through the DIS protocol from other applications are displayed as "UFO".

Support

News, bugs and updates for ACM are available at www.icosaedro.it/acm/download.html.

Acknowledgments

The original version of this program, ACM-5.0, was developed by Riley Rainey and distributed under the GPL license.

The first version of ACM was released in 1991 via the venerable Usenet comp.sources.unix newsgroup. Since then, ACM has been upgraded to support the IEEE 1278 Distributed Interactive Simulation (DIS) protocol.

ACM's DIS glue code was created by Mats Loftkvist.

Many others have generously supplied bug fixes and other changes to ACM-5.0 since it was originally released. In particular, Brad Bass and Tim Tessin contributed with their encouragement and continued support. Charlie Briggs and Tom Giertz have helped out a lot, too.

This manual documents ACM version 6, basically the ACM-5.0 version with some additions and corrections, more aircraft models both military and civil and more instrumentation for the pilot, and several other new features.

Launcher interface

You can start the program either from the command line or from the graphical interface. The ACM distribution package includes a simple launcher program to start ACM.

Windows users need to install the TCL/TK language interpreter from www.tcl.tk in order to execute this launcher interface. There are several implementations of the binary executable TCL/TK; one I found very easy to install is that provided by Magicsplat available at www.magicsplat.com/tcl-installer/index.html. Often these packages provide very advanced libraries and programs along with the basic Tcl/tk, but for our needs only a basic installation is enough.

Run the program acm.tcl by either double clicking on the icon or issuing the command

$ ./acm.tcl

If your computer complains about the invalid path of the "wish" interpreter (the Tcl/Tk window shell), simply open the file acm.tcl with your text editor and change the first line so that the file path will match the location of the "wish" interpreter on your system. The windows can display several panels: select the desired panel pressing the button at the top of the window.

Start from the Configuration panel. If this this is the first time you run the launcher, it is mandatory to check the correct configuration in the Configure panel as described below. Usually the launcher can figure out by itself the correct paths of the ACM executable program and of the objects directory, but in some cases human assistance is required :-)

The preferences you set in this mask are saved in the file .acmtkrc in your home directory, and restored every time you restart the program. The button Run starts ACM. The button Default sets the default values into all the panels. The Quit button (or the keyboard Esc key) exits the program saving the contents of all panels; you may also click on the close window button.

The Plane panel

This panel lets you to select your aircraft Model among those defined in the objects/aircraft.txt file.

The Payload entry box allows to set the total payload of your craft; at least 200 lb should be accounted for the pilot and for each passenger; if left empty, the default is 150 lb.
The Fuel entry box allows to set how much fuel to load; if left empty, the default is the maximum allowed by the specific aircraft model.
The Panel radio buttons allows to choose among the classic instruments panel and HUD mode; once started, you can however switch between the two modes by pressing SHIFT-H.
The Eye dist. from screen allows to set the distance of your head from the screen, so an appropriate zoom factor can be calculated (more about this next).
The Downward view angle allows to set your downward visibility angle from the cockpit; usual values are about 10 degrees for civil aircraft and 15 degrees or more for modern jet fighters. The picture below illustrates these parameters:

Scale factor and cockpit view layout.

From the distance of the eye from the screen the program compute a proper scale factor so that the landscape visible outside the cockpit can be rendered realistically and without distortion, a feature particularly useful in visual flight mode.

The downward angle of view (DAV) allows the pilot to see below the horizontal axis of the aircraft. This angle can range from 7 to 10° for civil aircraft, up to 15 or even 18° on fighters. Flying at low speed the angle of attack (AoA) reduces the visibility even more, and the effective downward angle of view becomes the difference DAV−AoA. To fully display the HUD graphics a DAV of at least 12° is required.

The Departure panel

From this panel you may choose the departure location at the end of some runway, or enter a location by hand at an arbitrary geographical location.

You may select the airport and the runway among the zones defined in the objects/zones.txt file and listed in the zones menu. Once the zone of your interest has been chosen, the full list of airports and runways is updated accordingly. By clicking on a runway, the latitude, longitude and heading fields below are set and a Description field is automatically generated. The altitude and initial speed gets blanked so that the aircraft can be gently deployed on the selected runway.

The initial location can also be entered manually and a corresponding description field can be freely edited. By entering a specific altitude, speed and heading, the aircraft starts airborne with the landing gear up and a pitch of 2 degrees nose up.

If all fields are left blank, the starting location is 0N 0S at sea level altitude...

The Time field allows to enter the departure date and time in ISO 8601 format, for example "2017-10-26T09:00". The time is "zulu", that is UT; there is no way to specify a time zone. For a complete list of other abbreviated syntaxes, type a random string and let the program complain: the error message will explain all the possible alternatives.

By leaving checked the now box, the program reads the current UT from the clock of your computer.

It is very important to correctly set the date and the time of the departure. In fact, the program calculates the Sun ephemeris for the day and adjusts the brightness of the scene accordingly. Moreover, the magnetic field on the Earth is calculated for the given date; you may experience how much the the magnetic field changes over time at any location of the Earth by entering different dates.
Use SHIFT-D to display state informations. At any time while you are flying, by pressing this keys combination, the state page is displayed with several useful informations, including: the aircraft model you are currently using; the current simulated zulu date and time; the current position; the current magnetic field variation VAR respect to the geographical north. Several other informations are there mostly for debugging and may not be of much interest for you.

The Environment panel

This panel allows to set the weather conditions and some other environmental and rendering options.

The Terrain radio buttons allows to choose among the flat terrain rendering (faster, but boring) and the tiled terrain rendering (nicer, but possibly slow on some very old computer with shared built-in video memory). The tiled mode is recommended as it gives a simple but still useful speed and orientation feedback while flying at low altitude. At high altitudes, or for combat maneuvering, probably the faster flat terrain rendering is preferable.

The Clouds base and top entry fields allow to set a tick layer of clouds. Clouds are opaque both to visible light and to the infra-red seekers of your missiles and those of the drones. No clouds are rendered if the top level is less or equal to the base level.

The current implementation of the DIS protocol ignores the clouds. ACM does not currently manages the environmental parameters over the DIS protocol, so daylight, wind and clouds have only a local effect and are not shared among the participants into the simulation. Then, for example, trying to hide yourself inside the clouds to escape an hostile missile aiming at you fired by a remote player, does not work because the remote missiles are guided by the remote program where probably the player has set a clear sky...

The Wind direction if the geographic (NOT magnetic) direction from which the wind blows. The Wind velocity parameter is self explanatory. The Wind gust max intensity adds some horizontal random, rapidly varying, component to the wind velocity to make things more interesting.

The Drones panel

You may practice with ACM (air combat maneuvering) techniques also alone by fighting against the robots driven by the program itself. Up to 31 drones can be generated by simply pressing the l key, but typically just one is challenging enough.

Drones can be generated in either "dog fight" or "hunting" mode. In dog fight mode, drones are placed just in front of you. In hunting mode, drones are placed up to 50 NM away from you in a random direction and altitude.

This panel allows also to set the drones aggressiveness, that is how much "G"s they will pull to escape from you or to attack you. For example, by selecting 50% aggressiveness, drones will maneuver up to the 50% of their maximum structural vertical load, both positive and negative. Your airplane undergoes to the same structural limitations, so always put an eye on the G-LOAD light of the warning panel or you will loose your plane!

The DIS panel

The distributed interactive simulation protocol (DIS) is a standard network protocol born to simulate war sceneries involving any type of known submarine, ship, land vehicle, aircraft, missile, space vehicle and munition, both civil or military. The ACM program uses that same protocol to share its local entities with other ACM programs running on other computers, or even among several instances of the ACM program running on the same computer.

The DIS protocol feature can be disabled, or operating on a local network (LAN) using the broadcast protocol, or operating on a wide area network (WAN) like Internet. If disabled, ACM works in stand-alone mode, that is it does not send nor accepts anything from the network.

The Force menu allows to choose the force your plane belongs to among Other, Friendly, Opposing and Neutral. By choosing Friendly, drones generated by you will be Opposing using MiG-29 and will attack any other force (including Neutral...). By choosing any other force, drones generated by you will be Friendly using F-16 (and still will continue attacking any craft of any other force...). Your radar and radar warning receiver (RWR) will display as friendly any craft radar emission corresponding to your force, and as hostile any radar emission from other forces.

To play on a LAN in broadcast mode, all the participants must share the exact same subnet mask, for example 255.255.255.0, otherwise the IP broadcast protocol does not work. Participants must also share the same UDP port number (typically 3000) and the same exercise number (in a range from 1 to 255). The Relay server field must be left empty.

To play on a WAN, a relay server is necessary. The ACM package comes with its own relay server program src/dis/server/dis_relay.exe; this relay server must be launched from the command line of some computer having a statically assigned IP address. To start the relay server, type a command like:

dis_relay.exe --port 3000

Other options are available; try with --help. All the participants must then enter the address or the network name of that shared relay server in their Relay server entry field.

Before to explain what to enter in the Site ID and Application ID fields, a note about how the DIS protocol works may help. Every aircraft, missile, cannon burst and, in general, every entity the simulator program generates must have an unique DIS entity ID; this ID is generated combining a sequential counter managed by the program (the serial entity ID), the application ID, and the site ID:

DIS_Entity_ID = Site_ID, Application_ID, Serial_Entity_ID

This DIS_Entity_ID must be unique of the entity among all the entities involved in the exercise.

But how to assign an unique application ID and site ID? The ACM program allows to set -1 for both these values, in which case them are chosen by the program itself using the algorithm explained below.

If the the Application ID is set to -1, then its value is set as the process ID of the program. In this way it is guaranteed several instances of the program on the computer will have distinct DIS entity IDs.

If the Site ID is set to -1, then a random Site ID number is generated and the program enters a validation period that last 15 seconds. During the validation period the program listens for incoming packets looking for collisions with already used site IDs. Normally no collision is detected, and the program successfully completes the validation and starts sending its packets. Instead, if a collision is detected, a new random site ID is generated and the validation period restarts.

The Configure panel

The entry box Program contains the file-name of the ACM executable program, normally located in src/acm/acm.exe. This is the program launched when you press the "Run" button. The acm.tcl launcher invokes that same program to get the list of aircraft models it displays in the Plane panel we explained above, so it is very important to set correctly this path.

The entry box Objects directory contains the directory-name of the directory containing the scenes, the aircraft inventory and other resources the ACM program needs.

The Frame rate is the number of times per second the program will update the image on the screen. 20 is probably a good choice for civil aviation, 30 is better in combat.

Mouse movements are translated to ailerons and elevator movements. The Mouse mode menu allows to choose among fast, normal or precise movements. "Fast" may be useful in dog fight combat. "Normal" and "precise" modes are recommended for the normal flight.

Sound effects can be enable and disabled at runtime with CTRL-M.

The remaining options of this panel are quite self-explanatory.

Command line options

The ACM program can also be started directly from the command line. By default the aircraft model is a C-172 located at latitude zero and longitude zero, which might not be a so interesting place where to start from. So, you may try with another model and some other departure location for which a runway and a scenery is available. Historically, up to the version 5 of ACM the default starting location was the Addison airport at Dallas, Texas, runway 15:

src/acm/acm.exe -plane F-16 -latitude 32-58-40N -longitude 096-50-26W -heading 156
On Windows, the back-slash character \ must be used instead.

The general syntax of the command is

acm.exe [OPTIONS]

where [OPTIONS] is any combination of the following:

-help
-version
-copyright

Displays program version, copyright informations and then exit.

-init command-file-name

Take extra command options, in command line format, from the specified text file. For example, say there is a file in your home directory named ‘.acmrc’. Its contents look like this:

-dis-site 34
-dis-appl  4

New lines are treated as normal white space, so feel free to separate command line options onto multiple lines. From a shell, you enter the command:

$ acm.exe -geometry 800x600 -init ~/.acmrc

This would be equivalent to:

$ acm.exe -geometry 800x600 -dis-site 34 -dis-appl 4
-objects path1:path2:...

Scenes, audio effects, aircraft shapes, aircraft data files and other resources are stored as files inside the objects/ directory. ACM will look for its data files inside these directories: the current directory, objects/, ../objects/. So, if you try to start ACM from outside its base directory, it will complain not to be able to load these files. This option lets you to specify where these files actually are. You may specify one or more directories separated by a colon (Linux) or semicolon (Windows).

-stealth

Start ACM in stealth mode. ACM allows users to monitor out-the-window views for any aircraft active in an exercise. Additionally, ACM supports an experimental DIS Request/Grant Control protocol that would permit ACM to “take over” aircraft of similarly enabled applications. See the “Stealth Mode” section for detailed information on this capability.

-subject-entity-id site-id.appl-id.entity-id

This option can be used in conjunction with the -stealth flag to identify the initial DIS entity to be “stealthed”:

$ acm.exe -stealth -subject-entity-id 32.1.1

-geometry x11-geometry-specification
Specify precise location and size settings for the main ACM window.
-frame-rate target-frame-rate-hertz

Specifies a not-to-exceed rate at which ACM will attempt to render the cockpit scene. The default is 20 Hz, which is quite low; 30 Hz is recommended.

-plane MODEL
Allows the user to select the aircraft model to be flown chosen among those defined in the objects/aircraft.txt file, that is one of: AMX, C-172 (default), F-16, MiG-29, Su-30, B-747, MD-81, P-51A, UFO. Note that the C-172 simulated is the RG version with retractable gear; UFO is mostly intended for debugging of the sceneries, as it may fly very fast. To know which models are currently available, simply start the program with an invalid model, for example "xxx" then look at the error message.
-fuel fuel-lb

Allows the user to set the amount of fuel loaded (lb). If left empty, the max amount of fuel allowed by the aircraft is loaded.

-payload payload-lb

The payload = passengers + cargo (lb). The default is 150 lb, a rough estimation of pilot's weight.

-force FORCE

Tells to the DIS protocol to which force you belong among Other (default), Friendly, Opposing or Neutral. Fiendly and Opposing forces are special because the scenery may define a resupply location (that is, your air force base airport) where you may get fuel, munitions and repairs automatically by simply staying still: operations completes within few minutes! These locations are identified respectively as team 1 and team 2 and are read from the departure scenery (see the scenery team record definitions). The force you belongs to also affects how incoming radar beams are displayed (see radar warning receiver) and how drones behave (see drone).

-departure-time TIMEDATE

Allows to set the simulated departure date and time. The ISO 8601 date-time format must be used, for example "2017-10-23T12:30". By entering an invalid value, the programs lists all the supported formats along with the error message. The current computer date and time is the default if this option is missing. The state page (SHIFT-E) displays the updated date and time the program is simulating. Sun position, general scene illumination, and Earth magnetic field are calculated based on this simulated date and time.

-latitude DD-PP-SS.SSSQ
-longitude DDD-PP-SS.SSSQ
-altitude altitude-msl-feet
-heading initial-magnetic-heading-degrees
-airspeed-kt initial-airspeed-knots

These options may be combined to tailor the startup location of the ACM aircraft. The exact syntax of the latitude and of the longitude is:

degrees[-primes[-seconds]](N|S|E|W)

Seconds and degrees can take a fractional part. Examples:

-latitude 3.54N -longitude 123-4W
-latitude 1-2-3.4S -longitude 45-59-22.2E

If the -altitude option is not supplied, ACM automatically sets the aircraft on the ground at the specified location. Starting airborne (i.e. specifying an altitude grater that the local terrain altitude) the initial pitch is set to 2° and the landing gear is retracted. Care should be taken not to specify an altitude too close to the ground.

-dis-exercise DIS-exercise-id
-dis-site DIS-site-id
-dis-appl DIS-application-id

By specifying any of these options, the program activates the DIS protocol and prepares for communicate over the network in multiplayers mode. It is very important to set properly these values because because each entity generated by the simulator (aircraft, missile or munition) must be univocally identified through its site ID, application ID and a sequential number generated by the program. These 3 numbers form the DIS entity ID that univocally identified each specific entity.
The exercise ID identifies network packets for the specific simulation we want to participate to; the program will simply ignore packets for any other exercise. The allowed range of the exercise ID is from 0 up to 255; the default value is 1.
The site ID identifies your computer and should be unique among all the participants to the specified exercise. If not specified, or set to -1, a random value is generated and then validated on a period of 15 seconds; if no collisions are detected during this validation period, the randomly generated site ID is confirmed and the program starts sending packets; if a collision is detected, a new random value is generated and the validation period starts again. The allowed range of the site ID is from -1 up to 65535; the default value is -1.
The application ID identifies the specific instance of the ACM program running on a specific site/host. If you are running 2 or more applications on the same host, you may assign them the numbers 1, 2, 3, ... If the special value -1 is assigned, ACM uses the current process number instead. The allowed range of the application ID is from -1 up to 65535; the default value is -1.

-no-sound
Disable sounds. Sounds can still be enabled at runtime with CTRL-M.
-visibility flight-visibility-nm

Set the clouds/fog density. Runways farther than that are difficult to see or are totally invisible. The default is 50 nautical miles.

-ground-mode MODE

Allows to choose the terrain rendering mode among "flat" (default) or "tiled". The flat mode is faster, but the terrain is displayed as a boring uniform color. The tiled mode is slower, but the player may feel some speed and scenery depth feedback.

-clouds-range BASE TOP

Allows to set a tick layer of clouds, being BASE the bottom altitude and TOP the top altitude of this layer (ft). The sky is clear if this option is not set or BASE is equal or greater then TOP, which is the default. Clouds are completely opaque to the visible light and to the infrared seekers of the missiles; visibility inside is zero.

-mouse-mode fast|normal|precise

Movements of the mouse are mapped to the corresponding movements of the ailerons and of the elevator. "Fast" uses linear relation, so the aircraft reacts promptly to the commands but it is difficult to pilot with precision. "Normal" and "precise" are the recommended modes. The default is "normal".

-end-game

This flag is only valid in stealth mode. Hostile aircraft near the subject aircraft are tracked. If any of these aircraft moves within the subject aircraft’s radar locking range, then ACM will request control of subject aircraft. Control is requested using a variant of the proposed DIS 2.1.4++ transfer control protocol sequence.

-threshold-range threshold-nautical-miles
This flag is only valid in the end-game mode. If a hostile aircraft moves within the specified threshold distance of the stealthed (subject) aircraft, ACM will attempt to take control and engage the hostile target. If threshold range is not specified, then the subject aircraft’s radar lock range is used as the distance threshold.
-wind WD/WV
Sets the wind direction (WD, degrees) and the wind velocity (WV, knots).
-gust GUST_MAX
Sets the wind gust maximum intensity (ft/s). Default: 0 (no wind gusts).
-eye_to_screen_cm CM

Sets the distance between your eyes and the screen, expressed in cm (1 inch = 2.54 cm). This parameter allows the program to computer the proper scale factor needed to render the outside view without distortions. Default: 50 cm.

-downward_view_angle_deg DEG

Sets the downward view angle (DAV, degrees) below the horizontal axis of the aircraft. The instruments panel and the engine cover above the pilot, usually limit its capability to view downward toward the ground, as explained above describing the acm.tcl program. To fully display the HUD graphics a DAV of at least 12° is required. Default: 15°

-drone-mode mode
Set how drones are generated. Allowed values are "DOG_FIGHT" (default) and "HUNTING".
-da FACTOR
Set drone aggressiveness, default 0.5. See below the paragraph about drones.
-hud-mode
By default the program starts displaying the classic instruments panel. This option allows to start in HUD mode instead.

Mandatory initialization files

The program looks for the following files under any directory specified along with the -objects command line option.

object-map.txt
This file defines a mapping from DIS entity types to 3D object definition files. The object files are used to render an image of the entity.

munition-map.txt
This file defines the explosion and damage producing characteristics of DIS munition entity type and warhead combinations.

aircraft.txt
This file defines the performance characteristics of all aircraft types modeled by ACM. The layout of this file is defined in the section titled Defining New Aircraft.

Exit status

Exit status 0 indicates a normal termination of the program. The specific reason for the termination of the program is sent to standard output; nothing is written if the program terminated by player's request. Some diagnostic message might be sent to standard error, for example invalid DIS packet received or too many entities generated, but these events are not fatal and do not indicate an error in the program.

Exit status 1 indicates a fatal error occurred: internal error, or invalid command line parameters, or system failure in providing some service. Appropriate description of the error occurred is sent to standard error.

Keyboard Commands

General

g Landing gear up/down

b Wheel brakes on/off

h Flaps down 1 step

y Flaps up 1 step

s Deploy speed brakes 1 step (one or more steps, depending on the aircraft model)

w Retract speed brakes 1 step (one or more steps, depending on the aircraft model)

t Start/stop/reset the timer display

z Rudder step left

x Rudder centered

c Rudder step right

l Create a drone opponent aircraft. For Friendly force player, an Opposing drone is created; if the player belongs to any other force, a Friendly drone is created instead. Drones attack crafts belonging to any other force but their own.

d Detach commands from the ACM window, so that you can leave the ACM window in background.

+ Zoom in.

Zoom out.

Shift-D Displays a state page with several useful informations; among these: current aircraft model; current simulated date and time in ISO 8601 format, zulu time; latitude, longitude and altitude over the WGS-84 ellipsoid; characteristics of the air at the altitude (standard model).

Shift-H Toggle between HUD and "classic instruments".

Shift-M Switch between MH (default) and TH indication (see HUD and HSI sections).

Shift-P Print screen shot to the file /tmp/acm-dump-* (not available under Windows)

Shift-K Calibrate joystick

Shift-$ Play like a drone (toggle).

Ctrl-M Mute/unmute sounds (toggle).

Shift-Q Shift-Q Quit the simulation. NOTE: press two times!

Auto-Pilot System (APS)

Shift-A Engage/disengage the auto-pilot in hold altitude mode or in hold climb rate mode (see The Auto-pilot for details).

Shift-Z Engage/disengage the auto-pilot in hold altitude mode (see The Auto-pilot for details).

Shift-T Engage/disengage the auto-throttle (see The Auto-throttle for details).

Shift-X Engage/disengage the rudder/aileron auto-coordinator (see The Auto-coordinator for details).

Shift-N Engage/disengage the auto-navigator (see The Auto-navigator for details).

Shift-L Engage/disengage the auto-landing (see The Auto-landing for details).

Shift-( Decrease maximum bank angle.

Shift-) Increase maximum bank angle.

Home Release all the auto-pilot sub-systems, with the only exception of the auto-coordinator.

Shift-E Engages/disengages the rate control mode rather than the direct control mode. In direct control mode, the mouse position relative to the center of the window directly sets the position of the ailerons and of the elevator. In rate control mode the mouse position relative to the center of the window sets the roll rate and the pitch rate.

Views

View buttons are located on the PC’s numeric keypad.

KP8 Forward view

KP2 Rear view

KP4 Look Left

KP6 Look Right

KP5 Look Up

KP0 Look Down

n Chase view (this view button is not located on the numeric keypad)

Mouse and Mouse Buttons

Move left/right ailerons deflection and nose wheel steering.

Move forward/backward move elevator to control the pitch.

Left button fire currently selected weapon.

Right button select a weapon.

Joystick Buttons

Button2 (top) Select weapon (Sidewinder IR missile or 20mm cannon)

Button1 (front) Fire selected weapon

Classic instruments

Shift-H Toggle between HUD and "classic instruments".

F7,F8 Adjust altimeter isobaric reference level from 28 to 31 inHg.

F9 "Caging" button: forces alignment of attitude gyro with its case.

F11,F12 Adjust pitch of the symbolic airplane in the attitude indicator.

Radar

r Select radar/HSI/ADF/off mode

Shift-R Toggle between radar modes: Normal, ACM 20x30, STT, Standby. Also Button3 on Microsoft Sidewinder Joysticks.

q Break Lock -- track a different target (also Button4)

Engine control

The meaning of these keys changes when the the auto-throttle is enabled. See The Auto-throttle for details.

1 Engine Idle

2 Decrease Power

3 Increase Power

4 Full Power

a Toggle Afterburner (if available)

SHIFT-! Deploy/retract thrust reverse (if available)

IMPORTANT. The thrust reverse device can be deployed only with engine commanded idle (throttle lever below 25%).

Auto-turn

The auto-turn automatism helps the pilot to keep the desired standard rate of turn of 1.5 or 3.0°/s. Enabling the auto-turn, also the AC is enabled. This is an experimental feature mainly intended for flight test purposes. It might be removed or otherwise changed in future releases of the program.

< (less than) Set left turn rate 3.0°/s

, (comma) Set left turn rate 1.5°/s

> (greater than) Set right turn rate 3.0°/s

. (period) Set right turn rate 1.5°/s

| (vertical bar) Set turn rate 0°/s

/ (slash) Disable auto-turn (see also key Home)

Trim

Trim buttons may be pressed until the desired trim is attained

j Adjust elevator trim to the current pitch command

Ctrl-Shift-UpArrow Forward (down) pitch trim

Ctrl-Shift-DownArrow Aft (up) pitch trim

Ctrl-Shift-LeftArrow Left roll trim

Ctrl-Shift-RightArrow Right roll trim

Home Reset elevator and ailerons trim, disable auto-pilot, auto-throttle, auto-navigator, auto-landing and auto-turn

HSI receiver control

Press r until the HSI gets displayed.

SPACE Switch between NAV1/NAV2/RNAV1/.../RNAV5 receivers.

9,0 Set station frequency

7,8 Set OBS

F3,F4 Set RNAV radial of the WP (only in RNAV mode)

F5,F6 Set RNAV distance of the WP (only in RNAV mode)

ADF receiver control

Press r until the ADF gets displayed.

9,0 Set station frequency

7,8 Move rotatable heading needle

Abbreviations

ACM Air Combat Maneuvering
AAM Air-to-Air Missile
AOA Angle Of Attack
DME Distance Measurement Equipment
DIS Distributed Interactive Simulation
ECM Electronic Countermeasures
HSI Horizontal Situation Indicator
HUD Head-Up Display
IAS Indicated Airspeed
IFR Instrumental Flight Rules
ILS Instrumental Landing System
IR Infrared
KIAS Knots Indicated Airspeed
KT Nautical Miles per Hour, NM/h.
LOC Localizer
MH Magnetic Heading, the direction referred to the magnetic north pole (see also TH, VAR)
NAV Navigation
NDB Nondirectional Radio Beacon
OBS Omni Bearing Selector
RWR Radar Warning Receiver
TAA Target Aspect Angle
TACAN Tactical Air Navigation System
TAS True Airspeed
TEWS Threat Early Warning System − a form of radar warning receiver also known as radard warning receiver (RWR)
RWR See TEWS
TH True Heading, the direction referred to the geographic north pole (see also MH, VAR)
VAR Magnetic variation, the difference between the geographic north and the magnetic north: VAR = TH - MH. For example, VAR=+6=6°E means that the local magnetic north points toward 6° geographic.
VFR Visual Flight Rules
VOR VHF Omnidirectional Radio Range
WP Waypoint

Units of measurement

Numbers are indicated with 4 significant digits.

Name Symbol Value(1) Equivalences
Time
Second s    
Minute min 60 s  
Hour h 3600 s  
Length
Meter m   3.281 ft = 0.0005400 NM
Foot ft   0.3048 m = 0.0001646 NM
Nautical Mile(2) NM   1853 m = 1.853 Km = 6076 ft
Speed
Knot KT 1 NM/h 0.5144 m/s = 1.853 Km/h
Feet per minute fpm 1 ft/min 0.3048 m/min = 0.005080 m/s
Mass
Pound lb   0.4536 Kg
Kilogram Kg   2.205 lb
Slug slug 1 lbf / (1 ft/s2) 32.17 lb = 14.59 Kg
Acceleration
Earth acceleration
at sea level(3)
g   9.806 m/s2 = 32.17 ft/s2
Force
Newton N 1 kg m / s2 0.1020 Kgf = 0.2248 lbf
Kilogram-force(4) Kgf 1 kg g 9.806 N = 2.205 lbf
Pound-force(4) lbf 1 lb g 4.448 N = 0.4536 Kgf
Slug-force(4) slugf slug g 143.1 N = 32.17 lbf

1. A value is given only for those units that are defined in terms of other base units.

2. Nautical miles are a practical length unit used in naval and aerial navigation, as its value is is very close to the length of a arc-minute measured along a meridian, or the length of a arc-minute measured along the equatorial line.

3. As Isaac Newton explained, on the Earth at sea level every body fall under its weight with the same acceleration, here indicated with the slanted letter g, not to be confused with the gram unit of mass "g".

4. The weight is the force with which the Earth attracts bodies toward its center. So it is useful for practical calculations to associate to every mass unit (kg, lb, ...) its corresponding weight-force unit whose symbol is the same as the mass unit with "f" added. Then, for example, 1 lbf is the weight of 1 lb mass measured on the Earth at sea level.

acm-6.0_20200416/doc/manual/acmdoc_html-reference-frame.png0000644000000000000000000005200710644355520021631 0ustar rootrootPNG  IHDRhc pHYs : ÀtIME L IDATx}X X@gV1;aVԭ emt k׎ggg ;:뵝s®kv ݵ\7$UClC'6iKBT"Ikb|}Ǜ$bHBy?ΚG)W˦熂"122[oݸqcժUO?4% 0Qɓ'].szzFA=j|>GAAqԩ۷o#rrrկnڴEL&077ZtieeecccfJ 200pugYYَ;rrrRS⠠X (((x衇֯_. =gn֭[*//O#֠AA0t:y<^KKKQQQ:~ JɃ:x---k֬I/Bscn' [ZZ" J# 4⠠HX,D"ݻӝ5(qPP$5t:BH*n߾=3ݪPP$vyA"0 !DIA"Py~ % p68((I-[2Q⠠?^lFe&E`ZB$}E8((8D"Q~AJqWDB"}JS(qPP} % Ԁx<<oƍ8(((8lD38A"J|>W8NP(I8(fff777G~8˲bdjooሷzd2}g/=Cq,.pGvzzҥK'Ozpa|>3::D;wƅ> 3J"O8166xЮjX=f{7nկ~5FX$QJgZZ" f7222::#}|>qPP1N@$׳UsrrmV[[/ 8((ccc:\õ!>>m۶EA8(( 0'`b(ЇT*{/\}n֭\/L"szu:W\922b6fH$ K۷oȦMR;wnpp󑥓[qve¦ŋGFF/G"E!r9=@C$566k_x<N788X[[/*/CCC.\FqPH]d2*CF&pjvC Tvvׯ_p80}\p! }@-v1T(q+l6Fj=H$) ''bf aD" 1 ׯ_Գ(828:::9q`hll HHRT̔|GII +lUhA*j1k0x`-b!Wxff;RH{X;PDѱƚ5k PH$H$;KRNgZ4LbmF"A (דFubFҥK6p!@@"mq.Ƅ]|a1}l۶ 62qq\=_ttt$K(qPP0c˖-[l Ȟ飨-Y&.&q@^bٴZBAAbĘFeppppp_I0L(~/,{<EB>O*ADXf6V+b$T*]~=G>_p (C<@T*8Nt|>x -HbϺS솢-$O(}jZ"H*nܸ>B=Q;vPSSSRTTb8 ?pAm$g`0!Eq;PodP ~g`ؔaL&B8d2ZNfRJ?F(ǃD"fw Q"H$̞з胑L}0(ߖў5JKKBjZպnZT*|سS-x<>/X(! 1S|PCr?j)>χH$ z}CC:g0@*8쑻NUSba[ y^9Jhb\.onnjrf $6R8b %"= illx-L}PXDmlqomm:ǻ}9{^Fv,x{t2wc@8`('p=z'aT*H$47?88ZZZf,jX}gG9w~JR6-9q#X(&k"'bp9JW  TA>FGG=bh !~C.஻z_yX)A Jpg1l v@j)//OZ qDqC$vp\>ƅ2?&V[[uUV!A]]ݦMҀ8\.$,, KX#B~ؿ`,((ؼyT*MFqY QЇ?xH$vc"F*fgg}߽v~D"yr^p­[񼼼|+)JG V%fTMؼ6nzPB8{q .PKQYn]ss+W .+Wܹ,Ƴg~'V˖-_0X,oV~~kN(`\nڴit !hj M6-G郬޽;eu}>SomT@zk633К5kryqq 2tHdWTT$?wCr= |e ŗ=*F@ hnn޾}{III>He˖}xY'4{>Ar-᳖'BTz*ʤ(q$m1@# (t @ZJeWW8W}RGFF?srr>'({ʵ;w7Ν#2ipX*e˖d$(q$m1K7$C\[[ ^f'jebx<HXW^=y$v[tw{|:L|>q`p83g,j`V^]SS8%Dc||0GGZz 3R)h=nw[[V%ɥ,?gТUTT}xeO#\.Nu:!++eX*e˖I$ۿ;}PH(渰P(>G2Qn-S@ ޿;<<WcۂCntk׮πVVDA8!֭[77(q$-FtGAN6L͐4L`JRuF#8 VX!JJBľiDSӉ DG#p8:C<d2Aڢ\3;^.ޢ]`fggK$vaGAL@}:|>_t>QKx1GQ=!ÍPjZFikkdF1EH`^{eH,YGYrez3 #N* H|>&kp [V۔J"-8FGG 0{}kEx7n$P( q.nY,bȨO/9>KqpttӟDA<) ea·zkhh͛xAn޼ 'FpO!W\t:C70S$ɖ-[>쳱~-9$SF&6Qjdjfd2Gnnƍoߞp܍ 6d#W}@Nf= *H$/~5v:K3Nwnu]fffz~(qDswƚLгZzrbb"9_Bk.j^x{&/]$ 3LNb4zN W%(#5l <$" q!$'%acl6 7oΰi앿k׮W\ի82?.*U*UzV'T'tKԩH$ IXd K{(*mmmX]E=r؍S>"}]rɓ@?(q BB0v͡톽 VҀbK)EdU^^^VVtEqQ@`GKգaoL_ה8^pH5 vC~KW+*,}u=q+1mf=c~Ex N[š{yX d5ص0L~6.Oa1UU LrΝ;x XRt0v.lM:.ĞO 7l8 H4cYD"ĥ%U|lFL&knnV*a幡)NΝH|k9'JB6lp8h]]]\Hu,WND=y$bWC"eB]]] Rx cKR#i鰈rCXQ.9:? #V\VZ;  .mz ON؉N'KX ޮVtᤆD"illק=( Gw #9ė r`C'Փ="S8Z7ǒX@ 5vm6+ֱǁò8 r0 -yw^Jb ,KCE]j%0Aj0ӑҸX6 l؊T*Z sru.G\D c4SGd mQ &?Kޏc'Wd2AvԸBj EXR}.}L:.Sm>(}љ3gG\dI AQ RL\JIHj$> 34.ā9TH;npW"gTzS$ݾ}8AL`f* ^'MIPR#:fȸqߚLݡFd2,Rg\V 2XΦH^>x< %XP(1oLjDGB[VlBzC0Iӷ`ru>zzz~_h+7Bk%z0>L@Dg:::gAM~Pmr-e\o⹄j:DJk= )>ЄngJ_@qX#uiI(fe*E*`݀! x:v`<:Y}烹K1;8/,_|ٲenݚ pX]J&5t:ݻ|Cobii)TmC{FNćX, W%GװAbttho[bEaa!BhaƐ2S(rHK$z{{TA @z/l{ 9?솀8{f\=Asd?.`@T}TO9NqP*fqn ѤǪUnw,3Vز 6QչOr7O` D])p@K .E===\~CH 0u"ҤfkkkK:Bj Jz;;;BdXRic7ZVp"ӤF܈d2L&ldo14  Z S`}x~7iإw!zQq<±cǬVT* 1=8.6܀Q$5~2K ZZ'ND Css3~- `Z'\6FP(JV"BC.FFn* խ<nwvvc$T*ݷo_NN+ߟIVysrrm۶o>8X,F8U*UDI4Q:tFcc#e _&OOO+ r3~-P@ 0JrzzwyHs]]]Q91`YjZϛOsofggg':;;[wvv^.ߊ4B.v矇Ut:)89VZZ2& Z!L& Pd %++ ؚTPxpn[,i 7 k/I)(xcDX{CPv&sE]jQ'?xa``/_fsssVjEEE׀"8>>,BhϞ=bX&|FSQQQQQ'OWf;~۹s^旺/SSSSSSCCC׮][v-#xyyyatt$~hhh8|ÇY`#;;&??nnnjjjbbh4޸q0K(߂!fyڵ|>?Ν;~G ߿QhH>=un?yG)DUCgpOcG&/ Vd|>B|>ȉ'^xᅢx}X"x>|xddD._JJJfggvpaa!;...8ydnn.V[/ !*_GMMMΎ ߸qcڵq `ӵkNg<###RYWWWQQ8qܜH$z'R#V[6 zpqB !=2)-tX,G.S% uf4=u\5 Z] IDATF8+`Wk zⅵ(OH Xy '!]!h ݔ r81( &'c1}e]Y,zgfiZJ`rJ )ٙ#jv\ ̭^q!T{a&wo腒'8 x^S0l! 1v˗/O@!TZZ [Khbc̋-3*5T5`8tOy].׭[FFFP n]9|>_$[,gBQ\\\WWpR@ŭ:ጔ8Wjmmmeۘi:/̽>v)_B>~G8 bx}`Ԡg..A\N``MqqFH",5-o޼i6;joo2L޵kW"MjPHȡa+\W3g@`;& U=Q0 _t ~K.SSSq;X{8ΕZvmzjJx! d [] `RХ%=h4>}/0#VvS8ٳgF#\]q.I 5=fLmNkAi%@9"A84kii 0&O͛7{{{gH)81X.r_ e@zQ8L[HX jbP  7oFMLLLMM۷ocb9q lmm "޷v94%NpƍjZt!"]?YKeН;w={WTT\|m6t~n8p!TWWxXnBRa=`e蔓Jkkkax fo07*_{bӦMu±Z[[yEI 2> u2q :6RRd7l6)vF!PPP}fd0`n߾:ٷoO_k׮z/~W_(ɩ~СC#XRȑ#hڵ+]6ЀVuM`>YJ}J6/dBl+V{18Ӱ͎.9WPPc4hϸ4 @pESYYO\t7<4}|^fMww#Gr/)t8B7bLΑNeglllrr2??>h4{B !$T*H8Ρ!Q>WUU]zԩSخ-2r\.djjjM4BcWUb|88z<I* ؀]㌭8ZF 8ZBӌ^z=MJ LOOrBQU[qإCc#Bammm|-[~HMjjjH}}} BϧBd.BDa---=ؒ%KB֭KǑئQ4VBG0_ ECCw-Hrss[[['pzPv.[?DqH_֭0УǗƃ @*lhh_R6bJɠع]wݵ{^z)Af$}{ll׿uZ]\j`& X3j-?z !'`-ղ\A#,/#/$Q{zzU=XGg5NȊ Ч -(LQॗ^:p~Ȧ$FH]31FXKc$h< m䈬BлP^IJ%p7a{Ďz%{M5 *6ZIii)KC׮]L/XQChJr:$`:zjVdP P6˱w3J&)qg/R+G:댤 BV3G|cGy<'o>/liC\򔸤 iwwdf%CI]],K>(AB]]]Lw7"Pzդ'qWѣG!_{ -D叻aGpæT\.d2RR J7؀FQ&Av@,T,2gZC `:GzAVc].W,RChJ#IPmm--,z{{>ȢT %%s!FA]{ԉI}@$Z.+%0W( 4Zt jpڀ5x%ʀ5JJJ}( XT*DR$޲e 8ݾC$D"XE0 N#"9 8rnH$V5_rA$=cmG #~qDS)F 0$.xƤ c4mVVC6b2ZVeT#l(_q;omm] ]ȭ26h]K6ntk׆R+2nw"&>HX^@˗/l/|P( Ţb=qBmmmww\@_}ll,`ۡեT*ڴZmOO0O8W. 6RkrC0^6#b0~%r96HvɩH$߰zMJOـWՆ:< `мl~WqF `5|4ovKCכL&Ʉ`u]eee>t;NM@"2R%bJEP` 5>ݱ`>p8@9JJ%>0f}UUU[lٺu x>(q,<`߿NPѣGaHʺu>{n;b1k@zXѣG%5nwVVSO=?3Ir p̭[d h,n'Y{K(4Q%q ^xχr*=+mPIx<-<1^^;v,*Uuo΀T*裏~`tta144t̙O#˯\en]CG +d=f ͒a*EJ` uدoۃgϞEDX,*L\#<2<|>,YD$PH![ĸ= 9RZx@tk ^^z)??_/~l% gyRߟWRRBZ1)0Y(9I',.[8R~G1Ɨti *R^6kGZ[[/_jժ$ju)ܹ7H9„ )Q+Vrssggg+s=x@Wj  g ʬ'|rG:M_zd-))!CCCN wą=NT*ݱcNJ+ggg&&&fz'NLMMr^{5:RYWW_ D~җ4<<ٹ|{{^YY|\.UV}gK,Yf͖-[ط첲2 Hoijjj󧦦<jM(w}\~}ppeee4H-`d{5t-A`( ]qK·~?Swַ8q_\UU}?rʕ+\B6P$aD27 h9_":S2~ݺu+8q$ fkCCCSSS7ox<0=i->_YYYRR2;;ec2v]QQÐSN >}+D hjjz;|߰a֭[Rn>m60d*E"QUUeeessszڵkúegD"NMMMMM ݸq#o ۷|>҈#2M%W5Ѱl>(MGKJJCnd2c9Yp I zN[[ "Ud4=y^ID5q!+vďLOO?g4bZLİ \= QTbRdɒ}kt7SSS?+x3k611vؑ.`$>o~{/+++k׮ bxϞ= Tvc``]@ 555˖-s:ONNcbD266vԩիWgq)Ni]6F#//t޼yڵkϟ=lG (^2)^pn0#~Zf ǛHncAw2!28o:VydyN2ȭNj""[]կf@%":|>FZ(|PTk '|2M(n?? ^P*MMMO?L&H$"Q#<%Avcdd'Y!j2rss!ve`qd^}>ujxbiiiZ8ݢAp*4^]pqkFCCL& ;txK@ [0Gݰt  {5aIfЌ>~8MUΎh4']JJJ.]R5]0c]0SX +B2VZpețB%=;'T|,]tӦM?0%$k(8ЈqW@U!Y#PsLL&K.a+fruYYDzKٚHqd#''_rzM~JiY 򕯤gfYLc) r׃z)atH$իWF.Wt~>S TP|\JcQ@~~jeE~Iyn߾ͱ@C h4Jaddgg`EEЇdyϿPPΖH$Pu:333;w\b(,=4’UVVပtBtFSFׯOcızIh c7 x55(J]cljjJ߸q*@jB Dvsss׮]-aQQQj4q9yNU5?<$ bE9b1g@tWߵkNwŎ0m$Y{ `:`h"/++ %J"mt:ᄐ<099x`#b Lo6#O8l6[EEESSSQQQWWW58,˱cdžfggy<^MMݻKKKW {]]˗_}լ{^rUUUCehh8x@nZ3U,1ܸ z1ߤ%JG(H6tJRT4,%߯E"EF!3x h}Gg, 6j]] ruҌ566rL'B˖-OxrqxW8+zC3Qu >Rj/q:v#ڔR*W^ݱcѝa333yw)vNKөG>eH$Y__zL tG:@c>}iǑ>JKKD|_.ctː{-*XFMGd2\4c*q1`\{P(Hj$# zͬ8ܐ]]] -/e17m 90r_$r`9t.ĖvH8`{㹹999 >P(Jznbk||\,]]]T?*\~g =~ӟ;jׯprAXFAB-D9n޼:ؓ9B].fV j.pIΗe71b"(Fyg󭰰ԩS+Vxg/_H$N3?sb " y$M38Boֻ.@مA~@---awgϞ}嗁#FQ(|q2m2$T*MxǏg0GpL/^ov`0N)!UM38Ǒ#Go-.؉UM[֙3g#*JV'3`D333W\ɋ3w`|{شiӶmA6t<88eF.Iț>}!|;R ahcy€i`JbA&ܾ}!t@>~ ֭{Njʧ~z̙Ç沏{I^ʉ'O&HS@UAPiF E&91逵kB޻w˗#_ C]1RV{zСk&ޡ!j-))yW saxҥK`w˗/>|0ҙ?u65,xBa^tFGGt/_n6 RH[B]2Ѐb^W( B,Lf~.uJD^]FF#GAAA}}͛7GGG}>eD"H$Zo&͛2@<@~QU( Rbs=wVZMz7x5ER,[V=B*q]B8 a<ի\$AN}^qƄn۶烣45+ `پ@EF(JJvɁMWp\ ğ6-GA\b_N?;@T*HvT* u:`@Jl6+-WnO JDDϖ#:!cje:I%1R-pF互zv.{HG52^FFppDuuuh|縀!HnI8X |@K4MEEſ˿O;wtww  `:x@xh_ cqo~sjFƅ&1,}8O>x≣GJ-[HRHv>ZZZvoru׫p(o9!H zCAmz{gΝ;vPh_SNF-aтqq*0 Vgyw}iZV .AlInNNζmjkk҇H$jmm56lؐ 7qBCPtsiBؓfX|ԩӧOر#//1D[)'\zD"ٵkW KEPsNq@ gӁ?Z^^e 428  C۶m!ЈbU c$ba$82ӈv&*TerSl~[,twWa >4ݙ@ޟ?p˖-_Ο??Q*XB*A]Ȁ#q@B#<&IRi46{QGH18E.FOFVŋv{?Vp ^|Ŧ3g<àkmm }^b@q9nd2>EJ<m^}3IZ!hd2q0>VK.S8u*T*---xqԏV!)8:6ž`Xy7D; 5mm287(Paa]EYVN`b+ıi l)jЏ>R]ݨj9mD|>BԐ/Yl.,"X,~^Ba]]]cccii)Z,ӧO!|8Cf5pBl[(Fdl[RSN%8  @vS,C"FTP`-7`P+a1,ϰ#AvH CKFj**tKt: MS??$kjjL&,&wvvz`8f:^cZqDX0B>t]āG l6{X`)/4-F ZAhh2jUX a f\(C"/*9qSl魰e][I'#~C*|>܄H$|rE! -Q 0 N4ްAMkH@#]#`VEܕ@`D `\Q#L&# ® HW#~qfB!bqDZ:t:Z,:˗ߺukժU֭'#G999PxSjtr {ȹ\)RQ-v%`'a9^t ÙPl57*=;jq3\ `\ d2}_v`RyF! M&laa!c*tlٲŋSSSy'N02nݚH@~,HTTT߿h``ҍ }YX"pJ۷AlNwڵBӱcfܜH$JmfqE0FQ&)XVtAnӪ[K$\'S3J)DlyEЃsߙFw(qRkOOBhkkh4 '7z(P]odZZZ*Q pZǂ~qfNa.(+.l޼9Ď#e28R+Vvttp9.Bv\\޶%irlOe/->L_ahw4"Ј!d%BQJKKԩL&Sɗ$IAA[FjG\JNȠ{~tjh4KX  7o4 0#>e;38@FWjX-nuV wHhSU[rA|>ϷJFX$ɑVz&RO6|>x<_UWW۷^*u|di:BVzƍo߾ݻwKRX6YreKK˶m2vm'2L LOO9PP^}٬V;;;ٿ2 j{>UA`)b8$b4†|zϗ-y={B ϫjW82FnZ@"~EN@$ij`-$A*l7Aܑ#JBx_Qd$d2\.wPi[[[[[nHvd21'O`䠶vNy"v;'";>X+/P%8nw[[#d6_|EX.YРcq+Ȝ^/--edJvdСC@8tXVObJyS FSZZ07dP&1DdfP&`)'z'n5>>N&nVEw-(æLrڙj~=A% K/  `Dv)kWgZB3`00% xޔh'>rVJRC( I:^#[/(lٲv% KNND"Lx( TjA[v mmm첄@}}=d:M`qz2o_GtZA/oJX~=dIu:ၾ ,V%#@eaz<0wX1{bEw U$&vWD## NEDΖ,eIΝ qU7 R,Zu:.wK; BRÒ:\hȼD#-%83H4v 4Ӑ?VOl0 ̥%!k@[LER !>CI*f1{مFtbX 6$KPM)qk `蔍wuumɔ0J HRHP\/80ɠ9ttI$z=} Lz* z){snhSVA;EzGzd2)JN2qNwp3LSX&ANKFo??l6Fsq79v#T+ԕJ%fe2C<==-@}9kA;h]&0LNJqd"=0ߐv@֙RdWra Z=@OOhSaiǜvd7A kiJ3==KJ_W0t@y=L7cN;EGbZ) "Z7هsz)Mj7AoPpc9k G`"8DpraH8 Q0r tc¾V՚L&XӓF#PUPa4_raHL444@/Sq3,Pɴj*`GGGkh4V  8>@:뷷7440jstǘvl6fnf-֗cN;EݪPPPPP⠠AAA:S]IENDB`acm-6.0_20200416/doc/manual/acmdoc-ellipsoid.svg0000644000000000000000000004546313175033707017570 0ustar rootroot image/svg+xml Northpole P localhorizon localvertical z x A B lat y terrain sea a b acm-6.0_20200416/doc/manual/acmdoc_html-runway_step.png0000644000000000000000000000277510425636754021202 0ustar rootrootPNG  IHDR%PLTEٟIDATxQhGB(tPA\{iҐ5 iC؆)vRWRLc"Ő*XRķ, 3dٝݙ<ub*puD=Dy.T;N(+DurҲQ%.;PDuUv<*}Tf s:*U3SM/:USaS.4HQJp@Iv1jP' T@jBJUT'O LTSV՚FUN5`pS)pv*5MvzNTljj:Qe'SQ kTd׉KY^NzZL ^CQ%q~-qrr_c]S]^ofvYzJMG:e5'N ^n |uZ$AԫرSa|lکcNQ=+lev(>_vi"oFq+viϱy4']TKjTKZto]:7إS]:2e6u T[@uu T_K ?RPK1}l?kt pN k}H/4 _/T.)ەLKv6 iޮ Ieː^{cԐ4y핍 w1խ5Yo*EFЌzA@2Yͦfn&%x 4&EP9Rrn!/SofJEKhV&jcm)&v!14NکhMBnx q]氕 Y۠JhʣVT"ul`śy6̞%5xIQ7Kfu+TQ*oė|If܅fS_2e:GE^"Z\㧯U*l s!VkU-F= kr΋*?Z#Χ+_KjM7#Sj`W^N7#<7ßwd67kU_h\ pZ*Q'p$@%*Uf,CrQ%HQmAT6ש$*u %H|Fȳ%%+AL:5%w_K~꩹ JX%9*PNגB LSZJTԖSZ-SSILX]ʔa-J6e>c*W>1TBZJ ˆ؂zbj2'ux**Xhb*WvBKSk0 TZwb**aǽSo vK{' 16ooM_KԯX#⒬W=|]``^FX&7p>FP{< ;dPKT!3 TP$z$/%.D+<|{IENDB`acm-6.0_20200416/doc/manual/acmdoc-inside.html0000644000000000000000000017442413646045022017220 0ustar rootroot ACM - Inside the program

ACM - Inside the program

by Riley Rainey
updated by Umberto Salsi

Contents

Back to general contents
Geodetic coordinates and the WGS-84 ellipsoid
Defining new zones
Defining new scenes
Defining new aircraft
Frame and aerodynamics
Engine
Landing gear
Armament
Defining new objects
IEEE 1278.1 (DIS) compliance
Suggested further reading

Geodetic coordinates and the WGS-84 ellipsoid

The WGS-84 defines a reference shape for the Earth which is very close to the real shape of our planet; the concepts of local vertical, local horizontal plane, altitude and longitude are all referred to this ideal shape named geodetic ellipsoid. The figure below illustrates the right-handed Cartesian reference centered on the geodetic ellipsoid:


The WGS-84 geodetic ellipsoid. In this figure, P=[x,0,z].

The surface of this ellipsoid are the solutions of the equation x2/a2 + y2/a2 + z2/b2 = 1 where "a" is the length of the major semi-axis (or equatorial semi-axis) and "b" is the length of the minor semi-axis (or polar semi-axis):

a = 6378137.0000 m
b = 6356752.3142 m

These values, although very close to the real size of the Earth, are by definition of the WGS-84 model. Although very accurate measurements of the Earth are available and the actual shape of the Earth, named geoid, is known with very high precision, such an accuracy does not make much difference in most practical applications and is negligible. So in general any measurement of latitude, longitude and altitude, if not otherwise stated, is to be intended as geodetic, that is refereed to the WGS-84 ellipsoid.

The north pole is located at Cartesian coordinates [0,0,b] and the south pole is located at [0,0,-b]. The rightmost point [a,0,0] has latitude zero and longitude zero; the Greenwich meridian crosses this point joining the two poles.

For any point P=[x,y,z] in the Cartesian reference, a corresponding mapping to the geographic coordinates [lat,lon,alt] has to be defined. First, the local vertical is the line crossing P and perpendicular to the surface of the ellipsoid in its point A; the tangent plane to this point is the local horizontal plane at altitude zero. The local vertical line is the local plumb line. Note that the vertical line in this model, just like on our real planet, does not cross the center of the ellipsoid but intersects the x axis at some point B.

The latitude is defined as the angle between the local vertical and the xy plane. Calculating this latitude given the Cartesian coordinates is not simple; curious may look at the module src/dis/dis/earth in the sources of ACM. Latitudes range from 90S at the south pole, up to 90N at the north pole. The 0N latitude (or 0S if you prefer) is the equator.

The longitude is defined as the angle between the point P and the xz plane measured around the z axis: lon=atan(y/x). No surprises here. Longitudes range from 180 degrees west up to 180 degrees east; obviously the 180W meridian coincides with the 180E meridian. The 0E meridian (or 0W if you prefer) is named Greenwich meridian.

The mean sea level (MSL) is the surface of the ellipsoid; altitudes are measured as distance of the point P from the local horizon beneath it. All altitudes under ACM are intended referred to this MSL.

The local terrain altitude (measured vs. the MSL, of course) varies from point to point. ACM looks at the altitude of the nearest runway within 100 NM to determine the terrain altitude; if none found, it assumes zero. Negative altitudes are also possible.

Defining new zones

A zone is a range of longitude and latitude bound to the scenery file where the items inside the zone are listed. Sceneries are dynamically loaded and un-loaded by the program as necessary as the plane moves around the globe.

As the program starts and initializes, it looks for a zones file named zones.txt normally located under the objects/ directory. The zones files lists all the zones that are available to the program along with the range of geodetic coordinates the scene covers, for example:

# zones.txt file:
35N  40N  125W  120W  zones/usa/sfrancisco.txt
30N  35N  120W  115W  zones/usa/losangeles.txt
35N  40N  120W  115W  zones/usa/lasvegaswest.txt
#35N  40N  115W  110W  zones/usa/lasvegaseast.txt
30N  35N  115W  110W  zones/usa/tucson.txt
30N  35N  100W  095W  zones/usa/dallas.txt
40N  45N  075W  070W  zones/usa/newyork.txt
35N  47N  006E  019E  zones/europe/italy.txt
30N  35N  040E  045E  zones/middleeast/iraq.txt

The Italy scenery file has been compiled by hand. The Iraq scenery only contains some sample runways and it is otherwise incomplete. All the USA sceneries have been generated automatically from the FAA data base using the the program available under tools/faaairports; further zones covering the USA territory can be added in the same way.

The image below summarizes the currently defines zones, but other might be added in future release and others can be added by the player itself:


Zones defined by the sample zones file contents above.

As the simulated aircraft flies, any zone within 200 NM from the aircraft is loaded and made available to the simulation, so runways, radio stations and features therein defined enter the simulation: runways can be seen, radio stations can be tuned, etc. Zones left behind or too far away are un-loaded from memory.

The zones file is a simple text file organized by lines, each line representing a zone with 5 fields:

  1. Minimum latitude covered.
  2. Maximum latitude covered.
  3. Minimum longitude covered.
  4. Maximum longitude covered.
  5. File name of the scenery as path relative to this file. Example: "../../myscene.txt". The extension of the file does not really matter. White spaces are not allowed inside the path.

Latitude and longitudes can be indicated in several ways, here are some examples:

10N     10-20-30.400S     30.500S
10E     10-20-30.400W     30.500W

Fields must be separated by at least one white space. Apart from that, white spaces are ignored. Empty lines and lines beginning with '#' are ignored.

Notes and restrictions

  • The program gives error is the latitude or longitude fields are not valid or out of the range.
  • The program gives error if the file path of a scenery file cannot be resolved. The existence and readability of each scenery file is checked as the program starts; their content is checked only whenever the scenery file is loaded.
  • The program gives error if any two zones overlap.
  • The right and upper edge of the range does not belong to the zone, so a new zone can safely be defined next to the other.
  • Items defined in the scenery of a zone must lie inside the range of geographical coordinates of the zone. The points in the right and upper edges does not belong to the zone. The program gives a non-fatal error if an item lies outside the zone. For runways, the reference point is their center; for ILS, the reference point is the locator.

Note that for extended items, some of their points may lie outside the zone. For example, although the center of the runway must be in, one or both of its ends can be out; the locator of the ILS must be in, but the corresponding glide slope antenna can be out.

Note that the maximum latitude is 90N, the north pole; if a zone extends up to this limit, its upper edge is a point. Due to the rules above, the north pole does not belong to the zone, and there is no way to put an item at that exact location; this does not seem to be a severe limitation, though.

Don't try to fly over the poles! There is a know bug in the program that prevents to fly over the poles. Near to these locations (below 1 NM), the computation of the aircraft's next step fails and the aircraft tilts unpredictably, mostly crashing -- look at the comments in the src/dis/dis/earth for more.

There is no limit to the number of zones that can be defined. If each zone covers a 5x5 DEG range of latitude and longitude, considering only the range of latitudes [80S,80N], and since 70% of the Earth is covered by water, one may expect the maximum number of zone that might be needed to cover all the globe be about 692.

Defining new scenes

The scene file defines the contents of a zone. It should be stored as a ASCII text file. Every record occupies exactly one line, with leading and trailing spaces ignored. Fields in a record are separated by one or more spaces or tabulation characters. Empty lines and lines beginning with the character '#' are ignored.

Team Locations

Friendly and Opposing DIS participants may have a resupply base where to get fuel, munitions a repairs. Servicing starts as the aircraft stops close enough to the specified location. Typically, these location will be positioned and oriented at the end of a runway at the player's air force base airport. Example:

# Friendly air force base:
TEAM1_LOC 32-58-18.798N 096-50-16.604W 0 0
# Opposing air force base:
TEAM2_LOC 33-58-00.000N 097-50-00.000W 0 0
Fields:
0 Type: TEAM1_LOC, TEAM2_LOC
1 Latitude
2 Longitude
3 Initial Altitude MSL (ft) (this value ignored)
4 Initial Heading (degrees, true) (this value ignored)

Ground Color

An X11-style #RRGGBB color specification defining the color of the ground. Red, green and blue color components are hexadecimal value from 00 to FF. Example:

GROUND_COLOR #305030
Fields:
0 Type: GROUND_COLOR
1 Color

Runway record

The record entry of the ACM scene describing a runway can take two forms, depending on the available informations: the old one (RWY) and the new one (RWY2). The RWY format requires the geographic coordinates of both the ends of the runway. The RWY2 requires only the center of the runway and its true heading. The syntax of the runway identifier (field no. 2) must be of the form:

H[S]/H[S]

where H is the heading (an integral number between 1 and 36) and S is a capital letter ("L", "C" or "R"). The S part of the identifier is optional. A leading "0" in an identifier is allowed. The runway identifiers can be specified in any order.

Example of the RWY record format:
RWY ADS 15/33 644 7202 100 32-58-40.245N 096-50-25.820W 32-57-33.383N 096-49-56.608W
Fields of the RWY record:
0 Record Identifier: RWY
1 Three/Four letter airport code
2 Runway identifier
3 Runway Altitude (ft, MSL)
4 Runway Length (ft)
5 Runway Width (ft)
6 Near End Latitude
7 Near End Longitude
8 Reciprocal End Latitude
9 Reciprocal End Longitude
Example of the RWY2 record format (same runway):
RWY2 ADS 15/33 644 7202 100 32-58-06.81N 096-50-11.21W 160.0
Fields of the RWY2 record:
0 Record Identifier: RWY2
1 Three/Four letter airport code
2 Runway identifier
3 Runway Altitude of the Center (ft, MSL)
4 Runway Length (ft)
5 Runway Width (ft)
6 Latitude of the Center
7 Longitude of the Center
8 Runway geographical heading (DEG)

The model of the terrain simulated by ACM is very simple and efficient: the elevation of the nearest runway gives the local terrain altitude, the distance being calculated relatively to the center of the runway. Nevertheless, this behavior has a strange implication: between two runways at different altitudes there is a step line where the local altitude suddenly change. Crossing this step line taxing on the ground, the aircraft would crash its landing gear.

In the figure below the terrain to the left side of the step line has elevation 500 feet, while the terrain in the other side has elevation 510 feet. Unfortunately in this case we have a problem, since the step line crosses both the runways.


The problem of the step line crossing the runways.


The only practical solution to this problem is to keep all the runways of a given airport at the same exact altitude.

Navaid Record

A "NAV" record may be a VOR, a DME or a NDB. The TACAN stations of the ACM world behave simply as VOR/DME stations. VOR and ILS stations frequency ranges from 108.00 MHz up to 117.95 MHz.

OMARKER, MMARKER and IMARKER are just like NDB stations but with limited range (20 NM rather than 100 NM). NDB station frequency ranges from 200 KHz up to 529 KHz. This latter upper limit is a rather arbitrary value set in ACM, but most of the stations do not exceed 415 KHz.

Example:
NAV TTT VOR/DME 32-52-08.98N 097-02-25.81W 540 113.10 -
NAV FWH TACAN   32-46-17.46N 097-26-22.07W 663 108.7  024X
NAV RBD NDB     32-40-36.98N 096-52-15.91W 670 287    -
Fields:
0 Record Identifier: NAV
1 Up to four letters identifier
2 NAVAID Type: VOR, DME, VOR/DME, VORTAC (=VOR+DME), TACAN (=VOR+DME), NDB, OMARKER (=NDB), MMARKER (=NDB), IMARKER (=NDB)
3 Transmitter Latitude
4 Transmitter Longitude
5 Transmitter Altitude (ft, MSL)
6 VHF Frequency (MHz for VOR/DME/ILS stations and KHz for NDB)
7 TACAN channel number, or '-' if not available. Ignored by ACM anyway.

ILS Record

An ILS (instrumental landing system) is a LOCALIZER antenna (emitting the signal giving the right heading toward the runway) that may include also a glide slope antenna (GS, giving the deviation from the glide plane) and a DME antenna.


Typical ILS arrangement around the runway.


In the real world, each antenna has its latitude, longitude and elevation, but under ACM the simplified ILS record does not allow to specify the location of the DME antenna and provides only one elevation field whose value is shared among the LOCALIZER, the GS and the DME antenna; the distance displayed by ACM actually is the distance from the LOCALIZER. The recommended workaround is to indicate the elevation of the GS antenna to allow precise landing at the expected distance from the threshold; if not available, the elevation of the DME antenna should be indicated for closer match between displayed distance and the expected value; finally, the elevation of the LOCALIZER antenna can be indicated. Limitations and recommendations are detailed below.

The LOCALIZER antenna is normally located near the reciprocal end of the runway and the signal is normally aligned with the centerline of the runway. The exceptions are the LDA and SDF antennas which may deviate from the centerline of the runway or even be completely unrelated with any runway at all.

The GS antenna, when available, is normally located near the side of the runway threshold. The elevation of this antenna is critical in order to land at the specified spot on the runway, so its value should be indicated when available.

The DME antenna, when available, is always assumed to be coincident with the LOCALIZER antenna; there is no way to specify another location, so the distance displayed in the program may differ from the official navigation charts.


Type Description
LOCALIZER
LDA
SDF
LOCALIZER antenna only available. LDA and SDF are handled just like a LOCALIZER, the only difference is that the chart generator program is advised a corresponding runway end may not be available for this ILS and so no error should be emitted. The elevation field should be set with the elevation of the locator antenna.
ILS
LOC/GS
LOCALIZER and GS antennas both available. The elevation field should specify the elevation of the GS antenna, when available.
LOC/DME
LDA/DME
SDF/DME
LOCALIZER and DME antennas both available. LDA and SDF are handled just like a LOCALIZER, the only difference is that the chart generator program is advised a corresponding runway end may not be available for this ILS and so no error should be emitted. The elevation field should specify the elevation of the DME antenna, when available, or the elevation of the LOCALIZER otherwise.
ILS/DME LOCALIZER, GS and DME antennas available. The elevation field should specify the elevation of the GS antenna when available, or the elevation of the DME or of the LOCALIZER (in this order of preference).
Types of ILS record.

Example:
ILS 30 ILS IAIW 108.9 34-18-47.161N 097-01-38.280W 34-17-59.533N 097-00-35.018W 729.2 4.92 315.5 3.00
Fields:
0 Record Identifier: 'ILS'
1 Runway Identifier:
2 ILS Type: see table above
3 Four letter Identifier
4 VHF Frequency (MHz)
5 Localizer Transmitter Latitude
6 Localizer Transmitter Longitude
7 Glide Slope Transmitter Latitude ('-' for Localizer-only approaches)
8 Glide Slope Transmitter Longitude ('-' for Localizer-only approaches)
9 Glide slope antenna elevation when available, or localizer antenna elevation (ft, MSL)
10 Localizer beam width (DEG)
11 Localizer geographic bearing (DEG)
12 Glide slope angle (DEG) ('-' for Localizer-only approaches)

Features

Use feature records to place objects in an ACM scene. Example:
FEATURE features/tower.obv 32-58-04.800N 096-50-16.800W 644 0
Fields:
0 Record identifier: FEATURE
1 Object filename, either absolute or relative to the scene file
2 Latitude
3 Longitude
4 Altitude (ft, MSL)
5 Orientation angle (degrees, true)

Defining new aircraft

The ACM program loads all the aircraft models defined in the aircraft.txt file; this file is searched in all the specified object directories. Lines beginning with # are ignored by the program and can be used to add comments.

The inventory file may contain several include and aircraft records. The include record has syntax

include "some/other/file"

and allows to include the content of other inventory files in a more structured way. The path can be relative to the current inventory file. The aircraft record is described below in detail.

The stout-of-heart may be interested in creating new aircraft types. Some of this information must be generated by hand, but I did create a program to help me generate aircraft objects: GEDIT. GEDIT is a rudimentary Motif program that allows you to create 3-dimensional objects. It is available in the directory gedit of the distributed package.

The syntax of the aircraft record is more articulated. The program does not complain about missing numeric values, and they are assumed to be zero.

# Aircraft Inventory for ACM-6
# See ACM-Bibliography for further information about the sources of this
# information.
# MiG-29 Fulcrum
# MiG-29M information was derived from two sources: [Spick87] and [AirI Aug92].

aircraft "MiG-29" {
    Description "Mikoyan-Guryevich MiG-29M Fulcrum"
    Object "mig29.obj"

The visual description of an ACM aircraft is stored separately in V-library format and specified in the Object field. The name of the file may include a relative path which is resolved against the directory of the current file. This file describes a set of polygons that roughly approximates the shape of the actual aircraft. I used GEDIT to create most of the ACM aircraft objects. If not available, you may leave this parameter commented-out, but the UFO object will be displayed instead...

Frame and aerodynamics

    WingArea     400.0     # (wingS) Wing surface area (ft2)
    WingHalfSpan 18.87     # (wings) Wing half-span (ft)
    WingHeight    0.0      # (wingh) Height of the wing aerodynamic center
                           #    above the CM (ft)
    Chord        9.61      # (c) Mean geometric chord of wing (ft)
    AspectRatio  3.56      # (aspectRatio) aspect ratio
    EmptyWeight  22500.0   # (emptyWeight) Empty mass (lb)

These values are usually quoted with an aircraft's performance figures. The WingHeight is used to estimate the ground effect, and its value is positive for wings above the center of mass.

    # Max. wing load (lb):
    MaxLoadZPositive    273000  # 10*(EmptyWeight+50%*MaxFuel) (+10 g)
    MaxLoadZNegative    137000  # 5*(EmptyWeight+50%*MaxFuel) (-5 g)

The maximum vertical load, either positive climbing (MaxLoadZPositive) or negative diving (MaxLoadZNegative). If the weight the wings have to sustain is greater than that, the structure suddenly breaks and the aircraft gets destroyed.

For civil aircraft you may guess these values as 2.5*MTOW and 1.0*MTOW. Military aircraft, and fighters expecially, are reported to sustain up to some number N of positive "g" and some other number Q of negative "g". If not indicated, you should suppose at least 60% of the fuel contributing to the mass:

MaxLoadZPositive = N * (EmptyWeight + 60%*MaxFuel)
MaxLoadZNegative = Q * (EmptyWeight + 60%*MaxFuel)

where typical values for N range from 7 to 10, and Q=3.


The reference frame of the aircraft, with main inertial axes
and center of mass (CM) indicated.


    # (I(x,y,z)) Moments of inertia (lb ft2)
    Ixx 10000
    Iyy 75000
    Izz 80000

These are hard values to simple guess. I have grabbed values where they were available and simply guessed sometimes, too. Moments of inertia in an actual aircraft are not constant. Most notably, as an aircraft burns fuel, it's weight distribution, center-of-gravity, and moments of inertia change. In ACM, however, moments of inertia and CM do not change.

    # (cFlap) Lift due to flaps (yields Clift of 1.0 at max extension)
    CFlap 0.64279
    BetaStall     15.0    # (deg) Stall angle for rudder
    CFlapDrag     0.0467  # (cFlapDrag) Drag due to Flaps
    CGearDrag     0.03    # (cGearDrag) Drag due to Gear
    CSpeedBrake   0.03    # (cSpeedBrake) Drag due to Speed Brake
                          # at 90 degrees


    # (CDb) Drag Characteristic equation [Wave+body]
    # independent variable is mach number

    CDb {                 # (CDb) Drag Characteristic equation [Wave+body]
        # independent variable is mach number
        0.0, 0.020,
        0.2, 0.020,
        0.95, 0.015,
        1.05, 0.045,
        2.00, 0.030,
        10.0, 0.030
    }

In ACM, wave/body drag coefficient is a function of the airspeed expressed as a Mach number. Less drag makes for a faster aircraft. This function generally has a maximum near Mach 1.0. You probably should not change this table unless you really know what you're doing.
For the CFlap coefficient see below.

    CLift {               # (CLift) Lift-slope curve (vs alpha)
        -3.0, 0.0,
        -1.05, 0.0,
        -0.576, -2.199,
        -0.556, -2.23,
        -0.524, -2.199,
        0.524, 2.199,
        0.556, 2.23,
        0.576, 2.199,
        1.05, 0.0,
        2.0, 0.0
    }

In ACM, the coefficient of lift is purely a function of angle of attack (alpha). The CLift table gives the coefficient of lift for some values of the AoA "alpha". In the example above, the maximum coefficient of lift is 2.23 at 0.556 RAD = 32 DEG of AoA. Above this angle, the lift drops abruptly and the plane stalls. The coefficient of lift also depends on the current flap deflection angle according to the function:

CL = CLift(alpha) + sin(flaps) * CFlap

being CLift(alpha) the interpolated value given by the CLift table above. The total lift force is given by the equation:

L = 1/2 r WingArea V2 CL

where r is the air density (r=1.225 Kg/m3 at sea level), V is the airspeed and CL is the coefficient of lift.

    CnBeta { # (CnBeta) Yaw moment due to sideslip equation
        0, -0.08125,
        0.523540, -0.078125,
        0.785340, -0.0609375,
        1.047198, 0.125,
        1.58, 0.0
    }

In ACM negative yaw due to sideslip means that the aircraft is "weathercock stable", that is, the aircraft tends to yaw in a way that reduces the sideslip component.

    ClBeta { # (ClBeta) Roll moment due to sideslip equation
        0, -0.0125,
        0.43633, -0.015,
        0.78540, 0.125,
        1.58, 0.0,
        3.142, 0.125,
    }

A negative value means that the aircraft will roll in the opposite direction of the sideslip component, tending to make the aircraft more stable.

    CDBOrigin   0       # (CDBOrigin, CDBFactor) Drag due to sideslip
    CDBFactor   0.5
    CDBPhase    0       # (CDBPhase) sideslip drag phase (deg)
CDB values define the body drag added by sideslip on the aircraft.
    CYBeta      -0.85   # (CYbeta) Side-force from side-slip [dCY/dBeta]

CYBeta is the "lift" due to sideslip. This is the factor that allows to roll 90 degrees from level, kick the rudder a lot, and still stay level. Not all simulators take this into account.

    EffElevator   0.60 # (effElevator) Elevator effectiveness
    CmAlpha      -0.30 # (cmSlope) CmAlpha curve slope
    EffRudder     0.35 # (effRudder) Rudder effectiveness
    MaxRudder     20   # (maxRudder) max Rudder (deg)
    MaxAileron    20   # (maxAileron) max Aileron (deg)
    MaxFlap       20   # (maxFlap) max flap setting (deg)

    # (flapRate) flap extension rate (about 2 secs to fully extend flaps)
    FlapRate      10   # (deg/s)

    MaxSpeedBrake 80   # (maxSpeedBrake) max Speed Brake setting (deg)

    # (speedBrakeRate) rate of speed brake extension (2 secs to full ext)
    SpeedBrakeRate 40  # (deg/s)

    # (speedBrakeIncr) speed Brake increment per keystroke
    SpeedBrakeIncr 80  # (deg)

These values determine the characteristics of the aircraft's speed brakes (speed brakes are used in the air, wheel brakes are used on the ground). MaxSpeedBrake determines the maximum extension of the speed brake panels. SpeedBrakeIncr determines how far one press of the s key will increase the speed brake extension. It does not need to be an even increment of MaxSpeedBrake. SpeedBrakeRate determines how fast the brakes will deploy or retract.

    Clda  0.048 # (Clda) roll moment from aileron offset
    Cldr  0.004 # (Cldr) roll moment from rudder offset
    Clp   -0.27 # (Clp) roll damping
    Cmq   -8.0  # (Cmq) pitch damping factor
    Cnr   -2.0  # (Cnr) yaw damping factor

These factors characterize some of the roll, pitch and yaw characteristics of the aircraft. They are in the NACA form. Damping factors determine how quickly an aircraft returns to a steady state after some change in control input. Larger negative damping factors make for a more stable aircraft.

    # Speed limits at MTOW. Leave undefined or set to 0 if unknown.
    MTOW  32250.0    # maximum takeoff weight (lb)
    #Vs0     42.0    # stall speed, full flaps (kt)
    #Vs1     50.0    # stall speed, no flaps (kt)
    #Vfe    100.0    # max speed with flaps extended (kt)
    #Vno    145.0    # normal operation speed (kt)
    #Vne    164.0    # never exceed speed (kt)

These parameters allow the program to set or calculate several speed limits (IAS). These speed limits are used to draw the colored arcs on the air speed indicator. Every arc is displayed only if its start and end are known, and it is now drawn otherwise. These speed limits are also considered to simulate structural failures when exceeded, as detailed below. Leave commented-out or set to 0 the parameters that are unknown: the program will try to guess the missing values or simply will left them undefined if this guess is not possible.

MTOW is the maximum take off weight (lb).

Vs0 is the stall speed at MTOW, full flaps, at sea level. It is indicated by the beginning of the white arc in the anemometer. If undefined or set to zero, the program tries to calculate this value with the following formula:

Vs0 = sqrt( 2 MTOW earth_g / (r WingArea CL) )
where:
earth_g is the gravity acceleration at sea level.
r is the air density at sea level.
CL is the lift coefficient calculated with:
CL = maxCLift + CFlap sin(MaxFlap)
being maxCLift the maximum coefficient of lift as given by the CLift curve.

Vs1 is the stall speed at MTOW, without flaps, at sea level. It is indicated by the end of the short white arc in the anemometer. If undefined or set to zero, the program calculates this value with the following formula:

Vs1 = sqrt( 2 MTOW earth_g / (r WingArea maxCLift) )

Vfe is the maximum speed with flaps extended. It is indicated by the end of the longer white arc in the anemometer. Exceeding this speed with flaps deployed, also partially, causes a flaps failure that makes them unusable. If undefined or set to 0, the Vfe is unlimited.

Vno is the normal operation speed, that is the maximum speed in turbolent air conditions. It is indicated by the beginning of the yellow arc in the anemometer. Flying above this speed in turbulent air, a vertical wind gust of 30 ft/s would cause a vertical positive or negative acceleration above the maximum structural load capacity of the wings. If undefined or set to 0, the Vno is estimated with the following formula:

Vno = 2 earth_g (MaxLoadZNegative + EmptyWeight) / (r WingArea * b * MAX_GUST)
where:
b = 6.302 is the slope of the CLift curve in its linear range; this value was actually calculated for the C-172RG but it is also very close to that of the other aircraft models, so it is assumed as constant.
MAX_GUST = 30 ft/s is the conventional maximum vertical wind gust intensity assumed as reference to calculate Vno.

Vne is the speed that must never be exceeded. It is indicated by a short red line. Flying above this speed limit the aircraft may suffer a catastrophic structural failure. If undefined or set to zero, this limit does not apply.

    # (viewPoint) pilot's viewing location
    ViewPoint { 14.75, 0, -5.375 }

This is the location of the pilot's eye view outside of the cockpit.

    # (tailExtent) as we rotate, this part may drag
    TailExtent { -18.165, 0.0, 1.191 }

This defines where the aft-most lower part of the aircraft is located. This is the part of the aircraft that may scrape the ground as we rotate. This value is not currently used. Instead we simply limit up-pitch on the ground to 20 degrees.

Engine

    EngineType "GenericJetEngine"

    MaxFuel  9750  # (maxFuel) maximum internal fuel (lb)

    # engine lag factor (how fast does it respond to throttle changes
    EngineLag -3.0

    # Engine data based on updated RD-33K engines cited in [AirI Aug89].
    # (maxThrust) max static thrust, military power (lbf)
    MaxThrust 27000

    # (maxABThrust) max static thrust, afterburner on (lbf)
    MaxABThrust 44000

    HasThrustReverser 0 # 0=no (default), 1=yes

This section describes the engine and its performances. One among these types of engine can be chosen:

EngineType "NoEngine"
Basically, a glider. The remaining engines parameters are then ignored. This is the default.
EngineType "GenericPistonEngine"
Propeller driven aircraft with pistons engine. Its thrust is proportional to the current RPM and to the factor (ρh0)1.6, being ρh the air density at the current altitude and ρ0 the air density at sea level.
EngineType "GenericJetEngine"
Jet engine. Its thrust is proportional to the square of the current RPM and to the ratio between air density at the given altitude and air density at sea level.
EngineType "GenericRocketEngine"
Rocket engine. Its thrust is proportional to the indicated fuel pump RPM. Thrust does not depend on altitude, so this aircraft can fly up to the edge of the space before loosing directional control.

Maximum static military and afterburner thrust values can usually be found in documents that describe aircraft performance. Setting MaxABThrust to the same value of MaxThrust disable the AB for those aircraft that lack this device. For the conversions, remember that 1 pound = 1 lb g = 4.448 N = 0.4536 Kgf.

The HasThrustReverser parameter tells if the aircraft has a thrust reverse device. Set to 1 if available or 0 if not. If this parameter is missing the default is "no". With thrust reverse deployed and engine at the max power, the resulting reverse thrust is calculated as 50% of the max forward thrust.

    Thrust {        # (Thrust) Mach Number vs. thrust
        0,   1,
        1.7, 1.5,
        2.0, 0.84,
        5,   0.5
    }

    ABThrust {      # (ABThrust) afterburner thrust table
        0,   1,
        0.5, 1,
        1,   1.21,
        1.7, 1.7,
        5,   1.64
    }

The Thrust and ABThrust corrects the static thrust value for the aircraft's Mach number. Unless you have hard information about this, leave these fields alone. The ABThrust table is ignored when the AB device is disabled.

    # (spFuelConsump) specific fuel consump(lb fuel/lb T x hr)
    SpFuelConsump    0.68

    # (spABFuelConsump) AB specific fuel consump(lb fuel/lb T x hr)
    SpABFuelConsump  2.55

These fields define the specific fuel consumption (fuel consumed per pound of thrust per hour).

Landing gear

    # Landing Gear control parameters
    GearRate   30   # (gearRate) gear extension rate from 0 to 90 DEG (DEG/s)
    MuStatic   0.08 # (muStatic) static coeff of friction no-brakes
    MuKinetic  0.05 # (muKinetic) moving coeff of friction no-brakes
    MuBStatic  0.7  # (muBStatic) static brakes-on
    MuBKinetic 0.6  # (muBKinetic) moving brakes-on

These four values characterize the amount of friction that the wheels generate when in contact with the ground. If F is the force (usually a weight) that load a wheel, then F*MuStatic is the friction force when the wheel is at rest; F*MuKinetic when the wheel is rolling. MuBStatic and MuBKinetic have the same meaning with the only difference that the brakes are on. The maximum theoretical value of any of these is 1.0.

NOTE 1. In our landing gear, only the wheels of the main gear have brakes; the nose wheel can't brake.

NOTE 2. The MuKinetic and MuBKinetic are probably misnomers as these coefficients are more commonly known as "MuRolling" instead. Proper "kinetic" coefficients are involved when the wheel skids over the runway, either longitudinally (blocked brakes) or laterally. In ACM brakes never block, but still wheels can skid laterally over the runway. The coefficient involved in the skidding behavior is currently hard-coded in the gear.c module. Moreover, the gear breaks when the lateral force applied to the wheel exceeds the empty weight of the aircraft. This limit too is hard-coded into the source program.

    MaxNWDef   72   # (maxNWDef) maximum nosewheel deflection (deg)

The MaxNWDef is the maximum deflection angle of the nose wheel. If this figure is available from the characteristics of the airplane, the figure and the formulas below allows to calculate the minimum turning radius.


Minimum turn radius of turn on the ground.


If Q is the distance between the contact point with ground of the nose wheel and the middle point between the contact points of the main landing gear, then this latter middle point draws a circle or radius:

r = Q / tan(MaxNWDef)

while the contact point of the nose wheel draws a circle of radius:

R = Q / sin(MaxNWDef)

Sometimes the maximum deflection of the nose wheel is not reported, but a minimum turning radius is provided instead. Normally this is defined as the radius of the smallest cylinder inside which the aircraft can perform a full 360 degrees turn. From the figure above we see the this value could be estimated as the turn radius of the center of the main landing gear (r) plus the half-wings length:

MinRadius = WingsLength/2 + r

from which:

MaxNWDef = atan( Q / (MinRadius - WingsLength/2) )

Several "minimum turning radius" could be indicated for a given aircraft referring to:
 1. the pilot using the pedals only;
 2. the pilot using both pedals and differential brakes;
 3. the pilot using the steering crank handle (where available);
 4. the ground crew with the nose wheel hooked-up.
Obviously, we are interested to the case 1 only.

    # (rm) location of right main gear attachments {x,y,z} (ft)
    Rm { -2.2, 4, 1.702 }

    # (rn) location of nose gear attachments {x,y,z} (ft)
    Rn { 9.395000, 0, 1.807 }

    Km    18220.7 # main oleo spring factor (lbf/ft)
    Kn    4278.34 # nose oleo spring factor (lbf/ft)
    Dm    10000   # main oleo damping factor (lbf s/ft)
    Dn    80      # nose oleo damping factor (lbf s/ft)
    Gm    1.5     # main strut length with tire (ft)
    Gn    1.5     # nose strut length with tire (ft)
    CmMax 1.0     # (cmMax) main max oleo extension distance (ft)
    CnMax 1.5     # (cnMax) nose max oleo extension distance (ft)

Parameters of the landing gear.


The parameters Rn and Rm give the positions of the nose and main gear attachments, while Gn and Gm are their total length including the tire but excluding the oleo extension CnMax and CmMax. As a first approximation of these parameters, you can take these values (all the distances are measured in feet, 1 ft = 0.3048 m):

Rn.x
Attachment point of the nose landing gear strut, x coordinate (ft). Positive for tricycle landing gear, negative for bicycle landing gear.
Rn.y
Always zero.
Rn.z
Attachment point of the nose landing gear strut, z coordinate (ft).
CnMax
The oleo + spring part of the nose gear extends from zero up to this length (ft).
Gn
Length of the rigid part of the nose landing gear strut (ft). The total length of the nose gear strut including tire is then this value plus the current extension of the oleo part.
Rm.x
Attachment point of the right main landing gear strut, x coordinate (ft). Negative for tricycle landing gear, positive for bicycle landing gear.
Rm.y
Attachment point of the right main landing gear strut, y coordinate (ft). Always positive; the left main gear it is assumed to be at -Rm.y but with the same Rm.x and Rm.z components of the right main gear.
Rm.z
Attachment point of the right main landing gear, z coordinate (ft).
CmMax
The oleo + spring part of each main gear strut extends from zero up to this length (ft). About half foot for light planes, and up to 1.5 feet for larger ones.
Gm
Length of the rigid part of the each main landing gear strut (ft). The total length of each main gear strut including tire is then this value plus the current extension of the oleo part.

Every wheel of the landing gear is attached to the aircraft through a spring (K) and a damper (D). The parameters referring to the main landing gear are the sum for the left and right gear, so the actual parameter for each wheel strut is half the value reported in the inventory (see the picture above).

The landing gear parameters are difficult to estimate. We will give some simple rule to set good starting values based on reasonable assumptions.

Km
Total spring factor for the left+right main landing gear (lbf/ft), then each spring is half this value. The main landing gear must sustain most of the weight of the aircraft, so a reasonable rule is to set this spring (left + right) so that the strut be half compressed with the aircraft in its empty weight:

Km = 2 * EmptyWeight / CmMax

For example, if the empty weight is 10000 lbf and the strut maximum extension is 1.5 ft, we have Km = 13300 lbf/ft.

Kn
Nose spring factor (lbf/ft). The nose spring must sustain the static weight that depends on its distance from the CM. Moreover, on bicycle landing gears the nose must sustain also the braking. Here to we will assume the oleo damper be half compressed while the aircraft is braking at its empty weight. The resulting quite complex formula is:

Kn = 2 * EmptyWeight * (-Rm.x / (Rn.x - Rm.x) + MuBKinetic * (Rm.z + Gm + CmMax)/Rn.x) / CnMax

Note that the distances that appear in this formula have their sign, so usually Rm.x is negative while Rn.x is positive. For bicycle landing gear we can neglect the braking effect by assuming MuBKinetic=0 in the formula above, but consider that these aircraft usually have an higher static pitch for which this simple formula is not valid anymore.

Dm
Total damping factor for the left + right landing gear strut (lbf s/ft). The principal role of the damping factor in the main gear is to adsorb harder landings at high descending speed, when the spring cannot help because is still not compressed at all. 600 fpm is usually the maximum allowed vertical speed for which aircraft are tested. That means that the force produced by the damper when the wheels of the main gear hits the ground is F=Dm*600 fpm. Since in ACM there is an hard-coded vertical limit to the main gear equal to 1.5 times the empty weight for each leg of the main landing gear, the following formula gives a safe value for Dm:

Dm <= 0.2 * EmptyWeight

For example, if the empty weight is 10000 lbf, then the damping factor should not exceed 2000 lbf s/ft.

Dn
Damping factor for the nose landing gear strut (lbf s/ft). A good starting value might be Dm calculated above.

The program GEDIT can be used to determine correct landing gear locations. I then use the program tools/balance.c to generate the appropriate values for the spring factors for each new aircraft type that I create. Note that neither GEDIT nor balance.c currently calculate oleo damping factors.

Choosing the right values for the landing gear is difficult, and the program may terminate abruptly with one of the following messages related to the landing gear:

Nose/left/right gear smash.
An excessive vertical load has fully compressed the suspension transferring that load directly to the aircraft frame and causing a permanent, fatal damage. Possible fixes: increase the spring factor; increase damping factor.
Nose/left/right gear collapsed under too hight vertical load.
The landing gear transferred an excessive vertical load to the aircraft's frame causing a permanent, fatal damage. The maximum vertical load the each leg of the landing gear can sustain is hard-coded in the source to be the empty weight for the nose, and 1.5 times the empty weight for each of the left and right legs. Possible fixes: decrease the spring factor; decrease the damping factor.
Nose/left/right gear broken under too high lateral force.
The wheel transferred an excessive torque due to a lateral force. This is typically caused by an excessive landing pitch, or excessive bank angle, or by steering at high speed. The maximum lateral force each wheel can transfer to the frame is hard-coded in the source to be the empty weight. Fix: touchdown should always be performed at low vertical speed with zero bank angle and reasonable low pitch; do not brake while steering.

Armament


    StructurePoints 15 # (structurePts) maximum structural damage

This value characterizes how much damage can be absorbed by the aircraft before it starts falling to the ground (drones simply explode). A detailed description of the meaning of this field is available as a comment to the objects/munition-map.txt file, where all the recognized warheads are listed along with their effectiveness.

    # Radar data based on N-019 Pulse Doppler radar cited in [AirI Aug89].
    RadarOutput   15000 # (radarOutput) radar output (watts)
    RadarTRange   38    # (radarTRange) tracking radar range (NM)
    RadarDRange   55    # (radarDRange) detection radar range (NM)
    TEWSThreshold 0     # Radar Warning Receiver threshold (watts)

If you have any information about the radar capabilities of the aircraft, here's the place for them. The detection range is the maximum range that a target can be seen on radar. No attempt is made to take into account the radar cross section of the target. The tracking range is the range required to get a lock onto the target.

    # Weapons
    WeaponCount 9

Number of weapon hard-points. The following fields are ignored if this value is set to zero, so they can be omitted if the aircraft does not carry weapons at all.

    HardPoint0 { 7.0, -4.0, 0.0 }
    HardPoint1 { 0.357, 15.6, 0.0 }
    HardPoint2 { 0.357, -15.6, 0.0 }
    HardPoint3 { 1.5, 9.0, 2.0 }
    HardPoint4 { 1.5, -9.0, 2.0 }
    HardPoint5 { 1.5, 8.0, 1.5 }
    HardPoint6 { 1.5, -8.0, 1.5 }
    HardPoint7 { 1.5, 10.0, 1.5 }
    HardPoint8 { 1.5, -10.0, 1.5 }

These are the XYZ locations relative to the aircraft CM of each weapon. By defining these, each missile or cannon fires from its appropriate location on the aircraft.

    WeaponStation   0 "M61A1"   500 0   0
    WeaponStation   1 "AIM-9M"   0   0   0
    WeaponStation   2 "AIM-9M"   0   0   0
    WeaponStation   3 "AIM-9M"   0   0   0
    WeaponStation   4 "AIM-9M"   0   0   0
    WeaponStation   5 "AIM-9M"   0   0   0
    WeaponStation   6 "AIM-9M"   0   0   0
    WeaponStation   7 "AIM-120"  0   0   0
    WeaponStation   8 "AIM-120"  0   0   0
}

The WeaponStation directive defines the type of weapon located at each hard point. The first argument is the number of the hard point, that ranges from 0 up to WeaponCount−1. The second argument is the name of the weapon. Then three integer numbers follow whose meaning depends on the specific weapon. The table below summarizes by examples all the available weapons:

Example Notes
WeaponStation 0 "M61A1" 500 0 0
M-61A1 "Vulcan" cannon. 500 is the number of rounds initially supplied to the cannon. The other two numbers are ignored.
WeaponStation 1 "AIM9M" 0 0 0
AIM9M "Sidewinder", infra-red guided, short range, air-to-air missile. The other 3 numbers are ignored.
WeaponStation 2 "AIM120" 0 0 0
AIM-120 "AMRAAM", radar guided, medium-range, air-to-air missile. The other 3 numbers are ignored.
WeaponStation 6 "MK82" 0 0 0
Mark 82 250 lb standard drop bomb. The other 3 numbers are ignored.

Remote aircraft may submit detonation PDUs claiming you have been hit by something. The objects/munition-map.txt lists all the recognized munitions by their DIS entity type, along with their effectiveness.

Defining new objects

An "object" can be the shape of an aircraft (field "Object" of the aircraft inventory file) or a feature of the scene file (record "FEATURE"). The format of the object file, described here, is copied from the ACM Flight Simulator Frequently-Asked Questions List maintained by Brad Bass (bass@convex.com).

The first line is the object name.

The 2nd line has two integers which represent the number of points and the number of polygons in the object.

Then, the points are listed, one per line, with the point id number followed by the X, Y and Z coordinate (North, East, Down). The units are feet.

Finally, the polygons are listed as color, number of corners, and the list of point id numbers. The color may be expressed as a single color or as a front and back color. Also, the polygon can be flagged as "one-sided" -- that is visible only from the front.

For example:

pyramid                  # the object name
5 4                      # the point count and polygon count
1 28000 0 0              # the
2 0 16000 0              #   points that
3 -35000 0 0             #     describe
4 0 -14000 0             #       the
5 0 0 -8200              #         corners
#788b63      3  1 2 5    # side 1 - color (X-style), cornercount,
                         #   corner list
violet       3  2 3 5    # side 2
(blue red)   3  3 4 5    # side 3 - front is blue, back is red
(green clip) 3  4 1 5    # side 4 - one-sided polygon

IEEE 1278.1 (DIS) compliance

ACM emits and recognizes the following DIS PDU Types:



Entity State

Fire

Detonation

Electromagnetic Emission



The ACM program may simulate several entities, including the aircraft the user is flying on, each missile it fires and possibly other entities. For each entity it simulates, the program sends a state packet to all the other participants every 4.8 seconds along with the dead reckoning algorithm each remote program must apply in the meanwhile. The program also sends an updated state packet when it detects the actual state of the entity deviates from the stated dead reckoning method for more than a given amount.

The following dead reckoning methods are recognized:

Name DIS enumeration Description
Other 0 NOT SUPPORTED.
Static 1 Entity does not move.
FPW 2 Entity moves at constant speed.
RPW 3 Entity moves at constant speed and rotates at constant speed.
RVW 4 Entity moves at constant acceleration and rotates at constant speed.
FVW 5 Entity moves at constant acceleration and does not rotate.
FPB 6 NOT SUPPORTED.
RPB 7 NOT SUPPORTED.
RVB 8 NOT SUPPORTED.
FVB 9 NOT SUPPORTED.
RPW 10 NOT SUPPORTED.
RVW 11 NOT SUPPORTED.

For methods not supported, the state is not updated and the remote entity looks moving by steps.

Entities managed by ACM emit entity state PDU’s specifying the RPW(3) dead reckoning method. No articulation parameters are currently sent by entities managed by ACM. As with most current DIS-based simulations, altitudes are expressed as heights above the WGS-84 ellipsoid, not as heights above the geoid. Dead reckoning threshold values are hard-coded in the src/acm/manifest.h file:

DescriptionValue
Maximum time between Entity State PDUs4.8 seconds
Dead Reckoning Cartesian distance error3 meters
Dead Reckoning angular orientation error2 degrees

When operating in IEEE 1278 mode, the default UDP port number for PDU transmission is 3000.

The Transfer Control Protocol

ACM supports an experimental DIS 2.1.4++ control request protocol. It permits it to “take over” aircraft of similarly enabled applications. For ACM to take over an aircraft, it must have model information in the “inventory” file describing the characteristics of that aircraft type. Those aircraft entities will be marked with an asterisk (*) in the left margin of the stealth browser display. Double click an aircraft entity id to take control.

Transfer Control Request PDU

Field
Size
(bits)
Transfer Control Request PDU fields
96 PDU Header

Protocol Version—8-bit enumeration

Exercise ID—8-bit unsigned integer

PDU Type —8-bit unsigned integer

Protocol Family—8-bit enumeration

Timestamp—32-bit unsigned integer

Length—16-bit unsigned integer

Padding—16-bits unused

48 Originating Entity ID

Site—16-bit unsigned integer

Application—16-bit unsigned integer

Entity—16-bit unsigned integer

48 Receiving Entity ID Site—16-bit unsigned integer

Application—16-bit unsigned integer

Entity—16-bit unsigned integer

32 Request ID 32-bit unsigned integer
8 Required Reliability Service 8-bit enumeration
8 Transfer Type 8-bit enumeration
48 Entity ID to be Transferred Site—16-bit unsigned integer

Application—16-bit unsigned integer

Entity—16-bit unsigned integer

32 Number of Record Sets (R) 32-bit unsigned integer
96 +
(L1 x Q1)
+ P1
Record Set #1 Datum ID—32-bit enumeration

Record Set Serial Number—32-bit unsigned integer

Record Length—16-bit unsigned integer (L1)

Record Count—16-bit unsigned integer (Q1)

Record Values—(L1 x Q1) bits

Padding—P1 bits

·

·

·

96 +
(LR x QR)
+ PR
Record Set #R

Datum ID—32-bit enumeration

Record Set Serial Number—32-bit unsigned integer

Record Length—16-bit unsigned integer (LR)

Record Count—16-bit unsigned integer (QR)

Record Values—(LR x QR) bits

Padding—PR bits

Total Transfer Control Request PDU size:

320 + Sumi=1..R(96 + (Li x Qi) + Pi) bits

where R is the number of Record Sets.

ACM currently ignores record sets in a transfer control PDU.

Transfer Type

This section specifies the 8-bit enumeration for the Transfer Type field of the Transfer Control PDU.



Field Value Nature
0 Other
1 Controlling application requests transfer of an entity
2 Application desiring control requests transfer of an entity
3 Mutual exchange / swap of an entity
4 Controlling application requests transfer of an environmental process
5 Application desiring controls request transfer of an environmental process
6 Mutual exchange of an environmental



Assuming Ownership



Accepting Ownership by Request

Another feature of ACM’s transfer control protocol support is that other applications may request that ACM take control of an aircraft that the other application controls.

Suggested further reading

  • 3D Graphics Programming for Windows 95
    by Nigel Thompson ISBN 1-57231-345-5
  • Fighter Combat
    by Robert L. Shaw ISBN 0-87021-059-9
  • Aircraft Control and Simulation
    by Brian L. Stevens and Frank L. Lewis ISBN 0-471-61397-5
  • 1278.1-1995 IEEE Standard for Distributed Interactive Simulation--Application Protocols ISBN 1-55937-572-8
  • The Surveying Handbook, second edition
    edited by Russel Brinker and Roy Minnick ISBN 0-412-98511-X

...and the source code of ACM which contains lots of interesting comments!

acm-6.0_20200416/doc/manual/acmdoc_html-landing-gear.png0000644000000000000000000001116210765065201021126 0ustar rootrootPNG  IHDRm?iL PLTEG2 $IDATx͎h $0I`2o?SC'BX42S$K2!Lw[EVX鈴Cfd:zDޓF~DDkb ;΄]7?D8yp ЁB˞@W\vdMYpc "gQNjXF)NtÞlT { V>{ H><p!4'eѦ~{!p{ h\JtPK5Np ѵÖp9Nk vH|1jlƇQ:$:wY 8V INj.# L%_mۄt̵@+@oUN[ 1Pu837V Ry\LPTpΥXr"ALnZXdc= NiwoSpVp 6iQf"YkVyWW[MoUV1 =?XOՄEM|nR~pM&빊pZ}vs2vD+mKY8 ɥ"lr RUpkq":ѪCˍe#녝Kp~\NY ErƲ}[]NY&Xl]5k7mSTn%M Wٳ="}qYu "V%ܟsd–W̥:T]9GG'B7Մā*2;!Vu}Nbu܁۔uY\8RQmU1t$ 64ypG%+n]9QW{M\j_PpS-8Wݵ&9uE3ց{\o8]t87LkU4(& qp$ w~/y\iY !8fdƞR~LUfYށ+d,SpjwMe8ҍK7[z8R| _.7G8aFt@Y{( nqp;p֗b81Apۣ'&rB9Ne/ٛ윜 _׏Ip}5,^fG |%֘p|pw"~7,p?zWy"F(P?}΃<Gޅ SU݁N?m i8AMLU9V F:Gy,8-3kքww&=m! a%Prඑ+]2'X!c|{lˎc$_rԷsߣܾm "GyՅ{FA'g{H._.##9ի/\ 8ICUtЪIS8 ԵzaG87z.wwi8_!|[\Pn NЏ8'P*pfg_>#8P՛p[zf WUp)UG,/C;&;Cjzܿ- *‰FW8#&/ypNo(˪.E wwN-I5  ]Ap$8`^+4pe·S_1O7ᜂ8^yI8wd|}N 1JvEO2C=}  ƛC=D w ?i8TC))P{Dz5cvN(.rsjG휱o Ն융oEgPjR-Fr B;fV}*& 1; %-|tp5~TA%8qUr0pf>`5΍?B8)&\lfvvN|YYf+TݲG0p׺:jܰEGU{t윕\Rov*nVn.`Y}mV ힾs_0pGU}6de;Wji^^F'.98oP]YC^p3ap~1ui"Zr]ٿV.lf~9sW< oUO"n&¸]ʈuG@.p \Ʊ+|DecKӶ l^£p S}¥I 8o.-&QI~qp;.eNJ63XI}pX H1X%0LAx8Qv)p sR,68U ^3MS}LL >e]'옴rT\A^~Ћ*s.r zp2xE!Mi\ j尔7ֵ C8|8Ȝ4"18Pt)׈RfpEpY/dN0[wJpJ[?C8uD8F86y( G78*.%-a۟ke9QDЬȹ59`K_m yHS"!W3ɔP.r^%\.4'/)0'/+Keu \)9*:p9ʶUaQ^ 7'R]|~r4{Q%8_tϰ2,xXL9vY\D~uMV;Y 3'D5QunR !zpc9yik͜4mn~M8Gtfb4lWM8DZ_۾bU͜Gm[knUtL.瘡pcrr3HW[t˹p֜P~˹&6Xs#-cGv9w[Κ΋eԇ3dp?áDSdq8M\ץπ+P|\SwϞg_i{\N'2|\6{\as>Yp[u: v; 'b!%(<8`S'Gt&86̣N*"w{"/Y4|:ܞi/Ζ5Y2IENDB`acm-6.0_20200416/doc/manual/acmdoc_html_hsi_rnav-usage.obj0000644000000000000000000000665610666003515021575 0ustar rootroot%TGIF 4.1.43-QPL state(0,37,100.000,260,160,1,4,0,9,1,1,1,0,1,6,1,1,'Times-Bold',1,46080,0,0,0,10,0,1,1,1,0,16,0,0,1,1,1,1,1088,1408,1,0,5760,0). % % @(#)$Header$ % %W% % unit("1 pixel/pixel"). color_info(11,65535,0,[ "magenta", 65535, 0, 65535, 65535, 0, 65535, 1, "red", 65535, 0, 0, 65535, 0, 0, 1, "green", 0, 65535, 0, 0, 65535, 0, 1, "blue", 0, 0, 65535, 0, 0, 65535, 1, "yellow", 65535, 65535, 0, 65535, 65535, 0, 1, "pink", 65535, 49344, 52171, 65535, 49344, 52171, 1, "cyan", 0, 65535, 65535, 0, 65535, 65535, 1, "CadetBlue", 24415, 40606, 41120, 24415, 40606, 41120, 1, "white", 65535, 65535, 65535, 65535, 65535, 65535, 1, "black", 0, 0, 0, 0, 0, 0, 1, "DarkSlateGray", 12079, 20303, 20303, 12079, 20303, 20303, 1 ]). script_frac("0.6"). fg_bg_colors('black','white'). dont_reencode("FFDingbests:ZapfDingbats"). page(1,"",1,''). group([ box('black','',244,307,268,331,2,1,1,330,0,0,0,0,0,'1',0,[ ]), polygon('black','',7,[ 244,319,250,307,262,307,268,319,262,331,250,331,244,319],2,1,1,0,331,0,0,0,0,0,'1',0, "00",[ ]) ], 344,0,0,[ ]). group([ box('black','',468,244,492,268,2,1,7,348,0,0,0,0,0,'1',0,[ ]), polygon('black','',7,[ 468,256,474,244,486,244,492,256,486,268,474,268,468,256],2,1,7,0,349,0,0,0,0,0,'1',0, "00",[ ]) ], 347,0,0,[ ]). poly('black','',3,[ 520,356,480,256,368,188],0,2,1,357,0,0,0,0,0,0,0,'2',0,0, "0","",[ 0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[ ]). text('black',504,251,1,0,1,126,16,40,12,4,2,0,0,0,2,126,16,0,0,"",0,0,0,0,263,'',[ minilines(126,16,0,0,0,0,0,[ mini_line(126,12,4,0,0,0,[ str_block(0,126,12,4,0,0,0,0,0,[ str_seg('black','Courier-Bold',1,80640,126,12,4,0,0,0,0,0,0,0, "WP=75 /24.5 NM")]) ]) ])]). text('black',550,246,1,0,1,6,11,100,9,2,2,0,0,0,2,6,11,0,0,"",0,0,0,0,255,'',[ minilines(6,11,0,0,0,0,0,[ mini_line(6,9,2,0,0,0,[ str_block(0,6,9,2,0,-1,0,0,0,[ str_seg('black','Courier-Bold',1,57600,6,9,2,0,-1,0,0,0,0,0, "o")]) ]) ])]). poly('black','',2,[ 256,320,480,256],0,1,1,311,0,6,0,0,0,0,0,'1',0,0, "0","",[ 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ ]). oval('black','',364,184,372,192,2,1,1,360,0,0,0,0,0,'1',0,[ ]). oval('black','',516,352,524,360,2,1,1,361,0,0,0,0,0,'1',0,[ ]). text('black',536,348,1,1,1,9,15,362,12,3,2,0,0,0,2,9,15,-1,0,"",0,0,0,0,360,'',[ minilines(9,15,-1,0,1,0,0,[ mini_line(9,12,3,-1,0,0,[ str_block(0,9,12,3,-1,-1,0,0,0,[ str_seg('black','Times-Bold',1,69120,9,12,3,-1,-1,0,0,0,0,0, "A")]) ]) ])]). text('black',384,180,1,1,1,9,15,364,12,3,2,0,0,0,2,9,15,0,0,"",0,0,0,0,192,'',[ minilines(9,15,0,0,1,0,0,[ mini_line(9,12,3,0,0,0,[ str_block(0,9,12,3,0,-1,0,0,0,[ str_seg('black','Times-Bold',1,69120,9,12,3,0,-1,0,0,0,0,0, "B")]) ]) ])]). text('black',307,315,1,1,1,59,15,370,12,3,2,0,0,0,2,59,15,0,0,"",0,0,0,0,327,'',[ minilines(59,15,0,0,1,0,0,[ mini_line(59,12,3,0,0,0,[ str_block(0,59,12,3,0,-1,0,0,0,[ str_seg('black','Times-Bold',1,69120,59,12,3,0,-1,0,0,0,0,0, "VOR/DME")]) ]) ])]). poly('black','',2,[ 510,331,492,287],1,2,1,383,0,6,0,0,0,0,0,'2',0,0, "0","",[ 0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[ ]). poly('black','',2,[ 460,244,420,220],1,2,1,384,0,6,0,0,0,0,0,'2',0,0, "0","",[ 0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[ ]). polygon('black','',18,[ 504,307,502,310,502,313,493,314,493,317,502,317,502,321,500,321, 500,323,508,323,508,321,506,321,506,317,515,317,515,314,506,313, 506,310,504,307],2,1,1,0,406,0,0,0,1,0,'1',0, "00000",[ 493,307,493,307,515,323,918.036,-396.497,396.497,918.036,-2,6],[ ]). acm-6.0_20200416/doc/manual/acmdoc_html-steer.png0000644000000000000000000004650413646045022017730 0ustar rootrootPNG  IHDRz*%sBIT|d pHYs  tEXtSoftwarewww.inkscape.org< IDATxy|\eǿϝ5% eQP6I@ȋ₾*ꋊB`-isЦ;ݛfǹYw&'ܹ$3{s`0 `0 `0 `0 `0 `0 `0 `0 `0d e(p&`z<7sO{<~& qӀ!N408.uϣSg$pPlK0 <pq7 b/<џ,V;AY`NFspD㓀F/`{xB?Ec-#ǎ Mk?$-Ȁ68??X~`06Q1}x(nAX$ 4_qˁ#>AĽ? X^Es> pu5{znGdG!#zC`| Ѭr( a$>CG oVgԸ>?o!gyY1!)CEˀ B<\st$PĺAֹ..@~JV`-lCދs`0ꆩR&KH "eHSrxJ&? Cם#/!5AD/_9.>)886#sl2 B*7ӎIHH!oVNA^|QX9HÖ-ql #ЩȚBZ=!)={ЕO4X?uH}8W<؟H~\`0xۼHH_LyC:t B{d՝v ݈T4 :!}"$;3SDBj{.EB-@>s%}., C0Iʐ"O=C'FBIxmth%;Kp 0@EBoOplHst(B3\B@GݟpT⥑G:a#VGb<d77ށ*lD ?yRM<=Fz`+ KmmP(4 L,k8CRÐ@x̚5k}>>~VuS8nZ7UVVgL1 H%H!0aHNoR8_Ep$NK6 iOA~ 9}>)p3ңd,`7=ZК5kBֳRS O;n:vћ ^U)U^ZZ,ܗG#14F817zī2hCd ;gIGg Y?ӑC򒆆hZ)U@)xx )Lw[oĉ==C6L555uvvmoot(QWJbQ`RyHř3g6w!^(D_@>HHF{=,> ,COt -kzCP[[[?RT$uRPk9h٤Iy>]bŠc9Ʋg#Zԣ_-z2A'x%dWodP uo'#l:;H^s,k!F gŊJJJWJ}x}(=;qĶ~^"%/>dljooe#y.k:$<$Qj ``hl(T+iqq2 A(k֬9, ]YVT \)BHSٰ/K(ҧ`0ħvp}}|۶mk/Zg1zmڶt\T|Lg$$ߺ_)`r Y-`>7~FˁǐVfi4cACCm;mԔ&w٭ڲm<@d֬Y?ϊsQtqflp:߆=mpKARےR.DZ@눠T5Ŷm`v5SÇ_x}uuukkk+H>߆?,'+M8pyS~~)\H_ }1ciCZvq3"ޗq |◈ǖ|=|- ^bFׯ{k!ڴieo'7USs?:*{Źs|> !3!m,xYt}Y*lBGk=W)eY} 8ԊlnYpG=o޼wttVhWG~Y|%āL6mmo?d]A% Y$6$e C-wA<'lFdsPcRsSLYӏG#|"P]]]}9s޳vڝ㼩^aY;555yo̱SV )yɍ}y}" нؠ!GUqF/!Gh!(P 3&SR/fGEqN WWWI)g8.>xH>Akk+vp8LUUcǎeڴis3uz+^/<8h&|c$:cK]nGl.qG2ҥiys YfѢEax|$˦f,W$Ay!CsN.]Jgg'EEEspO:wE'^Ԑ$U5UE:>n߉xៅܿ 4qMUJg8>]Hk\|Gf} k(mڴ{(ZwV&0#KhA}Qܓtr@/B2&N "PJ A!77?PJy^gǎpꩧR^~Hfq2ZqРAoQuz N }R',D+3BJPhU.x .o$ȯYfN8&NHii=LOn~?3fLR-12!_Z L:uj]OCsN:t"K.e„ TTT]tu6m9 .{oZ`ԩS|OHZHސ%яGr̛ȇ'$3GM6}5᚞X8lڵ+DېBlb'^A W_@jW *#ܟb`R*ܗΝ;ٷommmlڴQF1rdR+M[n>p@CLD ݫo. 3N~׍ w>5$7z]l Hl}TrJJJ(.. qV/^[+WV=\GfM&iM~Hyi(}>`#)\MrUtў{'JJJB6.eCdj*,酕㜽gϞδhoo_kHY" R$|`=Ct"e>şs?}֓oe;z>k.VZŸqRy}ew$ߓ?2KB< [H/E9f.y  9?@v~ i^}a9i'X> );Cmm-'x"G'M'߂~đs&y߆*bdўd1)vzZq(:Xz˖-q)ǁZϋ]s 9RSWW4T< oF. {'@ ٙj#*=1[KqSNݚs?#{Rp7rꩧRRR)*/rO?/r+;?G^k@)5)ٱ@ 8YS++G D6,E_#'IRM [mR$,^7!JqZ-J)'_pz]'|2@:]е{+,k-Rjr !Nk_$mN~dqSn_+p⍞d5ę_)xT6<_WJ}Ie׮]׭zG}օ nCz +"ݳn 3z-8Sy&|5r! 4t"MO&#? ?`dc@oÏ:["y&dָh[p'W;G6lXܡ~_$裏>ګ㜯8Mő5&i+\ѷ ;e/lQJģ̤:xKE 8ܶmm2xZ )Iv49yNb۶mr\|Ware3#Hx!$ӣޟN$fSZ[[` 2Ě_nUt8t@Xs[?FJ\$@ZRf+-pzn@78iHhG:i~2 AL|o3/,k:1o:Ǎ$y:rp<]O"ᴩHHh& kPWa{Jh*566#4#a7%B`QH4#"s4"3X/!cRj@(ʄYX#@6B̤.Br"-HGko˲VggL7, N>C H휽/B܏ض}mۺ!zP%N?#h޶!g~RHdۣԧCم >e>)Sl9 DY-H32qBqDсy4VTMd?؄ DB On[R=SSa_IpwXCv | (cބo2Dw6_Bbl2'1'#aW3kQV؇xwjcƌiARoR ?+6PȖП4ׇ]#_̼U|GDHzB IDAT~g-O#{5&|%$=0`ؼys90qtll R>[,I~H(~dF(@ .@fsZPƇd_c;@)-ŗ}&KfyNv?-Hɉ6@ڵkd̪`!Єo2@6Wp-L5G}'mY@{5}{zq&d֬Cr 5)2-]ٜf(˲R!qL-TQo8@k}t :^| w2-HuC5t8Ztv\h.PJ Dj7$B9 8A\  I 7"uzAՐ6E&pC^GO*pgw"c7}"B?[Qѐ;| ׏@zU^n'z$ \ G2!C\݌ۀJ!fգA`7}$B 6d0pRZ?~&FцDM0a9_ 0q6{vv$|cӤBϐyލ{n#]A> %HP(T"됚p"Yh ߤI~0;R}Lco"6#qˁ['+eFwmKтx>ޠ=0>_ː @88P"D7oBueYFدX\k]Q[[;A] ߤEc[0gn?H&c^JUD<T@QQiXxdp8? 1dt㓭"d`TC7(;6V?Q7$ لoR/B cR/: ro8eeeZк!1#;*؄|oI4dVCG4SM)8C >H$2 Y7&T.$Zk|d>6n :}6_04$go=`=2M>@)5@km6KMBMU9%,@f&|tDǐklD!i/_k%.Hd $1I!ď!I2Ðu"@=AJ7%q_ܣmۺ\_;y?>=$X߼ysmۺQ8 꿹f<}S 2z_sN:dA࿁_DBgk/ ~퇡PJCƯ<ۑQ/")S(lJ:l`S2ccNOםps戮&IkCW3t-;ӐЃt<;0Ђʿ/rB}A|.ߒͤn&|d$!-5a(L2%.Wtݥ9Zt[፷yo#ށ!-fõΎfxڵ(=dM>\7GfOې N~A֬02C vOR tC)Ek8m{Rj[0nRjRjgggN˲vM6-^vZ$~$# %>8R:6#Dk)[ icCkM($kmw"wAc ,ko={vg,G7ӹ&U0 `J#G83Bk=²ZZ aHu_ / N$s!(**>}FXuۧ78\k]k` n0 m;j۵[,8VV˲Dm[l ՓGCҴL|>9$FoVWJTJUy S p + RO݌xF2uS2 GLCCh4zغu}ݿ83^+l`Rjv$0V)5[k=$qR3۶#aZJmvԖH$mrN"0BߍTJ75kfYHDG*F93 8믿g]w)Jr=ֻJ,FwY+jmm=s^7G$H\O#eRqFEQo>TJvJY lvMZFqk7m8qb[?s:9H#9xz8GX5Fky##R#֞pw{/#Fx_RxGkC)[ Bv ,_20&3y+ܟhCWiYP(4ƹ31ttS,IH7&uQ)>6lN0)7 ~TLCBډ9%mp˲Z#c)8p<"9[)V`)n,kk/)sɸ#K3"D7rFSSSYKKJqxQ`p=S555477;= mzqCە*,Yp\djkkGe8Nl<"%"%t[܃F`IOB[7 0p*3tFj?U?~|+PĥvDqqюL&̘1?i˗/C+?)fMZ&˲6zq6٨ dep04d|=a3uȶ,˚TJUj螝ց kֵeZn޼ymB28ihjkkG[5- U93ŲLRJMBZ WJso뀷,ڠ8eʔ9dJCȢf̚ʑ7a vٗ,Z(<~ hR)U8t1JZ늘C;RZ@zu(Zq ~Li͛7777W9SeYV0W~\Z,kqu[li #'&B_ > Mې4mkYLqZTJ L'&w+^X)SfږTH$Ñt9sX6ӲYȈ<͝NֶRVJv좢'Oޛkρ#bdDJ~:wI, eHs߆I-p25Z[ 9ֲc'#=~wKR+^BK&MtVcm:~ZO{F`RRueM4I)oSJ?0B?lz!3O#!)r39X Ddvt0`Y֋HdچDB, wttKknԉ-'ZZ~cԩ}m}bG?8;J "$_Hàs (=DڪBDdJS)])89mڴf"_n1#\eAW}'+oUF2])xƑH 3;LNj}!hjj*;pssRCxwӦMCћEbLdn|Jn*Ȭ`R5b`qUUm.9}v٧YI14RJ=Ο>}Tכ[bln]]q%JR`Rj_6;?}}bFB[:Cw_徶hİ YM)uF-!w5444p{"ߓUblmmP(teYZ< <,cMCv0Bd(S_k 瀗BH &85!a8@aH;Mw'eHn՝cmGlֶmmիW-~X߆%?cȺӂH}  d7o.amf۶j"1uuu-sOV___CCû־gR}b<~R6:V;tP8AƩ tҢխw5)9i~Q__mQ۶w۶ݷzmF ER55&ktooG @S윽oCz,m۱m{Ɋ+z+ޅ:TWW!m{lO)T/5NTt~繿 ]K߆mHm+m=f.Fs;%>uFWL~ ~PD~߆lk֬z3m^e`qhDd|\BAuh@ ۶ϵm[]]Tc9 خlr*`!Iͣ?0IBe,ϸw6#|/ Cf+XŽy8W]:ݑ ,> #4ЌG! 1,p_9@)UZh-2k SR<.$.$  K,FʪRdr }SS.$ ЇAF*0abY G;";9 &s΍(Zu*g ^L&trEByHz?W+ru\ hBeZk#l?7,4@ rבhwq=gG;::JL`A}v! '7dFof}!'hv)MJ)1+g E;~oZ'#(Zp?=~eY^,&FwH&PϨˁp7ZB~ y&Fo Ky"ћ'k4}s20ף/ZX? `B7FoyaDЖtgoCRV/Grr|d[7JqX_ώFeeMa`B72k, 0C: Kuxh7nX"pL0иہWriH) wW"!\FMD3 oWUa ,vQl&?7}Ed:;;b *B&tc Hk|'0p![5fWȎ݂CkBX q=1ѧϱ~AEۑW~!4ɾy(ZkT:?mD }o*e9V2#  I>#I"f/[(,~yHx ݤi$,]/ ļTTT7 {yVl ~+x٫zPP7J)}P;7;ƍ3Bọ^ÐD>Mv6 /|DуBx1ap?Z _LK<CIAo}G 7x󅃉'jGÈW?P #^s{Kpn_{18 g51=0@R݆w" _ q !+jfMaabP v_բ"?nA(lw$p& >!|N3f 6l/ضn/m!BJ,n#{~K%̌9PWWwmۺ, z,EV @l!;x!Sk} LJ̘J0@4X@R-2Y-L&1K?kHN?d؋xMdoCUDty EoZ,ˊXHiޓHa iF.oF EHjI˲ʴ`c )2o޼PKK˻C1Z`miio۶4(G-`d$11zCR.’e˖iZoase-K'ؼtFģzu}^MEc\|}Z *q^/'EEEC>Gɺw9/澞< Cj;DG͛wJC9{t;y{F!%D)u!CfС:4#^uֺUkO)ա Z=@̙3zODB27Dv^M #9ėU @kmbIξ9yOuI9]kΎ魭_kf[umH,&jjjpCزeKn'+ IDAT.wmJ)Ro{DŽ#ڶ pJ`8euMkYoYV 8nòJfCkqc=vR*IOۑrbTGwVJjM>'B<˿XkvGg͛w4˸9K|4it\3fL 1TXU*D"eYUFKReJRqʔR=ok˴֥HQZ)Rbހ "K)EII `Цjuiwh?MoO޶m|9sַȑ#36qZp[4K/gh7_| )m(hnnn ӣ GlA~IIx cNK¨*d o#b6l KǏo%wMMMew.-... B@*UJ9spJReZ w(Cī 4c{{p(*G>?O</_k~`Y㠔իW8NG(;x"3ݭvZdƌw/@k۲V7{5 9H֭㴅B.YDgϞFvd_"WO礎cرcw(eees|477tf$G2]$qwftVj۔R7Xۛxc\{R%H0ꫯ.D"ZeYo2=ИAd{` uRL@>ZabE+ c\m@ڀJ689*uOb> [nX[[[YQQQRjx4-,˛JruRjRj8JaZAP`0vp ̟?]YUJq% Z=̛F<}zR*mZ랝̂HJa`^k:Q4]I hX}@m.4ioedcccˊ!˲ʕR%QbY `X)5(uۿdpKk;AblIIɀ/Z(|Gaao Q@oK"p7cFRj7s{i^oB˲oE=SO]~xRj }꫗mBHZa`PJ:!907H𿆄 Z5DHSreĉmwgasxA,]h#%ȱY=oNnz˽}Hͻs&hhsHC8m۶=*6kg۲@)2?^~H?ڋ~F[mkkˈG_[[[  ӵ%Z)'ǖTx  ڝ!1&O"S" sхjdiD<gb+tQQ5k֔[52˲*\!.SJ .GBôփCXRQ2qc~w k[-{qdzO4m íZ뽝-'OΧbg[J'2vm7 OwIģL}#nުZ,)W ܡ:e[RŽ5#nqgO(ju=ヷvg0dab>&\u-~a'HyUH|1mYug>eYm4koFhi.َ~6$? !kqWgBnӦMO2CCS#A>㜣 %Ѽd\߿!n8sX7Z=!5d!nh?\> z +P֗b^WH\A519@ⴟDHx|J7p3,> =\IYb'w!FvD05V#EAqbd>$\ ZH邧Or;fS̚"*bYl@:|90:]@br퇐rL 4!o8t_sXDtV#ze#sG|K%HmMI?Kzߋ6%Is{/bFQ#N}n.9<qDęM#q'  @vBU:߉yYp6`Oߋc;gG8e+'boA> y d=R y.RZ{%Ls3IT7pRuЁl:e7R/Zi[2~˲FLq&#}!mܚiW$?zyJ}|鞇~x{F1O'?#>Q߇DljWJ nqٲGť/!;DG i"syXy{,,,"f6@)6b a,Kq#!,[AlЛ>.{\s+"/dEeEKkݘ|!T%Det BT[JDX쩮AIAo:+UUwZ"Cf8^&ܕnSUnq#Ӵ1ʳn2`{?tm=8Od]̌-}`>:,.GxCW>眛5obA("IENDB`acm-6.0_20200416/doc/manual/acmtcl-departure.png0000644000000000000000000005616713175033707017604 0ustar rootrootPNG  IHDRP IDATx}|[g}ظ;f)v *ؖ&ia,NL:b-46ghx .]&Yjܔ4u![URS?e{ IG9GGOdޯ9׹{Bc pl B!1".U![B RDrtHNr%v2JYQW :AAN&G[_EB!$ !#wƳ>PNrH!$ BSI˟rH~-Żo~7~7ݽm؋'wby/pB2(=nʔɻo~'n+o{pm7\~|_ǹnPp_??Ȅ - (K|'={177а9{wq%JIN1)]OEC? ~_n}^[[Gyj˶nW;|g|w'm/F\wv[?ŋc4VO,]6nA>:/ !fqĢܮـU";[[tϖX$w܃p[Q ~h!0[pG`7oƅv“X>\i|HݱS'zuw7&؍k aWWps؟_rw{;Ŵ a~|6I~} u!-X]c][oP|>l.ލ_WooyK x[gDm 3N|7U͕U-W߿YPkEf!AL|nkg'͇}{r mN|eKZדrDc ܳ;U{\ݻ`݆=} {7^ŋx##VS UZ{j8$:{-|U`mx OzۅnێOWsq1GCo |]$g JcFrH{ۻ*LKތw?Vx{+3 fɹU7ԓEwo@jv W@~LH Fn$*bl2lկ替r^߬߻'\Q)gu\~ 7Uo-y;/)2tJ.Q, ~ O {1|SsyۨBѻCËۆ{6cW/s 9yW@Q,rJDzF2ںm:ٿȉ3xm-oU_{×}o3%pG>S< `' 3nG e+Fq7s%&sߩ%nlx OBS+Ċ 8fa"BY/ ؇7u\z?[wrux[+Y$[n߄G5 c ^;~[???g|Wi'j?\nS{Iߋ=K,|gX\ qwbE;lWg}wpg'񣊟cU'F}'h=Zwg/8s{Qs663qCoY)?>PF sw'pn eHBqE%kKvغ=kGG7,--7z~0Sm*n^Fg&1Ώ6r LG?wq< ~"%?迮j,)BdÏ@?1Ia&gFR?"$,/Y޽;] !2J_]+r0 !Z$Uq.`gW]sS!c;^N* z- #!JcG`m.0 $cj9Œqw8Wku,ܽztM.\^sX l^(:|*.hPDW _;R?gE,brmS {.K8W3tG׌aq6yq]{ڱ6}*[|&qCp8>&)ȿ2ݾ5e {*;VKP*6(FHO#0ɔ>vC"dkk VSWɾ2n*Ja# p4$y@9890O` 38)#u`;< ֊nqH#Kq'QU)/$NЅ&ห;ZS"q\Tt* ԅbc ɞ$K~e5R"LWiA/{'%,D..BPP|})u-Sé,Z16S\P(nN&0٢#'xnsRKp!/%mKֱkK~ ! '/%A~37&IP j6DZI ̋'mX,O\+EG'*\dX$^PV X\I+c9*8tBߤldt'*/S$K-ETQe1|5"c pssf`oKo\½pnG(QܰV̗MhD4U͒s/<6D]B]Jk>}$ʸ(QLMIBd GfJS@g%SӠf5h[M8: M~y\\=88(x ncGR0ڊ!iTѦs};Ttn׬w~ صkǃ_xWx>FX tQL  yxAW}(`|>z>9ygCg͊ȯ&:`ߩ '+;_+f{N5θcKe}-u)rЇ+9WM^B2f+`T!dM"d})JBR K!$I&P^/p[mZrP$wZ[[E'dRM2WV5$,J,_{$d3<#!BEB!B !*B!B !*B!T$B !*B!T$BH!*B!T$B2ܱu;({nƐ!$:%!$ ][BH!PB"!BEB!PAVPsh˩.3s驐dqP:׶yqY{$XvhC;I^r-b9aغ<*mtr}$P\]Psvm"ԜG]%D;4.ٺ`蝅5 gGgpmp[sX l#{qD q4I2 N=׏/b)`M\NPq= ,ܽzt *{&dS=iN,FH#y]@8~ZBȥ]hE\8V)lģs/Lu1]̀ ɕϻ2<,2䏨gD~)j {.{/(Iȅa[G(F3"R"pԆ;%rv!R BAqW3ZGQc+1pXYVީܟ2hq02:g%>E=傻,G&oj wF[:Bʬ=_>+JDXp9հWiF:YwF[\r I0tn׬t Ek6Ңʰ2>GKe{2SeB; lUeB;H!PB"!DBHvBv"BEB!B !*B!B !*B!T$B !*B!T$BH!*B!T$BH!2/jl]p.lA8"Z$Z)l5 k8o$BH"'rht{&R+1u>$#B!H.M\a6Fo vVLo9`9'E,XCp2s<.qݫGǩpg2TG!pCFJ5KF8Fn<8\*<Sq+^cOmN ?)2[&0R rWh!U㌫#B2"񟑌4$Zqpmi1nj L.-°XT"P6?i_ \,ǞRBE'gz&aD,O\%Oν@ xY\6}e{qg|y;j9O_ !pCKX gXMG<8m:`(XJ( (yp@5E7ZDy9f^vnH!tn׬eF8:`vFC!0>>IBe,!@EŽ!Y-B!T$BGƸX^pf{s2I8_8!kVt:[ǜI&Dg$BH!PB"Y=0ttJ} `3c;b:;dKc)o1B,#k< c,cVRZJccI*KddIt)?/~ʓ1OFky-|J5&kv)}=|>xKPWgcTһ> XZC 1;(A]K}BӇĒnQ|n)/-}B޺S!\M%-$+][#1r}N1&`OFcrOgQxda:`oIiX|YTv Fũ\?(AY IXNj'8<*ijxUMJ{XB ړKub ʲ?Ԟo?G]`|}]1V*iDAd"a ,otOfCAp4=1o4ⳬNۘu:.ZGU|Bh ,o0f45Y nBhvcVT+-(Հ&K,yaJ#1P*cpm]pØz戒teuDsoE1VCCʭyŷzpXU?m`UTyn{b(SAx\G΀K3WKSE_cAFIId['*Q(ȍ6 J3 aJCq o^GUH n׬IRw跊ڏi\EN3;s 3!T Fk_DC4Gt6, c*3e?%MbaZ,I䯂Y%c]qS߆?/FE1GU`Vf)]S_*\Ego6uom9ΐTqo eXVUd9Rإ;1;$ CTq0 Ͳ. KSw1*iE8nLGzp_wڧr:δ>/z 2+Lnߪص qʍ~MXx{`64`xo̮ 3zz04HV=0[1`'ܛaV(UƇ}FwAx1ݠZ,!^ABs^]S>Uĕ.a@lEtCciW/,~J$2ԞW?x{o_+"o%->H k4 _EYNkOŕ||<_e]BI3>&AEB!i{L"4 !DH<H! -B!H!"bEqHR[#/YH$| mB)rGL\ܔ#E2,Ibk$[If<ˢwC5.j>D--1oMQ[)GB$dJLhqSIZ$5-K*(q2Rh@ʔ-HpoɢVwyGߘϜx$T$ bקi%c`OCbUGYg=#7|惚,LGBEF!j-H, | O*@Ĩ(]k̊v-=}*iS4ATdN<6(;k'Y8}i/|Z;}, uT:]d}lE4Яs3*&nۥ>)} uy]a7 `*dT|P%1*īdx$7,I,v9u`<B!I"4i`"!,">ɍ9!k7=z&[B#$BIl'B$yÛa|I{{'U;tX؆'=MOjSe7OmBKSj$e>}O-lb׷-/=WXtLA9%\6|>R"WOH[q7_oO27ߏ FI#8խpisӇWӽ|T~lx5J8)< }ʙ|YT3>u"nBo{S8oiѽe}G8++[':zSUSʻR@p!иZS_V8~Epל|/*맖w%2m3/oON}}NJRBh_:<&n&g3y|Pg*c)|⽯mp^Λ@$MHw+X*n1k:Ti)bmb8 ty!uq]I'PȹQUö}7]1lKƴD27oEٞ7is/VXE&x_ g}uPZ[;YW>O[El]7S®[s(7~(~®nUh^K|p~|/P+ű1|c7xW>~bG0O˶ԓWycx{pJ|aއyOC8~sTl+EKx99}fWau{ Ëhr߷h(3j[8Youzp]uxp3R ["I[dgs?>ު-I-\؛oz#d2&{!xRS3+^yxӁz^|%>I?w\60 <È[D~Z'!a;R"Z%$`Kh4cjE{[GJ}6R|%?=srE%27T=7W{$œ `SIvqjMoy70Oq Wpo z^ʿR'yI xsX/gepo>˧mIay4 i69+$♇cIͤMZC7'ރ*u0Wƻ_*'ۤC!8K8xHV,Gwg~ BY˼y,"I6*<2 !$Hd׊E¯BHH_%u-A! -B!""!,HH! -UNNΌw}L9?N DIK],sH{!m-_Y.]]y &+S$_yjD>yThm֒ j_Z$@_)Osu#y,V82F4tiJKQz^ iDCE#SziBӍ4Y|=fUzL_ vyUTSNԕαx.s>=YR]r)~Z*tDʢKrFT|[['S1)-aa0:ԾfA3Lل(_%T)IKi,Q-ik3|cv8<Zv\ndW['u:0:UeQ_tD*@ǽӉONC:h鈛PՔ~וI[~X`~C}2 aНÐSް"884~Zae\!cvWB*,J>}=NU9$cBtEi髬GUషlEtCciJ}!m] QJObHTxWN|{aJDŢO}e#I2x$ ZG_BH ! !Z$T$BBhPBzHc ˘z$Z%֖QuX;HbdtЙ)3!Jm-1+SK< ~ =Fx̊GH\cy$2DW)zx$R$Lc#}n9C>WPq9Q'HGS#Z xY(=WSQ@jinDȸx$qƅ7G"A)**Sk3X3!=H k4HvxĉTP=CeOIz}UҢP~#?.L<=AZaPѽ Ί~4;ND2\)#C{ZlejQJS7,TcVH"6XIpG66SU`r! IHx$uNѥ%u~x($9·!*8DvL\ Q ߣ-M-fZ{fB< V2!x$hy C։p"?*# wiIv4g!˜=eM~.mq>b/A6-ie*?4:Rm$7.I8I(Z3,ʄKʱfjRܮ٘SĽ+$]8Ɉ“(j12^f'J1+ԾK1+4Ȁx$S\v\ޞJ}V?6S56VТ42]d";?]5dPGA0A*A(jqtL-OjbY!uE#⑈r&XqԺQbƚ>V3I4e J`<BI$q@z:0 !@EB!BHȨ6|ȴ0f"tUuC&} ~M(ly͍BH(<#!BEB!B !*B!B !*B!T$B !*B! l/z:x{`頓ʔ{Ԥ=cmF*.EN1Z{<˝>Y iԡJnx|>|>QdIX瓸jyFBւ"YyB?Q#+F 8Z^6&MF= ߖ.-UVUl#)pwI\;&]oMQG%e pQ9Q?l "kB\7.k8'r7&py `_Ē2$)GduHP"ï#wP<.qc^”ʴ5pc^:Qw|9[zoR DN1fcZzBHV*Z1pԄCZɐ| p?xryT*LE2rraDeHR}N# kQ(h1w2(@AYm `pT=FYx A,>P5ѩuG!5 \Y6][[-hy\T28ӻi(FH#jl|BshP&AQ3 a+µYXϓʢd{6 =)>__eLM}}>dǔ/ar)'-oJF9eWd~ʇz-F["ǔcDEvغ/]fkrUZ,ZK9~I^{wp)[[B'k͖Q&d]e3d ][BH!PB"!a;YL]c#l6_"!$5>"BEB!$P.3h BE+iä)Ժ$R4j8ٰ!͚"٥ݥRSzh:Ct}̲1 Y늄{.,XQ|ScKbת/cvQ{2&D烧 R(\%9ĘJ "P@l: K֓"k4>`m.0~7T QKSfh`Fb*1ʙl/BYO$ʸr=pe^TSA~}U(Q$=hCKcnt{Tň1)7F'pzE eB9Ӣ?ù+5&/m2@T=fta,Q8 0Bң~W "TCl]r*\l`"uHev=\t'*nL\a#=p_+S8?_=Ҵ xY1ۏ1%@z`et!]StLv0ƴ?,?}t!rF.F"sn2ny6Bb#;2[\ [М◗TTc:+=kGg*s]>l Ӄvw7N0עkA}xzI[o̵|t%%hRS"ar_[#X}*q`S VSUftVq5l ve#kՕt$w>8?nM2N=v2E]a]Awi#-0N73^TǰQn,}KIN5#y7Dy ahh4 Ydi.'.ܓ퍒 bQ$IɅCxIB&.-ҝIgQV׊ĩـp wԁiȾl(۪ >X`A[r݁*كlU#}TߋZوyT9 Q䵠ܮY[ㅹ05  tu|#͢z wPc[ՌK+yF:GQ!6- l Gd{6 =Ck郮-B!T$BHBY/&y3h%*uDN5H¯A`?. t]u"/+NJ嗿g̮,F=~ofIDo!y`W"!dM@H\kJFWDZ1v®ܠ ̓i4t .Q4 0{W%p zPĚ#T$Y"\yͅRpו'cI,/l.LL2рk+< 蔻OѥsݍC8jZE pĽ`P]8)[>{BBžYn.2:>FFyǫXnk[rq"g7`z#$ݱu;^9R \ELMuH4;a&$brTzyq8}@e,ZKG`|^E)SH om]Z9!շi)fNxUfp)g"Yff:!Y  "!(ĕHs%F!DjӚ8*Khe*zTL`l8'd(K8Ww'EXX=Kf_sB9D4> -<6w>22B:'#][Cj+ Cm/L\0ly\ggOHr(+ k$P+E"_+ڱγ xeϣV3bnڂsDŽ9x8MۀOtbve#Aom6I1:kwxa2[9.ϭ6$~ !gɚfP?tz"BEB!B !ɚfܪ=fpPY$5c^kB !*PVP#V6CW3hS 5LVa|Sz)*p$lK8WLQ98M1JMޤ3^u:fxï1P.:+@=?I?  \!T$(+R$Be^o:)up||PV)\ta%IbʄBP:N?4 4F YW۹8?eiq{v[).yAN5GR7A . ᨒ(Uxl994[>!oQEkCv_OFe-b}U(q/H)݉XPC6$T$a(WIqmIeH7Kpa#+BEpgu'LJP8U ;Q /M\a#iD<-()..p4߼D)EHF96lƂ[ cC-z-IKbvcBD 1w^),Z-'jBv[ `y /l'\ n5f- ,Qd|^2PCsU>m" p)iY-جؘ"J,Bwh9Np%#HԽ0_s3WPc,sFw( SzKnU#zǡj,b̎9wi#|$w/M&&|QV8>EH{*GDZ.ؑXZK2)';Q9߅*g7qo/JÞ'K&G*R0=f nAnFg,,}N@nh0gI@ pF U_ 1f[[;vޠ/?d;ŠԅF 3G846]R~1 "\EP<Q-䈡ަFTB \&ۋзi0SՇ_TEN~jkRgJZ ͌Ӈ*`P\HZѹ];n sAuX+vSV/YO ?5pR ێjS32z /5U.I˛P;8/񴏦:C =/6Y~9;6[\Q['T$ib~;[@ ^!ɋv38ىzǮrO)߯*r1NW_XTdWK"U6y#L|,>Z,(kK2UV"Ǽhřhi 8blBE&hr(qÈ#'ŝ9ҝ$tnr%_`^"*-p.Zڥ +laixKpGK7 /,K9E35J 1]tx-hV^yj MAkiqr ljl'pXvQݨ/|5Ӗ7ea6j1Vι& Pd8qqtٕĘBllK^ 'r,J6˸1E,MF,WNe]5vҴ~)Yd[[90`Eą&nj`@&Ou W^]겫ϞP>#Mױ6nXGSzt<$m/yNH2cnڂsDŽWr& BL3.lD:{m5Ȏ]pu 8,w*q^8*{i_&ZZ1ZGmp%>Z뼂kuV4 G?X$ُݱu;^Xu]Kߏh]ݷ.u؟PSUh#KOa||?H\ĘBe]!dug=8ta oNl6?NHkBH\еE!$)PB"!BEB!BzFap)6!IoR?*@! еE!BHkzɳ*eVPcRͽ{q"ZUBqMvEEBN5θ%J%RitK7pyBBweL}SxVO麄 @Ŷb%h[?I;Q{3/M2мJ}w#1%rgz-*_1ksr ,3*6&nE;^,T~Rlȕ&K{J0/M/Xsoy}woƫW5ʢ]y$.'~t:|>"ȾpqP}FG3h D %Jwoq!ǯP$n7pKv̿kn eo@[o~~9B۶-xe+'40ǵ{&Ɗnw9 b)#DzhP%:ÊA(P (an),;101;ΜCIoTӼU^$UvUR{^)s(Ja6դNq訕KkfOc]o}-P{4yA.ժH`E7/pFTjXirMUA[Ϭ6w}UOlM*\U_c8e_l{+M`6D%So+8=s#Hpʑ]uxF qEۤ[/5S^oL*vhkzu0FPa㡥ȏOgq_.^v8K;ZU}yW3J.\ULUi˲͑b?q N;j )ET&9$UZ}(jPλW6RSNn98=s :ڕuiqΡ>Wr֪U=ᢺ wʴ<8Yf \̵/߉7ٛ/Dg^̎U}9wiﵕt?Q~aRUZ5(ZRS}QqW}&uŇOJ+ru_Pڲ7j+1a2DI_ ݆riץ]f>b}_։.Yof#)`?Q=hdQ+!5z ~H6GFpfn73 Q׭q} ܐ`$)@  h%u< @A H H $$@A H  $@@A H H TONiKKc[E y#k:U='Hˆ{ҀOa#iE  ۛ'| a.KNA몭4 TqOX nܞ}ů:A4u{A6Ցxep˗rKV+uZu-)LsWBy)I6Mb!k|=z9:;ahu땴H!є$29d[JE(ʜĽ2-hԂ IR5zIқձnȕJxXҰˣ)s*lxZM̡/i+#9RP u'yAg>z&9QԷ?4[Uh3Eۡ!#!e;J\vQhc NA{$x4X\74iο,IuNa5NցDÕ/3Ԟ7cVT}n@ia6AjhW yɘRgY#=PDnrl^Nny>$a=1/]7':DGsNY~˃ AzdP'RnJ-W)u;sy6T6|Vۍ9d5l탺z 4IZZ:˻5[(q$lNi.}ע'}c\gf*Q<KE[[[] ,X~nⳬ*AYh mA Hʆof@P@}A~8  /pҨ@}AvVod; $@@A H H D99wO7?e4IENDB`acm-6.0_20200416/doc/manual/acmdoc_html-ils.png0000644000000000000000000001631310405571276017375 0ustar rootrootPNG  IHDR9bKGD̿ pHYs  tIME  I^:7\IDATxw\k+l,HGƂɽލ]laĎmMd1bHTcQ1lKJSUcC@AY&7;[XvA9vy9ygfg A{SO $ {$zCdH2T$NDc{S$e̩R@2+.Dd.o/j%{ٰ~S'/=yıfe͏&/w1lT~B}T=&,Q`cESr.,9?=];K{;M%fj3-BarX̦ѩOaY說o٢YqҨbF$׎ RfOwI2q,9s3}tCEbbr岳}JAŪ~gX&"9`4nPI%h "1^2Я2^߷ƥÚ+gטNTYI rף-*=~8=w|n o!q-瞍sa ȼG*axR[Zlן ]u+IOThxk||йYZ?c^@( z2sDY/yC@7h$:nʁKOwqb@J=莐u)WHIp[w$s:W!@J{HJ2cCujruU- `o ыd\KA -VCRz- B]5lBRJBZVKmƿ~x._8 hȘ߄zMǍ*x@J8p…eÿN~bY"d<&Z؛z/$,QYu8ɲ(A]ʲIJj]t!SCB!jJmt ԠU2%O1bZ%C[:f9e~X`p< 'IQ3Z穋.VPA1l1uŶ9 =l_+Q$ ~ZRI3h=SǸbA#,8b9(bKPbBX@$zSNMd_N^H!V@%DrkŹ8 ̹0c;%b!IYDJc}KP6$3/̼QߢK.娿TP `$gJRSmsj*ZR@c $HndD갣UerOp[aaa7i!TD bY*$˪*5u Q>ꍔMe{yC*kVc *T(4BCLU> s>HRaiT>M*N+wpA[+B*%b!JA T ;( B ԁU@PHP@JGRԁmC*x4AAZJ*WT=j>8p8YYQ^74.GR;7V*۔urN?H=jף 9iQ`TLi?Q7)ܲK5ɯ]I/W!=U?L?ENz\tw Kڴi }nG17i QfM[^{wA0KO)nTgc^})Zy1:T -*mW: h+MTjg MYQ=iZYa:%6MG5׮u[\7:۲d"'=Yٜi:|,8te&6Me'wfݡ9.\Xqr 誋o"Ԥع]ʚ1a~ܚ[b:^eoY˪)>;O_q16n偈"Xb#7C[p\!v~zU2;ޚv@Ӝ7ܻT뭹hB~/{ 8R;ד):y? vǝWꌌ$ܫ4aθB, >99,ca7/8 ڴ8*UO3c/F]cS4-2Uk,SKO2ˁ#95AWs??_#0 ^Xc0̰m`x| {f&z+O^&eqӏhZ2KM N5gwTI;9悷/JdR&1DBsul"*%ˉ@yQ*WڝWd %Q݋owzѢOs_YYE]xhh n&䘠Vo`e]+ѭs+H6)^KıR-h>귎S~*,*^Sx{鹝Ӈ2!_2 pڹh)]ńFkZ?wt1TmIij6CIu\0c\<~s1V!ufdo/V|x>g̠" .=_]}٥?@V|geNEK+.nW8Iba{挠֨d|^]L |&/ArH kp9?߯|։cY%s[IqXɌ95#ȩU{eWnwK#Fj T@0Y3P~I^K,_.sEI1HUI?{z@S! fO9g)v E_?/e.6VJ5qaM^n}-3+uו+%2d H}#2\d,s[WPgJuE^ϋ< 4EF5JF8Ls [?` pnG*׿kϪ^2cb2GAhT_w~[LԁqP5sS{*4Uf3pHR_ʦjQ2~ψ#}j:@R/_;ܩ[Mm9yyZT$(3w7ɥa]W]_ >W;bN)]ΨlV p]0L_d $ݹ˿8 N\f(Q*9fBa9OFvͯn /M^irX?FoRU3l߿E d*_h<0d>Uo;v@ُ9u lufN $K`v s6w$܍e0ߏ7(}SO*+;_nx8g9xѼw>)T Bp HJ|H>tɖ Yv 1>V+RmI׵Jɀ- @[=k#[ΑENuTc>kێVǾ{p-&u}I]8> Is S-M?V}pksd{M,^[:*f=W\JkLՈ4H^nꫯjt&&gdّW5+wD@eYT9ZkuJU`T?Nz:n$BR;Flm*tz;^e;>l7+PMk[M0Dy|7kMYeW"[v29x<8b:˿:?#؜JZc1JN"L\s˭EbLn1\RzrCLk͵,?1&Hj+ sIJRb&h͊Jxri ,Wi%wsS\O.&c@垹4MSYn/oqƻyrVhgXmO/4ha&-*XG-l*{!魍-g&0˧E>Dy.jL_9vOqU2fhU<]NAy~4d5D̲# FI&Ep1G쎍c %Du'\#6%mߞ OsN"[ǟX#qblͦ+ϯp6G쮖X:˿G昉ּ{8&4O8b?GeZxݽk^ik{1Q'O0Z$v}0.3M>IdHo#ݫ⨭qWbU 9b1W<0; \pF ҕ̦:l3r«#a^Y8Md+BUfr̉ vL*dN Hj3 ہKioYTg$6L,af`543*f&Mdf9bEfY碢yEQk웘g\4G,HKFZ 2(QAEE̾JZ3.2Evnj|W1L*"&(L翏u Yq gz(A#*.`!dG`5ie~}V:F3̲Cui+sʕbD&@i*#߸j]47abjik[9klOȯeK?"M*ב)S-)KK:NVYYDC)| dK(KbбvgUa obS( ,"ʲ}drLٱ&WҎyn5Dر Zpof$n,9qfW<iƩv``?b7)N1\kRHlHY$džb{h,Ƭ!xIL2j/&Y&dSh+Lߏ36<+@U$@j ͑ ^l k=8m&b&b4e#Yǯ,e!ܷu]|ڕ"Giix+-ѣJ#WQ_YBo+I}tnx 'KLtI]([IdA;,e!ܷ QzEqܟ_"".njDl,bOļ@W#`$$@W}NpZe2)0[0Ml9ؿߑDl(?@01sa/RQMBBD\9SA:eR@aĹą#$.$$$qrr*%l-CpP@Yy +((͛W r8fLDl`"˪ %rEvrcKf4h"hrq.唅oHjre!PZ<L,rʆ):IjPz>G#r{/M}@\>OH{ise=)g|AGH'λqOX`wq}vz_@S)UbQL & ( Q(DرIQMz\-2onaGR;fQp'"IprT'W)sRm Dz2Ͻ'}d1,m!"Yb (1YK[jR~g[BDV~ci Y~ci YM6,m!"Yb.-m!"Qb2!K[jF/ 6<4|QDVv ?z"r:&khi YMʟ ,G,m!"QbG-m!"I#4-Y^G-n!f(w""cܖZ _>uZ94G}1ˬ.k)~O}-#'\Ee7F0L,mB@jOI.Վ+лkAK/aB"-EE.O`4LvdCCzdz(RT=GpdJy=N\e!* F>⪳uÂOR׮epr&ڣnZ,,_2me:lT\/=upGX2<E\d#Y–!I3%i%.Bұn'PXEywu#J,zE7+'wXgۃq ;8{.3S 3u9]R,|^/{10zd ;u8;zGW,w?V~Hyx0gҬ/"k6):Z}8HOfof`ӖpyOF58cog/B8W[h$ԯIϿR 6GLؼ 3B{KLMk=`0R+Tu6N<ςVMWPg|s_ò (:rSqfH{/FJ:`qS|_a砃lU-w`hn=:89?ۤcK ߞ*~EYTv`0FD`ȱdrKVDA.U w.ݣl! կH.`GoO/?x+ppeY>,XI|ZcQ6;ny܊aMDHo\h^T\iF0yzz>-rw QT,8獢bT8{SuC%RT|6 қhM.T}kI0ѳ-TNفL˒{6AHle]Y-mw޻9s͚xCnݗaW7~@c N|6F XXT{orU~ЊEA?K {8m `hj|Ҳu%"tOQ~ ŊOi;Bͩ2F䗍̟^Ѝ$4B='$T+UQ{Pn(X^ h{O>\xkM){NǪ\[ыSiUf'n{d[Q Mpn@O2j>2V3ҦKz!xi31Hv`)A?PRl tw=kWX {않.P@ [mqiLo늉]kT+|D;/o|p8:7oDA;'-[z(=Ɣh͔F^#EO?y--h,髱HߏwE[0+5YGftCZ ҃. nMze.Vm̊m5rg%2R.9 VOX‡7|kd$ͩi>xgx­94S JLO'8 O8Rkk>Xi0}+ Trd(ftk}Sft&yOQ r9xsBcϐKt54Ut~~>蹣.7<-BLUU-qEjs` :5!Z]Dl2 ' }vrEly"CTChaAgUH¹\F'tJN{|a}d>]j+C2R@OY=CT{zu!}N炳2V8eǨaQO|+%)eԟy#(ub&~WN3ٓ[3XG`7ryN%}^To!6?q Acv/͡?=`lU)v|?_Ú!ǃ1Nj2j;5rқܷ>I|gp85/FMg];nbϽiϗ/]rc#}l.tݨ$ˍk6nv=qFD:_ f]]l_ՠf+ KDS3z@b@"¥ "O$sGNT{j5Y}y׿mK^$;"kw^ޢ[кmW]I۾S?5]^hă([͉߼n[ZzP@M~c.0Un$9OzwٞזW׸0BP 's)@Ha:Us7'}U9?KnMJ$QeqC !!vjܙj]I7*HYj?_NM|U*A:%ylZoHbȖj y7J΅>w$}N=洁+ @_ig[p"0b^ a[-,F܍xp{0EI8gae!fqn&UƱjU{uegfNxr2$SxڶVHq4>9bѫ!R}h7GO| &-)Kcgݧm.=vx:l^.2Яz$)琍Po18O:O] l 'X{3(b15I/FGR9v{q,?ϐi3_Z8,9.mWz$% O;<~U}6Xӥ"3&*ix0˩ ($ my%ͺ\QP]$-Ͽ|XS&-o^Ϸ .W4'rUsbBxI}:Woͥ[\_uFy>hP{ܡ,&{?FNҨGዒh:r2}{TU=p|k4@~k-V' i06t=[ecG*Jjr%k1aߝ,3uX}K?tL[Toei}QJK/k=آBG5.Yp 1+ "jjG t%ق?1KvZ3zIy\w+5eNRo}I}Ve<+n59nnB̀5l+/xP/ MgyP㱂N;r?3EaP[hZ#Iꤹ[Ҹm_}4tztL5[ܼjB2I}q]x6K=v|-)FRSH&c(%gߨǧ)4˒0;ڈ&MdsˍxDc؞ D#?n,isV!H!YQ rZvP#ʐbE=2"{mGc=&';͟/a.zWETk-O`p<@$U_8?<4]3IyAL"$~{М:L>/x٨Q:#κlTG1b }3G=D޻J,M,=jI]$shr**Bl, K\ZVb(Ia;4(a6yXrJIGKtVtݳ-Zl($tY(jm3(iK%y?Y(1_Nsc0_xo.JL- RC$?ܥH{kTۗfVN !v8y3Eіd+Wsq8R2~I뺺Z%kr.Fv#P"wo?*F2M! 3r>+v9Vg0^y8@oiB8{г!5D]8_ ==ke&  PWN',53\f ݗ|Eף/S^~ *JXA/&` =Y8`wܾFvO7ZjZ~Ru+: ZlWԗJܹ$7BanT:ݾxuzAbE\STnhGb Ql4,䚦ǹ7+z$ oG.RR ѥbSe4 幦Jfh>dӣqhgCsEvFto,/Ͻ`+^O\G{b ,RCF"LEV#qxVZ]صxuUHGh.S Gu0kA-!m"H_(ڻCHE!"aY}t%y`HS"%E)xvϮ0)IѸe߾u14 4Ea+CQSK}Y8ރld/1@`HS s-KO{οBڥ~I(ȆוRX蹷i0rAw~X:*ِq^~{a,i4v$}Asp}o(Lƛ}Y _tɦDM,T7\ ;ah" _ZW{۝.Jf_q1،SI¢{E]-ϸH/ m_S gG}MkWde|z]RB)"עMF)T|47V}MX?YCߛp+7k Ny'#< ߬$ڏ۪ ]i|HRh^d)qB5|?sԼ?: JB&WOOq=p<=SFfL2^֔,d2y܃'m䶌BиCOF'[73 -օ"rd%I4}sPH" ?ns@b!?mm:1hEAi7#hϽt3R[wY;|7WvY+>) Uݽt͎v̺w2yw S.Y 4W!͝7pw82CTXK8r=4tޠg"|_4 =? (+_z{Tzp@*CȤ[W`Em ^N4 v7zI۟9c(54h/1AWXВ'rk'o`{ΣYI3ROރ4CTض0%%%%>mnQUzo3~V@m*z>@OIII+u2)]IiC-JJCҁH%%%zXzO~VHI/_▀Zژ&lCMM[^TWRf[֮DրrpcM]/yRw{)Wj+Zդ&2zu ACM Reference Manual

ACM Reference Manual

by Riley Rainey
2020-04-16 updated by Umberto Salsi

Contents

acm-6.0_20200416/doc/manual/acmdoc_html_radar-display.png0000644000000000000000000001301010700520772021404 0ustar rootrootPNG  IHDR( TPLTE@ ` @ @@@`@@@@@` `@``````` @` @` @` @`@ @@@`@@@@@ @ @@ @` @ @ @ @ @@@ @@@@@`@@@@@@@@@@`@ `@@`@``@`@`@`@`@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@ @` @ ` @ @@@`@@@@@` `@``````` @` @`ࠀ @` @` @` @ ` @ @@@`@@@@@` `@``````` @` @` @`𠠤X4DbKGDH pHYs+tIME  *&AIDATxM,|0KqL4L=UhtkƗsoQD~ mQXQQQtCL<F9];Ngf^ /Н0gQ:7`N^fFʦ^.v`NF> 27홟#wkC}i]*r =_H=mPt'UݾraN r3{}j>1״Ǥ|n~^n[ϮϨ::+jܣ޷jJJf칊N6zR_w!eR95}3}H@CNvB*we:zNzS>3O@Xo>?y9q?5x~^'g~Jw  $̈N9䕍W*JM:KE"qVOЩҴwݕ|Hf|f[ԑ!Gʵp]hm@O`z}44*Ƚ |L'4 5h-6J +jhHM 7/4ʽ -=m-܉܍TTrUvяfnF=/G"0IGWV=\t!G!teR#r߷| jb}4X#:s!ds)܅bØ3N^ZﺑԥZѥ+Pǻt>Dhan%-όwǎtr%=p}spAgF6ȍC\/{ŝ#Dia_r'6G+Zqio`=toyqGy@(5T8۾{'g-mf+C&mzyn#Z}*Mі8YuxU'ayٯ߫ZnJ~%p?^rZyYo-ݽZQ}X[ؒ^Ǝ5]ͮK|t. ;Jץ~iW~a~Yد//Ƚٝ;QQo/Y;a#-]qǑquWM|geit_=j}"2ؙZp,V]p׾IT!Fpi_}6*~}YіF)r95'%[}o#Q(uf~]#6MpK<~枿TcTl\} G{ƷіKrIV7TS]ew? ǷÕo㗸OķYr-TzVM|5+a:X C||%ܽmm%wķY/ۀe#%WpO/ؤg_C㿉@'܁;'/_͠oޫi:obq}<~ܿ{|Q_g_6_cոe"72>L`߿;os8p2~ú%~ ̸`}{zW~MwI=/?Q=kE^t/:G܃ U'|Zw~cw)9ݭ9e?iBv*96g)F%8dg:i~UYǽqPOTa{rt~TN7|}*'.7\83'X{7sƜ=NY>7I_sfɢGU^Цܐc-d]6u)"3hMO5Kz'nRRؾ7n&;'tmF=J9]&%epj3QlFZ*IUi8 n\f;NOF9]S͔^KmIMy^zL5w%-0qaUk]s9R+$"4'χlGy>tI0笳g4û}gk$:WҲǔ=q/NB^F^jspR+CRHfHU.V܅QӗAשG~m}Ew%/wN^ݏ~Veֲ,5U?Ux "?Z):U}GKswCӲGپɱKaMZsc)TZn41)'wI g s2OORg+rvUM~'iJ=:u5INxk8Dmk_9)lz6??^rgam9lVOc0O .݆{ч'녳Tr޹[r0-'|genUi{~_,/yCYwWh<,c. w^?'w|w6q_ܿğ_x(,kt}WΖZޛ/]%xpׯk>}-xpџkq+ۀuq?Oa?=/nLܯBQ.BQ.BQQQQ܏^L(Hߵ_ZLp?T.XE3!t聦7J%`cKq;Gy5FVB~r/o%g*PpU Cjc\YHtwfSA }|ц2w'SMsy*~$}ˑp UJC(.!}+^s)P=řןC>F'T{ܻ& rbFTgxzb&vnUg*R)yݱFp%AIV~lT+U8%@|wNZ ߚ$=Ȼa~DϱۻnbBoN =ʯ]crr:9lmtv}?Z *ğo%9ȝ\7;6{rKb4`^4GOtĥ{)x0[~'WNպȫY1mם<XypGwÖ_1&pSGIENDB`acm-6.0_20200416/doc/manual/acmdoc-zones.jpeg0000644000000000000000000001575713175033707017073 0ustar rootrootJFIFYYC   %# , #&')*)-0-(0%()( K !1A"QTaq2B#34bsCRS7u$%DUr?cdEG8cesWA{uō1;~/&JZ8C+qcH'U:"""""ׯQLٴIWYSQt2uJr3YIGHbZьjIvc .Cp9lW,sF$V;* d9Tv6S%nD U5Tjdix-&F&NGx}\BrI<ʾ8)m.rGE;vai9c# %up >c s==Õh4ٚPC+Q0{`%L}@7蕬ZpAEQeQ,\CX3y=_-+; b:7xsۣ[FTM@ֿVRFL$ 0s]6%kYROtFcwnlq裂3c:ppb.LoS> ťXvVMwiJ($81`-҈û庴ҖoGI-8{rK9XiLhIg*""""""ѹn,p./

Z^ Iqiq*'VS [|14dϭ\㌍jwbm ]Zm6"BRΒ7Si[SD>W]S ;bɟ׌RJH(bj8̮e#tvܕacVQmYmJ:(?IwuQy ǵqZ4]u{{ha^][$)_,3_z o7 :""܎lkb""""paWK{Nsd).ӻpIxK/k@4ثτ/~(mhYEqH(VZ@$#,t|Dګ;-֒Z{c49rqyt^oWc[gKE;'[Ih(I/tܕQ3zF\\:ȦʼnJl <$c C4]Xaw>] ikc7\`3{T8JdɋYniDv^Y٠jh;ֱ6cͅv)g P 49#*CsuUŮp؃MSM@j& Bi=A31At\b8#ֶmE-t,ᑗ Elqͣ:O77BC*7QQMeMLp66w F9>1Y+*y'AixꈈSfÕ0N ?[<\ ZczU2AZj策zia丕7JwnܼIѾ^>lls})8A07>tEVWU"""DD*quTWic!8qx.o니?M+'RGi"{gb_${c`˵n~չQo{%vaBQTK-tU}kyPCAǏ DNe.R`mD0vw-niGE+kqvF[NlWVih*fk (Ty9fh4nA`%CNY<`HC=@ZE ksN{-?nYt,/%h%Ͽbx~QFQFZtɀ朅mIs,hʈjq m0+DH1H\Hx.㉼CYvO.1hӎ[}ZKlӸA{f>9uRdDDDDA ~]~2v \7Zk]4bB֜gum6kmm5d$$Mj"" DDDDDT;n޶frNv 9u].e}8evE26wFmhmGؐ\p 7WdOQc$~ͻP:NzM,VqTCZwFZvn%#PDs54:6U_fl1`1W.y{G#x|n,pA7Zjesgl<Y'CvË|'B<2Ş>%gҿɤ 9/2Z%vI>),ꊨmu..h[j&ci`nCpyrTR۝h4- V0[Y.|q×KGsY$ooa(s>[5XDDDDEа=k@/K6C#icFW*"uDDDEAn+r}}DrQ\J^TC?XlipuAn=fn9k^-JloeR)87[NKnpKraQ:v-cع'W2Qf򋔎LhbXY$=ӧO5e,Y=V]J qȷpb5C[x$Z]^Jis{hmV3[ 7Sݮui8)s6;MT{XX;!FZFFܳG֗U Ch&C_P}{wסwD6?jWi_nöM\Tq0F'skqςrAEv*LC#cr[BՍpp:* r*xmQv:{qmnVknTFED!@CٌaH*n[EyVSA-0u3!x{8$c8 +Ɵ)K,kh8=Fy˃UW >R6AJӤE1#k[QhjiʼOq`KvX# 9K$P@sAoSA׆]1De:4}AT۞ZjҶf•NuDDDDDT*\žIcKJʙ'Ĺ;C)שؚ2] 4tm6I`EMK9[1[@ i`>" 529ǀ+_[V"5IFT*k\yRH8̄Ϫ7H\yךe51;pmPѧ(Wz5rd0IAot`PĦ̭e¦u=38:A^K\EF)dWQ65V\1}cXƶbX0`E),興d`Qge8(2 w5tO9c"b92ϢC}Ԯ*bvəFo TqUm_8C MG4ꛕqmv,Tcc{2K#k<*RղjW: a1Fsn\% Բ@8 w՗Hf#IUQ9 ܒCwi33%5|qR6h$tHՀɠ`lRnegG0Zz9ӝbzzby#B *=1F":->C$U09lY #~^HÇ'5™cZ.[hIAW$ok0>ZKSIYQi\*>0`kb%X`EAk觡03K#ЏRWDG#^`*%les瑟RuT!q(-5D#389]=k-88:*"uEETDDDE;`Š?.-8Q2fDc+^;rΏi+ "آhw4ְ9kp QlO57O+9YB~5^L>yZ pUt,uPW1͓Dn ?l/Ak ҃iݣFdӸ*&L5Sآ$[>}etHZѤ<;GU2;g~Ϛs' 9hX|ŀuby,SG0vi>)qi tP|x M&="j`m864`kꥅ >guF ncI"""""q5JC1\᫯JOɳGO᪂hđL0F(vY.<3;G8’ܭ1J$COQGm`7\đX ]d6@pr0"""""""-[nP ̝<ۇHªӇVZ5F[L{*;ׁ>ԑHݹaX$SO[mښH#[5~eSKYHlyox;D~qki :7u\I͇ ]d $ѱţER933y>૧ TԬs΢Fy~KӨQnj9p& a0L& .EӇݬ/W3lBZgQgMYVY~Kf+`ӇkN 䤶gR6'[$i[XL+ L2B֙v7\Fy66րIc]@R6;a0L& aPW X_ T6n/u0ugE?ߒyY~K%G U)x sŏHA)JJI=89%gOwgOw; ` IKOw䮋k+g\3*?+8OO'<Ϭ{$>)Yzۮx4|ܤ6:$s w,w2Vn7\qr$st8`٭˰d)EDA 2H?jZ,Ȍkp]$DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD_acm-6.0_20200416/doc/manual/acmdoc_html-adf.png0000644000000000000000000000531010663645550017336 0ustar rootrootPNG  IHDRuVJJ IDATxI6Ea='β}e}e[0b|<_#K pp׏?_Po._][ _Pi{䏟_afk(%/[%,5#VM8P(h+o_]@ïXf N%ᢔGY/9yGQpW8u~ 18Vu^ԟF~Q=S R$(9X:K{ϲHb~ϋ#$,8q,m_-ql\*/h& TL͙9{rwRAS)jƴGمX |.όV*f]KnG.:.bץ#@h & DiJb6-Ťm8POՒk;b?]a۝B{Y ['_4V }A߬J%h6Of;V0SU(xjݝY^EW~t~5AP`_j_}pQﻲU8NQCQ'+Ћ)!wqeBan&$+M.~\;ؾ}/mݯ#v]+ ew^0^{ aـ䒦G3nH0:a'<\,0VۢȰ{hby+;2P]{󬿬[.x2hSQY2pH %4q{NQڿ/=8*sgkoRX:d;;̺U'^E۶+{ؤjXg@2%p40\)_~z-3ï5Qe_Lry?K 0B l3! qM8#\ _V a7rͫnwތTs'6D__p5QJg&D3\%t{sry1@i/cT \k0Nl?OwÇyJ:PDx7G={GF^.v?)g q%xdlE\w7&Oz$e"9#ymZ[bK#V-,JͨŚB=[+QH(v^T9Ͷb5\^Q׽mUR sH4Ok:uJ ;N80d2٣Oh*(З\DO]_7pSM%JೊxK{B /nP @.#G#dykl f'mL;;7C|.~AQy5$wɥ rS f)6{ٝ?Bo{8}{L .h(ȅ_rQ#\-p>$xϳTX3=_7#~Arg/mwd(bK!Hg˵\Vg~KgOk+~cyvT\U#Tlnwa B=(-lo,_@.j; Jaų1- i  ްB.}ё/&k^+,qDF.# ~~E ,yM\G@!n?Bgu u8kd~tߕ'byr˲K/x` v"b:E~A10LQWh=~՜2uQ}r%,/hQ\ XŔ_G!I0ړ_DW%7`r;נ妳#dv2Q9m>_t+k0&K!~A )~۪t/g=2%~ܵk嚊v3@w/86Rk*.Q `R^r-aYA.0' oy~,2jEWPڐ\QLř#v\7+b..Tl7?G>n`0\3=#6{'nTͪR_0wxK}) yiy)deSxt/ ug &K8|Mqy5C- P Ux#!#UT~~3#ه_ ~~/3x~`{{(IENDB`acm-6.0_20200416/doc/manual/acmdoc_html-ap-blocks.obj0000644000000000000000000001417210644355520020445 0ustar rootroot%TGIF 4.1.43-QPL state(0,37,100.000,0,0,0,8,1,9,1,1,1,0,1,0,1,1,'Helvetica-Bold',1,97920,0,0,0,10,0,0,1,1,0,16,0,0,1,1,1,1,1088,1408,1,0,2880,0). % % @(#)$Header$ % %W% % unit("1 pixel/pixel"). color_info(11,65535,0,[ "magenta", 65535, 0, 65535, 65535, 0, 65535, 1, "red", 65535, 0, 0, 65535, 0, 0, 1, "green", 0, 65535, 0, 0, 65535, 0, 1, "blue", 0, 0, 65535, 0, 0, 65535, 1, "yellow", 65535, 65535, 0, 65535, 65535, 0, 1, "pink", 65535, 49344, 52171, 65535, 49344, 52171, 1, "cyan", 0, 65535, 65535, 0, 65535, 65535, 1, "CadetBlue", 24415, 40606, 41120, 24415, 40606, 41120, 1, "white", 65535, 65535, 65535, 65535, 65535, 65535, 1, "black", 0, 0, 0, 0, 0, 0, 1, "DarkSlateGray", 12079, 20303, 20303, 12079, 20303, 20303, 1 ]). script_frac("0.6"). fg_bg_colors('black','white'). dont_reencode("FFDingbests:ZapfDingbats"). page(1,"",1,''). text('black',176,89,1,1,1,59,15,0,12,3,0,0,0,0,2,59,15,0,0,"",0,0,0,0,101,'',[ minilines(59,15,0,0,1,0,0,[ mini_line(59,12,3,0,0,0,[ str_block(0,59,12,3,0,-1,0,0,0,[ str_seg('black','Helvetica-Bold',1,69120,59,12,3,0,-1,0,0,0,0,0, "VOR Nav.")]) ]) ])]). text('black',176,153,1,1,1,45,15,6,12,3,0,0,0,0,2,45,15,0,0,"",0,0,0,0,165,'',[ minilines(45,15,0,0,1,0,0,[ mini_line(45,12,3,0,0,0,[ str_block(0,45,12,3,0,-1,0,0,0,[ str_seg('black','Helvetica-Bold',1,69120,45,12,3,0,-1,0,0,0,0,0, "Landing")]) ]) ])]). text('black',368,89,1,1,1,27,15,8,12,3,0,0,0,0,2,27,15,0,0,"",0,0,0,0,101,'',[ minilines(27,15,0,0,1,0,0,[ mini_line(27,12,3,0,0,0,[ str_block(0,27,12,3,0,-1,0,0,0,[ str_seg('black','Helvetica-Bold',1,69120,27,12,3,0,-1,0,0,0,0,0, "Turn")]) ]) ])]). text('black',368,154,1,1,1,56,15,10,12,3,0,0,0,0,2,56,15,0,0,"",0,0,0,0,166,'',[ minilines(56,15,0,0,1,0,0,[ mini_line(56,12,3,0,0,0,[ str_block(0,56,12,3,0,-1,0,0,0,[ str_seg('black','Helvetica-Bold',1,69120,56,12,3,0,-1,0,0,0,0,0, "Alt./Climb")]) ]) ])]). text('black',368,217,1,1,1,69,15,12,12,3,0,0,0,0,2,69,15,0,0,"",0,0,0,0,229,'',[ minilines(69,15,0,0,1,0,0,[ mini_line(69,12,3,0,0,0,[ str_block(0,69,12,3,0,-1,0,0,0,[ str_seg('black','Helvetica-Bold',1,69120,69,12,3,0,-1,0,0,0,0,0, "Turn Coord.")]) ]) ])]). text('black',368,281,1,1,1,47,15,14,12,3,0,0,0,0,2,47,15,0,0,"",0,0,0,0,293,'',[ minilines(47,15,0,0,1,0,0,[ mini_line(47,12,3,0,0,0,[ str_block(0,47,12,3,0,-1,0,0,0,[ str_seg('black','Helvetica-Bold',1,69120,47,12,3,0,-1,0,0,0,0,0, "Throttle")]) ]) ])]). box('black','',128,64,224,112,0,2,1,82,0,0,0,0,0,'2',0,[ ]). box('black','',128,128,224,176,0,2,1,83,0,0,0,0,0,'2',0,[ ]). box('black','',320,128,416,176,0,2,1,84,0,0,0,0,0,'2',0,[ ]). box('black','',320,64,416,112,0,2,1,85,0,0,0,0,0,'2',0,[ ]). box('black','',320,192,416,240,0,2,1,86,0,0,0,0,0,'2',0,[ ]). box('black','',320,256,416,304,0,2,1,87,0,0,0,0,0,'2',0,[ ]). text('black',481,80,1,0,1,47,15,88,12,3,0,0,0,0,2,47,15,0,0,"",0,0,0,0,92,'',[ minilines(47,15,0,0,0,0,0,[ mini_line(47,12,3,0,0,0,[ str_block(0,47,12,3,0,-1,0,0,0,[ str_seg('black','Helvetica-Bold',1,69120,47,12,3,0,-1,0,0,0,0,0, "Ailerons")]) ]) ])]). text('black',481,144,1,0,1,50,15,90,12,3,0,0,0,0,2,50,15,0,0,"",0,0,0,0,156,'',[ minilines(50,15,0,0,0,0,0,[ mini_line(50,12,3,0,0,0,[ str_block(0,50,12,3,0,0,0,0,0,[ str_seg('black','Helvetica-Bold',1,69120,50,12,3,0,0,0,0,0,0,0, "Elevator")]) ]) ])]). text('black',481,208,1,0,1,42,15,92,12,3,0,0,0,0,2,42,15,0,0,"",0,0,0,0,220,'',[ minilines(42,15,0,0,0,0,0,[ mini_line(42,12,3,0,0,0,[ str_block(0,42,12,3,0,0,0,0,0,[ str_seg('black','Helvetica-Bold',1,69120,42,12,3,0,0,0,0,0,0,0, "Rudder")]) ]) ])]). text('black',481,272,1,0,1,46,15,94,12,3,0,0,0,0,2,46,15,0,0,"",0,0,0,0,284,'',[ minilines(46,15,0,0,0,0,0,[ mini_line(46,12,3,0,0,0,[ str_block(0,46,12,3,0,-1,0,0,0,[ str_seg('black','Helvetica-Bold',1,69120,46,12,3,0,-1,0,0,0,0,0, "Engines")]) ]) ])]). text('black',176,72,1,1,1,24,20,117,16,4,0,0,0,0,2,24,20,0,0,"",0,0,0,0,88,'',[ minilines(24,20,0,0,1,0,0,[ mini_line(24,16,4,0,0,0,[ str_block(0,24,16,4,0,-1,0,0,0,[ str_seg('black','Helvetica-Bold',1,97920,24,16,4,0,-1,0,0,0,0,0, "AN")]) ]) ])]). text('black',176,136,1,1,1,22,20,122,16,4,0,0,0,0,2,22,20,0,0,"",0,0,0,0,152,'',[ minilines(22,20,0,0,1,0,0,[ mini_line(22,16,4,0,0,0,[ str_block(0,22,16,4,0,-1,0,0,0,[ str_seg('black','Helvetica-Bold',1,97920,22,16,4,0,-1,0,0,0,0,0, "AL")]) ]) ])]). text('black',368,72,1,1,1,27,20,124,16,4,0,0,0,0,2,27,20,0,0,"",0,0,0,0,88,'',[ minilines(27,20,0,0,1,0,0,[ mini_line(27,16,4,0,0,0,[ str_block(0,27,16,4,0,-1,0,0,0,[ str_seg('black','Helvetica-Bold',1,97920,27,16,4,0,-1,0,0,0,0,0, "AW")]) ]) ])]). text('black',368,136,1,1,1,23,20,126,16,4,0,0,0,0,2,23,20,0,0,"",0,0,0,0,152,'',[ minilines(23,20,0,0,1,0,0,[ mini_line(23,16,4,0,0,0,[ str_block(0,23,16,4,0,-1,0,0,0,[ str_seg('black','Helvetica-Bold',1,97920,23,16,4,0,-1,0,0,0,0,0, "AP")]) ]) ])]). text('black',368,200,1,1,1,24,20,128,16,4,0,0,0,0,2,24,20,0,0,"",0,0,0,0,216,'',[ minilines(24,20,0,0,1,0,0,[ mini_line(24,16,4,0,0,0,[ str_block(0,24,16,4,0,-1,0,0,0,[ str_seg('black','Helvetica-Bold',1,97920,24,16,4,0,-1,0,0,0,0,0, "AC")]) ]) ])]). text('black',368,264,1,1,1,22,20,130,16,4,0,0,0,0,2,22,20,0,0,"",0,0,0,0,280,'',[ minilines(22,20,0,0,1,0,0,[ mini_line(22,16,4,0,0,0,[ str_block(0,22,16,4,0,0,0,0,0,[ str_seg('black','Helvetica-Bold',1,97920,22,16,4,0,0,0,0,0,0,0, "AT")]) ]) ])]). poly('black','',2,[ 224,88,320,88],1,2,1,140,0,0,0,0,0,0,0,'2',0,0, "0","",[ 0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[ ]). poly('black','',2,[ 224,152,320,104],1,2,1,141,0,0,0,0,0,0,0,'2',0,0, "0","",[ 0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[ ]). poly('black','',2,[ 224,152,320,152],1,2,1,142,0,0,0,0,0,0,0,'2',0,0, "0","",[ 0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[ ]). poly('black','',2,[ 416,88,472,88],1,2,1,143,0,0,0,0,0,0,0,'2',0,0, "0","",[ 0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[ ]). poly('black','',2,[ 416,152,472,152],1,2,1,144,0,0,0,0,0,0,0,'2',0,0, "0","",[ 0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[ ]). poly('black','',2,[ 416,216,472,216],1,2,1,145,0,0,0,0,0,0,0,'2',0,0, "0","",[ 0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[ ]). poly('black','',2,[ 416,280,472,280],1,2,1,146,0,0,0,0,0,0,0,'2',0,0, "0","",[ 0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[ ]). acm-6.0_20200416/doc/manual/acmdoc_html-classic-panel.png0000644000000000000000000002131413156510016021310 0ustar rootrootPNG  IHDRp| bKGDC pHYs  tIME D88 IDATx]7_O ؊@r+G`gv` &鍠ߏJ $ =>>"$@P %N~|%^e1U4a~̭R_7| eb`=Nzغ ؂)ǠGOד=};,k繆cDE6[l^}OY7 }F!e&@]fZHȻOj jgwKv\&hCt ] r?A>VgN32xd& _iOh: Ӂ!8Oc2@Z:GaZ4ajelESh>+-+Ot!B Zߦ>A9P;T)$l B*P +^a,`zRkw(bX]*@Z K2x3CԕD PS)hF1e''TF.l2M쭃tj is+aD- Ղ.!Ԩ ڕ{fDA*t+BMV&#@h()KI`TdQ^PfeVc0kD;К T:* ^*t>ZE5i"ؗ>P0 T*t^-v۶Mo[ŝ+~U12)s *\  l>ׄYG|5T@Z亾~&r`>AYCϠ-uTJaS7!3_&N܈۶m_yχ_ev/Njx=zDm:VsC`ys f___S<zM~q5W4zAx ܚ3A]:c:cŤ!~Myhϐtͤ]6U,mf_L%Ư5f+>>qֈݜ)-6kveSmk~ CaT"KYiNJB2'K - UtD3v95kFCˬym9V܂訯u{m,_:nv{zFrf}zJ''@(qeTف|S[QVݐYp'Uũ)MSJ^E?)@J׸z| :ZB*L3Y{Wp dnW$27'suIIA >+7d>\~[]?Sn %O%Y%AY/W ʨm BR?V|PA*W7۲mI՜J|8o 7+pꝨJd~YMnVC009WQ;ZTfwI,*m{P`ڇ5+Z?]0ݮRۢ ٖpþCF9~Bl Rm< =̕ [{|gњU==Uׯ!0möyUp3=4"ņo0bVUrj3jl]rՌ)I%G̃ 5uW>܊ bڶnf :xrHZ37݈!:pף:|g붅ܷopm9k>;]U6 ˫J8_\M=v{;Nu?UmiIN%MۛytڟQe~fy.B<6ꬤNEp7sAw i;D"ԙS5٫_ĨOj7 uNNgҟb(0`eS j# ǵdDn¶39!Z->303VS ðȩq l!S\ʦHǩ-Eb(˭:&b=?i[K K'W$h RUA$b/ QV8M7].177c[4ۊT/Z)>Zº6Jxt6}k%Tu͇ېk)m?ZpQY95N+>e Bm~RL|H3 *bri~׿տ%%6ehNKD"u* THVwښٞq󅍈yã#JjYؔPIvYL WȻǛ'"s*.¦lh&TU-5ͦ.z<B6i;ٖC2JoۅxEؔPtZ\MC2('YkNM%JCk$At-YksLDVz{8Ʃr;)V/Ԋԕ[]*W5OLO\X2htLyJ9r w^\TBl:^WIm 鯧1Ķ5u)_Jp2r)MJ}Աp4yg OlQiSO4ߣà}=VbQ)|z[) >׶9%.0HC^(~^h 0Uv *c癨SqLCi˄_dL{>JhjW&xIC\1yXcx(Ds@u©W-{}ҍM[Z=6a6N%&jW1bDT+2v3d]d\hC%q[cvh& ܜ4U/PUa8N z& Qi]EC.qj k6͖Pڶtwo\{;GUM dd~Y3SӼ$pW:O+/*Km%hi|لdU6VƷ ʬ/cVɡV;Q?AWcz6 %j]]InNoɕyT&HfWVOv5U؋U7ͯ _C_V O63k2w{]uɵ%lJ:M0ҿ^z4.m"Wz  ‰\eKO{ֶQ[e؃G [VOB6IGvR>A7dE^𲴱0j-EUXp`>|/R`Duh͒F>Ef[ADF!vP۬ƧۧΩ7w_T+7lobx:Y{HՂ?, 쳈~vYs4ʺKfG\(;YąZSA$Y_o+I/9MJlN$!y2iTƏ^׷=H(T->̋F8yt*L)f e5>7vl߶-FMgB2 j;JmS6Mp's˝SO[T!ctFpH lW\CUan6ǘCQ!atTȠVP=tKG~҈P-ΦZLRzAjAUT˺Ñ,!BH Df(6iQ{ޔ32Ap> B,[KLDLuqᣬ զhrG0 l1+xYÆITa=mQա3{B:!Tk˴j=<SևefwVt9ەw ]PIZ9+%)R,^KTbI?}Vh.+N.=znz–2?JC$tS>8p#QLbJ-/M>Z|ձS\Cw`#n++aMNX^qf$ey$ǻ2_g^A6 1 TF: 1x=_ɽ 퉞AOr|uvɣd$Pk4v6*Bb 5JKU2KZO~{?nf2,44ޜJ]]l۬a2Ǯ>#Ʀsw0내Mz(wLS5 -E5=Vns&%-E6/yto\?xxJovz/m>ED=+p(dVI}BKNy&ml/mT^^)~}TvM=߽O=|0%u)3$ƀu`93niMR%(X!; /ţeȠ*G4 Qbڡ5cJSy;@݀!W;A=؎D +[`/QkK=PVn ABEE!a1vlDWqwz`دFo rѶ?F[m(B9/HEe讓_MP/j)Ոx%эt fǵr<[Cgz4U»&|Ljdږ K)凷5lԽ_w^p)?GaJ}Co&Sr w7DY=[ ;Gwu4^t APo:@J7 cIȮiݬ/.P\xJlaΫ"k)K[k4fP+Pm/ewܠ`LxjlnT?KB}]6eԱdP2{#0EhLm*~q&e)s_#w Јp\c-ibGC t[ $J1b>hvH:RfW(A=j)i4˙b!nCǑQ6ݩ<Ki7Y 4"/ˆW T^9G i>Mj^hB1CSC 4pwixňng-Ρ(Zg'.5 H@iwFOXRJD-SQ.?6Mtv$ts޵MtgӍXf[z2"ffS(?[TQg}˘9N9(9-zv$dΥy QET)K1/}%w`) vö98xMM1ח=;¦u}ۇM,'B>T85d>pBĊHen}Cnx>.`[ږ `kDe~ɿ tye>MQcnfaâVk R#W:- 2жgV܎Ɲ ](o#;^$!Wtz˔b>=){xZ1ߋ um88FZ8KVh5ЙM_^ɕ`WH2Mp*)T+S:wo^zFRȱlc8^K`\-`M7*eRp,KxYش: AۂnBc7eM{7lmS9zsR8c{+k[tI u-];NoE48^o΅%^{~ս^R} _ вcȆ2@ؖ5#W.i\JZO+tPB2w':]¦DOEìTM_gem-RJ3#J%wL c?6ҘSrHc%T_5 wy9u 8ux$3^6vkHjM[ln.ے m /FRb 2jȹ=;ISG%tTt2p¬B>01Ԫc !E)%drny$jyzO}V]u\4yq[w;zF5ma^$:yk>Mz{&ʼnN%]O!WU:ƦabHO4A*xL(W =abhw9{oثۋW!) g-յsmVt'v{+Շp[ [KotΨJ]ӢYq̬wLjZ>ۍP 3A)B!q&pJC5!XVaw!B4`ٶf x7ζ߇P7-A)Sج TɋƩ4=P;kݶuYZIM XWIAoͥ!yZlUET:kK+eMc[gZ;m+Yss^6my-u>?tgȨe}Yg--m9KuZ0_kHbȶF=2gNJg{8ɜVh/ݺ4)ɨ'HS2-=U$Fig.:xpʜ6MӪ8[:O"42.=nv5ͱ 2NLS?۶ )GkN}b-rtO/(s0"Jd>PNT,zi :RP\kEс'eJ}RN<36(50峺Ps;F'o]FG[ۑ-fP?x2Lѱ0M9Nw%ne/RPrRYH`vޟe}4#}h/Kiq)ɯzdd.g'@˨ j*hAWB,dX[&uAގMmh: ƨGu5[^Bs@, 1 ΀X?&!IENDB`acm-6.0_20200416/doc/manual/acmtcl-dis.png0000644000000000000000000004226413175033707016361 0ustar rootrootPNG  IHDRt&J IDATx{|i}v \Zdkqq0k*@)l瘗aW('E5m$)Y6Ca `/krZ~{.KpJ?f$F3mI_v=<\>}3z!ON8p[BJ!yB!%lB)TxrA 0_ 4dM 0Hc0Ҕ'_Q\9I=O$zOI LNz}Qrq2*0仴 !dOXR#k[ZZOu}_\)H=bP !{\>]Z OAW%^u׫+~_۵Gտkƾ'PgiH{NHhꮗo:_W5/U5O5oO'O?o2, ="O!t~O-  |_:#7XUih'^NHZkW_G?n׽GqK^rMwʗMY$fx^~3IK 揀7>U/Ayiq$< ѳw,X /Q]w75[[7ʯ/yf * |8֪~|  _;/ޅ?9|A;.?7J?OW'fp߼'_>}Yoa;|濽I<92u~-b15h?'[0{ ! 8sq0pxJc“5࿶,⡍7e 8K:{&8?VSn|!W7Oߍ>M~ױvϻ9G;x9𡻀.~doCGq+y?6}̨xa_~GLEO0KM^x=|i|ӫ|'?~~ #ߦHpPZٺl2vaB{߃?ٿ} /q[6w w7S}{̸3_^\,fo'S/nQ@u}sL?373-! `\E`?206{53O;xloE^V_?ǟj-[x-߯_»{>.mwW`&2"y xxk-rXe8W|QAHB7` V𲗿_4_ॆ{ Y/_R;^ _ ?[xޅo T ك#|I8rx&-/B.n?*T~ 8p_Ы'ph`r:c:B܏p @Pmݢv,W {+t,ه{\c ^ a﯂{w|w &?8oPAHZ4[ߌdg#d  F쫭3߾oM^j~Z{Ze]ޅOڿvk6^r;ϾjT ;11^6?`0 Ib|q =0s<>&:W<Ǿ;UhO` | _P#ė'¯͒ '<$`b.g+i].e|q| UpKt?.e3s7| Əgx;ߚ | @G:1䴿4-/l-'o7Qc,|V-ľ _E$Z}{"׽2.I0yFO"ς.=F^v_ÐQ-Ja/^}8#x [㥙f6($wsf$K_⮷70㣟 |4v| x'.?s_'ϡ/EU0GhP"_4fҊ#^OGA]?B /\ !|oG1 ػ/ڷ巤^&m' gcuZ{+>;x>~qF79 -@n|7/}kЕ8َ=(脐 /!_BBBBH!=:ID~CX =:Τ}=XحeN?Trc2zf[:KꆗshC}pOva R$gff.=̙].It04ĠzE~bl2mb$:m^CX]8'Ѥ8xGEb"'6RsBX`3skQ#ءΕpRȱTKRƆU,$k+S.XrKB-$:=NGz{MBXҀaOe4S+}*Ji$:VNxqdǴ&ƺ3S1hӉ>髤1jŒDH,>< 3MXƐmҹf2X6q}pOĻi@;6XƐ ~*W:]p)s*eLDhǤ%ߊĎ1ua,cƩ@?y,&Ԯ:'v :|AҮKuyާ$v)b֦vrq-&Nr4'[h)uvTgz}&kQ;3j~6|OI|J~CBs4>RAU\.I6tĎ2X} ȧnfJ22U'ڰ sUӶF~olF-@t фڕy1Јz-~E(1Jmgώ>tU_\7JpҀ qؒ<[`P}lmseףW<97]2=ͲZuP\A=A:; bY؎SZpmRo yҽӽ| k#a* Ar8'4\=:mafGhW&`ā'yS?:LYYˈRjX]9@ m1z/J gw;YQ9WF,NɢuY#w̿ }.!؎q=㴦At, 7 [.RX!9aKJnE!tB!ń˥bxXmS/8NHVR4+>&Z MHq :?"$;vSBM !N!N!N!N!tB!tB!tB!tBBBBBBBBBB(B(B(BrbլܱBAϒ@ yZ$:m^Ö~;*dqJp n<+ ^KSBA|ɴdfq.I1dq2Q0g1nxEbKɁ 茝g9jy!1s0BA/.˄x.{RYUxFsB!AsbSLZ=A7$ "$18v.˘sUҦ]XHKBA/Q6؈AACA&i9q³1Օ195qԚnyL]8aUYAdS!za<+2M'.X|2v]*k[D52J a*T])X.<2!B)1%qOם9,D17Le%L,:*k Ϧ B}7Dpne aH}iGod]K=1d..ĮYƣ#pQhB-`Fε6ùţ$:c/?ӖA)', '~ZIGAs.Q5܀67qT[0, .YDU\8.tP{`1F GꜛxOT!!$;*2W!`lnl]D.S/E4Nox9!6/jG AFkythR;Z_Mu)m=)(t@0;1{tOblu#=J %61-;I{УS1+ '.!t~=+yL]ʬ F0#p=.Y΁orPiqn XvOQLab<={ E.LՄGxZt$@Wue Z{w< z`Be‡j*noTI"XPf%]w>uSsD'q ڃɏ@ ? f}cmo @.B(;Ce,+alpFq{Ef0U 9g؈-6>;dCKK g!hB-FUrj ./B͡u"jD-S;%FjWduK(2?RNk:y a0jKB(;H#]5.&!sů\Dy.{1dQ'\b?s5`lǸCy !ȞݜTYFTgQlq}h=Sl!l#c,W*`A%RKboxE*[t}@meEv起/L\LKjo_1ցe|vvOBߕa9].BKrsB+R !/tBHAA' :! :!ï\HYt&l+6 ?z1Ru@hB ! tB)咲t GsBHvWa_!$r4wŃB)aAOE#* éA#'S `Qznb;I>O)yA_x+R6MTzjDgo:7$g呌ErϠ.> k׋.(F'+-bT@cB uЉΞf-9T4"K,:>2?'|zBѦ4^J_ƒԋJ/C3:(2j|.^]'M` #'zB)AAwŘJOpkGg7u<e FVKԵ"gP^N?,1vNBH\X8XM3J]?M,ap%=ӺH4+[rBJB N m&3J=&vy jnԉ䎊?OQ!nYqsmNFd~N9$!&{{/v9VTۛBA.9 ʘb <@N@ !P !P !P !P !N!N!N!L] Ϧ:.H!C}HpKBA)|-vORG!ere\}\J(cB)rA7ڳ' IDAT c k؎qK&!;䮉Nۃ-eq/rJ>H9]ft2nORGJZ.y!^]7IMxtb* K[NyX7ҷpCJ12qRc}m0,c>$GoYtɌ1'}~8G4.%&ˊ "$фMuܙuvKQ[WD;JeVf B#&)em~52^}yN֗ipOrz4bp 8')Yg8'ݳDF!UL>VfMǕ+M\]H㎶Q@ANH):MTae*`Q\,E_W]0bQ\Spz<.]zԈ`*RfkH)ohGIb'ܮIG诇l4=*#ya?6K 箴!(sDƎ7 dBU6/_y?N~ndc@UεWziCz`ރ9la=fd*\^zͼLi€YL!Ervm6#C@Vгd°K|}fmsŋGc_JC 9:>ReMyLWw(^)?O =cHd{̶AC8fq w)^K.Q5܀67qL&]kfG|YmmviX ؄ˡ 61sE;fi 5,ߤ2nԫ2Oue`ڎ0l ("<q(yܚUEV,hliwc(R}^8Givp(c 7$K61}%Mt0N麧xw*r!$W"s93.B2BF)r!.B)3(BA'BA'Rp )kn:l6;P ɗ]-g'.BBCJN+T!{D9հ161֭b/״B!yD'nBvcA1 2`;SxBLo7xt:* ( ]0g!!s?ze"kڎ5c;N `, FHz~phOj_{86I=%wHc\5)t2暶s4'-躮FL':w?<ٷ&,*)'AWRoi)#K[z?FXZ}W3fvZiE[ǔ96Vj?s.49#/xO(M[&#AXWqSQPF 0~bCLuUr /?1h;[9%ȟ M=pEzSuQlXX(|rxis1էB0UpQ3N2t}n,3@x:HoN=,zF{)Fuc^Y\D'ѩ\6ùţZ)X ⤺<^^8},8jG A]XKxh <6cR JX _Go$"ui qN.c{ȪJV A-ʼn>?2RBV@O!tʨ;-=%~V[^oiY{K6c,zl. }ifcJo薡5ҥ^PKc%HKMSqhx 2/Ck(rǬ>(pFAEe,+alVaO#Em47Kb> ƍ1?% ṹU4s%!fdUxO΅)qe>˥}v aOIF&̕tM3+^<(XFjǵQ0FY^]@N9u!td#*@°Kۯ͹=Ҟ\eZ|B>Kyx mn\qՉSAT 7M60#_\uڒߢkFV<R-ܗWp{4J{ȯaY~p{6-RιQVvU>(1>Fsp~wY|\HiHdw0'4ŃV?l2[7oU՟LHcm;]@ \!\BHp'ÄlxXN!N!tB!tB!tB!tBBBvDS/Vmq `aXWTn=YBA'9Nmȱx\Ջ޲T,3ӨS;A1Յ :)"'Qgqaag`- !e$颳ғ\(O=k GP&ʻY^iI+ҵ'**}++^7z}PN^ڟ޷6/'/Z2Uנ>f3tD+M.Ó tIe;i}2ҍgR‚.:xd]gv Ms[U׎8ɚMwG-dmL>1c<^n4e B.tfϧ]ԪOP?Z;{'z]f"Oc񲅑)W+#]wEgJ<H4l"$"7 ,]~ -S2b,_Nfhε>1NW޼Kt|ף"uneNiǬ~$wtt5a*Y-#c,YG>Wz%VEyOw>TyȪË@1I_{ q'1Y8I7" m[Y7f~e R3^YJdEDq{ETq+d\M;]e@Ey׻l}L(@7'9FߎqO}Si'Lj]@c%Fj!85HϩzM_1<:>pe"<>E>eEO۟pi#kbL^ze:gryc_o2Dg׵reQ˓kĉz5` yF>-menY^mbgWZY^?cUY;Dşn:$9'jE,ƾxv~T 0ցl BKz_2+W"BJNwBc;ϡ-kw&B}D\!N!N!N!D%eҍfG/FظNNSy6*)Jr! :! z:Ẓ`Z+S>ؑ#M-1N9䑂4"pp \=ķ c;ƅe Yw÷п jvO:Er#;ܬT$Bn i͵6hu\Dy0-tRX1ˑ#a0BZ|M]5f+Y;6'B-RT}WQKXHZKXE/Vyy0L7L!yp [kbX45Fj5e(c#m"|K3 4BAvU/7:X1Ǽ@M&xRL#EUOc 3IQOɣ\h;$E3IٵJ]WWdWm#58'H{45gH=XhKcSRЋ tQs4([,Q3Ȟ.^yYs bLi 1.+]7MilO zQ AF]SZE*"nT~#E9lj70PJ>t9kL "emY:Fd׋WsNajSO=Z(5}hV$>ㆀG@kcט&B~. evm؄@cQu"[7zQ5X C̓Kz84B/kTǼq3V7fOҐJ5^) !!u!<}[K7nn\!˥ďa n=*8%Ub'2F5'sIYcيtUxl OJ3um1qm#0tB D!Z0u\Dc˅B(B(B(BKQR,ݸulErP )1 âl)&I9B !P !P3B=9Zʨ)  ӎŌEJS9䑷3j\',@Fh}(A@ݰ\Y )5_ƐŁNp :| K)੿NQHaiR$:mCkCpHsLVZtRxƮV6bH뺎5s]]gtoCQf?rC.֮ k;,̭3R:c;ƅăb!eSC3MGJs<ɞt1Hrl#=K˘UGoR/L{ItÔ5.akaS7Sf ƏWqɈѐꮘz쨗|\T5i( İtmP"Z.9찤1?~X?54ӔQAu${H#shRn_6؄G%^T4LU.)c,"?zcL^`avllfǤBQph2)[ĥ#e*sʰTIt.ax:YuHh? t|A%WRH8)'IWGtB)(BA'BA'BA'BA' zIDu'1&Mu7G /gKddΉ<1<?ټ@!!L?5`h1χD@v7>B.X|,D}ff ;**L ^8 ID(ef&cn30՗uTA7b)Tqw88ӈ+sǭyLI!ڢl{+71vZx>%L;UX'`ŋR^וnL)/S;DpOZS KdcP[<6U6V OI"e Y\\*! mݓ]p"y!ė,9C^cc L](} r!{\#Ncjdף2. %Kϳ06Ŋ>|.\nϮ/#џecYz;[VVǃ0/FV.%ŁV_ܢ#Zo⃵f8K):NIE7q}v@=+{?>bkؿAEU|b.rG y)hXSҗ YcyfWt5PySD'qNQ>3N|* ~f$4.x'!LHePЋJw#4tOcki@c@YAqxd_^h4&+ųb9V79y_`(Ԯ,~/!$6}_C7>^%oFp7 .(y%WJ(\!x($h(,0(4hcЀ#O:6#q,АPF.D>$RS҆Q!*kfyf^ fuI&g`R8ڥ߅!^g(w2\{As )hK'{2j~FzJzJJ)N~'z:+%+Q>駩&넓jB V; NFf*mhbV衺+ovj.~ ۱:Hon^ƶכKVp Y&rw_rTK2]#P*rN 2lsv|d>{sб6I4UC-JgtӺ SOO=V#Ug=U\o5T`C]Nh/6oM-ZtsK3vWfn'&8l[Tngw砇.~ͧ_o.Ӕ̷6z^{L\ϻsTV7ûtSD?oΥw;?=]Gw}S^9f.|0{I3?0:EPt׾u0 $G9sc [7AL}r78B 0k h p0L2DYHD%Jc"rL|ț('4ombj*1&Ўe X#+B*k"Jf8GNjFJ r)ܢ!DvS#CIcDJ9?\'IH޽򖸤)V4%'IY*ȼe,ELZS%d9jzY d"t5Ia.1^&!8PR|Ay>G @!H47I2N}3\<9K6Tr(Gчb1$%5*G-?J΀~! `!Ǘ@镔Jdԩkr+*TiW, VǺD!O (UmIֶZ/իTwd vū`FA~U`;[]WyX`9iR\UVf hGKn'],T˷Hlk {*ҵnԶݭoY wb\2FmG #J׵]mv;Ⱥլr5&ɴMzѫio]8/վ^Hⷻ;b T_ {WXFU#Z6~ꖸ-*L8A/zϢO$9S0mF&hA%դE9NS-*,HiJe+n5bQПD!wv61ڒ#3n r b."E6glG%VrZ;5w=7tA|j!}!Ɖr-:D)I)O44F9mbVh]8<66 )uF|m"b׌}d'[۬5mYEUP/8Sfht)iLVbt-^zrg% gCהTu-t fi QI^s( #^BǴ %4rҰ.%)ƱGC6U^aН*~|@rҹoX-W ـU d*W/ʎCgou@y4ďsƸBvq)o73c(COOI4 FHju(TntFc!zgJom ƍ8牦iu$ S,JR4h(TdIs%|8:wWYڑWכnu `#hzÑ~Xj:k6ꪰXMxZ*:U$٫脀Ě f7MxJ6vUCL1Ϛ?e&ʞحתw6AhZ핫48N%z險h8I٬ǰ!(#iR+] {˙%;yɲ* Z[粱iG:4LK8:ճ&JH/6G@B[F;U>RYW_;[N{P{G[ek%Sk1lC3hs&NwF>pFCrGt;xk if8|:P\|Z© ׬|˒jι uIl+[ϴi|[l|q Mv\, M ] \ЙK]o|f{h%( ҢU),.02=4,]6}8:<>@B=D]F}HJLN;acm-6.0_20200416/doc/manual/acmdoc-styles.css0000644000000000000000000000110213175033707017076 0ustar rootrootBODY { line-height: 1.5em; } H2 { margin-top: 2.0em; margin-bottom: 0.5em; padding-bottom: 0.3em; font-family: sans-serif; color: rgb(120,120,120); border-bottom-color: rgb(192,192,192); border-bottom-style: solid; border-bottom-width: 0.1em; } H3 { margin-top: 1.5em; margin-bottom: 0.0em; padding-bottom: 0.0em; font-family: sans-serif; color: rgb(120,120,120); } P { margin-top: 0.5em; margin-bottom: 0.5em; line-height: 1.5em; } LI { margin-top: 0.5em; margin-bottom: 0.5em; } DT { margin-top: 1.5em; } DD { margin-top: 0.5em; margin-bottom: 1.5em; } acm-6.0_20200416/doc/manual/acmdoc_html-vor-line-sigth.png0000644000000000000000000001443310667616724021466 0ustar rootrootPNG  IHDR  pHYs : ÀIDATx]݋,]nFP A EF_ ^!s[0w^? dno Tq#Ċ/VR,vK8Ly.JݙIs><|J;;;ab@ #0aBJOڶm۶8  p'"tKa<۶-<w3,xkdQ'603gt@aT8J1 8j:klҸZ,̰';}EgDn6lt} ςsT9dXNcPU՞aߟ6F u{x&b*$m7ܞeeYf+%nMɋ0,ii 0iF9aXQQg=i#<0lQ:Mv9R6"SL;́ FYeXQӑ;M1EÐJ1 5O1i,YVTa=?VQ" 4_v2J1 |ta#vTfet]#%K*T3,yv׿4 Q%/ȰFM'@2GQR)NXcH][?2Z;3FAAh3l?O2]^3~i'|iaXA1pAR)"3Mm7i~v}3ġl6ɥctSNQ?QEuwjJlmmٳd"a5ne.r޽d"aybƆ̌]|^ 6 e9߃O5M b,i?12!L≄Z3,y71i&ɋ$ݟ%S&&>F)(L۔C4ժ,laV%/nv,eY2]'%/&`XJ 3c/.ư)yaOg{_ &ʰ)frRFa(l0n5S"O*ŹYmg`n'~ "';>Z#S/:9 Pˁ"ÒSP{Xoz3X %0t Y ́#y1$uب鉦 ;c~q]H쩕  .d=y1: pJl0Vi"7~``FXN˹J"L&m{飯jYV&DK(`Өf{3RŰZ#/{ݲRKXr]`|` sg?*AhdF#j3b9ƆEe,"58ȻFy^&܈z$=k6s a(/b wCÐ6qXO4Mt\f5rt2A`4M[[[CѢ0EUs\4AX²A g:gy^  l1,$ 2MHmJnnX^&7,#Y|90c_\e]GTRjBFD6aF! RUsMyPd~,'',yuqgX$:iV)`XQE ǰ7ǎ;sȑT=\8=EeSBӴKBKeݻ:th MLF?AUoV&㰏?֭[޵kװK&ż{p|qʜG zFze=sk׮10w}<kڱcLj 3-ZiY{M_nsbTEQl1lnm0:eٲ0b"a# $IgŌRod3MHsi0DwhZ$ah 4'`K |NbX*na44#ajTU4jawyvC + RnyF vbXV1ZdlX*)Q$h6mGrٶmyPZ_߲,T*䀠cS5,xm]EMslC5O.iγEQ0:u:H&LH(W(Υa6Jbf_EflYu/S"H>Ka ,lہ>9c%@@Hx#o;q#e9HgbLAXR&p  pс 0= nH./0?@Ɣ_ :BR0Q!@4  BHh}۶mu߷Ǜ>_;8Xv{w}wƈa!AHry >YWhRBwvm(Nd{l|N;$3$U˛)R)I9.3RqRC R*;g)m5 ow=.eXr:̧:SD<*V"#dO"p@-a.bt [^_sy>4%Mj +P-js\!=,* W0=kĨV%`˒H<Ȁ!VHDɬbxy<6&v~*mC+귇1oo??> Qhs4D5oO 8 `)^߶gߟ?yx| 1aޢ$y&E?$%Cl;5T8m \%r"Z>IsI^mNUv"c{, 3mQ8om6ANS7I]%Hl  6 UJ  ڣ]4롡Vyx۾{_hl@`jO qK pb  p07??0%< 9ƶZ:l&4 O" h@כO9-EF$m-]!]DWAA`J?ЋחM,{}yIt@"yҚ^8"p p0%8$ 8 șV;=L"I8 8)>-}xaT h O"i` n0D41=ê49D4`0BE8>%nQ4xRbNX@`<E`fCC A Ka9!i l%jρC8+1MN@*Ik=I۶mD20c`1aEZ8ao ' po4è+e3{@ p[:}ۘ,"ia pHڶmc,b;) pTS@AIIx8 $xB@44$ 8 o iPIၬ4 ߫?o۶m}Nfܨ$ ck pA+~)o h0 ///Sckb phZF 8 @Q=6QC,Шs@4A`fnI@>5"^Zi!bŲ8D qCn8 | pHTY YAsT>'AP(pH2C@#=kF@@eCƂ8_9|?w]wc@@  p#rG܉ 2D@DZ )@mx6ZZh8LF8J@eD ڢK,3C̃Hx)T6!EM@K@80D8@m#z)eǝ $ p*plT}O -18XFJ!e4$ p Y^3 "A@`Yr6`C8@@sYRu1P*T88aٮݗ) p z7 pDZGK pЉ<#2 p3 p^jDR"uRֺF  p0:CnaT@aWd-8@`# EV5tI9$ }<~A2 Cwzw>y oI&D|tC88@8@@88@8@@ٶd}IA8c#~  QvCڐ>uӆ9p p s:uB̃2qlc\fL r+Uti*q tիQigδiM f靑[- 27f*87(}sFy39iu^]]cT~ߞߪ#p ǓVbp8\QY#:ru5x-Uj"W.Ԓ/Ϡ~h֨ju m7 i&$M~W#"bXғ6/PNVeC ׮9}rʌQ_]|Dܢz KfN&u߷=n+:N~Vc]>9]Eqơb[wӞ&eFC~3VtMY+=V~fMb[c(=}3nVv?]擜JgRѷ4~Sڞz՞ߎԑ7[D%5 Z$M{}̧w y%f5|og[{fRet;mhiχ8GeNe_'sK b/EG8W *|JsaɭH7{. ^~u4 oMWZpC \KkU!Z|(^Z]K@J[1b;D;i^KS]Mvኄn[2:M~ɲ"?ވc(vamOޞ):HhM}nV3ˊ]׮)˅m;m+>E.=_q-wMs yJ3}C-ʪT~JЈߧYSvoN)kF81Dz.p!o(:7i;{ӻ=^=# dPzU^߫=n5JS:I F\py??$sе:.qip"Fk4+ZBC l{~fy+FMC-RbbI [wJ-qkI~mD*ح3Hõ~Ƥ敢pתo!_Z. yZIț(˦ J$[K{>[{*CKeo.b#gE ۪JPi7L&+Ygc51o?}m۶?4M)w[+)=alIow>LZUn4.Sj^=䭄)qfFZ վ(p޺3kK6#/qJ=523#Y]0́[!mO\{j"o[]JuN5l4Ցu}䰮o^J9k9ͤ>Q%E:E>Ug^Z7p"(bvUsЪ#)cdoei=Qڤ'JN2Ǭ%Kܶ5IIo}FTIy9q{|Hsf4۸D޴ɼNU w9jχ՞ԏyt.ڪV9Ky>c+1Fg, qqՅD0Rihsn[:ҺsSf}ON{^g'ʕzkr"@gaz []FS>o'q&K ZuV3:ps={-2ԺLRIB?jGI~)r#ț*\7Dn6v|/]K7w'sBZ-=K]i5&6Kȭ&oΈ٢nnD#P{-:R{^->?i{G$j4С-Hlz8}i*5W'rbeH\߿?0J=|zZMy5Z.{,J^oJ~G ѷz 9ykQhK^.'HGQ=7t)p P0FrUMѶ™M'J[,5wGI' W[iLy ~ZmpgQmTVlO4&3EFjN[\5<$4$Fԭ0ֺҁLl8G'wS[5뚵Gz])ep9̾nP&%uG91jlVj=\:J{nJZn؞ȯV34̷Gi3E~,osծǬgV]+zZKRDLaR5,"='xn^rp]C9vݞclϒw#@ז1ll֔ rlʐqskYV%SJ$PfThW6r<Jl'FlIlw!'3p-+96f5;} Uuԁќ߷;U~ϲ{ĵJ] #D&b"#-w>C-R؜ w,6캾ڶ:#vt[Ln oڟdL' sʟMrxó=JN2%u29wͳ;2"1󢽡Ŋ0:74v|7\)q.v6"!Mn + ym7ܨ=ߘTz5-b]!Hx̺PVj ՕVm9хеs1eڝWۆ k%9'!u<'\Cz4HLuh=ZAtC`6F|x!ϷU״m4g7uZ7ޠJD.k[OZDSr'>91T*bQ_;l)W8UcT\aToxe%Q9n1b<{`y{ KÙ7q9I)9}Ge2etZ64 27*m TV3s)QshRj{݊{ lou|[x#k #Ӑ7#+^PQ GB~mDݪwuz1@[Zռ^/oY7}Swm7o??ϊrڡ{@hhH]:m_QO:_ w֟\|='|D8n n?[~[Px/vP&p482R7Y0OEOZSr=٫u$4$v )3ܗ2n+WH"G|]Q90F]7}%nv;#oJ+z)1*AJb/j[`َ}Q9HBI/,|͘nlyqOD@A_ٟm{Okl617-$Qt,m3-tèQ9ɛ Jmd+5"p*vlk=[`CBW3*Pvcrv>47UU-39IOVt@l~Xw>5ڱVT%; O'[ِ4܊=ңKOhٞ(3#Жffcr=9}7S*/3'b PS3F4\ TWrs6z -BZ v|(BED?0\_rbv{}z,U(`Ÿ?[g.p͍M&8Ȯ0WZboZ=徨6ɒI.귯v>KScELBikbE*RSrXk4:cbZ=g_ͬߵ4>+)o7y-8MzXh*ˁ 0Ol:>t^ܧ\+Rqmj0}{WRabuJ^s-vͧؑSo}CpSv =ӞyB.qjjDs&~[wky"15n|:*^!YSmݾd.IDV[/{$jmBOzgݩn'V{ɆCC<|s% km]l s[C!qʛ(I/Wlz͍ QN}~S;Gn%L]7:lL~C߆Z:+S5%f[?7$ve`.L|f0896y|;eE^_IDATD=-j%q]"[*Zwȵ^wɺac[l']kwtkuU-[nE (]|V-?]˟Hwt%E$o79t;Μ ^_u'-BgG⾻v|<'Rg[Ԭ[1}[k$j}n%Er۵nZl/%6269K qcKCI[F컔L8 *T84 r}UcHi, GC -4jo.[\.vX^9ߙrZU! 7s4V)Kvͧ$#wXIl+шJ|D: !lقrYM:|y0BÙ2ק@tKg-Ta/±g呒+rL6C{.}1K.~ri}+qb - F1A,{Iѵwym=DbW"sΣI7Ch y|񉡄4N';8{ڮdZ, --WjDm۶Uqˮ&Qfnfm%Iۓ`'^&wXMm(Mz F4}Rs%&U!dݛ·+IcmJvMОqף,Y:-f,5*糵΃iʤ-q.I'-סQJwsZE5Ӟ,;3۶s%ȶVǕDkY7(Ům4:.LjZ3ОS5ͿZ6!'p- AH|4$FHzi/o)eSS!p#y("bd4V+v>J ᶾQy4{Jg_bʩ~Ho;Dfyz>*աkouCF=˰kDОsV kUĨDR]ΒߣiV~kXXVP)9oIn)țְv+O/oB«=724G!X'kɭS7Wo|mBikFK[+MhiGsbX1]siOH.}aղ-9y]%zwӧP)\(n{ TWkU[1 P-O’cϨ&앀uuYIVF)5gPAV*%,bk"moDqYF8wZ~42R~z7oXC␶Q&_K|H=5 ܨN~"թ/$>=8b~#p-q ߰!mzPM~Ӟkf8ho_萶1UQiGahsZZ}2YS'SiG)FRoCڨ@~#pnq}B +qGIGox^pHS3H}8XP6Q7v x\;5tEhU8@AM>=1Ǻ6\=s8ȺaQOO^x]{q=_98@*tÁvRuҝ f%"!ֳ[01/.pǡFB\ތ$~kdKf~C9-$s+DyĪH,BkkP{HX3 n[ޟʝY]O)iQ$+gK"a[E]7ܴG]3Ko>K;M˩K廙1A7P+)6.RRa#{Tˊlߺi蠄/Ilf:=d}t[ * *mk-|0ĵ.gQ,ox&6iųvcqj}47 w,)f i[tMr(3%Q7^I| q=Rм?KyhpHŎ3!/[YYE4ME,zGZ=0PqF4̇C(%>dc\khhyESmJyv{]ܫ|V8inuǰ*]nJyp=oг/@文(ORuH%g6 )~y^.Au 9#5LC/w,m/Yoۢln8ܫ8osuEZW^=eE{㡎^һhƵ:ԥ4K&p1Ì#su]~[ MH\h>ڊeII);s+%oQ:tֶ57+|UFz/uj$[~h΂o+ͣ7vk=ʺbt\OPI)ml%HttRi{D׽yC_׶(uW=w٨"p c>~+[QQ!7+מLӨQٷ-Mg;`kzazJk|nP$Lk/Ƕ?Ü&uciyɏu]|Dztni^n:roHڗ3&`7aI4Vlttj0DHl݆.o)oZ!TJ)dfMP_JLX"ldz[\F˧De~hdzψLçak0̘ՇUm^i+ٲ-|zF&g-1isKA\#JZ[6n9u\ my]4?l߾m,N/MQOviǶș#YV{K3R/F[7g!k~c%*u2\f[:mi{Yal>W QnЮ(G.,f:JeI!kQ>VY|t:qsV"q>ٕ~pL#MŖǶ]c~kK "kʒ^^hҿfPKʺoкcE{SeXmFҾQ%wǗ@͍]6ײ\שj6L'=#n)9j}ʙJ@,~wdO3kI$B[clɶanz oρEf J?hM~uFBrZq]/ms 'C!4rf5zc}&Y]MP.pa.98wM>!E`KV/3Ans"n/K|piox K[Yi s^5ݝmXfڅct5@b*Cdm &ugJbiF򝠇\4 uBoӘ*ĶSδDbGg8HI׍ׯ;>VZ1k#YVF` jZ~/;1iFܮ]c߼B]?Q7Q(\N֪l~Oc3Qț&]a{oc~ HI^r!omۿG-&DJ~oh+[UwC=kE4tE஑%אKzaKRP5_;o9sW.ѨOen\<+=?z $#Z~3]7g#چPC97VLsW*j;{9כJǝ=1ٶ"@̟_=~YM_s:5> p3-t P7]lK0=GDY@ [ m~_^m#{I\iKs{eqk+ ph,]?rr|S&L۟owʖngzkO_M|LQ8X1-+&B4Ҧ?\ܒS lf8WkIϘa0Fe8EhnMB ^Cvqyp5w[X|sS\{Z|Gt0$Q8Qv͜he"pPU0\yijO9fpgrF=_?mYަhAiY6^VOl%Ҵu>\/]R[67ttp+tp[ s}>c+kg&m;%W}NZ!S+W} u!y2%%tRf|^ `]ٳ55 ֝GΖe.y6ՐGՄDZEܐ8 WYv}NҡtkAIBhI+ckI!kFK5 7"yk}ߋ)1Gsیcqݺok3E]Urx1%*\=1"URt"f .(y5xݾJv\l%5^/ɲl:T-Kic(BY3`-s>q-uH^"lkDdx5yB0p.j7Z y3&5 IK\9cʝ'j YɃ 33%[ )$z\hSs<}P14{=+hE9pǺ_9lZO0y#A= 0՞r[wF:Jr 07 p IC;xFspqmSDEU]9IENDB`acm-6.0_20200416/doc/manual/acmdoc_html_hud.png0000644000000000000000000002067410753331133017445 0ustar rootrootPNG  IHDR)<өBPLTE{[wi|oc~tw_{ok~sgy. IDATx c`uKYz?F66ΚdPU !pH 8{8 ‘,#-X GZ`)iR8҂pKH ‘,#-X GZ`)iR8҂pKH ‘,#-X GZ`)iR8҂pKH ‘,#-X GZQ ,q[}| .JwTgqhU[ֆ)EߔJ?uxy-=3C~ 7-N!gdI2XlR)recJQQ\xzYX^Pˍ)G,> 2\k 7M.%+I 8 J1Z-ǒb>m>w$B[@Hr%^ڂ`Nnc+WY{}y[k2kKۜ^TH#R*%RTR˹9/ ~ǖ\BJpvis8RЬ39| Y GZ`)i1 [[Mgd],eo<|)m3vsQ 6.ng<;u8 iaz[jw*ڙbM_yJ(4[>nEbm `p2Xu(E9v»8p jE T'9*<1ŁP^[XRܟҰmDdDKJ%b)ҬWxK-7ØkX}n>5UIJ)PFH $#Jc^(~?PI1EoS@nD?t6zzuzږE¾Mi[.)Tbc^6`)i1Ztcg)u˺t)pRZ?K^u|Kh,#-FէYJ믺;pPX=ĮU$jRkg8t:`= (r[;9 >2l {qҞyЊo8'tKuzR<X+$bc ^Zzŧp$:BٕL*sοO)žxWZ^GD=G[,:+#ƛ@S4U-O>ƺ "A -ܬGE99OhV+,)3|'xSzԦ5JXm 9 >clN!¡&V)gCx}wu=t|4_$кF6,U Bx$)^:5 fVCP *؃QR-cB^J;ķ,q =q4cJ!8 mw56xW5\R1ڋt,%lFh#m/XJi[/C6j1jc=1r+F1,U_NGRx췊7Xc?':|tkL[(K9yMԝWJRNk.=-ߔҳs&]z*mWJR[>E^ίzGϳ5E=KIq5.笠g(}K9TLQr6\J0+9h-ѷ߲fQrT^\n&獾e1|/jcK1?x%_zXwM1ș?X|pt1-/Rt;CUqN3}qh q, clj]RuGSHڻ&Qn7K1_0!R3F; R/`T)5ѥ>:8܏#wG^JT1]+M7Zd~Rf8&F1 W[m.>Qr0J}?SKax\4ȤTͷ > 1۹~  ސ]uEӳNw)LJq_F 5/8qJq2K~"brn9Fh/{M)Ug&mơsqגEURd֎o>'28"&\}L#, $䄥ؑS} DN1q',0&P8a)š/pS83uݏBDL`)fwYI)C]ig@Yrs9jFꗺvR|6__@P.ec܇K^< ^ئ/_M!\*bGLv*.gbFPYJBHD['ׅGrJ KI =FO5NXc$ E;ڈ&RwI!G(9Ƅs^f>!Y@{H"@? Wr^~_9W`3:@D :Ihg wXw=ߐ|r7Ί|'HRە%x`)}H0yi'$g<{'+je[IP 7->)NN>7AБ(rHQD3>2Sw7GdKЧ1:(trJV~~~|Rt"7ܡSpo.,4'h)k2擨> R|bHALT!\'1q;aOqĉt(# L/6dMˋyz]}9=;")"G9ZJFN^IHWG3@XJ])9q%:s"_ GNHKIJxŘxrRE t\wcҕkCtHk@&no0z xvryS۝8+c;DN<ۉJ': '~&|7;ˉG3'tKi'Fg8oT1sfjCK{H4Сb>ae$D)DPJTN L'^)W7_S1ڈl{'Q@xFIY )R]= 6($L|-ގR~,)璉ψEO)|"O@YFD1|0?1R9d>RtQRL'~:&VƋwW DΠeIĒF&u.u,'"%>O{NR9R~IIQ0a)R8ن;;N4_[ F)m1q#H)i.ȅ=_S|}mN.(T7v &'=9n lqoR4qDJoOۤ4\sSvv8erRԨ-xP)qמ|_Oـ3Tf$'m5*. :ƈN%Ư%e'V\J'z p$ H'v]]JbxDu:QWkXl8yc)FT>'',Ōj䁝ɸl34Ѷ'o dlO&$ Kq:N*NXJ$ОL?R pj'6vR;,Iԛf we.;"~:1mD@y*8=KLLkٙ8a)5b,Bg-8)kcB4Tn*e~βMes y=a)qIK'dR8'M~)(,ljpD)Ÿ{8{XpR61YJTYXʶM;!)h-7>=H rE J)N(žPi7Q's4Pe?:QT̄"R_"eb 0}RL'I߭8DĜ,JI(P"F٦&.akO9 )7%"}9E\&$םUbcyXKʚYع[!1~eJ1OXJkubLg8qɴPYDDNP>Q?n=GILO~}9RT`tO֝_QxV%!ĉN*Ky]'֤jcXWJRBJ\8Q{dLʷH(֧93 A8AKFXyz&psJxSᵬ3-;AW"ʑtE<9E0?RG H=)mˎkc[УÝeGvR^R..RB:,Ne#qbLΎkKqRo;yR^))̬<ҤTRpfeNr=Hy}l'`&҅OCMxlvQ!gB?,O66(%Rc'/'H$է'4v:H< N;"'Gړ<&N̜r{l='=ݦI}xϥ1`53urnIqoZ2<稸ic|TL)͝'I@uL/si1a)tĐr)'{RK9SgۓiR K8Z'Q7uҠ=I;֖=S#TpB5YuT)zc\Z;1=ޜdҿr$\SǂԼ:mOIy8RlO*;0!$9٤;T;N3,xRDةJ0R:Yt2bcNKc'b&kNֽ#a\fI<]+.TNf)Gˎ+ )$q!3p{.S Jv2';N'ӀNXGw+ BOx{ןL;dzT'IKdlgľ$'&uߟL' Kʩm,YYtdd%T}Rj81xRN'oBXO@ypr4|9%цqX$%Mwy{"XRŸ˓b=%Rj9R;_@T 'ĤOAdJqy64gH!g;SҰ𛋍δO)Wt5ROk͕ jOr ɱM (&I|664 JlRmlR:Y$9 ()VїxTWP[RoOHGdr?Y(m h(&ouXgkOJQSTv,y謽#E!٤L'IّBODQR"D{e PjNh7#oRD {ɮuG w6)F;6J)F&R.ԞԑmL"j~>,mlH#NBÝ SۓZR *N?O:Z<ćpqB*eRwI}ʝ4"LtT{bNR{RG Z^,&dʎ.t$ u*O@Jc'%%,粡d_vXdN7()eL՞Tr& o@#A܉Q}D'Lr8]Q@R|\=9IJc' l;u'8LN{~֘3%od>NsD0!Oh./W\JE'v6ݕҞ )kOR)c" #2Po[GwB+ŋG}JKQBL(ml\%e-Gɔst>15O^:U>1')ERwo~n wܲJI.IcT' -e*a%a1'mra#hD[&0iԞԐb Q)*IJu mNO3on'vR.X ̠'7.;դTfr66IN<b&*R(5ۀ퉘9XF;r'LYʳ)BkH13I۷x(`=N)<'[>Y'rܽ}zD%M w5<=E(I䨔T'a)i=gKZ'_Q|+I#NCʻU7Cw⣀8 g@ w/: z N<3 čzFiԬ|$Ya&Kn{ϧW|Kȹ9/YdH #d;ԻbJ|;1IB$֠XlXʑ6Vov@5`)_S *?| v1q:IR˞Y}i6Lheu1eL-g;yhړ5YJΉR3 8IRɳ߉*@|#_]6 >G 3ٗrIu'IQ6>ekI>ɿ@(; 6hE)IDAT_p#D'kY,)i)PR#:=]kTJ=ڱ>!s}֯:NR8 Ci3kwYЛw^PrbYZL"Rh'%ę41gOR; JCPJE'!)DN O+'6d,BOd ;K/NRN(M+3J$5널IN\)]9)I&&Nl)͝;9JN914qN(Öd21rXxuBȤc'Z 1d2iDJi$1aUIENDB`acm-6.0_20200416/doc/manual/acmdoc_html-ap-blocks.png0000644000000000000000000000241310644355520020452 0ustar rootrootPNG  IHDRxPLTEٟIDATxkfp;9@^(Iq/Bk_$TL4<;DU <& ]vP"<&Y~c=/~:*ÓG~~^x$\Ձ}KcoLf 8xg78)hSp;D kdm,h350q.lNzf ]inöe'Id\0\vܸ|*lݱS>n])Fy2n9~/vNdpIFy kĤ~uZ3/8lͭVx̌1oSpUMLD7w<~5;MPP氌65ϜhSpl΃bPvza^bž\2_ <־Ys^ 'Sf7n f :hlݼ')b9C,c` nnl"A~ C.i( pT]';9j) bO@3bl8# G1˛بqGC8Acn9ŒK;7]9U9;727r}U^snZk 8H<"s­͎Yl+IDEuQx_x-Q^^pze3Ȭ矅YqUcW) Mc@&dkYdK'S=3N sf?qǚ#.zx{Yq4q& 5537~'ǝ]ܻN~|S3;\1Mt;n) i\fCy?1d4B#bڙF6c0 2cM eH;F1p¸ p&%4[0 ]#Įi]YSIE10a%0`݄`H&7DhoGBl]4vi`*1晩|ZJQYg1vf>-_Gf2sM2s/C}$s0)1*)L6c%lRL6r͕ ~4S7A^-Jff$:l2T c L1]Vl¿|nLA!_w0*CO51LgG]u smOSyno_F5vf>-??}rIENDB`acm-6.0_20200416/doc/manual/acmdoc_html-magnetic_compass.png0000644000000000000000000000160710773306243022120 0ustar rootrootPNG  IHDRd&bNIDATxm0@QHN;t hR\L:hF~\|_}\nBp n[-p : Kn[-p n-[p n[PV^ȹ\>>s$аa !uK"&GWR[II<,QZMK}Շ iby2jTUJ͟VlŤZqSWa6Fz}+3X]ȨN XU_C_s[Yrk6pY&72rͽOꏉ;VS|kmx+V\(g.ޝ0֮Uaȼt.MT^g~ώ},3CˏFߙj :ӗ'u+d`*:/q?f1C+*b}m9V3{L#םoIY'}\~)@uڪ*]5حG]c6rxaON눫@ɫ[}CU׿9Dݎ%VƀJ'K:2o=UJy2ex׵y׉fG~ӗْŸo`gWVѳmmY/tʭ8<R GUŦ#ubmNK^5.upvkum+%qzMv͖gM<1[7*[]Tbdke7 I 63,xY$qw~~kw>>!|~ G[p n[-p n[-p n-[p8-p n- 1E39IENDB`acm-6.0_20200416/doc/ACM-Bibliography0000644000000000000000000000244310370307757015310 0ustar rootrootHere is a list of my references for those looking for more detailed information about modern air combat and the technical basis for this software. Good General References: [Spick87], [Sweet87] Air Combat Tactics: [Shaw85] Aerodynamics: [Huenecke87, [Blake91] Aircraft Performance Data: [Spick87], [AirI Aug92], [Blake91], [Gunston80], [Chant81] Modern Air-to-Air Missiles: [Blake91], [Shaw85] --------- [Spick87] Spick, Mike. An Illustrated Guide to Modern Fighter Combat. New York: Prentice Hall, 1987. [Sweet87] Sweetman, Bill, et al. The Great Book of Modern Warplanes. New York: Portland House, 1987. [Shaw85] Shaw, Robert L. Fighter Combat. Annapolis: Naval Institute Press, 1985. [Huenecke87] Huenecke, Klaus. Modern Combat Aircraft Design. Trans. Airlife Publishing Ltd. Annapolis: Naval Institute Press, 1987. [Blake91] Blakelock, John H. Automatic Control of Aircraft and Missiles. New York: John Wiley and Sons, 1991. [Gunston80] Gunston, Bill. An Illustrated Guide to Modern Fighters and Attack Aircraft. New York: Arco Publishing Inc., 1980. [Chant81] Chant, Chris (editor). Concise Guide to Military Aircraft of the World. Feltham: Temple Press, 1981. [AirI Aug92] Braybrook, Roy. ``Rapidly Going Nowhere?'', Air International, 43, No. 2 (1992), 67-74. acm-6.0_20200416/doc/charts/0000755000000000000000000000000013260345311013622 5ustar rootrootacm-6.0_20200416/doc/charts/europe/0000755000000000000000000000000013260345311015121 5ustar rootrootacm-6.0_20200416/doc/charts/europe/italy/0000755000000000000000000000000013260345311016243 5ustar rootrootacm-6.0_20200416/doc/charts/europe/italy/bologna-borgopanigale.pdf0000644000000000000000000001036213646045017023200 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xXn7}߯[^~1Ї1vn6ڗ(V YM\H.H 3s8!{%$lM>quIq} EVPV\;Q8x\_Lכx7Y\Mxq(O|gf|l6|DOo0Mou&ts>:Nϳ_ f.GBK-=Teoob~;?z+vU no&~1[Mͺ_l'jrYvF֛=s2HE)b3ts=΁Xe@m 8XG0Z>ypy]Wp.7x(x pSNh[_:~3O΀EN .dkJ'[ 玬ʨҖ}op75kc+=-am#ޏXջJoyoַw6BOx?zT+}wޏ;x(OɑW+ $~Rɕ:ܛ^~kT'7֦W-nr?ܟ?ŽpovtZ~㽵:ܛwwچRCo~>y^vFK/LRce#-.۵-LCE8T8&X"?D1eX,Bך5)-L% W}PzaB 4&sQ6!W,PrEHdcg8R;GW舵;Pm,ۚئ6:eX,BߚEwPj,}N_3|@Ó(ԉ0}ЁwAR =bf,3߶EzPuN%s!|adtO)٫;NQu^'sJ qvO%My7$2cO0Y8s|nnv}?la{rz/o[=7/Yxc *5Jendstream endobj 6 0 obj 1740 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:18:38+02:00 2020-04-16T10:18:38+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000002063 00000 n 0000003802 00000 n 0000002004 00000 n 0000001845 00000 n 0000000015 00000 n 0000001825 00000 n 0000002128 00000 n 0000002228 00000 n 0000002169 00000 n 0000002198 00000 n 0000002308 00000 n 0000002381 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<1F8755A74874CF38F37962D9B2248992><1F8755A74874CF38F37962D9B2248992>] >> startxref 3925 %%EOF acm-6.0_20200416/doc/charts/europe/italy/reggiocalabria.pdf0000644000000000000000000001023413646045020021673 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xXRGWθ** (;TJ6ld1$d UN1{O>ӯg!{%$lM΃露>w"_f+PV\;Q8|Yt9YLݻߎš8?}sGDDﺃp7lb9l{?'×0Yl˯Ցv~^NA6\ZJ{<^}\̦xu|&V/V_zq~:Ll}?7~Lgn^RZoO/? EN RAXe m 888! ThpN|Poů-<ӇP{Q>wt3'3 Ap0CN%)uO? {C1px]!ȭ LNx ;z^_ !]'MTZxw;'mGoc}WOԻ*=q.z|ȁb*ST*P?$GCl>aHJhze4kh~̩O?L2 Oe{Mԡ#n勺Op$4nOQp4W{=NMEO:x-XW"D"EbG,БK1Cs~6[s,n$R[*zcpTK.2N=Y^ N GT[2e!%s\J#0m\s:ޱ`m]X^({ޙ}hHgזUFuҺu-I w8aXUJ٘=:f[IӖEYVPgF(We,rU9);;s+%:Eh|eN&|\:5@jKRBam5Ok6HHaDn-K%94Bߖʕ/^Ƃ5$pREgg' i*83 ؛m\EZJt(\0+7ߖʅKܜ4ofi݉c0xԧ <9ے(jZiv%r)*`%U=c/e0` 'e^j&h02hь8iTr%6sQ`h%..D@lKb현ԝ݄7mUgF(`[yvI]0Nʾx}GzYN けjJMt#c7zWA_ 4߶V ggo8҈scv~$\Mψ{|'w5N^ qo#goxDl={{0wc瓓FR|*MnzZ$QO^;5.!endstream endobj 6 0 obj 1654 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:19:14+02:00 2020-04-16T10:19:14+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000001977 00000 n 0000003716 00000 n 0000001918 00000 n 0000001759 00000 n 0000000015 00000 n 0000001739 00000 n 0000002042 00000 n 0000002142 00000 n 0000002083 00000 n 0000002112 00000 n 0000002222 00000 n 0000002295 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<3DE2D63A4B7E0C0A9719E48835FCE5D0><3DE2D63A4B7E0C0A9719E48835FCE5D0>] >> startxref 3839 %%EOF acm-6.0_20200416/doc/charts/europe/italy/verona-villafranca.pdf0000644000000000000000000001044313646045020022514 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xXn7}[l`CxgExdO0G(Wo; D-YӬSjOJFi-nX`بeS]"!) >FW1u]f]^7z͋?Oׯ<~s7QѬZ/GY]os5 zu]Y.ֿ׋q<8*X-oέZk;WV[}ݙ d{vZl7ɿ_~.ÿz>q.qs\,WŻv|7~8zPa=ϘQV>iVpM>}~1x4{hY]i[I;L9WUGsDMzVԷ3|.0z(@Q,1'ia}?o@A_v5bСha8B8~iLxW!q!88y&蚼14ymL!RJx<$}w)*xKi }6Mag!;KpL$O N0MO{V0*C)ޡ !U㛪cDmY&Һ$8Q;;my9 ZN~'عȍcHD\iZ'dKkGTpmbi8n&4AK!.h1 bDm.X}!bNWE0| 5FMTNtVVs*`zSEXg˩.:U-B*.iaiStq TҾAL\5tPO1-fIesªzhZdIri+CϲUӕǔ*U #_bH0\N.iiaNؐzԴpLzTlD7N(8b0)Z"lئeU;a.д0J2T :'l{68MIو7& Z!KsnĠs"7Y#4ŅEJ'bc+qT肷k(-;*@MFwU1Ss豩1^#gܙpJ\,>TEpyɎȓ0F.lLC2Թȍcy\iZ'lKFj*z.Vʍ;u1%vpJyVD wM I.CTfQ+;} R__Bkˇē:.'a/COFjx:YD`ఈse*ϯ_^>$2RT&N"{y^d^pJ]t/ Yv,NzyV@Fw.7O~UMA꿧d <<+|s}478Lendstream endobj 6 0 obj 1789 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:19:28+02:00 2020-04-16T10:19:28+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000002112 00000 n 0000003851 00000 n 0000002053 00000 n 0000001894 00000 n 0000000015 00000 n 0000001874 00000 n 0000002177 00000 n 0000002277 00000 n 0000002218 00000 n 0000002247 00000 n 0000002357 00000 n 0000002430 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<373C8DE636FF9045C8A432EAFC3D4657><373C8DE636FF9045C8A432EAFC3D4657>] >> startxref 3974 %%EOF acm-6.0_20200416/doc/charts/europe/italy/brindisi-casale.pdf0000644000000000000000000001030513646045017021776 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xXn7}߯[^~1Ї8IZFElH 7΅(h<ڙ9<C+!7U7:zIq}En+qzQ(+.(aIUwtY^-Wd9Gߝcqz6|qy3SHx:mb9;}?ϳn;mGlM_;?Չv~^Mv31̠:Zjy,h{yw\L'ۉxꃘ/7;].'gnww2z;]mb7LWr=ov7bz}9 RpQ /̺9&ys`vƃ)%)Vp[D8!| <90ĉx+~¼^?TL ia} g@OE?mg@v1ha9pC{Sx>c'B[X`0vLo+u0zbKDՔ"Fo]O}'<=.JOxKwOC]7.?PeʫQ^?$Gc>aHgu%WVNp02ߵZK  T/{p~^-zR(`^ |@uf~ g[PU/zG3( K1Z z :0օXZw-`-q()Hg5%-Ą8'aeq/<- 6ӱiHX3G]IFj%yM֙ޤbhCbB/ʓkѩp R\77~IRd>z]FFcWG1O/W=Y1N0*,VJ0fmT|16Dg."<|"^I66W9 N!RNԆkX[F bPm\8Xr!r*!r*GTÊd /E@]{qU08LF~=@(0?lMEf]k\j'URuQ]q౵*X)J Va70aUb~ȋ$bRBDcNېXPelmGXV$\f:zNF>:F-goC|B/pK\J'hsHLc8"!1µX Gϋ8XW kq.]E7s NWb1ॹ|A!*s/!:.D;akC\9ÌdDQi<98WfjCT"/ґk KW 1kQ.ĀS7B$yl*69q3 Q+g^'4IW.gkC\̧ɞ19Փy87lmHhNv†k| 1˰W I+g>2ON׀_8{LɀS/pKox6-&}D/p]Hon<+I gmO\@PܻӏB{?UgyfNoHAu*y~iI7f%%o Hgg%ANτ󋗯2~0^nO5=~?4Aݪi3S^Ϧ"_endstream endobj 6 0 obj 1695 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:18:41+02:00 2020-04-16T10:18:41+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000002018 00000 n 0000003757 00000 n 0000001959 00000 n 0000001800 00000 n 0000000015 00000 n 0000001780 00000 n 0000002083 00000 n 0000002183 00000 n 0000002124 00000 n 0000002153 00000 n 0000002263 00000 n 0000002336 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<87BEDFA9485D2D186F97D7B535145906><87BEDFA9485D2D186F97D7B535145906>] >> startxref 3880 %%EOF acm-6.0_20200416/doc/charts/europe/italy/A.pdf0000644000000000000000000004264213646045017017136 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream x}ٲemf)u+AP((+zKuE:xE,[mӉ8>֢ȋV`9)?Ë{`Go8rz@xg8c'|kMo^}Dr 46aP78ȻSqlxw.KSAލ_|/k)u}S~G-[ͧǦ%):mNt-bA7vfl,J0X ëegF5XWEF5ۢǤeWƳZ~Q*4U* )LbzG:h7dLz_R?Z>eE]Ӌ/'ՃR#}NNb)dLO'Vgi2KȰ}i S|T!FGz=k,v *`D\"=Ro/2T6HnL%VP,U;Sof'JI y)9KZӓOnˇq3;C- āTjKr+,8SX"&4bXE40WWvRU6 Z+L'_a#.U/m%2gtzrEb#Ӵ[zu K*h5'UZRSgHUaUL8S9hg@y3E Ӄl$]"8* 'G^|޾VH y 7Hkxb%%`s+>T!S 4c 2!évm;W]&+;&5M^itD(~ԑɗpfߪNyݤ;ۖF*ny8gzw{aV˰Й?-w\: e!UZRWđ*qr`Ξ;A'@A;з9gr))_Jd{d}q2W̎H iTB&*zLw e 3ydi͞m_3hBĩQcMđ*) w"ѽJX"ԖtڙUƁE;k85iqcq[Pd,B҃l$=Byn8gzu5xrjĔf/B$JQWSNE Ta`Y&d8îmg.auem%zi*QV&=@#=aڇX($5 KY: ra_U)Љ kgBW픸߶p"~,A\!a:*OZmpqɗI Ώtl}ruU[I`D7@#5fXM42T,a꿠FOw]LN>4-/-Z؉C|7'߆/K| HWGBd7p&>OGSчD)eZUa `Y&Uk)K3F$!#8kVVųcfJcwpF0?%&cuYjW:kF$ )| F*ec^]k L*zvu{$C+1=^!OZmzLDlT~3)R|'_oYX~vtw!rmZQWqPmU%VP,UƁŹN҈ؠv&n+ች$39A#bcpbӇ۷Fhw8E^r?q>2nةVW K@sh*43#zx`Nj'eD˄d:_yC@OHƗtKygV}.kkl#ڗ髧Yyl1|PI >LB8Mq3yáy: ̏eiCOƁL/*7J$ ڼtδ!!z!=+.\GL_^&x ?^a,'hq˗8 q8qy],y$bNLǭ//Ռ {[HǑ (:!?7Х 6tE_}TaLq]g*Kt ѼJ;88INY`ߖ i%(k`-"=;p˖V-!>Ӈۗj00+:WNE5H$ЄQJXKJ5 J `1eXSm'9:*!Z1,'(t`6 +-W'_Vd gc:ț!P2M;*WxD tJ0P02J=hD+Bǀ:X~2 xtYAo.P6C8B>!oʚm=Wre~}JISQmU)Сp*JUabL^%X} Tgw]kgPFzu630pq_ҙ/K|{%Kdz>Px 6HQgR kgF*a &Lc2l+[A 뗘^|MSŴGÉQ|Ig7{ ]1%Pu`,aԐ1N)fTajw&d8îmg{ %2c!rɇqfuav#:}Q-WH.Kepmy(CX֑!Sғ.EDlX5X&`d +ON̯&^>ʽ[}(c3W)n\DPɆ)3yfXO،j_JoI {^ Fc8t%իTBdREP (3cziXOYMA#phr=$:f[t+(^(Hp 3 ͫ4zz_F_M/1=׋'ZI |9#-q ƥZ_lJV,ݣ+VlL^yM3ϧP%37QJQ,żT<F*Ͱ + JFլ\_tACO*5dm5g2NF*E  n4hXR;0Wϣyzh'gɸXm˼0W)σyU)3yfXe̕N3ʆ7&W.nlJyteVYh$dVk<J2W%R+x*]Ua=Ʉ+~V(ΐc֕٫c[%w&dTR kY_F_Mъlih|E 8I^ ܘPKʅK@a 9TUJ UK#9˄T.O[Y=l Zz>*YyЉnTufBF*հRhYUlV1!-_ihggPNQi+#{X" QU5X+v&dt K<ߎˤ|S7VB7QJq{IoϫJ7Lh^x:_cCg59m]&~Ǡ3n"wX HF*Y4e9bӥJ0,v&`t k&l;K5c?itVPSRnTF*E %4{J1B ͫ4/snZSβ𲕜5bNReS'(G}ʈ^%*HUbXe~gBF*հҚZ@O|Tkk>U #{X1"tyU)U(3zjXO˶Re._v)feߦ62M!Ym6~NR(UXQ˄T.S$*h*━沓lhʈ^%])]QjXR;0WɆ%#8_WJ+tՈt$%쨤mR56I ;>4JfGP)Ѷe" f*fƱcn'0(٦%huѽJW,HAVJ42W1&5"G[]}Y,k'7=z,^{ )2SCR ݑ0]|'ɐf8@XR`Mjι2W)%R +PjgF*Ͱ|禣8Qdxѕpҵ2d'f]ѝ tξ7ـX2OW oV6) Jo8'eEprN%J ^%*.n*Ű v&`d KFeߴ<(ń4,ҜX0"+S0AJKG: 2wȡ +kgF*ٰdraxy @p{um5(fLUbAp׶kLVUa-+ԗnfqQ1+GR+bQJȸș=Zvn.mQJU,b@v0UaJL^e֓҇9~~je"wPPz26#yX"8 7J1B ū+eO g2LLcհdp~G2ݬ pB[#)ޜBS%#dl՛&N^L×Gd fB"Qt?Hf)Uvg҂8O""8r[>s!I\_{鈒 )TY2 KgUCY浺IeX{8KiN0x9uɐR 4lXmم(̵t ,2)Y7>2W)cw*ڙeveГŰb71,)!, Zk0wkw~-k R,S)}c1eEԪcIyU;.z ddJP,HNFUU)3B>Ta|.2wjڹ1T+ΣY'3l1Ia9-d4‡N)\'vTo:2WKQ]G/j@"b>f}9@p`TUJ覵ViŚ2#:VM֨㈡ٵ"bb A 6-1"0ڌA UY89ΎXi.Nl^kNRC%,a0{U1X.. ŝEb"R2Wiк%Taqe*ðeetZ֠*oݤak؄UҬڭnt2fUbhVڇJ0,zL^e\#ڏ[HsDM\d7#4MТGF*ݲ@J1B ݫtwˎ'^(P̪EL64#.:rLb,[\á&ū)äV*xeB*ðd>j2Tfw3J>eP[L%]L^D!˼"zS#6n8;7[VxLJj6ūBqG*ڙ10,2橫8鬌Uqǭ",'aRJ3!#{lX2nΗhz58nkcdc\H4w Z\@URbTZ\`cHNB!w?;98Xk 9:h76:yq` %l( }pĊʭcKK=F"7MHEW ʛ%S0SCVȨUaaʑ0]IE$#a}H0ޱ,2W)o0fݙѼJ3,q<| Z$=aNq}5"嶅]ʣc.ĸK]fb[&dTRQSg@W;!xrBͫ4w>9*ݰ:v&` 2 KdKxl"ڈÞ{5V ] ]E)]U`$ t0z[%V5{A0Wi.j][$SIǍuQ:Uaa˱q ;&֤pf(gMcԪUb5MdXL^eZ4|$ װ\!U;頱UI(3I,^%Z͗ q[ؘYf<ΪTӞ_Jr_J=:c~Iݩg/oc u/U6BimUڭ\F+\#F*zZWJ6,]3{nX:} zDٸ'#&\B&)9FX72s$/be~Q.J*ɰv&`tQ,Y'@ѡAC%24HF*ݓASM%OL^e~R/yNf opPL QnO86qMY 4x$JGm٫.;nP^י=Y;^F*ݬ=C%{Ζ ͫ4zz_VtϞ6)0&6fb!MBŮpFO1t33J/Ow],0Yq*!no)M78XeBF*%}Wi%s&ʉczIEPF*] B:1UauJL^ejԗWbT+ic' sOuq=;y\i=d⡒t ,z2!y6#NҒ3`.a8D.##zx\"4m7?ޙJ6, cKx'yw܍1nJV7x8z~GЕQJ[JӍ"&=o1傀]A;tƴe^:$[e? C%X&`D KKx mrSNŠth:E&Y%J յe;>TJJ6,oDT.(.*]9S.*\$j{ F*DiN0J6L ٫dZVїS*.hm#}wVnLvpp*mϯ 瓜v4xdb2xW9Ȯ IǞr^x!$^%W(Viî6D΄Uab|z^j" gs6ƂJӍ{NK٫䲽4xdⴥeF*2/K9j9GS)5ë w ib7hX W[&8V1*]$|Y =/sb&h MƗQur$Ǟp(\8#yX&]K16^ ͫ4myv- x-o=)oSF*ѮD󼜏Tj"n4q0 1̇磬LL@ tp W􂴪m*]BZwndX\aѼJ3,Ypҝ/ U74OJ*aڽ1R ͫ4X4Uw\5-zH-MZݨA:׉5G2n Iug-0Wp{)Kt̺x`f&r΋*#yt\3tB9zˤT٦J1,D#fy^8. z|r Ⳓ#2d` DXy>p Mnt ^֑ʛ=,GC>6&йJUq in*eC ɫ$ÒyP"᠉DuIROϛN;[eDQ_"2rrN$)ɕ⑖ ɩ]Fܺ-~Wжܺ-n~W̗BK쓄˭e9J+M7,p0}eDiuP`a;2W<dHkd%^d4܅7y঩$Jڙ10,]&c:|lHbyy@I]'@N;qϷrP6HNN~ۣ89c.v '9BU`D6uTaq2^%EbѮQ8z&cG\; vˇ&y|Ë׫Cuzɓ~#.y7?{~?y=l #rVGBm|W9'矜΋4ĀqzgꈟޟN78-26N?|ů>NF?7w8"3L˨TP^}kBާ,y;wn0.|uk(+V >O,]ȡK◳f}FaZӻ~x׳'xn%gIy^ߟNHUnKpJӸէo0wěoN.xq|I?:Ǵ o {} /f]Ɋz%~?qEK\ gܕmr\5m|mRgbۗ|ym͇WoUk]&d]BrXs؈KNt#\w+>J ۴W˴EnFG :Yyt)ž2.kup>l߾f}=.~[i^;cƉ9V}qPrNeiu4aWz#e|$7}nxANq/LiN$N[﴾ix{8O}+^_nez+.K&/s>>]j/r9L?:+If%lvޱ|gZr6zEr-g-(SjˮFº[Y׊eWf58G/^: sf٭Ի zqBZjUik6}\Q8g0y^_J϶5ΐ [?̏][^ovpu2:h3ZЮwd%EI}ޥ|y>Nk=Uuwhj7zؗÖhЛ{cE!=[}CH#h#ɫno۔k.?4_-vQO 6Lke'{`F1Qq GJQU, 9hf7o $l)qރ|g//_TQ;οwF#V9DOd(V}~<ƏoMʍ7)ӻ|_ZoS G?7?<:(Q'fc/>iTxD΍|Qr 0h}{G_Psn Ƚ2o?G^^".Lʵĺ L;&+k"/|g\rM7ʚa7kڒL/zOʖڍ|3>[r|l֬o.?nxf*l|2#^lšw{ڹgWvߨ/?JNhO^_U4W=3aH/pӗ* zML ޚO.*7"Sɜw@i%ˏ[6 \"\V],%Ƽ?\z_f|kHi 10+$ٲtm;C2yXEMSWL6Sgo|Si^}Mʘ[wiS0!|Qhu&f_67 eTʖ[Pa˯^Ҹ ׶LUW\57+7s /u[ўw6,O/WͶD.z<0a SX(]GR.? Sڃq\W Q> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:18:17+02:00 2020-04-16T10:18:17+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000015550 00000 n 0000017289 00000 n 0000015491 00000 n 0000015332 00000 n 0000000015 00000 n 0000015311 00000 n 0000015615 00000 n 0000015715 00000 n 0000015656 00000 n 0000015685 00000 n 0000015795 00000 n 0000015868 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<771F5CCB9BE958151EC00EC2E369592C><771F5CCB9BE958151EC00EC2E369592C>] >> startxref 17412 %%EOF acm-6.0_20200416/doc/charts/europe/italy/cagliari-elmas.pdf0000644000000000000000000001040113646045017021614 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xXn7}W PH}H&-ZK^EUHV"pӯw:.EZ=3sx8;gcg,|3Ě<"l\0Wˉ8hRqj3ybv^vfvg?yŅ93/zӫ? Z_ͳrٛl}o s:N|{7[|m~:op߬r3n1Jm&5Z[L{J$3B$S)l*N&^g\Z0>pJR#9cfFlx)A3$hJ.dvӐ{z=:_LCH_ԁx2==$}pP*sCݑPpL&# j D<%. @(4WF#a\Ľ;D!3no(J9ɋ 'u_R7f:stet@2Hf%Bzt3P'4'W5\%88u!иrAĀ}nX'Sqp (ad&R:t#OP/ss{X)ԼωH7NU4xgZ G!#{ v][k\rA}D8T-M{3KJB"M^Q0bjxr=w{}g`y>AT4C\Ϯ-摋{AԐԸd6$9f*"f qUCrcŵƥ3nl\KyUi@΅JwύtDTYrL)q͊dGɏdQ!z%8h\ ^m1. @q@єq"fȚ5>$W.fĵ@a_C.Q3\vS-Abisܿsj2d-DOЪZƐ5c4.Pq1@Kꞷ뵚Z%*Zb>*xTb{ wH^Q!ظ>!0bZD7e>Flɿ#$"hxܨ\%}и/APҸxNO+B0BNmoMa-d1`>!ظPAĐԸHLs#K5]9ś"> /NJJo E8M5>W.[/QCCbZu Bޤ!JW!Bqz!!qJF쁺 B#x_W ß$jendstream endobj 6 0 obj 1755 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:18:43+02:00 2020-04-16T10:18:43+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000002078 00000 n 0000003817 00000 n 0000002019 00000 n 0000001860 00000 n 0000000015 00000 n 0000001840 00000 n 0000002143 00000 n 0000002243 00000 n 0000002184 00000 n 0000002213 00000 n 0000002323 00000 n 0000002396 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<5B3F6D0E9A54C78DF2CEB4EF194099DD><5B3F6D0E9A54C78DF2CEB4EF194099DD>] >> startxref 3940 %%EOF acm-6.0_20200416/doc/charts/europe/italy/roma-ciampino.pdf0000644000000000000000000002027613646045020021502 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream x\r]}WUC/ǑW8#)WM4i+Eē|ƿ3V7q3qqm{woѸus9k.._n~ZBuV^]|'}sw}/?>>?ǯBWWcy{{v8\Ç޿py?\_}xs>lOCvǿ7oOĥO|Ag?p7oo>_l7oaoozO//۫o}xp޿vs~}g/Km|xH?ȧx#=r_Q9Gy{wQ)F khĥġw7'孴C$Ӗܯ?Uh2}f*cPˤ'>>Զ't)yCXZ)<ڡ(}isOOzs+K/u3;No:%g@m%9?A nOyr$)Vc'<'//!fg~cߏ0f)KQ~³SNqtdi³s ǽ'!'(K#}@XNX]0 's.$bV(#2Ic۔O'g/ }^̋{!! #$!0'O!RsP(n4Z^^NlV#O>9)9Ʋ@BP,ʹmd^lNIω}'|,i=Y.| Js a~ǍK-m1HOn/<7=e(!e|ymhyK*Je#1"4" j/2*#M(IŃK.[oi#< ׸;S]ӱSTAL0Q2xDz )O c]h82ˢ[ܺf=Ul+qML(ܞ;DLL,!j: _BY zd(+@/2Dg*j;|ѕ!Jz pU .HLѡ'7.keU);SLx%km0 s|hiOy8u8y?"jɗf1\8wo2uuJzvZ)bck4ŠK@9$]VM(JAh$y]+ϋ|ġ+\Ui']$'Å]D\NjG ǜ$̹hE^Ug?*erhŪRv.S:$(xt3FzRo6Z.l$SOOO{ԾQUcJ0JD`Sb .RǴ(#2uʗS3Y(䝇2#A*ZװTH%|rY yjaȁ,,;;㔟iƀia]ᙐ!X %Rc;J\͸8RٹNNbp"hĉg~eڨ85eY^RȌ?1a(ږ㝪|>iqˢƦ=p3Y(䝇I7# ɱHɬ;Ч. R٣tl "ya5-`Gܿ3W<ªQ$1d*SGY\V2yhLk|䪕a#i*҈2߅5>&& b4qUK-NC as: 5wu8G$ i("" )^ f'9"^&>?pc׺U]Txk-9m):c1Q@HAF*ª RND\AF*erazAbs:7Ё wwS0"K)&nsO~V]c7ԍe`#,n'!ǬlOѿD'VzҼI+GR&WPшf)J\j))d͆8$5k⺈Te*8"m*9"'ͅ/,= uMkƭU^!lqUV* RPF"vʦBg 4uf35(@EGԍZڢpQ i7T\\=s6aQvqC4VBip9,⡍0 q 惃iO)[G' ֜ҍ"qzu+n.c},c)u.|E%UlީrRy6}U}_*G7>k{u&z0f .vv@ х,1wId m1j$]w'؁­*θt!8:Uw"*irüB,[d/q]&Y?;E[.5a !x,X>`  llQq0wRq3NUC@{UU%kW˫hmUi UgE I"øqRVJ(E]8T*5aE^U亹73_Nr-9}vDQ9ۦ[%nu޼}Kh}QчlV7ݦJ\FXW}9zF5ى^yJ֜N"=#һ@HWX#}u_X֞}F~pJ'4WuC+b'E ׍-cuQR.F>pa6o*.\¨I\.Q77`r-yE<7x5C~x1rE B2p(1Ga\[≸wj<.aY"*ɸ. bΚhJ\J/~S} 4[bz6T)(h~U 2}3]Q?8)?;1؎=?rⳌ-xn?Kؗ_mQa)xOL^Ĵſ3b\ eNڟ ~ci/bS0(b///cz'1{^I;U|y- ?2﹘7!<'3@՟yOvTaImm/Lj(2mچS4I@#Ng6Voxl[DŽ6ZSصpr=*=.yoϧ۞?q?MOz<۪!`ի^>n'YFѴyLˆf5\y?^?Y|WSS;ؔ"nj˧K+Vg?%퟾|UU?cǜ*>1q 8yKqxǗGe"vƷD7m_?ikRWendstream endobj 6 0 obj 5784 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:19:17+02:00 2020-04-16T10:19:17+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000006107 00000 n 0000007846 00000 n 0000006048 00000 n 0000005889 00000 n 0000000015 00000 n 0000005869 00000 n 0000006172 00000 n 0000006272 00000 n 0000006213 00000 n 0000006242 00000 n 0000006352 00000 n 0000006425 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<69130FBB09EBF1D0CF1A4FA88B19C4C4><69130FBB09EBF1D0CF1A4FA88B19C4C4>] >> startxref 7969 %%EOF acm-6.0_20200416/doc/charts/europe/italy/bari-palese.pdf0000644000000000000000000001003213646045017021126 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xWn7SW$z ꤩe_ye+,GR$OtfRt-g\~UBO~‹]#MQl1_KtBqhR`J\vyqv:;wz&ŻWw//?pHrM].Uw"v7>wncs&澛,vm/t>#u/_4Gg}''BK-9VlWr?~{/^믫~EN'Covzil\oVu{_bͶke'㦱Kፕ)b5 Jicl)F){t[!Cd kjd|=G9i.ߊ_8/U4)4!83LAxX_@k$Z-@ٽE W z!LdL#2V(P!(}!>hX5k08z WBD[Mx=ځzcLg<Wѫ'ꭉg4::& r5}@\ !BB΂YMLYQSguFGS C{0Hnf )#+"K)c[4'219ziB~ŪBdυ^ KO%.r'p2pݲN^'cڀ~w Wqru߮+mƄQ_x2?ߛZh@=aڟN-hK'oxAJ±,bWMN^mL~< }DM!z֕״gewՅq19{zХ<֡gǥ f,_8YNA }PC?lendstream endobj 6 0 obj 1524 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:18:33+02:00 2020-04-16T10:18:33+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000001847 00000 n 0000003586 00000 n 0000001788 00000 n 0000001629 00000 n 0000000015 00000 n 0000001609 00000 n 0000001912 00000 n 0000002012 00000 n 0000001953 00000 n 0000001982 00000 n 0000002092 00000 n 0000002165 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<78B4E504ED04614E5F52E94A50E15039><78B4E504ED04614E5F52E94A50E15039>] >> startxref 3709 %%EOF acm-6.0_20200416/doc/charts/europe/italy/catania-fontanarossa.pdf0000644000000000000000000001164713646045020023045 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xYn[Sn9"zuI$EF*Rm%Sm:?PO!93Gb䌥\_/?gnaŗcx Ÿ`. qG3׋Ggr ne?zٙyb.ůc,77of{yyjivYn6woϛ~um7|"}?XVkgTB!>fEgݺxej޾}SNB[e='Ϳ£MN'W3'jhiUB4λ)|n\հD>tzƧуO=6-i>)!tzƧчzjjOMi}3>>4ЇC-zSr"~B3<]@rE'wރ3<%юRR~' >2<щߍ=;}+;xR{KMa:mdʰQ}x^%ub)qz1Ya(nfzKmu0y@L9N@֌+0f* q;~r:bx2δ2,D%` ,1ㄻ~T&l3[YcSrR x~YКMp`ҸHpɁTI\Et$\8V]ģ)[|KDmf BGxx 4xvdi)zz4A V*8EZOM|m\PK'Qhf.{3_|C3;)vз(8sEzu<э]&/ g^" YACn4qG_7q WD \'Oƕ 5/5ryܕY_8SKy(2g}G9,ЕsQ,A!AMR"-VﵚeM"$\gS,Nex`{m£<`G`r>J!ż1u3`b “SAMrcLTM\r&aAMjRƉR0E^"b> 6&IT.bHu6qˉVy4ɝkoa:gj0/[`<ڂ!@ &AHPv۹hIXPFҹ0PiYYb{AR &IX9G}6I+Ve4) i, ;e9*A%RR{)O(5r8fr(Eިb#4$"-ޒl DMB^M_&AU^牛 ̮Q+vfZ|sYPF\җPOMJi\E3N^M_쥬LbL38Y|]%1N|x8ZK$O@ h╋㑦 bDZ2 h;eOJԀZMP$XQ $)k15Qq@X$\襬LbPEpV6P,tp6L U=("㥤06WJ &smb=IY]؝(AMб.UϼЩ~XoN"4E91̱ cm) Q,9zNw6&3bI t.8g!5D\O3X< h_f;W6 h;z)+X}2[\hE<_$m$D:'AxxplDF\$iw׹dIXGعo+[(eNJ'&@o9I\Y$,:z)+Xn u2.8YUX8{*,5}R;Ri4I*,Pa!7.q,WԤ%:2h{Tl`M!ZT\IX tVa5a/eqz6C mCQI?xz_"i-KH]V8\˖~rwG<<:|sC;c^9_>\+A*,Aּ}ǡoc:з#''N*=0=s&))%CNQBQ=>p`SdžOsP19R8;o`ߎzoov}xst$o?x9̑3}o9;~l endstream endobj 6 0 obj 2433 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:18:46+02:00 2020-04-16T10:18:46+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000002756 00000 n 0000004495 00000 n 0000002697 00000 n 0000002538 00000 n 0000000015 00000 n 0000002518 00000 n 0000002821 00000 n 0000002921 00000 n 0000002862 00000 n 0000002891 00000 n 0000003001 00000 n 0000003074 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<7755A734ECD0B33483A28FCA64B9069D><7755A734ECD0B33483A28FCA64B9069D>] >> startxref 4618 %%EOF acm-6.0_20200416/doc/charts/europe/italy/torino-caselle.pdf0000644000000000000000000001070513646045020021663 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xXr7}W-vjK㦪}ploZX_"EbJ|fg`02eif(=\}TgZ}}Tܩo )f=W1u=6wvR}{?ԅywo~ vz[fT0_[-?wj9._]/do.wgǕZVxxBÅ fu^/zt{Tq_r>xx6b6b?mqUAՀof?$f^G"x|*hٚ|@Y8=]l8i'bk_:~s% Sr"GA!m2Z =óuCa=>Agx>}Obwl%'x6v\gx6=@bOwϦVy?̬PٴY 2Ta $`v c`;8n.=tg@/[V 8zڭƜF8جq POw9]O3g'OXlRlvGan1U X  Z%_4阸T."l|is2wŌ\,/Ω)>(8PDD1v12 ͕>>>`<5m4]M d-qAΥ"S$Wd6eƩ'cp,a;L%"?dniOcAjs!D6Owe\)lU>hϵ ,ɸ,+F+W=߻EVi;.>U.BdUܻƵ5&~g3x9_n<2:j]tb+ƚLGظXA.q(]=M`{>o}fG-RؘI uR:wEV!5.'VuHKj\U}𩩏ut>TfFS_:t WUи CƵbT-4yٺ>!;+h{_JCֺ{Hrt%7.R^cգepb\!aFB\?#iS:R [S"Ļ 2|qiqqT/'[cE!*@6f#s]tb+X-Ib:w@kM6y+,LWЗcs\qRHK*\lEذi\F x[1.Rf&Z&*֍<,|8TFc)л@*.иR`FԸ0tOHI%O\߻xb:w%6Rmb1tW9skڋ]pҞŰ7./,4s%?<w%7.yhi* $βp5=2';w-@x.{T[F'kp5}D̸lcNv/|Vdᙁ0d[~.>WZ `8Ob-Xwr>>{TS d|Cd>͙endstream endobj 6 0 obj 1951 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:19:23+02:00 2020-04-16T10:19:23+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000002274 00000 n 0000004013 00000 n 0000002215 00000 n 0000002056 00000 n 0000000015 00000 n 0000002036 00000 n 0000002339 00000 n 0000002439 00000 n 0000002380 00000 n 0000002409 00000 n 0000002519 00000 n 0000002592 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [] >> startxref 4136 %%EOF acm-6.0_20200416/doc/charts/europe/italy/milano-linate.pdf0000644000000000000000000001243213646045020021473 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xYݎT7]@Z."EP2Zf+40Q T;֟}|fzm |Ǯ\.>Wl}ZYnqc}m~@b\0ە8~cZգg4nO>KWvw|}w٘''?ַ.7onzgwn3!?#VfkrbMmV[rgOW#$՚kvv{/);#'- wsO+- -.%v6/ڛ*_fhvD aXBx"c97R_ߙ4=N8zi>=@}ڄ8?>GB1GLCg|}i sq49M X~޹]IE8{@M}`w qxZF!7rGCvSrPzG:/޹M]@> & |~ ~\\֫cEڈP!b㙧ӫZ!IDn70f@KSϙFSg1,I,^`IΕE yTɝkҙ/Cø:UNPpγS6+4J|#*Q1fOU|UsltfgqeEкOZ8$ EiH`a_7q_IMG6N&$. Sbzx;$P*rF9FJֈ.r֎0")ƉöύEt(J\xjBפʗ/ |T#:?ӎ4$z"*4.B$HGUJB+efKtF︠JK ֳ E8;o3@cR REHH'?rcWqy !ëJK E.ҋ :$5hJPBҮED_ ^ 6x=nW<ԅOK+cDc3p>etPUŕV, ڸevkKW*XjXf p(j*0_]gIJ\Y Gعiș]S|-"it.szyQ3w2"Ÿ$ϪBpB6tA5S:XLk"'IMW]vMEJO=1'1N&$.t c^ Ӑҭ=[EJk&4tJPҭnm~LQFҹt.ǂZ$~r,Y3wQ cR*sejP *ݮ97_ƨ*{qżB}V~2wk2]e{4@zMVl&i?-$!UM<|u% /{SV^WO=βH=aq1Og˼K3Ŕj/byX̃GYGĵ~;}x1a\GJha棌 CC:hap&o<gƼ|l_;WC7o؄t_.&\xܳFWYs(ºohi _U(Zo Zq- Nendstream endobj 6 0 obj 2804 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:18:55+02:00 2020-04-16T10:18:55+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000003127 00000 n 0000004866 00000 n 0000003068 00000 n 0000002909 00000 n 0000000015 00000 n 0000002889 00000 n 0000003192 00000 n 0000003292 00000 n 0000003233 00000 n 0000003262 00000 n 0000003372 00000 n 0000003445 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<7F6FF31C71C81CC4DBDBBD9DBD566145><7F6FF31C71C81CC4DBDBBD9DBD566145>] >> startxref 4989 %%EOF acm-6.0_20200416/doc/charts/europe/italy/D.pdf0000644000000000000000000002467613646045017017150 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream x\˒\qWr5S#IYMR2#  H$U3[ӒܙܪSyVepOA=o opyߟ>}%u)SϾݟ>WN9g<ݛtzz'ÿǏ?<߽7o|(+ϵ^Կp8G2nl_.sOfa/%Up_]VE7ז/?bbızl46O1J/j̜Zk9\,kc_9Yd0gc;gM]0T4bD2K~`S,#o/BPR F禥0U$u@{ t;[<0@>Hׇ?ghC, Skk AL ϙDqRrT_|x Mez`z[z8u9tntlMگEC^2a&8O k:˥cJsiJ%64Rnme55"e4Rd],.ntdZ0cWSq I۩ᙕ9&mL|n#T8i&Q2gzkKRe$:1)%qakצp}uTDNx:Ƕ)#2SHtavm\=ZDVħ6 <4t^,gw[,T]lZqJtMbEJB/kg*KjTe *WP2T׎SLhɧzܵF-"!?&n,Y':9}AzӘuр-X<"XIq~}9ONn^ع<9-d,2#3Ʈ2HJth\V3T.)ͦmk\3YYzSr+&zK8O!#o=U2#2QE6ݺ4ta)VmR}Ǧ‡J)UPΕ+W[dMz{ҭ]]Mۼ^w5K- s.㾌Qvb\*ؑQC%:W*mWi i3`H_mo Vkj1,lP+9߱H$Δ0?v`\R*ɹV!(Jq'];AC ]uAuQ}'I]ֲvŇJ7.H=Ts%[B1w\b%ߌ gbiqBۋKX'I*J~I?VbdA < *BU3򮒝i19w6 Uǎ@>˨J5.(NĮ AFUsi댇/µhTrqfyl]m_G=̗mGqTВG"N(Ex!H۵y<+|3Qwj\y$gΕw\Oa/iT2AZsQLt^&# f$WчбTN$RVeMn/OnZ7QF=b![)̈J4.*"FScqA)+yWtgofT#B iMir~7JCEν7#6T2RK 7JKJY!̘t']˺m{!SZ TdlC&j je]=fRf]e:XI/їq~j i]~uY&b کq^J\q>I8/J+6fv bBQw8-s9h-zڥ2 Rn4>WgX L+feYX.P焴xv w 7Dq7<"a"2®K 4JqBU2ʮRIMx CRΝHg1iWIƥR?Tsb6+fe]ߠ8!-^Y;  v: H4PfQwj\*\e\Rd]e:ד.| S):Ek-pnX ȌmaAUA)+mWi%V˱pғ?Ҩ| 2ؗ FiG9ae yʬȈJ4.R\'*u,:(e0*չBc2~$v!X Hx7G;Ti,N%M|:5lOG?VnnMtz>"L$=1yJ0.Z@K%;W*eW)c~NױG f irě‚Ałkć2t_XX]Ma)oȳnA'c.->`@,~31Bw\O^\o"VujZ*e/Ƣ-|bYy-]xsuu<yp +#_@_x`Q]QtDY0&زȑ3®K+F)JuJU2ʮRIO5O#$-8:mOh8TF ^>ZT9삕|32,✌'%iằa 4G8%"p#2h*|aR\\d]%;<0߉y>&AD1@)`v tn8Bъaїq;8,]OWplccqb顭qbi8Q C8ƉG!H5EJ s-xԉǚ-'"*͸}5r$JZ c*ù|3r,\QV3:?[ KB/5@̬[zhW3T:ƴG6iBw\Oz  aE]<)̽.XFUqa=I̘2AkmC42o#* 󦐍GdB!_&9M;]8₣{:=fNfw=$N<ĉVlx],6trMxt6TZ_g'dqƆf&ŖTtI HGu\볌15Ju.FC/D3X]6BĪ!79ܛF4uQ3Ʈ2 RKEEA)+D)FΥ#y2.\JQiqNZ\)j*]਺F9?cFUqᬁb*ѹ"V!(Jq.] ʉJSU!FNvs6*ٹ2V!aPie\Et@BG_FkUfr*6ސW\RxW΅G!Hۅ09n`0f`5"=AXFUq,b.*͹V!ȨJu.of}}8{VZ }7vS*M.I6Mf _M!T%Oc/PG)!~zX> ~`x],XNsrMxtwyMaY41rి;2XX:^Gr,s~+Ǵ]y,W cqŒq¼D_tyyB,8QFn<0DQʒQьP ?Tsq/ o*nBH8gC[c]4:75yl㸝&M-,J93jmk?0(q$)/r0o6/R\P=. lB~) L_/ƙ}גo{uGקӫ0NFW$\-@g.|I wXWRC*bp|.e]K6ŭ勫݅S3%f.롮嬯9k)pn[%9dظZ?_~K|ދWo2*YaFYl<76ϭ|u LNYn֥tW3΍|q ׫|ó#I/kɷ0Nگ5^j}H־yLJz S{|qkka\}y̿`\ƈy59}鋗W? r}L܅EWRoiHa=f;8vE^Kv۝3%a\zUqJ`}w גo 23ŗ=wv宥dnԲw+y]‘ץkɷ%cl/?{qKJMU@גoA*թl__2,{f*._O?>ɬʺW)^Uy(L @mH%O|nY!>L +68ܚRY烞k7Bx<$RB4C|RI͹cҸUVo__?&sϔ}bw5>M_.KxӸz]"Eq"fݵۍ9fv-΍D<_MqmӅsn_|%V}Ѣ݊p%n5-+a2'a)◗/g`7(|-֭? ѕ[ڳZЍ:5גoiwã }wg]rendstream endobj 6 0 obj 8087 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:18:25+02:00 2020-04-16T10:18:25+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000008410 00000 n 0000010149 00000 n 0000008351 00000 n 0000008192 00000 n 0000000015 00000 n 0000008172 00000 n 0000008475 00000 n 0000008575 00000 n 0000008516 00000 n 0000008545 00000 n 0000008655 00000 n 0000008728 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<2DB960BA13125E0EAF4D2FE402086FB9><2DB960BA13125E0EAF4D2FE402086FB9>] >> startxref 10272 %%EOF acm-6.0_20200416/doc/charts/europe/italy/palermo-puntaraisi.pdf0000644000000000000000000001146113646045020022557 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xXr7}W-vz4'v޵b} CShKt)Wo;/5Lg(=o.weTgZ}}6rYԏ萔qz=W1u=XlWw\l7óB]߄F3 =ZnWwz]a|ny5o?W3)Р_hyY.~l7ogOj|9vqMݯVp|6?<< ~x6b?naUV򿾞 u4:j'n5[W3forjWpD->LA|hIuF]uNB K@i',A|CYL1PV`DN8084s>Ϋ MS&nqrƧh'1=F1O&)moI.PFRH${Mg|϶'هb7O89 qdnFT_ h"7sȍu3cyU,8Z6@#6Ԃa>0lF0 z4X pT Ɠ%I+>[D/\1>$U.lݸt*a2rp-O:,3@;[hjx@x ?}d-q!3ϴ&!kD!qUaCyB2-OƑ.HL!,5G-mo͘#a"Ru.b,!qE񪃰!!qa2%p]8 [I<-&,P;>:cq Z9X 1G5ąE b}o\;jfWK"'N斞 ;k#Cpaێ ˚Z_y6>5̌x‚qIq]^J/$Q2:b}.\Eh\ ^u6>5.V{+ptQ>[BQ>څVP.ʗ۸l9 lp}k\LE3%*MjI50)R wIjI'!Pȋ*SCR\ȫ "ЇEu>`3=BNX|$dC\AX㲆#䄭!!qQ:-yV:k]5r҇g"WcQIV>W}<}H <ҵ2.I8< & }zn~1,[HiP3-)SՏc:+W|nQ۱ۧ[Cm>_dendstream endobj 6 0 obj 2315 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:19:11+02:00 2020-04-16T10:19:11+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000002638 00000 n 0000004377 00000 n 0000002579 00000 n 0000002420 00000 n 0000000015 00000 n 0000002400 00000 n 0000002703 00000 n 0000002803 00000 n 0000002744 00000 n 0000002773 00000 n 0000002883 00000 n 0000002956 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<7BA30051D76C1C1C0F043FE4549E0696><7BA30051D76C1C1C0F043FE4549E0696>] >> startxref 4500 %%EOF acm-6.0_20200416/doc/charts/europe/italy/bergamo-orio-al-serio.pdf0000644000000000000000000001121413646045017023040 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xYn[7S >"95&Hld좋ܨdDVOۇVBU.AS7^lvjow띚olIóo\TՏ~i&Bg~VR ~y8^*}fެ_.V_6n7\t8~7b;{vV_LxkVAk_NVGģC@QZm AA gij?ٮGqDNڮ5 +m mnC{6^  iu?t PF`0CQcT;s=Ϋ8UY.`y&=om y6o!%|=$|wOw)J[>3qrH׮f3JN4]u,Yq 3=NWPB "-,s 5)ީC77ݼq7t"Df:YƵx] &yl!eb0YtY0x0 Qj YBwG9)"ZFOW貳. Z"0\aCf+\e\wgOƐ @u ]0KD nuvSuSyOHUD'!aM|b-ֱj3ˊV7kō}T FSF?%LI [Rl/k\o i1ƐTiIDzԸ0|65_]^2{9>"/\XRG$E$"Il\IY2V EqL9,< |u.r"н.\EXu4%y&aM\㢼tI%%^0qqFKlDzWH%m\V$,Ih\襬Lb I(=# :̬m`%,Dԙȍ-:KWݸrv&/NŐ[ނ nc`J"xbi7Zo 9J@ocoZ0hb: |oתt%b- ]՜IÖQP"/\5ATG߸Sk &qQC K:ց@fM ͖.&q9Ѫzh\5K,Q3BdIlX>56S}7w V-9ƌ+mIœyY8wZ7ogeM+_ׯ;rV$G>=g;ֿcqZvS4>1c,.ppxR~6zg0qJ Vx9ur,p>N/FH?O ߳O$ldcܑ7?e0Sendstream endobj 6 0 obj 2150 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:18:36+02:00 2020-04-16T10:18:36+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000002473 00000 n 0000004212 00000 n 0000002414 00000 n 0000002255 00000 n 0000000015 00000 n 0000002235 00000 n 0000002538 00000 n 0000002638 00000 n 0000002579 00000 n 0000002608 00000 n 0000002718 00000 n 0000002791 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<5E3C07DEA190C75B9D99798369CBBE8E><5E3C07DEA190C75B9D99798369CBBE8E>] >> startxref 4335 %%EOF acm-6.0_20200416/doc/charts/europe/italy/genova-sestri.pdf0000644000000000000000000001071613646045020021533 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xXn[7}W-P_q_ !ᤍ42(d+,GV&_t^p83p8_씐h1ף/#EBxy Q(+.#Q8vx2m_ı8L hލ&|U,1m>}voxvs7/wnNd6E}uFGm:Zjy,({qwZΦx\,V뛝_\MwO~>7x-gj閻t_mnWUw[bv7 EN R|P>@T'#bgD3ؐ@AamMlB-j+Wd2 Zs~-bpۙ% ?b\x܆^qqL ~z<{HcbGTK^Y%`hϰ<Sre<ΆPY`ZrΛUДT.gςКʅ9+.=N$FAN6ISQc|6T{< TcR9_b =NL oNP[Aﶰ- ERc[T7[y,aGҎ/.z3׺wpxg#tɩoMƯ>}|[v"6hr:ѽ5]T.eqϩÃFúRO MkߩC*Y!޿~ٻDz @~Y~IFǞAendstream endobj 6 0 obj 1960 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:18:51+02:00 2020-04-16T10:18:51+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000002283 00000 n 0000004022 00000 n 0000002224 00000 n 0000002065 00000 n 0000000015 00000 n 0000002045 00000 n 0000002348 00000 n 0000002448 00000 n 0000002389 00000 n 0000002418 00000 n 0000002528 00000 n 0000002601 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [] >> startxref 4145 %%EOF acm-6.0_20200416/doc/charts/europe/italy/italy.pdf0000644000000000000000000006304113646045020020066 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xͽ۲eq-bYh~(^$\,tfIrLw9F&5,K&E@@.LL $zs_՛zwOy?/o '[̷_|ӷ_'r9p ϟ~wݏ~{O߽W^A ?߼|+៿_|O^~n_ނ o\_$x~_^oᄏ嗯^Oz?ۗ??|Ͽw?x{Ï=O>ݿ{ʮ[MrsIiݯy#;2zwJkf]͟yuydׁ)/on"odoGU~ֿ>šз(JퟟP2EIЄ$~hrBo OʷҞ#~Ol_ݾ c辧oyf=g‡+҄|J|Wxa|asSaҳ鈟baf Gb/9zJ/r)芴PRBD:z˩~Goo#Qe2螺e܉p&q)ԅgSCFN"s@Ӗ 1DIiލ<*n*3ǾItCzy"M4i ̸YP"j¨sl12Q/! ٥3HaHyT^C\x_RGKߥM>m_7<wJQ!JX.9> aYsF͎ӒGrMB:LO~K`O!tKK {Fr> n4AgxS-HA@m% !9;d'K?4KgEa h~"SNJ,+HXX**RwQ{3spi[#ǧ4S9"FG 1x J7Lt' Vh4>t1BkiOGL1y7}l_^_c tt' v?̥1vUQ{uc裻[5 1eXjC ]#h0ݹ--CxOi7V5=cjN|rҽҩmtZ 2h$`?qGԧz<ߐ{W-JU |x`.A18O ZS!NGTN鑜GǠ*tIWxPd頕!G3c&HjAi#?\'3X.1'4>%$K_78,rh73E9rGiЙ5G^f2H(Ό3 Krz(䐧y%CzL}ic*2]ϱU>M;?MY36i9/vh`cI_T2ېa@җk)VtP0/H˜{LeVÂ>}qIs3r: C~L :"7춓3<}cI~+Ȇo AfLQm.6VW:F!zHO56O^{1hU-wlAl) [cx)'v s|h` ck>QPNZ`<&tqO0:(jrt9xjI2>nIy M5 MBfFS8l9BIF&ԲlT48 Fq'bX:lTEr "ua>a^Nۦ&Z]tZsdR3z-Bg GO9B6Y&IaVF8!*}$D@/ѥw勖d Ea(*w ]1 "iIL/q6~Ùu憵cds0 mbN4^yYhm# I OdzI+t\hkQZ\%vC[ S Onj|qQV^Υ:&] $4ӫ8j}7 P( Y k"98Jkƫ蟐O:,,uѽ-.b6~á͑0XC&$uh39dG?q8Xz}eҴ{X\ޜ0a^`b,BZxeIZȑG,f#CPv1h5VOLwu8$OaN t)[^YѶ#1&%li&\c"U5 G-"K/{ Jw-WŅ? S\PH[/eEa<)]9LHJ(Yf"aaQOY3=1RSdrZ|b}KwSG #LTJkz3˾|03 hY)"d]pvpL$NH,+HXX3'dtr0`r2-sBҀI7uE%?icn8>~e5OF1|ҼI9tc$! OJ %0cYJ).%Agi%, xSz|} 4&H #=m))d)]=HwDq]Dd"Ѱ t,l*'V$E=}YzUrC+`eVAgF'G{n93΁l\j'Hש'iH37+_  ,TdTRkצ0O2J2bkrC%=/\wՆ"<NM4\F-1QU.$"ް`cC"ebBq'gqKOеI uk'~nH:u,'G^6vd=ES2:(GxBKGƌ.Ь)&V Œ].,%hV1^BECkta_UGШ'N$#=n<[Eд|]=QHЉd]$p SO,O,+HZX94L9YԎ>ES;IXOZu S՟*)_?QɏBpt֏ 8zfb=m:d]XHM$MXZ3DStw*ONʹr07~ߧS嗽hհL/wM,ֹK JcE@f"հ EL$OL,+mi zK2Fx?PKN_jW': dO}lW#`c8i<5'Y$̸1,Z0X^d]$,,{z u}-cr=tSt/>UF3o\8*GzXU+G2.R 5n ڋf"uaQPzpt:``]UGk5/\TC*+>~rRrnxaO10>3D K@G]HJX3.?Irt,!at⢤ljHow{s5o8 ^ߢlUYS$ιNe{T7f`!̸YXs:ؾC{B-َJ\#y?el&kgk !e=)y7iƝa î_YGpOٸnd٢X !U` $.sMHU$OL,+H^X3'h")%8(H/ҭ')\ ,88_01ء::(Tpw" z]tˆ2LwSGҩp"N8q7D7w8GG9 XuH䑨VtdÒP\t07bi!̸YXgUO! GSK%sF]:TdǺf8e]x7:uFsy|7Rb"ci%\B{n:gJi刞KI"#U6ZԓD^{$Z"KyJw=Iyb9)~.Ɵ~opZѓDgz{vvB s~JعBtC1 >Ǵ $WL!GWéѼ= #u{ R%TYgF~2+!&?HUdqע(i񧸫'D{bfr']fC0c %\Dg n"qaQO^0MuLK t]M~l{RC%>CXmN_t8Qgm}$No tS8i ̸YP:ؗcWvo*nh2H+p#ěU ;q~Dzot=ԵQvS;ÂB{, K zleI:q;PK6"*qe:t:,xFmHo+w94SxRrmjDyj̉gkH2'yZrZ<2DW=AibZg5s7~ߧqj@572YLc@*i`Js'%,f-uɆsQhngM7bi!̸YX$1AX 2ԑ4&88׸%x#d)M!R.L0xX2.@1ʄ/\mġzN[E&KTRrԼs:r|20+#!,F*4nl"g݋qĪ[Ɲa h;Va+(,ƪd]-,)LOt=)r*XzC]:ljk x艴aekRbf܉p K AFEF:ROLIc":Ӑ5l%d7: z55 30Nİ] JE򊥅 "mawݧ; ŕFtJ`zC_:t"/C#-wKqŵMH@U D@6uDJ$KdezJhS .r%gu,tizs^:掁򋇠jY0 ɿQijwtF Y :C^Qo,ۈH w(/KػH6,YpoPԇOEJ0NdaQ=2G¥p%z7~SWwhXGj"ebBq'gKOihRK~)jx+ISGߩ^7w8;83"=(b .X h@6'tD4Q| yKU$-, raR<nb$ᄸ`pKz^YytF\K2B,YEd"ٰpz@dj1NZQv'; qhz4dl'JrHzs[:fڂtV$88/,SxBb5 S;?cKWfYjƢd1SQf*;8:kHYq!<v<0Ua15OJ@ɟd"6Sdz*4 ,Nƈ}l]4c`O8}< AFEš`OIdArՒ~eVA{V~7q1or?-7tՐY"=IjNd܉֋ 4eqd]-,mnIhTD 3CEbMOrKGБQ$?LFRww h=Y|#5Vx)j9:po"S&*'VT,-u Kԓ4OGpQ;"s,6y:a`H]\AϽx6I*q";©LA4X&VR,-$n UO܎l/ 't??O)8ܾ7|F9/f*mmurNRP.T4EaЉ(M$Mgd]$-,=;9&p ô H/OZu]pRS6gtK}]gD|ЙA;a뒻{$~x3z"Ѱ @*&#Œ]$-,tBN1q71mVA{ƒV~7qoHم[+u9Y;. ="26>F.zEY<*?ti/(oYSgyi}Ə ۩a&Ig#mF7jBXYY{k!nq&G;&S,-w" K'QM4B[3dZT^q7~ߦ#?LkGzKUJ. =րD+)8^,#"IKXM4*\Z3.&ֻg ?Q=54X/OFu䉕ԉ)5(_h[+L_쮓ʕ|ңe*`e~+M1tºDʌh #l"S/]ޥ.gY*d|I..Xԏf]$(IXHX"lwxIݓ2e0fB7Lpc%H{3*8VG&mԍf]+Z%&:[!ȻHX DR=,I ~c"U bI .\'ʻ'1nK\L&8sN &]-4(%Ն 7>D6Eb\Y2.'֬91;ޚR0Xio0"Uţ7LD/V3.'ВLR&ݩԉ n= _VCy|LQ3&v袧 M< AWתEFj}5_Wsj|]#"}b k ug{nehEvЃ*́X)q(#)ƠA-HP,zjJ8EbF.-e) 5 Κ|6/ IbpZk%R \Қ +Œ5d-i]WVdc6͏;&\3M;oD tm"x\)"-U`f0#l"S/&5чhvl#9"'zcq4k|ԉVX!b kh_ƺF98d^1бqձ;sJImUJ(HQ,I:UVĉe7m"S/yFa^Úa#RSvX?Z*R'V%%5V]V>oۚ{o$WGV!4`d  tK)Z`$(3&2ҚkG-#? |ӚGPUk^2. \z5"ubieI%j uˆ\&I,ѽycUU\<-,A'fFEb r"rHkf]Lwr!*ĮzGM+A{NQvX:"qbErY!hHXCK2͆C1ކQ{[b;MŎ[8)^CM\g5HXZ?V2&2bKoF)k 9)<[%3.R \ּEY2.'h鶺t,?+Acrmr2Ds<Ǵ^*Ct. \w%%#}͌dze^ fXNOak!HX lr>˅[r@t5@FEb1&D"ib%rY!HXXhpMR3/. ]9lzJ,AwX=\՚"ib,ukռjjϚ5geVP+^>Xh,[{LZ=8$M,XP&W긛gkb,O(];23^09pdF.ȇih4]50xwycp u. Ͱ.-}K ֮\IUĮmIPㄠdJ^Lrkk%\[0q%\BG2S$6Ê\Z3.R';\(MHGJsCnlT 3.R \G4ER+ 5:kIRh9x$Bm[(S{.8FW®L bJ]pT\ ,: aFEB^ey|k~)~y|ko5_E_5uAGo5/Z7)Ѹ2n6ubfM\ƧX/ "S/ԼLWP If'gPV#3.R \a,YKnyf]$L%kIR^IJ6h-i3]dV ܊i s-m4HX = A6kޡW Ruq\dk;@fM܅T:ꢚ廾T&Вu ZV e>18>F5TX9rEjahFErNjۘHXQ$-}kX !ˢҘEr<*ꞅfMD)"Wjṇf!`*2mSW]N31L!#.1#<ZSl+W,8ؤ%\,D3.'rDQ֚T$Vn<䪅0o"S/hZҺZg!JfbvE#nA`waK yPtX"qbUwĉNqtw…D&WRå^f]$)B܂DZ3ȥ0"eb~K5k Mnmjbm2]_ّ*#5ۙ 2`˜bM ӫqL(;&b7J!8QFwX),ulK#AUJ{>˥:5qCDHD^r[$<&?Gxw#M`8Hn;3T{ E+ܱ.p4dRCFEb+ X{&R'V%ԉ%!eUx%FƢ!6v1MZAHOFpԢxTcgMH$}d4x,Ȃ)0 G@<]dI/1B6  LgT`5'0ޱ $J j84c :ݭT\teTlG{3. \Bue "mba(].ͲFc vQwXk"ibY2.'ֻ'e`W$bfuqoABWCofKEjMAId%mu)tβᑲz1S ˜Iv#W+^6⬢H4T,Sp ΩxnZY+<ꙆțuT3.R \B"yb|? U-gFuC,@# AFERU_ n%rXf2: yXqZsAcHCӛnj$2QOD.4RMFf]MwOl!9pS tt9 8fm9r#ȳ2"N,`Cd"~b⭱N0dԺ F"gk+6-l44b,i.F\1+Q6miVi.2.<2d]Ƶ;~BCKWNej&3)DԒme",^E^[] -oc5OnK+{]9&Dʒn@d]$+H_"yberY!HXRX@IK𙋝%&32. L:UDVc52Df]$MwO˴.:,A.Ku%S>v8r!L!Pz%ґV)aq%bŒԉN~[E 4":qj pU丱G '{1BGrسș=((W“Y⵿Wb r'HdقdBkg4/Oc& $<   _&&%FӐ[.0]hSH ]YH_~$+px4mwt3*l;F'r@r8xL7vOce)1PJ' 7h(p9[dL\T%D'1Si>䥉k@`LfP+ AFEJ[GʳVu*l*:l]V{ h CfC+8d F)1\ 2FqC1$f]$;HZO,NY&9BQvCrDJwNV:[$K<ĻI}g W,p ]9Y"ubUrY!ȈHX.+Cib6߈\^iB$;Qn7Cf](">m"LFg+,^E^<&Z%{ o>INA ' xhZS$MD.+qKme6:Pd)fӜܦ EЕ~Xҏ_nq`5"7/خtI+,Q2.'<ӚvV.N@ImK3. \M$M,y+d ݓ2֥7:" )ռ1ShST>}&‡\Bk4)&pBazi#@g̓.Z"" a]uTcb5""N5"ybeoSv0ouqq<}FKG b;"rtvp҇ś$7Nj&jFEb 覽jXK aFEĒbKҕC"|]r |rk"W4#"! -9"|, g0"eb ԈЄ'k51ȴ>hTe$uÌDWbX'a"ybBw;,G+>6kVz]oPy 8ƃ e)*91E{d]M,Qu)tMru9}9ū4whD&(_)4"N~nXq+iIT4]=jl0=)I'*92.Iiz.2g!ȻHXzb%~UC̀*<7ڷ}AM ͈HT,ݤrIQXg!̨HX5?C@@*%"J dE( Dr؃K>(󦟍=MݤsF{9X|NƠBDYX3kQ0np=H_d#=miX3T|W=?n%9lAQE  .icOEc9jхSq =9G[k-iCnoEyHǦq.y qȁpbB.-uKoV/'6ӄERA[dV]pv *"sfMdꅆ_ƺlFG9!f[Og4xE/E[𻈏.aHgA,"f]$ՋYc<`sV._I"knMDxБSAf]OإtczP~nJTq ZhE|4eʲDJBwt HJG"Fd-3XljDEb h&''ĉ0.ё9CLuiih"C]F ۏg ?}ؿ ^>zM!~OO}[AG*eP8 4ZnRd4 H~p9%Q}vsUpR|%V_զ,KvUcy\5srǯ\K_o׮ӽFW)$ "ooz/>4iWecm7ޢ{*6ǘrNT-OF>d(W_kո$u]J~+cݫж+l nե{.-&hvU>)Z?c,r_3a2cUc5J4M{_kO?>{R6ڽvɏi'Ǟ$~ }uspa:lޣt̞߻~~O?ϻQ(EYT3Ǻ_]śҫcupяy܏F?&0M9_}OC>Ec0g|6~z>&Kr ~t+o__6ipyiu~ԟ&Ǥܬ>1UKXi@w'WyLƷjol"[61ꖓShfEfF}Fp3U% Guo\%?R<-~k{~|Ur*!p\ ae_M6/'ybmLK?o>- yƧwn?[GftaA[8|YGA4fv~lfTޛ]gy]3N2dv.Jŧc]%?R ψX3+B+̻Yacx.0e}FyN7/܍}lF&o>?uc9эE0!|mP'뢔8:.SmWynw(a/~@jLVNɫ)-'<я;eQNhUcML.ϮS1i`mt`qދ4E*qo%^%?f74,ʳ;}\[W-dzjkFe/msm`rUco2u땢22%[I۔Pm^%?ӝ~`<ѕO\gWFAjl5{rk/?8`ɏw[*nv}Lvae;.?/q>ɨh%lSЏTXt`CG̏;2,;ۧ*,E |Nc֑V9Va}*A~P~ӡ4MQGzz5u ~s9Iˎ#M>MARR>su"OfcrM^>7]Kn;B?c>IU.q_I?SNv?cq_ZFYsʓ]RL~L9 P.޼Zj.n۶{ZpzZ9"^krZkHW:Jo]lb2elH:b>zeWUcJIBq 8u/ gy;.[%v;D-_]f_$ȏevnwvz_u[kZ?c_d7b5tH7ґQO~]m9B\X䟱~!q[ 6n6~gyYbc'^ic&1ӥa8 0710BY>m|x|=9`4i?zr9Tg+/L\/!|UWWx*'zoW}򡁓i}2g|k۷GgzXSvm쾶Σw6J}lF^O}5x[c2Aڒ܌Ls9@e.~gnl^@piKL~p.&PZ8}K:e j;.@9K|rݢ.PIG ;: \=>-,AO.E8c7pXcXr2*]TRS,Q.c:tJ伬wȪR{J~xl+oEMy{L~pd?ɾbJ0]&?8ɍTQǸ_+U/ .'IUN9aSO?~qbQϖ/2A=9n%vq"@`9b&7J Y *H}pq^j6 =fL[=ec:e P郆﹒|Mb$myX䑢Ϯ Wݸ )cH~A5+HWUjUÈݶIRX+q"UGjܛ?rev>Z-o> \rⳒe\Yu߈E$$L~k&7_][^6xS< wؙPvJ 䒂xk^&?[Vo?/>)wVl܄5 TA]$?AAӹvpOkyEcKb !OWnm+AZ)>\ͷo.5utnKQX۱wH~x9\S7ŽH~Н0sz-A>"I;}’%J=ٞ1" ݱJ~!YG*A|վ%z`.47H~nW\n_~Ѷ|?~X%2C7y.+`Nxiީ"GU$>DǽW"K\  uQioWɏӮ5%.zi;.ZI/KvϥAyA1>A\qJ~pp 3gǺ拨|/RYn?dGUI  x_1WO{=}<}L%*e0%c͸Swe7ױcwc}<)OUcoj"w>ϩ%Gk2;7Dݟ$~wGc*dǯ8N؋^9Qw)w$?5Wg#9u5ԀG/)OU.*|Z1vF5KW?oVsoTF'=Nd t _|W.~ͫk\rpj P:ns7eŦ:|5wM᏿: tGz 8q9'?dSGۘ=eQemDq}s l'ت^ \/pY|`[ xcl;:M@$Tq *uxΎ8..RDžwl-<<yZec(VN]_}u2nDOro~_5W:yH0 PR:y=)1l{(f_qԼJ~D|Od%ᖤ?Σ.%lK x3wƟ$VL8-^&?:%_uˢ8?~ODp ra"~agZc .{qu\QAc$WNoI`Nnݽ r+ ب6o!!贘u`aϥ_iq/*Iah:|͹͜r9'?07ޞ,VC;䇗{w_9 xh.RkXlNcc{DwW΢$v@ezmv4xuJ}p 8u^`ׅ}(E&,ְ^Fnj\&?mk ܡ͔B2?9]%?4Xa9^S/:VDWS?]%?8ĺuOj/ GJ.;so*a#,?7&qfyr>;t~KQSuP[8wԟזs WN |slt;}PW>_99Svǔ+ͩrK7sc>8Q yyypA/wsłNWoJwe=|^؞rf> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:18:14+02:00 2020-04-16T10:18:14+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000023869 00000 n 0000025608 00000 n 0000023810 00000 n 0000023651 00000 n 0000000015 00000 n 0000023630 00000 n 0000023934 00000 n 0000024034 00000 n 0000023975 00000 n 0000024004 00000 n 0000024114 00000 n 0000024187 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<4AA684DCC0E86FF1F5502E0A3A612B78><4AA684DCC0E86FF1F5502E0A3A612B78>] >> startxref 25731 %%EOF acm-6.0_20200416/doc/charts/europe/italy/milano-malpensa.pdf0000644000000000000000000001470113646045020022020 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xZn}߯7@KU_䁖YWvDɃ ^dbƿuOrg%Y޳]Ukjj{ɭ}_^Ǖޭ~YyNq~=}az}R?ErգՇdzͣ77'/6O?ׯV 'Dtztz6]\^mLwGl?m=?m}џZ=~;m);xˎ?|}Z_~<۾]__tsu{vjokzwɻ &,nJMw~ I1V7]ΤvE8g\# ɍ}Bg;/a]>MBB\/H~?o1ݬ"݄t2x08.*Rlv RYGWKq}3r0.}ȩ >>2ⱇa5R|=Nxwzc#SM u>WlfdiLgș*hgcfGrCHh&(efzXNO~] cww|x0=|;Zcx09z~~2gx9rEa$*$6KX'??!9*CjCf"V$7.2v\\m&ezO~FY=:AvbhHW$}aQpٳJ0a@^%gS)Fq_dv twCy ]jǹP6T c b! 2~j?i!@Us^#x ŬNeO H W${4~;j6(?LShk $LB &AM̵H"adj_-i 3.(Nu8 nMB;$ZV}I\U!|+)( &GG3)M"4}KbZ$ Jژ 13uh0胟}~ yIx} +6}yA@iTMҀ.HRdEjr`44f;WV6`4KaSp|Kl^i#xa~.{2.~Ǟx Q ngZH՚WCs*X4.b u6\`\6hRgs~*@)=Zkn4/st6f>Èu_R8.J1ȣF.qnU$6.B) v@7}{:gOGnܩ|L?W@+ιgJ뚚G4.Ug\ZmѤv ήAhݖ4)7+iJ hnW1Ե@j &s])]Ƴ4LιNͽ9GZ.z*(ǟT E D hɡ&й@$"HI\l>' }ON6*"f*G$k):VDu4+XƆ,l޻)ڲҳ­a,PdEμJ&Ke5fsYlѤt.{VW&HS9+{,dg$U k)$wZm$u]Y06Kq6W{kRPIy٪E1AL cȒ$v.$%T7@Ϲ MexN;QT &Kkw׹jIDFԹ.Vve0Us"r>RZSE;W,Ov>-U |99k2.AsΛ&s]pQ[WvH&IXyHJhZ1K v.T6h:Rr^0!j$S)ܸ \7tLAȢ"'q`_j1`i\HM0t4dS]tRz"^Lh%51t v.T68u(i,#𢨜}ʻIUsi hף}j86*7.UTM"Msq8lF>W p4A:ד2Z4̈́7ʥ;> h;ʮLcNE13<-(h h⍫E:E⌋yhs+Fo9V3li4I%Z弙UM"2"o S_ho06z:yFCW&`\u5.(c7AMJw!*aLHU= JѤ 2&sej@7۠u^0uU)|j?oim2E;z?!|`a͊hw.ʥuOM:tHwE$]N@IlL h e'wm$w.RĆe8AJshjȹ6R U(퐽uL k1J"Lri\X&QAMJ"x9#dEuK yuR&%c5u.\mw.Rdt e$,ko2Ռ !k >o0gR &TKp($t Z}e9?ҁY/k(M 5g\Zm$w.s,S{Dp.4ΤՆ8E z$ -+xCrJ@F"Oᘵl&sj &sIO KA_d I[0p/8J2UM"4u+XƆ6Ns?''ҩ/*9WD TD~ܸdfDa0~iP3{>j0jtIw"ȣIj$*I\ϷXBäM&/E^1FpI8 ?,djC~4ZMsjID v.9O iہG=mTT nH\^$"HI\^Œ178+Q'vmMb> -*bй+ hR:׼y^a-fb+,+lYa; } bX>~qzJ/ڹ2m}Az}0҃)렯>;ބ|t~Q}=9'aAewN^l^NT"E^TԼD$0zg|bZzͱgNȹWw7|xJOQEe}Çi&+f^{)}!En"5qOv r͕ȝ`-B&=@kAYo0ߨl˙G9>u6)%ݝe TS{ 7ǁ+JRMe;__tc4'nߟpTⲖGڛ׻ǣOۻO^V5]N`ڐb'/NSHQ!NXȽ彄̿?^l>;H' ˵W/>q@ݦ% nP\zʵ Ѣ^o;$;K&mkVYB,۶4:jw Hś b㍯yჼ'lM|ywќ r{$wq7.(^endstream endobj 6 0 obj 3995 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:19:00+02:00 2020-04-16T10:19:00+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000004318 00000 n 0000006057 00000 n 0000004259 00000 n 0000004100 00000 n 0000000015 00000 n 0000004080 00000 n 0000004383 00000 n 0000004483 00000 n 0000004424 00000 n 0000004453 00000 n 0000004563 00000 n 0000004636 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<9688464D05009F21DAC53EC2A019B08D><9688464D05009F21DAC53EC2A019B08D>] >> startxref 6180 %%EOF acm-6.0_20200416/doc/charts/europe/italy/firenze-peretola.pdf0000644000000000000000000000773113646045020022223 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xXn6}W-Pky'ei&E ~Z{8knUNBr@*;83GCrH拐ӳV *)/"Hv+~[CʊŪ%QbN^[w;t~'ĩxu~qrt9$qyu2o]w*VMw&z>wm7uwk KWgIy:y;:x\ -`j) p7V?0(8R7W w%H;29`/ Op0،!;8ا넏XX߱+2r,ƮmGz|'<^8IO7Ԯл}'YMYI}ے00h I(8;u^׈npd>ۭ=3GEdQi.܄FUCАFFmԠ  C%aȵȫ| zRj``IH2n3p0fca`!&qaȵ¥+ n ׊N0wؘ7!RO>bi,-XÈOAh" ~ KzV?} zRbiG,RBd!W!fTR r"C2aRU{叐ACtd=,mO ʫˏ0 Gb()qR1<LԆ fbzv\K-\G!pA$*J& >Bw%)Y҆ r"Wv14CTW0D.Ȓ{Zʌ4:K7"NSycl%bPZ2T>ACtB/*1D.^#d_;RE"pށJ,"`F&0D&."Lb | z d=c-] k7͜=ק7 Yi==jtłͳ ]K '6Gb9g⿰ ױ><99*`b!ğ\^{yN)6FI׍cm4Vtzo*wL BZ6i`U3I)8p\|$Ϟs儿3o;endstream endobj 6 0 obj 1459 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:18:48+02:00 2020-04-16T10:18:48+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000001782 00000 n 0000003521 00000 n 0000001723 00000 n 0000001564 00000 n 0000000015 00000 n 0000001544 00000 n 0000001847 00000 n 0000001947 00000 n 0000001888 00000 n 0000001917 00000 n 0000002027 00000 n 0000002100 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [] >> startxref 3644 %%EOF acm-6.0_20200416/doc/charts/europe/italy/napoli-capodichino.pdf0000644000000000000000000001232613646045020022504 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xYnG}W[l`5>(ae$l^Pŀe*M~g==<]u`ƿ򹸞Or?Фŵ2^fc *ίgN.nK\/7[NOԑ:93&z?{vX,ᄅz|a\now||v)s@y 4{bT%|\PV[}8w|{Y/.~[oֻo/jYک_~TWaX/˻/f{q9\7jSۻg|J>hVQkuП7f0UVׂm bk^~L'Ľ:>}qC[q^́?87F_́u7 ͈]C}?|2Mr‡~LoSl)OwلRćѻ}><đFO0P\7ߕ~b},1A|`<~bJ8[z>24 z9U~wF6j?mS~S·vbO`~o~;?X'x0~j({3+. ccTF̿T+@f!gȌ6LdݍQ=S,ϰ״<5 LTx-E01M.qȏ?b% dvXMdv66Eޗby_S'ľ1gy zA„ o^2VýAh!B[~&mZcAl[e”N"TPpB.^D&\^CP; l@৤|'7'R Ub,UҫƵːT rSe"OxȎ`eZ&b ;Gl*qY//*.X{ё+ x95F+q"*QH%W6߸Fc@DUpaJl\"4{ܸJ~3¶$UNg(@w ax.F ҔdB*ZH OcM^7V0*crDSyLr ^T)m`$.Y9&Q1Pe)"+SN@ՖSkA NBFg_2t{OR{aXt[_fadVծ͌k>+O 7|m tBޜ+u~d4 3xgos>$x$r/㫿 UM*6M>:>Y#?_}x=uT}.՟l4'޽?C;߬=;N61oA4^~ 3OѼ@A4O':G'`aKvK}/>}X0G?r(ѡ> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:19:06+02:00 2020-04-16T10:19:06+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000003059 00000 n 0000004798 00000 n 0000003000 00000 n 0000002841 00000 n 0000000015 00000 n 0000002821 00000 n 0000003124 00000 n 0000003224 00000 n 0000003165 00000 n 0000003194 00000 n 0000003304 00000 n 0000003377 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [] >> startxref 4921 %%EOF acm-6.0_20200416/doc/charts/europe/italy/alghero-fertilia.pdf0000644000000000000000000001047113646045017022167 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xXn7+#P'j'hloYȖ#+pwz$ )P?0gx=7&:lU韨Vz } =aΩO{g+=aW2\rsqrv⃐z#MOdK}T`z}ZƆ 7u;%[vrwhjp03 Qoh@ >bFY-յ`\Bp iݍ EMHKQ+ ii']X36VpSi/O;^ÄŘas2I'$b\XWȂw#CVD## KyT2*#d41ΤbhCdB/2*t!rI*A!": k tw[T֥5XxS;O{IJ kklm\E8xt-!&Elm\ Md+]ppZbDyt ڇ%٫tB؆ʵ[SBi*ٷP ZVV 1̾qx:ВhA!2sbm(5DU.^26V.ȾA' ;>RcbԓC!)lmH\EP*K zNȐpHE*ydKS0Qp7fv^x.ˈr)7d0 K^̙!ri*!ra{Guϸ X#ʫ`ЋE\B\rȝ!raUKSQx4NNk+xB M8B}R2 [8g%tA.BPW ,%T]8` bu|yx )8=4Zh^Wc66f."lS {NېX\5#{Z:\)'DUܰA!*saZ:[,{N`S@%,q%b3˫PrIE&Ě[9c28[6#:ґ љ Kx p!?Xdm\X?S1VhH L$*!!9S1ETTNؐڐTPmrIT4,"$g? u!Y۠)ttiw.!XK|و9%EkV0~ xm?ޥUl0q6!!~jPJvp89tmUL@uv (LG!&'za0KHs$AKXN?aQJuIZzgҖJ;j5I`Kjzy&xHmrٓo^L^ !Áendstream endobj 6 0 obj 1811 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:18:28+02:00 2020-04-16T10:18:28+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000002134 00000 n 0000003873 00000 n 0000002075 00000 n 0000001916 00000 n 0000000015 00000 n 0000001896 00000 n 0000002199 00000 n 0000002299 00000 n 0000002240 00000 n 0000002269 00000 n 0000002379 00000 n 0000002452 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<0215CC003D6FC6D0D3CEF2902627C89C><0215CC003D6FC6D0D3CEF2902627C89C>] >> startxref 3996 %%EOF acm-6.0_20200416/doc/charts/europe/italy/ancona-falconara.pdf0000644000000000000000000001036513646045017022136 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xXn7}߯[^^ 66Z"KrdnUNg:R5gwfz? +!'_gnދNS(eO!eK1J>*qof銮۩89y_P{s!Nf"Ho>|vwdyOK{'lJH[D\!J>m˯5~{kzh9 珣zNv{7jaX]͏HAjEpo~][~ Tܽ4/%x#UX H:(,*:;HO_=)``1]’`Sȋ̮9*$2H2!vf<1/ Y#cL!pc@p1Bs4][3oeހ"d>lb3W<6k3:sj2 3iF+3_IUyzt{`ɵʥW Qd>צp7znl].ܚK*璞WQ`bnKUɅ@7)hCr-s5=aǥ2}>u\`coRdJG &2T*w&LF+ '{׍ Ч ۯF=w<L(^/\AޓG }8rʟ޼< !Z7!zF)N_t'㎥j"kgB=)%{gR=&# +D}t-C:VeiWymC?D{endstream endobj 6 0 obj 1743 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:18:30+02:00 2020-04-16T10:18:30+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000002066 00000 n 0000003805 00000 n 0000002007 00000 n 0000001848 00000 n 0000000015 00000 n 0000001828 00000 n 0000002131 00000 n 0000002231 00000 n 0000002172 00000 n 0000002201 00000 n 0000002311 00000 n 0000002384 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [] >> startxref 3928 %%EOF acm-6.0_20200416/doc/charts/europe/italy/B.pdf0000644000000000000000000001315513646045017017134 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xZے5}}0Ŏņ 8{!f}ݽj..vͲѿ7?}8ۛKY~3'O<ۙ.o}`W..~}h}\\]y{g>\^|u~ws7a3o?<;rp{}{\ޝo^||wuszy{w}e.nnn!ǯ6$[)1Y5Zs\p>R:r;L]Ysp)^pc埼2D݅4uzbn=1L\Vл8 i/7Nw@nNr:+X|eGC8LL7~bP2kFaSq]kKpL>1>M>x&\\ȧcO/Q|#ge>0,,9N`q<ĽM]dyoä]dcpMO֏-mCcBg@ X<аl.K{$A3^.Ơn&:s?VsQ;^N>Ɖ`qNb+ôiez#035صPৠo">H8 Nvέݮ֜79[uiRkK{z5{M q hlu0"63$|&%*DM Xz{X Z);v*€(]u2Ykeʡp[⛎ B1jǞIb uԡUUK4U ~ƚr!w/ ro#c ;È9/u׼U\ nAˆ:Z!(3rjq w46 *4^T(2oKW)tqnn sQF*)=8fwb5~iTͩifuB4HhMj1 8La⇖V:lօȣ21UF#&i0mTpMX(IZ䥌Lb:vI`%fLǀ`Nb ĢDZ?xb0qC ?y6C6[W6 In*[k0v$#I&eha&eh22eJ:uͪ929Ih k'FB狌!y2ȪC"9cVos1Sx͈S<n6q,Ʃ!T#fC#&ih|8%J1MfNc#ڋ%{KbhVl:#&A\&.w-F҇HGM†}:\bcD9Mˏ g_g^MAE&qh22eߔƁ /l]M4~hI,O16y?UzJ Pd.(J׽-S֓\e<{a(>gMU_O=s1{;|Zr4m7ܣ_7/ξ|xJ%'oS;u$<|߿}S=t >&>~%ɷ/+zBxߑ=Eʋ] B"KWtD:~ 7o _ 9endstream endobj 6 0 obj 3143 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:18:20+02:00 2020-04-16T10:18:20+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000003466 00000 n 0000005205 00000 n 0000003407 00000 n 0000003248 00000 n 0000000015 00000 n 0000003228 00000 n 0000003531 00000 n 0000003631 00000 n 0000003572 00000 n 0000003601 00000 n 0000003711 00000 n 0000003784 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<5229B1750E5215E25369CE5FD0C3D2BD><5229B1750E5215E25369CE5FD0C3D2BD>] >> startxref 5328 %%EOF acm-6.0_20200416/doc/charts/europe/italy/C.pdf0000644000000000000000000001370313646045017017134 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xZn\ߧ8wMz5' B8h^+d+,GV&Ot!wE(ФgpRB[kϋ벼槍p+j6n i)-g/y8ٗg?A|/e=ç_>\~:ɵl?o.E=%?>]>JezdBDz(Q:j ZF x4knm>xM\#mw)2DGyw~(>؃7Q^$S|du 93e** gŢ㵝ڮV製H)8˅)la/jPyU\bXtx[h7x@ƁRecy\+%E`8:M{HW*u'),!'"Nvy/R㉈^32RO~<ڙ %8ǭh'Ǯ+.8^mC3&ԹD :LhprNT0=~8oy {H)lS[^!ZGÉTAL%0o}3+Bkt"L_}[+"i`x.*B\Mȸ%FL;&~p:2- m|Ԗǘ0Ɗg*z,NSؘ &ɸ%"@f6o"#XYen=]Q17EyG5(8 lK0qs -L_2&/8ޕ%5cU$V\I0.RDu5 KG<: &ip%%ugi98͑s9 aIcP~ĠaTMq0sHI\Qz'$5iȧȧy#ȇnSv7Iԑi,C}Y]6Ynn;.nm%!i6IeM.λ Hnc6%=/69-co[lKCu5E; &ypnc:- JЖÙwL+!'X| r̊pĪ4ALpZ_MDڽ xw\O-2b91(¹`Cd/vrQ0&np9=]N p ^4cx˥qz\ UiEcE*'0N&RT 81LJ@'F^R1¨/ETQ*tM*I5.h tUw"L_yZc;r_qTN˰M.^k!)lyGGXrc& iT&2_\2'8xPLk)ﭤZ PKlBaI7˫V?uai=gđ$]^?26$aEsRn%(io &ɸD 8ju2LRatAMຒ BQ1֞DLƅK@R4&^( aw~M.RG*$ 'Nn Ur''fS$Ò4MqAqhP&uk$ .)tX NlZkи$kIPLŴW/,ZziM&/xQXƎ&48n1 OZ*~AcE|F/It60Z]&ME$KIh.%N?4AL$\JDTJ@74(pt4bTfrd/v騘l͛\^މG}2 F)c;sB ~d׆>O? :(;>r?Bē=gÿ䯽W"K~JR5/rԜ~YN~?r;.^B{.j>Υ$?J%ON%\W/&i)E3rS.@8bI$NbޛC=I~7`N=;`6,?5z<`se+kף#=t0އ6K`pJE%ݡݛW/ܵGNqLjsDNԭSVo݋*kljh7>r&J;}՞7GhM{9|lEQonڒbs= zǛHf _6~c%$_<ۏMx\i9bjΚ7XO endstream endobj 6 0 obj 3485 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:18:23+02:00 2020-04-16T10:18:23+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000003808 00000 n 0000005547 00000 n 0000003749 00000 n 0000003590 00000 n 0000000015 00000 n 0000003570 00000 n 0000003873 00000 n 0000003973 00000 n 0000003914 00000 n 0000003943 00000 n 0000004053 00000 n 0000004126 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [] >> startxref 5670 %%EOF acm-6.0_20200416/doc/charts/europe/italy/venezia-tessera.pdf0000644000000000000000000001102613646045020022045 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xXn7}W P8@h&i)PEUXd% 7Ms!cݦ rJӟ2.wδz?862,w+tH Z$*fPW٣7ju{:,Goo^<f:W0Zo7j9.GE].k7GOǕZV8;WF}=aY.l7O/zy}T_qVݮVxp> vzw|nŻ۪vj@ٯ3Vy|*hٚxạۀm8zO86?Q쟐GsDNzDWw3uCb=I/̢- ْhY](:M"lO8\38UH8EFdↈ3}O71_ |K)i67zzBѻ0ghl;zClčGTd7*?ɉfq)QE#obag8F=}( 'pWvp_3Ο zm'm:~s޹h ?y8=~otd~i=}:CAGoh-#Vju(kXHUd ELf *s8\։& Zf>mxX4Ah*&Â](,: Zΰ`% ̮-4.#\u1!if5CB?CJpU%"?/hdɱ\yBvozDKČR15.'^u6>5.T)Y\KߖLyt7 8pld.n ª2xv!rċ*3eI`+q]O% ^H$J,Ӈʌ!q񪓰!qi\k:əBm<@}TUJsc^ЏwP;^h|$yZ $No.^)%KE)=՗>ҤcR/2+Ezӗ]? J*`=-_ |Q/(]7Oj|O̓'nMj4w$pӲS n:Ճ V *endstream endobj 6 0 obj 2032 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:19:26+02:00 2020-04-16T10:19:26+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000002355 00000 n 0000004094 00000 n 0000002296 00000 n 0000002137 00000 n 0000000015 00000 n 0000002117 00000 n 0000002420 00000 n 0000002520 00000 n 0000002461 00000 n 0000002490 00000 n 0000002600 00000 n 0000002673 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<21BD12F9E6EF4F5341CBCD3D0EC64334><21BD12F9E6EF4F5341CBCD3D0EC64334>] >> startxref 4217 %%EOF acm-6.0_20200416/doc/charts/europe/italy/roma-fiumicino.pdf0000644000000000000000000002060413646045020021660 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream x\ےGn}ﯨ"̞ o%bIQrE8Fq6f892*~2+m<]NPYH$*G,n'k7e-?m~x.~ +fĴ7O."zw%ϧ|{\pO=YdOvwo-Oxqp{[>\_/oǏÇ?lo/v?>||wpr~xego6i\qKTݒ[_on$9qZzXbfQkn7\Xq!\$3~ORRbqaNyJoZ}yd[]<~WڽmonQ^[m"݅t6xXB!*Q7T,w/G%%/|#w^ }4Gb!}o[y6 t= zD-wzѧy zg=B\^޻mQ3gͥ/|Z93Crޖ?)7Wx6?*۶ǿ?l~ q?q""l$/{k2A "O!t,/$Ð8mK˿Wlv66u.vQT\θlLVgՆ75Ew1p5!NK4U$X3Thp_ЛyrQJdTϷYB\('x˜ࡿwHDZjOsruR,Iz) fk"HQYe(z| S7>eJSXcLu-eCdbqd`C cAZCS(&y+cNWY! MVq~a a 4(24}ɯ I6e ?2ivڨ&s0(fRW5.=ौ9Hd*ͧwB Xg%rVeD~KqAXtua(ަl^W~J <J[P ~W K?P[Xp N դtԒ&d٤t.RUuU`6+[$ʺ)2!M%#avU\/mW}T\Dy q&}p 5O?_юb@f׹X "M3q ?y ?W2p:4fF߮]w#p*Ocz=Mf8]pfbj+:t.RL$h\6 lV.S\Xj.2fc&amQe!^/~i\`qamW܊tN=$]+]b7=%ZIUI\Ѹl٤\oQFAC^WYN`yp=N1>*N8ix_I=pbJ/I̓Eq6KgU&u.Ee`6 ~R[$D|/rηׅl7WQ4}u3x߮ӤOmϿ*%#G_L$&s } fҹDK:ݦAM?]XT0t9u/3Q͛]O~ crBc& tr&5o dk@yy7w2%Z:m&4\}frHy&F!贔*5-鴑륮bލBmqDz='x">*K3VSJ@kuI- t2q *IXOB'^~G2X_i7I! [Z$<.:t@E[& لKIT iKha٤VSV~ɿ\Nj$ Du5 UDi6IF)3tfܖuoy[탶3(I7 U&\ԭ&ᡥ9Q&u.A L&///͂:*$~5$d|^U$>$j NMTW4 *HI\7Rp2^BΩگ%B2a6KAKdlHHfh6!Ro'B .VDu6E^a디5ӌNblRK{韛\Z}٤ .y`r'!:8UU:rI'N 6!=LU)kkp{>!2)C@ s}ap0z٤oW+oiؑ6HV0R-QTW0&f\7-c^QIm!y6)sC4+5&لhoeBPg:nDu/jR0Ⱦh՜;5K*I4.ղtg&ypehATf4,=x NՖt^4ܰ%6TX8Z)$dh).XŸ́wQƥH0 l׍*W`HF/qDPAMqb0+B:^K_%AIS͵>sL֧V4qٜ4罬y٤.6">gpIG m#6Q&&aphATf0lXV:U{ĤղbF_\JqJ@:ydZ&~pNxDL_$[E^#0˜glӔ5&ȳI6.aVDu6K6b[^vא,M> op@ꐯ(0mHZ=/27-ֹ6c`x3~=/Uk:nKP8FlKD\Mꃨf\%X9/9䒓˝7 W:H0{ܹ AMl#}Ytl?ܡH:_ m2gZ.i-&uk? l~#簓Ȣ^7Ttڧӥ 5 &ѸDK+0Wи1AMຑQ8 Y/@;9EY &d\B:L*ꃨ &ypl,JKmVx!;Tmu&VLciHՎ"TAMqiOTG\Z}`x3~Y=?}V{=Lv] &amfzQ&4n6vgˎᔳ~p繊sXt;ljBe."M&G[DAMqQMv\> lR&5XKԉ9?thJ$j FW0Ms Mhp3IJvJچV}I`lMQ:Z^@\%2dGTk " o&/*=\=,KD)vr, cЫ측U*UǴnRJlnVDm6ieUZڱS8\WiU%aҪQKh:5QW"4DT( e5[HcZС#ewgJ#QKCM =tE\uR`Q^¡;eԻ/py Ң,Lxps#dmeEk#4qY#uny ꃨ&up10z5XM1+4z9&~=f@R1 -8eK\B"MdKlqMYTwlZ˵Y MMU%g&p3.KXx"7%tlBKzf" JǙP&~=}3<2 *I\{,CǑsyu*M ۵n35N"%)4$-h P:W(вA hI\Q.è+v31q h6(bq5Ƀ [1 l{;C,kǬ NAW +&(@zn'g?*dH6AdC bÛ TYF--+%hǡQ*i6I/řn&ypeg? 2%նRqr0R;gͪ@n2?\7d5F^M1UvKt\  2!q1#^(3LgH̄bZq6ĝ!%38Iljp#Rp?2IsIn6q%ZmR lB&;H&p.f X-A HI\vU?ISlu–kʬ'^A0-D~6+0DIc[Qk,xpږ7꒲[6O;l AMq/D: b&/']p0 oV*ClGRRQ4t>S7)mbkвA ȳI\&k,Cw?gf>6)i^j쬿 ڷۀ}X.0Jg Nekm__>]8](T(!Gn䏻#{8U5+7NuϻSN IOeW_|'/YWsJh_|k  Ov[x4O^>{*IU9eq"~ҽчY%_^Dz19JKV}Zl߹Ss.խ=^{{(0y8c'KS~ͷň WOM8B:7+,?Frs}o~c(H|2{Ke _>rSfxR/Q.Mf&÷|Cq[O^>7g|ԪXržORs8WߜNdVm ג*W{QO( O[O$-t+}\^Q^ko|uGu/Be@{Dx k<ƅ/z=zM _>;Kzs Йһ{z+U+6aw:zBY?N]=~᳾{sYF_S\3d밮^FyգrDioB{H4pendstream endobj 6 0 obj 5982 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:19:20+02:00 2020-04-16T10:19:20+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000006305 00000 n 0000008044 00000 n 0000006246 00000 n 0000006087 00000 n 0000000015 00000 n 0000006067 00000 n 0000006370 00000 n 0000006470 00000 n 0000006411 00000 n 0000006440 00000 n 0000006550 00000 n 0000006623 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<7BDDAD546C1F243658B8A89AF3BCD87C><7BDDAD546C1F243658B8A89AF3BCD87C>] >> startxref 8167 %%EOF acm-6.0_20200416/doc/charts/europe/united-kingdom/0000755000000000000000000000000013260345311020037 5ustar rootrootacm-6.0_20200416/doc/charts/europe/united-kingdom/Stansted.pdf0000644000000000000000000001211313646045021022320 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xYے }Wz ];vٮ7Mg5==#w7$ElKpATl'uuXIӻ->.zY]OOB!OOo7 S*vz{xj{sYovFajlY6m.֏y^_֫nt^~_޼^ϻ_w9[}D-<=߭G2h#pu:rۣ_^OwwOz=>g9Dgzv z޾<~1=/v#ai}\88vziY8݄p:Vx0Qf*lMP0f2`L|7ȳO'FpY6mƧ;2s=N/4zOa@96z#e2xO.{k1LGp^CcmM\8}Gdq1{zd Uz'ӓs3 {,N_H~໋>7rHHO{*e Ó=9[UGXXK0VT&ԹH ,IKo JrX7;\d4ZD}ob;U6hR:ԙi,M%hs (ygؙ"a,&"AQ2 h*k QXMxP.FUQAMJyxԺ6'} c֠7NG+& h+h vfBT "<εYԙi,mdC;hs,)VCuyF; h4ZfMsjADGعxN{6~u^iV(pl &rI LRi\ATGܹLc&b)5L6.s+dN _m/h%*𣉯\8jĻI\A "ȣI\1qvIѓF mKRrV#/MrଥܸVD~4 ^4pm]lE fG`H8a!h-M*ф*k N5ħň *I\81 h%A{H_h= h4ZDU "?/uf0[t^9EsZ#bK1H8-+u"fب&rcl)5ň *HI\hB`oyF@2p\1 ,h&nUŪJ%~PI#jHV&zUKpZMbl\V> h0~I6K6)y̸pl&rc7EAMb,4a>ކ8Vl-T92|8*;ンv-ӳggd46{nǒ ? >}|{pp/.ٯVw=uHC=>;4^7{ͦ{gwi219O8GK2{p}I{|oV~0σo- 7푸 |A`VT|{ÿ}|ٰ$l&_0\J{zbc:~}Kakn}OGV9ЊH/Sia]p/@|: gWRܗIMo%9A9pA6^rgcE;;e8endstream endobj 6 0 obj 2597 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:34:27+02:00 2020-04-16T10:34:27+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000002920 00000 n 0000004659 00000 n 0000002861 00000 n 0000002702 00000 n 0000000015 00000 n 0000002682 00000 n 0000002985 00000 n 0000003085 00000 n 0000003026 00000 n 0000003055 00000 n 0000003165 00000 n 0000003238 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [] >> startxref 4782 %%EOF acm-6.0_20200416/doc/charts/europe/united-kingdom/Heathrow.pdf0000644000000000000000000001572213646045020022324 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream x[ݖ裡8g=$_ )k5-MvFcKMoY|b7ܭm" ϋ_m.-o7?ot.[boT/n7/]~x_Uȳ泗on,w^>^Nj_>t}7oPOBrz\p⧟novrs{'_X7o=,o~}pߗ˻\\|i{͇śOo_پ{][?o7ܒ[sˇ.tMDZs˝bS;9/)I]ճOˋg˿w=yͮ=pL ͍`~Clvd[%T`:*Nw5vE?96ʔuX i >>4wLO1m)mZY zǐ&zzd} 5wzZh >>S\؊A9F(KT8f>ffmLfEϦ.\Pvz֙zFF/lz>X],F/l¶B<>mRlz'C+MDHbj9REE //u*sAJ0C \}ȳJ^NV;s<&n%#_1]kϫn`Q;,T~iWT~أ?w׌Q)2ov*aR;c["W 3 #2+/*l@ª<ʯq> lrm!*cPbxi8 X.y$Fk_-83pLvWv&?xd'WK4'дTniq1?MJq_@x x Ǽ+ΓG9y~\ ~fޡzaHEfi*8,]: )rKkkL EyED)ݸv^e\X7>RmzdG硽'4 b<^[k/A2bpb/$PI[$mjǐ=JS\2);KK27Ǡ`Ʌ LyR2ysVy DhU6 oPx`BOۄ#MX b4'c ũ ;4I T>t6ax1,F(8zٞ~N#5~75$xc Y Ry/*J Qf2UI WX#-. 1 X*d\"*qpEHGUoKK1ksZx0NFp,wS9M]E~7f`\a!:Tr*<%ocNH|4q火TJ\@A#*ip:3瑢 8瞓ݦT^VFq*OG2/u`U`*YσrU(˼6'b_p 0c` Ytr4I<Fg"^(GrԿ(q^Qs)4)$CB CACx4 ~ioBsk(Ir!g}TN Fu$^\ h 6q,A6-kC_ZPmZ0Ue7̟sZ*?U|$0)aYb*:bG{q'6qX pb, o I 8DMm7:Zp# $GX1܃"y *8d뤢(MaEJG 3~V%R8ѡjrhGUs+0Am*lY*d\\DW2JA#*ip%e8qˍEҊ遫7X)zzE;JFHJ2.ơRJ mVik"TT4%NXGj.J*m4ZTf]%R}HJ\x![V_R(.1SEM(TiV h ȲN)BLCv:EV)IP+D:¤2ՔTA7fRcӧj֎:ԩlXRWQ>:Uv:lVf N8_ j:Ď764(cˊ8Uجf2.H VUTD:ʬR)8[Ru!tY% .Rg,SŮtNFŽDP. ԐEPYA DP~TG` eV)kTU,ri4Fb_K⫊\N A .ٍV_93Nfsɰ-è ,m^<gJN Z*4(;Yy?$BmNxZ`qUȥL⥳7:sA J&xO4-Ŕu : ow"$+aV %oHLv7JA#*yp!Tn!ayZu)Vpgh\"%*qpEHGUB'_{|C0 sLzX.^1ubsV]ȣtU|5*Z*(j)V ڑf4tY% .+5ÚAJ_D||W5YyV%R5nV:\ uV G&| \) 歊fXk}9JQU?놆hZ֑fT$K*9ɚƷ(y^):u g9*}7Ebx [m{ڡ'2NȼmݺK]^rCi7ϫV <>yM}>TOl}Wlls~u#"xr`ީֳp8j 6._M#^eiΞj=˴* +!M/ä_8E=0TY%|[WӼm2%[]˴ȴ筶LOøo|g5y.#<[+K;|u3B³a__Ogx(N6eOa+nԟq±|whT .:|3!NԚ/:&yΣ9|rj|?^YGGSl7 (vk5 J#ߜl>7\}, ٵm}@}xN5w7=_{ON%Ic/;iGFgʡSynQj2 8~]l>!Sn];tyL92y>|%endstream endobj 6 0 obj 4524 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:34:19+02:00 2020-04-16T10:34:19+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000004847 00000 n 0000006586 00000 n 0000004788 00000 n 0000004629 00000 n 0000000015 00000 n 0000004609 00000 n 0000004912 00000 n 0000005012 00000 n 0000004953 00000 n 0000004982 00000 n 0000005092 00000 n 0000005165 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<51CEE2BCD028147BF95DE169F5F12BEA><51CEE2BCD028147BF95DE169F5F12BEA>] >> startxref 6709 %%EOF acm-6.0_20200416/doc/charts/europe/united-kingdom/Manchester.pdf0000644000000000000000000001210513646045021022625 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xYr}z+MUyؕ˩XYK6hKt)_/#_jΠFI~Uz4J\Q}~<| Uyou(UF]/w˻᰹Wlv7mN8_7avY}9l^v< ͉a|\(~ $˗n>_ag٨j8ެxsX]oWWǻj>vn__ X|ZEZUZo-|(.(gn C샌v`b?9i.ުO; %v6^;7dGNOnpvӡha7p8WҚW!w-]&n1 9e&Om 2zSO{o!%%7Foy)Jx=4>FxϮwϼ9Ė7&NNcgC6% Cr"~I3@y "1&rٍc> =bt3וֹ3\Lo;ۙXZja>3]\LSf73yƺY{2n$xchaЄ 0f#qE h} 8ץȹ+8G#.w"[OGA%$,\,oV5I+ WDOZ1ޠMLYڋ}eFD̚c6O=8t`{Rd@ j\XG2YzV|DkyA@78Jw-Lh:9 \S<' U/0|JI `tvI~jgκUA#r;Is߼cA"j#2qj@&paL\rU'a&иGm\r Z%m13&pHu2 +[&aM|g:9]ƽ(lѷ-w@㜥H}X1>E .bl%6.+Zu$5.>%:átF:tu/sD^tbY\6Lgb/ee%-eihpas)Y5M #JEzP}!K(&!TPV^&aL_L_&O'8Ki@/XrMlb-ZG3эKVЛ@HS,D2id`)ܘzZl@8x`)ܓk\N$,ȽIc :>R~DNuiI4#Y)ݛ7иhIX`{۸KYUA#lrS(?{x3!cZdqC:L8i4:xCSks% z茣hȰuk:N*cJNöSe;J8j„56rIh bkRP! {BۛEZL|)+!e$4.bl1 N_,^CSQKG<"l ̜ν9X%A޷BȭyuR^<6}捦{slx7R$]Bn'lF3/r B_Ielpg] ޓޔk>}OwK^my}txnaō(?D;;Ss->[~WȆ7~orAa>s}0m9ZqÇνYm#qÏ$|džϥrޝi+Y1qendstream endobj 6 0 obj 2591 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:34:29+02:00 2020-04-16T10:34:29+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000002914 00000 n 0000004653 00000 n 0000002855 00000 n 0000002696 00000 n 0000000015 00000 n 0000002676 00000 n 0000002979 00000 n 0000003079 00000 n 0000003020 00000 n 0000003049 00000 n 0000003159 00000 n 0000003232 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<546AAA1AEE84288F8D799BF55430EC45><546AAA1AEE84288F8D799BF55430EC45>] >> startxref 4776 %%EOF acm-6.0_20200416/doc/charts/europe/united-kingdom/Gatwick.pdf0000644000000000000000000001353013646045020022127 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xZے7}W[xq>رkڮuqؓ+$_@3f_J!&A's{ڼJӻ+3["jz yazsR;yRӛ՗/nn7'O۟zQы՗o^ow7׻/7v_/?]\;ZO CGbnqprƙ&|؞pqyŻ/Lw~fӧf}ߜn6g7/oNWtus[տw+2L)()3VOaAL>BT*NP3e_I!xy6szlz3?~2x&"l2W~7NOo땇Mc ˌ{ 5 S"y"bg#^3 >Yjd]zo0ڴGYL||}p4{ޓ˱ >kag{G;裧-.Ǩ.$g gǼfT?QI oriEf; q*%*>#\ $dç hb+k ƹu.ZmhB=DkGğf`13:*𣉯\%ذj7qq1/uhB\::;gjuf5ŢF }O-3As&rc1T|c"MsI3FLJ>rh(EG_$h4Ėň *ф:LcFQdyo:GR, =UNmMIv9 h4Z,t.ZmѤtsTIJW-Ƨ7(:EE`6c?%Z-&si&Թάƒu<-ÕN)ڈgg8]5ezd!\wFب&r(k}6E&Թ8:$򊓆1; gx8ZjEGXX+rYQMp]Ry4ɝ ^4aALm6#f-O`IP+B$n$T.ډL3AX+WUQAMr}ӜݐhҜm\/=[u$!j,'`mP5jI0ЦjP WZl5*0\%؈j7AEPVDa4 ۮ-U96V2i3WLmb{fBT "MsK25lc懆Q9E'sBA_(vԋ !I/Ta K̓^j YT\^ "pIKּ C#+,S?퍬Y*pIT\S5#FĢZu$t.x3Xچa]nEn?X E Eіk_ h*k16nbrbZu$vsnַbIڨϳTzZaLI2 hWp=ΕT "2/5J52KqC16\|dab+.4GіT `F?L=r L_ArK,+ԁW>Q]I[a'H(T`R/ I\A "IKC,&ԖhqVNlc&bPM%\bQGEz\˖ziY7 }!؉lb; "pIK2!,́bSM(΂7Aب&r`/IU "MsK6l ( SQUF+TBIKD tjz-Mb4oj~D}c>XG8IQ$tйjADGܹLc8]9E_[s2N4^. Fz9e `j1gӹa_M_Ak,6,Б.GQY!(3?%Z&s%jF\RgL =CBX9E_+Tj`YQ{V.y8kLRj\jAT@ u.-3;IQOjDZ&r`I\F "p\\KN4+l?7=? 3~Pțӓ珧}Y3`?,r?AJD2o nڍ+w8T9_[so*4̡{_`ièKN8}gRC8 r0$v[мxnt9NoߜL{y5x^>}t >)[{z9M>y<;7ڱx4}\ЋKc(< ,t?0wo`!qD^##܁sX:hjbxK#_СEmmg){̅SobXKY'/>7]w NONϘӝo3I\{Hh6 dPjendstream endobj 6 0 obj 3378 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:34:24+02:00 2020-04-16T10:34:24+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000003701 00000 n 0000005440 00000 n 0000003642 00000 n 0000003483 00000 n 0000000015 00000 n 0000003463 00000 n 0000003766 00000 n 0000003866 00000 n 0000003807 00000 n 0000003836 00000 n 0000003946 00000 n 0000004019 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<7BB6D30B3BF934907AD679F1A6357E19><7BB6D30B3BF934907AD679F1A6357E19>] >> startxref 5563 %%EOF acm-6.0_20200416/doc/charts/europe/spain/0000755000000000000000000000000013260345311016233 5ustar rootrootacm-6.0_20200416/doc/charts/europe/spain/madrid-barajas.pdf0000644000000000000000000002137213646045020021576 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream x\ےq}߯7QaqP # ThKB( Z* ǙdU%#`Q䜮<]u~s}^]=x^o?\۫?_y7bj˻Oo~=z՟^}ؾO?_~/Dccxzɋ뛷7ݾ~sv8~~w^||o޽ǻ7ݻ7տK4ʮV\j~q^*8"vg]1B eWGۿn~bRo.+a_{Z;A|}w{'&=eɥ>^age}a_F_|Z=﫯u_F_}?ԝ{Z h+rڋGaozӷr+[Cix1}(e!GT^LS>j3zSȇЇ#eב^L]Qy;U)~ iOMCl׺*^ 9LjAb\%1x؋uS$tI a"wVfa-j7GL$]P)Xl\%|g'a|ĖE}*>hѢ}KnϢ I^WѻJt-n~)p\TI\\ Vs}"n:`N?bY!X;O'g=[ 1qg'U+_3bդ.R,C^U\\jv.)Cg ܠoNS\pKAոX{GŮ{Q E!ю~MC'csBwQxiTt}Z&mpph:M@WsOqy \`h2t4?i`|=/9> S?NHɮ?Džu p!VvbdG^/_$#ڵ3/Jup'VvvnO:NEAy#k.>jb pIe}5<>O$˾GZ ϫUhdU=1N];ɮmoqu;I%ǎ U[g=X}5DO"KKt<<$.9EOO_ l~=ص``vWb* !]K ӍsD3@pd2T 8!]O:qY'դ\34$np^:朑pОvf_Q:g{_{ZK]H-mC%ؓB(tVfBNl1D(Q,mFPH|Qx`5i .k&yrerN I߹5Rw?;׈V+B^+hayuWF&49O̿(ӒaP'^#>4ܚNd cj5K~K-5kђLJA]M-\:LjePpdsaw?{K.>īCuV8}$NM2yxsIUrU7%b/X;tr p'Vv>N'ɸ j45 H9Xu:kۉݮS 'yQgQ߁QΚt# Cv7'sET{b &}ƨ+g0M7Nka*:' ߘs7>aR>u0=̻=9慮n:/j 7G6/R1$: hA<¤V`2)5gԬ9.XT5`S%!XX*r4E=O[D3*\j$$j01\;33 uNL\ j˛Ii'W%.IC`A;x@)Y9-XT&#zC AeQ/E _!5!T%ҩWID S8 1k2HJF,(ȫI6.\Zj'PLJ0A 7QF6ňZ׸0MV`\P&~ryjN HI\TXƁ%N 䄶D>7]+wXj}#W ?];ď1`MVd\,5Z"ղN(hI\R %ZP0FK: AZMqc$H jR&x;c,үfV$re{1]DX46AZMqbirZ m5iV5RP.Ψ@,D1A\Mqb<:L4^ⓟPW<2c)ohIc?Ǽ._}'b?pcLYpD⇄ a&θw=Tw8"F'$M[")>H29i [D:ki&͸8!a&ir%[HNf 1q蝎9-(ș̝t\a sE JR…$ZAa &T aOZ"ղN((I\yy9JnmMVg\6Gj\!.ci5IK"_u&i{5 K0ZWTJ$֙3 j Zx]&erjN I\6G,Qg _=rVaYn2̤-ϭ0&uٔT:N)٩ePW>Kc -4#+ sn0UHnvf֫ ȫI6.dЎ2si'WužI\*نz,\ jRmLbfɕ5:&}rmIJb⤋#VWtccXRCLBdDywJua &ɸT !Oy1:&mrimڳs 5Ј JDBL @W8$2pԥɨ+V"-E̻{℞Eގ:D:H&(I1.Suh9D.IϵdsWNHxE"hh=դFjsB:Mɥ32 샞usLAbwk_IxW\_Lxaˊ$O. q5׹N^mr#H2/ט9/y<'Dz,X\:Y$Լ ,Vki@,ԋmj뮤TQ^8;.$ #W$ctaH[MqpmVP˕u i5I+![*gՖrd` MVd\ѻ5:&er^ٝ1a{7NIg0jcx,f7WRřSTv:WRcXs&arjN ȫI X<fnUC{h$1K/k0K^>&mri~8\Tth!_Hs8R-4 o a5 jK;~CQ'@]nHa.JZp%bǑ$crC_M|4ѓG⑤ y5m? Zwj[sݤǒNT`dŷP}`<颗.A#fAѤBNfF j:v8bY#OA^Mr۳M ZmzL 7n{vjA^MqA gI\ZjR'׈Lr\pΚPV4tS;Am[}K!X_LZvc! rɥw=~+~gIWX<ϕH2.p%u1E0gN\X;q8LlF8޺Xw6Ilz j Zyjc6juBA]MX9x78; L/]3~̓7#ԧ?msA;Ԇ Q[3 ȡOԽ3< ~={*=ӳ?~A 4~/sP8'eAj9ID'[iĽs͗{uiiv`\{;彳?w"$Z={IA =#qJ'kC=՗ʑwŻ%zRÙw/.SaD\V8rmȿ$%9c,4~z6#ǰi0~RqK0nۗO-ݜoGGBIΜm,'D,X?9&IN zD*~拼 zzUFroOCک3-_4yax5_R<`ݾ~|~֩zԩp"䩝kȥhW/OZh3ԥ9|Y|q`ʋu:`>7?cٽzw`EOGΜm,/F{'s75h'Ib>}\ح5cg5_e)W^ϟj{2U?ߞt?@\Ntk̛s m{/C{I>za5bzP6>Cg~bgA>3:(qle.߄G7O_Sv4O!}?߽9|ϴD[{zο~Ͽw2IG}?gOd> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:34:02+02:00 2020-04-16T10:34:02+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000006679 00000 n 0000008418 00000 n 0000006620 00000 n 0000006461 00000 n 0000000015 00000 n 0000006441 00000 n 0000006744 00000 n 0000006844 00000 n 0000006785 00000 n 0000006814 00000 n 0000006924 00000 n 0000006997 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<5365C7E13B08961C32241B7A87047183><5365C7E13B08961C32241B7A87047183>] >> startxref 8541 %%EOF acm-6.0_20200416/doc/charts/europe/spain/barcelona-elprat.pdf0000644000000000000000000001261613646045020022151 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xYr7)p]4~]v[K{IД%S6y?YqtFјb䌥^,Ox±ڜB1.˅8z޼ޚ.v7'O<=U-#jln.f/nֻ7添ϛ狫i?g w}w'.vχ[o%y{j{y^}3W׿m/vwߛ|>?_.~:]o/6nb}pf{{aޚ;s}{' Eٚ5X5w%E+EDqZVQmK8}¥ _R')8#'7yfѤЄTtƏe ,nBt:) ̾9O2?(DM)o;z=N8ziw!=@ GMqOBg|}iF8ݔO1tzѧzykKr"~F#$zȑ;"wJhvq5zG{W~=϶O_H>rTz7=Mbϼ*ZZ"x4}0"OqgYqZz|@T0, YBq^$},KPM>.3VC*b8ye?\"*Gu'|"z0%}vw&-R>¾UXAj #cN ,0"-V+ڸ"2Eq Fρ7hkV0&^Xnb;6 h:z)QXq64-VIpd%mEIBD.j9dV&sꃐ@W=t35 'DOJ &YHMl粢aAMj˓I,CB4N֦]v ve%O*U."lnjbK"DZ:h:%u+Yl|m/ehUG<̌$2ADPGڹ.%oN2R'Mu|{Nd "":Eb-Af:W6 `4{U05f4$IP.bt|ʒm$u.nKh{>'(R:o<_j"(^au.C@WeKS%KoI[0bW%:,H@~4EZ4CĖEt$u.|3m8  ̡dhRΕD BuEL_DIcOiUP('kcL;oTp&.!x ?+p=P&\ů9&sj &sE=1zN^ Asޚ"vxtCi78"- Ls샰F\<IJ4 {8D oݿb9(OR=v4$N?X7! &/yUb.O΄WF3m$+k7 +Vu4 'X2.%>Bd՞,yy65ZFPYλڸ 9/<9O%)ksyKֱVUF\XΕt ,:WyeistN6iP7PazޏʎuS7K g^Ə7Yɦo}b_tԵZxwιNOؾμ;xaؑer3Nѻ̜;t8S4.bΘtY&\Co1sN>Cs*} 'g[= yLendstream endobj 6 0 obj 2920 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:34:05+02:00 2020-04-16T10:34:05+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000003243 00000 n 0000004982 00000 n 0000003184 00000 n 0000003025 00000 n 0000000015 00000 n 0000003005 00000 n 0000003308 00000 n 0000003408 00000 n 0000003349 00000 n 0000003378 00000 n 0000003488 00000 n 0000003561 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<1BDA197517F3DE9CB67AD528A87E2C5D><1BDA197517F3DE9CB67AD528A87E2C5D>] >> startxref 5105 %%EOF acm-6.0_20200416/doc/charts/europe/spain/malaga.pdf0000644000000000000000000001121513646045020020152 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xXr7}W-vzqU>(kfR%/~ahRbe)%*ѥtA4j?ḭPjAS7^l~j-oӫO->tlfWjݭ/0/i~4_xxXϟQjIz?z<춫Bmvۻz-ǿZ]Ϗa{/W<;9MAplD{]Hg5.'Zu5.L]R I->l.blo\^ ,pk\efK[1h\u p6FS{w肓0:[?;SFi.`@L&`tTo\^ ,׆vrF5vڰG{Q7i`h: \oz)3XB`#d_9DI) NvB6/%7G"I(\Mil.\HK _L_\xY0!p8)(eRgRnDqZMb̏@/&/iDxV2q6|W`iK!s#!bJ.b,]f4эKV7ɍ/޳7mskg ZM"ݛ175.q7 I,Cb/mK嬇NЧIkgeQ+dR"L20C‰QlC0fms?ʱ!`ų'yGOgB~?zFI8s$gX?_]*>.u2vZ-NM^IN:xZpY^^>->\u S#6S= oscyyv >VDc\-BDޅ W|_f3Խa,!^>q~EFendstream endobj 6 0 obj 2151 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:34:13+02:00 2020-04-16T10:34:13+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000002474 00000 n 0000004213 00000 n 0000002415 00000 n 0000002256 00000 n 0000000015 00000 n 0000002236 00000 n 0000002539 00000 n 0000002639 00000 n 0000002580 00000 n 0000002609 00000 n 0000002719 00000 n 0000002792 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<63F395DFB253800F63577C555BDD1E12><63F395DFB253800F63577C555BDD1E12>] >> startxref 4336 %%EOF acm-6.0_20200416/doc/charts/europe/spain/palmademallorca.pdf0000644000000000000000000001250613646045020022052 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xYr7}W-vzqu>ȗJ^Ф)SNU`$VcǙ3FO1`9,x°P栞]BRƩBlb6xv?ՇX7z˷g~|k6Gţf{Cۧj/n7ǻ7ۻۛpj&}zxb}ܪ/*~Hvjju:{~v~}nէׯnp{3\afat'+-SqwvugƬ义s0X~*Lphfϥ7 , k(I"-Ƹݢj3 ‚ܛ䑋W @l! KD4-<ͣ-ocs͔3t D^}Ɓ08m#M .Q-hbkpVS R[J'ZX߫Sh$2l9 ǚ l&_G,+y_Jtw| gQv3E`rF7cB6.+Zu$4.lԲUox j\ۛEZ5&qѪ&qPf'4vF@-(#h|yc s@|) J *T!.bU [jAD`; K!1;]C,\n m􂄒71Ī$E "nQf&tcwe}ۅl)6kCWq)kA)&MDnR"26*!ʨ2 db⼏&B\"1 N9jNbܙ ъYu4 W71 I,cXf{ydmj?C2q=_Ȃ"0)\EYj DߛƵ5I`ck@!pEz5s 6߸hAXzԸKc* řD 'kSGl<\B,9)!, Z*H$ n셋iAD{ظJ[jpJh6E`zSj6ݦ4YFЛ@w$cPcm4mpF)*8@Lư`--\ "Mqh7~6l|%.!XyefĽ@z Mpc]o\^ ,o\Dɔ`ÐJh[jSRvy<=@E$AGEzWHn&qiѪ &qac%;.xS rP Du,4-Fjb%q{)3XNP9yG+sƘ!LIdNz4*"/\E8I)&x&)\HK)ܛƅ7', m&DA,{`.4$6. ,Il\eK‰J.f>%󙵓Ro%A\96E`zSP|11ˈV7(wk<N%ץ։>$hIs$.bz5 K>ӴAX{ܸηXR D_#pVS[V;)0XKW*Һw7cFG28uw"4qyyNw>㞜|4SN>v 8z5<59f<ϥ޵g||عK޼xyϫ?'`d&ޜ|endstream endobj 6 0 obj 2848 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:34:09+02:00 2020-04-16T10:34:09+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000003171 00000 n 0000004910 00000 n 0000003112 00000 n 0000002953 00000 n 0000000015 00000 n 0000002933 00000 n 0000003236 00000 n 0000003336 00000 n 0000003277 00000 n 0000003306 00000 n 0000003416 00000 n 0000003489 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<93F2A1D86B04A475D7635DEA35680864><93F2A1D86B04A475D7635DEA35680864>] >> startxref 5033 %%EOF acm-6.0_20200416/doc/charts/europe/germany/0000755000000000000000000000000013260345311016563 5ustar rootrootacm-6.0_20200416/doc/charts/europe/germany/munich.pdf0000644000000000000000000001425513646045017020560 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xZn7}$>8kyKyV#[rd7;[ufNrNE_&3wߜӻO3Ng"20]lN>NjE@,^m>~nnvϧy>y}tݧݯwgv͏y5[./6__?-{|rƙg&~^t{w7ӧw׏>vǏ>ϷgwôjM4L9D3bdp>S=.DGHT3QW1Dg1ntlsB ^뗍'?T=;=8}xr N`v_CQxov qJexPLbzͯfJ1%>f?No!˩Frx=Oϱӻ'އR>>2N|}~OO57OLZЯ&j63ҴSr&~=P\"w Nnx20#)?Ε٭WostZFӸ4v'5kV~ϔ7Ѣ?rd~q=4ݸlI N|5%9VI[]'Ļ؂\Z71'.8`hvM3*Ug@:iL"-M% ZK:XD: 3N]?w ރũ-m[$; lu#Rs3[C Ovu \2i5 #&ri~+26` " l "bN$5.Ni&sj@Gp&-~2&qSkKu=1->qQ}#~|v4սAVj>W]YrhKkVFԸX ~u.'\h.'p{z zO"qЏnrVχz0@Gs78c/&s9j@FйKy3ejE7͡8M3(MvHO+/#ZC &A ߻Iki'"(I\{#Ǿaڏ%$0AђĒѣIR.h;{5qˉV2u( ;^iiڔsIh;LIGg!{A[p"6"IT.b+"M|m\v":΅/0'zy/h9}y*QMr!%̈́ bNDFйKIJ4LKZ?#cU ;)W4^%-# ,3㜠&(kI'*I\7tZ( lТA6OzBOaGzXLARTw",~Ky3iXt Mצ4[bED3WtK8&`DX)iND7~`i7J;~r%eo&s%m.%^i0^aD8CmJ)k0v߹hN HI\7|4^1fU:0rΈ hfbJ:(&sael*Yhk1OKHK%J],iNRd4 UL\LB :&,OelP @ULJ~䈞e=AMpti&s9j@PFҹKy3ejȔ+530D`0AHA'A|y$6"U.P]LL2: &su,*,\CId4̥7[|Rt>Ѩc4~ &W)䵛GO07K y2"VF6!%ŌI${x~z/^43]|*drGFʡͧ9d܌ ٪COP-rhIgcE4]1FKyHu\t?LhӚqMC9Xi$M2 /^<ŧz苜OyXiS,+jKIdpf ͧE&w66o.&>FOh3h_I>..cCk7ROOa_t_Eο`!ӊ/Q7cͧ WTh9i=rW6ŵbRPm>m iͻV[K^ӕ߾Ոk>ma& ܻ\͑=\e;|ZU|c@5RhX^endstream endobj 6 0 obj 3719 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:33:50+02:00 2020-04-16T10:33:50+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000004042 00000 n 0000005781 00000 n 0000003983 00000 n 0000003824 00000 n 0000000015 00000 n 0000003804 00000 n 0000004107 00000 n 0000004207 00000 n 0000004148 00000 n 0000004177 00000 n 0000004287 00000 n 0000004360 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<850F22150F15822570D54B23F74F52F3><850F22150F15822570D54B23F74F52F3>] >> startxref 5904 %%EOF acm-6.0_20200416/doc/charts/europe/germany/frankfurt.pdf0000644000000000000000000001621513646045017021275 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream x[ےE}ȷa̖_0@hV0vyif[Hiou?#2fgkQ'OxzFxxD~oN7 xp7/Em>m/o/h㷘'O__oWoTwPgy{gp)_o?\ۛ77\pMyq}?\|fo~l .O]}Owmv{Wۇo~߶77۫>W7?wx}yuw޽v?%?^dWVSv[nn+mo.n5t%:-qEcQn{cڝx_q⟼,*Z^~ۧ[8+q%= (~ң:}a MqC#ۖi҇&=y!>?؊ϣ2msO)MzS*+#seG?Iy_rї\V#[YJM(y#Wglv}nx6}u%?=2|<#1;1f&O8Z ϧoW#s.i$Ag$8=tf B%aJPM$2oDlaSD^tUBS"yF )"9驡 IrzBCKxu& 7Jtc][R_Dt-pH /KKRi&WldZ&}HO>Q#. evx%O}#pmm EC~O~ʫYI?})On×'?(N-1Ң8FȆ1b+G&K:Le@VsEObEyR^ RX5Pv]WE}(R~]kYQGeu8Rh1un4t3ESZa, 4F#$\'pYkSE߼D]|NIЏ'g}K鏅7HwU~ okb$PyWJqO\eȋs,rpD6e&ç6kYdjj hHn7. ѲF(ȫI޹^Ow?&$)Ow(4RP'it1i?֑Z?Y.6y {V$g<Կ{P(.8“LA-V@ Nq2cS %),?/5(EԒPxpRnI 8+̳Yra/CP^ T$Lو ؼLe}F5]RXiBFY&L<&HI2.ӤNJe5) tg8Jߐ$<L׻&L25kդjPN7F#*`f2BtכB`<^- S4mj|(hI3.h#껉\ZEMec >/'%kqc?4(HdE V #y5ƥZ!$NH}5 >³v%eD؉!HI2.h)x5&er^ؓ1e`Mc2M)CXcXJZ5@~ jK;0 upy5ɓ IVWIE]+!6դF^؁$PV6=aਓ6A&0ʨ)3*`%3y]&` 3DL.F~6BA\Mb#oyс)L!^@:L!tiڡ:MZ\T &arچ,H݆%v5r-="eݴD>0B_"oɥeE\yeDDG!HI2.h{qeke5)"?bFq# <ЕeF )ؑt+)HI2.PM@V6K,F0:ubU@Vd\BFw?ZGGZZ^8j)}6ϳ b2bˎqe0Bfqsnj;m 𫉟\['&snj^F(I\K? 5=ny^DlPRl,E봼6bCAYMqa#FUf"+.R-6B7殮#Ṵ9]JYp6lIf"+&ŸDrUl%1a`)k_qV|u`Ƞ $%6,:Nw6K q5-\EMZWePPW:ʾhCRAs1rRi5Iˆ#0Sn'h%^m1#I\ dE/0py֕T*[M] c)am8RB]w*Bs*[Hjc ! :g:HS=dI~WpfyԔ6ҿa΋>R_K,s*%&0a\6FLPVԧ[bf5`l6&e5v0qQk4A[M/deg N,Jk30&f*׉Hr)7.h)Na&qrEjF ȫI\LQOǒ0?>fLl;2Ca5 -`v2 F#$M.|\bsty% a-{9n3v$D[FMeH'nښ &T 8bKl7 +Pk4AYMTMRЉ Cck'$\1(Џ /i3;O289F ~Zb;ȶ>`CʄPwւ޲MuU;.,PV`\\Y RW|4BAYM=h( 3&Q.`$vFljH j&|2= -#"FKìe~N|7ǩ| 8&f-ɅqoDlL_z~&)I 'O(LY Q B^Djc3r7 +@k6s&/x'c,| t88.72ġ>!N]))v[(HI2.vYI냫ujY#դM.R7X2űܮE"c jR Z:u}  \T&}riUX)BXM}m󹶑 3i\A-KEZf&lI{7 +Pk4A]Mj[Þ:4lU_!s\PM.y3~qd%1MRlmk, sK ZCה1AYM9&arqm66o&/:<6=Y :2^I۝߽;=y<ݞdk;qiB#|m=bLw9&б3nL*ok > Zty>UU2HO(H} kveO>/˶t5V?zd۞|y@\ءSs(IftG'< vvA=3փn< { 'wu瓷_[w'H(9u> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:33:47+02:00 2020-04-16T10:33:47+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000005034 00000 n 0000006773 00000 n 0000004975 00000 n 0000004816 00000 n 0000000015 00000 n 0000004796 00000 n 0000005099 00000 n 0000005199 00000 n 0000005140 00000 n 0000005169 00000 n 0000005279 00000 n 0000005352 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [] >> startxref 6896 %%EOF acm-6.0_20200416/doc/charts/europe/germany/dusseldorf.pdf0000644000000000000000000001317513646045017021447 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xZے7}Л툥ZC˰q008oRf:}2(+%e ^_gneͻէ6:ȆGHǏ/W4ջswuyyn˗/rf:/77_>o.N{57 YCnm&hM,$kv}0>;.XEGPT5׊3gO:_ɼqZ"3rҼynn^>77K "lXVѣzrl><݄tR]!P3WC3dLO>Q5&|0ř!N4@xCMi1”fާ:=SL_xo+.?%'G4B(!܇< V Qx/ݬQ:ڸLr)EHĘuܷ0܇YО9$B;Er$;m%#MԬԹX 9ڳ5;5$ ܮCf }u:s!HU]><>"&=-S>Qؿ0,cD8b k7gT ڠWqT`G\Ev߹hAXFйvi-T9P PFθ h╋Īv.+Zm$v<$a Z$(/[`qbbm)s@| k*jukj?x"-!p(\^ ,ȣI\Jg N"!-3"eh(l&s%j&sdK>ғ2Nkcɸ3c8cb7&[&S{NEb78"-XR8$Et$u +5^ W ^88x dN(6*C!:V~4 (I,SèO׍1c2&Xv0km/%Q ,HIR."LMp)!AX7=8{p`r5 R JD.h &sq^!"&/R$t c6Nloڊ%>B"Be0 -nB.|Dn0~>LGV,Ѓ d(@q4ZmIR۹hAXGܹv+24,9&k&_ԁM=,DF\ZVm&6.B@WclJF1IE+)6WM!$𣉟 v۹hAXGعK5\䩜ن$F[,Gn[}Ye &I8p4ۨI\A %#c,mt!C?b4UW%6LBw^ڏU:`0~ich,N- )6HβQi4IuMM| ! &/~&ԞY~&Uh4,X dӶt,(^a\. EGaL_s5a*g[ 2cŎeO2B?LQAMra$jj"DZ:hR;ǧI`5E{hTGbe &YXf:6 hR;}[s,}xUlW7(^Zm tἠ j4"U.b\8u4ňd$tZKr "fǙX0r0fnK"^ "\bIT~^!5*ybX1D F#f<1JUG\V'W* %5"<΅]qs|:,-6^9"Slea4 EZ%t\ Zm$uJ$, cʡ(bUN]kUa)x8+*=WXvUQ$t Zq:|35D}.HQAp#: E0 h[Yw./Zm$u.:i9аXr6yJʛ)-"iWɌ0ZEʥ h-b7ɥq"-<|3~3ez Lp;dnH Bl,`*k1T3s"-Dn4qk(I,)eOƺ*'ي-QI2xzvvnk_ӗKwfG阷;_бBy%pӼߜg{O^}'~?m?Eٻhkc={|IƞͻW0{&^[IY:'k}͘z}UJ)N8 >m>1b|;u˜WgOf?p*&ro>ydٓ{7zs_񦧊ό7W/s-;sK>͡HKu'^@Cx\*r߽cLVn uw:_/^a2xq~AKT,nwiσw|%0|AuutbcJH''2oc !?endstream endobj 6 0 obj 3159 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:33:54+02:00 2020-04-16T10:33:54+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000003482 00000 n 0000005221 00000 n 0000003423 00000 n 0000003264 00000 n 0000000015 00000 n 0000003244 00000 n 0000003547 00000 n 0000003647 00000 n 0000003588 00000 n 0000003617 00000 n 0000003727 00000 n 0000003800 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<9BBBDCB4B600BF28CAFAF2C49549EE88><9BBBDCB4B600BF28CAFAF2C49549EE88>] >> startxref 5344 %%EOF acm-6.0_20200416/doc/charts/europe/france/0000755000000000000000000000000013260345311016357 5ustar rootrootacm-6.0_20200416/doc/charts/europe/france/lebourget.pdf0000644000000000000000000001351313646045017021055 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xZr}W*k9` *JqD&~!@ e.*M~'ݧ{f ,v df;٫<2ӛ/+ )Ɇj;8j՗?\|zL~yg0 ՗ͻofy:wϛÇm>m~{9_[o?Lr}5/V_~wxtrƙ'&M1|1e涙2LɁOcaO.N|e/C4z_~9%F|}(eN ;vzc#M57OLZ mNퟒ3nqL>M"s96}0;oL\HFzmN_H^S>ތ'{7ѤFx2}4a>G+gsH )Ej3҈e.JDᮩI$kN_ɨ9j$ڴMfo}{MYW5 a,8C'{_[;z ?4VxH6F ט%\ъB D6}Z֩PRPkEd 6yYw|w28eS;-}K$`y)CicH Rws2zQtxIl]_zitn>TZȥ%}T"<EwH6cE$4$>ŏpYLvdL5`Z7ht />i/G@kTR)kf‘.F &smf"/8ϑψ2!pS.h1&XE5AMBb{x 9M&E?rŶ%h$QO eT/1 *W.JMlj\XKAMrrg phN G|DF\bQ&s9j@FйKƒ)lݩt&PNhS䳧傋m"|ZiD~dcRL!@K0U\NZ#w.{Ib#ATA!"fZohYLA fJby&/x)=XynlnЦ8rbg'xOJZVD &AX 6R#FDPFҹG Ex s  h Z-x1ˊVk:^%i6N'9OE6ʉy8tPi8 "?R@5VMrCXLl>F ȣI\3,kha0cEe|5XBFԹK26LK.4N+9O-.X3JT!YAk E[a4 -6@eD5AMJyyjL*t3WX:8DLL2 &smW3Ē bWe8M9ox+J0 1$2D'Q,nRJIw.S6y,H!ȃ5FѤ(fe1ˋVkҼt3Eɤy(mbK/E/R C8 P{AM#,*HIR.NP]Lb犢a4&/Fl8qzڲL{&Af>I)Iٛ*2"HIm)Ie'y5~-}j^6mc]gCRhQo 3$c{ 0dqVUTF\b쬤{3Kro2E3H f/F,/(t, h┋#Jb;Wa4 gHbI,dPL4е)M#sd gIJ >[yLif:Vo7tMM`DeV1өJ5VΕE5AM]*LcɘVCIoiETa58 S+K C|#Y)8Db-,fbJ2EѤv.yՁ-c[l<_s hR Z張%=@W]yejS_(CGy*f{9i{(#o RZ·roѐ"pIK*sa, .6/ ̂P}`YI,si#"\-[,{=XqVYmQ )5,EvuQv4ʵ^)D5AMbyl3IQ,.wEI1@q4ZZ:\Rmz#$w.Rz&t {K?qjmbʷ%pfhb]T,[n—%$v-qr TTeTMrA _L| &sk,]8Ad;'/+ a%pTvw4.3[΋l?sS*ciS8:n2/{.}}wt & g..ޅbxsݱקyӌѷzozFݞoG_[]nf׼;g.ȽWȖX Ff=2wG{b>vP1͜2:xIzkg\ ]Mӿl}:4R/݋ˣNřhy3FFok|i9KJ4dKDTH # ~w)qؿ#S~G_6zygp/lfj  -Nmw3\Bq _~< m> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:33:39+02:00 2020-04-16T10:33:39+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000003688 00000 n 0000005427 00000 n 0000003629 00000 n 0000003470 00000 n 0000000015 00000 n 0000003450 00000 n 0000003753 00000 n 0000003853 00000 n 0000003794 00000 n 0000003823 00000 n 0000003933 00000 n 0000004006 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<632528F4699ACA74DDB968AC597E7198><632528F4699ACA74DDB968AC597E7198>] >> startxref 5550 %%EOF acm-6.0_20200416/doc/charts/europe/france/france-ne.pdf0000644000000000000000000003242713646045017020730 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream x}ے%q{EY8(ERːHZ=ҭi(wN(MۛODz4k ,݇xݫO ]dM`rӝt}//o?w_/{wŷoUjj'=˛o髯7o}?˛^oWO|x=~X'|͟~vB ? 姱!ソ|Ww_xͷ7o|?{W|ś?}W^}՟_?=|O|{o<,z牢:} 7wO0͚]ZvͲ#ܿuMkt2)x=};ղq|{/zl{a6>ێJ_U{fZï{JKح"1DJ~(|>OZmy*qMznT H⟢Xȳ?\) ofO?I_Lxȓ>|x3} EkKhBP G1-`Qutj䇙̶k9UkGV;*iQrDN, ܍jx(llƹg:saV1ߖi1B1@c$IL#F:코c=#"r)F(xޜ)-1[!:^PztcJT<w_B;yDY)0C³.:*GX:)]&KVW]Tƥ?V&&܃0dg:SDI` o 4R ]v2,}{mM:"Q !0ZJ%t>"B"<kMF2 , t)?yfYpfG+tb_<ZzVX3 50)NquijI1tYA`JLMKv2fcXP:0ATYJ貓/fSYg?þ3#nN2Ѻ˜D=q\2L xiʃ96F_l?;x6ߌ֋xFUsA*jmKż+d 8>m f0Zw󑫐1xviWIE)`k\&z$5 aFUz ?'T{Ȁ9xax7V182~>rc*$yF*F<ɔYHoB[ (c*cq=P? TljKG?= E<;|hJs.JӈJX\ARf]e,;22't>9[`=¡Sn![Ϧk=HAȬUfFUsQ k27ۇpN0 o5 谍g]8#DO^3ڮRV-+Iϰ.5U-gvS`Xb(3IRđũ{QSYc#D6ri?#ָـM?Rām}1,^2⦲Z-Ġłenv.;>62z"KSסTM]%c\YK8vcq=Kj܇)4F)l,yWw2->U\}H QFUB-i6(j'ĹOf!ȻJ^\O̙"j?p ~c񌺫TzgO׮Bwܖ𘱬`<8ےƂܬU) .E%M\ ygryGعI#XZcN&x0x,I"N[dId0V,or?$:-AqtZ_X(r󨴘g]8ũIy!X\6Bue]W~,rfr 3lv\w%R B6Q>~0?#n.MDɅ,4OrMzLXGlzxsF4L䰉gae%g Lr&M<-e/86bCj%=Baṷ%uDgiWIrn=UJi=*mqYͬ̉elҟC#="T9fUsQp scrA a*^lG9^GϴViIk'kCFzt!L4!􌾩GqTJ CŻʪvf겊Qx#A2ĉ0*lw\tuzTɋK*uW Se8Pj(9A<L=R'J\v2y+B=N 7o'x; a5aW )Tɋ+KjŒe~@g [vD\=bGg䰉g`ϷdiHNxZ,6Vad01Ȃd}t`k]z- \*q̥e]:/CKe \*cW9L=0L}ꡥVav) gysm#XHNxZ,:2͗'v2mROp0 >šFs*.hY>ƔQv\"|pɹf!X\fpU+nkv: 8e;Ėx,Lr)"mEG||lk(1Ѓ<!xױ~* ݧ|<Ϻ ª`9xOwVRI䴉'gZm;x8NArbyӓjkJ!IZ|XRk]I!8gJ/BqMK {S>pN>6x`߆=}-7>3 e$&5h7V7,/`?H}t;9&^j׸%9Vr[m$ӵ+#*32EORie],^IFPà3®qŗCT)Kϲ aFU޵۲Nl6arV|) n ??Xw&"33Ү RęW,mWikz:.Xv~g rv\.jJ_\2ҮRO&[qνqKLElv\K8K lQv`<4Rre/lT)iFe]%:Gɤcrq:BwO[։ f#%|wvZv3zUӌv\ns-0Jyg],.y|1GT'nnt ɦnyd]%8D/,O .B!#VFUsAxhk16f!ʨJ]\VK=l&6yJ /~fLs:3D~hiM)Tm:4RAzŅq$N5,y _SU2RR<־Str2R ^*}quIBwl9&68ɥLΡĂS].2%uG;0+BuA˥U3,V{&<ٟ1qT4Ve]%9m UI&S,BU3ҦŐ`J w18xLzāw\ES%/,Y3RRO |휫HEbQ9;41}`|*qLıS%-.B\0*u\68|ݷIM^Ke]:6RIҘ QFUL{%0}o`^_P?.n8I kK"x׫Ԕ^6<&CXvÏGAvY*`!V -蕢.moBSAmo@.0Y8#XHX,8t`1zyaBCl jY$)]SFUsAXT)Hj *^׈Eo'n! Q&SãON8(~T"`TЋY3⦲`qڲOl FZY0! tet;\#UC(Jq.HCf*|Y8 QUw˛k,gfV*Sax'8|;jTxU'grb1c02_8V.`?'ai u?ds "qsͽi΍臢dO a^TVX氍 6._0 㱍 b+7X[|S@|Lwhîj9fvgψJ- {#]*<)N.?B> QFU85֐p*ZL7+ihxZS(B7U/&Ӗqb]`3y/"pC$k+'3~j_GeW))4*yqeIB1vt"LjGŻi״v\R!z%5 aFUm8)Ĵ8#Y c`]\u ;BxBmQw\"~NUR\Ceʱ|m.& sMm!Z@䰯|iҚ+_f]..Ӗy†q9o#fO~pS3=)Xˡ6f]8Rɋ+KjŒŘ~뒪m"m4E˧&>Ģ̌eL2YD-.E0n>N߱5VrU#4XѴ39Fa.hde HyGr)ގzxť fMeՋh)nJQ7bxkUvYA})Nympv+ϋ3ΰиts4`6S(4DӃ8M_^O./BSM}KaY8̸ލ<* עWu| Ĥ,H"I!-S%,. gKZv-"Tԡ4炔pR;UJ0c*cqY's[*J 3|^/[?HWpxu_qNb8IgN/WBQvbK+aoǐ-.\_k1JmWi{È|=W~εB1v͖<<|T,gFr@e %T*Qb+9Q< ĩ&O3uEqQ^ _]vmWiEq 뢸!)/DcW y:dtaaj!]wǚԨ}r]YBѦg]8 |\Tqi QUBKԖ%6s|SiyW.J)wqeI]h]..nOgHerchG!6/ p|e]:eS,"Y3]X\Ow8/DԵUϛH2ylY [88Yipr 8͗' Z"ÊQ爈VEB Af<*lc6\[CҞ*DyWɋ ,` u`}WLwJ~O&^i%& }~4_s,g>GW䁌{?VPhFA3(419+TI+IjŒŅMB,/׮Pa.ux͢rj_3RR#Ru T<*XqJ^\YRf]..X~ tlLJӌ[lWi}~TIo30c*cq!:ljұ&LHVԛKVg]%vgd%e򱫴_xGz wт)XIYKj)-f]%;$N aFUx9mY&f$n8[ҟ>N3ռlr/!C}2dm꣗qd  +OIu?.kx-9mUngf8@uY3AMƻ|SݢU{pʵW+{+w5!art^qVn<Ηg]ٿݵjWE[f*p."Ћ]Mk(~_CpfYxXclsגoks1kxf:.ʳK]Kta϶6gs>s'\ZJm/n%6k]kp-%N{{V*[&Cx2ċ]KMn+G ~9v+D_ҔG ׶= ~Q5.+=1c ev/zaޜ^MrJ f9 -^M_+jl[r5|mz#*Wc]SiUƈGtHEGr5O=#/˩~э$^Mzu<\ o8^}r9߹}>A灞Wo܁6&m!v:tWza0zU2NE_#ع8%8/5~*U;B_ҋ>|[j]Cힵg_ċe:ɷ8jnWiZVrXK]Kˆx#/ޫYn[(aXij/7 _ĵ۾žy>!6?J[jt-* z!t?XK^^Hגo67SO*}[6\g+m/+s-`5-}?/EEϵ샸aFg?ԈKV)ߩGNnepBa`Ե*8zJ+[:zҢ&}6}xRb)sxiɷU*at篯Z_X:OQ eY~+} F/h;|br@n'T_g{w%ƕ=t8{/K=kM/>Rou܈ZJ>|z5%>bE%]I!U}:?OpO$zN˪\K{Š:D|peQgGגo\B zQ)\TJmK$۫y6fTmbg&/k7MñX~tA毼W|`zO>[^6 >ܯ&߸G^h /gv-lDٹ]+iݕueNQX׿C]Kojh7C^%.]%lخ}jZ{fpendstream endobj 6 0 obj 10991 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:33:18+02:00 2020-04-16T10:33:18+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000011315 00000 n 0000013054 00000 n 0000011256 00000 n 0000011097 00000 n 0000000015 00000 n 0000011076 00000 n 0000011380 00000 n 0000011480 00000 n 0000011421 00000 n 0000011450 00000 n 0000011560 00000 n 0000011633 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [] >> startxref 13177 %%EOF acm-6.0_20200416/doc/charts/europe/france/france-nw.pdf0000644000000000000000000002377013646045017020753 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream x]۲ő}_o#}~!bc7w//4s0'_?߷W>܎;?wxw{GpMy~R ?׿}a?|\p/*^W_G<_o}xw?_ݿW_{y?|˯߼z{|n{Q?}qo ׇjnmŹQ#,zwU^+,Wܚ?O' >s{?gRB{6_QrKCP._SHoKNӿy?)o#'nj\o.+Œ6v_1MtAjч|A3o-3?7wAZ)6ڱLzApA_z(v5+f/ɕc*<0Nn_ wBOCoBN/:-񔼴>LK9>ЧXLb>ʠ>v1xl>d XOK|^4V?Jb+ Um#[L=hcEU $UA04QV`SʝVtѴ蓌F$A<'TrUTyYjEH!G]bD7,z=eHd.u$}n0CA"=!ETjaD1⤏Qk2r'ouG7b-BҸإ`Hd<)8}3 I-~H_vN𩙍 %<}uG ^ZqKra(NgDe&OQp21`X׀"Srf?x|JJB0O :6Zv`NeyM{9qur8CW',͡S$V%#`;0t Uu]'ukCdz<'bW'*/IB0CW4k=ʁAۦ$5C(z%N?XRwɣuiUji29;&b -RB7-VV0,/~q!'sXNCfuMKíq`5IKP58"F%$\S'̊EEfRTڠG9gLmbb.YUw2 f%d/5ûx*YÔuBňyF߻r}(-bC \(׈ 'wup9 b2}ޙ"-4>7Mpz:F+YuQ!I3bc$R-q3)djդM.͔ʔf.ӈ;!/-ޒ O$2ؘ&޸%X!aRRtPW8vgeX丕0uaKς`*Ҡ^TH!$jGD|7 ɥšTȥpĠ;NF8R-bg7<2F%$L.wXypB[2G}oh7c ;"Zmń޴VU 3p87*SQB \Y!JUW ,56&7.IUw<2F%$N.Qb,A2/*ښVނ% O LM\w]d{MU &ѸT XaRZV u5K#E^a6C`P 2&iHA\Mq 0qQkTA^Mz aDe50YuȊ*3, i!rGAXMqCױ5*&erIk'5fb54ǜ\DA4AYMqcħ\Zj&x;c,Q&[ҐHRA6pC0bbڐ:(] jRK "ɕ5*Q7IֳR+qsa1Ld-S9FLMV`\E:L4L.EePV4vge8&M7|y_Μ4JH jK}b\Zj'F>kDjE!u[PơYƥj [ͤLBQ y5ɓK1ex0NhkK +X`MJT4iSP^jgqŧ8+Q7.<ѳ#몣r'ұ] jR #<08Mbg%դM.wXtsD^6qa]2%KֈЃbAjB81$NHQ XL,z$3,jQ:jfM jR ZSgI\Zj&F=YӼ䄶eyfqg($4Eu#{ Sfn9f{%dnX 8bD MMV`\R,`& LĨeكKA]inp%o5FPQG 4rY2D res b2bs783FvAi &ѸS,#쬄eDĺbPl[kGb6`д /|m>tc\6g3&/˘}y$]My!f3njҌ ZaR&W֨D抳m~w@鎱qVfK|12#B2'Z D뵌$ jKK٤ɕ5*&mr%6\my{m 59&p36&yrY a5 K1u`V7tYAҖۡO"1].h<i5I5";|ˇ5q &mri9502"^Љ0BWo\n'֨5"?p !Lm=@#]tY@``984W+=!ȫI6.R;#>Lt\T*&}r=$ p ֙'rሰȜe5)uyi&W֨x(1q`}6YݺE^3L xPnsPPVb\'IijZV ~L,Qo0n c`fW2 #e5)-`g78"F%դM.x2 , _68e5"v{ 7|Kž;?;µSVg\M$OLQ i5IQwhpܭs<>pI[MqA a,7* &ari,5frYxKq"V"F&޸by$e̤0+ &yr=E@cGMCk|9a5 qF08L`pYG%$%32  C~M߯;#b.Ѿ3b›bW֝$IXLxO8Wq4p6,(h͙Hna}1 R̵nR&W lEV ~1~͝:8''ҰwHܹ*/A]@ MxuMaR*\V q5K?hzLca[7% |MPVb\X贇IKjY%դM.wX%r9(p*6CsLz~@8Lt&8pSu턑UAXL_%qr5G'FTゖ-f&wg%դO.a0׳d ]9#6D3pyN4 DG"T0D-ȉ4 [nŽ! A7-|Ł+fvB ȫI6.+nߧNXȥH jR'63R5} rv~hfe6zYi5Iƅbq7 +PkTA[MuasMfad©-`.I\\J I\%{]_,"=r Ĝn| NV&ȫI6.f>ZUBA_M=Q_%gng;H7gdzO32y082k0M䊪WMv[Xc\gr{?/ k7yyKχ~1&HI2.e~^'WtK?oɥ=.['M?-\xゖbNTv0F%$N.g,KoN{6 oír4L[!i&ŸT $&I\Zz3~=^\ \DƯQ2N5u &T 8b5* &ir32 ,G:DW å,А6@8I~5u0\8\N<2F%$O.m0npn#k>߉`vs j Zqu ?Tя:۫\Q_ͨ U]O8Ý3OMƣ)ٙm=#j$NHQ y5ɓK3I?Iwy1Mp3.$ 9pp &v7F%$M.=X*.Ѣdwv,9v8kiPcPp4/XWmPip=??>|3peYS>3W᙭ńZę4I+kTA\Mz䆘s]~٘Da5 Ŏ 2ˬɥ۫yeNms.DIY׏|?#/'^+| m_4v׊o֯)ޜcq.݅8WB7:?s_xŷ9'K|7#x\5;ΝjMaf#ܗxZMG+}o맾]-7=%B}W]Ȼww#r1K_xBݽ+9]NgjG|?O.bW[?jFɔ;|RYgw6|Q}&޵'w]+ͿԿ.}yߥWo{9d'O\a /G_0~.xvۧ/E:ʌq2D!tۆ&]7S9 ͙O<^_t&G9ZG|ᐝ'4H׊o\AK3o>xnJs:/)x\+ɕœsx͇֬Hw6endstream endobj 6 0 obj 7634 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:33:15+02:00 2020-04-16T10:33:15+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000007957 00000 n 0000009696 00000 n 0000007898 00000 n 0000007739 00000 n 0000000015 00000 n 0000007719 00000 n 0000008022 00000 n 0000008122 00000 n 0000008063 00000 n 0000008092 00000 n 0000008202 00000 n 0000008275 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<10DE6A52B7F5CDE305CD8EA941AA436B><10DE6A52B7F5CDE305CD8EA941AA436B>] >> startxref 9819 %%EOF acm-6.0_20200416/doc/charts/europe/france/degaulle.pdf0000644000000000000000000001364613646045017020656 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xZr }߯7UְUAPEgz+ѵ%.*'NwOrg"Y34FczˠF=([>כwqpQÇ͗P>ó RHv~=X?ĬͣWw? /v寇_`Ā6ηO߆ad_vo>Nv|ޝo/?mwsdD+wG/.wvG FX:χWߞ O_7? w󓓓_Wۛۛr{}a7_^lA!*!:nw=+tY~$6(g5\I>CO%IGggB; <֗%?oȖ~>m,]t(Mbl kr5O?>6jH.}|nxO#^31 ^Go15yzl#Z, J;uΆ{KK ^G%Ds^:BO?lm6F%Y`rm04/@.p5j4U=ZzɣMOOk.Ds݌<, Wh-uw6B/p5~y?XB5jz;z>z*&jJ!*e&GR!$R-ڠ Mkթ81RqŒHlYUVLuQ^ob`x8^v Qr7iyq.4U'G!uQVFfY'}U3@BWNL:;GV Zwxªl0Ûe^aLHXqYP4INC8cy춗wglm#'ߤ8GbHֈŔA)Qh\|2=!d.5J(GuT7NUܥuȲOsuBd2zJg=W aʼ8Ӫ!LG:-&9AC%)o댙5gyM9Y%$a#Ƒ:smIK|*՛%ZfVD7qk#b 8~tT"fRF6LLʅh 9j5ѹr1b27эk/=qy:VLzl|Q,(AGӭ<s@ҧIۇiS3`jba/&/DP(X+(ڮ#-B)כZ,&*U.FU &q7KW1G#MjVӡ&Q 3ڒ"P*\%JO&qYhADz׸\?xY`ȟKMTb-*;Vm&*W.FU&qx2_,~&hS佧y>4N>QM?$@&pɓ3vfbVD7񍋞ZIzl%.d*taEbo h 6fWVD7ɍNtSDu'@S7r #()D/MٗfZQ4&}]yL|?vNE&*n􅀑#&#ỳΐvC-=oI`0LKvS BŽI$jhx[D{j:;Y:,n5F[Ң:ӛZԒD7. :Boמ^W7eNd$-(:!ME{]DKԒD5.:lob{X ʩQͩYMˡoL#5 (R @[~kCAMBb-V!4.: 0|1i~39N*Ny'IrCy D:zt1"I,\8$jWVD7ɍē!bjy3rv#}5|,QW!н.\SUs>C{߸NZ~Q.JkGg,wzVt0"-\%>ƥUM|ռUl,*VNG .Td%# p=7 KSK/ \ML2Ъd&dTj({ ^gF(ҹ&p(z2+B"؛E^K[1O*_9꼉m ccQ\i趕tMȝ .d,dWD7݆J])uNa6KCТIv՛%Z%Ⓣi\Zu4<b*T hלʴyऀ &p՜Yrާsuդ:O)Cd0^a)G!H}91Q:Xrg _ҭ׸~ "НIkK[3ҩQ/M9x荜; Fzͥk7]LT(]; To k v6. :\ou )]{NZpG8ӈQQ?C8EzPDKi\Zu$5nW OU2ZDЫd-T׸pL_MŇR&Uqm7Rװ g/>7KbW߸< "Il\|FX-)rgQcFEp֣ۡwm # B`FUMl㢜܃dSt63]Dy Kto kKh&bZelob<Ē#OUS66q5ZGҨ[FQ$J M\b-JfsZeRoequ\DnNK?<…SQ8j&qyhAD{߸KD ۠8VPޤXJrrC[;?_<,'aM_U%<6XsFLr|aQ Wtvg}{: *hKmh= ޛ ?ehu|GMlΟx{B3j]w+7@31n:|嘑Gыgߦ/:rNaߝxz)by!GWD(W#t~~f)?RW> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:33:34+02:00 2020-04-16T10:33:34+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000003779 00000 n 0000005518 00000 n 0000003720 00000 n 0000003561 00000 n 0000000015 00000 n 0000003541 00000 n 0000003844 00000 n 0000003944 00000 n 0000003885 00000 n 0000003914 00000 n 0000004024 00000 n 0000004097 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<97B95378A65A3481E2D1C8D3C35E9D84><97B95378A65A3481E2D1C8D3C35E9D84>] >> startxref 5641 %%EOF acm-6.0_20200416/doc/charts/europe/france/paris.pdf0000644000000000000000000002371313646045017020206 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream x\ے}7/ɒ)R}G3CQ_l< -oӲ4YY( q{y=|;|{ƒ{s(O777ջ?ݫ/Tv,&Oo~w?<~p(?/^W7ݻ{LJȥ|~x|}ϯ_LJO~߽?_??{oo뻷?~߾7o޾? /o[nۛ;Ԕ!7w(< n?I\"αwwxc#pf9pkC<>,*x&/8/'"╄v6D(Oo=t1HXC{H y?)J;F~>$WuܾJ 3rױiϧI:PBϼRcǼџyZ)^uc!}μOzW3K/u+No:f kU<'/~+羣}~ aG]Az<>&I^#Wx5y]:Aj$8]~re<8 Gԝؤn' n&Ir2&'zMVۘҼGV}M4L%UI*^z8d-(KYKWu"io$ttH*ǘG6$6FЄbU$`NTS`=Ik]rOHU\4P&1${Q<9,%U6)Z.ݶJp57V+v Rnx>)VrO{JjW[bFpW: |u+'NpT]e9"-m$- 5}f1t:G9qtjW" )2h2VmKzSQ,MEF-CWop`Ew%cELw7YHX v&wd{?"\aE?kB}/~xXȣV^W"zt47n-J7A IKJ "I\R;T\\$m\O G Y/E?G9ci$?Y/?9K싾oa} X;~ӟex^E)klam|K$0:oo'U.WHoԝuH+]]SdzkRR8IN\XqtGcr-xώet4A\Mq# i"qA*&ur=H|4f\b1/`ވɀ$T74F%*HI\db<] ^KPN% FT]w{:u1EbaD}ɕUkV_L_8.td1I^E!b&ŸTrU5*QA[Mz;c,J'%Tm{y"F7dg8"cCAYMq=Su^KR~ɅG}.0FϠH#iv j ZĞa&nr9jJTW8}ldg̲u-LY1p]#_{FWi‹J-%UkɥV b2ẘ ٍH㑇"avLVd\R2T70F%*(I\%b L2"JC2N`8]c-%*^>#}E^y b2b%sYbyY8[׆mJtEF jRKc82äNJQ j&׈!J-|-^&ݑ Ύ_EÉUͽI,Ɔゖu:ePPV2|ʚ3rpbj:yPV`\Ȉ:*F%*HI\2 Hym[wMzE[M{"&Wm$\nmL)E+g0 k̸B!Ҙ:Q~5-208"F%*I\g, :v,`rL1gqskC.#J ;M\,)TI HF%d{y47gmrkIeO$ilLVg\Xf'W֨Da5 K1a`!g 3{,S{IuM#ߵ9z25"Dj6AYMqAKq 0 +PkTtu1~12,K,łRq--j) 0SkTɅȷ-a`yXKo302uu̎ydЈtƮ^xj)vuLvMI\!r*Q_L_%XeypFKKbk!3Ȏ@/PНh9ǮL^4"uLI \V q55yF0y3yǞq5yF8Mbg%*ȫI[,d$cLXe&t) * [U]M 6tg@P:e1 1z-~<hX6 qKngTLWt0u5-Ȧ>L*&}r=b0bHz4+;*` dCQXoU3RFe1(#: v*SKc :fM,bӣ/ّ6>E= TcҼeUe8-im3L-Iǻ$N.nJT6/UAfb +^:wfSbbElI4񓋻O.ygK7,H8$eᚹDMb#L $dEu1E;LJ5+ѥPLt*SO(Μ;%~?9Mĥ]h90$NHQ j'x;c,co&y9&N9:圄PjR8r3qQkTtYf1~=T [0j!]f.Q&ոl1Z0\rV%^K: 3ӳRxd8{[e (s!~$ݍи;L &ur!!Tt?paB'ғ @H9ș &ѸT 8gf$OLQ j'y:p2< baxLزg"6i5I- 7<2F%*hI\P2(.\JV` 豘9`[̡/&E5MD~5KY,ݵmƙ!bۣ]K" N QpwӤӌObGtryq'Gy] A![jʀM|=Ԫ1%AqXԃ Q}T/EW7&9Ӣ& DV,hj}l8#"OkĖ83QA32Džn[3M3KfZMR_2=.8N,)i>5PA\MbN-Suew<*QA^M䂗aƲY_^p05 #E25$T{",TMP^4+%f0rqlVVo&/8v23T&e9Ei'W֨Dm5i +}e8bN/trk<&C w}53߉WnSPb 湊:Le.ɅqJGсUZG%B+m\򣠮&ո 0$OLQ j'x(Y,ӜE,˖],qn_ĒvqnpFഽ K1MxE,a}\~ݾ0AXL_aO2c ą;ǹؖNOgO)ۖi5IƥZӤNJQ jR&m_XW=UrfK%bFچ`@Z_%"pu:&M}v`2|!UBA\M{l;5sQEG\N%&#*ȫI6= øU5*QA]M;c,z:|w7|Nـw*']fO%]M\p0f+$;%1q^f%*(I\Ӆ%j "g*[oSJrmކt*ӄ~(,+ b2bw րr4#hFьV[YL0x4cV7mf,.f6oچ5-&.hf L.F~VBAZMR"0gϵb[ \8&-k\2_Mqb.L863+QA\M6?cw)/gZ#Z[jݍ6-m^ڴ /a v6?;l0+I[Sm %qP5]'7"00AZMq/p4 +PkT5%paG!VJ΄fG8lz)w[\\4ALx.h)nL·IV[5d%4Whŕ>xPo4`,p ' C$z_Mqp9aӊ!J(I\7vgˁJKym M:(pˣλVqu5AZMR^|A#pBK v3`)rA ~5-ϱKfe!rF-5zKzj>l7O3ZXDz% GsXդgXN652;+QA_M/ygKGNz/ ꖙT(25N~?Be*ǹ`(ꧤd ňc_,y?=\ ?Z􇤚t\2=ǺW[;9x:ߤ짡̻z]o.=bUItlP7K%jkݥb~%xמކ| %ZqpmzsqZn[~Y޿KW%KOw]W_¤ΣwZ-oէG8f\._ >m}7W—I9t§I{OP|s)rpOP/g=rg9-EF>mpsUWĻӃObUޅ\=[xWnCZx==n0BuWϚ(gK1m,]*%|>D,Dtu҂Lt'-Ru-!'DN .5sFf_E~ʵc8k6E=OO? yꓧB%YM?pX/F ~8T|ay͞|sm7 NX}zJqv^0htr!p3}gzZϴ`n4.ҹ_[]m ;)5?-ϻK bN{+V;k{޿x1wg/w./ZݧK ;6?XuuZYv=Iޖ4>1 ;sb}|Dz{=H4t{^zM>{Ϟ~5u47VvF>[w/2,~ Kq.z#hֶ-rC:o?y9e#Z+g ? |Ƴny!G{U=Nendstream endobj 6 0 obj 7589 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:33:30+02:00 2020-04-16T10:33:30+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000007912 00000 n 0000009651 00000 n 0000007853 00000 n 0000007694 00000 n 0000000015 00000 n 0000007674 00000 n 0000007977 00000 n 0000008077 00000 n 0000008018 00000 n 0000008047 00000 n 0000008157 00000 n 0000008230 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<04538725B5C7E71C9313814D720948C7><04538725B5C7E71C9313814D720948C7>] >> startxref 9774 %%EOF acm-6.0_20200416/doc/charts/europe/france/france-sw.pdf0000644000000000000000000003354413646045017020760 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream x}ے]q{y1E@Q)db nE:A"w&su.OcHQ2sUUYSw ?.y?O?-u)SO~?==׏oxz7ߨ&_??NO߽{ÿǏ?~~xǏÏ?x޼>wۏߝ>|zONp#Z= o~y &9])ݙT~OK NOOZbWfVO?.ً)F7#ߑi(I | :vZJ|_J%)8Էjv)<<}%|_gl >1ͫ -BTOE9_c X KqkSH JIʳJ,)SRM^\V()w3t*mhuIf顝z(rRHV,"G''rʥZR*2ziT֧֦'ipdP{yCPFK":<>%63UJlGGxRbV}$aβB62LM1j:V"9*]Ҕtrj%M>(͜x,K(3T8w,&C} +'Oet}SF[hI1*$<:kZnⲜ71DIcz #&~6L6RR5Ҹf3RkVQW 2#*sD,Cڔ?bB[V %ݧ7A.Kׅcq3BSGzd :#_8zďp0mt6H=JE+Ag3RJW񈈺JujX eW)>KӴ$MxR(EEhe/T-u.TL̻}fH=k'z$Z*[4TRw⠎7#*qaѥ"a)J:h4 n'6?PqFK>;N&#l%VzjMzV)3.#44mS,!-%'V&*= iLHy_8l=]dVOH!EvPyW 5jۓJwN J9;A_|h2+K7j:;kʓ6A/}.>!X;qT6N$aCFCqS&jULT{FUTaK5yUMhfFruJ8Is媌xgt(ץkeBƮ,TqȲtmZXV ȡh5C:M-%'^6RvdUG4;҈XH2Mq. mL sGh Дzp3we'QRU 2!LB iN5h! HYzcuID>&}]$csVS26PkdLf*S^ftK~p,uBƑlXYI^0\Tzz!uTcòL8S9a'肶uUn=h,M>VtDۺ>&}MEi!1:8 -еLezG:hw9t^hézAhkUF&p;2#G29-Ē#CV Z,$©1UFUR)qK8V!ʄ]XpN jxE+ \M'm6rɗpR3=oy^W4B=(B QL,;\T,iZ8"'Z cIKX|`],, *ѱ"V&d*B#Sɭeg',+12e򠗍 .N!>&_nD\:.yZt1VtK~p%g-\^_$s]2.OzR:I֒]%-,*a'TcbLȻJ>;A'ִ%f&'m6'|pQk:c RN1"n 뤕NҐN 4dub!8t^ha #,&hɁ:~^J/ya?"\:5f2(-ce6d,,ot@Y譟5}W{1Nsg*BJ+VM>FLMSyf!gQocs \'q@s⦊a`ԣ~ '8SYX*č ew|`Τ$*}lx%(O+l6͒s 6Ͼ' z^H=@¤ÖyL jP (}K!3,yW s{i5TǪeqr`q~@Jkb~j-ʲR(AWcaA)˄t+fe_t0c9yщ]v)'530e]Kk*P Gea8u8JGcdsZ0T ԣnJ` |6 IXR qSq`%|tZ:77„ ]H2mMՀoԱ۝ FzXIt|\8|MBGhwұm$-iwWCyAa(-#oQ&Z_p/L%51賂Uca@m"^ #MR#C8W ]<6FhZ%~"h/)a<.Iahc]JfvXR+0ңWRtbBSӖ;{ml5QIRGf4R)ЅcJW)e]+e0{Sqm ~t$3`n!ǻI#*y,XR+bѡRKїuYx maV"/IѶ* $w vKaqWBx-Rsa)R uW96xrѝMsHj08)TR{5mTcqu3 qSq`%D_EqE0r֚<ޚ'u]\es2W5Oν5O.t#Cu 3j`PhrP7"`rē*DGx](\&^y,R)%sIзl"V ~Iq1Ү 'b^6XR+0ڮK4q.Ԥ2a*5 ?(#*ɰ tBy$JZQvXb%|}Mс%aab~4p֏,AjG@wT!  я#m*ny/:/sTGSNvT+-0ʮRk˗JLjQ+gZ4\AzQ:rTJ FȻJ6,0b-Rima5F+2 'yhTtC8Qb&mN]v`X͕ evXOwfe]t)X/pT1P8;@ڦM+_P)ƙTR)yXiLtu8 INԳ2PH=bs!`]ep@UcUJLaavq&̋97$&cyk<S4o)yTZcy^\+{Lǂ];HN $Fnc*ð :M9LaDc-ϛ/Ei ghf-hns"%1lNjwhX*H{nXqR2!*ձT0h]f4:GrT!aW )TǪZvXb%D_E -?'8%b|҃ 0)#pmWiR+?RRje fo*nSB#e\Ȱc3S3G=@Âҩ$JZvXy}0Rs̼<[5yhĆAd%D,M1b2 K@8UcEJLJw,|8xPP锗)xh[9J2,"(TcJL(Jq,<ߌ N[ŒSr5:H1)z*♫ԍdMR<>PScaUL_{&` vA㱌fb>hX0,CD2 RPtVbA)˄dR+2E'Mei;+J%pM*%s@Y۳X3J0,kUP%,2ʮRKʎ +CĆgO!©(4ƨJ5,HelkfTcEJLJw,ľ/\G\c*ñK1нQ< AiQT)mHɚAq+X ]r>0<*V&`]%;֓Aaˠ 3kDI.}W醥R_P)2c*ӱt4R<jY(a$@6R2)gՓS`]%JWI(2*ͱwD FN6ȑqAЇBQscW7TC9VDv*nїyIwW@y¨4y2\ cކ q>ım m)c.%!τ]lms y(^PB^`]%vzsG2IM؇Jv,q_-#В:fʠurW8h=A=u\ԐC o0*Ű iY*z8XV&d]e8֓8Gmr:x3nGˍd]%Jac3J +MJY&d]%;ӭzX 6WPGaHJiY\meW)R[d_*ձ*V&`]e8z~ ;>N[%*K2ʮR1@SjeFUc=ٛ/]_KIgkmACjnЕ([qݥ.UWu|]MW0^# , NN JͦDBUpwoʄdR+K  5 }V%{Nx1͵G$TzXUaAJUc%JL"Mxuh[R> \02FUvhk~K%: LJw,=_Ţh fJ6{ yYX[T=DLJG#*ѰT t) X*ٱ2V&`]:Ϙ 3fYT#*ḧt3fűJ=1#*ɱt oSymAcVyllA(@nXֹ7gVֹm*ɰT tJ K;τ4y֑9%=8Ռ,We]'t TcEJLJw,1+/C;Ұ^QfwIŵbÖ8%Mv4C:z#6 QoW47A0'%ٙj; pjSჍIR ŕ+]lK;&B0bl69FSs2ʮR k6Қ698L g\e88;l*U8c2!#*]*y:Uc TDzvfyݘ!hf(L Zj2 \4Է@WHFK~D<&dt5%Ζc_V(P*u2®Q0K%;$DzƼH_.EI[dG-o٧G-Y5Xo:Nݪx 'cLX88bkwڪ/";lqtZ,b@yKEabeBFv5 +K̚2򮒏[H'ޮ1gFUcY6*63czEWnv tk ! _ցbWAJ5#WJ0,P (2*ű.$2yjf2ڮ K@w;-Tcq63]e8ӝ2683vi+ J4u@J?r,#v`X Xzι k JY&d]87~=wl5"^a~=6*|UvX-|u.X7vM]#&W܍d]%|C%;V(Jq,%E7sOv^nv*ɰ+/=0ʮRky~RitV\u^wV9pɢ% cq=*mӯv`b{s˄v5m*-(3"z+-$#*Ḟh&KER iWIq/Z-ism 4zرE㩬6W46>tJtR/=0ҦvqI#t&lG tή4 _a=vT\Xa2!#*ѱtp|E=ySki_]Ťm-+qwh1 ֛ZKE/p"V uW펠3̃w;rxTcSݜH!Dp3Q֛ܗxKݶUl&fbUDI Ʋ5/2A'⨌z$X&,pGr YS pu hHv d]Jݢ1Vv nc*ӱ.FF]2@ۭk4gFV @?298֡JBY8ed\vpx ?E`y:[ AQwjXwfb*AɶG2TcYg\(uI8GZ KԶl(++pux}݇Jn+6Q+PjeFUzwI!jmXFM_ 1^uC+*u]MEq_ -c];ӝRi'2p֕ [oy)3Ϸ>[wlX盗b[2)C;n~%FceY~U(v]" 0XR+0Ʈ2f5v޾n_QwXRfE:bv>+t屃عNEIGk`(J1,H$-O*JrD cWă= ?~sz%.1Ү vSjexʡRK<73_*]IK;9S %Oq=5¯~Or*9&]$"{ҟ, O*3n>>%ܭg٦u'X68ltnڭgY6CirJ7ii ˚W]>ײ}_d8,|.cEMWKz]Oܬ sF;3Vlz{_Ci5+QmίMn@n>ߴ՗Wesp4r]7׮qQ_2Zp>=anf;7.鏿ҍ3n&?˸$Cp^k$l>Qtz KSܭyNע1q7Oװ}w7/yV\+PzԻױz=m7ŒfGoU #[϶ _?r6 yPqѐJ~^Kn ou<-2%-p8Dp3yHʚq/~#ܮuEqsLU%o_~ue]{-nězx2Mu^*!lN/\J/g̎k_|+N?};4羺L_iOu!ߜp^ zqaШG; Nn;ü?yS c~eQJ~1M}k6c~Oߠ~⋳xԫ_7W\CGGmk1gr7Iȫ/IOv)`0 Iyiu}LMoPˬ7s E^f5ߩFWev3SًϮl/ Qο[Bǩ˿fţW_E'`_⟮vU;Մci! oR;/yq¸}ʢ[âW5\`ݟw][ϳE]wӔ_ެV.A\{VLV'FIv\v7=嗗Vu32"SIzq/АN\[t)To~~Ց+1f3ן1w_\}[Wd˷7Hc|Yw/θOgJendstream endobj 6 0 obj 11580 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:33:21+02:00 2020-04-16T10:33:21+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000011904 00000 n 0000013643 00000 n 0000011845 00000 n 0000011686 00000 n 0000000015 00000 n 0000011665 00000 n 0000011969 00000 n 0000012069 00000 n 0000012010 00000 n 0000012039 00000 n 0000012149 00000 n 0000012222 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<024775B61329FC90633EA077DEEED5F0><024775B61329FC90633EA077DEEED5F0>] >> startxref 13766 %%EOF acm-6.0_20200416/doc/charts/europe/france/france-se.pdf0000644000000000000000000002517613646045017020740 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream x}۲qya~a dT#- U\++fτ(^S*;:))?Ëo?>Qy?N|#u)S/ᇷ?;O~?߾Wxw?>?/?=~}ݏ/减z OI*co~뷟ޝO)> شǷ>秗zuzztywo?}/^O?~xӋ^O߿o?}xzޝ7,C =zTG8N?{xR$v*573>"^`2) ~ܞߝ*]8O~s-V|{6\֟ء,ӿb= R[SROm3>7R`r.]ȁc=ӧ+ԛG}KGG>Wҗ[)E|}ܜ9uFμ_;ֽ(qϝsެȺJği =J,yrܱiwsO)bwӧO^O?"]{m\k9/]SjFx7})7K$}b»k*#]9<_>ȕ<\q|LC(F4s;^&jHQm'2A):VX EBS(B- Sp0 H֤'ZPt䉥kMAqa;1Tqk@,[^}xJ#WKE~t5&5ևiD1U(Q:M+vTJqDR)UȵAU1vn"?ԄVy[8lK>8O w{h_t1 8ymD$\U\,.D]*y.. b#J<`g$kELSB2\r1u9u}X7F0P>ţHeɷۗ3.#pFh9%V]hH":E+ҮJ)㇫DZbWI 4x9-+sB~rh'6ǩȒc(R |Ȼ=f_-2Me`b+#dpu*SV*eqp S%$R+R.ډ "Cq =/+ir?*o<, \>9OrKyg12㞻҉N#d+v2郫}t'1"O76ZuWK}xcpa\+.T.N3޴2&HqoL~ţHeɷqa_fYW&q  t;~]: 8Ud2}ҹI2%)֔1v$`N<1mpJ]dQ&dncV\,.Θ׹Jvl\*on'q׉Wl j3fA\0IfyœX/~C)M2Җ鄬 p+&YVy=ٯǺS9sYi\d]Hf>p]-eHTs%rFPw~p)=N /+@ +MFS]?Vvd\p Z*ŹI[uqBZ,,s{yyG!M4V]%1UP)U(AEUs}9涼̆'u ĹaՍ2T24K&ұ5GT]%JKgQ7JrD*ڮҜK#N֭<,tn 9oC0qDYwh\KCa*"*ٹ˸Nℴn.DYfWHpZbcK:3:o*q\[ M5q ȅ sZƬJ7.H)JvL*2, }^F W"i*ȻJ6mR)&em6Jw.x^p53Yd]w J7.H)7\RT]e:׊6˱pnzHqBzo"j ~D #W|ŠG(> 3]otK\ *RqmzBc̠-k> ~Eù06&+hsSjRڇJq.Px#Ř8_9*?,NeԬC Гf M7$_Y:Xwh\*<*չ*V#Juu QG +*ݸ ʡRPj5L+yee_㜕s'$%glgH;;&E*`87Ȑ"DV7d ƦYZI\GGaEUqAJq衒+Qj54+ye2.үح}hеt=JبPGeW9:wxqk<=4 y L<>uƢ" /XoYx%Z[骩JapbJ1OLJm/M!vY\4)Ώ)tά;B+ DZⴉ'cBkqċ<=Jൾ`YO$kFˉ+mђ8Vb}ǨjuWƥR94TsAUsh94;.qcݬ.u*v{'$I*͸8'JtH*Ʈ2KWX3>LЧnΊEŲ3[izf8{uWƥRUR_\SaUs=lޏ7sNE Y(%0"*ٸ]9׶*RKїmaj"qEU4ql EXjv7(J1.\yc7.<"FX1v\rMQ7WzB~Н3NYDYoXvf\*E*H1)eb*ù͗ azYI3%}):{Dl8ǡ[6ճ2WaS]\+Reu Yֆ9ikp$ډȊ4*>1p\vAUs2/{8+Q$ھanMY{0%aǍ8gSgr$*Ҧvq+m Ӷ8cv&FJ8b+R *ҮK22.,kn=lCr6 9hÇopdD qqWƥRgTb7Tz M L%VVɁ|*&r_Kr&*Ѹ [YKyLFXw\b%|Q%kYXpF"]=pTM?Iq'K%;Fp7sygz2g&isJҌmL%:OT]e:Ӄ]} ^VFHZhy ֣\0tAو,Pъ86KE<h\[mZ6֣GbiQ薠fV*eKL˥+Rj54h8|`iF+bЋp֎u u#Ǯ+Yv`\HV0*ɹV#(Jq.Y8Ab '\)Qzv\Is mXt Ju.{#hJs./.n:j5^&h׍_mNJ;ĶT.ہ_*;Sv锵  C&T> aIy E Kqhܞ1ϑ=oyW< s9e{d|6*m{' ؒM];_0FP1v\7_*uOJ)yݥ%ĄWaffP'sJ(!EO(!*1 8Ts%JFPQwd0Wl--?#{}JT]%JqZh*ȷnL_*Ź$ _X8#-:ƾ8'7Ɗ&a^x|rӚxjs`$Rc5 6o*n=Wm SeJ<^3ҝ&oyWΥǫe\8w7|)x[Xh+QXrUZ[銆{D犔Zh7 $S:l}ڬZsٵ%@ƔGWi(AEUs22-\PE'41T'V"atVQvb\66Y#'bJ7 a^$ LB1QNJJ;0 를TySq|5_bN/sr_ ej~iJͺ&fV ůAz,)^_ҧؕ*O~M5*`)_ҥ}72MտN!s3N)W&y2F>o*Ϻ/5eWb]ElMǝ+֍}V|w/F갮\f.΅q7\5i%`/hf}]} },Y]'۞^?Q?-vi<ǗV]Exu+ֽ& [ǹ4=={$ne8$y8%εb{~S{V]M|Q~a< a{r G2Һmu,*/'1׃AŎgf}ɌyG71bhuŀqen׿zRe-*Sc^㘕ze1.L{bx0MDC6u!V}!.z/zu:}_nD.~_P,SySi&H/] եA2Y|_6wrWA֛]zV\hѯ_>U!]0}Ҙ[gC?~ׯe-fE ݬ[ݬd_ͱ7bԛznR=k=L@2axvp 5Fe&^^Y3sk kn7藬4&;+os>q12G~֗ÍteXQz_TdM8W +pc׷Yϸ[G'\ܓ+;nxͰo8Ϧ]?UϋSUek]W7v cƷ*Xx\9oSɯ|~jy~tC [neJg|W7 W笞=\7J{m_^Ezy>ݦwn9auwcx;*;KG,C8LtP#~|νqя_-_MngRG4 &]:(_=[ܟ5ﳦ?ueM]ܳϋFnrh￸; endstream endobj 6 0 obj 8279 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:33:26+02:00 2020-04-16T10:33:26+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000008602 00000 n 0000010341 00000 n 0000008543 00000 n 0000008384 00000 n 0000000015 00000 n 0000008364 00000 n 0000008667 00000 n 0000008767 00000 n 0000008708 00000 n 0000008737 00000 n 0000008847 00000 n 0000008920 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<5067B98ABD81A1FF4717D95D0AF73A57><5067B98ABD81A1FF4717D95D0AF73A57>] >> startxref 10464 %%EOF acm-6.0_20200416/doc/charts/usa/0000755000000000000000000000000013260345311014412 5ustar rootrootacm-6.0_20200416/doc/charts/usa/newyork/0000755000000000000000000000000013260345311016110 5ustar rootrootacm-6.0_20200416/doc/charts/usa/newyork/new-york.pdf0000644000000000000000000001660713646045022020374 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream x[vǍ}W[5êB]<(GR,Y ʼn'ybIKR%f)Wo;6P3vBQ[_ߜ'nb?7P 4ߜ|号oxy󿪶6ۼ8חw^>ӿ}8}wGn^/D? ?gO..=7sw%>wsE/ݏ_\~nowspyǏwo..}{{wz9ۋowony~{~N+n)1%Ud'WOeÅծkZ敔$Wrl?v'y)BU\pl7qspBǮӍ ]^g Ki U pC?(%ၢi W(pY}3r}]Ӈ=qԙT}!|=UڥAxkΝ8X.OzS>=>\F>2qZݕ~}vͲY%ϥTwMZ ec<ޓĽ:^̿s{*tvGS)^g1hGTN?Q <>y=2UB KJrUL]Rd\.%ZȅlٞŽZlL:h($ `\e6)+0Jrzj`.Yׇ[hR%cp/"h _Ո48Peprk|0Ia3aG-c0'ݣ͍wп砏<Mx,YcLu"Vc1͡bpzQJ L20N[)sTS߼<*( >u{+ȋ$NlŁ$"\Jxa-"ߟ0qk䴍Uc3:䳴WqHGhMDC#iQ']^9~]L*Kbԧ+0NQ0Rl:xyE38#˃q<:'~U9[hnp:ee5]3{kN{K kNϸح:.+$rc3ԜS6iY3_R֊/BSZEgܹXKqL:LJe`cr)~׼V)!PWdl2'c8# }_ =%d h6!ゖप$ ZlWyeH]qڲ ը*:9U*#2IXco(Lf`\%XNf"( ѲFTgLj\daO&/e% G9JYm2E;G˔ ·&@m6E{H9W.lByRYrQNiՑ},7eMTAMqA XI\Az#٤.]k,s!qb [7͎w(ZwLgo\c| lH\nQEp4h)&p&ype@f0lǬ2t$_'g6$ Y>1zD"gDEd lKtP: ѲFTf4xֲJ;W[B Ixx&" l Zu`5Ƀ+Vo<%z2v,{S2YΝگ0EV@p4(m|0Bfg\[ÄsjY#*I\Wr`eHưNT.rR&i_(FlB-^'*.K@f40RJ+K9m|SN=~>'ˢ抖9DZ3igRIal%{"^FŖ&޸pZ.X7W\ZlMb-ӏ&~@aV4k,sܝeXsZ!M:TNՎ;dX!to~-MȸD پe6)>n :ۈMNL&jSQAMYe[c;bd8m>/_ <=_>9|\ts/~PANpn/A|8x湟:&,.8 LگӖO9q?'z@o;x/vav{Ws?$jݡyGuÁ7O/Nϡ?]OrznG׶y7Neooޡǹ#eKO˛:Wkxt7.q]Kyl2gp?㞋[^>젏rЧ CDAyo15w5 CwĎ\w7b(`{;^H][''=Mݖ@WorC `;B_<꙽MMYNnso_vcuݹ߾bvv z[:P87eaw9o7F$v#}UBϾ_mo5ӥE79X{ 2020-04-16T10:25:57+02:00 2020-04-16T10:25:57+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000005284 00000 n 0000007023 00000 n 0000005225 00000 n 0000005066 00000 n 0000000015 00000 n 0000005046 00000 n 0000005349 00000 n 0000005449 00000 n 0000005390 00000 n 0000005419 00000 n 0000005529 00000 n 0000005602 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<2EB987E481994ED4814FDC2D0C9A1B2B><2EB987E481994ED4814FDC2D0C9A1B2B>] >> startxref 7146 %%EOF acm-6.0_20200416/doc/charts/usa/newyork/boston.pdf0000644000000000000000000001723713646045022020125 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream x[ےǍ}ﯨ7˱L~EPHڊ}rG"3-FcӢiYS$ B"Z/NWn6?m<]do/!-w,o/O^\]~}shnw_worwoo{ER#Jm>yry\0?ZȑO}g?xoo^hgwoqsyw˫v߿߾{wyۻon.߾Ywoۻ[[6ܒ[s^iMbq EpaNWL-H`pC|? s yW=_ [qɱ=M`G_[7~w!{ (,TC = F\S_Xwr5Z)A|=<ӧcZ-<6 zz}qGcxb˝<6>><xdɅS!-5 rc5v}m%qV~"x6?㬜G?݁J:xS"iN^pGA&_I6k^ z^.#I2*k(;.>IVCvY*Hڏ]g,|ZVCA|o3@ i 9`r4o8:>%mw،L1EkM9ďҜDcվ9 |[OPT:@O#Ʊ6>?ԑdd'd4-Yhs`H Q\ J7Q.94 q^d.=tU,VǓ8a0O7Cj|OPt!Wn6qKaRWU> fr ܍e{KF2~k2+༫b"+}?xNr13= l ZD1: ѲATPf22KK$C6Ggy V<I lT;E7LBL I j++AvSy6-`fp -Du6k+XRA<V^^me7W>nZ!j)*DbՆߒPEm6&I\Rmd-ݓZr!H* #go\X0E &apYd["t`up?#̰^ h4|R68aV lKUڹ :j#Kl{%0%i.NZ!7.T`KnWR>a6 Kf<W/;g֜-\ XZ ~>T˲-.J!@MCK:Wm: lֱiVFy[Z"&4qA [ͤ Z}l<~%ev&/6 ^i*-"qz9(芵2i6I%Z-0)sZ6 l~C"R+o;&$0qCUF٤\N ٤ .RLc;f˩+Ws&%EĽ x|a&لK ˢՄV<%Om\aL(^Vo%m0-`YW$Մ}lR6m%u .sBw2dTP:Z]Jzy}:+3 h6!4ϰ+]2Ͱ&ȳI\ >41|\ *b;+&ل Z$Z}lͰ=cF^hYt%*WAKoi(Ʀ.d֜w7PA dORab󣅿*A'Vb$gI\j AMUb)j8ɴ:gwR2$^€ͯ,|7Ţj$#ʫa@:_<:_ &é+lO=lu6y`Hrk|`ۋdCh&nȰNÄVDW߳ .#k,}X&gߑ$j'>e٫^Ke2уZ$ctx3~a|pWϼTI<,:m^!$B?%Hl٤.mFC2WK^KN ™d敀Wbc0cy*c&v.AX/ *(I\wTmW͍,?UM⚴hI;*"D4zie8JǘH/GCWaIIY?,)`M%q=^|I4))(uN>kx 5dY\Q+~Ւytb0fF;u<86I6eu9&kٹϻqEܒ帵5ytwG' 覞<}k\~S9w!N79Awk#N>9T)y;mr;v]pGxwY^iͶ~9{wzqsK菃wy%e0 oא=qcOčm.Aֹ)MtyQw-꧰dUV}K ny~8LSK:ngɻao|*<}{$lX½o2vTWBkW^35q<}k49Vv!ME!*'2Gd\A9ߞ{ ӍMxg_ rE9wy+Y* {eyzKsc5uzb~=>+=O|?+CN>Ͽ,_']ٿy%𡃺>u# ya<#$&q?(쎫ީU=n:P({#<f]Q'pYqa=OO'>.Cه]؎'S?#A{ɿ#nwohcj nQsZ'Ϝϗ'n/> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:25:59+02:00 2020-04-16T10:25:59+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000005564 00000 n 0000007303 00000 n 0000005505 00000 n 0000005346 00000 n 0000000015 00000 n 0000005326 00000 n 0000005629 00000 n 0000005729 00000 n 0000005670 00000 n 0000005699 00000 n 0000005809 00000 n 0000005882 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<0D4D0B7E1D7A37C4C2280EA568E78DAE><0D4D0B7E1D7A37C4C2280EA568E78DAE>] >> startxref 7426 %%EOF acm-6.0_20200416/doc/charts/usa/losangeles/0000755000000000000000000000000013260345311016546 5ustar rootrootacm-6.0_20200416/doc/charts/usa/losangeles/los-angeles-area.pdf0000644000000000000000000002361213646045021022367 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream x\ْ}ﯨ7E%k$PIښbKttH*~gLpkʲԧYY( ~s=>7nn<{>|) mi{y6~yo/o~w߼~xn{Wy5p4g7~qcp_^߽wϷ߽~wwn޾{L~^ܽ d'ͯn~W_owR_o]/=_ܽ7϶7|~{޿߶w_o߾noÛ;߿=y?|ׇo?>lo~ jnmŹ7O._dXDԻ WQ{u)oKL]KqN(c  nyC)o"o(W n]ױigwJrч\W3Rc ͝yJWԕ\]e3K͓:RJ}5Y?A[:*-_Mn_7r«}-TAk`^]A(+8è t)h^]A*8J]+pGwMm;>zee! -PHR$J_%>BNU]`1j=)XbH>䦒$UFu({|^gyVDI[X}~=Ԏ58i2$E$] n>JJ sbM UAifTu}{{+p3T(߼Hyb&q(ϧ5̑\lJkZޒ]4x\D:*I\`$dz?֑!H|Abh6)X#ne8i4I^B;l JчiKZc؛'DQ,CӲ(E?#d&͹NhBLݮSJC2BI >|━Xl<988F&ɰd^i8䃸)kߒ".bUt.$s4_MqAN$O{tfŃ܋\o05o`қ6e5)uw30U JUu"3 nxi$ _pe@$+ kDdE u j ZęQMJ5* &irI<3r39>س"Fk)h^"vJ3ɓ#^ 抚Lޙ2Rqy''eA33Ýa瓴1#U~"?j2)ȫI6.hWq2RQ-D}5^,y9| 0Qma36*I5.>Cu7˫֨%^i,bipR{DЈdGkZ"dҕarF^}5kF8aty jRkF޵ȻQ)I\#2FKEi&m8~q˴t-!wkUcE1-4I+QkVVo&/}9AD`̿CpQaU J-;jY$M.RLcY);R6jǩ&e'|fr+NrAlLVd\"lI\IF%դM{Ź.e8#)dž^\DE`1AXMqQ XoQM*5* &ir˲2 CVSशDI;r 0pzŨHh1_MqA 0$O.lOqƤA e0 &ѸE4dH[VBA^M/5J:p*6 άMJ<QȎCT IE(6v5)9ƐXd`$ N r~w^jTVj=MaLks%^i,\F^S C2QsΦ(;GDE\b5AYMqqq(r,Dfɥ֬$0_XL_y^ǁK' 1F jR"o&ir%PV6dX;X}G2mn6{.dDeZ0uN%w"D΅ 37rA*QAZMc熆\hEa}U$^Bs.TkTBAXMY,1#D7NӧOÚLCJm$2.3)&۰fI\AF%դ= ߺfX4> .RQh%gad[MqAXiNAI$O.L828G?]>`F"<70*h}1 No512(.?JTW8Ѓ.qKа-l8t8pDfUTkTBAXMB{,;G~X]myK`gͫ+$ ѬMVd\Ɗw3Kt*6+QA[MuqbB=#FRYR N-UVg\iR]$L.Rd^%yb?e2ǔ8uGeE2 j˖| n]&O.e2$M.L\1@T̕U9'rWp81A[MqQ 8pe7 +֨;n1~e9N0J᮸06䂭ryA{pwHRO0rJ(I\8B)q ]kG lr]px j⍋ZĚ $$N.RLc`5۽eNx8UE7"Dg^Da&~riV7+ ,&/<8 cӠD8*B\0RVg\"0?=%^i,`;"49h&c3ØY,&>JER-0&ar b2\fAۘ+ddV]_ d/iQOBTwũ,eX0|ࠛyZsւYkLh&Ÿl֚%+\gr=_f*dy$xX&ۚ !+DAYMq Mv>BդM.XeԷc柳'=cb2Nu**qkA7ԙ&zNa&.Y ~L%[$iXk]WeK7(I5.jsMJ5*&}r6͈e8ܛcGؒd:O#*KQz8x%W$n j J`YbX\zQA_.=x45%Ͱ1 JQd⸨Ge &#C=*F⼨"ahAE% 1&rpfԱ:^9 &ɸETuhɅG.[p_Ez҅R_L´N<2f%d`"qh ΢;SRֹfgپMOMcLWƔR5 +Dy5aUOK28$K-PWh\3iR'WUQ y5ɓK"QXCq 4$%(.:o0X lMr jZvXfb%դL.ְd̺ɈY{i)˥ &컞&~ryPV4o,' ĩ-I ]X$5n:i!*Χ j Zv$j\DJLV4pOHrNqB_3G3B'MY&͸E<3qqaO [v ӰaKi&BL5j-qX$Ha(ffP3]? ;\jj0tIJBAFzbAuymץA-.z1rT$Gq[d;a 0KnK6V]s=ZG .-7:( (I1.xcf:L\;+闦tyw4YG,\?k &M ֲͤU[%*HI\<=X&`2ύ?!#?l0Nc}7W^Gû3.h(fj"wo\UɅe^|NQ~s؎O~E=΁Y7LVf\XUkTyy1~?,]:\3;R atEׯivgDq0TդN.,&U|rFúr(:8HY~t*ȫI6.j=20Lr5*&ur7"#708b#숼O(:)y$׈+ &qrȏXfzlrW(޶6xP/w= D7إl[IUWh\"ztCEդN{|YqPEةQ'MWo\x.I\YF%$N.\y%#"ɔر0dvL΃]F!q)7S-`;u1M9H3:jhdA jtjq6c۰qh*5jlzPCTƲ 1Ꮺc׳WZdsL .-!G6`gJ48t=fVBAZMBn\qNB7t3 T1[[ jZAO]L0hʬDz']3{vOV emx8f̄"ȕjY%*ȫI\Gkmj<+lA`;iq SPYn;4;DK-u2q,mZYX)Á/|m(uƟ(cZxK>^,9 ۺ;ms=sN?;w*d*}WbG_~&nC~'ww_r.8wRKyuȵ]yZRusۧUlw,,ԙgx 5:bUaP8W> ;QHNuݥ뼓eH޻zwPs ?띋N|sw|nwL?7BfM= BNV0Ru>쵐lTY'(-mT|sIJ/>Bo_;*% i/q>K__<44;/}?cICiC/utnygϕs<._\e˳Ëk;| qUyw:p=ߖȵzR;aOսǞ>{m+]\zF}? q. ſ`!eק̅ko5,Şf܉k5K:p9ݳ/>z>v27mac/^V!$)W>X[{+XNIK"JTa\X(<*._`l O?Ϗ|~?_Zi_04駿pu/?wb/R}ő| / wʗJH;ٳH׼Q%Y.t{X4t |F>YC'떇RϻKWyqȹ]|o C9qRUU,Ίss,r\izܹ_~Iˏ;7[v^(2,;%t#Y#W._J#V-Jp-ԩ7?I ؛Ky!.gO_<uƕ/<, qH|X|]%yS<Х}哧gO͝>5]ǁ]*r m8:gzkGC;hc._9M,}"pxҗendstream endobj 6 0 obj 7524 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:27:08+02:00 2020-04-16T10:27:08+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000007847 00000 n 0000009586 00000 n 0000007788 00000 n 0000007629 00000 n 0000000015 00000 n 0000007609 00000 n 0000007912 00000 n 0000008012 00000 n 0000007953 00000 n 0000007982 00000 n 0000008092 00000 n 0000008165 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<733F38DFD54F5AD1A0C48C07B9B82493><733F38DFD54F5AD1A0C48C07B9B82493>] >> startxref 9709 %%EOF acm-6.0_20200416/doc/charts/usa/losangeles/los-angeles.pdf0000644000000000000000000001430313646045021021456 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xZr }߯7UѰUAʊI:NH(t)Wo;==Fgi4b:7O'gybXÇُW۫_NϞ.WoOwW׿lon2]\L?<=8|uN^ί||9{3N7L/N7Rnf!)3%cۋ%#M$qDZq&&S}1oKV>6yHL<6/N^NO&kDžDŽFbƓ#/zr8U^OO7nB:) ̮0k( -s.8Yg>yi fz|ޏ޹8҇եی.!yG|ZCi*9~䔆>MpZ>0XPy^lTf`BK&are> adY:䓩^bà ⤩~ʅ֡Ad蝏22 AmKmG_SJv3S"$ꖓ4/kN9$Es&,Kb5i( *XZ'IY;Z=vA=U'|ʹ n¸ d9f,CX7ƃ`$T7ޤPY)!'"9i9;v4Zųj7.F &s]R&%z()4OC?CD̩9&(IQ.h{V]LB a"&/;gn8d+‚2 `9 .y uࢠs(k16ձj71q1b-mDa4 g\}b H%% #=,iA &QX IԻ\y4ɝrQXƆ('rB"_ywd#hpݦ"?jJh}A\^Z#Ѥv.<9sF}V%T*1Ef &AX CI\IZ#$u.Rz&, L'DJN8MkiuPpEiLR x9DVR> W.Nc7q1b-mDy4ɝVY E!вHG(UJp!(u0Zbb:Vo;tK4Lمc`Rmh&!놵/DѢҀMrAnb;a4 #ON^"_Ɠr. he)"HIR._`'al&sj@PFҹ(3oҎ2`Momv#`8oK:^c;XcSYu11ˈVk8u;JGt\(H`b'=WzU1')*IP. $w,Zh:y)=X-P+gFj39 Y AMrAq0vԹhFRԶAgfZb1s"8DޅoGnIA/2݁h˥ hnɞD5AMj碽7(R1\b ]i%e4)-ަWDڸ6o&/x)=X2vA#v')~ 899/ =1z<L!x)3VT\NZ#w.&g%tZyR0.&:/Xv7K|oDZMb]Lc7x|I yg⌢MY?C[)g\D2PMrp@^L| &sQt3NQ!pAl@F\P:йhF I\LcpO*|W.*\Sa LL\S"0jkV. 9"/?΅2݆̌B VQJv4- E5M|C,+$-/ImO]"fJ$)kK}& RTEKGm^dS%d`95 _=9m)$*pk-'n;y4ɝrQB,.;hͷ!LVM$/Df(¨3b-@Lxo%\XKAMBlr5-#Cy ƱHf41Za\LL2&sqMtK,s6QIƤi5[/2~1flÄRf|2׸/_O.׸? 5-m.G)K\|z/ow wSg"с NjwM#zNjp;Ufޮ{G{s5tb3z?dՃwBUJ?uڹ]s.dߢ1t3\% 'Ʈ{yWk˛W;8#0/iX֮|LW=e;wz^-?wTxVF'C~RA]{xtrիUcJrpm!_E/훕Ǐ 8r?zQkM×~9:G̏|Uvޯ.wdQJE:+<..;_^,X^R\> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:27:11+02:00 2020-04-16T10:27:11+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000004064 00000 n 0000005803 00000 n 0000004005 00000 n 0000003846 00000 n 0000000015 00000 n 0000003826 00000 n 0000004129 00000 n 0000004229 00000 n 0000004170 00000 n 0000004199 00000 n 0000004309 00000 n 0000004382 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<739D27D99E606EE71B9AA2E35832F0B7><739D27D99E606EE71B9AA2E35832F0B7>] >> startxref 5926 %%EOF acm-6.0_20200416/doc/charts/usa/dallas/0000755000000000000000000000000013260345311015652 5ustar rootrootacm-6.0_20200416/doc/charts/usa/dallas/BA.pdf0000644000000000000000000002464313646045021016643 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream x]ݖG;`-]?Y\8 I $YfRHP>y׻~=7߾޾|^fݻ~xyo^^{Ճo߽n_^~ss _==⛫zza#l--{rgO*knĚ3l$vGtϸ,DH?wO%v'Lgo}#c*Odo޾޾dbM;= 1 oG>Q[Pra+goijOЗ<|L_KM$3G9Lcy^W>#'~)}0W 8S`R W.nmC袈cbEzJ$'*k GcQS XѫDúUϫ/âI(}a4́*4m؍)5:|5',Y|# Nw\t]J5 Ո0WɆ%w+GC燭V,腮|@A*ͰtźFUvJ<|M f/ cSsHJ2 )Ps44kF{c(yX,%t$JZ0ͫDJH @7toY2 e )KV)kj T.X9v_EIb4/(ZQ_Jb z3rE&/tzE㤷(zX,%t*հ*V#˜^ezN酕D2)ZvEEȭW ݫt)۔1o*ͰV#˜^eY'/ۢ"WbT0+*LgPĝMU(:oJT,LGDS  F*հ}P23%p -84ѧxkm:\4:UϽaDbv!&feΜ`6"wƫEOL\保g ZT"o:A|Fw* a\*-,Hj5" 4*f>Si2su(9 ;A:2#zX2>ڪbJwQgX)FzlXd% L.C'E`Nx>eNk\YiʯxRS*dB]TF*EDZdJ1Ո0WuKJtGFKhIBB7PQͫ4b)Q*ݰ:V#^eY'/Ӣ)%)4&^Oy&'B/%xJ)"#zX,%tG|WZ+P,FQJ5[QSi!Ihjٍ4)/ 72#)k7J1,{#HNw lB(-+x/ju%U.QJQ,b/n\* 8!ѼJ3,y3/; #> D.pc9cNiy>*!-o) 7*Ű0Z#(^$yxPw3mnT88ɫ{^L}zrtc=/+za*u.*#:VRKYI lhSr"&u{tXEL~j2(rMLTp %t,(-`XAa$bvGe(ϤkSX|}Z(UbСK%VjDիTT}]d! bFqPZCBGn 1pxq*"IUaU`FJ6[ݠoA*"cK1~4gF*I ѥ" VEj5F*Ű/]}"^{Aia(uԭnC^*Z(*^JvuJ%H熣]D_éERica5X#PSbv!/ǢI[Zz9jq 2u.'m8b2WRLYJ + Hi#`L2 -FQ#9/;*|Q@qn%h+#{X"tiJ1Ո0WŹM}xbV̰9Ѻ]k Ji}iuLKUnC3WIyZFfW)U F*-MZB Xi -YLGpjɠe=9P٫d,TaVژΙQJ5+}22.R50Ef:/nhr'A'hVZūb)eLKBcxaXçb!CK)HX"wO u-CF0W%RL *Z^%Y /e%pެW̊p>"բg@r5oWJadnQ.S,ѽJ7,|cK ꯠXIT (VAF*ED\*ٰ2V#h^Y'/ %$ @@ĺ4)*bڌ\د]F*EXlS ca)mUag.?hزb[˶^zZGi,~vjXRaL2 K3& Ru$tČUb,&MK NHi#`$ ē/qTTKs򞵧Ylg퉏J>*Ԟ+zXӼ}Nڕ14,HՍHK-#PF*%gܨ*ppͻ0Wiy>|(8A[K<$=]p\hZgᩘkɊP?F*MD*HK%Vjh^U.ɇ$r^EI0NjQkUb8d*ٰ2V#¨^E<|mmS1i>cki}3 &Ss:^*ұ.Bu*Ӱ+Acȩ GdʘZfߣ"҇ѽJW,b㈌tkDӫLú'S_:;%Q*4{/yyD󼼮J[JÍJ0Ո0Wy:Ku,:J6,už̘}U墀ݼUm>K͌RªX10,[lG||V[%Z\{~pڎKHv=Sŀ8d*gFHNB]lj}eo)ժuXݫtŒ7ҵȵTai]l5"Ua鞟R<6E%ȀQJQ, >V_hUaI˴$g),>1QQGdh؂ntwy*Q1v#٫db)+Ș OQeѽJ7,YI>wr3T~C{isFH^%%<%,?mV`pjѫU 25 %sxX,%*^.lXȔa 2 sm@ܦ%툠$YUKUbBj'ɪz~a4<3WɆU|PoR܆9pclw?-S}*--o) 7*ٰ2V#@bv?Q1. os8̰jUb}Ͱ 0ͫمh3v_ -OC>[ sh3*4G:̱<hH]RBcd0ͫ٥Y\c~$Y11ȅ]5@w;Imd<711O_ ͞||OƼڧcRؤ46XqY?NRLk6BFHN;-W.zv/wl3c8\dZ-dXk$gjF+Gȇg-N䀠 F*AD _1Jh*pF*ɰnԗayAS5 lᤨRd=đ2W mARJ0,Y#(^g \1J]J=1S5i'«TjvlXRat Klb݈*e 8fQ$!aBC͌I6p?8PVp4LÉ /Nd݂켠f  φa7[d)^"U%jڷokLX ؝][t%{tzEǿx&!9i<77o{͛|Jؚs/P(cmy[fʙwݾȖXAӎ7ڶF7-cD|';{"(<d"Oȸ Gg\=jwe,`:\wWFMGH=ݾ̸Rd\}n\'۝hwl!+wEOe.~ܩW@KfMpǶ{i3t FI+ ǎ;w2qィow4>͋!R7޾>ZWQ:>vԣyig̻=̫|TߛG[wO 8Gcۗb^Mg '18we/ qq?ѵ={={q>>Tzi7}~8>s2(Ṽy8-N͓ái{}{ell/y:ͳ2NNkγgo_VPjϾda+lç" hCw"JP̅^dO9|zHլY=g~ngGO<ܶG>_mѫcaÀ/>kC^~weE9ݣ_}zdco`!('Hg U$?{dݹYǿʇu}:(iu iA>e=w=4ci.Hw2;[ʿ~޾gEGѻ(:cO_[~u{D߷O}lSÙcS|oݾoN Lgne,G_[>ew&읽}Y\wɗw#hؓgoGQo~;د6Χ#PNy!t{dG}E=6i*ũ|lY#_ B)ĉy8%xp0:?XڵwONXwgǏގ_4PϘwe}[v6x6>O ñݾKsG>/'!O;w2_~#t#Nѩgo_do??6lF2ENFۗu#GGrO{iWdW{9vH'F5g^ktE&\ٳgg-?:u3w/)>},={HʑA6Pendstream endobj 6 0 obj 8060 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:26:30+02:00 2020-04-16T10:26:30+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000008383 00000 n 0000010122 00000 n 0000008324 00000 n 0000008165 00000 n 0000000015 00000 n 0000008145 00000 n 0000008448 00000 n 0000008548 00000 n 0000008489 00000 n 0000008518 00000 n 0000008628 00000 n 0000008701 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<4C2D12408F9A7967F269BA66B11FFDD3><4C2D12408F9A7967F269BA66B11FFDD3>] >> startxref 10245 %%EOF acm-6.0_20200416/doc/charts/usa/dallas/A.pdf0000644000000000000000000004000213646045021016524 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream x}ْ%q{}}e6}<4V1E@Md7;~Gddkn @Fcɿ^ܽ8>{e;w_<2/.>](/1_j7wzNW_=W߿o^~Ӌo|zVo?wz۟_]|%Kpڥ_y/?~o߿{^^~x??.?zu/~W~??ח~Wݿ..5ew]s_=~<,9]]еHz렻Aӿo^C]B*>˧]~}oN}țVl{e6<_(Uח?EQ{d$khJk ߁N9%'K V1Mg(PY}m>>Cva >pvqsLo.Gⴼ78 6\Og)ե6R}.T klw_z+y;~kCmAތj+%7y3~,MOqԽ}r> oƗxO}_J ZKG_9 }[[JhQ3U$ ,"NQ4'}5El|C*FhH6sBkNA5(KNlb8Ar֕d=݃6betEX*A&+틽cyQ_"^wy j:hEk}J7ˑW;F:E/U9IK/x RkOil/oMGk5H4~ənI^I[+ljj6k霤 nR9#IYߧȑ~[ԕau t|[OяrFO4#DtG-n^ХYT& 9b3Ѻ@tMB$X[GqU1!E18^hmz.3+iZDJ|R)etgvɬF EH>dh?z2$]F!oQA =>\j -iqz9-L:%C*:PXrt]^V(LHQxl0i+jۚ5KY{靤 i 3|·2jp-|GoђotUE2b"%s9ɉ?*jJۨ ]MbIrORC(#P|/w">rT)Μp[f<QO}_4Wb<%xCQ_W/-uEztGK  4 Vtaq0G]bq\Ei#:>J-3 +/0d.$we021 +P{M+$1̊Wh%1{ Q܃q;7b_0dօE+1P`H+bc&PiLmKmNd_םLd A砭I:n*Bmԣ۩q1cIK_* }`z0#"y#Tz^'ejtڡev(8maLO ꛎ&##/ɄG}q3-:!̬5RxXFfz'`+:9'x匱tI0>gUaMgIt/,G {0÷E?2@'HX\dEdx%2 Z^h֖3ML^^WE&ʺU5 AF^Ez 쩴=d^İչZj3Nedyi.}j^ b}fEdEKKi}LY* øp [\8yɆ.Ô&&#(uɬ=ltnMcl>4Ĭ. :+(CQ\CI=ޡkP32#"ɰ t74F!hHXBdǵ3#"ѰfOZW<`-k;:k$R[L`yg t04:hNQhFfUr0qˑkeu~R} B' n }Pk7A2)/6H0,**+k%`,nL# k|P~K5:,#"Oʺ5 AFZEz'-ˠEF7BVyMG-r)~{2*蛍f=DНQeU䭟*l$)3O1ES4ů39".P$&(NpM {(Ow0f>k(Ox`LGhE@+[nfF\Ea)ҮpSDbq0"ub=ɴ FN@'4yTmĶe XF]Ea)i+HX\dUO;m-Yq`; d ]EjK =U%O O`8ңq^2qxcdQ Ȏ6EхTw-cF_ؽ Ho259.qHKjm\$B0pjY@hx{LQK`_Ea) {\װR.+yK CMX,V\؃h9n(J#9-i8XitrFd 1Ia/FAFRW)7{٘VgX:6 {S$N,gdU$M,|ml un&wꋧWlXEHXag!ȨHXOwdfK h3;t!LIǴzNa:s!NwdpYC& wȌLwudæ3Wc'4}H0,pFoԉU5 AFZEᰥl۷?n]EKEi3ͣVZ_EaKe"yberB]EĒFk2s 4l鋪)U%sT4í"ΰxqˑk%Zh:h: //q,0 dK^r&?\*)_r& '.,&l"ɮ6YM޵ ){P\JeybH {(恛ՊIehWN^Zܙuq(!K@8<3f~eߜaX亰WL+Ɓj_$f/jq㕧RGerپk>5Ohi^.}K϶LSw \l*X tTY$=ʣm|䴰"OAJ-@fx gFn^Ah2lD .xVgXR:xCO,OQ2*&y[3wF݌-:i)m V`XR:n"ib%rBV4h8ĥ}̬WU3{cdegc٧+%c_=qG*=I1x$?'3ael3YUUƫ)C zFrY QSyd8*7 Y CJӼ=akA :c}]d:uS?\ :/^ybu2"2Yr Z;,5T:[?QvD#̨H5ǻAG[os? aF_E2ooR逥خ&Y>FX$jy}mch}X~,azhh22cp3,"^ykeS:},=O 7O9H̥_iv]"mfdFXEa)ȥ)&Vxb=2vIDlfd%x\cjx7h[t"eb.QwI"ybi2-Tj80?EX)ydj(sJjJ)6OՎΎfF 18kQWjXc_lۘHX\p*'֨ÖuU뒎ڇ|vUȿ͢ˑ2* K@["abBQV2)luu1lu>·U$Γ "),uOF[Apoܨ:(1pT=`﹕2*q=SO,OQ2*'y>mY'6?T2;qjIYFXEaL*6L*466 AFYEpwj% Qc3Sj VfXmqD hBלIM[b)aq]yZ#z]8$nWA5~ƣ#4lyҀGrX>(hU'qֽJߌB5Q^q5rniIKv+M~ ;BJ2`bu7E<[#X/Xc0 AF_E27}O f΢ndt]o3NWq*)r z}G&D7}ĉ+O+azqt2Mt}<ܫѹQfE?f,O\&awtk S"S/:n Ak=V Mgh+7&8672* tڕ.kniI GzF1KngIN(]ȫH6qI!&f!ȨHX[A' 1#58N]GP3xG3*g(Ob}S_<\swnflÑR#ы$ҡzC$L@Q2*R&f CgQ/^磆9+)Lq+n0:rrՐ`>z.h}jg`5 AF\Et8ZHRaHDv׷2}h\y`bUY2"2BoC+-^#QwlC+Y@\CF:Eۓ.UJ R.Ёu}5 AFYER;|:s;t~8qfDF[DWm&L\"29ٲ:Vf=W\(xQ-#C8F;[0 iF|!R՛Fd0Kz3#f3q+2)i43*R q\X8\N<2F!hHX8/Sz>t_5b#`2Dmd3(qqrq* &&t "-/qG8I;-t MAoPC6QVbXmu~,miKw ŖJk1꫐Ty Fȼs ֔,` 34&3Eå)2SZ5/ XG!ԋ_ěr.МWPf3gbuR:&&dEd55ӖxJv L tڅ#gR-0U(9ƼQ"8-"nb13 AF\E'` 3ZǁB QtQWjX8]XUY2*'δf>8a;t 03@cof#+B7ƾFD "5l{$v!򃦣g `MH0,p)M3n"ybqa`gbKj|D5ҝFQPW(e+lÌ­\8Of \cVŊ7Tg}7fPF 0 (4#3* \pʘR$M,z5 AF\E-d%hzvZ&ܑE k4 Jk@2* 1J30F!ȨHX<6wZY>(2ny2&fL4#2* \YDĊ #"qbi̛-Ę'f{qv~j5Eߠ%Dpd82cB񧁓x;4|G!m ~;ipheU$@G8HX4,iI鎏EFѻ5[:]vE4pC-P*AbruQH$?Dgp1򷁣1KɁkUO'0LZw${(8^L$Z5[ ̼n("rDuz_G;oȨ~N.8E4A,&f!Ƞ*&2=*ɳ,5p^]qS!nawDKK`9cW:Y䰰oTZi바ce~dvCQVbXc̜o"~b`&2-&N͐1XlŨ1ک&uNM {v$L A-"SO[xrogAojSPYs#oWhX3b;Er "uba)Q1ևxz 1#"ٰ0 ևHXi.OdUN,|2eT|Ln fmyF7[vZd+@i`K̖VgX7<2F!HHXjh] ˼㾀PI.3ï"ް E`U5 AF\E oXlx.-YI I?%^=J[h%C(H1,]7D"{Y2XLE 性g`] Ya .|c˓ktgOF[-°[!.u^ì):Lv]U`fU֨ի:_%#V}HHXOܿ9AW[ذwxI,VΌ<ӃU!'VP2*&֨ÖxJcM! bsK4[ցdkQAaD[Ea)Ҏ)fU$M, `rft剀lwiAfE? H`"ybaVf*zm ]>,0{U,ב DKJ{"!x(e)K_R,8ԈrFeZ(H1,p )&?1 AF[EPl siW< /GFѯ23#2Ȍόl"ibZe)K WSVik嚾+ G(a \g1+"ebrBV4͖iػ0k\,|촧QkofFfU$ְ|`=E|XdYM^/w88B!kgHEjrކuS'?C=uz_z,I^XI{w,_b[ծWߓ2\闐ߥwo6Ae>cqo'6|} qXov,~aѮʗڽmĐΚis~tX|o7NimpߖON'C>K~DPHA5_3wH0&`q'?c"uoS..ޕ zq˱C9MI;Imm+cWO~FW[l zҍٖ^rRok>;m@N7\r7woFkȻ0=X=Ǩim3',qhgcۥ>_Orp>|}k M`иByLy/[f׹js R^&?ܣxE kw6 9MAڜSNl5~r=q83GnQO>8o)fn9KM7lun]y#|;=im\:x;CA阯26t;OV,6B;R#Q.~c.k3ыg`ڵrgɷ)WNR<*TvYV< {adYYzwnڕ۬֋vrÏ|Xi zmگ4&B}XVJy|)pγ_y=9svi %ET]C}k#uu~q ~|ף'cO~FB'K:hLt|ق6,k囓5-I7z]^,^yRǚ`;ozrշ۔sWի P!.~ }Ncᛗ螗Rݜ~1約 cܡEBS븡,kN9`⽡,#}>쬁zQ]3Th}8n *0xa| ![A ZA;z}$m?ݫ[ e#|Y`ﳝޮ}'IB}"HnӛE:I1R} ۍ.vzՕng47?a+A! @4N}fuk:]+Н^[j5Eh/֐@V4>Ы< j:„XҶ'us1$MM5 M~ TW_uzCc5eǷަy|r~XǮN\w#ZIIzCiHa$ke ^YRêi+V}s|omvne =Βo{Y*Џ=_W~z$V1<">:䃡NoMM~VK_kt|•6=~A%GiR4W;lY㓗_)Q'NJwf{ '>{wL֞kΒo\8Ӻq/n?.9`Zr|si=` ^v|ccH^aLK~g,4u);#o HJ"{])8s:&xQB߲UglEülma4EyܺNo~7\@FTKux|[H@o/*O=P7CY, qį5pg-uw$fWbWvd$8jHm7kɈ\~ };.ݱ Z _Oendstream endobj 6 0 obj 13786 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:26:14+02:00 2020-04-16T10:26:14+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000014110 00000 n 0000015849 00000 n 0000014051 00000 n 0000013892 00000 n 0000000015 00000 n 0000013871 00000 n 0000014175 00000 n 0000014275 00000 n 0000014216 00000 n 0000014245 00000 n 0000014355 00000 n 0000014428 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<2F8AD26EF24AAC8F84E3E965C9CC63D7><2F8AD26EF24AAC8F84E3E965C9CC63D7>] >> startxref 15972 %%EOF acm-6.0_20200416/doc/charts/usa/dallas/BC.pdf0000644000000000000000000000753713646045021016650 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xWn7SwI 6A NShre#lK 6y eH׶|3HΊBJH٪ν6R4bȗJzA(#.MQQUst9|/~؊?ޞWϯ_~LÑb6 bX'm;[8vnv}w/} NϚWǹ+G>-b}=/;v'e[o^0I=< pF1G̻\0dzTkeͯ d~Bj~j~2?`] 7ƖN7oj~ Pg8߂zTwb<.-cH+T΅\h(hKHx\%l;(LHՎ0Xfl%csy8q4'zJ8Т&(7Z&4C/td"3{\ !I!fPP,IƱZ+6̯Oybu\Eb 1b"D^9I2:$\s~%=`Io\#GMm ;u>.Jdu\E}@}#Zd0uX}.O8JS .!V_&X}2CWI†XđkZBg%Nn !d'٠؋08q WIS L*Y06D '{`P>I8$#+nC.uPCdCd"/!XB/\+'IS$]>.U@%kޒ6ꐐR_BJ!nr$dHsXWFr:9}6tHa>[> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:26:35+02:00 2020-04-16T10:26:35+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000001660 00000 n 0000003399 00000 n 0000001601 00000 n 0000001442 00000 n 0000000015 00000 n 0000001422 00000 n 0000001725 00000 n 0000001825 00000 n 0000001766 00000 n 0000001795 00000 n 0000001905 00000 n 0000001978 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<3BAEC2EBB87B5A0E464222939929BED3><3BAEC2EBB87B5A0E464222939929BED3>] >> startxref 3522 %%EOF acm-6.0_20200416/doc/charts/usa/dallas/DA.pdf0000644000000000000000000001007513646045021016637 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xWn7}߯[ ^û>MMzȒ@GR&_t.$rgˏJFi-ɲGu>v\&K%:$euc*f.t~]Z]of^|s?Ο*̇ot5|Vbz~?L'z5ݎ>mǣb1?w~.&c6gFϓﺓTM6S\)РO;5l|1}>S~|fNmOnyөF~>YoͺFrt_-v\zʹGo(Mu*:OZfH{ΣۀZmA8s¨{`_|+h^}N^ |c@6b-;,]t(p!0B"l82848UHXLNLSᔉD,B8vm!=G1 A?&)mCzB􌏣w)aOl=}CڐCluCɩ{Wk|)gpIOԧ4;?{[:cÐWh] +;m ([^gx4PjhYqؠǂ9˖ZpB~&Ka|k4?83h-dZ{C,뤬Ӕ HQ`gb` #@"/A\[o\^ lÐиf8\%`j#W'hB)= хGqm!qE񪃰!и0Khi*hg*!4彍{Zʋ!P޸n\: CƅuE06\xE,'NV"#0.bBl\ȫ "0 *_4CΨ -?F-nc`2I$D`Q>㍱0YF1g>Dn { ֑\[ɕqA`!q:Cq i5!3~ﰌbHr#^SQCR\O <| iyqh*F u.561v!K'o@v+eSJ1X.[zAz]@?IK6Vj>yU67DAj )B&qאиpA`!qͺh*.ݟ/}DA-Nw⣶y>ەn@@Oy1i3:I{rgVqtᣏL>]q*6Nؑ5?cW|&k<9N c: } O{~|Aj )T> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:26:40+02:00 2020-04-16T10:26:40+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000001882 00000 n 0000003621 00000 n 0000001823 00000 n 0000001664 00000 n 0000000015 00000 n 0000001644 00000 n 0000001947 00000 n 0000002047 00000 n 0000001988 00000 n 0000002017 00000 n 0000002127 00000 n 0000002200 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [] >> startxref 3744 %%EOF acm-6.0_20200416/doc/charts/usa/dallas/AB.pdf0000644000000000000000000001130013646045021016625 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xYn\ߧ]l >jDZQA#1PlV+KJ 6~ÕT[ɫxfpp˿{}X̧5_ BSW毧 xszP0.T^-ݞ]ngv{C>>xWbIN֛ryiiIn~u--[-Vn{gdbmx^vK _@dձ9^~ؙ˫߶n1t[mnorZ_ooVgjkon r"N@|ZI>X5ZsYs)?>-?YIT5W'RNN3.0?;i9ĉ851o &ʷo݈v/l/ G~'87Nz&$c[ 3cUBp15<9Y_ߙReDUM~1N/0zLyG޻ a.)9F/0z;=>>ō􏼏%7Lݾ%lfTOəkK䀔.`z@O9?ۑax0?L8=i.pw9g? {Rx0O@y3 #yBC!%87̳`DolLYTBk0{&;Ϫu.W$"ȣI.O'MB#-v-muvCH1Zn)Aj g+/Y6lTޱfr:J,*[s-}:^J@(p@Yv(Xt^4_Wlgu"x+9QԔF 8 A.VݨL=&Hj1dv.+Z}ךE9ԬJdPo=OMG?Yu6 +VDq4\Nguu0ۧ+ʙ*ER)Yp1)ZVJW.l-v\#֪ &sQ3|@i eEC'>xE1J2Ab ^CLshIDIQXbi3mgȱq6}d Kbi8 cР Ȉ,0G\%8GIfB\XN8%y@k6).55(>qvq}c$aTM|-!׼&sj &sKXajTáq6R> g'W ,)EhMZF\Ug\Zm$t.:&_|Z1Q0eh yP1SIlT T.lYu6˪VDn4qԕi,Sd͉BmzzDl|*I`%r͊֋f% &:8j7 q1"6 p0~ SR{x.%EkFW.Z v.T6h;zRЇ\SX P_5VaA Iڤ2)24ԁU-ƹ$U&97.F$*dK?rlS`jƜHZET*ȣI\%DҸVD5~I(I,brOO(ƍ=1Qڥ6ә9TD]ѡ**k @j &sQ> W$t䋒@1C *I\%X8TM"z T 㓲^TEG?A4-,Ճ'/4y.8E~}lhK<WT18ѣn|JOhtsˇEƱ[)Υ siWG=瞼|sҧC}Yg<{AB~86xɷtqY5NTB*-}aԆ t7@7߅om7xxGr"{ˇ:Hq`̻'ƌہWҙؚeԖ@l{aFOJOϧGfπNi'sJ/endstream endobj 6 0 obj 2202 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:26:28+02:00 2020-04-16T10:26:28+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000002525 00000 n 0000004264 00000 n 0000002466 00000 n 0000002307 00000 n 0000000015 00000 n 0000002287 00000 n 0000002590 00000 n 0000002690 00000 n 0000002631 00000 n 0000002660 00000 n 0000002770 00000 n 0000002843 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<4AEB4992F9BD10ED2C1763ACFC60CBFF><4AEB4992F9BD10ED2C1763ACFC60CBFF>] >> startxref 4387 %%EOF acm-6.0_20200416/doc/charts/usa/dallas/AA.pdf0000644000000000000000000001425513646045021016640 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xZr7}$U/G8;Z*cVJK)'g:;4h9df;E^mzB8fdtv;8jͧ/voϧί'.?;IL LۋwOWyҿm}{q|H's;gmEC>dӎzxxrƙG&聏wq>遏&4di=q9-{':=qɆy->>:~} Eg3#Iď]0y-2-_vrmUvms]"ݯ.Ye<;7+zGkg7O_ Ge&e α r7DItI4%͙BS/8y$4սwV%ѳ$@(t>xDc9q=9XBNVa@وi.Nm]$|٫ 'zbনlS $aO , @y& ;3H:2颿֡L5W3FF:^t MfMu)S\3L Uy> ڑɳ*HIj\\cnR:WQ.D+ LfzJ<>B_zI m5GR)6#~iO~2+]Y^^7!Z<ǣ bAQhkG J3q W0K1w?++\KShڞd.6F#h~E!g_bNp5" n<8>`%siFr>&eLt;;E AOJj L-3-’*}xzvy*mJHsY`tRk)Àt?`;&S6jٛ5g|XN^n]Cf7;ea\rI!( RQr4A=tK$*\n0D/TK+Ҽi#]ϔ y> ڑ *kS* $t Zh;7Nn,e>ă695 Pqsԣ o,*; |_mqUW1"D mR,TF\Lpefb: {5~`!J rE h╋Eb:W q4I,MTpn]E ((4$j"oSɌ@WF7$c&F B'1Fh ZFLb犢: &sk,MRZ:* ;pQiJ6=bD~F)k'D|1+V4őO<[(4\1t,}< AMr!QIJ: &s22oXP]{zr4ePt"{|".D&VX &s9j@Gع. FJSiG'"TL`:j1:I\z'%^%aCTglCIC0H%#lĵhA(<b\o&4.F:L_<&c4yR 8{(2Uo%*IT.he$v(Zh;F$ Jv8 g*KY7cJȋM@1tm\ȫ &/<yȢi&sI|z',դ%/|O0&9yBFi4Iʥ9¾Ab;W e4)#_XTR6Nh)R )ѧzU*i^UF=*AR".&sj@Wy>s&'s8k@Phx00F$(KYLb犢:i/n1Ir#XƆ=jTCvTBDAQ8hEF[%XJn›pn;@WDX 0ZI0m\LAg c7ɝKb;tk,c>Gj6Epr(8KD~=Pa4 Z1hQйdN (I\6].r$*7Dp&\&Id˾ۥp"ZډhR:y)#Xi߮!waoN *_'haMrAFMJm\EffDa4 !IpıIϼbD6⬣0b-P]L|: &s%o;O r U.xLSơ`bS6Td9eDh5΅1-@Ɣp7.XRoȮ~7nFaV&n.U{3)ߍWNDFй.7:2mWǥ<QUޅqBFfPUA(<$VJ5 K n0~Imb u߀KhUX$<686j;W u4 U0sH]{ G 2scD'*R~4Z^\NZ'$wK]ꁾjE,Y hRki]4D"ꊘtpi,y󽤷(-DcҸiX@Hϕc^e'~7#ZffbJbDZ19.J—$ZZUIjU% h Z8LvժsEj@PGڹK8/3}ox"n _ZbD`d%>j%j$4zI񳊵ҾolFG]`ڵGFߌwW6Pֹs9wo{wzoT`|q 9j>εPgᒃsi7JߌC9ˌkNcg\tU:=] **i׮l>5>pvpɞoTPj92Ͼssa2N8%!c*4?:țެ;|)yu3r`"?{`qNԿ߳!Hw{`qЎw=qɒTk5[_pe 7pg/9Mzՙ+hiC92ru~sizkY%;='2zw(gg/>1UZ> ڛGJWO;l>zCV ''O^͚T.j>row߿ F܃  Ym#endstream endobj 6 0 obj 3719 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:26:25+02:00 2020-04-16T10:26:25+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000004042 00000 n 0000005781 00000 n 0000003983 00000 n 0000003824 00000 n 0000000015 00000 n 0000003804 00000 n 0000004107 00000 n 0000004207 00000 n 0000004148 00000 n 0000004177 00000 n 0000004287 00000 n 0000004360 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [] >> startxref 5904 %%EOF acm-6.0_20200416/doc/charts/usa/dallas/D.pdf0000644000000000000000000003733713646045021016550 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream x}ۖ%q{}y֚֨I6)ȶ.~.uImeU`@\FӤDlDF"@'OߧW_{p?<ǃg<~z0OO뗇|&Gzzwo|z||5Ϳ߽ۧoWͫ߿yw ??ӷoǟ\p?rGw_?ׯ}~|/Nߟ޼q߿zo{~Wo^^7o~/N|{z۷W;Ք)7w*Ν} SeXzȣ:2zw`{7UA?m]ȣL܆?;?;_qOp?Ɲx3l{f6^<ġq[zҧߜڳr(]|':b#ʔkO==^Oj lkC? }ѥ zrW6I\l 8هO>mk/?v[Ʃ!,xא6s[w&iGhG6^d nx}g"|w㇚ǝ~,>ɻcS;}RIލr|;}rJqV )<>Sl ;t2Iñdm屌!'߹(a 叱UL@8O$]󏱟8N8ǡ^JiTq8*GPgy_$˼rp#Ar]64qNcn8L|.'wg0XYrAV?ItOH;.gL@83Y 8Hby 1DѸ|rT^~Ѧ#i!~'6Yvſ oI֋YlO Qu8X=S&V6,k}lSO=EGO3ũ堀3/iOБKtNşŘ)U7v=advLKqV6I0N'(_}\?"P E<8 %uNxcfb=3a(iVV]$N,pwՄ5Q.,u.h>A `iZa[v: wckU]~ǹxafQOUPY.N> +k6ŠKz:wI: (FL~Ɵݡ#@'c&9>sB=s͸W1ycIQ|ۯ `8 *ց@D[`řiN?Ere""҈0^kPM-FAǍ?CGҞ~c,oK~A>*]@D tcT<[yX|`x QY(xH"IC!t]Uv7 Aܵg H$.(و*v`)&MOұ(wtmjB!_U>f_HuBPU7w^M1Μ0qݤ rfh8KfP ~48)cLv anCoʞC@4"CDP|sÇA֧Hq'"4Z62oceR\,N{Z(~rićOkeixLMc(Nj=m , i U]$@1J%.kDmi y!&A40~V)fÜ,V6!.Ҳ!V$j$Md%-a4ib$7wSeҙ]uj8$D 1' |ƭ"ΰ:"aaqFXvvu?.AkXy2V hrbEa ƐC$.h++.RW&[I3܈-EI{cFb"l"RXy+dXD ⚍"}a=s=EQ1~;FY(M~Kt`"ajhTc_Xвlm@In ѧ6:%_ddDnIaӌ@я(.U %'jaYzqXLZ.6*9F Q mce)E.y2%Rܰ+.t-X$mo؁cs1q=zBm~8qU&/jl~,#)6&b=)E f4t>Gh.8A"֥-uכ$7bȑc31\WS+""ٰE:HXXA\V]/gL۳֐̡t8˘dQpжzT1p"pC<5`W&[I MLr#Ϲ1bp`s hXZJQp +. \ )ly Sdt13vi&W)I-(PEEB9F˿;D*⚍""vetl#Ssu ^sCG~ VꏬH 'EsO &R/Q *.;8x'rRR22bHjZ/=Ź좵2p=L gDagX+F_=qƟ{^kC5̧~dU]iqa}*.еW@4m~}-܊k9!})K~F .&Vl`o"K?m'hk0,0Zhu3ϩ_14\M3ZC$, +.LFtpuκ(I4نyɆE)lu ZÖu<dqbp~Sto'i㖤7앤 [5Š,pM8ʁ_ izj%xzYQ=繩H {(,p׍.3hJX^ǂJg "ł3cSf .~XO6lK9NC*+M^gFv_r~ zCGJinM>v(92 $0Y@I>ͦ\3NQn\M85c7,[3NQ!ly 1cM!7;$QOӔUȊdҮp"uaUfb"uaٚe&fӚ13eJItARG&U]$e"7왈caEEYHdgNX'B vI]Vi:Er⚍"ea=σɏ=ZVEEa+*BLf#(HYXX#I-ˤy1eUm؜f& f[E|Y%-d EXPY""9*8{/1F3|mTƋ;*. \Z"ia%ka d8êyeG3""ٰ.ݬݙuB.Ra2r 3ϗ|'C|I4>oe)e}&[KYVyYzA26Z`gr1~E.Q)eY""qaY̓f!wYfu )Hs(JB ""8ʧ"Me"ea!QFЫTܫӱL,8 Qnq@0l +k6ŠQlx!O5L=Nf# ttg_K9fn.*. \ΙH+>U],,!ѩu:{ZYBcvZcEEaK:_X]"ea -uefKZ /ph 'fPh9`1f?t;"epf/""͝FHXXʮFXv֎]cǯ&?@:@*e\քTQwjX܅ZsC.,IV]/,̤a4߂U ɷቀV0Z]Yo0 n"ag) K{1V#юO\"K/[}_=kn5}ެ@iIE.' Nf#(HYXveY),6ˋ֖F8 XE1֢l|U]Hk!Vly ׄIVÒ/5[Tdi ڇH^XY\V].,mfm eF96d ]Bzo(%1[EEaY3΂Š⚍B͛;$M<~(ŽSS,]sYEyɆgM$, +.R%AO[IC ibmOHb8,,)~VvdX6#c^7@U]-,XAyMx͌RܴYQvbX?%8oJ⚍"ma8?m&pZIbEY}^{d>#Z᯵ +2b6Ⲃ[t~qVq 7NyhϝfF%ty/3"ٰZf#H]Xs%s1 k{-ML;)+8WTC:*7-HZxl+&ҙȥ$+sf#98!'aⲱC IgDaX(n{[(̇U]P#E6M~+X41Eq.,5b~ ltȼ}9l-.C[xi tژ xA dёS 4D"lAyr|HhVO8}~%٦V]$m!ݴcc~QEE6eiN#A=~;vzH7O^DNΟc.;R)&NJî󷉃`rT֩#NdapZt xie"ya)QH\XO!LƉh)cܣ!^fev6{`1e,~(@8I';gO}itM!e|aH>z?ollWokV\O־0{L.,saEEB;L8HcA, k~bcLArW\nb-]]Ձ8I8"b[a(Mh³m~yG3Unޥ iR͟6oEDCuOnߥGM~i}b[??At6ϔY|r{ }>/dl#ÿfi0k3ᰜiv>ǿ J9|x|)t1%2)w.|{ګz\˻7)O.w4iʫVM-h_|p*K5y 8t|D= ǾP"qܭ푇 )ΟS*WK7=U|= ý^Y.┠ p"wN>W' Q};>!_5 n-l75tC!fv qͧW1새KC7&lw-sr'T޲vCްe iz>辏]< 1ta٬"}گ햆pnM.vsbׯ1Ng\9 7?`s8 /o9 eqrŭ'!rI('!G{k}ߧpxK!r(?r8Gt]zBTKg[3$,R_c,GǕ`:rYq_P?ﮕ;^]=<[=cbsSY_R!kpJ74,͆?os[phƠpzDoߧ[gh-" U =| ǰ9ڎ9g:0G(<jo[rmmW׏>)E7P;5nߧVc_z֤4\v8M,Oyu8v=m|VN]a0\bHQWt碯 7Ӎ,n\ " *7LwU܏Vz#p[UfyضHW#_~\1Y|koAi]O$ɬ.zZ骧i"j]Jɖ~U_l:^otl y~r/+r\Ը ,r0-8%l=b{6g !,1dj_jqoS=ԫټ&ByEKc9g_ 1x_9܁/]ojܜ~d??/f|67MKmxp<:mn9!hC=L m>cOq BT>q_\_ݭ5nq>>RB2J `=g\ݪKUUlj޵an9ןfOU݊b\(uI^ÿwVW&TDyLΐfyD֣&aRr 3L/Gppn~ՍBb֕B7 Y|2 2?8C^?d/~.su{E"+7'f~ܵY|W'~εnNBXpFhq;Ͽ9Gw9 Q|B#ϗҫ/or J*3 #|rO& N_fq> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:26:22+02:00 2020-04-16T10:26:22+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000013819 00000 n 0000015558 00000 n 0000013760 00000 n 0000013601 00000 n 0000000015 00000 n 0000013580 00000 n 0000013884 00000 n 0000013984 00000 n 0000013925 00000 n 0000013954 00000 n 0000014064 00000 n 0000014137 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<271D243D6A5BE0A81096FF8D1AAF3A6E><271D243D6A5BE0A81096FF8D1AAF3A6E>] >> startxref 15681 %%EOF acm-6.0_20200416/doc/charts/usa/dallas/CB.pdf0000644000000000000000000000763113646045021016643 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xWr6}W-LLg6$SM#MEle(ɑqw!2v'e8< 񓐵~u&XWR\W*A/u A(#f*(Qٺ:5۶y&^柯oӋU6;qyr}.^n>&&Lw^Lͦ}Uۜ퇏Ⱏ|n~>|_LsVg`%<}R5x: AJsŞ޶ê]]e9jgb4p=Lb7Wm:Lj{inr RxcA '5ՒCs_=VV; (:ci-bo}‘\xb#'?qZ ]{z$8AځmZ k?h*,cWI^H#=xWl8ztm z:zM;?Po*ۨ{@ΗuCx‰Gz?/gyOi B 4 GdOJp4?P#1a^;vuu'~@6;BOCyZZY-౴48IGjSH">c@0豴pkac0gZADR ZX5ŒC”c`cDS>)ǧl:@3K8Z)0:fiUG_{G].s14H~+\KCBw$_E !6 ~\Xsj)хKn@ גO<0Eم+:⾳vcK su;-;(\}SK\Be$|d 1C6`ZNVrK|,R" LY X0 'gӎ7NsblM׽4 kyݧ闘EYADny~I(\K¸P T2d~ld:&,+3_Vc/\>eupKLኗ; ;lv+Trp<_P:{08\\EO@藄E5Rp!٨,{EKܒmL/lJL2)//oU)]7 ȣQbZ\ t~0 ]X[U<_ @᣷8gXD8_+xvnT%GޜO'/.^̣Fe=7ADAۣѼ|GzҔ@7Xendstream endobj 6 0 obj 1395 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:26:43+02:00 2020-04-16T10:26:43+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000001718 00000 n 0000003457 00000 n 0000001659 00000 n 0000001500 00000 n 0000000015 00000 n 0000001480 00000 n 0000001783 00000 n 0000001883 00000 n 0000001824 00000 n 0000001853 00000 n 0000001963 00000 n 0000002036 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<56E067ABCBBB1CD32DB494A8FF6B3D27><56E067ABCBBB1CD32DB494A8FF6B3D27>] >> startxref 3580 %%EOF acm-6.0_20200416/doc/charts/usa/dallas/CA.pdf0000644000000000000000000001246513646045021016643 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream xYے7}Л!T~!b8a3>nz`=303lLInmGY$UғQbyԻۅV/38de:;_HQ.T:\{Z_ͻV=p}s{sӣ'g+7W~<`{w\mnPC5MKw˯j]Nw)s^yhƟ-=]mfV?d{bb{qCRo/޽SmWw7߫Fpt]m\OwrzvzwU7f3ſ ˻EIV!kV79 >;l?]0e n[䥟p!ͭ>{[`N{u\C|(7tKvF l|Yyпo,V!fDұ­d3a =]#H^*8YzE)I^q&wzmq6]6KJ8z:*{cl􌏣9Oq*PLg|}(n_eKL}>r<~'{cәaKOh cdi/ 3Xo5I?0cxwwwNhvw)h~ⴓ͟ag5?`b3WY8m:lNBw+R9$Zgx߶Ki'R#3Fa|W4S&:8w`DKMՒ85WsӞ.pFԸ",L3)aL;|7]\=03 .px~'p 2EDd3+DZsHmDرkI+U:vBf'y2N&RcZmf7Vɱㄧsc) 89o䓥?_}b%j/MMW Z%d81O֋TBm;|4:WiyEzB&,iv$,``.8 Pȯȥ%{υ*NTar9tnM 6^d)P X/!ͤ? AH_7>P:"Ả-A=],^DMΘX"б_u@fZu|vpb=ۣ2#\UxRZ{_Gz2w;E^O9w./^m61$vsl<1.,u!3 E󁧨+{1f۹xAǐع\h\m'{CbXF|~7dO #SpO.';˕ d\u\qOĎzEr˧/@6Öˁqx@USJzxN UiO-~=`qj[b瓳GOphq; a7endstream endobj 6 0 obj 2831 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:26:38+02:00 2020-04-16T10:26:38+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000003154 00000 n 0000004893 00000 n 0000003095 00000 n 0000002936 00000 n 0000000015 00000 n 0000002916 00000 n 0000003219 00000 n 0000003319 00000 n 0000003260 00000 n 0000003289 00000 n 0000003399 00000 n 0000003472 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [<2F405856D422383025CA7D2CD9C8FEF2><2F405856D422383025CA7D2CD9C8FEF2>] >> startxref 5016 %%EOF acm-6.0_20200416/doc/charts/usa/dallas/B.pdf0000644000000000000000000003636613646045021016547 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream x}ٲeGVYs3~H! )^ڒK^PY&)iN;@Ul vD;a)Ë/>y?ONq2xz{'G}/7qz__<~7߾뷯_۷}|ޟ/^+wA {~RH|?6{?z??=|w}ӷoޜǯW_~z_Oo~?7w_QxS/57j~|;ˇ*57ɚ3݅=2]际NQ/P% WOO?w}'>M۞ ,z5mfUӟ2Ef[= 9I?.!.9%SIV9]QbR} \҂}|1>s0i>׾_Ji_Gp}_nP<[OύCVAZok)?c~:O}Dy7~1 ?: >ewKKS/SK\y7}}Sڀ"?2AVKoYc>{vH'($Kw#< Cyyd,|6vQ+iVǑ][:AI7c#18 ԅE1p2p_M8|EǑ99Alj8]ZH4{MѢ 'gځZԌtX8K՜BΜ(hj9NC[9QjQBLS'kNLÌZ_L"!=,:6J2ZV5uN3݈TbP I9U[B7! WkжSk$ˉS9ZC͑ ]7sS$7jO-4Fx)q6}CqE&CUlbz-À5R{"!GGܵ/МZ5 d3xtu:dڢ JV&(SFrZ ]uM:ѧ&ӭ#!"M#ܦtQ+_V4)]]hLoHm7W,cXIJzoeԂGipXmt8!:I?&Fjеe@/dQ>Si/(L:2'1=#;f}R0>Ec tuEW:hw~wRq4.1YC_{ QjwȌ]$/,` 1X%:jFEʁtxeąW*:8`Pee]$͕Jks+Vkq+YFEc=5ݱ}>d=sTtk+X͜0Cwx$JZ #"ѱllu,Lph* k\Ú01+ -&<vЊb$a( p珳.VǧF N cbn,|.W y:whX>.-|Nm/$!RKG#6qu3F.F<;h%I /v5>'qoHs3\dh6Տ$h8>z&2 gL~4:fHq,L8B6 8nT$wV] κmwCyے0%tgEWIt%|iCYR3*>H'.j v5AXl3f]$.eϪݖ.Ef];ֳnʩe[\ihC2. \8Y"ձ*V!(Hq,ђV-뢣+8Υ_H~ @}XOMGFr+qGIO/p0 s αLVV5󲬬H.{1elq 6(j0JNKLu`-]qտH;ur e.(s'J#kظxփz>,H.T`a3@rؓءj[{0}:L"8^Ac %~˩saBVaM:M[/-xaVF.vM\fdh.|eJC\aײvW|h.\$΅X}EZ>bQF$eiE!=rn߭WEFEa0\)3.B1wXkl-&bal#c¤mhI:liPX"vdXFI ȵ AFEcX]BٰP] $SO6*ϑ@8ֹEoS˜p ^AOc/FCS<¤⚣"C7~XEJFDPŒdz~(Q`ޢH:W\u h\eFEa)Εɵ AFEc=?ؓіq%  4='n=ьY1}݄=Hav[~}H2,]&p/X\d]9ֳ=G55Aˏ. ] vzDchnqXpB7׋Z͖"˼.L8RF3^WF9B|,qR'fS0#"ɰ qHt2VaϹ aFEcm-"cghѣqݢs pzQ=6ŴX3&\ѻH +OX śYdt?./j1ZW;6̣V;Da[hF mXe aFEciX[E2~QAͩ%5hn٨P٨]54SKI'8BMmxzbMΩe .ÚnZ2. [.Hq,"BwXSJe]tTXf]hλe2!qtU63E9>?ÌVybI!@sHH2,MEtцX\BvXjt]땋q1-D5`- #"xN͸L8V!*iIDzO.1r{sټe}EO;&뀛x"CJ.}ddMX=aQ撾М2"ͰphQ64%.B,c"ñ-Ӣs ?f(H4:tbFú7~.PFTd>DX4pa=8 Ƭԋ,q!1\bFEXg7?rtZ c"ñld&LFjh; 65m(ϵ6lCxvmm(eFA 1x$ P!;i0D >:fzīfv\6BȶBd1p$-Q OB#ve&kX}m !]?.l(O3Cwڻpk8-I0Ê@ AFD\/Zm<$מxbd{~qucD{[(,侱b|v駃<] :w?8;>ygc.~6VfggcMv v6E\/ںopC$H0ֻXDrɼycDKՉguT8^ʲ2_33bֻ&vbJfsd -ₑD Wo -jFEa)h/uW^3.2A/XoEǸs+6gO ]v&ŚL&Fg]sɪoóD\uܰ wXFE֎&pF%hx rY!HHr,df`_ ~7r)0''2ýg~.&wďZ2&\JW7e d%zN uiyfF|>KbiJC@sQKf];Z~S#v7Y^1Bюh" _(QvbXM8?2m&bB1vX h[3 K/0)-2./MGEcOBwXf%%gkma&mMJҍ{#J4#>@J{4ҙ0\$;V&*D3X^A;UbNm~emQ7I,Mg];J .Pprvׅ8'2>49z[Ɏ]7RcA/K; BM z𗅃95nqAЬo~O^vN2#"ё}ɵ AFEc=?hB%(;lwu*'nNYD@e]T$ީnXNclx_!ڃO;d[Xa >u&kc"0/iI:eˆ qˌ ˋ2cI.A~-_bDYaRY~ b">(5jP>SiW|HshXa!ȈŮo Zsz:IʺK띟[?<>)p+.>oB{~_y_7__sEׇ/TyOWؽɄ&7R%Z~Rfᓓ^ӫ#s|'sN4:tÝwbgLK7Hk;t{/D"Mwe6Ån\V?Lwr\TǿzyeBN/7rS:W+i:⫗nWoT=\xۭ!=2 Sf_Ձ#u}-T b5sSkUD';[G_\w0Zʥn~ʜJG'o'z~O- sk26aQF#]ڭ Ev+.tF@ZG_)JvZpiLMmrm] f}5KQPK j9+\n%ߧZ8g諟%6TY.fҥsnާZMzg//?Զ/6z4.ޕ.w 愛b_bv@n6~K4J_f_j+tܵw7Yk7j vz&C;OJjzS5\y鸙|bzvkڋ\6#r SuFʵ?tz?T.-(rl?&TWFu&h3Q]h?6āz|UN/㳟z{Wsd+r!η߮+WOu JO9D؊,Bۙۅ-f}njg~Q]}Zs()N_O/? xߚ%o%_ƲDq3&I%~t"zB7yNtӥ͙/U">ڡpчLO3a";X.|ryZZΔ;o dˑf}A/7FWF4Ơ 7&M4Ү;y- X.uӝWn4iXnx Ej}wd6H:tzSLOܣXrL~۟\S?" O zcf}nI#P.sͭYZ=-L1o/?B\|zjF^)Jך«/>Z(_nk6{/hgSr0ȯh3Th5ogcnv!i]2+θ2K[V" #|7az庾]&@Kz)ڭ%|vʚM\f}y3xx=bŞ Aդ9vk|3:ټb> /=rץqv|rZVpŧӯŋ?nQ?ϋ}Δ|>mb>Y=;\4tsJD3?ڔPRms3tnw ^ث?<_}uiؕsn%:'+K e=㼹HG*.?nVnT-:պCg?`~v]oxW*T?߬+Pfx^6wb녁bֻlt]||gZ ճ/?&+mpE}]67 3eW(S9jG3=WV__0h+E~]'޸|f_]vӺM׀O|lJs]R[5nC,WM>OC_/8Sf]9L_ӹz]'͋u3Q5&Of&5a=Jʋ }zS| aBp2͇endstream endobj 6 0 obj 13008 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:26:17+02:00 2020-04-16T10:26:17+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000013332 00000 n 0000015071 00000 n 0000013273 00000 n 0000013114 00000 n 0000000015 00000 n 0000013093 00000 n 0000013397 00000 n 0000013497 00000 n 0000013438 00000 n 0000013467 00000 n 0000013577 00000 n 0000013650 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [(\273{F\242^nL\337\34644V+\342Pq)(\273{F\242^nL\337\34644V+\342Pq)] >> startxref 15194 %%EOF acm-6.0_20200416/doc/charts/usa/dallas/C.pdf0000644000000000000000000003704013646045021016536 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream x}ݲlm~KR5އ? Y%YNF):R:V")I*o|@,v2},KM  /ߗO>?.zקȋyy{k0.\^y"Mz3^^}?FR|_|׿%ܱ/^ؗ0WN+^9-+$|W1=rĜD Zoك/A|q2=D⟺tWaWyp?֌ v)VKuZJ^ kIy"OeF1 ,SҶʔBE#1U^/W|b.5̢,k0% XhbZPKRIfطS)Km ,cG(=g8Tb*iI\K*-BS @g8c׌g!$ cBhXh`( V.Ŵ0 S-!j',S$^(K̴&6 Vui4 *#n^4i1z:ġ5abH +MF'K:LSowĤG)pw 3w&S)0w{oS D)v䍶Tp\TP)&t%Nq=a,6J-]Tߩ<ĺ誦 a 塞N60k&b҂Fޯ}W`yA6GU}]."pnNsB«']=pq%]:킳y52.I ysOa[>*V& y\z^㧈h7wZzhnC ])BX E/PMG%f@Q:0R)|=}I7m[2]Ůc]m aG5D5̉Hƕ,z+N,9qibVUtYQD$Ѱ`([ҷ3[2i`k#p"+Vvk}ٵkw3x*uS; N6q)_]ڷŞi%u1rz7~]5֚40&1<(>c6(v˓4!?FP`Ϣk|ogWlMJO} \e $?)m>K_a)[U.~ɻh9ʘk`NHYl24Rxb"\/x@-{`|PGܻl'g^?:>U Y5f xiw?L8?SY< ȦYK&e2Vc<:D|uEwhPKᔵDYk5T,be\3NSŏB\B$/U48U$8ZE$97{`OG}^:dT Ӿ!yi_&k?)O"$x3L*%7$yuv}1d9^i_a' ˵/ϕJH;Ir^oɨ˾`|XY!%5 eȢ| GtCքNU$8EYo $PPHoЍ!N2R8" +j$.I2hO UPJ Ӎ-29 =?8td}h]1]+x pyEf5}/h留Dz[ >F=YE翎z:rh1xTwYTVLLk_h#6}4@"ޯKA@h~Z|RU$'YGޑf\s4U+Kiqu(/~#̜W7X(8*LMb?QeQNZY Bh2R1},(2v1/OKFPvqZ|nITkm5cXb̬|5ֱR9zA`Jm!Nj)\t$yZ($yy =34L}S|gŋm)`$㥵'vh'I+jDe')KQiYG3g2_}nU,87%YjV!yHn wlPK +jD}' B+pO`:2MԃЋn@7h;I3^y!NW`Ո"N2כ'{2.T&)#$O k65L׺@9UB/XO&"$x¦F'΋FQv`1.(Y:#E\bsi wnPK^AWfՈ"N2H'3]Fh@4!Ie.Z9bv=L5NZv=>;}dCԝO 2kF1w>/V^ddGn*R!?T ߡq'Kk.6}.hE$;/OF]˓0jxVZy6#+!~wHJSLXHphV+hxU⼊F6 $^+6{`韢J]lk}h.vՍ!NҍR8AҜWcՈ"N2H'.ӂN$d6Omkz^k ײiX8 >-$yռ} 6K=stM <Vw3+A!"$xi-MAҜWcՈ"N}\5#rx:2_n B$mթ]\.W}IH^U$o\|36ҕʺ&|*t;I6^$\͋\$yYXT$yUҥX&5-[5L7yR?%XLT#m'ic?H󊬵˥τڊ7v`Gw4맹k4bI8;Iq^V#;p^2L zm[oXp>:<N^YdrLڬ i#q`ͥ1sY^RRxLsRYH5*"$x&s$yEZ("$y-kt x ; F-׹xZ`GzʄSROPuc$Z DHG^P!$yD`M[}nFAR^xU|}$=o}ZUǂD y}N \ˮy(O ,5"$9׈JyӼ!NaҼK1o|H5Ko5Oxqe_("$qh~,X[͹x=G^+ٌBJe') W`Wxi>ChO3n 65:Iq^wͧM÷xse\ X%5ȝ6UHb!TDIZ:ZEԝ:/6FD \uN~sVc#p/,r4}4uKx#qTJ>0ȹ#-xjm$~10MH5 Aڠ!NAk)&ոHX5BDIz Mۻ ]/+Wla' bFRw-E$9//#*tyCĝ$[GWxŸyCԝ:/m df1P fb-Ԩ$Zq"kFQv⼬ϻ.Ϭa)}.Z[4_|l0-6ۈd:8HJ^tT. yѷF;ȇoärab FQ"NR׋%,F6/@ewDuY)ֱ 1_$f:pQ9wlP 0ӱHXjt{HLW8En@DZhv`tZ EW`Ո"Nu%4G&#qQFYZRswU;I6^0ARWaՈ"Nҝ;QG[_FDB¹Eu v`P;ZE$9/Of=1{lEރP_Av FP}O~A\s#SӴ38!h{CIu κ;KjABS5eg"$x•UXk5߱DXe'̀n{Ŏaq*m"NR8H% sZe')K )Tiiśέ޴BGta' kEgZ-:s$ya6PLA=8|)SI"$j!WY4 qWy)1DH\#:t J!c|!}9}jZ f|HDI>_eſ x1QDIBzXң#l b !b,; 39YEyL'Dĝ$'-9Ib>7켐1]*jl3Z3 ҬW `%kl9 0H3_eW3 6OH /"Eqwe!NjƖH4;.?Y!"$yٞk`]v<O !l#\$fm҈ѭMa' yYi:Fhm"NRfmqOaj(#8ʬfaQE~X-ݏrdhF`FrAJ{2ӥj [׆ !xΰ g-rl0\GX>M:熈;I+rNBNGz#Dԝ- գ<.s<. ri^e'S1va4o$yqmaӼSKD0Ki4+O8B pk#zL; nmҘ ;5 I+jDy'6Yn% .u<aūvC?ZCARW& I\.j>nXMƮIXg6"8`n=WJUhv !NF2Ir^V#;Iv^C\ҫ Ι yyHL6Bh2ˎZIt^V#h;Is^"% r+̄h^MՋpZ_h!NRʻ3 yIu^V#;p^ C" \,kuh6(/5;I0^ZKa .伒ŕE$9/Of1dž̦Y VhX`w1HLYl#*9Zfr"NRj) fA^^x#D̝d:/db׼߃ a4qAJf='dfvEčb.^yҶAsyr\M!YmL6!Nj)3ոHJQDI\\hDcQhϦy dHgh 16mY$yih$.5_]\>os\QUmچH;Ik`NNU⦫7BDIg҈#OC-,a#f;; W4$̣MIv^V#;Iu^.3[jxPڷ/%Užo+~Dř);/^(b$y!{9v, 쨯^Wi,N`;9HzyZp$T#΋gE$9.2q#Ld}ge8 #N @#QT:Dĝ$/Rx$Z# xB-kT7$R79y+Asن;I7^Z 0%$y5Z(b$y|i Jƅm LyUk&T"_1ҠFb'IKpd"A"NҜG1y@ fgݛūn wnVx^j$9dֈ"N2>ucS3[ؼrA sN4xIB-EQDI+VW +CyRʛq!h0dZ#$yeZ($ydKQ/V}8B^?0"l."Np17(#!_"NҌN"./z#m$.M/'aکn w04Qe')Kk饾9X$u.^u)"NҜכ'{aCcC;B._XzrFy[随Uy:k>b: 0bF_ŋF H\.j ܘ&f7wB-!F?1ض9Iv^vt5u\jd%5k^ K6-rD f ɞoc|ocI䙃$:/#ƚ_$*BcQ`.++]tuݴzMι!NfÒg$;/yFv0ÖMmr+7e*+/&M᫼cڼJ"N*+P9H oDm'i v7p]N´U`E!f&"$ĂsHMM^̫F;IGÞt{$"\4F SDd9 Y;I6^%/=K>&?Yk5t@anV&4+қpf~^NFRUyj\%L^oH;I2^4ceFFQv,zznpyZAcYpGa^8 X^_m!#mE'wbc!"$yv2-8b0s3f~0WWz;~9fD mI#L?H`ieNr1^#9 *R3ɉ,4>pӮIp^<_(b$yYRK̝ELʋこANSW(LMa܀e#(cM9QSc#XKm x9һݙ(}Dz[Qwj^ =')ΫjD}'*i57'b`=, MA!:4o#|>1+>@afdfG_02 TZ2 W%mzQ}no|&1Bzv;򞽃$^(jf$Yz5BDIZe?z(P3&]a杠h%4'&|_ׯ/69A^|\xgiˌ abBzЫ.ؙʌ F;It^z0e1ޒfS fθ?;wo kg\!G1 vV%";þvc#`*C9D8EOQb be9tv_aPp9nHi )og~}y\Bz><[2h;<8,+ OA=UNp2ㅟ ')w[.9plU.lMfb0ۼN?Ho]vVhX"rZ^+S5"|#n(#CWr>$W+i {*Y̯r$+!d |J҇$zsr=MƯWwNM~l_Si~m-S3Һz>\FczlUӱdkvtf|sXvVl vO_IVFG{zN{]?شàߩM^8mw3'?$i'T@(6Y^s`;zǯHgxKnqéx&[FׄLh.q.n;vZhcp/om忑O_"nN>y7<,.ۺQxzYzĞ?6be[m\xvGO 1R!k]cCwZ1>8N>.v>#;+~L{!?L6".܏DŽ1q0_ eS1ppWىnAqȉ˖{,;n=ލ⇄C"ClMeqVЮe;+~Lq.&{; p((z`=-~o5/?D|綰/W޻~tGt};'<1qg0NwAώo(obogŏQ wcB|Yk6פߜV1N8Տ ŏ-cq uq䟐@q:oy'UWͼן/"n(s7/ڎy! / >t{:gŏ ޏ +Ӌ9JnՊkp杞?fE;xe7qEK^jeY8Jw7)^*{ŏu26Q]ݍl{qŏ ݕMwCXxHʼŏW9j_ݔ_>yw+91$5|5ݽ^+\\xM1J~[P7yWkp~q̹-~8MdZ>_x.y0_M/v1zx{DlA19~O߅rN᥮PNTF~~ ճdž*@@$]_>xB>f~aV1q]vD~ c^H݃'9uV"‡~|G~ 'i(T {s-n wZQC\hR<ٜ>(M ޵\q{Viyl۽}y/UT$܎Q5dN-~9A3m+ ;((&h{]>%zmyHe;-~LqCq.ۗ5Mk>ܸ EYcAw*Ւl1ǝWyZ.*k8RbpwkT ڊm;I6 7!6 |uMs~$OHzC"AƂ>^z]ķَ)n/96J>庙?+QfUm;cJ6H_:ӫncaZo{08+}}텔[9ҭ`xq'1_ 5F'YLsp@F׵U;)}̨uJ#6~O4r[hwYo‡$XF"kFfX%>;>F>/\8R*xpRO67;@Ƚٸ)}1hg{95gYy,HyS.I٢1*ٍjHAܻVpd_|xr姺&yxׂۋmy'X]qs?Ęʳ_frrҽU/ N?,.@+x4 8+KwZ``ߓk~.ѽͫ}֓Ypg`Sb_|`#aڵ*̫zVk^ կ?`!ǕQS^ uZYá RQEzޞ6~SFK'9fQ+K&O~gEpx3>GIpF!_^S+{d{Oa'Q~7ia{>;b[kz}] ,ӇݻyeYZ4*y%M'Hk7ܗ>L|%6E%|mkiΊLz,L;Dʨ{¸UӏNM{C%<+~ zc[[laiJsZ`F>X2oـW?-endstream endobj 6 0 obj 13304 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:26:19+02:00 2020-04-16T10:26:19+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000013628 00000 n 0000015367 00000 n 0000013569 00000 n 0000013410 00000 n 0000000015 00000 n 0000013389 00000 n 0000013693 00000 n 0000013793 00000 n 0000013734 00000 n 0000013763 00000 n 0000013873 00000 n 0000013946 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [] >> startxref 15490 %%EOF acm-6.0_20200416/doc/charts/usa/dallas/BB.pdf0000644000000000000000000001513113646045021016634 0ustar rootroot%PDF-1.4 %쏢 5 0 obj <> stream x[rE}7 *}06Y dY`Wo[eWtg쬬K7?On'Gws::-ӫw+7Z,gs=}v uq:\ Mzݧ/|O'ϋO^GṕL'm.\u^ܟ#/6~yswG/}}ۉ<ۜ#jbڼ=Iয়WWޟ<|:]n^]]=ybz}{߯67/^Y_o^޼9~}{.oN7o/[ ɫUrM%&7buI|ab*8AFQknV\Pm'"?~*c7%~:{2czd7:|.8.Ə 7 .D­*aXBQx8gviu <>L~4}M./^J0v_`>]P3>>:҇]z>YH FiFk]>ҧ捞aHks=|ܢk=i%9ߣb]sD ύc(;Ã=d?! !bڌq3<|ȏa.4gxx[[7{6oU# bFŀг8 [NE)$ 6>65@ .Ƞl`z$r-$ ؓ$$auI*$R|mPбPI%D%NGvq`ĸ0RÀUYCn<* !& !CIv1C.$Pv'M$_Yd>9{.Ixpen;:ow:h6 T(Y{ڑ֐8PW۝gW@S0}/U))cLѧdK$$2Z샇)W* H]al6bj}_PEo>am=:&PC0BV\8N$fY>K㐥y "-8测7ryjF A-떻FP."Tgo\^z#,(I1K udzb.Q2c]_a4 ZULqꍰ &Ѹ.yO'.ױvi+ i1JՏ\D.k1fHL"D\ڈ`4㺤6-@yP\)  E~Ѥ*kvTgg\YHjb~~E ==`Ay֞Z[= SMBCދFP.{$c#r1^e4)uIŪQj@p``EdMІ&$AMrc\鑪 aAMq]$cH ydg ,Q E׫5QId% |LXKpIf Wo0qQ)x#XGD꿂4#Y(4$"-Uˇ@\HKAMq]$cZgsGZZ[X|4G>Ѥx` [#,hIs5JK~J8v951z1q4!gZӬLk3N윕"(\Db f{qnҼ_RAiӊg#t~@*uw|"!\x5$HIR."\YLh%\FDPFb\<2t:49Y۲nBK{ mwk@L䢪/Tx&XufQ &=OQQk'H6AȌ@hRK̈́,\ykDm4iE'Kbf;Z0Ω\3BOŹ:!^,2M"c\qkY#,%ՆWʂjR*"H$+i1.M*aAMqdqt$prVΪ|n\$XRB?0\D.h1NF3Y!4&ΰ"/XØk#9G>Ѥ8` [#,hIsC$qޡ&)@$IGE6^]& h2fKk hRwRIԵ;) =F7OIP."\dj&ŸhFXGh\<IJtT|dm]s\w긞Naih^ϫFP.]χXҸ;y=2㺔yFL9|Ǒ>G>$x` [#EvIC c< pj#_xw($kAEuh=9*ȣIV."*jA"DZ 51tK5Uadބ&A;z4$b-AV$Wވl[Gb\'XBQݕ-[6myD㮇aLssp B? &YH1N`3 D7Bi^M/vN̸QnGEV ^>]##I:Z}>k/gǧ v{ލq͇i:>yvӴ(/tlꦧO~[vߞۇa!'Ͽ"31Mw3Ir'57ǟ}?:gH#E]>,-|ӻb!O .vۇa\+AWߎEzvOp)>ܢ7z½ w'g%s9>=,Q:\.w (,Ǿۇ B<'ڡao)}mgahՒ׵w^zz}WL{ouͧ:?>W2"xw.f3ʽ@}(=I[=st0VA|tpoV:M] {n6D*XuMw<%<&SDѶendstream endobj 6 0 obj 4147 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 9 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <>stream 2020-04-16T10:26:33+02:00 2020-04-16T10:26:33+02:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 13 0000000000 65535 f 0000004470 00000 n 0000006209 00000 n 0000004411 00000 n 0000004252 00000 n 0000000015 00000 n 0000004232 00000 n 0000004535 00000 n 0000004635 00000 n 0000004576 00000 n 0000004605 00000 n 0000004715 00000 n 0000004788 00000 n trailer << /Size 13 /Root 1 0 R /Info 2 0 R /ID [] >> startxref 6332 %%EOF acm-6.0_20200416/doc/acm.man0000644000000000000000000000635213175511062013604 0ustar rootroot.TH ACM l "Oct 30, 2017" .SH NAME acm-5.0-ico \- an aerial combat simulator for X .SH SYNOPSIS .B acm [ .I options ] .LP .SH DESCRIPTION acm-5.0-ico is a generic flight simulator and a distributed air combat simulator that runs on the X window system. Players can engage in simultaneous air combat from different computers. Players fly jet aircraft equipped with radar, heat seeking missiles and cannon. Please read the complete manual in HTML format that comes with this package, where more commands and more options are described. .SH USAGE REFERENCE .LP The following command line options are recognized by acm (see full list in the reference manual): .LP .TP -version Displays program version and copyright, then exit. .TP -plane MODEL Select the aircraft type that you'd like to fly. Enter an invalid name (for example "xxx") to see the list of the available models. .TP -frame-rate N Limits the displayed frame rate to N frames per second. .TP -geometry GEOMETRY An X compatible window geometry specification, typically something like 800x600+0+0. .SS Exit status: .TP 0 Normal termination of the program. The reason for the termination of the program is sent to standard output; nothing is written if the program terminated by player's request. Some diagnostic message might be sent to standard error, for example invalid DIS packet received or too many entities generated, but these events are not fatal and do not indicate an error in the program. .TP 1 Internal error, or invalid command line parameters, or system failure in providing some service. Appropriate description of the error occurred is sent to standard error. .SH ENGINE CONTROLS The following keys control your engine thrust: .LP 4 Full Power .LP 3 Increase Power (about 2 percent) .LP 2 Decrease Power (about the same amount) .LP 1 Idle Power .LP a Toggle Afterburner Your engine gauge displays the power that you are generating. Below that, you have displays showing your total fuel remaining as well as your current fuel consumption rate. .SH KEYBOARD COMMAND LIST Stick and Rudder Controls .LP The Mouse is your stick. It controls pitch and roll. .LP z -- Rudder Left .LP c -- Rudder Right .LP x -- Center the Rudder .LP SHIFT-E -- Toggle between stick direct control mode (default) and stick rate control mode. Engine Controls .LP 4 -- Full Power .LP 3 -- Increase Power .LP 2 -- Decrease Power .LP 1 -- Idle .LP a -- Toggle Afterburner State Radar Controls .LP r -- Toggle Radar State (On/Standby) .LP q -- Target Designator Flaps .LP h -- Extend 10 degrees .LP y -- Retract 10 degrees Speed Brakes .LP s -- Extend .LP w -- Retract Weapon Controls .LP Mouse Button 1 -- Fire the selected weapon .LP Mouse Button 3 -- Select another weapon Pitch Trim Controls .LP u -- Set Take-off pitch trim .LP j -- Set pitch trim to the control stick's current pitch setting Other Controls .LP g -- Retract/Extend landing gear .LP l -- Launch a target drone .LP Shift-Q Shift-Q -- Self-Destruct (Quit the game) View Controls (Numeric Keypad) .LP 8 -- Forward .LP 2 -- Aft .LP 4 -- Left .LP 6 -- Right .LP 5 -- Up .SH AUTHOR Riley Rainey is the original author of acm-5.0. Umberto Salsi made the enhancements published as `acm-5.0-ico'. acm-6.0_20200416/INSTALL.txt0000644000000000000000000002067413646045017013461 0ustar rootrootInstalling ACM and basic usage ============================== Contents -------- System requirement to execute the binary package under MS Windows System requirements to compile under Linux System requirements to compile under MS Windows Compiling and install from the sources Running acm.exe Single player, practice mode The entities IDs problem solved Multiplay on a local network Multiplay mode on Internet System requirement to execute the binary package under MS Windows ----------------------------------------------------------------- A binary package is also available for MS Windows and comes with the i386 32-bits executable that runs also under 64-bits systems in compatibility mode. It does not requires compilation nor installation as it runs just "out of the box" by double-clicking on the acm.exe executable program. The dis_realy.exe server is also provided to support multiplayer mode over the net, as explained below. Installation of the Tcl/tk interpreter is required to execute the acm.tcl launch interface, which is handy to start the acm.exe program and tuning the great number of its options. The Tcl/tk interpreter is available at www.tcl.tk in binary form by different providers, for example from Magicsplat at http://www.magicsplat.com/tcl-installer/index.html Often these packages provide very advanced libraries and programs along with the basic Tcl/tk, but for our needs only a basic installation is enough. System requirements to compile under Linux ------------------------------------------ In order to compile the program from the source you will need: - A 32-bits or 64-bits Linux system. - The gcc C compiler and the "make" utility as usual. - The X Window development libraries and runtime. - The Tcl/tk interpreter to execute the acm.tcl launch interface (recommended). Tcl/tk is typically already installed, or a specific package is available for any Linux distribution ready for installation. System requirements to compile under MS Windows ----------------------------------------------- In order to compile the program from the source you will need: - MS Windows 7 or later. - The MinGW system development kit, in particular the C compiler. - The Tcl/tk interpreter to execute the acm.tcl launch interface (recommended). The Tcl/tk interpreter is available at www.tcl.tk in binary form by different providers, for example from Magicsplat at http://www.magicsplat.com/tcl-installer/index.html Often these packages provide very advanced libraries and programs along with the basic Tcl/tk, but for our needs only a basic installation is enough. Compiling and install from the sources -------------------------------------- Under Windows, you will have to install MinGW first in order to have a complete system development kit including the C language compiler, the "make" utility and other needed tools. Then, open a terminal window and change the directory up to ACM sources packages. There is not a configure script: simply type "make" to build all, and cross the fingers... :-) This will build all the source tree under the src/ directory, and usually takes only a few seconds on a recent machine: $ make You may also build part of the system. For example, you may build only the acm.exe program: $ cd src/acm $ make The "installation" procedure ends here. Afterward what you will need to run the program are only these files: src/acm/acm.exe (the ACM program) objects/ (scenery, aircraft models, munitions data, etc.) acm.tcl (acm launch interface) src/dis/server/dis_relay.exe (the relay server for net multiplay) Running acm.exe --------------- There are two ways. From the command line, type the command: $ src/acm/acm.exe -objects objects/ The acm.exe program has so many options that it is practically unusable from the command line. For this reason I created the acm.tcl script to provide an handy lunch interface. You may launch that program explicitly invoking the tk/tcl "window shell" interpreter: $ wish acm.tcl & Remember to go first in the Configure panel and set the path of the acm.exe program and the path of the objects/ directory before trying to start the simulator. The DIS panel allows to chose among the single player mode and the multiplayer mode as detailed below. Single player, practice mode ---------------------------- Does not require any network, and allows to learn the basic of the flight techniques: aircraft control, takeoff, landing and navigation. You may generate as many opponent drones as you want and fight against them; the "Drone" panel of the launch panel allows also to set their "aggressiveness", that is how much close (in percent) to their "G" structural limit they will pull to get behind you... The entities IDs problem solved ------------------------------- Each entity in the DIS protocol (aircraft, missile, detonation, etc.) must have an identification code, or "DIS entity ID", which must be unique between all the participants into the simulation. But, how to generate these unique IDs on a network of independent hosts connected together? This problem has been solved by the DIS protocol by assigning to each entity a number of sub-IDs: the exercise ID, the site ID, the application ID and the entity sequential number ID. In more detail: - Exercise ID: is a number in the range [0,255] all the participants must agree on. acm.exe simply ignores and discards any packet with different exercise ID. - Site ID: each host must have an unique value in the range [0,65534]. ACM also allows the special value -1 which triggers site ID automatic generation. With site ID automatic generation, ACM-6 generates a random number and then enter a validation phase checking for collisions with the incoming packets. If a collision is detected, the generation process restarts. - Application ID: each instance of the acm.exe program on a given host must have it own host-specific different number chosen in the range [0,65534]. ACM also allows the special value -1; in this case the current process number is used as application ID. - Each instance of the acm.exe program will automatically generate an univocal further entity sequential number ID in the range [1,65533] for each entity it generates. Then, it is very important to configure the exercise, site and application IDs as follows: - exercise ID: the same number for all the participants in the range [0,255], for example 1. - site ID: -1 is the simpler choice. - application ID: -1 is the simpler choice. Multiplay on a local network ---------------------------- You may use the broadcast mode of the ACM program. In the launch interface, DIS panel, ensure the DIS relay host be the empty string; this triggers the network broadcast packet routing in the program, allowing all the participants to talk the DIS protocol using the specified shared UDP port. The default port for the DIS protocol is 3000, but you may agree on any other port to share with the other participants. Be aware that the broadcasting routing works only if all the hosts on the local network really share the same exact sub-net, or they will fail communicate together. Example with netmask leaving 8 bits for the local network: Host1: IP address: 192.168.1.33, netmask: 255.255.255.0 Host2: IP address: 192.168.1.95, netmask: 255.255.255.0 Host3: IP address: 192.168.1.147, netmask: 255.255.255.0 Another example with a netmask leaving only 2 bits available: Host1: IP address: 192.168.1.33, netmask: 255.255.255.252 Host2: IP address: 192.168.1.34, netmask: 255.255.255.252 Also set exercise no. 1 or any other value shared with the other participants. Leave the site ID and application ID set to -1 to trigger automatic assignment. Multiplay mode on Internet -------------------------- There must be a DIS relay server running on one of the machines participating into the simulation, and that machine must have a public IP address. On that machine issue this command: $ src/dis/server/dis_relay --port 3000 to start the relay server; 3000 is the standard UDP port used by the DIS protocol. Each player must then set that host and that port in the DIS configuration panel of acm.tcl. All the participants must agree on a exercise number ID. Site ID and application ID should be set both to -1 for automatic assignment. You may try the --debug command line switch to display all the incoming and relayed packets, along with the IP addresses of all the participants, new clients entering the simulation and stale clients leaving. That's all, enjoy! Umberto Salsi Bologna, 2017-07-13 acm-6.0_20200416/TODO.txt0000644000000000000000000000365013172246446013116 0ustar rootrootTODO ---- - Joystick not supported. The Debian package has an interesting implementation, I not tested though. - There are 3 radar modes: normal (120x120 DEG view), ACM (20x30 DEG view) and STT (single tracked target, 0x0 view !?). I do not understand why one should use the second, and what the third should do (currently it does not display anything). Maybe they put their energy on a smaller area (for longer range) or on a single target (higher resolution) respectively? In any case, the current code does not really implement these radar modes. - BUG: the correct display resolution (see gui_getDisplayDimensions()) only works under X-Window and only if manually set by either adding the DisplaySize specification in the "Monitor" section or adding the xrandr --dpy YOURDPI to the $HOME/.xinitrc file. - BUG: src/gedit.exe does not work on 64-bits systems: it crashes reading files created on 32-bits systems. It cannot write compatible files anyway due to the different word size (some data structures are written verbatim from memory!). The whole program should be rewritten or deeply modified to make its user interface more usable. Does not compile under Windows. - The ILS record of the scene does not allow to specify the location of the DME antenna, when available, and the location of the LOCALIZER antenna is assumed instead. Furthermore, there is only one elevation field available that must be shared among all the antennas: setting there the elevation of the GS as recommended in the reference manual may affect the distance measurement, while setting the elevation of the LOCALIZER antenna instead may affect the exact landing point. To fix all this, the format of the ILS record should be changed and these additional fields should be added: . DME latitude, longitude and elevation; . LOCALIZER elevation; . GS elevation. The current generic elevation field should then be removed. acm-6.0_20200416/README.txt0000644000000000000000000001217613646045017013306 0ustar rootrootAir Combat Maneuvering 6.0 -------------------------- ACM is an air combat maneuvering flight simulator program originally developed by Riley Rainey until the version 5.0. Starting from that already good program, I added several new features and extensions to make the program more suitable for civil and instrumental flight. The following list summarizes the features of the program; please read the reference manual for a detailed description: - Open source, mostly GNU GPL or public domain license. - Only C source code with small TCL launcher interface. - Very small CPU and memory footprint; does not require specialized hardware. - Simulated environment: ellipsoidal Earth (WGS-84 model), magnetic field calculation (NOAA WMM model), Sun ephemeris, standard atmosphere, wind and gusts, clouds. - Aircraft: several models available, both civil and military, 6 degrees of freedom, bicycle or tricycle landing gear, aerodynamics simulation; power-plant: propeller piston engine, jet engine with afterburner, rocket, glider. - Instrumentation: magnetic compass, classic panel (attitude indicator, airspeed indicator, altitude indicator, turn and slip indicator, climb speed indicator), HSI and RNAV calculator, ADF, head-up display, autopilot, direct stick control or rate stick control. - Weapon systems: radar, radar warning receiver, missiles, cannon, drop bombs; robot opponents can be generated for ACM techniques practicing. - Multiplayer capability through the standard DIS network protocol; up to 31 remote players supported. - Sound effects. - Extensible sceneries for several areas of the world, with navigation charts including airports, NDB, VOR, ILS. - Allow to choose the departure date and time, airport and runway; allows to fly freely around the globe (sceneries are loaded dynamically, where available). Sources and binary packages are available from http://www.icosaedro.it/acm/download.html Please read the INSTALL.txt file for more about system requirements, compilation procedure and basic usage of the program. The doc/ directory contains a detailed reference manual and other useful documents. Layout of the package --------------------- Here is summary of the contents of the ACM source package. The Windows binary package may contain only the essential part of these files and directories. acm.tcl Launcher for the src/acm.exe simulator. Requires the TCL interpreter. CHANGES.txt Latest changes are listed here. COPYING.txt GNU GPL license; most of the source refers to this one. doc Documentation and reference manual. doc/charts Basic navigation charts generated from the available sceneries using the tools/chart/chart.exe program (see below). doc/manual/acmdoc.html ACM Reference Manual (START HERE!). doc/acm.man Very basic ACM "troff" manual page (Unix-like systems only). objects Inventory of planes, zones, sceneries etc. acm.exe needs this dir. objects/WMM.COF Coefficients for the World Magnetic Model library. objects/zones.txt Zones of the Earth covered by the available seneries. objects/zones/ The sceneries. USA sceneries generated from FAA data base. src All the sources in C language. Makefiles made with make-makefile. src/acm The actual simulator. src/dis DIS protocol library and tools. src/dis/server/dis_relay.exe DIS relay program. src/gedit Very basic aircraft model editor. DOES NOT WORK ON 64-BITS PC. src/util Utility libraries. src/V Very efficient, lightweight, 3D graphic library. src/wmm World Magnetic Model library. test Test programs. tools/build-doxygen-doc.sh Bash script to generate Doxygen docs from sources. Mostly useful to check for missing or non-compliant DocBlocks. tools/chart Program to generate navigation charts from ACM sceneries. tools/faaairports Program to generate sceneries from the USA FAA data base. CHANGES.txt Chronological list of the changes to the ACM program since its version 2 back in the '90! COPYING.txt GNU GPL license covering most of the code. Where not stated otherwise, the license is public domain. INSTALL.txt Basic installation instructions. See also the ACM Reference Manual. Makefile Global, do-it-all makefile. Works on Linux only, though... Under Windos + MinGW I had to issue the "make" command under the src/acm directory (or any specific directory of interest). README.txt This file. TODO.txt Known bugs and wanted features. acm.tcl Handy launcher interface. Requires the tck/tk interpreter. Development of the source ------------------------- This version of ACM compiles and has been tested under these systems: - Slackware 14.2, x86_64 (Linux). - Slackware 14.1, x86_32 (Linux). - Windows 7 Starter, x86_32 + MinGW system development kit. Each Makefile has been generated using the make-makefile program available at http://cvs.icosaedro.it:8080/viewvc/public/tools The CVS repository is available at: http://cvs.icosaedro.it:8080/viewvc/public/acm (HTML interface) http://www.icosaedro.it/cvs.html (anonymous cvs access instructions) Enjoy! Umberto Salsi (salsi@icosaedro.it) Bologna, Italy 2017-10-29 acm-6.0_20200416/CHANGES.txt0000644000000000000000000016652113646045017013425 0ustar rootrootacm-6.0_20200416 Umberto Salsi =================================================== Maintenance release: + World Magnetic Model library: updated source code and coefficients to the latest version available WMM-2020. + Fix: charts updated; NDB frequency unit fixed to "KHz" (was "MHz"); magnetic variation sign was reversed. + Fix: src/dis/test/decoy.exe did not compile under MinGW/Windows. + Fix: damage calculation: munitions were mostly ineffective due to a bug (introduced by me :-). acm-6.0_20180725 Umberto Salsi =================================================== + Fixes misleading indentation in source formatting of src/util/zulu.c which is detected by newer GCC 6 and 7 as a "warning" and then failing to compile. + Fixed PRNG test program, so now src/util/prng.c passes all FIPS 140-1 tests. acm-6.0_20180402 Umberto Salsi =================================================== + Added new zones from the ourairports.com data base: France zone, Germany zone, Spain zone, United Kingdom zone. + New tools/ourairports_com program that generates sceneries from the ourairports.com data base. + New tools/create-ils program that generate ILS scenery record for each RWY record found in the given scenery. Used to complete the sceneries created from the ourairports.com data base, where all the ILS antennas are missing. acm-6.0_20171030 Umberto Salsi =================================================== ABSTRACT Sceneries are loaded dynamically; flying between sceneries is now possible. Departure airport, runway, date and time can now be set. By setting a specific date and time, the corresponding Sun position, environment lighting and Earth magnetic field are calculated. A new tool (faaairports.exe) allows to generate the scenery for any chosen area covered by the FAA airports data base, which covers the whole U.S. territory. A new tool (chart.exe) allows to generate detailed navigation charts in PDF format from any given ACM scenery. Changes to the configuration files: + A new objects/zones.txt file has been added. This zones file lists all the known scenery files and the range of latitude and longitude each scenery covers. The program now dynamically loads and un-loads sceneries based on the current position of the player. The limitation to a single scenery file per program run has then been removed. + File objects/inventory.txt renamed objects/aircraft.txt. Changes to the src/acm.exe program: + Fixed crash when too many remote entities enter the simulation. The maximum number of local and remote aircraft at any given time is 32; the maximum number of local or remote munitions and explosions at any given time is 32. The program warns when it runs out of free space in its entities tables. + A new -departure-time TIMEDATE allows to set the departure date and time. Sun position, scene lighting and Earth magnetic field are calculated based on this value. The default is the current time retrieved from the internal clock. The old "-lighting" (sic) option is not needed anymore -- removed. + A new rendering command line parameter allows to choose among flat terrain rendering (faster) or tiled terrain rendering (for some speed and altitude feedback): -ground-mode MODE where MODE can be either "flat" (default) or "tiled". On computers with very slow screen access time the first mode might be preferred. + The clouds layer can now be set with the new command line parameter; -clouds-range BASE TOP where BASE and TOP are the base and top altitude of the clouds (ft). If equal (or top is less than base) no clouds. Clouds are opaque to both visible and infra-red light, which implies aircraft can hides inside clouds and IR seekers of the missiles cannot lock the target and fly ballistically. A clouds layer was already present in the last release of the program, but its altitude range was not adjustable. The default now is no clouds. + New -force [Other, Friendly, Opposing, Neutral} option to set the force the layer belongs to. Old -team {1, 2} option removed. If the player belongs to Friendly, its drones are created Opposing and attack any other force; If the player belongs to any other force, its drones are created Friendly and attack any other force (including the player itself). Drones created by player belonging to the Friendly force are Opposing and using MiG-29; drones created by player belonging to any other force are Friendly and using F-16. + The -scene FILE command line option has been removed; scenery files are automatically loaded based on the current position of the player. Providing the starting position with the -latitude and -longitude command line options is now pretty mandatory: the default start position is 0N 0E :-) + Supports ILS types LDA and SDF as synonym of LOCATOR. + Maximum tunable NDB frequecncy increased from 499 to 529 KHz. + The flight state data page (SHIFT-D) now displays current or simulated time. + Finer zoom by steps of about 1.2 factor rather than 2. New programs and tools: + src/chart: a new program that reads an ACM scenery and generates the navigation chart. Currently generates PostScript on output, which can be easily translated to PDF -- see the readme file for more. + tools/faaairports: a new program to parse the US FAA airports data base and to generate the corresponding ACM scenery for any given range of latitude and longitude. Also added shell scripts that automate the generation of the "dallas" scenery and the new "newyork" scenery. + The objects/dallas.txt is completely generated with the faaairports tool based on the FAA airports data base; now it covers the latitude range [30N,35N] and the longitude range [95W,100W] and includes 291 runways (+177%), 34 ILS (+91%) and 76 NAVAIDs (+15) and it is supposedly more actual. A new objects/newyork.txt has been also generated that covers the latitude range [40N,45N] and longitude range [70W,75W]. Other regions covered by the FAA data base can also be generated. Changes to the scenery file format: + ILS record: added types LDA and SDF; see the reference manual for further details about these new types and recommendations about the elevation field. For short: LDA and SDF are just like LOCALIZER for the ACM program, but the automatic navigation charts generator program is advised a runway end may not be available so no error should be emitted. + NAV record: field 7 (channel number) is now mandatory and '-' should be indicated if not available/unknown; the ACM program does not use it anyway. Change made only to simplify parsing programs so that each record has a fixed number of fields. Changes to the acm.tcl launch program: + The "You" panel renamed "Plane"; options related to the plane moved here; the "Instruments" panel removed. + A new "Departure" panel allows to choose the starting position as airport and runway, along with altitude and airspeed. Departure date and time can be set. + The "Environment" panel allows to chose among flat terrain rendering (faster) and tiled terrain rendering (better feedback). + The "Environment" panel allows to set the base and top altitude of a tick layer of clouds. acm-5.0-ico-20170914 Umberto Salsi ======================================================= Abstract. Sounds support restored. The type of engine can now be specified and a specific dynamics is applied. The anemometer now displays Mach's number too. Several bugs fixed. + Fix modulo bias in random number generation. Now the pseudo-random numbers generators has its built-in implementation compliant with the C99, C11 suggestion in the ISO/IEC 9899. + Fix: under Windows, acm.tcl did not displayed the reason for the termination of the program. This has been fixed by forcing the creation of a console window to capture and preserve the standard output and standard error streams. + Fix: C preprocessor macro "WINNT" replaces "WIN32" to support compilation under both 32 and 64-bits Windows systems using MinGW. + Each aircraft model now has its specific type of engine. Added the "EngineType" field to the "aircraft" inventory record that may specify one among these: EngineType "NoEngine" EngineType "GenericPistonEngine" EngineType "GenericJetEngine" EngineType "GenericRocketEngine" This allows to simulate the proper dynamics and to generate the proper sound for each specific type of engine. Default is "NoEngine". + Sounds now supported under Windows and under Linux with ALSA drivers. Sounds are enabled by default, but can be disabled with the -no-sound command line option. At runtime, CTRL-M mute/unmutes sounds. The following sounds are currently supported: engine, gear up and down, stall warning, tire "screetch" on touchdown, radar lock, TEWS warning, cannon and missile firing, warning, crash. The sampled engine sounds (see the objects/sounds directory) are assumed to represent 100% RPM; lower RPM are rendered by resampling those sounds at a lower frequency. + Classic instruments: the anemometer now also displays the Mach number. + Engine idle setting is now 20% RPM (not 25%). Reason: too much thrust for idle piston engines now that the RPM vs. thrust law is proportional, you had to apply brakes very quickly once started! + The following aural and textual messages are generated to help the pilot landing and flying at low altitude: "Warning: gear down!" Radar altitude available and descending rate leaves less than 120 seconds to extend the gear, but the gear is not fully extended and locked yet. "Warning: pull up!" Radar altitude available, descending rate too high, no time time left to safely extend the landing gear which is not fully extended and locked yet. Or: Radar altitude available, descending rate too high to recover within 1.2 G vertical acceleration limit before impact. + acm.tcl: the Configure panel now has a "Enable sound effects" check box to enable audio. Sounds can be enabled or muted at runtime with CTRL-M. + Several text files (CHANGES, COPYING, INSTALL, README and TODO) now have their ".txt" file name extension. acm-5.0-ico-20170822 Umberto Salsi ======================================================= Abstract. The current magnetic field of the Earth is now calculated based on the World Magnetic Model from NOAA. The rendering of the terrain, that was boring flat, is now tiled giving some distance and speed feedback; also introducing a thick layer of clouds with zero visibility inside. More colors and shades. Minor corrections. + Fix: under Windows, did not recognized semicolon as directory separator, so multiple directories in objects parameter did not worked. + Fix: the state of the instruments panel was not updated with the window in minimized or iconified state. + The magnetic field on the Earth is now calculated using the World Magnetic Model library from NOAA (https://www.ngdc.noaa.gov/geomag/WMM/soft.shtml) and it is used to display the current magnetic heading of the aircraft, to rotate the magnetic compass, and to calculate the magnetic bearing at each VOR station. Therefore, the format of the scenery is now a bit simpler as reported below. The file of the coefficients objects/WMM.COF provided along the package is valid for dates in the range from year 2015 up to year 2019 included; beyond this range, a warning is displayed and a new updated file should be installed. It is important to note that the components of the Earth's magnetic field are calculated respect to the current date, so updated navigation charts may be needed. The navigation charts provided along this package are outdated, so magnetic bearings there indicated may differ more or less from the calculated values. (In the previous versions of the program, the local magnetic variation was calculated based on the nearest radio station for which a magnetic variation was available in the scenery; the magnetic inclination needed to simulate the behavior of the magnetic compass was calculated with a quite raw world-wide approximation. In both the cases, the resulting values were not aligned with the current date.) + Scenery format changes: . The magnetic deviation at the radio stations is now removed. . The bearing of the localizer must now be reported as geographic (not magnetic). + Colors and colors handling completely revised for better rendering. Now uses a 17*17*17=4913 colors table rather than only 5*5*5=125. Non-linear mapping of the colors look-up table gives higher resolution on darker colors. The quite obscure concept (for the user point of view) of "depth cueing steps" removed, and then removed the -depth_steps parameter from the application and from the launcher interface acm.tcl. There is no more limit to the number of colors the program may request (although they are still approximated with those available in the colors look-up table). + Improved rendering: . Introducing terrain tiling effect for motion feeling and depth cue rendering. . Introducing clouds layer with zero visibility in the range 5000-12000 ft. acm-5.0-ico-20170723 Umberto Salsi ======================================================= Abstract. ACM now runs natively also under Windows. Others minor fixes and improvements. Specific of the acm.exe simulator program: + Compiles under Windows with the MinGW system development kit generating a true native executable that runs "out of the box". Previous compatibility with Cygwin + X-Window emulator has then been dropped. + Introducing the GUI abstraction module (src/util/gui) with implementations for both X-Windows and Windows. Removed any other dependency from a specific GUI all around the sources. + Rate control, whenever enabled, now working also with "weight on the wheels" for smoother rotation maneuver at liftoff. + Fix infinite loop in random number generator on systems whose random source provides only 15 bits. + Fix: killing with missile was nearly impossible, especially over the net. Now the relative position of the explosion in the explosion DIS PDU is set and then properly used. + Audio disabled if no proper lib available (which practically means, no audio :-). + The update rate of the dynamic models is now internally tuned to its optimal value around 60 Hz and kept tuned around this value independently from the chosen frame rate and from the actual resulting frame rate. This improves the numerical stability and makes simpler for the user to configure the program. + The following command line options have been removed from acm.exe: -update-rate (internally tuned). -watch-frame-rate (actual frame rate is periodically displayed by default). -bw and -cmap (superseded by the abstraction GUI module). Specific of the acm.tcl launcher interface: + Gets iconified while the program runs, avoiding a boring gray dead window. + Removed audio and joystick options (still not working, anyway). + Removed update rate option (now internally determined). acm-5.0-ico-20170527 Umberto Salsi ======================================================= + Removed any dependency from the RCP library and XDR library; now ACM has its own built-in encoding/decoding routines, fully supporting 32-bits and 64-bits processors and with memory leaks detector. + Fix memory leaks when decoding of incoming DIS packets fails, which may happen on an heterogenous network of applications speaking the DIS protocol. + Fix memory leaks releasing DIS packets. + Passes incoming random packets stress-test to resist in an hostile network; safety and security issues start to be seriously addressed. + Automatically generated site ID, once validated in the validation period, does not change anymore and no further site IDs collision tests are performed. + Fix declarations for DIS protocol IEEE 1278.1-1995 compliance: fix articulation parameter data structure (not used by ACM anyway, for now); fix comment PDU (not used by ACM anyway, for now). acm-5.0-ico-20170514 Umberto Salsi ======================================================= Abstract. Currently compiles under Linux and Cygwin/Windows at 32 and 64 bits. Support for the DIS protocol has been restored and multiplayer mode works again; clients connect each other either in multicast mode or in relay mode through a specific relay program; DIS protocol parameters (site ID and application ID) can now be assigned automatically (no more need for a SIM/x server). IAS (indicated airspeed) and then rate control mode stick have been introduced. Changes to the general layout of the package -------------------------------------------- + Removed original configure script, now replaced by several Makefile(s) automatically generated using the script make-makefile available from http://cvs.icosaedro.it:8080/viewvc/public/tools/ + Fix to support 64 bits architecture (DIS protocol encoding, acm, gedit). + All the sources are under src/ and the test programs under test/. + The simxd server has been removed and replaced by new site ID random generation and validation algorithm; entities db query not used anyway and so the ndbs data base has been removed as well. Any dependency from the RPC portmapper services has been removed and its configuration is not needed anymore. + Most of the source code has been "modularized": each implementation source file .c has its own corresponding interface declaration file .h. The only exceptions are the programs, where an interface file is not necessary their only programming interface being the main() function. + The src/dis/server/dis_relay.exe program implements a DIS relay to support multiplayer interaction through Internet. + The objects/inventory.txt file got the extension '.txt'. The "include" statement has been introduced for a more structured inventory. DIS relay server ---------------- + The DIS relay program src/dis/server/dis_relay.exe allows several players to interact though Internet; it can be started with the command: ./dis_relay --port 3000 --debug being 3000 the default port. The --debug option displays packets received and forwarded. Clients silent from too much time (currently 60 s) are automatically removed from the dispatching list. Changes specific of the src/acm/acm.exe program ----------------------------------------------- + Fix crash if the GROUND_COLOR record is missing from scenario. + Fix: sometimes the scale of the magnetic compass did not shown. + Fix: gravity bombs now work as expected over the DIS protocol. + Fix: radar beam sweep angle in the DIS packets is half the angular aperture, not the full aperture; units are RAD, not DEG. Added heuristic to continue supporting old bugged versions of the program. + Fix: radar in standby does not emits energy anymore. + Fix: did not set ACM 20x30 radar mode (for what it worth; see TODO). + Fix: TEWS did not accounted for emissions from remote entities, so remote aircraft were not displayed. + Fix: in TEWS, enemies are now drawn as 3 concentric circles to distinguish from friends. + Fix: drones were fighting against all; funny, but silly. Now they belongs to the enemy team and they select properly their target (that is, you!). + The program now works as a DIS application, either in broadcast mode or in relay mode. To support this latter, two more options have been added: -dis-relay-name HOST -dis-relay-port PORT where HOST and PORT are the DIS relay host and its UDP port. If the HOST is not set or it is set to the empty string, use packets broadcasting instead. Previous DIS_RELAY envar not supported anymore. + Site ID default value is now -1, which triggers site ID automatic assignment. A temporary randomly generated site ID is calculated, then the program enters a validation period where it listen for incoming packets; if a collision is detected, another value is generated. + Application ID default value is now -1 which assign the process ID. + Option -no-dis removed; now DIS protocol enabled by any -dis-* option. + Drones always working, no need to "enable DIS" anymore. + Periodically displays DIS protocol state and network performances: total number of tracked remote entities; processed DIS packets per second. + Periodically displays actual frame rate and update rate. + The separator character in directories list is colon under Linux and semicolon under Windows to support the -objects option on both platforms. + The ground color has now a default flat light green. + New rate control mode enabled/disabled with SHIFT-E allows to control the roll ratio and pitch ratio. + Brakes are now engaged/disengaged smoothly within 1 s. + Computes the indicated air speed with compressibility correction as: IAS = TAS * sqrt(rho/rho0) * (1.0 + 1.0/8*(1.0 - delta)*M^2) being TAS the airspeed along x, rho the air density at the current altitude, rho0 the air density at sea level, delta the ratio P/P0 between the current air pressure and the pressure at sea level, and M the Mach number. + Vne and Vfe are now IAS (not TAS). + "Hints" periodically shown to the user are now read from objects/hints.txt. + The scenery may include the terrain surface as a FEATURE record; its name must start with '#' so it is drawn on the background (quite an hac, but it works!). + Mouse buttons meaning changed: left button to fire, right button to change weapon. Center button currently not used. + Landing gear dynamics: the dumper is now single effect, as it dissipates energy only on compression and has no effect on release. + Drones now set a proper combat aircraft configuration with gear up, flaps up, speed brakes off, APS off. + Auto-Pilot: + Internal architecture completely redesigned, with pitch rate and roll rate control functions as common basic of all the other functions. + Pitch and roll rate control law added (SHIFT-E): mouse controls rate. + Auto-throttle target speed is now IAS (not TAS). + HUD: + Radar altimeter removed (it is already available in the instruments panel below). + Added "Rate" display when rate control law enabled. + Changed display of the auto-pilot's currently active mode: "AP" --> "VS/ALT" "AN" --> "NAV" "AT" --> "THR" "AW" --> "Turn" "AC" --> "Coord" "AL" --> "Land" + When auto-throttle is engaged, target speed is IAS (left ladder still displays TAS). + Added air temperature, pressure, density and speed of sound to the displayed data (SHIFT-D). + Classic instruments panel: + Added "Rate" display when rate control law enabled. + Changed display of the auto-pilot's currently active mode: "AP" --> "VS/ALT" "AN" --> "NAV" "AT" --> "THR" "AW" --> "Turn" "AC" --> "Coord" "AL" --> "Land" + Airpeed indicator now displays IAS. + Altitude indicator now has a thousands needle. Inventory file objects/inventory -------------------------------- + Improved structured inventory by adding the include "filepath" statement; relative filepath is resolved against the directory of the current file, so that the referred included file can be in a different directory. Same feature enabled for the Object "path/model.obv" statement inside the aircraft{} record, now allowing a relative path which is resolved against the directory of the current file. + P51A now has a machine gun. + Added UFO aircraft intended to replace remote entities for which a model is not available. Also useful to quickly explore maps because of its exceptional performances :-) Changes specific of the acm.tcl launch interface ------------------------------------------------ + The old "acm.tk" program changed extension becoming now "acm.tcl". + Add a "DIS" panel for all DIS related configurations: relay host and port, exercise, application and site. + Allows for wind speed up to 40 kt (was 20 kt). + The update rate can now be set. acm-5.0-ico-20100109 Umberto Salsi + HUD: pitch scale ladder now rendered in perspective projection, so that it matches exactly the pitch as indicated by the FPM (fix). + Stall warning: panel light + HUD display + audible alarm. + Player whose aircraft is damaged fall down and crashes. + More accurate CCIP HUD symbology (use circle rather than cross). + Mark 82 bomb blast may damage aircraft. + CCIP: corrected position of the CCIP accounting for the pilot's head position. + Added keypad button 0 to look down. acm-5.0-ico-20090215 Umberto Salsi + Added Mark 82 drop bombs with CCIP calculator. + Added down view (keypad 0). + Inventory: Su-30 now armed with 4 MK82, 2 AIM9M and M61A1 for bombing practice with CCIP. acm-5.0-ico-20090208 Umberto Salsi + FIX: the runway numbers are now rendered in the proper order. + FIX: properly evaluates max lateral mouse range. + FIX: corrected elevator non-linear response curve. + Introduced wind gust model. + Anemometer: now displays speed limits arcs. + Attitude indicator: increased gyro rigidity. + Removed keyboard command 'u'. + Auto-Pilot System: + Now implemented using the proportional-integrative algo. + AC: smooth release. + AW: smooth release. + AL: performs flare maneuver at lower altitude. + Weapons: + Enabled radar guided "AMRAAM" missile AIM-120 (previously was disabled). + Drone algorithm now uses AIM-120 first, then AIM-9M. + Inventory file: + Removed unused parameters CLNegStall, CLPosStall, SeTrimTakeoff, CmFactor. + Added parameters MTOW, Vs0, Vs1, Vfe, Vno, Vne. + Weapons have new canonical names M61A1, AIM-9M, AIM-120, MK82. + C-172 has lower pitch. + F-16 and MiG-29 now mount 2 AIM-120. + MD-80 now has the thrust reverser. + Updated manual. acm-5.0-ico-20080420 Umberto Salsi + FIX: HUD, turn indicator: now shows actual yaw rate. + FIX: classic turn&slip indicator: now show turn rate around aircraft z axis. + FIX: rendering: show correct downward view at higher zoom factors. + Added Thrust Reverser device (currently available only on B-747): * Inventory: added parameter HasThrustReverser. * Enable/disable thrust reverser with SHIFT-!. To enable, engine setting must be idle (<= 25% RPM). * Panel: new "THR REV" lights, blinking while the device is moving. + AutoLanding, flare maneuver: with tricycle, thrust reverser, lower nose, brakes; with bicycle, thrust reverser, raise nose, no brakes. + Render: darker night. + ADF: added rotatable heading needle for pilot's convenience (7 and 8 to move). + Manual updated with the new features listed above, and AutoLanding procedure fully described. acm-5.0-ico-20080328 Umberto Salsi + BUG FIXED: now works also with 8-bit and 16-bit color depth (please choose accordingly the "Color depth steps" parameter now available in acm.tk). + BUG FIXED in magnetic compass scale labels. + Now compiles under GCC 4. + Aerodynamic forces fully implemented also on the ground. + Landing gear model rewritten, now it deals with the roll moment, wheels skidding, detect max lateral load on all the landing gears, steering effectiveness reduced at high speed. + Bicycle landing gear now supported. + Added P-51A "Mustang" to the inventory (first bicycle gear available). + Starting airborne, set pitch 3 DEG and gear retracted. + The parameter -heading now sets MH (not TH). + Auto-Pilot System: introduced max bank limiter from 5 to 25 DEG. + New option -drone_mode [DOG_FIGHT | HUNTING]. + New panel light "G-LOAD" blinks above 75% max wings load. + Inventory file: * GroundingPoint parameter removed since now it is calculated at run-time along a proper rest pitch, so that the aircraft can be deployed gently over the runway. * MaxNWS parameter removed since now steering effectiveness gets reduced as far as the velocity increases, reproducing some "resistance" feedback to lateral acceleration. * NWIncr parameter removed as the keyboard cannot be used to steer. * If Object parameter undefined do not display aircraft chase view rather than simply crash the program. + Source changes: * Vlib and Alib reorganized as "C modules", extensively introduced the concept of "Rect", old Win32 code moved into a sub-dir. * The number of polygons that may be rendered is now unlimited. * New module src/vpath_gallery that implements common drawings. * Removed all the bitmaps images, now implemented with vpath. All the graphics routines now based on Vlib, no more X Window calls spread. * Module src/vlist properly renamed as "viewer". * HUD ladder and HSI compass scale now generated at run-time, so removed tools/horizon.c and tools/hsi_header.c. acm-5.0-ico-20080209 Umberto Salsi + New: cockpit view now rendered in accurate scale based on screen resolution (pixel/meter) and on the distance of the eye from the screen. The downward angle of view can also be specified. The command line parameters -eye_to_screen_cm and -downward_view_angle_deg were also added. The -scale parameter then removed. + New: zoom with +/- keys, ranging from x0.125 up to x4. + HUD now rendered more realistically with smaller dimension and moved downward 3 DEG (or, nose pointer move up 3 DEG) so that the center of the HUD is very close to the point toward we are flying to or we are aiming to. + New: SHIFT-$ enable combat in drone mode. + Smarther drones do not crash to the ground (almost :-) anymore. + Splash screeen removed; copyright info displayed with -copyright switch. + acm.tk: support for new parameters "eye distance from screen" and "downward angle of view". acm-5.0-ico-20071002 Umberto Salsi + AL: now performs flare maneuver, touch-down and braking, faster recovery of misalignment from LOCATOR + AP: new algorithm that improves stability and responsiveness + AN: smoother maneuvering at small deviation angles + NEW: radar altimeter now available in the instruments panel + Automatic fuel resupply now disabled -- restart the program to fill the tank + Enlarged HUD acm-5.0-ico-20070905 Umberto Salsi + BUG fixed that prevented compilation under gcc 4. + NEW: VOR/DME radio signal can no more be received above the horizon of sight (see the manual for details). acm-5.0-ico-20070831 Umberto Salsi + BUG: crash trying to set altimeter offset or pitch offset in HUD mode: fixed. + NEW: magnetic compass. + NEW: RNAV calculator. + NEW: support for NDB stations. + NEW: ADF receiver. + NEW: option -hud-mode. + Dallas scene: restored existing NDBs, updated nav. charts. + Italy scene: added known NDB, updated nav. charts. + Now starts in classic instruments mode rather than HUD mode (but see also the new -hud-mode option). + Now starts in MH mode rather than TH mode. + Now starts with HSI enabled. acm-5.0-ico-20070725 Umberto Salsi + BUG: crash when at rest on the runway: fixed + BUG: turn indicator of the classic instrument panel now displays the actual turn rate around the vertical axis of the aircraft (not the turn rate around the zenith) + NEW: you can set the altimeter offset in the range 28-31 inHg + NEW: aircraft description: added MaxLoadZPositive and MaxLoadZNegative + Drone aggressiveness (option -da) now sets the fraction of the max load at which drones will maneuver. Drones now behave more realistically maneuvering within their structural limits. + acm.tk: now manages the -da option + Removed AutoCoord, AutoThr and AutoPilot warning lights from the panel: classic instruments mode and HUD mode already provide these alarms + B-747: increased elevator effectiveness acm-5.0-ico-20070715 Umberto Salsi + NEW: classic instruments panel: attitude indicator, anemometer, altimeter, turn&slip indicator, vertical speed indicator. Press SHIFT-H to toggle between the HUD mode and the classic instruments panel. Read the manual for details about the classic instruments characteristics, their limitations and usage. + NEW: flight by night option -lighting daylight|night + NEW: mouse mode option -mouse-mode fast|normal|precise + NEW: SHIFT-Z to engage the AP in hold-altitude mode acm-5.0-ico-20070709 Umberto Salsi + acm.tk: the Mig-29 wasn't displayed, now it is (BUG FIX) + auto-navigation with VOR (AN) + auto-pilot: max vertical acceleration: +/- 0.1 g hold-altitude mode, max vertical speed: +100 fpm hold-altitude mode, min vertical speed: -1000 fpm disengaging the AP, smooth release of the elevator within 3 s + C-172RG: engine power and drag coeff. tuning. acm-5.0-ico-20070621 Umberto Salsi + nose wheel now can attain the specified angle of steering (BUG FIX) + corrected TAS indication with wind (BUG FIX) + conflicting NAV on the same freq.: now only nearest gets received (BUG FIX) + the payload can now be specified (see option -payload WEIGHT) + new airplanes: AMX, MD-81 + the '7' key rotates OBS of 10 DEG (not 20 DEG) + acm.tk: now it gathers the planes from the inventory file (no hard-coded) acm-5.0-ico-20061022 Umberto Salsi + acm/tk: now you can choose your team + auto-turn feature (keys ,.<>/|) + AP: smoother release + AL: now bank angle limited to 25 DEG (no more limits on turn rate) + removed unused open socket that sometimes saturated the CPU + manual updated accordingly + C-172RG: reduced engine power to closely match performances of the real plane (max climb rate, max speed) acm-5.0-ico-20060529 Umberto Salsi + auto-landing system (AL) + auto-pilot: now uses a faster dynamic model of the elevator + now 'Home' resets ailerons/elevator trim and disable AP/AT/AL + (rough) estimation of the ground effect + inventory file: new parameter "WingHeight" + if no NETAUDIO nor HPAUDIO, try sending audio data directly to /dev/dsp + audio module completely reworked + chaser module removed (not used) + mouse control: no fuzz zone + updated Unix man page + manual updated accordingly + Unix "man page" updated + acm.tk: displays on stdout the resulting command used to start ACM acm-5.0-ico-20060507 Umberto Salsi + AC: response time reduced + AT: out-of-range alarm now raised properly + HUD: now indicate the effective total airspeed + B-747: increased rudder effectiveness to attain 3DEG/s at 185 kts acm-5.0-ico-20060505 Umberto Salsi + autothrottle controlling the TAS + manual updated accordingly + italy.acmscene, Genova-Sestri airport: fixed up ILS acm-5.0-ico-20060502 Umberto Salsi + 'd' detach commands from the window + handle properly window focus in/out (you can leave ACM in background) + double HSI receiver - press 'SPACE' to switch NAV1/NAV2 + source reorganized - every *.c module now has its *.h + improved rendering of the engine gouge and gear handle + afterburner disabled on aircraft lacking this device + to exit from the program press SHIFT-Q twice acm-5.0-ico-20060427 Umberto Salsi + optional true heading (TH) or magnetic heading (MH) indication (SHIFT-M) + HSI: displays the current selected TH/MH mode + HSI: digital display of the OBS + HUD, heading scale: displays TH or MH + some source clan-up based on the gcc -Wall complains :-) + manual: updated with the changes above + manual: now explains the terrain model and the "step line" problem + Italy scene: 8 more airports, 25 more NAVAIDS, more navigation charts. + bug fix: "Color Segment pool overflow" and crash acm-5.0-ico-20060416 Umberto Salsi + BUG FIX (the autocoordinator was always engaged) acm-5.0-ico-20060415 Umberto Salsi + autocoordinator controlling the rudder + HUD: now displays a bank indicator acm-5.0-ico-20060409 Umberto Salsi + HUD: now displays a radar altimeter + fixed up bug in flight calculations (calcAlphaBetaVT()) acm-5.0-ico-20060402 Umberto Salsi + HUD, pitch ladder: added -1, -2 and -3 degrees markers + navigation charts now include average magnetic variation + dallas.acmscene: improved ILS alignment to their runways + italy.acmscene: improved ILS alignment to their runways acm-5.0-ico-20060326 Umberto Salsi + autopilot controlling the elevator + acmscene file format: new RWY2 record type + acmscene file format: DME only NAVAIDs now allowed + scene rendering: displays runway numbers + objects/inventory, Boeing 747: speed brakes, elevator effectiveness + objects/dallas.scene: minimal updates and corrections + objects/italy.acmscene: +Firenze-Peretola, +Napoli-Capodichino + improved navigation charts + undocumented SHIFT-D feature displaying debugging infos acm-5.0-ico-20060319 Umberto Salsi + new italy.acmscene (only north Italy, by now) + dallas.scene: minimal updates and corrections + better navigation charts acm-5.0-ico-20060314 Umberto Salsi + range of ILS stations now limited to 18 nm + range of terminal VOR now limited to 40 nm + range of en-route VOR now limited to 200 nm + the HSI now looses/acquires the tuning accordingly to the previous changes + manual updated accordingly - see section "The HSI" for details + "acmscene" file format, RWY record: fields 10 and 11 removed (not used) + improved navigation charts acm-5.0-ico-20060307 Umberto Salsi + HSI: always display the CDI of the ILS locator + magnetic variation for NAV and ILS can be fractional (ex.: "1.3E") + gedit compile properly under Linux + added chart BB.pdf acm-5.0-ico-20060301 Umberto Salsi + manual: now explain the landing gear parameters in more detail + twoOrder() in src/pm.c sometimes generates NAN and crashes the program: rewritten acm-5.0-ico-20060215 Umberto Salsi + acm.tk: new radio button "Debug" to debug through GDB + lateral accel. indicator: every tick now is 0.25 g + fix that prevent pm.c/twoOrder() from generating NAN values as result + fuel level: better precision for low fuel level (required for the C-172) acm-5.0-ico-20060202 Umberto Salsi + HUD: now displays the TAS along the x-axis of the plane (see "-wind" opt.) + HUD: now displays a turn and slip indicator + HUD: now displays a timer -- press 't' for start/stop/reset + HSI: now displays the NAVAID 4-char ID + HSI: rendering enlarged and improved + HSI, ILS: does not display CDI if we are outside of the station beam + HSI, ILS: every dot now is 0.4 degrees regardless to the station + new option "-wind WD/WV" that sets the wind direction (DEG) and speed (kt) + new option -scale FACTOR that sets the scale of the rendering + new option -no-splash that disable the initial splash-screen + new option -no-dis that disable the DIS protocol + SHIFT-P generates screen shoot into /tmp/acm-dump-* + fixed up minor bugs that prevented the compilation under GNU/Linux + upper-case letters are now reserved for future extensions of the program + displays flaps (fix) + displays the engine settings at the start of the program (fix) + moved the manual into doc/manual/ + added flying charts about the default scene (see doc/charts/) + added Boeing 747 to objects/inventory + added objects/man.obv + new option -objects path1:path2:... for objects directories + new option -help and -version + new option -no-sound + new option -fuel FUEL-LB; use MaxFuel if this opt is not specified + added program acm.tk to the distributed package + on abnormal termination (crash, damage, etc.) displays an explanatory message + the opts -latitude and -longitude now support the format DD-PP-SS.SSSQ + fuel resupply rate: +10% every 30 seconds + if no weapons available for the plane, disable weapons display/select/fire 2006-01-05 + starting playing around the source of the original version acm-5.0 from www.websimulations.com. From here on: changes list made to ACM-5.0 by Riley Rainey (circa dec 1998). ============================================================================ What's different with revision 5.0: ----------------------------------- Current ACM documentation may be found in the file "acmdoc.rtf". --------------------- UPDATE ------------------------ The reference manual is now in HTML format under the doc/manual directory, with the new features described. U.S. 2017-04-03 ----------------------------------------------------- ACM now dynamically maps DIS entity identifiers to rendered objects. The mapping is defined in the file "objects/object-map.txt". ACM now has a more flexible scheme for determining aircraft damage. See the file "objects/munition-map.txt". ACM now supports reading DXF object description files. This support isn't exhaustive, but it works with many popular 3D CAD programs capable of exporting DXF files. The V library object description file suffix was changed from ".obj" to ".obv" to avoid conflicting with Microsoft object file names. A bug in the new scene reader code was preventing 'FEATURES' (special ground based features) from being rendered. The default.acmscene file now contains an example of a ground feature reference -- the tower at Addison airport. Support for the GNU --srcdir option to 'configure'. Michael Deutschmann (ldeutsch@mail.netshop.net) suggested changes to support this as well as numerous autoconfig enhancements. --------------------- UPDATE ------------------------ I removed the configure script, now replaced by seve- ral Makefile automatically generated with make-makefile. U.S. 2017-04-03 ----------------------------------------------------- Several changes have been made to allow ACM to compile and link cleanly on Linux systems. ACM's configure now looks for a /usr/lib/games directory and installs ACM's object files there if it is present. Mats Lofkvist fixed several bugs relating to DIS processing. The DIS/x library now supports more DIS dead reckoning methods. All static and world-based methods are now supported. Body frame methods remain unsupported. Missiles will no longer fire while weight is on the landing gear. Mark Cianfaglione (markcia@nortel.ca) suggested changes to landing gear handling. Now the gear will not come up until weight is off the wheels. At Mark's suggestion, the low fuel light now comes on when there is fifteen percent fuel remaining -- it used to be hard coded to come on any time there was less than 1000 lbs of fule on-board. Misha Stephanov pointed out two one-line, but significant bugs in update.c and damage.c. Misha also suggest a changes to landing gear handling to detect when someone is unlucky enough to attempt a gear-up landing. ACM now has a basic DIS Stealth capability. ACM supports numerous new command line options, all of which are documented in the acmdoc.rtf file. What's different with revision 4.8: ----------------------------------- The world is now round -- er, spheroidal. When you enter the ACM world, you are placed on runway 15 at Addison airport in Dallas, Texas [my aircraft's home base ;-) ]. The scene databases now include realistic radio navigation aid information as well as runway location information. With this info integrated into ACM, you can fly more real instrument approaches. If you'd like to try, you should get a copy of the current National Ocean Service [NOS] terminal procedures [approach plates] South Central Volume 2. I will try to get permission to scan and distribute a few with the release of ACM. Only the Dallas scene database is currently available. Use your PC joystick with ACM! Support for the Colorado Spectrum Workstation Gameport(tm) has been added to ACM. This gameport adapter allows you to connect a PC joystick to a serial line on your UNIX workstation. The Workstation Gameport can be ordered from Colorado Spectrum by phone: +1 (970) 225-6929; it currently lists for $100. The Workstation Gameport is a different design than the Notebook Gameport that you will find in your local PC retail store. The Notebook Gameport will not work with ACM. WARNING: This support is currently incomplete. The joystick driver has been temporarily hard-wired to interface to two-axis joysticks. To enable joystick operation, type: $ acm -js /dev/cua1 The name of the serial port connected to the gameport is supplied as the second argument. The device name will vary from one system to the next (/dev/cua1 corresponds to the direct-connect port "B" on my Sparc IPX). Mats Lofkvist has integrated ACM with the U.S. Navy Postgraduate School's Distributed Interactive Simulation software (called NPSNET). As the name implies, DIS is a simulation information interchange protocol that allows distributed servers (ACM servers, in this case) to work cooperatively. I have replaced Mats' use of NPSNET with a DIS library that I created. This library implementation should be more portable. Using DIS means that if you are using ACM in a multiplayer environment, you'll see much better overall performance. The DIS protocol relies on broadcast UDP datagrams. Therefore, all ACM players must currently run on the same subnet (UDP broadcasts are not propagated beyond a subnet). There are DIS bridges available that would potentially relax this restriction, but none have been tested with ACM yet. The ACM server (acms) has been eliminated. Invoke acm by simply typing 'acm'. Check the acm man page for information about new command-line arguments and switches. A font problem that manifested itself on AIX/Windows has been fixed. Fixes for Linux compatibility problems in ACM 4.7 were submitted by Jeremie Petit (petit@aurora.unice.fr). What's different with revision 4.7: ----------------------------------- A problem with V library 3-D to 2-D mapping has been fixed. A problem with the V library could cause this esoteric error message on some X servers: BadPixmap (invalid Pixmap parameter) The fix to this problem was identified by Brent Holland. What's different with revision 4.6: ----------------------------------- Sound support has been added for many HP platforms. Philippe-Andre Prindeville made the changes required for ACM to function with the HP-UX audio API. Configure no longer assumes that the NCD netaudio library is the only only one named "libaudio.a". Cloud layers can now be used to affect combat conditions. A single cloud top/base can be set. This solid cloud layer is opaque to IR emissions, so you will have a hard time shooting down an opponent who is on the other side of the clouds. The default cloud base is 2800 feet, tops at 9000 feet. It is not currently possible to "turn-off" clouds. Portability problems with ACM's usage of the random number generators rand() and random() have been fixed. A problem with architectures where a "long" is not the size of an "int" (DEC Alphas) has been fixed. What's different with revision 4.5: ----------------------------------- The HUD compass and HSI were pointing to true north rather than to magnetic north. This has been fixed. The magnetic variation has been set to eight degrees east (it can be changed in navaid.c). This means that the 18-36 runways at both team's airfields are actually 17-35 runways; the runway heading for the ILS 17 approach at team one's airfield is 172 degrees; the runway heading for the ILS 36 approach at team two's airfield is 352 degrees. A field has been added to the navaid description structure to account for the fact that ILS localizers have a variable beam width (three to six degrees according to the FAA Airman's Information Manual). The two ILS approaches have been adjusted so that their beam widths are 700 feet wide at the runway threshold (per the standard). Porting problems with Solaris 2.3 and DEC Alpha OSF/1 have been fixed. Thanks to Bill Davidson, Peter Asenstorfer, and S.Y. Ni. A problem in the VOR TO/FROM logic was pointed out by Jeff Westbrook and has been fixed. A problem with monochrome support was fixed by Jeff Westbrook. ACM's configuration facility was rebuilt using autoconf 1.9. What's different with revision 4.4: ----------------------------------- Simple visual depth cueing has been added to ACM. Depth cueing is only activated on color or grey-scale screens that have at least 8 bit planes. Visibility can be set using the "-visibility" switch on the acms command line. It produces interesting, if slow, results when used with any of the Hawaiian Island scenes. I intend to improve the performance and visual fidelity of this feature. A bug in the depth cueing color blending code has been fixed. Fixes to src/makefile.in and V/lib/Makefile.in have been applied. A "make depend" target has been added. What's different with revision 4.3: ----------------------------------- Drones will now maneuver and attempt to attack you with missiles. The original inspiration and code changes were supplied by Jason Nyberg (nyberg@ctron.com). The drone tracking method was modified and the missile launch logic was created by Riley Rainey. A bug in the AIM-9 time-to-target HUD calculation was fixed. Support for NCD's netaudio software has been added. The NCD netaudio software is free and available in source form via anonymous ftp from ftp.x.org. Netaudio 1.1 does not allow the user to switch the audio output port on a Sun IPX (an IPX has both an internal speaker and an external jack for headphones or separate speakers). You can switch ports by using the SunOS /usr/demo/SOUND/x_soundtool before executing acms. The scene file format has been modified slightly. The third line is now the color to be used for the "ground". The kauai-scene, oahu-scene and maui-scene files display environments around those Hawaiian islands. Terrain elevation data was extracted from USGS one degree Digital Elevation Model (DEM) data files. Because of the complexity of these scenes, rendering speed is unacceptably slow on all but the fastest contemporary workstations. A bug in the V library backface clipping code was fixed by Tim Love. A bug in the V library was resulting in oddly colored instrument panels at seemingly random times. This has been fixed. A problem with the landing gear parameters on the F-16 has been fixed. Acms 4.2 core dumped on AIX systems. This has been fixed. Tom McConnell supplied the changes. What's different with revision 4.2: ----------------------------------- Several nits reported by CodeCenter have been repaired by Brad Bass. Makefiles now use the $(MFLAGS) macro, where needed. What's different with revision 4.1: ----------------------------------- Ultrix and HP-UX make(1) was having problems with the $(MAKEFLAGS) directive in V/Makefile.in. It has been removed. It's removal should not affect the build process. The Ultrix 4.3 shell was having problems with "./configure". The problem has been fixed. A problem in "./Makefile" that would cause a mis-identification of the default target has been fixed. ClipPoly.c was unused in ACM 4, but has been updated so that it compiles. A problem in inventory.c that was causing the nose-wheel steering mode to stay enabled at all times has been fixed. This problem was pointed-out by _ Mats Lofkvist (d87-mal@nada.kth.se). What's different with revision 4.0: ----------------------------------- Combat Simulation ----------------- Mig-29's are now the default team two plane. The HUD display has been improved. A bug in the missile tracking algorithm that would induce misses when the target was moving at a high speed has been fixed. ACM now supports situation recording and playback. The "{" key will start recording, the "}" key ends it. The positions of all aircraft existing during the recording period will be saved in the file "./back_box_output". That file can be played back by moving it to the file "./black_box_input". Activate the playback by pressing the "[" key while you're in ACM. DME, VOR's, Localizers, and Glide Slopes have been added. An HSI has been added to provide VOR and ILS readouts. To activate the HSI, press the 'R' key. Each press of the 'R' key cycles through RADAR -> HSI -> RADAR STANDBY. The Omni Bearing Selector is moved 20 degrees with the '7' key, and one degree with the '8' key. The '9' key increases the NAV frequency by 1 MHz, the '0' key increases it by 0.05 MHz. The selected frequency is displayed at the lower right-hand section of the HSI. If you want to shoot an ILS approach, I suggest the following settings: LEVEL FLIGHT: power 45 %RPM flaps 20 gear up speed brake deployed as needed speed ~ 150 kts ON GLIDE SLOPE: power 35 %RPM flaps 20 gear down speed brake retracted speed 140-150 kts AOA 10-11 degrees When you shoot the ILS 17 approach, don't forget to set the OBS dial to the runway heading (172 degrees). Otherwise, you'll get a very confusing picture of which way to fly. This approach configuration gives you a good opportunity to practice soft landings. Flight Simulation ----------------- Engine response is no longer instantaneous. Engine RPM (power) will increase and decrease gradually to a newly selected setting. The aircraft simulation model has been changed substantially. Tim Tessin uncovered a bug in pm.c that was substantially degrading the performance of all aircraft in high angle of attack situations. It's been fixed. Several problems with the lift-curve determination have been fixed. The lift coefficient is now determined by interpolation. The lift contribution of flaps has been modified to be more consistent with reality. Aircraft control surface effectiveness has been increased substantially. I believe that this increase in consistent with a more realistic simulation. ACM now models aircraft motion on the ground more accurately. ACM actually models the spring and motion damping effects of the landing gear struts, as well as the contribution of ground friction by the wheels. A problem with the roll dynamics of the flight simulation model pointed out by Tim Tessin has been fixed. The roll model (no pun intended) has been substantially re-worked to be able to use standard NACA stability derivatives to describe aircraft roll performance. The pitch and yaw dynamics have been modified to use NACA derivatives. The outside view has been modified. The F-16 flight model has been modified to be more well behaved; lateral and longitudinal motion damping coefficients have been increased. The Graphics ------------ The graphics have been re-vamped to be much faster on color workstations. Monochrome graphics are slower. Object clipping has been improved in the V library to improve rendering performance. The Guts of ACM --------------- ACM now participates in the X11 WM_CLOSEDOWN and WM_DELETE_WINDOW protocols. The directory structure has been modified to get the object description files out of the source directory. Object files now all have a '.obj' extension. The 'make install' target has been improved. Aircraft descriptions are now defined in the file "objects/inventory". Terrain layout is now described using a "scene" file. Acms accepts a "-s scene-file-name" command line option. The file "default.acmscene" describes the default layout. A periodic alarm facility has been added in the guts of ACM. See alarm.[hc] for details. An example of its use can be found in navaid.c; it is used to periodically update DME readouts on all aircraft. It is designed to be compatible with variants of ACM that modify deltaT on the fly. The radar display has been modified to be more closely coupled to the V library. This code was borrowed from the ACM 4.0 version. If no geometry specification is supplied, the ACM server now computes a reasonable window geometry based on the screen's width. Keypad view selection has been added for Sun systems with some help from Keith Fredericks (keith@cray.com). What's different with revision 2.4: ----------------------------------- Missiles now use a more realistic target tracking method, known as proportional navigation guidance. Sustained aircraft load factors at high speeds are now limited to a range of about +10.0 to -4.0 gees. More math portability problems have been worked-around. src/manifest.h contains the definition NEEDS_COPYSIGN. You may comment this out if your system supports the IEEE copysign function. This revision has been tested with X11R5. What's different with revision 2.3: ----------------------------------- This revision repairs several portability problems uncovered in revision 2.2. A problem with IEEE math in interpolate.c has been worked-around. Invalid interpolation requests (which shouldn't happen in ACM) will now result in messages being printed to standard error. Several debugging code fragments are now only conditionally compiled. See manifest.h for more information. A problem controlling aircraft resupply could generate unexpected errors from a system's sqrt function ("sqrt: domain error", for example). It has been fixed. What's different with revision 2.2: ----------------------------------- Explosions now appear in the skies of ACM. Explosions will appear when an aircraft is struck by a missile or cannon shell. Players go out with a bang, too. The flight simulation model has been tweaked to allow for spins. I don't think you can really spin an F-16, but if you'd like to try it in ACM, do this: build up some airspeed in level flight and then go vertical (pitch up to ninety degrees, or thereabouts). Cut the throttle and afterburner and keep the nose pointed vertically. Eventually, the F-16 will begin to fall back to earth -- and typically enter a spin. The only recovery procedure that I've tried that works is to apply full forward (down) elevator to break the stall; then re-apply power. Elevator trim has been added. The (J) key sets to the elevator trim to be equal to the current elevator setting. The (U) key resets it to the normal takeoff setting. Typically, you'll get the aircraft into the pitch configuration that you want (e.g. level flight) and then press the (J) key -- then move the elevator control to the neutral position (the center of the HUD). Aircraft now have functioning landing gear. The (G) key acts as the landing gear handle. A landing gear handle and status lights are located to the right of the radar set. Each aircraft now carries a limited number of air-to-air missiles (eight, to be precise). Aircraft can now be re-armed and re-fueled on the ground. To do this, a player must land successfully at the team's home airfield and come to a complete stop. After an interval of not greater than 30 seconds, the aircraft will be completely re-armed and refueled. Aircraft damage is repaired, as well. Acm's reaction to the resizing of its window has been improved substantially. The code handling the HUD altitude, airspeed, and heading ladders has been improved. A problem with acms dumping core when it cannot access the graphics description files has been fixed. Thanks go to Mark Moraes. Acm now makes an effort to select an appropriate X Visual to run in. These changes are based on code supplied by Mark Hall. A problem with unwanted NoExpose events on monochrome displays was fixed by Georges Lauri. Acm's usage of the X DISPLAY environment variable has been improved with the help of some code from Michael Pall. Now systems where the ACM server is running on the same system as the X server can get "unix:*" and "local:*" connections. GENERAL NOTES ------------- This software is divided into three major parts: the 3-D graphics routines, the DIS library and the flight simulator itself. The 3-D stuff is contained in the V directory. V/lib holds the library itself. V/test contains a program that can be used to test your port of the V library. The dis directory holds the Distributed Interactive Simulation library. `src' contains the remainder of the flight simulator. Comments and suggestions to improve this software are welcome. Several "features" in this revision of the software: * flaps and landing gear can be lowered at rediculously high speeds. * you can fly through mountains. * engines do not flame-out. README: patchlevel-4.8 acm-6.0_20200416/COPYING.txt0000644000000000000000000003543510357223036013457 0ustar rootroot GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS acm-6.0_20200416/acm.tcl0000755000000000000000000007561113175263153013062 0ustar rootroot#!/usr/bin/wish # Simple interface to start the ACM program. # # Requires the tk/tcl interpreter from http://www.tcl.tk/ # Under Windows, the recommended implementation I suggest is that by Magicsplat # at http://www.magicsplat.com/tcl-installer/index.html # # Author: Umberto Salsi (salsi@icosaedro.it) # Version: $Date: 2017/10/29 05:21:15 $ set padx 10 set pady 10 set butw 10 set font_norm "Helvetica 10" set font_em "Helvetica 10 bold" set font_but "Helvetica 10 bold" set font_mono "Courier 9" # Creates a button. # path: tk path of the button. # name: label. # cmd: associated command. # proc StdButt { path name cmd } { global font_but button $path -text $name -width 10 -command $cmd -font $font_but #pack $path } # Text entry box. # w: tk path. # label: description before entry field. # varname: bound variable. # width: width of the text entry field (roughly a char). # unit: description past the entry box, typically the unit of measurement. # proc StdEntry { w label varname width unit } { global font_norm frame $w #pack $w label $w.l -text $label -font $font_norm -width 18 -anchor w pack $w.l -side left if { [string length $unit] >= 1 } { label $w.u -text $unit -font $font_norm pack $w.u -side right } entry $w.v -textvariable $varname -background white -width $width pack $w.v -side right } # Button press feedback and associated command invocation. # proc Press { button } { $button configure -relief sunken update ;# update window after 500 ;# wait 0.5 s $button configure -relief raised ;# release button $button invoke ;# execute command bound to the button } # Returns the absolute path of the file using the current working directory for # resolution. Returns the path itself if not relative. # proc abspath { file } { if { ! [file exists $file] } { return $file } if { [file pathtype $file] == "relative" } { set file [file join [pwd] $file] } return $file } # Tries to figure out where the objects directory is and return the best guess. # proc GuessObjectsDir { } { global program objects if { [string length $objects] > 0 } { return } if { [string length $program] == 0 } { return } set d [file dirname [file dirname $program]] set d "$d/objects" if { [file exists $d] } { set objects $d } } # Parse int number. Returns 0 on error. proc parseInt { x } { if { [scan $x "%d" y] == 1 } { return $y } else { return 0 } } # Par floating point number. Returns zero on error. proc parseFloat { x } { if { [scan $x "%f" y] == 1 } { return $y } else { return 0.0 } } set PI 3.141592653589793 set FEETtoMETERS 0.30480060960 set EARTH_MAJOR 6378137.0 # Parse latitude. # lat_string: latitude as "DD-PP-SS.SSSH". # Returns: RAD. proc parseLatitude {lat_string} { global PI if { [scan $lat_string "%d-%d-%f%c" d p s e] != 4 } { error "Failed to parse latitude $lat_string." return 0 } set lat [expr $d/180.0*$PI + ($p/60.0/180.0*$PI) + $s/3600.0/180.0*$PI] if { [string compare $e "S"] == 0 } { set lat [expr - $lat] } return $lat } # Parse longitude. # s: latitude as "DD-PP-SS.SSSH". # Returns: RAD. proc parseLongitude {lon_string} { global PI if { [scan $lon_string "%d-%d-%f%c" d p s e] != 4 } { error "Failed to parse longitude $lon_string." return 0 } set lon [expr $d/180.0*$PI + ($p/60.0/180*$PI) + $s/3600.0/180*$PI] if { [string compare $e "W"] == 0 } { set lat [expr - $lon] } return $lon } proc formatLatitude {lat} { global PI set e "N" if { $lat < 0 } { set lat [expr - $lat] set e "S" } set lat [expr $lat / $PI * 180.0] set d [expr floor($lat)] set lat [expr 60.0*($lat - $d)] set p [expr floor($lat)] set lat [expr 60.0*($lat - $p)] set s $lat return [format "%02.0f-%02.0f-%02.3f%s" $d $p $s $e] } proc formatLongitude {lon} { global PI set e "E" if { $lon < 0 } { set lon [expr - $lon] set e "W" } set lon [expr $lon / $PI * 180.0] set d [expr floor($lon)] set lon [expr 60.0*($lon - $d)] set p [expr floor($lon)] set lon [expr 60.0*($lon - $p)] set s $lon return [format "%03.0f-%02.0f-%02.3f%s" $d $p $s $e] } # Returns runway ends gedetic coordinates given it center, length and bearing. # Used to convert the RWY2 records. # Return: list of lat1, lon1, lat2 and lon2. proc computeRunwayEnds { center_lat_field center_lon_field len_field heading_field } { global PI FEETtoMETERS EARTH_MAJOR set center_lat [parseLatitude $center_lat_field] set center_lon [parseLongitude $center_lon_field] set half_len [expr 0.5 * [parseFloat $len_field] * $FEETtoMETERS] set heading [expr [parseFloat $heading_field] / 180.0 * $PI] # Normalize heading range to [0,180[ so runway ends can be listed in # the correct order. if { $heading >= $PI } { set heading [expr $heading - $PI] } set delta_lat [expr $half_len * cos($heading) / $EARTH_MAJOR] set delta_lon [expr $half_len * sin($heading) / ($EARTH_MAJOR * cos($center_lat))] return [list \ [formatLatitude [expr $center_lat - $delta_lat]] \ [formatLongitude [expr $center_lon - $delta_lon]] \ [formatLatitude [expr $center_lat + $delta_lat]] \ [formatLongitude [expr $center_lon + $delta_lon]] ] } set displayLongMessageCount 0 proc DisplayLongMessage { title content } { global displayLongMessageCount set displayLongMessageCount [expr $displayLongMessageCount + 1] set w .displayLongMessage_$displayLongMessageCount toplevel $w wm title $w $title wm minsize $w 400 300 frame $w.f text $w.f.t -width 50 -height 10 -yscrollcommand "$w.f.sbar set" scrollbar $w.f.sbar -orient vertical -command "$w.f.t yview" $w.f.t insert 1.0 $content $w.f.t see end pack $w.f.t -side left -fill y -expand true -fill both pack $w.f.sbar -side left -fill y pack $w.f -expand true -fill both button $w.ok -text " OK " -command "destroy $w" pack $w.ok -side bottom -pady 5 wm withdraw $w update wm deiconify $w } proc RunACM {} { global \ env \ mouse_mode \ airspeed \ altitude \ debug \ dis_force \ dis_protocol \ dis_relay_name \ dis_relay_port \ dis_appl \ dis_exercise \ dis_site \ drone_mode \ drone_aggressiveness \ framerate \ fuel \ payload \ hud_mode \ geometry_w geometry_h geometry_x geometry_y \ heading \ joystick \ dept_descr \ dept_time_usenow \ dept_time \ latitude \ longitude \ objects \ plane \ program \ eye_to_screen_cm \ downward_view_angle_deg \ sound \ visibility \ clouds_base \ clouds_top \ wind_d \ wind_v \ gust \ ground_mode \ if { [file exists $program] } { set program [abspath $program] } if { [file exists $objects] } { set objects [abspath $objects] } set user "guest" if { [info exists env("USER")] } { # Typically available on *nix. set user $env("USER") } elseif { [info exists env("USERNAME")] } { # Available on Cygwin. set user $env("USERNAME") } set opt "-name \"$user\" -mouse-mode $mouse_mode -da 0.$drone_aggressiveness" if { [string compare $drone_mode "hunting" ] == 0 } { set opt "$opt -drone-mode HUNTING" } else { set opt "$opt -drone-mode DOG_FIGHT" } if { [string length $geometry_w] >= 1 && [string length $geometry_h] >=1 } { set geometry_w [parseInt $geometry_w] set geometry_h [parseInt $geometry_h] set opt "$opt -geometry ${geometry_w}x$geometry_h" if { [string length $geometry_x] >= 1 && [string length $geometry_y] >= 1 } { set geometry_x [parseInt $geometry_x] set geometry_y [parseInt $geometry_y] set opt "$opt+$geometry_x+$geometry_y" } } if { [string length $objects] >= 1 } { set opt "$opt -objects $objects" } if { [string length $eye_to_screen_cm] >= 1 } { set eye_to_screen_cm [expr floor(10.0 * [parseFloat $eye_to_screen_cm]) / 10] if { $eye_to_screen_cm < 5 } { set eye_to_screen_cm 5 } if { $eye_to_screen_cm > 500 } { set eye_to_screen_cm 500 } set opt "$opt -eye_to_screen_cm $eye_to_screen_cm" } if { [string length $downward_view_angle_deg] >= 1 } { set downward_view_angle_deg [expr floor(10.0 * [parseFloat $downward_view_angle_deg]) / 10] if { $downward_view_angle_deg < 0.0 } { set downward_view_angle_deg 0.0 } if { $downward_view_angle_deg > 45.0 } { set downward_view_angle_deg 45.0 } set opt "$opt -downward_view_angle_deg $downward_view_angle_deg" } if { $dis_protocol } { set opt "$opt -force $dis_force -dis-relay-name \"$dis_relay_name\" -dis-relay-port $dis_relay_port -dis-site \"$dis_site\" -dis-exercise \"$dis_exercise\" -dis-appl \"$dis_appl\"" } if { ! $sound } { set opt "$opt -no-sound" } if { [string length $framerate] >= 1 } { set framerate [parseInt $framerate] set opt "$opt -frame-rate $framerate" } if { [string length $visibility] >= 1 } { set visibility [parseFloat $visibility] set opt "$opt -visibility $visibility" } set clouds_base [parseFloat $clouds_base] set clouds_top [parseFloat $clouds_top] if { $clouds_base <= $clouds_top } { set opt "$opt -clouds-range $clouds_base $clouds_top" } if { [string length $clouds_base] >= 1 && [string length $clouds_top] >= 1 } { set clouds_base [parseFloat $clouds_base] set clouds_top [parseFloat $clouds_top] } if { [string length $wind_d] >= 1 && [string length $wind_v] >= 1 } { set wind_d [parseInt $wind_d] set wind_v [parseInt $wind_v] set opt "$opt -wind $wind_d/$wind_v" } if { [string length $gust] >= 1 } { set gust [parseFloat $gust] set opt "$opt -gust $gust" } set opt "$opt -ground-mode $ground_mode" set opt "$opt -plane \"$plane\"" if { [string length $fuel] > 0 } { set fuel [parseInt $fuel] set opt "$opt -fuel $fuel" } if { [string length $payload] > 0 } { set payload [parseInt $payload] set opt "$opt -payload $payload" } if { $hud_mode } { set opt "$opt -hud-mode" } if { ! $dept_time_usenow && [string length $dept_time] > 0 } { #set opt "$opt -departure-time \"$dept_time\"" set opt "$opt -departure-time $dept_time" } if { [string length $latitude] >= 1 } { set opt "$opt -latitude $latitude" } if { [string length $longitude] >= 1 } { # FIXME: missing validation #scan $longitude "%d-%d-%f%s" d p s e #set lon [expr $d + ($p/60.0) + $s/3600.0] #if { [string compare $e "W"] == 0 } { # set lon [expr - $lon] #} set opt "$opt -longitude $longitude" } if { [string length $altitude] >= 1 } { set altitude [parseInt $altitude] set opt "$opt -altitude $altitude" } if { [string length $heading] >= 1 } { set heading [parseInt $heading] set opt "$opt -heading $heading" } if { [string length $airspeed] >= 1 } { set airspeed [parseInt $airspeed] set opt "$opt -airspeed-kt $airspeed" } #if { [string length $joystick] >= 1 } { # set opt "$opt -js $joystick" #} if { $debug } { set cmd "xterm -e gdb --args $program $opt" #puts "$cmd" } else { set cmd "$program $opt" } wm iconify . # Notes about the behavior of the tcl "exec" command. # $out collects both stdout and stderr. # If the invoked program sends anything to stderr, "exec" will # report error code 1 anyway, disregarding the actual exit status. # If the exit status of the program is error but no output sent to stderr, # tcl adds the line "child process exited abnormally" to $out. set status [catch {eval exec $cmd} out] wm deiconify . if { $status == 0 } { if { [string length $out] > 0 } { DisplayLongMessage "ACM message for you" $out } } else { DisplayLongMessage "ACM Error Report" \ "ACM ERROR REPORT\n\nCommand\n--------------------\n$cmd\n\nOutput\n--------------------\n$out\n\nExit code\n--------------------\n$status" } } proc SetDefault { } { global \ rcfile \ mouse_mode \ airspeed \ altitude \ debug \ dis_force \ dis_protocol \ dis_relay_name \ dis_relay_port \ dis_appl \ dis_exercise \ dis_site \ drone_mode \ drone_aggressiveness \ framerate \ fuel \ payload \ hud_mode \ geometry_w geometry_h geometry_x geometry_y \ heading \ joystick \ dept_descr \ dept_time_usenow \ dept_time \ latitude \ longitude \ objects \ plane \ program \ eye_to_screen_cm \ downward_view_angle_deg \ sound \ visibility \ clouds_base \ clouds_top \ wind_d \ wind_v \ gust \ ground_mode \ set mouse_mode "normal" set airspeed "" set altitude "" set debug 0 set dis_force "Other" set dis_protocol 0 set dis_relay_name "" set dis_relay_port 3000 set dis_appl -1 set dis_exercise 1 set dis_site -1 set drone_mode "dog fight" set drone_aggressiveness 50 set framerate 20 set fuel "" set payload 150 set hud_mode 0 set geometry_w "800" set geometry_h "600" set geometry_x "0" set geometry_y "0" set heading "" set joystick "" set dept_descr "" set dept_time_usenow "1" set dept_time "" set latitude "" set longitude "" set objects "" if { [file exists "objects"] } { set objects "objects" } else { # keep curr value } set plane "C-172" if { [file exists "acm.exe"] } { set program "acm.exe" } elseif { [file exists "src/acm/acm.exe"] } { set program "src/acm/acm.exe" } else { # keep curr value } set eye_to_screen_cm 50.0 set downward_view_angle_deg 10.0 set sound 0 set visibility 20 set clouds_base 0 set clouds_top 0 set wind_d "0" set wind_v "0" set gust 0 set ground_mode flat } proc Save { } { global \ rcfile \ mouse_mode \ airspeed \ altitude \ debug \ dis_force \ dis_protocol \ dis_relay_name \ dis_relay_port \ dis_appl \ dis_exercise \ dis_site \ display \ drone_mode \ drone_aggressiveness \ framerate \ fuel \ payload \ hud_mode \ geometry_w geometry_h geometry_x geometry_y \ heading \ joystick \ dept_descr \ dept_time_usenow \ dept_time \ latitude \ longitude \ objects \ plane \ program \ eye_to_screen_cm \ downward_view_angle_deg \ sound \ visibility \ clouds_base \ clouds_top \ wind_d \ wind_v \ gust \ ground_mode \ set fid [open $rcfile w] puts $fid "set mouse_mode \"$mouse_mode\"" puts $fid "set airspeed \"$airspeed\"" puts $fid "set altitude \"$altitude\"" puts $fid "set debug \"$debug\"" puts $fid "set dis_protocol \"$dis_protocol\"" puts $fid "set dis_relay_name \"$dis_relay_name\"" puts $fid "set dis_relay_port $dis_relay_port" puts $fid "set dis_appl $dis_appl" puts $fid "set dis_exercise $dis_exercise" puts $fid "set dis_site $dis_site" puts $fid "set drone_mode \"$drone_mode\"" puts $fid "set drone_aggressiveness $drone_aggressiveness" puts $fid "set framerate \"$framerate\"" puts $fid "set fuel \"$fuel\"" puts $fid "set payload \"$payload\"" puts $fid "set hud_mode $hud_mode" puts $fid "set geometry_w \"$geometry_w\"" puts $fid "set geometry_h \"$geometry_h\"" puts $fid "set geometry_x \"$geometry_x\"" puts $fid "set geometry_y \"$geometry_y\"" puts $fid "set heading \"$heading\"" puts $fid "set joystick \"$joystick\"" puts $fid "set dept_descr \"$dept_descr\"" puts $fid "set dept_time_usenow \"$dept_time_usenow\"" puts $fid "set dept_time \"$dept_time\"" puts $fid "set latitude \"$latitude\"" puts $fid "set longitude \"$longitude\"" puts $fid "set objects \"$objects\"" puts $fid "set plane \"$plane\"" puts $fid "set program \"$program\"" puts $fid "set eye_to_screen_cm \"$eye_to_screen_cm\"" puts $fid "set downward_view_angle_deg \"$downward_view_angle_deg\"" puts $fid "set sound \"$sound\"" puts $fid "set dis_force $dis_force" puts $fid "set visibility \"$visibility\"" puts $fid "set clouds_base \"$clouds_base\"" puts $fid "set clouds_top \"$clouds_top\"" puts $fid "set wind_d \"$wind_d\"" puts $fid "set wind_v \"$wind_v\"" puts $fid "set gust \"$gust\"" puts $fid "set ground_mode \"$ground_mode\"" close $fid } proc readPlanesList { } { global program objects if { ! [file exists "$program"] } { return ERROR_missing_program } if { ! [file exists "$objects"] } { return ERROR_missing_objects_dir } catch {exec $program -objects $objects -plane xxx} err set planes [split $err "\n"] set planes [lrange $planes 1 [expr [llength $planes] - 2]] set planes [lsort $planes] return $planes } proc updatePlanesMenu { } { # Populates the planes menu global planes_menu set planes [readPlanesList] $planes_menu delete 0 9999 foreach p $planes { $planes_menu add command -label $p -command "set plane \"$p\"" } } proc show_panel { panel } { # Raise all the tab button: .tab.plane configure -relief raised .tab.departure configure -relief raised .tab.environment configure -relief raised .tab.drones configure -relief raised .tab.configure configure -relief raised .tab.dis configure -relief raised # Hide all the panels: pack forget .plane .departure .environment .drones .configure .dis # Sunk selected button and show selected panel: .tab.$panel configure -relief sunken pack .$panel -anchor nw -expand 1 -fill both -padx 30 -pady 15 } SetDefault # # Load saved preferences: # set home $env(HOME) set rcfile "$home/.acmtk.rc" if { [file exists $rcfile] } { source $rcfile } wm title . "Air Combat Maneuvering" # # Layout: # # Tab buttons: pack [frame .tab] -side top -anchor nw # Buttons: pack [frame .buttons] -side bottom -anchor se pack [frame .space -width 20] -side bottom # Panels: pack \ [frame .plane] \ [frame .departure] \ [frame .environment] \ [frame .drones] \ [frame .configure] \ [frame .dis] \ -anchor nw # # Tab buttons: # set f .tab button $f.plane -text Plane -command {show_panel plane} button $f.departure -text Departure -command {show_panel departure} button $f.environment -text Environment -command {show_panel environment} button $f.drones -text Drones -command {show_panel drones} button $f.dis -text DIS -command {show_panel dis} button $f.configure -text Configure -command {show_panel configure} pack $f.plane $f.departure $f.environment $f.drones $f.dis $f.configure -side left # # "Plane" panel: # set f .plane.model pack [frame $f] -anchor nw pack [label $f.l -text "Model:" -font $font_norm] -side left set planes_menu [tk_optionMenu $f.v plane ???] pack $f.v -side left set f .plane StdEntry $f.payload "Payload:" payload 8 "lb" StdEntry $f.fuel "Fuel:" fuel 8 "lb" pack $f.payload $f.fuel -anchor nw set g $f.hud_mode pack [frame $g] -anchor nw set g $f.panel pack [frame $g] -anchor nw pack [label $g.l -text "Panel:" -font $font_norm] -side left pack [radiobutton $g.classic -text "Classic" \ -variable hud_mode -value 0 -font $font_norm] -side left pack [radiobutton $g.hud -text "HUD" \ -variable hud_mode -value 1 -font $font_norm] -side left StdEntry $f.eye_to_screen_cm "Eye dist. from screen:" \ eye_to_screen_cm 5 "cm" pack $f.eye_to_screen_cm -anchor nw StdEntry $f.downward_view_angle_deg "Downward view angle:" \ downward_view_angle_deg 5 "DEG" pack $f.downward_view_angle_deg -anchor nw # # "Departure" panel: # proc error {msg} { tk_messageBox -type ok -icon error -message $msg -parent . -title Error } # Trim and split the string at spaces. Return list of fields. # Empy lines and lines beginning with '#' contains zero fields. proc mysplit {s} { set res {} set s [string trim $s] if { [string length $s] == 0 || [string compare [string index $s 0] "#"] == 0 } { return $res } set l [split $s] foreach e $l { set x [string trim $e] if {[string length $x] > 0} { lappend res $x } } return $res } # Zone selected from zones menu. Parses the scenery file and collects runways, # then populates the runways list box. # zones_path: path of the zones file needed for relative path resolution. # zone: path of the scenery; if relative, join directory of zones file. proc selectZone {zones_path zone} { global curr_zone runways_listbox $runways_listbox delete 0 end set curr_zone $zone set zone_path $zone if {[file pathtype $zone_path] == "relative"} { set zones_dir [file dirname $zones_path] set zone_path "$zones_dir/$zone_path" } if [catch {open $zone_path r} f] { error "Failed opening $zone_path." return } set entries {} while {[gets $f line] >= 0} { set args [mysplit $line] if {[llength $args] == 10 && [lindex $args 0] == "RWY"} { set lat1 [lindex $args 6] set lon1 [lindex $args 7] set lat2 [lindex $args 8] set lon2 [lindex $args 9] } elseif {[llength $args] == 9 && [lindex $args 0] == "RWY2"} { set ends [computeRunwayEnds [lindex $args 6] [lindex $args 7] \ [lindex $args 4] [lindex $args 8]] set lat1 [lindex $ends 0] set lon1 [lindex $ends 1] set lat2 [lindex $ends 2] set lon2 [lindex $ends 3] } else { continue } set ends [split [lindex $args 2] "/"] lappend entries [format " %-4s %-3s %s %s" [lindex $args 1] [lindex $ends 0] $lat1 $lon1] lappend entries [format " %-4s %-3s %s %s" [lindex $args 1] [lindex $ends 1] $lat2 $lon2] } set entries [lsort -dictionary $entries] foreach e $entries { $runways_listbox insert end $e } close $f } # Populates the zones menu reading the specified zones file. # proc updateZonesMenu {zones_path} { global curr_zone zones_menu set curr_zone "" if [catch {open $zones_path r} f] { error "Failed opening $zones_path." return } $zones_menu delete 0 end set curr_zone "" while {[gets $f line] >= 0} { set args [mysplit $line] if {[llength $args] != 5} { continue } set zone [lindex $args 4] if {[string length $curr_zone] == 0} { set curr_zone $zone } $zones_menu add command -label $zone -command "selectZone {$zones_path} {$zone}" } close $f } # Runway selection callback bind to the <> event. # Retrieve the runway just selected, parse its content and set the # departure fields accordingly: description, lat, lon, heading. # proc selectRunway {} { global runways_listbox curr_zone dept_descr latitude longitude heading altitude airspeed set i [lindex [$runways_listbox curselection] 0] if { [string length $i] == 0 } { return } set l [mysplit [$runways_listbox get $i]] if { [llength $l] != 4 } { return } set airport [lindex $l 0] set rwyend [lindex $l 1] set latitude [lindex $l 2] set longitude [lindex $l 3] set dept_descr "[file tail $curr_zone] $airport $rwyend" set heading [expr [scan $rwyend "%d"] * 10] set altitude "" set airspeed "" } # Load available zones and initialize zones menu and runways list box. # proc readZonesFile {} { global objects curr_zone set zones_path "$objects/zones.txt" if { [file exists $zones_path] } { updateZonesMenu $zones_path if {[string length $curr_zone] > 0} { selectZone $zones_path $curr_zone } } else { error "Zones file $zones_path not found." } } set f .departure # Zones menu from the zones file: set curr_zone "" set g $f.zones pack [frame $g] -anchor nw pack [label $g.l -text "Zone:"] -side left set zones_menu [tk_optionMenu $g.zones_menu curr_zone ???] pack $g.zones_menu -side left # Runways from the selected zone: set g $f.runways_listbox pack [frame $g] -expand 1 -fill both -anchor nw -pady $pady pack [label $g.l -text "Runway:"] -anchor nw pack [listbox $g.lb -height 6 -yscrollcommand [list $g.sb set] -font $font_mono] -expand 1 -fill both -side left pack [scrollbar $g.sb -orient vertical -command [list $g.lb yview] ] -fill y -side left set runways_listbox $g.lb # Invoke selectRunway on selection from this listbox: bind $runways_listbox <> selectRunway readZonesFile # Departure the user may choose from the widgets above or edit by hand: StdEntry $f.dept_descr "Description:" dept_descr 30 "" StdEntry $f.latitude "Latitude:" latitude 20 "" StdEntry $f.longitude "Longitude:" longitude 20 "" StdEntry $f.altitude "Altitude:" altitude 8 "ft" StdEntry $f.heading "Magnetic Heading:" heading 4 "DEG" StdEntry $f.airspeed "True Air Speed (TAS):" airspeed 4 "kt" pack $f.dept_descr $f.latitude $f.longitude $f.altitude $f.heading $f.airspeed \ -anchor nw set g $f.dept_time pack [frame $g] -anchor nw pack [label $g.l -text "Time:" -font $font_norm] -side left set dept_time_entry $g.t pack [entry $dept_time_entry -textvariable dept_time -width 30 -font $font_mono] -side left # If using "now time", this proc disables the time entry box. proc onUseNowCheck {} { global dept_time_entry dept_time_usenow if { $dept_time_usenow } { $dept_time_entry configure -state disable } else { $dept_time_entry configure -state normal } } pack [checkbutton $g.usenow -text "now" -variable dept_time_usenow \ -font $font_norm -command onUseNowCheck ] -side left onUseNowCheck # # "Environment" panel: # set f .environment.environment pack [frame $f] -anchor nw # Terrain rendering mode: set g $f.ground pack [frame $g] -anchor nw pack [label $g.l -text "Terrain: " -font $font_norm] -side left pack [radiobutton $g.flat -text "flat" \ -variable ground_mode -value flat -font $font_norm] -side left pack [radiobutton $g.tiled -text "tiled" \ -variable ground_mode -value tiled -font $font_norm] -side left set slider_len 10 # Visibility: scale $f.visibility -from 0 -to 20 -length 300 -variable visibility \ -orient horizontal -label "Visibility (NM):" \ -tickinterval 5 -showvalue false -sliderlength $slider_len \ -font $font_norm -width 10 pack $f.visibility # Clouds layer: set g $f.clouds pack [frame $g] -anchor nw pack [label $g.l1 -text "Clouds base: " -font $font_norm] -side left pack [entry $g.base -textvariable clouds_base -background white -width 6] -side left pack [label $g.l2, -text "ft, top: " -font $font_norm] -side left pack [entry $g.top -textvariable clouds_top -background white -width 6] -side left pack [label $g.l3 -text "ft" -font $font_norm] -side left pack [label $f.clouds_hint -text "(set both to zero for no clouds)" -font $font_norm] -anchor nw # Wind: scale $f.wind_d -from 0 -to 360 -length 300 -variable wind_d \ -orient horizontal -label "Wind direction (DEG):" \ -tickinterval 45 -showvalue false -sliderlength $slider_len \ -font $font_norm -width 10 pack $f.wind_d scale $f.wind_v -from 0 -to 50 -length 300 -variable wind_v \ -orient horizontal -label "Wind velocity (kt):" \ -tickinterval 10 -showvalue false -sliderlength $slider_len \ -font $font_norm -width 10 pack $f.wind_v scale $f.gust -from 0 -to 20 -length 300 -variable gust \ -orient horizontal -label "Wind gust max intensity (ft/s):" \ -tickinterval 5 -showvalue false -sliderlength $slider_len \ -font $font_norm -width 10 pack $f.gust # # "Drone" panel # set g .drones.drone_mode frame $g -pady 20 label $g.l -text "Mode:" -font $font_norm -width 20 -anchor w tk_optionMenu $g.v drone_mode "dog fight" "hunting" pack $g.l $g.v -side left pack $g -anchor nw set g .drones.drone_aggressiveness frame $g -pady 20 label $g.note -text "Max allowed vertical load over structural limits:" label $g.l -text "Aggressiveness:" -font $font_norm -width 20 -anchor w tk_optionMenu $g.v drone_aggressiveness 30 40 50 60 70 80 90 label $g.u -text "%" -font $font_em pack $g.note -anchor nw pack $g.l $g.v $g.u -side left pack $g -anchor nw # # "Configure" panel # set f .configure.program frame $f -pady $pady pack $f -side top -anchor nw label $f.l -text "Program:" -font $font_norm pack $f.l -side left -anchor nw entry $f.v -textvariable program -background white -width 30 pack $f.v -side left button $f.program_sel -text "..." -command { global program set new $program set new [tk_getOpenFile \ -initialfile $program \ -initialdir [file dirname "$program"] \ -parent . \ -filetypes { {{ACM Program} {.exe}} {{All Files} *} \ } \ -title "Select the ACM program" ] if { [string length $new] > 0 } { set program $new updatePlanesMenu } } pack $f.program_sel -side right set f .configure.objects frame $f -pady $pady pack $f -side top -anchor nw label $f.l -text "Objects directory:" -font $font_norm pack $f.l -side left -anchor nw entry $f.v -textvariable objects -background white -width 30 pack $f.v -side left button $f.objects_sel -text "..." -command { global program set new $program set new [tk_chooseDirectory \ -initialdir $objects \ -parent . \ -title "Select the ACM objects directory" ] if { [string length $new] > 0 } { set objects $new readZonesFile } } pack $f.objects_sel -side top -anchor nw set f .configure StdEntry $f.framerate "Frame rate:" framerate 3 "Hz" pack $f.framerate -side top -anchor nw set g $f.mouse_mode frame $g label $g.l -text "Mouse mode:" -font $font_norm -width 20 -anchor w tk_optionMenu $g.v mouse_mode fast normal precise pack $g.l $g.v -side left pack $g -anchor nw #StdEntry $f.joystick "Joystick serial port:" joystick 15 "" #pack $f.joystick -anchor nw set g $f.geometry_size frame $g -pady $pady label $g.l -text "Window size and position:" -font $font_norm -anchor w pack $g.l -anchor nw entry $g.geometry_w -textvariable geometry_w -background white -width 4 pack $g.geometry_w -side left label $g.x -text "x" -font $font_norm pack $g.x -side left entry $g.geometry_h -textvariable geometry_h -background white -width 4 pack $g.geometry_h -side left label $g.p1 -text "+" -font $font_norm pack $g.p1 -side left entry $g.geometry_x -textvariable geometry_x -background white -width 4 pack $g.geometry_x -side left label $g.p2 -text "+" -font $font_norm pack $g.p2 -side left entry $g.geometry_y -textvariable geometry_y -background white -width 4 pack $g.geometry_y -side left pack $g -anchor nw checkbutton $f.sound -text "Enable sound effects" -variable sound -font $font_norm pack $f.sound -anchor nw checkbutton $f.debug -text "Debug through GDB" -variable debug -font $font_norm pack $f.debug -anchor nw # # "DIS" panel # set f ".dis" # Set parameters panel visibility. proc setDisParamsVisibility {} { global dis_protocol if { $dis_protocol } { pack .dis.panel -anchor nw } else { pack forget .dis.panel } } checkbutton $f.enable -text "DIS protocol" \ -variable dis_protocol \ -command setDisParamsVisibility \ -font $font_norm pack $f.enable -anchor nw # Create the DIS parameters panel: set f $f.panel pack [frame $f] -anchor nw setDisParamsVisibility set g $f.force pack [frame $g] -anchor nw pack [label $g.l -text "Force:" -font $font_norm] -side left tk_optionMenu $g.v dis_force Other Friendly Opposing Neutral pack $g.v -side left label $f.relay_l -text "Empty relay server for broadcast:" -font $font_norm pack $f.relay_l -anchor nw StdEntry $f.relay_name "Relay server:" dis_relay_name 25 "" pack $f.relay_name -anchor nw label $f.relay_l1 -text "Shared broadcast port or relay port:" -font $font_norm pack $f.relay_l1 -anchor nw StdEntry $f.relay_port "Port:" dis_relay_port 5 " (3000 std.)" pack $f.relay_port -anchor nw frame $f.vspace2 -height 10 pack $f.vspace2 -anchor nw label $f.relay_l3 -text "DIS connection parameters. Site ID and appl. ID" \ -font $font_norm label $f.relay_l4 -text "should be set to -1 for automatic assignment." \ -font $font_norm pack $f.relay_l3 $f.relay_l4 -anchor nw StdEntry $f.exercise "Exercise ID:" dis_exercise 3 " \[0,255\]" pack $f.exercise -anchor nw StdEntry $f.site "Site ID:" dis_site 5 " \[-1,65535\]" pack $f.site -anchor nw StdEntry $f.appl "Application ID:" dis_appl 5 " \[-1,65535\]" pack $f.appl -anchor nw # # Buttons: # set padx 10 set pady 10 set f ".buttons" StdButt $f.run Run RunACM pack $f.run -padx $padx -pady $pady -side right StdButt $f.default Default SetDefault pack $f.default -padx $padx -pady $pady -side right pack [frame $f.space -width 30] -side right StdButt $f.quit Quit { Save; exit } pack $f.quit -padx $padx -pady $pady -side left $f.run configure -default active bind . "Press $f.run" bind . "Press $f.run" bind . "Press $f.quit" GuessObjectsDir updatePlanesMenu show_panel plane # THE END! acm-6.0_20200416/VERSION.txt0000644000000000000000000000001513646051406013462 0ustar rootroot6.0_20200416 acm-6.0_20200416/Makefile0000644000000000000000000000301213646045017013235 0ustar rootrootWORKING_DIR := $(shell pwd) PROGNAME := acm VER := 6.0 WEBDIR := /home/www.icosaedro.it/public_html/acm BUILD := $(shell date +%Y%m%d) VERSION := ${VER}_${BUILD} DISTFILE := ${PROGNAME}-${VERSION} all: # Really do all (but something does not builds yet): #find . -mindepth 2 -name Makefile \ # | while read m; do make -C $$(dirname $$m) all || exit 1; done # # Only do what we really care the most: make -C src all clean: rm -rf build-doxygen-docs-errors.txt doc/doxygen-html find . -mindepth 2 -name Makefile \ | while read m; do make -C $$(dirname $$m) clean; done strip: .PHONY: rebuild rebuild: clean find . -mindepth 1 -type d \ | while read d; do \ if [ -f $$d/Makefile ]; then \ echo "$$d"; \ (cd $$d; check-included && make-makefile); \ fi \ done make # SUBROUTINE: dist_make_package: clean echo ${VERSION} > VERSION.txt cd .. && \ ln -sf ${WORKING_DIR} ${DISTFILE} && \ tar --create --gzip \ --owner=root --group=root \ --exclude="*CVS*" \ --exclude="*.cvsignore" \ --exclude="*nbproject*" \ --dereference \ ${DISTFILE} \ > /tmp/${DISTFILE}.tar.gz && \ rm ${DISTFILE} && \ echo "Package available in /tmp/${DISTFILE}.tar.gz" distclean: clean dist: dist_make_package doxygen: tools/build-doxygen-docs.sh upgrade: @echo "" @echo "ACM Upgrade Procedure" @echo "=====================" @echo "" @echo "The version of this package is `cat VERSION.txt`. Check for new releases on:" @echo "" @echo " http://www.icosaedro.it/acm/download.html" @echo "" acm-6.0_20200416/src/0000755000000000000000000000000013175511160012362 5ustar rootrootacm-6.0_20200416/src/acm/0000755000000000000000000000000013646051405013126 5ustar rootrootacm-6.0_20200416/src/acm/players.h0000644000000000000000000000222513127461230014752 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #ifndef _players_h #define _players_h #include "pm.h" #include "list.h" #ifdef players_IMPORT #define EXTERN #else #define EXTERN extern #endif EXTERN int players_new(char *logname, list_Type *switches); /** * Release aircraft with the specified reason. The reason is broadcasted * to all the active viewers only if it is != NULL. */ EXTERN void players_kill(craft *c, char *reason); #undef EXTERN #endif acm-6.0_20200416/src/acm/weapon.c0000644000000000000000000000575613064342050014571 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1996 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include "pm.h" #include "weapon_null.h" #include "ccip.h" #include "m61a1.h" #include "aim9m.h" #include "aim120.h" #define weapon_IMPORT #include "weapon.h" #define WEAPONTYPES 5 /* Total no. defined weapons, i.e. size of wtbl[]. */ static weapon_Type * wtbl[WEAPONTYPES]; /* Descriptions of different available weapons. */ static char * names[WEAPONTYPES] = { "----", "M61A1", "AIM-9M", "AIM-120", "MK82" }; int weapon_nameToId(char * name) { int i; for( i = 0; i < WEAPONTYPES; i++ ) if( strcmp(name, names[i]) == 0 ) return i; return -1; } char * weapon_idToName(int id) { if( id < 0 || id >= WEAPONTYPES ) return NULL; return names[id]; } int weapon_countOrdinance(craft * c, int id) { register int i, count = 0; for (i = 0; i < c->cinfo->sCount; ++i) { if (c->station[i].id == id) ++count; } return count; } int weapon_getReadyStation(craft * c, int id) { register int i; for (i = 0; i < c->cinfo->sCount; ++i) { if (c->station[i].id == id) return i; } return -1; } int weapon_selectNextAvailable(craft * c) { int n, m; m = c->curWeapon; n = (c->curWeapon + 1) % WEAPONTYPES; for (; n != m; n = (n + 1) % WEAPONTYPES) { if( n == weapon_NULL ){ c->curWeapon = weapon_NULL; return 1; } else if (weapon_getReadyStation(c, n) >=0 && wtbl[n]->select != NULL){ if ((*wtbl[n]->select) (c) == 1) { c->curWeapon = n; return 1; } } } return 0; /* should never reach this point */ } int weapon_selectByName(craft * c, int id) { if ((*wtbl[id]->select) (c) == 1) { c->curWeapon = id; return 1; } return 0; } int weapon_fire(craft * c) { return (*wtbl[c->curWeapon]->firePress) (c); } int weapon_ceaseFire(craft * c) { if (wtbl[c->curWeapon]->fireRelease != NULL) return (*wtbl[c->curWeapon]->fireRelease) (c); return 0; } int weapon_displaySelected(craft * c, viewer * u, int fpm_x, int fpm_y) { return (*wtbl[c->curWeapon]->display) (c, wtbl[c->curWeapon]->w, u, fpm_x, fpm_y); } int weapon_update(craft * c) { return (*wtbl[c->curWeapon]->update) (c); } void weapon_init() { wtbl[weapon_NULL] = weapon_null_new(); wtbl[weapon_M61A1] = m61a1_new(); wtbl[weapon_MK82] = ccip_new(); wtbl[weapon_AIM9M] = aim9m_new(); wtbl[weapon_AIM120] = aim120_new(); } acm-6.0_20200416/src/acm/drone.h0000644000000000000000000000532013175036232014404 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /** * The original "Smart Drone" code was created by * Jason Nyberg (nyberg@ctron.com). Enhancements added by Riley Rainey. * Further modifications by Umberto Salsi: limits speed to reasonable values; * "G" within structural limits as set in the model definition; avoid to * too low altitudes (but still the drone may crash on the ground :->); * smoother maneuvering. * * @file */ #ifndef _drone_h #define _drone_h #include "pm.h" #ifdef drone_IMPORT #define EXTERN #else #define EXTERN extern #endif typedef enum {drone_DOG_FIGHT_MODE, drone_HUNTING_MODE} drone_Mode; /** * Set how the drone is generated: 1500 ft behind you * (DRONE_DOG_FIGHT_MODE) or randomly up to 50 NM far away in any * direction from you (DRONE_HUNTING_MODE). */ EXTERN void drone_set_mode(drone_Mode drone_mode); /** * Set drone aggressiveness as % of the max vertical load factor. * For example, the value 0.7 means the drones will maneuver with a maximum * vertical load not greater than the 70% of maxLoadZPositive/Negative * (see the inventory file). The default is 0.5. */ EXTERN void drone_set_aggressiveness(double a); /** * Creates e new drone opponent for practicing ACM. */ EXTERN void drone_new(craft * p); /** * Attach the drone data structure to an existing craft. Do nothing * if it is already a drone. Release with drone_release_commands(). */ EXTERN void drone_take_commands(craft *c); /** * Remove drone data structure from craft. */ EXTERN void drone_release_commands(craft *c); /** * Remove current opponent. */ EXTERN void drone_reset_opponent(craft *c); /** * This alarm function is invoked periodically (once per second) to look * for hostile aircraft in the proximity of this DIS entity -- the entity is * owned by another application at this point, we may ask to take control * of it, if a hostile aircraft comes within range. * @param p1 Craft. * @param p2 Viewer. */ EXTERN void drone_endGameDistanceCheck(void * p1, void *p2); #undef EXTERN #endif acm-6.0_20200416/src/acm/planes.h0000644000000000000000000000502113175511064014556 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /** * Retrieves crafts types models from the data base and implements their basic * behavior by setting call-back functions (engine, resupply, ...). * * @file */ #ifndef _planes_h #define _planes_h #include "pm.h" #ifdef planes_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Returns the thrust engine function specific for the specified aircraft. * This module contains specific functions that simulates the performances * of several types of engines; its one of these functions that gets returned. * @param cinfo Specific craft informations. * @return Engine RPM update and thrust calculator function. */ EXTERN inventory_ThrustCalculator * planes_getThrustCalculator(craftType * cinfo); /** * Fuel resupply +10% max fuel load, weapon resupply and damage repair. * This function should be called once for any new aircraft, then every 30 s * while on ground. * If drone, set fuel quantity to half the capacity. * FIXME: fuel resupply of aircraft commented out as it can be set by user. * @param c */ EXTERN void planes_genericResupply(craft * c); /** * Call-back function for the alarm module. * Scans for all the players aircraft; if a player is on the airport * grounds and motionless, then invoke the plane's resupply procedure. */ EXTERN void planes_doResupply(void *dummy1, void *dummy2); /** * Returns the fuel consumed in the last deltaT interval. * @param c * @return Fuel consumed in the last deltaT interval (lb). */ EXTERN double planes_fuelUsed( craft * c ); /** * Allocates a new plane in the ptbl[] table. * @param planeType Name of the plane, for ex. "C-172". * @return Index of the new plane in the ptbl[] table. If negative: -1 == table * full; -2 == unknown plane name. */ EXTERN int planes_newPlane(char *planeType); #undef EXTERN #endif acm-6.0_20200416/src/acm/aps.c0000644000000000000000000011257013175035416014064 0ustar rootroot/* * acm - Auto-Pilot System module * Copyright (C) 2007 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /* The proportional-integrative control algorithm ("PI" from here on) is extensively used in this module. The PI algo can be applied to a black-box system y(t) = f(x(t), t) were t = time x(t) = controlling variable (ex.: aileron position) y(t) = resulting output (ex.: roll speed) The basic problem is how to adjust the value of x in order to achieve and maintain a given target output y_T. The PI algo addresses just this problem. It is expressed by this formula: x(t) = x_ss + Gp * err(t) + Gi * integral(err(z)*dz, z=0...t) were the integral of the error ranges from 0 to t, and the error is defined by err(t) = y(t) - y_T and x_ss is a constant depending on the initial conditions, Gp is the proportional gain, Gi is the integral gain. The time derivative of the x(t) function is x_dot(t) = Gp * y_dot(t) + Gi * (y(t) - y_T) or, in the discrete domain: x(i+1) = x(i) + Gp * (y(i) - y(i-1)) + Gi * (y(i) - y_T) * dt were: i = current sample time i-/+1 = previous or next sample time x(i+1) = new calculated value for the controlling variable y(i) = current value of the controlled variable y(i-1) = previous value at t-dt of the controlled variable Try trickiest part of the PI algo is to choose a good controlled variable y(t) and a good value for the proportionl gain Gp and the integral gain Gi that work for all the aircraft models and in any flight condition of speed and altitude. The table below summarizes the algo used with every autopilot subsystem: A* x(t) y(t) Algorithm used -- -------- ---------------- ------------------------------------- AP elevator pitch rate bare incremental algo AW ailerons roll rate PI with varying target roll rate y_T AC rudder lateral accel. PI */ #include #include #include "flaps.h" #include "hsi.h" #include "../util/memory.h" #include "pm.h" #include "terrain.h" #include "gear.h" #include "../util/units.h" #define aps_IMPORT #include "aps.h" typedef struct { craft * c; /* Pitch rate control. */ _BOOL pitch_rate_enabled; double pitch_rate_transfer; double pitch_rate_target; /* pitch rate to hold (RAD/s) */ double pc_prev_time; /* prev update time */ double pc_prev_pitch_dot; /* previous pitch rate */ double delta_Se; /* current elevator correction [-1.0,1.0] */ /* * Bank rate control. */ _BOOL bank_rate_enabled; /* bank rate control enabled */ double bank_rate_transfer; double bank_rate_target; /* target rate of bank (RAD/s) */ double bank_rate_prev_time; double bank_rate_prev_a_dot; double bank_rate_prev_a_dot_exp; double delta_Sa; /* current ailerons correction [-1.0,+1.0] */ /* Hold altitude and hold VS autopilot (AP) state. */ _BOOL ap_enabled; _BOOL ap_hold_altitude; /* hold altitude or hold VS? */ double ap_target_altitude; /* target altitude (m) */ double ap_prev_time; /* previous update (s) */ double ap_target_vs; /* target vertical speed (m/s) */ double ap_prev_vs; /* previous v.s. (m/s) */ /* Rudder auto-coordination (AC). */ _BOOL ac_enabled; double ac_prev_a; /* the lateral accel. c->G.y ... */ double ac_prev_time; /* ... at this time */ double ac_delta_Sr; /* AC rudder correction */ /* AutoThrottle (AT). */ _BOOL at_enabled; double at_target_v; /* target IAS speed (ft/s) */ double at_prev_v; /* speed at the previous... */ double at_prev_time; /* ...time (s) */ /* Auto-turn (AW). */ _BOOL aw_enabled; double aw_bank_max; /* max bank angle (RAD) */ double aw_w_target; /* target z turn rate (RAD/s) */ double aw_prev_time; /* Auto Landing (AL). */ _BOOL al_enabled; double al_prev_adiff; double al_prev_time; double al_v_touchdown; /* 0.0 = still unknown (m/s) */ _BOOL al_touchdown; /* bouncing fix: set when first contact with ground */ /* Auto Navigation (AN). */ _BOOL an_enabled; double an_prev_time; double an_prev_cdi; /* * Pitch and roll rate control. */ _BOOL rate_control_enabled; /* Warning flags: */ _BOOL ap_warn; _BOOL an_warn; _BOOL al_warn; _BOOL aw_warn; _BOOL at_warn; _BOOL ac_warn; } aps_Type; static double qround(double value, double step) /* Round the given positive value to the nearest quantized value. The quantum is 'step'. Warning: does not work properly with negative values. */ { /* if( value < 0.0 ) return -step * floor(-value / step + 0.5); else */ return step * floor(value / step + 0.5); } static double forceRange(double x, double min, double max) { if( x >= min ){ if( x <= max ){ return x; } else { return max; } } else { return min; } } #define LO units_DEGtoRAD(30.0) #define HI units_DEGtoRAD(60.0) static double get_pitch_rate(craft * c) { double roll_abs, pitch_rate, k; roll_abs = fabs(c->curRoll); if( roll_abs > HI ) return c->q; pitch_rate = c->q*cos(c->curRoll) - c->r*sin(c->curRoll); if( roll_abs > LO ){ k = (roll_abs - LO)/(HI - LO); return (1.0-k)*pitch_rate + k*c->q; } return pitch_rate; /* if( fabs(c->curRoll) < units_DEGtoRAD(30.0) ) return c->q*cos(c->curRoll) - c->r*sin(c->curRoll); else return c->q; */ } static void aps_destruct(void *p) { aps_Type * aps = p; if ( aps == NULL ) return; aps->c->aps = NULL; } /** * Retrieves the APS data from aircraft. If not already set, allocates a new * APS. */ static aps_Type * aps_get(craft * c) { aps_Type * aps; if ( c->aps != NULL ) return (aps_Type *) c->aps; aps = memory_allocate( sizeof( aps_Type ), aps_destruct ); memset(aps, 0, sizeof(*aps)); c->aps = aps; aps->c = c; /* Rests pitch rate control: */ aps->pitch_rate_enabled = FALSE; aps->pitch_rate_transfer = 0.0; aps->delta_Se = 0.0; /* Reset bank rate control: */ aps->bank_rate_enabled = FALSE; aps->bank_rate_transfer = 0.0; aps->delta_Sa = 0.0; /* AP disabled: */ aps->ap_enabled = FALSE; /* AC disabled: */ aps->ac_enabled = FALSE; aps->ac_delta_Sr = 0.0; /* AT disabled: */ aps->at_enabled = FALSE; /* AW disabled: */ aps->aw_enabled = FALSE; aps->aw_bank_max = units_DEGtoRAD(25); /* AL disabled: */ aps->al_enabled = FALSE; /* AN disabled: */ aps->an_enabled = FALSE; /* Rate control disabled: */ aps->rate_control_enabled = FALSE; /* Reset warning flags: */ aps->ap_warn = FALSE; aps->an_warn = FALSE; aps->al_warn = FALSE; aps->aw_warn = FALSE; aps->ac_warn = FALSE; return aps; } /** * Enables pitch control and set target pitch rate. * @param c The aircraft. * @param target Pitch rate to set (RAD/s). */ static void pitch_rate_set(craft * c, double target) { aps_Type * aps; aps = aps_get(c); if( ! aps->pitch_rate_enabled ){ /* Smooth engaging: */ aps->pc_prev_time = curTime; aps->pc_prev_pitch_dot = get_pitch_rate(c); } aps->pitch_rate_enabled = TRUE; aps->pitch_rate_target = target; } /** * Releases the pitch rate controller. * @param c The aircraft. */ static void pitch_rate_disable(craft * c) { aps_Type * aps; if( c->aps == NULL ) return; aps = (aps_Type *) c->aps; aps->pitch_rate_enabled = FALSE; } /* Min/max elevator correction: */ #define PC_DELTA_SE_MAX 1.0 /* Warning if elevator correction outside this range: */ #define PC_DELTA_SE_OUT_RANGE (0.5 * PC_DELTA_SE_MAX) #define PITCH_DOT_MAX units_DEGtoRAD(20.0) /** * If pitch rate control is enabled, and the nose or tail wheel is not in * contact with the ground, updates the elevator correction to attain the * pitch rate set. Otherwise, smoothly reset the elevator correction. * Transition from direct law to rate control and vice-versa is smoothly * performed within about 3 seconds. * @param c The aircraft. */ static void pitch_rate_update(craft * c) { aps_Type * aps; double dt, pitch_dot_exp, pitch_dot; if( c->aps == NULL ) return; aps = (aps_Type *) c->aps; dt = curTime - aps->pc_prev_time; if( dt <= 0.0 ) return; aps->pc_prev_time = curTime; if( aps->pitch_rate_enabled /* && ! gear_noseWheelGroundContact(c) */ ){ aps->pitch_rate_transfer += 0.33 * deltaT; if ( aps->pitch_rate_transfer > 1.0 ) aps->pitch_rate_transfer = 1.0; pitch_dot = get_pitch_rate(c); /* * Basically, the target pitch rate is that set, but here we account * for the transfer of control while the nose/tail wheel loose contact * with the ground: */ pitch_dot_exp = aps->pitch_rate_transfer * aps->pitch_rate_target + (1.0 - aps->pitch_rate_transfer) * pitch_dot; pitch_dot_exp = forceRange(pitch_dot_exp, -PITCH_DOT_MAX, PITCH_DOT_MAX); /* Authority: */ double k = c->cinfo->I.m[1][1] / (-c->cinfo->cmSlope * (1.0 + c->IAS * c->IAS) * c->cinfo->wingS); double Gp = 2000.0 * k; double Gi = 5000.0 * k; aps->delta_Se = aps->delta_Se + Gp * (pitch_dot - aps->pc_prev_pitch_dot) + Gi * (pitch_dot - pitch_dot_exp) * dt; if ( aps->delta_Se < -PC_DELTA_SE_OUT_RANGE || aps->delta_Se > +PC_DELTA_SE_OUT_RANGE ){ aps->ap_warn = TRUE; } aps->delta_Se = forceRange(aps->delta_Se, -PC_DELTA_SE_MAX, +PC_DELTA_SE_MAX); aps->pc_prev_pitch_dot = pitch_dot; } else { /* Smooth release: */ aps->pitch_rate_transfer -= 0.33 * deltaT; if ( aps->pitch_rate_transfer < 0.0 ) aps->pitch_rate_transfer = 0.0; if( aps->delta_Se != 0.0 ){ aps->delta_Se *= 1.0 - 0.3*dt; if( fabs(aps->delta_Se) < 1e-3 ) aps->delta_Se = 0.0; } } } double aps_get_delta_elevator(craft * c) { aps_Type * aps; if ( c->aps == NULL ) return 0.0; aps = (aps_Type *) c->aps; return aps->pitch_rate_transfer * (aps->delta_Se - c->pitchComm); } static double get_roll_rate(craft * c) { double bank_abs, pitch_abs, bank_rate, tanCurPitch, k; bank_abs = fabs(c->curRoll); pitch_abs = fabs(c->curPitch); if( bank_abs > HI || pitch_abs > HI ) return c->p; tanCurPitch = tan(c->curPitch); bank_rate = c->p + c->q*tanCurPitch*sin(c->curRoll) + c->r*tanCurPitch*cos(c->curRoll); if( bank_abs > LO || pitch_abs > LO ){ k = (bank_abs - LO)/(HI - LO); return (1.0-k)*bank_rate + k*c->p; } return bank_rate; } /** * Enables bank rate controller and set bank rate. * @param c The aircraft. * @param target Target bank rate (RAD/s). */ static void bank_rate_set(craft * c, double target) { aps_Type * aps; double bank_rate; aps = aps_get(c); if ( ! aps->bank_rate_enabled ){ aps->bank_rate_enabled = TRUE; /* Smooth engaging: */ bank_rate = get_roll_rate(c); aps->bank_rate_prev_a_dot = bank_rate; aps->bank_rate_prev_a_dot_exp = bank_rate; } aps->bank_rate_target = target; } static void bank_rate_disable(craft * c) { aps_Type * aps; aps = aps_get(c); aps->bank_rate_enabled = FALSE; } /* Max roll rate (RAD/s). */ #define BANK_DOT_MAX units_DEGtoRAD(60.0) /* Max roll rate accel. (RAS/s^2). */ #define BANK_DOT_DOT_MAX units_DEGtoRAD(600.0) /* Max aileron correction control range. */ #define BANK_RATE_SA_MAX 1.0 /** * If the bank rate controller is enabled, and both the main wheels are not * in contact with the ground, updates the ailerons correction to attain the * bank rate set. Otherwise, smoothly resets the ailerons correction. * @param c The aircraft. */ static void bank_rate_update(craft * c) { aps_Type * aps; double a_dot, a_dot_exp, a_dot_dot_exp, delta_Sa; aps = aps_get(c); aps->bank_rate_prev_time = curTime; if ( aps->bank_rate_enabled && ! gear_mainWheelsGroundContact(c) ){ aps->bank_rate_transfer += 0.3*deltaT; if ( aps->bank_rate_transfer > 1.0 ) aps->bank_rate_transfer = 1.0; a_dot = get_roll_rate(c); /* * Basically, the target bank rate is that set, but here we account * for the transfer of control while the main landing wheels loose * contact with the ground: */ a_dot_exp = aps->bank_rate_transfer * aps->bank_rate_target + (1.0 - aps->bank_rate_transfer) * a_dot; /* Compute roll angle accel., apply limit then recalculate: */ a_dot_dot_exp = (a_dot_exp - a_dot) / deltaT; a_dot_dot_exp = forceRange(a_dot_dot_exp, -BANK_DOT_DOT_MAX, BANK_DOT_DOT_MAX); a_dot_exp = a_dot + a_dot_dot_exp * deltaT; a_dot_exp = forceRange( a_dot_exp, -BANK_DOT_MAX, BANK_DOT_MAX); /* authority */ double k = (0.003 * (1.0 + c->IAS * c->IAS)) * c->cinfo->wingS * c->cinfo->wings * c->cinfo->Clda * c->cinfo->maxAileron / c->cinfo->I.m[0][0]; delta_Sa = aps->delta_Sa + 10.0 / k * (a_dot - a_dot_exp - aps->bank_rate_prev_a_dot + aps->bank_rate_prev_a_dot_exp) + 30.0 / k * (a_dot - a_dot_exp) * deltaT; aps->delta_Sa = forceRange( delta_Sa, -BANK_RATE_SA_MAX, BANK_RATE_SA_MAX); aps->aw_warn = fabs(aps->delta_Sa) == BANK_RATE_SA_MAX; aps->bank_rate_prev_a_dot = a_dot; aps->bank_rate_prev_a_dot_exp = a_dot_exp; } else { aps->bank_rate_transfer -= deltaT; if ( aps->bank_rate_transfer < 0.0 ) aps->bank_rate_transfer = 0.0; if( aps->delta_Sa != 0.0 ){ /* Smooth release (-66% within 1.0 s): */ aps->delta_Sa -= aps->delta_Sa * deltaT; if( fabs(aps->delta_Sa) < 1e-3 ) aps->delta_Sa = 0.0; } } } double aps_get_delta_ailerons(craft * c) { aps_Type * aps; if ( c->aps == NULL ) return 0.0; aps = (aps_Type *) c->aps; return aps->bank_rate_transfer * (aps->delta_Sa - c->rollComm); } /* AutoPilot (AP) ============== */ _BOOL aps_ap_enabled(craft * c) { return (c->aps != NULL) && ( ((aps_Type *) (c->aps))->ap_enabled ); } void aps_ap_enable(craft * c) { aps_Type * aps; aps = aps_get(c); if ( aps->ap_enabled ) return; aps_al_disable(c); aps_rate_control_disable(c); aps->ap_enabled = TRUE; aps->ap_hold_altitude = (fabs(c->Cg.z) < 100.0/60.0); aps->ap_target_altitude = qround( c->w.z, units_FEETtoMETERS(100.0) ); aps->ap_target_vs = units_FEETtoMETERS( - c->Cg.z ); aps->ap_prev_time = 0.0; aps->ap_prev_vs = aps->ap_target_vs; } void aps_ap_disable(craft * c) { aps_Type * aps; if( c->aps == NULL ) return; aps = aps_get(c); aps->ap_enabled = FALSE; aps->ap_warn = FALSE; pitch_rate_disable(c); } void aps_ap_toggle(craft * c) { if( aps_ap_enabled(c) ) aps_ap_disable(c); else aps_ap_enable(c); } void aps_ap_set_vs(craft * c, double vs) { aps_Type * aps; aps_ap_enable(c); aps = aps_get(c); aps->ap_hold_altitude = (fabs(vs) < units_FEETtoMETERS(100.0)/60.0); if( aps->ap_hold_altitude ) aps->ap_target_altitude = qround( c->w.z, units_FEETtoMETERS(100.0) ); else aps->ap_target_vs = vs; } #ifdef FIXME_NOT_USED static void aps_ap_set_alt(craft * c, double altitude /* m */) { aps_Type * aps; aps_ap_enable(c); aps = aps_get(c); aps->ap_hold_altitude = TRUE; aps->ap_target_altitude = altitude; } #endif #define AP_DELTA_T 0.2 /* Min vertical speed in hold-altitude mode: */ #define AP_VS_MIN units_FEETtoMETERS(-1000.0/60.0) /* m/s */ /* Max vertical speed in hold-altitude mode: */ #define AP_VS_MAX units_FEETtoMETERS(100.0/60.0) /* m/s */ /* Min/max vertical accel.: */ #define AP_VS_DOT_MAX (0.5 * 9.8) /* m/s^2 */ static void aps_ap_update(craft * c) { aps_Type * aps; double vs, vs_exp, vs_dot_exp, dt, err, a_dot; aps = aps_get(c); if( aps->ap_prev_time == 0.0 ){ /* First time we are called. */ dt = AP_DELTA_T; } else { dt = curTime - aps->ap_prev_time; } if( dt < AP_DELTA_T ) return; aps->ap_prev_time = curTime; aps->ap_warn = FALSE; if( ! aps->ap_enabled ) return; /* Current vertical speed vs (m/s): */ vs = -units_FEETtoMETERS(c->Cg.z); /* Current vertical acceleration vs_dot (m/s^2): */ /* vs_dot = (vs - aps->ap_prev_vs) / dt; */ /* Expected vertical speed vs_exp (m/s): */ if ( aps->ap_hold_altitude ) { /* Current altitude error (m): */ err = c->w.z - aps->ap_target_altitude; if( fabs(err) > units_FEETtoMETERS(150.0) ) aps->ap_warn = TRUE; /* Compute a vertical speed vs_exp suitable to attain the target altitude (m/s): */ vs_exp = forceRange(-err / 15.0, AP_VS_MIN, AP_VS_MAX); } else { vs_exp = aps->ap_target_vs; if( fabs(vs - vs_exp) > units_FEETtoMETERS(200.0/60.0) ) aps->ap_warn = TRUE; } /* Expected vertical acceleration vs_dot_exp (m/s^2). Set max accel. if the v.s. error is 500 fpm or greater. */ vs_dot_exp = forceRange((vs_exp - vs)/2.0, -AP_VS_DOT_MAX, AP_VS_DOT_MAX); /* The angle of the climb path is a = pitch - AOA where AOA is the angle of attack. At constant speed the AOA is constant, so deriving this latter gives: a_dot = pitch_dot = c->q The vertical speed is vs = v*tan(a) where v=c->VT is the TAS. For small angles tan(a)=a, then: vs = v*a Since v is constant, deriving this latter gives: vs_dot = v*a_dot So changes in vertical acceleration can be controlled through c->q: a_dot = vs_dot / v */ a_dot = vs_dot_exp / units_FEETtoMETERS(c->VT + 0.1); pitch_rate_set(c, a_dot); aps->ap_prev_vs = vs; } /* AutoCoordination (AC) ===================== */ void aps_ac_enable(craft * c) { aps_Type * aps; aps = aps_get(c); if( aps->ac_enabled ) return; aps->ac_enabled = TRUE; aps->ac_prev_time = 0.0; aps->ac_prev_a = c->G.y; /* aps->ac_delta_Sr = 0.0; */ aps->ac_warn = FALSE; } void aps_ac_disable(craft * c) { aps_Type * aps; if( c->aps == NULL ) return; aps = aps_get(c); aps->ac_enabled = FALSE; /* aps->ac_delta_Sr = 0.0; */ aps->ac_warn = FALSE; c->Sr = 0.0; } _BOOL aps_ac_enabled(craft * c) { return (c->aps != NULL) && ( ((aps_Type *) (c->aps))->ac_enabled ); } void aps_ac_toggle(craft * c) { if( aps_ac_enabled(c) ) aps_ac_disable(c); else aps_ac_enable(c); } double aps_ac_get_delta_rudder(craft * c) { aps_Type * aps; if ( c->aps == NULL ) return 0.0; aps = (aps_Type *) c->aps; return aps->ac_delta_Sr; } #define AC_DELTA_T 0.01 #define AC_SR_DOT_MAX 0.1 static void aps_ac_update(craft * c) { aps_Type * aps; double dt, a, a_dot, a_dot_exp, delta_Sr; aps = aps_get(c); if( aps->ac_prev_time == 0.0 ){ /* First time we are called. */ dt = AC_DELTA_T; } else { dt = curTime - aps->ac_prev_time; } if( dt < AC_DELTA_T ) return; aps->ac_prev_time = curTime; aps->ac_warn = FALSE; if( aps->ac_enabled && ! gear_noseWheelGroundContact(c) ) { /* Normal AC handling. Update aps->ac_delta_Sr so that to reduce lateral acceleration c->G.y. */ a = c->G.y; a_dot = (a - aps->ac_prev_a) / dt; a_dot_exp = - 0.5 * a; double k = 2000.0 / (1.0 + c->IAS * c->IAS); /* authority */ delta_Sr = aps->ac_delta_Sr + 1.0 * k * (a_dot - a_dot_exp); aps->ac_delta_Sr = forceRange(delta_Sr, -1.0, 1.0); aps->ac_warn = fabs(aps->ac_delta_Sr) == 1.0; aps->ac_prev_a = a; } else if ( aps->ac_delta_Sr != 0.0 ){ /* Smooth release (-66% within 2 s): */ if( aps->ac_delta_Sr != 0.0 ){ aps->ac_delta_Sr -= aps->ac_delta_Sr / 2.0 * dt; if( fabs(aps->ac_delta_Sr) < 1.e-3 ) aps->ac_delta_Sr = 0.0; } } } /* AutoThrottle (AT) ================= */ #define AT_V_STEP units_KTtoFPS(5.0) /* ft/s */ void aps_at_enable(craft * c) { aps_Type * aps; double v; aps = aps_get(c); if( aps->at_enabled ) return; v = c->IAS; if( v < 0.0 ) v = 0.0; aps->at_target_v = qround(v, AT_V_STEP); aps->at_prev_v = v; aps->at_prev_time = 0.0; aps->at_enabled = TRUE; aps->at_warn = FALSE; } void aps_at_disable(craft * c) { aps_Type * aps; if( c->aps == NULL ) return; aps = aps_get(c); if( ! aps->at_enabled ) return; aps->at_enabled = FALSE; aps->at_warn = FALSE; } _BOOL aps_at_enabled(craft * c) { return (c->aps != NULL) && ( ((aps_Type *) (c->aps))->at_enabled ); } void aps_at_toggle(craft * c) { if( aps_at_enabled(c) ) aps_at_disable(c); else aps_at_enable(c); } double aps_at_get_velocity(craft * c) { aps_Type * aps; aps = (aps_Type *) c->aps; if ( aps == NULL || ! aps->at_enabled ) return 0.0; return aps->at_target_v; } #define AT_DELTA_T 0.5 /* s */ #define AT_V_DOT_MAX (+0.1*units_earth_g) #define AT_V_DOT_MIN (-0.5*units_earth_g) #define AT_REALIGN_TIME 15.0 /* time for vel. realignment (s) */ static void aps_at_update(craft * c) { aps_Type * aps; double dt, v, v_dot, exp_v_dot, thr; _BOOL thr_alarm; aps = aps_get(c); if ( ! aps->at_enabled ) return; if( aps->at_prev_time == 0.0 ){ /* First time we are called. */ dt = AT_DELTA_T; } else { dt = curTime - aps->at_prev_time; } if ( dt < AT_DELTA_T ) return; aps->at_warn = FALSE; v = c->IAS; /* ft/s */ v_dot = (v - aps->at_prev_v) / dt; exp_v_dot = forceRange( (aps->at_target_v - v) / AT_REALIGN_TIME, AT_V_DOT_MIN, AT_V_DOT_MAX); thr = (1.0 + 0.2 * (exp_v_dot - v_dot)) * c->rpm; thr_alarm = FALSE; if ( thr <= 0.2 ) { thr = 0.2; if ( v_dot >= 0.0 ) thr_alarm = TRUE; } else if ( thr >= 1.0 ) { thr = 1.0; if ( v_dot <= 0.0 ) thr_alarm = TRUE; } aps->at_warn = thr_alarm; c->throttleComm = (int) (32768.0 * thr + 0.5); aps->at_prev_v = v; aps->at_prev_time = curTime; #ifdef DEBUG printf("AT: v_target=%3.0f kt v=%3.0f kt v_dot=%g g exp_v_dot=%g g\n", units_FPStoKT(aps->at_target_v), units_FPStoKT(v), v_dot/units_earth_g, exp_v_dot/units_earth_g); #endif } void aps_at_inc_velocity(craft * c) { aps_Type * aps; aps = aps_get(c); aps->at_target_v = qround(aps->at_target_v + AT_V_STEP, AT_V_STEP); } void aps_at_dec_velocity(craft * c) { aps_Type * aps; aps = aps_get(c); aps->at_target_v = qround( fabs(aps->at_target_v - AT_V_STEP), AT_V_STEP); } /* AutoTurn (AW) ============= Controls z turn rate or x roll rate, depending on which value gets set. */ #define AW_DELTA_T 0.02 void aps_bank_max_inc(craft * c) { aps_Type * aps; int b; if( c->aps == NULL ) return; aps = aps_get(c); b = (int) (units_RADtoDEG(aps->aw_bank_max) + 0.5); if( b >= 25 ) return; aps->aw_bank_max = units_DEGtoRAD(b + 5); } void aps_bank_max_dec(craft * c) { aps_Type * aps; int b; aps = aps_get(c); b = (int) (units_RADtoDEG(aps->aw_bank_max) + 0.5); if( b <= 5 ) return; aps->aw_bank_max = units_DEGtoRAD(b - 5); } int aps_bank_max_get(craft * c) { aps_Type * aps; if( c->aps == NULL ) return 25; aps = aps_get(c); return (int) (units_RADtoDEG(aps->aw_bank_max) + 0.5); } void aps_aw_enable(craft * c) { aps_Type * aps; aps = aps_get(c); if ( aps->aw_enabled ) return; aps_rate_control_disable(c); aps->aw_enabled = TRUE; /* aps->aw_bank_max = units_DEGtoRAD(25.0); This field must be initialized by aps_get once for all. */ aps->aw_w_target = c->r / cos(c->curRoll); aps->aw_prev_time = 0.0; aps->aw_warn = FALSE; aps_ac_enable(c); } _BOOL aps_aw_enabled(craft * c) { return (c->aps != NULL) && ( ((aps_Type *) (c->aps))->aw_enabled ); } void aps_aw_disable(craft * c) { aps_Type * aps; if ( c->aps == NULL ) return; aps = (aps_Type *) c->aps; if ( ! aps->aw_enabled ) return; aps->aw_enabled = FALSE; bank_rate_disable(c); } void aps_aw_set(craft * c, double w) /* Sets the turn rate w (RAD/s) around the local earth vertical. w > 0 ==> turn left w < 0 ==> turn right */ { aps_Type * aps; aps_aw_enable(c); aps = (aps_Type *) c->aps; aps->aw_w_target = w; } /****** not used static void aps_aw_bank_max_set(craft * c, double bank) { aps_data * aps; aps = (aps_data *) c->aps; if( aps == NULL ) return; aps->aw_bank_max = bank; } *******/ /* * FIXME: what to return if the roll rate is enabled rather than turn rate? */ double aps_aw_get(craft * c) { aps_Type * aps; if ( c->aps == NULL ) return 0.0; aps = aps_get(c); if ( aps->aw_enabled ) return aps->aw_w_target; else return 0.0; } static void aps_aw_update(craft * c) { aps_Type * aps; double dt, a, a_exp, a_dot_exp; aps = aps_get(c); if ( ! aps->aw_enabled ) return; if( aps->aw_prev_time == 0.0 ){ /* First time we are called. */ dt = AW_DELTA_T; } else { dt = curTime - aps->aw_prev_time; } if ( dt < AW_DELTA_T ) return; aps->aw_prev_time = curTime; a = c->curRoll; /* Compute angle of bank to attain the required turn speed: */ a_exp = atan( c->VT * aps->aw_w_target / units_earth_g ); a_exp = forceRange( a_exp, -aps->aw_bank_max, aps->aw_bank_max); /* Compute the bank rate to attain the expected angle of bank: */ a_dot_exp = (a_exp - a) / 2.0; a_dot_exp = forceRange(a_dot_exp, -units_DEGtoRAD(10.0), units_DEGtoRAD(10.0)); bank_rate_set(c, a_dot_exp); } /* Auto Navigation (AN) ==================== */ void aps_an_enable(craft * c) { aps_Type * aps; aps = aps_get(c); aps_al_disable(c); aps_rate_control_disable(c); aps->an_enabled = TRUE; aps->an_prev_time = 0.0; aps->an_prev_cdi = 0.0; aps->an_warn = FALSE; } void aps_an_disable(craft * c) { aps_Type * aps; if( c->aps == NULL ) return; aps = aps_get(c); if( ! aps->an_enabled ) return; bank_rate_disable(c); aps->an_enabled = FALSE; aps->an_warn = FALSE; } _BOOL aps_an_enabled(craft * c) { return (c->aps != NULL) && ( ((aps_Type *) (c->aps))->an_enabled ); } void aps_an_toggle(craft * c) { if( aps_an_enabled(c) ) aps_an_disable(c); else aps_an_enable(c); } static double min_angle_diff(double a, double b) { double d; d = a - b; if( d > M_PI ) d = - 2.0*M_PI + d; else if( d < - M_PI ) d = 2.0*M_PI + d; return d; } static double normalize_angle(double x) { while( x < 0 ) x = x + 2.0*M_PI; while( x > 2.0*M_PI ) x = x - 2.0*M_PI; return x; } static void aps_an_update(craft * c) { aps_Type * aps; viewer *u; double dt, r, obs, magvar, cdi, th_diff, th, w, cdi_dot, cdi_expected, k; if( c->aps == NULL ) return; aps = aps_get(c); if( ! aps->an_enabled ) return; if( aps->an_prev_time == 0.0 ){ /* First time we are called. */ dt = 1.7; } else { dt = curTime - aps->an_prev_time; } if ( dt < 1.7 ) return; aps->an_warn = FALSE; /* Get current radial: */ u = c->vl; if( u == NULL || ! hsi_vor_radial(u, &r) ){ aps_an_disable(c); return; } /* Target radial: */ obs = units_DEGtoRAD( hsi_get_obs(u) ); /* Magnetic variation: */ if( c->showMag ) magvar = c->indicatedLocalVAR; else //magvar = c->hsiSelect->station->magvar; FIXME magvar = 0.0; /* Course deviation: */ cdi = min_angle_diff(r, obs); if( cdi > units_DEGtoRAD(90.0) ) cdi = units_DEGtoRAD(180.0) - cdi; else if( cdi < - units_DEGtoRAD(90.0) ) cdi = - units_DEGtoRAD(180.0) - cdi; /* * Set turn speed only if cdi_dot available. */ if( aps->an_prev_time > 0.0 ){ /* Evaluates the velocity of CDI, then guess what the CDI will be within, say, 10 seconds so to compensate the inertia of the plane allowing also a smooth change of bank angle (it requires just about 10 seconds to pass from -25 DEG to +25 DEG). */ cdi_dot = forceRange( (cdi - aps->an_prev_cdi)/dt, units_DEGtoRAD(-5.0), units_DEGtoRAD(5.0)); cdi_expected = forceRange(cdi + cdi_dot * 10.0, units_DEGtoRAD(-10.0), units_DEGtoRAD(10.0)); /* Compute approaching heading to OBS. The heading error CDI (i.e. the diff. between the actual heading and the expected obs heading) gets amplified by a factor k. This factor normally evaluates to 20, but if the cdi moves too fast (i.e. we are close to the VOR) it gets reduced up to 1.2 for smooth movements. The max approching angle gets limited to +/-45 DEG. */ k = 1.2 + 18.8 / (1.0 + 500.0 * fabs(cdi_dot)); th = normalize_angle(obs - magvar - forceRange(k * cdi_expected, units_DEGtoRAD(-45.0), units_DEGtoRAD(45.0))); /* Heading correction: */ th_diff = min_angle_diff(th, c->curHeading); w = forceRange( 0.05 * th_diff, units_DEGtoRAD(-3.0), units_DEGtoRAD(3.0)); aps_aw_set(c, w); /**** bank_max = units_DEGtoRAD(5.0) + (25.0 - 5.0)/30.0 * fabs(th_diff); if( bank_max > units_DEGtoRAD(25.0) ) bank_max = units_DEGtoRAD(25.0); aps_aw_bank_max_set(c, bank_max); ****/ } /* Update status: */ aps->an_prev_time = curTime; aps->an_prev_cdi = cdi; #ifdef DEBUG printf("r=%.0f" " obs=%.0f" " curHeading=%.0f" " w=%.1f" "\n", units_RADtoDEG(r), units_RADtoDEG(obs), units_RADtoDEG(c->curHeading), units_RADtoDEG(w)); #endif } /* AutoLanding (AL) ================ */ void aps_al_enable(craft * c) { aps_Type * aps; aps = aps_get(c); if ( aps->al_enabled ) return; aps_an_disable(c); aps_aw_disable(c); aps_rate_control_disable(c); aps_ap_enable(c); aps_ac_enable(c); aps->al_enabled = TRUE; aps->al_prev_adiff = 0.0; aps->al_prev_time = 0.0; aps->al_v_touchdown = 0.0; aps->al_touchdown = FALSE; aps->al_warn = FALSE; } void aps_al_disable(craft * c) { aps_Type * aps; if( c->aps == NULL ) return; aps = aps_get(c); if ( ! aps->al_enabled ) return; aps->al_enabled = FALSE; aps->al_warn = FALSE; aps_aw_disable(c); } _BOOL aps_al_enabled(craft * c) { return (c->aps != NULL) && ( ((aps_Type *) (c->aps))->al_enabled ); } void aps_al_toggle(craft * c) { if( aps_al_enabled(c) ) aps_al_disable(c); else aps_al_enable(c); } #define AL_ALIGN_TIME 30.0 /* Expected time for LOC alignment (s). Decrease for faster realignment, but beware of the Izz inertia and the rudder effectiveness because values too small may introduce oscillations. */ static void aps_al_update(craft * c) { aps_Type * aps; viewer *u; double dt, h, radial, adiff, adiff_dot, exp_adiff_dot, w, gs_offset, v, vs, flare_thr; int is_tricycle; aps = aps_get(c); if( ! aps->al_enabled ) return; if( aps->al_prev_time == 0.0 ){ /* First time we are called. */ dt = 0.5; } else { dt = curTime - aps->al_prev_time; } if ( dt < 0.5 ) return; aps->al_prev_time = curTime; aps->al_warn = FALSE; h = units_METERStoFEET(c->w.z - terrain_localAltitude(c)) - c->cinfo->rm.z - c->cinfo->Gm - c->cinfo->cmMax; u = c->vl; if( h > 250.0 /* ft */ ){ /* Get radial: */ if( u == NULL || ! hsi_loc_radial(u, &radial) ){ aps_al_disable(c); return; } if (radial > M_PI / 2.0) { adiff = radial - 2.0*M_PI; } else { adiff = radial; } adiff_dot = (adiff - aps->al_prev_adiff) / dt; //adiff += adiff_dot * dt; /* guess adiff at next step */ exp_adiff_dot = forceRange( -0.69 /*log(2)*/ * adiff / AL_ALIGN_TIME, units_DEGtoRAD(-0.1), units_DEGtoRAD(0.1)); w = 10.0 * (adiff_dot - exp_adiff_dot); if( fabs(adiff) > units_DEGtoRAD(0.2) ) w *= 2.0; w = forceRange(w, units_DEGtoRAD(-3.0), units_DEGtoRAD(3.0)); aps_aw_set(c, w); aps->al_prev_adiff = adiff; #ifdef DEBUG printf("adiff=%.1f" " adiff_dot=%.3f" " exp_adiff_dot=%.3f" " w=%.1f " "\n", units_RADtoDEG(adiff), units_RADtoDEG(w), units_RADtoDEG(adiff_dot), units_RADtoDEG(exp_adiff_dot)); #endif } v = units_FEETtoMETERS( c->IAS ); /* m/s */ /* The flare maneuver starts when the radar altimeter indicates flare_thr feet from the ground. This value is calculated considering H_THR be a good value for a craft landing at V_THR speed; other values are interpolated. */ #define V_THR 160.0 /* kt */ #define H_THR 50.0 /* ft */ flare_thr = H_THR / V_THR * units_METERStoNM(v)*3600.0; /* Bouncing fix: */ if( !aps->al_touchdown && gear_mainWheelsGroundContact(c) ) aps->al_touchdown = TRUE; if( h > 250.0 && hsi_gs_offset(u, &gs_offset) ){ /* Follow GS, if available */ double vs_target; gs_offset = units_RADtoDEG( gs_offset ); if( gs_offset < -0.2 ){ vs = 0.0; } else { vs_target = -0.0524 /* tan(3 DEG) */ * v; vs = forceRange( (1.0 + 0.7*gs_offset) * vs_target, 1.7*vs_target, 0.0); } aps_ap_set_vs(c, vs); /* Ensure brakes be off: */ gear_brakesDisengage(c); } else if( h < flare_thr ){ /* Flare maneuver. FIXME: for accuracy (and more realisitically) determinate v.s. based on radar altimeter rather than VSI. */ /* Constant -1 DEG: */ vs = -units_DEGtoRAD(1.0)*v; /* Linear curve: glide path angle = tan(1+2*h/flare_thr): */ /* vs = -units_DEGtoRAD(1.0 + 2.0*h/flare_thr) * v; */ /* Quadratic curve: */ /* vs = -units_DEGtoRAD(1.0 + h*h/(flare_thr*flare_thr)*2.0) * v; */ if( h < 0.5*flare_thr ){ /* Keep current engine setting: */ aps_at_disable(c); if( aps->al_touchdown ){ /* Main wheels in contact. */ /* If this is the first contact, set v_touchdown: */ if( aps->al_v_touchdown == 0.0 ) aps->al_v_touchdown = v; /* Engine control: If thrust reverser available: - set engine idle - deploy thrust rev. - set engine 75% power - when speed < 0.4 v_touchdown, set engine idle - when speed < 0.2 v_touchdown, retract thr. rev. If thrust rev. not available: - set engine idle */ if( c->cinfo->hasThrustReverser ){ if( v > 0.4 * aps->al_v_touchdown ){ if( c->thrust_reverse_on ){ /* 75% power with thrust rev. */ c->throttleComm = (int) (75.0/100.0 * 32768); } else { /* Engine idle: */ c->throttleComm = (int) (20.0/100.0 * 32768); pm_thrust_reverse_toggle(c); } } else { /* Engine idle: */ c->throttleComm = (int) (20.0/100.0 * 32768); } } else { /* Engine idle: */ c->throttleComm = (int) (20.0/100.0 * 32768); } /* Extend speed brakes: */ flaps_speed_brakes_extend(c); /* note that the function above will be called several times looping here, so ensuring the speed brakes be fully extended */ /* Pitch control. Once the main wheels are on ground, we have to deploy gently the nose/tail wheel. To this aim we control the pitch rate instead of the v.s. */ is_tricycle = (c->cinfo->rn.x > c->cinfo->rm.x); if( aps_ap_enabled(c) ) aps_ap_disable(c); if( ! is_tricycle && v > 0.85 * aps->al_v_touchdown ){ pitch_rate_set(c, 0.0); } else { if( is_tricycle ){ /* Gently lower the nose: */ pitch_rate_set(c, -units_DEGtoRAD(2.0)); } else { /* Gently raise nose, avoiding to take-off again! */ pitch_rate_set(c, units_DEGtoRAD(0.5)); } } if( gear_noseWheelGroundContact(c) ){ /* All the wheels in contact. */ /* Keep current pitch so elevator transfers torque from nose to main: */ pitch_rate_set(c, 0); /* Brakes are enabled only on tricycle landing gears when the nose is in contact and, if thrust rev. available, when the speed is half the touchdown speed: */ if( is_tricycle && ( !c->cinfo->hasThrustReverser || v < 0.5 * aps->al_v_touchdown ) ) /* Brakes on: */ gear_brakesEngage(c); if( v < 0.2 * aps->al_v_touchdown ){ aps_al_disable(c); aps_ap_disable(c); aps_aw_disable(c); pitch_rate_disable(c); if( c->thrust_reverse_on ) pm_thrust_reverse_toggle(c); } } } else { aps_ap_set_vs(c, vs); } } else { aps_ap_set_vs(c, vs); } } else if( h <= 250.0 ){ /* ILS signal unreliable -- follow standard slope 3 DEG: */ aps_ap_set_vs(c, -0.0524 /* tan(3 DEG) */ * v ); } else { aps_ap_set_vs(c, 0.0 ); } } /** * Enables pitch and roll rate control. */ void aps_rate_control_enable(craft * c) { aps_Type * aps; aps = aps_get(c); if ( aps->rate_control_enabled ) return; aps_an_disable(c); aps_al_disable(c); aps_aw_disable(c); aps_ap_disable(c); aps_ac_enable(c); aps->rate_control_enabled = TRUE; } void aps_rate_control_disable(craft * c) { aps_Type * aps; aps = aps_get(c); if ( ! aps->rate_control_enabled ) return; aps->rate_control_enabled = FALSE; pitch_rate_disable(c); bank_rate_disable(c); } void aps_rate_control_toggle(craft * c) { aps_Type * aps; aps = aps_get(c); if ( aps->rate_control_enabled ) aps_rate_control_disable(c); else aps_rate_control_enable(c); } _BOOL aps_rate_control_enabled(craft * c) { return (c->aps != NULL) && ( ((aps_Type *) (c->aps))->rate_control_enabled ); } static void aps_rate_control_update(craft * c) { aps_Type * aps; double pitch_dot, bank_dot; aps = aps_get(c); if ( ! aps->rate_control_enabled ) return; pitch_dot = - c->pitchComm * PITCH_DOT_MAX; pitch_rate_set(c, pitch_dot); bank_dot = - c->rollComm * BANK_DOT_MAX; bank_rate_set(c, bank_dot); } /* Warning detection ================= */ _BOOL aps_ap_warn(craft *c) { return (c->aps != NULL) && ( ((aps_Type *) (c->aps))->ap_warn ); } _BOOL aps_at_warn(craft *c) { return (c->aps != NULL) && ( ((aps_Type *) (c->aps))->at_warn ); } _BOOL aps_al_warn(craft *c) { return (c->aps != NULL) && ( ((aps_Type *) (c->aps))->al_warn ); } _BOOL aps_an_warn(craft *c) { return (c->aps != NULL) && ( ((aps_Type *) (c->aps))->an_warn ); } _BOOL aps_aw_warn(craft *c) { return (c->aps != NULL) && ( ((aps_Type *) (c->aps))->aw_warn ); } _BOOL aps_ac_warn(craft *c) { return (c->aps != NULL) && ( ((aps_Type *) (c->aps))->ac_warn ); } void aps_update(craft * c) { if ( c->aps == NULL ) return; aps_at_update(c); aps_an_update(c); aps_al_update(c); aps_ap_update(c); aps_ac_update(c); aps_aw_update(c); aps_rate_control_update(c); bank_rate_update(c); pitch_rate_update(c); } void aps_off(craft * c) { aps_at_disable(c); aps_an_disable(c); aps_al_disable(c); aps_ap_disable(c); aps_ac_disable(c); aps_rate_control_disable(c); aps_aw_disable(c); bank_rate_disable(c); pitch_rate_disable(c); } /* End of aps.c */ acm-6.0_20200416/src/acm/ccip.c0000644000000000000000000003356213175035532014221 0ustar rootroot#include #include "air.h" #include "damage.h" #include "dis_if.h" #include "draw.h" #include "effects.h" #include "init.h" #include "inventory.h" #include "../util/memory.h" #include "pm.h" #include "terrain.h" #include "weapon.h" #include "gear.h" #include "../util/units.h" #define ccip_IMPORT #include "ccip.h" static int select_mk82(craft *); static int display_mk82(craft *, craftType *, viewer *, int, int); static int update_mk82(craft *); static int press_mk82(craft *); static int release_mk82(craft *); static weapon_Type mk82Desc = { select_mk82, /* select */ update_mk82, /* update */ display_mk82, /* display procedure */ press_mk82, /* fire */ release_mk82, /* fire button release */ }; static char * ccip_update(craft * c); static void ccip_kill(craft * c, char *reason); static void computeImpactPoint(craft *c, earth_LatLonAlt *ip) { double t_sec, ground_speed_fps, loft_distance_feet; double T1_sec, T2_sec; double A, B, C, S4AC; double sin_course, cos_course; /* * Local terrain skin location */ *ip = c->w; ip->z = terrain_localAltitude(c); A = - 0.5 * units_earth_g; B = - c->Cg.z; C = units_METERStoFEET ( c->w.z - ip->z ); S4AC = sqrt ( B * B - 4.0 * A * C ); /* * Compute time to impact using the solution to the quadratic formula: * * x = 0.5 * ( - earth_g ) * t^2 + v0 * t + x0 * * v0 = vertical velocity (up positive, feet-per-second) * x0 = height above surface (feet) */ if (S4AC >= 0.0) { T1_sec = ( - B + S4AC ) / ( 2.0 * A ); T2_sec = ( - B - S4AC ) / ( 2.0 * A ); } else { /* complex root(s) */ T1_sec = T2_sec = 10.0; /* FIXME: ??? */ } t_sec = (T1_sec > T2_sec) ? T1_sec : T2_sec; ground_speed_fps = sqrt ( c->Cg.x * c->Cg.x + c->Cg.y * c->Cg.y ); loft_distance_feet = ground_speed_fps * t_sec; /* * Based on instantaneous velocity, not aircraft orientation */ cos_course = c->Cg.x / ground_speed_fps; sin_course = c->Cg.y / ground_speed_fps; earth_updateLatLon(ip, cos_course, sin_course, units_FEETtoMETERS ( loft_distance_feet ) ); } static int count[manifest_MAXPLAYERS]; static int hasFired[manifest_MAXPLAYERS]; static int select_mk82( craft * c ) { hasFired[c->pIndex] = 0; count[c->pIndex] = weapon_countOrdinance(c, weapon_MK82); return 1; } weapon_Type * ccip_new(void) { craftType *c; FILE *f; dis_entity_type em1 = {2, 9, 225, 2, 73, 0, 0}; dis_entity_type em2 = {0, 0, 0, 0, 0, 0, 0}; c = inventory_craftTypeNew(NULL); c->name = memory_strdup( weapon_idToName(weapon_MK82) ); mk82Desc.w = c; c->entityType = em1; c->altEntityType = em2; /* * Unverified parameters calculated using DATCOM recommendations */ c->CDOrigin = 0.081; c->CDFactor = 0.0; c->CDBOrigin = 0.0; c->CDBFactor = 0.0; c->emptyWeight = 510.0; c->wingS = 1.0; /* FIXME */ c->maxFuel = 0.0; c->maxThrust = 0.0; c->spFuelConsump = 0.0; /* * dCL/da = 4.09 * dCm,cg/da = -21.4 */ f = init_fopen("missiles/sa10.obv", "r"); /* FIXME */ c->object = VReadObject(f); fclose(f); return &mk82Desc; } static int dropOrdinance ( craft *c, int ind ) { craft *m; int i; VPoint s, s1; VPoint cY, mX, mY, mZ; double v; double disLocation[3]; VPoint velocity; double disVelocity[3]; double disZeroVec[3]; double disOrientation[3]; /* * Find an empty projectile entry */ for ((i = 0, m = &mtbl[0]); i < manifest_MAXPROJECTILES; (++i, ++m)) { if (m->type == CT_FREE) { m->type = CT_BOMB; break; } } if (i == manifest_MAXPROJECTILES) return -1; m->cinfo = inventory_craftTypeSearchByZoneAndName(NULL, "MK82"); m->fuel = 0.0; m->curThrust = 0.0; m->owner = c->pIndex; m->payload = 0.0; m->armTimer = 0.0; m->prevSg = c->Sg; /* * Build trihedral based on the launching aircraft's current velocity vector * rather than simply it's current direction vector. * * (1) build a unit velocity vector. * (2) calculate bomb local Z axis from * plane's-y-axis CROSS bomb's-unit-velocity-vector * (3) calculate bomb's Y axis. */ if ((v = VMagnitude(&c->Cg)) < 1.0) { m->trihedral = c->trihedral; m->curRoll = c->curRoll; m->curPitch = c->curPitch; m->curHeading = c->curHeading; } else { mX = c->Cg; mX.x /= v; mX.y /= v; mX.z /= v; cY.x = c->trihedral.m[0][1]; cY.y = c->trihedral.m[1][1]; cY.z = c->trihedral.m[2][1]; VCrossProd(&mX, &cY, &mZ); VCrossProd(&mZ, &mX, &mY); m->trihedral.m[0][0] = mX.x; m->trihedral.m[1][0] = mX.y; m->trihedral.m[2][0] = mX.z; m->trihedral.m[0][1] = mY.x; m->trihedral.m[1][1] = mY.y; m->trihedral.m[2][1] = mY.z; m->trihedral.m[0][2] = mZ.x; m->trihedral.m[1][2] = mZ.y; m->trihedral.m[2][2] = mZ.z; pm_euler(m); } m->Cg = c->Cg; VTransform(&(c->cinfo->wStation[ind]), &(c->trihedral), &s1); VReverseTransform_(&s1, &c->XYZtoNED, &s); m->Sg.x = c->prevSg.x + units_FEETtoMETERS(s.x); m->Sg.y = c->prevSg.y + units_FEETtoMETERS(s.y); m->Sg.z = c->prevSg.z + units_FEETtoMETERS(s.z); earth_XYZToLatLonAlt(&m->Sg, &m->w); earth_generateWorldToLocalMatrix(&m->w, &m->XYZtoNED); m->armTimer = m->cinfo->armDelay; m->flags = 0; m->createTime = curTime; m->curRadarTarget = -1; m->update = ccip_update; m->kill = ccip_kill; /* * ACM bombs are DIS "tracked munitions", so we are * responsible for sending entity state PDU's for them */ { VPoint tmp; disLocation[0] = m->Sg.x; disLocation[1] = m->Sg.y; disLocation[2] = m->Sg.z; tmp.x = units_FEETtoMETERS(m->Cg.x); tmp.y = units_FEETtoMETERS(m->Cg.y); tmp.z = units_FEETtoMETERS(m->Cg.z); VReverseTransform_(&tmp, &m->XYZtoNED, &velocity); disVelocity[0] = velocity.x; disVelocity[1] = velocity.y; disVelocity[2] = velocity.z; disZeroVec[0] = 0.0; disZeroVec[1] = 0.0; disZeroVec[2] = 0.0; disOrientation[0] = m->curHeading; disOrientation[1] = m->curPitch; disOrientation[2] = m->curRoll; dis_if_entityEnter(c->force, m, &m->cinfo->entityType, &m->cinfo->altEntityType, disLocation, disVelocity, disZeroVec, disOrientation, disZeroVec, &m->disId); } return 0; } static int update_mk82(craft * c) { int i; if( ! hasFired[c->pIndex] ) return 1; hasFired[c->pIndex] = 0; /* reset fire request */ /* * Bombs won't drop if we have "Weight on wheels" * or if we run out of ammunition. */ if( gear_someWheelGroundContact(c) || count[c->pIndex] <= 0 ) return 1; /* Get station from which to drop the bomb: */ i = weapon_getReadyStation(c, weapon_MK82); if (i < 0){ fprintf(stderr, "Oops. Can't find an MK82\n"); return 1; } /* * Decrement bombs counter. * In arcade mode, we never run out of ammunition */ if ( ! arcadeMode ) { c->station[i].id = -1; count[c->pIndex]--; } /* Drop bomb from station i: */ dropOrdinance (c, i); /* playSound(c, SoundBombDrop); */ return 1; } static int display_mk82(craft *c, craftType *ct, viewer *u, int fpm_x, int fpm_y) { char s[16]; earth_LatLonAlt ip_wc; /* impact point (world) */ VPoint ip_gc; /* impact point (geocentric XYZ coords) */ VPoint ip_ned; /* impact point (NED coords) */ VPoint ip_eye; /* impact point (eye space) */ double x0, y0; /* cross center (viewport coords, pixels) */ double xscale, yscale; /* world-to-viewport scale factors */ /* * Update HUD display strings. */ sprintf(s, "%d %s", count[c->pIndex], weapon_idToName(weapon_MK82)); strcpy(c->leftHUD[3], s); strcpy(c->leftHUD[2], ""); strcpy(c->leftHUD[4], ""); /* Compute impact point ip_wc (world coords): */ computeImpactPoint(c, &ip_wc); /* Compute impact point ip_gc (geocentric coords XYZ): */ earth_LatLonAltToXYZ(&ip_wc, &ip_gc); /* Compute impact point ip_eye (pilot's eye coords): */ VTransform(&ip_gc, &c->XYZtoNED, &ip_ned); VReverseTransform(&ip_ned, &c->AXYZtoNED, &ip_eye); /* Pilot's head position correction: */ ip_eye.x -= units_FEETtoMETERS(c->cinfo->viewPoint.x); ip_eye.y -= units_FEETtoMETERS(c->cinfo->viewPoint.y); ip_eye.z -= units_FEETtoMETERS(c->cinfo->viewPoint.z); /* Display CCIP circle only if the impact point is ahead of us and closer than 45 DEG from HUD center: */ if( ip_eye.x > 0.0 && ip_eye.x * ip_eye.x > ip_eye.y * ip_eye.y + ip_eye.z * ip_eye.z ){ xscale = u->v->xres * u->v->dist / ip_eye.x; yscale = u->v->yres * u->v->dist / ip_eye.x; /* Center of the CCIP circle: */ x0 = u->v->focus.x + xscale * ip_eye.y; y0 = u->v->focus.y + yscale * ip_eye.z; draw_Type *dd = draw_new(); /* Draw CCIP circle, 5 mm radius: */ double r = 0.005 /* m */ * u->v->xres * u->zoom/100.0; draw_circle(dd, x0, y0, r); /* Draw bomb fall line: */ double nx = x0 - fpm_x; double ny = y0 - fpm_y; double n = sqrt(nx * nx + ny * ny); double fpm_r = 8.0 * u->xscaleFactor; /* FPM circle radius */ /* Draw BFL only if FPM and CCIP are far enough: */ if( n > fpm_r + r ){ nx /= n; ny /= n; draw_segment(dd, fpm_x + nx * fpm_r, fpm_y + ny * fpm_r, fpm_x + nx * (n - r), fpm_y + ny * (n - r)); } draw_stroke(dd, u->v, HUDColor); draw_free(dd); } /* * Return TRUE if we are recommending a bomb drop. */ return 0; } static int press_mk82(craft *c) /* Fire! */ { hasFired[c->pIndex] = 1; return 1; } static int release_mk82(craft *c) { return 0; } /** * Gravity bomb dynamics update. * @param c * @return "Exploded on the ground" or NULL if still falling down. */ static char * ccip_update(craft * c) { double q; double FDrag, FWeight; double dNorth, dEast, dmag; VPoint F, Fg; if (c->w.z < terrain_localAltitude(c)) { c->Cg = (VPoint) {0,0,0}; c->w.z = terrain_localAltitude(c); dis_if_updateLocal(c); return "exploded on the ground"; } /* * Compute the resultant force vector on the bomb. */ air_update(&c->air, units_METERStoFEET(c->w.z)); c->prevSg = c->Sg; c->VT = VMagnitude(&c->Cg); q = c->air.rho * c->cinfo->wingS * c->VT * c->VT * 0.5; FDrag = c->cinfo->CDOrigin * q; F.x = c->curThrust - FDrag; F.y = 0.0; F.z = 0.0; /* * Now calculate changes in position (Sg) and velocity (Cg). */ VTransform(&F, &c->AXYZtoNED, &Fg); FWeight = c->cinfo->emptyWeight; Fg.z += FWeight; pm_calcGForces(c, &Fg, FWeight); /* * Update the bomb's position and velocity. */ dNorth = units_FEETtoMETERS(c->Cg.x * deltaT + Fg.x / FWeight * units_earth_g * halfDeltaTSquared); dEast = units_FEETtoMETERS(c->Cg.y * deltaT + Fg.y / FWeight * units_earth_g * halfDeltaTSquared); c->w.z -= units_FEETtoMETERS(c->Cg.z * deltaT + Fg.z / FWeight * units_earth_g * halfDeltaTSquared); dmag = sqrt(dNorth * dNorth + dEast * dEast); earth_updateLatLon(&c->w, dNorth / dmag, dEast / dmag, dmag); earth_LatLonAltToXYZ(&c->w, &c->Sg); earth_generateWorldToLocalMatrix(&c->w, &c->XYZtoNED); c->Cg.x += Fg.x / FWeight * units_earth_g * deltaT; c->Cg.y += Fg.y / FWeight * units_earth_g * deltaT; c->Cg.z += Fg.z / FWeight * units_earth_g * deltaT; dis_if_updateLocal(c); return NULL; } /** * Returns the distance between the two points. * Return a negative value if the distance is greater then the range. */ static double distance(VPoint * a, VPoint * b, double range) { double dx = a->x - b->x; if( fabs(dx) > range ) return -1.0; double dy = a->y - b->y; if( fabs(dy) > range ) return -1.0; double dz = a->z - b->z; if( fabs(dz) > range ) return -1.0; double r = sqrt( dx * dx + dy * dy + dz * dz ); if( r > range ) return -1.0; return r; } /** * Gravity bomb explodes and gets removed from simulation. * Test for damage of any local craft. * Send explosion DIS event toward any remote craft that might be involved; * if no potential remote target is involved, send explosion DIS event anyway * but without target, just to display an explosion on any remote client. * @param c * @param reason */ static void ccip_kill(craft * bomb, char *reason) { double worldLocation[3], entityLocation[3]; VPoint worldVel, localVel; int i; craft *target; double r, explosion_diameter_meters; worldLocation[0] = bomb->Sg.x; worldLocation[1] = bomb->Sg.y; worldLocation[2] = bomb->Sg.z; /* * killBomb's calling sequence needs to be updated to allow for the * entity detonation location to be passed. */ /* entityLocation[0] = 0.0; entityLocation[1] = 0.0; entityLocation[2] = 0.0; */ entityLocation[0] = bomb->Sg.x; entityLocation[1] = bomb->Sg.y; entityLocation[2] = bomb->Sg.z; localVel.x = units_FEETtoMETERS(bomb->Cg.x); localVel.y = units_FEETtoMETERS(bomb->Cg.y); localVel.z = units_FEETtoMETERS(bomb->Cg.z); VReverseTransform_(&localVel, &bomb->XYZtoNED, &worldVel); /* Look for damaged targets: */ for( i = 0; i < manifest_MAXPLAYERS; i++ ){ target = &ptbl[i]; /* Ignores free entries in players table: */ if( target->type == CT_FREE ) continue; /* Distance of the blast from this craft (m): */ r = distance(&target->Sg, &bomb->Sg, 900.0 /* m */); if( r < 0.0 ) continue; if( target->type == CT_PLANE || target->type == CT_DRONE ){ /* Local craft. Absorb damage: */ if( damage_absorbDISDamage(target, &bomb->cinfo->entityType, 0, 0, r, 0.0 /* dummy */, &explosion_diameter_meters) == 0 ){ target->kill(target, "Mark 82 bomb"); } } else if( target->type == CT_DIS_PLANE ){ /* Remote craft. Send detonation event, but don't remove bomb yet: */ dis_if_detonation(&bomb->cinfo->entityType, ptbl[bomb->owner].disId, target->disId, dis_if_ID_NONE, // don't remove remote bomb worldLocation, entityLocation, (double *) &worldVel); } } /* Send explosion to the remote clients and remove their bomb entry: */ dis_if_detonation(&bomb->cinfo->entityType, ptbl[bomb->owner].disId, dis_if_ID_NONE, bomb->disId, worldLocation, entityLocation, (double *) &worldVel); /* Set local explosion effect: */ effects_new_explosion(&bomb->Sg, &(VPoint){0.0, 0.0, 0.0}, 50.0, 15.0, 1.0); /* Remove bomb: */ dis_if_entityExit(bomb->disId); pm_hud_strings_free(bomb); bomb->type = CT_FREE; } acm-6.0_20200416/src/acm/runway.h0000644000000000000000000000143113064343574014630 0ustar rootroot#ifndef _runway_h #define _runway_h #include "../V/VPoly.h" #ifdef runway_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Build runway polygons. * @param id Runway ends names separated by '/', ex. "10L/36R", in any order, * 7 chars max. * @param RWYtoXYZ Runway-to-world coord. transformation with origin in the * middle of the runway, with x pointing in the range [0,180[ DEG of the * geographical coors. and z pointing down. * @param length Runway length (meters). * @param width Runway width (meters). * @param heading Runway heading; it MUST be normalized to the range [0,pi[. * @return Set of polygons that draw the runway. */ EXTERN VPolySet * runway_build(char *id, VMatrix * RWYtoXYZ, double length, double width, double heading); #undef EXTERN #endif acm-6.0_20200416/src/acm/terrain.h0000644000000000000000000000313713172244437014752 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #ifndef _terrain_h #define _terrain_h #include "pm.h" #ifdef terrain_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Returns the altitude over the sea level of the terrain under the aircraft. * The "sea level" is the surface of the WGS84 ellipsoid. * * Implementation: takes the altitude of the closer runway within 100 NM "down * range"; if none found, the sea level zero is returned. * * Since the terrain changes its altitude very slowly, values are cached * in c->local_altitude and updated only if c->local_altitude_timeout > * curTime, then the timeout is moved forward a few to avoid to repeat * the same calculation to often. * @param c The aircraft. * @return Terrain altitude over the WGS84 ellipsoid of the point below the * given aircraft position (m). */ EXTERN double terrain_localAltitude(craft *c); #undef EXTERN #endif acm-6.0_20200416/src/acm/weapon.h0000644000000000000000000000776213064342124014577 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #ifndef _weapon_h #define _weapon_h #include "pm.h" #ifdef weapon_IMPORT #define EXTERN #else #define EXTERN extern #endif /* Index of the weapon into the wtbl[] table: */ #define weapon_NULL 0 /* null weapon, or no weapon selected */ #define weapon_M61A1 1 /* M-61A1 Vulcan 20mm cannon */ #define weapon_AIM9M 2 /* Sidewinder missile */ #define weapon_AIM120 3 /* AIM-120 missile */ #define weapon_MK82 4 /* Mark 82 (510 lb) gravity bomb */ //#define weapon_AGM65 5 /* FIXME: not used */ /** * Defines call-back procedures for all the standard actions of a weapon. * In other words, this type defines the "abstract class" from which any other * specific weapon is derived. */ typedef struct { /** * Weapon select procedure invoked by pilot. * A selection function normally determines whether there are any weapons * of this type on-board. If so, and the weapon system is functional * (in other words, undamaged) then return true, otherwise return 0. * Return: true if there is actually a weapon of this type available and * functional. */ int (*select) (struct craft *); /** * Per tick update procedure that implements weapon dynamics. * Return: FIXME. */ int (*update) (struct craft *); /** * Display (that is HUD) update procedure. * Return: TRUE if there is a reasonable chance of scoring a kill. */ int (*display) (struct craft *, craftType *, viewer *, int, int); /** * Fire button pressed procedure. * Return: FIXME. */ int (*firePress) (struct craft *); /** * Fire button released. * Return: FIXME. */ int (*fireRelease) (struct craft *); /** * Description of this weapon. */ craftType *w; } weapon_Type; /** * Initialize the module. */ EXTERN void weapon_init(void); /** * Return the weapon number WK_* given its name. * Return a negative value if name unknown. */ EXTERN int weapon_nameToId(char * name); /** * Return the weapon name given its id WK_*. * Return NULL if the id is invalid. */ EXTERN char * weapon_idToName(int id); /** * Count a particular type of ordinance on an aircraft, where id is * one of the constants WK_* (see pm.h). */ EXTERN int weapon_countOrdinance(craft * c, int id); /** * Draw HUD data specific of the currently selected weapon. * fpm_x,fpm_y is the current position of the HUD FPM (used by the * ccip module). * Return a nonzero value if have a reasonable chance of scoring a kill. */ EXTERN int weapon_displaySelected(craft * c, viewer * u, int fpm_x, int fpm_y); EXTERN int weapon_update(craft * c); /** * Fire the weapon currently selected. * Returns 0 if no weapon is currently available. */ EXTERN int weapon_fire(craft * c); EXTERN int weapon_ceaseFire(craft * c); /** * Return the index of the first station with a particular type of ordinance * ready for fire. * id is one of the constants WK_* (see pm.h). */ EXTERN int weapon_getReadyStation(craft * c, int id); /** * Select the given weapon number id (see constants WK_* in pm.h). * Returns 0 if the selection cannot be operated. */ EXTERN int weapon_selectByName(craft * c, int id); /** * Select next available type of weapon. * Returns 0 if the selection cannot be operated. */ EXTERN int weapon_selectNextAvailable(craft * c); #undef EXTERN #endif acm-6.0_20200416/src/acm/events.h0000644000000000000000000000225113063670321014600 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #ifndef _events_h #define _events_h #include "pm.h" #ifdef events_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Scan all the viewers for X Window pending events concerning windows events, * key events and button events. Then call proper handling function. */ EXTERN void events_window_keyb_buttons(void); EXTERN int events_joystick(craft * c, viewer * u, double throttle, int switches); #undef EXTERN #endif acm-6.0_20200416/src/acm/instruments.h0000644000000000000000000000645013145001766015676 0ustar rootroot/* * acm : an aerial combat simulator for X * Classic instruments module * Copyright (C) 2007 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /** * This module takes care to update and draw the upper strip of the controls * panel containing the classic instruments, which includes: * * - timer * - APS lights * - turn and slip indicator * - anemometer * - artificial horizon * - altimeter * - vertical speed indicator * * A data structure holding the state of these instruments is allocated and * attached to the aircraft data structure only after a request by the pilot, * and hereafter updated. * * @file */ #ifndef _instruments_h #define _instruments_h #include "pm.h" #ifdef instruments_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Enables the classic instruments panel. The state of each instrument is created * and saved into the aircraft's "instruments" field if does not exist already. * @param u */ EXTERN void instruments_enable(viewer * u); /** * Disables the classic instruments panel. Does nothing if a classic instruments * data structure does not already exist. * @param u */ EXTERN void instruments_disable(viewer * u); /** * Returns true if the classic instruments panel is currently enabled. * @param u * @return */ EXTERN _BOOL instruments_isEnabled(viewer * u); /** * The little aircraft frame in front of the attitude indicator can be * adjusted in pitch by the pilot moving up and down by delta RAD up to * +/-10 DEG. */ EXTERN void instruments_attitude_adjust_pitch(viewer * u, double delta); /** * Erects gyro vertical to case orientation. */ EXTERN void instruments_attitude_reset(viewer * u); /** * Sets altimeter altitude correction. 'delta' is hundreds of inHg, for * example if the current altitude correction is 29.92 inHg (the default) * and delta==-1, the new altitude correction will be 29.91 inHg. */ EXTERN void instruments_altimeter_correction(viewer *u, int delta); /** * Starts/stops/resets timer. */ EXTERN void instruments_timer_toggle(viewer *u); /** * Updates the state the instruments if their data structure has been already * created. Does nothing if no instruments data structure not allocated. */ EXTERN void instruments_update(viewer * u); /** * Draws the instruments if their data structure has been already created. * Does nothing if data structure not allocated or allocated but currently not * enabled (that is, HUD displayed instead). */ EXTERN void instruments_draw(viewer * u); /** * Releases the data structure u->inst (if not NULL). Data "released" * are not actually released from memory, but reused if required. */ EXTERN void instruments_free(viewer *u); #undef EXTERN #endif acm-6.0_20200416/src/acm/inventory.h0000644000000000000000000002543213175511064015341 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /** * This modules manages several data structures: * * - Munitions defined in the munition file. * * - Craft types. Crafts types includes: aircraft, airports (with each runway * being represented by several polygons) and generic features from the scenery. * Airports and features are related to some zone they were loaded from and * can be added and removed along with the zones. Aircraft are defined in the * corresponding configuration file. */ #ifndef _inventory_h #define _inventory_h #include "../V/Vlib.h" #include "../V/VObjects.h" #include "../dis/dis/dis.h" #include "interpolate.h" #include "manifest.h" #include "zone.h" #ifdef inventory_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Maps munition entity/warhead combinations to explosions sizes and damage. */ typedef struct { dis_entity_type entity_type; dis_entity_type entity_mask; /** Type of warhead; currently always 1; no other values defined. */ u_short warhead_type; /** 0 = any, 1 = specific type of warhead. */ u_short warhead_mask; double explosion_diameter_meters; double damage_factor; /* If kinetic, only relative velocity matters; if blast type, only explosion * diameter matters to asses damage. */ int kinetic_flag; } munition_map; typedef struct { int id; /* weapon type weapon_* */ char *type; /* type of weapon at this station */ int info; /* extra info (weapon specific) */ int info2; /* " " */ int info3; /* " " */ double info4; /* time offset to next round firing (s) */ } weaponStation; typedef enum { /** Glider. */ inventory_NoEngine, /** Generic piston engine with propeller. */ inventory_GenericPistonEngine, /** Generic jet engine. */ inventory_GenericJetEngine, /** Generic rocket engine (thrust does not depends on air density). */ inventory_GenericRocketEngine } inventory_EngineType; // Forward declaration. struct craft; /** * Function that calculates the current thrust for the aircraft and updates the * current RPM value based on the current throttle setting, afterburner status, * speed and altitude. There is one for each type of aircraft/engine. * @param cinfo Specific craft informations. * @return Current engine thrust (lbf). */ typedef double inventory_ThrustCalculator(struct craft *cinfo); /* * This structure describes a class of aircraft (e.g. an F-16C). */ typedef struct craftType { struct craftType *prev, *next; /** * Zone this craft type belongs to. Set only for runways and features; * NULL in any other type of "craft". */ zone_Type *zone; char *name; /* short name of aircraft class */ char *description; /* long name */ char *modelname; /* compiled object model to drive this aircraft type */ double aspectRatio; /* wing aspect ratio */ double CLOrigin, CLSlope; /* Defines the CL characteristic eqn */ double betaStall; /* Stall angle for rudder */ double CDOrigin, CDFactor; /* Defines the CD Characteristic eqn */ interpolate_Table *CLift; /* compute lift coefficient */ interpolate_Table *CDb; /* compute body + wave drag coeff */ interpolate_Table *CnBeta; /* compute yaw moment due to sideslip */ interpolate_Table *ClBeta; /* compute roll moment due to sideslip */ double CDBOrigin, CDBFactor; /* Defines the CD Characteristic eqn */ double CDBPhase; double CYbeta; /* Side-force from side-slip (dCY/dBeta) */ double Clda; /* roll moment from aileron offset */ double Cldr; /* roll moment from rudder offset */ double Clp; /* roll damping */ double Cmq; /* damping in pitch */ double Cnr; /* damping in yaw */ double maxAileron; /* maximum aileron offset */ double maxRudder; /* maximum rudder offset */ double effElevator; /* Elevator effectiveness */ double effRudder; /* Rudder effectiveness */ VMatrix I; /* Moments of Inertia about CG in AXYZ (lb ft^2) */ double cmSlope; /* CmAlpha curve slope */ double maxFlap; /* maximum flap setting (RAD) */ double cFlap; /* lift coefficient of flaps */ double cFlapDrag; /* drag coefficient of lowered flaps */ double flapRate; /* flap movement rate (RAD/s) */ double cGearDrag; /* drag coefficient of lowered gear */ double gearRate; /* landing gear movement rate (RAD/s) */ double maxSpeedBrake; /* maximum speed brake setting (RAD) */ double cSpeedBrake; /* drag coefficient of 90 degree speed brake */ double speedBrakeRate; /* rate of speed brake movement (RAD/s) */ double speedBrakeIncr; /* number of radians than one keystroke moves brake */ double wingS; /* wing area (ft^2) */ double wings; /* wing half-span (ft) */ double wingh; /* wing areodyn. center height above the CM (ft) */ double c; /* mean aerodynamic chord (MAC) (ft) */ double emptyWeight; /* empty mass (lb) */ double maxLoadZPositive; /* max climb wing load (lbf) */ double maxLoadZNegative; /* max sink wing load (lbf) */ double maxFuel; /* maximum internal fuel (lb) */ inventory_EngineType engineType; double maxThrust; /* max static thrust, military power (lbf) */ double maxABThrust; /* max static thrust, afterburner on (lbf) */ interpolate_Table *Thrust; /* Change in thrust due to mach number */ interpolate_Table *ABThrust; /* Change in thrust due to mach number */ int hasThrustReverser;/* 0 = no, otherwise yes */ double engineLag; /* controls lag between throttle and RPM */ double spFuelConsump; /* specific fuel consump(lb fuel/lbf T x hr) */ double spABFuelConsump; VPoint viewPoint; /* pilot's viewing location wrt CG (ft) */ double muStatic; /* static coefficient of friction no-brakes */ double muKinetic; /* moving coefficient of friction no-brakes */ double muBStatic; /* static brakes-on */ double muBKinetic; /* moving brakes-on */ double maxNWDef; /* maximum nose wheel deflection (RAD) */ VPoint rm, rn; /* location if main/nose gear attachments */ double Dm, Dn; /* main/nose oleo damping factor */ double Km, Kn; /* main/nose oleo spring factor */ double Gm, Gn; /* main/nose strut length with tire */ double cmMax, cnMax; /* main/nose maximum oleo extension distance */ VPoint tailExtent; /* as we rotate, this part may drag */ /* Speed limits at MTOW (0.0 = unknown): */ double MTOW; /* max takeoff weight (lb) */ double alpha_stall; /* stall AoA (RAD) */ double Vs0; /* stall speed, full flaps (kt) */ double Vs1; /* stall speed, no flaps (kt) */ double Vfe; /* max speed with flaps (kt) */ double Vno; /* normal operation speed (kt) */ double Vne; /* never exceed speed (kt) */ double armDelay; /* arming delay for missiles */ long damageBits; /* initial bit mask of damaged systems */ long structurePts; /* maximum structural damage */ double radarOutput; /* radar output (watts) */ double radarTRange; /* tracking (lock) radar range (nm) */ double radarDRange; /* detection radar range (nm) */ double TEWSThreshold; long sCount; /* number of weapon stations */ VPoint wStation[manifest_STATIONS]; /* weapon's stations (launch points) */ weaponStation station[manifest_STATIONS]; /* what can be at each weapon station */ inventory_ThrustCalculator *thrust; /* computes current thrust */ void (*resupply) (struct craft *); /* the plane's rearm & refuel procedure */ int (*placeProc) (Viewport *, struct craft *, VMatrix *, VPolySet *ps); /* Object placement procedure (for special craft; see place.c) */ char *objname; /* name of file containing the object */ VObject *object; /* what it looks like */ dis_entity_type entityType; /* craft type used in DIS */ dis_entity_type altEntityType; /* alternate craft type used in DIS */ } craftType; /** * Compile the aircraft inventory, DIS entity/munition maps. */ EXTERN void inventory_init(void); /** * Returns next, empty available entry in the craft models table. * @param zone Zone the static items (runway, feature, ...) belongs to. * Leave to NULL for real aircraft types which, being mobile, are not bound to * any specific zone. * @return Empty and reset data structure. */ EXTERN craftType * inventory_craftTypeNew(zone_Type *zone); /** * Releases a craft type. There is normally no need for the client to invoke * this function. */ EXTERN void inventory_craftTypeRelease(craftType *c); /** * Search a specific craft type by zone and name. * @param zone Zone the craft belongs to: NULL for real aircraft; zone for * surface items (runways, features). * @param name Name of the craft type. * @return Found craft type, or NULL. */ EXTERN craftType * inventory_craftTypeSearchByZoneAndName(zone_Type *zone, char *name); /** * Retrieves craft type informations. First look among the already known * aircraft (file objects/inventory) then search in objects/object-map.txt. * @param id * @return Craft type informations, or NULL if not found. */ EXTERN craftType * inventory_craftTypeSearchByEntityType(const dis_entity_type * id ); /** * Removes craft types belonging to the given zone. * @param zone */ EXTERN void inventory_purgeZone(zone_Type *zone); /** * Returns munition at given index. * @param i Munition index, starting from 0. * @return Munition, or NULL if invalid index. */ EXTERN munition_map * inventory_getMunition(int i); /** * Print on standard output a list of the currently defined aircraft types. */ EXTERN void inventory_printValidAircraft(void); #undef EXTERN #endif acm-6.0_20200416/src/acm/astro.c0000644000000000000000000002640213646045023014425 0ustar rootroot/* * IMPLEMENTATION NOTES * * NOTE 0. Earth motions accounted in this implementation: * 1. Rotation around the polar axis. * 2. Precession of the polar axis due to the Moon; nutations negligible. * 3. Revolution around the Sun on an elliptic orbit at varying speed and * varying distance. * 4. Magic constant added to the time to account for light speed propagation * and errors on the solstice date and perihelion date. * Comparison with published ephemeris of years 2010 and 2017 matches within * 0.1 DEG of latitude and 0.2 DEG of longitude - see test program. * * NOTE 1. Computing the position of the Sun in the geodetic Earth reference. * We start the whole reasoning from a Sun-centric reference "S". The orbit of * the Earth is the xy plane; the initial position of the Earth with components * on the S reference is T_S = [r,0,0] being r the mean distance of the Earth * from the Sun. * We assume the Earth's polar axis be inclined toward the Sun by an angle sigma. * * The Earth rotates around the Sun on an ellipse; be r is initial distance from * the Sun; the components of its position over time given in the S reference are: * * T_S(t) = [r*cos(omegaY*t + phiY), r*sin(omegaY*t + phiA), 0] * * where: * * omegaA = 2*PI / SIDERAL_YEAR, being SIDERAL_YEAR the revolution time of * the Earth around the Sun in the S reference; * * phiA = phase to account for the actual start of the simulation. * * The distance from the Sun and the orbital angle of revolution depend on the * time according to the Kepler laws; specific interpolation tables are computed * just to solve this problem. * * For any point P, its components P_S in the S reference and its components T_G * in the geodetic rotating Earth are related by: * * P_G = Rz(omegaD*t + phiD) * Ry(sigma) * (P_S - T_S(t)) * * where: * * Ry() and Rz() are "active" rotations around the y and z axis respectively, * that is, the reference system rotates in the opposite direction; * * omegaD = 2*PI / SIDERAL_DAY, being SIDERAL_DAY the rotation period of the * Earth around its polar axis measured in the S reference; * phiA = phase to account for the actual start of the simulation. * * If the point P is the Sun itself P_S = [0,0,0] the formula above gives the * position of the Sun with components in G: * * SUN_G(t) = Rz(omegaD*t + phiD) * Ry(sigma) * (- T_S(t)) * * Setting the correct values for phiY and phiD for any given departure time is * a bit tricky, but note that with both values set to zero the date period is * around the Summer solstice (21 of June) and the midnight is at the zero * meridian. * By setting the phase angle phiY we may set any other date, and this mainly * affects the elevation of the Sun over the horizon. * By setting the phase angle phiD we may set the current UTC on the simulated * Earth. * * Equinox precession can be introduced by simply replacing the Ry(sigma) * factor with the Rz(tss/(26000 years))Ry(sigma) where tss is the time elapsed * since the summer solstice of reference and 26000 years is the precession * period of the Earth axis. * * NOTE 2. The summer solstice of the year 2017 is assumed as a reference point * for all the calculations. At this exact time the polar axis of the Earth was * inclined toward the Sun, and from here we compute the state of the Earth for * any future or past date, including the equinox precession. */ #include #include #include #include #include "../util/error.h" // LINKER_OPTIONS -lm #define astro_IMPORT #include "astro.h" /** Earth sidereal polar axis rotation period (s). */ #define astro_EARTH_SPIN_PERIOD (23.9344699 * 3600) /** Earth sidereal Sun orbit period (s). */ #define astro_EARTH_ORBIT_PERIOD (365.256363004 * 86400.0) /** Minimal distance Earth to Sun (m). */ #define astro_EARTH_ORBIT_PERIHELION (147.098291e9) /** Earth orbit eccentricity. */ #define astro_EARTH_ORBIT_ECCENTRICITY (0.0167086) /** * Earth polar axis angular inclination from the perpendicular to the orbit * plane (RAD). This value refers to year 2017; the following parameters must * refer to this same year. */ #define astro_EARTH_INCL (23.435*M_PI/180.0) /** * Date and time of Earth solstice (ISO 8601 format). Allows to establish the * orientation of the polar axis: in fact, at this exact time the polar axis * is inclined toward the Sun. It should be the absolute time not affected by * the light travel time and NOT the time the event can be observed from the * Earth. I don't know if this is the case of the value I reported here, though. */ #define astro_EARTH_SUMMER_SOLSTICE_ZULU "2017-06-21T04:24" /** * Date and time of Earth perihelion (ISO 8601 format). Allows to determine * where the perihelion point of the orbit is in reference to our main reference * point, the summer solstice, so that the varying orbital speed of the Earth * and the correct distance of the Sun can be calculated. It should be the * absolute time not affected by the light travel time and NOT the time the * event can be observed from the Earth. I don't know if this is the case of the * value I reported here, though. */ #define astro_EARTH_PERIHELION_ZULU "2017-01-04T14:18" /** If this module has been initialized. */ static int initialized; /** Offset to the simulator time to get time since summer solstice (s). */ static double year_offset; /** Offset to the simulator time to get angular rotation around polar axis. */ static double day_offset; /** * Offset to the simulation time to get elapsed time since reference summer * solstice. Used to calculate the Earth equinox precession. */ static double precession_offset; static double perihelion_to_solstice_time; static double theta_solstice; // Cached last position of the Sun. static int last_available; static double last_timestamp; static VPoint last_sun; #define astro_LAST_SUN_POSITION_EXPIRE_PERIOD (30) #define INTERPOLATION_TABLE_LEN (99) /** * Interpolation table giving the Sun distance from Earth. The first value refers * to the perihelion; the other values are computed at time steps of 1/INTERPOLATION_TABLE_LEN * of the Earth sidereal period. Last entry duplicates the first one. */ static double rho_table[INTERPOLATION_TABLE_LEN]; /** * Interpolation table giving the angular position of the Earth respect to the * Sun measured from the perihelion. Each steps by 1/INTERPOLATION_TABLE_LEN * ofthe Earth sidereal year, which means about 10 DEG. Last entry is * (should be...) 360 DEG. */ static double theta_table[INTERPOLATION_TABLE_LEN]; /** Converts ISO 8601 into Unix timestamp. */ static int astro_zuluToTimestamp(char *zulu) { zulu_Date d; zulu_dateParse(zulu, &d); return zulu_dateToTimestamp(&d); } /** * Generates the interpolation tables distance and orbital angle of the Earth * vs. time. */ static void astro_computeEarthTables() { double p = (1 + astro_EARTH_ORBIT_ECCENTRICITY) * astro_EARTH_ORBIT_PERIHELION; double e = astro_EARTH_ORBIT_ECCENTRICITY; double a = astro_EARTH_ORBIT_PERIHELION / (1-e); // major axis double b = astro_EARTH_ORBIT_PERIHELION * sqrt((1+e)/(1-e)); // minor axis // dTheta = h/rho^2 * dt (Kepler law of equal areas) double h = 2*M_PI*a*b/astro_EARTH_ORBIT_PERIOD; double theta = 0; // initial theta rho_table[0] = 0; // initial rho theta_table[0] = theta; double dt = astro_EARTH_ORBIT_PERIOD / (INTERPOLATION_TABLE_LEN - 1.0); int i; for(i = 1; i < INTERPOLATION_TABLE_LEN; i++){ double rho = p / (1+e*cos(theta)); theta += h * dt / (rho * rho); rho_table[i] = rho; theta_table[i] = theta; } } /** * Determines the orbital angle and distance of the Earth vs. Sun by * interpolation of the tables. * @param t Time elapsed since the perihelion (s). Multiple of the sidereal * orbit period allowed as well. For time zero, for example, the minimal * distance from the Sun and the angle zero are returned. * @param rho Here returns the distance from the Sun (m). * @param theta Here returns the orbital angle vs. summer solstice (RAD in [0,2*PI[). */ static void astro_earthRhoAndTheta(double t, double *rho, double *theta) { t -= astro_EARTH_ORBIT_PERIOD * floor(t / astro_EARTH_ORBIT_PERIOD); int i = t * (INTERPOLATION_TABLE_LEN - 1.0) / astro_EARTH_ORBIT_PERIOD; double f = (INTERPOLATION_TABLE_LEN - 1.0) / astro_EARTH_ORBIT_PERIOD * t - i; assert(0 <= i && i < INTERPOLATION_TABLE_LEN); *rho = rho_table[i] + f * (rho_table[i+1] - rho_table[i]); *theta = theta_table[i] + f * (theta_table[i+1] - theta_table[i]); } void astro_init(double simulation_time, zulu_Date *departure) { /* * Account here once for all for the light propagation delay Sun-to-Earth * and error in the summer solstice and perihelion time we are currently using. */ simulation_time += 3.25*60; // 3.25 min seems to fit with data available int solstice_timestamp = astro_zuluToTimestamp(astro_EARTH_SUMMER_SOLSTICE_ZULU); double since_solstice = zulu_dateToTimestamp(departure) - solstice_timestamp; year_offset = since_solstice; // Normalize to [0,astro_EARTH_ORBIT_PERIOD[ range: year_offset -= astro_EARTH_ORBIT_PERIOD * floor(year_offset / astro_EARTH_ORBIT_PERIOD); year_offset -= simulation_time; zulu_Date solstice_date; zulu_dateParse(astro_EARTH_SUMMER_SOLSTICE_ZULU, &solstice_date); day_offset = 3600.0 * solstice_date.hour + 60.0 * solstice_date.minutes + solstice_date.seconds + since_solstice; // Normalize to [0,astro_EARTH_ROTATION_PERIOD[ range: day_offset -= astro_EARTH_SPIN_PERIOD * floor(day_offset / astro_EARTH_SPIN_PERIOD); day_offset -= simulation_time; precession_offset = - simulation_time + since_solstice; astro_computeEarthTables(); perihelion_to_solstice_time = astro_zuluToTimestamp(astro_EARTH_SUMMER_SOLSTICE_ZULU) - astro_zuluToTimestamp(astro_EARTH_PERIHELION_ZULU); double dummy; astro_earthRhoAndTheta(perihelion_to_solstice_time, &dummy, &theta_solstice); initialized = 1; last_available = 0; } void astro_getSun(double simulation_time, VPoint *sun) { if( ! initialized ) error_internal("module not initialized", 0); // Return cached value most of the times: if( last_available && simulation_time - last_timestamp < astro_LAST_SUN_POSITION_EXPIRE_PERIOD ){ *sun = last_sun; return; } // Compute: // rho = current distance from the Sun; // year_angle = orbital angle since perihelion. double year_angle, rho; astro_earthRhoAndTheta(simulation_time + year_offset + perihelion_to_solstice_time, &rho, &year_angle); // Convert angle to angle from summer solstice (polar axis facing the Sun): year_angle -= theta_solstice; year_angle -= 2*M_PI*floor(year_angle / (2*M_PI)); // normalize [0,2*PI[ VPoint p; // (Minus sign actually needed next, not here) p.x = - rho * cos(year_angle); p.y = - rho * sin(year_angle); p.z = 0; // FIXME: this matrix is constant. Or Earth precession should be accounted. VMatrix m; VIdentMatrix(&m); // Equinox precession, 26000 years period: VRotate(&m, ZRotation, (simulation_time + precession_offset) /(26000.0*86400.0*365.25)); VRotate(&m, YRotation, astro_EARTH_INCL); VTransform_(&p, &m, &p); double day_angle = 2*M_PI/astro_EARTH_SPIN_PERIOD * (simulation_time + day_offset); day_angle -= 2*M_PI*floor(day_angle / (2*M_PI)); VIdentMatrix(&m); VRotate(&m, ZRotation, day_angle); VReverseTransform_(&p, &m, &p); *sun = p; last_sun = p; last_available = 1; }acm-6.0_20200416/src/acm/dis_if.c0000644000000000000000000020242213260344464014533 0ustar rootroot/* * Copyright (C) 1995 Mats Lofkvist CelsiusTech Electronics AB * * With additions by Riley Rainey, 1995-1998 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include "../util/error.h" #include "../util/memory.h" #include "../util/prng.h" #include "../dis/dis/disx.h" #include "../dis/dis/datum.h" #include "inventory.h" #include "pm.h" #include "update.h" #define dis_if_IMPORT #include "dis_if.h" /* * If we may trust DIS timestamps from incoming DIS packets. If true, absolute * timestamp from incoming DIS packets is used to build an actual Unix timestamp * to mark the state of the entities, performing DR calculations and discarding * stale entities (for example, from suddenly disconnected remote hosts). But * all this may fail if some remote server is misconfigured. * If set to false, DIS timestamp is ignored and out timestamp is assumed instead. * * FIXME: it is simpler and safer to simply ignore the DIS timestamp * (and in general, we can't trust on any data coming from the net). */ #define dis_if_USE_DIS_TIMESTAMP 0 /** * Default dead reckoning linear threshold (m). A new state packet is sent if * the position of the entity as calculated using the stated DR algorithm applied * to the last sent state packet deviates from the current position more than that. */ #define DEFAULT_LOCATION_THRESHOLD 2.0 /** * Default dead reckoning rotational threshold (DEG). A new state packet is sent if * the rotation of the entity as calculated using the stated DR algorithm applied * to the last sent state packet deviates from the current rotation angles more * than that. */ #define DEFAULT_ORIENTATION_THRESHOLD (3.0 * M_PI / 180.0) /** * Send anyway a fresh state packet within this time interval since last state * packet sent (s). */ #define dis_if_SEND_TIMEOUT_SECONDS 4.8 /** Entities silent from so much time are stale and then removed (s). */ #define dis_if_RECV_TIMEOUT_SECONDS 12.0 /** * Client callback through which ACM is notified new remote entity enters * simulation. */ static dis_if_EntityEnterCb entityEnterCb; /** * Client callback through which ACM is notified an existing remote entity * exits simulation. */ static dis_if_DetonationCb detonationCb; /** * Client callback through which ACM is notified a remote cannon burst has been * fired. */ static dis_if_CannonFireCb cannonFireCb; static double locationThreshold = DEFAULT_LOCATION_THRESHOLD; static double orientationThreshold = DEFAULT_ORIENTATION_THRESHOLD; static int exercise; static int site; static int application; /* * Automatic site ID assignment. When the user sets -1 as site ID we generate * a random value then we enter in "silent mode" listening all the incoming * packets for a few seconds. During this time we look at all the currently * used site IDs we see looking for collisions and, in that case, we generate * another random site ID. * * When a relay server is used, we must also send some dummy initial packet * to subscribe our host and start getting routed packets; this subscription * has to be periodically renewed because the relay removes silent clients. */ /* If randomly generated site ID is still under validation for collisions. */ static int validating_site_id; /* When validation started (time from time()). */ static int validating_site_id_since; /* Duration of the validation (s). */ #define VALIDATING_SITE_ID_PERIOD 15 /* If we have a relay server requiring subscription (i.e., a dummy packet) in * order to start receiving packets from which read used site IDs. */ static int validating_site_id_relay_have; /* Last subscription sent to the relay server. Need to renew subscription * because the relay server removes stale clients! */ static int validating_site_id_relay_last_pkt; static disx_ApplicationInfo *app; static dis_if_OutstandingRequestInfo *request_chain_head = 0; static dis_if_OutstandingRequestInfo *request_chain_tail = 0; /** * If network enabled. If false, does not tries to connect, send or receive * anything. */ static int network_enabled = 1; /** * We must limit our PDU transmission rate on lower bandwidth connections. * 0.0 turns off limiting. */ static double bandwidth_bps = 0.0; static double theTime; static int absoluteTime = 0; /** * All the allocated entities of type dis_if_Entity managed by this module. */ static varray_Type *entities; /** No. of local entities. */ static int stats_local_entities_no; /** No. of remote entities. */ static int stats_remote_entities_no; /** Timestamp start counting incoming processed packets. */ static double stats_processed_packets_count_t0; /** Counter of incoming processed packets. */ static int stats_processed_packets_count; /** Current estimated incoming processed packets per second. */ static double stats_processed_packets_per_second; static int acknowledgePDU (dis_acknowledge_pdu *pdu); static int transferControlPDU (dis_transfer_control_pdu *pdu); static int setDataPDU (dis_set_data_pdu *pdu); static int startPDU (dis_start_pdu *); static int stopPDU (dis_stop_pdu *); static int initializeEMInfo ( dis_if_Entity *e ); static dis_if_TransferControlRequestCallback transferControlRequestCallback = 0; int dis_if_readyToReceive() { return app != NULL; } void dis_if_setTransferControlRequestCallback ( dis_if_TransferControlRequestCallback p ) { transferControlRequestCallback = p; } static dis_if_OutstandingRequestInfo * addRequest( dis_request_id request_id ) { dis_if_OutstandingRequestInfo *p = memory_allocate(sizeof(dis_if_OutstandingRequestInfo), NULL); memset (p, 0, sizeof(dis_if_OutstandingRequestInfo)); p->request_id = request_id; p->next = NULL; p->prev = request_chain_tail; if ( request_chain_tail ) { p->next = p; } if (request_chain_head == NULL) { request_chain_head = p; } request_chain_tail = p; return p; } /** * Remove the specified request tracking structure from the * request tracking list. */ static void removeRequest(dis_if_OutstandingRequestInfo *pItem) { dis_if_OutstandingRequestInfo *p = request_chain_head; /* * The request list is a mundane doubly linked list. */ if (pItem) { if (pItem->prev == NULL) { request_chain_head = p->next; } else { pItem->prev->next = p->next; } if (pItem->next == NULL) { request_chain_tail = p->prev; } else { pItem->next->prev = p->prev; } memory_dispose( pItem ); } } static dis_if_OutstandingRequestInfo * findRequestByRequestID ( dis_request_id request_id ) { dis_if_OutstandingRequestInfo *p = request_chain_head; while ( p ) { if (p->request_id == request_id) { break; } p = p->next; } return p; } disx_ApplicationInfo * dis_if_getApplicationInfo(void) { return app; } varray_Type * dis_if_getEntityTable(void) { return entities; } void dis_if_enableNetwork(int enabled) { network_enabled = enabled; } static void ACMtoDISVelocity(VPoint * in, dis_float_vector * out) { out->x = units_FEETtoMETERS(in->x); out->y = units_FEETtoMETERS(in->y); out->z = units_FEETtoMETERS(in->z); } static void DIStoACMVelocity(dis_float_vector * in, VPoint * out) { out->x = units_METERStoFEET(in->x); out->y = units_METERStoFEET(in->y); out->z = units_METERStoFEET(in->z); } /** * Find the entity with DIS ID id in the local entities table * and return its index in the table. * * The id (handle) is returned on success, 0 is returned on failure. */ static int findEntity(dis_entity_id * id) { int i; dis_if_Entity *e; for (i = varray_firstHandle(entities); i != 0; i = varray_nextHandle(entities)) { e = varray_getValue(entities, i); if (e->entityId.entity_id == id->entity_id && e->entityId.sim_id.application_id == id->sim_id.application_id && e->entityId.sim_id.site_id == id->sim_id.site_id) { varray_releaseIterator(entities); return i; } } varray_releaseIterator(entities); return 0; } dis_if_Entity *dis_if_findEntityByDISID(dis_entity_id * id) { int eid = findEntity(id); if( eid == 0 ) return NULL; return varray_getValue(entities, eid); } dis_if_Entity *dis_if_findEntityByID(int eid) { if( varray_isValidHandle(entities, eid) ) return varray_getValue(entities, eid); else return NULL; } /** * Find the local entity with Dis id id in the local entities table * and return its index in the table. * * The id (handle) is returned on success, 0 is returned on failure. */ static int findLocalEntity( const dis_entity_id * id ) { int i; dis_if_Entity *e; for (i = varray_firstHandle(entities); i != 0; i = varray_nextHandle(entities)) { e = varray_getValue(entities, i); if (e->isLocal && e->entityId.entity_id == id->entity_id && e->entityId.sim_id.application_id == id->sim_id.application_id && e->entityId.sim_id.site_id == id->sim_id.site_id) { varray_releaseIterator(entities); return i; } } varray_releaseIterator(entities); return 0; } void dis_if_setBandwidth(double bps) { bandwidth_bps = bps; } /** * Starts or re-start on collision the randomly generated site ID validation. */ static void startSiteIdValidation() { int eid; validating_site_id = 1; validating_site_id_since = time(NULL); site = prng_getIntInRange(1, 65534); if( app != NULL ) app->id.site_id = site; /* Update site ID of the local entities: */ for(eid = varray_firstHandle(entities); eid != dis_if_ID_NONE; eid = varray_nextHandle(entities)){ dis_if_Entity *e = varray_getValue(entities, eid); if( e->isLocal ) e->entityId.sim_id.site_id = site; } varray_releaseIterator(entities); } /** * Send a dummy empty packet to the relay host to subscribe us and to renew * our subscription in order to continue receiving packets from which read * the currently used site IDs. */ static void subscribeToRelayHost() { dis_pdu pdu; memory_zero(&pdu); /* Send a PDU type the other clients will ignore: */ pdu.hdr.pdu_type = PDUTypeOther; disx_writePDU(app, &pdu); } /** * Evaluates a site ID read from the network and set the validation status of * our randomly generated site ID accordingly. This function can be called * by the initialization function when site ID is set to -1, and once the * connection has been fully established with a valid site ID, it is called * again for each received packet looking for possible new collisions. * If a collision is detected, generates a new site ID and restarts validation. * @param in_use_site_id Site ID read from incoming packet, or -1 if no packets * received just to update timeouts and renew subscription to the relay server. */ static void gotSiteId(int in_use_site_id) { if( in_use_site_id == site ){ /* Collision detected. Restart generation and validation: */ startSiteIdValidation(); return; } if( validating_site_id ){ if( time(NULL) - validating_site_id_since > VALIDATING_SITE_ID_PERIOD ){ /* Randomly generated site ID validated: no collisions. */ validating_site_id = 0; } else if( validating_site_id_relay_have && time(NULL) - validating_site_id_relay_last_pkt > 3.0 ){ /* Renew subscription to the relay server. */ subscribeToRelayHost(); validating_site_id_relay_last_pkt = time(NULL); } } } int dis_if_isValidatingSiteId() { return validating_site_id; } int dis_if_init(char *relay_host, int relay_port, int xexercise, int xsite, int xapplication, dis_if_EntityEnterCb xentityEnterCb, dis_if_DetonationCb xdetonationCb, dis_if_CannonFireCb xcannonFireCb) { dis_Transceiver *xcvr; dis_simulation_addr addr; if( entities ) error_internal("DIS module already initialized", 0); entityEnterCb = xentityEnterCb; detonationCb = xdetonationCb; cannonFireCb = xcannonFireCb; exercise = xexercise; entities = varray_new(); stats_local_entities_no = 0; stats_remote_entities_no = 0; stats_processed_packets_count_t0 = theTime; stats_processed_packets_count = 0; stats_processed_packets_per_second = 0.0; /* * Check relay host: */ if( relay_host != NULL ){ while(isspace(*relay_host)) relay_host++; if( *relay_host == 0 ) relay_host = NULL; } validating_site_id_relay_have = relay_host != NULL; validating_site_id_relay_last_pkt = 0; /* * Check site ID and special values. */ if( xsite == -1 ){ if( network_enabled ){ startSiteIdValidation(); xsite = site; } else { xsite = 1; /* harmless, ignored value */ validating_site_id = 0; } } else { validating_site_id = 0; } /* * Check application ID and special values: */ if( xapplication == -1 ) xapplication = getpid(); if( ! network_enabled ) return 0; xcvr = dis_openTransceiver(0, relay_host, relay_port); if( xcvr == NULL ){ return -1; } app = disx_initializeApplication(xcvr, xexercise, xsite, xapplication); if (app == NULL) { dis_closeTransceiver(xcvr); return -1; } /* * Get the actual simulation address assigned to us. */ disx_getSimulationAddress(app, &addr); site = addr.site_id; application = addr.application_id; return 0; } int dis_if_close(void) { int i; if (entities) { /* Release currently live entities: */ for(i = varray_firstHandle(entities); i != 0; i = varray_nextHandle(entities)) dis_if_entityExit(i); varray_releaseIterator(entities); /* Dispose spare detached entities: */ while( (i = varray_getDetachedHandle(entities)) != 0 ) memory_dispose(varray_getValue(entities, i)); memory_dispose(entities); entities = NULL; } if(app){ disx_closeApplication(app); app = NULL; } stats_local_entities_no = 0; stats_remote_entities_no = 0; stats_processed_packets_count_t0 = 0.0; stats_processed_packets_count = 0; stats_processed_packets_per_second = 0.0; network_enabled = 0; validating_site_id = 0; return 0; } void dis_if_setDRThresholds(double location, double orientation) { locationThreshold = location; orientationThreshold = orientation; } /** 2^31/3600 bits per second. */ #define timeFactor (596523.235556) #ifdef WINNT #define rint(x) (double)( (int)(x) ) #endif /** * Convert a DIS timestamp to a double in UNIX format (seconds since 1970). * * If the timestamp _and_ the local time both are absolute times, * the timestamp is used for the part of hour. The local time 'theTime' * is used to get the hour part. The returned value will be * the closest possible to 'theTime'. * * If either the timestamp or the local time are _not_ absolute, * the local time is returned. This could be improved... */ static double timeDISToDouble(dis_timestamp disTime) { #if dis_if_USE_DIS_TIMESTAMP double seconds; /* seconds into the current hour */ double myseconds; /* ditto for 'theTime' */ double diffseconds; double myhour; /* hour part of 'theTime' */ /* if either time is not absolute, return the local time */ if (disTime.type == 0 || absoluteTime == 0) return theTime; seconds = disTime.time / timeFactor; myseconds = fmod(theTime, 3600.0); myhour = rint((theTime - myseconds) / 3600.0); diffseconds = myseconds - seconds; if (diffseconds > 1800.0) return 3600.0 * (myhour + 1) + seconds; else if (diffseconds < -1800.0) return 3600.0 * (myhour - 1) + seconds; else return 3600.0 * myhour + seconds; #else return theTime; #endif } /** * Convert a double in UNIX format (seconds since 1970) to a DIS timestamp. */ static dis_timestamp timeDoubleToDIS(double time, int isAbsolute) { uint32_t tmp; dis_timestamp res; tmp = (uint32_t) (fmod(time, 3600.0) * timeFactor); if (tmp > 2147483647L) /* 2^31 - 1 */ res.timexxx = 2147483647UL; else res.timexxx = tmp; if( isAbsolute ) res.timexxx |= 0x8000000UL; return res; } void dis_if_setTime(double time) { theTime = time; absoluteTime = 0; } void dis_if_setTimeAbsolute(void) { struct timeval tv; gettimeofday(&tv, NULL); theTime = tv.tv_sec + tv.tv_usec / 1000000.0; absoluteTime = 1; } /** * Remove the stale or destroyed entity. */ static void entityExit(int eid, char *reason) { dis_if_Entity *e = varray_getValue(entities, eid); e->c->kill(e->c, reason); } /** * Read in the entity state data from the entity state PDU es * and write it to the local entity with id (index) eid. */ static void getEntityStateData(int eid, dis_entity_state_pdu * es) { dis_if_Entity *e = varray_getValue(entities, eid); e->lastTime = timeDISToDouble(es->hdr.time_stamp); e->lastLocation[0] = es->pos.x; e->lastLocation[1] = es->pos.y; e->lastLocation[2] = es->pos.z; e->lastVelocity[0] = es->vel.x; e->lastVelocity[1] = es->vel.y; e->lastVelocity[2] = es->vel.z; e->lastOrientation[0] = es->orientation.phi; e->lastOrientation[1] = es->orientation.theta; e->lastOrientation[2] = es->orientation.psi; e->lastLinearAcc[0] = es->dr_parm.linear_acc.x; e->lastLinearAcc[1] = es->dr_parm.linear_acc.y; e->lastLinearAcc[2] = es->dr_parm.linear_acc.z; e->lastAngularVel[0] = es->dr_parm.angular_vel.x; e->lastAngularVel[1] = es->dr_parm.angular_vel.y; e->lastAngularVel[2] = es->dr_parm.angular_vel.z; if (es->marking.charset == DISCharSetASCII) memory_strcpy((char *) e->markings, sizeof(e->markings), (char *) es->marking.marking); else e->markings[0] = '\0'; dis_processNewDRParameters(es, &e->dr); } /** * Process the entity state PDU esPDU for a new (currently unknown) * entity. * @param esPDU * @return Entity ID or 0 if not added to the entities list. */ static int entityEnter(dis_entity_state_pdu * esPDU) { int eid; craft *c = NULL; dis_if_Entity *e; /* Get new entity and entity handle: */ eid = varray_getDetachedHandle(entities); if( eid == 0 ){ /* Allocate entity: */ e = memory_allocate(sizeof(dis_if_Entity), NULL); eid = varray_addValue(entities, e); } else { /* Recycle existing entity block: */ e = varray_getValue(entities, eid); } /* It's safe to reset everything: */ memory_zero(e); e->isLocal = 0; e->state = dis_if_ENTITY_STATE_SIMULATING; e->pending_state = dis_if_ENTITY_STATE_NONE; e->emit_while_frozen = 0; e->forceId = esPDU->force_id; e->entityId = esPDU->id; e->entityType = esPDU->type; e->altEntityType = esPDU->alt_type; e->em = NULL; /* * We only care about setting the dead reckoning thresholds * so that we can assume control of an entity. */ dis_setDRThresholds(&e->dr, dis_if_SEND_TIMEOUT_SECONDS, locationThreshold, orientationThreshold); getEntityStateData(eid, esPDU); /* * Pass entity information to the main ACM code. Based on the DIS * entity type, it will determine if this is worth tracking. */ (entityEnterCb) ( eid, &esPDU->type, esPDU->force_id, &c ); if (c) { /* ACM says it's worth tracking */ e->c = c; return eid; } else { /* must not be an entity we care about ... */ e->c = NULL; dis_if_entityExit(eid); return 0; } } /** * Process an incoming entity state PDU. * Zero is returned on success. */ static int entityStatePDU(dis_entity_state_pdu * esPDU) { int eid = findEntity(&esPDU->id); if (esPDU->appearance & DISAppearanceDamageDestroyed) { /* deactivated or destroyed entity. if we know about it, exit it */ if (eid != 0) { dis_if_Entity *e = varray_getValue(entities, eid); e->c->kill(e->c, "destroyed or deactivated"); } return 0; } else { /* normal entity state PDU. if we know about it, update data, otherwise enter it */ if (eid != 0) { getEntityStateData(eid, esPDU); return 0; } else { eid = entityEnter(esPDU); if (eid != 0) { return 0; } else return -1; } } } /* * These munition types are renderable with ACM's cannon simulation * code. */ static dis_entity_type cannon_types[] = { {2, 2, 225, 2, 1, 0, 0}, {2, 2, 225, 2, 2, 0, 0}, {2, 2, 225, 2, 3, 0, 0}, {2, 2, 225, 2, 4, 0, 0}, {2, 2, 222, 2, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0} }; /** * Process an incoming fire PDU. * * Zero is returned on success. */ static int firePDU(dis_fire_pdu * fPDU) { int owner, eid; dis_entity_type *dp; for (dp = cannon_types; dp->kind != 0; ++dp) { if (fPDU->burst.munition.kind == dp->kind && fPDU->burst.munition.domain == dp->domain && fPDU->burst.munition.country == dp->country && fPDU->burst.munition.category == dp->category && fPDU->burst.munition.subcategory == dp->subcategory) { break; } } /* Not one of the ones that we model? Then do nothing. */ if (dp->kind == 0) { return 0; } eid = findEntity(&fPDU->firing_id); if (eid != 0) { dis_if_Entity *e = varray_getValue(entities, eid); owner = e->c->pIndex; } else { owner = 0; } VPoint pos, vel; pos = fPDU->pos; DIStoACMVelocity((dis_float_vector *)&fPDU->vel, &vel); cannonFireCb(owner, &pos, &vel, fPDU->burst.quantity); return 0; } /** * Process an incoming detonation PDU. * * Zero is returned on success. */ static int detonationPDU(dis_detonation_pdu * dPDU) { int munition_eid, ftype; double time, worldLocation[3], entityLocation[3]; craft *munition; dis_if_Entity *firing, *target; if (detonationCb == NULL) { munition_eid = findEntity(&dPDU->munition_id); if (munition_eid != 0) { dis_if_entityExit(munition_eid); } return 0; } firing = dis_if_findEntityByDISID(&dPDU->firing_id); if (firing == NULL) return -1; target = dis_if_findEntityByDISID(&dPDU->target_id); if (target == NULL) return -2; if (dPDU->burst.munition.category == 2) /* Ballistic */ ftype = dis_if_FIRE_M61A1; else ftype = dis_if_FIRE_AIM9M; /* FIXME: add AIM-120 */ time = timeDISToDouble(dPDU->hdr.time_stamp); worldLocation[0] = dPDU->pos.x; worldLocation[1] = dPDU->pos.y; worldLocation[2] = dPDU->pos.z; entityLocation[0] = dPDU->loc.x; entityLocation[1] = dPDU->loc.y; entityLocation[2] = dPDU->loc.z; munition_eid = findEntity(&dPDU->munition_id); if( munition_eid != 0 && varray_isValidHandle(entities, munition_eid) ){ dis_if_Entity *e = varray_getValue(entities, munition_eid); munition = e->c; } else { munition = NULL; } /* * Send detonation event to ACM so that an explosion effect is set and * damage calculations are performed on local aircraft. Note that the * munition itself is not removed from managed entities; this task is up * to an eventual "entity exit" event. */ detonationCb(ftype, firing->c, target->c, time, worldLocation, entityLocation, munition, dPDU); return 0; } /* static void printEM(dis_em_emission_pdu *em) { int i; assert(em->hdr.pdu_type == PDUTypeEmission); printf(" no. of systems: %d\n", em->num_systems); if( em->num_systems == 0 ) return; for(i = 0; i < em->num_systems; i++){ dis_em_system_info *s = &em->system[0]; printf(" system no. %d: no. of beams %d\n", i, s->num_beams); } } */ /** * Process an incoming EM emission PDU. * * Zero is returned on success. */ static int emissionPDU(dis_em_emission_pdu * pdu) { dis_if_Entity *e; int emitterEid; emitterEid = findEntity(&pdu->emitter_id); if (emitterEid == 0) return -1; e = varray_getValue(entities, emitterEid); /* * First emission received? */ if (e->em == NULL){ initializeEMInfo(e); } /* * Not the first emission. Free the old PDU variable fields and insert * the new one. */ else { dis_freePDUComponents((dis_pdu *) & e->em->em); } e->em->em = *pdu; e->em->lastTime = theTime; return 0; } static int dis_if_isLocalEntity (const dis_entity_id *id) { return findLocalEntity(id) != 0; } int dis_if_canSimulate ( int eid ) { dis_if_Entity *e; if( ! varray_isValidHandle(entities, eid) ) return 0; e = varray_getValue(entities, eid); return e->isLocal && e->state == dis_if_ENTITY_STATE_SIMULATING; } static void updateProcessedPacketsPerSecond(int processed) { double dt; stats_processed_packets_count += processed; dt = theTime - stats_processed_packets_count_t0; if( dt < 0.0 || dt >= 10.0 ){ stats_processed_packets_count_t0 = theTime; stats_processed_packets_count = 0; stats_processed_packets_per_second = 0.0; } else if( dt >= 1.0 ){ stats_processed_packets_per_second = 0.80 * stats_processed_packets_per_second + 0.20 * stats_processed_packets_count / dt; stats_processed_packets_count_t0 = theTime; stats_processed_packets_count = 0; } } static int messagePDU ( dis_comment_pdu *pdu ) { char s[1000]; int s_len; char *c; if( pdu->num_variable_data != 1 || pdu->variable_datum->datum_id != datum_AltDescription ) return -1; s_len = pdu->variable_datum->value_length / 8; if( s_len >= sizeof(s) ) s_len = sizeof(s) - 1; // Note that here we really need strncpy() and NOT memory_strcpy() because // the first also reset the whole field and NUL-termination is not needed. strncpy(s, (char *) pdu->variable_datum->value.ptr_value, s_len); s[s_len] = 0; c = s; while(*c != 0){ if( !(32 <= *c && *c <= 126) ) *c = '?'; c++; } printf("FIXME: message received: \"%s\"\n", s); return 0; } int dis_if_receive(void) { int err, free_needed; dis_pdu pdu; int processed = 0; if ( ! network_enabled || ! app ) return 0; err = 0; while ( disx_readPDU(app, &pdu) ) { /* Some handling funcs store the PDU: do not release! */ free_needed = 1; /* ignore other exercises */ if (pdu.hdr.exercise_id != exercise) goto free_pdu; switch (pdu.hdr.pdu_type) { case PDUTypeOther: /* Clients in validation state may send this type of PDU to subscribe * to the relay server. We ignore it. */ break; case PDUTypeEntityState: /* don't read our own broadcasts */ if (dis_if_isLocalEntity(&pdu.entity_state.id)) goto free_pdu; if( validating_site_id ) gotSiteId(pdu.entity_state.id.sim_id.site_id); err = entityStatePDU(&pdu.entity_state); processed++; break; case PDUTypeFire: /* don't read our own broadcasts */ if (dis_if_isLocalEntity(&pdu.fire.firing_id)) goto free_pdu; if( validating_site_id ) gotSiteId(pdu.fire.firing_id.sim_id.site_id); err = firePDU(&pdu.fire); processed++; break; case PDUTypeDetonation: /* don't read our own broadcasts */ if (dis_if_isLocalEntity(&pdu.detonation.firing_id)) goto free_pdu; if( validating_site_id ) gotSiteId(pdu.detonation.firing_id.sim_id.site_id); err = detonationPDU(&pdu.detonation); processed++; break; case PDUTypeEmission: /* don't read our own broadcasts */ if (dis_if_isLocalEntity(&pdu.em_emission.emitter_id)) goto free_pdu; if( validating_site_id ) gotSiteId(pdu.em_emission.emitter_id.sim_id.site_id); err = emissionPDU(&pdu.em_emission); free_needed = err != 0; processed++; break; case PDUTypeSetData: /* don't read our own broadcasts */ if (dis_if_isLocalEntity(&pdu.set_data.orig_id)) goto free_pdu; if( validating_site_id ) gotSiteId(pdu.set_data.orig_id.sim_id.site_id); err = setDataPDU( &pdu.set_data ); free_needed = err != 0; processed++; break; case PDUTypeStopFreeze: /* don't read our own broadcasts */ if (dis_if_isLocalEntity(&pdu.stop.orig_id)) goto free_pdu; if( validating_site_id ) gotSiteId(pdu.stop.orig_id.sim_id.site_id); err = stopPDU( &pdu.stop ); free_needed = err != 0; processed++; break; case PDUTypeStartResume: /* don't read our own broadcasts */ if (dis_if_isLocalEntity(&pdu.start.orig_id)) goto free_pdu; if( validating_site_id ) gotSiteId(pdu.start.orig_id.sim_id.site_id); err = startPDU( &pdu.start ); free_needed = err != 0; processed++; break; case PDUTypeTransferControl: /* don't read our own broadcasts */ if (dis_if_isLocalEntity(&pdu.transfer_control.orig_id)) goto free_pdu; if( validating_site_id ) gotSiteId(pdu.transfer_control.orig_id.sim_id.site_id); err = transferControlPDU( &pdu.transfer_control ); free_needed = err != 0; processed++; break; case PDUTypeAcknowledge: /* don't read our own broadcasts */ if (dis_if_isLocalEntity(&pdu.acknowledge.orig_id)) goto free_pdu; if( validating_site_id ) gotSiteId(pdu.acknowledge.orig_id.sim_id.site_id); err = acknowledgePDU( &pdu.acknowledge ); free_needed = err != 0; processed++; break; case PDUTypeComment: /* don't read our own broadcasts */ if (dis_if_isLocalEntity(&pdu.message.orig_id)) goto free_pdu; if( validating_site_id ) gotSiteId(pdu.message.orig_id.sim_id.site_id); err = messagePDU( &pdu.message ); free_needed = 1; processed++; break; default: fprintf(stderr, "Ignoring unexpected/unsupported DIS PDU type %d\n", pdu.hdr.pdu_type); err = 0; break; } /* * Free any dynamically allocated variable components that are part of this * PDU. */ free_pdu: if (free_needed) { dis_freePDUComponents(&pdu); } } updateProcessedPacketsPerSecond(processed); if( processed == 0 && validating_site_id ){ /* * No packets received. We still need to update timeouts and renew the * subscription to the relay server: */ gotSiteId(-1); } /* * Check for timeouts on remote entities and look for pending state changes. */ stats_local_entities_no = 0; stats_remote_entities_no = 0; int i; for (i = varray_firstHandle(entities); i != 0; i = varray_nextHandle(entities)) { dis_if_Entity *e = varray_getValue(entities, i); if( e->isLocal ) stats_local_entities_no++; else stats_remote_entities_no++; if ( ! e->isLocal && theTime - e->lastTime > dis_if_RECV_TIMEOUT_SECONDS) { char s[99]; sprintf(s, "stale -- no packets received since %.0f s", theTime - e->lastTime); entityExit(i, s); } else if ( e->pending_state != dis_if_ENTITY_STATE_NONE ) { if (theTime >= e->pending_time) { e->state = e->pending_state; e->pending_state = dis_if_ENTITY_STATE_NONE; } } } varray_releaseIterator(entities); return err != 0; } int dis_if_snoop ( int millisec ) { int interval_millisec = 500; if( ! network_enabled || ! app ) return 0; if (dis_if_haveAbsoluteTime) dis_if_setTimeAbsolute(); else dis_if_setTime(curTime); dis_if_receive(); while ( millisec > 0 ) { if ( millisec < interval_millisec ) { interval_millisec = millisec; } #ifdef WINNT Sleep(interval_millisec); #else usleep ( interval_millisec * 1000 ); #endif update_simulationTime (); if (dis_if_haveAbsoluteTime) dis_if_setTimeAbsolute(); else dis_if_setTime(curTime); dis_if_receive(); millisec -= interval_millisec; } return 0; } int dis_if_transferControlRequestHandler(dis_if_Entity *e, dis_transfer_control_pdu *pdu) { int result = dis_if_RESULT_UNABLE; craftType *cinfo; switch (pdu->transfer_type) { /* * Someone would like use to take control of an entity * * If it is an aircraft we can model, then make it a drone. */ case DISTransferTypeEntityControllerRequest: cinfo = inventory_craftTypeSearchByEntityType( &e->entityType ); if ( cinfo != NULL ) { e->c->type = CT_DRONE; e->c->cinfo = cinfo; /* TODO: provision the aircraft; landing gear, etc */ result = dis_if_RESULT_REQUEST_OK; } break; /* * Control of this entity is requested by someone else. * * Change type to DIS aircraft and we're done. */ case DISTransferTypeEntityRequest: result = dis_if_RESULT_REQUEST_OK; e->c->type = CT_DIS_PLANE; } return result; } /** * Determines if an entity should emit entity state PDUs based on * protocol rules */ static int dis_shouldTransmitPDUs ( dis_if_Entity *e ) { int result = 0; if (e->isLocal) { if ( e->state == dis_if_ENTITY_STATE_SIMULATING ) { result = 1; } else if ( e->state == dis_if_ENTITY_STATE_STOPPED && e->emit_while_frozen ) { result = 1; } } return result; } /** * Send an entity state PDU for the local entity with id (index) eid. * * Zero is returned on success. */ static int sendEntityState(dis_if_Entity *e) { dis_entity_state_pdu pdu, *esPDU = &pdu; int i; if ( ! network_enabled || ! app || validating_site_id ) return 0; if (dis_shouldTransmitPDUs ( e ) == 0) { return 0; } esPDU->hdr.pdu_type = PDUTypeEntityState; esPDU->hdr.time_stamp = timeDoubleToDIS(theTime, absoluteTime); esPDU->id = e->entityId; esPDU->force_id = e->forceId; esPDU->art_parm_count = 0; esPDU->type = e->entityType; esPDU->alt_type = e->altEntityType; esPDU->pos.x = e->location[0]; esPDU->pos.y = e->location[1]; esPDU->pos.z = e->location[2]; esPDU->vel.x = (float) e->velocity[0]; esPDU->vel.y = (float) e->velocity[1]; esPDU->vel.z = (float) e->velocity[2]; esPDU->orientation.phi = (float) e->orientation[0]; esPDU->orientation.theta = (float) e->orientation[1]; esPDU->orientation.psi = (float) e->orientation[2]; esPDU->appearance = e->appearance; esPDU->dr_parm.algorithm = DISDRMethodRVW; esPDU->dr_parm.linear_acc.x = (float) e->linearAcceleration[0]; esPDU->dr_parm.linear_acc.y = (float) e->linearAcceleration[1]; esPDU->dr_parm.linear_acc.z = (float) e->linearAcceleration[2]; esPDU->dr_parm.angular_vel.x = (float) e->angularVelocity[0]; esPDU->dr_parm.angular_vel.y = (float) e->angularVelocity[1]; esPDU->dr_parm.angular_vel.z = (float) e->angularVelocity[2]; esPDU->marking.charset = DISCharSetASCII; memset(esPDU->marking.marking, 0, sizeof(esPDU->marking.marking)); // We really need strncpy() here, NOT memory_strcpy(): strncpy((char *) esPDU->marking.marking, (char *) e->markings, sizeof(esPDU->marking.marking)); esPDU->capabilities = 0; esPDU->art_parm = NULL; if ( ! disx_writePDU(app, (dis_pdu *) esPDU) ) { return -2; } else { dis_processNewDRParameters(esPDU, &e->dr); e->lastTime = theTime; for (i = 0; i < 3; i++) { e->lastLocation[i] = e->location[i]; e->lastVelocity[i] = e->velocity[i]; e->lastLinearAcc[i] = e->linearAcceleration[i]; e->lastOrientation[i] = e->orientation[i]; e->lastAngularVel[i] = e->angularVelocity[i]; } return 0; } } /** * Set the position data of the entity with id (index) eid to the given * values. */ static void setPosData(int eid, double loc[3], double vel[3], double linAcc[3], double ori[3], double angVel[3]) { int i; dis_if_Entity *e = varray_getValue(entities, eid); for (i = 0; i < 3; i++) { e->location[i] = loc[i]; e->velocity[i] = vel[i]; e->linearAcceleration[i] = linAcc[i]; e->orientation[i] = ori[i]; e->angularVelocity[i] = angVel[i]; } } /* * Construct an EM emission PDU that reflects the current state of our * radar set. We set 1 radar system with 0 or 1 beams. */ static int constructEmissionPDU(dis_if_Entity *e, int mode, int update) { dis_em_emission_pdu *em; dis_em_system_info *s; dis_beam_info b; int num_beams = 0; dis_track_info target; if( e->em == NULL ){ e->em = (dis_if_EntityEM *) memory_allocate(sizeof(dis_if_EntityEM), NULL); memory_zero(e->em); e->em->em.hdr.pdu_type = PDUTypeEmission; } e->em->mode = mode; em = &e->em->em; if( network_enabled && ! validating_site_id ) disx_issueEventID(app, &em->event); else memory_zero(&em->event); // Creates 1 radar system: if( em->num_systems == 0 ){ em->system = memory_allocate(sizeof(dis_em_system_info), NULL); memory_zero(em->system); } em->num_systems = 1; s = em->system; em->state_update = update; s->location.x = 0.0f; s->location.y = 0.0f; s->location.z = 0.0f; s->emitter_system.name = 0; s->emitter_system.function = DISEmitterFuncAirborneFireControl; s->emitter_system.id = 1; // Set 0 or 1 beams: memory_zero(&b); switch (mode) { case 0: num_beams = 0; break; /* * Three-bar track while scan mode */ case 1: num_beams = 1; b.beam_id = 1; b.beam_parm_index = 0; b.beam_function = DISBeamFuncAcquisitionAndTracking; b.fundamental.freq = 9000.0f; b.fundamental.erp = 100.0f; b.fundamental.prf = 18000.0f; b.fundamental.pulse_width = 1.0f; b.fundamental.beam_azimuth_center = 0.0f; b.fundamental.beam_azimuth_sweep = units_DEGtoRAD(60); b.fundamental.beam_elev_center = 0.0f; b.fundamental.beam_elev_sweep = units_DEGtoRAD(60); b.fundamental.beam_sweep_sync = 0.0f; b.pad = 0; b.jamming_mode = 0; break; /* * Four bar 20 x 30 ACM mode */ case 2: num_beams = 1; b.beam_id = 1; b.beam_parm_index = 1; b.beam_function = DISBeamFuncAcquisitionAndTracking; b.fundamental.freq = 9000.0f; b.fundamental.erp = 100.0f; b.fundamental.prf = 18000.0f; b.fundamental.pulse_width = 1.0f; b.fundamental.beam_azimuth_center = 0.0f; b.fundamental.beam_azimuth_sweep = units_DEGtoRAD(30); b.fundamental.beam_elev_center = 0.0f; b.fundamental.beam_elev_sweep = units_DEGtoRAD(20); b.fundamental.beam_sweep_sync = 0.0f; b.pad = 0; b.jamming_mode = 0; break; /* * Single target track */ case 3: num_beams = 1; b.beam_id = 1; b.beam_parm_index = 2; b.beam_function = DISBeamFuncAcquisitionAndTracking; b.fundamental.freq = 9000.0f; b.fundamental.erp = 100.0f; b.fundamental.prf = 18000.0f; b.fundamental.pulse_width = 1.0f; b.fundamental.beam_azimuth_center = 0.0f; /* wrong, don't care */ b.fundamental.beam_azimuth_sweep = 0.0f; b.fundamental.beam_elev_center = 0.0f; /* wrong, don't care */ b.fundamental.beam_elev_sweep = 0.0f; b.fundamental.beam_sweep_sync = 0.0f; b.pad = 0; b.jamming_mode = 0; break; default: error_internal("invalid radar mode: %d", mode); } // Set tracked target: int num_targets = 0; if( num_beams > 0 ){ e->em->cur_target = e->c->curRadarTarget; craft *c = e->c; if( c->curRadarTarget >= 0 && ! varray_isValidHandle(entities, ptbl[c->curRadarTarget].disId) ){ /* * Target missing or already killed and removed. Update craft/missile * target: */ c->curRadarTarget = -1; } if (c->curRadarTarget >= 0) { num_targets = 1; dis_if_Entity *curRadarTarget = varray_getValue(entities, ptbl[c->curRadarTarget].disId); target.target = curRadarTarget->entityId; target.emitter_id = 1; target.beam_id = 1; } } /* * Set beam in the radar system avoiding dynamic memory allocation as much * as possible by using the existing data structure already available in the * emission PDU. We must set the system, the beam in the system, and the * target in the beam. */ if( num_beams == 0 ){ // No beams and no targets. Dispose any existing beam data: if( s->num_beams > 0 ){ int i; for(i = 0; i < s->num_beams; i++){ if( s->beam[0].num_targets > 0 ){ memory_dispose(s->beam[0].tracked_target); } memory_dispose(s->beam); } s->beam = NULL; } s->num_beams = 0; } else { // One beam to set. if( s->num_beams == 0 ){ if( num_targets > 0 ){ b.num_targets = 1; b.tracked_target = memory_allocate(sizeof(dis_track_info), NULL); b.tracked_target[0] = target; } s->beam = memory_allocate(sizeof(dis_beam_info), NULL); } else { if( s->beam[0].num_targets == 0 ){ if( num_targets > 0 ){ b.num_targets = 1; b.tracked_target = memory_allocate(sizeof(dis_track_info), NULL); b.tracked_target[0] = target; } } else { if( num_targets == 0 ){ memory_dispose(s->beam[0].tracked_target); } else { b.num_targets = 1; b.tracked_target = s->beam[0].tracked_target; b.tracked_target[0] = target; } } } s->num_beams = 1; s->beam[0] = b; } return 0; } void dis_if_entityEnter(DISForce force, craft * c, dis_entity_type * e1, dis_entity_type * e2, double loc[3], double vel[3], double linAcc[3], double ori[3], double angVel[3], int *neid) { int eid; dis_if_Entity *e; /* Get new entity and entity handle: */ eid = varray_getDetachedHandle(entities); if( eid == 0 ){ /* Allocate entity: */ e = memory_allocate(sizeof(dis_if_Entity), NULL); eid = varray_addValue(entities, e); } else { /* Recycle existing entity block: */ e = varray_getValue(entities, eid); } /* It's safe to reset everything: */ memory_zero(e); e->isLocal = 1; e->c = c; e->state = dis_if_ENTITY_STATE_SIMULATING; e->pending_state = dis_if_ENTITY_STATE_NONE; e->emit_while_frozen = 0; if( network_enabled ){ disx_issueEntityID(app, &e->entityId); } else { memory_zero(&e->entityId); /* FIXME: ???? */ } e->forceId = force; e->entityType = *e1; e->altEntityType = *e2; e->markings[0] = '\0'; e->appearance = 0; setPosData(eid, loc, vel, linAcc, ori, angVel); *neid = eid; constructEmissionPDU(e, 0, 0); dis_setDRThresholds(&e->dr, dis_if_SEND_TIMEOUT_SECONDS, locationThreshold, orientationThreshold); } void dis_if_setEntityMarkings(int eid, char *markings) { dis_if_Entity *e = varray_getValue(entities, eid); // Note that here we really need strncpy() and NOT memory_strcpy() because // the first also reset the whole field and NUL-termination is not needed. strncpy((char *) e->markings, markings, MARKINGS_LEN); } void dis_if_getEntityMarkings(int eid, char *markings, int max) { dis_if_Entity *e = varray_getValue(entities, eid); // Note that here we really need strncpy() and NOT memory_strcpy() because // the first also reset the whole field and NUL-termination is not needed. strncpy(markings, (char *) e->markings, max); } void dis_if_setEntityAppearance(int eid, dis_entity_appearance x) { dis_if_Entity *e = varray_getValue(entities, eid); e->appearance = x; } dis_entity_appearance dis_if_getEntityAppearance(int eid) { dis_if_Entity *e = varray_getValue(entities, eid); return e->appearance; } void dis_if_entityExit(int eid) { dis_if_Entity *e; e = varray_getValue(entities, eid); e->appearance = DISAppearanceDamageDestroyed; sendEntityState(e); if (e->em) { dis_freePDUComponents((dis_pdu *) &e->em->em); memory_dispose(e->em); e->em = NULL; } varray_detach(entities, eid); } int dis_if_setEntityState(int eid, double loc[3], double vel[3], double linAcc[3], double ori[3], double angVel[3]) { if ( ! network_enabled || ! app || validating_site_id ) return 0; double delta, min_delta; int sendESPDU = 0, sendEMPDU = 0, i, j; dis_euler_angles ori_e; dis_if_Entity *e = varray_getValue(entities, eid); assert(e->isLocal); setPosData(eid, loc, vel, linAcc, ori, angVel); /* * EM emission PDU possibly needed ? */ delta = theTime - e->lastTime; if (e->em && e->em->mode > 0 && (delta > dis_if_SEND_TIMEOUT_SECONDS || e->em->em.state_update) ) { sendEMPDU = 1; for (i = 0; i < e->em->em.num_systems; ++i) { for (j = 0; j < e->em->em.system[0].num_beams; ++j) { e->em->em.system[i].beam[j].fundamental.beam_sweep_sync += (float) delta; } } e->em->lastTime = theTime; e->em->em.state_update = 0; } ori_e.phi = ori[0]; ori_e.theta = ori[1]; ori_e.psi = ori[2]; sendESPDU = dis_testDRThresholds(&e->dr, delta, (VPoint *) loc, &ori_e); /* * Are we limiting PDU transmissions? * * If so, ensure enough time has passed since * our last entity state transmission. */ if (bandwidth_bps > 0.0) { min_delta = 1440.0 * varray_length(entities) / bandwidth_bps; if (delta < min_delta) { sendESPDU = 0; } } if (sendESPDU != 0) { sendEntityState(e); } if ( sendEMPDU && e->state == dis_if_ENTITY_STATE_SIMULATING ) { e->em->em.hdr.time_stamp = timeDoubleToDIS(theTime, absoluteTime); if( network_enabled && ! validating_site_id ){ // Set (or refresh because of the site ID validation) our ID: e->em->em.emitter_id = e->entityId; disx_writePDU(app, (dis_pdu *) & e->em->em); } } return sendESPDU || sendEMPDU; } int dis_if_getEntityState(int eid, double loc[3], double vel[3], double ori[3]) { int i; VMatrix orientation; dis_linear_vel_vector drvel; if( ! varray_isValidHandle(entities, eid) ) return 0; dis_if_Entity *e = varray_getValue(entities, eid); assert( ! e->isLocal ); if( ! e->isLocal ){ /* Remote entity. */ dis_computeDRPosition(&e->dr, theTime - e->lastTime, (VPoint *) & e->location, &drvel, &orientation); e->velocity[0] = drvel.x; e->velocity[1] = drvel.y; e->velocity[2] = drvel.z; VMatrixToEuler(&orientation, &e->orientation[0], &e->orientation[1], &e->orientation[2]); for (i = 0; i < 3; i++) { loc[i] = e->location[i]; vel[i] = e->velocity[i]; ori[i] = e->orientation[i]; } } else { /* Local entity. */ for (i = 0; i < 3; i++) { loc[i] = e->location[i]; vel[i] = 0.0; ori[i] = e->orientation[i]; } } return 1; } int dis_if_fire(int ftype, int firingEid, int targetEid, int rounds, double location[3], double velocity[3], double range, int *eventId, int *missileEid) { /* FIXME: TODO */ *eventId = 0; *missileEid = 0; return 0; } static dis_entity_id null_id = {{0, 0}, 0}; int dis_if_fireCannon(craft * c, VPoint * pos, VPoint * vel, int quantity, int rate) { dis_fire_pdu fire; int status; dis_if_Entity *e; if ( ! network_enabled || ! app || validating_site_id) return 0; fire.hdr.pdu_type = PDUTypeFire; e = varray_getValue(entities, c->disId); fire.firing_id = e->entityId; fire.target_id = null_id; fire.munition_id = null_id; disx_issueEventID(app, &fire.event); fire.fire_mission_index = 0; /* NO_FIRE_MISSION */ fire.pos = *pos; fire.burst.munition = cannon_types[1]; fire.burst.warhead = 0; fire.burst.fuze = 0; fire.burst.quantity = quantity; fire.burst.rate = rate; ACMtoDISVelocity(vel, (void *) &fire.vel); fire.range = 0.0f; fire.hdr.time_stamp = timeDoubleToDIS(theTime, absoluteTime); status = disx_writePDU(app, (dis_pdu *) & fire); return (status == 0) ? 0 : -1; } int dis_if_detonation(dis_entity_type * munition_type, int firingEid, int targetEid, int munitionEid, double worldLocation[3], double entityLocation[3], double vel[3]) { dis_detonation_pdu pdu; int status; dis_if_Entity *firing, *target, *munition; if ( ! network_enabled || ! app || validating_site_id ) return 0; pdu.hdr.pdu_type = PDUTypeDetonation; if( ! varray_isValidHandle(entities, firingEid) ){ /* only local entities may set a detonation, should never happen */ return -3; } firing = varray_getValue(entities, firingEid); if ( ! firing->isLocal ) { /* should never happen, only local entities may set detonation */ return -1; } if( targetEid != dis_if_ID_NONE && varray_isValidHandle(entities, targetEid) ) /* Target entity available. */ target = varray_getValue(entities, targetEid); else /* Either no target set, or targeted entity not available. */ target = NULL; if (targetEid != dis_if_ID_NONE && target == NULL) { /* Set target isn't available anymore in our table. */ return -2; } pdu.firing_id = firing->entityId; if (target != NULL) { pdu.target_id = target->entityId; } else { pdu.target_id = null_id; } if (munitionEid != dis_if_ID_NONE) munition = varray_getValue(entities, munitionEid); else munition = NULL; if (munition != NULL) { pdu.munition_id = munition->entityId; } else { pdu.munition_id = null_id; } disx_issueEventID(app, &pdu.event); pdu.vel.x = (float) vel[0]; pdu.vel.y = (float) vel[1]; pdu.vel.z = (float) vel[2]; pdu.pos.x = worldLocation[0]; pdu.pos.y = worldLocation[1]; pdu.pos.z = worldLocation[2]; pdu.burst.munition = *munition_type; /* * This code will need some extra work ... */ if (pdu.burst.munition.category == 2) { pdu.burst.warhead = DISWarheadKinetic; pdu.burst.fuze = DISFuzeContact; pdu.burst.quantity = 1; pdu.burst.rate = 0; pdu.result = DISDetonationResultEntityImpact; } else { pdu.burst.warhead = DISWarheadHEFragment; pdu.burst.fuze = DISFuzeProximity; pdu.burst.quantity = 1; pdu.burst.rate = 0; pdu.result = DISDetonationResultDetonation; } pdu.loc.x = (float) entityLocation[0]; pdu.loc.y = (float) entityLocation[1]; pdu.loc.z = (float) entityLocation[2]; pdu.result = 0; pdu.num_art_parms = 0; pdu.art_parm = NULL; pdu.hdr.time_stamp = timeDoubleToDIS(theTime, absoluteTime); status = disx_writePDU(app, (dis_pdu *) & pdu); return (status == 0) ? 0 : -1; } /** * Initialize EM info data structures. Returns zero on success, -1 on error. */ static int initializeEMInfo ( dis_if_Entity *e ) { int result = 0; if (e->em == NULL) { /* * Allocate EM emission information structure and initialize it to reflect * that this is an external entity (mode == -1). */ e->em = (dis_if_EntityEM *) memory_allocate(sizeof(dis_if_EntityEM), NULL); memory_zero(e->em); e->em->mode = -1; e->em->cur_target = -1; } return result; } int dis_if_setRadarMode(craft * c, int mode, int update) { int status; dis_if_Entity *e; e = varray_getValue(entities, c->disId); if ( e->em == NULL) { initializeEMInfo ( e ); } if ( e->em->mode == mode) { return 0; } constructEmissionPDU(e, mode, 1); e->em->em.hdr.time_stamp = timeDoubleToDIS(theTime, absoluteTime); e->em->lastTime = theTime; if ( ! network_enabled || ! app || validating_site_id ) return 0; status = disx_writePDU(app, (dis_pdu *) & e->em->em); return (status == 0) ? 0 : -1; } int dis_if_radarTargetChanged(craft * c) { int status; dis_if_Entity *e; e = varray_getValue(entities, c->disId); if ( e->em == NULL) { initializeEMInfo(e); } if (e->em->cur_target == c->curRadarTarget) { return 0; } constructEmissionPDU(e, e->em->mode, 1); e->em->em.hdr.time_stamp = timeDoubleToDIS(theTime, absoluteTime); e->em->lastTime = theTime; if ( ! network_enabled || ! app || validating_site_id ) return 0; status = disx_writePDU(app, (dis_pdu *) & e->em->em); return (status == 0) ? 0 : -1; } int dis_if_getBeamCount(craft * c) { dis_if_Entity *e = varray_getValue(entities, c->disId); if (e->em && e->em->em.num_systems > 0) { return e->em->em.system[0].num_beams; } return 0; } void dis_if_getRadarParameters(craft * c, int j, double *az_center, double *az_width, double *el_center, double *el_width, double *erp) { dis_if_Entity *e = varray_getValue(entities, c->disId); dis_beam_info *b = &e->em->em.system[0].beam[j]; *az_center = b->fundamental.beam_azimuth_center; *az_width = b->fundamental.beam_azimuth_sweep; *el_center = b->fundamental.beam_elev_center; *el_width = b->fundamental.beam_elev_sweep; *erp = b->fundamental.erp; } static int transferControlPDU ( dis_transfer_control_pdu *pdu ) { dis_if_Entity *e; int eid; dis_acknowledge_pdu reply_pdu; int status = 0; int error_return_needed = 0; if( app == NULL || validating_site_id ) return -1; reply_pdu.hdr = pdu->hdr; reply_pdu.hdr.pdu_type = PDUTypeAcknowledge; reply_pdu.hdr.time_stamp = timeDoubleToDIS( theTime, absoluteTime ); reply_pdu.orig_id = pdu->recv_id; reply_pdu.recv_id = pdu->orig_id; reply_pdu.request_id = pdu->request_id; /* * Request applies to one of our entities? */ eid = findLocalEntity( &pdu->target_id ); if ( eid != 0 ) { e = varray_getValue(entities, eid); if (pdu->recv_id.sim_id.site_id == site && ( pdu->recv_id.sim_id.application_id == ALL_APPLIC || pdu->recv_id.sim_id.application_id == application )) { reply_pdu.acknowledge_flag = 36; /* per CALSPAN */ reply_pdu.resp_flag = 1; /* per CALSPAN */ switch (pdu->transfer_type) { /* * Someone wants us to take control of an entity */ case DISTransferTypeEntityControllerRequest: /* * the transferControlRequestCallback function is * responsible for determining if we can feasibly take * control of the entity. */ if ( (transferControlRequestCallback != NULL) & ((*transferControlRequestCallback)(e, pdu) == 0) ) { status = disx_writePDU( app, (dis_pdu *) & reply_pdu ); status = (status == 0) ? 0 : -1; if (status == 0) { e->isLocal = 1; } } else { error_return_needed = 1; } break; /* * Control of this entity is requested by someone else. */ case DISTransferTypeEntityRequest: if (transferControlRequestCallback != NULL && (*transferControlRequestCallback)(e, pdu) == 0) { status = disx_writePDU( app, (dis_pdu *) & reply_pdu ); status = (status == 0) ? 0 : -1; if (status == 0) { e->isLocal = 0; } } else { error_return_needed = 1; } break; } } } else { /* * The target entity was not local to us. Still, the PDU might * look like it is destined for us. In this case, return an * error reply. */ if (pdu->recv_id.sim_id.site_id == site && ( pdu->recv_id.sim_id.application_id == ALL_APPLIC || pdu->recv_id.sim_id.application_id == application )) { error_return_needed = 1; } } if (error_return_needed) { reply_pdu.acknowledge_flag = 36; /* per CALSPAN */ reply_pdu.resp_flag = 5; /* error state, per CALSPAN */ status = disx_writePDU(app, (dis_pdu *) & reply_pdu); status = (status == 0) ? 0 : -1; } return status; } static int acknowledgePDU ( dis_acknowledge_pdu *pdu ) { dis_if_Entity *e; dis_if_OutstandingRequestInfo *preq; preq = findRequestByRequestID ( pdu->request_id ); if ( preq != NULL && preq->request_type == OUTSTANDING_REQUEST_TRANSFER_CONTROL ) { e = preq->e; /* * no longer need to track the request */ removeRequest ( preq ); /* * Were we expecting to be granted control? If not, there is some sort * of error. * * This is a non-standard exchange defined by CALSPAN. We are * processing a response to a control request. The request was * originated by us, the response we just received comes from the * controlling application. */ if ( pdu->acknowledge_flag == 36 ) { /* * response flag set to "1" to indicate a success * "5" indicates a failure */ switch (pdu->resp_flag) { case 1: if (e->controlRequestCallback) { (e->controlRequestCallback)( (dis_pdu *) pdu, e->callbackData ); } e->isLocal = 1; e->state = dis_if_ENTITY_STATE_SIMULATING; e->pending_state = dis_if_ENTITY_STATE_NONE; break; case 5: if (e->controlRequestCallback) { (e->controlRequestCallback)( (dis_pdu *) pdu, e->callbackData ); } break; default: printf("Unrecognized response flag in Acknowledge DIS PDU: %d\n", pdu->resp_flag ); break; } e->controlRequestCallback = NULL; e->callbackData = NULL; } } return 0; } int dis_if_sendMessage(int senderEid, char *s) { dis_comment_pdu pdu, *msgPDU = &pdu; dis_variable_datum datum; dis_if_Entity *sender = varray_getValue(entities, senderEid); if ( ! network_enabled || ! app || validating_site_id ) return 0; msgPDU->hdr.pdu_type = PDUTypeComment; msgPDU->hdr.time_stamp = timeDoubleToDIS(theTime, absoluteTime); msgPDU->orig_id = sender->entityId; msgPDU->recv_id.entity_id = 0; // ? msgPDU->num_variable_data = 1; msgPDU->variable_datum = &datum; datum.datum_id = datum_AltDescription; // ? datum.value_length = 8*strlen(s); datum.value.ptr_value = (u_char *) s; if (disx_writePDU(app, (dis_pdu *) msgPDU) != 0) { return -1; } return 0; } int dis_if_requestControl (dis_if_Entity *e, int (*callbackFn)(dis_pdu*, void *), void *arg) { dis_pdu pdu; int status; dis_if_OutstandingRequestInfo *preq; if ( app == NULL || validating_site_id || e->isLocal) return -1; memset ( &pdu, 0, sizeof(pdu) ); e->callbackData = arg; e->controlRequestCallback = callbackFn; pdu.hdr.pdu_type = PDUTypeTransferControl; pdu.hdr.time_stamp = timeDoubleToDIS(theTime, absoluteTime); pdu.transfer_control.request_id = disx_issueRequestID ( app ); pdu.transfer_control.orig_id.sim_id.site_id = site; pdu.transfer_control.orig_id.sim_id.application_id = application; pdu.transfer_control.orig_id.entity_id = NO_ENTITY; pdu.transfer_control.recv_id.sim_id = e->entityId.sim_id; pdu.transfer_control.recv_id.entity_id = NO_ENTITY; pdu.transfer_control.target_id = e->entityId; pdu.transfer_control.reliability_service = 1; pdu.transfer_control.num_record_sets = 0; pdu.transfer_control.transfer_type = DISTransferTypeEntityRequest; /* * Add tracking information so that we know about this * outstanding request. */ preq = addRequest ( pdu.transfer_control.request_id ); if (preq) { preq->request_type = OUTSTANDING_REQUEST_TRANSFER_CONTROL; preq->e = e; /* requests can timeout, but we don't track that, yet */ preq->timeout_time = theTime + 5.0; } status = disx_writePDU( app, & pdu ); return (status == 0) ? 0 : -1; } static int setDataPDU (dis_set_data_pdu *pdu) { int eid; dis_data_pdu reply_pdu; unsigned int i; int status; if( app == NULL ) return -1; reply_pdu.hdr = pdu->hdr; reply_pdu.hdr.pdu_type = PDUTypeData; reply_pdu.hdr.time_stamp = timeDoubleToDIS( theTime, absoluteTime ); reply_pdu.orig_id = pdu->recv_id; reply_pdu.recv_id = pdu->orig_id; reply_pdu.request_id = pdu->request_id; disx_initializeDatumInfo (&reply_pdu.datum_info); eid = findEntity(&pdu->recv_id); if (eid == 0) { return -1; } /* else { e = &entities[eid]; } */ for (i=0; idatum_info.num_fixed_data; ++i) { switch ( pdu->datum_info.variable_datum[i].datum_id ) { case datum_OrientationX: break; case datum_OrientationY: break; case datum_OrientationZ: break; case datum_XVelocity: break; case datum_YVelocity: break; case datum_ZVelocity: break; } } for (i=0; idatum_info.num_variable_data; ++i) { switch ( pdu->datum_info.variable_datum[i].datum_id ) { case datum_GeocentricCoordinatesX: break; case datum_GeocentricCoordinatesY: break; case datum_GeocentricCoordinatesZ: break; } } /* * Send reply */ status = disx_writePDU(app, (dis_pdu *) & reply_pdu); return (status == 0) ? 0 : -1; } static int stopPDU (dis_stop_pdu *pdu) { dis_if_Entity *e; int eid; int status = 0; int need_reply = 1; int all_local_entities = 0; dis_acknowledge_pdu reply_pdu; struct timeval tv; double changeTime; if( app == NULL || validating_site_id ) return -1; reply_pdu.hdr = pdu->hdr; reply_pdu.hdr.pdu_type = PDUTypeAcknowledge; reply_pdu.hdr.time_stamp = timeDoubleToDIS( theTime, absoluteTime ); reply_pdu.orig_id = pdu->recv_id; reply_pdu.recv_id = pdu->orig_id; reply_pdu.request_id = pdu->request_id; reply_pdu.acknowledge_flag = DISAcknowledgeFlagStop; reply_pdu.resp_flag = DISRequestStatusComplete; if (pdu->recv_id.sim_id.site_id == ALL_SITES) { all_local_entities = 1; } else if (pdu->recv_id.sim_id.site_id == site && pdu->recv_id.sim_id.application_id == ALL_APPLIC) { all_local_entities = 1; } else if (pdu->recv_id.sim_id.site_id == site && pdu->recv_id.sim_id.application_id == application && pdu->recv_id.entity_id == ALL_ENTITIES) { all_local_entities = 1; } dis_timeToTimeval( &pdu->real_time, &tv ); changeTime = tv.tv_sec + tv.tv_usec / 1000000.0; if ( all_local_entities ) { int i; for(i = varray_firstHandle(entities); i != 0; i = varray_nextHandle(entities)){ e = varray_getValue(entities, i); if ( ! e->isLocal ) { continue; } if ( changeTime <= theTime ) { e->state = dis_if_ENTITY_STATE_STOPPED; } else { e->pending_state = dis_if_ENTITY_STATE_STOPPED; e->pending_time = changeTime; } if ( pdu->behavior & DISFrozenBehaviorRunClock ) { } if ( pdu->behavior & DISFrozenBehaviorTransmit ) { e->emit_while_frozen = 1; } if ( pdu->behavior & DISFrozenBehaviorReceive ) { } } varray_releaseIterator(entities); } else { eid = findEntity(&pdu->recv_id); if (eid == 0) { /* cannot comply, entity not found */ reply_pdu.orig_id.entity_id = NO_ENTITY; reply_pdu.resp_flag = DISRequestStatusOther; } else { e = varray_getValue(entities, eid); if (e->isLocal) { if ( changeTime <= theTime ) { e->state = dis_if_ENTITY_STATE_STOPPED; } else { e->pending_state = dis_if_ENTITY_STATE_STOPPED; e->pending_time = changeTime; } if ( pdu->behavior & DISFrozenBehaviorRunClock ) { } if ( pdu->behavior & DISFrozenBehaviorTransmit ) { e->emit_while_frozen = 1; } if ( pdu->behavior & DISFrozenBehaviorReceive ) { } } else { need_reply = 0; } } } /* * Send reply */ if (need_reply) { status = disx_writePDU(app, (dis_pdu *) & reply_pdu); } return (status == 0) ? 0 : -1; } static int startPDU (dis_start_pdu *pdu) { dis_if_Entity *e; int eid; int status = 0; int need_reply = 1; int all_local_entities = 0; dis_acknowledge_pdu reply_pdu; struct timeval tv; double changeTime; if( app == NULL || validating_site_id ) return -1; reply_pdu.hdr = pdu->hdr; reply_pdu.hdr.pdu_type = PDUTypeAcknowledge; reply_pdu.hdr.time_stamp = timeDoubleToDIS( theTime, absoluteTime ); reply_pdu.orig_id = pdu->recv_id; reply_pdu.recv_id = pdu->orig_id; reply_pdu.request_id = pdu->request_id; reply_pdu.acknowledge_flag = DISAcknowledgeFlagStop; reply_pdu.resp_flag = DISRequestStatusComplete; if (pdu->recv_id.sim_id.site_id == ALL_SITES) { all_local_entities = 1; } else if (pdu->recv_id.sim_id.site_id == site && pdu->recv_id.sim_id.application_id == ALL_APPLIC) { all_local_entities = 1; } else if (pdu->recv_id.sim_id.site_id == site && pdu->recv_id.sim_id.application_id == application && pdu->recv_id.entity_id == ALL_ENTITIES) { all_local_entities = 1; } dis_timeToTimeval( &pdu->real_time, &tv ); changeTime = tv.tv_sec + tv.tv_usec / 1000000.0; if ( all_local_entities ) { int i; for(i = varray_firstHandle(entities); i != 0; i = varray_nextHandle(entities)){ e = varray_getValue(entities, i); if ( ! e->isLocal ) { continue; } if ( changeTime <= theTime ) { e->state = dis_if_ENTITY_STATE_SIMULATING; } else { e->pending_state = dis_if_ENTITY_STATE_SIMULATING; e->pending_time = changeTime; } e->emit_while_frozen = 0; } varray_releaseIterator(entities); } else { eid = findEntity( &pdu->recv_id ); if (eid == 0) { /* cannot comply. entity not found */ reply_pdu.orig_id.entity_id = NO_ENTITY; reply_pdu.resp_flag = DISRequestStatusOther; } else { e = varray_getValue(entities, eid); /* * Is entity local ? */ if ( e->isLocal ) { if ( changeTime <= theTime ) { e->state = dis_if_ENTITY_STATE_SIMULATING; } else { e->pending_state = dis_if_ENTITY_STATE_SIMULATING; e->pending_time = changeTime; } e->emit_while_frozen = 0; } else { need_reply = 0; } } } /* * Send reply */ if (need_reply) { status = disx_writePDU(app, (dis_pdu *) & reply_pdu); } return (status == 0) ? 0 : -1; } int dis_if_getNumberOfLocalEntities() { return stats_local_entities_no; } int dis_if_getNumberOfRemoteEntities() { return stats_remote_entities_no; } double dis_if_getProcessedPacketsPerSecond() { return stats_processed_packets_per_second; } char *dis_if_updateRemote(craft *c) { double location[3]; double velocity[3]; double orientation[3]; VPoint tmp; VMatrix ABCtoXYZ; if( ! dis_if_getEntityState(c->disId, location, velocity, orientation) ) return "entity not tracked anymore"; c->prevSg = c->Sg; c->Sg.x = location[0]; c->Sg.y = location[1]; c->Sg.z = location[2]; earth_XYZToLatLonAlt(&c->Sg, &c->w); earth_generateWorldToLocalMatrix(&c->w, &c->XYZtoNED); tmp.x = units_METERStoFEET(velocity[0]); tmp.y = units_METERStoFEET(velocity[1]); tmp.z = units_METERStoFEET(velocity[2]); VTransform_(&tmp, &c->XYZtoNED, &c->Cg); /* Compute the "ABCtoNED" trihedral from the DIS Euler angles: */ c->curRoll = pm_normalize_roll( orientation[0] ); c->curPitch = pm_normalize_pitch( orientation[1] ); c->curHeading = pm_normalize_yaw( orientation[2] ); VEulerToMatrix(c->curRoll, c->curPitch, c->curHeading, &ABCtoXYZ); VMatrixMultByRank(&ABCtoXYZ, &c->XYZtoNED, &c->trihedral, 3); /* Now derive NED heading, pitch and roll from adjusted trihedral: */ pm_euler(c); return NULL; } void dis_if_updateLocal(craft *c) { VPoint velocity, linearAcceleration; double location[3], disVelocity[3], disLinearAcceleration[3]; double orientation[3], angularVelocity[3]; VPoint tmp; VMatrix ABCtoXYZ, NEDtoXYZ; static double base = -1; if (base < 0) base = curTime; /* * Well, this is a bit strange, but ACM's coordinate system for positions * is meters in the Geocentric; for velocities are expressed as feet per * second in the local NED [north-east-down] system. */ location[0] = c->Sg.x; location[1] = c->Sg.y; location[2] = c->Sg.z; tmp.x = units_FEETtoMETERS(c->Cg.x); tmp.y = units_FEETtoMETERS(c->Cg.y); tmp.z = units_FEETtoMETERS(c->Cg.z); VReverseTransform_(&tmp, &c->XYZtoNED, &velocity); disVelocity[0] = velocity.x; disVelocity[1] = velocity.y; disVelocity[2] = velocity.z; /* * Derive ECI [Geocentric] heading, pitch, roll */ VMatrixTranspose(&c->XYZtoNED, &NEDtoXYZ); /* the trihedral is an "ABCtoNED" transformation */ VMatrixMultByRank(&c->trihedral, &NEDtoXYZ, &ABCtoXYZ, 3); VMatrixToEuler(&ABCtoXYZ, &orientation[0], &orientation[1], &orientation[2]); /* * Body frame angular velocities. */ angularVelocity[0] = c->p; /* x-axis */ angularVelocity[1] = c->q; /* y-axis */ angularVelocity[2] = c->r; /* z-axis */ /* * Transform linear acceleration vector * from body coordinates to ECI system */ tmp = c->linAcc; tmp.x = units_FEETtoMETERS(tmp.x); tmp.y = units_FEETtoMETERS(tmp.y); tmp.z = units_FEETtoMETERS(tmp.z); VTransform_(&tmp, &ABCtoXYZ, &linearAcceleration); disLinearAcceleration[0] = linearAcceleration.x; disLinearAcceleration[1] = linearAcceleration.y; disLinearAcceleration[2] = linearAcceleration.z; dis_if_setEntityState(c->disId, location, disVelocity, disLinearAcceleration, orientation, angularVelocity); }acm-6.0_20200416/src/acm/vpath_gallery.h0000644000000000000000000000413113064342406016135 0ustar rootroot/* * acm : an aerial combat simulator for X - Gallery of common drawings * Copyright (C) 2008 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /** * This module collects some common drawings. * * @file */ #ifndef vpath_gallery_H #define vpath_gallery_H #include "vpath.h" #ifdef vpath_gallery_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Return a compass scale drawn over the xy plane in screen coordinates, * north is up, radius 1.0. */ EXTERN vpath_Type * vpath_gallery_get_compass_scale(void); /** * Release all the internal data structures. */ EXTERN void vpath_gallery_free_all(void); /** * Return a compass fixed scale composed of tick marks drawn every 45 * DEG. The scale is drawn inside a circle of radius 1.0 with internal * radius of 0.90. The scale is drawn over the xy plane in screen frame * and centered on the origin. */ EXTERN vpath_Type * vpath_gallery_get_compass_fixed_scale(void); /** * Return a stylized aircraft draw inside a square box of side length * 2.0, nose "up", the center is the origin of the xy plane. */ EXTERN vpath_Type * vpath_gallery_get_stylized_aircraft(void); /** * Arrow that points "up" centered on a circle of radius 1.0. */ EXTERN vpath_Type * vpath_gallery_get_pointer_arrow(void); /** * Pointer shaped as a triangle and located on the outside border of a * circle of radius 1.0. Its initial indication is "up". */ EXTERN vpath_Type * vpath_gallery_get_pointer_triangle(void); #undef EXTERN #endif acm-6.0_20200416/src/acm/windows.h0000644000000000000000000000224413063670321014770 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #ifndef _windows_h #define _windows_h #ifdef windows_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Resize the window, change HUD mode/classic panel mode, set cockpit view * and instrument panel layout. */ EXTERN void windows_set_layout(craft * c, viewer * u, int width, int height, _BOOL hud_mode); EXTERN void windows_zoom_in(viewer * u); EXTERN void windows_zoom_out(viewer * u); #undef EXTERN #endif acm-6.0_20200416/src/acm/effects.c0000644000000000000000000002011213173127011014675 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1997 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include "../V/VObjects.h" #include "pm.h" #include "../util/memory.h" #include "../util/prng.h" #define effects_IMPORT #include "effects.h" typedef struct _explosion_data { struct _explosion_data * next; /* linked list of released blocks */ double escale; /* overall size (m) */ int duration; /* dust expiry time (units of deltaT) */ int flameDuration; /* flame expiry time (units of deltaT) */ } explosion_data; static explosion_data * explosion_data_free_list; /** * If cleanup already invoked, then the program is terminating and is killing * any remaining entity, so placing new explosions is useless and has no effect. */ static int no_more_explosions; /* * Better to fill-in all the data structures because several parts of the * program relies on their availability and crashes otherwise. The alternative * would be to put several if() here and there to check for NULL entries, but * simply assigning something reasonable makes the program simpler, faster and * easier to debug. */ static VObject explosion_obj = { "Explosion", (VPoint) {0.0, 0.0, 0.0}, (VPoint) {0.0, 0.0, 0.0}, (VPoint) {0.0, 0.0, 0.0}, (VPoint) {0.0, 0.0, 0.0}, 0.0, 0, NULL, NULL }; #define SPIKES 16 #define FLAME_SPIKES 8 #define SMOKE_INNER 0.2 #define SMOKE_RADIUS 1.0 #define SMOKE_MIN_RADIUS 0.5 #define SMOKE_VARIATION (SMOKE_RADIUS - SMOKE_MIN_RADIUS) #define FLAME_RADIUS 0.5 #define FLAME_MIN_RADIUS 0.3 static VObject *explosionTemplate; static craftType *explosion_craft; static VColor_Type *effectBlackColor; static void explosion_free(explosion_data * ed) { ed->next = explosion_data_free_list; explosion_data_free_list = ed; } static void effects_kill_explosion(craft * e, char *reason) { explosion_free( (explosion_data *) e->effects ); e->effects = NULL; e->type = CT_FREE; } /** * Releases internal data structures. Also release data for any mtbl[] * of type CT_EXPLOSION. * * WARNING. This also removes data that might be used by some craft of * type CT_EXPLOSION, so all the crafts of this type should be already * released. */ static void effects_cleanup() { int i; craft *c; explosion_data * ed; for(i = 0; i < manifest_MAXPROJECTILES; i++ ){ c = &mtbl[i]; if( c->type == CT_EXPLOSION ){ effects_kill_explosion(c, "program terminated"); } } if( explosionTemplate ){ VDestroyObject(explosionTemplate); explosionTemplate = NULL; } if( explosion_craft != NULL ){ memory_dispose(explosion_craft); explosion_craft = NULL; } while( explosion_data_free_list != NULL ){ ed = explosion_data_free_list; explosion_data_free_list = ed->next; memory_dispose(ed); } no_more_explosions = 1; } static char * effects_explosion_calculations(craft * e) { explosion_data * ed = (explosion_data *) e->effects; --(ed->flameDuration); if ((--ed->duration) <= 0) return "flames and smoke vanished"; else return NULL; } static explosion_data * explosion_malloc() { explosion_data * ed; if( explosion_data_free_list == NULL ){ return memory_allocate( sizeof(explosion_data), NULL ); } else { ed = explosion_data_free_list; explosion_data_free_list = ed->next; return ed; } } double copysign(double x, double y) { return (y < 0.0) ? -fabs(x) : fabs(x); } static VObject * buildExplosion(void) { register int i, numSpikes, numFlame, numRed, poly; register VObject *obj; VColor_Type *redFlameColor, *orangeFlameColor, *color; VPoint vp[3]; double x, s; numSpikes = SPIKES; numFlame = FLAME_SPIKES; numRed = numFlame / 2; effectBlackColor = VColor_getByName("black", 0); redFlameColor = VColor_getByName("red", 0); orangeFlameColor = VColor_getByName("orange", 0); obj = (VObject *) memory_allocate(sizeof(VObject), NULL); obj->name = memory_strdup("explosion"); obj->numPolys = numSpikes + numFlame; obj->polygon = (VPolygon **) memory_allocate(obj->numPolys * sizeof(VPolygon *), NULL); obj->order = (unsigned short *) NULL; poly = 0; for (i = 0; i < numSpikes; ++i) { x = prng_getDouble2(); s = copysign(1.0, x); x = fabs(x); vp[0].x = (SMOKE_MIN_RADIUS + x * SMOKE_VARIATION) * s; x = prng_getDouble2(); s = copysign(1.0, x); x = fabs(x); vp[0].y = (SMOKE_MIN_RADIUS + x * SMOKE_VARIATION) * s; x = prng_getDouble2(); s = copysign(1.0, x); x = fabs(x); vp[0].z = (SMOKE_MIN_RADIUS + x * SMOKE_VARIATION) * s; vp[1].x = prng_getDouble2() * SMOKE_INNER; vp[1].y = prng_getDouble2() * SMOKE_INNER; vp[1].z = prng_getDouble2() * SMOKE_INNER; vp[2].x = prng_getDouble2() * SMOKE_INNER; vp[2].y = prng_getDouble2() * SMOKE_INNER; vp[2].z = prng_getDouble2() * SMOKE_INNER; obj->polygon[poly++] = VCreatePolygon(3, vp, effectBlackColor); } for (i = 0; i < numFlame; ++i) { x = prng_getDouble2(); s = copysign(1.0, x); x = fabs(x); vp[0].x = (FLAME_MIN_RADIUS + x * FLAME_RADIUS) * s; x = prng_getDouble2(); s = copysign(1.0, x); x = fabs(x); vp[0].y = (FLAME_MIN_RADIUS + x * FLAME_RADIUS) * s; x = prng_getDouble2(); s = copysign(1.0, x); x = fabs(x); vp[0].z = (FLAME_MIN_RADIUS + x * FLAME_RADIUS) * s; vp[1].x = prng_getDouble2() * SMOKE_INNER; vp[1].y = prng_getDouble2() * SMOKE_INNER; vp[1].z = prng_getDouble2() * SMOKE_INNER; vp[2].x = prng_getDouble2() * SMOKE_INNER; vp[2].y = prng_getDouble2() * SMOKE_INNER; vp[2].z = prng_getDouble2() * SMOKE_INNER; if (i < numRed) color = redFlameColor; else color = orangeFlameColor; obj->polygon[poly++] = VCreatePolygon(3, vp, color); } return obj; } static int placeExplosion(Viewport * v, craft * obj, VMatrix * mtx, VPolySet *ps) { explosion_data * ed; int i, k, n; VPolygon **e, *p; VPoint tmp, *q; ed = (explosion_data *) obj->effects; n = explosionTemplate->numPolys; e = explosionTemplate->polygon; for (i = 0; i < n; ++i) { if (ed->flameDuration > 0 || e[i]->color == effectBlackColor) { p = VCopyPolygon(e[i]); for ((k = 0, q = p->vertex); k < p->numVtces; (++k, ++q)) { tmp.x = q->x * ed->escale + obj->Sg.x; tmp.y = q->y * ed->escale + obj->Sg.y; tmp.z = q->z * ed->escale + obj->Sg.z; *q = tmp; } VTransformPolygon(p, &v->eyeSpace); VPolySet_Add(ps, p); } } return 0; } static void effects_init() { memory_registerCleanup(effects_cleanup); explosionTemplate = buildExplosion(); explosion_craft = memory_allocate( sizeof(craft), NULL ); memset(explosion_craft, 0, sizeof(craft)); explosion_craft->object = &explosion_obj; explosion_craft->objname = "Explosion"; explosion_craft->placeProc = placeExplosion; explosion_data_free_list = NULL; } void effects_new_explosion(VPoint * loc, VPoint *vel, double s_meters, double dur1, double dur2) { int i; craft *e; explosion_data * ed; if( no_more_explosions ){ return; } if( explosionTemplate == NULL ) effects_init(); for (i = 0; i < manifest_MAXPROJECTILES; ++i) { if (mtbl[i].type == CT_FREE) { ed = explosion_malloc(); ed->escale = s_meters; ed->duration = (int) (dur1 / deltaT + 0.5); ed->flameDuration = (int) (dur2 / deltaT + 0.5); e = &mtbl[i]; e->type = CT_EXPLOSION; e->effects = ed; memory_strcpy(e->name, sizeof(e->name), "Explosion"); e->Sg = *loc; earth_XYZToLatLonAlt(&e->Sg, &e->w); e->Cg = *vel; e->cinfo = explosion_craft; e->curHeading = e->curRoll = e->curPitch = 0.0; e->update = effects_explosion_calculations; e->kill = effects_kill_explosion; break; } } } acm-6.0_20200416/src/acm/planes.c0000644000000000000000000001516213173127546014566 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include #include "alarm.h" #include "damage.h" #include "gear.h" #include "inventory.h" #include "pm.h" #include "terrain.h" #include "weapon.h" #include "../util/error.h" #include "../util/units.h" #define planes_IMPORT #include "planes.h" static double planes_noEngineThrust(craft *c) { c->rpm = 0.0; return 0.0; } /** * Generic piston engine performances with altitude. * The formula has been estimated from the reference below, in particular from * table 1 page 19 from which I deduced the following relation: * * P[h]/P[0] = pow(rho[h]/rho[0], 1.6) * * where P[h] is the maximum power at the given altitude and rho[h] is the * air density at the given altitude. As stated in the conclusions of the * reference, the effects of the air temperature are minimal, at least on * the altitude range of a small piston engine like our C-172RG, so the air * temperature is here ignored. * * Performances were measured on a small 2-strokes engine on a simulated * environment. I don't know how much these data are representative of a real * piston engine on a real airplane. * * Reference: * Travis Don Husaboe, Effects of temperature on the performance of a small * internal combustion engine at altitude", thesis at Department of the Air * Force, Air University, Ohio, March 2013. * @param c * @return Thrust (lbf). */ static double planes_genericPistonEngineThrust(craft *c) { if ( c->fuel > 0.0 ) c->throttle = c->throttleComm; else c->throttle = 0; double ts = c->throttle / 32768.0; c->rpm = (c->rpm - ts) * exp(deltaT / c->cinfo->engineLag) + ts; return c->rpm * interpolate_value(c->cinfo->Thrust, c->mach) * c->cinfo->maxThrust * pow(c->air.rho / units_RHO_0, 1.6); } static double planes_genericJetEngineThrust(craft *c) { double t, ts; if (c->flags & FL_AFTERBURNER) { t = interpolate_value(c->cinfo->ABThrust, c->mach) * c->cinfo->maxABThrust; } else { t = interpolate_value(c->cinfo->Thrust, c->mach) * c->cinfo->maxThrust; } if ( c->fuel > 0.0 ) c->throttle = c->throttleComm; else c->throttle = 0; ts = c->throttle / 32768.0; c->rpm = (c->rpm - ts) * exp(deltaT / c->cinfo->engineLag) + ts; return t * c->rpm * c->rpm * c->air.rho / units_RHO_0; } static double planes_genericRocketEngineThrust(craft *c) { if ( c->fuel > 0.0 ) c->throttle = c->throttleComm; else c->throttle = 0; double ts = c->throttle / 32768.0; c->rpm = (c->rpm - ts) * exp(deltaT / c->cinfo->engineLag) + ts; if( c->rpm < 0 ) c->rpm = 0; else if( c->rpm > 1 ) c->rpm = 1; return c->rpm * c->cinfo->maxThrust; } inventory_ThrustCalculator * planes_getThrustCalculator(craftType * cinfo) { switch(cinfo->engineType){ case inventory_NoEngine: return planes_noEngineThrust; case inventory_GenericPistonEngine: return planes_genericPistonEngineThrust; case inventory_GenericJetEngine: return planes_genericJetEngineThrust; case inventory_GenericRocketEngine: return planes_genericRocketEngineThrust; default: error_internal("unknown engine type: %d", cinfo->engineType); } } double planes_fuelUsed( craft * c ) { double spFuelConsump; if (c->flags & FL_AFTERBURNER) { spFuelConsump = c->cinfo->spABFuelConsump; } else { spFuelConsump = c->cinfo->spFuelConsump; } return spFuelConsump * c->curThrust * deltaT / 3600.0; } void planes_genericResupply(craft * c) { int i; if( c->type == CT_DRONE ){ /* half refueling for drones: */ c->fuel = 0.5 * c->cinfo->maxFuel; #ifdef FIXME_NOT_DEFINED } else { /* +10% every 30 s while on ground: */ c->fuel += c->cinfo->maxFuel / 10.0; if ( c->fuel > c->cinfo->maxFuel ) c->fuel = c->cinfo->maxFuel; #endif } for (i = 0; i < c->cinfo->sCount; i++) { c->station[i] = c->cinfo->station[i]; } damage_reset(c); } void planes_doResupply(void *arg1, void *arg2) { craft *c; int i; double d; for ((i = 0, c = &ptbl[0]); i < manifest_MAXPLAYERS; (++i, ++c)) { if (c->type != CT_PLANE) continue; if (VMagnitude(&c->Cg) < 5.0) { d = 0.0; if (d <= manifest_MAX_GROUND_DISTANCE) (*c->cinfo->resupply) (c); /* ignore = */ weapon_selectByName(c, c->curWeapon); } } /* id = */ alarm_add(manifest_RESUPPLY_INTERVAL, planes_doResupply, NULL, NULL); } int planes_newPlane(char *planeType) { int i; craft *c; for (i = 0; i < manifest_MAXPLAYERS; ++i) { if (ptbl[i].type == CT_FREE || ptbl[i].type == CT_RESERVED) { break; } } if (i == manifest_MAXPLAYERS) return -1; c = &ptbl[i]; if ((c->cinfo = inventory_craftTypeSearchByZoneAndName(NULL, planeType)) == NULL) { return -2; } c->type = CT_PLANE; c->Cg.x = 0.0; c->Cg.y = 0.0; c->Cg.z = 0.0; /* Ensure terrain_local_altitude() will update the local altitude at the first call */ c->terrain_altitude_timeout = curTime - 10.0; /* c->terrain_altitude = UNKNOW; */ c->p = c->q = c->r = 0.0; c->pitchComm = c->rollComm = c->steerComm = c->rudderComm = 0.0; c->Se = c->Sr = c->Sa = 0.0; c->SeTrim = c->SaTrim = 0.0; c->throttleComm = 0.20 * 32768.0; /* 20% */ c->throttle = 0; c->curThrust = (c->cinfo->thrust) (c); c->rpm = (double) c->throttle / 32768.0; c->thrust_reverse_on = FALSE; c->thrust_reverse_pos = 1.0; c->curFlap = 0.0; c->flapSetting = 0.0; c->curSpeedBrake = 0.0; c->speedBrakeSetting = 0.0; c->curHeading = c->curPitch = c->curRoll = 0.0; VIdentMatrix(&(c->trihedral)); c->flags = 0; c->curRadarTarget = -1; pm_hud_strings_alloc(c); /* AutoPilot System (automatically allocated by aps.c): */ c->aps = NULL; /* Magnetic VAR handling: */ c->showMag = 0; c->actualLocalVAR = 0.0; c->updActualMagneticField = 0.0; c->indicatedLocalVAR = 0.0; c->updIndicatedMagneticField = 0.0; c->radarMode = RM_OFF; gear_allocate(c); gear_down(c); /* * rearm and fuel the aircraft. */ (*c->cinfo->resupply) (c); c->w.z = 0.0; /* sea level -- caller must set properly */ /* Set c->curWeapon: */ weapon_selectByName(c, weapon_NULL); return i; } acm-6.0_20200416/src/acm/place.h0000644000000000000000000000214113064345261014361 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #ifndef _place_h #define _place_h #include "pm.h" #ifdef place_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Add the object view of the object to the polygons set of the view from * the given craft. Polygons are added to ps. */ EXTERN void place_craft(Viewport * v, craft * c, viewer *u, craft * obj, VPolySet *ps); #undef EXTERN #endif acm-6.0_20200416/src/acm/missile.h0000644000000000000000000000236313104077365014752 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /** * Common routines for any specific type of missile. * @file */ #ifndef _missile_h #define _missile_h #include "pm.h" #ifdef missile_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Fires a missile. * @param c Shooting craft. * @param ind Station index of the missile. * @return 0=missile fired. -1=projectiles table full, sorry! */ EXTERN int missile_fire(craft * c, int ind); EXTERN int missile_getIRTarget(craft * c, VPoint * t, double scanSlope); #undef EXTERN #endif acm-6.0_20200416/src/acm/aps.h0000644000000000000000000001363613175035430014070 0ustar rootroot/* * acm - AutoPilot System module * Copyright (C) 2007 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /** * Auto-Pilot System (APS). Implements the following features: * * - AutoPilot (AP): hold altitude or hold climb ratio. * - AutoCoordination (AC): rudder control in turns. * - AutoTurn (AW): hold heading or hold turn ratio. * - AutoNavigation (AN): follow HSI OBS. * - AutoLanding (AL): follow ILS locator and glide plane. * - AutoThrottle (AT): throttle control to keep IAS. * - Rate control: pilot's stick position controls pitch ratio and roll ratio * on a defined range. * * Keeps the status of the APS in the 'aps' fields of the 'craft' type. * Each function may allocate the APS in the given craft if not already set, * no need to call any specific initialization function. */ #ifndef _aps_h #define _aps_h #include "pm.h" #ifdef aps_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Turns of the APS. * @param c */ EXTERN void aps_off(craft * c); /** * Enables AP: hold altitude (if climb ratio module less than +/-100 fpm) or * hold climb ratio. */ EXTERN void aps_ap_enable(craft * c); /** * Disables AP. */ EXTERN void aps_ap_disable(craft * c); /** * Returns true if AP is enabled. * @param c * @return */ EXTERN _BOOL aps_ap_enabled(craft * c); /** * AP enable/disable toggle. * @param c */ EXTERN void aps_ap_toggle(craft * c); /** * Set AP climb ratio. If current climb ratio is less than +/-100 fpm, hold * altitude. * @param c * @param vs */ EXTERN void aps_ap_set_vs(craft * c, double vs /* m/s */); /** * Returns the computed elevator correction as a number between -1.0 and +1.0. * Returns 0.0 if AP disabled. * @param c * @return */ EXTERN double aps_get_delta_elevator(craft * c); /** * Returns the computed ailerons correction as a number between-1.0 and +1.0. * Returns 0.0 if AP not enabled. * @param c * @return */ EXTERN double aps_get_delta_ailerons(craft * c); /** Enables AC. */ EXTERN void aps_ac_enable(craft * c); /** Disables AC. */ EXTERN void aps_ac_disable(craft * c); /** Toggles AC status. */ EXTERN void aps_ac_toggle(craft * c); /** Returns true if AC currently enabled. */ EXTERN _BOOL aps_ac_enabled(craft * c); /** AC calculated rudder correction [-1,+1], or zero if disabled. */ EXTERN double aps_ac_get_delta_rudder(craft * c); /** Enables AT. */ EXTERN void aps_at_enable(craft * c); /** Disables AT. */ EXTERN void aps_at_disable(craft * c); /** Toggles AT status. */ EXTERN void aps_at_toggle(craft * c); /** Returns true if AT currently enabled. */ EXTERN _BOOL aps_at_enabled(craft * c); /** Returns AT current target IAS (ft/s). */ EXTERN double aps_at_get_velocity(craft * c); /** Increments AT target IAS +5 KT. */ EXTERN void aps_at_inc_velocity(craft * c); /** Decrements AT target IAS -5 KT. */ EXTERN void aps_at_dec_velocity(craft * c); /** Increments maximum bank angle +5 DEG. Max is 25; default is 25. */ EXTERN void aps_bank_max_inc(craft * c); /** Decrements maximum bank angle -5 DEG. Min is 5; default is 25. */ EXTERN void aps_bank_max_dec(craft * c); /** Returns current maximum allowed bank angle in turns (DEG). */ EXTERN int aps_bank_max_get(craft * c); /** Enables AW. */ EXTERN void aps_aw_enable(craft * c); /** Disables AW. */ EXTERN void aps_aw_disable(craft * c); /** Returns true if AW currently enabled. */ EXTERN _BOOL aps_aw_enabled(craft * c); /** * Set AW turn rate around the current Earth vertical. * @param c * @param w Turn rate, left if positive (RAD/s). */ EXTERN void aps_aw_set(craft * c, double w); /** Returns current AW rate (RAD/s). */ EXTERN double aps_aw_get(craft * c); /** Enables AN. */ EXTERN void aps_an_enable(craft * c); /** Disables AN. */ EXTERN void aps_an_disable(craft * c); /** Toggles AN. */ EXTERN void aps_an_toggle(craft * c); /** Returns true if AN currently enabled. */ EXTERN _BOOL aps_an_enabled(craft * c); /** Enables AL on currently tuned ILS. Does nothing if no tuned ILS. */ EXTERN void aps_al_enable(craft * c); /** Disables AL. */ EXTERN void aps_al_disable(craft * c); /** Toggles AL. */ EXTERN void aps_al_toggle(craft * c); /** Returns true if AL currently enabled. */ EXTERN _BOOL aps_al_enabled(craft * c); /** Enables rate control. */ EXTERN void aps_rate_control_enable(craft * c); /** Disables rate control. */ EXTERN void aps_rate_control_disable(craft * c); /** Toggles rate control. */ EXTERN void aps_rate_control_toggle(craft * c); /** Returns true if rate control currently enabled. */ EXTERN _BOOL aps_rate_control_enabled(craft * c); /** Returns true if AP cannot attain the requested altitude or climb rate. */ EXTERN _BOOL aps_ap_warn(craft * c); /** Returns true if AT cannot attain the requested speed. */ EXTERN _BOOL aps_at_warn(craft * c); /** Returns true if AN cannot follow the VOR curse. */ EXTERN _BOOL aps_an_warn(craft * c); /** Returns true if AL cannot follow the ILS locator or glide slope. */ EXTERN _BOOL aps_al_warn(craft * c); /** Returns true if AW cannot attain the given turn rate. */ EXTERN _BOOL aps_aw_warn(craft * c); /** Returns true if the AC cannot compensate lateral acceleration. */ EXTERN _BOOL aps_ac_warn(craft * c); /** * Updates the internal state of the APS. Should be called frequently enough, * at least every 0.1 s. Does nothing if no APS enabled. * @param c */ EXTERN void aps_update(craft * c); #undef EXTERN #endif acm-6.0_20200416/src/acm/init.h0000644000000000000000000000375113173127226014250 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #ifndef _init_h #define _init_h #include #ifdef init_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Overall initialization of the program. * @param objects List of directories where to search for configuration files. * @param departure_date Departure zulu date and time formatted as one of: * - "YYYY-MM-DDThh:mm:ss" * - "YYYY-MM-DDThh:mm" * - "YYYY-MM-DD" * - "YYYY-MM" * If NULL or empty, the current zulu time is used. */ EXTERN void init_init(char *objects, char *departure_date); /** * Terminates... the initialization module! */ EXTERN void init_term(void); /** * Find an important configuration data file, or die trying. First tries the * path alone, then it tries each objects directory joined with it, in the * order. * @param path File to search. * @return Resolved path to an existing file as a pointer to an internal * statically allocated buffer; do not overwrite and copy as necessary! */ EXTERN char * init_findFile(char *path); /** * Opens a file. * @param path File to open. Applies init_findFile() to the search. * @param access Access mode. * @return Opened file. If not found or access denied, its a fatal error. */ EXTERN FILE * init_fopen(char *path, char *access); #undef EXTERN #endif acm-6.0_20200416/src/acm/missile.c0000644000000000000000000004374713175037632014761 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include #include "pm.h" #include "dis_if.h" #include "effects.h" #include "damage.h" #include "inventory.h" #include "planes.h" #include "terrain.h" #include "../util/error.h" #include "../util/memory.h" #include "../util/units.h" #define missile_IMPORT #include "missile.h" /** * Estimated closer point to the target. */ typedef struct missile_CloserPoint { /** Target. */ craft *c; /** Time to target (s). */ double time; /** Distance to target (m). */ double min; /** Position of the missile (world coordinates, m). */ VPoint Sg; /** Position of explosion relative in the target frame (m). */ VPoint rpos; /** Velocity of the missile in target frame (m/s). */ VPoint rvel; /** Next estimated entry. */ struct missile_CloserPoint *next; } missile_CloserPoint; static int mdebug = 0; static int isMissileHit(double min, craft * c); static int missile_lookForImpacts(craft *m); static void missile_trackTarget(craft * c); static void missile_kill(craft * c, char *reason); /** * Tells if the craft is above (0), in (1), below (2) the clouds. * Returns 0 when no clouds at all. */ static int inCloud(craft * c) { int state; if (clouds_top <= clouds_base || c->w.z > clouds_top) { state = 0; } else if (c->w.z > clouds_base) { state = 1; } else { state = 2; } return state; } static char * missile_update(craft * c) { double q; double FDrag, FWeight; double dNorth, dEast, dmag; VPoint F, Fg; /* * Check for ground impact. We do this at the beginning to permit us to * kill ground targets. */ if (c->w.z < terrain_localAltitude(c)) { q = -c->prevSg.z / (c->Sg.z - c->prevSg.z); c->Sg.x = c->prevSg.x + q * (c->Sg.x - c->prevSg.x); c->Sg.y = c->prevSg.y + q * (c->Sg.y - c->prevSg.z); c->Sg.z = 0.0; return "hit the ground"; } missile_trackTarget(c); /* * If we haven't armed the missile, yet. Decrement the delay timer. * If the FL_BALLISTIC flag is set, we have no target; self-destruct * if the timer expires. */ if (c->armTimer != 0.0) { if ((c->armTimer -= deltaT) < 0.0) { if (c->flags & FL_BALLISTIC) { return "no target -- self destruct"; } c->armTimer = 0.0; } } /* * Re-orient the body of the missile towards it's intended target. */ c->prevSg = c->Sg; air_update(&c->air, units_METERStoFEET(c->w.z)); /* * Compute the resultant force vector on the missile. */ c->VT = VMagnitude(&c->Cg); q = c->air.rho * c->cinfo->wingS * c->VT * c->VT * 0.5; FDrag = c->cinfo->CDOrigin * q; F.x = c->curThrust - FDrag; F.y = 0.0; F.z = 0.0; /* * Now calculate changes in position (Sg) and velocity (Cg). */ if ((c->fuel -= planes_fuelUsed(c)) <= 0.0) { /* if (c->curThrust > 0.0) if (mdebug) printf("Missile burnout; velocity = %g fps (%g kt)\n", c->VT, units_FPStoKT(c->VT)); */ c->fuel = 0.0; c->curThrust = 0.0; } /* * The missile's trihedral matrix is managed by * missile_trackTarget(). */ VTransform(&F, &c->AXYZtoNED, &Fg); FWeight = c->cinfo->emptyWeight + c->fuel + c->payload; Fg.z += FWeight; pm_calcGForces(c, &Fg, FWeight); /* if (mdebug) { printf("v = %g kt, Fg = { %g, %g, %g }\n", units_FPStoKT(c->VT), Fg.x, Fg.y, Fg.z); printf("F = { %g, %g, %g }\n", F.x, F.y, F.z); } */ /* * Update the missile's position and velocity. */ dNorth = units_FEETtoMETERS(c->Cg.x * deltaT + Fg.x / FWeight * units_earth_g * halfDeltaTSquared); dEast = units_FEETtoMETERS(c->Cg.y * deltaT + Fg.y / FWeight * units_earth_g * halfDeltaTSquared); c->w.z -= units_FEETtoMETERS(c->Cg.z * deltaT + Fg.z / FWeight * units_earth_g * halfDeltaTSquared); dmag = sqrt(dNorth * dNorth + dEast * dEast); earth_updateLatLon(&c->w, dNorth / dmag, dEast / dmag, dmag); earth_LatLonAltToXYZ(&c->w, &c->Sg); earth_generateWorldToLocalMatrix(&c->w, &c->XYZtoNED); c->Cg.x += Fg.x / FWeight * units_earth_g * deltaT; c->Cg.y += Fg.y / FWeight * units_earth_g * deltaT; c->Cg.z += Fg.z / FWeight * units_earth_g * deltaT; /* if (mdebug) { printf("Altitude = %g ft\n", units_METERStoFEET(c->w.z)); printf("Euler angles { %g, %g, %g }\n", units_RADtoDEG(c->curRoll), units_RADtoDEG(c->curPitch), units_RADtoDEG(c->curHeading)); printf("Cg = { %g, %g, %g }\n", c->Cg.x, c->Cg.y, c->Cg.z); printf("Sg = { %g, %g, %g }\n", c->Sg.x, c->Sg.y, c->Sg.z); } */ if( missile_lookForImpacts(c) ) return "target hit"; dis_if_updateLocal(c); return NULL; } int missile_fire(craft * c, int ind) { char * missileName; craftType * missile; register craft *m; register int i; VPoint s, s1; VPoint cY, mX, mY, mZ; double v; double disLocation[3]; VPoint velocity; double disVelocity[3]; double disZeroVec[3]; double disOrientation[3]; for ((i = 0, m = &mtbl[0]); i < manifest_MAXPROJECTILES; (++i, ++m)) if (m->type == CT_FREE) { m->type = CT_MISSILE; break; } if (i == manifest_MAXPROJECTILES) return -1; missileName = c->cinfo->station[ind].type; missile = inventory_craftTypeSearchByZoneAndName(NULL, missileName); if( missile == NULL ) error_internal("firing unknow missile type `%s'", missileName); memory_strcpy(m->name, sizeof(m->name), missile->name); m->cinfo = missile; m->fuel = missile->maxFuel; m->payload = 0.0; m->curThrust = missile->maxThrust; m->owner = c->pIndex; /* * Build trihedral based on the launching aircraft's current velocity vector * rather than simply it's current direction vector. * * (1) build a unit velocity vector. * (2) calculate missiles local Z axis from * plane's-y-axis CROSS missile's-unit-velocity-vector * (3) calculate missile's Y axis. */ if ((v = VMagnitude(&c->Cg)) < 1.0) { m->trihedral = c->trihedral; m->curRoll = c->curRoll; m->curPitch = c->curPitch; m->curHeading = c->curHeading; } else { mX = c->Cg; mX.x /= v; mX.y /= v; mX.z /= v; cY.x = c->trihedral.m[0][1]; cY.y = c->trihedral.m[1][1]; cY.z = c->trihedral.m[2][1]; VCrossProd(&mX, &cY, &mZ); VCrossProd(&mZ, &mX, &mY); m->trihedral.m[0][0] = mX.x; m->trihedral.m[1][0] = mX.y; m->trihedral.m[2][0] = mX.z; m->trihedral.m[0][1] = mY.x; m->trihedral.m[1][1] = mY.y; m->trihedral.m[2][1] = mY.z; m->trihedral.m[0][2] = mZ.x; m->trihedral.m[1][2] = mZ.y; m->trihedral.m[2][2] = mZ.z; pm_euler(m); } m->Cg = c->Cg; VTransform(&(c->cinfo->wStation[ind]), &(c->trihedral), &s1); VReverseTransform_(&s1, &c->XYZtoNED, &s); m->Sg.x = c->prevSg.x + units_FEETtoMETERS(s.x); m->Sg.y = c->prevSg.y + units_FEETtoMETERS(s.y); m->Sg.z = c->prevSg.z + units_FEETtoMETERS(s.z); earth_XYZToLatLonAlt(&m->Sg, &m->w); earth_generateWorldToLocalMatrix(&m->w, &m->XYZtoNED); m->armTimer = missile->armDelay; m->flags = FL_HAS_GYRO; m->createTime = curTime; /* * kludge */ m->curRadarTarget = c->curRadarTarget; /* * ACM missiles are DIS "tracked munitions", so we are * responsible for sending entity state PDU's for them */ { VPoint tmp; disLocation[0] = m->Sg.x; disLocation[1] = m->Sg.y; disLocation[2] = m->Sg.z; tmp.x = units_FEETtoMETERS(m->Cg.x); tmp.y = units_FEETtoMETERS(m->Cg.y); tmp.z = units_FEETtoMETERS(m->Cg.z); VReverseTransform_(&tmp, &m->XYZtoNED, &velocity); disVelocity[0] = velocity.x; disVelocity[1] = velocity.y; disVelocity[2] = velocity.z; disZeroVec[0] = 0.0; disZeroVec[1] = 0.0; disZeroVec[2] = 0.0; disOrientation[0] = m->curHeading; disOrientation[1] = m->curPitch; disOrientation[2] = m->curRoll; dis_if_entityEnter(c->force, m, &missile->entityType, &missile->altEntityType, disLocation, disVelocity, disZeroVec, disOrientation, disZeroVec, &m->disId); } m->update = missile_update; m->kill = missile_kill; return 0; } /** * Kill missile|cannon with possible target hit. * @param c Missile|cannon. * @param target Hit target, or NULL. * @param rpos Location of the explosion in the target frame (m). */ static void missile_targetHit(craft * missile, craft * target, VPoint * rpos) { VPoint worldVel; worldVel.x = units_FEETtoMETERS(missile->Cg.x); worldVel.y = units_FEETtoMETERS(missile->Cg.y); worldVel.z = units_FEETtoMETERS(missile->Cg.z); VReverseTransform_(&worldVel, &missile->XYZtoNED, &worldVel); dis_if_detonation(&missile->cinfo->entityType, ptbl[missile->owner].disId, target->disId, missile->disId, (double *) &missile->Sg, (double *) rpos, (double *) &worldVel); } static void missile_kill(craft * missile, char *reason) { /* Set a generic explosion effect: */ effects_new_explosion(&missile->Sg, &(VPoint){0.0, 0.0, 0.0}, 50.0, 15.0, 1.0); dis_if_entityExit(missile->disId); missile->type = CT_FREE; pm_hud_strings_free(missile); } /** * Returns true if the missile hit something. * @param m * @return True if the missile hit something. */ static int missile_lookForImpacts(craft *m) { craft *c; missile_CloserPoint p[manifest_MAXPLAYERS], *list, *q, *r, *rprev; VPoint mv, v, s0; double t, d, explosion_diameter_meters; int j; if (m->type != CT_MISSILE || m->armTimer > 0.0) return 0; // Missile vel. in world coords. (ft/s): VReverseTransform_(&m->Cg, &m->XYZtoNED, &mv); list = (missile_CloserPoint *) NULL; for (c = ptbl, j = 0; j < manifest_MAXPLAYERS; ++j, ++c) { if (c->type == CT_FREE) continue; /* * Reduce the relative motion of "c" to a the parametric system * of equations: * * x(t) = vx * t + s0x * y(t) = vy * t + s0y * z(t) = vz * t + s0z * * where x,y,z is the position of "c" relative to "m" in world coord. (m). * * We can then compute the time of perigee (closest pass) along with * the associated minimum distance. */ VPoint cv; VReverseTransform_(&c->Cg, &c->XYZtoNED, &cv); v.x = units_FEETtoMETERS(cv.x - mv.x); v.y = units_FEETtoMETERS(cv.y - mv.y); v.z = units_FEETtoMETERS(cv.z - mv.z); s0.x = c->Sg.x - m->Sg.x; s0.y = c->Sg.y - m->Sg.y; s0.z = c->Sg.z - m->Sg.z; /* * Compute time of minimum distance between the two objects. */ t = -(v.x * s0.x + v.y * s0.y + v.z * s0.z) / (v.x * v.x + v.y * v.y + v.z * v.z); if (mdebug) printf("perigee in %g seconds with player %d\n", t, j); /* * If the closest pass occurs within a given time interval, check for a hit. * * We'll build a linked list of all craft that this projectile may strike * during this period, arranged in ascending order by time of "perigee" * (closest pass). We'll then test for strikes. If a projectile misses * the first object, then it may have struck subsequent objects in the * list ... */ /* * One special case occurs when a target or missile's turn suddenly * changes the perigee time from positive to negative. If the missile * is within hitting range at t=0 and the time of perigee is negative, * then zap 'em. */ if (t < 0.0) { d = sqrt(s0.x * s0.x + s0.y * s0.y + s0.z * s0.z); if (isMissileHit(d, c)) { t = 0.0; } } if (t >= 0.0 && t <= 0.05) { q = &p[j]; // Position of the explosion (world coords., m): q->Sg = m->Sg; q->Sg.x += units_FEETtoMETERS(mv.x) * t; q->Sg.y += units_FEETtoMETERS(mv.y) * t; q->Sg.z += units_FEETtoMETERS(mv.z) * t; // Position of the explosion (target local frame, m): q->rpos.x = -v.x * t - s0.x; q->rpos.y = -v.y * t - s0.y; q->rpos.z = -v.z * t - s0.z; VTransform_(&q->rpos, &c->XYZtoNED, &q->rpos); VReverseTransform_(&q->rpos, &c->AXYZtoNED, &q->rpos); // Vel. of the missile (target local frame, m/s): VSetPoint(&q->rvel, -v.x, -v.y, -v.z); if (list == (missile_CloserPoint *) NULL) { q->next = list; list = q; } else if (list->time > t) { q->next = list; list = q; } else { for (rprev = list, r = list->next; r != (missile_CloserPoint *) NULL;) { if (r->time > t) break; rprev = r; r = r->next; } rprev->next = q; q->next = r; } q->time = t; q->c = c; q->min = VMagnitude(&q->rpos); } } /* * Now look for missile hits in the list of perigees. */ for (r = list; r != (missile_CloserPoint *) NULL; r = r->next){ if (isMissileHit(r->min, r->c)) { m->Sg = r->Sg; /* Set detonation point for missile_kill() */ missile_targetHit(m, r->c, &r->rpos); /* can only damage local player */ if (r->c->type != CT_DIS_PLANE){ if (damage_absorbDISDamage(r->c, &m->cinfo->entityType, 0, 0, r->min, VMagnitude(&r->rvel), &explosion_diameter_meters) == 0) { r->c->kill(r->c, "air-to-air missile"); } if( explosion_diameter_meters > 0 ) /* Something on the target has been damaged (this is NOT * the explosion of the missile): */ effects_new_explosion(&(r->Sg), &r->rvel, explosion_diameter_meters, 10.0, 3.0); } return 1; } } return 0; } /*ARGSUSED */ static int isMissileHit(double min, craft * c) { return (min < 15.0) ? 1 : 0; } #define IRMaxRange units_FEETtoMETERS(15.0 * units_NmToFeetFactor) static int isIRVisible(craft * m, craft * c, VPoint * t, double IRScanSlope) { VPoint relPos, tmp; int cstate, mstate; if (c->type == CT_FREE) return 0; /* * If the seeker is in clouds, or the target is not at the same level * (e.g seeker is above clouds, but target is below), then the target is * not IR visible. */ if ((mstate = inCloud(m)) == 1) { return 0; } if ((cstate = inCloud(c)) != mstate) { return 0; } VTransform(&c->prevSg, &m->XYZtoNED, &tmp); VReverseTransform_(&tmp, &m->trihedral, t); if (sqrt(t->x * t->x + t->y * t->y + t->z * t->z) > IRMaxRange) return 0; if (t->x <= 0.0) return 0; relPos.z = t->z / (t->x * IRScanSlope); relPos.y = t->y / (t->x * IRScanSlope); return (sqrt(relPos.z * relPos.z + relPos.y * relPos.y) > 1.0) ? 0 : 1; } int missile_getIRTarget(craft * c, VPoint * t, double scanSlope) { int i, n; craft *p; VPoint tNew, tMin; double m1, min; if (c->curRadarTarget != -1 && c->type != CT_FREE && isIRVisible(c, &ptbl[c->curRadarTarget], t, scanSlope)) return c->curRadarTarget; /* * Look for a target. Designate the closest one as a new target. */ min = 1000000.0; n = -1; for (i = 0, p = ptbl; i < manifest_MAXPLAYERS; ++i, ++p) { if (p == c) continue; if (p->type != CT_FREE) if (isIRVisible(c, p, &tNew, scanSlope)) { m1 = VMagnitude(&tNew); if (m1 < min) { n = i; min = m1; tMin = tNew; } } } *t = tMin; return n; } /* * Track target using proportional navigation guidance (N = 4). */ #define AIM9SLOPE 0.57735 static void missile_trackTarget(craft * c) { VMatrix mtx, mtx1; VPoint t, t1, v, vrel, zeroVec = {0,0,0}; double h, maxTurn, omegap, omegay; double hs; double deltaRoll, deltaPitch, deltaYaw; craft *target; /* * Now let's get to target tracking; the missile won't start tracking until * 0.60 seconds has elapsed. Then, if we don't already have a target * designated, get one. */ if (curTime - c->createTime < 0.60) { deltaPitch = 0.0; deltaYaw = 0.0; goto change; } else if ((c->curRadarTarget = missile_getIRTarget(c, &t, AIM9SLOPE)) == -1) { /* * Not target; missile goes ballistic */ deltaPitch = 0.0; deltaYaw = 0.0; goto change; #ifdef manifest_FLIGHTDEBUG if (mdebug) printf("Missile elects to self-destruct\n"); #endif effects_new_explosion(&(c->Sg), &zeroVec, 5.0, 10.0, 3.0); missile_kill(c, "lost IR target"); return; } /* * We'll steer towards the target at a rate proportional to the * rate of change of the target's position in the missile's XZ (pitch) * and XY (yaw) planes. */ target = &ptbl[c->curRadarTarget]; v.x = target->Cg.x - c->Cg.x; v.y = target->Cg.y - c->Cg.y; v.z = target->Cg.z - c->Cg.z; t.x = units_METERStoFEET(t.x); t.y = units_METERStoFEET(t.y); t.z = units_METERStoFEET(t.z); VReverseTransform_( &v, &c->trihedral, &vrel ); hs = t.x * t.x + t.y * t.y; omegay = (vrel.y * t.x - vrel.x * t.y) / hs; omegap = (vrel.z * hs - t.z * (vrel.x * t.x + vrel.y * t.y)) / (sqrt(hs) * (hs + t.z * t.z)); deltaPitch = omegap * 4.0 * deltaT; deltaYaw = omegay * 4.0 * deltaT; h = sqrt( deltaPitch * deltaPitch + deltaYaw * deltaYaw ); /* * We'll constrain missile turns to about 20 degree/second unless it's velocity * would make that greater than a 25g load factor. */ if ( c->VT > 0.0 ) { maxTurn = (units_earth_g / c->VT) * sqrt( 25.0 * 25.0 - 1.0 ); } else { maxTurn = 0.0; } if (maxTurn > units_DEGtoRAD(20.0)) { maxTurn = units_DEGtoRAD(20.0); } maxTurn *= deltaT; #ifdef manifest_FLIGHTDEBUG if (mdebug) printf("\nturn rate = %g; maxTurn = %g\n", h, maxTurn); #endif if (h > maxTurn) { deltaPitch *= maxTurn / h; deltaYaw *= maxTurn / h; } /* * Re-orient the missile and velocity vector. */ change: deltaRoll = 0.0; #ifdef manifest_FLIGHTDEBUG if (mdebug) { printf("Missile changes: pitch/yaw: %g %g (deg).\n", units_RADtoDEG(deltaPitch), units_RADtoDEG(deltaYaw)); printf("position [%g, %g, %g]\n", t.x, t.y, t.z); printf("target pitch/yaw rates: %g, %g (deg/sec)\n", units_RADtoDEG(omegap), units_RADtoDEG(omegay)); } #endif VEulerToMatrix(deltaRoll, -deltaPitch, deltaYaw, &mtx); VReverseTransform_(&c->Cg, &c->trihedral, &t); VTransform(&t, &mtx, &t1); VTransform(&t1, &c->trihedral, &c->Cg); VMatrixMultByRank(&mtx, &c->trihedral, &mtx1, 3); c->trihedral = mtx1; pm_euler(c); }acm-6.0_20200416/src/acm/instruments.c0000644000000000000000000011220113172241321015652 0ustar rootroot/* * acm : an aerial combat simulator for X * Classic instruments module * Copyright (C) 2007 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include #include #include #include "../util/memory.h" #include "../util/units.h" #include "../V/Vlibmath.h" #include "aps.h" #include "draw.h" #include "pm.h" #include "vpath.h" #define instruments_IMPORT #include "instruments.h" /** * The viewer object associated to every aircraft contains a pointer * to an instance of this struct, giving the state of the classic * instruments. */ typedef struct instruments_Type { /** * Disposed structs are linked in a recycle pool; set to NULL for * currently used structs. */ struct instruments_Type *next; /** * If classic instruments panel is enabled, then every instrument * needs to be updated. */ _BOOL enabled; /** Anemometer: cosine of the stall angle. */ double cos_alpha_stall; /** Attitude: last update time (s). */ double attitude_erection_upd; /** Attitude: pilot's pitch offset; default zero (RAD). */ double attitude_pitch_offset; /** Attitude: normalized gyro orientation (NED reference). */ VPoint attitude_gyro; /** Attitude current bank. */ double attitude_bank; /** Attitude current pitch. */ double attitude_pitch; /** Altimeter: pressure offset in [2800,3100] inHg*100; default 2992. */ int altimeter_p0; /** VSI: last update time (s). */ double vsi_last_upd; /** VSI: last computed vertical speed (ft/min). */ double vsi_last_vs; /** Timer: current operation mode (0=off, 1=run, 2=stop). */ int timer_op; /** Timer: displayed value in 'stop' mode (s). */ int timer_freezed; /** Timer: time offset relative to the ACM clock in mode 'run' and 'stop' * (s). */ double timer_offset; } instruments_Type; /** * Linked list of recycled instruments_data structures. */ static instruments_Type *free_list = NULL; /** Maps a viewer into instruments_data pointer. */ #define INST(u) ((instruments_Type *)(u->inst)) /** 'Blinking' display toggle. */ static _BOOL blink = FALSE; static double blink_toggle_time = 0.0; static Alib_Pixel black_color, white_color, attitude_bank_sky_color, attitude_bank_ground_color, attitude_pitch_sky_color, attitude_pitch_ground_color; static vpath_Type * ball_ladder_vpath = NULL; static vpath_Type *anemometer_vpath = NULL; /** Bank scale ring outer radius (in 1/1000 of the available slot half width). */ #define ATTITUDE_BANK_OUTER_RADIUS 1000 /** Bank scale ring inner radius (in 1/1000 of the available slot half width). */ #define ATTITUDE_BANK_INNER_RADIUS 700 /** Bank scale ring, upper half (sky) on a circle of radius 1000. */ static Alib_Polygon *attitude_bank_half_upper_ring; /** Bank scale ring, lower half (ground) on a circle of radius 1000. */ static Alib_Polygon *attitude_bank_half_lower_ring; /** Bank scale ring, zero bank tick mark. */ static Alib_Polygon *attitude_bank_zero_tick_mark; /** Bank needle. */ static Alib_Polygon *attitude_bank_needle; /** Pitch needle. */ static Alib_Polygon *attitude_pitch_needle; static int inited; static void instruments_cleanup() { instruments_Type *p; while( free_list != NULL ){ p = free_list; free_list = free_list->next; memory_dispose(p); } memory_dispose(ball_ladder_vpath); ball_ladder_vpath = NULL; memory_dispose(anemometer_vpath); anemometer_vpath = NULL; memory_dispose(attitude_bank_half_upper_ring); memory_dispose(attitude_bank_half_lower_ring); memory_dispose(attitude_bank_zero_tick_mark); memory_dispose(attitude_bank_needle); memory_dispose(attitude_pitch_needle); inited = 0; } /** * Initializes this module. */ static void instruments_init() { int i; if( inited ) return; inited = 1; memory_registerCleanup(instruments_cleanup); black_color = gui_getColorIndexString(NULL, "#000000"); white_color = gui_getColorIndexString(NULL, "#ffffff"); attitude_bank_sky_color = gui_getColorIndexString(NULL, "#0083cb"); attitude_bank_ground_color = gui_getColorIndexString(NULL, "#6c5735"); attitude_pitch_sky_color = gui_getColorIndexString(NULL, "#0074b3"); attitude_pitch_ground_color = gui_getColorIndexString(NULL, "#5f4c2f"); /* * Attitude's polygons are drawn on a circle of radius * ATTITUDE_BANK_OUTER_RADIUS units. */ // Create attitude_bank_half_upper_ring: attitude_bank_half_upper_ring = Alib_Polygon_new(); int angle_deg; for(angle_deg = 0; angle_deg <= 180; angle_deg += 10){ double a = units_DEGtoRAD(angle_deg); Alib_Polygon_addPointXY(attitude_bank_half_upper_ring, ATTITUDE_BANK_OUTER_RADIUS * cos(a), - ATTITUDE_BANK_OUTER_RADIUS * sin(a)); } Alib_Polygon_addPointXY(attitude_bank_half_upper_ring, -ATTITUDE_BANK_INNER_RADIUS, 0); for(angle_deg = 170; angle_deg >= 0; angle_deg -= 10){ double a = units_DEGtoRAD(angle_deg); Alib_Polygon_addPointXY(attitude_bank_half_upper_ring, ATTITUDE_BANK_INNER_RADIUS * cos(a), - ATTITUDE_BANK_INNER_RADIUS * sin(a)); } // Create attitude_bank_half_lower_ring: attitude_bank_half_lower_ring = Alib_Polygon_clone(attitude_bank_half_upper_ring); for(i = attitude_bank_half_lower_ring->npts - 1; i >= 0; i--) attitude_bank_half_lower_ring->pts[i].y *= -1; // Create zero bank tick mark: attitude_bank_zero_tick_mark = Alib_Polygon_new(); Alib_Polygon_addPointXY(attitude_bank_zero_tick_mark, 0, -ATTITUDE_BANK_INNER_RADIUS); Alib_Polygon_addPointXY(attitude_bank_zero_tick_mark, -100, -ATTITUDE_BANK_OUTER_RADIUS); Alib_Polygon_addPointXY(attitude_bank_zero_tick_mark, 100, -ATTITUDE_BANK_OUTER_RADIUS); // Create bank needle: attitude_bank_needle = Alib_Polygon_new(); Alib_Polygon_addPointXY(attitude_bank_needle, -100, -ATTITUDE_BANK_INNER_RADIUS + 200); Alib_Polygon_addPointXY(attitude_bank_needle, 100, -ATTITUDE_BANK_INNER_RADIUS + 200); Alib_Polygon_addPointXY(attitude_bank_needle, 0, -ATTITUDE_BANK_INNER_RADIUS); // Create pitch needle: //Alib_Point poly[] = { {0, 200}, {170, 50}, {500, 50}, {500, 0}, // {140, 0}, {0, 130}, {-140, 0}, {-500, 0}, {-500, 50}, {-170, 50} }; Alib_Point poly[] = { {0,80}, {500, 200}, {0, 0}, {-500, 200} }; attitude_pitch_needle = Alib_Polygon_new(); i = sizeof(poly) / sizeof(Alib_Point) - 1; for( ; i >= 0; i--) Alib_Polygon_addPoint(attitude_pitch_needle, &poly[i]); } /** * Draws a needle rotating counter-clock wise around (xo,yo), len pixels long. */ static void drawNeedle(Alib_Window *w, int xo, int yo, double angle, double len, Alib_Pixel color) { static Alib_Point pts[] = { {200, -70}, {1000, -5}, {1000, 5}, {200, 70} }; Alib_Matrix m; Alib_MatrixIdentity(&m); Alib_MatrixRotate(&m, angle); Alib_MatrixScale(&m, 0.001 * len); Alib_MatrixTranslate(&m, xo, yo); Alib_fillPolygonWithMatrix(w, pts, 4, &m, color); } /** * Draws the turn and slip indicator. * @param u Viewer instance of the aircraft. * @param x0 Horizontal position of the center of the dial. * @param y0 Vertical position of the center of the dial. * @param width Width and height of the dial. */ static void instruments_turnslip_draw(viewer *u, double xo, double yo, double width) { double radius, x1, y1, r, co, si, a, r1, r2, l, m; draw_Type *dd; int j; radius = 0.48 * width; dd = draw_new(); draw_circle(dd, xo, yo, radius); /* Yaw rate: */ x1 = xo; y1 = yo + 0.25 * radius; r = 0.90 * radius; for( j=-30; j<= 30; j+=15 ){ co = cos( units_DEGtoRAD(j) ); si = sin( units_DEGtoRAD(j) ); draw_segment(dd, x1 + r*si, y1 - r*co, x1 + radius*si, y1 - radius*co); } /* This instrument measures the rotational speed around the craft z axis: */ a = u->c->r; a = fmin(a, units_DEGtoRAD(5.0)); a = fmax(a, -units_DEGtoRAD(5.0)); //draw_pointer(dd, x1, y1, -M_PI/2.0 + a*30.0/3.0, 0.87*radius); drawNeedle(u->w, x1, y1, M_PI/2.0 - a*30.0/3.0, 0.87*radius, white_color); /* Slip indicator: */ x1 = xo; y1 = yo - 1.5*radius; /* curved glass: */ r1 = 2.0*radius; r2 = 2.25*radius; l = units_DEGtoRAD(15.0); draw_arc(dd, x1, y1, r1, units_DEGtoRAD(90.0) - l, units_DEGtoRAD(90.0) + l); draw_arc(dd, x1, y1, r2, units_DEGtoRAD(90.0) - l, units_DEGtoRAD(90.0) + l); co = cos(l); si = sin(l); draw_segment(dd, x1 - r1*si, y1 + r1*co, x1 - r2*si, y1 + r2*co); draw_segment(dd, x1 + r1*si, y1 + r1*co, x1 + r2*si, y1 + r2*co); /* center marks of the curved glass: */ co = cos(units_DEGtoRAD(4.0)); si = sin(units_DEGtoRAD(4.0)); draw_segment(dd, x1 - r1*si, y1 + r1*co, x1 - r2*si, y1 + r2*co); draw_segment(dd, x1 + r1*si, y1 + r1*co, x1 + r2*si, y1 + r2*co); /* ball: */ a = atan2(-u->c->G.y, -u->c->G.z); /* max angular displacement of the ball (approximated for little angles): */ m = l - (r2-r1)/(r1+r2); a = fmin(a, m); a = fmax(a, -m); co = cos(a); si = sin(a); draw_circle(dd, x1 + (r1+r2)/2.0*si, y1 + (r1+r2)/2.0*co, 0.95*(r2-r1)/2.0); draw_stroke(dd, u->v, white_color); draw_free(dd); } /* ANEMOMETER ========== */ #define ANEMOMETER_MAX_VEL 450.0 #define ANEMOMETER_MAX_ANGLE units_DEGtoRAD(320.0) #define ANEMOMETER_LINEARITY 0.8 #define ANEMOMETER_OFFSET 30.0 static void instruments_anemometer_init(viewer * u) { instruments_Type *d = INST(u); craftType *p = u->c->cinfo; d->cos_alpha_stall = cos(p->alpha_stall); } static double map_vel_to_angle(double vel) { double a; static double k = 0.0; if( k == 0.0 ) k = 1.0 / (sqrt(ANEMOMETER_MAX_VEL - ANEMOMETER_OFFSET + ANEMOMETER_LINEARITY*ANEMOMETER_LINEARITY) - ANEMOMETER_LINEARITY); vel = fmax(vel - ANEMOMETER_OFFSET, 0.0); a = k*(sqrt(vel + ANEMOMETER_LINEARITY*ANEMOMETER_LINEARITY) - ANEMOMETER_LINEARITY); a = fmin(a, 1.0); return a * ANEMOMETER_MAX_ANGLE; } static void instruments_draw_bold_arc(draw_Type *dd, double xo, double yo, double r, double a1, double a2) { draw_arc(dd, xo, yo, r, a1, a2); draw_arc(dd, xo, yo, r - 1.0, a1, a2); draw_arc(dd, xo, yo, r + 1.0, a1, a2); } static vpath_Type * build_anemometer_vpath() { int i, j, n, l; double radius, r, r1, r2, r3, fh, fw, si, co, vel, a; vpath_Type *p; double v[200]; char buf[10]; VMatrix m; p = vpath_new(); radius = 1.0; /* Build array v[] of the velocity to display */ n = 0; /* add speeds from 40 up to 150 kt step 10: */ for( i = 40; i <= 250; i+= 10 ) v[n++] = (double) i; /* add speeds from 200 up to ANEMOMETER_MAX_VEL kt step 50: */ for( i = 200; i <= ANEMOMETER_MAX_VEL; i += 10 ) v[n++] = (double) i; v[n++] = -1.0; i = 0; j = 0; r = 0.83 * radius; /* labels center radius */ r1 = 0.60 * radius; /* nock - inner radius */ r2 = 0.65 * radius; /* short nock - outer radius */ r3 = 0.72 * radius; /* long nock - outer radius */ while( v[j] >= 0.0 ){ vel = v[j]; a = map_vel_to_angle(vel); co = cos(a); si = sin(a); if( (vel <= 120.0 && (int) vel % 20 == 0) || ((int) vel % 50 == 0) ){ sprintf(buf, "%d", (int) vel); l = strlen(buf); VIdentMatrix(&m); fh = 0.10*radius; fw = 2.0 * fh / l; /* same width (fw*l) for any length (l) */ VScaleMatrix(&m, fw, fh, 1.0); VTranslate(&m, r*si - 0.5*fw*l, - r*co + 0.5*fh, 0.0); vpath_draw_string(p, buf, l, &m); vpath_moveTo(p, &(VPoint){r1*si, - r1*co, 0.0}); vpath_lineTo(p, &(VPoint){r3*si, - r3*co, 0.0}); } else { vpath_moveTo(p, &(VPoint){r1*si, - r1*co, 0.0}); vpath_lineTo(p, &(VPoint){r2*si, - r2*co, 0.0}); } j++; } /* "KT": */ strcpy(buf, "KT"); l = strlen(buf); fh = 0.15 * radius; fw = fh; VIdentMatrix(&m); VScaleMatrix(&m, fw, fh, 1.0); VTranslate(&m, -0.5*fw*l, 0.3*radius + 0.5*fh, 0.0); vpath_draw_string(p, buf, l, &m); return p; } static void instruments_anemometer_draw(viewer *u, double xo, double yo, double width) { double radius, a, b, r1, r2, ias; draw_Type *dd; VMatrix m; radius = 0.48 * width; dd = draw_new(); draw_circle(dd, xo, yo, radius); double cos_alpha_stall = INST(u)->cos_alpha_stall; /* Speed limit arcs */ craftType *p = u->c->cinfo; r1 = 0.55 * radius; r2 = 0.50 * radius; // White arc: if( p->Vs0 > 0.0 && p->Vfe > 0.0 ){ instruments_draw_bold_arc(dd, xo, yo, r1, map_vel_to_angle(p->Vs0 * cos_alpha_stall) - 0.5*M_PI, map_vel_to_angle(p->Vfe) - 0.5*M_PI); } if( p->Vs0 > 0.0 && p->Vs1 > 0.0 ){ instruments_draw_bold_arc(dd, xo, yo, r2, map_vel_to_angle(p->Vs0 * cos_alpha_stall) - 0.5*M_PI, map_vel_to_angle(p->Vs1 * cos_alpha_stall) - 0.5*M_PI); } // Green arc: if( p->Vs1 > 0.0 && p->Vfe > 0.0 && p->Vno > 0.0 ){ draw_Type *green = draw_new(); b = map_vel_to_angle(p->Vno) - 0.5*M_PI; instruments_draw_bold_arc(green, xo, yo, r1, map_vel_to_angle(p->Vfe) - 0.5*M_PI, b); instruments_draw_bold_arc(green, xo, yo, r2, map_vel_to_angle(p->Vs1 * cos_alpha_stall) - 0.5*M_PI, b); draw_stroke(green, u->v, radarColor); draw_free(green); } // Yellow arc: if( p->Vno > 0.0 && p->Vne > 0.0 ){ draw_Type *yellow = draw_new(); a = map_vel_to_angle(p->Vno) - 0.5*M_PI; b = map_vel_to_angle(p->Vne) - 0.5*M_PI; instruments_draw_bold_arc(yellow, xo, yo, r1, a, b); instruments_draw_bold_arc(yellow, xo, yo, r2, a, b); draw_stroke(yellow, u->v, yellowColor); draw_free(yellow); } // Red line (actually here we draw a short arc): if( p->Vne > 0.0 ){ a = map_vel_to_angle(p->Vne); draw_Type *red = draw_new(); instruments_draw_bold_arc(red, xo, yo, r1, a - 0.5*M_PI, a + units_DEGtoRAD(3) - 0.5*M_PI); instruments_draw_bold_arc(red, xo, yo, r2, a - 0.5*M_PI, a + units_DEGtoRAD(3) - 0.5*M_PI); draw_stroke(red, u->v, redColor); draw_free(red); } if( anemometer_vpath == NULL ) anemometer_vpath = build_anemometer_vpath(); VIdentMatrix(&m); VScaleMatrix(&m, radius, radius, radius); VTranslate(&m, xo, yo, -1.0); vpath_stroke(anemometer_vpath, &m, u->w, white_color); /* Mach number: */ char s[5]; snprintf(s, sizeof(s), "%.2f", u->c->mach); double fh = 0.12*radius; double fw = VFontWidthPixels(u->v, (int) (fh+0.5)); VDrawStrokeString(u->v, (int) (xo - 0.5 * fw * strlen(s) + 0.5), (int) (yo - 0.35*radius + 0.5), s, strlen(s), (int)(fh+0.5), white_color); /* Draw pointer: */ ias = units_FPStoKT( u->c->IAS ); if( ias < ANEMOMETER_OFFSET ) ias = ANEMOMETER_OFFSET; a = map_vel_to_angle( ias ); //draw_pointer(dd, xo, yo, a - M_PI/2.0, 0.60 * radius); draw_stroke(dd, u->v, white_color); draw_free(dd); drawNeedle(u->w, xo, yo, M_PI/2.0 - a, 0.60 * radius, white_color); } /* ATTITUDE INDICATOR ================== */ #define ATTITUDE_MAX_PITCH_OFFSET units_DEGtoRAD(10.0) #define ATTITUDE_MAX_PITCH units_DEGtoRAD(70.0) #define ATTITUDE_MAX_BANK units_DEGtoRAD(70.0) #define ATTITUDE_UPDATE_PERIOD 0.2 static void instruments_attitude_update(viewer *u) { VPoint *gyro, g; double m, k, dt; /* Erection system: the gyro axis (smoothly) follows the local vertical: */ dt = curTime - INST(u)->attitude_erection_upd; if( dt > ATTITUDE_UPDATE_PERIOD ){ INST(u)->attitude_erection_upd = curTime; gyro = &INST(u)->attitude_gyro; VTransform_(&u->c->G, &u->c->trihedral, &g); m = VMagnitude(&g); if( m > 0.98 && m < 1.02 /* erection cut-out */){ k = 0.005 * dt / m; g.x = gyro->x + k * g.x; g.y = gyro->y + k * g.y; g.z = gyro->z + k * g.z; m = VMagnitude(&g); if( m > 1e-6 ){ k = 1.0 / m; gyro->x = k * g.x; gyro->y = k * g.y; gyro->z = k * g.z; } } } /* Compute gyro angles of bank and pitch: */ VReverseTransform_(&INST(u)->attitude_gyro, &u->c->trihedral, &g); double bank = atan2(-g.y, -g.z); /* positive turning right */ double pitch = atan2(g.x, sqrt(g.y*g.y + g.z*g.z)); /* positive pulling up */ int tilt = FALSE; if( bank > ATTITUDE_MAX_BANK ){ tilt = TRUE; bank = ATTITUDE_MAX_BANK; } else if( bank < -ATTITUDE_MAX_BANK ){ tilt = TRUE; bank = -ATTITUDE_MAX_BANK; } if( pitch > ATTITUDE_MAX_PITCH ){ tilt = TRUE; pitch = ATTITUDE_MAX_PITCH; } else if( pitch < -ATTITUDE_MAX_PITCH ){ tilt = TRUE; pitch = -ATTITUDE_MAX_PITCH; } if( tilt ){ g.x = sin(pitch) * cos(bank); g.y = -sin(bank); g.z = -cos(pitch) * cos(bank); VTransform_(&g, &u->c->trihedral, &INST(u)->attitude_gyro); } INST(u)->attitude_bank = bank; INST(u)->attitude_pitch = pitch; } static void instruments_attitude_init(viewer *u) { INST(u)->attitude_pitch_offset = 0.0; /* Init gyro randomly oriented: */ INST(u)->attitude_gyro.x = 0.2; INST(u)->attitude_gyro.y = 0.2; INST(u)->attitude_gyro.z = -0.959; INST(u)->attitude_erection_upd = curTime; // Initialize bank and pitch angles: instruments_attitude_update(u); } void instruments_attitude_adjust_pitch(viewer * u, double delta) { if( u->inst == NULL ) return; INST(u)->attitude_pitch_offset += delta; INST(u)->attitude_pitch_offset = fmin(INST(u)->attitude_pitch_offset, ATTITUDE_MAX_PITCH_OFFSET); INST(u)->attitude_pitch_offset = fmax(INST(u)->attitude_pitch_offset, -ATTITUDE_MAX_PITCH_OFFSET); } void instruments_attitude_reset(viewer * u) { VPoint g; if( u->inst == NULL ) return; g.x = 0.0; g.y = 0.0; g.z = -1.0; VTransform_(&g, &u->c->trihedral, &INST(u)->attitude_gyro); // Initialize bank and pitch angles: instruments_attitude_update(u); } /** Draw arc on attitude ball. The arc starts from (pitch1,yaw1) and ends on (pitch2,yaw2). Longer arcs are split in two or more segments. */ static void build_ball_draw_arc( double pitch1, double yaw1, double pitch2, double yaw2) { int n, i; VPoint a, b, c; double m; pitch1 = units_DEGtoRAD(pitch1); yaw1 = units_DEGtoRAD(yaw1); pitch2 = units_DEGtoRAD(pitch2); yaw2 = units_DEGtoRAD(yaw2); n = (int) (fmax( fabs(pitch2-pitch1), fabs(yaw2-yaw1) ) / units_DEGtoRAD(5) + 0.5); if( n < 1 ) n = 1; VSetPoint(&a, cos(pitch1)*sin(yaw1), -sin(pitch1), -cos(pitch1)*cos(yaw1)); VSetPoint(&b, cos(pitch2)*sin(yaw2), -sin(pitch2), -cos(pitch2)*cos(yaw2)); vpath_moveTo(ball_ladder_vpath, &a); for( i=1; i<=n; i++ ){ VSetPoint(&c, a.x + (double)i/n*(b.x-a.x), a.y - (double)i/n*(b.y-a.y), a.z + (double)i/n*(b.z-a.z)); m = VMagnitude(&c); VSetPoint(&c, c.x/m, c.y/m, c.z/m); vpath_lineTo(ball_ladder_vpath, &c); } } static void build_ball_draw_str(int pitch, int yaw) { VMatrix m; double fh, fw; char s[10]; int s_len; sprintf(s, "%d", abs(pitch)); s_len = strlen(s); fh = 0.05; fw = 0.05; VIdentMatrix(&m); VScaleMatrix(&m, fw, fh, 1.0); VTranslate(&m, -s_len*fw/2, fh/2, -1.0); VRotate(&m, YRotation, units_DEGtoRAD(yaw)); VRotate(&m, XRotation, units_DEGtoRAD(-pitch)); vpath_draw_string(ball_ladder_vpath, s, s_len, &m); VIdentMatrix(&m); VScaleMatrix(&m, fw, fh, 1.0); VTranslate(&m, -s_len*fw/2, fh/2, -1.0); VRotate(&m, YRotation, units_DEGtoRAD(-yaw)); VRotate(&m, XRotation, units_DEGtoRAD(-pitch)); vpath_draw_string(ball_ladder_vpath, s, s_len, &m); } static void build_ball_ladder() { ball_ladder_vpath = vpath_new(); /* Pitch ladder: */ build_ball_draw_arc( 30,-15, 30,+15); build_ball_draw_str( 30, 20 ); build_ball_draw_arc( 25, -3, 25, +3); build_ball_draw_arc( 20,-10, 20,+10); build_ball_draw_str( 20, 15 ); build_ball_draw_arc( 15, -3, 15, +3); build_ball_draw_arc( 10, -5, 10, +5); build_ball_draw_str( 10, 10 ); build_ball_draw_arc( 5, -3, 5, +3); build_ball_draw_arc( 0,-45, 0,+45); build_ball_draw_arc( -5, -3, -5, +3); build_ball_draw_arc(-10, -5, -10, +5); build_ball_draw_str(-10, 10 ); build_ball_draw_arc(-15, -3, -15, +3); build_ball_draw_arc(-20,-10, -20,+10); build_ball_draw_str(-20, 15 ); build_ball_draw_arc(-25, -3, -25, +3); build_ball_draw_arc(-30,-15, -30,+15); build_ball_draw_str(-30, 20 ); } #define ATTITUDE_EDGES_MAX_NUMBER 200 static int attitude_pitch_dome_edges_number; static VPoint attitude_pitch_dome_sky_edges[200]; static VPoint attitude_pitch_dome_ground_edges[200]; static void build_attitude_pitch_dome_background() { int i, lon_deg, lat_deg; VPoint p; double t, lon_rad, lat_rad; int lon_step = 10; int lon_max = 40; int lat_step = 10; int lat_max = 40; i = 0; /* * We are drawing the edges of the "north" half doom. * "x" goes right, "y" goes down, "z" goes forward. * This doom is then parallel projected to the xy plane of the screen, giving * a nice 3D effect while it rotates. * * Add points of the horizon line: */ lat_rad = 0; for(lon_deg = -lon_max; lon_deg <= lon_max; lon_deg += lon_step){ lon_rad = units_DEGtoRAD(lon_deg); t = cos(lat_rad); p = (VPoint) {t * sin(lon_rad), -sin(lat_rad), -t * cos(lon_rad)}; attitude_pitch_dome_sky_edges[i] = p; p.y = -p.y; attitude_pitch_dome_ground_edges[i] = p; i++; } // Add points to the right ("meridian" at lon 30E): lon_deg = lon_max; lon_rad = units_DEGtoRAD(lon_deg); for(lat_deg = lat_step; lat_deg <= lat_max; lat_deg += lat_step){ lat_rad = units_DEGtoRAD(lat_deg); t = cos(lat_rad); p = (VPoint) {t * sin(lon_rad), -sin(lat_rad), -t * cos(lon_rad)}; attitude_pitch_dome_sky_edges[i] = p; p.y = -p.y; attitude_pitch_dome_ground_edges[i] = p; i++; } // Add points to the upper edge ("parallel" at lat 30N): lat_deg = lat_max; lat_rad = units_DEGtoRAD(lat_deg); for(lon_deg = lon_max - lon_step; lon_deg >= -lon_max; lon_deg -= lon_step){ lon_rad = units_DEGtoRAD(lon_deg); t = cos(lat_rad); p = (VPoint) {t * sin(lon_rad), -sin(lat_rad), -t * cos(lon_rad)}; attitude_pitch_dome_sky_edges[i] = p; p.y = -p.y; attitude_pitch_dome_ground_edges[i] = p; i++; } // Add points to the left edge ("meridian" at lon 30W): lon_deg = -lon_max; lon_rad = units_DEGtoRAD(lon_deg); for(lat_deg = lat_max - lat_step; lat_deg >= lat_step; lat_deg -= lat_step){ lat_rad = units_DEGtoRAD(lat_deg); t = cos(lat_rad); p = (VPoint) {t * sin(lon_rad), -sin(lat_rad), -t * cos(lon_rad)}; attitude_pitch_dome_sky_edges[i] = p; p.y = -p.y; attitude_pitch_dome_ground_edges[i] = p; i++; } assert( i < ATTITUDE_EDGES_MAX_NUMBER ); attitude_pitch_dome_edges_number = i; } /** * Draw the pitch scale dome background. * @param u * @param R Maps the points of a unit radius dome to the screen. */ static void instruments_attitude_draw_pitch_dome_background(viewer * u, VMatrix *R) { if( attitude_pitch_dome_edges_number == 0 ) build_attitude_pitch_dome_background(); Alib_Point sky[ATTITUDE_EDGES_MAX_NUMBER], ground[ATTITUDE_EDGES_MAX_NUMBER]; int i; for( i = attitude_pitch_dome_edges_number - 1; i >= 0; i-- ){ VPoint p; VTransform(&attitude_pitch_dome_sky_edges[i], R, &p); sky[i].x = p.x + 0.5; sky[i].y = p.y + 0.5; VTransform(&attitude_pitch_dome_ground_edges[i], R, &p); ground[i].x = p.x + 0.5; ground[i].y = p.y + 0.5; } Alib_fillPolygon(u->w, sky, attitude_pitch_dome_edges_number, attitude_pitch_sky_color); Alib_fillPolygon(u->w, ground, attitude_pitch_dome_edges_number, attitude_pitch_ground_color); } static void instruments_attitude_draw(viewer * u, double xo, double yo, double width) { Alib_Window *w; int j; double bank, pitch, radius, a, r, co, si; VMatrix R; Alib_Matrix bankMatrix; w = u->v->w; radius = 0.48 * width; bank = INST(u)->attitude_bank; pitch = INST(u)->attitude_pitch; Alib_setClipRect(w, &u->attitude); /* Draw pitch scale. First, build a rotational matrix acting on vectors of the screen frame: x axis pointing right, y axis down, z forward: */ r = 0.60 * width; /* radius of the rotating pitch scale dome */ VIdentMatrix(&R); VRotate(&R, XRotation, pitch); VRotate(&R, ZRotation, -bank); VScaleMatrix(&R, r, r, r); VTranslate(&R, xo, yo, 0.0); Alib_setClipRect(u->w, &u->attitude); Alib_Rect rect = u->attitude; Alib_expandRect(&rect, -0.35*radius, -0.35*radius); Alib_setClipRect(u->w, &rect); instruments_attitude_draw_pitch_dome_background(u, &R); if( ball_ladder_vpath == NULL ) build_ball_ladder(); vpath_stroke(ball_ladder_vpath, &R, w, white_color); Alib_setClipRect(u->w, &u->attitude); /* * Draw bank scale background. Upper half is blue, lower half is brown. */ r = radius; Alib_MatrixIdentity(&bankMatrix); Alib_MatrixRotate(&bankMatrix, bank); Alib_MatrixScale(&bankMatrix, 0.001 * r); Alib_MatrixTranslate(&bankMatrix, xo, yo); Alib_fillPolygonWithMatrix(u->w, attitude_bank_half_upper_ring->pts, attitude_bank_half_upper_ring->npts, &bankMatrix, attitude_bank_sky_color); Alib_fillPolygonWithMatrix(u->w, attitude_bank_half_lower_ring->pts, attitude_bank_half_lower_ring->npts, &bankMatrix, attitude_bank_ground_color); /* Bank scale tick marks: */ // Zero bank tick mark: Alib_fillPolygonWithMatrix(u->w, attitude_bank_zero_tick_mark->pts, attitude_bank_zero_tick_mark->npts, &bankMatrix, white_color); // 10, 20, 30, 60 and 90 DEG bank tick marks: for( j = 10; j <= 90; j+=10 ){ if( !( j <= 30 || (j % 30) == 0 ) ) continue; a = units_DEGtoRAD(j); co = cos(a); si = sin(a); int outer; if( j % 30 == 0 ) outer = ATTITUDE_BANK_OUTER_RADIUS; // major tick outer radius else outer = (ATTITUDE_BANK_OUTER_RADIUS + ATTITUDE_BANK_INNER_RADIUS) / 2; // minor tick outer radius // bank left tick: Alib_Point f = (Alib_Point) {ATTITUDE_BANK_INNER_RADIUS * si, -ATTITUDE_BANK_INNER_RADIUS * co}; Alib_Point g = (Alib_Point) {outer * si, -outer * co}; Alib_MatrixTransformPoint(&f, &bankMatrix, &f); Alib_MatrixTransformPoint(&g, &bankMatrix, &g); Alib_drawLine(u->w, f.x, f.y, g.x, g.y, white_color); // bank right tick: f = (Alib_Point) {-ATTITUDE_BANK_INNER_RADIUS * si, -ATTITUDE_BANK_INNER_RADIUS * co}; g = (Alib_Point) {-outer * si, -outer * co}; Alib_MatrixTransformPoint(&f, &bankMatrix, &f); Alib_MatrixTransformPoint(&g, &bankMatrix, &g); Alib_drawLine(u->w, f.x, f.y, g.x, g.y, white_color); } /* Bank needle: */ Alib_Matrix m; Alib_MatrixIdentity(&m); Alib_MatrixScale(&m, 0.001 * r); Alib_MatrixTranslate(&m, xo, yo); Alib_fillPolygonWithMatrix(u->w, attitude_bank_needle->pts, attitude_bank_needle->npts, &m, magentaColor); /* Pitch needle: */ Alib_MatrixTranslate(&m, 0, radius * INST(u)->attitude_pitch_offset); Alib_fillPolygonWithMatrix(u->w, attitude_pitch_needle->pts, attitude_pitch_needle->npts, &m, magentaColor); } /* ALTIMETER ========= */ static void instruments_altimeter_init(viewer *u) { INST(u)->altimeter_p0 = 2992; } void instruments_altimeter_correction(viewer *u, int delta) { int p0; if( u->inst == NULL ) return; p0 = INST(u)->altimeter_p0; p0 += delta; if( p0 < 2800 ) p0 = 2800; else if( p0 > 3100 ) p0 = 3100; INST(u)->altimeter_p0 = p0; } static void instruments_altimeter_draw(viewer * u, double xo, double yo, double width) { Alib_Window *w; double alt, radius, r, r1, r2, a, fw, fh, co, si, x; int j, hi, lo, p0; draw_Type *dd; char buf[20]; w = u->v->w; Alib_setClipRect(w, &u->altimeter); radius = 0.48 * width; dd = draw_new(); draw_circle(dd, xo, yo, radius); j = 0; r = 0.85 * radius; /* tick mark with number */ r1 = 0.92 * radius; /* tick mark without number */ r2 = 0.70 * radius; /* center circonf. for numbers */ fh = 0.15 * radius; for( a = 0.0; a < units_DEGtoRAD(359.9); a += units_DEGtoRAD(360.0/20.0) ){ co = cos(a); si = sin(a); if( j % 10 == 0 ){ sprintf(buf, "%d", j/10); draw_string_centered(u->v, xo + r2*si, yo - r2*co, fh, buf, white_color); draw_segment(dd, xo + r*si, yo - r*co, xo + radius*si, yo - radius*co); } else { draw_segment(dd, xo + r1*si, yo - r1*co, xo + radius*si, yo - radius*co); } j = j+5; } /* FIXME: what if alt<0? */ alt = units_METERStoFEET(u->c->w.z); /* apply altitude correction: */ p0 = INST(u)->altimeter_p0; alt = alt + 949.9 * (p0*0.01 - 29.92); if( alt < -0.5 ) alt = 1e5+alt; j = (int) (alt + 0.5); j = (j + 5) / 10 * 10; lo = j % 100; hi = j / 100; /* Thousand pointer: */ a = fmod(alt, 10000.0) * M_PI / 5000.0; //draw_pointer(dd, xo, yo, a - units_DEGtoRAD(90.0), 0.5*radius); drawNeedle(u->w, xo, yo, units_DEGtoRAD(90.0) - a, 0.5*radius, white_color); /* Hundreds pointer: */ a = fmod(alt, 1000.0) * M_PI / 500.0; //draw_pointer(dd, xo, yo, a - units_DEGtoRAD(90.0), 0.8*radius); drawNeedle(u->w, xo, yo, units_DEGtoRAD(90.0) - a, 0.8*radius, white_color); /* Digital value, flight level part: */ fh = 0.18*radius; fw = VFontWidthPixels(u->v, (int) (fh+0.5)); sprintf(buf, "%03d", hi); x = fw * 1.0; VDrawStrokeString(u->v, (int) (xo - fw * (strlen(buf)-1) + 0.5), (int) (yo - 0.2*radius + 0.5), buf, strlen(buf), (int)(fh+0.5), white_color); /* Digital value, last two digits: */ fh = 0.12*radius; fw = VFontWidthPixels(u->v, (int)(fh+0.5)); sprintf(buf, "%02d", lo); VDrawStrokeString(u->v, (int) (xo + x + 0.5), (int) (yo - 0.2*radius + 0.5), buf, strlen(buf), (int)(fh+0.5), white_color); /* Draw altitude correction: */ draw_string_centered(u->v, xo, yo + 0.1*radius, 0.10*radius, "inHg hPa", white_color); sprintf(buf, "%2.2f %04d", 0.01*p0, (int)(1013.25/29.92 * 0.01 * p0 + 0.5)); draw_string_centered(u->v, xo, yo+0.30*radius, 0.10*radius, buf, white_color); draw_string_centered(u->v, xo, yo-0.5*radius, 0.10*radius, "FEET", white_color); draw_stroke(dd, u->v, white_color); draw_free(dd); } /* Vertical speed indicator (VSI) ============================== */ static double vario[] = {0.0, 100.0, 200.0, 300.0, 400.0, 500.0, 1000.0, 2000.0, 3000.0, 4000.0, -1.0}; static double map_vario_to_angle(double v) { static double k = 0.0; double a; if( k == 0.0 ){ /* limit of the scale at 4000 ft/min: */ k = M_PI / (sqrt(4500.0 + 15.0*15.0) - 15.0); } v = fmin(v, 4000.0); v = fmax(v, -4000.0); a = k * (sqrt(fabs(v) + 15.0*15.0) - 15.0); if( v < 0.0 ) a = -a; return a; } static void instruments_vsi_init(viewer *u) { INST(u)->vsi_last_upd = curTime; INST(u)->vsi_last_vs = - u->c->Cg.z * 60.0; /* vertical speed, ft/min */ } #define VSI_K (1.0/4.0) /* If the vertical speed changes abruptly from vs(0) to some vs_actual, then in our model of the instrument lag the indicated vertical speed will be: vs(t) = (vs(0) - vs_actual) * exp(-VSI_K*t) + vs_actual where 1/VSI_K is the "time constant" (i.e. an extimation of the lag time). */ static void instruments_vsi_update(viewer *u) { double vs, dt; vs = - u->c->Cg.z * 60.0; /* vertical speed, ft/min */ dt = curTime - INST(u)->vsi_last_upd; INST(u)->vsi_last_vs += VSI_K * (vs - INST(u)->vsi_last_vs) * dt; INST(u)->vsi_last_upd = curTime; } static void instruments_vsi_draw(viewer * u, double xo, double yo, double width) { Alib_Window *w; double climb, radius, r, r1, r2, r3, a, fh, co, si; int j; draw_Type *dd; char buf[20]; w = u->v->w; Alib_setClipRect(w, &u->vsi); radius = 0.48 * width; dd = draw_new(); draw_circle(dd, xo, yo, radius); r1 = 0.87 * radius; /* tick mark with number */ r2 = 0.92 * radius; /* tick mark without number */ r3 = 0.70 * radius; /* center of the number */ fh = 0.12 * radius; j = 0; while( vario[j] >= 0 ){ climb = vario[j]; a = map_vario_to_angle(climb); co = cos(a); si = sin(a); sprintf(buf, "%.0f", climb/100); if( (int) (climb + 0.5) % 500 == 0 ){ draw_string_centered(u->v, xo - r3*co, yo - r3*si, fh, buf, white_color); draw_string_centered(u->v, xo - r3*co, yo + r3*si, fh, buf, white_color); r = r1; } else { r = r2; } draw_segment(dd, xo - r*co, yo - r*si, xo - radius*co, yo - radius*si); /* FIXME: because of a bug in Vlib, drawing a segment over another segment results in no segment drawn at all! This if() fixes that: */ if( j != 0 ) draw_segment(dd, xo - r*co, yo + r*si, xo - radius*co, yo + radius*si); j++; } a = map_vario_to_angle(INST(u)->vsi_last_vs); //draw_pointer(dd, xo, yo, a - M_PI, 0.80*radius); drawNeedle(u->w, xo, yo, M_PI - a, 0.80*radius, white_color); #ifdef DEBUG /* actual v.s.: */ climb = - u->c->Cg.z * 60.0; /* climb ratio, ft/min */ a = map_vario_to_angle(climb); draw_pointer(dd, xo, yo, a - M_PI, 0.40*radius); #endif draw_string_centered(u->v, xo, yo-0.3*radius, 0.15*radius, "FPM", white_color); draw_string_centered(u->v, xo, yo+0.3*radius, 0.12*radius, "x100", white_color); draw_stroke(dd, u->v, white_color); draw_free(dd); } /* AutoPilot System lights panel ============================= */ static void instruments_ap_panel(viewer *u, double x1, double y1, double x2, double y2) { Alib_Window *w; double margin, width, h, fh; void draw_light(char *label, int order, _BOOL on) { double xa, ya, xb, yb; Alib_Rect r; xa = x1 + order*width + margin; ya = y1 + margin; xb = x1 + order*width + width - margin; yb = y1 + h - margin; if( on ){ Alib_setRect(&r, xa, ya, xb, yb); Alib_fillRect(w, &r, magentaColor); } draw_string_centered(u->v, (xa+xb)/2.0, (ya+yb)/2.0, fh, label, black_color); } w = u->w; Alib_setClipRect(w, &u->stripe); /* size of every light: */ width = (x2-x1)/7.0; h = y2-y1; /* margin around each light: */ margin = 0.1*h; /* font height: */ fh = 0.5 * (h - 2.0*margin); draw_light("Rate", 0, aps_rate_control_enabled(u->c)); draw_light("VS/ALT", 1, aps_ap_enabled(u->c) && ( ! aps_ap_warn(u->c) || ! blink )); draw_light("Nav", 2, aps_an_enabled(u->c) && ( ! aps_an_warn(u->c) || ! blink )); draw_light("Land", 3, aps_al_enabled(u->c) && ( ! aps_al_warn(u->c) || ! blink )); draw_light("Turn", 4, aps_aw_enabled(u->c) && ( ! aps_aw_warn(u->c) || ! blink )); draw_light("Thr", 5, aps_at_enabled(u->c) && ( ! aps_at_warn(u->c) || ! blink )); draw_light("Coord", 6, aps_ac_enabled(u->c) && ( ! aps_ac_warn(u->c) || ! blink )); } /* TIMER ===== */ static void instruments_timer_init(viewer *u) { INST(u)->timer_op = 0; /* do not display */ } void instruments_timer_toggle(viewer *u) { if( u->inst == NULL ) return; INST(u)->timer_op = (INST(u)->timer_op + 1) % 3; if ( INST(u)->timer_op == 1 ) { INST(u)->timer_offset = curTime; } else if ( INST(u)->timer_op == 2 ) { INST(u)->timer_freezed = (int) (curTime - INST(u)->timer_offset + 0.5); } } static void instruments_timer_draw(viewer *u, double x1, double y1, double x2, double y2) { Alib_Window *w; int t, l; double h, fh, fw; char buffer[20]; Alib_Rect rect; if ( INST(u)->timer_op == 0 ) { return; } else if ( INST(u)->timer_op == 1 ) { t = (int) (curTime - INST(u)->timer_offset); } else { t = INST(u)->timer_freezed; } if (t >= 3600) { int h, m, s; h = t / 3600; t = t % 3600; m = t / 60; s = t % 60; sprintf(buffer, "%d:%02d:%02d", h, m, s); } else if (t >= 60) { int m, s; m = t / 60; s = t % 60; sprintf(buffer, "%d:%02d", m, s); } else { sprintf(buffer, "%d", t); } /* Background: */ w = u->v->w; h = y2 - y1; Alib_setRect(&rect, x1, y1, x2, y2); Alib_setClipRect(w, &rect); fh = h/2.0; fw = VFontWidthPixels(u->v, (int)(fh+0.5)); l = strlen(buffer); VDrawStrokeString(u->v, (int) (x2 - (l+2)*fw + 0.5), (int) (y1 + h/2.0 + fh/2.0 + 0.5), buffer, l, (int)(fh+0.5), white_color); } void instruments_update(viewer * u) { if( u->inst == NULL ) return; instruments_attitude_update(u); instruments_vsi_update(u); } void instruments_draw(viewer * u) { Alib_Window *w; double width; Alib_Rect rect; /* Update instruments. */ if( u->inst == NULL || ! INST(u)->enabled ) return; w = u->v->w; /* We have only the flux gate, not an inertial platform: */ u->c->showMag = TRUE; /* Update blink flag: */ if( curTime >= blink_toggle_time ){ blink = ! blink; if( blink ) blink_toggle_time = curTime + 0.1; else blink_toggle_time = curTime + 0.3; } /* Clear area of the classic instruments: */ Alib_setRect(&rect, 0, u->stripe.a.y, gui_getWidth(u->gui), u->engine.a.y); Alib_setClipRect(w, &rect); Alib_fillRect(w, &rect, panelBackgroundColor); width = RectWidth(u->vsi); /* FIXME: see FIXME above */ /* Instruments that occupy a standard slot: */ instruments_turnslip_draw (u, u->turn.a.x+width/2.0, u->turn.a.y+width/2.0, width); instruments_anemometer_draw(u, u->anemometer.a.x+width/2.0, u->anemometer.a.y+width/2.0, width); instruments_attitude_draw (u, u->attitude.a.x+width/2.0, u->attitude.a.y+width/2.0, width); instruments_altimeter_draw (u, u->altimeter.a.x+width/2.0, u->altimeter.a.y+width/2.0, width); instruments_vsi_draw (u, u->vsi.a.x+width/2, u->vsi.a.y+width/2, width); /* Timer and auto-pilot system lights goes in the stripe: */ instruments_timer_draw (u, u->stripe.a.x, u->stripe.a.y, width, u->stripe.b.y); instruments_ap_panel (u, width, u->stripe.a.y, u->stripe.b.x, u->stripe.b.y); } void instruments_enable(viewer * u) { if( u->inst == NULL ){ instruments_init(); if( free_list == NULL ){ u->inst = memory_allocate( sizeof(instruments_Type), NULL ); } else { u->inst = free_list; free_list = free_list->next; INST(u)->next = NULL; } instruments_anemometer_init(u); instruments_attitude_init(u); instruments_altimeter_init(u); instruments_vsi_init(u); instruments_timer_init(u); } INST(u)->enabled = TRUE; } void instruments_disable(viewer * u) { if( u->inst == NULL ) return; INST(u)->enabled = FALSE; } _BOOL instruments_isEnabled(viewer * u) { return (u->inst != NULL) && INST(u)->enabled; } void instruments_free(viewer *u) { if( u->inst == NULL ) return; INST(u)->next = free_list; free_list = u->inst; u->inst = NULL; } acm-6.0_20200416/src/acm/place.c0000644000000000000000000001002213076136533014354 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1997 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include "pm.h" #define place_IMPORT #include "place.h" static VPoint origin = {0.0, 0.0, 0.0}; void place_craft(Viewport * v, craft * c, viewer *u, craft * obj, VPolySet *ps) { int i, k, n; VPoint *q, tmp, tmp1, center, nc; VMatrix mtx, mtx1, m, m1; VPolygon *poly, **p, *p1; double dist; int aspect, offset; VObject *op; /* * Build a transformation matrix to convert from object to world coordinates. */ if ((obj->flags & FL_FIXED_OBJECT) == 0) { VIdentMatrix(&m); VRotate(&m, YRotation, -units_DEGtoRAD(90.0)); VRotate(&m, YRotation, -obj->w.latitude); VRotate(&m, ZRotation, obj->w.longitude); VEulerToMatrix(obj->curRoll, obj->curPitch, obj->curHeading, &m1); VMatrixMultByRank(&m1, &m, &mtx, 3); VTranslatePoint(&mtx, obj->Sg); } else { VIdentMatrix(&mtx); } /* * If the object uses a special method to render itself, call that procedure. */ if( obj->cinfo == NULL ){ printf("%s:%d: obj->cinfo == NULL, obj->type == %d\n", __FILE__, __LINE__, obj->type); return; } if (obj->cinfo->placeProc != NULL) { (*obj->cinfo->placeProc) (v, obj, &mtx, ps); return; } /* * Build a matrix to transform from world to eye coordinate systems. */ VMatrixMult(&mtx, &v->eyeSpace, &mtx1); /* * Reject the object if is completely outside any of the clipping planes */ if (obj->flags & FL_FIXED_OBJECT) tmp = obj->cinfo->object->center; else VTransform(&obj->cinfo->object->center, &mtx, &tmp); VTransform(&tmp, &u->v->eyeSpace, ¢er); for (i = 0; i < 4; ++i) { dist = VPointToClipPlaneDistance(¢er, &(u->v->clipNormals[i])); if (dist > obj->cinfo->object->extent) return; } op = obj->cinfo->object; n = op->numPolys; p = op->polygon; offset = 0; if (op->order) { VTransform(&origin, &mtx1, &nc); VTransform_(&VUnitVectorI, &mtx1, &op->xaxis); VTransform_(&VUnitVectorJ, &mtx1, &op->yaxis); VTransform_(&VUnitVectorK, &mtx1, &op->zaxis); aspect = VComputeObjectAspect(op, &nc); #ifdef notdef printf("%s: %s\n", op->name, VGetAspectName(aspect)); #endif offset = aspect * n; } for (i = 0; i < n; ++i) { /* * Here is an opportunity to cull back-facing polygons without * copying or transforming them. tmp1 becomes the transformed coordinates * of the first vertex in the polygon. */ p1 = (op->order) ? p[op->order[offset + i]] : p[i]; VTransform(&p1->vertex[0], &mtx1, &tmp1); if (p1->flags & PolyNormalValid) { VTransform_(&p1->normal, &mtx1, &tmp); } if (p1->flags & PolyClipBackface) { if (VDotProd(&tmp1, &tmp) >= 0.0) { continue; } } /* * Beyond the culling distance? Don't plot this polygon */ if (p1->flags & PolyUseCullDistance) { if (sqrt(tmp1.x * tmp1.x + tmp1.y * tmp1.y + tmp1.z * tmp1.z) > p1->cullDistance) { continue; } } poly = VCopyPolygon(p1); /* * First copy the normal vector and the transformed first point, then loop * over all remaining points. */ if (poly->flags & PolyNormalValid) { poly->normal = tmp; } q = poly->vertex; /* * First, copy the previously transformed first vertex. */ *q = tmp1; q++; /* * Now transform and copy the remaining vertices. */ for (k = 1; k < poly->numVtces; (++k, ++q)) { VTransform(q, &mtx1, &tmp); *q = tmp; } VPolySet_Add(ps, poly); } } acm-6.0_20200416/src/acm/joystick.h0000644000000000000000000000237313063670321015140 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #ifndef _joystick_h #define _joystick_h #ifdef joystick_IMPORT #define EXTERN #else #define EXTERN extern #endif EXTERN void joystick_setPort (char * name); EXTERN void joystick_calibrate(void); EXTERN void joystick_getPosition(double *x1, double *y1, double *x2, double *y2, int *switches); /** * This procedure should be called just before you call joystick_getPosition(). * It processes any pending input from the Workstation Gameport. */ EXTERN int joystick_processInput(void); #undef EXTERN #endif acm-6.0_20200416/src/acm/scale.c0000644000000000000000000001310213131100632014340 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1996 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include "../util/error.h" #include "../V/Vlib.h" #define scale_IMPORT #include "scale.h" static char * skipBlanks(char *s) { for (; *s == ' '; s++); return s; } void scale_draw(Viewport * vp, scale_Type * s, double value) { int ftw; Alib_Point p; Alib_Segment seg[32]; int is = 0; double tickDelta; int top = s->yorg - s->length; int yRef, tickDeltaPixels; int y, w, v, hticks; int ytick = (int) ((double) s->minorInterval / s->scale + 0.5); int doMajor; char str[16], *q; /* Very low zoom factors may reduce ytick to 0. Prevent division by 0: */ if( ytick == 0 ) return; ftw = VFontWidthPixels(vp, s->fontSize); yRef = s->yorg - (int) ((double) s->length / 2.0 + 0.5); tickDelta = value - (double) ((int) value / s->minorInterval * s->minorInterval); tickDeltaPixels = (int) (tickDelta / s->scale + 0.5); hticks = s->length / (2 * ytick); y = yRef + hticks * ytick + tickDeltaPixels; if (value >= 0.0) v = (int) (value - tickDelta - hticks * s->minorInterval); else { printf("scale.c, scale_draw(): can't do negative value scales, yet (1)\n"); v = 0; } if (tickDeltaPixels != 0) { y -= ytick; v += s->minorInterval; } v = v / s->minorInterval * s->minorInterval; /* * Draw the index mark */ seg[is].y1 = seg[is].y2 = yRef; if (s->orientation & scale_ORIENT_RIGHT) { seg[is].x1 = s->xorg - 2; seg[is].x2 = seg[is].x1 - s->indexSize; } else { seg[is].x1 = s->xorg + 2; seg[is].x2 = seg[is].x1 + s->indexSize; } ++is; /* * step through the doMajor and minor ticks */ for (; y > top; (y -= ytick, v += s->minorInterval)) { /* we don't mark negative ticks */ if (v < 0) continue; seg[is].x1 = s->xorg; seg[is].y1 = seg[is].y2 = p.y = y; if ((v % s->majorInterval) == 0) { doMajor = 1; w = s->majorSize; if (s->orientation & scale_ORIENT_RIGHT) seg[is].x2 = s->xorg + w; else seg[is].x2 = s->xorg - w; sprintf(str, s->format, (double) v / s->divisor); q = skipBlanks(str); p.y += (int) (0.30 * s->fontSize + 0.5); if (s->orientation & scale_ORIENT_RIGHT) { p.x = seg[is].x2 + 3; } else { p.x = seg[is].x2 - 3 - ftw * strlen(q); } } else { doMajor = 0; w = s->minorSize; if (s->orientation & scale_ORIENT_RIGHT) seg[is].x2 = s->xorg + w; else seg[is].x2 = s->xorg - w; } if (doMajor) VDrawStrokeString(vp, p.x, p.y, q, strlen(q), s->fontSize, s->pixel); ++is; } VDrawSegments(vp, seg, is, s->pixel); } void scale_drawCompass(Viewport * vp, scale_Type * s, double value) { int ftw; Alib_Point p; Alib_Segment seg[32]; int is = 0; int top = s->xorg + s->length; int x, w, v; int xtick = (int) ((double) s->minorInterval / s->scale + 0.5); int doMajor; char str[16], *q; double tickDelta; int tickDeltaPixels, xRef, hticks; /* Very low zoom factors may reduce xtick to 0. Prevent division by 0: */ if( xtick == 0 ) return; ftw = VFontWidthPixels(vp, s->fontSize); xRef = s->xorg + (int) ((double) s->length / 2.0 + 0.5); tickDelta = value - (double) ((int) value / s->minorInterval * s->minorInterval); tickDeltaPixels = (int) (tickDelta / s->scale + 0.5); hticks = s->length / (2 * xtick); x = xRef - hticks * xtick - tickDeltaPixels; v = (int)(value - tickDelta - hticks * s->minorInterval); while(v < 0) v += 36000; while(v >= 36000) v -= 36000; if (tickDeltaPixels != 0) { x += xtick; v += s->minorInterval; } v = v / s->minorInterval * s->minorInterval; /* * Draw the index mark */ seg[is].x1 = seg[is].x2 = xRef; if (s->orientation & scale_ORIENT_RIGHT) { seg[is].y1 = s->yorg - 2; seg[is].y2 = seg[is].y1 - s->indexSize; } else { seg[is].y1 = s->yorg + 2; seg[is].y2 = seg[is].y1 + s->indexSize; } ++is; /* * step through the doMajor and minor ticks */ for (; x < top; (x += xtick, v += s->minorInterval)) { if (v > 36000) v -= 36000; if (is >= 32) error_internal("too many segments: %d", is); seg[is].y1 = s->yorg; seg[is].x1 = seg[is].x2 = p.x = x; if ((v % s->majorInterval) == 0) { doMajor = 1; w = s->majorSize; if (s->orientation & scale_ORIENT_RIGHT) seg[is].y2 = s->yorg + w; else seg[is].y2 = s->yorg - w; sprintf(str, s->format, (double) v / s->divisor); q = skipBlanks(str); p.x -= (strlen(q) * ftw) / 2; if (s->orientation & scale_ORIENT_RIGHT) { p.y = seg[is].y2 + 3 + s->fontSize; } else { p.y = seg[is].y2 - 3; } } else { doMajor = 0; w = s->minorSize; if (s->orientation & scale_ORIENT_RIGHT) seg[is].y2 = s->yorg + w; else seg[is].y2 = s->yorg - w; } if (doMajor) VDrawStrokeString(vp, p.x, p.y, q, strlen(q), s->fontSize, s->pixel); ++is; } VDrawSegments(vp, seg, is, (Alib_Pixel) s->pixel); } acm-6.0_20200416/src/acm/alarm.h0000644000000000000000000000363513064352665014410 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991,1992 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #ifndef _alarm_h #define _alarm_h #ifdef alarm_IMPORT #define EXTERN #else #define EXTERN extern #endif typedef long alarm_id_t; /** * Add a new entry into the alarm list. * * BEWARE. * If any of the parameters arg1,arg2 makes reference to a data structure * that may be removed before the call-back procedure be called, make sure * to remove also any alarm that makes reference to these data. * @param delta Calls proc when exactly delta seconds are elapsed, * then remove this alarm. * @param proc Call-back procedure with signature void(void *, void *). * @param arg1 Utility parameter for proc. * @param arg2 Utility parameter for proc. * @return Univocal alarm identifier. */ EXTERN alarm_id_t alarm_add(double delta, void (*proc) (void *, void *), void *arg1, void *arg2); /** * Removes the alarm from the pending alarms. Does nothing if the alarm was * already thrown. * @param id */ EXTERN void alarm_cancel(alarm_id_t id); /** * Updates the alarms list. For alarms whose delay time is elapsed, the * alarm entry is first removed, and then the corresponding call-back * function is called. */ EXTERN void alarm_update(void); #undef EXTERN #endif acm-6.0_20200416/src/acm/interpolate.h0000644000000000000000000000457613074624377015652 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991,1992,1997 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /** * Some data structures to perform fast 2-D interpolation * * A lot of aircraft information is in tabular form. We perform linear * interpolation to determine values. In order to speed up that process, * we'll create preprocessed tables. Each entry in the table contains the * upper bound of the domain value (x) and the equation of the line that * defines the data for that interval (y = m * x + b). * * @file */ #ifndef _interpolate_h #define _interpolate_h #include #ifdef interpolate_IMPORT #define EXTERN #else #define EXTERN extern #endif typedef struct { double x; /* upper x value for this interval */ double m; /* slope of line in this interval */ double b; /* y-intercept of line in this interval */ } interpolate_Entry; typedef struct { int count; /* entry count in the interpolation table */ double minX; /* minimum x value that can be interpolated */ interpolate_Entry *entry; /* vector of interpolation entries */ } interpolate_Table; /** * Allocates a new interpolation table. * @param size Number of entries. * @return New allocated table. Can be released with memory_dispose(). */ EXTERN interpolate_Table * interpolate_new(int size); /** * Determine the value of a function of one variable by interpolation. * Interpolation tables are built by the 'ibuild' utility. */ EXTERN double interpolate_value(interpolate_Table * table, double x); /** * Returns a copy of the given table. * @param oldp * @return Copy of the given table. Can be released with memory_dispose(). */ EXTERN interpolate_Table * interpolate_clone (interpolate_Table *oldp); #undef EXTERN #endif acm-6.0_20200416/src/acm/render.h0000644000000000000000000000377113175040636014567 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #ifndef _render_h #define _render_h #include "pm.h" #ifdef render_IMPORT #define EXTERN #else #define EXTERN extern #endif /** Outside view modes. */ typedef enum { render_VIEW_FORWARD, render_VIEW_UP, render_VIEW_DOWN, render_VIEW_LEFT, render_VIEW_RIGHT, render_VIEW_AFT, render_VIEW_CHASE } render_ViewDirection; typedef enum {render_GROUND_FLAT, render_GROUND_TILED} render_Ground; /** * Set visibility range. Above that distance objects are not drawn and haze * effect is displayed instead. The default visibility range is 10 NM. * @param range Visibility range (m). The value is forced to the range * from 0.01 NM up to 50 NM (185 and 92650 m respectively). */ EXTERN void render_setVisibility(double range); /** * Set ground depth mode. * @param mode The default depth mode is flat rendering. */ EXTERN void render_setGroundDepth(render_Ground mode); /** * Set tick clouds layer range. No clouds if the top is less or equal to bottom. * @param base Clouds base altitude (m). Default: zero. * @param top Clouds top altitude (m). Default: zero. */ EXTERN void render_setClouds(double base, double top); EXTERN void render_drawCockpitViews(void); EXTERN void render_setOutsideView(craft * c, viewer *u, render_ViewDirection v); #undef EXTERN #endif acm-6.0_20200416/src/acm/flaps.c0000644000000000000000000000512313063670321014375 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1997 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include "pm.h" #include "damage.h" #define flaps_IMPORT #include "flaps.h" int flaps_down(craft * c) { c->flapSetting += 10.0 * M_PI / 180.0; if (c->flapSetting > c->cinfo->maxFlap) c->flapSetting = c->cinfo->maxFlap; return 0; } int flaps_up(craft * c) { c->flapSetting -= 10.0 * M_PI / 180.0; if (c->flapSetting < 0.0) c->flapSetting = 0.0; return 0; } void flaps_update(craft * c) { if (damage_isFunctioning(c, SYS_FLAPS)) { if (c->flapSetting > c->curFlap) { c->curFlap += c->cinfo->flapRate * deltaT; if (c->curFlap > c->flapSetting) c->curFlap = c->flapSetting; } else if (c->flapSetting < c->curFlap) { c->curFlap -= c->cinfo->flapRate * deltaT; if (c->curFlap < c->flapSetting) c->curFlap = c->flapSetting; } } if (damage_isFunctioning(c, SYS_SPEEDBRAKE)) { if (c->speedBrakeSetting > c->curSpeedBrake) { c->curSpeedBrake += c->cinfo->speedBrakeRate * deltaT; if (c->curSpeedBrake > c->speedBrakeSetting) c->curSpeedBrake = c->speedBrakeSetting; } else if (c->speedBrakeSetting < c->curSpeedBrake) { c->curSpeedBrake -= c->cinfo->speedBrakeRate * deltaT; if (c->curSpeedBrake < c->speedBrakeSetting) c->curSpeedBrake = c->speedBrakeSetting; } } /* * Set some status flags */ if (c->fuel < (c->cinfo->maxFuel * 0.15)) c->damageBits |= FLAG_LOWFUEL; else c->damageBits &= ~FLAG_LOWFUEL; if (c->speedBrakeSetting > 0.0) c->damageBits |= FLAG_SPEEDBRAKE; else c->damageBits &= ~FLAG_SPEEDBRAKE; } int flaps_speed_brakes_extend(craft * c) { c->speedBrakeSetting += c->cinfo->speedBrakeIncr; if (c->speedBrakeSetting > c->cinfo->maxSpeedBrake) c->speedBrakeSetting = c->cinfo->maxSpeedBrake; return 0; } int flaps_speed_brakes_retract(craft * c) { c->speedBrakeSetting -= c->cinfo->speedBrakeIncr; if (c->speedBrakeSetting < 0.0) c->speedBrakeSetting = 0.0; return 0; } acm-6.0_20200416/src/acm/hsi.c0000644000000000000000000005431413143113774014064 0ustar rootroot/* * acm : an aerial combat simulator for X * HSI tuner and HSI indicator module * Copyright (C) 1991-1998 Riley Rainey * Copyright (C) 2007 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include "../util/memory.h" #include "pm.h" #include "navaid.h" #include "../util/units.h" #include "vpath_gallery.h" #define hsi_IMPORT #include "hsi.h" /* how many NAV receivers */ #define HSI_NAV_MAX 2 /* how many RNAV calculators */ #define HSI_RNAV_MAX 5 /* repeat station reception check every ... (s) */ #define RECEPTION_CHECK_INTERVAL 4.0 /* * Every station sends its Morse ID every ... (s) * * In the reality different stations can send their ID at different intervals * of time. */ #define ID_DELAY 10.0 /* * If we are lucky, the DME station will reply to our requests every so * many seconds. This module simulates a DME receiver that performs some * estimations in order to update the DME readout. * * In the reality, DMEs may or may not respond at all, and the responses * come at random intervals of times. */ #define DME_DELAY 3.0 /* * Every CDI dot means that angular deviation. */ #define CDI_DOT_STEP units_DEGtoRAD(1.7) /* * Constant that maps the current angular deviation to some displacement * of the CDI segment as drawn inside a circumference of unit radius. */ #define CDI_DOT_K (0.9 / CDI_MAX_DEVIATION) /* * Number of dots to the left and to the right of the OBS indicator. */ #define CDI_DOT_NO 5 /* * The CDI stops if the angular deviation is greater than that. We allow * the CDI segment to go half-dot beyond the last dot, just to alert the * pilot that the indicator is out of scale. */ #define CDI_MAX_DEVIATION ((CDI_DOT_NO + 0.5)*CDI_DOT_STEP) /* * The GS indicator stops at +/-2.5 DEG deviation */ #define GS_OFFSET_MAX units_DEGtoRAD(2.5) /* * Constant that maps the current GS deviation to some displacement of the * GS indicator. */ #define GS_OFFSET_K (1.0/units_DEGtoRAD(2)) /* * Way point: can be either a NAVAID station (VOR, DME, ILS) or a proper WP * relative to some VOR/DME station for the RNAV calculator. */ typedef struct { navaid_Channel frequency; /* selected freq. */ navaid_Type *station; /* NAVAID station, possibly NULL */ double station_at; /* last reception check */ double radial; /* current radial occupied */ double id_update_at; /* when to update the id field (s) */ char *id; /* station name -- invalid if NULL */ int obs; /* OBS (DEG, 0-359) */ _BOOL is_wp; /* if it is a WP, the following fields have meaning: */ /* RNAV data -- meaningful only if is_wp */ int rho; /* distance VOR-WP (tenth of NM, 1-2000) */ int theta; /* WP bearing relative to the VOR (DEG, 0-359) */ double cos_theta, sin_theta; /* Handling of the DME signal: */ double dme_response; /* last response from DME, invalid if < 0 (NM) */ double dme_response_at; /* last response received at this time (s) */ double dme_response_dot; /* time derivative of the responses (NM/s) */ double dme; /* estimated distance, invalid if < 0 (NM) */ /* Values to be displayed: */ double radial_readout; /* current radial relative to the WP (RAD) */ double dme_readout; /* distance from WP (NM) */ } waypoint; typedef struct _hsi_data { struct _hsi_data *next; _BOOL enabled; int idx; /* index of the current WP displayed */ waypoint wps[HSI_NAV_MAX + HSI_RNAV_MAX]; } hsi_data; /* Released HSI available for re-use. */ static hsi_data *free_list = NULL; static vpath_Type * obs_pointer = NULL, * cdi_segment = NULL, * vor_orientation = NULL, * gs_dots = NULL, * gs_pointer = NULL; static void hsi_cleanup() { hsi_data *p; while( free_list != NULL ){ p = free_list; free_list = free_list->next; memory_dispose(p); } memory_dispose(obs_pointer); obs_pointer = NULL; memory_dispose(cdi_segment); cdi_segment = NULL; memory_dispose(vor_orientation); vor_orientation = NULL; memory_dispose(gs_dots); gs_dots = NULL; memory_dispose(gs_pointer); gs_pointer = NULL; } /* Set the "no DME readout" status */ static void hsi_reset_dme(waypoint *wp) { wp->dme_response = -1.0; /* still no DME response */ wp->dme_response_at = curTime; wp->dme_response_dot = 0.0; wp->dme = -1.0; /* still no DME estimation */ } void hsi_enable(viewer *u) { int i; hsi_data *hsi; waypoint *wp; if( u->hsi == NULL ){ /* Allocate memory for HSI status: */ if( free_list == NULL ){ hsi = memory_allocate( sizeof(hsi_data), NULL ); memory_registerCleanup(hsi_cleanup); } else { hsi = free_list; free_list = hsi->next; } /* Initialize: */ hsi->idx = 0; for( i = 0; i < HSI_NAV_MAX + HSI_RNAV_MAX; i++ ){ wp = &hsi->wps[i]; wp->frequency = navaid_VOR_CHANNEL_MIN; wp->station = NULL; wp->station_at = 0.0; wp->radial = 0.0; wp->obs = 0; wp->is_wp = (i >= HSI_NAV_MAX); wp->rho = 10; /* 1.0 NM */ wp->theta = 0; wp->id = NULL; hsi_reset_dme(wp); wp->radial_readout = 0.0; wp->dme_readout = 0.0; } u->hsi = hsi; } else { hsi = u->hsi; } hsi->enabled = TRUE; } void hsi_disable(viewer *u) { hsi_data *hsi; hsi = u->hsi; if( hsi == NULL ) return; hsi->enabled = FALSE; } static void hsi_retune(waypoint *wp) { /* Reset VOR receiver: */ wp->station = NULL; wp->station_at = curTime; wp->radial = 0.0; wp->id = NULL; wp->radial_readout = 0.0; wp->dme_readout = 0.0; /* Reset DME receiver: */ hsi_reset_dme(wp); } void hsi_update(viewer * u) { navaid_Type *n; VPoint v; double d; hsi_data *hsi = u->hsi; if( hsi == NULL || ! hsi->enabled ) return; waypoint *wp = &hsi->wps[hsi->idx]; /* * Determinate the station 'n', possibly re-scanning all the * receivable stations at this freq. */ if( curTime < wp->station_at + RECEPTION_CHECK_INTERVAL ){ n = wp->station; } else { wp->station_at = curTime; n = navaid_reception_check(u->c, wp->frequency); if( n != NULL && wp->is_wp && (n->type & navaid_VOR) == 0 ){ /* can't tune LOC in RNAV mode: */ n = NULL; } } if( n == NULL ){ /* no station found. */ wp->station = NULL; wp->id = NULL; hsi_reset_dme(wp); } else if( wp->station != n ){ /* Station change: */ wp->station = n; wp->id_update_at = curTime + ID_DELAY; wp->id = NULL; wp->radial = 0.0; hsi_reset_dme(wp); wp->dme_response_at = curTime; } else { /* Still the same station. Update station ID: */ if( wp->id == NULL && curTime > wp->id_update_at ) wp->id = n->id; /* Update occupied radial: */ VTransform(&u->c->Sg, &n->lt, &v); wp->radial = pm_heading(&v); if( ! wp->is_wp ) wp->radial_readout = wp->radial; /* Update DME: */ if( (n->type & navaid_DME) != 0 && curTime > wp->dme_response_at + DME_DELAY ){ /* Got DME signal! */ d = units_METERStoNM( VMagnitude(&v) ); if( wp->dme_response >= 0.0 ){ wp->dme_response_dot = (d - wp->dme_response) / (curTime - wp->dme_response_at); } wp->dme_response = d; wp->dme_response_at = curTime; wp->dme = d; } else if( wp->dme_response >= 0.0 ){ /* No response from DME but previous data available. Compute estimated value. */ wp->dme = fabs( wp->dme_response + wp->dme_response_dot * (curTime - wp->dme_response_at) ); } /* * Update values to be read by pilot and HSI display: */ if( wp->is_wp ){ /* RNAV. Convert polar coords (dme,radial) relative to the VOR/DME to polar coords (dme_readout,radial_readout) relative to the WP: */ v.x = wp->dme * cos(wp->radial) - 0.1 * wp->rho * wp->cos_theta; v.y = wp->dme * sin(wp->radial) - 0.1 * wp->rho * wp->sin_theta; v.z = 0.0; wp->radial_readout = pm_heading(&v); wp->dme_readout = VMagnitude(&v); } else { /* * NAV. Simply copy better estimation of the * distance: */ wp->dme_readout = wp->dme; } } } void hsi_switch_mode(viewer * u) { hsi_data *hsi; hsi = u->hsi; if( hsi == NULL || ! hsi->enabled ) return; hsi->idx++; if( hsi->idx >= HSI_NAV_MAX + HSI_RNAV_MAX ) hsi->idx = 0; hsi_retune( &hsi->wps[ hsi->idx ] ); } static _BOOL is_auto_repeat( double *timeout ) { _BOOL res; res = (curTime < *timeout); *timeout = curTime + 0.1; return res; } void hsi_frq_inc(viewer * u, int step) { hsi_data *hsi; waypoint *wp; static double timeout = 0.0; hsi = u->hsi; if( hsi == NULL || ! hsi->enabled ) return; wp = &hsi->wps[hsi->idx]; if( is_auto_repeat(&timeout) ) step *= 2; wp->frequency += step; if( wp->frequency < navaid_VOR_CHANNEL_MIN ) wp->frequency = navaid_VOR_CHANNEL_MIN; if( wp->frequency > navaid_VOR_CHANNEL_MAX ) wp->frequency = navaid_VOR_CHANNEL_MAX; hsi_retune(wp); } void hsi_obs_inc(viewer * u, int step) { hsi_data *hsi; waypoint *wp; static double timeout = 0.0; hsi = u->hsi; if( hsi == NULL || ! hsi->enabled ) return; wp = &hsi->wps[hsi->idx]; if( is_auto_repeat(&timeout) ) step *= 2; wp->obs += step; while( wp->obs < 0 ) wp->obs += 360; while( wp->obs >= 360 ) wp->obs -= 360; } void hsi_theta_inc(viewer * u, int step) { hsi_data *hsi; waypoint *wp; static double timeout = 0.0; hsi = u->hsi; if( hsi == NULL || ! hsi->enabled ) return; wp = &hsi->wps[hsi->idx]; if( ! wp->is_wp ) return; if( is_auto_repeat(&timeout) ) step *= 2; wp->theta += step; while( wp->theta < 0 ) wp->theta += 360; while( wp->theta >= 360 ) wp->theta -= 360; wp->cos_theta = cos( units_DEGtoRAD(wp->theta) ); wp->sin_theta = sin( units_DEGtoRAD(wp->theta) ); wp->dme_response_dot = 0.0; } void hsi_rho_inc(viewer * u, int step) { hsi_data *hsi; waypoint *wp; static double timeout = 0.0; hsi = u->hsi; if( hsi == NULL || ! hsi->enabled ) return; wp = &hsi->wps[hsi->idx]; if( ! wp->is_wp ) return; if( is_auto_repeat(&timeout) ) step *= 5; wp->rho += step; if( wp->rho < 0 ) wp->rho = 0; if( wp->rho > 2000 /* 200 NM */ ) wp->rho = 2000; wp->dme_response_dot = 0.0; } int hsi_get_obs(viewer *u) { hsi_data *hsi; hsi = u->hsi; if( hsi == NULL || ! hsi->enabled ) return 0; return hsi->wps[ hsi->idx ].obs; } _BOOL hsi_vor_radial(viewer *u, double *r) { hsi_data *hsi; waypoint *wp; hsi = u->hsi; if( hsi == NULL || ! hsi->enabled ) return FALSE; wp = &hsi->wps[ hsi->idx ]; if( wp->station == NULL || (wp->station->type & navaid_VOR) == 0 ) return FALSE; /* no station tuned */ if( wp->is_wp && wp->dme < 0.0 ) return FALSE; /* RNAV can't compute */ *r = wp->radial_readout; return TRUE; } _BOOL hsi_dme(viewer *u, double *dist) { hsi_data *hsi; waypoint *wp; hsi = u->hsi; if( hsi == NULL || ! hsi->enabled ) return FALSE; wp = &hsi->wps[ hsi->idx ]; if( wp->station == NULL || wp->dme < 0.0 ) return FALSE; *dist = wp->dme_readout; return TRUE; } _BOOL hsi_loc_radial(viewer *u, double *r) { hsi_data *hsi; waypoint *wp; hsi = u->hsi; if( hsi == NULL || ! hsi->enabled ) return FALSE; wp = &hsi->wps[ hsi->idx ]; if( wp->station == NULL || (wp->station->type & navaid_LOC) == 0 ) return FALSE; *r = wp->radial_readout; return TRUE; } _BOOL hsi_gs_offset(viewer *u, double *offset) { hsi_data *hsi; waypoint *wp; VPoint p; hsi = u->hsi; if( hsi == NULL || ! hsi->enabled ) return FALSE; wp = &hsi->wps[ hsi->idx ]; if( wp->station == NULL || (wp->station->type & navaid_GS) == 0 ) return FALSE; VTransform(&u->c->Sg, &wp->station->gst, &p); *offset = atan2(-p.z, p.x) - wp->station->slope; return TRUE; } static void hsi_panel_string(viewer *u, double x, double y, double fh, char *s1, char *s2, char *s3) { double fw, fh2, fw2; fw = fh; fh2 = 1.5*fh; fw2 = fh2; VDrawStrokeString(u->v, (int) (x + 0.5), (int) (y + 0.5), s1, strlen(s1), (int) (fh + 0.5), radarColor); VDrawStrokeString(u->v, (int) (x + 13*fw - fw2*strlen(s2) + 0.5), (int) (y + 0.5), s2, strlen(s2), (int) (fh2 + 0.5), whiteColor); VDrawStrokeString(u->v, (int) (x + 14*fw + 0.5), (int) (y + 0.5), s3, strlen(s3), (int) (fh + 0.5), radarColor); } void hsi_panel_draw(viewer * u) { hsi_data *hsi; waypoint *wp; Alib_Window *w; double x, y, fh, fw, il; int f; char s[100], r[100]; hsi = u->hsi; if( hsi == NULL || ! hsi->enabled ) return; wp = &hsi->wps[hsi->idx]; w = u->v->w; Alib_setClipRect(w, &u->tuner); Alib_fillRect(w, &u->tuner, panelBackgroundColor); fh = RectWidth(u->tuner) / 20.0; fw = fh; il = 1.2*fh*2.5; /* inter-line spacing */ x = u->tuner.a.x + fw; y = u->tuner.a.y + il; /* * Displays mode: */ if( wp->is_wp ) sprintf(s, "RNAV%d", hsi->idx - HSI_NAV_MAX + 1); else sprintf(s, "NAV%d", hsi->idx + 1); hsi_panel_string(u, x, y, fh, "Mode", s, ""); y += il; /* * Displays frequency */ f = 10800 + 5 * (wp->frequency - navaid_VOR_CHANNEL_MIN); sprintf(s, "%d.%02d", f / 100, f % 100); hsi_panel_string(u, x, y, fh, "FRQ", s, "MHz"); y += il; /* * Displays station ID: */ if( wp->id != NULL ) strcpy(s, wp->station->id); else strcpy(s, "----"); hsi_panel_string(u, x, y, fh, "STA", s, ""); y += il; /* * Display DME: */ if( wp->dme >= 0.0 ){ sprintf(s, "%0.1f", wp->dme_readout); } else { strcpy(s, "---.-"); } hsi_panel_string(u, x, y, fh, "DME", s, "NM"); y += il; /* * Displays WP setting: */ if( wp->is_wp ){ sprintf(s, "%3d", wp->theta); sprintf(r, "%d.%d", wp->rho / 10, wp->rho % 10); } else { strcpy(s, ""); strcpy(r, ""); } hsi_panel_string(u, x, y, fh, "RAD", s, "DEG"); y += il; hsi_panel_string(u, x, y, fh, "DST", r, "NM"); y += il; } static void add_dot(vpath_Type *p, double ox, double oy, double r) { VPoint a, b, c, d; VSetPoint(&a, ox + r, oy, 0.0); VSetPoint(&b, ox, oy + r, 0.0); VSetPoint(&c, ox - r, oy, 0.0); VSetPoint(&d, ox, oy - r, 0.0); vpath_moveTo(p, &a); vpath_lineTo(p, &b); vpath_lineTo(p, &c); vpath_lineTo(p, &d); vpath_lineTo(p, &a); } static void build_vpaths() /* * Build Vpats specific of the HSI. Every vpath is build over the xy plane in * screen coords.: x=right, y=down. Vpaths that have a circular symmetry or * need to be rotated, are build around the origin (0,0) and have a radius * of 1.0 so that they can be easily rotated, scaled and translated to the * final screen location. */ { int i; double l1, l2, l3, dev; if( obs_pointer != NULL ) return; /* all the vpats already done */ /* * Build obs_pointer, including CDI scale */ l1 = 0.06; /* OBS pointer half-width */ l2 = 0.60; /* CDI segment half-length */ obs_pointer = vpath_new(); vpath_moveTo(obs_pointer, &(VPoint){0.0, -1.00, 0.0}); vpath_lineTo(obs_pointer, &(VPoint){ l1, -1.00+3.0*l1, 0.0}); vpath_lineTo(obs_pointer, &(VPoint){ l1, -l2, 0.0}); vpath_lineTo(obs_pointer, &(VPoint){ -l1, -l2, 0.0}); vpath_lineTo(obs_pointer, &(VPoint){ -l1, -1.00+3.0*l1, 0.0}); vpath_lineTo(obs_pointer, &(VPoint){0.0, -1.00, 0.0}); vpath_moveTo(obs_pointer, &(VPoint){l1, l2, 0.0}); vpath_lineTo(obs_pointer, &(VPoint){l1, 1.0, 0.0}); vpath_lineTo(obs_pointer, &(VPoint){-l1, 1.0, 0.0}); vpath_lineTo(obs_pointer, &(VPoint){-l1, l2, 0.0}); vpath_lineTo(obs_pointer, &(VPoint){l1, l2, 0.0}); for( i = 1; i <= CDI_DOT_NO; i++ ){ dev = i * CDI_DOT_STEP * CDI_DOT_K; add_dot(obs_pointer, dev, 0.0, 0.03); add_dot(obs_pointer, -dev, 0.0, 0.03); } /* * Build CDI segment */ cdi_segment = vpath_new(); vpath_moveTo(cdi_segment, &(VPoint){l1, -l2, 0.0}); vpath_lineTo(cdi_segment, &(VPoint){l1, l2, 0.0}); vpath_lineTo(cdi_segment, &(VPoint){-l1, l2, 0.0}); vpath_lineTo(cdi_segment, &(VPoint){-l1, -l2, 0.0}); vpath_lineTo(cdi_segment, &(VPoint){l1, -l2, 0.0}); /* * Build VOR orientation indicator */ vor_orientation = vpath_new(); vpath_moveTo(vor_orientation, &(VPoint){0.0, -0.50, 0.0}); vpath_lineTo(vor_orientation, &(VPoint){2.0*l1, -0.50 + 2.0*l1, 0.0}); vpath_lineTo(vor_orientation, &(VPoint){-2.0*l1, -0.50 + 2.0*l1, 0.0}); vpath_lineTo(vor_orientation, &(VPoint){0.0, -0.50, 0.0}); /* * Build GS scale */ gs_dots = vpath_new(); add_dot(gs_dots, 0.0, 0.0, 0.05); add_dot(gs_dots, 0.0, 0.5, 0.03); add_dot(gs_dots, 0.0, 1.0, 0.03); add_dot(gs_dots, 0.0, -0.5, 0.03); add_dot(gs_dots, 0.0, -1.0, 0.03); /* * Build GS pointer */ l3 = 0.10; gs_pointer = vpath_new(); vpath_moveTo(gs_pointer, &(VPoint){0.0, 0.0, 0.0}); vpath_lineTo(gs_pointer, &(VPoint){-l3, 2.0*l3, 0.0}); vpath_lineTo(gs_pointer, &(VPoint){-l3, -2.0*l3, 0.0}); vpath_lineTo(gs_pointer, &(VPoint){0.0, 0.0, 0.0}); } void hsi_draw(viewer * u) { hsi_data *hsi; waypoint *wp; Alib_Window *w; Alib_Pixel white, magenta; int xc, yc, h, x, y; int vor_orient; VMatrix m; double scale, obs_scale, gs_scale, hdg, gs_offset, r, diff, dev; char s[8]; hsi = u->hsi; if( hsi == NULL || ! hsi->enabled ) return; wp = &hsi->wps[hsi->idx]; w = u->w; Alib_setClipRect(w, &u->indicator); Alib_fillRect(w, &u->indicator, panelBackgroundColor); build_vpaths(); white = whiteColor; magenta = magentaColor; x = u->indicator.a.x; y = u->indicator.a.y; scale = RectWidth(u->indicator); r = 0.44*scale; obs_scale = 0.80 * r; gs_scale = 0.60 * r; xc = x + (int) (0.48*scale+0.5); yc = y + (int) (0.50*scale+0.5); if (u->c->showMag) hdg = pm_mag_heading(u->c); else hdg = u->c->curHeading; h = (int) (0.045*scale + 0.5); /* * Displays "TH" or "MH" */ VDrawStrokeString(u->v, x + (int) (0.05*scale+0.5), y + (int) (0.06*scale), (u->c->showMag)? "MH":"TH", 2, h, whiteColor); /* * Display the OBS value. */ VDrawStrokeString(u->v, x + (int) (0.85*scale), y + (int) (0.06*scale), "OBS", 3, h, whiteColor); sprintf(s, "%03d", wp->obs); VDrawStrokeString(u->v, x + (int) (0.85*scale), y + (int) (0.13*scale), s, 3, h, whiteColor); /* Draw compass scale: */ VIdentMatrix(&m); VRotate(&m, ZRotation, -hdg); VScaleMatrix(&m, r, r, r); VTranslate(&m, xc, yc, -1.0); vpath_stroke( vpath_gallery_get_compass_scale(), &m, w, white); /* Draw compass fixed scale: */ VIdentMatrix(&m); VScaleMatrix(&m, r/0.90, r/0.90, r/0.90); VTranslate(&m, xc, yc, -1.0); vpath_stroke( vpath_gallery_get_compass_fixed_scale(), &m, w, white); /* Draw stylized aircraft: */ VIdentMatrix(&m); VScaleMatrix(&m, 0.25*r, 0.20*r, 0.25*r); VTranslate(&m, xc, yc, -1.0); vpath_stroke( vpath_gallery_get_stylized_aircraft(), &m, w, white); /* Draw OBS pointer with CDI scale: */ VIdentMatrix(&m); VRotate(&m, ZRotation, units_DEGtoRAD(wp->obs) - hdg); VScaleMatrix(&m, obs_scale, obs_scale, obs_scale); VTranslate(&m, xc, yc, -1.0); vpath_stroke( obs_pointer, &m, w, white); /* * Draw the Course Deviation Indicator */ if( wp->station != NULL && wp->station->type & (navaid_VOR|navaid_LOC) && (! wp->is_wp || wp->dme >= 0.0) ) { /* * Full localizer/SDF offsets will vary based on the beam width of the * transmitter (typical localizer values are 3 to 6 degrees). * * VOR offsets are 1.7 degrees per dot on the HSI. * ILS course offsets are 0.4 degrees per dot. */ diff = wp->radial_readout; if( wp->station->type & navaid_LOC ){ /* * Calculate actual angular deviation from the * LOCATOR as angle between -M_PI and +M_PI: */ if( diff > M_PI ) diff = diff - 2*M_PI; vor_orient = 0; } else { diff = diff - units_DEGtoRAD(wp->obs); /* * Calculate actual angular deviation from the * selected OBS as angle between -M_PI and +M_PI: */ if( diff > M_PI ){ diff = diff - 2*M_PI; } else if( diff < -M_PI ){ diff = 2*M_PI + diff; } if( fabs(diff) <= M_PI/2 ){ /* * We are in the "FROM" half-plane: */ vor_orient = -1; diff = -diff; } else { /* * We are in the "TO" half-plane. Reduce * angular reviation relative to the * complementar radial OBS+M_PI: */ vor_orient = 1; if( diff > 0 ) diff = diff - M_PI; else diff = M_PI + diff; } } /* Draw CDI segment: */ VIdentMatrix(&m); /* Little hack for LOC CDI: increase sensibility from CDI_DOT_STEP to 0.4 DEG/DOT: */ if( wp->station->type & navaid_LOC ){ diff *= CDI_DOT_STEP / units_DEGtoRAD(0.4); } if( diff > CDI_MAX_DEVIATION ) dev = CDI_MAX_DEVIATION; else if( diff < -CDI_MAX_DEVIATION ) dev = -CDI_MAX_DEVIATION; else dev = diff; VTranslate(&m, CDI_DOT_K * dev, 0.0, 0.0); VRotate(&m, ZRotation, units_DEGtoRAD(wp->obs) - hdg); VScaleMatrix(&m, obs_scale, obs_scale, obs_scale); VTranslate(&m, xc, yc, -1.0); vpath_stroke( cdi_segment, &m, w, magenta); /* Draw VOR TO/FROM indicator: */ if( vor_orient != 0 ){ VIdentMatrix(&m); if( vor_orient == 1 ){ VRotate(&m, ZRotation, units_DEGtoRAD(wp->obs) - hdg); } else if( vor_orient == -1 ){ VRotate(&m, ZRotation, units_DEGtoRAD(wp->obs) - hdg + M_PI); } VScaleMatrix(&m, obs_scale, obs_scale, obs_scale); VTranslate(&m, xc, yc, -1.0); vpath_stroke( vor_orientation, &m, w, white); } } /* Draw the Glide Slope scale: */ VIdentMatrix(&m); VScaleMatrix(&m, gs_scale, gs_scale, gs_scale); VTranslate(&m, xc + 1.15*r, yc, -1.0); vpath_stroke(gs_dots, &m, w, white); /* Draw the Glide Slope Deviation Indicator: */ if( wp->station != NULL && wp->station->type & navaid_GS ){ if( ! hsi_gs_offset(u, &gs_offset) ) { } gs_offset = -gs_offset; if( gs_offset > GS_OFFSET_MAX ) dev = GS_OFFSET_MAX; else if( gs_offset < -GS_OFFSET_MAX ) dev = -GS_OFFSET_MAX; else dev = gs_offset; VIdentMatrix(&m); VTranslate(&m, 0.0, -dev*GS_OFFSET_K, 0.0); VScaleMatrix(&m, gs_scale, gs_scale, gs_scale); VTranslate(&m, xc + 1.10*r, yc, -1.0); vpath_stroke(gs_pointer, &m, w, magenta); } } void hsi_free(viewer *u) { hsi_data *hsi; hsi = u->hsi; if( hsi == NULL ) return; hsi->next = free_list; free_list = u->hsi; u->hsi = NULL; } acm-6.0_20200416/src/acm/radar.h0000644000000000000000000000331713101126165014364 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #ifndef _radar_h #define _radar_h #include "pm.h" #ifdef radar_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Set the display of the "radar" panel slot. * @param c * @param mode One of the RM_* constants. */ EXTERN void radar_setMode(craft * c, int mode); /** * Compute how much radar energy the emitter craft puts on each other player * and which other players are visible in the radar of the emitter. * Calculates: [craft].rinfo (visible targets) and [craft].rval (received energy * from each other player). * @param emitter */ void radar_calculateEmissions(craft * emitter); EXTERN void radar_droneUpdate(craft * c); /** * Draw the radar display or do nothing if radar disabled */ EXTERN void radar_update(craft * c, viewer * u); /* * Draw the TEWS display or do nothing if radar disabled */ EXTERN void radar_updateTEWS(craft * c, viewer * u); /* * Get a new radar target */ EXTERN int radar_getNewTarget(craft * c); #undef EXTERN #endif acm-6.0_20200416/src/acm/effects.h0000644000000000000000000000245413175511064014722 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #ifndef _effects_h #define _effects_h #include "pm.h" #ifdef effects_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Add a new "explosion craft" to the list of aircraft. * @param loc Location of the explosion (geocentric, m). * @param vel Initial velocity of the explosion (NED, ft/s). * @param s_meters Overall radius of the explosion (m). * @param dur1 Dust duration (s). * @param dur2 Flame duration (s). */ EXTERN void effects_new_explosion(VPoint * loc, VPoint *vel, double s_meters, double dur1, double dur2); #undef EXTERN #endif acm-6.0_20200416/src/acm/damage.c0000644000000000000000000001576313646045023014523 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include "pm.h" #include "sounds.h" #include "inventory.h" #include "../util/prng.h" #define damage_IMPORT #include "damage.h" static long selectSystem(void) /* Randomly select a subsystem to receive damage. Each subsystem has its own probability to be damaged, the total probabbility being, obviously, 100%. Return: damaged subsystem mask. */ { double r; long i; r = prng_getDouble(); if (r < 0.25) /* 25% */ i = SYS_ENGINE1; else if (r < 0.35) /* 10% */ i = SYS_RADAR; else if (r < 0.40) /* 5% */ i = SYS_TEWS; else if (r < 0.45) /* 5% */ i = SYS_HYD1; else if (r < 0.50) /* 5% */ i = SYS_HYD2; else if (r < 0.53) /* 3% */ i = SYS_GEN1; else if (r < 0.56) /* 3% */ i = SYS_GEN2; else if (r < 0.61) /* 5% */ i = SYS_FLAPS; else if (r < 0.69) /* 8% */ i = SYS_SPEEDBRAKE; else if (r < 0.78) /* 9% */ i = SYS_FUEL; else if (r < 0.85) /* 7% */ i = SYS_HUD; else if (r < 0.90) /* 5% */ i = SYS_LEFTMAIN; else if (r < 0.95) /* 5% */ i = SYS_RIGHTMAIN; else if (r < 0.97) /* 2% */ i = SYS_WINGS; else /* 3% */ i = SYS_NOSEGEAR; return i; } /** * Set damage to the specified subsystem. If the subsystem is already * damaged does nothing, but if it is a fuel leak (SYS_FUEL) then * increments the current fuel leak rate. Also accounts for failures to * other subsystems that depends on this one. */ static void damageSystem(craft * c, long sys) { if ((c->damageBits & sys) == 0 || (sys == SYS_FUEL)) { c->damageBits |= sys; switch (sys) { case SYS_ENGINE1: c->throttle = 0; break; case SYS_RADAR: c->curRadarTarget = -1; break; case SYS_FUEL: /* * Fuel leaks can be up to 40 pounds per second here. */ c->leakRate += 40.0 * prng_getDouble(); break; case SYS_HYD1: case SYS_HYD2: if ( c->damageBits & SYS_HYD1 && c->damageBits & SYS_HYD2 ) { c->damageBits |= SYS_SPEEDBRAKE; c->damageBits |= SYS_FLAPS; } break; case SYS_GEN1: case SYS_GEN2: if ( c->damageBits & SYS_GEN1 && c->damageBits & SYS_GEN2 ) { c->damageBits |= (SYS_HUD | SYS_RADAR | SYS_TEWS); } break; } } } #define DAMAGE_DEBUG 0 /** * Target craft hit with d points of damage. Every point has 15% of * probability to damage some subsystem, and 85% of probability to be * absorbed by the aircraft frame. On structural damage, decrements * target->structurePts. * @param target Hit target aircraft. * @param d Points of damage. * @return True if the damage has been adsorbed and the target can still live; * this means that human players can only die falling to the ground after a * severe structural damage. * False only if the craft is a drone and all the target->structurePts are * exhausted, then the drone should be killed immediately. */ static _BOOL damage_absorbDamage(craft * target, int d) { double n, x; long sys; if( DAMAGE_DEBUG ) printf("damage_absorbDamage, %d points\n", d); /* * Actual damage sustained is adjusted by a damage factor that forms a * bell curve centered around 0.75 * d. */ x = 0.5*(prng_getDouble() + prng_getDouble()) + 0.25; d = (int) (d * x + 0.5); if (d > 0) { sounds_playSound(target, sounds_Explosion, FALSE); } for (; d > 0; --d) { /* * For each damage point absorbed, there is a 15 percent chance that * it will be absorbed by some subsystem other than the actual * airframe. */ if (prng_getDouble() <= 0.15) { if( DAMAGE_DEBUG ) printf("damage_absorbDamage: subsystem damaged\n"); sys = selectSystem(); damageSystem(target, sys); } /* * For each point absorbed by the airframe, there is a 20% chance that * it'll be absorbed by the wing and induce a rolling moment or a 10 * percent chance that it will hit a horizontal stabilizer and induce * a pitching and rolling moment. */ else { if ((n = prng_getDouble()) <= 0.20) { if( DAMAGE_DEBUG ) printf("damage_absorbDamage: damaged CL\n"); target->damageCL += (prng_getDouble() - 0.5) * 0.20; } else if (n <= 0.30) { if( DAMAGE_DEBUG ) printf("damage_absorbDamage: damaged CL, CM\n"); target->damageCL += (prng_getDouble() - 0.5) * 0.10; target->damageCM += (prng_getDouble() - 0.5) * 0.20; } if( target->structurePts <= 1 ){ target->structurePts = 0; damageSystem(target, SYS_WINGS); if( target->type == CT_PLANE ) return TRUE; /* human players fall to ground :-) */ else return FALSE; /* destroy immediately drones */ } if( DAMAGE_DEBUG ) printf("damage_absorbDamage: some structural damage\n"); target->structurePts--; } } return TRUE; } int damage_absorbDISDamage(craft * target, dis_entity_type *warhead_dis_type, u_short warhead_type, u_short fuze_type, double distance_meters, double velocity_meters_per_sec, double *explosion_diameter_meters) { int i; int damage_points; munition_map *pmm; *explosion_diameter_meters = 0.0; for(i = 0; ; i++){ pmm = inventory_getMunition(i); if( pmm == NULL ) break; if (dis_entityWildcardMatch(warhead_dis_type, &pmm->entity_type, &pmm->entity_mask)) { if (pmm->warhead_mask == 0 || pmm->warhead_type == warhead_type) { if( DAMAGE_DEBUG ) printf("damage_absorbDISDamage: hit by %s\n", dis_entityTypeToString(&pmm->entity_type)); /* found a match; assess damage */ if (pmm->kinetic_flag) { /* Kinetic warhead: */ damage_points = (int) (0.5 * pmm->damage_factor * velocity_meters_per_sec * velocity_meters_per_sec + 0.5); if( DAMAGE_DEBUG ) printf("damage_absorbDISDamage: kinetic, damage factor %g, velocity %g m/s\n", pmm->damage_factor, velocity_meters_per_sec); } else { /* Blast warhead: */ damage_points = (int) ( pmm->damage_factor / (distance_meters * distance_meters + 1.0) + 0.5 ); if( DAMAGE_DEBUG ) printf("damage_absorbDISDamage: blast, damage factor %g, distance %g m\n", pmm->damage_factor, distance_meters); } *explosion_diameter_meters = pmm->explosion_diameter_meters; return damage_absorbDamage(target, damage_points); } } } printf ("Warning: munition entity lookup failed\n"); return 1; } void damage_reset(craft * c) { c->damageBits = c->cinfo->damageBits; c->structurePts = c->cinfo->structurePts; c->leakRate = 0.0; c->damageCL = 0.0; c->damageCM = 0.0; } acm-6.0_20200416/src/acm/hud.h0000644000000000000000000000231213063670321014052 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #ifndef _hud_h #define _hud_h #include "pm.h" #ifdef hud_IMPORT #define EXTERN #else #define EXTERN extern #endif EXTERN void hud_enable(viewer *u); EXTERN void hud_disable(viewer *u); EXTERN void hud_draw(viewer *u); EXTERN void hud_timer_toggle(viewer *u); EXTERN void hud_free(viewer *u); /* FIXME: these functions should not stay in this module: */ EXTERN void doFlightStatusPage(craft * c, viewer * u); EXTERN void FSPageToggle(void); #undef EXTERN #endif acm-6.0_20200416/src/acm/draw.h0000644000000000000000000000505613175036565014251 0ustar rootroot/* * ACM - Drawing utilities * Copyright (C) 2007 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /** * This module implements some drawing procedures based on the Vlib * module. The main difference is that floating point numbers are used * instead of integer numbers, and the list of segments gets allocated * dynamically. * * Every path, once generated, can be draw on the screen several times, in * different positions and with some transformation. */ #ifndef _DRAW_H #define _DRAW_H #include "../V/Vlib.h" #ifdef draw_IMPORT #define EXTERN #else #define EXTERN extern #endif typedef struct draw_Type draw_Type; /** * Returns a new, empty path. Can be released with draw_free() or disposed off * with memory_dispose(). * @return */ EXTERN draw_Type * draw_new(void); /** * Releases a path which is not going to be used anymore. Released paths are * saved in a spare list to be reused later. * @param dd */ EXTERN void draw_free(draw_Type *dd); EXTERN void draw_segment(draw_Type *dd, double x1, double y1, double x2, double y2); EXTERN void draw_rect(draw_Type *dd, double x1, double y1, double x2, double y2); EXTERN void draw_circle(draw_Type *dd, double xo, double yo, double r); EXTERN void draw_arc(draw_Type *dd, double xo, double yo, double r, double a1, double a2); /** * Creates a pointer of length l with pivot at (xo,yo) and rotated 'a' RAD. * a=0 means the pointer is oriented toward right, and it rotates * clockwise on the screen. */ EXTERN void draw_pointer(draw_Type *dd, double xo, double yo, double a, double l); /** Send draw data to the specified viewport using the specified color */ EXTERN void draw_stroke(draw_Type *dd, Viewport *v, Alib_Pixel color); /** FIXME: it does not work yet */ EXTERN void draw_fill(draw_Type *dd, Viewport *v, Alib_Pixel color); EXTERN void draw_string_centered(Viewport *v, double xo, double yo, double fh, char *s, Alib_Pixel color); #undef EXTERN #endif /* _DRAW_H */ acm-6.0_20200416/src/acm/flaps.h0000644000000000000000000000212313063670321014377 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #ifndef _flaps_h #define _flaps_h #include "pm.h" #ifdef flaps_IMPORT #define EXTERN #else #define EXTERN extern #endif EXTERN void flaps_update(craft * c); EXTERN int flaps_down(craft * c); EXTERN int flaps_up(craft * c); EXTERN int flaps_speed_brakes_extend(craft * c); EXTERN int flaps_speed_brakes_retract(craft * c); #undef EXTERN #endif acm-6.0_20200416/src/acm/drone.c0000644000000000000000000004514513175036654014420 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1996 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /* * The original "Smart Drone" code was created by * Jason Nyberg (nyberg@ctron.com). Enhancements added by Riley Rainey. * * 2007-07-23 Umberto Salsi * - made a proper "module" * - drone now has a data structure by its own (see (craft)->drone field) * - the 'aggressiveness' now sets the % of the max vertical load */ #include #include #include "../util/error.h" #include "../util/memory.h" #include "../util/prng.h" #include "../util/units.h" #include "pm.h" #include "alarm.h" #include "aps.h" #include "browse.h" #include "dis_if.h" #include "flaps.h" #include "gear.h" #include "inventory.h" #include "players.h" #include "prompt.h" #include "radar.h" #include "weapon.h" #define drone_IMPORT #include "drone.h" #include "aps.h" static drone_Mode mode = drone_DOG_FIGHT_MODE; static double aggressiveness = 0.5; /* Drone status: */ #define DM_ATTACK 0 /* normal drone attack mode */ #define DM_RETURN 1 /* return to drone activation point (interceptStartPoint) */ #define DM_RETURN_CAPTURED 2 /* in return mode and moving towards return pt */ #define MIN_VEL 300 /* min speed (KIAS) */ #define MED_VEL 350 /* medium speed (KIAS) */ #define MAX_VEL 400 /* max speed (KIAS) */ #define MIN_ALTITUDE 15000 /* min altitude (ft) */ /** * Drone state. */ typedef struct _drone_data { /* * If takes commands over existing player's aircraft, here saves the original * update procedure before replacing with the drone specific algorithm; * restores when user leaves the drone mode and gets back commands. */ char * (*update_original)(craft *c); int curOpponent; /* who this drone is trying to kill; -1 = none */ int curDroneMode; /* drone operating mode (DM_* constants ) */ int holdCount; /* non-zero when drones holding fire */ VPoint interceptStartPoint; /* geocentric coordinates location where an end-game intercept was initiated */ } drone_Type; void drone_set_mode(drone_Mode drone_mode) { mode = drone_mode; } void drone_set_aggressiveness(double a) { if( a < 0.05 ) a = 0.05; else if( a > 1.0 ) a = 1.0; aggressiveness = a; } static char *drone_update(craft *c); static void drone_kill(craft *c, char *reason); static craft * create_new_drone_craft(craft * p, int force, char *model) { int i; craft *c; VPoint s, tmp; double v; double disLocation[3]; double disZeroVec[3]; double disOrientation[3]; /* Allocate new craft data structure: */ for (i = 0; i < manifest_MAXPLAYERS; ++i) { if (ptbl[i].type == CT_FREE) { break; } } if (i == manifest_MAXPLAYERS) return NULL; c = &ptbl[i]; /* Set craft state: */ c->pIndex = i; c->type = CT_DRONE; c->force = force; c->createTime = curTime; c->vl = NULL; c->trihedral = p->trihedral; c->Cg = p->Cg; c->VT = p->VT; c->Sg = p->Sg; c->w = p->w; c->terrain_altitude_timeout = curTime - 10.0; /* ensure will be updated */ /* c->terrain_altitude = UNKNOWN; */ c->XYZtoNED = p->XYZtoNED; c->air = p->air; c->mach = p->mach; c->G = p->G; c->linAcc = p->linAcc; c->prevSg = p->prevSg; c->p = p->p; c->q = p->q; c->r = p->r; c->pitchComm = 0.0; c->rollComm = 0.0; c->steerComm = 0.0; c->rudderComm = 0.0; c->throttleComm = 32768; c->throttle = 32768; c->Se = p->Se; c->Sa = p->Sa; c->Sr = p->Sr; c->SeTrim = 0.0; c->SaTrim = 0.0; c->curHeading = p->curHeading; c->curPitch = p->curPitch; c->curRoll = p->curRoll; c->curThrust = 0.0; c->curFlap = 0.0; c->flapSetting = 0.0; c->curSpeedBrake = 0.0; c->speedBrakeSetting = 0.0; c->throttle = 32768; c->rpm = 1.0; c->alpha = p->alpha; c->beta = p->beta; c->fuel = 0.0; c->payload = 0.0; c->flags = 0; c->damageBits = 0; c->structurePts = 0; c->leakRate = 0.0; c->damageCL = 0.0; c->damageCM = 0.0; c->radarMode = RM_ACM; c->nextRadarTime = 0.0; c->cinfo = inventory_craftTypeSearchByZoneAndName(NULL, model); sprintf(c->name, "Drone%d", i); c->curRadarTarget = -1; c->targetDistance = 0.0; c->targetClosure = 0.0; /* skip fields: relPos, rval */ pm_hud_strings_alloc(c); /* skip fields: curWeapon, station */ /* skip fields: rinfo, rtop */ c->showMag = FALSE; c->aps = NULL; c->curThrust = (c->cinfo->thrust) (c); gear_allocate(c); gear_up(c); if( mode == drone_DOG_FIGHT_MODE ){ /* Position the drone about 1500 meters ahead of the player's craft. */ s.x = 1500.0 + 500.0 * prng_getDouble2(); s.y = 200.0 * prng_getDouble2(); s.z = 200.0 * prng_getDouble2(); c->curHeading = pm_normalize_yaw( p->curHeading + units_DEGtoRAD(30.0) * prng_getDouble2() ); c->curRoll = 0.0; c->curPitch = units_DEGtoRAD(2.0); v = p->VT + 50.0 * prng_getDouble2(); VSetPoint(&c->Cg, v*cos(c->curHeading), v*sin(c->curHeading), 0.0); } else { /* mode == DRONE_HUNTING_MODE */ /* Position the drone up to 50 NM away, random altitude, random direction, random heading. */ s.x = 50000.0 * prng_getDouble2(); s.y = 50000.0 * prng_getDouble2(); s.z = 5000.0 - p->w.z + (11000.0 - 5000.0)/2.0 * prng_getDouble2(); c->curHeading = pm_normalize_yaw( 2*M_PI * prng_getDouble2() ); c->curRoll = 0.0; c->curPitch = units_DEGtoRAD(2.0); v = 350.0 + 50.0 * prng_getDouble2(); VSetPoint(&c->Cg, v*cos(c->curHeading), v*sin(c->curHeading), 0.0); } c->r = c->q = c->p = 0.0; VEulerToMatrix(c->curRoll, c->curPitch, c->curHeading, &(c->trihedral)); VTransform_(&s, &(p->trihedral), &tmp); /* convert NED (meters) to Geocentric (meters) */ VReverseTransform_(&tmp, &(c->XYZtoNED), &c->Sg); c->Sg.x += p->Sg.x; c->Sg.y += p->Sg.y; c->Sg.z += p->Sg.z; c->prevSg = c->Sg; c->update = drone_update; c->kill = drone_kill; earth_XYZToLatLonAlt(&c->Sg, &c->w); earth_generateWorldToLocalMatrix(&c->w, &c->XYZtoNED); /* * Rearm and fuel the aircraft. */ (*c->cinfo->resupply) (c); weapon_selectByName(c, weapon_AIM9M); /* will set properly next */ disLocation[0] = c->Sg.x; disLocation[1] = c->Sg.y; disLocation[2] = c->Sg.z; disZeroVec[0] = 0.0; disZeroVec[1] = 0.0; disZeroVec[2] = 0.0; disOrientation[0] = c->curHeading; disOrientation[1] = c->curPitch; disOrientation[2] = c->curRoll; dis_if_entityEnter(force, c, &c->cinfo->entityType, &c->cinfo->altEntityType, disLocation, disZeroVec, disZeroVec, disOrientation, disZeroVec, &c->disId); dis_if_setRadarMode(c, 1, 1); return c; } void drone_take_commands(craft *c) { drone_Type *dd; gear_up(c); flaps_up(c); flaps_up(c); flaps_up(c); flaps_up(c); flaps_speed_brakes_retract(c); flaps_speed_brakes_retract(c); flaps_speed_brakes_retract(c); flaps_speed_brakes_retract(c); aps_off(c); c->type = CT_DRONE; /* ignore = */ weapon_selectByName(c, weapon_AIM9M); dd = (drone_Type *) c->drone; if( dd == NULL ) dd = memory_allocate(sizeof(drone_Type), NULL); dd->curOpponent = -1; dd->curDroneMode = DM_ATTACK; dd->holdCount = 0; /* dd->inceptStartPoint = ignored in DM_ATTACK mode; */ c->drone = dd; dd->update_original = c->update; c->update = drone_update; } void drone_new(craft * p) { int force = p->force == DISForceOpposing? DISForceFriendly : DISForceOpposing; char *model = force == DISForceFriendly? "F-16" : "MiG-29"; craft *c = create_new_drone_craft(p, force, model); if( c == NULL ){ prompt_craft_print(p, "Memory exhausted -- can't create new drone"); return; } drone_take_commands(c); char s[100]; sprintf(s, "%s drone generated for %s practice [%d]", c->name, (mode == drone_DOG_FIGHT_MODE)? "dog fight" : "hunting", mode); prompt_craft_print(p, s); } void drone_release_commands(craft *c) { drone_Type *dd = c->drone; if( dd == NULL ) return; c->update = dd->update_original; memory_dispose(c->drone); c->drone = NULL; c->type = CT_PLANE; } void drone_reset_opponent(craft *c) { drone_Type *dd; if( c->drone == NULL ) return; dd = (drone_Type *) c->drone; dd->curOpponent = -1; dd->holdCount = 0; } /* * convert target plane coords from world to drone's */ static void myCoordSys(craft * c, craft * p, VPoint * pos, VPoint * vel) { VPoint tpos; VTransform(&p->prevSg, &c->XYZtoNED, &tpos); VReverseTransform_(&tpos, &c->trihedral, pos); VTransform_(&p->Cg, &c->XYZtoNED, &tpos); VReverseTransform_(&tpos, &c->trihedral, vel); } static void unholdFireAlarm(void *arg1, void *arg2) { craft *c = (craft *) arg1; drone_Type *dd; if( c->drone == NULL ) return; dd = (drone_Type *) c->drone; if (dd->holdCount > 0) { dd->holdCount--; } } /* * Dumbly choose the closest hostile plane to be target */ static int pickTarget(craft * c) { int i, target = -1; craft *p; double d, min; VPoint pos, vel; min = 100000000.0; for (i = 0, p = ptbl; i < manifest_MAXPLAYERS; ++i, ++p) { if ( p != c && p->force != c->force && (p->type == CT_PLANE || p->type == CT_DIS_PLANE || p->type == CT_DRONE) ) { myCoordSys(c, p, &pos, &vel); d = VMagnitude( &pos ); if (d < min) { min = d; target = p->pIndex; } } } return target; } /* * droneFlyTo * * Generate sitck/rudder controls to move the plane to the specified * geocentric point. */ static void droneFlyTo ( craft *c, VPoint *pos ) { double phi, rho, w, f, pitch_rate, roll_rate; craftType *p; VPoint q; /***** Example: climb toward north VPoint q; q.x = 100.0; q.y = 0.0; q.z = -20.0; VReverseTransform(&q, &c->trihedral, pos); *****/ /* Avoid too low altitudes */ if( c->w.z < units_FEETtoMETERS(MIN_ALTITUDE) ){ VTransform(pos, &c->trihedral, &q); if( q.z >= 0.0 ){ q.z = -0.5*sqrt(q.x*q.x + q.y*q.y); } VReverseTransform(&q, &c->trihedral, pos); } /* d = sqrt(pos->x * pos->x + pos->y * pos->y + pos->z * pos->z); */ /* * Compute total lift force 'f': */ p = c->cinfo; w = p->emptyWeight + c->fuel + c->payload; f = c->G.z * w; /* current vertical load (pounds) */ phi = atan2 ( pos->y, -pos->z ); /* * If the target is behind our 3/9-line, we are defensive. Pull maximum * G's into the target (after rolling into him). * * If we are behind of the target, perform pure pursuit (until the code * gets a bit smarter). */ if (f < -aggressiveness * p->maxLoadZPositive) { /* * Close to the positive structural load limit. */ if ( c->q > 0.0 ) pitch_rate = 0.95 * c->q; else pitch_rate = 0.0; } else if (f > aggressiveness * p->maxLoadZNegative) { /* * Close to the negative structural load limit. */ if ( c->q < 0.0 ) pitch_rate = 0.95 * c->q; else pitch_rate = 0.0; } else if (pos->x < 0.0) { /* * Target behind me. * Wait for lift vector to be close to where we want it before * pulling G's. */ if ((fabs(phi) > units_DEGtoRAD(130.0)) || fabs(phi) < units_DEGtoRAD(50.0)) { pitch_rate = units_DEGtoRAD(20.0); } else { pitch_rate = 0.0; } } else { rho = atan2(-pos->z, pos->x) - units_DEGtoRAD(2.0); if( rho > 0.0 ){ pitch_rate = fmin(rho, units_DEGtoRAD(20.0)); } else { pitch_rate = 0.0; } } c->pitchComm -= deltaT * (pitch_rate - c->q); if (c->pitchComm > 1.0) c->pitchComm = 1.0; else if (c->pitchComm < -1.0) c->pitchComm = -1.0; /* * Put the lift vector on the target. * A lot of conventional 1V1 air combat involves keeping your lift * vector on the target aircraft. Phi is the computed angle between our * target and the lift vector (simplified to be just the negative Z-axis). */ roll_rate = 0.5 * phi; if ( roll_rate > units_DEGtoRAD(30.0) ) roll_rate = units_DEGtoRAD(30.0); else if ( roll_rate < -units_DEGtoRAD(30.0) ) roll_rate = -units_DEGtoRAD(30.0); c->rollComm -= deltaT * (roll_rate - c->p); if (c->rollComm > 1.0) c->rollComm = 1.0; else if (c->rollComm < -1.0) c->rollComm = -1.0; /* * Don't use the rudder, for now. */ c->rudderComm = 0.0; /* * Adjust engine power */ if( c->IAS < units_KTtoFPS(MIN_VEL) ){ c->throttleComm = 32768; /* max power + AB */ pm_after_burner_on(c); } else if( c->IAS < units_KTtoFPS(MED_VEL) ){ c->throttleComm = 32768; /* max power */ pm_after_burner_off(c); } else if( c->IAS < units_KTtoFPS(MAX_VEL) ){ c->throttleComm = 32768/2; /* medium power */ pm_after_burner_off(c); } else { c->throttleComm = 32768/4; /* idle */ pm_after_burner_off(c); } } /* * Drone flight management in Attack Mode (this is most common) */ static int droneCalculationsAttackMode ( craft * c ) { drone_Type *dd; double htime; VPoint pos, vel; _BOOL doFire; dd = (drone_Type *) c->drone; /* * Our opponent has exited? Return to engagement initiation point. */ if ( (c->flags & FL_END_GAME_DRONE ) ) { if ( dd->curOpponent != -1 && ptbl[dd->curOpponent].type == CT_FREE ) { dd->curDroneMode = DM_RETURN; } } /* * No opponent, or opponent isn't there anymore */ else if (dd->curOpponent == -1 || ptbl[dd->curOpponent].type == CT_FREE) { dd->curOpponent = pickTarget(c); dd->holdCount = 0; } if (dd->curOpponent != -1) { myCoordSys(c, &(ptbl[dd->curOpponent]), &pos, &vel); droneFlyTo ( c, &pos ); /* * Fire at the target, if appropriate. * Tryes first with AIM-120, then AIM-9M. * * We'll have to figure out a way to do lead pursuit in order to * fire the cannon; we do pure pursuit now, which is the * (somewhat) right thing to fire a missile. */ if (dd->holdCount == 0 ) { /* Select weapon. Try AIM-120 first, then AIM-9M. */ if( weapon_getReadyStation(c, weapon_AIM120) >= 0 && weapon_selectByName(c, weapon_AIM120) ) doFire = TRUE; /* Uses AIM-120 */ else if( weapon_getReadyStation(c, weapon_AIM9M) >= 0 && weapon_selectByName(c, weapon_AIM9M) ) doFire = TRUE; /* Uses AIM-9M */ else doFire = FALSE; /* No suitable weapon available. */ if( doFire && weapon_displaySelected(c, (viewer *) NULL, 0, 0) == 1) { weapon_fire(c); htime = 10.0 + 10.0 * prng_getDouble2(); alarm_add(htime, unholdFireAlarm, c, NULL); dd->holdCount++; } } } return 0; } /* * Drone flight management in Return Modes */ static int droneCalculationsReturnMode ( craft * c ) { drone_Type *dd; VPoint tpos, pos, vel; double dist_meters, closure_meters_per_sec; int result = 0; dd = (drone_Type *) c->drone; /* * Generate body relative position of return point */ VTransform(&dd->interceptStartPoint, &c->XYZtoNED, &tpos); VReverseTransform_(&tpos, &c->trihedral, &pos); /* * Convert NED velocity to body-relative velocity */ VReverseTransform_(&c->Cg, &c->trihedral, &vel); dist_meters = VMagnitude( &pos ); closure_meters_per_sec = ( vel.x * pos.x + vel.y * pos.y + vel.z * pos.z ) / dist_meters; droneFlyTo ( c, &pos ); /* * If we are in return mode and turned within 30 degrees towards * the return point, enter the "return-captured" mode. */ if ( dd->curDroneMode == DM_RETURN ) { if ( closure_meters_per_sec > 0.866 * units_FEETtoMETERS(c->VT) ) { dd->curDroneMode = DM_RETURN_CAPTURED; } } /* * If we are in return-capture mode and start to move away from the * intercept point, then we're done; destroy the aircraft. */ else { if ( closure_meters_per_sec < 0.0 ) { result = 1; } } return result; } /** * Update flight and combat management of the drone. * @return FALSE stands for mission in progress, TRUE for drone self-destroy * request on mission concluded. */ static _BOOL drone_calculations( craft * c ) { drone_Type *dd; dd = (drone_Type *) c->drone; switch (dd->curDroneMode) { case DM_ATTACK: return droneCalculationsAttackMode ( c ); case DM_RETURN: return droneCalculationsReturnMode ( c ); case DM_RETURN_CAPTURED: return droneCalculationsReturnMode ( c ); default: error_internal("dd->curDroneMode=%d", dd->curDroneMode); } } static char *drone_update(craft *c) { if( drone_calculations(c) ) return "mission completed, self destroy"; char *killReason = pm_flightCalculations(c); if (killReason != NULL) return killReason; weapon_update(c); flaps_update(c); radar_droneUpdate(c); dis_if_updateLocal(c); return NULL; } static void drone_kill(craft *c, char *reason) { players_kill(c, reason); } void drone_endGameDistanceCheck(void * p1, void *p2) { double range_meters; VPoint del; craft *p; craft *c = (craft * ) p1; viewer *u = (viewer *) p2; int i; int done = 0; double threshold_meters; if ( c->type == CT_DIS_PLANE && (c->flags & FL_END_GAME_DRONE) ) { /* * Determine the appropriate range threshold; if one was specified * on the command line, use that. Otherwise use the lock range from * the aircraft definition. */ if ( end_game_threshold_meters <= 0.0 ) { threshold_meters = units_FEETtoMETERS( c->cinfo->radarTRange * units_NmToFeetFactor ); } else { threshold_meters = end_game_threshold_meters; } for ((i = 0, p = ptbl); (i < manifest_MAXPLAYERS) && ( ! done ); (++i, ++p)) { /* * Skip this entry if: * * 1) It's the entry for our own aircraft. * 2) The craft isn't a hostile. */ if (p->pIndex == c->pIndex || c->force == p->force ) { continue; } if ( p->type == CT_PLANE || p->type == CT_DIS_PLANE || p->type == CT_DRONE) { VSub(&p->Sg, &c->Sg, &del); range_meters = VMagnitude( &del ); /* * If the distance is within our threshold, then * initiate a control request. */ if ( range_meters <= threshold_meters ) { /* * Record start point of engagement; we will return * to this point after a kill. */ if( c->drone != NULL ) ((drone_Type *)(c->drone))->interceptStartPoint = c->Sg; dis_if_requestControl ( dis_if_findEntityByID(c->disId), browse_controlRequestCallback, u ); done = 1; } } } } /* * This craft is no longer a DIS plane. No need to continue proximity * testing. */ else { done = 1; } /* * If nothing was within our threshold range, look again after one * second has elapsed. */ if ( ! done ) { alarm_add(1.0, drone_endGameDistanceCheck, p1, p2); } } acm-6.0_20200416/src/acm/windows.c0000644000000000000000000002165713174072165015001 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991,1992,1997 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include "../V/Vlib.h" #include "pm.h" #include "hud.h" #include "instruments.h" #include "prompt.h" #define windows_IMPORT #include "windows.h" #define WIN_MIN_WIDTH 150 #define WIN_MIN_HEIGHT 150 #define HDG_LENGTH (6*33+1) #define HDG_MIN_INTERVAL 500 #define HDG_MIN_SIZE 5 #define HDG_MAJ_INTERVAL 1000 #define HDG_MAJ_SIZE 10 #define HDG_DIVISOR 1000.0 #define HDG_FORMAT "%2.2g" #define VEL_LENGTH ALT_LENGTH #define VEL_ORIENT 0 #define VEL_SCALE (153.0 / (double) VEL_LENGTH) #define VEL_INDEX_SIZE 32 #define VEL_MIN_INTERVAL 10 #define VEL_MIN_SIZE 9 #define VEL_MAJ_INTERVAL 50 #define VEL_MAJ_SIZE 17 #define VEL_DIVISOR 10.0 #define VEL_FORMAT "%3.3g" #define ALT_LENGTH 219 #define ALT_ORIENT scale_ORIENT_RIGHT #define ALT_SCALE (1530.0 / (double) ALT_LENGTH) #define ALT_INDEX_SIZE 32 #define ALT_MIN_INTERVAL 100 #define ALT_MIN_SIZE 9 #define ALT_MAJ_INTERVAL 500 #define ALT_MAJ_SIZE 17 #define ALT_DIVISOR 1000.0 #define ALT_FORMAT "%4.3g" #define HUD_OFFSET units_DEGtoRAD(3.0) /* HUD drawing angular offset vs. nose pointer. Real HUD devices offer a quite small angle of view, limited to about +/-6 DEG. This offset angle allows to organize the drawing around a point that is so many DEG below the nose. Because the AoA is commonly between 3 and 4 DEG, looking at the center of the HUD drawing the pilot will see the point toward he is actually flying or it is aiming to. */ static int mymin(int a, int b){ if(a<=b) return a; else return b; } void windows_set_layout(craft * c, viewer * u, int width, int height, _BOOL hud_mode) { double xres, yres, eye, xscale, yscale; int w, xo, yo, stripe_height; Alib_Rect view; void set_slot(Alib_Rect *r, int row, int col) { Alib_setRect(r, xo + col * w, yo - row * w - w, xo + col * w + w, yo - row * w); } if( width < WIN_MIN_WIDTH ) width = WIN_MIN_WIDTH; if( height < WIN_MIN_HEIGHT ) height = WIN_MIN_HEIGHT; if( hud_mode ){ /* HUD mode: at least 2/3 of the vertical space to the cockpit view */ w = mymin(width / 5, height / 3); stripe_height = 0; Alib_setRect(&view, 0, 0, width, height - w); Alib_setRect(&u->stripe, 0, 0, 0, 0); } else { /* Classic instruments: at least 1/3 of the vertical space to the cockpit view. The stripe is 1/8 of the slot. */ w = mymin(width / 5, (int) (height * 2.0/3.0 / (1.0 + 1.0 + 1.0/8.0))); stripe_height = w/8; Alib_setRect(&view, 0, 0, width, height - stripe_height - w - w); Alib_setRect(&u->stripe, 0, view.b.y, width, height - 2*w); } /* Open the Viewport if required, but set dummy parameters. FIXME: the Viewport should be opened or resized only after all the layout has been calculated; I open it here just because I need the screen resolution. The screen resolution is a property of the window, so it should stay in Alib since it may be useful for 2D graphics too. */ if( u->v == NULL ){ Alib_Rect r; Alib_setRect(&r, 0, 0, width, height); u->v = Vlib_new(u->gui, u->w, &r, &(Alib_Point){0,0}, 1.0); } xres = u->v->xres / 100; /* horiz. screen resolution (pixels/cm) */ yres = u->v->yres / 100; /* vert. screen resolution (pixels/cm) */ /* Apply zoom factor to actual eye distance from screen */ eye = eye_to_screen_cm * u->zoom/100.0; /* Resize AWindow. This must be done before resizing Viewport because this latter compute its rect field as intersection with AWindow. */ Alib_resize(u->w, width, height); /* Resize Viewport */ { double h; Alib_Point focus; /* Distance of the focus projection from bottom border (pixels): */ h = yres * eye * tan(downward_view_angle_rad); /* For higher zoom factors the pilot may end up looking the terrain rather than the target craft. Correct: */ if( u->zoom > 200 && view.b.y - h < 0.0 ) h = view.b.y; /* Nose pointer position (pixel): */ Alib_setPoint(&focus, RectMiddleX(view), view.b.y - h); /* Organize HUD drawing center HUD_OFFSET DEG below the horizon: */ u->hud_yCenter = focus.y + yres * eye * tan(HUD_OFFSET); VResizeViewport(u->v, &view, &focus, 0.01*eye); } /* (xo,yo) is the left-bottom corner of the panel: */ xo = (width - 5 * w) / 2; yo = height; set_slot(&u->lights, 0, 0); set_slot(&u->tuner, 0, 1); set_slot(&u->indicator, 0, 2); set_slot(&u->gear, 0, 3); set_slot(&u->engine, 0, 4); set_slot(&u->turn, 1, 0); set_slot(&u->anemometer, 1, 1); set_slot(&u->attitude, 1, 2); set_slot(&u->altimeter, 1, 3); set_slot(&u->vsi, 1, 4); /* To save space, the radar altimeter occupies the right part of the lights slot. So, reduce lights slot width: */ { int h; h = (int) (0.2 * w); u->radar_altimeter = u->lights; u->radar_altimeter.a.x = u->lights.b.x - h; u->lights.b.x -= h; } /* Scale factor for HUD graphics. FIXME. The magic numeric factor below follows from an "experimental" measurement and it accounts for the fixed layout under which the screen was originally designed. A more elegant, deterministic formula would require to eliminate all the fixed constants that appear in the renderer and HUD modules. */ xscale = 0.5 * 1.53e-3 * eye * xres; yscale = 0.5 * 1.53e-3 * eye * yres; u->xscaleFactor = xscale; u->yscaleFactor = yscale; /* Fill in the scale structures for the airspeed/altitude HUD scales. */ u->altScale.xorg = u->v->focus.x + (int) (xscale * 160); u->altScale.length = (int) (ALT_LENGTH * yscale); u->altScale.yorg = u->hud_yCenter + (u->altScale.length / 2); u->altScale.orientation = ALT_ORIENT; u->altScale.scale = ALT_SCALE / yscale; u->altScale.minorInterval = ALT_MIN_INTERVAL; u->altScale.minorSize = (int) (ALT_MIN_SIZE * yscale); u->altScale.majorInterval = ALT_MAJ_INTERVAL; u->altScale.majorSize = (int) (ALT_MAJ_SIZE * yscale); u->altScale.indexSize = (int) (ALT_INDEX_SIZE * xscale); u->altScale.divisor = ALT_DIVISOR; u->altScale.format = ALT_FORMAT; u->altScale.pixel = HUDColor; u->altScale.fontSize = (int) (14.0 * xscale + 0.5); u->velScale.xorg = u->v->focus.x - (int) (xscale * 160); u->velScale.length = (int) (VEL_LENGTH * yscale); u->velScale.yorg = u->hud_yCenter + (u->velScale.length / 2); u->velScale.orientation = VEL_ORIENT; u->velScale.scale = VEL_SCALE / yscale; u->velScale.minorInterval = VEL_MIN_INTERVAL; u->velScale.minorSize = (int) (VEL_MIN_SIZE * yscale); u->velScale.majorInterval = VEL_MAJ_INTERVAL; u->velScale.majorSize = (int) (VEL_MAJ_SIZE * yscale); u->velScale.indexSize = (int) (VEL_INDEX_SIZE * xscale); u->velScale.divisor = VEL_DIVISOR; u->velScale.format = VEL_FORMAT; u->velScale.pixel = HUDColor; u->velScale.fontSize = (int) (14.0 * xscale + 0.5); /* Compass scale in HUD: */ u->hdgScale.xorg = u->v->focus.x - (int) (xscale * HDG_LENGTH / 2.0 + 0.5); u->hdgScale.yorg = u->hud_yCenter - u->velScale.length / 2 - 130.0 * yscale; u->hdgScale.length = (int) (HDG_LENGTH * xscale); u->hdgScale.orientation = scale_ORIENT_LEFT; /* really orient TOP */ u->hdgScale.scale = (2727.0 / (double) HDG_LENGTH) / xscale; u->hdgScale.minorInterval = HDG_MIN_INTERVAL; u->hdgScale.minorSize = (int) (HDG_MIN_SIZE * xscale); u->hdgScale.majorInterval = HDG_MAJ_INTERVAL; u->hdgScale.majorSize = (int) (HDG_MAJ_SIZE * xscale); u->hdgScale.indexSize = (int) (10 * yscale); u->hdgScale.divisor = HDG_DIVISOR; u->hdgScale.format = HDG_FORMAT; u->hdgScale.pixel = HUDColor; u->hdgScale.fontSize = (int) (14.0 * xscale + 0.5); /* Clean instruments panel area */ { Alib_Rect r; Alib_setRect(&r, 0, view.b.y, width, height); Alib_setClipRect(u->w, &r); Alib_fillRect(u->w, &r, panelBackgroundColor); } /* Disable/Enable instruments: */ if( hud_mode ){ instruments_disable(u); hud_enable(u); } else { hud_disable(u); instruments_enable(u); } u->hud_mode = hud_mode; } static void windows_setZoom(viewer *u, int zoom) { if( 91 <= zoom && zoom <= 109 ) zoom = 100; else if( zoom < 10 ) zoom = 10; else if( zoom > 400 ) zoom = 400; if( zoom != u->zoom ){ u->zoom = zoom; windows_set_layout(u->c, u, gui_getWidth(u->gui), gui_getHeight(u->gui), u->hud_mode); } char s[20]; sprintf(s, "%d%%", u->zoom); prompt_viewer_print(u, s); } void windows_zoom_in(viewer *u) { windows_setZoom(u, 12*u->zoom / 10); } void windows_zoom_out(viewer *u) { windows_setZoom(u, 10*u->zoom / 12); } acm-6.0_20200416/src/acm/panel.c0000644000000000000000000005054313172244100014366 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 2008 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include "../util/error.h" #include "../util/memory.h" #include "../util/units.h" #include "adf.h" #include "aps.h" #include "hsi.h" #include "pm.h" #include "damage.h" #include "draw.h" #include "planes.h" #include "radar.h" #include "terrain.h" #include "vpath.h" #include "gear.h" #define panel_IMPORT #include "panel.h" #define GEARDOWN (M_PI / 2.0) #define FLAP_ANGLE_SCALE 2.0 /* The angular deflection of the flaps is amplified for readability: (actual drawing angle) = FLAP_ANGLE_SCALE * (actual flaps deflection) */ #define MAX_BANK_ANGLE_SCALE 9.0 #define MAX_BANK_ANGLE_OFFSET units_DEGtoRAD(-225) /* The max angle of bank scale ranges from 5 to 25 DEG with stepd of 5 DEG. For readability, the scale is expanded and rotated so that 5 DEG appears to the left, and 25 DEG to the right. These are the coefficients of the linear transformation: (actual drawing angle) = MAX_BANK_ANGLE_OFFSET + MAX_BANK_ANGLE_SCALE * (current max bank angle) */ #define LIGHTS_N 14 /* max no. of lights allowed in the lights panel */ static struct { long mask; char *name; int blink; /* does this lights blink when on? */ } *pptr, panelVec[] = { /* Sub-system failure indicators: */ { SYS_ENGINE1, "OIL", TRUE }, { SYS_HYD1, "HYD1", TRUE }, { SYS_HYD2, "HYD2", TRUE }, { SYS_GEN1, "GEN1", TRUE }, { SYS_GEN2, "GEN2", TRUE }, { SYS_FLAPS, "FLAP", TRUE }, { SYS_SPEEDBRAKE, "SPBRK", TRUE }, { SYS_RADAR, "RADAR", TRUE }, { SYS_TEWS, "TEWS", TRUE }, { SYS_HUD, "HUD", TRUE }, /* Status and warning indicators: */ { FLAG_MAX_G_LOAD, "G-LOAD", TRUE }, { FLAG_LOWFUEL, "FUEL", FALSE }, { FLAG_SPEEDBRAKE, "SPD BRK", FALSE }, { FLAG_WHEELBRAKE, "BRAKES", FALSE }, { 0, (char *) 0 } }; static vpath_Type *panel_fixed = NULL; static vpath_Type *panel_flap = NULL; static vpath_Type *panel_bank_pointer = NULL; static vpath_Type *panel_handle_up = NULL; static vpath_Type * radar_altimeter_scale = NULL; /* The radar-altimeter scale is 1.0 wide. The zero altitude is the line between (0,0) and (1,0); the 100 ft mark is a line between (0,1) and (1,1); the 200 ft mark is at (0,2)-(1,2) and so on. Above 500 ft the step becomes 200 ft. So in general the altitude h (ft) is located at y = -h/100 if h <= 500 ft y = -5 - (h-500)/200 if h > 500 ft */ static void panel_cleanup() { memory_dispose(panel_fixed); memory_dispose(panel_flap); memory_dispose(panel_bank_pointer); memory_dispose(panel_handle_up); memory_dispose(radar_altimeter_scale); } /** * Prepare all the VPath needed for the panel, either fixed drawings * (labels, scales, etc.) and the moving parts (flaps, pointers, etc.). * This virtual drawings take place in a square box 1.0x1.0 with origin in * its top-left corner, so that, once properly scaled and translated to * their actual position in screen, they can be drawn. */ static void panel_create_vpaths() { vpath_Type *p; double x, y, co, si, r, r1, r2, r3, r4, w, h; int a; VMatrix m; char s[10]; if( panel_fixed != NULL ) return; memory_registerCleanup(panel_cleanup); /* Fixed drawings: */ p = vpath_new(); /* Wing profile without flap: */ VIdentMatrix(&m); VScaleMatrix(&m, 0.030, 0.030, 1.0); VTranslate(&m, 0.05, 0.05, 0.0); vpath_draw_string(p, "FLAPS", 5, &m); vpath_moveTo(p, &(VPoint){0.05, 0.15, 0.0}); vpath_lineTo(p, &(VPoint){0.07, 0.13, 0.0}); vpath_lineTo(p, &(VPoint){0.13, 0.12, 0.0}); vpath_lineTo(p, &(VPoint){0.23, 0.13, 0.0}); vpath_lineTo(p, &(VPoint){0.22, 0.15, 0.0}); vpath_lineTo(p, &(VPoint){0.23, 0.17, 0.0}); vpath_lineTo(p, &(VPoint){0.08, 0.17, 0.0}); vpath_lineTo(p, &(VPoint){0.065, 0.165, 0.0}); vpath_lineTo(p, &(VPoint){0.05, 0.15, 0.0}); /* Flaps deflection scale, with angle amplified by 2 for readability: */ x = 0.25; y = 0.15; r1 = 0.17; /* notchs internal radius */ r2 = 0.19; /* short notchs external radius */ r3 = 0.21; /* long notchs external radius */ r4 = 0.25; /* label's center radius */ for( a = 0; a <= 40; a += 5 ){ co = cos( FLAP_ANGLE_SCALE * units_DEGtoRAD(a) ); si = sin( FLAP_ANGLE_SCALE * units_DEGtoRAD(a) ); if( a % 10 == 0 ) r = r3; else r = r2; vpath_moveTo(p, &(VPoint){x + r1*co, y + r1*si, 0.0}); vpath_lineTo(p, &(VPoint){x + r*co, y + r*si, 0.0}); /* Draw label: */ if( a % 10 == 0 ){ sprintf(s, "%d", a); w = 0.025; /* font width */ h = 0.030; /* font height */ VIdentMatrix(&m); VScaleMatrix(&m, w, h, 1.0); VTranslate(&m, x + r4*co - 0.5*strlen(s)*w, y + r4*si + 0.5*h, 0.0); vpath_draw_string(p, s, strlen(s), &m); } } /* Max bank fixed scale: */ VIdentMatrix(&m); VScaleMatrix(&m, 0.03, 0.03, 1.0); VTranslate(&m, 0.65, 0.05, 0.0); vpath_draw_string(p, "MAX BANK", 8, &m); x = 0.80; y = 0.30; r1 = 0.08; /* notchs internal radius */ r3 = 0.11; /* long notchs external radius */ r4 = 0.15; /* label's center radius */ for( a = 5; a <= 25; a += 5 ){ co = cos( MAX_BANK_ANGLE_OFFSET + MAX_BANK_ANGLE_SCALE * units_DEGtoRAD(a) ); si = sin( MAX_BANK_ANGLE_OFFSET + MAX_BANK_ANGLE_SCALE * units_DEGtoRAD(a) ); vpath_moveTo(p, &(VPoint){x + r1*co, y + r1*si, 0.0}); vpath_lineTo(p, &(VPoint){x + r3*co, y + r3*si, 0.0}); /* Draw label: */ sprintf(s, "%d", a); w = 0.025; /* font width */ h = 0.030; /* font height */ VIdentMatrix(&m); VScaleMatrix(&m, w, h, 1.0); VTranslate(&m, x + r4*co - 0.5*strlen(s)*w, y + r4*si + 0.5*h, 0.0); vpath_draw_string(p, s, strlen(s), &m); } /* Max bank, knob: */ r1 = 0.06; vpath_moveTo(p, &(VPoint){0.80 + r1, 0.30, 0.0}); for( a = 30; a <= 360; a += 30 ){ vpath_lineTo(p, &(VPoint){0.80 + r1*cos(units_DEGtoRAD(a)), 0.30 + r1*sin(units_DEGtoRAD(a)), 0.0}); } /* Handle attachment: */ /* Gear lights: */ panel_fixed = p; /* Flap with pivot in (0,0,0) indicating 0 DEG deflection: */ p = vpath_new(); vpath_moveTo(p, &(VPoint){-0.02, 0.00, 0.0}); vpath_lineTo(p, &(VPoint){ 0.00, -0.02, 0.0}); vpath_lineTo(p, &(VPoint){ 0.15, 0.00, 0.0}); vpath_lineTo(p, &(VPoint){ 0.00, 0.02, 0.0}); vpath_lineTo(p, &(VPoint){-0.02, 0.00, 0.0}); panel_flap = p; /* Max bank knob, oriented right: */ p = vpath_new(); vpath_lineTo(p, &(VPoint){0.06, 0.00, 0.0}); vpath_lineTo(p, &(VPoint){0.025, 0.0, 0.0}); panel_bank_pointer = p; /* Handle up, centered on its fulcrum: */ p = vpath_new(); vpath_moveTo(p, &(VPoint){-0.05, -0.25, 0.0}); vpath_lineTo(p, &(VPoint){ 0.05, -0.25, 0.0}); vpath_lineTo(p, &(VPoint){ 0.05, -0.05, 0.0}); vpath_lineTo(p, &(VPoint){-0.05, -0.05, 0.0}); vpath_lineTo(p, &(VPoint){-0.05, -0.25, 0.0}); vpath_moveTo(p, &(VPoint){-0.02, -0.05, 0.0}); vpath_lineTo(p, &(VPoint){-0.02, 0.00, 0.0}); vpath_lineTo(p, &(VPoint){-0.01, 0.01, 0.0}); vpath_lineTo(p, &(VPoint){ 0.01, 0.01, 0.0}); vpath_lineTo(p, &(VPoint){ 0.02, 0.00, 0.0}); vpath_lineTo(p, &(VPoint){ 0.02, -0.05, 0.0}); vpath_moveTo(p, &(VPoint){-0.03, -0.05, 0.0}); vpath_lineTo(p, &(VPoint){-0.03, 0.10, 0.0}); vpath_lineTo(p, &(VPoint){ 0.03, 0.10, 0.0}); vpath_lineTo(p, &(VPoint){ 0.03, -0.05, 0.0}); panel_handle_up = p; /* Handle down: */ /* We simply draw the handle up with y axis reversed. */ } static void panel_gear_and_flaps_draw(craft * c, viewer * u) { int x, y, pos[3]; Alib_Window *w; double xscale, yscale, curMaxBank; VMatrix m; static _BOOL blink = FALSE; static double blink_toggle_time = 0.0; void gear_light(double xpos, double ypos, double gear_pos, char *label) { int h, v, width, height, len, fh, fw; Alib_Rect r; h = x + xscale*xpos; v = y + yscale*ypos; width = 0.25*xscale; height = 0.20*yscale; Alib_setRect(&r, h, v, h + width, v + height); if( (gear_pos == 0.0) || (blink && (gear_pos < GEARDOWN)) ) Alib_fillRect(u->w, &r, panelBackgroundColor); else Alib_fillRect(u->w, &r, radarColor); Alib_drawRect(u->w, &r, blackColor); Alib_expandRect(&r, 1, 1); Alib_drawRect(u->w, &r, blackColor); len = strlen(label); fh = height/6; fw = fh; VDrawStrokeString(u->v, h + width/2 - len*fw/2, v + height/2 + fh/2, label, len, fh, blackColor); } if( curTime > blink_toggle_time ){ blink = ! blink; if( blink ) blink_toggle_time = curTime + 0.5; else blink_toggle_time = curTime + 0.7; } if( panel_fixed == NULL ) panel_create_vpaths(); w = u->w; x = u->gear.a.x; y = u->gear.a.y; xscale = (double) RectWidth(u->gear); yscale = (double) RectHeight(u->gear); Alib_setClipRect(w, &u->gear); /* Update gear lights status: */ pos[0] = gear_nosePosition(c); pos[1] = gear_leftPosition(c); pos[2] = gear_rightPosition(c); /* Fixed drawings */ VIdentMatrix(&m); VScaleMatrix(&m, xscale, yscale, 1.0); VTranslate(&m, x, y, -1.0); vpath_stroke(panel_fixed, &m, w, whiteColor); /* * Draw flaps current state */ VIdentMatrix(&m); VRotate(&m, ZRotation, FLAP_ANGLE_SCALE * c->curFlap); VScaleMatrix(&m, xscale, yscale, 1.0); VTranslate(&m, x + 0.25*xscale, y + 0.15*yscale, -1.0); vpath_stroke(panel_flap, &m, w, whiteColor); /* * Draw flaps commanded setting */ VIdentMatrix(&m); VRotate(&m, ZRotation, FLAP_ANGLE_SCALE * c->flapSetting); VScaleMatrix(&m, xscale, yscale, 1.0); VTranslate(&m, x + 0.25*xscale, y + 0.15*yscale, -1.0); vpath_stroke(panel_flap, &m, w, magentaColor); /* Draw max bank setting */ curMaxBank = units_DEGtoRAD( aps_bank_max_get(c) ); VIdentMatrix(&m); VRotate(&m, ZRotation, MAX_BANK_ANGLE_OFFSET + MAX_BANK_ANGLE_SCALE*curMaxBank); VScaleMatrix(&m, xscale, yscale, 1.0); VTranslate(&m, x + 0.8*xscale, y + 0.30*yscale, -1.0); vpath_stroke(panel_bank_pointer, &m, w, magentaColor); /* Draw gear handle */ if( gear_isHandleDown(c) ){ VIdentMatrix(&m); VScaleMatrix(&m, xscale, /* upside-down */ -yscale, 1.0); } else { VIdentMatrix(&m); VScaleMatrix(&m, xscale, yscale, 1.0); } VTranslate(&m, x + 0.25*xscale, y + 0.70*yscale, -1.0); vpath_stroke(panel_handle_up, &m, w, whiteColor); /* Draw gear lights: */ if( c->cinfo->rn.x > c->cinfo->rm.x ){ /* Tricycle: */ gear_light(0.55, 0.55, pos[0], "Nose"); gear_light(0.40, 0.80, pos[1], "Left"); gear_light(0.70, 0.80, pos[2], "Right"); } else { /* Bicycle: */ gear_light(0.55, 0.80, pos[0], "Tail"); gear_light(0.40, 0.55, pos[1], "Left"); gear_light(0.70, 0.55, pos[2], "Right"); } } #define MAX_ALTITUDE 2500 #define THR_ALTITUDE 500 #ifdef FIXME_UNUSED_BUT_STILL_USEFUL_REFERENCE static double normalized_h(double h) /* Map the altitude h >= 0.0 ft to the range [0.0,1.0]. Altituded above MAX_ALTITUDE ft are mapped into 1.0. */ { if( h > MAX_ALTITUDE ) return 1.0; if( h < 0.0 ) return 0.0; if( h <= THR_ALTITUDE ) return h/THR_ALTITUDE*0.5; else return 0.5 + 0.5*(h - THR_ALTITUDE)/(MAX_ALTITUDE - THR_ALTITUDE); } #endif static double map_altitude_to_y(double h) /* Maps altitude h (ft) to y of the radar_altimeter_scale */ { if( h <= 500.0 ) return -0.01*h; else return -5.0 - 0.005*(h - 500.0); } #ifdef FIXME_UNUSED_BUT_STILL_USEFUL_REFERENCE static double map_y_to_altitude(double y) /* Maps y of the radar_altimeter_scale into the altitude h (ft) */ { if( y >= -5.0 ) return -100.0*y; else return 500.0 - 200.0*(y - 5.0); } #endif static void build_radar_altimeter_scale() { vpath_Type *p; int h_inc, h, s_len; double fw, fh, y, s_width; char s[10]; VMatrix m; p = vpath_new(); vpath_moveTo(p, &(VPoint){0.0, 0.0, 0.0}); vpath_lineTo(p, &(VPoint){1.0, 0.0, 0.0}); fw = 0.15; fh = 1.6*fw; h_inc = 100; for( h = 100; h <= 2500; h += h_inc ){ if( h == 500 ) h_inc = 200; y = map_altitude_to_y(h); sprintf(s, "%d", h); s_len = strlen(s); s_width = fw*s_len; VIdentMatrix(&m); VScaleMatrix(&m, fw, fh, 1.0); VTranslate(&m, 0.5 - 0.5*s_width, y + fh/2.0, 0.0); vpath_draw_string(p, s, s_len, &m); vpath_moveTo(p, &(VPoint){0.0, y, 0.0}); vpath_lineTo(p, &(VPoint){0.5 - 0.5*s_width - 0.1, y, 0.0}); vpath_moveTo(p, &(VPoint){1.0, y, 0.0}); vpath_lineTo(p, &(VPoint){0.5 + 0.5*s_width + 0.1, y, 0.0}); } radar_altimeter_scale = p; } static void panel_radar_altimeter(viewer *u) { double yscale, y0, h; craft *c; Alib_Rect clip; Alib_Window *w; VMatrix m; w = u->w; /* Clear area: */ Alib_setClipRect(w, &u->radar_altimeter); /* Draw frame: */ Alib_drawRect(w, &u->radar_altimeter, whiteColor); /* Clip to internal frame: */ clip = u->radar_altimeter; Alib_expandRect(&clip, -1, -1); Alib_setClipRect(w, &clip); /* Get current altitude over the ground: */ c = u->c; h = units_METERStoFEET(c->w.z - terrain_localAltitude(c)) - c->cinfo->rm.z - c->cinfo->Gm - c->cinfo->cmMax; /* Mapping between screen y and altitude h: y = y0 - yscale*map_altitude_to_y(h) and its reverse: h = map_y_to_altitude((y - y0)/yscale) The reference mark is located at the center of the scale. */ y0 = RectMiddleY(clip); yscale = 0.25*RectHeight(clip); /* 2 marks above and below reference */ if( h > 2900.0 ){ Alib_drawLine(w, clip.a.x, clip.a.y, clip.b.x, clip.b.y, whiteColor); } else { double y_h; Alib_Rect g; y_h = y0 - yscale * map_altitude_to_y(h); /* Draw sky: */ /*** g = clip; g.b.y = (int) (y_h + 0.5); AlibFillRectangle(w, &g, attitudeSkyColor->cIndex); ***/ /* Draw ground: */ g = clip; g.a.y = (int) (y_h + 0.5); if( g.a.y < clip.b.y ){ int i, x, B, H, W; H = RectHeight(g); W = RectWidth(g); B = W/4; Alib_fillRect(w, &g, yellowColor); for( i = g.a.x + B; i < g.b.x + W + H; i += 2*B ){ for( x = i; x < i + B; x++ ){ Alib_drawLine(w, x, g.a.y, x - H, g.a.y + H, blackColor); } } } /* Draw scale: */ VIdentMatrix(&m); VScaleMatrix(&m, RectWidth(clip), yscale, 1.0); VTranslate(&m, clip.a.x, y_h, -1.0); if( radar_altimeter_scale == NULL ) build_radar_altimeter_scale(); vpath_stroke(radar_altimeter_scale, &m, w, whiteColor); } /* Draw reference mark: */ Alib_drawLine(w, clip.a.x, y0+0.5, clip.b.x, y0+0.5, magentaColor); Alib_drawLine(w, clip.a.x, y0+0.5+1.0, clip.b.x, y0+0.5, magentaColor); } static void panel_lights_draw(craft * c, viewer * u) { draw_Type *dd; Alib_Window *w; int rows, cols, row, col; double width, height, x, y, cellH, cellW, cellX, cellY, fh, m; Alib_Pixel black; Alib_Rect rect; static _BOOL blink = FALSE; static double blink_toggle_time = 0.0; if( curTime > blink_toggle_time ){ blink = ! blink; if( blink ) blink_toggle_time = curTime + 0.1; /* off time */ else blink_toggle_time = curTime + 0.2; /* on time */ } w = u->w; Alib_setClipRect(w, &u->lights); dd = draw_new(); width = RectWidth(u->lights); height = RectHeight(u->lights); x = u->lights.a.x; y = u->lights.a.y; cols = 2; rows = (LIGHTS_N + 1) / 2; cellW = width / cols; cellH = height / rows; fh = 0.30*cellH; m = 0.07*cellH; /* cell margin */ row = 0; col = 0; black = blackColor; ; if( gear_brakesEngaged(c) ) c->damageBits |= FLAG_WHEELBRAKE; else c->damageBits &= ~FLAG_WHEELBRAKE; for( pptr = &panelVec[0]; pptr->mask != 0; ++pptr ){ if( col >= cols ) error_internal("col=%d >= cols=%d", col, cols); cellX = x + col * cellW; cellY = y + row * cellH; /* Draw cell background: */ if( (c->damageBits & pptr->mask) != 0 && (! pptr->blink || ! blink ) ){ Alib_setRect(&rect, cellX + m, cellY + m, cellX + cellW - 2*m, cellY + cellH - 2*m); Alib_fillRect(w, &rect, magentaColor); } /* Draw cell label: */ draw_string_centered(u->v, cellX + 0.5*cellW, cellY + 0.5*cellH, fh, pptr->name, black); /* Draw cell border: */ /**** draw_rect(dd, cellX + m, cellY + m, cellX + cellW - 2*m, cellY + cellH - 2*m); ****/ row++; if( row >= rows ){ row = 0; col++; } } draw_stroke(dd, u->v, HUDColor); draw_free(dd); panel_radar_altimeter(u); } static double map_rpm_to_angle(int rpm) { if( rpm < 20 ) rpm = 20; else if( rpm > 120 ) rpm = 120; return units_DEGtoRAD( (rpm - 20)*270.0 / 80.0 - 90 ); } static void thrust_reverse_light(craft * c, viewer * u) { static double blink_toggle_time = 0.0; static _BOOL blink = FALSE; int xsize, ysize, x, y, width, height, fh, fw, moving, fully_deployed; double xscale, yscale; Alib_Rect r; if( ! c->cinfo->hasThrustReverser ) return; if( curTime > blink_toggle_time ){ blink = ! blink; if( blink ) blink_toggle_time = curTime + 0.2; else blink_toggle_time = curTime + 0.4; } xsize = RectWidth(u->engine); ysize = RectHeight(u->engine); xscale = xsize; yscale = ysize; x = u->engine.a.x + 0.82 * xscale; y = u->engine.a.y + 0.50 * yscale; width = 0.18*xscale; height = 0.18*yscale; fully_deployed = (c->thrust_reverse_pos < -0.4); moving = (c->thrust_reverse_pos < 0.9) && (c->thrust_reverse_pos > -0.4); Alib_setRect(&r, x, y, x + width, y + height); if( fully_deployed || (moving && !blink) ) Alib_fillRect(u->w, &r, radarColor); Alib_drawRect(u->w, &r, blackColor); Alib_expandRect(&r, 1, 1); Alib_drawRect(u->w, &r, blackColor); fh = 0.25 * height; fw = fh; VDrawStrokeString(u->v, x + width/2 - 3*fw/2, y + height/2 - 0.02*yscale, "THR", 3, fh, blackColor); VDrawStrokeString(u->v, x + width/2 - 3*fw/2, y + height/2 + fh + 0.02 * yscale, "REV", 3, fh, blackColor); } static void panel_engine_draw(craft * c, viewer * u) { draw_Type *dd; Alib_Window *w; int xsize, ysize, percent, percento, ab, x, y, rpm, fu; double r, r1, r2, xc, yc, fh, co, si, a; char s[32]; Alib_Pixel white; Alib_Rect rect; xsize = RectWidth(u->engine); ysize = RectHeight(u->engine); x = u->engine.a.x; y = u->engine.a.y; white = whiteColor; dd = draw_new(); w = u->v->w; Alib_setRect(&rect, x, y, x + xsize, y + ysize); Alib_setClipRect(w, &rect); percento = (int) ( (double)c->throttleComm / 32768.0 * 100.0 + 0.5); if (damage_isFunctioning(c, SYS_ENGINE1)) { percent = (int) (c->rpm * 100.0 + 0.5); } else { percent = 0; } ab = ((c->flags & FL_AFTERBURNER) == 0)? 0:1; r = 0.30*xsize; /* body */ r1 = 0.85*r; /* ticks */ r2 = 0.65*r; /* numbers */ xc = x + xsize/2; yc = y + r + 0.04*ysize; fh = 0.15*r; draw_circle(dd, xc, yc, r); for( rpm = 20; rpm <= 100; rpm += 10 ){ a = map_rpm_to_angle(rpm); co = cos(a); si = sin(a); draw_segment(dd, xc + r*co, yc + r*si, xc + r1*co, yc + r1*si); if( rpm > 20 && rpm % 20 == 0 ){ sprintf(s, "%d", rpm); draw_string_centered(u->v, xc + r2*co, yc + r2*si, fh, s, white); } } draw_arc(dd, xc, yc, 0.95*r, map_rpm_to_angle(85), map_rpm_to_angle(100)); draw_string_centered(u->v, xc, yc + 0.20*r, 0.12*r, "RPM%", white); draw_pointer(dd, xc, yc, map_rpm_to_angle(percent), r2); /* Draw ordered power */ sprintf(s, "%3d%s", percento, ab? "AB" : " "); draw_string_centered(u->v, xc, yc - 0.55*r, 0.18*r, s, white); draw_rect(dd, xc - 0.56*r, yc - 0.75*r, xc + 0.56*r, yc - 0.37*r); /* Print fuel total and fuel consumption rate */ fu = (int) (planes_fuelUsed(c) * 3600.0 / deltaT); if ( fu < 50 ) fu = (fu + 3) / 5 * 5; else if ( fu < 500 ) fu = (fu + 5) / 10 * 10; else fu = (fu + 50) / 100 * 100; draw_string_centered(u->v, x + xsize/2, y + 0.76*ysize, 0.05*xsize, "lb total lb/hour", white); sprintf(s, " %6d %6d", ((int) c->fuel + 5)/10*10, (fu + 5)/10*10); draw_string_centered(u->v, x + xsize/2, y + 0.90*ysize, 0.05*xsize, s, white); draw_stroke(dd, u->v, whiteColor); draw_free(dd); thrust_reverse_light(c, u); } void panel_updateAndDraw(craft *c, viewer *u) { Alib_Rect rect; Alib_setRect(&rect, 0, u->lights.a.y, gui_getWidth(u->gui), gui_getHeight(u->gui)); Alib_setClipRect(u->w, &rect); Alib_fillRect(u->w, &rect, panelBackgroundColor); panel_lights_draw(c, u); radar_update(c, u); /* Radar */ radar_updateTEWS(c, u); /* TEWS -- radar_update must be called first */ adf_panel_draw(u); adf_draw(u); hsi_panel_draw(u); hsi_draw(u); panel_gear_and_flaps_draw(c, u); panel_engine_draw(c, u); }acm-6.0_20200416/src/acm/magnetic_compass.h0000644000000000000000000000373313170023735016616 0ustar rootroot/* * acm : an aerial combat simulator for X * Magnetic compass module * Copyright (C) 2007 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /** * This module simulates the magnetic compass for didactic purposes. * Components of the local magnetic vector are calculated by the wmm module. * * The compass rotates under the effect of the torque produced by the Earth * magnetic field and it is braked by its inertia and by the viscosity of * the fluid. * * @file */ #ifndef _magnetic_compass_h #define _magnetic_compass_h #include "pm.h" #ifdef magnetic_compass_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Enables the magnetic compass for this particular viewer. * If u->magnetic_compass is NULL, instantiate with a pointer to internal data. */ EXTERN void magnetic_compass_enable(viewer *u); /** * Disable the magnetic compass for this particular viewer. */ EXTERN void magnetic_compass_disable(viewer *u); /** * Release magnetic_compass data u->magnetic_compass. */ EXTERN void magnetic_compass_free(viewer *u); /** * Magnetic compass state update. */ EXTERN void magnetic_compass_update(viewer * u); /** * Draw magnetic compass only if MH display is enabled; does nothing in TH mode. * If no magnetic compass active in this viewer, do nothing. */ EXTERN void magnetic_compass_draw(viewer * u); #undef EXTERN #endif acm-6.0_20200416/src/acm/prompt.h0000644000000000000000000000316413155527371014631 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 2007 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /** * Simple one-line text feedback on the virtual terminal. * @file */ #ifndef _prompt_h #define _prompt_h #include "pm.h" #ifdef prompt_IMPORT #define EXTERN #else #define EXTERN extern #endif /** Release u->prompt data. */ EXTERN void prompt_free(viewer *u); EXTERN void prompt_viewer_print(viewer *u, char *s); /** * Displays the given string in the cockpit area of the given * viewer. Intended to provide to the user some feedback about events * internal to the program that otherwise would not be noticed. The * message get cleared after some seconds. A new message clears the * old one. */ EXTERN void prompt_craft_print(craft *c, char *s); /** * Broadcast the message to all the viewers. */ EXTERN void prompt_broadcast_print(char *s); /** * The renderer module must call this to draw the current message. */ EXTERN void prompt_draw(viewer *u); #undef EXTERN #endif acm-6.0_20200416/src/acm/manifest.h0000644000000000000000000000405513175037565015121 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1996 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #ifndef _manifest_h #define _manifest_h #include "../util/units.h" #ifdef manifest_IMPORT #define EXTERN #else #define EXTERN extern #endif /** Maximum number of players and drones. */ #define manifest_MAXPLAYERS 32 /** Maximum number of chasers. */ #define manifest_MAXCHASERS 1 /** Maximum number of missiles and cannon streams. */ #define manifest_MAXPROJECTILES (manifest_MAXPLAYERS * 1) #define manifest_MAXEXPLOSIONS manifest_MAXPROJECTILES /** Max number of weapon stations launch points per aircraft. */ #define manifest_STATIONS 9 /** * We'll check every now and again to see if any aircraft are waiting to * be resupplied. RESUPPLY_EVERY defines the number of seconds * between each check (30 seconds, here). */ #define manifest_RESUPPLY_INTERVAL (30.0) /** * When on the ground, we won't allow planes to stray too far from their * team's airport. manifest_MAX_GROUND_DISTANCE defines that distance. */ #define manifest_MAX_GROUND_DISTANCE (3.0 * units_NmToFeetFactor) /** * The maximum allowed dead reckoning errors for DIS. * (Note: the units are meters and radians.) */ #define manifest_DIS_LOCATION_THRESHOLD 3.0 #define manifest_DIS_ORIENTATION_THRESHOLD units_DEGtoRAD(2) /** Identifies X-Window resources related to this program. */ #define manifest_ACM "acm" #undef EXTERN #endif acm-6.0_20200416/src/acm/magnetic_compass.c0000644000000000000000000001573013143113502016601 0ustar rootroot/* * acm : an aerial combat simulator for X * Magnetic compass module * Copyright (C) 2007 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include "../util/memory.h" #include "pm.h" #include "vpath.h" #define magnetic_compass_IMPORT #include "magnetic_compass.h" typedef struct _magnetic_compass_data { double last_time; /* last update */ double hdg; /* current indicated value (RAD) */ double hdg_dot; /* current rotation speed (RAD/s) */ double x_rot, y_rot; /* compass roll and pitch angles in aircraft frame */ } magnetic_compass_data; static vpath_Type * compass_scale_path = NULL; static void magnetic_compass_cleanup() { memory_dispose(compass_scale_path); compass_scale_path = NULL; } void magnetic_compass_enable(viewer *u) { magnetic_compass_data *mc; if( u->magnetic_compass == NULL ){ mc = memory_allocate(sizeof(magnetic_compass_data), NULL); mc->last_time = curTime; mc->hdg = 0.0; mc->hdg_dot = 0.0; mc->x_rot = 0.0; mc->y_rot = 0.0; u->magnetic_compass = mc; } else { mc = u->magnetic_compass; } } void magnetic_compass_disable(viewer *u) { magnetic_compass_free(u); } #define TILT_ANGLE units_DEGtoRAD(18) void magnetic_compass_update(viewer *u) { magnetic_compass_data *mc; double x_rot, y_rot, MH, dt; _BOOL tilted; VPoint aH, cH; VMatrix R; mc = u->magnetic_compass; if( mc == NULL ) return; if( ! u->c->showMag ){ // Magnetic field components not available. mc->last_time = curTime; // avoid abrupt turn if c->showMag enabled again return; } dt = curTime - mc->last_time + 0.01 /* div by zero workaround! */; mc->last_time = curTime; /* Update compass roll and pitch angles based on the local vertical u->c->G: */ tilted = FALSE; x_rot = atan2(u->c->G.y, -u->c->G.z); y_rot = -atan2(u->c->G.x, -u->c->G.z); mc->x_rot += (x_rot - mc->x_rot) * 0.002 / dt; if( mc->x_rot < -TILT_ANGLE ){ mc->x_rot = -TILT_ANGLE; tilted = TRUE; } if( mc->x_rot > TILT_ANGLE ){ mc->x_rot = TILT_ANGLE; tilted = TRUE; } mc->y_rot += (y_rot - mc->y_rot) * 0.002 / dt; if( mc->y_rot < -TILT_ANGLE ){ mc->y_rot = -TILT_ANGLE; tilted = TRUE; } if( y_rot > TILT_ANGLE ){ y_rot = TILT_ANGLE; tilted = TRUE; } if( tilted ) mc->hdg_dot = 0.0; /* Local magnetic field aH in aircraft frame (nT): */ VReverseTransform_(&u->c->actualMagneticField, &u->c->trihedral, &aH); /* Local magnetic field cH in compass frame (nT): */ VIdentMatrix(&R); VRotate(&R, YRotation, mc->y_rot); VRotate(&R, XRotation, mc->x_rot); VReverseTransform_(&aH, &R, &cH); /* MH is the magnetic heading in the compass frame, i.e. projection if cH on the local horizontal plane x-y of the aircraft: */ if( fabs(cH.x) + fabs(cH.y) < 1e-5 ) return; MH = atan2(-cH.y, cH.x); if( MH < 0.0 ) MH += 2*M_PI; /* Update rotational speed: */ mc->hdg_dot += /* Apply torque due to the magnetic field. 42000 nT is the max intensity * of the mag. field on the Earth; 0.1 is a quite arbitrary factor * accounting for the magnetic dipole of the compass. */ 0.1/42000 * dt * sin( MH - mc->hdg ) * sqrt(cH.x*cH.x + cH.y*cH.y) /* Apply viscosity (quite arbitrary coeff.). */ - 0.007 * mc->hdg_dot; mc->hdg += mc->hdg_dot * dt; while( mc->hdg < 0.0 ) mc->hdg += 2*M_PI; while( mc->hdg >= 2*M_PI ) mc->hdg -= 2*M_PI; } /** * Return the scale of the compass, drawn on a cone of radius 1.0 * and height 1.0. The axis of the cone is y and the pivot point is * the origin. */ static vpath_Type * get_compass_scale_path() { vpath_Type *path; int a, s_len; double r, notch_short, notch_long, notch_len; double fh, fw, slant, margin; VPoint p, q; VMatrix M, L; char *s; static char *labels[] = {"N", "3", "6", "E", "12", "15", "S", "21", "24", "W", "30", "33"}; path = vpath_new(); r = 1.0; /* radius and cone height */ notch_short = 0.12 * r; notch_long = 0.25 * r; slant = units_DEGtoRAD(45); fh = 0.20 * r; /* font height */ fw = 0.12 * r; /* font width */ margin = 0.03 * r; /* long notch to char margin */ for( a = 0; a < 360; a += 5 ){ /* Transformation for this notch + label */ VIdentMatrix(&M); VRotate(&M, XRotation, -slant); VTranslate(&M, 0.0, r, -r); VRotate(&M, YRotation, -units_DEGtoRAD(a)); /* Draw notch */ if( a % 10 == 0 ) notch_len = notch_long; else notch_len = notch_short; VSetPoint(&p, 0.0, 0.0, 0.0); VSetPoint(&q, 0.0, -notch_len, 0.0); VTransform(&p, &M, &p); VTransform(&q, &M, &q); vpath_moveTo(path, &p); vpath_lineTo(path, &q); /* Draw label */ if( a % 30 == 0 ){ s = labels[a/30]; s_len = strlen(s); VIdentMatrix(&L); VScaleMatrix(&L, fw, fh, 1.0); VTranslate(&L, -0.5 * (fw * s_len), -notch_len - margin, 0.0); VMatrixMult(&L, &M, &L); vpath_draw_string(path, s, s_len, &L); } } return path; } void magnetic_compass_draw(viewer * u) { magnetic_compass_data *mc; Alib_Window *w; double x, y, width, h, r, xmargin, ymargin; VMatrix M; Alib_Rect rect; if( ! u->c->showMag ){ // Components of the magnetic field not available. return; } mc = u->magnetic_compass; if( mc == NULL ) return; if( u->viewDirection.x < 0.90 ) return; w = u->v->w; x = 0.85 * gui_getWidth(u->gui); y = 0.0; width = gui_getWidth(u->gui) - x; h = 0.50 * width; r = 0.45 * width; /* actual radius of the scale cone */ Alib_setRect(&rect, x, 0, gui_getWidth(u->gui), h); Alib_setClipRect(w, &rect); Alib_fillRect(w, &rect, panelBackgroundColor); VIdentMatrix(&M); /* Set scale size */ VScaleMatrix(&M, r, r, r); /* Rotate based on the current magnetic compass state */ VRotate(&M, YRotation, mc->hdg); VRotate(&M, XRotation, mc->y_rot); VRotate(&M, ZRotation, mc->x_rot); /* Move to the final screen location */ VTranslate(&M, x + width/2, y - r + h*2/3, 0.0); /* Draw compass scale */ xmargin = 0.20 * width; ymargin = 0.10 * h; Alib_setRect(&rect, x + xmargin, y + ymargin, x + width - xmargin, y + h - ymargin); Alib_setClipRect(w, &rect); if( compass_scale_path == NULL ){ compass_scale_path = get_compass_scale_path(); memory_registerCleanup(magnetic_compass_cleanup); } vpath_stroke(compass_scale_path, &M, w, whiteColor); /* Draw reference line */ Alib_drawLine(w, x + 0.5*width, y + 0.10*h, x + 0.5*width, y + 0.90*h, magentaColor); } void magnetic_compass_free(viewer *u) { memory_dispose(u->magnetic_compass); u->magnetic_compass = NULL; } acm-6.0_20200416/src/acm/weapon_null.h0000644000000000000000000000234313063670320015620 0ustar rootroot/* * acm : an aerial combat simulator for X * Null weapon module. * Copyright (C) 2009 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /** * Implements the "null" weapon, that is a weapon that does nothing. * * @file */ #ifndef _weapon_null_h #define _weapon_null_h #include "weapon.h" #ifdef weapon_null_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Returns the weapon description record for the "null weapon", that is the * weapon that does nothing. * @return Null weapon descriptor, statically allocated. */ EXTERN weapon_Type * weapon_null_new(void); #undef EXTERN #endif acm-6.0_20200416/src/acm/scale.h0000644000000000000000000000356513064343237014400 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991,1992 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #ifndef _scale_h #define _scale_h #include "../V/Vlib.h" #ifdef scale_IMPORT #define EXTERN #else #define EXTERN extern #endif typedef enum { scale_ORIENT_LEFT, scale_ORIENT_RIGHT, scale_ORIENT_HORIZONTAL } scale_Orient; typedef struct { int xorg; /* x loc of bottom of scale */ int yorg; /* y loc of bottom of scale */ int length; /* length of scale (pixels) */ scale_Orient orientation; /* orientation flags */ double scale; /* units per pixel */ int minorInterval; /* units per minor tick */ int minorSize; /* width of minor ticks (pixels) */ int majorInterval; /* units per major tick */ int majorSize; /* width of major ticks (pixels) */ int indexSize; /* width of index (pixels) */ double divisor; /* divisor on digit scale */ char *format; /* output format */ int pixel; /* pixel value to use when drawing */ int fontSize; /* font size (pixels) */ } scale_Type; EXTERN void scale_draw(Viewport * vp, scale_Type * s, double value); EXTERN void scale_drawCompass(Viewport * vp, scale_Type * s, double value); #undef EXTERN #endif acm-6.0_20200416/src/acm/patchlevel.c0000644000000000000000000000020013064345213015406 0ustar rootroot/* * Dummy empty implementation: this module only exports declarations. */ #define patchlevel_IMPORT #include "patchlevel.h" acm-6.0_20200416/src/acm/hsi.h0000644000000000000000000001125713134151734014066 0ustar rootroot/* * acm : an aerial combat simulator for X * HSI tuner and HSI indicator module * Copyright (C) 1991-1998 Riley Rainey * Copyright (C) 2007 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /** * HSI panel. * * The HSI panel receives signals from VOR, DME, LOCATOR and GS stations, * then it feeds the data to the HSI display (course deviation indicator and * glide slope deviation indicator). For VOR+DME stations, implements also * the RNAV computer. * * VOR, LOC and GS antennas all transmit a continuous signal that gives * angular informations. On the contrary, DME stations provide their response * to the transponder on board at random intervals of time, so the distance * has to be extrapolated in order to feed with continuous values the RNAV * calculator. Nevertheless DME and expecially CDI indications calculated * on WP by the RANV computer are quite unstable. * * BEWARE. In the following functions hsi_xxx_inc(u, step) usually the value * of the step should be +1 (increment) or -1 (decrement) simply to indicate * the direction of the change. Every function internally implements an * auto-repeat detection feature that speeds-up this otherwise very slow * interface. If the auto-repeat gets detected, the increment actually * applied gets multiplied by a factor that ranges from 2 up to 20. * * @file */ #ifndef _hsi_h #define _hsi_h #include "pm.h" #ifdef hsi_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Enables the HSI for this particular viewer. If u->hsi is NULL, * instantiate with a pointer to internal data. */ EXTERN void hsi_enable(viewer *u); /** * Disables the HSI for this particular viewer. If u->hsi is NULL, * instantiate with a pointer to internal data. */ EXTERN void hsi_disable(viewer *u); /** * Release HSI data u->hsi. */ EXTERN void hsi_free(viewer *u); /** * Loops between NAV1, NAV2, RNAV1, ... modes. */ EXTERN void hsi_switch_mode(viewer *u); /** * Increment station frequency by step channels. VOR/ILS/DME channels ranges * from 0 (108.00 MHz) up to 199 (117.95 MHz) by steps of 1 (0.05 MHz). */ EXTERN void hsi_frq_inc(viewer *u, int step); /** * Increment OBS pointer by 'step' DEG. */ EXTERN void hsi_obs_inc(viewer *u, int step); /** * Increment waypoint theta angle by 'step' DEG. */ void hsi_theta_inc(viewer *u, int step); /** * Increment waypoint distance from VOR by 'step' tenth of NM. */ EXTERN void hsi_rho_inc(viewer *u, int step); /** * Updates the internal state of the HSI. Does nothing if no HSI enabled in this * viewer. * @param u */ EXTERN void hsi_update(viewer * u); /** * Draw HSI tuner panel (uses the TEWS panel). If no HSI active in this viewer, * do nothing. */ EXTERN void hsi_panel_draw(viewer * u); /** * Draw HSI compass, OBS, CDI and GS (uses the radar panel). If no HSI * active in this viewer, do nothing. */ EXTERN void hsi_draw(viewer * u); /** * Return the currently selected OBS, or 0 if HSI not active. */ EXTERN int hsi_get_obs(viewer *u); /** * Return in 'r' the radial (RAD) occupied by the aircraft in the VOR or * WP horizontal plane xy, with x aligned with the magnetic north at the * station location, y oriented magnetic east, -PI≤r≤PI. Return FALSE * if no station tuned in the HSI or not a VOR and neither a WP. */ EXTERN _BOOL hsi_vor_radial(viewer *u, double *r); /** * Return in 'r' the radial (RAD) occupied by the aircraft in the LOCATOR * plane xy, with x aligned with the LOCATOR bearing, i.e. r==0 means we * are aligned with LOC. Return FALSE if no station tuned in the HSI or * not a LOCATOR. */ EXTERN _BOOL hsi_loc_radial(viewer *u, double *r); /** * Return in 'dist' the distance (NM) from the DME/ILS-DME station or WP * currently selected in the HSI panel. Return FALSE if HSI not enabled or * no DME available. */ EXTERN _BOOL hsi_dme(viewer *u, double *dist); /** * Return the offset angle (RAD) from the GS plane, positive if the aircraft * is too high. Return FALSE if no station tuned in the HSI or not an ILS. */ EXTERN _BOOL hsi_gs_offset(viewer *u, double *offset); #undef EXTERN #endif acm-6.0_20200416/src/acm/gear.h0000644000000000000000000000721213175037100014210 0ustar rootroot/* * ACM - Landing gear module * Copyright (C) 2008 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /** * Aircraft gear dynamics, including steering, aerodynamic drag, drag over the * terrain. * @file */ #ifndef _gear_h #define _gear_h #include "pm.h" #ifdef gear_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Allocates the gear state data structure c->gear. The gear is initialized * up and locked, zero steering angle, no brakes applied. */ EXTERN void gear_allocate(craft * c); /** * Release the gear state data structure c->gear and sets that field to * null. Does nothing if already NULL. */ EXTERN void gear_free(craft *c); /** * Set initial handle and gear state, no animation, no sound. * @param c */ EXTERN void gear_up(craft *c); /** * Set initial handle and gear state, no animation, no sound. * @param c */ EXTERN void gear_down(craft *c); EXTERN _BOOL gear_isHandleDown(craft * c); /** Move gear handle with gear animation and sound. */ EXTERN void gear_handle_up(craft *c); /** Move gear handle with gear animation and sound. */ EXTERN void gear_handle_down(craft *c); /** Move gear handle with gear animation and sound. */ EXTERN void gear_handle_toggle(craft *c); /** * Returns the nose landing gear position: 0 = up, 1 = moving, 2 = down. */ EXTERN int gear_nosePosition(craft * c); /** * Returns the left landing gear position: 0 = up, 1 = moving, 2 = down. */ EXTERN int gear_leftPosition(craft * c); /** * Returns the right landing gear position: 0 = up, 1 = moving, 2 = down. */ EXTERN int gear_rightPosition(craft * c); /** * Returns true if all wheel are in ground contact. */ EXTERN _BOOL gear_allWheelsGroundContact(craft * c); /** * Returns true if at least one wheel is in ground contact. */ EXTERN _BOOL gear_someWheelGroundContact(craft * c); /** * Returns true if the nose/tail wheel is in ground contact. */ EXTERN _BOOL gear_noseWheelGroundContact(craft * c); /** * Returns true if any of the two main wheels is in ground contact. */ EXTERN _BOOL gear_mainWheelsGroundContact(craft * c); EXTERN _BOOL gear_brakesEngaged(craft * c); EXTERN void gear_brakesEngage(craft * c); EXTERN void gear_brakesDisengage(craft * c); /** * Return the rest altitude of the CM over the terrain (ft) and the rest * pitch (RAD) at which the plane can be gently deployed over the runway. The * spring compression are set in order to sustain the total gross weight * empty+fuel+payload. * * ATTENTION. Fuel quantity and payload must be already set before calling * this function. */ EXTERN void gear_ground_altitude_pitch(craft *c, double *altitude, double *pitch); /** * Returns the gear contribute to the drag factor. * @return Gear contribute to the drag factor. */ EXTERN double gear_get_drag(craft * c); /** * Return the total force and moment due to the friction of the wheels on * the ground, components in aircraft XYZ. Return NULL on success, or the * reason of the crash. */ EXTERN char * gear_ground_dynamics(craft * c, VPoint *gearF, VPoint *gearM); #undef EXTERN #endif acm-6.0_20200416/src/acm/vpath.h0000644000000000000000000000704613175040522014423 0ustar rootroot/* * ACM - 3-D draw utilities * Copyright (C) 2008 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /** * This module implements collections of "tracks", every track being * a collection of two or more VPoint. 3-D paths can then be transformed * with a matrix and projected on the x-y plane of the screen. * @file */ #ifndef _VPATH_H #define _VPATH_H #include "../V/Alib.h" #include "../V/Vlib.h" #ifdef vpath_IMPORT #define EXTERN #else #define EXTERN extern #endif typedef struct vpath_Type vpath_Type; /** * Create new empty VPath. The drawing pen is located by default to the * origin point (0,0,0). Can be released with memory_dispose(). */ EXTERN vpath_Type * vpath_new(void); /** * Move the drawing pen to the given absolute point, beginning a new * track. */ EXTERN void vpath_moveTo(vpath_Type *p, VPoint *to); /** * Move the pen from the current pen position to the given destination * point, drawing a segment. */ EXTERN void vpath_lineTo(vpath_Type *p, VPoint *to); /** * Starting from the current pen position as set by vpath_moveTo() or * vpath_lineTo(), draw an arc of ellipse having the given center and the * final point. n>=1 is the number of intermediate segments, higher values * give a smoother line. */ EXTERN void vpath_arc(vpath_Type *p, VPoint *center, VPoint *final, int n); /** * Draw the string on the xy plane starting from the origin and * proceeding along the x axis as baseline. Characters have the * dimension 1.0x1.0. m is the transformation matrix. For example, * this code will add to the VPath the string "Hello" centered around * the point (h,v) of the screen: * * VMatrix m; * double fw, fh; * char *s = "Hello"; * * fw = fh = 10.0; * VIdentMatrix(&m); * VScaleMatrix(&m, fw, fh, 1.0); * VTranslate(&m, h - fw*strlen(s)/2, v + fh/2, 0.0); * vpath_draw_string(path, s, strlen(s), m); */ EXTERN void vpath_draw_string(vpath_Type *path, char *str, int len, VMatrix *m); /** * Translate the 3-D VPath into 2-D segments with a parallel projection * from (x,y,z) 3-D coords to (x,y) 2-D coords in the screen frame * (x=right, y=down, z=toward the screen). Every point get transformed as * per the provided matrix. Segments are clipped to the z < 0 space (= * front of the screen) so to ensure that only the wanted part of the * drawing be visible either translate along the z axis or extrude setting * z scale negative. */ EXTERN void vpath_stroke(vpath_Type *p, VMatrix *m, Alib_Window *w, Alib_Pixel color); /** * Perspective projection of the vpath on the screen. The matrix m is * applied to every point of the vpath to obtain the point q=m*p to * project on the given viewport, current clipping region. The unit of q * is the meter, so q=(0,0,1) is the point exactly one meter in front to * the eye of the observer, and q=(1,0,0) is one meter to the right. */ EXTERN void vpath_perspective_stroke(vpath_Type *p, VMatrix *m, Viewport *v, Alib_Pixel color); #undef EXTERN #endif acm-6.0_20200416/src/acm/sounds.h0000644000000000000000000000512313155527202014611 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #ifndef sounds_h #define sounds_h #include "pm.h" #ifdef sounds_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Pre-defined sound IDs. */ typedef enum { sounds_None = -1, sounds_NoEngine, sounds_GenericPistonEngine, sounds_GenericJetEngine, sounds_GenericRocketEngine, sounds_Crash, sounds_GearUp, sounds_GearDown, sounds_MissileLaunch, sounds_CannonFiring, sounds_Explosion, sounds_Touchdown, sounds_GenericWarning, sounds_StallWarning, sounds_LockWarning, sounds_APGLockAcquired, sounds_NumberOfSounds // Gives the total number of defined sounds. } sounds_SoundID; /** * Enables or disables sounds playing. When enabled the first time, a sounds * data structure is attached to the "sounds" field of the viewer of the aircraft; * this field must be released along with the viewer using memory_dispose(). * @param status True to enable sounds, false to mute. */ EXTERN void sounds_enable(craft * c, int enable); /** * Returns true if allowed to play sounds, false if muted. */ EXTERN int sounds_isEnabled(craft * c); /** * * Sets the engine background sound on all the viewers of this plane. * @param c * @param rpm_rate RPM rate in [0,1]. * @param afterburner Afterburner enabled. * @param dDynamicPressure IGNORED. */ EXTERN void sounds_setBackgroundSound(craft * c, double rpm_rate, int afterburner, double dynamicPressure); /** * Play a sound one time or continously on all the viewers of this plane. * @param c * @param id * @param loop */ EXTERN void sounds_playSound(craft * c, sounds_SoundID id, int loop); /** * Stop the execution of the sound started by playSound on all the viewers of * that plane. * @param c * @param id */ EXTERN void sounds_stopSound(craft * c, sounds_SoundID id); /** * To be called continously to update the audio. */ EXTERN void sounds_update(craft * c); #undef EXTERN #endif acm-6.0_20200416/src/acm/m61a1.h0000644000000000000000000000404413131102030014102 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #ifndef _m61a1_h #define _m61a1_h #include "pm.h" #include "weapon.h" #ifdef m61a1_IMPORT #define EXTERN #else #define EXTERN extern #endif /** The display routine of this modules saves here the position of the LCOS reticule on the HUD. The HUD module then uses this value to decide if to draw or not the designator marker. */ EXTERN Alib_Point m61a1_lcos_last_pos; /** Creates a new description record for the M61A1 cannon. */ EXTERN weapon_Type * m61a1_new(void); /** * The dis_if should invoke this function when a fire DIS PDU arrives involving * a cannon burst. This function add a "craft" item carrying the rounds. * All units and reference systems are those usual in this program (not the DIS * ones). * Cannon burst are NOT tracked by the dis_if module, and no state update events * are send by the shooter. This implies the disId field of a burst is set to * zero because there is no a corresponding tracked entity in the dis_if module, * and each remote client is responsible to simulate the dynamics of the burst. * @param owner Index of shooter in the ptbl[] array. Ignored, anyway. * @param pos Position of the burst. * @param vel Velocity of the burst. * @param rounds Number of rounds. */ EXTERN void m61a1_DISFire(int owner, VPoint *pos, VPoint *vel, int rounds); #undef EXTERN #endif acm-6.0_20200416/src/acm/navaid.h0000644000000000000000000001054713172243713014547 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991,1992 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #ifndef _navaid_h #define _navaid_h #include "pm.h" #ifdef navaid_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Every navaid_Type station has a frequency encoded as int number * whose value is here indicated as "channel". * * Channels in the range 0-199 encode frequency between 108.00 MHz * and 117.95 MHz (VOR, DME and ILS stations). * * Channels in the range 200-529 encode frequency between 200 KHz * and 529 KHz (NDB stations). */ #define navaid_VOR_CHANNEL_MIN 0 #define navaid_VOR_CHANNEL_MAX 199 #define navaid_NDB_CHANNEL_MIN 200 #define navaid_NDB_CHANNEL_MAX 529 /** * Type of radio station. The following combination of flags are allowed: * * navaid_LOC (possibly + navaid_LOC + navaid_GS) * navaid_DME * navaid_VOR (possibly + navaid_DME) * navaid_NDB (possibly + navaid_OMARKER|navaid_MMARKER|navaid_IMARKER) */ #define navaid_LOC 0x0001 #define navaid_VOR 0x0002 #define navaid_DME 0x0004 #define navaid_GS 0x0008 #define navaid_NDB 0x0010 #define navaid_OMARKER 0x0020 #define navaid_MMARKER 0x0040 #define navaid_IMARKER 0x0080 typedef int navaid_Channel; typedef struct navaid_Type { /** Linked list of registered NAVAIDs. */ struct navaid_Type *prev, *next; /** The zone (that is, the scenery) from which this NAVAID was read. */ zone_Type *zone; /** Type of radio station. */ unsigned short type; /** Identifier (e.g. "IHNL"). */ char id[5]; /** Channel number. */ navaid_Channel frequency; /** Location of the station. */ earth_LatLonAlt loc; /** Geocentric location of the station. */ VPoint Sg; /** * VOR station: magnetic bearing, that is local magnetic deviation, * positive east. Localizer station: geographic bearing, normally aligned * with its runway. Zero for any other type of station. */ double bearing; /** Beam width for localizers (rad). */ double beam_width; /** Location of the glide-slope. */ earth_LatLonAlt gs_loc; /** Angle of glide slope (rad). */ double slope; /** * Transform geocentric to local coordinates with the x axis facing the * bearing direction. */ VMatrix lt; /** * Transform geocentric to glide slope local coordinates. */ VMatrix gst; } navaid_Type; /** * Adds ILS to the internal list of known NAVAIDs. * @param zone Zone this ILS belongs to. * @param ident Station identifier; gets trunked to max 4 chars. * @param type Station type. * @param w Station location. * @param gsw Glide slope location. * @param freq Station frequency. * @param loc_width Localizer beam width (DEG). * @param loc_bearing Localizer geographic bearing (DEG). * @param gs_angle Glide slope angle (DEG). */ EXTERN void navaid_add_ils(zone_Type *zone, char *ident, char *type, earth_LatLonAlt * w, earth_LatLonAlt * gsw, double freq, double loc_width, double loc_bearing, double gs_angle); /** * Adds VOR or NDB to the internal list of known NAVAIDs. On error, a message is * sent to stderr and the function returns non-zero. * @param zone Zone this NAVAID belongs to. * @param ident Station identifier; gets trunked to max 4 chars. * @param type Station type. * @param w Station location. * @param freq Station frequency. */ EXTERN void navaid_add_vor_dme_ndb(zone_Type *zone, char *ident, char *type, earth_LatLonAlt * w, double freq); /** * Search for a NAVAID receivable at the frequency specified. * Return the station found, or NULL if no station can be received. */ EXTERN navaid_Type * navaid_reception_check(craft * c, navaid_Channel f); /** * Releases all the NAVAIDs related to the specified zone. */ EXTERN void navaid_purgeZone(zone_Type *zone); #undef EXTERN #endif acm-6.0_20200416/src/acm/render.c0000644000000000000000000006255213175511065014563 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include #include #include "../util/memory.h" #include "../util/units.h" #include "astro.h" #include "browse.h" #include "damage.h" #include "dis_if.h" #include "hud.h" #include "instruments.h" #include "magnetic_compass.h" #include "panel.h" #include "place.h" #include "pm.h" #include "prompt.h" #include "sounds.h" #include "terminal.h" #include "terrain.h" #define render_IMPORT #include "render.h" #include "gear.h" #define render_DEFAULT_GROUND_COLOR "#406030" /** * Entry in the array of items to draw using the painter algorithm. */ typedef struct { /** Distance of the item. */ double distance; /** Item to be drawn. */ craft *item; } ItemToDraw; static VPoint hex[6] = { {1.00000, 0.00000, 0.0}, {0.50000, 0.86603, 0.0}, {-0.50000, 0.86603, 0.0}, {-1.00000, 0.00000, 0.0}, {-0.50000, -0.86603, 0.0}, {0.50000, -0.86603, 0.0} }; static double visibility = units_NMtoMETERS(10); /** If ground flat or tiled. */ static render_Ground ground_mode = render_GROUND_FLAT; VColor_Type *sunColor; /** * Ground color name as retrieved from the zone the craft if currently flying * over. */ static char *groundColorName; static VColor_Type *groundColor; // may depend on the scenery static ItemToDraw *toDraw; static int toDrawCapacity; static int toDrawLen; static int inited; static void render_cleanup() { memory_dispose(toDraw); toDraw = NULL; toDrawCapacity = 0; toDrawLen = 0; inited = 0; } static void render_init() { if( inited ) return; inited = 1; groundColorName = render_DEFAULT_GROUND_COLOR; groundColor = VColor_getByName(groundColorName, 0); sunColor = VColor_getByRGB(255, 255, 255, 0); toDraw = NULL; toDrawCapacity = 0; toDrawLen = 0; memory_registerCleanup(render_cleanup); } void render_setVisibility(double range) { if (range < units_NMtoMETERS(0.01) ) { range = 0.01; } else if (range > units_NMtoMETERS(50.0) ) { range = units_NMtoMETERS(50.0); } visibility = range; } void render_setGroundDepth(render_Ground mode) { ground_mode = mode; } void render_setClouds(double base, double top) { clouds_base = base; clouds_top = top; } /** * Draw the Sun. * @param c Point of view. * @param ps Add Sun polygon here. * @return Sun elevation over the NED horizon: positive values means above (RAD). */ static double render_addSun(craft *c, VPolySet *ps) { VPoint sun; astro_getSun(curTime, &sun); VTransform(&sun, &c->XYZtoNED, &sun); double elevation = atan2(-sun.z, sqrt(sun.x*sun.x + sun.y*sun.y)); /* * Draw the Sun disc as a circle perpendicular to the sun vector. * We need a point p of the polygon: first we take any perpendicular * point to sun, then normalize to Sun disc radius, then add the * sun vector, finally rotate that vector around sun to generate the * vertices: */ VPoint p = (VPoint){sun.y, -sun.x, 0}; double sun_radius = 6.5e8; // radius of the Sun (m) double p_mag = sun_radius / VMagnitude(&p); p.x *= p_mag; p.y *= p_mag; p.z *= p_mag; VAdd(&sun, &p, &p); /* * Rotate p around craft-to-sun vector step by step to get vertices: */ VMatrix r; VIdentMatrix(&r); #define SUN_STEPS 8 VRotateAroundAxis(&r, &sun, 2*M_PI/SUN_STEPS); VPoint disc[SUN_STEPS]; int i; for(i = 0; i < SUN_STEPS; i++){ VTransform_(&p, &r, &p); disc[i] = p; VReverseTransform(&disc[i], &c->XYZtoNED, &disc[i]); } VPolygon *sun_poly = VCreatePolygon(SUN_STEPS, disc, sunColor); VPolySet_Add(ps, sun_poly); return elevation; } /** * Add a horizontal hexagonal layer to the polygons set. * @param c Craft, for NED to XYZ transformation. * @param color Color of the hexagon. * @param z "Zeta" position of the hexagon in aircraft's NED frame (m), then * positive if below. * @param r Radius of the hexagon (m). * @param ps Polygons set to add to. */ static void render_addHorizontalLayer(craft * c, VColor_Type * color, double z, double r, VPolySet *ps) { VPoint hex1[6]; int i; for (i = 0; i < 6; ++i) { hex1[i].x = hex[i].x * r; hex1[i].y = hex[i].y * r; hex1[i].z = z; VReverseTransform(&hex1[i], &c->XYZtoNED, &hex1[i]); } VPolySet_Add(ps, VCreatePolygon(6, hex1, color)); } /** * Add hexagonal polygon for the terrain. * @param c Craft, for NED to XYZ transformation. * @param local_z Local altitude of the terrain below the aircraft. * @param groundColor * @param ps Polygons set to add to. */ static void render_drawFlatTerrain(craft * c, double local_z, VColor_Type *groundColor, VPolySet *ps) { render_addHorizontalLayer(c, groundColor, c->w.z - local_z, visibility, ps); /* double r = 0.95 * visibility; int i; for(i = 4; i >= 0; i--){ double h = 0.5 * r*r / 6e6; addHorizontalLayer(c, ground_color, c->w.z - local_z + h, r, ps); r *= 0.5; } */ } static double myfmod(double x, double m) { if( x >= 0 ){ return x - m * floor(x / m); } else { return m + x + m * floor(-x / m); } } // Terrain with n*n grid for a total of (n-1)^2 tiles. #define n 21 /** * Draws grid of tiles on a square 2*visibility meters wide below the aircraft. * Each tile will be blended to the fog color according to the distance. * Due to the limited number of colors, each tile remains perfectly visible. * We take advantage of this artifact to generate an interesting texture effect * that helps feeling the speed and orientation in VFR. To this aim the square * grid must be still with the terrain rather than being centered below the * aircraft. We use the current latitude and longitude and some modulo * arithmetic trickery to generate the anchor point A in NED where that * square grid has to be centered. * Here the Earth is a perfect sphere of radius earth_MAJOR and the local * terrain altitude is ignored in order to calculate A, but the result is * good enough. * @param c Craft, for NED to XYZ transformation. * @param local_z Local altitude of the terrain below the aircraft. * @param groundColor * @param ps Polygons set to add to. */ static void render_drawTiledTerrain(craft * c, double local_z, VColor_Type *groundColor, VPolySet *ps) { // Evaluate each tile size as angles: double cos_lat = cos(c->w.latitude); double sin_lat = sin(c->w.latitude); double cos_lon = cos(c->w.longitude); double sin_lon = sin(c->w.longitude); // Each tile north-to-south size (RAD): double lat_step = 2 * visibility / (n - 1) / earth_MAJOR; if( lat_step < units_DEGtoRAD(1/3600.0) ) // not less than 1 arc second lat_step = units_DEGtoRAD(1/3600.0); else if( lat_step > units_DEGtoRAD(1) ) // no more than 1 degree lat_step = units_DEGtoRAD(1); // Each tile west-to-east size (RAD): double lon_step = lat_step; while( cos_lat * lon_step < lat_step / 2 ) // tile height at least half width lon_step *= 2; // Compute anchor point of the grid in NED: VPoint A; A.x = - earth_MAJOR * myfmod(c->w.latitude, lat_step); A.y = - earth_MAJOR * cos_lat * myfmod(c->w.longitude, lon_step); A.z = c->w.z - local_z; // ...then transform in world coordinates: VReverseTransform(&A, &c->XYZtoNED, &A); int h, v; VPoint grid[n][n]; for(h = 0; h < n; h++){ for(v = 0; v < n; v++){ double delta_lat = (h - n/2) * lat_step; double delta_lon = (v - n/2) * lon_step; /* * Exact formulas for the points of the grid are: * * grid[h][v].x = earth_MAJOR * cos(lat+delta_lat) * sin(lon+delta_lon) * grid[h][v].y = earth_MAJOR * cos(lat+delta_lat) * sin(lon+delta_lon) * grid[h][v].z = earth_MAJOR * sin(lat+delta_lat) * * where lat,lon are the coords of A. Here the first order approximation * on delta_lat,delta_lon is used to save some sin() and cos() calculations: */ VSetPoint(&grid[h][v], A.x - earth_MAJOR * ( cos_lat * sin_lon * delta_lon + cos_lon * sin_lat * delta_lat), A.y + earth_MAJOR * ( cos_lat * cos_lon * delta_lon - sin_lon * sin_lat * delta_lat), A.z + earth_MAJOR * cos_lat * delta_lat); } } for(h = 0; h < n-1; h++){ for(v = 0; v < n-1; v++){ VPoint tile[4]; tile[0] = grid[h+1][v]; tile[1] = grid[h+1][v+1]; tile[2] = grid[h][v+1]; tile[3] = grid[h][v]; VPolySet_Add(ps, VCreatePolygon(4, tile, groundColor)); } } } /** * Add terrain to the polygons set. * @param c Craft, for NED to XYZ transformation. * @param local_z Local altitude of the terrain below the aircraft. * @param ps Polygons set to add to. */ static void render_addTerrain(craft * c, double local_z, VColor_Type *groundColor, VPolySet *ps) { if( ground_mode == render_GROUND_FLAT ) render_drawFlatTerrain(c, local_z, groundColor, ps); else render_drawTiledTerrain(c, local_z, groundColor, ps); } /** * Add item 'p' to the list of items to draw for the view from craft 'c'. * @param c * @param p * @param zmin Draw only if above this altitude (m). * @param zmax Draw only if below this altitude. */ static void insertToDraw(craft * c, craft * p, double zmin, double zmax) { double distance; if( !(zmin <= p->w.z && p->w.z < zmax) ) return; /* * FIXME: original comment below might need update. * * Here's a kludge for you: to avoid polygon clipping, I'm going to * cheat and hack a way to get ground objects to display properly. * if the Z coordinate of an object is zero (i.e. on ground objects), * I'll add a huge offset to their distance values to force them to be * plotted first -- and in roughly their correct drawing order. * * To support automated world outline maps, stbl[0] is considered to be * the world map, and will always be plotted in the background. */ if( p->cinfo->object == NULL ){ printf("%s:%d: p->cinfo->object is NULL for %s\n", __FILE__, __LINE__, p->cinfo->name); return; } if( p->cinfo->object->name[0] == '#' ){ /* * Object name beginning with '#' is handled in special way, as its * distance is set beyond the center of the Earth. This ensures it will * be painted first on the background. Typically it is the FEATURE * representing the terrain surface. */ distance = (7000.0 * units_NmToFeetFactor) * (7000.0 * units_NmToFeetFactor); } else { /* * "Normal" item: compute its distance from us -- well, actually the * square of that distance, but it does not matter here. */ VPoint ds; ds.x = p->Sg.x - c->Sg.x; ds.y = p->Sg.y - c->Sg.y; ds.z = p->Sg.z - c->Sg.z; distance = VMagnitude2(&ds); } /* Add item to draw to the array, allocating more space if necessary: */ if( toDrawLen >= toDrawCapacity ){ // Increase capacity about +50%: toDrawCapacity = toDrawCapacity + toDrawCapacity/2 + 10; toDraw = memory_realloc(toDraw, toDrawCapacity * sizeof(ItemToDraw)); } toDraw[toDrawLen++] = (ItemToDraw) {distance, p}; } /** * Compares order of items to draw for qsort(); nearest comes first. * @param a * @param b * @return */ static int toDrawCmp(const void *a, const void *b) { double d = ((ItemToDraw *)a)->distance - ((ItemToDraw *)b)->distance; if( d < 0 ) return -1; else if( d > 0 ) return +1; else return 0; } static void renderCockpitView ( craft *c, viewer *u ) { instruments_update(u); if( ! gui_isVisible(u->gui) ) return; /* * Build a vector of polygons for all objects in the scene. * * This vector should be ordered from "most distant" to "closest" so that * the final display will end up correct. Rather than generalizing this * to death, we'll use a few heuristics to get very close to what we need: * * (0) Build a single polygon to represent the ground. * (1) Objects on the surface (stbl) are collected first. * (2) Planes and projectiles (ptbl and mtbl) are first sorted in * descending order by their distance from the observer and then * polygons are collected. */ VPolySet *ps, *ps_clipped; VPolygon *poly, *poly_clipped; craft *p; int j; VPoint tmp, vp, fwd, up; double v, view_dist, local_z, zmin, zmax; static _BOOL blink = FALSE; static double blink_toggle_time = 0.0; craft *vc; VSetClipRect(u->v, &u->v->rect); /* * pay attention: vc will be the viewer craft information, c will be * the watched entity craft information */ vc = c; if ( c->type == CT_DIS_STEALTH ) { if ( c->vl->viewer_state == ViewerStatePiggyback ) { c = c->vl->watchedCraft; } } /* * Set up the eye space transformation for this viewpoint */ if (vc->flags & FL_CHASE_VIEW) { /* * Set a convenient distance of view behind the aircraft based * on the estimated length of the actual aircraft (m). */ view_dist = -10 * units_FEETtoMETERS(fabs(c->cinfo->rn.x - c->cinfo->rm.x)); /* * Set viewpoint vp in world frame XYZ (m). * If the ground speed (projection of c->Cg over the horizontal plane) * is greater than 2 m/s, use this as direction of view, otherwise * use the current heading. */ tmp = c->Cg; tmp.z = 0.0; VReverseTransform_(&tmp, &c->XYZtoNED, &vp); v = VMagnitude(&vp); if (v > 2.0) { vp.x *= view_dist / v; vp.y *= view_dist / v; vp.z *= view_dist / v; } else { tmp.x = view_dist * cos(c->curHeading); tmp.y = view_dist * sin(c->curHeading); tmp.z = 0.0; VReverseTransform_(&tmp, &c->XYZtoNED, &vp); } vp.x += c->Sg.x; vp.y += c->Sg.y; vp.z += c->Sg.z; /* * Look at the CM, world frame (m). */ fwd = c->Sg; /* * Set "up" point position in world XYZ (m). */ tmp.x = tmp.y = 0.0; tmp.z = -1.0; VReverseTransform_(&tmp, &c->XYZtoNED, &up); up.x += vp.x; up.y += vp.y; up.z += vp.z; } else { if (c->cinfo) { VTransform_(&c->cinfo->viewPoint, &(c->trihedral), &tmp); } else { tmp.x = tmp.y = tmp.z = 0.0; } tmp.x = units_FEETtoMETERS(tmp.x); tmp.y = units_FEETtoMETERS(tmp.y); tmp.z = units_FEETtoMETERS(tmp.z); VReverseTransform(&tmp, &c->XYZtoNED, &vp); VTransform_(&u->viewDirection, &(c->trihedral), &tmp); VReverseTransform_(&tmp, &c->XYZtoNED, &fwd); fwd.x += vp.x; fwd.y += vp.y; fwd.z += vp.z; VTransform_(&u->viewUp, &(c->trihedral), &tmp); VReverseTransform_(&tmp, &c->XYZtoNED, &up); up.x += vp.x; up.y += vp.y; up.z += vp.z; } local_z = terrain_localAltitude(c); VGetEyeSpace(u->v, vp, fwd, up); ps = VPolySet_New(); toDrawLen = 0; /* * Add the Sun to the polygons we will draw later along with aircraft etc. * As a side beneficial effect, we get the Sun elevation over the * horizon which allows to compute a general brightness factor, which in * turn allows to calculate the sky color and general scene brightness. */ double sun_elevation_over_terrain = render_addSun(c, ps); double terrain_brightness = (sun_elevation_over_terrain + units_DEGtoRAD(6)) / units_DEGtoRAD(10); if( terrain_brightness < 0 ) terrain_brightness = 0.0; else if( terrain_brightness > 1.0 ) terrain_brightness = 1.0; /* * Compute Sun elevation over the far horizon of the Earth. * Start assuming we are still very close to the ground: */ double sun_elevation_over_horizon = sun_elevation_over_terrain; double far_horizon_brightness = terrain_brightness; double half_globe_tan = INFINITY; // If pilot can see far horizon, do a precise calculation: if( c->w.z > 0 && c->w.z - local_z > 1.0 ){ double r = c->w.z / earth_MAJOR; // Apparent half-angular size of the Earth as seen from the craft: half_globe_tan = 1.0 / sqrt(r*(r+2)); sun_elevation_over_horizon += M_PI/2 - atan(half_globe_tan); far_horizon_brightness = (sun_elevation_over_horizon + units_DEGtoRAD(2)) / units_DEGtoRAD(4); if( far_horizon_brightness < 0 ) far_horizon_brightness = 0; else if( far_horizon_brightness > 1 ) far_horizon_brightness = 1; } /* * Compute sky color. Note that each color component of the sky follows a * different law for even nicer dusk effects. Sky becomes darker at high * altitude. */ double altitudeFactor = 10000.0 / (fabs(c->w.z) + 10000.0); int skyColor = gui_getColorIndex(NULL, 150*sqrt(far_horizon_brightness)*altitudeFactor, // red prevails at dusk 150*far_horizon_brightness*altitudeFactor, 220*far_horizon_brightness*far_horizon_brightness*altitudeFactor // blue prevails in plain light ); VColor_Type *cloudsColor = VColor_getByRGB( 200*terrain_brightness, 200*terrain_brightness, 200*terrain_brightness, 0); int hazeComponent = 176*terrain_brightness; VColor_Type *hazeColor = VColor_getByRGB( hazeComponent, hazeComponent, hazeComponent, 0); /* * Draw far horizon, that is the round shape of the Earth. The "round shape" * here is an... hexagon drawn at some safe distance between the center of * the Earth and the terrain below to avoid overlapping with the terrain * polygons. */ if( far_horizon_brightness > 0 ){ double d = earth_MAJOR/2 + c->w.z; // safe distance below aircraft double r = d * half_globe_tan; // radius of the hexagon int farHorizonComponent = 176*far_horizon_brightness; VColor_Type *farHorizonColor = VColor_getByRGB( farHorizonComponent, farHorizonComponent, farHorizonComponent, 0); render_addHorizontalLayer(c, farHorizonColor, d, r, ps); } /* * Configure Alib depth cueing color and culling distance: */ Alib_setVisibility(u->w, visibility, hazeColor); /* * Ground color name. If the zone the craft is flying over defines a * ground color, set that color, otherwise use the default. */ char *newGroundColorName = render_DEFAULT_GROUND_COLOR; if( c->zone != NULL && zone_isLoaded(c->zone) && zone_getGroundColor(c->zone) != groundColorName ){ newGroundColorName = zone_getGroundColor(c->zone); groundColor = VColor_getByName(newGroundColorName, ground_mode == render_GROUND_TILED); } /* Compute dimmed ground color. */ VColor_Type *dimGroundColor = VColor_getByRGB( terrain_brightness * VColor_getRed(groundColor), terrain_brightness * VColor_getGreen(groundColor), terrain_brightness * VColor_getBlue(groundColor), ground_mode == render_GROUND_TILED); if( clouds_top <= clouds_base ){ // No clouds. // Sky. VFillRectangle(u->v, &u->v->rect, skyColor); // Terrain below: render_addTerrain(c, local_z, dimGroundColor, ps); // Draw items from sea level up to the deep outer space: zmin = 0.0; zmax = INFINITY; } else if( c->w.z < clouds_base ){ // Craft between terrain and clouds base. // Sky. VFillRectangle(u->v, &u->v->rect, skyColor); // Terrain below: render_addTerrain(c, local_z, dimGroundColor, ps); // Clouds above: render_addHorizontalLayer(c, cloudsColor, c->w.z - clouds_base, 1e5, ps); // Draw items from sea level up to the clouds base: zmin = 0.0; zmax = clouds_base; } else if( c->w.z < clouds_top ){ // Craft inside clouds. // Pilot can't see nothing but a bright gray: VFillRectangle(u->v, &u->v->rect, VColor_getIndex(cloudsColor)); // Nothing to draw - set impossible range: zmin = 0.0; zmax = -1.0; } else { // Craft above clouds. // Sky. VFillRectangle(u->v, &u->v->rect, skyColor); // Clouds below: render_addHorizontalLayer(c, cloudsColor, c->w.z - clouds_top, 1e5, ps); // Draw items from clouds top up to the deep outer space: zmin = clouds_top; zmax = INFINITY; } // Perspective on terrain and clouds polygons drawn so far: poly = VPolySet_First(ps); while( poly != NULL ){ VTransformPolygon(poly, &u->v->eyeSpace); poly = VPolySet_Next(ps); } // Add surface elements: for (p = stbl; p != NULL; p = p->next) { insertToDraw(c, p, zmin, zmax); } for ((j = 0, p = ptbl); j < manifest_MAXPLAYERS; (++j, ++p)) { if (p->type != CT_FREE && p->type != CT_DIS_STEALTH && (p != c || c->flags & FL_CHASE_VIEW)) { insertToDraw(c, p, zmin, zmax); } } for ((j = 0, p = mtbl); j < manifest_MAXPROJECTILES; (++j, ++p)) { if (p->type != CT_FREE) { insertToDraw(c, p, zmin, zmax); } } /* Sort items to draw in increasing order of distance from 'c': */ qsort(toDraw, toDrawLen, sizeof(ItemToDraw), toDrawCmp); /* Painter algorithm: draw far items first, near last: */ for(j = toDrawLen-1; j >= 0; j--) place_craft(u->v, c, u, toDraw[j].item, ps); /* * Display this image for each viewer associated with this craft */ /* FIXME: to do */ /* * Clip all polygons against the view frustum. * * Attention: we can't release the ps set of polygons right * after the clipping because polygons completely visible * are shared with ps_clipped set. */ ps_clipped = VPolySet_New(); poly = VPolySet_First(ps); while( poly != NULL ){ VPolySet_Set(ps, NULL); poly = VClipSidedPolygon(poly, u->v->clipPoly); if( poly != NULL ) VPolySet_Add(ps_clipped, poly); poly = VPolySet_Next(ps); } poly_clipped = VPolySet_First(ps_clipped); while( poly_clipped != NULL ){ VFillPolygon(u->v, poly_clipped); poly_clipped = VPolySet_Next(ps_clipped); } /* * Release polygons */ VPolySet_Free(ps, TRUE); ps = NULL; VPolySet_Free(ps_clipped, TRUE); ps_clipped = NULL; hud_draw(u); terminal_draw(u); //browse_page( vc, u ); if ( u->viewer_state == ViewerStateNormal ) { prompt_draw(u); magnetic_compass_draw(u); instruments_draw(u); // instruments panel upper row panel_updateAndDraw(c, u); // instruments panel bottom row doFlightStatusPage(c, u); } if( curTime > blink_toggle_time ){ blink = ! blink; if( blink ) blink_toggle_time = curTime + 0.05; else blink_toggle_time = curTime + 1.2; } if( ! blink ){ char *s = NULL; if ( u->hasFocus && ! u->hasComm ) { s = "[PRESS `d' TO TAKE COMMANDS]"; } else if( dis_if_isValidatingSiteId() ){ s = "Validating site ID"; } else if( u->hasFocus && c->type == CT_DRONE ){ s = "[DRONE]"; } if( s != NULL ){ int len = strlen(s); int fw = (int) (0.6 * RectWidth(u->v->rect) / (double) len); int fh = fw; /* FIXME */ int x = RectMiddleX(u->v->rect) - (fw * len / 2); int y = RectMiddleY(u->v->rect) + (fh / 2); Alib_setClipRect(u->w, &u->v->rect); VDrawStrokeString(u->v, x+1, y, s, len, fh, blackColor); VDrawStrokeString(u->v, x, y, s, len, fh, whiteColor); } } /* Expose the completed drawing */ VExposeBuffer(u->v); } static void setAudio(craft * c) { /* Set engine sound: */ if( damage_isFunctioning(c, SYS_ENGINE1 ) ) sounds_setBackgroundSound(c, c->rpm, (c->flags & FL_AFTERBURNER) ? 1 : 0, 0.0 /* dummy, ignored */); /* Stall warning: */ if( c->damageBits & FLAG_STALL_WARN ) sounds_playSound(c, sounds_StallWarning, TRUE); else sounds_stopSound(c, sounds_StallWarning); /* Low altitude and gear warnings: */ double radar_altitude = units_METERStoFEET(c->w.z - terrain_localAltitude(c)); double vertical_speed = c->Cg.z; /* ft/s */ if( radar_altitude < 2500 /* radar altitude available */ && vertical_speed > 0 /* diving */ ){ int gear_down = gear_nosePosition(c) == 2 && gear_leftPosition(c) == 2 && gear_rightPosition(c) == 2; double time_to_impact = radar_altitude / vertical_speed; if( vertical_speed / time_to_impact > 0.2 * units_earth_g ){ /* diving too fast to recover within 0.2 g limit before impact */ prompt_craft_print(c, "WARNING: pull-up!"); sounds_playSound(c, sounds_GenericWarning, 0); } else if( ! gear_down && time_to_impact < 2 * M_PI_2 / c->cinfo->gearRate ){ /* no time left to extend gear (2 factor for extra safety) */ prompt_craft_print(c, "WARNING: pull-up!"); sounds_playSound(c, sounds_GenericWarning, 0); } else if( ! gear_down && time_to_impact < 120 ){ /* no gear, less than 2 min to impact */ prompt_craft_print(c, "WARNING: gear down!"); sounds_playSound(c, sounds_GenericWarning, 0); } } sounds_update(c); } void render_drawCockpitViews(void) { viewer *u; render_init(); for (u = vl_head; u != NULL; u=u->vl_next ) { renderCockpitView( u->c, u ); setAudio(u->c); u->c->zone = zones_load(zones, &u->c->w, u->c->zone, 0); } } void render_setOutsideView(craft * c, viewer *u, render_ViewDirection v) { if (v == render_VIEW_CHASE) { c->flags |= FL_CHASE_VIEW; } else { c->flags &= ~FL_CHASE_VIEW; } switch (v) { case render_VIEW_CHASE: case render_VIEW_FORWARD: u->viewDirection.x = 1.0; u->viewDirection.y = 0.0; u->viewDirection.z = 0.0; u->viewUp.x = 0.0; u->viewUp.y = 0.0; u->viewUp.z = -1.0; break; case render_VIEW_UP: u->viewDirection.x = 0.0; u->viewDirection.y = 0.0; u->viewDirection.z = -1.0; u->viewUp.x = -1.0; u->viewUp.y = 0.0; u->viewUp.z = 0.0; break; case render_VIEW_DOWN: u->viewDirection.x = 0.0; u->viewDirection.y = 0.0; u->viewDirection.z = 1.0; u->viewUp.x = 1.0; u->viewUp.y = 0.0; u->viewUp.z = 0.0; break; case render_VIEW_LEFT: u->viewDirection.x = 0.0; u->viewDirection.y = -1.0; u->viewDirection.z = 0.0; u->viewUp.x = 0.0; u->viewUp.y = 0.0; u->viewUp.z = -1.0; break; case render_VIEW_RIGHT: u->viewDirection.x = 0.0; u->viewDirection.y = 1.0; u->viewDirection.z = 0.0; u->viewUp.x = 0.0; u->viewUp.y = 0.0; u->viewUp.z = -1.0; break; case render_VIEW_AFT: u->viewDirection.x = -1.0; u->viewDirection.y = 0.0; u->viewDirection.z = 0.0; u->viewUp.x = 0.0; u->viewUp.y = 0.0; u->viewUp.z = -1.0; break; } } acm-6.0_20200416/src/acm/commands.h0000644000000000000000000000243513646045023015103 0ustar rootroot/* * acm - Commands interpreter, mostly for debugging * Copyright (C) 2007 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /** * Execute a command given as a string, returning results on the terminal * (see module "terminal") currently active on the given viewer. Mostly * useful for debugging at run-time. Useless for the end user. * * @author Umberto Salsi * @license GNU GPL * @version $Date: 2020/01/08 06:01:45 $ * @file */ #ifndef _commands_h #define _commands_h #include "pm.h" #ifdef commands_IMPORT #define EXTERN #else #define EXTERN extern #endif EXTERN void commands_execute(viewer *u, char *cmd); #undef EXTERN #endif acm-6.0_20200416/src/acm/zones.h0000644000000000000000000000661513646045024014445 0ustar rootroot/** * A "zones" object manages a list of "zone" objects (see) and their state. * * Basically, the zones objects reads the list of the available zones from a * file (normally objects/zones.txt) and initializes a corresponding list of * "zone" objects. Each zone is actually read and loaded or unloaded as needed * based on the location of each player (normally only one). * * The zones file is a text file containing one line for each available zone; * each line must contains 5 fields separated by at least one white space: * * 1. Minimum covered latitude. * 2. Maximum covered latitude. * 3. Minimum covered longitude. * 4. Maximum covered longitude. * 5. File name of the ACM scenery; may contain a path relative to the * zones file itself. * * Latitudes and longitudes may have the usual syntax, examples: * * 10N 10-20-30.400S 30.5S * 10E 10-20-30.400W 30.5W * * The ordering is important, so 90S < 90N, 180W < 180E. * * For each zone (that is, each ACM scenery file) a specific zone object is * created; runways, craft types, features and NAVAIDS belonging to a specific * zone, have that zone as one of their "struct" field. That field allows to * recognize to which zone each object belongs. * * Each player's aircraft (normally only one per program) should then feed its * current position by calling the zones_load() function, which in turn triggers * the loading of the appropriate scenery; sceneries that are not needed anymore * are removed from memory along with all their own objects. * * @file * @author Umberto Salsi * @version $Date: 2020/01/08 06:11:32 $ */ #ifndef ZONES_H #define ZONES_H #include "../dis/dis/earth.h" #include "zone.h" #ifdef zones_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Available zones and their state. */ typedef struct zones_Type zones_Type; /** * Creates a new zones object. The zones file is read, ranges of latitude and * longitude for each zone is parsed, sceneries files are checked for * readability but not read yet. Non-fatal errors while parsing the zones file * are sent to standard error; fatal errors causes abort. * @param path Path of the zones file, normally objects/zones.txt. * @return New zones object. Must be released with memory_dispose(), which in * turn triggers the release of any loaded zone and all the items therein * defined. */ EXTERN zones_Type * zones_new(char *path); /** * Feed the zones object with the current position of a player. In turn, this * may update the zones cache by triggering the loading or the un-loading of some * zone. For performances reason, this request is only evaluated from time to * time and ignored most of the times. * @param this Zones object. * @param p Position of the player; the altitude does not matter. * @param last_known Last known zone the point (that is, the craft) was flying * over. Set to NULL if still unknown. * @param forced If true, forces the evaluation of the position and guarantees * the appropriate zone be loaded immediately if available. * @return Current zone below the specified point. If forced update has been * requested, this is the real zone below the point, possibly NULL if no zone * available. If not forced, the last know zone is returned most of the times. */ EXTERN zone_Type * zones_load(zones_Type *this, earth_LatLonAlt *p, zone_Type *last_known, int forced); #undef EXTERN #endif acm-6.0_20200416/src/acm/aim9m.h0000644000000000000000000000177013064355617014326 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #ifndef _aim9m_h #define _aim9m_h #include "weapon.h" #ifdef aim9m_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Creates weapon description record for the AIM-9M missile. */ EXTERN weapon_Type * aim9m_new(void); #undef EXTERN #endif acm-6.0_20200416/src/acm/zone.c0000644000000000000000000005310713260344464014255 0ustar rootroot#include #include #include #include #include #include #include "../util/error.h" #include "../util/memory.h" #include "../util/reader.h" #include "../util/units.h" #include "navaid.h" #include "runway.h" #define zone_IMPORT #include "zone.h" /** * Schedule zone purge if nobody flies over or near to a zone for so much * time (s). */ #define zone_EXPIRE_PERIOD_SEC 60 /** * A location is close to a zone if inside or whithin this angle range. * Note that 4 DEG corresponds to about 240 NM while the max range of a NAVAID * under ACM is NM: this guarantees any close scenery be loaded and then any * tunable station can be received. */ #define zone_CLOSE_ANGLE units_DEGtoRAD(4) struct zone_Type { /** * Range of geographic coordinates covered by this zone (RAD). */ double lat1, lat2, lon1, lon2; /** * The zone range enlarged by our DELTA margin. Locations inside this * range of latitude and longitude are close to this zone. * Basically, * close_lat1 = lat1 - DELTA, * close_lat2 = lat2 + DELTA, * close_lon1 = lon1 - DELTA, * close_deltaLon = lon2 - lon1 + 2*DELTA, * but special case must be taken near the poles. The longitude range might * be de-normalized outside the canonical [-180,+180] DEG range. */ double close_lat1, close_lat2, close_lon1, close_deltaLon; /** Path to the ACM scenery file. */ char *path; /** If this scenery is currently loaded in memory. */ int isLoaded; /* * The following fields assigned only if loaded. */ /** Scheduled purge time (s). */ time_t expire; /** Team locations read from the scenery. */ earth_LatLonAlt forceBaseLocations[4]; /** Ground color read from the scenery. */ char *groundColor; }; /** * Recycled surface objects. Objects removed from global surface objects table * stbl goes here. */ static craft *stbl_pool; /** * If cleanup function registered in the memory module. */ static int cleanup_set; static void zone_cleanup() { //printf("DEBUG: %s\n", __FUNCTION__); while( stbl_pool != NULL ){ craft *next = stbl_pool->next; memory_dispose(stbl_pool); stbl_pool = next; } cleanup_set = 0; } /** * Returns a brand new craft data structure linked to the surface objects table. * @return */ static craft * zone_craftNew() { craft *c; if( stbl_pool == NULL ){ c = memory_allocate(sizeof(craft), NULL); memset(c, 0, sizeof(craft)); } else { c = stbl_pool; stbl_pool = c->next; } c->prev = NULL; c->next = stbl; if( stbl != NULL ) stbl->prev = c; stbl = c; return c; } /** * Removes a craft from the surface objects linked list. * @param c */ static void zone_craftRelease(craft *c) { if( c->prev == NULL ){ if( c->next != NULL ) c->next->prev = NULL; stbl = c->next; } else { c->prev->next = c->next; if( c->next != NULL ) c->next->prev = c->prev; } memset(c, 0, sizeof(craft)); c->next = stbl_pool; stbl_pool = c; } static void zone_destruct(void *p) { zone_Type *this = p; //printf("DEBUG: %s %s\n", __FUNCTION__, this->path); zone_purge(this, 1); memory_dispose(this->path); } zone_Type * zone_new(char *path, double lat1, double lat2, double lon1, double lon2) { if( ! cleanup_set ){ memory_registerCleanup(zone_cleanup); cleanup_set = 1; } zone_Type * this = memory_allocate(sizeof(zone_Type), zone_destruct); memset(this, 0, sizeof(*this)); this->path = memory_strdup(path); this->lat1 = lat1; this->lat2 = lat2; this->lon1 = lon1; this->lon2 = lon2; this->groundColor = NULL; this->isLoaded = 0; this->expire = 0; // Compute the range for locations close to this zone. if( lat2 > units_DEGtoRAD(85) ){ // Close to north pole. Take all dome above lat1. this->close_lat1 = lat1 - zone_CLOSE_ANGLE; this->close_lat2 = units_DEGtoRAD(90); this->close_lon1 = -M_PI; this->close_deltaLon = 2*M_PI; } else if( lat1 < units_DEGtoRAD(-85) ){ // Close to south pole. Take all dome below lat2. this->close_lat1 = units_DEGtoRAD(-90); this->close_lat2 = lat2 + zone_CLOSE_ANGLE; this->close_lon1 = -M_PI; this->close_deltaLon = 2*M_PI; } else { this->close_lat1 = lat1 - zone_CLOSE_ANGLE; this->close_lat2 = lat2 + zone_CLOSE_ANGLE; // Meridians are very close together near poles, so zone_CLOSE_ANGLE // must be adjusted by a 1/cos(lat) factor; take the max: double dlon_south = zone_CLOSE_ANGLE / cos(lat1); double dlon_north = zone_CLOSE_ANGLE / cos(lat2); double dlon; if( dlon_north < dlon_south ) dlon = dlon_south; else dlon = dlon_north; this->close_lon1 = lon1 - dlon; this->close_deltaLon = lon2 - lon1 + 2*dlon; } return this; } int zone_isLoaded(zone_Type *this) { return this->isLoaded; } char * zone_getPath(zone_Type *this) { return this->path; } char * zone_getGroundColor(zone_Type *this) { return this->groundColor; } earth_LatLonAlt * zone_getForceBaseLocation(zone_Type *this, int force) { assert(0 <= force && force < 4); if( ! this->isLoaded ) return NULL; return &this->forceBaseLocations[force]; } /** Returns true if the zone includes the location. */ int zone_includesLocation(zone_Type *this, earth_LatLonAlt *w) { return this->lat1 <= w->latitude && w->latitude < this->lat2 && this->lon1 <= w->longitude && w->longitude < this->lon2; } /** * Normalize angle difference B-A for a point moving from a longitude A to * longitude B walking east. For example, going from longitude 30 to 40 is a * walk of 10 DEG; vice-versa, going from 40 to 30 still walking east is a * 350 DEG walk. */ static double zone_goEast(double x) { while(x < 0) x += M_PI; return x; } int zone_isClose(zone_Type *this, earth_LatLonAlt *p) { return this->close_lat1 <= p->latitude && p->latitude < this->close_lat2 && zone_goEast(p->longitude - this->close_lon1) < this->close_deltaLon; } int zone_overlaps(zone_Type *this, zone_Type *other) { return !( (this->lat2 <= other->lat1 || other->lat2 <= this->lat1) || (this->lon2 <= other->lon1 || other->lon2 <= this->lon1) ); } #define parse_error(in, ...) \ { \ fprintf(stderr, "%s:%d: ", reader_getPath(in), reader_getLineNumber(in)); \ fprintf(stderr, __VA_ARGS__); \ fprintf(stderr, "\n"); \ } /** * Remove some of the detail in an object to reduce the CPU overhead * of transforming and clipping it. * * FIXME: quite arbitrary algorithm -- to be revised. * We might, for example, "linearize" near straight lines. * For now, applies only to polygons with more than 9 vertices. */ static void zone_undersampleObject (VObject * obj, int rate) { int i, j, k; k = 0; for (i = 0; i < obj->numPolys; ++i) { if( obj->polygon[i]->numVtces < 9 ) continue; for (j = 0; j < obj->polygon[i]->numVtces; j += rate) { obj->polygon[i]->vertex[k++] = obj->polygon[i]->vertex[j]; } obj->polygon[i]->numVtces = k; } } static int zone_parseDouble(reader_Type *in, char *s, double *freq) { char *tail; *freq = strtod(s, &tail); if( tail == s || *tail != 0 || ! isfinite(*freq) ){ fprintf(stderr, "%s:%d: invalid decimal number syntax: %s\n", reader_getPath(in), reader_getLineNumber(in), s); return 0; } return 1; } /** * Parses the latitude, longitude and altitude fields. * @param in Input file to generate punctual error messages. * @param lat Latitude string. * @param lon Longitude string. * @param alt Altitude (ft). * @param w Put result here. * @return True if parsing succeeded; false if parsing failed and an error has * been sent to standard error. */ static int zone_parseLatLonAlt(reader_Type *in, char *lat, char *lon, char *alt, earth_LatLonAlt *w) { if( ! earth_parseLatitude(lat, &w->latitude) ){ fprintf(stderr, "%s:%d: invalid latitude syntax: %s\n", reader_getPath(in), reader_getLineNumber(in), lat); return 0; } if( ! earth_parseLongitude(lon, &w->longitude) ){ fprintf(stderr, "%s:%d: invalid longitude syntax: %s\n", reader_getPath(in), reader_getLineNumber(in), lon); return 0; } if( ! zone_parseDouble(in, alt, &w->z) ) return 0; w->z = units_FEETtoMETERS(w->z); return 1; } static void zone_parseTeamLocationRecord(zone_Type *this, reader_Type *in, char **argv, int argc, int team_no) { if( argc != 5 ){ fprintf(stderr, "%s:%d: invalid number of fields in %s record\n", reader_getPath(in), reader_getLineNumber(in), argv[0]); return; } if( ! zone_parseLatLonAlt(in, argv[1], argv[2], argv[3], &this->forceBaseLocations[team_no]) ) return; if( ! zone_includesLocation(this, &this->forceBaseLocations[team_no]) ) fprintf(stderr, "%s:%d: team location outside range of zone %s\n", reader_getPath(in), reader_getLineNumber(in), this->path); double heading; if( ! zone_parseDouble(in, argv[4], &heading) ) return; } /** * Parses RWY and RWY2 records and add to the surface list array. * @param in * @param argv Fields of the scene record. * @param argc Number of fields in the record. */ static void zone_parseRunwayRecord(zone_Type *this, reader_Type *in, char **argv, int argc) { double heading, mag, length, width; int j; VPoint fwd, down, local_fwd, local_right, local_down; earth_LatLonAlt w, w1, w2; VPoint xyz; VPolygon *p; if (strcmp(argv[0], "RWY") == 0) { if( argc != 10 ){ parse_error(in, "invalid number of fields in runway record -- ignoring."); return; } if( ! zone_parseDouble(in, argv[4], &length) ) return; length = units_FEETtoMETERS(length); if( ! zone_parseDouble(in, argv[5], &width) ) return; width = units_FEETtoMETERS(width); if( ! zone_parseLatLonAlt(in, argv[6], argv[7], argv[3], &w) ) return; if( ! zone_parseLatLonAlt(in, argv[8], argv[9], argv[3], &w1) ) return; earth_LatLonAltToXYZ(&w, &xyz); VPoint xyz1; earth_LatLonAltToXYZ(&w1, &xyz1); /* * Calculate runway forward direction: */ local_fwd.x = xyz1.x - xyz.x; local_fwd.y = xyz1.y - xyz.y; local_fwd.z = xyz1.z - xyz.z; mag = sqrt ( local_fwd.x * local_fwd.x + local_fwd.y * local_fwd.y + local_fwd.z * local_fwd.z ); local_fwd.x /= mag; local_fwd.y /= mag; local_fwd.z /= mag; /* * Average those two points to generate a midpoint that will be the * origin of a runway coordinate system. */ xyz.x = (xyz.x + xyz1.x) / 2.0; xyz.y = (xyz.y + xyz1.y) / 2.0; xyz.z = (xyz.z + xyz1.z) / 2.0; earth_XYZToLatLonAlt(&xyz, &w2); if( ! zone_includesLocation(this, &w2) && ! zone_includesLocation(this, &w1) ) fprintf(stderr, "%s:%d: RWY %s %s middle point outside of the zone\n", reader_getPath(in), reader_getLineNumber(in), argv[1], argv[2]); VMatrix XYZtoNED; earth_generateWorldToLocalMatrix(&w2, &XYZtoNED); down.z = 1.0; down.x = down.y = 0.0; VReverseTransform_(&down, &XYZtoNED, &local_down); /* * Calculate runway heading, normalized to [0,pi[ and fix the * local_fwd direction accordingly: */ VPoint q; VTransform_(&local_fwd, &XYZtoNED, &q); heading = atan2(q.y, q.x); if( heading < 0.0 ){ heading += M_PI; local_fwd.x = -local_fwd.x; local_fwd.y = -local_fwd.y; local_fwd.z = -local_fwd.z; } } else { // RWY2 if( argc != 9 ){ parse_error(in, "invalid number of fields in runway record -- ignoring."); return; } if( ! zone_parseDouble(in, argv[4], &length) ) return; length = units_FEETtoMETERS(length); if( ! zone_parseDouble(in, argv[5], &width) ) return; width = units_FEETtoMETERS(width); if( ! zone_parseDouble(in, argv[8], &heading) ) return; heading = units_DEGtoRAD(heading); /* In order to correctly place the runway numbers, the local_fwd vector must be oriented in the range [0,pi[: */ if( heading >= M_PI ) heading -= M_PI; if( ! zone_parseLatLonAlt(in, argv[6], argv[7], argv[3], &w) ) return; if( ! zone_includesLocation(this, &w) ) fprintf(stderr, "%s:%d: the middle point of the runway lies outside of the zone\n", reader_getPath(in), reader_getLineNumber(in)); earth_LatLonAltToXYZ(&w, &xyz); VMatrix XYZtoNED; earth_generateWorldToLocalMatrix(&w, &XYZtoNED); fwd.x = cos(heading); fwd.y = sin(heading); fwd.z = 0.0; VReverseTransform_(&fwd, &XYZtoNED, &local_fwd); down.z = 1.0; down.x = down.y = 0.0; VReverseTransform_ (&down, &XYZtoNED, &local_down); } /* * Calculate the local right vector in geocentric XYX. * A basic property of Cross Products: k x i = j */ VCrossProd(&local_down, &local_fwd, &local_right); /* * Generate a transformation matrix to get from "runway" coordinates to * Geocentric. The x axis of the runway coord. (local_fwd) points in the * range [0,180[ DEG of the geographical coords. */ VMatrix RWYtoXYZ; VIdentMatrix(&RWYtoXYZ); RWYtoXYZ.m[0][0] = local_fwd.x; RWYtoXYZ.m[1][0] = local_fwd.y; RWYtoXYZ.m[2][0] = local_fwd.z; RWYtoXYZ.m[0][1] = local_right.x; RWYtoXYZ.m[1][1] = local_right.y; RWYtoXYZ.m[2][1] = local_right.z; RWYtoXYZ.m[0][2] = local_down.x; RWYtoXYZ.m[1][2] = local_down.y; RWYtoXYZ.m[2][2] = local_down.z; RWYtoXYZ.m[0][3] = xyz.x; RWYtoXYZ.m[1][3] = xyz.y; RWYtoXYZ.m[2][3] = xyz.z; char *airport = argv[1]; char *runways_no = argv[2]; VPolySet *ps = runway_build(runways_no, &RWYtoXYZ, length, width, heading); /* * We create a "craft type" for each airport. * * Optimize a bit here and put all the runways for a given airport * in the same object, assuming runways are listed per airport. * NOTE. With this optimization, a runway that crosses another one * will hide part of this latter. Otherwise without this * optimization the two overlapping parts are rendered * alternatively one and the other producing a bad flickering * effect, I don't know why. */ VObject *object; if( stbl == NULL ) object = NULL; else object = stbl->cinfo->object; if ((object != NULL) && (strcmp(object->name, airport) == 0)) { /* * New runway at same airport as the last one. Optimize by adding a * polygon to the last runway. */ object->polygon = memory_realloc( object->polygon, sizeof (VPolygon *) * (object->numPolys + VPolySet_Count(ps))); j = 0; p = VPolySet_First(ps); while( p != NULL ){ object->polygon[object->numPolys + j] = p; p = VPolySet_Next(ps); j++; } object->numPolys += VPolySet_Count(ps); VPolySet_Free(ps, 0); VComputeObjectExtent (object); } else { /* * New airport. New object and craftInfo. */ object = memory_allocate(sizeof(VObject), NULL); memset(object, 0, sizeof(VObject)); object->name = memory_strdup(airport); object->numPolys = VPolySet_Count(ps); object->polygon = memory_allocate( sizeof(VPolygon *) * object->numPolys, NULL ); p = VPolySet_First(ps); j = 0; while( p != NULL ){ object->polygon[j++] = p; p = VPolySet_Next(ps); } VPolySet_Free(ps, 0); object->order = NULL; VComputeObjectExtent (object); craft *c = zone_craftNew(); c->zone = this; c->type = CT_SURFACE; c->flags = FL_FIXED_OBJECT; c->w = w; /* * The terrain module needs the center position of the airport (or of * any nearby runway) to calculate altitude of the terrain. */ c->Sg.x = xyz.x; c->Sg.y = xyz.y; c->Sg.z = xyz.z; /* Create new craft info only if really necessary. */ c->cinfo = inventory_craftTypeSearchByZoneAndName(this, airport); if( c->cinfo == NULL ){ // FIXME: BUG: these airports are not released along with the zone. c->cinfo = inventory_craftTypeNew(this); c->cinfo->name = memory_strdup(airport); c->cinfo->object = object; c->cinfo->placeProc = NULL; } } } static void zone_parseNavRecord(zone_Type *this, reader_Type *in, char **argv, int argc) { if( argc != 8 ){ fprintf(stderr, "%s:%d: invalid number of fields in NAV record\n", reader_getPath(in), reader_getLineNumber(in)); return; } earth_LatLonAlt w; if( ! zone_parseLatLonAlt(in, argv[3], argv[4], argv[5], &w) ) return; if( ! zone_includesLocation(this, &w) ) fprintf(stderr, "%s:%d: NAV outside range of zone %s\n", reader_getPath(in), reader_getLineNumber(in), this->path); double freq; if( ! zone_parseDouble(in, argv[6], &freq) ) return; navaid_add_vor_dme_ndb(this, argv[1], argv[2], &w, freq); } static void zone_parseILSRecord(zone_Type *this, reader_Type *in, char **argv, int argc) { if( argc != 13 ){ fprintf(stderr, "%s:%d: invalid number of fields in ILS record\n", reader_getPath(in), reader_getLineNumber(in)); return; } earth_LatLonAlt localizer; if( ! zone_parseLatLonAlt(in, argv[5], argv[6], argv[9], &localizer) ) return; if( ! zone_includesLocation(this, &localizer) ) fprintf(stderr, "%s:%d: LOCALIZER outside range of zone %s\n", reader_getPath(in), reader_getLineNumber(in), this->path); // FIXME: check presence of the GS based on the type of ILS. earth_LatLonAlt gs = (earth_LatLonAlt){0, 0, 0}; double gs_angle = 0; if( strcmp(argv[7], "-") != 0 ){ if( ! zone_parseLatLonAlt(in, argv[7], argv[8], "0", &gs) ) return; if( ! zone_includesLocation(this, &gs) ) fprintf(stderr, "%s:%d: GS outside range of zone %s\n", reader_getPath(in), reader_getLineNumber(in), this->path); gs.z = localizer.z; if( ! zone_parseDouble(in, argv[12], &gs_angle) ) return; } double freq; if( ! zone_parseDouble(in, argv[4], &freq) ) return; double loc_width; if( ! zone_parseDouble(in, argv[10], &loc_width) ) return; double loc_bearing; if( ! zone_parseDouble(in, argv[11], &loc_bearing) ) return; navaid_add_ils(this, argv[3], argv[2], &localizer, &gs, freq, loc_width, loc_bearing, gs_angle); } static void zone_parseFeature(zone_Type *this, reader_Type *in, char **argv, int argc) { if( argc != 6 ){ fprintf(stderr, "%s:%d: invalid number of fields in FEATURE record\n", reader_getPath(in), reader_getLineNumber(in)); return; } earth_LatLonAlt w; if( ! zone_parseLatLonAlt(in, argv[2], argv[3], argv[4], &w) ) return; if( ! zone_includesLocation(this, &w) ) fprintf(stderr, "%s:%d: FEATURE outside range of zone %s\n", reader_getPath(in), reader_getLineNumber(in), this->path); double heading; if( ! zone_parseDouble(in, argv[5], &heading) ) return; heading = units_DEGtoRAD(heading); int depthcue = 1; int undersample = 0; char *fn = argv[1]; if (*fn == '@') { fn++; undersample = 1; } if (*fn == '+') { fn++; depthcue = 0; } craft *c = zone_craftNew(); c->zone = this; c->type = CT_SURFACE; c->w = w; earth_LatLonAltToXYZ(&c->w, &c->Sg); c->curHeading = pm_normalize_yaw(heading); c->cinfo = inventory_craftTypeSearchByZoneAndName(this, fn); if ( c->cinfo == NULL ) { /* Create new inventory object from this feature. */ char *fn_resolved = reader_resolveRelativePath(reader_getPath(in), fn); char *p = strrchr(fn_resolved, '.'); FILE *f = fopen(fn_resolved, "r"); if (f == NULL){ parse_error(in, "failed opening %s: %s", fn_resolved, strerror(errno)); memory_dispose(fn_resolved); zone_craftRelease(c); return; } c->cinfo = inventory_craftTypeNew(this); c->cinfo->name = fn_resolved; c->cinfo->object = NULL; if (p != NULL && (strcmp(p, ".dxf") == 0 || strcmp(p, ".DXF") == 0)) { c->cinfo->object = VReadDepthCueuedDXFObject(f, depthcue); } else { c->cinfo->object = VReadDepthCueuedObject(f, depthcue); } if ( c->cinfo->object == NULL ) { parse_error(in, "failed reading %s: %s", fn_resolved, strerror(errno)); fclose(f); inventory_craftTypeRelease(c->cinfo); zone_craftRelease(c); return; } fclose(f); if (undersample) zone_undersampleObject(c->cinfo->object, 3); } } void zone_load(zone_Type *this) { this->expire = time(NULL) + zone_EXPIRE_PERIOD_SEC; if( this->isLoaded ) return; //printf("DEBUG: loading zone %s\n", this->path); this->isLoaded = 1; this->groundColor = memory_strdup("#305030"); /* * The units used in the objects we've created are expressed in FEET. * Internally, graphics objects should be METERS. */ VPoint scale; scale.x = scale.y = scale.z = units_FEETtoMETERS (1.0); VSetReadObjectScale (&scale); reader_Type *in = reader_new(this->path); char *argv[16], line[1000]; int argc; while( reader_getLine(in, line, sizeof(line)) ){ // Ignore empty and comment lines. if( line[0] == '\0' || line[0] == '#' ) continue; if( ! reader_split(line, &argc, argv, 32) ){ parse_error(in, "too many fields -- ignoring line"); } else if ( strcmp(argv[0], "TEAM1_LOC") == 0 ) { zone_parseTeamLocationRecord(this, in, argv, argc, 1); } else if( strcmp(argv[0], "TEAM2_LOC") == 0 ){ zone_parseTeamLocationRecord(this, in, argv, argc, 2); } else if( strcmp(argv[0], "GROUND_COLOR") == 0 ){ if( argc == 2 ){ memory_dispose(this->groundColor); this->groundColor = memory_strdup(argv[1]); } else { parse_error(in, "invalid number of fields in GROUND_COLOR record"); } } else if (strcmp(argv[0], "RWY") == 0) { zone_parseRunwayRecord(this, in, argv, argc); } else if (strcmp(argv[0], "RWY2") == 0) { zone_parseRunwayRecord(this, in, argv, argc); } else if (strcmp(argv[0], "NAV") == 0) { zone_parseNavRecord(this, in, argv, argc); } else if (strcmp(argv[0], "ILS") == 0) { zone_parseILSRecord(this, in, argv, argc); } else if (strcmp(argv[0], "FEATURE") == 0) { zone_parseFeature(this, in, argv, argc); } else { parse_error(in, "unexpected record `%s' -- ignoring.", argv[0]); } } if( reader_getError(in) != NULL ) error_external("%s: %s", reader_getPath(in), reader_getError(in)); memory_dispose(in); } void zone_purge(zone_Type *this, int forced) { if( ! this->isLoaded ) return; if( ! forced && time(NULL) < this->expire ) this->isLoaded = 0; //printf("DEBUG: releasing zone %s\n", this->path); navaid_purgeZone(this); memory_dispose(this->groundColor); this->groundColor = NULL; craft *c = stbl; while( c != NULL ){ craft *next = c->next; if( c->zone == this ) zone_craftRelease(c); c = next; } inventory_purgeZone(this); } acm-6.0_20200416/src/acm/aim120.c0000644000000000000000000002043513172240620014260 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include #include "pm.h" #include "../util/memory.h" #include "missile.h" #include "init.h" #include "inventory.h" #include "weapon.h" #include "sounds.h" #include "gear.h" #include "../util/units.h" #define aim120_IMPORT #include "aim120.h" static int hasFired[manifest_MAXPLAYERS]; static int count[manifest_MAXPLAYERS]; /* * AIM-120 selection function * * A selection function normally determines whether there are any weapons * of this type on-board. If so, and the weapon system is functional * (in other words, undamaged) then return 1; otherwise return 0. */ static int select_aim120(craft * c) { hasFired[c->pIndex] = 0; count[c->pIndex] = weapon_countOrdinance(c, weapon_AIM120); return 1; } #ifdef FIXME_NOT_USED static double Rmax(craft *c) { return 40.0 * units_NmToFeetFactor; } #endif #ifdef FIXME_NOT_USED static void computeASECircleParameters(craft *c, double * ASE_diameter_millirad, double * ASE_dot_az_millirad, double * ASE_dot_el_millirad) { double range_feet, rmax_feet = Rmax(c), hs, omegay, omegap, h; VPoint v, t, vrel; craft *target; radarInfo *pr = NULL, *p; int i; /* * find target information entry in the radar info table */ for (i = 0, p = c->rinfo; i < c->rtop; ++i, ++p) { if (c->curRadarTarget == p->targetID ) { pr = p; break; } } /* * Without a radar lock, display only the ASE circle. * * We represent this case by passing the ASE diameter as a negative value. */ if ( c->curRadarTarget == -1 || pr == NULL) { *ASE_diameter_millirad = -130.0; *ASE_dot_az_millirad = 0.0; *ASE_dot_az_millirad = 0.0; return; } target = &ptbl[c->curRadarTarget]; /* * Range greater than Rmax? Place aircraft and target on * a lead collision course. */ VSub(&target->Cg, &c->Cg, &v); /* * t becomes relative position of target wrt to aircraft body axes (feet) */ t = pr->rel; VReverseTransform_( &v, &c->trihedral, &vrel ); /* * If range is less than Rmax, compute lead collision based on aircraft * plus missile velocity, not just our aircraft's velocity. */ if (range_feet < rmax_feet) { vrel.x -= 1000.0; /* 1,000 fps is just a SWAG */ } hs = t.x * t.x + t.y * t.y; /* * Omega values are rates of azimuth and elevation changes (rad/sec) */ omegay = (vrel.y * t.x - vrel.x * t.y) / hs; omegap = (vrel.z * hs - t.z * (vrel.x * t.x + vrel.y * t.y)) / (sqrt(hs) * (hs + t.z * t.z)); /* * Just SWAGs here ... */ *ASE_diameter_millirad = 130.0; *ASE_dot_az_millirad = units_RADtoDEG(omegay) * 150.0; *ASE_dot_el_millirad = units_RADtoDEG(omegap) * 150.0; h = sqrt ( *ASE_dot_az_millirad * *ASE_dot_az_millirad + *ASE_dot_el_millirad * *ASE_dot_el_millirad ); /* * Limit ASE "dot" to position just outside the circle */ if (h > 70.0) { *ASE_dot_az_millirad = *ASE_dot_az_millirad * 70.0 / h; *ASE_dot_el_millirad = *ASE_dot_el_millirad * 70.0 / h; } } #endif static int update_aim120(craft * c) { int i; if( ! hasFired[c->pIndex] ) return 1; hasFired[c->pIndex] = 0; /* reset fire request */ /* * Missile won't fire if we have "Weight on wheels" * or if we run out of ammunition. */ if( gear_someWheelGroundContact(c) || count[c->pIndex] <= 0 ) return 1; /* Get station from which to launch the missile: */ i = weapon_getReadyStation(c, weapon_AIM120); if (i < 0){ fprintf(stderr, "Oops. Can't find an AIM-120\n"); return 1; } /* * Decrement missiles counter. * In arcade mode, we never run out of ammunition */ if (arcadeMode == 0) { c->station[i].id = -1; count[c->pIndex]--; } /* Launch missile from station i: */ missile_fire(c, i); sounds_playSound(c, sounds_MissileLaunch, FALSE); return 1; } static int fire_aim120(craft * c) { hasFired[c->pIndex] = 1; return 1; } #ifdef FIXME_NOT_USED static double missileTimeToImpact (craft * c, craftType * w) { double v, t, root1, root2, r, a1, d, n; v = c->VT; a1 = (w->maxThrust - 0.5 * c->rho * w->CDOrigin * v * v) / (w->emptyWeight + w->maxFuel) * units_earth_g; if (c->curRadarTarget >= 0 && a1 >= 0.0) { d = c->targetDistance; r = c->targetClosure; n = r * r + 2.0 * a1 * d; if (n > 0) { n = sqrt(n); root1 = (-r + n) / a1; root2 = (-r - n) / a1; if (root1 >= 0.0) if (root2 >= 0.0) if (root1 < root2) t = root1; else t = root2; else t = root1; else if (root2 >= 0.0) t = root2; else t = -1.0; } else t = -1.0; } else { t = -1.0; } return t; } #endif /* * AIM-120 display function * * Update the HUD display strings associated with this weapon system. * c = the aircraft. * w = the missile's description record. * dummy1, dummy2 = ignored, not set. * * This code may be called by drones, so the viewer may be NULL. * * Return a nonzero value if have a reasonable chance of scoring a kill. */ static int display_aim120(craft * c, craftType * w, viewer * unused, int dummy1, int dummy2) { char s[16]; double d, a1, v, r, root1, root2, n, t; int target; sprintf(s, "%d %s", count[c->pIndex], weapon_idToName(weapon_AIM120)); strcpy(c->leftHUD[3], s); /* * Compute time to target t. Gives < 0.0 if no target available or not * reachable. */ target = c->curRadarTarget; v = VMagnitude(&c->Cg); a1 = (w->maxThrust - 0.5 * c->air.rho * w->CDOrigin * v * v) / (w->emptyWeight + w->maxFuel) * units_earth_g; if (target >= 0 && a1 >= 0.0) { d = c->targetDistance; r = c->targetClosure; n = r * r + 2.0 * a1 * d; if (n > 0) { n = sqrt(n); root1 = (-r + n) / a1; root2 = (-r - n) / a1; if (root1 >= 0.0) if (root2 >= 0.0) if (root1 < root2) t = root1; else t = root2; else t = root1; else if (root2 >= 0.0) t = root2; else t = -1.0; } else t = -1.0; } else t = -1.0; /* * Update HUD display strings. */ if (t < 0.0) sprintf(s, "ARM --"); else if (target >= 0 && t >= (w->armDelay + 0.5) && t <= 90.0) sprintf(s, "LOCKED %d", (int) (t + 0.5)); else if (t <= 90.0) sprintf(s, "IN RANGE %d", (int) (t + 0.5)); else sprintf(s, "ARM %d", (int) (t + 0.5)); strcpy(c->leftHUD[2], s); strcpy(c->leftHUD[4], ""); /* * Return TRUE if we are recommending a missile shot. */ return target >= 0 && t >= (w->armDelay + 0.5) && t <= 90.0; } static weapon_Type aim120Desc = { select_aim120, /* select */ update_aim120, /* update */ display_aim120, /* display procedure */ fire_aim120, /* fire */ (int (*)(craft *)) NULL, /* fire button release */ }; weapon_Type * aim120_new(void) { craftType *c; FILE *f; dis_entity_type em1 = {2, 1, 225, 1, 2, 1, 0}; dis_entity_type em2 = {0, 0, 0, 0, 0, 0, 0}; c = inventory_craftTypeNew(NULL); c->name = memory_strdup( weapon_idToName(weapon_AIM120) ); c->entityType = em1; c->altEntityType = em2; aim120Desc.w = c; c->CDOrigin = 0.2; /* 5" radius of body */ c->CDFactor = -2.56694; c->CDBOrigin = 0.0; c->CDBFactor = 0.0; VIdentMatrix(&(c->I)); c->I.m[0][0] = 0.0; c->I.m[1][1] = 0.0; c->I.m[2][2] = 0.0; c->cmSlope = -1.88; c->wingS = 1.0; /* * Assume 150.0 lb of weight is fuel and that it burns for about 4 seconds. * That yields a fuel burn rate of 40 lb/s. */ c->emptyWeight = 100.0; c->maxFuel = 234.0; c->maxThrust = 2500.0; c->spFuelConsump = 16.0; /* Isp = 220, SFC = 3600.0 / Isp */ /* * Three seconds arm delay: */ c->armDelay = 3.0; f = init_fopen("missiles/aim9.obv", "r"); /* FIXME: missing custom image */ c->object = VReadObject(f); fclose(f); return &aim120Desc; } acm-6.0_20200416/src/acm/panel.h0000644000000000000000000000257313145002337014377 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 2008 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /** * This module takes care to update and draw the bottom strip of the instruments * panel, which includes: * * - lights panel * - radar altimeter * - HSI tuner, or ADF tuner or TEWS (depending on the settings) * - HSI, or ADF or radar (depending on the settings) * - flaps status, max bank, gear status * - engine setting * * @file */ #ifndef _panel_h #define _panel_h #include "pm.h" #ifdef panel_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Updates and draws the bottom strip of the instruments panel. * @param c * @param u */ EXTERN void panel_updateAndDraw(craft *c, viewer *u); #undef EXTERN #endif acm-6.0_20200416/src/acm/patchlevel.h0000644000000000000000000000030113646051170015417 0ustar rootroot#ifndef patchlevel_H #define patchlevel_H #ifdef patchlevel_IMPORT #define EXTERN #else #define EXTERN extern #endif #define patchlevel_REVISION_STRING "6.0_20200416" #undef EXTERN #endif acm-6.0_20200416/src/acm/browse.h0000644000000000000000000000335513646045023014605 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /** * DIS entities browser and entity take over. * * FIXME: this modules does not work anymore, mostly trying to implement an * experimental DIS feature, unfinished yet (U.S.). * * @author Riley Rainey * @license GNU GPL * @version $Date: 2020/01/08 06:00:49 $ * @file */ #ifndef _browse_h #define _browse_h #include "../dis/dis/dis.h" #include "pm.h" #ifdef browse_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * This callback is invoked by the DIS code when we receive a grant * control PDU that we've been waiting for. */ EXTERN int browse_controlRequestCallback( dis_pdu *pdu, void *pu ); //EXTERN int browse_keyEvent(craft * c, viewer * u, XEvent * ev, int player); //EXTERN void browse_page(craft * c, viewer * u); /** * Switch attention to the designated aircraft. */ EXTERN int browse_stealthCraft(craft *c, viewer *u, int item, int take_control); EXTERN void browse_selectCockpitItem( craft *c, viewer *u, int x, int y, unsigned long time); #undef EXTERN #endif acm-6.0_20200416/src/acm/vpath.c0000644000000000000000000001356013175040535014420 0ustar rootroot/* * ACM - 3-D draw utilities * Copyright (C) 2008 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include "../V/VRoman.h" #include "../util/memory.h" #define vpath_IMPORT #include "vpath.h" typedef struct { int s; /* no. of points allocated in p[] */ int n; /* no. of points inserted in p[], n<=s */ VPoint *p; /* array of one or more points */ } VPathTrack; typedef struct vpath_Type { int s; /* no. of tracks pointers allocated in p[] */ int n; /* no. of tracks pointers inserted in p[], n<=s */ VPathTrack **p; /* array of pointers to tracks */ } vpath_Type; static void vpath_destruct(void *vp) { vpath_Type *p = vp; VPathTrack *t; int i; if( p == NULL ) return; for( i = 0; i < p->n; i++ ){ t = p->p[i]; memory_dispose(t->p); memory_dispose(t); } memory_dispose(p->p); } vpath_Type * vpath_new() { vpath_Type *p; p = memory_allocate(sizeof( vpath_Type ), vpath_destruct); p->s = 0; p->n = 0; p->p = NULL; return p; } void vpath_moveTo(vpath_Type *p, VPoint *to) { VPathTrack *t; if( p->n > 0 && p->p[ p->n - 1 ]->n == 1 ){ /* Previous track contains only one, unuseful point. */ p->p[ p->n - 1 ]->p[0] = *to; } if( p->n >= p->s ){ p->s = 2*p->s + 10; p->p = memory_realloc( p->p, p->s * sizeof(VPathTrack) ); } t = memory_allocate(sizeof(VPathTrack), NULL); t->s = 5; t->n = 1; t->p = memory_allocate(t->s * sizeof(VPoint), NULL); t->p[0] = *to; p->p[ p->n++ ] = t; } void vpath_lineTo(vpath_Type *p, VPoint *to) { VPathTrack *t; if( p->n == 0 ){ /* No previous starting point available, add default: */ vpath_moveTo(p, &(VPoint){0.0, 0.0, 0.0}); } t = p->p[ p->n - 1 ]; if( t->n >= t->s ){ t->s = 2*t->s + 5; t->p = memory_realloc( t->p, t->s * sizeof(VPoint) ); } t->p[ t->n++ ] = *to; } void vpath_arc(vpath_Type *p, VPoint *center, VPoint *final, int n) /* FIXME: not used */ { VPoint s, a, b, dif, q, r; VPathTrack *track; int i; double t, a_len, b_len, l; /* The starting point `s' is the current pen position */ if( p->n == 0 ){ /* No previous starting point available, add default: */ VSetPoint(&s, 0.0, 0.0, 0.0); vpath_moveTo(p, &s); } else { track = p->p[ p->n - 1 ]; s = track->p[ track->n - 1 ]; } VSub(&s, center, &a); /* a = s - center */ VSub(final, center, &b); /* b = final - center */ VSub(final, &s, &dif); /* dif = b - a */ a_len = VMagnitude(&a); b_len = VMagnitude(&b); /* The points r(t) of the arc can be described in parametric form using t=[0,1.0] as follows: q(t) = a + t*(b-a) l(t) = |q| / ((1-t)*|a| + t*|b|) r(t) = center + q(t)/l(t) Note that r(0) is the current pen position, so we may start from t=1/n. */ for( i=1; i<=n; i++ ){ t = i / (double) n; VAdd(&a, &(VPoint){t*dif.x, t*dif.y, t*dif.z}, &q); l = ((1.0-t)*a_len + t*b_len) / VMagnitude(&q); VSetPoint(&r, center->x + l*q.x, center->y + l*q.y, center->z + l*q.z); vpath_lineTo(p, &r); } } void vpath_draw_string(vpath_Type *path, char *str, int len, VMatrix *m) { int c, i, k, j; VGlyph_Vertex *g; double x, x1, y1; VPoint p; x = 0.0; for ( ; len > 0; --len, ++str) { c = *str; if( c >= 128 ){ continue; } k = VRomanGlyph[c].path_start; for (i = 0; i < VRomanGlyph[c].path_count; ++ i, ++ k) { g = &VRomanVertex[VRomanPath[k].vertex_start]; for (j=0; j < VRomanPath[k].vertex_count; ++j, ++g) { x1 = x + g->x / 25600.0; y1 = -g->y / 25600.0; VSetPoint(&p, x1, y1, 0.0); VTransform (&p, m, &p); if( j == 0 ) vpath_moveTo(path, &p); else vpath_lineTo(path, &p); } } x += VRomanGlyph[c].glyph_width / 25600.0; } } void vpath_stroke(vpath_Type *p, VMatrix *m, Alib_Window *w, Alib_Pixel color) /* FIXME: segments where at least a point is behind the screen aren't drawn, rather than being clipped as stated in the .h. */ { int i, j; VPathTrack *t; VPoint a, b; for( i = 0; i < p->n; i++ ){ t = p->p[i]; VTransform(&t->p[0], m, &a); for( j = 1; j < t->n; j++ ){ VTransform(&t->p[j], m, &b); if( a.z < 0.0 && b.z < 0.0 ) Alib_drawLine(w, a.x + 0.5, a.y + 0.5, b.x + 0.5, b.y + 0.5, color); a = b; } } } void vpath_perspective_stroke(vpath_Type *p, VMatrix *m, Viewport *v, Alib_Pixel color) /* FIXME: segments where at least a point is behind the screen aren't drawn, rather than being clipped as stated in the .h. */ { int i, j; VPathTrack *t; VPoint a, b; double ka, kb; int a_in, b_in; double ax, ay, bx, by; /* Draw the segment only if within about +/85 DEG angle of view just to avoid overflow converting double into int when the arguments of AlibDrawLine() are passed. */ ax = ay = bx = by = 0.0; for( i = 0; i < p->n; i++ ){ t = p->p[i]; VTransform(&t->p[0], m, &a); a_in = a.z > 0.0 && a.z > 0.1 * (fabs(a.x) + fabs(a.y)); if( a_in ){ ka = v->dist / a.z; ax = v->xres * ka * a.x + v->focus.x; ay = v->yres * ka * a.y + v->focus.y; } for( j = 1; j < t->n; j++ ){ VTransform(&t->p[j], m, &b); b_in = b.z > 0.0 && b.z > 0.1 * (fabs(b.x) + fabs(b.y)); if( b_in ){ kb = v->dist / b.z; bx = v->xres * kb * b.x + v->focus.x; by = v->yres * kb * b.y + v->focus.y; } if( a_in && b_in ){ Alib_drawLine(v->w, ax, ay, bx, by, color); } ax = bx; ay = by; a_in = b_in; } } } /* The vpath.c module ends here. */ acm-6.0_20200416/src/acm/alarm.c0000644000000000000000000000677413064355205014403 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1997 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include "../util/memory.h" #include "pm.h" #define alarm_IMPORT #include "alarm.h" typedef struct _alarm_descriptor_t { struct _alarm_descriptor_t *next; double t; alarm_id_t id; void (*proc) (void *, void *); char *arg1; char *arg2; } alarm_descriptor_t; /* Pending alarms ordered by increasing time t. */ static alarm_descriptor_t *alarm_list = NULL; /* Recycled list of available blocks. */ static alarm_descriptor_t *alarm_free_list = NULL; static alarm_id_t next_alarm_id = 0; /** * Module cleanup. */ static void alarm_cleanup() { alarm_descriptor_t * p; while( alarm_list != NULL ){ p = alarm_list; alarm_list = p->next; memory_dispose(p); } while( alarm_free_list != NULL ){ p = alarm_free_list; alarm_free_list = p->next; memory_dispose(p); } } static alarm_descriptor_t * alarm_alloc() { alarm_descriptor_t *p; if( alarm_free_list == NULL ){ memory_registerCleanup(alarm_cleanup); return memory_allocate(sizeof(alarm_descriptor_t), NULL); } else { p = alarm_free_list; alarm_free_list = p->next; return p; } } static void alarm_free(alarm_descriptor_t *p) { if( alarm_free_list == NULL ){ alarm_free_list = p; p->next = NULL; } else { p->next = alarm_free_list; alarm_free_list = p; } } void alarm_update(void) { alarm_descriptor_t *p; while( alarm_list != NULL && alarm_list->t <= curTime ){ /* We have to remove the entry first because some call-back function also adds another entry to the list itself, so changing the value of alarm_list itself: */ p = alarm_list; alarm_list = p->next; /* Invoke the call-back function: */ (*p->proc) (p->arg1, p->arg2); /* We can now safely release the used entry: */ alarm_free(p); } } alarm_id_t alarm_add(double delta, void (*proc) (void *, void *), void *arg1, void *arg2) { alarm_descriptor_t *n, *p, *q; n = alarm_alloc(); n->id = next_alarm_id++; n->t = curTime + delta; n->proc = proc; n->arg1 = arg1; n->arg2 = arg2; /* Add entry to the list preserving the increasing order of time: */ if( alarm_list == NULL ){ n->next = NULL; alarm_list = n; } else { q = alarm_list; p = NULL; while( q != NULL && q->t <= n->t ){ p = q; q = q->next; } if( p == NULL ){ n->next = alarm_list; alarm_list = n; } else { p->next = n; n->next = q; } } return n->id; } void alarm_cancel(alarm_id_t id) { alarm_descriptor_t *p, *q; if( alarm_list == NULL ){ return; } else if( alarm_list->id == id ){ p = alarm_list; alarm_list = alarm_list->next; alarm_free(p); } else { p = alarm_list; q = p->next; while( q != NULL && q->id != id ){ p = q; q = q->next; } if( q == NULL ) return; p->next = q->next; alarm_free(q); } } acm-6.0_20200416/src/acm/pm.h0000644000000000000000000005215113646045024013717 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /** * Plane management data structures and routines. Basically, the core of all * tools needed for the ACM simulation are defined here. * * @author Riley Rainey * @license GNU GPL * @version $Date: 2020/01/08 06:10:19 $ * @file */ #ifndef _pm_h #define _pm_h #include "../V/Vlibmath.h" #include "../V/VObjects.h" #include "../util/gui.h" #include "inventory.h" #include "manifest.h" #include "scale.h" #include "air.h" #include "zones.h" #ifdef pm_IMPORT #define EXTERN #else #define EXTERN extern #endif #ifdef WINNT typedef BOOL _BOOL; #else typedef int _BOOL; #endif #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif /* * Each rendering window has a _viewer structure which may be in one * of several states. */ #define ViewerStateNormal 0 /* just a plane that we control */ #define ViewerStateBrowsing 1 /* not yet associated with an entity */ #define ViewerStatePiggyback 2 /* a stealth glued to an entity */ #define ViewerStateControlPending 3 /* requested control of an entity */ //#define ViewerStateControlling 4 /* have control of another entity (FIXME: not used) */ /** * Cockpit view from a specific aircraft is rendered through this object. */ typedef struct viewer { /** Linked list of all active rendering viewers. */ struct viewer *vl_next; /** Next viewer attached to this craft. Since usually there is just only one viewer per craft, this field is usually NULL. */ struct viewer *next; /** One of the ViewerState* constants. */ int viewer_state; /** Associated aircraft. */ struct craft *c; /** Associated craft when in stealth mode. */ struct craft *watchedCraft; /** * The window. Users' input and window events are read from here, but * drawing is always performed into the z-buffer first. */ gui_Type *gui; /** If the window has focus, then may receive keyboard and mouse input. */ _BOOL hasFocus; /** If users' input is currently accepted or "don't touch anything" mode. */ _BOOL hasComm; /** 2-D off-screen drawing device with z-buffer. */ Alib_Window *w; /** 3-D off-screen drawing device bound to the z-buffer. */ Viewport *v; /** Cockpit view direction as a vector in AXYZ. */ VPoint viewDirection; /** "Up" direction in AXYZ. */ VPoint viewUp; /** Organize HUD drawing around (xCenter,hud_yCenter). */ int hud_yCenter; /** Zoom factor (percent). */ int zoom; /** * If HUD mode, otherwise it is "classic panel mode". This is a * read-only flag, as it set by (indows_resizePlayerWindow(). */ _BOOL hud_mode; /** Classic mode: timer and APS lights stripe area. */ Alib_Rect stripe; /** Classic mode: turn and slip indicator area. */ Alib_Rect turn; /** Classic mode: air speed indicator area. */ Alib_Rect anemometer; /** Classic mode: attitude indicator area. */ Alib_Rect attitude; /** Classic mode: altimeter indicator area. */ Alib_Rect altimeter; /** Classic mode: vertical speed indicator area. */ Alib_Rect vsi; /** Alarm and status lights area. */ Alib_Rect lights; /** Radard altimeter area. */ Alib_Rect radar_altimeter; /** Tuner area. */ Alib_Rect tuner; /** Area shared by HSI, ADF and radar. */ Alib_Rect indicator; /** Gear, flaps and max bank area. */ Alib_Rect gear; /** Engine RPM and throttle area. */ Alib_Rect engine; /** HUD, altitude stripe. */ scale_Type altScale; /** HUD, air speed stripe. */ scale_Type velScale; /** HUD, heading stripe. */ scale_Type hdgScale; /** HUD, overall x scale factor. */ double xscaleFactor; /** HUD, overall y scale factor. */ double yscaleFactor; /** Previous radar frame. */ Alib_Segment radarImage[1024]; int radarImageCount; /** First drawn DIS entity in RM_DIS_BROWSE. */ int browseBase; int browseSelectedItem; unsigned long browseClickTime; /* Private data structures handled by the corresponding modules: */ void *hud; /* see hud module */ void *magnetic_compass; /* see magnetic_compass module */ void *hsi; /* see hsi module */ void *adf; /* see adf module */ void *sounds; /* see sounds module */ void *inst; /* see instruments module */ void *terminal; /* see terminal module */ void *prompt; /* see prompt module */ } viewer; /** * Radar tracking information. */ typedef struct { int beamID; /* index number of beam */ VPoint rel; /* location relative to radar set */ double d; /* distance to target (ft) */ int targetID; /* craft id of target */ int locked; /* 1=we have a "lock" */ int altDisplay_kft; /* altitude readout (ft x 1000) */ int headingDisplay_deg; /* ground track of target */ int x, y; } radarInfo; /** Alias for the (quite obscure for me) "trihedral" craft struct field. */ #define AXYZtoNED trihedral /** * State of the aircraft. Also missiles, drop bombs, cannon bursts, runways, * land features and explosion effects all share this same struct, although some * fields may have a slightly different meaning or aren't used at all. * * The involved reference frames are all right-handled: * * - XYZ: world reference frame. * * - AXYZ: aircraft reference frame, center in CM, x longitudinal * pointing forward, y pointing rightward and z pointing * downward. * * - NED: center=aircraft CM, x toward geographic north, y east, * z downward. * * The involved matrices are: * * - c->trihedral or c->AXYZtoNED is a pure rotational matrix from AXYZ to NED. * * - c->XYZtoNED is a roto-translational matrix from XYZ to NED. * * The Euler angles, giving the angular rotations to pass from NED to AXYZ, * are so normalized (sorted in order of application to obtain the actual * aircraft orientation): * * - c->curHeading rotation around z, [0,2*PI[ * - c->curPitch rotation around y, [-PI/2,PI/2] * - c->curRoll rotation around x, [-PI,PI] * * * In some cases, this data structure belongs to an array; in other cases * (surface objects) a double-linked list of dynamically allocated items is * used instead. That's why there are both index-related fields (pIndex) and * list-related fields as well (next, prev). * * An update() and kill() fields points to the specific dynamic update and delete * routines mostly like this struct was a class in a object-oriented language, * but this program does not go any further on this paradigm. */ typedef struct craft { /** Index of this structure in the container vector. */ int pIndex; /** Previous craft in a doubly-linked list. */ struct craft *prev; /** Next craft in in a doubly-linked list. */ struct craft *next; /** Status flags, see FL_* constants. */ unsigned long flags; /** Craft type, see CT_* constants. */ int type; /** Name of the player. */ char name[32]; /** DIS force this plane belongs to. */ DISForce force; /** Creation time (simulation time, s). */ double createTime; /** * For real local players, the zone the craft is currently flying over. * For runways and features implemented through this same data struct, * it is the zone from which that item was loaded from. * For munitions and remote crafts it is set to NULL. */ zone_Type *zone; /** * List of viewers windows looking through the windshield of this craft. */ viewer *vl; /** * Transforms from aircraft XYZ to NED. The self-explaining macro "AXYZtoNED" * could also be used instead. */ VMatrix trihedral; /** Velocity vector in NED (ft/s). */ VPoint Cg; /** Airspeed (ft/s). */ double VT; /** Indicated air speed (ft/s). */ double IAS; /** Position in geocentric frame XYZ (m). */ VPoint Sg; /** Position as geodetic coordinates. */ earth_LatLonAlt w; /** Properties of the surrounding air. */ air_Properties air; /** Current Mach number. */ double mach; /* current Mach number */ /** * Altitude over the terrain (m). * BEWARE: this field is for internal use only of the terrain module; * client code should invoke terrain_altitude() instead. */ double terrain_altitude; /** * Scheduled update of the local terrain altitude. For internal use only of * the terrain module. */ double terrain_altitude_timeout; /** Geocentric to NED transformation. */ VMatrix XYZtoNED; /** Euler angle of heading vs. NED (RAD). */ double curHeading; /** Euler angle of pitch vs. NED (RAD). */ double curPitch; /** Euler angle of bank vs. NED (RAD). */ double curRoll; /** Roll rate (RAD/s). */ double p; /** Pitch rate (RAD/s). */ double q; /** Yaw rate (RAD/s). */ double r; /** Angle of attack (RAD). */ double alpha; /** Angle of sideslip (RAD). */ double beta; /** G-force in aircraft frame (units of "g"). */ VPoint G; /** Acceleration in aircraft frame (ft/s^2). */ VPoint linAcc; /** Last interval's Sg value (m). Unsure if still needed. */ VPoint prevSg; /** Pilot's pitch command [-1.0,1.0]. */ double pitchComm; /** Pilot's roll command [-1.0,1.0]. */ double rollComm; /** Pilot's steer command [-1.0,1.0]. */ double steerComm; /** Pilot's rudder command [-1.0,1.0]. */ double rudderComm; /** Pilot's throttle command [0,32768]. */ int throttleComm; /** Elevator position [-1.0,1.0]. */ double Se; /** Ailerons position [-1.0,1.0]. */ double Sa; /** Rudder position [-1.0,1.0]. */ double Sr; /** Pitch trim setting. */ double SeTrim; /** Roll trim setting. */ double SaTrim; /** Current thrust value (lbf). */ double curThrust; /** Pilot's thrust reverser command. */ _BOOL thrust_reverse_on; /** * Thrust reverser factor [-0.5 .. +1.0]. The actual thrust that pushes the * aircraft is a vector directed as the x axis and with module * curThrust*thrust_reverse_pos, possibly yielding a negative value. */ double thrust_reverse_pos; /** Actual flaps position (RAD). */ double curFlap; /** Flaps command position (RAD). */ double flapSetting; /** Current speed brake position (RAD). */ double curSpeedBrake; /** Current target speed brake setting (RAD). */ double speedBrakeSetting; /** Landing gear module state - see gear.h. */ void * gear; /** Thrust setting [0,32768]. */ int throttle; /** Engine RPM [0.0,1.0]. */ double rpm; /** Current fuel on board (lb). */ double fuel; /** Payload (lb). */ double payload; /** Bit flags of damaged subsystems. */ long damageBits; /** Damage pts that can be absorbed. */ long structurePts; /** Fuel leakage rate (lb/s). */ double leakRate; /** Damage induced roll. */ double damageCL; /** Damage induced pitch. */ double damageCM; /** Shared panel current mode: radar, HSI or ADF. */ int radarMode; /** General craft information. */ craftType *cinfo; /** Time of next Radar frame. */ double nextRadarTime; /** Our primary "threat". */ short curRadarTarget; /** Distance to primary target [ft]. */ double targetDistance; /** Closure rate on primary target [ft/s]. */ double targetClosure; /** Used by radar and missile. */ VPoint relPos[manifest_MAXPLAYERS]; /** Radar strength seen by us from other craft. */ double rval[manifest_MAXPLAYERS]; /** Radar target information: relative positions of possible targets. */ radarInfo rinfo[32]; /** Number of entries used in rinfo. */ int rtop; /** Strings in upper left corner of HUD reserved for weapons' status. */ char *leftHUD[6]; /** Strings in upper right corner of HUD reserved for radar target info. */ char *rightHUD[6]; /** Index of currently selected weapon in wtbl[]. */ int curWeapon; /** What's at each weapon station. */ weaponStation station[manifest_STATIONS]; /** * Handle assigned by dis_if module to this craft to retrieve associated * DIS state. */ int disId; /* * Magnetic field data at the location of the aircraft. Since the * calculation is a bit expensive, we store here the last current value * calculated and the time we expect it to be updated; the indicated value * smoothly follows the current one. */ /** * If HUD and HSI have to display magnetic header rather than geographic * heading. Always true in "classic instruments" mode. Always false for * drones (no need to calculate Earth's magnetic field for them). */ int showMag; /** * Latest calculated magnetic field components in NED (nT). * This field periodically updated only if showMag is true. */ VPoint actualMagneticField; /** * Latest calculated magnetic variation, positive west (RAD). * This field periodically updated only if showMag is true. */ double actualLocalVAR; /** * Scheduled update of the local magnetic field data (s). Normally this is * done every 10 s, but at higher speed an update is forced early. */ double updActualMagneticField; /** * Indicated magnetic field components in NED (nT). Smoothly follows the * latest calculated value. */ VPoint indicatedMagneticField; /** * Indicated local magnetic variation, positive west (RAD). Smoothly follows * the latest calculated value. */ double indicatedLocalVAR; /** * When to update the indicated magnetic field so that it smoothly follows * the actual calculated value (s). */ double updIndicatedMagneticField; /** * Drone module private data, set when this aircraft is created as a drone * or a player enables the drone mode -- see drone module. */ void *drone; /** Autopilot System private data -- see aps module. */ void *aps; /** Effects private data -- see effects module. */ void *effects; /* Munition handling (see dis_if.c, ccip.c, missile.c): */ double offset; long tracerMod; int tracerVal; double interval; short rounds; int owner; double armTimer; /** * Internal state update procedure bound to this specific craft. * Local entities must also send their new state to the DIS module, while * for remote entities the state can be retrieved from the DIS module. * May return the kill reason, or NULL if still alive. */ char *(*update)(struct craft *c); /** * Kill procedure to call before removal bound to this specific craft. * The kill reason can be set by the update procedure itself, or by client. */ void (*kill)(struct craft *c, char *reason); } craft; /* * Craft type definitions */ #define CT_FREE 0 /* an unused craft entry */ #define CT_PLANE 1 /* a player */ #define CT_MISSILE 2 /* an air to air missile */ #define CT_CANNON 3 /* a stream of cannon fire */ #define CT_SURFACE 4 /* surface object (e.g. a runway) */ //#define CT_CHASER 5 /* a non-player "watcher" chasing a plane (FIXME: not used) */ #define CT_DRONE 6 /* a target drone */ #define CT_EXPLOSION 7 /* an explosion */ #define CT_DIS_PLANE 8 /* external player (on different server) */ #define CT_DIS_MUNITION 9 /* external tracked munition */ #define CT_DIS_CANNON 10 /* external untracked munition (cannon) */ #define CT_RESERVED 11 /* a reserved, uninitialized entry */ #define CT_DIS_STEALTH 12 /* a place-holder for stealths */ #define CT_BOMB 13 /* gravity bomb */ /* Flag word definitions */ #define FL_RECORD (1<<0) /* activate recording function */ #define FL_AFTERBURNER (1<<1) /* afterburner state */ #define FL_HAS_GYRO (1<<2) /* missile is gyroscope equiped */ #define FL_FIXED_OBJECT (1<<3) /* fixed (surface) object */ #define FL_CHASE_VIEW (1<<4) /* chase plane view */ #define FL_BLACK_BOX (1<<5) /* object is from a black box recording */ #define FL_BALLISTIC (1<<6) /* munition has no target */ #define FL_RADAR_MODE_CHANGE (1<<7) /* set when user changes radar mode */ #define FL_END_GAME_DRONE (1<<8) /* drone in CALSPAN end-game mode */ /* Radar mode definitions. Since radar+TEWS, ADF and HSI+HSI panel all share * the same slots in the panel of the radar, these constants are global rather * than being defined inside their respective modules radar.h, adf.h and hsi.h. */ #define RM_OFF 0 /* radar is off */ #define RM_STANDBY 1 /* standby */ #define RM_NORMAL 2 /* track while scan */ #define RM_ACM 4 /* 20x30 acm */ #define RM_STT 8 /* single target track */ #define RM_HSI 16 /* HSI mode */ #define RM_ADF 32 /* ADF mode */ #define RM_DIS_BROWSE 64 /* browse entities */ /** Linked list of all rendering windows (normally only one). */ EXTERN viewer *vl_head; /** Number of players recording info. */ EXTERN int recordCount; /** Number of active entries in ptbl. */ EXTERN int ptblCount; /** Number of chasers. */ EXTERN int ctblCount; /** Departure timestamp (seconds since 1970-01-01T00:00:00). */ EXTERN int departure_timestamp; /** * Simulation time (s). Or, time elapsed since simulation started. * Added to the departure timestamp gives the current (simulated) timestamp. */ EXTERN double curTime; /** List of surface objects: runways, features -- see zones module. */ EXTERN craft *stbl; /** Players table, including drones, locale and remote. */ EXTERN craft ptbl[manifest_MAXPLAYERS]; /** Missiles and cannon bursts table, locale and remote. */ EXTERN craft mtbl[manifest_MAXPROJECTILES]; /** * Location of the force base for resupply. The index is one of the DISForce * constants. Currently only the 1 (DISForceFriendly) and 2 (DISForceOpposing) * are set with the team locations read from the starting zone, if available. * The default force base is located at 0N 0E! */ EXTERN earth_LatLonAlt forceBaseLocation[4]; /** * Dynamics update period (s). That is, aerodynamic forces, gear dynamics and * in general the craft state update are performed with frequency 1/deltaT Hz * which is (or should be) much higher than the frame rate of the renderer to * prevent numerical instability issues. */ EXTERN double deltaT; /** 0.5 * deltaT * deltaT */ EXTERN double halfDeltaTSquared; /* Colors look-up table index for some colors of general usage. */ EXTERN int HUDColor; EXTERN int whiteColor; EXTERN int blackColor; EXTERN int yellowColor; EXTERN int redColor; EXTERN int magentaColor; EXTERN int radarColor; EXTERN int panelBackgroundColor; /** Cloud base altitude (ft). */ EXTERN double clouds_base; /** Cloud top altitude (ft). No clouds if clouds_top is less or equal to clouds_base. */ EXTERN double clouds_top; /** Set by arcade -a switch: never run out of ammunitions. */ EXTERN int arcadeMode; EXTERN double end_game_threshold_meters; EXTERN int end_game_mode; EXTERN int transferEntityIdBits; EXTERN dis_entity_id subjectEntityID; EXTERN int subjectEntitySpecified; /* =1 if subject entity was specified on the command line */ /** Pilot eye dist. from screen (cm). */ EXTERN double eye_to_screen_cm; /** Downward view angle over the nose (RAD). */ EXTERN double downward_view_angle_rad; /** State of the zones module. */ EXTERN zones_Type *zones; EXTERN void pm_calcGForces(craft * c, VPoint * f, double w); /** * Performs flight dynamics calculations. Return NULL on success, * otherwise return a string reporting the reason why the aircraft * was destroyed. */ EXTERN char * pm_flightCalculations(craft * c); /** * Calculate Euler angles c->curRoll, c->curPitch and c->curHeading * from the matrix c->trihedral. It is a shorter version of * * VMatrixToEuler(&c->AXYZtoNED, &c->curRoll, &c->curPitch, &c->curHeading); */ EXTERN void pm_euler(craft * c); /* These functions return the program idea of normalized Euler's angles, as explained above describing the "craft" data type. */ EXTERN double pm_normalize_roll(double roll); EXTERN double pm_normalize_pitch(double pitch); EXTERN double pm_normalize_yaw(double yaw); EXTERN double pm_heading(VPoint * x); EXTERN void pm_hud_strings_alloc(craft *c); EXTERN void pm_hud_strings_free(craft *c); EXTERN void pm_thrust_reverse_toggle(craft *c); EXTERN void pm_after_burner_toggle(craft *c); EXTERN void pm_after_burner_on(craft *c); EXTERN void pm_after_burner_off(craft *c); /** * Return current magnetic heading of the aircraft. Also updates the fields * related to the magnetic field. */ EXTERN double pm_mag_heading(craft * c); #undef EXTERN #endif acm-6.0_20200416/src/acm/commands.c0000644000000000000000000000726413175035577015115 0ustar rootroot/* * acm - Commands interpreter * Copyright (C) 2007 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include "players.h" #include "pm.h" #include "terminal.h" #define commands_IMPORT #include "commands.h" #define MAX_ARGC 5 static void split_cmd(char *cmd, int *argc, char *argv[]) { int n; char *p; n = 0; p = strtok(cmd, " \t"); while( p != NULL && n < MAX_ARGC ){ argv[n] = p; n++; p = strtok(NULL, " \t"); } *argc = n; } static void parse_set(viewer *u, int argc, char *argv[]) { if( argc != 3 ){ terminal_write(u, "ERROR: expected `set VAR VALUE'\r\n"); return; } if( strcmp(argv[1], "xView") == 0 ) u->v->Middl.x = atoi(argv[2]); else if( strcmp(argv[1], "yView") == 0 ){ u->v->Middl.y = atoi(argv[2]); /********* } else if( strcmp(argv[1], "dist") == 0 ){ u->v->dist = atof(argv[2]); resizePlayerWindow(u->c, u, u->width, u->win_height, FALSE, u->hud_mode); } else if( strcmp(argv[1], "xscaleFactor") == 0 ){ u->xscaleFactor = atof(argv[2]); resizePlayerWindow(u->c, u, u->width, u->win_height, FALSE, u->hud_mode); } else if( strcmp(argv[1], "Scale") == 0 ){ u->v->Scale.x = atof(argv[2]); u->v->Scale.y = atof(argv[2]); u->v->Scale.z = atof(argv[2]); resizePlayerWindow(u->c, u, u->width, u->win_height, FALSE, u->hud_mode); ************/ } else terminal_write(u, "ERROR: unknow variable\r\n"); } static void print_double(viewer *u, char *name, double value, char *unit) { char s[100]; terminal_write(u, name); terminal_write(u, " = "); sprintf(s, "%f", value); terminal_write(u, s); terminal_write(u, " "); terminal_write(u, unit); terminal_write(u, "\r\n"); } void commands_execute(viewer *u, char *cmd) { int argc; char *argv[MAX_ARGC]; split_cmd(cmd, &argc, argv); if( argc == 0 ) return; if( strcmp(argv[0], "help") == 0 ){ terminal_write(u, "Currently availablecommands\r\n" " help\r\n" " create\r\n" ); } else if( strcmp(argv[0], "v") == 0 ){ print_double(u, "Vs0", u->c->cinfo->Vs0, "KT"); print_double(u, "Vs1", u->c->cinfo->Vs1, "KT"); print_double(u, "Vfe", u->c->cinfo->Vfe, "KT"); print_double(u, "Vno", u->c->cinfo->Vno, "KT"); print_double(u, "Vne", u->c->cinfo->Vne, "KT"); print_double(u, "Alpha Stall", units_RADtoDEG(u->c->cinfo->alpha_stall), "DEG"); print_double(u, "MTOW", u->c->cinfo->MTOW, "lb"); print_double(u, "Total Mass", u->c->cinfo->emptyWeight + u->c->fuel + u->c->payload, "lb"); } else if( strcmp(argv[0], "create") == 0 ){ /**** if( players_new(STDERR_FILENO, ":0.0", "Mate", "|-geometry|937x737+0+0|-scale|1.5|-no-sound|1|-plane|C-172|-force|Other|-fuel|100|-payload|150" ) != 0 ){ terminal_write(u, "FAILED\r\n"); } *****/ /***** if( planes_newPlane("C-172") != 0 ){ terminal_write(u, "FAILED\r\n"); } ******/ /***** newDrone(u->c, "C-172"); ptbl[1].type = CT_PLANE; *****/ } else if( strcmp(argv[0], "set") == 0 ){ parse_set(u, argc, argv); } else { terminal_write(u, "ERROR: unknown command. Type `help' for help.\r\n"); } } /* End of the commands module */ acm-6.0_20200416/src/acm/m61a1.c0000644000000000000000000005007613260344464014131 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1997 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include #include "sounds.h" #include "damage.h" #include "dis_if.h" #include "effects.h" #include "init.h" #include "inventory.h" #include "pm.h" #include "weapon.h" #include "../util/prng.h" #include "../util/memory.h" #include "../util/units.h" #define m61a1_IMPORT #include "m61a1.h" #define BORE_CROSS_SIZE 7 #define MUZZLE_VELOCITY (3.2808 * 1036.0) #define TRACER_MOD 10 #define OFFSET_ANGLE (units_DEGtoRAD(3.0)) /* the gun points up at this angle */ #define RATE_OF_FIRE (3000.0 / 60.0) /* rounds per second */ #define FUZZ (units_DEGtoRAD(1.0)) /* distribution due to vibration */ static int select_m61a1(craft *); static int display_m61a1(craft *, craftType *, viewer *, int, int); static int update_m61a1(craft *); static int fire_m61a1(craft *); static int release_m61a1(craft *); static void lcos(craft * c, viewer * u); static int isCannonHit(double min, craft * c); static weapon_Type m61a1Desc = { select_m61a1, /* select */ update_m61a1, /* update */ display_m61a1, /* display procedure */ fire_m61a1, /* fire */ release_m61a1, /* fire button release */ }; /* * We'll take a running average of our pitch and yaw rates to keep the * aiming reticle from jumping all over the screen. */ #define HIST 8 typedef struct { double pitch_hist[HIST]; double yaw_hist[HIST]; int cur; /* current entry in the histories */ int count; /* number of valid entries */ double pitch_total; double yaw_total; } hist_t; static hist_t history[manifest_MAXPLAYERS]; static void m61a1_lookForCannonImpacts(craft * burst); /* * M61A1 selection function * * A selection function normally determines whether there are any weapons * of this type on-board. If so, and the weapon system is functional * (in other words, undamaged) then return 1; otherwise return 0. */ static int select_m61a1(craft * c) { hist_t *p; p = &history[c->pIndex]; p->count = p->cur = 0; p->pitch_total = p->yaw_total = 0.0; /* * FIXME. The cannon must be located at station zero, for now. We should * change that. */ if (c->station[0].id == weapon_M61A1 && c->station[0].info > 0) { c->station[0].info4 = 0.0; return 1; } else return 0; } /* * M61A1 display function * * Update the HUD display strings associated with this weapon system. */ /*ARGSUSED */ static int display_m61a1(craft * c, craftType * w, viewer * u, int fpm_x, int fpm_y) { char s[16]; int tx, ty, m; Alib_Segment seg[2]; hist_t *p; p = &history[c->pIndex]; if ((m = p->cur = p->cur + 1) >= HIST) m = p->cur = 0; if (p->count != HIST) (p->count)++; else { p->pitch_total -= p->pitch_hist[m]; p->yaw_total -= p->yaw_hist[m]; } p->pitch_hist[m] = c->q; p->yaw_hist[m] = c->r; p->pitch_total += c->q; p->yaw_total += c->r; strcpy(c->leftHUD[2], "LCOS"); sprintf(s, "%.3d %s", c->station[0].info, weapon_idToName(weapon_M61A1)); strcpy(c->leftHUD[3], s); if (c->station[0].info3) strcpy(c->leftHUD[4], "FIRING"); else strcpy(c->leftHUD[4], ""); /* * Draw the boresight cross */ m = (int) ((double) BORE_CROSS_SIZE * u->xscaleFactor); tx = u->v->focus.x; ty = u->v->focus.y - (int)(u->v->yres * u->zoom/100.0 * eye_to_screen_cm * 0.01 * OFFSET_ANGLE); seg[0].x1 = tx - m; seg[0].x2 = tx + m; seg[0].y1 = seg[0].y2 = ty; seg[1].x1 = seg[1].x2 = tx; seg[1].y1 = ty - m; seg[1].y2 = ty + m; VDrawSegments(u->v, seg, 2, HUDColor); /* * Plot the reticle. */ lcos(c, u); return 0; } static int fire_m61a1(craft * c) { c->station[0].info3 |= 1; if (c->station[0].info > 0) { sounds_playSound(c, sounds_CannonFiring, TRUE); } return 0; } static int release_m61a1(craft * c) { c->station[0].info3 &= ~1; c->station[0].info4 = 0.0; sounds_stopSound(c, sounds_CannonFiring); return 0; } static char * m61a1_update(craft * burst) { double dNorth, dEast, dmag; /* * Kill projectile streams after 10.0 seconds of flight or when * they strike the ground. */ if (curTime - burst->createTime > 10.0) return "lifetime expired"; /* FIXME: actually, this is the impact with the sea level... */ if (burst->w.z < 0.0) { return "impact with the ground"; } burst->prevSg = burst->Sg; dNorth = units_FEETtoMETERS(burst->Cg.x * deltaT); dEast = units_FEETtoMETERS(burst->Cg.y * deltaT); burst->w.z -= units_FEETtoMETERS(burst->Cg.z * deltaT + units_earth_g * halfDeltaTSquared); dmag = sqrt(dNorth * dNorth + dEast * dEast); earth_updateLatLon(&burst->w, dNorth / dmag, dEast / dmag, dmag); earth_LatLonAltToXYZ(&burst->w, &burst->Sg); burst->Cg.z += units_earth_g * deltaT; // FIXME: not sure why we should look for cannon impacts only for local shells. // Should we include CT_DIS_CANNON too in the calculation? if( burst->type == CT_CANNON ) m61a1_lookForCannonImpacts(burst); return NULL; } static void m61a1_kill(craft * burst, char *reason) { burst->type = CT_FREE; } static int update_m61a1(craft * c) { craft *burst; int i; VPoint tmp, tmp1, mvel; double fuzz, fuzzAngle, phiY, phiZ, tm, mv = MUZZLE_VELOCITY; if (c->station[0].info3 == 0) return 0; /* * Got any ammunition ? */ if (c->station[0].info <= 0) return -1; /* * It is possible (especially on today's faster machines) that no rounds * actually left the barrel during this time interval. */ if (c->station[0].info4 > deltaT) { c->station[0].info4 -= deltaT; } else { /* * Allocate a projectile record */ for ((i = 0, burst = &mtbl[0]); i < manifest_MAXPROJECTILES; (++i, ++burst)) if (burst->type == CT_FREE) { break; } if (i == manifest_MAXPROJECTILES) return -1; memory_zero(burst); burst->type = CT_CANNON; burst->pIndex = i; burst->disId = dis_if_ID_NONE; /* * Determine how far we're fuzzed off the ideal boresight. */ fuzz = 2.0 * prng_getDouble() - 1.0; /* -1.0 <= fuzz <= 1.0 */ fuzz = fuzz * FUZZ; fuzzAngle = 2.0 * M_PI * prng_getDouble(); /* * Determine the initial velocity of the projectile stream. */ phiZ = fuzz * sin(fuzzAngle); phiY = fuzz * cos(fuzzAngle); tm = mv * cos(OFFSET_ANGLE + phiZ); tmp.x = tm * cos(phiY); tmp.y = tm * sin(phiY); tmp.z = mv * sin(-OFFSET_ANGLE + phiZ); VTransform(&tmp, &(c->trihedral), &mvel); burst->owner = c->pIndex; burst->createTime = curTime; burst->curRoll = c->curRoll; burst->curPitch = c->curPitch; burst->curHeading = c->curHeading; burst->Cg = c->Cg; burst->Cg.x += mvel.x; burst->Cg.y += mvel.y; burst->Cg.z += mvel.z; /* Determine the initial position. */ VTransform_(&c->cinfo->wStation[0], &c->trihedral, &tmp1); VReverseTransform_(&tmp1, &c->XYZtoNED, &tmp); burst->Sg.x = c->Sg.x + units_FEETtoMETERS(tmp.x); burst->Sg.y = c->Sg.y + units_FEETtoMETERS(tmp.y); burst->Sg.z = c->Sg.z + units_FEETtoMETERS(tmp.z); earth_XYZToLatLonAlt(&burst->Sg, &burst->w); burst->prevSg = burst->Sg; earth_XYZToLatLonAlt(&burst->Sg, &burst->w); earth_generateWorldToLocalMatrix(&burst->w, &burst->XYZtoNED); /* Subtract the number of rounds fired. */ burst->offset = c->station[0].info4; burst->interval = deltaT; burst->rounds = 1 + (int) (RATE_OF_FIRE * (deltaT - burst->offset)); burst->rounds = (burst->rounds > c->station[0].info) ? c->station[0].info : burst->rounds; /* Compute time interval until the next round leaves the barrel (in a * subsequent time interval). */ c->station[0].info4 = 1.0 / RATE_OF_FIRE - fmod(deltaT - burst->offset, 1.0 / RATE_OF_FIRE); /* Include tracer information */ burst->tracerMod = TRACER_MOD; burst->tracerVal = c->station[0].info2 % burst->tracerMod; if ( ! arcadeMode ) { c->station[0].info -= burst->rounds; } c->station[0].info2 += burst->rounds; burst->cinfo = inventory_craftTypeSearchByZoneAndName(NULL, weapon_idToName(weapon_M61A1)); burst->update = m61a1_update; burst->kill = m61a1_kill; dis_if_fireCannon(c, &burst->Sg, &burst->Cg, burst->rounds, (int) RATE_OF_FIRE); } if (c->station[0].info <= 0) { sounds_stopSound(c, sounds_CannonFiring); } return 0; } void m61a1_DISFire(int owner, VPoint *pos, VPoint *vel, int rounds) { int i; craft *burst; for ((i = 0, burst = mtbl); i < manifest_MAXPROJECTILES; (++i, ++burst)) { if (burst->type == CT_FREE) { break; } } if (i == manifest_MAXPROJECTILES) { return; } memory_zero(burst); burst->pIndex = i; burst->disId = dis_if_ID_NONE; // not a tracked entity burst->type = CT_DIS_CANNON; strcpy(burst->name, "M61A1"); burst->owner = owner; burst->createTime = curTime; burst->curRoll = 0.0; burst->curPitch = 0.0; burst->curHeading = 0.0; burst->Sg = *pos; burst->Cg = *vel; earth_XYZToLatLonAlt(pos, &burst->w); // (needed, check renderer) burst->prevSg = burst->Sg; burst->rounds = rounds; burst->tracerMod = TRACER_MOD; burst->tracerVal = 0; burst->offset = 0.0; burst->interval = deltaT; burst->cinfo = inventory_craftTypeSearchByZoneAndName(NULL, weapon_idToName(weapon_M61A1)); burst->update = m61a1_update; burst->kill = m61a1_kill; } static int placeCannon(Viewport * vp, craft * burst, VMatrix * m, VPolySet *ps) { double t, startT; VPoint v, s; int i, k, n; VPoint *q, tmp; VPolygon **p, *poly; /* * Reduce the shell path to a set of parametric equations. */ v.x = burst->Sg.x - burst->prevSg.x; v.y = burst->Sg.y - burst->prevSg.y; v.z = burst->Sg.z - burst->prevSg.z; /* * Now add each tracer shell to the view. */ startT = (burst->offset + (burst->tracerVal / RATE_OF_FIRE)) / burst->interval; for (t = startT; t <= 1.0; t += TRACER_MOD / (RATE_OF_FIRE * burst->interval)) { s.x = -v.x * t; s.y = -v.y * t; s.z = -v.z * t; /* TODO: check should be based on local altitude */ /* underground? don't plot it */ if (burst->w.z + s.z < 0.0) { continue; } n = burst->cinfo->object->numPolys; p = burst->cinfo->object->polygon; for (i = 0; i < n; ++i) { poly = VCopyPolygon(p[i]); for ((k = 0, q = poly->vertex); k < poly->numVtces; (++k, ++q)) { VTransform(q, m, &tmp); tmp.x += s.x; tmp.y += s.y; tmp.z += s.z; *q = tmp; } VTransformPolygon(poly, &vp->eyeSpace); VPolySet_Add(ps, poly); } } return 0; } weapon_Type * m61a1_new(void) { craftType *c; FILE *f; dis_entity_type em1 = {2, 9, 225, 2, 1, 0, 0}; dis_entity_type em2 = {2, 1, 222, 2, 3, 0, 0}; c = inventory_craftTypeNew(NULL); c->name = memory_strdup( weapon_idToName(weapon_M61A1) ); c->entityType = em1; c->altEntityType = em2; c->placeProc = placeCannon; f = init_fopen("tracer.obv", "r"); c->object = VReadObject(f); fclose(f); m61a1Desc.w = c; return &m61a1Desc; } /* * plotReticle : draws the aiming reticle onto the HUD. * * An aiming reticle is a circle with an inner arc that clues the * pilot as to the range of the target. Twelve tic marks are used * to demarcate the range -- each tic represents 1000 feet of * distance. */ static struct { double x, y; } ticTable[12] = { { 0.0, -1.0 }, { 0.5, -0.866 }, { 0.866, -0.5 }, { 1.0, 0.0 }, { 0.866, 0.5 }, { 0.5, 0.866 }, { 0.0, 1.0 }, { -0.5, 0.866 }, { -0.866, 0.5 }, { -1.0, 0.0 }, { -0.866, -0.5 }, { -0.5, -0.866 } }; /*ARGSUSED */ static void plotReticle(craft * c, viewer * u, int x, int y, int range) { #define RETICLE_SIZE 65 #define RANGE_SIZE 59 #define TICK_SIZE (RETICLE_SIZE + 12) int i, size, xt, yt, size1, xt1, yt1, nseg, arc; Alib_Segment seg[16]; register double rs, rt; size = (int) (RETICLE_SIZE * u->xscaleFactor); if ((size & 1) == 0) ++size; /* insure it is an odd value */ xt = x - size / 2; yt = y - size / 2; rs = size / 2; rt = ((TICK_SIZE + 1) / 2) * u->xscaleFactor; for (i = 0; i < 12; i++) { seg[i].x1 = x + (int) (rs * ticTable[i].x + 0.5); seg[i].y1 = y + (int) (rs * ticTable[i].y + 0.5); seg[i].x2 = x + (int) (rt * ticTable[i].x + 0.5); seg[i].y2 = y + (int) (rt * ticTable[i].y + 0.5); } nseg = 12; Alib_drawArc(u->v->w, xt, yt, size, size, 0, 360 * 64, HUDColor); if (range != -1) { if (range > 12000) range = 12000; arc = -range * 23040 / 12000; size1 = (int) (RANGE_SIZE * u->xscaleFactor); if ((size1 & 1) == 0) ++size1; if (size == size1) --size1; xt1 = x - size1 / 2; yt1 = y - size1 / 2; Alib_drawArc(u->v->w, xt1, yt1, size1, size1, 90 * 64, arc, HUDColor); } VDrawSegments(u->v, seg, nseg, HUDColor); } void lcos(craft * c, viewer * u) { /* * How does this LCOS thing work, anyway? * * First, let me say that this may or, more probably, may not look * anything like the technique used in a real fighter's gun sighting * system. Having said that, here's the basic assumptions and steps * used to generate the reticle on the HUD: * * 1) Using radar, we know the distance to the target. Assuming that the * radar is in working order and is locked onto something. * * 2) We know the muzzle velocity of the shells we're firing and can * use that value to closely estimate the flight time of the shells * to a target that's a certain distance away (the target). Call * this value "fTime". * * 3) Use the muzzle velocity vector to determine the * relative position (w.r.t. our craft) of a shell "fTime" seconds into * its flight. Call this vector "pos". * * 4) Gravity will accelerate the shells. Use d = 0.5 * g * t ^ 2 * to add a distance (along the Z axis that will approximate the * effect of gravity. Add that to "pos". * * 5) We know our pitch and yaw rates. These rotations will have the * effect of visually "bending" the cannon stream, from the pilot's * perspective. Use the values to generate a matrix to transform * "pos" by an amount proportional to our "fTime" value. * * 6) Convert our "pos" vector to screen x,y coordinates and call * plotReticle. */ double fTime, range, gm, pitch_rate, yaw_rate; VPoint pos, tmp; VPoint zg, z; VMatrix rotation; int clue, x, y; hist_t *hist; hist = &history[c->pIndex]; /* Step 1 */ if (c->curRadarTarget >= 0) range = c->targetDistance; else range = 2500.0; /* Step 2 */ fTime = range / MUZZLE_VELOCITY; /* Step 3 */ pos.x = fTime * MUZZLE_VELOCITY * cos(OFFSET_ANGLE); pos.y = 0.0; pos.z = -fTime * MUZZLE_VELOCITY * sin(OFFSET_ANGLE); /* Step 4 */ zg.x = zg.y = 0.0; zg.z = 1.0; VReverseTransform_(&zg, &c->trihedral, &z); gm = 0.5 * units_earth_g * fTime * fTime; pos.x += z.x * gm; pos.y += z.y * gm; pos.z += z.z * gm; /* Step 5 */ VIdentMatrix(&rotation); pitch_rate = hist->pitch_total / (double) hist->count; yaw_rate = hist->yaw_total / (double) hist->count; if (pitch_rate != 0.0) VRotate(&rotation, YRotation, -pitch_rate * fTime); if (yaw_rate != 0.0) VRotate(&rotation, ZRotation, -yaw_rate * fTime); VTransform(&pos, &rotation, &tmp); /* Step 6 */ x = (u->v->Middl.x + (int) (tmp.y * u->v->Scale.x / tmp.x)) >> 2; y = (u->v->Middl.y + (int) (tmp.z * u->v->Scale.y / tmp.x)) >> 2; if (c->curRadarTarget >= 0) clue = (int) c->targetDistance; else clue = -1; plotReticle(c, u, x, y, clue); m61a1_lcos_last_pos.x = x; m61a1_lcos_last_pos.y = y; } typedef struct _entry { double time; double min; VPoint Sg; VPoint rvel; craft *c; struct _entry *next; } entry; /** * Track cannon shells and look for impacts with aircraft. This algorithm * tracks each shell's flight. */ static void m61a1_lookForCannonImpacts(craft * burst) { craft *c; entry p[manifest_MAXPLAYERS], *list, *q, *r, *rprev; VPoint v, s0, prevSg, Vm, zeroVec = {0, 0, 0}; double t, d, roundT, startT, explosion_diameter_meters; int j; double worldLocation[3], entityLocation[3]; startT = burst->offset / burst->interval; Vm.x = burst->Sg.x - burst->prevSg.x; Vm.y = burst->Sg.y - burst->prevSg.y; Vm.z = burst->Sg.z - burst->prevSg.z; for (roundT = startT; roundT < 1.0; roundT += 1.0 / (RATE_OF_FIRE * burst->interval)) { prevSg.x = burst->prevSg.x - Vm.x * (1.0 - roundT); prevSg.y = burst->prevSg.y - Vm.y * (1.0 - roundT); prevSg.z = burst->prevSg.z - Vm.z * (1.0 - roundT); list = (entry *) NULL; for (c = ptbl, j = 0; j < manifest_MAXPLAYERS; ++j, ++c) { if (c->type == CT_FREE || burst->owner == c->pIndex) continue; /* * Reduce the relative motion of this object to a the parametric system * of equations: * x(t) = vx * t + s0x * y(t) = vy * t + s0y * z(t) = vz * t + s0z * * We can then compute the time of perigee (closest pass) along with * the associated minimum distance. */ v.x = c->Sg.x - c->prevSg.x - Vm.x; v.y = c->Sg.y - c->prevSg.y - Vm.y; v.z = c->Sg.z - c->prevSg.z - Vm.z; s0.x = c->prevSg.x - prevSg.x; s0.y = c->prevSg.y - prevSg.y; s0.z = c->prevSg.z - prevSg.z; /* * Compute time of minimum distance between the two objects (note that units * here are UPDATE_INTERVAL seconds). */ t = -(v.x * s0.x + v.y * s0.y + v.z * s0.z) / (v.x * v.x + v.y * v.y + v.z * v.z); /* * If the closest pass occurs during this update interval, check for a hit. * We'll build a linked list of all craft that this projectile may strike * during this period, arranged in ascending order by time of "perigee" * (closest pass). We'll then test for strikes. If a projectile misses * the first object, then it may have struck subsequent objects in the * list ... */ /* * One special case occurs when a target or missile's turn suddenly * changes the perigee time from positive to negative. If the missile * is within hitting range at t=0 and the time of perigee is negative, * then zap 'em. */ if (t < 0.0) { d = sqrt(s0.x * s0.x + s0.y * s0.y + s0.z * s0.z); if (isCannonHit(d, c)) { t = 0.0; } } if (t >= 0.0 && t <= 1.0) { q = &p[j]; q->Sg = prevSg; q->Sg.x += Vm.x * t; q->Sg.y += Vm.y * t; q->Sg.z += Vm.z * t; q->rvel = v; if (list == (entry *) NULL) { q->next = list; list = q; } else if (list->time > t) { q->next = list; list = q; } else { for (rprev = list, r = list->next; r != (entry *) NULL;) { if (r->time > t) break; rprev = r; r = r->next; } if (rprev != list) rprev->next = q; q->next = r; } q->time = t; q->c = c; q->min = sqrt(pow(v.x * t + s0.x, 2.0) + pow(v.y * t + s0.y, 2.0) + pow(v.z * t + s0.z, 2.0)); } } /* * Now look for cannon hits in the list of perigees. */ for (r = list; r != (entry *) NULL; r = r->next) if (isCannonHit(r->min, r->c)) { effects_new_explosion(&(r->Sg), &zeroVec, 1.0, 2.0, 0.5); /* can only damage local player */ if (r->c->type != CT_DIS_PLANE) if (damage_absorbDISDamage(r->c, &burst->cinfo->entityType, 0, 0, 0.0, VMagnitude(&r->rvel), &explosion_diameter_meters) == 0) { r->c->kill(r->c, "cannon fire"); } worldLocation[0] = r->Sg.x; worldLocation[1] = r->Sg.y; worldLocation[2] = r->Sg.z; entityLocation[0] = 0.0; entityLocation[1] = 0.0; entityLocation[2] = 0.0; dis_if_detonation( &burst->cinfo->entityType, /* munition type */ ptbl[burst->owner].disId, /* munition owner */ r->c->disId, /* target */ burst->disId, /* always zero -- not a tracked entity */ worldLocation, entityLocation, (double *) &r->rvel ); break; } } } /*ARGSUSED */ int isCannonHit(double min, craft * c) { return (min < 3.0) ? 1 : 0; } acm-6.0_20200416/src/acm/dis_if.h0000644000000000000000000005554213646045023014546 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * Copyright (C) 1995 Mats Lofkvist CelsiusTech Electronics AB * Additions Copyright (c) 1998 Web Simulations, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /** * Interface routines between the ACM program and the DIS protocol that * manages an internal array of local and remote entities. * *

Entity ID or entity handle.

* The "entity ID", or "eid" for short, is an handle of type int assigned by * this module to each tracked DIS entity, either local or remote, be it a craft, * a missile or a projectile. The zero value IS NOT a valid entity ID and can be * used to indicate "no DIS entity assigned"; the dis_if_ID_NONE macro makes * this value more apparent. This entity ID should not be confused with the * "DIS entity ID", this latter being part of the DIS protocol. * *

DIS entity identification

* All the participants to the simulation must share the same exercise ID. * Each participant shall generate its own local entities and shall send its own * state to the other participants; each entity must be univocally identified * by: DIS application ID, DIS site ID and DIS entity ID. The first 2 parameters * can be set once for all in the initialization function of this module. * The DIS entity ID is a counter assigned by the DIS library to each new DIS * entity registered by the local application. Then, each participant MUST have * a distinct application and site IDs, and MUST share the same exercise ID. * *

Local entities.

* A local entity (aircraft or missile) is registered in this module by ACM * by calling dis_if_entityEnter(), updated with dis_if_setEntityState() and finally * killed with dis_if_entityExit(). This module will take care to send all the * corresponding DIS packets to the participants. * The state of the local entities is broadcasted to the other players * periodically or after any meaningful state change according to the set * DR thresholds. The only exception to this rule are the cannon shells: each * cannon burst creates a "craft" that carries a certain number of rounds, but * each burst is not a tracked entity and each client is responsible for * simulating its dynamics once a "fire" event PDU is received from a remote * client. * *

Remote entities.

* ACM must also call dis_if_receive() to process incoming DIS packets. New * entities entering and old entities exiting the simulation are notified to ACM * through the callback function it specified in the initialization functions. * ACM may then call dis_if_getEntityState() to retrieve a "dead reckoning" DR * updated state of the remote entity. * "Silent" remote entities are removed automatically after some time; ACM is * notified as usual about that. * *

Credits

* This module was originally written by Mats Lofkvist specifically for the ACM * program and then maintained by Riley Rainey up to ACM 5. Source cleaning * and documentation integrated by Umberto Salsi for the ACM 6 release. * * @author Mats Lofkvist -- CelsiusTech Electronics AB * @author Riley Rainey * @license GNU GPL * @version $Date: 2020/01/08 06:03:07 $ * @file */ #ifndef dis_if_H #define dis_if_H #include "../util/varray.h" #include "pm.h" #include "../dis/dis/disx.h" #ifdef dis_if_IMPORT #define EXTERN #else #define EXTERN extern #endif /* fire types */ //#define dis_if_FIRE_OTHER 0 /* FIXME: not used */ #define dis_if_FIRE_M61A1 1 #define dis_if_FIRE_AIM9M 2 #define dis_if_FIRE_AIM120 3 /** * Unassigned entity ID. */ #define dis_if_ID_NONE (0) #define MARKINGS_LEN 11 typedef int (*dis_if_RequestControlCallback)(dis_pdu *, void *); typedef struct { /** Current mode. */ int mode; /** Current radar target (ptbl index). */ int cur_target; /** Time of last update. */ double lastTime; /** Last emission PDU sent or received for this emitter. */ dis_em_emission_pdu em; /** Systems passed to us. */ /** Track/jam target info. */ dis_track_info *target; } dis_if_EntityEM; typedef enum { /** Created, but non participating. */ dis_if_ENTITY_STATE_WAIT, /** Actively simulating. */ dis_if_ENTITY_STATE_SIMULATING, /** Stopped/Frozen. */ dis_if_ENTITY_STATE_STOPPED, /** used in pending state. */ dis_if_ENTITY_STATE_NONE } dis_if_EntytyState; /** * Local or remote DIS entity. */ typedef struct { /** If this entity is local or remote. */ int isLocal; /** Entity state; per [1] 4.5.5.5.3. */ dis_if_EntytyState state; dis_if_EntytyState pending_state; /** Time of state change. */ double pending_time; /** 1 to send entity state updates. */ int emit_while_frozen; /** Pointer to craft structure in ptbl. */ craft *c; /** * For local entity, it is the last time a packet has been sent. * For remote entity, it is the last time a packet has been receive. * Currently both times are set using our timestamp (seconds since Unix * epoch). */ double lastTime; /** DISForce enum. */ u_char forceId; dis_entity_id entityId; dis_entity_type entityType; dis_entity_type altEntityType; /** Dead reckoning parameters. */ dis_dr_parameters dr; /** EM emission PDU information, or NULL if not available. */ dis_if_EntityEM *em; unsigned char markings[MARKINGS_LEN+1]; unsigned int appearance; double location[3]; double velocity[3]; double linearAcceleration[3]; double orientation[3]; double angularVelocity[3]; double lastLocation[3]; double lastVelocity[3]; double lastLinearAcc[3]; double lastOrientation[3]; double lastAngularVel[3]; dis_if_RequestControlCallback controlRequestCallback; void *callbackData; } dis_if_Entity; typedef enum { OUTSTANDING_REQUEST_TRANSFER_CONTROL = 0, } dis_if_OutstandingRequest; typedef struct dis_if_OutstandingRequestInfo { /** Type of pending request. */ dis_if_OutstandingRequest request_type; /** DIS request identifier. */ dis_request_id request_id; /** Entity involved in request. */ dis_if_Entity *e; /** When will the request expire. */ double timeout_time; struct dis_if_OutstandingRequestInfo *next; struct dis_if_OutstandingRequestInfo *prev; } dis_if_OutstandingRequestInfo; /** * Callback invoked by this module when a new remote entity enter the simulation. * The arguments are the id of the new entity and its type * (one of dis_if_ENTITY_XXX). */ typedef void (*dis_if_EntityEnterCb) (int eid, dis_entity_type * etype, DISForce force, craft ** cptr); /** * Callback invoked by this module when a remote detonation occurs. * The arguments are the type of fire detonating (one of dis_if_FIRE_XXX), * the id of the firing entity, the id of the target entity, * the time of the detonation and the location of the detonation in * world coordinates and in target body coordinates. * @param ftype dis_if_FIRE_M61A1 or dis_if_FIRE_AIM9M. * @param firing Firing entity. * @param target Target craft that might so result damaged or destroyed. * @param time DIS PDU timestamp. * @param worldLocation Point of impact, that is where the missile was when * it exploded. * @param entityLocation Ignored by ACM. * @param m The missile or munition that hit the target. * @param dpdu Detonation DIS PDU. */ typedef void (*dis_if_DetonationCb) (int ftype, craft *firing, craft *target, double time, double worldLocation[3], double entityLocation[3], craft * munition, dis_detonation_pdu *dpdu); /** * Callback invoked by this module when the remote cannon firing burst DIS PDU * arrives. The m61a1 modules already provides a function for that. */ typedef void (*dis_if_CannonFireCb) (int owner, VPoint *pos, VPoint *vel, int rounds); /** This host have true UTC time. */ EXTERN int dis_if_haveAbsoluteTime; /** * Tells if networking is currently configured and ready to receive DIS packets. * If packets do really arrive is another story, but there are other monitoring * functions available to check that. * @return True if ready to receive DIS packets. */ EXTERN int dis_if_readyToReceive(void); /** * When initialized with site ID -1, this function tells if currently still * trying to validate a randomly generated site ID for possible collisions with * already used site IDs on the same exercise. While validating, no packet is * sent and the user is not really visible from the other participants. * @return True if still validating a randomly generated site ID. */ EXTERN int dis_if_isValidatingSiteId(void); /** * Initialize the DIS library. Network communication can be configured in one of * these modes: * * 1. Stand-alone mode: no networking. Client must call dis_if_enableNetwork(0) * to enable this mode; the other parameters of this function are then ignored. * * 2. Broadcast mode: all the capable interfaces are configured in * broadcasting mode and bind to the specified UDP port number for both sending * and receiving. * * 3. Relay mode: packets are sent to the specified relay host and port number; * the local computer gets an ephemeral UDP port number from the operating * system. * * Each participant MUST have a distinct application and site IDs, and MUST * share the same exercise ID. Received packets with different exercise ID are * simply discarded. * * If the site ID is set to -1, a random value is chosen and a validation period * of 15 seconds starts. During the validation period packets are received and * decoded as usual, but not packet is sent; if a site ID collision is detected, * another random value is chosen and the validation period restarts. * Client program may poll the dis_if_isValidationSiteId() function to check * if this module is currently sending packets or not. * * If the application ID is set to -1, the current process number is assigned. * * @param relay_host Name or network address of the relay server. If NULL or * empty, uses packets broadcasting instead. * @param relay_port UDP port of the relay server if in relay mode, or UDP port * number shared for local network broadcasting ([0,65535]). * @param exercise The exercise ID of the simulation application in [0,255]. * Simulation applications participating in the same simulation MUST have * the same exercise IDs. * @param site Site number in [-1,65535]. * @param application The DIS application id in [-1,65535]. * @param entityEnterCb User callback for entity enter. * @param detonationCb User callback for detonation. * @param cannonFireCb Cannon fire callback. The m61a1 modules already provides * a suitable function that can be passed here. * @return Zero is returned on success, -1 on failure. */ EXTERN int dis_if_init(char *relay_host, int relay_port, int exercise, int site, int application, dis_if_EntityEnterCb entityEnterCb, dis_if_DetonationCb detonationCb, dis_if_CannonFireCb cannonFireCb); /** * Close down the DIS library. * @return Zero is returned on success. */ EXTERN int dis_if_close(void); /** * Set the dead reckoning thresholds for location and orientation. * The values shall be given in meters and radians (phi, theta, psi). */ EXTERN void dis_if_setDRThresholds(double location, double orientation); /** * Set the current time in the DIS library. */ EXTERN void dis_if_setTime(double time); /** * Set the current time in the DIS library using the system time, * and mark the time as absolute, i.e. true UTC time. * This will improve the dead reckoning performance on networks * with significant delays between players _iff_ all hosts have * true UTC time (with millisecond precision!). * * If this is used when players do _not_ have synchronized clocks, * the result will be very strange positions for external players!! * * @return Zero is returned on success. */ EXTERN void dis_if_setTimeAbsolute(void); /** * Process all available incoming PDU's from the network. * User callbacks will be called for entering entities, * exiting entities, firing entities and detonations. * * @return Zero is returned on success. */ EXTERN int dis_if_receive(void); /** * Returns true if the entity ID is a valid handle, it is local and it is in * the simulating state. */ EXTERN int dis_if_canSimulate ( int eid ); /** * Enter a local entity. * The initial location, velocity, linear acceleration, orientation * and angular velocity will be set from the corresponding arguments. * Velocity and acceleration shall be given in world coordinates. * All parameter units are based on meters, radians and seconds. * * The world coordinate system used in DIS is GCC (geocentric Cartesian * coordinates), an earth-centered right-handed Cartesian system with * the positive X-axis passing through the Prime Meridian at the Equator, * with the positive Y-axis passing through 90 degrees East longitude * at the Equator and with the positive Z-axis passing through the * North Pole. * * The body coordinate system used in DIS is centered at the center of * the entity's bounding volume (excluding articulated parts) and have * the positive x-axis pointing to the front of the entity, the positive * y-axis pointing to the right side of the entity and the positive z-axis * pointing out of the bottom of the entity. * * @param force * @param c * @param e1 Primary entity type. * @param e2 Secondary entity type. * @param location Geocentric Cartesian coordinates (m). * @param velocity Velocity (m/s). * @param linearAcceleration * @param orientation Phi, theta and psi angles, in the order. * @param angularVelocity Angular velocity is given as [angular velocity around * body x-axis, ditto y, ditto z]. * @param eid Here returns the handle to be used for further reference. */ EXTERN void dis_if_entityEnter(DISForce force, craft * c, dis_entity_type * e1, dis_entity_type * e2, double location[3], double velocity[3], double linearAcceleration[3], double orientation[3], double angularVelocity[3], int *eid); /** * Remove the entity with id eid from the simulation. If local entity, sends a * "destroyed" DIS PDU if it is a local entity. * @param eid Entity ID. */ EXTERN void dis_if_entityExit(int eid); /** * Update the state information for a local entity. The information will be * broadcasted on the network only if it is necessary to keep the other hosts * dead reckoning from exceeding the thresholds. * See dis_if_entityEnter for information about the arguments. * @param eid Entity ID. * @param location * @param velocity * @param linearAcceleration * @param orientation Phi, theta and psi angles, in the order. * @param angularVelocity * @return True if a DIS packet of type Entity State and/or a DIS packet of * type Emission has been sent. */ EXTERN int dis_if_setEntityState(int eid, double location[3], double velocity[3], double linearAcceleration[3], double orientation[3], double angularVelocity[3]); /** * Return state information for a remote or local entity. For local entity, the * last registered state informations are returned. For remote entity, the state * information is dead reckoned from the last received data on the entity. * @param eid Entity handle. * @param location * @param velocity * @param orientation * @return True if entity available and the its state set, false if the entity * does not exist (anymore). */ EXTERN int dis_if_getEntityState(int eid, double location[3], double velocity[3], double orientation[3]); /** * Returns the entity given its DIS entity ID. * @param id * @return Entity or NULL if not found. */ EXTERN dis_if_Entity *dis_if_findEntityByDISID(dis_entity_id * id); /** * Returns the entity with given its index. * @param eid * @return Entity or NULL if not found. */ EXTERN dis_if_Entity *dis_if_findEntityByID(int eid); /** * Broadcast information about an entity firing a weapon. * The type of fire is given by ftype as one of the dis_if_FIRE_XXX types. * The id's of the firing entity and the target entity are given with * firingEid and targetEid or as dis_if_ID_NONE if not known. * The number of rounds, location of the source of fire, the velocity * vector of the rounds and the range of the rounds are given with * the corresponding arguments. * The id of the event generated is returned in eventId. * If the fire type is a missile, a missile entity is created and its * id is returned in missileEid. The user program should generate * position data for the missile during its lifetime by calling * dis_if_setEntityState(). * * FIXME: dis_if_fire() not used. Not yet implemented. * * @return Zero is returned on success. */ EXTERN int dis_if_fire(int ftype, int firingEid, int targetEid, int rounds, double location[3], double velocity[3], double range, int *eventId, int *missileEid); /** * Broadcast information about a detonation of a local entity. * The type of fire is given by ftype as one of the dis_if_FIRE_XXX types. * The id's of the firing entity and the target entity are given with * firingEid and targetEid or as dis_if_ID_NONE if not known. * The id of the corresponding fire event is given as eventId or as * dis_if_ID_NONE if not known. * If the detonation is from a missile, the id of the missile is given * as missileEid or as dis_if_ID_NONE. The library will exit the * missile entity. * The location of the detonation in world coordinates and in target * body coordinates are given as worldLocation and entityLocation. * * @param munition_type Munition DIS entity ID. * @param firingEid Firing craft (this module's ID). * @param targetEid Target craft (this module's ID). * @param munitionEid Munition (this module's ID). * @param worldLocation Location of the explosion. * @param entityLocation Location of the detonation in the reference system of * the target (m). Used for damage assessment of missiles and bombs. * @param vel Velocity of the munition (world coord., m/s). Damages due to * kinetic weapons (that is, cannon shells) depends on it. * @return * 0 = Network disabled or successfully sent PDU. * -1 = Firing entity is not local. * -2 = Target isn't available anymore in our table. * -3 = Firing entity not available (player died in the meanwhile?) */ EXTERN int dis_if_detonation(dis_entity_type * munition_type, int firingEid, int targetEid, int munitionEid, double worldLocation[3], double entityLocation[3], double vel[3]); /** * Networking is enabled by default. Disabling networking no attempt will be * made to transmit or receive anything. All the rest will work as expected. * If networking disabled before initializing this module, the DIS protocol * is not initialized and an attempt to re-enable the network brings to abort. */ EXTERN void dis_if_enableNetwork(int enabled); EXTERN void dis_if_setEntityMarkings(int eid, char *markings); EXTERN void dis_if_getEntityMarkings(int eid, char *markings, int max); EXTERN void dis_if_setEntityAppearance(int eid, dis_entity_appearance x); EXTERN dis_entity_appearance dis_if_getEntityAppearance(int eid); /** * Notify the world that our current radar target changed. */ EXTERN int dis_if_radarTargetChanged(craft * c); /** * Set local entities current radar mode (modes are 0=off, 1=wide scan). */ EXTERN int dis_if_setRadarMode(craft * c, int mode, int update); /** * Get the number of radar beams emitted from this aircraft. * The dis_if_getRadarParameters() will return each specific beam. */ EXTERN int dis_if_getBeamCount(craft * c); /** * Get parameters describing the specified radar beam. * @param c Emitter. * @param j Beam number, in the range from 0 up to dis_if_getBeamCount(c)-1. * @param az_center Azimuth relative to the emitter (RAD). * @param az_width Beam half width (RAD). * @param el_center Elevation relative to the emitter (RAD). * @param el_width Beam half height (RAD). * @param erp Energy, dBm = 10.0 * log10 (e_watts / 0.001). */ EXTERN void dis_if_getRadarParameters(craft * c, int j, double *az_center, double *az_width, double *el_center, double *el_width, double *erp); /** * Set and estimate of the available network bandwidth * in bits per second. This value is used to limit entity * state transmissions in an effort to keep UDP traffic * as close to real-time as possible. */ EXTERN void dis_if_setBandwidth(double bps); /** * Process incoming PDUs for the specified number of milliseconds, thus * priming the entity table. This is called only during program * initialization, when a complete entity table is required. */ EXTERN int dis_if_snoop ( int millisec ); EXTERN int dis_if_requestControl (dis_if_Entity *e, dis_if_RequestControlCallback callbackFn, void *arg); typedef int (*dis_if_TransferControlRequestCallback)(dis_if_Entity *, dis_transfer_control_pdu *); EXTERN void dis_if_setTransferControlRequestCallback ( dis_if_TransferControlRequestCallback ); #define dis_if_RESULT_REQUEST_OK 0 #define dis_if_RESULT_UNABLE 1 /** * This routine is responsible for handling entity transfer control requests * at the simulation level. It determines if the control transfer is * feasible, adjusts simulation level data structures as needed, and returns * an indication to the caller (the DIS interface) whether the request * should proceed, or not. */ EXTERN int dis_if_transferControlRequestHandler(dis_if_Entity *e, dis_transfer_control_pdu *pdu); EXTERN int dis_if_fireCannon(craft * c, VPoint * pos, VPoint * vel, int quantity, int rate); EXTERN disx_ApplicationInfo * dis_if_getApplicationInfo(void); EXTERN varray_Type * dis_if_getEntityTable(void); /** * Returns the number of local entities currently handled. * @return */ EXTERN int dis_if_getNumberOfLocalEntities(void); /** * Returns the number of remote entities currently handled. * @return */ EXTERN int dis_if_getNumberOfRemoteEntities(void); /** * Returns the current number of received DIS packets processed per second * (estimated). * @return */ EXTERN double dis_if_getProcessedPacketsPerSecond(void); /** * Updates the state of the remote craft according to the most updated DIS data * available. * @param c Remote craft to update. * @return NULL on success, or "not tracked anymore" if no data available. */ EXTERN char *dis_if_updateRemote(craft *c); /** * Acquires the state of the local craft, possibly broadcasting a DIS state * packet. * @param c Local craft. */ EXTERN void dis_if_updateLocal(craft *c); /** * Sends a broadcast text message all the users will see in their emulated * terminal (F1). * EXPERIMENTAL, does not work yet. */ EXTERN int dis_if_sendMessage(int senderEid, char *s); #undef EXTERN #endif acm-6.0_20200416/src/acm/adf.c0000644000000000000000000002046213646045023014027 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * Copyright (C) 2007 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include "../util/memory.h" #include "pm.h" #include "navaid.h" #include "vpath_gallery.h" #define adf_IMPORT #include "adf.h" /** Repeat station reception check every ... (s). */ #define RECEPTION_CHECK_INTERVAL 1.0 /* Every station sends its Morse ID every ... (s). */ #define ID_DELAY 10.0 /** * State of the ADF display panel. */ typedef struct adf_data { /** Next ADF in the list. */ struct adf_data *next; /** Associated viewer. */ viewer * v; /** If currently visible, as the panel slot is shared with radar and HSI. */ _BOOL enabled; /** Tuned frequency. */ navaid_Channel frequency; /** Tuned station, if in range. */ navaid_Type *station; /** Next planned station tuning check (simulation time, s). */ double next_check; /** Next expected ID transmission from tuned station (simulation time, s). */ double id_update_at; /** Current station ID, if available. */ char *id; /** Current needle heading (DEG). */ int hdg; } adf_data; static adf_data *free_list = NULL; /** * Module cleanup function to be registered in the memory manager. */ static void adf_cleanup() { adf_data *p; while( free_list != NULL ){ p = free_list; free_list = free_list->next; memory_dispose(p); } } void adf_enable(viewer *u) { adf_data *adf; if( u->adf == NULL ){ /* Allocate memory for ADF status: */ if( free_list == NULL ){ adf = memory_allocate( sizeof(adf_data), NULL); memory_registerCleanup(adf_cleanup); } else { adf = free_list; free_list = adf->next; } /* Initialize: */ adf->v = u; adf->frequency = 200; adf->station = NULL; adf->next_check = curTime + RECEPTION_CHECK_INTERVAL; adf->id_update_at = curTime + ID_DELAY; adf->id = NULL; adf->hdg = 0; u->adf = adf; } else { adf = u->adf; } if( ! adf->enabled ){ adf->enabled = TRUE; adf->station = NULL; adf->next_check = curTime + RECEPTION_CHECK_INTERVAL; adf->id_update_at = curTime + ID_DELAY; adf->id = NULL; } } void adf_disable(viewer *u) { adf_data *adf; adf = u->adf; if( adf == NULL ) return; adf->enabled = FALSE; } static void adf_retune(adf_data *adf) { adf->station = NULL; adf->next_check = curTime + RECEPTION_CHECK_INTERVAL; adf->id_update_at = curTime + ID_DELAY; adf->id = NULL; } static void adf_update_reception(craft *c, adf_data *adf) { navaid_Type *n; if( curTime < adf->next_check ) return; adf->next_check = curTime + RECEPTION_CHECK_INTERVAL; n = navaid_reception_check(c, adf->frequency); if( n == NULL ){ /* no station found. */ adf->station = NULL; adf->id_update_at = curTime + ID_DELAY; adf->id = NULL; } else if( adf->station != n ){ /* Station change: */ adf->station = n; adf->id_update_at = curTime + ID_DELAY; adf->id = NULL; } else { /* Still the same station. Update station ID: */ if( adf->id == NULL && curTime > adf->id_update_at ){ adf->id = n->id; } } } static _BOOL is_auto_repeat( double *timeout ) { _BOOL res; res = (curTime < *timeout); *timeout = curTime + 0.1; return res; } void adf_frq_inc(viewer * u, int step) { adf_data *adf; static double timeout = 0.0; adf = u->adf; if( adf == NULL || ! adf->enabled ) return; if( is_auto_repeat(&timeout) ) step *= 2; adf->frequency += step; if( adf->frequency < navaid_NDB_CHANNEL_MIN ) adf->frequency = navaid_NDB_CHANNEL_MIN; if( adf->frequency > navaid_NDB_CHANNEL_MAX ) adf->frequency = navaid_NDB_CHANNEL_MAX; adf_retune(adf); } void adf_hdg_inc(viewer *u, int step) { adf_data *adf; static double timeout = 0.0; adf = u->adf; if( adf == NULL || ! adf->enabled ) return; if( is_auto_repeat(&timeout) ) step *= 2; adf->hdg += step; while( adf->hdg < 0 ) adf->hdg += 360; while( adf->hdg >= 360 ) adf->hdg -= 360; } static void adf_panel_string(viewer *u, double x, double y, double fh, char *s1, char *s2, char *s3) { double fw, fh2, fw2; fw = fh; fh2 = 1.5*fh; fw2 = fh2; VDrawStrokeString(u->v, (int) (x + 0.5), (int) (y + 0.5), s1, strlen(s1), (int) (fh + 0.5), radarColor); VDrawStrokeString(u->v, (int) (x + 13*fw - fw2*strlen(s2) + 0.5), (int) (y + 0.5), s2, strlen(s2), (int) (fh2 + 0.5), whiteColor); VDrawStrokeString(u->v, (int) (x + 14*fw + 0.5), (int) (y + 0.5), s3, strlen(s3), (int) (fh + 0.5), radarColor); } void adf_panel_draw(viewer * u) { adf_data *adf; Alib_Window *w; double x, y, fh, fw, il; char s[100]; adf = u->adf; if( adf == NULL || ! adf->enabled ) return; adf_update_reception(u->c, adf); w = u->v->w; Alib_setClipRect(w, &u->tuner); Alib_fillRect(w, &u->tuner, panelBackgroundColor); fh = RectWidth(u->tuner) / 20.0; fw = fh; il = 1.2*fh*2.5; /* inter-line spacing */ x = u->tuner.a.x + fw; y = u->tuner.a.y + il; /* Displays mode: */ adf_panel_string(u, x, y, fh, "Mode", "ADF", ""); y += il; /* Displays frequency */ sprintf(s, "%d", adf->frequency); adf_panel_string(u, x, y, fh, "FRQ", s, "KHz"); y += il; /* Displays station ID: */ if( adf->id != NULL ) strcpy(s, adf->id); else strcpy(s, "----"); adf_panel_string(u, x, y, fh, "STA", s, ""); y += il; /* DIsplays signal level "LVL": */ if( ! adf->enabled ) adf_panel_string(u, x, y, fh, "LVL", "OFF", ""); if( adf->station == NULL ) adf_panel_string(u, x, y, fh, "LVL", "no sgn", ""); else if( adf->id == NULL ) adf_panel_string(u, x, y, fh, "LVL", "low", ""); /* FIXME: actually, station ID still not received */ else adf_panel_string(u, x, y, fh, "LVL", "good", ""); y += il; } void adf_draw(viewer * u) { adf_data *adf; Alib_Window *w; int xc, yc, h, x, y; VMatrix m; VPoint rloc; double scale, hdg, r, a; Alib_Pixel color; adf = u->adf; if( adf == NULL || ! adf->enabled ) return; w = u->v->w; Alib_setClipRect(w, &u->indicator); Alib_fillRect(w, &u->indicator, panelBackgroundColor); color = whiteColor; x = u->indicator.a.x; y = u->indicator.a.y; scale = RectWidth(u->indicator); r = 0.44*scale; xc = x + (int) (0.50*scale+0.5); yc = y + (int) (0.50*scale+0.5); if (u->c->showMag) hdg = pm_mag_heading(u->c); else hdg = u->c->curHeading; h = (int) (0.045*scale + 0.5); /* Displays "TH" or "MH": */ VDrawStrokeString(u->v, x + (int) (0.05*scale+0.5), y + (int) (0.06*scale), (u->c->showMag)? "MH":"TH", 2, h, color); /* Draw compass scale: */ VIdentMatrix(&m); VRotate(&m, ZRotation, -hdg); VScaleMatrix(&m, r, r, r); VTranslate(&m, xc, yc, -1.0); vpath_stroke( vpath_gallery_get_compass_scale(), &m, w, whiteColor); /* Draw fixed scale: */ VIdentMatrix(&m); VScaleMatrix(&m, r/0.90, r/0.90, r/0.90); VTranslate(&m, xc, yc, -1.0); vpath_stroke( vpath_gallery_get_compass_fixed_scale(), &m, w, whiteColor); /* Draw stylized aircraft: */ VIdentMatrix(&m); VScaleMatrix(&m, 0.25*r, 0.20*r, 0.25*r); VTranslate(&m, xc, yc, -1.0); vpath_stroke( vpath_gallery_get_stylized_aircraft(), &m, w, whiteColor); /* Draw selected HDG: */ VIdentMatrix(&m); VRotate(&m, ZRotation, -hdg + units_DEGtoRAD(adf->hdg)); VScaleMatrix(&m, r, r, r); VTranslate(&m, xc, yc, -1.0); vpath_stroke( vpath_gallery_get_pointer_triangle(), &m, w, magentaColor); /* Draw pointer: */ if( adf->station == NULL ){ /* No signal -- pointer indicates right: */ a = units_DEGtoRAD(90.0); } else { VTransform(&adf->station->Sg, &u->c->XYZtoNED, &rloc); VReverseTransform(&rloc, &u->c->trihedral, &rloc); a = atan2(rloc.y, rloc.x); } VIdentMatrix(&m); VRotate(&m, ZRotation, a); VScaleMatrix(&m, 0.90*r, 0.90*r, 0.90*r); VTranslate(&m, xc, yc, -1.0); vpath_stroke( vpath_gallery_get_pointer_arrow(), &m, w, whiteColor); } acm-6.0_20200416/src/acm/events.c0000644000000000000000000003615413175036762014615 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include #include #include #include "../util/error.h" #include "adf.h" #include "aps.h" #include "box.h" #include "browse.h" #include "commands.h" #include "dis_if.h" #include "drone.h" #include "flaps.h" #include "gear.h" #include "hud.h" #include "hsi.h" #include "instruments.h" #include "joystick.h" #include "mouse.h" #include "pm.h" #include "prompt.h" #include "radar.h" #include "render.h" #include "sounds.h" #include "terminal.h" #include "weapon.h" #include "windows.h" #define events_IMPORT #include "events.h" #define MAX_MAPPED_STRING_LEN 20 #define MAX_POPUP_STRING_LEN 40 #define FLIGHT_STATE_FILE "./acm-flight-state" /* To prevent unwanted quits from the program, it is requested to press SHIFT-Q two times within 2 seconds. Anyway, the user can still close the window. Here we store the last time the SHIFT-Q was pressed: */ static double pressed_XK_Q_time = -5.0; static void doButtonEvent(craft * c, viewer * u, gui_Event * ev) { if ( ! u->hasFocus | ! u->hasComm ) return; if (ev->code == gui_EVENT_LBUTTONDOWN) { weapon_fire(c); } else if (ev->code == gui_EVENT_MBUTTONDOWN) { browse_selectCockpitItem( c, u, ev->x, ev->y, time(NULL) ); } else if (ev->code == gui_EVENT_RBUTTONDOWN) { weapon_selectNextAvailable(c); } } static void doButtonReleaseEvent(craft * c, viewer * u, gui_Event * ev) { if (ev->code == gui_EVENT_LBUTTONUP) weapon_ceaseFire(c); } /* Handle key press event. Returns TRUE if player gets killed or player asked to terminate the program. */ static _BOOL doKeyEvent(craft * c, viewer * u, int key) { if ( ! u->hasFocus ) { return FALSE; } if ( ! u->hasComm ){ if ( key == 'd' ) u->hasComm = TRUE; return FALSE; } if ( terminal_enabled(u) && (key != gui_KEY_F(1)) ){ terminal_input_char(u, key); { char line[100]; if( terminal_read_string(u, line, 100) ) commands_execute(u, line); } return FALSE; } switch (key) { case gui_KEY_F(1): terminal_toggle(u); break; case 'd': u->hasComm = FALSE; break; case 'H': windows_set_layout(c, u, gui_getWidth(u->gui), gui_getHeight(u->gui), !u->hud_mode); break; case 'A': aps_ap_toggle(c); break; case 'E': aps_rate_control_toggle(c); break; case 'Z': aps_ap_toggle(c); if( aps_ap_enabled(c) ) aps_ap_set_vs(c, 0.0); break; case 'X': aps_ac_toggle(c); break; case 'T': aps_at_toggle(c); break; case 'N': aps_an_toggle(c); break; case 'L': aps_al_toggle(c); break; case '(': aps_bank_max_dec(c); break; case ')': aps_bank_max_inc(c); break; case 'M': /* Toggle MH<->TH display */ c->showMag = ! c->showMag; break; case '<': aps_an_disable(c); aps_al_disable(c); aps_aw_set(c, units_DEGtoRAD(-3.0)); break; case '>': aps_an_disable(c); aps_al_disable(c); aps_aw_set(c, units_DEGtoRAD(3.0)); break; case ',': aps_an_disable(c); aps_al_disable(c); aps_aw_set(c, units_DEGtoRAD(-1.5)); break; case '.': aps_an_disable(c); aps_al_disable(c); aps_aw_set(c, units_DEGtoRAD(1.5)); break; case '|': aps_an_disable(c); aps_al_disable(c); aps_aw_set(c, units_DEGtoRAD(0.0)); break; case '/': aps_an_disable(c); aps_al_disable(c); aps_aw_disable(c); break; case '\\': dis_if_sendMessage(c->disId, "sending message to all the participants through DIS"); break; case gui_KEY_UP: c->pitchComm = c->pitchComm + 0.01; if ( c->pitchComm > 1.0 ) c->pitchComm = 1.0; break; case gui_KEY_DOWN: c->pitchComm = c->pitchComm - 0.01; if ( c->pitchComm < -1.0 ) c->pitchComm = -1.0; break; case 'z': c->rudderComm = c->rudderComm + 0.01; if ( c->rudderComm > 1.0 ) c->rudderComm = 1.0; break; case 'c': c->rudderComm = c->rudderComm - 0.01; if ( c->rudderComm < -1.0 ) c->rudderComm = -1.0; break; case 'x': c->rudderComm = 0.0; break; case gui_KEY_HOME: aps_off(c); c->SeTrim = 0.0; c->SaTrim = 0.0; break; case 'j': /* Adjust Elevator Trim */ c->SeTrim -= c->pitchComm; break; case 'y': flaps_up(c); break; case 'h': flaps_down(c); break; case 'w': flaps_speed_brakes_retract(c); break; case 's': flaps_speed_brakes_extend(c); break; case 't': if( u->hud_mode ) hud_timer_toggle(u); else instruments_timer_toggle(u); break; case '1': case gui_KEY_PGDW: aps_al_disable(c); aps_an_disable(c); aps_ap_disable(c); aps_at_disable(c); aps_aw_disable(c); c->throttleComm = 0.20 * 32768.0; break; case '2': case gui_KEY_PAD_MINUS: if ( aps_at_enabled(c) ) { aps_at_dec_velocity(c); } else { c->throttleComm -= 512; if ( c->throttleComm < 6553 ) c->throttleComm = 6553; } break; case '3': case gui_KEY_PAD_PLUS: if ( aps_at_enabled(c) ) { aps_at_inc_velocity(c); } else { c->throttleComm += 512; if ( c->throttleComm >= 32768 ) c->throttleComm = 32768; } break; case '4': case gui_KEY_PGUP: aps_al_disable(c); aps_an_disable(c); aps_at_disable(c); aps_ap_disable(c); aps_aw_disable(c); c->throttleComm = 32768; break; case '!': pm_thrust_reverse_toggle(c); break; case 'a': pm_after_burner_toggle(c); break; case ' ': /* Switch NAVn/RNAVn receivers: */ aps_al_disable(c); aps_an_disable(c); hsi_switch_mode(u); break; case '7': aps_an_disable(c); hsi_obs_inc(u, -1); adf_hdg_inc(u, -1); break; case '8': aps_an_disable(c); hsi_obs_inc(u, +1); adf_hdg_inc(u, +1); break; case '9': aps_al_disable(c); aps_an_disable(c); hsi_frq_inc(u, -1); adf_frq_inc(u, -1); break; case '0': aps_al_disable(c); aps_an_disable(c); hsi_frq_inc(u, +1); adf_frq_inc(u, +1); break; case gui_KEY_F(3): hsi_theta_inc(u, -1); break; case gui_KEY_F(4): hsi_theta_inc(u, +1); break; case gui_KEY_F(5): hsi_rho_inc(u, -1); break; case gui_KEY_F(6): hsi_rho_inc(u, +1); break; case 'b': if( gear_brakesEngaged(c) ) gear_brakesDisengage(c); else gear_brakesEngage(c); break; case 'g': gear_handle_toggle(c); break; case 'l': drone_new(c); break; case gui_KEY_PAD_8: render_setOutsideView(c, u, render_VIEW_FORWARD); prompt_viewer_print(u, "Front view"); break; /* look right */ case gui_KEY_PAD_6: render_setOutsideView(c, u, render_VIEW_RIGHT); prompt_viewer_print(u, "Right view"); break; /* look left */ case gui_KEY_PAD_4: render_setOutsideView(c, u, render_VIEW_LEFT); prompt_viewer_print(u, "Left view"); break; /* look back */ case gui_KEY_PAD_2: render_setOutsideView(c, u, render_VIEW_AFT); prompt_viewer_print(u, "Rear view"); break; /* look up */ case gui_KEY_PAD_5: render_setOutsideView(c, u, render_VIEW_UP); prompt_viewer_print(u, "Up view"); break; case gui_KEY_PAD_0: render_setOutsideView(c, u, render_VIEW_DOWN); prompt_viewer_print(u, "Down view"); break; case 'n': if( c->flags & FL_CHASE_VIEW ){ render_setOutsideView(c, u, render_VIEW_FORWARD); prompt_viewer_print(u, "Front view"); } else if( c->cinfo->object == NULL ){ prompt_viewer_print(u, "Sorry, no object model available for this plane."); } else { render_setOutsideView(c, u, render_VIEW_CHASE); prompt_viewer_print(u, "Chase view"); } break; case 'q': c->curRadarTarget = radar_getNewTarget(c); dis_if_radarTargetChanged(c); break; case 'D': /* Debug */ FSPageToggle(); break; case 'r': aps_al_disable(c); aps_an_disable(c); switch (c->radarMode) { case RM_OFF: case RM_STANDBY: if( u->c->cinfo->radarOutput > 0.0 ){ /* we really have a radar -- enable it */ radar_setMode(c, RM_NORMAL); } else { /* no radar -- HSI mode */ radar_setMode(c, RM_HSI); hsi_enable(u); } break; case RM_NORMAL: case RM_ACM: case RM_STT: radar_setMode(c, RM_HSI); hsi_enable(u); break; case RM_HSI: hsi_disable(u); radar_setMode(c, RM_ADF); adf_enable(u); break; case RM_ADF: adf_disable(u); radar_setMode(c, RM_OFF); break; default: adf_disable(u); radar_setMode(c, RM_OFF); hsi_enable(u); break; } break; /* this is a hack to allow change of beam parameter index in the outgoing electromagnetic emission pdu's */ case 'R': /* Cycle through radar modes: */ hsi_disable(u); adf_disable(u); aps_al_disable(c); aps_an_disable(c); switch (c->radarMode) { case RM_OFF: case RM_HSI: case RM_ADF: case RM_STANDBY: radar_setMode(c, RM_NORMAL); break; case RM_NORMAL: radar_setMode(c, RM_ACM); break; case RM_ACM: radar_setMode(c, RM_STT); break; case RM_STT: radar_setMode(c, RM_STANDBY); break; default: error_internal("c->radarMode=%d", c->radarMode); } break; #ifdef FIXME_INCOMPLETE_OR_BUGGED case XK_i: fp = fopen(FLIGHT_STATE_FILE, "w"); if ( fp == NULL ) { char s[1000]; sprintf("Error opening the file " FLIGHT_STATE_FILE " for writing: %s", strerror(errno)); prompt_craft_print(c, s); } else { fwrite((char *) &ptbl[c->pIndex], sizeof(craft), 1, fp); fclose(fp); prompt_craft_print(c, "Flight state saved in file " FLIGHT_STATE_FILE); } break; case XK_I: fp = fopen(FLIGHT_STATE_FILE, "r"); if ( fp == NULL ) { char s[1000]; sprintf("Error opening the file " FLIGHT_STATE_FILE " for reading: %s", strerror(errno)); prompt_craft_print(c, s); } else { fread((char *) &pentry, sizeof(craft), 1, fp); fclose(fp); c->flags = pentry.flags; c->Sg = pentry.Sg; c->prevSg = pentry.prevSg; c->Cg = pentry.Cg; c->trihedral = pentry.trihedral; c->curHeading = pentry.curHeading; c->curPitch = pentry.curPitch; c->curRoll = pentry.curRoll; c->p = pentry.p; c->q = pentry.q; c->r = pentry.r; c->damageBits = pentry.damageBits; c->structurePts = pentry.structurePts; c->damageCL = pentry.damageCL; c->damageCM = pentry.damageCM; c->curThrust = pentry.curThrust; c->throttle = pentry.throttle; /* FIXME: there are missing fields */ prompt_craft_print(c, "Flight state restored from file " FLIGHT_STATE_FILE); } break; case XK_semicolon: debug ^= 1; break; #endif /* FIXME_INCOMPLETE_OR_BUGGED */ case 27: prompt_viewer_print(u, "To exit the program, press SHIFT-Q two times"); break; case 'Q': if ( pressed_XK_Q_time + 2.0 >= curTime ){ c->kill(c, NULL); return TRUE; } else { pressed_XK_Q_time = curTime; prompt_viewer_print(u, "Press SHIFT-Q again within 2 sec. to exit the program"); } break; #ifndef WINNT case 'P': system("xwd -name " manifest_ACM " -out /tmp/acm-dump-`date +%s`"); prompt_viewer_print(u, "Screen dumped in file /tmp/acm-dump-*"); break; #endif #ifdef FIXME_INCOMPLETE_OR_BUGGED case XK_braceleft: box_startRecording(); prompt_viewer_print(u, "Black box recording started"); break; case XK_braceright: box_endRecording(); prompt_viewer_print(u, "Black box recording stopped"); break; case XK_bracketleft: box_startPlayback(); prompt_viewer_print(u, "Black box playback started"); break; #endif case 'K': joystick_calibrate(); break; case gui_KEY_F(7): instruments_altimeter_correction(u, -1); break; case gui_KEY_F(8): instruments_altimeter_correction(u, +1); break; case gui_KEY_F(9): instruments_attitude_reset(u); break; case gui_KEY_F(11): instruments_attitude_adjust_pitch(u, -units_DEGtoRAD(0.5)); break; case gui_KEY_F(12): instruments_attitude_adjust_pitch(u, units_DEGtoRAD(0.5)); break; case '+': windows_zoom_in(u); break; case '-': windows_zoom_out(u); break; case '$': if( c->type == CT_PLANE ) drone_take_commands(c); else drone_release_commands(c); break; case 'M' - 64: /* ctrl-m */ sounds_enable(c, ! sounds_isEnabled(c)); if( sounds_isEnabled(c) ) prompt_viewer_print(u, "Sounds enabled."); else prompt_viewer_print(u, "Sounds muted."); break; default: prompt_viewer_print(u, "Invalid key."); break; } return FALSE; } /** * Process all events from this viewer. * * Return TRUE on: * * - close request of the window: in this case the viewer u gets closed * and released * * - player gets killed or terminated: in this case the viewer u and all * the other viewers attached to the craft c gets closed and the craft c * gets released */ static _BOOL doWindowEvent(viewer * u) { gui_Event ev; craft *c; c = u->c; while( gui_getEvent(u->gui, &ev) ) { switch (ev.code) { case gui_EVENT_KEYDOWN: /* if (u->viewer_state == ViewerStateBrowsing || u->viewer_state == ViewerStatePiggyback) { if (browse_keyEvent( c, u, &ev, 1)) { return FALSE; } } else { */ if( doKeyEvent(c, u, ev.key) ){ return TRUE; } /* } */ break; case gui_EVENT_LBUTTONDOWN: case gui_EVENT_MBUTTONDOWN: case gui_EVENT_RBUTTONDOWN: doButtonEvent(c, u, &ev); break; case gui_EVENT_LBUTTONUP: case gui_EVENT_MBUTTONUP: case gui_EVENT_RBUTTONUP: doButtonReleaseEvent(c, u, &ev); break; case gui_EVENT_WINDOW_SIZE_CHANGE: windows_set_layout(c, u, ev.x, ev.y, u->hud_mode); break; case gui_EVENT_WINDOW_FOCUS_IN: u->hasFocus = TRUE; break; case gui_EVENT_WINDOW_FOCUS_OUT: u->hasFocus = FALSE; u->hasComm = FALSE; break; case gui_EVENT_WINDOW_EXPOSE: Alib_invalidate(u->w); break; case gui_EVENT_WINDOW_CLOSE: c->kill(c, NULL); return TRUE; default: break; } } return FALSE; /* done with all pending events for this viewer */ } /* Process events for each viewer */ void events_window_keyb_buttons(void) { viewer *u; u = vl_head; while( u != NULL ){ mouse_getPosition(u->c, u); if( doWindowEvent(u) ){ /* Viewer or craft terminated. We can't continue scanning the linked list of viewers because we don't know how many viewers were attached to this craft, so we have to restart from the first viewer: */ u = vl_head; } else { u = u->vl_next; } } } static int last_switches = 0; int events_joystick(craft * c, viewer * u, double throttle, int switches) { int switch_xor = switches ^ last_switches; /* * Change in state of any buttons ? */ if (switch_xor != 0) { if (switch_xor & 1) { /* * Button 1 press */ if (switches & 1) { weapon_fire(c); } /* * Button 1 release */ else { weapon_ceaseFire(c); } } /* * Button 2 press */ if (switch_xor & 2) { if (switches & 2) { weapon_selectNextAvailable(c); } } } last_switches = switches; return 0; } acm-6.0_20200416/src/acm/terminal.c0000644000000000000000000001610313175040561015104 0ustar rootroot/* * acm - Virtual terminal * Copyright (C) 2007 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include "../util/memory.h" #include "../V/Vlib.h" #include "pm.h" #define terminal_IMPORT #include "terminal.h" #define TAB_LEN 8 #define ROWS 20 #define COLS 40 #define KBD_BUF_SIZE 50 typedef struct _terminal_data { struct _terminal_data *next; _BOOL show; /* show the terminal on the viewport */ int cursor_row, cursor_col; char screen[ROWS][COLS]; char kbd_buf[KBD_BUF_SIZE]; /* chars got from keyboard */ int kbd_n; /* no. of chars in keyboard buffer */ } terminal_data; static terminal_data *free_list = NULL; static _BOOL blink = FALSE; static double blink_toggle_time = 0.0; static void terminal_cleanup() { terminal_data *trm; while( free_list != NULL ){ trm = free_list; free_list = trm->next; memory_dispose(trm); } free_list = NULL; } static void terminal_clear(terminal_data *trm) { memset(&trm->screen, ' ', ROWS*COLS); trm->cursor_row = 0; trm->cursor_col = 0; } static void terminal_scroll(terminal_data *trm) { memmove(&trm->screen, &trm->screen[1], (ROWS-1)*COLS); memset(&trm->screen[ROWS-1], ' ', COLS); } static void terminal_putc(terminal_data *trm, int ch) { int c; if( ch == '\r' ){ trm->cursor_col = 0; } else if( ch == '\n' ){ trm->cursor_row++; if( trm->cursor_row >= ROWS ){ trm->cursor_row = ROWS-1; terminal_scroll(trm); } } else if( ch == '\t' ){ c = trm->cursor_col; c += TAB_LEN; c -= c % TAB_LEN; trm->cursor_col = c; while( trm->cursor_col >= COLS ){ trm->cursor_col -= COLS; trm->cursor_row += 1; if( trm->cursor_row >= ROWS ){ trm->cursor_row = ROWS-1; terminal_scroll(trm); } } } else if( ch == '\010' /* BS */ ){ if( trm->cursor_row == 0 && trm->cursor_col == 0 ) return; trm->cursor_col--; if( trm->cursor_col < 0 ){ trm->cursor_row--; trm->cursor_col = COLS-1; } } else if( ch >= 32 ){ if( ch >= 127 ) ch = '?'; trm->screen[ trm->cursor_row ] [ trm->cursor_col ] = ch; trm->cursor_col++; if( trm->cursor_col >= COLS ){ trm->cursor_col = 0; trm->cursor_row++; if( trm->cursor_row >= ROWS ){ trm->cursor_row = ROWS-1; terminal_scroll(trm); } } } else { /* ignore */ } } void terminal_write(viewer *u, char *s) { terminal_data *trm; trm = (terminal_data *) u->terminal; while( *s != '\0' ){ terminal_putc(trm, *s); s++; } } void terminal_enable(viewer *u) { terminal_data *trm; if( u->terminal != NULL ){ trm = (terminal_data *) u->terminal; trm->show = TRUE; return; } if( free_list == NULL ){ memory_registerCleanup(terminal_cleanup); trm = memory_allocate( sizeof(terminal_data), NULL ); } else { trm = free_list; free_list = free_list->next; } trm->show = TRUE; terminal_clear(trm); trm->kbd_n = 0; u->terminal = trm; terminal_write(u, "Terminal ready. Press F1 again to exit from the terminal. Type \"help\" to get help.\n\r"); } void terminal_disable(viewer *u) { terminal_data *trm; if( u->terminal == NULL ) return; trm = (terminal_data *) u->terminal; trm->show = FALSE; } _BOOL terminal_enabled(viewer *u) { return (u->terminal != NULL) && ((terminal_data *)u->terminal)->show; } void terminal_toggle(viewer *u) { if( terminal_enabled(u) ) terminal_disable(u); else terminal_enable(u); } void terminal_input_char(viewer *u, int ch) { terminal_data * trm; if( ! terminal_enabled(u) ) return; trm = (terminal_data *) u->terminal; if( (ch >= ' ' && ch <= 126) || (ch == '\r') || (ch == '\n') ){ if( trm->kbd_n < KBD_BUF_SIZE ){ if( ch == '\r' || ch == '\n' ){ /* FIXME: set a flag telling we already have a complete line */ trm->kbd_buf[ trm->kbd_n++ ] = '\0'; terminal_write(u, "\r\n"); } else if( trm->kbd_n <= KBD_BUF_SIZE-2 ){ trm->kbd_buf[ trm->kbd_n++ ] = ch; terminal_putc(trm, ch); } else { /* keyboard buffer full */ } } else { /* FIXME: keyboard buffer full */ } } else if( ch == '\010' /* BS */ || ch == '\177' /* DEL */ ){ if( trm->kbd_n > 0 && trm->kbd_buf[ trm->kbd_n - 1 ] != '\0' ){ trm->kbd_n--; terminal_write(u, "\010 \010"); } } } _BOOL terminal_read_string(viewer *u, char *s, int s_len) { terminal_data *trm; char *eol; int n; if( s_len <= 0 ) return FALSE; if( u->terminal == NULL ) return FALSE; trm = (terminal_data *) u->terminal; if( trm->kbd_n == 0 ) return FALSE; eol = (char *) memchr(&trm->kbd_buf, 0, trm->kbd_n); if( eol == NULL ){ /* incomplete line */ if( trm->kbd_n >= KBD_BUF_SIZE ){ /* FIXME: always returns a full buffer as if it were a complete line */ n = trm->kbd_n; if( n >= s_len ) n = s_len-1; memcpy(s, &trm->kbd_buf, n); s[n] = '\0'; memmove(&trm->kbd_buf, &trm->kbd_buf[n], trm->kbd_n - n); trm->kbd_n -= n; return TRUE; } return FALSE; /* incomplete line */ } else { /* complete line available */ n = eol - &trm->kbd_buf[0]; if( n < s_len ){ memcpy(s, &trm->kbd_buf, n); s[n] = '\0'; memmove(&trm->kbd_buf, eol+1, trm->kbd_n - n-1); trm->kbd_n -= n+1; } else { n = s_len-1; memcpy(s, &trm->kbd_buf, n); s[n] = '\0'; memmove(&trm->kbd_buf, &trm->kbd_buf[n], trm->kbd_n - n); trm->kbd_n -= n; } return TRUE; } } void terminal_draw(viewer *u) { double fh, fw, lh; terminal_data *trm; int row; Alib_Rect rect; if( ! terminal_enabled(u) ) return; trm = (terminal_data *) u->terminal; if( ! trm->show ) return; /* FIXME: dynamically determinate terminal size and font height based on the current dimension of u->width, u->height */ fh = 10.0; /* font height */ fw = fh; /* font width */ lh = fh + fh/2.0; /* line height */ Alib_setRect(&rect, 0, 0, (int)(COLS*fw+0.5), (int)(ROWS*lh+0.5)); VSetClipRect(u->v, &rect); for( row=0; rowv, 0, (int)(row*lh+fh+0.5), &(trm->screen[row][0]), COLS, (int)(fh+0.5), whiteColor); /* Set blink flag: */ if( curTime >= blink_toggle_time ){ blink = ! blink; if( blink ) blink_toggle_time = curTime + 0.3; else blink_toggle_time = curTime + 0.7; } if( ! blink ){ VDrawStrokeString(u->v, (int)(trm->cursor_col*fw+0.5), (int)(trm->cursor_row*lh+fh+0.5), "_", 1, (int)(fh+0.5), whiteColor); } } void terminal_free(viewer *u) { terminal_data *trm; if( u->terminal == NULL ) return; trm = (terminal_data *) u->terminal; trm->next = free_list; free_list = trm; u->terminal = NULL; } acm-6.0_20200416/src/acm/viewer.h0000644000000000000000000000235113064343075014602 0ustar rootroot/* * acm : an aerial combat simulator for X -- Viewers handling module * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #ifndef _vlist_h #define _vlist_h #include "pm.h" #ifdef viewer_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Attach a new viewer to the given aircraft and return its pointer. * The field c->vl must be already initialized or set to NULL. */ EXTERN viewer * viewer_new(craft *c); /** * Release the viewer, close the window, and detach the viewer from the * craft's list of viewers. */ EXTERN void viewer_free(viewer *v); #undef EXTERN #endif acm-6.0_20200416/src/acm/inventory.c0000644000000000000000000011256213260344464015340 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include #include #include #include "../util/error.h" #include "../util/memory.h" #include "../util/reader.h" #include "../util/units.h" #include "init.h" #include "planes.h" #include "pm.h" #include "weapon.h" #define inventory_IMPORT #include "inventory.h" /** * The entity_object_map is used to map DIS entity types to a * displayable object. */ typedef struct _entity_object_map { dis_entity_type entity_type; dis_entity_type entity_mask; char * object_name; VObject *obj; } entity_object_map; /** * Currently active craft types. This double-linked list includes: * - Aircraft types loaded from the inventory file. * - Missiles created in the respective modules. * - Drop bombs created in the ccip module. * - Cannon shells created by the m61a1 module. * - Runways, the name being the name of the airport and the polygons being * one or several runways of that airport. * - Features. */ static craftType *craft_types; // Recycled craft types. static craftType *craft_types_pool; craftType * inventory_craftTypeNew(zone_Type *zone) { craftType *c; if( craft_types_pool == NULL ){ c = memory_allocate(sizeof(craftType), NULL); memset(c, 0, sizeof(craftType)); } else { c = craft_types_pool; craft_types_pool = c->next; } c->next = craft_types; c->prev = NULL; c->zone = zone; if( craft_types != NULL ) craft_types->prev = c; craft_types = c; return c; } /** * Removes a craft type and put into the recycle pool. * @param c */ void inventory_craftTypeRelease(craftType *c) { if( c->prev == NULL ){ if( c->next != NULL ) c->next->prev = NULL; craft_types = c->next; } else { c->prev->next = c->next; if( c->next != NULL ) c->next->prev = c->prev; } memory_dispose(c->name); if( c->object != NULL ) VDestroyObject (c->object); memory_dispose(c->objname); memory_dispose(c->description); memory_dispose(c->modelname); memory_dispose(c->CLift); memory_dispose(c->CDb); memory_dispose(c->CnBeta); memory_dispose(c->ClBeta); memory_dispose(c->Thrust); memory_dispose(c->ABThrust); int i; for (i=0; istation[i].type); } memset(c, 0, sizeof(craftType)); c->next = craft_types_pool; craft_types_pool = c; } struct lex_record; typedef enum { RESERVED_WORD, vtDOUBLE, vtLONG, vtANGLE, vtNMILES, vtKNOTS, vtTABLE, vtPOINT, vtSTRING, vtSTATION, vtENTITY } value_type; typedef enum { Nil, EndOfFile, /* * Reserved words must be added to this section */ TOKEN_NUMBER, RW_PUNCTUATION, TOKEN_STRING, TOKEN_LEFT_BRACE, TOKEN_RIGHT_BRACE, TOKEN_COMMA, TOKEN_COLON, TOKEN_SEMICOLON, RW_INCLUDE, RW_USE, RW_AIRCRAFT, RW_DESCRIPTION, RW_ENGINE_TYPE, RW_HARDPOINT, RW_KINETIC, RW_EXPLOSIVE, /* * Fields in the craftType structure must be added in this section */ Object, InternalModel, AspectRatio, BetaStall, CLift, CDb, CnBeta, ClBeta, CDBOrigin, CDBFactor, CDBPhase, CYbeta, Clda, Cldr, Clp, Cmq, Cnr, maxAileron, maxRudder, effElevator, effRudder, Ixx, Iyy, Izz, CmAlpha, MaxFlap, CFlap, FlapDrag, FlapRate, CGearDrag, GearRate, MaxSpeedBrake, CSpeedBrake, SpeedBrakeRate, SpeedBrakeIncr, WingArea, WingSpan, WingChord, WingHeight, EmptyWeight, MaxLoadZPositive, MaxLoadZNegative, MaxFuel, EngineType, MaxThrust, MaxABThrust, Thrust, ABThrust, HasThrustReverser, EngineLag, SpFuelConsump, SpABFuelConsump, GroundingPoint, ViewPoint, MuStatic, MuKinetic, MuBStatic, MuBKinetic, MaxNWDef, Rm, Rn, Dm, Dn, Km, Kn, Gm, Gn, CmMax, CnMax, TailExtent, MTOW, Vs0, Vs1, Vfe, Vno, Vne, StructurePts, RadarOutput, RadarTRange, RadarDRange, TEWSThreshold, HardPoint0, HardPoint1, HardPoint2, HardPoint3, HardPoint4, HardPoint5, HardPoint6, HardPoint7, HardPoint8, WeaponStation, WeaponCount, DISEntityType, Description } field_id; struct keyword_info { char *word; value_type type; field_id id; char *ptr; }; static craftType xxx; #define A(x) (char *) x #define B(x) ParseEngineType(&c.engineType) static struct keyword_info keywords[] = { {"Description", vtSTRING, Description, A(&xxx.description)}, {"Object", vtSTRING, Object, A(&xxx.objname)}, {"InternalModel", vtSTRING, InternalModel, A(&xxx.modelname)}, {"AspectRatio", vtDOUBLE, AspectRatio, A(&xxx.aspectRatio)}, {"BetaStall", vtANGLE, BetaStall, A(&xxx.betaStall)}, {"CLift", vtTABLE, CLift, A(&xxx.CLift)}, {"CDb", vtTABLE, CDb, A(&xxx.CDb)}, {"CnBeta", vtTABLE, CnBeta, A(&xxx.CnBeta)}, {"ClBeta", vtTABLE, ClBeta, A(&xxx.ClBeta)}, {"CDBOrigin", vtDOUBLE, CDBOrigin, A(&xxx.CDBOrigin)}, {"CDBFactor", vtDOUBLE, CDBFactor, A(&xxx.CDBFactor)}, {"CDBPhase", vtANGLE, CDBPhase, A(&xxx.CDBPhase)}, {"CYBeta", vtDOUBLE, CYbeta, A(&xxx.CYbeta)}, {"Clda", vtDOUBLE, Clda, A(&xxx.Clda)}, {"Cldr", vtDOUBLE, Cldr, A(&xxx.Cldr)}, {"Clp", vtDOUBLE, Clp, A(&xxx.Clp)}, {"Cmq", vtDOUBLE, Cmq, A(&xxx.Cmq)}, {"Cnr", vtDOUBLE, Cnr, A(&xxx.Cnr)}, {"MaxAileron", vtANGLE, maxAileron, A(&xxx.maxAileron)}, {"MaxRudder", vtANGLE, maxRudder, A(&xxx.maxRudder)}, {"EffElevator", vtDOUBLE, effElevator, A(&xxx.effElevator)}, {"EffRudder", vtDOUBLE, effRudder, A(&xxx.effRudder)}, {"Ixx", vtDOUBLE, Ixx, A(&xxx.I.m[0][0])}, {"Iyy", vtDOUBLE, Iyy, A(&xxx.I.m[1][1])}, {"Izz", vtDOUBLE, Izz, A(&xxx.I.m[2][2])}, {"CmAlpha", vtDOUBLE, CmAlpha, A(&xxx.cmSlope)}, {"MaxFlap", vtANGLE, MaxFlap, A(&xxx.maxFlap)}, {"CFlap", vtDOUBLE, CFlap, A(&xxx.cFlap)}, {"CFlapDrag", vtDOUBLE, FlapDrag, A(&xxx.cFlapDrag)}, {"FlapRate", vtANGLE, FlapRate, A(&xxx.flapRate)}, {"CGearDrag", vtDOUBLE, CGearDrag, A(&xxx.cGearDrag)}, {"GearRate", vtANGLE, GearRate, A(&xxx.gearRate)}, {"MaxSpeedBrake", vtANGLE, MaxSpeedBrake, A(&xxx.maxSpeedBrake)}, {"CSpeedBrake", vtDOUBLE, CSpeedBrake, A(&xxx.cSpeedBrake)}, {"SpeedBrakeRate", vtANGLE, SpeedBrakeRate, A(&xxx.speedBrakeRate)}, {"SpeedBrakeIncr", vtANGLE, SpeedBrakeIncr, A(&xxx.speedBrakeIncr)}, {"WingArea", vtDOUBLE, WingArea, A(&xxx.wingS)}, {"WingHalfSpan", vtDOUBLE, WingSpan, A(&xxx.wings)}, {"WingHeight", vtDOUBLE, WingHeight, A(&xxx.wingh)}, {"Chord", vtDOUBLE, WingChord, A(&xxx.c)}, {"EmptyWeight", vtDOUBLE, EmptyWeight, A(&xxx.emptyWeight)}, {"MaxLoadZPositive", vtDOUBLE, MaxLoadZPositive, A(&xxx.maxLoadZPositive)}, {"MaxLoadZNegative", vtDOUBLE, MaxLoadZNegative, A(&xxx.maxLoadZNegative)}, {"MaxFuel", vtDOUBLE, MaxFuel, A(&xxx.maxFuel)}, {"MaxThrust", vtDOUBLE, MaxThrust, A(&xxx.maxThrust)}, {"MaxABThrust", vtDOUBLE, MaxABThrust, A(&xxx.maxABThrust)}, {"Thrust", vtTABLE, Thrust, A(&xxx.Thrust)}, {"ABThrust", vtTABLE, ABThrust, A(&xxx.ABThrust)}, {"HasThrustReverser", vtLONG, HasThrustReverser, A(&xxx.hasThrustReverser)}, {"EngineLag", vtDOUBLE, EngineLag, A(&xxx.engineLag)}, {"SpFuelConsump", vtDOUBLE, SpFuelConsump, A(&xxx.spFuelConsump)}, {"SpABFuelConsump", vtDOUBLE, SpABFuelConsump, A(&xxx.spABFuelConsump)}, {"ViewPoint", vtPOINT, ViewPoint, A(&xxx.viewPoint)}, {"MuStatic", vtDOUBLE, MuStatic, A(&xxx.muStatic)}, {"MuKinetic", vtDOUBLE, MuKinetic, A(&xxx.muKinetic)}, {"MuBStatic", vtDOUBLE, MuBStatic, A(&xxx.muBStatic)}, {"MuBKinetic", vtDOUBLE, MuBKinetic, A(&xxx.muBKinetic)}, {"MaxNWDef", vtANGLE, MaxNWDef, A(&xxx.maxNWDef)}, {"Rm", vtPOINT, Rm, A(&xxx.rm)}, {"Rn", vtPOINT, Rn, A(&xxx.rn)}, {"Dm", vtDOUBLE, Dm, A(&xxx.Dm)}, {"Dn", vtDOUBLE, Dn, A(&xxx.Dn)}, {"Km", vtDOUBLE, Km, A(&xxx.Km)}, {"Kn", vtDOUBLE, Kn, A(&xxx.Kn)}, {"Gm", vtDOUBLE, Gm, A(&xxx.Gm)}, {"Gn", vtDOUBLE, Gn, A(&xxx.Gn)}, {"CmMax", vtDOUBLE, CmMax, A(&xxx.cmMax)}, {"CnMax", vtDOUBLE, CnMax, A(&xxx.cnMax)}, {"TailExtent", vtPOINT, TailExtent, A(&xxx.tailExtent)}, {"MTOW", vtDOUBLE, MTOW, A(&xxx.MTOW)}, {"Vs0", vtDOUBLE, Vs0, A(&xxx.Vs0)}, {"Vs1", vtDOUBLE, Vs1, A(&xxx.Vs1)}, {"Vfe", vtDOUBLE, Vfe, A(&xxx.Vfe)}, {"Vno", vtDOUBLE, Vno, A(&xxx.Vno)}, {"Vne", vtDOUBLE, Vne, A(&xxx.Vne)}, {"StructurePoints", vtLONG, StructurePts, A(&xxx.structurePts)}, {"RadarOutput", vtDOUBLE, RadarOutput, A(&xxx.radarOutput)}, {"RadarTRange", vtNMILES, RadarTRange, A(&xxx.radarTRange)}, {"RadarDRange", vtNMILES, RadarDRange, A(&xxx.radarDRange)}, {"TEWSThreshold", vtDOUBLE, TEWSThreshold, A(&xxx.TEWSThreshold)}, {"HardPoint1", vtPOINT, HardPoint1, A(&xxx.wStation[1])}, {"HardPoint2", vtPOINT, HardPoint2, A(&xxx.wStation[2])}, {"HardPoint3", vtPOINT, HardPoint3, A(&xxx.wStation[3])}, {"HardPoint4", vtPOINT, HardPoint4, A(&xxx.wStation[4])}, {"HardPoint5", vtPOINT, HardPoint5, A(&xxx.wStation[5])}, {"HardPoint6", vtPOINT, HardPoint6, A(&xxx.wStation[6])}, {"HardPoint7", vtPOINT, HardPoint7, A(&xxx.wStation[7])}, {"HardPoint8", vtPOINT, HardPoint8, A(&xxx.wStation[8])}, {"HardPoint0", vtPOINT, HardPoint0, A(&xxx.wStation[0])}, {"WeaponCount", vtLONG, WeaponCount, A(&xxx.sCount)}, {"WeaponStation", vtSTATION, WeaponStation, 0}, {"include", RESERVED_WORD, RW_INCLUDE, 0}, {"use", RESERVED_WORD, RW_USE, 0}, {"aircraft", RESERVED_WORD, RW_AIRCRAFT, 0}, {"description", RESERVED_WORD, RW_DESCRIPTION, 0}, {"EngineType", RESERVED_WORD, RW_ENGINE_TYPE, 0}, {"hardpoint", RESERVED_WORD, RW_HARDPOINT, 0}, {"kinetic", RESERVED_WORD, RW_KINETIC, 0}, {"explosive", RESERVED_WORD, RW_EXPLOSIVE, 0}, {"blast", RESERVED_WORD, RW_EXPLOSIVE, 0}, {"DISEntityType", vtENTITY, DISEntityType, A(&xxx.entityType)}, {"DISAltEntityType", vtENTITY, DISEntityType, A(&xxx.altEntityType)}, {NULL, RESERVED_WORD, Nil, 0} }; typedef union { struct keyword_info *kw; double double_value; interpolate_Table *table_value; char *string_value; long long_value; } lex_val; static lex_val lex_value; struct lex_record { char *filename; FILE *f; int lineno; int lookahead_valid; int lookahead; int stack_top; lex_val value_stack[16]; }; #define push_value(p, type, val) \ p->value_stack[p->stack_top++].type = val #define pop_value(p, type) (p->value_stack[--p->stack_top].type) #define input(p) (p->lookahead_valid \ ? (p->lookahead_valid = 0, p->lookahead) \ : (((p->lookahead = getc(p->f)) == '\n') \ ? (p->lineno++, p->lookahead) \ : p->lookahead)) #define unput(p, c) { p->lookahead = c; p->lookahead_valid = 1; } static char token[256]; static int token_length = 0; #define STATE_INITIAL 0 #define STATE_WORD 1 #define STATE_NUMBER 2 #define STATE_STRING 3 #define STATE_COMMENT 4 static struct lex_record * OpenSourceFile(char *name) { struct lex_record *p; FILE *f; if ((f = fopen(name, "r")) == (FILE *) NULL) { return (struct lex_record *) NULL; } p = (struct lex_record *) memory_allocate(sizeof(struct lex_record), NULL); p->filename = memory_strdup(name); p->lineno = 1; p->lookahead_valid = 0; p->stack_top = 0; p->f = f; return p; } static void ParseError(struct lex_record *p, char *s) { error_external("%s:%): %s", p->filename, p->lineno, s); } static field_id NextTokenx(struct lex_record *p) { register int c, state = STATE_INITIAL; register struct keyword_info *q; token_length = 0; while ((c = input(p)) != EOF) { switch (state) { case STATE_INITIAL: if (isalpha(c)) { token[token_length++] = c; state = STATE_WORD; } else if (isspace(c)) { continue; } else if (isdigit(c) || c == '-' || c == '+' || c == '.') { token[token_length++] = c; state = STATE_NUMBER; } else if (c == '"') { state = STATE_STRING; } else if (c == '#') { state = STATE_COMMENT; } else { token[0] = c; token[1] = '\0'; switch (c) { case ',': return TOKEN_COMMA; case ':': return TOKEN_COLON; case ';': return TOKEN_SEMICOLON; case '{': return TOKEN_LEFT_BRACE; case '}': return TOKEN_RIGHT_BRACE; default: ParseError(p, "invalid character"); state = STATE_INITIAL; } } break; case STATE_WORD: case STATE_NUMBER: if (isspace(c) || c == ':' || c == ',' || c == '{' || c == '}') { token[token_length] = '\0'; unput(p, c); if (state == STATE_WORD) { for (q = keywords; q->word; ++q) { if (strcmp(q->word, token) == 0) { lex_value.kw = q; return q->id; } } return Nil; } else { errno = 0; char *end; lex_value.double_value = strtod( token, &end ); if( end == token || *end != 0 ) error_external("%s:%d: invalid syntax for number: %s", p->filename, p->lineno, token); if (errno == ERANGE) error_external("%s:%d: floating point number out of the range: %s", p->filename, p->lineno, token); return TOKEN_NUMBER; } } else { token[token_length++] = c; } break; case STATE_STRING: switch (c) { case '"': token[token_length] = '\0'; return TOKEN_STRING; case '\n': ParseError(p, "strings cannot span a line"); unput(p, c); state = STATE_INITIAL; break; case '\\': switch (c = input(p)) { case EOF: ParseError(p, "Premature End-of-file"); break; case 'n': token[token_length++] = '\n'; break; case 't': token[token_length++] = '\t'; break; default: token[token_length++] = c; break; } default: token[token_length++] = c; break; } break; case STATE_COMMENT: while (c != EOF) { if (c == '\n') break; c = input(p); } state = STATE_INITIAL; break; } } return EndOfFile; } static field_id NextToken(struct lex_record * p) { field_id t; t = NextTokenx(p); return t; } /* * Skip to the specified token, if token is Nil, then skip to the end of the * current line. */ static void Resync(struct lex_record *p, field_id token) { field_id t; int c; if (token == Nil) { while ((c = input(p)) != EOF) { if (c == '\n') break; } } else { while ((t = NextToken(p)) != EndOfFile) { if (t == token) break; } } } /* * Parse syntax: '{' number ',' number ',' number '}' */ static int ParsePoint(struct lex_record *p) { if (NextToken(p) != TOKEN_LEFT_BRACE) { Resync(p, TOKEN_RIGHT_BRACE); return -1; } if (NextToken(p) != TOKEN_NUMBER) { Resync(p, TOKEN_RIGHT_BRACE); return -1; } push_value(p, double_value, lex_value.double_value); if (NextToken(p) != TOKEN_COMMA) { Resync(p, TOKEN_RIGHT_BRACE); return -1; } if (NextToken(p) != TOKEN_NUMBER) { Resync(p, TOKEN_RIGHT_BRACE); return -1; } push_value(p, double_value, lex_value.double_value); if (NextToken(p) != TOKEN_COMMA) { Resync(p, TOKEN_RIGHT_BRACE); return -1; } if (NextToken(p) != TOKEN_NUMBER) { Resync(p, TOKEN_RIGHT_BRACE); return -1; } push_value(p, double_value, lex_value.double_value); if (NextToken(p) != TOKEN_RIGHT_BRACE) { Resync(p, TOKEN_RIGHT_BRACE); return -1; } return 0; } static int ParseValue(struct lex_record *p) { if (NextToken(p) != TOKEN_NUMBER) { Resync(p, Nil); return -1; } push_value(p, double_value, lex_value.double_value); return 0; } /* * Parse syntax: n.n.n.n.n.n.n */ static int ParseDISEntityType(struct lex_record *p) { long i, av; field_id t; for (i = 0; i < 7; ++i) { t = NextToken(p); if (t != TOKEN_NUMBER) { if (t == EndOfFile) { return -2; } Resync(p, Nil); return -1; } if (lex_value.double_value > 0) { av = (long) (lex_value.double_value + 0.5); } else { av = (long) (lex_value.double_value - 0.5); } push_value(p, long_value, av); if (i < 6 && NextToken(p) != TOKEN_COLON) { Resync(p, Nil); return -1; } } return 0; } static int ParseEntityMapEntry(struct lex_record *p, entity_object_map *po) { long ival, result; memset (po, 0, sizeof(entity_object_map)); result = ParseDISEntityType(p); /* end-of-file */ if (result == -2) { return -1; } /* other error */ if (result != 0) { Resync(p, TOKEN_SEMICOLON); return -1; } ival = pop_value(p, long_value); if (ival == -1) { po->entity_mask.extra = 0; } else { po->entity_mask.extra = 1; po->entity_type.extra = (unsigned char) ival; } ival = pop_value(p, long_value); if (ival == -1) { po->entity_mask.specific = 0; } else { po->entity_mask.specific = 1; po->entity_type.specific = (unsigned char) ival; } ival = pop_value(p, long_value); if (ival == -1) { po->entity_mask.subcategory = 0; } else { po->entity_mask.subcategory = 1; po->entity_type.subcategory = (unsigned char) ival; } ival = pop_value(p, long_value); if (ival == -1) { po->entity_mask.category = 0; } else { po->entity_mask.category = 1; po->entity_type.category = (unsigned char) ival; } ival = pop_value(p, long_value); if (ival == -1) { po->entity_mask.country = 0; } else { po->entity_mask.country = 1; po->entity_type.country = (unsigned short) ival; } ival = pop_value(p, long_value); if (ival == -1) { po->entity_mask.domain = 0; } else { po->entity_mask.domain = 1; po->entity_type.domain = (unsigned char) ival; } ival = pop_value(p, long_value); if (ival == -1) { po->entity_mask.kind = 0; } else { po->entity_mask.kind = 1; po->entity_type.kind = (unsigned char) ival; } if (NextToken(p) != TOKEN_COMMA) { Resync(p, TOKEN_SEMICOLON); return -1; } if (NextToken(p) != TOKEN_STRING) { Resync(p, TOKEN_SEMICOLON); return -1; } po->object_name = memory_strdup( token ); if (NextToken(p) != TOKEN_SEMICOLON) { Resync(p, TOKEN_SEMICOLON); return -1; } return 0; } entity_object_map *eo_map; int eo_map_count; static int inventory_compileMapEntities(char *name, int *count, entity_object_map **pmap) { struct lex_record *p; int code = 0; entity_object_map po; int n = 0; *pmap = NULL; *count = 0; if ((p = OpenSourceFile(name)) == NULL) { fprintf(stderr, "unable to open entity map file\n"); return -1; } while (ParseEntityMapEntry(p, &po) == 0 && code == 0) { *pmap = memory_realloc(*pmap, sizeof(entity_object_map) * (n+1) ); (*pmap)[n] = po; n++; } *count = n; fclose(p->f); memory_dispose(p->filename); memory_dispose((char *) p); return code; } /* * munition_entity_type , warhead_type , explosion_diameter , damage_factor ; */ munition_map *mun_map; int mun_map_count; static int ParseMunitionMapEntry(struct lex_record *p, munition_map *po) { long ival, result; field_id t; memset (po, 0, sizeof(munition_map)); result = ParseDISEntityType(p); /* end-of-file */ if (result == -2) { return -1; } /* other error */ if (result != 0) { Resync(p, TOKEN_SEMICOLON); return -1; } ival = pop_value(p, long_value); if (ival == -1) { po->entity_mask.extra = 0; } else { po->entity_mask.extra = 1; po->entity_type.extra = (unsigned char) ival; } ival = pop_value(p, long_value); if (ival == -1) { po->entity_mask.specific = 0; } else { po->entity_mask.specific = 1; po->entity_type.specific = (unsigned char) ival; } ival = pop_value(p, long_value); if (ival == -1) { po->entity_mask.subcategory = 0; } else { po->entity_mask.subcategory = 1; po->entity_type.subcategory = (unsigned char) ival; } ival = pop_value(p, long_value); if (ival == -1) { po->entity_mask.category = 0; } else { po->entity_mask.category = 1; po->entity_type.category = (unsigned char) ival; } ival = pop_value(p, long_value); if (ival == -1) { po->entity_mask.country = 0; } else { po->entity_mask.country = 1; po->entity_type.country = (unsigned short) ival; } ival = pop_value(p, long_value); if (ival == -1) { po->entity_mask.domain = 0; } else { po->entity_mask.domain = 1; po->entity_type.domain = (unsigned char) ival; } ival = pop_value(p, long_value); if (ival == -1) { po->entity_mask.kind = 0; } else { po->entity_mask.kind = 1; po->entity_type.kind = (unsigned char) ival; } if (NextToken(p) != TOKEN_COMMA) { Resync(p, TOKEN_SEMICOLON); return -1; } if (NextToken(p) != TOKEN_NUMBER) { Resync(p, TOKEN_SEMICOLON); return -1; } /* warhead type */ if (lex_value.double_value >= 0) { ival = (int) (lex_value.double_value + 0.5); } else { ival = (long)(lex_value.double_value - 0.5); } if (ival == -1) { po->warhead_mask = 0; } else { po->warhead_mask = 1; po->warhead_type = (unsigned short) ival; } if (NextToken(p) != TOKEN_COMMA) { Resync(p, TOKEN_SEMICOLON); return -1; } /* explosion diameter */ if (NextToken(p) != TOKEN_NUMBER) { Resync(p, TOKEN_SEMICOLON); return -1; } po->explosion_diameter_meters = units_FEETtoMETERS(lex_value.double_value); if (NextToken(p) != TOKEN_COMMA) { Resync(p, TOKEN_SEMICOLON); return -1; } /* damage factor */ if (NextToken(p) != TOKEN_NUMBER) { Resync(p, TOKEN_SEMICOLON); return -1; } po->damage_factor = lex_value.double_value; if (NextToken(p) != TOKEN_COMMA) { Resync(p, TOKEN_SEMICOLON); return -1; } /* warhead class: kinetic or explosive */ t = NextToken(p); if (t != RW_KINETIC && t != RW_EXPLOSIVE) { Resync(p, TOKEN_SEMICOLON); return -1; } po->kinetic_flag = (t == RW_KINETIC) ? 1 : 0; if (NextToken(p) != TOKEN_SEMICOLON) { Resync(p, TOKEN_SEMICOLON); return -1; } return 0; } static int inventory_compileMunitionsMap(char *name, int *count, munition_map **pmap) { struct lex_record *p; int code = 0; munition_map po; int n = 0; *pmap = NULL; *count = 0; if ((p = OpenSourceFile(name)) == NULL) { fprintf(stderr, "unable to open entity map file\n"); return -1; } while (ParseMunitionMapEntry(p, &po) == 0 && code == 0) { *pmap = memory_realloc(*pmap, sizeof(munition_map) * (n+1) ); (*pmap)[n] = po; n++; } *count = n; fclose(p->f); memory_dispose(p->filename); memory_dispose((char *) p); return code; } /* * Parse syntax: '{' number_list '}' * * Where number_list is a collection of zero or more comma separated * numbers. The list of numbers must be an even count. * */ static int ParseTable(struct lex_record *p) { field_id t; double x[64], y[64]; int count = 0, i; interpolate_Table *table; interpolate_Entry *entry; if (NextToken(p) != TOKEN_LEFT_BRACE) { Resync(p, TOKEN_RIGHT_BRACE); return -1; } while ((t = NextToken(p)) != TOKEN_RIGHT_BRACE) { if (t == EndOfFile) return -1; if (t == TOKEN_NUMBER) { if (count == 64) { ParseError(p, "too many table entries"); return -1; } x[count] = lex_value.double_value; if (NextToken(p) != TOKEN_COMMA) { Resync(p, TOKEN_RIGHT_BRACE); return -1; } if (NextToken(p) != TOKEN_NUMBER) { Resync(p, TOKEN_RIGHT_BRACE); return -1; } y[count++] = lex_value.double_value; t = NextToken(p); if (t == TOKEN_RIGHT_BRACE) goto done; else if (t != TOKEN_COMMA) { Resync(p, TOKEN_RIGHT_BRACE); return -1; } } else { Resync(p, TOKEN_RIGHT_BRACE); return -1; } } done: /* * Build an interpolation table */ table = interpolate_new(count - 1); entry = table->entry; table->minX = x[0]; table->count = count - 1; table->entry = entry; for (i = 1; i < count; ++i) { entry[i - 1].x = x[i]; entry[i - 1].m = ((y[i] - y[i - 1]) / (x[i] - x[i - 1])); entry[i - 1].b = (y[i] - (x[i] * entry[i - 1].m)); } push_value(p, table_value, table); return 0; } /* * Parse syntax: number weapon-type number number number */ static int ParseStation(struct lex_record *p) { long i, a1, b1, c1; char *ptr; if (NextToken(p) != TOKEN_NUMBER) { Resync(p, Nil); return -1; } i = (long) (lex_value.double_value + 0.5); if (NextToken(p) != TOKEN_STRING) { Resync(p, Nil); return -1; } ptr = memory_strdup(token); if (NextToken(p) != TOKEN_NUMBER) { Resync(p, Nil); return -1; } a1 = (long) (lex_value.double_value + 0.5); if (NextToken(p) != TOKEN_NUMBER) { Resync(p, Nil); return -1; } b1 = (long) (lex_value.double_value + 0.5); if (NextToken(p) != TOKEN_NUMBER) { Resync(p, Nil); return -1; } c1 = (long) (lex_value.double_value + 0.5); push_value(p, long_value, c1); push_value(p, long_value, b1); push_value(p, long_value, a1); push_value(p, string_value, ptr); push_value(p, long_value, i); return 0; } /** * Reads next aircraft model. * The current token must be "aircraft" (RW_AIRCRAFT). */ static int ParseAircraft(struct lex_record *p, craftType *c) { field_id t; long n=0, i; double d; VPoint pt; interpolate_Table *table; dis_entity_type entity; char s[256]; struct keyword_info *kw; craftType *used; // Parse all inside global "xxx" and, if we succeeded, copy into *c. memset(&xxx, 0, sizeof(xxx)); xxx.engineType = inventory_NoEngine; if (NextToken(p) != TOKEN_STRING) { return -1; } xxx.name = memory_strdup(token); if (NextToken(p) != TOKEN_LEFT_BRACE) { return -1; } while ((t = NextToken(p)) != EndOfFile) { if (t >= Object || t == RW_USE || t == RW_ENGINE_TYPE ) { kw = lex_value.kw; switch (kw->type) { case RESERVED_WORD: /* * use "aircraft-type-name" * * uses a previously defined aircraft as the starting point for defining another */ if (kw->id == RW_USE) { if ( NextToken(p) == TOKEN_STRING ) { char * ptmp = xxx.name; n = 1; used = inventory_craftTypeSearchByZoneAndName(NULL, token); if (used) { xxx = *used; xxx.CLift = interpolate_clone (used->CLift ); xxx.CDb = interpolate_clone (used->CDb ); xxx.CnBeta = interpolate_clone (used->CnBeta ); xxx.ClBeta = interpolate_clone (used->ClBeta ); xxx.Thrust = interpolate_clone (used->Thrust ); xxx.ABThrust = interpolate_clone (used->ABThrust); //if (used->name) { // xxx.name = memory_strdup( used->name ); //} xxx.name = ptmp; if (used->description) { xxx.description = memory_strdup( used->description ); } if (used->modelname) { xxx.modelname = memory_strdup( used->modelname ); } if (used->objname) { xxx.objname = memory_strdup( used->objname ); } for (i=0; istation[i].type ) { xxx.station[i].type = memory_strdup( used->station[i].type) ; } } n = 0; } else { sprintf(s, "\"%s\" is not a valid aircraft type", token); ParseError(p, s); } } } else if (kw->id == RW_ENGINE_TYPE) { if ( NextToken(p) == TOKEN_STRING ) { if( strcmp(token, "NoEngine") == 0 ) xxx.engineType = inventory_NoEngine; else if( strcmp(token, "GenericPistonEngine") == 0 ) xxx.engineType = inventory_GenericPistonEngine; else if( strcmp(token, "GenericJetEngine") == 0 ) xxx.engineType = inventory_GenericJetEngine; else if( strcmp(token, "GenericRocketEngine") == 0 ) xxx.engineType = inventory_GenericRocketEngine; else { sprintf(s, "unknown engine type: \"%s\"", token); ParseError(p, s); } } else { sprintf(s, "unexpected token: \"%s\"", token); ParseError(p, s); } } else { sprintf(s, "unexpected token: \"%s\"", token); ParseError(p, s); } break; case vtSTRING: if (NextToken(p) == TOKEN_STRING) { n = 0; *((char **) kw->ptr) = memory_strdup(token); } else n = -1; break; case vtDOUBLE: case vtNMILES: case vtKNOTS: if ((n = ParseValue(p)) == 0) { d = pop_value(p, double_value); if (kw->type == vtNMILES) d *= units_NmToFeetFactor; else if (kw->type == vtKNOTS) d *= units_NmToFeetFactor / 3600; *((double *) kw->ptr) = d; } break; case vtANGLE: if ((n = ParseValue(p)) == 0) { d = units_DEGtoRAD(pop_value(p, double_value)); *((double *) kw->ptr) = d; } break; case vtLONG: if ((n = ParseValue(p)) == 0) { d = pop_value(p, double_value); *((long *) kw->ptr) = (long) (d + 0.5); } break; case vtTABLE: if ((n = ParseTable(p)) == 0) { table = pop_value(p, table_value); *((interpolate_Table **) kw->ptr) = table; } break; case vtPOINT: if ((n = ParsePoint(p)) == 0) { pt.z = pop_value(p, double_value); pt.y = pop_value(p, double_value); pt.x = pop_value(p, double_value); *(VPoint *) kw->ptr = pt; } break; case vtSTATION: if ((n = ParseStation(p)) == 0) { i = pop_value(p, long_value); char * wname = pop_value(p, string_value); int wid = weapon_nameToId(wname); if( wid < 0 ) error_external("unknown weapon `%s'", wname); xxx.station[i].id = wid; xxx.station[i].type = wname; xxx.station[i].info = pop_value(p, long_value); xxx.station[i].info2 = pop_value(p, long_value); xxx.station[i].info3 = pop_value(p, long_value); } break; case vtENTITY: if ((n = ParseDISEntityType(p)) == 0) { entity.extra = (unsigned char) pop_value(p, long_value); entity.specific = (unsigned char) pop_value(p, long_value); entity.subcategory = (unsigned char) pop_value(p, long_value); entity.category = (unsigned char) pop_value(p, long_value); entity.country = (unsigned char) pop_value(p, long_value); entity.domain = (unsigned char) pop_value(p, long_value); entity.kind = (unsigned char) pop_value(p, long_value); *((dis_entity_type *) kw->ptr) = entity; } break; } if (n != 0) { sprintf(s, "invalid syntax for %s\ parameter", kw->word); ParseError(p, s); } } else if (t == TOKEN_RIGHT_BRACE) { if( xxx.objname != NULL ){ char *path = reader_resolveRelativePath(p->filename, xxx.objname); memory_dispose(xxx.objname); xxx.objname = path; } // Success! xxx.zone = c->zone; xxx.prev = c->prev; xxx.next = c->next; *c = xxx; return 0; } else { sprintf(s, "\"%s\" was found where another token was\ expected", token); ParseError(p, s); return -1; } } return -1; } static void maxCLift(craftType *c, double *max_clift, double *stall_alpha) /* Return the max CLift and the corresponding stall AoA. */ { double m = 0.0, a = 0.0, n; int i; for( i = 1; i < c->CLift->count; i++ ){ /* Retrieve the original "y" value from the table: */ n = c->CLift->entry[i-1].b + c->CLift->entry[i-1].x * c->CLift->entry[i-1].m; if( i == 0 || n > m ){ m = n; a = c->CLift->entry[i-1].x; } } *max_clift = m; *stall_alpha = a; } /* Standard air density at sea level: */ #define RHO 0.07648 /* lb/ft^3 */ /* Max vertical pos/neg gust speed: */ #define MAX_GUST 30.0 /* ft/s */ static void compileSpeedLimits(craftType *c) { double max_clift, alpha_stall; maxCLift(c, &max_clift, &alpha_stall); c->alpha_stall = alpha_stall; /* Calculate Vs0, stall speed at MTOW with full flaps: */ if( c->Vs0 == 0.0 && c->MTOW > 0.0 ){ double clift = max_clift + c->cFlap * sin(c->maxFlap); c->Vs0 = units_FPStoKT( sqrt( 2.0*c->MTOW * units_earth_g / (RHO * c->wingS * clift) ) ); } /* Calculate Vs1, stall speed at MTOW without flaps: */ if( c->Vs1 == 0.0 && c->MTOW > 0.0 ){ c->Vs1 = units_FPStoKT( sqrt( 2.0*c->MTOW * units_earth_g / (RHO * c->wingS * max_clift) ) ); } /* Calculate Vno: */ if( c->Vno == 0.0 ){ double b = 6.302; c->Vno = units_FPStoKT( 2.0 * (c->maxLoadZNegative + c->emptyWeight) * units_earth_g / (RHO * c->wingS * b * MAX_GUST) ); } } /** * Parse "aircraft" record. * @param p * @return True on success. */ static int parseAircraft(struct lex_record *p) { craftType *c = inventory_craftTypeNew(NULL); if ( ParseAircraft(p, c) != 0 ){ inventory_craftTypeRelease(c); return 0; } /* * Initialize some other interesting values */ if( c->objname != NULL ){ FILE *f = fopen(c->objname, "r"); if( f == NULL ){ error_external("%s: file %s not found", p->filename, c->objname); return 0; } c->object = VReadDepthCueuedObject(f, 1); fclose(f); } else { c->object = NULL; } c->placeProc = NULL; c->damageBits = 0; c->thrust = planes_getThrustCalculator(c); c->resupply = planes_genericResupply; /* * Some older values are now derived from more precise information */ c->CLOrigin = interpolate_value(c->CLift, 0.0); c->CLSlope = (interpolate_value(c->CLift, units_DEGtoRAD(10.0)) - c->CLOrigin) / units_DEGtoRAD(10.0); compileSpeedLimits(c); return 1; } static int parseInventoryFile(char *filename) { struct lex_record *p; field_id t; int success = 1; char *subfile; if ((p = OpenSourceFile(filename)) == NULL) { error_external("%s: failed opening inventory file", filename); } t = NextToken(p); while (1) { if( t == EndOfFile ){ break; } else if( t == RW_AIRCRAFT ){ success = parseAircraft(p); if( ! success ) break; t = NextToken(p); } else if( t == RW_INCLUDE ){ t = NextToken(p); if( t != TOKEN_STRING ) error_external("%s:%d: expected double-quoted string after 'include'", p->filename, p->lineno); subfile = reader_resolveRelativePath(filename, token); success = parseInventoryFile(subfile); memory_dispose(subfile); if( ! success ){ error_external("%s:%d: failed including '%s'", p->filename, p->lineno, token); break; } t = NextToken(p); } else { error_external("%s:%d: expected either 'include' or 'aircraft'", p->filename, p->lineno); } } fclose(p->f); memory_dispose(p->filename); memory_dispose((char *) p); return success; } craftType * inventory_craftTypeSearchByZoneAndName(zone_Type *zone, char *name) { craftType *c = craft_types; while( c != NULL ){ if( zone == c->zone && strcmp(name, c->name) == 0 ) return c; c = c->next; } return NULL; } /* * Find (or possible generate) the craftType entry associated with a * given DIS entity type. */ craftType * inventory_craftTypeSearchByEntityType( const dis_entity_type * id ) { int depthcue = 1; entity_object_map *ep; craftType *c = craft_types; while( c != NULL ){ if (c->entityType.kind == id->kind && c->entityType.domain == id->domain && c->entityType.country == id->country && c->entityType.category == id->category && c->entityType.subcategory == id->subcategory && c->entityType.specific == id->specific && c->entityType.extra == id->extra) { return c; } c = c->next; } /* * Well, there wasn't a craft type defined that matched the desired * entity type. So, we'll look for an entry in the patterns contained * in the eo_map. If we find a match, create a new craftType entry * and return it. */ ep = eo_map; int i; for (i = 0; i < eo_map_count; ++ i) { FILE *f1; if (dis_entityWildcardMatch(id, &ep->entity_type, &ep->entity_mask)) { c = inventory_craftTypeNew(NULL); char *p = strrchr (ep->object_name, '.'); f1 = init_fopen (ep->object_name, "r"); c->name = memory_strdup(ep->object_name); c->objname = memory_strdup(ep->object_name); c->entityType = *id; c->altEntityType = *id; c->object = NULL; if (p != NULL && (strcmp (p, ".dxf") == 0 || strcmp (p, ".DXF") == 0)) { c->object = VReadDepthCueuedDXFObject (f1, depthcue); } else { c->object = VReadDepthCueuedObject (f1, depthcue); } if (c->object == NULL) error_internal("failed to read object from file: %s", ep->object_name); ep->obj = c->object; fclose (f1); return c; } ++ ep; } return c; } void inventory_purgeZone(zone_Type *zone) { craftType *c = craft_types; while( c != NULL ){ if( c->zone == zone ){ craftType *q = c; c = c->next; inventory_craftTypeRelease(q); } else { c = c->next; } } } static void inventory_cleanup() { /* Releases munitions map: */ memory_dispose(mun_map); mun_map = NULL; mun_map_count = 0; /* Releases aircraft inventory and recycle pool: */ while( craft_types != NULL ){ craftType *next = craft_types->next; inventory_craftTypeRelease(craft_types); craft_types = next; } while( craft_types_pool != NULL ){ craftType *next = craft_types_pool->next; memory_dispose(craft_types_pool); craft_types_pool = next; } /* Releases entity-to-object map: */ int i; for (i = 0; i < eo_map_count; ++ i) { memory_dispose(eo_map[i].object_name); } memory_dispose(eo_map); eo_map = NULL; eo_map_count = 0; } void inventory_init() { char name[999]; memory_strcpy(name, sizeof(name), init_findFile("aircraft.txt")); if ( ! parseInventoryFile(name) ) error_external("Fatal error compiling aircraft inventory"); memory_strcpy(name, sizeof(name), init_findFile("object-map.txt")); if (inventory_compileMapEntities(name, &eo_map_count, &eo_map) != 0) error_external("Fatal error reading object-map.txt"); memory_strcpy(name, sizeof(name), init_findFile("munition-map.txt")); if (inventory_compileMunitionsMap(name, &mun_map_count, &mun_map) != 0) error_external("Fatal error reading munition-map.txt"); memory_registerCleanup(inventory_cleanup); } munition_map * inventory_getMunition(int i) { if( 0 <= i && i < mun_map_count ) return &mun_map[i]; else return NULL; } void inventory_printValidAircraft() { craftType *c = craft_types; while( c != NULL ){ if( c->CLift != NULL ) printf("%s\n", c->name); c = c->next; } } acm-6.0_20200416/src/acm/list.h0000644000000000000000000000204513072421525014250 0ustar rootroot/** * Dynamic array of pointers to elements. * * FIXME: missing getter with index range check. * * FIXME: missing list manipulation functions: setter, remove, sorting. * Probably not needed by this program. * * FIXME: BUG: repeated element causes abort releasing memory for "double free". * * @file */ #ifndef _LIST_H_ #define _LIST_H_ #ifdef list_IMPORT #define EXTERN #else #define EXTERN extern #endif typedef struct { int size; int n; char **arr; } list_Type; /** * Returns a new empty list. * @return New empty list. Can be released with memory_dispose(), which also * releases each element. */ EXTERN list_Type * list_new(void); /** * Appends an element to the list. * @param l Subject list. * @param s Element to append, which is internally duplicated in memory. Can be * NULL. */ EXTERN void list_add_elem(list_Type *l, char *s); /** * Appends all the elements of another list. * @param l Subject list. * @param q Elements to append. */ EXTERN void list_add_list(list_Type *l, list_Type *q); #undef EXTERN #endif acm-6.0_20200416/src/acm/damage.h0000644000000000000000000001000613104276733014514 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991,1992 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #ifndef _damage_h #define _damage_h #include "pm.h" #ifdef damage_IMPORT #define EXTERN #else #define EXTERN extern #endif #define damage_isFunctioning(c, sys) ((c->damageBits & sys) == 0) /* * Each of these bits is true if the corresponding system is * damaged (== not functioning). * Some flags (for ex. FLAG_LOWFUEL) aren't proper "damages" * are set to warn the pilot. */ #define SYS_RADAR 0x0001 /* set if radar damaged */ #define SYS_TEWS 0x0002 /* set if TEWS damaged */ #define SYS_FLAPS 0x0004 /* set if flaps damaged */ #define SYS_SPEEDBRAKE 0x0008 #define SYS_HYD1 0x0010 #define SYS_HYD2 0x0020 #define SYS_GEN1 0x0040 #define SYS_GEN2 0x0080 #define SYS_ENGINE1 0x0100 /* set if engine #1 damaged */ //#define SYS_ENGINE2 0x0200 /* set if engine #2 damaged (FIXME: NOT USED) */ #define SYS_HUD 0x0400 /* set if HUD damaged */ #define SYS_FUEL 0x0800 /* set if there is a fuel leak */ #define SYS_NOSEGEAR 0x1000 #define SYS_LEFTMAIN 0x2000 #define SYS_RIGHTMAIN 0x4000 #define SYS_WINGS 0x08000 /* if wings broken, no lift! */ #define FLAG_LOWFUEL 0x10000 /* set when fuel < 1000 lb */ #define FLAG_SPEEDBRAKE 0x20000 /* set when speedbrake is deployed */ #define FLAG_WHEELBRAKE 0x40000 /* set when wheel brakes are applied */ #define FLAG_MAX_G_LOAD 0x80000 /* near the max positive/neg. wings load */ #define FLAG_STALL_WARN 0x100000 /* stall warning */ /** * Repairs any damage, making a brand new aircraft :-). */ EXTERN void damage_reset(craft * c); /** * Craft c is hit, assesses damage points. The points of damage depends on * the type of the warhead, the velocity of impact (for "kinetic" * warheads) and distance of the blast (for "blast" warhead). * * - For kinetic warhead, points are proportional to the product * between 0.5 * warhead damage factor and the square of the * velocity of impact. * * - For blast warhead, point are calculated as product between * warhead damage factor / (distance^2 + 1.0). * * Actual damage sustained is adjusted by a damage factor that forms a * bell curve centered around 0.75 * d. * * For each damage point absorbed, there is a 15 percent chance that it * will be absorbed by some subsystem other than the actual airframe. * * For each point absorbed by the airframe, there is a 20% chance that * it'll be absorbed by the wing and induce a rolling moment or a 10 * percent chance that it will hit a horizontal stabilizer and induce a * pitching and rolling moment. * * @param target The craft hit. * @param warhead_dis_type DIS type of the warhead. * @param warhead_type Type of warhead. * @param fuze_type Ignored. * @param distance_meters Distance from the blast (blast warhead only, m). * @param velocity_meters_per_sec Velocity of impact (meaningful for kinetic * warhead only, m/s). * @param explosion_diameter_meters Here returns the explosion diameter for the * warhead (m). * @return False if the damage cannot be absorbed and the craft must be * destroyed. */ EXTERN int damage_absorbDISDamage(craft * target, dis_entity_type *warhead_dis_type, u_short warhead_type, u_short fuze_type, double distance_meters, double velocity_meters_per_sec, double *explosion_diameter_meters); #undef EXTERN #endif acm-6.0_20200416/src/acm/update.h0000644000000000000000000000254313134152105014554 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #ifndef _update_h #define _update_h #ifdef update_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Main loop of the program. Returns when there are no more viewers. * @param frame_rate Requested frame rate on each viewer (Hz). */ EXTERN void update_loop(int frame_rate); /** * Update the variable curTime with the current time in seconds with the 0 set * as the time the program was started (this to prevent the number to become too * large, so loosing in precision). This clock is monotonic, that is curTime * never decreases. */ EXTERN void update_simulationTime(void); #undef EXTERN #endif acm-6.0_20200416/src/acm/terrain.c0000644000000000000000000000360513172244437014745 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1997 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include "pm.h" #define terrain_IMPORT #include "terrain.h" static inline double sqr(double x) { return x * x; } static double dist2(VPoint * a, VPoint *b) { return sqr(a->x - b->x) + sqr(a->y - b->y) + sqr(a->z - b->z); } double terrain_localAltitude(craft *c) { double d2_min, d2, z; if( c->terrain_altitude_timeout > curTime ) // Return the cached value. return c->terrain_altitude; // Schedule an update timeout as the aircraft moves at least 0.1 NM: double dt = 0.1*units_NmToFeetFactor / (fabs(c->Cg.x) + fabs(c->Cg.y) + 1); // ...but not too late because it might accelerate in the meanwhile: if( dt > 5 ) dt = 5; c->terrain_altitude_timeout = curTime + dt; // Search nearest runway within 100 NM. If none found, assume sea level. d2_min = sqr( units_NMtoMETERS(100) ); z = 0.0; // Sea level. craft *rwy = stbl; while( rwy != NULL ){ if( rwy->type == CT_SURFACE && (rwy->flags && FL_FIXED_OBJECT) ){ // It is a runway. d2 = dist2(&c->Sg, &rwy->Sg); if( d2 < d2_min ){ d2_min = d2; z = rwy->w.z; } } rwy = rwy->next; } // Save cached value: c->terrain_altitude = z; return z; } acm-6.0_20200416/src/acm/mouse.c0000644000000000000000000000544613140120272014417 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991,1992 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include "pm.h" #include "events.h" #include "joystick.h" #define mouse_IMPORT #include "mouse.h" void mouse_getPosition(craft * c, viewer * u) { _BOOL gotValues; int x, y; double pitchComm, rollComm, steerComm; gotValues = FALSE; /* * Sample joystick, if present */ /* if (joystick_processInput() >= 0) { double dummy, throttle; int sw; XSync(u->dpy, False); joystick_getPosition(&rollComm, &pitchComm, &dummy, &throttle, &sw); steerComm = rollComm; events_joystick(c, u, throttle, sw); gotValues = TRUE; } */ /* * No joystick, sample mouse */ //else { int width, height; gui_getPointerPosition(u->gui, &x, &y); width = gui_getWidth(u->gui); height = gui_getHeight(u->gui); if (x >= 0 && y >= 0 && x < width && y < height) { int r; /* x/y mouse movements should give a response in pitch/roll command independent from the format of the window: */ if( width < height ) r = width / 2; else r = height / 2; x = x - (width / 2); y = y - (height / 2); rollComm = - (double) x / (double) r; if( rollComm < -1.0 ) rollComm = -1.0; else if( rollComm > 1.0 ) rollComm = 1.0; steerComm = rollComm; pitchComm = - (double) y / (double) r; if( pitchComm < -1.0 ) pitchComm = -1.0; else if( pitchComm > 1.0 ) pitchComm = 1.0; if( mouse_stick_mode == mouse_NORMAL ){ /* quadratic response */ if (rollComm < 0.0) rollComm = -rollComm * rollComm; else rollComm = rollComm * rollComm; if (pitchComm < 0.0) pitchComm = -pitchComm * pitchComm; else pitchComm = pitchComm * pitchComm; } else if( mouse_stick_mode == mouse_PRECISE ){ /* cubic response */ rollComm = rollComm * rollComm * rollComm; pitchComm = pitchComm * pitchComm * pitchComm; } else { /* linear response */ } gotValues = TRUE; } } if ( gotValues && u->hasFocus && u->hasComm && c->type != CT_DRONE ) { c->pitchComm = pitchComm; c->rollComm = rollComm; c->steerComm = steerComm; } } acm-6.0_20200416/src/acm/update.c0000644000000000000000000002441413175077040014561 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /* * IMPLEMENTATION NOTES. * * This implementation basically exports the update_redraw() function which is * responsible for all the dynamics and graphics updates. Each time that function * gets called, a new updated frame is drawn. This function is also responsible * to keep the internal notion of time and "delta t". * * This "delta t" is periodically adjusted so that the simulation time follows * the wall clock. Since the wall clock is given by the gettimeofday() function, * and since this function has very high precision but typically very coarse grain, * that comparison can be made only at wide intervals of time so that the grain * becomes negligible and the interval of time is meaningful. * * Dynamics calculations are generally much lighter in terms of CPU usage than * graphic 3D calculations and screen updates, so it does not hurt to perform * several cycles of dynamic updates per each drawn frame in order to improve * the numerical stability of the simulated models (mainly, of the landing gear * with its very demanding timings). 50 Hz may be a good compromise, so if the * requested frame rate is, say, 20 Hz, then the dynamics should be re-calculated * 2 or 3 times per frame so attaining an update rate of 40 or 60 Hz respectively. */ #include #include #include "alarm.h" #include "box.h" #include "dis_if.h" #include "events.h" #include "pm.h" #include "prompt.h" #include "render.h" #include "../util/memory.h" #include "../util/timer.h" #define update_IMPORT #include "update.h" #include "radar.h" /** * Optimal update rate (Hz). This is a compromise between numerical stability * (requiring higher values) and CPU saving (requiring 1 as a minimum). * See also the comments about the updates_per_frame variable. */ #define UPDATE_RATE_OPTIMAL 60 #define FRAME_RATE_FEEDBACK_INTERVAL 60.0 /** * How many times to cycle through the dynamic calculations per displayed frame. * This value must be at least 1 (obviously), but the resulting update rate * * update_rate = updates_per_frame * frame_rate * * should be around optimal value. The actual attained update rate is * periodically evaluated, and this value is tuned accordingly in order to keep * the resulting update rate close to the optimal one. */ static int updates_per_frame = 10; /** * When we started counting processed screen frames and dynamic updates * (monotonic system time, s). */ static double start_count; /** Number of processed screen frames since we start counting. */ static int frame_count; /** Current system monotonic time (s). */ static double sysmon; /** * Returns the "system monotonic time" sysmon. Sysmon starts at 0 and * basically follows "gettimeofday()", but it is monotonic. It suffers of the * same coarse granularity of gettimeofday(), typically 10 ms under Linux and * 15 ms under Windows, so it is not suitable by itself for our simulator; it * is pretty useless to call this function at every update cycle of the * simulation because it would return the same value most of the times! */ static double update_updateSysmon() { static int sysmon_initialized = 0; static struct timeval sysmon_prev; struct timeval curr; struct timezone tz; gettimeofday(&curr, &tz); if( ! sysmon_initialized ){ /* Initialize monotonic clock. */ sysmon_initialized = 1; sysmon_prev = curr; sysmon = 0.0; } else { /* Evaluates delta_usec since last invocation: */ long delta_usec = 1000000 * (curr.tv_sec - sysmon_prev.tv_sec) + (curr.tv_usec - sysmon_prev.tv_usec); if( delta_usec > 0 ){ sysmon += 1e-6 * delta_usec; sysmon_prev = curr; } else if( delta_usec < 0 ){ /* Clock step backward (user adjust, NTP, ...). Reset: */ sysmon_prev = curr; } } return sysmon; } /** * Updates the simulation time curTime and the time interval deltaT overcoming * the limitation of the coarse granularity of the monotonic system time. * It does that by evaluating an average time interval deltaT between the calls * of this function, and then adjusting this interval so that the resulting * simulation time curTime smoothly follows the system monotonic time. * It is then guaranteed the sum of all the time intervals always matches the * total simulation time. */ void update_simulationTime () { static double dt = 0.01; // current estimated dt static double t0; // time of the last dt evaluation static int n; // no. of iterations /* Evaluate dt if enough data available. */ n++; if( (n & 7) == 0 /* ...not too often */ && n > updates_per_frame /* ...include at least 1 frame */ ){ double t1 = update_updateSysmon(); if( t1 - t0 > 0.5 ){ /* At least 0.5 s elapsed: several system ticks have been accounted, * so time difference on sysmon is meaningful. Moreover, a good * number of iterations have been accounted. Then the ratio * (t1 - t0)/n is a good estimation of the real dt over the * past n iterations. * * But this is not enough. We also require the simulation time * curTime to be as close as possible to the sysmon. * So, evaluate dt so to realign curTime to the sysmon within a given * recovery time. The recovery time is chosen so the realignment * process be smooth and to prevent div by zero (1 term * added). * * Note that if the error is zero it means curTime is perfectly * aligned with sysmon and the new evaluated dt is just the average * time interval of the last n iterations. */ double error = curTime - t1; double recovery_time = 1.0 + fabs(error); dt = (recovery_time - error) * (t1 - t0) / (recovery_time * n); // Safety: bounds dt to +/-25% of the "optimal" update rate if( dt < 0.75 / UPDATE_RATE_OPTIMAL ) dt = 0.75 / UPDATE_RATE_OPTIMAL; else if( dt > 1.25 / UPDATE_RATE_OPTIMAL ) dt = 1.25 / UPDATE_RATE_OPTIMAL; t0 = t1; n = 0; } } curTime += dt; deltaT = dt; halfDeltaTSquared = 0.5 * dt * dt; } /** * Basically updates the dynamics and displays a new frame on each viewer. * Performs the dynamics calculations updates over all the simulated entities, * updates the dead reckoning position of the remote entities, receives incoming * packets, draws the updates window frame on each active viewer, etc. * Periodically evaluates and returns the actual frame rate. * The caller is responsible to call this function periodically with a rate that * matches the user's requested frame rate, and avoiding to waste too much CPU * time by performing some delay from a frame to the next. * @return Actual frame rate (Hz) if non-negative, otherwise not available because * still evaluating. Note that a frame rate of zero is possible due to the int * limited precision! */ static int update_redraw(void) { int i, j; craft *c; char *killReason; /* * Update the dynamics of the simulated entities and updates the dead * reckoning of the remote entities. */ j = updates_per_frame; do { update_simulationTime(); /* * Jobs at high priority to be executed at UPDATE_RATE_OPTIMAL rate here. */ /* Update time in DIS interface module for correct DR calculations. */ if (dis_if_haveAbsoluteTime) dis_if_setTimeAbsolute(); else dis_if_setTime(curTime); /* Get latest remote events. */ dis_if_receive(); for ((i = 0, c = ptbl); i < manifest_MAXPLAYERS; (++i, ++c)) { if( c->type == CT_FREE || (c->flags & FL_BLACK_BOX) ) continue; killReason = c->update(c); if( killReason != NULL ) c->kill(c, killReason); } for ((i = 0, c = mtbl); i < manifest_MAXPROJECTILES; (++i, ++c)) { if(c->type == CT_FREE) continue; killReason = c->update(c); if( killReason != NULL ) c->kill(c, killReason); } j--; } while(j > 0); /* * Jobs with lesser priority to be executed at frame rate and * at the "user's experience time scale": */ /* * GUI events: */ events_window_keyb_buttons(); box_input(); /* * Update radar emissions: visible targets and received beams. */ for (i = 0; i < manifest_MAXPLAYERS; i++){ c = &ptbl[i]; if( c->type != CT_FREE ) radar_calculateEmissions(c); } /* * Render cockpit view(s): */ frame_count++; render_drawCockpitViews(); box_output(); alarm_update(); /* * Evaluate actual frame rate and adjust update rate accordingly. */ int frame_rate = -1; double elapsed = sysmon - start_count; if (frame_count >= 2 && elapsed >= 0.2) { // Evaluate actual frame rate: frame_rate = frame_count / elapsed + 0.5; if( frame_rate < 1 ) frame_rate = 1; // Adjust the update rate according to the actual frame rate: updates_per_frame = (double) UPDATE_RATE_OPTIMAL / frame_rate + 0.5; if( updates_per_frame < 1 ) updates_per_frame = 1; // Reset frame rate counters: start_count = sysmon; frame_count = 0; } return frame_rate; } void update_loop(int frame_rate) { if( frame_rate < 1 ) frame_rate = 1; int frame_interval_ms = 1000 / frame_rate; double frame_rate_feedback_next = FRAME_RATE_FEEDBACK_INTERVAL; deltaT = 1.0 / UPDATE_RATE_OPTIMAL; halfDeltaTSquared = 0.5 * deltaT * deltaT; curTime = 0.0; timer_Type *t = timer_new(); // Loop until there is at least a viewer. while ( vl_head != NULL ) { timer_reset(t); timer_start(t); int frame_rate_actual = update_redraw(); if( frame_rate_actual >= 0 && curTime > frame_rate_feedback_next ){ char s[99]; snprintf(s, sizeof(s), "Frame rate: %d Hz", frame_rate_actual); prompt_broadcast_print(s); frame_rate_feedback_next = curTime + FRAME_RATE_FEEDBACK_INTERVAL; } timer_sleepMilliseconds(frame_interval_ms - timer_getElapsedMilliseconds(t)); } memory_dispose(t); }acm-6.0_20200416/src/acm/air.c0000644000000000000000000000755113101717712014051 0ustar rootroot/* * acm : an aerial combat simulator for X * Air and wind properties module. * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include "pm.h" #include "../util/prng.h" #include "../util/units.h" #define air_IMPORT #include "air.h" void air_update(air_Properties * air, double h) { if (h < 36089.2) { air->t = units_T0 - 3.56616e-3 * h; air->p = units_P0 * pow(air->t / units_T0, 5.255912); /* lbf/ft^2 */ } else { air->t = 389.97; air->p = 472.6773 * exp(-units_earth_g * (h - 36089.2) / (units_RA * air->t)); /* lbf/ft^2 */ } air->rho = air->p / (units_RA * air->t); /* slug/ft^3 */ air->mach1 = sqrt(units_GM * units_RA * air->t); } /* Wind has two components: a constant component const_wind[], and a gust component gust[] that varies in intensity and frequence. The resulting wind is wind[] = const_wind[] + gust[]. */ static VPoint wind = { 0.0 /* from N */, 0.0 /* from E */, 0.0 /* from zenith */ }; /* wind speed (ft/s) */ static VPoint const_wind = { 0.0 /* from N */, 0.0 /* from E */, 0.0 /* from zenith */ }; /* Constant wind speed (ft/s) */ static double gust_max = 0.0; /* Max gust speed (ft/s). */ static VPoint gust = { 0.0 /* from N */, 0.0 /* from E */, 0.0 /* from zenith */ }; /* Current gust speed [ft/s] */ static VPoint target_gust = { 0.0 /* from N */, 0.0 /* from E */, 0.0 /* from zenith */ }; /* Target gust speed (ft/s) */ void air_set_wind( double wd, /* wind direction (deg) */ double wv) /* wind velocity (kt) */ { wd = units_DEGtoRAD(wd); wv = units_KTtoFPS(wv); const_wind.x = wv * cos(wd); const_wind.y = wv * sin(wd); const_wind.z = 0.0; } void air_set_gust(double _gust_max) { gust_max = _gust_max; } #define T1_2 0.5 static void air_update_gust() { static double t_prev = 0.0, t_next = 0.0; double dt, x; /* Update gust speed: */ dt = curTime - t_prev; t_prev = curTime; gust.x += dt / T1_2 * (target_gust.x - gust.x); gust.y += dt / T1_2 * (target_gust.x - gust.y); gust.z += dt / T1_2 * (target_gust.x - gust.z); /* Update target gust speed: */ if( curTime <= t_next ) return; x = 2.0 * prng_getDouble() - 1.0; /* -1.0 <= x <= +1.0 */ target_gust.x = gust_max * x * x * x * x * x; x = 2.0 * prng_getDouble() - 1.0; /* -1.0 <= x <= +1.0 */ target_gust.y = gust_max * x * x * x * x * x; x = 2.0 * prng_getDouble() - 1.0; /* -1.0 <= x <= +1.0 */ target_gust.z = gust_max * x * x * x * x * x; /* Evaluate time of the next gust evaluation. The idea behind this calculation is that the bigger is the gust, the more is the frequency of the recalculation. So we start with this (approximated) gust module calculation: */ double m = fabs(target_gust.x) + fabs(target_gust.y) + fabs(target_gust.z); t_next = curTime + 10.0 / (m + 5.0); } static double t_next_gust_upd = 20.0; VPoint * air_get_wind(double h) { /* Update current gust speed: */ if( curTime > t_next_gust_upd ){ air_update_gust(); t_next_gust_upd = curTime + 0.1; } /* Calculate total wind speed. The gust intensity decreases as the altitude increases. */ double k = 3000.0 / (h + 3000.0); wind.x = const_wind.x + k * gust.x; wind.y = const_wind.y + k * gust.y; wind.z = const_wind.z + k * gust.z; return &wind; } acm-6.0_20200416/src/acm/radar.c0000644000000000000000000006071613175511064014374 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include #include #include "../V/Vlib.h" #include "sounds.h" #include "damage.h" #include "dis_if.h" #include "draw.h" #include "pm.h" #include "../util/error.h" #include "../util/units.h" #define radar_IMPORT #include "radar.h" #define RADAR_WINDOW_WIDTH 200 #define scanSlope 2.1445 #define SetSegment(s, xa, ya, xb, yb) {s.x1=u->indicator.a.x+(xa); \ s.x2=u->indicator.a.x+(xb); s.y1=u->indicator.a.y+(ya); s.y2=u->indicator.a.y+(yb); } #ifdef FIXME_NOT_USED typedef enum ( RM_OFF, /* radar is off */ RM_STANDBY, /* standby */ RM_NORMAL, /* track while scan */ RM_ACM, /* 20x30 acm */ RM_STT /* single target track */ ) radar_mode; typedef struct _radar_data { struct _radar_data *next; _BOOL enabled; radar_mode mode; Alib_Segment radarImage[1024]; /* the last radar frame */ int radarImageCount; } radar_data; static radar_data *free_list = NULL; #endif static char *thirty = "30"; static Alib_Point tgt[4]; static _BOOL tgt_valid = FALSE; static int rftw, rfth, slot_size; /** * Calculates the matrix to rotate from geocentric to radar coordinates, so * that the center of the radar beam is the x axis. Azimuth and elevation of the * radar beam are referred to the aircraft system; for the record, in ACM they * are always zero, so the the radar beam of our aircraft is always directed * as the x axis. * @param c Emitter. * @param XYZtoRadar Here returns the calculated rotation from geocentric to * radar. * @param el_center Elevation, up positive (RAD). * @param az_center Azimuth, left positive (RAD). */ static void GenerateWorldToRadarMatrix(craft * c, VMatrix * XYZtoRadar, double el_center, double az_center) { earth_LatLonAlt *w = &c->w; VMatrix m, ABCtoNED; VIdentMatrix(&m); VRotate(&m, ZRotation, -w->longitude); VRotate(&m, YRotation, w->latitude); VRotate(&m, YRotation, units_DEGtoRAD(90.0)); VRotate(&m, YRotation, el_center); VRotate(&m, ZRotation, -az_center); VMatrixTranspose(&c->trihedral, &ABCtoNED); VMatrixMultByRank(&m, &ABCtoNED, XYZtoRadar, 3); } static void plotNormalTarget(viewer * u, int x, int y) { SetSegment(u->radarImage[u->radarImageCount], x - 2, y - 2, x - 2, y + 2); u->radarImageCount++; SetSegment(u->radarImage[u->radarImageCount], x - 2, y + 2, x + 2, y + 2); u->radarImageCount++; SetSegment(u->radarImage[u->radarImageCount], x + 2, y + 2, x + 2, y - 2); u->radarImageCount++; SetSegment(u->radarImage[u->radarImageCount], x + 2, y - 2, x - 2, y - 2); u->radarImageCount++; } static void plotPrimaryTarget(craft * c, viewer * u, int i, int x, int y) { int xp, yp, interline; char s[16], lr; VPoint tmp, rel, deltaV; double d, cl, targetAspectAngle; xp = u->indicator.a.x + slot_size * 6 / 8; yp = u->indicator.a.y + slot_size * 5 / 8; interline = (int) (1.5 * rfth + 0.5); tgt_valid = TRUE; tgt[0].x = u->indicator.a.x + x; tgt[0].y = u->indicator.a.y + y - 4; tgt[1].x = u->indicator.a.x + x + 4; tgt[1].y = u->indicator.a.y + y; tgt[2].x = u->indicator.a.x + x; tgt[2].y = u->indicator.a.y + y + 4; tgt[3].x = u->indicator.a.x + x - 4; tgt[3].y = u->indicator.a.y + y; //Alib_fill3DPolygon(u->v->w, tgt, 4, &u->rz); Alib_fillPolygon(u->w, tgt, 4, radarColor); /* * Heading of target */ sprintf(s, " %3.3d", (int) (units_RADtoDEG(ptbl[i].curHeading))); VGetStrokeString(u->v, xp, yp, u->radarImage, &u->radarImageCount, s, strlen(s), rfth); /* * Groundspeed of target */ rel.x = ptbl[i].Cg.x; rel.y = ptbl[i].Cg.y; rel.z = 0.0; sprintf(s, "%3.3d K", (int) (VMagnitude(&rel) / units_NmToFeetFactor * 3600.0)); yp += interline; VGetStrokeString(u->v, xp, yp, u->radarImage, &u->radarImageCount, s, strlen(s), rfth); /* * Relative heading to target. */ tmp.x = units_METERStoFEET(ptbl[i].Sg.x - c->Sg.x); tmp.y = units_METERStoFEET(ptbl[i].Sg.y - c->Sg.y); tmp.z = units_METERStoFEET(ptbl[i].Sg.z - c->Sg.z); VTransform_(&tmp, &c->XYZtoNED, &rel); targetAspectAngle = ptbl[i].curHeading - pm_heading(&rel); if (targetAspectAngle > 0.0) { lr = 'R'; } else { lr = 'L'; targetAspectAngle = -targetAspectAngle; } sprintf(s, "%3.3d %c", (int) (units_RADtoDEG(targetAspectAngle) + 0.5), lr); yp += interline; VGetStrokeString(u->v, xp, yp, u->radarImage, &u->radarImageCount, s, strlen(s), rfth); /* * Closure rate */ deltaV.x = ptbl[i].Cg.x - c->Cg.x; deltaV.y = ptbl[i].Cg.y - c->Cg.y; deltaV.z = ptbl[i].Cg.z - c->Cg.z; d = VMagnitude(&rel); cl = -(deltaV.x * rel.x + deltaV.y * rel.y + deltaV.z * rel.z) / d; c->targetDistance = d; c->targetClosure = cl; yp += interline; sprintf(s, "%3.3d", (int) (cl / units_NmToFeetFactor * 3600.0)); VGetStrokeString(u->v, xp, yp, u->radarImage, &u->radarImageCount, s, strlen(s), rfth); /* * Range to target */ #define XA 40 #define XB 150 xp = XA * slot_size / RADAR_WINDOW_WIDTH; yp = rfth + 4; sprintf(s, "%d", (int) (d / units_NmToFeetFactor)); VGetStrokeString(u->v, xp + u->indicator.a.x, yp + u->indicator.a.y, u->radarImage, &u->radarImageCount, s, strlen(s), rfth); /* * Altitude of target */ xp = XB * slot_size / RADAR_WINDOW_WIDTH; yp = rfth + 4; sprintf(s, "%d", (int) (units_METERStoFEET(ptbl[i].w.z) / 1000.0)); VGetStrokeString(u->v, xp + u->indicator.a.x, yp + u->indicator.a.y, u->radarImage, &u->radarImageCount, s, strlen(s), rfth); sprintf(c->rightHUD[0], "R_+__"); sprintf(c->rightHUD[1], "%05.1f", d / units_NmToFeetFactor); sprintf(c->rightHUD[2], " %4.4d", (int) (cl / units_NmToFeetFactor * 3600.0)); } static double radarFrameInterval(craft * c) { double dt = 1.0; switch (c->radarMode) { case RM_OFF: case RM_STANDBY: dt = 1.0; break; case RM_NORMAL: dt = 1.0; break; case RM_STT: dt = 1.0; break; } return dt; } /** * Add information about a target that this aircraft's radar can "see". */ static void addRadarInfo(craft * emitter, craft * target, double d) { if (emitter->rtop < 16) { emitter->rinfo[emitter->rtop].rel = emitter->relPos[target->pIndex]; emitter->rinfo[emitter->rtop].d = d; emitter->rinfo[emitter->rtop].targetID = target->pIndex; emitter->rinfo[emitter->rtop].beamID = 0; emitter->rinfo[emitter->rtop].locked = 0; ++emitter->rtop; } } /** * Compute the radar energy arriving at the target and if the target is visible. * @param emitter Emitter aircraft. * @param target Possible target. * @param XYZtoRadar Rotation from geocentric to radar system. * @param el_ratio Emitter beam, tangent of the half sweep angle height. * @param az_ratio Emitter beam, tangent of the half sweep angle width. * @param energy Emitter energy irradiated in the sweep cone (W). */ static void computeRadarEnergy(craft * emitter, craft * target, VMatrix * XYZtoRadar, double el_ratio, double az_ratio, double energy) { VPoint r1; double xs, ys, d; /* * Calculate the coordinates of the target relative to the craft's frame * and the position of the radar search volume. */ r1.x = units_METERStoFEET(target->Sg.x - emitter->Sg.x); r1.y = units_METERStoFEET(target->Sg.y - emitter->Sg.y); r1.z = units_METERStoFEET(target->Sg.z - emitter->Sg.z); VTransform(&r1, XYZtoRadar, &emitter->relPos[target->pIndex]); target->rval[emitter->pIndex] = 0.0; if (emitter->relPos[target->pIndex].x <= 0.0) return; xs = emitter->relPos[target->pIndex].y / emitter->relPos[target->pIndex].x; ys = emitter->relPos[target->pIndex].z / emitter->relPos[target->pIndex].x; /* * If the target is inside the radiation cone, then we are painting this target * with radar energy. Estimate the value of the energy that the target sees. */ if ((fabs(xs) <= az_ratio) && (fabs(ys) <= el_ratio)) { d = VMagnitude(&emitter->relPos[target->pIndex]); target->rval[emitter->pIndex] = energy / (4.0 * M_PI * d * d); /* * Can we detect that ? */ /* return_energy = target->rval[emitter->pIndex] / (4.0 * M_PI * d * d); */ /* * Lookdown? */ if (ys > 0.0) { d *= 4.0 / 3.0; } /* * Reject targets that would not appear on our radar set */ /* * Not a DIS platform? */ if (target->cinfo->entityType.kind != DISKindPlatform) { return; } /* * Ground-based entity? Ignore it. */ if (target->cinfo->entityType.kind == DISKindPlatform && target->cinfo->entityType.domain == DISDomainLand) { return; } /* * For now, compute radar visibility based on fixed ranges. A better * solution would include factoring estimated target radar cross sections, * antenna size and radar set sensitivity. Wow. Where would you get that * sort of information? */ if (d >= emitter->cinfo->radarDRange) { return; } else if (d >= emitter->cinfo->radarTRange) { addRadarInfo(emitter, target, d); return; } else { addRadarInfo(emitter, target, d); return; } } else { return; } } void radar_calculateEmissions(craft * emitter) { VMatrix m1; register int i, j, target_idx; double el_center, az_center, el_width, az_width, el_ratio, az_ratio, e; craft *target; /* Reset no. of possible targets the emitter can see: */ emitter->rtop = 0; /* Reset energy the emitter puts on each other player: */ for (i = 0; i < manifest_MAXPLAYERS; ++i) { ptbl[i].rval[emitter->pIndex] = 0.0; } /* * Check if this emitter actually... emits anything! (save time otherwise). * - CT_DIS_PLANE may emit, but must ask to dis_if for emission PDU. * - CT_DIS_STEALTH I don't know what is it, but it was here in the original * code. FIXME: check if CT_DIS_STEALTH does really emits radar beam. * - CT_DRONE are always attacking! * - CT_PLANE only if radar on. */ if ( !( emitter->type == CT_DIS_PLANE || emitter->type == CT_DIS_STEALTH || emitter->type == CT_DRONE || ( /* local plane with radar turned on: */ emitter->type == CT_PLANE && (emitter->radarMode & (RM_NORMAL | RM_ACM | RM_STT)) ) )) { return; } /* Ask dis_if how many radar beams emits (always max 1 for ACM entities): */ i = dis_if_getBeamCount(emitter); /* * For each beam, compute: * 1. How much energy the emitter puts on each other player. * 2. Which other player the emitter can see. */ for (j = 0; j < i; ++j) { dis_if_getRadarParameters(emitter, j, &az_center, &az_width, &el_center, &el_width, &e); /* * In the original ACM program, the dis_if.c module sets the full sweep angles * and uses degrees for them; in this version we fixed that and we set the * half angle in radiants. For compatibility with the original program any * angle greater than 89*M_PI/180 RAD is assumed using the original values: */ if( az_width <= 89*M_PI/180 && el_width <= 89*M_PI/180 ){ az_ratio = tan(az_width); el_ratio = tan(el_width); } else { az_ratio = tan(units_DEGtoRAD(az_width/2)); el_ratio = tan(units_DEGtoRAD(el_width/2)); } /* * Note: the energy value returned by DIS for EM emissions is in units of * dBm. e_dBm = 10.0 * log10 (e_watts / 0.001). * * Sooo, to convert to watts, we'd do this: * * e_watts = 1000.0 * exp10(e_dBm / 10.0); */ /* * "Transmission Test Procedures for DIS Compliance: Distributed Emission * Regeneration Protocol Family" says that the elevation value is * up-positive, and azimuth is left-positive; units in radians (!) */ GenerateWorldToRadarMatrix(emitter, &m1, el_center, az_center); for (target = ptbl, target_idx = 0; target_idx < manifest_MAXPLAYERS; ++target_idx, ++target) { if (target->type == CT_FREE || target->type == CT_DIS_STEALTH || emitter == target) continue; computeRadarEnergy(emitter, target, &m1, el_ratio, az_ratio, e); } } } void radar_update(craft * c, viewer * u) { register radarInfo *p; Alib_Window *w; int i, x, y, j = -1, state; int xc, yc; double xs, ys, dmax; char *buf; Alib_Segment *seg; int primary = 0; _BOOL time_up = FALSE; Alib_Rect rect; if ( (c->radarMode & (RM_NORMAL | RM_ACM | RM_STT )) == 0 ) return; rftw = (int) (0.025 * RectWidth(u->indicator) + 0.5); rfth = (int) (1.3 * rftw + 0.5); slot_size = RectWidth(u->indicator); w = u->w; Alib_setClipRect(w, &u->indicator); /* * Compute radar emissions */ seg = u->radarImage; /* * Are we ready to give the pilot the next frame ? If not, mark the * radar display as an "Unchanged" area, and return. */ if (curTime >= c->nextRadarTime) { time_up = TRUE; } /* * If we fall through to here, then a redraw is required. * There are four possible scenarios: * * 1) The frame redraw timer has expired. * An entire radar frame, including target information, * must be generated and displayed. A logical copy * of the image is saved for possible future use. * * 2) The frame redraw timer has not expired, but some * external event has triggered a frame redraw (e.g. * the window was uncovered after being hidden). * In this case, the frame is redrawn from the * information used to generate the last frame. * * 3) The frame redraw timer has not expired, but * the user changed radar modes. In this case, we should * redraw just the legend information (i.e. no targets), * save a copy of what was drawn, and reset the frame * timer. * * 4) If none of the first three cases are true, then simply * mark the screen region associated with the radar display * as unchanged, and return. */ state = 4; if (time_up) { state = 1; } else { if (c->flags & FL_RADAR_MODE_CHANGE) { state = 3; } } /* * Case 4; nothing interesting happens. Mark the display as unchanged */ if (state == 4) { /**** FIXME This code should prevent the updating of the screen area, but it does not work because it erases the slot to its right (gear+flap) for some obscure reason, probably a bug in V/SLDiff.c. Skip and continue with the regular redraw. ZInfo z; z.depth = --w->depth; z.color = UnchangedColor; AlibFillRectangle(u->w, &rect, UnchangedColor); return; ****/ state = 1; /* full redraw */ } c->flags &= ~FL_RADAR_MODE_CHANGE; if (state == 2) { Alib_fillRect(w, &rect, panelBackgroundColor); VDrawSegments(u->v, u->radarImage, u->radarImageCount, radarColor); if (tgt_valid) { Alib_fillPolygon(u->w, tgt, 4, radarColor); } return; } tgt_valid = FALSE; /* * Verify that the current target is still visible. */ if (c->curRadarTarget != -1) { for (i = 0, p = c->rinfo; i < c->rtop; ++i, ++p) { if (c->curRadarTarget == p->targetID) { p->locked = 1; j = i; break; } } if (j == -1) { c->curRadarTarget = -1; dis_if_radarTargetChanged(c); } } /* * Go find the closest radar return ... that becomes our victim. */ if (state == 1) { dmax = 1000.0 * units_NmToFeetFactor; if (c->curRadarTarget == -1) { for (i = 0, p = c->rinfo, j = -1; i < c->rtop; ++i, ++p) { if (p->d < dmax) { dmax = p->d; j = i; } } if (j != -1) { c->curRadarTarget = c->rinfo[j].targetID; c->rinfo[j].locked = 1; dis_if_radarTargetChanged(c); sounds_playSound(c, sounds_APGLockAcquired, FALSE); } } } xc = (slot_size + 1) / 2; yc = (slot_size + 1) / 2; /* * Fill background */ Alib_fillRect(w, &u->indicator, panelBackgroundColor); /* * Draw reference "thing" and the border */ u->radarImageCount = 0; SetSegment(seg[u->radarImageCount], xc, yc, xc - 5, yc + 5); u->radarImageCount++; SetSegment(seg[u->radarImageCount], xc - 10, yc, xc - 5, yc + 5); u->radarImageCount++; SetSegment(seg[u->radarImageCount], xc - 10, yc, xc - 18, yc); u->radarImageCount++; SetSegment(seg[u->radarImageCount], xc, yc, xc + 5, yc + 5); u->radarImageCount++; SetSegment(seg[u->radarImageCount], xc + 10, yc, xc + 5, yc + 5); u->radarImageCount++; SetSegment(seg[u->radarImageCount], xc + 10, yc, xc + 18, yc); u->radarImageCount++; /* * Radar dead? */ if (damage_isFunctioning(c, SYS_RADAR) == 0) { Alib_drawSegments(w, seg, u->radarImageCount, radarColor); return; } /* * Radar off? */ if (c->radarMode <= RM_STANDBY) { if (c->radarMode == RM_OFF) buf = "RADAR OFF"; else buf = "RADAR STBY"; c->curRadarTarget = -1; VGetStrokeString(u->v, u->indicator.a.x + rftw * 4, u->indicator.a.y + rfth * 3, seg, &u->radarImageCount, buf, strlen(buf), rfth); return; } c->nextRadarTime = curTime + radarFrameInterval(c); /* * Show acm and stt HACK */ if (c->radarMode == RM_ACM) { buf = "ACM 20x30"; VGetStrokeString(u->v, u->indicator.a.x + rftw * 4, u->indicator.a.y + rfth * 3, seg, &u->radarImageCount, buf, strlen(buf), rfth); } else if (c->radarMode == RM_STT) { buf = "STT"; VGetStrokeString(u->v, u->indicator.a.x + rftw * 4, u->indicator.a.y + rfth * 3, seg, &u->radarImageCount, buf, strlen(buf), rfth); } /* * Plot reference lines */ i = (slot_size + 3) / 4; y = rfth + 3; SetSegment(seg[u->radarImageCount], xc, y, xc, y + 4); u->radarImageCount++; y = slot_size - 10 - rfth; SetSegment(seg[u->radarImageCount], xc, y, xc, y + 4); u->radarImageCount++; x = xc - i; y = rfth + 6; SetSegment(seg[u->radarImageCount], x, y, x, y + 4); u->radarImageCount++; y = slot_size - 10 - rfth; SetSegment(seg[u->radarImageCount], x, y, x, y + 4); u->radarImageCount++; VGetStrokeString(u->v, x - rftw + u->indicator.a.x, y + 6 + rfth + u->indicator.a.y, seg, &u->radarImageCount, thirty, 2, rfth); x = xc + i; y = rfth + 6; SetSegment(seg[u->radarImageCount], x, y, x, y + 4); u->radarImageCount++; y = slot_size - 10 - rfth; SetSegment(seg[u->radarImageCount], x, y, x, y + 4); u->radarImageCount++; VGetStrokeString(u->v, x - rftw + u->indicator.a.x, y + 6 + rfth + u->indicator.a.y, seg, &u->radarImageCount, thirty, 2, rfth); i = (slot_size + 3) / 4; x = 2; SetSegment(seg[u->radarImageCount], x, yc, x + 4, yc); u->radarImageCount++; x = slot_size - 6; SetSegment(seg[u->radarImageCount], x, yc, x + 4, yc); u->radarImageCount++; x = 5 + 2 * rftw; y = yc - i; SetSegment(seg[u->radarImageCount], x, y, x + 4, y); u->radarImageCount++; x = 3; VGetStrokeString(u->v, x + u->indicator.a.x, y + (rfth + 1) / 2 + u->indicator.a.y, seg, &u->radarImageCount, thirty, 2, rfth); x = slot_size - 6; SetSegment(seg[u->radarImageCount], x, y, x + 4, y); u->radarImageCount++; x = 5 + 2 * rftw; y = yc + i; SetSegment(seg[u->radarImageCount], x, y, x + 4, y); u->radarImageCount++; x = 3; VGetStrokeString(u->v, x + u->indicator.a.x, y + (rfth + 1) / 2 + u->indicator.a.y, seg, &u->radarImageCount, thirty, 2, rfth); x = slot_size - 6; SetSegment(seg[u->radarImageCount], x, y, x + 4, y); u->radarImageCount++; /* * If the user was simply changing radar modes skip looking * for new targets .. */ if (state != 3) { /* * Now plot all targets visible to the radar system. */ /* * Scan the radar information table and plot targets */ for (i = 0, p = c->rinfo; i < c->rtop; ++i, ++p) { if (p->rel.x >= 0.0) { xs = p->rel.y / (p->rel.x * scanSlope); ys = p->rel.z / (p->rel.x * scanSlope); if (fabs(xs) <= 1.0 && fabs(ys) <= 1.0) { x = (int) (xs * (double) xc + xc); y = (int) (ys * (double) yc + yc); if (p->locked) { plotPrimaryTarget(c, u, p->targetID, x, y); primary = 1; } else { plotNormalTarget(u, x, y); } } } } } if (primary == 0) { strcpy(c->rightHUD[0], "R_+__"); strcpy(c->rightHUD[1], ""); strcpy(c->rightHUD[2], ""); } Alib_drawSegments(w, u->radarImage, u->radarImageCount, radarColor); return; } /* * Get a new radar target. */ int radar_getNewTarget(craft * c) { int i, j = -1; radarInfo *p; if (c->curRadarTarget == -1) { return -1; } /* * Locate the locked target in the list of visible targets. */ for (i = 0, p = c->rinfo; i < c->rtop; ++i, ++p) { if (c->curRadarTarget == p->targetID) { j = i; p->locked = 0; break; } } if (j == -1) { return -1; } ++j; i = (j == c->rtop) ? 0 : j; c->rinfo[i].locked = 1; return c->rinfo[i].targetID; } void radar_updateTEWS(craft * c, viewer * u) { Alib_Window *w; int i, x, y, hostile_found = 0; VPoint rel, tmp; double r, r1, m, unit, xo, yo; draw_Type *dd; if ( (c->radarMode & (RM_STANDBY | RM_NORMAL | RM_ACM | RM_STT)) == 0 && c->radarMode != RM_OFF ) return; slot_size = RectWidth(u->indicator); w = u->v->w; Alib_setClipRect(w, &u->tuner); Alib_fillRect(w, &u->tuner, panelBackgroundColor); if ( c->radarMode == RM_OFF ) return; r = 0.45 * slot_size; r1 = 0.06 * r; xo = u->tuner.a.x + 0.5*slot_size; yo = u->tuner.a.y + 0.5*slot_size; dd = draw_new(); draw_circle(dd, xo, yo, r); if( damage_isFunctioning(c, SYS_TEWS) ){ for (i = 0; i < manifest_MAXPLAYERS; ++i) { if (ptbl[i].type == CT_FREE || c->pIndex == i) continue; if (c->rval[i] > c->cinfo->TEWSThreshold) { VTransform(&ptbl[i].Sg, &c->XYZtoNED, &tmp); VReverseTransform_(&tmp, &c->trihedral, &rel); m = 1.0/VMagnitude(&rel); rel.x *= m; rel.y *= m; rel.z *= m; unit = sqrt(rel.x * rel.x + rel.y * rel.y); if (unit == 0.0) { rel.x = 1.0; rel.y = 0.0; } x = (int) (xo + (int) (rel.y / unit * r * 0.7)); y = (int) (yo - (int) (rel.x / unit * r * 0.7)); if (c->force == ptbl[i].force) { draw_circle(dd, x, y, r1); } else { // Draw filled circle: //draw_Type *ee; //ee = draw_new(); //draw_circle(ee, x, y, r1); //draw_fill(ee, u->v, HUDPixel); //draw_free(ee); /* FIXME: draw_fill() does not actually fill! */ /* Workaround: draw 3 concentric circles (close enough!): */ draw_circle(dd, x, y, r1); draw_circle(dd, x, y, 0.66*r1); draw_circle(dd, x, y, 0.33*r1); hostile_found = 1; } } } if (c->vl == u && hostile_found == 1) { sounds_playSound(c, sounds_LockWarning, FALSE); } } draw_stroke(dd, u->v, HUDColor); draw_free(dd); } void radar_droneUpdate(craft * c) { int i, j = -1; radarInfo *p; double dmax = 500.0 * units_NmToFeetFactor; VPoint tmp, rel, deltaV; /* * Go find the closest radar return ... that becomes our victim. */ if (c->curRadarTarget == -1) { for (i = 0, p = c->rinfo; i < c->rtop; ++i, ++p) { if (ptbl[p->targetID].force != c->force && p->d < dmax) { dmax = p->d; j = i; } } c->curRadarTarget = j; dis_if_radarTargetChanged(c); } /* * Is the current radar target still visible to the radar set? */ else { for (i = 0, p = c->rinfo; i < c->rtop; ++i, ++p) { if (c->curRadarTarget == p->targetID) { j = i; } } if (j == -1) { c->curRadarTarget = -1; dis_if_radarTargetChanged(c); } } /* * Compute tracking parameters */ if ((i = c->curRadarTarget) != -1) { tmp.x = units_METERStoFEET(ptbl[i].Sg.x - c->Sg.x); tmp.y = units_METERStoFEET(ptbl[i].Sg.y - c->Sg.y); tmp.z = units_METERStoFEET(ptbl[i].Sg.z - c->Sg.z); VTransform_(&tmp, &c->XYZtoNED, &rel); deltaV.x = ptbl[i].Cg.x - c->Cg.x; deltaV.y = ptbl[i].Cg.y - c->Cg.y; deltaV.z = ptbl[i].Cg.z - c->Cg.z; c->targetDistance = VMagnitude(&rel); c->targetClosure = -(deltaV.x * rel.x + deltaV.y * rel.y + deltaV.z + rel.z) / c->targetDistance; } } void radar_setMode(craft * c, int mode) { int dis_mode; switch (mode) { case RM_OFF: dis_mode = 0; break; case RM_STANDBY: dis_mode = 0; break; case RM_NORMAL: dis_mode = 1; break; case RM_ACM: dis_mode = 2; break; case RM_STT: dis_mode = 3; break; case RM_HSI: case RM_ADF: case RM_DIS_BROWSE: dis_mode = 0; break; default: error_internal("invalid mode %d", mode); } if( dis_mode == 0 ){ c->rightHUD[0][0] = '\0'; c->rightHUD[1][0] = '\0'; c->rightHUD[2][0] = '\0'; } else { strcpy(c->rightHUD[0], "R_+__"); c->rightHUD[1][0] = '\0'; c->rightHUD[2][0] = '\0'; } c->radarMode = mode; c->nextRadarTime = curTime + radarFrameInterval(c); c->flags |= FL_RADAR_MODE_CHANGE; c->curRadarTarget = -1; dis_if_setRadarMode(c, dis_mode, 1); } acm-6.0_20200416/src/acm/joystick.c0000644000000000000000000002523213154073366015141 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #define joystick_IMPORT #include "joystick.h" #ifdef WINNT // No joystick support under Win32. Provides dummy functions instead. void joystick_setPort(char * name){} void joystick_calibrate(void){} void joystick_getPosition(double *x1, double *y1, double *x2, double *y2, int *switches) { *x1 = *y1 = *x2 = *y2 = 0.0; *switches = 0; } int joystick_processInput(void) { return -1; } #else #include #include #include #include #include static int min[4] = {999, 999, 999, 999}; static int max[4] = {-1, -1, -1, -1}; static int home[4]; static int value[5] = {128, 128, 128, 128, 0}; static char *joystick_port = NULL; void joystick_setPort (char * name) { joystick_port = name; } /* * ProcessJoystickInput() * * This procedure should be called just before you call GetJoystickInput(). * In processes any pending input from the Workstation Gameport. */ static int init = 0, state; int joystick_processInput() { static int fd; static int x1, y1, x2, y2, switches; int flags, n, i, updated = 0; unsigned char bytes[512], *p; if (init < 0) { return init; } else if (init == 0) { struct termios term; init = -1; if (!joystick_port) { return init; } if ((fd = open(joystick_port, O_RDWR)) < 0) { perror("joystick port open failed"); return -1; } /* * Set POSIX non-blocking I/O */ if ((flags = fcntl(fd, F_GETFL, 0)) == -1) { perror("F_GETFL failed"); return -1; } if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) { perror("F_SETFL failed"); return -1; } /* * Assert both DTR and RTS (these pins supply power to * the Workstation Gameport). */ #ifdef TIOCM_RTS flags = TIOCM_RTS | TIOCM_DTR; if (ioctl(fd, TIOCMSET, &flags) == -1) { perror("ioctl failed"); return -1; } #endif /* * Condition the TTY line to talk to the converter */ if (tcgetattr(fd, &term) != 0) { perror("tcgetattr failed"); return -1; } term.c_iflag = IGNBRK | IGNPAR; term.c_oflag = 0; term.c_cflag = CLOCAL | CS8 | CSTOPB | CREAD; term.c_lflag &= ~(ECHO | ICANON); for (i = 0; i < NCCS; ++i) { term.c_cc[i] = -1; } term.c_cc[VMIN] = 1; term.c_cc[VTIME] = 0; cfsetospeed(&term, B9600); cfsetispeed(&term, B9600); if (tcsetattr(fd, TCSAFLUSH, &term) != 0) { perror("tcsetattr failed"); return -1; } state = 0; init = 1; } /* * Read a whole bunch of characters from the tty */ n = read(fd, bytes, sizeof bytes); if (n != -1) { printf("%d ->", n); for (state = 0; state < n; state++) printf(" %d", bytes[state]); printf("\n"); } /* * And then process them ... */ for (p = bytes; n > 0; --n) { switch (state) { case 0: if ((*p & 0x80) != 0) { switches = (((int) *p) >> 3) & 0x0F; x1 = (((int) *p) & 0x07) << 5; state = 1; } break; case 1: if ((*p & 0x80) != 0) { state = 0; break; } x1 += (((int) *p) >> 2) & 0x1F; y1 = (((int) *p) & 0x03) << 6; state = 2; break; case 2: if ((*p & 0x80) != 0) { state = 0; break; } y1 += (((int) *p) >> 1) & 0x3F; x2 = (((int) *p) & 0x01) << 7; state = 3; break; case 3: if ((*p & 0x80) != 0) { state = 0; break; } x2 += ((int) *p) & 0x7F; state = 4; break; case 4: if ((*p & 0x80) != 0) { state = 0; break; } y2 = ((int) *p) << 1; state = 5; break; case 5: if ((*p & 0x80) != 0) { state = 0; break; } y2 += ((int) *p) & 0x01; value[0] = 255 - x1; value[1] = 255 - y1; value[2] = x2; value[3] = y2; value[4] = switches; state = 0; updated = 1; // printf("%d %d %d -> %d %d\n", switches, x1, y1, x2, y2); break; } ++p; } return updated; } void joystick_calibrate() { int i; printf("\n\nCenter the joystick, click when ready!\n\n"); for (;;) if (joystick_processInput()) if (value[4] != 0) break; for (i = 0; i < 4; i++) home[i] = value[i]; for (;;) if (joystick_processInput()) if (value[4] == 0) break; printf("\n\nPosition stick in minimum and maximum values, then click\n\n"); for (;;) { if (joystick_processInput()) { for (i = 0; i < 4; i++) { if (value[i] < min[i]) min[i] = value[i]; if (value[i] > max[i]) max[i] = value[i]; } if (value[4] != 0) break; } } for (;;) if (joystick_processInput()) if (value[4] == 0) break; printf("\n\nJoystick Calibrated\n"); } static double fixJoy(int i) { // Forward joysticks. if (min[i] < max[i]) { if (value[i] <= home[i]) return (double) (value[i] - min[i]) / (double)(home[i] - min[i]) - 1.0; else return (double) (value[i] - home[i]) / (double)(max[i] - home[i]); } // Backwards joysticks. else if (value[i] >= home[i]) return ((double)(min[i] - value[i]) / (double)(min[i] - home[i]) - 1.0); else return ((double)(home[i] - value[i]) / (double)(home[i] - max[i])); } void joystick_getPosition(double *x1, double *y1, double *x2, double *y2, int *switches) { if (min[0] == 999) { *x1 = 0.0; *y1 = 0.0; *x2 = 0.0; *y2 = 0.0; *switches = value[4]; return; } *x1 = fixJoy(0); if (*x1 < -1.0) *x1 = -1.0; *y1 = fixJoy(1); if (*y1 < -1.0) *y1 = -1.0; *x2 = fixJoy(2); if (*x2 < -1.0) *x2 = -1.0; *y2 = fixJoy(3); if (*y2 < -1.0) *y2 = -1.0; *switches = value[4]; } #endif /* * 2017-03-20 Umberto Salsi: * The source code below for Colorado Spectrum Workstation Gameport(TM) was * in the "joystick-cms.c" but apparently not used. Save here just in case. */ #ifdef ___________NOT__USED______________ /* * Colorado Spectrum Workstation Gameport(TM) * * Interface Notes by Riley Rainey (rainey@netcom.com) * * The Colorado Spectrum Workstation Gameport allows you to connect * a PC joystick to a serial port on your Unix workstation. It presents * a DB-9 plug that can be attached directly into any system that has a * PC-style 9 pin serial port. I created a simple adapter cable to convert a * Sparc IPX DIN-8 serial connector to the 9-pin that this unit requires. * * The Workstation Gameport costs about $100. * Colorado Spectrum accepts credit card phone orders: +1 (970) 225-6929 * * The workstation gameport emits asynchronous six byte sequences * up to 30 times per second. If the state of switches and joystick pots * does not change, no packet is emitted. The data rate is 9600 bps; * eight data bits and two stop bits. * * Byte Contents * ---- ---------------------------------------------- * 0 Sync Byte (always zero) * 1 Switches (J2s2, J2s1, J1s2, J1s1, 0, 0, 0, 0) * 2 J1x * 3 J1y * 4 J2x * 5 J2y * * The driver (this module) must ensure that both DTR and RTS * are raised to supply power to the joystick adapter. */ #include #include #include #include #include static int max[4] = {255, 255, 255, 255}; static int home[4] = {128, 128, 128, 128}; static int value[5] = {128, 128, 128, 128, 0}; static char *joystick_port = NULL; void joystick_setPort(char *name) { joystick_port = name; } void joystick_calibrate(void) { int i; for (i = 0; i < 4; ++i) { home[i] = value[i]; } } void joystick_getPosition(double *x1, double *y1, double *x2, double *y2, int *switches) { *x1 = (double) (value[0] - home[0]) / (max[0] - home[0]); if (*x1 < -1.0) { *x1 = -1.0; } *y1 = (double) (value[1] - home[1]) / (max[1] - home[1]); if (*y1 < -1.0) { *y1 = -1.0; } *x2 = (double) (value[2] - home[2]) / (max[2] - home[2]); if (*x2 < -1.0) { *x2 = -1.0; } *y2 = (double) (value[3] - home[3]) / (max[3] - home[3]); if (*y2 < -1.0) { *y2 = -1.0; } *switches = value[4]; } /* * ProcessJoystickInput() * * This procedure should be called just before you call GetJoystickInput(). * In processes any pending input from the Workstation Gameport. */ static int init = 0, state; int joystick_processInput(void) { static int fd; static int x1, y1, x2, switches; int flags, n, i, updated = 0; unsigned char bytes[512], *p; if (init < 0) { return init; } else if (init == 0) { struct termios term; init = -1; if (!joystick_port) { return init; } if ((fd = open(joystick_port, O_RDWR)) < 0) { perror("joystick port open failed"); return -1; } /* * Set POSIX non-blocking I/O */ if ((flags = fcntl(fd, F_GETFL, 0)) == -1) { perror("F_GETFL failed"); return -1; } if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) { perror("F_SETFL failed"); return -1; } /* * Assert both DTR and RTS (these pins supply power to * the Workstation Gameport). */ #ifdef TIOCM_RTS flags = TIOCM_RTS | TIOCM_DTR; if (ioctl(fd, TIOCMSET, &flags) == -1) { perror("ioctl failed"); return -1; } #endif /* * Condition the TTY line to talk to the converter */ if (tcgetattr(fd, &term) != 0) { perror("tcgetattr failed"); return -1; } term.c_iflag = IGNBRK | IGNPAR; term.c_oflag = 0; term.c_cflag = CLOCAL | CS8 | CSTOPB | CREAD; term.c_lflag &= ~(ECHO | ICANON); for (i = 0; i < NCCS; ++i) { term.c_cc[i] = -1; } term.c_cc[VMIN] = 1; term.c_cc[VTIME] = 0; cfsetospeed(&term, B9600); cfsetispeed(&term, B9600); if (tcsetattr(fd, TCSAFLUSH, &term) != 0) { perror("tcsetattr failed"); return -1; } state = 0; init = 1; } /* * Read a whole bunch of characters from the tty */ n = read(fd, bytes, sizeof bytes); /* * And then process them ... */ for (p = bytes; n > 0; --n) { switch (state) { case 0: if (*p == 0) { state = 1; } break; case 1: if ((*p & 0x0f) == 0 || 1) { switches = *p >> 4; state = 2; } else { state = 0; } break; case 2: x1 = *p; state = 3; break; case 3: y1 = *p; state = 4; break; case 4: x2 = *p; state = 5; break; case 5: state = 0; value[0] = x1; value[1] = y1; value[2] = x2; value[3] = *p; value[4] = switches; updated = 1; break; } ++p; } return updated; } #endif /* ___NOT__USED___ */acm-6.0_20200416/src/acm/Makefile0000644000000000000000000005115113173127313014566 0ustar rootroot# This file generated by make-makefile, do not edit! # Create Makefile-include.txt instead for your customizations. CC := gcc CFLAGS := -Wall -Werror -g -fmax-errors=99 -Wuninitialized -Wmissing-prototypes -Wredundant-decls LIBS := .PHONY: all all: make acm.exe adf.o aim120.o aim9m.o air.o alarm.o aps.o astro.o box.o browse.o ccip.o commands.o damage.o dis_if.o draw.o drone.o effects.o events.o flaps.o gear.o hsi.o hud.o init.o instruments.o interpolate.o inventory.o joystick.o list.o m61a1.o magnetic_compass.o manifest.o missile.o mouse.o navaid.o panel.o patchlevel.o place.o planes.o players.o pm.o prompt.o radar.o render.o runway.o scale.o sounds.o terminal.o terrain.o update.o viewer.o vpath.o vpath_gallery.o weapon.o weapon_null.o windows.o zone.o zones.o include Makefile-include.txt .PHONY: test test: acm.exe ./acm.exe .PHONY: clean clean: rm -f *.o *.exe *.stackdump acm acm.o: acm.c ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/disx.h ../dis/dis/earth.h ../util/error.h ../util/gui.h ../util/memory.h ../util/reader.h ../util/units.h ../util/varray.h air.h box.h damage.h dis_if.h drone.h effects.h gear.h init.h interpolate.h inventory.h joystick.h list.h m61a1.h manifest.h mouse.h patchlevel.h players.h pm.h render.h scale.h update.h weapon.h zone.h zones.h $(CC) $(CFLAGS) -c acm.c -o acm.o acm.exe: ../V/Alib.o ../V/VColor.o ../V/VGlyph.o ../V/VObjects.o ../V/VPoly.o ../V/VRoman.o ../V/Vlib.o ../V/Vlibmath.o ../dis/dis/datum.o ../dis/dis/dis.o ../dis/dis/disx.o ../dis/dis/earth.o ../dis/dis/xdr.o ../dis/dis/xdr_dis.o ../util/audio.o ../util/error.o ../util/gui.o ../util/memory.o ../util/prng.o ../util/reader.o ../util/sparsearray.o ../util/timer.o ../util/units.o ../util/varray.o ../util/wav.o ../util/zulu.o ../wmm/Geomagnetism.o ../wmm/wmm.o acm.o adf.o aim120.o aim9m.o air.o alarm.o aps.o astro.o box.o browse.o ccip.o commands.o damage.o dis_if.o draw.o drone.o effects.o events.o flaps.o gear.o hsi.o hud.o init.o instruments.o interpolate.o inventory.o joystick.o list.o m61a1.o magnetic_compass.o manifest.o missile.o mouse.o navaid.o panel.o patchlevel.o place.o planes.o players.o pm.o prompt.o radar.o render.o runway.o scale.o sounds.o terminal.o terrain.o update.o viewer.o vpath.o vpath_gallery.o weapon.o weapon_null.o windows.o zone.o zones.o $(CC) $(CFLAGS) -o acm.exe ../V/Alib.o ../V/VColor.o ../V/VGlyph.o ../V/VObjects.o ../V/VPoly.o ../V/VRoman.o ../V/Vlib.o ../V/Vlibmath.o ../dis/dis/datum.o ../dis/dis/dis.o ../dis/dis/disx.o ../dis/dis/earth.o ../dis/dis/xdr.o ../dis/dis/xdr_dis.o ../util/audio.o ../util/error.o ../util/gui.o ../util/memory.o ../util/prng.o ../util/reader.o ../util/sparsearray.o ../util/timer.o ../util/units.o ../util/varray.o ../util/wav.o ../util/zulu.o ../wmm/Geomagnetism.o ../wmm/wmm.o acm.o adf.o aim120.o aim9m.o air.o alarm.o aps.o astro.o box.o browse.o ccip.o commands.o damage.o dis_if.o draw.o drone.o effects.o events.o flaps.o gear.o hsi.o hud.o init.o instruments.o interpolate.o inventory.o joystick.o list.o m61a1.o magnetic_compass.o manifest.o missile.o mouse.o navaid.o panel.o patchlevel.o place.o planes.o players.o pm.o prompt.o radar.o render.o runway.o scale.o sounds.o terminal.o terrain.o update.o viewer.o vpath.o vpath_gallery.o weapon.o weapon_null.o windows.o zone.o zones.o $(LIBS) -lm adf.o: adf.c adf.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/gui.h ../util/memory.h ../util/units.h air.h interpolate.h inventory.h manifest.h navaid.h pm.h scale.h vpath.h vpath_gallery.h zone.h zones.h $(CC) $(CFLAGS) -c adf.c -o adf.o aim120.o: aim120.c aim120.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/gui.h ../util/memory.h ../util/units.h air.h gear.h init.h interpolate.h inventory.h manifest.h missile.h pm.h scale.h sounds.h weapon.h zone.h zones.h $(CC) $(CFLAGS) -c aim120.c -o aim120.o aim9m.o: aim9m.c aim9m.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/gui.h ../util/memory.h ../util/units.h air.h gear.h init.h interpolate.h inventory.h manifest.h missile.h pm.h scale.h sounds.h weapon.h zone.h zones.h $(CC) $(CFLAGS) -c aim9m.c -o aim9m.o air.o: air.c air.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/gui.h ../util/prng.h ../util/units.h interpolate.h inventory.h manifest.h pm.h scale.h zone.h zones.h $(CC) $(CFLAGS) -c air.c -o air.o alarm.o: alarm.c alarm.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/gui.h ../util/memory.h ../util/units.h air.h interpolate.h inventory.h manifest.h pm.h scale.h zone.h zones.h $(CC) $(CFLAGS) -c alarm.c -o alarm.o aps.o: aps.c aps.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/gui.h ../util/memory.h ../util/units.h air.h flaps.h gear.h hsi.h interpolate.h inventory.h manifest.h pm.h scale.h terrain.h zone.h zones.h $(CC) $(CFLAGS) -c aps.c -o aps.o astro.o: astro.c astro.h ../V/Vlibmath.h ../util/error.h ../util/memory.h ../util/zulu.h $(CC) $(CFLAGS) -c astro.c -o astro.o box.o: box.c box.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/error.h ../util/gui.h ../util/memory.h ../util/units.h air.h interpolate.h inventory.h manifest.h planes.h pm.h scale.h zone.h zones.h $(CC) $(CFLAGS) -c box.c -o box.o browse.o: browse.c browse.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/disx.h ../dis/dis/earth.h ../util/gui.h ../util/units.h ../util/varray.h air.h box.h damage.h dis_if.h drone.h interpolate.h inventory.h joystick.h manifest.h pm.h render.h scale.h zone.h zones.h $(CC) $(CFLAGS) -c browse.c -o browse.o ccip.o: ccip.c ccip.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/disx.h ../dis/dis/earth.h ../util/gui.h ../util/memory.h ../util/units.h ../util/varray.h air.h damage.h dis_if.h draw.h effects.h gear.h init.h interpolate.h inventory.h manifest.h pm.h scale.h terrain.h weapon.h zone.h zones.h $(CC) $(CFLAGS) -c ccip.c -o ccip.o commands.o: commands.c commands.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/gui.h ../util/units.h air.h interpolate.h inventory.h list.h manifest.h players.h pm.h scale.h terminal.h zone.h zones.h $(CC) $(CFLAGS) -c commands.c -o commands.o damage.o: damage.c damage.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/gui.h ../util/prng.h ../util/units.h air.h interpolate.h inventory.h manifest.h pm.h scale.h sounds.h zone.h zones.h $(CC) $(CFLAGS) -c damage.c -o damage.o dis_if.o: dis_if.c dis_if.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/datum.h ../dis/dis/dis.h ../dis/dis/disx.h ../dis/dis/earth.h ../util/error.h ../util/gui.h ../util/memory.h ../util/prng.h ../util/units.h ../util/varray.h air.h interpolate.h inventory.h manifest.h pm.h scale.h update.h zone.h zones.h $(CC) $(CFLAGS) -c dis_if.c -o dis_if.o draw.o: draw.c draw.h ../V/Alib.h ../V/VColor.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../util/gui.h ../util/memory.h ../util/units.h $(CC) $(CFLAGS) -c draw.c -o draw.o drone.o: drone.c drone.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/disx.h ../dis/dis/earth.h ../util/error.h ../util/gui.h ../util/memory.h ../util/prng.h ../util/units.h ../util/varray.h air.h alarm.h aps.h browse.h dis_if.h flaps.h gear.h interpolate.h inventory.h list.h manifest.h players.h pm.h prompt.h radar.h scale.h weapon.h zone.h zones.h $(CC) $(CFLAGS) -c drone.c -o drone.o effects.o: effects.c effects.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/gui.h ../util/memory.h ../util/prng.h ../util/units.h air.h interpolate.h inventory.h manifest.h pm.h scale.h zone.h zones.h $(CC) $(CFLAGS) -c effects.c -o effects.o events.o: events.c events.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/disx.h ../dis/dis/earth.h ../util/error.h ../util/gui.h ../util/units.h ../util/varray.h adf.h air.h aps.h box.h browse.h commands.h dis_if.h drone.h flaps.h gear.h hsi.h hud.h instruments.h interpolate.h inventory.h joystick.h manifest.h mouse.h pm.h prompt.h radar.h render.h scale.h sounds.h terminal.h weapon.h windows.h zone.h zones.h $(CC) $(CFLAGS) -c events.c -o events.o flaps.o: flaps.c flaps.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/gui.h ../util/units.h air.h damage.h interpolate.h inventory.h manifest.h pm.h scale.h zone.h zones.h $(CC) $(CFLAGS) -c flaps.c -o flaps.o gear.o: gear.c gear.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/error.h ../util/gui.h ../util/memory.h ../util/units.h air.h damage.h interpolate.h inventory.h manifest.h pm.h prompt.h scale.h sounds.h terrain.h zone.h zones.h $(CC) $(CFLAGS) -c gear.c -o gear.o hsi.o: hsi.c hsi.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/gui.h ../util/memory.h ../util/units.h air.h interpolate.h inventory.h manifest.h navaid.h pm.h scale.h vpath.h vpath_gallery.h zone.h zones.h $(CC) $(CFLAGS) -c hsi.c -o hsi.o hud.o: hud.c hud.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/gui.h ../util/memory.h ../util/units.h air.h aps.h damage.h draw.h interpolate.h inventory.h m61a1.h manifest.h pm.h scale.h vpath.h weapon.h zone.h zones.h $(CC) $(CFLAGS) -c hud.c -o hud.o init.o: init.c init.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/disx.h ../dis/dis/earth.h ../util/error.h ../util/gui.h ../util/memory.h ../util/units.h ../util/varray.h ../util/zulu.h ../wmm/wmm.h air.h alarm.h astro.h dis_if.h interpolate.h inventory.h manifest.h planes.h pm.h scale.h vpath.h vpath_gallery.h weapon.h zone.h zones.h $(CC) $(CFLAGS) -c init.c -o init.o instruments.o: instruments.c instruments.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/gui.h ../util/memory.h ../util/units.h air.h aps.h draw.h interpolate.h inventory.h manifest.h pm.h scale.h vpath.h zone.h zones.h $(CC) $(CFLAGS) -c instruments.c -o instruments.o interpolate.o: interpolate.c interpolate.h ../util/error.h ../util/memory.h $(CC) $(CFLAGS) -c interpolate.c -o interpolate.o inventory.o: inventory.c inventory.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/error.h ../util/gui.h ../util/memory.h ../util/reader.h ../util/units.h air.h init.h interpolate.h manifest.h planes.h pm.h scale.h weapon.h zone.h zones.h $(CC) $(CFLAGS) -c inventory.c -o inventory.o joystick.o: joystick.c joystick.h $(CC) $(CFLAGS) -c joystick.c -o joystick.o list.o: list.c list.h ../util/memory.h $(CC) $(CFLAGS) -c list.c -o list.o m61a1.o: m61a1.c m61a1.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/disx.h ../dis/dis/earth.h ../util/gui.h ../util/memory.h ../util/prng.h ../util/units.h ../util/varray.h air.h damage.h dis_if.h effects.h init.h interpolate.h inventory.h manifest.h pm.h scale.h sounds.h weapon.h zone.h zones.h $(CC) $(CFLAGS) -c m61a1.c -o m61a1.o magnetic_compass.o: magnetic_compass.c magnetic_compass.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/gui.h ../util/memory.h ../util/units.h air.h interpolate.h inventory.h manifest.h pm.h scale.h vpath.h zone.h zones.h $(CC) $(CFLAGS) -c magnetic_compass.c -o magnetic_compass.o manifest.o: manifest.c manifest.h ../util/units.h $(CC) $(CFLAGS) -c manifest.c -o manifest.o missile.o: missile.c missile.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/disx.h ../dis/dis/earth.h ../util/error.h ../util/gui.h ../util/memory.h ../util/units.h ../util/varray.h air.h damage.h dis_if.h effects.h interpolate.h inventory.h manifest.h planes.h pm.h scale.h terrain.h zone.h zones.h $(CC) $(CFLAGS) -c missile.c -o missile.o mouse.o: mouse.c mouse.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/gui.h ../util/units.h air.h events.h interpolate.h inventory.h joystick.h manifest.h pm.h scale.h zone.h zones.h $(CC) $(CFLAGS) -c mouse.c -o mouse.o navaid.o: navaid.c navaid.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/error.h ../util/gui.h ../util/memory.h ../util/units.h ../wmm/wmm.h air.h interpolate.h inventory.h manifest.h pm.h scale.h zone.h zones.h $(CC) $(CFLAGS) -c navaid.c -o navaid.o panel.o: panel.c panel.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/error.h ../util/gui.h ../util/memory.h ../util/units.h adf.h air.h aps.h damage.h draw.h gear.h hsi.h interpolate.h inventory.h manifest.h planes.h pm.h radar.h scale.h terrain.h vpath.h zone.h zones.h $(CC) $(CFLAGS) -c panel.c -o panel.o patchlevel.o: patchlevel.c patchlevel.h $(CC) $(CFLAGS) -c patchlevel.c -o patchlevel.o place.o: place.c place.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/gui.h ../util/units.h air.h interpolate.h inventory.h manifest.h pm.h scale.h zone.h zones.h $(CC) $(CFLAGS) -c place.c -o place.o planes.o: planes.c planes.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/error.h ../util/gui.h ../util/units.h air.h alarm.h damage.h gear.h interpolate.h inventory.h manifest.h pm.h scale.h terrain.h weapon.h zone.h zones.h $(CC) $(CFLAGS) -c planes.c -o planes.o players.o: players.c players.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/disx.h ../dis/dis/earth.h ../util/error.h ../util/gui.h ../util/memory.h ../util/units.h ../util/varray.h air.h box.h browse.h dis_if.h drone.h effects.h flaps.h gear.h hsi.h hud.h instruments.h interpolate.h inventory.h list.h magnetic_compass.h manifest.h patchlevel.h planes.h pm.h prompt.h render.h scale.h sounds.h terrain.h update.h viewer.h weapon.h windows.h zone.h zones.h $(CC) $(CFLAGS) -c players.c -o players.o pm.o: pm.c pm.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/disx.h ../dis/dis/earth.h ../util/gui.h ../util/memory.h ../util/units.h ../util/varray.h ../wmm/wmm.h air.h aps.h damage.h dis_if.h gear.h interpolate.h inventory.h manifest.h planes.h prompt.h scale.h terrain.h zone.h zones.h $(CC) $(CFLAGS) -c pm.c -o pm.o prompt.o: prompt.c prompt.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/disx.h ../dis/dis/earth.h ../util/gui.h ../util/memory.h ../util/prng.h ../util/units.h ../util/varray.h air.h dis_if.h init.h interpolate.h inventory.h list.h manifest.h patchlevel.h pm.h scale.h zone.h zones.h $(CC) $(CFLAGS) -c prompt.c -o prompt.o radar.o: radar.c radar.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/disx.h ../dis/dis/earth.h ../util/error.h ../util/gui.h ../util/units.h ../util/varray.h air.h damage.h dis_if.h draw.h interpolate.h inventory.h manifest.h pm.h scale.h sounds.h zone.h zones.h $(CC) $(CFLAGS) -c radar.c -o radar.o render.o: render.c render.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/disx.h ../dis/dis/earth.h ../util/gui.h ../util/memory.h ../util/units.h ../util/varray.h ../util/zulu.h air.h astro.h browse.h damage.h dis_if.h gear.h hud.h instruments.h interpolate.h inventory.h magnetic_compass.h manifest.h panel.h place.h pm.h prompt.h scale.h sounds.h terminal.h terrain.h zone.h zones.h $(CC) $(CFLAGS) -c render.c -o render.o runway.o: runway.c runway.h ../V/VColor.h ../V/VPoly.h ../V/Vlibmath.h ../util/memory.h ../util/units.h $(CC) $(CFLAGS) -c runway.c -o runway.o scale.o: scale.c scale.h ../V/Alib.h ../V/VColor.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../util/error.h ../util/gui.h ../util/units.h $(CC) $(CFLAGS) -c scale.c -o scale.o sounds.o: sounds.c sounds.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/audio.h ../util/error.h ../util/gui.h ../util/memory.h ../util/units.h air.h init.h interpolate.h inventory.h manifest.h pm.h scale.h zone.h zones.h $(CC) $(CFLAGS) -c sounds.c -o sounds.o terminal.o: terminal.c terminal.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/gui.h ../util/memory.h ../util/units.h air.h interpolate.h inventory.h manifest.h pm.h scale.h zone.h zones.h $(CC) $(CFLAGS) -c terminal.c -o terminal.o terrain.o: terrain.c terrain.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/gui.h ../util/units.h air.h interpolate.h inventory.h manifest.h pm.h scale.h zone.h zones.h $(CC) $(CFLAGS) -c terrain.c -o terrain.o update.o: update.c update.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/disx.h ../dis/dis/earth.h ../util/gui.h ../util/memory.h ../util/timer.h ../util/units.h ../util/varray.h air.h alarm.h box.h dis_if.h events.h interpolate.h inventory.h manifest.h pm.h prompt.h radar.h render.h scale.h zone.h zones.h $(CC) $(CFLAGS) -c update.c -o update.o viewer.o: viewer.c viewer.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/gui.h ../util/memory.h ../util/units.h air.h hsi.h hud.h instruments.h interpolate.h inventory.h magnetic_compass.h manifest.h pm.h prompt.h render.h scale.h terminal.h zone.h zones.h $(CC) $(CFLAGS) -c viewer.c -o viewer.o vpath.o: vpath.c vpath.h ../V/Alib.h ../V/VColor.h ../V/VGlyph.h ../V/VPoly.h ../V/VRoman.h ../V/Vlib.h ../V/Vlibmath.h ../util/gui.h ../util/memory.h ../util/units.h $(CC) $(CFLAGS) -c vpath.c -o vpath.o vpath_gallery.o: vpath_gallery.c vpath_gallery.h ../V/Alib.h ../V/VColor.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../util/gui.h ../util/memory.h ../util/units.h vpath.h $(CC) $(CFLAGS) -c vpath_gallery.c -o vpath_gallery.o weapon.o: weapon.c weapon.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/gui.h ../util/units.h aim120.h aim9m.h air.h ccip.h interpolate.h inventory.h m61a1.h manifest.h pm.h scale.h weapon_null.h zone.h zones.h $(CC) $(CFLAGS) -c weapon.c -o weapon.o weapon_null.o: weapon_null.c weapon_null.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/gui.h ../util/units.h air.h interpolate.h inventory.h manifest.h pm.h scale.h weapon.h zone.h zones.h $(CC) $(CFLAGS) -c weapon_null.c -o weapon_null.o windows.o: windows.c windows.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/gui.h ../util/units.h air.h hud.h instruments.h interpolate.h inventory.h manifest.h pm.h prompt.h scale.h zone.h zones.h $(CC) $(CFLAGS) -c windows.c -o windows.o zone.o: zone.c zone.h ../V/Alib.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlib.h ../V/Vlibmath.h ../dis/dis/dis.h ../dis/dis/earth.h ../util/error.h ../util/gui.h ../util/memory.h ../util/reader.h ../util/units.h air.h interpolate.h inventory.h manifest.h navaid.h pm.h runway.h scale.h zones.h $(CC) $(CFLAGS) -c zone.c -o zone.o zones.o: zones.c zones.h ../V/Vlibmath.h ../dis/dis/earth.h ../util/error.h ../util/memory.h ../util/reader.h zone.h $(CC) $(CFLAGS) -c zones.c -o zones.o # Checksum of the original file: 4005364219 acm-6.0_20200416/src/acm/manifest.c0000644000000000000000000000017413064346041015077 0ustar rootroot/* * Dummy empty implementation: this module only exports declarations. */ #define manifest_IMPORT #include "manifest.h" acm-6.0_20200416/src/acm/zones.c0000644000000000000000000001002313175057126014427 0ustar rootroot#include #include #include #include #include #include #include "../util/memory.h" #include "../util/error.h" #include "../util/reader.h" #include "zone.h" #define zones_IMPORT #include "zones.h" struct zones_Type { /** Path to the zones file. */ char *path; /* List of zones. */ int zones_capacity; int zones_length; zone_Type **zones; /** * Scheduled next update time (s). Ignore load requests since then to reduce * overload. */ time_t next_zone_update; }; static void zones_destruct(void *p) { //printf("DEBUG: %s\n", __FUNCTION__); zones_Type *this = (zones_Type *) p; while( this->zones_length > 0 ){ this->zones_length--; memory_dispose(this->zones[ this->zones_length ]); } memory_dispose(this->zones); memory_dispose(this->path); } static void zones_parseZone(zones_Type *this, reader_Type *in, char **argv, int argc) { if( argc != 5 ) error_external("%s:%d: expected 5 fields, found %d", reader_getPath(in), reader_getLineNumber(in), argv); double lat1, lat2, lon1, lon2; if( ! earth_parseLatitude(argv[0], &lat1) ) error_external("%s:%d: invalid latitude: %s", reader_getPath(in), reader_getLineNumber(in), argv[0]); if( ! earth_parseLatitude(argv[1], &lat2) ) error_external("%s:%d: invalid latitude: %s", reader_getPath(in), reader_getLineNumber(in), argv[1]); if( ! earth_parseLongitude(argv[2], &lon1) ) error_external("%s:%d: invalid longitude: %s", reader_getPath(in), reader_getLineNumber(in), argv[2]); if( ! earth_parseLongitude(argv[3], &lon2) ) error_external("%s:%d: invalid longitude: %s", reader_getPath(in), reader_getLineNumber(in), argv[3]); if( !(lat1 < lat2 && lon1 < lon2) ) error_external("%s:%d: check latitude and longitude ordering", reader_getPath(in), reader_getLineNumber(in)); // Check the scenery file is indeed there: char *path = reader_resolveRelativePath(reader_getPath(in), argv[4]); if( ! reader_isReadable(path) ) error_external("%s:%d: file %s does not exist or it is not readable", reader_getPath(in), reader_getLineNumber(in), path); // Create zone object: zone_Type *zone = zone_new(path, lat1, lat2, lon1, lon2); memory_dispose(path); // Check if this zone overlaps with any other zone: int i; for(i = this->zones_length-1; i >= 0; i--){ if( zone_overlaps(zone, this->zones[i]) ) error_external("%s:%d: zone %s overlaps with zone %s", reader_getPath(in), reader_getLineNumber(in), zone_getPath(zone), zone_getPath(this->zones[i])); } // Ok, add this zone: if( this->zones_length >= this->zones_capacity ){ this->zones_capacity += 100; this->zones = memory_realloc(this->zones, this->zones_capacity * sizeof(zone_Type *)); } this->zones[this->zones_length++] = zone; } zones_Type * zones_new(char *path) { zones_Type * this = memory_allocate(sizeof(zones_Type), zones_destruct); this->path = memory_strdup(path); this->zones_capacity = 0; this->zones_length = 0; this->zones = NULL; this->next_zone_update = 0; reader_Type *in = reader_new(path); char line[999]; while( reader_getLine(in, line, sizeof(line)) ){ char *s = line; while( isspace(*s) ) s++; if( *s == 0 || *s == '#' ) continue; char *argv[5]; int argc; if( ! reader_split(line, &argc, argv, 5) ) error_external("%s:%d: too many fields", reader_getPath(in), reader_getLineNumber(in)); zones_parseZone(this, in, argv, argc); } if( reader_getError(in) != NULL ) error_external("%s: %s", reader_getPath(in), reader_getError(in)); memory_dispose(in); return this; } zone_Type * zones_load(zones_Type *this, earth_LatLonAlt *p, zone_Type *last_known, int forced) { time_t now = time(NULL); if( ! forced && now < this->next_zone_update ) return last_known; zone_Type *current_zone = NULL; this->next_zone_update = now + 10; int i; for( i = this->zones_length - 1; i >= 0; i--){ zone_Type *zone = this->zones[i]; if( zone_isClose(zone, p) ){ zone_load(zone); if( zone_includesLocation(zone, p) ) current_zone = zone; } else { zone_purge(zone, 0); } } return current_zone; } acm-6.0_20200416/src/acm/astro.h0000644000000000000000000000253413173767747014455 0ustar rootroot/** * Astronomical calculations. Currently, only the Earth position is calculated. * The ACM program needs to know the position of the Sun to determinate the * general brightness of the scene and to provide a further reference to * pilots flying VFR. * The returned values have been verified to be accurate within 0.1 DEG of * latitude and 0.2 DEG of longitude (the apparent diameter of the Sun being * only 0.5 DEG). * * @file * @author Umberto Salsi * @version $Date: 2017/10/25 01:59:03 $ */ #ifndef ASTRO_H #define ASTRO_H #include "../V/Vlibmath.h" #include "../util/zulu.h" #ifdef astro_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Initializes the module, and set the current position and rotation of the Earth * in the Universe. * @param simulation_time Simulation time (s). * @param departure The state of the Earth is set at the specified date and time. */ EXTERN void astro_init(double simulation_time, zulu_Date *departure); /** * Returns the current position of the Sun. Calculated values are cached and * a new position is calculated only from time to time. * @param simulation_time Simulation time (s). * @param sun Here returns the current position of the Sun in the Earth geodetic * reference (m). */ EXTERN void astro_getSun(double simulation_time, VPoint *sun); #undef EXTERN #endif acm-6.0_20200416/src/acm/aim9m.c0000644000000000000000000001331013172240620014275 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1994,1997 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include #include "pm.h" #include "init.h" #include "inventory.h" #include "missile.h" #include "../util/memory.h" #include "weapon.h" #include "sounds.h" #include "gear.h" #define aim9m_IMPORT #include "aim9m.h" static int select_aim9m(craft *); static int display_aim9m(craft *, craftType *, viewer *, int, int); static int update_aim9m(craft *); static int fire_aim9m(craft *); static weapon_Type aim9mDesc = { select_aim9m, /* select */ update_aim9m, /* update */ display_aim9m, /* display procedure */ fire_aim9m, /* fire */ (int (*)(craft *)) NULL, /* fire button release */ }; static int hasFired[manifest_MAXPLAYERS]; static int count[manifest_MAXPLAYERS]; /* * AIM-9M selection function * * A selection function normally determines whether there are any weapons * of this type on-board. If so, and the weapon system is functional * (in other words, undamaged) then return 1; otherwise return 0. */ static int select_aim9m(craft * c) { hasFired[c->pIndex] = 0; count[c->pIndex] = weapon_countOrdinance(c, weapon_AIM9M); return 1; } static int update_aim9m(craft * c) { int i; if( ! hasFired[c->pIndex] ) return 1; hasFired[c->pIndex] = 0; /* reset fire request */ /* * Missile won't fire if we have "Weight on wheels" * or if we run out of ammunition. */ if( gear_someWheelGroundContact(c) || count[c->pIndex] <= 0 ) return 1; /* Get station from which to launch the missile: */ i = weapon_getReadyStation(c, weapon_AIM9M); if (i < 0){ fprintf(stderr, "Oops. Can't find an AIM-9\n"); return 1; } /* * Decrement missiles counter. * In arcade mode, we never run out of ammunition */ if (arcadeMode == 0) { c->station[i].id = -1; count[c->pIndex]--; } /* Launch missile from station i: */ missile_fire(c, i); sounds_playSound(c, sounds_MissileLaunch, FALSE); return 1; } static int fire_aim9m(craft * c) { hasFired[c->pIndex] = 1; return 1; } /* * AIM-9M display function * * Update the HUD display strings associated with this weapon system. * c = the aircraft. * w = the missile's description record. * dummy1, dummy2 = ignored, not set. * * This code may be called by drones, so the viewer may be NULL. * * Return a nonzero value if have a reasonable chance of scoring a kill. */ static int display_aim9m(craft * c, craftType * w, viewer * unused, int dummy1, int dummy2) { char s[16]; double d, a1, v, r, root1, root2, n, t; VPoint tmp; int target; sprintf(s, "%d %s", count[c->pIndex], weapon_idToName(weapon_AIM9M)); strcpy(c->leftHUD[3], s); /* * Compute time to target t. Gives < 0.0 if no target available or not * reachable. */ v = VMagnitude(&c->Cg); a1 = (w->maxThrust - 0.5 * c->air.rho * w->CDOrigin * v * v) / (w->emptyWeight + w->maxFuel) * units_earth_g; if (c->curRadarTarget >= 0 && a1 >= 0.0) { d = c->targetDistance; r = c->targetClosure; n = r * r + 2.0 * a1 * d; if (n > 0) { n = sqrt(n); root1 = (-r + n) / a1; root2 = (-r - n) / a1; if (root1 >= 0.0) if (root2 >= 0.0) if (root1 < root2) t = root1; else t = root2; else t = root1; else if (root2 >= 0.0) t = root2; else t = -1.0; } else t = -1.0; } else t = -1.0; /* * See if the missiles can lock onto any target. We'll constrain missile_getIRTarget() * so that it will only select target's in a twenty degree boresight cone. */ if (count[c->pIndex] > 0) { target = missile_getIRTarget(c, &tmp, 0.17633); } else { target = -1; } /* * Update HUD display strings. */ if (t < 0.0) sprintf(s, "ARM --"); else if (target >= 0 && t >= (w->armDelay + 0.5) && t <= 15.0) sprintf(s, "LOCKED %d", (int) (t + 0.5)); else if (t <= 15.0) sprintf(s, "IN RANGE %d", (int) (t + 0.5)); else sprintf(s, "ARM %d", (int) (t + 0.5)); strcpy(c->leftHUD[2], s); strcpy(c->leftHUD[4], ""); /* * Return TRUE if we are recommending a missile shot. */ return target >= 0 && t >= (w->armDelay + 0.5) && t <= 10.0; } weapon_Type * aim9m_new(void) { craftType *c; FILE *f; dis_entity_type em1 = {2, 1, 225, 1, 1, 3, 0}; dis_entity_type em2 = {2, 1, 222, 1, 2, 1, 0}; c = inventory_craftTypeNew(NULL); c->name = memory_strdup( weapon_idToName(weapon_AIM9M) ); c->entityType = em1; c->altEntityType = em2; aim9mDesc.w = c; c->CDOrigin = 0.04; /* 5" radius of body */ c->CDFactor = -2.56694; c->CDBOrigin = 0.0; c->CDBFactor = 0.0; VIdentMatrix(&(c->I)); c->I.m[0][0] = 0.0; c->I.m[1][1] = 0.0; c->I.m[2][2] = 0.0; c->cmSlope = -1.88; c->wingS = 1.0; /* * Assume 150.0 lb of weight is fuel and that it burns for about 4 seconds. * That yields a fuel burn rate of 40 lb/s. */ c->emptyWeight = 90.0; c->maxFuel = 100.0; c->maxThrust = 4000.0; c->spFuelConsump = 40; /* * Three second arming delay */ c->armDelay = 1.0; f = init_fopen("missiles/aim9.obv", "r"); c->object = VReadObject(f); fclose(f); return &aim9mDesc; } acm-6.0_20200416/src/acm/weapon_null.c0000644000000000000000000000407513064342172015621 0ustar rootroot/* * acm : an aerial combat simulator for X * Null weapon module. * Copyright (C) 2009 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include "pm.h" #define weapon_null_IMPORT #include "weapon_null.h" static int select_null(craft * c) { return 1; } static int update_null(craft * c) { return 1; } static int fire_null(craft * c) { return 1; } /* * Display function * * Update the HUD display strings associated with this weapon system. * c = the aircraft. * w = the weapon's description record. * fpm_x, fpm_y = position of the FPM in HUD * * This code may be called by drones. Return a nonzero value if * have a reasonable chance of scoring a kill. */ static int display_null(craft * c, craftType * w, viewer * u, int fpm_x, int fpm_y) { /* HUD strings c->leftHUD[2, ..., 5] are reserved to the currently selected weapon. (leftHUD[1] is the Mach number, */ strcpy(c->leftHUD[2], ""); /* shot hint */ strcpy(c->leftHUD[3], ""); /* weapon name */ strcpy(c->leftHUD[4], ""); /* "FIRING", ecc. */ strcpy(c->leftHUD[5], ""); /* ??? */ /* Return TRUE if we are recommending a weapon shot. */ return 0; } static weapon_Type nullDesc = { select_null, /* select */ update_null, /* update */ display_null, /* display procedure */ fire_null, /* fire */ (int (*)(craft *)) NULL, /* fire button release */ }; weapon_Type * weapon_null_new(void) { nullDesc.w = NULL; return &nullDesc; } acm-6.0_20200416/src/acm/prompt.c0000644000000000000000000001232713173127674014627 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 2007 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include "../util/memory.h" #include "../util/prng.h" #include "dis_if.h" #include "init.h" #include "list.h" #include "pm.h" #include "patchlevel.h" #define prompt_IMPORT #include "prompt.h" /** Clear current msg after ... (s). */ #define EXPIRE_PERIOD 7.0 /** DIS status feedback period (s) */ #define DIS_FEEDBACK_PERIOD 25.0 /** if no msgs to show, show an hint after ... (s). */ #define HINT_PERIOD 30.0 static list_Type *hints; #define BUF_SIZE 100 typedef struct prompt_Line { struct prompt_Line *next; _BOOL have_msg; double expire; char buf[BUF_SIZE]; double last_msg_shown_at; } prompt_Line; static prompt_Line *free_list = NULL; void prompt_free(viewer *u) { prompt_Line *pd; if( u->prompt == NULL ) return; pd = u->prompt; pd->next = free_list; free_list = pd; u->prompt = NULL; } static void prompt_cleanup() { prompt_Line *pd; while( free_list != NULL ){ pd = free_list; free_list = pd->next; memory_dispose(pd); } memory_dispose(hints); hints = NULL; } static int isSpace(int c) { return c == ' ' || c == '\t' || c == '\r' || c == '\n'; } /** * Reads list of hints messages from the objects/hints.txt file. * Empty lines an lines starting with '#' are ignored. */ static void prompt_read_hints() { char line[999]; int s_len; char *s; if( hints != NULL ) return; memory_registerCleanup(prompt_cleanup); FILE *f = init_fopen("hints.txt", "r"); hints = list_new(); while( fgets(line, sizeof(line), f) != NULL ){ s = line; // Skip leading spaces: while( isSpace(*s) ) s++; // Ignore empty and comment line: if( *s == '#' || *s == '\0' ) continue; // Remove trailing spaces: s_len = strlen(s); while(s_len > 0 && isSpace(s[s_len-1])) s_len--; s[s_len] = '\0'; // Ok, add line: list_add_elem(hints, s); } fclose(f); } void prompt_viewer_print(viewer *u, char *s) { prompt_Line *pd; if( u->prompt == NULL ){ if( free_list == NULL ){ pd = memory_allocate( sizeof(prompt_Line), NULL ); memory_registerCleanup(prompt_cleanup); } else { pd = free_list; free_list = pd->next; } pd->next = NULL; pd->have_msg = FALSE; pd->expire = 0.0; pd->buf[0] = '\0'; pd->last_msg_shown_at = -HINT_PERIOD; /* next msg shown immediately */ u->prompt = pd; } else { pd = u->prompt; } pd->expire = curTime + EXPIRE_PERIOD; memory_strcpy(pd->buf, sizeof(pd->buf), s); pd->have_msg = TRUE; } void prompt_craft_print(craft *c, char *s) { viewer *v; v = vl_head; while( v != NULL ){ if( v->c == c ) prompt_viewer_print(v, s); v = v->next; } } void prompt_broadcast_print(char *s) { viewer *v; v = vl_head; while( v != NULL ){ prompt_viewer_print(v, s); v = v->next; } } static void draw_string(Viewport *v, prompt_Line *pd) { double fh, fw, w, k; int width, height, l, x, y; width = RectWidth(v->rect); height = RectHeight(v->rect); fh = ceil(height / 30.0); fw = VFontWidthPixels(v, (int) (fh+0.5)); l = strlen(pd->buf); k = l * fw / (0.95*width); if( k >= 1.0 ){ fh = floor(fh/k); fw = VFontWidthPixels(v, (int) (fh+0.5)); } w = fw * l; Alib_setClipRect(v->w, &v->rect); x = v->rect.a.x + width/2 - w/2.0; y = v->rect.b.y - fh; VDrawStrokeString(v, x + 1, y, pd->buf, l, fh, blackColor); VDrawStrokeString(v, x, y, pd->buf, l, fh, whiteColor); } void prompt_draw(viewer *u) { prompt_Line *pd; int n, i; if( u->prompt == NULL ){ prompt_viewer_print(u, "**** Welcome to ACM-" patchlevel_REVISION_STRING " ****"); return; } pd = u->prompt; /* * Avoid to distract the maneuvering pilot with silly messages: */ if( fabs(u->c->G.x) + fabs(u->c->G.y) + fabs(u->c->G.z + 1) > 0.2 ) pd->last_msg_shown_at = curTime + HINT_PERIOD; if( pd->have_msg ){ /* * Draw current msg: */ if( curTime > pd->expire ){ pd->have_msg = FALSE; pd->last_msg_shown_at = curTime; return; } draw_string(u->v, pd); } else if( dis_if_readyToReceive() && pd->last_msg_shown_at + DIS_FEEDBACK_PERIOD < curTime ) { /* * Show DIS protocol health state: */ char s[100]; snprintf(s, sizeof(s), "DIS: %d remote entities, %.1f incoming packets/s", dis_if_getNumberOfRemoteEntities(), dis_if_getProcessedPacketsPerSecond()); prompt_viewer_print(u, s); } else if( pd->last_msg_shown_at + HINT_PERIOD < curTime ){ /* * Chose another hint: */ if( hints == NULL ) prompt_read_hints(); n = hints->n; if( n > 0 ){ i = prng_getIntInRange(0, n - 1); prompt_viewer_print(u, hints->arr[i]); } } } /* End of the prompt module. */ acm-6.0_20200416/src/acm/list.c0000644000000000000000000000141413064345463014251 0ustar rootroot#include #include "../util/memory.h" #define list_IMPORT #include "list.h" static void list_destruct(void *p) { list_Type *l = p; int i; if( l == NULL ) return; for( i = l->n-1; i >=0; i-- ) memory_dispose(l->arr[i]); memory_dispose(l->arr); } list_Type * list_new() { list_Type *l; l = memory_allocate(sizeof( list_Type ), list_destruct); l->size = 0; l->n = 0; l->arr = NULL; return l; } void list_add_elem(list_Type *l, char *s) { if( l->n >= l->size ){ l->size = l->size * 2 + 50; l->arr = memory_realloc(l->arr, l->size * sizeof(char *)); } l->arr[ l->n++ ] = memory_strdup(s); } void list_add_list(list_Type *l, list_Type *q) { int i; if( q == NULL ) return; for( i = 0; i < q->n; i++ ) list_add_elem(l, q->arr[i]); } acm-6.0_20200416/src/acm/adf.h0000644000000000000000000000447313063670321014036 0ustar rootroot/* * acm : an aerial combat simulator for X * Module implementing the ADF indicator. * * Copyright (C) 2007 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #ifndef _adf_h #define _adf_h #include "pm.h" #ifdef adf_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Allocates and enables the ADF for this particular viewer. * If u->adf is NULL, instantiate with a pointer to internal data. */ EXTERN void adf_enable(viewer *u); /** * Disables and releases the ADF for this particular viewer, leaving u->adf set * to NULL, or does nothing if already NULL. */ EXTERN void adf_disable(viewer *u); /** * Increments station frequency. ADF channels ranges from 200 up to 415 KHz. * Implements an auto-repeat detection feature that speeds-up this otherwise * very slow interface. If the auto-repeat gets detected, the increment actually * applied gets multiplied by a factor that ranges from 2 up to 20. * @param u * @param step Either +1 or -1. */ EXTERN void adf_frq_inc(viewer *u, int step); /** * Increment heading pointer by 'step' DEG. * Implements an auto-repeat detection feature that speeds-up this otherwise * very slow interface. If the auto-repeat gets detected, the increment actually * applied gets multiplied by a factor that ranges from 2 up to 20. * @param u * @param step Either +1 or -1. */ EXTERN void adf_hdg_inc(viewer *u, int step); /** * Draws the ADF instrument in the TEWS panel. If no ADF active in this viewer, * does nothing. * @param u */ EXTERN void adf_panel_draw(viewer * u); /** * Draws the ADF compass card and OBS pointer. If no ADF active in this viewer, * does nothing. * @param u */ EXTERN void adf_draw(viewer * u); #undef EXTERN #endif acm-6.0_20200416/src/acm/Makefile-include.txt0000644000000000000000000000046513153616756017043 0ustar rootroot# OS specific compilation options: ifeq ($(OS),Windows_NT) CC = c:/mingw/bin/gcc CFLAGS += -mconsole -mwindows LIBS += -lws2_32 -lwinmm else UNAME_S := $(shell uname -s) ifeq ($(UNAME_S),Linux) CFLAGS += LIBS += -lX11 -lasound -pthread else CFLAGS += LIBS += -lX11 -lasound -pthread endif endifacm-6.0_20200416/src/acm/aim120.h0000644000000000000000000000177513063670321014277 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #ifndef _aim120_h #define _aim120_h #include "weapon.h" #ifdef aim120_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Creates weapon description record for the AIM-120 missile. */ EXTERN weapon_Type * aim120_new(void); #undef EXTERN #endif acm-6.0_20200416/src/acm/interpolate.c0000644000000000000000000000413613070371207015620 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991,1992 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include "../util/memory.h" #include "../util/error.h" #define interpolate_IMPORT #include "interpolate.h" static void interpolate_destruct(void *p) { interpolate_Table *oldp = p; if ( oldp != NULL ) { memory_dispose(oldp->entry); } } interpolate_Table * interpolate_new(int size) { interpolate_Table *t = memory_allocate(sizeof(interpolate_Table), interpolate_destruct); t->entry = memory_allocate(size * sizeof(interpolate_Entry), NULL); return t; } double interpolate_value(interpolate_Table * table, double x) { int i, count = table->count; if ( ! (x >= table->minX && x <= table->entry[count - 1].x) ) { error_internal("interpolate(..., %g): value out of the range [%g,%g]\n", x, table->minX, table->entry[count - 1].x); } for (i = 0; i < count; ++i) { if (x <= table->entry[i].x) { return (table->entry[i].m * x + table->entry[i].b); } } /* should never reach this point */ error_internal("i=%d", i); } interpolate_Table * interpolate_clone (interpolate_Table *oldp) { interpolate_Table * newp; int i; if ( oldp == NULL ) return NULL; newp = memory_allocate(sizeof(interpolate_Table), interpolate_destruct); *newp = *oldp; newp->entry = memory_allocate(sizeof(interpolate_Entry) * (oldp->count), NULL); for (i=0; icount; ++i) { newp->entry[i] = oldp->entry[i]; } return newp; } acm-6.0_20200416/src/acm/viewer.c0000644000000000000000000000441513174072143014575 0ustar rootroot#include #include "hsi.h" #include "hud.h" #include "instruments.h" #include "magnetic_compass.h" #include "../util/memory.h" #include "pm.h" #include "prompt.h" #include "render.h" #include "terminal.h" #define viewer_IMPORT #include "viewer.h" viewer * viewer_new(craft * c) { viewer *v; v = (viewer *) memory_allocate(sizeof(viewer), NULL); memset(v, 0, sizeof(viewer)); v->vl_next = vl_head; vl_head = v; v->next = c->vl; c->vl = v; v->viewer_state = ViewerStateNormal; v->c = c; v->watchedCraft = NULL; v->hasFocus = FALSE; v->hasComm = TRUE; /* FIXME: to-do fields v->w = ...; v->v = ...; v->dpy = ...; v->win = ...; v->gc = ...; v->cn = ...; v->protocolsAtom = ...; v->deleteWindowAtom = ...; v->closedownAtom = ...; v->hud_yCenter = ... */ /* All the Rect, drawnItem and scale_Type fields are in charge of the layout manager (see "windows" module). */ v->zoom = 100; // 100% v->hud_mode = FALSE; /* FIXME: to-do v->xscaleFactor = ... v->yscaleFactor = ... v->z = v->rz = ... v->radarImage = ... v->radarImageCount = ... */ v->browseBase = 0; v->browseSelectedItem = -1; v->browseClickTime = 0; /* Set v->viewDirection and v->viewUp: */ render_setOutsideView(c, v, render_VIEW_FORWARD); v->hud = NULL; v->magnetic_compass = NULL; v->hsi = NULL; v->adf = NULL; v->sounds = NULL; v->inst = NULL; v->terminal = NULL; v->prompt = NULL; return v; } void viewer_free(viewer *v) { viewer *update_cur; craft *c; /* Release attached services: */ memory_dispose(v->sounds); hud_free(v); magnetic_compass_free(v); memory_dispose(v->adf); hsi_free(v); instruments_free(v); terminal_free(v); prompt_free(v); /* Close the window */ memory_dispose(v->v); memory_dispose(v->w); memory_dispose(v->gui); /* Remove this viewer from the craft's list of viewers: */ c = v->c; if( c->vl == v ){ c->vl = v->next; } else { update_cur = c->vl; while( update_cur->next != v ) update_cur = update_cur->next; update_cur->next = v->next; } /* Remove viewer from the list of viewers: */ if( vl_head == v ){ vl_head = v->vl_next; } else { update_cur = vl_head; while( update_cur->vl_next != v ) update_cur = update_cur->vl_next; update_cur->vl_next = v->vl_next; } memory_dispose(v); } acm-6.0_20200416/src/acm/terminal.h0000644000000000000000000000435213175040551015113 0ustar rootroot/* * acm - Virtual terminal * Copyright (C) 2007 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /* This module implements a textual terminal where commands from the users can be accepted and outputs can be displayed. Every terminal is attached to a viewer data structure. Mostly useful for debugging at run-time. */ #ifndef _terminal_h #define _terminal_h #include "pm.h" #ifdef terminal_IMPORT #define EXTERN #else #define EXTERN extern #endif /* Enable/ disable/ toggle the terminal. */ EXTERN void terminal_toggle(viewer *u); EXTERN void terminal_enable(viewer *u); EXTERN void terminal_disable(viewer *u); /* Return TRUE if the terminal is currently enabled */ EXTERN _BOOL terminal_enabled(viewer *u); /* Send this char to the terminal */ EXTERN void terminal_input_char(viewer *u, int ch); /* Return TRUE if a complete line of input from the terminal is available. The string is returned in the buffer s, s_len bytes long. */ EXTERN _BOOL terminal_read_string(viewer *u, char *s, int s_len); /* Send the string to the terminal. Recognized control codes are: NL \n, CR \r, HT \t, BS \010. Any other control char is ignored. Coded above 127 are displayed as "?". */ EXTERN void terminal_write(viewer *u, char *s); /* If the terminal is currently active, display its contents */ EXTERN void terminal_draw(viewer *u); /* Disable and release the internal memory for this terminal. Internal buffers are not actually released, as thay may be re-used next for a new terminal. To actually release the occupied memory the next function can be called. */ EXTERN void terminal_free(viewer *u); #undef EXTERN #endif acm-6.0_20200416/src/acm/browse.c0000644000000000000000000002603613173126614014602 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include #include #include "box.h" #include "damage.h" #include "dis_if.h" #include "drone.h" #include "inventory.h" #include "joystick.h" #include "pm.h" #include "render.h" #define browse_IMPORT #include "browse.h" #define MAX_MAPPED_STRING_LEN 20 #define MAX_POPUP_STRING_LEN 40 #define REF_X -1.3 #define REF_Y -1.1 /* There's a bug lurking here, but for now ... */ #ifdef WINNT #define SCALE_1 5.0 #else #define SCALE_1 7.0 #endif struct _dis_browse { char info[32]; dis_if_Entity *p; craftType *cinfo; /* craftType iff this an aircraft we can grab */ }; #define BROWSE_MAX 256 #define ITEM_LIMIT 5 #define LINE_SPACING 0.2 static struct _dis_browse browse_info[BROWSE_MAX]; static int bcount; /* * Generate the stealth browsing table from the current DIS * entity database */ static void buildBrowseInfoTable () { abort(); #ifdef xxxxxxxxxxxxxxxxxxxxxxxx dis_if_Entity * e = dis_if_getEntityTable(), *ep; long etop = dis_if_getEntityTop(); int i=0; craftType * cinfo; char *marker; ep = e; bcount = 0; /* * Update the list of entities we might be interested in following */ for (i = 0; i <= etop && bcount < BROWSE_MAX; ++i, ++ep) { if (ep->entityType.kind == DISKindPlatform && ep->entityType.domain == DISDomainAir) { browse_info[bcount].p = ep; /* * Was this an aircraft type defined in the inventory file? * If so, mark it as "flyable". */ cinfo = inventory_craftTypeSearchByEntityType( &ep->entityType ); if (cinfo && cinfo->CLift) { browse_info[bcount].cinfo = cinfo; marker = "* "; } else { browse_info[bcount].cinfo = NULL; marker = " "; } sprintf (browse_info[bcount].info, "%s%d,%d,%d", marker, ep->entityId.sim_id.site_id, ep->entityId.sim_id.application_id, ep->entityId.entity_id ); ++ bcount; } } #endif } #ifdef XXXXXXXXXXXXXXXXXXXXXXXXXXXXX /* * Display the stealth browser page in the MFD */ void browse_page(craft * c, viewer * u) { XSegment seg[2048], m_seg[256]; char buf[256]; int slot_size, m_i = 0, i = 0, xc, yc, h, x, y; int item_count; static Alib_ZInfo z, zm; double yy; if (c->radarMode != RM_DIS_BROWSE) return; z.depth = --u->v->w->depth; z.color = (Alib_Pixel) (u->v->w->pixel[panelBackgroundColor]); zm.depth = z.depth; zm.color = (Alib_Pixel) (u->v->w->pixel[magentaColor]); Alib_fillRectangle(u->v->w, &u->indicator, &z); slot_size = RectWidth(u->indicator); xc = u->indicator.a.x + (slot_size + 1) / 2; yc = u->indicator.a.y + (slot_size + 1) / 2; yy = 0.0; h = (int) (11.0 * u->xscaleFactor + 0.5); y = (int) ((REF_Y + yy) * u->v->Scale.y / (SCALE_1 * 4)); /* * Update the list of entities we might be interested in following */ buildBrowseInfoTable (); /* * display current DIS entity browsing page */ item_count = 0; for (i=u->browseBase; iv->Scale.x / (SCALE_1 * 4)); y = (int) ((REF_Y + yy) * u->v->Scale.y / (SCALE_1 * 4)); if (u->browseSelectedItem == i) { VDrawStrokeString(u->v, x + xc, y + yc, buf, strlen(buf), h, zm.color); } else { VDrawStrokeString(u->v, x + xc, y + yc, buf, strlen(buf), h, z.color); } yy += LINE_SPACING; } VSetClipRect(u->v, &u->indicator); VDrawSegments(u->v, m_seg, m_i, (Alib_Pixel) (u->v->w->pixel[magentaColor])); VDrawSegments(u->v, seg, i, (Alib_Pixel) (u->v->w->pixel[HUDPixel])); return; } #endif /* XXXXXXXXXXXXXXXXXX */ int browse_controlRequestCallback( dis_pdu *pdu, void *pu ) { abort(); #ifdef xxxxxxxxxxxxxxxxxxxxxxxxxxxx viewer *u = (viewer *) pu; dis_if_Entity *e, *ep; dis_simulation_addr my_addr; dis_entity_id new_entity_id; disx_ApplicationInfo *app; craft *c; if ( pdu->hdr.pdu_type == PDUTypeAcknowledge && pdu->acknowledge.resp_flag == 1) { /* * "take over the craft" * * alter the viewer entry to reflect that we've hijacked an aircraft * * alter the ptbl (craft) entry to reflect that this is now an aircraft * that we are responsible for modeling */ u->viewer_state = ViewerStateNormal; c = u->watchedCraft; u->watchedCraft = u->c; u->c = c; c->type = CT_PLANE; c->vl = u; c->radarMode = RM_STANDBY; /* * Until we can think of a better way to set fuel state, * damage bits, etc. this will have to suffice. */ (*c->cinfo->resupply) (c); /* FIXME: array 'entities' does not exist anymore */ ep = &entities[c->disId]; ep->entryType = dis_if_LOCAL; app = dis_if_getApplicationInfo(); disx_getSimulationAddress ( app, &my_addr ); /* SITE ID */ if ((transferEntityIdBits & 0x4)) { new_entity_id.sim_id.site_id = my_addr.site_id; } else { new_entity_id.sim_id.site_id = ep->entityId.sim_id.site_id; } /* APPLICATION ID */ if ((transferEntityIdBits & 0x2)) { new_entity_id.sim_id.application_id = my_addr.application_id; } else { new_entity_id.sim_id.application_id = ep->entityId.sim_id.application_id; } /* ENTITY ID */ if ((transferEntityIdBits & 0x1)) { /* Issue a new entity id (good within this application) */ dis_entity_id temp_id; disx_issueEntityID( app, &temp_id ); new_entity_id.entity_id = temp_id.entity_id; } else { /* use existing entity ID */ new_entity_id.entity_id = ep->entityId.entity_id; } /* TODO: check for collisions in entity table if mode wasn't 0, or 7 */ ep->entityId = new_entity_id; } /* * Transfer Control Request was rejected. Return to stealth state. */ else { u->viewer_state = ViewerStatePiggyback; XBell( u->dpy, 50 ); } return 0; #endif } int browse_stealthCraft( craft *c, viewer *u, int item, int take_control) { int i; /* * Locate the browse info entry that corresponds to the * designated craft. */ if ( item == -1 ) { buildBrowseInfoTable (); for(i=0; ic == c) { item = i; break; } } } /* follow that aircraft */ if ( item != -1 ) { u->browseSelectedItem = item; } else { u->browseSelectedItem = -1; } if ( end_game_mode && take_control && item != -1 ) { browse_info[item].p->c->flags |= FL_END_GAME_DRONE; u->viewer_state = ViewerStateControlPending; drone_endGameDistanceCheck(browse_info[item].p->c, u); } else { u->viewer_state = ViewerStatePiggyback; } u->watchedCraft = c; return 0; } #ifdef XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX int browse_keyEvent(craft * c, viewer * u, XEvent * ev, int player) { KeySym keysym; XComposeStatus compose; char buffer[MAX_MAPPED_STRING_LEN]; int buflen = MAX_MAPPED_STRING_LEN; (void) XLookupString((XKeyEvent *) ev, buffer, buflen, &keysym, &compose); if (player) { switch (keysym) { #ifdef sun case XK_R7: #else case XK_Home: #endif break; case XK_Prior: u->browseBase -= ITEM_LIMIT; if (u->browseBase < 0) { u->browseBase = 0; XBell ( u->dpy, 50 ); } break; case XK_Next: u->browseBase += ITEM_LIMIT; if (u->browseBase >= bcount) { u->browseBase = bcount - ITEM_LIMIT + 1; } if (u->browseBase < 0) { u->browseBase = 0; XBell ( u->dpy, 50 ); } break; #ifdef sun case XK_Up: #else case XK_KP_8: #endif render_setOutsideView(c, u, render_VIEW_FORWARD); break; /* look right */ #ifdef sun case XK_Right: #else case XK_KP_6: #endif render_setOutsideView(c, u, render_VIEW_RIGHT); break; /* look left */ #ifdef sun case XK_Left: #else case XK_KP_4: #endif render_setOutsideView(c, u, render_VIEW_LEFT); break; /* look back */ #ifdef sun case XK_Down: #else case XK_KP_2: #endif render_setOutsideView(c, u, render_VIEW_AFT); break; /* look up */ #ifdef sun case XK_R11: #else case XK_KP_5: #endif render_setOutsideView(c, u, render_VIEW_UP); break; case XK_N: case XK_n: c->flags ^= FL_CHASE_VIEW; break; #ifdef SPECIAL_KEYS case XK_o: if (! damage_absorbDamage(c, 3) == 0) { c->kill(c, "You asked to absorb some damage. The aircraft was destroyed. No further details are available."); return -1; } break; case XK_semicolon: debug ^= 1; break; #endif case XK_P: case XK_p: c->kill(c, "(FIXME)"); return -1; /*NOTREACHED */ break; case XK_braceleft: box_startRecording(); break; case XK_braceright: box_endRecording(); break; case XK_bracketleft: box_startPlayback(); break; case XK_k: case XK_K: joystick_calibrate(); break; } } return 0; } #endif /* XXXXXXXXXXXX */ void browse_selectCockpitItem( craft *c, viewer *u, int x, int y, unsigned long time ) { double dy, yscale; int slot_size, item; int yc; slot_size = RectWidth(u->indicator); yc = u->indicator.a.y + (slot_size + 1) / 2; yscale = (int) (u->v->Scale.y / (SCALE_1 * 4)); if (c->radarMode != RM_DIS_BROWSE) { return; } /* * Click on radar set? */ if (x > u->indicator.a.x && x < u->indicator.a.x + slot_size && y > u->indicator.a.y && y < u->indicator.a.y + slot_size) { /* get index of selected item */ dy = (y - yc) / yscale; dy -= REF_Y; item = (int) ( dy / LINE_SPACING ) + u->browseBase; if (item < bcount && item >= 0) { /* * Double-Click? Activate control request */ if (u->browseSelectedItem == item && time - u->browseClickTime < 500) { /* * We can only take control of aircraft that we have a * definition for. When that's the case for a given * entity, cinfo will be non-NULL. */ if (browse_info[item].cinfo) { /* * If we're in end-game mode, check for hostile * aircraft in our proximity. Calling * drone_endGameDistanceCheck once will cause it to be called * once per second. */ u->viewer_state = ViewerStateControlPending; if ( end_game_mode ) { browse_info[item].p->c->flags |= FL_END_GAME_DRONE; drone_endGameDistanceCheck(browse_info[item].p->c, u); } else { dis_if_requestControl ( browse_info[item].p, browse_controlRequestCallback, u ); } } else { //XBell( u->dpy, 50 ); } } else { browse_stealthCraft ( browse_info[item].p->c, u, item, 0 ); } } } u->browseClickTime = time; }acm-6.0_20200416/src/acm/sounds.c0000644000000000000000000001303213173130224014574 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1994 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include "pm.h" #include "init.h" #include "../util/error.h" #include "../util/memory.h" #include "../util/audio.h" #define sounds_IMPORT #include "sounds.h" // BEWARE: the index of this array must match the sounds_SoundID enum values. static char *files[] = { "sounds/DUMMY-ARRAY-ENTRY.wav", // never really loaded "sounds/generic-piston-engine.wav", "sounds/generic-jet-engine.wav", "sounds/generic-rocket-engine.wav", "sounds/crash.wav", "sounds/gear_up.wav", "sounds/gear_dn.wav", "sounds/missile.wav", "sounds/cannon.wav", "sounds/crash.wav", "sounds/screetch.wav", "sounds/warning.wav", "sounds/stall.wav", "sounds/rwr.wav", "sounds/apglock.wav" }; typedef struct { /** If sound playing is enabled (that is, not muted). */ int isEnabled; /** Engine sound ID. */ sounds_SoundID engine_sound; /** Cached loaded sounds. */ audio_Type *samples[sounds_NumberOfSounds]; } sounds_Type; /** * Returns the current instance of this module bound to the aircraft. * @param c * @return Current instance bound to the craft, or NULL if no current instance * exists or the aircraft has no viewer. */ static sounds_Type * sounds_getCurrentInstance(craft *c) { if( c->vl == NULL ) return NULL; return c->vl->sounds; } static audio_Type *sounds_loadAndCacheSample(sounds_Type *this, sounds_SoundID id) { if( !(0 <= id && id < sounds_NumberOfSounds) ) error_internal("sound ID out of the range: %d", id); if( this->samples[id] == NULL ){ this->samples[id] = audio_new( init_findFile(files[id]) ); } return this->samples[id]; } static void sounds_destruct(void *p) { sounds_Type *this = p; int i; for(i = 0; i < sounds_NumberOfSounds; i++) memory_dispose(this->samples[i]); } static sounds_Type * sounds_new(craft *c) { viewer *v = c->vl; if( v == NULL ) error_internal("no viewer associated to craft", 0); sounds_Type *this = memory_allocate(sizeof(sounds_Type), sounds_destruct); this->isEnabled = 0; switch(v->c->cinfo->engineType){ case inventory_NoEngine: this->engine_sound = sounds_None; break; case inventory_GenericPistonEngine: this->engine_sound = sounds_GenericPistonEngine; break; case inventory_GenericJetEngine: this->engine_sound = sounds_GenericJetEngine; break; case inventory_GenericRocketEngine: this->engine_sound = sounds_GenericRocketEngine; break; default: this->engine_sound = sounds_None; break; } int i; for (i = 0; i < sounds_NumberOfSounds; ++i) { // Sound samples are loaded only if needed: this->samples[i] = NULL; // ... but check all the sounds are there to avoid surprises later :-) if( i > 0 ) /* ignore = */ init_findFile( files[i] ); } // Avoid delay playing the "screech" sound at touchdown, cache right now: /* ignore = */ sounds_loadAndCacheSample(this, sounds_Touchdown); v->sounds = this; return this; } void sounds_enable(craft *c, int enable) { sounds_Type *this = sounds_getCurrentInstance(c); if( enable ){ if( this == NULL ) this = sounds_new(c); this->isEnabled = 1; } else { if( this == NULL || ! this->isEnabled ) return; this->isEnabled = 0; // Stop any sound we are currently playing: int i; for(i = sounds_NumberOfSounds-1; i >= 0; i--){ if( this->samples[i] != NULL ) sounds_stopSound(c, i); } } } int sounds_isEnabled(craft * c) { sounds_Type *this = sounds_getCurrentInstance(c); if( this == NULL ) return 0; else return this->isEnabled; } void sounds_playSound(craft * c, sounds_SoundID id, int loop) { sounds_Type *this = sounds_getCurrentInstance(c); if( this == NULL || ! this->isEnabled ) return; audio_Type *sample = sounds_loadAndCacheSample(this, id); if( ! loop && ! audio_isPlaying(sample) ) audio_setCurrentPositionMilliseconds(sample, 0); audio_loop(sample, loop); audio_play(sample); } void sounds_stopSound(craft * c, sounds_SoundID id) { if( !(0 <= id && id < sounds_NumberOfSounds) ) error_internal("sound ID out of the range: %d", id); sounds_Type *this = sounds_getCurrentInstance(c); if( this == NULL ) return; audio_Type *sample = this->samples[id]; if( sample == NULL ) return; audio_pause(sample); audio_setCurrentPositionMilliseconds(sample, 0); } void sounds_setBackgroundSound(craft * c, double rpm_rate, int afterburner, double dynamicPressure) { sounds_Type *this = sounds_getCurrentInstance(c); if( this == NULL ) return; if( this->engine_sound == sounds_None || ( ! this->isEnabled && this->samples[this->engine_sound] == NULL ) ) return; audio_Type *sample = sounds_loadAndCacheSample(this, this->engine_sound); if( ! this->isEnabled || rpm_rate < 0.1 ){ audio_pause(sample); } else { audio_setCurrentSamplesPerSecond(sample, rpm_rate * audio_getOriginalSamplesPerSecond(sample)); audio_loop(sample, 1); audio_play(sample); } } void sounds_update(craft * c) { } acm-6.0_20200416/src/acm/zone.h0000644000000000000000000001304613646045024014256 0ustar rootroot/** * The zone objects represents the contents of a cached scenery file. * * ZONE LOADING AND CACHING. * A zone can be loaded or not loaded. When loaded, all the items of the scenery * (runways, navigation aids, ILS, features, ...) are available to the program. * When not loaded, all these elements are removed from memory. * * The zones module uses zone objects to implement a scenery caching mechanism * where only the strictly needed sceneries are loaded in memory at any given * time based on the region each player (normally only one) is flying over; * nearby zone closer than 200 NM are loaded as well, so any tunable radio * station be available. * * INSIDE/OUTSIDE ZONE DEFINITION. * As items are loaded from the scenery file, a consistency check is performed * and the location (lat,lon) of each item is compared against the state range * of latitude and longitude; the item is indeed inside the zone only if: * * LAT_MIN ≤ lat < LAT_MAX and * LON_MIN ≤ lon < LON_MAX * * A non-fatal warning is sent on standard output if the location of the item * falls outside the range. Note that there is no way to include an item if it * is located exactly at the north pole; this does not seem to be a severe * limitation, though. For items located exactly on the 180E meridian, the * 180W can be indicated instead. * * - VOR, DME and NDB are inside if their location is in the range. * * - ILS are included based on the location of the LOCATOR antenna only; * the location of the associate GS and DME antennas do not matter. * * - Runways are included if their middle point lies in the range. * * Note that a runway may belong to the zone but its corresponding ILS be outside * or vice-versa; this is not a problem as soon as the nearby zone including the * missing item be available, as in this case ACM loads both the zones anyway as * the aircraft gets close to the edge or within 200 NM from it. * * SIDE EFFECTS OF THIS MODULE. * Several global data structures and modules are involved: * * - The list of surface objects, including runways and features is constantly * updated based on the sceneries currently loaded. This is the main task of * this module. * * - The list of NAVAIDs, including NDB, VOR and ILS, see the navaid module. * * - The list of "craft types" used to store airports informations, see the * inventory module. * * @file * @author Umberto Salsi * @version $Date: 2020/01/08 06:11:07 $ */ #ifndef ZONE_H #define ZONE_H #include "../dis/dis/earth.h" #ifdef zone_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * State of a zone. */ typedef struct zone_Type zone_Type; /** * Allocates a new zone. The initial status of the zone is "not loaded". * @param path Scenery file. * @param lat1 Minimum latitude covered by this scenery (included, RAD). * @param lat2 Maximum latitude covered by this scenery (excluded, RAD). * @param lon1 Minimum longitude covered by this scenery (included, RAD). * @param lon2 Maximum longitude covered by this scenery (excluded, RAD). * @return Allocated new zone. Must be released with memory_dispose(). */ EXTERN zone_Type * zone_new(char *path, double lat1, double lat2, double lon1, double lon2); /** * Tells if this zone is currently loaded, that is the scenery file has been * parsed and the items therein defined are available to the player. */ EXTERN int zone_isLoaded(zone_Type *this); /** * Returns the name of the file this zone has been (or might be) loaded from. */ EXTERN char * zone_getPath(zone_Type *this); /** * Returns the ground color name defined in the zone. Returns NULL if the zone * is not currently loaded. */ EXTERN char * zone_getGroundColor(zone_Type *this); /** * Returns the location of the force base. * @param this * @param force Force number, one of the DISForce enum constants. * @return Location of the force base if the zone is currently loaded and the * zone defines the requested team location; NULL otherwise. */ EXTERN earth_LatLonAlt * zone_getForceBaseLocation(zone_Type *this, int force); /** * Returns true if the zone includes the point. Points over and beyond the * maximum latitude and longitude are outside. */ EXTERN int zone_includesLocation(zone_Type *this, earth_LatLonAlt *w); /** * Returns true if the point p is flying over or it is close to the zone. * A point is close to this zone if it is inside or not farther than 4 DEG * from any of its borders; the test is implemented to be fast, not precise. * Altitude does not matter here. * @param this * @param p * @return True if close or inside the zone. */ EXTERN int zone_isClose(zone_Type *this, earth_LatLonAlt *p); /** * Returns true is the zones overlaps, that is they share at least one point. */ EXTERN int zone_overlaps(zone_Type *this, zone_Type *other); /** * Reads the scenery file and all the items therein defined. Recoverable errors * are sent to standard error; unrecoverable errors are fatal. The lists of * surface items, navaids and ILS are updated accordingly. If the zone is * already in its loaded status, simply postpones its expiry time. */ EXTERN void zone_load(zone_Type *this); /** * Purge items related to the zone.The lists of surface items, navaids and ILS * are purged accordingly. Does nothing if the zone is already in its "not * loaded" status or the expiry time is not elapsed. * @param this * @param forced If true, overrides the internal expiry time caching mechanism * and really purges all items. */ EXTERN void zone_purge(zone_Type *this, int forced); #undef EXTERN #endif acm-6.0_20200416/src/acm/init.c0000644000000000000000000001246113174072313014236 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include "../V/Vlib.h" #include "../util/error.h" #include "../util/memory.h" #include "../wmm/wmm.h" #include "alarm.h" #include "astro.h" #include "dis_if.h" #include "inventory.h" #include "planes.h" #include "pm.h" #include "vpath_gallery.h" #include "weapon.h" #define init_IMPORT #include "init.h" #ifdef WINNT #define SEPARATOR ";" #else #define SEPARATOR ":" #endif #define DEFAULT_OBJECT_DIRS \ "." \ SEPARATOR "objects" \ SEPARATOR "../objects" \ SEPARATOR "../../objects" static char ** objects_dirs = NULL; static void init_fileNotFoundError(char * path) { fprintf(stderr, "acm: file `%s' not found. Attempts made:\n", path); fprintf(stderr, " %s\n", path); char **p = objects_dirs; while ( *p != NULL ) { fprintf(stderr, " %s/%s\n", *p, path); p++; } fprintf(stderr, "Relative paths are resolved against the current working directory:\n"); char cwd[999]; fprintf(stderr, " %s\n", getcwd(cwd, sizeof(cwd))); fprintf(stderr, "Hint: use the option -objects path1" SEPARATOR "path2" SEPARATOR "...\n"); } FILE * init_fopen(char *path, char *access) { return fopen(init_findFile(path), access); } char * init_findFile(char *path) { static char resolved[999]; struct stat statbuf; memory_strcpy(resolved, sizeof(resolved), path); if (stat(resolved, &statbuf) == 0) return resolved; char **p = objects_dirs; while ( *p != NULL ) { snprintf(resolved, sizeof(resolved), "%s/%s", *p, path); if (stat(resolved, &statbuf) == 0) return resolved; p++; } init_fileNotFoundError(path); exit(1); } void init_init(char *objects, char *departure_date) { if( objects == NULL ) objects = DEFAULT_OBJECT_DIRS; objects = memory_strdup(objects); int size = 0; int i = 0; objects_dirs = NULL; char *s = strtok(objects, SEPARATOR); do { if ( i >= size ) { size = 2 * size + 10; objects_dirs = memory_realloc(objects_dirs, size * sizeof( char * )); } if ( s == NULL ){ /* REMEMBER: last elements of objects_dirs[] must be NULL: */ objects_dirs[i++] = NULL; break; } else { objects_dirs[i++] = memory_strdup(s); } s = strtok(NULL, SEPARATOR); } while ( 1 ); memory_dispose(objects); zulu_Date departure; if( departure_date == NULL || *departure_date == 0 ){ departure_timestamp = time(NULL); zulu_timestampToDate(departure_timestamp, &departure); } else { if( ! zulu_dateParse(departure_date, &departure) ) error_external("invalid departure date and time '%s'.\n" "Check format and range of each field, examples:\n\n" " 2017-10 (2017-10-01T00:00:00 assumed)\n" " 2017-10-20 (00:00:00 assumed time)\n" " 2017-10-20T12:34 (00 seconds assumed)\n" " 2017-10-20T12:34:56\n\n" "Allowed year range is [1583,9999].", departure_date); departure_timestamp = zulu_dateToTimestamp(&departure); } wmm_init( init_findFile("WMM.COF") ); wmm_setCurrentTime( zulu_dateToYear(&departure) ); astro_init(0, &departure); craft *p; for ((i = 0, p = ptbl); i < manifest_MAXPLAYERS; (++i, ++p)) { p->pIndex = i; p->type = CT_FREE; } for ((i = 0, p = mtbl); i < manifest_MAXPROJECTILES; (++i, ++p)) { p->pIndex = i; p->type = CT_FREE; } HUDColor = gui_getColorIndexString(NULL, "#00ee00"); whiteColor = gui_getColorIndexString(NULL, "white"); blackColor = gui_getColorIndexString(NULL, "black"); yellowColor = gui_getColorIndexString(NULL, "#ee0"); redColor = gui_getColorIndexString(NULL, "#f44"); magentaColor = gui_getColorIndexString(NULL, "orange"); radarColor = gui_getColorIndexString(NULL, "#0c0"); panelBackgroundColor = gui_getColorIndexString(NULL, "#111"); inventory_init(); weapon_init(); zones = zones_new( init_findFile("zones.txt") ); /* * Add the periodic resupply check procedure * FIXME: fuel and weapons resupply currently disabled */ /* id = */ alarm_add(manifest_RESUPPLY_INTERVAL, planes_doResupply, NULL, NULL); } void init_term(void) { int i; for( i = 0; i < manifest_MAXPLAYERS; i++ ){ if( ptbl[i].type != CT_FREE ){ ptbl[i].kill(&ptbl[i], "program terminated"); } } for( i = 0; i < manifest_MAXPROJECTILES; i++ ){ if( mtbl[i].type != CT_FREE ){ mtbl[i].kill(&mtbl[i], "simulation ended"); } } dis_if_close(); vpath_gallery_free_all(); for( i=0; ; i++){ if( objects_dirs[i] != NULL ) memory_dispose(objects_dirs[i]); else break; } memory_dispose(objects_dirs); objects_dirs = NULL; memory_dispose(zones); zones = NULL; } acm-6.0_20200416/src/acm/players.c0000644000000000000000000003614113175040223014747 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include #include "../util/error.h" #include "../util/memory.h" #include "../util/units.h" #include "../V/Vlib.h" #include "sounds.h" #include "box.h" #include "browse.h" #include "dis_if.h" #include "drone.h" #include "effects.h" #include "flaps.h" #include "gear.h" #include "hsi.h" #include "hud.h" #include "instruments.h" #include "inventory.h" #include "list.h" #include "magnetic_compass.h" #include "patchlevel.h" #include "planes.h" #include "pm.h" #include "prompt.h" #include "render.h" #include "terrain.h" #include "update.h" #include "viewer.h" #include "weapon.h" #include "windows.h" #define players_IMPORT #include "players.h" #define ARG_BORDER_COLOR "bordercolor" #define ARG_BORDER "borderwidth" #define ARG_GEOMETRY "geometry" #define DEFAULT_BACKGROUND "#7c99b6" #define DEFAULT_BORDER "black" #define SW_BACKGROUND 2 #define SW_GEOM 4 #define SW_FORCE 6 #define SW_PLANE 9 #define SW_LIST_PLAYER 10 #define SW_HUD_MODE 12 #define SW_PASSIVE 13 #define SW_LATITUDE 14 #define SW_LONGITUDE 15 #define SW_ALTITUDE 16 #define SW_AIRSPEED_KT 17 #define SW_HEADING 18 #define SW_END_GAME 19 #define SW_NO_SOUND 20 #define SW_FUEL 21 #define SW_PAYLOAD 22 #define SW_LAST 22 /* last entry in list */ static struct { char *sw; int value; } swt[] = { {"-skycolor", SW_BACKGROUND}, {"-geometry", SW_GEOM}, {"-force", SW_FORCE}, {"-stealth", SW_PASSIVE}, {"-plane", SW_PLANE}, {"-list", SW_LIST_PLAYER}, {"-latitude", SW_LATITUDE}, {"-longitude", SW_LONGITUDE}, {"-altitude", SW_ALTITUDE}, {"-airspeed-kt", SW_AIRSPEED_KT}, {"-heading", SW_HEADING}, {"-end-game", SW_END_GAME}, {"-no-sound", SW_NO_SOUND}, {"-fuel", SW_FUEL}, {"-payload", SW_PAYLOAD}, {"-hud-mode", SW_HUD_MODE}, {NULL, 0} }, *swp; /** * Internal state update call-back, normally set in the craft->update field. * @param c Subject craft. * @return Reason why this craft should be killed. Normally NULL. */ static char *players_update(craft *c) { char *killReason = pm_flightCalculations(c); if (killReason != NULL) return killReason; magnetic_compass_update(c->vl); hsi_update(c->vl); weapon_update(c); flaps_update(c); dis_if_updateLocal(c); return NULL; } void players_kill(craft *c, char *reason) { viewer *v; int i; VPoint vel = { 0, 0, 0 }; /* * Notify to all the viewers the reason why this craft is dead */ if( (reason != NULL) && (c->type == CT_PLANE || c->type == CT_DRONE || c->type == CT_DIS_PLANE ) ){ char s[1000]; snprintf(s, sizeof(s), "%s %s force %s: %s", c->name, c->cinfo->name, dis_forceToString(c->force), reason); prompt_broadcast_print(s); /* The owner of the window can see the message, use its terminal: */ if( c->type == CT_PLANE ) printf("%s\n", s); } /* * Decrement the player count, iff this is a real person that just got * killed. */ if (c->type == CT_PLANE && (c->flags & FL_BLACK_BOX) == 0) { --ptblCount; } /* * Erase our radar emissions */ for (i = 0; i < manifest_MAXPLAYERS; ++i){ ptbl[i].rval[c->pIndex] = 0.0; } /* * No need to inform the others crafts and missiles we died: the * dis_if module will take care to update c->curRadarTarget field. */ /* * Replace the plane with an explosion. */ effects_new_explosion(&(c->Sg), &vel, 30.0, 15.0, 4.0); /* * Release services tied to the craft */ memory_dispose(c->aps); gear_free(c); drone_release_commands(c); pm_hud_strings_free(c); /* FIXME: HUD data should go in hud.c */ /* * Close all the viewers tied to this craft */ while( c->vl != NULL ){ v = c->vl; /* * If this was a situation where we had grabbed control in steath * mode and then died, return to the browsing state. */ if ( v->viewer_state == ViewerStateNormal && v->watchedCraft != NULL && v->watchedCraft->type == CT_DIS_STEALTH ) { printf ("player killed: returning to stealth browsing mode\n"); v->viewer_state = ViewerStateBrowsing; /* FIXME: the current status of the viewer does not match that of the watched craft, we should release the services (audio, terminal, etc. as in viewer_free()) and then initialize them properly. */ v->c = v->watchedCraft; v->watchedCraft = NULL; v = NULL; } else { /* vn = c->vl; */ } viewer_free(v); } if (c->flags & FL_RECORD) { --recordCount; } if (c->flags & FL_BLACK_BOX) box_killPlayer(c->pIndex); dis_if_entityExit(c->disId); c->type = CT_FREE; } static void parseGeometry(char *geometry, int *width, int *height) { int w, h; *width = 400; *height = 300; if( geometry == NULL ) return; if( sscanf(geometry, "%dx%d", &w, &h) < 2 || w < 1 || h < 1 ){ fprintf(stderr, "invalid geometry string: %s\n", geometry); return; }; *width = w; *height = h; } int players_new(char *logname, list_Type *switches) { int argc; char **argv; char *geomSpec; /* Window geometry string */ char *c; static char *background = NULL; int player; viewer *u; craft *cf; int i; DISForce force = DISForceOther; char *plane = "C-172"; /* name of plane type */ int width, height; /* size of the main window */ int passive = 0; _BOOL hud_mode; int overrides[SW_LAST+1]; char *overrideLatitude = NULL; char *overrideLongitude = NULL; double overrideAltitude = 0.0, overrideHeading_rad = 0.0, overrideAirspeed_fps = 0.0, overrideFuel = 0.0, overridePayload = 0.0; int end_game = 0; int no_sound = 0; double disLocation[3]; double disZeroVec[3]; double disOrientation[3]; /* * Parse command line */ memset(overrides, 0, sizeof(overrides)); geomSpec = NULL; hud_mode = FALSE; if( switches == NULL ){ argc = 0; argv = NULL; /* make happy gcc -Wall */ } else { argc = switches->n; argv = switches->arr; } for( i=0; ivalue != 0; ++swp) { if (strcmp(swp->sw, c) == 0) { switch (swp->value) { case SW_GEOM: i++; if( i < argc ) geomSpec = argv[i]; break; case SW_END_GAME: end_game = 1; break; /* case SW_BORDER: i++; if( i < argc ) borderWidth = atoi( argv[i] ); break; */ case SW_BACKGROUND: i++; if( i < argc ) background = argv[i]; break; case SW_FORCE: i++; if( i >= argc ) error_external("missing argument for -force"); force = dis_parseForce(argv[i]); if( force < 0 ) error_external("unknown DIS force: %s", argv[i]); break; case SW_PASSIVE: passive = 1; break; case SW_PLANE: i++; if( i < argc ) plane = argv[i]; break; case SW_LATITUDE: i++; if( i < argc ){ overrideLatitude = argv[i]; overrides[SW_LATITUDE] = 1; } break; case SW_LONGITUDE: i++; if( i < argc ){ overrideLongitude = argv[i]; overrides[SW_LONGITUDE] = 1; } break; case SW_ALTITUDE: i++; if( i < argc ){ overrideAltitude = units_FEETtoMETERS(atof( argv[i] )); overrides[SW_ALTITUDE] = 1; } break; case SW_AIRSPEED_KT: i++; if( i < argc ){ overrideAirspeed_fps = units_KTtoFPS(atof( argv[i] )); if (overrideAirspeed_fps > units_KTtoFPS(2500.0)) { printf ("You really should slow down.\n"); printf ("At least to less than 2500 knots.\n"); } overrides[SW_AIRSPEED_KT] = 1; } break; case SW_HEADING: i++; if( i < argc ){ overrideHeading_rad = units_DEGtoRAD(atof( argv[i] )); overrides[SW_HEADING] = 1; } break; case SW_LIST_PLAYER: { printf("\nname\t\tnumber\n"); printf("-------------------------\n"); int i; for (i = 0; i < manifest_MAXPLAYERS; i++) { if (ptbl[i].type == CT_PLANE) { printf("%-16s %d\n", ptbl[i].name, i); } } return -1; } /* case SW_DEFAULT_VISUAL: useDefaultVisual = 0; break; */ case SW_NO_SOUND: no_sound = 1; break; case SW_FUEL: i++; if( i < argc ){ overrideFuel = atof( argv[i] ); overrides[SW_FUEL] = 1; } break; case SW_PAYLOAD: i++; if( i < argc ){ overridePayload = atof( argv[i] ); overrides[SW_PAYLOAD] = 1; } break; case SW_HUD_MODE: hud_mode = TRUE; break; default: error_internal("swp->value=%d", swp->value); } break; } } if (swp->value == 0) { error_external("invalid switch %s", argv[i]); return -1; } } } player = planes_newPlane(plane); if (player < 0) { if (player == -1) { printf("Sorry, no room for any more players at this moment.\n"); } else { printf("You have selected an unknown plane type. Choose one among these types:\n"); inventory_printValidAircraft(); } return -1; } cf = &ptbl[player]; /* * Set fuel and payload */ if (overrides[SW_FUEL]) { if (overrideFuel > cf->cinfo->maxFuel) { printf("Too much fuel for this plane. Maximum is %.0f lb.\n", cf->cinfo->maxFuel); cf->fuel = cf->cinfo->maxFuel; } else { cf->fuel = overrideFuel; } } else { cf->fuel = cf->cinfo->maxFuel; } if (overrides[SW_PAYLOAD]) { cf->payload = overridePayload; } else { cf->payload = 150.0; /* weight of the pilot (lb) */ } // Default initial position: 0N 0E, sea level! cf->w = (earth_LatLonAlt){0,0,0}; // Set position according to command line parameters: if ( overrides[SW_LATITUDE] && ! earth_parseLatitude(overrideLatitude, &cf->w.latitude) ) error_external("invalid starting latitude: ", overrideLatitude); if ( overrides[SW_LONGITUDE] && ! earth_parseLongitude(overrideLongitude, &cf->w.longitude) ) error_external("invalid starting latitude: ", overrideLatitude); /* Forces terrain altitude recalculation: */ cf->terrain_altitude_timeout = 0.0; earth_LatLonAltToXYZ(&cf->w, &cf->Sg); /* * Forces loading of the scenery below the aircraft. If the starting zone * defines our force base location, retrieve that location for the resupply * procedure. */ cf->zone = zones_load(zones, &cf->w, NULL, 1); if( cf->zone != NULL && zone_isLoaded(cf->zone) ) forceBaseLocation[cf->force] = *zone_getForceBaseLocation(cf->zone, cf->force); if (overrides[SW_ALTITUDE]) { cf->w.z = overrideAltitude; cf->curPitch = units_DEGtoRAD(2.0); /* ensure some initial lift */ gear_up(cf); } else { double h; gear_ground_altitude_pitch(cf, &h, &cf->curPitch); /* WARNING. terrain_local_altitude() requires cf->Sg and zone be already set. */ cf->w.z = terrain_localAltitude(cf) + units_FEETtoMETERS(h); earth_LatLonAltToXYZ(&cf->w, &cf->Sg); gear_down(cf); } // Set magnetic variation based on the actual position. cf->updActualMagneticField = curTime - 1.0; /* force VAR recalculation */ /* ignore = */ pm_mag_heading(cf); /* set cf->actualLocalVAR */ cf->indicatedLocalVAR = cf->actualLocalVAR; cf->updIndicatedMagneticField = curTime + 2.0; cf->curHeading = 0; if( overrides[SW_HEADING] ) cf->curHeading = pm_normalize_yaw( overrideHeading_rad - cf->actualLocalVAR ); cf->prevSg = cf->Sg; cf->curRoll = 0.0; cf->r = cf->q = cf->p = 0.0; // Generate trihedral and world-to-aircraft matrices VEulerToMatrix(cf->curRoll, cf->curPitch, cf->curHeading, &(cf->trihedral)); earth_generateWorldToLocalMatrix(&cf->w, &cf->XYZtoNED); // Set airspeed. if (overrides[SW_AIRSPEED_KT]) { VMatrix turn; VPoint v = { overrideAirspeed_fps, 0.0, 0.0 }; VIdentMatrix(&turn); VRotate(&turn, ZRotation, cf->curHeading); VTransform_(&v, &turn, &cf->Cg ); } else { VSetPoint(&cf->Cg, 0, 0, 0); } cf->update = players_update; cf->kill = players_kill; // Open a new viewer. cf->vl = NULL; u = viewer_new(cf); u->hud_mode = hud_mode; /* * If we're passive (stealth mode), wipe out aircraft information; * this entry will become a placeholder for our browsing view. */ if ( passive ) { u->viewer_state = ViewerStateBrowsing; cf->type = CT_DIS_STEALTH; cf->cinfo = NULL; cf->radarMode = RM_DIS_BROWSE; if ( end_game ) { end_game_mode = 1; } /* * Stealth a specific entity? Go ahead and set it as the subject. * * This requires snooping for entities in the PDU stream prior * to looking for the entity in the table. */ if ( subjectEntitySpecified ) { dis_if_Entity *e; craft *c; printf ("Building entity database ... "); fflush ( stdout ); update_simulationTime (); dis_if_snoop ( 5500 ); printf ("done.\n"); e = dis_if_findEntityByDISID( & subjectEntityID ); if( e == NULL ) c = e->c; else c = NULL; if ( c ) { browse_stealthCraft ( c, u, -1, 1); } } } else { if ( end_game ) { printf("The -end-game switch is only valid when used " ); printf("with stealth mode.\n" ); printf("The switch will be ignored.\n\n" ); } if ( subjectEntitySpecified ) { printf("The -subject-entity-id switch is only valid when used " ); printf("with stealth mode.\n" ); printf("The switch will be ignored.\n\n" ); } } parseGeometry(geomSpec, &width, &height); u->gui = gui_new("ACM-" patchlevel_REVISION_STRING, width, height); render_setOutsideView(u->c, u, render_VIEW_FORWARD); if (background == NULL) background = DEFAULT_BACKGROUND; cf->force = force; memory_strcpy(cf->name, sizeof(cf->name), logname); sounds_enable(cf, ! no_sound); u->w = Alib_new(u->gui); Alib_setDepthCueing(u->w, 1); windows_set_layout(cf, u, width, height, hud_mode); if( hud_mode ){ hud_enable(u); } else { instruments_enable(u); } ++ptblCount; /* * Transmit initial DIS entity state PDU */ if ( cf->type != CT_DIS_STEALTH ) { earth_LatLonAltToXYZ(&cf->w, (VPoint *) disLocation); disZeroVec[0] = 0.0; disZeroVec[1] = 0.0; disZeroVec[2] = 0.0; disOrientation[0] = cf->curHeading; disOrientation[1] = 0.0; disOrientation[2] = 0.0; dis_if_entityEnter(force, cf, &cf->cinfo->entityType, &cf->cinfo->altEntityType, disLocation, disZeroVec, disZeroVec, disOrientation, disZeroVec, &cf->disId); } cf->showMag = TRUE; magnetic_compass_enable(u); cf->radarMode = RM_HSI; hsi_enable(u); return 0; } acm-6.0_20200416/src/acm/draw.c0000644000000000000000000001421513175036555014240 0ustar rootroot/* * ACM - Draw utilities module * Copyright (C) 2007 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include #include "../util/memory.h" #define draw_IMPORT #include "draw.h" typedef struct draw_Type { struct draw_Type *next; int segs_n; /* segs[0..segs_n-1] currently used */ int segs_size; /* allocated segments, segs_size >= segs_n */ Alib_Segment * segs; /* pointer to the allocated segments */ } draw_data; static draw_data *free_list = NULL; #define SEGMENT2(a,b,c,d) \ seg->x1 = (int) (a); \ seg->y1 = (int) (b); \ seg->x2 = (int) (c); \ seg->y2 = (int) (d); \ seg++; static void draw_destruct(void *p) { draw_data *dd = p; if( dd == NULL ) return; memory_dispose(dd->segs); } void draw_free(draw_data *dd) { if( dd == NULL ) return; dd->next = free_list; free_list = dd; } static void draw_cleanup() { draw_data *dd; while( free_list != NULL ){ dd = free_list; free_list = dd->next; memory_dispose(dd); } } draw_data * draw_new() { draw_data *dd; if( free_list == NULL ){ memory_registerCleanup(draw_cleanup); dd = memory_allocate(sizeof(draw_data), draw_destruct); dd->segs_size = 0; dd->segs = NULL; } else { dd = free_list; free_list = dd->next; } dd->next = NULL; dd->segs_n = 0; return dd; } static void required_segs(draw_data *dd, int n) /* Expands dd so that at least n free segs be available. */ { if( dd->segs_size - dd->segs_n >= n ) return; dd->segs_size = 2*dd->segs_size + 100; if( dd->segs_size - dd->segs_n < n ) dd->segs_size = dd->segs_n + n; dd->segs = memory_realloc(dd->segs, dd->segs_size * sizeof(Alib_Segment)); } void draw_segment(draw_data *dd, double x1, double y1, double x2, double y2) { int i; Alib_Segment *seg; required_segs(dd, 1); i = dd->segs_n; seg = &dd->segs[i]; SEGMENT2(x1 + 0.5, y1 + 0.5, x2 + 0.5, y2 + 0.5); dd->segs_n += 1; } void draw_rect(draw_data *dd, double x1, double y1, double x2, double y2) { int i; Alib_Segment *seg; required_segs(dd, 4); i = dd->segs_n; seg = &dd->segs[i]; /* Rounding: */ x1 += 0.5; y1 += 0.5; x2 -= 0.5; y2 -= 0.5; SEGMENT2(x1, y1, x2, y1); SEGMENT2(x2, y1, x2, y2); SEGMENT2(x2, y2, x1, y2); SEGMENT2(x1, y2, x1, y1); dd->segs_n += 4; } #define MAX_CIRCLE_ERR 0.7 void draw_circle(draw_data *dd, double xo, double yo, double r) { int i, j, steps; Alib_Segment *seg; double da, x1, y1, x2, y2, co, si; /* Rounding: */ /* FIXME: improper rounding, as it should be -0.5 rather thatn +0.5 */ xo += 0.5; yo += 0.5; r += 0.5; if( r < 1.0 ) return; /* Angle step for max MAX_CIRCLE_ERR error: */ da = 2.0 * acos((r-MAX_CIRCLE_ERR)/r); steps = (int) ceil(2.0 * M_PI / da); if( steps < 4 ) steps = 4; steps = (steps + 3) * 4 / 4; da = 2.0 * M_PI / steps; co = cos(da); si = sin(da); x1 = 0.70710678 * r; y1 = 0.70710678 * r; required_segs(dd, steps); i = dd->segs_n; seg = &dd->segs[i]; for( j = steps; j > 0; j-- ){ x2 = co * x1 - si * y1; y2 = co * y1 + si * x1; SEGMENT2(xo + x1, yo + y1, xo + x2, yo + y2); x1 = x2; y1 = y2; } dd->segs_n += steps; } void draw_arc(draw_data *dd, double xo, double yo, double r, double a1, double a2) { int i, j, steps; double a, da, co, si, x1, y1, x2, y2; Alib_Segment *seg; if( r < 1.0 ) return; /*** if( a1 < 0.0 ) a1 = 2*M_PI + a1; if( a2 < 0.0 ) a2 = 2*M_PI + a2; if( a1 > 2*M_PI ) a1 = fmod(a1, 2*M_PI); if( a2 > 2*M_PI ) a2 = fmod(a2, 2*M_PI); ***/ if( a1 > a2 ){ a = a1; a1 = a2; a2 = a; } if( a1 == a2 ) return; /* Rounding: */ xo += 0.5; yo += 0.5; /* Angle step for max MAX_CIRCLE_ERR error: */ da = 2.0 * acos((r-MAX_CIRCLE_ERR)/r); steps = (int) ceil((a2-a1) / da); if( steps < 1 ) steps = 1; da = (a2-a1) / steps; co = cos(da); si = sin(da); x1 = r*cos(a1); y1 = r*sin(a1); required_segs(dd, steps); i = dd->segs_n; seg = &dd->segs[i]; for( j = steps; j > 0; j-- ){ x2 = co * x1 - si * y1; y2 = co * y1 + si * x1; SEGMENT2(xo + x1, yo + y1, xo + x2, yo + y2); x1 = x2; y1 = y2; } dd->segs_n += steps; } #define POINTER_APERTURE_COS 0.9397 /* cos(20 DEG) */ #define POINTER_APERTURE_SIN 0.3420 /* sin(20 DEG) */ void draw_pointer(draw_data *dd, double xo, double yo, double a, double l) { double co, si, co1, si1, co2, si2, p0x, p0y, p1x, p1y, p2x, p2y; co = cos(a); si = sin(a); p0x = xo + l*co; p0y = yo + l*si; co1 = co*POINTER_APERTURE_COS - si*POINTER_APERTURE_SIN; si1 = co*POINTER_APERTURE_SIN + si*POINTER_APERTURE_COS; p1x = xo + 0.2*l*co1; p1y = yo + 0.2*l*si1; co2 = co*POINTER_APERTURE_COS + si*POINTER_APERTURE_SIN; si2 = -co*POINTER_APERTURE_SIN + si*POINTER_APERTURE_COS; p2x = xo + 0.2*l*co2; p2y = yo + 0.2*l*si2; draw_segment(dd, p0x, p0y, p1x, p1y); draw_segment(dd, p0x, p0y, p2x, p2y); draw_segment(dd, p1x, p1y, p2x, p2y); } void draw_stroke(draw_data *dd, Viewport *v, Alib_Pixel color) { if( dd->segs_n == 0 ) return; VDrawSegments(v, dd->segs, dd->segs_n, color); } void draw_fill(draw_data *dd, Viewport *v, Alib_Pixel color) { if( dd->segs_n == 0 ) return; draw_stroke(dd, v, color); /* FIXME: FillPolygonNoClipping(v->w, dd->segs, dd->segs_n, z); */ } void draw_string_centered(Viewport *v, double xo, double yo, double fh, char *s, Alib_Pixel color) { int fw, l, width, height; fw = VFontWidthPixels(v, (int) (fh+0.5)); l = strlen(s); width = l * fw; height = (int)(fh + 0.5); VDrawStrokeString(v, (int) (xo - 0.5*width + 0.5), (int) (yo + 0.5*height + 0.5), s, l, (int)(fh + 0.5), color); } /* End of the draw module. */ acm-6.0_20200416/src/acm/hud.c0000644000000000000000000005737213174071670014072 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include #include #include "../util/memory.h" #include "../util/units.h" #include "../util/zulu.h" #include "aps.h" #include "damage.h" #include "draw.h" #include "m61a1.h" #include "pm.h" #include "vpath.h" #include "weapon.h" #define hud_IMPORT #include "hud.h" #define DESIGNATOR_SIZE 20 #define HUD(u) ((hud_Type *)u->hud) static int blink = 0; static double blink_toggle_time = 0.0; typedef struct _hud_data { struct _hud_data *next; _BOOL enabled; int timer_op; /* timer operation: 0=do not display, 1=run, 2=stop */ int timer_freezed; /* store the time when timer_op is 2 */ double timer_offset; /* store the offset time when timer_op is 1 or 2 */ } hud_Type; static hud_Type *free_list = NULL; static vpath_Type * hud_vpath = NULL, * fpm_vpath = NULL; static void hud_cleanup() { hud_Type *hud; while( free_list != NULL ){ hud = free_list; free_list = free_list->next; memory_dispose(hud); } memory_dispose(hud_vpath); memory_dispose(fpm_vpath); } void hud_enable(viewer *u) { hud_Type *hud; if( u->hud == NULL ){ if( free_list == NULL ){ hud = memory_allocate( sizeof(hud_Type), NULL ); memory_registerCleanup(hud_cleanup); } else { hud = free_list; free_list = hud->next; hud->next = NULL; } hud->next = NULL; hud->timer_op = 0; u->hud = hud; } HUD(u)->enabled = TRUE; } void hud_disable(viewer *u) { if( u->hud == NULL ) return; HUD(u)->enabled = FALSE; } void hud_timer_toggle(viewer *u) /* Actually, it cycles between the states timer_op 0, 1 and 2. */ { if( u->hud == NULL || !HUD(u)->enabled ) return; HUD(u)->timer_op = (HUD(u)->timer_op + 1) % 3; if ( HUD(u)->timer_op == 1 ) { HUD(u)->timer_offset = curTime; } else if ( HUD(u)->timer_op == 2 ) { HUD(u)->timer_freezed = (int) (curTime - HUD(u)->timer_offset + 0.5); } } static void doBankIndicator(craft * c, viewer * u) { double xscale, yscale, r, r2, r3, r4, cosa, sina, bank, x1, y1, x2, y2, x3, y3; int x0, y0, a, blink_bank; draw_Type *dd; xscale = u->xscaleFactor; yscale = u->yscaleFactor; r = 200.0 * xscale; /* tick mark start radius */ r2 = 1.05*r; /* tick mark end radious */ r3 = 0.99*r; r4 = 0.94*r; x0 = u->v->focus.x; y0 = u->v->focus.y + (int) (-150.0*yscale + r); dd = draw_new(); VSetClipRect(u->v, &u->v->rect); for( a = -30; a <= 30; a += 10 ){ cosa = cos( units_DEGtoRAD(a) ); sina = sin( units_DEGtoRAD(a) ); draw_segment(dd, x0 + sina*r, y0 - cosa*r, x0 + sina*r2, y0 - cosa*r2); } bank = c->curRoll; blink_bank = 0; if( bank < units_DEGtoRAD(-40) ){ bank = units_DEGtoRAD(-40); blink_bank = blink; } else if( bank > units_DEGtoRAD(+40) ){ bank = units_DEGtoRAD(+40); blink_bank = blink; } if( ! blink_bank ){ x1 = x0 + sin(bank)*r3; y1 = y0 - cos(bank)*r3; x2 = x0 + sin(bank + units_DEGtoRAD(2))*r4; y2 = y0 - cos(bank + units_DEGtoRAD(2))*r4; x3 = x0 + sin(bank - units_DEGtoRAD(2))*r4; y3 = y0 - cos(bank - units_DEGtoRAD(2))*r4; draw_segment(dd, x1, y1, x2, y2); draw_segment(dd, x1, y1, x3, y3); draw_segment(dd, x2, y2, x3, y3); } draw_stroke(dd, u->v, HUDColor); draw_free(dd); } #define TurnAndSlipIndicatorWidth 100 static void doTurnAndSlipIndicator(craft * c, viewer * u) /* Displays the rate of turn (DEG/s), the lateral acceleration (g) and a timer (s). */ { double xscale, yscale, w; int tx, ty, t, blink_turn, blink_w; int w_tick; int w_t; double a; draw_Type *dd; int h, m, s; char buffer[20]; Alib_Pixel color; xscale = u->xscaleFactor; yscale = u->yscaleFactor; w_t = (int) (xscale * TurnAndSlipIndicatorWidth / 2.0); w_tick = (int) (xscale * TurnAndSlipIndicatorWidth / 4.0); tx = u->v->focus.x - (int) (xscale * 160); ty = u->v->focus.y + (int) (yscale * 200); dd = draw_new(); VSetClipRect(u->v, &u->v->rect); color = HUDColor; /* Draw scale: */ w = 6 * yscale; draw_segment(dd, tx-w_t, ty, tx+w_t, ty); draw_segment(dd, tx-w_t, ty, tx-w_t, ty-w); /* -3.0 DEG/s */ draw_segment(dd, tx-w_tick, ty, tx-w_tick, ty-w); /* -1.5 DEG/s */ draw_segment(dd, tx, ty, tx, ty-w); /* 0 DEG/s */ draw_segment(dd, tx+w_tick, ty, tx+w_tick, ty-w); /* +1.5 DEG/s */ draw_segment(dd, tx+w_t, ty, tx+w_t, ty-w); /* +3.0 DEG/s */ /* Draw turn rate needle: */ a = units_RADtoDEG( (c->q*sin(c->curRoll) + c->r*cos(c->curRoll)) / cos(c->curPitch) ); blink_turn = 0; if( a > 3.5 ){ a = 3.5; blink_turn = blink; } else if( a < -3.5 ){ a = -3.5; blink_turn = blink; } if( ! blink_turn ){ int x0 = tx + a / 3.0 * w_t; int y0 = ty - 4 * yscale; w = 4 * xscale; draw_segment(dd, x0 - w, y0, x0 - w - w, y0 - w); draw_segment(dd, x0 - w - w, y0 - w, x0 + w + w, y0 - w); draw_segment(dd, x0 + w + w, y0 - w, x0 + w, y0); } /* Draw lateral accel. needle: */ a = c->G.y; blink_turn = 0; if( a < -0.5 ){ a = -0.5; blink_turn = blink; } else if( a > 0.5 ){ a = 0.5; blink_turn = blink; } if( ! blink_turn ){ t = tx - (int) rint(2.0*a*w_t); draw_segment(dd, t, ty+2*yscale, t, ty+9*yscale); } if( aps_ac_enabled(c) && ( ! aps_ac_warn(c) || ! blink ) ){ VDrawStrokeString(u->v, tx - w_t, ty + (int) (yscale * 12), "AC", 2, xscale * 8.0, color); } draw_stroke(dd, u->v, HUDColor); draw_free(dd); /* Draw AutoTurn status: */ if ( aps_aw_enabled(c) && ( ! aps_aw_warn(c) || ! blink ) ){ w = aps_aw_get(c); blink_w = FALSE; if( w < units_DEGtoRAD(-3.1) ){ w = units_DEGtoRAD(-3.0); blink_w = blink; } else if( w > units_DEGtoRAD(3.1) ){ w = units_DEGtoRAD(3.0); blink_w = blink; } if ( ! blink_w ) VDrawStrokeString(u->v, tx + (int) (w * w_t / units_DEGtoRAD(3.0) - xscale * 6.0 + 0.5), ty + (int) (yscale * 4.0 + 0.5), "o", 1, xscale * 12.0, color); } /* Draw timer: */ if ( HUD(u)->timer_op == 0 ) { return; } else if ( HUD(u)->timer_op == 1 ) { t = (int) (curTime - HUD(u)->timer_offset); } else { t = HUD(u)->timer_freezed; } if (t >= 3600) { h = t / 3600; t = t % 3600; m = t / 60; s = t % 60; sprintf(buffer, "%d:%02d:%02d", h, m, s); } else if (t >= 60) { m = t / 60; s = t % 60; sprintf(buffer, "%d:%02d", m, s); } else { sprintf(buffer, "%d", t); } VDrawStrokeString(u->v, tx - w_t, ty + (int) (yscale * 30.0), buffer, strlen(buffer), yscale * 12.0, color); } static void draw_dashed_line(vpath_Type *p, VPoint *a, VPoint *b, int n) { int i; VPoint c, d; n = 2*n - 1; c = *a; for( i = 1; i <= n; i++ ){ VSetPoint(&d, a->x + i*(b->x - a->x)/n, a->y + i*(b->y - a->y)/n, a->z + i*(b->z - a->z)/n); if( (i & 1) == 1 ){ vpath_moveTo(p, &c); vpath_lineTo(p, &d); } else { c = d; } } } static vpath_Type * build_hud_vpath() { vpath_Type * p; int angle, s_len; VPoint a, b, c; VMatrix m, n; char s[10]; double fw, fh; p = vpath_new(); /**** Bare cross: vpath_moveTo(p, &(VPoint){-0.1, 0.0, 1.0}); vpath_lineTo(p, &(VPoint){+0.1, 0.0, 1.0}); vpath_moveTo(p, &(VPoint){0.0, 0.1, 1.0}); vpath_lineTo(p, &(VPoint){0.0, -0.1, 1.0}); return p; ****/ /* Since the HUD pitch ladder is drawn over a sphere of radius 1.0, it is convenient representing all the distances as angles under which every item can be seen from the center of the sphere. . | +---------- . v...--------+ 15 | | D . | . | | ............| . . ^ . . . | . . . .<--A-->. . . | . . .<------B------>. . | . .<--------D-------->. | */ #define A units_DEGtoRAD(1.0) /* ladder inner point */ #define B units_DEGtoRAD(2.0) /* ladder outer point */ #define C units_DEGtoRAD(0.5) /* ladder "comma" */ #define D units_DEGtoRAD(2.5) /* label yaw angle */ /* Draw horizon line, right side: */ VSetPoint(&a, cos(A), sin(A), 0.0); VSetPoint(&b, cos(2*B), sin(2*B), 0.0); vpath_moveTo(p, &a); vpath_lineTo(p, &b); /* Draw horizon line, left side: */ a.y = -a.y; b.y = -b.y; vpath_moveTo(p, &a); vpath_lineTo(p, &b); /* Draw ladder pitch marks, step 5 DEG: */ fh = sin(units_DEGtoRAD(0.7)); fw = sin(units_DEGtoRAD(0.4)); for( angle = -85; angle <= 85; angle += 5 ){ if( angle == 0 ) continue; VIdentMatrix(&m); VRotate(&m, YRotation, units_DEGtoRAD(angle)); /* Draw the right side of the ladder peg: */ VSetPoint(&a, cos(A), sin(A), 0.0); VSetPoint(&b, cos(B), sin(B), 0.0); VSetPoint(&c, cos(B), sin(B), sin(C)); if( angle < 0 ) c.z = -c.z; VTransform(&a, &m, &a); VTransform(&b, &m, &b); VTransform(&c, &m, &c); if( angle > 0 ){ vpath_moveTo(p, &a); vpath_lineTo(p, &b); vpath_lineTo(p, &c); } else { draw_dashed_line(p, &a, &b, 3); vpath_moveTo(p, &b); vpath_lineTo(p, &c); } /* Reverse y, then draw the left side of the peg: */ a.y = -a.y; b.y = -b.y; c.y = -c.y; if( angle > 0 ){ vpath_moveTo(p, &a); vpath_lineTo(p, &b); vpath_lineTo(p, &c); } else { draw_dashed_line(p, &a, &b, 3); vpath_moveTo(p, &b); vpath_lineTo(p, &c); } /* Now the label, right side: */ sprintf(s, "%d", abs(angle)); s_len = strlen(s); VIdentMatrix(&n); VScaleMatrix(&n, fw, fh, 1.0); VRotate(&n, XRotation, units_DEGtoRAD(90)); VRotate(&n, ZRotation, units_DEGtoRAD(90)); VTranslate(&n, 1.0, sin(D) - 0.5*s_len*fw, 0.5*fh); VMatrixMult(&n, &m, &n); vpath_draw_string(p, s, s_len, &n); /* Label, left side: */ VTranslate(&n, 0.0, -2.0*sin(D), 0.0); vpath_draw_string(p, s, s_len, &n); } /* -1, -2 and -3 pitch marks: */ for( angle = -1; angle >= -3; angle-- ){ VIdentMatrix(&m); VRotate(&m, YRotation, units_DEGtoRAD(angle)); /* Draw the right side of the ladder peg: */ VSetPoint(&a, cos(A), sin(A), 0.0); VSetPoint(&b, cos(B), sin(B), 0.0); VTransform(&a, &m, &a); VTransform(&b, &m, &b); draw_dashed_line(p, &a, &b, 3); /* Reverse y, then draw the left side of the peg: */ a.y = -a.y; b.y = -b.y; draw_dashed_line(p, &a, &b, 3); } return p; } static vpath_Type * build_fpm_vpath() { #define FPM_A_STEP 45 /* DEG */ vpath_Type *p; int a; p = vpath_new(); vpath_moveTo(p, &(VPoint){0.0, 0.0, 1.0}); for( a = FPM_A_STEP; a <= 360; a += FPM_A_STEP ){ vpath_lineTo(p, &(VPoint){0.0, sin(units_DEGtoRAD(a)), cos(units_DEGtoRAD(a))}); } vpath_moveTo(p, &(VPoint){0.0, 0.0, -1.0}); vpath_lineTo(p, &(VPoint){0.0, 0.0, -2.0}); vpath_moveTo(p, &(VPoint){0.0, 1.0, 0.0}); vpath_lineTo(p, &(VPoint){0.0, 2.0, 0.0}); vpath_moveTo(p, &(VPoint){0.0, -1.0, 0.0}); vpath_lineTo(p, &(VPoint){0.0, -2.0, 0.0}); return p; } #define LADDER_WIDTH 325.0 #define LADDER_HEIGHT 430.0 static void doLadder(craft * c, viewer * u, double vel) { _BOOL plotFPM; int windX, windY, w, tx, ty, x, y; VPoint tmp, tmp1, t1; VMatrix m; double v, d; Alib_Rect rect; Alib_Pixel color; tx = (int) (LADDER_WIDTH * u->xscaleFactor * 0.5 + 0.5); ty = (int) (LADDER_HEIGHT * u->yscaleFactor + 0.5); Alib_setRect(&rect, u->v->focus.x - tx, u->hud_yCenter - 0.37 * ty, u->v->focus.x + tx, u->hud_yCenter + 0.63 * ty); VSetClipRect(u->v, &rect); if( Alib_isEmptyRect(&u->v->rect) ) return; color = HUDColor; /* * Build a transformation matrix to be used to display the flight * path ladder (artificial horizon). * * One thing we do is to keep the ladder centered on the flight path * marker. The correction angle "v" is calculated to make that happen. */ if (fabs(c->Cg.x) < 5.0 && fabs(c->Cg.y) < 5.0) { v = 0.0; } else { t1.x = cos(c->curHeading) * c->Cg.x + sin(c->curHeading) * c->Cg.y; t1.y = -sin(c->curHeading) * c->Cg.x + cos(c->curHeading) * c->Cg.y; v = atan2(t1.y, t1.x); } if( hud_vpath == NULL ){ hud_vpath = build_hud_vpath(); fpm_vpath = build_fpm_vpath(); } VIdentMatrix(&m); VRotate(&m, ZRotation, v); VRotate(&m, YRotation, -c->curPitch); VRotate(&m, XRotation, -c->curRoll); VRotate(&m, ZRotation, units_DEGtoRAD(-90)); VRotate(&m, XRotation, units_DEGtoRAD(-90)); vpath_perspective_stroke(hud_vpath, &m, u->v, color); /* * Determine the location of the flight path marker */ VReverseTransform_(&c->Cg, &c->trihedral, &tmp); if (vel < 50.0 || tmp.x == 0.0) { plotFPM = ! blink; windX = u->v->focus.x; windY = u->v->focus.y; } else if (tmp.x > 0.0) { plotFPM = TRUE; windX = u->v->focus.x + ((int) (tmp.y * u->v->Scale.x / tmp.x) / 4); windY = u->v->focus.y + ((int) (tmp.z * u->v->Scale.y / tmp.x) / 4); } else { plotFPM = FALSE; windX = 0.0; windY = 0.0; } if (plotFPM) { d = 8.0 * u->xscaleFactor; VIdentMatrix(&m); VScaleMatrix(&m, d, d, d); VRotate(&m, ZRotation, units_DEGtoRAD(-90)); VRotate(&m, XRotation, units_DEGtoRAD(-90)); VTranslate(&m, windX, windY, -1.0); vpath_stroke(fpm_vpath, &m, u->w, color); } /* * Gather weapon display info (and maybe draw a reticle). * * WARNING. This function must be called before drawing the target * designator, as this will also set the m61a1_lcos_last_post global * variable that will be used next. */ weapon_displaySelected(c, u, (int) floor(windX), (int) floor(windY)); /* * Draw a target designator around the current primary radar target. */ if (c->curRadarTarget >= 0) { w = (int) (DESIGNATOR_SIZE * u->xscaleFactor); VTransform(&ptbl[c->curRadarTarget].Sg, &c->XYZtoNED, &tmp1); VReverseTransform_(&tmp1, &c->trihedral, &tmp); /* radar target is assumed to be ahead of us (tmp.z > 0.0) */ tx = (u->v->Middl.x + (((int) (tmp.y * u->v->Scale.x / tmp.x)))) >> 2; ty = (u->v->Middl.y + (((int) (tmp.z * u->v->Scale.y / tmp.x)))) >> 2; /* * If the LCOS reticule was drawn by weapon_displaySelected(), then * m61a1_lcos_last_pos contains its position on the screen. We avoid to * draw the target designator if this latter is too close to the LCOS. * * If no LCOS reticle was plotted or if the distance to the LCOS reticle is * sufficient, then plot a radar target designator box. */ if( c->curWeapon == weapon_M61A1 ){ x = m61a1_lcos_last_pos.x; y = m61a1_lcos_last_pos.y; d = sqrt((double) ((x - tx) * (x - tx) + (y - ty) * (y - ty))); } if( c->curWeapon != weapon_M61A1 || d > w * 2.5 ){ draw_Type *dd; dd = draw_new(); draw_segment(dd, tx - w, ty - w, tx + w, ty - w); draw_segment(dd, tx + w, ty - w, tx + w, ty + w); draw_segment(dd, tx + w, ty + w, tx - w, ty + w); draw_segment(dd, tx - w, ty + w, tx - w, ty - w); draw_stroke(dd, u->v, color); draw_free(dd); } } /* Bare nose pointer: */ Alib_drawArc(u->v->w, u->v->focus.x - 2, u->v->focus.y - 2, 4, 4, 0, 360 * 64, color); } #ifdef FIXME_TESTING_CODE_FOR_VLIB #define DASH_LEN 7 static void draw_dashed_line2(Viewport *v, int x1, int y1, int x2, int y2) { int len, n, i, d, x, y, nx, ny; double dx, dy; draw_Type *dd; len =sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)); n = (int) (len / DASH_LEN + 0.5); if( (n & 1) == 0 ) n++; dx = (x2 - x1)/(double)n; dy = (y2 - y1)/(double)n; x = x1; y = y1; dd = draw_new(); d = 1; for( i = 1; i <= n; i++ ){ nx = x1 + (int)(i*dx + 0.5); ny = y1 + (int)(i*dy + 0.5); if( d ){ draw_segment(dd, x, y, nx, ny); } x = nx; y = ny; d = !d; } draw_stroke(dd, v, v->w->pixel[magentaColor]); draw_free(dd); } static void FIXME_draw_dashed_rect(Viewport *v, Alib_Rect *rr) { Alib_Window *w; Alib_Rect r2, *r; w = v->w; Alib_setClipRect(w, rr); r2 = *rr; Alib_expandRect(&r2, -1, -1); r = &r2; //printf("FIXME: r=%d %d %d %d\n", r2.a.x, r2.a.y, r2.b.x, r2.b.y); draw_dashed_line2(v, r->a.x, r->a.y, r->b.x-1, r->a.y); draw_dashed_line2(v, r->a.x, r->a.y, r->a.x, r->b.y-1); draw_dashed_line2(v, r->a.x, r->b.y-1, r->b.x-1, r->b.y-1); draw_dashed_line2(v, r->b.x-1, r->a.y, r->b.x-1, r->b.y-1); draw_dashed_line2(v, v->focus.x, v->focus.y - 20, v->focus.x, v->focus.y + 20); draw_dashed_line2(v, v->focus.x - 20, v->focus.y, v->focus.x + 20, v->focus.y); } #endif void hud_draw(viewer * u) { craft *c; int i, x, x1, y, fth, xscale1, yscale1; double xscale, yscale, fontH, vel; char buffer[80]; Alib_Pixel color; //FIXME_draw_dashed_rect(u->v, &u->v->rect); if( u->hud == NULL || !HUD(u)->enabled ) return; c = u->c; if( ! damage_isFunctioning(c, SYS_HUD) ) return; xscale = u->xscaleFactor; yscale = u->yscaleFactor; color = HUDColor; /* Stall warning */ if( ! blink && c->damageBits & FLAG_STALL_WARN ){ fontH = (int) (24 * yscale); int fontW = fontH; x = u->v->focus.x - 5 * fontW / 2; y = u->v->focus.y + 4 * fontH; strcpy(buffer, "STALL"); VDrawStrokeString(u->v, x, y, buffer, strlen(buffer), fontH, color); } xscale1 = (int) (xscale * 2048.0); yscale1 = (int) (yscale * 2048.0); fontH = (int) (12.0 * yscale + 0.5); fth = (int) (18.0 * yscale + 0.5); if( curTime >= blink_toggle_time ){ blink = ! blink; if( blink ) blink_toggle_time = curTime + 0.05; else blink_toggle_time = curTime + 0.5; } if (u->viewDirection.x < 0.90) return; /* Angle of Attack */ if ((vel = VMagnitude(&c->Cg)) < 50.0) sprintf(buffer, "a=0.0"); else sprintf(buffer, "a=%.1f", units_RADtoDEG(c->alpha)); x = u->v->focus.x + 150 * xscale1 / 2048; y = u->v->focus.y - u->velScale.length / 2 - (int) (yscale * 50); VDrawStrokeString(u->v, x, y, buffer, strlen(buffer), fontH, color); /* Accelerometer */ x1 = u->v->focus.x - 220 * xscale1 / 2048; sprintf(buffer, "%4.1fg", - c->G.z); VDrawStrokeString(u->v, x1, y, buffer, strlen(buffer), fontH, color); /* APS lights: */ x = u->v->focus.x + 100.0*xscale; y = u->v->focus.y - 90.0*yscale; i = fontH * 2; /* interline */ /* Rate control law: */ if( aps_rate_control_enabled(c) ){ VDrawStrokeString(u->v, x, y, "Rate", 4, fontH, color); } /* Auto Pilot */ if( aps_ap_enabled(c) && ( ! aps_ap_warn(c) || ! blink ) ){ VDrawStrokeString(u->v, x, y, "VS/ALT", 6, fontH, color); } /* Auto Landing */ y += i; if( aps_al_enabled(c) && ( ! aps_al_warn(c) || ! blink ) ){ VDrawStrokeString(u->v, x, y, "Land", 4, fontH, color); } /* Auto Nav */ y += i; if ( aps_an_enabled(c) && ( ! aps_an_warn(c) || ! blink ) ){ VDrawStrokeString(u->v, x, y, "NAV", 3, fontH, color); } /* Auto Throttle */ y += i; if ( aps_at_enabled(c) && ( ! aps_at_warn(c) || ! blink ) ){ VDrawStrokeString(u->v, x, y, "THR", 3, fontH, color); } /* Auto Turn */ y += i; if ( aps_aw_enabled(c) && ( ! aps_aw_warn(c) || ! blink ) ){ VDrawStrokeString(u->v, x, y, "Turn", 4, fontH, color); } /* Auto Coord */ y += i; if ( aps_ac_enabled(c) && ( ! aps_ac_warn(c) || ! blink ) ){ VDrawStrokeString(u->v, x, y, "Coord", 5, fontH, color); } /* Vertical velocity */ x = u->v->focus.x + 130 * xscale1 / 2048; y = u->velScale.yorg + (int) (2 * yscale * fontH); sprintf(buffer, "%+6d0", (int) (-c->Cg.z * 6.0)); VDrawStrokeString(u->v, x, y, buffer, strlen(buffer), fontH, color); /* Compass, altitude and airspeed cards */ scale_drawCompass(u->v, &(u->hdgScale), units_RADtoDEG(c->showMag? pm_mag_heading(c) : c->curHeading) * 100.0); scale_draw(u->v, &(u->altScale), units_METERStoFEET(c->w.z)); /* TAS: */ //vel = c->VT; /* Airspeed along the x axis (the Pitot tube indicates this): */ vel = c->VT * cos(c->alpha) * cos(c->beta); if( vel < 0.0 ) vel = 0.0; scale_draw(u->v, &(u->velScale), units_FPStoKT(vel)); /* AutoThrottle */ if ( aps_at_enabled(c) && ( ! aps_at_warn(c) || ! blink ) ){ x = u->v->focus.x - 150 * xscale1 / 2048; y = u->hud_yCenter - 10 * yscale1 / 2048; sprintf(buffer, "AT%3d IAS", (int) (units_FPStoKT( aps_at_get_velocity(c) ) + 0.5)); VDrawStrokeString(u->v, x, y, buffer, strlen(buffer), fontH, color); } /* Mach number */ if (c->mach >= 0.20) { sprintf(c->leftHUD[1], " %4.2f", c->mach); } else { strcpy(c->leftHUD[1], ""); } x = u->v->focus.x - 220 * xscale1 / 2048; y = u->hud_yCenter - 200 * yscale1 / 2048; for (i = 0; i < 5; ++i) { VDrawStrokeString(u->v, x, y, c->leftHUD[i], strlen(c->leftHUD[i]), fontH, color); y += fth; } x = u->v->focus.x + 160 * xscale1 / 2048; y = u->hud_yCenter - 200 * yscale1 / 2048; for (i = 0; i < 5; ++i) { VDrawStrokeString(u->v, x, y, c->rightHUD[i], strlen(c->rightHUD[i]), fontH, color); y += fth; } doLadder(c, u, vel); doBankIndicator(c, u); doTurnAndSlipIndicator(c, u); } static int fspage_show = 0; /* FIXME: put in data struct tied to the viewer */ static void TermPrintLn(viewer * u, char *s) { static int x = 0, y = 0, h = 0, dy = 0; if( s == NULL ){ if( u->hud_mode ) h = RectHeight(u->v->rect) / 40; else h = RectHeight(u->v->rect) / 25; if( h > 9 ) h = 9; dy = (int) (h * 1.5 + 0.5); x = dy; y = dy; return; } VDrawStrokeString(u->v, x, y, s, strlen(s), h, whiteColor); y += dy; } void hud_free(viewer *u) { if( u->hud == NULL ) return; HUD(u)->next = free_list; free_list = u->hud; u->hud = NULL; } void FSPageToggle() { fspage_show = ! fspage_show; } static void doFSPage(craft * c, viewer * u) { double VAR; char buf[256], buf1[256]; VSetClipRect(u->v, &u->v->rect); TermPrintLn(u, NULL); TermPrintLn(u, c->cinfo->name); TermPrintLn(u, c->cinfo->description); zulu_Date d; zulu_timestampToDate(departure_timestamp + curTime, &d); sprintf(buf, "%04d-%02d-%02dT%02d:%02d", d.year, d.month, d.day, d.hour, d.minutes); TermPrintLn(u, buf); sprintf (buf, "G: %+.2f %+.2f %+.2f", c->G.x, c->G.y, c->G.z); TermPrintLn(u, buf); sprintf (buf, "Ail/Elev/Rdr: %+.3f %+.3f %+.3f", c->Sa, c->Se, c->Sr); TermPrintLn(u, buf); sprintf (buf, "Euler: %+.1f %+.1f %+.1f", units_RADtoDEG(c->curRoll), units_RADtoDEG(c->curPitch), units_RADtoDEG(c->curHeading)); TermPrintLn(u, buf); sprintf (buf, "Euler rates: %+.2f %+.2f %+.2f", units_RADtoDEG(c->p + c->q*tan(c->curPitch)*sin(c->curRoll) + c->r*tan(c->curPitch)*cos(c->curRoll)), units_RADtoDEG(c->q*cos(c->curRoll) - c->r*sin(c->curRoll)), units_RADtoDEG(c->q*sin(c->curRoll)/cos(c->curPitch) + c->r*cos(c->curRoll)/cos(c->curPitch))); TermPrintLn(u, buf); sprintf (buf, "Omega: %+.2f %+.2f %+.2f", units_RADtoDEG(c->p), units_RADtoDEG(c->q), units_RADtoDEG(c->r)); TermPrintLn(u, buf); earth_latitudeToString(buf, sizeof(buf), c->w.latitude, earth_LLM_DMS); TermPrintLn(u, buf); earth_longitudeToString(buf, sizeof(buf), c->w.longitude, earth_LLM_DMS); strcat (buf, " "); sprintf (buf1, "%d m", (int)(c->w.z+0.5)); strcat (buf, buf1); TermPrintLn(u, buf); if (c->showMag) { VAR = units_RADtoDEG( c->indicatedLocalVAR ); sprintf(buf, "VAR %.1f%c", fabs(VAR), VAR < 0 ? 'E' : 'W'); TermPrintLn(u, buf); } sprintf(buf, "T = %.0f C", units_RankineToCelsius(c->air.t)); TermPrintLn(u, buf); sprintf(buf, "P = %.0f hPa", c->air.p * units_LbToKgFactor * units_earth_g / units_FootToMeterFactor * 0.01); TermPrintLn(u, buf); sprintf(buf, "rho = %.3f Kg/m^3", units_SlugToKg(c->air.rho) / (units_FootToMeterFactor*units_FootToMeterFactor*units_FootToMeterFactor)); TermPrintLn(u, buf); sprintf(buf, "c = %.0f m/s", c->air.mach1 * units_FootToMeterFactor); TermPrintLn(u, buf); } void doFlightStatusPage(craft * c, viewer * u) { if ( ! fspage_show ) return; doFSPage(c, u); return; } acm-6.0_20200416/src/acm/vpath_gallery.c0000644000000000000000000001173713066635473016155 0ustar rootroot/* * acm : an aerial combat simulator for X - Gallery of common drawings * Copyright (C) 2008 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include "../V/Vlibmath.h" #include "../util/memory.h" #define vpath_gallery_IMPORT #include "vpath_gallery.h" static vpath_Type *compass_scale = NULL, *compass_fixed_scale = NULL, *stylized_aircraft = NULL, *pointer_arrow = NULL, *pointer_triangle = NULL; vpath_Type * vpath_gallery_get_compass_scale(void) { VMatrix m; VPoint a, b; int hdg, s_len; double fh, fw, margin, r, r_long, r_short, r1; char *s; static char *labels[] = {"N", "3", "6", "E", "12", "15", "S", "21", "24", "W", "30", "33"}; if( compass_scale != NULL ) return compass_scale; compass_scale = vpath_new(); fh = 0.11; fw = fh * 3.0/4.0; margin = 0.04; r = 1.0; r_long = 0.92; r_short = 0.96; for( hdg = 0; hdg < 360; hdg += 5 ){ VIdentMatrix(&m); VRotate(&m, ZRotation, units_DEGtoRAD(hdg)); if( hdg % 10 == 0 ) r1 = r_long; else r1 = r_short; VSetPoint(&a, 0.0, -r, 0.0); VSetPoint(&b, 0.0, -r1, 0.0); VTransform(&a, &m, &a); VTransform(&b, &m, &b); vpath_moveTo(compass_scale, &a); vpath_lineTo(compass_scale, &b); if( hdg % 30 == 0 ){ s = labels[hdg / 30]; s_len = strlen(s); VIdentMatrix(&m); VScaleMatrix(&m, fw, fh, 1.0); VTranslate(&m, -0.5*fw*s_len, -r1 + margin + fh, 0.0); VRotate(&m, ZRotation, units_DEGtoRAD(hdg)); vpath_draw_string(compass_scale, s, s_len, &m); } } return compass_scale; } vpath_Type * vpath_gallery_get_compass_fixed_scale(void) { VMatrix m; VPoint a, b; int hdg; double r, r1; if( compass_fixed_scale != NULL ) return compass_fixed_scale; compass_fixed_scale = vpath_new(); r = 1.0; r1 = 0.90; for( hdg = 0; hdg < 360; hdg += 45 ){ VIdentMatrix(&m); VRotate(&m, ZRotation, units_DEGtoRAD(hdg)); VSetPoint(&a, 0.0, -r, 0.0); VSetPoint(&b, 0.0, -r1, 0.0); VTransform(&a, &m, &a); VTransform(&b, &m, &b); vpath_moveTo(compass_fixed_scale, &a); vpath_lineTo(compass_fixed_scale, &b); } return compass_fixed_scale; } vpath_Type * vpath_gallery_get_stylized_aircraft(void) { double l1, l2, l3; if( stylized_aircraft != NULL ) return stylized_aircraft; stylized_aircraft = vpath_new(); l1 = 0.14; /* fuselage half-width */ l2 = 0.50; /* elevator half-width */ l3 = 0.30; /* wing y offset */ /* right side: */ vpath_moveTo(stylized_aircraft, &(VPoint){l1, -1.0, 0.0}); vpath_lineTo(stylized_aircraft, &(VPoint){l1, 1.0, 0.0}); vpath_lineTo(stylized_aircraft, &(VPoint){l2, 1.0, 0.0}); vpath_moveTo(stylized_aircraft, &(VPoint){l1, -l3, 0.0}); vpath_lineTo(stylized_aircraft, &(VPoint){1.0, -l3, 0.0}); /* left side (same as above with x reversed): */ vpath_moveTo(stylized_aircraft, &(VPoint){-l1, -1.0, 0.0}); vpath_lineTo(stylized_aircraft, &(VPoint){-l1, 1.0, 0.0}); vpath_lineTo(stylized_aircraft, &(VPoint){-l2, 1.0, 0.0}); vpath_moveTo(stylized_aircraft, &(VPoint){-l1, -l3, 0.0}); vpath_lineTo(stylized_aircraft, &(VPoint){-1.0, -l3, 0.0}); return compass_fixed_scale; } vpath_Type * vpath_gallery_get_pointer_arrow(void) { if( pointer_arrow != NULL ) return pointer_arrow; pointer_arrow = vpath_new(); vpath_moveTo(pointer_arrow, &(VPoint){0.0, -1.0, 0.0}); vpath_lineTo(pointer_arrow, &(VPoint){0.0, 1.0, 0.0}); vpath_moveTo(pointer_arrow, &(VPoint){0.0, -1.0, 0.0}); vpath_lineTo(pointer_arrow, &(VPoint){0.05, -0.80, 0.0}); vpath_lineTo(pointer_arrow, &(VPoint){0.12, -0.70, 0.0}); vpath_moveTo(pointer_arrow, &(VPoint){-0.0, -1.0, 0.0}); vpath_lineTo(pointer_arrow, &(VPoint){-0.05, -0.80, 0.0}); vpath_lineTo(pointer_arrow, &(VPoint){-0.12, -0.70, 0.0}); return pointer_arrow; } vpath_Type * vpath_gallery_get_pointer_triangle(void) { double l = 0.1; if( pointer_triangle != NULL ) return pointer_triangle; pointer_triangle = vpath_new(); vpath_moveTo(pointer_triangle, &(VPoint){0.0, -1.0, 0.0}); vpath_lineTo(pointer_triangle, &(VPoint){0.0-l, -1.0-l, 0.0}); vpath_lineTo(pointer_triangle, &(VPoint){0.0+l, -1.0-l, 0.0}); vpath_lineTo(pointer_triangle, &(VPoint){0.0, -1.0, 0.0}); return pointer_triangle; } void vpath_gallery_free_all(void) { memory_dispose(compass_scale); memory_dispose(compass_fixed_scale); memory_dispose(stylized_aircraft); memory_dispose(pointer_arrow); memory_dispose(pointer_triangle); } /* The vpath_gallery.c module end here. */ acm-6.0_20200416/src/acm/box.h0000644000000000000000000000245013646045023014067 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991,1992 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /** * Black box recording and playback. * * FIXME: This module not finished yet, still undocumented (U.S.). * * @author Riley Rainey * @license GNU GPL * @version $Date: 2020/01/08 06:00:16 $ * @file */ #ifndef _box_h #define _box_h #include "pm.h" #ifdef box_IMPORT #define EXTERN #else #define EXTERN extern #endif EXTERN void box_input(void); EXTERN void box_killPlayer(int id); EXTERN void box_output(void); EXTERN void box_endRecording(void); EXTERN void box_startPlayback(void); EXTERN void box_startRecording(void); #undef EXTERN #endif acm-6.0_20200416/src/acm/gear.c0000644000000000000000000007620113175037165014222 0ustar rootroot/* * ACM - Landing gear module * Copyright (C) 2008 Umberto Salsi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include #include "../util/error.h" #include "../util/memory.h" #include "../util/units.h" #include "sounds.h" #include "damage.h" #include "pm.h" #include "prompt.h" #include "terrain.h" #define gear_IMPORT #include "gear.h" #define GEARDOWN (M_PI / 2.0) #define MU_SKID 0.85 typedef struct gear_Type { /** If gear is in locked down position and can sustain the weight. */ _BOOL isHandleDown; /** Nose, left, right gear extension angle (RAD). */ double noseAngle; double leftAngle; double rightAngle; /** If nose, left, right are in contact with ground. */ _BOOL noseGroundContact; _BOOL leftGroundContact; _BOOL rightGroundContact; /** Current nose wheel steering angle (RAD). */ double noseSteeringAngle; /** If brakes engaged. */ _BOOL isBraking; /** Braking smoothing factor in [0,1]. */ double brakingFactor; } gear_Type; static gear_Type * get(craft * c) { gear_Type * g; g = (gear_Type *) c->gear; if( g == NULL ) error_internal("missing gear data structure for %s", c->name); return g; } void gear_free(craft * c) { memory_dispose(c->gear); c->gear = NULL; } void gear_allocate(craft * c) { gear_Type * g = memory_allocate( sizeof(gear_Type), NULL ); g->isHandleDown = FALSE; g->noseAngle = 0.0; g->leftAngle = 0.0; g->rightAngle = 0.0; g->noseGroundContact = FALSE; g->leftGroundContact = FALSE; g->rightGroundContact = FALSE; g->noseSteeringAngle = 0.0; g->isBraking = FALSE; g->brakingFactor = 0.0; c->gear = g; } _BOOL gear_isHandleDown(craft * c) { gear_Type * g; g = get(c); return g->isHandleDown; } static _BOOL gear_isUp(craft * c) { gear_Type * g; g = get(c); return g->noseAngle == 0.0 && g->leftAngle == 0.0 && g->rightAngle == 0.0; } /************* static _BOOL gear_isDown(craft * c) { gear * g; g = get(c); return g->noseAngle == GEARDOWN && g->leftAngle == GEARDOWN && g->rightAngle == GEARDOWN; } static _BOOL gear_isMoving(craft * c) { return ! gear_isUp(c) && ! gear_isDown(c); } **********/ int gear_nosePosition(craft * c) { gear_Type * g; g = get(c); if( g->noseAngle == 0.0 ) return 0; else if( g->noseAngle == GEARDOWN ) return 2; else return 1; } int gear_leftPosition(craft * c) { gear_Type * g; g = get(c); if( g->leftAngle == 0.0 ) return 0; else if( g->leftAngle == GEARDOWN ) return 2; else return 1; } int gear_rightPosition(craft * c) { gear_Type * g; g = get(c); if( g->rightAngle == 0.0 ) return 0; else if( g->rightAngle == GEARDOWN ) return 2; else return 1; } void gear_up(craft *c) { gear_Type * g; g = get(c); g->isHandleDown = FALSE; g->noseAngle = 0.0; g->leftAngle = 0.0; g->rightAngle = 0.0; } void gear_down(craft *c) { gear_Type * g; g = get(c); g->isHandleDown = TRUE; g->noseAngle = GEARDOWN; g->leftAngle = GEARDOWN; g->rightAngle = GEARDOWN; } _BOOL gear_allWheelsGroundContact(craft * c) { gear_Type * g; g = get(c); return g->noseGroundContact && g->leftGroundContact && g->rightGroundContact; } _BOOL gear_someWheelGroundContact(craft * c) { gear_Type * g; g = get(c); return g->noseGroundContact || g->leftGroundContact || g->rightGroundContact; } _BOOL gear_noseWheelGroundContact(craft * c) { gear_Type * g; g = get(c); return g->noseGroundContact; } _BOOL gear_mainWheelsGroundContact(craft * c) { gear_Type * g; g = get(c); return g->leftGroundContact || g->rightGroundContact; } void gear_handle_up(craft *c) { gear_Type * g; g = get(c); if( ! g->isHandleDown ) return; g->isHandleDown = FALSE; sounds_playSound(c, sounds_GearUp, FALSE); } void gear_handle_down(craft *c) { gear_Type * g; g = get(c); if( g->isHandleDown ) return; g->isHandleDown = TRUE; sounds_playSound(c, sounds_GearDown, FALSE); } void gear_handle_toggle(craft *c) { gear_Type * g; g = get(c); if( g->isHandleDown ) gear_handle_up(c); else gear_handle_down(c); } _BOOL gear_brakesEngaged(craft * c) { gear_Type * g; g = get(c); return g->isBraking; } void gear_brakesEngage(craft * c) { gear_Type * g; g = get(c); g->isBraking = TRUE; } void gear_brakesDisengage(craft * c) { gear_Type * g; g = get(c); g->isBraking = FALSE; } void gear_ground_altitude_pitch(craft *c, double *altitude, double *pitch) { craftType *p; double w, l, zn, zm, delta_cn, delta_cm, ne, me, F, M, dF_dcn, dF_dcm, dM_dcn, dM_dcm, new_F, new_M, z, dcn, dcm, err2max; int i; void force_and_moment(double ne, double me, double *F, double *M) /* * Calculate static forces due to springs for the aircraft at * rest on the horizontal ground. 'ne' is the nose oleo extension, * 'me' is the main oleo extension. * * Return total vertical force applied to the CM and total moment * around y axis. */ { double s, z, cosa, sina, Fn, Fm, ln, lm; /* Compute sine and cosine of the rest pitch angle */ if( p->rn.x > p->rm.x ) s = 1.0; else s = -1.0; z = zn + ne - zm - me; cosa = l / sqrt(l*l + z*z); sina = s * z / sqrt(l*l + z*z); Fn = (p->cnMax - ne)*p->Kn / cosa; Fm = (p->cmMax - me)*p->Km / cosa; *F = w - Fn - Fm; ln = p->rn.x*cosa + (zn + ne)*sina; lm = p->rm.x*cosa + (zm + me)*sina; *M = Fn*ln + Fm*lm; } p = c->cinfo; w = p->emptyWeight + c->fuel + c->payload; /* weight (lbf) */ l = fabs(p->rn.x - p->rm.x); zn = p->rn.z + p->Gn; zm = p->rm.z + p->Gm; /* * We are looking for the zero of the total force F(ne,me) and total * moment M(ne,me) being ne,me the extension of the springs. We * start from the middle point then moving the point (ne,me) in * the box [0,cnMax]x[0,cmMax]: */ ne = 0.5*p->cnMax; me = 0.5*p->cmMax; /* * Partial derivatives are numerically calculated using these steps: */ delta_cn = 1e-5 * p->cnMax; delta_cm = 1e-5 * p->cmMax; /* * The loop continues until the changes in ne,me become less than * about one hundredth of the max extension. Calculate the square * of this error: */ err2max = 1e-6 * (p->cnMax * p->cnMax + p->cmMax * p->cmMax); i = 0; do { /* * Evaluate the derivatives of F(ne,me) and M(ne,me): this * gives the plane that best approximates the functions F,M * around the point (ne,me): * * dF = dF_dcn dcn + dF_dcm * dcm dM = dM_dcn dcn + dM_dcm * * dcm */ force_and_moment(ne, me, &F, &M); #ifdef DEBUG printf("FIXME: ne=%f me=%f F=%f M=%f\n", ne, me, F, M); #endif force_and_moment(ne + delta_cn, me, &new_F, &new_M); dF_dcn = (new_F - F) / delta_cn; dM_dcn = (new_M - M) / delta_cn; force_and_moment(ne, me + delta_cm, &new_F, &new_M); dF_dcm = (new_F - F) / delta_cm; dM_dcm = (new_M - M) / delta_cm; /* * Move the point (ne,me) along the approximating planes in * order to cancel F,M: * * -F = dF_dcn dcn + dF_dcm * dcm -M = dM_dcn dcn + dM_dcm * * dcm * * Resolving this system of equations gives us dcn,dcm. */ dcm = (dM_dcn*F - dF_dcn*M) / (dF_dcn*dM_dcm - dF_dcm*dM_dcn); me += dcm; dcn = -F/dF_dcn -dF_dcm/dF_dcn*dcm; ne += dcn; if( ne < 0.0 ) ne = 0.0; if( ne > p->cnMax - delta_cn ) ne = p->cnMax - delta_cn; if( me < 0.0 ) me = 0.0; if( me > p->cmMax - delta_cm ) me = p->cmMax - delta_cm; i++; #ifdef DEBUG printf("FIXME: %d) ne=%.0f%% me=%.0f%%\n", i, 100.0 * ne / p->cnMax, 100.0 * me / p->cmMax); #endif if( i > 9 ){ /* * Usually two or three loops are enough, but * still there are cases in which this algo does * not converge. */ printf("WARNING: unbalanced gear parameters, can't find a good rest position.\n"); break; } } while( dcn*dcn + dcm*dcm > err2max ); z = zn + ne - zm - me; if( p->rn.x < p->rm.x ) z = -z; *pitch = asin( z / sqrt(l*l + z*z) ); *altitude = (zm + me)*cos(*pitch) + (-p->rm.x)*sin(*pitch); #ifdef DEBUG printf("FIXME: alt=%f pitch=%f\n", *altitude, units_RADtoDEG(*pitch)); #endif } static void gear_move_up_down(craft *c) { gear_Type * g; g = get(c); if (damage_isFunctioning(c, SYS_NOSEGEAR)) { if (g->isHandleDown) { if (g->noseAngle != GEARDOWN) { g->noseAngle += c->cinfo->gearRate * deltaT; if (g->noseAngle > GEARDOWN) g->noseAngle = GEARDOWN; } } else { if (g->noseAngle != 0.0) { g->noseAngle -= c->cinfo->gearRate * deltaT; if (g->noseAngle < 0.0) g->noseAngle = 0.0; } } } if (damage_isFunctioning(c, SYS_LEFTMAIN)) { if (g->isHandleDown) { if (g->leftAngle != GEARDOWN) { g->leftAngle += 0.8*c->cinfo->gearRate * deltaT; if (g->leftAngle > GEARDOWN) g->leftAngle = GEARDOWN; } } else { if (g->leftAngle != 0.0) { g->leftAngle -= 0.8*c->cinfo->gearRate * deltaT; if (g->leftAngle < 0.0) g->leftAngle = 0.0; } } } if (damage_isFunctioning(c, SYS_RIGHTMAIN)) { if (g->isHandleDown) { if (g->rightAngle != GEARDOWN) { g->rightAngle += 0.9*c->cinfo->gearRate * deltaT; if (g->rightAngle > GEARDOWN) g->rightAngle = GEARDOWN; } } else { if (g->rightAngle != 0.0) { g->rightAngle -= 0.9*c->cinfo->gearRate * deltaT; if (g->rightAngle < 0.0) g->rightAngle = 0.0; } } } } static double spring_and_damper_force(double K, double D, double eMax, double e, double e_dot) /* * Compute spring + damper force * K = spring factor (lbf/s^2) * D = damper factor (lbf s /ft) * eMax = max extension (ft) * e = current extension (ft) * e_dot = extension rate (ft/s) * * Return: the resultant vertical force (lbf), always <= 0.0. If the result * is 0.0, the wheel lost contact with ground. */ { double spring, damper; if( e >= eMax ) return 0.0; spring = - K * (eMax - e); if( e < 0.1 ) /* add resistance in the last 0.1 feet */ spring -= 100 * K * (e - 0.1); damper = D * e_dot; if( damper + spring > 0.0 ){ /* wheel lost contact with ground */ spring = 0.0; damper = 0.0; } return spring + damper; } static inline double sgn(double x) { if( x > 0.0 ) return 1.0; else if( x < 0.0 ) return -1.0; else return 0.0; } #define SLIP_MAX units_DEGtoRAD(3) static _BOOL /* return TRUE if wheel is skidding */ wheel_friction( double deflection, /* steering angle, positive right (RAD) */ double vx, double vy, /* forward and rightward velocity (ft/s)*/ double Fn, /* normal force (lbf) */ double muStatic, /* rolling, near rest mu factor */ double muKinetic, /* rolling mu factor */ double muLateral, /* lateral mu factor */ VPoint *F /* resulting friction force (lbf) */ , char *debug /* FIXME: remove */ ) /* * This function computes the friction force F of the wheel due to the * rolling friction and the lateral friction. The rolling friction brakes * the longitudinal motion, while the lateral friction is responsible for * the steering and the lateral skidding. Basically the longitudinal force * is proportional to the normal force: * * force = mu Fn * * where mu becomes larger at small speed (muStatic) and smaller at high * speed (muKinetic). * * SLIP_MAX is the maximum angle of slip between wheel rolling direction * and actual velocity. Below this angle the lateral friction is linerly * dependent on the slip angle: * * force = Fn muSkid * slip / SLIP_MAX * * above that angle the lateral force is constant: * * force = Fn muSkid * * This model for wheel steering is well described in this paper: * * How to Drive Like a Racecar Driver: Vehicle Stabilization at the Limits * of Handling Yung-Hsiang (Judy) Hsu, Shad Laws, Chris Gerdes Stanford * University http://ddl.stanford.edu/atthelimits * * See also: * * Tire Model in Driving Simulator * http://code.eng.buffalo.edu/dat/sites/tire/tire.html where the relation * between steering and braking forces and the relation between velocity * and varying mu coefficients are discussed. In our model the nose wheel * can steer but cannot brake, and vice-versa the left and right wheels * can brake but do not steer. * * The Physics of Racing Brian Beckman http://phors.locost7.info/contents.htm */ { _BOOL skid; double rx, ry, v_lateral, k, v_forward, F_forward, F_lateral, slip; skid = FALSE; if( deflection == 0.0 ){ rx = 1.0; ry = 0.0; } else { rx = cos(deflection); ry = sin(deflection); } /* * Evaluate the longitudinal static or rolling friction along the * longitudinal vector (rx,ry): */ v_forward = vx*rx + vy*ry; k = v_forward / 0.5; if( fabs(k) > 1.0 ) k = sgn(k); if( fabs(v_forward) < 0.5 /* ft/s */ ) F_forward = - k * muStatic * Fn; else F_forward = - k * muKinetic * Fn; /* * Evaluate the lateral friction along the lateral vector (-ry,rx): */ v_lateral = rx*vy - ry*vx; k = v_lateral / 3.0; if( fabs(k) > 1.0 ) k = sgn(k); /* * Slip angle between wheel direction and velocity, normalized to * the range +/-90 DEG: */ slip = atan2( v_lateral, v_forward ); if( ! (slip >= -M_PI && slip <= M_PI) ) slip = 0.5 * M_PI * sgn(v_lateral); if( slip > 0.5*M_PI ) slip = M_PI - slip; else if( slip < -0.5*M_PI ) slip = -slip - M_PI; if( fabs(slip) < SLIP_MAX ){ /* linear behavior: */ F_lateral = - k * muLateral * fabs(slip) / SLIP_MAX * Fn; } else { /* saturation */ if( fabs(slip) > 2*SLIP_MAX && fabs(k) > 0.5 ) skid = TRUE; F_lateral = - k * muLateral * Fn; } //F_lateral = 0.0; /* FIXME */ //F_forward = 0.0; /* FIXME */ F->x = F_forward * rx - F_lateral * ry; F->y = F_forward * ry + F_lateral * rx; F->z = 0.0; #ifdef DEBUG printf("FIXME: %5s, Fn=%6.0f v=%5.1f %5.1f defl=%5.1f slip=%5.1f F=%7.0f %7.0f\n", debug, Fn, vx, vy, units_RADtoDEG(deflection), units_RADtoDEG(slip), F->x, F->y); #endif return skid; } double gear_get_drag(craft * c) { gear_Type * g; if( gear_isUp(c) ) return 0.0; g = get(c); return (sin(g->noseAngle) + sin(g->leftAngle) + sin(g->rightAngle)) / 3.0 * c->cinfo->cGearDrag; } char * gear_ground_dynamics(craft * c, VPoint *gearF, VPoint *gearM) { gear_Type * g; craftType *p; double ne, ne_dot, re, re_dot, le, le_dot; VPoint nw, nw_dot, rw, rw_dot, lw, lw_dot; VPoint r, r_dot, q, q_dot; double ground_z, muStatic, muKinetic, k, v; VPoint F, M, mt, Cg, Fl, Fr, Fn, FnMu, FlMu, FrMu; VPoint omega; VMatrix NEDtoSWC, AXYZtoSWC; _BOOL skid; g = get(c); gear_move_up_down(c); /* * Update braking factor. * Engage/disengage within 1 s. */ if (g->isBraking){ g->brakingFactor += deltaT; if( g->brakingFactor > 1.0 ) g->brakingFactor = 1.0; } else { g->brakingFactor -= deltaT; if( g->brakingFactor < 0.0 ) g->brakingFactor = 0.0; } if( g->noseAngle < GEARDOWN && g->leftAngle < GEARDOWN && g->rightAngle < GEARDOWN ){ /* none of the wheels is fully extended */ VSetPoint(gearF, 0, 0, 0); VSetPoint(gearM, 0, 0, 0); return NULL; } ground_z = units_METERStoFEET(c->w.z - terrain_localAltitude(c)); if( ground_z <= 0.0 ){ return "sunken under the terrain..."; } else if( ground_z > 500.0 ){ /* very far from the terrain */ VSetPoint(gearF, 0, 0, 0); VSetPoint(gearM, 0, 0, 0); return NULL; } p = c->cinfo; /* * The Simplified Word Coordinates (SWC) is a reference frame centered * on the aircraft CM with the z axis pointing downward to the ground and * the x axis oriented as the current heading. This frame makes easier to * detect wheels contact with the ground. The ground is the plane z=ground_z * (ft). We compute two useful rotational matrices: * * NEDtoSWC that rotates from NED to SWC, and * * AXYZtoSWC that rotates from aircraft frame to SWC */ VIdentMatrix(&NEDtoSWC); VRotate(&NEDtoSWC, ZRotation, -c->curHeading); AXYZtoSWC = c->AXYZtoNED; VRotate(&AXYZtoSWC, ZRotation, -c->curHeading); /* * Cg (ft/s) is the CM ground speed vector with components in SWC. */ VTransform(&c->Cg, &NEDtoSWC, &Cg); v = VMagnitude(&Cg); /* * Set nose wheel steering angle c->curNWDef (RAD). * * Since mouse and joystick give very little force feedback, steering at * high speed often results in a catastrophic disaster :-) We have two * choices here: locking the nose wheel at high speed or gently reduce the * steering effectiveness. We follow this latter way. * * The criteria is: given the pilot's steering input, calculate an angle * of steering that produces the same centripetal acceleration at any speed * above some limit speed V_THR. This result is achieved as follows. * * The radius of steering for the point between the two main wheels (that * typically is also very close to the CM) is * * r = Q / tan(c->curNWDef) * * where Q=abs(c->rn.x - c->rm.x) is the distance between the nose and the * main gears. For little angles, this formula becomes * * r = Q / c->curNWDef * * The centripetal acceleration of the CM for v < V_THR is * * a = v*v/r = v*v*k*c->curNWDef/Q with k=1.0 * * For speeds above V_THR we reduce the steering angle by a factor "k" * such that the resulting centripetal acceleration be the same we had at * v=V_THR with the given pilot's input: * * k = (V_THR/v)^2 */ #define V_THR units_KTtoFPS(10.0) if( v < V_THR ) k = 1.0; else k = V_THR*V_THR / (v * v); //g->noseSteeringAngle = - k * (c->steerComm * c->cinfo->maxNWDef); g->noseSteeringAngle = - k * (c->rollComm * c->cinfo->maxNWDef); /* * muStatic and muKinetic are the friction mu coefficients of the left and * right wheels, that varies depending on brakes on/off. Since the nose * wheel does not brake, it always uses p->muStatic and p->muKinetic. */ if (g->isBraking) { muStatic = p->muBStatic; muKinetic = p->muBKinetic; } else { muStatic = p->muStatic; muKinetic = p->muKinetic; } /* * Compute brake force rate. */ muStatic = (1.0 - g->brakingFactor) * p->muStatic + g->brakingFactor * p->muBStatic; muKinetic = (1.0 - g->brakingFactor) * p->muKinetic + g->brakingFactor * p->muBKinetic; /* * A few theory about how oleo strut extension and extension rate are * calculated: * * r = position of the gear strut attachment in AXYZ (ex. rn + Gn) * q = [0,0,1] unity vector giving the oleo extension direction * e = oleo extension (ranging from 0 to cnMax or cmMax for nose or main) * M = AXYZtoSWC (for brevity) * * The wheel position in AXYZ will be ("==" means "definition"): * * w == r + eq * * Vector components can also conveniently be expressed in the SWC frame: * * r' == Mr (components of r in SWC, NOT the position in SWC!) * * q' == Mq (components of q in SWC) * * The wheel position in SWC requires to rotate the components of w and * add the position of the CM in the SWC frame, Sg: * * w' == Mw + Sg * = r' + eq' + Sg (1) * * If the wheel is in contact with ground, the z component of the eq. 1 * must be zero, from which we obtain the oleo extension: * * e = - (r'.z + Sg.z) / q'.z (2) * * Speeds in SWC can be easily calculated introducing the rotational speed * vector applied to the CM with components in SWC: * * omega == [c->p, c->q, c->r] * * from which for any vector r in components AXYZ, its components in SWC * are r' = Mr and its velocity in components SWC is r'_dot = omega x r'. * We can now calculate the derivative of e, needed to calculate the * damping. We obtain this value deriving (2): * * e_dot = - ([omega x r'].z + Cg.z) / q'.z - e [omega x q'].z / q'.z * * Finally, the velocity of the wheel in SWC is the derivative of eq. 1: * * w'_dot = omega x r' + e_dot q' + e * q'_dot + Cg * * We will now calculate e, e_dot and w'_dot for each wheel: */ /* Angular velocity vector, components in SWC: */ VSetPoint(&omega, c->p, c->q, c->r); /* Stroke unity vector and its derivative, components in SWC: */ VSetPoint(&q, 0, 0, 1); VTransform_(&q, &AXYZtoSWC, &q); VCrossProd(&omega, &q, &q_dot); /* NOSE GEAR */ ne = 0.0; /* dummy */ ne_dot = 0.0; /* dummy */ VSetPoint(&nw, 0.0, 0.0, 0.0); /* dummy */ VSetPoint(&nw_dot, 0.0, 0.0, 0.0); /* dummy */ if( g->noseAngle == GEARDOWN ){ /* * Gear down and locked. */ /* Strut attachment position, components in SWC: */ r = p->rn; r.z += p->Gn; VTransform_(&r, &AXYZtoSWC, &r); if( r.z < 1e-3 ){ /* Wheel is certainly not in contact. */ g->noseGroundContact = FALSE; ne = p->cnMax; /* FIXME: not needed */ } else { /* Possible contact with ground. Calculate oleo extension: */ ne = (ground_z - r.z) / q.z; if( ne < 0.0 ){ g->noseGroundContact = TRUE; return "nose gear smash"; } else if( ne > p->cnMax ){ /* Not in contact: */ g->noseGroundContact = FALSE; ne = p->cnMax; } else { /* In contact: */ /* Oleo extension rate: */ VCrossProd(&omega, &r, &r_dot); ne_dot = - (r_dot.z + Cg.z) / q.z - ne * q_dot.z / q.z; /* Wheel position, aircraft frame: */ nw.x = p->rn.x; nw.y = p->rn.y; nw.z = p->rn.z + p->Gn + ne; /* Wheel velocity vs. ground, components in SWC: */ nw_dot.x = r_dot.x + ne_dot * q.x + ne * q_dot.x + Cg.x; nw_dot.y = r_dot.y + ne_dot * q.y + ne * q_dot.y + Cg.y; nw_dot.z = r_dot.z + ne_dot * q.z + ne * q_dot.z + Cg.z; if( ! g->noseGroundContact && fabs(nw_dot.x) + fabs(nw_dot.y) > 1.0 && ne_dot <= 0 ){ /* First contact. */ sounds_playSound(c, sounds_Touchdown, FALSE); } g->noseGroundContact = TRUE; } } } else { /* * Gear up or not fully extended. */ g->noseGroundContact = FALSE; } /* RIGHT GEAR */ re = 0.0; /* dummy */ re_dot = 0.0; /* dummy */ VSetPoint(&rw, 0.0, 0.0, 0.0); /* dummy */ VSetPoint(&rw_dot, 0.0, 0.0, 0.0); /* dummy */ if( g->leftAngle == GEARDOWN ){ /* * Gear down and locked. */ /* Strut attachment position, components in SWC: */ r = p->rm; r.z += p->Gm; VTransform_(&r, &AXYZtoSWC, &r); if( r.z < 1e-3 ){ /* Wheel is certainly not in contact. */ g->rightGroundContact = FALSE; re = p->cmMax; /* FIXME: not needed */ } else { /* Possible contact with ground. Calculate oleo extension: */ re = (ground_z - r.z) / q.z; if( re < 0.0 ){ g->rightGroundContact = TRUE; return "right gear smash"; } else if( re > p->cmMax ){ /* Not in contact: */ g->rightGroundContact = FALSE; re = p->cmMax; } else { /* In contact: */ /* Oleo extension rate: */ VCrossProd(&omega, &r, &r_dot); re_dot = - (r_dot.z + Cg.z) / q.z - re * q_dot.z / q.z; /* Wheel position, aircraft frame: */ rw.x = p->rm.x; rw.y = p->rm.y; rw.z = p->rm.z + p->Gm + re; /* Wheel velocity vs. ground, components in SWC: */ rw_dot.x = r_dot.x + re_dot * q.x + re * q_dot.x + Cg.x; rw_dot.y = r_dot.y + re_dot * q.y + re * q_dot.y + Cg.y; rw_dot.z = r_dot.z + re_dot * q.z + re * q_dot.z + Cg.z; if( ! g->rightGroundContact && fabs(rw_dot.x) + fabs(rw_dot.y) > 1.0 && re_dot < 0 ){ /* First contact. */ sounds_playSound(c, sounds_Touchdown, FALSE); } g->rightGroundContact = TRUE; } } } else { /* * Gear up or not fully extended. */ g->rightGroundContact = FALSE; } /* LEFT GEAR */ le = 0.0; /* dummy */ le_dot = 0.0; /* dummy */ VSetPoint(&lw, 0.0, 0.0, 0.0); /* dummy */ VSetPoint(&lw_dot, 0.0, 0.0, 0.0); /* dummy */ if( g->rightAngle == GEARDOWN ){ /* * Gear down and locked. */ /* Strut attachment position, components in SWC: */ r = p->rm; r.y = -r.y; r.z += p->Gm; VTransform_(&r, &AXYZtoSWC, &r); if( r.z < 1e-3 ){ /* Wheel is certainly not in contact. */ g->leftGroundContact = FALSE; le = p->cmMax; /* FIXME: not needed */ } else { /* Possible contact with ground. Calculate oleo extension: */ le = (ground_z - r.z) / q.z; if( le < 0.0 ){ g->leftGroundContact = TRUE; return "left gear smash"; } else if( le > p->cmMax ){ /* Not in contact: */ g->leftGroundContact = FALSE; le = p->cmMax; } else { /* In contact: */ /* Oleo extension rate: */ VCrossProd(&omega, &r, &r_dot); le_dot = - (r_dot.z + Cg.z) / q.z - le * q_dot.z / q.z; /* Wheel position, aircraft frame: */ lw.x = p->rm.x; lw.y = -p->rm.y; lw.z = p->rm.z + p->Gm + le; /* Wheel velocity vs. ground, components in SWC: */ lw_dot.x = r_dot.x + le_dot * q.x + le * q_dot.x + Cg.x; lw_dot.y = r_dot.y + le_dot * q.y + le * q_dot.y + Cg.y; lw_dot.z = r_dot.z + le_dot * q.z + le * q_dot.z + Cg.z; if( ! g->leftGroundContact && fabs(lw_dot.x) + fabs(lw_dot.y) > 1.0 && le_dot < 0 ){ /* First contact. */ sounds_playSound(c, sounds_Touchdown, FALSE); } g->leftGroundContact = TRUE; } } } else { /* * Gear up or not fully extended. */ g->leftGroundContact = FALSE; } #ifdef DEBUG printf("FIXME: ne=%.0f%% re=%.0f%% le=%.0f%%\n", 100.0 * ne / p->cnMax, 100.0 * re / p->cmMax, 100.0 * le / p->cmMax); printf("FIXME: ne_dot=%f re_dot=%f le_dot=%f\n", ne_dot, re_dot, le_dot); #endif /* * Compute forces Fn,Fr,Fl (AXYZ) due to the static reaction of the wheels * against the terreain. If the terrain were perfectly smooth and clean, * this force would sustain the aircraft, but it would be impossible to * brake and to steer. * * The spring constant p->Km and the damping factor p->Dm in the inventory * refers to the two main landing gear right+left as a whole, that's why * of the 0.5 factor appearing in front of these coefficients. * * To these forces we have to add also the longitudinal friction and lateral * friction FnMu,FrMu,FlMu (AXYZ). These forces allow to brake and steer * the aircraft. */ /* NOSE GEAR: */ VSetPoint(&Fn, 0.0, 0.0, 0.0); /* Add force Fn.z (AXYZ) due to spring and damper: */ if( g->noseGroundContact ){ Fn.z = spring_and_damper_force(p->Kn, p->Dn, p->cnMax, ne, ne_dot); if( Fn.z < - 1.0 /* FIXME */ * p->emptyWeight ) return "nose gear collapsed under too high vertical load"; if( Fn.z == 0.0 ) g->noseGroundContact = FALSE; } /* Add friction and steering effects: */ if( g->noseGroundContact ){ VPoint f; double fm, deflection; /* Calculate terrain normal force f (SWC): */ fm = Fn.z * Fn.z; VTransform_(&Fn, &AXYZtoSWC, &f); VSetPoint(&f, 0, 0, fm / f.z); /* Set actual static force Fn (AXYZ): */ VReverseTransform_(&f, &AXYZtoSWC, &Fn); if( p->rn.x > p->rm.x ) /* tricycle gear */ deflection = g->noseSteeringAngle; else /* bicycle */ deflection = - g->noseSteeringAngle; skid = wheel_friction(deflection, nw_dot.x, nw_dot.y, -f.z, p->muStatic, p->muKinetic, MU_SKID, /* no brakes */ &f, "nose"); /* Convert f (SWC) in FnMu (AXYZ): */ VReverseTransform_(&f, &AXYZtoSWC, &FnMu); if( skid ){ sounds_playSound(c, sounds_Touchdown, 0); prompt_craft_print(c, "WARNING: nose wheel is skidding"); } if( fabs(FnMu.y) > 1.0 * /* FIXME */ p->emptyWeight ) return "nose gear broken under too high lateral force"; } else { /* Nose wheel isn't in contact with ground: */ VSetPoint(&FnMu, 0, 0, 0); } /* RIGHT GEAR: */ VSetPoint(&Fr, 0.0, 0.0, 0.0); /* Add force Fr.z (AXYZ) due to spring and damper: */ if( g->rightGroundContact ){ Fr.z = spring_and_damper_force(0.5*p->Km, 0.5*p->Dm, p->cmMax, re, re_dot); if( Fr.z < - 1.5 /* FIXME */ * p->emptyWeight ) return "right gear collapsed under too high vertical load"; if( Fr.z == 0.0 ) g->rightGroundContact = FALSE; } /* Add friction and braking: */ if( g->rightGroundContact ){ VPoint f; double fm; /* Calculate terrain normal force f (SWC): */ fm = Fr.z * Fr.z; VTransform_(&Fr, &AXYZtoSWC, &f); VSetPoint(&f, 0, 0, fm / f.z); /* Set actual static force Fr (AXYZ): */ VReverseTransform_(&f, &AXYZtoSWC, &Fr); skid = wheel_friction(0.0, rw_dot.x, rw_dot.y, -f.z, muStatic, muKinetic, MU_SKID, &f, "right"); VReverseTransform_(&f, &AXYZtoSWC, &FrMu); if( skid ){ sounds_playSound(c, sounds_Touchdown, 0); prompt_craft_print(c, "WARNING: right wheel is skidding"); } if( fabs(FrMu.y) > 1.0 * /* FIXME */ p->emptyWeight ) return "right gear broken under too high lateral force"; } else { /* Right wheel isn't in contact with ground: */ VSetPoint(&FrMu, 0, 0, 0); } /* LEFT GEAR: */ VSetPoint(&Fl, 0.0, 0.0, 0.0); /* Add force Fl.z (AXYZ) due to spring and damper: */ if( g->leftGroundContact ){ Fl.z = spring_and_damper_force(0.5*p->Km, 0.5*p->Dm, p->cmMax, le, le_dot); if( Fl.z < - 1.5 /* FIXME */ * p->emptyWeight ) return "left gear collapsed under too high vertical load"; if( Fl.z == 0.0 ) g->leftGroundContact = FALSE; } /* Add friction and braking: */ if( g->leftGroundContact ){ VPoint f; double fm; /* Calculate terrain normal force f (SWC): */ fm = Fl.z * Fl.z; VTransform_(&Fl, &AXYZtoSWC, &f); VSetPoint(&f, 0, 0, fm / f.z); /* Set actual static force Fl (AXYZ): */ VReverseTransform_(&f, &AXYZtoSWC, &Fl); skid = wheel_friction(0.0, lw_dot.x, lw_dot.y, -f.z, muStatic, muKinetic, MU_SKID, &f, "left"); VReverseTransform_(&f, &AXYZtoSWC, &FlMu); if( skid ){ sounds_playSound(c, sounds_Touchdown, 0); prompt_craft_print(c, "WARNING: left wheel is skidding"); } if( fabs(FlMu.y) > 1.0 * /* FIXME */ p->emptyWeight ) return "left gear broken under too high lateral force"; } else { /* Left wheel isn't in contact with ground: */ VSetPoint(&FlMu, 0, 0, 0); } /* * Here we sum up all the forces F and F*Mu at every wheel to get the total * force F (AXYZ) applyed to the CM. The result is F (AXYZ). */ F.x = Fn.x + Fl.x + Fr.x + FnMu.x + FlMu.x + FrMu.x; F.y = Fn.y + Fl.y + Fr.y + FnMu.y + FlMu.y + FrMu.y; F.z = Fn.z + Fl.z + Fr.z + FnMu.z + FlMu.z + FrMu.z; /* * Every wheel gives its contribute to the total moment M (AXYZ). */ VCrossProd(&nw, &Fn, &M); VCrossProd(&nw, &FnMu, &mt); VAdd(&M, &mt, &M); VCrossProd(&lw, &Fl, &mt); VAdd(&M, &mt, &M); VCrossProd(&lw, &FlMu, &mt); VAdd(&M, &mt, &M); VCrossProd(&rw, &Fr, &mt); VAdd(&M, &mt, &M); VCrossProd(&rw, &FrMu, &mt); VAdd(&M, &mt, &M); *gearF = F; *gearM = M; /* * Since we are inside this function, it means we are very close to the * ground. On a tricycle landing gear the tail will drag for pitch greater * than 20 DEG. * * FIXME: that's not very realistic as we should use the parameter TailExtent * of the inventory file to compute the actual maximum angle of rotation. The * roll angle should also be considered, since also wing tips can drag. */ if( (g->noseGroundContact || g->leftGroundContact || g->rightGroundContact) /* some wheel still in contact */ && (p->rn.x > p->rm.x) /* is bicycle */ && (c->curPitch > units_DEGtoRAD(20.0)) /* rotation above 20 DEG */ ) { return "rotation above 20 DEG, dragging tail to the runway"; } return NULL; } acm-6.0_20200416/src/acm/box.c0000644000000000000000000001461213173126564014072 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include #include "../util/error.h" #include "../util/memory.h" #include "pm.h" #include "inventory.h" #include "planes.h" #define box_IMPORT #include "box.h" #define BB_HDR_SIZE (sizeof(char) + sizeof(char) + sizeof(short)) #define BB_TYPE_SHORT_STATE 0x00 #define BB_TYPE_ADD_OBJECT 0x01 #define BB_TYPE_DELETE_OBJECT 0x02 #define BB_TYPE_END_OF_FRAME 0x03 typedef struct { earth_LatLonAlt w; VPoint Sg; VPoint Cg; double heading, pitch, roll; } _BBShortState; typedef struct { short type; /* craft type */ char name[64]; /* craft name */ } _BBNewObject; typedef struct { unsigned char rectype; /* black box record type */ unsigned char table; /* is it ptbl(0) or mtbl(1)? */ unsigned short id; /* player or missile index */ union { _BBShortState short_state; _BBNewObject object; } u; } BBRecord; static FILE *bbin = 0, *bbout = 0; static short rp_map[manifest_MAXPLAYERS], rm_map[manifest_MAXPROJECTILES]; static short pp_map[manifest_MAXPLAYERS], pm_map[manifest_MAXPROJECTILES]; static void newBlackBoxCraft(int id, int type, char *name) { register craft *c; register int i, max; register short *p; /* per PREfix */ if (type != CT_PLANE && type != CT_DRONE && type != CT_MISSILE && type != CT_CANNON) { printf("Invalid craft type passed to newBlackBoxCraft()\n"); } /* Initialize these vars in order to prevent warnings from gcc -Wall: */ c = NULL; max = 0; p = NULL; switch (type) { case CT_PLANE: case CT_DRONE: if ((i = planes_newPlane(name)) >= 0) { c = &ptbl[i]; c->type = type; c->flags = FL_BLACK_BOX; memory_strcpy(c->name, sizeof(c->name), name); pp_map[id] = i; } else { fprintf(stderr, "No room in player table to add another black box object.\n"); } return; /*NOTREACHED */ break; case CT_MISSILE: case CT_CANNON: c = mtbl; max = manifest_MAXPROJECTILES; p = rm_map; break; default: error_internal("type=%d", type); } for (i = 0; i < max; ++i, ++c) { if (c->type == CT_FREE) { c->type = type; c->flags = FL_BLACK_BOX; c->cinfo = inventory_craftTypeSearchByZoneAndName(NULL, name); p[id] = i; } } } void box_startRecording(void) { int i; if ((bbout = fopen("./black_box_output", "w")) == (FILE *) NULL) { fprintf(stderr, "unable to open black box recording file\n"); } for (i = 0; i < manifest_MAXPLAYERS; ++i) { rp_map[i] = -1; } for (i = 0; i < manifest_MAXPROJECTILES; ++i) { rm_map[i] = -1; } } void box_endRecording(void) { if ( bbout == NULL ) return; fclose(bbout); bbout = (FILE *) NULL; } void box_startPlayback(void) { int i; if ((bbin = fopen("./black_box_input", "r")) == (FILE *) NULL) { fprintf(stderr, "unable to open black box playback file\n"); } for (i = 0; i < manifest_MAXPLAYERS; ++i) { pp_map[i] = -1; } for (i = 0; i < manifest_MAXPROJECTILES; ++i) { pm_map[i] = -1; } } /* * Update items under the control of black box playback */ void box_input(void) { register int i; BBRecord rec; craft *c; if (bbin) { while (fread((char *) &rec, BB_HDR_SIZE, 1, bbin) == 1) { c = (rec.table == 0) ? &ptbl[pp_map[rec.id]] : &mtbl[pm_map[-(int) rec.id]]; switch (rec.rectype) { case BB_TYPE_SHORT_STATE: fread((char *) &rec.u.short_state, sizeof(rec.u.short_state), 1, bbin); if (pp_map[rec.id] == -1) break; c->prevSg = c->Sg; c->w = rec.u.short_state.w; c->Sg = rec.u.short_state.Sg; c->Cg = rec.u.short_state.Cg; c->curRoll = rec.u.short_state.roll; c->curPitch = rec.u.short_state.pitch; c->curHeading = rec.u.short_state.heading; break; case BB_TYPE_ADD_OBJECT: fread((char *) &rec.u.object, sizeof(rec.u.object), 1, bbin); newBlackBoxCraft(rec.id, rec.u.object.type, rec.u.object.name); break; case BB_TYPE_DELETE_OBJECT: pp_map[rec.id] = -1; c->kill(c, "(FIXME)"); break; case BB_TYPE_END_OF_FRAME: return; default: fprintf(stderr, "unknown rectype in\ black box recording: %d\n", rec.rectype); fclose(bbin); bbin = (FILE *) NULL; break; } } fclose(bbin); bbin = (FILE *) NULL; for (i = 0; i < manifest_MAXPLAYERS; ++i) { if (pp_map[i] != CT_FREE) ptbl[pp_map[i]].kill(&ptbl[pp_map[i]], "(FIXME)"); } } } /* * Write out black box records */ void box_output(void) { register int i; register craft *c; BBRecord rec; if (bbout) { for (i = 0, c = ptbl; i < manifest_MAXPLAYERS; ++i, ++c) { if (c->type != CT_FREE) { if (rp_map[i] == -1) { rp_map[i] = i; rec.rectype = BB_TYPE_ADD_OBJECT; rec.table = 0; rec.id = i; rec.u.object.type = c->type; memory_strcpy(rec.u.object.name, sizeof(rec.u.object.name), c->cinfo->name); fwrite((char *) &rec, BB_HDR_SIZE, 1, bbout); fwrite((char *) &rec.u.object, sizeof(rec.u.object), 1, bbout); } rec.rectype = BB_TYPE_SHORT_STATE; rec.table = 0; rec.id = i; rec.u.short_state.w = c->w; rec.u.short_state.Sg = c->Sg; rec.u.short_state.Cg = c->Cg; rec.u.short_state.roll = c->curRoll; rec.u.short_state.pitch = c->curPitch; rec.u.short_state.heading = c->curHeading; fwrite((char *) &rec, BB_HDR_SIZE, 1, bbout); fwrite((char *) &rec.u.object, sizeof(rec.u.short_state), 1, bbout); } } for (i = 0; i < manifest_MAXPROJECTILES; ++i) { rm_map[i] = -1; } rec.rectype = BB_TYPE_END_OF_FRAME; rec.id = 0; fwrite((char *) &rec, BB_HDR_SIZE, 1, bbout); } } void box_killPlayer(int id) { BBRecord rec; if (bbout) { rec.rectype = BB_TYPE_DELETE_OBJECT; rec.id = id; fwrite((char *) &rec, BB_HDR_SIZE, 1, bbout); } } acm-6.0_20200416/src/acm/mouse.h0000644000000000000000000000326113063670320014425 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #ifndef _mouse_h #define _mouse_h #include "pm.h" #ifdef mouse_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Mouse-to-command response law. The current position of the mouse pointer in * the window is mapped to the range [-1,1] in horizontal and vertical to set * ailerons and elevator rotation, respectively. The mapping ranges from linear * (very fast response to user input, low precision) to cubic (very slow response, * high precision). Ailerons and elevator are in thei neutral position when the * mouse pointer is exactly in the middle of the window. */ enum { /** Linear. */ mouse_FAST, /** Quadratic. */ mouse_NORMAL, /** Cubic. */ mouse_PRECISE } mouse_stick_mode; /** * Get stick input from mouse and set c->pitchComm, c->rollComm, and c->steerComm * as values in the range [-1.0 ... +1.0]. If detached, keeps the current * values. */ void mouse_getPosition(craft * c, viewer * u); #undef EXTERN #endif acm-6.0_20200416/src/acm/air.h0000644000000000000000000000377713646045023014067 0ustar rootroot/* * acm : an aerial combat simulator for X * Air and wind properties module. * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /** * Air data properties routines. * * @author Riley Rainey * @license GNU GPL * @version $Date: 2020/01/08 05:58:14 $ * @file */ #ifndef _air_h #define _air_h #include "../V/Vlibmath.h" #ifdef air_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Calculated air properties. */ typedef struct { /** Density [slug/ft^3]. */ double rho; /** Pressure [lbf/ft^2]. */ double p; /** Temperature [Rankine]. */ double t; /** Speed of sound [ft/s]. */ double mach1; } air_Properties; /** * Calculate air properties at the given altitude in standard atmosphere. * @param air Store here the air properties. * @param h Altitude [ft]. */ EXTERN void air_update(air_Properties * air, double h); /** * Sets wind direction. Default: no wind. * @param wd Direction from which the wind come from [RAD]. * @param wv Wind velocity [ft/s]. */ EXTERN void air_set_wind(double wd, double wv); /** * Set maximum gust intensity. Default: no gust. * @param gust_max Max gust intensity [ft/s]. */ EXTERN void air_set_gust(double gust_max); /** * Return wind speed (ft/s) at the given altitude (m). * @param h Altitude [m]. * @return Wind speed vector. */ EXTERN VPoint * air_get_wind(double h); #undef EXTERN #endif acm-6.0_20200416/src/acm/pm.c0000644000000000000000000004504313172244202013705 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. * */ #include #include #include "../util/memory.h" #define pm_IMPORT #include "pm.h" #include "aps.h" #include "damage.h" #include "dis_if.h" #include "gear.h" #include "planes.h" #include "prompt.h" #include "terrain.h" #include "../util/units.h" #include "../wmm/wmm.h" #ifdef WINNT #include #endif static double CM, CN, C_Y; /* * twoorder: solve linear second-order differential equation with initial * conditions known. * * y_dot_dot - d * y_dot - k * y - q = 0 * * given the initial conditions: * * y(0) == y. * y_dot(0) == v. * * Results are *newy=y(deltaT) and *newv=y_dot(deltaT) for deltaT seconds * into the future. * */ static void twoOrder(double k, double d, double q, double y, double v, double *newy, double *newv) { double qk, s, s1, s2, t, ac, c1, c2, exp_s1_x, exp_s2_x; /* Prevent numerical instabilities: since y,v are pitch/yaw angle and its derivative, it would be perfectly useless to consider factors too small. */ if( fabs(d) < 1e-9 ) d = 0.0; if( fabs(k) < 1e-9 ) k = 0.0; if( k == 0.0 ){ if( d == 0.0 ){ /* The equation reduces to: y_dot_dot = q. */ *newy = 0.5 * q * deltaT * deltaT + v * deltaT + y; *newv = q * deltaT + v; } else { /* The equation reduces to: y_dot_dot - d*y_dot - q = 0. */ *newy = (v + q/d)/d*exp(d*deltaT) - q/d*deltaT + y - (v + q/d)/d; *newv = (v + q/d)*exp(d*deltaT) - q/d; } *newy = y; *newv = v; return; } qk = q/k; ac = d * d + 4.0 * k; if ( ac > 0.0 ) { /* The general solution for ac > 0 is: y = c1 * exp(s1*x) + c2 * exp(s2*x) - q/k where: s1 = ...see code... s2 = ...see code... c1 = ...see code... c2 = ...see code... */ t = sqrt(ac); s1 = (d + t) * 0.5; s2 = (d - t) * 0.5; c1 = (-s2*y - s2*qk + v) / t; c2 = ( s1*y + s1*qk - v) / t; exp_s1_x = exp(s1 * deltaT); exp_s2_x = exp(s2 * deltaT); *newy = c1 * exp_s1_x + c2 * exp_s2_x - qk; *newv = c1 * s1 * exp_s1_x + c2 * s2 * exp_s2_x; } else if (ac < 0.0) { /* The general solution for ac < 0 is: y = exp(s*x) * (c1 * cos(t*x) + c2 * sin(t*x)) - qk where: s = d/2 t = sqrt(-ac)/2 c1 = y0 + qk c2 = (v-c1*s)/t */ double cos_t_x, sin_t_x; s = d * 0.5; t = sqrt(-ac) * 0.5; exp_s1_x = exp(s*deltaT); cos_t_x = cos(t*deltaT); sin_t_x = sin(t*deltaT); c1 = y + qk; c2 = (v - c1*s ) / t; *newy = exp_s1_x * ( c1*cos_t_x + c2*sin_t_x ) - qk; *newv = exp_s1_x * ( (c1*s+c2*t) * cos_t_x + (c2*s-c1*t) * sin_t_x ); } else { /* The general solution for ac = 0 is: y = (c1 + c2*x) * exp(s*x) - qk where: s = d/2 c1 = y0 + qk c2 = v - c1*s */ s = 0.5*d; c1 = y + qk; c2 = v - c1*s; exp_s1_x = exp(s*deltaT); *newy = (c1 + c2*deltaT) * exp_s1_x - qk; *newv = (c2 + (c1 + c2*deltaT)*s) * exp_s1_x; } } /* * calcCoefficients : Calculate CLift and friends */ static void calcCoefficients(craft * c, double *CLift, double *CDrag) { double CDAlpha, CDBeta; craftType *p = c->cinfo; double h, base, k; /* * We used to interpolate these values, but now use several characteristic * equations to compute these values for a given alpha value. The basic * formulas are: * * * C = C + (alpha * (C + sin(curFlap) * cFlap )) * L LOrigin LSlope * * * C = zero-lift-wave-and-body-drag + induced-drag + * D speed-brake-drag + flap drag + landing-gear-drag + * drag-based-on-sideslip * * There are independent equations defining drag resulting from alpha * and beta values. The hypoteneuse of those two values becomes the * resultant CDrag value. */ *CLift = interpolate_value(p->CLift, c->alpha); if( damage_isFunctioning(c, SYS_FLAPS) ) *CLift += sin(c->curFlap) * p->cFlap; /* Rough estimation of the ground effect correction to the CLift: FIXME: also the drag coeff. should be corrected */ /* Height of the wing aerodynamic center above the ground (ft): */ h = units_METERStoFEET(c->w.z - terrain_localAltitude(c)) + p->wingh; /* Limit ground effect, or we would "float" over the terrain... */ if( h < 1.0 ) h = 1.0; base = h / p->wings; /* Compute the expensive pow() only if k will be > 1.001: */ if ( base < 8.5 ) { /* Ground effect correction coefficient to the CLift: */ k = 1.0 + 0.025 * pow(base, -1.5); *CLift *= k; } CM = p->cmSlope + c->damageCM; CDAlpha = interpolate_value(p->CDb, c->mach) + *CLift * *CLift / (M_PI * p->aspectRatio); if( damage_isFunctioning(c, SYS_SPEEDBRAKE ) ) CDAlpha += sin(c->curSpeedBrake) * p->cSpeedBrake; if( damage_isFunctioning(c, SYS_FLAPS) ) CDAlpha += sin(c->curFlap) * p->cFlapDrag; CDAlpha += gear_get_drag(c); if (fabs(c->beta) > p->betaStall) CN = interpolate_value(p->CnBeta, fabs(c->alpha)) * fabs(sin(c->beta)); else CN = interpolate_value(p->CnBeta, fabs(c->alpha)); CDBeta = p->CDBOrigin + p->CDBFactor * sin(c->beta + p->CDBPhase); *CDrag = sqrt(CDAlpha * CDAlpha + CDBeta * CDBeta); C_Y = p->CYbeta * c->beta /* * fabs(cos(c->beta))*/; } double pm_heading(VPoint * x) { return atan2(x->y, x->x); } void pm_euler(craft * c) { VMatrixToEuler(&c->AXYZtoNED, &c->curRoll, &c->curPitch, &c->curHeading); } void pm_calcGForces(craft * c, VPoint * f, double w) { VPoint t, t1; double m_slugs; m_slugs = w / units_earth_g; t = *f; t.x = t.x / m_slugs; t.y = t.y / m_slugs; t.z = t.z / m_slugs; VReverseTransform_(&t, &c->AXYZtoNED, &c->linAcc); t.z -= units_earth_g; VReverseTransform_ (&t, &c->AXYZtoNED, &t1); c->G.x = t1.x / units_earth_g; c->G.y = t1.y / units_earth_g; c->G.z = t1.z / units_earth_g; } static void calcAlphaBetaVT(craft * c) { VPoint C, air, *wind; double delta; wind = air_get_wind(c->w.z); air.x = c->Cg.x + wind->x; air.y = c->Cg.y + wind->y; air.z = c->Cg.z + wind->z; VReverseTransform_(&air, &c->AXYZtoNED, &C); c->alpha = atan2(C.z, sqrt(C.y * C.y + C.x * C.x)); c->beta = atan2(C.y, C.x); c->VT = VMagnitude(&C); delta = c->air.p / units_P0; c->IAS = C.x * sqrt(c->air.rho / units_RHO_0) /* compressibility correction */ /* FIXME: mach no. is in the direction of VT, not x ! */ * (1.0 + 1.0/8*(1.0 - delta)*c->mach*c->mach); if (c->IAS < 0.0) c->IAS = 0.0; } static double elevatorSetting(craft * c) { double s; s = c->pitchComm + aps_get_delta_elevator(c) + c->SeTrim; if (s < -1.0) s = -1.0; if (s > +1.0) s = +1.0; c->Se = s; return s; } static double aileronSetting(craft * c) { double s; if( ! damage_isFunctioning(c, SYS_WINGS) ) return 0.0; s = c->rollComm + aps_get_delta_ailerons(c) + c->SaTrim; if (s < -1.0) s = -1.0; if (s > +1.0) s = +1.0; c->Sa = s; return s; } static double rudderSetting(craft * c) { double s; s = c->rudderComm + aps_ac_get_delta_rudder(c); if (s < -1.0) s = -1.0; if (s > +1.0) s = +1.0; c->Sr = s; return s; } char * pm_flightCalculations(craft * c) { craftType *p = c->cinfo; double qS, s, CLift, CDrag, Sr; double ClBeta; double FLift, FDrag, FWeight, FSideForce; double deltaRoll, deltaPitch, deltaYaw; double y, newy; double xa, inertia, torque, xd, r0; double dNorth, dEast, dmag, dHeading_rad; double mass_slugs; VPoint F, M, Fg, aeroF, aeroM, gearF, gearM, thrF, thrM; VMatrix mtx, new_AXYZtoNED; dis_entity_appearance appearance; char *killReason; air_update(&c->air, units_METERStoFEET(c->w.z)); c->prevSg = c->Sg; calcAlphaBetaVT(c); Sr = rudderSetting(c); /* * A note about thrust: Normal thrust diminishes in proportion to the * decrease in air density. */ c->mach = c->VT / c->air.mach1; appearance = dis_if_getEntityAppearance(c->disId); appearance &= ~(DISAppearanceAirAfterburnerOn | DISAppearancePlatformPowerplantOn); /* Update thrust reverse position */ if( c->thrust_reverse_on ){ /* deploy thrust reverser within 2 s */ c->thrust_reverse_pos -= deltaT / 2.0; if( c->thrust_reverse_pos < -0.5 ) c->thrust_reverse_pos = -0.5; } else { /* retract thrust reverser within 2 s */ c->thrust_reverse_pos += deltaT / 2.0; if( c->thrust_reverse_pos > 1.0 ) c->thrust_reverse_pos = 1.0; } /* Total engine force and moment. */ c->curThrust = (*p->thrust) (c); if (c->flags & FL_AFTERBURNER) { appearance |= DISAppearanceAirAfterburnerOn; } appearance |= DISAppearancePlatformPowerplantOn; dis_if_setEntityAppearance(c->disId, appearance); VSetPoint(&thrF, c->thrust_reverse_pos * c->curThrust, 0.0, 0.0); VSetPoint(&thrM, 0.0, 0.0, 0.0); /* Compute the resultant aerodynamic force vector on the aircraft. By the way, the variable "qS" should more properly be named "qS" -- it is the dynamic pressure times S, the reference wing area. */ calcCoefficients(c, &CLift, &CDrag); ClBeta = interpolate_value(p->ClBeta, fabs(c->alpha)); qS = c->air.rho * p->wingS * c->VT * c->VT * 0.5; if( damage_isFunctioning(c, SYS_WINGS) ) FLift = CLift * qS; else FLift = 0.5 * CLift * qS; FDrag = CDrag * qS; FSideForce = C_Y * qS; FWeight = p->emptyWeight + c->fuel + c->payload; /* Detect wings structural maximum limit. Note that FLift sign is reversed respect to the aircraft z axis so that FLift is positive when the craft is pulled up. */ if( FLift > p->maxLoadZPositive ){ c->damageBits |= SYS_WINGS | SYS_FLAPS | SYS_SPEEDBRAKE | SYS_HYD1 | SYS_HYD2; prompt_craft_print(c, "WINGS FAILURE due to excessive positive load"); } else if( FLift < - p->maxLoadZNegative ){ c->damageBits |= SYS_WINGS | SYS_FLAPS | SYS_SPEEDBRAKE | SYS_HYD1 | SYS_HYD2; prompt_craft_print(c, "WINGS FAILURE due to excessive negative load"); } /* Warn the pilot when the wings load exceeds 75% of maximum load. */ if( FLift > 0.75*p->maxLoadZPositive || FLift < -0.75 * p->maxLoadZNegative ) c->damageBits |= FLAG_MAX_G_LOAD; else c->damageBits &= ~FLAG_MAX_G_LOAD; /* * Set stall warning flag. */ if( ! gear_allWheelsGroundContact(c) && c->alpha > c->cinfo->alpha_stall ) c->damageBits |= FLAG_STALL_WARN; else c->damageBits &= ~FLAG_STALL_WARN; /* Total aerodynamic force and moment. These expressions convert lift and drag forces from wind axes to the aircraft fixed axes. The conversion is based on the wind to aircraft transformation matrix supplied in "Airplane Design" by Donald Crawford (page 90). */ VSetPoint(&aeroF, FLift * sin(c->alpha) - FDrag * cos(c->alpha) * cos(c->beta), - FDrag * sin(c->beta) + FSideForce, -FLift * cos(c->alpha) - FDrag * cos(c->beta) * sin(c->alpha)); /* * Aerodynamic torque (for future improvements, for example engine torque, * landing gear torque, etc.): */ VSetPoint(&aeroM, 0.0, 0.0, 0.0); /* Detect if speed is greater than the maximum allowed speed Vne: */ if( p->Vne > 0.0 && c->IAS > units_KTtoFPS(p->Vne) && (c->damageBits & SYS_WINGS) == 0 ){ c->damageBits |= SYS_WINGS | SYS_FLAPS | SYS_SPEEDBRAKE; prompt_craft_print(c, "WINGS FAILURE due to excessive airspeed"); } /* With flaps deployed, detect if speed is greater then the maximum allowed speed Vfe: */ if( p->Vfe > 0.0 && c->curFlap > 0.0 && c->IAS > units_KTtoFPS(p->Vfe) && (c->damageBits & SYS_WINGS) == 0 ){ c->damageBits |= SYS_FLAPS; c->curFlap = 0.0; c->flapSetting = 0.0; prompt_craft_print(c, "FLAPS FAILURE due to excessive airspeed"); } /* * Compute forces and moments due to the wheels friction on the terrain */ killReason = gear_ground_dynamics(c, &gearF, &gearM); if( killReason != NULL ) return killReason; /* Total force and moment. FIXME: weight still missing. */ F.x = aeroF.x + gearF.x + thrF.x; F.y = aeroF.y + gearF.y + thrF.y; F.z = aeroF.z + gearF.z + thrF.z; M.x = aeroM.x + gearM.x + thrM.x; M.y = aeroM.y + gearM.y + thrM.y; M.z = aeroM.z + gearM.z + thrM.z; /* * Compute fuel consumption */ c->fuel -= planes_fuelUsed(c) + c->leakRate * deltaT; if (c->fuel < 0.0) c->fuel = 0.0; /* * Resolve roll-axis (X-axis) changes */ /* FIXME: to avoid divisions by zero, c->VT cannot be == 0, that's why of this 0.001 term. */ xa = p->wings * p->wings * p->wingS * c->air.rho * (c->VT + 0.001) * p->Clp; inertia = p->I.m[0][0]; /* FIXME: the momentum M is inserted in a quite arbitrary point, check if this is the correct one. */ torque = qS * p->wings * 2.0 * (p->Clda * - aileronSetting(c) * p->maxAileron + ClBeta * c->beta + p->Cldr * Sr * p->maxRudder) //+ M.x /* FIXME: check */ + c->damageCL * qS; xd = c->p + torque / xa; r0 = xd * inertia / xa; deltaRoll = xd * inertia / xa * exp(xa / inertia * deltaT) - deltaT * torque / xa - r0; //c->p = xd * exp(xa / inertia * deltaT) - torque / xa; c->p = xd * exp(xa / inertia * deltaT) - torque / xa + gearM.x / inertia * deltaT; /* * Resolve pitch-axis (Y-axis) changes */ y = c->alpha + elevatorSetting(c) * p->effElevator; twoOrder(CM * qS * p->c / p->I.m[1][1], (0.25 * p->wingS * c->air.rho * p->c * p->c * c->VT * p->Cmq) / p->I.m[1][1], M.y / p->I.m[1][1], y, c->q, &newy, &(c->q)); deltaPitch = newy - y; /* * Resolve yaw-axis (Z-axis) changes. * * We do some trickery here. * If the absolute value of the sideslip angle is greater than 90 degrees, * we trick the code into believing that the sideslip angle is the negative * of its reciprocal value (e.g. -176 becomes -4 degrees). We do this with * the (somewhat inaccurate) assumption that the CN value for that angle is * roughly equal to the other. */ y = Sr * p->effRudder - c->beta; if (y > M_PI / 2.0) { y = M_PI - y; } else if (y < -M_PI / 2.0) { y = -M_PI - y; } s = p->wings; twoOrder(CN * qS * s / p->I.m[2][2], (p->wingS * c->air.rho * s * s * c->VT * p->Cnr) / p->I.m[2][2], M.z / p->I.m[2][2], y, c->r, &newy, &(c->r)); deltaYaw = newy - y; /* * Compute new aircraft trihedral, but don't set it yet. */ VEulerToMatrix(deltaRoll, deltaPitch, deltaYaw, &mtx); VMatrixMultByRank(&mtx, &c->AXYZtoNED, &new_AXYZtoNED, 3); /* * Transform the total force F in AXYZ into Fg in NED and add weight */ VTransform_(&F, &c->AXYZtoNED, &Fg); Fg.z += FWeight; pm_calcGForces(c, &Fg, FWeight); /* * Update our position (in flight mode). */ mass_slugs = FWeight / units_earth_g; dNorth = units_FEETtoMETERS(c->Cg.x * deltaT + Fg.x / mass_slugs * halfDeltaTSquared); dEast = units_FEETtoMETERS(c->Cg.y * deltaT + Fg.y / mass_slugs * halfDeltaTSquared); c->w.z -= units_FEETtoMETERS(c->Cg.z * deltaT + Fg.z / mass_slugs * halfDeltaTSquared); dmag = sqrt(dNorth * dNorth + dEast * dEast); dHeading_rad = 0.0; earth_updateLatLonEx (&c->w, dNorth / dmag, dEast / dmag, dmag, &dHeading_rad); /* * Update velocity vector based on acceleration */ c->Cg.x += Fg.x / mass_slugs * deltaT; c->Cg.y += Fg.y / mass_slugs * deltaT; c->Cg.z += Fg.z / mass_slugs * deltaT; /* * Now rotate the trihedral and velocity vector to reflect the change * in heading at the new spheroid location. */ VIdentMatrix( &mtx ); VRotate( &mtx, ZRotation, dHeading_rad ); VMatrixMultByRank( &mtx, &new_AXYZtoNED, &c->AXYZtoNED, 3 ); c->AXYZtoNED = new_AXYZtoNED; VTransform_(&c->Cg, &mtx, &c->Cg); pm_euler(c); if( c->w.z - terrain_localAltitude(c) <= 0.0 ){ if( ! damage_isFunctioning(c, SYS_WINGS) ) return "crash due to structural failure"; else if( c->Cg.z > 30.0 /* ft/s */ ) return "crash on ground"; else return "main landing gear wasn't down and locked or it was damaged"; } earth_LatLonAltToXYZ(&c->w, &c->Sg); earth_generateWorldToLocalMatrix(&c->w, &c->XYZtoNED); aps_update( c ); return NULL; } double pm_normalize_roll(double roll) { while( roll < M_PI ) roll += 2*M_PI; while( roll > M_PI ) roll -= 2*M_PI; return roll; } double pm_normalize_pitch(double pitch) { while( pitch < -M_PI/2 ) pitch += 2*M_PI; while( pitch > M_PI/2 ) pitch -= 2*M_PI; return pitch; } double pm_normalize_yaw(double yaw) { while( yaw < 0 ) yaw += 2*M_PI; while( yaw >= 2*M_PI ) yaw -= 2*M_PI; return yaw; } void pm_hud_strings_alloc(craft *c) { int i; for( i=0; i<6; i++ ){ if( c->leftHUD[i] == NULL ) c->leftHUD[i] = memory_allocate(32, NULL); c->leftHUD[i][0] = '\0'; if( c->rightHUD[i] == NULL ) c->rightHUD[i] = memory_allocate(32, NULL); c->rightHUD[i][0] = '\0'; } } void pm_hud_strings_free(craft *c) { int i; for( i=0; i<6; i++ ){ memory_dispose(c->leftHUD[i]); c->leftHUD[i] = NULL; memory_dispose(c->rightHUD[i]); c->rightHUD[i] = NULL; } } void pm_thrust_reverse_toggle(craft *c) { if( c->thrust_reverse_on ){ c->thrust_reverse_on = FALSE; /* thrust setting must be idle to activate reverser: */ } else if( c->cinfo->hasThrustReverser && c->throttleComm <= 32768 * 25 / 100 ){ c->thrust_reverse_on = TRUE; } } void pm_after_burner_toggle(craft *c) { if ( c->cinfo->maxThrust != c->cinfo->maxABThrust ) c->flags ^= FL_AFTERBURNER; } void pm_after_burner_on(craft *c) { if ( c->cinfo->maxThrust != c->cinfo->maxABThrust ) c->flags |= FL_AFTERBURNER; } void pm_after_burner_off(craft *c) { c->flags &= ~FL_AFTERBURNER; } double pm_mag_heading(craft * c) { // Update local magnetic declination. if (curTime >= c->updActualMagneticField) { wmm_MagneticField mf; wmm_getMagneticField(0.0, c->w.latitude, c->w.longitude, c->w.z, &mf); VSetPoint(&c->actualMagneticField, mf.X, mf.Y, mf.Z); c->actualLocalVAR = - mf.Decl; // Update mag. var. every 1 NM or every 10 s, whichever comes first: double dt = units_NmToFeetFactor / (1.0 + c->VT); if( dt > 10.0 ) dt = 10.0; c->updActualMagneticField = curTime + dt; } // Indicated magnetic field smoothly follows the calculated one: if (curTime >= c->updIndicatedMagneticField) { double k = 0.01; c->indicatedMagneticField.x += k * (c->actualMagneticField.x - c->indicatedMagneticField.x); c->indicatedMagneticField.y += k * (c->actualMagneticField.y - c->indicatedMagneticField.y); c->indicatedMagneticField.z += k * (c->actualMagneticField.z - c->indicatedMagneticField.z); c->indicatedLocalVAR += k * (c->actualLocalVAR - c->indicatedLocalVAR); c->updIndicatedMagneticField = curTime + 0.1; } return pm_normalize_yaw( c->curHeading + c->indicatedLocalVAR ); } acm-6.0_20200416/src/acm/runway.c0000644000000000000000000005165313166536624014641 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1997 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /* * Runway markings are designed to conform to FAA AC 150/5340-1G * dated 9/27/93. * * 2006-04-24 Added runway numbers. Not sure if it complies to something, * but it looks good :-) [U.S.] */ #include #include #include #include "../util/memory.h" #include "../V/Vlibmath.h" #include "../util/units.h" #define runway_IMPORT #include "runway.h" #define CENTERLINE_WIDTH units_FEETtoMETERS(3.0) #define CENTERLINE_LENGTH units_FEETtoMETERS(120.0) #define CENTERLINE_GAP units_FEETtoMETERS(80.0) #define THRESHOLD_STRIPE_WIDTH units_FEETtoMETERS(5.75) #define THRESHOLD_STRIPE_LENGTH units_FEETtoMETERS(150.0) #define THRESHOLD_STRIPE_X_OFFSET units_FEETtoMETERS(20.0) #define THRESHOLD_STRIPE_Y_OFFSET units_FEETtoMETERS(3.0) #define THRESHOLD_STRIPE_MARGIN units_FEETtoMETERS(5.75) #define FIXED_MARKER_LENGTH units_FEETtoMETERS(150.0) #define FIXED_MARKER_WIDTH units_FEETtoMETERS(30.0) #define FIXED_MARKER_Y_OFFSET units_FEETtoMETERS(3.0) #define FIXED_MARKER_X_OFFSET units_FEETtoMETERS(1000.0) #define RUNWAY_COLOR "#222" #define WHITE_PAINT "#ccc" #define RUNWAY_CULL_DISTANCE 20000.0 /* m */ #define MARKING_CULL_DISTANCE 5000.0 /* m */ /* Utilities to draw the runway name --------------------------------- Every char is defined inside a grid of 15x20 points, then scaled according to CHAR_SCALE_X and CHAR_SCALE_Y to buil a polygon. */ #define MAX_POINTS_PER_CHAR 20 /* max vertex per char polygon */ #define CHAR_SCALE_X 0.3 /* grid-to-meters width scale factor */ #define CHAR_SCALE_Y 1.0 /* grid-to-meters height scale factor */ #define CHAR_WIDTH (15*CHAR_SCALE_X) /* total char width (meters) */ #define CHAR_HEIGHT (20*CHAR_SCALE_Y) /* total char height (meters) */ #define CHAR_MARGIN_X 2.0 /* inter-char spacing (meters) */ #define CHAR_MARGIN_Y 6.0 /* inter-line spacing (meters) */ #define CHAR_X_OFFSET (THRESHOLD_STRIPE_X_OFFSET + THRESHOLD_STRIPE_LENGTH + 12.0) /* X offset of the chars from the threshold stripes (meters) */ #define CHAR_DEFAULT '/' typedef struct { int np; int xy[2*MAX_POINTS_PER_CHAR]; } Character; /** * The entry no. i is the ASCII char code i+32. */ static Character ** characters = NULL; static VColor_Type *runwayColor, *whitePaintColor; static void runway_cleanup() { int i; if( characters == NULL ) return; for( i=0; i<128-32; i++ ) if( characters[i] != NULL ) memory_dispose(characters[i]); memory_dispose(characters); characters = NULL; } /** * Fill-in the array of the chars 'characters'. It is called automatically * by BuildChar(). * Actually only the digits and the letters L,C,R are defined, and all the * other chars are displayed as '/'. */ static void InitBuildChar() { Character *s; int i; characters = memory_allocate((128-32)*sizeof(Character *), NULL); for ( i=0; i<128-32; i++ ) { characters[i] = NULL; } /* "/" */ s = memory_allocate(sizeof(Character), NULL); s->np = 4; s->xy[0] = 0; s->xy[1] = 3; s->xy[2] = 3; s->xy[3] = 0; s->xy[4] = 15; s->xy[5] = 17; s->xy[6] = 12; s->xy[7] = 20; characters['/'-32] = s; /* "0" and "O" */ s = memory_allocate(sizeof(Character), NULL); s->np = 13; s->xy[0] = 0; s->xy[1] = 4; s->xy[2] = 3; s->xy[3] = 0; s->xy[4] = 12; s->xy[5] = 0; s->xy[6] = 15; s->xy[7] = 4; s->xy[8] = 15; s->xy[9] = 16; s->xy[10] = 12; s->xy[11] = 20; s->xy[12] = 3; s->xy[13] = 20; s->xy[14] = 0; s->xy[15] = 16; s->xy[16] = 0; s->xy[17] = 4; s->xy[18] = 4; s->xy[19] = 4; s->xy[20] = 4; s->xy[21] = 16; s->xy[22] = 11; s->xy[23] = 16; s->xy[24] = 11; s->xy[25] = 4; characters['0'-32] = s; characters['O'-32] = memcpy(memory_allocate(sizeof(Character), NULL), s, sizeof(Character)); /* "1" */ s = memory_allocate(sizeof(Character), NULL); s->np = 6; s->xy[0] = 6; s->xy[1] = 0; s->xy[2] = 9; s->xy[3] = 0; s->xy[4] = 9; s->xy[5] = 20; s->xy[6] = 6; s->xy[7] = 20; s->xy[8] = 4; s->xy[9] = 15; s->xy[10] = 6; s->xy[11] = 15; characters['1'-32] = s; /* "2" */ s = memory_allocate(sizeof(Character), NULL); s->np = 16; s->xy[0] = 15; s->xy[1] = 0; s->xy[2] = 15; s->xy[3] = 3; s->xy[4] = 5; s->xy[5] = 3; s->xy[6] = 15; s->xy[7] = 11; s->xy[8] = 15; s->xy[9] = 15; s->xy[10] = 10; s->xy[11] = 20; s->xy[12] = 4; s->xy[13] = 20; s->xy[14] = 0; s->xy[15] = 15; s->xy[16] = 0; s->xy[17] = 13; s->xy[18] = 3; s->xy[19] = 13; s->xy[20] = 5; s->xy[21] = 16; s->xy[22] = 9; s->xy[23] = 16; s->xy[24] = 11; s->xy[25] = 14; s->xy[26] = 11; s->xy[27] = 11; s->xy[28] = 0; s->xy[29] = 3; s->xy[30] = 0; s->xy[31] = 0; characters['2'-32] = s; /* "3" */ s = memory_allocate(sizeof(Character), NULL); s->np = 18; s->xy[0] = 0; s->xy[1] = 5; s->xy[2] = 0; s->xy[3] = 2; s->xy[4] = 3; s->xy[5] = 0; s->xy[6] = 12; s->xy[7] = 0; s->xy[8] = 15; s->xy[9] = 2; s->xy[10] = 15; s->xy[11] = 8; s->xy[12] = 12; s->xy[13] = 11; s->xy[14] = 15; s->xy[15] = 14; s->xy[16] = 15; s->xy[17] = 20; s->xy[18] = 0; s->xy[19] = 20; s->xy[20] = 0; s->xy[21] = 16; s->xy[22] = 11; s->xy[23] = 16; s->xy[24] = 8; s->xy[25] = 12; s->xy[26] = 8; s->xy[27] = 9; s->xy[28] = 11; s->xy[29] = 7; s->xy[30] = 11; s->xy[31] = 3; s->xy[32] = 4; s->xy[33] = 3; s->xy[34] = 4; s->xy[35] = 5; characters['3'-32] = s; /* "4" */ s = memory_allocate(sizeof(Character), NULL); s->np = 14; s->xy[0] = 8; s->xy[1] = 0; s->xy[2] = 12; s->xy[3] = 0; s->xy[4] = 12; s->xy[5] = 4; s->xy[6] = 15; s->xy[7] = 4; s->xy[8] = 15; s->xy[9] = 8; s->xy[10] = 12; s->xy[11] = 8; s->xy[12] = 12; s->xy[13] = 20; s->xy[14] = 8; s->xy[15] = 20; s->xy[16] = 0; s->xy[17] = 8; s->xy[18] = 0; s->xy[19] = 4; s->xy[20] = 8; s->xy[21] = 4; s->xy[22] = 8; s->xy[23] = 8; s->xy[24] = 5; s->xy[25] = 8; s->xy[26] = 8; s->xy[27] = 12; characters['4'-32] = s; /* "5" */ s = memory_allocate(sizeof(Character), NULL); s->np = 14; s->xy[0] = 1; s->xy[1] = 0; s->xy[2] = 12; s->xy[3] = 0; s->xy[4] = 14; s->xy[5] = 2; s->xy[6] = 14; s->xy[7] = 10; s->xy[8] = 12; s->xy[9] = 12; s->xy[10] = 5; s->xy[11] = 12; s->xy[12] = 5; s->xy[13] = 16; s->xy[14] = 14; s->xy[15] = 16; s->xy[16] = 14; s->xy[17] = 20; s->xy[18] = 1; s->xy[19] = 20; s->xy[20] = 1; s->xy[21] = 8; s->xy[22] = 10; s->xy[23] = 8; s->xy[24] = 10; s->xy[25] = 4; s->xy[26] = 1; s->xy[27] = 4; characters['5'-32] = s; /* "6" */ s = memory_allocate(sizeof(Character), NULL); s->np = 15; s->xy[0] = 0; s->xy[1] = 2; s->xy[2] = 3; s->xy[3] = 0; s->xy[4] = 12; s->xy[5] = 0; s->xy[6] = 15; s->xy[7] = 2; s->xy[8] = 15; s->xy[9] = 11; s->xy[10] = 12; s->xy[11] = 13; s->xy[12] = 5; s->xy[13] = 13; s->xy[14] = 4; s->xy[15] = 9; s->xy[16] = 11; s->xy[17] = 9; s->xy[18] = 11; s->xy[19] = 4; s->xy[20] = 4; s->xy[21] = 4; s->xy[22] = 4; s->xy[23] = 9; s->xy[24] = 8; s->xy[25] = 20; s->xy[26] = 4; s->xy[27] = 20; s->xy[28] = 0; s->xy[29] = 10; characters['6'-32] = s; /* "7" */ s = memory_allocate(sizeof(Character), NULL); s->np = 10; s->xy[0] = 4; s->xy[1] = 0; s->xy[2] = 8; s->xy[3] = 0; s->xy[4] = 8; s->xy[5] = 4; s->xy[6] = 15; s->xy[7] = 12; s->xy[8] = 15; s->xy[9] = 20; s->xy[10] = 0; s->xy[11] = 20; s->xy[12] = 0; s->xy[13] = 16; s->xy[14] = 11; s->xy[15] = 16; s->xy[16] = 11; s->xy[17] = 13; s->xy[18] = 4; s->xy[19] = 6; characters['7'-32] = s; /* "8" */ s = memory_allocate(sizeof(Character), NULL); s->np = 18; s->xy[0] = 2; s->xy[1] = 0; s->xy[2] = 4; s->xy[3] = 0; s->xy[4] = 4; s->xy[5] = 16; s->xy[6] = 11; s->xy[7] = 16; s->xy[8] = 11; s->xy[9] = 12; s->xy[10] = 4; s->xy[11] = 12; s->xy[12] = 4; s->xy[13] = 8; s->xy[14] = 11; s->xy[15] = 8; s->xy[16] = 11; s->xy[17] = 4; s->xy[18] = 4; s->xy[19] = 4; s->xy[20] = 4; s->xy[21] = 0; s->xy[22] = 13; s->xy[23] = 0; s->xy[24] = 15; s->xy[25] = 2; s->xy[26] = 15; s->xy[27] = 18; s->xy[28] = 13; s->xy[29] = 20; s->xy[30] = 2; s->xy[31] = 20; s->xy[32] = 0; s->xy[33] = 18; s->xy[34] = 0; s->xy[35] = 2; characters['8'-32] = s; /* "9" */ s = memory_allocate(sizeof(Character), NULL); s->np = 15; s->xy[0] = 15; s->xy[1] = 18; s->xy[2] = 12; s->xy[3] = 20; s->xy[4] = 3; s->xy[5] = 20; s->xy[6] = 0; s->xy[7] = 18; s->xy[8] = 0; s->xy[9] = 9; s->xy[10] = 3; s->xy[11] = 7; s->xy[12] = 10; s->xy[13] = 7; s->xy[14] = 11; s->xy[15] = 11; s->xy[16] = 4; s->xy[17] = 11; s->xy[18] = 4; s->xy[19] = 16; s->xy[20] = 11; s->xy[21] = 16; s->xy[22] = 11; s->xy[23] = 11; s->xy[24] = 7; s->xy[25] = 0; s->xy[26] = 11; s->xy[27] = 0; s->xy[28] = 15; s->xy[29] = 10; characters['9'-32] = s; /* "C" */ s = memory_allocate(sizeof(Character), NULL); s->np = 10; s->xy[0] = 0; s->xy[1] = 3; s->xy[2] = 3; s->xy[3] = 0; s->xy[4] = 12; s->xy[5] = 0; s->xy[6] = 15; s->xy[7] = 4; s->xy[8] = 4; s->xy[9] = 4; s->xy[10] = 4; s->xy[11] = 16; s->xy[12] = 15; s->xy[13] = 16; s->xy[14] = 11; s->xy[15] = 20; s->xy[16] = 3; s->xy[17] = 20; s->xy[18] = 0; s->xy[19] = 17; characters['C'-32] = s; /* "L" */ s = memory_allocate(sizeof(Character), NULL); s->np = 6; s->xy[0] = 0; s->xy[1] = 0; s->xy[2] = 15; s->xy[3] = 0; s->xy[4] = 15; s->xy[5] = 4; s->xy[6] = 4; s->xy[7] = 4; s->xy[8] = 4; s->xy[9] = 20; s->xy[10] = 0; s->xy[11] = 20; characters['L'-32] = s; /* "R" */ s = memory_allocate(sizeof(Character), NULL); s->np = 15; s->xy[0] = 0; s->xy[1] = 0; s->xy[2] = 4; s->xy[3] = 0; s->xy[4] = 4; s->xy[5] = 16; s->xy[6] = 11; s->xy[7] = 16; s->xy[8] = 11; s->xy[9] = 11; s->xy[10] = 4; s->xy[11] = 11; s->xy[12] = 4; s->xy[13] = 7; s->xy[14] = 8; s->xy[15] = 7; s->xy[16] = 11; s->xy[17] = 0; s->xy[18] = 15; s->xy[19] = 0; s->xy[20] = 12; s->xy[21] = 8; s->xy[22] = 15; s->xy[23] = 10; s->xy[24] = 15; s->xy[25] = 18; s->xy[26] = 12; s->xy[27] = 20; s->xy[28] = 0; s->xy[29] = 20; characters['R'-32] = s; /**** s = memory_allocate(sizeof(Character), NULL); s->np = ; s->xy[0] = ; s->xy[1] = ; s->xy[2] = ; s->xy[3] = ; s->xy[4] = ; s->xy[5] = ; s->xy[6] = ; s->xy[7] = ; s->xy[8] = ; s->xy[9] = ; s->xy[10] = ; s->xy[11] = ; s->xy[12] = ; s->xy[13] = ; s->xy[14] = ; s->xy[15] = ; s->xy[16] = ; s->xy[17] = ; s->xy[18] = ; s->xy[19] = ; s->xy[20] = ; s->xy[21] = ; s->xy[22] = ; s->xy[23] = ; s->xy[24] = ; s->xy[25] = ; s->xy[26] = ; s->xy[27] = ; s->xy[28] = ; s->xy[29] = ; characters['R'-32] = s; ****/ } /** * Returns the polygon of the char c, with 32<=c<=127. * The char is translated to (x,y) before m be applied. * Since the main axis of the runway is along the x-axis, by default * the char is rotated accordingly. If upside_down is TRUE (i.e. != 0) * the char is rotated 180 DEG. */ static VPolygon * BuildChar(int c, VMatrix * m, double x, double y, int upside_down) { VPoint p, pts[MAX_POINTS_PER_CHAR]; Character *s; int i, np, *xy; VPolygon *poly; if ( c < 32 || c > 127 ) { fprintf(stderr, "BuildChar(): invalid char code %d\n", c); return NULL; } s = characters[c-32]; if ( s == NULL ) s = characters[CHAR_DEFAULT-32]; np = s->np; xy = &(s->xy[0]); for ( i=0; iflags |= PolyUseCullDistance; poly->cullDistance = RUNWAY_CULL_DISTANCE; return poly; } /** * Returns the string length in meters. */ static double StringWidth(char *s) { int l; l = strlen(s); return l*CHAR_WIDTH + (l-1) * CHAR_MARGIN_X; } /** * Add the string s to the set of polygons. * ox is the distance of the line base from the runway end. * oy is the center of the string, typically 0.0. */ static void AddBigString(char *s, VMatrix * m, double ox, double oy, int upside_down, VPolySet *ps) { VPolygon *p; int len, j; double x, y; if ( s == NULL ) return; len = strlen(s); if ( len == 0 ) return; x = ox; if ( upside_down ) y = oy - StringWidth(s) / 2.0; else y = oy + StringWidth(s) / 2.0; for ( j=0; j 7 ) { fprintf(stderr, "Runway name `%s' too long. Max 7 char allowed.\n", id); return; } c = id; /* Parse hdg1: */ i = 0; while( isdigit(*c) ){ hdg1[i] = *c; i++; c++; } hdg1[i] = 0; /* Parse side1: */ if( *c != 0 && *c != '/' ){ i = 0; do { side1[i] = *c; i++; c++; } while( *c != 0 && *c != '/' ); side1[i] = 0; } /* Parse hdg2: */ if( *c == 0 ){ fprintf(stderr, "Invalid runway name `%s', missing `/'.\n", id); return; } if( *c != '/' ){ fprintf(stderr, "Invalid character `%c' in runway name `%s'.\n", *c, id); return; } c++; i = 0; while( *c != 0 && isdigit(*c) ){ hdg2[i] = *c; i++; c++; } hdg2[i] = 0; /* Parse side2: */ i = 0; while( *c != 0 ){ side2[i] = *c; i++; c++; } side2[i] = 0; /* Sort labels: */ int n1 = atoi(hdg1); int n2 = atoi(hdg2); if( n1 > n2 ){ char s[10]; strcpy(s, hdg1); strcpy(hdg1, hdg2); strcpy(hdg2, s); strcpy(s, side1); strcpy(side1, side2); strcpy(side2, s); int t = n1; n1 = n2; n2 = t; } /* Consistency check: */ if( !(0 <= n1 && n1 <= 36 && 0 <= n2 && n2 <= 36) ) fprintf(stderr, "Invalid runway numbers `%s', out of the range [0,36]\n", id); if( n2 - n1 != 18 ) fprintf(stderr, "Incompatible numbers in runway name `%s', they must differ by 18, corresponding to 180 DEG.\n", id); /* The first label will be displayed at the "start" of the runway, that is at -0.5*length*(cos(heading),sin(heading), 0.0) in NED, whereas the second label would be displayed at the "end" of the runway, that is at 0.5*length*(cos(heading),sin(heading), 0.0) in NED. However there is an issue for runways whose heading is near the north-south direction when the magnetic variation is involved, because the heading refers to the geographical coords. whereas the labels refer to magnetic coords. So, for example, the heading of the runway 18/36 may be either 10 DEG or 170 DEG. In the first case the labels must be exchanged. A similar issue happens for runways whose heading is near suoth. This fix works for magnetic variations up to 45 DEG: */ int h = (int)(units_RADtoDEG(heading)); if( ( (h <= 45) && (n1 > 13) ) || ( (h >= 135) && (n1 < 9) ) ){ char s[10]; strcpy(s, hdg1); strcpy(hdg1, hdg2); strcpy(hdg2, s); strcpy(s, side1); strcpy(side1, side2); strcpy(side2, s); int t = n1; n1 = n2; n2 = t; } } static VPolygon * build_rectangle(double x1, double y1, double x2, double y2, VColor_Type * color, int cull_distance, VMatrix *m) { VPolygon *p; int i; VPoint v[4]; VSetPoint(&v[0], x1, y1, 0.0); VSetPoint(&v[1], x2, y1, 0.0); VSetPoint(&v[2], x2, y2, 0.0); VSetPoint(&v[3], x1, y2, 0.0); for( i=0; i < 4; i++ ) VTransform(&v[i], m, &v[i]); p = VCreatePolygon(4, v, color); p->flags |= PolyUseCullDistance; p->cullDistance = cull_distance; return p; } static void AddSymmetricPolygons(VMatrix * RWYtoXYZ, double x, double y, int count, double length, double width, double margin, VPolySet *ps) { for (; count > 0; --count, y -= width + margin) { VPolySet_Add(ps, build_rectangle( x, y, x - length, y - width, whitePaintColor, MARKING_CULL_DISTANCE, RWYtoXYZ ) ); /* * Opposite stripe on same runway end */ VPolySet_Add(ps, build_rectangle( x, -y, x - length, -y + width, whitePaintColor, MARKING_CULL_DISTANCE, RWYtoXYZ ) ); /* * Stripe on opposite runway end */ VPolySet_Add(ps, build_rectangle( -x, y, -x + length, y - width, whitePaintColor, MARKING_CULL_DISTANCE, RWYtoXYZ ) ); /* * Opposite stripe on opposite runway end */ VPolySet_Add(ps, build_rectangle( -x, -y, -x + length, -y + width, whitePaintColor, MARKING_CULL_DISTANCE, RWYtoXYZ ) ); } } VPolySet * runway_build(char *id, VMatrix * RWYtoXYZ, double length, double width, double heading) { double start, stop, x, delta_x, y; int n, i, stripes; VPolySet *ps; /* * Init module. */ if ( characters == NULL ) { InitBuildChar(); runwayColor = VColor_getByName(RUNWAY_COLOR, 1); whitePaintColor = VColor_getByName(WHITE_PAINT, 1); memory_registerCleanup(runway_cleanup); } ps = VPolySet_New(); /* * First, add the runway surface polygon, a rectangle spanning * on x=[-length/2,lenght/2] and y=[-height/2,height/2]. * Longer runways are splitted in several shorter pieces for * better haze rendering. */ if( length <= 500.0 ){ n = 1; delta_x = length; } else { n = (int) ceil(length / 500.0); delta_x = length / n; } x = -length/2; for( i = 0; i < n; i++ ){ VPolySet_Add(ps, build_rectangle( x, width/2, x + delta_x, -width/2, runwayColor, RUNWAY_CULL_DISTANCE, RWYtoXYZ ) ); x += delta_x; } /* * Runway numbers, both ends */ start = -0.5 * length + CHAR_X_OFFSET; stop = 0.5 * length - CHAR_X_OFFSET; if ( width >= 2.0 * CHAR_WIDTH + CHAR_MARGIN_Y ) { char hdg1[8], side1[8], hdg2[8], side2[8]; SplitRunwayName(id, heading, hdg1, side1, hdg2, side2); if ( strlen(side1) > 0 ) { AddBigString(side1, RWYtoXYZ, start, 0.0, 1, ps); start += CHAR_HEIGHT + CHAR_MARGIN_Y; } AddBigString(hdg1, RWYtoXYZ, start, 0.0, 1, ps); start += CHAR_HEIGHT; if ( strlen(side2) > 0 ) { AddBigString(side2, RWYtoXYZ, stop, 0.0, 0, ps); stop -= CHAR_HEIGHT + CHAR_MARGIN_Y; } AddBigString(hdg2, RWYtoXYZ, stop, 0.0, 0, ps); stop -= CHAR_HEIGHT; } /* * Now the runway centerline markings. */ start += 12.0 + CENTERLINE_LENGTH / 2.0; stop -= 12.0 + CENTERLINE_LENGTH / 2.0; for (x = start; x < stop; x += CENTERLINE_LENGTH + CENTERLINE_GAP) { VPolySet_Add(ps, build_rectangle( x - CENTERLINE_LENGTH / 2.0, CENTERLINE_WIDTH / 2.0, x + CENTERLINE_LENGTH / 2.0, -CENTERLINE_WIDTH / 2.0, whitePaintColor, MARKING_CULL_DISTANCE, RWYtoXYZ ) ); } /* * Runway threshold stripes */ /* From the Aeronautical Information Manual */ if (width >= 18.0) { stripes = 0; if (width >= 60.0) { stripes = 16; } else if (width >= 45.0) { stripes = 12; } else if (width >= 30.0) { stripes = 8; } else if (width >= 23.0) { stripes = 6; } else if (width >= 18.0) { stripes = 4; } stripes >>= 1; x = 0.5 * length - THRESHOLD_STRIPE_X_OFFSET; y = width / 2.0 - THRESHOLD_STRIPE_Y_OFFSET; for (; stripes > 0; --stripes, y -= THRESHOLD_STRIPE_WIDTH + THRESHOLD_STRIPE_MARGIN) { VPolySet_Add(ps, build_rectangle( x, y, x - THRESHOLD_STRIPE_LENGTH, y - THRESHOLD_STRIPE_WIDTH, whitePaintColor, MARKING_CULL_DISTANCE, RWYtoXYZ ) ); /* * Opposite stripe on same runway end */ VPolySet_Add(ps, build_rectangle( x, -y, x - THRESHOLD_STRIPE_LENGTH, -y + THRESHOLD_STRIPE_WIDTH, whitePaintColor, MARKING_CULL_DISTANCE, RWYtoXYZ ) ); /* * Stripe on opposite runway end */ VPolySet_Add(ps, build_rectangle( -x, y, -x + THRESHOLD_STRIPE_LENGTH, y - THRESHOLD_STRIPE_WIDTH, whitePaintColor, MARKING_CULL_DISTANCE, RWYtoXYZ ) ); /* * Opposite stripe on opposite runway end */ VPolySet_Add(ps, build_rectangle( -x, -y, -x + THRESHOLD_STRIPE_LENGTH, -y + THRESHOLD_STRIPE_WIDTH, whitePaintColor, MARKING_CULL_DISTANCE, RWYtoXYZ ) ); } } /* * Fixed distance marker */ if (length > units_FEETtoMETERS(3000.0)) { AddSymmetricPolygons(RWYtoXYZ, 0.5 * length - FIXED_MARKER_X_OFFSET, 0.5 * width - FIXED_MARKER_Y_OFFSET, 1, FIXED_MARKER_LENGTH, FIXED_MARKER_WIDTH, 0.0, ps); } return ps; } acm-6.0_20200416/src/acm/ccip.h0000644000000000000000000000235013646045023014214 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /** * CCIP - Constantly Computed Impact Point. * * This module implements the Mark 82 drop bomb and the HUD CCIP aiming * interface. * * @author Riley Rainey * @license GNU GPL * @version $Date: 2020/01/08 06:01:16 $ * @file */ #ifndef _ccip_h #define _ccip_h #include "weapon.h" #ifdef ccip_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Creates weapon description record for the Mark 82 drop bomb. */ EXTERN weapon_Type * ccip_new(void); #undef EXTERN #endif acm-6.0_20200416/src/acm/navaid.c0000644000000000000000000002173113173127407014541 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991,1992,1997 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include #include "../util/error.h" #include "../util/memory.h" #include "../util/units.h" #include "../wmm/wmm.h" #include "pm.h" #define navaid_IMPORT #include "navaid.h" /** Double-linked list of known registered NAVAIDs. */ static navaid_Type *navaids; /** Linked list of recycled NAVAIDs. */ static navaid_Type *pool; static void navaid_cleanup(void) { navaid_Type *n = navaids, *p; while (n) { p = n; n = n->next; memory_dispose(p); } navaids = NULL; n = pool; while (n) { p = n; n = n->next; memory_dispose(p); } pool = NULL; } static navaid_Type * navaid_new() { navaid_Type *n; if( pool != NULL ){ n = pool; pool = pool->next; } else { n = memory_allocate(sizeof(navaid_Type), NULL); } n->prev = NULL; n->next = navaids; if( navaids != NULL ) navaids->prev = n; navaids = n; return n; } /** * Removes navaid from active list an put into the pool. */ static void navaid_release(navaid_Type *n) { if( n->prev == NULL ) navaids = n->next; else n->prev->next = n->next; if( n->next != NULL ) n->next->prev = n->prev; n->next = pool; pool = n; } navaid_Type * navaid_reception_check(craft * c, navaid_Channel f) { navaid_Type *n; VPoint p; double range, dist, d; // nearest VOR station found: navaid_Type *last_found = NULL; double last_dist = 0.0; for (n = navaids; n; n = n->next) { if (f == n->frequency) { if (n->type & navaid_LOC) { VTransform(&c->Sg, &n->lt, &p); if ( p.x > 0.0 && fabs(p.y / p.x) < 1.192 /* = 50 DEG */ && VMagnitude(&p) < 33e3 /* LOC, typical max range 18 NM */ ) { // LOC in range found: return immediately return n; } } else if (n->type & (navaid_VOR|navaid_DME)){ if ( n->frequency < 80 /* 112.00 MHz */ ) { /* terminal VOR, range 40 NM */ range = units_NMtoMETERS(40); } else { /* en-route VOR, range 200 NM */ range = units_NMtoMETERS(200); } /* Compute aircraft position relative to the station in its magnetic north/east/down frame: */ VTransform(&c->Sg, &n->lt, &p); /* Ignore station if it can't be received: */ if( p.z > 0.0 ){ /* Aircraft below horizon of the radio station. Reduce radio range due to the Earth curvature. The value of the constant K below was derived from a pure geometric calculation based on an Earth mean radius of 6367 Km, giving a maximum reception range of d=K*(sqrt(transmitter_alt)+sqrt(aircraft_alt)) Other sources suggest a greater value K=4126 with all the distances in meters, but I adopted a more conservative approach. */ #define K 3568.0 d = K*( sqrt(fabs(n->loc.z)) + sqrt(fabs(c->w.z)) ); /* m */ if( d < range ) range = d; } dist = VMagnitude(&p); if( dist > range ) /* too far from station */{ continue; printf("%s: too far\n", n->id); } if ( last_found == NULL || last_dist > dist ) { // VOR found: continue looping searching // for possible nearest stations with same freq. last_found = n; last_dist = dist; } } else if(n->type & navaid_NDB){ if (n->type & (navaid_OMARKER|navaid_MMARKER|navaid_IMARKER)) { range = units_NMtoMETERS(20); } else { range = units_NMtoMETERS(100); } VTransform(&c->Sg, &n->lt, &p); dist = VMagnitude(&p); if ( dist < range && (last_found == NULL || last_dist > dist) ) { // NDB in range found: continue looping searching // for possible nearest stations last_found = n; last_dist = dist; } } else { error_internal("unexpected navaid type %d", n->type); } } } if( last_found == NULL ){ // no stations found in range return NULL; } else { // nearest in range station found return last_found; } } void navaid_add_vor_dme_ndb(zone_Type *zone, char *ident, char *type, earth_LatLonAlt * w, double freq) { // Automatic module initialization: if( navaids == NULL && pool == NULL ) memory_registerCleanup(navaid_cleanup); navaid_Type *n = navaid_new(); n->zone = zone; memory_strcpy(n->id, sizeof(n->id), ident); n->loc = *w; if (strcmp(type, "VORTAC") == 0) { n->type = navaid_VOR | navaid_DME; } else if (strcmp(type, "TACAN") == 0) { n->type = navaid_VOR | navaid_DME; } else if (strcmp(type, "VOR/DME") == 0) { n->type = navaid_VOR | navaid_DME; } else if (strcmp(type, "VOR") == 0) { n->type = navaid_VOR; } else if (strcmp(type, "DME") == 0) { n->type = navaid_DME; } else if (strcmp(type, "NDB") == 0) { n->type = navaid_NDB; } else if (strcmp(type, "OMARKER") == 0) { n->type = navaid_NDB | navaid_OMARKER; } else if (strcmp(type, "OMARKER/COMLO") == 0) { n->type = navaid_NDB | navaid_OMARKER; } else if (strcmp(type, "MMARKER") == 0) { n->type = navaid_NDB | navaid_MMARKER; } else if (strcmp(type, "IMARKER") == 0) { n->type = navaid_NDB | navaid_IMARKER; } else if (strcmp(type, "NDB") == 0) { n->type = navaid_NDB; } else { fprintf(stderr, "%s: %s: unexpected NAV of the type `%s'. Ignore.\n", zone_getPath(zone), ident, type); navaid_release(n); return; } earth_generateWorldToLocalMatrix(w, &n->lt); if( n->type & navaid_VOR ){ wmm_MagneticField mf; wmm_getMagneticField(0.0, w->latitude, w->longitude, w->z, &mf); n->bearing = - mf.Decl; VRotate(&n->lt, ZRotation, n->bearing); } else { n->bearing = 0; } earth_LatLonAltToXYZ(w, &n->Sg); if (n->type & (navaid_VOR | navaid_DME)) { n->frequency = navaid_VOR_CHANNEL_MIN + (int) ((freq - 108.00) * 20.0 + 0.5); if( n->frequency < navaid_VOR_CHANNEL_MIN || n->frequency > navaid_VOR_CHANNEL_MAX ){ fprintf(stderr, "%s: %s VOR/DME: frequency %g out of range. Ignore.\n", zone_getPath(zone), ident, freq); navaid_release(n); return; } } else { n->frequency = (int) freq; if( n->frequency < navaid_NDB_CHANNEL_MIN || n->frequency > navaid_NDB_CHANNEL_MAX ){ fprintf(stderr, "%s: %s: frequency out of range %g for NDB station. Ignore.\n", zone_getPath(zone), ident, freq); navaid_release(n); return; } } } void navaid_add_ils(zone_Type *zone, char *ident, char *type, earth_LatLonAlt * w, earth_LatLonAlt * gsw, double freq, double loc_width, double loc_bearing, double gs_angle) { // Automatic module initialization: if( navaids == NULL && pool == NULL ) memory_registerCleanup(navaid_cleanup); navaid_Type *n = navaid_new(); n->zone = zone; memory_strcpy(n->id, sizeof(n->id), ident); n->bearing = units_DEGtoRAD(loc_bearing); n->loc = *w; earth_generateWorldToLocalMatrix(w, &n->lt); VRotate(&n->lt, ZRotation, -n->bearing - M_PI); earth_LatLonAltToXYZ(w, &n->Sg); n->gs_loc = *gsw; earth_generateWorldToLocalMatrix(gsw, &n->gst); VRotate(&n->gst, ZRotation, -n->bearing - M_PI); n->slope = units_DEGtoRAD(gs_angle); n->beam_width = units_DEGtoRAD(loc_width); if (strcmp(type, "ILS") == 0 || strcmp(type, "LOC/GS") == 0 ) { n->type = navaid_LOC | navaid_GS; } else if (strcmp(type, "ILS/DME") == 0) { n->type = navaid_LOC | navaid_GS | navaid_DME; } else if (strcmp(type, "LOCALIZER") == 0 || strcmp(type, "LDA") == 0 || strcmp(type, "SDF") == 0 ) { n->type = navaid_LOC; } else if (strcmp(type, "LOC/DME") == 0 || strcmp(type, "LDA/DME") == 0 || strcmp(type, "SDF/DME") == 0 ) { n->type = navaid_LOC | navaid_DME; } else { fprintf(stderr, "%s: %s: unknown ILS type `%s'. Ignore.\n", zone_getPath(zone), ident, type); navaid_release(n); return; } if( (n->type & navaid_GS) && !(1 <= gs_angle && gs_angle <= 5) ){ fprintf(stderr, "%s: %s: invalid slope angle: %g DEG. Ignore.\n", zone_getPath(zone), ident, gs_angle); navaid_release(n); return; } n->frequency = navaid_VOR_CHANNEL_MIN + (int) ((freq - 108.00) * 20.0 + 0.5); if( n->frequency < navaid_VOR_CHANNEL_MIN || n->frequency > navaid_VOR_CHANNEL_MAX ){ fprintf(stderr, "%s: %s ILS: frequency %g out of the range. Ignore.\n", zone_getPath(zone), ident, freq); navaid_release(n); return; } if( navaids == NULL ) memory_registerCleanup(navaid_cleanup); } void navaid_purgeZone(zone_Type *zone) { navaid_Type *n = navaids; while( n != NULL ){ if( n->zone == zone ){ navaid_Type *q = n; n = n->next; navaid_release(q); } else { n = n->next; } } } acm-6.0_20200416/src/acm/acm.c0000644000000000000000000004333413260344464014043 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991-1998 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include #include #include "../util/error.h" #include "../util/memory.h" #include "../util/reader.h" #include "../util/units.h" #include "air.h" #include "box.h" #include "damage.h" #include "dis_if.h" #include "drone.h" #include "effects.h" #include "gear.h" #include "init.h" #include "joystick.h" #include "list.h" #include "m61a1.h" #include "manifest.h" #include "mouse.h" #include "patchlevel.h" #include "players.h" #include "pm.h" #include "render.h" #include "update.h" static char *objects = NULL; /* value of the -objects PATHs option */ static char * name = NULL; // Frame rate (Hz). static int frame_rate = 20; static int use_dis = 0; static char *dis_relay_name = NULL; static int dis_relay_port = 3000; static int dis_site = -1; static int dis_application = -1; static int dis_exercise = 1; static char *departure_time; /** * Generic kill callback for remote entities. * @param c Remote craft/missile/bomb/whatever to remove. */ static void disEntityKill(craft *c, char *reason) { int pIndex = c->pIndex; memory_dispose(c->aps); gear_free(c); drone_release_commands(c); pm_hud_strings_free(c); if (c->flags & FL_RECORD) { --recordCount; } if (c->flags & FL_BLACK_BOX) box_killPlayer(c->pIndex); dis_if_entityExit(c->disId); memory_zero(c); c->pIndex = pIndex; c->type = CT_FREE; } /** * Entity creation callback to be set in the dis_if module. Invoked when a new * remote entity state DIS PDU appears. * @param eid Handle the dis_if module assigned to this new entity. * @param etype DIS entity type. * @param force One of the DISForceXxx constants. * @param cptr Here we return NULL if we are not interested to follow this * entity. Otherwise, here we set the craft or missile we associate to that * new remote entity. */ static void disEntityEnterCb(int eid, dis_entity_type * etype, DISForce force, craft ** cptr) { int i, top, mtype; craftType *p; craft *tbl; *cptr = NULL; /* Determines which table to insert into: */ if (etype->kind == DISKindPlatform) { tbl = ptbl; top = manifest_MAXPLAYERS; mtype = CT_DIS_PLANE; } else if (etype->kind == DISKindMunition) { tbl = mtbl; top = manifest_MAXPROJECTILES; mtype = CT_DIS_MUNITION; } else { return; } /* * If no picture available for the entity, try UFO instead. */ p = inventory_craftTypeSearchByEntityType(etype); if (p == NULL) { printf("entering entity %s not found in the inventory\n", dis_entityTypeToString(etype)); p = inventory_craftTypeSearchByZoneAndName(NULL, "UFO"); } if( p == NULL ) return; /* Search a free entry: */ craft *c = NULL; for (i = 0; i < top; ++i) { if (tbl[i].type == CT_FREE) { c = &tbl[i]; break; } } if (c == NULL ){ if( tbl == ptbl ) fprintf(stderr, "Sorry, cannot store remote craft, table is full: %d\n", manifest_MAXPLAYERS); else fprintf(stderr, "Sorry, cannot store remote munition, table is full: %d\n", manifest_MAXPROJECTILES); return; } memory_zero(c); c->pIndex = i; /* here restores pIndex we just reset :-) */ c->type = mtype; c->force = force; c->createTime = curTime; c->vl = NULL; c->disId = eid; c->cinfo = p; memory_strcpy(c->name, sizeof(c->name), "DIS"); c->flags = 0; c->radarMode = RM_OFF; c->curRadarTarget = -1; if( c->type == CT_DIS_PLANE ){ pm_hud_strings_alloc(c); gear_allocate(c); gear_up(c); } c->update = dis_if_updateRemote; c->kill = disEntityKill; *cptr = c; } /** * Detonation callback to be set in the dis_if module and invoked by the * dis_module when a DIS detonation PDU is received. Establishes the damage of * the target and possibly kills the target. Also creates an explosion effect. * @param ftype dis_if_FIRE_M61A1 or dis_if_FIRE_AIM9M. * @param firing Firing entity. * @param target Target craft. * @param time Ignored. * @param worldLocation Point of impact, that is where the missile where when * it exploded. * @param entityLocation Location of the detonation in the reference system of * the target (m). Used for damage assessment of missiles and bombs. * @param munition The munition that hit the target (missile, bomb, cannon shell). * @param dpdu Detonation DIS PDU. */ static void disDetonationCb(int ftype, craft *firing, craft *target, double time, double *worldLocation, double *entityLocation, craft * munition, dis_detonation_pdu *dpdu) { VPoint Sg, rvel, tmp; double exp_diameter, dist_meters, vel_meters_per_sec; char reason[1000]; Sg.x = worldLocation[0]; Sg.y = worldLocation[1]; Sg.z = worldLocation[2]; /* If the target is a local player, damage him: */ if (target != NULL && (target->type == CT_PLANE || target->type == CT_DRONE) ){ /* impact distance from C.G. */ dist_meters = VMagnitude((VPoint *)entityLocation); /* impact velocity */ tmp.x = units_FEETtoMETERS(target->Cg.x); tmp.y = units_FEETtoMETERS(target->Cg.y); tmp.z = units_FEETtoMETERS(target->Cg.z); VReverseTransform_(&tmp, &target->XYZtoNED, &rvel); rvel.x = dpdu->vel.x - rvel.x; rvel.y = dpdu->vel.y - rvel.y; rvel.z = dpdu->vel.z - rvel.z; vel_meters_per_sec = VMagnitude(&rvel); if( damage_absorbDISDamage(target, &dpdu->burst.munition, dpdu->burst.warhead, dpdu->burst.fuze, dist_meters, vel_meters_per_sec, &exp_diameter) == 0) { snprintf(reason, sizeof(reason), "%s fired by %s", ftype == dis_if_FIRE_M61A1 ? "cannon shells" : "something (presumably a missile)", firing->name ); target->kill(target, reason); } else { /* * Ouch, damage_absorbDISDamage() not invoked, no explosion diameter. * Here we have either to query the munition table, or set an * arbitrary "average explosion diameter": */ exp_diameter = 10.0; } } /* Set a generic explosion effect: */ effects_new_explosion(&Sg, &(VPoint){0.0, 0.0, 0.0}, exp_diameter, 15.0, 1.0); } static int disInit(void) { int err; if( !(0 <= dis_exercise && dis_exercise <= 255) ) error_external("exercise ID must be in [0,255], %d given", dis_exercise); if( !(-1 <= dis_site && dis_site <= 65535) ) error_external("site ID must be in [-1,65535], %d given", dis_site); if( !(-1 <= dis_application && dis_application <= 65535) ) error_external("application ID must be in [-1,65535], %d given", dis_application); err = dis_if_init(dis_relay_name, dis_relay_port, dis_exercise, dis_site, dis_application, disEntityEnterCb, disDetonationCb, m61a1_DISFire); dis_if_setDRThresholds(manifest_DIS_LOCATION_THRESHOLD, manifest_DIS_ORIENTATION_THRESHOLD); return err; } static void help() { printf("ACM %s\n", patchlevel_REVISION_STRING); printf( "Copyright (C) 1991-1998 Riley Rainey (rrainey@ix.netcom.com)\n" "Updated and modified by Umberto Salsi (salsi@icosaedro.it)\n" "ACM comes with ABSOLUTELY NO WARRANTY.\n" "This is free software, and you are welcome to distribute it under the\n" "conditions described in the COPYING file.\n"); } static list_Type * read_switches_from_file(const char *fname) { FILE *f; char commands[4096]; char *argv[100]; int argc; int n, err, i; list_Type *l; argv[0] = NULL; argc = 1; f = fopen (fname, "r"); if( f == NULL ){ fprintf(stderr, "ERROR: failed to read file `%s'\n", fname); return NULL; } n = fread(commands, 1, sizeof(commands) - 1, f); err = ferror(f); fclose(f); if( err != 0 ){ fprintf(stderr, "ERROR: failed to read file `%s'\n", fname); return NULL; } if( n == sizeof(commands) - 1 ){ fprintf(stderr, "ERROR: file `%s' too long\n", fname); return NULL; } if( n < 1 ) return NULL; if( ! reader_split(commands, &argc, argv, 100) ){ fprintf(stderr, "ERROR: too many arguments in file `%s'\n", fname); return NULL; } if( argc == 0 ) return NULL; l = list_new(); for( i = 0; i < argc; i++ ) list_add_elem(l, argv[i]); return l; } static list_Type * processCommandSwitches(list_Type *args) { int i; char *a; list_Type *switches; switches = list_new(); for (i = 0; i < args->n; ++i) { a = args->arr[i]; if (strcmp(a, "-h") == 0 || strcmp(a, "-help") == 0 || strcmp(a, "--help") == 0 || strcmp(a, "-version") == 0 || strcmp(a, "-copyright") == 0) { help(); exit(0); } else if (strcmp(a, "-objects") == 0 && ++i < args->n) { memory_dispose(objects); objects = memory_strdup(args->arr[i]); } else if (strcmp(a, "-no-dis") == 0) { /* * FIXME: the -no-dis option now useless. * Networking is enabled if any -dis-* option is set. */ use_dis = 0; } else if (strcmp(a, "-dis-relay-name") == 0 && ++i < args->n) { memory_dispose(dis_relay_name); dis_relay_name = memory_strdup(args->arr[i]); use_dis = 1; } else if (strcmp(a, "-dis-relay-port") == 0 && ++i < args->n) { dis_relay_port = strtol(args->arr[i], (char **) NULL, 0); use_dis = 1; } else if (strcmp(a, "-dis-site") == 0 && ++i < args->n) { dis_site = strtol(args->arr[i], (char **) NULL, 0); use_dis = 1; } else if (strcmp(a, "-dis-appl") == 0 && ++i < args->n) { dis_application = strtol(args->arr[i], (char **) NULL, 0); use_dis = 1; } else if (strcmp(a, "-dis-exercise") == 0 && ++i < args->n) { dis_exercise = strtol(args->arr[i], (char **) NULL, 0); use_dis = 1; } else if (strcmp(a, "-dis-absolute-time") == 0) { dis_if_haveAbsoluteTime = 1; use_dis = 1; } else if (strncmp(a, "-dis", 4) == 0) { fprintf(stderr, "Acm DIS arguments:\n" " -dis-relay-name (default: use broadcasting)\n" " -dis-relay-port (default: 3000)\n" " -dis-exercise (default %d)\n" " -dis-site (default %d)\n" " -dis-appl (default %d)\n" " -dis-absolute-time\n", dis_exercise, dis_site, dis_application); } else if (strcmp(a, "-init") == 0 && ++i < args->n) { list_Type *q; q = read_switches_from_file(args->arr[i]); list_add_list(switches, q); memory_dispose(q); } else if (strcmp(a, "-arcade") == 0) { arcadeMode = 1; } else if (strcmp(a, "-da") == 0 && ++i < args->n) { drone_set_aggressiveness( atof(args->arr[i]) ); } else if (strcmp(a, "-drone-mode") == 0 && ++i < args->n) { if( strcmp(args->arr[i], "DOG_FIGHT") == 0 ) drone_set_mode(drone_DOG_FIGHT_MODE); else if( strcmp(args->arr[i], "HUNTING") == 0 ) drone_set_mode(drone_HUNTING_MODE); else error_external("invalid argument for -drone-mode option, must be DOG_FIGHT or HUNTING: %s", args->arr[i]); } else if (strcmp(a, "-display") == 0 && ++i < args->n) { setenv("DISPLAY", args->arr[i], 1); } else if (strcmp(a, "-geometry") == 0 && ++i < args->n) { list_add_elem(switches, "-geometry"); list_add_elem(switches, args->arr[i]); } else if (strcmp(a, "-eye_to_screen_cm") == 0 && ++i < args->n) { eye_to_screen_cm = atof(args->arr[i]); } else if (strcmp(a, "-downward_view_angle_deg") == 0 && ++i < args->n) { downward_view_angle_rad = units_DEGtoRAD( atof(args->arr[i]) ); } else if (strcmp(a, "-js") == 0 && i+1 < args->n) { if (args->arr[i + 1][0] != '-') { joystick_setPort(args->arr[++i]); } else { joystick_setPort("/dev/cua0"); } } else if (strcmp(a, "-name") == 0 && ++i < args->n) { memory_dispose(name); name = memory_strdup(args->arr[i]); } else if (strcmp(a, "-plane") == 0 && ++i < args->n) { list_add_elem(switches, "-plane"); list_add_elem(switches, args->arr[i]); } else if (strcmp(a, "-fuel") == 0 && ++i < args->n) { list_add_elem(switches, "-fuel"); list_add_elem(switches, args->arr[i]); } else if (strcmp(a, "-payload") == 0 && ++i < args->n) { list_add_elem(switches, "-payload"); list_add_elem(switches, args->arr[i]); } else if (strcmp(a, "-stealth") == 0) { list_add_elem(switches, "-stealth"); } else if (strcmp(a, "-end-game") == 0) { list_add_elem(switches, "-end-game"); } else if (strcmp(a, "-threshold-range") == 0 && ++i < args->n) { double end_game_threshold_nm; end_game_threshold_nm = atof( args->arr[i] ); if (end_game_threshold_nm < 1.0) { end_game_threshold_nm = 1.0; } end_game_threshold_meters = units_FEETtoMETERS(end_game_threshold_nm*units_NmToFeetFactor); } else if (strcmp(a, "-force") == 0 && ++i < args->n) { list_add_elem(switches, "-force"); list_add_elem(switches, args->arr[i]); } else if (strcmp(a, "-departure-time") == 0 && ++i < args->n) { memory_dispose(departure_time); departure_time = memory_strdup(args->arr[i]); } else if (strcmp(a, "-latitude") == 0 && ++i < args->n) { list_add_elem(switches, "-latitude"); list_add_elem(switches, args->arr[i]); } else if (strcmp(a, "-longitude") == 0 && ++i < args->n) { list_add_elem(switches, "-longitude"); list_add_elem(switches, args->arr[i]); } else if (strcmp(a, "-altitude") == 0 && ++i < args->n) { list_add_elem(switches, "-altitude"); list_add_elem(switches, args->arr[i]); } else if (strcmp(a, "-heading") == 0 && ++i < args->n) { list_add_elem(switches, "-heading"); list_add_elem(switches, args->arr[i]); } else if (strcmp(a, "-airspeed-kt") == 0 && ++i < args->n) { list_add_elem(switches, "-airspeed-kt"); list_add_elem(switches, args->arr[i]); } else if (strcmp(a, "-visibility") == 0 && ++i < args->n) { render_setVisibility( units_NMtoMETERS(atof(args->arr[i]) ) ); } else if( strcmp(a, "-clouds-range") == 0 && i+2 < args->n ){ render_setClouds( units_FEETtoMETERS(atof(args->arr[i+1])), units_FEETtoMETERS(atof(args->arr[i+2]))); i += 2; } else if (strcmp(a, "-ground-mode") == 0 && ++i < args->n ){ a = args->arr[i]; if( strcmp(a, "flat") == 0 ) render_setGroundDepth(render_GROUND_FLAT); else if( strcmp(a, "tiled") == 0 ) render_setGroundDepth(render_GROUND_TILED); else error_external("invalid -render-ground-mode: must be flat or tiled, %s given", a); } else if (strcmp(a, "-wind") == 0 && ++i < args->n) { double wd, wv; if( sscanf(args->arr[i], "%lf/%lf", &wd, &wv) != 2 ) error_external("invalid parameter for -wind. Expected DIRECTION/VELOCITY"); air_set_wind(wd, wv); } else if (strcmp(a, "-gust") == 0 && ++i < args->n) { air_set_gust( atof(args->arr[i]) ); } else if (strcmp(a, "-no-sound") == 0 ) { list_add_elem(switches, "-no-sound"); } else if (strcmp(a, "-frame-rate") == 0 && ++i < args->n) { frame_rate = atoi(args->arr[i]); if( frame_rate < 1 ) frame_rate = 1; } else if (strcmp(a, "-transfer-entity-mode") == 0 && ++i < args->n) { transferEntityIdBits = strtol ( args->arr[i], NULL, 0 ); } else if (strcmp(a, "-subject-entity-id") == 0 && ++i < args->n) { dis_entity_id id; if (dis_parseEntityID ( &id, args->arr[i], strlen(args->arr[i])+1, ":/." ) == 0) { subjectEntityID = id; subjectEntitySpecified = 1; } else { error_external("invalid entity ID \"%s\"", args->arr[i]); } } else if (strcmp(a, "-mouse-mode") == 0 && ++i < args->n) { a = args->arr[i]; if( strcmp(a, "fast") == 0 ) mouse_stick_mode = mouse_FAST; else if( strcmp(a, "normal") == 0 ) mouse_stick_mode = mouse_NORMAL; else if( strcmp(a, "precise") == 0 ) mouse_stick_mode = mouse_PRECISE; else error_external("invalid mouse mode \"%s\", must be fast|normal|precise", a); } else if (strcmp(a, "-hud-mode") == 0 ) { list_add_elem(switches, "-hud-mode"); } else { error_external("unknown command line option `%s' or missing mandatory value of the option", args->arr[i]); } } return switches; } int main(int argc, char **argv) { list_Type *args, *newPlayerSwitches; int i; error_init("ACM-" patchlevel_REVISION_STRING); curTime = 0.0; mouse_stick_mode = mouse_NORMAL; eye_to_screen_cm = 50.0; downward_view_angle_rad = units_DEGtoRAD(15.0); /* * An endGameThreshold of -1.0 means "use the radar lock range for * the current aircraft. */ end_game_threshold_meters = -1.0; end_game_mode = 0; /* * When accepting control of an entity, the default is to use our * site ID and keep everything else the same. */ transferEntityIdBits = 0x4; dis_if_haveAbsoluteTime = 0; ptblCount = ctblCount = 0; /* Parse command line arguments. */ args = list_new(); for ( i = 1; i < argc; i++ ) list_add_elem(args, argv[i]); newPlayerSwitches = processCommandSwitches(args); memory_dispose(args); if( name == NULL ) name = memory_strdup("Anonymous"); /* Init DIS module interface. */ /* Define handler for DIS transfer control requests. */ dis_if_setTransferControlRequestCallback ( dis_if_transferControlRequestHandler ); dis_if_enableNetwork(use_dis); if( disInit() != 0 ) error_external("DIS protocol initialization failed"); /* Init ACM global variables. */ init_init(objects, departure_time); /* Create 1 player. */ if( ! players_new(name, newPlayerSwitches) == 0 ) return 1; /* Do simulation until player dies or quits. */ update_loop(frame_rate); /* Release all global stuff. */ init_term(); memory_dispose(newPlayerSwitches); memory_dispose(name); memory_dispose(objects); memory_dispose(dis_relay_name); memory_dispose(departure_time); return memory_report(); } acm-6.0_20200416/src/dis/0000755000000000000000000000000013175511160013141 5ustar rootrootacm-6.0_20200416/src/dis/doc/0000755000000000000000000000000013175062143013710 5ustar rootrootacm-6.0_20200416/src/dis/doc/dis_library_network.svg0000644000000000000000000005362113065071607020517 0ustar rootroot image/svg+xml DIS applications obtainunique application id'sand other values bycommunicating with theSIM/x server DIS applicationscommunicate to one-another via the DISbroadcast port (UDP) DIS Application DIS Application DIS Application SIM/x Server acm-6.0_20200416/src/dis/doc/dis_library_stack.svg0000644000000000000000000001146713065071606020134 0ustar rootroot image/svg+xml DIS/x SIM/x DIS acm-6.0_20200416/src/dis/doc/rfc1014_XDR_encoding.txt0000644000000000000000000011246613106475701020130 0ustar rootroot Network Working Group Sun Microsystems, Inc. Request for Comments: 1014 June 1987 XDR: External Data Representation Standard STATUS OF THIS MEMO This RFC describes a standard that Sun Microsystems, Inc., and others are using, one we wish to propose for the Internet's consideration. Distribution of this memo is unlimited. 1. INTRODUCTION XDR is a standard for the description and encoding of data. It is useful for transferring data between different computer architectures, and has been used to communicate data between such diverse machines as the SUN WORKSTATION*, VAX*, IBM-PC*, and Cray*. XDR fits into the ISO presentation layer, and is roughly analogous in purpose to X.409, ISO Abstract Syntax Notation. The major difference between these two is that XDR uses implicit typing, while X.409 uses explicit typing. XDR uses a language to describe data formats. The language can only be used only to describe data; it is not a programming language. This language allows one to describe intricate data formats in a concise manner. The alternative of using graphical representations (itself an informal language) quickly becomes incomprehensible when faced with complexity. The XDR language itself is similar to the C language [1], just as Courier [4] is similar to Mesa. Protocols such as Sun RPC (Remote Procedure Call) and the NFS* (Network File System) use XDR to describe the format of their data. The XDR standard makes the following assumption: that bytes (or octets) are portable, where a byte is defined to be 8 bits of data. A given hardware device should encode the bytes onto the various media in such a way that other hardware devices may decode the bytes without loss of meaning. For example, the Ethernet* standard suggests that bytes be encoded in "little-endian" style [2], or least significant bit first. 2. BASIC BLOCK SIZE The representation of all items requires a multiple of four bytes (or 32 bits) of data. The bytes are numbered 0 through n-1. The bytes are read or written to some byte stream such that byte m always precedes byte m+1. If the n bytes needed to contain the data are not a multiple of four, then the n bytes are followed by enough (0 to 3) SUN Microsystems [Page 1] RFC 1014 External Data Representation June 1987 residual zero bytes, r, to make the total byte count a multiple of 4. We include the familiar graphic box notation for illustration and comparison. In most illustrations, each box (delimited by a plus sign at the 4 corners and vertical bars and dashes) depicts a byte. Ellipses (...) between boxes show zero or more additional bytes where required. +--------+--------+...+--------+--------+...+--------+ | byte 0 | byte 1 |...|byte n-1| 0 |...| 0 | BLOCK +--------+--------+...+--------+--------+...+--------+ |<-----------n bytes---------->|<------r bytes------>| |<-----------n+r (where (n+r) mod 4 = 0)>----------->| 3. XDR DATA TYPES Each of the sections that follow describes a data type defined in the XDR standard, shows how it is declared in the language, and includes a graphic illustration of its encoding. For each data type in the language we show a general paradigm declaration. Note that angle brackets (< and >) denote variablelength sequences of data and square brackets ([ and ]) denote fixed-length sequences of data. "n", "m" and "r" denote integers. For the full language specification and more formal definitions of terms such as "identifier" and "declaration", refer to section 5: "The XDR Language Specification". For some data types, more specific examples are included. A more extensive example of a data description is in section 6: "An Example of an XDR Data Description". 3.1 Integer An XDR signed integer is a 32-bit datum that encodes an integer in the range [-2147483648,2147483647]. The integer is represented in two's complement notation. The most and least significant bytes are 0 and 3, respectively. Integers are declared as follows: int identifier; (MSB) (LSB) +-------+-------+-------+-------+ |byte 0 |byte 1 |byte 2 |byte 3 | INTEGER +-------+-------+-------+-------+ <------------32 bits------------> SUN Microsystems [Page 2] RFC 1014 External Data Representation June 1987 3.2.Unsigned Integer An XDR unsigned integer is a 32-bit datum that encodes a nonnegative integer in the range [0,4294967295]. It is represented by an unsigned binary number whose most and least significant bytes are 0 and 3, respectively. An unsigned integer is declared as follows: unsigned int identifier; (MSB) (LSB) +-------+-------+-------+-------+ |byte 0 |byte 1 |byte 2 |byte 3 | UNSIGNED INTEGER +-------+-------+-------+-------+ <------------32 bits------------> 3.3 Enumeration Enumerations have the same representation as signed integers. Enumerations are handy for describing subsets of the integers. Enumerated data is declared as follows: enum { name-identifier = constant, ... } identifier; For example, the three colors red, yellow, and blue could be described by an enumerated type: enum { RED = 2, YELLOW = 3, BLUE = 5 } colors; It is an error to encode as an enum any other integer than those that have been given assignments in the enum declaration. 3.4 Boolean Booleans are important enough and occur frequently enough to warrant their own explicit type in the standard. Booleans are declared as follows: bool identifier; This is equivalent to: enum { FALSE = 0, TRUE = 1 } identifier; SUN Microsystems [Page 3] RFC 1014 External Data Representation June 1987 3.5 Hyper Integer and Unsigned Hyper Integer The standard also defines 64-bit (8-byte) numbers called hyper integer and unsigned hyper integer. Their representations are the obvious extensions of integer and unsigned integer defined above. They are represented in two's complement notation. The most and least significant bytes are 0 and 7, respectively. Their declarations: hyper identifier; unsigned hyper identifier; (MSB) (LSB) +-------+-------+-------+-------+-------+-------+-------+-------+ |byte 0 |byte 1 |byte 2 |byte 3 |byte 4 |byte 5 |byte 6 |byte 7 | +-------+-------+-------+-------+-------+-------+-------+-------+ <----------------------------64 bits----------------------------> HYPER INTEGER UNSIGNED HYPER INTEGER 3.6 Floating-point The standard defines the floating-point data type "float" (32 bits or 4 bytes). The encoding used is the IEEE standard for normalized single-precision floating-point numbers [3]. The following three fields describe the single-precision floating-point number: S: The sign of the number. Values 0 and 1 represent positive and negative, respectively. One bit. E: The exponent of the number, base 2. 8 bits are devoted to this field. The exponent is biased by 127. F: The fractional part of the number's mantissa, base 2. 23 bits are devoted to this field. Therefore, the floating-point number is described by: (-1)**S * 2**(E-Bias) * 1.F SUN Microsystems [Page 4] RFC 1014 External Data Representation June 1987 It is declared as follows: float identifier; +-------+-------+-------+-------+ |byte 0 |byte 1 |byte 2 |byte 3 | SINGLE-PRECISION S| E | F | FLOATING-POINT NUMBER +-------+-------+-------+-------+ 1|<- 8 ->|<-------23 bits------>| <------------32 bits------------> Just as the most and least significant bytes of a number are 0 and 3, the most and least significant bits of a single-precision floating- point number are 0 and 31. The beginning bit (and most significant bit) offsets of S, E, and F are 0, 1, and 9, respectively. Note that these numbers refer to the mathematical positions of the bits, and NOT to their actual physical locations (which vary from medium to medium). The EEE specifications should be consulted concerning the encoding for signed zero, signed infinity (overflow), and denormalized numbers (underflow) [3]. According to IEEE specifications, the "NaN" (not a number) is system dependent and should not be used externally. 3.7 Double-precision Floating-point The standard defines the encoding for the double-precision floating- point data type "double" (64 bits or 8 bytes). The encoding used is the IEEE standard for normalized double-precision floating-point numbers [3]. The standard encodes the following three fields, which describe the double-precision floating-point number: S: The sign of the number. Values 0 and 1 represent positive and negative, respectively. One bit. E: The exponent of the number, base 2. 11 bits are devoted to this field. The exponent is biased by 1023. F: The fractional part of the number's mantissa, base 2. 52 bits are devoted to this field. Therefore, the floating-point number is described by: (-1)**S * 2**(E-Bias) * 1.F SUN Microsystems [Page 5] RFC 1014 External Data Representation June 1987 It is declared as follows: double identifier; +------+------+------+------+------+------+------+------+ |byte 0|byte 1|byte 2|byte 3|byte 4|byte 5|byte 6|byte 7| S| E | F | +------+------+------+------+------+------+------+------+ 1|<--11-->|<-----------------52 bits------------------->| <-----------------------64 bits-------------------------> DOUBLE-PRECISION FLOATING-POINT Just as the most and least significant bytes of a number are 0 and 3, the most and least significant bits of a double-precision floating- point number are 0 and 63. The beginning bit (and most significant bit) offsets of S, E , and F are 0, 1, and 12, respectively. Note that these numbers refer to the mathematical positions of the bits, and NOT to their actual physical locations (which vary from medium to medium). The IEEE specifications should be consulted concerning the encoding for signed zero, signed infinity (overflow), and denormalized numbers (underflow) [3]. According to IEEE specifications, the "NaN" (not a number) is system dependent and should not be used externally. 3.8 Fixed-length Opaque Data At times, fixed-length uninterpreted data needs to be passed among machines. This data is called "opaque" and is declared as follows: opaque identifier[n]; where the constant n is the (static) number of bytes necessary to contain the opaque data. If n is not a multiple of four, then the n bytes are followed by enough (0 to 3) residual zero bytes, r, to make the total byte count of the opaque object a multiple of four. 0 1 ... +--------+--------+...+--------+--------+...+--------+ | byte 0 | byte 1 |...|byte n-1| 0 |...| 0 | +--------+--------+...+--------+--------+...+--------+ |<-----------n bytes---------->|<------r bytes------>| |<-----------n+r (where (n+r) mod 4 = 0)------------>| FIXED-LENGTH OPAQUE 3.9 Variable-length Opaque Data The standard also provides for variable-length (counted) opaque data, SUN Microsystems [Page 6] RFC 1014 External Data Representation June 1987 defined as a sequence of n (numbered 0 through n-1) arbitrary bytes to be the number n encoded as an unsigned integer (as described below), and followed by the n bytes of the sequence. Byte m of the sequence always precedes byte m+1 of the sequence, and byte 0 of the sequence always follows the sequence's length (count). If n is not a multiple of four, then the n bytes are followed by enough (0 to 3) residual zero bytes, r, to make the total byte count a multiple of four. Variable-length opaque data is declared in the following way: opaque identifier; or opaque identifier<>; The constant m denotes an upper bound of the number of bytes that the sequence may contain. If m is not specified, as in the second declaration, it is assumed to be (2**32) - 1, the maximum length. The constant m would normally be found in a protocol specification. For example, a filing protocol may state that the maximum data transfer size is 8192 bytes, as follows: opaque filedata<8192>; 0 1 2 3 4 5 ... +-----+-----+-----+-----+-----+-----+...+-----+-----+...+-----+ | length n |byte0|byte1|...| n-1 | 0 |...| 0 | +-----+-----+-----+-----+-----+-----+...+-----+-----+...+-----+ |<-------4 bytes------->|<------n bytes------>|<---r bytes--->| |<----n+r (where (n+r) mod 4 = 0)---->| VARIABLE-LENGTH OPAQUE It is an error to encode a length greater than the maximum described in the specification. 3.10 String The standard defines a string of n (numbered 0 through n-1) ASCII bytes to be the number n encoded as an unsigned integer (as described above), and followed by the n bytes of the string. Byte m of the string always precedes byte m+1 of the string, and byte 0 of the string always follows the string's length. If n is not a multiple of four, then the n bytes are followed by enough (0 to 3) residual zero bytes, r, to make the total byte count a multiple of four. Counted byte strings are declared as follows: SUN Microsystems [Page 7] RFC 1014 External Data Representation June 1987 string object; or string object<>; The constant m denotes an upper bound of the number of bytes that a string may contain. If m is not specified, as in the second declaration, it is assumed to be (2**32) - 1, the maximum length. The constant m would normally be found in a protocol specification. For example, a filing protocol may state that a file name can be no longer than 255 bytes, as follows: string filename<255>; 0 1 2 3 4 5 ... +-----+-----+-----+-----+-----+-----+...+-----+-----+...+-----+ | length n |byte0|byte1|...| n-1 | 0 |...| 0 | +-----+-----+-----+-----+-----+-----+...+-----+-----+...+-----+ |<-------4 bytes------->|<------n bytes------>|<---r bytes--->| |<----n+r (where (n+r) mod 4 = 0)---->| STRING It is an error to encode a length greater than the maximum described in the specification. 3.11 Fixed-length Array Declarations for fixed-length arrays of homogeneous elements are in the following form: type-name identifier[n]; Fixed-length arrays of elements numbered 0 through n-1 are encoded by individually encoding the elements of the array in their natural order, 0 through n-1. Each element's size is a multiple of four bytes. Though all elements are of the same type, the elements may have different sizes. For example, in a fixed-length array of strings, all elements are of type "string", yet each element will vary in its length. +---+---+---+---+---+---+---+---+...+---+---+---+---+ | element 0 | element 1 |...| element n-1 | +---+---+---+---+---+---+---+---+...+---+---+---+---+ |<--------------------n elements------------------->| FIXED-LENGTH ARRAY SUN Microsystems [Page 8] RFC 1014 External Data Representation June 1987 3.12 Variable-length Array Counted arrays provide the ability to encode variable-length arrays of homogeneous elements. The array is encoded as the element count n (an unsigned integer) followed by the encoding of each of the array's elements, starting with element 0 and progressing through element n- 1. The declaration for variable-length arrays follows this form: type-name identifier; or type-name identifier<>; The constant m specifies the maximum acceptable element count of an array; if m is not specified, as in the second declaration, it is assumed to be (2**32) - 1. 0 1 2 3 +--+--+--+--+--+--+--+--+--+--+--+--+...+--+--+--+--+ | n | element 0 | element 1 |...|element n-1| +--+--+--+--+--+--+--+--+--+--+--+--+...+--+--+--+--+ |<-4 bytes->|<--------------n elements------------->| COUNTED ARRAY It is an error to encode a value of n that is greater than the maximum described in the specification. 3.13 Structure Structures are declared as follows: struct { component-declaration-A; component-declaration-B; ... } identifier; The components of the structure are encoded in the order of their declaration in the structure. Each component's size is a multiple of four bytes, though the components may be different sizes. +-------------+-------------+... | component A | component B |... STRUCTURE +-------------+-------------+... 3.14 Discriminated Union A discriminated union is a type composed of a discriminant followed by a type selected from a set of prearranged types according to the SUN Microsystems [Page 9] RFC 1014 External Data Representation June 1987 value of the discriminant. The type of discriminant is either "int", "unsigned int", or an enumerated type, such as "bool". The component types are called "arms" of the union, and are preceded by the value of the discriminant which implies their encoding. Discriminated unions are declared as follows: union switch (discriminant-declaration) { case discriminant-value-A: arm-declaration-A; case discriminant-value-B: arm-declaration-B; ... default: default-declaration; } identifier; Each "case" keyword is followed by a legal value of the discriminant. The default arm is optional. If it is not specified, then a valid encoding of the union cannot take on unspecified discriminant values. The size of the implied arm is always a multiple of four bytes. The discriminated union is encoded as its discriminant followed by the encoding of the implied arm. 0 1 2 3 +---+---+---+---+---+---+---+---+ | discriminant | implied arm | DISCRIMINATED UNION +---+---+---+---+---+---+---+---+ |<---4 bytes--->| 3.15 Void An XDR void is a 0-byte quantity. Voids are useful for describing operations that take no data as input or no data as output. They are also useful in unions, where some arms may contain data and others do not. The declaration is simply as follows: void; Voids are illustrated as follows: ++ || VOID ++ --><-- 0 bytes 3.16 Constant The data declaration for a constant follows this form: SUN Microsystems [Page 10] RFC 1014 External Data Representation June 1987 const name-identifier = n; "const" is used to define a symbolic name for a constant; it does not declare any data. The symbolic constant may be used anywhere a regular constant may be used. For example, the following defines a symbolic constant DOZEN, equal to 12. const DOZEN = 12; 3.17 Typedef "typedef" does not declare any data either, but serves to define new identifiers for declaring data. The syntax is: typedef declaration; The new type name is actually the variable name in the declaration part of the typedef. For example, the following defines a new type called "eggbox" using an existing type called "egg": typedef egg eggbox[DOZEN]; Variables declared using the new type name have the same type as the new type name would have in the typedef, if it was considered a variable. For example, the following two declarations are equivalent in declaring the variable "fresheggs": eggbox fresheggs; egg fresheggs[DOZEN]; When a typedef involves a struct, enum, or union definition, there is another (preferred) syntax that may be used to define the same type. In general, a typedef of the following form: typedef <> identifier; may be converted to the alternative form by removing the "typedef" part and placing the identifier after the "struct", "union", or "enum" keyword, instead of at the end. For example, here are the two ways to define the type "bool": SUN Microsystems [Page 11] RFC 1014 External Data Representation June 1987 typedef enum { /* using typedef */ FALSE = 0, TRUE = 1 } bool; enum bool { /* preferred alternative */ FALSE = 0, TRUE = 1 }; The reason this syntax is preferred is one does not have to wait until the end of a declaration to figure out the name of the new type. 3.18 Optional-data Optional-data is one kind of union that occurs so frequently that we give it a special syntax of its own for declaring it. It is declared as follows: type-name *identifier; This is equivalent to the following union: union switch (bool opted) { case TRUE: type-name element; case FALSE: void; } identifier; It is also equivalent to the following variable-length array declaration, since the boolean "opted" can be interpreted as the length of the array: type-name identifier<1>; Optional-data is not so interesting in itself, but it is very useful for describing recursive data-structures such as linked-lists and trees. For example, the following defines a type "stringlist" that encodes lists of arbitrary length strings: struct *stringlist { string item<>; stringlist next; }; SUN Microsystems [Page 12] RFC 1014 External Data Representation June 1987 It could have been equivalently declared as the following union: union stringlist switch (bool opted) { case TRUE: struct { string item<>; stringlist next; } element; case FALSE: void; }; or as a variable-length array: struct stringlist<1> { string item<>; stringlist next; }; Both of these declarations obscure the intention of the stringlist type, so the optional-data declaration is preferred over both of them. The optional-data type also has a close correlation to how recursive data structures are represented in high-level languages such as Pascal or C by use of pointers. In fact, the syntax is the same as that of the C language for pointers. 3.19 Areas for Future Enhancement The XDR standard lacks representations for bit fields and bitmaps, since the standard is based on bytes. Also missing are packed (or binary-coded) decimals. The intent of the XDR standard was not to describe every kind of data that people have ever sent or will ever want to send from machine to machine. Rather, it only describes the most commonly used data-types of high-level languages such as Pascal or C so that applications written in these languages will be able to communicate easily over some medium. One could imagine extensions to XDR that would let it describe almost any existing protocol, such as TCP. The minimum necessary for this are support for different block sizes and byte-orders. The XDR discussed here could then be considered the 4-byte big-endian member of a larger XDR family. SUN Microsystems [Page 13] RFC 1014 External Data Representation June 1987 4. DISCUSSION (1) Why use a language for describing data? What's wrong with diagrams? There are many advantages in using a data-description language such as XDR versus using diagrams. Languages are more formal than diagrams and lead to less ambiguous descriptions of data. Languages are also easier to understand and allow one to think of other issues instead of the low-level details of bit-encoding. Also, there is a close analogy between the types of XDR and a high-level language such as C or Pascal. This makes the implementation of XDR encoding and decoding modules an easier task. Finally, the language specification itself is an ASCII string that can be passed from machine to machine to perform on-the-fly data interpretation. (2) Why is there only one byte-order for an XDR unit? Supporting two byte-orderings requires a higher level protocol for determining in which byte-order the data is encoded. Since XDR is not a protocol, this can't be done. The advantage of this, though, is that data in XDR format can be written to a magnetic tape, for example, and any machine will be able to interpret it, since no higher level protocol is necessary for determining the byte-order. (3) Why is the XDR byte-order big-endian instead of little-endian? Isn't this unfair to little-endian machines such as the VAX(r), which has to convert from one form to the other? Yes, it is unfair, but having only one byte-order means you have to be unfair to somebody. Many architectures, such as the Motorola 68000* and IBM 370*, support the big-endian byte-order. (4) Why is the XDR unit four bytes wide? There is a tradeoff in choosing the XDR unit size. Choosing a small size such as two makes the encoded data small, but causes alignment problems for machines that aren't aligned on these boundaries. A large size such as eight means the data will be aligned on virtually every machine, but causes the encoded data to grow too big. We chose four as a compromise. Four is big enough to support most architectures efficiently, except for rare machines such as the eight-byte aligned Cray*. Four is also small enough to keep the encoded data restricted to a reasonable size. SUN Microsystems [Page 14] RFC 1014 External Data Representation June 1987 (5) Why must variable-length data be padded with zeros? It is desirable that the same data encode into the same thing on all machines, so that encoded data can be meaningfully compared or checksummed. Forcing the padded bytes to be zero ensures this. (6) Why is there no explicit data-typing? Data-typing has a relatively high cost for what small advantages it may have. One cost is the expansion of data due to the inserted type fields. Another is the added cost of interpreting these type fields and acting accordingly. And most protocols already know what type they expect, so data-typing supplies only redundant information. However, one can still get the benefits of data-typing using XDR. One way is to encode two things: first a string which is the XDR data description of the encoded data, and then the encoded data itself. Another way is to assign a value to all the types in XDR, and then define a universal type which takes this value as its discriminant and for each value, describes the corresponding data type. 5. THE XDR LANGUAGE SPECIFICATION 5.1 Notational Conventions This specification uses an extended Back-Naur Form notation for describing the XDR language. Here is a brief description of the notation: (1) The characters '|', '(', ')', '[', ']', '"', and '*' are special. (2) Terminal symbols are strings of any characters surrounded by double quotes. (3) Non-terminal symbols are strings of non-special characters. (4) Alternative items are separated by a vertical bar ("|"). (5) Optional items are enclosed in brackets. (6) Items are grouped together by enclosing them in parentheses. (7) A '*' following an item means 0 or more occurrences of that item. For example, consider the following pattern: "a " "very" (", " "very")* [" cold " "and "] " rainy " ("day" | "night") An infinite number of strings match this pattern. A few of them are: SUN Microsystems [Page 15] RFC 1014 External Data Representation June 1987 "a very rainy day" "a very, very rainy day" "a very cold and rainy day" "a very, very, very cold and rainy night" 5.2 Lexical Notes (1) Comments begin with '/*' and terminate with '*/'. (2) White space serves to separate items and is otherwise ignored. (3) An identifier is a letter followed by an optional sequence of letters, digits or underbar ('_'). The case of identifiers is not ignored. (4) A constant is a sequence of one or more decimal digits, optionally preceded by a minus-sign ('-'). 5.3 Syntax Information declaration: type-specifier identifier | type-specifier identifier "[" value "]" | type-specifier identifier "<" [ value ] ">" | "opaque" identifier "[" value "]" | "opaque" identifier "<" [ value ] ">" | "string" identifier "<" [ value ] ">" | type-specifier "*" identifier | "void" value: constant | identifier type-specifier: [ "unsigned" ] "int" | [ "unsigned" ] "hyper" | "float" | "double" | "bool" | enum-type-spec | struct-type-spec | union-type-spec | identifier enum-type-spec: "enum" enum-body enum-body: "{" ( identifier "=" value ) SUN Microsystems [Page 16] RFC 1014 External Data Representation June 1987 ( "," identifier "=" value )* "}" struct-type-spec: "struct" struct-body struct-body: "{" ( declaration ";" ) ( declaration ";" )* "}" union-type-spec: "union" union-body union-body: "switch" "(" declaration ")" "{" ( "case" value ":" declaration ";" ) ( "case" value ":" declaration ";" )* [ "default" ":" declaration ";" ] "}" constant-def: "const" identifier "=" constant ";" type-def: "typedef" declaration ";" | "enum" identifier enum-body ";" | "struct" identifier struct-body ";" | "union" identifier union-body ";" definition: type-def | constant-def specification: definition * 5.4 Syntax Notes (1) The following are keywords and cannot be used as identifiers: "bool", "case", "const", "default", "double", "enum", "float", "hyper", "opaque", "string", "struct", "switch", "typedef", "union", "unsigned" and "void". (2) Only unsigned constants may be used as size specifications for arrays. If an identifier is used, it must have been declared previously as an unsigned constant in a "const" definition. SUN Microsystems [Page 17] RFC 1014 External Data Representation June 1987 (3) Constant and type identifiers within the scope of a specification are in the same name space and must be declared uniquely within this scope. (4) Similarly, variable names must be unique within the scope of struct and union declarations. Nested struct and union declarations create new scopes. (5) The discriminant of a union must be of a type that evaluates to an integer. That is, "int", "unsigned int", "bool", an enumerated type or any typedefed type that evaluates to one of these is legal. Also, the case values must be one of the legal values of the discriminant. Finally, a case value may not be specified more than once within the scope of a union declaration. 6. AN EXAMPLE OF AN XDR DATA DESCRIPTION Here is a short XDR data description of a thing called a "file", which might be used to transfer files from one machine to another. const MAXUSERNAME = 32; /* max length of a user name */ const MAXFILELEN = 65535; /* max length of a file */ const MAXNAMELEN = 255; /* max length of a file name */ /* * Types of files: */ enum filekind { TEXT = 0, /* ascii data */ DATA = 1, /* raw data */ EXEC = 2 /* executable */ }; /* * File information, per kind of file: */ union filetype switch (filekind kind) { case TEXT: void; /* no extra information */ case DATA: string creator; /* data creator */ case EXEC: string interpretor; /* program interpretor */ }; SUN Microsystems [Page 18] RFC 1014 External Data Representation June 1987 /* * A complete file: */ struct file { string filename; /* name of file */ filetype type; /* info about file */ string owner; /* owner of file */ opaque data; /* file data */ }; Suppose now that there is a user named "john" who wants to store his lisp program "sillyprog" that contains just the data "(quit)". His file would be encoded as follows: OFFSET HEX BYTES ASCII COMMENTS ------ --------- ----- -------- 0 00 00 00 09 .... -- length of filename = 9 4 73 69 6c 6c sill -- filename characters 8 79 70 72 6f ypro -- ... and more characters ... 12 67 00 00 00 g... -- ... and 3 zero-bytes of fill 16 00 00 00 02 .... -- filekind is EXEC = 2 20 00 00 00 04 .... -- length of interpretor = 4 24 6c 69 73 70 lisp -- interpretor characters 28 00 00 00 04 .... -- length of owner = 4 32 6a 6f 68 6e john -- owner characters 36 00 00 00 06 .... -- length of file data = 6 40 28 71 75 69 (qui -- file data bytes ... 44 74 29 00 00 t).. -- ... and 2 zero-bytes of fill 7. REFERENCES [1] Brian W. Kernighan & Dennis M. Ritchie, "The C Programming Language", Bell Laboratories, Murray Hill, New Jersey, 1978. [2] Danny Cohen, "On Holy Wars and a Plea for Peace", IEEE Computer, October 1981. [3] "IEEE Standard for Binary Floating-Point Arithmetic", ANSI/IEEE Standard 754-1985, Institute of Electrical and Electronics Engineers, August 1985. [4] "Courier: The Remote Procedure Call Protocol", XEROX Corporation, XSIS 038112, December 1981. SUN Microsystems [Page 19] RFC 1014 External Data Representation June 1987 8. TRADEMARKS AND OWNERS SUN WORKSTATION Sun Microsystems, Inc. VAX Digital Equipment Corporation IBM-PC International Business Machines Corporation Cray Cray Research NFS Sun Microsystems, Inc. Ethernet Xerox Corporation. Motorola 68000 Motorola, Inc. IBM 370 International Business Machines Corporation SUN Microsystems [Page 20] acm-6.0_20200416/src/dis/doc/xdr_manual_page.txt0000644000000000000000000004446313106475701017614 0ustar rootroot man7.org > Linux > man-pages Linux/UNIX system programming training NAME | SYNOPSIS AND DESCRIPTION | ATTRIBUTES | SEE ALSO | COLOPHON XDR(3) Linux Programmer's Manual XDR(3) NAME top xdr - library routines for external data representation SYNOPSIS AND DESCRIPTION top These routines allow C programmers to describe arbitrary data structures in a machine-independent fashion. Data for remote procedure calls are transmitted using these routines. The prototypes below are declared in and make use of the following types: typedef int bool_t; typedef bool_t (*xdrproc_t) (XDR *, void *,...); For the declaration of the XDR type, see . bool_t xdr_array(XDR *xdrs, char **arrp, unsigned int *sizep, unsigned int maxsize, unsigned int elsize, xdrproc_t elproc); A filter primitive that translates between variable-length arrays and their corresponding external representations. The argument arrp is the address of the pointer to the array, while sizep is the address of the element count of the array; this element count cannot exceed maxsize. The argument elsize is the sizeof each of the array's elements, and elproc is an XDR filter that translates between the array elements' C form, and their external representation. This routine returns one if it succeeds, zero otherwise. bool_t xdr_bool(XDR *xdrs, bool_t *bp); A filter primitive that translates between booleans (C integers) and their external representations. When encoding data, this filter produces values of either one or zero. This routine returns one if it succeeds, zero otherwise. bool_t xdr_bytes(XDR *xdrs, char **sp, unsigned int *sizep, unsigned int maxsize); A filter primitive that translates between counted byte strings and their external representations. The argument sp is the address of the string pointer. The length of the string is located at address sizep; strings cannot be longer than maxsize. This routine returns one if it succeeds, zero otherwise. bool_t xdr_char(XDR *xdrs, char *cp); A filter primitive that translates between C characters and their external representations. This routine returns one if it succeeds, zero otherwise. Note: encoded characters are not packed, and occupy 4 bytes each. For arrays of characters, it is worthwhile to consider xdr_bytes(), xdr_opaque() or xdr_string(). void xdr_destroy(XDR *xdrs); A macro that invokes the destroy routine associated with the XDR stream, xdrs. Destruction usually involves freeing private data structures associated with the stream. Using xdrs after invoking xdr_destroy() is undefined. bool_t xdr_double(XDR *xdrs, double *dp); A filter primitive that translates between C double precision numbers and their external representations. This routine returns one if it succeeds, zero otherwise. bool_t xdr_enum(XDR *xdrs, enum_t *ep); A filter primitive that translates between C enums (actually integers) and their external representations. This routine returns one if it succeeds, zero otherwise. bool_t xdr_float(XDR *xdrs, float *fp); A filter primitive that translates between C floats and their external representations. This routine returns one if it succeeds, zero otherwise. void xdr_free(xdrproc_t proc, char *objp); Generic freeing routine. The first argument is the XDR routine for the object being freed. The second argument is a pointer to the object itself. Note: the pointer passed to this routine is not freed, but what it points to is freed (recursively). unsigned int xdr_getpos(XDR *xdrs); A macro that invokes the get-position routine associated with the XDR stream, xdrs. The routine returns an unsigned integer, which indicates the position of the XDR byte stream. A desirable feature of XDR streams is that simple arithmetic works with this number, although the XDR stream instances need not guarantee this. long *xdr_inline(XDR *xdrs, int len); A macro that invokes the inline routine associated with the XDR stream, xdrs. The routine returns a pointer to a contiguous piece of the stream's buffer; len is the byte length of the desired buffer. Note: pointer is cast to long *. Warning: xdr_inline() may return NULL (0) if it cannot allocate a contiguous piece of a buffer. Therefore the behavior may vary among stream instances; it exists for the sake of efficiency. bool_t xdr_int(XDR *xdrs, int *ip); A filter primitive that translates between C integers and their external representations. This routine returns one if it succeeds, zero otherwise. bool_t xdr_long(XDR *xdrs, long *lp); A filter primitive that translates between C long integers and their external representations. This routine returns one if it succeeds, zero otherwise. void xdrmem_create(XDR *xdrs, char *addr, unsigned int size, enum xdr_op op); This routine initializes the XDR stream object pointed to by xdrs. The stream's data is written to, or read from, a chunk of memory at location addr whose length is no more than size bytes long. The op determines the direction of the XDR stream (either XDR_ENCODE, XDR_DECODE, or XDR_FREE). bool_t xdr_opaque(XDR *xdrs, char *cp, unsigned int cnt); A filter primitive that translates between fixed size opaque data and its external representation. The argument cp is the address of the opaque object, and cnt is its size in bytes. This routine returns one if it succeeds, zero otherwise. bool_t xdr_pointer(XDR *xdrs, char **objpp, unsigned int objsize, xdrproc_t xdrobj); Like xdr_reference() except that it serializes null pointers, whereas xdr_reference() does not. Thus, xdr_pointer() can represent recursive data structures, such as binary trees or linked lists. void xdrrec_create(XDR *xdrs, unsigned int sendsize, unsigned int recvsize, char *handle, int (*readit) (char *, char *, int), int (*writeit) (char *, char *, int)); This routine initializes the XDR stream object pointed to by xdrs. The stream's data is written to a buffer of size sendsize; a value of zero indicates the system should use a suitable default. The stream's data is read from a buffer of size recvsize; it too can be set to a suitable default by passing a zero value. When a stream's output buffer is full, writeit is called. Similarly, when a stream's input buffer is empty, readit is called. The behavior of these two routines is similar to the system calls read(2) and write(2), except that handle is passed to the former routines as the first argument. Note: the XDR stream's op field must be set by the caller. Warning: to read from an XDR stream created by this API, you'll need to call xdrrec_skiprecord() first before calling any other XDR APIs. This inserts additional bytes in the stream to provide record boundary information. Also, XDR streams created with different xdr*_create APIs are not compatible for the same reason. bool_t xdrrec_endofrecord(XDR *xdrs, int sendnow); This routine can be invoked only on streams created by xdrrec_create(). The data in the output buffer is marked as a completed record, and the output buffer is optionally written out if sendnow is nonzero. This routine returns one if it succeeds, zero otherwise. bool_t xdrrec_eof(XDR *xdrs); This routine can be invoked only on streams created by xdrrec_create(). After consuming the rest of the current record in the stream, this routine returns one if the stream has no more input, zero otherwise. bool_t xdrrec_skiprecord(XDR *xdrs); This routine can be invoked only on streams created by xdrrec_create(). It tells the XDR implementation that the rest of the current record in the stream's input buffer should be discarded. This routine returns one if it succeeds, zero otherwise. bool_t xdr_reference(XDR *xdrs, char **pp, unsigned int size, xdrproc_t proc); A primitive that provides pointer chasing within structures. The argument pp is the address of the pointer; size is the sizeof the structure that *pp points to; and proc is an XDR procedure that filters the structure between its C form and its external representation. This routine returns one if it succeeds, zero otherwise. Warning: this routine does not understand null pointers. Use xdr_pointer() instead. xdr_setpos(XDR *xdrs, unsigned int pos); A macro that invokes the set position routine associated with the XDR stream xdrs. The argument pos is a position value obtained from xdr_getpos(). This routine returns one if the XDR stream could be repositioned, and zero otherwise. Warning: it is difficult to reposition some types of XDR streams, so this routine may fail with one type of stream and succeed with another. bool_t xdr_short(XDR *xdrs, short *sp); A filter primitive that translates between C short integers and their external representations. This routine returns one if it succeeds, zero otherwise. void xdrstdio_create(XDR *xdrs, FILE *file, enum xdr_op op); This routine initializes the XDR stream object pointed to by xdrs. The XDR stream data is written to, or read from, the stdio stream file. The argument op determines the direction of the XDR stream (either XDR_ENCODE, XDR_DECODE, or XDR_FREE). Warning: the destroy routine associated with such XDR streams calls fflush(3) on the file stream, but never fclose(3). bool_t xdr_string(XDR *xdrs, char **sp, unsigned int maxsize); A filter primitive that translates between C strings and their corresponding external representations. Strings cannot be longer than maxsize. Note: sp is the address of the string's pointer. This routine returns one if it succeeds, zero otherwise. bool_t xdr_u_char(XDR *xdrs, unsigned char *ucp); A filter primitive that translates between unsigned C characters and their external representations. This routine returns one if it succeeds, zero otherwise. bool_t xdr_u_int(XDR *xdrs, unsigned *up); A filter primitive that translates between C unsigned integers and their external representations. This routine returns one if it succeeds, zero otherwise. bool_t xdr_u_long(XDR *xdrs, unsigned long *ulp); A filter primitive that translates between C unsigned long integers and their external representations. This routine returns one if it succeeds, zero otherwise. bool_t xdr_u_short(XDR *xdrs, unsigned short *usp); A filter primitive that translates between C unsigned short integers and their external representations. This routine returns one if it succeeds, zero otherwise. bool_t xdr_union(XDR *xdrs, int *dscmp, char *unp, struct xdr_discrim *choices, xdrproc_t defaultarm); /* may equal NULL */ A filter primitive that translates between a discriminated C union and its corresponding external representation. It first translates the discriminant of the union located at dscmp. This discriminant is always an enum_t. Next the union located at unp is translated. The argument choices is a pointer to an array of xdr_discrim() structures. Each structure contains an ordered pair of [value,proc]. If the union's discriminant is equal to the associated value, then the proc is called to translate the union. The end of the xdr_discrim() structure array is denoted by a routine of value NULL. If the discriminant is not found in the choices array, then the defaultarm procedure is called (if it is not NULL). Returns one if it succeeds, zero otherwise. bool_t xdr_vector(XDR *xdrs, char *arrp, unsigned int size, unsigned int elsize, xdrproc_t elproc); A filter primitive that translates between fixed-length arrays and their corresponding external representations. The argument arrp is the address of the pointer to the array, while size is the element count of the array. The argument elsize is the sizeof each of the array's elements, and elproc is an XDR filter that translates between the array elements' C form, and their external representation. This routine returns one if it succeeds, zero otherwise. bool_t xdr_void(void); This routine always returns one. It may be passed to RPC routines that require a function argument, where nothing is to be done. bool_t xdr_wrapstring(XDR *xdrs, char **sp); A primitive that calls xdr_string(xdrs, sp,MAXUN.UNSIGNED ); where MAXUN.UNSIGNED is the maximum value of an unsigned integer. xdr_wrapstring() is handy because the RPC package passes a maximum of two XDR routines as arguments, and xdr_string(), one of the most frequently used primitives, requires three. Returns one if it succeeds, zero otherwise. ATTRIBUTES top For an explanation of the terms used in this section, see attributes(7). ┌────────────────────────────────┬───────────────┬─────────┐ │Interface │ Attribute │ Value │ ├────────────────────────────────┼───────────────┼─────────┤ │xdr_array(), xdr_bool(), │ Thread safety │ MT-Safe │ │xdr_bytes(), xdr_char(), │ │ │ │xdr_destroy(), xdr_double(), │ │ │ │xdr_enum(), xdr_float(), │ │ │ │xdr_free(), xdr_getpos(), │ │ │ │xdr_inline(), xdr_int(), │ │ │ │xdr_long(), xdrmem_create(), │ │ │ │xdr_opaque(), xdr_pointer(), │ │ │ │xdrrec_create(), xdrrec_eof(), │ │ │ │xdrrec_endofrecord(), │ │ │ │xdrrec_skiprecord(), │ │ │ │xdr_reference(), xdr_setpos(), │ │ │ │xdr_short(), xdrstdio_create(), │ │ │ │xdr_string(), xdr_u_char(), │ │ │ │xdr_u_int(), xdr_u_long(), │ │ │ │xdr_u_short(), xdr_union(), │ │ │ │xdr_vector(), xdr_void(), │ │ │ │xdr_wrapstring() │ │ │ └────────────────────────────────┴───────────────┴─────────┘ SEE ALSO top rpc(3) The following manuals: eXternal Data Representation Standard: Protocol Specification eXternal Data Representation: Sun Technical Notes XDR: External Data Representation Standard, RFC 1014, Sun Microsystems, Inc., USC-ISI. COLOPHON top This page is part of release 4.11 of the Linux man-pages project. A description of the project, information about reporting bugs, and the latest version of this page, can be found at https://www.kernel.org/doc/man-pages/. 2015-07-23 XDR(3) Pages that refer to this page: rpc(3) Copyright and license for this manual page HTML rendering created 2017-05-03 by Michael Kerrisk, author of The Linux Programming Interface, maintainer of the Linux man-pages project. For details of in-depth Linux/UNIX system programming training courses that I teach, look here. Hosting by jambit GmbH. Valid XHTML 1.1 Cover of TLPI acm-6.0_20200416/src/dis/doc/dis_library.html0000644000000000000000000001503113104300603017065 0ustar rootroot DIS/x Library Description
These notes from Riley Rainey have now only an historical value and illustrate the motivation and the origin of the DIS library in ACM. The current ACM-5.0-ico solved the problem of site ID and application ID assignment in another way, then removing the need for a simx layer and the corresponding libraries and simx server; also RCP is not needed anymore making all a bit simpler. Also the data base of DIS is gone as it is not used anymore. [U.S.]

DIS/x: An Implementation of the IEEE 1278

Distributed Interactive Simulation Protocol

Version 1.0

Riley Rainey

Preface

Why another DIS implementation?

I have always been interested in distributed interactive simulations.  In 1991, I released via Usenet a free X11-based  multi-player air combat simulation which I had named “ACM”.

In the spring of 1994, Eyal Lebedinsky contacted me.  He is the author of another freely available flight simulator, “fly8”.  He introduced me to the IEEE DIS protocol and expressed interest in using DIS to integrate our two programs.  He pointed me to the Naval Postgraduate School’s freely available DIS implementation, called NPSNET.

At the time I looked at it, the NPSNET DIS library is a reasonably complete, if somewhat literal implementation of the DIS protocol standard written for Sun and SGI UNIX systems.  However, it had the significant portability drawback that it was written exclusively for big-endian machines.  I set out to create a more functional and portable implementation but was quickly drawn back to work more directly related to my “real” job.

Early in 1995, I was contacted by Mats Loftkvist.  Mats had independently taken the time to integrate a version of NPSNET into the current release of ACM.  This prompted me to dust-off the work that I had dropped earlier and to begin considering in earnest how one might create an improved DIS interface.

My thinking is that a reasonably complete DIS library would automate these functions:

1. Allow for easy construction, transmission, reception and disassembly of DIS PDU’s. This implies that the library must standardize data structures that will correspond to all DIS PDU data structures.

2. Present the programmer with easy access to the wide variety of pre-defined DIS enumerated values.

Here is where I start to wish to go further than the NPSNET code:

3. Provide standardized mechanisms that will automatically generate values for many fields whose contents are defined to be outside the scope of the DIS protocol. For example, it would be nice to be able to supply application id field values (part of the simulation address structure) with little or no user-level coordination required.

4. Provide a mechanism that would allow an application to temporarily define new entity types. Those new entity types would have dynamically assigned enumeration values. Those temporary entity types could then be used by other applications.

5. Provide a mechanism to allow disparate DIS applications to share other simulation-related information. An example of this would be a database of all defined DIS entity types that could be queried at runtime to determine information about entities owned by other applications.

6. Implement the source code so that it is not big-endian specific.

7. Provide a mechanism to automate Dead Reckoning computation that might include the automated transmission of position updates.

DIS library layout

My DIS library implementation is divided into three layers. Each layer is assigned a three or four character naming prefix. All subroutine calls and data structures belonging to a given layer have names that begin with the associated character prefix.

The lowest level layer is called simply DIS. It defines routines used to broadcast and receive PDU’s on the network, translating those PDU’s to and from PDU data structures defined in this library. Translation is performed through calls to ONC XDR library routines.

There are a number of details to the DIS protocol that are undefined. For example, no guidance is provided on how various user-defined fields (e.g. a DIS application id) are actually allocated. The implication seems to be that these values are manually allocated and distributed before an exercise begins. That method seems unusable in an environment where you’d like to insulate users from the details of DIS. To remedy this problem, I have defined a central simulation management server, SIM/x. Individual DIS applications may elect to consult that server to be assured to be getting appropriate values for these fields.

The middle, SIM/x, layer implements an interface to this central SIM/x server. Server requests are communicated via ONC RPC.

The top layer, called DIS/x, integrates the two lower layers in a manner that allows DIS applications to interoperate whether they are consulting a common SIM/x server or not. This layer is implemented in such a way that the runtime environment can be tailored (through various environment variables and special configuration files) to allow the use of automatic (SIM/x) or manual value allocation techniques.

Riley Rainey -- Dallas, Texas, August 15, 1995

References

acm-6.0_20200416/src/dis/dis/0000755000000000000000000000000013646051406013725 5ustar rootrootacm-6.0_20200416/src/dis/dis/datum.h0000644000000000000000000003637513066337232015226 0ustar rootroot/* * DIS/x : An implementation of the IEEE 1278.1 protocol * * Copyright (C) 1996, Riley Rainey (rainey@netcom.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of either: * * a) the GNU Library General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your * option) any later version. A description of the terms and conditions * of the GLPL may be found in the "COPYING.LIB" file. * * b) the "Artistic License" which comes with this Kit. Information * about this license may be found in the "Artistic" file. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License or the Artistic License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Information describing how to contact the author can be found in the * README file. */ #ifndef DATUM_H #define DATUM_H #ifdef datum_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * This enumerative type was prepared from values listed in: * * "Enumeration and Bit-Encoded Values for use with * IEEE 1278.1 - 1994, Distributed Interactive Simulation -- * Application Protocols" * * Document Number: IST-CR-93-46 * Date: March 1994 * * Copyright (C) 1995, Riley Rainey, riley@netcom.com * * DATUM IDENTIFIERS * * Problem: Which are fixed and which are variable ??? */ typedef enum { datum_Identification = 10000, /* */ datum_EntityType = 11000, /* */ datum_Concatenated = 11100, /* */ datum_Kind = 11110, /* u_long */ datum_Domain = 11120, /* u_long */ datum_Country = 11130, /* u_long */ datum_Category = 11140, /* u_long */ datum_Subcategory = 11150, /* u_long */ datum_Specific = 11160, /* u_long */ datum_Extra = 11170, /* u_long */ datum_ForceID = 11200, /* u_long */ datum_Description = 11300, /* */ datum_AlternativeEntityType = 12000, /* */ datum_AltKind = 12110, /* u_long */ datum_AltDomain = 12120, /* u_long */ datum_AltCountry = 12130, /* u_long */ datum_AltCategory = 12140, /* u_long */ datum_AltSubcategory = 12150, /* u_long */ datum_AltSpecific = 12160, /* u_long */ datum_AltExtra = 12170, /* u_long */ datum_AltDescription = 12300, /* */ datum_EntityMarking = 13000, /* */ datum_EntityMarkingCharacters = 13100, /* char[10] */ datum_CrewID = 13200, /* char[10] */ datum_TaskOrganization = 14000, /* */ datum_RegimentName = 14200, /* String */ datum_BattalionName = 14300, /* String */ datum_CompanyName = 14400, /* String */ datum_PlatoonName = 14500, /* */ datum_SquadName = 14520, /* */ datum_TeamName = 14540, /* */ datum_BumperNumber = 14600, /* */ datum_VehicleNumber = 14700, /* */ datum_UnitNumber = 14800, /* */ datum_DISIdentity = 15000, /* */ datum_DISSiteID = 15100, /* */ datum_DISHostID = 15200, /* */ datum_DISEntityID = 15300, /* */ datum_Loads = 20000, /* */ datum_CrewMembers = 21000, /* */ datum_CrewMemberID = 21100, /* */ datum_Health = 21200, /* */ datum_JobAssignment = 21300, /* String */ datum_Fuel = 23000, /* */ datum_Quantity = 23100, /* Liters */ datum_QuantityGallons = 23105, /* Gallons */ datum_Ammunition = 24000, /* */ datum_120mmHEATquantity = 24001, /* Rounds */ datum_120mmSABOTquantity = 24002, /* Rounds */ datum_127mmM8quantity = 24003, /* Rounds */ datum_127mmM20quantity = 24004, /* Rounds */ datum_762mmM62quantity = 24005, /* Rounds */ datum_M250UKL8A1quantity = 24006, /* Grenades */ datum_M250UKL8A3quantity = 24007, /* Grenades */ datum_762mmM80quantity = 24008, /* Rounds */ datum_127mmquantity = 24009, /* Rounds */ datum_762mmquantity = 24010, /* Rounds */ datum_Minesquantity = 24060, /* Mines */ datum_AmmunitionType = 24100, /* */ datum_AmmunitionKind = 24110, /* */ datum_AmmunitionDomain = 24120, /* */ datum_AmmunitionCountry = 24130, /* */ datum_AmmunitionCategory = 24140, /* */ datum_AmmunitionSubcategory = 24150, /* */ datum_AmmunitionExtra = 24160, /* */ datum_AmmunitionDescription = 24300, /* */ datum_Cargo = 25000, /* */ datum_VehicleMass = 26000, /* u_long */ datum_SupplyQuantity = 27000, /* */ datum_Armament = 28000, /* Boolean */ datum_Status = 30000, /* */ datum_Position = 31000, /* */ datum_MilGrid10 = 31100, /* */ datum_GeocentricCoordinates = 31200, /* */ datum_GeocentricCoordinatesX = 31210, /* u_long */ datum_GeocentricCoordinatesY = 31220, /* u_long */ datum_GeocentricCoordinatesZ = 31230, /* u_long */ datum_Latitude = 31300, /* */ datum_Longitude = 31400, /* */ datum_Orientation = 32000, /* */ datum_HullHeadingAngle = 32100, /* Degrees */ datum_HullPitchAngle = 32200, /* */ datum_RollAngle = 32300, /* */ datum_OrientationX = 32500, /* u_long */ datum_OrientationY = 32600, /* u_long */ datum_OrientationZ = 32700, /* u_long */ datum_Appearance = 33000, /* */ datum_AmbientLighting = 33100, /* */ datum_Lights = 33101, /* */ datum_PaintScheme = 33200, /* */ datum_Smoke = 33300, /* */ datum_TrailingEffects = 33400, /* */ datum_Flaming = 33500, /* */ datum_Marking = 33600, /* */ datum_MinePlowsAttached = 33710, /* */ datum_MineRollersAttached = 33720, /* */ datum_TankTurretAzimuth = 33730, /* Degrees */ datum_FailuresandMalfunctions = 34000, /* */ datum_Age = 34100, /* Miles */ datum_Kilometers = 34110, /* */ datum_Damage = 35000, /* */ datum_Cause = 35050, /* */ datum_MobilityKill = 35100, /* */ datum_Fire_PowerKill = 35200, /* */ datum_PersonnelCasualties = 35300, /* */ datum_Velocity = 36000, /* */ datum_XVelocity = 36100, /* Meters/sec */ datum_YVelocity = 36200, /* Meters/sec */ datum_ZVelocity = 36300, /* Meters/sec */ datum_Acceleration = 37000, /* */ datum_XAcceleration = 37100, /* */ datum_YAcceleration = 37200, /* */ datum_ZAcceleration = 37300, /* */ datum_EngineStatus = 38100, /* */ datum_Exercise = 40000, /* */ datum_TerrainDatabase = 41000, /* */ datum_Missions = 42000, /* */ datum_MissionID = 42100, /* */ datum_MissionType = 42200, /* */ datum_MissionRequestTimeStamp = 42300, /* */ datum_ExerciseDescription = 43000, /* String */ datum_Name = 43100, /* String */ datum_Entities = 43200, /* Integer */ datum_Version = 43300, /* */ datum_Environment = 50000, /* */ datum_Weather = 51000, /* */ datum_ThermalCondition = 51100, /* */ datum_Time = 52000, /* */ datum_TimeofDayDiscrete = 52100, /* */ datum_TimeofDayContinuous = 52200, /* */ datum_TimeMode = 52300, /* */ datum_TimeScene = 52305, /* */ datum_CurrentHour = 52310, /* */ datum_CurrentMinute = 52320, /* */ datum_CurrentSecond = 52330, /* */ datum_Azimuth = 52340, /* */ datum_MaximumElevation = 52350, /* */ datum_TimeZone = 52360, /* */ datum_TimeSunriseEnabled = 52400, /* */ datum_SunriseHour = 52410, /* */ datum_SunriseMinute = 52420, /* */ datum_SunriseSecond = 52430, /* */ datum_SunriseAzimuth = 52440, /* */ datum_TimeSunsetEnabled = 52500, /* */ datum_SunsetHour = 52510, /* */ datum_SunsetMinute = 52520, /* */ datum_SunsetSecond = 52530, /* */ datum_Date = 52600, /* */ datum_Month = 52610, /* */ datum_Day = 52620, /* */ datum_Year = 52630, /* */ datum_Clouds = 53000, /* */ datum_CloudLayerEnable = 53050, /* */ datum_CloudLayerSelection = 53060, /* */ datum_CloudVisibility = 53100, /* */ datum_CloudBaseAltitude = 53200, /* Meters */ datum_CloudBaseAltitudeFeet = 53250, /* Feet */ datum_CloudCeiling = 53300, /* Meters */ datum_cloudCeilingFeet = 53350, /* Feet */ datum_Characteristics = 53400, /* */ datum_Precipitation = 54000, /* */ datum_Rain = 54100, /* Boolean */ datum_Fog = 55000, /* Boolean */ datum_Visibility = 55100, /* Meters */ datum_VisibilityMiles = 55105, /* Miles */ datum_Density = 55200, /* */ datum_Base = 55300, /* */ datum_ViewLayerFromAbove = 55401, /* */ datum_TransitionRange = 55410, /* */ datum_Bottom = 55420, /* Meters */ datum_BottomFeet = 55425, /* Feet */ datum_Ceiling = 55430, /* Meters */ datum_CeilingFeet = 55435, /* Feet */ datum_HeavenlyBodies = 56000, /* */ datum_Sun = 56100, /* */ datum_SunPosition = 56110, /* */ datum_SunPositionAzimuth = 56120, /* */ datum_SunPositionElevation = 56130, /* */ datum_SunPositionIntensity = 56140, /* */ datum_Moon = 56200, /* */ datum_MoonPosition = 56210, /* */ datum_MoonPositionAzimuth = 56220, /* */ datum_MoonPositionElevation = 56230, /* */ datum_MoonPositionIntensity = 56240, /* */ datum_Horizon = 56310, /* */ datum_HorizonAzimuth = 56320, /* */ datum_HorizonElevation = 56330, /* */ datum_HorizonHeading = 56340, /* */ datum_HorizonIntensity = 56350, /* */ datum_Meteorological = 57000, /* */ datum_MeteorologicalTemperature = 57100, /* */ datum_MeteorologicalHumidity = 57200, /* */ datum_MeteorologicalVisibility = 57300, /* */ datum_MeteorologicalWinds = 57400, /* */ datum_MeteorologicalSpeed = 57410, /* */ datum_MeteorologicalRainsoak = 57500, /* */ datum_Haze = 58000, /* Boolean */ datum_HazeVisibility = 58100, /* Meters */ datum_HazeVisibilityMiles = 58105, /* Miles */ datum_HazeDensity = 58200, /* */ datum_HazeCeiling = 58430, /* Meters */ datum_HazeCeilingFeet = 58435, /* Feet */ datum_Communications = 60000, /* */ datum_ChannelType = 61100, /* */ datum_ChannelType1 = 61101, /* */ datum_ChannelIdentification = 61200, /* */ datum_AlphaIdentification = 61300, /* */ datum_RadioIdentification = 61400, /* */ datum_LandLineIdentification = 61500, /* */ datum_IntercomIdentification = 61600, /* */ datum_GroupNetworkChannelNumber = 61700, /* */ datum_RadioCommunicationsStatus = 62100, /* */ datum_StationaryRadioTransmittersDefaultTime = 62200, /* u_long */ datum_MovingRadioTransmittersDefaultTime = 62300, /* u_long */ datum_StationaryRadioSignalsDefaultTime = 62400, /* */ datum_MovingRadioSignalDefaultTime = 62500, /* */ datum_RadioInitTransecSecurityKey = 63101, /* variable */ datum_RadioInitInternalNoiseLevel = 63102, /* variable */ datum_RadioInitSquelchThreshold = 63103, /* variable */ datum_RadioInitAntennaLocation = 63104, /* variable */ datum_RadioInitAntennaPatternType = 63105, /* variable */ datum_RadioInitAntennaPatternLength = 63106, /* variable */ datum_RadioInitBeamDefinition = 63107, /* variable */ datum_RadioInitTransmitHeartbeatTime = 63108, /* variable */ datum_RadioInitTransmitDistanceThreshold = 63109, /* variable */ datum_RadioChannelInitLockoutID = 63110, /* variable */ datum_RadioChannelInitHopsetID = 63111, /* variable */ datum_RadioChannelInitPresetFrequency = 63112, /* variable */ datum_RadioChannelInitFrequencySyncTime = 63113, /* variable */ datum_RadioChannelInitComsecKey = 63114, /* variable */ datum_RadioChannelInitAlpha = 63115, /* variable */ datum_AlgorithmParameters = 70000, /* */ datum_DeadReckoningAlgorithm = 71000, /* */ datum_DRALocationThreshold = 71100, /* u_long */ datum_DRAOrientationThreshold = 71200, /* */ datum_DRATimeThreshold = 71300, /* */ datum_SimulationManagementParameters = 72000, /* */ datum_CheckpointInterval = 72100, /* */ datum_TransmitterTimeThreshold = 72600, /* */ datum_ReceiverTimeThreshold = 72700, /* */ datum_InteroperabilityMode = 73000, /* */ datum_SIMNETDataCollection = 74000, /* variable* */ datum_EventID = 75000, /* */ datum_SourceSiteID = 75100, /* */ datum_SourceHostID = 75200, /* */ datum_ArticulatedPart = 90000, /* */ datum_ArticulatedPartID = 90050, /* */ datum_ArticulatedPartIndex = 90070, /* */ datum_ArticulatedPartPosition = 90100, /* */ datum_ArticulatedPartPositionRate = 90200, /* */ datum_ArticulatedPartExtension = 90300, /* */ datum_ArticulatedPartExtensionRate = 90400, /* */ datum_ArticulatedPartX = 90500, /* */ datum_ArticulatedPartXRate = 90600, /* */ datum_ArticulatedPartY = 90700, /* */ datum_ArticulatedPartYRate = 90800, /* */ datum_ArticulatedPartZ = 90900, /* */ datum_ArticulatedPartZRate = 91000, /* */ datum_ArticulatedPartAzimuth = 91100, /* */ datum_ArticulatedPartAzimuthRate = 91200, /* */ datum_ArticulatedPartElevation = 91300, /* */ datum_ArticulatedPartElevationRate = 91400, /* */ datum_ArticulatedPartRotation = 91500, /* */ datum_ArticulatedPartRotationRate = 91600, /* */ datum_DRAAngularXVelocity = 100001, /* */ datum_DRAAngularYVelocity = 100002, /* */ datum_DRAAngularZVelocity = 100003, /* */ datum_AppearanceTrailingEffects = 100004, /* */ datum_AppearanceHatch = 100005, /* */ datum_AppearanceCharacterSet = 100008, /* */ datum_CapabilityAmmunitionSupplier = 100010, /* */ datum_CapabilityMiscellaneousSupplier = 100011, /* */ datum_CapabilityRepairProvider = 100012, /* */ datum_ArticulationParameter = 100014, /* */ datum_ArticulationParameterType = 100047, /* */ datum_ArticulationParameterValue = 100048, /* */ datum_TimeofDayScene = 100058 /* */ } datum_Type; EXTERN char * datum_lookupDatumIDName(datum_Type id); #undef EXTERN #endif acm-6.0_20200416/src/dis/dis/dis.c0000644000000000000000000007156513260344464014667 0ustar rootroot/* * DIS/x : An implementation of the IEEE 1278.1 protocol * * Copyright (C) 1997, Riley Rainey (rrainey@ix.netcom.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of either: * * a) the GNU Library General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your * option) any later version. A description of the terms and conditions * of the GLPL may be found in the "COPYING.LIB" file. * * b) the "Artistic License" which comes with this Kit. Information * about this license may be found in the "Artistic" file. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License or the Artistic License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Information describing how to contact the author can be found in the * README file. */ #ifdef WINNT #define WINVER WindowsXP #endif #include #include #include #include #include #ifdef WINNT #include #include #else #include #include #include #include #endif #include #include #include #include #include "../../util/error.h" #include "../../util/memory.h" #include "xdr.h" #include "xdr_dis.h" #include "datum.h" #define dis_IMPORT #include "dis.h" #ifdef WINNT // recvmsg() not available under WINNT. #undef HAVE_RECVMSG #else #define HAVE_RECVMSG // Cope with slightly different field names of msghdr: Solaris and BSD call // them "msg_accessright...", any other system calls them "msg_control...". #undef HAVE_MSG_ACCRIGHTS #define HAVE_MSG_CONTROL #endif #define MILLION 1000000 #define dis_timestamp_const 2147483646L /* 2 ^ 31 - 1 */ #ifdef WINNT typedef __int64 my_quad_t; #else typedef long long my_quad_t; #endif #ifdef WINNT #else #define INVALID_SOCKET -1 #define SOCKET_ERROR -1 #endif #ifdef WINNT static char *errorCodeToString(int code) { static char s[999]; char win_err_descr[900]; DWORD err = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM, NULL, code, LANG_SYSTEM_DEFAULT, win_err_descr, sizeof(win_err_descr), NULL ); if( err > 0 ){ snprintf(s, sizeof(s), "%s (Windows error code %d)", win_err_descr, code); } else { snprintf(s, sizeof(s), "error code %d (description not available: FormatMessageA() failed with code %lu)", code, err); } return s; } #endif DISForce dis_parseForce(char *s) { if( s == NULL ) return -1; else if( strcmp(s, "Other") == 0 ) return DISForceOther; else if( strcmp(s, "Friendly") == 0 ) return DISForceFriendly; else if( strcmp(s, "Opposing") == 0 ) return DISForceOpposing; else if( strcmp(s, "Neutral") == 0 ) return DISForceNeutral; else return -1; } char * dis_forceToString(DISForce force) { switch(force){ case DISForceOther: return "Other"; case DISForceFriendly: return "Friendly"; case DISForceOpposing: return "Opposing"; case DISForceNeutral: return "Neutral"; default: error_internal("invalid force: %d", force); } } int dis_entityWildcardMatch (const dis_entity_type *in, const dis_entity_type *pattern, const dis_entity_type *pattern_mask) { if (pattern_mask->kind == 0 || pattern->kind == in->kind) { if (pattern_mask->domain == 0 || pattern->domain == in->domain) { if (pattern_mask->country == 0 || pattern->country == in->country) { if (pattern_mask->category == 0 || pattern->category == in->category) { if (pattern_mask->subcategory == 0 || pattern->subcategory == in->subcategory) { if (pattern_mask->specific == 0 || pattern->specific == in->specific) { if (pattern_mask->extra == 0 || pattern->extra == in->extra) { return 1; } } } } } } } return 0; } dis_Result dis_addArticulationParm(dis_entity_state_pdu * esp, dis_articulation_parm * parm, int *parmID) { int n = esp->art_parm_count + 1; if (esp->art_parm_count == 0) { esp->art_parm = (dis_articulation_parm *) memory_allocate(sizeof(dis_articulation_parm), NULL); } else { esp->art_parm = (dis_articulation_parm *) memory_realloc(esp->art_parm, sizeof(dis_articulation_parm) * n); } /* * Return an error if the memory could not be allocated */ if (esp->art_parm == NULL) { esp->art_parm_count = 0; return dis_RESULT_NO_MEMORY; } esp->art_parm[esp->art_parm_count] = *parm; esp->art_parm_count = n; *parmID = n; return dis_RESULT_OK; } int dis_setNBIOState(dis_Transceiver * xcvr, int state) { #ifdef WINNT unsigned long int i; #else int i; #endif i = (state) ? 1 : 0; #ifdef WINNT if (ioctlsocket(xcvr->s, FIONBIO, &i) != 0) { #else if (ioctl(xcvr->s, FIONBIO, &i) != 0) { #endif return -1; } return 0; } dis_Transceiver * dis_openTransceiver(int isServer, char *host_name, int host_port) { #ifdef WINNT //char Hostname[100]; //HOSTENT *pHostEnt; //char *ad; #else char buf[BUFSIZ]; int n; struct ifconf ifc; struct ifreq *ifr; #endif int s, i = 0; int on = 1; dis_Transceiver *xcvr; int isClient, useBroadcast; /* Empty host name is the same as NULL: */ if( host_name != NULL && host_name[0] == 0 ) host_name = NULL; /* Check port range: */ if( !(0 <= host_port && host_port <= 65535) ) error_internal("expected host port in [0,65535], %d given", host_port); isClient = ! isServer; useBroadcast = isClient && host_name == NULL; #ifdef WINNT /* * Initialize Windows sockets DLL. */ WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD(2, 2); err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { fprintf(stderr, "failed initializing Winsock.dll -- error code from WSAStartup() is %d\n", err); return NULL; } if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) { fprintf(stderr, "could not find a usable version of Winsock.dll\n"); WSACleanup(); return NULL; } #endif /* Create socket: */ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) { perror("failed creating Internet socket"); return NULL; } /* * If client without relay server, enable broadcasting on any interface * on the specified port: */ if( isClient && host_name == NULL ){ struct sockaddr_in sin; if( useBroadcast ){ if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *) &on, sizeof(on)) == SOCKET_ERROR) { #ifdef WINNT errno = WSAGetLastError(); #endif perror("can't set broadcast flag"); return NULL; } if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) == SOCKET_ERROR) { perror("can't reuse broadcast port"); return NULL; } } sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_ANY); sin.sin_port = htons(host_port); if( bind(s, (struct sockaddr *) &sin, sizeof(sin)) != 0 ){ perror("bind()"); return NULL; } } if( isServer ){ struct sockaddr_in sin; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) == SOCKET_ERROR) { perror("can't reuse port"); return NULL; } sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_ANY); sin.sin_port = htons(host_port); if( bind(s, (struct sockaddr *) &sin, sizeof(sin)) != 0 ){ perror("bind()"); return NULL; } } /* * Allocate and initialize the transceiver structure. */ xcvr = (dis_Transceiver *) memory_allocate(sizeof(dis_Transceiver), NULL); xcvr->s = 0; xcvr->num_dest = 0; xcvr->s = s; /* * If client with relay server, configure a single destination: */ if ( isClient && host_name != NULL ) { char service[6]; struct addrinfo hints; struct addrinfo *results; /* Retrieves list of available matching relay host services: */ memory_zero(&hints); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = 0; hints.ai_flags = 0; sprintf(service, "%d", host_port); int err = getaddrinfo(host_name, service, &hints, &results); if( err != 0 ){ fprintf(stderr, "Failed retrieving info for %s:%d: %s\n", host_name, host_port, gai_strerror(err)); close(s); memory_dispose(xcvr); return NULL; } if( results == NULL ){ fprintf(stderr, "The host %s:%d does not support IPv4 datagrams\n", host_name, host_port); freeaddrinfo(results); close(s); memory_dispose(xcvr); return NULL; } /* ...and use the first matching result: */ xcvr->dest[0].addr = *((struct sockaddr_in *)(results->ai_addr)); xcvr->dest[0].type = 1; xcvr->num_dest = 1; freeaddrinfo(results); return xcvr; } /* * Currently the relay server uses its own sending function, so no need to * configure the destinations for it. */ if( isServer ){ xcvr->num_dest = 0; return xcvr; } /* * Client using broadcast: configure all the available interfaces. * * Determine how many interfaces are configured on the local system. */ #ifdef WINNT #ifdef notdef gethostname(Hostname, sizeof(Hostname)); pHostEnt = gethostbyname(Hostname); i = 0; while (pHostEnt->h_addr_list[i]) { // pHostEnt->h_addr_list[i] - the current address in host order ad = pHostEnt->h_addr_list[i]; bcopy((char *) ad, (char *) &xcvr->dest[i].addr.sin_addr, sizeof(xcvr->dest[i].addr)); bcopy((char *) ad, (char *) x, 4); xcvr->dest[i].addr.sin_family = AF_INET; xcvr->dest[i].addr.sin_port = htons(host_port); xcvr->dest[i].type = 0; i++; } #endif xcvr->dest[0].addr.sin_family = AF_INET; xcvr->dest[0].addr.sin_addr.S_un.S_addr = INADDR_BROADCAST; xcvr->dest[0].addr.sin_port = htons(host_port); xcvr->dest[0].type = 0; i = 1; #else ifc.ifc_len = BUFSIZ; ifc.ifc_ifcu.ifcu_buf = buf; if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0) { perror("error getting interface configuration"); close(s); memory_dispose(xcvr); return NULL; } n = ifc.ifc_len / sizeof(struct ifreq); /* * Insure that there are enough elements in blist to accomodate all interfaces. */ if (n > 32) { fprintf(stderr, "Too many host interfaces: %d\n", n); memory_dispose(xcvr); return NULL; } for (ifr = ifc.ifc_req; --n >= 0; ifr++) { /* * We're only interested in Internet domain interfaces */ if (ifr->ifr_addr.sa_family != AF_INET) continue; if (ioctl(s, SIOCGIFFLAGS, (char *) ifr) < 0) { perror("error getting interface flags"); close(s); memory_dispose(xcvr); return NULL; } /* * Skip boring cases ... */ if( (ifr->ifr_flags & IFF_UP) == 0) /* Ignore interface down. */ continue; if( (ifr->ifr_flags & IFF_LOOPBACK) != 0 ) /* Ignore loopback interface. */ continue; /* * Get the appropriate broadcast address based on the interface type. */ if (! useBroadcast && ifr->ifr_flags & IFF_POINTOPOINT) { if (ioctl(s, SIOCGIFDSTADDR, (char *) ifr) < 0) { close(s); perror("error getting address"); memory_dispose(xcvr); return NULL; } bcopy((char *) &ifr->ifr_dstaddr, (char *) &xcvr->dest[i].addr, sizeof(ifr->ifr_dstaddr)); } else if (useBroadcast && ifr->ifr_flags & IFF_BROADCAST) { if (ioctl(s, SIOCGIFBRDADDR, (char *) ifr) < 0) { close(s); perror("error getting broadcast address"); memory_dispose(xcvr); return NULL; } bcopy((char *) &ifr->ifr_broadaddr, (char *) &xcvr->dest[i].addr, sizeof(ifr->ifr_broadaddr)); } else { continue; } xcvr->dest[i].addr.sin_port = htons(host_port); xcvr->dest[i].type = 0; i++; } #endif /* not WINNT */ xcvr->num_dest = i; return xcvr; } void dis_closeTransceiver(dis_Transceiver * xcvr) { if( xcvr == NULL ) return; #ifdef WINNT shutdown(xcvr->s, SD_BOTH); closesocket(xcvr->s); WSACleanup(); #else close(xcvr->s); #endif memory_dispose(xcvr); } int dis_readPDU(dis_Transceiver * xcvr, dis_pdu * pdu) { char buffer[2048]; int size; xdr_Type *xdr; #ifdef HAVE_RECVMSG struct sockaddr from; struct msghdr msg; struct iovec vec; #endif read_next_pdu: #ifdef HAVE_RECVMSG msg.msg_name = (caddr_t) & from; msg.msg_namelen = sizeof(from); msg.msg_iov = &vec; msg.msg_iovlen = 1; #ifdef HAVE_MSG_ACCRIGHTS msg.msg_accrights = (caddr_t) NULL; msg.msg_accrightslen = 0; #endif #ifdef HAVE_MSG_CONTROL msg.msg_control = (caddr_t) NULL; msg.msg_controllen = 0; #endif vec.iov_base = (caddr_t) & buffer; vec.iov_len = sizeof(buffer); size = recvmsg(xcvr->s, &msg, 0); #else size = recv(xcvr->s, buffer, sizeof(buffer), 0); #endif if (size == -1) { return 0; } xdr = xdr_new(buffer, size, xdr_DECODE); if( ! xdr_dis_pdu(xdr, pdu) ){ fprintf(stderr, "ERROR: failed decoding received PDU: %s\n", xdr_getErrorDescription(xdr)); xdr_free(xdr); goto read_next_pdu; } if( xdr_getpos(xdr) != pdu->hdr.length ){ fprintf(stderr, "ERROR: failed decoding received PDU: stated length %d does not match actual packet length %d\n", pdu->hdr.length, xdr_getpos(xdr)); xdr_free(xdr); goto read_next_pdu; } xdr_free(xdr); return 1; } int dis_writePDU(dis_Transceiver * xcvr, dis_pdu * pdu) { char buffer[2048], *p; #ifdef HAVE_RECVMSG struct msghdr msg; struct iovec vec; #endif xdr_Type *xdr; int i, len; int err = 0; /* * Fill-out any length fields internal to the PDU (other than the length * field in the header. */ dis_addPDUSizes(pdu); xdr = xdr_new(buffer, sizeof(buffer), xdr_ENCODE); if( ! xdr_dis_pdu(xdr, pdu) ) error_internal("dis_writePDU(): failed encoding packet: %s", xdr_getErrorDescription(xdr)); len = xdr_getpos(xdr); xdr_free(xdr); /* * Now for a hack. We need to insert the correct packet length into * the PDU header. The header is somewhat stable from one protocol release * to the next, so I've just hard-coded it here. */ p = buffer + 8; *((u_short *) p) = htons(len); #ifdef HAVE_RECVMSG msg.msg_namelen = sizeof(struct sockaddr); msg.msg_iov = &vec; msg.msg_iovlen = 1; #ifdef HAVE_MSG_ACCRIGHTS msg.msg_accrights = (caddr_t) NULL; msg.msg_accrightslen = 0; #endif #ifdef HAVE_MSG_CONTROL msg.msg_control = (caddr_t) NULL; msg.msg_controllen = 0; #endif vec.iov_base = (caddr_t) & buffer; vec.iov_len = len; for (i = 0; i < xcvr->num_dest; ++i) { msg.msg_name = (caddr_t) & xcvr->dest[i].addr; if (sendmsg(xcvr->s, &msg, 0) == -1) { perror("on sendmsg"); err = 1; } }; #else for (i = 0; i < xcvr->num_dest; ++i) { if (sendto(xcvr->s, buffer, len, 0, (struct sockaddr *) &xcvr->dest[i].addr, sizeof(struct sockaddr)) == -1) { #ifdef WINNT fprintf(stderr, "failed sending packet: %s\n", errorCodeToString(WSAGetLastError())); #else perror("sendto()"); #endif } }; #endif if( err ) fprintf(stderr, "ERROR: failed sending DIS PDU to at least one destination address.\n"); return ! err; } static void dis_disposeVariableDatum(dis_variable_datum *v) { /* * BEWARE. * ====== * Here anything other than the types listed below is assumed * to be a dynamically allocated string. The same assumption * holds for xdr_dis_variable_datum() so both functions MUST be * kept in sync. */ if( !( v->datum_id == datum_GeocentricCoordinatesX || v->datum_id == datum_GeocentricCoordinatesY || v->datum_id == datum_GeocentricCoordinatesZ ) ){ memory_dispose(v->value.ptr_value); } } void dis_freePDUComponents(dis_pdu * p) { int i, j; if( p == NULL ) return; switch (p->hdr.pdu_type) { case PDUTypeDetonation: { dis_detonation_pdu *det = (dis_detonation_pdu *) p; if (det->num_art_parms > 0) { memory_dispose(det->art_parm); } } break; case PDUTypeEmission: { dis_em_emission_pdu *pdu = (dis_em_emission_pdu *) p; dis_em_system_info *s = pdu->system; dis_beam_info *b; for (i = 0; i < pdu->num_systems; ++i, ++s) { b = s->beam; for (j = 0; j < s->num_beams; ++j, ++b) { if (b->num_targets > 0) { memory_dispose((char *) b->tracked_target); } } if (s->num_beams > 0) { memory_dispose(s->beam); } } if (pdu->num_systems > 0) { memory_dispose(pdu->system); } } break; case PDUTypeEntityState: { dis_entity_state_pdu *pdu = (dis_entity_state_pdu *) p; if (pdu->art_parm_count > 0) { memory_dispose(pdu->art_parm); } } break; case PDUTypeComment: { dis_comment_pdu *m = (dis_comment_pdu *) p; if( m->num_fixed_data > 0 ) memory_dispose(m->fixed_datum); for(i = 0; i < m->num_variable_data; i++){ dis_disposeVariableDatum( &m->variable_datum[i] ); } memory_dispose(m->variable_datum); } break; case PDUTypeSetData: { dis_set_data_pdu *sd = (dis_set_data_pdu *) p; dis_datum_spec_record *dsr = &sd->datum_info; if( dsr->num_fixed_data > 0 ) memory_dispose(dsr->fixed_datum); for(i = 0; i < dsr->num_variable_data; i++){ dis_disposeVariableDatum( &dsr->variable_datum[i] ); } memory_dispose(dsr->variable_datum); } break; default: break; } } void dis_addPDUSizes(dis_pdu * p) { int i, j; switch (p->hdr.pdu_type) { case PDUTypeEmission: { dis_em_emission_pdu *pdu = (dis_em_emission_pdu *) p; dis_em_system_info *s = pdu->system; dis_beam_info *b; unsigned long len; for (i = 0; i < pdu->num_systems; ++i, ++s) { b = s->beam; len = 0; for (j = 0; j < pdu->system[i].num_beams; ++j, ++b) { b->beam_data_length = 13 + b->num_targets * 2; len += b->beam_data_length; } s->sys_data_length = (unsigned char) (5 + len); } } break; default: break; } } int dis_getRealTime(dis_time * result) { struct timeval t; struct timezone tz; my_quad_t i; if (gettimeofday(&t, &tz) != 0) { return -1; } result->hour = t.tv_sec / 3600; i = (t.tv_sec % 3600) * MILLION + t.tv_usec; i = (i * dis_timestamp_const / 3600) / MILLION; // set relative time (bit 32 reset) result->rel.timexxx = i & 0x7fffffff; return 0; } int dis_getTimestamp(dis_timestamp * result) { #if defined(NPSNET_COMPAT) time_t i = time(0); result->time = i >> 1; result->type = i & 1; #else struct timeval t; struct timezone tz; my_quad_t i; if (gettimeofday(&t, &tz) != 0) { return -1; } i = (t.tv_sec % 3600) * MILLION + t.tv_usec; i = (i * dis_timestamp_const / 3600) / MILLION; // set relative time (bit 32 reset)) result->timexxx = i & 0x7ffffff; //result->type = 0; #endif return 0; } void dis_timestampToTimeval(dis_timestamp * in, struct timeval *out) { #if defined(NPSNET_COMPAT) out->tv_sec = (in->time << 1) + in->type; out->tv_usec = 0; #else error_internal("not implemented", 0); /* my_quad_t i; i = (my_quad_t) in->time * MILLION * 3600 / dis_timestamp_const; out->tv_sec = (long) ( i / MILLION); out->tv_usec = (long) ( i % MILLION ); */ #endif } void dis_timeToTimeval(dis_time * in, struct timeval *out) { error_internal("not implemented", 0); /* my_quad_t i; i = (my_quad_t) in->rel.time * MILLION / dis_timestamp_const; out->tv_sec = (long) ( in->hour * 3600 + i / MILLION ); out->tv_usec = (long) ( i % MILLION ); */ } void dis_processNewDRParameters(dis_entity_state_pdu * pdu, dis_dr_parameters * dr) { switch (pdu->dr_parm.algorithm) { case DISDRMethodRPB: case DISDRMethodRVB: case DISDRMethodRPW: case DISDRMethodRVW: dis_generateDRParameters(pdu, dr); break; case DISDRMethodStatic: case DISDRMethodFPW: case DISDRMethodFVW: case DISDRMethodFPB: case DISDRMethodFVB: break; case DISDRMethodOther: default: break; } dr->pdu = *pdu; VEulerToMatrix( pdu->orientation.phi, pdu->orientation.theta, pdu->orientation.psi, &dr->R0); } void dis_generateDRParameters(dis_entity_state_pdu * pdu, dis_dr_parameters * dr) { double ox, oy, oz; double ax = 0.0, ay = 0.0, az = 0.0; double omega; ox = pdu->dr_parm.angular_vel.x; oy = pdu->dr_parm.angular_vel.y; oz = pdu->dr_parm.angular_vel.z; omega = sqrt(ox * ox + oy * oy + oz * oz); if (omega > 0.0) { ax = ox / omega; ay = oy / omega; az = oz / omega; } dr->omega = omega; dr->skew.m[0][0] = dr->skew.m[1][1] = dr->skew.m[2][2] = 0.0; dr->skew.m[1][0] = -az; dr->skew.m[0][1] = az; dr->skew.m[2][0] = ay; dr->skew.m[0][2] = -ay; dr->skew.m[2][1] = -ax; dr->skew.m[1][2] = ax; dr->aat.m[0][0] = ax * ax; dr->aat.m[1][0] = ax * ay; dr->aat.m[2][0] = ax * az; dr->aat.m[0][1] = ay * ax; dr->aat.m[1][1] = ay * ay; dr->aat.m[2][1] = ay * az; dr->aat.m[0][2] = az * ax; dr->aat.m[1][2] = az * ay; dr->aat.m[2][2] = az * az; } static void DISComputeDRMatrix(dis_dr_parameters * dr, double dT, VMatrix * m) { double theta = dr->omega * dT; double cosTheta = cos(theta); double sinTheta = sin(theta); double Icos, x = (1.0 - cosTheta); int i, j; for (i = 0; i < 3; ++i) { for (j = 0; j < 3; ++j) { if (i == j) { Icos = cosTheta; } else { Icos = 0.0; } m->m[i][j] = Icos - dr->skew.m[i][j] * sinTheta + dr->aat.m[i][j] * x; } } m->m[0][3] = m->m[1][3] = m->m[2][3] = 0.0; m->m[3][0] = m->m[3][1] = m->m[3][2] = 0.0; m->m[3][3] = 1.0; } void dis_computeDRPosition(dis_dr_parameters * dr, double dT, VPoint * pos, dis_linear_vel_vector * vel, VMatrix * orientation) { VMatrix DR; double hDTSqr; dis_entity_state_pdu * pdu = &dr->pdu; /* Position */ switch (dr->pdu.dr_parm.algorithm) { case DISDRMethodRPW: pos->x = pdu->pos.x + pdu->vel.x * dT; pos->y = pdu->pos.y + pdu->vel.y * dT; pos->z = pdu->pos.z + pdu->vel.z * dT; *vel = pdu->vel; DISComputeDRMatrix(dr, dT, &DR); VMatrixMultByRank(&DR, &dr->R0, orientation, 3); break; case DISDRMethodRVW: hDTSqr = 0.5 * dT * dT; pos->x = pdu->pos.x + pdu->vel.x * dT + pdu->dr_parm.linear_acc.x * hDTSqr; pos->y = pdu->pos.y + pdu->vel.y * dT + pdu->dr_parm.linear_acc.y * hDTSqr; pos->z = pdu->pos.z + pdu->vel.z * dT + pdu->dr_parm.linear_acc.z * hDTSqr; vel->x = (float) (pdu->vel.x + pdu->dr_parm.linear_acc.x * dT); vel->y = (float) (pdu->vel.y + pdu->dr_parm.linear_acc.y * dT); vel->z = (float) (pdu->vel.z + pdu->dr_parm.linear_acc.z * dT); DISComputeDRMatrix(dr, dT, &DR); VMatrixMultByRank(&DR, &dr->R0, orientation, 3); break; case DISDRMethodStatic: *pos = pdu->pos; *vel = pdu->vel; *orientation = dr->R0; break; case DISDRMethodFPW: pos->x = pdu->pos.x + pdu->vel.x * dT; pos->y = pdu->pos.y + pdu->vel.y * dT; pos->z = pdu->pos.z + pdu->vel.z * dT; *vel = pdu->vel; *orientation = dr->R0; break; case DISDRMethodFVW: hDTSqr = 0.5 * dT * dT; pos->x = pdu->pos.x + pdu->vel.x * dT + pdu->dr_parm.linear_acc.x * hDTSqr; pos->y = pdu->pos.y + pdu->vel.y * dT + pdu->dr_parm.linear_acc.y * hDTSqr; pos->z = pdu->pos.z + pdu->vel.z * dT + pdu->dr_parm.linear_acc.z * hDTSqr; vel->x = (float) (pdu->vel.x + pdu->dr_parm.linear_acc.x * dT); vel->y = (float) (pdu->vel.y + pdu->dr_parm.linear_acc.y * dT); vel->z = (float) (pdu->vel.z + pdu->dr_parm.linear_acc.z * dT); *orientation = dr->R0; break; /* * For all the remaining unimplemented methods it seems safe to simply * keep the current position, velocity and orientation: */ case DISDRMethodRPB: case DISDRMethodRVB: /* todo: position */ /* todo: orientation */ case DISDRMethodFPB: case DISDRMethodFVB: /* todo: position */ case DISDRMethodOther: /* how on earth would we handle this? callbacks, perhaps? */ default: /* Unknown method -- should we display a warning? */ *pos = pdu->pos; *vel = pdu->vel; *orientation = dr->R0; break; } } void dis_getDRThresholds(dis_dr_parameters * dr, double *time, double *location, double *orientation) { *time = dr->timeThreshold; *location = dr->locationThreshold; *orientation = dr->orientationThreshold; } void dis_setDRThresholds(dis_dr_parameters * dr, double time, double location, double orientation) { dr->timeThreshold = time; dr->locationThreshold = location; dr->orientationThreshold = orientation; } dis_DR_FLAGS dis_testDRThresholds(dis_dr_parameters *dr, double deltaT, VPoint *current_location, dis_euler_angles *current_orientation) { int result = 0; VPoint dr_loc, d_loc; dis_linear_vel_vector dr_vel; double d_squared, d1, d2, d3, orientation_error_squared; VMatrix dr_orientation, cur_orientation; if (deltaT > dr->timeThreshold) { result |= dis_DR_TIME; } else { dis_computeDRPosition(dr, deltaT, &dr_loc, &dr_vel, &dr_orientation); d_loc.x = current_location->x - dr_loc.x; d_loc.y = current_location->y - dr_loc.y; d_loc.z = current_location->z - dr_loc.z; d_squared = d_loc.x * d_loc.x + d_loc.y * d_loc.y + d_loc.z * d_loc.z; if (d_squared > dr->locationThreshold * dr->locationThreshold) { result |= dis_DR_LOCATION; } VEulerToMatrix( current_orientation->phi, current_orientation->theta, current_orientation->psi, &cur_orientation); d1= dr_orientation.m[0][0] * cur_orientation.m[0][0] + dr_orientation.m[0][1] * cur_orientation.m[0][1] + dr_orientation.m[0][2] * cur_orientation.m[0][2] ; d2= dr_orientation.m[1][0] * cur_orientation.m[1][0] + dr_orientation.m[1][1] * cur_orientation.m[1][1] + dr_orientation.m[1][2] * cur_orientation.m[1][2] ; d3= dr_orientation.m[2][0] * cur_orientation.m[2][0] + dr_orientation.m[2][1] * cur_orientation.m[2][1] + dr_orientation.m[2][2] * cur_orientation.m[2][2] ; d1 = 1.0 - d1 * d1; d2 = 1.0 - d2 * d2; d3 = 1.0 - d3 * d3; orientation_error_squared = d1 * d1 + d2 * d2 + d3 * d3; if (orientation_error_squared > dr-> orientationThreshold * dr-> orientationThreshold) { result |= dis_DR_ORIENTATION; } } return result; } #define DMAX 16 /* maximum number of delimiter chars */ #define BMAX 64 /* maximum incoming string length */ int dis_parseEntityID (dis_entity_id *p, char * buf, int bufsize, char *delim) { char pdelim[DMAX+1]; char tbuf[BMAX+1]; char *cur, *next, *endptr; long rval; int result = 1; memset ( p, 0, sizeof(dis_entity_id)); /* * Buffer too large? */ if (bufsize > BMAX ) { return 2; } memory_strcpy(tbuf, sizeof(tbuf), buf); if (delim) memory_strcpy(pdelim, sizeof(pdelim), delim); else memory_strcpy(pdelim, sizeof(pdelim), ":./"); cur = tbuf; next = strpbrk ( cur, pdelim ); if ( next != NULL ) { /* * Once we get a delimiter, all other delimeters must match */ pdelim[0] = *next; pdelim[1] = '\0'; /* * Get Site ID */ endptr = next; rval = strtol ( cur, &endptr, 0 ); if (rval < 0 || rval > 0xffff) { return 3; } else { p->sim_id.site_id = (unsigned short) rval; } /* * Ensure strtol stopped parsing at the correct spot */ if ( endptr != next ) { return 4; } cur = next+1; next = strpbrk ( cur, pdelim ); if ( next != NULL ) { /* * Get application ID */ endptr = next; rval = strtol ( cur, &endptr, 0 ); if (rval < 0 || rval > 0xffff) { return 3; } else { p->sim_id.application_id = (unsigned short) rval; } /* * Ensure strtol stopped parsing at the correct spot */ if ( endptr != next ) { return 4; } /* * Get Entity ID */ cur = next+1; rval = strtol ( cur, NULL, 0 ); if (rval < 0 || rval > 0xffff) { return 3; } else { p->entity_id = (unsigned short) rval; } result = 0; } } return result; } int dis_parseEntityType(char *s, dis_entity_type *et) { int f[7]; char buf[6]; if( s == NULL ) return 0; // skip leading white spaces: while(isspace(*s)) s++; int i = 0; do { // scan number: if( ! isdigit(*s) ) return 0; char *start = s; do { s++; } while(isdigit(*s)); if( s - start > 5 ) return 0; memcpy(buf, start, s - start); buf[s - start] = 0; f[i] = atoi(buf); if( !((i == 2 && f[i] <= 65535) || (i != 2 && f[i] <= 255)) ) return 0; // skip '.': i++; if( i == 7 ) break; if( *s != '.' ) return 0; s++; } while(1); // skip trailing white spaces: while(isspace(*s)) s++; // check for trailing chars: if( *s != 0 ) return 0; et->kind = f[0]; et->domain = f[1]; et->country = f[2]; et->category = f[3]; et->subcategory = f[4]; et->specific = f[5]; et->extra = f[6]; return 1; } char * dis_entityTypeToString(dis_entity_type *et) { static char s[99]; sprintf(s, "%u.%u.%u.%u.%u.%u.%u", et->kind, et->domain, et->country, et->category, et->subcategory, et->specific, et->extra); return s; } #ifdef NOT_USED_________________________________ int DISSetMulticastMode(dis_Transceiver * xcvr, unsigned long maddress, unsigned long ointerface) { int ttl = 8; unsigned long addr = ointerface; struct ip_mreq mreq; mreq.imr_multiaddr.s_addr = maddress; mreq.imr_interface.s_addr = ointerface; setsockopt(xcvr->s, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &ttl, sizeof(ttl)); setsockopt(xcvr->s, IPPROTO_IP, IP_MULTICAST_IF, (char *) &addr, sizeof(addr)); setsockopt(xcvr->s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq)); return 0; } #endif acm-6.0_20200416/src/dis/dis/xdr.h0000644000000000000000000002401213260344464014673 0ustar rootroot/* * DIS/x : An implementation of the IEEE 1278.1 protocol * * Copyright (C) 1996, Riley Rainey (rainey@netcom.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of either: * * a) the GNU Library General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your * option) any later version. A description of the terms and conditions * of the GLPL may be found in the "COPYING.LIB" file. * * b) the "Artistic License" which comes with this Kit. Information * about this license may be found in the "Artistic" file. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License or the Artistic License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Information describing how to contact the author can be found in the * README file. */ /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape * media and as a part of the software program in whole or part. Users * may copy or modify Sun RPC without charge, but are not authorized * to license or distribute it to anyone else except as part of a product or * program developed by the user. * * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. * * Sun RPC is provided with no support and without any obligation on the * part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC * OR ANY PART THEREOF. * * In no event will Sun Microsystems, Inc. be liable for any lost revenue * or profits or other special, indirect and consequential damages, even if * Sun has been advised of the possibility of such damages. * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 */ /** * XDR implementation using memory buffers. * * If you have some data to be interpreted as external data representation * or to be converted to external data representation in a memory buffer, * then this is the package for you. * * This implementation is tailored for the needs of the DIS protocol and the ACM * program, so deviates from the requirements of the standard by adding some * low-level byte-oriented routines. * * In this implementation, the normal usage cycle is as follows: * * 1. Create an encoding/decoding object by calling xdr_new(). * * 2. Encode/decode any number of fields by calling the appropriate functions. * Each encoding/decoding function returns true if the operation succeeded, * false if it fails. If a decoding operation fails, any dynamically * allocated data created by xdr_var_array() and xdr_getBytesAllocate() is * released before returning the failure status flag; any user's data decoded * so far is then destroyed. * * 3. Release the decoding object by calling xdr_free() or memory_dispose(). * Encoding/decoding objects cannot be re-used (but are recycled by * xdr_free()). * * Dynamically allocated data are allocated with the "memory" module and can * then be released with memory_dispose(). * * Specifications of the XDR encoding: RFC 1014. * * @copyright Copyright (C) 1984, Sun Microsystems, Inc. * @version $Date: 2018/04/02 05:41:30 $ */ #ifndef XDR_H #define XDR_H #include #ifdef xdr_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Xdr operations. xdr_ENCODE causes the type to be encoded into the * stream. xdr_DECODE causes the type to be extracted from the stream. * xdr_FREE can be used to release the space allocated by an xdr_DECODE * request. * * FIXME: xdr_FREE not supported -- not used by ACM. */ typedef enum { xdr_ENCODE=0, xdr_DECODE=1, xdr_FREE=2 } xdr_Operation; /** * The XDR handle. */ typedef struct xdr_Type xdr_Type; /** * Client's call-back prototype to encode/decode elements of arrays. */ typedef int (*xdr_Callback)(xdr_Type *xdr, ...); /** * Creates and initializes an encoding/decoding stream descriptor for a memory * buffer. Returns a recycled descriptor previously released with xdr_free() if * available, otherwise allocates a new one with memory_allocate(). * @param buffer Destination (for encoding) or source (for decoding) buffer. * @param size Size of the buffer. * @param op Requested operation: encoding, decoding, free. * @return New stream descriptor, possibly recycled from a previously released * stream descriptor. Can be released either with memory_dispose() or with * xdr_free() for recycling. */ EXTERN xdr_Type * xdr_new(char * buffer, unsigned int size, xdr_Operation op); /** * Releases a stream descriptor making it available for recycling. This function * is usually more efficient than memory_dispose(). * @param xdr */ EXTERN void xdr_free(xdr_Type *xdr); /** * Set error state and removes any dynamically data allocated so far. * @param xdr * @param description * @return Always returns 0. */ EXTERN int xdr_setError(xdr_Type *xdr, char *description); /** * Returns the description of the latest failed encoding/decoding operation. * @param xdr * @return Description of the latest failed encoding/decoding operation. */ EXTERN char * xdr_getErrorDescription(xdr_Type *xdr); /** * Returns the currently performed operation as set in the creator function. * @param xdr * @return Currently performed operation. */ EXTERN xdr_Operation xdr_getOperation(xdr_Type * xdr); /** * Returns current byte offset in the working buffer. * @param xdr * @return Current byte offset in the working buffer. */ EXTERN unsigned int xdr_getpos(xdr_Type *xdr); /** * Set byte offset in the working buffer. * @param xdr * @param pos Offset to set. * @return True on success. False if the offset is beyond the end of the working * buffer. */ EXTERN int xdr_setpos(xdr_Type *xdr, unsigned int pos); /** * Encodes/decodes a 32 bits signed integer. * @param xdr * @param i * @return */ EXTERN int xdr_int32(xdr_Type *xdr, int32_t *i); /** * Encodes/decodes a 32 bits unsigned integer. * @param xdr * @param ui * @return */ EXTERN int xdr_uint32(xdr_Type *xdr, uint32_t *ui); /** * Low-level, byte-oriented decoding function. It is responsibility of the client * to comply with the XDR encoding constraints to 4 bytes boundary, possibly by * reading some more padding bytes. * @param xdr * @param addr Destination buffer. * @param len Number of bytes to read. * @return True on success. False on premature end of the buffer space. */ EXTERN int xdr_getBytes(xdr_Type * xdr, void *addr, unsigned int len); /** * Low-level, byte-oriented decoding function that also allocates the required * memory space. It is responsibility of the client to comply with the XDR * encoding constraints to 4 bytes boundary, possibly by reading some more * padding bytes. * @param xdr * @param addr On success, here returns the pointer to the dynamically allocated * buffer of decoded bytes; it can be released with memory_dispose(). * @param len Number of bytes to read. * @param add_nul If true, a trailing NUL byte is added, which may be safer and * handy with strings of characters. * @return True on success. False on premature end of the buffer space. */ EXTERN int xdr_getBytesAllocated(xdr_Type * xdr, void **addr, unsigned int len, int add_nul); /** * Low-level, byte-oriented encoding function. It is responsibility of the client * to comply with the XDR decoding constraints to 4 bytes boundary, possibly by * writing some more padding bytes. * @param xdr * @param addr Source buffer. * @param len Number of bytes to write. * @return True on success. False on premature end of the buffer space. */ EXTERN int xdr_putBytes(xdr_Type * xdr, void *addr, unsigned int len); /** * Encodes/decodes a single byte. Note that it takes 4 bytes of the working * buffer. */ EXTERN int xdr_char(xdr_Type *xdr, char *c); /** * Encodes/decodes a single precision floating point number. * @param xdr * @param f * @return */ EXTERN int xdr_float(xdr_Type *xdr, float *f); /** * Encodes/decodes a double precision floating point number. * @param xdr * @param d * @return */ EXTERN int xdr_double(xdr_Type *xdr, double *d); /** * Encodes/decodes array of elements. Note that on decoding, the array must be * already allocated. * @param xdr * @param arrp Pointer to the array. * @param size Number of elements in the array. * @param elsize Size in bytes of each element. * @param elproc Element encoding/decoding procedure. * @return */ EXTERN int xdr_vector(xdr_Type *xdr, char *arrp, unsigned int size, unsigned int elsize, xdr_Callback elproc); /** * Encodes/decodes an array of elements allocating the array while decoding. * @param xdr * @param addrp Pointer to array pointer. While decoding, (size * elsize) * bytes are allocated overwriting *addrp with the new allocated array; * if the size is zero, nothing is allocated and *addrp is set to NULL. * @param size Number of elements in the array. * @param elsize Size in bytes of each element. * @param elproc Element encoding/decoding procedure. * @return True if the array has been successfully encoded/decoded. False if * the total size of the array overflows the unsigned int capacity. False if * any element fails to be encoded/decoded. False if the number of elements * exceeds the number of bytes left in the buffer. */ EXTERN int xdr_var_array(xdr_Type * xdr, void * * addrp, unsigned int size, unsigned int elsize, xdr_Callback elproc); #undef EXTERN #endif /* XDR_H */ acm-6.0_20200416/src/dis/dis/datum.c0000644000000000000000000002603713066337232015213 0ustar rootroot/* * DIS/x : An implementation of the IEEE 1278.1 protocol * * Copyright (C) 1996, Riley Rainey (rainey@netcom.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of either: * * a) the GNU Library General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your * option) any later version. A description of the terms and conditions * of the GLPL may be found in the "COPYING.LIB" file. * * b) the "Artistic License" which comes with this Kit. Information * about this license may be found in the "Artistic" file. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License or the Artistic License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Information describing how to contact the author can be found in the * README file. */ #define datum_IMPORT #include "datum.h" #undef datum_IMPORT typedef struct { datum_Type id; char *name; } datum_info; /* * This list was originally generated with * * $ perl datumtbl.pl < datum.h > datumtbl.h * * FIXME: restore automatic generation from datumtbl.h [2017-03-26 Umberto Salsi] */ static datum_info lookup[] = { { 10000, "Identification" }, { 11000, "Entity Type" }, { 11100, "Concatenated" }, { 11110, "Kind" }, { 11120, "Domain" }, { 11130, "Country" }, { 11140, "Category" }, { 11150, "Subcategory" }, { 11160, "Specific" }, { 11170, "Extra" }, { 11200, "Force ID" }, { 11300, "Description" }, { 12000, "Alternative Entity Type" }, { 12110, "Alternate Kind" }, { 12120, "Alternate Domain" }, { 12130, "Alternate Country" }, { 12140, "Alternate Category" }, { 12150, "Alternate Subcategory" }, { 12160, "Alternate Specific" }, { 12170, "Alternate Extra" }, { 12300, "Alternate Description" }, { 13000, "Entity Marking" }, { 13100, "Entity Marking Characters" }, { 13200, "Crew ID" }, { 14000, "Task Organization" }, { 14200, "Regiment Name" }, { 14300, "Battalion Name" }, { 14400, "Company Name" }, { 14500, "Platoon Name" }, { 14520, "Squad Name" }, { 14540, "Team Name" }, { 14600, "Bumper Number" }, { 14700, "Vehicle Number" }, { 14800, "Unit Number" }, { 15000, "DIS Identity" }, { 15100, "DIS Site ID" }, { 15200, "DIS Host ID" }, { 15300, "DIS Entity ID" }, { 20000, "Loads" }, { 21000, "Crew Members" }, { 21100, "Crew Member ID" }, { 21200, "Health" }, { 21300, "Job Assignment" }, { 23000, "Fuel" }, { 23100, "Quantity" }, { 23105, "Quantity Gallons" }, { 24000, "Ammunition" }, { 24001, "120mm HEAT Quantity" }, { 24002, "120mm Sabot Quantity" }, { 24003, "127mm M8Quantity" }, { 24004, "127mm M20Quantity" }, { 24005, "762mm M62Quantity" }, { 24006, "M250 U K L8 A1Quantity" }, { 24007, "M250 U K L8 A3Quantity" }, { 24008, "762mm M80Quantity" }, { 24009, "12mm Quantity" }, { 24010, "76mm Quantity" }, { 24060, "MinesQuantity" }, { 24100, "Ammunition Type" }, { 24110, "Ammunition Kind" }, { 24120, "Ammunition Domain" }, { 24130, "Ammunition Country" }, { 24140, "Ammunition Category" }, { 24150, "Ammunition Subcategory" }, { 24160, "Ammunition Extra" }, { 24300, "Ammunition Description" }, { 25000, "Cargo" }, { 26000, "Vehicle Mass" }, { 27000, "Supply Quantity" }, { 28000, "Armament" }, { 30000, "Status" }, { 31000, "Position" }, { 31100, "Mil Grid10" }, { 31200, "Geocentric Coordinates" }, { 31210, "Geocentric Coordinates X" }, { 31220, "Geocentric Coordinates Y" }, { 31230, "Geocentric Coordinates Z" }, { 31300, "Latitude" }, { 31400, "Longitude" }, { 32000, "Orientation" }, { 32100, "Hull Heading Angle" }, { 32200, "Hull Pitch Angle" }, { 32300, "Roll Angle" }, { 32500, "Orientation X" }, { 32600, "Orientation Y" }, { 32700, "Orientation Z" }, { 33000, "Appearance" }, { 33100, "Ambient Lighting" }, { 33101, "Lights" }, { 33200, "Paint Scheme" }, { 33300, "Smoke" }, { 33400, "Trailing Effects" }, { 33500, "Flaming" }, { 33600, "Marking" }, { 33710, "Mine Plows Attached" }, { 33720, "Mine Rollers Attached" }, { 33730, "Tank Turret Azimuth" }, { 34000, "Failuresand Malfunctions" }, { 34100, "Age" }, { 34110, "Kilometers" }, { 35000, "Damage" }, { 35050, "Cause" }, { 35100, "Mobility Kill" }, { 35200, "Fire_ Power Kill" }, { 35300, "Personnel Casualties" }, { 36000, "Velocity" }, { 36100, "X Velocity" }, { 36200, "Y Velocity" }, { 36300, "Z Velocity" }, { 37000, "Acceleration" }, { 37100, "X Acceleration" }, { 37200, "Y Acceleration" }, { 37300, "Z Acceleration" }, { 38100, "Engine Status" }, { 40000, "Exercise" }, { 41000, "Terrain Database" }, { 42000, "Missions" }, { 42100, "Mission ID" }, { 42200, "Mission Type" }, { 42300, "Mission Request Time Stamp" }, { 43000, "Exercise Description" }, { 43100, "Name" }, { 43200, "Entities" }, { 43300, "Version" }, { 50000, "Environment" }, { 51000, "Weather" }, { 51100, "Thermal Condition" }, { 52000, "Time" }, { 52100, "Timeof Day Discrete" }, { 52200, "Timeof Day Continuous" }, { 52300, "Time Mode" }, { 52305, "Time Scene" }, { 52310, "Current Hour" }, { 52320, "Current Minute" }, { 52330, "Current Second" }, { 52340, "Azimuth" }, { 52350, "Maximum Elevation" }, { 52360, "Time Zone" }, { 52400, "Time Sunrise Enabled" }, { 52410, "Sunrise Hour" }, { 52420, "Sunrise Minute" }, { 52430, "Sunrise Second" }, { 52440, "Sunrise Azimuth" }, { 52500, "Time Sunset Enabled" }, { 52510, "Sunset Hour" }, { 52520, "Sunset Minute" }, { 52530, "Sunset Second" }, { 52600, "Date" }, { 52610, "Month" }, { 52620, "Day" }, { 52630, "Year" }, { 53000, "Clouds" }, { 53050, "Cloud Layer Enable" }, { 53060, "Cloud Layer Selection" }, { 53100, "Cloud Visibility" }, { 53200, "Cloud Base Altitude" }, { 53250, "Cloud Base Altitude Feet" }, { 53300, "Cloud Ceiling" }, { 53350, "cloud Ceiling Feet" }, { 53400, "Characteristics" }, { 54000, "Precipitation" }, { 54100, "Rain" }, { 55000, "Fog" }, { 55100, "Visibility" }, { 55105, "Visibility Miles" }, { 55200, "Density" }, { 55300, "Base" }, { 55401, "View Layer From Above" }, { 55410, "Transition Range" }, { 55420, "Bottom" }, { 55425, "Bottom Feet" }, { 55430, "Ceiling" }, { 55435, "Ceiling Feet" }, { 56000, "Heavenly Bodies" }, { 56100, "Sun" }, { 56110, "Sun Position" }, { 56120, "Sun Position Azimuth" }, { 56130, "Sun Position Elevation" }, { 56140, "Sun Position Intensity" }, { 56200, "Moon" }, { 56210, "Moon Position" }, { 56220, "Moon Position Azimuth" }, { 56230, "Moon Position Elevation" }, { 56240, "Moon Position Intensity" }, { 56310, "Horizon" }, { 56320, "Horizon Azimuth" }, { 56330, "Horizon Elevation" }, { 56340, "Horizon Heading" }, { 56350, "Horizon Intensity" }, { 57000, "Meteorological" }, { 57100, "Meteorological Temperature" }, { 57200, "Meteorological Humidity" }, { 57300, "Meteorological Visibility" }, { 57400, "Meteorological Winds" }, { 57410, "Meteorological Speed" }, { 57500, "Meteorological Rainsoak" }, { 58000, "Haze" }, { 58100, "Haze Visibility" }, { 58105, "Haze Visibility Miles" }, { 58200, "Haze Density" }, { 58430, "Haze Ceiling" }, { 58435, "Haze Ceiling Feet" }, { 60000, "Communications" }, { 61100, "Channel Type" }, { 61101, "Channel Type1" }, { 61200, "Channel Identification" }, { 61300, "Alpha Identification" }, { 61400, "Radio Identification" }, { 61500, "Land Line Identification" }, { 61600, "Intercom Identification" }, { 61700, "Group Network Channel Number" }, { 62100, "Radio Communications Status" }, { 62200, "Stationary Radio Transmitters Default Time" }, { 62300, "Moving Radio Transmitters Default Time" }, { 62400, "Stationary Radio Signals Default Time" }, { 62500, "Moving Radio Signal Default Time" }, { 63101, "Radio Init Transec Security Key" }, { 63102, "Radio Init Internal Noise Level" }, { 63103, "Radio Init Squelch Threshold" }, { 63104, "Radio Init Antenna Location" }, { 63105, "Radio Init Antenna Pattern Type" }, { 63106, "Radio Init Antenna Pattern Length" }, { 63107, "Radio Init Beam Definition" }, { 63108, "Radio Init Transmit Heartbeat Time" }, { 63109, "Radio Init Transmit Distance Threshold" }, { 63110, "Radio Channel Init Lockout ID" }, { 63111, "Radio Channel Init Hopset ID" }, { 63112, "Radio Channel Init Preset Frequency" }, { 63113, "Radio Channel Init Frequency Sync Time" }, { 63114, "Radio Channel Init Comsec Key" }, { 63115, "Radio Channel Init Alpha" }, { 70000, "Algorithm Parameters" }, { 71000, "Dead Reckoning Algorithm" }, { 71100, "D R A Location Threshold" }, { 71200, "D R A Orientation Threshold" }, { 71300, "D R A Time Threshold" }, { 72000, "Simulation Management Parameters" }, { 72100, "Checkpoint Interval" }, { 72600, "Transmitter Time Threshold" }, { 72700, "Receiver Time Threshold" }, { 73000, "Interoperability Mode" }, { 74000, "S I M N E T Data Collection" }, { 75000, "Event ID" }, { 75100, "Source Site ID" }, { 75200, "Source Host ID" }, { 90000, "Articulated Part" }, { 90050, "Articulated Part ID" }, { 90070, "Articulated Part Index" }, { 90100, "Articulated Part Position" }, { 90200, "Articulated Part Position Rate" }, { 90300, "Articulated Part Extension" }, { 90400, "Articulated Part Extension Rate" }, { 90500, "Articulated Part X" }, { 90600, "Articulated Part X Rate" }, { 90700, "Articulated Part Y" }, { 90800, "Articulated Part Y Rate" }, { 90900, "Articulated Part Z" }, { 91000, "Articulated Part Z Rate" }, { 91100, "Articulated Part Azimuth" }, { 91200, "Articulated Part Azimuth Rate" }, { 91300, "Articulated Part Elevation" }, { 91400, "Articulated Part Elevation Rate" }, { 91500, "Articulated Part Rotation" }, { 91600, "Articulated Part Rotation Rate" }, { 100001, "D R A Angular X Velocity" }, { 100002, "D R A Angular Y Velocity" }, { 100003, "D R A Angular Z Velocity" }, { 100004, "Appearance Trailing Effects" }, { 100005, "Appearance Hatch" }, { 100008, "Appearance Character Set" }, { 100010, "Capability Ammunition Supplier" }, { 100011, "Capability Miscellaneous Supplier" }, { 100012, "Capability Repair Provider" }, { 100014, "Articulation Parameter" }, { 100047, "Articulation Parameter Type" }, { 100048, "Articulation Parameter Value" }, { 100058, "Timeof Day Scene" }, }; char * datum_lookupDatumIDName(datum_Type id) { int i; for (i = 0; lookup[i].id != 0; ++i) { if (lookup[i].id == id) { return lookup[i].name; } } return (char *) 0; } /* dis_variable_datum * DISCreateVariableDatumString(datum_Type id, char *s, int str_len) { dis_variable_datum *p; int len = ((str_len + 7) / 8) * 8; p = (dis_variable_datum *) memory_allocate(sizeof(dis_variable_datum) + len, NULL); if (!p) { return p; } p->datum_id = id; p->value_length = str_len * 8; p->value.ptr_value = (unsigned char *) (p + 1); memset(p->value.ptr_value, 0, len); memcpy(p->value.ptr_value, s, str_len); return p; } */acm-6.0_20200416/src/dis/dis/disx.h0000644000000000000000000001212013107615166015042 0ustar rootroot/* * DIS/x : An implementation of the IEEE 1278.1 protocol * * Copyright (C) 1996, Riley Rainey (rainey@netcom.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of either: * * a) the GNU Library General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your * option) any later version. A description of the terms and conditions * of the GLPL may be found in the "COPYING.LIB" file. * * b) the "Artistic License" which comes with this Kit. Information * about this license may be found in the "Artistic" file. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License or the Artistic License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Information describing how to contact the author can be found in the * README file. */ /** * Interface between the lower layer (see dis module) and upper layer (see disx * module). * * @file * @author Riley Rainey (rainey@netcom.com) * @version $Date: 2017/05/19 16:16:54 $ */ #ifndef DISX_H #define DISX_H #include "dis.h" #ifdef disx_IMPORT #define EXTERN #else #define EXTERN extern #endif typedef struct { dis_Transceiver *xcvr; dis_pdu_header hdr; dis_simulation_addr id; u_short last_event; u_long last_request; u_short last_entity; } disx_ApplicationInfo; /** * Establishes the application’s connection to the DIS Network; also set the * non-blocking mode on the transceiver socket. * @param xcvr DIS transceiver. * @param exercise_id DIS exercise number in [0,255]. * @param site_id Site number in [0,65535]. * @param application_id The DIS application id in [0,65535]. * @return Initialized application information structure, or NULL if fails to * set the non-blocking mode. */ EXTERN disx_ApplicationInfo * disx_initializeApplication( dis_Transceiver *xcvr, int exercise_id, int site_id, int application_id); /** * Closes the application context and the underlying DIS transceiver. * Does nothing if info is NULL. * @param info */ EXTERN void disx_closeApplication(disx_ApplicationInfo *info); /** * Returns the next PDU received from the DIS network. If no packet is available, * it returns immediately. * @param app The application information structure returned by * disx_initializeApplication(). * @param pdu * @return True if a DIS PDU is available. False if no more packets are * available. Invalid packets are skipped and an error message is logged. */ EXTERN int disx_readPDU(disx_ApplicationInfo *app, dis_pdu *pdu); /** * Broadcasts the specified PDU onto the DIS network. It automatically fills in * the following fields in the PDU: * - protocol_version * - exercise_id * - protocol_family * - length (always filled automatically) * @param app The pointer to the application information structure returned by * disx_initializeApplication(). * @param pdu A pointer to the protocol data unit to be transmitted. Certain * structure members are automatically inserted when disx_writePDU() is called. * Those values are updated within the referenced structure. * @return True on success. False if failed sending the packet to at least one * destination address. Failing to encode the PDU is fatal. */ EXTERN int disx_writePDU(disx_ApplicationInfo *app, dis_pdu *pdu); /** * Returns DIS simulation address in-use by this application. * @param app The application information structure returned by * disx_initializeApplication(). * @param p Simulation address. */ EXTERN void disx_getSimulationAddress(disx_ApplicationInfo * app, dis_simulation_addr * p); /** * Allocate a unique DIS event ID for use by this application. * @param app The application information structure returned by * disx_initializeApplication(). * @param event A pointer to an empty dis_event_id structure. It will be filled * in by this function. * @return Value of “event” that was passed to it. */ EXTERN dis_event_id * disx_issueEventID(disx_ApplicationInfo * app, dis_event_id * event); /** * Allocate a unique DIS entity ID for use by this application. The entity id * returned by the first call will be 0x0000. The number returned on subsequent * calls is always one greater than the previous call. * @param app The application information structure returned by * disx_initializeApplication(). * @param p A pointer to an empty dis_entity_id structure. It will be filled in * by this function. * @return Value of “p” that was passed to it. */ EXTERN dis_entity_id *disx_issueEntityID(disx_ApplicationInfo * app, dis_entity_id * p); EXTERN dis_request_id disx_issueRequestID(disx_ApplicationInfo * app); EXTERN int disx_setProtocolVersion(int version); EXTERN void disx_initializeDatumInfo(dis_datum_spec_record *pd); #undef EXTERN #endif acm-6.0_20200416/src/dis/dis/xdr.c0000644000000000000000000003050313260344464014670 0ustar rootroot/* * DIS/x : An implementation of the IEEE 1278.1 protocol * * Copyright (C) 1996, Riley Rainey (rainey@netcom.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of either: * * a) the GNU Library General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your * option) any later version. A description of the terms and conditions * of the GLPL may be found in the "COPYING.LIB" file. * * b) the "Artistic License" which comes with this Kit. Information * about this license may be found in the "Artistic" file. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License or the Artistic License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Information describing how to contact the author can be found in the * README file. */ /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape * media and as a part of the software program in whole or part. Users * may copy or modify Sun RPC without charge, but are not authorized * to license or distribute it to anyone else except as part of a product or * program developed by the user. * * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. * * Sun RPC is provided with no support and without any obligation on the * part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC * OR ANY PART THEREOF. * * In no event will Sun Microsystems, Inc. be liable for any lost revenue * or profits or other special, indirect and consequential damages, even if * Sun has been advised of the possibility of such damages. * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 */ /* * xdr_mem.h, XDR implementation using memory buffers. * * Copyright (C) 1984, Sun Microsystems, Inc. * * If you have some data to be interpreted as external data representation * or to be converted to external data representation in a memory buffer, * then this is the package for you. */ #include #ifdef WINNT #include #else #include #endif #include #include #include #include "../../util/memory.h" #define xdr_IMPORT #include "xdr.h" /** * Entry of the list of dynamically allocated blocks created while decoding. * If the decoding process fails, the allocated blocks can then be released. */ typedef struct xdr_Allocated { /** Next element in the list of allocated blocks, or next recycled element. */ struct xdr_Allocated *next; /** Allocated block. */ void *allocated; } xdr_Allocated; /** * Released elements that can be recycled. */ static xdr_Allocated *recycle_xdr_Allocated; /** * Encoder/decoder state. The currently performed operation is set in the * constructor and never changes during the lifetime of this object. * The working buffer must be provided by the user; while encoding, its size * should be large enough to contain the resulting encoded packet or a failure * is triggered. While decoding, manages a list of dynamically allocated blocks * that can be released if the operation fails; this implies that any user's * data decoded so far gets destroyed if the decoding fails. */ struct xdr_Type { xdr_Type *next_recycled; /* recycle list */ xdr_Operation op; /* operation */ char * buffer; /* working buffer */ char * next_byte; /* pointer to next byte in the buffer */ unsigned int bytes_left; /* bytes left in the buffer */ xdr_Allocated *allocated; /* list of allocated blocks while decoding */ char *error_description; /* latest error description */ }; /** * Objects that where released with xdr_free() and can be recycled. */ static xdr_Type *recycle_xdr_Type; /** * Callback for memory module that releases the content of a xdr_Type. * @param p Pointer to the xdr_Type to release. */ static void xdr_destruct(void *p) { xdr_Type *xdr = p; while( xdr->allocated != NULL ){ xdr_Allocated *e = xdr->allocated; xdr->allocated = e->next; e->next = recycle_xdr_Allocated; e->allocated = NULL; recycle_xdr_Allocated = e; } } /** * Module cleanup callback to be registered in the memory module. */ static void xdr_cleanup() { while(recycle_xdr_Type != NULL){ xdr_Type *next = recycle_xdr_Type->next_recycled; memory_dispose(recycle_xdr_Type); recycle_xdr_Type = next; } while(recycle_xdr_Allocated != NULL){ xdr_Allocated *next = recycle_xdr_Allocated->next; memory_dispose(recycle_xdr_Allocated); recycle_xdr_Allocated = next; } } xdr_Type * xdr_new(char * buffer, unsigned int size, xdr_Operation op) { xdr_Type *xdr; if( recycle_xdr_Type == NULL ){ memory_registerCleanup(xdr_cleanup); xdr = memory_allocate(sizeof(*xdr), xdr_destruct); } else { xdr = recycle_xdr_Type; recycle_xdr_Type = recycle_xdr_Type->next_recycled; } memory_zero(xdr); xdr->op = op; xdr->buffer = buffer; xdr->next_byte = buffer; xdr->bytes_left = size; xdr->allocated = NULL; xdr->error_description = NULL; return xdr; } void xdr_free(xdr_Type *xdr) { if( xdr == NULL ) return; xdr_destruct(xdr); xdr->next_recycled = recycle_xdr_Type; recycle_xdr_Type = xdr; } int xdr_setError(xdr_Type *xdr, char *description) { xdr->error_description = description; while(xdr->allocated != NULL){ xdr_Allocated *a = xdr->allocated; memory_dispose(a->allocated); a->allocated = NULL; xdr->allocated = a->next; a->next = recycle_xdr_Allocated; recycle_xdr_Allocated = a; } return 0; } char * xdr_getErrorDescription(xdr_Type *xdr) { return xdr->error_description; } /** * Registers a dynamically allocated block created while decoding, so that * these blocks can be released if the decoding operation fails. * @param xdr Decoding context. * @param allocated Pointer to the allocated block. */ static void xdr_addAllocated(xdr_Type *xdr, void *allocated) { xdr_Allocated *a; if( recycle_xdr_Allocated == NULL ){ a = memory_allocate(sizeof(*a), NULL); } else { a = recycle_xdr_Allocated; recycle_xdr_Allocated = a->next; } a->next = xdr->allocated; a->allocated = allocated; xdr->allocated = a; } xdr_Operation xdr_getOperation(xdr_Type * xdr) { return xdr->op; } unsigned int xdr_getpos(xdr_Type *xdr) { return (unsigned int) (xdr->next_byte - xdr->buffer); } int xdr_setpos(xdr_Type *xdr, unsigned int pos) { char *newaddr = xdr->buffer + pos; char *lastaddr = xdr->next_byte + xdr->bytes_left; if ((long) newaddr > (long) lastaddr || (UINT_MAX < LONG_MAX && (long) UINT_MAX < (long) lastaddr - (long) newaddr)) return xdr_setError(xdr, "xdr_setpos(): position set beyond unsigned int 32 bits limits"); xdr->next_byte = newaddr; xdr->bytes_left = (int) (lastaddr - newaddr); return 1; } static int xdr_getint32(xdr_Type * xdr, int32_t *lp) { int32_t tmp; if (xdr->bytes_left < sizeof(int32_t)) return xdr_setError(xdr, "xdr_getint32(): premature end of the buffer"); xdr->bytes_left -= sizeof(int32_t); bcopy(xdr->next_byte, (char *) &tmp, sizeof(int32_t)); *lp = (int32_t) ntohl((int32_t) tmp); xdr->next_byte += sizeof(int32_t); return 1; } static int xdr_putint32(xdr_Type * xdr, int32_t *lp) { int32_t tmp; if (xdr->bytes_left < sizeof(int32_t)) return xdr_setError(xdr, "xdr_putint32(): premature end of the buffer"); xdr->bytes_left -= sizeof(int32_t); tmp = (int32_t) htonl((uint32_t) (*lp)); bcopy((char *) &tmp, xdr->next_byte, sizeof(int32_t)); xdr->next_byte += sizeof(int32_t); return 1; } int xdr_getBytes(xdr_Type * xdr, void *addr, unsigned int len) { if (xdr->bytes_left < len) return xdr_setError(xdr, "xdr_getBytes(): premature end of the buffer"); xdr->bytes_left -= len; bcopy(xdr->next_byte, addr, len); xdr->next_byte += len; return 1; } int xdr_getBytesAllocated(xdr_Type * xdr, void **addr, unsigned int len, int add_nul) { if (xdr->bytes_left < len) return xdr_setError(xdr, "xdr_getBytesAllocated(): premature end of the buffer"); xdr->bytes_left -= len; *addr = memory_allocate(len + (add_nul? 1 : 0), NULL); xdr_addAllocated(xdr, *addr); bcopy(xdr->next_byte, *addr, len); if( add_nul ) ((char *) *addr)[len] = 0; xdr->next_byte += len; return 1; } int xdr_putBytes(xdr_Type * xdr, void *addr, unsigned int len) { if (xdr->bytes_left < len) return xdr_setError(xdr, "xdr_putBytes(): premature end of the buffer"); xdr->bytes_left -= len; bcopy(addr, xdr->next_byte, len); xdr->next_byte += len; return 1; } int xdr_var_array(xdr_Type * xdr, void * * addrp, unsigned int size, unsigned int elsize, xdr_Callback elproc) { unsigned int i; void *target; int stat; unsigned int nodesize; if ( UINT_MAX/elsize < size ) return xdr_setError(xdr, "xdr_var_array(): array size exceeds unsigned int 32 bits capacity"); nodesize = size * elsize; /* * The memory module causes a fatal error if a huge memory space is requested, * so ill formed packets coming from the network may cause a crash is we try * to blindly allocate memory. Since we expect at least one byte per element, * there can't be more elements to decode than the number of bytes left in * the buffer. */ if( size > xdr->bytes_left ) return xdr_setError(xdr, "xdr_var_array(): array size exceeds the space left in the buffer"); /* * If we are deserializing, we may need to allocate an array. * We also save time by checking for a null array if we are freeing. * * * Always allocate storage when decoding. * */ if (*addrp == NULL || xdr->op == xdr_DECODE){ switch (xdr->op) { case xdr_DECODE: if (size == 0){ *addrp = NULL; return 1; } *addrp = memory_allocate(nodesize, NULL); xdr_addAllocated(xdr, *addrp); memset(*addrp, 0, nodesize); target = *addrp; break; case xdr_FREE: return 1; case xdr_ENCODE: break; } } /* * now we xdr each element of array */ target = *addrp; stat = 1; for (i = 0; (i < size) && stat; i++) { stat = (*elproc) (xdr, target); target += elsize; } /* * the array may need freeing */ if (xdr->op == xdr_FREE) { memory_dispose(*addrp); *addrp = NULL; } return stat; } #define IS_LITTLE_ENDIAN (((char *)&(int){1})[0] == 1) int xdr_int32(xdr_Type *xdr, int32_t *i) { switch(xdr->op){ case xdr_ENCODE: return xdr_putint32(xdr, i); case xdr_DECODE: return xdr_getint32(xdr, i); case xdr_FREE: return 1; default: abort(); } } int xdr_uint32(xdr_Type *xdr, uint32_t *ui) { return xdr_int32(xdr, (int32_t *) ui); } int xdr_char(xdr_Type *xdr, char *c) { int32_t tmp; if( xdr->op == xdr_ENCODE ){ tmp = *c & 255; return xdr_int32(xdr, &tmp); } else if( xdr->op == xdr_DECODE ){ if( ! xdr_int32(xdr, &tmp) ) return xdr_setError(xdr, "xdr_char(): premature end of the buffer while reading 32 bits word"); *c = tmp & 255; return 1; } return 1; } int xdr_float(xdr_Type *xdr, float *f) { return xdr_int32(xdr, (int32_t *) f); } int xdr_double(xdr_Type *xdr, double *d) { switch(xdr->op){ case xdr_ENCODE: if( IS_LITTLE_ENDIAN ) return xdr_putint32(xdr, (int32_t *)((char *) d + 4)) && xdr_putint32(xdr, (int32_t *)((char *) d)); else return xdr_putint32(xdr, (int32_t *)((char *) d)) && xdr_putint32(xdr, (int32_t *)((char *) d + 4)); case xdr_DECODE: if( IS_LITTLE_ENDIAN ) return xdr_getint32(xdr, (int32_t *)((char *) d + 4)) && xdr_getint32(xdr, (int32_t *)((char *) d)); else return xdr_getint32(xdr, (int32_t *)((char *) d)) && xdr_getint32(xdr, (int32_t *)((char *) d + 4)); case xdr_FREE: return 1; default: abort(); } } int xdr_vector(xdr_Type *xdr, char *arrp, unsigned int size, unsigned int elsize, xdr_Callback elproc) { unsigned int i; for(i = 0; i < size; i++){ if( ! elproc(xdr, arrp + i*elsize) ) return 0; } return 1; } acm-6.0_20200416/src/dis/dis/xdr_dis.c0000644000000000000000000010331313173132341015517 0ustar rootroot/* * DIS/x : An implementation of the IEEE 1278.1 protocol * * Copyright (C) 1997, Riley Rainey (rrainey@ix.netcom.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of either: * * a) the GNU Library General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your * option) any later version. A description of the terms and conditions * of the GLPL may be found in the "COPYING.LIB" file. * * b) the "Artistic License" which comes with this Kit. Information * about this license may be found in the "Artistic" file. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License or the Artistic License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Information describing how to contact the author can be found in the * README file. */ #include #include #include "../../util/error.h" #include "datum.h" #define xdr_dis_IMPORT #include "xdr_dis.h" /* * This file was manually generated. It was NOT created by RPCGEN. * It contains xdr definitions for structures that do not fit the * conventional RPCGEN structure model for variable length vectors or * union definitions. */ /* * These xdr_byte_*() routines act just as their xdr_ equivalents except that * input data is not required to be aligned on a 4-byte boundary. This * implies that data alignment is the responsibility of the protocol * designer. */ static int xdr_byte_opaque(xdr_Type * xdrs, void * cp, u_int cnt) { /* * if no data we are done */ if (cnt == 0) return 1; if (xdr_getOperation(xdrs) == xdr_DECODE) { if (!xdr_getBytes(xdrs, cp, cnt)) { return 0; } return 1; } if (xdr_getOperation(xdrs) == xdr_ENCODE) { if (!xdr_putBytes(xdrs, cp, cnt)) { return 0; } return 1; } if (xdr_getOperation(xdrs) == xdr_FREE) { return 1; } return 0; } static int xdr_byte_uint32(xdr_Type * xdrs, uint32_t *cp) { uint32_t u; u = htonl(*cp); if (!xdr_byte_opaque(xdrs, &u, 4)) { return 0; } if (xdr_getOperation(xdrs) == xdr_DECODE ) *cp = ntohl(u); return 1; } static int xdr_byte_uint16(xdr_Type * xdrs, uint16_t *cp) { u_short u; u = htons(*cp); if (!xdr_byte_opaque(xdrs, &u, 2)) { return 0; } if (xdr_getOperation(xdrs) == xdr_DECODE ) *cp = ntohs(u); return 1; } static int xdr_byte_uchar(xdr_Type * xdrs, u_char * cp) { return xdr_byte_opaque(xdrs, cp, 1); } static int xdr_dis_variable_datum(xdr_Type * xdrs, dis_variable_datum * objp) { static char pad[8]; /* force padding to be zeroes */ int padbytes; uint32_t len; if (!xdr_uint32(xdrs, &objp->datum_id)) { return 0; } if (!xdr_uint32(xdrs, &objp->value_length)) { return 0; } switch (objp->datum_id) { /* * Double variable data items */ case datum_GeocentricCoordinatesX: case datum_GeocentricCoordinatesY: case datum_GeocentricCoordinatesZ: if (!xdr_double(xdrs, &objp->value.double_value)) { return 0; } break; /* * BEWARE. * ====== * Datum type defaults to String, which are dynamically allocated and then * must be released. Currently anything other than the types above is * assumed to be string here and in the dis_disposeVariableDatum() function, * then both MUST be kept synchronized. */ default: /* * Assumes string of chars. Note that: * - Length is given in bits (!), so the actual number of bytes is len/8. * Here we ignore any fractional byte, that is we ignore the last * 3 bits of the length. * - Strings are padded to 8 bytes fields. * - Decoding, strings are dynamically allocated and a trailing NUL byte * is added for safety. */ len = objp->value_length / 8; if( xdr_getOperation(xdrs) == xdr_ENCODE ){ if( ! xdr_putBytes(xdrs, objp->value.ptr_value, len) ) return 0; padbytes = len % 8; if (padbytes != 0) { memset(pad, 0, 8 - padbytes); if( ! xdr_putBytes(xdrs, pad, 8 - padbytes) ) return 0; } } else if( xdr_getOperation(xdrs) == xdr_DECODE ){ if( ! xdr_getBytesAllocated(xdrs, (void **) &objp->value.ptr_value, len, 1) ) return 0; padbytes = len % 8; if (padbytes != 0) { if( ! xdr_getBytes(xdrs, pad, 8 - padbytes) ) return 0; } } break; } return 1; } static int xdr_dis_articulation_parm(xdr_Type * xdrs, dis_articulation_parm * objp) { if (!xdr_byte_uchar(xdrs, &objp->type)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->change)) { return 0; } if (!xdr_byte_uint16(xdrs, &objp->attachment_id)) { return 0; } if (!xdr_byte_uint32(xdrs, &objp->attached_part)) { return 0; } if (!xdr_byte_uint32(xdrs, &objp->articulated_part)) { return 0; } // FIXME: missing support for articulation parameter value. // Here we should add a specific encoding for each type of parameter. // Assume double just to pass incoming packets, but ignored by ACM anyway. if (!xdr_double(xdrs, &objp->value.d)) { return 0; } return 1; } static int xdr_dis_timestamp(xdr_Type * xdrs, dis_timestamp * objp) { if (!xdr_uint32(xdrs, (u_int *) objp)) { return 0; } return 1; } /* static int xdr_dis_float_vector(XDR *xdrs, dis_float_vector *objp) { if (!xdr_float(xdrs, &objp->x)) { return 0; } if (!xdr_float(xdrs, &objp->y)) { return 0; } if (!xdr_float(xdrs, &objp->z)) { return 0; } return 1; } */ static int xdr_dis_angular_vel_vector(xdrs, objp) xdr_Type *xdrs; dis_angular_vel_vector *objp; { if (!xdr_float(xdrs, &objp->x)) { return 0; } if (!xdr_float(xdrs, &objp->y)) { return 0; } if (!xdr_float(xdrs, &objp->z)) { return 0; } return 1; } static int xdr_dis_linear_acc_vector(xdrs, objp) xdr_Type *xdrs; dis_linear_acc_vector *objp; { if (!xdr_float(xdrs, &objp->x)) { return 0; } if (!xdr_float(xdrs, &objp->y)) { return 0; } if (!xdr_float(xdrs, &objp->z)) { return 0; } return 1; } static int xdr_dis_linear_vel_vector(xdrs, objp) xdr_Type *xdrs; dis_linear_vel_vector *objp; { if (!xdr_float(xdrs, &objp->x)) { return 0; } if (!xdr_float(xdrs, &objp->y)) { return 0; } if (!xdr_float(xdrs, &objp->z)) { return 0; } return 1; } static int xdr_dis_entity_coord_vector(xdrs, objp) xdr_Type *xdrs; dis_entity_coord_vector *objp; { if (!xdr_float(xdrs, &objp->x)) { return 0; } if (!xdr_float(xdrs, &objp->y)) { return 0; } if (!xdr_float(xdrs, &objp->z)) { return 0; } return 1; } static int xdr_dis_entity_type(xdrs, objp) xdr_Type *xdrs; dis_entity_type *objp; { if (!xdr_byte_uchar(xdrs, &objp->kind)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->domain)) { return 0; } if (!xdr_byte_uint16(xdrs, &objp->country)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->category)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->subcategory)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->specific)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->extra)) { return 0; } return 1; } static int xdr_dis_entity_marking(xdrs, objp) xdr_Type *xdrs; dis_entity_marking *objp; { if (!xdr_byte_uchar(xdrs, &objp->charset)) { return 0; } if (!xdr_vector(xdrs, (char *)objp->marking, sizeof(objp->marking), sizeof(u_char), (xdr_Callback) xdr_byte_uchar)) { return 0; } return 1; } static int xdr_dis_fixed_datum(xdrs, objp) xdr_Type *xdrs; dis_fixed_datum *objp; { if (!xdr_uint32(xdrs, &objp->datum_id)) { return 0; } if (!xdr_uint32(xdrs, &objp->value)) { return 0; } return 1; } static int xdr_dis_simulation_addr(xdrs, objp) xdr_Type *xdrs; dis_simulation_addr *objp; { if (!xdr_byte_uint16(xdrs, &objp->site_id)) { return 0; } if (!xdr_byte_uint16(xdrs, &objp->application_id)) { return 0; } return 1; } static int xdr_dis_emitter_system(xdrs, objp) xdr_Type *xdrs; dis_emitter_system *objp; { if (!xdr_byte_uint16(xdrs, &objp->name)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->function)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->id)) { return 0; } return 1; } static int xdr_dis_entity_id(xdrs, objp) xdr_Type *xdrs; dis_entity_id *objp; { if (!xdr_dis_simulation_addr(xdrs, &objp->sim_id)) { return 0; } if (!xdr_byte_uint16(xdrs, &objp->entity_id)) { return 0; } return 1; } static int xdr_dis_euler_angles(xdrs, objp) xdr_Type *xdrs; dis_euler_angles *objp; { if (!xdr_float(xdrs, &objp->psi)) { return 0; } if (!xdr_float(xdrs, &objp->theta)) { return 0; } if (!xdr_float(xdrs, &objp->phi)) { return 0; } return 1; } static int xdr_dis_event_id(xdrs, objp) xdr_Type *xdrs; dis_event_id *objp; { if (!xdr_dis_simulation_addr(xdrs, &objp->sim_id)) { return 0; } if (!xdr_byte_uint16(xdrs, &objp->event_id)) { return 0; } return 1; } static int xdr_dis_fundamental_parameters(xdrs, objp) xdr_Type *xdrs; dis_fundamental_parameters *objp; { if (!xdr_float(xdrs, &objp->freq)) { return 0; } if (!xdr_float(xdrs, &objp->freq_range)) { return 0; } if (!xdr_float(xdrs, &objp->erp)) { return 0; } if (!xdr_float(xdrs, &objp->prf)) { return 0; } if (!xdr_float(xdrs, &objp->pulse_width)) { return 0; } if (!xdr_float(xdrs, &objp->beam_azimuth_center)) { return 0; } if (!xdr_float(xdrs, &objp->beam_azimuth_sweep)) { return 0; } if (!xdr_float(xdrs, &objp->beam_elev_center)) { return 0; } if (!xdr_float(xdrs, &objp->beam_elev_sweep)) { return 0; } if (!xdr_float(xdrs, &objp->beam_sweep_sync)) { return 0; } return 1; } /* static int xdr_dis_modulation_type(xdrs, objp) XDR *xdrs; dis_modulation_type *objp; { if (!xdr_byte_u_short(xdrs, &objp->spread_spectrum)) { return 0; } if (!xdr_byte_u_short(xdrs, &objp->major_type)) { return 0; } if (!xdr_byte_u_short(xdrs, &objp->detail)) { return 0; } if (!xdr_byte_u_short(xdrs, &objp->system)) { return 0; } return 1; } */ static int xdr_dis_pdu_header(xdrs, objp) xdr_Type *xdrs; dis_pdu_header *objp; { if (!xdr_byte_uchar(xdrs, &objp->protocol_version)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->exercise_id)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->pdu_type)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->protocol_family)) { return 0; } if (!xdr_dis_timestamp(xdrs, &objp->time_stamp)) { return 0; } if (!xdr_byte_uint16(xdrs, &objp->length)) { return 0; } if (!xdr_byte_uint16(xdrs, &objp->padding)) { return 0; } return 1; } /* static int xdr_dis_double_vector(xdrs, objp) XDR *xdrs; dis_double_vector *objp; { if (!xdr_byte_double(xdrs, &objp->x)) { return 0; } if (!xdr_byte_double(xdrs, &objp->y)) { return 0; } if (!xdr_byte_double(xdrs, &objp->z)) { return 0; } return 1; } */ static int xdr_earth_XYZ(xdrs, objp) xdr_Type *xdrs; VPoint *objp; { if (!xdr_double(xdrs, &objp->x)) { return 0; } if (!xdr_double(xdrs, &objp->y)) { return 0; } if (!xdr_double(xdrs, &objp->z)) { return 0; } return 1; } /* static int xdr_dis_relative_coordinates(xdrs, objp) XDR *xdrs; dis_relative_coordinates *objp; { if (!xdr_float(xdrs, &objp->x)) { return 0; } if (!xdr_float(xdrs, &objp->y)) { return 0; } if (!xdr_float(xdrs, &objp->z)) { return 0; } return 1; } */ /* static int xdr_dis_antenna_location(xdrs, objp) XDR *xdrs; dis_antenna_location *objp; { if (!xdr_earth_XYZ(xdrs, &objp->ant_location)) { return 0; } if (!xdr_dis_relative_coordinates(xdrs, &objp->relative)) { return 0; } return 1; } */ /* static int xdr_dis_beam_antenna_pattern(xdrs, objp) XDR *xdrs; dis_beam_antenna_pattern *objp; { if (!xdr_dis_euler_angles(xdrs, &objp->direction)) { return 0; } if (!xdr_float(xdrs, &objp->azimuth_width)) { return 0; } if (!xdr_float(xdrs, &objp->elev_width)) { return 0; } if (!xdr_byte_u_char(xdrs, &objp->reference_system)) { return 0; } if (!xdr_vector(xdrs, (char *)objp->pad, 3, sizeof(byte_u_char), (xdrproc_t) xdr_byte_u_char)) { return 0; } if (!xdr_float(xdrs, &objp->Ez)) { return 0; } if (!xdr_float(xdrs, &objp->Ex)) { return 0; } if (!xdr_float(xdrs, &objp->phase)) { return 0; } return 1; } */ /* static int xdr_dis_spherical_harmonic_antenna_pattern(xdrs, objp) XDR *xdrs; dis_spherical_harmonic_antenna_pattern *objp; { if (!xdr_byte_u_char(xdrs, &objp->pattern)) { return 0; } if (!xdr_float(xdrs, &objp->coefficients)) { return 0; } if (!xdr_byte_u_char(xdrs, &objp->ref_system)) { return 0; } return 1; } */ static int xdr_dis_time(xdrs, objp) xdr_Type *xdrs; dis_time *objp; { if (!xdr_uint32(xdrs, &objp->hour)) { return 0; } if (!xdr_dis_timestamp(xdrs, &objp->rel)) { return 0; } return 1; } static int xdr_dis_burst_descriptor(xdrs, objp) xdr_Type *xdrs; dis_burst_descriptor *objp; { if (!xdr_dis_entity_type(xdrs, &objp->munition)) { return 0; } if (!xdr_byte_uint16(xdrs, &objp->warhead)) { return 0; } if (!xdr_byte_uint16(xdrs, &objp->fuze)) { return 0; } if (!xdr_byte_uint16(xdrs, &objp->quantity)) { return 0; } if (!xdr_byte_uint16(xdrs, &objp->rate)) { return 0; } return 1; } static int xdr_dis_dead_reckoning(xdrs, objp) xdr_Type *xdrs; dis_dead_reckoning *objp; { if (!xdr_byte_uchar(xdrs, &objp->algorithm)) { return 0; } if (!xdr_vector(xdrs, (char *)objp->other, sizeof(objp->other), sizeof(u_char), (xdr_Callback) xdr_byte_uchar)) { return 0; } if (!xdr_dis_linear_acc_vector(xdrs, &objp->linear_acc)) { return 0; } if (!xdr_dis_angular_vel_vector(xdrs, &objp->angular_vel)) { return 0; } return 1; } static int xdr_dis_capabilities(xdrs, objp) xdr_Type *xdrs; dis_capabilities *objp; { if (!xdr_uint32(xdrs, objp)) { return 0; } return 1; } /* static int xdr_dis_supply_quantity(xdrs, objp) XDR *xdrs; dis_supply_quantity *objp; { if (!xdr_dis_entity_type(xdrs, &objp->entity)) { return 0; } if (!xdr_float(xdrs, &objp->quantity)) { return 0; } return 1; } */ static int xdr_dis_entity_appearance(xdrs, objp) xdr_Type *xdrs; dis_entity_appearance *objp; { if (!xdr_uint32(xdrs, objp)) { return 0; } return 1; } static int xdr_dis_entity_state_pdu(xdrs, objp) xdr_Type *xdrs; dis_entity_state_pdu *objp; { if (!xdr_dis_pdu_header(xdrs, &objp->hdr)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->id)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->force_id)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->art_parm_count)) { return 0; } if (!xdr_dis_entity_type(xdrs, &objp->type)) { return 0; } if (!xdr_dis_entity_type(xdrs, &objp->alt_type)) { return 0; } if (!xdr_dis_linear_vel_vector(xdrs, &objp->vel)) { return 0; } if (!xdr_earth_XYZ(xdrs, &objp->pos)) { return 0; } if (!xdr_dis_euler_angles(xdrs, &objp->orientation)) { return 0; } if (!xdr_dis_entity_appearance(xdrs, &objp->appearance)) { return 0; } if (!xdr_dis_dead_reckoning(xdrs, &objp->dr_parm)) { return 0; } if (!xdr_dis_entity_marking(xdrs, &objp->marking)) { return 0; } if (!xdr_dis_capabilities(xdrs, &objp->capabilities)) { return 0; } if (!xdr_var_array(xdrs, (void **)&objp->art_parm, objp->art_parm_count, sizeof(dis_articulation_parm), (xdr_Callback) xdr_dis_articulation_parm)) { return 0; } return 1; } static int xdr_dis_collision_pdu(xdrs, objp) xdr_Type *xdrs; dis_collision_pdu *objp; { if (!xdr_dis_pdu_header(xdrs, &objp->hdr)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->id)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->collision_id)) { return 0; } if (!xdr_dis_event_id(xdrs, &objp->event)) { return 0; } if (!xdr_dis_linear_vel_vector(xdrs, &objp->vel)) { return 0; } if (!xdr_uint32(xdrs, &objp->mass)) { return 0; } if (!xdr_dis_entity_coord_vector(xdrs, &objp->loc)) { return 0; } return 1; } static int xdr_dis_fire_pdu(xdrs, objp) xdr_Type *xdrs; dis_fire_pdu *objp; { if (!xdr_dis_pdu_header(xdrs, &objp->hdr)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->firing_id)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->target_id)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->munition_id)) { return 0; } if (!xdr_dis_event_id(xdrs, &objp->event)) { return 0; } if (!xdr_uint32(xdrs, &objp->fire_mission_index)) { return 0; } if (!xdr_earth_XYZ(xdrs, &objp->pos)) { return 0; } if (!xdr_dis_burst_descriptor(xdrs, &objp->burst)) { return 0; } if (!xdr_dis_linear_vel_vector(xdrs, &objp->vel)) { return 0; } if (!xdr_float(xdrs, &objp->range)) { return 0; } return 1; } static int xdr_dis_detonation_pdu(xdrs, objp) xdr_Type *xdrs; dis_detonation_pdu *objp; { if (!xdr_dis_pdu_header(xdrs, &objp->hdr)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->firing_id)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->target_id)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->munition_id)) { return 0; } if (!xdr_dis_event_id(xdrs, &objp->event)) { return 0; } if (!xdr_dis_linear_vel_vector(xdrs, &objp->vel)) { return 0; } if (!xdr_earth_XYZ(xdrs, &objp->pos)) { return 0; } if (!xdr_dis_burst_descriptor(xdrs, &objp->burst)) { return 0; } if (!xdr_dis_entity_coord_vector(xdrs, &objp->loc)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->result)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->num_art_parms)) { return 0; } if (!xdr_byte_uint16(xdrs, &objp->pad)) { return 0; } if (!xdr_var_array(xdrs, (void **)&objp->art_parm, objp->num_art_parms, sizeof(dis_articulation_parm), (xdr_Callback) xdr_dis_articulation_parm)) { return 0; } return 1; } /* static int xdr_dis_service_type(xdrs, objp) XDR *xdrs; dis_service_type *objp; { if (!xdr_byte_u_char(xdrs, objp)) { return 0; } return 1; } */ /* static int xdr_dis_repair_type(xdrs, objp) XDR *xdrs; dis_repair_type *objp; { if (!xdr_byte_u_short(xdrs, objp)) { return 0; } return 1; } */ /* static int xdr_dis_repair_result(xdrs, objp) XDR *xdrs; dis_repair_result *objp; { if (!xdr_byte_u_char(xdrs, objp)) { return 0; } return 1; } */ /* static int xdr_dis_service_request_pdu(xdrs, objp) XDR *xdrs; dis_service_request_pdu *objp; { if (!xdr_dis_pdu_header(xdrs, &objp->hdr)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->requestor_id)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->server_id)) { return 0; } if (!xdr_dis_service_type(xdrs, &objp->requested_service)) { return 0; } if (!xdr_byte_u_char(xdrs, &objp->num_supply_types)) { return 0; } if (!xdr_byte_u_short(xdrs, &objp->pad)) { return 0; } if (!xdr_var_array(xdrs, (char **)&objp->supplies, objp->num_supply_types, objp->num_supply_types, sizeof(dis_supply_quantity), (xdrproc_t) xdr_dis_supply_quantity)) { return 0; } return 1; } */ /* static int xdr_dis_resupply_offer_pdu(xdrs, objp) XDR *xdrs; dis_resupply_offer_pdu *objp; { if (!xdr_dis_pdu_header(xdrs, &objp->hdr)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->receiver_id)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->supplier_id)) { return 0; } if (!xdr_byte_u_char(xdrs, &objp->num_supply_types)) { return 0; } if (!xdr_vector(xdrs, (char *)objp->pad, 3, sizeof(byte_u_char), (xdrproc_t) xdr_byte_u_char)) { return 0; } if (!xdr_var_array(xdrs, (char **)&objp->supplies, objp->num_supply_types, objp->num_supply_types, sizeof(dis_supply_quantity), (xdrproc_t) xdr_dis_supply_quantity)) { return 0; } return 1; } */ /* static int xdr_dis_resupply_received_pdu(xdrs, objp) XDR *xdrs; dis_resupply_received_pdu *objp; { if (!xdr_dis_pdu_header(xdrs, &objp->hdr)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->receiver_id)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->supplier_id)) { return 0; } if (!xdr_byte_u_char(xdrs, &objp->num_supply_types)) { return 0; } if (!xdr_vector(xdrs, (char *)objp->pad, 3, sizeof(byte_u_char), (xdrproc_t) xdr_byte_u_char)) { return 0; } if (!xdr_var_array(xdrs, (char **)&objp->supplies, objp->num_supply_types, objp->num_supply_types, sizeof(dis_supply_quantity), (xdrproc_t) xdr_dis_supply_quantity)) { return 0; } return 1; } */ /* static int xdr_dis_resupply_cancel_pdu(xdrs, objp) XDR *xdrs; dis_resupply_cancel_pdu *objp; { if (!xdr_dis_pdu_header(xdrs, &objp->hdr)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->receiver_id)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->supplier_id)) { return 0; } return 1; } */ /* static int xdr_dis_repair_complete_pdu(xdrs, objp) XDR *xdrs; dis_repair_complete_pdu *objp; { if (!xdr_dis_pdu_header(xdrs, &objp->hdr)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->receiver_id)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->supplier_id)) { return 0; } if (!xdr_dis_repair_type(xdrs, &objp->repair)) { return 0; } if (!xdr_byte_u_short(xdrs, &objp->pad)) { return 0; } return 1; } */ /* static int xdr_dis_repair_response_pdu(xdrs, objp) XDR *xdrs; dis_repair_response_pdu *objp; { if (!xdr_dis_pdu_header(xdrs, &objp->hdr)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->receiver_id)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->supplier_id)) { return 0; } if (!xdr_dis_repair_result(xdrs, &objp->result)) { return 0; } if (!xdr_vector(xdrs, (char *)objp->pad, 3, sizeof(byte_u_char), (xdrproc_t) xdr_byte_u_char)) { return 0; } return 1; } */ static int xdr_dis_request_id(xdrs, objp) xdr_Type *xdrs; dis_request_id *objp; { if (!xdr_uint32(xdrs, objp)) { return 0; } return 1; } static int xdr_dis_create_entity_pdu(xdrs, objp) xdr_Type *xdrs; dis_create_entity_pdu *objp; { if (!xdr_dis_pdu_header(xdrs, &objp->hdr)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->orig_id)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->recv_id)) { return 0; } if (!xdr_dis_request_id(xdrs, &objp->request_id)) { return 0; } return 1; } static int xdr_dis_remove_entity_pdu(xdrs, objp) xdr_Type *xdrs; dis_remove_entity_pdu *objp; { if (!xdr_dis_pdu_header(xdrs, &objp->hdr)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->orig_id)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->recv_id)) { return 0; } if (!xdr_dis_request_id(xdrs, &objp->request_id)) { return 0; } return 1; } static int xdr_dis_start_pdu(xdrs, objp) xdr_Type *xdrs; dis_start_pdu *objp; { if (!xdr_dis_pdu_header(xdrs, &objp->hdr)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->orig_id)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->recv_id)) { return 0; } if (!xdr_dis_time(xdrs, &objp->real_time)) { return 0; } if (!xdr_dis_time(xdrs, &objp->sim_time)) { return 0; } if (!xdr_dis_request_id(xdrs, &objp->request_id)) { return 0; } return 1; } static int xdr_dis_stop_pdu(xdrs, objp) xdr_Type *xdrs; dis_stop_pdu *objp; { if (!xdr_dis_pdu_header(xdrs, &objp->hdr)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->orig_id)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->recv_id)) { return 0; } if (!xdr_dis_time(xdrs, &objp->real_time)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->reason)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->behavior)) { return 0; } if (!xdr_vector(xdrs, (char *)objp->pad, 2, sizeof(u_char), (xdr_Callback) xdr_byte_uchar)) { return 0; } if (!xdr_dis_request_id(xdrs, &objp->request_id)) { return 0; } return 1; } static int xdr_dis_acknowledge_pdu(xdrs, objp) xdr_Type *xdrs; dis_acknowledge_pdu *objp; { if (!xdr_dis_pdu_header(xdrs, &objp->hdr)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->orig_id)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->recv_id)) { return 0; } if (!xdr_byte_uint16(xdrs, &objp->acknowledge_flag)) { return 0; } if (!xdr_byte_uint16(xdrs, &objp->resp_flag)) { return 0; } if (!xdr_dis_request_id(xdrs, &objp->request_id)) { return 0; } return 1; } /* static int xdr_dis_data_query_pdu(xdrs, objp) XDR *xdrs; dis_data_query_pdu *objp; { if (!xdr_dis_pdu_header(xdrs, &objp->hdr)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->orig_id)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->recv_id)) { return 0; } if (!xdr_dis_time(xdrs, &objp->interval)) { return 0; } if (!xdr_dis_request_id(xdrs, &objp->request_id)) { return 0; } if (!xdr_byte_u_long(xdrs, &objp->num_fixed_data)) { return 0; } if (!xdr_byte_u_long(xdrs, &objp->num_variable_data)) { return 0; } if (!xdr_var_array(xdrs, (char **)&objp->fixed_datum_id, objp->num_fixed_data, objp->num_fixed_data, sizeof(byte_u_long), (xdrproc_t) xdr_byte_u_long)) { return 0; } if (!xdr_var_array(xdrs, (char **)&objp->variable_datum_id, objp->num_variable_data, objp->num_variable_data, sizeof(byte_u_long), (xdrproc_t) xdr_byte_u_long)) { return 0; } return 1; } */ static int xdr_dis_datum_spec_record(xdrs, objp) xdr_Type *xdrs; dis_datum_spec_record *objp; { if (!xdr_uint32(xdrs, &objp->num_fixed_data)) { return 0; } if (!xdr_uint32(xdrs, &objp->num_variable_data)) { return 0; } if (!xdr_var_array(xdrs, (void **)&objp->fixed_datum, objp->num_fixed_data, sizeof(dis_fixed_datum), (xdr_Callback) xdr_dis_fixed_datum)) { return 0; } if (!xdr_var_array(xdrs, (void **)&objp->variable_datum, objp->num_variable_data, sizeof(dis_variable_datum), (xdr_Callback) xdr_dis_variable_datum)) { return 0; } return 1; } static int xdr_dis_set_data_pdu(xdrs, objp) xdr_Type *xdrs; dis_set_data_pdu *objp; { if (!xdr_dis_pdu_header(xdrs, &objp->hdr)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->orig_id)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->recv_id)) { return 0; } if (!xdr_dis_request_id(xdrs, &objp->request_id)) { return 0; } if (!xdr_dis_datum_spec_record(xdrs, &objp->datum_info)) { return 0; } return 1; } /* static int xdr_dis_data_pdu(xdrs, objp) XDR *xdrs; dis_data_pdu *objp; { if (!xdr_dis_pdu_header(xdrs, &objp->hdr)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->orig_id)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->recv_id)) { return 0; } if (!xdr_dis_request_id(xdrs, &objp->request_id)) { return 0; } if (!xdr_dis_datum_spec_record(xdrs, &objp->datum_info)) { return 0; } return 1; } */ /* static int xdr_dis_event_report_pdu(xdrs, objp) XDR *xdrs; dis_event_report_pdu *objp; { if (!xdr_dis_pdu_header(xdrs, &objp->hdr)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->orig_id)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->recv_id)) { return 0; } if (!xdr_dis_event_id(xdrs, &objp->event_type)) { return 0; } if (!xdr_dis_datum_spec_record(xdrs, &objp->datum_info)) { return 0; } return 1; } */ static int xdr_dis_comment_pdu(xdr_Type *xdrs, dis_comment_pdu *objp) { if (!xdr_dis_pdu_header(xdrs, &objp->hdr)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->orig_id)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->recv_id)) { return 0; } if (!xdr_uint32(xdrs, &objp->num_fixed_data)) { return 0; } if (!xdr_uint32(xdrs, &objp->num_variable_data)) { return 0; } if (!xdr_var_array(xdrs, (void **)&objp->fixed_datum, objp->num_fixed_data, sizeof(dis_fixed_datum), (xdr_Callback) xdr_dis_fixed_datum)) { return 0; } if (!xdr_var_array(xdrs, (void **)&objp->variable_datum, objp->num_variable_data, sizeof(dis_variable_datum), (xdr_Callback) xdr_dis_variable_datum)) { return 0; } return 1; } static int xdr_dis_track_info(xdrs, objp) xdr_Type *xdrs; dis_track_info *objp; { if (!xdr_dis_entity_id(xdrs, &objp->target)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->emitter_id)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->beam_id)) { return 0; } return 1; } static int xdr_dis_beam_info(xdrs, objp) xdr_Type *xdrs; dis_beam_info *objp; { if (!xdr_byte_uchar(xdrs, &objp->beam_data_length)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->beam_id)) { return 0; } if (!xdr_byte_uint16(xdrs, &objp->beam_parm_index)) { return 0; } if (!xdr_dis_fundamental_parameters(xdrs, &objp->fundamental)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->beam_function)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->num_targets)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->high_density_track_jam)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->pad)) { return 0; } if (!xdr_uint32(xdrs, &objp->jamming_mode)) { return 0; } if (!xdr_var_array(xdrs, (void **)&objp->tracked_target, objp->num_targets, sizeof(dis_track_info), (xdr_Callback) xdr_dis_track_info)) { return 0; } return 1; } static int xdr_dis_em_system_info(xdrs, objp) xdr_Type *xdrs; dis_em_system_info *objp; { if (!xdr_byte_uchar(xdrs, &objp->sys_data_length)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->num_beams)) { return 0; } if (!xdr_byte_uint16(xdrs, &objp->pad)) { return 0; } if (!xdr_dis_emitter_system(xdrs, &objp->emitter_system)) { return 0; } if (!xdr_dis_entity_coord_vector(xdrs, &objp->location)) { return 0; } if (!xdr_var_array(xdrs, (void **)&objp->beam, objp->num_beams, sizeof(dis_beam_info), (xdr_Callback) xdr_dis_beam_info)) { return 0; } return 1; } static int xdr_dis_em_emission_pdu(xdrs, objp) xdr_Type *xdrs; dis_em_emission_pdu *objp; { if (!xdr_dis_pdu_header(xdrs, &objp->hdr)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->emitter_id)) { return 0; } if (!xdr_dis_event_id(xdrs, &objp->event)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->state_update)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->num_systems)) { return 0; } if (!xdr_byte_uint16(xdrs, &objp->pad)) { return 0; } if (!xdr_var_array(xdrs, (void **)&objp->system, objp->num_systems, sizeof(dis_em_system_info), (xdr_Callback) xdr_dis_em_system_info)) { return 0; } return 1; } /* static int xdr_dis_designator_pdu(xdrs, objp) XDR *xdrs; dis_designator_pdu *objp; { if (!xdr_dis_pdu_header(xdrs, &objp->hdr)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->designating_id)) { return 0; } if (!xdr_byte_u_short(xdrs, &objp->code_name)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->designated_id)) { return 0; } if (!xdr_byte_u_char(xdrs, &objp->pad)) { return 0; } if (!xdr_byte_u_char(xdrs, &objp->code)) { return 0; } if (!xdr_float(xdrs, &objp->power)) { return 0; } if (!xdr_float(xdrs, &objp->wavelength)) { return 0; } if (!xdr_dis_entity_coord_vector(xdrs, &objp->spot_rel)) { return 0; } if (!xdr_earth_XYZ(xdrs, &objp->spot_pos)) { return 0; } return 1; } */ /* static int xdr_dis_experimental_request_control_pdu(xdrs, objp) XDR *xdrs; dis_experimental_request_control_pdu *objp; { if (!xdr_dis_pdu_header(xdrs, &objp->hdr)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->requesting_id)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->control_target_id)) { return 0; } return 1; } */ /* static int xdr_dis_experimental_grant_control_pdu(xdrs, objp) XDR *xdrs; dis_experimental_grant_control_pdu *objp; { if (!xdr_dis_pdu_header(xdrs, &objp->hdr)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->granting_id)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->control_target_id)) { return 0; } return 1; } */ static int xdr_dis_transfer_control_pdu(xdrs, objp) xdr_Type *xdrs; dis_transfer_control_pdu *objp; { if (!xdr_dis_pdu_header(xdrs, &objp->hdr)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->orig_id)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->recv_id)) { return 0; } if (!xdr_uint32(xdrs, &objp->request_id)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->reliability_service)) { return 0; } if (!xdr_byte_uchar(xdrs, &objp->transfer_type)) { return 0; } if (!xdr_dis_entity_id(xdrs, &objp->target_id)) { return 0; } if (!xdr_uint32(xdrs, &objp->num_record_sets)) { return 0; } return 1; } int xdr_dis_pdu(xdr_Type * xdrs, dis_pdu * objp) { uint32_t pos; /* * On decoding, retrieve the header first just to get the PDU type and * then apply the specific decoding function next. Each specific function * will then decode the header back again, which is a bit redundant, but * necessary because each specific function must serve also for encoding. */ if (xdr_getOperation(xdrs) == xdr_DECODE) { pos = xdr_getpos(xdrs); if (!xdr_dis_pdu_header(xdrs, (dis_pdu_header *) objp)) { return 0; } if (!xdr_setpos(xdrs, pos)) { return 0; } } switch (objp->hdr.pdu_type) { case PDUTypeOther: if (!xdr_dis_pdu_header(xdrs, &objp->hdr)) { return 0; } break; case PDUTypeEntityState: if (!xdr_dis_entity_state_pdu(xdrs, (dis_entity_state_pdu *) objp)) { return 0; } break; case PDUTypeCollision: if (!xdr_dis_collision_pdu(xdrs, (dis_collision_pdu *) objp)) { return 0; } break; case PDUTypeFire: if (!xdr_dis_fire_pdu(xdrs, (dis_fire_pdu *) objp)) { return 0; } break; case PDUTypeDetonation: if (!xdr_dis_detonation_pdu(xdrs, (dis_detonation_pdu *) objp)) { return 0; } break; case PDUTypeCreateEntity: if (!xdr_dis_create_entity_pdu(xdrs, (dis_create_entity_pdu *) objp)) { return 0; } break; case PDUTypeRemoveEntity: if (!xdr_dis_remove_entity_pdu(xdrs, (dis_remove_entity_pdu *) objp)) { return 0; } break; case PDUTypeStopFreeze: if (!xdr_dis_stop_pdu(xdrs, (dis_stop_pdu *) objp)) { return 0; } break; case PDUTypeStartResume: if (!xdr_dis_start_pdu(xdrs, (dis_start_pdu *) objp)) { return 0; } break; case PDUTypeSetData: if (!xdr_dis_set_data_pdu(xdrs, (dis_start_pdu *) objp)) { return 0; } break; case PDUTypeComment: if (!xdr_dis_comment_pdu(xdrs, (dis_comment_pdu *) objp)) { return 0; } break; case PDUTypeEmission: if (!xdr_dis_em_emission_pdu(xdrs, (dis_em_emission_pdu *) objp)) { return 0; } break; case PDUTypeTransferControl: if (!xdr_dis_transfer_control_pdu(xdrs, (dis_transfer_control_pdu *) objp)) { return 0; } break; case PDUTypeAcknowledge: if (!xdr_dis_acknowledge_pdu(xdrs, (dis_acknowledge_pdu *) objp)) { return 0; } break; default: return xdr_setError(xdrs, "unknown/unsupported DIS PDU type"); } return 1; } acm-6.0_20200416/src/dis/dis/Makefile0000644000000000000000000000205613172244762015373 0ustar rootroot# This file generated by make-makefile, do not edit! # Create Makefile-include.txt instead for your customizations. CC := gcc CFLAGS := -Wall -Werror -g -fmax-errors=99 -Wuninitialized -Wmissing-prototypes -Wredundant-decls LIBS := .PHONY: all all: make datum.o dis.o disx.o earth.o xdr.o xdr_dis.o include Makefile-include.txt .PHONY: clean clean: rm -f *.o *.exe *.stackdump datum.o: datum.c datum.h $(CC) $(CFLAGS) -c datum.c -o datum.o dis.o: dis.c dis.h ../../V/Vlibmath.h ../../util/error.h ../../util/memory.h datum.h earth.h xdr.h xdr_dis.h $(CC) $(CFLAGS) -c dis.c -o dis.o disx.o: disx.c disx.h ../../V/Vlibmath.h ../../util/memory.h dis.h earth.h $(CC) $(CFLAGS) -c disx.c -o disx.o earth.o: earth.c earth.h ../../V/Vlibmath.h ../../util/units.h $(CC) $(CFLAGS) -c earth.c -o earth.o xdr.o: xdr.c xdr.h ../../util/memory.h $(CC) $(CFLAGS) -c xdr.c -o xdr.o xdr_dis.o: xdr_dis.c xdr_dis.h ../../V/Vlibmath.h ../../util/error.h datum.h dis.h earth.h xdr.h $(CC) $(CFLAGS) -c xdr_dis.c -o xdr_dis.o # Checksum of the original file: 1870947444 acm-6.0_20200416/src/dis/dis/earth.c0000644000000000000000000004101613646045024015175 0ustar rootroot/* * DIS/x : An implementation of the IEEE 1278.1 protocol * * Copyright (C) 1997, Riley Rainey (rrainey@ix.netcom.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of either: * * a) the GNU Library General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your * option) any later version. A description of the terms and conditions * of the GLPL may be found in the "COPYING.LIB" file. * * b) the "Artistic License" which comes with this Kit. Information * about this license may be found in the "Artistic" file. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License or the Artistic License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Information describing how to contact the author can be found in the * README file. */ /* * IMPLEMENTATION NOTES. * * "The Surveying Handbook", edited by Brinker and Minnick contains a decent * discussion of the technical issues required to understand what's going on in * this code. */ #include #include #include #include /* * Linker options collected by make-makefile script. * LINKER_OPTIONS -lm */ #include #include "../../util/error.h" #include "../../util/units.h" #define earth_IMPORT #include "earth.h" #undef earth_IMPORT double earth_normalizeLatitude(double lat) { if( ! isfinite(lat) ) return lat; /* Force range [-PI,+PI] by adding/removing multiples of 2*PI: */ if(lat > M_PI) lat = lat - 2*M_PI*(floor(lat / (2*M_PI)) + 1); if(lat < -M_PI) lat = lat + 2*M_PI*(floor(-lat / (2*M_PI)) + 1); /* Normalize to the [-PI/2,+PI/2] range: */ if (lat > M_PI_2) lat = M_PI_2 - lat; else if (lat < -M_PI_2) lat = -M_PI - lat; return lat; } double earth_normalizeLongitude(double lon) { if( ! isfinite(lon) ) return lon; /* Force range [-PI,+PI] by adding/removing multiples of 2*PI: */ if(lon > M_PI) lon = lon - 2*M_PI*(floor(lon / (2*M_PI)) + 1); if(lon < -M_PI) lon = lon + 2*M_PI*(floor(-lon / (2*M_PI)) + 1); /* Normalize to the ]-PI,+PI] range: */ if( lon > M_PI ) lon -= 2*M_PI; else if( lon <= - M_PI ) lon += 2*M_PI; return lon; } void earth_updateLatLon(earth_LatLonAlt * p, double cos_course, double sin_course, double d_meters) { double n1, n2, m1; double sin_lat, sin_lat_sqr, tan_lat, sin_course_sqr; double delta_latitude, delta_longitude, d_sqr, cos_lat; double B, C, /* D, */ E, h, sin_newlat; /* Increase our height to the height above the reference ellipsoid */ double wgs84_a = earth_MAJOR + p->z; sin_lat = sin(p->latitude); sin_lat_sqr = sin_lat * sin_lat; cos_lat = cos(p->latitude); tan_lat = sin_lat / cos_lat; sin_course_sqr = sin_course * sin_course; d_sqr = d_meters * d_meters; n1 = wgs84_a / sqrt(1.0 - earth_ECCENTRICITY_SQR * sin_lat_sqr); m1 = (wgs84_a * (1.0 - earth_ECCENTRICITY_SQR)) / pow(1.0 - earth_ECCENTRICITY_SQR * sin_lat_sqr, 1.5); B = 1.0 / m1; h = d_meters * B * cos_course; C = tan_lat / (2.0 * m1 * n1); #ifdef notdef D = (3.0 * earth_ECCENTRICITY_SQR * sin_lat * cos_lat) / (2.0 * (1.0 - earth_ECCENTRICITY_SQR * sin_lat_sqr)); #endif E = (1.0 + 3.0 * tan_lat * tan_lat) * (1.0 - earth_ECCENTRICITY_SQR * sin_lat_sqr) / (6.0 * wgs84_a * wgs84_a); delta_latitude = d_meters * B * cos_course - d_sqr * C * sin_course_sqr - h * d_sqr * E * sin_course_sqr; p->latitude = earth_normalizeLatitude(p->latitude + delta_latitude); sin_newlat = sin(p->latitude); n2 = wgs84_a / sqrt(1.0 - earth_ECCENTRICITY_SQR * sin_newlat * sin_newlat); delta_longitude = (d_meters * sin_course) / (n2 * cos(p->latitude)); p->longitude = earth_normalizeLongitude(p->longitude + delta_longitude); } void earth_updateLatLonEx(earth_LatLonAlt * p, double cos_course, double sin_course, double d_meters, double * delta_course_rad ) { double n1, n2, m1; double sin_lat, sin_lat_sqr, tan_lat, sin_course_sqr; double delta_latitude, delta_longitude, d_sqr, cos_lat; double B, C, /* D, */ E, h, sin_newlat; double old_latitude, phi_m, sin_phi_m, cos_phi_m; /* arc-seconds per rad */ const double rho = 206264.8062470964; /* Increase our height to the height above the reference ellipsoid */ double wgs84_a = earth_MAJOR + p->z; sin_lat = sin(p->latitude); sin_lat_sqr = sin_lat * sin_lat; cos_lat = cos(p->latitude); tan_lat = sin_lat / cos_lat; sin_course_sqr = sin_course * sin_course; d_sqr = d_meters * d_meters; n1 = wgs84_a / sqrt(1.0 - earth_ECCENTRICITY_SQR * sin_lat_sqr); m1 = (wgs84_a * (1.0 - earth_ECCENTRICITY_SQR)) / pow(1.0 - earth_ECCENTRICITY_SQR * sin_lat_sqr, 1.5); B = 1.0 / m1; h = d_meters * B * cos_course; C = tan_lat / (2.0 * m1 * n1); #ifdef notdef D = (3.0 * earth_ECCENTRICITY_SQR * sin_lat * cos_lat) / (2.0 * (1.0 - earth_ECCENTRICITY_SQR * sin_lat_sqr)); #endif E = (1.0 + 3.0 * tan_lat * tan_lat) * (1.0 - earth_ECCENTRICITY_SQR * sin_lat_sqr) / (6.0 * wgs84_a * wgs84_a); delta_latitude = d_meters * B * cos_course - d_sqr * C * sin_course_sqr - h * d_sqr * E * sin_course_sqr; old_latitude = p->latitude; p->latitude = earth_normalizeLatitude(p->latitude + delta_latitude); phi_m = old_latitude + delta_latitude / 2.0; sin_phi_m = sin(phi_m); cos_phi_m = cos(phi_m); sin_newlat = sin(p->latitude); n2 = wgs84_a / sqrt(1.0 - earth_ECCENTRICITY_SQR * sin_newlat * sin_newlat); delta_longitude = (d_meters * sin_course) / (n2 * cos(p->latitude)); *delta_course_rad = delta_longitude * sin_phi_m / cos(delta_latitude / 2.0) + delta_longitude * (sin_phi_m * cos_phi_m * cos_phi_m) / rho; p->longitude = earth_normalizeLongitude(p->longitude + delta_longitude); } char * earth_latitudeToString(char *s, int s_capacity, double la, earth_LatLonDisplayFormat mode) { int s100, d, m; double dla, dmin; double round_dm = 1.0 / (600.0 * 2.0); char ns; if( ! (isfinite(la) && -M_PI_2 <= la && la <= M_PI_2) ){ // De-normalized or INF or NAN. snprintf(s, s_capacity, "%g", la); return s; } // Beware: pay attention to printf() format descriptors ".1f" as a // rounding might take place giving unexpected results, for example // 59.95 would be rendered as "60.0" which is not a valid number of primes nor // seconds! Better using int numbers representing the wanted precision and // manage rounding ourself. round_dm = 0.0; switch (mode) { case earth_LLM_DMS: ns = (la >= 0.0) ? 'N' : 'S'; s100 = units_RADtoDEG(fabs(la)) * 360000 + 0.5; // hundreds of second if( s100 > 360000 * 90 ){ // Rounding fooled us... s100 = 360000 * 90; } d = s100 / 360000; s100 -= 360000 * d; m = s100 / 6000; s100 -= 6000 * m; snprintf(s, s_capacity, "%02d-%02d-%02d.%02d%c", d, m, s100 / 100, s100 % 100, ns); break; case earth_LLM_DM: ns = (la >= 0.0) ? 'N' : 'S'; dla = units_RADtoDEG(fabs(la)) + round_dm; d = (int) dla; dmin = (dla - (double) d) * 60.0; snprintf(s, s_capacity, "%d %.1f %c", d, dmin, ns); break; case earth_LLM_D: ns = (la >= 0.0) ? 'N' : 'S'; dla = units_RADtoDEG(fabs(la)); snprintf(s, s_capacity, "%.1f %c", dla, ns); break; case earth_LLM_SIGNED_D: snprintf(s, s_capacity, "%.1f", units_RADtoDEG(la)); break; default: error_internal("invalid format descriptor: %d", mode); } return s; } char * earth_longitudeToString(char *s, int s_capacity, double lo, earth_LatLonDisplayFormat mode) { int s100, d, m; double dlo, dmin; double round_dm = 1.0 / (600.0 * 2.0); char ew; if( ! (isfinite(lo) && -M_PI <= lo && lo <= M_PI) ){ // De-normalized or INF or NAN. snprintf(s, s_capacity, "%g", lo); return s; } round_dm = 0.0; switch (mode) { case earth_LLM_DMS: ew = (lo >= 0.0) ? 'E' : 'W'; s100 = units_RADtoDEG(fabs(lo)) * 360000 + 0.5; // hundreds of second if( s100 > 360000 * 180 ){ // Rounding fooled us... s100 = 360000 * 180; } d = s100 / 360000; s100 -= 360000 * d; m = s100 / 6000; s100 -= 6000 * m; sprintf(s, "%03d-%02d-%02d.%02d%c", d, m, s100 / 100, s100 % 100, ew); break; case earth_LLM_DM: ew = (lo >= 0.0) ? 'E' : 'W'; dlo = units_RADtoDEG(fabs(lo)) + round_dm; d = (int) dlo; dmin = (dlo - (double) d) * 60.0; snprintf(s, s_capacity, "%d %.1f %c", d, dmin, ew); break; case earth_LLM_D: ew = (lo >= 0.0) ? 'E' : 'W'; dlo = units_RADtoDEG(fabs(lo)); snprintf(s, s_capacity, "%.1f %c", dlo, ew); break; case earth_LLM_SIGNED_D: snprintf(s, s_capacity, "%.1f", units_RADtoDEG(lo)); break; default: error_internal("invalid format descriptor: %d", mode); } return s; } void earth_XYZToString(char *s, int s_capacity, VPoint *xyz) { snprintf(s, s_capacity, "%.0f m, %.0f m, %.0f m", xyz->x, xyz->y, xyz->z); } void earth_LatLonAltToString(char * s, int s_capacity, earth_LatLonAlt *w, earth_LatLonDisplayFormat mode) { char lat[99], lon[99]; earth_latitudeToString(lat, sizeof(lat), w->latitude, mode); earth_longitudeToString(lon, sizeof(lon), w->longitude, mode); snprintf(s, s_capacity, "%s %s %.0f m", lat, lon, w->z); } void earth_XYZToLatLonAlt(VPoint * loc, earth_LatLonAlt * p) { double a_sqr = earth_MAJOR * earth_MAJOR, b_sqr = earth_MINOR * earth_MINOR; double w, x, x_sqr, z, delta_x, cos_x; double f, f_prime, w0, z0; w = sqrt(loc->x * loc->x + loc->y * loc->y); z = loc->z; /* * x is the sine of the parametric latitude. Use the sine of the geocentric * latitude as the initial guess. */ if (w == 0.0 && z == 0.0) { p->latitude = 0.0; p->longitude = 0.0; p->z = 0.0; return; } x = z / sqrt(w * w + z * z); /* * Compute x with accuracy that will yield a lat/lon accuracy of * about 0.0001 arc-seconds (~ 0.10 foot). */ for (delta_x = 1.0; fabs(delta_x) > 4.8E-10;) { x_sqr = x * x; cos_x = sqrt(1.0 - x_sqr); f = 2.0 * (earth_MAJOR * x * w - a_sqr * x * cos_x - earth_MINOR * cos_x * z + b_sqr * cos_x * x); f_prime = 2.0 * (a_sqr + 2.0 * (a_sqr * x_sqr) - earth_MAJOR * w * x_sqr + b_sqr - 2.0 * b_sqr * x_sqr + earth_MINOR * x * z); delta_x = f / f_prime; x -= delta_x; } z0 = earth_MINOR * x; w0 = earth_MAJOR * sqrt(1.0 - x * x); p->z = sqrt((z - z0) * (z - z0) + (w - w0) * (w - w0)); p->latitude = atan(z0 / (w0 * (1.0 - earth_ECCENTRICITY_SQR))); p->longitude = atan2(loc->y, loc->x); } void earth_LatLonAltToXYZ(earth_LatLonAlt * w, VPoint * p) { double N, N1; double cos_latitude, sin_latitude; sin_latitude = sin(w->latitude); cos_latitude = cos(w->latitude); /* * N is the length of the normal line segment from the surface to the * spin axis. */ N = earth_MAJOR / sqrt(1.0 - (earth_ECCENTRICITY_SQR * sin_latitude * sin_latitude)); /* * N1 lengthens the normal line to account for height above the surface */ N1 = N + w->z; p->x = N1 * cos_latitude * cos(w->longitude); p->y = N1 * cos_latitude * sin(w->longitude); p->z = (((earth_MINOR * earth_MINOR) / (earth_MAJOR * earth_MAJOR)) * N + w->z) * sin_latitude; } /* * Symbols scanner for geographical coordinates. */ #define STATE_INITIAL 0 #define STATE_WORD 1 #define STATE_INTEGER 2 #define STATE_FLOAT 3 typedef enum { EndOfFile, TOKEN_FLOAT, TOKEN_LONG, TOKEN_DASH, TOKEN_NORTH, TOKEN_SOUTH, TOKEN_EAST, TOKEN_WEST } token_id; typedef union { double double_value; long long_value; } lex_val; static lex_val lex_value; struct lex_record { char *s; FILE *f; int lookahead_valid; int lookahead; int stack_top; lex_val value_stack[16]; }; static int input(struct lex_record *p) { int val; if (p->lookahead_valid) { p->lookahead_valid = 0; val = p->lookahead; } else if (p->s) { val = *(p->s)++; } else { val = fgetc(p->f); } return val; } #define push_value(p, type, val) \ p->value_stack[p->stack_top++].type = val #define pop_value(p, type) (p->value_stack[--p->stack_top].type) #define unput(p, c) { p->lookahead = c; p->lookahead_valid = 1; } #define InitializeLexRecord(p) { p->lookahead_valid = 0; } static char token[256]; static int token_length = 0; static token_id NextTokenx(struct lex_record *p) { register int c, state = STATE_INITIAL; token_length = 0; while ((c = input(p)) != EOF) { switch (state) { case STATE_INITIAL: if (isspace(c)) { continue; } else if (isdigit(c)) { token[token_length++] = c; state = STATE_INTEGER; } else if (c == '.') { token[token_length++] = c; state = STATE_FLOAT; } else { token[0] = c; token[1] = '\0'; #ifdef DEBUG printf("other %s\n", token); #endif switch (c) { case '-': return TOKEN_DASH; case 'n': case 'N': return TOKEN_NORTH; case 'e': case 'E': return TOKEN_EAST; case 's': case 'S': return TOKEN_SOUTH; case 'w': case 'W': return TOKEN_WEST; /* * invalid character */ default: return EndOfFile; } } break; case STATE_INTEGER: case STATE_FLOAT: if (isspace(c) || c == '-' || toupper(c) == 'N' || toupper(c) == 'S' || toupper(c) == 'W' || toupper(c) == 'E') { token[token_length] = '\0'; unput(p, c); if (state == STATE_INTEGER) { lex_value.long_value = atoi(token); return TOKEN_LONG; } else { lex_value.double_value = atof(token); return TOKEN_FLOAT; } } else { if (c == '.') { state = STATE_FLOAT; } token[token_length++] = c; } break; default: token[token_length++] = c; break; } } return EndOfFile; } static token_id NextToken(struct lex_record *p) { token_id t; t = NextTokenx(p); #ifdef DEBUG printf("token %s\n", token); #endif return t; } static int ParseLatitude(struct lex_record *p) { double x = 0.0; double divider = 1.0; int int_valid = 1; token_id t; t = NextToken(p); for (;;) { switch (t) { case TOKEN_NORTH: lex_value.double_value = x; return 0; case TOKEN_SOUTH: lex_value.double_value = -x; return 0; case TOKEN_LONG: if (int_valid) { x += lex_value.long_value / divider; divider *= 60.0; t = NextToken(p); if (t == TOKEN_DASH) { t = NextToken(p); } } else { return -1; } break; case TOKEN_FLOAT: int_valid = 0; x += lex_value.double_value / divider; divider *= 60.0; t = NextToken(p); if (t == TOKEN_DASH) { t = NextToken(p); } break; default: return -1; } } } static int ParseLongitude(struct lex_record *p) { double x = 0.0; double divider = 1.0; int t, int_valid = 1; t = NextToken(p); for (;;) { switch (t) { case TOKEN_EAST: lex_value.double_value = x; return 0; case TOKEN_WEST: lex_value.double_value = -x; return 0; case TOKEN_LONG: if (int_valid) { x += lex_value.long_value / divider; divider *= 60.0; t = NextToken(p); if (t == TOKEN_DASH) { t = NextToken(p); } } else { return -1; } break; case TOKEN_FLOAT: int_valid = 0; x += lex_value.double_value / divider; divider *= 60.0; t = NextToken(p); if (t == TOKEN_DASH) { t = NextToken(p); } break; default: return -1; } } } int earth_parseLatitude(char *s, double *latitude_rad) { struct lex_record p; p.s = s; p.lookahead_valid = 0; if (ParseLatitude(&p) != 0) return 0; *latitude_rad = units_DEGtoRAD(lex_value.double_value); return *p.s == 0; } int earth_parseLongitude(char *s, double *longitude_rad) { struct lex_record p; p.s = s; p.lookahead_valid = 0; if (ParseLongitude(&p) != 0) return 0; *longitude_rad = units_DEGtoRAD(lex_value.double_value); return *p.s == 0; } char * earth_parseLatLon(char *s, earth_LatLonAlt * w) { struct lex_record p; p.s = s; p.lookahead_valid = 0; if (ParseLatitude(&p) != 0) { return 0; } w->latitude = units_DEGtoRAD(lex_value.double_value); if (ParseLongitude(&p) != 0) { return 0; } w->longitude = units_DEGtoRAD(lex_value.double_value); w->z = 0.0; return p.s; } void earth_generateWorldToLocalMatrix(earth_LatLonAlt *w, VMatrix *XYZtoNED) { VPoint gc, p; VIdentMatrix(XYZtoNED); VRotate(XYZtoNED, ZRotation, -w->longitude); VRotate(XYZtoNED, YRotation, w->latitude); VRotate(XYZtoNED, YRotation, units_DEGtoRAD(90.0)); earth_LatLonAltToXYZ(w, &gc); VTransform(&gc, XYZtoNED, &p); XYZtoNED->m[0][3] = -p.x; XYZtoNED->m[1][3] = -p.y; XYZtoNED->m[2][3] = -p.z; } acm-6.0_20200416/src/dis/dis/Makefile-include.txt0000644000000000000000000000031013106475701017615 0ustar rootroot.PHONY: rebuild rebuild: clean find . -mindepth 1 -type d \ | while read d; do \ if [ -f $$d/Makefile ]; then \ echo "$$d"; \ (cd $$d; check-included && make-makefile); \ fi \ done make acm-6.0_20200416/src/dis/dis/earth.h0000644000000000000000000002167613646045024015214 0ustar rootroot/* * DIS/x : An implementation of the IEEE 1278.1 protocol * * Copyright (C) 1997, Riley Rainey (rrainey@ix.netcom.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of either: * * a) the GNU Library General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your * option) any later version. A description of the terms and conditions * of the GLPL may be found in the "COPYING.LIB" file. * * b) the "Artistic License" which comes with this Kit. Information * about this license may be found in the "Artistic" file. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License or the Artistic License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Information describing how to contact the author can be found in the * README file. */ /** * Earth Cartesian geocentric coordinates system, calculations and conversions. * In the DIS 2.0 coordinate system: * * - positive X axis points to 0N, 0E * - positive Y axis points to 0N 90E * - positive Z axis is North * * THE WGS84 ELLIPSOID * The world is considered a perfect ellipsoid based on the WGS84 standard -- * no correction is made to take into account height differences between the * ellipsoid and the actual shape of the Earth (the "geoid"). The surface of the * WGS84 ellipsoid is described by the equation below: * * x^2/a^2 + y^2/a^2 + z^2/b^2 = 1 * * where "a" the equatorial (or major) semi-axis, and "b" is the polar (or minor) * semi-axis of the ellipsoid. This surface is our "sea level" and all the * altitudes are referred to this base level. Note that the z axis is the spin * axis of our ellipsoidal Earth, and the x and y semi-axis are both equal to "a". * The north pole is located at (0,0,b). * The south pole is located at (0,0,-b). * The equatorial line is the circle x^2 + y^2 = a^2 with z=0. * The zero meridian of Greenwich is the semi-ellipse x^2/a^2 + z^2/b^2 = 1 * with x >= 0, y = 0. * * DEFINITION OF THE GEODETIC LONGITUDE * Because of this symmetry around the z spin axis, the geodetic longitude can * be easily defined and calculated for any given point (x,y,z) as: * * longitude = atan(y/x) * * This formula is valid for any point, at any longitude, any latitude and * altitude, and not only for the points on the ellipsoid. * * DEFINITION OF LOCAL VERTICAL * For any point on the surface of the ellipsoid, the line perpendicular to the * surface is the local vertical (our "plumb line") and the tangent plane is our * local horizon. Note that the local vertical line DOES NOT cross the center of * the ellipsoid as it would on a simple sphere. * * DEFINITION OF THE GEODETIC ALTITUDE * The geodetic altitude of a point (x,y,z) above (or even below) the surface of * the ellipsoid is defined as the distance of the point from the surface of the * ellipsoid measured over a line perpendicular to the ellipsoid, that is over * the local vertical. The altitude is taken positive above the surface, negative * below. * * DEFINITION OF THE GEODETIC LATITUDE * The geodetic latitude of a point is defined as the angle between the local * vertical line and the xy plane, taken positive for z>0. * * @file * @author Riley Rainey * @version $Date: 2020/01/08 06:20:05 $ */ #ifndef EARTH_H #define EARTH_H #include "../../V/Vlibmath.h" #ifdef earth_IMPORT #define EXTERN #else #define EXTERN extern #endif /** WGS84 equatorial semi-axis "a" (m). */ #define earth_MAJOR 6378137.0 /** WGS84 polar semi-axis "b" (m). */ #define earth_MINOR 6356752.3142 /** Eccentricity = sqrt(1 - (b/a)^2). */ #define earth_ECCENTRICITY 0.081819190928906199466 /** Eccentricity squared. */ #define earth_ECCENTRICITY_SQR 0.006694380004260806515 /** * Geodetic coordinates of a point. */ typedef struct { /** Geodetic latitude (RAD, [M_PI/2, -M_PI/2]). */ double latitude; /** Geodetic longitude (RAD, [-M_PI, M_PI]). */ double longitude; /** Geodetic altitude (m). */ double z; } earth_LatLonAlt; typedef enum { earth_LLM_DMS, /* dd-mm-ss.ss[EWNS] */ earth_LLM_DM, /* dd mm [EWNS] */ earth_LLM_D, /* dd [EWNS] */ earth_LLM_SIGNED_D } earth_LatLonDisplayFormat; /** * Normalizes the latitude. * @param lat Latitude to normalize (RAD). * @return Latitude normalized to the range [-M_PI/2,+M_PI/2]. If not finite, * returns the value itself. */ EXTERN double earth_normalizeLatitude(double lat); /** * Normalizes the longitude. * @param lon Longitude to normalize (RAD). * @return Longitude normalized to the range ]-M_PI,+M_PI]. If not finite, * returns the value itself. */ EXTERN double earth_normalizeLongitude(double lon); /** * Shift location d meters on a given geodetic course (radians). As usual, * course 0 degrees is north, course 90 degrees is east. * FIXME: the result is undefined at and near the north and south pole, and * quite random numbers come out. * @param p * @param sin_course Sine of the course. * @param cos_course Cosine of the course. * @param d_meters Step length, constant altitude (m). */ EXTERN void earth_updateLatLon(earth_LatLonAlt * p, double sin_course, double cos_course, double d_meters); /** * Shift location d_meters meters on a given geodetic course (radians). * FIXME: the result is undefined at and near the north and south pole, and * quite random numbers come out. * @return new outbound heading correct for the new location in delta_course_rad */ EXTERN void earth_updateLatLonEx(earth_LatLonAlt * p, double cos_course, double sin_course, double d_meters, double * delta_course_rad ); /** * Format a latitude. If the latitude is not finite or out of the range, then * the literal number is returned using the standard "%g" format descriptor. * @param s Destination buffer. * @param s_capacity Destination buffer capacity. * @param la Latitude (RAD). * @param mode * @return Pointer to the same "s" string. */ EXTERN char * earth_latitudeToString(char *s, int s_capacity, double la, earth_LatLonDisplayFormat mode); /** * Format a longitude. If the latitude is not finite or out of the range, then * the literal number is returned using the standard "%g" forma descriptor. * @param s Destination buffer. * @param s_capacity Destination buffer capacity. * @param lo Longitude (RAD). * @param mode * @return Pointer to the same "s" string. */ EXTERN char * earth_longitudeToString(char *s, int s_capacity, double lo, earth_LatLonDisplayFormat mode); /** * Formats Cartesian coordinates of a point on the Earth, rounded to 1 meter of * precision. * @param s Destination string. * @param s_capacity Capacity of the destination string. * @param xyz Cartesian coordinates of the point (m). */ EXTERN void earth_XYZToString(char *s, int s_capacity, VPoint *xyz); /** * Formats geographic coordinates. * @param s Destination string. * @param s_capacity Capacity of the destination string. * @param w Geographic coordinates to format. * @param mode */ EXTERN void earth_LatLonAltToString(char * s, int s_capacity, earth_LatLonAlt *w, earth_LatLonDisplayFormat mode); /** * Convert Cartesian coordinates into WGS84 geodetic lat/lon/z. * @param p Cartesian coordinates to convert (m). * @param w Resulting world coordinates. */ EXTERN void earth_XYZToLatLonAlt(VPoint * p, earth_LatLonAlt * w); /** * Convert WGS84 geodetic lat/lon/z into Cartesian coordinates. * @param w World coordinates to convert. * @param Resulting Cartesian coordinates (m). */ EXTERN void earth_LatLonAltToXYZ(earth_LatLonAlt * w, VPoint * p); /** * Parse a latitude string. Example: "12-34-56.7N" or "12.5824N". * @param s Latitude string. * @param latitude_rad Resulting parsed latitude (RAD). * @return True if parsing succeeded. */ EXTERN int earth_parseLatitude(char *s, double *latitude_rad); /** * Parse a longitude string. Example: "123-45-06.7E" or "123.7519E". * @param s Longitude string. * @param longitude_rad Resulting parsed longitude (RAD). * @return True if parsing succeeded. */ EXTERN int earth_parseLongitude(char *s, double *longitude_rad); /** * Parse latitude and longitude string. * @param s Latitude and longitude separated by at least one white space * character; the syntax of each component is the same of a single latitude * and longitude. * @param w Here returns parsed latitude and longitude; altitude set to zero. * @return True if parsing succeeded. */ EXTERN char * earth_parseLatLon(char *s, earth_LatLonAlt * w); /** * Generate a transform matrix to get from Cartesian to local NED coordinates. */ EXTERN void earth_generateWorldToLocalMatrix(earth_LatLonAlt *w, VMatrix *XYZtoNED); #undef EXTERN #endif acm-6.0_20200416/src/dis/dis/dis.h0000644000000000000000000011156413175225346014670 0ustar rootroot/* * DIS/x : An implementation of the IEEE 1278.1 protocol * * Copyright (C) 1997, Riley Rainey (rrainey@ix.netcom.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of either: * * a) the GNU Library General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your * option) any later version. A description of the terms and conditions * of the GLPL may be found in the "COPYING.LIB" file. * * b) the "Artistic License" which comes with this Kit. Information * about this license may be found in the "Artistic" file. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License or the Artistic License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Information describing how to contact the author can be found in the * README file. */ /** * DIS types and data structure and basic access routines. * Basically compliant with IEEE 1278.1-1995, but some more declaration added * for future upgrade of this compliance. * * @file * @author Riley Rainey * @version $Date: 2017/10/28 10:41:22 $ */ #ifndef DIS_H #define DIS_H #ifdef WINNT #include #include #else #include #endif #include "earth.h" #include "../../V/Vlibmath.h" // needs VMatrix type #ifdef dis_IMPORT #define EXTERN #else #define EXTERN extern #endif // FI = field information #define PDUTypeOther 0 #define PDUTypeEntityState 1 #define PDUTypeFire 2 #define PDUTypeDetonation 3 #define PDUTypeCollision 4 #define PDUTypeServiceRequest 5 #define PDUTypeResupplyOffer 6 #define PDUTypeResupplyReceived 7 #define PDUTypeResupplyCancel 8 #define PDUTypeRepairComplete 9 #define PDUTypeRepairResponse 10 #define PDUTypeCreateEntity 11 #define PDUTypeRemoveEntity 12 #define PDUTypeStartResume 13 #define PDUTypeStopFreeze 14 #define PDUTypeAcknowledge 15 #define PDUTypeActionRequest 16 #define PDUTypeActionResponse 17 #define PDUTypeDataQuery 18 #define PDUTypeSetData 19 #define PDUTypeData 20 #define PDUTypeEventReport 21 #define PDUTypeComment 22 #define PDUTypeEmission 23 #define PDUTypeDesignator 24 #define PDUTypeTransmitter 25 #define PDUTypeSignal 26 #define PDUTypeReceiver 27 #define PDUTypeAnnounceObject 129 #define PDUTypeDeleteObject 130 #define PDUTypeDescribeApplication 131 #define PDUTypeDescribeEvent 132 #define PDUTypeDescribeObject 133 #define PDUTypeRequestEvent 134 #define PDUTypeRequestObject 135 #define PDUTypeTimeSpacePositionIndicatorFI 140 #define PDUTypeAppearanceFI 141 #define PDUTypeArticulatedPartsFI 142 #define PDUTypeFireFI 143 #define PDUTypeDetonationFI 144 #define PDUTypePointObjectState 150 #define PDUTypeLinearObjectState 151 #define PDUTypeArealObjectState 152 #define PDUTypeEnvironment 153 #define PDUTypeTransferControlRequest 155 #define PDUTypeTransferControl 156 #define PDUTypeTransferControlAcknowledge 157 #define PDUTypeIntercomControl 160 #define PDUTypeIntercomSignal 161 #define PDUTypeAggregate 170 //#define PDUTypeExperimentalRequestControl 150 //#define PDUTypeExperimentalGrantControl 151 //#define PDUTypeTransferControl 36 #define PDUFamilyOther 0 #define PDUFamilyEntityInformation 1 #define PDUFamilyWarfare 2 #define PDUFamilyLogistics 3 #define PDUFamilyRadioCommunications 4 #define PDUFamilySimulationManagement 5 #define PDUFamilyDistributedEmissionRegeneration 6 #define PDUFamilyExperimentalCGF 129 #define PDUFamilyExperimentalEntityInteractionInformationFI 130 #define PDUFamilyExperimentalWarfareFI 131 #define PDUFamilyExperimentalEnvironmentObjectInformationInteraction 132 #define PDUFamilyExperimentalEntityManagement 133 typedef enum { /** Version 1.0 Draft (1992). */ DISProtocolVersionMay92 = 1, /** IEEE 1278-1993. */ DISProtocolVersionIEEE1278_93 = 2, /** Version 2.0 Third Draft (May 1993). */ DISProtocolVersionMay93 = 3, /** Version 2.0 Fourth Draft (March 1994). */ DISProtocolVersion2_04 = 4, /** IEEE 1278.1-1995, the target compliance of this module. */ DISProtocolVersionIEEE1278_95 = 5, /** IEEE 1278.1a-1998 (amendment to IEEE 1278.1-1995). */ DISProtocolVersionIEEE1278_98 = 6, /** IEEE 1278.1-2012. */ DISProtocolVersionIEEE1278_2012 } DISProtocolVersion; /** * Force the entity belongs to. See also handy conversion routines from * force to string and vice-versa dis_parseForce() and dis_forceToString(). */ typedef enum { DISForceOther = 0, DISForceFriendly = 1, DISForceOpposing = 2, DISForceNeutral = 3 } DISForce; typedef enum { DISRequestStatusOther = 0, DISRequestStatusPending = 1, DISRequestStatusExecuting = 2, DISRequestStatusPartiallyComplete = 3, DISRequestStatusComplete = 4 } DISRequestStatus; typedef enum { DISAcknowledgeFlagCreateEntity = 1, DISAcknowledgeFlagRemoveEntity = 2, DISAcknowledgeFlagStart = 3, DISAcknowledgeFlagStop = 4 } DISAcknowledgeFlag; typedef enum { DISStopReasonOther = 0, DISStopReasonRecess = 1, DISStopReasonTermination = 2, DISStopReasonSystemFailure = 3, DISStopReasonSecurityViolation = 4, DISStopReasonEntityReconstitution = 5 } DISStopReason; #define DISFrozenBehaviorRunClock (1<<0) #define DISFrozenBehaviorTransmit (1<<1) #define DISFrozenBehaviorReceive (1<<2) typedef enum { DISTransferTypeOther = 0, DISTransferTypeEntityControllerRequest = 1, DISTransferTypeEntityRequest = 2, DISTransferTypeEntityMutualExchange = 3, DISTransferTypeEnvironmentalControllerRequest = 4, DISTransferTypeEnvironmentalRequest = 5, DISTransferTypeEnvironmentalMutualExchange = 6 } DISTransferType; /* * From IEEE 1278.1-1995 */ #define ALL_APPLIC 0xFFFF #define ALL_ENTITIES 0xFFFF #define ALL_SITES 0xFFFF #define COLLISION_THRSH_DFLT 0.1 #define DRA_ORIENT_THRSH_DFLT 3.0 #define DRA_POS_THRSH_DFLT 1.0 #define NO_APPLIC 0x0000 #define NO_ENTITY 0x0000 #define NO_SITE 0x0000 #define NOR_FIRE_MISSION 0x0000 #define RQST_ASSIGN_ID 0xFFFE #define DISAppearancePaintUniform 0 #define DISAppearancePaintCamouflage 1 #define DISAppearancePaintMask 1 #define DISAppearanceMobilityNormal (0 << 1) #define DISAppearanceMobilityDisabled (1 << 1) #define DISAppearanceFirepowerNormal (0 << 2) #define DISAppearanceFirepowerDisabled (1 << 2) #define DISAppearanceDamageNone (0 << 3) #define DISAppearanceDamageSlight (1 << 3) #define DISAppearanceDamageModerate (2 << 3) #define DISAppearanceDamageDestroyed (3 << 3) #define DISAppearanceDamageMask (3 << 3) #define DISAppearanceSmokeNone (0 << 5) #define DISAppearanceSmokePlume (1 << 5) #define DISAppearanceSmokeEngine (2 << 5) #define DISAppearanceSmokePlumeAndEngine (3 << 5) #define DISAppearanceSmokeMask (3 << 5) #define DISAppearanceSmokeTrailingNone (0 << 7) #define DISAppearanceSmokeTrailingSmall (1 << 7) #define DISAppearanceSmokeTrailingMedium (2 << 7) #define DISAppearanceSmokeTrailingLarge (3 << 7) #define DISAppearanceSmokeTrailingMask (3 << 7) #define DISAppearanceHatchNA (0 << 9) #define DISAppearanceHatchClosed (1 << 9) #define DISAppearanceHatchPopped (2 << 9) #define DISAppearanceHatchPoppedPerson (3 << 9) #define DISAppearanceHatchOpen (4 << 9) #define DISAppearanceHatchOpenPerson (5 << 9) #define DISAppearanceHatchMask (7 << 9) #define DISLightsNone (0 << 12) #define DISLightsRunning (1 << 12) #define DISLightsNavigation (2 << 12) #define DISLightsFormation (3 << 12) #define DISLightsMask (3 << 12) #define DISNoFlames (0 << 15) #define DISFlamesPresent (1 << 15) #define DISAppearancePlatformNotFrozen (0 << 21) #define DISAppearancePlatformFrozen (1 << 21) #define DISAppearancePlatformPowerplantOff (0 << 22) #define DISAppearancePlatformPowerplantOn (1 << 22) #define DISAppearancePlatformActive (0 << 23) #define DISAppearancePlatformDeactivated (1 << 23) #define DISAppearanceAirAfterburnerOn (1 << 16) #define DISAppearanceLandLauncherRaised (1 << 16) #define DISAppearanceLandCammouflageDesert (0 << 17) #define DISAppearanceLandCammouflageWinter (1 << 17) #define DISAppearanceLandCammouflageForest (2 << 17) #define DISAppearanceLandCammouflageMask (3 << 17) #define DISAppearanceLandConcealed (1 << 19) #define DISKindOther 0 #define DISKindPlatform 1 #define DISKindMunition 2 #define DISKindLifeForm 3 #define DISKindEnvironmental 4 #define DISKindCultural 5 #define DISKindSupply 6 #define DISKindRadio 7 #define DISDomainOther 0 #define DISDomainLand 1 #define DISDomainAir 2 #define DISDomainSurface 3 #define DISDomainSubsurface 4 #define DISDomainSpace 5 #define DISCategoryLandOther 0 #define DISCategoryLandTank 1 #define DISCategoryLandAFV 2 #define DISCategoryLandAUV 3 #define DISCategorySPA 4 #define DISCategoryTowedArty 5 #define DISCategorySmallWUV 6 #define DISCategoryLargeWUV 7 #define DISTargetDomainOther 0 #define DISTargetDomainAntiAir 1 #define DISTargetDomainAntiArmor 2 #define DISTargetDomainAntiGuidedMunition 3 #define DISTargetDomainAntiRadar 4 #define DISTargetDomainAntiSatellite 5 #define DISTargetDomainAntiShip 6 #define DISTargetDomainAntiSubmarine 7 #define DISTargetDomainBattlefieldSupport 8 #define DISTargetDomainStrategic 8 #define DISTargetDomainMisc 10 #define DISDRMethodOther 0 #define DISDRMethodStatic 1 #define DISDRMethodFPW 2 #define DISDRMethodRPW 3 #define DISDRMethodRVW 4 #define DISDRMethodFVW 5 #define DISDRMethodFPB 6 #define DISDRMethodRPB 7 #define DISDRMethodRVB 8 #define DISDRMethodFVB 9 #define DISDRMethodRPW_2 10 #define DISDRMethodRVW_2 11 #define DISCharSetUnused 0 #define DISCharSetASCII 1 #define DISCapabilityAmmunitionSupply 1 #define DISCapabilityFuelSupply 2 #define DISCapabilityMiscSupply 4 #define DISCapabilityRepair 8 #define DISWarheadOther 0 #define DISWarheadHE 1000 #define DISWarheadHEPlastic 1100 #define DISWarheadHEIncendiary 1200 #define DISWarheadHEFragment 1300 #define DISWarheadHEAntiTank 1400 #define DISWarheadHEBomblets 1500 #define DISWarheadHEShapedCharge 1600 #define DISWarheadSmoke 2000 #define DISWarheadIllumination 3000 #define DISWarheadPractice 4000 #define DISWarheadKinetic 5000 #define DISWarheadUnused 6000 #define DISWarheadNuclear 7000 #define DISWarheadChemGeneral 8000 #define DISWarheadChemBlister 8100 #define DISWarheadChemBlood 8200 #define DISWarheadChemNerve 8300 #define DISWarheadBiologicalGeneral 9000 #define DISFuzeOther 0 #define DISFuzeContact 1000 #define DISFuzeContactInstant 1100 #define DISFuzeContactDelayed 1200 #define DISFuzeContactElectronic 1300 #define DISFuzeContactGraze 1400 #define DISFuzeContactCrush 1500 #define DISFuzeContactHydrostatic 1600 #define DISFuzeContactMechanical 1700 #define DISFuzeContactChemical 1800 #define DISFuzeTimed 2000 #define DISFuzeProximity 3000 #define DISFuzeProximityActiveLaser 3100 #define DISFuzeProximityMagnetic 3200 #define DISFuzeProximityRadar 3300 #define DISFuzeProximityRF 3400 #define DISFuzeProximityProgrammable 3500 #define DISFuzeProximityInfrared 3700 #define DISFuzeCommand 4000 #define DISFuzeCommandElectronicRS 4100 #define DISFuzeAltitude 5000 #define DISFuzeAltitudeRadioAltimeter 5100 #define DISFuzeAltitudeRadioAirBurst 5100 #define DISFuzeDepth 6000 #define DISFuzeAcoustic 7000 #define DISFuzePressure 8000 #define DISFuzePyrotechnic 9000 #define DISDetonationResultOther 0 #define DISDetonationResultEntityImpact 1 #define DISDetonationResultEntityProxDetonation 2 #define DISDetonationResultGroundImpact 3 #define DISDetonationResultGroundProxDetonation 4 #define DISDetonationResultDetonation 5 #define DISDetonationResultNone 6 #define DISDetonationResultHESmall 7 #define DISDetonationResultHEMedium 8 #define DISDetonationResultHELarge 9 #define DISDetonationResultAP 10 #define DISDetonationResultDBSmall 11 #define DISDetonationResultDBMedium 12 #define DISDetonationResultDBLarge 13 #define DISDetonationResultAirHit 17 #define DISDetonationResultBuildingHitSmall 18 #define DISDetonationResultBuildingHitMedium 19 #define DISDetonationResultBuildingHitLarge 20 #define DISDetonationResultMineClearingLineCharge 21 #define DISServiceTypeOther 0 #define DISServiceTypeResupply 1 #define DISServiceTypeRepair 2 #define DISRepairTypeNone 0 #define DISRepairTypeAll 1 #define DISRepairResultOther 0 #define DISRepairResultEnded 1 #define DISRepairResultInvalid 2 #define DISRepairResultInterrupted 3 #define DISRepairResultCancelled 4 #define DISAckFlagOther 0 #define DISAckFlagCreateEntity 1 #define DISAckFlagRemoveEntity 2 #define DISAckFlagStartResume 3 #define DISAckFlagStopFreeze 4 #define DISActionOther 0 #define DISActionLocalStorage 1 #define DISActionOutOfAmmunition 2 #define DISActionKIA 3 #define DISActionDamage 4 #define DISActionMobilityDisabled 5 #define DISActionFireDisabled 6 #define DISResponseOther 0 #define DISResponsePending 1 #define DISResponseExecuting 2 #define DISResponsePartiallyComplete 3 #define DISResponseComplete 4 #define DISActivateReasonOther 0 #define DISActivateReasonStart 1 #define DISActivateReasonRestart 2 #define DISActivateReasonEntry 3 #define DISActivateReasonReconstite 4 #define DISActivateResultOther 0 #define DISActivateResultRequestAccepted 1 #define DISActivateResultInvalidParam 2 #define DISActivateResultUnexpectedParam 3 #define DISDeactivateReasonOther 0 #define DISDeactivateReasonEnd 1 #define DISDeactivateReasonWithdrawn 2 #define DISDeactivateReasonDestroyed 3 #define DISDeactivateResultOther 0 #define DISDeactivateResultReqAccepted 1 #define DISDeactivateResultInvalidParam 2 #define DISDeactivateResultUnexpectedReason 3 #define DISDeactivateResultNotActive 4 #define DISFrozenSimulationClock (1<<0) #define DISFrozenTransmitPDUs (1<<1) #define DISFrozenReceivePDUs (1<<2) #define DISInputSourceOther 0 #define DISInputSourcePilot 1 #define DISInputSourceCopilot 2 #define DISInputSourceFirstOfficer 3 #define DISReceiverStateOff 0 #define DISReceiverStateOnNotReceiving 1 #define DISReceiverStateOnReceiving 2 #define DISEmitterFuncUnknown 0 #define DISEmitterFuncLandBasedAirDefense 1 #define DISEmitterFuncBattlefieldAndGroundSurveillance 2 #define DISEmitterFuncNavalSurveillanceAndNavigation 3 #define DISEmitterFuncNavalFireControl 4 #define DISEmitterFuncAirborneSurveillance 5 #define DISEmitterFuncAirborneFireControl 6 #define DISEmitterFuncSpaceborne 7 #define DISEmitterFuncATCInstrumentationAndRanging 8 #define DISEmitterFuncWeather 9 #define DISEmitterFuncMissileGuidance 10 #define DISEmitterFuncJamming 11 #define DISBeamFuncUnknown 0 #define DISBeamFuncSearch 1 #define DISBeamFuncHeightFinder 2 #define DISBeamFuncAcquisition 3 #define DISBeamFuncTracking 4 #define DISBeamFuncAcquisitionAndTracking 5 #define DISBeamFuncCommandGuidance 6 #define DISBeamFuncIlluminator 7 #define DISBeamFuncRangeOnlyRadar 8 #define DISBeamFuncMissileBeacon 9 #define DISBeamFuncMissileFuze 10 #define DISBeamFuncActiveRadarMissileSeeker 11 #define DISBeamFuncJammer 12 #define DISPRITypeUnknown 0 #define DISPRITypeSteady 1 #define DISPRITypeStaggered 2 #define DISPRITypeJitter 3 #define DISPRITypePulseGroup 4 #define DISPRITypeCW 5 #define DISPRITypePulseDoppler 6 #define DISScanTypeUnknown 0 #define DISScanTypeSteady 1 #define DISScanTypeUnidirectional 2 #define DISScanTypeBidirectional 3 #define DISScanTypeConical 4 #define DISScanTypeTwoBar 5 #define DISScanTypeThreeBar 6 #define DISScanTypeFourBar 7 #define DISScanTypeOneBar 8 typedef struct { float x; float y; float z; } dis_float_vector; typedef struct { float x; float y; float z; } dis_angular_vel_vector; typedef struct { float x; float y; float z; } dis_linear_acc_vector; typedef struct { float x; float y; float z; } dis_linear_vel_vector; typedef struct { float x; float y; float z; } dis_entity_coord_vector; /** * DIS entity type. * See also: dis_entityTypeToString(), dis_parseEntityType(). */ typedef struct { unsigned char kind; unsigned char domain; uint16_t country; unsigned char category; unsigned char subcategory; unsigned char specific; unsigned char extra; } dis_entity_type; typedef struct { unsigned char charset; unsigned char marking[11]; } dis_entity_marking; typedef struct { uint32_t datum_id; uint32_t value; } dis_fixed_datum; typedef struct { uint32_t datum_id; uint32_t value_length; union { double double_value; dis_entity_type entity_type_value; unsigned char *ptr_value; } value; } dis_variable_datum; /** * Timestamp associated to the packet. If absolute, the host participating in * the simulation is synchronized with all the other hosts, typically via NTP. * If relative, the host is not synchronized and the other participating hosts * must (should...) take care of this using this value only to perform time * differences with other timestamps coming from that same host. * Note that the time field only carries the lowest 31 bits of the timestamp * measured in units of 3600/2^31 seconds; this value is not monotonic and * returns to 0 after reaching (2^31-1). * * NOTE. Currently src/acm/dis_if.c simply ignores the timestamp from incoming * DIS packets and always assumes our timestamp instead. * * 2017-04-26 XDR routines fail to encode/decode this data as originally defined * with separated time and type fields on 64 bits platform. Fixed declaring a * single field "timexxx"; the highest bit is the absolute time flag. This value * is set by ACM but it is otherwise ignored, only internal clock matters. [U.S.] */ typedef struct { ///** 3600/2^31 = 1.676... usec units. */ //unsigned time:31; ///** Type: 0=relative, 1=absolute. */ //unsigned type:1; uint32_t timexxx; } dis_timestamp; typedef struct { uint16_t site_id; uint16_t application_id; } dis_simulation_addr; typedef struct { uint16_t name; unsigned char function; unsigned char id; } dis_emitter_system; typedef struct { dis_simulation_addr sim_id; uint16_t entity_id; } dis_entity_id; typedef struct { float psi; float theta; float phi; } dis_euler_angles; typedef struct { dis_simulation_addr sim_id; uint16_t event_id; } dis_event_id; typedef struct { float freq; float freq_range; float erp; float prf; float pulse_width; float beam_azimuth_center; float beam_azimuth_sweep; float beam_elev_center; float beam_elev_sweep; float beam_sweep_sync; } dis_fundamental_parameters; typedef struct { uint16_t spread_spectrum; uint16_t major_type; uint16_t detail; uint16_t system; } dis_modulation_type; typedef struct { unsigned char protocol_version; unsigned char exercise_id; unsigned char pdu_type; unsigned char protocol_family; dis_timestamp time_stamp; uint16_t length; uint16_t padding; } dis_pdu_header; typedef struct { double x; double y; double z; } dis_double_vector; typedef struct dis_relative_coordinates { float x; float y; float z; } dis_relative_coordinates; typedef struct { VPoint ant_location; dis_relative_coordinates relative; } dis_antenna_location; typedef struct { dis_euler_angles direction; float azimuth_width; float elev_width; unsigned char reference_system; unsigned char pad[3]; float Ez; float Ex; float phase; } dis_beam_antenna_pattern; typedef struct { unsigned char pattern; float coefficients; unsigned char ref_system; } dis_spherical_harmonic_antenna_pattern; typedef union { double d; float f[2]; char c[8]; uint32_t l[2]; uint16_t s[4]; } dis_parm_value; typedef struct { unsigned char type; unsigned char change; uint16_t attachment_id; uint32_t attached_part; uint32_t articulated_part; dis_parm_value value; } dis_articulation_parm; typedef struct { uint32_t hour; dis_timestamp rel; } dis_time; typedef struct { dis_entity_type munition; uint16_t warhead; uint16_t fuze; uint16_t quantity; uint16_t rate; } dis_burst_descriptor; typedef struct { unsigned char algorithm; unsigned char other[15]; dis_linear_acc_vector linear_acc; dis_angular_vel_vector angular_vel; } dis_dead_reckoning; typedef uint32_t dis_capabilities; typedef struct { dis_entity_type entity; float quantity; } dis_supply_quantity; typedef uint32_t dis_entity_appearance; typedef struct { dis_pdu_header hdr; dis_entity_id id; unsigned char force_id; unsigned char art_parm_count; dis_entity_type type; dis_entity_type alt_type; dis_linear_vel_vector vel; VPoint pos; dis_euler_angles orientation; dis_entity_appearance appearance; dis_dead_reckoning dr_parm; dis_entity_marking marking; dis_capabilities capabilities; dis_articulation_parm *art_parm; } dis_entity_state_pdu; typedef struct { dis_pdu_header hdr; dis_entity_id id; dis_entity_id collision_id; dis_event_id event; dis_linear_vel_vector vel; uint32_t mass; dis_entity_coord_vector loc; } dis_collision_pdu; typedef struct { dis_pdu_header hdr; dis_entity_id firing_id; dis_entity_id target_id; dis_entity_id munition_id; dis_event_id event; uint32_t fire_mission_index; VPoint pos; dis_burst_descriptor burst; dis_linear_vel_vector vel; float range; } dis_fire_pdu; typedef struct { dis_pdu_header hdr; dis_entity_id firing_id; dis_entity_id target_id; dis_entity_id munition_id; dis_event_id event; dis_linear_vel_vector vel; VPoint pos; dis_burst_descriptor burst; dis_entity_coord_vector loc; unsigned char result; unsigned char num_art_parms; uint16_t pad; dis_articulation_parm *art_parm; } dis_detonation_pdu; typedef unsigned char dis_service_type; typedef uint16_t dis_repair_type; typedef unsigned char dis_repair_result; typedef struct { dis_pdu_header hdr; dis_entity_id requestor_id; dis_entity_id server_id; dis_service_type requested_service; unsigned char num_supply_types; uint16_t pad; dis_supply_quantity *supplies; } dis_service_request_pdu; typedef struct { dis_pdu_header hdr; dis_entity_id receiver_id; dis_entity_id supplier_id; unsigned char num_supply_types; unsigned char pad[3]; dis_supply_quantity *supplies; } dis_resupply_offer_pdu; typedef struct { dis_pdu_header hdr; dis_entity_id receiver_id; dis_entity_id supplier_id; unsigned char num_supply_types; unsigned char pad[3]; dis_supply_quantity *supplies; } dis_resupply_received_pdu; typedef struct { dis_pdu_header hdr; dis_entity_id receiver_id; dis_entity_id supplier_id; } dis_resupply_cancel_pdu; typedef struct { dis_pdu_header hdr; dis_entity_id receiver_id; dis_entity_id supplier_id; dis_repair_type repair; uint16_t pad; } dis_repair_complete_pdu; typedef struct { dis_pdu_header hdr; dis_entity_id receiver_id; dis_entity_id supplier_id; dis_repair_result result; unsigned char pad[3]; } dis_repair_response_pdu; typedef uint32_t dis_request_id; typedef struct { dis_pdu_header hdr; dis_entity_id orig_id; dis_entity_id recv_id; dis_request_id request_id; } dis_create_entity_pdu; typedef struct { dis_pdu_header hdr; dis_entity_id orig_id; dis_entity_id recv_id; dis_request_id request_id; } dis_remove_entity_pdu; typedef struct { dis_pdu_header hdr; dis_entity_id orig_id; dis_entity_id recv_id; dis_time real_time; dis_time sim_time; dis_request_id request_id; } dis_start_pdu; typedef struct { dis_pdu_header hdr; dis_entity_id orig_id; dis_entity_id recv_id; dis_time real_time; unsigned char reason; unsigned char behavior; unsigned char pad[2]; dis_request_id request_id; } dis_stop_pdu; typedef struct { dis_pdu_header hdr; dis_entity_id orig_id; dis_entity_id recv_id; uint16_t acknowledge_flag; uint16_t resp_flag; dis_request_id request_id; } dis_acknowledge_pdu; typedef struct { dis_pdu_header hdr; dis_entity_id orig_id; dis_entity_id recv_id; dis_time interval; dis_request_id request_id; uint32_t num_fixed_data; uint32_t num_variable_data; uint32_t *fixed_datum_id; uint32_t *variable_datum_id; } dis_data_query_pdu; typedef struct { uint32_t num_fixed_data; uint32_t num_variable_data; dis_fixed_datum *fixed_datum; dis_variable_datum *variable_datum; } dis_datum_spec_record; typedef struct { dis_pdu_header hdr; dis_entity_id orig_id; dis_entity_id recv_id; dis_request_id request_id; dis_datum_spec_record datum_info; } dis_set_data_pdu; typedef struct { dis_pdu_header hdr; dis_entity_id orig_id; dis_entity_id recv_id; dis_request_id request_id; dis_datum_spec_record datum_info; } dis_data_pdu; typedef struct { dis_pdu_header hdr; dis_entity_id orig_id; dis_entity_id recv_id; dis_event_id event_type; dis_datum_spec_record datum_info; } dis_event_report_pdu; typedef struct { dis_pdu_header hdr; dis_entity_id orig_id; dis_entity_id recv_id; uint32_t num_fixed_data; uint32_t num_variable_data; dis_fixed_datum *fixed_datum; dis_variable_datum *variable_datum; } dis_comment_pdu; typedef struct { dis_entity_id target; unsigned char emitter_id; unsigned char beam_id; } dis_track_info; typedef struct { unsigned char beam_data_length; unsigned char beam_id; uint16_t beam_parm_index; dis_fundamental_parameters fundamental; unsigned char beam_function; unsigned char num_targets; unsigned char high_density_track_jam; unsigned char pad; uint32_t jamming_mode; dis_track_info *tracked_target; } dis_beam_info; typedef struct { unsigned char sys_data_length; unsigned char num_beams; uint16_t pad; dis_emitter_system emitter_system; dis_entity_coord_vector location; dis_beam_info *beam; } dis_em_system_info; typedef struct { dis_pdu_header hdr; dis_entity_id emitter_id; dis_event_id event; unsigned char state_update; unsigned char num_systems; uint16_t pad; dis_em_system_info *system; } dis_em_emission_pdu; typedef struct { dis_pdu_header hdr; dis_entity_id designating_id; uint16_t code_name; dis_entity_id designated_id; unsigned char pad; unsigned char code; float power; float wavelength; dis_entity_coord_vector spot_rel; VPoint spot_pos; } dis_designator_pdu; typedef struct { dis_pdu_header hdr; dis_entity_id requesting_id; dis_entity_id control_target_id; } dis_experimental_request_control_pdu; typedef struct { dis_pdu_header hdr; dis_entity_id granting_id; dis_entity_id control_target_id; } dis_experimental_grant_control_pdu; typedef struct { dis_pdu_header hdr; dis_entity_id orig_id; dis_entity_id recv_id; uint32_t request_id; unsigned char reliability_service; unsigned char transfer_type; dis_entity_id target_id; uint32_t num_record_sets; } dis_transfer_control_pdu; typedef union { dis_pdu_header hdr; dis_entity_state_pdu entity_state; dis_collision_pdu collision; dis_fire_pdu fire; dis_detonation_pdu detonation; dis_create_entity_pdu create_entity; dis_remove_entity_pdu remove_entity; dis_start_pdu start; dis_stop_pdu stop; dis_acknowledge_pdu acknowledge; dis_data_query_pdu data_query; dis_set_data_pdu set_data; dis_data_pdu data; dis_event_report_pdu event_report; dis_comment_pdu message; dis_em_emission_pdu em_emission; dis_designator_pdu designator; dis_transfer_control_pdu transfer_control; dis_experimental_request_control_pdu request_control; dis_experimental_grant_control_pdu grant_control; } dis_pdu; typedef struct { double timeThreshold; /* [ seconds ] */ double locationThreshold; /* [ meters ] */ double orientationThreshold; /* [ radians ] */ double omega; /* angular velocity magnitude */ VMatrix R0; /* orientation based on Euler angles in entity state */ VMatrix skew; VMatrix aat; dis_entity_state_pdu pdu; /* saved entity state PDU */ } dis_dr_parameters; typedef enum { dis_RESULT_OK = 0, dis_RESULT_ERROR = 1, dis_RESULT_NO_MEMORY = 2 } dis_Result; /** * In broadcasting mode, local interface to send packets; * in unicast mode, the destination relay server. */ typedef struct { /** Local interface or relay server. */ struct sockaddr_in addr; /** 0=broadcast; 1=other (unicast?). */ int type; /* 0=broadcast; 1=other */ } dis_DestinationAddress; /** * All destinations of our packets. */ typedef struct { /** Socket. */ int s; dis_DestinationAddress dest[32]; int num_dest; } dis_Transceiver; /** * Parses the force type. * @param s Force type string, one of "Other", "Friendly", "Opposing", "Neutral". * @return Parsed force, or -1 if the string is NULL or invalid. */ EXTERN DISForce dis_parseForce(char *s); /** * Returns the name of the force. * @param force Type of the force. Fatal error if the value is invalid. * @return Pointer to statically allocated string describing the force. */ EXTERN char * dis_forceToString(DISForce force); /** * Compare an incoming DIS entity type against a wildcarded entity type; * returns non-zero value if they match. */ EXTERN int dis_entityWildcardMatch(const dis_entity_type *in, const dis_entity_type *pattern, const dis_entity_type *pattern_mask); /** * Add articulation parameter to the Entity State PDU. */ EXTERN dis_Result dis_addArticulationParm(dis_entity_state_pdu * esp, dis_articulation_parm * parm, int *parmID); EXTERN int dis_setNBIOState(dis_Transceiver *, int); /** * Establishes a connection to the DIS network. It should be called only once by * a user application. There are two modes: relay server and client. In server * mode the port parameter sets the port of the server, the host name parameter * is ignored. In client mode, if a relay server and port are set, sends packets * to that relay server; if no host name is defined, uses broadcasting. * When broadcasting is required on UNIX systems, this function automatically * locates all active broadcast-compatible network interfaces and configures the * DIS library to automatically transmit broadcast PDU’s on each of those * interfaces. * * The socket is created in blocking mode; the disx module will set it to non- * blocking mode. * * See Also: dis_closeTransceiver(). * @param isServer Set to false for client connection, true for relay server. * @param host_name If client, name or network address of the relay server if * available, or NULL or empty to use broadcasting. If server, it is ignored. * @param host_port If client, the UDP port to use in broadcast mode, or the port * of the relay server if available. If server, the UDP port of the server. * @return Pointer to DISTransceiver on success, NULL otherwise (and a message * is sent to stderr). */ EXTERN dis_Transceiver *dis_openTransceiver(int isServer, char *host_name, int host_port); /** * Does nothing if xcvr is NULL. * @param xcvr */ EXTERN void dis_closeTransceiver(dis_Transceiver *xcvr); /** * Returns the next PDU received from the DIS network. Some PDU structures * contain variable length fields (for example, the emitter systems field of an * electromagnetic emission PDU). Space required to hold those variable length * components will be dynamically allocated. Before discarding the PDU, call * dis_freePDUComponents() to release this dynamically allocated storage. * See Also: dis_openTransceiver(), dis_writePDU(), dis_freePDUComponents(). * @param xcvr * @param pdu * @return True if a DIS PDU is available. False if no more packets are * available. Invalid packets are skipped and an error message is logged. */ EXTERN int dis_readPDU(dis_Transceiver *xcvr, dis_pdu *pdu); /** * Broadcasts the specified PDU onto the DIS network. * See Also: dis_openTransceiver(), dis_readPDU(). * @param xcvr * @param pdu * @return True on success. False if either failed encoding the PDU (should * never happen) or failed sending the packet to at least one destination * address. */ EXTERN int dis_writePDU(dis_Transceiver *xcvr, dis_pdu *pdu); /** * Release storage occupied by the variable-length fields of a PDU. Some PDU * structures contain variable length fields (e.g. the emitter systems field of * an electromagnetic emission PDU). Space required to hold those variable length * components is dynamically allocated through during a call to dis_readPDU (or * DISxReadPDU). Before discarding a PDU, call this function to release this * dynamically allocated storage. See Also: disx_readPDU(), dis_readPDU(). * @param pdu DIS PDU whose variable length components have to be released. * Does nothing if NULL. */ EXTERN void dis_freePDUComponents(dis_pdu *pdu); EXTERN void dis_addPDUSizes(dis_pdu *); /** * Returns the current relative time based on the local system’s clock. * See Also: dis_getTimestamp(). * @param result * @return Currently always returns zero. */ EXTERN int dis_getRealTime(dis_time * result); /** * Returns a DIS absolute timestamp based on the local system’s clock. Absolute * timestamps are interpreted by other DIS applications to be based on UTC time. * This normally assumes that the clocks of all systems participating in this * DIS exercise have been somehow synchronized with Coordinated Universal * Time (UTC). * See Also: dis_getRealTime(). * @param result Relative DIS timestamp. * @return Currently always returns zero. */ EXTERN int dis_getTimestamp(dis_timestamp * result); EXTERN void dis_timeToTimeval(dis_time * in, struct timeval *out); EXTERN void dis_timestampToTimeval(dis_timestamp * in, struct timeval *out); /** * Bits for the DR test status mask telling for which reason the state of a * entity needs to be updated and then a new state packet should be send. * The words "too much" that follow should be read "beyond the configured DR * threshold". */ typedef enum { /** Stale entity state: too much time elapsed since last packet sent. */ dis_DR_TIME = 0x01, /** Entity moved too much. */ dis_DR_LOCATION = 0x02, /** Entity rotates too much. */ dis_DR_ORIENTATION = 0x04, } dis_DR_FLAGS; EXTERN void dis_processNewDRParameters(dis_entity_state_pdu * pdu, dis_dr_parameters * dr); EXTERN void dis_generateDRParameters(dis_entity_state_pdu * pdu, dis_dr_parameters * dr); /** * Updates the state of the remote entity using the specified dead reckoning * algorithm. Updates the current state vectors accordingly. * @param dr Dead reckoning parameters. * @param dT Time elapsed since last update (s). * @param pos Last known position. * @param vel Last known velocity. * @param orientation Last known orientation. */ EXTERN void dis_computeDRPosition(dis_dr_parameters * dr, double dT, VPoint * pos, dis_linear_vel_vector * vel, VMatrix * orientation); EXTERN void dis_getDRThresholds(dis_dr_parameters *, double *time, double *location, double *orientation); EXTERN void dis_setDRThresholds(dis_dr_parameters *, double time, double location, double orientation); /** * Updates the DR state and returns a bit mask with the DR test result. * @param dr * @param deltaT * @param current_location * @param current_orientation * @return Result of the test. */ EXTERN dis_DR_FLAGS dis_testDRThresholds(dis_dr_parameters *dr, double deltaT, VPoint *current_location, dis_euler_angles *current_orientation); /** * Generate a DIS entity ID from a string. * C-style hexadecimal numbers may be used in the input stream: * * 1/1/0xfffe, and 0xff/0xff/0x1 are both valid * * Example invalid strings: * * 1/1/1,000 Entity ID field contains an invalid character * 1/1/1000000 Entity ID field > 0xffff * * @param p Resulting parsed entity. * @param buf Buffer to parse -- BEWARE: overwritten! * @param bufsize Length of the buffer, including terminating zero if any. * @param delim List of delimiter characters, typically ".:/". * @return * 0: success, * 1: parse error, * 2: incoming string buffer too large (max is 64 characters), * 3: one or more of the fields contains an invalid value (<0 or >0xffff), * 4: invalid character in string. */ EXTERN int dis_parseEntityID (dis_entity_id *p, char * buf, int bufsize, char *delim); /** * Parse entity type string of the form "9.9.9.9.9.9.9". Each value must be an * integer number in the range [0,255], except country which is [0,65535]. * Ignores leading and trailing white spaces. * @param s String to parse. * @param et Here returns the parsed entity type. * @return True on success. False if the string is NULL or does not contain * a valid entity type. */ EXTERN int dis_parseEntityType(char *s, dis_entity_type *et); /** * Returns the entity type as a string of the form "9.9.9.9.9.9.9". * @param et Subject entity type. * @return Pointer to a statically allocated string buffer with the formatted * entity type. */ EXTERN char * dis_entityTypeToString(dis_entity_type *et); #undef EXTERN #endif acm-6.0_20200416/src/dis/dis/xdr_dis.h0000644000000000000000000000320313106475701015527 0ustar rootroot/* * DIS/x : An implementation of the IEEE 1278.1 protocol * * Copyright (C) 1997, Riley Rainey (rrainey@ix.netcom.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of either: * * a) the GNU Library General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your * option) any later version. A description of the terms and conditions * of the GLPL may be found in the "COPYING.LIB" file. * * b) the "Artistic License" which comes with this Kit. Information * about this license may be found in the "Artistic" file. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License or the Artistic License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Information describing how to contact the author can be found in the * README file. */ /** * Encoding/decoding functions for DIS packets. * * @file */ #ifndef XDR_DIS_H #define XDR_DIS_H #include "xdr.h" #include "dis.h" #ifdef xdr_dis_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Encodes/decodes a DIS PDU packet. * @param xdrs * @param objp * @return True on success. */ EXTERN int xdr_dis_pdu(xdr_Type * xdrs, dis_pdu * objp); #undef EXTERN #endif /* XDR_DIS_H */ acm-6.0_20200416/src/dis/dis/disx.c0000644000000000000000000001147213107615207015042 0ustar rootroot/* * DIS/x : An implementation of the IEEE 1278.1 protocol * * Copyright (C) 1996, Riley Rainey (rainey@netcom.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of either: * * a) the GNU Library General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your * option) any later version. A description of the terms and conditions * of the GLPL may be found in the "COPYING.LIB" file. * * b) the "Artistic License" which comes with this Kit. Information * about this license may be found in the "Artistic" file. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License or the Artistic License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Information describing how to contact the author can be found in the * README file. */ #include #include #include #include "../../util/memory.h" #define disx_IMPORT #include "disx.h" /* * This table defines the correct protocol family based on the pdu type */ static unsigned char pdu_family[256] = { 0, 1, 2, 2, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, /* 0..15 */ 5, 5, 5, 5, 5, 5, 5, 6, 6, 4, 4, 0, 0, 0, 0, 0, /* 16..31 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 32..47 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 48..63 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 64..79 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80..95 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 96..111 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112..127 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128..143 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, /* 144..159 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 160..175 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 176..191 */ }; static int protocol_version = DISProtocolVersionIEEE1278_95; int disx_setProtocolVersion(int version) { int result = protocol_version; protocol_version = version; return result; } disx_ApplicationInfo * disx_initializeApplication(dis_Transceiver *xcvr, int exercise_id, int site_id, int application_id) { disx_ApplicationInfo *p = (disx_ApplicationInfo *) memory_allocate( sizeof(disx_ApplicationInfo), NULL); memset(p, 0, sizeof(*p)); p->hdr.protocol_version = protocol_version; p->hdr.exercise_id = exercise_id; p->hdr.padding = 0; p->last_event = 0; p->last_entity = 0; p->last_request = 0; p->xcvr = xcvr; if (dis_setNBIOState(p->xcvr, 1) != 0) { fprintf(stderr, "Socket rejected non-blocking mode.\n"); dis_closeTransceiver(p->xcvr); memory_dispose(p); return NULL; } p->id.site_id = site_id; p->id.application_id = application_id; return p; } void disx_getSimulationAddress(disx_ApplicationInfo * info, dis_simulation_addr * p) { *p = info->id; } int disx_writePDU(disx_ApplicationInfo * info, dis_pdu * p) { p->hdr.protocol_version = info->hdr.protocol_version; p->hdr.exercise_id = info->hdr.exercise_id; p->hdr.protocol_family = pdu_family[p->hdr.pdu_type]; /* don't set time here until there is a function to set the value (time) and type (relative/absolute) of the time in the DISx library dis_getTimestamp(&p->hdr.time_stamp); */ return dis_writePDU(info->xcvr, p); } int disx_readPDU(disx_ApplicationInfo * info, dis_pdu * p) { return dis_readPDU(info->xcvr, p); } void disx_closeApplication(disx_ApplicationInfo * info) { if( info == NULL ) return; dis_closeTransceiver(info->xcvr); memory_dispose(info); } dis_entity_id * disx_issueEntityID(disx_ApplicationInfo * info, dis_entity_id * e) { e->sim_id = info->id; // Valid range for entity ID is [1,0xfffd]; // zero, 0xfffe and 0xffff are not allowed; // cyclic. info->last_entity++; if (info->last_entity >= 0xfffe) { info->last_entity = 1; } e->entity_id = info->last_entity; return e; } dis_request_id disx_issueRequestID( disx_ApplicationInfo * info ) { // Valid range for request ID: any 32-bits value; // cyclic. return ++info->last_request; } dis_event_id * disx_issueEventID(disx_ApplicationInfo * info, dis_event_id * event) { event->sim_id = info->id; // Valid range for event ID is [1,0xffff]; // zero not allowed; // cyclic. info->last_event++; if (info->last_event == 0 ) { info->last_event = 1; } event->event_id = info->last_event; return event; } void disx_initializeDatumInfo ( dis_datum_spec_record *pd ) { memset (pd, 0, sizeof(dis_datum_spec_record)); } acm-6.0_20200416/src/dis/Makefile0000644000000000000000000000062713074216360014610 0ustar rootrootall: rm -rf doxygen-html find . -mindepth 2 -name Makefile \ | while read m; do make -C $$(dirname $$m) all || exit 1; done clean: rm -rf doxygen-html find . -mindepth 2 -name Makefile \ | while read m; do make -C $$(dirname $$m) clean || exit 1; done rebuild: rm -rf doxygen-html find . -mindepth 2 -name Makefile \ | while read m; do make -C $$(dirname $$m) rebuild || exit 1; done acm-6.0_20200416/src/dis/server/0000755000000000000000000000000013646051406014454 5ustar rootrootacm-6.0_20200416/src/dis/server/dis_relay.c0000644000000000000000000002610713646045024016600 0ustar rootroot/* * DIS/x : An implementation of the IEEE 1278.1 protocol * * Copyright (C) 1996, Riley Rainey (rainey@netcom.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of either: * * a) the GNU Library General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your * option) any later version. A description of the terms and conditions * of the GLPL may be found in the "COPYING.LIB" file. * * b) the "Artistic License" which comes with this Kit. Information * about this license may be found in the "Artistic" file. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License or the Artistic License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Information describing how to contact the author can be found in the * README file. */ /** * DIS relay daemon. * * Currently this program registers as client any host from which it * receives an UDP packet on the given server port. Each packet received from a * client is then re-sent to all the registered clients. Registered clients are * automatically de-registered after they are silent for too much time * (currently 60 s). * The server listens on any available Internet interface. * * Command line options: * * --port PORT Set the UDP port of the relay server, default being 3000. * * --debug Displays several debugging messages, including: new registered * clients; received packets; sent packets; de-registered clients. * * --help | -h Help! * * @file */ #ifdef WINNT // recvmsg() not available under WINNT. #undef HAVE_RECVMSG #include // Under MinGW, add missing prototype of a function provided by libws2_32.a: WINSOCK_API_LINKAGE const char * WSAAPI inet_ntop(int af, const void *src, char *dst, socklen_t size); #else #include #include #include #include #include #define HAVE_RECVMSG // Cope with slightly different field names of msghdr: Solaris and BSD call // them "msg_accessright...", any other system calls them "msg_control...". #undef HAVE_MSG_ACCRIGHTS #define HAVE_MSG_CONTROL #endif #include #include #include #include #include #include #include #include "../../util/memory.h" #include "../../util/error.h" #include "../dis/dis.h" /** * Remove client silent since so much time (s). */ #define STALE_PERIOD 60 typedef struct SwitchClient { struct SwitchClient *prev, *next; struct sockaddr addr; /** Timestamp last received PDU. */ time_t last_got_pdu; } SwitchClient; static SwitchClient *client_list = 0; static void accountErrorOnClient(SwitchClient *sc) { // FIXME: to do: remove unreachable clients after a while } /** * Returns true if the two sockets are equal. * @param a * @param b * @return True if the two sockets are equal. */ static int sockaddrEquals(struct sockaddr *a, struct sockaddr *b) { return a->sa_family == b->sa_family && ( ( (a->sa_family == AF_INET) && (memcmp(a, b, sizeof(struct sockaddr_in)) == 0) ) || ( (a->sa_family == AF_INET6) && (memcmp(a, b, sizeof(struct sockaddr_in6)) == 0) /* ) || ( (a->sa_family == AF_UNIX) && (strcmp(((struct sockaddr_un *) a)->sun_path, ((struct sockaddr_un *) b)->sun_path) == 0) */ ) ); } /** * Returns the socket address as a human readable string. * @author W. Richard Stevens, UNIX Network Programming vol. 1, par. 3.8. * @param sa * @return */ static char * sockaddrToString(const struct sockaddr *sa) { char portstr[7]; static char str[128]; /* Unix domain is largest */ switch (sa->sa_family) { case AF_INET: { struct sockaddr_in *sin = (struct sockaddr_in *) sa; if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str)) == NULL) return(NULL); if (ntohs(sin->sin_port) != 0) { snprintf(portstr, sizeof(portstr), ":%d", ntohs(sin->sin_port)); strcat(str, portstr); } return str; } case AF_INET6: { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa; if (inet_ntop(AF_INET6, &sin6->sin6_addr, str, sizeof(str)) == NULL) return(NULL); if (ntohs(sin6->sin6_port) != 0) { snprintf(portstr, sizeof(portstr), ":%d", ntohs(sin6->sin6_port)); strcat(str, portstr); } return str; } /* case AF_UNIX: { struct sockaddr_un *unp = (struct sockaddr_un *) sa; / * OK to have no pathname bound to the socket: happens on every connect() unless client calls bind() first. * / if (unp->sun_path[0] == 0) strcpy(str, "(no pathname bound)"); else snprintf(str, sizeof(str), "%s", unp->sun_path); return str; } */ #ifdef HAVE_SOCKADDR_DL_STRUCT case AF_LINK: { struct sockaddr_dl *sdl = (struct sockaddr_dl *) sa; if (sdl->sdl_nlen > 0) snprintf(str, sizeof(str), "%*s", sdl->sdl_nlen, &sdl->sdl_data[0]); else snprintf(str, sizeof(str), "AF_LINK, index=%d", sdl->sdl_index); return str; } #endif default: snprintf(str, sizeof(str), "sock_ntop: unknown AF_xxx: %d", sa->sa_family); return str; } } #ifdef WINNT static char *errorCodeToString(int code) { static char s[999]; char win_err_descr[900]; DWORD err = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM, NULL, code, LANG_SYSTEM_DEFAULT, win_err_descr, sizeof(win_err_descr), NULL ); if( err > 0 ){ snprintf(s, sizeof(s), "%s (Windows error code %d)", win_err_descr, code); } else { snprintf(s, sizeof(s), "error code %d (description not available: FormatMessageA() failed with code %lu)", code, err); } return s; } #endif /** * Reads next PDU. * @param xcvr * @param pdu_content * @param pdu_max_len * @param pdu_from * @return Length of the read PDU, or zero on error. */ static int ReadPDUFrame(dis_Transceiver * xcvr, char *pdu_content, int pdu_max_len, struct sockaddr *pdu_from) { int size; #ifdef HAVE_RECVMSG struct msghdr msg; struct iovec vec; #endif #ifdef HAVE_RECVMSG msg.msg_name = (caddr_t) pdu_from; msg.msg_namelen = sizeof(struct sockaddr); msg.msg_iov = &vec; msg.msg_iovlen = 1; #ifdef HAVE_MSG_CONTROL msg.msg_control = (caddr_t) NULL; msg.msg_controllen = 0; #endif #ifdef HAVE_MSG_ACCRIGHTS msg.msg_accrights = (caddr_t) NULL; msg.msg_accrightslen = 0; #endif vec.iov_base = (caddr_t) pdu_content; vec.iov_len = pdu_max_len; size = recvmsg(xcvr->s, &msg, 0); if( size < 0 ){ if( errno != EAGAIN ) printf("failed reading socket: %s (%d)\n", strerror(errno), errno); size = 0; } #else /* WINNT assumed */ int pdu_from_len = sizeof(*pdu_from); size = recvfrom(xcvr->s, pdu_content, pdu_max_len, 0, pdu_from, &pdu_from_len); if( size < 0 ){ printf("recvfrom(): %s\n", errorCodeToString( WSAGetLastError() ) ); size = 0; } #endif return size; } static int WritePDU(dis_Transceiver * xcvr, char *buffer, int length, struct sockaddr *to) { #ifdef HAVE_RECVMSG struct msghdr msg; struct iovec vec; msg.msg_namelen = sizeof(struct sockaddr); msg.msg_iov = &vec; msg.msg_iovlen = 1; #ifdef HAVE_MSG_CONTROL msg.msg_control = (caddr_t) NULL; msg.msg_controllen = 0; #endif #ifdef HAVE_MSG_ACCRIGHTS msg.msg_accrights = (caddr_t) NULL; msg.msg_accrightslen = 0; #endif vec.iov_base = buffer; vec.iov_len = length; msg.msg_name = (caddr_t) to; if (sendmsg(xcvr->s, &msg, 0) == -1) { fprintf(stderr, "%s: relaying PDU to %s: %s\n", error_prog_name, sockaddrToString(to), strerror(errno)); return 0; } else { return 1; } #else if (sendto(xcvr->s, buffer, length, 0, to, sizeof(struct sockaddr)) == -1) { #ifdef WINNT fprintf(stderr, "sendto(): %s\n", errorCodeToString(WSAGetLastError())); #else perror("sendto()"); #endif return 0; } else { return 1; } #endif } /** * Sends the packet received from a client to all the other registered clients. * If the sender is not already registered, it is added to the list. * Also checks for stale silent clients and removes them from the list. * @param xcvr * @param pdu_content The packet. * @param pdu_len Length of the packet. * @param pdu_from Sender of the packet. */ static void RelayPDUFrame(dis_Transceiver * xcvr, char *pdu_content, int pdu_len, struct sockaddr *pdu_from) { SwitchClient *c, *new, *stale; int found = 0; time_t now; now = time(NULL); c = client_list; while(c != NULL){ if( sockaddrEquals(pdu_from, &c->addr) ){ /* Found sender in registered clients. Renew stale period. */ found = 1; c->last_got_pdu = now; c = c->next; } else if( now - c->last_got_pdu > STALE_PERIOD ){ /* Remove stale client from registered clients. */ stale = c; if( debug ) printf("%s: removing stale client %s\n", error_prog_name, sockaddrToString(&stale->addr)); if( stale->prev == NULL ) client_list = stale->next; else stale->prev->next = stale->next; if( stale->next != NULL ) stale->next->prev = stale->prev; c = stale->next; memory_dispose(stale); } else { /* Relay frame to client. */ if( debug ) printf("%s: relaying frame to %s\n", error_prog_name, sockaddrToString(&c->addr)); if( ! WritePDU(xcvr, pdu_content, pdu_len, &c->addr) ) accountErrorOnClient(c); c = c->next; } } if ( ! found ) { if( debug ) printf("%s: adding client %s\n", error_prog_name, sockaddrToString(pdu_from)); new = memory_allocate(sizeof(SwitchClient), NULL); new->prev = NULL; new->next = client_list; if( new->next != NULL ) new->next->prev = new; memcpy(&new->addr, pdu_from, sizeof(struct sockaddr)); new->last_got_pdu = time(NULL); client_list = new; } } int main(int argc, char **argv) { int i, port; dis_Transceiver *xcvr; struct sockaddr pdu_from; int pdu_len; char pdu_content[2048]; error_prog_name = argv[0]; /* Set default values: */ port = 3000; for(i = 1; i < argc; i++){ if( strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0){ printf("Allowed options:\n"); printf(" --port N Use port number N (default: 3000)\n"); printf(" --debug Displays several debugging messages.\n"); printf(" --help|-h This help.\n"); exit(0); } else if( strcmp(argv[i], "--debug") == 0 ){ debug = 1; } else if( strcmp(argv[i], "--port") == 0 && i+1 < argc ){ port = atoi(argv[++i]); } else { error_external("unknown option: %s. Try --help for help.", argv[i]); } } xcvr = dis_openTransceiver(1, NULL, port); if( xcvr == NULL ) error_external("failed establishing a connection to the DIS network"); if( debug ) printf("%s: running on port %d ...\n", argv[0], port); while (1) { pdu_len = ReadPDUFrame(xcvr, pdu_content, sizeof(pdu_content), &pdu_from); if( debug && pdu_len > 0 ) printf("%s: got PDU size %d from %s\n", error_prog_name, pdu_len, sockaddrToString(&pdu_from)); if (pdu_len > 0) { RelayPDUFrame(xcvr, pdu_content, pdu_len, &pdu_from); } } } acm-6.0_20200416/src/dis/server/Makefile0000644000000000000000000000175613131102153016106 0ustar rootroot# This file generated by make-makefile, do not edit! # Create Makefile-include.txt instead for your customizations. CC := gcc CFLAGS := -Wall -Werror -g -fmax-errors=99 -Wuninitialized -Wmissing-prototypes -Wredundant-decls LIBS := .PHONY: all all: make dis_relay.exe include Makefile-include.txt .PHONY: test test: dis_relay.exe ./dis_relay.exe .PHONY: clean clean: rm -f *.o *.exe *.stackdump dis_relay dis_relay.o: dis_relay.c ../../V/Vlibmath.h ../../util/error.h ../../util/memory.h ../dis/dis.h ../dis/earth.h $(CC) $(CFLAGS) -c dis_relay.c -o dis_relay.o dis_relay.exe: ../../V/Vlibmath.o ../../util/error.o ../../util/memory.o ../../util/units.o ../dis/datum.o ../dis/dis.o ../dis/earth.o ../dis/xdr.o ../dis/xdr_dis.o dis_relay.o $(CC) $(CFLAGS) -o dis_relay.exe ../../V/Vlibmath.o ../../util/error.o ../../util/memory.o ../../util/units.o ../dis/datum.o ../dis/dis.o ../dis/earth.o ../dis/xdr.o ../dis/xdr_dis.o dis_relay.o $(LIBS) -lm # Checksum of the original file: 2783985363 acm-6.0_20200416/src/dis/server/Makefile-include.txt0000644000000000000000000000037513131102165020344 0ustar rootroot# OS specific compilation options: ifeq ($(OS),Windows_NT) CC = c:/mingw/bin/gcc CFLAGS += -mconsole -mwindows LIBS += -lws2_32 else UNAME_S := $(shell uname -s) ifeq ($(UNAME_S),Linux) CFLAGS += LIBS += else CFLAGS += LIBS += endif endifacm-6.0_20200416/src/dis/COPYING.LIB0000644000000000000000000006126110357223037014611 0ustar rootroot GNU LIBRARY GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the library GPL. It is numbered 2 because it goes with version 2 of the ordinary GPL.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Library General Public License, applies to some specially designated Free Software Foundation software, and to any other libraries whose authors decide to use it. You can use it for your libraries, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library, or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link a program with the library, you must provide complete object files to the recipients so that they can relink them with the library, after making changes to the library and recompiling it. And you must show them these terms so they know their rights. Our method of protecting your rights has two steps: (1) copyright the library, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the library. Also, for each distributor's protection, we want to make certain that everyone understands that there is no warranty for this free library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that companies distributing free software will individually obtain patent licenses, thus in effect transforming the program into proprietary software. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License, which was designed for utility programs. This license, the GNU Library General Public License, applies to certain designated libraries. This license is quite different from the ordinary one; be sure to read it in full, and don't assume that anything in it is the same as in the ordinary license. The reason we have a separate public license for some libraries is that they blur the distinction we usually make between modifying or adding to a program and simply using it. Linking a program with a library, without changing the library, is in some sense simply using the library, and is analogous to running a utility program or application program. However, in a textual and legal sense, the linked executable is a combined work, a derivative of the original library, and the ordinary General Public License treats it as such. Because of this blurred distinction, using the ordinary General Public License for libraries did not effectively promote software sharing, because most developers did not use the libraries. We concluded that weaker conditions might promote sharing better. However, unrestricted linking of non-free programs would deprive the users of those programs of all benefit from the free status of the libraries themselves. This Library General Public License is intended to permit developers of non-free programs to use free libraries, while preserving your freedom as a user of such programs to change the free libraries that are incorporated in them. (We have not seen how to achieve this as regards changes in header files, but we have achieved it as regards changes in the actual functions of the Library.) The hope is that this will lead to faster development of free libraries. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, while the latter only works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. c) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. d) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Library General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! acm-6.0_20200416/src/dis/README0000644000000000000000000000070613106475701014030 0ustar rootrootDIS Library, version 1.0 Copyright (C) 1996, Riley Rainey (rainey@netcom.com) COPYING and USE Use and distribution of this software is governed by your choice of one of two licensing schemes: the GNU Library Public License or the "Artistic" license. See the COPYING.LIB and Artistic files for more information. The XDR module contains software copyrighted by Sun Microsystems, Inc.; please read the respective source for full copying conditions. acm-6.0_20200416/src/dis/test/0000755000000000000000000000000013646051406014125 5ustar rootrootacm-6.0_20200416/src/dis/test/disscope.c0000644000000000000000000002065113154073366016111 0ustar rootroot/* * DIS/x : An implementation of the IEEE 1278.1 protocol * * Copyright (C) 1996, Riley Rainey (rainey@netcom.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of either: * * a) the GNU Library General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your * option) any later version. A description of the terms and conditions * of the GLPL may be found in the "COPYING.LIB" file. * * b) the "Artistic License" which comes with this Kit. Information * about this license may be found in the "Artistic" file. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License or the Artistic License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Information describing how to contact the author can be found in the * README file. */ /** * Test program that continously displays all the incoming DIS packets. * Currently operates only in broadcast mode on the UDP port 3000. * * @file */ #include "../dis/dis.h" #ifdef _DEBUG #include #endif #ifndef WINNT #include #endif #include static void PrintEntityID (dis_entity_id *p) { printf ("%d.%d.%d", p->sim_id.site_id, p->sim_id.application_id, p->entity_id); } static void PrintEmitterSystem (dis_em_system_info *p) { dis_emitter_system *p1 = &p->emitter_system; char *s; int i; switch (p1->function) { case DISEmitterFuncUnknown: s = "Unknown"; break; case DISEmitterFuncLandBasedAirDefense: s = "Land Based Air Defense"; break; case DISEmitterFuncBattlefieldAndGroundSurveillance: s = "Battlefield And Ground Surveillance"; break; case DISEmitterFuncNavalSurveillanceAndNavigation: s = "Naval Surveillance And Navigation"; break; case DISEmitterFuncNavalFireControl: s = "Naval Fire Control"; break; case DISEmitterFuncAirborneSurveillance: s = "Airborne Surveillance"; break; case DISEmitterFuncAirborneFireControl: s = "Airborne Fire Control"; break; case DISEmitterFuncSpaceborne: s = "Spaceborne"; break; case DISEmitterFuncATCInstrumentationAndRanging: s = "ATC Instrumentation And Ranging"; break; case DISEmitterFuncWeather: s = "Weather"; break; case DISEmitterFuncMissileGuidance: s = "Missile Guidance"; break; case DISEmitterFuncJamming: s = "Jamming"; break; default: s = "Unknown*"; break; } printf (" %s (%d, %d) (system data length = %d)\n", s, p1->name, p1->id, p->sys_data_length); for (i=0; inum_beams; ++i) { printf (" beam %d: length %d; targets %d\n", p->beam[i].beam_id, p->beam[i].beam_data_length, p->beam[i].num_targets); } } static char * PDUName (dis_pdu *pdu) { char *s = "*Unknown*"; switch (pdu->hdr.pdu_type) { case PDUTypeOther: s = "Other"; break; case PDUTypeEntityState: s = "Entity State"; break; case PDUTypeFire: s = "Fire"; break; case PDUTypeDetonation: s = "Detonation"; break; case PDUTypeCollision: s = "Collision"; break; case PDUTypeServiceRequest: s = "Service Request"; break; case PDUTypeResupplyOffer: s = "Resupply Offer"; break; case PDUTypeResupplyReceived: s = "Resupply Received"; break; case PDUTypeResupplyCancel: s = "Resupply Cancel"; break; case PDUTypeRepairComplete: s = "Repair Complete"; break; case PDUTypeRepairResponse: s = "Repair Response"; break; case PDUTypeCreateEntity: s = "Create Entity"; break; case PDUTypeRemoveEntity: s = "Remove Entity"; break; case PDUTypeStartResume: s = "Start/Resume"; break; case PDUTypeStopFreeze: s = "Stop/Freeze"; break; case PDUTypeAcknowledge: s = "Acknowledge"; break; case PDUTypeActionRequest: s = "Action Request"; break; case PDUTypeActionResponse: s = "Action Response"; break; case PDUTypeDataQuery: s = "Data Query"; break; case PDUTypeSetData: s = "Set Data"; break; case PDUTypeData: s = "Data"; break; case PDUTypeEventReport: s = "Event Report"; break; case PDUTypeComment: s = "Message"; break; case PDUTypeEmission: s = "EM Emission"; break; case PDUTypeDesignator: s = "Designator"; break; case PDUTypeTransmitter: s = "Transmitter"; break; case PDUTypeSignal: s = "Signal"; break; case PDUTypeReceiver: s = "Receiver"; break; case PDUTypeTransferControl: s = "Transfer Control"; break; } return s; } int main(int argc, char **argv) { dis_Transceiver *xcvr; dis_pdu pdu; struct timeval tm; int i, count; #ifdef WINNT WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD(1, 1); err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { fprintf (stderr, "Windows Sockets initialization failed.\n"); exit (2); } #endif xcvr = dis_openTransceiver(0, NULL, 3000); printf ("%d broadcast interface(s) detected\n", xcvr->num_dest); count = 0; while (1) { if( ! dis_readPDU (xcvr, &pdu) ) continue; printf ("\npacket; type %d -- \"%s\" (%d bytes)\n", pdu.hdr.pdu_type, PDUName(&pdu), pdu.hdr.length); printf (" Version %d\n", pdu.hdr.protocol_version); printf (" Family %d\n", pdu.hdr.protocol_family); printf (" Exercise id %d\n", pdu.hdr.exercise_id); dis_timestampToTimeval (&pdu.hdr.time_stamp, &tm); printf (" Time stamp %ld.%ld\n", tm.tv_sec, tm.tv_usec / 1000); switch (pdu.hdr.pdu_type) { case PDUTypeEntityState: printf (" Entity (sim.app.eid) : %d/%d/%d\n", pdu.entity_state.id.sim_id.site_id, pdu.entity_state.id.sim_id.application_id, pdu.entity_state.id.entity_id); printf (" Entity type: %s\n", dis_entityTypeToString(&pdu.entity_state.type)); printf (" Geocentric Position (meters) : %.1f, %.1f, %.1f\n", pdu.entity_state.pos.x, pdu.entity_state.pos.y, pdu.entity_state.pos.z); printf (" Geocentric Velocity (meters/sec) : %.1f, %.1f, %.1f\n", pdu.entity_state.vel.x, pdu.entity_state.vel.y, pdu.entity_state.vel.z); printf (" Articulation parameters: %d\n", pdu.entity_state.art_parm_count); printf ("\n"); break; case PDUTypeDetonation: printf (" Firing Entity (sim.app.eid) : "); PrintEntityID (&pdu.detonation.firing_id); printf ("\n Target Entity (sim.app.eid) : "); PrintEntityID (&pdu.detonation.target_id); printf ("\n Munition Entity (sim.app.eid) : "); PrintEntityID (&pdu.detonation.munition_id); printf ("\n\n"); break; case PDUTypeEmission: printf (" Emitting Entity (sim.app.eid) : "); PrintEntityID (&pdu.em_emission.emitter_id); printf ("\n State Update Indicator : %d", pdu.em_emission.state_update); printf ("\n Number of Systems : %d\n", pdu.em_emission.num_systems); for (i=0; i #include #include #include #include #include #include #include "../../util/error.h" /* * GNU C library includes getopt_long() */ #ifdef __GNU_LIBRARY__ #include #endif #include "../../V/Vlibmath.h" #include "../dis/dis.h" #include "../dis/disx.h" #include "../../util/units.h" #include "../../util/timer.h" #define FEETtoMETERS(x) ((x) * 0.3048) #ifdef __GNU_LIBRARY__ /* * long command line options */ static struct option long_options[] = { { "help", 0, 0, 'h' }, { "relay", 1, 0, 'R' }, { "port", 1, 0, 'P' }, { "force-id", 1, 0, 'f' }, { "appl-id", 1, 0, 'a' }, { "site-id", 1, 0, 's' }, { "entity-id", 1, 0, 'e' }, { "exercise-id", 1, 0, 'E' }, { "latitude", 1, 0, 'l' }, { "longitude", 1, 0, 'L' }, { "altitude", 1, 0, 'A' }, { "type", 1, 0, 't' }, }; #endif static void help() { printf( "Test DIS client application that generates a SA-13 SAM launcher entity and\n" "keeps sending DIS state packets until interrupted.\n" "\n" "Options:\n" " -R host Name of the relay host. Empty for broadcasting (default).\n" " -P port UDP port for broadcasting or UDP port of the relay (0-65535,\n" " default 3000).\n" " -f force Force: 0=other, 1=friendly (defaut), 2=opposing, 3=neutral.\n" " -a appl Application ID (0-65535, default 1).\n" " -s site Site ID (0-65535, default 1).\n" " -e entity Entity ID (0-65535, default 1).\n" " -E exercise Exercise ID (0-65535, default 1).\n" " -l lat Latitude ([-90.0,+90.0] DEG, default 0.0 DEG).\n" " -L lon Longitude ([-180.0,+180.0] DEG, default 0.0 DEG).\n" " -A alt Altitude (feet, default 0.0).\n" " -t type entity type of the form \"9.9.9.9.9.9.9\" (default\n" " \"1.1.222.4.21.1\" the SA-13 SAM.\n" " -h This help.\n" "\n" "Example:\n" "\n" " $ ./decoy -R 192.168.1.33 -a 123 -l 32.87 -L -96.85 -A 2000\n" "\n" "generates a SA-13 SAM launcher floating at 2000 ft over the Love Field airport,\n" "using the specified host as a relay.\n" ); } /** * Generate a transform matrix to get from geocentric to local NED coordinates */ static void GenerateWorldToLocalMatrix(earth_LatLonAlt * w, VMatrix * m) { VPoint gc; VPoint p; VIdentMatrix(m); VRotate(m, ZRotation, -w->longitude); VRotate(m, YRotation, w->latitude); VRotate(m, YRotation, units_DEGtoRAD(90.0)); earth_LatLonAltToXYZ(w, &gc); VTransform(&gc, m, &p); m->m[0][3] = -p.x; m->m[1][3] = -p.y; m->m[2][3] = -p.z; } /** * Convert a double in UNIX format (seconds since 1970) to a DIS timestamp. * If reference is 0, the time will be marked relative. * If reference is 1, the time will be marked absolute, i.e. true UTC time. */ static dis_timestamp TimeDoubleToDIS(double time, int reference) { return (dis_timestamp) {0}; // NOT IMPLEMENTED - dis_if ignores DIS timestamps anyway #ifdef NOT_IMPLEMENTED unsigned long tmp; dis_timestamp res; tmp = (unsigned long) (fmod(time, 3600.0)); if (tmp > 2147483647L) /* 2^31 - 1 */ res.time = 2147483647L; else res.time = tmp; res.type = reference; return res; #endif } static void transpose(VMatrix * m, VMatrix * r) { int i, j; for (i = 0; i < 4; ++i) for (j = 0; j < 4; ++j) r->m[i][j] = m->m[j][i]; } int main(int argc, char **argv) { char *relay = NULL; int port = 3000; dis_Transceiver *xcvr; struct timeval curtime; int c; double unix_time_sec; #ifdef __GNU_LIBRARY__ int option_index = 0; #endif VMatrix XYZtoNED, NEDtoXYZ, trihedral, ABCtoXYZ; double orientation[3]; VPoint velocity = { 0, 0, 0 }; dis_pdu estate, em; dis_entity_state_pdu *esPDU; disx_ApplicationInfo * app; earth_LatLonAlt pos; error_prog_name = argv[0]; memset (&orientation, 0, sizeof(orientation)); memset (&estate, 0, sizeof(dis_pdu)); memset (&em, 0, sizeof(dis_pdu)); memset (&pos, 0, sizeof(pos)); /* * Fill out PDUs */ esPDU = (dis_entity_state_pdu *) &estate; esPDU->id.sim_id.site_id = 1; esPDU->id.sim_id.application_id = 1; esPDU->id.entity_id = 1; esPDU->force_id = 1; esPDU->hdr.protocol_version = DISProtocolVersionIEEE1278_95; esPDU->hdr.exercise_id = 1; esPDU->hdr.pdu_type = PDUTypeEntityState; esPDU->hdr.protocol_family = 1; // must match the PDU type above esPDU->hdr.time_stamp = (dis_timestamp) {0}; // will set later esPDU->hdr.length = 0; esPDU->hdr.padding = 0; /* * SA-13 SAM launcher */ esPDU->type.kind = 1; esPDU->type.domain = 1; esPDU->type.country = 222; esPDU->type.category = 4; esPDU->type.subcategory = 21; esPDU->type.specific = 1; /* * process command line arguments */ while (1) { #ifdef __GNU_LIBRARY__ c = getopt_long ( argc, argv, "hR:P:f:a:s:e:E:l:L:A:t:", long_options, &option_index ); #else c = getopt ( argc, argv, "hR:P:f:a:s:e:E:l:L:A:t:" ); #endif if (c == -1) { break; } switch (c) { case 'h': help(); return 0; case 'R': relay = strdup(optarg); break; case 'P': port = atoi(optarg); break; case 'f': estate.entity_state.force_id = atoi(optarg); break; case 'a': estate.entity_state.id.sim_id.application_id = atoi(optarg); break; case 's': estate.entity_state.id.sim_id.site_id = atoi(optarg); break; case 'e': estate.entity_state.id.entity_id = atoi(optarg); break; case 'E': esPDU->hdr.exercise_id = atoi(optarg); break; case 'l': pos.latitude = units_DEGtoRAD(atof(optarg)); break; case 'L': pos.longitude = units_DEGtoRAD(atof(optarg)); break; case 'A': pos.z = FEETtoMETERS(atof(optarg)); break; case 't': if( ! dis_parseEntityType(optarg, &esPDU->type) ){ fprintf(stderr, "invalid entity type specification: %s\n", optarg); return 1; } break; default: fprintf(stderr, "unknown option %c -- try -h for help\n", c); return 1; } } xcvr = dis_openTransceiver(0, relay, port); if( xcvr == NULL ) error_external("failed opening socket"); app = disx_initializeApplication(xcvr, 1, estate.entity_state.id.sim_id.site_id, estate.entity_state.id.sim_id.application_id ); if( app == NULL ) error_internal("failed configuring disx", 0); /* * loop until interrupted ... */ double psi = 0.0; while (1) { gettimeofday( &curtime, NULL ); unix_time_sec = (double) curtime.tv_sec + (double) curtime.tv_usec / 1000000.0; esPDU->hdr.time_stamp = TimeDoubleToDIS( unix_time_sec, 1 ); /* esPDU->id already set */ //esPDU->force_id = DISForceOpposing; esPDU->art_parm_count = 0; earth_LatLonAltToXYZ( &pos, &esPDU->pos ); psi += units_DEGtoRAD(5); VEulerToMatrix(0.0, 0.0, psi, &trihedral); GenerateWorldToLocalMatrix ( &pos, &XYZtoNED ); /* * Derive ECI [Geocentric] heading, pitch, roll */ transpose(&XYZtoNED, &NEDtoXYZ); /* the trihedral is an "ABCtoNED" transformation */ VMatrixMultByRank(&trihedral, &NEDtoXYZ, &ABCtoXYZ, 3); VMatrixToEuler(&ABCtoXYZ, &orientation[0], &orientation[1], &orientation[2]); esPDU->orientation.phi = orientation[0]; esPDU->orientation.theta = orientation[1]; esPDU->orientation.psi = orientation[2]; esPDU->vel.x = velocity.x; esPDU->vel.y = velocity.y; esPDU->vel.z = velocity.z; esPDU->appearance = ( DISAppearancePaintUniform | DISAppearanceFirepowerNormal | DISAppearanceHatchClosed | DISAppearanceLandLauncherRaised ); esPDU->dr_parm.algorithm = DISDRMethodRVW; esPDU->dr_parm.linear_acc.x = 0.0f; esPDU->dr_parm.linear_acc.y = 0.0f; esPDU->dr_parm.linear_acc.z = 0.0f; esPDU->dr_parm.angular_vel.x = 0.0f; esPDU->dr_parm.angular_vel.y = 0.0f; esPDU->dr_parm.angular_vel.z = 0.0f; esPDU->marking.charset = DISCharSetASCII; memset(esPDU->marking.marking, 0, sizeof(esPDU->marking.marking)); strncpy((char *) esPDU->marking.marking, "HI THERE", sizeof(esPDU->marking.marking)); esPDU->capabilities = 0; esPDU->art_parm = NULL; if ( ! disx_writePDU(app, (dis_pdu *) esPDU) ) { printf ( "error writing PDU\n" ); } else { printf ( "." ); fflush ( stdout ); } timer_sleepMilliseconds(2000); } } acm-6.0_20200416/src/dis/test/Makefile0000644000000000000000000000310613646045024015564 0ustar rootroot# This file generated by make-makefile, do not edit! # Create Makefile-include.txt instead for your customizations. CC := gcc CFLAGS := -Wall -Werror -g -fmax-errors=99 -Wuninitialized -Wmissing-prototypes -Wredundant-decls LIBS := .PHONY: all all: make decoy.exe disscope.exe include Makefile-include.txt .PHONY: test test: decoy.exe disscope.exe ./decoy.exe ./disscope.exe .PHONY: clean clean: rm -f *.o *.exe *.stackdump decoy disscope decoy.o: decoy.c ../../V/Vlibmath.h ../../util/error.h ../../util/timer.h ../../util/units.h ../dis/dis.h ../dis/disx.h ../dis/earth.h $(CC) $(CFLAGS) -c decoy.c -o decoy.o decoy.exe: ../../V/Vlibmath.o ../../util/error.o ../../util/memory.o ../../util/timer.o ../../util/units.o ../dis/datum.o ../dis/dis.o ../dis/disx.o ../dis/earth.o ../dis/xdr.o ../dis/xdr_dis.o decoy.o $(CC) $(CFLAGS) -o decoy.exe ../../V/Vlibmath.o ../../util/error.o ../../util/memory.o ../../util/timer.o ../../util/units.o ../dis/datum.o ../dis/dis.o ../dis/disx.o ../dis/earth.o ../dis/xdr.o ../dis/xdr_dis.o decoy.o $(LIBS) -lm disscope.o: disscope.c ../../V/Vlibmath.h ../dis/dis.h ../dis/earth.h $(CC) $(CFLAGS) -c disscope.c -o disscope.o disscope.exe: ../../V/Vlibmath.o ../../util/error.o ../../util/memory.o ../../util/units.o ../dis/datum.o ../dis/dis.o ../dis/earth.o ../dis/xdr.o ../dis/xdr_dis.o disscope.o $(CC) $(CFLAGS) -o disscope.exe ../../V/Vlibmath.o ../../util/error.o ../../util/memory.o ../../util/units.o ../dis/datum.o ../dis/dis.o ../dis/earth.o ../dis/xdr.o ../dis/xdr_dis.o disscope.o $(LIBS) -lm # Checksum of the original file: 770107327 acm-6.0_20200416/src/dis/test/Makefile-include.txt0000644000000000000000000000064713646045024020032 0ustar rootroot# OS specific compilation options: ifeq ($(OS),Windows_NT) CC = c:/mingw/bin/gcc LIBS += -lws2_32 else UNAME_S := $(shell uname -s) ifeq ($(UNAME_S),Linux) CFLAGS += LIBS += else CFLAGS += LIBS += endif endif .PHONY: rebuild rebuild: clean find . -mindepth 1 -type d \ | while read d; do \ if [ -f $$d/Makefile ]; then \ echo "$$d"; \ (cd $$d; check-included && make-makefile); \ fi \ done makeacm-6.0_20200416/src/dis/Artistic0000644000000000000000000001137510357223037014657 0ustar rootroot The "Artistic License" Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder as specified below. "Copyright Holder" is whoever is named in the copyright or copyrights for the package. "You" is you, if you're thinking about copying or distributing this Package. "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as uunet.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) give non-standard executables non-standard names, and clearly document the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. 6. Aggregation of this Package with a commercial distribution is always permitted provided that the use of this Package is embedded; that is, when no overt attempt is made to make this Package's interfaces visible to the end user of the commercial distribution. Such use shall not be construed as a distribution of this Package. 7. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 8. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End Note: this "Artistic" license is based on the Artistic license distributed with Perl by Larry Wall. acm-6.0_20200416/src/dis/COPYING0000644000000000000000000004307610357223037014210 0ustar rootroot GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. acm-6.0_20200416/src/V/0000755000000000000000000000000013646051406012574 5ustar rootrootacm-6.0_20200416/src/V/VGlyph.c0000644000000000000000000000003013063667560014151 0ustar rootroot/* Only declarations. */acm-6.0_20200416/src/V/VObjects.h0000644000000000000000000000270313140076407014463 0ustar rootroot#ifndef _VOBJECTS_H #define _VOBJECTS_H #include "VPoly.h" #ifdef VObjects_IMPORT #define EXTERN #else #define EXTERN extern #endif typedef struct { char *name; /* object name */ VPoint xaxis, yaxis, zaxis; VPoint center; /* average of all the object's points */ double extent; /* distance from center to most distant point */ int numPolys; /* polygon count */ VPolygon **polygon; /* pointer to array of polygon pointers */ unsigned short *order; /* 3-D relative polygon depth ordering */ } VObject; EXTERN int VComputeObjectAspect (VObject * obj, VPoint * loc); /** * Determine if an object should be ordered. Objects that are not * made of entirely the same color, or that have colored back-sides * probably should be ordered. */ EXTERN int VObjectNeedsOrdering (VObject * obj); EXTERN void VComputePolygonOrdering (VObject * obj); EXTERN void VDestroyObject (VObject *obj); EXTERN VObject *VCopyObject (VObject *); EXTERN VObject * VExtrudeObject(VObject * obj, VPoint * vec); EXTERN VObject *VReadObject (FILE * f); EXTERN VObject *VReadDepthCueuedObject (FILE * f, int is_depth_cueing); EXTERN int VWriteObject (FILE *, VObject *); EXTERN void VSetReadObjectScale (VPoint *); EXTERN void VComputeObjectExtent (VObject *); /* * DXF to V-library (obv) file converter */ EXTERN VObject * VReadDXFObject(FILE *f); EXTERN VObject * VReadDepthCueuedDXFObject(FILE *f, int is_depth_cueing); #undef EXTERN #endif acm-6.0_20200416/src/V/Vlib.h0000644000000000000000000001062413140076676013651 0ustar rootroot/** * Vlib is a 3-D aware graphical library. * * @file */ #ifndef _VLIB_H #define _VLIB_H #include #include "Vlibmath.h" #include "Alib.h" #ifdef Vlib_IMPORT #define EXTERN #else #define EXTERN extern #endif /* * Viewport flags (must be changed manually after VOpenViewport for now) */ #define VPClip 1 /* polygons should be clipped before drawing */ #define VPPerspective 2 /* Z coordinate used for depth information */ typedef struct { gui_Type * gui; Alib_Window *w; /* performs 2-D drawing and z-buffer */ Alib_Rect rect; /* view rectangle inside w */ Alib_Point focus; /* infinite sight point (pixel) */ double dist; /* distance from eye to focus (m) */ Alib_Point Middl; /* focus point *4 (pixels) */ double xres; /* x screen resolution (pixels/m) */ double yres; /* y screen resolution (pixels/m) */ VPoint Scale; /* scaling factor *4 */ int flags; /* (see VP* constants above) */ VMatrix eyeSpace; /* transforms from world to eyeSpace system */ VPolygon *clipPoly; /* planes to clip viewed polygons */ VPoint clipNormals[4]; /* normal vectors corresponding to clipPoly */ } Viewport; /** * Return a new 3-D rectangular area (view_rect) on the given window (w). * The focus is the focus of the projection in screen coordinates (pixel). * The distance of the eye from the focus of the view_rect (dist, meters) * must also be given. * * Note that the AWindow must be already set, and that there may be * several Viewport on the same AWindow. * * Must be released with memory_dispose(). */ EXTERN Viewport * Vlib_new(gui_Type *gui, Alib_Window *w, Alib_Rect *view_rect, Alib_Point *focus, double dist); /** * Change size and projection infos. Basically does the same as * VOpenViewport(), with the only difference that it operates on an * existing Viewport. Note that the AWindow is not affected. */ EXTERN void VResizeViewport(Viewport *v, Alib_Rect *view_rect, Alib_Point *focus, double dist); /** * Set the clipping rectangular region in the AWindow to which this * Viewport is linked. The resulting clipping rectangle is the * intersection among the Viewport rectangle and the AWindow rectangle, * possibly empty. */ EXTERN void VSetClipRect(Viewport *v, Alib_Rect *r); EXTERN void VExposeBuffer(Viewport *); /** * Transform a 3-D point in the eye space system into viewable * coordinates. The function returns 1 if the x,y information is * displayable (probably displayable, that is). */ EXTERN int VEyeToScreen(Viewport * v, VPoint * p, int *x, int *y); /** * Transform a 3-D point in the world system into viewable coordinates. * The function returns 1 if the x,y information is displayable * (probably displayable, that is). */ EXTERN int VWorldToScreen(Viewport * v, VPoint * p, int *x, int *y); EXTERN void VDrawSegments(Viewport * v, Alib_Segment * seg, int nseg, Alib_Pixel color); EXTERN void VFillRectangle(Viewport *v, Alib_Rect *r, Alib_Pixel c); EXTERN void VDrawPolygon(Viewport * v, VPolygon * poly); EXTERN void VFillPolygon(Viewport * v, VPolygon * poly); EXTERN void VDrawString(Viewport * v, VPoint * p, char *str, int len); EXTERN int VFontWidthPixels(Viewport * v, int scale); EXTERN void VDrawStrokeString(Viewport * v, int x, int y, char *str, int len, int scale, Alib_Pixel color); EXTERN void VGetStrokeString(Viewport * v, int x, int y, Alib_Segment * seg, int *nseg, char *str, int len, int scale); /** * Set the perspective projection transformation. Vectors does not need to be * normalized to the unity length. * @param vp Position of the eye in XYZ world frame. * @param fwd The point the eye is looking at in XYZ world frame. * @param up Eye's up direction in XYZ world frame. */ EXTERN void VGetEyeSpace(Viewport * v, VPoint EyePt, VPoint CntrInt, VPoint up); EXTERN VPolygon *VGetPlanes(VPolygon * poly); /** * We'll create the notion of a viewport-specific color tweaking * procedure. This procedure allows some user code to get control * just before we hand the color name to XParseColor() so that we * might alter the name a bit. Why use it? It allows us to shrink * down the color space a bit on color-poor screens. */ EXTERN void VSetColorTweakProc(Viewport * v, void (*proc) ( /** ??? */ )); EXTERN void VForceWindowRedraw(Viewport * v); #undef EXTERN #endif acm-6.0_20200416/src/V/Vlibmath.c0000644000000000000000000002262013173131065014503 0ustar rootroot/* * LINKER_OPTIONS -lm */ #include #define Vlibmath_IMPORT #include "Vlibmath.h" void VSetPoint(VPoint *p, double x, double y, double z) { p->x = x; p->y = y; p->z = z; } void VAdd(VPoint *a, VPoint *b, VPoint *sum) { sum->x = a->x + b->x; sum->y = a->y + b->y; sum->z = a->z + b->z; } double VMagnitude(VPoint *p) { return sqrt( p->x*p->x + p->y*p->y + p->z*p->z ); } double VMagnitude2(VPoint *p) { return p->x*p->x + p->y*p->y + p->z*p->z; } void VSub(VPoint *a, VPoint *b, VPoint *dif) { dif->x = a->x - b->x; dif->y = a->y - b->y; dif->z = a->z - b->z; } double VDotProd(a, b) VPoint *a, *b; { return a->x * b->x + a->y * b->y + a->z * b->z; } void VCrossProd(a, b, r) VPoint *a, *b, *r; { int overlap; VPoint q, *p; if( a == r || b == r ){ overlap = 1; p = &q; } else { overlap = 0; p = r; } p->x = a->y * b->z - a->z * b->y; p->y = a->z * b->x - a->x * b->z; p->z = a->x * b->y - a->y * b->x; if( overlap ) *r = *p; } static VMatrix ident = { { {1.0, 0.0, 0.0, 0.0}, {0.0, 1.0, 0.0, 0.0}, {0.0, 0.0, 1.0, 0.0}, {0.0, 0.0, 0.0, 1.0} } }; void VIdentMatrix(VMatrix * Mtx) { *Mtx = ident; } void VMatrixTranspose(VMatrix *ori, VMatrix *trans) { int i, j; VMatrix *r, m; if( ori == trans ) r = &m; else r = trans; for (i = 0; i < 4; ++i) for (j = 0; j < 4; ++j) r->m[i][j] = ori->m[j][i]; if( ori == trans ) *trans = m; } void VMatrixMult(VMatrix *Mt1, VMatrix *Mt2, VMatrix *R) { register int I, J, K; register double x; int overlap; VMatrix *r, M; if( Mt1 == R || Mt2 == R ){ overlap = 1; r = &M; } else { overlap = 0; r = R; } for (I = 0; I < 4; ++I) for (J = 0; J < 4; ++J) { x = 0.0; for (K = 0; K < 4; ++K) x += Mt1->m[K][J] * Mt2->m[I][K]; r->m[I][J] = x; } if( overlap ) *R = M; } #define ZEROFOURTH void VMatrixMultByRank(VMatrix * Mt1, VMatrix * Mt2, VMatrix * R, int rank) { int I, J, K; double x; int overlap; VMatrix *r, M; if( Mt1 == R || Mt2 == R ){ overlap = 1; r = &M; } else { overlap = 0; r = R; } for (I = 0; I < rank; ++I) for (J = 0; J < rank; ++J) { x = 0.0; for (K = 0; K < rank; ++K) x += Mt1->m[K][J] * Mt2->m[I][K]; r->m[I][J] = x; } #ifdef ZEROFOURTH r->m[0][3] = r->m[1][3] = r->m[2][3] = 0.0; r->m[3][0] = r->m[3][1] = r->m[3][2] = 0.0; r->m[3][3] = 1.0; #endif if( overlap ) *R = M; } void VRotate(VMatrix * m, int operation, double angle) { VMatrix r; double co, si; VIdentMatrix(&r); co = cos(angle); si = sin(angle); switch (operation) { case XRotation: r.m[1][1] = r.m[2][2] = co; r.m[2][1] = si; r.m[1][2] = -si; break; case YRotation: r.m[0][0] = r.m[2][2] = co; r.m[0][2] = si; r.m[2][0] = -si; break; case ZRotation: r.m[0][0] = r.m[1][1] = co; r.m[1][0] = si; r.m[0][1] = -si; break; } VMatrixMult(m, &r, m); } void VRotateAroundAxis(VMatrix * m, VPoint * axis, double angle) { VPoint u = *axis; double k = 1 / VMagnitude(&u); u.x *= k; u.y *= k; u.z *= k; double co = cos(angle); double co1 = 1-co; double si = sin(angle); VMatrix r; VIdentMatrix(&r); // FIXME: several redundant calculations -- compiler smart enough? r.m[0][0] = co + u.x*u.x*co1; r.m[0][1] = u.x*u.y*co1-u.z*si; r.m[0][2] = u.x*u.z*co1+u.y*si; r.m[1][0] = u.x*u.y*co1+u.z*si; r.m[1][1] = co+u.y*u.y*co1; r.m[1][2] = u.y*u.z*co1-u.x*si; r.m[2][0] = u.x*u.z*co1-u.y*si; r.m[2][1] = u.y*u.z*co1+u.x*si; r.m[2][2] = co+u.z*u.z*co1; VMatrixMult(m, &r, m); } void VScaleMatrix(VMatrix *m, double xscale, double yscale, double zscale) { VMatrix s; VIdentMatrix(&s); s.m[0][0] = xscale; s.m[1][1] = yscale; s.m[2][2] = zscale; VMatrixMult(m, &s, m); } void VTranslatePoint(VMatrix * m, VPoint t) { m->m[0][3] += t.x; m->m[1][3] += t.y; m->m[2][3] += t.z; } void VTranslate(VMatrix * m, double x, double y, double z) { m->m[0][3] += x; m->m[1][3] += y; m->m[2][3] += z; } void VTransform(VPoint *p, VMatrix *m, VPoint *newp) { VPoint q; q.x = p->x * m->m[0][0] + p->y * m->m[0][1] + p->z * m->m[0][2] + m->m[0][3]; q.y = p->x * m->m[1][0] + p->y * m->m[1][1] + p->z * m->m[1][2] + m->m[1][3]; q.z = p->x * m->m[2][0] + p->y * m->m[2][1] + p->z * m->m[2][2] + m->m[2][3]; *newp = q; } void VReverseTransform(VPoint *p, VMatrix *m, VPoint *newp) { VPoint q; q.x = p->x - m->m[0][3]; q.y = p->y - m->m[1][3]; q.z = p->z - m->m[2][3]; newp->x = q.x * m->m[0][0] + q.y * m->m[1][0] + q.z * m->m[2][0]; newp->y = q.x * m->m[0][1] + q.y * m->m[1][1] + q.z * m->m[2][1]; newp->z = q.x * m->m[0][2] + q.y * m->m[1][2] + q.z * m->m[2][2]; } void VTransform_(VPoint *p, VMatrix *m, VPoint *newp) { VPoint q; q.x = p->x * m->m[0][0] + p->y * m->m[0][1] + p->z * m->m[0][2]; q.y = p->x * m->m[1][0] + p->y * m->m[1][1] + p->z * m->m[1][2]; q.z = p->x * m->m[2][0] + p->y * m->m[2][1] + p->z * m->m[2][2]; *newp = q; } void VReverseTransform_(VPoint *p, VMatrix *m, VPoint *newp) { VPoint q; q.x = p->x * m->m[0][0] + p->y * m->m[1][0] + p->z * m->m[2][0]; q.y = p->x * m->m[0][1] + p->y * m->m[1][1] + p->z * m->m[2][1]; q.z = p->x * m->m[0][2] + p->y * m->m[1][2] + p->z * m->m[2][2]; *newp = q; } #define EPSILON 1e-6 void VEulerToMatrix(double phi, double theta, double psi, VMatrix *m) { double sinPhi, cosPhi, sinTheta, cosTheta, sinPsi, cosPsi; sinPhi = sin(phi); cosPhi = cos(phi); sinTheta = sin(theta); cosTheta = cos(theta); sinPsi = sin(psi); cosPsi = cos(psi); m->m[0][0] = cosTheta * cosPsi; m->m[0][1] = sinPhi * sinTheta * cosPsi - cosPhi * sinPsi; m->m[0][2] = cosPhi * sinTheta * cosPsi + sinPhi * sinPsi; m->m[1][0] = cosTheta * sinPsi; m->m[1][1] = sinPhi * sinTheta * sinPsi + cosPhi * cosPsi; m->m[1][2] = cosPhi * sinTheta * sinPsi - sinPhi * cosPsi; m->m[2][0] = -sinTheta; m->m[2][1] = sinPhi * cosTheta; m->m[2][2] = cosPhi * cosTheta; m->m[0][3] = m->m[1][3] = m->m[2][3] = 0.0; m->m[3][0] = m->m[3][1] = m->m[3][2] = 0.0; m->m[3][3] = 1.0; } void VMatrixToEuler(VMatrix *m, double *phi, double *theta, double *psi) { double sin_theta; sin_theta = -m->m[2][0]; /* if (fabs(sin_theta) > 1.0 - EPSILON) { / * we have the nose pointing very close to straight up or straight down, set roll to zero and compute the resulting heading * / *psi = atan2(-m->m[0][1], m->m[1][1]); if (sin_theta > 0.0) *theta = M_PI / 2.0; else *theta = -M_PI / 2.0; *phi = 0.0; } else { */ *psi = atan2(m->m[1][0], m->m[0][0]); *theta = asin(sin_theta); *phi = atan2(m->m[2][1], m->m[2][2]); /* } */ /* Normalize ranges: */ if (*psi < 0.0) *psi += 2.0 * M_PI; } /* * Quaternion code based on code from "Advanced Animation and Rendering * Techniques: Theory and Practice" by Alan Watt and Mark Watt. */ void VQuaternionToMatrix(VQuaternion * q, VMatrix * m) { double s, xs, ys, zs, wx, wy, wz, xx, xy, xz, yy, yz, zz; s = 2.0 / (q->v.x * q->v.x + q->v.y * q->v.y + q->v.z * q->v.z + q->s * q->s); xs = q->v.x * s; ys = q->v.y * s; zs = q->v.z * s; wx = q->s * xs; wy = q->s * ys; wz = q->s * zs; xx = q->v.x * xs; xy = q->v.x * ys; xz = q->v.x * zs; yy = q->v.y * ys; yz = q->v.y * zs; zz = q->v.z * zs; VIdentMatrix(m); m->m[0][0] = 1.0 - (yy + zz); m->m[0][1] = xy + wz; m->m[0][2] = xz - wy; m->m[1][0] = xy - wz; m->m[1][1] = 1.0 - (xx + zz); m->m[1][2] = yz + wx; m->m[2][0] = xz + wy; m->m[2][1] = yz - wx; m->m[2][2] = 1.0 - (xx + yy); } void VMatrixToQuaternion(VMatrix * m, VQuaternion * q) { double tr, s, *q1 = (double *) &q->v; int i, j, k; tr = m->m[0][0] + m->m[1][1] + m->m[2][2]; if (tr > 0.0) { s = sqrt(tr + 1.0); q->s = s * 0.5; s = 0.5 / s; q->v.x = (m->m[1][2] - m->m[2][1]) * s; q->v.y = (m->m[2][0] - m->m[0][2]) * s; q->v.z = (m->m[0][1] - m->m[1][0]) * s; } else { i = 0; if (m->m[1][1] > m->m[0][0]) { i = 1; } if (m->m[2][2] > m->m[i][i]) { i = 2; } j = (i + 1) % 3; k = (j + 1) % 3; s = sqrt((m->m[i][i] - (m->m[j][j] + m->m[k][k])) + 1.0); q1[i] = s * 0.5; s = 0.5 / s; q->s = (m->m[j][k] + m->m[k][j]) * s; q1[j] = (m->m[i][j] + m->m[j][i]) * s; q1[k] = (m->m[i][k] + m->m[k][i]) * s; } } void VInterpolateQuaternion(VQuaternion * p, VQuaternion * q, double t, VQuaternion * qt) { double omega, cosom, sinom, sclp, sclq; cosom = p->v.x * p->v.x + p->v.y * p->v.y + p->v.z * p->v.z + p->s * p->s; if ((1.0 + cosom) > EPSILON) { if ((1.0 - cosom) > EPSILON) { omega = acos(cosom); sinom = sin(omega); sclp = sin((1.0 - t) * omega) / sinom; sclq = sin(t * omega) / sinom; } else { sclp = 1.0 - t; sclq = t; } qt->v.x = p->v.x * sclp + q->v.x * sclq; qt->v.y = p->v.y * sclp + q->v.y * sclq; qt->v.z = p->v.z * sclp + q->v.z * sclq; qt->s = p->s * sclp + q->s * sclq; } else { qt->v.x = -p->v.y; qt->v.y = p->v.x; qt->v.z = -p->s; qt->s = p->v.z; sclp = sin((1.0 - t) * M_PI_2); sclq = sin(t * M_PI_2); qt->v.x = p->v.x * sclp + qt->v.x * sclq; qt->v.y = p->v.y * sclp + qt->v.y * sclq; qt->v.z = p->v.z * sclp + qt->v.z * sclq; } } VQuaternion * VQuaternionMult(VQuaternion * a, VQuaternion * b, VQuaternion * r) { VPoint c; r->s = a->s * b->s - VDotProd(&a->v, &b->v); VCrossProd(&a->v, &b->v, &c); c.x += a->s * b->v.x + b->s * a->v.x; c.y += a->s * b->v.y + b->s * a->v.y; c.z += a->s * b->v.z + b->s * a->v.z; r->v = c; return r; } VQuaternion * VQuaternionComplement(VQuaternion * a, VQuaternion * r) { r->s = a->s; r->v.x = -a->v.x; r->v.y = -a->v.y; r->v.z = -a->v.z; return r; } acm-6.0_20200416/src/V/VPoly.c0000644000000000000000000002376113173131161014012 0ustar rootroot#include #include #include #include "../util/error.h" #include "../util/memory.h" #define VPoly_IMPORT #include "VPoly.h" static char *aspect_name[] = { "left", "right", "front right bottom", "front right top", "front left bottom", "front left top", "aft right bottom", "aft right top", "aft left bottom", "aft left top" }; typedef struct VPolySet_Elem { VPolygon *poly; struct VPolySet_Elem *next; } VPolySet_Elem; struct VPolySet { int count; VPolySet_Elem *first; VPolySet_Elem *last; VPolySet_Elem *curr; }; static VPolySet_Elem *free_elem = NULL; static VPolySet *free_set = NULL; static void VPoly_cleanup(void) { VPolySet *s; VPolySet_Elem *e; while( free_set != NULL ){ s = free_set; free_set = (VPolySet *) free_set->first; memory_dispose(s); } while( free_elem != NULL ){ e = free_elem; free_elem = free_elem->next; memory_dispose(e); } } VPolySet * VPolySet_New() { VPolySet *s; if( free_set == NULL ){ s = memory_allocate( sizeof( VPolySet ), NULL ); memory_registerCleanup(VPoly_cleanup); } else { s = free_set; free_set = (VPolySet *) free_set->first; } s->count = 0; s->first = NULL; s->last = NULL; s->curr = NULL; return s; } void VPolySet_Free(VPolySet *s, int release_polygons_too) { VPolySet_Elem *e, *p; if( s == NULL ) return; if( s->count < 0 ) error_internal("using already released VPolySet", 0); e = s->first; while( e != NULL ){ p = e->next; if( release_polygons_too ) VDestroyPolygon(e->poly); /* Release "e": */ e->next = free_elem; free_elem = e; e = p; } s->first = (VPolySet_Elem *) free_set; free_set = s; free_set->count = -1; } void VPolySet_Add(VPolySet *s, VPolygon *p) { VPolySet_Elem *e; if( s->count < 0 ) error_internal("using already released VPolySet", 0); if( free_elem == NULL ){ e = memory_allocate( sizeof( VPolySet_Elem ), NULL ); } else { e = free_elem; free_elem = free_elem->next; } e->poly = p; e->next = NULL; if( s->count == 0 ){ s->first = e; } else { s->last->next = e; } s->last = e; s->count++; } VPolygon * VPolySet_First(VPolySet *s) { if( s == NULL ) return NULL; if( s->count < 0 ) error_internal("using already released VPolySet", 0); if( s->count == 0 ){ s->curr = NULL; return NULL; } s->curr = s->first; return s->curr->poly; } VPolygon * VPolySet_Next(VPolySet *s) { if( s == NULL ) return NULL; if( s->count < 0 ) error_internal("using already released VPolySet", 0); if( s->curr == NULL ) return NULL; s->curr = s->curr->next; if( s->curr == NULL ) return NULL; else return s->curr->poly; } void VPolySet_Set(VPolySet *s, VPolygon *poly) { if( s->count < 0 ) error_internal("using already released VPolySet", 0); s->curr->poly = poly; } int VPolySet_Count(VPolySet *s) { if( s == NULL ) return 0; if( s->count < 0 ) error_internal("using already released VPolySet", 0); if( s == NULL ) return 0; else return s->count; } char * VGetAspectName(int aspect) { return aspect_name[aspect]; } void VPrintPolygon(FILE * file, VPolygon * p) { int i; char *nullPoly = "*** Null Polygon ***\n"; if (p == (VPolygon *) NULL) fprintf(file, nullPoly); else { if (p->numVtces == 0) { fprintf(file, nullPoly); return; } fprintf(file, "%d vertices:\n", p->numVtces); for (i = 0; i < p->numVtces; ++i) fprintf(file, "%9.6g %9.6g %9.6g\n", p->vertex[i].x, p->vertex[i].y, p->vertex[i].z); } return; } VPolygon * VCreatePolygon(int numVtces, VPoint * vert, VColor_Type * color) { VPolygon template; template.color = color; template.backColor = (VColor_Type *) NULL; template.flags = 0; template.cullDistance = 0.0; return VCreatePolygonFromTemplate(numVtces, vert, &template); } VPolygon * VCreatePolygonFromTemplate(int numVtces, VPoint * vert, VPolygon * template) { VPolygon *p; VPoint a, b; p = memory_allocate(sizeof(VPolygon), NULL); *p = *template; p->numVtces = numVtces; p->vertex = memory_allocate(sizeof(VPoint) * numVtces, NULL); memcpy((char *) p->vertex, (char *) vert, sizeof(VPoint) * p->numVtces); if ((p->flags & PolyNormalValid) == 0) { if ((p->flags & PolyClipBackface) != 0 || p->backColor != (VColor_Type *) NULL) { a.x = vert[0].x - vert[1].x; a.y = vert[0].y - vert[1].y; a.z = vert[0].z - vert[1].z; b.x = vert[2].x - vert[1].x; b.y = vert[2].y - vert[1].y; b.z = vert[2].z - vert[1].z; VCrossProd(&a, &b, &p->normal); p->flags |= PolyNormalValid; } } return p; } VPolygon * VCopyPolygon(VPolygon * poly) { return VCreatePolygonFromTemplate(poly->numVtces, poly->vertex, poly); } VPolygon * VTransformPolygon(VPolygon * poly, VMatrix * m) { int i; VPoint tmp; for (i = 0; i < poly->numVtces; ++i) { VTransform(&(poly->vertex[i]), m, &tmp); poly->vertex[i] = tmp; } return poly; } static VPolygon * _VClipPolygon(VPolygon * poly, VPoint * clipPlane) { register int j, lastj, numPts = 0, clipped = 0; double d1, d2, a; VPoint tmpPoint[VmaxVP]; VPolygon *p; if (poly->numVtces > 0) { lastj = poly->numVtces - 1; d1 = VDotProd(&(poly->vertex[poly->numVtces - 1]), clipPlane); numPts = 0; /* * Examine each vertex and determine if it is inside or outside of the * specified clipping plane. */ for (j = 0; j < poly->numVtces; ++j) { /* Leading vertex inside? */ if (d1 > 0.0) tmpPoint[numPts++] = poly->vertex[lastj]; d2 = VDotProd(&(poly->vertex[j]), clipPlane); /* Does the edge straddle the window? If so, add a vertex on the window */ if (d1 * d2 < 0.0) { clipped = 1; a = d1 / (d1 - d2); tmpPoint[numPts].x = a * poly->vertex[j].x + (1.0 - a) * poly->vertex[lastj].x; tmpPoint[numPts].y = a * poly->vertex[j].y + (1.0 - a) * poly->vertex[lastj].y; tmpPoint[numPts++].z = a * poly->vertex[j].z + (1.0 - a) * poly->vertex[lastj].z; } lastj = j; d1 = d2; } } /* * If the polygon was completely out of bounds, delete this polygon. */ if (numPts == 0) { p = (VPolygon *) NULL; VDestroyPolygon(poly); #ifdef DEBUG fprintf(stderr, "VClipPolygon: polygon outside area of interest\n"); #endif } /* * If we did any clipping, return the clipped polygon. */ else if (clipped) { p = VCreatePolygonFromTemplate(numPts, tmpPoint, poly); #ifdef DEBUG fprintf(stderr, "VClipPolygon: Polygon has been clipped:\n"); fprintf(stderr, "Before Clipping:\n"); VPrintPolygon(stderr, poly); fprintf(stderr, "\nAfter Clipping:\n\n"); VPrintPolygon(stderr, p); #endif VDestroyPolygon(poly); } else p = poly; return p; } VPolygon * VClipPolygon(VPolygon * poly, VPolygon * clipPoly) { int i; VPolygon *p = poly; /* * Clip against each clipping plane supplied, one at a time. */ for (i = 0; i < clipPoly->numVtces; ++i) { if (p == (VPolygon *) NULL) break; p = _VClipPolygon(p, &(clipPoly->vertex[i])); } return p; } VPolygon * VClipSidedPolygon(VPolygon * poly, VPolygon * clipPoly) { int i; VPolygon *p = poly; if (p->flags & PolyNormalValid) { if (VDotProd(&p->vertex[0], &p->normal) >= 0.0) { if (p->backColor) { p->flags |= PolyUseBackColor; } else if (p->flags & PolyClipBackface) { VDestroyPolygon(p); return (VPolygon *) NULL; } } else { p->flags &= ~(PolyUseBackColor); } } /* * Clip against each clipping plane supplied, one at a time. */ for (i = 0; i < clipPoly->numVtces; ++i) { if (p == (VPolygon *) NULL) break; p = _VClipPolygon(p, &(clipPoly->vertex[i])); } return p; } static void ComputeRotationMatrix(double r, VPoint * e, VMatrix * m) { double one64th = 1.0 / 64.0, ma; VPoint Ax, Ay, Wy = {0, 1, 0}, Wz = {0, 0, 1}; VMatrix tm, tm1; VIdentMatrix(&tm); if (r != 0.0) { VRotate(&tm, ZRotation, r * M_PI / 180.0); } if (fabs(e->x) < one64th && fabs(e->y) < one64th) { VCrossProd(&Wy, e, &Ax); } else { VCrossProd(&Wz, e, &Ax); } ma = sqrt(Ax.x * Ax.x + Ax.y * Ax.y + Ax.z * Ax.z); Ax.x /= ma; Ax.y /= ma; Ax.z /= ma; VCrossProd(e, &Ax, &Ay); ma = sqrt(Ay.x * Ay.x + Ay.y * Ay.y + Ay.z * Ay.z); Ay.x /= ma; Ay.y /= ma; Ay.z /= ma; VIdentMatrix(m); m->m[0][0] = Ax.x; m->m[1][0] = Ax.y; m->m[2][0] = Ax.z; m->m[0][1] = Ay.x; m->m[1][1] = Ay.y; m->m[2][1] = Ay.z; m->m[0][2] = e->x; m->m[1][2] = e->y; m->m[2][2] = e->z; VMatrixMultByRank(&tm, m, &tm1, 3); *m = tm1; } VPolygon * ScalePolygon(VPolygon * in, VPoint * offset, VPoint * scale, VPoint *e, double r) { int numVtces = in->numVtces, i; VPoint *vert; VPolygon *p; VPoint a, b, tmp, offset1; VMatrix m; p = memory_allocate(sizeof(VPolygon), NULL); #ifdef DEBUG fprintf(stderr, "scaling %d-point polygon %g, %g, %g; rotation %g; offset %g, %g, %g\n", in->numVtces, scale->x, scale->y, scale->z, r, offset->x, offset->y, offset->z); #endif *p = *in; p->numVtces = numVtces; vert = p->vertex = memory_allocate(sizeof(VPoint) * numVtces, NULL); ComputeRotationMatrix(r, e, &m); VTransform_ (offset, &m, &offset1); for (i = 0; i < numVtces; ++i) { p->vertex[i] = in->vertex[i]; #ifdef notdef p->vertex[i].x -= offset->x; p->vertex[i].y -= offset->y; p->vertex[i].z -= offset->z; #endif VTransform_(&p->vertex[i], &m, &tmp); #ifdef notdef tmp.x += offset1.x; tmp.y += offset1.y; tmp.z += offset1.z; #endif p->vertex[i].x = tmp.x * scale->x; p->vertex[i].y = tmp.y * scale->y; p->vertex[i].z = tmp.z * scale->z; #ifdef notdef p->vertex[i].x += offset->x; p->vertex[i].y += offset->y; p->vertex[i].z += offset->z; p->vertex[i].x += offset1.x; p->vertex[i].y += offset1.y; p->vertex[i].z += offset1.z; #endif } if ((p->flags & PolyNormalValid) == 0) { if ((p->flags & PolyClipBackface) != 0 || p->backColor != (VColor_Type *) NULL) { a.x = vert[0].x - vert[1].x; a.y = vert[0].y - vert[1].y; a.z = vert[0].z - vert[1].z; b.x = vert[2].x - vert[1].x; b.y = vert[2].y - vert[1].y; b.z = vert[2].z - vert[1].z; VCrossProd(&a, &b, &p->normal); p->flags |= PolyNormalValid; } } return p; } acm-6.0_20200416/src/V/VGlyph.h0000644000000000000000000000106113063667560014163 0ustar rootroot/** * Type declarations for vectorial font. * * @file */ #ifndef VGLYPH_H #define VGLYPH_H /** * Defines a single glyph. Each glyph contains zero or more paths, each path * contains zero or more points. For example, the vertical bar '|' can be * described by a single path with 2 vertices. */ typedef struct { short path_count; short path_start; short glyph_width; } VGlyph_Type; typedef struct { short vertex_count; short vertex_start; } VGlyph_Path; typedef struct { short x; short y; } VGlyph_Vertex; #endif acm-6.0_20200416/src/V/VColor.c0000644000000000000000000000502613141045366014145 0ustar rootroot#include #include #include #include "../util/error.h" #include "../util/memory.h" #include "../util/gui.h" #include "../util/sparsearray.h" #define VColor_IMPORT #include "VColor.h" struct VColor_Type { /** Index to CLUT in gui.c. */ int index; /** 0 = no depth cueing, 1 = yes. */ unsigned char is_depth_cueing; /** RGB color actually requested by client. */ unsigned char red; unsigned char green; unsigned char blue; }; /** * Sparse array of colors. The index is built by packing the is_depth_cueing, * red, green and blue fields of the color, which are univocal of that color. * Lazy initialized as the first color gets requested. */ static sparsearray_Type *colors; static void VColor_cleanup() { double quality = sparsearray_getAverageComparisonsPerSearch(colors); if( quality > 2 ) sparsearray_report(colors, "Warning: VColor module performances issue"); memory_dispose(colors); colors = NULL; } VColor_Type * VColor_getByRGB(int red, int green, int blue, int is_depth_cueing) { if( (red&255)!=red || (green&255)!=green || (blue&255)!=blue ) error_internal("invalid RGB: %d,%d,%d", red, green, blue); is_depth_cueing = is_depth_cueing? 1 : 0; // normalize flag to 0 or 1 // Search for existing color in the hash map: if( colors == NULL ){ colors = sparsearray_new(1234, 0); memory_registerCleanup(VColor_cleanup); } int packed = (is_depth_cueing << 24) | (red << 16) | (green << 8) | blue; VColor_Type *c = sparsearray_get(colors, packed); if( c != NULL ) return c; // Add new color to the colors table: c = memory_allocate(sizeof(struct VColor_Type), NULL); c->index = gui_getColorIndex(NULL, red, green, blue); c->is_depth_cueing = is_depth_cueing; c->red = red; c->green = green; c->blue = blue; sparsearray_set(colors, packed, c); assert( sparsearray_get(colors, packed) == c ); return c; } VColor_Type * VColor_getByName(char *name, int is_depth_cueing) { int red, green, blue; if( ! gui_parseColorString(name, &red, &green, &blue) ) error_internal("invalid color specification: %s", name); return VColor_getByRGB(red, green, blue, is_depth_cueing); } int VColor_getIndex(VColor_Type *c){ return c->index; } int VColor_isDepthCueing(VColor_Type *c){ return c->is_depth_cueing; } int VColor_getRed(VColor_Type *c){ return c->red; } int VColor_getGreen(VColor_Type *c){ return c->green; } int VColor_getBlue(VColor_Type *c){ return c->blue; } char * VColor_getName(VColor_Type *c) { static char s[8]; sprintf(s, "#%02u%02u%02u", c->red, c->green, c->blue); return s; } acm-6.0_20200416/src/V/VObjects.c0000644000000000000000000012154313143357745014474 0ustar rootroot#include #include #include #include #include #include "VPoly.h" #include "../util/error.h" #include "../util/memory.h" #define VObjects_IMPORT #include "VObjects.h" struct entry { int id; double d; struct entry *next; }; int VComputeObjectAspect(VObject * obj, VPoint * loc) { register int q; register double a, b, c, m; m = mag(loc->x, loc->y, loc->z); a = VDotProd(loc, &obj->xaxis); b = VDotProd(loc, &obj->yaxis) / m; c = VDotProd(loc, &obj->zaxis); /* * If the absolute angle between the Y axis and viewing vector is less than 30 * degrees, then it is either a right or left aspect. */ if (b > 0.866) { return 1; } else if (b < -0.866) { return 0; } if (a < 0.0) { /* front */ if (b < 0.0) { /* front right */ if (c < 0.0) { /* front right bottom */ q = 2; } else { /* front right top */ q = 3; } } else { /* front left */ if (c < 0.0) { /* front left bottom */ q = 4; } else { /* front left top */ q = 5; } } } else { /* aft */ if (b < 0.0) { /* aft right */ if (c < 0.0) { /* aft right bottom */ q = 6; } else { /* aft right top */ q = 7; } } else { /* aft left */ if (c < 0.0) { /* aft left bottom */ q = 8; } else { /* aft left top */ q = 9; } } } return q; } VObject * VExtrudeObject(VObject * obj, VPoint * vec) { #ifdef notdef VPoint tmp[4]; int k, other; #endif VPolygon *poly_tmp[65536]; int i, j; VObject *newObj; #ifdef FIXME_NOT_USED_CHECK_BELOW VPolygon *poly; VPoint scale = {1, 1, 1}; #endif #ifdef DEBUG fprintf(stderr, "creating an extrusion based on \"%s\"\n", obj->name); fprintf(stderr, "starting with %d polygons\n", obj->numPolys); #endif newObj = memory_allocate(sizeof(VObject), NULL); newObj->name = obj->name; newObj->extent = obj->extent; newObj->center = obj->center; for (i = 0; i < obj->numPolys; ++i) { if ((poly_tmp[obj->numPolys - i - 1] = VCopyPolygon(obj->polygon[i])) == (VPolygon *) NULL) { error_internal("VExtrudeObject: can't copy polygons", 0); } } /* * If clipping is enabled, then we should be reversing the vertices * of this polygon */ for (i = 0, j = obj->numPolys; i < obj->numPolys; ++i, ++j) { /* FIXME: to do */ error_internal("FIXME", 0); #ifdef FIXME /* ERROR: missing 4-th argument of ScalePolygon(): */ if ((poly_tmp[j] = ScalePolygon(obj->polygon[i], vec, &scale, 0.0)) == (VPolygon *) NULL) { error_internal("VExtrudeObject: can't copy polygons", 0); } #endif } /* * Now create extrusion polygons by marching through the original polygon * vertices and creating new polygons that connect the edges of the "upper" * and "lower" polygons as we go. */ #ifdef notdef for (i = 0; i < obj->numPolys; ++i) { poly = obj->polygon[i]; for (k = 0; k < poly->numVtces; ++k) { other = (k == 0) ? poly->numVtces - 1 : k - 1; tmp[0] = poly->vertex[other]; tmp[1] = poly->vertex[k]; tmp[2] = poly->vertex[k]; tmp[2].x += vec->x; tmp[2].y += vec->y; tmp[2].z += vec->z; tmp[3] = poly->vertex[other]; tmp[3].x += vec->x; tmp[3].y += vec->y; tmp[3].z += vec->z; poly_tmp[j++] = VCreatePolygonFromTemplate(4, tmp, poly); } } #endif /* * Complete filling the object structure */ #ifdef DEBUG fprintf(stderr, "%d polygons in the extruded object\n", j); #endif newObj->polygon = memory_allocate(sizeof(VPolygon *) * j, NULL); newObj->numPolys = j; for (i = 0; i < j; ++i) { newObj->polygon[i] = poly_tmp[i]; } return newObj; } void VDestroyObject(VObject *obj) { long i; for (i=0; inumPolys; ++i) { VDestroyPolygon (obj->polygon[i]); } memory_dispose(obj->order); memory_dispose(obj->polygon); memory_dispose(obj->name); memory_dispose(obj); } VObject * VCopyObject(VObject * obj) { register int i; register VObject *newObj; newObj = memory_allocate(sizeof(VObject), NULL); newObj->name = obj->name; newObj->extent = obj->extent; newObj->center = obj->center; newObj->numPolys = obj->numPolys; newObj->polygon = memory_allocate(sizeof(VPolygon *) * newObj->numPolys, NULL); if (obj->order) { newObj->order = memory_allocate(sizeof(unsigned short) * NUM_ASPECTS * newObj->numPolys, NULL); memcpy((char *) newObj->order, (char *) obj->order, sizeof(unsigned short) * NUM_ASPECTS * newObj->numPolys); } else { newObj->order = (unsigned short *) NULL; } for (i = 0; i < obj->numPolys; ++i) { if ((newObj->polygon[i] = VCopyPolygon(obj->polygon[i])) == (VPolygon *) NULL) { error_internal("VCopyObject: can't copy polygons", 0); } } return newObj; } int VObjectNeedsOrdering(VObject * obj) { VPolygon **p; int i; if (obj->order || obj->numPolys == 0) { return 0; } for (i = 0, p = obj->polygon; i < obj->numPolys; ++i) { #ifdef notdef if (p[i]->color != c) { return 1; } #endif if (p[i]->backColor) { return 1; } } return 0; } void VComputePolygonOrdering(VObject * obj) { register int i, j, k, inserted; register double d, dn; VMatrix mtx; VPoint pt1, pt2; VPolygon **p; struct entry ent[VmaxVP], *head, *e, *last_e; obj->order = memory_allocate(sizeof(unsigned short) * NUM_ASPECTS * obj->numPolys, NULL); for (i = 0; i < NUM_ASPECTS; ++i) { VIdentMatrix(&mtx); VRotate(&mtx, YRotation, view[i].pitch); VRotate(&mtx, ZRotation, view[i].yaw); pt1.x = obj->extent * 10.0; pt1.y = pt1.z = 0.0; VTransform(&pt1, &mtx, &pt2); head = (struct entry *) NULL; for (j = 0, p = obj->polygon; j < obj->numPolys; ++j) { /* * Compute the distance to the farthest vertex on this polygon */ dn = mag(p[j]->vertex[0].x - pt2.x, p[j]->vertex[0].y - pt2.y, p[j]->vertex[0].z - pt2.z); for (k = 1; k < p[j]->numVtces; ++k) { d = mag( p[j]->vertex[k].x - pt2.x, p[j]->vertex[k].y - pt2.y, p[j]->vertex[k].z - pt2.z); if (d > dn) { dn = d; } } ent[j].id = j; ent[j].d = dn; /* * Insert this entry into the descending sorted list of polygons */ if (!head) { ent[j].next = head; head = &ent[j]; } else { last_e = (struct entry *) NULL; inserted = 0; for (e = head; e; e = e->next) { if (e->d < ent[j].d) { if (last_e) { ent[j].next = last_e->next; last_e->next = &ent[j]; } else { ent[j].next = e; head = &ent[j]; } inserted = 1; break; } last_e = e; } if (inserted == 0) { last_e->next = &ent[j]; ent[j].next = (struct entry *) NULL; } } } /* * Copy this list as the hints for this quadrant. */ k = obj->numPolys * i; for (j = 0, e = head; j < obj->numPolys; ++j, e = e->next) { obj->order[k + j] = e->id; } } } static VPoint scale = {1.0, 1.0, 1.0}; void VSetReadObjectScale(VPoint * p) { scale = *p; } typedef enum { Nil, EndOfFile, TOKEN_RGB_VALUE, TOKEN_LPAREN, TOKEN_RPAREN, TOKEN_COMMA, TOKEN_STRING, TOKEN_CLIP, TOKEN_DOUBLE, TOKEN_LONG, } field_id; struct keyword_info { char *word; field_id id; }; static struct keyword_info keywords[] = { {"clip", TOKEN_CLIP}, {(char *) NULL, Nil}, }; static char token[256]; static int token_length = 0; typedef union { struct keyword_info *kw; double double_value; char *string_value; long long_value; VPoint point; VPolygon *poly; } lex_val; static lex_val lex_value; struct lex_record { char *name; FILE *f; int lineno; int lookahead_valid; int lookahead; int stack_top; lex_val value_stack[4]; }; #define push_value(p, type, val) \ p->value_stack[p->stack_top++].type = val #define pop_value(p, type) (p->value_stack[--p->stack_top].type) #define input(p) (p->lookahead_valid \ ? (p->lookahead_valid = 0, p->lookahead) \ : (((p->lookahead = getc(p->f)) == '\n') \ ? (p->lineno++, p->lookahead) \ : p->lookahead)) #define unput(p, c) { p->lookahead = c; p->lookahead_valid = 1; } #define STATE_INITIAL 0 #define STATE_WORD 1 #define STATE_NUMBER 2 #define STATE_STRING 3 #define STATE_RGB 4 static void ParseError(p, s) struct lex_record *p; char *s; { fprintf(stderr, "error in file %s (line %d):\n\t%s\n", p->name, p->lineno, s); } static field_id NextToken(struct lex_record *p) { register int c, state = STATE_INITIAL, seen_dot = 0; register struct keyword_info *q; token_length = 0; while ((c = input(p)) != EOF) { switch (state) { case STATE_INITIAL: if (isalpha(c)) { token[token_length++] = c; state = STATE_WORD; } else if (isspace(c)) { continue; } else if (isdigit(c) || c == '-' || c == '+' || c == '.') { if (c == '.') seen_dot = 1; token[token_length++] = c; state = STATE_NUMBER; } else if (c == '"') { state = STATE_STRING; } else if (c == '#') { token[token_length++] = c; state = STATE_RGB; } else { token[0] = c; token[1] = '\0'; #ifdef DEBUG printf("other %s\n", token); #endif switch (c) { case ',': return TOKEN_COMMA; case '(': return TOKEN_LPAREN; case ')': return TOKEN_RPAREN; default: ParseError(p, "invalid character"); state = STATE_INITIAL; } } break; case STATE_WORD: case STATE_NUMBER: if (isspace(c) || c == ',' || c == '(' || c == ')') { token[token_length] = '\0'; unput(p, c); if (state == STATE_WORD) { for (q = keywords; q->word; ++q) { if (strcmp(q->word, token) == 0) { lex_value.kw = q; return q->id; } } return TOKEN_STRING; } else { if (seen_dot) { lex_value.double_value = atof(token); return TOKEN_DOUBLE; } else { lex_value.long_value = atoi(token); return TOKEN_LONG; } } } else { if (c == '.' || c == 'e' || c == 'E') { seen_dot = 1; } token[token_length++] = c; } break; case STATE_STRING: switch (c) { case '"': token[token_length] = '\0'; return TOKEN_STRING; case '\n': ParseError(p, "strings cannot span a line"); unput(p, c); state = STATE_INITIAL; break; case '\\': switch (c = input(p)) { case EOF: ParseError(p, "Premature End-of-file"); break; case 'n': token[token_length++] = '\n'; break; case 't': token[token_length++] = '\t'; break; default: token[token_length++] = c; break; } default: token[token_length++] = c; break; } break; case STATE_RGB: while (isxdigit(c)) { token[token_length++] = c; c = input(p); } unput(p, c); token[token_length] = '\0'; state = STATE_INITIAL; return TOKEN_RGB_VALUE; /*NOTREACHED */ break; } } return EndOfFile; } /* * Skip to the specified token, if token is Nil, then skip to the end of the * current line. */ static void Resync(p, token) struct lex_record *p; field_id token; { field_id t; int c; if (token == Nil) { while ((c = input(p)) != EOF) { if (c == '\n') break; } } else { while ((t = NextToken(p)) != EndOfFile) { if (t == token) break; } } } /* * Parse a polygon's color information * * color_information: foreground_color * | '(' foreground_color [ background_color ] [ 'clip' ] ')' * ; */ static int ParseColorInfo(struct lex_record *p, int is_depth_cueing) { field_id t; static VPolygon template; int count = 0, done = 0; template.color = template.backColor = (VColor_Type *) NULL; template.flags = 0; t = NextToken(p); if (t == TOKEN_RGB_VALUE || t == TOKEN_STRING) { template.color = VColor_getByName(token, is_depth_cueing); } else if (t == TOKEN_LPAREN) { template.flags = 0; while (!done) { t = NextToken(p); switch (t) { case TOKEN_RGB_VALUE: case TOKEN_STRING: if (count++ == 0) { template.color = VColor_getByName(token, is_depth_cueing); } else { template.backColor = VColor_getByName(token, is_depth_cueing); } break; case TOKEN_COMMA: break; case TOKEN_CLIP: template.flags |= PolyClipBackface; break; case TOKEN_RPAREN: done = 1; break; default: break; } } } else { Resync(p, Nil); return 1; } push_value(p, poly, &template); return 0; } static int ParseVertex(p) struct lex_record *p; { field_id t; VPoint pt; if (NextToken(p) != TOKEN_LONG) { } t = NextToken(p); if (t == TOKEN_DOUBLE) { pt.x = lex_value.double_value; } else if (t == TOKEN_LONG) { pt.x = lex_value.long_value; } else { return 1; } t = NextToken(p); if (t == TOKEN_DOUBLE) { pt.y = lex_value.double_value; } else if (t == TOKEN_LONG) { pt.y = lex_value.long_value; } else { return 1; } t = NextToken(p); if (t == TOKEN_DOUBLE) { pt.z = lex_value.double_value; } else if (t == TOKEN_LONG) { pt.z = lex_value.long_value; } else { return 1; } push_value(p, point, pt); return 0; } /* * Parse a polygon description. tmp is the vector containing the points list * (all points vertices used in all polgons in this object). pts is a * scratch point list used to build this polygon; it is pre-allocated * by the caller. */ static int ParsePolygon(struct lex_record *p, VPoint *tmp, VPoint *pts, int is_depth_cueing) { int num_points, i, id; VPolygon template; if (ParseColorInfo(p, is_depth_cueing) != 0) { ParseError(p, "invalid color specification"); return 1; } template = *(pop_value(p, poly)); if (NextToken(p) != TOKEN_LONG) { ParseError(p, "invalid polygon vertex count"); return 1; } num_points = lex_value.long_value; for (i = 0; i < num_points; ++i) { if (NextToken(p) != TOKEN_LONG) { ParseError(p, "invalid polygon vertex"); return 1; } id = lex_value.long_value; pts[i] = tmp[id - 1]; } push_value(p, poly, VCreatePolygonFromTemplate(num_points, pts, &template)); return 0; } VObject * VReadObject(f) FILE *f; { return VReadDepthCueuedObject(f, 0); } VObject * VReadDepthCueuedObject(FILE *f, int is_depth_cueing) { char *name; int num_points, num_polys, i; VPoint *tmp_points, *tmp_points1; VPolygon **polygons; VObject *object; struct lex_record lr, *p; char line[256]; p = &lr; p->f = f; p->lineno = 1; p->lookahead_valid = 0; p->stack_top = 0; fgets(line, sizeof(line), f); p->lineno = 2; p->name = line; name = memory_strdup(line); if (NextToken(p) != TOKEN_LONG) { return (VObject *) NULL; } num_points = lex_value.long_value; if (NextToken(p) != TOKEN_LONG) { return (VObject *) NULL; } num_polys = lex_value.long_value; /* * Allocate temporary storage for the polygon vertices. tmp_points1 is * a vector of points used to build each polygon structure. Also, allocate * storage for the object's polygon vector. */ tmp_points = memory_allocate(num_points * 2 * sizeof(VPoint), NULL); tmp_points1 = &tmp_points[num_points]; polygons = memory_allocate(num_polys * sizeof(VPolygon *), NULL); /* * Get the vertices */ for (i = 0; i < num_points; ++i) { if (ParseVertex(p) != 0) { return (VObject *) NULL; } tmp_points[i] = pop_value(p, point); tmp_points[i].x *= scale.x; tmp_points[i].y *= scale.y; tmp_points[i].z *= scale.z; } /* * Now get the polygon descriptions */ for (i = 0; i < num_polys; ++i) { if (ParsePolygon(p, tmp_points, tmp_points1, is_depth_cueing) != 0) { ParseError(p, "invalid polygon specification"); return (VObject *) NULL; } polygons[i] = pop_value(p, poly); } /* * Build the object structure */ object = memory_allocate(sizeof(VObject), NULL); object->name = name; object->numPolys = num_polys; object->polygon = polygons; object->order = (unsigned short *) NULL; VComputeObjectExtent(object); if (VObjectNeedsOrdering(object)) { VComputePolygonOrdering(object); } memory_dispose((char *) tmp_points); return object; } int VWriteObject(FILE * f, VObject * obj) { int i, j, k, points; VPolygon **q; VPoint *p; /* * Total the number of vertices in all of the object's polygons */ points = 0; q = obj->polygon; for (i = 0; i < obj->numPolys; ++i) { points += q[i]->numVtces; } /* * Print the header */ fprintf(f, "%s\n%d %d\n", obj->name, points, obj->numPolys); /* * Print the point list */ k = 1; q = obj->polygon; for (i = 0; i < obj->numPolys; ++i) { for ((j = 0, p = q[i]->vertex); j < q[i]->numVtces; (++p, ++j)) { fprintf(f, "%d %g %g %g\n", k, p->x, p->y, p->z); ++k; } } /* * Print the polygon list */ k = 1; q = obj->polygon; for (i = 0; i < obj->numPolys; ++i) { if (q[i]->backColor) { fprintf(f, "(%s", VColor_getName(q[i]->color)); fprintf(f, " %s) %d", VColor_getName(q[i]->backColor), q[i]->numVtces); } else if (q[i]->flags & PolyClipBackface) { fprintf(f, "(%s clip) %d", VColor_getName(q[i]->color), q[i]->numVtces); } else { fprintf(f, "%s %d", VColor_getName(q[i]->color), q[i]->numVtces); } for (j = 0; j < q[i]->numVtces; ++j) fprintf(f, " %d", k++); fprintf(f, "\n"); } return ferror(f) ? -1 : 0; } void VComputeObjectExtent(VObject * obj) { VPoint sum; register int i, j, npts = 0; register double d; obj->extent = 0.0; sum.x = 0.0; sum.y = 0.0; sum.z = 0.0; /* * Add the xyz components of each point in the object so that we can * determine the average location (i.e. the center). */ for (i = 0; i < obj->numPolys; ++i) { for (j = 0; j < obj->polygon[i]->numVtces; ++j) { sum.x += obj->polygon[i]->vertex[j].x; sum.y += obj->polygon[i]->vertex[j].y; sum.z += obj->polygon[i]->vertex[j].z; ++npts; } } if (npts != 0) { obj->center.x = sum.x / npts; obj->center.y = sum.y / npts; obj->center.z = sum.z / npts; /* * Determine the most distant point from the center of the object */ for (i = 0; i < obj->numPolys; ++i) { for (j = 0; j < obj->polygon[i]->numVtces; ++j) { sum.x = obj->polygon[i]->vertex[j].x - obj->center.x; sum.y = obj->polygon[i]->vertex[j].y - obj->center.y; sum.z = obj->polygon[i]->vertex[j].z - obj->center.z; d = sqrt(sum.x * sum.x + sum.y * sum.y + sum.z * sum.z); if (d > obj->extent) obj->extent = d; } } } else { obj->center.x = obj->center.y = obj->center.z = 0.0; } } #define STATE_NORMAL 0 #define STATE_ENTITIES 1 #define STATE_POLYLINE 2 #define STATE_3DFACE 3 #define STATE_VERTEX 4 #define STATE_BLOCK 5 #define STATE_INSERT 6 #define STATE_TABLES 7 #define STATE_GENERAL_ENTITY 8 static char *colors[] = { "black", "red", "yellow", "green", "cyan", "blue", "magenta", "white" }; #define POLY_MAX (10 * 1024) #define BOBJECT_MAX 128 #define POINT_MAX 32768 static VObject *bobject[BOBJECT_MAX]; static int btop = 0; #ifdef DEBUG #define PDEBUG(a) printf a #else #define PDEBUG(a) #endif static int lineno = 0; #define COMPARE(a,b) strcmp(a,b) enum _token_id { DXF_NULL, DXF_EOF, DXF_X_COORD, DXF_Y_COORD, DXF_Z_COORD, DXF_X_SCALE, DXF_Y_SCALE, DXF_Z_SCALE, DXF_ROTATE, DXF_SECTION, DXF_ENDSEC, DXF_SEQEND, DXF_TITLE, DXF_POLYLINE, DXF_3DFACE, DXF_ENTITIES, DXF_VERTEX, DXF_BLOCKS, DXF_INSERT, DXF_X_EXTRUDE, DXF_Y_EXTRUDE, DXF_Z_EXTRUDE, DXF_M_COUNT, DXF_N_COUNT, DXF_THIRD_VERTEX, DXF_FOURTH_VERTEX, DXF_FLAGS, DXF_ITEM, DXF_TABLES, DXF_TABLE, DXF_ENDTAB, DXF_LAYER, DXF_STYLE, DXF_LTYPE, DXF_ATTDEF, DXF_ATTRIB, DXF_DICTIONARY, /* found in OBJECTS section */ DXF_MLINESTYLE, DXF_ACAD_GROUP, DXF_ACAD_MLINESTYLE, DXF_APPID, /* found in TABLES and BLOCKS section */ DXF_BLOCK, DXF_ENDBLK, DXF_VPORT, DXF_VIEW, DXF_COLOR_INDEX }; typedef enum _token_id dxf_token_id; typedef struct { dxf_token_id id; char *name; } token_table; token_table a[] = { {DXF_SECTION, "SECTION"}, {DXF_ENDSEC, "ENDSEC"}, {DXF_POLYLINE, "POLYLINE"}, {DXF_3DFACE, "3DFACE"}, {DXF_VERTEX, "VERTEX"}, {DXF_SEQEND, "SEQEND"}, {DXF_EOF, "EOF"}, {DXF_BLOCK, "BLOCK"}, {DXF_ENDBLK, "ENDBLK"}, {DXF_INSERT, "INSERT"}, {DXF_TABLE, "TABLE"}, {DXF_ENDTAB, "ENDTAB"}, {DXF_LAYER, "LAYER"}, {DXF_STYLE, "STYLE"}, {DXF_LTYPE, "LTYPE"}, {DXF_VPORT, "VPORT"}, {DXF_DICTIONARY, "DICTIONARY"}, {DXF_MLINESTYLE, "MLINESTYLE"}, {DXF_APPID, "APPID"}, {DXF_ACAD_GROUP, "ACAD_GROUP"}, {DXF_ACAD_MLINESTYLE, "ACAD_MLINESTYLE"}, {DXF_ATTDEF, "ATTDEF"}, {DXF_ATTRIB, "ATTRIB"}, {DXF_EOF, NULL} }; static int int_value; static dxf_token_id ReadToken(FILE *f, double *fp_value, char *cp_value, int *code, char *string) { long i; int len; token_table *p; char buf1[512], buf2[512], *r1, *r2; r1 = fgets(buf1, sizeof(buf1), f); r2 = fgets(buf2, sizeof(buf2), f); lineno += 2; /* * Remove the trailing newline ... */ len = strlen(buf1); if (len > 0) { buf1[len - 1] = '\0'; } /* * File in MSDOS format? */ if (len >= 2 && buf1[len - 2] == '\r') { buf1[len - 2] = '\0'; } /* * Remove the trailing newline ... */ len = strlen(buf2); if (len > 0) { buf2[len - 1] = '\0'; } /* * File in MSDOS format? */ if (len >= 2 && buf2[len - 2] == '\r') { buf2[len - 2] = '\0'; } strcpy(cp_value, buf2); strcpy(string, buf2); if (r1 != (char *) NULL && r2 != (char *) NULL) { i = strtol(buf1, (char **) NULL, 0); *code = i; if (i == 0) { for (p = a; p->name != (char *) NULL; ++p) { if (COMPARE(p->name, buf2) == 0) { /* PDEBUG(("token: %s --> ", p->name)); */ return p->id; } } printf ("Warning: unrecognized directive, \"%s\"\n", buf2); } else if (i == 2) { if (COMPARE("ENTITIES", buf2) == 0) { return DXF_ENTITIES; } else if (COMPARE("BLOCKS", buf2) == 0) { return DXF_BLOCKS; } else if (COMPARE("TABLES", buf2) == 0) { return DXF_TABLES; } else { return DXF_TITLE; } } else if (i >= 10 && i <= 19) { *fp_value = strtod(buf2, (char **) NULL); return DXF_X_COORD; } else if (i >= 20 && i <= 29) { *fp_value = strtod(buf2, (char **) NULL); return DXF_Y_COORD; } else if (i >= 30 && i <= 39) { *fp_value = strtod(buf2, (char **) NULL); return DXF_Z_COORD; } else if (i == 41) { *fp_value = strtod(buf2, (char **) NULL); return DXF_X_SCALE; } else if (i == 42) { *fp_value = strtod(buf2, (char **) NULL); return DXF_Y_SCALE; } else if (i == 43) { *fp_value = strtod(buf2, (char **) NULL); return DXF_Z_SCALE; } else if (i == 50) { *fp_value = strtod(buf2, (char **) NULL); return DXF_ROTATE; } else if (i == 62) { int_value = strtol(buf2, (char **) NULL, 0); return DXF_COLOR_INDEX; } else if (i == 70) { int_value = strtol(buf2, (char **) NULL, 0); return DXF_FLAGS; } else if (i == 71) { int_value = strtol(buf2, (char **) NULL, 0); return DXF_M_COUNT; } else if (i == 72) { int_value = strtol(buf2, (char **) NULL, 0); return DXF_N_COUNT; } else if (i == 73) { int_value = strtol(buf2, (char **) NULL, 0); return DXF_THIRD_VERTEX; } else if (i == 74) { int_value = strtol(buf2, (char **) NULL, 0); return DXF_FOURTH_VERTEX; } else if (i == 210) { *fp_value = strtod(buf2, (char **) NULL); return DXF_X_EXTRUDE; } else if (i == 220) { *fp_value = strtod(buf2, (char **) NULL); return DXF_Y_EXTRUDE; } else if (i == 230) { *fp_value = strtod(buf2, (char **) NULL); return DXF_Z_EXTRUDE; } else { return DXF_ITEM; } } return DXF_EOF; } static int lookahead_valid = 0; static double fp_la; static dxf_token_id token_id_la; static char cp_la[256], string_la[256]; static int code_la; static dxf_token_id DXFNextToken(FILE * f, double *fp_value, char *cp_value, int * code, char *string) { if (lookahead_valid) { lookahead_valid = 0; *fp_value = fp_la; strcpy(cp_value, cp_la); strcpy(string, string_la); *code = code_la; return token_id_la; } else { return ReadToken(f, fp_value, cp_value, code, string); } } static void PushToken(dxf_token_id id, double fp_value, char *cp_value, int code, char *string) { lookahead_valid = 1; fp_la = fp_value; token_id_la = id; strcpy(cp_la, cp_value); strcpy(string_la, string); code_la = code; } static void InsertBlock(char *name, VPoint * o, VPoint * scale, VPoint * extrude, double r, VPolygon **poly, int *ptop) { VObject **p; int i, j, extrusion = 0; PDEBUG(("looking for \"%s\"; offset %g, %g, %g; scale %g, %g, %g; extrude %g, %g, %g; rotate %g\n", name, o->x, o->y, o->z, scale->x, scale->y, scale->z, extrude->x, extrude->y, extrude->z, r)); for (p = bobject, i = 0; i < btop; ++i, ++p) { if (strcmp((*p)->name, name) == 0) { /* * If this is an extrusion, create a temporary object representing the * given extrusion direction. */ #ifdef notdef if (extrude->x != 0.0 || extrude->y != 0.0 || extrude->z != 0.0) { PDEBUG(("extrusion (%f, %f, %f)\n", extrude->x, extrude->y, extrude->z)); extrusion = 1; ex_tmp = VExtrudeObject(*p, extrude); p = &ex_tmp; } #endif /* * Add points to the block ... */ PDEBUG(("adding %d polygons to %d existing\n", (*p)->numPolys, (*ptop))); for (j = 0; j < (*p)->numPolys; ++j) { poly[(*ptop)++] = ScalePolygon((*p)->polygon[j], o, scale, extrude, r); } /* * Delete the temporarily created extrusion object */ if (extrusion) { for (j = 0; j < (*p)->numPolys; ++j) { VDestroyPolygon((*p)->polygon[j]); memory_dispose((char *) (*p)); } } return; } } } VObject * VReadDXFObject(FILE *f) { return VReadDepthCueuedObject(f, 0); } VObject * VReadDepthCueuedDXFObject(FILE *f, int flag) { double value, rotate = 0; dxf_token_id id; int i, j, m0 = 0, n0 = 0, vertices_listed_by_index = 0; VPoint temp[POINT_MAX], temp1[4], *p, scale, pt, bpt, extrude; VPolygon template; VObject *object; int top = 0; int state = STATE_NORMAL; char cp[256], title[256], insert_title[256], *stop_block = ""; int order = 0; int indices[4], num_indices = 0; VMatrix m; int code; char string[256]; VColor_Type *blackColor = VColor_getByName("black", 0); VPolygon *poly[POLY_MAX]; int ptop = 0; VSetPoint(&bpt, 0.0, 0.0, 0.0); /* * Start with the first of our selected colors. If ordering was reqested, * make the same color the "backface color". */ memset(&template, 0, sizeof(VPolygon)); template.color = blackColor; template.backColor = NULL; if (order) { template.backColor = template.color; } /* * I'm not sure about backface clipping, yet. */ template.flags = 0; /* template.flags = PolyClipBackface; */ p = &temp[top]; while (1) { id = DXFNextToken(f, &value, cp, &code, string); switch (state) { case STATE_NORMAL: /// PDEBUG(("NORMAL: %s\n", string)); switch (id) { case DXF_ENTITIES: state = STATE_ENTITIES; break; case DXF_BLOCKS: state = STATE_ENTITIES; break; case DXF_TABLES: state = STATE_TABLES; break; case DXF_EOF: /* * Build the object structure */ object = memory_allocate(sizeof(VObject), NULL); memset (object, 0, sizeof(VObject)); object->name = memory_strdup("name"); object->numPolys = ptop; object->polygon = memory_allocate(ptop * sizeof(VPolygon *), NULL); memcpy(object->polygon, poly, ptop * sizeof(VPolygon *)); object->order = (unsigned short *) NULL; VComputeObjectExtent(object); if (VObjectNeedsOrdering(object)) { VComputePolygonOrdering(object); } /* * Change to V library axes (Z-axis = down); */ VIdentMatrix(&m); #ifdef notdef m.m[2][1] = 1.0; m.m[2][2] = 0.0; m.m[1][1] = 0.0; m.m[1][2] = -1.0; #endif m.m[2][2] = -1.0; m.m[1][1] = -1.0; for (i = 0; i < object->numPolys; ++i) { for (j = 0; j < object->polygon[i]->numVtces; ++j) { VTransform_(&object->polygon[i]->vertex[j], &m, &pt); object->polygon[i]->vertex[j] = pt; } } return object; default: break; } break; /* * Skip table definitions (for now) ... */ case STATE_TABLES: switch (id) { case DXF_ENDSEC: state = STATE_NORMAL; break; default: break; } break; case STATE_ENTITIES: if (code == 0) { // close-out last entity #ifdef notdef printf ("Entity closed 0, \"%s\"\n", string); #endif } // PDEBUG(("ENTITIES: %s\n", string)); switch (id) { case DXF_ATTDEF: case DXF_ATTRIB: state = STATE_GENERAL_ENTITY; break; case DXF_POLYLINE: state = STATE_POLYLINE; p = &temp[0]; top = 0; m0 = n0 = 0; vertices_listed_by_index = num_indices = 0; break; case DXF_3DFACE: state = STATE_3DFACE; p = &temp[0]; top = 0; break; case DXF_BLOCK: state = STATE_BLOCK; strcpy (title, "*none*"); bpt.x = bpt.y = bpt.z = 0.0; break; case DXF_ENDBLK: state = STATE_BLOCK; PushToken(id, value, cp, code, string); break; case DXF_INSERT: pt.x = pt.y = pt.z = 0.0; scale.x = 1.0; scale.y = 1.0; scale.z = 1.0; rotate = 0.0; extrude = pt; extrude.z = 1.0; state = STATE_INSERT; strcpy (insert_title, "*not-specified*"); break; case DXF_ENDSEC: state = STATE_NORMAL; break; default: if (code != 0) { printf ("hmm, %d \"%s\"\n", code, string); } else { state = STATE_GENERAL_ENTITY; } break; case DXF_EOF: break; } break; case STATE_POLYLINE: //PDEBUG(("POLYLINE: %s\n", string)); switch (id) { case DXF_COLOR_INDEX: if (int_value < 8) { error_internal("variable `i' uninitialized", 0); /* FIXME template.color = VAllocColor (colors[i]); */ if (order) { template.backColor = template.color; } } else { printf ("color index %d\n", int_value); } break; case DXF_SEQEND: /* * Mesh? */ if (vertices_listed_by_index == 0) { if (m0 != 0 || n0 != 0) { for (i = 1; i < m0; ++i) { for (j = 1; j < n0; ++j) { temp1[0] = temp[(i - 1) * n0 + j - 1]; temp1[1] = temp[(i) * n0 + j - 1]; temp1[2] = temp[(i) * n0 + j]; poly[ptop++] = VCreatePolygonFromTemplate(3, temp1, &template); temp1[0] = temp[(i) * n0 + j]; temp1[1] = temp[(i - 1) * n0 + j]; temp1[2] = temp[(i - 1) * n0 + j - 1]; poly[ptop++] = VCreatePolygonFromTemplate(3, temp1, &template); } } PDEBUG(("mesh %d x %d\n", m0, n0)); } else { poly[ptop++] = VCreatePolygonFromTemplate(top, temp, &template); } } PDEBUG(("added POLYLINE polygon number %d\n", ptop - 1)); #ifdef notdef VPrintPolygon(stdout, poly[ptop - 1]); #endif p = &temp[0]; top = 0; state = STATE_ENTITIES; break; case DXF_FLAGS: if ((int_value & 2) || (int_value & 4)) { printf ("Warning: POLYLINE splines or curves not supported by Vlib (line %d).\n", lineno); } break; case DXF_VERTEX: state = STATE_VERTEX; break; case DXF_M_COUNT: m0 = int_value; break; case DXF_N_COUNT: n0 = int_value; break; default: break; } break; case STATE_3DFACE: // PDEBUG(("3DFACE: %s\n", string)); switch (id) { case DXF_COLOR_INDEX: if (int_value < 8) { template.color = VColor_getByName(colors[int_value], 0); if (order) { template.backColor = template.color; } } else { printf ("color index %d\n", int_value); } break; case DXF_ENDBLK: state = STATE_BLOCK; PushToken(id, value, cp, code, string); /* create polygon */ poly[ptop++] = VCreatePolygonFromTemplate(top, temp, &template); p = &temp[0]; top = 0; break; case DXF_X_COORD: p->x = value; if ((id = DXFNextToken(f, &p->y, cp, &code, string)) != DXF_Y_COORD) { printf("syntax error4 %d\n", id); } if ((id = DXFNextToken(f, &p->z, cp, &code, string)) != DXF_Z_COORD) { printf("syntax error5 %d\n", id); } ++p; ++top; if (top == POINT_MAX) { printf ("Point overflow, increase POINT_MAX.\n"); } break; case DXF_3DFACE: case DXF_POLYLINE: case DXF_ENDSEC: default: if (code == 0) { /* * Turbocad bug */ if (temp[top-1].x == temp[top-2].x && temp[top-1].y == temp[top-2].y && temp[top-1].z == temp[top-2].z) { -- top; } /* create polygon */ poly[ptop++] = VCreatePolygonFromTemplate(top, temp, &template); #ifdef notdef printf("polygon %d\n", ptop - 1); VPrintPolygon(stdout, poly[ptop - 1]); #endif p = &temp[0]; top = 0; PushToken(id, value, cp, code, string); state = STATE_ENTITIES; } break; } break; /* * Get X,Y,Z components following a VERTEX directive */ case STATE_VERTEX: // PDEBUG(("VERTEX: %d\n", id)); switch (id) { case DXF_COLOR_INDEX: if (int_value < 8) { error_internal("var `i' uninitialized", 0); /* FIXME template.color = VAllocColor (colors[i]); */ if (order) { template.backColor = template.color; } } else { printf ("color index %d\n", int_value); } break; case DXF_X_COORD: p->x = value; break; case DXF_Y_COORD: p->y = value; break; case DXF_Z_COORD: p->z = value; break; /* * M_COUNT and N_COUNT really are the first and second vertex indices in * a VERTEX. */ case DXF_M_COUNT: vertices_listed_by_index = 1; if (int_value < 0) { int_value = - int_value; } indices[0] = int_value - 1; num_indices = 1; break; case DXF_N_COUNT: vertices_listed_by_index = 1; if (int_value < 0) { int_value = - int_value; } indices[1] = int_value - 1; num_indices = 2; break; case DXF_THIRD_VERTEX: vertices_listed_by_index = 1; if (int_value < 0) { int_value = - int_value; } indices[2] = int_value - 1; num_indices = 3; break; case DXF_FOURTH_VERTEX: vertices_listed_by_index = 1; if (int_value < 0) { int_value = - int_value; } indices[3] = int_value - 1; num_indices = 4; break; case DXF_SEQEND: case DXF_VERTEX: if (vertices_listed_by_index) { for (i=0; i= top) { printf ("internal error polygon vertex out of range: %d (max %d) -- %d\n", indices[i], top, i); } temp1[i] = temp[indices[i]]; } poly[ptop++] = VCreatePolygonFromTemplate(num_indices, temp1, &template); } else { ++p; ++top; if (top == POINT_MAX) { printf ("Point overflow, increase POINT_MAX.\n"); } } PushToken(id, value, cp, code, string); state = STATE_POLYLINE; break; default: break; } break; case STATE_INSERT: // PDEBUG(("INSERT: %s\n", string)); switch (id) { case DXF_ENDBLK: state = STATE_BLOCK; PushToken(id, value, cp, code, string); InsertBlock(insert_title, &pt, &scale, &extrude, rotate, poly, &ptop); break; case DXF_TITLE: strcpy(insert_title, cp); break; case DXF_X_COORD: pt.x = value; break; case DXF_Y_COORD: pt.y = value; break; case DXF_Z_COORD: pt.z = value; break; case DXF_X_SCALE: scale.x = value; break; case DXF_Y_SCALE: scale.y = value; break; case DXF_Z_SCALE: scale.z = value; break; case DXF_ROTATE: rotate = value; break; case DXF_X_EXTRUDE: extrude.x = value; break; case DXF_Y_EXTRUDE: extrude.y = value; break; case DXF_Z_EXTRUDE: extrude.z = value; break; case DXF_INSERT: case DXF_POLYLINE: case DXF_3DFACE: case DXF_ENDSEC: default: if (code == 0) { state = STATE_ENTITIES; PushToken(id, value, cp, code, string); InsertBlock(insert_title, &pt, &scale, &extrude, rotate, poly, &ptop); } break; } break; case STATE_GENERAL_ENTITY: if (code == 0) { state = STATE_ENTITIES; PushToken(id, value, cp, code, string); } break; case STATE_BLOCK: PDEBUG(("BLOCK: %s\n", string)); switch (id) { case DXF_ENDBLK: /* * Build the object structure and place it on the block list */ object = memory_allocate(sizeof(VObject), NULL); object->name = memory_allocate(strlen(title) + 1, NULL); strcpy(object->name, title); PDEBUG(("added block \"%s\" %d polygons (line %d)\n", title, ptop, lineno)); object->numPolys = ptop; object->polygon = memory_allocate(ptop * sizeof(VPolygon *), NULL); memcpy((char *) object->polygon, (char *) poly, ptop * sizeof(VPolygon *)); ptop = 0; object->order = NULL; PDEBUG(("Block offset %f, %f, %f\n", bpt.x, bpt.y, bpt.z)); for (i = 0; i < object->numPolys; ++i) { for (j = 0; j < object->polygon[i]->numVtces; ++j) { object->polygon[i]->vertex[j].x += bpt.x; object->polygon[i]->vertex[j].y += bpt.y; object->polygon[i]->vertex[j].z += bpt.z; } } bobject[btop++] = object; state = STATE_ENTITIES; if (strcmp(stop_block, object->name) == 0) { VIdentMatrix(&m); #ifdef notdef m.m[2][1] = 1.0; m.m[2][2] = 0.0; m.m[1][1] = 0.0; m.m[1][2] = -1.0; #endif m.m[2][2] = -1.0; m.m[1][1] = -1.0; for (i = 0; i < object->numPolys; ++i) { for (j = 0; j < object->polygon[i]->numVtces; ++j) { VTransform(&object->polygon[i]->vertex[j], &m, &pt); object->polygon[i]->vertex[j] = pt; } } return object; } break; case DXF_TITLE: strcpy(title, cp); break; case DXF_X_COORD: bpt.x = value; break; case DXF_Y_COORD: bpt.y = value; break; case DXF_Z_COORD: bpt.z = value; break; case DXF_POLYLINE: case DXF_3DFACE: case DXF_INSERT: default: if (code == 0) { state = STATE_ENTITIES; PushToken(id, value, cp, code, string); } break; } } } return 0; } #ifdef FIXME_NOT_USED static void ArbitraryAxis (VPoint *normal, VMatrix *out) { double minval = 1.0 / 64.0, d; VPoint Ax, Ay, Az; d = sqrt (normal->x * normal->x + normal->y * normal->y + normal->z * normal->z); Az.x = normal->x / d; Az.y = normal->y / d; Az.z = normal->z / d; if (fabs (Az.x) < minval && fabs (Az.y) < minval) { VCrossProd(&VUnitVectorJ, &Az, &Ax); } else { VCrossProd(&VUnitVectorK, &Az, &Ax); } VCrossProd (&Az, &Ax, &Ay); out->m[0][0] = Ax.x; out->m[0][1] = Ax.y; out->m[0][2] = Ax.z; out->m[1][0] = Ay.x; out->m[1][1] = Ay.y; out->m[1][2] = Ay.z; out->m[2][0] = Az.x; out->m[2][1] = Az.y; out->m[2][2] = Az.z; out->m[3][0] = out->m[3][1] = out->m[3][2] = 0.0; out->m[0][3] = out->m[1][3] = out->m[2][3] = 0.0; out->m[3][3] = 1.0; } #endif /* FIXME_NOT_USED */ /* The VObjects.c module ends here */ acm-6.0_20200416/src/V/Vlibmath.h0000644000000000000000000001422313173131022014501 0ustar rootroot#ifndef _VLIBMATH_H #define _VLIBMATH_H #include #ifdef Vlibmath_IMPORT #define EXTERN #else #define EXTERN extern #endif typedef struct { double x; double y; double z; } VPoint; typedef struct { double m[4][4]; } VMatrix; EXTERN VPoint VUnitVectorI #ifdef Vlibmath_IMPORT = {1.0, 0.0, 0.0} #endif ; EXTERN VPoint VUnitVectorJ #ifdef Vlibmath_IMPORT = {0.0, 1.0, 0.0} #endif ; EXTERN VPoint VUnitVectorK #ifdef Vlibmath_IMPORT = {0.0, 0.0, 1.0} #endif ; #define VPointToClipPlaneDistance(pt, pl) \ (- VDotProd(pl, pt) / ((pl)->x * (pl)->x + (pl)->y * (pl)->y + \ (pl)->z * (pl)->z)) EXTERN void VSetPoint(VPoint *p, double x, double y, double z); #define mag(x,y,z) sqrt ( (x) * (x) + (y) * (y) + (z) * (z) ) /** * Returns the magnitude. * @param p * @return Magnitude sqrt(p->x*p->x + p->y*p->y + p->z*p->z). */ EXTERN double VMagnitude(VPoint *p); /** * Returns the square magnitude. * @param p * @return Squared magnitude p->x*p->x + p->y*p->y + p->z*p->z. */ EXTERN double VMagnitude2(VPoint *p); /** * Return sum=(a.x+b.x, a.y+b.y, a.z+b.z). */ EXTERN void VAdd(VPoint *a, VPoint *b, VPoint *sum); /** * Return dif=(a.x-b.x, a.y-b.y, a.z-b.z). */ EXTERN void VSub(VPoint *a, VPoint *b, VPoint *dif); /** * Return a.x*b.x + a.y*b.y + a.z*b.z. */ EXTERN double VDotProd (VPoint *a, VPoint *b); /** * Return * * p.x = a.y*b.z - a.z*b.y * p.y = a.z*b.x - a.x*b.z * p.z = a.x*b.y - a.y*b.x * * The vectors may overlap. */ EXTERN void VCrossProd (VPoint *a, VPoint *b, VPoint *p); /** * Set the matrix with the identity transformation (i.e. no rotation, * no translation). */ EXTERN void VIdentMatrix(VMatrix * Mtx); /** * Transpose 'ori' into 'trans'. Matrices may overlap. */ EXTERN void VMatrixTranspose(VMatrix *ori, VMatrix *trans); /** * Return r=b*a. The matrices may overlap. * * NOTE that the b matrix is applied NEXT to the a matrix, so that * the algebraic expression r=a*b translates into VMatrixMult(b,a,r). * Another way to remember the order of the arguments is thinking that * the matrices a,b as appears in the formal arguments are applied in * the order to a point. */ EXTERN void VMatrixMult (VMatrix *a, VMatrix *b, VMatrix *r); /** * Performs a sub-matrix multiplication by the given rank 1-4. * Typically rank=3 to perform pure rotations. Matrices may overlap. */ EXTERN void VMatrixMultByRank (VMatrix *a, VMatrix *b, VMatrix *r, int rank); /** * Add active translation to the matrix (increments are added to the point * components). */ EXTERN void VTranslate(VMatrix * m, double x, double y, double z); /** * Add active translation to the matrix (increments are added to the point * components). */ EXTERN void VTranslatePoint(VMatrix * m, VPoint t); /* * VRotate options (see VRotate() below) */ #define XRotation 1 /** rotate about X axis */ #define YRotation 2 /** rotate about Y axis */ #define ZRotation 3 /** rotate about Z axis */ /** * Add the active rotation around the specified coordinate axis to the right * of the given matrix. For example, a rotation by +90 DEG around the z axis * changes the components of the point [1,0,0] into [0,1,0]. * @param m Subject matrix. * @param axis Rotation around: 1=X, 2=Y, 3=Z. * @param theta Angle of the rotation (RAD). */ EXTERN void VRotate(VMatrix *m, int axis, double theta); /** * Add the active rotational around the specified axis to the right of the * given matrix. * @param axis Axis of the rotation. Does not need to be normalized to 1, but * its length must not be zero. * @param angle Angle of rotation. * @param m Resulting rotational matrix. */ EXTERN void VRotateAroundAxis(VMatrix * m, VPoint * axis, double angle); /** * Add a scale transformation next to the given matrix. Example: */ EXTERN void VScaleMatrix(VMatrix *m, double xscale, double yscale, double zscale); /** * Apply the rotation and translation matrix m to the vector p, giving * q[i] = m[i,j]*p[j]+m[i,3] with i,j=0..2. p,q may overlap. */ EXTERN void VTransform(VPoint *p, VMatrix *m, VPoint *q); /** * Apply the rotational matrix only. p,q may overlap. */ EXTERN void VTransform_(VPoint *p, VMatrix *m, VPoint *q); /** * Apply the reverse rotation and translation matrix m to the vector p, giving * q[i] = m[j,i]*(p[j]+m[j,3]) with i,j=0..2. p,q may overlap. */ EXTERN void VReverseTransform(VPoint *p, VMatrix *m, VPoint *q); /** * Apply the reverse rotational matrix only. p,q may overlap. */ EXTERN void VReverseTransform_(VPoint *p, VMatrix *m, VPoint *q); /** * Compute the rotational matrix given the Euler's angles. The resulting matrix * rotates from the rotated reference system to the "fixed" reference system. * The rotated reference system undergone to there rotations, in the order: * 1. Around z of an angle psi. * 2. Around y of an angle theta. * 3. Around x of an angle phi. * @param phi Rotation around the x axis, or "roll" (RAD). * @param theta Rotation around the y axis, or "pitch" (RAD). * @param psi Rotation around the z axis, or "heading" (RAD). * @param m Here returns the computed rotational matrix. */ EXTERN void VEulerToMatrix(double phi, double theta, double psi, VMatrix *m); /** * Computes the Euler's angles given the rotational matrix. * @param m Rotational matrix. * @param phi Here returns the angle of rotation around x axis, or "roll", * in the range [-M_PI/2, M_PI/2] (RAD). * @param theta Here returns the angle of rotation around y axis, or "pitch", * in the range [-M_PI/2, M_PI/2] (RAD). * @param psi Here returns the angle of rotation around z axis, or "heading", * in the range [0, 2*M_PI] (RAD). */ EXTERN void VMatrixToEuler(VMatrix *m, double *phi, double *theta, double *psi); typedef struct { double s; VPoint v; } VQuaternion; EXTERN void VQuaternionToMatrix(VQuaternion * q, VMatrix * m); EXTERN void VMatrixToQuaternion(VMatrix * m, VQuaternion * q); EXTERN void VInterpolateQuaternion(VQuaternion * p, VQuaternion * q, double t, VQuaternion * qt); EXTERN VQuaternion * VQuaternionMult(VQuaternion * a, VQuaternion * b, VQuaternion * r); EXTERN VQuaternion * VQuaternionComplement(VQuaternion * a, VQuaternion * r); #undef EXTERN #endif acm-6.0_20200416/src/V/VRoman.c0000644000000000000000000005201113063667560014150 0ustar rootroot#define VRoman_IMPORT #include "VRoman.h" VGlyph_Type VRomanGlyph[128] = { {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 26819}, {2, 0, 26819}, {2, 2, 26819}, {4, 4, 26819}, {3, 8, 26819}, {3, 11, 26819}, {1, 14, 26819}, {1, 15, 26819}, {1, 16, 26819}, {1, 17, 26819}, {3, 18, 26819}, {2, 21, 26819}, {1, 23, 26819}, {1, 24, 26819}, {1, 25, 26819}, {1, 26, 26819}, {1, 27, 26819}, {1, 28, 26819}, {1, 29, 26819}, {1, 30, 26819}, {2, 31, 26819}, {1, 33, 26819}, {1, 34, 26819}, {2, 35, 26819}, {1, 37, 26819}, {1, 38, 26819}, {2, 39, 26819}, {2, 41, 26819}, {1, 43, 26819}, {2, 44, 26819}, {1, 46, 26819}, {2, 47, 26819}, {2, 49, 26819}, {3, 51, 26819}, {3, 54, 26819}, {1, 57, 26819}, {2, 58, 26819}, {4, 60, 26819}, {3, 64, 26819}, {2, 67, 26819}, {3, 69, 26819}, {1, 72, 26819}, {1, 73, 26819}, {3, 74, 26819}, {2, 77, 26819}, {4, 79, 26819}, {3, 83, 26819}, {1, 86, 26819}, {2, 87, 26819}, {2, 89, 26819}, {3, 91, 26819}, {1, 94, 26819}, {2, 95, 26819}, {1, 97, 26819}, {2, 98, 26819}, {4, 100, 26819}, {2, 104, 26819}, {2, 106, 26819}, {3, 108, 26819}, {4, 111, 26819}, {1, 115, 26819}, {4, 116, 26819}, {2, 120, 26819}, {1, 122, 26819}, {2, 123, 26819}, {2, 125, 26819}, {2, 127, 26819}, {1, 129, 26819}, {2, 130, 26819}, {1, 132, 26819}, {2, 133, 26819}, {2, 135, 26819}, {2, 137, 26819}, {2, 139, 26819}, {2, 141, 26819}, {3, 143, 26819}, {1, 146, 26819}, {3, 147, 26819}, {2, 150, 26819}, {1, 152, 26819}, {2, 153, 26819}, {2, 155, 26819}, {2, 157, 26819}, {1, 159, 26819}, {2, 160, 26819}, {2, 162, 26819}, {2, 164, 26819}, {4, 166, 26819}, {2, 170, 26819}, {2, 172, 26819}, {3, 174, 26819}, {3, 177, 26819}, {1, 180, 26819}, {3, 181, 26819}, {2, 184, 26819}, {2, 186, 26819} }; VGlyph_Path VRomanPath[] = { {2, 0}, {5, 2}, {2, 7}, {2, 9}, {2, 11}, {2, 13}, {2, 15}, {2, 17}, {2, 19}, {2, 21}, {20, 23}, {2, 43}, {16, 45}, {11, 61}, {34, 72}, {2, 106}, {10, 108}, {10, 118}, {2, 128}, {2, 130}, {2, 132}, {2, 134}, {2, 136}, {8, 138}, {2, 146}, {5, 148}, {2, 153}, {17, 155}, {4, 172}, {14, 176}, {15, 190}, {3, 205}, {2, 208}, {17, 210}, {23, 227}, {2, 250}, {2, 252}, {29, 254}, {23, 283}, {5, 306}, {5, 311}, {5, 316}, {8, 321}, {3, 329}, {2, 332}, {2, 334}, {3, 336}, {14, 339}, {5, 353}, {8, 358}, {19, 366}, {2, 385}, {2, 387}, {2, 389}, {2, 391}, {9, 393}, {10, 402}, {18, 412}, {2, 430}, {12, 432}, {2, 444}, {2, 446}, {2, 448}, {2, 450}, {2, 452}, {2, 454}, {2, 456}, {19, 458}, {2, 477}, {2, 479}, {2, 481}, {2, 483}, {2, 485}, {10, 487}, {2, 497}, {2, 499}, {2, 501}, {2, 503}, {2, 505}, {2, 507}, {2, 509}, {2, 511}, {2, 513}, {2, 515}, {2, 517}, {2, 519}, {21, 521}, {2, 542}, {10, 544}, {21, 554}, {2, 575}, {2, 577}, {10, 579}, {2, 589}, {20, 591}, {2, 611}, {2, 613}, {10, 615}, {2, 625}, {2, 627}, {2, 629}, {2, 631}, {2, 633}, {2, 635}, {2, 637}, {2, 639}, {3, 641}, {2, 644}, {2, 646}, {2, 648}, {2, 650}, {2, 652}, {2, 654}, {2, 656}, {2, 658}, {2, 660}, {2, 662}, {2, 664}, {2, 666}, {2, 668}, {2, 670}, {2, 672}, {5, 674}, {2, 679}, {3, 681}, {2, 684}, {14, 686}, {2, 700}, {14, 702}, {14, 716}, {2, 730}, {14, 732}, {17, 746}, {5, 763}, {2, 768}, {7, 770}, {14, 777}, {2, 791}, {7, 793}, {5, 800}, {2, 805}, {5, 807}, {5, 812}, {2, 817}, {2, 819}, {2, 821}, {2, 823}, {2, 825}, {7, 827}, {7, 834}, {2, 841}, {7, 843}, {17, 850}, {2, 867}, {14, 869}, {2, 883}, {14, 885}, {2, 899}, {5, 901}, {17, 906}, {5, 923}, {2, 928}, {7, 930}, {2, 937}, {2, 939}, {2, 941}, {2, 943}, {2, 945}, {2, 947}, {2, 949}, {2, 951}, {2, 953}, {2, 955}, {6, 957}, {2, 963}, {2, 965}, {2, 967}, {10, 969}, {17, 979}, {10, 996}, {2, 1006}, {10, 1008}, {17, 1018}, {10, 1035}, {11, 1045}, {11, 1056}, {2, 1067}, {17, 1069} }; VGlyph_Vertex VRomanVertex[] = { {13409, 25600}, {13409, 8533}, {13409, 2438}, {12190, 1219}, {13409, 0}, {14628, 1219}, {13409, 2438}, {8533, 25600}, {8533, 17066}, {18285, 25600}, {18285, 17066}, {14019, 30476}, {5485, -8533}, {21333, 30476}, {12800, -8533}, {5485, 14628}, {22552, 14628}, {4266, 7314}, {21333, 7314}, {10971, 30476}, {10971, -4876}, {15847, 30476}, {15847, -4876}, {21942, 21942}, {19504, 24380}, {15847, 25600}, {10971, 25600}, {7314, 24380}, {4876, 21942}, {4876, 19504}, {6095, 17066}, {7314, 15847}, {9752, 14628}, {17066, 12190}, {19504, 10971}, {20723, 9752}, {21942, 7314}, {21942, 3657}, {19504, 1219}, {15847, 0}, {10971, 0}, {7314, 1219}, {4876, 3657}, {24380, 25600}, {2438, 0}, {8533, 25600}, {10971, 23161}, {10971, 20723}, {9752, 18285}, {7314, 17066}, {4876, 17066}, {2438, 19504}, {2438, 21942}, {3657, 24380}, {6095, 25600}, {8533, 25600}, {10971, 24380}, {14628, 23161}, {18285, 23161}, {21942, 24380}, {24380, 25600}, {19504, 8533}, {17066, 7314}, {15847, 4876}, {15847, 2438}, {18285, 0}, {20723, 0}, {23161, 1219}, {24380, 3657}, {24380, 6095}, {21942, 8533}, {19504, 8533}, {25600, 14628}, {25600, 15847}, {24380, 17066}, {23161, 17066}, {21942, 15847}, {20723, 13409}, {18285, 7314}, {15847, 3657}, {13409, 1219}, {10971, 0}, {6095, 0}, {3657, 1219}, {2438, 2438}, {1219, 4876}, {1219, 7314}, {2438, 9752}, {3657, 10971}, {12190, 15847}, {13409, 17066}, {14628, 19504}, {14628, 21942}, {13409, 24380}, {10971, 25600}, {8533, 24380}, {7314, 21942}, {7314, 19504}, {8533, 15847}, {10971, 12190}, {17066, 3657}, {19504, 1219}, {21942, 0}, {24380, 0}, {25600, 1219}, {25600, 2438}, {13409, 25600}, {13409, 17066}, {17676, 30476}, {15238, 28038}, {12800, 24380}, {10361, 19504}, {9142, 13409}, {9142, 8533}, {10361, 2438}, {12800, -2438}, {15238, -6095}, {17676, -8533}, {9142, 30476}, {11580, 28038}, {14019, 24380}, {16457, 19504}, {17676, 13409}, {17676, 8533}, {16457, 2438}, {14019, -2438}, {11580, -6095}, {9142, -8533}, {13409, 18285}, {13409, 3657}, {7314, 14628}, {19504, 7314}, {19504, 14628}, {7314, 7314}, {13409, 21942}, {13409, 0}, {2438, 10971}, {24380, 10971}, {14628, 1219}, {13409, 0}, {12190, 1219}, {13409, 2438}, {14628, 1219}, {14628, -1219}, {13409, -3657}, {12190, -4876}, {2438, 10971}, {24380, 10971}, {13409, 2438}, {12190, 1219}, {13409, 0}, {14628, 1219}, {13409, 2438}, {4876, -3657}, {21942, 25600}, {12190, 25600}, {8533, 24380}, {6095, 20723}, {4876, 14628}, {4876, 10971}, {6095, 4876}, {8533, 1219}, {12190, 0}, {14628, 0}, {18285, 1219}, {20723, 4876}, {21942, 10971}, {21942, 14628}, {20723, 20723}, {18285, 24380}, {14628, 25600}, {12190, 25600}, {10361, 20723}, {12800, 21942}, {16457, 25600}, {16457, 0}, {6095, 19504}, {6095, 20723}, {7314, 23161}, {8533, 24380}, {10971, 25600}, {15847, 25600}, {18285, 24380}, {19504, 23161}, {20723, 20723}, {20723, 18285}, {19504, 15847}, {17066, 12190}, {4876, 0}, {21942, 0}, {7314, 25600}, {20723, 25600}, {13409, 15847}, {17066, 15847}, {19504, 14628}, {20723, 13409}, {21942, 9752}, {21942, 7314}, {20723, 3657}, {18285, 1219}, {14628, 0}, {10971, 0}, {7314, 1219}, {6095, 2438}, {4876, 4876}, {16457, 25600}, {4266, 8533}, {22552, 8533}, {16457, 25600}, {16457, 0}, {19504, 25600}, {7314, 25600}, {6095, 14628}, {7314, 15847}, {10971, 17066}, {14628, 17066}, {18285, 15847}, {20723, 13409}, {21942, 9752}, {21942, 7314}, {20723, 3657}, {18285, 1219}, {14628, 0}, {10971, 0}, {7314, 1219}, {6095, 2438}, {4876, 4876}, {20114, 21942}, {18895, 24380}, {15238, 25600}, {12800, 25600}, {9142, 24380}, {6704, 20723}, {5485, 14628}, {5485, 8533}, {6704, 3657}, {9142, 1219}, {12800, 0}, {14019, 0}, {17676, 1219}, {20114, 3657}, {21333, 7314}, {21333, 8533}, {20114, 12190}, {17676, 14628}, {14019, 15847}, {12800, 15847}, {9142, 14628}, {6704, 12190}, {5485, 8533}, {21942, 25600}, {9752, 0}, {4876, 25600}, {21942, 25600}, {10971, 25600}, {7314, 24380}, {6095, 21942}, {6095, 19504}, {7314, 17066}, {9752, 15847}, {14628, 14628}, {18285, 13409}, {20723, 10971}, {21942, 8533}, {21942, 4876}, {20723, 2438}, {19504, 1219}, {15847, 0}, {10971, 0}, {7314, 1219}, {6095, 2438}, {4876, 4876}, {4876, 8533}, {6095, 10971}, {8533, 13409}, {12190, 14628}, {17066, 15847}, {19504, 17066}, {20723, 19504}, {20723, 21942}, {19504, 24380}, {15847, 25600}, {10971, 25600}, {21333, 17066}, {20114, 13409}, {17676, 10971}, {14019, 9752}, {12800, 9752}, {9142, 10971}, {6704, 13409}, {5485, 17066}, {5485, 18285}, {6704, 21942}, {9142, 24380}, {12800, 25600}, {14019, 25600}, {17676, 24380}, {20114, 21942}, {21333, 17066}, {21333, 10971}, {20114, 4876}, {17676, 1219}, {14019, 0}, {11580, 0}, {7923, 1219}, {6704, 3657}, {13409, 17066}, {12190, 15847}, {13409, 14628}, {14628, 15847}, {13409, 17066}, {13409, 2438}, {12190, 1219}, {13409, 0}, {14628, 1219}, {13409, 2438}, {13409, 17066}, {12190, 15847}, {13409, 14628}, {14628, 15847}, {13409, 17066}, {14628, 1219}, {13409, 0}, {12190, 1219}, {13409, 2438}, {14628, 1219}, {14628, -1219}, {13409, -3657}, {12190, -4876}, {23161, 21942}, {3657, 10971}, {23161, 0}, {2438, 14628}, {24380, 14628}, {2438, 7314}, {24380, 7314}, {3657, 21942}, {23161, 10971}, {3657, 0}, {6095, 19504}, {6095, 20723}, {7314, 23161}, {8533, 24380}, {10971, 25600}, {15847, 25600}, {18285, 24380}, {19504, 23161}, {20723, 20723}, {20723, 18285}, {19504, 15847}, {18285, 14628}, {13409, 12190}, {13409, 8533}, {13409, 2438}, {12190, 1219}, {13409, 0}, {14628, 1219}, {13409, 2438}, {16457, 13409}, {14019, 14628}, {11580, 14628}, {10361, 12190}, {10361, 10971}, {11580, 8533}, {14019, 8533}, {16457, 9752}, {16457, 14628}, {16457, 9752}, {17676, 8533}, {20114, 8533}, {21333, 10971}, {21333, 12190}, {20114, 15847}, {17676, 18285}, {14019, 19504}, {12800, 19504}, {9142, 18285}, {6704, 15847}, {5485, 12190}, {5485, 10971}, {6704, 7314}, {9142, 4876}, {12800, 3657}, {14019, 3657}, {17676, 4876}, {13409, 25600}, {3657, 0}, {13409, 25600}, {23161, 0}, {7314, 8533}, {19504, 8533}, {4876, 25600}, {4876, 0}, {4876, 25600}, {15847, 25600}, {19504, 24380}, {20723, 23161}, {21942, 20723}, {21942, 18285}, {20723, 15847}, {19504, 14628}, {15847, 13409}, {4876, 13409}, {15847, 13409}, {19504, 12190}, {20723, 10971}, {21942, 8533}, {21942, 4876}, {20723, 2438}, {19504, 1219}, {15847, 0}, {4876, 0}, {22552, 19504}, {21333, 21942}, {18895, 24380}, {16457, 25600}, {11580, 25600}, {9142, 24380}, {6704, 21942}, {5485, 19504}, {4266, 15847}, {4266, 9752}, {5485, 6095}, {6704, 3657}, {9142, 1219}, {11580, 0}, {16457, 0}, {18895, 1219}, {21333, 3657}, {22552, 6095}, {4876, 25600}, {4876, 0}, {4876, 25600}, {13409, 25600}, {17066, 24380}, {19504, 21942}, {20723, 19504}, {21942, 15847}, {21942, 9752}, {20723, 6095}, {19504, 3657}, {17066, 1219}, {13409, 0}, {4876, 0}, {5485, 25600}, {5485, 0}, {5485, 25600}, {21333, 25600}, {5485, 13409}, {15238, 13409}, {5485, 0}, {21333, 0}, {5485, 25600}, {5485, 0}, {5485, 25600}, {21333, 25600}, {5485, 13409}, {15238, 13409}, {22552, 19504}, {21333, 21942}, {18895, 24380}, {16457, 25600}, {11580, 25600}, {9142, 24380}, {6704, 21942}, {5485, 19504}, {4266, 15847}, {4266, 9752}, {5485, 6095}, {6704, 3657}, {9142, 1219}, {11580, 0}, {16457, 0}, {18895, 1219}, {21333, 3657}, {22552, 6095}, {22552, 9752}, {16457, 9752}, {22552, 9752}, {4876, 25600}, {4876, 0}, {21942, 25600}, {21942, 0}, {4876, 13409}, {21942, 13409}, {13409, 25600}, {13409, 0}, {19504, 25600}, {19504, 6095}, {18285, 2438}, {17066, 1219}, {14628, 0}, {12190, 0}, {9752, 1219}, {8533, 2438}, {7314, 6095}, {7314, 8533}, {4876, 25600}, {4876, 0}, {21942, 25600}, {4876, 8533}, {10971, 14628}, {21942, 0}, {6095, 25600}, {6095, 0}, {6095, 0}, {20723, 0}, {3657, 25600}, {3657, 0}, {3657, 25600}, {13409, 0}, {23161, 25600}, {13409, 0}, {23161, 25600}, {23161, 0}, {4876, 25600}, {4876, 0}, {4876, 25600}, {21942, 0}, {21942, 25600}, {21942, 0}, {10971, 25600}, {8533, 24380}, {6095, 21942}, {4876, 19504}, {3657, 15847}, {3657, 9752}, {4876, 6095}, {6095, 3657}, {8533, 1219}, {10971, 0}, {15847, 0}, {18285, 1219}, {20723, 3657}, {21942, 6095}, {23161, 9752}, {23161, 15847}, {21942, 19504}, {20723, 21942}, {18285, 24380}, {15847, 25600}, {10971, 25600}, {4876, 25600}, {4876, 0}, {4876, 25600}, {15847, 25600}, {19504, 24380}, {20723, 23161}, {21942, 20723}, {21942, 17066}, {20723, 14628}, {19504, 13409}, {15847, 12190}, {4876, 12190}, {10971, 25600}, {8533, 24380}, {6095, 21942}, {4876, 19504}, {3657, 15847}, {3657, 9752}, {4876, 6095}, {6095, 3657}, {8533, 1219}, {10971, 0}, {15847, 0}, {18285, 1219}, {20723, 3657}, {21942, 6095}, {23161, 9752}, {23161, 15847}, {21942, 19504}, {20723, 21942}, {18285, 24380}, {15847, 25600}, {10971, 25600}, {14628, 4876}, {21942, -8600}, {4876, 25600}, {4876, 0}, {4876, 25600}, {15847, 25600}, {19504, 24380}, {20723, 23161}, {21942, 20723}, {21942, 18285}, {20723, 15847}, {19504, 14628}, {15847, 13409}, {4876, 13409}, {13409, 13409}, {21942, 0}, {21942, 21942}, {19504, 24380}, {15847, 25600}, {10971, 25600}, {7314, 24380}, {4876, 21942}, {4876, 19504}, {6095, 17066}, {7314, 15847}, {9752, 14628}, {17066, 12190}, {19504, 10971}, {20723, 9752}, {21942, 7314}, {21942, 3657}, {19504, 1219}, {15847, 0}, {10971, 0}, {7314, 1219}, {4876, 3657}, {13409, 25600}, {13409, 0}, {4876, 25600}, {21942, 25600}, {4876, 25600}, {4876, 7314}, {6095, 3657}, {8533, 1219}, {12190, 0}, {14628, 0}, {18285, 1219}, {20723, 3657}, {21942, 7314}, {21942, 25600}, {3657, 25600}, {13409, 0}, {23161, 25600}, {13409, 0}, {1219, 25600}, {7314, 0}, {13409, 25600}, {7314, 0}, {13409, 25600}, {19504, 0}, {25600, 25600}, {19504, 0}, {4876, 25600}, {21942, 0}, {21942, 25600}, {4876, 0}, {3657, 25600}, {13409, 13409}, {13409, 0}, {23161, 25600}, {13409, 13409}, {21942, 25600}, {4876, 0}, {4876, 25600}, {21942, 25600}, {4876, 0}, {21942, 0}, {9142, 30476}, {9142, -8533}, {10361, 30476}, {10361, -8533}, {9142, 30476}, {17676, 30476}, {9142, -8533}, {17676, -8533}, {4876, 25600}, {21942, -3657}, {16457, 30476}, {16457, -8533}, {17676, 30476}, {17676, -8533}, {9142, 30476}, {17676, 30476}, {9142, -8533}, {17676, -8533}, {13409, 28038}, {3657, 10971}, {13409, 28038}, {23161, 10971}, {0, -8533}, {26819, -8533}, {26819, -7314}, {0, -7314}, {0, -8533}, {10971, 25600}, {17066, 18285}, {10971, 25600}, {9752, 24380}, {17066, 18285}, {20723, 20000}, {20723, 0}, {20723, 9000}, {14285, 17066}, {12847, 17066}, {12190, 17066}, {9752, 15847}, {7314, 13409}, {6095, 9752}, {6095, 7314}, {7314, 3657}, {9752, 1219}, {12190, 0}, {15847, 0}, {18285, 1219}, {20723, 3657}, {6095, 25600}, {6095, 0}, {6095, 13409}, {8533, 15847}, {10971, 17066}, {14628, 17066}, {17066, 15847}, {19504, 13409}, {20723, 9752}, {20723, 7314}, {19504, 3657}, {17066, 1219}, {14628, 0}, {10971, 0}, {8533, 1219}, {6095, 3657}, {20723, 13409}, {18285, 15847}, {15847, 17066}, {12190, 17066}, {9752, 15847}, {7314, 13409}, {6095, 9752}, {6095, 7314}, {7314, 3657}, {9752, 1219}, {12190, 0}, {15847, 0}, {18285, 1219}, {20723, 3657}, {20723, 25600}, {20723, 0}, {20723, 13409}, {18285, 15847}, {15847, 17066}, {12190, 17066}, {9752, 15847}, {7314, 13409}, {6095, 9752}, {6095, 7314}, {7314, 3657}, {9752, 1219}, {12190, 0}, {15847, 0}, {18285, 1219}, {20723, 3657}, {6095, 9752}, {20723, 9752}, {20723, 12190}, {19504, 14628}, {18285, 15847}, {15847, 17066}, {12190, 17066}, {9752, 15847}, {7314, 13409}, {6095, 9752}, {6095, 7314}, {7314, 3657}, {9752, 1219}, {12190, 0}, {15847, 0}, {18285, 1219}, {20723, 3657}, {18285, 25600}, {15847, 25600}, {13409, 24380}, {12190, 20723}, {12190, 0}, {8533, 17066}, {17066, 17066}, {20723, 17066}, {20723, -2438}, {19504, -6095}, {18285, -7314}, {15847, -8533}, {12190, -8533}, {9752, -7314}, {20723, 13409}, {18285, 15847}, {15847, 17066}, {12190, 17066}, {9752, 15847}, {7314, 13409}, {6095, 9752}, {6095, 7314}, {7314, 3657}, {9752, 1219}, {12190, 0}, {15847, 0}, {18285, 1219}, {20723, 3657}, {6704, 25600}, {6704, 0}, {6704, 12190}, {10361, 15847}, {12800, 17066}, {16457, 17066}, {18895, 15847}, {20114, 12190}, {20114, 0}, {12190, 25600}, {13409, 24380}, {14628, 25600}, {13409, 26819}, {12190, 25600}, {13409, 17066}, {13409, 0}, {14628, 25600}, {15847, 24380}, {17066, 25600}, {15847, 26819}, {14628, 25600}, {15847, 17066}, {15847, -3657}, {14628, -7314}, {12190, -8533}, {9752, -8533}, {6704, 25600}, {6704, 0}, {18895, 17066}, {6704, 4876}, {11580, 9752}, {20114, 0}, {13409, 25600}, {13409, 0}, {0, 17066}, {0, 0}, {0, 12190}, {3657, 15847}, {6095, 17066}, {9752, 17066}, {12190, 15847}, {13409, 12190}, {13409, 0}, {13409, 12190}, {17066, 15847}, {19504, 17066}, {23161, 17066}, {25600, 15847}, {26819, 12190}, {26819, 0}, {6704, 17066}, {6704, 0}, {6704, 12190}, {10361, 15847}, {12800, 17066}, {16457, 17066}, {18895, 15847}, {20114, 12190}, {20114, 0}, {11580, 17066}, {9142, 15847}, {6704, 13409}, {5485, 9752}, {5485, 7314}, {6704, 3657}, {9142, 1219}, {11580, 0}, {15238, 0}, {17676, 1219}, {20114, 3657}, {21333, 7314}, {21333, 9752}, {20114, 13409}, {17676, 15847}, {15238, 17066}, {11580, 17066}, {6095, 17066}, {6095, -8533}, {6095, 13409}, {8533, 15847}, {10971, 17066}, {14628, 17066}, {17066, 15847}, {19504, 13409}, {20723, 9752}, {20723, 7314}, {19504, 3657}, {17066, 1219}, {14628, 0}, {10971, 0}, {8533, 1219}, {6095, 3657}, {20723, 17066}, {20723, -8533}, {20723, 13409}, {18285, 15847}, {15847, 17066}, {12190, 17066}, {9752, 15847}, {7314, 13409}, {6095, 9752}, {6095, 7314}, {7314, 3657}, {9752, 1219}, {12190, 0}, {15847, 0}, {18285, 1219}, {20723, 3657}, {8533, 17066}, {8533, 0}, {8533, 9752}, {9752, 13409}, {12190, 15847}, {14628, 17066}, {18285, 17066}, {20114, 13409}, {18895, 15847}, {15238, 17066}, {11580, 17066}, {7923, 15847}, {6704, 13409}, {7923, 10971}, {10361, 9752}, {16457, 8533}, {18895, 7314}, {20114, 4876}, {20114, 3657}, {18895, 1219}, {15238, 0}, {11580, 0}, {7923, 1219}, {6704, 3657}, {12190, 25600}, {12190, 4876}, {13409, 1219}, {15847, 0}, {18285, 0}, {8533, 17066}, {17066, 17066}, {6704, 17066}, {6704, 4876}, {7923, 1219}, {10361, 0}, {14019, 0}, {16457, 1219}, {20114, 4876}, {20114, 17066}, {20114, 0}, {6095, 17066}, {13409, 0}, {20723, 17066}, {13409, 0}, {3657, 17066}, {8533, 0}, {13409, 17066}, {8533, 0}, {13409, 17066}, {18285, 0}, {23161, 17066}, {18285, 0}, {6704, 17066}, {20114, 0}, {20114, 17066}, {6704, 0}, {6704, 17066}, {14019, 0}, {21333, 17066}, {14019, 0}, {11580, -4876}, {9142, -7314}, {6704, -8533}, {5485, -8533}, {20114, 17066}, {6704, 0}, {6704, 17066}, {20114, 17066}, {6704, 0}, {20114, 0}, {16457, 30476}, {14019, 29257}, {12800, 28038}, {11580, 25600}, {11580, 23161}, {12800, 20723}, {14019, 19504}, {15238, 17066}, {15238, 14628}, {12800, 12190}, {14019, 29257}, {12800, 26819}, {12800, 24380}, {14019, 21942}, {15238, 20723}, {16457, 18285}, {16457, 15847}, {15238, 13409}, {10361, 10971}, {15238, 8533}, {16457, 6095}, {16457, 3657}, {15238, 1219}, {14019, 0}, {12800, -2438}, {12800, -4876}, {14019, -7314}, {12800, 9752}, {15238, 7314}, {15238, 4876}, {14019, 2438}, {12800, 1219}, {11580, -1219}, {11580, -3657}, {12800, -6095}, {14019, -7314}, {16457, -8533}, {13409, 30476}, {13409, -8533}, {10361, 30476}, {12800, 29257}, {14019, 28038}, {15238, 25600}, {15238, 23161}, {14019, 20723}, {12800, 19504}, {11580, 17066}, {11580, 14628}, {14019, 12190}, {12800, 29257}, {14019, 26819}, {14019, 24380}, {12800, 21942}, {11580, 20723}, {10361, 18285}, {10361, 15847}, {11580, 13409}, {16457, 10971}, {11580, 8533}, {10361, 6095}, {10361, 3657}, {11580, 1219}, {12800, 0}, {14019, -2438}, {14019, -4876}, {12800, -7314}, {14019, 9752}, {11580, 7314}, {11580, 4876}, {12800, 2438}, {14019, 1219}, {15238, -1219}, {15238, -3657}, {14019, -6095}, {12800, -7314}, {10361, -8533}, {2438, 7314}, {2438, 9752}, {3657, 13409}, {6095, 14628}, {8533, 14628}, {10971, 13409}, {15847, 9752}, {18285, 8533}, {20723, 8533}, {23161, 9752}, {24380, 12190}, {2438, 9752}, {3657, 12190}, {6095, 13409}, {8533, 13409}, {10971, 12190}, {15847, 8533}, {18285, 7314}, {20723, 7314}, {23161, 8533}, {24380, 12190}, {24380, 14628}, {18285, 25600}, {8533, -8533}, {12190, 17066}, {8533, 15847}, {6095, 13409}, {4876, 9752}, {4876, 6095}, {6095, 3657}, {8533, 1219}, {12190, 0}, {14628, 0}, {18285, 1219}, {20723, 3657}, {21942, 7314}, {21942, 10971}, {20723, 13409}, {18285, 15847}, {14628, 17066}, {12190, 17066} }; acm-6.0_20200416/src/V/Makefile0000644000000000000000000000262113155536400014232 0ustar rootroot# This file generated by make-makefile, do not edit! # Create Makefile-include.txt instead for your customizations. CC := gcc CFLAGS := -Wall -Werror -g -fmax-errors=99 -Wuninitialized -Wmissing-prototypes -Wredundant-decls LIBS := .PHONY: all all: make Alib.o VColor.o VGlyph.o VObjects.o VPoly.o VRoman.o Vlib.o Vlibmath.o #include Makefile-include.txt .PHONY: clean clean: rm -f *.o *.exe *.stackdump Alib.o: Alib.c Alib.h ../util/error.h ../util/gui.h ../util/memory.h ../util/units.h VColor.h VPoly.h Vlibmath.h $(CC) $(CFLAGS) -c Alib.c -o Alib.o VColor.o: VColor.c VColor.h ../util/error.h ../util/gui.h ../util/memory.h ../util/sparsearray.h $(CC) $(CFLAGS) -c VColor.c -o VColor.o VGlyph.o: VGlyph.c VGlyph.h $(CC) $(CFLAGS) -c VGlyph.c -o VGlyph.o VObjects.o: VObjects.c VObjects.h ../util/error.h ../util/memory.h ../util/units.h VColor.h VPoly.h Vlibmath.h $(CC) $(CFLAGS) -c VObjects.c -o VObjects.o VPoly.o: VPoly.c VPoly.h ../util/error.h ../util/memory.h ../util/units.h VColor.h Vlibmath.h $(CC) $(CFLAGS) -c VPoly.c -o VPoly.o VRoman.o: VRoman.c VRoman.h VGlyph.h $(CC) $(CFLAGS) -c VRoman.c -o VRoman.o Vlib.o: Vlib.c Vlib.h ../util/gui.h ../util/memory.h ../util/units.h Alib.h VColor.h VGlyph.h VPoly.h VRoman.h Vlibmath.h $(CC) $(CFLAGS) -c Vlib.c -o Vlib.o Vlibmath.o: Vlibmath.c Vlibmath.h $(CC) $(CFLAGS) -c Vlibmath.c -o Vlibmath.o # Checksum of the original file: 4113147918 acm-6.0_20200416/src/V/Vlib.c0000644000000000000000000002173313170025320013626 0ustar rootroot#include #include "../util/memory.h" #include "VRoman.h" #define Vlib_IMPORT #include "Vlib.h" #define COLLAPSEUNUSEDPOINTS static void VComputeClipNormals(Viewport * v) { VPoint *p, *q; int i, max; double mag; p = v->clipPoly->vertex; q = v->clipNormals; /* * We only reserved space for four clipping plane normals in clipNormals */ max = (v->clipPoly->numVtces > 4) ? 4 : v->clipPoly->numVtces; /* * Compute the unit-normal vectors corresponding to each clipping plane */ for (i = 0; i < max; ++i) { mag = sqrt(p->x * p->x + p->y * p->y + p->z * p->z); q->x = p->x / mag; q->y = p->y / mag; q->z = p->z / mag; q++; p++; } } static void set_size_and_scale( Viewport * v, Alib_Rect * view_rect, Alib_Point *focus, double dist) { VPoint a, b, clip[4]; Alib_Rect r; Alib_setRect(&r, 0, 0, gui_getWidth(v->gui), gui_getHeight(v->gui)); Alib_intersectRect(view_rect, &r, &v->rect); v->focus = *focus; v->dist = dist; /* * Use that info to set scaling factors. */ v->Scale.x = v->xres * dist * 4; v->Scale.y = v->yres * dist * 4; v->Scale.z = 1.0; /* * Middl should have been a "double" for accuracy, but was made an "int" for * speed. Sooo, to eliminate some stick rounding problems, we'll consider it * a fixed point number with the right two bits after the decimal point. */ v->Middl.x = 4 * focus->x; v->Middl.y = 4 * focus->y; /* Build the clipping planes for our view into the eye space. The eye is located in (0,0,0) and looking toward the z+ axis, x=right, y=down. The projection rectangle v->rect is located at z=dist and parallel to xy. The z axis intersects the projection screen in its "focus" point. Begin calculating the points "a" (top-left corner of the screen) and "b" (bottom-right corner) in meters: */ VSetPoint(&a, (v->rect.a.x - focus->x) / v->xres, (v->rect.a.y - focus->y) / v->yres, dist); VSetPoint(&b, (v->rect.b.x - focus->x) / v->xres, (v->rect.b.y - focus->y) / v->yres, dist); clip[0] = a; VSetPoint(&clip[1], a.x, b.y, dist); clip[2] = b; VSetPoint(&clip[3], b.x, a.y, dist); v->clipPoly = VCreatePolygon(4, clip, (VColor_Type *) 0); VGetPlanes(v->clipPoly); VComputeClipNormals(v); VIdentMatrix(&v->eyeSpace); } static void Vlib_destruct(void *p) { Viewport *v = p; VDestroyPolygon(v->clipPoly); } Viewport * Vlib_new ( gui_Type * gui, Alib_Window *w, Alib_Rect *view_rect, Alib_Point *focus, double dist) { Viewport *v = memory_allocate(sizeof(Viewport), Vlib_destruct); memset(v, 0, sizeof(sizeof(Viewport))); v->gui = gui; v->w = w; v->flags = VPPerspective | VPClip; /* FIXME: enable also VPDoubleBuffer */ gui_DisplayDimensions dd; gui_getDisplayDimensions(gui, &dd); v->xres = 1000.0 * dd.widthPixels / dd.widthMillimiters; v->yres = 1000.0 * dd.heightPixels / dd.heightMillimiters; set_size_and_scale(v, view_rect, focus, dist); return v; } void VResizeViewport ( Viewport *v, Alib_Rect *view_rect, Alib_Point *focus, double dist) { VDestroyPolygon(v->clipPoly); set_size_and_scale(v, view_rect, focus, dist); } void VDrawSegments(Viewport * v, Alib_Segment * seg, int nseg, Alib_Pixel color) { Alib_drawSegments(v->w, seg, nseg, color); } int VFontWidthPixels(Viewport * v, int scale) { return VRomanGlyph['A'].glyph_width * scale / 25600; } void VDrawStrokeString(Viewport * v, int x, int y, char *str, int len, int scale, Alib_Pixel color) { int c, i, k, m; VGlyph_Vertex *p; int x1, y1, x2, y2; for (; len > 0; --len) { if ((c = *str++) < 128) { k = VRomanGlyph[c].path_start; for (i = 0; i < VRomanGlyph[c].path_count; ++i, ++k) { p = &VRomanVertex[VRomanPath[k].vertex_start]; x1 = p->x * scale / 25600 + x; y1 = y - p->y * scale / 25600; ++p; for (m = 1; m < VRomanPath[k].vertex_count; ++m, ++p) { x2 = p->x * scale / 25600 + x; y2 = y - p->y * scale / 25600; Alib_drawLine(v->w, x1, y1, x2, y2, color); x1 = x2; y1 = y2; } } x += VRomanGlyph[c].glyph_width * scale / 25600; } } } void VGetStrokeString(Viewport * v, int x, int y, Alib_Segment * seg, int *nseg, char *str, int len, int scale) { int c, i, k, m, count; VGlyph_Vertex *p; int x1, y1, x2, y2; Alib_Segment *pseg; count = *nseg; for (; len > 0; --len) { if ((c = *str++) < 128) { k = VRomanGlyph[c].path_start; for (i = 0; i < VRomanGlyph[c].path_count; ++i, ++k) { p = &VRomanVertex[VRomanPath[k].vertex_start]; x1 = p->x * scale / 25600 + x; y1 = y - p->y * scale / 25600; ++p; for (m = 1; m < VRomanPath[k].vertex_count; ++m, ++p) { x2 = p->x * scale / 25600 + x; y2 = y - p->y * scale / 25600; pseg = &seg[count++]; pseg->x1 = x1; pseg->x2 = x2; pseg->y1 = y1; pseg->y2 = y2; x1 = x2; y1 = y2; } } x += VRomanGlyph[c].glyph_width * scale / 25600; } } *nseg = count; } void VFillPolygon(Viewport * v, VPolygon * poly) { VPoint *p; Alib_Point xpt[VmaxVP]; #ifdef COLLAPSEUNUSEDPOINTS Alib_Point *lastpt; #endif int i, k; Alib_Window *w; w = v->w; k = 0; #ifdef COLLAPSEUNUSEDPOINTS lastpt = &xpt[0]; #endif for ((i = 0, p = poly->vertex); i < poly->numVtces; (++i, ++p)) { if (v->flags & VPPerspective && p->z != 0.0 /* FIXME */) { xpt[k].x = (v->Middl.x + (int) (v->Scale.x * p->x / p->z)) >> 2; xpt[k].y = (v->Middl.y + (int) (v->Scale.y * p->y / p->z)) >> 2; } else { xpt[k].x = (v->Middl.x + (int) (v->Scale.x * p->x)) >> 2; xpt[k].y = (v->Middl.y + (int) (v->Scale.y * p->y)) >> 2; } #ifdef COLLAPSEUNUSEDPOINTS if (k == 0 || !(xpt[k].x == lastpt->x && xpt[k].y == lastpt->y)) lastpt = &xpt[k++]; #else ++k; #endif } if (k > 0) { #ifdef COLLAPSEUNUSEDPOINTS if ( k > 2 ){ /* if (k == 1){ Alib_drawPoint(w, xpt[0].x, xpt[0].y, z); } else if (k == 2){ DrawLine(w, xpt[0].x, xpt[0].y, xpt[1].x, xpt[1].y, z); } else { */ #endif Alib_Pixel color = Alib_computePolygonColor(w, poly); Alib_fillPolygon(w, xpt, k, color); #ifdef COLLAPSEUNUSEDPOINTS } #endif } } void VFillRectangle (Viewport *v, Alib_Rect *r, Alib_Pixel c) { Alib_fillRect( v->w, r, c ); } VPolygon * VGetPlanes(VPolygon * poly) { VPoint tmp[VmaxVP], *p; int i, lasti; lasti = poly->numVtces - 1; p = poly->vertex; for (i = 0; i < poly->numVtces; ++i) { tmp[i].x = p->y * poly->vertex[lasti].z - p->z * poly->vertex[lasti].y; tmp[i].y = p->z * poly->vertex[lasti].x - p->x * poly->vertex[lasti].z; tmp[i].z = p->x * poly->vertex[lasti].y - p->y * poly->vertex[lasti].x; lasti = i; p++; } for (i = 0; i < poly->numVtces; ++i) poly->vertex[i] = tmp[i]; return poly; } void VSetClipRect (Viewport *v, Alib_Rect *r) { Alib_Rect clip; Alib_intersectRect(&v->rect, r, &clip); Alib_setClipRect(v->w, &clip); } void VExposeBuffer(Viewport * v) { Alib_drawDifferences(v->w); } void VForceWindowRedraw(Viewport * v) { Alib_invalidate(v->w); } int VEyeToScreen(Viewport * v, VPoint * p, int *x, int *y) { if (p->z <= 0.0) return 0; *x = (v->Middl.x + (int) (v->Scale.x * p->x / p->z)) >> 2; *y = (v->Middl.y + (int) (v->Scale.y * p->y / p->z)) >> 2; return 1; } void VGetEyeSpace(Viewport * v, VPoint EyePt, VPoint CntrInt, VPoint up) { VMatrix Mtx, es; VPoint C1, C2; double Hypotenuse, h1, CosA, SinA; /* * Calculate the eye space transformation matrix * * First, orient the Z axis towards the center of interest. */ VIdentMatrix(&(v->eyeSpace)); v->eyeSpace.m[0][3] = -EyePt.x; v->eyeSpace.m[1][3] = -EyePt.y; v->eyeSpace.m[2][3] = -EyePt.z; VTransform(&CntrInt, &(v->eyeSpace), &C1); VIdentMatrix(&Mtx); Hypotenuse = sqrt(C1.x * C1.x + C1.y * C1.y); if (Hypotenuse > 0.0) { CosA = C1.y / Hypotenuse; SinA = C1.x / Hypotenuse; Mtx.m[0][0] = Mtx.m[1][1] = CosA; Mtx.m[1][0] = SinA; Mtx.m[0][1] = -SinA; es = v->eyeSpace; VMatrixMult(&es, &Mtx, &(v->eyeSpace)); } VTransform(&CntrInt, &(v->eyeSpace), &C2); VIdentMatrix(&Mtx); Hypotenuse = sqrt(C2.y * C2.y + C2.z * C2.z); if (Hypotenuse > 0.0) { CosA = C2.y / Hypotenuse; SinA = -C2.z / Hypotenuse; Mtx.m[1][1] = Mtx.m[2][2] = CosA; Mtx.m[2][1] = SinA; Mtx.m[1][2] = -SinA; es = v->eyeSpace; VMatrixMult(&es, &Mtx, &(v->eyeSpace)); } /* * Orient the y axis towards "up". */ VTransform(&up, &(v->eyeSpace), &C2); VIdentMatrix(&Mtx); h1 = sqrt(C2.y * C2.y + C2.z * C2.z); Hypotenuse = sqrt(C2.x * C2.x + h1 * h1); if (Hypotenuse > 0.0) { CosA = h1 / Hypotenuse; SinA = C2.x / Hypotenuse; if (C2.z < 0.0) { CosA = -CosA; } Mtx.m[0][0] = Mtx.m[2][2] = CosA; Mtx.m[2][0] = SinA; Mtx.m[0][2] = -SinA; es = v->eyeSpace; VMatrixMult(&es, &Mtx, &(v->eyeSpace)); } /* * Swap y and z axes. */ VIdentMatrix(&Mtx); Mtx.m[1][1] = Mtx.m[2][2] = 0.0; Mtx.m[2][1] = Mtx.m[1][2] = 1.0; Mtx.m[1][2] = -1.0; /* FIXME -- remove, test code */ es = v->eyeSpace; VMatrixMult(&es, &Mtx, &(v->eyeSpace)); } int VWorldToScreen(Viewport * v, VPoint * p, int *x, int *y) { VPoint eyept; VTransform(p, &(v->eyeSpace), &eyept); return VEyeToScreen(v, &eyept, x, y); } acm-6.0_20200416/src/V/VPoly.h0000644000000000000000000001067713141044030014012 0ustar rootroot#ifndef _VPOLY_H #define _VPOLY_H #include #include "Vlibmath.h" #include "VColor.h" #include "../util/units.h" #ifdef VPoly_IMPORT #define EXTERN #else #define EXTERN extern #endif #define VmaxVP 2048 /* max # of vertices in a polygon */ #define NUM_ASPECTS 10 /* (VPolygon)->flags: */ #define PolyClipBackface 0x01 /* Polygon is "one-sided" */ #define PolyUseBackColor 0x02 /* should be rendered using backColor */ #define PolyNormalValid 0x04 /* "normal" contains valid info */ #define PolyUseCullDistance 0x08 /* cullDistance should be tested before plotting */ typedef struct { short flags; /* (see flags above) */ short numVtces; /* vertex count */ VPoint normal; /* normal vector, available only if PolyNormalValid flag is set */ VPoint *vertex; /* pointer to array of vertices (& normal) */ VColor_Type *color; /* pointer to color descriptor */ VColor_Type *backColor; /* pointer to back's color (sometimes NULL) */ double cullDistance; /* this polygon is ignored beyond this distance */ } VPolygon; struct _euler { double yaw; double pitch; }; /* Views corresponding to each of the eight defined major aspects */ EXTERN struct _euler view[] #ifdef VPoly_IMPORT = { {units_DEGtoRAD(90.0), units_DEGtoRAD(0.0)}, /* 0 - right */ {units_DEGtoRAD(-90.0), units_DEGtoRAD(0.0)}, /* 1 - left */ {units_DEGtoRAD(45.0), units_DEGtoRAD(45.0)}, /* 2 - front right bottom */ {units_DEGtoRAD(45.0), units_DEGtoRAD(-45.0)}, /* 3 - front right top */ {units_DEGtoRAD(-45.0), units_DEGtoRAD(45.0)}, /* 4 - front left bottom */ {units_DEGtoRAD(-45.0), units_DEGtoRAD(-45.0)}, /* 5 - front left top */ {units_DEGtoRAD(135.0), units_DEGtoRAD(45.0)}, /* 6 - aft right bottom */ {units_DEGtoRAD(135.0), units_DEGtoRAD(-45.0)}, /* 7 - aft right top */ {units_DEGtoRAD(-135.0), units_DEGtoRAD(45.0)}, /* 8 - aft left bottom */ {units_DEGtoRAD(-135.0), units_DEGtoRAD(-45.0)}, /* 9 - aft left top */ } #endif ; EXTERN char *VGetAspectName (int aspect); EXTERN VPolygon *VCreatePolygon (int npts, VPoint * pts, VColor_Type *); #define VDestroyPolygon(a) {if((a)!=NULL){memory_dispose(a->vertex); memory_dispose(a);}} /** * VPolySet data type is a set that can contain zero or more VPolygon(s). * Polygons can be added but cannot be removed. Typical usage: */ typedef struct VPolySet VPolySet; /** * Allocates a new set of polygons. */ EXTERN VPolySet * VPolySet_New(void); /** * Release the set from memory. The flag says if also the VPolygon(s) the * set points to have to be released with VDestroyPolygon(). */ EXTERN void VPolySet_Free(VPolySet *s, int release_polygons_too); /** * Empties the set to zero elements without actually releasing the memory, * so the set can be re-used several times. The flag says if the polygons * have to released with VDestroyPolygon(). */ EXTERN void VPolySet_Empty(VPolySet *s, int release_polygons_too); /** * Add the polygon to the set. Polygons are not copied, only their pointer * it is. */ EXTERN void VPolySet_Add(VPolySet *s, VPolygon *p); /** * Start a new scanning sequence of the set, and return the first polygon * of this sequence. Return NULL if the set is empty. */ EXTERN VPolygon * VPolySet_First(VPolySet *s); /** * Return the pointer to the next polygon in set, or NULL if the scanning * sequence is terminated and all the polygons scanned. */ EXTERN VPolygon * VPolySet_Next(VPolySet *s); /** * Set the value of the current entry with a new one. */ EXTERN void VPolySet_Set(VPolySet *s, VPolygon *poly); /** * Return the number of polygons in the set. */ EXTERN int VPolySet_Count(VPolySet *s); EXTERN VPolygon *VCreatePolygonFromTemplate (int npts, VPoint * pts, VPolygon * templ); EXTERN VPolygon *VCopyPolygon (VPolygon *); EXTERN void VPrintPolygon (FILE * file, VPolygon * p); EXTERN VPolygon * VTransformPolygon (VPolygon * poly, VMatrix * m); EXTERN VPolygon * VClipPolygon(VPolygon * poly, VPolygon * clipPoly); /** * Clip polygon 'poly' against the view frustum 'clipPoly'. The original * polygon gets destroyed and released and the new clipped one is * returned. Return NULL if not visible at all. */ EXTERN VPolygon * VClipSidedPolygon(VPolygon * poly, VPolygon * clipPoly); EXTERN VPolygon * ScalePolygon(VPolygon * in, VPoint * offset, VPoint * scale, VPoint *e, double r); #undef EXTERN #endif acm-6.0_20200416/src/V/VRoman.h0000644000000000000000000000057113063667560014161 0ustar rootroot/** * The "Roman" vectorial font. * * @file */ #ifndef _VROMAN_H #define _VROMAN_H #include "VGlyph.h" #ifdef VRoman_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * The ASCII character set, index being the ASCII code. */ EXTERN VGlyph_Type VRomanGlyph[]; EXTERN VGlyph_Path VRomanPath[]; EXTERN VGlyph_Vertex VRomanVertex[]; #undef EXTERN #endif acm-6.0_20200416/src/V/VColor.h0000644000000000000000000000406613141045366014155 0ustar rootroot/** * Stores a table of RGB colors with depth cueing flag and index to the CLUT * created by the GUI module. * The table is automatically released from memory when the program terminates. * * Note that the GUI module does not store the exact RGB value but only the * index to the closest matching entry in the CLUT, while Alib needs the RGB * value and the depth cueing flag to do the haze effect. * * @file * @author Umberto Salsi * @version $Date: 2017/08/04 10:22:46 $ */ #ifndef VCOLOR_H #define VCOLOR_H #ifdef VColor_IMPORT #define EXTERN #else #define EXTERN extern #endif typedef struct VColor_Type VColor_Type; /** * Returns the color specified by RGB value. * @param red [0,255]. * @param green [0,255]. * @param blue [0,255]. * @param is_depth_cueing True if depth cueing is enabled on this color. * @return Pointer to new or cached color. */ EXTERN VColor_Type * VColor_getByRGB(int red, int green, int blue, int is_depth_cueing); /** * Returns the color specified by name. * @param name Descriptive string of the color name (example: "red") or * hexadecimal RGB value (examples: "#f00", "#ff0000"). * @param is_depth_cueing * @return */ EXTERN VColor_Type * VColor_getByName(char *name, int is_depth_cueing); /** * Returns the index of this color in the CLUT of the GUI module. * @param c Subject color. * @return Index of this color in the CLUT of the GUI module. */ EXTERN int VColor_getIndex(VColor_Type *c); /** * Tells if this color has to be depth cued. * @param c Subject color. * @return True if this color has to be depth cued. */ EXTERN int VColor_isDepthCueing(VColor_Type *c); EXTERN int VColor_getRed(VColor_Type *c); EXTERN int VColor_getGreen(VColor_Type *c); EXTERN int VColor_getBlue(VColor_Type *c); /** * Formats and then returns the color name in the hexadecimal notation. * @param c Subject color. * @return Pointer to a statically allocated string where the hexadecimal RGB * value of the long form "#HHHHHH" is retrieved. */ EXTERN char * VColor_getName(VColor_Type *c); #undef EXTERN #endif acm-6.0_20200416/src/V/README0000644000000000000000000000101513132477067013456 0ustar rootrootVlib and Alib ------------- This directory basically contains the modules Alib and Vlib. Alib is a 2-D graphic library with support for z-buffer drawing. It is based on the GUI module which in turn is the abstract window graphic module supporting both X-Window and MS Windows. Vlib is the higher-level abstraction layer that collects all the 3-D routines that draw over a Viewport: lines, polygons, etc. Vlib routines are based on the Alib library and its z-buffer, and some functions are simply a wrapper to this latter. acm-6.0_20200416/src/V/Alib.c0000644000000000000000000012031313172245425013607 0ustar rootroot#include #include #include #include "../util/error.h" #include "../util/memory.h" #define Alib_IMPORT #include "Alib.h" /* #define FLOAT_SLOPE Comment-out this macro if you want "int" precision arithmetic on line slopes: faster but some garbage on the screen may appear. */ /** * NOTE. Max no. of ColorSegment per ScanLine. Its value depends on the * complexity of the image. Increase if you get the "Color Segment pool * overflow" error. In the worst case this value is the width of the window. */ #define MAX_CS_PER_LINE 128 #define NotAnElement ((Alib_ZInfo *) -1) #define MaxDepth 0xFFFFFFFF /** * Max no. of colors, that is the length of the CLUT. */ #define Alib_MaxPixelValue (17*17*17) /* * Bit masks for the "flags" fields of the window. Currently set in the * constructor, no client access to them. */ #define Alib_ModeDepthCueing 32 /* Perform depth cueing */ #define Alib_ModeDepthCueParsed 64 /* Pixel has been assigned to dc color */ struct Alib_ZInfo { Alib_Pixel color; /* color of this polygon */ unsigned int depth; /* depth of this polygon */ Alib_ZInfo *next; /* next polygon in plane sweep set */ Alib_ZInfo *prev; /* previous polygon in plane sweep set */ }; /** * Polygons are built from edges. */ typedef struct Edge { short y2; /* Ending y location */ #ifdef FLOAT_SLOPE float x1; /* Starting x location */ float Dx; /* Inverse slope of edge line */ #else long x1; /* Starting x location */ long Dx; /* Inverse slope of edge line */ #endif Alib_ZInfo *p; /* depth and color information */ struct Edge *nexte; /* next edge on this edge list */ struct Edge *next; /* next edge on active edge list */ } Edge; /** * Pointer to a list of Edges. */ typedef struct EdgeList { Edge *head; /* pointer to first edge in list */ } EdgeList; /** * Row of adjacent pixels all of the same color. */ typedef struct ColorSegment { short x; /* starting x location */ unsigned short length; /* number of pixels of this color */ Alib_Pixel color; /* color of this segment */ } ColorSegment; typedef struct { Alib_Segment *head; /* pointer to a vector of BufferedSegment's */ int count; /* number of seg's currently in use */ } SegmentGroup; /** * Vector of ColorSegment's. */ typedef struct ScanLine { ColorSegment *head; /* first element in the list */ ColorSegment *tail; /* last element in the list */ int count; } ScanLine; struct Alib_Window { gui_Type *gui; int width, height; /* dimensions of this window */ Alib_Rect rect; /* (0,0)-(width,height) */ Alib_Rect clip; /* clipping bounds for current drawing */ int flags; /* (for internal use only) */ int bsegSize; /* Count of elements in each bseg element */ SegmentGroup *bseg; int ymin, ymax; /* range of EdgeList's with polygons */ ScanLine *scanLine; /* a vector with height elements */ ScanLine *lastScanLine; /* a vector with height elements */ EdgeList *edges; /* a vector with height elements */ EdgeList *lines; /* a vector with height elements */ Edge *edgePool; /* a pool of polygon edges */ unsigned int EPSize; /* number of entries in edgePool */ unsigned int EPTop; /* index of first free edge */ unsigned int curPool; /* selects csPool (0 or 1) */ ColorSegment *csPool0; unsigned int CSSize0; /* number of entries in csPool0 */ unsigned int CSTop0; /* index of first free color seg */ ColorSegment *csPool1; unsigned int CSSize1; /* number of entries in csPool1 */ unsigned int CSTop1; /* index of first free color seg */ unsigned long depth; /* polygon depth while plotting */ Alib_ZInfo *zpool; long zsize; /* capacity of zpool */ long ztop; /* index next available zpool entry */ double visibility; /* visibility range (m) */ VColor_Type *haze_color; /* fade-out color with distance */ }; void Alib_setPoint(Alib_Point *p, int x, int y) { p->x = x; p->y = y; } void Alib_setRect(Alib_Rect *r, int ax, int ay, int bx, int by) { if( ax >= bx || ay >= by ){ r->a.x = 0; r->a.y = 0; r->b.x = 0; r->b.y = 0; } else { r->a.x = ax; r->a.y = ay; r->b.x = bx; r->b.y = by; } } int Alib_isEmptyRect(Alib_Rect *r) { if( (r->a.x >= r->b.x) || (r->a.y >= r->b.y) ) return 1; else return 0; } void Alib_expandRect(Alib_Rect *r, int dx, int dy) { Alib_setRect(r, r->a.x - dx, r->a.y - dy, r->b.x + dx, r->b.y + dy); } static int min(int x, int y) { if( x <= y ) return x; else return y; } static int max(int x, int y) { if( x >= y ) return x; else return y; } void Alib_intersectRect(Alib_Rect *r1, Alib_Rect *r2, Alib_Rect *res) { Alib_setRect(res, max(r1->a.x, r2->a.x), max(r1->a.y, r2->a.y), min(r1->b.x, r2->b.x), min(r1->b.y, r2->b.y)); } /** * Allocate internal buffers based on current width,height, then * set counters and indeces to these buffers. */ static void awindow_alloc_internals(Alib_Window *w) { int i; w->edges = memory_allocate(w->height * sizeof(EdgeList), NULL); w->lines = memory_allocate(w->height * sizeof(EdgeList), NULL); w->EPSize = 64 * 1024; w->edgePool = memory_allocate(w->EPSize * sizeof(Edge), NULL); memset(w->edgePool, 0, w->EPSize * sizeof(Edge)); w->scanLine = memory_allocate(w->height * sizeof(ScanLine), NULL); w->lastScanLine = memory_allocate(w->height * sizeof(ScanLine), NULL); w->CSSize0 = w->height * MAX_CS_PER_LINE; w->csPool0 = memory_allocate(w->CSSize0 * sizeof(ColorSegment), NULL); memset(w->csPool0, 0, w->CSSize0 * sizeof(ColorSegment)); w->CSSize1 = w->height * MAX_CS_PER_LINE; w->csPool1 = memory_allocate(w->CSSize1 * sizeof(ColorSegment), NULL); memset(w->csPool1, 0, w->CSSize1 * sizeof(ColorSegment)); w->EPTop = w->CSTop0 = w->CSTop1 = w->curPool = 0; w->ymin = w->height; w->ymax = 0; for (i = 0; i < w->height; ++i) { w->scanLine[i].count = 0; w->scanLine[i].head = NULL; w->scanLine[i].tail = NULL; w->lastScanLine[i].count = 0; w->lastScanLine[i].head = NULL; w->lastScanLine[i].tail = NULL; w->edges[i].head = NULL; w->lines[i].head = NULL; } } /** * Release all the internal data buffers, but DO NOT set counters nor * indices and does not free nor initialize: bseg[], zpool, aPixel. */ static void awindow_free_internals(Alib_Window *w) { memory_dispose(w->edges); memory_dispose(w->lines); memory_dispose(w->edgePool); memory_dispose(w->scanLine); memory_dispose(w->lastScanLine); memory_dispose(w->csPool0); memory_dispose(w->csPool1); } static void Alib_destruct(void *p) { Alib_Window *w = (Alib_Window *) p; int i; awindow_free_internals(w); for (i = 0; i < w->bsegSize; ++i){ if( w->bseg[i].count >= 0 ){ memory_dispose(w->bseg[i].head); } } memory_dispose(w->bseg); memory_dispose(w->zpool); } Alib_Window * Alib_new(gui_Type *gui) { Alib_Window *w; int i; int width = gui_getWidth(gui); int height = gui_getHeight(gui); if( width < 1 ) width = 1; if( height < 1 ) height = 1; w = memory_allocate(sizeof(Alib_Window), Alib_destruct); memset(w, 0, sizeof(Alib_Window)); w->gui = gui; w->width = width; w->height = height; Alib_setRect(&w->rect, 0, 0, w->width, w->height); w->clip = w->rect; w->flags = 0; w->zsize = 32768; w->ztop = 0; w->zpool = memory_allocate(sizeof(Alib_ZInfo) * w->zsize, NULL); w->depth = MaxDepth; awindow_alloc_internals(w); w->bsegSize = Alib_MaxPixelValue + 1; w->bseg = memory_allocate(sizeof(SegmentGroup) * w->bsegSize, NULL); for (i = 0; i < w->bsegSize; ++i) w->bseg[i].count = -1; w->visibility = 20.0 * 1853.0; w->haze_color = VColor_getByName("#ccc", 0); return w; } void Alib_resize(Alib_Window * w, int width, int height) { if( width < 1 ) width = 1; if( height < 1 ) height = 1; if( w->width == width && w->height == height ){ return; } awindow_free_internals(w); w->width = width; w->height = height; Alib_setRect(&w->rect, 0, 0, width, height); Alib_intersectRect(&w->clip, &w->rect, &w->clip); awindow_alloc_internals(w); } void Alib_setDepthCueing(Alib_Window *w, int value) { if( value ) w->flags |= Alib_ModeDepthCueing; else w->flags &= ~Alib_ModeDepthCueing; } static ColorSegment * CSOverflow(void) { static int warning_raised = 0; if( ! warning_raised ){ fprintf(stderr, "Color Segment pool overflow.\n" "Try increasing the constant MAX_CS_PER_LINE in " __FILE__ "\n"); warning_raised = 1; } return NULL; } static ColorSegment * mallocCS(Alib_Window * w) { switch (w->curPool) { case 0: return (w->CSTop0 == w->CSSize0) ? CSOverflow() : &(w->csPool0[(w->CSTop0)++]); case 1: return (w->CSTop1 == w->CSSize1) ? CSOverflow() : &(w->csPool1[(w->CSTop1)++]); default: error_internal("w->curPool=%d", w->curPool); } } static __inline void freeLastCS(Alib_Window * w) { switch (w->curPool) { case 0: w->CSTop0--; break; case 1: w->CSTop1--; break; default: error_internal("w->curPool=%d", w->curPool); } } /** * Draw a line segment ranging from pixel (x0,y) to (x1-1,y) so that the * segment is exactly (x1-x0) pixels long. Does nothing if the length is * zero or negative, i.e. x1-x0<=0. Successive calls on the same scan line * must be ordered by x0 value. */ static void DrawScanLine(Alib_Window * w, int y, int x0, int x1, Alib_Pixel color) { ColorSegment *p; int lastx; assert( 0 <= y && y < w->height ); if( x0 >= x1 ) return; if (w->scanLine[y].count == 0) { /* * This is the first segment on this scan line. */ p = mallocCS(w); if (p != NULL) { p->x = x0; p->length = x1 - x0; p->color = color; w->scanLine[y].head = w->scanLine[y].tail = p; w->scanLine[y].count = 1; } } /* * The scan line wasn't empty. Check the previous scan line entry for * any overlap with this one. */ else { p = w->scanLine[y].tail; lastx = p->x + p->length; if (lastx > x0) { /* * The segments overlap. * * If the overlapping segments have the same color, then simply * extend the previous segment's length. */ if (p->color == color) p->length = x1 - p->x; /* * The overlapping segment's colors are different. Shorten the previous * segment and allocate an entry for the current one. If the shortened * segment is eliminated, use it to store this segment's information. */ else { p->length = x0 - p->x; if (p->length > 0) { if ((p = mallocCS(w)) != NULL) { ++w->scanLine[y].count; w->scanLine[y].tail = p; } } /* * If the shortened segment's length went to zero, we may need to merge * this segment with the last one. */ if (((p - 1)->color == color) && (w->scanLine[y].count > 1)) { freeLastCS(w); p = w->scanLine[y].tail = p - 1; --w->scanLine[y].count; p->length = x1 - p->x; } else { p->x = x0; p->length = x1 - x0; p->color = color; } } } /* * The segments do not overlap. * * If the segments are adjacent and the colors are the same, extend the * last segment. * * Otherwise, create a new segment and append it to this line. */ else if ((lastx == x0) && (p->color == color)) p->length = x1 - p->x; else if ((p = mallocCS(w)) != NULL) { ++w->scanLine[y].count; w->scanLine[y].tail = p; p->x = x0; p->length = x1 - x0; p->color = color; } } } #define QDrawScanLine(w, y, x0, x1, c) \ { \ if (lastStart == -1) { \ lastStart = x0; \ lastColor = c; \ } \ else if (c != lastColor) { \ DrawScanLine (w, y, lastStart, x0, lastColor); \ lastStart = x0; \ lastColor = c; \ } \ } /** * Remove entries from the active edge table that should no longer * be drawn. Increment the x value of all others. Add all entries * that begin on this row. */ static void updateActiveEdgeList(Alib_Window * w, Edge ** head, Edge ** lineHead, int y) { int inserted; Edge *p, *q, *last, *newhead, *newtail, *q1, *q2; /* * Remove stale edges from the active list and increment x values of the rest. * * We get a bit tricky here. The active edge table must be ordered by x1 * value to allow for the plane sweep method to work. The relative edge * sequence may change as each edge's x1 value changes. We'll build an * updated, sorted "partial" edge list as we increment x1 values. An edge that * no longer belongs after its predecessor in the list is temporarily moved * to this row's new edge list so that it can be inserted in it's proper * position. */ newhead = newtail = NULL; for (p = *head; p != NULL; p = p->next) { if (p->y2 != y) { p->x1 += p->Dx; if (newhead == NULL) { newhead = newtail = p; } else if (p->x1 >= newtail->x1) { newtail->next = p; newtail = p; } else { p->nexte = w->edges[y].head; w->edges[y].head = p; } } } *head = newhead; if (newtail != NULL) newtail->next = NULL; /* * Add any new entries to the active line list. */ for (q = w->lines[y].head; q != NULL; q = q->nexte) { q->next = *lineHead; *lineHead = q; } /* * Add edges corresponding to each active line. */ newhead = newtail = NULL; for (q = *lineHead; q != NULL; q = q->next) { if (y < q->y2) { q1 = q + 1; q2 = q + 2; q1->x1 = q->x1; q2->x1 = q->x1 = q->x1 + q->Dx; q1->y2 = q2->y2 = y + 1; q1->nexte = q2; q2->nexte = w->edges[y].head; w->edges[y].head = q1; if (newhead == NULL) { newhead = newtail = q; } else { newtail->next = q; newtail = q; } } } *lineHead = newhead; if (newtail != NULL) newtail->next = NULL; /* * Insert all new edges for this row in sorted order onto the active edge list */ for (q = w->edges[y].head; q != NULL; q = q->nexte) { if (*head == NULL) { *head = q; q->next = NULL; } else { inserted = 0; for (p = *head, last = NULL; p != NULL;) { if (q->x1 <= p->x1) { if (last == NULL) *head = q; else last->next = q; q->next = p; inserted = 1; break; } last = p; p = p->next; } if (inserted == 0) { last->next = q; q->next = NULL; } } } } #define RIGHT_SIDE_CORRECTION /** * Draw all polygons on this scan line by the plane sweep method. */ static void planeSweep(Alib_Window * w, Edge * head, int y) { Alib_ZInfo *ps = NULL; /* polygon set head */ Alib_ZInfo *q, *r, *lastr = NULL; Edge *p; /* current edge */ register int x0, x1 = 0, lastStart = -1; Alib_Pixel lastColor = 0; unsigned long lastDepth = MaxDepth; if (head == NULL) { w->scanLine[y].count = 0; return; } for (p = head; p->next != NULL; p = p->next) { #ifdef FLOAT_SLOPE x0 = p->x1; x1 = p->next->x1; #else x0 = p->x1 >> 16; x1 = p->next->x1 >> 16; #endif /* * Polygons are ordered on the ps list by depth. We use a special flag * to determine quickly if the current polygon is or is not an element of the * currently active polygon set. Since the polygon set is ordered by depth, * the first element determines the color that's drawn. */ q = p->p; if (q->next == NotAnElement) { if (ps == NULL) { ps = q; q->next = q->prev = NULL; } else { for (r = ps; r != NULL; r = r->next) { if (q->depth < r->depth) { if (r->prev == NULL) ps = q; else r->prev->next = q; q->next = r; q->prev = r->prev; r->prev = q; break; } lastr = r; } if (r == NULL) { q->next = lastr->next; lastr->next = q; q->prev = lastr; } } } else { if (q->prev == NULL) ps = q->next; else q->prev->next = q->next; if (q->next != NULL) q->next->prev = q->prev; q->next = NotAnElement; } /* * If the polygon set is non-null, then there is some line segment that * should be plotted. We'll perform one small correction here: if the depth * of the last adjacent polygon segment was less than the depth of this one, * then add one to the x0 value. This prevents the right side of a polygon * from looking different than the left side. */ #ifdef RIGHT_SIDE_CORRECTION if (ps != NULL) { if (lastDepth < ps->depth) { if ((++x0) <= x1) { QDrawScanLine(w, y, x0, x1, ps->color); lastDepth = ps->depth; } } else { QDrawScanLine(w, y, x0, x1, ps->color); lastDepth = ps->depth; } } else { lastDepth = MaxDepth; if (lastStart != -1) { DrawScanLine(w, y, lastStart, x1, lastColor); lastStart = -1; } } #else if (ps != NULL) DrawScanLine(w, y, x0, x1, ps->color); #endif } if (lastStart != -1) DrawScanLine(w, y, lastStart, x1, lastColor); if (ps != NULL) { #ifdef DEBUG if (ps->next != NULL) fprintf(stderr, "More then 1 element left at end of planeSweep\n"); #endif ps->next = NotAnElement; } } /** * Convert the edge table to scan line segments. */ static void EdgeTableToScanLine(Alib_Window * w) { int y; Edge *active; /* head of active edge list */ Edge *activeLines; /* head of active line list */ active = activeLines = NULL; if( !(0 <= w->ymin && w->ymin <= w->ymax && w->ymax < w->height) ) error_internal("ymin = %d, ymax = %d, height = %d", w->ymin, w->ymax, w->height); for (y = w->ymin; y <= w->ymax; ++y) { updateActiveEdgeList(w, &active, &activeLines, y); planeSweep(w, active, y); } } static void AllocBufferedSegments(Alib_Window * w, Alib_Pixel c) { assert( 0 <= c && c < w->bsegSize ); w->bseg[c].head = memory_allocate(w->bsegSize * sizeof(Alib_Segment), NULL); w->bseg[c].count = 0; } static void OutputSegments(gui_Type *gui, Alib_Segment *segments, int nsegments, int color_index) { while(nsegments > 0) { gui_drawLine(gui, segments->x1, segments->y1, segments->x2, segments->y2, color_index); segments++; nsegments--; } } static void OutputSegment(Alib_Window *w, int yp, int x0p, int x1p, Alib_Pixel c) { int i; Alib_Segment *p; assert( 0 <= c && c < w->bsegSize ); if (w->bseg[c].count == -1) AllocBufferedSegments (w, c); i = ++(w->bseg[c].count); p = &(w->bseg[c].head[i-1]); p->x1 = x0p; p->x2 = x1p; p->y1 = p->y2 = yp; if (i == w->bsegSize) { p = w->bseg[c].head; OutputSegments(w->gui, p, w->bsegSize, c); w->bseg[c].count = 0; } } static void FlushBufferedSegments(Alib_Window * w) { int i; for (i = 0; i < w->bsegSize; ++i) { if (w->bseg[i].count > 0) { OutputSegments(w->gui, w->bseg[i].head, w->bseg[i].count, i); w->bseg[i].count = 0; } } } /** * Determine the differences between this frame and the previous one * and plot the differences. */ static void ScanLineDifference(Alib_Window * w) { ColorSegment *cur, *last; int len, curX = 0, curLength = 0, curCount, lastCount, y; for (y = 0; y < w->height; ++y) { cur = w->scanLine[y].head; curCount = w->scanLine[y].count; if (curCount > 0) { curX = cur->x; curLength = cur->length; } last = w->lastScanLine[y].head; lastCount = w->lastScanLine[y].count; while (curCount != 0) { if (lastCount == 0) { OutputSegment(w, y, curX, curX + curLength - 1, cur->color); ++cur; curX = cur->x; curLength = cur->length; --curCount; } else if (curX == last->x) { if (curLength == last->length) { /* * The trivial case: Both segments have the same length. If the colors are * different, then output the correct new color. */ if (cur->color != last->color) { OutputSegment(w, y, curX, curX + curLength - 1, cur->color); } ++last; ++cur; curX = cur->x; curLength = cur->length; --curCount; --lastCount; } else if (curLength < last->length) { /* * The current segment is shorter than the last one. Output a new line segment * if the colors differ; delete the current segment and update the last one's * x value and length. */ if (cur->color != last->color) { OutputSegment(w, y, curX, curX + curLength - 1, cur->color); } last->x += curLength; last->length -= curLength; ++cur; curX = cur->x; curLength = cur->length; --curCount; } /* * The current segment is longer than the last one. Output, if necessary; * delete the last segment and update the current segment's x value and length. */ else { if (cur->color != last->color) { OutputSegment(w, y, curX, curX + last->length - 1, cur->color); } curX += last->length; curLength -= last->length; ++last; --lastCount; } } /* * The current segment starts before any previous segments. */ else if (curX < last->x) { if (curX + curLength > last->x) len = last->x - curX; else len = curLength; OutputSegment(w, y, curX, curX + len - 1, cur->color); curX += len; curLength -= len; if (curLength == 0) { ++cur; curX = cur->x; curLength = cur->length; --curCount; } } /* * The previous segment begins before the first current segment. */ else { if (last->x + last->length > curX) len = curX - last->x; else len = last->length; last->x += len; last->length -= len; if (last->length == 0) { ++last; --lastCount; } } } } } /* * Randomly changing drawing colors in X would require that we add an XChangeGC * request before virtually every line segment draw. * Once the scan line segment output has been optimized by ScanLineDifference, * we can add a further optimization to reduce the number of XChangeGC * requests that are required. We'll add a structure to group drawing * requests by color. When some watermark is past, an XChangeCG request may * be issued, followed by all requests for that color. This request buffer * will be flushed with a call to FrameComplete(). */ static void FrameComplete(Alib_Window * w) { ScanLine *tmp; int i; /* * Convert the edge table to scan line segments. */ EdgeTableToScanLine(w); /* * Determine the differences between this frame and the previous one * and plot the differences. */ ScanLineDifference(w); /* * This frame now becomes the previous frame; clear the new current frame. */ tmp = w->lastScanLine; w->lastScanLine = w->scanLine; w->scanLine = tmp; for (i = 0; i < w->height; ++i) { w->scanLine[i].count = 0; w->edges[i].head = NULL; w->lines[i].head = NULL; } /* * Release the allocated color segments for what was the last frame. */ if (w->curPool == 0) { w->curPool = 1; w->CSTop1 = 0; } else if (w->curPool == 1) { w->curPool = 0; w->CSTop0 = 0; } else { w->curPool = 0; w->CSTop0 = 0; } /* * Release the allocated elements of the edge pool. */ w->EPTop = 0; w->ymin = w->height; w->ymax = 0; /* * Perform any graphics-dependent finish-up */ FlushBufferedSegments(w); } void Alib_invalidate(Alib_Window * w) { int i; for (i = 0; i < w->height; ++i) { w->lastScanLine[i].count = 0; } } Alib_ZInfo * Alib_nextZInfo(Alib_Window * w, Alib_Pixel color) { if (w->ztop >= w->zsize) error_internal("Z-information pool overflow", 0); Alib_ZInfo *z = &(w->zpool[(w->ztop)++]); z->depth = --w->depth; z->color = color; return z; } void Alib_drawSegments(Alib_Window * w, Alib_Segment * seg, int nseg, Alib_Pixel color) { Alib_ZInfo *z = Alib_nextZInfo(w, color); for (; nseg > 0; --nseg) { Alib_draw3DLine(w, seg->x1, seg->y1, seg->x2, seg->y2, z); ++seg; } } void Alib_drawLine(Alib_Window *w, int x1, int y1, int x2, int y2, Alib_Pixel color) { Alib_ZInfo *z = Alib_nextZInfo(w, color); Alib_draw3DLine(w, x1, y1, x2, y2, z); } #define TICKtoRAD(a) (a * M_PI / (180.0 * 64.0)) #define INCR (30 * 64) void Alib_drawArc(Alib_Window *w, int x, int y, int width, int height, int angle1, int angle2, Alib_Pixel color) { /* FIXME: needs optimization avoiding to calculate all that cos/sin. FIXME: the no. of sides should depend on the radius. */ double W, H, xc, yc; int incr, x1, x2, y1, y2; Alib_ZInfo *z = Alib_nextZInfo(w, color); W = width / 2.0; H = height / 2.0; xc = x + width / 2.0; yc = y + height / 2.0; if (angle2 < 0) { incr = -INCR; angle2 = -angle2; } else incr = INCR; if (angle2 > 360 * 64) angle2 = 360 * 64; x1 = (int) (xc + (W * cos(TICKtoRAD(angle1)))); y1 = (int) (yc - (H * sin(TICKtoRAD(angle1)))); while (angle2 != 0) { angle1 += incr; angle2 -= INCR; if (angle2 < 0) { angle1 -= angle2; angle2 = 0; } x2 = (int) (xc + (W * cos(TICKtoRAD(angle1)))); y2 = (int) (yc - (H * sin(TICKtoRAD(angle1)))); Alib_drawLine(w, x1, y1, x2, y2, z->color); x1 = x2; y1 = y2; } } void Alib_drawRect(Alib_Window *w, Alib_Rect *r, Alib_Pixel color) { Alib_Segment seg[4]; if( Alib_isEmptyRect(r) ) return; seg[0].x1 = r->a.x; seg[0].y1 = r->a.y; seg[0].x2 = r->b.x - 1; seg[0].y2 = r->a.y; seg[1].x1 = r->b.x - 1; seg[1].y1 = r->a.y; seg[1].x2 = r->b.x - 1; seg[1].y2 = r->b.y - 1; seg[2].x1 = r->b.x - 1; seg[2].y1 = r->b.y - 1; seg[2].x2 = r->a.x; seg[2].y2 = r->b.y - 1; seg[3].x1 = r->a.x; seg[3].y1 = r->b.y - 1; seg[3].x2 = r->a.x; seg[3].y2 = r->a.y; Alib_drawSegments(w, seg, 4, color); } void Alib_fillRect(Alib_Window *w, Alib_Rect *r, Alib_Pixel color) { if( Alib_isEmptyRect(r) ) return; Alib_ZInfo *z = Alib_nextZInfo(w, color); Alib_fill3DRect(w, r, z); } void Alib_fillPolygon(Alib_Window *w, Alib_Point * pts, int npts, Alib_Pixel color) { Alib_ZInfo *z = Alib_nextZInfo(w, color); Alib_fill3DPolygon(w, pts, npts, z); } void Alib_setClipRect(Alib_Window *w, Alib_Rect *r) { Alib_intersectRect(&w->rect, r, &w->clip); } /** * Build an edge table based on edge coherence as described by * Rod Salmon and Mel Slater, 1987. */ static void MakeET(Alib_Window * w, Alib_Point * pts, int npts, Alib_ZInfo * zinfo) { int i, t, addedEdge = 0; int x1, y1, x2, y2; int ymin, ymax; Edge *e; ymin = w->height; ymax = 0; zinfo->next = NotAnElement; /* * Process each edge in this polygon */ for (i = 1; i <= npts; ++i) { /* * Determine the end-points of this edge (x1, y1), (x2, y2). */ if (i == npts) { x2 = pts[0].x; y2 = pts[0].y; } else { x2 = pts[i].x; y2 = pts[i].y; } x1 = pts[i - 1].x; y1 = pts[i - 1].y; if (y1 > y2) { t = x1; x1 = x2; x2 = t; t = y1; y1 = y2; y2 = t; } if (y1 != y2) { if (w->EPTop == w->EPSize) { fprintf(stderr, "Edge Pool Overflow\n"); return; } e = &(w->edgePool[(w->EPTop)++]); e->y2 = y2; #ifdef FLOAT_SLOPE e->x1 = x1; e->Dx = (x2 - x1) / (double) (y2 - y1); #else e->x1 = (x1 << 16) + 0x8000; e->Dx = ((x2 - x1) << 16) / (y2 - y1); #endif e->p = zinfo; e->nexte = w->edges[y1].head; w->edges[y1].head = e; addedEdge = 1; if (y1 < ymin) ymin = y1; if (y2 > ymax) ymax = y2; } } if (addedEdge) { if (w->ymin > ymin) w->ymin = ymin; if (w->ymax < ymax) w->ymax = ymax; } } void Alib_draw3DPoint(Alib_Window * w, int x, int y, Alib_ZInfo * zinfo) { Edge *e, *e1; if (x < w->clip.a.x || x >= w->clip.b.x || y < w->clip.a.y || y >= w->clip.b.y) return; zinfo->next = NotAnElement; if (w->EPTop + 2 > w->EPSize) { fprintf(stderr, "Edge Pool Overflow\n"); return; } e = &(w->edgePool[(w->EPTop)++]); e1 = &(w->edgePool[(w->EPTop)++]); e->y2 = e1->y2 = y + 1; #ifdef FLOAT_SLOPE e->x1 = e1->x1 = x; e->Dx = 0.0; #else e->x1 = e1->x1 = (x << 16) + 0x8000; e->Dx = 0; #endif e->p = e1->p = zinfo; e1->nexte = w->edges[y].head; e->nexte = e1; w->edges[y].head = e; if (y < w->ymin) w->ymin = y; if (y > w->ymax) w->ymax = y; } void Alib_drawDifferences(Alib_Window *w) { w->ztop = 0; w->depth = MaxDepth; FrameComplete(w); } /* FIXME: remove static limit */ #define MAX_VERT 1000 void Alib_fill3DPolygon(Alib_Window * w, Alib_Point * pts, int npts, Alib_ZInfo * zinfo) { int x1, y1, x2, y2, i, np, nr; Alib_Point *a, *b, q; int a_in, b_in; double t; Alib_Point p[MAX_VERT], r[MAX_VERT]; if( npts < 3 ){ return; } if( npts > MAX_VERT ) error_internal("too many vertices", 0); x1 = w->clip.a.x; y1 = w->clip.a.y; x2 = w->clip.b.x; y2 = w->clip.b.y; /* Clipping of pts[0..npts-1] against the right side. Generating p[0..np-1]. */ np = 0; a = &pts[npts-1]; a_in = (a->x <= x2); for( i=0; i < npts ; i++ ){ b = &pts[i]; b_in = (b->x <= x2); if( a_in ){ if( b_in ){ p[np++] = *b; a = b; a_in = 1; } else { q.x = x2; t = (x2 - a->x) / (double)(b->x - a->x); q.y = a->y + t*(b->y - a->y) + 0.5; p[np++] = q; a = b; a_in = 0; } } else { if( b_in ){ q.x = x2; t = (x2 - a->x) / (double)(b->x - a->x); q.y = a->y + t*(b->y - a->y) + 0.5; p[np++] = q; p[np++] = *b; a = b; a_in = 1; } else { a = b; a_in = 0; } } } if( np < 3 ) return; /* Clipping of p[0..np-1] against the left side. Generating r[0..nr-1]. */ nr = 0; a = &p[np-1]; a_in = (a->x >= x1); for( i=0; i < np ; i++ ){ b = &p[i]; b_in = (b->x >= x1); if( a_in ){ if( b_in ){ r[nr++] = *b; a = b; a_in = 1; } else { q.x = x1; t = (x1 - a->x) / (double)(b->x - a->x); q.y = a->y + t*(b->y - a->y) + 0.5; r[nr++] = q; a = b; a_in = 0; } } else { if( b_in ){ q.x = x1; t = (x1 - a->x) / (double)(b->x - a->x); q.y = a->y + t*(b->y - a->y) + 0.5; r[nr++] = q; r[nr++] = *b; a = b; a_in = 1; } else { a = b; a_in = 0; } } } if( nr < 3 ) return; /* Clipping of r[0..nr-1] against the bottom side. Generating p[0..np-1]. */ np = 0; a = &r[nr-1]; a_in = (a->y <= y2); for( i=0; i < nr ; i++ ){ b = &r[i]; b_in = (b->y <= y2); if( a_in ){ if( b_in ){ p[np++] = *b; a = b; a_in = 1; } else { t = (y2 - a->y) / (double)(b->y - a->y); q.x = a->x + t*(b->x - a->x) + 0.5; q.y = y2; p[np++] = q; a = b; a_in = 0; } } else { if( b_in ){ t = (y2 - a->y) / (double)(b->y - a->y); q.x = a->x + t*(b->x - a->x) + 0.5; q.y = y2; p[np++] = q; p[np++] = *b; a = b; a_in = 1; } else { a = b; a_in = 0; } } } if( np < 3 ) return; /* Clipping of p[0..np-1] against the top side. Generating r[0..nr-1]. */ nr = 0; a = &p[np-1]; a_in = (a->y >= y1); for( i=0; i < np ; i++ ){ b = &p[i]; b_in = (b->y >= y1); if( a_in ){ if( b_in ){ r[nr++] = *b; a = b; a_in = 1; } else { t = (y1 - a->y) / (double)(b->y - a->y); q.x = a->x + t*(b->x - a->x) + 0.5; q.y = y1; r[nr++] = q; a = b; a_in = 0; } } else { if( b_in ){ t = (y1 - a->y) / (double)(b->y - a->y); q.x = a->x + t*(b->x - a->x) + 0.5; q.y = y1; r[nr++] = q; r[nr++] = *b; a = b; a_in = 1; } else { a = b; a_in = 0; } } } if( nr < 3 ) return; MakeET(w, r, nr, zinfo); } void Alib_fill3DRect(Alib_Window *w, Alib_Rect *r, Alib_ZInfo * zinfo) { Alib_Point pts[4]; Alib_Rect f; Alib_intersectRect(r, &w->clip, &f); if( Alib_isEmptyRect(&f) ) return; pts[0] = f.a; pts[1].x = f.b.x - 1; pts[1].y = f.a.y; pts[2].x = f.b.x - 1; pts[2].y = f.b.y - 1; pts[3].x = f.a.x; pts[3].y = f.b.y - 1; MakeET(w, pts, 4, zinfo); } typedef int outcode_t; #define NONE 0 #define Top 1 #define Bottom 2 #define Left 8 #define Right 4 static outcode_t CompOutCode(Alib_Window * w, int x, int y) { /* +-----------------------------+-> x | | | Bottom | | .................... | | . .R | | L. w->clip .i | | e. .g | | f. rectangle .h | | t. .t | | .................... | | Top | +-----------------------------+ | (w->width,w->height) v y Please note that if the point lies exactly on the Right border or the Top border it is considered outside the clipping rectangle. */ outcode_t code = NONE; if (y >= w->clip.b.y) { code |= Top; } else if (y < w->clip.a.y) { code |= Bottom; } if (x >= w->clip.b.x) { code |= Right; } else if (x < w->clip.a.x) { code |= Left; } return code; } /** * Perform the clipping of the segment (x0,y0)-(x1,y1) vs. the w->clip * rectangle. Return value: * * 0 = the segment is visible, possibly partially; in this case * the returned points are both inside w->clip, i.e. * w->clip.a.x <= x0,x1 < w->clip.b.x * w->clip.a.y <= y0,y1 < w->clip.b.y * * 1 = segment not visible at all * * Cohen/Sutherland 2D clipping algorithm as described by Foley, van Dam, * Feiner and Hughes. */ static int ClipLine(Alib_Window * w, int *x0, int *y0, int *x1, int *y1) { outcode_t outcode0, outcode1, outcodeOut; outcode0 = CompOutCode(w, *x0, *y0); outcode1 = CompOutCode(w, *x1, *y1); do { if (outcode0 == 0 && outcode1 == 0) { /* Points are both inside the clip rect */ return 0; } else if (outcode0 & outcode1) { /* Points are both above some side of the clip rect, for ex. both above the Left side */ return 1; } else { /* At least one point is outside of the clip area */ int x, y; outcodeOut = outcode0 ? outcode0 : outcode1; if (outcodeOut & Top) { x = *x0 + (*x1 - *x0) * (w->clip.b.y - 1 - *y0) / (*y1 - *y0); y = w->clip.b.y - 1; } else if (outcodeOut & Bottom) { x = *x0 + (*x1 - *x0) * (w->clip.a.y - *y0) / (*y1 - *y0); y = w->clip.a.y; } else if (outcodeOut & Right) { y = *y0 + (*y1 - *y0) * (w->clip.b.x - 1 - *x0) / (*x1 - *x0); x = w->clip.b.x - 1; } else { /* Left */ y = *y0 + (*y1 - *y0) * (w->clip.a.x - *x0) / (*x1 - *x0); x = w->clip.a.x; } if (outcodeOut == outcode0) { *x0 = x; *y0 = y; outcode0 = CompOutCode(w, *x0, *y0); } else { *x1 = x; *y1 = y; outcode1 = CompOutCode(w, *x1, *y1); } } } while (1); } void Alib_draw3DLine(Alib_Window * w, int x1, int y1, int x2, int y2, Alib_ZInfo * zinfo) { int t; Edge *e, *e1; zinfo->next = NotAnElement; if (ClipLine(w, &x1, &y1, &x2, &y2)){ return; } if (y1 > y2) { t = x1; x1 = x2; x2 = t; t = y1; y1 = y2; y2 = t; } if ((x1 == x2) || (y1 == y2)) { if (w->EPTop + 2 > w->EPSize) { fprintf(stderr, "Edge Pool Overflow\n"); return; } e = &(w->edgePool[(w->EPTop)++]); e1 = &(w->edgePool[(w->EPTop)++]); e->y2 = e1->y2 = y2 + 1; #ifdef FLOAT_SLOPE if (x1 == x2) e->x1 = e1->x1 = x1; else { /* y1 == y2 */ e->x1 = x1; e1->x1 = x2; } e->Dx = e1->Dx = 0.0; #else if (x1 == x2) e->x1 = e1->x1 = (x1 << 16) + 0x8000; else { /* y1 == y2 */ e->x1 = (x1 << 16) + 0x8000; e1->x1 = (x2 << 16) + 0x8000; } e->Dx = e1->Dx = 0; #endif e->p = e1->p = zinfo; e1->nexte = w->edges[y1].head; e->nexte = e1; w->edges[y1].head = e; } /* * A non-trivial case. There is a slope that is non-zero and not infinity. * We will need one edge entry to hang off the line list at the starting y * value of the line. We will also pre-allocate two edge entries to be used * as the line'e edges during the EdgeTableToScanLine procedure. By our own * convention, we'll place them in the two edge pool entries immediately * following the line information entry. */ else { if (w->EPTop + 3 >= w->EPSize) { fprintf(stderr, "Edge Pool Overflow\n"); return; } e = &(w->edgePool[(w->EPTop)++]); w->EPTop += 2; /* required -- see comment above */ e->y2 = y2; #ifdef FLOAT_SLOPE e->x1 = x1; e->Dx = (x2 - x1) / (double) (y2 - y1); #else e->x1 = (x1 << 16) + 0x8000; e->Dx = ((x2 - x1) << 16) / (y2 - y1); #endif e->p = (e + 1)->p = (e + 2)->p = zinfo; e->nexte = w->lines[y1].head; w->lines[y1].head = e; } if (y1 < w->ymin) w->ymin = y1; if (y2 > w->ymax) w->ymax = y2; } void Alib_setVisibility(Alib_Window *w, double visibility, VColor_Type * haze_color) { w->visibility = visibility; w->haze_color = haze_color; } Alib_Pixel Alib_computePolygonColor(Alib_Window *w, VPolygon * poly) { /* * First, are we seeing the front or the back of this polygon? */ VColor_Type *c; if (poly->flags & PolyUseBackColor) { c = poly->backColor; } else { c = poly->color; } /* * If depth cueing isn't turned on, or this color is not a depth-cued * color, then simply return the color index. */ if ((w->flags & Alib_ModeDepthCueing) == 0 || ! VColor_isDepthCueing(c) ) { return VColor_getIndex(c); } /* * Okay, it is a depth cued color. Compute the distance of the polygon from * the eye (the origin) and then compute the corresponding depth cued color. * We may take the distance from an arbitrary point of the polygon (for example * the first vertex; fast but some artifacts in rendering due to clipping * against the frustum), or we may compute a middle point (slower, but more * accurate rendering). */ double visibility2 = w->visibility * w->visibility; /* // Compute distance from the average point (expensive algo): VPoint p = {0.0, 0.0, 0.0}; for(int i = poly->numVtces - 1; i >= 0; i--){ VAdd(&p, &poly->vertex[i], &p); } p.x /= poly->numVtces; p.y /= poly->numVtces; p.z /= poly->numVtces; double d2 = VMagnitude2(&p); */ // Compute distance from the first point (fast): double d2 = VMagnitude2(&poly->vertex[0]); if( d2 > visibility2 ) return VColor_getIndex(w->haze_color); // Quite arbitrary blending law, but result good enough anyway: double k = 1.0 / (1.0 + 9.0 * d2 / visibility2); // 0 < k <= 1.0 int r = k * VColor_getRed(c) + (1.0 - k) * VColor_getRed(w->haze_color); int g = k * VColor_getGreen(c) + (1.0 - k) * VColor_getGreen(w->haze_color); int b = k * VColor_getBlue(c) + (1.0 - k) * VColor_getBlue(w->haze_color); return gui_getColorIndex(w->gui, r, g, b); } void Alib_MatrixIdentity(Alib_Matrix *m) { m->rxx = 1; m->rxy = 0; m->ryx = 0; m->ryy = 1; m->tx = 0; m->ty = 0; } void Alib_MatrixScale(Alib_Matrix *m, double s) { m->rxx *= s; m->rxy *= s; m->ryx *= s; m->ryy *= s; m->tx *= s; m->ty *= s; } void Alib_MatrixRotate(Alib_Matrix *m, double a) { double c = cos(a); double s = sin(a); double rxx = c * m->rxx + s * m->ryx; double rxy = c * m->rxy + s * m->ryy; m->ryx = -s * m->rxx + c * m->ryx; m->ryy = -s * m->rxy + c * m->ryy; m->rxx = rxx; m->rxy = rxy; m->tx *= c; m->ty *= c; } void Alib_MatrixTranslate(Alib_Matrix *m, double dx, double dy) { m->tx += dx; m->ty += dy; } void Alib_MatrixTransformPoint(Alib_Point *p, Alib_Matrix *m, Alib_Point *q) { double qx = m->rxx * p->x + m->rxy * p->y + m->tx; q->y = m->ryx * p->x + m->ryy * p->y + m->ty + 0.5; q->x = qx + 0.5; } #define MAX_TRANSFORMED_POINTS 99 void Alib_fillPolygonWithMatrix(Alib_Window *w, Alib_Point * pts, int npts, Alib_Matrix *m, Alib_Pixel color) { int i; Alib_Point tpts[MAX_TRANSFORMED_POINTS]; assert( npts <= MAX_TRANSFORMED_POINTS ); for(i = npts - 1; i >= 0; i--) Alib_MatrixTransformPoint(&pts[i], m, &tpts[i]); Alib_fillPolygon(w, tpts, npts, color); } static void Alib_Polygon_destruct(void *p) { Alib_Polygon *poly = p; memory_dispose(poly->pts); } Alib_Polygon * Alib_Polygon_new() { Alib_Polygon *poly = memory_allocate(sizeof(Alib_Polygon), Alib_Polygon_destruct); poly->allocated_pts = 10; poly->npts = 0; poly->pts = memory_allocate(poly->allocated_pts * sizeof(Alib_Point), NULL); return poly; } void Alib_Polygon_addPointXY(Alib_Polygon *poly, int x, int y) { if( poly->npts >= poly->allocated_pts ){ poly->allocated_pts *= 2; poly->pts = memory_realloc(poly->pts, poly->allocated_pts * sizeof(Alib_Point)); } poly->pts[poly->npts++] = (Alib_Point) {x, y}; } void Alib_Polygon_addPoint(Alib_Polygon *poly, Alib_Point *p) { if( poly->npts >= poly->allocated_pts ){ poly->allocated_pts *= 2; poly->pts = memory_realloc(poly->pts, poly->allocated_pts * sizeof(Alib_Point)); } poly->pts[poly->npts++] = *p; } Alib_Polygon * Alib_Polygon_clone(Alib_Polygon *poly) { Alib_Polygon *copy = memory_allocate(sizeof(Alib_Polygon), Alib_Polygon_destruct); copy->allocated_pts = poly->npts; copy->npts = poly->npts; copy->pts = memory_allocate(copy->npts * sizeof(Alib_Point), NULL); memcpy(copy->pts, poly->pts, copy->npts * sizeof(Alib_Point)); return copy; } acm-6.0_20200416/src/V/Alib.h0000644000000000000000000001440613145001105013602 0ustar rootroot/** * Alib -- Basic 2-D drawing routines with Z-buffer for polygons. * Nobody knows what that "A" stands for. * * @file */ #ifndef _ALIB_H #define _ALIB_H #include #include "Vlibmath.h" #include "VPoly.h" #include "../util/gui.h" #ifdef Alib_IMPORT #define EXTERN #else #define EXTERN extern #endif typedef struct { short x, y; } Alib_Point; typedef struct { short x1, y1, x2, y2; } Alib_Segment; /** * A Rect is exactly (b.x - a.x) pixels wide and (b.y - a.y) pixels tall, * being a,b two geometrical points. * * This library assumes a.x < b.x and a.y < b.y, otherwise the Rect * is considered empty. * * Please note that the pixel "a" is inside, while "b" is outside. */ typedef struct { Alib_Point a, b; } Alib_Rect; /** * 2D transformation (misleading name as it is not properly a "matrix"). */ typedef struct { double rxx, rxy, ryx, ryy, tx, ty; } Alib_Matrix; /** * Expandable polygon. Last point implicitly joined with the the first to close. */ typedef struct { /** Number of points of the polygon. */ int npts; /** Number of points allocated in memory. */ int allocated_pts; /** Allocated points. */ Alib_Point *pts; } Alib_Polygon; typedef unsigned short Alib_Pixel; typedef struct Alib_ZInfo Alib_ZInfo; typedef struct Alib_Window Alib_Window; EXTERN void Alib_setPoint(Alib_Point *p, int x, int y); /** * Set the rectangle. */ EXTERN void Alib_setRect(Alib_Rect *r, int ax, int ay, int bx, int by); /** * Return true if the given rectangle is empty, false otherwise. */ EXTERN int Alib_isEmptyRect(Alib_Rect *r); /** * Return in res the intersection between r1,r2. If the result is empty, * return (Rect){{0,0},{0,0}}. Rectangles may overlap in memory. */ EXTERN void Alib_intersectRect(Alib_Rect *r1, Alib_Rect *r2, Alib_Rect *res); /** * Expands the given rectangle around its center so that it becomes 2*dx * pixels wider and 2*dy pixel taller. */ EXTERN void Alib_expandRect(Alib_Rect *r, int dx, int dy); #define RectWidth(r) ((r).b.x - (r).a.x) #define RectHeight(r) ((r).b.y - (r).a.y) #define RectMiddleX(r) (((r).b.x + (r).a.x)/2) #define RectMiddleY(r) (((r).b.y + (r).a.y)/2) /** * Create a new z-buffer rectangular area in the content area of the window. * @param gui * @return A new z-buffer rectangular area in the content area of the window. * Can be released with memory_dispose(). */ EXTERN Alib_Window * Alib_new(gui_Type *gui); /** * Resize the AWindow, intersection the current clipping rectangle * with the new area. */ EXTERN void Alib_resize(Alib_Window * w, int width, int height); /** * Enables depth cueing feature. * @param w Involved window. * @param value True to enable depth cueing, false to disable. */ EXTERN void Alib_setDepthCueing(Alib_Window *w, int value); /** * Set visibility (meters), haze color and number of steps for color * depth-cueing. */ EXTERN void Alib_setVisibility(Alib_Window *w, double visibility, VColor_Type * haze_color); /** * Set the clipping rectangle w->clip as the intersection between r and * the whole available drawing area (0,0)-(w->width,w->height). Drawing * will never be performed outside this rectangle. */ EXTERN void Alib_setClipRect(Alib_Window *w, Alib_Rect *r); /* * Basic 2-D drawing routines that draw on the given window and perform * clipping to the current clipping rectangle as set by AlibSetClip(). */ EXTERN void Alib_drawLine(Alib_Window *w, int x1, int y1, int x2, int y2, Alib_Pixel color); EXTERN void Alib_drawArc(Alib_Window *w, int x, int y, int width, int height, int angle1, int angle2, Alib_Pixel color); EXTERN void Alib_drawSegments(Alib_Window *w, Alib_Segment * seg, int nseg, Alib_Pixel color); EXTERN void Alib_drawRect(Alib_Window *w, Alib_Rect *r, Alib_Pixel color); EXTERN void Alib_fillRect(Alib_Window *w, Alib_Rect *r, Alib_Pixel color); EXTERN void Alib_fillPolygon(Alib_Window *w, Alib_Point * pts, int npts, Alib_Pixel color); /* * Basic 3-D drawing routines with color z-buffer that draw on the given * window and perform clipping to the current clipping rectangle as set by * AlibSetClip(). */ /** * Returns next pre-allocated ZInfo with specified color set. * @param w * @param color * @return Next pre-allocated ZInfo with specified color set. */ EXTERN Alib_ZInfo * Alib_nextZInfo(Alib_Window * w, Alib_Pixel color); EXTERN void Alib_draw3DPoint(Alib_Window * w, int x, int y, Alib_ZInfo * zinfo); EXTERN void Alib_draw3DLine(Alib_Window * w, int x1, int y1, int x2, int y2, Alib_ZInfo * zinfo); EXTERN void Alib_fill3DRect(Alib_Window * w, Alib_Rect *r, Alib_ZInfo * zinfo); EXTERN void Alib_fill3DPolygon(Alib_Window * w, Alib_Point * pts, int npts, Alib_ZInfo * zinfo); /** * Draw differences between this frame and the last drawn frame. */ EXTERN void Alib_drawDifferences(Alib_Window *w); /** * Invalidate the current frame's drawing information so that it will be fully * redrawn at next update. This function typically invoked after a window * redraw event. */ EXTERN void Alib_invalidate(Alib_Window *w); /** * Returns the faded color of the polygon given the current visibility range, * distance from the origin, and haze color. The "distance" is arbitrarily * calculated from the first point of the polygon, assuming the polygon be * much smaller than the visibility range. Beyond the visibility range the * haze color is returned. If the depth cueing is turned off, or the color of * the polygon is not marked as depth cued, simply returns the color of the * polygon. * @param w * @param poly * @return Faded color of the polygon. */ EXTERN Alib_Pixel Alib_computePolygonColor(Alib_Window *w, VPolygon * poly); EXTERN void Alib_MatrixIdentity(Alib_Matrix *m); EXTERN void Alib_MatrixScale(Alib_Matrix *m, double s); EXTERN void Alib_MatrixRotate(Alib_Matrix *m, double a); EXTERN void Alib_MatrixTranslate(Alib_Matrix *m, double dx, double dy); EXTERN void Alib_MatrixTransformPoint(Alib_Point *p, Alib_Matrix *m, Alib_Point *q); EXTERN void Alib_fillPolygonWithMatrix(Alib_Window *w, Alib_Point * pts, int npts, Alib_Matrix *m, Alib_Pixel color); EXTERN Alib_Polygon * Alib_Polygon_new(void); EXTERN void Alib_Polygon_addPointXY(Alib_Polygon *poly, int x, int y); EXTERN void Alib_Polygon_addPoint(Alib_Polygon *poly, Alib_Point *p); EXTERN Alib_Polygon * Alib_Polygon_clone(Alib_Polygon *poly); #undef EXTERN #endif acm-6.0_20200416/src/gedit/0000755000000000000000000000000013646051406013463 5ustar rootrootacm-6.0_20200416/src/gedit/gutil.h0000644000000000000000000000412713074625071014764 0ustar rootroot/* * Copyright (c) 1994, Riley Rainey, riley@netcon.com * * Permission to use, copy, modify and distribute (without charge) this * software, documentation, images, etc. is granted, provided that this * comment and the author's name is retained. * * This software is provided by the author as is, and without any expressed * or implied warranties, including, but not limited to, the implied * warranties of merchantability and fitness for a particular purpose. In no * event shall the author be liable for any direct, indirect, incidental, or * consequential damages arising in any way out of the use of this software. */ #ifndef gutil_H #define gutil_H #include "shared.h" #ifdef gutil_IMPORT #define EXTERN #else #define EXTERN extern #endif EXTERN void ComputePlaneEquation (polygon_t *p); EXTERN void DisplayPoint(point_t *p); EXTERN polygon_t * AllocPolygon (void); EXTERN void FreePolygon (polygon_t *p); EXTERN polygon_t * BeginPolygon (void); EXTERN void PointXY (Widget w, view_info_t *p, int x, int y, point_t *q); EXTERN int PinPoint (Widget w, view_info_t *p, polygon_t *poly, int x, int y, XPoint *pt, XPoint *opt); EXTERN int DragPoint (Widget w, view_info_t *p, polygon_t *poly, int delta, XPoint *pt, XPoint *opt); EXTERN void BeginPolygonPoint (Widget w, view_info_t *p, int x, int y); EXTERN void DragPolygonPoint(Widget w, view_info_t *p, int x, int y); EXTERN void CompletePolygonPoint(Widget w, view_info_t *p, int x, int y); EXTERN void CompletePolygon (Widget w, polygon_t *p); EXTERN int PolygonProximity (view_info_t *p, polygon_t *poly, int x, int y); EXTERN int PickObject (view_info_t *p, int x, int y); EXTERN void CompleteMarker(Widget w, view_info_t *p, int x, int y); EXTERN void BeginPick (Widget w, view_info_t *p, int x, int y, Boolean extend); EXTERN void DragSelection (Widget w, view_info_t *p, int x, int y); EXTERN void CompleteDrag (Widget w, view_info_t *p, int x, int y); EXTERN void SelectObject (int id); EXTERN void DetermineObjectExtent (VPoint *extent); EXTERN void RescaleObject (double factor); #undef EXTERN #endif acm-6.0_20200416/src/gedit/VReadObject.c0000644000000000000000000000347113143357677015777 0ustar rootroot/* * Copyright (c) 1994, Riley Rainey, riley@netcon.com * * Permission to use, copy, modify and distribute (without charge) this * software, documentation, images, etc. is granted, provided that this * comment and the author's name is retained. * * This software is provided by the author as is, and without any expressed * or implied warranties, including, but not limited to, the implied * warranties of merchantability and fitness for a particular purpose. In no * event shall the author be liable for any direct, indirect, incidental, or * consequential damages arising in any way out of the use of this software. */ #include #include "../util/memory.h" #define VReadObject_IMPORT #include "VReadObject.h" VObject *VReadObject2(FILE *f) { short I, J, vertex, vertices, NumPts, NumPolys; float x, y, z; char str[64], name[128]; VPoint *tmpPts, pts[VmaxVP]; VPolygon **polygons; VObject *object; fscanf(f, "%s\n", name); fscanf(f, "%hd", &NumPts); fscanf(f, "%hd", &NumPolys); tmpPts = (VPoint *) memory_allocate(NumPts * sizeof(VPoint), NULL); polygons = (VPolygon **) memory_allocate(NumPolys * sizeof(VPolygon *), NULL); for (I=0; Iname = memory_strdup (name); object->numPolys = NumPolys; object->polygon = polygons; memory_dispose(tmpPts); return ferror(f) ? (VObject *) 0 : object; } acm-6.0_20200416/src/gedit/shared.h0000644000000000000000000002431413154325021015075 0ustar rootroot/* * Copyright (c) 1994, Riley Rainey, riley@netcon.com * * Permission to use, copy, modify and distribute (without charge) this * software, documentation, images, etc. is granted, provided that this * comment and the author's name is retained. * * This software is provided by the author as is, and without any expressed * or implied warranties, including, but not limited to, the implied * warranties of merchantability and fitness for a particular purpose. In no * event shall the author be liable for any direct, indirect, incidental, or * consequential damages arising in any way out of the use of this software. */ #ifndef shared_H #define shared_H #include #include "../V/Vlibmath.h" #ifdef shared_IMPORT #define EXTERN #else #define EXTERN extern #endif /* * Application resources */ typedef struct { char *name; /* pushbutton's name */ XtCallbackProc callback; /* activate callback */ XtPointer client_data; /* data to register for callback */ } ActionAreaButton; typedef struct { Pixel select_pixel; Pixel grid_pixel; int line_thickness; int selection_thickness; int box_size; int box_offset; /* half of box_size */ int pick_sensitivity; int button_size; Pixel cursor_foreground; Pixel cursor_background; Boolean show_grid; Boolean show_ruler; XFontStruct *ruler_font; } AppData, *AppDataPtr; #define XtNselectionColor "selectionColor" #define XtCSelectionColor "SelectionColor" #define XtNgridColor "gridColor" #define XtCGridColor "GridColor" #define XtNlineThickness "lineThickness" #define XtCLineThickness "LineThickness" #define XtNselectionThickness "selectionThickness" #define XtCSelectionThickness "SelectionThickness" #define XtNboxSize "boxSize" #define XtCBoxSize "BoxSize" #define XtNpickSensitivity "pickSensitivity" #define XtCPickSensitivity "PickSensitivity" #define XtNbuttonSize "buttonSize" #define XtCButtonSize "ButtonSize" #define XtNcursorForeground "cursorColor" #define XtCCursorForeground "CursorColor" #define XtNcursorBackground "cursorBackgroundColor" #define XtCCursorBackground "CursorBackgroundColor" #define XtNshowGrid "showGrid" #define XtCShowGrid "ShowGrid" #define XtNshowRuler "showRuler" #define XtCShowRuler "ShowRuler" #define XtNrulerFont "rulerFont" /* * Menu dialog identification codes */ #define MENU_SET_VIEWS 1 #define MENU_COPY 2 #define MENU_CUT 3 #define MENU_PASTE 4 #define MENU_MIRROR_XZ 5 #define MENU_MIRROR_XY 6 #define MENU_MIRROR_YZ 7 #define MENU_CLEAR 8 #define MENU_SAVE 9 #define MENU_SAVE_AS 10 #define MENU_OPEN 11 #define MENU_NEW 12 #define MENU_GRID 13 #define MENU_RULER 14 #define MENU_SET_VIEWS_COMPLETE 15 #define MENU_SET_VIEWS_CANCEL 16 #define MENU_RESCALE_APPLY 17 #define MENU_RESCALE_CANCEL 18 #define MENU_RESCALE 19 #define MENU_MARKER 20 /* 32 markers are available */ #define MENU_MARKER_LAST 51 /* This is the highest marker */ #define MENU_GEAR_CALCULATE 52 #define MENU_GEAR_CANCEL 53 #define MENU_GEAR 54 #define MENU_INFO_CALCULATE 55 #define MENU_INFO_CANCEL 56 #define MENU_INFO 57 #define MENU_DERIV_CALCULATE 58 #define MENU_DERIV_CANCEL 59 #define MENU_DERIV 60 #define MENU_PWR_CALCULATE 61 #define MENU_PWR_CANCEL 62 #define MENU_PWR 63 #define MENU_ROTATE_X 64 typedef struct _view_info_t { struct _view_info_t *other_view; unsigned int flags; Widget other_widget; /* the other view */ Window other_window; /* XtWindow (other_widget) */ Pixmap pixmap; /* A copy of this window's contents */ GC gc; GC erase_gc; GC grid_gc; short origin_x, origin_y; /* view's origin screen location */ int layout; /* axes that we're viewing */ Dimension width, height; } view_info_t; #define VI_PIXMAP_ALLOCATED 1 typedef struct { long numerator, denominator; } fraction_t; typedef struct { fraction_t x, y, z; } loc_t; typedef struct { loc_t location; /* precise point location */ VPoint point; /* location as doubles */ short x, y, z; /* pixel offset from origin */ } point_t; typedef struct _polygon_t { long id; long next; VPoint normal; /* normal vector of this polygon's plane */ VPoint origin; /* plane's origin */ double d; /* plane equation: a x + b y + c z + d = 0 */ VPoint trihedral; /* used to transform from planar to world */ int num_points; /* number of points defined */ point_t *point; /* an array of points */ } polygon_t; typedef struct { Boolean defined; /* is the marker defined yet? */ int id; /* a unique identifier for each marker */ char name[32]; /* name of this marker */ point_t location; /* where is this marker located */ } marker_t; EXTERN AppData app_data; EXTERN int edit_state; EXTERN polygon_t *cur_polygon; EXTERN int sel_polygon; /* list of selected polygons */ EXTERN int unsel_polygon; /* list of unselected polygons */ EXTERN int clipboard_polygon; EXTERN polygon_t *polygon_list; /* array of polygon pool */ EXTERN int polygon_count, polygon_max; EXTERN double pixel_scale; /* display scale (units per pixel) */ EXTERN long ruler_divisions; EXTERN point_t *tmp_point; EXTERN int tmp_point_max; EXTERN Widget twindow; EXTERN Widget bwindow; EXTERN Widget open_dialog; EXTERN Widget save_as_dialog; EXTERN Widget save_formats[3]; EXTERN Widget set_views_dialog; EXTERN Widget rescale_field; EXTERN Widget rescale_dialog; EXTERN Widget gear_dialog; EXTERN Widget info_dialog; EXTERN Widget deriv_dialog; EXTERN Widget powerplant_dialog; EXTERN Widget extent_x, extent_y, extent_z; EXTERN Widget x_field, y_field, z_field; EXTERN XPoint drag_origin; /* where a drag operation started */ EXTERN Boolean drag_mode; EXTERN XSegment rubber_lines[2]; EXTERN Cursor cursors[6]; EXTERN Boolean filename_valid; EXTERN char filename[256]; EXTERN int desired_view; EXTERN marker_t *marker_list; EXTERN int current_marker; EXTERN int marker_count; EXTERN Boolean craft_valid; EXTERN char craft_name[128]; // A copy of the craft type structure from the acm/inventory.h file with only // the fields here left. typedef struct craftType { char *name; /* short name of aircraft class */ double Clda; /* roll moment from aileron offset */ double Cldr; /* roll moment from rudder offset */ double Clp; /* roll damping */ double Cmq; /* damping in pitch */ double Cnr; /* damping in yaw */ VMatrix I; /* Moments of Inertia about CG in AXYZ (lb ft^2) */ double cmSlope; /* CmAlpha curve slope */ double wingS; /* wing area (ft^2) */ double wings; /* wing half-span (ft) */ double c; /* mean aerodynamic chord (MAC) (ft) */ double emptyWeight; /* empty mass (lb) */ double maxFuel; /* maximum internal fuel (lb) */ double maxThrust; /* max static thrust, military power (lbf) */ double maxABThrust; /* max static thrust, afterburner on (lbf) */ double engineLag; /* controls lag between throttle and RPM */ double spFuelConsump; /* specific fuel consump(lb fuel/lbf T x hr) */ double spABFuelConsump; VPoint viewPoint; /* pilot's viewing location wrt CG (ft) */ VPoint rm, rn; /* location if main/nose gear attachments */ double Dm, Dn; /* main/nose oleo damping factor */ double Km, Kn; /* main/nose oleo spring factor */ double Gm, Gn; /* main/nose strut length with tire */ double cmMax, cnMax; /* main/nose maximum oleo extension distance */ } craftType; EXTERN craftType c; /* * edit_state values */ #define STATE_POINT 0 #define STATE_POLYGON 1 #define STATE_MOVE_ORIGIN 2 #define STATE_CIRCLE 3 #define STATE_MARKER 4 /* * view layouts */ #define VL_XZ 0 #define VL_XY 1 #define VL_NXZ 2 #define VL_NXY 3 #define VL_NXNZ 4 #define VL_NXNY 5 #define VL_NYX 6 #define VL_NYZ 7 #define VL_NYNX 8 #define VL_NYNZ 9 /* * Cursor definitions */ #define CURSOR_POINT 0 #define CURSOR_POLY_PLANE 1 #define CURSOR_POLY 2 #define CURSOR_ORIGIN 3 #define CURSOR_CIRCLE 4 #define CURSOR_MARKER 5 /* * Valid view configurations */ #define VIEW_LEFT_TOP 0 #define VIEW_FRONT_TOP 1 /* * Markers */ #define MARKER_HEAD 0 #define MARKER_NOSE_GEAR 1 #define MARKER_MAIN_GEAR 2 #define MARKER_TAIL_SCRAPE 3 /* * Nasty pointer to/from int conversions that prevent gcc -Wall complains * on both 32 and 64 bits systems. The code use them here and there where * Xt callbacks expects users' data be pointers instead. */ #define shared_PtrToInt(p) ((int)((void *)(p) - (void *) 0)) #define shared_IntToPtr(i) ((void *)((char *) 0 + i)) EXTERN view_info_t t_info, b_info; EXTERN void SetCursor (int id); EXTERN void MenuCB (Widget w, void *client_data, void *call_data); #undef EXTERN #endif acm-6.0_20200416/src/gedit/io.c0000644000000000000000000001477013074625071014247 0ustar rootroot/* * Copyright (c) 1994, Riley Rainey, riley@netcon.com * * Permission to use, copy, modify and distribute (without charge) this * software, documentation, images, etc. is granted, provided that this * comment and the author's name is retained. * * This software is provided by the author as is, and without any expressed * or implied warranties, including, but not limited to, the implied * warranties of merchantability and fitness for a particular purpose. In no * event shall the author be liable for any direct, indirect, incidental, or * consequential damages arising in any way out of the use of this software. */ #include #include #include #include #include "../util/memory.h" #include "shared.h" #include "gutil.h" #include "gutil1.h" #include "dialog.h" #include "edit.h" #define io_IMPORT #include "io.h" static char magic_header[] = { 'R', 'R', '1', '1', 0, 0, 0, 1 }; #define REVISION 1 void ClearWorkspace (Boolean redisplay) { register int i; for (i=sel_polygon; i >= 0; i = polygon_list[i].next) FreePolygon (&polygon_list[i]); sel_polygon = -1; for (i=unsel_polygon; i >= 0; i = polygon_list[i].next) FreePolygon (&polygon_list[i]); unsel_polygon = -1; if (cur_polygon != NULL) FreePolygon (cur_polygon); if (redisplay) { DrawWidget (twindow, False); DrawWidget (bwindow, False); } for (i=0; i 4 && strcmp(&name[n-4], ".obj") == 0) { return -1; // FIXME: handle error } if ((f = fopen (name, "r")) == (FILE *) NULL) { fprintf (stderr, "Unable to open %s\n", name); return -1; } ClearWorkspace (False); if (fread ((char *) magic, sizeof (magic), 1, f) != 1) { return -1; // FIXME: handle error } if (strncmp (magic, magic_header, 8) != 0) { gedit_error ("That file does not appear to be\n\ a gedit data file. It cannot be\n\ edited by this program."); return -1; } if (fread ((char *) &revision, sizeof (revision), 1, f) != 1) { return -1; // FIXME: handle error } if (fread ((char *) &object_count, sizeof (object_count), 1, f) != 1) { return -1; // FIXME: handle error } if (fread ((char *) &scale, sizeof (scale), 1, f) != 1) { return -1; // FIXME: handle error } pixel_scale = scale; while (object_count-- > 0) { ReadObject (f); } /* * Now try to read markers */ if (fread ((char *) &object_count, sizeof (object_count), 1, f) == 1) { while (object_count-- > 0) { ReadMarker (f); } } /* * Attempt to read the craft structure. */ if (fread ((char *) &craft_name, sizeof (craft_name), 1, f) != 1) { return -1; // FIXME: handle error } if (fread ((char *) &c, sizeof (c), 1, f) == 1) { craft_valid = 1; c.name = craft_name; InitializeDialogs (&c); } fclose (f); DrawWidget (twindow, False); DrawWidget (bwindow, False); return 0; } int ReadObject (FILE *f) { polygon_t poly, *p; view_info_t *q; register int i; fread ((char *) &poly, sizeof (poly), 1, f); XtVaGetValues (twindow, XmNuserData, &q, NULL); p = AllocPolygon (); p->normal = poly.normal; p->origin = poly.origin; p->d = poly.d; p->num_points = poly.num_points; p->point = (point_t *) memory_allocate(poly.num_points * sizeof (point_t), NULL); fread ((char *) p->point, sizeof (point_t), poly.num_points, f); for (i=0; i < p->num_points; ++i) PointToXYZ (q, &p->point[i]); p->next = unsel_polygon; unsel_polygon = p->id; return 0; } int ReadMarker (FILE *f) { marker_t m; register int i; fread ((char *) &m, sizeof (m), 1, f); for (i=0; i= 0; i = polygon_list[i].next) { p = &polygon_list[i]; if (!(p->point[0].point.x == 0.0 && p->point[0].point.y == 0.0 && p->point[0].point.z == 0.0 && p->point[1].point.x == 0.0 && p->point[1].point.y == 0.0 && p->point[1].point.z == 0.0)) object_count ++; } for (i=unsel_polygon; i >= 0; i = polygon_list[i].next){ p = &polygon_list[i]; if (!(p->point[0].point.x == 0.0 && p->point[0].point.y == 0.0 && p->point[0].point.z == 0.0 && p->point[1].point.x == 0.0 && p->point[1].point.y == 0.0 && p->point[1].point.z == 0.0)) object_count ++; } if (fwrite ((char *) &object_count, sizeof (object_count), 1, f) != 1) { return -1; // FIXME: handle error } if (fwrite ((char *) &pixel_scale, sizeof (pixel_scale), 1, f) != 1) { return -1; // FIXME: handle error } for (i=sel_polygon; i >= 0; i = polygon_list[i].next) WriteObject (f, &polygon_list[i]); for (i=unsel_polygon; i >= 0; i = polygon_list[i].next) WriteObject (f, &polygon_list[i]); object_count = 0; for (i=0; ipoint[0].point.x == 0.0 && p->point[0].point.y == 0.0 && p->point[0].point.z == 0.0 && p->point[1].point.x == 0.0 && p->point[1].point.y == 0.0 && p->point[1].point.z == 0.0) { return; } fwrite ((char *) p, sizeof (polygon_t), 1, f); fwrite ((char *) p->point, sizeof (point_t), p->num_points, f); } void WriteMarker (FILE *f, marker_t *p) { fwrite ((char *) p, sizeof (marker_t), 1, f); } int gedit_error (char *s) { fprintf (stderr, s); return 0; } acm-6.0_20200416/src/gedit/actions.h0000644000000000000000000000167613074625071015306 0ustar rootroot/* * Copyright (c) 1994, Riley Rainey, riley@netcon.com * * Permission to use, copy, modify and distribute (without charge) this * software, documentation, images, etc. is granted, provided that this * comment and the author's name is retained. * * This software is provided by the author as is, and without any expressed * or implied warranties, including, but not limited to, the implied * warranties of merchantability and fitness for a particular purpose. In no * event shall the author be liable for any direct, indirect, incidental, or * consequential damages arising in any way out of the use of this software. */ #ifndef actions_H #define actions_H #ifdef actions_IMPORT #define EXTERN #else #define EXTERN extern #endif EXTERN void InitializeTranslations (XtAppContext app, Widget w1, Widget w2); EXTERN void InstallNormalTranslations (Widget w); EXTERN void InstallExtraTranslations (Widget w); #undef EXTERN #endif acm-6.0_20200416/src/gedit/CrExFormDlg.c0000644000000000000000000001035613074625071015750 0ustar rootroot/* * Copyright (c) 1994, Riley Rainey, riley@netcon.com * * Permission to use, copy, modify and distribute (without charge) this * software, documentation, images, etc. is granted, provided that this * comment and the author's name is retained. * * This software is provided by the author as is, and without any expressed * or implied warranties, including, but not limited to, the implied * warranties of merchantability and fitness for a particular purpose. In no * event shall the author be liable for any direct, indirect, incidental, or * consequential damages arising in any way out of the use of this software. */ #include #include #include #include #include #include #include "shared.h" #define CrExFormDlg_IMPORT #include "CrExFormDlg.h" void DestroyParentCallback(Widget w, XtPointer client_data, XtPointer call_data) { XtDestroyWidget(XtParent(w)); } void SetDialogPosition(Widget w, XtPointer client_data, XtPointer call_data) { Position x, y, x1, y1; Dimension twidth, width, theight, height; Widget top = XtParent(w); XtVaGetValues(top, XmNx, &x, XmNy, &y, XmNwidth, &twidth, XmNheight, &theight, NULL); XtVaGetValues(w, XmNy, &x1, XmNy, &y1, XmNwidth, &width, XmNheight, &height, NULL); if(x1 != 0 && y1 != 0) return; XtVaSetValues(w, XmNx, x +(twidth - width) / 2, XmNy, y +(theight - height) / 2, NULL); } Widget CreateButtonArea(char *name, Widget parent, ActionAreaButton *buttons, int num_buttons, int tightness, int default_button) { Widget button_area, widget; register int i; Dimension height, h; button_area = XtVaCreateWidget(name, xmFormWidgetClass, parent, XmNfractionBase, tightness * num_buttons - 1, XmNskipAdjust, True, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); for(i=0; i #ifdef io_IMPORT #define EXTERN #else #define EXTERN extern #endif EXTERN void ClearWorkspace (Boolean redisplay); EXTERN int ReadGeditFile (char *name); EXTERN int ReadObject (FILE *f); EXTERN int ReadMarker (FILE *f); EXTERN int WriteGeditFile (char *name); EXTERN void WriteObject (FILE *f, polygon_t *p); EXTERN void WriteMarker (FILE *f, marker_t *p); EXTERN int gedit_error (char *s); #undef EXTERN #endif acm-6.0_20200416/src/gedit/gutil1.h0000644000000000000000000000245213074625071015044 0ustar rootroot/* * Copyright (c) 1994, Riley Rainey, riley@netcon.com * * Permission to use, copy, modify and distribute (without charge) this * software, documentation, images, etc. is granted, provided that this * comment and the author's name is retained. * * This software is provided by the author as is, and without any expressed * or implied warranties, including, but not limited to, the implied * warranties of merchantability and fitness for a particular purpose. In no * event shall the author be liable for any direct, indirect, incidental, or * consequential damages arising in any way out of the use of this software. */ #ifndef gutil1_H #define gutil1_H #ifdef gutil1_IMPORT #define EXTERN #else #define EXTERN extern #endif EXTERN void RescaleView (Widget w, double factor); EXTERN void DrawWidget (Widget w, Boolean immediate); EXTERN void DrawPolygon (Widget w, polygon_t *poly, Boolean immediate); EXTERN void WorldToWidget (view_info_t *p, point_t *q, int *x, int *y); EXTERN void DrawGrid (view_info_t *p, Display *dpy, Drawable d); EXTERN void DrawSelectedPolygon (Widget w, polygon_t *poly, Boolean immediate, Boolean erase); EXTERN void DrawRuler (view_info_t *p, Display *dpy, Drawable d, Pixel bg); EXTERN void StringSize (char *s, int *xw, int *yw); #undef EXTERN #endif acm-6.0_20200416/src/gedit/gdf-little-endian/0000755000000000000000000000000013175062143016747 5ustar rootrootacm-6.0_20200416/src/gedit/gdf-little-endian/sa11-u.gdf0000644000000000000000000001754410357223037020453 0ustar rootrootRR11?(CM???( (& (?L(CM???L(?CM??L(?L(ܿCM??L( CM??L(мL(CM?ܿL(ܿCM?L(<L( ?CM?L( CM??ۿL@%" #]@%W'M(J"@Hj dj j j j j  %@?"@@@(I)H H6  3 ?'@1 (?J'@M@%@W#?]?@0  ?i@r@ؿ??(?/ )H(?I@?@?"@?%@ ?"@H. %@?"@@@(I)H ?`- ؿr i ?@%x, #]@%W'M(J'@@% (?J'@M@%@W#?]@X$  ?i@r@ؿ?(?# )H(?I@?@?"@?%@k k k k l $l 0! ؿr iacm-6.0_20200416/src/gedit/gdf-little-endian/sa10-s.gdf0000644000000000000000000001314410357223037020440 0ustar rootrootRR11 ??@2?H3 K4|Pk?K4,Ԛ?oŏa @,Ԛ?9k@ݵ|г? rH@ݵ|г?uq h@|Pk?0@`2 Onfc]?<,ԊI.!?I.!I.!? #include #define balance_IMPORT #include "balance.h" void balance (struct balance_data *s) { double theta, cosTheta, sinTheta; double Fmz, Fnz; /* * Determine the rest pitch angle of the aircraft body */ theta = - atan2 (s->rn.z - s->rm.z, s->rn.x - s->rm.x); cosTheta = cos(theta); sinTheta = sin(theta); printf ("Theta = %f degrees (positive down)\n", theta * 180.0 / M_PI); /* * Determine correct rm/rn values */ s->rn.z = s->rn.z - s->Gn - s->cn; s->rm.z = s->rm.z - s->Gm - s->cm; /* * Determine spring constants */ Fmz = (s->weight * s->rn.x) / (s->rn.x - s->rm.x); Fnz = s->weight - Fmz; s->Km = Fmz / (s->cmMax - s->cm); s->Kn = Fnz / (s->cnMax - s->cn); /* * Determine the initial grounding point */ s->Gpz = s->rm.x * sinTheta + (s->rm.z + s->Gm + s->cm) * cosTheta; } #ifdef notdef main() { struct balance_data s; /* * Wheel contact locations for the aircraft fully loaded at rest. */ VSetPoint (s.rn, 14.0, 0, 6.5); VSetPoint (s.rm, -1.0, 0, 6.5); /* * Gross weight */ s.weight = 24326.0; /* * Maximum oleo extension lengths */ s.cnMax = 1.5; s.cmMax = 1.5; /* * The length of the wheel and lower landing gear strut */ s.Gm = 1.5; s.Gn = 1.5; /* * Rest oleo extension; must be less than cnMax or cmMax; usually about * half the max value. */ s.cm = 1.0; s.cn = 1.0; printf ("Input:\n"); printf ("nose contact = %lf %lf %lf\n", s.rn.x, s.rn.y, s.rn.z); printf ("main's contact = %lf %lf %lf\n", s.rm.x, s.rm.y, s.rm.z); printf ("Weight = %lf\n", s.weight); balance(&s); printf ("\nOutput:\n"); printf ("rm = %lf, %lf, %lf\n", s.rm.x, s.rm.y, s.rm.z); printf ("rn = %lf, %lf, %lf\n", s.rn.x, s.rn.y, s.rn.z); printf ("Km = %lf\n", s.Km); printf ("Kn = %lf\n", s.Kn); printf ("Grounding point (z) = %lf\n", s.Gpz); printf ("\n\"inventory\" form:\n\n"); printf ("\tRm\t\t{%lg, %lg, %lg}\n", s.rm.x, s.rm.y, s.rm.z); printf ("\tRn\t\t{%lg, %lg, %lg}\n", s.rn.x, s.rn.y, s.rn.z); printf ("\tKm\t\t%lg\n", s.Km); printf ("\tKn\t\t%lg\n", s.Kn); printf ("\tGm\t\t%lg\n", s.Gm); printf ("\tGn\t\t%lg\n", s.Gn); printf ("\tCmMax\t\t%lg\n", s.cmMax); printf ("\tCnMax\t\t%lg\n", s.cnMax); printf ("\tGroundingPoint\t{0.0, 0.0, %lg}\n", s.Gpz); exit (0); } #endif acm-6.0_20200416/src/gedit/edit.c0000644000000000000000000001377713156540162014571 0ustar rootroot/* * Copyright (c) 1994, Riley Rainey, riley@netcon.com * * Permission to use, copy, modify and distribute (without charge) this * software, documentation, images, etc. is granted, provided that this * comment and the author's name is retained. * * This software is provided by the author as is, and without any expressed * or implied warranties, including, but not limited to, the implied * warranties of merchantability and fitness for a particular purpose. In no * event shall the author be liable for any direct, indirect, incidental, or * consequential damages arising in any way out of the use of this software. */ #include #include #include "../util/memory.h" #include "shared.h" #include "gutil.h" #include "gutil1.h" #define edit_IMPORT #include "edit.h" void Mirror (int op) { int i, j; polygon_t *new, *poly; view_info_t *p; XtVaGetValues (twindow, XmNuserData, &p, NULL); for (i = sel_polygon; i >= 0; i = polygon_list[i].next) { new = BeginPolygon (); poly = &polygon_list[i]; new->num_points = poly->num_points; new->point = (point_t *) memory_allocate(new->num_points * sizeof (point_t), NULL); for (j=0; j < poly->num_points; ++j) { switch (op) { case MENU_MIRROR_XZ: new->point[j] = poly->point[poly->num_points - j - 1]; new->point[j].point.y = - new->point[j].point.y; PointToXYZ (p, &new->point[j]); break; case MENU_MIRROR_XY: new->point[j] = poly->point[poly->num_points - j - 1]; new->point[j].point.z = - new->point[j].point.z; PointToXYZ (p, &new->point[j]); break; case MENU_MIRROR_YZ: new->point[j] = poly->point[poly->num_points - j - 1]; new->point[j].point.x = - new->point[j].point.x; PointToXYZ (p, &new->point[j]); break; } } ComputePlaneEquation (new); new->next = sel_polygon; sel_polygon = new->id; cur_polygon = (polygon_t *) NULL; } DrawWidget (twindow, False); DrawWidget (p->other_widget, False); } void PointToXYZ (view_info_t *p, point_t *point) { /* * warning, signs assume the original layout only */ switch (p->layout) { case VL_NXZ: point->x = (int) (- point->point.x / pixel_scale) + p->origin_x; point->y = (int) (- point->point.y / pixel_scale) + p->other_view->origin_y; point->z = (int) (point->point.z / pixel_scale) + p->origin_y; break; case VL_NXNY: point->x = (int) (- point->point.x / pixel_scale) + p->origin_x; point->y = (int) (- point->point.y / pixel_scale) + p->origin_y; point->z = (int) (point->point.z / pixel_scale) + p->other_view->origin_y; break; case VL_NYZ: point->x = (int) (point->point.x / pixel_scale) + p->other_view->origin_y; point->y = (int) (- point->point.y / pixel_scale) + p->origin_x; point->z = (int) (point->point.z / pixel_scale) + p->origin_y; break; case VL_NYX: point->x = (int) (point->point.x / pixel_scale) + p->origin_y; point->y = (int) (- point->point.y / pixel_scale) + p->origin_x; point->z = (int) (point->point.z / pixel_scale) + p->other_view->origin_y; break; } } void ClearSelection() { int i, j; view_info_t *p; XtVaGetValues (twindow, XmNuserData, &p, NULL); for (i=sel_polygon; i>= 0; i = j) { j = polygon_list[i].next; FreePolygon (&polygon_list[i]); } sel_polygon = -1; DrawWidget (twindow, False); DrawWidget (p->other_widget, False); } void CopySelection() { int i, j, nn = 0; view_info_t *p; polygon_t *new, *poly; XtVaGetValues (twindow, XmNuserData, &p, NULL); ClearClipboard(); for (i = sel_polygon; i >= 0; i = polygon_list[i].next) { new = BeginPolygon (); poly = &polygon_list[i]; new->num_points = poly->num_points; new->point = (point_t *) memory_allocate(new->num_points * sizeof (point_t), NULL); for (j=0; j < poly->num_points; ++j) { new->point[j] = poly->point[j]; PointToXYZ (p, &new->point[j]); } ComputePlaneEquation (new); new->next = clipboard_polygon; clipboard_polygon = new->id; cur_polygon = (polygon_t *) NULL; ++nn; } } void ClearClipboard() { int i, j; view_info_t *p; XtVaGetValues (twindow, XmNuserData, &p, NULL); for (i=clipboard_polygon; i>= 0; i = j) { j = polygon_list[i].next; FreePolygon (&polygon_list[i]); } clipboard_polygon = -1; } void PasteSelection() { int i, j, nn = 0; view_info_t *p; polygon_t *new, *poly; XtVaGetValues (twindow, XmNuserData, &p, NULL); ClearSelection(); for (i = clipboard_polygon; i >= 0; i = polygon_list[i].next) { new = BeginPolygon (); poly = &polygon_list[i]; new->num_points = poly->num_points; new->point = (point_t *) memory_allocate(new->num_points * sizeof (point_t), NULL); for (j=0; j < poly->num_points; ++j) { new->point[j] = poly->point[j]; /*new->point[j].y += 1.0; new->point[j].z += 1.0;*/ PointToXYZ (p, &new->point[j]); } ComputePlaneEquation (new); new->next = sel_polygon; sel_polygon = new->id; cur_polygon = (polygon_t *) NULL; ++nn; } DrawWidget (twindow, False); DrawWidget (p->other_widget, False); } void RotateXSelection() { int i, j; view_info_t *p; double tmp; polygon_t *poly; XtVaGetValues (twindow, XmNuserData, &p, NULL); for (i = sel_polygon; i >= 0; i = polygon_list[i].next) { poly = &polygon_list[i]; for (j=0; j < poly->num_points; ++j) { tmp = poly->point[j].point.z; poly->point[j].point.z = poly->point[j].point.y; poly->point[j].point.y = tmp; PointToXYZ (p, &poly->point[j]); } ComputePlaneEquation (poly); } DrawWidget (twindow, False); DrawWidget (p->other_widget, False); } void PrintList(int start) { int i; if (start == -1) { printf ("NULL"); } else { for (i = start; i >= 0; i = polygon_list[i].next) { printf ("%d ", i); } } printf ("\n"); } void PrintDiagnostics() { printf ("sel_polygon list : "); PrintList (sel_polygon); printf ("unsel_polygon list : "); PrintList (unsel_polygon); printf ("clipboard_polygon list : "); PrintList (clipboard_polygon); } acm-6.0_20200416/src/gedit/dialog.c0000644000000000000000000002766213143357677015116 0ustar rootroot/* * Copyright (c) 1994, Riley Rainey, riley@netcon.com * * Permission to use, copy, modify and distribute (without charge) this * software, documentation, images, etc. is granted, provided that this * comment and the author's name is retained. * * This software is provided by the author as is, and without any expressed * or implied warranties, including, but not limited to, the implied * warranties of merchantability and fitness for a particular purpose. In no * event shall the author be liable for any direct, indirect, incidental, or * consequential damages arising in any way out of the use of this software. */ #include #include #include #include #include #include "shared.h" #include "cell.h" #include "CrExFormDlg.h" #define dialog_IMPORT #include "dialog.h" void balance (struct balance_data *s) { double theta, cosTheta, sinTheta; double Fmz; /* * Determine the rest pitch angle of the aircraft body */ theta = - atan2 (s->rn.z - s->rm.z, s->rn.x - s->rm.x); cosTheta = cos(theta); sinTheta = sin(theta); s->theta = theta; /* * Determine correct rm/rn values */ s->rn.z = s->rn.z - s->Gn - s->cn; s->rm.z = s->rm.z - s->Gm - s->cm; /* * Determine spring constants */ Fmz = (s->weight * cosTheta * s->rn.x) / (s->rm.x - s->rn.x); s->Km = - Fmz * s->cm; s->Kn = (- Fmz - s->weight * cosTheta) * - s->cn; /* * Determine the initial grounding point */ s->Gpz = s->rm.x * sinTheta + (s->rm.z + s->Gm + s->cm) * cosTheta; } enum { InfoName, InfoEmptyWeight, InfoIxx, InfoIyy, InfoIzz, InfoWingSpan, InfoWingArea, InfoWingChord, GearGm, GearcmMax, GearDm, GearKm, GearGn, GearcnMax, GearDn, GearKn, DerivClda, DerivCldr, DerivClp, DerivCmq, DerivCnr, DerivCmAlpha, DerivCmFactor, PowerplantFuel, PowerplantThrust, PowerplantABThrust, PowerplantLag, PowerplantSpFuelConsump, PowerplantSpABFuelConsump }; struct cell info_dialog_items[] = { { InfoName, "Aircraft Name", "Unknown", 10, NULL, NULL }, { InfoEmptyWeight, "Empty Weight [lbs]", "10000", 10, NULL, NULL }, { InfoIxx, "Ixx [slug*ft^2]", "5000", 10, NULL, NULL }, { InfoIyy, "Iyy [slug*ft^2]", "50000", 10, NULL, NULL }, { InfoIzz, "Izz [slug*ft^2]", "50000", 10, NULL, NULL }, { InfoWingSpan, "WingSpan [ft]", "50000", 10, NULL, NULL }, { InfoWingArea, "Wing Area [ft]", "50000", 10, NULL, NULL }, { InfoWingChord, "Wing Chord [ft]", "50000", 10, NULL, NULL }, { -1, NULL, NULL, 0, NULL, NULL } }; struct cell gear_dialog_items[] = { { GearGm, "Main Gear Assembly Length (Gm) [ft]", "2.0", 10, NULL, NULL }, { GearcmMax, "Main Gear Max Extension (cmMax) [ft]", "1.0", 10, NULL, NULL }, { GearDm, "Main Gear Damping Factor (Dm) [lb/ft/sec]", "2.0", 10, NULL, NULL }, { GearKm, "Main Gear Spring Factor (Km) [*]", "0.0", 10, NULL, NULL }, { GearGn, "Nose Gear Assembly Length (Gn) [ft]", "2.0", 10, NULL, NULL }, { GearcnMax, "Nose Gear Max Extension (cnMax) [ft]", "1.0", 10, NULL, NULL }, { GearDn, "Nose Gear Damping Factor (Dn) [lb/ft/sec]", "2.0", 10, NULL, NULL }, { GearKn, "Nose Gear Spring Factor (Kn) [*]", "0.0", 10, NULL, NULL }, { -1, NULL, NULL, 0, NULL, NULL } }; struct cell deriv_dialog_items[] = { { DerivClda, "Roll moment from aileron offset", "0.03", 10, NULL, NULL }, { DerivCldr, "Roll moment from rudder offset", "0.003", 10, NULL, NULL }, { DerivClp, "Roll damping", "-0.3", 10, NULL, NULL }, { DerivCmq, "Pitch damping", "-8.0", 10, NULL, NULL }, { DerivCnr, "Yaw damping", "-2.0", 10, NULL, NULL }, { DerivCmAlpha, "Pitch due to angle of attack", "-0.3", 10, NULL, NULL }, { DerivClda, "Pitch due to angle of attack [stalled]", "-0.2", 10, NULL, NULL }, { -1, NULL, NULL, 0, NULL, NULL } }; struct cell pwr_dialog_items[] = { { PowerplantFuel, "Internal Fuel Capacity [lbs]", "1000", 10, NULL, NULL }, { PowerplantThrust, "Military Thrust [lbs]", "10000", 10, NULL, NULL }, { PowerplantABThrust, "Afterburner Thrust [lbs]", "10000", 10, NULL, NULL }, { PowerplantLag, "Engine response lag [negative value]", "-3.0", 10, NULL, NULL }, { PowerplantSpFuelConsump, "Specific fuel consumption, afterburner off [lb fuel/lb T * hr]", "0.7", 10, NULL, NULL }, { PowerplantSpABFuelConsump, "Specific fuel consumption, afterburner on [lb fuel/lb T * hr]", "2.50", 10, NULL, NULL }, { -1, NULL, NULL, 0, NULL, NULL } }; static Widget CreatePanelDialog (char *name, Widget parent, struct cell *p, int count, int calc_fn, int cancel) { Arg args[10]; char s1[32], s2[32]; static ActionAreaButton action_items[] = { { "Calculate", MenuCB, (XtPointer) NULL }, { "Dismiss", MenuCB, (XtPointer) NULL }, { "Help", NULL, NULL }, }; Widget dialog, form; int i, n; XmString s; count --; /* * Nasty cast here to assign int param to a 32 or 64 bits pointer * preventing gcc -Wall complains :-) */ action_items[0].client_data = (XtPointer) shared_IntToPtr(calc_fn); action_items[1].client_data = (XtPointer) shared_IntToPtr(cancel); dialog = CreateExtendedFormDialog (name, parent, &form, action_items, XtNumber (action_items), 0); for (i=0; iemptyWeight); SetCellValueDouble (info_dialog_items, InfoIxx, c->I.m[0][0]); SetCellValueDouble (info_dialog_items, InfoIyy, c->I.m[1][1]); SetCellValueDouble (info_dialog_items, InfoIzz, c->I.m[2][2]); SetCellValueDouble (info_dialog_items, InfoWingSpan, c->wings * 2.0); SetCellValueDouble (info_dialog_items, InfoWingArea, c->wingS); SetCellValueDouble (info_dialog_items, InfoWingChord, c->c); SetCellValueDouble (gear_dialog_items, GearGm, c->Gm); SetCellValueDouble (gear_dialog_items, GearcmMax, c->cmMax); SetCellValueDouble (gear_dialog_items, GearDm, c->Dm); SetCellValueDouble (gear_dialog_items, GearKm, c->Km); SetCellValueDouble (gear_dialog_items, GearGn, c->Gn); SetCellValueDouble (gear_dialog_items, GearcnMax, c->cnMax); SetCellValueDouble (gear_dialog_items, GearDn, c->Dn); SetCellValueDouble (gear_dialog_items, GearKn, c->Kn); SetCellValueDouble (pwr_dialog_items, PowerplantFuel, c->maxFuel); SetCellValueDouble (pwr_dialog_items, PowerplantThrust, c->maxThrust); SetCellValueDouble (pwr_dialog_items, PowerplantABThrust, c->maxABThrust); SetCellValueDouble (pwr_dialog_items, PowerplantLag, c->engineLag); SetCellValueDouble (pwr_dialog_items, PowerplantSpFuelConsump, c->spFuelConsump); SetCellValueDouble (pwr_dialog_items, PowerplantSpABFuelConsump, c->spABFuelConsump); } void GetCraftInfo(craftType *c) { GetCellValueString (info_dialog_items, InfoName, craft_name); GetCellValueDouble (info_dialog_items, InfoEmptyWeight, &c->emptyWeight); GetCellValueDouble (info_dialog_items, InfoIxx, &c->I.m[0][0]); GetCellValueDouble (info_dialog_items, InfoIyy, &c->I.m[1][1]); GetCellValueDouble (info_dialog_items, InfoIzz, &c->I.m[2][2]); GetCellValueDouble (info_dialog_items, InfoWingSpan, &c->wings); c->wings /= 2.0; GetCellValueDouble (info_dialog_items, InfoWingArea, &c->wingS); GetCellValueDouble (info_dialog_items, InfoWingChord, &c->c); GetCellValueDouble (gear_dialog_items, GearGm, &c->Gm); GetCellValueDouble (gear_dialog_items, GearcmMax, &c->cmMax); GetCellValueDouble (gear_dialog_items, GearDm, &c->Dm); GetCellValueDouble (gear_dialog_items, GearKm, &c->Km); GetCellValueDouble (gear_dialog_items, GearGn, &c->Gn); GetCellValueDouble (gear_dialog_items, GearcnMax, &c->cnMax); GetCellValueDouble (gear_dialog_items, GearDn, &c->Dn); GetCellValueDouble (gear_dialog_items, GearKn, &c->Kn); GetCellValueDouble (pwr_dialog_items, PowerplantFuel, &c->maxFuel); GetCellValueDouble (pwr_dialog_items, PowerplantThrust, &c->maxThrust); GetCellValueDouble (pwr_dialog_items, PowerplantABThrust, &c->maxABThrust); GetCellValueDouble (pwr_dialog_items, PowerplantLag, &c->engineLag); GetCellValueDouble (pwr_dialog_items, PowerplantSpFuelConsump, &c->spFuelConsump); GetCellValueDouble (pwr_dialog_items, PowerplantSpABFuelConsump, &c->spABFuelConsump); c->viewPoint = marker_list[MARKER_HEAD].location.point; } void GearCalculate(craftType *c) { struct balance_data b; b.weight = c->emptyWeight + c->maxFuel; b.rm = marker_list[MARKER_MAIN_GEAR].location.point; b.rn = marker_list[MARKER_NOSE_GEAR].location.point; b.cm = GetCellValueDouble (gear_dialog_items, GearcmMax, &c->cmMax); b.cm *= 0.6; b.cn = GetCellValueDouble (gear_dialog_items, GearcnMax, &c->cnMax); b.cn *= 0.6; b.Gm = GetCellValueDouble (gear_dialog_items, GearGm, &c->Gm); b.Gn = GetCellValueDouble (gear_dialog_items, GearGn, &c->Gn); #ifdef notdef printf ("Input:\n"); printf ("nose contact = %lf %lf %lf\n", b.rn.x, b.rn.y, b.rn.z); printf ("main's contact = %lf %lf %lf\n", b.rm.x, b.rm.y, b.rm.z); printf ("Weight = %lf\n", b.weight); #endif balance (&b); #ifdef notdef printf ("\nOutput:\n"); printf ("rm = %lf, %lf, %lf\n", b.rm.x, b.rm.y, b.rm.z); printf ("rn = %lf, %lf, %lf\n", b.rn.x, b.rn.y, b.rn.z); printf ("Km = %lf\n", b.Km); printf ("Kn = %lf\n", b.Kn); printf ("Grounding point (z) = %lf\n", b.Gpz); printf ("\n\"inventory\" form:\n\n"); printf ("\tRm\t\t{%lg, %lg, %lg}\n", b.rm.x, b.rm.y, b.rm.z); printf ("\tRn\t\t{%lg, %lg, %lg}\n", b.rn.x, b.rn.y, b.rn.z); printf ("\tKm\t\t%lg\n", b.Km); printf ("\tKn\t\t%lg\n", b.Kn); printf ("\tGm\t\t%lg\n", b.Gm); printf ("\tGn\t\t%lg\n", b.Gn); printf ("\tCmMax\t\t%lg\n", c->cmMax); printf ("\tCnMax\t\t%lg\n", c->cnMax); printf ("\tGroundingPoint\t{0.0, 0.0, %lg}\n", b.Gpz); #endif c->rm = b.rm; c->rn = b.rn; c->Km = b.Km; c->Kn = b.Kn; //c->groundingPoint.x = c->groundingPoint.y = 0.0; //c->groundingPoint.z = b.Gpz; SetCellValueDouble (gear_dialog_items, GearKm, c->Km); SetCellValueDouble (gear_dialog_items, GearKn, c->Kn); } acm-6.0_20200416/src/gedit/gdf-big-endian/0000755000000000000000000000000013175062143016213 5ustar rootrootacm-6.0_20200416/src/gedit/gdf-big-endian/xmig29.gdf0000644000000000000000000003414410357223037020022 0ustar rootrootRR11??@@? #@@@i@@?i@?i@i@ i@@i@@i@@i@@i@@i@@?i@@ @i@?@ #@ @i@?i@i@i@i@i@i@ i@i@i@?i@@i?@3 ??3 #(@2@2?@2?@2@@2?@2?@2?@2?@3 3 #`@2@2@2@2@2@2@2@2??'?@' #'@?'?'''@ '@ '@'@7'@'@'@'@?'@@@?@ #'@'?''''7'' ' '?'''?MEz&f y~'7 LAw XQ7#"7{'7 LAw'7V-7@oh.6 *@@s?MEܿ&fi?y~*@@@ XQ8'#@@s*@@.@6 -@7@oh'@7V'@7 LAw"@7{ @? #0@Au@? @<@7@3@2@.@?7 J6 B@-@7@:@?@@Apz @>@? #@A?u@>@?@:`?@7?@"@I@@j0@8`@T7@N5@=3?0 `=291?ԚkK1:@@/j#/@:@@/cP>@-@Y9@`6`@D ?r[˓?CE|?yGC9@ f| #8@ X8@X&@?@ (!5@@ Ӹ S@#@ iE@*@ Uj%\)@"@ rd@I@@ $@g@@  9\@"@@ M}전@3@ h?-8@ ?X ?VlTDXzkP 88@?qnpN#4@78@W8@X2??CY(% ?VlTD?XzkP 88?qnpN#2?CY(%8X8W47r[˓?CE|yGC3 h?@ EL #8 ?X3 h?-"@ M}전@@  9\@@ $@g@" rd@I@* Uj%\)@# iE@ Ӹ S? (!5&8X8 XՍ]a?:ma#6u3 !@a #, 6u3 !F6^ F 7`C9FOL 8 /7"@R7 Vy"P8@!^-Ё'@Sr6 !)Bi$`=291ԚkK09j#6`D9` >-@C:@/cL/?5@ #H305=7N8`T0@j@"I@7@:`@>@@Au?Ս]a?:?ma $@a #@$@6 @!)Bi8@@!^-Ё'@Sr7@ Vy"P8 @ /7"@R7`@C9FOL6@^ F6@u3 !F,@ 4@4 #4@64@64@64@64@64@ 64?6464?64@?64@?6?4?@4 #04?64?64646464 64646464646?%r?@*@:"x"#H@*@)@*@)@"?@I@"@@I?%r]N7?@"@:"x"#`@"@I@"@I@*)@*)Pilot's Head Location@2@Nose/Tail Gear Ground Contact Po@&@9Main Gear Ground Contact Point@Tail Ground Contact Point8?Xacm-6.0_20200416/src/gedit/gdf-big-endian/ewacs.gdf0000644000000000000000000004412010357223037020000 0ustar rootrootRR11&?/hKȼm[s?e(V<" ?:}S$ShiftosfQuickPaste:5osfQuickPaste: quick-cut-s<" _+quick-cut-set() osfQ@" 2+Meta osfPrimaryPaste:<.cim%?@4?@4tosfPaste: paste-clipbo#??%@kgy-t: cut-primary() #??.@kgy>mary() Meta osfCut#??{B^Й@kg CuaryPaste: cut-primary() #?@佡/hJ?hKgrita osfPrimaryPaste:#?@佡/hJP% gimick-cut-set() osfQ#?@佡/hJ% {BgMefQuickPaste: quick-cut-s#??{B^Й % {CgquShiftosfQuickPaste:#?B^З % {Bgos%$f:s@)2R,>?X+./M@)2R,>t: cut-primary() @ @)2R,>?X+./MOy>mary() Meta osfCutf:s@)2R,>?X+./MCuaryPaste: cut-primary() f:s@)2R,>@$ަWrita osfPrimaryPaste:?X@)2R,>@ H(y imick-cut-set() osfQ@;@)2R,>@p+!MefQuickPaste: quick-cut-s@FLJ@)2R,>@`(quShiftosfQuickPaste:@6>T@)2R,>@YWNos$ @,?5w@)2R,>?< X}@)2R,>ShiftosfQuickPaste:@D@)2R,>?mOosfQuickPaste: quick-cut-s@,?5w@)2R,>?< X}(quick-cut-set() osfQ@X@)2R,>?\qq"Meta osfPrimaryPaste:?\qq@)2R,>?EimaryPaste: cut-primary() eO@)2R,>?S[rimary() Meta osfCuteO@)2R,>?ECut: cut-primary() @hK@)2R,>?EPy> !?eO)2R,>?E@)2R,>~t: cut-primary() @hK)2R,>?EP]y>mary() Meta osfCuteO)2R,>?E]CuaryPaste: cut-primary() eO)2R,>?S[]rita osfPrimaryPaste:?\qq)2R,>?E]imick-cut-set() osfQ@X)2R,>?\qq"]MefQuickPaste: quick-cut-s@,?5w)2R,>?< X}(]quShiftosfQuickPaste:@D)2R,>?mO]os!#?@FLJ)2R,>@`@)2R,>ShiftosfQuickPaste:@6>T)2R,>@YWN]osfQuickPaste: quick-cut-s@FLJ)2R,>@`(]quick-cut-set() osfQ@;)2R,>@p+!]Meta osfPrimaryPaste:?X)2R,>@ H(y] imaryPaste: cut-primary() f:s)2R,>@$ަW]rimary() Meta osfCutf:s)2R,>?X+./M]Cut: cut-primary() @ )2R,>?X+./MO]y>#"?73@\…@3ShiftosfQuickPaste:?DQ}3@o-*osfQuickPaste: quick-cut-s73@\…quick-cut-set() osfQ3@xCŮ- Meta osfPrimaryPaste:ܫק3@oh imaryPaste: cut-primary() !i 3?Kdrimary() Meta osfCut!i 3?p UCut: cut-primary() ?${tE3?p Uy>"?$gz3?he@3t: cut-primary() ?֗x7@3?hey>mary() Meta osfCut$gz3?heCuaryPaste: cut-primary() $gz3?N+rita osfPrimaryPaste:44贾3?UCimick-cut-set() osfQ 3?ֿ[MefQuickPaste: quick-cut-s~XZ!3?M#uquShiftosfQuickPaste:?߭=3?cCNos@,?5w@)2R,>?< X}@)2R,> hShiftosfQuickPaste:?߭=@3?cCNosfQuickPaste: quick-cut-s~XZ!@3?M#uquick-cut-set() osfQ @3?ֿ[Meta osfPrimaryPaste:44贾@3?UCimaryPaste: cut-primary() $gz@3?N+rimary() Meta osfCut$gz@3?heCut: cut-primary() ?֗x7@@3?hey>eO@)2R,>E@)2R,>|t: cut-primary() ?${tE@3?p Uy>mary() Meta osfCut!i @3?p UCuaryPaste: cut-primary() !i @3?Kdrita osfPrimaryPaste:ܫק@3@oh imick-cut-set() osfQ@3@xCŮ- MefQuickPaste: quick-cut-s7@3@\…quShiftosfQuickPaste:?DQ}@3@o-*os@8k)S?@$hø@8k losfPaste: paste-clipbo@8k'ʭr@yDNS y-t: cut-primary() @8k)S?@$høN^ y>mary() Meta osfCut@8k*DWR@#*ONf CuaryPaste: cut-primary() @8k+/a?SNmrita osfPrimaryPaste:@8k+'~S?ʵk Njimick-cut-set() osfQ@8k)e|n1?ྱN^MefQuickPaste: quick-cut-s@8k'?}{<+NRquShiftosfQuickPaste:@8k'$O?SNNos?@2?@2zosfPaste: paste-clipbo@2?@y-t: cut-primary() @2?@y>mary() Meta osfCut@2?@ CuaryPaste: cut-primary() @2@?rita osfPrimaryPaste:@2@imick-cut-set() osfQ@2@MefQuickPaste: quick-cut-s@2? quShiftosfQuickPaste:@2os?@4 4xShiftosfQuickPaste:@2osfQuickPaste: quick-cut-s@2 quick-cut-set() osfQ@2Meta osfPrimaryPaste:@2imaryPaste: cut-primary() @2?rimary() Meta osfCut@2@ Cut: cut-primary() @2@y>osfPaste: paste-clipbo@2@y-?# @#vShiftosfQuickPaste:#??y gosfQuickPaste: quick-cut-s#? gquick-cut-set() osfQ#?gMeta osfPrimaryPaste:#?gimaryPaste: cut-primary() #??grimary() Meta osfCut#?@g Cut: cut-primary() #?@gy>osfPaste: paste-clipbo#?<@gy-rpn?osfPrimaryPaste:?qt~-4% {Cimick-cut-set() osfQ88?% {B`MefQuickPaste: quick-cut-s@" {B^?% {B`oquShiftosfQuickPaste:@osfQuickPaste:@osfQ8@8?% {B`Meta osfPrimaryPaste:?qt?~-4% {Cim?ȼm[t?e(V@@" ?:}T#ta osfPrimaryPaste:<.cimick-cut-set() osfQ@@" 23MefQuickPaste: quick-cut-s<@" _3quShiftosfQuickPaste:5?osS:s-S:s?WJ1@/?4lmary() Meta osfCut>GCuaryPaste: cut-primary() 1@/rita osfPrimaryPaste:'@*Jimick-cut-set() osfQ@5@MefQuickPaste: quick-cut-s@<?uquShiftosfQuickPaste:@<?{osS:sI?S:sI?WJ@<?&jShiftosfQuickPaste:@<{osfQuickPaste: quick-cut-s@<uquick-cut-set() osfQ@5Meta osfPrimaryPaste:'*JimaryPaste: cut-primary() 1/rimary() Meta osfCut>GCu?Tq~P) l̿޻ i@?QQ?I ht: cut-primary() @?4ߊ4ߍy>mary() Meta osfCut@?QQpCuaryPaste: cut-primary() @'utrita osfPrimaryPaste:,@=@ff(imick-cut-set() osfQ'@<N MefQuickPaste: quick-cut-s$@< b+quShiftosfQuickPaste:@"@?mosTq~m) l?޻ i$< I fShiftosfQuickPaste:@"?mosfQuickPaste: quick-cut-s$< b3quick-cut-set() osfQ'<N>Meta osfPrimaryPaste:,=@ff(CimaryPaste: cut-primary() 'utMrimary() Meta osfCut?QQCut: cut-primary() ?4ߊ4ߍy>)??dt: cut-primary() @)@?P]y>mary() Meta osfCut)?[CuaryPaste: cut-primary() *@?drita osfPrimaryPaste:?+?iimick-cut-set() osfQ@+@?%kMefQuickPaste: quick-cut-s@+?+nquShiftosfQuickPaste:@+?Pmos @&??bShiftosfQuickPaste:@'?PMosfQuickPaste: quick-cut-s@&?+Lquick-cut-set() osfQ@'@?%OMeta osfPrimaryPaste:?'?QimaryPaste: cut-primary() (@?Vrimary() Meta osfCut)?_Cut: cut-primary() @)@?P]y> @4??`t: cut-primary() ?@3?y>mary() Meta osfCut@4?CuaryPaste: cut-primary() @3`?rita osfPrimaryPaste:@3?imick-cut-set() osfQ@2?MefQuickPaste: quick-cut-s@2?quShiftosfQuickPaste:?@2?os @5 ??^ShiftosfQuickPaste:?@5?osfQuickPaste: quick-cut-s@5 ?quick-cut-set() osfQ@4?Meta osfPrimaryPaste:@4?imaryPaste: cut-primary() @4`?rimary() Meta osfCut@3?Cut: cut-primary() ?@3?y> 3??\t: cut-primary() ?3?y>mary() Meta osfCut3?CuaryPaste: cut-primary() 4`?rita osfPrimaryPaste:4?imick-cut-set() osfQ4?MefQuickPaste: quick-cut-s5 ?quShiftosfQuickPaste:?5?os 2??ZShiftosfQuickPaste:?2?osfQuickPaste: quick-cut-s2?quick-cut-set() osfQ2?Meta osfPrimaryPaste:3?imaryPaste: cut-primary() 3`?rimary() Meta osfCut4?Cut: cut-primary() ?3?y> @;  ShiftosfQuickPaste:@=|osfQuickPaste: quick-cut-s@;mquick-cut-set() osfQ@:@VMeta osfPrimaryPaste:@7@ -imaryPaste: cut-primary() @2 rimary() Meta osfCut/ Cut: cut-primary() >Ny>osfPaste: paste-clipbo=Py-primary() Alt osfC2 ?Copy: copy-clipboard() &@T ning-of-line(extend) osfEndLi@8`?<>osfEndLine: end-of-line(@< ?ple?3 XShiftosfQuickPaste:2osfQuickPaste: quick-cut-s3 quick-cut-set() osfQ5`Meta osfPrimaryPaste:;*@w7imaryPaste: cut-primary() > *@L7rimary() Meta osfCut;kCu(??Vt: cut-primary() @@)@?Py>mary() Meta osfCut@)?CuaryPaste: cut-primary() @(@?rita osfPrimaryPaste:?@'? imick-cut-set() osfQ@@'@?%MefQuickPaste: quick-cut-s@@&?+quShiftosfQuickPaste:@@'?Pos@8k@'?}{<+@8kTShiftosfQuickPaste:?hÎ@2y b?\V osfQuickPaste: quick-cut-s?hÎ@3BD?GNnbquick-cut-set() osfQ?hÎ@3I?;-Meta osfPrimaryPaste:?hÎ@45d?)@imaryPaste: cut-primary() ?hÎ@5qE?\V rimary() Meta osfCut?hÎ@4}|".@O Cut: cut-primary() ?hÎ@3 X$@`U3 y>osfPaste: paste-clipbo?hÎ@3!0a@-jy-?hÎ3 X$@`U3?hÎRosfPaste: paste-clipbo?hÎ3!0a@-jy-t: cut-primary() ?hÎ3 X$@`U3 y>mary() Meta osfCut?hÎ4}|".@O CuaryPaste: cut-primary() ?hÎ5qE?\V rita osfPrimaryPaste:?hÎ45d?)@imick-cut-set() osfQ?hÎ3I?;-MefQuickPaste: quick-cut-s?hÎ3BD?GNnbquShiftosfQuickPaste:?hÎ2y b?\V os@8k@'?}{<+@8kPShiftosfQuickPaste:@8k@'$O?SNosfQuickPaste: quick-cut-s@8k@'?}{<+N quick-cut-set() osfQ@8k@)e|n1?ྱNMeta osfPrimaryPaste:@8k@+'~S?ʵk NimaryPaste: cut-primary() @8k@+/a?SNrimary() Meta osfCut@8k@*DWR@#*ON Cut: cut-primary() @8k@)S?@$høN y>osfPaste: paste-clipbo@8k@'ʭr@yDN  y- n@@+?? jShiftosfQuickPaste:@@+?PosfQuickPaste: quick-cut-s@@+?+quick-cut-set() osfQ@@+@?%Meta osfPrimaryPaste:?@+?imaryPaste: cut-primary() @*@?rimary() Meta osfCut@)?Cut: cut-primary() @@)@?Py>acm-6.0_20200416/src/gedit/gdf-big-endian/f18.gdf0000644000000000000000000002767010357223037017307 0ustar rootrootRR11?`깥ӨUaQu`깥Ө@,ٙ?@,l @-@:@,ٙ?<@,s33333@>@,Y@>@,&ffffg@?@,@@?>@,??<@-@?:`깥ӣ?UaQv@,?@,s @-@?:@,?<@,@?>@,&ffffg?@,Y>@,s33333>@,ٙ<@-@:@   @@@@@?@@?@?@  ??@@ ?  ?௻Aѿkkx?Ң1&+ # 1&;"5@&Y"3/;NhM ?௻A?kkx?Ң5@@&+ 3@/;NhM5@@&Y1@&;#@@@  @A?@@@=@7 @2@-;@'Q@"e@"9@y9@y ?@@`? @A?@@`?@>?@8?@?8@?q8u ?:@@  9@{:@@=@%=@'=@(:@)1@@92@C0@ / 2  0 /2C1@9:)P=(N='J=%B:@ 9{ @A?  @A@A?@? ?@:@@6@@@?1`?:9 x 1`  9 x1`:@@6@:@? @A@A ?:@@  9@{:@@=@%=@'=@(:@)1@@92@C0@ /2  0 /2C1@9:)P=(N='J=%B:@ 9{ -)G)G)*⤒I$JX!F  0 mm0*⤒I$J ?mm@$I$J@!@mj@+@[mmB @0( @4`  @6 -&?G)G)@4`@ X!F  @6 @@4`@  @0@(@+@@[mmB@!@@mj@@$I$J?@mm*@⤒I$J0 ?mm0?xt_w yG?*?@?J4` @5@B?@*@ )@@5Lx@?xt_w ?yG?** ?J4b )@5Lx* ?5@?;? 9`z;?;@9`@z6`@b@@??@ ?@6`b9`z ;;9`z?;@  ;@?;@: @5@^,@"@@?@?@??@@/@@@,7`@?j/@@  L7`?j/@@,?@???,"5^: ;;?acm-6.0_20200416/src/gedit/gdf-big-endian/mig25.gdf0000644000000000000000000002610010357223037017617 0ustar rootrootRR11?@BP  ShiftosfQuickPaste:@D\(cosfQuickPaste: quick-cut-s@A\(8Qquick-cut-set() osfQ@<@Q^QMeta osfPrimaryPaste:@9vfffffO\(imaryPaste: cut-primary() @5(\Rrimary() Meta osfCut@4=p  Cut: cut-primary() @&p =RUy>osfPaste: paste-clipbo: =p^Qy-primary() Alt osfC;(\)u\(Copy: copy-clipboard() - =p@nzG&ning-of-line(extend) osfEndLi@

osfEndLine: end-of-line(@B=p ?(\)le?`O兿i$%9s!S? 0baryPaste: cut-primary() 7GzH B?W =pi rita osfPrimaryPaste:8(\ ??W =pt imick-cut-set() osfQ8~zGffffff@W =prMefQuickPaste: quick-cut-s.zGW =p@R) quShiftosfQuickPaste:)vfffffR? =p osڦ2?0~du* C!@@6 L`*ShiftosfQuickPaste:@=p @˅QGzHosfQuickPaste: quick-cut-s Q@60Q =p ;quick-cut-set() osfQ0@6nfffff =p 69Meta osfPrimaryPaste:-@G{n#imڦ20~du* C17 L^)ta osfPrimaryPaste:-G{n#imick-cut-set() osfQ06nfffff =p 6MefQuickPaste: quick-cut-s Q60Q =p quShiftosfQuickPaste:@=p ˅QGzHos:  e() Shift osfEndLi7 ? =p g>ong-of-line(extend) osfC8(\\(tCoosfPaste: paste-clipbo&O\(GzHy-t: cut-primary() ?(\) =py>mary() Meta osfCut@)zG˅QICuaryPaste: cut-primary() @*0 =pffffffGrita osfPrimaryPaste:@7 ^Qimick-cut-set() osfQ@=8 =pffffffMefQuickPaste: quick-cut-s@AR(\)quShiftosfQuickPaste:@D =pdoss%vS?D26e')@k+`ShiftosfQuickPaste:!Gz}p = 8Q osfQuickPaste: quick-cut-s(@nzG quick-cut-set() osfQ833333R' =pu(Meta osfPrimaryPaste:;Hp0%Q'imaryPaste: cut-primary() 9\(lSGzH~rimary() Meta osfCut7\(7& =p kCu?s%vj?D25?e':@d)k+^mary() Meta osfCut7\(@7& =p kCuaryPaste: cut-primary() 9\(@lSGzH~rita osfPrimaryPaste:;H@p0%Qimick-cut-set() osfQ833333@R' =puMefQuickPaste: quick-cut-s(@@nzG quShiftosfQuickPaste:!Gz@}p = 8QosۨKSԿ\O+> @-?mR\ShiftosfQuickPaste:20@ffffff?ffffff@osfQuickPaste: quick-cut-s=8 =p@,ۅQ?(\)yquick-cut-set() osfQ?g\(@)zG? =p Meta osfPrimaryPaste:;(\@˅Q?.vfimaryPaste: cut-primary() ; R@33333?h0Erimary() Meta osfCut9zG@R?c>|Cu?ەKS?\O,;?X?mNZmary() Meta osfCut9zGR?c>| CuaryPaste: cut-primary() ; R33333?h0Erita osfPrimaryPaste:;(\˅Q?.vfimick-cut-set() osfQ?g\()zG? =p RMefQuickPaste: quick-cut-s=8 =p,ۅQ?(\)_quShiftosfQuickPaste:20ffffff?ffffff@os?Ίb"~Z?TT@ @+6cXShiftosfQuickPaste:@!Gz@=p 0 =pwosfQuickPaste: quick-cut-sW =p@Gz !Gzquick-cut-set() osfQ-WzG@ (\)@$Meta osfPrimaryPaste:9\(@]Pu\(~imaryPaste: cut-primary() 9\(@F&B?8Q~rimary() Meta osfCut*G{@7Kw@nzGCut: cut-primary() @&p =@ VL@nzGUy> ?Ίb$?~Z?Te+\@@+6dVt: cut-primary() @&p = VL@nzGUy>mary() Meta osfCut*G{7Kw@nzGCuaryPaste: cut-primary() 9\(F&B?8Q~rita osfPrimaryPaste:9\(]Pu\(~imick-cut-set() osfQ-WzG (\)@$MefQuickPaste: quick-cut-sW =pGz !Gz quShiftosfQuickPaste:@!Gz=p 0 =pwos ?@55TShiftosfQuickPaste:@4G{? =p R osfQuickPaste: quick-cut-s@4G{ =p  quick-cut-set() osfQ@4G{W =p (\) Meta osfPrimaryPaste:@4G{}p =@ imaryPaste: cut-primary() @4G{ffffff?(\) rimary() Meta osfCut@4G{GzH@^Q Cut: cut-primary() @4G{@W =p y> ?@5?@5Rt: cut-primary() @4G{@W =p y>mary() Meta osfCut@4G{?GzH@^Q CuaryPaste: cut-primary() @4G{@ffffff?(\) rita osfPrimaryPaste:@4G{@}p =@ imick-cut-set() osfQ@4G{?W =p (\) MefQuickPaste: quick-cut-s@4G{? =p  quShiftosfQuickPaste:@4G{ =p R os ?@PShiftosfQuickPaste:@=p ,_osfQuickPaste: quick-cut-s@=p O\(i6quick-cut-set() osfQ@=p O\(?t @Meta osfPrimaryPaste:@=p ^Q@b0imaryPaste: cut-primary() @=p Gz@m:ӡ rimary() Meta osfCut@=p }p =@b0Cut: cut-primary() @=p ? =p ?~Ky> ?@@@ nt: cut-primary() @=p =p ?~Ky>mary() Meta osfCut@=p @}p =@b0CuaryPaste: cut-primary() @=p @Gz@m:ӡrita osfPrimaryPaste:@=p @^Q@b0imick-cut-set() osfQ@=p @O\(?t @MefQuickPaste: quick-cut-s@=p @O\(i6quShiftosfQuickPaste:@=p ,_os ?m8迨Oc ~?@5 @QÍ!_= lShiftosfQuickPaste:@4 =p =p GzH osfQuickPaste: quick-cut-s@4G{G{ 8Q quick-cut-set() osfQ@)vfffffGzH 8QJMeta osfPrimaryPaste:@O\(GzH~XimaryPaste: cut-primary() %W =p˅Qɿrimary() Meta osfCut3ÅQ=p 4MCut: cut-primary() 3p = =p #:YGKy>?m8?Oc ~?4`@m( Z@QÍ!_; jt: cut-primary() 3p =? =p #:YGKy>mary() Meta osfCut3ÅQ@=p 4MCuaryPaste: cut-primary() %W =p@˅Qɿrita osfPrimaryPaste:@O\(@GzH~Ximick-cut-set() osfQ@)vfffff@GzH 8QJMefQuickPaste: quick-cut-s@4G{@G{ 8Q quShiftosfQuickPaste:@4 =p? =p GzH os@B?  ShiftosfQuickPaste:@D =pdosfQuickPaste: quick-cut-s@AR?(\)quick-cut-set() osfQ@=8 =p@ffffffMeta osfPrimaryPaste:@7 @^QimaryPaste: cut-primary() @*0 =p@ffffffGrimary() Meta osfCut@)zG@˅QICut: cut-primary() ?(\)@ =py>osfPaste: paste-clipbo&O\(@GzHy-primary() Alt osfC8(\@\(tCopy: copy-clipboard() :0 =p@Rning-of-line(extend) osfEndLi7 =p g>o?o/?h@5Z@j "bǪ l(ShiftosfQuickPaste:@*@@ȈGosfQuickPaste: quick-cut-s@4@@ quick-cut-set() osfQ@4@DDDDD@ Meta osfPrimaryPaste:@)_`@Ȉ@wwwwxHim?o/?h@5Z "bǪ l'ta osfPrimaryPaste:@)_`Ȉ@wwwwxHimick-cut-set() osfQ@4DDDDD@ MefQuickPaste: quick-cut-s@4@ quShiftosfQuickPaste:@*@ȈGos?uÂ6O?t2ǁf1l@)@@!:&ShiftosfQuickPaste:@4@ osfQuickPaste: quick-cut-s@)@@Hquick-cut-set() osfQ$@@Meta osfPrimaryPaste:#@qZ&im?uÂ6Oſt2ǁf1p$@!:%ta osfPrimaryPaste:#qZ&imick-cut-set() osfQ$@MefQuickPaste: quick-cut-s@)@HquShiftosfQuickPaste:@4 os?`O?i$%/@@ 0r hShiftosfQuickPaste:)vfffff@R? =p osfQuickPaste: quick-cut-s.zG@W =p@R) quick-cut-set() osfQ8~zG@ffffff@W =prMeta osfPrimaryPaste:8(\@ ??W =ptimaryPaste: cut-primary() 7GzH@ B?W =pirikM?.Hп8Ɨ%@d?8H.Z\~#ShiftosfQuickPaste:)5xH@,?5w?< X}osfQuickPaste: quick-cut-s8Ɨ%@d?8Huquick-cut-set() osfQ8R,?5@ ~kt1hKuMeta osfPrimaryPaste:$t2a@ ӂ]58Himkf.Hп8R,?5 ~kt1hK.Z\~$ta osfPrimaryPaste:$t2a ӂ]58Himick-cut-set() osfQ8R,?5 ~kt1hKuMefQuickPaste: quick-cut-s8Ɨ%d?8Hu quShiftosfQuickPaste:)5xH,?5w?< X}osacm-6.0_20200416/src/gedit/gdf-big-endian/scaled-c172.gdf0000644000000000000000000002307410357223037020610 0ustar rootrootRR11?\3?4?B{\3@W}]GIkꪈX?JEP?mTI?=iYx\3@W}]GI?JEP@W}]GI?hK?|=X?mTIz4?B{?JEPW}]GIkꪈp?hK|=X?mTI?JEPW}]GI(\3W}]GI(?JEPmTI?=iY\N(2?Ea?Ҽ6Ww-ô?,i =`Qr陟Ŀ&T{6Ww-ôu/ֹ*r9 >{LlT$>{g14ܹ>{CAI[> >{LlT$FN>{)%u3FN>{|4Q ?5gR@u}u{ ?̶LlT$$T>gxsݑĿ,<z/ E*?̶LlT$$T>gxsݑ? =`QƿxsݑĿxsݑ? =`Q׿EE*?5gR@?u}u{ ? =`Q?xsݑĿxsݑĿ,#? =`Q?EE*s? =`Q?xsݑĿxsݑq?̶LlT$?$T>gxsݑp<?z/ E*r?FR?>{)%u4>{#@FN?>{|4Q qFN?>{)%u3q> ?>{LlT$qg14ܹ?>{CAI[qEa?Ҽ/ֹ*?OLfs/<-X?Gb O$d?r9osfQuickPaste:@2/! =@A>X]>@M]?p`osfQuickPaste: quick-cut-s@'3Mqڋ@Afz:#@M]?_quick-cut-set() osfQ@$7;o@A7N@M]?aMeta osfPrimaryPaste:?*@@#@M]?bimaryPaste: cut-primary() /@@u {@M]?erimary() Meta osfCut/@?Z{5+@M]?jCut: cut-primary() @2/! =@?Xg4€@M]?piy>#"@8k@'?}{<+@8k7ShiftosfQuickPaste:@1,@<-J@yI)qqosfQuickPaste: quick-cut-s@1,@=œU@ݢ#qoquick-cut-set() osfQ@1,@?[ v?‹ÚqhMeta osfPrimaryPaste:@1,@@xCqP@̫6qaimaryPaste: cut-primary() @1,@AGX@yI)q_rimary() Meta osfCut@1,@@Z@RqdCut: cut-primary() @1,@? ?@d4qhy>osfPaste: paste-clipbo@1,@=+r@f:iqqoy-"!?hÎ3 X$@`U3?hÎ7PosfPaste: paste-clipbo@ QGr@rGQhy-t: cut-primary() @ QH0A@ ;"Bny>mary() Meta osfCut@ QI< Uz@L?[sCuaryPaste: cut-primary() @ QJZ:ӳ@ K mkwrita osfPrimaryPaste:@ QJ c?SosfQ@ QH Mvh?c e'nMefQuickPaste: quick-cut-s@ QG?-?1kh@gquShiftosfQuickPaste:@ QGs@ K mkeos! @8k@'?}{<+@8k7ShiftosfQuickPaste:@ Q@Gs@ K mk7osfQuickPaste: quick-cut-s@ Q@G?-?1kh@5quick-cut-set() osfQ@ Q@H Mvh?c e'.Meta osfPrimaryPaste:@ Q@J c?SosfCut@ Q@I< Uz@L?[)Cut: cut-primary() @ Q@H0A@ ;"B.y>osfPaste: paste-clipbo@ Q@Gr@rGQ4y- (??7t: cut-primary() @2/! =@?Xg4€@M]?piy>mary() Meta osfCut/@?-O@M]?hCuaryPaste: cut-primary() /@>iMLN,@M]?mrita osfPrimaryPaste:?*@=x!-@M]?pimick-cut-set() osfQ@$7;o@=(B1hW@M]?qMefQuickPaste: quick-cut-s@'3Mqڋ@<=.@M]?squShiftosfQuickPaste:@2/! =@osfQuickPaste:F/Oȕ0;osfQuickPaste: quick-cut-sHtX!xGquick-cut-set() osfQJM^&/VMeta osfPrimaryPaste:P#@u {fimaryPaste: cut-primary() RE+<@u {frimary() Meta osfCutQz>/Cu@; 6ShiftosfQuickPaste:@R/! =cU:osfQuickPaste: quick-cut-s@Qz> Oȕ0quick-cut-set() osfQ@Pu {cU:Meta osfPrimaryPaste:@M(B1hW M]?imaryPaste: cut-primary() @G8\g!xrimary() Meta osfCutCnZ{5+)Cut: cut-primary() RϦ}U4_y>osfPaste: paste-clipboRμ *y-primary() Alt osfCFG@ <Copy: copy-clipboard() ;Oȕ0@5ning-of-line(extend) osfEndLi@NnS@x>osfEndLine: end-of-line(@Q*EM?cU:le2??60ShiftosfQuickPaste:@ *G8\g@ Oȕ0eosfQuickPaste: quick-cut-s Oȕ0G[n6@ Oȕ0dquick-cut-set() osfQϦ}G.@ Oȕ0fMeta osfPrimaryPaste:*nUzG5@ Oȕ0gimaryPaste: cut-primary() 1?PwHL7),I4@ Oȕ0jrimary() Meta osfCut1?PwI*@ Oȕ0oCut: cut-primary() @ *H켶c@ Oȕ0ny>3??6t: cut-primary() @ *H켶c@ Oȕ0ny>mary() Meta osfCut1?PwHěSB4@ Oȕ0mCuaryPaste: cut-primary() 1?PwIBD~@ Oȕ0rrita osfPrimaryPaste:*nUzJn(҇@ Oȕ0uimick-cut-set() osfQϦ}J-х2@ Oȕ0vMefQuickPaste: quick-cut-s Oȕ0J~ ?&@ Oȕ0xquShiftosfQuickPaste:@ *JU4_@ Oȕ0wos@5 ??6ShiftosfQuickPaste:@ *@JU4_@ Oȕ0%osfQuickPaste: quick-cut-s Oȕ0@J~ ?&@ Oȕ0$quick-cut-set() osfQϦ}@J-х2@ Oȕ0&Meta osfPrimaryPaste:*nUz@Jn(҇@ Oȕ0'imaryPaste: cut-primary() 1?Pw@IBD~@ Oȕ0*rimary() Meta osfCut1?Pw@HěSB4@ Oȕ0/Cut: cut-primary() @ *@H켶c@ Oȕ0.y>@4??6t: cut-primary() @ *@H켶c@ Oȕ0.y>mary() Meta osfCut1?Pw@I*@ Oȕ0-CuaryPaste: cut-primary() 1?Pw@HL7),I4@ Oȕ02rita osfPrimaryPaste:*nUz@G5@ Oȕ05imick-cut-set() osfQϦ}@G.@ Oȕ06MefQuickPaste: quick-cut-s Oȕ0@G[n6@ Oȕ08quShiftosfQuickPaste:@ *@G8\g@ Oȕ07os@&??6ShiftosfQuickPaste:@2/! =osfQ@$7;o=(B1hW@M]?+Meta osfPrimaryPaste:?*=x!-@M]?,imaryPaste: cut-primary() />iMLN,@M]?/rimary() Meta osfCut/?-O@M]?4Cut: cut-primary() @2/! =?Xg4€@M]?p3y>)??6`t: cut-primary() @2/! =?Xg4€@M]?p3y>mary() Meta osfCut/?Z{5+@M]?2CuaryPaste: cut-primary() /@u {@M]?7rita osfPrimaryPaste:?*@#@M]?:imick-cut-set() osfQ@$7;oA7N@M]?;MefQuickPaste: quick-cut-s@'3MqڋAfz:#@M]?=quShiftosfQuickPaste:@2/! =A>X]>@M]?p<osTq~m) l?޻ i$< I 6ShiftosfQuickPaste:@78\g*@ Oȕ0_osfQuickPaste: quick-cut-s9*Q*EM quick-cut-set() osfQosfPrimaryPaste:A?PwRWBifBimaryPaste: cut-primary() .osfCut(tX'3Mqڋ?d3Cut: cut-primary() '5*?[Y |Oy>?Tq~P) l̿޻ i@?QQ?I 6@t: cut-primary() '5@*?[Y |Oy>mary() Meta osfCut(tX@'3Mqڋ?d3CuaryPaste: cut-primary() .@osfPrimaryPaste:A?Pw@RWBifBimick-cut-set() osfQosfQuickPaste:@78\g@*@ Oȕ0_osS:sI?S:sI?WJ@<?&6ShiftosfQuickPaste:@RT[cU:cU:osfQuickPaste: quick-cut-s@Q?Pwx꓿cU:quick-cut-set() osfQ@K%A0U4_ܿ*Meta osfPrimaryPaste:=x!-5 khimaryPaste: cut-primary() FckcU: 18rimary() Meta osfCutSZ6;pnUCuS:s-S:s?WJ1@/?46mary() Meta osfCutSZ6;pnUCuaryPaste: cut-primary() Fck@cU: 18rita osfPrimaryPaste:=x!-@5 khimick-cut-set() osfQ@K%A0@U4_ܿ*MefQuickPaste: quick-cut-s@Q?Pw@x꓿cU:quShiftosfQuickPaste:@RT[?cU:cU:os?ȼm[t?e(V@@" ?:}T6ta osfPrimaryPaste:Q?Pw "6timick-cut-set() osfQTcU:@6/Z{5+MefQuickPaste: quick-cut-sR>@6/Z{5+quShiftosfQuickPaste:Knk΅?  Zos?osfQuickPaste:@R$vJHosfQuickPaste: quick-cut-s@7Ė@d; @ H^quick-cut-set() osfQ' h@ h?HMeta osfPrimaryPaste:@j R?SoR'4im?osfPrimaryPaste:@j RSoR'4imick-cut-set() osfQ' h h?HMefQuickPaste: quick-cut-s@7Ėd; @ H^quShiftosfQuickPaste:@R$vJHos ?@4 46HShiftosfQuickPaste:@G[n6"Ϧ}osfQuickPaste: quick-cut-s@G[n6Ϧ} M]?quick-cut-set() osfQ@G[n655Meta osfPrimaryPaste:@G[n6jʃ imaryPaste: cut-primary() @G[n6U4_?*rimary() Meta osfCut@G[n6M]?@/Cut: cut-primary() @G[n6 @U4_y>osfPaste: paste-clipbo@G[n6cU:@U4_y- ?@2?@26osfPaste: paste-clipbo@G[n6?cU:@U4_y-t: cut-primary() @G[n6? @U4_y>mary() Meta osfCut@G[n6@M]?@/CuaryPaste: cut-primary() @G[n6@U4_?*rita osfPrimaryPaste:@G[n6@jʃ imick-cut-set() osfQ@G[n6@55MefQuickPaste: quick-cut-s@G[n6@Ϧ} M]?quShiftosfQuickPaste:@G[n6"Ϧ}os @8k)S?@$hø@8k6osfPaste: paste-clipbo@1,=+r@f:iqq-y-t: cut-primary() @1,? ?@d4q4y>mary() Meta osfCut@1,@Z@Rq8CuaryPaste: cut-primary() @1,AGX@yI)q=rita osfPrimaryPaste:@1,@xCqP@̫6q;imick-cut-set() osfQ@1,?[ v?‹Úq4MefQuickPaste: quick-cut-s@1,=œU@ݢ#q-quShiftosfQuickPaste:@1,<-J@yI)q+os eO@)2R,>E@)2R,>6(t: cut-primary() @]A@HO@ EDB.y>mary() Meta osfCut1~@HO@ EDB.CuaryPaste: cut-primary() 1~@HO@^g71.rita osfPrimaryPaste:+j/X.@HO@Y I.imick-cut-set() osfQ%4[@HO@j;e.MefQuickPaste: quick-cut-s Sn9@HO@pY.quShiftosfQuickPaste:@bа@HO@K az.os @,?5w@)2R,>?< X}@)2R,>6ߘShiftosfQuickPaste:@JC@HO?*.9.osfQuickPaste: quick-cut-s]<ܖ@HO?X=.quick-cut-set() osfQkr@HO?3P.Meta osfPrimaryPaste:+X#+@HO?9v.imaryPaste: cut-primary() 15@HO@:Bꅲ.rimary() Meta osfCut15@HO@ ̹w@.Cut: cut-primary() @;@HO@ ̹w@.y>?$gz3?he@36t: cut-primary() @;HO@ ̹w@ny>mary() Meta osfCut15HO@ ̹w@nCuaryPaste: cut-primary() 15HO@:Bꅲnrita osfPrimaryPaste:+X#+HO?9vnimick-cut-set() osfQkrHO?3PnMefQuickPaste: quick-cut-s]<ܖHO?X=nquShiftosfQuickPaste:@JCHO?*.9nos?73@\…@36xShiftosfQuickPaste:@bаHO@K aznosfQuickPaste: quick-cut-s Sn9HO@pYnquick-cut-set() osfQ%4[HO@j;enMeta osfPrimaryPaste:+j/X.HO@Y InimaryPaste: cut-primary() 1~HO@^g71nrimary() Meta osfCut1~HO@ EDBnCut: cut-primary() @]AHO@ EDBny>?@FLJ)2R,>@`@)2R,>6ShiftosfQuickPaste:@16$?V@Ibq3osfQuickPaste: quick-cut-s@&b=?V@QK=3quick-cut-set() osfQ@#q?V@K,Q3Meta osfPrimaryPaste:?4M?V@`JS53imaryPaste: cut-primary() ؗ?V@>w2Y3rimary() Meta osfCutؗ?V@)73Cut: cut-primary() @2DB ?V@)7p3y>?eO)2R,>?E@)2R,>6Xt: cut-primary() @2$vH?V@r9xmmp3y>mary() Meta osfCut~13?V@r9xmm3CuaryPaste: cut-primary() ~13?V@Qnm3rita osfPrimaryPaste:?ūvs#?V?r9xmm3imick-cut-set() osfQ@#Dd?V?ūvs#3MefQuickPaste: quick-cut-s@&?V?Z_3quShiftosfQuickPaste:@1k _?V?uq3os@,?5w@)2R,>?< X}@)2R,>6ShiftosfQuickPaste:@1k _@?V?uqiosfQuickPaste: quick-cut-s@&@?V?Z_iquick-cut-set() osfQ@#Dd@?V?ūvs#iMeta osfPrimaryPaste:?ūvs#@?V?r9xmmiimaryPaste: cut-primary() ~13@?V@Qnmirimary() Meta osfCut~13@?V@r9xmmiCut: cut-primary() @2$vH@?V@r9xmmpiy>f:s@)2R,>?X+./M@)2R,>7t: cut-primary() @2DB @?V@)7piy>mary() Meta osfCutؗ@?V@)7iCuaryPaste: cut-primary() ؗ@?V@>w2Yirita osfPrimaryPaste:?4M@?V@`JS5iimick-cut-set() osfQ@#q@?V@K,QiMefQuickPaste: quick-cut-s@&b=@?V@QK=iquShiftosfQuickPaste:@16$@?V@Ibqiosȼm[s?e(V<" ?:}S7ShiftosfQuickPaste:Knk΅  ZosfQuickPaste: quick-cut-sR>6/Z{5+quick-cut-set() osfQTcU:6/Z{5+Meta osfPrimaryPaste:Q?Pw "6tim?# @#6(67ShiftosfQuickPaste:8$ς?.~"=w!osfQuickPaste: quick-cut-s8$ςخo4 'Bquick-cut-set() osfQ8$ςڴ}qǽMeta osfPrimaryPaste:8$ςFMRѿ5imaryPaste: cut-primary() 8$ς^)?&\Mrimary() Meta osfCut8$ς0r{@RCut: cut-primary() 8$ς=)! @l:\My>osfPaste: paste-clipbo8$ς/e@l:\My-?@4?@4Gr`7@osfPaste: paste-clipbo8$ς?V:@'=J,y-t: cut-primary() 8$ς??3P@'=J,y>mary() Meta osfCut8$ς@.v@d/CuaryPaste: cut-primary() 8$ς@>v?Z.q^rita osfPrimaryPaste:8$ς@! mӺ-imick-cut-set() osfQ8$ς@}q~(4MefQuickPaste: quick-cut-s8$ς@Q>†̥aquShiftosfQuickPaste:8$ςʪk"f}9losacm-6.0_20200416/src/gedit/gdf-big-endian/scaled-mig29.gdf0000644000000000000000000004103410357223037021057 0ustar rootrootRR11?4 S(z,fm4 4MuhN84 S(z,fm4UUUUUUhN84)W/,fk4\iwshN84A\r<|>=hr|4\iww?hN84)W1?,fn4UUUUUU?hN84 S(z?,fm4Mu?hN84D֨~8@Mu?hN8 4@D֨~8p4@Mu?hN8r4@ S(z?,fmv4@UUUUUU?hN8|4@)W1?,fn4?\iww?hN84?A\r<|>=hr|4?\iwshN84@)W/,fk4@UUUUUUhN8|4@ S(z,fmv4@MuhN8r?%r]N7?@"@:@A [7 m]?sM@A [76E?sQ@%ٳ|sQ+jf6@%ٳ| 䎊qj+jf6?%r?@*@:@%ٳ|@ 䎊qj+jf6w@%ٳ|?sQ+jf6@A [7?6E?sQ@A [7@ m]?sMv?4?@4 נ1UO;dZ sQ?#(1UO;dZTFs?#(1UO;dZ#䎊qj(1UO;dZ}!.H(1UO;dZ䎊qj+(1UO;dZ_!-w1}!.H(1UO;dZ:kP|A [7(1UO;dZ_!-w1#(1UO;dZ#+(1UO;dZ\(ÿ䎊qj(1UO;dZ:kP|䎊qj(4@4 01UO;dZ@:kP|䎊qj(n1UO;dZ@\(ÿ䎊qj(e1UO;dZ@#+(_1UO;dZ@_!-w1#(]1UO;dZ@:kP|A [7(n1UO;dZ@_!-w1}!.H(z1UO;dZ?䎊qj+(1UO;dZ}!.H(1UO;dZ?#䎊qj(1UO;dZ@TFs?#(1UO;dZ@ sQ?#(u?Ս]a?:?ma $@a +jf@EF L0+b!:kP|@# jOw|_2@ilD%n!R<Qi4a4J@1&Pk# Qr4YJ@A?D+T4FOv_خ@. T3!-w@nĻT jOwZ3A@%u}#[3A@nF"#^'#@r蔿䎊qj^a?5@ Ј0$䎊qj䎊qj.2o:kP|䎊qj!3ڽ<64حV䎊qj4|tkEF L0䎊qj ,]V#䎊qjF@cF]cj~#䎊qj@A [7\(ÿ䎊qj@3ڽ<646E䎊qj@6*a|Q6E䎊qj@9lߤ@ٳ|䎊qj@=Վ!R䎊qj䎊qj`=291ԚkK09jh2Ϫ͞n!R< eπ5A6E96E(JM䎊qj 6|hs*xPH#*xPHn!R<䎊qjOՍ]a?:ma#6u3 !@a 0'#r蔿䎊qj^3AnF"#3A%u}#3!-wnĻT jOw4FOv_خ. 4YJA?D+4a4J1&Pk# r2ilD%n!R<i!:kP|# jOw|+jfEF L0+ r[˓?CE|yGC3 h?@ EL P4͞j~#?#0cF]cB-?ٳ|1L@N?A [7?A [7ތFk,?iDg8@ڹJU&?iDg8@A [7 ?A [7@%ٳ|7U䎊qj6@iDg8uA [7@ jOwrnyiDg8 ?+ 23 Yz+"}!.H 6E䎊qjv4͞ 6E}!.H4͞_!-w1䎊qj ?VlTD?XzkP 88?qnpN/D+}!.H?p#94͞A [7䎊qj4?cF]c䎊qj1p4m9ڹ' ?VlTDXzkP 88@?qnpN1p4m9@ڹ'm4?@cF]c䎊qjp4͞?A [7䎊qj/D+?}!.H?p#9 ?r[˓?CE|?yGC9@ f| p4͞@_!-w1䎊qjz4͞@ 6E}!.Hy"}!.H@ 6E䎊qjvy?+@ 23 Yz+y@ jOw@rnyiDg8 z@iDg8@uA [7{@%ٳ|@7U䎊qj6{@A [7@ ?A [7}@ڹ@JU&?iDg8}?A [7@ތFk,?iDg8}@L@N?A [7}0cF]c@B-?ٳ|1|4͞@j~#?#| `=291?ԚkK1:@@/j *xPH@n!R<䎊qjOd6|hs@*xPH#96E@(JM䎊qj"5A@6E[2Ϫ͞@n!R< eπd @>@? @=Վ!R?䎊qj䎊qj@9lߤ@?ٳ|䎊qj@6*a|Q?6E䎊qj@3ڽ<64?6E䎊qj@A [7@\(ÿ䎊qje@cF]c@j~#䎊qj`,]V@#䎊qjF_4|tk@EF L0䎊qj b3ڽ<64@حV䎊qjh2o@:kP|䎊qj!n0$?䎊qj䎊qj.@? @=Վ!R䎊qj@:m\_!-w1@7# ilD@3TFs:kP|@0rGEMjm@.A [7ʳg _@)lߤ@MjH?#A [73o+ IA [72䎊qj@)|+jfF@3TFs+@5ٳ|䎊qj@:C33334䎊qj@=OXfA [7?MEܿ&fi?y~*@@@ XQ8' @ 6E@D+a&|hs@ٳ|iDg8ec)6E@3}Vl+U(_!-w1@3Kb0*Z#@3حVSUo#TFs@3o+ Iڅ@rD+@3TFsܿ{P.MEz&f y~'7 LAw XQ7D+3TFsܿ{P.P#TFs3o+ Iڅ@rQ#3حVSUoT(_!-w13Kb0*ZR)6E3}Vl+UN&|hsٳ|iDg8e@ 6ED+@?@ #حV+jf?A [7p#حVA [7?ٳ|p#حVcF]c䎊qjp#حV!.I+jfp#حVD}!.Hp#حV3حV+pT#حVMj+p#حViDg8ٳ|p#حV\(#p#حV?䎊qj jOwp#حV䎊qjp#حVA [7䎊qjp#حV䎊qj?+p?'?@' #حV?䎊qj?+p#حV?A [7䎊qjp#حV䎊qjp#حV䎊qj jOwp#حV@\(#p~#حV@iDg8ٳ|pq#حV@Mj+p^#حV@3حV+p#حV@D}!.Hpa#حV@!.I+jfpf#حV@cF]c䎊qjpp#حV@A [7?ٳ|ps#حV@+jf?A [7p?@3 3 @/D+ʳg c@/D+A [7j~#c@/D+#TFsc@/D+6EiDg8c@/D+sQ+c@/D+ٳ|+c@/D+++c@/D+?䎊qj+jfc?@3 ??3 x@/D+䎊qj+jfc@/D+?++c@/D+?ٳ|+c@/D+?sQ+c@/D+?6EiDg8c@/D+?#TFsc@/D+?A [7j~#c@/D+ʳg c@?@ `@+\(?iDg8@+A [7?6E@+iDg8䎊qj@+!.I+@+j~#A [7@+#A [7@+A [7+jf@+_!-w1@+@+}!.H@+A [7?+@+ڹ?sQ?@@?spe>@ @+@ڹ?sQ@+?A [7?+@+?}!.H@+@+_!-w1@+@A [7+jfs@+@#A [7_@+@j~#A [7`@+@!.I+f@+@iDg8䎊qjq@+@A [7?6Es@+@\(?iDg8~acm-6.0_20200416/src/gedit/gdf-big-endian/mig29.gdf0000644000000000000000000003334010357223037017627 0ustar rootrootRR11??%r]N7?@"@:#@"@b@"@b@*B@*B?%r?@*@:#@*@B@*@B@"?@b@"@@b?4?@4 #X4?O4?O4O4O4O4 O4O4O4O4O4O 4@4 #4@O4@O4@O4@O4@O4@ O4?O4O4?O4@?O4@?O ?Ս]a?:?ma $@a $@$@6 @!)[i8@@!^-Ё'@lr7@ Vy"i8 @ /7"@k7`@C9FOe6@^ _6@u3 !_,@ ?5@ $,83I5V7g8`m01@@"b@7@:`@>@@A`=291ԚkK09j$+6`]9y >-@C:@/|L/(Ս]a?:ma#6u3 !@a $(, 6u3 !_6^ _ 7`C9FOe 8 /7"@k7 Vy"i8@!^-Ё'@lr6 !)[i$r[˓?CE|yGC3 h?@ EL $&8 ?q3 h?F"@ M}전@@  9\@@ $@@" rd@b@* Uj%\B@# i^@ Ӹ l? (!5&8q8 q ?VlTD?XzkP 88?qnpN$%2?CY(>8q8p4P ?VlTDXzkP 88@?qnpN$$04@P8@p8@q2??CY(> ?r[˓?CE|?yGC9@ f| $!P8@ q8@q&@?@ (!5@@ Ӹ l@#@ i^@*@ Uj%\B@"@ rd@b@@ $@@@  9\@"@@ M}전@3@ h?F8@ ?q `=291?ԚkK1:@@/j$/@(:@@/|P>@-@Y9@y6`@] @>@? $@A?@>@?@:`?@7?@"@b@@0@18`@m7@g5@V3?I@? $8@A@? @<@7@3 @2@.@1?7 c6 [@-3@7@:@?@@Ap?MEܿ&fi?y~*@@@ XQ8'$@@*@@.@6"-@7@oh'@7V '@7 LAw"@7{MEz&f y~'7 LAw XQ7$"7{'7 LAw'7V -7@oh.6"*@@@?@ $8'@'?''''7'' ' '?'''??'?@' $X'@?'?'''@ '@ '@'@7'@'@'@'@?'@@?@3 3 $ @2@2@2@2@2@2@2@2??@3 ??3 #&#.$ @2@2?@2?@2@@2?@2?@2?@2@?@#&#. $ @ @@?@@@@@@ @@@?@@?@@?H $x@@@@@?@?@@ @@@@@@@@@@@@?@@ @acm-6.0_20200416/src/gedit/gdf-big-endian/scaled-ewacs.gdf0000644000000000000000000004412010357223037021231 0ustar rootrootRR11&?Pܛ?@4?@4tosfPaste: paste-clipbo8$ς?V:@'=J,y-t: cut-primary() 8$ς??3P@'=J,y>mary() Meta osfCut8$ς@.v@d/CuaryPaste: cut-primary() 8$ς@>v?Z.q^rita osfPrimaryPaste:8$ς@! mӺ-imick-cut-set() osfQ8$ς@}q~(4MefQuickPaste: quick-cut-s8$ς@Q>†̥aquShiftosfQuickPaste:8$ςʪk"f}9los?# @#vShiftosfQuickPaste:8$ς?.~"=w!osfQuickPaste: quick-cut-s8$ςخo4 'Bquick-cut-set() osfQ8$ςڴ}qǽMeta osfPrimaryPaste:8$ςFMRѿ5imaryPaste: cut-primary() 8$ς^)?&\Mrimary() Meta osfCut8$ς0r{@RCut: cut-primary() 8$ς=)! @l:\My>osfPaste: paste-clipbo8$ς/e@l:\My-%ȼm[s?e(V<" ?:}S$ShiftosfQuickPaste:Knk΅  _osfQuickPaste: quick-cut-sR>6/Z{5+4quick-cut-set() osfQTcU:6/Z{5+4Meta osfPrimaryPaste:Q?Pw "6tim%$f:s@)2R,>?X+./M@)2R,>t: cut-primary() @2DB @?V@)7uy>mary() Meta osfCutؗ@?V@)7CuaryPaste: cut-primary() ؗ@?V@>w2Yrita osfPrimaryPaste:?4M@?V@`JS5imick-cut-set() osfQ@#q@?V@K,QMefQuickPaste: quick-cut-s@&b=@?V@QK=quShiftosfQuickPaste:@16$@?V@Ibvos$ @,?5w@)2R,>?< X}@)2R,>ShiftosfQuickPaste:@1k _@?V?uvosfQuickPaste: quick-cut-s@&@?V?Z_quick-cut-set() osfQ@#Dd@?V?ūvs#Meta osfPrimaryPaste:?ūvs#@?V?r9xmmimaryPaste: cut-primary() ~13@?V@Qnmrimary() Meta osfCut~13@?V@r9xmmCut: cut-primary() @2$vH@?V@r9xmmuy> !?eO)2R,>?E@)2R,>~t: cut-primary() @2$vH?V@r9xmmuQy>mary() Meta osfCut~13?V@r9xmmQCuaryPaste: cut-primary() ~13?V@QnmQrita osfPrimaryPaste:?ūvs#?V?r9xmmQimick-cut-set() osfQ@#Dd?V?ūvs#QMefQuickPaste: quick-cut-s@&?V?Z_QquShiftosfQuickPaste:@1k _?V?uvQos!#?@FLJ)2R,>@`@)2R,>ShiftosfQuickPaste:@16$?V@IbvQosfQuickPaste: quick-cut-s@&b=?V@QK=Qquick-cut-set() osfQ@#q?V@K,QQMeta osfPrimaryPaste:?4M?V@`JS5QimaryPaste: cut-primary() ؗ?V@>w2YQrimary() Meta osfCutؗ?V@)7QCut: cut-primary() @2DB ?V@)7uQy>#"?73@\…@3ShiftosfQuickPaste:@bаHO@K azosfQuickPaste: quick-cut-s Sn9HO@pYquick-cut-set() osfQ%4[HO@j;eMeta osfPrimaryPaste:+j/X.HO@Y IimaryPaste: cut-primary() 1~HO@^g71rimary() Meta osfCut1~HO@ EDBCut: cut-primary() @]AHO@ EDBy>"?$gz3?he@3t: cut-primary() @;HO@ ̹w@y>mary() Meta osfCut15HO@ ̹w@CuaryPaste: cut-primary() 15HO@:Bꅲrita osfPrimaryPaste:+X#+HO?9vimick-cut-set() osfQkrHO?3PMefQuickPaste: quick-cut-s]<ܖHO?X=quShiftosfQuickPaste:@JCHO?*.9os@,?5w@)2R,>?< X}@)2R,> hShiftosfQuickPaste:@JC@HO?*.9LosfQuickPaste: quick-cut-s]<ܖ@HO?X=Lquick-cut-set() osfQkr@HO?3PLMeta osfPrimaryPaste:+X#+@HO?9vLimaryPaste: cut-primary() 15@HO@:BꅲLrimary() Meta osfCut15@HO@ ̹w@LCut: cut-primary() @;@HO@ ̹w@Ly>eO@)2R,>E@)2R,>|t: cut-primary() @]A@HO@ EDBLy>mary() Meta osfCut1~@HO@ EDBLCuaryPaste: cut-primary() 1~@HO@^g71Lrita osfPrimaryPaste:+j/X.@HO@Y ILimick-cut-set() osfQ%4[@HO@j;eLMefQuickPaste: quick-cut-s Sn9@HO@pYLquShiftosfQuickPaste:@bа@HO@K azLos@8k)S?@$hø@8k losfPaste: paste-clipbo@1,=+r@f:iqvKy-t: cut-primary() @1,? ?@d4vRy>mary() Meta osfCut@1,@Z@RvVCuaryPaste: cut-primary() @1,AGX@yI)v[rita osfPrimaryPaste:@1,@xCqP@̫6vYimick-cut-set() osfQ@1,?[ v?‹ÚvRMefQuickPaste: quick-cut-s@1,=œU@ݢ#vKquShiftosfQuickPaste:@1,<-J@yI)vIos?@2?@2zosfPaste: paste-clipbo@G[n6?cU:@U4_y-t: cut-primary() @G[n6? @U4_y>mary() Meta osfCut@G[n6@M]?@/CuaryPaste: cut-primary() @G[n6@U4_?*rita osfPrimaryPaste:@G[n6@jʃ imick-cut-set() osfQ@G[n6@55MefQuickPaste: quick-cut-s@G[n6@Ϧ} M]?quShiftosfQuickPaste:@G[n6"Ϧ}os?@4 4xShiftosfQuickPaste:@G[n6"Ϧ}osfQuickPaste: quick-cut-s@G[n6Ϧ} M]?quick-cut-set() osfQ@G[n655Meta osfPrimaryPaste:@G[n6jʃ imaryPaste: cut-primary() @G[n6U4_?*rimary() Meta osfCut@G[n6M]?@/Cut: cut-primary() @G[n6 @U4_y>osfPaste: paste-clipbo@G[n6cU:@U4_y-rpn?osfPrimaryPaste:@j RSoR'4imick-cut-set() osfQ' h h?HMefQuickPaste: quick-cut-s@7Ėd; @ HcquShiftosfQuickPaste:@R$vJHos?osfQuickPaste:@R$vJHosfQuickPaste: quick-cut-s@7Ė@d; @ Hcquick-cut-set() osfQ' h@ h?HMeta osfPrimaryPaste:@j R?SoR'4im?ȼm[t?e(V@@" ?:}T#ta osfPrimaryPaste:Q?Pw "6timick-cut-set() osfQTcU:@6/Z{5+MefQuickPaste: quick-cut-sR>@6/Z{5+quShiftosfQuickPaste:Knk΅?  _osS:s-S:s?WJ1@/?4lmary() Meta osfCutSZ6;pnUCuaryPaste: cut-primary() Fck@cU: 1=rita osfPrimaryPaste:=x!-@5 kh imick-cut-set() osfQ@K%A0@U4_ܿ*MefQuickPaste: quick-cut-s@Q?Pw@x꓿cU:quShiftosfQuickPaste:@RT[?cU:cU:osS:sI?S:sI?WJ@<?&jShiftosfQuickPaste:@RT[cU:cU:osfQuickPaste: quick-cut-s@Q?Pwx꓿cU:quick-cut-set() osfQ@K%A0U4_ܿ*Meta osfPrimaryPaste:=x!-5 kh imaryPaste: cut-primary() FckcU: 1=rimary() Meta osfCutSZ6;pnUCu?Tq~P) l̿޻ i@?QQ?I ht: cut-primary() '5@*?[Y |Oy>mary() Meta osfCut(tX@'3Mqڋ?d3CuaryPaste: cut-primary() .@osfPrimaryPaste:A?Pw@RWBifB!imick-cut-set() osfQosfQuickPaste:@78\g@*@ Oȕ0dosTq~m) l?޻ i$< I fShiftosfQuickPaste:@78\g*@ Oȕ0dosfQuickPaste: quick-cut-s9*Q*EM quick-cut-set() osfQosfPrimaryPaste:A?PwRWBifB!imaryPaste: cut-primary() .osfCut(tX'3Mqڋ?d3Cut: cut-primary() '5*?[Y |Oy>)??dt: cut-primary() @2/! =?Xg4€@M]?uQy>mary() Meta osfCut/?Z{5+@M]?PCuaryPaste: cut-primary() /@u {@M]?Urita osfPrimaryPaste:?*@#@M]?Ximick-cut-set() osfQ@$7;oA7N@M]?YMefQuickPaste: quick-cut-s@'3MqڋAfz:#@M]?[quShiftosfQuickPaste:@2/! =A>X]>@M]?uZos @&??bShiftosfQuickPaste:@2/! =osfQ@$7;o=(B1hW@M]?IMeta osfPrimaryPaste:?*=x!-@M]?JimaryPaste: cut-primary() />iMLN,@M]?Mrimary() Meta osfCut/?-O@M]?RCut: cut-primary() @2/! =?Xg4€@M]?uQy> @4??`t: cut-primary() @ *@H켶c@ Oȕ0Ly>mary() Meta osfCut1?Pw@I*@ Oȕ0KCuaryPaste: cut-primary() 1?Pw@HL7),I4@ Oȕ0Prita osfPrimaryPaste:*nUz@G5@ Oȕ0Simick-cut-set() osfQϦ}@G.@ Oȕ0TMefQuickPaste: quick-cut-s Oȕ0@G[n6@ Oȕ0VquShiftosfQuickPaste:@ *@G8\g@ Oȕ0Uos @5 ??^ShiftosfQuickPaste:@ *@JU4_@ Oȕ0CosfQuickPaste: quick-cut-s Oȕ0@J~ ?&@ Oȕ0Bquick-cut-set() osfQϦ}@J-х2@ Oȕ0DMeta osfPrimaryPaste:*nUz@Jn(҇@ Oȕ0EimaryPaste: cut-primary() 1?Pw@IBD~@ Oȕ0Hrimary() Meta osfCut1?Pw@HěSB4@ Oȕ0MCut: cut-primary() @ *@H켶c@ Oȕ0Ly> 3??\t: cut-primary() @ *H켶c@ Oȕ0y>mary() Meta osfCut1?PwHěSB4@ Oȕ0CuaryPaste: cut-primary() 1?PwIBD~@ Oȕ0rita osfPrimaryPaste:*nUzJn(҇@ Oȕ0imick-cut-set() osfQϦ}J-х2@ Oȕ0MefQuickPaste: quick-cut-s Oȕ0J~ ?&@ Oȕ0quShiftosfQuickPaste:@ *JU4_@ Oȕ0os 2??ZShiftosfQuickPaste:@ *G8\g@ Oȕ0osfQuickPaste: quick-cut-s Oȕ0G[n6@ Oȕ0quick-cut-set() osfQϦ}G.@ Oȕ0Meta osfPrimaryPaste:*nUzG5@ Oȕ0imaryPaste: cut-primary() 1?PwHL7),I4@ Oȕ0rimary() Meta osfCut1?PwI*@ Oȕ0Cut: cut-primary() @ *H켶c@ Oȕ0y> @;  ShiftosfQuickPaste:@R/! =cU:osfQuickPaste: quick-cut-s@Qz> Oȕ0quick-cut-set() osfQ@Pu {cU:Meta osfPrimaryPaste:@M(B1hW M]?imaryPaste: cut-primary() @G8\g!xrimary() Meta osfCutCnZ{5+.Cut: cut-primary() RϦ}U4_y>osfPaste: paste-clipboRμ *y-primary() Alt osfCFG@ ACopy: copy-clipboard() ;Oȕ0@5ning-of-line(extend) osfEndLi@NnS@x>osfEndLine: end-of-line(@Q*EM?cU:le?3 XShiftosfQuickPaste:F/Oȕ0@osfQuickPaste: quick-cut-sHtX!xLquick-cut-set() osfQJM^&/[Meta osfPrimaryPaste:P#@u {imaryPaste: cut-primary() RE+<@u {rimary() Meta osfCutQz>/Cu(??Vt: cut-primary() @2/! =@?Xg4€@M]?uy>mary() Meta osfCut/@?-O@M]?CuaryPaste: cut-primary() /@>iMLN,@M]?rita osfPrimaryPaste:?*@=x!-@M]?imick-cut-set() osfQ@$7;o@=(B1hW@M]?MefQuickPaste: quick-cut-s@'3Mqڋ@<=.@M]?quShiftosfQuickPaste:@2/! =@osfQuickPaste:@ Q@Gs@ K mkUosfQuickPaste: quick-cut-s@ Q@G?-?1kh@Squick-cut-set() osfQ@ Q@H Mvh?c e'LMeta osfPrimaryPaste:@ Q@J c?SosfCut@ Q@I< Uz@L?[GCut: cut-primary() @ Q@H0A@ ;"BLy>osfPaste: paste-clipbo@ Q@Gr@rGQRy-?hÎ3 X$@`U3?hÎRosfPaste: paste-clipbo@ QGr@rGQy-t: cut-primary() @ QH0A@ ;"By>mary() Meta osfCut@ QI< Uz@L?[CuaryPaste: cut-primary() @ QJZ:ӳ@ K mkrita osfPrimaryPaste:@ QJ c?SosfQ@ QH Mvh?c e'MefQuickPaste: quick-cut-s@ QG?-?1kh@quShiftosfQuickPaste:@ QGs@ K mkos@8k@'?}{<+@8kPShiftosfQuickPaste:@1,@<-J@yI)vosfQuickPaste: quick-cut-s@1,@=œU@ݢ#vquick-cut-set() osfQ@1,@?[ v?‹ÚvMeta osfPrimaryPaste:@1,@@xCqP@̫6vimaryPaste: cut-primary() @1,@AGX@yI)v}rimary() Meta osfCut@1,@@Z@RvCut: cut-primary() @1,@? ?@d4vy>osfPaste: paste-clipbo@1,@=+r@f:iqvy- n@@+?? jShiftosfQuickPaste:@2/! =@A>X]>@M]?u~osfQuickPaste: quick-cut-s@'3Mqڋ@Afz:#@M]?}quick-cut-set() osfQ@$7;o@A7N@M]?Meta osfPrimaryPaste:?*@@#@M]?imaryPaste: cut-primary() /@@u {@M]?rimary() Meta osfCut/@?Z{5+@M]?Cut: cut-primary() @2/! =@?Xg4€@M]?uy>acm-6.0_20200416/src/gedit/gdf-big-endian/f181.gdf0000644000000000000000000003227010357223037017360 0ustar rootrootRR11?< X?t( ظ?Ohrbp9"r88?< X?H "[Xf-'J-"r88?< XH3K?< X< X3KXg-?t( ظϿOhrbp93K< X< X?H 3K@Xg3K< X< X"r88忮< XH"[@Xf-'J?5o5WYςףF?@UA0^З'?uv݋D 0^З'JEQ0 0^З'@6p?< X?< X@@6p% {E8;@ ?5o5WT?ςףE?@UA@6p< X?< X?uv݋D @6p?% {E8;@@6p< X?< X@0^З'0^З'?JEQ0 ?@ ?@26`"69`S.;y;y9`S`깥ӨUaQu`깥Ө@,ٙ?@,l @-@@,ٙ?@,s33333@@,Y@@,&ffffg@@,@@?@,??@-@?`깥ӣ?UaQv@,?@,s @-@?@,?@,@?@,&ffffg@,Y@,s33333 @,ٙ@-@@   @@@@@?@@?@?@  ??@@.?::C* ?௻Aѿkkx?Ң1&+ #L.1&[25@&[63/;Nh.?௻A?kkx?Ң5@@&+ 3@/;Nh5@@&}61@&}2#@L@@  @A?^@@@=@7 *@2}@-@'@"@a"H9@Q9@Q ?@@`? @A?^@@`?@>?@8?@?X8@?A8I ?:@@  9@V:@@b=@%:=@'*=@(!:@)^1@@2@0@  2  0 !2C1@C:)^=(='=%:@b.9V* @A?  @Ai@A?y@? ?@:@@6@4@@V?%1`?9 O 1`  9 O1`% @V@64 @: @?  @Ay@Ai ?:@@  9@V:@@b=@%:=@'*=@(!:@)^1@@2@0@ 2  0 !2C1@C:)^=(='=%:@b.9V*-)G)G)*⤒I$JX!F  0 mm*⤒I$J0?mmG@$I$JVC@!@m :@+@[mm.@0*@4` ^!@6 @ -&?G)G)@4`@ X!F  @6 @@@4`@ ^@0@@+@@[mm@!@@m @@$I$JV?@mm*@⤒I$J0 ?mm?xt_w yG?*?@?J4` @5@ ?@*@ )@@5Lx?xt_w ?yG?** ?J4b )@5LxP* &?:5@ L?;? 9`S;?y;@y9`@S6`@"@@??;@  ;@?y;@y: @`5@,@@@?@?@? ?@@/@@@7`@?2 /@@  l7`?2  /@@ ?@ ??  ?   , 5 : ` ;y ;?y acm-6.0_20200416/src/gedit/gdf-big-endian/scale-f18.gdf0000644000000000000000000002767010357223037020374 0ustar rootrootRR11?/@@ (3Q\(\?fffffN*\(\@zG?\(\?R?:G{\(\?fffff?fffff\(\ =pԅQ녿\(\:G{Q\(\R(Ϳ\(\zG2\(\>QD6V=p \(\ǮzHa7\(¿\(\ =pk7\(¿\(\?\(\k?;@ $7\(?\(\?\(\k7\(?\(\ =pk6V=p ?\(\ǮzHa2?\(\>QD(?\(\zGQ?\(\RԅQ?\(\:G{?fffff?\(\ =p?:G{?\(\?fffff??\(\?R*?\(\@zG3Q?\(\?fffffN?@b?Q녀@>Q R 3!p =ǮzHH 5zG \(\\7\(Qk7\(¿k5zG\?;?`5zG\7\(?k7\(@Qk5zG@ \(\\3!p =@ǮzHH@>Q@ R?Q?xt_w ?yG?** ?J4b%Q2aRƈLE5L& =p =pQ ?fffff>QQ <2+33333\(\}?xt_w yG?*?@?J4`<@2+33333\(\[?fffff@>QQ& =p@ =pQ %Q@2aRƈLE5LY-&?G)G)@4`@ X!F ^@2Q?\(\\(@1kzH@:G{$@,33333@ fffffǮzH<@'LzG@ \(\>"R@\(@>Q .Ϲu@aR@zGɂ1f?:G{@\(𜆕6 0& =p@ 7 =p׿Zy +G{?CJ -)G)G)*⤒I$JX!F \+G{CJ& =p 7 =p׿Zy ?:G{\(𜆕6 0@aRzGɂ1f@\(>Q .Ϲu @'LzG \(\>"R@,33333 fffffǮzH<@1kzH:G{$@2Q\(\\( 2 Z+\(\:G{/\(zG--\(zG$6:G{%``A8˅Q$\(€u?98\)$zHx<9ozH"aRz56q \(\b5p = fffff] ?:@@ X5p =@ fffff]6q@ \(\b9ozH@"aRz98\)@$zHx8˅Q@$\(€u6:G{@%``-\(@zG$/\(@zG-+\(\@:G{ 1` V5{\(Z-zG\(\%^zG =p@aRǮzH@3G{\(\@6îzH\(\@: =p =p@=-Gz\(\@>(\ @A? T@>(\@=-Gz?\(\@: =p? =p@6îzH?\(\@3G{?\(\@aR?ǮzH^zG? =p-zG?\(\%5{\(Z 2 R+\(\:G{/\(zG--\(zG$6:G{%``A8˅Q$\(€u?98\)$zHx<9ozH"aRz56q \(\b5p = fffff]?:@@ P5p =@ fffff]6q@ \(\b9ozH@"aRz98\)@$zHx8˅Q@$\(€u6:G{@%``-\(@zG$/\(@zG-+\(\@:G{?@@`? ^@>\)?\(\@<Q? =p@9fffff?\(@4\(€?\(@zG?\(4 =p?T5)GzX@@  @>\)?\(\@Q@4zH˅Q@/\(zH1@(˅QQL@$zHp =_@\(zHp@>Q =p =p\(\( Gz5Q[5Q\(\[?௻A?kkx?Ң5@@&+0G{@ {AhSֿR62+33333@\("\(@-@\(#<& >Q@ \(\\(?௻Aѿkkx?Ң1&+ >Q \(\\(-\(#<&2+33333\("\(@0G{ {AhSֿR6@  \ Gz?\(\?:G{ GzQ@>Q Gz \(\?R Gz>Q? =p Gz>Q =p GzzG\( Gz fffffR GzǮzH=p  Gz˅Q@  Z Gz˅Q Gz?ǮzH=p  Gz@ fffffR Gz@zG\( Gz@>Q =p Gz@>Q? =p Gz@ \(\?R Gz?Q@>Q Gz\(\?:G{`깥ӣ?UaQv@,?@,s V@)=p ?:G{K@(Ϳ?\(M@('\(?\(\O@(x\(\(O@(=?|iǮzHzGO@(S"`A\(\ GzN@( ě\(\ =pM@)=p zHK`깥ӨUaQu`깥Ө@,ٙ?@,l X@)=p zHK@( ě?\(\ =pM@(S"`A?\(\ GzN@(=?|i?ǮzHzGO@(x@\(\(O@('\(@?\(\O@(??\(M@)=p ?:G{Kacm-6.0_20200416/src/gedit/actions.c0000644000000000000000000001171613074625071015275 0ustar rootroot/* * Copyright (c) 1994, Riley Rainey, riley@netcon.com * * Permission to use, copy, modify and distribute (without charge) this * software, documentation, images, etc. is granted, provided that this * comment and the author's name is retained. * * This software is provided by the author as is, and without any expressed * or implied warranties, including, but not limited to, the implied * warranties of merchantability and fitness for a particular purpose. In no * event shall the author be liable for any direct, indirect, incidental, or * consequential damages arising in any way out of the use of this software. */ #include #include #include "shared.h" #include "gutil.h" #include "edit.h" #include "circle.h" #define actions_IMPORT #include "actions.h" static String normal_translations = ": point-begin() \n\ : point-end()"; static String extra_translations = "Shift: point-begin(extend) \n\ : point-begin() \n\ : point-motion() \n\ : point-end() \n\ : close-polygon()"; static XtTranslations normal, extra; /* * The next action procedure is typically associated with Button 1 down. * * The action taken here depends on the value of edit_state. But we may: * * Determine the polygon nearest the click -- within reason. * * Begin the process of entering a 3-D point. * * Begin the process of relocating the origin. * */ static void PointBegin (Widget w, XEvent *event, String *params, Cardinal *num_params) { XButtonEvent *ev = (XButtonEvent *) event; view_info_t *p; Boolean extend = False; if ((*num_params > 0) && (strcmp (*params, "extend") == 0)) extend = True; XtVaGetValues (w, XmNuserData, &p, NULL); switch (edit_state) { case STATE_POINT: BeginPick (w, p, ev->x, ev->y, extend); break; case STATE_POLYGON: BeginPolygonPoint(w, p, ev->x, ev->y); break; case STATE_MOVE_ORIGIN: break; case STATE_CIRCLE: BeginCirclePoint (w, p, ev->x, ev->y); break; case STATE_MARKER: BeginPolygonPoint(w, p, ev->x, ev->y); break; } } /* * Move the selected polygon in point mode. * * Slide the new point along the perpedicular-axis line. * * Move the origin locator. */ static void PointMotion (Widget w, XEvent *event, String *params, Cardinal *num_params) { XMotionEvent *ev = (XMotionEvent *) event; view_info_t *p; XtVaGetValues (w, XmNuserData, &p, NULL); switch (edit_state) { case STATE_POINT: DragSelection (w, p, ev->x, ev->y); break; case STATE_POLYGON: case STATE_MARKER: DragPolygonPoint(w, p, ev->x, ev->y); break; case STATE_CIRCLE: DragCirclePoint (w, p, ev->x, ev->y); break; case STATE_MOVE_ORIGIN: break; } } /* * Lock in a polygon selection. * * The point has been positioned and is ready to be registered. * * Relocate the origin. */ static void PointEnd (Widget w, XEvent *event, String *params, Cardinal *num_params) { XButtonEvent *ev = (XButtonEvent *) event; view_info_t *p; XtVaGetValues (w, XmNuserData, &p, NULL); switch (edit_state) { case STATE_POINT: CompleteDrag(w, p, ev->x, ev->y); break; case STATE_POLYGON: CompletePolygonPoint (w, p, ev->x, ev->y); break; case STATE_CIRCLE: CompleteCirclePoint (w, p, ev->x, ev->y); break; case STATE_MOVE_ORIGIN: break; case STATE_MARKER: CompleteMarker (w, p, ev->x, ev->y); break; } } /* * Delete the currently selected object. */ static void DeleteCurrent (Widget w, XEvent *event, String *params, Cardinal *num_params) { ClearSelection (); } static void ClosePolygon (Widget w, XEvent *event, String *params, Cardinal *num_params) { if (cur_polygon != (polygon_t *) NULL) CompletePolygon (w, cur_polygon); } static XtActionsRec action_list[] = { { "point-begin", PointBegin }, { "point-motion", PointMotion }, { "point-end", PointEnd }, { "close-polygon", ClosePolygon }, { "delete-selection", DeleteCurrent } }; void InitializeTranslations (XtAppContext app, Widget w1, Widget w2) { XtAppAddActions (app, action_list, XtNumber(action_list)); normal = XtParseTranslationTable (normal_translations); extra = XtParseTranslationTable (extra_translations); XtVaSetValues (w1, XmNtranslations, extra, NULL); XtVaSetValues (w2, XmNtranslations, extra, NULL); } void InstallNormalTranslations (Widget w) { view_info_t *p; XtVaGetValues (w, XmNuserData, &p, NULL); XtVaSetValues (w, XmNtranslations, normal, NULL); XtVaSetValues (p->other_widget, XmNtranslations, normal, NULL); } void InstallExtraTranslations (Widget w) { view_info_t *p; XtVaGetValues (w, XmNuserData, &p, NULL); XtVaSetValues (w, XmNtranslations, extra, NULL); XtVaSetValues (p->other_widget, XmNtranslations, extra, NULL); }acm-6.0_20200416/src/gedit/VWriteObject.h0000644000000000000000000000155513074625117016212 0ustar rootroot/* * Copyright (c) 1994, Riley Rainey, riley@netcon.com * * Permission to use, copy, modify and distribute (without charge) this * software, documentation, images, etc. is granted, provided that this * comment and the author's name is retained. * * This software is provided by the author as is, and without any expressed * or implied warranties, including, but not limited to, the implied * warranties of merchantability and fitness for a particular purpose. In no * event shall the author be liable for any direct, indirect, incidental, or * consequential damages arising in any way out of the use of this software. */ #ifndef VWriteObject_H #define VWriteObject_H #include #include "../V/VObjects.h" #ifdef VWriteObject_IMPORT #define EXTERN #else #define EXTERN extern #endif EXTERN int WriteVFile(char *name); #undef EXTERN #endif acm-6.0_20200416/src/gedit/VReadObject.h0000644000000000000000000000155613074625117015774 0ustar rootroot/* * Copyright (c) 1994, Riley Rainey, riley@netcon.com * * Permission to use, copy, modify and distribute (without charge) this * software, documentation, images, etc. is granted, provided that this * comment and the author's name is retained. * * This software is provided by the author as is, and without any expressed * or implied warranties, including, but not limited to, the implied * warranties of merchantability and fitness for a particular purpose. In no * event shall the author be liable for any direct, indirect, incidental, or * consequential damages arising in any way out of the use of this software. */ #ifndef VReadObject_H #define VReadObject_H #include #include "../V/VObjects.h" #ifdef VReadObject_IMPORT #define EXTERN #else #define EXTERN extern #endif EXTERN VObject *VReadObject2(FILE *f); #undef EXTERN #endif acm-6.0_20200416/src/gedit/balance.h0000644000000000000000000000342213143357677015235 0ustar rootroot/* * Copyright (c) 1994, Riley Rainey, riley@netcon.com * * Permission to use, copy, modify and distribute (without charge) this * software, documentation, images, etc. is granted, provided that this * comment and the author's name is retained. * * This software is provided by the author as is, and without any expressed * or implied warranties, including, but not limited to, the implied * warranties of merchantability and fitness for a particular purpose. In no * event shall the author be liable for any direct, indirect, incidental, or * consequential damages arising in any way out of the use of this software. */ #ifndef balance_H #define balance_H #include "../V/Vlibmath.h" #ifdef balance_IMPORT #define EXTERN #else #define EXTERN extern #endif /** *

 *   ----------------  z = 0 in body coordinates
 *      ^
 *      |       r{m,n}.z        (constant)
 *      v
 *      o       gear attachment point
 *      ^
 *      |       c{m,n}.z        strut extension  (0 - c{m,n}Max)
 *      v
 *      ^
 *      |       G{m,n}          strut + tire length  (constant)
 *      v
 *   ----------------  ground
 * 
*/ struct balance_data { double weight; /* weight for this test */ VPoint rm; /* rest main gear ground contact point (input), rest main gear attachment point (output) */ VPoint rn; /* rest nose gear ground contact point (input), rest nose gear attachment point (output) */ double cm, cn; /* rest extension values of each strut */ double cmMax, cnMax; /* maximum extension values of each strut */ double Gm, Gn; /* strut + tire lengths */ double Km, Kn; /* string constants (output) */ double Gpz; /* the old "grounding point" Z value */ }; EXTERN void balance (struct balance_data *s); #undef EXTERN #endif acm-6.0_20200416/src/gedit/VWriteObject.c0000644000000000000000000001037413174326440016202 0ustar rootroot/* * Copyright (c) 1994, Riley Rainey, riley@netcon.com * * Permission to use, copy, modify and distribute (without charge) this * software, documentation, images, etc. is granted, provided that this * comment and the author's name is retained. * * This software is provided by the author as is, and without any expressed * or implied warranties, including, but not limited to, the implied * warranties of merchantability and fitness for a particular purpose. In no * event shall the author be liable for any direct, indirect, incidental, or * consequential damages arising in any way out of the use of this software. */ #include #include #include "../util/error.h" #include "shared.h" #define VWriteObject_IMPORT #include "VWriteObject.h" int WriteVFile(char *name) { int i, j, k, points = 0, polygons = 0, error; register point_t *p; FILE *f; char ivname[1024]; if ((f = fopen (name, "w")) == (FILE *) NULL) { perror ("can't open file"); } /* * Total the number of vertices in all of the object's polygons */ for (i=sel_polygon; i >= 0; i = polygon_list[i].next) { polygons ++; points += polygon_list[i].num_points; } for (i=unsel_polygon; i >= 0; i = polygon_list[i].next) { polygons ++; points += polygon_list[i].num_points; } /* * Print the header */ fprintf (f, "%s\n%d %d\n", "object", points, polygons); /* * Print the point list */ k = 1; for (i=sel_polygon; i >= 0; i = polygon_list[i].next) { for (j=0; j < polygon_list[i].num_points; ++j) { p = &polygon_list[i].point[j]; fprintf (f, "%d %lg %lg %lg\n", k, p->point.x, p->point.y, p->point.z); ++k; } } for (i=unsel_polygon; i >= 0; i = polygon_list[i].next) { for (j=0; j < polygon_list[i].num_points; ++j) { p = &polygon_list[i].point[j]; fprintf (f, "%d %lg %lg %lg\n", k, p->point.x, p->point.y, p->point.z); ++k; } } /* * Print the polygon list */ k = 1; for (i=sel_polygon; i >= 0; i = polygon_list[i].next) { fprintf(f, "%s %d", "gray44", polygon_list[i].num_points); for (j=0; j < polygon_list[i].num_points; ++j) { fprintf(f, " %d", k++); } fprintf (f, "\n"); } for (i=unsel_polygon; i >= 0; i = polygon_list[i].next) { fprintf(f, "%s %d", "gray44", polygon_list[i].num_points); for (j=0; j < polygon_list[i].num_points; ++j) { fprintf(f, " %d", k++); } fprintf (f, "\n"); } error = ferror(f) ? -1 : 0; fclose (f); /* * Now write the aircraft inventory information */ snprintf(ivname, sizeof(ivname), "%s.inv", name); if ((f = fopen (ivname, "w")) == NULL) error_system("opening %s for writing", ivname); c.viewPoint = marker_list[MARKER_HEAD].location.point; fprintf (f, "aircraft \"%s\" {\n\n", c.name); fprintf (f, "\tWingArea\t%lg\n", c.wingS); fprintf (f, "\tWingHalfSpan\t%lg\n", c.wings); fprintf (f, "\tChord\t\t%lg\n", c.c); fprintf (f, "\tEmptyWeight\t%lg\n", c.emptyWeight); fprintf (f, "\tMaxFuel\t\t%lg\n", c.maxFuel); fprintf (f, "\tIxx\t\t%lg\n", c.I.m[0][0]); fprintf (f, "\tIyy\t\t%lg\n", c.I.m[1][1]); fprintf (f, "\tIzz\t\t%lg\n", c.I.m[2][2]); fprintf (f, "\tRm\t\t{%lg, %lg, %lg}\n", c.rm.x, c.rm.y, c.rm.z); fprintf (f, "\tRn\t\t{%lg, %lg, %lg}\n", c.rn.x, c.rn.y, c.rn.z); fprintf (f, "\tKm\t\t%lg\n", c.Km); fprintf (f, "\tKn\t\t%lg\n", c.Kn); fprintf (f, "\tGm\t\t%lg\n", c.Gm); fprintf (f, "\tGn\t\t%lg\n", c.Gn); fprintf (f, "\tCmMax\t\t%lg\n", c.cmMax); fprintf (f, "\tCnMax\t\t%lg\n", c.cnMax); //fprintf (f, "\tGroundingPoint\t{0.0, 0.0, %lg}\n", c.groundingPoint.z); fprintf (f, "\tViewPoint\t{%lg, %lg, %lg}\n", c.viewPoint.x, c.viewPoint.y, c.viewPoint.z); fprintf (f, "\n"); fprintf (f, "\tMaxThrust\t%lg\n", c.maxThrust); fprintf (f, "\tMaxABThrust\t%lg\n", c.maxABThrust); fprintf (f, "\tSpFuelConsump\t%lg\n", c.spFuelConsump); fprintf (f, "\tSpABFuelConsump\t%lg\n", c.spABFuelConsump); fprintf (f, "\tEngineLag\t%lg\n", c.engineLag); fprintf (f, "\n"); fprintf (f, "\tClda\t\t%lg\n", c.Clda); fprintf (f, "\tCldr\t\t%lg\n", c.Cldr); fprintf (f, "\tClp\t\t%lg\n", c.Clp); fprintf (f, "\tCmq\t\t%lg\n", c.Cmq); fprintf (f, "\tCnr\t\t%lg\n", c.Cnr); fprintf (f, "\tCmAlpha\t\t%lg\n", c.cmSlope); //fprintf (f, "\tCmFactor\t%lg\n", c.cmFactor); fprintf (f, "\t}\n"); fclose (f); return error; } acm-6.0_20200416/src/gedit/cell.c0000644000000000000000000000326113074625071014550 0ustar rootroot/* * Copyright (c) 1994, Riley Rainey, riley@netcon.com * * Permission to use, copy, modify and distribute (without charge) this * software, documentation, images, etc. is granted, provided that this * comment and the author's name is retained. * * This software is provided by the author as is, and without any expressed * or implied warranties, including, but not limited to, the implied * warranties of merchantability and fitness for a particular purpose. In no * event shall the author be liable for any direct, indirect, incidental, or * consequential damages arising in any way out of the use of this software. */ #include #include #include #include #include #include "shared.h" #define cell_IMPORT #include "cell.h" int LocateCell (struct cell *p, int id) { int n; for (n = 0; p->id >= 0; n++, p++) { if (id == p->id) { return n; } } fprintf (stderr, "Unable to locate cell %d\n \ Cell zero will contain invalid data\n", id); return 0; } double GetCellValueDouble (struct cell *p, int n, double *value) { char *s; s = XmTextFieldGetString (p[LocateCell(p, n)].field); *value = atof(s); XtFree (s); return *value; } void SetCellValueDouble (struct cell *p, int n, double value) { char s[64]; sprintf (s, "%.8lg", value); XmTextFieldSetString (p[LocateCell(p, n)].field, s); } char * GetCellValueString (struct cell *p, int n, char *value) { char *s; s = XmTextFieldGetString (p[LocateCell(p, n)].field); strcpy (value, s); XtFree (s); return value; } void SetCellValueString (struct cell *p, int n, char *value) { XmTextFieldSetString (p[LocateCell(p, n)].field, value); } acm-6.0_20200416/src/gedit/gutil1.c0000644000000000000000000002324113156540162015034 0ustar rootroot/* * Copyright (c) 1994, Riley Rainey, riley@netcon.com * * Permission to use, copy, modify and distribute (without charge) this * software, documentation, images, etc. is granted, provided that this * comment and the author's name is retained. * * This software is provided by the author as is, and without any expressed * or implied warranties, including, but not limited to, the implied * warranties of merchantability and fitness for a particular purpose. In no * event shall the author be liable for any direct, indirect, incidental, or * consequential damages arising in any way out of the use of this software. */ #include #include #include "shared.h" #include "edit.h" #define gutil1_IMPORT #include "gutil1.h" #define MINIMUM_GRID_SPACING 50 #define MINIMUM_RULER_SPACING 50 #define RULER_MARGIN 2 #define RULER_MAJOR_LENGTH 7 #define RULER_MINOR1_LENGTH 4 #define RULER_MINOR2_LENGTH 2 #define RULER_THICKNESS 2 void RescaleView (Widget w, double factor) { polygon_t *poly; point_t *q; view_info_t *p; register int i, j, xc, yc, zc; XtVaGetValues (w, XmNuserData, &p, NULL); switch (p->layout) { case VL_NXNY: case VL_NYX: xc = (p->width + 1) / 2; yc = (p->height + 1) / 2; zc = (p->other_view->height + 1) / 2; p->other_view->origin_x = p->origin_x = (p->origin_x - xc) * factor + xc; p->origin_y = (p->origin_y - yc) * factor + yc; p->other_view->origin_y = (p->other_view->origin_y - zc) * factor + zc; break; case VL_NXZ: xc = (p->width + 1) / 2; yc = (p->other_view->height + 1) / 2; zc = (p->height + 1) / 2; p->other_view->origin_x = p->origin_x = (p->origin_x - xc) * factor + xc; p->origin_y = (p->origin_y - zc) * factor + zc; p->other_view->origin_y = (p->other_view->origin_y - yc) * factor + yc; break; case VL_NYZ: xc = (p->other_view->height + 1) / 2; yc = (p->width + 1) / 2; zc = (p->height + 1) / 2; p->other_view->origin_x = p->origin_x = (p->origin_x - yc) * factor + yc; p->origin_y = (p->origin_y - zc) * factor + zc; p->other_view->origin_y = (p->other_view->origin_y - xc) * factor + xc; break; } pixel_scale /= factor; for (i=0, poly=polygon_list; i < polygon_max; ++i, ++poly) { for (j=0, q=poly->point; j < poly->num_points; ++j, ++q) { PointToXYZ (p, q); } } DrawWidget (w, False); DrawWidget (p->other_widget, False); } void DrawWidget (Widget w, Boolean immediate) { polygon_t *poly; point_t *q; view_info_t *p; register int i, j; int x1, y1, x2, y2; Display *dpy; Drawable d; Pixel fg, bg; XtVaGetValues (w, XmNuserData, &p, XmNforeground, &fg, XmNbackground, &bg, NULL); dpy = XtDisplay (w); d = XtWindow (w); if (d == 0) immediate = False; XSetForeground (dpy, p->gc, bg); if (immediate) XFillRectangle (dpy, d, p->gc, 0, 0, p->width, p->height); XFillRectangle (dpy, p->pixmap, p->gc, 0, 0, p->width, p->height); XSetForeground (dpy, p->gc, fg); XSetLineAttributes (dpy, p->gc, app_data.line_thickness, LineSolid, CapButt, JoinMiter); for (i=unsel_polygon; i >= 0; i = polygon_list[i].next) { poly = &polygon_list[i]; if (poly->num_points == 0) continue; WorldToWidget (p, &poly->point[poly->num_points-1], &x1, &y1); for (j=0, q=poly->point; j < poly->num_points; ++j, ++q) { WorldToWidget (p, q, &x2, &y2); if (immediate) XDrawLine (dpy, d, p->gc, x1, y1, x2, y2); XDrawLine (dpy, p->pixmap, p->gc, x1, y1, x2, y2); x1 = x2; y1 = y2; } } XSetForeground (dpy, p->gc, app_data.select_pixel); XSetLineAttributes (dpy, p->gc, app_data.selection_thickness, LineSolid, CapButt, JoinMiter); for (i=sel_polygon; i >= 0; i = polygon_list[i].next) { poly = &polygon_list[i]; if (poly->num_points == 0) continue; WorldToWidget (p, &poly->point[poly->num_points-1], &x1, &y1); for (j=0, q=poly->point; j < poly->num_points; ++j, ++q) { WorldToWidget (p, q, &x2, &y2); if (immediate) XDrawLine (dpy, d, p->gc, x1, y1, x2, y2); XDrawLine (dpy, p->pixmap, p->gc, x1, y1, x2, y2); x1 = x2; y1 = y2; } } if (immediate) DrawGrid (p, dpy, d); DrawGrid (p, dpy, p->pixmap); if (immediate) DrawRuler (p, dpy, d, bg); DrawRuler (p, dpy, p->pixmap, bg); if (immediate == False && d != 0) XCopyArea (dpy, p->pixmap, d, p->gc, 0, 0, p->width, p->height, 0, 0); } void DrawPolygon (Widget w, polygon_t *poly, Boolean immediate) { point_t *q; view_info_t *p; register int j; int x1, y1, x2, y2; Display *dpy; Drawable d; Pixel fg, bg; XtVaGetValues (w, XmNuserData, &p, XmNforeground, &fg, XmNbackground, &bg, NULL); dpy = XtDisplay (w); d = XtWindow (w); if (d == 0) immediate = False; XSetForeground (dpy, p->gc, fg); XSetLineAttributes (dpy, p->gc, app_data.line_thickness, LineSolid, CapButt, JoinMiter); if (poly->num_points == 0) return; WorldToWidget (p, &poly->point[poly->num_points-1], &x1, &y1); for (j=0, q=poly->point; j < poly->num_points; ++j, ++q) { WorldToWidget (p, q, &x2, &y2); if (immediate) XDrawLine (dpy, d, p->gc, x1, y1, x2, y2); XDrawLine (dpy, p->pixmap, p->gc, x1, y1, x2, y2); x1 = x2; y1 = y2; } if (immediate == False && d != 0) XCopyArea (dpy, p->pixmap, d, p->gc, 0, 0, p->width, p->height, 0, 0); } void WorldToWidget (view_info_t *p, point_t *q, int *x, int *y) { switch (p->layout) { case VL_NXZ: *x = q->x; *y = q->z; break; case VL_NXNY: *x = q->x; *y = q->y; break; case VL_NYX: *x = q->y; *y = q->x; break; case VL_NYZ: *x = q->y; *y = q->z; break; } } void DrawGrid (view_info_t *p, Display *dpy, Drawable d) { int exp, n, x, y; if (app_data.show_grid == False) return; XSetForeground (dpy, p->grid_gc, app_data.grid_pixel); for (exp = 1; ; exp *= 10) { if (exp / pixel_scale >= MINIMUM_GRID_SPACING) break; if (5.0 * exp / pixel_scale >= MINIMUM_GRID_SPACING) { exp = 5 * exp; break; } } /* * Y-axis lines */ for (x=p->origin_x, n = 0; x > 0; ) { XDrawLine (dpy, d, p->grid_gc, x, 0, x, p->height); ++ n; x = p->origin_x - (int) (n * exp / pixel_scale); } for (x=p->origin_x, n = 0; x < p->width; ) { ++ n; x = p->origin_x + (int) (n * exp / pixel_scale); XDrawLine (dpy, d, p->grid_gc, x, 0, x, p->height); } /* * X-axis lines */ for (y=p->origin_y, n = 0; y > 0; ) { XDrawLine (dpy, d, p->grid_gc, 0, y, p->width, y); ++ n; y = p->origin_y - (int) (n * exp / pixel_scale); } for (y=p->origin_y, n = 0; y < p->height; ) { ++ n; y = p->origin_y + (int) (n * exp / pixel_scale); XDrawLine (dpy, d, p->grid_gc, 0, y, p->width, y); } } void DrawSelectedPolygon (Widget w, polygon_t *poly, Boolean immediate, Boolean erase) { register int i; int x1, x2, y1, y2; point_t *q; view_info_t *p; Pixel bg; Display *dpy; Drawable d; dpy = XtDisplay (w); d = XtWindow (w); if (d == 0) immediate = False; XtVaGetValues (w, XmNuserData, &p, XmNbackground, &bg, NULL); if (erase) XSetForeground (dpy, p->gc, bg); else XSetForeground (dpy, p->gc, app_data.select_pixel); XSetLineAttributes (dpy, p->gc, app_data.selection_thickness, LineSolid, CapButt, JoinMiter); WorldToWidget (p, &poly->point[poly->num_points-1], &x1, &y1); for (i=0, q=poly->point; i < poly->num_points; ++i, ++q) { WorldToWidget (p, q, &x2, &y2); if (immediate) XDrawLine (dpy, d, p->gc, x1, y1, x2, y2); XDrawLine (dpy, p->pixmap, p->gc, x1, y1, x2, y2); x1 = x2; y1 = y2; } } void DrawRuler (view_info_t *p, Display *dpy, Drawable d, Pixel bg) { int ruler_y, font_y, nseg, exp, n, x, xw, yw, xv; XSegment seg[256]; char s[32]; /* * we'll only display the horizontal ruler in the top window */ if (p->other_widget == twindow) return; if (app_data.show_ruler == False) return; for (exp = 1; ; exp *= 10) { if (exp / pixel_scale >= MINIMUM_RULER_SPACING) break; if (2.0 * exp / pixel_scale >= MINIMUM_RULER_SPACING) { exp = 2 * exp; break; } if (5.0 * exp / pixel_scale >= MINIMUM_RULER_SPACING) { exp = 5 * exp; break; } } ruler_y = p->height - (RULER_THICKNESS + 2 * RULER_MARGIN + RULER_MAJOR_LENGTH + app_data.ruler_font->max_bounds.ascent); font_y = ruler_y + RULER_THICKNESS + RULER_MARGIN + app_data.ruler_font->max_bounds.ascent - 2; XSetForeground (dpy, p->gc, bg); XFillRectangle (dpy, d, p->gc, 0, ruler_y, p->width, p->height - ruler_y); XSetForeground (dpy, p->gc, app_data.grid_pixel); seg[0].x1 = 0; seg[0].x2 = p->width - 1; seg[0].y1 = seg[0].y2 = ruler_y; nseg = 1; /* * Major tick marks */ for (x=p->origin_x, n = 0; x > 0; ) { seg[nseg].x1 = seg[nseg].x2 = x; seg[nseg].y1 = p->height - 1; seg[nseg].y2 = p->height - RULER_MAJOR_LENGTH; ++ nseg; xv = (int) (n * exp); sprintf (s, "%d", xv); StringSize (s, &xw, &yw); XDrawString (dpy, d, p->gc, x - xw / 2, font_y, s, strlen(s)); ++ n; x = p->origin_x - (int) (n * exp / pixel_scale); } for (x=p->origin_x, n = 0; x < p->width; ) { ++ n; x = p->origin_x + (int) (n * exp / pixel_scale); xv = (int) (n * exp); sprintf (s, "%d", xv); StringSize (s, &xw, &yw); XDrawString (dpy, d, p->gc, x - xw / 2, font_y, s, strlen(s)); seg[nseg].x1 = seg[nseg].x2 = x; seg[nseg].y1 = p->height - 1; seg[nseg].y2 = p->height - RULER_MAJOR_LENGTH; ++ nseg; } XSetLineAttributes (dpy, p->gc, RULER_THICKNESS, LineSolid, CapButt, JoinMiter); XDrawSegments (dpy, d, p->gc, seg, nseg); } void StringSize (char *s, int *xw, int *yw) { *xw = XTextWidth (app_data.ruler_font, s, strlen (s)); *yw = app_data.ruler_font->max_bounds.ascent; } acm-6.0_20200416/src/gedit/Makefile0000644000000000000000000000574613646045024015136 0ustar rootroot# This file generated by make-makefile, do not edit! # Create Makefile-include.txt instead for your customizations. CC := gcc CFLAGS := -Wall -Werror -g -fmax-errors=99 -Wuninitialized -Wmissing-prototypes -Wredundant-decls LIBS := .PHONY: all all: make CrExFormDlg.o VReadObject.o VWriteObject.o actions.o balance.o cell.o circle.o dialog.o edit.o gedit.exe gutil.o gutil1.o io.o shared.o include Makefile-include.txt .PHONY: test test: gedit.exe ./gedit.exe .PHONY: clean clean: rm -f *.o *.exe *.stackdump gedit CrExFormDlg.o: CrExFormDlg.c CrExFormDlg.h ../V/Vlibmath.h shared.h $(CC) $(CFLAGS) -c CrExFormDlg.c -o CrExFormDlg.o VReadObject.o: VReadObject.c VReadObject.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlibmath.h ../util/memory.h ../util/units.h $(CC) $(CFLAGS) -c VReadObject.c -o VReadObject.o VWriteObject.o: VWriteObject.c VWriteObject.h ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlibmath.h ../util/error.h ../util/units.h shared.h $(CC) $(CFLAGS) -c VWriteObject.c -o VWriteObject.o actions.o: actions.c actions.h ../V/Vlibmath.h circle.h edit.h gutil.h shared.h $(CC) $(CFLAGS) -c actions.c -o actions.o balance.o: balance.c balance.h ../V/Vlibmath.h $(CC) $(CFLAGS) -c balance.c -o balance.o cell.o: cell.c cell.h ../V/Vlibmath.h shared.h $(CC) $(CFLAGS) -c cell.c -o cell.o circle.o: circle.c circle.h ../V/Vlibmath.h edit.h gutil.h gutil1.h shared.h $(CC) $(CFLAGS) -c circle.c -o circle.o dialog.o: dialog.c dialog.h ../V/Vlibmath.h CrExFormDlg.h cell.h shared.h $(CC) $(CFLAGS) -c dialog.c -o dialog.o edit.o: edit.c edit.h ../V/Vlibmath.h ../util/memory.h gutil.h gutil1.h shared.h $(CC) $(CFLAGS) -c edit.c -o edit.o gedit.o: gedit.c ../V/VColor.h ../V/VObjects.h ../V/VPoly.h ../V/Vlibmath.h ../util/memory.h ../util/units.h CrExFormDlg.h VReadObject.h VWriteObject.h actions.h dialog.h gutil1.h io.h shared.h $(CC) $(CFLAGS) -c gedit.c -o gedit.o gedit.exe: ../V/VColor.o ../V/VObjects.o ../V/VPoly.o ../V/Vlibmath.o ../util/error.o ../util/gui.o ../util/memory.o ../util/sparsearray.o ../util/units.o CrExFormDlg.o VReadObject.o VWriteObject.o actions.o cell.o circle.o dialog.o edit.o gedit.o gutil.o gutil1.o io.o shared.o $(CC) $(CFLAGS) -o gedit.exe ../V/VColor.o ../V/VObjects.o ../V/VPoly.o ../V/Vlibmath.o ../util/error.o ../util/gui.o ../util/memory.o ../util/sparsearray.o ../util/units.o CrExFormDlg.o VReadObject.o VWriteObject.o actions.o cell.o circle.o dialog.o edit.o gedit.o gutil.o gutil1.o io.o shared.o $(LIBS) -lX11 -lXm -lXt -lm gutil.o: gutil.c gutil.h ../V/Vlibmath.h ../util/memory.h edit.h gutil1.h shared.h $(CC) $(CFLAGS) -c gutil.c -o gutil.o gutil1.o: gutil1.c gutil1.h ../V/Vlibmath.h edit.h shared.h $(CC) $(CFLAGS) -c gutil1.c -o gutil1.o io.o: io.c io.h ../V/Vlibmath.h ../util/memory.h dialog.h edit.h gutil.h gutil1.h shared.h $(CC) $(CFLAGS) -c io.c -o io.o shared.o: shared.c shared.h ../V/Vlibmath.h dialog.h edit.h gutil.h gutil1.h io.h $(CC) $(CFLAGS) -c shared.c -o shared.o # Checksum of the original file: 1198779506 acm-6.0_20200416/src/gedit/circle.c0000644000000000000000000000533313074625071015074 0ustar rootroot/* * Copyright (c) 1994, Riley Rainey, riley@netcon.com * * Permission to use, copy, modify and distribute (without charge) this * software, documentation, images, etc. is granted, provided that this * comment and the author's name is retained. * * This software is provided by the author as is, and without any expressed * or implied warranties, including, but not limited to, the implied * warranties of merchantability and fitness for a particular purpose. In no * event shall the author be liable for any direct, indirect, incidental, or * consequential damages arising in any way out of the use of this software. */ #include #include "shared.h" #include "edit.h" #include "gutil.h" #include "gutil1.h" #define circle_IMPORT #include "circle.h" #define NUM_POINTS 12 static point_t drag; void ScaleCircle(view_info_t *p, polygon_t *poly, double scale) { double a = 0.0, a_incr = M_PI * 2.0 / NUM_POINTS; double other = 0.0, ocos, osin; int i; for (i=0; ipoint[i] = drag; switch (p->layout) { case VL_NYX: case VL_NXNY: poly->point[i].point.x += osin * scale; poly->point[i].point.y += ocos * scale; poly->point[i].point.z += other; break; case VL_NYZ: poly->point[i].point.x += other; poly->point[i].point.y += ocos * scale; poly->point[i].point.z += osin * scale; break; case VL_NXZ: poly->point[i].point.x += osin * scale; poly->point[i].point.y += other; poly->point[i].point.z += ocos * scale; break; default: poly->point[i].point.x += osin * scale; poly->point[i].point.y += ocos * scale; poly->point[i].point.z += other; break; } a += a_incr; PointToXYZ (p, &poly->point[i]); } if (scale > 0.0) { ComputePlaneEquation (poly); } } void BeginCirclePoint (Widget w, view_info_t *p, int x, int y) { polygon_t *poly; poly = BeginPolygon(); poly->num_points = NUM_POINTS; drag_origin.x = x; drag_origin.y = y; PointXY (w, p, x, y, &drag); ScaleCircle (p, poly, 0.0); } void DragCirclePoint(Widget w, view_info_t *p, int x, int y) { double dx = x - drag_origin.x, dy = y - drag_origin.y; double scale = sqrt (dx * dx + dy * dy) * pixel_scale; Display *dpy = XtDisplay(w); XSetFunction (dpy, p->gc, GXxor); XSetFunction (dpy, p->other_view->gc, GXxor); DrawPolygon (w, cur_polygon, True); DrawPolygon (p->other_widget, cur_polygon, True); ScaleCircle (p, cur_polygon, scale); DrawPolygon (w, cur_polygon, True); DrawPolygon (p->other_widget, cur_polygon, True); XSetFunction (dpy, p->gc, GXcopy); XSetFunction (dpy, p->other_view->gc, GXcopy); } void CompleteCirclePoint(Widget w, view_info_t *p, int x, int y) { CompletePolygon (w, cur_polygon); } acm-6.0_20200416/src/gedit/CrExFormDlg.h0000644000000000000000000000313113074625071015746 0ustar rootroot/* * Copyright (c) 1994, Riley Rainey, riley@netcon.com * * Permission to use, copy, modify and distribute (without charge) this * software, documentation, images, etc. is granted, provided that this * comment and the author's name is retained. * * This software is provided by the author as is, and without any expressed * or implied warranties, including, but not limited to, the implied * warranties of merchantability and fitness for a particular purpose. In no * event shall the author be liable for any direct, indirect, incidental, or * consequential damages arising in any way out of the use of this software. */ #ifndef CrExFormDlg_H #define CrExFormDlg_H #ifdef CrExFormDlg_IMPORT #define EXTERN #else #define EXTERN extern #endif //#include //#include //#include //#include //#include //#include //#include "XrMisc.h" EXTERN void DestroyParentCallback(Widget w, XtPointer client_data, XtPointer call_data); EXTERN void SetDialogPosition(Widget w, XtPointer client_data, XtPointer call_data); /** * Builds an dialog box action area based on a list of * buttons passed to it. This code is based on the example in chapter 7 of * the O'Reilly & Associates Volume 6 by Dan Heller. */ EXTERN Widget CreateButtonArea(char *name, Widget parent, ActionAreaButton *buttons, int num_buttons, int tightness, int default_button); EXTERN Widget CreateExtendedFormDialog(char *name, Widget parent, Widget *content_widget, ActionAreaButton *buttons, int num_buttons, int default_button); #undef EXTERN #endif acm-6.0_20200416/src/gedit/COPYRIGHT0000644000000000000000000000116210357223037014753 0ustar rootrootGEDIT - A 3-D object editor Copyright(c) 1994, Riley Rainey, rainey@netcom.com Permission to use, copy, modify and distribute (without charge) this software, documentation, images, etc. is granted, provided that this comment and the author's name is retained. This software is provided by the author as is, and without any expressed or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose. In no event shall the author be liable for any direct, indirect, incidental, or consequential damages arising in any way out of the use of this software. acm-6.0_20200416/src/gedit/cell.h0000644000000000000000000000232313074625071014553 0ustar rootroot/* * Copyright (c) 1994, Riley Rainey, riley@netcon.com * * Permission to use, copy, modify and distribute (without charge) this * software, documentation, images, etc. is granted, provided that this * comment and the author's name is retained. * * This software is provided by the author as is, and without any expressed * or implied warranties, including, but not limited to, the implied * warranties of merchantability and fitness for a particular purpose. In no * event shall the author be liable for any direct, indirect, incidental, or * consequential damages arising in any way out of the use of this software. */ #ifndef cell_H #define cell_H #ifdef cell_IMPORT #define EXTERN #else #define EXTERN extern #endif struct cell { int id; char *prompt; char *initial_value; int field_width; Widget field; Widget label; }; EXTERN int LocateCell (struct cell *p, int id); EXTERN double GetCellValueDouble (struct cell *p, int n, double *value); EXTERN void SetCellValueDouble (struct cell *p, int n, double value); EXTERN char * GetCellValueString (struct cell *p, int n, char *value); EXTERN void SetCellValueString (struct cell *p, int n, char *value); #undef EXTERN #endif acm-6.0_20200416/src/gedit/shared.c0000644000000000000000000001203513100126074015063 0ustar rootroot/* * Copyright (c) 1994, Riley Rainey, riley@netcon.com * * Permission to use, copy, modify and distribute (without charge) this * software, documentation, images, etc. is granted, provided that this * comment and the author's name is retained. * * This software is provided by the author as is, and without any expressed * or implied warranties, including, but not limited to, the implied * warranties of merchantability and fitness for a particular purpose. In no * event shall the author be liable for any direct, indirect, incidental, or * consequential damages arising in any way out of the use of this software. */ #include #include #include #define shared_IMPORT #include "shared.h" #include "dialog.h" #include "gutil.h" #include "gutil1.h" #include "edit.h" #include "io.h" void SetCursor (int id) { Cursor cursor; switch (id) { case CURSOR_POINT: cursor = cursors[CURSOR_POINT]; break; case CURSOR_POLY_PLANE: cursor = cursors[CURSOR_POLY]; break; case CURSOR_CIRCLE: case CURSOR_POLY: cursor = cursors[CURSOR_POLY]; break; case CURSOR_ORIGIN: cursor = cursors[CURSOR_ORIGIN]; break; case CURSOR_MARKER: cursor = cursors[CURSOR_MARKER]; break; } XDefineCursor (XtDisplay(twindow), XtWindow(twindow), cursor); XDefineCursor (XtDisplay(bwindow), XtWindow(bwindow), cursor); } void MenuCB (Widget w, void *client_data, void *call_data) { int menu_id = shared_PtrToInt(client_data); Boolean value; VPoint extent; XmString string; char s[64], *factor_s; double factor; if (menu_id >= MENU_MARKER && menu_id < MENU_MARKER+32) { current_marker = menu_id - MENU_MARKER; if (marker_list[current_marker].defined) DisplayPoint(&marker_list[current_marker].location); SetCursor (CURSOR_MARKER); edit_state = STATE_MARKER; return; } switch (menu_id) { case MENU_MIRROR_XZ: case MENU_MIRROR_XY: case MENU_MIRROR_YZ: Mirror (menu_id); break; case MENU_CLEAR: ClearSelection(); break; case MENU_COPY: CopySelection(); break; case MENU_PASTE: PasteSelection(); break; case MENU_ROTATE_X: RotateXSelection(); break; case MENU_SAVE: if (filename_valid) WriteGeditFile (filename); else XtManageChild (save_as_dialog); break; case MENU_GRID: XtVaGetValues (w, XmNset, &value, NULL); if (value != app_data.show_grid) { app_data.show_grid = value; DrawWidget (twindow, False); DrawWidget (bwindow, False); } else { app_data.show_grid = value; } break; case MENU_RULER: XtVaGetValues (w, XmNset, &value, NULL); if (value != app_data.show_ruler) { app_data.show_ruler = value; DrawWidget (twindow, False); DrawWidget (bwindow, False); } else { app_data.show_ruler = value; } break; case MENU_OPEN: XtManageChild (open_dialog); break; case MENU_SAVE_AS: XtManageChild (save_as_dialog); break; case MENU_SET_VIEWS: XtManageChild (set_views_dialog); break; case MENU_SET_VIEWS_COMPLETE: switch (desired_view) { case VIEW_LEFT_TOP: t_info.layout = VL_NXZ; b_info.layout = VL_NXNY; break; case VIEW_FRONT_TOP: t_info.layout = VL_NYZ; b_info.layout = VL_NYX; break; } RescaleView (twindow, 1.0); XtUnmanageChild (set_views_dialog); break; case MENU_SET_VIEWS_CANCEL: XtUnmanageChild (set_views_dialog); break; case MENU_RESCALE: DetermineObjectExtent (&extent); sprintf (s, " %s : %f", "X", extent.x); string = XmStringCreateSimple(s); XtVaSetValues (extent_x, XmNlabelString, string, NULL); XmStringFree (string); sprintf (s, " %s : %f", "Y", extent.y); string = XmStringCreateSimple(s); XtVaSetValues (extent_y, XmNlabelString, string, NULL); XmStringFree (string); sprintf (s, " %s : %f", "Z", extent.z); string = XmStringCreateSimple(s); XtVaSetValues (extent_z, XmNlabelString, string, NULL); XmStringFree (string); XtManageChild (rescale_dialog); break; case MENU_RESCALE_APPLY: factor_s = XmTextFieldGetString (rescale_field); factor = atof(factor_s); if (factor != 0.0) RescaleObject (factor); break; case MENU_RESCALE_CANCEL: XtUnmanageChild (rescale_dialog); break; case MENU_GEAR: XtManageChild (gear_dialog); break; case MENU_GEAR_CANCEL: GetCraftInfo (&c); XtUnmanageChild (gear_dialog); break; case MENU_GEAR_CALCULATE: GearCalculate (&c); GetCraftInfo (&c); break; case MENU_INFO: XtManageChild (info_dialog); break; case MENU_INFO_CANCEL: GetCraftInfo (&c); XtUnmanageChild (info_dialog); break; case MENU_INFO_CALCULATE: GetCraftInfo (&c); break; case MENU_DERIV: XtManageChild (deriv_dialog); break; case MENU_DERIV_CANCEL: GetCraftInfo (&c); XtUnmanageChild (deriv_dialog); break; case MENU_DERIV_CALCULATE: GetCraftInfo (&c); break; case MENU_PWR: XtManageChild (powerplant_dialog); break; case MENU_PWR_CANCEL: GetCraftInfo (&c); XtUnmanageChild (powerplant_dialog); break; case MENU_PWR_CALCULATE: GetCraftInfo (&c); break; } }acm-6.0_20200416/src/gedit/Makefile-include.txt0000644000000000000000000000023513646045024017361 0ustar rootroot# OS specific compilation options: ifeq ($(OS),Windows_NT) all: @echo gedit is a X-Window program only, cannot compile under Windows, sorry! exit 0 endifacm-6.0_20200416/src/gedit/README0000644000000000000000000000752210357223037014346 0ustar rootrootGEDIT - A 3-D object editor Copyright(c) 1993-1998, Riley Rainey, rainey@netcom.com Permission to use, copy, modify and distribute (without charge) this software, documentation, images, etc. is granted, provided that this comment and the author's name is retained. This software is provided by the author as is, and without any expressed or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose. In no event shall the author be liable for any direct, indirect, incidental, or consequential damages arising in any way out of the use of this software. WHAT IS GEDIT? Well, this can be considered "work in progress", but it works. GEDIT can be used to build displayable objects for ACM. It requires Motif 1.1 or later. Generating three dimensional objects on a two dimensional screen is a bit of a challenge. GEDIT solves the problem by displaying two views of the same object simultaneously. The main GEDIT window displays a top and side view of an area used to build an object out of planar polygons. As an experiment, press the Polygon button on the left-hand side of the display. You must then define the three points that will determine the polygon's plane. You do that by clicking the mouse in one of the two view windows -- hold mouse button one down and move the mouse. See how the point in the opposite window moves up and down when you move the mouse up and down? What you're doing is defining a point in 3-space -- the first two coordinates are determined from where you clicked the mouse in the first window. The remaining coordinate is determined by the location of the point in the other window when you're finished dragging and you release the mouse button. Do that three times and you've defined three points that define a plane -- more mouse clicks immediately define a point on the polygon since the polygon's plane has already been determined by the location of the first three points. How is that useful? Picture this: take your favorite airplane book that contains three-views (top, left, front view) of a given aircraft. Now take the book over to a copier and copy those diagrams onto an overhead slide (the clear paper ;-)). Now cut out each view. You can then fire up GEDIT on your workstation, and tape the side view in the top window and the top view over the bottom one (I usually have enough static electricity around to hold it up without any tape) (make sure the two diagrams line up correctly). Now start defining wings, tails, etc ... cute, no? You can then change views (see the Layout menu) and do a similar thing with the front view. In the SaveAs dialog, you can output a file in V format. If you want the object to be revisable, save a copy under another filename in GEDIT (GDF) format. -- RBR BUILDING GEDIT -------------- GEDIT uses the ACM V graphics library. You must have the ACM sources available in order to build GEDIT. You will need to edit GEDIT's Makefile to set the "ACM" variable to point to the top-level ACM source directory (i.e. the directory that contains ACM's README file). The GEDIT File Format --------------------- Unfortunately, I was in a rush when I defined this graphics file format. It stores information in your platform's binary form (with its definition of structure alignment and floating point values) -- this is likely to be incompatible with the binary format of someone else's machine. So, until someone defines a "PGDF" (portable GDF) file format and a converter between "PGDF" and GDF, you are limited in the sharing that you'll be able to do with raw GDF files. A gdf directory that includes several files that I created (on a Sun-4) have been provided for you to examine. OTHER NOTES ----------- This software is designed to run on paletted visuals. It will run, but produce undesireable results in DirectColor visual. acm-6.0_20200416/src/gedit/dialog.h0000644000000000000000000000306313154325021015064 0ustar rootroot/* * Copyright (c) 1994, Riley Rainey, riley@netcon.com * * Permission to use, copy, modify and distribute (without charge) this * software, documentation, images, etc. is granted, provided that this * comment and the author's name is retained. * * This software is provided by the author as is, and without any expressed * or implied warranties, including, but not limited to, the implied * warranties of merchantability and fitness for a particular purpose. In no * event shall the author be liable for any direct, indirect, incidental, or * consequential damages arising in any way out of the use of this software. */ #ifndef dialog_H #define dialog_H #include "../V/Vlibmath.h" #ifdef dialog_IMPORT #define EXTERN #else #define EXTERN extern #endif struct balance_data { double weight; /* weight for this test */ VPoint rm; /* rest main gear location (input) */ VPoint rn; /* rest nose gear location (input) */ double cm, cn; /* rest compression values of each strut */ double Gm, Gn; /* strut + tire lengths */ double Km, Kn; /* string constants (output) */ double Gpz; /* the old "grounding point" Z value */ double theta; }; EXTERN void balance(struct balance_data *s); EXTERN Widget CreateInfoDialog(Widget parent); EXTERN Widget CreateGearDialog(Widget parent); EXTERN Widget CreateDerivDialog(Widget parent); EXTERN Widget CreatePowerplantDialog(Widget parent); EXTERN void InitializeDialogs(craftType *c); EXTERN void GetCraftInfo(craftType *c); EXTERN void GearCalculate(craftType *c); #undef EXTERN #endif acm-6.0_20200416/src/gedit/edit.h0000644000000000000000000000212313074625071014557 0ustar rootroot/* * Copyright (c) 1994, Riley Rainey, riley@netcon.com * * Permission to use, copy, modify and distribute (without charge) this * software, documentation, images, etc. is granted, provided that this * comment and the author's name is retained. * * This software is provided by the author as is, and without any expressed * or implied warranties, including, but not limited to, the implied * warranties of merchantability and fitness for a particular purpose. In no * event shall the author be liable for any direct, indirect, incidental, or * consequential damages arising in any way out of the use of this software. */ #ifndef edit_H #define edit_H #ifdef edit_IMPORT #define EXTERN #else #define EXTERN extern #endif EXTERN void Mirror (int op); EXTERN void PointToXYZ (view_info_t *p, point_t *point); EXTERN void ClearSelection(void); EXTERN void CopySelection(void); EXTERN void ClearClipboard(void); EXTERN void PasteSelection(void); EXTERN void RotateXSelection(void); EXTERN void PrintList(int start); EXTERN void PrintDiagnostics(void); #undef EXTERN #endif acm-6.0_20200416/src/gedit/circle.h0000644000000000000000000000205513074625071015077 0ustar rootroot/* * Copyright (c) 1994, Riley Rainey, riley@netcon.com * * Permission to use, copy, modify and distribute (without charge) this * software, documentation, images, etc. is granted, provided that this * comment and the author's name is retained. * * This software is provided by the author as is, and without any expressed * or implied warranties, including, but not limited to, the implied * warranties of merchantability and fitness for a particular purpose. In no * event shall the author be liable for any direct, indirect, incidental, or * consequential damages arising in any way out of the use of this software. */ #ifndef circle_H #define circle_H #ifdef circle_IMPORT #define EXTERN #else #define EXTERN extern #endif EXTERN void ScaleCircle(view_info_t *p, polygon_t *poly, double scale); EXTERN void BeginCirclePoint (Widget w, view_info_t *p, int x, int y); EXTERN void DragCirclePoint(Widget w, view_info_t *p, int x, int y); EXTERN void CompleteCirclePoint(Widget w, view_info_t *p, int x, int y); #undef EXTERN #endif acm-6.0_20200416/src/gedit/gedit.c0000644000000000000000000010304213173131671014721 0ustar rootroot/* * Copyright (c) 1994, Riley Rainey, riley@netcon.com * * Permission to use, copy, modify and distribute (without charge) this * software, documentation, images, etc. is granted, provided that this * comment and the author's name is retained. * * This software is provided by the author as is, and without any expressed * or implied warranties, including, but not limited to, the implied * warranties of merchantability and fitness for a particular purpose. In no * event shall the author be liable for any direct, indirect, incidental, or * consequential damages arising in any way out of the use of this software. */ /* * LINKER_OPTIONS -lX11 * LINKER_OPTIONS -lXt * LINKER_OPTIONS -lXm */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../util/memory.h" #include "shared.h" #include "dialog.h" #include "CrExFormDlg.h" #include "gutil1.h" #include "io.h" #include "actions.h" #include "VWriteObject.h" #include "VReadObject.h" #include "xbm/curs_poly.xbm" #include "xbm/curs_poly_mask.xbm" #include "xbm/curs_marker.xbm" #include "xbm/curs_marker_mask.xbm" static char grid_dash_list[2] = { 1, 4 }; static XmStringCharSet charset = (XmStringCharSet) XmSTRING_DEFAULT_CHARSET; /* * fallback resources */ static String fallback[] = { "*.Background: GhostWhite", "*buttons*highlightColor: GhostWhite", "*.fontList: -*-helvetica-medium-r-*-*-*-140-*", "*.rulerFont: -*-courier-bold-r-*-*-*-140-*", "*XmTextField.fontList: -*-courier-medium-r-*-*-*-140-*", "*XmPushButton.shadowThickness: 3", "*XmDrawingArea.traversalOn: false", "*.menu_bar*Background: #bbb", "*.menu_bar.spacing: 10", "*.top_frame.shadowType: XmSHADOW_ETCHED_OUT", "*.bottom_frame.shadowType: XmSHADOW_ETCHED_OUT", "*.twindow.background: #d8d8d8", "*.twindow.foreground: black", "*.bwindow.background: #e1caac", "*.bwindow.foreground: black", "*.main.form.height: 700", "*.main.form.width: 950", "*set_views.labelString: Set Views ...", "*mirror_xz.labelString: Mirror left/right", "*mirror_xz.acceleratorText: Alt-L", "*mirror_xz.accelerator: Metal:", "*mirror_xz.mnemonic: l", "*mirror_xy.labelString: Mirror top/bottom", "*mirror_xy.acceleratorText: Alt-T", "*mirror_xy.accelerator: Metat:", "*mirror_xy.mnemonic: t", "*mirror_yz.labelString: Mirror front/back", "*mirror_yz.acceleratorText: Alt-F", "*mirror_yz.accelerator: Metaf:", "*mirror_yz.mnemonic: f", "*rescale.labelString: Rescale Object ...", "*rescale.mnemonic: R", "*info.labelString: Aircraft Information ...", "*gear.labelString: Landing Gear ...", "*stability.labelString: Stability Derivatives ...", "*powerplant.labelString: Powerplant ...", "*rescale_dialog.dialogTitle: Rescale Object", "*open_d.dialogTitle: Open a File", "*open_d.okLabelString: Open", "*open_d.selectionLabelString: Open which file?", "*open_d.autoUnmanage: true", "*open_d*pattern: *.gdf", "*save_as_d.dialogTitle: Save Work", "*save_as_d.selectionLabelString: File name:", "*save_as_d.okLabelString: Save", "*save_as_d.*.fontList: -*-helvetica-medium-r-*-*-*-120-*", "*gedit_format.labelString: Gedit format", "*gedit_format.set: true", "*v_format.labelString: V format", "*rayshade_format.labelString: ACM Inventory format", "*show_grid.visibleWhenOff: true", "*show_ruler.visibleWhenOff: true", "*coodinates*columns: 8", "*coodinates*sensitive: false", "*new.labelString: New", "*open.labelString: Open ...", "*save.labelString: Save", "*save_as.labelString: Save As ...", "*exit.labelString: Exit", "*new.acceleratorText: Alt-N", "*new.accelerator: Metan:", "*new.mnemonic: N", "*open.acceleratorText: Alt-O", "*open.accelerator: Metao:", "*open.mnemonic: O", "*save.acceleratorText: Alt-S", "*save.accelerator: Metas:", "*save.mnemonic: S", "*save_as.mnemonic: A", "*exit.acceleratorText: Alt-E", "*exit.accelerator: Metae:", "*exit.mnemonic: E", "*cut.labelString: Cut", "*cut.acceleratorText: Shift-Del", "*cut.accelerator: ShiftDelete:", "*cut.mnemonic: t", "*copy.labelString: Copy", "*copy.acceleratorText: Ctrl-Ins", "*copy.accelerator: CtrlInsert:", "*copy.mnemonic: C", "*paste.labelString: Paste", "*paste.acceleratorText: Shift-Ins", "*paste.accelerator: ShiftInsert:", "*paste.mnemonic: P", "*clear.labelString: Clear", "*clear.mnemonic: e", "*rotx.labelString: Rotate 90 about X-Axis", "*info_dialog*XmLabelGadget.topOffset: 7", "*info_dialog*XmLabelGadget.rightOffset: 10", "*info_dialog*XmLabelGadget.leftOffset: 10", "*info_dialog*XmTextField.rightOffset: 10", "*gear_dialog*XmLabelGadget.topOffset: 7", "*gear_dialog*XmLabelGadget.rightOffset: 10", "*gear_dialog*XmLabelGadget.leftOffset: 10", "*gear_dialog*XmTextField.rightOffset: 10", "*powerplant_dialog*XmLabelGadget.topOffset: 7", "*powerplant_dialog*XmLabelGadget.rightOffset: 10", "*powerplant_dialog*XmLabelGadget.leftOffset: 10", "*powerplant_dialog*XmTextField.rightOffset: 10", "*stability_dialog*XmLabelGadget.topOffset: 7", "*stability_dialog*XmLabelGadget.rightOffset: 10", "*stability_dialog*XmLabelGadget.leftOffset: 10", "*stability_dialog*XmTextField.rightOffset: 10", "*stability_dialog*Calculate.sensitive: false", "*info_dialog*Calculate.sensitive: false", "*info_dialog*Calculate.sensitive: false", NULL }; static XrmOptionDescRec options[] = { {"-controllerClass", "*controllerClass", XrmoptionSepArg, "is"}, }; static XtResource resources[] = { { XtNselectionColor, XtCSelectionColor, XtRPixel, sizeof(Pixel), XtOffset(AppDataPtr, select_pixel), XtRString, (caddr_t) "firebrick" }, { XtNgridColor, XtCGridColor, XtRPixel, sizeof(Pixel), XtOffset(AppDataPtr, grid_pixel), XtRString, (caddr_t) "black" }, { XtNlineThickness, XtCLineThickness, XtRInt, sizeof(int), XtOffset(AppDataPtr, line_thickness), XtRImmediate, (caddr_t) 0 }, { XtNselectionThickness, XtCSelectionThickness, XtRInt, sizeof(int), XtOffset(AppDataPtr, selection_thickness), XtRImmediate, (caddr_t) 2 }, { XtNboxSize, XtCBoxSize, XtRInt, sizeof(int), XtOffset(AppDataPtr, box_size), XtRImmediate, (caddr_t) 5 }, { XtNpickSensitivity, XtCPickSensitivity, XtRInt, sizeof(int), XtOffset(AppDataPtr, pick_sensitivity), XtRImmediate, (caddr_t) 64 }, { XtNbuttonSize, XtCButtonSize, XtRInt, sizeof(int), XtOffset(AppDataPtr, button_size), XtRImmediate, (caddr_t) 32 }, { XtNcursorForeground, XtCCursorForeground, XtRPixel, sizeof(Pixel), XtOffset(AppDataPtr, cursor_foreground), XtRString, (caddr_t) "black" }, { XtNcursorBackground, XtCCursorBackground, XtRPixel, sizeof(Pixel), XtOffset(AppDataPtr, cursor_background), XtRString, (caddr_t) "white" }, { XtNshowGrid, XtCShowGrid, XmRBoolean, sizeof(Boolean), XtOffset(AppDataPtr, show_grid), XtRString, (caddr_t) "true" }, { XtNshowRuler, XtCShowRuler, XmRBoolean, sizeof(Boolean), XtOffset(AppDataPtr, show_ruler), XtRString, (caddr_t) "false" }, { XtNrulerFont, XtCFont, XtRFontStruct, sizeof(XFontStruct *), XtOffset(AppDataPtr, ruler_font), XtRString, (caddr_t) "fixed" } }; typedef struct { Boolean defined_in_this_version; Widget widget; char *name; char *pixmap_file; } button_list_t; button_list_t button_list[] = { { True, NULL, "point", "xbm/cursor_%d.xbm" }, { False, NULL, "hand", "xbm/hand_%d.xbm" }, { True, NULL, "polygon", "xbm/polygon_%d.xbm" }, { True, NULL, "circle", "xbm/circle_%d.xbm" }, { True, NULL, "origin", "xbm/origin_%d.xbm" }, { True, NULL, "zoom_out", "xbm/zoom_out_%d.xbm" }, { True, NULL, "zoom_in", "xbm/zoom_in_%d.xbm" } }; #define MAX_ARGS 16 #define APP_CLASS "Gedit" static Widget help_box; //static Widget view_box = (Widget) NULL; static void ViewCB (w, client_data, call_data) Widget w; caddr_t client_data; caddr_t call_data; { register XmToggleButtonCallbackStruct *cbs = (XmToggleButtonCallbackStruct *) call_data; if (cbs->set == False) return; if (client_data == 0) desired_view = VIEW_LEFT_TOP; else desired_view = VIEW_FRONT_TOP; } static Widget CreateHelp (parent) Widget parent; { Widget button; Widget message_box; Arg args[MAX_ARGS]; register int n; static char message[BUFSIZ]; XmString title_string = NULL; XmString message_string = NULL; XmString button_string = NULL; sprintf (message, "\ Gedit: A Three Dimensional Object Editor\n\ \n\ Copyright (c) 1991 Riley Rainey\n\ \n\n"); message_string = XmStringCreateLtoR (message, charset); button_string = XmStringCreateLtoR ("Continue", charset); title_string = XmStringCreateLtoR ("graphics editor help", charset); n = 0; XtSetArg (args[n], XmNdialogTitle, title_string); n++; XtSetArg (args[n], XmNokLabelString, button_string); n++; XtSetArg (args[n], XmNmessageString, message_string); n++; message_box = XmCreateMessageDialog (parent, "help_box", args, n); button = XmMessageBoxGetChild (message_box, XmDIALOG_CANCEL_BUTTON); XtUnmanageChild (button); button = XmMessageBoxGetChild (message_box, XmDIALOG_HELP_BUTTON); XtUnmanageChild (button); if (title_string) XmStringFree (title_string); if (message_string) XmStringFree (message_string); if (button_string) XmStringFree (button_string); return (message_box); } static Widget CreateViewsDialog (parent) Widget parent; { XmString string; static ActionAreaButton action_items[] = { { "Ok", MenuCB, (XtPointer) MENU_SET_VIEWS_COMPLETE}, { "Cancel", MenuCB, (XtPointer) MENU_SET_VIEWS_CANCEL}, { "Help", NULL, NULL }, }; Widget dialog, string_w, form, box; dialog = CreateExtendedFormDialog("dialog", parent, &form, action_items, XtNumber (action_items), 0); string = XmStringCreateSimple("Select the desired views:"); string_w = XtVaCreateManagedWidget("label", xmLabelGadgetClass, form, XmNlabelString, string, XmNleftAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, NULL); XmStringFree(string); box = XmVaCreateSimpleRadioBox (form, "box", 0, ViewCB, XmVaRADIOBUTTON, XmStringCreateSimple("Left side / Top"), NULL, NULL, NULL, XmVaRADIOBUTTON, XmStringCreateSimple("Front / Top"), NULL, NULL, NULL, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, string_w, NULL); XtManageChild (box); XtManageChild (form); return dialog; } static Widget CreateRescaleDialog (parent) Widget parent; { XmString string; static ActionAreaButton action_items[] = { { "Apply", MenuCB, (XtPointer) MENU_RESCALE_APPLY}, { "Cancel", MenuCB, (XtPointer) MENU_RESCALE_CANCEL}, { "Help", NULL, NULL }, }; Widget dialog, string_w, prompt, form; dialog = CreateExtendedFormDialog("rescale_dialog", parent, &form, action_items, XtNumber (action_items), 0); string = XmStringCreateSimple("Current object dimensions:"); string_w = XtVaCreateManagedWidget("label", xmLabelGadgetClass, form, XmNlabelString, string, XmNleftAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, NULL); XmStringFree(string); extent_x = XtVaCreateManagedWidget("label_x", xmLabelGadgetClass, form, XmNleftAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, string_w, NULL); extent_y = XtVaCreateManagedWidget("label_y", xmLabelGadgetClass, form, XmNleftAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, extent_x, NULL); extent_z = XtVaCreateManagedWidget("label_z", xmLabelGadgetClass, form, XmNleftAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, extent_y, NULL); string = XmStringCreateSimple("Enter the object scaling factor:"); prompt = XtVaCreateManagedWidget("label_z", xmLabelGadgetClass, form, XmNlabelString, string, XmNleftAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, extent_z, NULL); XmStringFree(string); rescale_field = XtVaCreateManagedWidget("rescale_field", xmTextFieldWidgetClass, form, XmNleftAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, prompt, XmNcolumns, 32, NULL); XtManageChild (form); return dialog; } static void InitializeCursors() { unsigned long fg = 1, bg = 0; XColor colors[2]; Drawable d; Display *dpy; Pixmap source, mask; Colormap cmap; dpy = XtDisplay (twindow); d = RootWindow(dpy, DefaultScreen(dpy)); XtVaGetValues (twindow, XmNcolormap, &cmap, NULL); cursors[CURSOR_POINT] = XCreateFontCursor (dpy, XC_left_ptr); source = XCreatePixmapFromBitmapData (dpy, d, curs_poly_bits, curs_poly_width, curs_poly_height, fg, bg, 1); mask = XCreatePixmapFromBitmapData (dpy, d, curs_poly_mask_bits, curs_poly_width, curs_poly_height, fg, bg, 1); colors[0].pixel = app_data.cursor_foreground; colors[1].pixel = app_data.cursor_background; XQueryColors (dpy, cmap, colors, 2); cursors[CURSOR_POLY] = XCreatePixmapCursor (dpy, source, mask, &colors[0], &colors[1], curs_poly_x_hot, curs_poly_y_hot); XFreePixmap (dpy, source); XFreePixmap (dpy, mask); source = XCreatePixmapFromBitmapData (dpy, d, curs_marker_bits, curs_marker_width, curs_marker_height, fg, bg, 1); mask = XCreatePixmapFromBitmapData (dpy, d, curs_marker_mask_bits, curs_marker_width, curs_marker_height, fg, bg, 1); cursors[CURSOR_MARKER] = XCreatePixmapCursor (dpy, source, mask, &colors[0], &colors[1], curs_marker_x_hot, curs_marker_y_hot); XFreePixmap (dpy, source); XFreePixmap (dpy, mask); cursors[CURSOR_ORIGIN] = XCreateFontCursor (dpy, XC_crosshair); } static void QuitCB (w, client_data, call_data) Widget w; caddr_t client_data; caddr_t call_data; { exit (0); } static void HelpCB (w, client_data, call_data) Widget w; caddr_t client_data; caddr_t call_data; { XtManageChild (help_box); } static void ButtonCB (w, client_data, call_data) Widget w; caddr_t client_data; caddr_t call_data; { switch ( shared_PtrToInt(client_data) ) { case 0: edit_state = STATE_POINT; SetCursor (CURSOR_POINT); break; case 1: break; case 2: edit_state = STATE_POLYGON; SetCursor (CURSOR_POLY); break; case 3: edit_state = STATE_CIRCLE; SetCursor (CURSOR_CIRCLE); break; case 4: edit_state = STATE_MOVE_ORIGIN; SetCursor (CURSOR_ORIGIN); break; case 5: RescaleView(twindow, 1 / 1.2); XmProcessTraversal (button_list[0].widget, XmTRAVERSE_CURRENT); edit_state = STATE_POINT; SetCursor (CURSOR_POINT); break; case 6: RescaleView(twindow, 1.2); XmProcessTraversal (button_list[0].widget, XmTRAVERSE_CURRENT); edit_state = STATE_POINT; SetCursor (CURSOR_POINT); break; default: printf ("button %d\n", shared_PtrToInt(client_data)); } } static void FileCB (w, client_data, call_data) Widget w; caddr_t client_data; caddr_t call_data; { register int menu_id = shared_PtrToInt(client_data), i; register XmSelectionBoxCallbackStruct *p = (XmSelectionBoxCallbackStruct *) call_data; char *value; Boolean state; XmStringGetLtoR (p->value, charset, &value); switch (menu_id) { case MENU_OPEN: ReadGeditFile (value); break; case MENU_SAVE_AS: for (i=0; i < 3; ++i) { XtVaGetValues (save_formats[i], XmNset, &state, NULL); if (state) { switch (i) { case 0: WriteGeditFile (value); break; case 1: WriteVFile (value); break; } break; } } break; } strcpy (filename, value); filename_valid = True; XtFree (value); } static void AllocPixmap (w, width, height) Widget w; Dimension width, height; { Pixel bg; view_info_t *p; Display *d; int depth; d = XtDisplay (w); XtVaGetValues (w, XmNbackground, &bg, XmNuserData, &p, XmNdepth, &depth, NULL); if (p->flags & VI_PIXMAP_ALLOCATED) XFreePixmap (d, p->pixmap); p->pixmap = XCreatePixmap (d, RootWindow (d, DefaultScreen(d)), width, height, depth); XSetForeground (d, p->erase_gc, bg); XSetLineAttributes (d, p->erase_gc, app_data.selection_thickness, LineSolid, CapButt, JoinMiter); XFillRectangle (d, p->pixmap, p->erase_gc, 0, 0, width, height); p->width = width; p->height = height; p->flags |= VI_PIXMAP_ALLOCATED; } static void WindowCB (w, client_data, call_data) Widget w; caddr_t client_data; caddr_t call_data; { register XmDrawingAreaCallbackStruct *q; view_info_t *p; q = (XmDrawingAreaCallbackStruct *) call_data; XtVaGetValues (w, XmNuserData, &p, NULL); switch (q->reason) { case XmCR_EXPOSE: if ((p->flags & VI_PIXMAP_ALLOCATED) == 0) { XtVaGetValues (w, XmNwidth, &p->width, XmNheight, &p->height, NULL); AllocPixmap (w, p->width, p->height); } XCopyArea (XtDisplay(w), p->pixmap, XtWindow(w), p->gc, 0, 0, p->width, p->height, 0, 0); break; case XmCR_RESIZE: XtVaGetValues (w, XmNwidth, &p->width, XmNheight, &p->height, NULL); AllocPixmap (w, p->width, p->height); p->origin_x = (p->width + 1) / 2; p->origin_y = (p->height + 1) / 2; DrawWidget (w, False); break; } } static char *markers[] = { "Pilot's Head Location", "Nose/Tail Gear Ground Contact Point", "Main Gear Ground Contact Point", "Tail Ground Contact Point", NULL }; static void CreateMarkerList(Widget parent) { register char **p; register int count = 0, i, n; XmString string; Widget item, menu, cascade; Arg args[4]; char s[32]; for (p=markers; *p; ++p) { ++count; } marker_count = count; n = 0; menu = XmCreatePulldownMenu (parent, "marker_menu", args, n); marker_list = (marker_t *) XtMalloc (count * sizeof(marker_t)); for (i=0; ifid; t_info.gc = XCreateGC (display, RootWindow(display, DefaultScreen(display)), GCGraphicsExposures | GCFont, &gcv); t_info.erase_gc = XCreateGC (display, RootWindow(display, DefaultScreen(display)), GCGraphicsExposures, &gcv); t_info.grid_gc = XCreateGC (display, RootWindow(display, DefaultScreen(display)), GCGraphicsExposures | GCLineStyle, &gcv); XSetDashes (display, t_info.grid_gc, 0, grid_dash_list, 2); XtVaSetValues (twindow, XmNuserData, &t_info, NULL); display = XtDisplay (twindow); b_info.flags = 0; b_info.other_view = &t_info; b_info.layout = VL_NXNY; b_info.other_widget = twindow; b_info.other_window = XtWindow (twindow); b_info.gc = XCreateGC (display, RootWindow(display, DefaultScreen(display)), GCGraphicsExposures | GCFont, &gcv); b_info.erase_gc = XCreateGC (display, RootWindow(display, DefaultScreen(display)), GCGraphicsExposures, &gcv); b_info.grid_gc = XCreateGC (display, RootWindow(display, DefaultScreen(display)), GCGraphicsExposures | GCLineStyle, &gcv); XSetDashes (display, b_info.grid_gc, 0, grid_dash_list, 2); XtVaSetValues (bwindow, XmNuserData, &b_info, NULL); help_box = CreateHelp (toplevel); edit_state = STATE_POINT; cur_polygon = (polygon_t *) NULL; polygon_max = 256; polygon_list = (polygon_t *) memory_allocate(polygon_max * sizeof (polygon_t), NULL); sel_polygon = unsel_polygon = clipboard_polygon = -1; drag_mode = False; for (i=0; i #include #include #include #include #include #include "../util/memory.h" #include "shared.h" #include "edit.h" #include "gutil1.h" #define gutil_IMPORT #include "gutil.h" /* * Once we have three points entered, we can compute the equation associated * with the plane defined by them. The general equation looks like this: * * a x + b y + c z + d = 0 * * Where the normal vector is N=[a, b, c] and d = - a x0 - b y0 - c z0; * the origin is O=[x0, y0, z0]. * * Once the plane equation is computed, it's a trivial task to determine * the xyz coordinates of any subsequent points entered for this polygon * -- since all points on the polygon are, by our definition, coplanar. */ #define magv(v) sqrt( v.x * v.x + v.y * v.y + v.z * v.z ) void ComputePlaneEquation (polygon_t *p) { VPoint a, b; register double length; VSetPoint (&a, p->point[0].point.x - p->point[1].point.x, p->point[0].point.y - p->point[1].point.y, p->point[0].point.z - p->point[1].point.z); VSetPoint (&b, p->point[2].point.x - p->point[1].point.x, p->point[2].point.y - p->point[1].point.y, p->point[2].point.z - p->point[1].point.z); VCrossProd (&a, &b, &(p->normal)); length = magv(p->normal); p->normal.x /= length; p->normal.y /= length; p->normal.z /= length; p->d = - VDotProd (&p->normal, &p->point[1].point); p->origin = p->point[1].point; } void DisplayPoint(point_t *p) { char value[64]; sprintf (value, "%d", p->x); XmTextFieldSetString (x_field, value); sprintf (value, "%d", p->y); XmTextFieldSetString (y_field, value); sprintf (value, "%d", p->z); XmTextFieldSetString (z_field, value); } polygon_t * AllocPolygon () { register int i, n; register polygon_t *tmp; for (i=0; i < polygon_max; ++i) { if (polygon_list[i].num_points == 0) { polygon_list[i].next = -1; return &polygon_list[i]; } } n = polygon_max * 2; tmp = (polygon_t *) memory_allocate (n * sizeof (polygon_t), NULL); bcopy ((char *) polygon_list, (char *) tmp, polygon_max * sizeof (polygon_t)); for (i = polygon_max; i < n; ++i) { tmp[i].next = tmp[i].num_points = 0; tmp[i].id = i; } polygon_max = n; memory_dispose ((char *) polygon_list); polygon_list = tmp; return tmp; } void FreePolygon (polygon_t *p) { p->num_points = 0; if (p->point != tmp_point) memory_dispose ((char *) p->point); } polygon_t * BeginPolygon () { register polygon_t *p; if ((p = AllocPolygon()) == (polygon_t *) NULL) { fprintf (stderr, "out of memory\n"); exit (1); } p->num_points = 0; p->point = tmp_point; cur_polygon = p; return p; } void PointXY (Widget w, view_info_t *p, int x, int y, point_t *q) { switch (p->layout) { case VL_NXZ: q->x = x; q->y = p->other_view->origin_y; q->z = y; q->point.x = - (x - p->origin_x) * pixel_scale; q->point.y = 0.0; q->point.z = (y - p->origin_y) * pixel_scale; break; case VL_NXNY: q->x = x; q->y = y; q->z = p->other_view->origin_y; q->point.x = - (x - p->origin_x) * pixel_scale; q->point.y = - (y - p->origin_y) * pixel_scale; q->point.z = 0.0; break; case VL_NYZ: q->x = p->other_view->origin_y; q->y = x; q->z = y; q->point.x = 0.0; q->point.y = - (x - p->origin_x) * pixel_scale; q->point.z = (y - p->origin_y) * pixel_scale; break; case VL_NYX: q->x = y; q->y = x; q->z = p->other_view->origin_y; q->point.x = (y - p->origin_y) * pixel_scale; q->point.y = -(x - p->origin_x) * pixel_scale; q->point.z = 0.0; break; default: printf ("oops\n"); } } int PinPoint (Widget w, view_info_t *p, polygon_t *poly, int x, int y, XPoint *pt, XPoint *opt) { point_t *q, *oq; int z; Boolean plane_established; if (poly->num_points == 0) oq = (point_t *) NULL; else oq = &poly->point[poly->num_points-1]; q = &poly->point[poly->num_points++]; plane_established = (poly->num_points > 3) ? True : False; switch (p->layout) { case VL_NXZ: if (oq != (point_t *) NULL) { pt->x = opt->x = oq->x; pt->y = oq->z; opt->y = oq->y; q->y = oq->y; } else { q->y = p->other_view->origin_y; } q->x = x; q->z = y; z = q->y; q->point.x = - (x - p->origin_x) * pixel_scale; q->point.z = (y - p->origin_y) * pixel_scale; switch (p->other_view->layout) { case VL_NXNY: if (plane_established) { q->point.y = - (poly->normal.x * q->point.x + poly->normal.z * q->point.z + poly->d) / poly->normal.y; z = q->y = - q->point.y / pixel_scale + p->other_view->origin_y; } else q->point.y = - (q->y - p->other_view->origin_y)* pixel_scale; break; case VL_NXY: if (plane_established) { q->point.y = - (poly->normal.x * q->point.x + poly->normal.z * q->point.z + poly->d) / poly->normal.y; z = q->y = q->point.y / pixel_scale + p->other_view->origin_y; } else q->point.y = (q->y - p->other_view->origin_y) * pixel_scale; break; } break; case VL_NXNY: if (oq != (point_t *) NULL) { pt->x = opt->x = oq->x; pt->y = oq->y; opt->y = oq->z; q->z = oq->z; } else { q->z = p->other_view->origin_y; } q->x = x; q->y = y; z = q->z; q->point.x = - (x - p->origin_x) * pixel_scale; q->point.y = - (y - p->origin_y) * pixel_scale; switch (p->other_view->layout) { case VL_NXNZ: if (plane_established) { q->point.z = - (poly->normal.x * q->point.x + poly->normal.y * q->point.y + poly->d) / poly->normal.z; z = q->z = q->point.z / pixel_scale + p->other_view->origin_y; } else q->point.z = - (q->z - p->other_view->origin_y)* pixel_scale; break; case VL_NXZ: if (plane_established) { q->point.z = - (poly->normal.x * q->point.x + poly->normal.y * q->point.y + poly->d) / poly->normal.z; z = q->z = q->point.z / pixel_scale + p->other_view->origin_y; } else q->point.z = (q->z - p->other_view->origin_y) * pixel_scale; break; } break; case VL_NYZ: if (oq != (point_t *) NULL) { pt->x = opt->x = oq->y; pt->y = oq->z; opt->y = oq->x; q->x = oq->x; } else { q->x = p->other_view->origin_y; } q->y = x; q->z = y; z = q->x; q->point.y = - (x - p->origin_x) * pixel_scale; q->point.z = (y - p->origin_y) * pixel_scale; switch (p->other_view->layout) { case VL_NYX: if (plane_established) { q->point.x = - (poly->normal.y * q->point.y + poly->normal.z * q->point.z + poly->d) / poly->normal.x; z = q->x = q->point.x / pixel_scale + p->other_view->origin_y; } else q->point.x = (q->x - p->other_view->origin_y) * pixel_scale; break; case VL_NYNX: if (plane_established) { q->point.x = - (poly->normal.y * q->point.y + poly->normal.z * q->point.z + poly->d) / poly->normal.x; z = q->x = - q->point.x / pixel_scale + p->other_view->origin_y; } else q->point.x = -(q->x - p->other_view->origin_y)* pixel_scale; break; } break; case VL_NYX: if (oq != (point_t *) NULL) { pt->x = opt->x = oq->y; pt->y = oq->x; opt->y = oq->z; q->z = oq->z; } else { q->z = p->other_view->origin_y; } q->x = y; q->y = x; z = q->z; q->point.x = - (y - p->origin_x) * pixel_scale; q->point.y = (x - p->origin_y) * pixel_scale; switch (p->other_view->layout) { case VL_NYZ: if (plane_established) { q->point.z = - (poly->normal.x * q->point.x + poly->normal.y * q->point.y + poly->d) / poly->normal.z; z = q->z = q->point.z / pixel_scale + p->other_view->origin_y; } else q->point.z = (q->z - p->other_view->origin_y)* pixel_scale; break; case VL_NYNZ: if (plane_established) { q->point.z = - (poly->normal.x * q->point.x + poly->normal.y * q->point.y + poly->d) / poly->normal.z; z = q->z = - q->point.z / pixel_scale + p->other_view->origin_y; } else q->point.z = - (q->z - p->other_view->origin_y)* pixel_scale; break; } break; } DisplayPoint (q); return z; } int DragPoint (Widget w, view_info_t *p, polygon_t *poly, int delta, XPoint *pt, XPoint *opt) { point_t *q, *oq; int z; if (poly->num_points == 1) oq = (point_t *) NULL; else oq = &poly->point[poly->num_points-2]; q = &poly->point[poly->num_points-1]; switch (p->layout) { case VL_NXZ: if (oq != (point_t *) NULL) { pt->x = opt->x = oq->x; pt->y = oq->z; opt->y = oq->y; } switch (p->other_view->layout) { case VL_NXNY: q->y = drag_origin.y + delta; q->point.y = - (q->y - p->other_view->origin_y) * pixel_scale; break; case VL_NXY: q->y = drag_origin.y + delta; q->point.y = (q->y - p->other_view->origin_y) * pixel_scale; break; } z = q->y; break; case VL_NXNY: if (oq != (point_t *) NULL) { pt->x = opt->x = oq->x; pt->y = oq->y; opt->y = oq->z; } switch (p->other_view->layout) { case VL_NXNZ: q->z = drag_origin.y + delta; q->point.z = - (q->z - p->other_view->origin_y) * pixel_scale; break; case VL_NXZ: q->z = drag_origin.y + delta; q->point.z = (q->z - p->other_view->origin_y) * pixel_scale; break; } z = q->z; break; case VL_NYX: if (oq != (point_t *) NULL) { pt->x = opt->x = oq->y; pt->y = oq->x; opt->y = oq->z; } switch (p->other_view->layout) { case VL_NYNZ: q->z = drag_origin.y + delta; q->point.z = - (q->z - p->other_view->origin_y) * pixel_scale; break; case VL_NYZ: q->z = drag_origin.y + delta; q->point.x = (q->z - p->other_view->origin_y) * pixel_scale; break; } z = q->z; break; case VL_NYZ: if (oq != (point_t *) NULL) { pt->x = opt->x = oq->y; pt->y = oq->z; opt->y = oq->x; } switch (p->other_view->layout) { case VL_NYNX: q->x = drag_origin.y + delta; q->point.x = - (q->x - p->other_view->origin_y) * pixel_scale; break; case VL_NYX: q->x = drag_origin.y + delta; q->point.x = (q->x - p->other_view->origin_y) * pixel_scale; break; } z = q->x; break; } DisplayPoint (q); return z; } void BeginPolygonPoint (Widget w, view_info_t *p, int x, int y) { int z; Display *dpy; Drawable w1, w2; XPoint last, last_other; polygon_t *poly; dpy = XtDisplay (w); w1 = XtWindow (w); w2 = XtWindow (p->other_widget); if (cur_polygon == NULL) BeginPolygon (); poly = cur_polygon; drag_origin.x = x; drag_origin.y = y; XSetFunction (dpy, p->gc, GXxor); XSetForeground (dpy, p->gc, app_data.select_pixel); XSetLineAttributes (dpy, p->gc, app_data.selection_thickness, LineSolid, CapButt, JoinMiter); XFillRectangle (dpy, w1, p->gc, x + app_data.box_offset, y + app_data.box_offset, app_data.box_size, app_data.box_size); z = PinPoint (w, p, poly, x, y, &last, &last_other); XFillRectangle (dpy, w2, p->gc, x + app_data.box_offset, z + app_data.box_offset, app_data.box_size, app_data.box_size); if (poly->num_points > 1) { XDrawLine (dpy, w1, p->gc, last.x, last.y, x, y); XDrawLine (dpy, w2, p->gc, last_other.x, last_other.y, x, z); rubber_lines[0].x1 = last.x; rubber_lines[0].y1 = last.y; rubber_lines[0].x2 = x; rubber_lines[0].y2 = y; rubber_lines[1].x1 = last_other.x; rubber_lines[1].y1 = last_other.y; } rubber_lines[1].x2 = x; rubber_lines[1].y2 = z; XSetFunction (dpy, p->gc, GXcopy); } void DragPolygonPoint(Widget w, view_info_t *p, int x, int y) { int z, nx, delta; Display *dpy; //Drawable w1; Drawable w2; XPoint last, last_other; polygon_t *poly; dpy = XtDisplay (w); //w1 = XtWindow (w); w2 = XtWindow (p->other_widget); poly = cur_polygon; /* * We don't drag points once the polygon's plane is determined. */ if (poly->num_points > 3) return; /* * Erase old stuff */ XSetFunction (dpy, p->other_view->gc, GXxor); XFillRectangle (dpy, w2, p->other_view->gc, rubber_lines[1].x2 + app_data.box_offset, rubber_lines[1].y2 + app_data.box_offset, app_data.box_size, app_data.box_size); if (poly->num_points > 1) { XDrawSegments (dpy, w2, p->other_view->gc, &rubber_lines[1], 1); } /* * Draw new line/point */ delta = y - drag_origin.y; nx = rubber_lines[1].x2; z = DragPoint (w, p, poly, delta, &last, &last_other); XFillRectangle (dpy, w2, p->other_view->gc, nx + app_data.box_offset, z + app_data.box_offset, app_data.box_size, app_data.box_size); if (poly->num_points > 1) { XDrawLine (dpy, w2, p->other_view->gc, last_other.x, last_other.y, nx, z); } rubber_lines[1].y2 = z; XSetFunction (dpy, p->other_view->gc, GXcopy); } void CompletePolygonPoint(Widget w, view_info_t *p, int x, int y) { if (cur_polygon) if (cur_polygon->num_points == 3) ComputePlaneEquation (cur_polygon); } void CompletePolygon (Widget w, polygon_t *p) { register point_t *points; view_info_t *q; XtVaGetValues (w, XmNuserData, &q, NULL); if (p == (polygon_t *) NULL) return; if (p->num_points < 3) { p->num_points = 0; return; } points = (point_t *) memory_allocate (p->num_points * sizeof(point_t), NULL); bcopy ((char *) tmp_point, (char *) points, p->num_points * sizeof (point_t)); p->point = points; /* * Add this polygon to the selected list. */ p->next = sel_polygon; sel_polygon = p->id; cur_polygon = (polygon_t *) NULL; #ifdef notdef DrawPolygon (w, p, True); DrawPolygon (q->other_widget, p, True); #endif DrawWidget (w, False); DrawWidget (q->other_widget, False); } int PolygonProximity (view_info_t *p, polygon_t *poly, int x, int y) { register long i, min_distance, d; int xp, yp; min_distance = 0x3fffffff; for (i=0; i < poly->num_points; ++ i) { WorldToWidget (p, &poly->point[i], &xp, &yp); xp -= x; yp -= y; d = (int) sqrt ((double) (xp * xp + yp * yp)); if (d < min_distance) { min_distance = d; } } return min_distance; } int PickObject (view_info_t *p, int x, int y) { register int i, dist, d, id = -1; dist = 0x3fffffff; for (i=0; i < polygon_max; ++i) { if (polygon_list[i].num_points == 0) continue; if ((d = PolygonProximity (p, &polygon_list[i], x, y)) < dist) { dist = d; id = i; } } if (dist < app_data.pick_sensitivity) return id; else return -1; } void CompleteMarker(Widget w, view_info_t *p, int x, int y) { if (cur_polygon) { marker_list[current_marker].defined = True; marker_list[current_marker].location = cur_polygon->point[0]; cur_polygon = NULL; DrawWidget (w, False); DrawWidget (p->other_widget, False); } } void BeginPick (Widget w, view_info_t *p, int x, int y, Boolean extend) { register int id, last, i; id = PickObject (p, x, y); if (extend) { if (id >= 0) { SelectObject (id); } } else { if (id == -1) { if (sel_polygon >= 0) { for (i=sel_polygon; i >= 0; i = polygon_list[i].next) last = i; polygon_list[last].next = unsel_polygon; unsel_polygon = sel_polygon; sel_polygon = -1; } } else if (sel_polygon >= 0) { drag_origin.x = x; drag_origin.y = y; drag_mode = True; } else { SelectObject (id); } } DrawWidget (w, False); DrawWidget (p->other_widget, False); } void DragSelection (Widget w, view_info_t *p, int x, int y) { register int dx, dy, i, j; point_t q; polygon_t *poly; dx = x - drag_origin.x + p->origin_x; dy = y - drag_origin.y + p->origin_y; drag_origin.x = x; drag_origin.y = y; PointXY (w, p, dx, dy, &q); for (i=sel_polygon; i >= 0; i = polygon_list[i].next) DrawSelectedPolygon (w, &polygon_list[i], True, True); for (i=sel_polygon; i >= 0; i = polygon_list[i].next) { poly = &polygon_list[i]; for (j=0; jnum_points; ++j) { poly->point[j].point.x += q.point.x; poly->point[j].point.y += q.point.y; poly->point[j].point.z += q.point.z; PointToXYZ (p, &poly->point[j]); } DrawSelectedPolygon (w, poly, True, False); } } void CompleteDrag (Widget w, view_info_t *p, int x, int y) { drag_mode = False; DrawWidget (w, False); DrawWidget (p->other_widget, False); } void SelectObject (int id) { register int i, last; if (unsel_polygon == -1) { polygon_list[id].next = sel_polygon; sel_polygon = id; return; } if (unsel_polygon == id) { unsel_polygon = polygon_list[id].next; polygon_list[id].next = sel_polygon; sel_polygon = id; return; } last = unsel_polygon; for (i=polygon_list[unsel_polygon].next; i >= 0; i = polygon_list[i].next) { if (i == id) { polygon_list[last].next = polygon_list[id].next; polygon_list[id].next = sel_polygon; sel_polygon = id; return; } last = i; } } void DetermineObjectExtent (VPoint *extent) { VPoint min, max; register int i, j; polygon_t *poly; min.x = min.y = min.z = 10000000.0; max.x = max.y = max.z = -10000000.0; for (i=0; i < polygon_max; ++i) { if (polygon_list[i].num_points == 0) continue; poly = &polygon_list[i]; for (j=0; jnum_points; ++j) { if (poly->point[j].point.x > max.x) max.x = poly->point[j].point.x; if (poly->point[j].point.y > max.y) max.y = poly->point[j].point.y; if (poly->point[j].point.z > max.z) max.z = poly->point[j].point.z; if (poly->point[j].point.x < min.x) min.x = poly->point[j].point.x; if (poly->point[j].point.y < min.y) min.y = poly->point[j].point.y; if (poly->point[j].point.z < min.z) min.z = poly->point[j].point.z; } } extent->x = max.x - min.x; extent->y = max.y - min.y; extent->z = max.z - min.z; } void RescaleObject (double factor) { register int i, j; polygon_t *poly; for (i=0; i < polygon_max; ++i) { if (polygon_list[i].num_points == 0) continue; poly = &polygon_list[i]; for (j=0; jnum_points; ++j) { poly->point[j].point.x *= factor; poly->point[j].point.y *= factor; poly->point[j].point.z *= factor; } } for (i=0; i < marker_count; ++i) { if (marker_list[i].defined) { marker_list[i].location.point.x *= factor; marker_list[i].location.point.y *= factor; marker_list[i].location.point.z *= factor; } } RescaleView (twindow, 1.0); } acm-6.0_20200416/src/gedit/xbm/0000755000000000000000000000000013175062144014247 5ustar rootrootacm-6.0_20200416/src/gedit/xbm/origin_32.xbm0000644000000000000000000000157210357223037016556 0ustar rootroot#define origin_32_width 32 #define origin_32_height 32 static char origin_32_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00, 0x10, 0x00, 0x03, 0x00, 0x08, 0x00, 0x03, 0x00, 0x10, 0x00, 0x03, 0x00, 0x08, 0x00, 0x03, 0x00, 0x10, 0x00, 0x03, 0x00, 0x08, 0x00, 0x03, 0x00, 0x10, 0x00, 0x03, 0x00, 0x08, 0x00, 0x03, 0x00, 0x10, 0x00, 0x03, 0x00, 0x08, 0x00, 0x03, 0x55, 0x55, 0x55, 0x17, 0xaa, 0xaa, 0xaa, 0x0b, 0x00, 0x10, 0x00, 0x03, 0x00, 0x48, 0x00, 0x03, 0x00, 0x90, 0x01, 0x03, 0x00, 0x08, 0x22, 0x03, 0x00, 0x10, 0x3c, 0x03, 0x00, 0x08, 0x70, 0x03, 0x00, 0x10, 0x78, 0x03, 0x00, 0x08, 0x00, 0x03, 0xe0, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0x00, 0x10, 0x00, 0x03, 0x00, 0x08, 0x00, 0x03, 0x00, 0x10, 0x00, 0x03, 0x00, 0x08, 0x00, 0x03, 0x00, 0x10, 0x00, 0x03, 0x00, 0x08, 0x00, 0x03, 0x00, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00}; acm-6.0_20200416/src/gedit/xbm/zoom_out_64.xbm0000644000000000000000000000632710357223037017152 0ustar rootroot#define zoom_out_width 64 #define zoom_out_height 64 static char zoom_out_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; acm-6.0_20200416/src/gedit/xbm/polygon_32.xbm0000644000000000000000000000157510357223037016761 0ustar rootroot#define polygon_32_width 32 #define polygon_32_height 32 static char polygon_32_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x38, 0xe0, 0x00, 0x00, 0x38, 0xe0, 0x00, 0x00, 0x3c, 0x40, 0x03, 0x00, 0x12, 0x40, 0x04, 0x80, 0x11, 0x40, 0x08, 0x40, 0x10, 0x20, 0x10, 0x30, 0x10, 0x20, 0x60, 0x08, 0x20, 0x20, 0x80, 0x07, 0x20, 0x20, 0x80, 0x03, 0x20, 0x20, 0x80, 0x03, 0x20, 0x20, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x20, 0x38, 0x00, 0x00, 0x40, 0xf8, 0x00, 0x00, 0x40, 0x38, 0x3f, 0x00, 0x40, 0x00, 0xc0, 0x1f, 0x40, 0x00, 0x00, 0xe0, 0xe7, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; acm-6.0_20200416/src/gedit/xbm/circle_64.xbm0000644000000000000000000000632410357223037016535 0ustar rootroot#define polygon_width 64 #define polygon_height 64 static char polygon_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xe3, 0xe3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x30, 0xe0, 0x03, 0x06, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x30, 0xe0, 0x03, 0x06, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xe3, 0xe3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00}; acm-6.0_20200416/src/gedit/xbm/marker.xbm0000644000000000000000000000632110357223037016241 0ustar rootroot#define marker_width 64 #define marker_height 64 static char marker_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff, 0x07, 0xc0, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; acm-6.0_20200416/src/gedit/xbm/curs_poly_mask.xbm0000644000000000000000000000171110357223037020010 0ustar rootroot#define curs_poly_mask_width 32 #define curs_poly_mask_height 32 #define curs_poly_mask_x_hot 15 #define curs_poly_mask_y_hot 15 static char curs_poly_mask_bits[] = { 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0xff, 0x3f, 0xfe, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00}; acm-6.0_20200416/src/gedit/xbm/hand_32.xbm0000644000000000000000000000156410357223037016202 0ustar rootroot#define hand_32_width 32 #define hand_32_height 32 static char hand_32_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0x80, 0x00, 0xd0, 0x00, 0xa0, 0x01, 0x50, 0x00, 0xf0, 0x00, 0x30, 0x00, 0xd8, 0x00, 0x6e, 0x00, 0x70, 0x00, 0x7f, 0x00, 0x7c, 0x80, 0x3f, 0x00, 0x6a, 0xc0, 0x1f, 0x00, 0x27, 0x60, 0x0e, 0x00, 0x33, 0xf0, 0x01, 0x80, 0x1f, 0x38, 0x03, 0x00, 0x11, 0xfa, 0xc0, 0xc0, 0x8f, 0x06, 0xd0, 0x00, 0x98, 0x3b, 0x1e, 0x40, 0x70, 0xfc, 0x4b, 0x20, 0x07, 0xe8, 0xe6, 0xa0, 0xf9, 0x7f, 0xfa, 0x60, 0xc0, 0xfe, 0xff, 0x70, 0x03, 0xa4, 0xaf, 0xf0, 0x3f, 0xde, 0x67, 0xf0, 0x08, 0xbe, 0x7f, 0x30, 0x86, 0xff, 0x7f, 0x38, 0x0d, 0x20, 0x19, 0xf8, 0xee, 0xf8, 0x07, 0xf8, 0x00, 0xec, 0x07, 0x5c, 0x80, 0x74, 0x02, 0xfc, 0x7f, 0x8e, 0x01, 0x9c, 0x7f, 0x0c, 0x01, 0x7a, 0x80, 0x07, 0x00, 0x06, 0x87, 0x7f, 0x00, 0xed, 0xb0, 0x0d, 0x00}; acm-6.0_20200416/src/gedit/xbm/curs_reshape_mask.xbm0000644000000000000000000000173010357223037020455 0ustar rootroot#define curs_reshape_mask_width 32 #define curs_reshape_mask_height 32 #define curs_reshape_mask_x_hot 15 #define curs_reshape_mask_y_hot 15 static char curs_reshape_mask_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x04, 0x38, 0x00, 0x00, 0x0e, 0x70, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x80, 0x03, 0xc0, 0x01, 0xc0, 0x01, 0x80, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, 0x0e, 0x38, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x0e, 0x38, 0x00, 0x00, 0x07, 0x70, 0x00, 0x80, 0x03, 0xe0, 0x00, 0xc0, 0x01, 0xc0, 0x01, 0xe0, 0x00, 0x80, 0x03, 0x70, 0x00, 0x00, 0x07, 0x38, 0x00, 0x00, 0x0e, 0x10, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; acm-6.0_20200416/src/gedit/xbm/curs_marker.xbm0000644000000000000000000000167210357223037017301 0ustar rootroot#define curs_marker_width 32 #define curs_marker_height 32 #define curs_marker_x_hot 15 #define curs_marker_y_hot 15 static char curs_marker_bits[] = { 0x00, 0xc0, 0x01, 0x00, 0x00, 0xfc, 0x1e, 0x00, 0x00, 0xab, 0x60, 0x00, 0xc0, 0xd5, 0x80, 0x01, 0xa0, 0xaa, 0x00, 0x02, 0x50, 0xd5, 0x00, 0x04, 0xa8, 0xaa, 0x00, 0x08, 0x58, 0xd5, 0x00, 0x08, 0xac, 0xaa, 0x00, 0x10, 0x54, 0xd5, 0x00, 0x10, 0xaa, 0xaa, 0x00, 0x20, 0x56, 0xd5, 0x00, 0x20, 0xaa, 0xaa, 0x02, 0x20, 0x56, 0x15, 0x04, 0x20, 0xab, 0x0a, 0x00, 0x40, 0xff, 0x9f, 0xfc, 0x7f, 0x01, 0x00, 0xa8, 0x6a, 0x02, 0x10, 0x54, 0x35, 0x02, 0xa0, 0xaa, 0x2a, 0x02, 0x80, 0x55, 0x35, 0x02, 0x80, 0xaa, 0x2a, 0x04, 0x80, 0x55, 0x15, 0x04, 0x80, 0xaa, 0x1a, 0x08, 0x80, 0x55, 0x0d, 0x08, 0x80, 0xaa, 0x0a, 0x10, 0x80, 0x55, 0x05, 0x20, 0x80, 0xaa, 0x02, 0xc0, 0x80, 0xd5, 0x01, 0x00, 0x83, 0x6a, 0x00, 0x00, 0xbc, 0x1f, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; acm-6.0_20200416/src/gedit/xbm/curs_poly.xbm0000644000000000000000000000166010357223037017000 0ustar rootroot#define curs_poly_width 32 #define curs_poly_height 32 #define curs_poly_x_hot 15 #define curs_poly_y_hot 15 static char curs_poly_bits[] = { 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x1f, 0xfc, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00}; acm-6.0_20200416/src/gedit/xbm/curs_reshape.xbm0000644000000000000000000000167710357223037017454 0ustar rootroot#define curs_reshape_width 32 #define curs_reshape_height 32 #define curs_reshape_x_hot 15 #define curs_reshape_y_hot 15 static char curs_reshape_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x04, 0x20, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x01, 0x80, 0x00, 0x80, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x01, 0x40, 0x00, 0x80, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; acm-6.0_20200416/src/gedit/xbm/hand_64.xbm0000644000000000000000000000631310357223037016204 0ustar rootroot#define hand_width 64 #define hand_height 64 static char hand_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x78, 0x01, 0x00, 0x80, 0xae, 0x00, 0x00, 0x00, 0xec, 0x01, 0x00, 0x80, 0xbb, 0x00, 0x00, 0x00, 0x75, 0x01, 0x00, 0xe0, 0x66, 0x00, 0x00, 0x00, 0xd7, 0x00, 0x00, 0xa0, 0xad, 0x00, 0x00, 0x80, 0xed, 0x01, 0x00, 0x78, 0xeb, 0x00, 0x00, 0xc0, 0x5b, 0x00, 0x00, 0xd4, 0x36, 0x00, 0x00, 0xc0, 0xf6, 0x00, 0x00, 0xbe, 0x2d, 0x00, 0x00, 0xa0, 0xb5, 0x00, 0x00, 0x57, 0x15, 0x00, 0x00, 0xe0, 0x6a, 0x00, 0x00, 0xab, 0x07, 0x00, 0x00, 0xd8, 0x35, 0x00, 0xc0, 0x5d, 0x05, 0x00, 0x00, 0x3c, 0x5d, 0x00, 0xc0, 0xea, 0x02, 0x00, 0x00, 0xec, 0x36, 0x00, 0x70, 0x57, 0x01, 0x00, 0x00, 0x96, 0x1a, 0x00, 0xa8, 0x75, 0x00, 0x00, 0x00, 0xbd, 0x0e, 0x00, 0xbe, 0x5e, 0x00, 0x00, 0x00, 0xa7, 0x06, 0x00, 0xaa, 0x15, 0x00, 0x00, 0x00, 0xad, 0x05, 0x80, 0x57, 0x0b, 0x00, 0x00, 0x80, 0x4b, 0x03, 0x40, 0x55, 0x05, 0x00, 0x00, 0x40, 0x55, 0x03, 0x60, 0xad, 0x05, 0x80, 0x00, 0xc0, 0xd5, 0x02, 0xb8, 0x55, 0x01, 0xe0, 0x00, 0xa0, 0xab, 0x01, 0x6c, 0x75, 0x00, 0xf8, 0x00, 0xe0, 0x6a, 0x01, 0xdb, 0x56, 0x00, 0xff, 0x00, 0x50, 0xd5, 0xc0, 0xb6, 0x2a, 0x80, 0x5b, 0x00, 0xf0, 0xfa, 0xa0, 0x5b, 0x0f, 0xf0, 0xfd, 0x00, 0xa8, 0xca, 0x6b, 0x6d, 0x05, 0x5e, 0xab, 0x00, 0xb0, 0x7a, 0xdd, 0xd5, 0x4a, 0xb5, 0x76, 0x00, 0xb8, 0xaa, 0xb7, 0x5a, 0xdf, 0xef, 0xba, 0x00, 0xb4, 0xde, 0x6a, 0xb5, 0x7d, 0x99, 0xed, 0x00, 0xac, 0xb5, 0xaa, 0xea, 0xd6, 0xb6, 0xfe, 0x00, 0xba, 0xaa, 0xb6, 0xdd, 0xaf, 0xd5, 0xbd, 0x00, 0x6c, 0x6b, 0x55, 0x55, 0xb5, 0x6e, 0x77, 0x00, 0xde, 0xaa, 0x6a, 0xbb, 0xab, 0xfa, 0xdd, 0x00, 0xb4, 0xaa, 0xda, 0x56, 0xdd, 0x5f, 0xf7, 0x00, 0x6e, 0x55, 0xad, 0xea, 0xb6, 0xba, 0xba, 0x00, 0xb5, 0xad, 0xaa, 0x9a, 0xee, 0xd7, 0x6e, 0x80, 0x5e, 0xab, 0xd5, 0x6a, 0xb5, 0x5a, 0xdb, 0x00, 0x77, 0x55, 0xad, 0x56, 0xdb, 0xb5, 0x36, 0x80, 0xad, 0xaa, 0x6a, 0xa9, 0xb6, 0xd6, 0x6f, 0x80, 0xdf, 0xea, 0xaa, 0x56, 0x6d, 0xfd, 0x35, 0x80, 0xba, 0xad, 0x56, 0xb5, 0xea, 0x7f, 0x2f, 0x80, 0xaf, 0xb6, 0x6a, 0x55, 0x55, 0xd7, 0x1d, 0x40, 0xfb, 0x6d, 0xd5, 0x56, 0xf5, 0xbd, 0x16, 0xc0, 0xad, 0x5b, 0xaa, 0xaa, 0xae, 0x6b, 0x0b, 0x80, 0x7f, 0x55, 0x55, 0x5b, 0x59, 0xd7, 0x07, 0xc0, 0xd5, 0x56, 0xd4, 0x6a, 0xd7, 0xbd, 0x00, 0x40, 0xbf, 0x4a, 0x55, 0x55, 0xa9, 0xd6, 0x10, 0xc0, 0xd7, 0xaa, 0xaa, 0xda, 0xd6, 0x1d, 0x02, 0xe0, 0xad, 0xaa, 0x56, 0xab, 0x5a, 0x2b, 0x00, 0xf0, 0xbb, 0xaa, 0xea, 0xba, 0xb5, 0x8e, 0x00, 0x50, 0x55, 0x55, 0x55, 0x55, 0xad, 0x15, 0x00, 0xf0, 0x57, 0x55, 0xb5, 0xd6, 0x6a, 0x03, 0x00, 0xb8, 0xac, 0xaa, 0xaa, 0x55, 0xab, 0x86, 0x00, 0x78, 0x6b, 0x55, 0xb5, 0xda, 0xaa, 0x01, 0x00, 0xa8, 0x5a, 0x55, 0x55, 0x57, 0x75, 0x11, 0x00, 0x6c, 0x95, 0xaa, 0x6a, 0xb5, 0xaa, 0x00, 0x00, 0xd4, 0x56, 0x49, 0x55, 0xab, 0x2a, 0x00, 0x00, 0xbc, 0x2a, 0xb5, 0x6a, 0x5d, 0x15, 0x00, 0x00, 0xa6, 0x52, 0x55, 0xd5, 0x56, 0x03, 0x00, 0x00, 0xdb, 0x56, 0x2a, 0x6d, 0xdb, 0x00, 0x00, 0x00, 0xb7, 0xaa, 0xaa, 0xba, 0x05, 0x08, 0x00, 0x00}; acm-6.0_20200416/src/gedit/xbm/cursor_32.xbm0000644000000000000000000000157210357223037016604 0ustar rootroot#define cursor_32_width 32 #define cursor_32_height 32 static char cursor_32_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0xc0, 0xff, 0x03, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0xc0, 0xff, 0x03, 0x00, 0xc0, 0xff, 0x01, 0x00, 0x80, 0x7f, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xeb, 0x03, 0x00, 0x80, 0xf2, 0x07, 0x00, 0x80, 0xc1, 0x0f, 0x00, 0x00, 0xe0, 0x1f, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x40, 0xff, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x80, 0xfe, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; acm-6.0_20200416/src/gedit/xbm/zoom_in_64.xbm0000644000000000000000000000632410357223037016746 0ustar rootroot#define zoom_in_width 64 #define zoom_in_height 64 static char zoom_in_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; acm-6.0_20200416/src/gedit/xbm/zoom_out_32.xbm0000644000000000000000000000160010357223037017132 0ustar rootroot#define zoom_out_32_width 32 #define zoom_out_32_height 32 static char zoom_out_32_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x80, 0xff, 0x3f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; acm-6.0_20200416/src/gedit/xbm/cursor_64.xbm0000644000000000000000000000632110357223037016606 0ustar rootroot#define cursor_width 64 #define cursor_height 64 static char cursor_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xd0, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xd0, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xd0, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0xd0, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x9f, 0xfe, 0x03, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xef, 0xfe, 0x07, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x13, 0xfd, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0c, 0xfd, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0xfa, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0xfa, 0xff, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0xf4, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf4, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x40, 0xfe, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x80, 0xfe, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0xfc, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; acm-6.0_20200416/src/gedit/xbm/origin_64.xbm0000644000000000000000000000632110357223037016560 0ustar rootroot#define origin_width 64 #define origin_height 64 static char origin_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xae, 0x02, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x5f, 0x01, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xae, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x80, 0xf2, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x82, 0x07, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x1c, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x70, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0xe0, 0x10, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x13, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x3f, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x38, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x7e, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x7e, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; acm-6.0_20200416/src/gedit/xbm/curs_marker_mask.xbm0000644000000000000000000000172310357223037020311 0ustar rootroot#define curs_marker_mask_width 32 #define curs_marker_mask_height 32 #define curs_marker_mask_x_hot 15 #define curs_marker_mask_y_hot 15 static char curs_marker_mask_bits[] = { 0x00, 0xc0, 0x01, 0x00, 0x00, 0xfc, 0x1e, 0x00, 0x00, 0xff, 0x60, 0x00, 0xc0, 0xff, 0x80, 0x01, 0xe0, 0xff, 0x00, 0x02, 0xf0, 0xff, 0x00, 0x04, 0xf8, 0xff, 0x00, 0x08, 0xf8, 0xff, 0x00, 0x08, 0xfc, 0xff, 0x00, 0x10, 0xfc, 0xff, 0x00, 0x10, 0xfe, 0xff, 0x00, 0x20, 0xfe, 0xff, 0x00, 0x20, 0xfe, 0xff, 0x02, 0x20, 0xfe, 0x3f, 0x04, 0x20, 0xff, 0x1f, 0x00, 0x40, 0xff, 0x9f, 0xfc, 0x7f, 0x01, 0x00, 0xfc, 0x7f, 0x02, 0x10, 0xfe, 0x3f, 0x02, 0xa0, 0xff, 0x3f, 0x02, 0x80, 0xff, 0x3f, 0x02, 0x80, 0xff, 0x3f, 0x04, 0x80, 0xff, 0x1f, 0x04, 0x80, 0xff, 0x1f, 0x08, 0x80, 0xff, 0x0f, 0x08, 0x80, 0xff, 0x0f, 0x10, 0x80, 0xff, 0x07, 0x20, 0x80, 0xff, 0x03, 0xc0, 0x80, 0xff, 0x01, 0x00, 0x83, 0x7f, 0x00, 0x00, 0xbc, 0x1f, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; acm-6.0_20200416/src/gedit/xbm/zoom_in_32.xbm0000644000000000000000000000157510357223037016744 0ustar rootroot#define zoom_in_32_width 32 #define zoom_in_32_height 32 static char zoom_in_32_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x07, 0xf0, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0xff, 0x0f, 0xe0, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0xc0, 0x1f, 0x00, 0x00, 0xe0, 0x1f, 0x00, 0x00, 0xf0, 0xff, 0xff, 0x07, 0xf0, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; acm-6.0_20200416/src/gedit/xbm/circle_32.xbm0000644000000000000000000000157210357223037016530 0ustar rootroot#define circle_32_width 32 #define circle_32_height 32 static char circle_32_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x98, 0x19, 0x00, 0x00, 0x02, 0x40, 0x00, 0x80, 0x00, 0x00, 0x01, 0x30, 0x00, 0x00, 0x0e, 0x30, 0x00, 0x00, 0x0c, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x40, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x02, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x70, 0x00, 0x00, 0x0c, 0x70, 0x00, 0x00, 0x0e, 0x80, 0x00, 0x00, 0x01, 0x00, 0x02, 0x40, 0x00, 0x00, 0x98, 0x19, 0x00, 0x00, 0x80, 0x01, 0x00}; acm-6.0_20200416/src/gedit/xbm/polygon_64.xbm0000644000000000000000000000632410357223037016763 0ustar rootroot#define polygon_width 64 #define polygon_height 64 static char polygon_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x38, 0x03, 0x00, 0xb8, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x03, 0x00, 0x18, 0x07, 0x00, 0x00, 0x00, 0x06, 0x03, 0x00, 0x18, 0x0e, 0x00, 0x00, 0x80, 0x03, 0x03, 0x00, 0x18, 0x38, 0x00, 0x00, 0xc0, 0x01, 0x03, 0x00, 0x18, 0x70, 0x00, 0x00, 0x70, 0x00, 0x06, 0x00, 0x18, 0xc0, 0x00, 0x00, 0x38, 0x00, 0x06, 0x00, 0x1c, 0x80, 0x03, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x07, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x1c, 0x80, 0x01, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x38, 0xe0, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x60, 0x70, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0xc0, 0x1f, 0x00, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; acm-6.0_20200416/src/wmm/0000755000000000000000000000000013646051406013167 5ustar rootrootacm-6.0_20200416/src/wmm/README.txt0000644000000000000000000000277113646045024014673 0ustar rootrootThis directory contains the World Magnetic Model library created by the National Centers for Environmental Information - NOAA Downloaded from: https://www.ngdc.noaa.gov/geomag/WMM/soft.shtml Date taken: 2020-01-03 CONTENTS OF THIS DIRECTORY ========================== This directory contains only parts of the distributed library that are really needed to ACM: Geomagnetism.h Originally named src/GeomagnetismHeader.h in the package distributed by NOAA, contains the interface header to the WMM library. Geomagnetism.c Originally named src/GeomagnetismLibrary.c in the package distributed by NOAA, contains the actual implementation of the WMM library. wmm.h wmm.c ACM specific interface module to the WMM library. The file of the coefficients bin/WMM.COF has been copied into objects/WMM.COF; this file is valid for dates in the range from year 2015 up to 2019. It is important to remember that the file of the coefficients WMM.COF ensures accurate results only in the specified range of years; beyond this range a warning is displayed. LICENSES ======== The WMM source code is in the public domain and not licensed or under copyright. The information and software may be used freely by the public. As required by 17 U.S.C. 403, third parties producing copyrighted works consisting predominantly of the material produced by U.S. government agencies must provide notice with such work(s) identifying the U.S. Government material incorporated and stating that such material is not subject to copyright protection. acm-6.0_20200416/src/wmm/wmm.h0000644000000000000000000000406013173131401014125 0ustar rootroot/** * Interface module to the World Magnetic Model library to retrieve the magnetic * field components at any given location on the Earth. * * Performances: the wmm_getMagneticField() can evaluate more than 8000 point * data per second on a Intel Atom processor at 1.6 GHz. * * @file * @author Umberto Salsi * @version $Date: 2017/10/22 15:02:25 $ */ #ifndef wmm_H #define wmm_H #ifdef wmm_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Result of the query for the components of the magnetic field. */ typedef struct { /** Components of the magnetic field in the NED reference (nano Tesla). */ double X, Y, Z; /** Geomagnetic declination (magnetic variation), positive east (RAD). */ double Decl; /** Geomagnetic inclination, positive down (RAD). */ double Incl; } wmm_MagneticField; /** * Initializes this module. * @param coefficients_file File of the coefficients, normally named "WMM.COF". * If file not found or fails to read, it is a fatal error. */ EXTERN void wmm_init(char * coefficients_file); /** * Allows to change the default "current date" value used when client asks for * magnetic field at year zero. * @param date Date as year and fraction. */ EXTERN void wmm_setCurrentTime(double date); /** * Returns the components of the Earth's magnetic field at the given location. * @param date Date as year and fraction, example 2017.5 = 2017-07-02 12:00 UTC. * If set to zero, uses the current date as determined at initialization time, * which is accurate enough for the duration of a simulation and saves some lines * in the client code. * @param latitude Latitude, positive north (RAD). * @param longitude Longitude, positive east (RAD). * @param altitude Altitude over the WGS84 ellipsoid (m). The result is accurate * for a range of altitudes from 1 Km below the surface of the Earth, up to * 850 Km above. * @param mf Calculated magnetic field. */ EXTERN void wmm_getMagneticField(double date, double latitude, double longitude, double altitude, wmm_MagneticField *mf); #undef EXTERN #endif acm-6.0_20200416/src/wmm/wmm.c0000644000000000000000000000640713173131363014136 0ustar rootroot#include #include #include #include "../util/error.h" #include "../util/units.h" #include "../util/zulu.h" #include "Geomagnetism.h" // We use WGS84 altitude, no need for the geoid data: //# include "EGM9615.h" #define wmm_IMPORT #include "wmm.h" /** If this module has been initialized. */ static int inited; /** Current date to be used when client asks for year==0. */ static double date_current; static MAGtype_Geoid Geoid; static MAGtype_Ellipsoid Ellip; static MAGtype_MagneticModel * MagneticModels[1], *TimedMagneticModel; /* If the WMM.COF file becomes outdated, gives warning only once. */ static int warning_date_range_already_given; void wmm_init(char * coefficients_file) { if( inited ) return; inited = 1; date_current = zulu_timestampToYear(time(NULL)); int NumTerms, nMax = 0; int epochs = 1; if (!MAG_robustReadMagModels(coefficients_file, &MagneticModels, epochs)) error_external("failed reading WMM coefficients file %s", coefficients_file); if (nMax < MagneticModels[0]->nMax) nMax = MagneticModels[0]->nMax; NumTerms = ((nMax + 1) * (nMax + 2) / 2); TimedMagneticModel = MAG_AllocateModelMemory(NumTerms); /* For storing the time modified WMM Model parameters */ if (MagneticModels[0] == NULL || TimedMagneticModel == NULL) { MAG_Error(2); } MAG_SetDefaults(&Ellip, &Geoid); /* Set default values and constants */ /* Check for Geographic Poles */ /* Set EGM96 Geoid parameters */ //Geoid.GeoidHeightBuffer = GeoidHeightBuffer; Geoid.Geoid_Initialized = 0; } void wmm_setCurrentTime(double date) { date_current = date; } void wmm_getMagneticField(double date, double latitude, double longitude, double altitude, wmm_MagneticField *mf) { if( ! inited ) error_internal("wmm module not initialized", 0); if( date == 0 ) date = date_current; if( ! warning_date_range_already_given ){ double date_start = MagneticModels[0]->epoch; double date_end = MagneticModels[0]->CoefficientFileEndDate; if( !(date_start <= date && date <= date_end) ){ warning_date_range_already_given = 1; fprintf(stderr, "Warning: requested date %.1f is beyond the intended range [%.1f-%.1f] supported by the current coefficients file WMM.COF. The World Magnetic Model Library cannot evaluate the components of the Earth magnetic field with the needed accuracy.\n", date, date_start, date_end); } } MAGtype_CoordGeodetic CoordGeodetic; MAGtype_Date UserDate; MAGtype_GeoMagneticElements GeoMagneticElements; MAGtype_CoordSpherical CoordSpherical; UserDate.DecimalYear = date; UserDate.Year = UserDate.Month = UserDate.Day = 0; CoordGeodetic.lambda = units_RADtoDEG(longitude); CoordGeodetic.phi = units_RADtoDEG(latitude); CoordGeodetic.UseGeoid = 0; CoordGeodetic.HeightAboveEllipsoid = 0.001 * altitude; Geoid.UseGeoid = 0; //MAG_ConvertGeoidToEllipsoidHeight(CoordGeodetic, Geoid); MAG_GeodeticToSpherical(Ellip, CoordGeodetic, &CoordSpherical); MAG_TimelyModifyMagneticModel(UserDate, MagneticModels[0], TimedMagneticModel); MAG_Geomag(Ellip, CoordSpherical, CoordGeodetic, TimedMagneticModel, &GeoMagneticElements); mf->X = GeoMagneticElements.X; mf->Y = GeoMagneticElements.Y; mf->Z = GeoMagneticElements.Z; mf->Incl = units_DEGtoRAD(GeoMagneticElements.Incl); mf->Decl = units_DEGtoRAD(GeoMagneticElements.Decl); } acm-6.0_20200416/src/wmm/Geomagnetism.h0000644000000000000000000004446313646045024015771 0ustar rootroot/** * This file is part of the World Magnetic Model library created by the * National Centers for Environmental Information - NOAA. * Downloaded from: https://www.ngdc.noaa.gov/geomag/WMM/soft.shtml * Date taken: 2020-01-03. * @version $Date: 2020/01/08 05:11:01 $ * @file */ /* WMM Subroutine library was tested in the following environments * * 1. Red Hat Linux with GCC Compiler * 2. MS Windows XP with CodeGear C++ compiler * 3. Sun Solaris with GCC Compiler * * * Revision Number: Revision: 1437 * Last changed by: Author: awoods * Last changed on: Date: 2016-03-01 10:49:40 -0700 (Tue, 01 Mar 2016) * * */ //#ifndef _POSIX_C_SOURCE //#define _POSIX_C_SOURCE //#endif #include /* #ifndef EPOCHRANGE #define EPOCHRANGE (int)5 #endif */ #ifndef GEOMAGHEADER_H #define GEOMAGHEADER_H #ifdef Geomagnetism_IMPORT #define EXTERN #else #define EXTERN extern #endif #define READONLYMODE "r" #define MAXLINELENGTH (1024) #define NOOFPARAMS (15) #define NOOFCOEFFICIENTS (7) #define _DEGREE_NOT_FOUND (-2) #define CALCULATE_NUMTERMS(N) (N * ( N + 1 ) / 2 + N) /*These error values come from the ISCWSA error model: *http://www.copsegrove.com/Pages/MWDGeomagneticModels.aspx */ #define INCL_ERROR_BASE (0.20) #define DECL_ERROR_OFFSET_BASE (0.36) #define F_ERROR_BASE (130) #define DECL_ERROR_SLOPE_BASE (5000) #define WMM_ERROR_MULTIPLIER 1.21 #define IGRF_ERROR_MULTIPLIER 1.21 /*These error values are the NCEI error model * */ #define WMM_UNCERTAINTY_F 145 #define WMM_UNCERTAINTY_H 128 #define WMM_UNCERTAINTY_X 131 #define WMM_UNCERTAINTY_Y 94 #define WMM_UNCERTAINTY_Z 157 #define WMM_UNCERTAINTY_I 0.21 #define WMM_UNCERTAINTY_D_OFFSET 0.26 #define WMM_UNCERTAINTY_D_COEF 5625 #ifndef M_PI #define M_PI ((2)*(acos(0.0))) #endif #define RAD2DEG(rad) ((rad)*(180.0L/M_PI)) #define DEG2RAD(deg) ((deg)*(M_PI/180.0L)) #define ATanH(x) (0.5 * log((1 + x) / (1 - x))) #ifndef TRUE #define TRUE ((int)1) #endif #ifndef FALSE #define FALSE ((int)0) #endif #define MAG_PS_MIN_LAT_DEGREE -55 /* Minimum Latitude for Polar Stereographic projection in degrees */ #define MAG_PS_MAX_LAT_DEGREE 55 /* Maximum Latitude for Polar Stereographic projection in degrees */ #define MAG_UTM_MIN_LAT_DEGREE -80.5 /* Minimum Latitude for UTM projection in degrees */ #define MAG_UTM_MAX_LAT_DEGREE 84.5 /* Maximum Latitude for UTM projection in degrees */ #define MAG_GEO_POLE_TOLERANCE 1e-5 #define MAG_USE_GEOID 1 /* 1 Geoid - Ellipsoid difference should be corrected, 0 otherwise */ #define LAT_BOUND_MIN -90 #define LAT_BOUND_MAX 90 #define LON_BOUND_MIN -180 #define LON_BOUND_MAX 360 #define ALT_BOUND_MIN -10 #define NO_ALT_MAX -99999 #define USER_GAVE_UP -1 #define WGS84ON 1 #define MSLON 2 /* Data types and prototype declaration for World Magnetic Model (WMM) subroutines. July 28, 2009 manoj.c.nair@noaa.gov*/ #define MODEL_RELEASE_DATE "10 Dec 2019" #define VERSIONDATE_LARGE "Date: 2019-12-10 10:40:43 -0700 (Tue, 10 Dec 2019) " typedef enum { DECLINATION, INCLINATION, HOR_INTENSITY, TOTAL_INTENSITY, X_COMPONENT, Y_COMPONENT, Z_COMPONENT, ALL } MAGenum_Comp; typedef struct { double EditionDate; double epoch; /*Base time of Geomagnetic model epoch (yrs)*/ char ModelName[32]; double *Main_Field_Coeff_G; /* C - Gauss coefficients of main geomagnetic model (nT) Index is (n * (n + 1) / 2 + m) */ double *Main_Field_Coeff_H; /* C - Gauss coefficients of main geomagnetic model (nT) */ double *Secular_Var_Coeff_G; /* CD - Gauss coefficients of secular geomagnetic model (nT/yr) */ double *Secular_Var_Coeff_H; /* CD - Gauss coefficients of secular geomagnetic model (nT/yr) */ int nMax; /* Maximum degree of spherical harmonic model */ int nMaxSecVar; /* Maximum degree of spherical harmonic secular model */ int SecularVariationUsed; /* Whether or not the magnetic secular variation vector will be needed by program*/ double CoefficientFileEndDate; } MAGtype_MagneticModel; typedef struct { double a; /*semi-major axis of the ellipsoid*/ double b; /*semi-minor axis of the ellipsoid*/ double fla; /* flattening */ double epssq; /*first eccentricity squared */ double eps; /* first eccentricity */ double re; /* mean radius of ellipsoid*/ } MAGtype_Ellipsoid; typedef struct { double lambda; /* longitude */ double phi; /* geodetic latitude */ double HeightAboveEllipsoid; /* height above the ellipsoid (HaE) */ double HeightAboveGeoid; /* (height above the EGM96 geoid model ) */ int UseGeoid; } MAGtype_CoordGeodetic; typedef struct { double lambda; /* longitude*/ double phig; /* geocentric latitude*/ double r; /* distance from the center of the ellipsoid*/ } MAGtype_CoordSpherical; typedef struct { int Year; int Month; int Day; double DecimalYear; /* decimal years */ } MAGtype_Date; typedef struct { double *Pcup; /* Legendre Function */ double *dPcup; /* Derivative of Legendre fcn */ } MAGtype_LegendreFunction; typedef struct { double Bx; /* North */ double By; /* East */ double Bz; /* Down */ } MAGtype_MagneticResults; typedef struct { double *RelativeRadiusPower; /* [earth_reference_radius_km / sph. radius ]^n */ double *cos_mlambda; /*cp(m) - cosine of (m*spherical coord. longitude)*/ double *sin_mlambda; /* sp(m) - sine of (m*spherical coord. longitude) */ } MAGtype_SphericalHarmonicVariables; typedef struct { double Decl; /* 1. Angle between the magnetic field vector and true north, positive east*/ double Incl; /*2. Angle between the magnetic field vector and the horizontal plane, positive down*/ double F; /*3. Magnetic Field Strength*/ double H; /*4. Horizontal Magnetic Field Strength*/ double X; /*5. Northern component of the magnetic field vector*/ double Y; /*6. Eastern component of the magnetic field vector*/ double Z; /*7. Downward component of the magnetic field vector*/ double GV; /*8. The Grid Variation*/ double Decldot; /*9. Yearly Rate of change in declination*/ double Incldot; /*10. Yearly Rate of change in inclination*/ double Fdot; /*11. Yearly rate of change in Magnetic field strength*/ double Hdot; /*12. Yearly rate of change in horizontal field strength*/ double Xdot; /*13. Yearly rate of change in the northern component*/ double Ydot; /*14. Yearly rate of change in the eastern component*/ double Zdot; /*15. Yearly rate of change in the downward component*/ double GVdot; /*16. Yearly rate of change in grid variation*/ } MAGtype_GeoMagneticElements; typedef struct { int NumbGeoidCols; /* 360 degrees of longitude at 15 minute spacing */ int NumbGeoidRows; /* 180 degrees of latitude at 15 minute spacing */ int NumbHeaderItems; /* min, max lat, min, max long, lat, long spacing*/ int ScaleFactor; /* 4 grid cells per degree at 15 minute spacing */ float *GeoidHeightBuffer; int NumbGeoidElevs; int Geoid_Initialized; /* indicates successful initialization */ int UseGeoid; /*Is the Geoid being used?*/ } MAGtype_Geoid; typedef struct { int UseGradient; MAGtype_GeoMagneticElements GradPhi; /* phi */ MAGtype_GeoMagneticElements GradLambda; /* lambda */ MAGtype_GeoMagneticElements GradZ; } MAGtype_Gradient; typedef struct { char Longitude[40]; char Latitude[40]; } MAGtype_CoordGeodeticStr; typedef struct { double Easting; /* (X) in meters*/ double Northing; /* (Y) in meters */ int Zone; /*UTM Zone*/ char HemiSphere; double CentralMeridian; double ConvergenceOfMeridians; double PointScale; } MAGtype_UTMParameters; enum PARAMS { SHDF, MODELNAME, PUBLISHER, RELEASEDATE, DATACUTOFF, MODELSTARTYEAR, MODELENDYEAR, EPOCH, INTSTATICDEG, INTSECVARDEG, EXTSTATICDEG, EXTSECVARDEG, GEOMAGREFRAD, NORMALIZATION, SPATBASFUNC }; enum COEFFICIENTS { IE, N, M, GNM, HNM, DGNM, DHNM }; enum YYYYMMDD { YEAR, MONTH, DAY }; /*Prototypes */ /*Functions that should be Magnetic Model member functions*/ /*Wrapper Functions*/ EXTERN int MAG_Geomag(MAGtype_Ellipsoid Ellip, MAGtype_CoordSpherical CoordSpherical, MAGtype_CoordGeodetic CoordGeodetic, MAGtype_MagneticModel *TimedMagneticModel, MAGtype_GeoMagneticElements *GeoMagneticElements); EXTERN void MAG_Gradient(MAGtype_Ellipsoid Ellip, MAGtype_CoordGeodetic CoordGeodetic, MAGtype_MagneticModel *TimedMagneticModel, MAGtype_Gradient *Gradient); EXTERN int MAG_robustReadMagneticModel_Large(char *filename, char* filenameSV, MAGtype_MagneticModel **MagneticModel); EXTERN int MAG_robustReadMagModels(char *filename, MAGtype_MagneticModel *(*magneticmodels)[], int array_size); EXTERN int MAG_SetDefaults(MAGtype_Ellipsoid *Ellip, MAGtype_Geoid *Geoid); /*User Interface*/ EXTERN void MAG_Error(int control); EXTERN int MAG_GetUserGrid(MAGtype_CoordGeodetic *minimum, MAGtype_CoordGeodetic *maximum, double *step_size, double *a_step_size, double *step_time, MAGtype_Date *StartDate, MAGtype_Date *EndDate, int *ElementOption, int *PrintOption, char *OutputFile, MAGtype_Geoid *Geoid); EXTERN int MAG_GetUserInput(MAGtype_MagneticModel *MagneticModel, MAGtype_Geoid *Geoid, MAGtype_CoordGeodetic *CoordGeodetic, MAGtype_Date *MagneticDate); EXTERN void MAG_PrintGradient(MAGtype_Gradient Gradient); EXTERN void MAG_PrintUserData(MAGtype_GeoMagneticElements GeomagElements, MAGtype_CoordGeodetic SpaceInput, MAGtype_Date TimeInput, MAGtype_MagneticModel *MagneticModel, MAGtype_Geoid *Geoid); EXTERN int MAG_ValidateDMSstring(char *input, int min, int max, char *Error); EXTERN int MAG_Warnings(int control, double value, MAGtype_MagneticModel *MagneticModel); /*Memory and File Processing*/ EXTERN MAGtype_LegendreFunction *MAG_AllocateLegendreFunctionMemory(int NumTerms); EXTERN MAGtype_MagneticModel *MAG_AllocateModelMemory(int NumTerms); EXTERN MAGtype_SphericalHarmonicVariables *MAG_AllocateSphVarMemory(int nMax); EXTERN void MAG_AssignHeaderValues(MAGtype_MagneticModel *model, char values[][MAXLINELENGTH]); EXTERN void MAG_AssignMagneticModelCoeffs(MAGtype_MagneticModel *Assignee, MAGtype_MagneticModel *Source, int nMax, int nMaxSecVar); EXTERN int MAG_FreeMemory(MAGtype_MagneticModel *MagneticModel, MAGtype_MagneticModel *TimedMagneticModel, MAGtype_LegendreFunction *LegendreFunction); EXTERN int MAG_FreeLegendreMemory(MAGtype_LegendreFunction *LegendreFunction); EXTERN int MAG_FreeMagneticModelMemory(MAGtype_MagneticModel *MagneticModel); EXTERN int MAG_FreeSphVarMemory(MAGtype_SphericalHarmonicVariables *SphVar); EXTERN void MAG_PrintWMMFormat(char *filename, MAGtype_MagneticModel *MagneticModel); EXTERN void MAG_PrintEMMFormat(char *filename, char *filenameSV, MAGtype_MagneticModel *MagneticModel); EXTERN void MAG_PrintSHDFFormat(char *filename, MAGtype_MagneticModel *(*MagneticModel)[], int epochs); EXTERN int MAG_readMagneticModel(char *filename, MAGtype_MagneticModel *MagneticModel); EXTERN int MAG_readMagneticModel_Large(char *filename, char *filenameSV, MAGtype_MagneticModel *MagneticModel); EXTERN int MAG_readMagneticModel_SHDF(char *filename, MAGtype_MagneticModel *(*magneticmodels)[], int array_size); EXTERN char *MAG_Trim(char *str); /*Conversions, Transformations, and other Calculations*/ EXTERN void MAG_BaseErrors(double DeclCoef, double DeclBaseline, double InclOffset, double FOffset, double Multiplier, double H, double* DeclErr, double* InclErr, double* FErr); EXTERN int MAG_CalculateGeoMagneticElements(MAGtype_MagneticResults *MagneticResultsGeo, MAGtype_GeoMagneticElements *GeoMagneticElements); EXTERN void MAG_CalculateGradientElements(MAGtype_MagneticResults GradResults, MAGtype_GeoMagneticElements MagneticElements, MAGtype_GeoMagneticElements *GradElements); EXTERN int MAG_CalculateSecularVariationElements(MAGtype_MagneticResults MagneticVariation, MAGtype_GeoMagneticElements *MagneticElements); EXTERN int MAG_CalculateGridVariation(MAGtype_CoordGeodetic location, MAGtype_GeoMagneticElements *elements); EXTERN void MAG_CartesianToGeodetic(MAGtype_Ellipsoid Ellip, double x, double y, double z, MAGtype_CoordGeodetic *CoordGeodetic); EXTERN MAGtype_CoordGeodetic MAG_CoordGeodeticAssign(MAGtype_CoordGeodetic CoordGeodetic); EXTERN int MAG_DateToYear(MAGtype_Date *Calendar_Date, char *Error); EXTERN void MAG_DegreeToDMSstring(double DegreesOfArc, int UnitDepth, char *DMSstring); EXTERN void MAG_DMSstringToDegree(char *DMSstring, double *DegreesOfArc); EXTERN void MAG_ErrorCalc(MAGtype_GeoMagneticElements B, MAGtype_GeoMagneticElements* Errors); EXTERN int MAG_GeodeticToSpherical(MAGtype_Ellipsoid Ellip, MAGtype_CoordGeodetic CoordGeodetic, MAGtype_CoordSpherical *CoordSpherical); EXTERN MAGtype_GeoMagneticElements MAG_GeoMagneticElementsAssign(MAGtype_GeoMagneticElements Elements); EXTERN MAGtype_GeoMagneticElements MAG_GeoMagneticElementsScale(MAGtype_GeoMagneticElements Elements, double factor); EXTERN MAGtype_GeoMagneticElements MAG_GeoMagneticElementsSubtract(MAGtype_GeoMagneticElements minuend, MAGtype_GeoMagneticElements subtrahend); EXTERN int MAG_GetTransverseMercator(MAGtype_CoordGeodetic CoordGeodetic, MAGtype_UTMParameters *UTMParameters); EXTERN int MAG_GetUTMParameters(double Latitude, double Longitude, int *Zone, char *Hemisphere, double *CentralMeridian); EXTERN int MAG_isNaN(double d); EXTERN int MAG_RotateMagneticVector(MAGtype_CoordSpherical, MAGtype_CoordGeodetic CoordGeodetic, MAGtype_MagneticResults MagneticResultsSph, MAGtype_MagneticResults *MagneticResultsGeo); EXTERN void MAG_SphericalToCartesian(MAGtype_CoordSpherical CoordSpherical, double *x, double *y, double *z); EXTERN void MAG_SphericalToGeodetic(MAGtype_Ellipsoid Ellip, MAGtype_CoordSpherical CoordSpherical, MAGtype_CoordGeodetic *CoordGeodetic); EXTERN void MAG_TMfwd4(double Eps, double Epssq, double K0R4, double K0R4oa, double Acoeff[], double Lam0, double K0, double falseE, double falseN, int XYonly, double Lambda, double Phi, double *X, double *Y, double *pscale, double *CoM); EXTERN int MAG_YearToDate(MAGtype_Date *Date); /*Spherical Harmonics*/ EXTERN int MAG_AssociatedLegendreFunction(MAGtype_CoordSpherical CoordSpherical, int nMax, MAGtype_LegendreFunction *LegendreFunction); EXTERN int MAG_CheckGeographicPole(MAGtype_CoordGeodetic *CoordGeodetic); EXTERN int MAG_ComputeSphericalHarmonicVariables(MAGtype_Ellipsoid Ellip, MAGtype_CoordSpherical CoordSpherical, int nMax, MAGtype_SphericalHarmonicVariables * SphVariables); EXTERN void MAG_GradY(MAGtype_Ellipsoid Ellip, MAGtype_CoordSpherical CoordSpherical, MAGtype_CoordGeodetic CoordGeodetic, MAGtype_MagneticModel *TimedMagneticModel, MAGtype_GeoMagneticElements GeoMagneticElements, MAGtype_GeoMagneticElements *GradYElements); EXTERN void MAG_GradYSummation(MAGtype_LegendreFunction *LegendreFunction, MAGtype_MagneticModel *MagneticModel, MAGtype_SphericalHarmonicVariables SphVariables, MAGtype_CoordSpherical CoordSpherical, MAGtype_MagneticResults *GradY); EXTERN int MAG_PcupHigh(double *Pcup, double *dPcup, double x, int nMax); EXTERN int MAG_PcupLow(double *Pcup, double *dPcup, double x, int nMax); EXTERN int MAG_SecVarSummation(MAGtype_LegendreFunction *LegendreFunction, MAGtype_MagneticModel *MagneticModel, MAGtype_SphericalHarmonicVariables SphVariables, MAGtype_CoordSpherical CoordSpherical, MAGtype_MagneticResults *MagneticResults); EXTERN int MAG_SecVarSummationSpecial(MAGtype_MagneticModel *MagneticModel, MAGtype_SphericalHarmonicVariables SphVariables, MAGtype_CoordSpherical CoordSpherical, MAGtype_MagneticResults *MagneticResults); EXTERN int MAG_Summation(MAGtype_LegendreFunction *LegendreFunction, MAGtype_MagneticModel *MagneticModel, MAGtype_SphericalHarmonicVariables SphVariables, MAGtype_CoordSpherical CoordSpherical, MAGtype_MagneticResults *MagneticResults); EXTERN int MAG_SummationSpecial(MAGtype_MagneticModel *MagneticModel, MAGtype_SphericalHarmonicVariables SphVariables, MAGtype_CoordSpherical CoordSpherical, MAGtype_MagneticResults *MagneticResults); EXTERN int MAG_TimelyModifyMagneticModel(MAGtype_Date UserDate, MAGtype_MagneticModel *MagneticModel, MAGtype_MagneticModel *TimedMagneticModel); /*Geoid*/ EXTERN int MAG_ConvertGeoidToEllipsoidHeight(MAGtype_CoordGeodetic *CoordGeodetic, MAGtype_Geoid *Geoid); /* * The function Convert_Geoid_To_Ellipsoid_Height converts the specified WGS84 * geoid height at the specified geodetic coordinates to the equivalent * ellipsoid height, using the EGM96 gravity model. * * Latitude : Geodetic latitude in radians (input) * Longitude : Geodetic longitude in radians (input) * Geoid_Height : Geoid height, in meters (input) * Ellipsoid_Height : Ellipsoid height, in meters. (output) * */ EXTERN int MAG_GetGeoidHeight(double Latitude, double Longitude, double *DeltaHeight, MAGtype_Geoid *Geoid); /* * The private function Get_Geoid_Height returns the height of the * WGS84 geiod above or below the WGS84 ellipsoid, * at the specified geodetic coordinates, * using a grid of height adjustments from the EGM96 gravity model. * * Latitude : Geodetic latitude in radians (input) * Longitude : Geodetic longitude in radians (input) * DeltaHeight : Height Adjustment, in meters. (output) * */ EXTERN void MAG_EquivalentLatLon(double lat, double lon, double *repairedLat, double *repairedLon); EXTERN void MAG_WMMErrorCalc(double H, MAGtype_GeoMagneticElements *Uncertainty); EXTERN void MAG_PrintUserDataWithUncertainty(MAGtype_GeoMagneticElements GeomagElements, MAGtype_GeoMagneticElements Errors, MAGtype_CoordGeodetic SpaceInput, MAGtype_Date TimeInput, MAGtype_MagneticModel *MagneticModel, MAGtype_Geoid *Geoid); void MAG_GetDeg(char* Query_String, double* latitude, double bounds[2]); int MAG_GetAltitude(char* Query_String, MAGtype_Geoid *Geoid, MAGtype_CoordGeodetic* coords, int bounds[2], int AltitudeSetting); #undef EXTERN #endif /*GEOMAGHEADER_H*/ acm-6.0_20200416/src/wmm/Makefile0000644000000000000000000000115613161734016014627 0ustar rootroot# This file generated by make-makefile, do not edit! # Create Makefile-include.txt instead for your customizations. CC := gcc CFLAGS := -Wall -Werror -g -fmax-errors=99 -Wuninitialized -Wmissing-prototypes -Wredundant-decls LIBS := .PHONY: all all: make Geomagnetism.o wmm.o #include Makefile-include.txt .PHONY: clean clean: rm -f *.o *.exe *.stackdump Geomagnetism.o: Geomagnetism.c Geomagnetism.h $(CC) $(CFLAGS) -c Geomagnetism.c -o Geomagnetism.o wmm.o: wmm.c wmm.h ../util/error.h ../util/units.h ../util/zulu.h Geomagnetism.h $(CC) $(CFLAGS) -c wmm.c -o wmm.o # Checksum of the original file: 2847787348 acm-6.0_20200416/src/wmm/Geomagnetism.c0000644000000000000000000051111113646045024015751 0ustar rootroot/** * This file is part of the World Magnetic Model library created by the * National Centers for Environmental Information - NOAA. * Downloaded from: https://www.ngdc.noaa.gov/geomag/WMM/soft.shtml * Date taken: 2020-01-03. * @version $Date: 2020/01/08 05:11:01 $ * @file */ #include #include #include #include #include #include #define Geomagnetism_IMPORT #include "Geomagnetism.h" // LINKER_OPTIONS -lm /* Id: GeomagnetismLibrary.c 1521 2017-01-24 17:52:41Z awoods * * ABSTRACT * * The purpose of Geomagnetism Library is primarily to support the World Magnetic Model (WMM) 2015-2020. * It however is built to be used for spherical harmonic models of the Earth's magnetic field * generally and supports models even with a large (>>12) number of degrees. It is also used in many * other geomagnetic models distributed by NCEI. * * REUSE NOTES * * Geomagnetism Library is intended for reuse by any application that requires * Computation of Geomagnetic field from a spherical harmonic model. * * REFERENCES * * Further information on Geoid can be found in the WMM Technical Documents. * * * LICENSES * * The WMM source code is in the public domain and not licensed or under copyright. * The information and software may be used freely by the public. As required by 17 U.S.C. 403, * third parties producing copyrighted works consisting predominantly of the material produced by * U.S. government agencies must provide notice with such work(s) identifying the U.S. Government material * incorporated and stating that such material is not subject to copyright protection. * * RESTRICTIONS * * Geomagnetism library has no restrictions. * * ENVIRONMENT * * Geomagnetism library was tested in the following environments * * 1. Red Hat Linux with GCC Compiler * 2. MS Windows 7 with MinGW compiler * 3. Sun Solaris with GCC Compiler * * * National Centers for Environmental Information * NOAA E/NE42, 325 Broadway * Boulder, CO 80305 USA * Attn: Arnaud Chulliat * Phone: (303) 497-6522 * Email: Arnaud.Chulliat@noaa.gov * Software and Model Support * National Centers for Environmental Information * NOAA E/NE42 * 325 Broadway * Boulder, CO 80305 USA * Attn: Adam Woods or Manoj Nair * Phone: (303) 497-6640 or -4642 * Email: geomag.models@noaa.gov * URL: http://www.ngdc.noaa.gov/Geomagnetic/WMM/DoDWMM.shtml * For more details on the subroutines, please consult the WMM * Technical Documentations at * http://www.ngdc.noaa.gov/Geomagnetic/WMM/DoDWMM.shtml * Nov 23, 2009 * Written by Manoj C Nair and Adam Woods * Manoj.C.Nair@noaa.Gov * Adam.Woods@noaa.gov */ /****************************************************************************** ************************************Wrapper*********************************** * This grouping consists of functions call groups of other functions to do a * complete calculation of some sort. For example, the MAG_Geomag function * does everything necessary to compute the geomagnetic elements from a given * geodetic point in space and magnetic model adjusted for the appropriate * date. These functions are the external functions necessary to create a * program that uses or calculates the magnetic field. ****************************************************************************** ******************************************************************************/ int MAG_Geomag(MAGtype_Ellipsoid Ellip, MAGtype_CoordSpherical CoordSpherical, MAGtype_CoordGeodetic CoordGeodetic, MAGtype_MagneticModel *TimedMagneticModel, MAGtype_GeoMagneticElements *GeoMagneticElements) /* The main subroutine that calls a sequence of WMM sub-functions to calculate the magnetic field elements for a single point. The function expects the model coefficients and point coordinates as input and returns the magnetic field elements and their rate of change. Though, this subroutine can be called successively to calculate a time series, profile or grid of magnetic field, these are better achieved by the subroutine MAG_Grid. INPUT: Ellip CoordSpherical CoordGeodetic TimedMagneticModel OUTPUT : GeoMagneticElements CALLS: MAG_AllocateLegendreFunctionMemory(NumTerms); ( For storing the ALF functions ) MAG_ComputeSphericalHarmonicVariables( Ellip, CoordSpherical, TimedMagneticModel->nMax, &SphVariables); (Compute Spherical Harmonic variables ) MAG_AssociatedLegendreFunction(CoordSpherical, TimedMagneticModel->nMax, LegendreFunction); Compute ALF MAG_Summation(LegendreFunction, TimedMagneticModel, SphVariables, CoordSpherical, &MagneticResultsSph); Accumulate the spherical harmonic coefficients MAG_SecVarSummation(LegendreFunction, TimedMagneticModel, SphVariables, CoordSpherical, &MagneticResultsSphVar); Sum the Secular Variation Coefficients MAG_RotateMagneticVector(CoordSpherical, CoordGeodetic, MagneticResultsSph, &MagneticResultsGeo); Map the computed Magnetic fields to Geodetic coordinates MAG_CalculateGeoMagneticElements(&MagneticResultsGeo, GeoMagneticElements); Calculate the Geomagnetic elements MAG_CalculateSecularVariationElements(MagneticResultsGeoVar, GeoMagneticElements); Calculate the secular variation of each of the Geomagnetic elements */ { MAGtype_LegendreFunction *LegendreFunction; MAGtype_SphericalHarmonicVariables *SphVariables; int NumTerms; MAGtype_MagneticResults MagneticResultsSph, MagneticResultsGeo, MagneticResultsSphVar, MagneticResultsGeoVar; NumTerms = ((TimedMagneticModel->nMax + 1) * (TimedMagneticModel->nMax + 2) / 2); LegendreFunction = MAG_AllocateLegendreFunctionMemory(NumTerms); /* For storing the ALF functions */ SphVariables = MAG_AllocateSphVarMemory(TimedMagneticModel->nMax); MAG_ComputeSphericalHarmonicVariables(Ellip, CoordSpherical, TimedMagneticModel->nMax, SphVariables); /* Compute Spherical Harmonic variables */ MAG_AssociatedLegendreFunction(CoordSpherical, TimedMagneticModel->nMax, LegendreFunction); /* Compute ALF */ MAG_Summation(LegendreFunction, TimedMagneticModel, *SphVariables, CoordSpherical, &MagneticResultsSph); /* Accumulate the spherical harmonic coefficients*/ MAG_SecVarSummation(LegendreFunction, TimedMagneticModel, *SphVariables, CoordSpherical, &MagneticResultsSphVar); /*Sum the Secular Variation Coefficients */ MAG_RotateMagneticVector(CoordSpherical, CoordGeodetic, MagneticResultsSph, &MagneticResultsGeo); /* Map the computed Magnetic fields to Geodeitic coordinates */ MAG_RotateMagneticVector(CoordSpherical, CoordGeodetic, MagneticResultsSphVar, &MagneticResultsGeoVar); /* Map the secular variation field components to Geodetic coordinates*/ MAG_CalculateGeoMagneticElements(&MagneticResultsGeo, GeoMagneticElements); /* Calculate the Geomagnetic elements, Equation 19 , WMM Technical report */ MAG_CalculateSecularVariationElements(MagneticResultsGeoVar, GeoMagneticElements); /*Calculate the secular variation of each of the Geomagnetic elements*/ MAG_FreeLegendreMemory(LegendreFunction); MAG_FreeSphVarMemory(SphVariables); return TRUE; } /*MAG_Geomag*/ void MAG_Gradient(MAGtype_Ellipsoid Ellip, MAGtype_CoordGeodetic CoordGeodetic, MAGtype_MagneticModel *TimedMagneticModel, MAGtype_Gradient *Gradient) { /*It should be noted that the x[2], y[2], and z[2] variables are NOT the same coordinate system as the directions in which the gradients are taken. These variables represent a Cartesian coordinate system where the Earth's center is the origin, 'z' points up toward the North (rotational) pole and 'x' points toward the prime meridian. 'y' points toward longitude = 90 degrees East. The gradient is preformed along a local Cartesian coordinate system with the origin at CoordGeodetic. 'z' points down toward the Earth's core, x points North, tangent to the local longitude line, and 'y' points East, tangent to the local latitude line.*/ double phiDelta = 0.01, /*DeltaY = 0.01,*/ hDelta = -1, x[2], y[2], z[2], distance; MAGtype_CoordSpherical AdjCoordSpherical; MAGtype_CoordGeodetic AdjCoordGeodetic; MAGtype_GeoMagneticElements GeomagneticElements, AdjGeoMagneticElements[2]; /*Initialization*/ MAG_GeodeticToSpherical(Ellip, CoordGeodetic, &AdjCoordSpherical); MAG_Geomag(Ellip, AdjCoordSpherical, CoordGeodetic, TimedMagneticModel, &GeomagneticElements); AdjCoordGeodetic = MAG_CoordGeodeticAssign(CoordGeodetic); /*Gradient along x*/ AdjCoordGeodetic.phi = CoordGeodetic.phi + phiDelta; MAG_GeodeticToSpherical(Ellip, AdjCoordGeodetic, &AdjCoordSpherical); MAG_Geomag(Ellip, AdjCoordSpherical, AdjCoordGeodetic, TimedMagneticModel, &AdjGeoMagneticElements[0]); MAG_SphericalToCartesian(AdjCoordSpherical, &x[0], &y[0], &z[0]); AdjCoordGeodetic.phi = CoordGeodetic.phi - phiDelta; MAG_GeodeticToSpherical(Ellip, AdjCoordGeodetic, &AdjCoordSpherical); MAG_Geomag(Ellip, AdjCoordSpherical, AdjCoordGeodetic, TimedMagneticModel, &AdjGeoMagneticElements[1]); MAG_SphericalToCartesian(AdjCoordSpherical, &x[1], &y[1], &z[1]); distance = sqrt((x[0] - x[1])*(x[0] - x[1])+(y[0] - y[1])*(y[0] - y[1])+(z[0] - z[1])*(z[0] - z[1])); Gradient->GradPhi = MAG_GeoMagneticElementsSubtract(AdjGeoMagneticElements[0], AdjGeoMagneticElements[1]); Gradient->GradPhi = MAG_GeoMagneticElementsScale(Gradient->GradPhi, 1 / distance); AdjCoordGeodetic = MAG_CoordGeodeticAssign(CoordGeodetic); /*Gradient along y*/ /*It is perhaps noticeable that the method here for calculation is substantially different than that for the gradient along x. As we near the North pole the longitude lines approach each other, and the calculation that works well for latitude lines becomes unstable when 0.01 degrees represents sufficiently small numbers, and fails to function correctly at all at the North Pole*/ MAG_GeodeticToSpherical(Ellip, CoordGeodetic, &AdjCoordSpherical); MAG_GradY(Ellip, AdjCoordSpherical, CoordGeodetic, TimedMagneticModel, GeomagneticElements, &(Gradient->GradLambda)); /*Gradient along z*/ AdjCoordGeodetic.HeightAboveEllipsoid = CoordGeodetic.HeightAboveEllipsoid + hDelta; AdjCoordGeodetic.HeightAboveGeoid = CoordGeodetic.HeightAboveGeoid + hDelta; MAG_GeodeticToSpherical(Ellip, AdjCoordGeodetic, &AdjCoordSpherical); MAG_Geomag(Ellip, AdjCoordSpherical, AdjCoordGeodetic, TimedMagneticModel, &AdjGeoMagneticElements[0]); MAG_SphericalToCartesian(AdjCoordSpherical, &x[0], &y[0], &z[0]); AdjCoordGeodetic.HeightAboveEllipsoid = CoordGeodetic.HeightAboveEllipsoid - hDelta; AdjCoordGeodetic.HeightAboveGeoid = CoordGeodetic.HeightAboveGeoid - hDelta; MAG_GeodeticToSpherical(Ellip, AdjCoordGeodetic, &AdjCoordSpherical); MAG_Geomag(Ellip, AdjCoordSpherical, AdjCoordGeodetic, TimedMagneticModel, &AdjGeoMagneticElements[1]); MAG_SphericalToCartesian(AdjCoordSpherical, &x[1], &y[1], &z[1]); distance = sqrt((x[0] - x[1])*(x[0] - x[1])+(y[0] - y[1])*(y[0] - y[1])+(z[0] - z[1])*(z[0] - z[1])); Gradient->GradZ = MAG_GeoMagneticElementsSubtract(AdjGeoMagneticElements[0], AdjGeoMagneticElements[1]); Gradient->GradZ = MAG_GeoMagneticElementsScale(Gradient->GradZ, 1/distance); AdjCoordGeodetic = MAG_CoordGeodeticAssign(CoordGeodetic); } int MAG_SetDefaults(MAGtype_Ellipsoid *Ellip, MAGtype_Geoid *Geoid) /* Sets default values for WMM subroutines. UPDATES : Ellip Geoid CALLS : none */ { /* Sets WGS-84 parameters */ Ellip->a = 6378.137; /*semi-major axis of the ellipsoid in */ Ellip->b = 6356.7523142; /*semi-minor axis of the ellipsoid in */ Ellip->fla = 1 / 298.257223563; /* flattening */ Ellip->eps = sqrt(1 - (Ellip->b * Ellip->b) / (Ellip->a * Ellip->a)); /*first eccentricity */ Ellip->epssq = (Ellip->eps * Ellip->eps); /*first eccentricity squared */ Ellip->re = 6371.2; /* Earth's radius */ /* Sets EGM-96 model file parameters */ Geoid->NumbGeoidCols = 1441; /* 360 degrees of longitude at 15 minute spacing */ Geoid->NumbGeoidRows = 721; /* 180 degrees of latitude at 15 minute spacing */ Geoid->NumbHeaderItems = 6; /* min, max lat, min, max long, lat, long spacing*/ Geoid->ScaleFactor = 4; /* 4 grid cells per degree at 15 minute spacing */ Geoid->NumbGeoidElevs = Geoid->NumbGeoidCols * Geoid->NumbGeoidRows; Geoid->Geoid_Initialized = 0; /* Geoid will be initialized only if this is set to zero */ Geoid->UseGeoid = MAG_USE_GEOID; return TRUE; } /*MAG_SetDefaults */ int MAG_robustReadMagneticModel_Large(char *filename, char *filenameSV, MAGtype_MagneticModel **MagneticModel) { char line[MAXLINELENGTH], ModelName[] = "Enhanced Magnetic Model";/*Model Name must be no longer than 31 characters*/ int n, nMax = 0, nMaxSV = 0, num_terms, a, epochlength=5, i; FILE *MODELFILE; MODELFILE = fopen(filename, "r"); if(MODELFILE == 0) { return 0; } if (NULL == fgets(line, MAXLINELENGTH, MODELFILE)) { return 0; } do { if(NULL == fgets(line, MAXLINELENGTH, MODELFILE)) break; a = sscanf(line, "%d", &n); if(n > nMax && (n < 99999 && a == 1 && n > 0)) nMax = n; } while(n < 99999 && a == 1); fclose(MODELFILE); MODELFILE = fopen(filenameSV, "r"); if(MODELFILE == 0) { return 0; } n = 0; if (NULL == fgets(line, MAXLINELENGTH, MODELFILE)) return 0; do { if(NULL == fgets(line, MAXLINELENGTH, MODELFILE)) break; a = sscanf(line, "%d", &n); if(n > nMaxSV && (n < 99999 && a == 1 && n > 0)) nMaxSV = n; } while(n < 99999 && a == 1); fclose(MODELFILE); num_terms = CALCULATE_NUMTERMS(nMax); *MagneticModel = MAG_AllocateModelMemory(num_terms); (*MagneticModel)->nMax = nMax; (*MagneticModel)->nMaxSecVar = nMaxSV; if(nMaxSV > 0) (*MagneticModel)->SecularVariationUsed = TRUE; for(i = 0; i < num_terms; i++) { (*MagneticModel)->Main_Field_Coeff_G[i] = 0; (*MagneticModel)->Main_Field_Coeff_H[i] = 0; (*MagneticModel)->Secular_Var_Coeff_G[i] = 0; (*MagneticModel)->Secular_Var_Coeff_H[i] = 0; } MAG_readMagneticModel_Large(filename, filenameSV, *MagneticModel); (*MagneticModel)->CoefficientFileEndDate = (*MagneticModel)->epoch + epochlength; strcpy((*MagneticModel)->ModelName, ModelName); (*MagneticModel)->EditionDate = (*MagneticModel)->epoch; return 1; } /*MAG_robustReadMagneticModel_Large*/ int MAG_robustReadMagModels(char *filename, MAGtype_MagneticModel *(*magneticmodels)[], int array_size) { char line[MAXLINELENGTH]; int n, nMax = 0, num_terms, a; FILE *MODELFILE; MODELFILE = fopen(filename, "r"); if(MODELFILE == 0) { return 0; } if (NULL==fgets(line, MAXLINELENGTH, MODELFILE)){ return 0; } if(line[0] == '%'){ MAG_readMagneticModel_SHDF(filename, magneticmodels, array_size); } else if(array_size == 1) { do { if(NULL == fgets(line, MAXLINELENGTH, MODELFILE)) break; a = sscanf(line, "%d", &n); if(n > nMax && (n < 99999 && a == 1 && n > 0)) nMax = n; } while(n < 99999 && a == 1); num_terms = CALCULATE_NUMTERMS(nMax); (*magneticmodels)[0] = MAG_AllocateModelMemory(num_terms); (*magneticmodels)[0]->nMax = nMax; (*magneticmodels)[0]->nMaxSecVar = nMax; MAG_readMagneticModel(filename, (*magneticmodels)[0]); (*magneticmodels)[0]->CoefficientFileEndDate = (*magneticmodels)[0]->epoch + 5; } else return 0; fclose(MODELFILE); return 1; } /*MAG_robustReadMagModels*/ /*End of Wrapper Functions*/ /****************************************************************************** ********************************User Interface******************************** * This grouping consists of functions which interact with the directly with * the user and are generally specific to the XXX_point.c, XXX_grid.c, and * XXX_file.c programs. They deal with input from and output to the user. ******************************************************************************/ void MAG_Error(int control) /*This prints WMM errors. INPUT control Error look up number OUTPUT none CALLS : none */ { switch(control) { case 1: printf("\nError allocating in MAG_LegendreFunctionMemory.\n"); break; case 2: printf("\nError allocating in MAG_AllocateModelMemory.\n"); break; case 3: printf("\nError allocating in MAG_InitializeGeoid\n"); break; case 4: printf("\nError in setting default values.\n"); break; case 5: printf("\nError initializing Geoid.\n"); break; case 6: printf("\nError opening WMM.COF\n."); break; case 7: printf("\nError opening WMMSV.COF\n."); break; case 8: printf("\nError reading Magnetic Model.\n"); break; case 9: printf("\nError printing Command Prompt introduction.\n"); break; case 10: printf("\nError converting from geodetic co-ordinates to spherical co-ordinates.\n"); break; case 11: printf("\nError in time modifying the Magnetic model\n"); break; case 12: printf("\nError in Geomagnetic\n"); break; case 13: printf("\nError printing user data\n");\ break; case 14: printf("\nError allocating in MAG_SummationSpecial\n"); break; case 15: printf("\nError allocating in MAG_SecVarSummationSpecial\n"); break; case 16: printf("\nError in opening EGM9615.BIN file\n"); break; case 17: printf("\nError: Latitude OR Longitude out of range in MAG_GetGeoidHeight\n"); break; case 18: printf("\nError allocating in MAG_PcupHigh\n"); break; case 19: printf("\nError allocating in MAG_PcupLow\n"); break; case 20: printf("\nError opening coefficient file\n"); break; case 21: printf("\nError: UnitDepth too large\n"); break; case 22: printf("\nYour system needs Big endian version of EGM9615.BIN. \n"); printf("Please download this file from http://www.ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml. \n"); printf("Replace the existing EGM9615.BIN file with the downloaded one\n"); break; } } /*MAG_Error*/ int MAG_GetUserGrid(MAGtype_CoordGeodetic *minimum, MAGtype_CoordGeodetic *maximum, double *step_size, double *a_step_size, double *step_time, MAGtype_Date *StartDate, MAGtype_Date *EndDate, int *ElementOption, int *PrintOption, char *OutputFile, MAGtype_Geoid *Geoid) /* Prompts user to enter parameters to compute a grid - for use with the MAG_grid function Note: The user entries are not validated before here. The function populates the input variables & data structures. UPDATE : minimum Pointer to data structure with the following elements double lambda; (longitude) double phi; ( geodetic latitude) double HeightAboveEllipsoid; (height above the ellipsoid (HaE) ) double HeightAboveGeoid;(height above the Geoid ) maximum -same as the above -MAG_USE_GEOID step_size : double pointer : spatial step size, in decimal degrees a_step_size : double pointer : double altitude step size (km) step_time : double pointer : time step size (decimal years) StartDate : pointer to data structure with the following elements updates double DecimalYear; ( decimal years ) EndDate : Same as the above CALLS : none */ { FILE *fileout; char filename[] = "GridProgramDirective.txt"; char buffer[20]; int dummy; printf("Please Enter Minimum Latitude (in decimal degrees):\n"); if (NULL == fgets(buffer, 20, stdin)) { minimum->phi = 0; printf("Unrecognized input default %lf used\n", minimum->phi); }else { sscanf(buffer, "%lf", &minimum->phi); } strcpy(buffer, ""); printf("Please Enter Maximum Latitude (in decimal degrees):\n"); if (NULL == fgets(buffer, 20, stdin)) { maximum->phi = 0; printf("Unrecognized input default %lf used\n", maximum->phi); } else { sscanf(buffer, "%lf", &maximum->phi); } strcpy(buffer, ""); printf("Please Enter Minimum Longitude (in decimal degrees):\n"); if (NULL == fgets(buffer, 20, stdin)) { minimum->lambda = 0; printf("Unrecognized input default %lf used\n", minimum->lambda); } else { sscanf(buffer, "%lf", &minimum->lambda); } strcpy(buffer, ""); printf("Please Enter Maximum Longitude (in decimal degrees):\n"); if (NULL == fgets(buffer, 20, stdin)){ maximum->lambda = 0; printf("Unrecognized input default %lf used\n", maximum->lambda); } else { sscanf(buffer, "%lf", &maximum->lambda); } strcpy(buffer, ""); printf("Please Enter Step Size (in decimal degrees):\n"); if (NULL == fgets(buffer, 20, stdin)){ *step_size = fmax(maximum->phi - minimum->phi, maximum->lambda - minimum->lambda); printf("Unrecognized input default %lf used\n", *step_size); } else { sscanf(buffer, "%lf", step_size); } strcpy(buffer, ""); printf("Select height (default : above MSL) \n1. Above Mean Sea Level\n2. Above WGS-84 Ellipsoid \n"); if (NULL == fgets(buffer, 20, stdin)) { Geoid->UseGeoid = 1; printf("Unrecognized option, height above MSL used."); } else { sscanf(buffer, "%d", &dummy); if(dummy == 2) Geoid->UseGeoid = 0; else Geoid->UseGeoid = 1; } strcpy(buffer, ""); if(Geoid->UseGeoid == 1) { printf("Please Enter Minimum Height above MSL (in km):\n"); if (NULL == fgets(buffer, 20, stdin)) { minimum->HeightAboveGeoid = 0; printf("Unrecognized input default %lf used\n", minimum->HeightAboveGeoid); } else { sscanf(buffer, "%lf", &minimum->HeightAboveGeoid); } strcpy(buffer, ""); printf("Please Enter Maximum Height above MSL (in km):\n"); if (NULL == fgets(buffer, 20, stdin)) { maximum->HeightAboveGeoid = 0; printf("Unrecognized input default %lf used\n", maximum->HeightAboveGeoid); } else { sscanf(buffer, "%lf", &maximum->HeightAboveGeoid); } strcpy(buffer, ""); } else { printf("Please Enter Minimum Height above the WGS-84 Ellipsoid (in km):\n"); if (NULL == fgets(buffer, 20, stdin)) { minimum->HeightAboveGeoid = 0; printf("Unrecognized input default %lf used\n", minimum->HeightAboveGeoid); } else { sscanf(buffer, "%lf", &minimum->HeightAboveGeoid); } minimum->HeightAboveEllipsoid = minimum->HeightAboveGeoid; strcpy(buffer, ""); printf("Please Enter Maximum Height above the WGS-84 Ellipsoid (in km):\n"); if (NULL == fgets(buffer, 20, stdin)) { maximum->HeightAboveGeoid = 0; printf("Unrecognized input default %lf used\n", maximum->HeightAboveGeoid); } else { sscanf(buffer, "%lf", &maximum->HeightAboveGeoid); } maximum->HeightAboveEllipsoid = maximum->HeightAboveGeoid; strcpy(buffer, ""); } printf("Please Enter height step size (in km):\n"); if (NULL == fgets(buffer, 20, stdin)) { *a_step_size = maximum->HeightAboveGeoid - minimum->HeightAboveGeoid; printf("Unrecognized input default %lf used\n", *a_step_size); } else { sscanf(buffer, "%lf", a_step_size); } strcpy(buffer, ""); printf("\nPlease Enter the decimal year starting time:\n"); while (NULL == fgets(buffer, 20, stdin)) { printf("\nUnrecognized input, please re-enter a decimal year\n"); } sscanf(buffer, "%lf", &StartDate->DecimalYear); strcpy(buffer, ""); printf("Please Enter the decimal year ending time:\n"); while (NULL == fgets(buffer, 20, stdin)) { printf("\nUnrecognized input, please re-enter a decimal year\n"); } sscanf(buffer, "%lf", &EndDate->DecimalYear); strcpy(buffer, ""); printf("Please Enter the time step size:\n"); if (NULL == fgets(buffer, 20, stdin)) { *step_time = EndDate->DecimalYear - StartDate->DecimalYear; printf("Unrecognized input, default of %lf used\n", *step_time); } else { sscanf(buffer, "%lf", step_time); } strcpy(buffer, ""); printf("Enter a geomagnetic element to print. Your options are:\n"); printf(" 1. Declination 9. Ddot\n 2. Inclination 10. Idot\n 3. F 11. Fdot\n 4. H 12. Hdot\n 5. X 13. Xdot\n 6. Y 14. Ydot\n 7. Z 15. Zdot\n 8. GV 16. GVdot\nFor gradients enter: 17\n"); if (NULL == fgets(buffer, 20, stdin)) { *ElementOption = 1; printf("Unrecognized input, default of %d used\n", *ElementOption); } sscanf(buffer, "%d", ElementOption); strcpy(buffer, ""); if(*ElementOption == 17) { printf("Enter a gradient element to print. Your options are:\n"); printf(" 1. dX/dphi \t2. dY/dphi \t3. dZ/dphi\n"); printf(" 4. dX/dlambda \t5. dY/dlambda \t6. dZ/dlambda\n"); printf(" 7. dX/dz \t8. dY/dz \t9. dZ/dz\n"); strcpy(buffer, ""); if (NULL == fgets(buffer, 20, stdin)) { *ElementOption=1; printf("Unrecognized input, default of %d used\n", *ElementOption); } else { sscanf(buffer, "%d", ElementOption); } strcpy(buffer, ""); *ElementOption+=16; } printf("Select output :\n"); printf(" 1. Print to a file \n 2. Print to Screen\n"); if (NULL ==fgets(buffer, 20, stdin)){ *PrintOption = 2; printf("Unrecognized input, default of printing to screen\n"); } else { sscanf(buffer, "%d", PrintOption); } strcpy(buffer, ""); fileout = fopen(filename, "a"); if(*PrintOption == 1) { printf("Please enter output filename\nfor default ('GridResults.txt') press enter:\n"); if(NULL==fgets(buffer, 20, stdin) || strlen(buffer) <= 1) { strcpy(OutputFile, "GridResults.txt"); fprintf(fileout, "\nResults printed in: GridResults.txt\n"); strcpy(OutputFile, "GridResults.txt"); } else { sscanf(buffer, "%s", OutputFile); fprintf(fileout, "\nResults printed in: %s\n", OutputFile); } /*strcpy(OutputFile, buffer);*/ strcpy(buffer, ""); /*sscanf(buffer, "%s", OutputFile);*/ } else fprintf(fileout, "\nResults printed in Console\n"); fprintf(fileout, "Minimum Latitude: %f\t\tMaximum Latitude: %f\t\tStep Size: %f\nMinimum Longitude: %f\t\tMaximum Longitude: %f\t\tStep Size: %f\n", minimum->phi, maximum->phi, *step_size, minimum->lambda, maximum->lambda, *step_size); if(Geoid->UseGeoid == 1) fprintf(fileout, "Minimum Altitude above MSL: %f\tMaximum Altitude above MSL: %f\tStep Size: %f\n", minimum->HeightAboveGeoid, maximum->HeightAboveGeoid, *a_step_size); else fprintf(fileout, "Minimum Altitude above WGS-84 Ellipsoid: %f\tMaximum Altitude above WGS-84 Ellipsoid: %f\tStep Size: %f\n", minimum->HeightAboveEllipsoid, maximum->HeightAboveEllipsoid, *a_step_size); fprintf(fileout, "Starting Date: %f\t\tEnding Date: %f\t\tStep Time: %f\n\n\n", StartDate->DecimalYear, EndDate->DecimalYear, *step_time); fclose(fileout); return TRUE; } int MAG_GetUserInput(MAGtype_MagneticModel *MagneticModel, MAGtype_Geoid *Geoid, MAGtype_CoordGeodetic *CoordGeodetic, MAGtype_Date *MagneticDate) /* This prompts the user for coordinates, and accepts many entry formats. It takes the MagneticModel and Geoid as input and outputs the Geographic coordinates and Date as objects. Returns 0 when the user wants to exit and 1 if the user enters valid input data. INPUT : MagneticModel : Data structure with the following elements used here double epoch; Base time of Geomagnetic model epoch (yrs) : Geoid Pointer to data structure MAGtype_Geoid (used for converting HeightAboveGeoid to HeightABoveEllipsoid OUTPUT: CoordGeodetic : Pointer to data structure. Following elements are updated double lambda; (longitude) double phi; ( geodetic latitude) double HeightAboveEllipsoid; (height above the ellipsoid (HaE) ) double HeightAboveGeoid;(height above the Geoid ) MagneticDate : Pointer to data structure MAGtype_Date with the following elements updated int Year; (If user directly enters decimal year this field is not populated) int Month;(If user directly enters decimal year this field is not populated) int Day; (If user directly enters decimal year this field is not populated) double DecimalYear; decimal years CALLS: MAG_DMSstringToDegree(buffer, &CoordGeodetic->lambda); (The program uses this to convert the string into a decimal longitude.) MAG_ValidateDMSstringlong(buffer, Error_Message) MAG_ValidateDMSstringlat(buffer, Error_Message) MAG_Warnings MAG_ConvertGeoidToEllipsoidHeight MAG_DateToYear */ { char Error_Message[255]; char buffer[40]; int i, j, a, b, c, done = 0; double lat_bound[2] = {LAT_BOUND_MIN, LAT_BOUND_MAX}; double lon_bound[2] = {LON_BOUND_MIN, LON_BOUND_MAX}; int alt_bound[2] = {ALT_BOUND_MIN, NO_ALT_MAX}; char* Qstring = malloc(sizeof(char) * 1028); strcpy(buffer, ""); /*Clear the input */ strcpy(Qstring, "\nPlease enter latitude\nNorth latitude positive, For example:\n30, 30, 30 (D,M,S) or 30.508 (Decimal Degrees) (both are north)\n"); MAG_GetDeg(Qstring, &CoordGeodetic->phi, lat_bound); strcpy(buffer, ""); /*Clear the input*/ strcpy(Qstring,"\nPlease enter longitude\nEast longitude positive, West negative. For example:\n-100.5 or -100, 30, 0 for 100.5 degrees west\n"); MAG_GetDeg(Qstring, &CoordGeodetic->lambda, lon_bound); strcpy(Qstring,"\nPlease enter height above mean sea level (in kilometers):\n[For height above WGS-84 ellipsoid prefix E, for example (E20.1)]\n"); if(MAG_GetAltitude(Qstring, Geoid, CoordGeodetic, alt_bound, FALSE)==USER_GAVE_UP) return FALSE; strcpy(buffer, ""); printf("\nPlease enter the decimal year or calendar date\n (YYYY.yyy, MM DD YYYY or MM/DD/YYYY):\n"); while (NULL == fgets(buffer, 40, stdin)) { printf("\nPlease enter the decimal year or calendar date\n (YYYY.yyy, MM DD YYYY or MM/DD/YYYY):\n"); } for(i = 0, done = 0; i <= 40 && !done; i++) { if(buffer[i] == '.') { j = sscanf(buffer, "%lf", &MagneticDate->DecimalYear); if(j == 1) done = 1; else buffer[i] = '\0'; } if(buffer[i] == '/') { sscanf(buffer, "%d/%d/%d", &MagneticDate->Month, &MagneticDate->Day, &MagneticDate->Year); if(!MAG_DateToYear(MagneticDate, Error_Message)) { printf("%s", Error_Message); printf("\nPlease re-enter Date in MM/DD/YYYY or MM DD YYYY format, or as a decimal year\n"); while (NULL == fgets(buffer, 40, stdin)) { printf("\nPlease re-enter Date in MM/DD/YYYY or MM DD YYYY format, or as a decimal year\n"); } i = 0; } else done = 1; } if((buffer[i] == ' ' && buffer[i + 1] != '/') || buffer[i] == '\0') { if(3 == sscanf(buffer, "%d %d %d", &a, &b, &c)) { MagneticDate->Month = a; MagneticDate->Day = b; MagneticDate->Year = c; MagneticDate->DecimalYear = 99999; } else if(1 == sscanf(buffer, "%d %d %d", &a, &b, &c)) { MagneticDate->DecimalYear = a; done = 1; } if(!(MagneticDate->DecimalYear == a)) { if(!MAG_DateToYear(MagneticDate, Error_Message)) { printf("%s", Error_Message); strcpy(buffer, ""); printf("\nError encountered, please re-enter Date in MM/DD/YYYY or MM DD YYYY format, or as a decimal year\n"); while( NULL== fgets(buffer, 40, stdin)){ printf("\nError encountered, please re-enter Date in MM/DD/YYYY or MM DD YYYY format, or as a decimal year\n"); } i = -1; } else done = 1; } } if(buffer[i] == '\0' && i != -1 && done != 1) { strcpy(buffer, ""); printf("\nError encountered, please re-enter as MM/DD/YYYY, MM DD YYYY, or as YYYY.yyy:\n"); while (NULL ==fgets(buffer, 40, stdin)) { printf("\nError encountered, please re-enter as MM/DD/YYYY, MM DD YYYY, or as YYYY.yyy:\n"); } i = -1; } if(done) { if(MagneticDate->DecimalYear > MagneticModel->CoefficientFileEndDate || MagneticDate->DecimalYear < MagneticModel->epoch) { switch(MAG_Warnings(4, MagneticDate->DecimalYear, MagneticModel)) { case 0: return 0; case 1: done = 0; i = -1; strcpy(buffer, ""); printf("\nPlease enter the decimal year or calendar date\n (YYYY.yyy, MM DD YYYY or MM/DD/YYYY):\n"); while(NULL == fgets(buffer, 40, stdin)){ printf("\nPlease enter the decimal year or calendar date\n (YYYY.yyy, MM DD YYYY or MM/DD/YYYY):\n"); } break; case 2: break; } } } } free(Qstring); return TRUE; } /*MAG_GetUserInput*/ void MAG_PrintGradient(MAGtype_Gradient Gradient) { printf("\nGradient\n"); printf("\n Northward Eastward Downward\n"); printf("X: %7.1f nT/km %9.1f nT/km %9.1f nT/km \n", Gradient.GradPhi.X, Gradient.GradLambda.X, Gradient.GradZ.X); printf("Y: %7.1f nT/km %9.1f nT/km %9.1f nT/km \n", Gradient.GradPhi.Y, Gradient.GradLambda.Y, Gradient.GradZ.Y); printf("Z: %7.1f nT/km %9.1f nT/km %9.1f nT/km \n", Gradient.GradPhi.Z, Gradient.GradLambda.Z, Gradient.GradZ.Z); printf("H: %7.1f nT/km %9.1f nT/km %9.1f nT/km \n", Gradient.GradPhi.H, Gradient.GradLambda.H, Gradient.GradZ.H); printf("F: %7.1f nT/km %9.1f nT/km %9.1f nT/km \n", Gradient.GradPhi.F, Gradient.GradLambda.F, Gradient.GradZ.F); printf("Declination: %7.2f min/km %8.2f min/km %8.2f min/km \n", Gradient.GradPhi.Decl * 60, Gradient.GradLambda.Decl * 60, Gradient.GradZ.Decl * 60); printf("Inclination: %7.2f min/km %8.2f min/km %8.2f min/km \n", Gradient.GradPhi.Incl * 60, Gradient.GradLambda.Incl * 60, Gradient.GradZ.Incl * 60); } void MAG_PrintUserData(MAGtype_GeoMagneticElements GeomagElements, MAGtype_CoordGeodetic SpaceInput, MAGtype_Date TimeInput, MAGtype_MagneticModel *MagneticModel, MAGtype_Geoid *Geoid) /* This function prints the results in Geomagnetic Elements for a point calculation. It takes the calculated * Geomagnetic elements "GeomagElements" as input. * As well as the coordinates, date, and Magnetic Model. INPUT : GeomagElements : Data structure MAGtype_GeoMagneticElements with the following elements double Decl; (Angle between the magnetic field vector and true north, positive east) double Incl; Angle between the magnetic field vector and the horizontal plane, positive down double F; Magnetic Field Strength double H; Horizontal Magnetic Field Strength double X; Northern component of the magnetic field vector double Y; Eastern component of the magnetic field vector double Z; Downward component of the magnetic field vector4 double Decldot; Yearly Rate of change in declination double Incldot; Yearly Rate of change in inclination double Fdot; Yearly rate of change in Magnetic field strength double Hdot; Yearly rate of change in horizontal field strength double Xdot; Yearly rate of change in the northern component double Ydot; Yearly rate of change in the eastern component double Zdot; Yearly rate of change in the downward component double GVdot;Yearly rate of chnage in grid variation CoordGeodetic Pointer to the data structure with the following elements double lambda; (longitude) double phi; ( geodetic latitude) double HeightAboveEllipsoid; (height above the ellipsoid (HaE) ) double HeightAboveGeoid;(height above the Geoid ) TimeInput : data structure MAGtype_Date with the following elements int Year; int Month; int Day; double DecimalYear; decimal years MagneticModel : data structure with the following elements double EditionDate; double epoch; Base time of Geomagnetic model epoch (yrs) char ModelName[20]; double *Main_Field_Coeff_G; C - Gauss coefficients of main geomagnetic model (nT) double *Main_Field_Coeff_H; C - Gauss coefficients of main geomagnetic model (nT) double *Secular_Var_Coeff_G; CD - Gauss coefficients of secular geomagnetic model (nT/yr) double *Secular_Var_Coeff_H; CD - Gauss coefficients of secular geomagnetic model (nT/yr) int nMax; Maximum degree of spherical harmonic model int nMaxSecVar; Maxumum degree of spherical harmonic secular model int SecularVariationUsed; Whether or not the magnetic secular variation vector will be needed by program OUTPUT : none */ { char DeclString[100]; char InclString[100]; MAG_DegreeToDMSstring(GeomagElements.Incl, 2, InclString); if(GeomagElements.H < 6000 && GeomagElements.H > 2000) MAG_Warnings(1, GeomagElements.H, MagneticModel); if(GeomagElements.H < 2000) MAG_Warnings(2, GeomagElements.H, MagneticModel); if(MagneticModel->SecularVariationUsed == TRUE) { MAG_DegreeToDMSstring(GeomagElements.Decl, 2, DeclString); printf("\n Results For \n\n"); if(SpaceInput.phi < 0) printf("Latitude %.2fS\n", -SpaceInput.phi); else printf("Latitude %.2fN\n", SpaceInput.phi); if(SpaceInput.lambda < 0) printf("Longitude %.2fW\n", -SpaceInput.lambda); else printf("Longitude %.2fE\n", SpaceInput.lambda); if(Geoid->UseGeoid == 1) printf("Altitude: %.2f Kilometers above mean sea level\n", SpaceInput.HeightAboveGeoid); else printf("Altitude: %.2f Kilometers above the WGS-84 ellipsoid\n", SpaceInput.HeightAboveEllipsoid); printf("Date: %.1f\n", TimeInput.DecimalYear); printf("\n Main Field\t\t\tSecular Change\n"); printf("F = %-9.1f nT\t\t Fdot = %.1f\tnT/yr\n", GeomagElements.F, GeomagElements.Fdot); printf("H = %-9.1f nT\t\t Hdot = %.1f\tnT/yr\n", GeomagElements.H, GeomagElements.Hdot); printf("X = %-9.1f nT\t\t Xdot = %.1f\tnT/yr\n", GeomagElements.X, GeomagElements.Xdot); printf("Y = %-9.1f nT\t\t Ydot = %.1f\tnT/yr\n", GeomagElements.Y, GeomagElements.Ydot); printf("Z = %-9.1f nT\t\t Zdot = %.1f\tnT/yr\n", GeomagElements.Z, GeomagElements.Zdot); if(GeomagElements.Decl < 0) printf("Decl =%20s (WEST)\t Ddot = %.1f\tMin/yr\n", DeclString, 60 * GeomagElements.Decldot); else printf("Decl =%20s (EAST)\t Ddot = %.1f\tMin/yr\n", DeclString, 60 * GeomagElements.Decldot); if(GeomagElements.Incl < 0) printf("Incl =%20s (UP)\t Idot = %.1f\tMin/yr\n", InclString, 60 * GeomagElements.Incldot); else printf("Incl =%20s (DOWN)\t Idot = %.1f\tMin/yr\n", InclString, 60 * GeomagElements.Incldot); } else { MAG_DegreeToDMSstring(GeomagElements.Decl, 2, DeclString); printf("\n Results For \n\n"); if(SpaceInput.phi < 0) printf("Latitude %.2fS\n", -SpaceInput.phi); else printf("Latitude %.2fN\n", SpaceInput.phi); if(SpaceInput.lambda < 0) printf("Longitude %.2fW\n", -SpaceInput.lambda); else printf("Longitude %.2fE\n", SpaceInput.lambda); if(Geoid->UseGeoid == 1) printf("Altitude: %.2f Kilometers above MSL\n", SpaceInput.HeightAboveGeoid); else printf("Altitude: %.2f Kilometers above WGS-84 Ellipsoid\n", SpaceInput.HeightAboveEllipsoid); printf("Date: %.1f\n", TimeInput.DecimalYear); printf("\n Main Field\n"); printf("F = %-9.1f nT\n", GeomagElements.F); printf("H = %-9.1f nT\n", GeomagElements.H); printf("X = %-9.1f nT\n", GeomagElements.X); printf("Y = %-9.1f nT\n", GeomagElements.Y); printf("Z = %-9.1f nT\n", GeomagElements.Z); if(GeomagElements.Decl < 0) printf("Decl =%20s (WEST)\n", DeclString); else printf("Decl =%20s (EAST)\n", DeclString); if(GeomagElements.Incl < 0) printf("Incl =%20s (UP)\n", InclString); else printf("Incl =%20s (DOWN)\n", InclString); } if(SpaceInput.phi <= -55 || SpaceInput.phi >= 55) /* Print Grid Variation */ { MAG_DegreeToDMSstring(GeomagElements.GV, 2, InclString); printf("\n\n Grid variation =%20s\n", InclString); } }/*MAG_PrintUserData*/ int MAG_ValidateDMSstring(char *input, int min, int max, char *Error) /* Validates a latitude DMS string, and returns 1 for a success and returns 0 for a failure. It copies an error message to the Error string in the event of a failure. INPUT : input (DMS string) OUTPUT : Error : Error string CALLS : none */ { int degree, minute, second, j = 0, n, max_minute = 60, max_second = 60; int i; degree = -1000; minute = -1; second = -1; n = (int) strlen(input); for(i = 0; i <= n - 1; i++) /*tests for legal characters*/ { if((input[i] < '0' || input[i] > '9') && (input[i] != ',' && input[i] != ' ' && input[i] != '-' && input[i] != '\0' && input[i] != '\n')) { strcpy(Error, "\nError: Input contains an illegal character, legal characters for Degree, Minute, Second format are:\n '0-9' ',' '-' '[space]' '[Enter]'\n"); return FALSE; } if(input[i] == ',') j++; } if(j == 2) j = sscanf(input, "%d, %d, %d", °ree, &minute, &second); /*tests for legal formatting and range*/ else j = sscanf(input, "%d %d %d", °ree, &minute, &second); if(j == 1) { minute = 0; second = 0; j = 3; } if(j != 3) { strcpy(Error, "\nError: Not enough numbers used for Degrees, Minutes, Seconds format\n or they were incorrectly formatted\n The legal format is DD,MM,SS or DD MM SS\n"); return FALSE; } if(degree > max || degree < min) { sprintf(Error, "\nError: Degree input is outside legal range\n The legal range is from %d to %d\n", min, max); return FALSE; } if(degree == max || degree == min) max_minute = 0; if(minute > max_minute || minute < 0) { strcpy(Error, "\nError: Minute input is outside legal range\n The legal minute range is from 0 to 60\n"); return FALSE; } if(minute == max_minute) max_second = 0; if(second > max_second || second < 0) { strcpy(Error, "\nError: Second input is outside legal range\n The legal second range is from 0 to 60\n"); return FALSE; } return TRUE; } /*MAG_ValidateDMSstring*/ int MAG_Warnings(int control, double value, MAGtype_MagneticModel *MagneticModel) /*Return value 0 means end program, Return value 1 means get new data, Return value 2 means continue. This prints a warning to the screen determined by the control integer. It also takes the value of the parameter causing the warning as a double. This is unnecessary for some warnings. It requires the MagneticModel to determine the current epoch. INPUT control :int : (Warning number) value : double: Magnetic field strength MagneticModel OUTPUT : none CALLS : none */ { char ans[20]; strcpy(ans, ""); switch(control) { case 1:/* Horizontal Field strength low */ do { printf("\nCaution: location is approaching the blackout zone around the magnetic pole as\n"); printf(" defined by the WMM military specification \n"); printf(" (https://www.ngdc.noaa.gov/geomag/WMM/data/MIL-PRF-89500B.pdf). Compass\n"); printf(" accuracy may be degraded in this region.\n"); printf("Press enter to continue...\n"); } while(NULL == fgets(ans, 20, stdin)); break; case 2:/* Horizontal Field strength very low */ do { printf("\nWarning: location is in the blackout zone around the magnetic pole as defined\n"); printf(" by the WMM military specification \n"); printf(" (https://www.ngdc.noaa.gov/geomag/WMM/data/MIL-PRF-89500B.pdf). Compass\n"); printf(" accuracy is highly degraded in this region.\n"); } while(NULL == fgets(ans, 20, stdin)); break; case 3:/* Elevation outside the recommended range */ printf("\nWarning: The value you have entered of %.1f km for the elevation is outside of the recommended range.\n Elevations above -10.0 km are recommended for accurate results. \n", value); while(1) { printf("\nPlease press 'C' to continue, 'G' to get new data or 'X' to exit...\n"); while( NULL == fgets(ans, 20, stdin)) { printf("\nInvalid input\n"); } switch(ans[0]) { case 'X': case 'x': return 0; case 'G': case 'g': return 1; case 'C': case 'c': return 2; default: printf("\nInvalid input %c\n", ans[0]); break; } } break; case 4:/*Date outside the recommended range*/ printf("\nWARNING - TIME EXTENDS BEYOND INTENDED USAGE RANGE\n CONTACT NCEI FOR PRODUCT UPDATES:\n"); printf(" National Centers for Environmental Information\n"); printf(" NOAA E/NE42\n"); printf(" 325 Broadway\n"); printf("\n Boulder, CO 80305 USA"); printf(" Attn: Manoj Nair or Arnaud Chulliat\n"); printf(" Phone: (303) 497-4642 or -6522\n"); printf(" Email: geomag.models@noaa.gov\n"); printf(" Web: http://www.ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml\n"); printf("\n VALID RANGE = %d - %d\n", (int) MagneticModel->epoch, (int) MagneticModel->CoefficientFileEndDate); printf(" TIME = %f\n", value); while(1) { printf("\nPlease press 'C' to continue, 'N' to enter new data or 'X' to exit...\n"); while (NULL ==fgets(ans, 20, stdin)){ printf("\nInvalid input\n"); } switch(ans[0]) { case 'X': case 'x': return 0; case 'N': case 'n': return 1; case 'C': case 'c': return 2; default: printf("\nInvalid input %c\n", ans[0]); break; } } break; case 5:/*Elevation outside the allowable range*/ printf("\nError: The value you have entered of %f km for the elevation is outside of the recommended range.\n Elevations above -10.0 km are recommended for accurate results. \n", value); while(1) { printf("\nPlease press 'C' to continue, 'G' to get new data or 'X' to exit...\n"); while (NULL ==fgets(ans, 20, stdin)){ printf("\nInvalid input\n"); } switch(ans[0]) { case 'X': case 'x': return 0; case 'G': case 'g': return 1; case 'C': case 'c': return 2; default: printf("\nInvalid input %c\n", ans[0]); break; } } break; } return 2; } /*MAG_Warnings*/ /*End of User Interface functions*/ /****************************************************************************** ********************************Memory and File Processing******************** * This grouping consists of functions that read coefficient files into the * memory, allocate memory, free memory or print models into coefficient files. ******************************************************************************/ MAGtype_LegendreFunction *MAG_AllocateLegendreFunctionMemory(int NumTerms) /* Allocate memory for Associated Legendre Function data types. Should be called before computing Associated Legendre Functions. INPUT: NumTerms : int : Total number of spherical harmonic coefficients in the model OUTPUT: Pointer to data structure MAGtype_LegendreFunction with the following elements double *Pcup; ( pointer to store Legendre Function ) double *dPcup; ( pointer to store Derivative of Legendre function ) FALSE: Failed to allocate memory CALLS : none */ { MAGtype_LegendreFunction *LegendreFunction; LegendreFunction = (MAGtype_LegendreFunction *) calloc(1, sizeof (MAGtype_LegendreFunction)); if(!LegendreFunction) { MAG_Error(1); return NULL; } LegendreFunction->Pcup = (double *) malloc((NumTerms + 1) * sizeof ( double)); if(LegendreFunction->Pcup == 0) { MAG_Error(1); return NULL; } LegendreFunction->dPcup = (double *) malloc((NumTerms + 1) * sizeof ( double)); if(LegendreFunction->dPcup == 0) { MAG_Error(1); return NULL; } return LegendreFunction; } /*MAGtype_LegendreFunction*/ MAGtype_MagneticModel *MAG_AllocateModelMemory(int NumTerms) /* Allocate memory for WMM Coefficients * Should be called before reading the model file * INPUT: NumTerms : int : Total number of spherical harmonic coefficients in the model OUTPUT: Pointer to data structure MAGtype_MagneticModel with the following elements double EditionDate; double epoch; Base time of Geomagnetic model epoch (yrs) char ModelName[20]; double *Main_Field_Coeff_G; C - Gauss coefficients of main geomagnetic model (nT) double *Main_Field_Coeff_H; C - Gauss coefficients of main geomagnetic model (nT) double *Secular_Var_Coeff_G; CD - Gauss coefficients of secular geomagnetic model (nT/yr) double *Secular_Var_Coeff_H; CD - Gauss coefficients of secular geomagnetic model (nT/yr) int nMax; Maximum degree of spherical harmonic model int nMaxSecVar; Maxumum degree of spherical harmonic secular model int SecularVariationUsed; Whether or not the magnetic secular variation vector will be needed by program FALSE: Failed to allocate memory CALLS : none */ { MAGtype_MagneticModel *MagneticModel; int i; MagneticModel = (MAGtype_MagneticModel *) calloc(1, sizeof (MAGtype_MagneticModel)); if(MagneticModel == NULL) { MAG_Error(2); return NULL; } MagneticModel->Main_Field_Coeff_G = (double *) malloc((NumTerms + 1) * sizeof ( double)); if(MagneticModel->Main_Field_Coeff_G == NULL) { MAG_Error(2); return NULL; } MagneticModel->Main_Field_Coeff_H = (double *) malloc((NumTerms + 1) * sizeof ( double)); if(MagneticModel->Main_Field_Coeff_H == NULL) { MAG_Error(2); return NULL; } MagneticModel->Secular_Var_Coeff_G = (double *) malloc((NumTerms + 1) * sizeof ( double)); if(MagneticModel->Secular_Var_Coeff_G == NULL) { MAG_Error(2); return NULL; } MagneticModel->Secular_Var_Coeff_H = (double *) malloc((NumTerms + 1) * sizeof ( double)); if(MagneticModel->Secular_Var_Coeff_H == NULL) { MAG_Error(2); return NULL; } MagneticModel->CoefficientFileEndDate = 0; MagneticModel->EditionDate = 0; strcpy(MagneticModel->ModelName, ""); MagneticModel->SecularVariationUsed = 0; MagneticModel->epoch = 0; MagneticModel->nMax = 0; MagneticModel->nMaxSecVar = 0; for(i=0; iMain_Field_Coeff_G[i] = 0; MagneticModel->Main_Field_Coeff_H[i] = 0; MagneticModel->Secular_Var_Coeff_G[i] = 0; MagneticModel->Secular_Var_Coeff_H[i] = 0; } return MagneticModel; } /*MAG_AllocateModelMemory*/ MAGtype_SphericalHarmonicVariables* MAG_AllocateSphVarMemory(int nMax) { MAGtype_SphericalHarmonicVariables* SphVariables; SphVariables = (MAGtype_SphericalHarmonicVariables*) calloc(1, sizeof(MAGtype_SphericalHarmonicVariables)); SphVariables->RelativeRadiusPower = (double *) malloc((nMax + 1) * sizeof ( double)); SphVariables->cos_mlambda = (double *) malloc((nMax + 1) * sizeof (double)); SphVariables->sin_mlambda = (double *) malloc((nMax + 1) * sizeof (double)); return SphVariables; } /*MAG_AllocateSphVarMemory*/ void MAG_AssignHeaderValues(MAGtype_MagneticModel *model, char values[][MAXLINELENGTH]) { /* MAGtype_Date releasedate; */ strcpy(model->ModelName, values[MODELNAME]); /* releasedate.Year = 0; releasedate.Day = 0; releasedate.Month = 0; releasedate.DecimalYear = 0; sscanf(values[RELEASEDATE],"%d-%d-%d",&releasedate.Year,&releasedate.Month,&releasedate.Day); if(MAG_DateToYear (&releasedate, NULL)) model->EditionDate = releasedate.DecimalYear;*/ model->epoch = atof(values[MODELSTARTYEAR]); model->nMax = atoi(values[INTSTATICDEG]); model->nMaxSecVar = atoi(values[INTSECVARDEG]); model->CoefficientFileEndDate = atof(values[MODELENDYEAR]); if(model->nMaxSecVar > 0) model->SecularVariationUsed = 1; else model->SecularVariationUsed = 0; } void MAG_AssignMagneticModelCoeffs(MAGtype_MagneticModel *Assignee, MAGtype_MagneticModel *Source, int nMax, int nMaxSecVar) /* This function assigns the first nMax degrees of the Source model to the Assignee model, leaving the other coefficients untouched*/ { int n, m, index; assert(nMax <= Source->nMax); assert(nMax <= Assignee->nMax); assert(nMaxSecVar <= Source->nMaxSecVar); assert(nMaxSecVar <= Assignee->nMaxSecVar); for(n = 1; n <= nMaxSecVar; n++) { for(m = 0; m <= n; m++) { index = (n * (n + 1) / 2 + m); Assignee->Main_Field_Coeff_G[index] = Source->Main_Field_Coeff_G[index]; Assignee->Main_Field_Coeff_H[index] = Source->Main_Field_Coeff_H[index]; Assignee->Secular_Var_Coeff_G[index] = Source->Secular_Var_Coeff_G[index]; Assignee->Secular_Var_Coeff_H[index] = Source->Secular_Var_Coeff_H[index]; } } for(n = nMaxSecVar + 1; n <= nMax; n++) { for(m = 0; m <= n; m++) { index = (n * (n + 1) / 2 + m); Assignee->Main_Field_Coeff_G[index] = Source->Main_Field_Coeff_G[index]; Assignee->Main_Field_Coeff_H[index] = Source->Main_Field_Coeff_H[index]; } } return; } /*MAG_AssignMagneticModelCoeffs*/ int MAG_FreeMemory(MAGtype_MagneticModel *MagneticModel, MAGtype_MagneticModel *TimedMagneticModel, MAGtype_LegendreFunction *LegendreFunction) /* Free memory used by WMM functions. Only to be called at the end of the main function. INPUT : MagneticModel pointer to data structure with the following elements double EditionDate; double epoch; Base time of Geomagnetic model epoch (yrs) char ModelName[20]; double *Main_Field_Coeff_G; C - Gauss coefficients of main geomagnetic model (nT) double *Main_Field_Coeff_H; C - Gauss coefficients of main geomagnetic model (nT) double *Secular_Var_Coeff_G; CD - Gauss coefficients of secular geomagnetic model (nT/yr) double *Secular_Var_Coeff_H; CD - Gauss coefficients of secular geomagnetic model (nT/yr) int nMax; Maximum degree of spherical harmonic model int nMaxSecVar; Maxumum degree of spherical harmonic secular model int SecularVariationUsed; Whether or not the magnetic secular variation vector will be needed by program TimedMagneticModel Pointer to data structure similar to the first input. LegendreFunction Pointer to data structure with the following elements double *Pcup; ( pointer to store Legendre Function ) double *dPcup; ( pointer to store Derivative of Lagendre function ) OUTPUT none CALLS : none */ { if(MagneticModel->Main_Field_Coeff_G) { free(MagneticModel->Main_Field_Coeff_G); MagneticModel->Main_Field_Coeff_G = NULL; } if(MagneticModel->Main_Field_Coeff_H) { free(MagneticModel->Main_Field_Coeff_H); MagneticModel->Main_Field_Coeff_H = NULL; } if(MagneticModel->Secular_Var_Coeff_G) { free(MagneticModel->Secular_Var_Coeff_G); MagneticModel->Secular_Var_Coeff_G = NULL; } if(MagneticModel->Secular_Var_Coeff_H) { free(MagneticModel->Secular_Var_Coeff_H); MagneticModel->Secular_Var_Coeff_H = NULL; } if(MagneticModel) { free(MagneticModel); MagneticModel = NULL; } if(TimedMagneticModel->Main_Field_Coeff_G) { free(TimedMagneticModel->Main_Field_Coeff_G); TimedMagneticModel->Main_Field_Coeff_G = NULL; } if(TimedMagneticModel->Main_Field_Coeff_H) { free(TimedMagneticModel->Main_Field_Coeff_H); TimedMagneticModel->Main_Field_Coeff_H = NULL; } if(TimedMagneticModel->Secular_Var_Coeff_G) { free(TimedMagneticModel->Secular_Var_Coeff_G); TimedMagneticModel->Secular_Var_Coeff_G = NULL; } if(TimedMagneticModel->Secular_Var_Coeff_H) { free(TimedMagneticModel->Secular_Var_Coeff_H); TimedMagneticModel->Secular_Var_Coeff_H = NULL; } if(TimedMagneticModel) { free(TimedMagneticModel); TimedMagneticModel = NULL; } if(LegendreFunction->Pcup) { free(LegendreFunction->Pcup); LegendreFunction->Pcup = NULL; } if(LegendreFunction->dPcup) { free(LegendreFunction->dPcup); LegendreFunction->dPcup = NULL; } if(LegendreFunction) { free(LegendreFunction); LegendreFunction = NULL; } return TRUE; } /*MAG_FreeMemory */ int MAG_FreeMagneticModelMemory(MAGtype_MagneticModel *MagneticModel) /* Free the magnetic model memory used by WMM functions. INPUT : MagneticModel pointer to data structure with the following elements double EditionDate; double epoch; Base time of Geomagnetic model epoch (yrs) char ModelName[20]; double *Main_Field_Coeff_G; C - Gauss coefficients of main geomagnetic model (nT) double *Main_Field_Coeff_H; C - Gauss coefficients of main geomagnetic model (nT) double *Secular_Var_Coeff_G; CD - Gauss coefficients of secular geomagnetic model (nT/yr) double *Secular_Var_Coeff_H; CD - Gauss coefficients of secular geomagnetic model (nT/yr) int nMax; Maximum degree of spherical harmonic model int nMaxSecVar; Maxumum degree of spherical harmonic secular model int SecularVariationUsed; Whether or not the magnetic secular variation vector will be needed by program OUTPUT none CALLS : none */ { if(MagneticModel->Main_Field_Coeff_G) { free(MagneticModel->Main_Field_Coeff_G); MagneticModel->Main_Field_Coeff_G = NULL; } if(MagneticModel->Main_Field_Coeff_H) { free(MagneticModel->Main_Field_Coeff_H); MagneticModel->Main_Field_Coeff_H = NULL; } if(MagneticModel->Secular_Var_Coeff_G) { free(MagneticModel->Secular_Var_Coeff_G); MagneticModel->Secular_Var_Coeff_G = NULL; } if(MagneticModel->Secular_Var_Coeff_H) { free(MagneticModel->Secular_Var_Coeff_H); MagneticModel->Secular_Var_Coeff_H = NULL; } if(MagneticModel) { free(MagneticModel); MagneticModel = NULL; } return TRUE; } /*MAG_FreeMagneticModelMemory */ int MAG_FreeLegendreMemory(MAGtype_LegendreFunction *LegendreFunction) /* Free the Legendre Coefficients memory used by the WMM functions. INPUT : LegendreFunction Pointer to data structure with the following elements double *Pcup; ( pointer to store Legendre Function ) double *dPcup; ( pointer to store Derivative of Lagendre function ) OUTPUT: none CALLS : none */ { if(LegendreFunction->Pcup) { free(LegendreFunction->Pcup); LegendreFunction->Pcup = NULL; } if(LegendreFunction->dPcup) { free(LegendreFunction->dPcup); LegendreFunction->dPcup = NULL; } if(LegendreFunction) { free(LegendreFunction); LegendreFunction = NULL; } return TRUE; } /*MAG_FreeLegendreMemory */ int MAG_FreeSphVarMemory(MAGtype_SphericalHarmonicVariables *SphVar) /* Free the Spherical Harmonic Variable memory used by the WMM functions. INPUT : LegendreFunction Pointer to data structure with the following elements double *RelativeRadiusPower double *cos_mlambda double *sin_mlambda OUTPUT: none CALLS : none */ { if(SphVar->RelativeRadiusPower) { free(SphVar->RelativeRadiusPower); SphVar->RelativeRadiusPower = NULL; } if(SphVar->cos_mlambda) { free(SphVar->cos_mlambda); SphVar->cos_mlambda = NULL; } if(SphVar->sin_mlambda) { free(SphVar->sin_mlambda); SphVar->sin_mlambda = NULL; } if(SphVar) { free(SphVar); SphVar = NULL; } return TRUE; } /*MAG_FreeSphVarMemory*/ void MAG_PrintWMMFormat(char *filename, MAGtype_MagneticModel *MagneticModel) { int index, n, m; FILE *OUT; MAGtype_Date Date; char Datestring[11]; Date.DecimalYear = MagneticModel->EditionDate; MAG_YearToDate(&Date); sprintf(Datestring, "%d/%d/%d", Date.Month, Date.Day, Date.Year); OUT = fopen(filename, "w"); fprintf(OUT, " %.1f %s %s\n", MagneticModel->epoch, MagneticModel->ModelName, Datestring); for(n = 1; n <= MagneticModel->nMax; n++) { for(m = 0; m <= n; m++) { index = (n * (n + 1) / 2 + m); if(m != 0) fprintf(OUT, " %2d %2d %9.4f %9.4f %9.4f %9.4f\n", n, m, MagneticModel->Main_Field_Coeff_G[index], MagneticModel->Main_Field_Coeff_H[index], MagneticModel->Secular_Var_Coeff_G[index], MagneticModel->Secular_Var_Coeff_H[index]); else fprintf(OUT, " %2d %2d %9.4f %9.4f %9.4f %9.4f\n", n, m, MagneticModel->Main_Field_Coeff_G[index], 0.0, MagneticModel->Secular_Var_Coeff_G[index], 0.0); } } fclose(OUT); } /*MAG_PrintWMMFormat*/ void MAG_PrintEMMFormat(char *filename, char *filenameSV, MAGtype_MagneticModel *MagneticModel) { int index, n, m; FILE *OUT; MAGtype_Date Date; char Datestring[11]; Date.DecimalYear = MagneticModel->EditionDate; MAG_YearToDate(&Date); sprintf(Datestring, "%d/%d/%d", Date.Month, Date.Day, Date.Year); OUT = fopen(filename, "w"); fprintf(OUT, " %.1f %s %s\n", MagneticModel->epoch, MagneticModel->ModelName, Datestring); for(n = 1; n <= MagneticModel->nMax; n++) { for(m = 0; m <= n; m++) { index = (n * (n + 1) / 2 + m); if(m != 0) fprintf(OUT, " %2d %2d %9.4f %9.4f\n", n, m, MagneticModel->Main_Field_Coeff_G[index], MagneticModel->Main_Field_Coeff_H[index]); else fprintf(OUT, " %2d %2d %9.4f %9.4f\n", n, m, MagneticModel->Main_Field_Coeff_G[index], 0.0); } } fclose(OUT); OUT = fopen(filenameSV, "w"); for(n = 1; n <= MagneticModel->nMaxSecVar; n++) { for(m = 0; m <= n; m++) { index = (n * (n + 1) / 2 + m); if(m != 0) fprintf(OUT, " %2d %2d %9.4f %9.4f\n", n, m, MagneticModel->Secular_Var_Coeff_G[index], MagneticModel->Secular_Var_Coeff_H[index]); else fprintf(OUT, " %2d %2d %9.4f %9.4f\n", n, m, MagneticModel->Secular_Var_Coeff_G[index], 0.0); } } fclose(OUT); return; } /*MAG_PrintEMMFormat*/ void MAG_PrintSHDFFormat(char *filename, MAGtype_MagneticModel *(*MagneticModel)[], int epochs) { int i, n, m, index, epochRange; FILE *SHDF_file; SHDF_file = fopen(filename, "w"); /*lines = (int)(UFM_DEGREE / 2.0 * (UFM_DEGREE + 3));*/ for(i = 0; i < epochs; i++) { if(i < epochs - 1) epochRange = (*MagneticModel)[i+1]->epoch - (*MagneticModel)[i]->epoch; else epochRange = (*MagneticModel)[i]->epoch - (*MagneticModel)[i-1]->epoch; fprintf(SHDF_file, "%%SHDF 16695 Definitive Geomagnetic Reference Field Model Coefficient File\n"); fprintf(SHDF_file, "%%ModelName: %s\n", (*MagneticModel)[i]->ModelName); fprintf(SHDF_file, "%%Publisher: International Association of Geomagnetism and Aeronomy (IAGA), Working Group V-Mod\n"); fprintf(SHDF_file, "%%ReleaseDate: Some Number\n"); fprintf(SHDF_file, "%%DataCutOFF: Some Other Number\n"); fprintf(SHDF_file, "%%ModelStartYear: %d\n", (int)(*MagneticModel)[i]->epoch); fprintf(SHDF_file, "%%ModelEndYear: %d\n", (int)(*MagneticModel)[i]->epoch+epochRange); fprintf(SHDF_file, "%%Epoch: %.0f\n", (*MagneticModel)[i]->epoch); fprintf(SHDF_file, "%%IntStaticDeg: %d\n", (*MagneticModel)[i]->nMax); fprintf(SHDF_file, "%%IntSecVarDeg: %d\n", (*MagneticModel)[i]->nMaxSecVar); fprintf(SHDF_file, "%%ExtStaticDeg: 0\n"); fprintf(SHDF_file, "%%ExtSecVarDeg: 0\n"); fprintf(SHDF_file, "%%Normalization: Schmidt semi-normailized\n"); fprintf(SHDF_file, "%%SpatBasFunc: spherical harmonics\n"); fprintf(SHDF_file, "# To synthesize the field for a given date:\n"); fprintf(SHDF_file, "# Use the sub-model of the epoch corresponding to each date\n"); fprintf(SHDF_file, "#\n#\n#\n#\n# I/E, n, m, Gnm, Hnm, SV-Gnm, SV-Hnm\n#\n"); n = 1; m = 0; for(n = 1; n <= (*MagneticModel)[i]->nMax; n++) { for(m = 0; m <= n; m++) { index = (n * (n+1)) / 2 + m; if(i < epochs - 1) { if(m != 0) fprintf(SHDF_file, "I,%d,%d,%f,%f,%f,%f\n", n, m, (*MagneticModel)[i]->Main_Field_Coeff_G[index], (*MagneticModel)[i]->Main_Field_Coeff_H[index], (*MagneticModel)[i]->Secular_Var_Coeff_G[index], (*MagneticModel)[i]->Secular_Var_Coeff_H[index]); else fprintf(SHDF_file, "I,%d,%d,%f,,%f,\n", n, m, (*MagneticModel)[i]->Main_Field_Coeff_G[index], (*MagneticModel)[i]->Secular_Var_Coeff_G[index]); } else { if(m != 0) fprintf(SHDF_file, "I,%d,%d,%f,%f,%f,%f\n", n, m, (*MagneticModel)[i]->Main_Field_Coeff_G[index], (*MagneticModel)[i]->Main_Field_Coeff_H[index], (*MagneticModel)[i]->Secular_Var_Coeff_G[index], (*MagneticModel)[i]->Secular_Var_Coeff_H[index]); else fprintf(SHDF_file, "I,%d,%d,%f,,%f,\n", n, m, (*MagneticModel)[i]->Main_Field_Coeff_G[index], (*MagneticModel)[i]->Secular_Var_Coeff_G[index]); } } } } } /*MAG_PrintSHDFFormat*/ int MAG_readMagneticModel(char *filename, MAGtype_MagneticModel * MagneticModel) { /* READ WORLD Magnetic MODEL SPHERICAL HARMONIC COEFFICIENTS (WMM.cof) INPUT : filename MagneticModel : Pointer to the data structure with the following fields required as inputs nMax : Number of static coefficients UPDATES : MagneticModel : Pointer to the data structure with the following fields populated char *ModelName; double epoch; Base time of Geomagnetic model epoch (yrs) double *Main_Field_Coeff_G; C - Gauss coefficients of main geomagnetic model (nT) double *Main_Field_Coeff_H; C - Gauss coefficients of main geomagnetic model (nT) double *Secular_Var_Coeff_G; CD - Gauss coefficients of secular geomagnetic model (nT/yr) double *Secular_Var_Coeff_H; CD - Gauss coefficients of secular geomagnetic model (nT/yr) CALLS : none */ FILE *MAG_COF_File; char c_str[81], c_new[5]; /*these strings are used to read a line from coefficient file*/ int i, icomp, m, n, EOF_Flag = 0, index; double epoch, gnm, hnm, dgnm, dhnm; MAG_COF_File = fopen(filename, "r"); if(MAG_COF_File == NULL) { MAG_Error(20); return FALSE; /* should we have a standard error printing routine ?*/ } MagneticModel->Main_Field_Coeff_H[0] = 0.0; MagneticModel->Main_Field_Coeff_G[0] = 0.0; MagneticModel->Secular_Var_Coeff_H[0] = 0.0; MagneticModel->Secular_Var_Coeff_G[0] = 0.0; fgets(c_str, 80, MAG_COF_File); sscanf(c_str, "%lf%s", &epoch, MagneticModel->ModelName); MagneticModel->epoch = epoch; while(EOF_Flag == 0) { if (NULL == fgets(c_str, 80, MAG_COF_File)){ break; } /* CHECK FOR LAST LINE IN FILE */ for(i = 0; i < 4 && (c_str[i] != '\0'); i++) { c_new[i] = c_str[i]; c_new[i + 1] = '\0'; } icomp = strcmp("9999", c_new); if(icomp == 0) { EOF_Flag = 1; break; } /* END OF FILE NOT ENCOUNTERED, GET VALUES */ sscanf(c_str, "%d%d%lf%lf%lf%lf", &n, &m, &gnm, &hnm, &dgnm, &dhnm); if(m <= n) { index = (n * (n + 1) / 2 + m); MagneticModel->Main_Field_Coeff_G[index] = gnm; MagneticModel->Secular_Var_Coeff_G[index] = dgnm; MagneticModel->Main_Field_Coeff_H[index] = hnm; MagneticModel->Secular_Var_Coeff_H[index] = dhnm; } } fclose(MAG_COF_File); return TRUE; } /*MAG_readMagneticModel*/ int MAG_readMagneticModel_Large(char *filename, char *filenameSV, MAGtype_MagneticModel *MagneticModel) /* To read the high-degree model coefficients (for example, NGDC 720) INPUT : filename file name for static coefficients filenameSV file name for secular variation coefficients MagneticModel : Pointer to the data structure with the following fields required as inputs nMaxSecVar : Number of secular variation coefficients nMax : Number of static coefficients UPDATES : MagneticModel : Pointer to the data structure with the following fields populated double epoch; Base time of Geomagnetic model epoch (yrs) double *Main_Field_Coeff_G; C - Gauss coefficients of main geomagnetic model (nT) double *Main_Field_Coeff_H; C - Gauss coefficients of main geomagnetic model (nT) double *Secular_Var_Coeff_G; CD - Gauss coefficients of secular geomagnetic model (nT/yr) double *Secular_Var_Coeff_H; CD - Gauss coefficients of secular geomagnetic model (nT/yr) CALLS : none */ { FILE *MAG_COF_File; FILE *MAG_COFSV_File; char c_str[81], c_str2[81]; /* these strings are used to read a line from coefficient file */ int i, m, n, index, a, b; double epoch, gnm, hnm, dgnm, dhnm; MAG_COF_File = fopen(filename, "r"); MAG_COFSV_File = fopen(filenameSV, "r"); if(MAG_COF_File == NULL || MAG_COFSV_File == NULL) { MAG_Error(20); return FALSE; } MagneticModel->Main_Field_Coeff_H[0] = 0.0; MagneticModel->Main_Field_Coeff_G[0] = 0.0; MagneticModel->Secular_Var_Coeff_H[0] = 0.0; MagneticModel->Secular_Var_Coeff_G[0] = 0.0; if (NULL == fgets(c_str, 80, MAG_COF_File)){ fclose(MAG_COF_File); fclose(MAG_COFSV_File); return FALSE; } sscanf(c_str, "%lf%s", &epoch, MagneticModel->ModelName); MagneticModel->epoch = epoch; a = CALCULATE_NUMTERMS(MagneticModel->nMaxSecVar); b = CALCULATE_NUMTERMS(MagneticModel->nMax); for(i = 0; i < a; i++) { if (NULL == fgets(c_str, 80, MAG_COF_File)){ fclose(MAG_COF_File); fclose(MAG_COFSV_File); return FALSE; } sscanf(c_str, "%d%d%lf%lf", &n, &m, &gnm, &hnm); if (NULL == fgets(c_str2, 80, MAG_COFSV_File)){ fclose(MAG_COF_File); fclose(MAG_COFSV_File); return FALSE; } sscanf(c_str2, "%d%d%lf%lf", &n, &m, &dgnm, &dhnm); if(m <= n) { index = (n * (n + 1) / 2 + m); MagneticModel->Main_Field_Coeff_G[index] = gnm; MagneticModel->Secular_Var_Coeff_G[index] = dgnm; MagneticModel->Main_Field_Coeff_H[index] = hnm; MagneticModel->Secular_Var_Coeff_H[index] = dhnm; } } for(i = a; i < b; i++) { if (NULL == fgets(c_str, 80, MAG_COF_File)){ fclose(MAG_COF_File); fclose(MAG_COFSV_File); return FALSE; } sscanf(c_str, "%d%d%lf%lf", &n, &m, &gnm, &hnm); if(m <= n) { index = (n * (n + 1) / 2 + m); MagneticModel->Main_Field_Coeff_G[index] = gnm; MagneticModel->Main_Field_Coeff_H[index] = hnm; } } if(MAG_COF_File != NULL && MAG_COFSV_File != NULL) { fclose(MAG_COF_File); fclose(MAG_COFSV_File); } return TRUE; } /*MAG_readMagneticModel_Large*/ int MAG_readMagneticModel_SHDF(char *filename, MAGtype_MagneticModel *(*magneticmodels)[], int array_size) /* * MAG_readMagneticModels - Read the Magnetic Models from an SHDF format file * * Input: * filename - Path to the SHDF format model file to be read * array_size - Max No of models to be read from the file * * Output: * magneticmodels[] - Array of magnetic models read from the file * * Return value: * Returns the number of models read from the file. * -2 implies that internal or external static degree was not found in the file, hence memory cannot be allocated * -1 implies some error during file processing (I/O) * 0 implies no models were read from the file * if ReturnValue > array_size then there were too many models in model file but only number were read . * if ReturnValue <= array_size then the function execution was successful. */ { char paramkeys[NOOFPARAMS][MAXLINELENGTH] = { "SHDF ", "ModelName: ", "Publisher: ", "ReleaseDate: ", "DataCutOff: ", "ModelStartYear: ", "ModelEndYear: ", "Epoch: ", "IntStaticDeg: ", "IntSecVarDeg: ", "ExtStaticDeg: ", "ExtSecVarDeg: ", "GeoMagRefRad: ", "Normalization: ", "SpatBasFunc: " }; char paramvalues[NOOFPARAMS][MAXLINELENGTH]; char *line = (char *) malloc(MAXLINELENGTH); char *ptrreset; char paramvalue[MAXLINELENGTH]; int paramvaluelength = 0; int paramkeylength = 0; int i = 0, j = 0; int newrecord = 1; int header_index = -1; int numterms; int tempint; int allocationflag = 0; char coefftype; /* Internal or External (I/E) */ /* For reading coefficients */ int n, m; double gnm, hnm, dgnm, dhnm, cutoff; int index; FILE *stream; ptrreset = line; stream = fopen(filename, READONLYMODE); if(stream == NULL) { perror("File open error"); return header_index; } /* Read records from the model file and store header information. */ while(fgets(line, MAXLINELENGTH, stream) != NULL) { j++; if(strlen(MAG_Trim(line)) == 0) continue; if(*line == '%') { line++; if(newrecord) { if(header_index > -1) { MAG_AssignHeaderValues((*magneticmodels)[header_index], paramvalues); } header_index++; if(header_index >= array_size) { fprintf(stderr, "Header limit exceeded - too many models in model file. (%d)\n", header_index); return array_size + 1; } newrecord = 0; allocationflag = 0; } for(i = 0; i < NOOFPARAMS; i++) { paramkeylength = strlen(paramkeys[i]); if(!strncmp(line, paramkeys[i], paramkeylength)) { paramvaluelength = strlen(line) - paramkeylength; strncpy(paramvalue, line + paramkeylength, paramvaluelength); paramvalue[paramvaluelength] = '\0'; strcpy(paramvalues[i], paramvalue); if(!strcmp(paramkeys[i], paramkeys[INTSTATICDEG]) || !strcmp(paramkeys[i], paramkeys[EXTSTATICDEG])) { tempint = atoi(paramvalues[i]); if(tempint > 0 && allocationflag == 0) { numterms = CALCULATE_NUMTERMS(tempint); (*magneticmodels)[header_index] = MAG_AllocateModelMemory(numterms); /* model = (*magneticmodels)[header_index]; */ allocationflag = 1; } } break; } } line--; } else if(*line == '#') { /* process comments */ } else if(sscanf(line, "%c,%d,%d", &coefftype, &n, &m) == 3) { if(m == 0) { sscanf(line, "%c,%d,%d,%lf,,%lf,", &coefftype, &n, &m, &gnm, &dgnm); hnm = 0; dhnm = 0; } else sscanf(line, "%c,%d,%d,%lf,%lf,%lf,%lf", &coefftype, &n, &m, &gnm, &hnm, &dgnm, &dhnm); newrecord = 1; if(!allocationflag) { fprintf(stderr, "Degree not found in model. Memory cannot be allocated.\n"); return _DEGREE_NOT_FOUND; } if(m <= n) { index = (n * (n + 1) / 2 + m); (*magneticmodels)[header_index]->Main_Field_Coeff_G[index] = gnm; (*magneticmodels)[header_index]->Secular_Var_Coeff_G[index] = dgnm; (*magneticmodels)[header_index]->Main_Field_Coeff_H[index] = hnm; (*magneticmodels)[header_index]->Secular_Var_Coeff_H[index] = dhnm; } } } if(header_index > -1) MAG_AssignHeaderValues((*magneticmodels)[header_index], paramvalues); fclose(stream); cutoff = (*magneticmodels)[array_size - 1]->CoefficientFileEndDate; for(i = 0; i < array_size; i++) (*magneticmodels)[i]->CoefficientFileEndDate = cutoff; free(ptrreset); line = NULL; ptrreset = NULL; return header_index + 1; }/*MAG_readMagneticModel_SHDF*/ char *MAG_Trim(char *str) { char *end; while(isspace(*str)) str++; if(*str == 0) return str; end = str + strlen(str) - 1; while(end > str && isspace(*end)) end--; *(end + 1) = 0; return str; } /*End of Memory and File Processing functions*/ /****************************************************************************** *************Conversions, Transformations, and other Calculations************** * This grouping consists of functions that perform unit conversions, coordinate * transformations and other simple or straightforward calculations that are * usually easily replicable with a typical scientific calculator. ******************************************************************************/ void MAG_BaseErrors(double DeclCoef, double DeclBaseline, double InclOffset, double FOffset, double Multiplier, double H, double* DeclErr, double* InclErr, double* FErr) { double declHorizontalAdjustmentSq; declHorizontalAdjustmentSq = (DeclCoef/H) * (DeclCoef/H); *DeclErr = sqrt(declHorizontalAdjustmentSq + DeclBaseline*DeclBaseline) * Multiplier; *InclErr = InclOffset*Multiplier; *FErr = FOffset*Multiplier; } int MAG_CalculateGeoMagneticElements(MAGtype_MagneticResults *MagneticResultsGeo, MAGtype_GeoMagneticElements *GeoMagneticElements) /* Calculate all the Geomagnetic elements from X,Y and Z components INPUT MagneticResultsGeo Pointer to data structure with the following elements double Bx; ( North ) double By; ( East ) double Bz; ( Down ) OUTPUT GeoMagneticElements Pointer to data structure with the following elements double Decl; (Angle between the magnetic field vector and true north, positive east) double Incl; Angle between the magnetic field vector and the horizontal plane, positive down double F; Magnetic Field Strength double H; Horizontal Magnetic Field Strength double X; Northern component of the magnetic field vector double Y; Eastern component of the magnetic field vector double Z; Downward component of the magnetic field vector CALLS : none */ { GeoMagneticElements->X = MagneticResultsGeo->Bx; GeoMagneticElements->Y = MagneticResultsGeo->By; GeoMagneticElements->Z = MagneticResultsGeo->Bz; GeoMagneticElements->H = sqrt(MagneticResultsGeo->Bx * MagneticResultsGeo->Bx + MagneticResultsGeo->By * MagneticResultsGeo->By); GeoMagneticElements->F = sqrt(GeoMagneticElements->H * GeoMagneticElements->H + MagneticResultsGeo->Bz * MagneticResultsGeo->Bz); GeoMagneticElements->Decl = RAD2DEG(atan2(GeoMagneticElements->Y, GeoMagneticElements->X)); GeoMagneticElements->Incl = RAD2DEG(atan2(GeoMagneticElements->Z, GeoMagneticElements->H)); return TRUE; } /*MAG_CalculateGeoMagneticElements */ int MAG_CalculateGridVariation(MAGtype_CoordGeodetic location, MAGtype_GeoMagneticElements *elements) /*Computes the grid variation for |latitudes| > MAG_MAX_LAT_DEGREE Grivation (or grid variation) is the angle between grid north and magnetic north. This routine calculates Grivation for the Polar Stereographic projection for polar locations (Latitude => |55| deg). Otherwise, it computes the grid variation in UTM projection system. However, the UTM projection codes may be used to compute the grid variation at any latitudes. INPUT location Data structure with the following elements double lambda; (longitude) double phi; ( geodetic latitude) double HeightAboveEllipsoid; (height above the ellipsoid (HaE) ) double HeightAboveGeoid;(height above the Geoid ) OUTPUT elements Data structure with the following elements updated double GV; ( The Grid Variation ) CALLS : MAG_GetTransverseMercator */ { MAGtype_UTMParameters UTMParameters; if(location.phi >= MAG_PS_MAX_LAT_DEGREE) { elements->GV = elements->Decl - location.lambda; return 1; } else if(location.phi <= MAG_PS_MIN_LAT_DEGREE) { elements->GV = elements->Decl + location.lambda; return 1; } else { MAG_GetTransverseMercator(location, &UTMParameters); elements->GV = elements->Decl - UTMParameters.ConvergenceOfMeridians; } return 0; } /*MAG_CalculateGridVariation*/ void MAG_CalculateGradientElements(MAGtype_MagneticResults GradResults, MAGtype_GeoMagneticElements MagneticElements, MAGtype_GeoMagneticElements *GradElements) { GradElements->X = GradResults.Bx; GradElements->Y = GradResults.By; GradElements->Z = GradResults.Bz; GradElements->H = (GradElements->X * MagneticElements.X + GradElements->Y * MagneticElements.Y) / MagneticElements.H; GradElements->F = (GradElements->X * MagneticElements.X + GradElements->Y * MagneticElements.Y + GradElements->Z * MagneticElements.Z) / MagneticElements.F; GradElements->Decl = 180.0 / M_PI * (MagneticElements.X * GradElements->Y - MagneticElements.Y * GradElements->X) / (MagneticElements.H * MagneticElements.H); GradElements->Incl = 180.0 / M_PI * (MagneticElements.H * GradElements->Z - MagneticElements.Z * GradElements->H) / (MagneticElements.F * MagneticElements.F); GradElements->GV = GradElements->Decl; } int MAG_CalculateSecularVariationElements(MAGtype_MagneticResults MagneticVariation, MAGtype_GeoMagneticElements *MagneticElements) /*This takes the Magnetic Variation in x, y, and z and uses it to calculate the secular variation of each of the Geomagnetic elements. INPUT MagneticVariation Data structure with the following elements double Bx; ( North ) double By; ( East ) double Bz; ( Down ) OUTPUT MagneticElements Pointer to the data structure with the following elements updated double Decldot; Yearly Rate of change in declination double Incldot; Yearly Rate of change in inclination double Fdot; Yearly rate of change in Magnetic field strength double Hdot; Yearly rate of change in horizontal field strength double Xdot; Yearly rate of change in the northern component double Ydot; Yearly rate of change in the eastern component double Zdot; Yearly rate of change in the downward component double GVdot;Yearly rate of chnage in grid variation CALLS : none */ { MagneticElements->Xdot = MagneticVariation.Bx; MagneticElements->Ydot = MagneticVariation.By; MagneticElements->Zdot = MagneticVariation.Bz; MagneticElements->Hdot = (MagneticElements->X * MagneticElements->Xdot + MagneticElements->Y * MagneticElements->Ydot) / MagneticElements->H; /* See equation 19 in the WMM technical report */ MagneticElements->Fdot = (MagneticElements->X * MagneticElements->Xdot + MagneticElements->Y * MagneticElements->Ydot + MagneticElements->Z * MagneticElements->Zdot) / MagneticElements->F; MagneticElements->Decldot = 180.0 / M_PI * (MagneticElements->X * MagneticElements->Ydot - MagneticElements->Y * MagneticElements->Xdot) / (MagneticElements->H * MagneticElements->H); MagneticElements->Incldot = 180.0 / M_PI * (MagneticElements->H * MagneticElements->Zdot - MagneticElements->Z * MagneticElements->Hdot) / (MagneticElements->F * MagneticElements->F); MagneticElements->GVdot = MagneticElements->Decldot; return TRUE; } /*MAG_CalculateSecularVariationElements*/ void MAG_CartesianToGeodetic(MAGtype_Ellipsoid Ellip, double x, double y, double z, MAGtype_CoordGeodetic *CoordGeodetic) { /*This converts the Cartesian x, y, and z coordinates to Geodetic Coordinates x is defined as the direction pointing out of the core toward the point defined * by 0 degrees latitude and longitude. y is defined as the direction from the core toward 90 degrees east longitude along * the equator z is defined as the direction from the core out the geographic north pole*/ double modified_b,r,e,f,p,q,d,v,g,t,zlong,rlat; /* * 1.0 compute semi-minor axis and set sign to that of z in order * to get sign of Phi correct */ if (z < 0.0) modified_b = -Ellip.b; else modified_b = Ellip.b; /* * 2.0 compute intermediate values for latitude */ r= sqrt( x*x + y*y ); e= ( modified_b*z - (Ellip.a*Ellip.a - modified_b*modified_b) ) / ( Ellip.a*r ); f= ( modified_b*z + (Ellip.a*Ellip.a - modified_b*modified_b) ) / ( Ellip.a*r ); /* * 3.0 find solution to: * t^4 + 2*E*t^3 + 2*F*t - 1 = 0 */ p= (4.0 / 3.0) * (e*f + 1.0); q= 2.0 * (e*e - f*f); d= p*p*p + q*q; if( d >= 0.0 ) { v= pow( (sqrt( d ) - q), (1.0 / 3.0) ) - pow( (sqrt( d ) + q), (1.0 / 3.0) ); } else { v= 2.0 * sqrt( -p ) * cos( acos( q/(p * sqrt( -p )) ) / 3.0 ); } /* * 4.0 improve v * NOTE: not really necessary unless point is near pole */ if( v*v < fabs(p) ) { v= -(v*v*v + 2.0*q) / (3.0*p); } g = (sqrt( e*e + v ) + e) / 2.0; t = sqrt( g*g + (f - v*g)/(2.0*g - e) ) - g; rlat =atan( (Ellip.a*(1.0 - t*t)) / (2.0*modified_b*t) ); CoordGeodetic->phi = RAD2DEG(rlat); /* * 5.0 compute height above ellipsoid */ CoordGeodetic->HeightAboveEllipsoid = (r - Ellip.a*t) * cos(rlat) + (z - modified_b) * sin(rlat); /* * 6.0 compute longitude east of Greenwich */ zlong = atan2( y, x ); if( zlong < 0.0 ) zlong= zlong + 2*M_PI; CoordGeodetic->lambda = RAD2DEG(zlong); while(CoordGeodetic->lambda > 180) { CoordGeodetic->lambda-=360; } } MAGtype_CoordGeodetic MAG_CoordGeodeticAssign(MAGtype_CoordGeodetic CoordGeodetic) { MAGtype_CoordGeodetic Assignee; Assignee.phi = CoordGeodetic.phi; Assignee.lambda = CoordGeodetic.lambda; Assignee.HeightAboveEllipsoid = CoordGeodetic.HeightAboveEllipsoid; Assignee.HeightAboveGeoid = CoordGeodetic.HeightAboveGeoid; Assignee.UseGeoid = CoordGeodetic.UseGeoid; return Assignee; } int MAG_DateToYear(MAGtype_Date *CalendarDate, char *Error) /* Converts a given calendar date into a decimal year, it also outputs an error string if there is a problem INPUT CalendarDate Pointer to the data structure with the following elements int Year; int Month; int Day; double DecimalYear; decimal years OUTPUT CalendarDate Pointer to the data structure with the following elements updated double DecimalYear; decimal years Error pointer to an error string CALLS : none */ { int temp = 0; /*Total number of days */ int MonthDays[13]; int ExtraDay = 0; int i; if(CalendarDate->Month == 0) { CalendarDate->DecimalYear = CalendarDate->Year; return TRUE; } if((CalendarDate->Year % 4 == 0 && CalendarDate->Year % 100 != 0) || CalendarDate->Year % 400 == 0) ExtraDay = 1; MonthDays[0] = 0; MonthDays[1] = 31; MonthDays[2] = 28 + ExtraDay; MonthDays[3] = 31; MonthDays[4] = 30; MonthDays[5] = 31; MonthDays[6] = 30; MonthDays[7] = 31; MonthDays[8] = 31; MonthDays[9] = 30; MonthDays[10] = 31; MonthDays[11] = 30; MonthDays[12] = 31; /******************Validation********************************/ if(CalendarDate->Month <= 0 || CalendarDate->Month > 12) { strcpy(Error, "\nError: The Month entered is invalid, valid months are '1 to 12'\n"); return 0; } if(CalendarDate->Day <= 0 || CalendarDate->Day > MonthDays[CalendarDate->Month]) { printf("\nThe number of days in month %d is %d\n", CalendarDate->Month, MonthDays[CalendarDate->Month]); strcpy(Error, "\nError: The day entered is invalid\n"); return 0; } /****************Calculation of t***************************/ for(i = 1; i <= CalendarDate->Month; i++) temp += MonthDays[i - 1]; temp += CalendarDate->Day; CalendarDate->DecimalYear = CalendarDate->Year + (temp - 1) / (365.0 + ExtraDay); return TRUE; } /*MAG_DateToYear*/ void MAG_DegreeToDMSstring(double DegreesOfArc, int UnitDepth, char *DMSstring) /*This converts a given decimal degree into a DMS string. INPUT DegreesOfArc decimal degree UnitDepth How many iterations should be printed, 1 = Degrees 2 = Degrees, Minutes 3 = Degrees, Minutes, Seconds OUPUT DMSstring pointer to DMSString. Must be at least 30 characters. CALLS : none */ { int DMS[3], i; double temp = DegreesOfArc; char tempstring[36] = ""; char tempstring2[32] = ""; strcpy(DMSstring, ""); if(UnitDepth > 3) MAG_Error(21); for(i = 0; i < UnitDepth; i++) { DMS[i] = (int) temp; switch(i) { case 0: strcpy(tempstring2, "Deg"); break; case 1: strcpy(tempstring2, "Min"); break; case 2: strcpy(tempstring2, "Sec"); break; } temp = (temp - DMS[i])*60; if(i == UnitDepth - 1 && temp >= 30) DMS[i]++; else if(i == UnitDepth - 1 && temp <= -30) DMS[i]--; sprintf(tempstring, "%4d%4s", DMS[i], tempstring2); strcat(DMSstring, tempstring); } } /*MAG_DegreeToDMSstring*/ void MAG_DMSstringToDegree(char *DMSstring, double *DegreesOfArc) /*This converts a given DMS string into decimal degrees. INPUT DMSstring pointer to DMSString OUTPUT DegreesOfArc decimal degree CALLS : none */ { int second, minute, degree, sign = 1, j = 0; j = sscanf(DMSstring, "%d, %d, %d", °ree, &minute, &second); if(j != 3) sscanf(DMSstring, "%d %d %d", °ree, &minute, &second); if(degree < 0) sign = -1; degree = degree * sign; *DegreesOfArc = sign * (degree + minute / 60.0 + second / 3600.0); } /*MAG_DMSstringToDegree*/ void MAG_ErrorCalc(MAGtype_GeoMagneticElements B, MAGtype_GeoMagneticElements* Errors) { /*Errors.Decl, Errors.Incl, Errors.F are all assumed to exist*/ double cos2D, cos2I, sin2D, sin2I, EDSq, EISq, eD, eI; cos2D = cos(DEG2RAD(B.Decl))*cos(DEG2RAD(B.Decl)); cos2I = cos(DEG2RAD(B.Incl))*cos(DEG2RAD(B.Incl)); sin2D = sin(DEG2RAD(B.Decl))*sin(DEG2RAD(B.Decl)); sin2I = sin(DEG2RAD(B.Incl))*sin(DEG2RAD(B.Incl)); eD = DEG2RAD(Errors->Decl); eI = DEG2RAD(Errors->Incl); EDSq = eD*eD; EISq = eI*eI; Errors->X = sqrt(cos2D*cos2I*Errors->F*Errors->F+B.F*B.F*sin2D*cos2I*EDSq+B.F*B.F*cos2D*sin2I*EISq); Errors->Y = sqrt(sin2D*cos2I*Errors->F*Errors->F+B.F*B.F*cos2D*cos2I*EDSq+B.F*B.F*sin2D*sin2I*EISq); Errors->Z = sqrt(sin2I*Errors->F*Errors->F+B.F*B.F*cos2I*EISq); Errors->H = sqrt(cos2I*Errors->F*Errors->F+B.F*B.F*sin2I*EISq); } int MAG_GeodeticToSpherical(MAGtype_Ellipsoid Ellip, MAGtype_CoordGeodetic CoordGeodetic, MAGtype_CoordSpherical *CoordSpherical) /* Converts Geodetic coordinates to Spherical coordinates INPUT Ellip data structure with the following elements double a; semi-major axis of the ellipsoid double b; semi-minor axis of the ellipsoid double fla; flattening double epssq; first eccentricity squared double eps; first eccentricity double re; mean radius of ellipsoid CoordGeodetic Pointer to the data structure with the following elements updates double lambda; ( longitude ) double phi; ( geodetic latitude ) double HeightAboveEllipsoid; ( height above the WGS84 ellipsoid (HaE) ) double HeightAboveGeoid; (height above the EGM96 Geoid model ) OUTPUT CoordSpherical Pointer to the data structure with the following elements double lambda; ( longitude) double phig; ( geocentric latitude ) double r; ( distance from the center of the ellipsoid) CALLS : none */ { double CosLat, SinLat, rc, xp, zp; /*all local variables */ /* ** Convert geodetic coordinates, (defined by the WGS-84 ** reference ellipsoid), to Earth Centered Earth Fixed Cartesian ** coordinates, and then to spherical coordinates. */ CosLat = cos(DEG2RAD(CoordGeodetic.phi)); SinLat = sin(DEG2RAD(CoordGeodetic.phi)); /* compute the local radius of curvature on the WGS-84 reference ellipsoid */ rc = Ellip.a / sqrt(1.0 - Ellip.epssq * SinLat * SinLat); /* compute ECEF Cartesian coordinates of specified point (for longitude=0) */ xp = (rc + CoordGeodetic.HeightAboveEllipsoid) * CosLat; zp = (rc * (1.0 - Ellip.epssq) + CoordGeodetic.HeightAboveEllipsoid) * SinLat; /* compute spherical radius and angle lambda and phi of specified point */ CoordSpherical->r = sqrt(xp * xp + zp * zp); CoordSpherical->phig = RAD2DEG(asin(zp / CoordSpherical->r)); /* geocentric latitude */ CoordSpherical->lambda = CoordGeodetic.lambda; /* longitude */ return TRUE; }/*MAG_GeodeticToSpherical*/ MAGtype_GeoMagneticElements MAG_GeoMagneticElementsAssign(MAGtype_GeoMagneticElements Elements) { MAGtype_GeoMagneticElements Assignee; Assignee.X = Elements.X; Assignee.Y = Elements.Y; Assignee.Z = Elements.Z; Assignee.H = Elements.H; Assignee.F = Elements.F; Assignee.Decl = Elements.Decl; Assignee.Incl = Elements.Incl; Assignee.GV = Elements.GV; Assignee.Xdot = Elements.Xdot; Assignee.Ydot = Elements.Ydot; Assignee.Zdot = Elements.Zdot; Assignee.Hdot = Elements.Hdot; Assignee.Fdot = Elements.Fdot; Assignee.Decldot = Elements.Decldot; Assignee.Incldot = Elements.Incldot; Assignee.GVdot = Elements.GVdot; return Assignee; } MAGtype_GeoMagneticElements MAG_GeoMagneticElementsScale(MAGtype_GeoMagneticElements Elements, double factor) { /*This function scales all the geomagnetic elements to scale a vector use MAG_MagneticResultsScale*/ MAGtype_GeoMagneticElements product; product.X = Elements.X * factor; product.Y = Elements.Y * factor; product.Z = Elements.Z * factor; product.H = Elements.H * factor; product.F = Elements.F * factor; product.Incl = Elements.Incl * factor; product.Decl = Elements.Decl * factor; product.GV = Elements.GV * factor; product.Xdot = Elements.Xdot * factor; product.Ydot = Elements.Ydot * factor; product.Zdot = Elements.Zdot * factor; product.Hdot = Elements.Hdot * factor; product.Fdot = Elements.Fdot * factor; product.Incldot = Elements.Incldot * factor; product.Decldot = Elements.Decldot * factor; product.GVdot = Elements.GVdot * factor; return product; } MAGtype_GeoMagneticElements MAG_GeoMagneticElementsSubtract(MAGtype_GeoMagneticElements minuend, MAGtype_GeoMagneticElements subtrahend) { /*This algorithm does not result in the difference of F being derived from the Pythagorean theorem. This function should be used for computing residuals or changes in elements.*/ MAGtype_GeoMagneticElements difference; difference.X = minuend.X - subtrahend.X; difference.Y = minuend.Y - subtrahend.Y; difference.Z = minuend.Z - subtrahend.Z; difference.H = minuend.H - subtrahend.H; difference.F = minuend.F - subtrahend.F; difference.Decl = minuend.Decl - subtrahend.Decl; difference.Incl = minuend.Incl - subtrahend.Incl; difference.Xdot = minuend.Xdot - subtrahend.Xdot; difference.Ydot = minuend.Ydot - subtrahend.Ydot; difference.Zdot = minuend.Zdot - subtrahend.Zdot; difference.Hdot = minuend.Hdot - subtrahend.Hdot; difference.Fdot = minuend.Fdot - subtrahend.Fdot; difference.Decldot = minuend.Decldot - subtrahend.Decldot; difference.Incldot = minuend.Incldot - subtrahend.Incldot; difference.GV = minuend.GV - subtrahend.GV; difference.GVdot = minuend.GVdot - subtrahend.GVdot; return difference; } int MAG_GetTransverseMercator(MAGtype_CoordGeodetic CoordGeodetic, MAGtype_UTMParameters *UTMParameters) /* Gets the UTM Parameters for a given Latitude and Longitude. INPUT: CoordGeodetic : Data structure MAGtype_CoordGeodetic. OUTPUT : UTMParameters : Pointer to data structure MAGtype_UTMParameters with the following elements double Easting; (X) in meters double Northing; (Y) in meters int Zone; UTM Zone char HemiSphere ; double CentralMeridian; Longitude of the Central Meridian of the UTM Zone double ConvergenceOfMeridians; Convergence of Meridians double PointScale; */ { double Eps, Epssq; double Acoeff[8]; double Lam0, K0, falseE, falseN; double K0R4, K0R4oa; double Lambda, Phi; int XYonly; double X, Y, pscale, CoM; int Zone; char Hemisphere; /* Get the map projection parameters */ Lambda = DEG2RAD(CoordGeodetic.lambda); Phi = DEG2RAD(CoordGeodetic.phi); MAG_GetUTMParameters(Phi, Lambda, &Zone, &Hemisphere, &Lam0); K0 = 0.9996; if(Hemisphere == 'n' || Hemisphere == 'N') { falseN = 0; } if(Hemisphere == 's' || Hemisphere == 'S') { falseN = 10000000; } falseE = 500000; /* WGS84 ellipsoid */ Eps = 0.081819190842621494335; Epssq = 0.0066943799901413169961; K0R4 = 6367449.1458234153093*K0; K0R4oa = K0R4/6378137; Acoeff[0] = 8.37731820624469723600E-04; Acoeff[1] = 7.60852777357248641400E-07; Acoeff[2] = 1.19764550324249124400E-09; Acoeff[3] = 2.42917068039708917100E-12; Acoeff[4] = 5.71181837042801392800E-15; Acoeff[5] = 1.47999793137966169400E-17; Acoeff[6] = 4.10762410937071532000E-20; Acoeff[7] = 1.21078503892257704200E-22; /* WGS84 ellipsoid */ /* Execution of the forward T.M. algorithm */ XYonly = 0; MAG_TMfwd4(Eps, Epssq, K0R4, K0R4oa, Acoeff, Lam0, K0, falseE, falseN, XYonly, Lambda, Phi, &X, &Y, &pscale, &CoM); /* Report results */ UTMParameters->Easting = X; /* UTM Easting (X) in meters*/ UTMParameters->Northing = Y; /* UTM Northing (Y) in meters */ UTMParameters->Zone = Zone; /*UTM Zone*/ UTMParameters->HemiSphere = Hemisphere; UTMParameters->CentralMeridian = RAD2DEG(Lam0); /* Central Meridian of the UTM Zone */ UTMParameters->ConvergenceOfMeridians = RAD2DEG(CoM); /* Convergence of meridians of the UTM Zone and location */ UTMParameters->PointScale = pscale; return 0; } /*MAG_GetTransverseMercator*/ int MAG_GetUTMParameters(double Latitude, double Longitude, int *Zone, char *Hemisphere, double *CentralMeridian) { /* * The function MAG_GetUTMParameters converts geodetic (latitude and * longitude) coordinates to UTM projection parameters (zone, hemisphere and central meridian) * If any errors occur, the error code(s) are returned * by the function, otherwise TRUE is returned. * * Latitude : Latitude in radians (input) * Longitude : Longitude in radians (input) * Zone : UTM zone (output) * Hemisphere : North or South hemisphere (output) * CentralMeridian : Central Meridian of the UTM Zone in radians (output) */ long Lat_Degrees; long Long_Degrees; long temp_zone; int Error_Code = 0; if((Latitude < DEG2RAD(MAG_UTM_MIN_LAT_DEGREE)) || (Latitude > DEG2RAD(MAG_UTM_MAX_LAT_DEGREE))) { /* Latitude out of range */ MAG_Error(23); Error_Code = 1; } if((Longitude < -M_PI) || (Longitude > (2 * M_PI))) { /* Longitude out of range */ MAG_Error(24); Error_Code = 1; } if(!Error_Code) { /* no errors */ if(Longitude < 0) Longitude += (2 * M_PI) + 1.0e-10; Lat_Degrees = (long) (Latitude * 180.0 / M_PI); Long_Degrees = (long) (Longitude * 180.0 / M_PI); if(Longitude < M_PI) temp_zone = (long) (31 + ((Longitude * 180.0 / M_PI) / 6.0)); else temp_zone = (long) (((Longitude * 180.0 / M_PI) / 6.0) - 29); if(temp_zone > 60) temp_zone = 1; /* UTM special cases */ if((Lat_Degrees > 55) && (Lat_Degrees < 64) && (Long_Degrees > -1) && (Long_Degrees < 3)) temp_zone = 31; if((Lat_Degrees > 55) && (Lat_Degrees < 64) && (Long_Degrees > 2) && (Long_Degrees < 12)) temp_zone = 32; if((Lat_Degrees > 71) && (Long_Degrees > -1) && (Long_Degrees < 9)) temp_zone = 31; if((Lat_Degrees > 71) && (Long_Degrees > 8) && (Long_Degrees < 21)) temp_zone = 33; if((Lat_Degrees > 71) && (Long_Degrees > 20) && (Long_Degrees < 33)) temp_zone = 35; if((Lat_Degrees > 71) && (Long_Degrees > 32) && (Long_Degrees < 42)) temp_zone = 37; if(!Error_Code) { if(temp_zone >= 31) *CentralMeridian = (6 * temp_zone - 183) * M_PI / 180.0; else *CentralMeridian = (6 * temp_zone + 177) * M_PI / 180.0; *Zone = temp_zone; if(Latitude < 0) *Hemisphere = 'S'; else *Hemisphere = 'N'; } } /* END OF if (!Error_Code) */ return (Error_Code); } /* MAG_GetUTMParameters */ int MAG_isNaN(double d) { return d != d; } int MAG_RotateMagneticVector(MAGtype_CoordSpherical CoordSpherical, MAGtype_CoordGeodetic CoordGeodetic, MAGtype_MagneticResults MagneticResultsSph, MAGtype_MagneticResults *MagneticResultsGeo) /* Rotate the Magnetic Vectors to Geodetic Coordinates Manoj Nair, June, 2009 Manoj.C.Nair@Noaa.Gov Equation 16, WMM Technical report INPUT : CoordSpherical : Data structure MAGtype_CoordSpherical with the following elements double lambda; ( longitude) double phig; ( geocentric latitude ) double r; ( distance from the center of the ellipsoid) CoordGeodetic : Data structure MAGtype_CoordGeodetic with the following elements double lambda; (longitude) double phi; ( geodetic latitude) double HeightAboveEllipsoid; (height above the ellipsoid (HaE) ) double HeightAboveGeoid;(height above the Geoid ) MagneticResultsSph : Data structure MAGtype_MagneticResults with the following elements double Bx; North double By; East double Bz; Down OUTPUT: MagneticResultsGeo Pointer to the data structure MAGtype_MagneticResults, with the following elements double Bx; North double By; East double Bz; Down CALLS : none */ { double Psi; /* Difference between the spherical and Geodetic latitudes */ Psi = (M_PI / 180) * (CoordSpherical.phig - CoordGeodetic.phi); /* Rotate spherical field components to the Geodetic system */ MagneticResultsGeo->Bz = MagneticResultsSph.Bx * sin(Psi) + MagneticResultsSph.Bz * cos(Psi); MagneticResultsGeo->Bx = MagneticResultsSph.Bx * cos(Psi) - MagneticResultsSph.Bz * sin(Psi); MagneticResultsGeo->By = MagneticResultsSph.By; return TRUE; } /*MAG_RotateMagneticVector*/ void MAG_SphericalToCartesian(MAGtype_CoordSpherical CoordSpherical, double *x, double *y, double *z) { double radphi; double radlambda; radphi = CoordSpherical.phig * (M_PI / 180); radlambda = CoordSpherical.lambda * (M_PI / 180); *x = CoordSpherical.r * cos(radphi) * cos(radlambda); *y = CoordSpherical.r * cos(radphi) * sin(radlambda); *z = CoordSpherical.r * sin(radphi); return; } void MAG_SphericalToGeodetic(MAGtype_Ellipsoid Ellip, MAGtype_CoordSpherical CoordSpherical, MAGtype_CoordGeodetic *CoordGeodetic) { /*This converts spherical coordinates back to geodetic coordinates. It is not used in the WMM but may be necessary for some applications, such as geomagnetic coordinates*/ double x,y,z; MAG_SphericalToCartesian(CoordSpherical, &x,&y,&z); MAG_CartesianToGeodetic(Ellip, x,y,z,CoordGeodetic); } void MAG_TMfwd4(double Eps, double Epssq, double K0R4, double K0R4oa, double Acoeff[], double Lam0, double K0, double falseE, double falseN, int XYonly, double Lambda, double Phi, double *X, double *Y, double *pscale, double *CoM) { /* Transverse Mercator forward equations including point-scale and CoM =--------- =------- =--=--= --------- Algorithm developed by: C. Rollins August 7, 2006 C software written by: K. Robins Constants fixed by choice of ellipsoid and choice of projection parameters --------------- Eps Eccentricity (epsilon) of the ellipsoid Epssq Eccentricity squared ( R4 Meridional isoperimetric radius ) ( K0 Central scale factor ) K0R4 K0 times R4 K0R4oa K0 times Ratio of R4 over semi-major axis Acoeff Trig series coefficients, omega as a function of chi Lam0 Longitude of the central meridian in radians K0 Central scale factor, for example, 0.9996 for UTM falseE False easting, for example, 500000 for UTM falseN False northing Processing option ---------- ------ XYonly If one (1), then only X and Y will be properly computed. Values returned for point-scale and CoM will merely be the trivial values for points on the central meridian Input items that identify the point to be converted ----- ----- Lambda Longitude (from Greenwich) in radians Phi Latitude in radians Output items ------ ----- X X coordinate (Easting) in meters Y Y coordinate (Northing) in meters pscale point-scale (dimensionless) CoM Convergence-of-meridians in radians */ double Lam, CLam, SLam, CPhi, SPhi; double P, part1, part2, denom, CChi, SChi; double U, V; double T, Tsq, denom2; double c2u, s2u, c4u, s4u, c6u, s6u, c8u, s8u; double c2v, s2v, c4v, s4v, c6v, s6v, c8v, s8v; double Xstar, Ystar; double sig1, sig2, comroo; /* Ellipsoid to sphere --------- -- ------ Convert longitude (Greenwhich) to longitude from the central meridian It is unnecessary to find the (-Pi, Pi] equivalent of the result. Compute its cosine and sine. */ Lam = Lambda - Lam0; CLam = cos(Lam); SLam = sin(Lam); /* Latitude */ CPhi = cos(Phi); SPhi = sin(Phi); /* Convert geodetic latitude, Phi, to conformal latitude, Chi Only the cosine and sine of Chi are actually needed. */ P = exp(Eps * ATanH(Eps * SPhi)); part1 = (1 + SPhi) / P; part2 = (1 - SPhi) * P; denom = 1 / (part1 + part2); CChi = 2 * CPhi * denom; SChi = (part1 - part2) * denom; /* Sphere to first plane ------ -- ----- ----- Apply spherical theory of transverse Mercator to get (u,v) coordinates Note the order of the arguments in Fortran's version of ArcTan, i.e. atan2(y, x) = ATan(y/x) The two argument form of ArcTan is needed here. */ T = CChi * SLam; U = ATanH(T); V = atan2(SChi, CChi * CLam); /* Trigonometric multiple angles ------------- -------- ------ Compute Cosh of even multiples of U Compute Sinh of even multiples of U Compute Cos of even multiples of V Compute Sin of even multiples of V */ Tsq = T * T; denom2 = 1 / (1 - Tsq); c2u = (1 + Tsq) * denom2; s2u = 2 * T * denom2; c2v = (-1 + CChi * CChi * (1 + CLam * CLam)) * denom2; s2v = 2 * CLam * CChi * SChi * denom2; c4u = 1 + 2 * s2u * s2u; s4u = 2 * c2u * s2u; c4v = 1 - 2 * s2v * s2v; s4v = 2 * c2v * s2v; c6u = c4u * c2u + s4u * s2u; s6u = s4u * c2u + c4u * s2u; c6v = c4v * c2v - s4v * s2v; s6v = s4v * c2v + c4v * s2v; c8u = 1 + 2 * s4u * s4u; s8u = 2 * c4u * s4u; c8v = 1 - 2 * s4v * s4v; s8v = 2 * c4v * s4v; /* First plane to second plane ----- ----- -- ------ ----- Accumulate terms for X and Y */ Xstar = Acoeff[3] * s8u * c8v; Xstar = Xstar + Acoeff[2] * s6u * c6v; Xstar = Xstar + Acoeff[1] * s4u * c4v; Xstar = Xstar + Acoeff[0] * s2u * c2v; Xstar = Xstar + U; Ystar = Acoeff[3] * c8u * s8v; Ystar = Ystar + Acoeff[2] * c6u * s6v; Ystar = Ystar + Acoeff[1] * c4u * s4v; Ystar = Ystar + Acoeff[0] * c2u * s2v; Ystar = Ystar + V; /* Apply isoperimetric radius, scale adjustment, and offsets */ *X = K0R4 * Xstar + falseE; *Y = K0R4 * Ystar + falseN; /* Point-scale and CoM ----- ----- --- --- */ if(XYonly == 1) { *pscale = K0; *CoM = 0; } else { sig1 = 8 * Acoeff[3] * c8u * c8v; sig1 = sig1 + 6 * Acoeff[2] * c6u * c6v; sig1 = sig1 + 4 * Acoeff[1] * c4u * c4v; sig1 = sig1 + 2 * Acoeff[0] * c2u * c2v; sig1 = sig1 + 1; sig2 = 8 * Acoeff[3] * s8u * s8v; sig2 = sig2 + 6 * Acoeff[2] * s6u * s6v; sig2 = sig2 + 4 * Acoeff[1] * s4u * s4v; sig2 = sig2 + 2 * Acoeff[0] * s2u * s2v; /* Combined square roots */ comroo = sqrt((1 - Epssq * SPhi * SPhi) * denom2 * (sig1 * sig1 + sig2 * sig2)); *pscale = K0R4oa * 2 * denom * comroo; *CoM = atan2(SChi * SLam, CLam) + atan2(sig2, sig1); } } /*MAG_TMfwd4*/ int MAG_YearToDate(MAGtype_Date *CalendarDate) /* Converts a given Decimal year into a Year, Month and Date it also outputs an error string if there is a problem INPUT CalendarDate Pointer to the data structure with the following elements double DecimalYear; decimal years OUTPUT CalendarDate Pointer to the data structure with the following elements updated * int Year * int Month * int Day Error pointer to an error string CALLS : none */ { int MonthDays[13], CumulativeDays = 0; int ExtraDay = 0; int i, DayOfTheYear; if(CalendarDate->DecimalYear == 0) { CalendarDate->Year = 0; CalendarDate->Month = 0; CalendarDate->Day = 0; return FALSE; } CalendarDate->Year = (int) floor(CalendarDate->DecimalYear); if((CalendarDate->Year % 4 == 0 && CalendarDate->Year % 100 != 0) || CalendarDate->Year % 400 == 0) ExtraDay = 1; DayOfTheYear = floor((CalendarDate->DecimalYear - (double) CalendarDate->Year) * (365.0 + (double) ExtraDay)+0.5) + 1; /*The above floor is used for rounding, this only works for positive integers*/ MonthDays[0] = 0; MonthDays[1] = 31; MonthDays[2] = 28 + ExtraDay; MonthDays[3] = 31; MonthDays[4] = 30; MonthDays[5] = 31; MonthDays[6] = 30; MonthDays[7] = 31; MonthDays[8] = 31; MonthDays[9] = 30; MonthDays[10] = 31; MonthDays[11] = 30; MonthDays[12] = 31; for(i = 1; i <= 12; i++) { CumulativeDays = CumulativeDays + MonthDays[i]; if(DayOfTheYear <= CumulativeDays) { CalendarDate->Month = i; CalendarDate->Day = MonthDays[i] - (CumulativeDays - DayOfTheYear); break; } } return TRUE; } /*MAG_YearToDate*/ /****************************************************************************** ********************************Spherical Harmonics*************************** * This grouping consists of functions that together take gauss coefficients * and return a magnetic vector for an input location in spherical coordinates ******************************************************************************/ int MAG_AssociatedLegendreFunction(MAGtype_CoordSpherical CoordSpherical, int nMax, MAGtype_LegendreFunction *LegendreFunction) /* Computes all of the Schmidt-semi normalized associated Legendre functions up to degree nMax. If nMax <= 16, function MAG_PcupLow is used. Otherwise MAG_PcupHigh is called. INPUT CoordSpherical A data structure with the following elements double lambda; ( longitude) double phig; ( geocentric latitude ) double r; ( distance from the center of the ellipsoid) nMax integer ( Maxumum degree of spherical harmonic secular model) LegendreFunction Pointer to data structure with the following elements double *Pcup; ( pointer to store Legendre Function ) double *dPcup; ( pointer to store Derivative of Lagendre function ) OUTPUT LegendreFunction Calculated Legendre variables in the data structure */ { double sin_phi; int FLAG = 1; sin_phi = sin(DEG2RAD(CoordSpherical.phig)); /* sin (geocentric latitude) */ if(nMax <= 16 || (1 - fabs(sin_phi)) < 1.0e-10) /* If nMax is less tha 16 or at the poles */ FLAG = MAG_PcupLow(LegendreFunction->Pcup, LegendreFunction->dPcup, sin_phi, nMax); else FLAG = MAG_PcupHigh(LegendreFunction->Pcup, LegendreFunction->dPcup, sin_phi, nMax); if(FLAG == 0) /* Error while computing Legendre variables*/ return FALSE; return TRUE; } /*MAG_AssociatedLegendreFunction */ int MAG_CheckGeographicPole(MAGtype_CoordGeodetic *CoordGeodetic) /* Check if the latitude is equal to -90 or 90. If it is, offset it by 1e-5 to avoid division by zero. This is not currently used in the Geomagnetic main function. This may be used to avoid calling MAG_SummationSpecial. The function updates the input data structure. INPUT CoordGeodetic Pointer to the data structure with the following elements double lambda; (longitude) double phi; ( geodetic latitude) double HeightAboveEllipsoid; (height above the ellipsoid (HaE) ) double HeightAboveGeoid;(height above the Geoid ) OUTPUT CoordGeodetic Pointer to the data structure with the following elements updates double phi; ( geodetic latitude) CALLS : none */ { CoordGeodetic->phi = CoordGeodetic->phi < (-90.0 + MAG_GEO_POLE_TOLERANCE) ? (-90.0 + MAG_GEO_POLE_TOLERANCE) : CoordGeodetic->phi; CoordGeodetic->phi = CoordGeodetic->phi > (90.0 - MAG_GEO_POLE_TOLERANCE) ? (90.0 - MAG_GEO_POLE_TOLERANCE) : CoordGeodetic->phi; return TRUE; } /*MAG_CheckGeographicPole*/ int MAG_ComputeSphericalHarmonicVariables(MAGtype_Ellipsoid Ellip, MAGtype_CoordSpherical CoordSpherical, int nMax, MAGtype_SphericalHarmonicVariables *SphVariables) /* Computes Spherical variables Variables computed are (a/r)^(n+2), cos_m(lamda) and sin_m(lambda) for spherical harmonic summations. (Equations 10-12 in the WMM Technical Report) INPUT Ellip data structure with the following elements double a; semi-major axis of the ellipsoid double b; semi-minor axis of the ellipsoid double fla; flattening double epssq; first eccentricity squared double eps; first eccentricity double re; mean radius of ellipsoid CoordSpherical A data structure with the following elements double lambda; ( longitude) double phig; ( geocentric latitude ) double r; ( distance from the center of the ellipsoid) nMax integer ( Maxumum degree of spherical harmonic secular model)\ OUTPUT SphVariables Pointer to the data structure with the following elements double RelativeRadiusPower[MAG_MAX_MODEL_DEGREES+1]; [earth_reference_radius_km sph. radius ]^n double cos_mlambda[MAG_MAX_MODEL_DEGREES+1]; cp(m) - cosine of (mspherical coord. longitude) double sin_mlambda[MAG_MAX_MODEL_DEGREES+1]; sp(m) - sine of (mspherical coord. longitude) CALLS : none */ { double cos_lambda, sin_lambda; int m, n; cos_lambda = cos(DEG2RAD(CoordSpherical.lambda)); sin_lambda = sin(DEG2RAD(CoordSpherical.lambda)); /* for n = 0 ... model_order, compute (Radius of Earth / Spherical radius r)^(n+2) for n 1..nMax-1 (this is much faster than calling pow MAX_N+1 times). */ SphVariables->RelativeRadiusPower[0] = (Ellip.re / CoordSpherical.r) * (Ellip.re / CoordSpherical.r); for(n = 1; n <= nMax; n++) { SphVariables->RelativeRadiusPower[n] = SphVariables->RelativeRadiusPower[n - 1] * (Ellip.re / CoordSpherical.r); } /* Compute cos(m*lambda), sin(m*lambda) for m = 0 ... nMax cos(a + b) = cos(a)*cos(b) - sin(a)*sin(b) sin(a + b) = cos(a)*sin(b) + sin(a)*cos(b) */ SphVariables->cos_mlambda[0] = 1.0; SphVariables->sin_mlambda[0] = 0.0; SphVariables->cos_mlambda[1] = cos_lambda; SphVariables->sin_mlambda[1] = sin_lambda; for(m = 2; m <= nMax; m++) { SphVariables->cos_mlambda[m] = SphVariables->cos_mlambda[m - 1] * cos_lambda - SphVariables->sin_mlambda[m - 1] * sin_lambda; SphVariables->sin_mlambda[m] = SphVariables->cos_mlambda[m - 1] * sin_lambda + SphVariables->sin_mlambda[m - 1] * cos_lambda; } return TRUE; } /*MAG_ComputeSphericalHarmonicVariables*/ void MAG_GradY(MAGtype_Ellipsoid Ellip, MAGtype_CoordSpherical CoordSpherical, MAGtype_CoordGeodetic CoordGeodetic, MAGtype_MagneticModel *TimedMagneticModel, MAGtype_GeoMagneticElements GeoMagneticElements, MAGtype_GeoMagneticElements *GradYElements) { MAGtype_LegendreFunction *LegendreFunction; MAGtype_SphericalHarmonicVariables *SphVariables; int NumTerms; MAGtype_MagneticResults GradYResultsSph, GradYResultsGeo; NumTerms = ((TimedMagneticModel->nMax + 1) * (TimedMagneticModel->nMax + 2) / 2); LegendreFunction = MAG_AllocateLegendreFunctionMemory(NumTerms); /* For storing the ALF functions */ SphVariables = MAG_AllocateSphVarMemory(TimedMagneticModel->nMax); MAG_ComputeSphericalHarmonicVariables(Ellip, CoordSpherical, TimedMagneticModel->nMax, SphVariables); /* Compute Spherical Harmonic variables */ MAG_AssociatedLegendreFunction(CoordSpherical, TimedMagneticModel->nMax, LegendreFunction); /* Compute ALF */ MAG_GradYSummation(LegendreFunction, TimedMagneticModel, *SphVariables, CoordSpherical, &GradYResultsSph); /* Accumulate the spherical harmonic coefficients*/ MAG_RotateMagneticVector(CoordSpherical, CoordGeodetic, GradYResultsSph, &GradYResultsGeo); /* Map the computed Magnetic fields to Geodetic coordinates */ MAG_CalculateGradientElements(GradYResultsGeo, GeoMagneticElements, GradYElements); /* Calculate the Geomagnetic elements, Equation 18 , WMM Technical report */ MAG_FreeLegendreMemory(LegendreFunction); MAG_FreeSphVarMemory(SphVariables); } void MAG_GradYSummation(MAGtype_LegendreFunction *LegendreFunction, MAGtype_MagneticModel *MagneticModel, MAGtype_SphericalHarmonicVariables SphVariables, MAGtype_CoordSpherical CoordSpherical, MAGtype_MagneticResults *GradY) { int m, n, index; double cos_phi; GradY->Bz = 0.0; GradY->By = 0.0; GradY->Bx = 0.0; for(n = 1; n <= MagneticModel->nMax; n++) { for(m = 0; m <= n; m++) { index = (n * (n + 1) / 2 + m); GradY->Bz -= SphVariables.RelativeRadiusPower[n] * (-1 * MagneticModel->Main_Field_Coeff_G[index] * SphVariables.sin_mlambda[m] + MagneticModel->Main_Field_Coeff_H[index] * SphVariables.cos_mlambda[m]) * (double) (n + 1) * (double) (m) * LegendreFunction-> Pcup[index] * (1/CoordSpherical.r); GradY->By += SphVariables.RelativeRadiusPower[n] * (MagneticModel->Main_Field_Coeff_G[index] * SphVariables.cos_mlambda[m] + MagneticModel->Main_Field_Coeff_H[index] * SphVariables.sin_mlambda[m]) * (double) (m * m) * LegendreFunction-> Pcup[index] * (1/CoordSpherical.r); GradY->Bx -= SphVariables.RelativeRadiusPower[n] * (-1 * MagneticModel->Main_Field_Coeff_G[index] * SphVariables.sin_mlambda[m] + MagneticModel->Main_Field_Coeff_H[index] * SphVariables.cos_mlambda[m]) * (double) (m) * LegendreFunction-> dPcup[index] * (1/CoordSpherical.r); } } cos_phi = cos(DEG2RAD(CoordSpherical.phig)); if(fabs(cos_phi) > 1.0e-10) { GradY->By = GradY->By / (cos_phi * cos_phi); GradY->Bx = GradY->Bx / (cos_phi); GradY->Bz = GradY->Bz / (cos_phi); } else /* Special calculation for component - By - at Geographic poles. * If the user wants to avoid using this function, please make sure that * the latitude is not exactly +/-90. An option is to make use the function * MAG_CheckGeographicPoles. */ { /* MAG_SummationSpecial(MagneticModel, SphVariables, CoordSpherical, GradY); */ } } int MAG_PcupHigh(double *Pcup, double *dPcup, double x, int nMax) /* This function evaluates all of the Schmidt-semi normalized associated Legendre functions up to degree nMax. The functions are initially scaled by 10^280 sin^m in order to minimize the effects of underflow at large m near the poles (see Holmes and Featherstone 2002, J. Geodesy, 76, 279-299). Note that this function performs the same operation as MAG_PcupLow. However this function also can be used for high degree (large nMax) models. Calling Parameters: INPUT nMax: Maximum spherical harmonic degree to compute. x: cos(colatitude) or sin(latitude). OUTPUT Pcup: A vector of all associated Legendgre polynomials evaluated at x up to nMax. The lenght must by greater or equal to (nMax+1)*(nMax+2)/2. dPcup: Derivative of Pcup(x) with respect to latitude CALLS : none Notes: Adopted from the FORTRAN code written by Mark Wieczorek September 25, 2005. Manoj Nair, Nov, 2009 Manoj.C.Nair@Noaa.Gov Change from the previous version The prevous version computes the derivatives as dP(n,m)(x)/dx, where x = sin(latitude) (or cos(colatitude) ). However, the WMM Geomagnetic routines requires dP(n,m)(x)/dlatitude. Hence the derivatives are multiplied by sin(latitude). Removed the options for CS phase and normalizations. Note: In geomagnetism, the derivatives of ALF are usually found with respect to the colatitudes. Here the derivatives are found with respect to the latitude. The difference is a sign reversal for the derivative of the Associated Legendre Functions. The derivatives can't be computed for latitude = |90| degrees. */ { double pm2, pm1, pmm, plm, rescalem, z, scalef; double *f1, *f2, *PreSqr; int k, kstart, m, n, NumTerms; NumTerms = ((nMax + 1) * (nMax + 2) / 2); if(fabs(x) == 1.0) { printf("Error in PcupHigh: derivative cannot be calculated at poles\n"); return FALSE; } f1 = (double *) malloc((NumTerms + 1) * sizeof ( double)); if(f1 == NULL) { MAG_Error(18); return FALSE; } PreSqr = (double *) malloc((NumTerms + 1) * sizeof ( double)); if(PreSqr == NULL) { MAG_Error(18); return FALSE; } f2 = (double *) malloc((NumTerms + 1) * sizeof ( double)); if(f2 == NULL) { MAG_Error(18); return FALSE; } scalef = 1.0e-280; for(n = 0; n <= 2 * nMax + 1; ++n) { PreSqr[n] = sqrt((double) (n)); } k = 2; for(n = 2; n <= nMax; n++) { k = k + 1; f1[k] = (double) (2 * n - 1) / (double) (n); f2[k] = (double) (n - 1) / (double) (n); for(m = 1; m <= n - 2; m++) { k = k + 1; f1[k] = (double) (2 * n - 1) / PreSqr[n + m] / PreSqr[n - m]; f2[k] = PreSqr[n - m - 1] * PreSqr[n + m - 1] / PreSqr[n + m] / PreSqr[n - m]; } k = k + 2; } /*z = sin (geocentric latitude) */ z = sqrt((1.0 - x)*(1.0 + x)); pm2 = 1.0; Pcup[0] = 1.0; dPcup[0] = 0.0; if(nMax == 0) return FALSE; pm1 = x; Pcup[1] = pm1; dPcup[1] = z; k = 1; for(n = 2; n <= nMax; n++) { k = k + n; plm = f1[k] * x * pm1 - f2[k] * pm2; Pcup[k] = plm; dPcup[k] = (double) (n) * (pm1 - x * plm) / z; pm2 = pm1; pm1 = plm; } pmm = PreSqr[2] * scalef; rescalem = 1.0 / scalef; kstart = 0; for(m = 1; m <= nMax - 1; ++m) { rescalem = rescalem*z; /* Calculate Pcup(m,m)*/ kstart = kstart + m + 1; pmm = pmm * PreSqr[2 * m + 1] / PreSqr[2 * m]; Pcup[kstart] = pmm * rescalem / PreSqr[2 * m + 1]; dPcup[kstart] = -((double) (m) * x * Pcup[kstart] / z); pm2 = pmm / PreSqr[2 * m + 1]; /* Calculate Pcup(m+1,m)*/ k = kstart + m + 1; pm1 = x * PreSqr[2 * m + 1] * pm2; Pcup[k] = pm1*rescalem; dPcup[k] = ((pm2 * rescalem) * PreSqr[2 * m + 1] - x * (double) (m + 1) * Pcup[k]) / z; /* Calculate Pcup(n,m)*/ for(n = m + 2; n <= nMax; ++n) { k = k + n; plm = x * f1[k] * pm1 - f2[k] * pm2; Pcup[k] = plm*rescalem; dPcup[k] = (PreSqr[n + m] * PreSqr[n - m] * (pm1 * rescalem) - (double) (n) * x * Pcup[k]) / z; pm2 = pm1; pm1 = plm; } } /* Calculate Pcup(nMax,nMax)*/ rescalem = rescalem*z; kstart = kstart + m + 1; pmm = pmm / PreSqr[2 * nMax]; Pcup[kstart] = pmm * rescalem; dPcup[kstart] = -(double) (nMax) * x * Pcup[kstart] / z; free(f1); free(PreSqr); free(f2); return TRUE; } /* MAG_PcupHigh */ int MAG_PcupLow(double *Pcup, double *dPcup, double x, int nMax) /* This function evaluates all of the Schmidt-semi normalized associated Legendre functions up to degree nMax. Calling Parameters: INPUT nMax: Maximum spherical harmonic degree to compute. x: cos(colatitude) or sin(latitude). OUTPUT Pcup: A vector of all associated Legendgre polynomials evaluated at x up to nMax. dPcup: Derivative of Pcup(x) with respect to latitude Notes: Overflow may occur if nMax > 20 , especially for high-latitudes. Use MAG_PcupHigh for large nMax. Written by Manoj Nair, June, 2009 . Manoj.C.Nair@Noaa.Gov. Note: In geomagnetism, the derivatives of ALF are usually found with respect to the colatitudes. Here the derivatives are found with respect to the latitude. The difference is a sign reversal for the derivative of the Associated Legendre Functions. */ { int n, m, index, index1, index2, NumTerms; double k, z, *schmidtQuasiNorm; Pcup[0] = 1.0; dPcup[0] = 0.0; /*sin (geocentric latitude) - sin_phi */ z = sqrt((1.0 - x) * (1.0 + x)); NumTerms = ((nMax + 1) * (nMax + 2) / 2); schmidtQuasiNorm = (double *) malloc((NumTerms + 1) * sizeof ( double)); if(schmidtQuasiNorm == NULL) { MAG_Error(19); return FALSE; } /* First, Compute the Gauss-normalized associated Legendre functions*/ for(n = 1; n <= nMax; n++) { for(m = 0; m <= n; m++) { index = (n * (n + 1) / 2 + m); if(n == m) { index1 = (n - 1) * n / 2 + m - 1; Pcup [index] = z * Pcup[index1]; dPcup[index] = z * dPcup[index1] + x * Pcup[index1]; } else if(n == 1 && m == 0) { index1 = (n - 1) * n / 2 + m; Pcup[index] = x * Pcup[index1]; dPcup[index] = x * dPcup[index1] - z * Pcup[index1]; } else if(n > 1 && n != m) { index1 = (n - 2) * (n - 1) / 2 + m; index2 = (n - 1) * n / 2 + m; if(m > n - 2) { Pcup[index] = x * Pcup[index2]; dPcup[index] = x * dPcup[index2] - z * Pcup[index2]; } else { k = (double) (((n - 1) * (n - 1)) - (m * m)) / (double) ((2 * n - 1) * (2 * n - 3)); Pcup[index] = x * Pcup[index2] - k * Pcup[index1]; dPcup[index] = x * dPcup[index2] - z * Pcup[index2] - k * dPcup[index1]; } } } } /* Compute the ration between the the Schmidt quasi-normalized associated Legendre * functions and the Gauss-normalized version. */ schmidtQuasiNorm[0] = 1.0; for(n = 1; n <= nMax; n++) { index = (n * (n + 1) / 2); index1 = (n - 1) * n / 2; /* for m = 0 */ schmidtQuasiNorm[index] = schmidtQuasiNorm[index1] * (double) (2 * n - 1) / (double) n; for(m = 1; m <= n; m++) { index = (n * (n + 1) / 2 + m); index1 = (n * (n + 1) / 2 + m - 1); schmidtQuasiNorm[index] = schmidtQuasiNorm[index1] * sqrt((double) ((n - m + 1) * (m == 1 ? 2 : 1)) / (double) (n + m)); } } /* Converts the Gauss-normalized associated Legendre functions to the Schmidt quasi-normalized version using pre-computed relation stored in the variable schmidtQuasiNorm */ for(n = 1; n <= nMax; n++) { for(m = 0; m <= n; m++) { index = (n * (n + 1) / 2 + m); Pcup[index] = Pcup[index] * schmidtQuasiNorm[index]; dPcup[index] = -dPcup[index] * schmidtQuasiNorm[index]; /* The sign is changed since the new WMM routines use derivative with respect to latitude insted of co-latitude */ } } if(schmidtQuasiNorm) free(schmidtQuasiNorm); return TRUE; } /*MAG_PcupLow */ int MAG_SecVarSummation(MAGtype_LegendreFunction *LegendreFunction, MAGtype_MagneticModel *MagneticModel, MAGtype_SphericalHarmonicVariables SphVariables, MAGtype_CoordSpherical CoordSpherical, MAGtype_MagneticResults *MagneticResults) { /*This Function sums the secular variation coefficients to get the secular variation of the Magnetic vector. INPUT : LegendreFunction MagneticModel SphVariables CoordSpherical OUTPUT : MagneticResults CALLS : MAG_SecVarSummationSpecial */ int m, n, index; double cos_phi; MagneticModel->SecularVariationUsed = TRUE; MagneticResults->Bz = 0.0; MagneticResults->By = 0.0; MagneticResults->Bx = 0.0; for(n = 1; n <= MagneticModel->nMaxSecVar; n++) { for(m = 0; m <= n; m++) { index = (n * (n + 1) / 2 + m); /* nMax (n+2) n m m m Bz = -SUM (a/r) (n+1) SUM [g cos(m p) + h sin(m p)] P (sin(phi)) n=1 m=0 n n n */ /* Derivative with respect to radius.*/ MagneticResults->Bz -= SphVariables.RelativeRadiusPower[n] * (MagneticModel->Secular_Var_Coeff_G[index] * SphVariables.cos_mlambda[m] + MagneticModel->Secular_Var_Coeff_H[index] * SphVariables.sin_mlambda[m]) * (double) (n + 1) * LegendreFunction-> Pcup[index]; /* 1 nMax (n+2) n m m m By = SUM (a/r) (m) SUM [g cos(m p) + h sin(m p)] dP (sin(phi)) n=1 m=0 n n n */ /* Derivative with respect to longitude, divided by radius. */ MagneticResults->By += SphVariables.RelativeRadiusPower[n] * (MagneticModel->Secular_Var_Coeff_G[index] * SphVariables.sin_mlambda[m] - MagneticModel->Secular_Var_Coeff_H[index] * SphVariables.cos_mlambda[m]) * (double) (m) * LegendreFunction-> Pcup[index]; /* nMax (n+2) n m m m Bx = - SUM (a/r) SUM [g cos(m p) + h sin(m p)] dP (sin(phi)) n=1 m=0 n n n */ /* Derivative with respect to latitude, divided by radius. */ MagneticResults->Bx -= SphVariables.RelativeRadiusPower[n] * (MagneticModel->Secular_Var_Coeff_G[index] * SphVariables.cos_mlambda[m] + MagneticModel->Secular_Var_Coeff_H[index] * SphVariables.sin_mlambda[m]) * LegendreFunction-> dPcup[index]; } } cos_phi = cos(DEG2RAD(CoordSpherical.phig)); if(fabs(cos_phi) > 1.0e-10) { MagneticResults->By = MagneticResults->By / cos_phi; } else /* Special calculation for component By at Geographic poles */ { MAG_SecVarSummationSpecial(MagneticModel, SphVariables, CoordSpherical, MagneticResults); } return TRUE; } /*MAG_SecVarSummation*/ int MAG_SecVarSummationSpecial(MAGtype_MagneticModel *MagneticModel, MAGtype_SphericalHarmonicVariables SphVariables, MAGtype_CoordSpherical CoordSpherical, MAGtype_MagneticResults *MagneticResults) { /*Special calculation for the secular variation summation at the poles. INPUT: MagneticModel SphVariables CoordSpherical OUTPUT: MagneticResults CALLS : none */ int n, index; double k, sin_phi, *PcupS, schmidtQuasiNorm1, schmidtQuasiNorm2, schmidtQuasiNorm3; PcupS = (double *) malloc((MagneticModel->nMaxSecVar + 1) * sizeof (double)); if(PcupS == NULL) { MAG_Error(15); return FALSE; } PcupS[0] = 1; schmidtQuasiNorm1 = 1.0; MagneticResults->By = 0.0; sin_phi = sin(DEG2RAD(CoordSpherical.phig)); for(n = 1; n <= MagneticModel->nMaxSecVar; n++) { index = (n * (n + 1) / 2 + 1); schmidtQuasiNorm2 = schmidtQuasiNorm1 * (double) (2 * n - 1) / (double) n; schmidtQuasiNorm3 = schmidtQuasiNorm2 * sqrt((double) (n * 2) / (double) (n + 1)); schmidtQuasiNorm1 = schmidtQuasiNorm2; if(n == 1) { PcupS[n] = PcupS[n - 1]; } else { k = (double) (((n - 1) * (n - 1)) - 1) / (double) ((2 * n - 1) * (2 * n - 3)); PcupS[n] = sin_phi * PcupS[n - 1] - k * PcupS[n - 2]; } /* 1 nMax (n+2) n m m m By = SUM (a/r) (m) SUM [g cos(m p) + h sin(m p)] dP (sin(phi)) n=1 m=0 n n n */ /* Derivative with respect to longitude, divided by radius. */ MagneticResults->By += SphVariables.RelativeRadiusPower[n] * (MagneticModel->Secular_Var_Coeff_G[index] * SphVariables.sin_mlambda[1] - MagneticModel->Secular_Var_Coeff_H[index] * SphVariables.cos_mlambda[1]) * PcupS[n] * schmidtQuasiNorm3; } if(PcupS) free(PcupS); return TRUE; }/*SecVarSummationSpecial*/ int MAG_Summation(MAGtype_LegendreFunction *LegendreFunction, MAGtype_MagneticModel *MagneticModel, MAGtype_SphericalHarmonicVariables SphVariables, MAGtype_CoordSpherical CoordSpherical, MAGtype_MagneticResults *MagneticResults) { /* Computes Geomagnetic Field Elements X, Y and Z in Spherical coordinate system using spherical harmonic summation. The vector Magnetic field is given by -grad V, where V is Geomagnetic scalar potential The gradient in spherical coordinates is given by: dV ^ 1 dV ^ 1 dV ^ grad V = -- r + - -- t + -------- -- p dr r dt r sin(t) dp INPUT : LegendreFunction MagneticModel SphVariables CoordSpherical OUTPUT : MagneticResults CALLS : MAG_SummationSpecial Manoj Nair, June, 2009 Manoj.C.Nair@Noaa.Gov */ int m, n, index; double cos_phi; MagneticResults->Bz = 0.0; MagneticResults->By = 0.0; MagneticResults->Bx = 0.0; for(n = 1; n <= MagneticModel->nMax; n++) { for(m = 0; m <= n; m++) { index = (n * (n + 1) / 2 + m); /* nMax (n+2) n m m m Bz = -SUM (a/r) (n+1) SUM [g cos(m p) + h sin(m p)] P (sin(phi)) n=1 m=0 n n n */ /* Equation 12 in the WMM Technical report. Derivative with respect to radius.*/ MagneticResults->Bz -= SphVariables.RelativeRadiusPower[n] * (MagneticModel->Main_Field_Coeff_G[index] * SphVariables.cos_mlambda[m] + MagneticModel->Main_Field_Coeff_H[index] * SphVariables.sin_mlambda[m]) * (double) (n + 1) * LegendreFunction-> Pcup[index]; /* 1 nMax (n+2) n m m m By = SUM (a/r) (m) SUM [g cos(m p) + h sin(m p)] dP (sin(phi)) n=1 m=0 n n n */ /* Equation 11 in the WMM Technical report. Derivative with respect to longitude, divided by radius. */ MagneticResults->By += SphVariables.RelativeRadiusPower[n] * (MagneticModel->Main_Field_Coeff_G[index] * SphVariables.sin_mlambda[m] - MagneticModel->Main_Field_Coeff_H[index] * SphVariables.cos_mlambda[m]) * (double) (m) * LegendreFunction-> Pcup[index]; /* nMax (n+2) n m m m Bx = - SUM (a/r) SUM [g cos(m p) + h sin(m p)] dP (sin(phi)) n=1 m=0 n n n */ /* Equation 10 in the WMM Technical report. Derivative with respect to latitude, divided by radius. */ MagneticResults->Bx -= SphVariables.RelativeRadiusPower[n] * (MagneticModel->Main_Field_Coeff_G[index] * SphVariables.cos_mlambda[m] + MagneticModel->Main_Field_Coeff_H[index] * SphVariables.sin_mlambda[m]) * LegendreFunction-> dPcup[index]; } } cos_phi = cos(DEG2RAD(CoordSpherical.phig)); if(fabs(cos_phi) > 1.0e-10) { MagneticResults->By = MagneticResults->By / cos_phi; } else /* Special calculation for component - By - at Geographic poles. * If the user wants to avoid using this function, please make sure that * the latitude is not exactly +/-90. An option is to make use the function * MAG_CheckGeographicPoles. */ { MAG_SummationSpecial(MagneticModel, SphVariables, CoordSpherical, MagneticResults); } return TRUE; }/*MAG_Summation */ int MAG_SummationSpecial(MAGtype_MagneticModel *MagneticModel, MAGtype_SphericalHarmonicVariables SphVariables, MAGtype_CoordSpherical CoordSpherical, MAGtype_MagneticResults *MagneticResults) /* Special calculation for the component By at Geographic poles. Manoj Nair, June, 2009 manoj.c.nair@noaa.gov INPUT: MagneticModel SphVariables CoordSpherical OUTPUT: MagneticResults CALLS : none See Section 1.4, "SINGULARITIES AT THE GEOGRAPHIC POLES", WMM Technical report */ { int n, index; double k, sin_phi, *PcupS, schmidtQuasiNorm1, schmidtQuasiNorm2, schmidtQuasiNorm3; PcupS = (double *) malloc((MagneticModel->nMax + 1) * sizeof (double)); if(PcupS == 0) { MAG_Error(14); return FALSE; } PcupS[0] = 1; schmidtQuasiNorm1 = 1.0; MagneticResults->By = 0.0; sin_phi = sin(DEG2RAD(CoordSpherical.phig)); for(n = 1; n <= MagneticModel->nMax; n++) { /*Compute the ration between the Gauss-normalized associated Legendre functions and the Schmidt quasi-normalized version. This is equivalent to sqrt((m==0?1:2)*(n-m)!/(n+m!))*(2n-1)!!/(n-m)! */ index = (n * (n + 1) / 2 + 1); schmidtQuasiNorm2 = schmidtQuasiNorm1 * (double) (2 * n - 1) / (double) n; schmidtQuasiNorm3 = schmidtQuasiNorm2 * sqrt((double) (n * 2) / (double) (n + 1)); schmidtQuasiNorm1 = schmidtQuasiNorm2; if(n == 1) { PcupS[n] = PcupS[n - 1]; } else { k = (double) (((n - 1) * (n - 1)) - 1) / (double) ((2 * n - 1) * (2 * n - 3)); PcupS[n] = sin_phi * PcupS[n - 1] - k * PcupS[n - 2]; } /* 1 nMax (n+2) n m m m By = SUM (a/r) (m) SUM [g cos(m p) + h sin(m p)] dP (sin(phi)) n=1 m=0 n n n */ /* Equation 11 in the WMM Technical report. Derivative with respect to longitude, divided by radius. */ MagneticResults->By += SphVariables.RelativeRadiusPower[n] * (MagneticModel->Main_Field_Coeff_G[index] * SphVariables.sin_mlambda[1] - MagneticModel->Main_Field_Coeff_H[index] * SphVariables.cos_mlambda[1]) * PcupS[n] * schmidtQuasiNorm3; } if(PcupS) free(PcupS); return TRUE; }/*MAG_SummationSpecial */ int MAG_TimelyModifyMagneticModel(MAGtype_Date UserDate, MAGtype_MagneticModel *MagneticModel, MAGtype_MagneticModel *TimedMagneticModel) /* Time change the Model coefficients from the base year of the model using secular variation coefficients. Store the coefficients of the static model with their values advanced from epoch t0 to epoch t. Copy the SV coefficients. If input "t�" is the same as "t0", then this is merely a copy operation. If the address of "TimedMagneticModel" is the same as the address of "MagneticModel", then this procedure overwrites the given item "MagneticModel". INPUT: UserDate MagneticModel OUTPUT:TimedMagneticModel CALLS : none */ { int n, m, index, a, b; TimedMagneticModel->EditionDate = MagneticModel->EditionDate; TimedMagneticModel->epoch = MagneticModel->epoch; TimedMagneticModel->nMax = MagneticModel->nMax; TimedMagneticModel->nMaxSecVar = MagneticModel->nMaxSecVar; a = TimedMagneticModel->nMaxSecVar; b = (a * (a + 1) / 2 + a); strcpy(TimedMagneticModel->ModelName, MagneticModel->ModelName); for(n = 1; n <= MagneticModel->nMax; n++) { for(m = 0; m <= n; m++) { index = (n * (n + 1) / 2 + m); if(index <= b) { TimedMagneticModel->Main_Field_Coeff_H[index] = MagneticModel->Main_Field_Coeff_H[index] + (UserDate.DecimalYear - MagneticModel->epoch) * MagneticModel->Secular_Var_Coeff_H[index]; TimedMagneticModel->Main_Field_Coeff_G[index] = MagneticModel->Main_Field_Coeff_G[index] + (UserDate.DecimalYear - MagneticModel->epoch) * MagneticModel->Secular_Var_Coeff_G[index]; TimedMagneticModel->Secular_Var_Coeff_H[index] = MagneticModel->Secular_Var_Coeff_H[index]; /* We need a copy of the secular var coef to calculate secular change */ TimedMagneticModel->Secular_Var_Coeff_G[index] = MagneticModel->Secular_Var_Coeff_G[index]; } else { TimedMagneticModel->Main_Field_Coeff_H[index] = MagneticModel->Main_Field_Coeff_H[index]; TimedMagneticModel->Main_Field_Coeff_G[index] = MagneticModel->Main_Field_Coeff_G[index]; } } } return TRUE; } /* MAG_TimelyModifyMagneticModel */ /*End of Spherical Harmonic Functions*/ /****************************************************************************** *************************************Geoid************************************ * This grouping consists of functions that make calculations to adjust * ellipsoid height to height above the geoid (Height above MSL). ****************************************************************************** ******************************************************************************/ int MAG_ConvertGeoidToEllipsoidHeight(MAGtype_CoordGeodetic *CoordGeodetic, MAGtype_Geoid *Geoid) /* * The function Convert_Geoid_To_Ellipsoid_Height converts the specified WGS84 * Geoid height at the specified geodetic coordinates to the equivalent * ellipsoid height, using the EGM96 gravity model. * * CoordGeodetic->phi : Geodetic latitude in degress (input) * CoordGeodetic->lambda : Geodetic longitude in degrees (input) * CoordGeodetic->HeightAboveEllipsoid : Ellipsoid height, in kilometers (output) * CoordGeodetic->HeightAboveGeoid: Geoid height, in kilometers (input) * CALLS : MAG_GetGeoidHeight ( */ { double DeltaHeight; int Error_Code; double lat, lon; if(Geoid->UseGeoid == 1) { /* Geoid correction required */ /* To ensure that latitude is less than 90 call MAG_EquivalentLatLon() */ MAG_EquivalentLatLon(CoordGeodetic->phi, CoordGeodetic->lambda, &lat, &lon); Error_Code = MAG_GetGeoidHeight(lat, lon, &DeltaHeight, Geoid); CoordGeodetic->HeightAboveEllipsoid = CoordGeodetic->HeightAboveGeoid + DeltaHeight / 1000; /* Input and output should be kilometers, However MAG_GetGeoidHeight returns Geoid height in meters - Hence division by 1000 */ } else /* Geoid correction not required, copy the MSL height to Ellipsoid height */ { CoordGeodetic->HeightAboveEllipsoid = CoordGeodetic->HeightAboveGeoid; Error_Code = TRUE; } return ( Error_Code); } /* MAG_ConvertGeoidToEllipsoidHeight*/ int MAG_GetGeoidHeight(double Latitude, double Longitude, double *DeltaHeight, MAGtype_Geoid *Geoid) /* * The function MAG_GetGeoidHeight returns the height of the * EGM96 geiod above or below the WGS84 ellipsoid, * at the specified geodetic coordinates, * using a grid of height adjustments from the EGM96 gravity model. * * Latitude : Geodetic latitude in radians (input) * Longitude : Geodetic longitude in radians (input) * DeltaHeight : Height Adjustment, in meters. (output) * Geoid : MAGtype_Geoid with Geoid grid (input) CALLS : none */ { long Index; double DeltaX, DeltaY; double ElevationSE, ElevationSW, ElevationNE, ElevationNW; double OffsetX, OffsetY; double PostX, PostY; double UpperY, LowerY; int Error_Code = 0; if(!Geoid->Geoid_Initialized) { MAG_Error(5); return (FALSE); } if((Latitude < -90) || (Latitude > 90)) { /* Latitude out of range */ Error_Code |= 1; } if((Longitude < -180) || (Longitude > 360)) { /* Longitude out of range */ Error_Code |= 1; } if(!Error_Code) { /* no errors */ /* Compute X and Y Offsets into Geoid Height Array: */ if(Longitude < 0.0) { OffsetX = (Longitude + 360.0) * Geoid->ScaleFactor; } else { OffsetX = Longitude * Geoid->ScaleFactor; } OffsetY = (90.0 - Latitude) * Geoid->ScaleFactor; /* Find Four Nearest Geoid Height Cells for specified Latitude, Longitude; */ /* Assumes that (0,0) of Geoid Height Array is at Northwest corner: */ PostX = floor(OffsetX); if((PostX + 1) == Geoid->NumbGeoidCols) PostX--; PostY = floor(OffsetY); if((PostY + 1) == Geoid->NumbGeoidRows) PostY--; Index = (long) (PostY * Geoid->NumbGeoidCols + PostX); ElevationNW = (double) Geoid->GeoidHeightBuffer[ Index ]; ElevationNE = (double) Geoid->GeoidHeightBuffer[ Index + 1 ]; Index = (long) ((PostY + 1) * Geoid->NumbGeoidCols + PostX); ElevationSW = (double) Geoid->GeoidHeightBuffer[ Index ]; ElevationSE = (double) Geoid->GeoidHeightBuffer[ Index + 1 ]; /* Perform Bi-Linear Interpolation to compute Height above Ellipsoid: */ DeltaX = OffsetX - PostX; DeltaY = OffsetY - PostY; UpperY = ElevationNW + DeltaX * (ElevationNE - ElevationNW); LowerY = ElevationSW + DeltaX * (ElevationSE - ElevationSW); *DeltaHeight = UpperY + DeltaY * (LowerY - UpperY); } else { MAG_Error(17); return (FALSE); } return TRUE; } /*MAG_GetGeoidHeight*/ void MAG_EquivalentLatLon(double lat, double lon, double *repairedLat, double *repairedLon) /*This function takes a latitude and longitude that are ordinarily out of range and gives in range values that are equivalent on the Earth's surface. This is required to get correct values for the geoid function.*/ { double colat; colat = 90 - lat; *repairedLon = lon; if (colat < 0) colat = -colat; while(colat > 360) { colat-=360; } if (colat > 180) { colat-=180; *repairedLon = *repairedLon+180; } *repairedLat = 90 - colat; if (*repairedLon > 360) *repairedLon-=360; if (*repairedLon < -180) *repairedLon+=360; } /*End of Geoid Functions*/ /*New Error Functions*/ void MAG_WMMErrorCalc(double H, MAGtype_GeoMagneticElements *Uncertainty) { double decl_variable, decl_constant; Uncertainty->F = WMM_UNCERTAINTY_F; Uncertainty->H = WMM_UNCERTAINTY_H; Uncertainty->X = WMM_UNCERTAINTY_X; Uncertainty->Z = WMM_UNCERTAINTY_Z; Uncertainty->Incl = WMM_UNCERTAINTY_I; Uncertainty->Y = WMM_UNCERTAINTY_Y; decl_variable = (WMM_UNCERTAINTY_D_COEF / H); decl_constant = (WMM_UNCERTAINTY_D_OFFSET); Uncertainty->Decl = sqrt(decl_constant*decl_constant + decl_variable*decl_variable); if (Uncertainty->Decl > 180) { Uncertainty->Decl = 180; } } void MAG_PrintUserDataWithUncertainty(MAGtype_GeoMagneticElements GeomagElements, MAGtype_GeoMagneticElements Errors, MAGtype_CoordGeodetic SpaceInput, MAGtype_Date TimeInput, MAGtype_MagneticModel *MagneticModel, MAGtype_Geoid *Geoid) { char DeclString[100]; char InclString[100]; MAG_DegreeToDMSstring(GeomagElements.Incl, 2, InclString); if(GeomagElements.H < 6000 && GeomagElements.H > 2000) MAG_Warnings(1, GeomagElements.H, MagneticModel); if(GeomagElements.H < 2000) MAG_Warnings(2, GeomagElements.H, MagneticModel); if(MagneticModel->SecularVariationUsed == TRUE) { MAG_DegreeToDMSstring(GeomagElements.Decl, 2, DeclString); printf("\n Results For \n\n"); if(SpaceInput.phi < 0) printf("Latitude %.2fS\n", -SpaceInput.phi); else printf("Latitude %.2fN\n", SpaceInput.phi); if(SpaceInput.lambda < 0) printf("Longitude %.2fW\n", -SpaceInput.lambda); else printf("Longitude %.2fE\n", SpaceInput.lambda); if(Geoid->UseGeoid == 1) printf("Altitude: %.2f Kilometers above mean sea level\n", SpaceInput.HeightAboveGeoid); else printf("Altitude: %.2f Kilometers above the WGS-84 ellipsoid\n", SpaceInput.HeightAboveEllipsoid); printf("Date: %.1f\n", TimeInput.DecimalYear); printf("\n Main Field\t\t\tSecular Change\n"); printf("F = %9.1f +/- %5.1f nT\t\t Fdot = %5.1f\tnT/yr\n", GeomagElements.F, Errors.F, GeomagElements.Fdot); printf("H = %9.1f +/- %5.1f nT\t\t Hdot = %5.1f\tnT/yr\n", GeomagElements.H, Errors.H, GeomagElements.Hdot); printf("X = %9.1f +/- %5.1f nT\t\t Xdot = %5.1f\tnT/yr\n", GeomagElements.X, Errors.X, GeomagElements.Xdot); printf("Y = %9.1f +/- %5.1f nT\t\t Ydot = %5.1f\tnT/yr\n", GeomagElements.Y, Errors.Y, GeomagElements.Ydot); printf("Z = %9.1f +/- %5.1f nT\t\t Zdot = %5.1f\tnT/yr\n", GeomagElements.Z, Errors.Z, GeomagElements.Zdot); if(GeomagElements.Decl < 0) printf("Decl =%20s (WEST) +/-%3.0f Min Ddot = %.1f\tMin/yr\n", DeclString, 60 * Errors.Decl, 60 * GeomagElements.Decldot); else printf("Decl =%20s (EAST) +/-%3.0f Min Ddot = %.1f\tMin/yr\n", DeclString, 60 * Errors.Decl, 60 * GeomagElements.Decldot); if(GeomagElements.Incl < 0) printf("Incl =%20s (UP) +/-%3.0f Min Idot = %.1f\tMin/yr\n", InclString, 60 * Errors.Incl, 60 * GeomagElements.Incldot); else printf("Incl =%20s (DOWN) +/-%3.0f Min Idot = %.1f\tMin/yr\n", InclString, 60 * Errors.Incl, 60 * GeomagElements.Incldot); } else { MAG_DegreeToDMSstring(GeomagElements.Decl, 2, DeclString); printf("\n Results For \n\n"); if(SpaceInput.phi < 0) printf("Latitude %.2fS\n", -SpaceInput.phi); else printf("Latitude %.2fN\n", SpaceInput.phi); if(SpaceInput.lambda < 0) printf("Longitude %.2fW\n", -SpaceInput.lambda); else printf("Longitude %.2fE\n", SpaceInput.lambda); if(Geoid->UseGeoid == 1) printf("Altitude: %.2f Kilometers above MSL\n", SpaceInput.HeightAboveGeoid); else printf("Altitude: %.2f Kilometers above WGS-84 Ellipsoid\n", SpaceInput.HeightAboveEllipsoid); printf("Date: %.1f\n", TimeInput.DecimalYear); printf("\n Main Field\n"); printf("F = %-9.1f +/-%5.1f nT\n", GeomagElements.F, Errors.F); printf("H = %-9.1f +/-%5.1f nT\n", GeomagElements.H, Errors.H); printf("X = %-9.1f +/-%5.1f nT\n", GeomagElements.X, Errors.X); printf("Y = %-9.1f +/-%5.1f nT\n", GeomagElements.Y, Errors.Y); printf("Z = %-9.1f +/-%5.1f nT\n", GeomagElements.Z, Errors.Z); if(GeomagElements.Decl < 0) printf("Decl =%20s (WEST)+/-%4f\n", DeclString, 60 * Errors.Decl); else printf("Decl =%20s (EAST)+/-%4f\n", DeclString, 60 * Errors.Decl); if(GeomagElements.Incl < 0) printf("Incl =%20s (UP)+/-%4f\n", InclString, 60 * Errors.Incl); else printf("Incl =%20s (DOWN)+/-%4f\n", InclString, 60 * Errors.Incl); } if(SpaceInput.phi <= -55 || SpaceInput.phi >= 55) /* Print Grid Variation */ { MAG_DegreeToDMSstring(GeomagElements.GV, 2, InclString); printf("\n\n Grid variation =%20s\n", InclString); } }/*MAG_PrintUserDataWithUncertainty*/ void MAG_GetDeg(char* Query_String, double* latitude, double bounds[2]) { /*Gets a degree value from the user using the standard input*/ char buffer[64], Error_Message[255]; int done, i, j; printf("%s", Query_String); while (NULL == fgets(buffer, 64, stdin)){ printf("%s", Query_String); } for(i = 0, done = 0, j = 0; i <= 64 && !done; i++) { if(buffer[i] == '.') { j = sscanf(buffer, "%lf", latitude); if(j == 1) done = 1; else done = -1; } if(buffer[i] == ',') { if(MAG_ValidateDMSstring(buffer, bounds[0], bounds[1], Error_Message)) { MAG_DMSstringToDegree(buffer, latitude); done = 1; } else done = -1; } if(buffer[i] == ' ')/* This detects if there is a ' ' somewhere in the string, if there is the program tries to interpret the input as Degrees Minutes Seconds.*/ { if(MAG_ValidateDMSstring(buffer, bounds[0], bounds[1], Error_Message)) { MAG_DMSstringToDegree(buffer, latitude); done = 1; } else done = -1; } if(buffer[i] == '\0' || done == -1) { if(MAG_ValidateDMSstring(buffer, bounds[0], bounds[1], Error_Message) && done != -1) { sscanf(buffer, "%lf", latitude); done = 1; } else { printf("%s", Error_Message); strcpy(buffer, ""); printf("\nError encountered, please re-enter as '(-)DDD,MM,SS' or in Decimal Degrees DD.ddd:\n"); while(NULL == fgets(buffer, 40, stdin)) { printf("\nError encountered, please re-enter as '(-)DDD,MM,SS' or in Decimal Degrees DD.ddd:\n"); } i = -1; done = 0; } } } } int MAG_GetAltitude(char* Query_String, MAGtype_Geoid *Geoid, MAGtype_CoordGeodetic* coords, int bounds[2], int AltitudeSetting){ int done, j, UpBoundOn; char tmp; char buffer[64]; double value; done = 0; if(bounds[1] != NO_ALT_MAX){ UpBoundOn = TRUE; } else { UpBoundOn = FALSE; } printf("%s", Query_String); while(!done) { strcpy(buffer, ""); while(NULL == fgets(buffer, 40, stdin)) { printf("%s", Query_String); } j = 0; if((AltitudeSetting != MSLON) && (buffer[0] == 'e' || buffer[0] == 'E' || AltitudeSetting == WGS84ON)) /* User entered height above WGS-84 ellipsoid, copy it to CoordGeodetic->HeightAboveEllipsoid */ { if(buffer[0]=='e' || buffer[0]=='E') { j = sscanf(buffer, "%c%lf", &tmp, &coords->HeightAboveEllipsoid); } else { j = sscanf(buffer, "%lf", &coords->HeightAboveEllipsoid); } if(j == 2) j = 1; Geoid->UseGeoid = 0; coords->HeightAboveGeoid = coords->HeightAboveEllipsoid; value = coords->HeightAboveEllipsoid; } else /* User entered height above MSL, convert it to the height above WGS-84 ellipsoid */ { Geoid->UseGeoid = 1; j = sscanf(buffer, "%lf", &coords->HeightAboveGeoid); MAG_ConvertGeoidToEllipsoidHeight(coords, Geoid); value = coords->HeightAboveGeoid; } if(j == 1) done = 1; else printf("\nIllegal Format, please re-enter as '(-)HHH.hhh:'\n"); if((value < bounds[0] || (value > bounds[1] && UpBoundOn)) && done == 1) { if(UpBoundOn) { done = 0; printf("\nWarning: The value you have entered of %f km for the elevation is outside of the required range.\n", value); printf(" An elevation between %d km and %d km is needed. \n", bounds[0], bounds[1]); if (AltitudeSetting == WGS84ON){ printf("Please enter height above WGS-84 Ellipsoid (in kilometers):\n"); } else if (AltitudeSetting==MSLON){ printf("Please enter height above mean sea level (in kilometers):\n"); } else { printf("Please enter height in kilometers (prepend E for height above WGS-84 Ellipsoid):"); } } else { switch(MAG_Warnings(3, value, NULL)) { case 0: return USER_GAVE_UP; case 1: done = 0; printf("Please enter height above sea level (in kilometers):\n"); break; case 2: break; } } } } return 0; } acm-6.0_20200416/src/Makefile0000644000000000000000000000076013646045023014030 0ustar rootrootall: find . -mindepth 2 -name Makefile \ | while read m; do make -C $$(dirname $$m) all || exit 1; done clean: rm -rf doxygen-html find . -mindepth 2 -name Makefile \ | while read m; do make -C $$(dirname $$m) clean || exit 1; done rebuild: find . -mindepth 2 -name Makefile \ | while read m; do make -C $$(dirname $$m) rebuild || exit 1; done doc: rm -rf doxygen-html find . -mindepth 2 -name Makefile \ | while read m; do make -C $$(dirname $$m) doc || exit 1; doneacm-6.0_20200416/src/util/0000755000000000000000000000000013646051406013344 5ustar rootrootacm-6.0_20200416/src/util/reader.h0000644000000000000000000001056713260344465014772 0ustar rootroot/** * Text file reader. Allows to read a text file line by line. Some basic path * and file names manipulation routines are also provided. * * @file * @author Umberto Salsi * @version $Date: 2017/11/02 07:43:53 $ */ #ifndef READER_H #define READER_H #ifdef reader_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * State of the reader. */ typedef struct reader_Type reader_Type; /** * Opens a text file for reading. On error, the error string is set and any * further read request fails. * @return New reader_Type. Must be released with memory_dispose(). */ EXTERN reader_Type * reader_new(char *path); /** * Gets the next line from file. Leading spaces, trailing spaces and * new-line are removed. * @param this * @param line Destination buffer for the line. * @param line_capacity Destination buffer capacity. * @return True if a new line is available, or false on end of the file or * error. */ EXTERN int reader_getLine(reader_Type *this, char *line, int line_capacity); /** Returns the path of the file being read. */ EXTERN char * reader_getPath(reader_Type *this); /** Returns the line number of the line just read; first line is no. 1. */ EXTERN int reader_getLineNumber(reader_Type *this); /** * Returns the description of the last error occurred. * @param this * @return Description of the last error occurred, or NULL if no error. */ EXTERN char * reader_getError(reader_Type *this); /* ---------------- UTILITIES -------------------------------------------- */ /** * Returns true if the path is absolute. * * A NULL or empty string is an absolute path (!). * * Under Unix and Linux, a path is absolute if it starts with slash '/'. * * Under Windows, a path is considered absolute if one of this conditions holds: * 1. it starts with slash '/' or back-slash '\' or: * 2. it starts with a letter followed by ':'. * Note that a drive letter followed by a relative path like "C:y\z" is assumed * to be absolute, although the "y\z" path is actually a relative path. * * FIXME: naive implementation as it does not account for duplicates slashes nor * special paths "." and "..". * * @param path * @return True if the path is absolute. */ EXTERN int reader_isAbsolute(char *path); /** * Resolves the relative path of a file specified inside another file. * Example: the file "models/data.txt" contains a relative reference to the * file "data2.txt" then the returned path is "models/data2.txt". * @param from File name containing the path. * @param to File name contained inside the file above. If already absolute, * does nothing and returns a copy of this path. * @return Resolved file path. The returned name is dynamically allocated and * must be released with memory_dispose(). */ EXTERN char * reader_resolveRelativePath(char *from, char *to); /** * Returns true if the file is readable. * @param path * @return True if the file is readable. */ EXTERN int reader_isReadable(char *path); /** * Split the string into fields separated by white spaces. * @param s Line to split in place. Beware: the content of this string gets * modified to add the NUL string terminators after each found field. * @param argc Here returns the number of parsed fields. * @param argv Here returns the pointers to the split fields. * @param argv_capacity Maximum number of fields. * @return True on success; false if there are too many fields and only the * first argv_capacity have been parsed and returned. */ EXTERN int reader_split(char *s, int *argc, char *argv[], int argv_capacity); /** * Split the string into fields separated by comma. Double-quotes can be used * to include spaces (which are otherwise ignored) and the comma itself. * Inside double-quotes, two consecutive double-quote characters are a returned * as a single double quote (double-quote escaping). * @param s Line to split in place. Beware: the content of this string gets * modified to add the NUL string terminators after each found field. * @param argc Here returns the number of parsed fields. * @param argv Here returns the pointers to the split fields. * @param argv_capacity Maximum number of fields. * @return True on success; false if there are too many fields and only the * first argv_capacity have been parsed and returned. */ EXTERN int reader_splitDoubleQuotedCommaSeparated(char *s, int *argc, char *argv[], int argv_capacity); #undef EXTERN #endif acm-6.0_20200416/src/util/varray.h0000644000000000000000000001474313175227305015032 0ustar rootroot/** * Dynamic array of pointers with versioned handle. Entries are made accessible * through an handle; each handle contains both an index and a version counter. * * RATIONALE. When complex data structures are used in programs, with * many cross references, versioned handles make easier to detect accesses * to stale entries. Simple arrays and pointers are not safe to this aim. * * Entries can be occupied or detached. The difference is that occupied entries * are freely accessible through their handle and can be scanned sequentially. * Detached entries can be recycled to reuse their space, but a brand new handle * is assigned to them. Any attempt to access a detached entry or invalid handle * is fatal. * * The zero value is never a valid handle just like NULL for pointer, so it is * safe to initialize data structures to zero. * * To add an entry, it is mandatory to first check if a detached entry is * available before attempting to allocate a new entry. Typical example: * *
 * varray_Type *va = ...array of string buffers...
 * int handle = varray_getDetachedHandle(va);
 * if( handle == 0 )
 *     handle = varray_addValue(va, malloc(100));
 * 
* * Retrieving an entry given its handle: * *
char *s = varray_getValue(va, handle);
* * Detaching an entry we may want to reuse later, but invalidating its current * handle so nobody can access it anymore and, if it does so, aborts: * *
varray_detach(s_handle);
* * Checking if an handle is still referring a fresh, occupied entry: * *
if( varray_isValidHandle(buffers, s_handle) ) ...
* * Sequential access to the elements of the array is allowed in constant time * through an internal cursor: varray_firstHandle() returns the handle of the * first occupied entry, and varray_nextHandle() moves the cursor to the next * entry: * *
 * for(i = varray_firstHandle(va); i != 0; i = varray_nextHandle(va))
 *     printf("%s\n", (char *) varray_getValue(va, i));
 * varray_releaseIterator(va);
 * 
* * In this implementation, only one iteration at a time is allowed per array; * the firstHandle() method sets the internal lock on this iterator, and the * releaseIterator() release this lock, so each call to firstHandle() must be * balanced by a corresponding call to releaseHandle(); nested usage of the * same iterator is a fatal error. * * The current entry under the cursor can be detached; scanning continues with * the next entry. * * Note that dynamic arrays never attempt to access the values stored, and neither * attempt to release them from memory. Releasing entries is in charge of the * client. One safe way to do that is to detach the occupied entries and then * reclaim and release each entry: * *
 * for(i = varray_firstHandle(va); i != 0; i = varray_nextHandle(va)){
 *     programSpecificTurnOffProcedure(i);
 *     varray_detach(va, i);
 * }
 * varray_releaseIterator(va);
 * while( (i = varray_getDetacheddHandle) != 0 )
 *     memory_dispose( varray_getValue(va, i) );
 * memory_dispose(va);
 * 
* * @file * @author Umberto Salsi * @version $Date: 2017/10/29 01:28:37 $ */ #ifndef VARRAY_H #define VARRAY_H #ifdef varray_IMPORT #define EXTERN #else #define EXTERN extern #endif typedef struct varray_Type varray_Type; /** * Allocates a new empty array. * @return New array. Must be released with memory_dispose(). */ EXTERN varray_Type * varray_new(void); /** * Returns the number of occupied entries, that is the number of entries that * would be returned in sequential scanning. * @param this * @return */ EXTERN int varray_length(varray_Type *this); /** * Returns the value at a specified handle of occupied entry. Aborts if: * invalid handle; entry is now detached; entry has been detached and reused * and then the handle is "stale". * See also: varray_isValidHandle(). * @param this * @param handle * @return Value allocated in the specified entry. */ EXTERN void * varray_getValue(varray_Type *this, int handle); /** * Returns the handle of a previously detached entry, making it 'occupied' * again. Note that the returned handle differs from that the entry had before. * If no detached entries available, returns 0 and the client has to add a new * entry. * See also: varray_addValue(). * @param this * @return Handle of a previously detached entry, or 0 if no detached entries * are available. */ EXTERN int varray_getDetachedHandle(varray_Type *this); /** * Adds a new entry, marking it as occupied. Client MUST always try to reuse * an existing detached entry by calling varray_getDetachedHandle() first; * invoking this function when detached entries are available is fatal. * @param this * @param value Value to set. * @return Handle of the newly allocated entry. */ EXTERN int varray_addValue(varray_Type *this, void *value); /** * Sets the value of a currently occupied entry. Aborts if: invalid handle; * handle of detached entry. * @param this * @param handle Handle of the occupied entry. * @param value New value to set. */ EXTERN void varray_setValue(varray_Type *this, int handle, void *value); /** * Returns true if the given handle refers to a occupied entry. * @param this * @param handle * @return True if the given handle refers to a occupied entry. False in any * other case. */ EXTERN int varray_isValidHandle(varray_Type *this, int handle); /** * Detaches entry, so it is not returned in scanning. * @param this * @param handle */ EXTERN void varray_detach(varray_Type *this, int handle); /** * Returns the handle to a first used entry from which to start * sequential scanning of the used entries. The exact order of the entries * returned in scanning is not specified, although it mostly follows the same * order the entries where added. Set a lock on the array iterator which MUST be * reset later with varray_releaseIterator(). * See also: varray_nextHandle(). * @param this * @return Handle of the first entry from which starting scanning, or 0 if there * are no currently used entries. */ EXTERN int varray_firstHandle(varray_Type *this); /** * Returns the handle to the next used entry. * See also: varray_firstHandle(). * @param this * @param handle Handle of the current entry being scanned, or 0 at the end of * the list of occupied entries. */ EXTERN int varray_nextHandle(varray_Type *this); /** * Releases the lock on the iterator bound to this array. * @param this */ EXTERN void varray_releaseIterator(varray_Type *this); #undef EXTERN #endif acm-6.0_20200416/src/util/prng.h0000644000000000000000000000305113107240552014454 0ustar rootroot/** * Pseudo-random number generator routines. * * The internal seed is initialized quite randomly so that this module starts * a new different pseudo-random sequence each time it is used. * * @file * @author Umberto Salsi * @version $Date: 2017/05/18 06:38:34 $ */ #ifndef PRNG_H #define PRNG_H #ifdef prng_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Set the initial seed. This function can be called to force the generator * to return the same sequence of random numbers. If not invoked, the module * initializes itself using a seed value calculated mixing the current time * (seconds and microseconds), total ticks counter and process ID. * @param seed */ EXTERN void prng_setSeed(unsigned int seed); /** * Returns a pseudo-random integer number in the specified range. * @param min Minimum value expected. * @param max Maximum value expected. * @return Generated pseudo-random number in the range [min,max]. */ EXTERN int prng_getIntInRange(int min, int max); /** * Returns a pseudo-random number in the range [0.0,1.0[. * @return Generated pseudo-random number in the range [0.0,1.0[. */ EXTERN double prng_getDouble(void); /** * Returns a pseudo-random number in the range [-1.0,1.0[. * @return Generated pseudo-random number in the range [-1.0,1.0[. */ EXTERN double prng_getDouble2(void); /** * Fill-in buffer with random bytes. * @param buffer Pointer to the buffer. * @param buffer_len Length of the buffer. */ EXTERN void prng_fill(void *buffer, int buffer_len); #undef EXTERN #endif acm-6.0_20200416/src/util/reader.c0000644000000000000000000000755613260344465014771 0ustar rootroot#include #include #include #include #include #include #include "memory.h" #define reader_IMPORT #include "reader.h" struct reader_Type { char * path; // path of the file FILE * file; // opened file char * err; // error string int line_no; // current line no., first is 1 }; static void reader_destruct(void *p) { reader_Type *this = (reader_Type *) p; fclose(this->file); memory_dispose(this->path); } reader_Type * reader_new(char *path) { reader_Type *this = memory_allocate(sizeof(reader_Type), reader_destruct); this->path = memory_strdup(path); this->file = fopen(path, "r"); if( this->file == NULL ) this->err = strerror(errno); else this->err = NULL; this->line_no = 0; return this; } int reader_getLine(reader_Type *this, char *line, int line_capacity) { if( this->err != NULL ) return 0; if( fgets(line, line_capacity, this->file) == NULL ){ if( ferror(this->file) ) this->err = strerror(errno); return 0; } int l = strlen(line); /* Remove trailing spaces: */ while( l > 0 && isspace(line[l-1]) ){ line[l-1] = '\0'; l--; } /* Remove leading spaces: */ int start = 0; while( isspace(line[start]) ) start++; if( start > 0 ) memmove(&line, line + start, l - start + 1); this->line_no++; return 1; } char * reader_getPath(reader_Type *this) { return this->path; } int reader_getLineNumber(reader_Type *this) { return this->line_no; } char * reader_getError(reader_Type *this) { return this->err; } static int isSept(char c) { #ifdef WINNT return c == '/' || c == '\\'; #else return c == '/'; #endif } int reader_isAbsolute(char *path) { if( path == NULL || *path == 0 ) return 1; #ifdef WINNT return isSept(path[0]) || ((('A' <= path[0] && path[0] <= 'Z') || ('a' <= path[0] && path[0] <= 'z')) && path[1] == ':'); #else return isSept(*path); #endif } #ifdef WINNT static char * rindex(char *s, int c) { char *found = NULL; while(*s != 0){ if( *s == c ) found = s; s++; } return found; } #endif char * reader_resolveRelativePath(char *from, char *to) { if( reader_isAbsolute(to) ) return memory_strdup(to); char *last_slash_ptr; int res_capacity; char *res; if( to[0] == '/' ) // 'to' is already absolute -- nothing to do. return memory_strdup(to); last_slash_ptr = rindex(from, '/'); if( last_slash_ptr == NULL ) return memory_strdup(to); res_capacity = 1 + strlen(to) + (last_slash_ptr - from + 1); res = memory_allocate(res_capacity, NULL); strncpy(res, from, last_slash_ptr - from + 1); strcat(res, to); return res; } int reader_isReadable(char *path) { FILE *f = fopen(path, "r"); if( f == NULL ){ return 0; } else { fclose(f); return 1; } } int reader_split(char *s, int *argc, char *argv[], int argv_capacity) { *argc = 0; while(1) { while( isspace(*s) ) s++; if( *s == 0 ) return 1; if( argv_capacity <= 0 ) return 0; argv_capacity--; (*argc)++; *argv = s; argv++; while(1) { s++; if( *s == 0 ) return 1; if( isspace(*s) ){ *s = 0; s++; break; } } } } int reader_splitDoubleQuotedCommaSeparated(char *s, int *argc, char *argv[], int argv_capacity) { *argc = 0; while(1) { while( isspace(*s) ) s++; if( *s == 0 ) return 1; if( argv_capacity <= 0 ) return 0; argv_capacity--; (*argc)++; *argv = s; argv++; char *dst = s; char inQuotes = 0; while(1) { if( *s == '"' ){ if( inQuotes ){ s++; if( *s == '"' ){ s++; *dst = '"'; dst++; } else { inQuotes = 0; } } else { inQuotes = 1; s++; } } else if( *s == 0 ){ *dst = 0; return 1; } else if( inQuotes ){ *dst = *s; s++; dst++; } else { if( isspace(*s) ){ s++; } else if( *s == ',' ){ s++; *dst = 0; break; } else { *dst = *s; s++; dst++; } } } } }acm-6.0_20200416/src/util/audio.c0000644000000000000000000006253013260344465014621 0ustar rootroot/* * Here there are two distinct implementations of the audio.h interface: * * 1. Windows. * * 2. Linux. * */ #ifdef WINNT /* * Windows implementation. * * IMPLEMENTATION NOTES. * * 0. A pulse-code modulation (PCM) sound consists in a sequence of frames, * each frame contains one sample for each channel in the order (for example, * channel 0 is left, channel 1 is right). Frames are played by the audio * driver at a given fixed rate. This rate can be changed, but see note 2. * The audio driver must be feed with an integral number of frames, that is * frames cannot be split. Each sample is assumed to be a little-endian byte * ordered integer number, which is exactly the case of the WAV files. * * 1. A feeder thread is created for each sound to play, so avoiding any * interruption in the execution of the main program. Once the feeder thread * has taken control of the sound, the main thread must not change or release * the data structures of the sound, with the only exception of some parameters: * rate of sampling, start/stop, thread termination request. * * 2. The audio driver may or may not support rate changes. Closing the device * and opening the device again just to change the rate would cause a brief * sound interruption the user would ear as a "click", so it is not suitable. * Then if the audio driver does not support rate changes, we must implement * our built-in re-sampler at the cost of a bit of CPU load. Resampling is * performed in the feeder thread, and the resulting re-sampled audio is then * sent to the audio driver which will play these frames at its own current * fixed rate. * * 3. The feeder thread sends to the audio driver chunks of sampled frames * of fixed size. Each chunk is played by the audio driver in a time of * * t = CHUNK_SIZE / (frameLength * nSamplesPerSec) * * seconds. Between each frame sent to the audio driver, the feeder thread here * checks the status of the sound, including the requested rate and start/stop. * By setting a value too large, the program reacts slowly to the changes and * a continuous rate pitch change becomes a sequence of tones instead. * By setting a value too small, slower machines may fail to feed the audio * driver with enough data and the sound becomes intermittent. * * For example, by setting a reasonable time of t = 0.1 s and a sound sampled * at 8000 Hz, 1 byte/frame, the resulting chunk size is: * * CHUNK_SIZE = t * frameLength * nSamplesPerSec = 800 bytes * * Again, still with t = 0.1 s but with a sound sampled at 44100 Hz, 16 bits per * sample and stereophonic (frame length of 4 bytes), we have: * * CHUNK_SIZE = 17640 bytes * * For our monophonic, 1 byte/frame, 8000 Hz audio samples, 1024 seems to be a * good compromise. An improved implementation would require to tune this value * based on the actual frame length and frame rate of each sound. */ #include #include #include #include "error.h" #include "memory.h" #include "wav.h" #define audio_IMPORT #include "audio.h" #include #include /** * Maximum length of the chunks sent to the audio driver. See implementation * note 3. */ #define CHUNK_SIZE (1024) struct audio_Type { /** Audio device. */ HWAVEOUT wave_out; /** Consumed chunks and thread termination requests signaled through this. */ HANDLE event; /** Thread that feeds chunks to the driver. See implementation note 1. */ HANDLE thread; /** Pause flag. */ int is_paused; /** Destructor sets this to ask feeding thread to terminate. * See implementation note 1. */ int thread_termination_request_pending; /** Loop execution flag. */ int loop; /** New cursor position requested flag; position_request_at is the value. */ int position_request_pending; /** Byte offset in the sample data where to set the cursor. */ int position_request_at; /** Current sampling rate requested by client. */ DWORD currentSamplesPerSec; /** Index to the next byte of sample data to play. */ int cursor; /** WAV file parameters. */ wav_Type *wav; /** * Chunks descriptor data for chunks to send to the driver. When playing, * tries to fill and send to the driver both the chunks to avoid the * annoying "click" sound. */ WAVEHDR chunks_headers[2]; /** Chunks of frames. */ char chunks_data[2][CHUNK_SIZE]; }; /** * Whether waveOutSetPitch() works on this device. If that function fails, * uses internal emulation. See implementation note 3. */ static int pitchChangeSupportedByDevice = 1; static void CALLBACK audio_waveOutputCallback(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) { audio_Type *this = (audio_Type *) dwInstance; switch (uMsg) { case WOM_OPEN: break; case WOM_DONE: SetEvent(this->event); break; case WOM_CLOSE: break; default: error_internal("unexpected event code: %d", uMsg); } } /** * Software emulation of the pitch changer. Used when hw support is missing, * see implementation note 3. * Increments this->index by the number of bytes copied or skipped from the * source (depending on the pitch skew rate) and returns the number of bytes * copied in the destination. * @param this * @param src Source of the original audio samples. * @param src_len Length in bytes of the source buffer of samples. * @param dst Destination of the re-sampled audio. * @param dst_len Length in bytes of the destination buffer. Must contain at * least one sample or a fatal error occurs. * @return Number of bytes actually copied in the destination. */ static int audio_resample(audio_Type *this, char *src, int src_len, char *dst, int dst_len) { int src_rate = this->wav->nSamplesPerSec; int dst_rate = this->currentSamplesPerSec; int sample_len = this->wav->nBlockAlign; // Pitch factor maps byte offset of the src into dst: double k = (double) dst_rate / (sample_len * src_rate); dst_len -= dst_len % sample_len; assert(dst_len >= sample_len); // For each dst sample, calculate the src sample and copy. int src_byte_index = 0; int dst_byte_index = 0; while( dst_byte_index < dst_len ){ src_byte_index = sample_len * (int) (dst_byte_index * k + 0.5); if( src_byte_index >= src_len ) break; memcpy(dst + dst_byte_index, src + src_byte_index, sample_len); dst_byte_index += sample_len; } this->cursor += src_byte_index + sample_len; return dst_byte_index; } /** * Fill-in and send to the audio driver a chunk of audio data. * @param this * @param index Chunk to fill, either 0 or 1. * @return True if some data available and sent, false if chunk empty. */ static int audio_fillAndFeedChunk(audio_Type *this, int index) { UINT avail_in_buffer = CHUNK_SIZE; WAVEHDR *wavehdr = &this->chunks_headers[index]; wavehdr->dwFlags &= ~WHDR_DONE; int sample_len = this->wav->nBlockAlign; if( this->position_request_pending ){ this->position_request_pending = 0; this->cursor = this->position_request_at; } do { int avail_in_sample = this->wav->data_len - this->cursor; if (avail_in_sample <= 0) { if( this->loop ){ this->cursor = 0; avail_in_sample = this->wav->data_len; } else { break; } } if( ! pitchChangeSupportedByDevice && this->currentSamplesPerSec != this->wav->nSamplesPerSec ){ // Do pitch change when no hw support available. avail_in_buffer -= audio_resample(this, this->wav->data + this->cursor, avail_in_sample, this->chunks_data[index] + CHUNK_SIZE - avail_in_buffer, avail_in_buffer); } else { // Basic algo when no pitch change or hw supports pitch change hw. int to_copy = avail_in_sample; if (to_copy > avail_in_buffer) to_copy = avail_in_buffer; memcpy(this->chunks_data[index] + CHUNK_SIZE - avail_in_buffer, this->wav->data + this->cursor, to_copy); this->cursor += to_copy; avail_in_buffer -= to_copy; } } while (avail_in_buffer > sample_len); wavehdr->lpData = this->chunks_data[index]; wavehdr->dwFlags = 0; wavehdr->dwBufferLength = CHUNK_SIZE - avail_in_buffer; if( wavehdr->dwBufferLength == 0 ){ return 0; } else { waveOutPrepareHeader(this->wave_out, wavehdr, sizeof(WAVEHDR)); waveOutWrite(this->wave_out, &this->chunks_headers[index], sizeof(WAVEHDR)); return 1; } } /** * Driver buffer feeder thread. Continuously feeds the driver with 2 chunks if * possible. See implementation note 1. * Suspends if end of the audio data reached and no loop enabled, but restarts * whenever loop enabled or current position moved back. * Note that the pause feature is already built-in in the driver so does not * need to be replicated here. * This function returns when this->thread_termination_request_pending is set. * @param pDataInput * @return */ static DWORD WINAPI audio_feeder(PVOID pDataInput) { audio_Type *this = (audio_Type *) pDataInput; // Marks all chunks as available. this->chunks_headers[0].dwFlags = 0; this->chunks_headers[1].dwFlags = 0; while (!this->thread_termination_request_pending) { if( ! this->is_paused ){ // Try to fill and send to the driver as many chunks as possible. if ( this->chunks_headers[0].dwFlags == 0 ) audio_fillAndFeedChunk(this, 0); if ( this->chunks_headers[1].dwFlags == 0 ) audio_fillAndFeedChunk(this, 1); } // Wait for either chunk consumed or timeout or more data to play // available because loop enabled or playing resumed, or thread // termination request from destructor: int waitStatus = WaitForSingleObject(this->event, 123); switch(waitStatus){ case WAIT_OBJECT_0: // Some chunk consumed by driver. Make it available again. if ( this->chunks_headers[0].dwFlags & WHDR_DONE ) this->chunks_headers[0].dwFlags = 0; if ( this->chunks_headers[1].dwFlags & WHDR_DONE ) this->chunks_headers[1].dwFlags = 0; break; case WAIT_TIMEOUT: // Still no chunk consumed, or no data to send (wav ended or pause). break; default: error_internal("WaitForSingleObject() returned code %d", waitStatus); } } waveOutReset(this->wave_out); return 0; } static void audio_destruct(void *p) { audio_Type *this = (audio_Type *) p; if (this->thread) { this->thread_termination_request_pending = 1; SetEvent(this->event); WaitForSingleObject(this->thread, INFINITE); CloseHandle(this->event); CloseHandle(this->thread); } waveOutClose(this->wave_out); memory_dispose(this->wav); } audio_Type * audio_new(char * wav_filename) { audio_Type *this = memory_allocate(sizeof(audio_Type), audio_destruct); memory_zero(this); this->wav = wav_fromFile(wav_filename); this->is_paused = 1; this->currentSamplesPerSec = this->wav->nSamplesPerSec; WAVEFORMATEX wf; wf.wFormatTag = this->wav->wFormatTag; wf.nChannels = this->wav->nChannels; wf.nSamplesPerSec = this->wav->nSamplesPerSec; wf.nAvgBytesPerSec = this->wav->nAvgBytesPerSec; wf.nBlockAlign = this->wav->nBlockAlign; wf.wBitsPerSample = this->wav->wBitsPerSample; wf.cbSize = sizeof(wf); MMRESULT err = waveOutOpen(&this->wave_out, WAVE_MAPPER, &wf, (ULONG) audio_waveOutputCallback, (ULONG) this, CALLBACK_FUNCTION); if( err != MMSYSERR_NOERROR) error_internal("waveOutOpen() failed: %d", err); DWORD dwThreadId; this->event = CreateEvent(NULL, FALSE, FALSE, NULL); if( this->event == NULL ) error_internal("CreateEvent() failed: %d", GetLastError()); this->thread = CreateThread(NULL, 0, audio_feeder, this, 0, &dwThreadId); if( this->thread == NULL ) error_internal("CreateThread() failed: %d", GetLastError()) //waveOutPause(this->wave_out); return this; } void audio_play(audio_Type *this) { if( this->is_paused ){ this->is_paused = 0; //waveOutRestart(this->wave_out); } } void audio_pause(audio_Type *this) { if( ! this->is_paused ){ this->is_paused = 1; //waveOutPause(this->wave_out); } } int audio_isPaused(audio_Type *this) { return ! this->is_paused; } void audio_loop(audio_Type *this, int enable) { this->loop = enable; } int audio_isLooping(audio_Type *this) { return this->loop; } int audio_isPlaying(audio_Type *this) { return ! this->is_paused && this->cursor < this->wav->data_len; } int audio_getOriginalLengthMilliseconds(audio_Type *this) { return 1000 * this->wav->data_len / (this->wav->nSamplesPerSec * this->wav->nChannels * this->wav->nBlockAlign); } int audio_getCurrentLengthMilliseconds(audio_Type *this) { return 1000 * this->wav->data_len / (this->currentSamplesPerSec * this->wav->nChannels * this->wav->nBlockAlign); } int audio_getCurrentPositionMilliseconds(audio_Type *this) { return 1000 * this->cursor / (this->currentSamplesPerSec * this->wav->nChannels * this->wav->nBlockAlign); } void audio_setCurrentPositionMilliseconds(audio_Type *this, int position) { int index = position * this->currentSamplesPerSec * this->wav->nChannels * this->wav->nBlockAlign / 1000; if( index < 0 ) index = 0; else if( index > this->wav->data_len ) index = this->wav->data_len; this->position_request_at = index; this->position_request_pending = 1; } int audio_getOriginalSamplesPerSecond(audio_Type *this) { return this->wav->nSamplesPerSec; } int audio_getCurrentSamplesPerSecond(audio_Type *this) { return this->currentSamplesPerSec; } void audio_setCurrentSamplesPerSecond(audio_Type *this, int rate) { if( rate < 100 ) rate = 100; else if( rate > 15000 ) rate = 15000; if( pitchChangeSupportedByDevice ){ double pitchFactor = rate / this->wav->nSamplesPerSec; MMRESULT err = waveOutSetPitch(this->wave_out, pitchFactor * UINT32_MAX); if( err == MMSYSERR_NOTSUPPORTED ){ pitchChangeSupportedByDevice = 0; // enable sw emulation instead } else if( err != MMSYSERR_NOERROR ){ printf("waveOutSetPitch() unexpected exit code is %d\n", err); pitchChangeSupportedByDevice = 0; } } this->currentSamplesPerSec = rate; } #else /* * * Linux implementation with Alsa audio library. * */ #include #include #include #include #include #include "error.h" #include "memory.h" #include "wav.h" #define audio_IMPORT #include "audio.h" #define audio_ALSA_DEVICE "default" struct audio_Type { /** Audio device. */ snd_pcm_t *wave_out; /** Thread that feeds chunks to the driver. */ pthread_t thread; /** Pause flag. */ int is_paused; /** Destructor sets this to ask feeding thread to terminate. */ int thread_termination_request_pending; /** Loop execution flag. */ int loop; /** New cursor position requested flag; position_request_at is the value. */ int position_request_pending; /** Byte offset in the sample data where to set the cursor. */ int position_request_at; /** Current sampling rate requested by client. */ uint32_t currentSamplesPerSec; /** Client signals here to the feeder thread he changed the current samples rate. */ int samplesPerSecRequestPending; /** Index to the next byte of the sample data to play. */ int cursor; /** WAV file parameters. */ wav_Type *wav; }; static void audio_alsaSetParameters(audio_Type *this) { /* * Maps our WAV file parameters into an ALSA compliant format specifier. * FIXME: check WAV to ALSA format mapping; this is only by trial and error! */ snd_pcm_format_t format; switch (this->wav->wBitsPerSample) { case 8: format = SND_PCM_FORMAT_U8; break; case 16: format = SND_PCM_FORMAT_S16_LE; break; case 24: format = SND_PCM_FORMAT_S24_LE; break; case 32: format = SND_PCM_FORMAT_S32_LE; break; default: error_internal("%s: unsupported number of bits per sample: %d", this->wav->filename, this->wav->wBitsPerSample); } int err = snd_pcm_set_params(this->wave_out, format, SND_PCM_ACCESS_RW_INTERLEAVED, this->wav->nChannels, this->currentSamplesPerSec, 1, // allows alsa-lib resampling // FIXME: ??????? 100000 // required overall latency in us // FIXME: ???????? ); if( err != 0 ) error_internal("%s: setting parameters for audio device '%s': %s", this->wav->filename, audio_ALSA_DEVICE, snd_strerror(err)); /* err = snd_pcm_prepare(this->wave_out); if( err != 0 ) error_internal("%s: preparing audio device '%s': %s", this->wav->filename, audio_ALSA_DEVICE, snd_strerror(err)); */ } /** * Software emulation of the pitch changer. * Increments this->cursor by the number of bytes copied or skipped from the * source (depending on the pitch skew rate) and returns the number of bytes * copied in the destination. It always consumes at least one frame of the * source and always copies at least one frame into the destination to prevent * locks in the caller. * @param this * @param src Source buffer of the original audio frames. * @param src_len Length in bytes of the source buffer of frames. Must contain * at least one frame or a fatal error occurs. * @param dst Destination buffer of the re-sampled audio. * @param dst_len Length in bytes of the destination buffer. Must contain at * least one frame or a fatal error occurs. * @return Number of bytes actually copied in the destination. It is always * positive. */ static int audio_resample(audio_Type *this, char *src, int src_len, char *dst, int dst_len) { int frame_len = this->wav->frameLength; // Destination must contain an integral number of frames for faster // end detection: dst_len -= dst_len % frame_len; assert(src_len >= frame_len); assert(dst_len >= frame_len); // Pitch factor maps frame offset of the src into dst: double k = (double) this->currentSamplesPerSec / this->wav->nSamplesPerSec; // For each dst sample, calculate the src frame and copy. int src_byte_index = 0; int dst_byte_index = 0; int dst_frame_index = 0; do { src_byte_index = frame_len * (int) (dst_frame_index * k + 0.5); if( src_byte_index >= src_len ) break; memcpy(dst + dst_byte_index, src + src_byte_index, frame_len); dst_byte_index += frame_len; dst_frame_index++; } while( dst_byte_index < dst_len ); if( src_byte_index < frame_len ) src_byte_index = frame_len; else if( src_byte_index > src_len ) src_byte_index = src_len; this->cursor += src_byte_index; return dst_byte_index; } static int32_t audio_write(audio_Type *this, void *frames, int number_of_frames) { int32_t wrote_frames = snd_pcm_writei(this->wave_out, frames, number_of_frames); // If an error, try to recover from it if (wrote_frames < 0) { int err = snd_pcm_recover(this->wave_out, wrote_frames, 1); if (err < 0){ error_internal( "ALSA library while playing %s:\n" " snd_pcm_writei() failed: %s\n" " snd_pcm_recover() failed: %s", this->wav->filename, snd_strerror(wrote_frames), snd_strerror(err)); } wrote_frames = 0; } return wrote_frames; } /** * Feeder thread. Continously submits sound frames to the audio driver, * checking for clients request changes (loop or one-shot mode, rewind and * positioning, thread termination request). * @param p Pointer to audio_Type. * @return Always returns NULL. */ static void * audio_feeder(void *p) { audio_Type *this = p; int paused = 0; // paused int draining = 0; // paused after one-shot play finished char *resample_buffer = NULL; int resample_buffer_capacity; int resample_length; int resample_cursor; while( ! this->thread_termination_request_pending ) { int do_sleep = 1; if( this->position_request_pending ){ this->cursor = this->position_request_at; if( this->cursor < 0 ) this->cursor = 0; else if( this->cursor > this->wav->data_len ) this->cursor = this->wav->data_len; this->cursor -= this->cursor % this->wav->frameLength; this->position_request_pending = 0; } assert(0 <= this->cursor && this->cursor <= this->wav->data_len); // Check pause request. if( this->is_paused ){ if( paused ){ // ok } else { snd_pcm_pause(this->wave_out, 1); paused = 1; } } else { if( paused ){ snd_pcm_pause(this->wave_out, 0); paused = 0; } else { // ok } } if( ! paused ){ if( this->cursor >= this->wav->data_len && this->loop ){ this->cursor = 0; } if( this->cursor < this->wav->data_len ){ if( this->samplesPerSecRequestPending ){ this->samplesPerSecRequestPending = 0; draining = 0; if( resample_buffer == NULL ){ // Create a resample buffer that may contain a quite short sample // so to react faster to commanded frequencies changes. // 1/8 s seems good. resample_buffer_capacity = (this->wav->frameLength * this->wav->nSamplesPerSec) >> 3; resample_buffer_capacity -= resample_buffer_capacity % this->wav->frameLength; resample_buffer = memory_allocate(resample_buffer_capacity, NULL); resample_cursor = 0; resample_length = 0; } } else if( draining ){ draining = 0; int err = snd_pcm_prepare(this->wave_out); if( err != 0 ) error_internal("preparing audio device '%s': %s", audio_ALSA_DEVICE, snd_strerror(err)); } if( resample_buffer == NULL ){ uint32_t avail_frames = (this->wav->data_len - this->cursor) / this->wav->frameLength; // Send max 1/4 s of audio per turn. if( avail_frames > (this->currentSamplesPerSec >> 2) ) avail_frames = (this->currentSamplesPerSec >> 2); int32_t wrote_frames = audio_write(this, this->wav->data + this->cursor, avail_frames); if( wrote_frames > 0 ){ this->cursor += wrote_frames * this->wav->frameLength; do_sleep = 0; } } else { // Fill resample buffer with frames from WAV: if( resample_length < resample_buffer_capacity ){ resample_length += audio_resample(this, this->wav->data + this->cursor, this->wav->data_len - this->cursor, resample_buffer + resample_length, resample_buffer_capacity - resample_length); } // Send resampled frames to the driver: uint32_t avail_frames = (resample_length - resample_cursor) / this->wav->frameLength; if( avail_frames > 0 ){ int32_t wrote_frames = audio_write(this, resample_buffer + resample_cursor, avail_frames); if( wrote_frames > 0 ){ resample_cursor += wrote_frames * this->wav->frameLength; if( resample_cursor >= resample_length ){ resample_cursor = 0; resample_length = 0; } do_sleep = 0; } } } } else if( this->cursor >= this->wav->data_len ){ // Single shot mode, end of the sample, . // Wait for playback to completely finish and release the // driver's playing pipeline, otherwise ALSA would send to // stderr the boring "ALSA lib pcm.c:7963:(snd_pcm_recover) // underrun occurred" message! snd_pcm_drain(this->wave_out); draining = 1; } } if( do_sleep ) usleep(100000); } memory_dispose(resample_buffer); return NULL; } static void audio_destruct(void *p) { audio_Type *this = (audio_Type *) p; this->thread_termination_request_pending = 1; pthread_join(this->thread, NULL); snd_pcm_close(this->wave_out); memory_dispose(this->wav); } audio_Type * audio_new(char * wav_filename) { audio_Type *this = memory_allocate(sizeof(audio_Type), audio_destruct); memory_zero(this); this->wav = wav_fromFile(wav_filename); if( this->wav->wFormatTag != 1 ) error_internal("%s: sorry, only WAV format tag 1 (PCM) supported, found: %d", wav_filename, this->wav->wFormatTag); int err = snd_pcm_open(&this->wave_out, audio_ALSA_DEVICE, SND_PCM_STREAM_PLAYBACK, 0); if( err != 0 ) error_internal("opening audio device '%s': %s", audio_ALSA_DEVICE, snd_strerror(err)); this->is_paused = 1; this->currentSamplesPerSec = this->wav->nSamplesPerSec; audio_alsaSetParameters(this); err = pthread_create(&this->thread, NULL, audio_feeder, this); if( err != 0 ) error_external("pthread_create() return code %d: cannot create audio feeder thread to play %s", err, wav_filename); return this; } void audio_play(audio_Type *this) { if( this->is_paused ){ this->is_paused = 0; } } int audio_isPlaying(audio_Type *this) { return ! this->is_paused && this->cursor < this->wav->data_len; } void audio_pause(audio_Type *this) { if( ! this->is_paused ){ this->is_paused = 1; } } int audio_isPaused(audio_Type *this) { return ! this->is_paused; } void audio_loop(audio_Type *this, int enable) { this->loop = enable; } int audio_isLooping(audio_Type *this) { return this->loop; } int audio_getOriginalLengthMilliseconds(audio_Type *this) { return 1000 * this->wav->data_len / (this->wav->nSamplesPerSec * this->wav->nChannels * this->wav->nBlockAlign); } int audio_getCurrentLengthMilliseconds(audio_Type *this) { return 1000 * this->wav->data_len / (this->currentSamplesPerSec * this->wav->nChannels * this->wav->nBlockAlign); } int audio_getCurrentPositionMilliseconds(audio_Type *this) { return 1000 * this->cursor / (this->currentSamplesPerSec * this->wav->nChannels * this->wav->nBlockAlign); } void audio_setCurrentPositionMilliseconds(audio_Type *this, int position) { int index = position * this->currentSamplesPerSec * this->wav->nChannels * this->wav->nBlockAlign / 1000; if( index < 0 ) index = 0; else if( index > this->wav->data_len ) index = this->wav->data_len; this->position_request_at = index; this->position_request_pending = 1; } int audio_getOriginalSamplesPerSecond(audio_Type *this) { return this->wav->nSamplesPerSec; } int audio_getCurrentSamplesPerSecond(audio_Type *this) { return this->currentSamplesPerSec; } void audio_setCurrentSamplesPerSecond(audio_Type *this, int rate) { if( rate < 100 ) rate = 100; else if( rate > 15000 ) rate = 15000; if( rate == this->currentSamplesPerSec ) return; this->currentSamplesPerSec = rate; this->samplesPerSecRequestPending = 1; } #endif acm-6.0_20200416/src/util/units.h0000644000000000000000000000372313066076331014664 0ustar rootroot/** * Physical constants, measurement units and conversions. * * @file */ #ifndef units_H #define units_H #include #ifdef units_IMPORT #define EXTERN #else #define EXTERN extern #endif #define units_DEGtoRAD(x) ((x) * M_PI / 180.0) #define units_RADtoDEG(x) ((x) * 180.0 / M_PI) #define units_earth_g 32.17 /* acceleration due to gravity (ft/s^2) */ #define units_NmToFeetFactor 6076.115 /* ft/NM */ #define units_NmToMeterFactor 1853.18 #define units_FootToMeterFactor 0.30480060960 #define units_LbToKgFactor 0.45359237 //#define units_LbfToNFactor (earth_g * units_LbToKgFactor / FtToMeterFactor) #define units_FPStoKT(v) ((v) / units_NmToFeetFactor * 3600.0) #define units_KTtoFPS(v) ((v) * units_NmToFeetFactor / 3600.0) #define units_FEETtoMETERS(v) ((v) * units_FootToMeterFactor) #define units_METERStoFEET(v) ((v) / units_FootToMeterFactor) #define units_METERStoNM(x) ((x) / units_NmToMeterFactor) //#define units_NMtoFEET(x) ((x) * units_NmToFeetFactor) #define units_NMtoMETERS(x) ((x) * units_NmToMeterFactor) /* * All constants referring to the standard atmosphere conditions * T = 15 C, P = 101325 Pa at sea level. */ #define units_GM 1.4 /* ratio of specific heats for air */ #define units_P0 2116.22 /* sea-level pressure [lbf/ft^2] */ #define units_TA 459.67 /* Conversion temperature from F to R (Rankine, or abs. F temp.) */ #define units_T0 (units_TA + 59.0) /* sea-level temperature [R] */ #define units_RU (1545.31 * units_earth_g) /* universal gas constant */ #define units_MA 28.9644 /* molecular weight for air [lbm/lbm-mole] */ #define units_RA (units_RU / units_MA) /* gas constant for air [ft^2/sec^2/R] */ #define units_RHO_0 2.3769e-3 /* air density at sea level, std. atm. [slug/ft^3] */ #define units_FarenheitToCelsius(f) (((f) - 32.0)*5/9) #define units_RankineToCelsius(r) units_FarenheitToCelsius(r - units_TA) #define units_SlugToKg(s) (14.59 * (s)) #undef EXTERN #endifacm-6.0_20200416/src/util/wav.c0000644000000000000000000001543613154074013014307 0ustar rootroot/* * IMPLEMENTATION NOTES. * * WAV files use the RIFF format. * * A RIFF formatted file contains one or more chunks. * * A chunk contains an header with type and size, and a body: * * - The chunk type as a readable ASCII string (4 bytes). * - The length of the following body section (unsigned 4 bytes, little-endian). * - The body section. * * A WAV file contains a single chunk of type "RIFF"; its body section contains * the string "WAVE" and the inner chunks up to the end of the file. * There are several types of chunks, but those we support here are only the * "fmt " chunk containing the sampling parameters, and the "data" chunks * containing the actual sampled data. All numbers are assumed in little-endian * ordering, including the sampled audio data. * * This implementation requires exactly one "fmt " chunk be present. * This implementation allows zero or more "data" chunks. * This implementation ignores and skips any other type of chunk. * * For more details about the internal structure of each chunk type, see the * code below. */ #include #include #include #include #include "memory.h" #include "error.h" #define wav_IMPORT #include "wav.h" #ifdef WINNT /** Converts x from LE byte ordering to host byte ordering. */ static uint16_t le16toh(uint16_t x) { if( *(uint16_t *) "AB" == 0x4241 ){ return x; } else { char s[2]; s[0] = x & 255; s[1] = (x >> 8) & 255; return *(uint16_t *) s; } } /** Converts x from LE byte ordering to host byte ordering. */ static uint32_t le32toh(uint32_t x) { if( *(uint32_t *) "ABCD" == 0x44434241 ){ return x; } else { char s[4]; s[0] = x & 255; s[1] = (x >> 8) & 255; s[2] = (x >> 16) & 255; s[3] = (x >> 24) & 255; return *(uint32_t *) s; } } #else #include #endif typedef struct { /** Zero-terminated RIFF chunk type. */ char id[5]; /** Length of the following data section (header bytes NOT included). */ uint32_t length; } wav_chunkHdr; static void wav_skipBytes(char *fn, FILE *f, int no_bytes) { if( fseek(f, no_bytes, SEEK_CUR) != 0 ) error_system("failed skipping %d bytes on file %s", no_bytes, fn); } static void wav_readBytes(char *fn, FILE *f, int no_bytes, void *bytes) { if( no_bytes < 0 ) error_internal("trying to read %d bytes: undefined", no_bytes); if( no_bytes == 0 ) return; int n = fread(bytes, no_bytes, 1, f); if( n == 1 ) return; if( feof(f) ) error_external("premature end of the file reading %s", fn); else error_external("unexpected error reading %s", fn); } static uint16_t wav_readUInt16LE(char *fn, FILE *f) { uint16_t x; wav_readBytes(fn, f, 2, &x); return le16toh(x); } static uint32_t wav_readUInt32LE(char *fn, FILE *f) { uint32_t x; wav_readBytes(fn, f, 4, &x); return le32toh(x); } static int wav_readChunkHdr(char *fn, FILE *f, wav_chunkHdr *hdr) { int n = fread(&hdr->id, 1, 4, f); if( n < 4 ){ if( feof(f) ){ if( n == 0 ) return 0; else error_external("unexpected end of the file reading %s", fn); } else { error_external("unexpected error reading %s", fn); } } hdr->id[4] = 0; hdr->length = wav_readUInt32LE(fn, f); return 1; } static void wav_destruct(void *p) { wav_Type *this = p; memory_dispose(this->filename); memory_dispose(this->data); } wav_Type * wav_fromFile(char *filename) { wav_Type *this = memory_allocate(sizeof(wav_Type), wav_destruct); this->filename = memory_strdup(filename); FILE *f = fopen(filename, "rb"); if( f == NULL ) error_system("failed opening file %s", filename); // Read 'RIFF' chunk. wav_chunkHdr hdr; if( ! wav_readChunkHdr(filename, f, &hdr) ) error_external("%s: not a WAV file, too short", filename); if( strcmp(hdr.id, "RIFF") != 0 ) error_external("%s: not a WAV file, missing 'RIFF' chunk", filename); if( hdr.length == 0 ) error_external("%s: WAV file is empty, no audio samples at all", filename); char WAVE[5]; wav_readBytes(filename, f, 4, WAVE); WAVE[4] = 0; if( strcmp(WAVE, "WAVE") != 0 ) error_external("%s: not a WAV file, missing 'WAVE'", filename); // Allocate audio data buffer estimating a length of file size - 8 bytes. uint32_t capacity = hdr.length; this->data = memory_allocate(capacity, NULL); this->data_len = 0; // Scan all chunks, parsing format and data only: int fmtChunkFound = 0; while( wav_readChunkHdr(filename, f, &hdr) ){ //printf("WAV %s: found '%s' chunk, %d bytes\n", fn, hdr.id, hdr.length); if( strcmp(hdr.id, "fmt ") == 0 ){ if( fmtChunkFound ) error_external("%s: bad WAV format, multiple 'fmt ' chunks", filename); fmtChunkFound = 1; if( hdr.length != 16 ) error_external("%s: bad WAV format, invalid length of the 'fmt ' chunk: %d", filename, hdr.length); this->wFormatTag = wav_readUInt16LE(filename, f); this->nChannels = wav_readUInt16LE(filename, f); this->nSamplesPerSec = wav_readUInt32LE(filename, f); this->nAvgBytesPerSec = wav_readUInt32LE(filename, f); this->nBlockAlign = wav_readUInt16LE(filename, f); this->wBitsPerSample = wav_readUInt16LE(filename, f); } else if( strcmp(hdr.id, "data") == 0 ){ if( hdr.length > capacity - this->data_len ) error_external("%s: bad WAV format: file contains more data than stated in the header", filename); wav_readBytes(filename, f, hdr.length, this->data + this->data_len); this->data_len += hdr.length; } else { // Unknown or unsupported RIFF chunk. Skip. wav_skipBytes(filename, f, hdr.length); } } fclose(f); if( ! fmtChunkFound ) error_external("%s: bad WAV format, missing 'fmt ' chunk", filename); if( this->wFormatTag != 1 ) error_external("%s: unknown or unsupported format tag in WAV file (possibly compressed?): %d", filename, this->wFormatTag); this->frameLength = this->nChannels * this->nBlockAlign; if( this->nChannels == 0 ) error_external("%s: bad format, zero channels", filename); if( this->nSamplesPerSec == 0 ) error_external("%s: bad format, zero samples per seconds!", filename); if( this->nBlockAlign == 0 ) error_external("%s: bad format, zero bytes of block alignment!", filename); if( this->wBitsPerSample == 0 ) error_external("%s: bad format, zero bits per sample!", filename); if( 8 * this->nBlockAlign < this->wBitsPerSample ) error_external("%s: bad format, blocks alignment too small for samples length", filename); // Data must contain an integral number of frames, each frame being a sample // for all the channels. If not, silently trim the odd trailing bytes. uint32_t odd_trail_length = this->data_len % this->frameLength; if( odd_trail_length > 0 ) this->data_len -= odd_trail_length; // Note that checks above prevent division by zero below. if( this->data_len % this->nBlockAlign != 0 ) error_external("%s: bad WAV format, odd sample block alignment", filename); return this; } acm-6.0_20200416/src/util/timer.h0000644000000000000000000000352313145716317014643 0ustar rootroot/** * Timer that measures real elapsed time, that is "wall clock time". * A timer can be started, stopped, restarted and reset. * There is no guarantee this timer may return accurate results on any system, * but a granularity better than 1 ms should be expected. * * @file * @author Umberto Salsi * @version $Date: 2017/08/19 02:05:03 $ */ #ifndef TIMER_H #define TIMER_H #include #ifdef timer_IMPORT #define EXTERN #else #define EXTERN extern #endif typedef struct timer_Type timer_Type; /** * Allocates a new stopped timer. * @return New stopped timer. Must be released with memory_dispose(). */ EXTERN timer_Type * timer_new(void); /** * Starts or restarts the timer, continuing accounting elapsed time. * Does nothing if the timer is already running. * @param t */ EXTERN void timer_start(timer_Type *t); /** * Stops the timer. Does nothing if already stopped. * @param t */ EXTERN void timer_stop(timer_Type *t); /** * Returns the current timer reading as nanoseconds. * @param t * @return Current timer reading as nanoseconds (1e-9 s). */ EXTERN int64_t timer_getElapsedNanoseconds(timer_Type *t); /** * Returns the current timer reading as microseconds. * @param t * @return Current timer reading as microseconds (1e-6 s). */ EXTERN int64_t timer_getElapsedMicroseconds(timer_Type *t); /** * Returns the current timer reading as milliseconds. * @param t * @return Current timer reading as milliseconds (1e-3 s), possibly INT_MAX if * more than 24 days elapsed. */ EXTERN int timer_getElapsedMilliseconds(timer_Type *t); /** * Resets the timer. * @param t */ EXTERN void timer_reset(timer_Type *t); /** * Stops for the given real, wall clock time. * @param ms Time to sleep (ms). Does nothing if zero or negative. */ EXTERN void timer_sleepMilliseconds(int ms); #undef EXTERN #endif acm-6.0_20200416/src/util/gui.h0000644000000000000000000001754713155062041014307 0ustar rootroot/** * Generic window, keyboard and mouse management. * * This modules provides very basic support for GUI management tailored for the * needs of the ACM program, and it is not intended for general use in other * applications. Implementation for both Microsoft Windows and X-Window (Unix, * Linux, Cygwin) is provided. * * Geometric units are in pixels, with [0,0] being the coordinates of the * top-left corner and [W-1,H-1] being the coordinates of the bottom-right corner * of a window content area W pixels wide and H pixels tall. * * A fixed color's look-up table (CLUT) is created and specific routines are * provided to map RGB values into the indeces of this CLUT that best match the * requested color. * * For basic usage, first invoke gui_new() to create a new window. * Events are returned by gui_getEvent(). * The only supported drawing routine is gui_drawLine() that draws a colored * segment. * The window and all the associated data structures can be released with * memory_dispose(). * * @file * @author Umberto Salsi * @version $Date: 2017/09/09 21:58:57 $ */ #ifndef GUI_H #define GUI_H #ifdef gui_IMPORT #define EXTERN #else #define EXTERN extern #endif #define gui_KEY_INS (-1) #define gui_KEY_HOME (-2) #define gui_KEY_END (-3) #define gui_KEY_PGUP (-4) #define gui_KEY_PGDW (-5) #define gui_KEY_DEL (-7) #define gui_KEY_UP (-8) #define gui_KEY_DOWN (-9) #define gui_KEY_LEFT (-10) #define gui_KEY_RIGHT (-11) #define gui_KEY_PAD_PLUS (-12) #define gui_KEY_PAD_MINUS (-13) #define gui_KEY_PAD_TIMES (-14) #define gui_KEY_PAD_DIVIDE (-15) #define gui_KEY_PAD_0 (-16) #define gui_KEY_PAD_1 (-17) #define gui_KEY_PAD_2 (-18) #define gui_KEY_PAD_3 (-19) #define gui_KEY_PAD_4 (-20) #define gui_KEY_PAD_5 (-21) #define gui_KEY_PAD_6 (-22) #define gui_KEY_PAD_7 (-23) #define gui_KEY_PAD_8 (-24) #define gui_KEY_PAD_9 (-24) #define gui_KEY_F(N) (-24 - (N)) /** * Single allocated window. */ typedef struct gui_Type gui_Type; /** * Estimated dimensions of the "main" or "desktop" display are * returned in this data structure as pixels and millimiters. */ typedef struct { int heightPixels, heightMillimiters, widthPixels, widthMillimiters; } gui_DisplayDimensions; /** * Event codes that may be returned. */ typedef enum { // Left, Middle and Right mouse button down and up. gui_EVENT_LBUTTONDOWN, gui_EVENT_MBUTTONDOWN, gui_EVENT_RBUTTONDOWN, gui_EVENT_LBUTTONUP, gui_EVENT_MBUTTONUP, gui_EVENT_RBUTTONUP, /** Keyboard key pressed. */ gui_EVENT_KEYDOWN, // Windows focus in and out. Brand new windows have no focus, then the // focus in event is one of the early events generated. gui_EVENT_WINDOW_FOCUS_IN, gui_EVENT_WINDOW_FOCUS_OUT, /** Part of the content area need to be redrawn. */ gui_EVENT_WINDOW_EXPOSE, /** Window size changed. */ gui_EVENT_WINDOW_SIZE_CHANGE, /** Windows close request. */ gui_EVENT_WINDOW_CLOSE } gui_EventCode; /** * Event. */ typedef struct { /** Code of the event. */ gui_EventCode code; /** * For mouse button down/up events, these are the pointer's coordinates. * For window size changes, these are the new width and height. */ int x, y; /** * For key down event, this is the key code. ASCII codes are returned as * usual values; for function keys, see the gui_KEY_F(N) macro. Other * locale key codes might be returned, but these are not used by ACM and * should be ignored. */ int key; } gui_Event; /** * Creates a window. * @param title Title for the title bar. * @param width Width of the content area (pixels). * @param height Height of the content area (pixels). * @return New window. Must be released with memory_dispose(). */ EXTERN gui_Type * gui_new(char *title, int width, int height); /** * Retrieves the dimensions of the current "main" or "desktop" display. On some * systems and some configurations the result might be completely wrong or * simply cannot be determined and a default is returned instead. * @param this Involved window. * @param d Here returns the dimensions. */ EXTERN void gui_getDisplayDimensions(gui_Type *this, gui_DisplayDimensions *d); /** * Returns the next event. This function is not blocking, and returns false if * no meaningful event is available. * @param this Involved window. * @param e Here set the event. * @return True if a meaningful event has been set. */ EXTERN int gui_getEvent(gui_Type *this, gui_Event *e); /** * Get the latest know position of the mouse pointer in the content area of the * window. * @param this Involved window. * @param x * @param y */ EXTERN void gui_getPointerPosition(gui_Type *this, int *x, int *y); /** * Returns window width. * @param this Involved window. * @return Window width (pixels). */ EXTERN int gui_getWidth(gui_Type *this); /** * Returns window height. * @param this Involved window. * @return Window height (pixels). */ EXTERN int gui_getHeight(gui_Type *this); /** * Returns true if the window currently has input focus. When the focus is lost, * the client should ignore any user's input, either from the mouse or the * keyboard. * @param this Involved window. * @return True if the window currently has input focus. */ EXTERN int gui_hasFocus(gui_Type *this); /** * Returns true if the content area of the window is (at least partially) visible * and then it worths to update its content. Returns false if the content area is * not visible, for example because the window has been minimized or iconified * (whatever these terms means for the specific underlying windowing system) so * the client can save time avoiding to update the content area. * @param this Involved window. * @return True if the content area of the window is (at least partially) visible. */ EXTERN int gui_isVisible(gui_Type *this); /** * Returns the index to the CLUT that better matches the specified RGB. * @param this Involved window. * @param red Red value in [0,255]. * @param green Green value in [0,255]. * @param blue Blue value in [0,255]. * @return Index into the table of the allocated colors for this window. */ EXTERN int gui_getColorIndex(gui_Type *this, int red, int green, int blue); /** * Returns the index to the CLUT that better matches the specified * descriptive color string. * @param this Involved window. * @param s Descriptive string of the color name (example: "red") or hexadecimal * RGB value (examples: "#f00", "#ff0000"). * @return Index into the table of the allocated colors for this window. */ EXTERN int gui_getColorIndexString(gui_Type *this, char *s); /** * Parses the descriptive color string and returns the corresponding RGB value. * @param s Descriptive string of the color name (example: "red") or hexadecimal * RGB value (examples: "#f00", "#ff0000"). * @param red Here returns the red value in [0,255]. * @param green Here returns the green value in [0,255]. * @param blue Here returns the blue value in [0,255]. * @return True if the descriptive color string has been successfully parsed. */ EXTERN int gui_parseColorString(char *s, int *red, int *green, int *blue); /** * Draws a segment of line on the window. The segment is 1 pixel wide. * Ending points can be specified in any order, resulting in the same exact * result being drawn. For example, the segment (1,1)-(2,1) causes two pixels * being drawn. Note that actually ACM only needs to draw horizontal segments, * so this function is just a bit more general than required. * * Under X-Window a great performance improvement can be achieved by grouping * lines having the same color, as this reduces the need to change the graphic * context. This grouping is exactly what the Alib module of ACM does right now. * * @param this Involved window. * @param x1 * @param y1 * @param x2 * @param y2 * @param color Color index as returned by gui_getColorIndex(). */ EXTERN void gui_drawLine(gui_Type *this, int x1, int y1, int x2, int y2, int color); #undef EXTERN #endif acm-6.0_20200416/src/util/varray.c0000644000000000000000000002303013175227156015016 0ustar rootroot#include #include #include #include "memory.h" #include "error.h" #define varray_IMPORT #include "varray.h" /* * Mask for the index part of the handle, that is the maximum index value. * For 32-bits int this expression generates 0x0000ffff, allowing a maximum of * 2^16 entries in the array. */ #define INDEX_MASK (~(-1 << (4*sizeof(int)))) /* * Mask for the version part of the handle. * For 32-bits int this expression generates 0xffff0000. */ #define VERSION_MASK (~INDEX_MASK) /* * Initial value and increment after each release for the version of each entry. * For 32-bits int this expression generates 0x00010000. * The zero value is discarded, so that the resulting handles are never zero. * Then the version start at 0x0001000, is incremented up to 0xffff0000 and * then returns to 0x0001000 again, so that up to (2^16-1) different handles can * be generated for the same recycled entry of the array: the probability that * a stale handle passes validation undetected is then only 1 / (2^16-1). */ #define VERSION_INCREMENT (INDEX_MASK + 1) /** * An entry can be 'used' (client added the value), 'detached' (client detached * the entry previously added), and 'spare' (entry allocated but never used by * client. */ typedef struct varray_Entry { /** Index of this entry in the array. */ int index; /** If client is currently using this entry. */ int isOccupied; /** Version counter incremented at each detach; it is never zero. */ int version; /** * For occupied entries, double linked list of entries. For detached * entries, only the 'next' field used to keep a list. * -1 = no entry. */ int prev, next; /** Value set by client. */ void *value; } varray_Entry; /** * Dynamic array of entries. * There are allocated_no entries allocated, the first used_no being actually * used, the remaining are spare. * Among the used entries, occupied_no are marked "occupied" and are returned * in sequential scanning; the remaining detached_no entries are marked as not * occupied and are not returned in sequential scanning. Obviously, * occupied_no + detached_no = used_no. * Occupied entries are kept in a doubly linked list for fast sequential access * and fast removal of detached entries. New entries are always appended to the * end, so preserving the order of insertion (just in case it may be useful). * Detached entries are kept in a single linked list. */ struct varray_Type { /** * No. of entries allocated. The first * used_no = occupied_no + detached_no entries * are currently used by client; the remaining entries are preallocated * spare entries. */ int allocated_no; /** * No. of entries currently used by client that are returned on sequential * scanning. */ int occupied_no; /** No. of entries detached by client; not returned on scanning. */ int detached_no; /** No. of entries used, both occupied and detached: */ int used_no; /** Index next entry for sequential scanning; -1 = no next entry. */ int next; /** Index first occupied entry for sequential scanning; -1 = empty. */ int firstOccupied; /** Index last occupied entry for tail adding; -1 = empty. */ int lastOccupied; /** Index first detached entry for recycled recovering; -1 = empty. */ int firstDetached; /** Index last detached entry for recycled adding; -1 = empty. */ int lastDetached; varray_Entry *entries; int iteratorLock; }; static void varray_check(varray_Type *this) { assert(this->occupied_no >= 0); assert(this->detached_no >= 0); assert(this->used_no <= this->allocated_no); assert(this->occupied_no + this->detached_no == this->used_no); assert(this->firstOccupied < 0 || this->entries[this->firstOccupied].isOccupied); assert(this->lastOccupied < 0 || this->entries[this->lastOccupied].isOccupied); assert(this->firstDetached < 0 || !this->entries[this->firstDetached].isOccupied); assert(this->lastDetached < 0 || !this->entries[this->lastDetached].isOccupied); } static void varray_destruct(void *p) { varray_Type *this = p; if( this == NULL ) return; varray_check(this); memory_dispose(this->entries); } varray_Type * varray_new() { varray_Type *this = memory_allocate(sizeof(varray_Type), varray_destruct); this->allocated_no = 0; this->occupied_no = 0; this->detached_no = 0; this->used_no = 0; this->next = -1; this->firstDetached = -1; this->lastDetached = -1; this->firstOccupied = -1; this->lastOccupied = -1; this->entries = NULL; this->iteratorLock = 0; return this; } static int varray_entryToHandle(varray_Entry *e) { return e->version + e->index; } int varray_length(varray_Type *this) { return this->occupied_no; } int varray_isValidHandle(varray_Type *this, int handle) { varray_Entry *e; int version = handle & ~INDEX_MASK; int index = handle & INDEX_MASK; if( !(0 <= index && index < this->used_no) ) return 0; e = &this->entries[index]; if( e->version != version ) return 0; if( ! e->isOccupied ) return 0; return 1; } static varray_Entry *varray_getEntry(varray_Type *this, int handle) { varray_Entry *e; if( handle == 0 ) error_internal("zero handle, not an allocated entry", 0); int version = handle & ~INDEX_MASK; int index = handle & INDEX_MASK; if( !(0 <= index && index < this->used_no) ) error_internal("invalid handle: index part out of the range)", 0); e = &this->entries[index]; if( ! e->isOccupied ) error_internal("accessing detached entry", 0); if( e->version != version ) error_internal("handle refers a stale entry that was detached, now recycled with possibly different meaning", 0); return e; } void * varray_getValue(varray_Type *this, int handle) { return varray_getEntry(this, handle)->value; } int varray_getDetachedHandle(varray_Type *this) { varray_Entry *e; if( this->firstDetached < 0 ) return 0; e = &this->entries[this->firstDetached]; /* Detach element from the beginning of the list of detached elements: */ this->firstDetached = e->next; if( e->next < 0 ) this->lastDetached = -1; /* Join element to the end of the list of occupied elements: */ if( this->lastOccupied < 0 ){ this->firstOccupied = this->lastOccupied = e->index; e->prev = e->next = -1; } else { e->prev = this->lastOccupied; e->next = -1; this->entries[e->prev].next = e->index; this->lastOccupied = e->index; } e->isOccupied = 1; this->occupied_no++; this->detached_no--; varray_check(this); return varray_entryToHandle(e); } int varray_addValue(varray_Type *this, void *value) { int size; varray_Entry *e; if( this->firstDetached >= 0 ) error_internal("there are detached entries available," " you must use varray_getDetachedHandle() first", 0); if( this->used_no >= this->allocated_no ){ if( this->allocated_no >= INDEX_MASK + 1 ) error_internal("varray full: %d", INDEX_MASK + 1); size = this->allocated_no + this->allocated_no / 2 + 1000; if( size > INDEX_MASK + 1 ) size = INDEX_MASK + 1; this->entries = memory_realloc(this->entries, size * sizeof(varray_Entry)); this->allocated_no = size; } e = &this->entries[this->used_no]; e->index = this->used_no; e->isOccupied = 1; e->version = VERSION_INCREMENT; e->value = value; /* Add new element to the end of the list of occupied entries: */ if( this->lastOccupied < 0 ){ this->lastOccupied = this->firstOccupied = e->index; e->next = e->prev = -1; } else { e->prev = this->lastOccupied; this->entries[e->prev].next = e->index; e->next = -1; this->lastOccupied = e->index; } this->occupied_no++; this->used_no++; varray_check(this); return varray_entryToHandle(e); } void varray_setValue(varray_Type *this, int handle, void *value) { varray_Entry *e = varray_getEntry(this, handle); e->value = value; } void varray_detach(varray_Type *thie, int handle) { varray_Entry *e = varray_getEntry(thie, handle); if( e->index == thie->next ) thie->next = e->next; e->isOccupied = 0; e->version += VERSION_INCREMENT; if( e->version == 0 ) e->version = VERSION_INCREMENT; /* Detach from list of occupied entries: */ if( e->next < 0 ){ if( e->prev < 0 ){ /* Only entry. */ thie->firstOccupied = thie->lastOccupied = -1; } else { /* Last entry of 2+. */ thie->entries[e->prev].next = -1; thie->lastOccupied = e->prev; } } else { if( e->prev < 0 ){ /* First entry of 2+. */ thie->firstOccupied = e->next; thie->entries[e->next].prev = -1; } else { /* Middle entry. */ thie->entries[e->prev].next = e->next; thie->entries[e->next].prev = e->prev; } } /* Attach to the end of the list of the detached entries: */ if( thie->lastDetached < 0 ){ thie->firstDetached = thie->lastDetached = e->index; } else { thie->entries[thie->lastDetached].next = e->index; thie->lastDetached = e->index; } e->next = -1; thie->occupied_no--; thie->detached_no++; varray_check(thie); } int varray_firstHandle(varray_Type *this) { if( this->iteratorLock ) error_internal("iterator still locked: check for nested iterations or missing call to varray_releaseIterator()", 0); this->iteratorLock = 1; varray_Entry *e; if( this->firstOccupied < 0 ){ this->next = -1; return 0; } else { e = &this->entries[this->firstOccupied]; this->next = e->next; return varray_entryToHandle(e); } } int varray_nextHandle(varray_Type *this) { if( ! this->iteratorLock ) error_internal("iterator not initialized by varray_firstHandle()", 0); if( this->next < 0 ){ return 0; } else { varray_Entry *e = &this->entries[this->next]; this->next = e->next; return varray_entryToHandle(e); } } void varray_releaseIterator(varray_Type *this) { if( ! this->iteratorLock ) error_internal("iterator is not set", 0); this->iteratorLock = 0; }acm-6.0_20200416/src/util/error.h0000644000000000000000000000714013155077471014655 0ustar rootroot/** * Error reporting utilities. Under Windows applications compiled in "window" * mode (not in "console") it is recommended to always initialize this module * by calling the error_init() function before trying to write to standard * output or standard error or invoking any other function of this module * otherwise messages might get lost in some situations. This does not affect * "console" applications nor "window" application started from a console. * For more about this issue, see: * * INFO: Calling CRT Output Routines from a GUI Application, * Article ID: 105305 - Last Review: Nov 21, 2006 - Revision: 1. * Quote: "To use C Run-time output routines, such as printf(), from a GUI * application, it is necessary to create a console. [...]". * https://support.microsoft.com/en-us/help/105305/info-calling-crt-output-routines-from-a-gui-application * * @file * @author Umberto Salsi * @version $Date: 2017/09/09 23:54:33 $ */ #ifndef ERROR_H #define ERROR_H #include #ifdef error_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Name of the program, to be reported along with the error messages. * Client program may retrieve from here its name to build other customized * messages. */ EXTERN char * error_prog_name #ifdef error_IMPORT = "UNDEFINED" #endif ; /** * Flag to enable debugging in the program. */ EXTERN int debug #ifdef error_IMPORT = 0 #endif ; /** * Initializes this module. Under Linux, this merely sets the error_prog_name * global variable by copying the pointer, normally retrieved from the * argv[0] parameters of the main() function. Under Windows this also checks * if a terminal is available where to send standard output and standard error; * if not, creates a terminal needed to preserve messages sent to these files. * @param prog_name Name of this program to display along with any error * message hereafter. */ EXTERN void error_init(char *prog_name); /** * Reports an internal unexpected error to stderr then aborts the program. * This kind of errors indicate a bug in the program. * @param fmt Format descriptor, just like in "printf". * @param ... Optional parameters for the format descriptor, each argument * matching a format descriptor of 'fmt'. If no optional arguments are required, * at least one must be given anyway, for example a simple zero: *
error_internal("unimplemented", 0);
*/ #define error_internal(fmt, ...) \ { error_internal_PRIVATE(__FILE__, __LINE__, fmt, __VA_ARGS__);\ abort(); /* makes happy gcc -Wall */ } /** * Reports an external error to stderr then exits the program with code 1. * This kind of errors may indicate an invalid configuration, system limitation, * unexpected system behavior, bad response from a remote server, invalid user * data. * @param fmt Format descriptor, just like in "printf". * @param ... Optional parameters for the format descriptor. */ EXTERN void error_external(char *fmt, ...); /** * Reports a fatal error generated by a system function that also sets errno to * stderr, then exits the program with code 1. Uses the current value of errno * to add the corresponding description to the message. This kind of errors * indicate a system limitation, failed access to the file system, invalid * configuration of the program, failed access to a remote server. * @param fmt Format descriptor, just like in "printf". * @param ... Optional parameters for the format descriptor. */ EXTERN void error_system(char *fmt, ...); /** * USE THE MACRO. */ EXTERN void error_internal_PRIVATE(char *file, int line, char *fmt, ...); #undef EXTERN #endif /* ERROR_H */ acm-6.0_20200416/src/util/hashtable.c0000644000000000000000000001641513260344465015454 0ustar rootroot#include #include #include #include "memory.h" #define hashtable_IMPORT #include "hashtable.h" typedef struct hashtable_Entry { struct hashtable_Entry *next; // Next entry that shares the same slot. int key_hash; // Hash of the key of this entry. void *key; // Key. void *value; // Value. } hashtable_Entry; struct hashtable_Type { hashtable_getKeyHash getKeyHash; // Computes the hash of the key. hashtable_equalKeys equalKeys; // Compares two keys for equality. int length; // No.of stored key/value pairs. int slots_no; // No. of entries in the array of slots (aka buckets). hashtable_Entry **slots; // Slots. int cursor_next_slot_no; // Sequential access, next slot no. hashtable_Entry *cursor_next_entry; // Sequential access, next entry. }; /** * Destructor call-back for the memory module. * @param p Hash table to destruct. */ static void hashtable_destruct(void *p) { int i; hashtable_Type *ht = p; if( ht == NULL ) return; for(i = ht->slots_no-1; i >= 0; i--){ hashtable_Entry *curr, *next; curr = ht->slots[i]; while( curr != NULL ){ next = curr->next; memory_dispose(curr->key); memory_dispose(curr->value); memory_dispose(curr); curr = next; } } memory_dispose(ht->slots); } static void hashtable_resetCursor(hashtable_Type *ht) { ht->cursor_next_slot_no = -1; ht->cursor_next_entry = NULL; } hashtable_Type *hashtable_new( hashtable_getKeyHash getKeyHash, hashtable_equalKeys equalKeys) { hashtable_Type *ht = memory_allocate(sizeof(hashtable_Type), hashtable_destruct); ht->getKeyHash = getKeyHash; ht->equalKeys = equalKeys; ht->length = 0; ht->slots_no = 0; ht->slots = NULL; hashtable_resetCursor(ht); return ht; } int hashtable_length(hashtable_Type *ht) { return ht->length; } static int hashtable_getSlotIndexFromHash(int slots_no, int hash) { int i = hash % slots_no; if( i < 0 ) i = - i - 1; return i; } /** * Re-allocates the hash table array of slots when the number of key/value * pairs equals its length. Attempts to double the length. */ static void hashtable_realloc(hashtable_Type *ht) { hashtable_Entry **slots2; int i; int slots_no2 = 2 * ht->slots_no + 1; int size = slots_no2 * sizeof(hashtable_Entry *); if( size <= 0 ) return; slots2 = memory_allocate(size, NULL); memset(slots2, 0, size); for(i = ht->slots_no-1; i >= 0; i--){ hashtable_Entry *curr = ht->slots[i]; while(curr != NULL){ hashtable_Entry *next = curr->next; int i2 = hashtable_getSlotIndexFromHash(slots_no2, curr->key_hash); curr->next = slots2[i2]; slots2[i2] = curr; curr = next; } } memory_dispose(ht->slots); ht->slots = slots2; ht->slots_no = slots_no2; } static hashtable_Entry *hashtable_getEntry(hashtable_Type *ht, int key_hash, void *key) { if( ht->slots_no == 0 ) return NULL; int i = hashtable_getSlotIndexFromHash(ht->slots_no, key_hash); hashtable_Entry *e = ht->slots[i]; while( e != NULL ){ if( e->key_hash == key_hash && ht->equalKeys(e->key, key) ) return e; e = e->next; } return NULL; } void hashtable_put(hashtable_Type *ht, void *key, void *value) { int key_hash = ht->getKeyHash(key); hashtable_Entry *e = hashtable_getEntry(ht, key_hash, key); if( e != NULL ){ /* Key already in table. Replace existing value. */ if( e->value != value ) memory_dispose(e->value); e->value = value; return; } else if( ht->slots_no == 0 ){ /* Table still empty. First allocation. */ ht->slots_no = 123; ht->slots = memory_allocate(ht->slots_no * sizeof(hashtable_Entry *), NULL); memset(ht->slots, 0, ht->slots_no * sizeof(hashtable_Entry *)); } else if( ht->slots_no == ht->length ){ /* Time to try to double the length of the array of slots. */ hashtable_realloc(ht); hashtable_resetCursor(ht); } /* Add entry. */ int i = hashtable_getSlotIndexFromHash(ht->slots_no, key_hash); e = memory_allocate(sizeof(hashtable_Entry), NULL); e->key_hash = key_hash; e->key = key; e->value = value; e->next = ht->slots[i]; ht->slots[i] = e; ht->length++; } void *hashtable_get(hashtable_Type *ht, void *key) { int key_hash = ht->getKeyHash(key); hashtable_Entry *e = hashtable_getEntry(ht, key_hash, key); if( e == NULL ) return NULL; else return e->value; } void hashtable_remove(hashtable_Type *ht, void *key) { int key_hash = ht->getKeyHash(key); hashtable_Entry *e = hashtable_getEntry(ht, key_hash, key); if( e == NULL ) return; int i = hashtable_getSlotIndexFromHash(ht->slots_no, key_hash); if( ht->slots[i] == e ){ ht->slots[i] = e->next; } else { hashtable_Entry *curr = ht->slots[i]; while(curr->next != e) curr = curr->next; curr->next = e->next; } if( e == ht->cursor_next_entry ){ /* * FIXME: unlikely removing of entry past the current cursor position. * We might support this, but worth the effort? For now simply reset: */ hashtable_resetCursor(ht); } memory_dispose(e->key); memory_dispose(e->value); memory_dispose(e); } void *hashtable_firstKey(hashtable_Type *ht) { int i; for(i = ht->slots_no - 1; i >= 0; i--) if( ht->slots[i] != NULL ) break; if( i < 0 ){ hashtable_resetCursor(ht); return NULL; } hashtable_Entry *e = ht->slots[i]; if( e->next == NULL ){ do { i--; }while( i >= 0 && ht->slots[i] == NULL ); ht->cursor_next_slot_no = i; ht->cursor_next_entry = i >= 0? ht->slots[i] : NULL; } else { ht->cursor_next_slot_no = i; ht->cursor_next_entry = e->next; } return e->key; } void *hashtable_nextKey(hashtable_Type *ht) { if( ht->cursor_next_entry == NULL ) return NULL; int i = ht->cursor_next_slot_no; hashtable_Entry *e = ht->cursor_next_entry; if( e->next == NULL ){ do { i--; }while( i >= 0 && ht->slots[i] == NULL ); ht->cursor_next_slot_no = i; ht->cursor_next_entry = i >= 0? ht->slots[i] : NULL; } else { ht->cursor_next_entry = e->next; } return e->key; } int hashtable_getHashOfMem(void *buf, int buf_len) { char *charptr; int *intptr = buf; int hash = 1; while(buf_len >= sizeof(int)){ hash = 573 * hash + *intptr; intptr++; buf_len -= sizeof(int); } charptr = (char *) intptr; while(buf_len > 0){ hash = 573 * hash + *charptr; charptr++; buf_len--; } return hash; } int hashtable_getHashOfString(void *s) { return hashtable_getHashOfMem(s, strlen(s)); } int hashtable_equalStrings(void *a, void *b) { return strcmp(a, b) == 0; } void hashtable_report(hashtable_Type *ht) { int i, si, simax, sisum, used; double si2sum, avg, var, Q; hashtable_Entry *s; if( ht->slots_no == 0 ){ printf(" empty table.\n"); return; } simax = 0; sisum = 0; si2sum = 0.0; used = 0; for(i = ht->slots_no-1; i >= 0; i--){ s = ht->slots[i]; if( s != NULL ) used++; si = 0; while(s != NULL){ si++; s = s->next; } if( si > simax ) simax = si; sisum += si; si2sum += si*si; } avg = (double) sisum / used; /* mean length of occupied slots */ var = si2sum / used - avg*avg; /* variance of the occupied slot length */ Q = 0.5*(si2sum/sisum + 1.0); /* mean no. of comparisons per search */ printf(" %d total table length\n", ht->slots_no); printf(" %d occupied table entries\n", used); printf(" %d max table entry length\n", simax); printf(" %g average table entry length\n", avg); printf(" %g variance table entry length\n", var); printf(" %g mean no. of comparisons per search\n", Q); }acm-6.0_20200416/src/util/error.c0000644000000000000000000000403013172245171014634 0ustar rootroot#include #include #include #include #include #ifdef WINNT #include #include #include #endif #define error_IMPORT #include "error.h" #undef error_IMPORT void error_init(char *prog_name) { error_prog_name = prog_name; #ifdef WINNT if( AllocConsole() ){ // FIXME: what if something goes wrong here? try writing to stdxxx anyway... int hCrt; FILE *hf; // Remap stdout to the console: hCrt = _open_osfhandle( (long) GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT); if( hCrt == -1 ) error_internal("_open_osfhandle() on STD_OUTPUT_HANDLE", 0); hf = _fdopen(hCrt, "w"); if( hf == NULL ) error_internal("_fdopen() failed on STD_OUTPUT_HANDLE", 0); *stdout = *hf; /* ignore = */ setvbuf(stdout, NULL, _IONBF, 0); // Remap stderr to the console: hCrt = _open_osfhandle( (long) GetStdHandle(STD_ERROR_HANDLE), _O_TEXT); if( hCrt == -1 ) error_internal("_open_osfhandle() on STD_ERROR_HANDLE", 0); hf = _fdopen(hCrt, "w"); if( hf == NULL ) error_internal("_fdopen() failed on STD_ERROR_HANDLE", 0); *stderr = *hf; /* ignore = */ setvbuf(stderr, NULL, _IONBF, 0); // Make the console (nearly) invisible: ShowWindow(GetConsoleWindow(), SW_HIDE); } #endif } void error_internal_PRIVATE(char *file, int line, char *fmt, ...) { va_list ap; char s[999]; va_start(ap, fmt); vsnprintf(s, sizeof(s), fmt, ap); va_end(ap); fflush(stdout); fprintf(stderr, "%s internal error in %s:%d: %s.\n", error_prog_name, file, line, s); abort(); } void error_external(char *fmt, ...) { va_list ap; char s[999]; va_start(ap, fmt); vsnprintf(s, sizeof(s), fmt, ap); va_end(ap); fflush(stdout); fprintf(stderr, "%s: %s.\n", error_prog_name, s); exit(1); } void error_system(char *fmt, ...) { int err; va_list ap; char s[999]; err = errno; // save current value of errno va_start(ap, fmt); vsnprintf(s, sizeof(s), fmt, ap); va_end(ap); fflush(stdout); fprintf(stderr, "%s: %s: %s.\n", error_prog_name, s, strerror(err)); exit(1); } acm-6.0_20200416/src/util/units.c0000644000000000000000000000016613064343246014655 0ustar rootroot/* * Dummy empty implementation: this module only exports declarations. */ #define units_IMPORT #include "units.h" acm-6.0_20200416/src/util/timer.c0000644000000000000000000000371013154073366014634 0ustar rootroot#include #include #ifdef WINNT #include #else #include #include #endif #include "error.h" #include "memory.h" #define timer_IMPORT #include "timer.h" struct timer_Type { int isRunning; int64_t start; int64_t total; }; /** Ticks counter frequency (Hz). */ static int64_t frequency; timer_Type * timer_new() { if( frequency == 0 ){ #ifdef WINNT LARGE_INTEGER f; if( ! QueryPerformanceFrequency(&f) ) error_internal("QueryPerformanceFrequency() failed", 0); frequency = f.QuadPart; #else frequency = 1000000000; #endif } timer_Type *t = memory_allocate(sizeof(timer_Type), NULL); t->isRunning = 0; t->total = 0; return t; } static int64_t timer_getTicks() { #ifdef WINNT LARGE_INTEGER ticks; if( ! QueryPerformanceCounter(&ticks) ) error_internal("QueryPerformanceCounter() failed", 0); return ticks.QuadPart; #else struct timespec t; clock_gettime(CLOCK_MONOTONIC, &t); return 1000000000LL * t.tv_sec + t.tv_nsec; #endif } void timer_start(timer_Type *t) { if( t->isRunning ) return; t->isRunning = 1; t->start = timer_getTicks(); } void timer_stop(timer_Type *t) { if( ! t->isRunning ) return; t->isRunning = 0; t->total += timer_getTicks() - t->start; } int64_t timer_getElapsedNanoseconds(timer_Type *t) { int64_t elapsed_ticks = t->total; if( t->isRunning ) elapsed_ticks += timer_getTicks() - t->start; return elapsed_ticks * 1000000000 / frequency; } int64_t timer_getElapsedMicroseconds(timer_Type *t) { return (timer_getElapsedNanoseconds(t) + 500) / 1000; } int timer_getElapsedMilliseconds(timer_Type *t) { int64_t elapsed_us = (timer_getElapsedNanoseconds(t) + 500000) / 1000000; if( elapsed_us <= INT_MAX ) return elapsed_us; else return INT_MAX; } void timer_reset(timer_Type *t) { t->isRunning = 0; t->total = 0; } void timer_sleepMilliseconds(int ms) { if( ms <= 0 ) return; #ifdef WINNT Sleep(ms); #else usleep(1000LL * ms); #endif } acm-6.0_20200416/src/util/memory.h0000644000000000000000000002234213260344465015032 0ustar rootroot/** * Dynamic memory allocation routines with memory corruption detection and * memory leaks detection. Each allocated block may have a defined destructor * function that gets invoked before actually release the memory block. * * A specific header block is prepended to each allocated block to carry * memory leaks detection and corruption. There is no currently way to disable * this safety mechanism. * * Each allocated block may define a destructor function that gets called before * the block is actually released. In this way a single memory_dispose() function * can be used to safely release blocks allocated by any module. * * Modules may register a cleanup function. All these registered cleanup functions * are then called along with the memory reporting routine and then de-registered. * The main function of each program may then call this reporting function * at the very end of its code, just before its normal ending, and may also * exit with the error status code returned by the reporting function itself: * *
 * int main()
 * {
 *     ...
 *     return memory_report();
 * }
 * 
* * Reporting memory leaks is particularly important in test programs, and can be * only optionally compiled in released programs. * * Mixing calls to the functions of this module with calls to the original * stdlib.h system calls over the same allocated blocks leads to memory corruption * and (hopefully :-) to an immediate crash. * * @file * @author Umberto Salsi * @version $Date: 2017/11/02 07:37:59 $ */ #ifndef MEMORY_H #define MEMORY_H #include #ifdef memory_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Allocates a memory block of at least the given size. If fails or the requested * size is not positive, gives error and aborts. * @param size Capacity of the block (bytes). Must be non-negative. * @param destructor Destructor function to call before actually release this * block from memory. Can be NULL. * @return Pointer to the allocated block. */ #define memory_allocate(size, destructor) memory_allocate_PRIVATE(__FILE__, __LINE__, size, destructor) /** * Releases a memory block allocated with this module. If the destructor function * is defined for this block, calls that function before actually releasing the * memory. Releasing an invalid pointer or a block already released aborts the * program. * @param p Block of memory to release. Does nothing if NULL. */ EXTERN void memory_dispose(void * p); /** * Re-allocates a previously allocated block of memory by also copying the * original content to the new block as required. If fails or the requested size * is not positive, gives error and exits with status code 1. * @param p Block to re-allocate. If NULL, this function performs just like * memory_allocate(). * @param size New capacity of the block (bytes). Must be positive. * @return Pointer to the block of the given capacity. */ #define memory_realloc(p,size) memory_realloc_PRIVATE(__FILE__,__LINE__,p,size) /** * Copies a NUL-terminated string. Maximum dst_capacity-1 bytes are copied from * the source string to leave room for the NUL byte. The destination string is * always NUL-terminated. If dst_capacity is less than 1, a fatal error occurs. * Bytes of the destination beyond the NUL terminator are not set. * Please note that this function is very similar to the standard strncpy(), but * here the destination is always properly NUL-terminated. * @param dst Destination string. * @param dst_capacity Capacity of the destination string. Must be at least 1. * @param src Source string. */ EXTERN void memory_strcpy(char *dst, int dst_capacity, char *src); /** * Returns a copy of the given NUL-terminated string. If it fails, aborts. * Must be released with memory_dispose(). * @param s NUL-terminated string to copy. * @return Dynamically allocated block containing a copy of the string. */ EXTERN char * memory_strdup(char * s); /** * Returns true if the string starts with the specified head. An empty head is * the beginning of any string. * @param s * @param head * @return True if 's' starts with the bytes of 'head'. */ EXTERN int memory_startsWith(char * s, char * head); /** * Returns 1 if the string begins with the given leading bytes of the tag, * otherwise returns 0. The comparison is case-insensitive according to the * function "toupper()" which is locale-aware, so strange and unexpected * results may occur if the tag contains non-ASCII codes. * @param s NUL-terminated string. * @param tag NUL-terminated string of leading bytes. * @return 1 if the string begins with the given leading bytes of the tag, * otherwise returns 0. */ EXTERN int memory_startsWithIgnoreCase(char * s, char * tag); /** * Returns true if the string ends with the specified tail. An empty tail is * the end of any string. * @param s * @param tail * @return True if 's' ends with the bytes of 'tail'. */ EXTERN int memory_endsWith(char * s, char * tail); /** * Search for a target substring. * memmem() seems to be a GNU extension still not widely available, * here is its replacement. * @param s Search area. * @param slen Length of the search area, not negative. * @param target Target to search. * @param targetlen Length of the target, not negative. * @return Pointer to the first occurrence of the target in the search area, * or NULL if not found. The empty target is always "found" at the beginning * of the search area. If either slen or targetlen is negative, aborts. */ EXTERN char * memory_indexOfMem(char *s, int slen, char *target, int targetlen); /** * Returns the index to the first occurrence of a sub-string in a string. * The comparison is case-insensitive according to the function "toupper()" * which is locale-aware, so strange and unexpected results may occur if the * tag contains non-ASCII codes. * @param str NUL-terminated string. * @param word NUL-terminated sub-string to search in the string. * @return Byte offset of the found sub-string, or -1 if not found. */ EXTERN int memory_indexOfStringIgnoreCase(char * str, char * word); /** * Returns the pointer to the value of the given environmental variable. * @param name Name of the environmental variable. * @param default_value Default value. If NULL, and the requested environment * variable does not exist, it is a fatal error with exit code 1. * @return Pointer to the value of the given environmental variable, or the * default value if not NULL. */ EXTERN char * memory_getEnvKey(char * name, char * default_value); /** * Returns a pointer to a string formatted according to the given format. * @param fmt Format descriptor, just like "printf". * @param ... Parameters. * @return Pointer to the resulting formatted string. The string is statically * allocated with a fixed capacity of 1000 bytes, and does not need to be * deallocated. */ EXTERN char *memory_format(char *fmt, ...); /** * Registers a cleanup function to call by memory_report(). Modules may register * here their specific cleanup function that releases from memory any temporary * data allocated. Cleanup functions are called in the reverse order of their * registration and then are de-registered. Trying to register the same function * more than once has no effect. * @param cleanup Cleanup function to register. */ EXTERN void memory_registerCleanup(void (*cleanup)()); /** * Calls any registered cleanup function and then reports memory leaks. Cleanup * functions are invoked in reverse order of registration and, once called, are * de-registered. The report is written to stderr; it includes the first 100 * remaining allocated blocks along with the file name and line number of the * location where the block was firstly allocated; for each block the first 20 * bytes are also displayed; a summary of the total number of remaining allocated * blocks and their total size is also displayed. If there are not memory leaks, * nothing is sent to stderr. * @return Zero if there are not remaining allocated blocks, 1 otherwise. */ EXTERN int memory_report(void); /** * USE THE MACRO. * Allocates a memory block of at least the given size. If fails or the requested * size is not positive, gives error and exits with status code 1. * @param file File name of the source for memory leaks reporting. * @param line Line number of the source for memory leaks reporting. * @param size Capacity of the block (bytes). Must be non-negative. * @param destructor Destructor function to call before actually release this * block. * @return Pointer to the allocated block. */ EXTERN void * memory_allocate_PRIVATE(char *file, int line, int size, void (*destructor)(void *data)); /** * USE THE MACRO. * For internal use only, use the memory_realloc(p,s) macro instead. */ EXTERN void * memory_realloc_PRIVATE(char *file, int line, void * p, int size); #define memory_zero(ptr) memset(ptr, 0, sizeof(*(ptr))) #undef EXTERN #ifndef memory_IMPORT // Catch possible direct usages of malloc() realloc(), strdup() and free() from here on: #define malloc ERROR_invalid_direct_usage_of_malloc #define free ERROR_invalid_direct_usage_of_free #define realloc ERROR_invalid_direct_usage_of_realloc #define strdup ERROR_invalid_direct_usage_of_strdup #endif #ifdef WINNT #define bcopy(s,d,n) memmove(d,s,n) #endif #endif /* MEMORY_H */ acm-6.0_20200416/src/util/audio.h0000644000000000000000000000623213154022035014607 0ustar rootroot/** * Simple audio playback object. Each object loads and stores a single WAV sound * file. WAV files must use the PCM encoding with no compression and 8, 16, 24 * or 32 bits per sample, any number of channels. * * Features: * * - Start and stop playback. * * - One-shot or loop playback. * * - Cursor positioning. * * - Change playback frequency rate. * * Example that loads a sound, plays the sound and waits for its ending: * *
 * audio_Type *a = audio_new("MySong.wav");
 * audio_play(a);
 * while( audio_isPlaying(a) )  Sleep(1000);
 * memory_dispose(a);
 * 
* * @file * @author Umberto Salsi * @version $Date: 2017/09/06 16:36:45 $ */ #ifndef AUDIO_H #define AUDIO_H #ifdef audio_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Playable sound. */ typedef struct audio_Type audio_Type; /** * Create new WAV file player. The player is paused, positioned at the beginning * of the sound, in one-shot mode and at its nominal sampling rate. * @param wav_filename WAV file to play. * @return New WAV file player. Can be released with memory_dispose(). */ EXTERN audio_Type * audio_new(char * wav_filename); /** * Starts or continue playing up to end of the sound (or forever if loop * enabled). */ EXTERN void audio_play(audio_Type *this); /** * Tells if currently playing the sound. * @return True if currently playing the sound; false if either end of the * sound and no loop enabled, or paused. */ EXTERN int audio_isPlaying(audio_Type *this); /** Puts sound in pause status. */ EXTERN void audio_pause(audio_Type *this); /** Tells if the sound is currently paused. */ EXTERN int audio_isPaused(audio_Type *this); /** Enables or disables the loop mode. */ EXTERN void audio_loop(audio_Type *this, int enable); /** Tells if loop mode is enabled. */ EXTERN int audio_isLooping(audio_Type *this); /** Returns the original total length of the sound (ms). */ EXTERN int audio_getOriginalLengthMilliseconds(audio_Type *this); /** * Returns the current total length of the sound based on the current playback * rate (ms). */ EXTERN int audio_getCurrentLengthMilliseconds(audio_Type *this); /** * Returns the current position of the cursor based on the current playback * rate (ms). */ EXTERN int audio_getCurrentPositionMilliseconds(audio_Type *this); /** * Moves the cursor at the specified time (ms) based on the current playback * rate. Negative values moves to the beginning. Values longer than the total * sound length move the cursor at the end. Sound playback continues based on * the current setting of the loop and pause modes. */ EXTERN void audio_setCurrentPositionMilliseconds(audio_Type *this, int position); /** Returns the original samples playback rate of the sound (Hz). */ EXTERN int audio_getOriginalSamplesPerSecond(audio_Type *this); /** Returns the current samples playback rate of the sound (Hz). */ EXTERN int audio_getCurrentSamplesPerSecond(audio_Type *this); /** * Set the current samples playback rate (Hz). The specified value is forced to * the range [100,15000] Hz. */ EXTERN void audio_setCurrentSamplesPerSecond(audio_Type *this, int rate); #undef EXTERN #endif acm-6.0_20200416/src/util/zulu.h0000644000000000000000000001746613173131276014531 0ustar rootroot/** * Timestamp, time and date UTC conversion routines. The following date * formats are supported: * * - Unix timestamp as number of seconds elapsed since 1970-01-01 00:00:00 UTC; * negative values indicate dates before that epoch. Here we use "int". * On compilers with 32-bits "int" (like gcc on any know platform including * 64-bits processors) a timestamp covers dates in the range between * 1901-12-13 20:45:52 (fractional year 1901.9503155758), and up to * 2038-01-19 03:14:07 (fractional year 2038.0496843924). * * - Broken-down Gregorian date and time as year, month, day, hour, minutes and * seconds UTC time. The minimal supported year is 1583. * * - Year with fractional part. For example, 2017.5 means 2017-07-02 12:00 UTC. * The minimal supported value is 1583.0. * * We assume that each year has 365 days (366 for leap years); each day has * 86400 seconds. Timestamps does not account for the leap seconds, so the * difference between two timestamps may not corresponds to the real elapsed * time, but it is very close to it. Anyway, the calculations performed by this * library exactly match those performed by the GNU C standard library I have * compared with. * * The local time zone has no effect on this library; the standard C library * already covers local time and local dates, but apparently there are not * portable and easy-to-use conversion functions for UTC. * * References: * - Eric S. Raymond, "Time, Clock, and Calendar Programming In C" * http://www.catb.org/esr/time-programming/ * ...or, why the C standard (and non standard) library is too much complex * and confusing to be used safely, and then the reason why I wrote this * replacement module. * * @file * @author Umberto Salsi * @version $Date: 2017/10/22 15:01:18 $ */ #ifndef ZULU_H #define ZULU_H #ifdef zulu_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * The Gregorian calendar was fully established and enter at regime in 1583. * 11 days were removed the year before to re-align the Julian calendar with the * new one. This library does not support years before this and may return wrong * results attempting to enter or calculate dates and timestamps before this * limit. */ #define zulu_YEAR_MIN (1583) /** * Broken-down Gregorian date and time. Time always refers to the UTC or "Zulu" * time. */ typedef struct { /** Year equal or greater than zulu_YEAR_MIN. */ int year; /** Month in the range [1,12]. */ int month; /** Day of the month in the range [1,31]; the exact maximum value depends on the specific month; for February it also depends on the year. */ int day; /** Hour in the range [0,23]. */ int hour; /** Minutes in the range [0,59]. */ int minutes; /** Seconds in the range [0,59]. */ int seconds; } zulu_Date; /** * Returns true if the year is a leap year according to the Gregorian calendar, * that is when February has 29 days. That rule can be stated like this: * "Years divisible by 100 are leap year only if they are also divisible by 400; * any other year is a leap year if it is divisible by 4." * The result is correct starting from year 1501, when the Julian calendar * was still in use; year 1500 was a leap year according to the Julian calendar, * but it was not according to this function that implements the Gregorian rule * only. * @param year No range check on this value. * @return True if the year is a leap year according to the Gregorian calendar. */ EXTERN int zulu_isLeapYear(int year); /** * Converts timestamp into date. * @param ts Timestamp to convert. No range check is performed: on 32-bits int * timestamps, the whole range returns a valid date; for 64-bits int timestamps, * the client should avoid unreasonable values for performances reasons. * @param d Here stores the resulting date. */ EXTERN void zulu_timestampToDate(int ts, zulu_Date *d); /** * Converts timestamp into year. * @param ts Timestamp to convert. No range check is performed: on 32-bits int * timestamps, the whole range returns a valid year; for 64-bits int timestamps, * the client should avoid unreasonable values for performances reasons. * @return Year. */ EXTERN double zulu_timestampToYear(int ts); /** * Converts date to timestamp. * @param d Date to convert. If any field is out of the allowed range, a fatal * error occurs; dates before the year 1583 when the Gregorian calendar was * established may return wrong timestamps; on 32-bits int compilers the range * of dates is much more narrow. If the result overflows or underflows the "int" * capacity of a timestamp, a fatal error occurs. * @return Timestamp. */ EXTERN int zulu_dateToTimestamp(zulu_Date *d); /** * Converts date to fractional year. * @param d Date to convert. If any field is out of the allowed range, a fatal * error occurs; dates before year the 1583 when the Gregorian calendar was * established may return wrong results. * @return Year. */ EXTERN double zulu_dateToYear(zulu_Date *d); /** * Converts year to timestamp. * @param year If the resulting timestamp overflows the "int" capacity of a * timestamp, a fatal error occurs. For performances reasons, the client should * definitely check for unreasonable values before calling this function. * @return Timestamp. */ EXTERN int zulu_yearToTimestamp(double year); /** * Converts fractional year to date. * @param year Year to convert. No range check is performed; years before * 1583 when the Gregorian calendar was established may return wrong results. * @param d Here stores the resulting UTC date. */ EXTERN void zulu_yearToDate(double year, zulu_Date *d); /** * Parse a zulu date and time string. Basically this function parses the * ISO 8601 extended format "yyyy-mm-ddThh:ii:ss" ("ii" are the minutes) * where the time zone part is missing as here we are dealing with zulu only. * Each component of the date and time counts as a "field"; the total number * of fields parsed is returned after successful parsing and validation of the * string passed, so allowing the client to know which pars has been omitted. * The full format then returns 6 fields; the following abbreviated formats are * also recognized: * - "yyyy-mm", assumes day 1, time 00:00:00 and returns 2. * - "yyyy-mm-dd", assumes time 00:00:00 and returns 3. * - "yyyy-mm-ddThh:ii", assumes seconds 00 and returns 5. * Year field must have 4 digits; the allowed year range is [1583,9999]. * Month must have two digits; the allowed month range is [01,12]. * Day must have two digits and its allowed range depends on the specific month * and year. Seconds must have two digits; decimals not allowed. * @param s String to parse. Null, empty or white spaces are not allowed. * @param z Parsed date and time. * @return True if parsing succeeded; false if null, empty, cannot parse or * some field out of the ranges. When parsing succeeds, the value returned is * the number of fields parsed. */ EXTERN int zulu_dateParse(char *s, zulu_Date *z); /** * Compares dates. * @param a * @param b * @return Negative, zero or positive if the first date is comes before, * is equal or comes past the second date. */ EXTERN int zulu_dateCompare(zulu_Date *a, zulu_Date *b); /** * Format a zulu date. The resulting format depends on the capacity of the * destination string; the following cases are examined in the order: * - At least 20 bytes: "yyyy-mm-ddThh:ii:ss" where "ii" are minutes. * - At least 17 bytes: "yyyy-mm-ddThh:ii". * - At least 11 bytes: "yyyy-mm-dd". * - At least 8 bytes: "yyyy-mm" where "ii" are minutes. * Smaller capacity causes fatal error. * @param d Date to format. * @param s Destination string. The format depends on the capacity of the * destination string buffer as explained above. * @param s_capacity Capacity of the destination buffer. */ EXTERN void zulu_dateFormat(zulu_Date *d, char *s, int s_capacity); #undef EXTERN #endif acm-6.0_20200416/src/util/Makefile0000644000000000000000000000276513172245204015011 0ustar rootroot# This file generated by make-makefile, do not edit! # Create Makefile-include.txt instead for your customizations. CC := gcc CFLAGS := -Wall -Werror -g -fmax-errors=99 -Wuninitialized -Wmissing-prototypes -Wredundant-decls LIBS := .PHONY: all all: make audio.o error.o gui.o hashtable.o memory.o prng.o reader.o sparsearray.o timer.o units.o varray.o wav.o zulu.o #include Makefile-include.txt .PHONY: clean clean: rm -f *.o *.exe *.stackdump audio.o: audio.c audio.h error.h memory.h wav.h $(CC) $(CFLAGS) -c audio.c -o audio.o error.o: error.c error.h $(CC) $(CFLAGS) -c error.c -o error.o gui.o: gui.c gui.h ../util/error.h ../util/memory.h $(CC) $(CFLAGS) -c gui.c -o gui.o hashtable.o: hashtable.c hashtable.h memory.h $(CC) $(CFLAGS) -c hashtable.c -o hashtable.o memory.o: memory.c memory.h error.h $(CC) $(CFLAGS) -c memory.c -o memory.o prng.o: prng.c prng.h $(CC) $(CFLAGS) -c prng.c -o prng.o reader.o: reader.c reader.h memory.h $(CC) $(CFLAGS) -c reader.c -o reader.o sparsearray.o: sparsearray.c sparsearray.h memory.h $(CC) $(CFLAGS) -c sparsearray.c -o sparsearray.o timer.o: timer.c timer.h error.h memory.h $(CC) $(CFLAGS) -c timer.c -o timer.o units.o: units.c units.h $(CC) $(CFLAGS) -c units.c -o units.o varray.o: varray.c varray.h error.h memory.h $(CC) $(CFLAGS) -c varray.c -o varray.o wav.o: wav.c wav.h error.h memory.h $(CC) $(CFLAGS) -c wav.c -o wav.o zulu.o: zulu.c zulu.h error.h $(CC) $(CFLAGS) -c zulu.c -o zulu.o # Checksum of the original file: 4151888144 acm-6.0_20200416/src/util/prng.c0000644000000000000000000001337313172245244014464 0ustar rootroot#include #include #include #include #include #include #include #include #define prng_IMPORT #include "prng.h" // To use the system random function, define this macro. //#define prng_USE_SYSTEM // To use the this module's built-in random function, define this macro: #define prng_USE_INTERNAL #ifdef prng_USE_SYSTEM #define prng_RAND_MAX RAND_MAX #define prng_SRAND(seed) srand(seed) #define prng_RAND() (rand()) #endif #ifdef prng_USE_INTERNAL /* * Uses the C99, C11 suggestion in the ISO/IEC 9899: * https://en.wikipedia.org/wiki/Linear_congruential_generator */ #define prng_RAND_MAX 0x7fff static unsigned int prng_seed; static void prng_SRAND(unsigned int seed) { prng_seed = seed; } static int prng_RAND() { prng_seed = 1103515245 * prng_seed + 12345; return (prng_seed >> 16) & prng_RAND_MAX; } #endif static int inited; /** Mask of bits covered by numbers returned by rand(). */ static unsigned int rand_max_mask; /** How many random bits per rand() value returned. */ static int bits_per_rand; static void prng_init() { inited = 1; /* Determines how many random bits are returned by rand(): */ bits_per_rand = 8*sizeof(unsigned int); rand_max_mask = (unsigned int) -1; while(rand_max_mask > prng_RAND_MAX){ rand_max_mask >>= 1; bits_per_rand--; } /* * To get different sequences each time the process is started, * set a "random" seed based on: current wall time; current number of * tick since computer start; current process ID. */ struct timeval tv; gettimeofday(&tv,NULL); prng_setSeed( tv.tv_sec + tv.tv_usec + clock() + getpid() ); } void prng_setSeed(unsigned int seed) { if( ! inited ) prng_init(); prng_SRAND(seed); } /* * By generating, say, 1 million of random numbers on a very wide range of the * int spectrum, about half of them should fall before the middle, right? * The typical naive implementation rand() % n to get a value in the range * [0,n-1] does not work and retrieves something like 666666 rather than * the expected 500000. * * Gets rid of this nasty "modulo bias" as suggested by: * * Mark Amery * http://stackoverflow.com/questions/10984974/why-do-people-say-there-is-modulo-bias-when-using-a-random-number-generator * * The penalty is that the random bits sequence must be generated twice in about * the 50% of the cases. * * The difference here is that the generated random number can be larger than * RAND_MAX, so we must keep the algorithm more general and replace RAND_MAX * with a variable bits_covered. */ int prng_getIntInRange(int min, int max) { assert(min <= max); if( ! inited ) prng_init(); unsigned int range_max = (unsigned int) (max - min); unsigned int bits; // generated random bits unsigned int bits_covered; // mask of covered generated random bits do { /* * Generate random bits enough to cover the requested range [0,range_max]. * Keep generating random numbers and shift left their bits accounting * in bits_covered the mask of the covered bits. Continue until * bits_covered >= range_max. */ bits = prng_RAND(); bits_covered = rand_max_mask; while(bits_covered < range_max){ bits_covered = (bits_covered << bits_per_rand) | rand_max_mask; bits = (bits << bits_per_rand) | (prng_RAND() & rand_max_mask); } /* * Now 0 <= bits <= bits_covered. If range_max equals bits_covered, * there is not the modulus bias problem and we can safely returns these * bits. This also prevents several possible overflows below. */ if( range_max == bits_covered ) return min + (int) bits; /* * Now 0 <= bits < bits_covered but we must cast bits to the requested * range [0,range_max] preventing the modulo bias problem, so a simple * bits % (range_max+1) does not work. We may think at this interval as * a sequence of sections, each section containing (bits_covered+1) / * (range_max+1) numbers plus the last, possibly shorter, section * containing the remaining numbers: * * rem = (bits_covered + 1) % (range_max + 1) * * If rem==0 there is no bias problem and the modulo operator * will return each number with the same probability. Otherwise, if * "bits" falls in this section, we must reject it and try another one. * But there is a catch: (bits_covered + 1) may overflow, so we must * evaluate the reminder on (bits_covered + 1 - (range_max + 1)) instead * getting the same result without overflow: */ unsigned int rem = (bits_covered - range_max) % (range_max + 1); if( rem == 0 || bits <= bits_covered - rem ) break; } while( 1 ); /* * Maps 0 <= bits <= range_max into [min,max]. */ return min + (int) (bits % (range_max + 1)); } double prng_getDouble() { if( ! inited ) prng_init(); unsigned int bits = (unsigned int) prng_RAND(); int bits_no = bits_per_rand; /* * Typical implementation of rand() returns 31 bits (Linux, Cygwin); * 31 bits are enough, do not waste one more call to rand() just to fill 1 bit: */ while( bits_no < 8*sizeof(unsigned int) - 1 ){ bits = (bits << bits_per_rand) | prng_RAND(); bits_no += bits_per_rand; } /* ...but now fill the highest bit if needed: */ if( bits_no < 8*sizeof(unsigned int) ) bits <<= 1; return (double) bits / ((double) UINT_MAX + 1.0); } double prng_getDouble2() { return 2.0 * prng_getDouble() - 1.0; } void prng_fill(void *buffer, int buffer_len) { if( ! inited ) prng_init(); unsigned int bits = 0; int bits_ready = 0; while(buffer_len > 0){ while(bits_ready < 8){ bits = (bits << bits_per_rand) | prng_RAND(); bits_ready += bits_per_rand; if( bits_ready > 8 * sizeof(unsigned int) ) bits_ready = 8 * sizeof(unsigned int); } *((char *) buffer) = bits; bits >>= 8; bits_ready -= 8; buffer++; buffer_len--; } }acm-6.0_20200416/src/util/sparsearray.h0000644000000000000000000000365213141045302016043 0ustar rootroot/** * Sparse array. Basically, a collection of elements where each element is * univocally identified by an index. Indeces can be positive and negative. * Each entry of the sparse array holds a pointer to some client data. * * @file * @author Umberto Salsi * @version $Date: 2017/08/04 10:21:54 $ */ #ifndef SPARSEARRAY_H #define SPARSEARRAY_H #ifdef sparsearray_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Sparse array type. */ typedef struct sparsearray_Type sparsearray_Type; /** * Allocates a new, empty sparse array. * @param size Expected or estimated total number of elements that will be stored. * @param keep_elements If the elements must not be released. * @return */ EXTERN sparsearray_Type * sparsearray_new(int size, int keep_elements); /** * Set and entry in the sparse array. Replaces the existing entry, if any; the * existing entry is released depending on the 'keep elements' flag set while * creating this sparse array. * @param sa Involved sparse array. * @param index Index of the entry to set. * @param entry Entry to set. */ EXTERN void sparsearray_set(sparsearray_Type *sa, int index, void *entry); /** * Retrieves the entry at the given index. * @param sa Involved sparse array. * @param index Index of the entry to retrieve. * @return Retrieved user element or NULL if not found. */ EXTERN void * sparsearray_get(sparsearray_Type * sa, int index); /** * Returns the current average comparisons to be performed to fetch an entry, * assuming each index has the same probability. Values greater than 2.0 indicate * sub-optimal performances. * @param sa * @return */ EXTERN double sparsearray_getAverageComparisonsPerSearch(sparsearray_Type *sa); /** * Writes to stdout a detailed report about the internals (for debugging only). * @param sa * @param title */ EXTERN void sparsearray_report(sparsearray_Type *sa, char * title); #undef EXTERN #endif acm-6.0_20200416/src/util/gui.c0000644000000000000000000007237013260344465014307 0ustar rootroot/* * IMPLEMENTATION NOTES. * * 1. We allocate a fixed colors' look-up table (CLUT) with indices than can be * easily mapped back and forth to their corresponding RGB colors. We cannot * use too much colors because that would defeat the drawing optimizations * performed by Alib (as the plane moves, there would be too many differences * from a frame to the next just to draw the sky shades), resulting in a very * low frame rate. You may experiment this issue by increasing the number of * planes per color component below. */ // LINKER_OPTIONS -lm #include #include #include #include #include #include "../util/memory.h" #include "../util/error.h" #define gui_IMPORT #include "gui.h" #define RED_PLANES 17 #define GREEN_PLANES 17 #define BLUE_PLANES 17 #define CLUT_LEN (RED_PLANES * GREEN_PLANES * BLUE_PLANES) static int inited; static unsigned char compressed[256]; static unsigned char expanded[256]; static void gui_init() { if( inited ) return; inited = 1; int i; double p = 1.0; double k = 255.0 / pow(255, p); for(i = 0; i < 256; i++){ compressed[i] = k * pow(i, p) + 0.5; expanded[i] = pow(i/k, 1/p) + 0.5; //printf("%d %d %d\n", i, compressed[i], expanded[i]); } } /** * Allocates a RGB color and returns the index to the CLUT. * Windows and X-Window will define their own specific implementation. * @param this * @param red * @param green * @param blue * @return Index to the allocated entry in the CLUT. */ static int gui_allocateColor(gui_Type *this, int red, int green, int blue); /** * Maps CLUT index into RGB. * @param idx * @param red Red color component in the range [0,255]. * @param green Green color component in the range [0,255]. * @param blue Blue color component in the range [0,255]. */ static void index_to_rgb(int idx, int *red, int *green, int *blue) { assert(0 <= idx && idx < CLUT_LEN); *blue = 256 * (idx % BLUE_PLANES) / (BLUE_PLANES - 1); if( *blue > 255 ) *blue = 255; idx = idx / BLUE_PLANES; *green = 256 * (idx % GREEN_PLANES) / (GREEN_PLANES - 1); if( *green > 255 ) *green = 255; idx = idx / GREEN_PLANES; *red = 256 * idx / (RED_PLANES - 1); if( *red > 255 ) *red = 255; gui_init(); *red = compressed[*red]; *green = compressed[*green]; *blue = compressed[*blue]; } /** * Allocates the CLUT. */ static void createCLUT(gui_Type *this) { int idx, red, green, blue; for(idx = 0; idx < CLUT_LEN; idx++){ index_to_rgb(idx, &red, &green, &blue); if( idx != gui_allocateColor(this, red, green, blue) ) abort(); } } int gui_getColorIndex(gui_Type *this, int red, int green, int blue) { if( (red&255)!=red || (green&255)!=green || (blue&255)!=blue ) error_internal("invalid RGB: %d,%d,%d", red, green, blue); gui_init(); red = expanded[red]; green = expanded[green]; blue = expanded[blue]; int r = ((RED_PLANES-1)*red + 128)/256; int g = ((GREEN_PLANES-1)*green + 128)/256; int b = ((BLUE_PLANES-1)*blue + 128)/256; int idx = (r*GREEN_PLANES + g)*BLUE_PLANES + b; assert(idx < CLUT_LEN); return idx; } int gui_getColorIndexString(gui_Type *this, char *s) { int red, green, blue; if( ! gui_parseColorString(s, &red, &green, &blue) ) error_internal("invalid color specification: %s", s); return gui_getColorIndex(this, red, green, blue); } // Color names currently used inside ACM and its objects collection, in no // particular order. // For more, check https://en.wikipedia.org/wiki/X11_color_names#Color_name_chart static char *ctab[][2] = { {"green", "#00ff00"}, {"white", "#ffffff"}, {"black", "#000000"}, {"orange", "#FF8C00"}, {"gray44", "#444444"}, {"red", "#ff0000"}, {"gray40", "#404040"}, {"gray77", "#777777"}, {NULL, NULL} }; int gui_parseColorString(char *s, int *red, int *green, int *blue) { if( s == NULL ){ return 0; } else if( s[0] == '#' ){ int len = strlen(s); if( len == 4 ){ char *end; // FIXME: strtol() also parses "0x..." long int x = strtol(s+1, &end, 16); if( *end != 0 ) return 0; int n = x & 15; *blue = (n << 4) + n; n = (x >> 4) & 15; *green = (n << 4) + n; n = x >> 8; *red = (n << 4) + n; return 1; } else if( len == 7 ){ char *end; long int x = strtol(s+1, &end, 16); if( *end != 0 ) return 0; *red = x >> 16; *green = (x >> 8) & 255; *blue = x & 255; return 1; } else { return 0; } } else { int i = 0; do { if( ctab[i][0] == NULL ) return 0; if( strcmp(ctab[i][0], s) == 0 ) return gui_parseColorString(ctab[i][1], red, green, blue); i++; } while(1); } } #ifdef WINNT /* * IMPLEMENTATION SPECIFIC FOR MICROSOFT WINDOWS * ============================================= * * IMPLEMENTATION NOTES. * * 1. What makes the code a bit complicated is the events handling. In fact the * window procedure is a call-back that MS Windows calls quite randomly and * unpredictably, even outside the program's main events loop. In particular, * I had a problem with the focus events that went lost because they aren't * reported to the program's main events loop but were instead consumed by * MS Windows internally and never returned to the usual TranslateMessage() * and DispatchMessage() pair. To reproduce the exact same behavior of X-Win, * I had then to introduce a queue of messages. */ #include #include #define EVENTS_QUEUE_CAPACITY 4 struct gui_Type { WNDCLASSEX wcex; HWND hWnd; HDC hdc; int showWindowInvoked; int has_focus; int is_visible; int width, height; // Current mouse pointer position in the content area. int pointer_x, pointer_y; // Indices to the beginning and to the end of the circular events queue. int queue_start, queue_end; // Tells if the queue is full. int queue_full; // Circular queue of events collected by the window procedure. gui_Event queue[EVENTS_QUEUE_CAPACITY]; // Number of allocated pen colors. int colors_number; // Allocated pen colors. HPEN colors[CLUT_LEN]; }; // hInstance always NULL as stated in https://msdn.microsoft.com/en-us/library/windows/desktop/ms633559(v=vs.85).aspx // FIXME: should I retrieve hInstance from WinMain() parameter? static HINSTANCE hInstance; // FIXME: should I retrieve nCommandShow from WinMain() parameter? // see https://msdn.microsoft.com/en-us/library/windows/desktop/ms633559(v=vs.85).aspx static int nCmdShow = SW_SHOWNORMAL; // The main window class name. static TCHAR szWindowClass[] = _T("win32app"); static int key_codes_map[][2] = { {VK_INSERT, gui_KEY_INS}, {VK_HOME, gui_KEY_HOME}, {VK_END, gui_KEY_END}, {VK_PRIOR, gui_KEY_PGUP}, {VK_NEXT, gui_KEY_PGDW}, {VK_DELETE, gui_KEY_DEL}, {VK_UP, gui_KEY_UP}, {VK_DOWN, gui_KEY_DOWN}, {VK_LEFT, gui_KEY_LEFT}, {VK_RIGHT, gui_KEY_RIGHT}, {VK_ADD, gui_KEY_PAD_PLUS}, {VK_SUBTRACT, gui_KEY_PAD_MINUS}, {VK_MULTIPLY, gui_KEY_PAD_TIMES}, {VK_DIVIDE, gui_KEY_PAD_DIVIDE}, {VK_NUMPAD0, gui_KEY_PAD_0}, {VK_NUMPAD1, gui_KEY_PAD_1}, {VK_NUMPAD2, gui_KEY_PAD_2}, {VK_NUMPAD3, gui_KEY_PAD_3}, {VK_NUMPAD4, gui_KEY_PAD_4}, {VK_NUMPAD5, gui_KEY_PAD_5}, {VK_NUMPAD6, gui_KEY_PAD_6}, {VK_NUMPAD7, gui_KEY_PAD_7}, {VK_NUMPAD8, gui_KEY_PAD_8}, {VK_NUMPAD9, gui_KEY_PAD_9}, {0, 0} }; static char *errorCodeToString(int code) { static char s[999]; char win_err_descr[900]; DWORD err = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM, NULL, code, LANG_SYSTEM_DEFAULT, win_err_descr, sizeof(win_err_descr), NULL ); if( err > 0 ){ snprintf(s, sizeof(s), "%s (Windows error code %d)", win_err_descr, code); } else { snprintf(s, sizeof(s), "error code %d (description not available: FormatMessageA() failed with code %lu)", code, err); } return s; } static int queueIsEmpty(gui_Type *this) { return ! this->queue_full && this->queue_start == this->queue_end; } static void queueRemoveEvent(gui_Type *this, int i) { assert( ! queueIsEmpty(this) ); assert( (this->queue_start < this->queue_end && this->queue_start <= i && i < this->queue_end) || (this->queue_end <= this->queue_start && !(this->queue_end <= i && i < this->queue_start))); do { // Replace event at index i with the next one. int j = (i + 1) % EVENTS_QUEUE_CAPACITY; if( j == this->queue_end ){ this->queue_end = i; this->queue_full = 0; return; } i = j; } while(1); } static void queueRemoveEvents(gui_Type *this, int code) { if( queueIsEmpty(this) ) return; int i = this->queue_start; do { if( this->queue[i].code == code) queueRemoveEvent(this, i); else i = (i + 1) % EVENTS_QUEUE_CAPACITY; if( i == this->queue_end ) return; } while(1); } /** * Returns the next free entry from the events queue of the given GUI. If the * queue is full, the oldest occupied entry is returned (then that old event * is lost, but this should never happen). * @param this * * @return Next free entry in the events queue. */ static gui_Event * queueGetFreeEntry(gui_Type *this) { gui_Event *free_entry; free_entry = &this->queue[this->queue_end]; this->queue_end = (this->queue_end + 1) % EVENTS_QUEUE_CAPACITY; if( this->queue_full ){ this->queue_start = this->queue_end; fprintf(stderr, "WARNING: event queue is full, some window event lost!\n"); int i; for(i = 0; i < EVENTS_QUEUE_CAPACITY; i++){ gui_Event *e = &this->queue[(this->queue_start + i) % EVENTS_QUEUE_CAPACITY]; fprintf(stderr, "event no. %d: %d\n", i, e->code); } } else { this->queue_full = this->queue_start == this->queue_end; } return free_entry; } /** * Returns the next queued event from the given GUI. * @param this * @return Next available event, or null if queue is empty. */ static gui_Event * getAvailableQueueEntry(gui_Type *this) { if( queueIsEmpty(this) ) return NULL; gui_Event *avail = &this->queue[this->queue_start]; this->queue_start = (this->queue_start + 1) % EVENTS_QUEUE_CAPACITY; this->queue_full = 0; return avail; } /** * Window event call-back. Meaningful events are added to the events queue. * @param hWnd * @param message * @param wParam * @param lParam * @return Zero if the event has been internally handled. */ static LRESULT CALLBACK gui_winProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { gui_Type *this = (gui_Type *) GetWindowLongPtr(hWnd, GWLP_USERDATA); gui_Event *e; switch (message) { case WM_MOUSEMOVE: this->pointer_x = LOWORD(lParam); this->pointer_y = HIWORD(lParam); break; case WM_LBUTTONDOWN: e = queueGetFreeEntry(this); e->code = gui_EVENT_LBUTTONDOWN; e->x = LOWORD(lParam); e->y = HIWORD(lParam); break; case WM_MBUTTONDOWN: e = queueGetFreeEntry(this); e->code = gui_EVENT_MBUTTONDOWN; e->x = LOWORD(lParam); e->y = HIWORD(lParam); break; case WM_RBUTTONDOWN: e = queueGetFreeEntry(this); e->code = gui_EVENT_RBUTTONDOWN; e->x = LOWORD(lParam); e->y = HIWORD(lParam); break; case WM_LBUTTONUP: e = queueGetFreeEntry(this); e->code = gui_EVENT_LBUTTONUP; e->x = LOWORD(lParam); e->y = HIWORD(lParam); break; case WM_MBUTTONUP: e = queueGetFreeEntry(this); e->code = gui_EVENT_MBUTTONUP; e->x = LOWORD(lParam); e->y = HIWORD(lParam); break; case WM_RBUTTONUP: e = queueGetFreeEntry(this); e->code = gui_EVENT_RBUTTONUP; e->x = LOWORD(lParam); e->y = HIWORD(lParam); break; case WM_KEYDOWN: if( VK_F1 <= wParam && wParam <= VK_F12 ){ e = queueGetFreeEntry(this); e->code = gui_EVENT_KEYDOWN; e->key = gui_KEY_F(wParam - VK_F1 + 1); return 0; } else { int i = 0; while(key_codes_map[i][0] != 0){ if( key_codes_map[i][0] == wParam ){ e = queueGetFreeEntry(this); e->code = gui_EVENT_KEYDOWN; e->key = key_codes_map[i][1]; return 0; } i++; } } return DefWindowProc(hWnd, message, wParam, lParam); break; case WM_SYSCOMMAND: // F10 requires special handling otherwise it blocks the events loop! if( wParam == SC_KEYMENU ){ e = queueGetFreeEntry(this); e->code = gui_EVENT_KEYDOWN; e->key = gui_KEY_F(10); } else { return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_CHAR: e = queueGetFreeEntry(this); e->code = gui_EVENT_KEYDOWN; e->key = wParam; break; /* case WM_WINDOWPOSCHANGED: { unsigned int flags = ((PWINDOWPOS) lParam)->flags; if ((flags & 0x8000) && (flags & SWP_NOCOPYBITS) && (flags & SWP_FRAMECHANGED)) { active = !(flags & SWP_NOACTIVATE); } if ((flags & 0x1000) && (flags & 0x0800) && (flags & SWP_NOMOVE) && (flags & SWP_NOSIZE)) { active = 1; } break; } */ case WM_ACTIVATE: e = queueGetFreeEntry(this); if( LOWORD(wParam) == 0 ){ e->code = gui_EVENT_WINDOW_FOCUS_OUT; this->has_focus = 0; } else { e->code = gui_EVENT_WINDOW_FOCUS_IN; this->has_focus = 1; } this->is_visible = ! HIWORD(wParam); break; case WM_PAINT: queueRemoveEvents(this, gui_EVENT_WINDOW_EXPOSE); e = queueGetFreeEntry(this); e->code = gui_EVENT_WINDOW_EXPOSE; // MUST handle the event otherwise it keeps generating WM_PAINT! return DefWindowProc(hWnd, message, wParam, lParam); case WM_SIZE: queueRemoveEvents(this, gui_EVENT_WINDOW_SIZE_CHANGE); e = queueGetFreeEntry(this); e->code = gui_EVENT_WINDOW_SIZE_CHANGE; e->x = this->width = LOWORD(lParam); e->y = this->height = HIWORD(lParam); break; case WM_DESTROY: e = queueGetFreeEntry(this); e->code = gui_EVENT_WINDOW_CLOSE; break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } static void gui_destruct(void *p) { gui_Type *this = (gui_Type *) p; // Dispose pen colors: int i; for(i = this->colors_number - 1; i >= 0; i--) DeleteObject(this->colors[i]); this->colors_number = 0; // Dispose window: ReleaseDC(this->hWnd, this->hdc); DestroyWindow(this->hWnd); } gui_Type * gui_new(char *title, int width, int height) { gui_Type * this; this = memory_allocate(sizeof(gui_Type), gui_destruct); this->showWindowInvoked = 0; this->is_visible = 0; this->has_focus = 0; this->width = width; this->height = height; this->pointer_x = 0; this->pointer_y = 0; this->has_focus = 0; this->queue_start = this->queue_end = 0; this->queue_full = 0; this->colors_number = 0; this->wcex.cbSize = sizeof (WNDCLASSEX); this->wcex.style = 0; this->wcex.lpfnWndProc = gui_winProc; this->wcex.cbClsExtra = 0; this->wcex.cbWndExtra = 0; this->wcex.hInstance = hInstance; this->wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION)); this->wcex.hCursor = LoadCursor(NULL, IDC_ARROW); this->wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); this->wcex.lpszMenuName = NULL; this->wcex.lpszClassName = szWindowClass; this->wcex.hIconSm = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION)); if (!RegisterClassEx(&this->wcex)) error_external("call to RegisterClassEx() failed"); this->hWnd = CreateWindow( szWindowClass, title, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, width, height, NULL, NULL, hInstance, NULL ); if (!this->hWnd) error_external("call to CreateWindow() failed"); // Let the window proc a way to retrieve "this": SetWindowLongPtr(this->hWnd, GWLP_USERDATA, (LONG_PTR) this); this->hdc = GetDC(this->hWnd); createCLUT(this); return this; } static int gui_allocateColor(gui_Type *this, int red, int green, int blue) { if( this->colors_number >= CLUT_LEN) error_internal("trying to allocate too many colors, %d maximum allowed", CLUT_LEN); if( (red&255)!=red || (green&255)!=green || (blue&255)!=blue ) error_internal("invalid RGB: %d,%d,%d", red, green, blue); HPEN color = CreatePen(PS_SOLID, 0 /* 0 = 1 pixel */, RGB(red, green, blue)); if (!color){ int err = WSAGetLastError(); error_internal("call to CreatePen() for CLUT entry no. %d failed: %s", this->colors_number, errorCodeToString(err)); } this->colors[this->colors_number] = color; return this->colors_number++; } void gui_getDisplayDimensions(gui_Type *this, gui_DisplayDimensions *d) { // FIXME: Win >= 8.1 has GetDpiForMonitor() that uses newer EIDI monitor // technology: try it once available under MinGW. // FIXME: BUG: this code gives 72x72 dpi for my screen, which is wrong // (actual is 117x122 dpi). d->widthPixels = GetDeviceCaps(this->hdc, HORZRES); d->widthMillimiters = GetDeviceCaps(this->hdc, HORZSIZE); d->heightPixels = GetDeviceCaps(this->hdc, VERTRES); d->heightMillimiters = GetDeviceCaps(this->hdc, VERTSIZE); } int gui_getEvent(gui_Type *this, gui_Event *e) { // If events queue contains something, return it immediately. if( ! queueIsEmpty(this) ){ *e = *getAvailableQueueEntry(this); return 1; } // First call to this event routine gives us the opportunity to initialize // and display the window. This also may trigger several calls to our window // procedure, but we are already prepared for that. if( ! this->showWindowInvoked ){ this->showWindowInvoked = 1; ShowWindow(this->hWnd, nCmdShow); UpdateWindow(this->hWnd); if( ! queueIsEmpty(this) ){ *e = *getAvailableQueueEntry(this); return 1; } } // Subsequent calls to this event routine require to first check if any // event is available to avoid blocking. Loop until we get at least one // meaningful event. // In some cases our window procedure gets called several times for a single // loop iteration, but this is not an issue because meaningful events are // added to the out events' queue. MSG msg; while( PeekMessage(&msg, this->hWnd, 0, 0, PM_REMOVE) ) { TranslateMessage(&msg); DispatchMessage(&msg); if( ! queueIsEmpty(this) ){ *e = *getAvailableQueueEntry(this); return 1; } } return 0; } void gui_getPointerPosition(gui_Type *this, int *x, int *y) { *x = this->pointer_x; *y = this->pointer_y; } int gui_getWidth(gui_Type *this) { /* RECT r; GetWindowRect(g->hWnd, &r); return r.right - r.left; */ return this->width; } int gui_getHeight(gui_Type *this) { /* RECT r; GetWindowRect(g->hWnd, &r); return r.bottom - r.top; */ return this->height; } int gui_hasFocus(gui_Type *this) { //return GetForegroundWindow() == this->hWnd; return this->has_focus; } int gui_isVisible(gui_Type *this) { // FIXME: IsWindowVisible() returns true also when minimized //return IsWindowVisible(this->hWnd); return this->is_visible; } void gui_drawLine(gui_Type *this, int x1, int y1, int x2, int y2, int color) { if( !(0 <= color && color < this->colors_number) ) error_internal("color index out of the range: %d", color); // Ensure ending point be drawn: if( x1 < x2 ) x2++; else if( x2 < x1 ) x1++; if( y1 < y2 ) y2++; else if( y2 < y1 ) y1++; else if( x1 == x2 ) x2++; SelectObject(this->hdc, this->colors[color]); MoveToEx(this->hdc, x1, y1, NULL); LineTo(this->hdc, x2, y2); } #else /* * IMPLEMENTATION SPECIFIC FOR X-WINDOW * ==================================== */ #include #include #include #include struct gui_Type { Display *dpy; Colormap cmap; Window win; GC gc; Atom protocolsAtom; Atom deleteWindowAtom; Atom closedownAtom; int has_focus; int is_visible; int width, height; // Current mouse pointer position in the content area. int pointer_x, pointer_y; // Index of the current foreground color set in the GC. -1 = no color set. int curr_color; // Number of allocated pen colors. int colors_number; // Allocated pen colors. unsigned long colors[CLUT_LEN]; }; static void gui_destruct(void *p) { gui_Type *this = (gui_Type *) p; // Dispose pen colors: /* int i; for(i = this->colors_number - 1; i >= 0; i--) DeleteObject(this->colors[i]); */ this->colors_number = 0; XDestroyWindow(this->dpy, this->win); // close window XCloseDisplay(this->dpy); // close connection } gui_Type * gui_new(char *title, int width, int height) { gui_Type * this; int useDefaultVisual = 1; char *display; XSizeHints xsh; XWMHints xwmh; Visual *theVisual; int depth; char *geomSpec = NULL; long win_attr_mask; XSetWindowAttributes window_attributes; Cursor cursor; Atom atom[2]; this = memory_allocate(sizeof(gui_Type), gui_destruct); this->has_focus = 0; this->is_visible = 0; this->pointer_x = 0; this->pointer_y = 0; this->curr_color = -1; display = getenv("DISPLAY"); this->dpy = XOpenDisplay(display); if (this->dpy == NULL) error_external("XOpenDisplay(\"%s\") failed", display); int screen = DefaultScreen(this->dpy); /* * If the player has specified that he want the default Visual, simply * give 'em that along with the default Colormap. */ if (useDefaultVisual) { theVisual = DefaultVisual(this->dpy, screen); this->cmap = DefaultColormap(this->dpy, screen); depth = DisplayPlanes(this->dpy, screen); } /* * Look for a visual; if we can't find one, * fall back to monochrome mode. */ else { error_internal("not implemented", 0); /* if ((theVisual = get_pseudo_visual(o->dpy, screen, &depth)) == NULL) { theVisual = DefaultVisual(o->dpy, screen); cmap = DefaultColormap(o->dpy, screen); depth = DefaultDepth(o->dpy, screen); } else { cmap = XCreateColormap(o->dpy, RootWindow(o->dpy, screen), theVisual, AllocNone); } */ } /* If the defaults database doesn't contain a specification of the initial size, set the size leaving to the window manager to set the position: */ char s[99]; sprintf(s, "%dx%d", width, height); geomSpec = s; if (geomSpec == NULL) { xsh.flags = /* PPosition | */ PSize; xsh.height = DisplayHeight(this->dpy, screen) * 3 / 4; xsh.width = DisplayWidth(this->dpy, screen) * 3 / 4; xsh.x = 0; /* ignored */ xsh.y = 0; /* ignored */ } else { int bitmask; memory_zero(&xsh); bitmask = XParseGeometry(geomSpec, &xsh.x, &xsh.y, (unsigned int *) &xsh.width, (unsigned int *) &xsh.height); if (bitmask & (XValue | YValue)) { xsh.flags |= USPosition; } if (bitmask & (WidthValue | HeightValue)) { xsh.flags |= USSize; } } width = xsh.width; height = xsh.height; /* * Create the Window with the information in the XSizeHints, the * border width, and the border & background pixels. */ win_attr_mask = CWColormap | CWBitGravity | CWBackPixel; window_attributes.colormap = this->cmap; window_attributes.bit_gravity = NorthWestGravity; window_attributes.background_pixel = BlackPixel(this->dpy, screen); this->win = XCreateWindow(this->dpy, RootWindow(this->dpy, screen), xsh.x, xsh.y, xsh.width, xsh.height, 0, depth, InputOutput, theVisual, win_attr_mask, &window_attributes); /* * Set the standard properties and hints for the window managers. */ XSetStandardProperties(this->dpy, this->win, title, title, None, NULL /* argv */, 0 /* argc */, &xsh); xwmh.flags = InputHint | StateHint; xwmh.input = True; xwmh.initial_state = NormalState; XSetWMHints(this->dpy, this->win, &xwmh); cursor = XCreateFontCursor(this->dpy, XC_tcross); XDefineCursor(this->dpy, this->win, cursor); /* * Tell the window manager that we'd like to participate in the * WM_CLOSEDOWN and WM_DELETE_WINDOW protocols. */ this->protocolsAtom = XInternAtom(this->dpy, "WM_PROTOCOLS", False); atom[0] = this->closedownAtom = XInternAtom(this->dpy, "WM_CLOSEDOWN", False); atom[1] = this->deleteWindowAtom = XInternAtom(this->dpy, "WM_DELETE_WINDOW", False); XSetWMProtocols(this->dpy, this->win, atom, 2); XSelectInput(this->dpy, this->win, KeyPressMask | ButtonPressMask | StructureNotifyMask | ButtonReleaseMask | ExposureMask | FocusChangeMask); XMapWindow(this->dpy, this->win); XSetWindowBackground(this->dpy, this->win, BlackPixel(this->dpy, screen)); XGCValues gcv; gcv.cap_style = CapButt; this->gc = XCreateGC(this->dpy, RootWindow(this->dpy, screen), GCCapStyle, &gcv); createCLUT(this); XFlush(this->dpy); return this; } static int gui_allocateColor(gui_Type *this, int red, int green, int blue) { if( this->colors_number >= CLUT_LEN) error_internal("trying to allocate too many colors, %d maximum allowed", CLUT_LEN); if( (red&255)!=red || (green&255)!=green || (blue&255)!=blue ) error_internal("invalid RGB: %d,%d,%d", red, green, blue); XColor color; color.red = (red << 8) + red; color.green = (green << 8) + green; color.blue = (blue << 8) + blue; if( ! XAllocColor(this->dpy, this->cmap, &color) ) error_internal("failed allocating RGB color %d,%d,%d", red, green, blue); this->colors[this->colors_number] = color.pixel; return this->colors_number++; } void gui_getDisplayDimensions(gui_Type *this, gui_DisplayDimensions *d) { d->widthPixels = DisplayWidth(this->dpy, DefaultScreen(this->dpy)); d->widthMillimiters = DisplayWidthMM(this->dpy, DefaultScreen(this->dpy)); d->heightPixels = DisplayHeight(this->dpy, DefaultScreen(this->dpy)); d->heightMillimiters = DisplayHeightMM(this->dpy, DefaultScreen(this->dpy)); } static int key_codes_map[][2] = { {XK_Insert, gui_KEY_INS}, {XK_Home, gui_KEY_HOME}, {XK_End, gui_KEY_END}, {XK_Prior, gui_KEY_PGUP}, {XK_Next, gui_KEY_PGDW}, {XK_Delete, gui_KEY_DEL}, {XK_Up, gui_KEY_UP}, {XK_Down, gui_KEY_DOWN}, {XK_Left, gui_KEY_LEFT}, {XK_Right, gui_KEY_RIGHT}, {XK_KP_Add, gui_KEY_PAD_PLUS}, {XK_KP_Subtract, gui_KEY_PAD_MINUS}, {XK_KP_Multiply, gui_KEY_PAD_TIMES}, {XK_KP_Divide, gui_KEY_PAD_DIVIDE}, {XK_KP_0, gui_KEY_PAD_0}, {XK_KP_1, gui_KEY_PAD_1}, {XK_KP_2, gui_KEY_PAD_2}, {XK_KP_3, gui_KEY_PAD_3}, {XK_KP_4, gui_KEY_PAD_4}, {XK_KP_5, gui_KEY_PAD_5}, {XK_KP_6, gui_KEY_PAD_6}, {XK_KP_7, gui_KEY_PAD_7}, {XK_KP_8, gui_KEY_PAD_8}, {XK_KP_9, gui_KEY_PAD_9}, {0, 0} }; int gui_getEvent(gui_Type *this, gui_Event *e) { XEvent ev; // If client is asking for events, certainly it has finished with drawings, // so it worths to flush the X Window commands queue: XFlush(this->dpy); // Loops until either a meaningful event to report is found or the queue // is empty: while(1){ if ( XCheckWindowEvent(this->dpy, this->win, -1L, &ev) ) { switch (ev.type) { case MappingNotify: XRefreshKeyboardMapping(&ev.xmapping); break; case KeyPress: { XKeyEvent *ke = (XKeyEvent *) &ev; KeySym keysym; XComposeStatus compose; char translated[9]; e->code = gui_EVENT_KEYDOWN; int len = XLookupString(ke, translated, sizeof(translated), &keysym, &compose); // Check function keys: if( XK_F1 <= keysym && keysym <= XK_F12 ){ e->key = gui_KEY_F(keysym - XK_F1 + 1); return 1; } // Check special keys: int i = 0; while(key_codes_map[i][0] != 0){ if( key_codes_map[i][0] == keysym ){ e->key = key_codes_map[i][1]; return 1; } i++; } // Checks ASCII: if( len == 1 && (translated[0]&127) == translated[0] ){ e->key = translated[0]; return 1; } } break; case ButtonPress: e->x = ev.xbutton.x; e->y = ev.xbutton.y; if (ev.xbutton.button == Button1) { e->code = gui_EVENT_LBUTTONDOWN; return 1; } else if (ev.xbutton.button == Button2) { e->code = gui_EVENT_MBUTTONDOWN; return 1; } else if (ev.xbutton.button == Button3) { e->code = gui_EVENT_RBUTTONDOWN; return 1; } break; case ButtonRelease: e->x = ev.xbutton.x; e->y = ev.xbutton.y; if (ev.xbutton.button == Button1) { e->code = gui_EVENT_LBUTTONUP; return 1; } else if (ev.xbutton.button == Button2) { e->code = gui_EVENT_MBUTTONUP; return 1; } else if (ev.xbutton.button == Button3) { e->code = gui_EVENT_RBUTTONUP; return 1; } break; case Expose: e->code = gui_EVENT_WINDOW_EXPOSE; return 1; case ConfigureNotify: e->code = gui_EVENT_WINDOW_SIZE_CHANGE; e->x = this->width = ev.xconfigure.width; e->y = this->height = ev.xconfigure.height; return 1; case FocusIn: this->has_focus = 1; e->code = gui_EVENT_WINDOW_FOCUS_IN; return 1; case FocusOut: this->has_focus = 0; e->code = gui_EVENT_WINDOW_FOCUS_OUT; return 1; case MapNotify: this->is_visible = 1; break; case UnmapNotify: this->is_visible = 0; break; default: break; } } else if( XCheckTypedEvent(this->dpy, ClientMessage, &ev) ) { if (ev.xclient.message_type == this->protocolsAtom && (ev.xclient.data.l[0] == this->deleteWindowAtom || ev.xclient.data.l[0] == this->closedownAtom) ){ e->code = gui_EVENT_WINDOW_CLOSE; return 1; } } else { // Events queue is empty. return 0; } } } void gui_getPointerPosition(gui_Type *this, int *x, int *y) { Window root, win; int root_x, root_y, win_x, win_y; unsigned int mask; if( XQueryPointer(this->dpy, this->win, &root, &win, &root_x, &root_y, &win_x, &win_y, &mask) && (0 <= win_x && win_x < this->width && 0 <= win_y && win_y < this->height) ){ this->pointer_x = win_x; this->pointer_y = win_y; } *x = this->pointer_x; *y = this->pointer_y; if( *x >= this->width ) *x = this->width - 1; if( *y >= this->height ) *y = this->height - 1; if( *x < 0 ) *x = 0; if( *y < 0 ) *y = 0; } int gui_getWidth(gui_Type *this) { return this->width; } int gui_getHeight(gui_Type *this) { return this->height; } int gui_hasFocus(gui_Type *this) { return this->has_focus; } int gui_isVisible(gui_Type *this) { return this->is_visible; } void gui_drawLine(gui_Type *this, int x1, int y1, int x2, int y2, int color) { if( !(0 <= color && color < this->colors_number) ) error_internal("color index out of the range: %d", color); if( color != this->curr_color ){ this->curr_color = color; XSetForeground(this->dpy, this->gc, this->colors[color]); } XDrawLine(this->dpy, this->win, this->gc, x1, y1, x2, y2); } #endif acm-6.0_20200416/src/util/hashtable.h0000644000000000000000000000737013166535036015462 0ustar rootroot/** * Collection of key/value pairs. Keys and values are generic pointer to client's * defined data types. For keys, an hash function must be provided to the * constructor and a key comparison function must be provided as well. * The hash table must be released with memory_dispose(); keys and values are * automatically released at that moment as well. * * @file * @author Umberto Salsi * @version $Date: 2017/10/08 23:51:58 $ */ #ifndef HASHTABLE_H #define HASHTABLE_H #ifdef hashtable_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * Key/value hash table, object of this module. */ typedef struct hashtable_Type hashtable_Type; /** * Prototype of the client's function that returns the hash given a key. */ typedef int (*hashtable_getKeyHash)(void *key); /** * Prototype of the client's function that compares two keys for equality. * This function must return true if the two keys are equal, false otherwise. */ typedef int (*hashtable_equalKeys)(void *key1, void *key2); /** * Returns a new, empty hash table. * @param getKeyHash Function that calculates the hash of a key. * @param equalKeys Function that compares two keys for equality. * @return New, empty hash table. Must be released with memory_dispose(); * all the key/value pairs are released along with the hash table. */ EXTERN hashtable_Type *hashtable_new( hashtable_getKeyHash getKeyHash, hashtable_equalKeys equalKeys); /** * Returns the number of key/value pairs in the table. * @param ht * @return Number of key/value pairs in the table. */ EXTERN int hashtable_length(hashtable_Type *ht); /** * Add a new key/value pair to the hash table. If key already present, replaces * the old value and the old value is released from memory. * @param ht * @param key * @param value */ EXTERN void hashtable_put(hashtable_Type *ht, void *key, void *value); /** * Returns the value corresponding to the given key. * @param ht * @param key * @return Value corresponding to the given key, or NULL if not found. */ EXTERN void *hashtable_get(hashtable_Type *ht, void *key); /** * Removes and releases from memory a key/value pair given the key. * Does nothing if not found. * @param ht * @param key */ EXTERN void hashtable_remove(hashtable_Type *ht, void *key); /** * Returns a key from which to start a sequential scanning of all the keys. * Next keys can be retrieved invoking hashtable_nextKey(). * The returned key can be used to retrieve the value, change the value and to * remove the associated key/pair. * @param ht * @return First key, or NULL if the hash table is empty. */ EXTERN void *hashtable_firstKey(hashtable_Type *ht); /** * Returns the next key for sequential scanning. * The returned key can be used to retrieve the value, change the value and to * remove the associated key/pair. * @param ht * @return Next key, or NULL if the hash table is empty. A NULL value may be * returned if some new kay/value pair has been added. */ EXTERN void *hashtable_nextKey(hashtable_Type *ht); /** * Proposed generic hash function for a block of bytes. * @param buf Pointer to a block of data. * @param buf_len Number of bytes, non negative. * @return Hash value. */ EXTERN int hashtable_getHashOfMem(void *buf, int buf_len); /** * Proposed generic hash function for NUL-terminates string. * @param s NUL-terminates string. * @return Hash value. */ EXTERN int hashtable_getHashOfString(void *s); /** * Proposed generic comparison function for NUL-terminated strings. * This implementation merely returns strcmp(a,b) == 0. * @param a A string. * @param b Another string. * @return True if the two strings are equal. */ EXTERN int hashtable_equalStrings(void *a, void *b); EXTERN void hashtable_report(hashtable_Type *ht); #undef EXTERN #endif acm-6.0_20200416/src/util/memory.c0000644000000000000000000001674713173131501015025 0ustar rootroot#include #include #include #include #include #include #include "error.h" #define memory_IMPORT #include "memory.h" #define MAGIC 987654321 /** * Double linked list of allocated blocks. This is the header prepended to each * user's allocated block. */ typedef struct Block { /** Previous block. */ struct Block *prev; /** Next block. */ struct Block *next; /** Size of the users' data this block header precedes. */ int size; /** Name of the source C file where this block was allocated. */ char *file; /** Line number in the source C file where this block was allocated. */ int line; /** User's defined destructor function. */ void (*destructor)(void *data); /** Magic number for memory corruption detection. */ int magic; } Block; /** * First block of the doubly linked list of allocated blocks. Well, actually * this block is the last allocated... */ static Block *firstBlock = NULL; /** * List of registered cleanup functions. */ typedef struct _CleanupEntry { /** Next registered cleanup function. */ struct _CleanupEntry *next; /** Registered cleanup function. */ void (*cleanup)(); } CleanupEntry; /** * First cleanup function of the list (that is, the last registered function). */ static CleanupEntry *firstCleanup = NULL; #define ERASE_LEADING_LEN 1000 void * memory_allocate_PRIVATE(char *file, int line, int size, void (*destructor)(void *data)) { Block *b; assert(size >= 0); b = malloc(sizeof(Block) + size); if( b == NULL ) error_internal_PRIVATE(file, line, "out of memory from malloc(%d)", size); b->next = firstBlock; b->prev = NULL; b->size = size; b->file = file; b->line = line; b->destructor = destructor; b->magic = MAGIC; if( firstBlock != NULL ) firstBlock->prev = b; firstBlock = b; if( size > 0 ) memset(b + 1, 0, size <= ERASE_LEADING_LEN? size : ERASE_LEADING_LEN); return b + 1; } static Block * getBlock(void *p) { Block *b; b = (Block *) p - 1; if( b->magic != MAGIC ) error_internal("memory corruption detected: not a block allocated by this module", 0); return b; } static void destructorRecursionDetector(void *data) { Block *b; b = getBlock(data); error_internal("recursion in destructor detected while releasing block allocated in %s:%d", b->file, b->line); } void memory_dispose(void * p) { Block *b; void (*destructor)(void *data); if( p == NULL ) return; b = getBlock(p); if( b->destructor != NULL ){ destructor = b->destructor; b->destructor = destructorRecursionDetector; destructor(p); } if( b->size > 0 ) memset(p, 0, b->size <= ERASE_LEADING_LEN? b->size : ERASE_LEADING_LEN); if( b == firstBlock ){ firstBlock = b->next; if( firstBlock != NULL ) firstBlock->prev = NULL; } else { b->prev->next = b->next; if( b->next != NULL ) b->next->prev = b->prev; } memset(b, 0, sizeof(Block)); free(b); } void * memory_realloc_PRIVATE(char *file, int line, void * p, int size) { Block *bold, *bnew; if( p == NULL ) return memory_allocate_PRIVATE(file, line, size, NULL); assert( size >= 0 ); bold = getBlock(p); if( bold->destructor != NULL ) error_internal_PRIVATE(file, line, "resizing block having destructor allocated in %s is not supported", bold->file); bold->magic = 0; bnew = realloc(bold, sizeof(Block) + size); if( bnew == NULL ) error_internal_PRIVATE(file, line, "out of memory from realloc(...,%d)", sizeof(Block) + size); if( bnew != bold ){ if( firstBlock == bold ) firstBlock = bnew; if( bnew->prev != NULL ) bnew->prev->next = bnew; if( bnew->next != NULL ) bnew->next->prev = bnew; } bnew->magic = MAGIC; bnew->size = size; return bnew + 1; } void memory_strcpy(char *dst, int dst_capacity, char *src) { assert(dst_capacity >= 1); char *dst_end = dst + dst_capacity - 1; while( dst < dst_end && *src != 0 ){ *dst = *src; dst++; src++; } *dst = 0; } char * memory_strdup(char * s) { int len; char * p; len = strlen(s)+1; p = memory_allocate(len, NULL); memcpy(p, s, len); return p; } int memory_startsWith(char * s, char * head) { while( *head != 0 && *head == *s ){ head++; s++; } return *head == 0; } int memory_startsWithIgnoreCase(char * s, char * tag) { while( (*tag!=0) && (toupper(*tag)==toupper(*s)) ){ tag++; s++; }; return *tag==0; } int memory_endsWith(char * s, char * tail) { int slen, taillen; slen = strlen(s); taillen = strlen(tail); if( slen < taillen ) return 0; s = s + slen - taillen; while( *s != 0 ){ if( *s != *tail ) return 0; s++; tail++; } return 1; } char * memory_indexOfMem(char *s, int slen, char *target, int targetlen) { char *end; if( slen < 0 || targetlen < 0 ) error_internal("memory_indexOfMem: slen=%d, taillen=%d", slen, targetlen); if( targetlen <= 0 ) return s; if( slen <= 0 || slen < targetlen ) return NULL; /* Now 1 <= targetlen <= slen. */ if( targetlen == 1 ) return memchr(s, *target, slen); /* Search stops when s goes beyond this limit: */ end = s + slen - targetlen; while(s <= end){ if( *s == *target ){ if( memcmp(s, target, targetlen) == 0 ) return s; } s++; } return NULL; } int memory_indexOfStringIgnoreCase(char * str, char * word) { int i, a; i=0; a = toupper(*word); while(*str!=0){ if((toupper(*str)==a) && (memory_startsWithIgnoreCase(str, word))) return i; str++; i++; } return -1; } char * memory_getEnvKey(char * name, char * default_value) { char * k; k = getenv(name); if( k != NULL ) return k; else if( default_value != NULL ) return default_value; else error_external("missing mandatory environmental variable `%s'", name); return NULL; /* avoid gcc -Wall flow control complains */ } char *memory_format(char *fmt, ...) { /* FIXME: allowed 4 recursion levels: should be enough, but... */ va_list ap; static int idx = 0; static char buf[4][1000]; idx = (idx + 1) % 4; va_start(ap, fmt); vsnprintf(buf[idx], 1000, fmt, ap); va_end(ap); return buf[idx]; } void memory_registerCleanup(void (*cleanup)()) { CleanupEntry *c; c = firstCleanup; while(c != NULL){ if( c->cleanup == cleanup ) return; /* already registered */ c = c->next; } c = memory_allocate(sizeof(CleanupEntry), NULL); c->cleanup = cleanup; c->next = firstCleanup; firstCleanup = c; } static void memory_cleanupAll() { CleanupEntry *c; while(firstCleanup != NULL){ c = firstCleanup; firstCleanup = c->next; c->cleanup(); memory_dispose(c); } } #define MAX_REPORT_LEAKS 100 int memory_report() { Block *b; int i, j, len, c, n, tot_size; char *bytes; memory_cleanupAll(); if( firstBlock == NULL ) return 0; fprintf(stderr, "%s, memory_report() leaks detection, first %d listed:\n\n", error_prog_name, MAX_REPORT_LEAKS); b = firstBlock; i = 0; fprintf(stderr, "no. magic size content file:line\n"); fprintf(stderr, "--- ----- ------ -------------------- --------------\n"); while( b != NULL && i < MAX_REPORT_LEAKS ){ i++; fprintf(stderr, "%3d %5s %6d ", i, (b->magic == MAGIC)? "ok":"BAD", b->size); len = b->size; if( len > 20 ) len = 20; bytes = (char *) (b + 1); for(j = 0; j < len; j++){ c = bytes[j] & 255; if( !(32 <= c && c <= 126) ) c = '.'; fprintf(stderr, "%c", c); } for(; j <= 20; j++) fprintf(stderr, " "); fprintf(stderr, " %s:%d\n", b->file, b->line); b = b->next; } n = 0; tot_size = 0; b = firstBlock; while(b != NULL){ n++; tot_size += b->size; b = b->next; } fprintf(stderr, "%d total blocks, %d bytes wasted.\n", n, tot_size); return 1; }acm-6.0_20200416/src/util/sparsearray.c0000644000000000000000000001522513141045302016035 0ustar rootroot/** * IMPLEMENTATION NOTES. * * The sparse array here implemented is basically an hash table where the hash * is the index associated to each stored element. * * To evaluate the performances of the hash table, several indicators can are * calculated. * * The hash table contains N slots, each slot points to a * concatenated list of s(i) elements with i=1,...,N. The total number of * elements in the table is then * * sisum = sum s(i) with i=1,...,N * * The max slot length is * * maxsi = max( s(i) with i=1,...,N ) * * The number of used slots is the number of slots containing at least one element: * * used = no. of slots for which s(i) >= 1 * * The average slot length calculated over the used slots is * * avg = sisum / used * * The variance of the slot length calculated over the used slots is * * var = ( sum (s(i) - avg)^2 ) / used i= over the s(i)>=1 only * = ( sum s(i)^2 )/used - avg^2 i= over all the slots * * Here we define the quality factor Q as the average number of comparisons * needed to find the elements of the hash table, assuming all the elements * to find are in the hash table and have the same probability. The number of * comparisons to find back the s(i) elements in the i-th slot of the hash table * is given by the well known Gauss formula * * s(i)*(s(i) + 1)/2 * * The total number of comparisons to find all the elements of the hash * table is the sum of this expression over all the entries of the hash table: * * totalcmp = sum s(i)*(s(i)+1)/2 for i=1,...,N * * Since sum s(i) is the total number of elements, the mean number of * comparisons is the ratio between the total number of comparisons and the * total number of elements: * * Q = totalcmp / sum s(i) = (sum s(i)^2 / sum s(i) + 1)/2 * * This number is then a good indicator of the hash table quality. * The minimum value is Q=1 when s(i) are all either 0 or 1. * The maximum value is Q=(sum s(i) + 1)/2 when all the elements fall into * a single slot of the hash table and the search degenerates into a sequential * search. A value of, say, Q=1.2 means that for a uniform distribution of * elements to search there will be an average of 1.2 comparisons to find the * given entry in the hash table. */ #include #include #include #include #include "memory.h" #define sparsearray_IMPORT #include "sparsearray.h" #undef sparsearray_IMPORT typedef struct _Slot { struct _Slot * next; int index; void * entry; } Slot; struct sparsearray_Type { /** If elements must not be released. */ int keep_elements; /** Length of the hash table, each entry containing a list of slots. */ int size; /** Array of pointer to list of slots. Each list of slots collect elements * whose hashes (calculated from the index) collide. */ Slot ** slots; }; static void sparsearray_destruct(void *p) { sparsearray_Type * sa = (sparsearray_Type *) p; int i; Slot *s, *snext; if( sa == NULL ) return; for(i = sa->size-1; i >= 0; i--){ s = sa->slots[i]; while(s != NULL){ if( ! sa->keep_elements ) memory_dispose(s->entry); snext = s->next; memory_dispose(s); s = snext; } } memory_dispose(sa->slots); } sparsearray_Type * sparsearray_new(int size, int keep_elements) { sparsearray_Type * sa; int p; /* * Sizes the table to the smallest power of two minus 1 not less that the * expected number of elements to store. Experimentally this give to me the * smallest values of the mean number of comparisons (Q) for the purposes * of this application. */ p = 3; while(p < size) p = (p << 1) + 1; size = p; sa = memory_allocate(sizeof(sparsearray_Type), sparsearray_destruct); sa->keep_elements = keep_elements; sa->size = size; sa->slots = memory_allocate(size * sizeof(Slot *), NULL); memset(sa->slots, 0, size * sizeof(Slot *)); return sa; } /** * Calculates the index to the slots array given the index of the element. * @param sa Involved sparse array. * @param index Client's provided index of the element. * @return Index to the slots array. */ static int getIndexHash(sparsearray_Type *sa, int index) { return ((index >= 0)? index : - index - 1) % sa->size; } /** * Retrieves a slot given the index and the corresponding calculated hash. * @param sa Involved sparse array. * @param index Client's provided index of the element. * @param hash Hash calculated from the index. * @return Found slot corresponding to the element at the given index, or NULL * if not found. */ static Slot * getSlot(sparsearray_Type * sa, int index, int hash) { Slot *s; s = sa->slots[hash]; while( s != NULL ){ if( s->index == index ) return s; s = s->next; } return NULL; } void sparsearray_set(sparsearray_Type *sa, int index, void *entry) { int hash; Slot *s; hash = getIndexHash(sa, index); s = getSlot(sa, index, hash); if( s != NULL ){ if( ! sa->keep_elements ) memory_dispose(s->entry); s->entry = entry; return; } s = memory_allocate(sizeof(Slot), NULL); s->next = sa->slots[hash]; s->index = index; s->entry = entry; sa->slots[hash] = s; } void * sparsearray_get(sparsearray_Type * sa, int index) { Slot *s; s = getSlot(sa, index, getIndexHash(sa, index)); if( s == NULL ) return NULL; else return s->entry; } double sparsearray_getAverageComparisonsPerSearch(sparsearray_Type *sa) { int i, si, simax, sisum, used; double si2sum; Slot *s; simax = 0; sisum = 0; si2sum = 0.0; used = 0; for(i = sa->size-1; i >= 0; i--){ s = sa->slots[i]; if( s != NULL ) used++; si = 0; while(s != NULL){ si++; s = s->next; } if( si > simax ) simax = si; sisum += si; si2sum += si*si; } return 0.5*(si2sum/sisum + 1.0); } void sparsearray_report(sparsearray_Type *sa, char * title) { int i, si, simax, sisum, used; double si2sum, avg, var, Q; Slot *s; printf("Sparse array report about %s:\n", title); simax = 0; sisum = 0; si2sum = 0.0; used = 0; for(i = sa->size-1; i >= 0; i--){ s = sa->slots[i]; if( s != NULL ) used++; si = 0; while(s != NULL){ si++; s = s->next; } if( si > simax ) simax = si; sisum += si; si2sum += si*si; } avg = (double) sisum / used; /* mean length of occupied slots */ var = si2sum / used - avg*avg; /* variance of the occupied slot length */ Q = 0.5*(si2sum/sisum + 1.0); /* mean no. of comparisons per search */ printf(" %d total table length\n", sa->size); printf(" %d occupied table entries\n", used); printf(" %d max table entry length\n", simax); printf(" %g average table entry length\n", avg); printf(" %g variance table entry length\n", var); printf(" %g mean no. of comparisons per search\n", Q); }acm-6.0_20200416/src/util/wav.h0000644000000000000000000000253113153616656014322 0ustar rootroot/** * WAV file reader. * @file * @author Umberto Salsi * @version $Date: 2017/09/05 21:57:02 $ */ #ifndef WAV_H #define WAV_H #include #ifdef wav_IMPORT #define EXTERN #else #define EXTERN extern #endif typedef struct { /** Copy of the file name from which the WAV has been read. */ char *filename; /** WAV format tag, normally 1 (PCM). */ uint16_t wFormatTag; /** Number of channels (one or more). */ uint16_t nChannels; /** Number of samples per seconds. */ uint32_t nSamplesPerSec; /** ? */ uint32_t nAvgBytesPerSec; /** Block size for each sample (bytes). */ uint16_t nBlockAlign; /** Number of bits per sample. Its value is less or equal to 8*nBlockAlign. */ uint16_t wBitsPerSample; /** Frame length in bytes. Its value is exactly nChannels times nBlockAlign. * Each frame contains a sample for each channel, in the order. */ uint32_t frameLength; /** Length of the sampled data (bytes). It is a multiple of the frame length. */ uint32_t data_len; /** Samples data. The byte ordering of the samples is little-endian. */ char *data; } wav_Type; /** * Reads WAV file. Any error accessing the file is fatal. Any inconsistency in * the file contents is fatal. * @return WAV contents. Must be released with memory_dispose(). */ EXTERN wav_Type * wav_fromFile(char *filename); #undef EXTERN #endif acm-6.0_20200416/src/util/zulu.c0000644000000000000000000001661213326036423014512 0ustar rootroot#include #include #include #include #include #include "error.h" #define zulu_IMPORT #include "zulu.h" static int days_per_month[2][12] = { {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} }; int zulu_isLeapYear(int year) { return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0); } static int zulu_secondsPerYear(int year) { return zulu_isLeapYear(year)? 86400 * 366 : 86400 * 365; } void zulu_timestampToDate(int ts, zulu_Date *d) { int year = 1970; while(ts < 0){ year--; ts += zulu_secondsPerYear(year); } do { int seconds_per_year = zulu_secondsPerYear(year); if( ts < seconds_per_year ) break; ts -= seconds_per_year; year++; } while(1); d->year = year; int month = 0; int leap_year_idx = zulu_isLeapYear(year)? 1 : 0; do { int seconds_per_month = 86400 * days_per_month[leap_year_idx][month]; if( ts < seconds_per_month ) break; ts -= seconds_per_month; month++; } while(1); d->month = month + 1; d->day = ts / 86400 + 1; ts -= 86400 * (d->day-1); d->hour = ts / 3600; ts -= 3600 * d->hour; d->minutes = ts / 60; ts -= 60 * d->minutes; d->seconds = ts; } double zulu_timestampToYear(int ts) { int year = 1970; int seconds_per_year = zulu_secondsPerYear(year); while(ts < 0){ year--; seconds_per_year = zulu_secondsPerYear(year); ts += seconds_per_year; } while(ts >= seconds_per_year){ ts -= seconds_per_year; year++; seconds_per_year = zulu_secondsPerYear(year); } return year + (double) ts / seconds_per_year; } int zulu_dateToTimestamp(zulu_Date *d) { int ts = 0; int year = 1970; while(d->year < year){ year--; ts -= zulu_secondsPerYear(year); // Check underflow. With 32-bits it underflows at around 1901-12-13: // if this happen just for that year, we ignore this here and will check // the sign of the final result next so that the latest days of the 1901 // are supported as well to cover the whole int range. Nice! if( ts > 0 && year != 1901 ) error_internal("timestamp underflow for year %d", d->year); } while(year < d->year){ ts += zulu_secondsPerYear(year); if( ts <= 0 ) error_internal("timestamp overflow for year %d", d->year); year++; } int leap_year_idx = zulu_isLeapYear(year)? 1 : 0; // Increments ts by previous months [1,d->month-1]: if( !(1 <= d->month && d->month <= 12) ) error_internal("month out of the allowed range: %d", d->month); int month = 1; while(month < d->month){ ts += 86400 * days_per_month[leap_year_idx][month-1]; month++; } // Increments ts by days, hours, minutes and seconds: if( !(1 <= d->day && d->day <= days_per_month[leap_year_idx][d->month-1]) ) error_internal("day out of the allowed range: %d-%02d-%02d", d->day); if( !(0 <= d->hour && d->hour <= 23 && 0 <= d->minutes && d->minutes <= 59 && 0 <= d->seconds && d->seconds <= 59) ) error_internal("invalid time: %02d:%02d:%02d", d->hour, d->minutes, d->seconds); ts += 86400 * (d->day-1) + 3600 * d->hour + 60 * d->minutes + d->seconds; if( ts < 0 && year > 1970 ) error_internal("timestamp overflow for year %d", year); // This may happen only with 32-bits int at year 1901 as explained above: if( ts >= 0 && year < 1970 ) error_internal("timestamp underflow for year %d", year); return ts; } double zulu_dateToYear(zulu_Date *d) { zulu_Date d2 = *d; if( zulu_isLeapYear(d2.year) ) d2.year = 1972; else d2.year = 1970; return zulu_timestampToYear(zulu_dateToTimestamp(&d2)) - d2.year + d->year; } int zulu_yearToTimestamp(double year) { if( !(INT_MIN <= year && year <= INT_MAX) ) error_internal("year overflows int capacity: %g", year); int year_i = (int) year; int ts = 0; int base_year = 1970; while(base_year > year_i){ base_year--; ts -= zulu_secondsPerYear(base_year); // Check underflow. With 32-bits it underflows at around 1901-12-13: // if this happen just for that year, we ignore this here and will check // the sign of the final result next so that the latest days of the 1901 // are supported as well to cover the whole int range. Nice! if( ts > 0 && year_i != 1901 ) error_internal("timestamp underflow for year %g", year); } while(base_year < year_i){ ts += zulu_secondsPerYear(base_year); base_year++; if( ts < 0 ) error_internal("timestamp overflow for year %g", year); } int seconds_per_year = zulu_secondsPerYear(year_i); // The "(int)" cast below is required to prevent gcc rounding instead of // trunk when ts < 0! ts += (int) ((year - year_i) * seconds_per_year + 0.5); if( ts < 0 && year_i >= 1970 ) error_internal("timestamp overflow for year %g", year); // This may happen only with 32-bits int at year 1901 as explained above: if( ts >= 0 && year_i < 1970 ) error_internal("timestamp underflow for year %g", year); return ts; } void zulu_yearToDate(double year, zulu_Date *d) { if( !(INT_MIN <= year && year <= INT_MAX) ) error_internal("year out of the range: %g", year); int year_i = (int) year; if( zulu_isLeapYear(year_i) ) // Set month, day, h:m:s for (any) leap year - adjust year next. zulu_timestampToDate(zulu_yearToTimestamp(year - year_i + 1972), d); else // Set month, day, h:m:s for (any) non leap year - adjust year next. zulu_timestampToDate(zulu_yearToTimestamp(year - year_i + 1970), d); // Set year. d->year = year_i; } static int zulu_scanDigits(char **s, int n, int *res) { *res = 0; while( n > 0 && isdigit(**s) ){ *res = 10 * *res + **s - '0'; (*s)++; n--; } return n == 0; } int zulu_dateParse(char *s, zulu_Date *z) { if( s == NULL ) return 0; int n = 0, year, month, day = 1, hour = 0, minutes = 0, seconds = 0; if( ! zulu_scanDigits(&s, 4, &year) ) return 0; if( *s != '-' ) return 0; s++; if( ! zulu_scanDigits(&s, 2, &month) ) return 0; n = 2; if( *s == '-' ){ s++; if( ! zulu_scanDigits(&s, 2, &day) ) return 0; n++; if( *s == 'T' ){ s++; if( ! zulu_scanDigits(&s, 2, &hour) ) return 0; if( *s != ':' ) return 0; s++; if( ! zulu_scanDigits(&s, 2, &minutes) ) return 0; n += 2; if( *s == ':' ){ s++; if( ! zulu_scanDigits(&s, 2, &seconds) ) return 0; n++; } } } if( *s != 0 ) return 0; if( !( 1583 <= year && year <= 9999 && 1 <= month && month <= 12 && 1 <= day && day <= 31 && day <= days_per_month[zulu_isLeapYear(year)? 1 : 0][month-1] ) ) return 0; z->year = year; z->month = month; z->day = day; z->hour = hour; z->minutes = minutes; z->seconds = seconds; return n; } void zulu_dateFormat(zulu_Date *d, char *s, int s_capacity) { if( s_capacity >= 20 ) snprintf(s, s_capacity, "%04d-%02d-%02dT%02d:%02d:%02d", d->year, d->month, d->day, d->hour, d->minutes, d->seconds); else if( s_capacity >= 17 ) snprintf(s, s_capacity, "%04d-%02d-%02dT%02d:%02d", d->year, d->month, d->day, d->hour, d->minutes); else if( s_capacity >= 11 ) snprintf(s, s_capacity, "%04d-%02d-%02d", d->year, d->month, d->day); else if( s_capacity >= 8 ) snprintf(s, s_capacity, "%04d-%02d", d->year, d->month); else error_internal("destination string buffer too small: %d", s_capacity); } int zulu_dateCompare(zulu_Date *a, zulu_Date *b) { int r; if( (r = a->year - b->year ) ) return r; if( (r = a->month - b->month ) ) return r; if( (r = a->day - b->day ) ) return r; if( (r = a->hour - b->hour ) ) return r; if( (r = a->minutes - b->minutes) ) return r; if( (r = a->seconds - b->seconds) ) return r; return 0; }acm-6.0_20200416/objects/0000755000000000000000000000000013175511255013231 5ustar rootrootacm-6.0_20200416/objects/hints.txt0000644000000000000000000000406513175034646015130 0ustar rootroot# Hints shown to the user, periodically, randomly, one line at a time, and only # while the plane is flying level. # Empty lines an lines starting with '#' are not shown. Hint: to exit the program press SHIFT-Q SHIFT-Q Hint: to leave the window in background, press 'd' Hint: check for updates at www.icosaedro.it/acm/download.html Hint: press SHIFT-H to switch between HUD and classic instruments Hint: press 'r' to show HSI, ADF and radar Hint: one nautical mile corresponds to about 2 Km Hint: knots is a speed unit corresponding to one nautical mile per hour Hint: one feet is about one third of a meter Hint: never exceed the maximum vertical load of the aircraft you are flying on! Hint: your plane lacks the speed brakes? use the flaps instead! Hint: press < or > to turn at standard rate of 3 DEG/s then press / or | to release Hint: press , or . to turn at 1.5 DEG/s then press / or | to release Hist: hold heading with | and release with / Hint: never exceed 25 DEG angle of bank for best passengers comfort! Hint: need a GPS? press SHIFT-D Hint: don't forget to enable the rudder/aileron coordinator (SHIFT-X) Hint: engine control keys: 1 (idle) 2 (decrease) 3 (increase) 4 (max) Hint: to hold the current speed enable the auto-throttle (SHIFT-T) Hint: to start/stop/reset the timer press 't' Hint: to retract/deploy the landing gear press 'g' Hint: to deploy the flaps press 'h' one or more times, retract with 'y' Hint: to hold the current altitude, press SHIFT-Z Hint: to hold the current climb rate press SHIFT-A Hint: release the auto-pilot system with the Home key Hint: select NAVAID frequency with 9 0, rotate the OBS pointer with 7 8 Hint: select RNAV waypoint with F3 F4 F5 F6 Hint: look around you: press NumLock then the arrows of the numeric keypad Hint: switch between NAV/RNAV HSI receivers with SPACE Hint: follow the VOR radial with the auto-navigator (SHIFT-N) Hint: follow the ILS landing path with the auto-landing (SHIFT-L) Hint: ACM comes with a good manual: read it carefully! Hint: set the zoom factor with + and - Hist: try flying in rate control mode with SHIFT-Eacm-6.0_20200416/objects/aircraft/0000755000000000000000000000000013175511063015021 5ustar rootrootacm-6.0_20200416/objects/aircraft/su30.txt0000644000000000000000000001511413153305524016355 0ustar rootrootaircraft "Su-30" { Object "su30.obv" Description "Sukhoi Su-30 Multi-Role Fighter" DISEntityType 1:2:222:2:9:0:0 # used Su-37 enumeration DISAltEntityType 1:2:225:1:3:3:0 WingArea 668.0 # (wingS) Wing surface area (ft^2) WingHalfSpan 24 # (wings) Wing half-span (ft) WingHeight 0.0 # (wingh) Height of the wing aerodyn. center above CM (ft) Chord 16 # (c) Mean geometric chord of wing (ft) AspectRatio 3.48 # (aspectRatio) aspect ratio EmptyWeight 32000 #(emptyWeight) Empty weight (well, actually mass) (lb) # Max. wing load: MaxLoadZPositive 339000 # 8*(EmptyWeight + 0.5*MaxFuel) (+8 g) MaxLoadZNegative 127000 # 3*(EmptyWeight + 0.5*MaxFuel) (-3 g) # (I(x,y,z)) Moments of inertia (lb ft^2) # FIXME. These are simply the moments of the F-16 multiplied by 3.5. # Since the Su-30 empty weight is 2 times the F-16, and supposing # the same geometric distribution of masses, moments are proportional # to emptyWeight^(5/3) and this gives the 3.5 factor. [U.S.] Ixx 25000 Iyy 175000 Izz 191000 # (cFlap) Lift due to flaps (yields Clift of 1.0 at max extension) CFlap 0.64279 BetaStall 15.0 # (deg) CFlapDrag 0.0467 # (cFlapDrag) Drag due to Flaps CGearDrag 0.03 # (cGearDrag) Drag due to Gear CSpeedBrake 0.03 # (cSpeedBrake) Drag due to Speed Brake # at 90 degrees # (CDb) Drag Characteristic equation [Wave+body] # independent variable is mach number CDb { # (CDb) Drag Characteristic equation [Wave+body] # independent variable is mach number 0.0, 0.020, 0.2, 0.020, 0.95, 0.015, 1.05, 0.045, 2.00, 0.030, 10.0, 0.030 } CLift { # (CLift) Lift-slope curve (vs alpha) -3.0, 0.0, -1.05, 0.0, -0.576, -2.199, -0.556, -2.23, -0.524, -2.199, 0.524, 2.199, 0.556, 2.23, 0.576, 2.199, 1.05, 0.0, 2.0, 0.0 } CnBeta { # (CnBeta) Yaw due to sideslip equation 0, -0.08125, 0.523540, -0.078125, 0.785340, -0.0609375, 1.047198, 0.125, 1.58, 0.0 } ClBeta { # (ClBeta) Roll due to sideslip equation 0, -0.0125, 0.43633, -0.015, 0.78540, 0.125, 1.58, 0.0, 3.142, 0.125, } CDBOrigin 0 # (CDBOrigin, CDBFactor) Drag due to sideslip CDBFactor 0.5 CDBPhase 0 # (CDBPhase) sideslip drag phase (deg) CYBeta -1.4 # (CYbeta) Side-force from side-slip [dCY/dBeta] EffElevator 0.60 # (effElevator) Elevator effectiveness EffRudder 0.10 # (effRudder) Rudder effectiveness MaxRudder 20 # (maxRudder) max Rudder (deg) MaxAileron 20 # (maxAileron) max Aileron (deg) MaxFlap 20 # (maxFlap) max flap setting (deg) # (flapRate) flap extension rate (about 2 secs to fully extend flaps) FlapRate 10 # (deg/sec) # (gearRate) gear extension rate (about 3 secs to fully extend gear) GearRate 30 # (deg/sec) MaxSpeedBrake 80 # (maxSpeedBrake) max Speed Brake setting (deg) # (speedBrakeRate) rate of speed brake extension (2 secs to full ext) SpeedBrakeRate 40 # (deg/sec) # (speedBrakeIncr) speed Brake increment per keystroke SpeedBrakeIncr 80 # (deg) Clda 0.048 # (Clda) roll moment from aileron offset Cldr 0.004 # (Cldr) roll moment from rudder offset Clp -0.27 # (Clp) roll damping Cmq -8.0 # (Cmq) pitch damping factor Cnr -0.378 # (Cnr) yaw damping factor CmAlpha -0.40 # (cmSlope) CmAlpha curve slope MaxFuel 20700 # (maxFuel) maximum internal fuel (lb) EngineType "GenericJetEngine" # engine lag factor (how fast does it respond to throttle changes) EngineLag -3.0 # Engine data based on updated RD-33K engines cited in [AirI Aug89]. # (maxThrust) max static thrust, military power (lbf) MaxThrust 17600 # (maxABThrust) max static thrust, afterburner on (lbf) MaxABThrust 55000 Thrust { # (Thrust) Mach Number vs. thrust 0, 1, 1.7, 1.5, 2.0, 0.84, 5, 0.5 } ABThrust { # (ABThrust) afterburner thrust table 0, 1, 0.5, 1, 1, 1.21, 1.7, 1.7, 5, 1.64 } HasThrustReverser 0 # (hasThrustReverser) 0=no, otherwise yes # (spFuelConsump) specific fuel consump(lb fuel/lb T x hr) SpFuelConsump 0.7 # (spABFuelConsump) AB specific fuel consump(lb fuel/lb T x hr) SpABFuelConsump 2.5 # (viewPoint) pilot's viewing location wrt CM ViewPoint { 34, 0, -8.9 } # Landing Gear control parameters MuStatic 0.08 # (muStatic) static coeff of friction no-brakes MuKinetic 0.05 # (muKinetic) moving coeff of friction no-brakes MuBStatic 0.7 # (muBStatic) static brakes-on MuBKinetic 0.6 # (muBKinetic) moving brakes-on MaxNWDef 72 # (maxNWDef) maximum nosewheel deflection (deg) # (rm) location of right main gear attachments Rm { -2.2, 8, 8.9 } # (rn) location of nose gear attachments Rn { 24.2, 0, 8.4 } Dm 6400 # main oleo damping factor (lbf s/ft) Dn 2000 # nose oleo damping factor (lbf s/ft) Km 106000 # main oleo spring factor (lbf/ft) Kn 22000 # nose oleo spring factor (lbf/ft) Gm 2 # main strut length with tire (ft) Gn 2 # nose strut length with tire (ft) CmMax 1.0 # (cmMax) main max oleo extension distance (ft) CnMax 1.5 # (cnMax) nose max oleo extension distance (ft) # (tailExtent) as we rotate, this part may drag TailExtent { -18.165, 0.0, 1.191 } # Speed limits at MTOW. Leave undefined or set to 0 if unknown. MTOW 52700.0 # maximum takeoff weight (lb) #Vs0 42.0 # stall speed, full flaps (KIAS) #Vs1 50.0 # stall speed, no flaps (KIAS) #Vfe 100.0 # max speed with flaps extended (KIAS) #Vno 145.0 # normal operation speed (KIAS) #Vne 164.0 # never exceed speed (KIAS) StructurePoints 30 # (structurePts) maximum structural damage # Radar data based on N-019 Pulse Doppler radar cited in [AirI Aug89]. RadarOutput 15000 # (radarOutput) radar output (watts) RadarTRange 38 # (radarTRange) tracking radar range (NM) RadarDRange 55 # (radarDRange) detection radar range (NM) TEWSThreshold 0 # Radar Warning Receiver threshold (watts) # Weapons WeaponCount 7 HardPoint0 { 7.0, -4.0, 0.0 } HardPoint1 { 0.357, 15.6, 0.0 } HardPoint2 { 0.357, -15.6, 0.0 } HardPoint3 { 1.5, 9.0, 2.0 } HardPoint4 { 1.5, -9.0, 2.0 } HardPoint5 { 1.5, 8.0, 1.5 } HardPoint6 { 1.5, -8.0, 1.5 } HardPoint7 { 1.5, 10.0, 1.5 } HardPoint8 { 1.5, -10.0, 1.5 } WeaponStation 0 "M61A1" 500 0 0 WeaponStation 1 "AIM-9M" 0 0 0 WeaponStation 2 "AIM-9M" 0 0 0 WeaponStation 3 "MK82" 0 0 0 WeaponStation 4 "MK82" 0 0 0 WeaponStation 5 "MK82" 0 0 0 WeaponStation 6 "MK82" 0 0 0 }acm-6.0_20200416/objects/aircraft/il78.obv0000644000000000000000000001567710357223037016334 0ustar rootrootobject 226 25 1 40.9151 7.83713 0.505125 2 40.9151 6.75434 4.54612 3 40.9151 3.79612 7.50434 4 40.9151 -0.244875 8.58713 5 40.9151 -4.28588 7.50434 6 40.9151 -7.24409 4.54612 7 40.9151 -8.32688 0.505125 8 40.9151 -7.24409 -3.53588 9 40.9151 -4.28587 -6.49409 10 40.9151 -0.244875 -7.57688 11 40.9151 3.79613 -6.49409 12 40.9151 6.75434 -3.53587 13 37.8844 36.8741 2.52563 14 37.8844 36.5358 3.78844 15 37.8844 35.6113 4.71288 16 37.8844 34.3485 5.05125 17 37.8844 33.0857 4.71288 18 37.8844 32.1612 3.78844 19 37.8844 31.8229 2.52563 20 37.8844 32.1612 1.26281 21 37.8844 33.0857 0.33837 22 37.8844 34.3485 0 23 37.8844 35.6113 0.33837 24 37.8844 36.5358 1.26281 25 37.8844 -36.5358 1.26281 26 37.8844 -35.6113 0.33837 27 37.8844 -34.3485 0 28 37.8844 -33.0857 0.33837 29 37.8844 -32.1612 1.26281 30 37.8844 -31.8229 2.52563 31 37.8844 -32.1612 3.78844 32 37.8844 -33.0857 4.71288 33 37.8844 -34.3485 5.05125 34 37.8844 -35.6113 4.71288 35 37.8844 -36.5358 3.78844 36 37.8844 -36.8741 2.52563 37 43.9459 -22.8974 -0.252562 38 43.9459 -21.9729 -1.17701 39 43.9459 -20.7101 -1.51538 40 43.9459 -19.4473 -1.17701 41 43.9459 -18.5229 -0.252563 42 43.9459 -18.1845 1.01025 43 43.9459 -18.5229 2.27306 44 43.9459 -19.4473 3.19751 45 43.9459 -20.7101 3.53588 46 43.9459 -21.9729 3.19751 47 43.9459 -22.8974 2.27306 48 43.9459 -23.2358 1.01025 49 80.3149 0 0.505125 50 78.7995 0 -1.51538 51 73.7483 0 -5.05125 52 71.2226 0 -7.57688 53 68.697 0 -8.58713 54 62.1304 0 -9.59738 55 -9.59738 0 -8.58713 56 -16.6691 0 -9.09225 57 -25.7614 0 -9.59738 58 -39.3998 0 -9.09225 59 -49.5023 0 -8.082 60 -56.574 0 -6.0615 61 -58.0894 0 -4.54612 62 -40.9151 0 3.03075 63 -16.164 0 6.56663 64 11.1128 0 8.082 65 35.8639 0 7.57688 66 60.615 0 7.07175 67 65.1611 0 6.56663 68 67.6868 0 8.082 69 70.2124 0 9.09225 70 77.2841 0 4.041 71 29.2973 -0 -4.041 72 29.2973 -0 -10.1025 73 -4.54612 -80.3149 -2.0205 74 -4.54612 80.3149 -2.0205 75 29.2973 0 -10.1025 76 29.2973 0 -4.041 77 43.9459 23.2358 1.01025 78 43.9459 22.8974 2.27306 79 43.9459 21.9729 3.19751 80 43.9459 20.7101 3.53588 81 43.9459 19.4473 3.19751 82 43.9459 18.5229 2.27306 83 43.9459 18.1845 1.01025 84 43.9459 18.5229 -0.252563 85 43.9459 19.4473 -1.17701 86 43.9459 20.7101 -1.51538 87 43.9459 21.9729 -1.17701 88 43.9459 22.8974 -0.252562 89 36.369 20.7101 3.53588 90 29.2973 20.7101 3.53588 91 24.7511 20.7101 2.52563 92 24.7511 20.7101 -3.53588 93 15.6589 20.7101 -6.56663 94 27.2768 20.7101 -7.07175 95 34.8536 20.7101 -4.041 96 39.3998 20.7101 -4.041 97 42.9356 20.7101 -3.53588 98 42.9356 20.7101 2.0205 99 18.6896 -3.03075 5.55638 100 34.8536 -7.07175 5.55638 101 31.3178 -8.58713 5.55638 102 16.164 -10.6076 5.55638 103 3.53588 -9.59738 5.55638 104 -2.52563 -7.57688 5.55638 105 -2.52563 7.57688 5.55638 106 3.53588 9.59738 5.55638 107 16.164 10.6076 5.55638 108 31.3178 8.58713 5.55638 109 34.8536 7.07175 5.55638 110 18.6896 3.03075 5.55638 111 28.287 -8.58713 3.03075 112 17.1743 -8.58713 1.51538 113 8.082 -8.58713 2.0205 114 -5.05125 -8.58713 3.53588 115 -13.1333 -8.58713 6.0615 116 -3.53588 -8.58713 10.1025 117 9.59738 -8.58713 11.6179 118 17.6794 -8.58713 10.6076 119 25.2563 -8.58713 8.58713 120 32.8331 -8.58713 6.0615 121 32.8331 8.58713 6.0615 122 25.2563 8.58713 8.58713 123 17.6794 8.58713 10.6076 124 9.59738 8.58713 11.6179 125 -3.53588 8.58713 10.1025 126 -13.1333 8.58713 6.0615 127 -5.05125 8.58713 3.53588 128 8.082 8.58713 2.0205 129 17.1743 8.58713 1.51538 130 28.287 8.58713 3.03075 131 30.3075 34.3485 4.54612 132 23.2358 34.3485 4.54612 133 18.6896 34.3485 3.53588 134 18.6896 34.3485 -2.52563 135 9.59738 34.3485 -5.55638 136 21.2153 34.3485 -6.0615 137 28.7921 34.3485 -3.03075 138 33.3383 34.3485 -3.03075 139 36.8741 34.3485 -2.52563 140 36.8741 34.3485 3.03075 141 42.9356 -20.7101 2.0205 142 42.9356 -20.7101 -3.53588 143 39.3998 -20.7101 -4.041 144 34.8536 -20.7101 -4.041 145 27.2768 -20.7101 -7.07175 146 15.6589 -20.7101 -6.56663 147 24.7511 -20.7101 -3.53588 148 24.7511 -20.7101 2.52563 149 29.2973 -20.7101 3.53588 150 36.369 -20.7101 3.53588 151 36.8741 -34.3485 3.03075 152 36.8741 -34.3485 -2.52563 153 33.3383 -34.3485 -3.03075 154 28.7921 -34.3485 -3.03075 155 21.2153 -34.3485 -6.0615 156 9.59738 -34.3485 -5.55638 157 18.6896 -34.3485 -2.52563 158 18.6896 -34.3485 3.53588 159 23.2358 -34.3485 4.54612 160 30.3075 -34.3485 4.54612 161 -61.6253 0.505125 -4.54612 162 -39.3998 -4.54612 -4.54612 163 -27.7819 -8.082 -4.54612 164 31.3178 -8.082 -4.54612 165 34.3485 -0.505125 -4.54612 166 34.3485 0.505125 -4.54612 167 31.3178 8.082 -4.54612 168 -27.7819 8.082 -4.54612 169 -39.3998 4.54612 -4.54612 170 -61.6253 -0.505125 -4.54612 171 -49.5023 0.505125 0 172 -33.3383 -2.52563 0 173 -22.2255 -4.54612 0 174 -12.123 -8.082 0 175 52.0279 -7.07175 0 176 63.1406 -6.56663 0 177 70.7175 -5.55638 0 178 79.3046 -3.03075 0 179 81.3251 -0.505125 0 180 81.3251 0.505125 0 181 79.3046 3.03075 0 182 70.7175 5.55638 0 183 63.1406 6.56663 0 184 52.0279 7.07175 0 185 -12.123 8.082 0 186 -22.2255 4.54612 0 187 -33.3383 2.52563 0 188 -49.5023 -0.505125 0 189 38.8946 -6.0615 -6.77563 190 42.4305 -0 -7.15167 191 5.55638 0.505125 -9.32963 192 5.05125 -6.56663 -8.68184 193 3.53588 -34.8536 -6.0615 194 -8.082 -78.7995 -2.52563 195 -1.01025 -79.8098 -2.0205 196 -1.01025 79.8098 -2.0205 197 -8.082 78.7995 -2.52563 198 3.53588 34.8536 -6.0615 199 5.05125 6.56663 -8.68184 200 5.55638 -0.505125 -9.32963 201 42.4305 0 -7.15167 202 38.8946 6.0615 -6.77563 203 -59.6048 -0.505125 -32.328 204 -68.1919 -26.2665 -32.328 205 -62.1304 -25.2563 -32.328 206 -45.4613 -3.03075 -32.328 207 -44.451 0.505125 -32.328 208 -44.451 -0.505125 -32.328 209 -45.4613 3.03075 -32.328 210 -62.1304 25.2563 -32.328 211 -68.1919 26.2665 -32.328 212 -59.6048 0.505125 -32.328 213 -17.1743 0 -9.09225 214 -25.2563 0 -11.6179 215 -29.8024 0 -14.1435 216 -42.9356 -0 -27.2768 217 -42.9356 -0 -30.8126 218 -36.369 -0 -32.8331 219 -43.9459 -0 -34.3485 220 -56.0689 -0 -33.8434 221 -64.656 -0 -32.328 222 -71.2226 -0 -29.2973 223 -63.1406 -0 -28.7921 224 -53.5433 -0 -10.1025 225 -53.5433 -0 -8.082 226 -56.574 -0 -4.54612 gray44 12 1 2 3 4 5 6 7 8 9 10 11 12 gray44 12 13 14 15 16 17 18 19 20 21 22 23 24 gray44 12 25 26 27 28 29 30 31 32 33 34 35 36 gray44 12 37 38 39 40 41 42 43 44 45 46 47 48 gray44 22 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 gray44 3 71 72 73 gray44 3 74 75 76 gray44 12 77 78 79 80 81 82 83 84 85 86 87 88 gray44 10 89 90 91 92 93 94 95 96 97 98 gray44 6 99 100 101 102 103 104 gray44 6 105 106 107 108 109 110 gray44 10 111 112 113 114 115 116 117 118 119 120 gray44 10 121 122 123 124 125 126 127 128 129 130 gray44 10 131 132 133 134 135 136 137 138 139 140 gray44 10 141 142 143 144 145 146 147 148 149 150 gray44 10 151 152 153 154 155 156 157 158 159 160 gray44 5 161 162 163 164 165 gray44 5 166 167 168 169 170 gray44 9 171 172 173 174 175 176 177 178 179 gray44 9 180 181 182 183 184 185 186 187 188 gray44 7 189 190 191 192 193 194 195 gray44 7 196 197 198 199 200 201 202 gray44 5 203 204 205 206 207 gray44 5 208 209 210 211 212 gray44 14 213 214 215 216 217 218 219 220 221 222 223 224 225 226 acm-6.0_20200416/objects/aircraft/b-747.gdf0000644000000000000000000002551413074621700016250 0ustar rootrootRR11u? ^) Mi[@I(C@helpP hicsX ]S g@\TQA@˜`m@/EOP>@M.ڞm@cӄ9@FT!m@ģ۲F2@Du3>&k@$8'@]*-0j@$8@hG9h@L0l@KF8~b@W,)@qa@ @H@W,)"@h3h@8ª;.:@ 8ª;Ը@cӄ@!; Sؿ!`@jsMB?r0@5P@@@O^ψS@9 } jA@; p1m@cӄ @ (p1m@u?Xm86@CLY2m@cӄ @Xm86@F\z3j@u$@Xm86@q\Ȭ h@$8'@Xm86@NY2M@!HM%@Xm86@YpZWM@*RJ(Xm86@X:%6h@*RJ(Xm86@Ԑ;Ij@u$Xm86@r m@cӄ Xm86@Gp1m@Xm86@C 𿏈u?(bC@ Xe@F@cӄ)@pUu$@(bC@cӄ)@rcӄ @cYC@cӄ)@scY#@u?cӄ)@u?I(Ccӄ)@EX,)"@(bCcӄ)@{pHE@ucӄ)@r 4ɩ<, <@ ( 9`Uh@n(@of4@9`Uh@su%@##9:@9`Uh@n@gO!?@9`Uh@ %LkHe@@9`Uh@ngO!?@9`Uh@su%##9:@9`Uh@n(of4@9`Uh@su%pxi,@9`Uh@nx!X#@9`Uh@ )jF @9`Uh@n@t!X#@9`Uh@su%@pxi,@ H[6$0%~;@ K6]a@7 '@X z7@K6]a@DoI$@gΊ`l=@K6]a@- @k`@@K6]a@@zRA@K6]a@` k`@@K6]a@[oI$gΊ`l=@K6]a@Q 'Z z7@K6]a@_oI$KH؇1@K6]a@h q:ZZ*@K6]a@@| (+'@K6]a@- @q:ZZ*@K6]a@DoI$@IH؇1@ 8},e6<@ "bS@MFA '@ԘaH5@<"bS@zf$@̀_;@<"bS@H`w@(Ő@@<"bS@u"b.R@@<"bS@]G(Ő@@<"bS@C(&̀_;@<"bS@uw V*ԘaH5@<"bS@G(&VaNJ .@<"bS@]Gkq$@<"bS@!uʑˠ!@<"bS@H`w@kq$@<"bS@zf$@VaNJ .@<?u?=aB@help LIST :Vzd@Tuxqۻ;@wQd@0ª+xqۻ;@vR@!`\xqۻ;@A]O@ ?\xqۻ;@T^DqX@V.Gxqۻ;@e[[@cӄ)xqۻ;@ vqۻ[@Tuxqۻ;@  o ("@ 1;=@ Pcӄ9V.7@cӄ9V.7@cӄ9V.7@cӄ9V.7@cӄ9V.7@cӄ9V.7@cӄ9V.7@cӄ9V.7@cӄ9V.7@cӄ9V.7@cӄ9V.7@cӄ9V.7@ 𿏈u `D@AsB@oBeb@fk ~D@[TQA@pBeb@>`D@u.@@oBeb@L~+E@JRe?@mBeb@0e@F@%?@jBeb@LUG@HRe?@fBeb@fO H@u.@@d-CY y_@@ @eb@z7v?D7 } jA@@eb@ccD%@@eb@Um8Fz1t->@@eb@hJiEc>@@eb@ccDJ&zc@@@ R[1Y.>@ /?e_@$;XHT6 } jA@+/?e_@G9pT$@6/?e_@㧄rUz1t->@2/?e_@l,Tc>@//?e_@G9pTI&zc@@@,ZS@g sU>@ !f/ `@ǻ@Z/T@6 } jA@.!f/ `@IyT@2ضB@0!f/ `@e|S@5)2xC@2!f/ `@cYS@̢RD@7!f/ `@ R@5)2xC@;!f/ `@ 4-9R@2ضB@=!f/ `@1$ R@7 } jA@?!f/ `@ 4-9R@l?A@@=!f/ `@ R@¡ CS>@;!f/ `@cYS@@"=@7!f/ `@e|S@¡ CS>@2!f/ `@IyT@k?A@@0cY#@r0 :Vzd@u?xqۻ;@:Vzd@ª+@xqۻ;@c0S@\@xqۻ;@>֦ݢN@\@xqۻ;@V)YX@V.G@xqۻ;@ex[[@cӄ)@xqۻ;@ qۻ[@u?xqۻ;@ acm-6.0_20200416/objects/aircraft/mig29.obv0000644000000000000000000001662610357223037016473 0ustar rootrootobject 235 25 1 -20.7292 -3.91308 -0.575279 2 -20.7292 -3.49195 -0.996413 3 -20.7292 -2.91667 -1.15056 4 -20.7292 -2.34139 -0.996413 5 -20.7292 -1.92025 -0.575279 6 -20.7292 -1.76611 6.51849e-16 7 -20.7292 -1.92025 0.575279 8 -20.7292 -2.34139 0.996413 9 -20.7292 -2.91667 1.15056 10 -20.7292 -3.49195 0.996413 11 -20.7292 -3.91308 0.575279 12 -20.7292 -4.06723 0 13 -20.7292 4.06723 0 14 -20.7292 3.91308 0.575279 15 -20.7292 3.49195 0.996413 16 -20.7292 2.91667 1.15056 17 -20.7292 2.34139 0.996413 18 -20.7292 1.92025 0.575279 19 -20.7292 1.76611 6.51849e-16 20 -20.7292 1.92025 -0.575279 21 -20.7292 2.34139 -0.996413 22 -20.7292 2.91667 -1.15056 23 -20.7292 3.49195 -0.996413 24 -20.7292 3.91308 -0.575279 25 7.5636 -3.46665 1.78585 26 7.5636 -1.57575 1.78585 27 10.9252 -1.78585 -0.6303 28 10.9252 -3.3616 -0.6303 29 10.9252 3.3616 -0.6303 30 10.9252 1.78585 -0.6303 31 7.5636 1.57575 1.78585 32 7.5636 3.46665 1.78585 33 -17.3332 -3.5717 0.73535 34 -17.3332 -2.41615 0.73535 35 -17.3332 -1.4707 -0.2101 36 -17.3332 -0 -1.15555 37 -17.3332 -0.10505 -2.101 38 -17.3332 -3.04645 -2.3111 39 -17.3332 -4.30705 -1.8909 40 -17.3332 -6.0929 -1.4707 41 -17.3332 -5.8828 -1.0505 42 -17.3332 -5.2525 -0.8404 43 -17.3332 -4.30705 -0.10505 44 -17.3332 4.30705 -0.10505 45 -17.3332 5.2525 -0.8404 46 -17.3332 5.8828 -1.0505 47 -17.3332 6.0929 -1.4707 48 -17.3332 4.30705 -1.8909 49 -17.3332 3.04645 -2.3111 50 -17.3332 0.10505 -2.101 51 -17.3332 0 -1.15555 52 -17.3332 1.4707 -0.2101 53 -17.3332 2.41615 0.73535 54 -17.3332 3.5717 0.73535 55 -5.0424 5.56765 -2.101 56 -8.6141 5.8828 -3.25655 57 -18.5938 7.3535 -10.7151 58 -20.3797 7.29856 -9.76965 59 -20.0646 7.00651 -7.7737 60 -20.2747 7.0009 -7.66865 61 -19.6443 6.35817 -3.25655 62 -19.0141 6.28704 -2.9414 63 -19.0141 5.97926 -0.73535 64 -11.7656 5.68152 -0.8404 65 -16.703 -0.10505 -1.6808 66 -18.0686 -4.30705 -1.6808 67 -19.8544 -4.93735 -1.6808 68 -20.4848 -5.56765 -1.6808 69 -14.1818 -5.8828 -1.6808 70 4.09695 -5.77775 -1.6808 71 7.5636 -5.2525 -1.6808 72 19.8544 -1.57575 -1.6808 73 22.1655 -1.57575 -1.6808 74 25.4221 -1.36565 -1.6808 75 29.8342 -0.10505 -1.6808 76 -18.804 -5.35755 -1.66969 77 -21.7454 -6.303 -1.55248 78 -25.212 -12.2909 -0.8404 79 -22.0605 -13.2363 -0.73535 80 -13.2363 -5.35755 -1.6808 81 -11.7656 -5.68152 -0.8404 82 -19.0141 -5.97926 -0.73535 83 -19.0141 -6.28704 -2.9414 84 -19.6443 -6.35817 -3.25655 85 -20.2747 -7.0009 -7.66865 86 -20.0646 -7.00651 -7.7737 87 -20.3797 -7.29856 -9.76965 88 -18.5938 -7.3535 -10.7151 89 -8.6141 -5.8828 -3.25655 90 -5.0424 -5.56765 -2.101 91 -20.9049 -2.88888 1.4707 92 -16.3878 -2.87903 1.36565 93 -7.66865 -2.78723 1.8909 94 1.8909 -2.73367 1.99595 95 4.4121 -2.72231 1.99595 96 7.5636 -2.71862 1.8909 97 10.9252 -2.97661 -0.8404 98 7.9838 -3.00036 -0.94545 99 6.5131 -3.11204 -1.99595 100 0.52525 -3.14951 -2.101 101 -9.2444 -3.1515 -1.6808 102 -20.9049 -3.1515 -1.15555 103 -20.9049 -3.04645 -0.10505 104 -15.5474 -1.15555 0.0642234 105 -20.9049 -1.8909 -0.10505 106 -20.7999 -4.09695 -0.10505 107 -17.4383 -4.4121 0 108 -17.4383 4.4121 0 109 -20.7999 4.09695 -0.10505 110 -20.9049 1.8909 -0.10505 111 -15.5474 1.15555 0.0642234 112 -20.9049 3.04645 -0.10505 113 -20.9049 3.1515 -1.15555 114 -9.2444 3.1515 -1.6808 115 0.52525 3.14951 -2.101 116 6.5131 3.11204 -1.99595 117 7.9838 3.00036 -0.94545 118 10.9252 2.97661 -0.8404 119 7.5636 2.71862 1.8909 120 4.4121 2.72231 1.99595 121 1.8909 2.73367 1.99595 122 -7.66865 2.78723 1.8909 123 -16.3878 2.87903 1.36565 124 -20.9049 2.88888 1.4707 125 -13.2363 5.35755 -1.6808 126 -22.0605 13.2363 -0.73535 127 -25.212 12.2909 -0.8404 128 -21.7454 6.303 -1.55248 129 -18.804 5.35755 -1.66969 130 29.8342 0.10505 -1.6808 131 25.4221 1.36565 -1.6808 132 22.1655 1.57575 -1.6808 133 19.8544 1.57575 -1.6808 134 7.5636 5.2525 -1.6808 135 4.09695 5.77775 -1.6808 136 -14.1818 5.8828 -1.6808 137 -20.4848 5.56765 -1.6808 138 -19.8544 4.93735 -1.6808 139 -18.0686 4.30705 -1.6808 140 -16.703 0.10505 -1.6808 141 29.8342 0 -1.6808 142 26.6827 0 -3.04645 143 23.5312 0 -3.67675 144 19.3292 0 -4.30705 145 16.5979 0 -5.98785 146 15.1272 0 -6.19795 147 12.7111 0 -5.98785 148 1.4707 0 -3.7818 149 -19.4343 0 -0.94545 150 -18.5938 0 -0.2101 151 12.501 0 -0.31515 152 19.3292 0 -0.52525 153 21.8504 0 -0.2101 154 26.2625 0 -0.4202 155 29.309 0 -0.94545 156 3.1515 5.6727 -2.101 157 -11.0303 5.4626 -1.99595 158 -12.606 19.1191 -0.52525 159 -12.1858 19.5393 -0.48421 160 -9.97975 19.7494 -0.481629 161 -9.6646 19.4343 -0.518073 162 -7.7737 19.3292 -0.546272 163 -7.7737 -19.3292 -0.546272 164 -9.6646 -19.4343 -0.518073 165 -9.97975 -19.7494 -0.481629 166 -12.1858 -19.5393 -0.48421 167 -12.606 -19.1191 -0.52525 168 -11.0303 -5.4626 -1.99595 169 3.1515 -5.6727 -2.101 170 -9.8747 -2.5212 1.8909 171 -9.8747 -3.7818 1.36565 172 -9.8747 -4.09695 -0.4202 173 -9.8747 -5.14745 -0.6303 174 -9.8747 -5.6727 -1.15555 175 -9.8747 -19.7494 -0.52525 176 -9.8747 -5.98785 -2.101 177 -9.8747 -3.9919 -2.7313 178 -9.8747 -2.62625 -2.9414 179 -9.8747 0.10505 -3.25655 180 -9.8747 0 -0.10505 181 -9.8747 -0.94545 -0.2101 182 -9.8747 -1.6808 0.52525 183 -9.8747 1.6808 0.52525 184 -9.8747 0.94545 -0.2101 185 -9.8747 -0 -0.10505 186 -9.8747 -0.10505 -3.25655 187 -9.8747 2.62625 -2.9414 188 -9.8747 3.9919 -2.7313 189 -9.8747 5.98785 -2.101 190 -9.8747 19.7494 -0.52525 191 -9.8747 5.6727 -1.15555 192 -9.8747 5.14745 -0.6303 193 -9.8747 4.09695 -0.4202 194 -9.8747 3.7818 1.36565 195 -9.8747 2.5212 1.8909 196 15.5474 0 -6.19795 197 15.5474 -0.94545 -5.77775 198 15.5474 -1.4707 -4.8323 199 15.5474 -1.57575 -3.9919 200 15.5474 -1.78585 -2.101 201 15.5474 -1.36565 -1.0505 202 15.5474 -0.52525 -0.52525 203 15.5474 0.10505 -0.31515 204 15.5474 -0.10505 -0.31515 205 15.5474 0.52525 -0.52525 206 15.5474 1.36565 -1.0505 207 15.5474 1.78585 -2.101 208 15.5474 1.57575 -3.9919 209 15.5474 1.4707 -4.8323 210 15.5474 0.94545 -5.77775 211 15.5474 0 -6.19795 212 4.202 -2.62625 1.99595 213 4.202 -3.7818 1.57575 214 4.202 -3.9919 -0.2101 215 4.202 -5.14745 -0.52525 216 4.202 -5.77775 -0.94545 217 4.202 -5.8828 -1.8909 218 4.202 -3.7818 -2.5212 219 4.202 0 -3.04645 220 4.202 0 0 221 4.202 -1.15555 0 222 4.202 -1.8909 1.0505 223 4.202 -2.20605 1.78585 224 4.202 2.20605 1.78585 225 4.202 1.8909 1.0505 226 4.202 1.15555 0 227 4.202 -0 0 228 4.202 -0 -3.04645 229 4.202 3.7818 -2.5212 230 4.202 5.8828 -1.8909 231 4.202 5.77775 -0.94545 232 4.202 5.14745 -0.52525 233 4.202 3.9919 -0.2101 234 4.202 3.7818 1.57575 235 4.202 2.62625 1.99595 (black gray44) 12 1 2 3 4 5 6 7 8 9 10 11 12 (black gray44) 12 13 14 15 16 17 18 19 20 21 22 23 24 (black gray44) 4 25 26 27 28 (black gray44) 4 29 30 31 32 gray44 11 33 34 35 36 37 38 39 40 41 42 43 gray44 11 44 45 46 47 48 49 50 51 52 53 54 gray44 10 55 56 57 58 59 60 61 62 63 64 gray44 11 65 66 67 68 69 70 71 72 73 74 75 gray44 5 76 77 78 79 80 gray44 10 81 82 83 84 85 86 87 88 89 90 gray44 13 91 92 93 94 95 96 97 98 99 100 101 102 103 gray44 4 104 105 106 107 gray44 4 108 109 110 111 gray44 13 112 113 114 115 116 117 118 119 120 121 122 123 124 gray44 5 125 126 127 128 129 gray44 11 130 131 132 133 134 135 136 137 138 139 140 gray44 15 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 gray44 7 156 157 158 159 160 161 162 gray44 7 163 164 165 166 167 168 169 gray44 13 170 171 172 173 174 175 176 177 178 179 180 181 182 gray44 13 183 184 185 186 187 188 189 190 191 192 193 194 195 gray44 8 196 197 198 199 200 201 202 203 gray44 8 204 205 206 207 208 209 210 211 gray44 12 212 213 214 215 216 217 218 219 220 221 222 223 gray44 12 224 225 226 227 228 229 230 231 232 233 234 235 acm-6.0_20200416/objects/aircraft/f117.dxf0000644000000000000000000003333310357223037016207 0ustar rootroot 0 SECTION 2 HEADER 0 ENDSEC 0 SECTION 2 TABLES 0 TABLE 2 LAYER 70 153 0 LAYER 2 0 70 0 62 15 6 CONTINUOUS 0 ENDTAB 0 ENDSEC 0 SECTION 2 ENTITIES 0 3DFACE 8 0 10 0.762000 20 -3.790279 30 0.000489 11 0.944880 21 -2.571079 31 0.000489 12 1.524000 22 -2.266279 32 0.000489 13 1.524000 23 -2.266279 33 0.000489 62 4 0 3DFACE 8 0 10 0.000031 20 -5.353721 30 0.000704 11 0.000000 21 -3.942679 31 0.610089 12 0.762000 22 -3.790279 32 0.000489 13 0.762000 23 -3.790279 33 0.000489 62 4 0 3DFACE 8 0 10 0.000000 20 -3.028280 30 1.524489 11 0.000011 21 3.729320 31 0.000000 12 0.000000 22 2.000921 32 0.610089 13 0.000000 23 2.000921 33 0.610089 62 0 0 3DFACE 8 0 10 1.371600 20 1.238921 30 0.610089 11 0.000000 21 -3.028280 31 1.524489 12 0.000000 22 2.000921 32 0.610089 13 0.000000 23 2.000921 33 0.610089 62 4 0 3DFACE 8 0 10 0.000011 20 3.729320 30 0.000000 11 1.467700 21 2.235796 31 0.010004 12 0.000000 22 2.000921 32 0.610089 13 0.000000 23 2.000921 33 0.610089 62 4 0 3DFACE 8 0 10 0.000000 20 -3.028280 30 1.524489 11 1.371600 21 1.238921 31 0.610089 12 0.762000 22 -3.790279 32 0.000489 13 0.762000 23 -3.790279 33 0.000489 62 4 0 3DFACE 8 0 10 0.762000 20 -3.790279 30 0.000489 11 0.000000 21 -3.942679 31 0.610089 12 0.000000 22 -3.028280 32 1.524489 13 0.000000 23 -3.028280 33 1.524489 62 4 0 3DFACE 8 0 10 0.000031 20 -5.353721 30 0.000704 11 3.631692 21 3.455000 31 0.018325 12 1.589602 22 1.595716 32 0.012271 13 1.589602 23 1.595716 33 0.012271 62 4 0 3DFACE 8 0 10 0.000000 20 -3.028280 30 1.524489 11 0.000000 21 2.000921 31 0.610089 12 0.000011 22 3.729320 32 0.000000 13 0.000011 23 3.729320 33 0.000000 62 0 0 3DFACE 8 0 10 1.219200 20 5.353721 30 1.676889 11 0.000011 21 3.729320 31 0.000000 12 1.219200 22 4.439321 32 1.676889 13 1.219200 23 4.439321 33 1.676889 62 3 0 3DFACE 8 0 10 1.524000 20 -2.266279 30 0.000489 11 3.631692 21 3.455000 31 0.018325 12 3.936492 22 3.150200 32 0.018417 13 3.936492 23 3.150200 33 0.018417 62 4 0 3DFACE 8 0 10 1.828800 20 -0.437479 30 0.000489 11 1.371600 21 1.238921 31 0.610089 12 1.589602 22 1.595716 32 0.012271 13 1.589602 23 1.595716 33 0.012271 62 3 0 3DFACE 8 0 10 1.524000 20 -2.266279 30 0.000489 11 1.219200 21 -1.809079 31 0.610089 12 1.828800 22 -0.437479 32 0.000489 13 1.828800 23 -0.437479 33 0.000489 62 4 0 3DFACE 8 0 10 1.371600 20 -0.437479 30 0.610089 11 0.762000 21 -0.589879 31 0.914889 12 1.371600 22 1.238921 32 0.610089 13 1.371600 23 1.238921 33 0.610089 62 4 0 3DFACE 8 0 10 0.762000 20 -2.266279 30 0.610089 11 0.762000 21 -0.589879 31 0.914889 12 1.219200 22 -1.809079 32 0.610089 13 1.219200 23 -1.809079 33 0.610089 62 4 0 3DFACE 8 0 10 0.944880 20 -2.571079 30 0.000489 11 0.762000 21 -2.266279 31 0.610089 12 1.524000 22 -2.266279 32 0.000489 13 1.524000 23 -2.266279 33 0.000489 62 4 0 3DFACE 8 0 10 1.371600 20 1.238921 30 0.610089 11 1.467700 21 2.235796 31 0.010004 12 1.589602 22 1.595716 32 0.012271 13 1.589602 23 1.595716 33 0.012271 62 4 0 3DFACE 8 0 10 0.000031 20 -5.353721 30 0.000704 11 3.631692 21 3.455000 31 0.018325 12 1.589602 22 1.595716 32 0.012271 13 1.589602 23 1.595716 33 0.012271 62 4 0 3DFACE 8 0 10 1.219200 20 5.353721 30 1.676889 11 1.219200 21 4.439321 31 1.676889 12 0.000011 22 3.729320 32 0.000000 13 0.000011 23 3.729320 33 0.000000 62 4 0 3DFACE 8 0 10 -0.762000 20 -3.790279 30 0.000489 11 -1.524000 21 -2.266279 31 0.000489 12 -0.944880 22 -2.571079 32 0.000489 13 -0.944880 23 -2.571079 33 0.000489 62 4 0 3DFACE 8 0 10 0.000031 20 -5.353721 30 0.000704 11 -0.762000 21 -3.790279 31 0.000489 12 0.000000 22 -3.942679 32 0.610089 13 0.000000 23 -3.942679 33 0.610089 62 4 0 3DFACE 8 0 10 0.000000 20 -3.028280 30 1.524489 11 0.000000 21 2.000921 31 0.610089 12 0.000011 22 3.729320 32 0.000000 13 0.000011 23 3.729320 33 0.000000 62 0 0 3DFACE 8 0 10 -1.371600 20 1.238921 30 0.610089 11 0.000000 21 2.000921 31 0.610089 12 0.000000 22 -3.028280 32 1.524489 13 0.000000 23 -3.028280 33 1.524489 62 4 0 3DFACE 8 0 10 0.000011 20 3.729320 30 0.000000 11 0.000000 21 2.000921 31 0.610089 12 -1.467700 22 2.235796 32 0.010004 13 -1.467700 23 2.235796 33 0.010004 62 3 0 3DFACE 8 0 10 0.000000 20 -3.028280 30 1.524489 11 -0.762000 21 -3.790279 31 0.000489 12 -1.371600 22 1.238921 32 0.610089 13 -1.371600 23 1.238921 33 0.610089 62 4 0 3DFACE 8 0 10 -0.762000 20 -3.790279 30 0.000489 11 0.000000 21 -3.028280 31 1.524489 12 0.000000 22 -3.942679 32 0.610089 13 0.000000 23 -3.942679 33 0.610089 62 4 0 3DFACE 8 0 10 0.000031 20 -5.353721 30 0.000704 11 -1.589602 21 1.595716 31 0.012271 12 -3.936492 22 3.150200 32 0.018417 13 -3.936492 23 3.150200 33 0.018417 62 4 0 3DFACE 8 0 10 0.000000 20 -3.028280 30 1.524489 11 0.000011 21 3.729320 31 0.000000 12 0.000000 22 2.000921 32 0.610089 13 0.000000 23 2.000921 33 0.610089 62 0 0 3DFACE 8 0 10 -1.219200 20 5.353721 30 1.676889 11 -1.219200 21 4.439321 31 1.676889 12 0.000011 22 3.729320 32 0.000000 13 0.000011 23 3.729320 33 0.000000 62 3 0 3DFACE 8 0 10 -1.524000 20 -2.266279 30 0.000489 11 -3.631692 21 3.455000 31 0.018325 12 -1.828800 22 -0.437479 32 0.000489 13 -1.828800 23 -0.437479 33 0.000489 62 4 0 3DFACE 8 0 10 -1.828800 20 -0.437479 30 0.000489 11 -1.371600 21 1.238921 31 0.610089 12 -1.371600 22 -0.437479 32 0.610089 13 -1.371600 23 -0.437479 33 0.610089 62 4 0 3DFACE 8 0 10 -1.524000 20 -2.266279 30 0.000489 11 -1.828800 21 -0.437479 31 0.000489 12 -1.219200 22 -1.809079 32 0.610089 13 -1.219200 23 -1.809079 33 0.610089 62 4 0 3DFACE 8 0 10 -1.371600 20 -0.437479 30 0.610089 11 -1.371600 21 1.238921 31 0.610089 12 -0.762000 22 -0.589879 32 0.914889 13 -0.762000 23 -0.589879 33 0.914889 62 4 0 3DFACE 8 0 10 -0.762000 20 -2.266279 30 0.610089 11 -1.219200 21 -1.809079 31 0.610089 12 -0.762000 22 -0.589879 32 0.914889 13 -0.762000 23 -0.589879 33 0.914889 62 4 0 3DFACE 8 0 10 -0.944880 20 -2.571079 30 0.000489 11 -1.524000 21 -2.266279 31 0.000489 12 -0.762000 22 -2.266279 32 0.610089 13 -0.762000 23 -2.266279 33 0.610089 62 4 0 3DFACE 8 0 10 -1.371600 20 1.238921 30 0.610089 11 -1.589602 21 1.595716 31 0.012271 12 -1.467700 22 2.235796 32 0.010004 13 -1.467700 23 2.235796 33 0.010004 62 0 0 3DFACE 8 0 10 0.000031 20 -5.353721 30 0.000704 11 -1.589602 21 1.595716 31 0.012271 12 -3.936492 22 3.150200 32 0.018417 13 -3.936492 23 3.150200 33 0.018417 62 4 0 3DFACE 8 0 10 -1.219200 20 5.353721 30 1.676889 11 0.000011 21 3.729320 31 0.000000 12 -1.219200 22 4.439321 32 1.676889 13 -1.219200 23 4.439321 33 1.676889 62 1 0 3DFACE 8 0 10 0.000000 20 2.000921 30 0.610089 11 1.467700 21 2.235796 31 0.010004 12 1.371600 22 1.238921 32 0.610089 13 1.371600 23 1.238921 33 0.610089 62 3 0 3DFACE 8 0 10 0.762000 20 -3.790279 30 0.000489 11 1.371600 21 1.238921 31 0.610089 12 1.589602 22 1.595716 32 0.012271 13 1.589602 23 1.595716 33 0.012271 62 3 0 3DFACE 8 0 10 3.936492 20 3.150200 30 0.018417 11 0.000031 21 -5.353721 31 0.000704 12 3.936492 22 2.723480 32 0.018509 13 3.936492 23 2.723480 33 0.018509 62 4 0 3DFACE 8 0 10 0.000011 20 3.729320 30 0.000000 11 1.589602 21 1.595716 31 0.012271 12 1.467700 22 2.235796 32 0.010004 13 1.467700 23 2.235796 33 0.010004 62 4 0 3DFACE 8 0 10 3.631692 20 3.455000 30 0.018325 11 0.000031 21 -5.353721 31 0.000704 12 3.936492 22 3.150200 32 0.018417 13 3.936492 23 3.150200 33 0.018417 62 3 0 3DFACE 8 0 10 0.000031 20 -5.353721 30 0.000704 11 1.589602 21 1.595716 31 0.012271 12 0.000011 22 3.729320 32 0.000000 13 0.000011 23 3.729320 33 0.000000 62 4 0 3DFACE 8 0 10 1.219200 20 4.439321 30 1.676889 11 0.000011 21 3.729320 31 0.000000 12 0.304800 22 2.427640 32 0.396729 13 0.304800 23 2.427640 33 0.396729 62 2 0 3DFACE 8 0 10 3.631692 20 3.455000 30 0.018325 11 1.828800 21 -0.437479 31 0.000489 12 1.589602 22 1.595716 32 0.012271 13 1.589602 23 1.595716 33 0.012271 62 4 0 3DFACE 8 0 10 1.524000 20 -2.266279 30 0.000489 11 3.936492 21 3.150200 31 0.018417 12 3.936492 22 2.723480 32 0.018509 13 3.936492 23 2.723480 33 0.018509 62 2 0 3DFACE 8 0 10 3.631692 20 3.455000 30 0.018325 11 1.524000 21 -2.266279 31 0.000489 12 1.828800 22 -0.437479 32 0.000489 13 1.828800 23 -0.437479 33 0.000489 62 4 0 3DFACE 8 0 10 1.371600 20 1.238921 30 0.610089 11 1.828800 21 -0.437479 31 0.000489 12 1.371600 22 -0.437479 32 0.610089 13 1.371600 23 -0.437479 33 0.610089 62 3 0 3DFACE 8 0 10 1.828800 20 -0.437479 30 0.000489 11 1.219200 21 -1.809079 31 0.610089 12 1.371600 22 -0.437479 32 0.610089 13 1.371600 23 -0.437479 33 0.610089 62 3 0 3DFACE 8 0 10 1.219200 20 -1.809079 30 0.610089 11 0.762000 21 -0.589879 31 0.914889 12 1.371600 22 -0.437479 32 0.610089 13 1.371600 23 -0.437479 33 0.610089 62 3 0 3DFACE 8 0 10 1.524000 20 -2.266279 30 0.000489 11 0.762000 21 -2.266279 31 0.610089 12 1.219200 22 -1.809079 32 0.610089 13 1.219200 23 -1.809079 33 0.610089 62 4 0 3DFACE 8 0 10 3.936492 20 3.150200 30 0.018417 11 0.000031 21 -5.353721 31 0.000704 12 3.936492 22 2.723480 32 0.018509 13 3.936492 23 2.723480 33 0.018509 62 3 0 3DFACE 8 0 10 0.000011 20 3.729320 30 0.000000 11 1.589602 21 1.595716 31 0.012271 12 1.467700 22 2.235796 32 0.010004 13 1.467700 23 2.235796 33 0.010004 62 4 0 3DFACE 8 0 10 3.631692 20 3.455000 30 0.018325 11 0.000031 21 -5.353721 31 0.000704 12 3.936492 22 3.150200 32 0.018417 13 3.936492 23 3.150200 33 0.018417 62 4 0 3DFACE 8 0 10 0.000031 20 -5.353721 30 0.000704 11 1.589602 21 1.595716 31 0.012271 12 0.000011 22 3.729320 32 0.000000 13 0.000011 23 3.729320 33 0.000000 62 4 0 3DFACE 8 0 10 0.000011 20 3.729320 30 0.000000 11 1.219200 21 4.439321 31 1.676889 12 0.304800 22 2.427640 32 0.396729 13 0.304800 23 2.427640 33 0.396729 62 3 0 3DFACE 8 0 10 -1.467700 20 2.235796 30 0.010004 11 0.000000 21 2.000921 31 0.610089 12 -1.371600 22 1.238921 32 0.610089 13 -1.371600 23 1.238921 33 0.610089 62 4 0 3DFACE 8 0 10 -1.371600 20 1.238921 30 0.610089 11 -0.762000 21 -3.790279 31 0.000489 12 -1.589602 22 1.595716 32 0.012271 13 -1.589602 23 1.595716 33 0.012271 62 4 0 3DFACE 8 0 10 -1.467700 20 2.235796 30 0.010004 11 0.000031 21 -5.353721 31 0.000704 12 0.000011 22 3.729320 32 0.000000 13 0.000011 23 3.729320 33 0.000000 62 4 0 3DFACE 8 0 10 -3.936492 20 3.150200 30 0.018417 11 -1.589602 21 1.595716 31 0.012271 12 -3.631692 22 3.455000 32 0.018325 13 -3.631692 23 3.455000 33 0.018325 62 3 0 3DFACE 8 0 10 -1.589602 20 1.595716 30 0.012271 11 0.000031 21 -5.353721 31 0.000704 12 -1.467700 22 2.235796 32 0.010004 13 -1.467700 23 2.235796 33 0.010004 62 4 0 3DFACE 8 0 10 0.000031 20 -5.353721 30 0.000704 11 -3.936492 21 3.150200 31 0.018417 12 -3.936492 22 2.723480 32 0.018509 13 -3.936492 23 2.723480 33 0.018509 62 4 0 3DFACE 8 0 10 0.000011 20 3.729320 30 0.000000 11 -1.219200 21 4.439321 31 1.676889 12 -0.304800 22 2.427640 32 0.396729 13 -0.304800 23 2.427640 33 0.396729 62 4 0 3DFACE 8 0 10 -3.936492 20 3.150200 30 0.018417 11 -1.524000 21 -2.266279 31 0.000489 12 -3.936492 22 2.723480 32 0.018509 13 -3.936492 23 2.723480 33 0.018509 62 4 0 3DFACE 8 0 10 -1.828800 20 -0.437479 30 0.000489 11 -3.631692 21 3.455000 31 0.018325 12 -1.589602 22 1.595716 32 0.012271 13 -1.589602 23 1.595716 33 0.012271 62 4 0 3DFACE 8 0 10 -3.631692 20 3.455000 30 0.018325 11 -1.524000 21 -2.266279 31 0.000489 12 -3.936492 22 3.150200 32 0.018417 13 -3.936492 23 3.150200 33 0.018417 62 4 0 3DFACE 8 0 10 -1.371600 20 1.238921 30 0.610089 11 -1.828800 21 -0.437479 31 0.000489 12 -1.589602 22 1.595716 32 0.012271 13 -1.589602 23 1.595716 33 0.012271 62 4 0 3DFACE 8 0 10 -1.219200 20 -1.809079 30 0.610089 11 -1.828800 21 -0.437479 31 0.000489 12 -1.371600 22 -0.437479 32 0.610089 13 -1.371600 23 -0.437479 33 0.610089 62 4 0 3DFACE 8 0 10 -0.762000 20 -0.589879 30 0.914889 11 -1.219200 21 -1.809079 31 0.610089 12 -1.371600 22 -0.437479 32 0.610089 13 -1.371600 23 -0.437479 33 0.610089 62 4 0 3DFACE 8 0 10 -0.762000 20 -2.266279 30 0.610089 11 -1.524000 21 -2.266279 31 0.000489 12 -1.219200 22 -1.809079 32 0.610089 13 -1.219200 23 -1.809079 33 0.610089 62 4 0 3DFACE 8 0 10 -1.467700 20 2.235796 30 0.010004 11 0.000031 21 -5.353721 31 0.000704 12 0.000011 22 3.729320 32 0.000000 13 0.000011 23 3.729320 33 0.000000 62 4 0 3DFACE 8 0 10 -3.936492 20 3.150200 30 0.018417 11 -1.589602 21 1.595716 31 0.012271 12 -3.631692 22 3.455000 32 0.018325 13 -3.631692 23 3.455000 33 0.018325 62 3 0 3DFACE 8 0 10 -1.589602 20 1.595716 30 0.012271 11 0.000031 21 -5.353721 31 0.000704 12 -1.467700 22 2.235796 32 0.010004 13 -1.467700 23 2.235796 33 0.010004 62 4 0 3DFACE 8 0 10 0.000031 20 -5.353721 30 0.000704 11 -3.936492 21 3.150200 31 0.018417 12 -3.936492 22 2.723480 32 0.018509 13 -3.936492 23 2.723480 33 0.018509 62 2 0 3DFACE 8 0 10 -1.219200 20 4.439321 30 1.676889 11 0.000011 21 3.729320 31 0.000000 12 -0.304800 22 2.427640 32 0.396729 13 -0.304800 23 2.427640 33 0.396729 62 3 0 ENDSEC 0 EOF acm-6.0_20200416/objects/aircraft/b-747.obv0000644000000000000000000000652713156507735016315 0ustar rootrootobject 148 14 1 66.1 0.0 35.5 2 106.8 0.0 30.3 3 111.3 0.0 25.8 4 112.6 0.0 18.7 5 96.4 0.0 11.6 6 89.4 0.0 5.8 7 71.3 0.0 3.9 8 22.3 0.0 4.5 9 11.3 0.0 8.4 10 -75.8 0.0 9.0 11 -119.0 0.0 -27.1 12 -133.8 0.0 -27.1 13 -120.9 0.0 6.4 14 -126.1 0.0 7.1 15 -124.8 0.0 16.1 16 -59.6 0.0 33.5 17 -46.7 0.0 34.8 18 113.6 0.6 22.6 19 111.7 3.2 22.6 20 83.9 10.3 22.6 21 74.3 11.6 22.6 22 -66.3 11.0 22.6 23 -65.7 -12.3 22.6 24 71.7 -12.3 22.6 25 83.3 -10.3 22.6 26 111.0 -3.2 22.6 27 113.6 0.0 22.6 28 -81.2 0.0 12.9 29 -115.4 39.3 12.9 30 -122.5 38.7 12.9 31 -116.0 0.6 12.9 32 -124.4 -38.1 12.9 33 -116.7 -39.3 12.9 34 -82.5 -2.6 12.9 35 69.0 12.4 20.4 36 69.0 10.7 26.6 37 69.0 6.2 31.1 38 69.0 0.0 32.8 39 69.0 -6.2 31.1 40 69.0 -10.7 26.6 41 69.0 -12.4 20.4 42 69.0 -10.7 14.2 43 69.0 -6.2 9.7 44 69.0 0.0 8.0 45 69.0 6.2 9.7 46 69.0 10.7 14.2 47 13.2 11.9 23.5 48 13.2 10.3 29.4 49 13.2 5.9 33.8 50 13.2 0.0 35.4 51 13.2 -5.9 33.8 52 13.2 -10.3 29.4 53 13.2 -11.9 23.5 54 13.2 -10.3 17.5 55 13.2 -5.9 13.2 56 13.2 0.0 11.6 57 13.2 5.9 13.2 58 13.2 10.3 17.5 59 -47.0 11.9 21.3 60 -47.0 10.2 27.5 61 -47.0 5.6 32.1 62 -47.0 -0.6 33.8 63 -47.0 -6.9 32.1 64 -47.0 -11.5 27.5 65 -47.0 -13.2 21.3 66 -47.0 -11.5 15.0 67 -47.0 -6.9 10.4 68 -47.0 -0.6 8.8 69 -47.0 5.6 10.4 70 -47.0 10.2 15.0 71 38.1 -1.3 27.7 72 36.8 -13.5 27.7 73 -50.2 -113.5 27.7 74 -62.5 -114.2 27.7 75 -26.4 -47.7 27.7 76 -15.4 -12.9 27.7 77 -14.8 -1.3 27.7 78 -125.7 -25.8 23.9 79 -125.7 -25.8 23.9 80 -125.7 -25.8 23.9 81 -125.7 -25.8 23.9 82 -125.7 -25.8 23.9 83 -125.7 -25.8 23.9 84 -125.7 -25.8 23.9 85 -125.7 -25.8 23.9 86 -125.7 -25.8 23.9 87 -125.7 -25.8 23.9 88 -125.7 -25.8 23.9 89 -125.7 -25.8 23.9 90 -61.8 11.6 15.5 91 -123.8 0.0 15.5 92 -61.2 -11.6 15.5 93 -61.2 11.6 15.5 94 23.3 48.8 35.5 95 23.3 48.3 37.6 96 23.3 46.7 39.2 97 23.3 44.5 39.8 98 23.3 42.3 39.2 99 23.3 40.8 37.6 100 23.3 40.2 35.5 101 23.3 40.8 33.3 102 23.3 42.3 31.7 103 23.3 44.5 31.1 104 23.3 46.7 31.7 105 23.3 48.3 33.3 106 23.3 -40.5 34.8 107 23.3 -41.1 37.2 108 23.3 -42.8 38.9 109 23.3 -45.1 39.5 110 23.3 -47.5 38.9 111 23.3 -49.2 37.2 112 23.3 -49.8 34.8 113 23.3 -49.2 32.5 114 23.3 -47.5 30.8 115 23.3 -45.1 30.2 116 23.3 -42.8 30.8 117 23.3 -41.1 32.5 118 2.0 -81.1 34.8 119 2.0 -81.8 37.2 120 2.0 -83.5 38.9 121 2.0 -85.8 39.5 122 2.0 -88.1 38.9 123 2.0 -89.8 37.2 124 2.0 -90.4 34.8 125 2.0 -89.8 32.5 126 2.0 -88.1 30.8 127 2.0 -85.8 30.2 128 2.0 -83.5 30.8 129 2.0 -81.8 32.5 130 2.7 82.6 34.8 131 2.7 81.9 37.4 132 2.7 80.0 39.3 133 2.7 77.4 40.0 134 2.7 74.8 39.3 135 2.7 72.9 37.4 136 2.7 72.2 34.8 137 2.7 72.9 32.2 138 2.7 74.8 30.3 139 2.7 77.4 29.6 140 2.7 80.0 30.3 141 2.7 81.9 32.2 142 38.1 0.6 27.7 143 38.1 13.5 27.7 144 -48.9 114.8 27.7 145 -64.4 114.8 27.7 146 -28.3 47.7 27.7 147 -15.4 12.9 27.7 148 -14.8 0.6 27.7 gray77 17 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 gray77 10 18 19 20 21 22 23 24 25 26 27 gray77 7 28 29 30 31 32 33 34 gray77 12 35 36 37 38 39 40 41 42 43 44 45 46 gray77 12 47 48 49 50 51 52 53 54 55 56 57 58 gray77 12 59 60 61 62 63 64 65 66 67 68 69 70 gray77 7 71 72 73 74 75 76 77 gray77 12 78 79 80 81 82 83 84 85 86 87 88 89 gray77 4 90 91 92 93 gray77 12 94 95 96 97 98 99 100 101 102 103 104 105 gray77 12 106 107 108 109 110 111 112 113 114 115 116 117 gray77 12 118 119 120 121 122 123 124 125 126 127 128 129 gray77 12 130 131 132 133 134 135 136 137 138 139 140 141 gray77 7 142 143 144 145 146 147 148 acm-6.0_20200416/objects/aircraft/b-747.txt0000644000000000000000000001331513173125412016322 0ustar rootrootaircraft "B-747" { # see http://books.elsevier.com/companions/034074152X/appendices/data-a/table-3/table.htm # see http://www.faqs.org/faqs/aviation/flight-simulators/ Description "Boeing 747-400" Object "b-747.obv" WingArea 5500.0 # (wingS) Wing surface area (ft^2) WingHalfSpan 98 # (wings) Wing half-span (ft) WingHeight 0.0 # (wingh) Height of the wing aerodyn. center above CM (ft) Chord 27.3 # (c) Mean geometric chord of wing (ft) AspectRatio 6.96 # (aspectRatio) aspect ratio EmptyWeight 370000 #(emptyWeight) Empty weight (well, actually mass) (lb) # Max. wing load (lbf): MaxLoadZPositive 1.2e6 # 1.5*MTOW (1.5 g) MaxLoadZNegative 4.0e5 # 0.5*MTOW (0.5 g) DISEntityType 1:2:225:88:34:1:2 DISAltEntityType 1:2:225:88:34:1:2 # (I(x,y,z)) Moments of inertia (lb ft^2) Ixx 19000000 Iyy 25000000 Izz 25000000 # (cFlap) Lift due to flaps (yields Clift of 1.0 at max extension) CFlap 0.64279 BetaStall 15.0 # (deg) CFlapDrag 0.0467 # (cFlapDrag) Drag due to Flaps CGearDrag 0.03 # (cGearDrag) Drag due to Gear CSpeedBrake 0.03 # (cSpeedBrake) Drag due to Speed Brake # at 90 degrees # (CDb) Drag Characteristic equation [Wave+body] # independent variable is mach number CDb { # (CDb) Drag Characteristic equation [Wave+body] # independent variable is mach number 0.0, 0.020, 0.2, 0.020, 0.95, 0.015, 1.05, 0.045, 2.00, 0.030, 10.0, 0.030 } CLift { # (CLift) Lift-slope curve (vs alpha) -3.0, 0.0, -1.05, 0.0, -0.3316, -1.65, -0.2967, -1.7, -0.2618, -1.65, 0.2618, 1.65, # 15 DEG (CLmax, stall begin) 0.2967, 1.2, # 17 DEG 0.3316, 0.8, # 19 DEG 1.05, 0.0, 2.0, 0.0 } CnBeta { # (CnBeta) Yaw due to sideslip equation 0, -0.08125, 0.523540, -0.078125, 0.785340, -0.0609375, 1.047198, 0.125, 1.58, 0.0 } ClBeta { # (ClBeta) Roll due to sideslip equation 0, -0.0125, 0.43633, -0.015, 0.78540, 0.125, 1.58, 0.0, 3.142, 0.125, } CDBOrigin 0 # (CDBOrigin, CDBFactor) Drag due to sideslip CDBFactor 0.5 CDBPhase 0 # (CDBPhase) sideslip drag phase (deg) CYBeta -1.0 # (CYbeta) Side-force from side-slip [dCY/dBeta] EffElevator 1.0 # (effElevator) Elevator effectiveness EffRudder 1.0 # (effRudder) Rudder effectiveness MaxRudder 20 # (maxRudder) max Rudder (deg) MaxAileron 30 # (maxAileron) max Aileron (deg) MaxFlap 40 # (maxFlap) max flap setting (deg) # (flapRate) flap extension rate FlapRate 4 # (deg/sec) MaxSpeedBrake 80 # (maxSpeedBrake) max Speed Brake setting (deg) # (speedBrakeRate) rate of speed brake extension (4 secs to full ext) SpeedBrakeRate 20 # (deg/sec) # (speedBrakeIncr) speed Brake increment per keystroke SpeedBrakeIncr 20 # (deg) Clda 0.048 # (Clda) roll moment from aileron offset Cldr 0.004 # (Cldr) roll moment from rudder offset Clp -0.27 # (Clp) roll damping Cmq -8.0 # (Cmq) pitch damping factor Cnr -1.0 # (Cnr) yaw damping factor CmAlpha -0.30 # (cmSlope) CmAlpha curve slope MaxFuel 360000 # (maxFuel) maximum internal fuel (lb) EngineType "GenericJetEngine" # engine lag factor (how fast does it respond to throttle changes) EngineLag -4.0 # (maxThrust) max static thrust, military power (lbf) MaxThrust 200000 # (maxABThrust) max static thrust, afterburner on (lbf) MaxABThrust 200000 Thrust { # (Thrust) Mach Number vs. thrust 0, 1, 1.7, 1.5, 2.0, 0.84, 5, 0.5 } ABThrust { # (Thrust) Mach Number vs. thrust 0, 1, 1.7, 1.5, 2.0, 0.84, 5, 0.5 } HasThrustReverser 1 # (hasThrustReverser) 0=no, otherwise yes # (spFuelConsump) specific fuel consump(lb fuel/lb T x hr) SpFuelConsump 0.6 # (spABFuelConsump) AB specific fuel consump(lb fuel/lb T x hr) SpABFuelConsump 0.6 # (viewPoint) pilot's viewing location wrt CM ViewPoint { 94, -3, -15.3 } # Landing Gear control parameters MuStatic 0.08 # (muStatic) static coeff of friction no-brakes MuKinetic 0.05 # (muKinetic) moving coeff of friction no-brakes MuBStatic 0.40 # (muBStatic) static brakes-on MuBKinetic 0.30 # (muBKinetic) moving brakes-on MaxNWDef 40 # (maxNWDef) maximum nosewheel deflection (deg) # (gearRate) gear extension rate (about 3 secs to fully extend gear) GearRate 10 # (deg/sec) # (rn) location of nose gear attachments Rn { 85.7, 0, 1 } # (rm) location of right main gear attachments Rm { -6, 18, 2.7 } Gn 12.2 # nose strut length with tire (ft) Gm 12.2 # main strut length with tire (ft) CnMax 7.0 # (cnMax) nose max oleo extension distance (ft) CmMax 5.0 # (cmMax) main max oleo extension distance (ft) Kn 25000 # nose oleo spring factor (lbf/ft) Km 230000 # main oleo spring factor (lbf/ft) Dn 4000 # nose oleo damping factor (lbf s/ft) Dm 80000 # main oleo damping factor (lbf s/ft) # (tailExtent) as we rotate, this part may drag TailExtent { -100.0, 0.0, -30.0 } # Speed limits at MTOW. Leave undefined or set to 0 if unknown. MTOW 800000.0 # maximum takeoff weight (lb) #Vs0 42.0 # stall speed, full flaps (KIAS) #Vs1 50.0 # stall speed, no flaps (KIAS) Vfe 220.0 # max speed with flaps extended (KIAS) #Vno 145.0 # normal operation speed (KIAS) Vne 535.0 # never exceed speed (KIAS) StructurePoints 1 # (structurePts) maximum structural damage RadarOutput 0 # (radarOutput) radar output (watts) RadarTRange 0 # (radarTRange) tracking radar range (NM) RadarDRange 0 # (radarDRange) detection radar range (NM) TEWSThreshold 0 # Radar Warning Receiver threshold (watts) # Weapons WeaponCount 0 }acm-6.0_20200416/objects/aircraft/ufo.txt0000644000000000000000000001534413173125412016357 0ustar rootroot# Intended to become a very fast, pretty unkillable aircraft to be used for # testing. Acm uses this one to display something when a remote DIS entity # is not listed in the inventory nor in the objects map. # Currently basically a very light, MiG 29 with zero fuel consumption, # super powerful AB, and thrust reverse to hover! aircraft "UFO" { Description "UFO - Unidentified Flying Object" Object "ufo.obv" WingArea 400.0 # (wingS) Wing surface area (ft^2) WingHalfSpan 18.87 # (wings) Wing half-span (ft) WingHeight 0.0 # (wingh) Height of the wing aerodyn. center above CM (ft) Chord 9.61 # (c) Mean geometric chord of wing (ft) AspectRatio 3.56 # (aspectRatio) aspect ratio EmptyWeight 5000 # (emptyWeight) Empty weight (well, actually mass) (lb) # Max. wing load (lbf): MaxLoadZPositive 273000 # 10*(EmptyWeight+50%*MaxFuel) (+10 g) MaxLoadZNegative 137000 # 5*(EmptyWeight+50%*MaxFuel) (-5 g) DISEntityType 255:255:255:255:255:255:255 DISAltEntityType 255:255:255:255:255:255:255 # (I(x,y,z)) Moments of inertia (lb ft^2): Ixx 4000.0 Iyy 4000.0 Izz 4000.0 # (cFlap) Lift due to flaps (yields Clift of 1.0 at max extension) CFlap 0.64279 BetaStall 15.0 # (deg) CFlapDrag 0.0467 # (cFlapDrag) Drag due to Flaps CGearDrag 0.03 # (cGearDrag) Drag due to Gear CSpeedBrake 0.03 # (cSpeedBrake) Drag due to Speed Brake # at 90 degrees # (CDb) Drag Characteristic equation [Wave+body] # independent variable is mach number CDb { # (CDb) Drag Characteristic equation [Wave+body] # independent variable is mach number 0.0, 0.010, 0.2, 0.010, 0.95, 0.007, 1.05, 0.022, 2.00, 0.015, 10.0, 0.015 } CLift { # (CLift) Lift-slope curve (vs alpha) -3.0, 0.0, -1.05, 0.0, -0.576, -2.199, -0.556, -2.23, -0.524, -2.199, 0.524, 2.199, 0.556, 2.23, 0.576, 2.199, 1.05, 0.0, 2.0, 0.0 } CnBeta { # (CnBeta) Yaw due to sideslip equation 0, -0.08125, 0.523540, -0.078125, 0.785340, -0.0609375, 1.047198, 0.125, 1.58, 0.0 } ClBeta { # (ClBeta) Roll due to sideslip equation 0, -0.0125, 0.43633, -0.015, 0.78540, 0.125, 1.58, 0.0, 3.142, 0.125, } CDBOrigin 0 # (CDBOrigin, CDBFactor) Drag due to sideslip CDBFactor 0.5 CDBPhase 0 # (CDBPhase) sideslip drag phase (deg) CYBeta -1.4 # (CYbeta) Side-force from side-slip [dCY/dBeta] EffElevator 0.60 # (effElevator) Elevator effectiveness EffRudder 0.14 # (effRudder) Rudder effectiveness MaxRudder 20 # (maxRudder) max Rudder (deg) MaxAileron 20 # (maxAileron) max Aileron (deg) MaxFlap 20 # (maxFlap) max flap setting (deg) # (flapRate) flap extension rate (about 2 secs to fully extend flaps) FlapRate 10 # (deg/sec) # (gearRate) gear extension rate (about 3 secs to fully extend gear) GearRate 30 # (deg/sec) MaxSpeedBrake 80 # (maxSpeedBrake) max Speed Brake setting (deg) # (speedBrakeRate) rate of speed brake extension (2 secs to full ext) SpeedBrakeRate 40 # (deg/sec) # (speedBrakeIncr) speed Brake increment per keystroke SpeedBrakeIncr 80 # (deg) Clda 0.048 # (Clda) roll moment from aileron offset Cldr 0.004 # (Cldr) roll moment from rudder offset Clp -0.27 # (Clp) roll damping Cmq -8.0 # (Cmq) pitch damping factor Cnr -0.378 # (Cnr) yaw damping factor CmAlpha -0.40 # (cmSlope) CmAlpha curve slope EngineType "GenericRocketEngine" MaxFuel 1 # (maxFuel) maximum internal fuel (lb) # engine lag factor (how fast does it respond to throttle changes) EngineLag -3.0 # Engine data based on updated RD-33K engines cited in [AirI Aug89]. # (maxThrust) max static thrust, military power (lbf) MaxThrust 5000 # (maxABThrust) max static thrust, afterburner on (lbf) MaxABThrust 50000 Thrust { # (Thrust) Mach Number vs. thrust 0, 1, 1.7, 1.5, 2.0, 0.84, 5, 0.5 } ABThrust { # (ABThrust) afterburner thrust table 0, 1, 0.5, 1, 1, 1.21, 1.7, 1.7, 5, 1.64 } HasThrustReverser 1 # (hasThrustReverser) 0=no, otherwise yes # (spFuelConsump) specific fuel consump(lb fuel/lb T x hr) SpFuelConsump 0 # (spABFuelConsump) AB specific fuel consump(lb fuel/lb T x hr) SpABFuelConsump 0 # (viewPoint) pilot's viewing location wrt CM ViewPoint { 0, 0, -15 } # Landing Gear control parameters MuStatic 0.08 # (muStatic) static coeff of friction no-brakes MuKinetic 0.05 # (muKinetic) moving coeff of friction no-brakes MuBStatic 0.7 # (muBStatic) static brakes-on MuBKinetic 0.6 # (muBKinetic) moving brakes-on MaxNWDef 90 # (maxNWDef) maximum nosewheel deflection (deg) # (rn) location of nose gear attachments vs. CM (ft) Rn { 15, 0, 0 } Gn 3.0 # nose strut length with tire (ft) CnMax 2 # (cnMax) nose max oleo extension distance (ft) Kn 1000 # nose oleo spring factor (lbf/ft) Dn 100 # nose oleo damping factor (lbf s/ft) # (rm) location of right main gear attachments vs. CM (ft) Rm { -2.0, 9, 0 } Gm 3.0 # main strut length with tire (ft) CmMax 2 # (cmMax) main max oleo extension distance (ft) Km 3000 # main oleo spring factor (lbf/ft) Dm 300 # main oleo damping factor (lbf s/ft) # (tailExtent) as we rotate, this part may drag TailExtent { -5, 0.0, 0 } # Speed limits at MTOW. Leave undefined or set to 0 if unknown. MTOW 10000.0 # maximum takeoff weight (lb) #Vs0 42.0 # stall speed, full flaps (KIAS) #Vs1 50.0 # stall speed, no flaps (KIAS) #Vfe 100.0 # max speed with flaps extended (KIAS) #Vno 145.0 # normal operation speed (KIAS) #Vne 164.0 # never exceed speed (KIAS) StructurePoints 100000 # (structurePts) maximum structural damage # Radar data based on N-019 Pulse Doppler radar cited in [AirI Aug89]. RadarOutput 15000 # (radarOutput) radar output (watts) RadarTRange 38 # (radarTRange) tracking radar range (NM) RadarDRange 55 # (radarDRange) detection radar range (NM) TEWSThreshold 0 # Radar Warning Receiver threshold (watts) # Weapons WeaponCount 9 HardPoint0 { 7.0, -4.0, 0.0 } HardPoint1 { 0.357, 15.6, 0.0 } HardPoint2 { 0.357, -15.6, 0.0 } HardPoint3 { 1.5, 9.0, 2.0 } HardPoint4 { 1.5, -9.0, 2.0 } HardPoint5 { 1.5, 8.0, 1.5 } HardPoint6 { 1.5, -8.0, 1.5 } HardPoint7 { 1.5, 10.0, 1.5 } HardPoint8 { 1.5, -10.0, 1.5 } WeaponStation 0 "M61A1" 5000 0 0 WeaponStation 1 "MK82" 0 0 0 WeaponStation 2 "MK82" 0 0 0 WeaponStation 3 "AIM-9M" 0 0 0 WeaponStation 4 "AIM-9M" 0 0 0 WeaponStation 5 "AIM-9M" 0 0 0 WeaponStation 6 "AIM-9M" 0 0 0 WeaponStation 7 "AIM-120" 0 0 0 WeaponStation 8 "AIM-120" 0 0 0 }acm-6.0_20200416/objects/aircraft/f18.obv0000644000000000000000000001216410357223037016133 0ustar rootrootF-18-RBR 180 22 1 -19.9856 -1.71 1.60312 2 -13.3594 -1.71 2.24437 3 0.534375 -1.71 1.81688 4 1.38938 -1.71 1.60312 5 1.60312 -1.71 -0.748125 6 -0.320625 -1.71 -1.38938 7 -5.66437 -1.71 -1.81688 8 -12.2906 -1.71 -2.24437 9 -18.7031 -1.71 -2.03063 10 -22.3369 -1.71 -1.92375 11 -23.6194 -1.71 -1.49625 12 -23.6194 -1.71 0.4275 13 -23.6194 1.71 0.4275 14 -23.6194 1.71 -1.49625 15 -22.3369 1.71 -1.92375 16 -18.7031 1.71 -2.03063 17 -12.2906 1.71 -2.24437 18 -5.66437 1.71 -1.81688 19 -0.320625 1.71 -1.38938 20 1.60312 1.71 -0.748125 21 1.38938 1.71 1.60312 22 0.534375 1.71 1.81688 23 -13.3594 1.71 2.24437 24 -19.9856 1.71 1.60312 25 1.2825 0 0 26 2.03063 -3.63375 0 27 -19.1306 -3.8475 0 28 -21.6956 -3.42 0 29 -23.6194 -2.565 0 30 -23.6194 -1.06875 0 31 -21.6956 0 0 32 -21.6956 0 0 33 -23.6194 1.06875 0 34 -23.6194 2.565 0 35 -21.6956 3.42 0 36 -19.1306 3.8475 0 37 2.03063 3.63375 0 38 1.2825 0 0 39 -10.7944 -18.3825 -0.162309 40 -11.4356 -2.9925 -1.2825 41 1.60312 -4.06125 -1.2825 42 -4.80938 -18.1687 -0.21375 43 -4.80938 18.1687 -0.21375 44 1.60312 4.06125 -1.2825 45 -11.4356 2.9925 -1.2825 46 -10.7944 18.3825 -0.162309 47 18.9169 1.71 -2.35125 48 17.4206 2.77875 -2.1375 49 14.4281 3.20625 -1.92375 50 11.6494 3.42 -1.74817 51 7.37437 4.06125 -1.439 52 4.59563 4.48875 -1.2367 53 1.38938 4.7025 -1.03821 54 -11.4356 3.52687 -0.498114 55 -13.7869 1.06875 -0.67942 56 -13.7869 -1.06875 -0.67942 57 -11.4356 -3.52687 -0.498114 58 1.38938 -4.7025 -1.03821 59 4.59563 -4.48875 -1.2367 60 7.37437 -4.06125 -1.439 61 11.6494 -3.42 -1.74817 62 14.4281 -3.20625 -1.92375 63 17.4206 -2.77875 -2.1375 64 18.9169 -1.71 -2.35125 65 -13.68 -2.77875 0 66 -15.8175 -4.48875 0 67 -14.7487 -4.48875 0 68 -22.23 -10.6875 0 69 -24.795 -10.4737 0 70 -25.2225 -10.0463 0 71 -25.4363 -9.19125 0 72 -22.4437 -3.42 0 73 -21.8025 -3.20625 0 74 -21.8025 3.20625 0 75 -22.4437 3.42 0 76 -25.4363 9.19125 0 77 -25.2225 10.0463 0 78 -24.795 10.4737 0 79 -22.23 10.6875 0 80 -14.7487 4.48875 0 81 -15.8175 4.48875 0 82 -13.68 2.77875 0 83 -21.4819 0 0 84 -14.8556 -0.855 0 85 -6.09187 -1.49625 0 86 4.59563 -1.92375 0 87 19.5581 -1.71 0 88 22.7644 -1.71 0 89 26.6119 -1.49625 0 90 29.1769 -0.855 0 91 30.0319 0 0 92 30.0319 0 0 93 29.1769 0.855 0 94 26.6119 1.49625 0 95 22.7644 1.71 0 96 19.5581 1.71 0 97 4.59563 1.92375 0 98 -6.09187 1.49625 0 99 -14.8556 0.855 0 100 -21.4819 0 0 101 -13.68 -2.77875 0 102 -15.8175 -4.48875 0 103 -14.7487 -4.48875 0 104 -22.23 -10.6875 0 105 -24.795 -10.4737 0 106 -25.2225 -10.0463 0 107 -25.4363 -9.19125 0 108 -22.4437 -3.42 0 109 -21.8025 -3.20625 0 110 -21.8025 3.20625 0 111 -22.4437 3.42 0 112 -25.4363 9.19125 0 113 -25.2225 10.0463 0 114 -24.795 10.4737 0 115 -22.23 10.6875 0 116 -14.7487 4.48875 0 117 -15.8175 4.48875 0 118 -13.68 2.77875 0 119 30.5663 0 0.106875 120 28.0012 0 0.748125 121 25.65 0 1.17562 122 20.9475 0 1.17562 123 4.48875 0 1.17562 124 -20.7338 0 0.534375 125 -21.1612 0 -0.534375 126 30.5663 0 0.106875 127 28.4288 0 -1.38938 128 25.2225 0 -2.03063 129 20.0925 0 -3.09937 130 15.8175 0 -5.02313 131 12.3975 0 -5.66437 132 10.0463 0 -5.45062 133 7.90875 0 -5.02313 134 4.06125 0 -4.38187 135 -1.49625 0 -3.95437 136 -7.90875 0 -3.31312 137 -21.5888 0 -0.534375 138 -21.5888 0 -0.106875 139 -16.8863 3.43518 -1.81688 140 -18.1687 5.77125 -9.405 141 -14.9625 5.77125 -9.61875 142 -8.1225 3.42 -2.35125 143 -8.1225 -3.42 -2.35125 144 -14.9625 -5.77125 -9.61875 145 -18.1687 -5.77125 -9.405 146 -16.8863 -3.43518 -1.81688 147 -3.31312 0.21375 1.38938 148 -3.31312 -1.2825 2.03063 149 -3.31312 -3.42 1.81688 150 -3.31312 -4.06125 0.748125 151 -3.31312 -4.06125 -0.748125 152 -3.31312 -4.48875 -1.17562 153 -3.31312 -3.20625 -1.81688 154 -3.31312 -1.92375 -2.45812 155 -3.31312 0 -3.09937 156 -3.31312 0 -3.09937 157 -3.31312 1.92375 -2.45812 158 -3.31312 3.20625 -1.81688 159 -3.31312 4.48875 -1.17562 160 -3.31312 4.06125 -0.748125 161 -3.31312 4.06125 0.748125 162 -3.31312 3.42 1.81688 163 -3.31312 1.2825 2.03063 164 -3.31312 -0.21375 1.38938 165 12.5044 0 1.38938 166 12.2906 -1.06875 1.17562 167 12.0769 -2.1375 0.106875 168 12.0341 -2.35125 -1.17562 169 12.1196 -1.92375 -2.24437 170 12.1624 -1.71 -3.31312 171 12.3334 -0.855 -4.38187 172 12.5044 0 -5.02313 173 12.5044 0 -5.02313 174 12.3334 0.855 -4.38187 175 12.1624 1.71 -3.31312 176 12.1196 1.92375 -2.24437 177 12.0341 2.35125 -1.17562 178 12.0769 2.1375 0.106875 179 12.2906 1.06875 1.17562 180 12.5044 0 1.38938 gray44 12 1 2 3 4 5 6 7 8 9 10 11 12 gray44 12 13 14 15 16 17 18 19 20 21 22 23 24 gray44 7 25 26 27 28 29 30 31 gray44 7 32 33 34 35 36 37 38 gray44 4 39 40 41 42 gray44 4 43 44 45 46 gray44 9 47 48 49 50 51 52 53 54 55 gray44 9 56 57 58 59 60 61 62 63 64 gray44 9 65 66 67 68 69 70 71 72 73 gray44 9 74 75 76 77 78 79 80 81 82 gray44 9 83 84 85 86 87 88 89 90 91 gray44 9 92 93 94 95 96 97 98 99 100 gray44 9 101 102 103 104 105 106 107 108 109 gray44 9 110 111 112 113 114 115 116 117 118 gray44 7 119 120 121 122 123 124 125 gray44 13 126 127 128 129 130 131 132 133 134 135 136 137 138 gray44 4 139 140 141 142 gray44 4 143 144 145 146 gray44 9 147 148 149 150 151 152 153 154 155 gray44 9 156 157 158 159 160 161 162 163 164 gray44 8 165 166 167 168 169 170 171 172 gray44 8 173 174 175 176 177 178 179 180 acm-6.0_20200416/objects/aircraft/md81.txt0000644000000000000000000001325613173125412016337 0ustar rootrootaircraft "MD-81" { # EXPERIMENTAL - not finished yet # See also: http://www.md80.it/OLDFILES/downloads/MD80POH.html Description "McDonnel-Douglas MD-81" Object "ufo.obv" # FIXME WingArea 1270 # (wingS) Wing surface area (ft^2) WingHalfSpan 54 # (wings) Wing half-span (ft) WingHeight 1.0 # (wingh) Height of the wing aerodyn. center above CM (ft) Chord 15 # (c) Mean geometric chord of wing (ft) AspectRatio 9.18 # (aspectRatio) aspect ratio EmptyWeight 78432 # (emptyWeight) Empty weight (well, actually mass) (lb) # Max. wing load (lbf): MaxLoadZPositive 3.5e6 # 2.5*MTOW (+2.5 g at MTOW) MaxLoadZNegative 77500 # 0.5*(MTOW + 150*100) DISEntityType 1:2:225:87:32:2:1 DISAltEntityType 1:2:225:87:32:2:1 # (I(x,y,z)) Moments of inertia (lb ft^2) Ixx 0.5e6 Iyy 1.5e6 Izz 1.9e6 # (cFlap) Lift due to flaps (yields Clift of 1.0 at max extension) CFlap 0.8 BetaStall 15.0 # (deg) CFlapDrag 0.07 # (cFlapDrag) Drag due to Flaps CGearDrag 0.03 # (cGearDrag) Drag due to Gear CSpeedBrake 0.03 # (cSpeedBrake) Drag due to Speed Brake # at 90 degrees # (CDb) Drag Characteristic equation [Wave+body] # independent variable is mach number CDb { # (CDb) Drag Characteristic equation [Wave+body] # independent variable is mach number 0.0, 0.020, 0.2, 0.020, 0.95, 0.015, 1.05, 0.045, 2.00, 0.030, 10.0, 0.030 } CLift { # (CLift) Lift-slope curve (vs alpha) -3.0, 0.0, -1.05, 0.0, -0.3316, -1.65, -0.2967, -1.7, -0.2618, -1.65, 0.2618, 1.65, # 15 DEG (CLmax, stall begin) 0.2967, 1.2, # 17 DEG 0.3316, 0.8, # 19 DEG 1.05, 0.0, 2.0, 0.0 } CnBeta { # (CnBeta) Yaw due to sideslip equation 0, -0.08125, 0.523540, -0.078125, 0.785340, -0.0609375, 1.047198, 0.125, 1.58, 0.0 } ClBeta { # (ClBeta) Roll due to sideslip equation 0, -0.0125, 0.43633, -0.015, 0.78540, 0.125, 1.58, 0.0, 3.142, 0.125, } CDBOrigin 0 # (CDBOrigin, CDBFactor) Drag due to sideslip CDBFactor 0.5 CDBPhase 0 # (CDBPhase) sideslip drag phase (deg) CYBeta -1.0 # (CYbeta) Side-force from side-slip [dCY/dBeta] EffElevator 0.8 # (effElevator) Elevator effectiveness EffRudder 0.50 # (effRudder) Rudder effectiveness MaxRudder 20 # (maxRudder) max Rudder (deg) MaxAileron 25 # (maxAileron) max Aileron (deg) MaxFlap 30 # (maxFlap) max flap setting (deg) # (flapRate) flap extension rate FlapRate 4 # (deg/sec) MaxSpeedBrake 90 # (maxSpeedBrake) max Speed Brake setting (deg) # (speedBrakeRate) rate of speed brake extension (4 secs to full ext) SpeedBrakeRate 20 # (deg/sec) # (speedBrakeIncr) speed Brake increment per keystroke SpeedBrakeIncr 30 # (deg) Clda 0.048 # (Clda) roll moment from aileron offset Cldr 0.004 # (Cldr) roll moment from rudder offset Clp -0.27 # (Clp) roll damping Cmq -8.0 # (Cmq) pitch damping factor Cnr -1.0 # (Cnr) yaw damping factor CmAlpha -0.30 # (cmSlope) CmAlpha curve slope MaxFuel 39160 # (maxFuel) maximum internal fuel (lb) EngineType "GenericJetEngine" # engine lag factor (how fast does it respond to throttle changes) EngineLag -4.0 # (maxThrust) max static thrust, military power (lbf) MaxThrust 37000 # (maxABThrust) max static thrust, afterburner on (lbf) MaxABThrust 37000 Thrust { # (Thrust) Mach Number vs. thrust 0, 1, 1.7, 1.5, 2.0, 0.84, 5, 0.5 } ABThrust { # (Thrust) Mach Number vs. thrust 0, 1, 1.7, 1.5, 2.0, 0.84, 5, 0.5 } HasThrustReverser 1 # (hasThrustReverser) 0=no, otherwise yes # (spFuelConsump) specific fuel consump(lb fuel/lb T x hr) SpFuelConsump 0.6 # (spABFuelConsump) AB specific fuel consump(lb fuel/lb T x hr) SpABFuelConsump 0.6 # (viewPoint) pilot's viewing location wrt CM ViewPoint { 65, -3, -6 } # Landing Gear control parameters MuStatic 0.08 # (muStatic) static coeff of friction no-brakes MuKinetic 0.05 # (muKinetic) moving coeff of friction no-brakes MuBStatic 0.6 # (muBStatic) static brakes-on MuBKinetic 0.4 # (muBKinetic) moving brakes-on MaxNWDef 82 # (maxNWDef) maximum nosewheel deflection (deg) # (gearRate) gear extension rate: GearRate 10 # (deg/sec) # (rn) location of nose gear attachments Rn { 68, 0, 2 } # (rm) location of right main gear attachments Rm { -2, 8.33, 2 } Gn 6 # nose strut length with tire (ft) Gm 6 # main strut length with tire (ft) CnMax 3.0 # (cnMax) nose max oleo extension distance (ft) CmMax 3.0 # (cmMax) main max oleo extension distance (ft) Kn 7000 # nose oleo spring factor (lbf/ft) Km 88000 # main oleo spring factor (lbf/ft) Dn 1000 # nose oleo damping factor (lbf s/ft) Dm 15600 # main oleo damping factor (lbf s/ft) # (tailExtent) as we rotate, this part may drag TailExtent { 28, 0, 2.4 } # Speed limits at MTOW. Leave undefined or set to 0 if unknown. MTOW 140000.0 # maximum takeoff weight (lb) #Vs0 ?? # stall speed, full flaps (KIAS) #Vs1 ?? # stall speed, no flaps (KIAS) Vfe 235.0 # max speed with flaps extended (KIAS) Vno 340.0 # normal operation speed (KIAS) Vne 499.0 # never exceed speed (KIAS) StructurePoints 1 # (structurePts) maximum structural damage # Radar data based on N-019 Pulse Doppler radar cited in [AirI Aug89]. RadarOutput 0 # (radarOutput) radar output (watts) RadarTRange 0 # (radarTRange) tracking radar range (NM) RadarDRange 0 # (radarDRange) detection radar range (NM) TEWSThreshold 0 # Radar Warning Receiver threshold (watts) # Weapons WeaponCount 0 }acm-6.0_20200416/objects/aircraft/mig23.obv0000644000000000000000000000472210357223037016457 0ustar rootrootmig-23-wings-swept 88 10 1 36.5891 0 0 2 34.4368 0.86092 0 3 30.9931 1.29138 0 4 27.119 1.72184 0 5 20.6621 1.72184 0 6 18.9402 2.1523 0 7 14.2052 3.01322 0 8 -3.44368 2.58276 0 9 -9.03966 2.1523 0 10 -16.7879 0.86092 0 11 -18.0793 0.43046 0 12 -18.0793 0 0 13 36.5891 0 0 14 34.4368 -0.86092 0 15 30.9931 -1.29138 0 16 27.119 -1.72184 0 17 20.6621 -1.72184 0 18 18.9402 -2.1523 0 19 14.2052 -3.01322 0 20 -3.44368 -2.58276 0 21 -9.03966 -2.1523 0 22 -16.7879 -0.86092 0 23 -18.0793 -0.43046 0 24 -18.0793 0 0 25 14.2052 3.01322 -3.01322 26 4.73506 7.31782 -3.01322 27 6.02644 8.6092 -3.01322 28 -11.192 13.7747 -3.01322 29 -12.0529 13.7747 -3.01322 30 -14.2052 11.192 -3.01322 31 -14.2052 10.7615 -3.01322 32 -3.44368 2.58276 -3.01322 33 14.2052 -3.01322 -3.01322 34 4.73506 -7.31782 -3.01322 35 6.02644 -8.6092 -3.01322 36 -11.192 -13.7747 -3.01322 37 -12.0529 -13.7747 -3.01322 38 -14.2052 -11.192 -3.01322 39 -14.2052 -10.7615 -3.01322 40 -3.44368 -2.58276 -3.01322 41 -18.9402 3.01322 -1.72184 42 -20.2316 7.31782 -1.72184 43 -18.5098 8.6092 -1.72184 44 -9.03966 2.1523 -1.72184 45 -16.7879 0.86092 -1.72184 46 -18.9402 -3.01322 -1.72184 47 -20.2316 -7.31782 -1.72184 48 -18.5098 -8.6092 -1.72184 49 -9.03966 -2.1523 -1.72184 50 -16.7879 -0.86092 -1.72184 51 36.5891 0 0 52 33.1454 0 -1.29138 53 30.1322 0 -2.1523 54 25.8276 0 -2.58276 55 22.3839 0 -3.87414 56 18.0793 0 -4.3046 57 9.47012 0 -3.87414 58 -0.860918 0 -3.44368 59 -8.6092 0 -6.02644 60 -16.3575 0 -10.331 61 -18.9402 0 -9.03966 62 -18.0793 0 -3.87414 63 -19.8012 0 -3.44368 64 -17.2184 0 -1.72184 65 -18.0793 0 -1.72184 66 -18.0793 0 1.29138 67 -15.4966 0 1.72184 68 -6.4569 0 2.1523 69 10.331 0 2.1523 70 20.2316 0 1.72184 71 28.8408 0 1.29138 72 33.1454 0 0.86092 73 -15.4966 0 1.72184 74 -15.4966 0 4.3046 75 -13.3443 0 5.16552 76 -6.4569 0 2.1523 77 20.6621 1.72184 -3.01322 78 18.9402 2.1523 -3.01322 79 14.2052 3.01322 -3.01322 80 -3.44368 2.58276 -3.01322 81 -3.44368 -2.58276 -3.01322 82 14.2052 -3.01322 -3.01322 83 18.9402 -2.1523 -3.01322 84 20.6621 -1.72184 -3.01322 85 -3.44368 2.58276 -3.01322 86 -16.7879 0.86092 -1.72184 87 -16.7879 -0.86092 -1.72184 88 -3.44368 -2.58276 -3.01322 gray44 12 1 2 3 4 5 6 7 8 9 10 11 12 gray44 12 13 14 15 16 17 18 19 20 21 22 23 24 gray44 8 25 26 27 28 29 30 31 32 gray44 8 33 34 35 36 37 38 39 40 gray44 5 41 42 43 44 45 gray44 5 46 47 48 49 50 gray44 22 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 gray44 4 73 74 75 76 gray44 8 77 78 79 80 81 82 83 84 gray44 4 85 86 87 88 acm-6.0_20200416/objects/aircraft/kc135.obv0000644000000000000000000001711010357223037016357 0ustar rootrootobject 237 34 1 -24.141 0.135459 6.78832 2 -24.141 1.70305 6.78832 3 -24.141 3.89769 5.84776 4 -24.141 6.40584 1.77202 5 -24.141 7.03288 -1.67669 6 -24.141 5.7788 -5.75244 7 -24.141 4.52472 -7.94707 8 -24.141 -0.17806 -9.20115 9 -24.141 0.241181 -9.30906 10 -24.141 -4.4616 -8.05499 11 -24.141 -5.71568 -5.86035 12 -24.141 -6.96975 -1.78461 13 -24.141 -6.34272 1.6641 14 -24.141 -3.83457 5.73985 15 -24.141 -1.63993 6.6804 16 -24.141 -0.072338 6.6804 17 -54.8658 -1.88111 -3.76223 18 -72.1094 -22.5734 -7.83797 19 -80.2608 -22.5734 -7.83797 20 -71.4823 0 -3.3917 21 18.108 31.5999 4.00309 22 -2.60576 31.5999 4.00309 23 -2.60576 31.5999 5.06146 24 1.32532 31.5999 5.96863 25 9.79227 31.5999 6.57341 26 11.0018 31.5999 7.32939 27 17.9568 31.5999 6.8758 28 17.9923 31.5999 1.05837 29 11.0373 31.5999 0.604782 30 9.82771 31.5999 1.36076 31 1.36076 31.5999 1.96554 32 -2.57032 31.5999 2.87271 33 -2.57032 31.5999 3.93108 34 18.1435 31.5999 3.93108 35 18.1435 -31.5999 3.93108 36 -2.57032 -31.5999 3.93108 37 -2.57032 -31.5999 2.87271 38 1.36076 -31.5999 1.96554 39 9.82771 -31.5999 1.36076 40 11.0373 -31.5999 0.604782 41 17.9923 -31.5999 1.05837 42 17.9568 -31.5999 6.8758 43 11.0018 -31.5999 7.32939 44 9.79227 -31.5999 6.57341 45 1.32532 -31.5999 5.96863 46 -2.60576 -31.5999 5.06146 47 -2.60576 -31.5999 4.00309 48 18.108 -31.5999 4.00309 49 2.9232 -49.8885 6.40654 50 -4.03179 -49.8885 6.86012 51 -5.24135 -49.8885 6.10415 52 -13.7083 -49.8885 5.49936 53 -17.6394 -49.8885 4.59219 54 -17.6394 -49.8885 3.53382 55 3.0744 -49.8885 3.53382 56 3.10983 -49.8885 3.46182 57 -17.6039 -49.8885 3.46182 58 -17.6039 -49.8885 2.40345 59 -13.6729 -49.8885 1.49628 60 -5.20592 -49.8885 0.891493 61 -3.99635 -49.8885 0.135516 62 2.95864 -49.8885 0.589102 63 2.95864 49.8885 0.589102 64 -3.99635 49.8885 0.135516 65 -5.20592 49.8885 0.891493 66 -13.6729 49.8885 1.49628 67 -17.6039 49.8885 2.40345 68 -17.6039 49.8885 3.46182 69 3.10983 49.8885 3.46182 70 3.0744 49.8885 3.53382 71 -17.6394 49.8885 3.53382 72 -17.6394 49.8885 4.59219 73 -13.7083 49.8885 5.49936 74 -5.24135 49.8885 6.10415 75 -4.03179 49.8885 6.86012 76 2.9232 49.8885 6.40654 77 17.937 -29.8366 5.59983 78 17.937 -31.7615 6.12482 79 17.937 -33.249 5.68733 80 17.937 -34.5615 4.02488 81 17.937 -33.949 2.09994 82 17.937 -31.849 1.31246 83 17.937 -29.7491 2.18743 84 17.937 -28.9616 4.02488 85 46.7143 0.313519 6.5839 86 46.7143 1.88111 6.5839 87 46.7143 4.07575 5.64334 88 46.7143 6.5839 1.56759 89 46.7143 7.21094 -1.88111 90 46.7143 5.95686 -5.95686 91 46.7143 4.70278 -8.15149 92 46.7143 -0 -9.40557 93 46.7143 0 -9.40557 94 46.7143 -4.70278 -8.15149 95 46.7143 -5.95686 -5.95686 96 46.7143 -7.21094 -1.88111 97 46.7143 -6.5839 1.56759 98 46.7143 -4.07575 5.64334 99 46.7143 -1.88111 6.5839 100 46.7143 -0.313519 6.5839 101 2.17721 -1.41805 -2.54008 102 -11.9747 -5.98734 1.81435 103 23.7679 -6.16878 3.62869 104 72.5738 -0 -0.907173 105 72.5738 0 -0.907173 106 23.7679 6.16878 3.62869 107 -11.9747 5.98734 1.81435 108 2.17721 1.41805 -2.54008 109 -71.4823 -0 -3.3917 110 -80.2608 22.5734 -7.83797 111 -72.1094 22.5734 -7.83797 112 -54.8658 1.88111 -3.76223 113 -76.4986 -0 -4.35987 114 -44.2062 5.0163 -3.63486 115 -29.4708 5.95686 -3.31808 116 54.2388 6.5839 -1.56759 117 71.4823 2.19463 -1.25408 118 72.4229 0.313519 -1.25408 119 72.4229 -0.313519 -1.25408 120 71.4823 -2.19463 -1.25408 121 54.2388 -6.5839 -1.56759 122 -29.4708 -5.95686 -3.31808 123 -44.2062 -5.0163 -3.63486 124 -76.4986 0 -4.35987 125 -11.9137 6.27038 1.8973 126 -12.2272 11.6002 1.46206 127 -15.3624 28.8437 -0.0389337 128 -35.7412 73.3634 -4.45217 129 -28.8437 72.4229 -4.07575 130 -25.0815 70.5418 -3.76223 131 23.5139 6.27038 3.44871 132 23.5139 -6.27038 3.44871 133 -25.0815 -70.5418 -3.76223 134 -28.8437 -72.4229 -4.07575 135 -35.7412 -73.3634 -4.45217 136 -15.3624 -28.8437 -0.0389337 137 -12.2272 -11.6002 1.46206 138 -11.9137 -6.27038 1.8973 139 18.1841 -31.6654 4.07575 140 -2.82167 -31.3519 4.07575 141 -2.82167 -32.9195 4.07575 142 1.56759 -33.86 4.07575 143 10.3461 -34.1736 4.07575 144 11.6002 -34.8006 4.07575 145 18.1841 -34.4871 4.07575 146 18.1841 -28.8437 4.07575 147 11.6002 -28.5302 4.07575 148 10.3461 -29.1573 4.07575 149 1.56759 -29.4708 4.07575 150 -2.82167 -30.4113 4.07575 151 -2.82167 -31.9789 4.07575 152 18.1841 -31.6654 4.07575 153 3.13519 49.8495 3.44871 154 -17.8706 50.163 3.44871 155 -17.8706 48.5954 3.44871 156 -13.4813 47.6549 3.44871 157 -4.70278 47.3414 3.44871 158 -3.44871 46.7143 3.44871 159 3.13519 47.0278 3.44871 160 3.13519 52.6712 3.44871 161 -3.44871 52.9847 3.44871 162 -4.70278 52.3577 3.44871 163 -13.4813 52.0441 3.44871 164 -17.8706 51.1036 3.44871 165 -17.8706 49.536 3.44871 166 3.13519 49.8495 3.44871 167 3.13519 -49.8495 3.44871 168 -17.8706 -49.536 3.44871 169 -17.8706 -51.1036 3.44871 170 -13.4813 -52.0441 3.44871 171 -4.70278 -52.3577 3.44871 172 -3.44871 -52.9847 3.44871 173 3.13519 -52.6712 3.44871 174 3.13519 -47.0278 3.44871 175 -3.44871 -46.7143 3.44871 176 -4.70278 -47.3414 3.44871 177 -13.4813 -47.6549 3.44871 178 -17.8706 -48.5954 3.44871 179 -17.8706 -50.163 3.44871 180 3.13519 -49.8495 3.44871 181 72.7364 0 -1.25408 182 69.9147 0 -3.44871 183 65.839 0 -5.0163 184 58.3145 0 -8.15149 185 47.0278 0 -8.77853 186 -39.5034 0 -7.83797 187 -75.2445 0 -6.5839 188 -74.931 0 -3.13519 189 -45.4602 0 3.76223 190 -27.5897 0 5.95686 191 48.5954 0 5.64334 192 61.1362 0 4.38926 193 70.5418 0 1.25408 194 -45.1467 0 -6.89742 195 -48.909 0 -8.77853 196 -53.6117 0 -11.2867 197 -67.7201 0 -32.9195 198 -75.5581 0 -32.9195 199 -69.9147 0 -5.64334 200 18.1841 31.6654 4.07575 201 -2.82167 31.9789 4.07575 202 -2.82167 30.4113 4.07575 203 1.56759 29.4708 4.07575 204 10.3461 29.1573 4.07575 205 11.6002 28.5302 4.07575 206 18.1841 28.8437 4.07575 207 3.24076 47.1051 3.66201 208 3.24076 47.8926 1.82457 209 3.24076 49.9925 0.949592 210 3.24076 52.0924 1.73707 211 3.24076 52.7049 3.66201 212 3.24076 51.3925 5.32446 213 3.24076 49.905 5.76195 214 3.24076 47.9801 5.23696 215 3.24076 -47.9801 5.23696 216 3.24076 -49.905 5.76195 217 3.24076 -51.3925 5.32446 218 3.24076 -52.7049 3.66201 219 3.24076 -52.0924 1.73707 220 3.24076 -49.9925 0.949592 221 3.24076 -47.8926 1.82457 222 3.24076 -47.1051 3.66201 223 17.937 28.9616 4.02488 224 17.937 29.7491 2.18743 225 17.937 31.849 1.31246 226 17.937 33.949 2.09994 227 17.937 34.5615 4.02488 228 17.937 33.249 5.68733 229 17.937 31.7615 6.12482 230 17.937 29.8366 5.59983 231 18.1841 34.4871 4.07575 232 11.6002 34.8006 4.07575 233 10.3461 34.1736 4.07575 234 1.56759 33.86 4.07575 235 -2.82167 32.9195 4.07575 236 -2.82167 31.3519 4.07575 237 18.1841 31.6654 4.07575 gray44 8 1 2 3 4 5 6 7 8 gray44 8 9 10 11 12 13 14 15 16 gray44 4 17 18 19 20 gray44 7 21 22 23 24 25 26 27 gray44 7 28 29 30 31 32 33 34 gray44 7 35 36 37 38 39 40 41 gray44 7 42 43 44 45 46 47 48 gray44 7 49 50 51 52 53 54 55 gray44 7 56 57 58 59 60 61 62 gray44 7 63 64 65 66 67 68 69 gray44 7 70 71 72 73 74 75 76 gray44 8 77 78 79 80 81 82 83 84 gray44 8 85 86 87 88 89 90 91 92 gray44 8 93 94 95 96 97 98 99 100 gray44 4 101 102 103 104 gray44 4 105 106 107 108 gray44 4 109 110 111 112 gray44 6 113 114 115 116 117 118 gray44 6 119 120 121 122 123 124 gray44 7 125 126 127 128 129 130 131 gray44 7 132 133 134 135 136 137 138 gray44 7 139 140 141 142 143 144 145 gray44 7 146 147 148 149 150 151 152 gray44 7 153 154 155 156 157 158 159 gray44 7 160 161 162 163 164 165 166 gray44 7 167 168 169 170 171 172 173 gray44 7 174 175 176 177 178 179 180 gray44 13 181 182 183 184 185 186 187 188 189 190 191 192 193 gray44 6 194 195 196 197 198 199 gray44 7 200 201 202 203 204 205 206 gray44 8 207 208 209 210 211 212 213 214 gray44 8 215 216 217 218 219 220 221 222 gray44 8 223 224 225 226 227 228 229 230 gray44 7 231 232 233 234 235 236 237 acm-6.0_20200416/objects/aircraft/ufo.obv0000644000000000000000000000362713075373404016336 0ustar rootrootufo 72 16 1 15.56 15.56 0.00 2 0.00 0.00 -20.00 3 22.00 0.00 0.00 4 0.00 22.00 0.00 5 0.00 0.00 -20.00 6 15.56 15.56 0.00 7 -15.56 15.56 0.00 8 0.00 0.00 -20.00 9 0.00 22.00 0.00 10 -22.00 0.00 0.00 11 0.00 0.00 -20.00 12 -15.56 15.56 0.00 13 -15.56 -15.56 0.00 14 0.00 0.00 -20.00 15 -22.00 0.00 0.00 16 -0.00 -22.00 0.00 17 0.00 0.00 -20.00 18 -15.56 -15.56 0.00 19 15.56 -15.56 0.00 20 0.00 0.00 -20.00 21 -0.00 -22.00 0.00 22 22.00 -0.00 0.00 23 0.00 0.00 -20.00 24 15.56 -15.56 0.00 25 20.44 13.88 0.00 26 21.40 11.57 -4.33 27 23.31 6.95 -4.33 28 24.27 4.64 -0.00 29 23.31 6.95 4.33 30 21.40 11.57 4.33 31 4.64 24.27 0.00 32 6.95 23.31 -4.33 33 11.57 21.40 -4.33 34 13.88 20.44 -0.00 35 11.57 21.40 4.33 36 6.95 23.31 4.33 37 -13.88 20.44 0.00 38 -11.57 21.40 -4.33 39 -6.95 23.31 -4.33 40 -4.64 24.27 -0.00 41 -6.95 23.31 4.33 42 -11.57 21.40 4.33 43 -24.27 4.64 0.00 44 -23.31 6.95 -4.33 45 -21.40 11.57 -4.33 46 -20.44 13.88 -0.00 47 -21.40 11.57 4.33 48 -23.31 6.95 4.33 49 -20.44 -13.88 0.00 50 -21.40 -11.57 -4.33 51 -23.31 -6.95 -4.33 52 -24.27 -4.64 -0.00 53 -23.31 -6.95 4.33 54 -21.40 -11.57 4.33 55 -4.64 -24.27 0.00 56 -6.95 -23.31 -4.33 57 -11.57 -21.40 -4.33 58 -13.88 -20.44 -0.00 59 -11.57 -21.40 4.33 60 -6.95 -23.31 4.33 61 13.88 -20.44 0.00 62 11.57 -21.40 -4.33 63 6.95 -23.31 -4.33 64 4.64 -24.27 -0.00 65 6.95 -23.31 4.33 66 11.57 -21.40 4.33 67 24.27 -4.64 0.00 68 23.31 -6.95 -4.33 69 21.40 -11.57 -4.33 70 20.44 -13.88 -0.00 71 21.40 -11.57 4.33 72 23.31 -6.95 4.33 (gray44 clip) 3 1 2 3 (gray44 clip) 3 4 5 6 (gray44 clip) 3 7 8 9 (gray44 clip) 3 10 11 12 (gray44 clip) 3 13 14 15 (gray44 clip) 3 16 17 18 (gray44 clip) 3 19 20 21 (gray44 clip) 3 22 23 24 (red clip) 6 25 26 27 28 29 30 (red clip) 6 31 32 33 34 35 36 (red clip) 6 37 38 39 40 41 42 (red clip) 6 43 44 45 46 47 48 (green clip) 6 49 50 51 52 53 54 (green clip) 6 55 56 57 58 59 60 (green clip) 6 61 62 63 64 65 66 (green clip) 6 67 68 69 70 71 72 acm-6.0_20200416/objects/aircraft/c172.obv0000644000000000000000000001017210357223037016206 0ustar rootrootobject 128 23 1 0.602816 1.25587 1.20249 2 -0.0502347 7.58544 -2.16009 3 0.301408 7.58544 -2.16009 4 0.904225 1.1554 1.25587 5 0.904225 -1.1554 1.25587 6 0.301408 -7.58544 -2.16009 7 -0.0502347 -7.58544 -2.16009 8 0.602816 -1.25587 1.20249 9 -4.26195 -1.41515 -1.00941 10 -4.52832 -1.40429 -1.12157 11 -4.02362 -1.32018 -1.99078 12 -3.79931 -1.32018 -1.99078 13 -2.42539 -1.64029 -2.03284 14 -2.45343 -1.64029 -0.897253 15 -2.18705 -1.64029 -0.911273 16 -2.18705 -1.64029 -2.06088 17 1.26288e-15 -1.5925 -2.15902 18 0.224313 -1.69637 -0.827155 19 0.532744 -1.65431 -0.827155 20 0.266372 -1.55617 -2.15902 21 0.266372 1.55617 -2.15902 22 0.532744 1.65431 -0.827155 23 0.224313 1.69637 -0.827155 24 1.26288e-15 1.5925 -2.15902 25 -2.18705 1.64029 -2.06088 26 -2.18705 1.64029 -0.911273 27 -2.45343 1.64029 -0.897253 28 -2.42539 1.64029 -2.03284 29 -3.79931 1.32018 -1.99078 30 -4.02362 1.32018 -1.99078 31 -4.52832 1.40429 -1.12157 32 -4.26195 1.41515 -1.00941 33 -4.03764 0.0841175 -2.0048 34 -5.00499 0.0841175 -1.33186 35 -5.00499 -0.0700979 -1.33186 36 -4.03764 -0.0981371 -2.0048 37 5.79319 0 -0.0919553 38 5.79319 0 -0.827598 39 4.13799 0 -1.19542 40 2.48279 0 -1.37933 41 1.74715 0 -1.01151 42 0.735643 0 -0.827598 43 -2.02302 0 -0.919553 44 -4.04603 0 -0.919553 45 -5.1495 0 -1.37933 46 -15.6324 0 -0.551732 47 -15.5404 0 -0.183911 48 0.275866 0 1.56324 49 3.03453 0 1.47129 50 3.95408 0 1.47129 51 4.96559 0 1.10346 52 -12.2301 0.183911 -0.827598 53 -12.7818 4.50581 -0.827598 54 -13.2416 4.87363 -0.827598 55 -15.1726 4.78168 -0.827598 56 -15.8163 0.551732 -0.827598 57 -14.1611 0.0919553 -0.827598 58 -0.551732 16.0002 -2.75866 59 -2.94257 16.0002 -2.6667 60 -3.95408 7.63229 -2.29888 61 -4.04603 0 -1.99534 62 0.275866 0 -2.16157 63 0.183911 1.56324 -2.21948 64 0.919553 1.6552 -2.25139 65 0.827598 7.54034 -2.47918 66 0.275866 15.5404 -2.77242 67 0.275866 -15.5404 -2.77242 68 0.827598 -7.54034 -2.47918 69 0.919553 -1.6552 -2.25139 70 0.183911 -1.56324 -2.21948 71 0.275866 -0 -2.16157 72 -4.04603 -0 -1.99534 73 -3.95408 -7.63229 -2.29888 74 -2.94257 -16.0002 -2.6667 75 -0.551732 -16.0002 -2.75866 76 -14.1611 -0.0919553 -0.827598 77 -15.8163 -0.551732 -0.827598 78 -15.1726 -4.78168 -0.827598 79 -13.2416 -4.87363 -0.827598 80 -12.7818 -4.50581 -0.827598 81 -12.2301 -0.183911 -0.827598 82 5.51732 0 -0.551732 83 5.1495 1.19542 -0.551732 84 -0.183911 1.74715 -0.551732 85 -4.22994 1.56324 -0.551732 86 -15.0807 0 -0.551732 87 -15.0807 -0 -0.551732 88 -4.22994 -1.56324 -0.551732 89 -0.183911 -1.74715 -0.551732 90 5.1495 -1.19542 -0.551732 91 5.51732 -0 -0.551732 92 0.0919553 0 1.6552 93 0.0919553 -0.919553 1.47129 94 0.0919553 -1.47129 0.919553 95 0.0919553 -1.56324 -0.0919553 96 0.0919553 -1.56324 -0.919553 97 0.0919553 0 -1.19542 98 0.0919553 -0 -1.19542 99 0.0919553 1.56324 -0.919553 100 0.0919553 1.56324 -0.0919553 101 0.0919553 1.47129 0.919553 102 0.0919553 0.919553 1.47129 103 0.0919553 -0 1.6552 104 4.13799 0 2.20693 105 4.13799 -0.275866 2.48279 106 4.13799 -0.367821 3.03453 107 4.13799 0 3.12648 108 4.13799 -0 3.12648 109 4.13799 0.367821 3.03453 110 4.13799 0.275866 2.48279 111 4.13799 -0 2.20693 112 -0.367821 -3.31039 3.03453 113 -0.367821 -3.21844 2.48279 114 -0.367821 -3.4943 2.20693 115 -0.367821 -3.77017 2.48279 116 -0.367821 -3.86212 3.12648 117 -0.367821 3.86212 3.12648 118 -0.367821 3.77017 2.48279 119 -0.367821 3.4943 2.20693 120 -0.367821 3.21844 2.48279 121 -0.367821 3.31039 3.03453 122 -6.01584 0 -1.2729 123 -11.2573 0 -1.82463 124 -12.3608 0 -2.1005 125 -14.5677 0 -4.85916 126 -16.5907 0 -4.58329 127 -15.5792 0 -0.997034 128 -15.5792 0 -0.629213 gray44 4 1 2 3 4 gray44 4 5 6 7 8 gray44 4 9 10 11 12 gray44 4 13 14 15 16 gray44 4 17 18 19 20 gray44 4 21 22 23 24 gray44 4 25 26 27 28 gray44 4 29 30 31 32 gray44 4 33 34 35 36 gray44 15 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 gray44 6 52 53 54 55 56 57 gray44 9 58 59 60 61 62 63 64 65 66 gray44 9 67 68 69 70 71 72 73 74 75 gray44 6 76 77 78 79 80 81 gray44 5 82 83 84 85 86 gray44 5 87 88 89 90 91 gray44 6 92 93 94 95 96 97 gray44 6 98 99 100 101 102 103 gray44 4 104 105 106 107 gray44 4 108 109 110 111 gray44 5 112 113 114 115 116 gray44 5 117 118 119 120 121 gray44 7 122 123 124 125 126 127 128 acm-6.0_20200416/objects/aircraft/f16.txt0000644000000000000000000001463213153305524016163 0ustar rootroot# F-16 C Falcon aircraft "F-16" { Description "General Dynamics F-16C Fighting Falcon" Object "f16.obv" WingArea 300.0 # (wingS) Wing surface area (ft^2) WingHalfSpan 16 # (wings) Wing half-span (ft) WingHeight 0.0 # (wingh) Height of the wing aerodyn. center above CM (ft) Chord 9.61 # (c) Mean geometric chord of wing (ft) AspectRatio 3.0 # (aspectRatio) aspect ratio EmptyWeight 14576 #(emptyWeight) Empty weight (well, actually mass) (lb) # Max. wing load (lbf): MaxLoadZPositive 219000 # 9*(EmptyWeight+MaxFuel) (+9 g) MaxLoadZNegative 73000 # 3*EmptyWeight (-3 g) DISEntityType 1:2:225:1:3:3:0 DISAltEntityType 1:2:222:1:2:5:0 # (I(x,y,z)) Moments of inertia (lb ft^2) Ixx 7240 Iyy 49786 Izz 54390 # (cFlap) Lift due to flaps (yields Clift of 1.0 at max extension) CFlap 0.64279 BetaStall 15.0 # (deg) CFlapDrag 0.0467 # (cFlapDrag) Drag due to Flaps CGearDrag 0.03 # (cGearDrag) Drag due to Gear CSpeedBrake 0.03 # (cSpeedBrake) Drag due to Speed Brake # at 90 degrees # (CDb) Drag Characteristic equation [Wave+body] # independent variable is mach number CDb { # (CDb) Drag Characteristic equation [Wave+body] # independent variable is mach number 0.0, 0.020, 0.2, 0.020, 0.95, 0.015, 1.05, 0.045, 2.00, 0.030, 10.0, 0.030 } CLift { # (CLift) Lift-slope curve (vs alpha) -3.0, 0.0, -1.05, 0.0, -0.576, -2.199, -0.556, -2.23, -0.524, -2.199, 0.524, 2.199, 0.556, 2.23, 0.576, 2.199, 1.05, 0.0, 2.0, 0.0 } CnBeta { # (CnBeta) Yaw due to sideslip equation 0, -0.08125, 0.523540, -0.078125, 0.785340, -0.0609375, 1.047198, 0.125, 1.58, 0.0 } ClBeta { # (ClBeta) Roll due to sideslip equation 0, -0.0125, 0.43633, -0.015, 0.78540, 0.125, 1.58, 0.0, 3.142, 0.125, } CDBOrigin 0 # (CDBOrigin, CDBFactor) Drag due to sideslip CDBFactor 0.5 CDBPhase 0 # (CDBPhase) sideslip drag phase (deg) CYBeta -1.14 # (CYbeta) Side-force from side-slip [dCY/dBeta] EffElevator 0.63 # (effElevator) Elevator effectiveness [Cmde(1/rad)] EffRudder 0.085 # (effRudder) Rudder effectiveness [CYdr(1/rad)] MaxRudder 20 # (maxRudder) max Rudder (deg) MaxAileron 20 # (maxAileron) max Aileron (deg) MaxFlap 20 # (maxFlap) max flap setting (deg) # (flapRate) flap extension rate (about 2 secs to fully extend flaps) FlapRate 10 # (deg/sec) # (gearRate) gear extension rate (about 3 secs to fully extend gear) GearRate 30 # (deg/sec) MaxSpeedBrake 80 # (maxSpeedBrake) max Speed Brake setting (deg) # (speedBrakeRate) rate of speed brake extension (2 secs to full ext) SpeedBrakeRate 40 # (deg/sec) # (speedBrakeIncr) speed Brake increment per keystroke SpeedBrakeIncr 80 # (deg) Clda 0.048 # (Clda) roll moment from aileron offset Cldr 0.004 # (Cldr) roll moment from rudder offset Clp -0.443 # (Clp) roll damping Cmq -5.23 # (Cmq) pitch damping factor Cnr -0.378 # (Cnr) yaw damping factor CmAlpha -0.35 # (cmSlope) CmAlpha curve slope MaxFuel 9750 # (maxFuel) maximum internal fuel (lb) # engine lag factor (how fast does it respond to throttle changes) EngineLag -3.0 # Engine data based on updated RD-33K engines cited in [AirI Aug89]. EngineType "GenericJetEngine" # (maxThrust) max static thrust, military power (lbf) MaxThrust 14080 # (maxABThrust) max static thrust, afterburner on (lbf) MaxABThrust 23540 Thrust { # (Thrust) Mach Number vs. thrust 0, 1, 1.7, 1.5, 2.0, 0.84, 5, 0.5 } ABThrust { # (ABThrust) afterburner thrust table 0, 1, 0.5, 1, 1, 1.21, 1.7, 1.7, 5, 1.64 } HasThrustReverser 0 # (hasThrustReverser) 0=no, otherwise yes # (spFuelConsump) specific fuel consump(lb fuel/lb T x hr) SpFuelConsump 0.68 # (spABFuelConsump) AB specific fuel consump(lb fuel/lb T x hr) SpABFuelConsump 2.55 # (viewPoint) pilot's viewing location wrt CM ViewPoint { 15.58, 0, -2.71 } # Landing Gear control parameters MuStatic 0.08 # (muStatic) static coeff of friction no-brakes MuKinetic 0.05 # (muKinetic) moving coeff of friction no-brakes MuBStatic 0.7 # (muBStatic) static brakes-on MuBKinetic 0.6 # (muBKinetic) moving brakes-on MaxNWDef 72 # (maxNWDef)maximum nosewheel deflection (deg) # (rm) location of right main gear attachments Rm { -1, 4, 4.5 } # (rn) location of nose gear attachments Rn { 14, 0, 4.5 } Dm 3000 # main oleo damping factor (lbf s/ft) Dn 1200 # nose oleo damping factor (lbf s/ft) Km 32000 # main oleo spring factor (lbf/ft) Kn 8600 # nose oleo spring factor (lbf/ft) Gm 1.5 # main strut length with tire (ft) Gn 1.5 # nose strut length with tire (ft) CmMax 1.5 # (cmMax) main max oleo extension distance (ft) CnMax 1.5 # (cnMax) nose max oleo extension distance (ft) # (tailExtent) as we rotate, this part may drag TailExtent { -18.165, 0.0, 1.191 } # Speed limits at MTOW. Leave undefined or set to 0 if unknown. MTOW 24326.0 # maximum takeoff weight (lb) #Vs0 42.0 # stall speed, full flaps (KIAS) #Vs1 50.0 # stall speed, no flaps (KIAS) #Vfe 100.0 # max speed with flaps extended (KIAS) #Vno 145.0 # normal operation speed (KIAS) #Vne 164.0 # never exceed speed (KIAS) StructurePoints 15 # (structurePts) maximum structural damage # Radar data based on N-019 Pulse Doppler radar cited in [AirI Aug89]. RadarOutput 15000 # (radarOutput) radar output (watts) RadarTRange 60 # (radarTRange) tracking radar range (NM) RadarDRange 80 # (radarDRange) detection radar range (NM) TEWSThreshold 0 # Radar Warning Receiver threshold (watts) # Weapons WeaponCount 9 HardPoint0 { 7.0, -4.0, 0.0 } HardPoint1 { 0.357, 15.6, 0.0 } HardPoint2 { 0.357, -15.6, 0.0 } HardPoint3 { 1.5, 9.0, 2.0 } HardPoint4 { 1.5, -9.0, 2.0 } HardPoint5 { 1.5, 8.0, 1.5 } HardPoint6 { 1.5, -8.0, 1.5 } HardPoint7 { 1.5, 10.0, 1.5 } HardPoint8 { 1.5, -10.0, 1.5 } WeaponStation 0 "M61A1" 500 0 0 WeaponStation 1 "AIM-9M" 0 0 0 WeaponStation 2 "AIM-9M" 0 0 0 WeaponStation 3 "AIM-9M" 0 0 0 WeaponStation 4 "AIM-9M" 0 0 0 WeaponStation 5 "AIM-9M" 0 0 0 WeaponStation 6 "AIM-9M" 0 0 0 WeaponStation 7 "AIM-120" 0 0 0 WeaponStation 8 "AIM-120" 0 0 0 }acm-6.0_20200416/objects/aircraft/f16.obv0000644000000000000000000000615310357223037016132 0ustar rootrootF-16-fighter 130 12 1 -18.165 0 0 2 -18.165 -1.191 0 3 -15.187 -2.085 0 4 -13.698 -2.382 0 5 -17.272 -2.382 0 6 -17.272 -3.573 0 7 -10.923 -3.573 0 8 -4.169 -3.573 0 9 -4.169 -4.765 0 10 5.598 -4.765 0 11 18.463 -2.144 0 12 18.939 -1.787 0 13 22.274 -1.489 0 14 24.895 -1.191 0 15 27.992 0 0 16 -6.551 -3.573 0 17 -6.551 -15.485 0 18 0.357 -15.485 0 19 0.357 -15.187 0 20 -2.978 -15.008 0 21 5.598 -4.765 0 22 -4.169 -4.765 0 23 -4.169 -3.573 0 24 -17.272 -3.573 0 25 -17.272 -8.934 0.893 26 -15.187 -8.934 0.893 27 -10.923 -3.573 0 28 27.992 0 0 29 24.895 1.191 0 30 22.274 1.489 0 31 18.939 1.787 0 32 18.463 2.144 0 33 5.598 4.765 0 34 -4.169 4.765 0 35 -4.169 3.573 0 36 -10.923 3.573 0 37 -17.272 3.573 0 38 -17.272 2.382 0 39 -13.698 2.382 0 40 -15.187 2.085 0 41 -18.165 1.191 0 42 -18.165 0 0 43 5.598 4.765 0 44 -2.978 15.008 0 45 0.357 15.187 0 46 0.357 15.485 0 47 -6.551 15.485 0 48 -6.551 3.573 0 49 -4.169 3.573 0 50 -4.169 4.765 0 51 -10.923 3.573 0 52 -15.187 8.934 0.893 53 -17.272 8.934 0.893 54 -17.272 3.573 0 55 27.992 0 0 56 23.525 0 -1.191 57 17.272 0 -2.382 58 15.783 0 -3.812 59 13.996 0 -4.169 60 11.316 0 -4.05 61 8.338 0 -3.335 62 1.787 0 -2.382 63 -4.169 0 -2.382 64 -13.936 0 -1.906 65 -15.128 0 -1.906 66 -15.187 0 -1.787 67 -18.165 0 -1.191 68 -18.165 0 0 69 -4.169 0 -2.382 70 -10.125 0 -4.05 71 -15.783 0 -10.482 72 -19.654 0 -10.482 73 -19.654 0 -9.529 74 -19.654 0 -9.529 75 -16.378 0 -3.573 76 -16.378 0 -2.144 77 -14.889 0 -2.382 78 -13.936 0 -2.382 79 -13.936 0 -1.906 80 -18.165 0 0 81 -18.165 0 1.191 82 -15.187 0 2.085 83 -13.698 0 2.263 84 -2.68 0 2.382 85 8.04 0 2.382 86 12.507 0 2.263 87 12.507 0 0.596 88 19.952 0 0.596 89 23.525 0 0.476 90 27.992 0 0 91 -3.551 0 -2.382 92 -3.551 -3.871 -0.10 93 -3.551 -15.485 0 94 -3.551 -15.485 0.1065 95 -3.551 -3.871 0.142 96 -3.551 -2.58 0.2556 97 -3.551 -2.387 1.818 98 -3.551 -2.102 2.015 99 -3.551 -1.03 2.251 100 -3.551 0 2.282 101 -3.551 1.03 2.251 102 -3.551 2.102 2.015 103 -3.551 2.387 1.818 104 -3.551 2.58 0.2556 105 -3.551 3.871 0.142 106 -3.551 15.485 0.1065 107 -3.551 15.485 0 108 -3.551 3.871 -0.10 109 13.996 0 -4.169 110 13.996 -0.8932 -3.692 111 13.996 -1.191 -2.978 112 13.996 -1.251 -2.502 113 13.996 -1.787 -1.311 114 13.996 -3.054 0 115 13.996 -1.583 0.3568 116 13.996 0 0.596 117 13.996 1.583 0.3568 118 13.996 3.054 0 119 13.996 1.787 -1.311 120 13.996 1.251 -2.502 121 13.996 1.191 -2.978 122 13.996 0.8932 -3.692 123 -18.165 1.191 0 124 -18.165 0.842 0.842 125 -18.165 0 1.191 126 -18.165 -0.842 0.842 127 -18.165 -1.191 0 128 -18.165 -0.842 -0.842 129 -18.165 0 -1.191 130 -18.165 0.842 -0.842 gray44 14 109 110 111 112 113 114 115 116 117 118 119 120 121 122 gray44 18 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 gray44 15 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 (gray44 gray40) 8 16 17 18 19 20 21 22 23 (gray44 gray40) 4 24 25 26 27 gray44 15 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 (gray40 gray44) 8 43 44 45 46 47 48 49 50 (gray44 gray40) 4 51 52 53 54 gray44 14 55 56 57 58 59 60 61 62 63 64 65 66 67 68 gray44 11 69 70 71 72 73 74 75 76 77 78 79 gray44 11 80 81 82 83 84 85 86 87 88 89 90 (black gray44) 8 123 124 125 126 127 128 129 130 acm-6.0_20200416/objects/aircraft/amx.txt0000644000000000000000000001455413173125412016355 0ustar rootrootaircraft "AMX" { Description "AMX International - AMX" Object "ufo.obv" # FIXME WingArea 226.04 # (wingS) Wing surface area (ft^2) WingHalfSpan 14.6 # (wings) Wing half-span (ft) WingHeight 0.0 # (wingh) Height of the wing aerodyn. center above CM (ft) Chord 7 # (c) Mean geometric chord of wing (ft) AspectRatio 3.75 # (aspectRatio) aspect ratio EmptyWeight 14835 #(emptyWeight) Empty weight (well, actually mass) (lb) # Max. wing load (lbf): MaxLoadZPositive 148350 # 10*EmptyWeight (+10 g) MaxLoadZNegative 74175 # 5*EmptyWeight (-5 g) DISEntityType 1:2:106:1:1:1:0 DISAltEntityType 1:2:106:1:1:1:0 # (I(x,y,z)) Moments of inertia (lb ft^2) Ixx 7240 Iyy 49786 Izz 54390 # (cFlap) Lift due to flaps (yields Clift of 1.0 at max extension) CFlap 0.64279 BetaStall 15.0 # (deg) CFlapDrag 0.0467 # (cFlapDrag) Drag due to Flaps CGearDrag 0.03 # (cGearDrag) Drag due to Gear CSpeedBrake 0.03 # (cSpeedBrake) Drag due to Speed Brake # at 90 degrees # (CDb) Drag Characteristic equation [Wave+body] # independent variable is mach number CDb { # (CDb) Drag Characteristic equation [Wave+body] # independent variable is mach number 0.0, 0.020, 0.2, 0.020, 0.95, 0.015, 1.05, 0.045, 2.00, 0.030, 10.0, 0.030 } CLift { # (CLift) Lift-slope curve (vs alpha) -3.0, 0.0, -1.05, 0.0, -0.3316, -1.65, -0.2967, -1.7, -0.2618, -1.65, 0.2618, 1.65, # 15 DEG (CLmax, stall begin) 0.2967, 1.2, # 17 DEG 0.3316, 0.8, # 19 DEG 1.05, 0.0, 2.0, 0.0 } CnBeta { # (CnBeta) Yaw due to sideslip equation 0, -0.08125, 0.523540, -0.078125, 0.785340, -0.0609375, 1.047198, 0.125, 1.58, 0.0 } ClBeta { # (ClBeta) Roll due to sideslip equation 0, -0.0125, 0.43633, -0.015, 0.78540, 0.125, 1.58, 0.0, 3.142, 0.125, } CDBOrigin 0 # (CDBOrigin, CDBFactor) Drag due to sideslip CDBFactor 0.5 CDBPhase 0 # (CDBPhase) sideslip drag phase (deg) CYBeta -1.14 # (CYbeta) Side-force from side-slip [dCY/dBeta] EffElevator 1.50 # (effElevator) Elevator effectiveness [Cmde(1/rad)] EffRudder 0.04 # (effRudder) Rudder effectiveness [CYdr(1/rad)] MaxRudder 20 # (maxRudder) max Rudder (deg) MaxAileron 20 # (maxAileron) max Aileron (deg) MaxFlap 40 # (maxFlap) max flap setting (deg) # (flapRate) flap extension rate (about 2 secs to fully extend flaps) FlapRate 10 # (deg/sec) # (gearRate) gear extension rate (about 3 secs to fully extend gear) GearRate 30 # (deg/sec) MaxSpeedBrake 80 # (maxSpeedBrake) max Speed Brake setting (deg) # (speedBrakeRate) rate of speed brake extension (2 secs to full ext) SpeedBrakeRate 40 # (deg/sec) # (speedBrakeIncr) speed Brake increment per keystroke SpeedBrakeIncr 80 # (deg) Clda 0.048 # (Clda) roll moment from aileron offset Cldr 0.004 # (Cldr) roll moment from rudder offset Clp -0.443 # (Clp) roll damping Cmq -5.23 # (Cmq) pitch damping factor Cnr -0.378 # (Cnr) yaw damping factor CmAlpha -0.35 # (cmSlope) CmAlpha curve slope MaxFuel 6780 # (maxFuel) maximum internal fuel (lb) EngineType "GenericJetEngine" # engine lag factor (how fast does it respond to throttle changes) EngineLag -3.0 # Engine data based on updated RD-33K engines cited in [AirI Aug89]. # (maxThrust) max static thrust, military power (lbf) MaxThrust 11030 # (maxABThrust) max static thrust, afterburner on (lbf) MaxABThrust 11030 Thrust { # (Thrust) Mach Number vs. thrust 0, 1, 1.7, 1.5, 2.0, 0.84, 5, 0.5 } ABThrust { # (ABThrust) afterburner thrust table 0, 1, 0.5, 1, 1, 1.21, 1.7, 1.7, 5, 1.64 } HasThrustReverser 0 # (hasThrustReverser) 0=no, otherwise yes # (spFuelConsump) specific fuel consump(lb fuel/lb T x hr) SpFuelConsump 0.68 # (spABFuelConsump) AB specific fuel consump(lb fuel/lb T x hr) SpABFuelConsump 0.68 # (viewPoint) pilot's viewing location wrt CM ViewPoint { 9.16, 0, -2.89 } # Landing Gear control parameters MuStatic 0.08 # (muStatic) static coeff of friction no-brakes MuKinetic 0.05 # (muKinetic) moving coeff of friction no-brakes MuBStatic 0.7 # (muBStatic) static brakes-on MuBKinetic 0.6 # (muBKinetic) moving brakes-on MaxNWDef 72 # (maxNWDef)maximum nosewheel deflection (deg) # (rm) location of right main gear attachments Rm { -1.92, 4.46, 1.54 } # (rn) location of nose gear attachments Rn { 13.2, 0, 1.54 } Dm 3000 # main oleo damping factor (lbf s/ft) Dn 900 # nose oleo damping factor (lbf s/ft) Km 29000 # main oleo spring factor (lbf/s^2) Kn 6300 # nose oleo spring factor (lbf/s^2) Gm 2.4 # main strut length with tire (ft) Gn 2.4 # nose strut length with tire (ft) CmMax 1.5 # (cmMax) main max oleo extension distance (ft) CnMax 1.5 # (cnMax) nose max oleo extension distance (ft) # (tailExtent) as we rotate, this part may drag TailExtent { -18.165, 0.0, 1.191 } # Speed limits at MTOW. Leave undefined or set to 0 if unknown. MTOW 21615.0 # maximum takeoff weight (lb) #Vs0 42.0 # stall speed, full flaps (KIAS) #Vs1 50.0 # stall speed, no flaps (KIAS) #Vfe 100.0 # max speed with flaps extended (KIAS) #Vno 145.0 # normal operation speed (KIAS) #Vne 164.0 # never exceed speed (KIAS) StructurePoints 15 # (structurePts) maximum structural damage # Radar data based on N-019 Pulse Doppler radar cited in [AirI Aug89]. RadarOutput 15000 # (radarOutput) radar output (watts) RadarTRange 60 # (radarTRange) tracking radar range (NM) RadarDRange 80 # (radarDRange) detection radar range (NM) TEWSThreshold 0 # Radar Warning Receiver threshold (watts) # Weapons WeaponCount 7 HardPoint0 { 7.0, -4.0, 0.0 } HardPoint1 { 0.357, 15.6, 0.0 } HardPoint2 { 0.357, -15.6, 0.0 } HardPoint3 { 1.5, 9.0, 2.0 } HardPoint4 { 1.5, -9.0, 2.0 } HardPoint5 { 1.5, 8.0, 1.5 } HardPoint6 { 1.5, -8.0, 1.5 } HardPoint7 { 1.5, 10.0, 1.5 } HardPoint8 { 1.5, -10.0, 1.5 } WeaponStation 0 "M61A1" 500 0 0 WeaponStation 1 "AIM-9M" 0 0 0 WeaponStation 2 "AIM-9M" 0 0 0 WeaponStation 3 "AIM-9M" 0 0 0 WeaponStation 4 "AIM-9M" 0 0 0 WeaponStation 5 "AIM-9M" 0 0 0 WeaponStation 6 "AIM-9M" 0 0 0 }acm-6.0_20200416/objects/aircraft/c172.txt0000644000000000000000000001325013156507636016251 0ustar rootroot# Cessna 172 aircraft "C-172" { Description "Cessna 172RG" Object "c172.obv" WingArea 174.0 # (wingS) Wing surface area (ft^2) WingHalfSpan 16 # (wings) Wing half-span (ft) WingHeight 2.4 # (wingh) Height of the wing aerodyn. center above CM (ft) Chord 4.9 # (c) Mean geometric chord of wing (ft) AspectRatio 5.9 # (aspectRatio) aspect ratio EmptyWeight 1450 #(emptyWeight) Empty weight (well, actually mass) (lb) # Max. wing load: MaxLoadZPositive 10070 # 3.8*MTOW (+3.8 g) MaxLoadZNegative 3975 # 1.5*MTOW (-1.5 g) DISEntityType 1:2:225:40:1:1:0 DISAltEntityType 1:2:225:40:1:1:0 # (I(x,y,z)) Moments of inertia (lb ft^2) Ixx 1000 Iyy 7500 Izz 8000 # (cFlap) Lift due to flaps (yields Clift of 1.0 at max extension) CFlap 1.47 BetaStall 15.0 # (deg) CFlapDrag 0.0467 # (cFlapDrag) Drag due to Flaps CGearDrag 0.03 # (cGearDrag) Drag due to Gear CSpeedBrake 0.03 # (cSpeedBrake) Drag due to Speed Brake # at 90 degrees # (CDb) Drag Characteristic equation [Wave+body] # independent variable is mach number CDb { # (CDb) Drag Characteristic equation [Wave+body] # independent variable is mach number 0.0, 0.034, 0.2, 0.034, 0.95, 0.020, 1.05, 0.045, 2.00, 0.030, 10.0, 0.030 } CLift { # (CLift) Lift-slope curve (vs alpha) -3.0, 0.0, -1.05, 0.0, -0.3316, -1.65, -0.2967, -1.7, -0.2618, -1.65, 0.2618, 1.65, # 15 DEG (CLmax, stall begin) 0.2967, 1.2, # 17 DEG 0.3316, 0.8, # 19 DEG 1.05, 0.0, 2.0, 0.0 } CnBeta { # (CnBeta) Yaw due to sideslip equation 0, -0.08125, 0.523540, -0.078125, 0.785340, -0.0609375, 1.047198, 0.125, 1.58, 0.0 } ClBeta { # (ClBeta) Roll due to sideslip equation 0, -0.0125, 0.43633, -0.015, 0.78540, 0.125, 1.58, 0.0, 3.142, 0.125, } CDBOrigin 0 # (CDBOrigin, CDBFactor) Drag due to sideslip CDBFactor 0.5 CDBPhase 0 # (CDBPhase) sideslip drag phase (deg) CYBeta -1.0 # (CYbeta) Side-force from side-slip [dCY/dBeta] EffElevator 1.00 # (effElevator) Elevator effectiveness EffRudder 0.50 # (effRudder) Rudder effectiveness MaxRudder 20 # (maxRudder) max Rudder (deg) MaxAileron 20 # (maxAileron) max Aileron (deg) MaxFlap 30 # (maxFlap) max flap setting (deg) # (flapRate) flap extension rate (about 2 secs to fully extend flaps) FlapRate 3 # (deg/sec) # (gearRate) gear extension rate (about 3 secs to fully extend gear) GearRate 15 # (deg/sec) MaxSpeedBrake 80 # (maxSpeedBrake) max Speed Brake setting (deg) # (speedBrakeRate) rate of speed brake extension (2 secs to full ext) SpeedBrakeRate 40 # (deg/sec) # (speedBrakeIncr) speed Brake increment per keystroke SpeedBrakeIncr 0 # (deg) Clda 0.048 # (Clda) roll moment from aileron offset Cldr 0.004 # (Cldr) roll moment from rudder offset Clp -0.27 # (Clp) roll damping Cmq -8.0 # (Cmq) pitch damping factor Cnr -1.0 # (Cnr) yaw damping factor CmAlpha -0.30 # (cmSlope) CmAlpha curve slope EngineType "GenericPistonEngine" MaxFuel 240 # (maxFuel) maximum internal fuel (lb) # engine lag factor (how fast does it respond to throttle changes) EngineLag -2.0 # (maxThrust) max static thrust, military power (lbf) MaxThrust 500 # (maxABThrust) max static thrust, afterburner on (lbf) MaxABThrust 500 Thrust { # (Thrust) Mach Number vs. thrust 0, 1, 0.1, 0.95, 0.2, 0.90, 1.7, 0.5, 5, 0.5 } ABThrust { # (ABThrust) afterburner thrust table 0, 1, 1.7, 1.5, 2.0, 0.84, 5, 0.5 } HasThrustReverser 0 # (hasThrustReverser) 0=no, otherwise yes # (spFuelConsump) specific fuel consump(lb fuel/lb T x hr) SpFuelConsump 0.1677 # (spABFuelConsump) AB specific fuel consump(lb fuel/lb T x hr) SpABFuelConsump 0.1677 # (viewPoint) pilot's viewing location wrt CM ViewPoint { 0.2791, -0.7326, -1.7792 } # Landing Gear control parameters MuStatic 0.03 # (muStatic) static coeff of friction no-brakes MuKinetic 0.02 # (muKinetic) moving coeff of friction no-brakes MuBStatic 0.6 # (muBStatic) static brakes-on MuBKinetic 0.5 # (muBKinetic) moving brakes-on MaxNWDef 30 # (maxNWDef) maximum nosewheel deflection (deg) # (rm) location of right main gear attachments Rm { -1.3, 4.25, 2 } # (rn) location of nose gear attachments Rn { 3.9, 0, 1.9 } Dm 300 # main oleo damping factor (lbf s/ft) Dn 600 # nose oleo damping factor (lbf s/ft) Km 9200 # main oleo spring factor (lbf/ft) Kn 5400 # nose oleo spring factor (lbf/ft) Gm 0.7 # main strut length with tire (ft) Gn 1.0 # nose strut length with tire (ft) CmMax 0.5 # (cmMax) main max oleo extension distance (ft) CnMax 0.5 # (cnMax) nose max oleo extension distance (ft) # (tailExtent) as we rotate, this part may drag TailExtent { -18.165, 0.0, 1.191 } # Speed limits at MTOW. Leave undefined or set to 0 if unknown. MTOW 2650.0 # maximum takeoff weight (lb) #Vs0 42.0 # stall speed, full flaps (KIAS) #Vs1 50.0 # stall speed, no flaps (KIAS) Vfe 100.0 # max speed with flaps extended (KIAS) Vno 145.0 # normal operation speed (KIAS) Vne 164.0 # never exceed speed (KIAS) StructurePoints 1 # (structurePts) maximum structural damage # Radar data based on N-019 Pulse Doppler radar cited in [AirI Aug89]. RadarOutput 0 # (radarOutput) radar output (watts) RadarTRange 0 # (radarTRange) tracking radar range (NM) RadarDRange 0 # (radarDRange) detection radar range (NM) TEWSThreshold 0 # Radar Warning Receiver threshold (watts) # Weapons WeaponCount 0 }acm-6.0_20200416/objects/aircraft/notavailable.obv0000644000000000000000000000034113074621700020166 0ustar rootrootobject 12 3 1 0.3 0 -5.6 2 0.3 0 -4.6 3 1.1 0 -4.6 4 1.1 0 -2.3 5 0.6 0 -2.3 6 0.6 0 0 7 -0.3 0 -5.6 8 -0.3 0 -4.6 9 -1.1 0 -4.6 10 -1.1 0 -2.3 11 -0.6 0 -2.3 12 -0.6 0 0 #886666 4 1 2 8 7 gray44 4 9 3 4 10 black 4 11 5 6 12 acm-6.0_20200416/objects/aircraft/mig29.txt0000644000000000000000000001501513153305524016512 0ustar rootroot# Mig-29 Fulcrum # MiG-29M information was derived from two sources: [Spick87] and [AirI Aug92]. aircraft "MiG-29" { Description "Mikoyan-Guryevich MiG-29M Fulcrum" Object "mig29.obv" WingArea 400.0 # (wingS) Wing surface area (ft^2) WingHalfSpan 18.87 # (wings) Wing half-span (ft) WingHeight 0.0 # (wingh) Height of the wing aerodyn. center above CM (ft) Chord 9.61 # (c) Mean geometric chord of wing (ft) AspectRatio 3.56 # (aspectRatio) aspect ratio EmptyWeight 22500 # (emptyWeight) Empty weight (well, actually mass) (lb) # Max. wing load (lbf): MaxLoadZPositive 273000 # 10*(EmptyWeight+50%*MaxFuel) (+10 g) MaxLoadZNegative 137000 # 5*(EmptyWeight+50%*MaxFuel) (-5 g) DISEntityType 1:2:222:1:2:5:0 DISAltEntityType 1:2:225:1:3:3:0 # (I(x,y,z)) Moments of inertia (lb ft^2): Ixx 10000.0 Iyy 75000.0 Izz 80000.0 # (cFlap) Lift due to flaps (yields Clift of 1.0 at max extension) CFlap 0.64279 BetaStall 15.0 # (deg) CFlapDrag 0.0467 # (cFlapDrag) Drag due to Flaps CGearDrag 0.03 # (cGearDrag) Drag due to Gear CSpeedBrake 0.03 # (cSpeedBrake) Drag due to Speed Brake # at 90 degrees # (CDb) Drag Characteristic equation [Wave+body] # independent variable is mach number CDb { # (CDb) Drag Characteristic equation [Wave+body] # independent variable is mach number 0.0, 0.020, 0.2, 0.020, 0.95, 0.015, 1.05, 0.045, 2.00, 0.030, 10.0, 0.030 } CLift { # (CLift) Lift-slope curve (vs alpha) -3.0, 0.0, -1.05, 0.0, -0.576, -2.199, -0.556, -2.23, -0.524, -2.199, 0.524, 2.199, 0.556, 2.23, 0.576, 2.199, 1.05, 0.0, 2.0, 0.0 } CnBeta { # (CnBeta) Yaw due to sideslip equation 0, -0.08125, 0.523540, -0.078125, 0.785340, -0.0609375, 1.047198, 0.125, 1.58, 0.0 } ClBeta { # (ClBeta) Roll due to sideslip equation 0, -0.0125, 0.43633, -0.015, 0.78540, 0.125, 1.58, 0.0, 3.142, 0.125, } CDBOrigin 0 # (CDBOrigin, CDBFactor) Drag due to sideslip CDBFactor 0.5 CDBPhase 0 # (CDBPhase) sideslip drag phase (deg) CYBeta -1.4 # (CYbeta) Side-force from side-slip [dCY/dBeta] EffElevator 0.60 # (effElevator) Elevator effectiveness EffRudder 0.14 # (effRudder) Rudder effectiveness MaxRudder 20 # (maxRudder) max Rudder (deg) MaxAileron 20 # (maxAileron) max Aileron (deg) MaxFlap 20 # (maxFlap) max flap setting (deg) # (flapRate) flap extension rate (about 2 secs to fully extend flaps) FlapRate 10 # (deg/sec) # (gearRate) gear extension rate (about 3 secs to fully extend gear) GearRate 30 # (deg/sec) MaxSpeedBrake 80 # (maxSpeedBrake) max Speed Brake setting (deg) # (speedBrakeRate) rate of speed brake extension (2 secs to full ext) SpeedBrakeRate 40 # (deg/sec) # (speedBrakeIncr) speed Brake increment per keystroke SpeedBrakeIncr 80 # (deg) Clda 0.048 # (Clda) roll moment from aileron offset Cldr 0.004 # (Cldr) roll moment from rudder offset Clp -0.27 # (Clp) roll damping Cmq -8.0 # (Cmq) pitch damping factor Cnr -0.378 # (Cnr) yaw damping factor CmAlpha -0.40 # (cmSlope) CmAlpha curve slope MaxFuel 9750 # (maxFuel) maximum internal fuel (lb) EngineType "GenericJetEngine" # engine lag factor (how fast does it respond to throttle changes) EngineLag -3.0 # Engine data based on updated RD-33K engines cited in [AirI Aug89]. # (maxThrust) max static thrust, military power (lbf) MaxThrust 27000 # (maxABThrust) max static thrust, afterburner on (lbf) MaxABThrust 44000 Thrust { # (Thrust) Mach Number vs. thrust 0, 1, 1.7, 1.5, 2.0, 0.84, 5, 0.5 } ABThrust { # (ABThrust) afterburner thrust table 0, 1, 0.5, 1, 1, 1.21, 1.7, 1.7, 5, 1.64 } HasThrustReverser 0 # (hasThrustReverser) 0=no, otherwise yes # (spFuelConsump) specific fuel consump(lb fuel/lb T x hr) SpFuelConsump 0.68 # (spABFuelConsump) AB specific fuel consump(lb fuel/lb T x hr) SpABFuelConsump 2.55 # (viewPoint) pilot's viewing location wrt CM ViewPoint { 14.75, 0, -5.375 } # Landing Gear control parameters MuStatic 0.08 # (muStatic) static coeff of friction no-brakes MuKinetic 0.05 # (muKinetic) moving coeff of friction no-brakes MuBStatic 0.7 # (muBStatic) static brakes-on MuBKinetic 0.6 # (muBKinetic) moving brakes-on MaxNWDef 72 # (maxNWDef) maximum nosewheel deflection (deg) # (rm) location of right main gear attachments Rm { -1.206000, 5, 4.4 } # (rn) location of nose gear attachments Rn { 10.395000, 0, 4.5 } Dm 4500 # main oleo damping factor (lbf s/ft) Dn 5000 # nose oleo damping factor (lbf s/ft) Km 65000 # main oleo spring factor (lbf/ft) Kn 32000 # nose oleo spring factor (lbf/ft) Gm 1.5 # main strut length with tire (ft) Gn 1.5 # nose strut length with tire (ft) CmMax 1.0 # (cmMax) main max oleo extension distance (ft) CnMax 0.75 # (cnMax) nose max oleo extension distance (ft) # (tailExtent) as we rotate, this part may drag TailExtent { -18.165, 0.0, 1.191 } # Speed limits at MTOW. Leave undefined or set to 0 if unknown. MTOW 32250.0 # maximum takeoff weight (lb) #Vs0 42.0 # stall speed, full flaps (KIAS) #Vs1 50.0 # stall speed, no flaps (KIAS) #Vfe 100.0 # max speed with flaps extended (KIAS) #Vno 145.0 # normal operation speed (KIAS) #Vne 164.0 # never exceed speed (KIAS) StructurePoints 15 # (structurePts) maximum structural damage # Radar data based on N-019 Pulse Doppler radar cited in [AirI Aug89]. RadarOutput 15000 # (radarOutput) radar output (watts) RadarTRange 38 # (radarTRange) tracking radar range (NM) RadarDRange 55 # (radarDRange) detection radar range (NM) TEWSThreshold 0 # Radar Warning Receiver threshold (watts) # Weapons WeaponCount 9 HardPoint0 { 7.0, -4.0, 0.0 } HardPoint1 { 0.357, 15.6, 0.0 } HardPoint2 { 0.357, -15.6, 0.0 } HardPoint3 { 1.5, 9.0, 2.0 } HardPoint4 { 1.5, -9.0, 2.0 } HardPoint5 { 1.5, 8.0, 1.5 } HardPoint6 { 1.5, -8.0, 1.5 } HardPoint7 { 1.5, 10.0, 1.5 } HardPoint8 { 1.5, -10.0, 1.5 } WeaponStation 0 "M61A1" 500 0 0 WeaponStation 1 "AIM-9M" 0 0 0 WeaponStation 2 "AIM-9M" 0 0 0 WeaponStation 3 "AIM-9M" 0 0 0 WeaponStation 4 "AIM-9M" 0 0 0 WeaponStation 5 "AIM-9M" 0 0 0 WeaponStation 6 "AIM-9M" 0 0 0 WeaponStation 7 "AIM-120" 0 0 0 WeaponStation 8 "AIM-120" 0 0 0 }acm-6.0_20200416/objects/aircraft/mig25.obv0000644000000000000000000001131710357223037016457 0ustar rootrootMig-25-RBR 159 25 1 -10.0068 -3.35328 -2.65239 2 -24.836 -3.49633 -1.80845 3 -24.7758 -4.21971 1.3262 4 -12.7797 -4.40056 1.92901 5 -12.7797 4.40056 1.92901 6 -24.7758 4.21971 1.3262 7 -24.836 3.49633 -1.80845 8 -10.0068 3.35328 -2.65239 9 -12.7312 4.48625 1.94 10 -15.2775 5.335 3.75875 11 -24.4925 4.85 2.6675 12 -24.735 4.23235 1.33375 13 -23.28 4.22906 1.33375 14 -10 -4.86127 -2.5 15 -10.25 -5.75 2.25 16 12.875 -5.625 2.25 17 20.75 -4.625 -2.875 18 20.75 4.625 -2.875 19 12.875 5.625 2.25 20 -10.25 5.75 2.25 21 -10 4.86127 -2.5 22 12.8867 -2.22292 2.32396 23 20.7135 -2.62708 -3.03125 24 20.7135 -4.95104 -3.03125 25 13.0344 -4.95104 2.22292 26 13.0344 4.95104 2.22292 27 20.7135 4.95104 -3.03125 28 20.7135 2.62708 -3.03125 29 12.8867 2.22292 2.32396 30 41.4675 0 0 31 35.89 1.6975 0 32 29.2212 2.425 0 33 23.0375 2.54625 0 34 13.095 2.425 0 35 12.8525 5.69875 0 36 1.6975 5.94125 0 37 -11.155 5.82 0 38 -24.735 4.97125 0 39 -26.19 4.48625 0 40 -25.8262 0.60625 0 41 -23.0375 -0.12125 0 42 -19.5212 0.12125 -2.7672 43 -19.7637 4.72875 -2.98536 44 -10.67 5.69875 -3.06372 45 2.78875 5.82 -3.11723 46 12.7312 5.82 -3.1525 47 20.855 5.21375 -3.1525 48 20.7338 0.12125 -2.91 49 20.7338 -0.12125 -2.91 50 20.855 -5.21375 -3.1525 51 12.7312 -5.82 -3.1525 52 2.78875 -5.82 -3.11723 53 -10.67 -5.69875 -3.06372 54 -19.7637 -4.72875 -2.98536 55 -19.5212 -0.12125 -2.7672 56 4.72875 -0.12125 1.59646 57 4.72875 2.06125 2.44521 58 4.72875 4.00125 2.68771 59 4.72875 5.0925 2.44521 60 4.72875 5.5775 1.47521 61 4.72875 5.5775 -3.01104 62 4.72875 0 -3.37479 63 4.72875 0 -3.37479 64 4.72875 -5.5775 -3.01104 65 4.72875 -5.5775 1.47521 66 4.72875 -5.0925 2.44521 67 4.72875 -4.00125 2.68771 68 4.72875 -2.06125 2.44521 69 4.72875 0.12125 1.59646 70 20.855 0 2.6675 71 20.855 1.455 2.54625 72 20.855 2.425 0.84875 73 20.855 2.06125 -3.03125 74 20.855 1.33375 -3.395 75 20.855 0.97 -4.24375 76 20.855 -0.12125 -4.48625 77 20.855 0.12125 -4.48625 78 20.855 -0.97 -4.24375 79 20.855 -1.33375 -3.395 80 20.855 -2.06125 -3.03125 81 20.855 -2.425 0.84875 82 20.855 -1.455 2.54625 83 20.855 0 2.6675 84 11.2762 -4.50912 2.30375 85 -13.4588 -3.0127 2.30375 86 -25.9475 -2.31928 1.57625 87 -25.9475 -2.64032 -2.1825 88 -14.6712 -3.395 -3.03125 89 -5.335 -4.00125 -3.51625 90 7.0325 -4.72875 -3.27375 91 7.0325 4.72875 -3.27375 92 -5.335 4.00125 -3.51625 93 -14.6712 3.395 -3.03125 94 -25.9475 2.64032 -2.1825 95 -25.9475 2.31928 1.57625 96 -13.4588 3.0127 2.30375 97 11.2762 4.50912 2.30375 98 -25.705 -3.75875 0.932298 99 -27.0388 -5.45625 0.950218 100 -27.7662 -5.69875 0.974422 101 -31.4037 -12.8525 0.97 102 -29.2212 -14.4287 0.84875 103 -18.1875 -4.85 0.60625 104 -18.1875 4.85 0.60625 105 -29.2212 14.4287 0.84875 106 -31.4037 12.8525 0.97 107 -27.7662 5.69875 0.974422 108 -27.0388 5.45625 0.950218 109 -25.705 3.75875 0.932298 110 -23.5225 5.02122 -1.94 111 -25.9475 5.43057 -2.91 112 -27.2813 7.4293 -10.7912 113 -24.8562 7.5175 -11.8825 114 -12.125 4.6075 -3.6375 115 -7.0325 4.1225 -3.1525 116 -7.0325 -4.1225 -3.1525 117 -12.125 -4.6075 -3.6375 118 -24.8562 -7.5175 -11.8825 119 -27.2813 -7.4293 -10.7912 120 -25.9475 -5.43057 -2.91 121 -23.5225 -5.02122 -1.94 122 -23.0375 0.12125 0 123 -25.8262 -0.60625 0 124 -26.19 -4.48625 0 125 -24.735 -4.97125 0 126 -11.155 -5.82 0 127 1.6975 -5.94125 0 128 12.8525 -5.69875 0 129 13.095 -2.425 0 130 23.0375 -2.54625 0 131 29.2212 -2.425 0 132 35.89 -1.6975 0 133 41.4675 0 0 134 -14.55 -5.21375 -2.49806 135 -16.975 -22.4312 -0.2425 136 -8.36625 -22.1887 -0.485 137 4.72875 -5.69875 -2.91 138 4.72875 5.69875 -2.91 139 -8.36625 22.1887 -0.485 140 -16.975 22.4312 -0.2425 141 -14.55 5.21375 -2.49806 142 -23.28 -4.22906 1.33375 143 -24.735 -4.23235 1.33375 144 -24.4925 -4.85 2.6675 145 -15.2775 -5.335 3.75875 146 -12.7312 -4.48625 1.94 147 41.5887 0 0 148 35.5262 0 -1.57625 149 28.2512 0 -2.54625 150 25.4625 0 -2.78875 151 21.7037 0 -4.48625 152 20.6125 0 -4.72875 153 11.2762 0 -4.48625 154 -26.7963 0 -2.54625 155 -27.16 0 -2.1825 156 -14.9138 0 2.30375 157 -4.00125 0 2.91 158 28.615 0 1.81875 159 37.83 0 0.84875 gray44 4 1 2 3 4 gray44 4 5 6 7 8 gray44 5 9 10 11 12 13 gray44 4 14 15 16 17 gray44 4 18 19 20 21 gray44 4 22 23 24 25 gray44 4 26 27 28 29 gray44 12 30 31 32 33 34 35 36 37 38 39 40 41 gray44 7 42 43 44 45 46 47 48 gray44 7 49 50 51 52 53 54 55 gray44 7 56 57 58 59 60 61 62 gray44 7 63 64 65 66 67 68 69 gray44 7 70 71 72 73 74 75 76 gray44 7 77 78 79 80 81 82 83 gray44 7 84 85 86 87 88 89 90 gray44 7 91 92 93 94 95 96 97 gray44 6 98 99 100 101 102 103 gray44 6 104 105 106 107 108 109 gray44 6 110 111 112 113 114 115 gray44 6 116 117 118 119 120 121 gray44 12 122 123 124 125 126 127 128 129 130 131 132 133 gray44 4 134 135 136 137 gray44 4 138 139 140 141 gray44 5 142 143 144 145 146 gray44 13 147 148 149 150 151 152 153 154 155 156 157 158 159 acm-6.0_20200416/objects/aircraft/su30.obv0000644000000000000000000001255310357223037016331 0ustar rootrootobject 176 19 1 11.3429 -5.49413 3.09587 2 11.0813 -3.66275 3.61913 3 17.3603 -3.1395 -1.09013 4 17.0986 -5.75575 -1.35175 5 17.0986 5.75575 -1.35175 6 17.3603 3.1395 -1.09013 7 11.0813 3.66275 3.61913 8 11.3429 5.49413 3.09587 9 -2.87787 -3.62019 -1.83137 10 -2.87787 -0 -4.97087 11 -4.97087 -10.7266 -2.61625 12 -11.5115 -36.3659 -2.093 13 -11.5115 36.3659 -2.093 14 -4.97087 10.7266 -2.61625 15 -2.87787 0 -4.97087 16 -2.87787 3.62019 -1.83137 17 41.0751 0.784875 -2.093 18 32.4415 3.66275 -2.093 19 22.7614 6.279 -2.093 20 17.7905 7.84875 -2.093 21 13.6045 9.15687 -2.093 22 11.2499 9.4185 -2.093 23 -10.465 35.8426 -2.093 24 -4.186 35.581 -2.093 25 -3.92437 36.1043 -2.093 26 -20.4067 36.3659 -2.093 27 -14.1277 10.9883 -2.093 28 -21.7149 10.9883 -2.093 29 -28.5171 8.372 -2.093 30 -32.1799 0.52325 -2.093 31 -34.0112 -7.28421 -0.661308 32 -34.0112 -6.41706 -1.52846 33 -34.0112 -5.2325 -1.84587 34 -34.0112 -4.04794 -1.52846 35 -34.0112 -3.18079 -0.661308 36 -34.0112 -2.86338 0.52325 37 -34.0112 -3.18079 1.70781 38 -34.0112 -4.04794 2.57496 39 -34.0112 -5.2325 2.89237 40 -34.0112 -6.41706 2.57496 41 -34.0112 -7.28421 1.70781 42 -34.0112 -7.60162 0.52325 43 -34.0112 7.60162 0.52325 44 -34.0112 7.28421 1.70781 45 -34.0112 6.41706 2.57496 46 -34.0112 5.2325 2.89237 47 -34.0112 4.04794 2.57496 48 -34.0112 3.18079 1.70781 49 -34.0112 2.86338 0.52325 50 -34.0112 3.18079 -0.661308 51 -34.0112 4.04794 -1.52846 52 -34.0112 5.2325 -1.84587 53 -34.0112 6.41706 -1.52846 54 -34.0112 7.28421 -0.661308 55 35.0577 -2.35462 -0.261625 56 35.0577 0.261625 0.52325 57 35.0577 -0 -8.11037 58 35.0577 -1.30812 -6.54063 59 35.0577 -1.0465 -5.49413 60 35.0577 -2.093 -4.70925 61 35.0577 -2.87787 -2.61625 62 35.0577 2.87787 -2.61625 63 35.0577 2.093 -4.70925 64 35.0577 1.0465 -5.49413 65 35.0577 1.30812 -6.54063 66 35.0577 0 -8.11037 67 35.0577 -0.261625 0.52325 68 35.0577 2.35462 -0.261625 69 -27.209 -8.11037 0.784875 70 -33.488 -11.5115 0.784875 71 -34.0112 -21.9765 0.784875 72 -29.5636 -24.5927 0.784875 73 -16.744 -10.9883 0.784875 74 -16.744 10.9883 0.784875 75 -29.5636 24.5927 0.784875 76 -34.0112 21.9765 0.784875 77 -33.488 11.5115 0.784875 78 -27.209 8.11037 0.784875 79 11.2499 -5.2325 3.1395 80 11.7731 -5.2325 4.186 81 9.94175 -5.2325 4.97087 82 -33.7496 -5.2325 4.186 83 -34.7961 -5.2325 -1.83137 84 -29.302 -5.2325 -2.35462 85 -18.3137 -5.2325 -2.093 86 -8.372 -5.2325 -3.40112 87 2.61625 -5.2325 -3.40112 88 13.8661 -5.2325 -2.35462 89 17.7905 -5.2325 -1.0465 90 17.7905 5.2325 -1.0465 91 13.8661 5.2325 -2.35462 92 2.61625 5.2325 -3.40112 93 -8.372 5.2325 -3.40112 94 -18.3137 5.2325 -2.093 95 -29.302 5.2325 -2.35462 96 -34.7961 5.2325 -1.83137 97 -33.7496 5.2325 4.186 98 9.94175 5.2325 4.97087 99 11.7731 5.2325 4.186 100 11.2499 5.2325 3.1395 101 10.2034 -10.465 -2.093 102 -14.3894 -10.465 1.30812 103 -17.7905 -10.465 6.01737 104 -24.3311 -10.465 5.2325 105 -24.5927 -10.465 1.56975 106 -25.3776 -10.465 1.56975 107 -27.4706 -10.465 -19.3603 108 -23.5463 -10.465 -21.1916 109 -9.94175 -10.465 -4.44763 110 -8.372 -10.465 -4.186 111 -8.63363 -10.465 -2.87787 112 -8.63363 10.465 -2.87787 113 -8.372 10.465 -4.186 114 -9.94175 10.465 -4.44763 115 -23.5463 10.465 -21.1916 116 -27.4706 10.465 -19.3603 117 -25.3776 10.465 1.56975 118 -24.5927 10.465 1.56975 119 -24.3311 10.465 5.2325 120 -17.7905 10.465 6.01737 121 -14.3894 10.465 1.30812 122 10.2034 10.465 -2.093 123 -32.1799 -0.52325 -2.093 124 -28.5171 -8.372 -2.093 125 -21.7149 -10.9883 -2.093 126 -14.1277 -10.9883 -2.093 127 -20.4067 -36.3659 -2.093 128 -3.92437 -36.1043 -2.093 129 -4.186 -35.581 -2.093 130 -10.465 -35.8426 -2.093 131 11.2499 -9.4185 -2.093 132 13.6045 -9.15687 -2.093 133 17.7905 -7.84875 -2.093 134 22.7614 -6.279 -2.093 135 32.4415 -3.66275 -2.093 136 41.0751 -0.784875 -2.093 137 -43.953 -0.261625 0 138 -40.0286 -1.0465 0 139 -39.767 -2.35462 0 140 -28.5171 -3.1395 0 141 11.7731 -3.66275 0 142 35.8426 -3.66275 0 143 44.4763 -3.40112 0 144 50.4936 -2.61625 0 145 55.9877 -1.30812 0 146 58.3424 -0.261625 0 147 58.3424 0.261625 0 148 55.9877 1.30812 0 149 50.4936 2.61625 0 150 44.4763 3.40112 0 151 35.8426 3.66275 0 152 11.7731 3.66275 0 153 -28.5171 3.1395 0 154 -39.767 2.35462 0 155 -40.0286 1.0465 0 156 -43.953 0.261625 0 157 59.1272 0 0 158 55.7261 0 -1.83137 159 49.9704 0 -4.186 160 43.953 0 -5.2325 161 38.4589 0 -8.63363 162 32.4415 0 -10.2034 163 29.302 0 -10.9883 164 24.5927 0 -10.7266 165 15.6975 0 -8.63363 166 0 0 -5.2325 167 -10.7266 0 -3.40112 168 -29.8253 0 -1.83137 169 -42.6449 0 -1.30812 170 -45.5228 0 0.784875 171 -42.3832 0 1.83137 172 20.1451 0 0.261625 173 33.7496 0 1.0465 174 41.5984 0 1.83137 175 46.3076 0 1.83137 176 50.7552 0 1.83137 (black gray44) 4 1 2 3 4 (black gray44) 4 5 6 7 8 gray44 4 9 10 11 12 gray44 4 13 14 15 16 gray44 14 17 18 19 20 21 22 23 24 25 26 27 28 29 30 (black gray44)12 31 32 33 34 35 36 37 38 39 40 41 42 (black gray44) 12 43 44 45 46 47 48 49 50 51 52 53 54 gray44 7 55 56 57 58 59 60 61 gray44 7 62 63 64 65 66 67 68 gray44 5 69 70 71 72 73 gray44 5 74 75 76 77 78 gray44 11 79 80 81 82 83 84 85 86 87 88 89 gray44 11 90 91 92 93 94 95 96 97 98 99 100 gray44 11 101 102 103 104 105 106 107 108 109 110 111 gray44 11 112 113 114 115 116 117 118 119 120 121 122 gray44 14 123 124 125 126 127 128 129 130 131 132 133 134 135 136 gray44 10 137 138 139 140 141 142 143 144 145 146 gray44 10 147 148 149 150 151 152 153 154 155 156 gray44 20 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 acm-6.0_20200416/objects/aircraft/space-shuttle-orbiter.txt0000644000000000000000000001461413173125412022012 0ustar rootroot# Basically, a very poor glider. Try falling from very high altitude and land # on your base airfield! # FIXME: all data pretty fictional, shame on me, but great fun anyway! # Author: Umberto Salsi # Version: 2017-04-08 aircraft "Space Shuttle Orbiter" { Description "Space Shuttle Orbiter" Object "ufo.obv" WingArea 3971 # (wingS) Wing surface area (ft^2) WingHalfSpan 38 # (wings) Wing half-span (ft) WingHeight -2.0 # (wingh) Height of the wing aerodyn. center above CM (ft) Chord 37 # (c) Mean geometric chord of wing (ft) AspectRatio 1.0 # (aspectRatio) aspect ratio EmptyWeight 172000 # (emptyWeight) Empty weight (well, actually mass) (lb) # Max. wing load (lbf): MaxLoadZPositive 1720000 # 10*(EmptyWeight+50%*MaxFuel) (+10 g) MaxLoadZNegative 860000 # 5*(EmptyWeight+50%*MaxFuel) (-5 g) DISEntityType 1:5:225:1:1:1:0 # "Atlantis" DISAltEntityType 1:5:225:1:1:1:0 # (I(x,y,z)) Moments of inertia (lb ft^2): Ixx 1e7 Iyy 3e7 Izz 3e7 # (cFlap) Lift due to flaps (yields Clift of 1.0 at max extension) CFlap 0.64279 BetaStall 15.0 # (deg) CFlapDrag 0.0467 # (cFlapDrag) Drag due to Flaps CGearDrag 0.01 # (cGearDrag) Drag due to Gear at 90 degrees # (CDb) Drag Characteristic equation [Wave+body] # independent variable is mach number CDb { # (CDb) Drag Characteristic equation [Wave+body] # independent variable is mach number 0.0, 0.035, 0.2, 0.035, 0.95, 0.030, 1.05, 0.090, 2.00, 0.060, 10.0, 0.060 } CLift { # (CLift) Lift-slope curve (vs alpha) -3.0, 0.0, -1.05, 0.0, -0.576, -2.199, -0.556, -2.23, -0.524, -2.199, 0.524, 2.199, 0.556, 2.23, 0.576, 2.199, 1.05, 0.0, 2.0, 0.0 } CnBeta { # (CnBeta) Yaw due to sideslip equation 0, -0.08125, 0.523540, -0.078125, 0.785340, -0.0609375, 1.047198, 0.125, 1.58, 0.0 } ClBeta { # (ClBeta) Roll due to sideslip equation 0, -0.0125, 0.43633, -0.015, 0.78540, 0.125, 1.58, 0.0, 3.142, 0.125, } CDBOrigin 0 # (CDBOrigin, CDBFactor) Drag due to sideslip CDBFactor 0.5 CDBPhase 0 # (CDBPhase) sideslip drag phase (deg) CYBeta -1.4 # (CYbeta) Side-force from side-slip [dCY/dBeta] EffElevator 0.60 # (effElevator) Elevator effectiveness EffRudder 0.14 # (effRudder) Rudder effectiveness MaxRudder 20 # (maxRudder) max Rudder (deg) MaxAileron 20 # (maxAileron) max Aileron (deg) MaxFlap 20 # (maxFlap) max flap setting (deg) # (flapRate) flap extension rate (about 2 secs to fully extend flaps) FlapRate 10 # (deg/sec) # (gearRate) gear extension rate (about 3 secs to fully extend gear) GearRate 30 # (deg/sec) MaxSpeedBrake 80 # (maxSpeedBrake) max Speed Brake setting (deg) # (speedBrakeRate) rate of speed brake extension (2 secs to full ext) SpeedBrakeRate 40 # (deg/sec) # (speedBrakeIncr) speed Brake increment per keystroke SpeedBrakeIncr 80 # (deg) Clda 0.048 # (Clda) roll moment from aileron offset Cldr 0.004 # (Cldr) roll moment from rudder offset Clp -0.27 # (Clp) roll damping Cmq -8.0 # (Cmq) pitch damping factor Cnr -0.378 # (Cnr) yaw damping factor CmAlpha -0.40 # (cmSlope) CmAlpha curve slope MaxFuel 0 # (maxFuel) maximum internal fuel (lb) EngineType "NoEngine" # engine lag factor (how fast does it respond to throttle changes) EngineLag 1.0 # (maxThrust) max static thrust, military power (lbf) MaxThrust 1 # (maxABThrust) max static thrust, afterburner on (lbf) MaxABThrust 1 Thrust { # (Thrust) Mach Number vs. thrust 0, 1, 1.7, 1.5, 2.0, 0.84, 5, 0.5 } ABThrust { # (ABThrust) afterburner thrust table 0, 1, 0.5, 1, 1, 1.21, 1.7, 1.7, 5, 1.64 } HasThrustReverser 0 # (hasThrustReverser) 0=no, otherwise yes # (spFuelConsump) specific fuel consump(lb fuel/lb T x hr) SpFuelConsump 0 # (spABFuelConsump) AB specific fuel consump(lb fuel/lb T x hr) SpABFuelConsump 0 # (viewPoint) pilot's viewing location wrt CM ViewPoint { 14.75, 0, -5.375 } # Landing Gear control parameters MuStatic 0.08 # (muStatic) static coeff of friction no-brakes MuKinetic 0.05 # (muKinetic) moving coeff of friction no-brakes MuBStatic 0.7 # (muBStatic) static brakes-on MuBKinetic 0.6 # (muBKinetic) moving brakes-on MaxNWDef 72 # (maxNWDef) maximum nosewheel deflection (deg) Rn { 53.0, 0.0, 3.0 } # (rn) location of nose gear attachments Rm { -13.3, 12.0, 6.0 } # (rm) location of right main gear attachments Dn 4000 # nose oleo damping factor (lbf s/ft) Dm 8000 # main oleo damping factor (lbf s/ft) Kn 60000 # nose oleo spring factor (lbf/ft) Km 120000 # main oleo spring factor (lbf/ft) Gn 3 # nose strut length with tire (ft) Gm 3 # main strut length with tire (ft) CnMax 3.0 # (cnMax) nose max oleo extension distance (ft) CmMax 3.0 # (cmMax) main max oleo extension distance (ft) # Speed limits at MTOW. Leave undefined or set to 0 if unknown. MTOW 32250.0 # maximum takeoff weight (lb) #Vs0 42.0 # stall speed, full flaps (KIAS) #Vs1 50.0 # stall speed, no flaps (KIAS) #Vfe 100.0 # max speed with flaps extended (KIAS) #Vno 145.0 # normal operation speed (KIAS) #Vne 164.0 # never exceed speed (KIAS) StructurePoints 15 # (structurePts) maximum structural damage # Radar data based on N-019 Pulse Doppler radar cited in [AirI Aug89]. RadarOutput 15000 # (radarOutput) radar output (watts) RadarTRange 38 # (radarTRange) tracking radar range (NM) RadarDRange 55 # (radarDRange) detection radar range (NM) TEWSThreshold 0 # Radar Warning Receiver threshold (watts) # Weapons # WeaponCount 9 # # HardPoint0 { 7.0, -4.0, 0.0 } # HardPoint1 { 0.357, 15.6, 0.0 } # HardPoint2 { 0.357, -15.6, 0.0 } # HardPoint3 { 1.5, 9.0, 2.0 } # HardPoint4 { 1.5, -9.0, 2.0 } # HardPoint5 { 1.5, 8.0, 1.5 } # HardPoint6 { 1.5, -8.0, 1.5 } # HardPoint7 { 1.5, 10.0, 1.5 } # HardPoint8 { 1.5, -10.0, 1.5 } # # WeaponStation 0 "M61A1" 500 0 0 # WeaponStation 1 "AIM-9M" 0 0 0 # WeaponStation 2 "AIM-9M" 0 0 0 # WeaponStation 3 "AIM-9M" 0 0 0 # WeaponStation 4 "AIM-9M" 0 0 0 # WeaponStation 5 "AIM-9M" 0 0 0 # WeaponStation 6 "AIM-9M" 0 0 0 # WeaponStation 7 "AIM-120" 0 0 0 # WeaponStation 8 "AIM-120" 0 0 0 }acm-6.0_20200416/objects/aircraft/p51a.txt0000644000000000000000000001342213173125412016327 0ustar rootrootaircraft "P-51A" { Description "North American P-51A Mustang" Object "ufo.obv" # FIXME WingArea 233 # (wingS) Wing surface area (ft^2) WingHalfSpan 18.5 # (wings) Wing half-span (ft) WingHeight -1.2 # (wingh) Height of the wing aerodyn. center above CM (ft) Chord 6.18 # (c) Mean geometric chord of wing (ft) AspectRatio 5.9 # (aspectRatio) aspect ratio EmptyWeight 6433 #(emptyWeight) Empty weight (well, actually mass) (lb) # Max. wing load: MaxLoadZPositive 35000 # 5*MTOW (+5 g) MaxLoadZNegative 14000 # 2*MTOW (-2 g) DISEntityType 1:2:225:255:255:255:255 # FIXME: not listed DISAltEntityType 1:2:225:255:255:255:255 # (I(x,y,z)) Moments of inertia (lb ft^2) Ixx 5000 Iyy 10000 Izz 15000 # (cFlap) Lift due to flaps (yields Clift of 1.0 at max extension) CFlap 0.64279 BetaStall 15.0 # (deg) CFlapDrag 0.0467 # (cFlapDrag) Drag due to Flaps CGearDrag 0.03 # (cGearDrag) Drag due to Gear CSpeedBrake 0.03 # (cSpeedBrake) Drag due to Speed Brake # at 90 degrees # (CDb) Drag Characteristic equation [Wave+body] # independent variable is mach number CDb { # (CDb) Drag Characteristic equation [Wave+body] # independent variable is mach number 0.0, 0.025, 0.2, 0.025, 0.95, 0.015, 1.05, 0.045, 2.00, 0.030, 10.0, 0.030 } CLift { # (CLift) Lift-slope curve (vs alpha) -3, -1.0, -0.17, -0.14, -0.03, 0.0, 0.0, 0.2, # CLift=0.2 at 0 DEG 0.122, 1.0, # CLift=1.0 at 7 DEG 0.26, 1.3, # CLift=1.3 at 15 DEG 0.40, 0.6, 3.0, 0.0 } CnBeta { # (CnBeta) Yaw due to sideslip equation 0, -0.08125, 0.523540, -0.078125, 0.785340, -0.0609375, 1.047198, 0.125, 1.58, 0.0 } ClBeta { # (ClBeta) Roll due to sideslip equation 0, -0.0125, 0.43633, -0.015, 0.78540, 0.125, 1.58, 0.0, 3.142, 0.125, } CDBOrigin 0 # (CDBOrigin, CDBFactor) Drag due to sideslip CDBFactor 0.5 CDBPhase 0 # (CDBPhase) sideslip drag phase (deg) CYBeta -1.0 # (CYbeta) Side-force from side-slip [dCY/dBeta] EffElevator 0.45 # (effElevator) Elevator effectiveness EffRudder 0.35 # (effRudder) Rudder effectiveness MaxRudder 30 # (maxRudder) max Rudder (deg) MaxAileron 20 # (maxAileron) max Aileron (deg) MaxFlap 40 # (maxFlap) max flap setting (deg) # (flapRate) flap extension rate (about 2 secs to fully extend flaps) FlapRate 3 # (deg/sec) # (gearRate) gear extension rate (about 3 secs to fully extend gear) GearRate 10 # (deg/sec) MaxSpeedBrake 80 # (maxSpeedBrake) max Speed Brake setting (deg) # (speedBrakeRate) rate of speed brake extension (2 secs to full ext) SpeedBrakeRate 40 # (deg/sec) # (speedBrakeIncr) speed Brake increment per keystroke (0 = no spd brk): SpeedBrakeIncr 0 # (deg) Clda 0.048 # (Clda) roll moment from aileron offset Cldr 0.004 # (Cldr) roll moment from rudder offset Clp -0.27 # (Clp) roll damping Cmq -8.0 # (Cmq) pitch damping factor Cnr -1.0 # (Cnr) yaw damping factor CmAlpha -0.30 # (cmSlope) CmAlpha curve slope MaxFuel 500 # (maxFuel) maximum internal fuel (lb) EngineType "GenericPistonEngine" # engine lag factor (how fast does it respond to throttle changes) EngineLag -2.0 # (maxThrust) max static thrust, military power (lbf) MaxThrust 1670 # (maxABThrust) max static thrust, afterburner on (lbf) MaxABThrust 1670 Thrust { # (Thrust) Mach Number vs. thrust 0, 1, 1.7, 1.5, 2.0, 0.84, 5, 0.5 } ABThrust { # (ABThrust) afterburner thrust table 0, 1, 1.7, 1.5, 2.0, 0.84, 5, 0.5 } HasThrustReverser 0 # (hasThrustReverser) 0=no, otherwise yes # (spFuelConsump) specific fuel consump(lb fuel/lb T x hr) SpFuelConsump 0.1677 # (spABFuelConsump) AB specific fuel consump(lb fuel/lb T x hr) SpABFuelConsump 0.1677 # (viewPoint) pilot's viewing location wrt CM ViewPoint { -2.4, 0, -3.35 } # Landing Gear control parameters MuStatic 0.08 # (muStatic) static coeff of friction no-brakes MuKinetic 0.05 # (muKinetic) moving coeff of friction no-brakes MuBStatic 0.25 # (muBStatic) static brakes-on MuBKinetic 0.20 # (muBKinetic) moving brakes-on MaxNWDef 30 # (maxNWDef) maximum nosewheel deflection (deg) # (rm) location of right main gear attachments Rm { 0.0, 6.0, 1.7 } # (rn) location of nose gear attachments Rn { -15, 0, 0.5 } Dm 1300 # main oleo damping factor (lbf s/ft) Dn 500 # nose oleo damping factor (lbf s/ft) Km 12000 # main oleo spring factor (lbf/ft) Kn 5000 # nose oleo spring factor (lbf/ft) Gm 3.5 # main strut length with tire (ft) Gn 1.4 # nose strut length with tire (ft) CmMax 1.0 # (cmMax) main max oleo extension distance (ft) CnMax 0.5 # (cnMax) nose max oleo extension distance (ft) # (tailExtent) as we rotate, this part may drag TailExtent { -18.165, 0.0, 1.191 } # Speed limits at MTOW. Leave undefined or set to 0 if unknown. MTOW 7000.0 # maximum takeoff weight (lb) #Vs0 xx.0 # stall speed, full flaps (KIAS) #Vs1 xx.0 # stall speed, no flaps (KIAS) Vfe 220.0 # max speed with flaps extended (KIAS) Vno 304.0 # normal operation speed (KIAS) Vne 370.0 # never exceed speed (KIAS) StructurePoints 10 # (structurePts) maximum structural damage # Radar data based on N-019 Pulse Doppler radar cited in [AirI Aug89]. RadarOutput 0 # (radarOutput) radar output (watts) RadarTRange 0 # (radarTRange) tracking radar range (NM) RadarDRange 0 # (radarDRange) detection radar range (NM) TEWSThreshold 0 # Radar Warning Receiver threshold (watts) # Weapons WeaponCount 1 HardPoint0 { 7.0, -7.0, 0.0 } WeaponStation 0 "M61A1" 500 0 0 }acm-6.0_20200416/objects/zones/0000755000000000000000000000000013175062137014367 5ustar rootrootacm-6.0_20200416/objects/zones/europe/0000755000000000000000000000000013260344463015666 5ustar rootrootacm-6.0_20200416/objects/zones/europe/italy.txt0000644000000000000000000003357613260344463017567 0ustar rootroot# ITALY # ----- # # References: # VATITA - VATSIM Italy (www.vatita.net) # World Aero Data (www.worldaerodata.com) # The Airport Guide (www.the-airport-guide.com) GROUND_COLOR #305030 # Team 1 base: # Milano Malpensa 17L: #TEAM1_LOC 45-38-31.390N 008-43-48.830E 745 169 # Bologna Borgo Panigale 12: #TEAM1_LOC 44-32-28.53N 011-16-21.000E 120 116.7 # Roma Fiumicino, 34R: TEAM1_LOC 41-48-44.72N 12-16-31.93E 7 342.68 # Team 2 base: # Milano Malpensa 17L: TEAM2_LOC 45-38-31.390N 008-43-48.830E 745 169 # Bologna Borgo Panigale 12: #TEAM2_LOC 44-32-28.53N 011-16-21.000E 120 116.7 # Roma Fiumicino, 34R: #TEAM2_LOC 41-48-44.72N 12-16-31.93E 7 342.68 # ALGHERO - FERTILIA RWY2 LIEA 02/20 78 9843 148 40-37-55.68N 08-17-26.78E 024.5 ILS 20 ILS/DME IALF 110.15 40-37-11.454N 08-17-00.214E 40-38-31.8N 08-17-45.0E 78 3 204.5 3 NAV AHO TACAN 40-38-10.00N 08-17-22.00E 78 109.30 030X NAV AEA VOR/DME 40-38-10.00N 08-17-22.00E 78 111.65 053Y # ANCONA - FALCONARA RWY2 LIPY 04/22 38 9783 150 43-36-59.38N 13-21-45.04E 44.75 ILS 22 ILS/DME IFA 111.90 43-36-23.30N 13-20-55.50E 43-37-28.50N 13-22-29.50E 38 3 224.75 3 # BARI - PALESE RWY2 LIBD 07/25 177 8005 148 41-08-18N 016-45-37E 69 ILS 07 ILS BPL 109.30 41-08-35.30N 016-46-36.79E 41-08-11.80N 016-45-02.05E 177 3 69 3 # BERGAMO - ORIO AL SERIO RWY LIME 10/28 779 9636 148 45-40-15.405N 009-41-24.888E 45-39-52.959N 009-43-25.742E ILS 28 ILS/DME BRM 108.70 45-40-16.300N 009-41-20.500E 45-39-49.500N 009-43-15.500E 779 3 284.88 3 RWY LIME 12/30 779 2200 67 45-40-40.54N 09-42-08.01E 45-40-27.88N 09-42-38.00E NAV ORI VOR/DME 45-40-18N 09-42-31E 779 112.60 - # BOLOGNA - G. MARCONI RWY2 LIPE 12/30 120 9186 148 44-32-07.70N 11-17-19.20E 116.5 NAV BOA VOR/DME 44-32-13.000N 011-17-26.000E 150 112.20 - ILS 12 ILS/DME BLN 108.9 44-31-45.55N 011-18-21.50E 44-32-20.500N 011-16-49.410E 120 3 116.5 3 FEATURE ../../features/tower.obv 44-31-50N 11-17-35E 120 0 # BRINDISI - CASALE RWY2 LIBR 14/32 25 8307 148 40-39-50.02N 17-56-24.51E 137 ILS 32 ILS IBN 109.50 40-40-20.08N 17-55-47.79E 40-39-29.50N 17-56-42.50E 25 3 317 3 RWY2 LIBR 05/23 25 5951 148 40-39-25N 17-56-45E 53 # CAGLIARI - ELMAS RWY2 LIEE 14/32 6 9196 148 39-15-05.31N 09-03-15.44E 138 ILS 32 ILS/DME IEL 109.50 39-15-39.20N 09-02-36.20E 39-14-35.70N 09-03-38.20E 6 3 318 3 NAV CAG VOR/DME 39-14-56.40N 009-03-14.70E 6 113.40 - # CATANIA - FONTANAROSSA RWY2 LICC 08/26 27 7390 148 37-28-00.44N 15-03-59.28E 84 ILS 08 ILS/DME CTN 109.90 37-28-04.28N 15-04-44.90E 37-27-54.59N 15-03-35.67E 27 3 84 3 # CROTONE RWY2 LIBC 17/35 517 6562 148 38-59-48N 17-04-45E 169 # FIRENZE - PERETOLA RWY2 LIRQ 05/23 144 5538 98 43-48-36N 11-12-18E 47 NAV PRT VOR/DME 43-48-37.50N 11-12-05.40E 144 112.50 072X ILS 05 ILS/DME IFZ 110.30 43-48-57.5N 11-12-50.0E 43-48-30.7N 11-12-01.4E 144 3 47 3 # FORLI' - LUIGI RIDOLFI RWY2 LIPK 12/30 97 7907 148 44-11-42N 12-04-11E 116 # GENOVA - SESTRI RWY2 LIMJ 11/29 9 9564 148 44-24-42.80N 08-50-32E 106 ILS 29 ILS/DME GSE 109.30 44-24-59N 08-49-21E 44-24-32N 08-51-12E 9 3 286.84 3 NAV SES VOR/DME 44-25-02.00N 08-49-25.00E 9 108.60 - # GIOIA DEL COLLE RWY LIBV 14R/32L 1157 9846 148 40-46-24.65N 16-55-25.37E 40-45-16.65N 16-56-38.25E RWY LIBV 14L/32R 1157 9829 98 40-46-51.12N 16-55-23.05E 40-45-41.78N 16-56-37.15E NAV GIO TACAN 40-48-05N 16-54-05E 150 117.80 125X # GRAZZANISE RWY2 LIRM 06/24 23 9810 98 41-03-37.43N 14-04-57.68E 61 NAV GRA TACAN 41-03-32N 14-05-31E 50 117.50 122X # LATINA RWY2 LIRL 12/30 75 5577 131 41-32-33N 12-54-27E 125 # LECCE - GALATINA RWY2 LIBN 14/32 153 6637 197 40-14-21.22N 18-07-59.97E 145.5 ILS 32 ILS/DME GAL 111.75 40-14-51.2N 18-07-33.1E 40-13-52.6N 18-08-21.0E 153 5 325.5 3 NAV LCC VORTAC 40-14-54.31N 18-07-50.52E 160 112.8 75X # MILANO - CAMERI RWY LIMN 17/35 569 9818 94 45-32-39.14N 8-39-53.73E 45-31-04.48N 8-40-23.43E # MILANO - LINATE RWY LIML 18L/36R 337 8005 196 45-27-22.377N 009-16-33.119E 45-26-03.515N 009-16-41.622E NAV LIN VOR/DME 45-27-39.386N 009-16-31.200E 353 116.00 - ILS 36R ILS LNT 110.30 45-27-32.096N 009-16-31.900E 45-26-13.072N 009-16-37.151E 337 3 355.5 3 RWY LIML 18R/36L 337 2168 197 45-27-28.936N 009-16-05.735E 45-27-09.506N 009-16-07.845E # MILANO - MALPENSA RWY MA1 17L/35R 745 12860 197 45-38-31.390N 008-43-48.830E 45-36-56.700N 08-44-14.990E ILS 17L ILS IAM 109.90 45-36-43.900N 08-44-18.500E 45-38-24.316N 08-43-56.730E 745 3 169 3 ILS 35R ILS MLP 109.90 45-38-31.390N 008-43-48.830E 45-37-08.785N 08-44-19.555E 745 3 349.07 3 NAV MAL VOR/DME 45-38-33.390N 008-44-05.830E 745 111.20 - RWY MA2 17R/35L 745 12860 197 45-38-43.660N 008-43-07.410E 45-36-51.850N 08-43-38.320E ILS 35L ILS/DME IMA 109.10 45-38-52.120N 08-43-05.000E 45-37-03.935N 08-43-42.885E 745 3 349 3 FEATURE ../../features/tower.obv 45-37-14N 08-42-54E 745 0 # MILANO - VERGIATE RWY LILG 16/34 863 3592 164 45-43-3.10N 8-41-52.69E 45-42-30.04N 8-42-11.55E # NAPOLI - CAPODICHINO RWY2 LIRN 06/24 294 8622 148 40-53-09.72N 14-17-26.81E 58 NAV POM VOR/DME 40-55-41.50N 14-23-00.80E 294 117.85 - ILS 24 ILS/DME INP 109.50 40-52-44.6N 14-16-33.5E 40-53-28.5N 14-18-05.5E 294 3 238 3 ILS 06 ILS/DME NPC 110.15 40-53-33.6N 14-18-17.5E 40-52-54.5N 14-16-53.5E 294 3 58 3 # PALERMO - PUNTA RAISI RWY2 LICJ 07/25 37 10912 197 38-10-48.14N 13-06-12.77E 67 RWY2 LICJ 02/20 37 6804 148 38-10-29.24N 13-05-25.71E 24 ILS 25 ILS/DME RAI 109.50 38-10-26.10N 13-05-07.14E 38-11-02.19N 13-07-09.40E 37 3 247 3 ILS 20 ILS/DME ITO 109.90 38-09-58.57N 13-05-08.50E 38-10-52.91N 13-05-32.93E 37 3 204 3 # That's a terminal VOR: NAV PRS VOR/DME 38-10-19.55N 13-04-47.85E 37 113.00 - # Pantelleria RWY2 LICG 08/26 635 5499 148 36-48-57N 11-57-56E 76 RWY2 LICG 03/21 635 4003 98 36-48-46N 11-57-57E 28 # PARMA - Giuseppe Verdi RWY LIMP 02/20 164 6961 147 44-49-10.18N 10-17-38.16E 44-50-03.54N 10-18-01.63E ILS 20 ILS/DME IPR 110.50 44-49-10.18N 10-17-38.16E 44-49-54N 10-17-52E 164 50 197.35 3 # REGGIO CALABRIA RWY2 LICR 11/29 50 5574 148 38-04-19.79N 15-38-54.85E 112 RWY2 LICR 15/33 50 6549 148 38-04-21.60N 15-39-02.17E 152 ILS - LDA REG 109.30 38-02-51N 15-39-50E - - 0 3 19 - # REGGIO EMILIA - CAMPO VOLO RWY2 LIDE 12/30 153 4593 98 44-41-54.00N 10-39-46.00E 120 # RIMINI RWY LIPR 13/31 31 9828 148 44-01-42.71N 12-35-49.07E 44-00-43.35N 12-37-35.50E ILS 31 ILS MIR 109.30 44-01-42.71N 12-35-49.07E 44-00-43.35N 12-37-35.50E 31 5 307.7 3 # ROMA - CIAMPINO RWY LIRA 15/33 341 7242 154 41-48-29.01N 12-35-19.78E 41-47-25.43N 12-36-03.62E NAV ROM VOR/DME 41-48-14.01N 12-35-19.78E 341 110.80 - ILS 15 ILS CIA 109.90 41-47-20.43N 12-36-07.20E 41-48-16.01N 12-35-23.78E 341 3 152.63 3 # ROMA - FIUMICINO RWY LIRF 07/25 7 10856 148 41-48-02.22N 12-14-12.55E 41-48-34.66N 12-16-10.11E RWY LIRF 16R/34L 7 12795 197 41-48-55.86N 12-13-34.90E 41-47-05.03N 12-14-21.31E RWY LIRF 16L/34R 7 12795 197 41-50-45.57N 12-15-41.34E 41-48-44.72N 12-16-31.93E ILS 34L ILS ISW 108.90 41-49-08N 12-13-29.7E 41-47-13N 12-14-08E 7 3 342.68 3 ILS 16R ILS FRR 110.30 41-46-55N 12-14-25.5E 41-48-45N 12-13-32E 7 3 162.68 3 ILS 25 ILS FEE 109.70 41-47-54.0N 12-13-43E 41-48-34N 12-15-53E 7 3 249.68 3 ILS 16L ILS FLL 108.10 41-48-31N 12-16-37.8E 41-50-34N 12-15-55E 7 3 162.58 3 ILS 34R ILS FSS 109.30 41-50-54N 12-15-37.9E 41-48-51N 12-16-34E 7 3 342.68 3 FEATURE ../../features/tower.obv 41-47-47N 12-15-10E 7 0 # ROMA - PRATICA DI MARE RWY LIRE 13L/31R 41 8138 98 41-39-40.13N 12-25-57.92E 41-38-47.17N 12-27-22.20E # ROMA - URBE RWY LIRU 16/34 55 3543 98 41-57-25.17N 12-30-00.02E 41-56-51.96N 12-30-15.92E # RAVENNA RWY LIDR 08/26 0 3937 98 44-21-48.23N 012-13-02.73E 44-21-54.37N 012-13-56.30E # TORINO - CASELLE RWY LIMF 18/36 989 10826 150 45-12-36.320N 07-39-04.440E 45-11-24.100N 07-38-59.860E NAV CSL VOR/DME 45-12-49.320N 07-39-02.140E 995 116.75 - ILS 36 ILS CAS 109.50 45-12-36.320N 07-39-04.440E 45-11-45.800N 07-39-02.860E 995 3 2.56 3 # VENEZIA - TESSERA RWY LIPZ 04R/22L 7 10827 148 45-29-42.10N 12-20-19.25E 45-31-01.40N 12-22-01.25E ILS 04R ILS VEN 110.30 45-31-10.00N 12-22-12.00E 45-29-50.00N 12-20-40.00E 7 3 42 3 NAV TES VOR/DME 45-31-15.00N 12-22-05.00E 7 115.30 - # VERONA - VILLAFRANCA RWY LIPX 05/23 238 10064 148 45-23-15.64N 10-52-36.70E 45-24-14.48N 10-54-02.27E ILS 05 ILS IVF 110.10 45-24-18.70N 10-54-08.50E 45-23-25.50N 10-52-38.70E 238 3 45.6 3 NAV VIL VOR 45-24-22.00N 10-54-13.50E 238 115.80 - NAV ALG VORTAC 40-37-41N 08-14-38E 1450 113.80 - NAV ANC VOR/DME 43-35-11N 13-28-18E 850 110.65 - NAV BAR VOR/DME 41-08-39N 16-46-35E 100 116.40 - NAV BOL VORTAC 42-37-06N 12-02-55E 2100 114.40 - NAV BRD VORTAC 40-36-39N 18-00-10E 100 113.20 - NAV CAR VOR/DME 39-06-41N 09-30-29E 200 115.10 - NAV CAT VOR/DME 37-27-22N 14-58-10E 200 112.10 - NAV CDC VORTAC 38-45-21N 16-22-09E 53 117.30 - NAV CHI VOR/DME 45-04-16N 12-16-53E 0 114.10 - NAV CMP VOR/DME 42-07-26N 12-22-53E 1450 111.40 - NAV CRN VOR/DME 38-59-46N 17-04-59E 0 117.10 - NAV CTF VOR/DME 37-27-52N 15-03-44E 53 116.25 - NAV ELB VORTAC 42-43-50N 10-23-45E 1400 114.70 - NAV FRZ VORTAC 44-01-38N 11-00-12E 4300 115.20 - NAV GEN VOR/DME 44-25-28N 09-04-56E 2900 112.80 - NAV LAT VOR/DME 41-32-28N 12-55-05E 100 111.20 - NAV OST VOR/DME 41-48-14N 12-14-15E 7 114.90 - NAV PAL VOR/DME 38-02-02N 13-10-39E 3900 112.30 - NAV PAN VOR/DME 36-48-51N 11-57-55E 600 116.10 - NAV PES VOR/DME 42-26-10N 14-11-04E 0 115.90 - NAV PIS VOR/DME 43-40-38N 10-23-26E 40 112.10 - NAV PNZ VORTAC 40-54-43N 12-57-27E 700 114.60 - NAV PRU VOR/DME 43-06-06N 12-30-43E 700 109.40 - NAV RCA VOR/DME 38-04-33N 15-38-44E 100 111.00 - NAV RCH VOR/DME 45-49-47N 13-28-49E 100 114.20 - NAV SME VOR/DME 40-53-24N 09-30-04E 100 113.90 - NAV SOR VOR/DME 40-34-57N 14-20-07E 1700 112.20 - NAV SRN VOR/DME 45-38-48N 09-01-22E 800 113.70 - NAV TAQ VOR/DME 42-12-54N 11-43-57E 100 111.80 - NAV TEA VOR/DME 41-17-48N 13-58-14E 3300 112.90 - NAV TPR TACAN 41-37-17.64N 12-29-37.58E 50 108.70 24X NAV TOP VOR/DME 44-55-31N 07-51-42E 900 114.50 - NAV TRP VOR/DME 37-53-45N 12-30-47E 100 108.80 - NAV TZO VOR/DME 45-33-33N 09-30-26E 500 111.80 - NAV VIC VOR/DME 45-38-14N 11-40-35E 200 113.40 - NAV VIE VOR/DME 41-54-46N 16-02-57E 1000 112.60 - NAV VOG VOR/DME 44-57-52N 08-58-13E 400 115.50 - # NDB data mostly from www.worldaerodata.com NAV RIV NDB 45-56-07.00N 12-56-31.00E 200 371 - NAV ABN NDB 44-03-21.00N 08-13-16.00E 200 420 - NAV ALG NDB 40-38-24.00N 08-17-30.00E 200 382 - NAV AME NDB 41-29-59.82N 15-50-16.10E 200 334 - NAV ANC NDB 43-35-12.00N 13-28-20.00E 200 374 - NAV ARB NDB 39-55-17.20N 09-40-43.20E 200 289 - NAV AVI NDB 45-55-27.59N 12-25-42.71E 200 390 - NAV BLA NDB 45-27-44.00N 08-07-24.00E 200 350 - NAV BOA NDB 44-34-02.30N 11-12-00.85E 200 413 - NAV BPL NDB 41-06-37.10N 16-39-37.60E 200 301 - NAV BRD NDB 40-36-19.70N 18-00-31.80E 200 363.5 - NAV BZO NDB 46-27-49.14N 11-19-18.77E 200 362 - NAV CAG NDB 39-12-52.70N 09-05-50.90E 200 371 - NAV CAM NDB 45-25-42.93N 08-42-02.82E 200 323 - NAV CAR NDB 39-06-42.00N 09-30-33.00E 200 402 - NAV CAS NDB 45-07-24.46N 07-38-43.17E 200 357 - NAV CAT NDB 37-27-24.78N 14-57-56.52E 200 345 - NAV CEV NDB 44-16-03.58N 12-10-48.39E 200 387 - NAV CHI NDB 45-04-18.50N 12-16-53.00E 200 408 - NAV CIA NDB 41-51-53.80N 12-33-38.90E 200 412 - NAV CMO NDB 44-20-45.00N 09-10-16.00E 200 389 - NAV CMP NDB 42-07-29.83N 12-22-49.40E 200 301.5 - NAV COD NDB 45-13-34.54N 09-32-28.23E 200 400.5 - NAV CTF NDB 37-27-49.10N 15-03-45.20E 200 407 - NAV DEC NDB 39-21-49.00N 08-58-27.00E 200 331 - NAV ELB NDB 42-43-57.00N 10-23-38.00E 200 360 - NAV FAL NDB 43-37-41.60N 13-22-24.70E 200 357.5 - NAV FE NDB 41-49-53.10N 12-21-03.90E 200 354 - NAV FER NDB 44-48-52.00N 11-36-59.00E 200 427 - NAV FN NDB 41-54-38.40N 12-14-04.60E 200 421 - NAV FOG NDB 41-25-51.00N 15-31-53.00E 200 340 - NAV FOR NDB 44-14-53.00N 11-55-29.00E 200 423 - NAV FRS NDB 41-38-38.00N 13-17-23.00E 200 371 - NAV FW NDB 41-52-51.10N 12-11-55.60E 200 345 - NAV GAZ NDB 45-12-06.10N 10-36-14.90E 200 382 - NAV GEN NDB 44-25-25.82N 09-05-00.01E 200 318 - NAV GIO NDB 40-48-00.70N 16-54-04.72E 200 328 - NAV GRA NDB 41-03-25.91N 14-05-00.54E 200 343 - NAV GRO NDB 42-42-19.00N 11-01-31.00E 200 406 - NAV GRT NDB 40-26-45.50N 17-25-19.70E 200 331 - NAV GUI NDB 41-59-59.00N 12-44-20.00E 200 388 - NAV ISA NDB 45-41-55.00N 12-13-42.00E 200 340 - NAV ITA NDB 41-32-28.20N 12-55-10.40E 200 393 - NAV LAT NDB 41-31-28.00N 12-56-37.00E 200 379 - NAV LEV NDB 44-32-39.20N 07-36-55.40E 200 371 - NAV LIN NDB 45-20-39.62N 09-17-18.89E 200 386 - NAV LPD NDB 35-30-01.60N 12-36-57.20E 200 373 - NAV MAL NDB 45-32-44.95N 08-45-22.53E 200 364 - NAV NOV NDB 45-25-26.90N 08-47-37.90E 200 292 - NAV NSY NDB 37-24-00.25N 14-55-15.96E 200 297 - NAV ORI NDB 45-38-37.59N 09-50-30.03E 200 376.5 - NAV OST NDB 41-48-18.60N 12-14-11.10E 200 321 - NAV PAL NDB 38-02-03.36N 13-10-38.51E 200 355.5 - NAV PAN NDB 36-48-40.90N 11-57-39.60E 200 335 - NAV PAR NDB 44-49-20.24N 10-17-35.77E 200 306 - NAV PDV NDB 45-21-36.50N 11-49-05.10E 200 285 - NAV PIA NDB 44-52-18.00N 09-49-36.00E 200 440 - NAV PIS NDB 43-35-21.20N 10-17-49.50E 200 379 - NAV PNZ NDB 40-54-40.00N 12-57-22.00E 200 367.5 - NAV POM NDB 40-55-43.00N 14-22-59.00E 200 351 - NAV PRA NDB 41-40-46.99N 12-27-10.24E 200 339 - NAV PRS NDB 38-11-21.79N 13-06-32.85E 200 329 - NAV RCA NDB 38-00-46.52N 15-39-00.97E 200 325 - NAV RIM NDB 44-04-44.50N 12-30-21.60E 200 335 - NAV RMG NDB 45-38-22.19N 08-43-59.38E 200 337 - NAV RON NDB 45-49-41.37N 13-21-38.50E 200 396 - NAV SIG NDB 37-23-44.87N 14-58-17.50E 200 412 - NAV SME NDB 40-53-36.90N 09-30-08.26E 200 357 - NAV SOR NDB 40-34-57.40N 14-20-07.80E 200 426 - NAV SRN NDB 45-38-48.50N 09-01-22.30E 200 330 - NAV TAQ NDB 42-12-50.24N 11-43-44.06E 200 312 - NAV TEA NDB 41-17-45.00N 13-58-18.00E 200 316 - NAV TOP NDB 44-55-28.90N 07-51-37.55E 200 392.5 - NAV TRE NDB 45-37-20.90N 12-05-44.30E 200 301.5 - NAV TRP NDB 37-54-51.60N 12-29-34.70E 200 317.5 - NAV TZO NDB 45-33-30.43N 09-30-33.48E 200 345 - NAV URB NDB 41-56-42.40N 12-29-24.40E 200 285 - NAV VEN NDB 45-26-56.70N 12-16-37.20E 200 379 - NAV VIB NDB 42-26-24.00N 12-03-25.00E 200 480 - NAV VIC NDB 45-38-12.72N 11-40-28.82E 200 417 - NAV VIE NDB 41-54-48.00N 16-03-04.00E 200 405 - NAV VIL NDB 45-19-28.00N 10-47-09.60E 200 355 - NAV VOG NDB 44-57-50.30N 08-58-17.40E 200 333.5 - acm-6.0_20200416/objects/zones/europe/spain.txt0000644000000000000000000005202413646045023017542 0ustar rootroot# Spain zone. # Created: 2020-04-16 # Latitude range: [35N, 42N[ # Longitude range: [010W, 006E[ # 2017-11-01 Source: http://ourairports.com GROUND_COLOR #305030 RWY DA14 05/23 732 3550 80 35-54-09.36N 000-08-31.07E 35-54-34.56N 000-09-01.06E RWY DA14 13/31 732 2275 100 35-54-34.20N 000-08-53.39E 35-54-20.88N 000-09-15.55E RWY DAAB 07/25 535 5833 150 36-30-05.04N 002-48-11.92E 36-30-28.80N 002-49-18.91E RWY DAAD 04/22 1506 7218 98 35-19-30.36N 004-11-54.35E 35-20-23.64N 004-12-52.63E RWY DAAE 08/26 20 7874 148 36-42-36.00N 005-03-24.01E 36-42-48.96N 005-04-59.02E RWY DAAG 05/23 82 11483 197 36-41-38.04N 003-13-12.61E 36-42-46.44N 003-15-05.04E RWY DAAG 09/27 82 11483 148 36-41-31.56N 003-10-14.99E 36-41-28.32N 003-12-35.71E RWY DAAK 05/23 335 11883 148 36-32-01.68N 002-51-45.22E 36-33-28.44N 002-53-24.29E RWY DAAQ 09L/27R 2132 10696 148 35-31-36.84N 002-51-38.88E 35-31-34.68N 002-53-48.16E RWY DAAQ 09R/27L 2132 10696 148 35-31-28.56N 002-51-38.81E 35-31-26.40N 002-53-48.08E RWY DAAV 17/35 36 7874 148 36-48-20.88N 005-52-17.40E 36-47-03.84N 005-52-32.56E RWY DAAZ 07/25 282 4265 70 35-44-59.64N 000-37-10.80E 35-45-16.20N 000-37-58.36E RWY DAOB 08/26 3245 9843 148 35-20-20.76N 001-26-48.70E 35-20-35.52N 001-28-45.95E RWY DAOE 07/25 187 9834 148 35-43-53.04N 000-49-09.90W 35-44-34.08N 000-47-22.00W RWY DAOI 07/25 463 5413 98 36-12-34.92N 001-19-24.13E 36-12-56.16N 001-20-24.58E RWY DAOL 08/26 367 9037 140 35-32-21.84N 000-32-49.05W 35-32-43.80N 000-31-03.31W RWY DAON 07/25 814 8530 148 35-00-33.48N 001-28-14.12W 35-01-02.64N 001-26-37.72W RWY DAOO 07/25 295 10039 148 35-37-06.60N 000-38-12.18W 35-37-45.12N 000-36-20.34W RWY DAOS 10/28 1614 4868 100 35-10-21.72N 000-36-04.85W 35-10-15.24N 000-35-06.74W RWY DAOV 08/26 1686 5577 98 35-12-23.04N 000-08-16.65E 35-12-32.76N 000-09-22.78E RWY GEML 15/33 156 4685 148 35-17-09.24N 002-57-40.25W 35-16-29.64N 002-57-08.06W RWY GMTA 18/36 95 8202 148 35-11-18.60N 003-50-28.75W 35-09-57.96N 003-50-16.04W RWY GMTN 06/24 10 7546 148 35-35-17.88N 005-19-49.30W 35-36-01.44N 005-18-34.85W RWY GMTT 07/25 62 6562 98 35-43-08.76N 005-55-23.23W 35-43-31.08N 005-54-08.42W RWY GMTT 10/28 62 11483 148 35-43-59.88N 005-56-25.12W 35-43-48.00N 005-54-06.55W RWY LE83 17/35 2329 3287 39 41-28-13.08N 004-42-49.72W 41-27-41.04N 004-42-43.96W RWY LE84 09/27 3654 3695 30 36-55-48.72N 003-50-30.05W 36-55-51.96N 003-49-44.69W RWY LE85 18/36 26 6004 116 37-21-35.64N 006-00-52.42W 37-20-36.60N 006-00-48.06W RWY LEAB 09/27 2302 8858 197 38-56-52.80N 001-52-44.62W 38-56-56.76N 001-50-52.58W RWY LEAL 10/28 142 9842 148 38-17-04.20N 000-34-29.99W 38-16-47.28N 000-32-28.74W RWY LEAM 08/26 70 10499 148 36-50-22.92N 002-23-14.14W 36-50-53.16N 002-21-10.58W RWY LEBA 03/21 297 4527 148 37-50-11.76N 004-51-09.61W 37-50-50.64N 004-50-42.32W RWY LEBE 09/27 1780 4757 98 38-16-31.08N 002-57-28.84W 38-16-32.88N 002-56-29.22W RWY LEBE 15/33 1780 2460 98 38-16-40.44N 002-56-54.20W 38-16-19.92N 002-56-37.68W RWY LEBL 02/20 12 8333 148 41-17-16.08N 002-05-05.42E 41-18-33.84N 002-05-40.96E RWY LEBL 07L/25R 12 11654 148 41-17-33.00N 002-03-54.40E 41-18-20.52N 002-06-13.43E RWY LEBL 07R/25L 12 8727 197 41-16-56.28N 002-04-27.66E 41-17-31.92N 002-06-11.81E RWY LEBZ 13/31 609 9350 197 38-53-55.68N 006-50-04.63W 38-53-01.68N 006-48-28.40W RWY LECU 09/27 2269 4921 98 40-22-15.96N 003-47-38.15W 40-22-12.72N 003-46-34.86W RWY LECU 09L/27R 2269 2698 148 40-22-20.28N 003-47-26.56W 40-22-17.76N 003-46-39.32W RWY LEFM 16/34 3307 3281 59 40-53-31.20N 004-14-30.41W 40-53-02.76N 004-14-10.07W RWY LEGA 18/36 2297 4265 98 37-08-20.76N 003-38-07.51W 37-07-38.64N 003-38-09.49W RWY LEGE 02/20 468 7874 148 41-53-41.64N 002-45-29.74E 41-54-56.52N 002-45-58.03E RWY LEGR 09/27 1860 9514 148 37-11-18.96N 003-47-37.28W 37-11-20.04N 003-45-39.71W RWY LEGT 05/23 2031 8136 197 40-17-10.32N 003-44-02.65W 40-18-06.84N 003-42-48.20W RWY LEGT 05R/23L 2031 3018 98 40-17-21.12N 003-43-30.54W 40-17-42.72N 003-43-02.35W RWY LEIB 06/24 24 9186 148 38-52-00.84N 001-21-31.93E 38-52-43.32N 001-23-14.57E RWY LEIZ 10/28 2902 5015 75 38-30-49.32N 003-22-22.98W 38-30-45.00N 003-21-20.16W RWY LEJR 02/20 93 7546 148 36-44-06.00N 006-03-53.32W 36-45-15.48N 006-03-19.48W RWY LELA 07/25 2644 4830 77 38-44-45.60N 003-31-21.72W 38-44-58.92N 003-30-23.15W RWY LELC 05/23 11 7546 197 37-46-03.72N 000-49-17.60W 37-46-55.92N 000-48-10.20W RWY LELC 05L/23R 11 2867 197 37-46-49.80N 000-49-00.62W 37-47-09.60N 000-48-34.89W RWY LELC 14/32 11 2625 197 37-47-12.48N 000-48-50.02W 37-46-53.40N 000-48-27.00W RWY LEMD 14L/32R 1998 11483 197 40-29-41.64N 003-33-28.33W 40-28-12.00N 003-31-57.29W RWY LEMD 14R/32L 1998 13084 197 40-29-05.64N 003-34-33.64W 40-27-20.52N 003-32-46.97W RWY LEMD 18L/36R 1998 11483 197 40-31-57.36N 003-33-33.77W 40-30-03.96N 003-33-33.16W RWY LEMD 18R/36L 1998 13711 197 40-31-54.48N 003-34-29.46W 40-29-33.36N 003-34-28.67W RWY LEMG 13/31 53 10500 148 36-41-04.20N 004-30-45.32W 36-39-55.44N 004-29-08.95W RWY LEMH 01L/19R 302 7710 148 39-51-04.68N 004-12-58.75E 39-52-19.92N 004-13-14.23E RWY LEMH 01R/19L 302 6890 148 39-51-12.24N 004-13-08.90E 39-52-19.56N 004-13-22.73E RWY LEMO 02/20 285 11801 200 37-09-34.56N 005-37-22.40W 37-11-24.36N 005-36-32.94W RWY LEOC 11/29 2405 4134 58 39-56-16.80N 003-30-28.48W 39-56-04.56N 003-29-37.82W RWY LEOC 17/35 2405 2936 328 39-56-27.60N 003-30-18.18W 39-55-59.16N 003-30-09.94W RWY LEPA 06L/24R 27 10728 148 39-32-49.56N 002-42-38.63E 39-33-45.00N 002-44-35.48E RWY LEPA 06R/24L 27 9842 148 39-32-28.68N 002-43-54.26E 39-33-19.08N 002-45-41.51E RWY LEPZ 14/32 1850 3346 59 38-54-56.16N 004-11-42.43W 38-54-31.68N 004-11-13.67W RWY LERI 07/25 250 3077 148 37-56-57.48N 001-14-06.68W 37-57-10.44N 001-13-31.58W RWY LERM 01/19 3097 3281 33 40-51-28.08N 003-14-51.97W 40-52-00.12N 003-14-46.54W RWY LERS 07/25 233 8054 148 41-08-38.76N 001-09-21.10E 41-09-07.20N 001-10-59.34E RWY LERS 12/30 233 1117 115 41-08-35.16N 001-09-16.49E 41-08-24.00N 001-09-54.50E RWY LERT 10/28 86 12106 200 36-38-49.92N 006-22-11.86W 36-38-35.52N 006-19-44.40W RWY LESA 03/21 2595 8202 197 40-56-31.20N 005-30-32.54W 40-57-43.20N 005-29-42.22W RWY LESA 08/26 2595 6594 400 40-56-59.28N 005-30-45.94W 40-57-17.28N 005-29-22.99W RWY LESB 05/23 157 3281 72 39-35-47.40N 002-41-55.93E 39-36-08.28N 002-42-28.04E RWY LESL 02/20 197 6069 148 39-51-15.84N 004-15-16.99E 39-52-12.36N 004-15-42.98E RWY LETI 05/23 1401 3280 49 40-14-34.08N 004-47-34.58W 40-14-56.04N 004-47-03.73W RWY LETI 05L/23R 1401 1969 197 40-14-46.32N 004-47-27.67W 40-15-01.08N 004-47-11.00W RWY LETO 05/23 2026 12001 217 40-29-05.28N 003-27-38.52W 40-30-31.32N 003-25-51.74W RWY LEVC 04/22 240 5394 148 39-28-55.92N 000-29-20.00W 39-29-38.76N 000-28-36.10W RWY LEVC 12/30 240 8858 148 39-29-39.84N 000-29-41.63W 39-29-00.96N 000-27-59.77W RWY LEVD 05/23 2776 9843 197 41-41-49.20N 004-51-53.10W 41-42-57.96N 004-50-20.90W RWY LEVD 15/33 2776 2976 197 41-42-47.88N 004-51-42.52W 41-42-24.12N 004-51-19.51W RWY LEZG 12L/30R 863 9843 148 41-40-08.76N 001-02-23.39W 41-39-19.44N 001-00-29.95W RWY LEZG 12R/30L 863 12198 148 41-40-48.72N 001-04-56.53W 41-39-48.60N 001-02-37.36W RWY LEZL 09/27 112 11024 148 37-25-04.44N 005-54-43.49W 37-25-04.80N 005-52-26.76W RWY LP77 15/33 541 4085 98 39-24-22.32N 008-17-34.04W 39-23-49.92N 008-17-05.96W RWY LPAR 04/22 11 9810 148 38-52-18.48N 009-02-21.23W 38-53-40.20N 009-01-14.38W RWY LPAV 17/35 26 4593 164 40-39-37.08N 008-44-44.30W 40-38-53.16N 008-44-29.26W RWY LPBG 02/20 2241 5600 98 41-51-01.08N 006-42-34.45W 41-51-55.08N 006-42-16.85W RWY LPBJ 01L/19R 636 11319 197 38-03-48.24N 007-56-03.95W 38-05-39.84N 007-55-49.33W RWY LPBJ 01R/19L 636 9682 98 38-03-55.44N 007-55-54.12W 38-05-30.84N 007-55-41.63W RWY LPBR 07/25 247 3117 82 41-35-06.00N 008-27-00.61W 41-35-20.40N 008-26-24.76W RWY LPCO 16/34 587 3018 98 40-09-39.60N 008-28-19.60W 40-09-12.24N 008-28-04.40W RWY LPCS 17/35 325 3969 98 38-43-46.20N 009-21-24.41W 38-43-09.12N 009-21-10.87W RWY LPEV 01/19 807 4265 75 38-31-40.08N 007-53-24.72W 38-32-21.48N 007-53-20.69W RWY LPFR 10/28 24 8169 148 37-01-02.28N 007-59-09.92W 37-00-48.24N 007-57-30.82W RWY LPMR 01/19 187 9816 148 39-49-04.08N 008-53-16.04W 39-50-40.92N 008-53-12.23W RWY LPMT 01/19 46 7044 148 38-41-59.64N 009-02-18.02W 38-43-10.56N 009-02-07.69W RWY LPMT 08/26 46 8005 148 38-42-18.00N 009-02-13.81W 38-42-41.76N 009-00-37.48W RWY LPOV 18/36 56 8005 148 40-55-36.48N 008-38-48.84W 40-54-18.00N 008-38-41.82W RWY LPPM 11/29 5 2819 98 37-09-01.80N 008-35-18.82W 37-08-53.52N 008-34-45.62W RWY LPPR 17/35 228 11417 148 41-15-47.88N 008-41-06.86W 41-13-57.00N 008-40-37.92W RWY LPPT 03/21 374 12484 148 38-45-56.52N 009-08-39.77W 38-47-50.28N 009-07-38.60W RWY LPPT 17/35 374 7874 148 38-47-10.32N 009-08-13.96W 38-45-54.00N 009-07-53.76W RWY LPST 14/32 440 5906 131 38-50-12.48N 009-20-48.77W 38-49-31.08N 009-19-56.75W RWY LPTN 08/26 266 7530 148 39-28-19.56N 008-23-08.56W 39-28-35.76N 008-21-34.85W RWY LPTN 12/30 266 3937 74 39-28-44.76N 008-22-25.68W 39-28-27.12N 008-21-40.93W RWY LPVR 02/20 1805 3107 98 41-16-13.08N 007-43-19.81W 41-16-42.24N 007-43-07.50W RWY LPVZ 01/19 2060 4015 97 40-43-12.00N 007-53-18.60W 40-43-51.60N 007-53-22.38W RWY LXGB 09/27 15 6000 150 36-09-03.24N 005-21-35.35W 36-09-05.76N 005-20-22.24W NAV AA NDB 40-26-53.52N 003-32-19.72W 0 355 - NAV ABT NDB 38-56-38.76N 001-59-51.61W 0 321 - NAV ACD NDB 40-35-08.52N 003-40-35.44W 0 417 - NAV ADX NDB 39-32-57.84N 002-23-45.10E 0 384 - NAV ALM VOR/DME 35-11-27.96N 003-50-30.23W 46 115.00 - NAV ALR VOR/DME 36-41-27.96N 003-12-56.02E 82 112.50 - NAV ALT VOR/DME 38-16-05.88N 000-34-12.41W 166 113.80 - NAV ALU NDB 35-10-52.31N 003-50-40.42W 0 401 - NAV AM NDB 36-52-32.88N 002-14-23.68W 0 284 - NAV AMN NDB 36-50-54.24N 002-22-44.98W 0 310 - NAV AMR VOR/DME 36-49-59.51N 002-15-33.91W 233 114.10 - NAV AOG TACAN 36-38-52.44N 006-20-56.62W 86 108.60 - NAV AOG NDB 36-38-31.56N 006-19-00.52W 0 268 - NAV ARM NDB 37-04-24.61N 003-48-07.49W 0 344 - NAV ARN NDB 40-57-50.05N 003-07-20.86W 0 291 - NAV ATE VOR/DME 38-17-09.95N 000-35-11.76W 192 114.65 - NAV ATR NDB 37-56-59.65N 001-13-49.51W 245 345 - NAV BAG NDB 41-57-05.40N 003-12-11.05E 0 319 - NAV BAI NDB 38-09-05.40N 003-37-45.01W 0 418 - NAV BAN VOR/DME 41-19-24.96N 002-37-47.24W 3717 112.80 - NAV BBI VOR/DME 41-01-00.48N 005-27-23.18W 2982 112.20 - NAV BCN VOR/DME 41-18-25.55N 002-06-28.12E 23 116.70 - NAV BEJ VORTAC 38-07-42.24N 007-55-36.08W 620 115.80 - NAV BGR VOR/DME 41-56-51.72N 003-12-31.90E 1082 112.20 - NAV BJ NDB 40-26-48.84N 003-33-45.18W 0 308 - NAV BJA NDB 36-42-24.12N 005-01-28.99E 0 423 - NAV BJA NDB 38-09-33.49N 007-55-18.16W 0 376 - NAV BJZ NDB 38-48-59.76N 006-41-53.48W 0 298 - NAV BLN VOR/DME 38-09-09.00N 003-37-30.04W 1788 116.20 - NAV BNA NDB 36-39-03.96N 003-35-29.00E 0 353 - NAV BRA VOR/DME 40-28-08.76N 003-33-27.14W 1962 116.45 - NAV BRB NDB 41-55-55.55N 005-40-00.80W 0 292 - NAV BRG NDB 41-47-48.12N 006-43-31.01W 2241 358 - NAV BSA VOR/DME 35-30-55.08N 004-24-06.01E 1328 115.90 - NAV BSA NDB 35-21-01.44N 004-13-30.07E 0 335 - NAV CA NDB 38-43-32.16N 009-21-29.99W 0 359 - NAV CAC NDB 39-31-44.04N 006-25-43.86W 0 380 - NAV CAS VOR/DME 38-44-53.88N 009-21-42.99W 326 114.30 - NAV CB NDB 40-09-38.16N 008-28-18.98W 0 426 - NAV CCH NDB 40-54-08.64N 001-17-53.92W 0 375 - NAV CCS VOR/DME 39-31-28.21N 006-26-05.06W 1394 114.20 - NAV CDB VOR/DME 37-50-45.25N 004-50-41.93W 325 112.40 - NAV CDP VOR/DME 39-41-51.72N 003-26-03.73E 778 112.90 - NAV CEU NDB 35-53-33.36N 005-18-19.58W 39 300 - NAV CHE NDB 36-36-05.03N 002-11-35.99E 0 397 - NAV CJN VOR/DME 40-22-19.21N 002-32-40.60W 3501 115.60 - NAV CLE VOR/DME 41-38-24.00N 002-38-04.81E 1351 115.35 - NAV CLS VOR/DME 39-42-25.92N 000-59-10.74W 1839 117.55 - NAV CMA VOR/DME 40-52-02.27N 001-17-52.98W 3150 116.00 - NAV CNR VOR/DME 40-38-45.60N 003-44-09.02W 2690 117.30 - NAV COR NDB 37-50-33.72N 004-50-48.52W 0 366 - NAV COV NDB 40-17-57.11N 007-25-32.99W 0 360 - NAV CP NDB 38-38-32.28N 009-13-17.47W 0 389 - NAV CST NDB 39-38-29.04N 002-54-56.23E 0 351 - NAV CTE NDB 40-23-02.04N 002-31-22.08W 0 362 - NAV CVT NDB 40-22-04.09N 003-46-24.28W 0 285 - NAV EAL NDB 38-57-07.93N 003-45-25.20W 0 332 - NAV EBT NDB 39-37-22.80N 000-28-19.50W 0 386 - NAV ECV NDB 40-41-57.85N 003-45-45.79W 0 319 - NAV EEC NDB 37-18-55.44N 006-00-04.72W 0 327 - NAV ESP VORTAC 38-25-27.48N 009-11-08.81W 648 112.50 - NAV FAR NDB 37-00-31.32N 007-55-33.35W 0 332 - NAV FTM VOR/DME 39-39-57.96N 008-29-35.56W 686 113.50 - NAV GBR TACAN 36-08-34.43N 005-20-33.79W 1397 113.60 - NAV GDA VOR/DME 37-10-59.52N 003-59-27.28W 1991 113.40 - NAV GE NDB 40-11-59.27N 003-50-39.37W 0 421 - NAV GIR VOR/DME 41-55-52.31N 002-46-19.09E 535 114.10 - NAV GM NDB 36-43-35.41N 004-34-17.22W 0 350 - NAV GRA NDB 37-11-21.84N 003-40-39.76W 0 412 - NAV GRS VOR 35-12-33.84N 000-08-56.09E 1686 113.10 - NAV GRS NDB 35-12-29.89N 000-09-36.00E 0 424 - NAV HIJ VOR/DME 38-30-29.15N 005-05-58.85W 1841 114.70 - NAV HMB NDB 35-21-47.15N 000-58-08.00W 0 432 - NAV HNS NDB 38-30-37.08N 005-06-39.82W 0 346 - NAV IBA VOR/DME 38-52-05.89N 001-21-57.28E 30 117.80 - NAV IZA NDB 38-54-55.80N 001-28-13.48E 0 394 - NAV JER NDB 36-50-04.20N 006-00-58.39W 0 433 - NAV JIL VOR/DME 36-46-36.12N 005-52-37.99E 49 117.90 - NAV JOA VOR/DME 39-33-52.92N 002-44-47.87E 26 117.70 - NAV JRZ VOR/DME 36-48-54.72N 006-01-35.54W 285 113.00 - NAV LAR NDB 38-59-39.48N 009-02-25.40W 0 382 - NAV LCZ NDB 37-40-34.68N 000-56-21.40W 0 381 - NAV LIS VOR/DME 38-53-21.84N 009-09-46.01W 1142 114.80 - NAV LO NDB 38-51-11.16N 009-05-51.00W 0 401 - NAV LRD NDB 41-33-10.43N 000-38-52.88E 0 404 - NAV MA NDB 40-24-02.88N 003-29-26.30W 0 390 - NAV MAR VOR/DME 37-03-19.09N 004-56-23.60W 2267 112.60 - NAV MAR NDB 36-41-06.72N 002-46-56.75E 0 416 - NAV MEL VOR/DME 35-16-49.44N 002-57-29.41W 200 114.25 - NAV MGA VOR/DME 36-48-51.48N 004-22-10.27W 3396 112.00 - NAV MHN VOR/DME 39-51-48.60N 004-13-01.88E 325 112.60 - NAV MIA NDB 35-18-28.08N 002-57-19.87W 381 292 - NAV MIO NDB 38-42-34.93N 009-02-35.63W 46 322 - NAV MJV VOR/DME 39-26-06.72N 002-45-29.84E 505 113.30 - NAV MLA VOR/DME 41-07-46.56N 000-09-54.88E 1184 112.10 - NAV MLG VOR/DME 36-40-43.32N 004-30-24.01W 75 113.55 - NAV MLL DME 35-18-26.64N 002-57-19.51W 381 117.40 - NAV MN NDB 39-50-11.39N 004-12-47.84E 297 344 - NAV MNF NDB 37-17-40.57N 005-33-43.70W 0 428 - NAV MOJ TACAN 38-42-31.68N 009-01-59.59W 66 110.00 - NAV MOS VOR/DME 35-53-54.97N 000-08-11.00E 732 112.20 - NAV MOS NDB 35-54-33.12N 000-08-14.00E 0 334 - NAV MRN TACAN 37-10-23.52N 005-37-10.70W 285 115.30 - NAV MRN VOR/DME 37-10-30.35N 005-37-08.11W 285 115.50 - NAV MTL NDB 39-54-28.08N 008-53-01.00W 0 336 - NAV MTN NDB 40-59-19.68N 005-19-47.75W 0 399 - NAV MTR TACAN 39-49-57.36N 008-53-24.50W 263 109.60 - NAV NSA VORTAC 39-33-52.92N 007-54-52.99W 1341 115.50 - NAV NVS VOR/DME 40-22-07.31N 004-14-57.91W 2516 114.95 - NAV ORA VOR/DME 35-36-45.35N 000-39-17.96W 284 114.00 - NAV OVR TACAN 40-53-13.20N 008-38-36.06W 102 110.60 - NAV PA NDB 39-35-57.84N 002-49-16.25E 0 308 - NAV PDT VOR/DME 40-15-10.44N 003-20-52.91W 2513 116.95 - NAV PG NDB 41-04-41.15N 008-38-12.01W 0 367 - NAV PND NDB 39-26-14.64N 000-20-47.26W 0 340 - NAV POR NDB 41-20-53.16N 008-42-29.02W 0 327 - NAV POS VOR/DME 39-55-38.64N 003-06-52.49E 1168 116.40 - NAV PRA VOR/DME 41-16-59.16N 002-04-54.70E 43 114.30 - NAV PRT VOR/DME 41-16-23.17N 008-41-16.01W 182 114.10 - NAV PTC NDB 39-25-38.28N 003-15-24.19E 0 401 - NAV RBO VOR/DME 40-51-14.04N 003-14-47.87W 3119 113.95 - NAV RES VOR/DME 41-08-58.92N 001-10-16.03E 272 114.20 - NAV RMA NDB 36-39-32.04N 004-28-36.26W 0 330 - NAV RS NDB 40-23-21.84N 003-33-44.14W 0 326 - NAV RUS NDB 41-08-52.08N 001-08-46.10E 0 424 - NAV SBD NDB 41-31-09.85N 002-06-10.98E 0 367 - NAV SCA NDB 40-55-37.92N 005-36-59.72W 0 423 - NAV SDM VOR 36-37-50.52N 002-58-27.37E 0 113.90 - NAV SGO NDB 39-40-27.11N 000-12-28.10W 0 356 - NAV SGR VOR/DME 37-05-02.04N 008-56-47.00W 500 113.90 - NAV SIE VOR/DME 41-09-06.12N 003-36-16.81W 5659 115.40 - NAV SLL VOR/DME 41-31-11.64N 002-06-35.10E 499 112.00 - NAV SMR NDB 36-41-34.45N 003-05-23.53E 0 370 - NAV SPP NDB 37-25-05.15N 005-47-43.87W 0 420 - NAV SRA VORTAC 38-49-45.12N 009-20-24.00W 440 112.10 - NAV SSJ TACAN 39-33-34.92N 002-43-59.70E 32 108.40 - NAV SSY VOR/DME 40-32-47.03N 003-34-30.68W 2012 117.85 - NAV SVL VOR/DME 37-25-40.43N 005-45-43.96W 404 113.70 - NAV TAB TACAN 38-56-44.88N 001-51-48.60W 2320 108.00 - NAV TBC TACAN 38-53-29.77N 006-49-07.25W 609 108.80 - NAV TEO NDB 39-58-22.08N 004-20-45.89W 0 385 - NAV TGR TACAN 37-07-57.00N 003-38-01.68W 2304 113.10 - NAV TJA NDB 40-34-05.16N 003-21-26.24W 0 426 - NAV TJZ TACAN 40-29-56.04N 003-26-43.76W 2011 112.50 - NAV TLD VOR/DME 39-58-10.21N 004-20-14.89W 1946 113.20 - NAV TLM VOR/DME 35-02-07.08N 001-23-17.02W 1001 116.50 - NAV TLM NDB 35-02-24.00N 001-22-04.01W 0 346 - NAV TNG VOR/DME 35-43-44.04N 005-53-26.99W 105 115.90 - NAV TOB NDB 39-46-59.52N 003-28-31.40W 0 403 - NAV TON NDB 41-55-40.43N 000-30-49.81W 0 335 - NAV TRB VOR/DME 35-20-52.08N 001-30-54.00E 2902 116.30 - NAV TRB NDB 35-20-44.87N 001-30-02.02E 0 389 - NAV TRL TACAN 37-57-03.96N 001-13-45.01W 243 116.60 - NAV TSC TACAN 40-57-18.72N 005-30-08.93W 2595 113.30 - NAV TTN VOR/DME 35-35-42.00N 005-19-28.99W 49 117.30 - NAV TUN NDB 35-36-56.88N 005-16-45.01W 0 388 - NAV TVD TACAN 41-42-14.77N 004-50-59.32W 2787 108.20 - NAV VAB VOR/DME 38-56-37.69N 002-00-09.61W 2277 115.80 - NAV VBZ VOR/DME 38-53-23.64N 006-48-56.70W 597 116.80 - NAV VFA VOR/DME 37-00-48.60N 007-58-30.04W 50 112.80 - NAV VGD NDB 41-00-05.75N 006-26-40.99W 0 365 - NAV VGE VOR 40-17-21.12N 003-43-37.56W 0 112.50 - NAV VGE TACAN 40-17-21.12N 003-43-37.56W 2029 112.05 - NAV VIS VOR/DME 40-43-23.88N 007-53-08.99W 2109 113.10 - NAV VJF VOR/DME 36-14-49.92N 005-58-18.73W 728 117.80 - NAV VJZ VOR/DME 40-33-50.75N 003-21-37.19W 2380 115.10 - NAV VLA VOR/DME 41-20-33.37N 001-32-51.72E 2077 113.15 - NAV VLC VOR/DME 39-29-08.16N 000-28-58.96W 200 116.10 - NAV VLD NDB 41-47-22.20N 004-44-20.69W 0 342 - NAV VNV NDB 41-12-38.17N 001-42-21.02E 0 380 - NAV VR NDB 41-12-55.09N 007-44-38.00W 0 304 - NAV VSJ TACAN 37-46-47.64N 000-48-46.40W 11 113.00 - NAV VSJ VOR/DME 37-46-47.28N 000-48-46.00W 11 113.00 - NAV VTB VOR/DME 39-46-50.88N 003-27-50.51W 2320 112.70 - NAV YES VOR/DME 38-21-38.89N 002-21-09.90W 4793 115.20 - NAV ZAR VOR/DME 41-39-28.45N 001-01-51.10W 876 113.00 - NAV ZEM VOR/DME 36-47-41.99N 003-34-14.99E 154 116.60 - NAV ZEM NDB 36-47-45.96N 003-34-18.98E 0 359 - NAV ZMR VOR/DME 41-31-48.72N 005-38-22.92W 2093 117.10 - NAV ZMR NDB 41-31-42.24N 005-39-06.26W 0 300 - NAV ZRZ NDB 41-43-49.80N 001-11-35.92W 0 389 - NAV ZZA NDB 41-35-56.04N 000-52-40.67W 0 348 - ILS 32R ILS/DME MBB 109.10 40-29-49.32N 003-33-36.14W 40-28-13.88N 003-31-59.62W 1938 5 322.2 3 ILS 32L ILS/DME MAA 109.90 40-29-13.32N 003-34-41.44W 40-27-22.40N 003-32-49.30W 1938 5 322.2 3 ILS 18L ILS/DME IML 111.50 40-29-54.24N 003-33-33.11W 40-31-57.48N 003-33-31.01W 2074 5 179.8 3 ILS 18R ILS/DME IMR 110.70 40-29-23.64N 003-34-28.62W 40-31-54.60N 003-34-26.71W 2074 5 179.8 3 ILS 02 ILS/DME BLT 108.75 41-18-43.03N 002-05-45.16E 41-17-15.10N 002-05-02.69E 59 5 19.0 3 ILS 07L ILS/DME QAA 110.30 41-18-24.53N 002-06-25.18E 41-17-30.08N 002-03-53.09E 19 5 65.6 3 ILS 25R ILS/DME BCA 109.50 41-17-28.98N 002-03-42.66E 41-18-23.44N 002-06-14.74E 43 5 245.6 3 ILS 07R ILS/DME BLE 110.75 41-17-35.94N 002-06-23.55E 41-16-53.36N 002-04-26.35E 19 5 65.6 3 ILS 25L ILS/DME BLW 111.50 41-16-52.26N 002-04-15.92E 41-17-34.84N 002-06-13.12E 43 5 245.6 3 ILS 06L ILS/DME PLM 110.90 39-33-50.08N 002-44-46.20E 39-32-46.85N 002-42-37.07E 13 5 58.5 3 ILS 24R ILS PAA 109.90 39-32-44.48N 002-42-27.92E 39-33-47.71N 002-44-37.04E 67 5 238.5 3 ILS 24L ILS/DME IPAL 109.30 39-32-23.63N 002-43-43.52E 39-33-21.80N 002-45-43.06E 67 5 238.7 3 ILS 13 ILS/DME GMM 109.50 36-39-48.99N 004-28-59.91W 36-41-01.88N 004-30-43.49W 106 5 131.5 3 ILS 31 ILS/DME GAA 109.90 36-41-10.65N 004-30-54.37W 36-39-57.76N 004-29-10.77W 0 5 311.5 3 acm-6.0_20200416/objects/zones/europe/france.txt0000644000000000000000000007100113646045023017662 0ustar rootroot# France zone. # Created: 2020-04-16 # Latitude range: [42N, 50N[ # Longitude range: [005W, 006E[ # 2017-11-01 Source: http://ourairports.com GROUND_COLOR #305030 RWY EBBX 06/24 1514 7874 148 49-52-53.76N 005-12-52.60E 49-53-34.44N 005-14-35.20E RWY EGJA 03/21 290 1630 121 49-42-19.08N 002-12-47.02W 49-42-33.12N 002-12-36.00W RWY EGJA 08/26 290 2887 75 49-42-21.60N 002-13-15.06W 49-42-26.64N 002-12-31.82W RWY EGJA 14/32 290 2402 121 49-42-32.04N 002-13-16.82W 49-42-15.84N 002-12-50.18W RWY EGJB 09/27 336 4800 148 49-26-04.92N 002-36-43.34W 49-26-06.72N 002-35-30.84W RWY EGJJ 08/26 277 5597 151 49-12-25.20N 002-12-24.95W 49-12-32.04N 002-11-01.25W RWY LEBB 10/28 138 6562 148 43-18-11.88N 002-56-13.31W 43-18-04.68N 002-54-45.14W RWY LEBB 12/30 138 8530 148 43-18-22.68N 002-55-29.78W 43-17-44.88N 002-53-46.68W RWY LEBG 06/24 2945 4393 98 42-21-15.12N 003-37-38.96W 42-21-39.60N 003-36-50.51W RWY LECD 07/25 3586 3773 75 42-23-04.20N 001-51-36.58E 42-23-17.88N 001-52-23.45E RWY LEPP 15/33 1504 7241 148 42-46-46.20N 001-39-11.70W 42-45-43.20N 001-38-25.80W RWY LESO 04/22 16 5755 148 43-21-01.44N 001-47-50.64W 43-21-45.72N 001-47-01.75W RWY LESU 04/22 2625 4396 98 42-20-13.56N 001-24-25.52E 42-20-47.40N 001-25-02.14E RWY LEVT 04/22 1682 11483 148 42-52-12.36N 002-44-13.31W 42-53-44.16N 002-42-42.80W RWY LEXJ 11/29 16 7612 148 43-25-50.88N 003-50-02.11W 43-25-24.96N 003-48-25.27W RWY LF50 07/25 255 3150 48 47-34-42.24N 000-25-04.90W 47-34-55.56N 000-24-23.44W RWY LF51 17/35 305 6562 98 44-11-19.68N 004-54-53.50E 44-10-18.12N 004-55-23.09E RWY LF52 05/23 866 7874 148 49-01-06.96N 005-51-48.31E 49-01-56.28N 005-53-19.39E RWY LFAG 09/27 295 4560 98 49-52-07.32N 003-01-11.64E 49-52-06.24N 003-02-21.34E RWY LFAI 05/23 428 3133 66 48-35-38.04N 003-00-06.91E 48-35-56.40N 003-00-44.21E RWY LFAI 06/24 428 3133 66 48-35-38.04N 003-00-06.91E 48-35-56.40N 003-00-44.21E RWY LFAO 12/30 718 3478 66 48-32-53.52N 000-23-37.19W 48-32-36.24N 000-22-52.41W RWY LFAQ 09/27 364 3838 82 49-58-17.40N 002-41-22.24E 49-58-17.40N 002-42-20.92E RWY LFAY 12/30 208 4134 82 49-52-31.80N 002-22-45.23E 49-52-13.80N 002-23-41.71E RWY LFBA 11/29 204 7103 98 44-10-39.72N 000-34-49.54E 44-10-13.08N 000-36-19.78E RWY LFBC 06/24 84 7900 148 44-31-40.80N 001-08-16.84W 44-32-24.00N 001-06-45.83W RWY LFBD 05/23 162 10171 148 44-49-08.76N 000-43-44.34W 44-50-19.32N 000-42-03.60W RWY LFBD 11/29 162 7923 148 44-49-53.76N 000-43-45.27W 44-49-31.44N 000-41-59.63W RWY LFBE 10/28 171 7234 148 44-49-31.08N 000-30-17.82E 44-49-25.68N 000-31-57.37E RWY LFBF 12/30 535 5906 148 43-32-56.76N 001-21-25.92E 43-32-32.28N 001-22-38.68E RWY LFBG 05/23 102 7949 148 45-38-54.24N 000-19-27.79W 45-39-45.00N 000-18-02.46W RWY LFBH 10/28 74 7398 148 46-10-46.92N 001-12-39.64W 46-10-43.68N 001-10-54.52W RWY LFBI 03/21 423 7710 148 46-34-46.56N 000-18-00.42E 46-35-52.44N 000-18-56.74E RWY LFBK 17/35 1497 6234 148 46-13-51.60N 002-21-40.50E 46-12-51.48N 002-22-00.01E RWY LFBL 03/21 1300 8202 148 45-51-09.00N 001-10-21.14E 45-52-16.68N 001-11-24.72E RWY LFBM 09/27 203 11821 148 43-54-38.52N 000-31-54.40W 43-54-44.28N 000-29-13.07W RWY LFBN 07/25 203 5774 98 46-18-29.88N 000-24-43.55W 46-18-52.20N 000-23-26.63W RWY LFBO 14L/32R 499 9843 148 43-38-14.64N 001-21-27.43E 43-36-56.16N 001-22-48.79E RWY LFBO 14R/32L 499 11483 148 43-38-38.76N 001-20-45.35E 43-37-08.40N 001-22-19.56E RWY LFBP 13/31 616 8202 148 43-23-15.72N 000-25-59.74W 43-22-28.20N 000-24-29.67W RWY LFBR 12/30 622 3609 98 43-27-05.04N 001-15-27.43E 43-26-48.84N 001-16-11.14E RWY LFBT 02/20 1260 9843 148 43-09-57.60N 000-00-45.90W 43-11-28.68N 000-00-00.25E RWY LFBU 10/28 436 5938 148 45-43-49.80N 000-12-25.67E 45-43-42.60N 000-13-48.77E RWY LFBX 11/29 328 5741 98 45-12-01.44N 000-48-20.77E 45-11-38.76N 000-49-34.27E RWY LFBZ 09/27 245 7382 148 43-28-05.52N 001-32-14.03W 43-28-06.60N 001-30-33.91W RWY LFCC 13/31 912 4921 98 44-21-20.16N 001-28-03.00E 44-20-49.92N 001-28-54.98E RWY LFCG 16/34 1368 3609 98 43-00-43.92N 001-06-00.25E 43-00-11.88N 001-06-22.43E RWY LFCH 08L/26R 49 4593 66 44-35-43.08N 001-07-05.02W 44-35-57.84N 001-06-04.00W RWY LFCI 09/27 564 5118 98 43-54-47.16N 002-06-03.38E 43-54-47.88N 002-07-13.37E RWY LFCK 14/32 788 5988 98 43-33-45.72N 002-16-55.56E 43-32-59.28N 002-17-46.54E RWY LFCL 15/33 459 3117 76 43-35-24.36N 001-29-49.09E 43-34-55.92N 001-30-04.93E RWY LFCM 14/32 2606 5577 98 43-59-43.44N 003-10-35.51E 43-58-59.88N 003-11-22.06E RWY LFCQ 10/28 581 3166 66 43-46-13.08N 002-00-20.88E 43-46-09.12N 002-01-03.72E RWY LFCR 13/31 1910 6693 148 44-24-49.32N 002-28-21.58E 44-24-07.56N 002-29-33.50E RWY LFCU 10/28 2428 4429 98 45-32-12.84N 002-24-58.61E 45-32-05.64N 002-25-59.70E RWY LFCW 10/28 190 3412 98 44-23-56.40N 000-45-14.02E 44-23-49.56N 000-45-59.98E RWY LFCY 10/28 72 4117 98 45-37-54.48N 000-58-48.35W 45-37-46.56N 000-57-51.58W RWY LFCZ 08/26 164 3412 66 44-08-43.80N 001-10-51.17W 44-08-48.12N 001-10-04.80W RWY LFDA 12/30 259 3281 98 43-42-42.84N 000-15-08.00W 43-42-29.88N 000-14-27.00W RWY LFDB 14/32 351 3215 66 44-01-43.68N 001-22-25.32E 44-01-21.36N 001-22-56.71E RWY LFDH 01/19 411 4921 98 43-40-37.20N 000-35-57.11E 43-41-25.44N 000-36-01.29E RWY LFDI 04/22 157 3609 66 44-58-42.96N 000-08-19.60W 44-59-11.76N 000-07-50.60W RWY LFDJ 09/27 1115 4265 98 43-05-26.88N 001-41-23.89E 43-05-25.44N 001-42-21.31E RWY LFDM 11/29 105 3937 98 44-30-02.16N 000-11-35.98E 44-29-50.28N 000-12-27.71E RWY LFDN 12/30 60 7480 148 45-53-46.32N 000-59-50.14W 45-53-06.36N 000-58-21.07W RWY LFED 10/28 407 3675 98 48-03-32.04N 002-55-45.59W 48-03-29.52N 002-54-51.44W RWY LFEH 06/24 630 3330 66 47-28-42.60N 002-23-20.04E 47-28-59.16N 002-24-02.02E RWY LFES 03/21 574 4921 98 48-02-46.68N 003-40-07.14W 48-03-31.68N 003-39-39.28W RWY LFEY 14/32 79 4035 82 46-43-19.56N 002-23-46.82W 46-42-48.24N 002-23-11.18W RWY LFFI 07/25 111 3937 82 47-24-23.76N 001-11-06.61W 47-24-35.28N 001-10-11.86W RWY LFFN 10/28 381 8038 148 48-25-53.40N 004-27-53.57E 48-25-41.16N 004-29-51.29E RWY LFGF 03/21 656 3462 98 47-00-06.12N 004-53-25.12E 47-00-37.08N 004-53-47.15E RWY LFGJ 05/23 645 7318 148 47-01-59.16N 005-24-55.22E 47-02-41.28N 005-26-21.08E RWY LFGK 08/26 732 3510 98 47-59-29.40N 003-23-06.79E 47-59-35.52N 003-23-58.60E RWY LFGW 10/28 1230 3675 66 49-07-23.52N 005-27-41.33E 49-07-17.40N 005-28-35.65E RWY LFHQ 01/19 3218 4298 98 45-04-11.64N 002-59-29.36E 45-04-53.40N 002-59-38.87E RWY LFHS 18/36 857 3737 98 46-12-21.60N 005-17-31.24E 46-11-44.88N 005-17-31.42E RWY LFHV 18/36 1076 3412 98 45-55-23.88N 004-38-06.00E 45-54-50.04N 004-38-05.32E RWY LFHV 18L/36R 1076 3609 262 45-55-24.60N 004-38-09.74E 45-54-49.68N 004-38-08.09E RWY LFHY 08/26 915 4265 98 46-32-01.68N 003-24-55.19E 46-32-07.44N 003-25-55.63E RWY LFIF 12/30 1686 4265 66 43-49-40.44N 002-44-20.62E 43-49-20.28N 002-45-11.92E RWY LFIG 10/28 2024 3445 66 44-10-47.28N 002-30-43.42E 44-10-44.76N 002-31-30.58E RWY LFJA 01/19 1001 4921 148 48-04-46.56N 005-02-53.16E 48-05-35.16N 005-03-00.00E RWY LFJB 04/22 576 4265 66 46-53-57.12N 000-42-05.05W 46-54-30.96N 000-41-28.95W RWY LFJR 08/26 194 5906 148 47-33-32.04N 000-19-28.83W 47-33-41.76N 000-18-03.45W RWY LFJU 06/24 746 4960 55 46-42-35.28N 002-56-15.54E 46-43-02.28N 002-57-14.90E RWY LFJU 06R/24L 746 2170 125 46-42-33.84N 002-56-22.31E 46-42-45.36N 002-56-48.66E RWY LFLA 01/19 523 5413 98 47-50-34.80N 003-29-45.96E 47-51-27.72N 003-29-53.56E RWY LFLB 18/36 779 6628 148 45-38-49.56N 005-52-46.13E 45-37-44.40N 005-52-51.46E RWY LFLC 08/26 1090 9885 148 45-47-05.28N 003-09-02.95E 45-47-18.96N 003-11-20.98E RWY LFLD 06/24 529 5085 148 47-03-23.76N 002-21-35.57E 47-03-49.68N 002-22-38.39E RWY LFLE 15/33 973 3281 66 45-33-52.56N 005-58-19.42E 45-33-27.00N 005-58-46.06E RWY LFLH 17/35 623 4725 98 46-49-57.00N 004-48-58.03E 46-49-10.92N 004-49-08.98E RWY LFLL 17L/35R 821 8760 148 45-44-05.64N 005-05-30.73E 45-42-39.60N 005-05-41.21E RWY LFLL 17R/35L 821 13124 148 45-44-47.76N 005-05-09.38E 45-42-38.52N 005-05-25.08E RWY LFLM 17/35 728 4036 79 46-18-02.16N 004-47-41.82E 46-17-22.56N 004-47-47.62E RWY LFLN 15L/33R 796 6660 148 46-25-19.20N 004-00-25.63E 46-24-23.40N 004-01-15.96E RWY LFLN 15R/33L 796 4921 98 46-24-59.40N 004-00-25.85E 46-24-18.00N 004-01-03.36E RWY LFLS 09/27 1302 10007 148 45-21-46.80N 005-18-35.68E 45-21-46.44N 005-20-55.82E RWY LFLT 11/29 771 3281 98 46-21-14.76N 002-33-51.77E 46-21-03.60N 002-34-35.72E RWY LFLU 01/19 525 6890 148 44-54-43.92N 004-58-05.16E 44-55-51.60N 004-58-18.12E RWY LFLV 01/19 817 7218 148 46-09-35.64N 003-24-06.19E 46-10-46.20N 003-24-20.70E RWY LFLW 15/33 2096 5577 98 44-53-52.44N 002-25-00.98E 44-53-06.00N 002-25-38.78E RWY LFLX 04/22 529 11483 148 46-51-02.16N 001-43-09.01E 46-52-36.84N 001-44-39.01E RWY LFLY 16/34 659 5971 148 45-44-06.00N 004-56-27.35E 45-43-09.48N 004-56-51.40E RWY LFMA 14/32 367 5249 98 43-30-41.76N 005-21-44.50E 43-29-58.92N 005-22-24.60E RWY LFMH 18/36 1325 7546 148 45-33-04.32N 004-17-42.50E 45-31-49.80N 004-17-51.94E RWY LFMI 15/33 82 12303 197 43-32-16.08N 004-54-47.88E 43-30-28.08N 004-56-04.63E RWY LFMK 10/28 433 6726 148 43-13-01.56N 002-17-35.41E 43-12-54.00N 002-19-05.63E RWY LFML 13L/31R 74 11483 148 43-26-56.76N 005-11-50.32E 43-25-38.28N 005-13-42.46E RWY LFML 13R/31L 74 7776 148 43-26-28.68N 005-12-10.87E 43-25-33.24N 005-13-27.66E RWY LFMO 15/33 197 7909 197 44-08-56.04N 004-51-35.06E 44-07-52.68N 004-52-38.50E RWY LFMP 13/31 144 4150 66 42-44-23.28N 002-51-55.58E 42-43-58.44N 002-52-39.36E RWY LFMP 15/33 144 8202 148 42-45-14.76N 002-51-42.16E 42-44-06.00N 002-52-39.90E RWY LFMQ 13/31 1391 5741 98 43-15-25.92N 005-46-35.62E 43-14-52.08N 005-47-37.75E RWY LFMS 01/19 668 4576 98 44-03-48.60N 004-08-24.79E 44-04-32.88N 004-08-38.40E RWY LFMT 12L/30R 17 8530 164 43-35-09.96N 003-57-20.63E 43-34-22.08N 003-58-55.99E RWY LFMT 12R/30L 17 3609 98 43-34-32.88N 003-57-06.80E 43-34-12.72N 003-57-47.12E RWY LFMU 10/28 56 5971 98 43-19-27.12N 003-20-33.90E 43-19-22.44N 003-21-54.22E RWY LFMV 17/35 124 6168 148 43-54-56.16N 004-53-58.42E 43-53-56.40N 004-54-14.69E RWY LFMY 16/34 195 6565 148 43-36-56.52N 005-06-15.88E 43-35-55.68N 005-06-46.94E RWY LFMZ 08/26 207 3281 98 43-10-28.92N 002-43-42.38E 43-10-35.40N 002-44-26.02E RWY LFNB 13/31 3362 4265 98 44-30-19.80N 003-31-34.28E 44-29-55.32N 003-32-22.27E RWY LFNH 13/31 394 3937 66 44-02-00.60N 005-04-21.00E 44-01-34.32N 005-05-01.64E RWY LFOA 06/24 580 11493 148 47-02-52.44N 002-36-42.37E 47-03-48.60N 002-39-06.62E RWY LFOB 04/22 359 3625 98 49-27-16.56N 002-06-46.87E 49-27-43.56N 002-07-23.77E RWY LFOB 13/31 359 7972 148 49-27-29.88N 002-06-13.86E 49-26-46.32N 002-07-54.26E RWY LFOC 10/28 433 7552 148 48-03-34.56N 001-21-40.82E 48-03-24.12N 001-23-30.88E RWY LFOD 10/28 269 4757 98 47-15-26.64N 000-07-28.51W 47-15-22.68N 000-06-19.85W RWY LFOE 04/22 464 9826 148 49-01-05.88N 001-12-24.16E 49-02-20.40N 001-13-58.87E RWY LFOH 05/23 313 7546 130 49-31-35.40N 000-04-39.31E 49-32-29.76N 000-05-57.57E RWY LFOJ 07/25 412 7887 148 47-59-02.04N 001-44-44.02E 47-59-29.40N 001-46-32.48E RWY LFOK 10/28 587 12664 148 48-46-46.56N 004-09-30.28E 48-46-22.08N 004-12-35.75E RWY LFOP 04/22 512 5577 148 49-22-46.20N 001-10-06.42E 49-23-27.60N 001-11-02.18E RWY LFOQ 12/30 398 4101 98 47-40-53.76N 001-12-08.32E 47-40-33.60N 001-12-57.10E RWY LFOT 02/20 357 7887 148 47-25-18.48N 000-43-24.27E 47-26-33.72N 000-43-54.48E RWY LFOU 03/21 443 4528 98 47-04-35.40N 000-52-51.27W 47-05-16.08N 000-52-23.58W RWY LFOV 14/32 330 5020 98 48-02-12.48N 000-44-57.26W 48-01-33.24N 000-44-12.25W RWY LFOZ 05/23 396 4567 98 47-53-38.76N 002-09-26.42E 47-54-06.12N 002-10-19.96E RWY LFPB 03/21 218 8743 197 48-56-55.32N 002-25-36.70E 48-58-13.80N 002-26-31.74E RWY LFPB 07/25 218 9843 148 48-57-49.68N 002-25-13.04E 48-58-26.40N 002-27-29.70E RWY LFPB 09/27 218 6053 148 48-57-49.32N 002-25-13.44E 48-57-54.36N 002-26-44.27E RWY LFPC 07/25 291 7871 164 49-14-56.40N 002-30-15.01E 49-15-29.16N 002-32-02.72E RWY LFPG 08L/26R 392 13829 148 48-59-44.52N 002-33-09.86E 48-59-55.68N 002-36-36.65E RWY LFPG 08R/26L 392 8858 197 48-59-34.44N 002-33-56.38E 48-59-41.64N 002-36-08.75E RWY LFPG 09L/27R 392 8858 197 49-01-28.92N 002-31-29.60E 49-01-36.12N 002-33-42.08E RWY LFPG 09R/27L 392 13780 148 49-01-14.16N 002-30-47.02E 49-01-25.32N 002-34-13.04E RWY LFPK 09/27 470 4593 66 48-50-15.36N 003-00-22.57E 48-50-15.00N 003-01-31.19E RWY LFPK 09L/27R 470 2132 164 48-50-19.32N 003-00-53.82E 48-50-18.96N 003-01-25.75E RWY LFPK 09R/27L 470 2165 262 48-50-06.72N 003-00-04.10E 48-50-06.36N 003-00-36.58E RWY LFPM 01/19 302 4265 98 48-36-21.96N 002-40-15.53E 48-37-03.00N 002-40-29.46E RWY LFPM 10/28 302 6480 148 48-36-23.40N 002-39-47.84E 48-36-08.28N 002-41-21.44E RWY LFPN 07L/25R 538 3609 98 48-45-04.32N 002-05-55.43E 48-45-15.84N 002-06-46.44E RWY LFPN 07R/25L 538 3445 98 48-44-58.20N 002-05-59.06E 48-45-09.36N 002-06-47.45E RWY LFPO 02/20 291 7874 197 48-43-03.00N 002-22-36.12E 48-44-16.80N 002-23-13.09E RWY LFPO 06/24 291 11975 148 48-43-12.00N 002-19-00.91E 48-44-07.80N 002-21-38.45E RWY LFPO 08/26 291 10892 148 48-43-09.84N 002-21-30.92E 48-43-38.64N 002-24-07.45E RWY LFPT 05/23 325 5541 164 49-05-16.08N 002-01-38.64E 49-05-54.96N 002-02-37.14E RWY LFPT 12/30 325 5413 164 49-06-06.84N 002-01-32.45E 49-05-41.64N 002-02-44.20E RWY LFPV 09/27 584 5948 148 48-46-26.76N 002-11-21.41E 48-46-28.56N 002-12-50.15E RWY LFQA 07/25 313 3773 98 49-12-24.12N 004-08-59.32E 49-12-39.24N 004-09-51.44E RWY LFQB 05/23 388 2559 328 48-19-00.12N 004-00-27.22E 48-19-16.32N 004-00-58.03E RWY LFQB 17/35 388 5413 98 48-19-46.20N 004-00-55.19E 48-18-52.92N 004-01-03.90E RWY LFQB 17R/35L 388 2953 328 48-19-32.16N 004-00-44.96E 48-19-03.00N 004-00-49.75E RWY LFQE 01/19 770 7874 148 49-12-59.04N 005-40-06.02E 49-14-14.64N 005-40-33.85E RWY LFQF 18/36 997 3350 98 46-58-18.84N 004-15-38.05E 46-57-45.72N 004-15-37.66E RWY LFQF 18L/36R 997 2087 164 46-58-17.40N 004-15-39.92E 46-57-56.88N 004-15-39.92E RWY LFQG 12/30 602 5348 98 47-00-23.40N 003-06-15.30E 46-59-55.32N 003-07-20.71E RWY LFQV 11/29 492 4921 98 49-47-11.40N 004-38-14.75E 49-46-53.04N 004-39-24.16E RWY LFRB 07L/25R 325 2297 59 48-26-59.28N 004-25-20.71W 48-27-06.84N 004-24-48.28W RWY LFRB 07R/25L 325 10171 148 48-26-36.24N 004-26-18.06W 48-27-08.28N 004-23-55.28W RWY LFRC 10/28 459 8005 148 49-39-07.92N 001-29-12.70W 49-38-53.16N 001-27-13.18W RWY LFRD 12/30 219 4708 148 48-35-25.80N 002-05-19.97W 48-35-06.00N 002-04-16.68W RWY LFRD 17/35 219 7218 148 48-35-53.16N 002-04-57.65W 48-34-42.96N 002-04-39.22W RWY LFRE 11/29 105 3117 82 47-17-24.36N 002-21-06.62W 47-17-15.36N 002-20-23.39W RWY LFRF 07/25 45 3150 98 48-52-49.80N 001-34-17.36W 48-53-03.12N 001-33-34.74W RWY LFRG 12/30 479 8366 148 49-22-13.80N 000-08-19.37E 49-21-36.36N 000-10-11.76E RWY LFRH 02/20 160 5479 148 47-45-22.32N 003-26-30.52W 47-46-14.16N 003-26-08.20W RWY LFRH 07/25 160 7884 148 47-45-22.68N 003-27-33.01W 47-45-46.80N 003-25-43.43W RWY LFRI 10/28 299 5085 98 46-42-11.88N 001-23-18.82W 46-42-02.16N 001-22-07.28W RWY LFRJ 08/26 348 8858 148 48-31-36.12N 004-10-09.01W 48-32-00.96N 004-08-03.01W RWY LFRK 05/23 256 3871 98 49-10-15.24N 000-27-16.09W 49-10-39.00N 000-26-30.15W RWY LFRK 13/31 256 6233 148 49-10-51.60N 000-27-59.10W 49-10-15.96N 000-26-42.61W RWY LFRL 05/23 287 3635 131 48-16-42.96N 004-27-03.46W 48-17-05.64N 004-26-21.16W RWY LFRL 13/31 287 2133 177 48-17-02.04N 004-26-46.57W 48-16-48.72N 004-26-21.62W RWY LFRM 02/20 194 4658 98 47-56-30.84N 000-11-52.76E 47-57-13.68N 000-12-16.53E RWY LFRN 10/28 124 6890 148 48-04-25.32N 001-44-45.96W 48-04-12.72N 001-43-06.20W RWY LFRN 14/32 124 2788 98 48-04-11.64N 001-44-25.80W 48-03-50.04N 001-44-00.71W RWY LFRO 11/29 290 5577 148 48-45-23.76N 003-28-57.76W 48-45-07.20N 003-27-38.77W RWY LFRQ 04/22 297 2657 148 47-58-08.04N 004-10-24.92W 47-58-30.00N 004-10-04.04W RWY LFRQ 10/28 297 7054 148 47-58-32.52N 004-11-07.22W 47-58-28.20N 004-09-23.76W RWY LFRS 03/21 90 9514 148 47-08-29.76N 001-37-10.34W 47-09-53.28N 001-36-06.84W RWY LFRT 06/24 453 7218 148 48-31-59.16N 002-52-02.57W 48-32-36.24N 002-50-30.62W RWY LFRU 04/22 272 5305 118 48-35-51.72N 003-49-22.58W 48-36-31.68N 003-48-31.79W RWY LFRV 04/22 446 5020 148 47-43-04.44N 002-43-29.86W 47-43-42.96N 002-42-43.49W RWY LFRV 08/26 446 3363 197 47-43-26.40N 002-43-52.72W 47-43-30.72N 002-43-04.01W RWY LFRZ 07/25 13 7874 148 47-18-32.76N 002-09-51.95W 47-18-55.08N 002-08-02.15W RWY LFSD 02/20 726 5905 118 47-15-51.12N 005-04-55.38E 47-16-48.72N 005-05-18.46E RWY LFSD 18/36 726 7874 148 47-16-35.76N 005-05-36.92E 47-15-18.36N 005-05-46.93E RWY LFSI 11/29 458 7913 148 48-38-25.08N 004-53-03.70E 48-37-54.48N 004-54-52.09E RWY LFSO 02/20 1106 7878 148 48-34-22.80N 005-56-56.72E 48-35-36.24N 005-57-35.82E RWY LFTW 18/36 309 8005 148 43-46-06.24N 004-24-56.02E 43-44-47.04N 004-25-01.70E RWY LFXA 01/19 823 6562 98 45-58-42.24N 005-19-36.41E 45-59-46.68N 005-19-48.40E RWY LFXA 02/20 823 2625 328 45-58-35.40N 005-20-07.26E 45-59-00.60N 005-20-16.58E NAV AGN VOR/DME 43-53-16.80N 000-52-22.30E 868 114.80 - NAV ALD NDB 49-42-32.04N 002-11-58.92W 331 383 - NAV ALM NDB 43-30-28.08N 005-21-37.69E 367 430 - NAV AMB VOR/DME 47-25-44.05N 001-03-51.98E 361 113.70 - NAV AMB NDB 47-25-05.53N 001-02-27.60E 354 341 - NAV AMU TACAN 45-59-18.97N 005-19-52.50E 801 116.30 - NAV ANG VOR 47-32-12.84N 000-51-06.60W 283 113.00 - NAV ARE VOR 48-19-57.36N 003-36-08.89W 588 112.50 - NAV ATN VOR/DME 46-48-21.24N 004-15-32.90E 2244 114.90 - NAV AVD TACAN 47-03-29.17N 002-37-47.50E 554 110.60 - NAV AVD NDB 47-07-14.52N 002-47-58.60E 679 289 - NAV AVN VOR 43-59-43.44N 004-44-47.00E 0 112.30 - NAV BD NDB 44-56-06.72N 000-33-44.10W 60 393 - NAV BDX TACAN 44-49-37.93N 000-43-23.80W 155 114.40 - NAV BE NDB 44-52-14.17N 000-23-52.10W 251 318 - NAV BGC NDB 44-49-10.20N 000-37-09.40E 0 374 - NAV BGP NDB 48-26-40.91N 004-24-59.40W 0 387 - NAV BGS NDB 42-21-29.16N 003-38-07.37W 2945 357 - NAV BLV VOR/DME 43-18-15.85N 002-56-09.17W 141 115.90 - NAV BMC VOR/DME 44-49-36.84N 000-43-16.00W 161 113.75 - NAV BRY VOR/DME 48-24-25.21N 003-17-41.21E 258 114.10 - NAV BSN VOR/DME 49-11-17.88N 003-03-23.29E 476 114.85 - NAV BST TACAN 48-17-04.56N 004-27-07.60W 286 114.70 - NAV BST NDB 48-17-00.96N 004-25-55.99W 0 428 - NAV BT VOR/DME 48-58-28.92N 002-27-18.61E 200 116.10 - NAV BTZ VOR/DME 43-27-59.75N 001-30-37.01W 233 114.15 - NAV BVS VOR 49-26-11.04N 002-09-11.48E 0 115.90 - NAV BZ NDB 43-28-13.80N 001-24-13.28W 295 341 - NAV CAA TACAN 44-31-52.32N 001-08-09.71W 74 110.80 - NAV CAA NDB 44-33-04.68N 001-07-11.89W 0 382 - NAV CAN VOR 49-10-18.12N 000-27-20.40W 256 115.40 - NAV CAV VOR/DME 48-46-51.96N 004-08-48.98E 538 111.65 - NAV CBY VOR/DME 45-52-54.84N 005-45-26.32E 4783 115.40 - NAV CDN NDB 48-03-44.64N 001-21-49.10E 433 360 - NAV CFA VOR/DME 45-47-14.99N 003-11-31.88E 1093 114.35 - NAV CGC TACAN 45-39-41.40N 000-18-28.30W 93 116.20 - NAV CGC NDB 45-40-09.48N 000-18-22.30W 113 354 - NAV CGN VOR/DME 49-01-11.64N 002-30-00.40E 356 115.35 - NAV CHW VOR/DME 48-28-48.00N 000-59-13.40E 702 115.20 - NAV CLM VOR/DME 48-50-40.56N 003-00-49.90E 486 112.90 - NAV CM NDB 43-54-29.87N 004-54-19.30E 124 369 - NAV CNA VOR/DME 45-39-34.56N 000-18-41.90W 85 114.65 - NAV CNE NDB 49-06-56.52N 000-19-16.50W 0 404 - NAV CPE VOR/DME 49-25-58.08N 002-47-57.70E 288 109.65 - NAV CRL VORTAC 49-15-19.08N 002-30-53.21E 325 109.20 - NAV CSM NDB 44-05-13.56N 001-07-50.81E 0 327 - NAV CTL VOR/DME 49-08-15.72N 003-34-39.68E 641 117.60 - NAV CTX NDB 46-56-11.76N 001-48-04.10E 539 428 - NAV DA NDB 44-03-59.04N 004-08-32.32E 681 402 - NAV DGO VOR/DME 42-27-11.88N 002-52-50.56W 2126 112.60 - NAV DIJ TACAN 47-16-18.84N 005-05-29.51E 726 113.50 - NAV DIN VOR/DME 48-35-09.97N 002-04-56.39W 213 114.30 - NAV DJL VOR/DME 47-16-14.89N 005-05-50.39E 726 111.45 - NAV DPE VOR 49-55-31.44N 001-10-14.30E 362 115.80 - NAV DVL VOR 49-18-38.52N 000-18-45.80E 497 110.20 - NAV EAG NDB 42-27-04.69N 002-18-53.06W 0 399 - NAV EPR VOR/DME 48-37-32.53N 001-39-23.62E 518 115.65 - NAV EVX VORTAC 49-01-54.12N 001-13-15.10E 499 112.40 - NAV FJR VOR/DME 43-34-42.24N 003-58-28.99E 17 114.45 - NAV GAI VOR 43-57-14.77N 001-49-27.01E 972 115.80 - NAV GL NDB 47-03-10.08N 001-41-16.19W 61 369 - NAV GRB NDB 49-26-04.21N 002-38-22.24W 0 361 - NAV GRN NDB 42-01-30.01N 002-48-25.96E 0 412 - NAV GU NDB 48-28-39.72N 004-17-07.80W 0 338 - NAV GUR VOR/DME 49-26-13.56N 002-36-07.42W 355 109.40 - NAV GUY NDB 49-26-11.40N 002-36-06.41W 0 361 - NAV HIG NDB 43-23-10.68N 001-47-45.20W 433 328 - NAV HOL NDB 48-43-50.15N 001-49-13.80E 0 315 - NAV ITR TACAN 43-31-33.96N 004-55-36.91E 82 115.70 - NAV ITR NDB 43-31-34.32N 004-55-47.78E 82 391 - NAV JSY VOR/DME 49-13-15.96N 002-02-46.00W 276 112.20 - NAV LCA VOR 46-41-29.04N 002-08-58.49E 882 112.10 - NAV LDV TACAN 48-31-41.88N 004-09-22.72W 364 115.15 - NAV LGL VOR 48-47-26.16N 000-31-49.00E 971 115.00 - NAV LM NDB 47-53-36.96N 000-10-17.00E 0 326 - NAV LMG VOR/DME 45-48-57.24N 001-01-32.09E 1375 114.50 - NAV LN NDB 48-43-09.48N 003-18-28.01W 297 345 - NAV LNP VOR 45-29-23.28N 005-26-24.00E 0 113.45 - NAV LOR TACAN 47-45-41.40N 003-26-28.21W 141 115.80 - NAV LOR NDB 47-45-47.52N 003-26-26.48W 161 359 - NAV LPA VOR/DME 42-27-37.80N 002-19-36.88W 1348 115.45 - NAV LSE VOR/DME 45-44-43.80N 005-05-26.09E 821 114.75 - NAV LTP VOR/DME 45-29-20.39N 005-26-20.62E 2165 115.55 - NAV MAR NDB 43-29-23.28N 005-08-14.10E 0 383 - NAV MBY VOR 46-32-28.69N 003-29-58.42E 0 109.60 - NAV MC NDB 46-22-21.36N 002-29-33.61E 1049 335 - NAV MDM TACAN 43-54-35.64N 000-30-15.80W 256 108.70 - NAV MEN VOR/DME 44-36-29.88N 003-09-44.71E 4515 115.30 - NAV MJ NDB 43-26-21.12N 005-13-03.00E 0 406 - NAV ML DME 43-26-39.49N 005-12-07.81E 0 110.30 - NAV MLN VOR/DME 48-27-20.88N 002-48-47.81E 335 113.60 - NAV MLX NDB 48-38-48.13N 003-45-45.68W 0 371 - NAV MM NDB 46-36-05.03N 004-19-53.00E 0 317 - NAV MMD VOR 49-23-28.68N 005-07-27.91E 1076 109.40 - NAV MOU VOR/DME 46-42-24.47N 003-37-54.01E 699 116.70 - NAV MOU NDB 46-42-21.23N 003-37-51.10E 0 324 - NAV MRM VOR/DME 43-22-38.28N 005-19-35.18E 771 108.80 - NAV MS NDB 43-23-18.96N 005-17-00.49E 0 343 - NAV MT NDB 47-20-01.68N 002-02-40.20W 67 398 - NAV MTD VOR 49-33-09.36N 002-29-22.09E 0 113.65 - NAV MTG VOR/DME 43-23-10.68N 005-05-12.59E 650 117.30 - NAV MTL VOR/DME 44-33-17.64N 004-46-47.50E 656 113.65 - NAV NAY TACAN 48-35-00.96N 005-57-06.59E 1115 116.80 - NAV NB NDB 45-08-51.00N 000-32-59.70W 155 361 - NAV NEA VOR/DME 42-01-39.36N 004-06-32.87W 3002 116.75 - NAV NEV VOR 47-09-10.80N 002-55-45.70E 593 113.40 - NAV NG NDB 43-51-25.92N 004-24-22.61E 0 354 - NAV NIM TACAN 43-44-44.88N 004-25-10.42E 309 111.60 - NAV NO NDB 42-45-00.00N 001-37-54.01W 0 386 - NAV NTS VOR/DME 47-09-39.24N 001-36-46.69W 82 115.50 - NAV OAN TACAN 47-59-21.84N 001-45-34.49E 402 116.40 - NAV OAN NDB 48-00-04.68N 001-46-07.39E 0 385 - NAV OB NDB 43-13-47.28N 005-39-55.51E 0 395 - NAV OL VOR/DME 48-43-47.64N 002-23-11.11E 285 111.20 - NAV ORG TACAN 44-08-21.48N 004-51-57.82E 197 109.40 - NAV ORG NDB 44-08-54.24N 004-51-25.88E 197 328 - NAV PAM NDB 42-42-51.12N 001-38-20.54W 0 422 - NAV PAP VOR/DME 42-41-18.24N 001-39-38.81W 1890 113.55 - NAV PAS VOR/DME 46-09-49.32N 005-59-59.71E 1418 116.60 - NAV PGS VOR/DME 48-59-58.20N 002-37-25.72E 325 117.05 - NAV PI NDB 46-42-14.04N 000-24-25.10E 316 363 - NAV POI VOR 46-34-51.60N 000-17-53.50E 426 113.30 - NAV PON VOR 49-05-45.96N 002-02-09.20E 318 111.60 - NAV PPG VOR/DME 42-45-01.80N 002-52-01.70E 134 116.25 - NAV PPN VOR/DME 42-44-01.32N 001-42-07.20W 3419 112.30 - NAV PTV VOR 48-09-20.17N 002-15-53.21E 424 116.50 - NAV QPR VOR/DME 47-57-26.27N 004-11-04.99W 285 117.80 - NAV RBT VOR/DME 48-39-14.04N 001-59-39.19E 577 114.70 - NAV REM VORTAC 49-18-41.76N 004-02-43.30E 335 112.30 - NAV REN VOR/DME 48-04-09.11N 001-44-30.01W 126 109.25 - NAV RLP VOR/DME 47-54-22.68N 005-14-57.01E 1490 117.30 - NAV ROA VOR 46-03-33.12N 003-59-57.41E 1106 109.20 - NAV ROU VOR 49-27-56.16N 001-16-50.30E 0 116.80 - NAV RQ NDB 47-58-05.88N 003-59-54.38W 386 380 - NAV RTN NDB 47-19-11.28N 001-41-16.91E 0 301 - NAV SA NDB 43-26-06.00N 003-50-59.64W 0 416 - NAV SAL TACAN 43-36-42.48N 005-06-10.12E 195 115.15 - NAV SAL NDB 43-36-38.16N 005-06-04.00E 195 334 - NAV SAU VOR 44-40-36.48N 000-09-10.50W 385 116.80 - NAV SCL NDB 44-03-02.52N 005-30-12.49E 0 348 - NAV SDI TACAN 48-38-13.20N 004-53-21.08E 492 114.00 - NAV SDI NDB 48-37-44.41N 004-54-38.41E 0 373 - NAV SEO NDB 42-13-55.92N 001-24-12.67E 0 340 - NAV SFC VOR 45-03-59.41N 002-59-26.70E 3222 109.80 - NAV SNR VOR/DME 43-26-59.27N 003-54-08.68W 164 115.30 - NAV SR NDB 47-15-34.19N 000-06-51.70W 0 372 - NAV SSN VOR/DME 43-18-40.32N 001-49-49.40W 804 117.90 - NAV TA NDB 48-46-17.76N 002-05-50.78E 0 287 - NAV TAN VOR 43-28-00.13N 000-01-06.30W 964 111.80 - NAV TBO VOR 43-19-55.92N 000-08-44.70E 1020 113.90 - NAV TH NDB 48-46-40.80N 002-22-43.39E 0 302 - NAV TIS VOR/DME 45-52-54.49N 003-33-12.89E 2258 117.50 - NAV TL NDB 43-17-18.24N 000-02-58.70E 928 321 - NAV TLU TACAN 43-32-54.60N 001-22-05.59E 597 116.00 - NAV TOE NDB 43-28-51.95N 001-40-47.60E 898 415 - NAV TOU VOR/DME 43-40-50.89N 001-18-35.32E 555 117.70 - NAV TRO VOR 48-15-04.33N 003-57-47.30E 859 116.00 - NAV TS NDB 43-30-26.28N 001-29-12.41E 844 423 - NAV TSU VOR 48-45-13.32N 002-06-08.50E 547 108.25 - NAV TUR TACAN 47-25-19.92N 000-43-51.21E 329 113.80 - NAV TUR NDB 47-33-57.24N 000-46-57.40E 551 331 - NAV TW NDB 43-31-50.17N 001-01-31.01E 813 406 - NAV VE NDB 44-50-56.40N 004-57-19.80E 0 320 - NAV VFD VOR/DME 42-52-50.16N 002-43-27.66W 1696 112.90 - NAV VIA VOR/DME 42-21-18.00N 003-36-48.89W 2970 111.40 - NAV VMP VOR/DME 48-03-32.04N 001-23-20.00E 433 117.20 - NAV VNE VOR 45-33-23.04N 004-53-00.31E 0 108.20 - NAV VRA VOR/DME 42-43-54.84N 002-51-56.09W 1903 116.60 - NAV VTA NDB 42-55-41.16N 002-40-46.60W 0 345 - NAV YN NDB 46-41-20.75N 001-17-10.72W 302 334 - # Paris, Charles De Gaulle (LFPG): ILS 08L ILS GLE 108.70 48-59-56.47N 002-36-51.36E 48-59-41.31N 002-33-09.34E 387 5 85.3 3 ILS 26R ILS GAU 109.10 48-59-43.72N 002-32-55.15E 48-59-58.89N 002-36-37.18E 397 5 265.3 3 ILS 08R ILS/DME DSE 108.55 48-59-42.44N 002-36-23.46E 48-59-31.23N 002-33-55.86E 387 5 85.3 3 ILS 26L ILS/DME DSU 108.35 48-59-33.64N 002-33-41.67E 48-59-44.85N 002-36-09.28E 397 5 265.3 3 ILS 09L ILS/DME PNE 109.35 49-01-36.92N 002-33-56.80E 49-01-25.71N 002-31-29.08E 387 5 85.3 3 ILS 27R ILS/DME PNW 110.35 49-01-28.12N 002-31-14.88E 49-01-39.33N 002-33-42.61E 397 5 265.3 3 ILS 09R ILS/DME CGE 110.10 49-01-26.11N 002-34-27.76E 49-01-10.95N 002-30-46.50E 387 5 85.3 3 ILS 27L ILS/DME PNW 110.35 49-01-13.36N 002-30-32.31E 49-01-28.53N 002-34-13.57E 397 5 265.3 3 # Paris, Le Bourget (LFPB): ILS 07 ILS/DME LBG 109.50 48-58-30.07N 002-27-43.36E 48-57-46.72N 002-25-11.45E 193 5 67.8 3 ILS 25 ILS LBW 111.10 48-57-46.01N 002-24-59.39E 48-58-29.35N 002-27-31.30E 243 5 247.8 3 ILS 27 ILS/DME RGE 110.55 48-57-48.50N 002-24-58.74E 48-57-57.57N 002-26-44.79E 224 5 265.2 3 # Paris, Orly (LFPO): ILS 02 ILS OLN 110.30 48-44-26.02N 002-23-17.71E 48-43-02.08N 002-22-32.57E 228 5 18.3 3 ILS 06 ILS/DME ORE 108.50 48-44-12.38N 002-21-51.40E 48-43-09.19N 002-18-59.00E 260 5 61.9 3 ILS 24 ILS/DME OLO 110.90 48-43-07.41N 002-18-47.97E 48-44-10.60N 002-21-40.36E 322 5 241.8 3 ILS 08 LOCALIZER OLE 108.15 48-43-41.24N 002-24-21.59E 48-43-06.75N 002-21-29.74E 273 5 74.5 3 ILS 26 ILS/DME OLW 111.75 48-43-07.24N 002-21-16.78E 48-43-41.73N 002-24-08.63E 309 5 254.4 3 acm-6.0_20200416/objects/zones/europe/united-kingdom.txt0000644000000000000000000010121313646045023021341 0ustar rootroot# United Kingdom zone. # Created: 2020-04-16 # Latitude range: [50N, 60N[ # Longitude range: [010W, 002E[ # 2017-11-01 Source: http://ourairports.com GROUND_COLOR #305030 RWY EG74 06/24 467 9842 197 52-28-47.64N 001-08-58.13W 52-29-38.40N 001-06-42.66W RWY EGAA 07/25 268 9121 148 54-39-08.28N 006-14-06.86W 54-39-46.08N 006-11-46.25W RWY EGAA 17/35 268 6401 148 54-39-28.44N 006-13-43.03W 54-38-33.36N 006-13-11.96W RWY EGAB 15/33 155 4350 98 54-24-11.88N 007-39-29.99W 54-23-38.04N 007-38-42.00W RWY EGAC 04/22 15 6001 148 54-36-41.04N 005-52-50.59W 54-37-29.64N 005-51-51.95W RWY EGAE 02/20 22 3955 148 55-02-12.12N 007-09-55.44W 55-02-49.20N 007-09-35.03W RWY EGAE 08/26 22 6076 147 55-02-25.44N 007-10-30.18W 55-02-42.72N 007-08-50.39W RWY EGBB 15/33 327 8527 151 52-27-56.16N 001-45-40.00W 52-26-47.04N 001-44-22.99W RWY EGBE 05/23 267 5988 151 52-21-51.84N 001-29-21.41W 52-22-31.80N 001-28-10.45W RWY EGBG 04/22 469 1608 59 52-36-12.96N 001-01-46.99W 52-36-25.92N 001-01-32.02W RWY EGBG 06/24 469 1099 98 52-36-19.08N 001-01-50.99W 52-36-24.84N 001-01-37.99W RWY EGBG 10/28 469 3084 98 52-36-29.16N 001-02-19.00W 52-36-25.92N 001-01-31.01W RWY EGBG 15/33 469 1624 59 52-36-28.08N 001-02-02.00W 52-36-14.04N 001-01-48.00W RWY EGBG 16/34 469 1371 98 52-36-27.00N 001-01-58.01W 52-36-15.48N 001-01-47.50W RWY EGBJ 04/22 101 3218 112 51-53-18.96N 002-10-05.27W 51-53-45.24N 002-09-36.29W RWY EGBJ 09/27 101 4656 112 51-53-36.96N 002-10-37.99W 51-53-40.92N 002-09-24.08W RWY EGBJ 18/36 101 2625 59 51-53-48.12N 002-09-58.00W 51-53-22.92N 002-09-54.00W RWY EGBN 03/21 138 2693 75 52-55-00.12N 001-04-45.98W 52-55-23.16N 001-04-25.00W RWY EGBN 09/27 138 3445 98 52-55-10.92N 001-05-08.99W 52-55-12.00N 001-04-12.00W RWY EGBO 04/22 283 2083 59 52-30-57.96N 002-15-58.00W 52-31-15.96N 002-15-38.02W RWY EGBO 10/28 283 2624 75 52-31-02.28N 002-16-02.50W 52-30-58.68N 002-15-20.45W RWY EGBO 16/34 283 3878 75 52-31-20.64N 002-15-47.63W 52-30-45.36N 002-15-22.36W RWY EGBP 08/26 433 6591 148 51-39-59.76N 002-04-15.89W 51-40-10.56N 002-02-32.75W RWY EGBT 09/27 448 3002 60 52-02-26.52N 001-06-07.99W 52-02-26.88N 001-05-21.01W RWY EGBW 05/23 159 1932 59 52-11-13.92N 001-37-04.01W 52-11-27.60N 001-36-41.00W RWY EGBW 18/36 159 3009 75 52-11-47.04N 001-36-54.00W 52-11-17.16N 001-36-50.00W RWY EGCC 05L/23R 257 10000 150 53-20-42.36N 002-17-33.86W 53-21-44.64N 002-15-25.70W RWY EGCC 05R/23L 257 9997 150 53-19-55.20N 002-18-38.38W 53-20-56.76N 002-16-29.96W RWY EGCK 02/20 1 3534 75 53-05-58.20N 004-20-32.57W 53-06-31.68N 004-20-19.43W RWY EGCK 08/26 1 2887 75 53-06-02.16N 004-20-35.99W 53-06-11.88N 004-19-48.22W RWY EGCN 02/20 55 9491 197 53-27-44.64N 001-00-40.14W 53-29-13.56N 000-59-51.86W RWY EGCW 04/22 233 3346 59 52-37-29.28N 003-09-27.94W 52-37-55.92N 003-08-56.40W RWY EGDC 10/28 27 6014 151 51-05-13.56N 004-09-48.64W 51-05-13.92N 004-08-14.46W RWY EGDM 05/23 407 10538 150 51-08-38.76N 001-46-07.00W 51-09-43.20N 001-44-04.27W RWY EGDM 17/35 407 6278 150 51-09-41.76N 001-44-01.28W 51-08-41.28N 001-43-38.39W RWY EGDR 07/25 267 3372 151 50-05-06.72N 005-15-48.49W 50-05-22.20N 005-15-01.76W RWY EGDR 12/30 267 6006 151 50-05-18.96N 005-15-57.28W 50-04-55.92N 005-14-32.46W RWY EGDR 18/36 267 3448 151 50-05-24.00N 005-15-06.73W 50-04-49.80N 005-15-05.29W RWY EGDX 08/26 163 5988 141 51-24-10.08N 003-26-45.64W 51-24-27.36N 003-25-15.31W RWY EGDY 04/22 75 4797 151 51-00-13.32N 002-38-39.08W 51-00-51.12N 002-37-53.83W RWY EGDY 09/27 75 7580 151 51-00-25.20N 002-39-42.19W 51-00-34.20N 002-37-44.54W RWY EGEC 11/29 42 10003 151 55-26-27.60N 005-42-34.34W 55-26-00.24N 005-39-47.66W RWY EGEO 01/19 20 4068 98 56-27-18.36N 005-24-19.40W 56-27-53.64N 005-24-04.57W RWY EGFA 08/26 428 3031 75 52-06-50.40N 004-33-48.10W 52-06-59.76N 004-33-01.91W RWY EGFE 03/21 159 5000 148 51-49-37.56N 004-57-59.90W 51-50-20.40N 004-57-20.45W RWY EGFE 09/27 159 3412 148 51-50-02.04N 004-58-13.01W 51-50-03.12N 004-57-19.01W RWY EGFF 12/30 220 7848 151 51-24-05.40N 003-21-31.25W 51-23-30.48N 003-19-40.76W RWY EGFH 04/22 299 4429 151 51-35-59.64N 004-04-27.16W 51-36-36.36N 004-03-43.74W RWY EGFH 10/28 299 2812 151 51-36-04.32N 004-04-34.54W 51-36-01.44N 004-03-50.29W RWY EGGD 09/27 622 6598 151 51-22-55.56N 002-44-00.60W 51-22-59.52N 002-42-16.81W RWY EGGP 09/27 80 7500 151 53-19-58.44N 002-51-57.67W 53-20-03.84N 002-49-57.68W RWY EGGW 08/26 526 7086 151 51-52-19.20N 000-23-00.78W 51-52-37.92N 000-21-12.00W RWY EGHH 08/26 38 7451 151 50-46-39.00N 001-51-28.55W 50-46-57.72N 001-49-36.44W RWY EGHI 02/20 44 5653 121 50-56-34.80N 001-21-39.17W 50-57-27.36N 001-21-09.86W RWY EGHL 09/27 618 5896 131 51-11-13.20N 001-02-47.15W 51-11-17.52N 001-01-14.84W RWY EGHQ 12/30 390 9006 285 50-26-49.20N 005-00-43.31W 50-26-04.20N 004-58-43.54W RWY EGKA 02/20 7 3399 59 50-49-55.20N 000-17-58.31W 50-50-23.64N 000-17-40.54W RWY EGKA 07/25 7 2877 164 50-49-57.36N 000-18-01.05W 50-50-10.32N 000-17-20.16W RWY EGKA 13/31 7 1312 98 50-50-17.88N 000-17-40.28W 50-50-10.32N 000-17-23.07W RWY EGKB 03/21 598 5912 148 51-19-24.96N 000-01-37.41E 51-20-17.88N 000-02-16.98E RWY EGKB 11/29 598 2598 59 51-19-24.60N 000-01-40.18E 51-19-17.76N 000-02-19.60E RWY EGKC 02/20 1 1995 59 50-47-57.12N 000-39-42.40W 50-48-12.60N 000-39-23.44W RWY EGKK 08L/26R 202 8415 148 51-08-48.84N 000-12-45.25W 51-09-06.48N 000-10-36.53W RWY EGKK 08R/26L 202 10364 148 51-08-42.36N 000-12-44.33W 51-09-04.32N 000-10-05.49W RWY EGLC 09/27 19 4948 98 51-30-20.16N 000-02-39.06E 51-30-17.64N 000-03-57.16E RWY EGLF 06/24 238 8005 148 51-16-14.16N 000-47-31.36W 51-16-50.88N 000-45-40.18W RWY EGLJ 18/36 240 4167 151 51-40-59.88N 001-04-37.52W 51-40-18.84N 001-04-35.18W RWY EGLK 07/25 325 4380 151 51-19-19.56N 000-51-23.84W 51-19-32.52N 000-50-18.16W RWY EGLL 09L/27R 83 12799 164 51-28-39.00N 000-29-21.94W 51-28-39.72N 000-25-59.75W RWY EGLL 09R/27L 83 12001 148 51-27-53.64N 000-29-12.38W 51-27-54.00N 000-26-02.67W RWY EGLM 03/21 131 3363 148 51-29-44.52N 000-46-04.82W 51-30-14.40N 000-46-06.95W RWY EGLM 07/25 131 3642 148 51-29-54.96N 000-46-53.98W 51-30-09.72N 000-46-04.82W RWY EGLM 11/29 131 3051 98 51-29-58.92N 000-46-47.09W 51-29-49.20N 000-46-04.83W RWY EGMC 05/23 49 5023 121 51-34-01.92N 000-41-10.56E 51-34-32.16N 000-42-17.99E RWY EGMD 03/21 13 4938 121 50-57-01.80N 000-56-00.11E 50-57-41.76N 000-56-40.81E RWY EGMD 14/32 13 2264 115 50-57-29.16N 000-56-00.00E 50-57-12.96N 000-56-23.00E RWY EGNC 01/19 190 3077 75 54-56-06.00N 002-48-41.00W 54-56-36.24N 002-48-40.00W RWY EGNC 07/25 190 6075 98 54-55-59.88N 002-49-17.00W 54-56-30.12N 002-47-47.00W RWY EGNE 03/21 91 5522 98 53-16-25.32N 000-57-24.59W 53-17-14.64N 000-56-45.41W RWY EGNE 08/26 91 2662 150 53-16-37.92N 000-58-09.00W 53-16-42.96N 000-57-26.00W RWY EGNE 15/33 91 2764 150 53-16-54.84N 000-58-00.00W 53-16-33.96N 000-57-31.00W RWY EGNH 07/25 34 2621 98 53-46-20.64N 003-02-28.79W 53-46-30.36N 003-01-48.36W RWY EGNH 10/28 34 6132 151 53-46-19.92N 003-02-33.68W 53-46-15.24N 003-00-51.98W RWY EGNH 13/31 34 3533 75 53-46-28.20N 003-02-37.43W 53-46-06.96N 003-01-50.66W RWY EGNJ 02/20 121 7205 148 53-33-55.08N 000-21-25.41W 53-35-00.96N 000-20-40.00W RWY EGNJ 08/26 121 3458 98 53-34-32.88N 000-21-12.49W 53-34-37.56N 000-20-15.69W RWY EGNL 05/23 173 3438 151 54-07-26.04N 003-15-58.00W 54-07-48.00N 003-15-15.01W RWY EGNL 12/30 173 1326 151 54-07-58.08N 003-16-13.22W 54-07-42.96N 003-15-11.92W RWY EGNL 17/35 173 3318 151 54-07-59.16N 003-16-09.44W 54-07-27.48N 003-15-56.05W RWY EGNM 14/32 681 7382 150 53-52-24.24N 001-40-19.45W 53-51-30.24N 001-38-56.65W RWY EGNO 08/26 55 7946 151 53-44-29.04N 002-54-04.61W 53-44-54.24N 002-51-59.44W RWY EGNO 14/32 55 4189 98 53-44-43.44N 002-53-49.52W 53-44-15.00N 002-52-57.43W RWY EGNR 04/22 45 6702 148 53-10-16.32N 002-59-15.50W 53-11-06.00N 002-58-03.47W RWY EGNS 03/21 52 3934 151 54-04-40.08N 004-37-54.01W 54-05-14.28N 004-37-23.23W RWY EGNS 08/26 52 5751 151 54-04-54.12N 004-38-12.98W 54-05-04.92N 004-36-40.00W RWY EGNS 17/35 52 2963 89 54-05-07.08N 004-37-49.01W 54-04-41.88N 004-37-39.00W RWY EGNT 07/25 266 7642 151 55-02-00.60N 001-42-22.82W 55-02-32.28N 001-40-23.77W RWY EGNV 05/23 120 7516 151 54-30-07.92N 001-26-32.75W 54-30-58.32N 001-24-58.97W RWY EGNX 09/27 306 9491 151 52-49-50.16N 001-20-58.45W 52-49-53.04N 001-18-24.01W RWY EGOD 05/23 30 4328 151 52-48-20.88N 004-08-02.08W 52-48-48.96N 004-07-09.30W RWY EGOD 15/33 30 4207 151 52-48-55.44N 004-08-07.80W 52-48-19.08N 004-07-34.39W RWY EGOD 17/35 30 7500 151 52-48-55.08N 004-07-49.01W 52-47-42.00N 004-07-27.34W RWY EGOE 05/23 272 3215 150 52-52-14.52N 002-32-09.71W 52-52-36.84N 002-31-35.62W RWY EGOE 10/28 272 3110 150 52-52-24.60N 002-32-24.61W 52-52-20.28N 002-31-36.55W RWY EGOQ 04/22 202 5180 150 53-15-14.04N 004-22-51.46W 53-15-54.36N 004-21-59.83W RWY EGOS 05/23 249 4523 151 52-47-33.72N 002-40-36.05W 52-48-05.40N 002-39-44.32W RWY EGOS 18/36 249 6018 151 52-48-06.48N 002-40-04.73W 52-47-07.44N 002-40-04.55W RWY EGOV 01/19 37 5377 151 53-14-36.96N 004-32-26.02W 53-15-29.16N 004-32-16.40W RWY EGOV 08/26 37 2200 151 53-14-44.88N 004-32-44.99W 53-14-58.92N 004-31-40.15W RWY EGOV 13/31 37 7513 151 53-15-13.68N 004-32-46.32W 53-14-25.80N 004-31-12.90W RWY EGOW 03/21 37 5405 150 53-34-31.08N 003-03-49.79W 53-35-17.52N 003-03-04.79W RWY EGOW 08/26 37 3505 148 53-34-39.00N 003-04-05.38W 53-34-44.76N 003-03-08.14W RWY EGPA 06/24 50 3881 151 58-57-20.88N 002-54-42.73W 58-57-41.04N 002-53-39.98W RWY EGPA 09/27 50 4685 151 58-57-27.72N 002-54-46.51W 58-57-29.88N 002-53-16.19W RWY EGPA 15/33 50 2231 59 58-57-37.80N 002-54-33.19W 58-57-23.76N 002-54-10.91W RWY EGPB 06H/24H 20 1804 148 59-52-29.28N 001-17-25.69W 59-52-39.72N 001-16-57.65W RWY EGPB 09/27 20 3871 151 59-52-50.88N 001-18-18.94W 59-52-55.20N 001-17-03.59W RWY EGPB 15/33 20 4678 151 59-52-54.84N 001-18-01.76W 59-52-17.76N 001-17-07.08W RWY EGPC 08/26 126 3399 148 58-27-20.88N 003-06-05.80W 58-27-29.16N 003-05-03.91W RWY EGPC 13/31 126 5988 148 58-27-49.32N 003-06-19.69W 58-27-13.68N 003-04-49.55W RWY EGPD 05/23 215 1893 151 57-12-12.96N 002-12-10.01W 57-12-25.92N 002-11-44.99W RWY EGPD 14/32 215 2165 75 57-12-14.04N 002-12-06.98W 57-11-57.84N 002-11-41.50W RWY EGPD 16/34 215 6001 151 57-12-34.20N 002-12-12.28W 57-11-39.48N 002-11-31.78W RWY EGPD 18/36 215 853 75 57-12-16.92N 002-12-06.01W 57-12-08.64N 002-12-05.72W RWY EGPE 05/23 31 6191 151 57-32-13.20N 004-03-34.24W 57-32-52.80N 004-02-08.05W RWY EGPE 12/30 31 2297 59 57-32-40.56N 004-03-35.53W 57-32-33.00N 004-02-55.72W RWY EGPF 05/23 26 8720 151 55-51-48.60N 004-26-56.62W 55-52-47.64N 004-25-05.92W RWY EGPF 09/27 26 3622 151 55-52-19.92N 004-26-40.99W 55-52-19.20N 004-25-38.10W RWY EGPH 06/24 135 8400 150 55-56-38.40N 003-23-24.50W 55-57-21.24N 003-21-18.22W RWY EGPH 08/26 135 2621 150 55-56-48.48N 003-21-21.64W 55-56-57.48N 003-20-37.28W RWY EGPH 12/30 135 5730 150 55-57-04.68N 003-21-33.98W 55-56-37.68N 003-20-05.64W RWY EGPI 08/26 56 2083 59 55-40-57.36N 006-15-32.51W 55-41-03.84N 006-14-57.98W RWY EGPI 13/31 56 5069 151 55-41-12.84N 006-16-45.98W 55-40-54.12N 006-15-24.16W RWY EGPK 03/21 65 6000 148 55-29-18.24N 004-35-14.68W 55-30-12.24N 004-34-32.74W RWY EGPK 12/30 65 9800 150 55-30-59.04N 004-36-53.14W 55-30-08.64N 004-34-28.13W RWY EGPL 06/24 19 6024 151 57-28-35.04N 007-22-31.01W 57-29-08.88N 007-21-00.25W RWY EGPL 17/35 19 4003 151 57-29-12.84N 007-21-56.70W 57-28-34.32N 007-21-40.25W RWY EGPN 09/27 17 4593 98 56-27-09.00N 003-02-13.85W 56-27-08.64N 003-00-52.13W RWY EGPO 06/24 26 3281 75 58-12-43.56N 006-20-08.92W 58-12-59.40N 006-19-15.78W RWY EGPO 18/36 26 7218 151 58-13-31.44N 006-19-58.58W 58-12-20.88N 006-19-45.12W RWY EGPU 05/23 38 4600 98 56-29-42.00N 006-52-37.88W 56-30-12.96N 006-51-37.87W RWY EGPU 11/29 38 2690 62 56-30-10.08N 006-52-45.98W 56-30-01.08N 006-52-00.01W RWY EGPU 17/35 38 1968 58 56-30-27.00N 006-52-39.00W 56-30-07.92N 006-52-32.02W RWY EGQK 07/25 22 7582 151 57-38-45.60N 003-34-43.75W 57-39-10.44N 003-32-32.57W RWY EGQL 04/22 38 4803 151 56-22-11.64N 002-52-27.44W 56-22-49.80N 002-51-36.72W RWY EGQL 09/27 38 8491 150 56-22-22.80N 002-52-54.16W 56-22-35.04N 002-50-24.90W RWY EGQS 05/23 42 9091 150 57-41-52.80N 003-21-12.31W 57-42-57.60N 003-19-16.72W RWY EGQS 10/28 42 6066 150 57-42-26.28N 003-20-37.82W 57-42-19.44N 003-18-46.84W RWY EGSC 05/23 47 6447 151 52-11-57.48N 000-09-50.48E 52-12-38.52N 000-11-09.53E RWY EGSC 05G/23G 47 2949 115 52-12-11.16N 000-10-32.14E 52-12-29.88N 000-11-08.40E RWY EGSC 10/28 47 2293 115 52-12-11.88N 000-10-07.18E 52-12-07.92N 000-10-43.49E RWY EGSF 10/28 26 3238 75 52-28-06.96N 000-15-30.00W 52-28-04.08N 000-14-38.00W RWY EGSF 16/34 26 2625 141 52-28-06.96N 000-15-27.00W 52-27-43.92N 000-15-06.00W RWY EGSH 04/22 117 4154 148 52-40-27.48N 001-16-55.49E 52-41-00.24N 001-17-35.56E RWY EGSH 09/27 117 6040 148 52-40-32.88N 001-16-08.58E 52-40-33.60N 001-17-46.57E RWY EGSS 04/22 348 10003 151 51-52-30.36N 000-13-11.73E 51-53-42.72N 000-15-00.16E RWY EGSU 06/24 125 4931 148 52-05-12.84N 000-07-25.00E 52-05-36.96N 000-08-32.00E RWY EGSU 06L/24R 125 2887 82 52-05-21.84N 000-07-31.00E 52-05-36.96N 000-08-11.00E RWY EGSX 02/20 321 6332 148 51-42-56.88N 000-09-12.03E 51-43-56.64N 000-09-39.61E RWY EGSX 13/31 321 3005 148 51-43-31.44N 000-08-47.53E 51-43-13.80N 000-09-26.14E RWY EGTC 03/21 358 5902 151 52-03-54.72N 000-37-24.95W 52-04-44.40N 000-36-35.27W RWY EGTC 18/36 358 2033 59 52-04-23.88N 000-37-15.40W 52-04-04.08N 000-37-12.84W RWY EGTE 08/26 102 6834 151 50-43-55.20N 003-25-41.30W 50-44-11.40N 003-23-58.20W RWY EGTE 13/31 102 4393 151 50-44-18.60N 003-25-37.34W 50-43-57.00N 003-24-38.20W RWY EGTK 01/19 270 4327 75 51-49-51.96N 001-19-12.00W 51-50-30.84N 001-19-00.01W RWY EGTK 03/21 270 2887 154 51-49-49.08N 001-19-05.99W 51-50-16.08N 001-18-47.99W RWY EGTK 09/27 270 2887 148 51-50-04.56N 001-19-31.01W 51-50-06.00N 001-18-47.02W RWY EGTK 11/29 270 2493 92 51-50-25.80N 001-19-22.19W 51-50-16.80N 001-18-45.00W RWY EGTP 01/19 330 2054 88 50-19-40.80N 005-10-30.68W 50-20-00.96N 005-10-27.23W RWY EGTP 05/23 330 3084 59 50-19-39.00N 005-11-03.73W 50-20-00.96N 005-10-30.65W RWY EGTP 09/27 330 2461 75 50-19-44.04N 005-11-09.28W 50-19-45.48N 005-10-31.44W RWY EGTU 04/22 839 3176 150 50-51-22.32N 003-14-16.80W 50-51-46.08N 003-13-44.40W RWY EGTU 09/27 839 2845 150 50-51-51.48N 003-14-25.01W 50-51-55.08N 003-13-41.02W RWY EGTU 17/35 839 2113 65 50-51-51.84N 003-14-06.00W 50-51-30.96N 003-13-59.99W RWY EGUB 01/19 226 5981 150 51-36-24.84N 001-05-51.54W 51-37-23.16N 001-05-38.65W RWY EGUB 06/24 226 4782 100 51-36-53.64N 001-06-08.39W 51-37-19.92N 001-05-05.39W RWY EGUL 06/24 32 9000 150 52-24-09.00N 000-32-39.78E 52-24-59.04N 000-34-39.53E RWY EGUN 11/29 33 9221 200 52-21-51.48N 000-28-04.80E 52-21-31.32N 000-30-29.40E RWY EGUO 01/19 593 3593 150 51-26-16.08N 002-17-08.99W 51-26-51.36N 002-17-04.06W RWY EGUO 07/25 593 5459 151 51-26-15.72N 002-17-27.02W 51-26-38.40N 002-16-08.98W RWY EGUW 05/23 284 7953 151 52-07-14.16N 000-56-37.68E 52-08-03.48N 000-58-06.71E RWY EGUY 09/27 135 8255 200 52-21-18.72N 000-07-28.39W 52-21-29.16N 000-05-16.54W RWY EGUY 15/33 135 2500 59 52-21-37.08N 000-06-55.29W 52-21-15.48N 000-06-35.88W RWY EGVA 09/27 286 9994 200 51-40-58.80N 001-48-43.20W 51-41-02.40N 001-46-04.80W RWY EGVN 08/26 288 10007 184 51-44-45.96N 001-36-14.87W 51-45-14.04N 001-33-42.44W RWY EGVO 09/27 405 6030 141 51-14-04.20N 000-57-21.19W 51-14-01.68N 000-55-46.66W RWY EGWC 06/24 272 3890 150 52-38-15.72N 002-18-45.76W 52-38-36.24N 002-17-52.22W RWY EGWU 07/25 124 5545 151 51-33-00.36N 000-25-51.67W 51-33-19.08N 000-24-29.40W RWY EGXC 07/25 25 9003 200 53-05-21.48N 000-11-08.03W 53-05-49.20N 000-08-48.09W RWY EGXD 10/28 117 4469 151 54-08-38.04N 001-25-40.58W 54-08-35.88N 001-24-25.60W RWY EGXD 15/33 117 6096 151 54-08-38.76N 001-25-36.91W 54-07-45.84N 001-24-46.44W RWY EGXE 16/34 132 7520 150 54-18-06.84N 001-32-33.40W 54-16-59.52N 001-31-41.45W RWY EGXG 06/24 29 6158 151 53-49-46.56N 001-12-26.06W 53-50-21.48N 001-11-02.29W RWY EGXG 16/34 29 5466 151 53-50-39.12N 001-12-10.08W 53-49-50.16N 001-11-33.04W RWY EGXH 09/27 174 9012 200 52-20-27.60N 000-45-11.20E 52-20-40.92N 000-47-34.46E RWY EGXP 04/22 202 8990 200 53-17-55.32N 000-33-51.67W 53-19-01.92N 000-32-14.31W RWY EGXT 08/26 273 9052 200 52-36-34.20N 000-29-43.80W 52-37-00.12N 000-27-24.00W RWY EGXU 03/21 53 6020 150 54-02-32.64N 001-15-37.51W 54-03-23.04N 001-14-44.74W RWY EGXU 10/28 53 4394 150 54-02-58.20N 001-15-45.50W 54-02-53.52N 001-14-32.32W RWY EGXW 02/20 231 9000 200 53-09-16.92N 000-31-53.33W 53-10-39.36N 000-30-58.79W RWY EGXY 07/25 228 5994 150 53-01-01.92N 000-55-41.84W 53-01-28.56N 000-54-14.49W RWY EGXY 12/30 228 4239 150 53-01-16.32N 000-55-29.64W 53-00-55.44N 000-54-29.62W RWY EGXY 16/34 228 4419 150 53-01-38.28N 000-54-55.25W 53-01-00.48N 000-54-19.93W RWY EGXZ 03/21 92 5951 150 54-11-51.72N 001-23-13.42W 54-12-47.52N 001-22-35.29W RWY EGXZ 13/31 92 4140 150 54-12-33.12N 001-23-19.97W 54-12-09.36N 001-22-23.59W RWY EGYD 01/19 218 4803 147 53-01-15.96N 000-29-07.49W 53-02-02.40N 000-28-56.39W RWY EGYD 09/27 218 6831 147 53-01-43.32N 000-30-20.53W 53-01-50.88N 000-28-43.47W RWY EGYD 09R/27L 218 2354 131 53-01-46.56N 000-29-57.08W 53-01-46.56N 000-29-18.58W RWY EGYE 06/24 367 6007 151 52-57-30.96N 000-34-18.70W 52-58-02.64N 000-32-55.95W RWY EGYE 11/29 367 4206 151 52-57-37.08N 000-34-20.14W 52-57-27.72N 000-33-13.22W RWY EGYE 18/36 367 2657 75 52-57-54.00N 000-33-22.20W 52-57-29.52N 000-33-20.40W RWY EGYM 01/19 75 6086 300 52-38-21.12N 000-33-20.63E 52-39-17.64N 000-33-34.84E RWY EGYM 06/24 75 9140 200 52-38-28.32N 000-32-00.73E 52-39-19.08N 000-34-02.65E RWY EICK 07/25 502 4298 148 51-50-29.76N 008-29-45.60W 51-50-49.20N 008-28-44.83W RWY EICK 17/35 502 6998 148 51-51-01.08N 008-29-47.18W 51-49-56.28N 008-29-08.84W RWY EICM 08/26 81 4003 98 53-17-55.68N 008-57-01.91W 53-18-05.40N 008-55-58.48W RWY EIDL 03/21 30 4908 98 55-02-16.44N 008-20-42.29W 55-03-01.80N 008-20-13.16W RWY EIDW 10/28 242 8652 148 53-25-20.64N 006-17-24.25W 53-25-13.08N 006-15-02.09W RWY EIDW 11/29 242 4393 200 53-26-11.76N 006-15-44.17W 53-26-00.24N 006-14-34.12W RWY EIDW 16/34 242 6798 200 53-26-13.20N 006-15-43.13W 53-25-11.64N 006-14-58.52W RWY EIKN 08/26 665 7546 148 53-54-29.88N 008-50-08.34W 53-54-44.28N 008-48-04.79W RWY EIKY 07/25 112 4035 98 52-10-44.04N 009-32-19.90W 52-11-04.92N 009-31-25.10W RWY EIKY 08/26 112 6562 148 52-10-40.80N 009-32-15.47W 52-11-01.68N 009-30-35.78W RWY EIME 05/23 319 4800 150 53-17-34.80N 006-27-12.74W 53-18-10.80N 006-26-21.05W RWY EIME 11/29 319 6001 150 53-18-24.84N 006-28-13.01W 53-18-07.20N 006-26-38.87W RWY EINN 04/22 46 463 198 52-41-42.36N 008-55-17.26W 52-42-34.56N 008-54-17.03W RWY EINN 06/24 46 10495 148 52-41-35.52N 008-56-36.67W 52-42-38.88N 008-54-21.96W RWY EINN 08/26 46 805 148 52-41-56.76N 008-55-55.20W 52-42-05.40N 008-54-38.48W RWY EINN 13/31 46 543 148 52-42-07.20N 008-55-32.99W 52-41-35.16N 008-54-18.00W RWY EINN 18/36 46 23 148 52-42-27.72N 008-54-42.59W 52-41-33.36N 008-54-25.85W RWY EISG 11/29 11 3933 98 54-16-51.96N 008-36-28.15W 54-16-45.48N 008-35-26.16W RWY EIWF 03/21 119 4701 98 52-10-52.32N 007-05-26.59W 52-11-35.52N 007-04-59.52W RWY EIWT 07/25 150 3038 23 53-21-04.32N 006-29-31.45W 53-21-12.24N 006-29-04.78W RWY LFAC 06/24 12 5036 148 50-57-31.68N 001-56-42.76E 50-57-55.44N 001-57-51.52E RWY LFAT 13/31 36 6070 131 50-31-26.40N 001-36-44.89E 50-30-45.00N 001-37-53.00E RWY LFOI 02/20 220 4101 75 50-08-17.88N 001-49-43.14E 50-08-55.32N 001-50-06.47E NAV ABB VOR/DME 50-08-06.36N 001-51-16.88E 223 108.45 - NAV ADN VOR/DME 57-18-38.16N 002-16-01.99W 600 114.30 - NAV AP NDB 52-06-58.68N 004-33-35.39W 0 371 - NAV AQ NDB 57-08-17.89N 002-24-16.99W 0 336 - NAV ATF NDB 57-04-39.00N 002-06-20.52W 0 348 - NAV BAL VOR/DME 53-17-59.64N 006-26-52.01W 300 115.80 - NAV BBA NDB 57-28-34.32N 007-22-09.30W 0 401 - NAV BCL DME 57-28-30.37N 007-22-13.15W 48 108.10 - NAV BCN VOR/DME 51-43-32.16N 003-15-47.02W 1450 117.45 - NAV BDN TACAN 51-08-56.39N 001-45-09.54W 430 108.20 - NAV BEL VOR/DME 54-39-39.95N 006-13-48.00W 194 117.20 - NAV BEN VOR/DME 57-28-40.45N 007-21-55.08W 130 113.95 - NAV BFD NDB 57-15-17.28N 005-49-58.33W 0 390 - NAV BHD VOR/DME 50-23-54.97N 003-29-37.00W 215 112.05 - NAV BHX NDB 52-27-16.19N 001-45-08.60W 325 406 - NAV BIA NDB 50-46-39.71N 001-50-32.96W 0 339 - NAV BIG VOR/DME 51-19-51.23N 000-02-05.32E 590 115.10 - NAV BKL TACAN 55-03-38.88N 007-00-47.99W 18 109.15 - NAV BKY VOR/DME 51-59-22.92N 000-03-43.00E 486 116.25 - NAV BLC DME 51-19-26.03N 000-50-46.96W 341 116.20 - NAV BLK NDB 51-19-23.88N 000-50-41.26W 0 328 - NAV BNE VOR 50-37-29.29N 001-54-25.60E 0 113.80 - NAV BNN VOR/DME 51-43-33.96N 000-32-59.00W 500 113.75 - NAV BOU NDB 52-12-39.97N 000-02-41.77W 0 392 - NAV BPK VOR/DME 51-44-58.92N 000-06-24.00W 382 117.50 - NAV BRI NDB 51-22-53.04N 002-43-03.14W 0 414 - NAV BRR NDB 57-01-32.16N 007-26-56.11W 0 316 - NAV BSO TACAN 51-36-52.19N 001-05-57.98W 226 110.00 - NAV BUR NDB 51-31-08.05N 000-40-38.00W 0 421 - NAV BV NDB 53-43-31.44N 000-34-53.34W 12 372 - NAV BZ NDB 51-44-57.12N 001-36-05.83W 288 386 - NAV BZN TACAN 51-44-53.52N 001-36-12.71W 331 111.90 - NAV CAE NDB 53-06-00.37N 004-20-22.27W 1 320 - NAV CAM NDB 52-12-38.88N 000-10-58.05E 0 333 - NAV CAR NDB 54-08-27.97N 004-29-30.01W 0 367 - NAV CBL NDB 55-26-08.16N 005-41-17.05W 44 380 - NAV CBN NDB 55-58-32.16N 003-58-28.99W 370 374 - NAV CFD VOR 52-04-27.12N 000-36-38.85W 357 116.50 - NAV CFN NDB 55-02-38.40N 008-20-21.41W 0 361 - NAV CGY TACAN 53-05-27.60N 000-10-08.31W 24 111.10 - NAV CHT NDB 51-37-23.16N 000-31-06.00W 0 277 - NAV CLN VOR/DME 51-50-54.24N 001-08-51.40E 100 114.55 - NAV CML NDB 52-27-13.68N 007-28-48.25W 0 387 - NAV COM NDB 50-57-58.33N 002-09-18.61W 0 350 - NAV CON VOR/DME 53-54-28.80N 008-49-12.36W 700 117.40 - NAV CPT VOR/DME 51-29-30.12N 001-13-10.99W 498 114.35 - NAV CRK VOR/DME 51-50-26.16N 008-29-39.37W 500 114.60 - NAV CRN NDB 53-17-57.84N 008-56-27.17W 0 342 - NAV CTM TACAN 52-44-07.44N 000-39-02.77W 452 112.30 - NAV CWL NDB 53-01-34.67N 000-29-20.34W 0 423 - NAV CWZ TACAN 53-01-42.96N 000-29-07.80W 218 117.40 - NAV DAP VOR/DME 53-25-24.96N 006-18-10.01W 280 111.20 - NAV DCS VOR/DME 54-43-18.84N 003-20-26.02W 700 115.20 - NAV DET VOR/DME 51-18-14.05N 000-35-50.00E 645 117.30 - NAV DND NDB 56-27-18.36N 003-06-53.71W 0 394 - NAV DTY VOR/DME 52-10-49.09N 001-06-50.00W 600 116.40 - NAV DUB VOR/DME 53-29-57.84N 006-18-25.60W 200 114.90 - NAV DVR VOR/DME 51-09-44.99N 001-21-33.01E 315 114.95 - NAV EAS NDB 50-57-18.01N 001-21-22.03W 0 392 - NAV EDN NDB 55-58-42.24N 003-17-02.83W 0 341 - NAV EKN NDB 54-23-39.12N 007-38-36.13W 0 358 - NAV EKN DME 54-23-54.97N 007-39-13.00W 176 116.75 - NAV ENS NDB 52-54-18.72N 008-55-39.97W 0 352 - NAV EPM NDB 51-19-09.84N 000-22-19.00W 0 316 - NAV FFA TACAN 51-40-54.13N 001-47-51.40W 299 113.40 - NAV FNL NDB 52-44-29.76N 000-01-40.59W 0 401 - NAV FNY NDB 53-28-29.28N 001-00-06.19W 0 338 - NAV FOS NDB 51-20-50.64N 000-33-55.54W 80 348 - NAV FOY NDB 52-33-58.68N 009-11-43.48W 0 395 - NAV FRK DME 51-20-50.64N 000-33-55.54W 80 109.85 - NAV GAM VOR/DME 53-16-53.04N 000-56-50.00W 121 112.80 - NAV GAR NDB 53-31-43.33N 006-26-50.86W 0 407 - NAV GE NDB 51-09-51.83N 000-04-08.88W 0 338 - NAV GLW NDB 55-52-11.28N 004-26-01.07W 26 331 - NAV GMN NDB 53-38-53.17N 006-13-36.01W 100 334 - NAV GOS DME 51-53-31.92N 002-10-04.55W 109 115.55 - NAV GOW VOR/DME 55-52-13.80N 004-26-44.59W 37 115.40 - NAV GST NDB 51-53-31.19N 002-10-04.44W 111 331 - NAV GWC VOR/DME 50-51-19.08N 000-45-24.00W 113 114.75 - NAV GY NDB 51-07-50.52N 000-18-57.44W 0 365 - NAV HAV NDB 51-49-54.85N 004-58-05.12W 0 328 - NAV HDW DME 51-49-55.20N 004-58-12.43W 201 116.75 - NAV HEN NDB 51-45-34.92N 000-47-25.00W 0 434 - NAV HON VOR/DME 52-21-24.12N 001-39-49.00W 435 113.65 - NAV ID DME 53-25-12.36N 006-16-13.87W 200 108.90 - NAV ING NDB 50-52-59.53N 001-44-30.52E 475 387 - NAV INS VOR/DME 57-32-33.36N 004-02-29.54W 58 109.20 - NAV IOF NDB 58-49-47.64N 003-08-42.22W 0 357 - NAV IOM VOR/DME 54-04-00.83N 004-45-48.49W 573 112.20 - NAV ISV DME 58-12-51.84N 006-19-33.78W 28 110.90 - NAV ISY DME 55-40-58.80N 006-14-57.88W 70 109.95 - NAV IVR NDB 57-32-29.40N 004-02-45.49W 0 328 - NAV IW NDB 50-40-50.89N 001-06-21.71W 0 426 - NAV KER NDB 52-10-55.92N 009-31-28.17W 0 334 - NAV KLY NDB 53-16-10.56N 006-06-23.18W 0 378 - NAV KMB NDB 51-40-09.00N 002-04-08.00W 0 349 - NAV KNK NDB 53-53-47.40N 008-56-13.20W 0 364 - NAV KS NDB 57-39-01.43N 003-35-13.34W 0 370 - NAV KSS TACAN 57-39-33.49N 003-32-06.40W 75 109.80 - NAV KW NDB 58-57-34.55N 002-54-41.69W 0 395 - NAV KWL VOR/DME 58-57-34.93N 002-53-38.22W 65 108.60 - NAV LA NDB 51-30-29.88N 002-00-21.13W 513 282 - NAV LAM VOR/DME 51-38-45.96N 000-09-06.00E 200 115.60 - NAV LAY NDB 55-40-58.44N 006-14-58.13W 58 395 - NAV LBA NDB 53-51-54.01N 001-39-10.40W 0 403 - NAV LCY NDB 51-30-15.48N 000-04-03.01E 0 322 - NAV LDY DME 50-57-33.13N 000-56-14.92E 28 108.15 - NAV LE NDB 52-36-23.04N 001-02-06.00W 0 384 - NAV LEE TACAN 54-17-49.56N 001-32-12.73W 92 112.60 - NAV LKH TACAN 52-24-23.04N 000-32-52.67E 91 110.20 - NAV LND VOR/DME 50-08-10.68N 005-38-13.16W 800 114.20 - NAV LNS NDB 57-30-59.39N 001-52-05.92W 0 339 - NAV LON VOR/DME 51-29-13.93N 000-28-00.00W 110 113.60 - NAV LOO TACAN 54-03-01.80N 001-14-56.54W 53 109.00 - NAV LSH NDB 51-09-16.92N 000-38-53.00E 72 340 - NAV LUK TACAN 56-22-22.08N 002-51-49.21W 72 110.50 - NAV LYD VOR/DME 50-59-58.92N 000-52-43.00E 30 114.05 - NAV LYE TACAN 51-30-36.36N 001-59-32.06W 463 109.80 - NAV LYX NDB 50-58-19.91N 000-57-19.03E 0 397 - NAV MAC VOR/DME 55-25-48.00N 005-39-01.01W 95 116.00 - NAV MAM TACAN 52-38-50.28N 000-33-11.75E 75 108.70 - NAV MAY VOR/DME 51-01-01.92N 000-06-58.00E 360 117.90 - NAV MCH NDB 53-21-11.87N 002-16-22.91W 0 428 - NAV MCT VOR/DME 53-21-24.84N 002-15-43.99W 282 113.55 - NAV MID VOR/DME 51-03-14.05N 000-37-30.00W 200 114.00 - NAV MLD TACAN 52-21-47.88N 000-29-17.77E 63 115.90 - NAV NEW VOR/DME 55-02-18.24N 001-41-54.13W 274 114.25 - NAV NGY NDB 55-10-39.01N 004-10-07.00W 0 399 - NAV NL NDB 52-40-35.04N 001-23-04.96E 0 372 - NAV NN NDB 52-17-56.76N 000-47-51.37W 0 379 - NAV NOT NDB 52-55-18.12N 001-04-45.59W 0 430 - NAV NT NDB 55-03-01.44N 001-38-33.65W 0 352 - NAV OCK VOR/DME 51-18-18.00N 000-26-50.00W 200 115.30 - NAV ODH TACAN 51-13-58.08N 000-56-54.57W 410 109.60 - NAV OE NDB 53-25-48.72N 006-25-43.68W 282 316 - NAV OF NDB 51-31-18.84N 002-35-24.83W 0 325 - NAV OK NDB 53-55-26.04N 008-41-59.24W 0 398 - NAV OP NDB 53-24-49.68N 006-08-18.10W 0 397 - NAV OTR VOR/DME 53-41-53.88N 000-06-13.00W 0 113.90 - NAV OX NDB 51-49-57.00N 001-19-23.66W 0 368 - NAV OX DME 51-49-56.64N 001-19-22.15W 276 117.70 - NAV OY NDB 54-41-33.36N 006-05-07.30W 0 332 - NAV PIK NDB 55-30-21.96N 004-34-38.10W 0 355 - NAV PMB NDB 51-42-49.32N 004-18-40.07W 0 341 - NAV POL VOR/DME 53-44-38.04N 002-06-11.99W 1400 112.10 - NAV PTH VOR 56-26-33.00N 003-22-07.00W 0 110.40 - NAV PW NDB 55-32-39.84N 004-40-53.58W 0 426 - NAV PY NDB 50-25-27.84N 004-06-44.39W 0 397 - NAV RCH NDB 51-21-13.69N 000-30-13.20E 0 369 - NAV RDL NDB 51-12-57.96N 000-08-25.37W 0 343 - NAV RSH NDB 53-30-42.85N 006-06-37.91W 0 326 - NAV RWY NDB 54-04-51.96N 004-37-22.40W 55 359 - NAV SAB VOR/DME 55-54-27.00N 002-12-23.00W 760 112.50 - NAV SAM VOR/DME 50-57-19.08N 001-20-42.00W 66 113.35 - NAV SAT TACAN 51-24-23.04N 003-26-05.89W 178 114.80 - NAV SAY NDB 58-12-55.80N 006-19-44.69W 24 431 - NAV SBH NDB 59-52-56.64N 001-17-41.39W 0 351 - NAV SBY NDB 53-18-36.00N 000-10-34.20E 0 330 - NAV SFD VOR/DME 50-45-38.16N 000-07-19.00E 300 117.00 - NAV SFH DME 53-23-34.81N 001-22-59.30W 273 111.35 - NAV SH NDB 52-14-36.24N 002-52-47.42W 0 426 - NAV SHA VOR/DME 52-43-15.60N 008-53-06.76W 130 113.30 - NAV SHD NDB 57-33-33.12N 001-49-01.99W 0 383 - NAV SLG NDB 54-16-43.33N 008-35-28.00W 15 384 - NAV SLP NDB 52-50-00.96N 002-46-25.00W 0 382 - NAV SM NDB 50-26-53.16N 004-59-40.38W 0 357 - NAV SMF NDB 53-23-33.36N 001-22-59.30W 0 333 - NAV SMG TACAN 50-26-04.21N 005-01-48.90W 323 112.60 - NAV SPA NDB 58-22-00.12N 001-54-24.98E 417 349 - NAV SSD NDB 51-53-40.56N 000-14-42.11E 0 429 - NAV STN VOR/DME 58-12-24.85N 006-10-59.02W 250 115.10 - NAV STU VOR/DME 51-59-40.92N 005-02-25.01W 600 113.10 - NAV SUM VOR/DME 59-52-44.04N 001-17-12.01W 19 117.35 - NAV SWB VOR/DME 52-47-52.80N 002-39-45.14W 269 116.80 - NAV SWN NDB 51-36-07.92N 004-03-56.99W 0 321 - NAV SWZ DME 51-36-12.96N 004-03-55.01W 299 109.20 - NAV TD NDB 54-33-37.08N 001-20-00.38W 0 348 - NAV TIR VOR/DME 56-29-35.51N 006-52-32.02W 36 117.70 - NAV TLA VOR/DME 55-29-57.12N 003-21-10.01W 2786 113.80 - NAV TNL NDB 52-48-52.20N 001-46-00.01W 0 327 - NAV TNT VOR/DME 53-03-14.05N 001-40-12.00W 968 115.70 - NAV TRN VOR/DME 55-18-47.88N 004-47-02.00W 600 117.50 - NAV UW NDB 55-54-18.72N 003-30-09.04W 0 368 - NAV VLN TACAN 51-00-18.00N 002-38-19.50W 113 111.00 - NAV VYL TACAN 53-15-26.64N 004-32-38.90W 101 108.40 - NAV WAD TACAN 53-09-55.07N 000-31-36.60W 231 117.10 - NAV WAL VOR/DME 53-23-30.84N 003-08-03.98W 55 114.10 - NAV WBA NDB 52-30-57.24N 002-15-42.34W 0 356 - NAV WCK NDB 58-26-48.12N 003-03-47.23W 0 344 - NAV WCO NDB 51-51-11.16N 000-57-45.00W 0 335 - NAV WFD NDB 53-20-15.72N 002-09-30.10W 0 380 - NAV WHI NDB 53-11-06.00N 002-37-23.02W 0 369 - NAV WIK VOR/DME 58-27-32.04N 003-06-01.01W 110 113.60 - NAV WIT TACAN 52-36-28.08N 000-29-55.20W 295 117.60 - NAV WL NDB 54-07-32.53N 003-15-46.91W 0 385 - NAV WL DME 54-07-37.92N 003-15-53.50W 74 109.40 - NAV WOD NDB 51-27-10.08N 000-52-44.00W 0 352 - NAV WOL DME 52-30-56.88N 002-15-42.55W 300 108.60 - NAV WPL NDB 52-37-48.00N 003-09-14.00W 282 323 - NAV WST VOR/DME 53-21-10.80N 006-29-41.53W 200 114.70 - NAV WTD NDB 52-11-20.40N 007-05-00.02W 0 368 - NAV WTN TACAN 53-44-25.08N 002-53-34.22W 54 113.20 - NAV WTN NDB 53-45-06.12N 002-51-08.06W 0 337 - NAV WTZ TACAN 52-07-18.84N 000-56-25.69E 324 109.30 - # Heathrow (EGLL): ILS 09L ILS/DME IAA 110.30 51-28-39.77N 000-25-44.21W 51-28-35.76N 000-29-21.92W 83 5 89.7 3 ILS 27R ILS/DME IRR 110.30 51-28-38.94N 000-29-37.48W 51-28-42.96N 000-25-59.76W 83 5 269.7 3 ILS 09R ILS/DME IBB 109.50 51-27-54.03N 000-25-47.13W 51-27-50.40N 000-29-12.35W 83 5 89.8 3 ILS 27L ILS/DME ILL 109.50 51-27-53.61N 000-29-27.92W 51-27-57.24N 000-26-02.70W 83 5 269.8 3 # Gatwick (EGKK): ILS 08R ILS IGG 110.90 51-09-06.40N 000-09-50.41W 51-08-39.20N 000-12-45.17W 189 5 77.6 3 ILS 26L ILS IWW 110.90 51-08-40.27N 000-12-59.40W 51-09-07.48N 000-10-04.64W 215 5 257.6 3 # Manchester (EGCC): ILS 05L ILS/DME IMM 108.50 53-21-50.76N 002-15-13.11W 53-20-39.78N 002-17-36.42W 219 5 50.9 3 ILS 23R ILS/DME INN 109.50 53-20-36.24N 002-17-46.44W 53-21-47.21N 002-15-23.13W 295 5 230.9 3 ILS 05R ILS/DME IMC 111.55 53-21-02.82N 002-16-17.30W 53-19-52.61N 002-18-40.92W 220 5 51.3 3 # Stansted (EGSS): ILS 04 ILS ISED 110.50 51-53-49.84N 000-15-10.83E 51-52-28.17N 000-13-08.70E 303 5 42.9 3 ILS 22 ILS ISX 110.50 51-52-23.24N 000-13-01.07E 51-53-44.91N 000-15-03.19E 393 5 222.8 3 acm-6.0_20200416/objects/zones/europe/germany.txt0000644000000000000000000012225513646045023020076 0ustar rootroot# Germany zone. # Created: 2020-04-16 # Latitude range: [47N, 55N[ # Longitude range: [006E, 015E[ # 2017-11-01 Source: http://ourairports.com GROUND_COLOR #305030 RWY EDAB 07/25 568 7218 164 51-11-26.52N 014-30-16.92E 51-11-47.04N 014-32-05.28E RWY EDAB 07L/25R 568 3281 131 51-11-30.84N 014-30-21.24E 51-11-40.20N 014-31-10.56E RWY EDAC 04/22 640 7333 148 50-58-27.84N 012-29-46.32E 50-59-21.48N 012-30-59.40E RWY EDAD 09/27 187 3281 82 51-49-54.84N 012-10-36.48E 51-49-54.12N 012-11-28.68E RWY EDAE 11/29 144 3839 75 52-11-58.20N 014-34-40.44E 52-11-42.72N 014-35-36.60E RWY EDAH 10/28 93 7562 115 53-52-53.76N 014-08-04.20E 53-52-33.96N 014-10-05.88E RWY EDAH 10R/28L 93 1969 98 53-52-46.56N 014-08-31.56E 53-52-41.16N 014-09-03.96E RWY EDAK 12/30 417 7874 157 51-18-45.36N 013-32-22.92E 51-18-12.96N 013-34-12.72E RWY EDAM 08/26 341 3740 98 51-21-43.92N 011-55-58.08E 51-21-49.68N 011-56-56.04E RWY EDAQ 11/29 348 3675 98 51-33-14.76N 012-02-43.08E 51-32-59.64N 012-03-36.00E RWY EDAU 09/27 322 2461 98 51-17-52.80N 013-20-31.20E 51-17-50.28N 013-21-09.36E RWY EDAU 12/30 322 3281 66 51-17-42.72N 013-21-06.12E 51-17-25.44N 013-21-50.04E RWY EDAV 10/28 121 8268 164 52-49-44.76N 013-40-30.36E 52-49-30.72N 013-42-42.84E RWY EDAX 07/25 220 7808 164 53-18-12.96N 012-44-09.24E 53-18-33.12N 012-46-13.44E RWY EDAY 05/23 262 3937 92 52-34-35.40N 013-54-32.40E 52-35-00.60N 013-55-20.64E RWY EDAY 05R/23L 262 3937 131 52-34-33.24N 013-54-34.92E 52-34-58.80N 013-55-24.24E RWY EDAZ 07/25 131 3937 75 52-12-07.20N 013-08-59.64E 52-12-16.56N 013-10-00.84E RWY EDAZ 12/30 131 2297 98 52-12-29.88N 013-09-14.76E 52-12-18.00N 013-09-46.08E RWY EDBH 09/27 23 3937 98 54-20-17.52N 012-42-03.24E 54-20-17.52N 012-43-09.48E RWY EDBH 09L/27R 23 2953 131 54-20-22.56N 012-42-10.08E 54-20-22.92N 012-42-59.76E RWY EDBJ 02/20 1247 3960 75 50-54-36.36N 011-42-41.40E 50-55-12.72N 011-43-03.00E RWY EDBJ 08/26 1247 2000 100 50-54-51.84N 011-42-32.40E 50-54-56.52N 011-43-02.64E RWY EDBK 14/32 131 3281 75 52-55-20.28N 012-25-14.16E 52-54-55.44N 012-25-48.00E RWY EDBK 14R/32L 131 3281 98 52-55-19.20N 012-25-11.64E 52-54-54.00N 012-25-45.84E RWY EDBM 09/27 259 3281 98 52-04-24.60N 011-37-09.12E 52-04-25.68N 011-38-01.68E RWY EDBN 09/27 228 7522 148 53-36-07.20N 013-17-19.32E 53-36-08.64N 013-19-23.88E RWY EDBR 18/36 518 8202 148 51-22-27.84N 014-56-59.28E 51-21-06.84N 014-57-00.72E RWY EDBT 07/25 932 3937 98 51-22-36.48N 011-25-44.40E 51-22-49.80N 011-26-42.72E RWY EDBW 08/26 262 4918 262 52-37-52.68N 013-45-52.20E 52-37-57.00N 013-47-11.76E RWY EDCA 09/27 16 3281 66 53-49-59.52N 013-39-41.76E 53-49-55.92N 013-40-36.12E RWY EDCA 09R/27L 16 2953 131 53-49-57.00N 013-39-46.44E 53-49-54.12N 013-40-35.76E RWY EDCD 07/25 272 8149 148 51-53-07.80N 014-30-54.72E 51-53-36.60N 014-32-55.68E RWY EDCD 07L/25R 272 6562 164 51-53-16.44N 014-31-10.92E 51-53-37.32N 014-32-49.92E RWY EDCM 03/21 495 3609 92 51-17-35.16N 014-07-23.52E 51-18-04.32N 014-07-55.56E RWY EDCM 03L/21R 495 3609 131 51-17-36.24N 014-07-20.28E 51-18-05.76N 014-07-52.32E RWY EDCO 11/29 909 4757 98 51-16-11.64N 010-37-30.36E 51-15-55.80N 010-38-40.56E RWY EDCP 13/31 7 7874 197 54-09-56.52N 013-45-36.72E 54-08-59.64N 013-47-06.72E RWY EDCY 04/22 374 6562 98 51-34-17.76N 014-07-50.16E 51-35-09.96N 014-08-51.36E RWY EDDB 07L/25R 157 8891 148 52-22-00.12N 013-28-51.24E 52-22-42.24N 013-31-48.72E RWY EDDB 07R/25L 157 9843 148 52-20-43.44N 013-28-06.24E 52-21-30.24N 013-31-23.52E RWY EDDC 04/22 755 8228 167 51-07-27.12N 013-45-19.44E 51-08-28.68N 013-46-44.04E RWY EDDE 10/28 1036 8530 164 50-58-53.40N 010-56-23.28E 50-58-41.16N 010-58-35.04E RWY EDDF 07C/25C 364 13123 197 50-01-57.36N 008-32-04.67E 50-02-42.36N 008-35-13.13E RWY EDDF 07L/25R 364 9186 148 50-02-13.56N 008-29-49.49E 50-02-44.88N 008-32-01.39E RWY EDDF 07R/25L 364 13123 148 50-01-39.00N 008-32-03.01E 50-02-24.36N 008-35-11.51E RWY EDDF 18/36 364 13123 148 50-02-03.84N 008-31-33.35E 49-59-54.24N 008-31-33.89E RWY EDDG 07/25 160 7119 148 52-07-53.40N 007-40-12.22E 52-08-16.44N 007-42-00.07E RWY EDDH 05/23 53 10663 150 53-37-05.88N 009-57-49.36E 53-38-13.56N 010-00-06.48E RWY EDDH 15/33 53 12028 150 53-39-15.84N 009-58-30.76E 53-37-30.36N 010-00-01.80E RWY EDDK 06/24 302 8067 148 50-51-36.36N 007-07-25.61E 50-52-10.92N 007-09-18.97E RWY EDDK 14L/32R 302 12516 197 50-52-49.80N 007-07-44.69E 50-51-18.72N 007-09-56.48E RWY EDDK 14R/32L 302 6112 148 50-52-14.88N 007-07-15.10E 50-51-30.60N 007-08-19.46E RWY EDDL 05L/23R 147 8858 148 51-17-01.32N 006-44-55.39E 51-17-54.24N 006-46-46.74E RWY EDDL 05R/23L 147 9842 148 51-16-46.56N 006-45-07.16E 51-17-45.24N 006-47-10.39E RWY EDDM 08L/26R 1487 13123 197 48-21-46.08N 011-46-03.36E 48-22-00.84N 011-49-16.32E RWY EDDM 08R/26L 1487 13123 197 48-20-26.52N 011-45-03.60E 48-20-41.28N 011-48-16.56E RWY EDDN 10/28 1046 8858 148 49-30-01.80N 011-03-33.12E 49-29-48.84N 011-05-45.60E RWY EDDP 08L/26R 465 11811 148 51-25-52.32N 012-12-56.88E 51-26-00.96N 012-16-02.64E RWY EDDP 08R/26L 465 11811 198 51-24-41.76N 012-12-19.80E 51-24-50.40N 012-15-19.44E RWY EDDR 09/27 1058 6562 148 49-12-51.12N 007-05-48.05E 49-12-54.00N 007-07-25.39E RWY EDDR 09L/27R 1058 1788 164 49-12-56.88N 007-06-43.99E 49-12-57.60N 007-07-10.92E RWY EDDS 07/25 1276 10974 148 48-41-08.52N 009-12-00.47E 48-41-38.40N 009-14-37.68E RWY EDDT 08L/26R 122 9918 151 52-33-27.36N 013-15-56.52E 52-33-43.20N 013-18-35.28E RWY EDDT 08R/26L 122 7966 151 52-33-24.12N 013-16-30.00E 52-33-36.36N 013-18-37.08E RWY EDDV 09C/27C 183 2559 74 52-27-53.28N 009-41-01.57E 52-27-52.20N 009-41-42.50E RWY EDDV 09L/27R 183 12467 148 52-28-06.24N 009-38-53.84E 52-28-00.48N 009-42-14.90E RWY EDDV 09R/27L 183 7677 148 52-27-18.00N 009-40-36.37E 52-27-14.40N 009-42-40.14E RWY EDDW 05/23 14 2297 75 53-02-33.36N 008-47-03.26E 53-02-47.40N 008-47-32.64E RWY EDDW 09/27 14 6693 148 53-02-47.76N 008-46-28.02E 53-02-50.28N 008-48-17.46E RWY EDFE 08/26 384 4593 82 49-57-37.44N 008-37-54.37E 49-57-40.68N 008-39-04.43E RWY EDFE 08R/26L 384 2198 98 49-57-31.32N 008-38-31.31E 49-57-32.76N 008-39-05.00E RWY EDFH 03/21 1649 12467 148 49-55-53.04N 007-14-48.77E 49-57-36.72N 007-16-31.04E RWY EDFM 09/27 308 3497 82 49-28-22.80N 008-30-21.71E 49-28-21.00N 008-31-14.52E RWY EDFM 09L/27R 308 2297 98 49-28-23.52N 008-30-37.94E 49-28-22.80N 008-31-12.68E RWY EDFQ 11/29 1158 4068 98 51-02-15.36N 008-40-21.90E 51-01-59.16N 008-41-20.29E RWY EDFV 06/24 295 2625 66 49-36-17.64N 008-21-48.56E 49-36-30.24N 008-22-23.41E RWY EDFV 06L/24R 295 3018 98 49-36-18.72N 008-21-42.34E 49-36-33.12N 008-22-22.44E RWY EDFV 06R/24L 295 2625 66 49-36-17.64N 008-21-48.56E 49-36-30.24N 008-22-23.41E RWY EDFZ 08/26 525 3281 72 49-58-03.72N 008-08-30.23E 49-58-12.36N 008-09-17.82E RWY EDFZ 08R/26L 525 3281 262 49-57-59.76N 008-08-29.15E 49-58-06.96N 008-09-18.11E RWY EDGE 10/28 1112 5643 180 50-59-39.12N 010-27-51.84E 50-59-24.72N 010-29-17.16E RWY EDGS 04/22 1966 1640 98 50-42-11.52N 008-05-02.62E 50-42-24.12N 008-05-18.38E RWY EDGS 13/31 1966 5315 98 50-42-46.08N 008-04-21.61E 50-42-13.68N 008-05-26.63E RWY EDGS 13L/31R 1966 1969 98 50-42-44.64N 008-04-30.29E 50-42-32.04N 008-04-55.60E RWY EDHI 05/23 23 8629 148 53-31-42.96N 009-49-17.36E 53-32-35.88N 009-51-09.58E RWY EDHK 08/26 102 4134 98 54-22-43.32N 010-08-08.16E 54-22-49.08N 010-09-17.28E RWY EDHK 08L/26R 102 1476 115 54-22-51.60N 010-08-26.88E 54-22-54.12N 010-08-51.00E RWY EDHL 07/25 53 6896 197 53-48-07.20N 010-42-06.84E 53-48-28.44N 010-43-55.92E RWY EDJA 06/24 2077 9780 98 47-58-59.88N 010-13-32.16E 47-59-39.48N 010-15-11.88E RWY EDKV 06/24 1896 3510 98 50-24-12.24N 006-31-18.01E 50-24-30.24N 006-32-04.20E RWY EDKZ 07/25 1549 3839 66 51-05-55.68N 007-35-42.61E 51-06-06.84N 007-36-38.70E RWY EDLA 05/23 794 3018 66 51-28-51.96N 007-53-42.07E 51-29-11.04N 007-54-18.68E RWY EDLE 07/25 424 5095 148 51-24-00.72N 006-55-45.98E 51-24-20.88N 006-56-59.53E RWY EDLI 11/29 433 4121 66 51-58-00.48N 008-32-10.61E 51-57-46.08N 008-33-12.20E RWY EDLN 13/31 125 3937 98 51-14-01.32N 006-29-52.04E 51-13-37.20N 006-30-40.36E RWY EDLP 06/24 699 7152 148 51-36-32.04N 008-36-11.12E 51-37-09.84N 008-37-46.52E RWY EDLS 11/29 157 3215 66 51-59-49.92N 006-50-00.92E 51-59-40.20N 006-50-49.88E RWY EDLV 09/27 106 8005 148 51-36-10.08N 006-07-28.34E 51-36-07.56N 006-09-35.03E RWY EDLW 06/24 425 6562 148 51-30-52.92N 007-36-06.84E 51-31-24.60N 007-37-37.16E RWY EDMA 07/25 1516 5230 98 48-25-24.24N 010-55-24.60E 48-25-37.20N 010-56-23.64E RWY EDMA 07L/25R 1516 3325 100 48-25-18.48N 010-55-49.08E 48-25-28.92N 010-56-35.88E RWY EDMB 04/22 1903 3215 75 48-06-25.56N 009-45-27.86E 48-06-49.32N 009-45-58.82E RWY EDME 09/27 1342 3806 75 48-23-44.52N 012-42-49.68E 48-23-46.68N 012-43-45.84E RWY EDMN 15/33 1857 3770 66 48-06-48.60N 010-31-15.60E 48-06-15.12N 010-31-39.72E RWY EDMO 04/22 1947 7500 147 48-04-26.40N 011-16-23.16E 48-05-21.12N 011-17-37.68E RWY EDMS 09/27 1047 4429 98 48-54-05.76N 012-30-27.00E 48-54-00.36N 012-31-32.88E RWY EDMV 12/30 991 3734 66 48-38-16.44N 013-11-20.76E 48-37-57.00N 013-12-07.92E RWY EDNL 06/24 2100 3346 66 47-51-23.40N 010-00-32.40E 47-51-41.76N 010-01-12.72E RWY EDNY 06/24 1367 7729 148 47-39-57.60N 009-29-52.40E 47-40-35.76N 009-31-30.32E RWY EDON 08/26 39 7874 164 52-36-41.40N 014-13-30.36E 52-36-52.20N 014-15-36.72E RWY EDOP 06/24 166 9843 180 53-25-16.68N 011-45-46.80E 53-25-57.72N 011-48-14.04E RWY EDOV 08/26 184 6552 171 52-37-40.08N 011-48-19.44E 52-37-47.28N 011-50-04.92E RWY EDOV 08L/26R 184 2297 131 52-37-43.32N 011-48-34.56E 52-37-46.20N 011-49-11.64E RWY EDPA 09L/27R 1916 3116 82 48-46-40.08N 010-15-29.52E 48-46-40.44N 010-16-15.96E RWY EDPA 09R/27L 1916 3117 98 48-46-37.92N 010-15-29.88E 48-46-39.00N 010-16-14.88E RWY EDQA 03/21 811 4223 50 49-54-57.96N 010-54-33.84E 49-55-31.08N 010-55-12.00E RWY EDQA 04/22 811 3773 50 49-55-00.12N 010-54-36.00E 49-55-30.00N 010-55-10.20E RWY EDQC 12/30 1490 2822 70 50-15-51.84N 010-59-26.16E 50-15-37.80N 011-00-03.60E RWY EDQD 06/24 1601 3550 98 49-58-57.00N 011-38-02.04E 49-59-14.64N 011-38-49.20E RWY EDQE 08/26 1673 3190 49 49-47-36.24N 011-07-32.52E 49-47-37.32N 011-08-21.12E RWY EDQE 08L/26R 1673 2317 85 49-47-39.48N 011-07-41.88E 49-47-40.56N 011-08-16.80E RWY EDQH 26/08 1070 2285 62 49-35-00.60N 010-52-58.08E 49-34-55.20N 010-52-24.60E RWY EDQK 09/27 1660 2340 160 50-08-04.92N 011-27-15.48E 50-08-07.08N 011-27-50.40E RWY EDQL 04/22 853 2300 100 50-08-44.16N 011-02-34.80E 50-09-01.80N 011-03-02.88E RWY EDQM 09/27 1959 4856 98 50-17-17.88N 011-50-37.32E 50-17-20.40N 011-51-51.84E RWY EDQT 11/29 719 3609 66 50-01-12.00N 010-31-20.64E 50-00-57.96N 010-32-11.40E RWY EDRB 05/23 1220 10026 148 49-56-13.56N 006-32-48.37E 49-57-10.44N 006-34-53.76E RWY EDRK 06/24 640 3855 66 50-19-20.64N 007-31-14.99E 50-19-40.44N 007-32-05.60E RWY EDRT 05/23 666 3937 98 49-51-34.56N 006-46-58.48E 49-52-01.56N 006-47-41.53E RWY EDRY 16/34 312 5501 98 49-18-29.16N 008-26-56.51E 49-17-50.64N 008-27-12.10E RWY EDRY 16R/34L 312 3281 98 49-18-27.72N 008-26-54.02E 49-17-56.40N 008-27-06.80E RWY EDRZ 03/21 1132 9677 148 49-11-52.80N 007-23-25.91E 49-13-15.60N 007-24-38.81E RWY EDSB 03/21 408 9787 148 48-46-04.08N 008-04-11.78E 48-47-26.52N 008-05-28.86E RWY EDSN 09/27 2638 4094 98 47-58-36.84N 008-53-48.52E 47-58-36.48N 008-54-48.67E RWY EDTB 04/22 404 2592 98 48-47-28.32N 008-11-09.71E 48-47-49.20N 008-11-31.96E RWY EDTD 18/36 2231 4232 98 47-58-47.64N 008-31-19.06E 47-58-05.88N 008-31-20.68E RWY EDTF 16/34 801 4068 98 48-01-40.44N 007-49-46.88E 48-01-02.64N 007-50-07.69E RWY EDTG 05/23 696 5413 148 47-53-55.32N 007-36-32.40E 47-54-27.36N 007-37-36.01E RWY EDTG 05R/23L 696 1969 98 47-54-01.80N 007-36-56.38E 47-54-14.04N 007-37-19.70E RWY EDTL 03/21 511 9842 148 48-21-26.64N 007-49-05.27E 48-22-51.96N 007-50-14.35E RWY EDTM 08/26 1818 5253 98 48-03-08.64N 009-21-44.32E 48-03-19.08N 009-23-00.10E RWY EDTY 10/28 1299 5053 98 49-07-09.84N 009-46-23.56E 49-07-02.28N 009-47-38.62E RWY EDTY 10L/28R 1299 2460 98 49-07-08.76N 009-46-54.23E 49-07-05.16N 009-47-31.06E RWY EDUF 08/26 312 3937 98 51-32-49.20N 013-13-13.80E 51-32-56.04N 013-14-15.36E RWY EDUS 09/27 384 3937 98 51-36-26.64N 013-43-45.48E 51-36-27.36N 013-44-48.12E RWY EDUS 09R/27L 384 2904 131 51-36-24.48N 013-44-04.92E 51-36-24.84N 013-44-51.00E RWY EDUW 17/35 26 7218 197 53-55-55.20N 013-12-57.96E 53-54-45.00N 013-13-17.04E RWY EDVE 08/26 295 7546 148 52-19-06.24N 010-32-31.56E 52-19-10.92N 010-33-59.76E RWY EDVE 08R/26L 295 2953 98 52-19-02.64N 010-32-54.60E 52-19-05.52N 010-33-42.12E RWY EDVK 04/22 820 4921 98 51-24-08.28N 009-22-08.87E 51-24-45.00N 009-22-59.92E RWY EDVK 04L/22R 820 2297 98 51-24-22.32N 009-22-15.49E 51-24-39.24N 009-22-39.76E RWY EDVM 07/25 292 4003 75 52-10-41.52N 009-56-13.74E 52-10-53.40N 009-57-15.05E RWY EDWE 07/25 3 4265 98 53-23-21.84N 007-13-02.21E 53-23-34.44N 007-14-09.38E RWY EDWF 08/26 3 3937 66 53-16-14.16N 007-26-00.64E 53-16-21.36N 007-27-03.92E RWY EDWI 02/20 16 4787 98 53-29-51.36N 008-02-56.08E 53-30-35.64N 008-03-23.15E RWY EDWI 16/34 16 2018 49 53-30-27.00N 008-03-04.50E 53-30-08.28N 008-03-15.08E RWY EDWR 05/23 3 2657 131 53-35-33.72N 006-42-13.64E 53-35-51.00N 006-42-46.66E RWY EDWR 12/30 3 2854 131 53-35-43.08N 006-42-07.88E 53-35-28.32N 006-42-48.17E RWY EDWR 13/31 3 3281 66 53-35-42.36N 006-42-35.86E 53-35-20.76N 006-43-16.54E RWY EDWY 09/27 7 3281 66 53-42-23.40N 007-13-21.79E 53-42-25.92N 007-14-15.97E RWY EDXF 04/22 131 2297 148 54-46-14.16N 009-22-19.96E 54-46-30.36N 009-22-45.55E RWY EDXF 11/29 131 4003 98 54-46-22.08N 009-22-04.55E 54-46-09.84N 009-23-09.35E RWY EDXF 11L/29R 131 3937 197 54-46-31.80N 009-22-15.13E 54-46-16.68N 009-23-17.05E RWY EDXJ 03/21 62 4757 98 54-30-16.56N 009-07-55.09E 54-30-55.08N 009-08-40.60E RWY EDXR 03/21 23 3150 98 54-13-02.64N 009-35-47.83E 54-13-28.20N 009-36-17.86E RWY EDXR 12/30 23 1969 98 54-13-10.20N 009-35-53.70E 54-13-00.84N 009-36-22.79E RWY EDXW 06/24 51 5564 148 54-54-33.84N 008-19-45.01E 54-55-01.56N 008-21-07.16E RWY EDXW 14/32 51 6955 148 54-55-09.48N 008-19-58.37E 54-54-14.04N 008-21-07.52E RWY EHDR 08/26 14 3117 102 53-07-04.80N 006-07-22.44E 53-07-13.08N 006-08-11.54E RWY EHGG 01/19 17 4922 148 53-07-02.64N 006-34-36.70E 53-07-50.52N 006-34-48.97E RWY EHGG 05/23 17 8202 148 53-06-54.00N 006-34-08.87E 53-07-30.00N 006-35-24.97E RWY EHTW 05/23 114 9801 148 52-16-05.52N 006-52-16.43E 52-17-00.60N 006-54-25.60E RWY EHTW 11/29 114 6558 82 52-16-17.76N 006-52-13.69E 52-15-54.36N 006-53-51.50E RWY EKMB 10/28 16 3937 98 54-42-00.36N 011-25-45.12E 54-41-55.68N 011-26-51.72E RWY EKPB 05/23 88 3524 98 54-52-00.84N 009-16-22.94E 54-52-25.32N 009-17-06.00E RWY EKSB 14/32 24 5895 98 54-58-08.40N 009-47-05.60E 54-57-24.12N 009-48-11.38E RWY ELLX 06/24 1234 13123 197 49-37-03.72N 006-11-14.86E 49-38-07.80N 006-14-08.02E RWY EPSC 13/31 154 8202 197 53-35-31.56N 014-53-16.44E 53-34-38.64N 014-54-59.40E RWY EPSD 09R/27L 3 2668 826 53-23-35.52N 014-37-38.28E 53-23-28.68N 014-38-20.76E RWY ETAD 05/23 1197 10007 148 49-58-00.48N 006-41-00.82E 49-59-10.68N 006-42-48.46E RWY ETAR 08/26 776 10498 148 49-25-57.36N 007-34-43.79E 49-26-11.04N 007-37-21.14E RWY ETAR 09/27 776 9278 148 49-26-09.96N 007-34-51.31E 49-26-15.72N 007-37-10.92E RWY ETHB 08/26 230 6010 148 52-16-35.76N 009-04-08.72E 52-16-48.72N 009-05-43.19E RWY ETHC 08/26 129 6007 148 52-35-23.64N 010-00-31.68E 52-35-33.00N 010-02-07.80E RWY ETHE 09/27 129 1673 98 52-17-26.88N 007-22-59.99E 52-17-28.68N 007-23-26.41E RWY ETHF 12/30 1345 3413 98 51-07-00.48N 009-16-45.91E 51-06-43.92N 009-17-33.00E RWY ETHL 03/21 1766 1968 164 48-13-16.32N 009-54-13.97E 48-13-32.88N 009-54-30.10E RWY ETHL 09/27 1766 5400 98 48-13-14.52N 009-53-56.26E 48-13-11.64N 009-55-15.89E RWY ETHM 08/26 597 5342 117 50-21-51.12N 007-18-15.59E 50-22-04.08N 007-19-35.00E RWY ETHN 07/25 1339 3320 98 49-23-26.52N 009-57-05.40E 49-23-34.80N 009-57-53.39E RWY ETHR 09/27 1268 1755 98 49-13-01.92N 011-05-46.68E 49-13-03.72N 011-06-13.68E RWY ETHS 06/24 245 1312 148 52-54-44.28N 010-11-29.04E 52-54-50.40N 010-11-49.92E RWY ETHS 09/27 245 8005 95 52-55-10.20N 010-09-56.52E 52-55-09.12N 010-12-07.20E RWY ETHS 09L/27R 245 3281 164 52-55-11.28N 010-10-42.96E 52-55-12.36N 010-11-37.68E RWY ETIC 14/32 1363 3300 73 49-42-08.28N 011-56-09.60E 49-41-42.36N 011-56-39.48E RWY ETIH 09/27 1455 2187 72 49-13-05.16N 011-49-54.12E 49-13-05.16N 011-50-26.16E RWY ETIN 07/25 689 2625 100 49-44-29.40N 010-11-43.80E 49-44-40.56N 010-12-20.16E RWY ETMN 08/26 74 8002 148 53-45-55.44N 008-38-25.40E 53-46-11.64N 008-40-35.80E RWY ETND 08/26 128 4209 148 52-35-06.00N 008-19-54.73E 52-35-09.60N 008-21-00.58E RWY ETNG 09/27 296 10009 147 50-57-39.60N 006-01-12.14E 50-57-38.52N 006-03-48.46E RWY ETNH 08/26 39 8005 98 54-18-36.72N 009-31-11.06E 54-18-51.12N 009-33-23.72E RWY ETNJ 10/28 24 8136 98 53-32-08.88N 007-52-13.19E 53-31-52.68N 007-54-25.20E RWY ETNL 10/28 138 8202 148 53-55-10.92N 012-15-37.08E 53-54-59.40N 012-17-53.52E RWY ETNN 07/25 386 8003 148 50-49-36.48N 006-38-31.99E 50-50-07.80N 006-40-26.40E RWY ETNS 05/23 70 8003 98 54-27-07.20N 009-30-09.00E 54-28-00.12N 009-31-49.19E RWY ETNS 07/25 70 6554 148 54-27-19.08N 009-30-09.00E 54-27-37.80N 009-31-55.20E RWY ETNT 08/26 26 8005 98 53-32-44.52N 007-38-57.59E 53-33-00.72N 007-41-07.19E RWY ETNW 03/21 187 5573 156 52-26-42.00N 009-25-37.20E 52-27-31.32N 009-26-17.99E RWY ETNW 08/26 187 6157 153 52-27-22.32N 009-24-48.60E 52-27-30.60N 009-26-26.99E RWY ETNW 08R/26L 187 3569 132 52-27-17.28N 009-24-58.79E 52-27-22.68N 009-25-55.81E RWY ETOI 10/28 1353 3500 80 49-38-03.84N 011-45-37.08E 49-37-57.00N 011-46-27.84E RWY ETOR 05/23 309 3004 75 49-33-39.24N 008-27-30.92E 49-33-58.32N 008-28-05.52E RWY ETOU 07/25 461 7065 120 50-02-49.56N 008-18-39.71E 50-03-09.36N 008-20-23.42E RWY ETSA 07/25 2044 6777 98 48-04-03.72N 010-53-34.08E 48-04-23.88N 010-55-09.12E RWY ETSB 03/21 1568 8225 148 50-09-50.40N 007-03-16.96E 50-11-00.96N 007-04-18.95E RWY ETSF 09/27 1703 9003 151 48-12-22.32N 011-14-55.68E 48-12-18.00N 011-17-07.80E RWY ETSH 09/27 265 7936 98 51-46-06.60N 013-09-00.72E 51-46-01.92N 013-11-06.72E RWY ETSI 07L/25R 1202 8002 98 48-43-00.12N 011-30-55.80E 48-43-29.64N 011-32-46.32E RWY ETSI 07R/25L 1202 9646 197 48-42-16.20N 011-31-07.32E 48-42-51.48N 011-33-20.88E RWY ETSL 03/21 1822 8012 98 48-10-33.24N 010-51-11.52E 48-11-42.36N 010-52-08.76E RWY ETSN 09/27 1249 8005 98 48-42-40.32N 011-11-42.00E 48-42-38.88N 011-13-41.52E RWY LFGA 01/19 628 5282 98 48-06-09.36N 007-21-24.80E 48-07-00.12N 007-21-39.67E RWY LFGB 02/20 788 3281 66 47-44-13.92N 007-25-46.88E 47-44-43.80N 007-26-05.03E RWY LFJL 04/22 870 8202 148 48-58-24.24N 006-14-25.94E 48-59-26.88N 006-15-43.56E RWY LFQC 09/27 790 3410 66 48-35-36.24N 006-32-11.08E 48-35-35.16N 006-33-01.80E RWY LFQM 05/23 1271 4593 66 47-12-10.08N 006-04-34.54E 47-12-37.08N 006-05-27.96E RWY LFQP 06/24 1017 7205 148 48-45-39.24N 007-11-16.76E 48-46-17.40N 007-12-47.23E RWY LFQW 08/26 1249 4731 66 47-38-15.72N 006-11-41.10E 47-38-22.20N 006-12-49.57E RWY LFSB 08/26 885 5969 197 47-35-16.80N 007-31-00.91E 47-35-30.12N 007-32-27.85E RWY LFSB 15/33 885 12795 197 47-37-03.72N 007-30-35.53E 47-35-09.24N 007-31-55.06E RWY LFSG 08/26 1084 8858 147 48-19-26.76N 006-03-06.55E 48-19-34.32N 006-05-17.16E RWY LFSH 03/21 491 3264 59 48-47-25.44N 007-48-51.55E 48-47-53.88N 007-49-15.02E RWY LFSH 03L/21R 491 3159 262 48-47-27.60N 007-48-47.38E 48-47-54.96N 007-49-10.24E RWY LFSM 08/26 1041 5578 66 47-29-08.16N 006-46-46.06E 47-29-18.24N 006-48-05.80E RWY LFSN 03/21 751 4593 131 48-41-11.76N 006-13-33.13E 48-41-51.36N 006-14-06.14E RWY LFST 05/23 505 7874 148 48-31-52.32N 007-36-57.71E 48-32-43.44N 007-38-25.58E RWY LFSX 04/22 913 7596 118 47-46-37.92N 006-21-25.78E 47-47-37.32N 006-22-34.39E RWY LFSX 11/29 913 7982 148 47-47-29.76N 006-20-04.34E 47-46-58.80N 006-21-51.88E RWY LKCS 09/27 1417 8202 262 48-56-47.04N 014-24-37.44E 48-56-47.04N 014-26-40.20E RWY LKHV 06/24 1214 6575 100 49-50-39.84N 013-52-50.88E 49-51-06.48N 013-54-22.32E RWY LKKB 06/24 939 6562 148 50-07-01.92N 014-31-52.68E 50-07-31.80N 014-33-21.60E RWY LKKV 11/29 1989 7054 98 50-12-24.48N 012-54-03.96E 50-11-57.12N 012-55-43.68E RWY LKLN 06/24 1188 4757 197 49-40-18.48N 013-15-57.60E 49-40-42.96N 013-16-59.52E RWY LKPC 09/27 1207 8218 95 50-18-19.44N 013-55-00.48E 50-18-25.20N 013-57-06.12E RWY LKPM 06L/24R 1529 4700 125 49-42-56.16N 014-05-21.12E 49-43-22.44N 014-06-20.52E RWY LKPM 06R/24L 1529 8202 98 49-42-49.32N 014-05-10.32E 49-43-35.04N 014-06-53.64E RWY LKPR 04/22 1247 6955 197 50-05-15.72N 014-16-00.12E 50-06-10.44N 014-17-03.84E RWY LKPR 06/24 1247 12189 148 50-06-06.48N 014-13-34.68E 50-06-57.60N 014-16-24.24E RWY LKPR 12/30 1247 10663 148 50-06-28.80N 014-14-43.44E 50-05-25.80N 014-16-54.12E RWY LKVO 10/28 919 8203 148 50-13-10.92N 014-22-44.40E 50-12-48.60N 014-24-45.36E RWY LOGI 11/29 2283 2575 59 47-29-41.28N 014-29-29.04E 47-29-30.84N 014-30-02.52E RWY LOGO 04/22 2142 2395 98 47-28-34.32N 014-00-16.92E 47-28-53.40N 014-00-37.08E RWY LOIH 05/23 1352 2067 59 47-22-57.36N 009-41-49.60E 47-23-11.76N 009-42-10.69E RWY LOIJ 13/31 2198 2461 59 47-31-21.36N 012-26-45.60E 47-31-05.16N 012-27-11.16E RWY LOLG 04/22 827 1575 82 48-06-05.76N 014-56-56.76E 48-06-17.28N 014-57-11.52E RWY LOLK 12/30 1378 2437 59 48-12-49.68N 013-20-30.48E 48-12-41.40N 013-20-55.68E RWY LOLS 14/32 1070 2625 75 48-24-19.80N 013-26-42.36E 48-24-01.08N 013-27-07.92E RWY LOLU 08/26 1670 1804 59 47-57-03.24N 013-51-50.40E 47-57-07.56N 013-52-16.68E RWY LOLW 09/27 1043 4560 98 48-10-59.16N 014-01-53.40E 48-11-00.24N 014-03-00.72E RWY LOLW 09L/27R 1043 3051 164 48-10-54.84N 014-02-02.40E 48-10-55.20N 014-02-47.04E RWY LOLW 09R/27L 1043 2952 148 48-10-49.80N 014-02-04.92E 48-10-50.16N 014-02-46.68E RWY LOWI 08/26 1907 6562 148 47-15-31.68N 011-19-51.24E 47-15-41.76N 011-21-25.20E RWY LOWL 08/26 980 9843 197 48-13-57.00N 014-10-02.64E 48-14-02.04N 014-12-27.72E RWY LOWL 08L/26R 980 2165 148 48-14-07.08N 014-11-01.68E 48-14-08.16N 014-11-33.36E RWY LOWS 15/33 1411 9022 148 47-48-16.92N 012-59-49.92E 47-46-54.84N 013-00-41.40E RWY LOWZ 08/26 2470 2165 59 47-17-26.88N 012-47-09.24E 47-17-32.28N 012-47-39.48E RWY LOXZ 08L/26R 2264 4625 131 47-12-13.68N 014-44-25.08E 47-12-19.44N 014-45-16.92E RWY LOXZ 08R/26L 2264 9022 197 47-12-02.52N 014-43-35.40E 47-12-17.28N 014-45-43.20E RWY LSGC 06/24 3368 3707 89 47-04-51.60N 006-47-13.27E 47-05-12.84N 006-47-56.72E RWY LSMD 11/29 1470 7726 130 47-24-05.76N 008-38-01.39E 47-23-43.08N 008-39-45.79E RWY LSMD 11R/29L 1470 2130 98 47-24-01.80N 008-38-17.38E 47-23-55.32N 008-38-46.79E RWY LSME 04/22 1400 8208 130 47-05-00.60N 008-17-42.25E 47-06-04.68N 008-18-54.61E RWY LSMF 01/19 1485 4920 130 47-04-15.24N 009-03-43.81E 47-05-04.20N 009-04-00.41E RWY LSZG 06/24 1411 3281 75 47-10-47.28N 007-24-40.25E 47-11-00.60N 007-25-23.52E RWY LSZG 06L/24R 1411 1640 98 47-10-50.16N 007-24-40.61E 47-10-56.64N 007-25-02.32E RWY LSZG 06R/24L 1411 2297 66 47-10-46.92N 007-24-40.10E 47-10-54.84N 007-25-11.35E RWY LSZH 10/28 1416 8202 197 47-27-32.04N 008-32-14.89E 47-27-23.76N 008-34-13.62E RWY LSZH 14/32 1416 10827 197 47-28-59.16N 008-32-05.03E 47-27-40.68N 008-33-52.06E RWY LSZH 16/34 1416 12139 197 47-28-32.16N 008-32-09.42E 47-26-43.44N 008-33-24.23E RWY LSZR 10L/28R 1306 1969 75 47-29-11.76N 009-33-22.61E 47-29-09.24N 009-33-51.01E RWY LSZR 10R/28L 1306 4922 98 47-29-09.96N 009-33-01.01E 47-29-02.76N 009-34-11.86E NAV ABU NDB 50-59-37.68N 012-31-15.60E 581 330 - NAV AGB NDB 48-25-27.48N 010-55-59.16E 1542 318 - NAV AGD DME 50-58-57.72N 012-30-44.28E 624 115.30 - NAV ALB VOR/DME 49-12-51.84N 011-13-17.04E 1434 111.20 - NAV ALF DME 53-38-07.08N 009-59-38.90E 66 115.80 - NAV ALS VOR 54-54-19.44N 009-59-36.17E 0 114.70 - NAV ANS NDB 49-18-34.92N 010-37-58.08E 1526 452 - NAV AUG DME 48-25-27.48N 010-55-58.80E 1542 115.90 - NAV BA NDB 51-11-55.68N 014-32-52.08E 0 359 - NAV BAM VORTAC 51-19-40.08N 007-10-37.13E 879 113.60 - NAV BAY VOR 49-59-06.72N 011-38-12.12E 1625 110.60 - NAV BAY DME 49-59-08.52N 011-38-17.16E 1620 110.60 - NAV BAZ NDB 49-57-24.85N 011-33-54.72E 0 420 - NAV BET NDB 52-17-16.08N 007-23-08.41E 219 402 - NAV BHD DME 54-20-25.44N 012-42-35.28E 45 115.40 - NAV BKD VOR/DME 53-02-04.20N 011-32-46.32E 92 117.70 - NAV BLM VOR/DME 47-37-58.08N 007-29-58.20E 886 117.45 - NAV BMN VOR/DME 53-02-38.40N 008-46-55.70E 40 117.45 - NAV BN NDB 47-39-42.12N 007-28-44.69E 0 353 - NAV BOT NDB 51-35-08.88N 007-01-22.84E 0 407 - NAV BRU NDB 52-19-19.92N 010-36-22.32E 0 427 - NAV BTH NDB 54-20-18.25N 012-41-09.96E 45 373 - NAV BUE TACAN 50-10-43.32N 007-04-10.20E 1618 117.10 - NAV BYC NDB 52-17-28.32N 009-05-27.60E 292 368 - NAV CDD DME 51-53-13.20N 014-31-55.20E 292 112.05 - NAV CEL NDB 52-35-22.92N 010-01-46.20E 173 311 - NAV CHA VOR 49-55-15.96N 009-02-23.32E 532 115.50 - NAV CLR TACAN 47-55-45.47N 007-23-59.89E 693 110.00 - NAV COL VORTAC 50-47-00.60N 007-35-39.08E 990 108.80 - NAV DBR NDB 52-28-05.88N 013-17-43.08E 0 347 - NAV DHE VOR/DME 54-11-08.52N 007-54-38.52E 44 116.30 - NAV DIK VOR/DME 49-51-41.04N 006-07-46.99E 1109 114.40 - NAV DIK NDB 49-51-41.04N 006-07-46.99E 0 307 - NAV DIP NDB 52-28-22.44N 013-28-05.88E 0 327 - NAV DKB VORTAC 49-08-34.08N 010-14-17.88E 1790 117.80 - NAV DLE VOR/DME 52-15-01.08N 009-53-00.60E 398 115.20 - NAV DLS NDB 52-36-50.04N 013-21-48.96E 0 414 - NAV DMN DME 48-22-00.85N 011-47-38.40E 1463 116.00 - NAV DMS DME 48-20-26.51N 011-46-41.52E 1495 108.60 - NAV DND DME 51-07-46.20N 013-45-27.36E 778 115.40 - NAV DOM VOR/DME 51-42-34.20N 007-35-13.67E 298 112.70 - NAV DON DME 47-57-38.52N 008-31-21.18E 2212 110.55 - NAV DOR VOR/DME 51-31-31.08N 007-37-51.82E 373 108.65 - NAV DP NDB 52-35-30.13N 008-27-12.31E 191 325 - NAV DRN VOR/DME 51-00-55.80N 013-35-56.04E 1086 114.35 - NAV DRW NDB 51-53-48.13N 014-33-45.00E 271 355 - NAV DUS VOR/DME 51-16-59.52N 006-45-13.43E 151 115.15 - NAV DVI NDB 47-57-38.52N 008-31-21.76E 0 490 - NAV DWI NDB 51-31-33.96N 007-38-03.80E 400 357 - NAV EEL VOR/DME 53-09-50.03N 006-40-00.05E 32 112.40 - NAV EFD DME 50-58-57.36N 010-57-27.72E 1076 112.05 - NAV EGG NDB 48-23-49.20N 012-44-59.28E 1329 393 - NAV EH NDB 49-57-36.35N 008-38-33.47E 0 386 - NAV ELU NDB 49-40-46.92N 006-21-19.01E 0 369 - NAV EMD NDB 53-23-38.05N 007-14-30.08E 0 345 - NAV END DME 48-23-39.85N 012-43-31.44E 1381 115.40 - NAV ENW DME 53-23-20.76N 007-13-44.90E 50 115.25 - NAV EPL VOR 48-19-04.08N 006-03-33.91E 1154 113.00 - NAV ERD TACAN 48-19-29.27N 011-57-10.08E 1545 113.60 - NAV ERF VOR/DME 50-57-03.24N 011-14-12.12E 1325 113.85 - NAV ERL VOR/DME 49-39-19.44N 011-09-02.88E 1841 114.90 - NAV ERT NDB 50-58-57.36N 010-55-22.80E 1036 425 - NAV EUR VOR/DME 47-44-06.00N 011-14-57.84E 2279 115.20 - NAV FFM VORTAC 50-03-13.32N 008-38-13.52E 491 114.20 - NAV FHA NDB 47-40-52.31N 009-32-16.01E 1366 473 - NAV FHD DME 47-39-59.04N 009-30-31.89E 1400 112.60 - NAV FLD VOR/DME 53-45-45.72N 013-33-47.16E 43 117.15 - NAV FR NDB 50-03-56.52N 008-41-00.56E 0 297 - NAV FRD DME 50-01-49.79N 008-34-01.38E 441 115.90 - NAV FRE VOR/DME 48-25-54.48N 014-07-47.28E 2014 113.50 - NAV FSB NDB 52-54-56.87N 010-11-17.16E 329 284 - NAV FTZ NDB 51-05-03.48N 009-24-54.87E 1096 468 - NAV FU NDB 53-34-31.80N 009-52-32.91E 0 351 - NAV FUL VOR/DME 50-35-33.00N 009-34-19.81E 1138 112.10 - NAV FW NDB 50-00-18.00N 008-25-46.38E 0 382 - NAV FWE VOR/DME 52-24-40.68N 014-07-50.16E 238 113.30 - NAV GBL TACAN 49-38-36.60N 009-57-00.61E 1022 111.00 - NAV GBL NDB 49-38-53.17N 009-58-50.48E 1020 429 - NAV GED VORTAC 50-24-42.84N 009-14-56.98E 1601 110.80 - NAV GIN NDB 50-38-08.16N 008-49-09.55E 0 314 - NAV GIX TACAN 50-57-47.88N 006-02-42.72E 327 108.10 - NAV GL NDB 52-34-20.28N 013-25-34.32E 0 321 - NAV GMH VOR/DME 51-10-13.81N 007-53-31.34E 1821 115.40 - NAV GOT VOR/DME 51-20-35.17N 011-35-51.00E 721 115.25 - NAV GRE VOR/DME 47-10-59.52N 007-25-05.45E 1435 115.45 - NAV GRE NDB 47-11-00.24N 007-24-52.56E 1411 326 - NAV GRF TACAN 49-41-28.68N 011-56-17.88E 1385 111.80 - NAV GRW NDB 49-41-40.56N 011-56-30.12E 1542 405 - NAV GT NDB 53-42-51.12N 009-55-27.48E 0 323 - NAV GTQ VOR/DME 48-59-11.04N 006-42-58.39E 1024 111.25 - NAV HA NDB 52-27-50.76N 009-48-18.29E 0 320 - NAV HAB NDB 50-05-35.17N 009-46-53.54E 0 403 - NAV HAD DME 52-28-07.68N 009-41-41.32E 184 113.95 - NAV HAE NDB 52-27-27.36N 009-34-02.35E 0 332 - NAV HAM VORTAC 53-41-08.16N 010-12-18.00E 187 113.10 - NAV HAN NDB 49-57-53.64N 007-16-51.17E 1649 376 - NAV HBD DME 52-27-19.08N 009-39-33.73E 171 116.90 - NAV HC NDB 53-52-26.76N 014-10-55.56E 93 330 - NAV HDL NDB 49-23-09.61N 008-35-48.34E 345 417 - NAV HDM VOR 49-33-56.16N 008-27-49.72E 327 109.00 - NAV HDM NDB 49-32-04.20N 008-23-25.80E 320 334 - NAV HDO VOR/DME 50-55-41.52N 014-22-07.68E 1439 115.00 - NAV HFX NDB 49-13-05.88N 011-51-33.84E 1579 286 - NAV HLZ VOR/DME 52-21-48.24N 010-47-42.72E 413 117.30 - NAV HMM VOR/DME 51-51-24.84N 007-42-29.84E 237 115.65 - NAV HN NDB 54-19-34.69N 009-40-13.19E 105 344 - NAV HND DME 49-56-44.15N 007-16-03.61E 1716 116.95 - NAV HNT TACAN 54-18-38.88N 009-32-19.21E 78 115.30 - NAV HNU NDB 50-09-44.99N 009-09-15.01E 397 432 - NAV HOC VOR/DME 47-27-59.75N 007-39-55.58E 2425 113.20 - NAV HOD DME 50-17-23.28N 011-51-18.72E 1946 110.70 - NAV HOF NDB 50-17-04.56N 011-45-41.04E 0 484 - NAV HOS NDB 53-40-37.19N 010-04-59.52E 0 339 - NAV HOZ TACAN 51-46-00.12N 013-11-56.40E 261 117.25 - NAV HOZ NDB 51-46-11.27N 013-05-51.00E 316 406 - NAV HR NDB 47-33-42.12N 006-43-56.10E 0 289 - NAV HW NDB 52-28-06.59N 009-32-47.18E 0 358 - NAV IGL TACAN 48-43-04.08N 011-34-11.28E 1233 111.40 - NAV IGL NDB 48-44-16.08N 011-38-40.92E 0 345 - NAV ILM NDB 49-28-18.84N 010-23-16.44E 1112 488 - NAV INN NDB 47-13-48.00N 011-24-06.84E 2969 420 - NAV KBA NDB 48-47-52.80N 008-05-51.18E 408 431 - NAV KBD DME 48-46-48.72N 008-05-18.56E 495 115.80 - NAV KBO VOR/DME 50-51-42.11N 007-08-43.87E 311 112.15 - NAV KD NDB 50-09-09.36N 014-38-11.76E 0 300 - NAV KHD DME 54-22-43.68N 010-08-43.44E 119 109.50 - NAV KIL NDB 54-22-39.37N 010-07-12.00E 0 353 - NAV KIR VORTAC 49-51-00.72N 007-22-10.49E 1453 117.50 - NAV KLF VOR/DME 52-01-09.85N 013-33-48.24E 233 115.15 - NAV KLO VOR/DME 47-27-25.56N 008-32-44.09E 1410 114.85 - NAV KNG NDB 49-45-43.92N 009-05-30.01E 0 355 - NAV KPT VOR/DME 47-44-44.88N 010-20-58.92E 2529 109.60 - NAV KRH VOR/DME 48-59-34.44N 008-35-03.26E 908 115.95 - NAV KSL NDB 51-27-53.29N 009-27-26.64E 886 349 - NAV KTG VOR 49-44-45.24N 010-12-48.96E 697 111.40 - NAV KTI NDB 47-12-55.80N 011-01-40.08E 6726 413 - NAV KVY VOR/DME 50-12-04.31N 012-55-33.24E 2167 111.55 - NAV LAB TACAN 48-03-55.08N 010-52-50.88E 2102 112.15 - NAV LAG TACAN 53-55-11.28N 012-17-10.68E 190 108.25 - NAV LAU NDB 51-12-15.48N 009-41-27.57E 0 341 - NAV LBE VOR/DME 53-39-15.13N 009-35-42.22E 50 115.10 - NAV LBU VOR/DME 48-54-46.79N 009-20-24.83E 1064 109.20 - NAV LCH TACAN 48-11-25.79N 010-51-32.40E 1838 108.80 - NAV LED DME 51-24-40.68N 012-13-25.68E 502 112.15 - NAV LEG VOR/DME 51-26-09.60N 012-28-23.52E 486 115.85 - NAV LHR NDB 48-20-55.33N 007-48-40.18E 0 337 - NAV LI NDB 51-20-49.20N 006-53-28.61E 0 417 - NAV LJ NDB 50-55-37.56N 007-03-44.24E 0 365 - NAV LMA NDB 51-22-14.88N 006-23-42.00E 0 311 - NAV LND DME 51-26-03.48N 012-13-32.52E 415 113.50 - NAV LNZ VOR/DME 48-13-46.91N 014-06-11.52E 1145 116.60 - NAV LNZ NDB 48-14-13.56N 014-19-18.48E 0 327 - NAV LPS NDB 47-05-01.31N 006-47-38.00E 0 403 - NAV LQ NDB 48-05-41.28N 011-01-07.68E 2062 448 - NAV LRD DME 48-21-50.77N 007-49-39.07E 556 108.05 - NAV LUB VOR 53-56-26.52N 010-40-04.08E 264 110.60 - NAV LUD DME 53-48-23.04N 010-43-06.96E 70 115.65 - NAV LUL VOR 47-41-17.88N 006-17-44.09E 0 117.10 - NAV LUP NDB 48-13-04.79N 009-54-39.13E 1846 407 - NAV LUX VOR/DME 49-38-21.84N 006-14-49.99E 1234 112.25 - NAV LV NDB 50-48-15.12N 007-14-24.79E 0 327 - NAV LW NDB 50-53-53.88N 007-15-10.26E 0 301 - NAV LWB VOR/DME 52-54-37.08N 013-08-04.56E 234 114.55 - NAV LXI TACAN 47-46-59.52N 006-21-25.60E 913 108.20 - NAV LXI NDB 47-47-47.76N 006-22-30.68E 913 364 - NAV LYE NDB 53-48-02.88N 010-41-45.24E 53 394 - NAV MA NDB 51-23-42.36N 012-20-35.52E 0 357 - NAV MAG VOR/DME 51-59-42.00N 011-47-39.48E 209 110.45 - NAV MAH VOR/DME 48-15-48.24N 011-18-42.84E 1759 115.20 - NAV MBG VOR/DME 48-34-24.23N 012-15-39.60E 1658 117.15 - NAV MDF VOR/DME 48-14-04.92N 012-20-14.64E 1526 117.00 - NAV MEG NDB 48-03-15.85N 009-22-03.18E 0 401 - NAV MET TACAN 49-04-00.83N 006-07-45.80E 663 108.00 - NAV MGB NDB 51-13-38.28N 006-30-19.48E 125 377 - NAV MGD DME 52-04-37.56N 011-37-51.24E 302 115.45 - NAV MHD DME 51-14-05.65N 006-29-31.09E 159 112.50 - NAV MHV VOR 51-14-14.28N 006-29-24.86E 156 109.80 - NAV MIC VOR 54-18-19.80N 011-00-18.72E 119 112.20 - NAV MIQ NDB 48-34-12.73N 011-35-51.00E 0 427 - NAV MND DME 49-28-14.16N 008-30-57.53E 351 113.55 - NAV MNE NDB 48-21-19.44N 011-40-33.60E 0 369 - NAV MNW NDB 48-22-27.47N 011-54-50.76E 0 338 - NAV MOD DME 52-08-16.80N 007-41-14.06E 207 114.05 - NAV MSE NDB 48-20-00.24N 011-39-10.44E 0 358 - NAV MST NDB 52-06-36.36N 007-34-18.16E 0 305 - NAV MSW NDB 48-21-08.65N 011-54-13.68E 0 400 - NAV MTR VOR 50-16-34.67N 008-50-55.07E 666 110.00 - NAV MU NDB 52-04-26.76N 011-38-53.88E 0 367 - NAV MUN VOR/DME 48-10-49.09N 011-48-57.60E 1802 112.30 - NAV MYN NDB 52-09-33.49N 007-47-59.96E 0 371 - NAV NDG NDB 48-49-45.84N 010-25-07.32E 0 375 - NAV NDO TACAN 53-46-08.40N 008-39-12.60E 120 117.10 - NAV NDO NDB 53-47-06.71N 008-48-22.21E 72 372 - NAV NEG TACAN 53-36-16.91N 013-18-31.32E 270 108.05 - NAV NER VOR/DME 50-21-59.76N 014-37-17.04E 1000 108.60 - NAV NEU TACAN 48-42-45.01N 011-12-39.60E 1296 108.90 - NAV NGD DME 49-30-04.33N 011-04-48.36E 1090 113.10 - NAV NID DME 51-35-59.99N 006-08-29.33E 152 115.50 - NAV NIE VOR 52-37-33.24N 009-22-19.16E 190 116.50 - NAV NKR NDB 49-20-12.12N 008-43-58.48E 0 292 - NAV NMN NDB 50-22-04.09N 007-18-49.21E 671 331 - NAV NRG NDB 53-36-10.07N 013-20-17.88E 264 357 - NAV NSN NDB 49-23-41.27N 009-57-54.00E 1595 311 - NAV NTM VORTAC 50-00-57.24N 006-31-54.44E 1388 115.30 - NAV OBI NDB 48-04-50.16N 011-17-07.44E 1923 429 - NAV OKG VOR/DME 50-03-54.37N 012-24-20.52E 1600 115.70 - NAV OKL VOR/DME 50-05-47.40N 014-15-46.08E 1200 112.60 - NAV OL NDB 53-33-18.00N 014-57-36.72E 0 397 - NAV OSB TACAN 52-12-06.11N 008-17-07.80E 343 108.35 - NAV OSN VOR 52-12-00.36N 008-17-07.87E 391 114.30 - NAV PAD NDB 51-37-24.96N 008-38-21.98E 673 354 - NAV PAH NDB 53-23-39.12N 011-39-57.24E 0 315 - NAV PG NDB 50-02-51.72N 014-22-09.48E 0 307 - NAV PI NDB 53-27-40.68N 011-54-25.92E 0 333 - NAV PMD DME 53-25-30.00N 011-47-06.00E 179 117.50 - NAV PR NDB 50-08-39.12N 014-22-01.92E 0 356 - NAV PSA NDB 49-51-43.93N 009-20-53.95E 0 370 - NAV PSK DME 49-47-51.00N 014-02-04.92E 2300 117.60 - NAV RA NDB 48-56-46.68N 014-30-55.08E 0 402 - NAV RAK NDB 50-05-49.56N 013-41-26.52E 0 386 - NAV RDG VOR/DME 49-02-25.07N 012-31-35.40E 2172 114.70 - NAV RID VOR/DME 49-46-54.12N 008-32-29.36E 328 112.20 - NAV RKN VOR/DME 52-07-59.53N 006-45-49.97E 137 116.80 - NAV RMS TACAN 49-26-04.92N 007-35-08.34E 762 113.40 - NAV RO NDB 51-20-36.96N 014-57-07.20E 0 432 - NAV RTB NDB 49-28-57.72N 011-15-10.44E 1096 415 - NAV RTT NDB 47-25-51.24N 011-56-24.36E 3707 303 - NAV RW NDB 52-32-42.36N 013-09-03.60E 0 392 - NAV SAD DME 49-12-45.01N 007-06-57.85E 1088 116.75 - NAV SAV VOR/DME 48-47-46.32N 007-26-52.73E 831 110.45 - NAV SBG VOR/DME 48-00-09.37N 012-53-34.08E 1494 113.80 - NAV SBG NDB 47-58-03.00N 012-53-38.76E 0 382 - NAV SBN NDB 49-13-08.04N 007-07-06.02E 1058 343 - NAV SDD DME 52-22-28.20N 013-30-13.32E 173 114.40 - NAV SG NDB 48-42-40.68N 009-20-06.14E 0 306 - NAV SGD DME 48-41-16.44N 009-13-26.79E 1332 115.45 - NAV SHD DME 49-06-59.40N 009-46-41.38E 1389 108.05 - NAV SHU NDB 47-01-18.48N 007-23-30.98E 2215 357 - NAV SI NDB 47-49-06.96N 012-59-15.72E 0 410 - NAV SIL NDB 50-40-48.00N 008-08-18.60E 0 489 - NAV SK NDB 51-26-05.28N 012-07-00.12E 0 434 - NAV SLD DME 50-42-24.47N 008-04-42.64E 2019 108.05 - NAV SLN NDB 52-23-33.36N 013-34-12.00E 0 362 - NAV SLT NDB 54-51-24.84N 008-24-35.93E 0 387 - NAV SO NDB 53-12-55.09N 006-47-06.58E 3 330 - NAV SPA TACAN 49-58-44.40N 006-41-51.72E 1161 109.50 - NAV SR NDB 49-13-04.08N 007-13-10.24E 0 360 - NAV STK NDB 52-59-48.12N 006-53-44.41E 18 315 - NAV STR VOR/DME 48-30-19.45N 007-34-19.09E 586 115.60 - NAV SU NDB 47-52-45.48N 012-56-59.64E 0 356 - NAV SUI VOR/DME 52-22-47.65N 014-35-08.16E 98 116.70 - NAV SUL VOR 48-22-53.76N 008-38-41.42E 0 116.10 - NAV SWG TACAN 54-27-13.32N 009-30-05.40E 105 111.80 - NAV SY NDB 48-40-09.12N 009-06-51.12E 0 384 - NAV TAU VORTAC 50-15-01.80N 008-09-45.07E 1343 116.70 - NAV TGL VOR/DME 52-33-41.40N 013-17-15.36E 118 112.30 - NAV TGO VORTAC 48-37-06.24N 009-15-33.15E 1213 112.50 - NAV TOF VOR/DME 52-28-23.16N 013-24-19.44E 199 114.10 - NAV TRA VOR/DME 47-41-22.20N 008-26-13.02E 1850 114.30 - NAV TRT VOR/DME 54-30-39.61N 013-14-57.48E 41 108.45 - NAV TWN TACAN 52-16-28.21N 006-53-29.51E 114 110.70 - NAV TWN NDB 52-16-04.43N 006-52-34.18E 98 336 - NAV VO NDB 50-12-39.97N 014-25-42.24E 0 333 - NAV VOZ VOR/DME 49-31-56.28N 014-52-28.92E 2200 116.30 - NAV WBD NDB 50-02-56.40N 008-19-43.21E 490 399 - NAV WES DME 54-54-37.80N 008-20-23.64E 49 111.50 - NAV WIB TACAN 50-02-46.32N 008-18-38.99E 472 114.10 - NAV WIL VOR/DME 47-10-41.88N 007-54-21.31E 2417 116.90 - NAV WLD VOR/DME 48-34-45.84N 011-07-45.84E 1396 112.80 - NAV WLU NDB 49-34-04.08N 006-03-15.01E 0 346 - NAV WRB VOR/DME 51-30-20.52N 009-06-39.28E 843 113.70 - NAV WSR VOR 53-20-51.71N 008-52-31.23E 0 112.90 - NAV WTM TACAN 53-33-15.47N 007-43-30.61E 61 113.50 - NAV WUN TACAN 52-27-37.08N 009-26-41.39E 202 114.85 - NAV WUN NDB 52-27-33.48N 009-27-16.78E 203 419 - NAV WUR VOR 49-43-03.00N 009-56-49.20E 1052 110.20 - NAV WYP VOR 51-02-54.24N 007-16-48.00E 902 109.60 - NAV ZBN NDB 49-13-39.36N 007-24-59.69E 0 435 - NAV ZIG NDB 51-26-02.39N 012-16-49.80E 463 340 - NAV ZND DME 49-12-33.48N 007-23-44.81E 1201 109.10 - NAV ZUE VOR/DME 47-35-31.92N 008-49-03.61E 1730 110.05 - NAV ZW NDB 47-11-53.16N 014-45-24.12E 0 418 - NAV ZWN VOR/DME 49-13-44.76N 007-25-04.40E 1177 114.80 - # Dusseldorf (EDDL): ILS 05L ILS/DME IDNE 110.95 51-18-00.10N 006-46-59.08E 51-16-58.94N 006-44-52.49E 109 5 52.9 3 ILS 23R ILS/DME IDNW 109.30 51-16-55.45N 006-44-43.06E 51-17-56.62N 006-46-49.64E 185 5 232.8 3 ILS 05R ILS/DME IDSE 111.50 51-17-51.11N 006-47-22.72E 51-16-44.18N 006-45-04.26E 109 5 52.8 3 ILS 23L ILS/DME IDSW 109.90 51-16-40.69N 006-44-54.84E 51-17-47.62N 006-47-13.29E 185 5 232.8 3 # Frankfurt (EDDF): ILS 07C ILS/DME IFCE 110.55 50-02-45.73N 008-35-27.27E 50-01-54.49N 008-32-02.65E 342 5 69.7 3 ILS 25C ILS/DME IFCW 111.55 50-01-53.98N 008-31-50.54E 50-02-45.23N 008-35-15.16E 386 5 249.6 3 ILS 07L ILS/DME IFNE 111.75 50-02-48.24N 008-32-15.54E 50-02-10.68N 008-29-47.48E 342 5 69.8 3 ILS 25R ILS/DME IFNW 111.35 50-02-10.20N 008-29-35.35E 50-02-47.76N 008-32-03.41E 386 5 249.7 3 ILS 07R ILS/DME IFSE 110.95 50-02-27.75N 008-35-25.63E 50-01-36.13N 008-32-00.98E 342 5 69.5 3 ILS 25L ILS/DME IFSW 111.15 50-01-35.60N 008-31-48.89E 50-02-27.23N 008-35-13.55E 387 5 249.5 3 # Munich (EDDM): ILS 08L ILS/DME IMNE 109.50 48-22-01.94N 011-49-30.80E 48-21-42.99N 011-46-01.97E 1479 5 83.5 3 ILS 26R ILS/DME IMNW 108.70 48-21-44.97N 011-45-48.88E 48-22-03.93N 011-49-17.71E 1495 5 263.4 3 ILS 08R ILS/DME IMSE 109.30 48-20-42.38N 011-48-31.03E 48-20-23.43N 011-45-02.21E 1479 5 83.5 3 ILS 26L ILS/DME IMSW 108.30 48-20-25.41N 011-44-49.13E 48-20-44.37N 011-48-17.95E 1495 5 263.4 3 acm-6.0_20200416/objects/zones/usa/0000755000000000000000000000000013175511064015155 5ustar rootrootacm-6.0_20200416/objects/zones/usa/sfrancisco.txt0000644000000000000000000004741513646045023020063 0ustar rootroot# S. Francisco area scenery. # Created: 2020-04-16 # Latitude range: [35N, 40N[ # Longitude range: [125W, 120W[ # 2017-10-04 Checked against https://nfdc.faa.gov/xwiki/bin/view/NFDC/56DaySub-2017-03-02 # "56 Day NASR Subscription - Effective March 2, 2017". # ?????: TEAM1_LOC 35N 125W 000 031 # ?????: TEAM1_LOC 35N 125W 000 031 GROUND_COLOR #305030 RWY 2O3 16/34 1875 3217 50 38-35-03.9300N 122-26-09.7400W 38-34-32.2700N 122-26-05.7300W RWY AUN 07/25 1539 3700 75 38-57-15.4684N 121-05-17.5148W 38-57-19.2296N 121-04-30.9279W RWY O02 08/26 4900 4651 75 39-49-06.7267N 120-21-39.9240W 39-49-06.6172N 120-20-40.3284W RWY D83 13/31 379 2838 50 39-01-01.3527N 123-23-04.5495W 39-00-39.1074N 123-22-42.6338W RWY 2CL1 06/24 2120 2326 20 39-27-16.5535N 121-17-44.4269W 39-27-20.9491N 121-17-15.3230W RWY C83 05/23 79 3000 75 37-49-20.3509N 121-37-48.4195W 37-49-33.7316N 121-37-15.0582W RWY C83 12/30 79 4500 100 37-50-08.4954N 121-37-53.5205W 37-49-36.8929N 121-37-14.0485W RWY O61 13/31 1287 4051 50 38-41-18.5051N 120-59-30.1488W 38-40-46.1900N 120-58-59.9894W RWY CIC 13L/31R 240 6724 150 39-48-12.1750N 121-51-50.8290W 39-47-16.1780N 121-51-04.4520W RWY CIC 13R/31L 240 3000 60 39-47-54.1962N 121-51-46.5686W 39-47-29.2063N 121-51-25.8867W RWY CA11 15/33 5909 1032 40 39-59-54.8700N 120-13-02.5300W 39-59-45.0700N 120-12-58.8400W RWY CL56 14/32 173 2156 30 39-43-19.8456N 121-52-19.7678W 39-43-00.7074N 121-52-07.6391W RWY 2O6 12/30 243 3253 60 37-06-59.1965N 120-15-03.3923W 37-06-36.4847N 120-14-34.9558W RWY CN13 09/27 12 2260 90 38-26-38.8398N 121-30-45.5759W 38-26-32.6349N 121-30-18.2885W RWY O60 14/32 276 2909 60 38-46-47.3350N 122-59-41.8530W 38-46-21.7967N 122-59-24.9654W RWY 3O8 14/32 470 2820 30 36-15-05.8000N 120-14-25.7400W 36-14-40.5200N 120-14-11.1800W RWY C80 01/19 625 2471 60 36-09-23.6880N 120-17-51.7437W 36-09-47.6108N 120-17-45.6259W RWY C80 12/30 625 5000 100 36-10-03.7300N 120-18-00.8405W 36-09-31.4749N 120-17-14.6340W RWY O22 11/29 2121 2607 50 38-01-58.8649N 120-25-13.8617W 38-01-41.0903N 120-24-50.2743W RWY O22 17/35 2121 4673 75 38-02-12.0276N 120-24-41.8439W 38-01-26.5676N 120-24-52.1590W RWY O08 13/31 50 3035 60 39-10-57.5045N 121-59-45.3908W 39-10-31.2992N 121-59-26.6340W RWY CCR 01L/19R 26 5001 150 37-58-55.0261N 122-03-40.7820W 37-59-40.3546N 122-03-15.8504W RWY CCR 01R/19L 26 2770 75 37-59-01.9609N 122-03-30.1664W 37-59-27.0673N 122-03-16.3488W RWY CCR 14L/32R 26 4602 150 37-59-47.4460N 122-03-31.8793W 37-59-06.7230N 122-03-06.2645W RWY CCR 14R/32L 26 2799 75 37-59-45.2356N 122-03-37.4729W 37-59-20.4670N 122-03-21.8795W RWY 0O4 17/35 296 2699 60 39-56-59.3248N 122-10-16.0258W 39-56-32.6529N 122-10-16.0132W RWY O09 10/28 1434 3670 60 39-47-32.7300N 123-16-20.5800W 39-47-18.8800N 123-15-37.1200W RWY DWA 16/34 100 6000 100 38-35-15.4205N 121-51-24.7450W 38-34-16.1107N 121-51-25.2738W RWY EDU 17/35 69 3176 50 38-32-08.9500N 121-47-11.0600W 38-31-37.5550N 121-47-11.5800W RWY 0CN1 16/34 140 2229 80 37-27-18.8600N 120-45-53.1200W 37-26-56.8200N 120-45-53.1300W RWY BLU 15/33 5284 3300 50 39-16-45.7757N 120-42-39.6251W 39-16-13.9215N 120-42-30.6529W RWY SUU 03L/21R 63 11001 150 38-14-35.8654N 121-57-25.1211W 38-15-49.1104N 121-55-43.1781W RWY SUU 03R/21L 63 10995 150 38-15-41.2758N 121-55-35.4583W 38-16-54.4489N 121-53-53.5150W RWY 74CA 09/27 1451 666 30 38-28-03.9400N 120-48-16.6700W 38-28-02.8300N 120-48-08.4200W RWY F34 12/30 157 3102 60 36-51-47.6400N 120-28-04.4530W 36-51-24.2770N 120-27-39.7150W RWY CN22 15/33 1170 2082 30 36-42-14.1200N 120-51-30.7800W 36-42-32.8300N 120-51-41.4700W RWY F72 09/27 23 3031 60 38-18-09.4485N 121-26-04.5064W 38-18-02.0722N 121-25-27.6606W RWY F72 18/36 23 3123 60 38-18-37.7757N 121-25-40.1089W 38-18-07.8454N 121-25-49.6873W RWY E36 16/34 2623 2980 60 38-55-30.1900N 120-51-53.0600W 38-55-00.7300N 120-51-53.7100W RWY 09CL 01/19 2280 2834 50 39-06-30.8729N 121-03-26.6455W 39-06-55.9847N 121-03-10.7122W RWY GOO 07/25 3154 4351 75 39-13-25.5322N 121-00-38.7170W 39-13-27.5510N 120-59-43.5113W RWY 44CL 12/30 35 2323 30 39-03-01.0800N 121-57-10.8500W 39-02-43.4700N 121-56-51.9500W RWY E45 09/27 2933 3624 50 37-51-48.2647N 120-11-03.9653W 37-51-35.7271N 120-10-21.6363W RWY E55 13/31 940 2500 50 38-48-15.9000N 123-31-59.5000W 38-47-55.8000N 123-31-41.1200W RWY 3O1 18/36 79 3207 60 37-15-53.2764N 120-57-45.8990W 37-15-22.7852N 120-57-56.7840W RWY HAF 12/30 66 5000 150 37-31-06.4216N 122-30-25.3737W 37-30-30.3128N 122-29-42.9993W RWY HWD 10L/28R 52 3107 75 37-39-44.9116N 122-07-38.1416W 37-39-29.6167N 122-07-04.6322W RWY HWD 10R/28L 52 5694 150 37-39-43.3603N 122-07-47.2468W 37-39-15.3360N 122-06-45.8415W RWY HES 13/31 280 2652 60 38-39-21.1600N 122-54-04.4530W 38-38-59.4260N 122-53-45.7660W RWY CVH 06/24 230 3150 100 36-53-22.9990N 121-24-48.2880W 36-53-32.6940N 121-24-11.4440W RWY CVH 13/31 230 6350 100 36-54-04.8080N 121-25-04.6290W 36-53-15.4090N 121-24-16.3730W RWY 1C9 05/23 152 2500 100 36-57-06.0175N 121-28-00.4867W 36-57-16.3563N 121-27-32.5019W RWY JAQ 01/19 1694 3401 60 38-22-20.9021N 120-47-46.0730W 38-22-52.0710N 120-47-30.0664W RWY KIC 11/29 374 4479 100 36-13-57.1650N 121-07-37.4748W 36-13-28.3731N 121-06-55.9374W RWY 1O2 10/28 1380 3600 60 38-59-34.8342N 122-54-22.4987W 38-59-17.5234N 122-53-42.6688W RWY LHM 15/33 121 6001 100 38-55-01.6673N 121-21-14.4429W 38-54-04.2960N 121-20-55.1873W RWY LLR 11/29 574 5249 100 39-15-59.2692N 123-45-39.9144W 39-15-27.4353N 123-44-47.2230W RWY LVK 07L/25R 400 5253 100 37-41-38.1733N 121-49-45.8457W 37-41-37.6575N 121-48-40.5005W RWY LVK 07R/25L 400 2699 75 37-41-33.1135N 121-49-30.3197W 37-41-32.8405N 121-48-56.7405W RWY 1O3 08/26 60 3547 40 38-12-11.2400N 121-16-33.9600W 38-12-09.7600N 121-15-49.5600W RWY 1O3 12/30 60 1979 25 38-12-12.6000N 121-16-12.6300W 38-11-58.8600N 121-15-54.9900W RWY 8CA8 17/35 56 3488 50 38-04-19.7200N 121-12-26.8000W 38-03-45.2500N 121-12-27.8800W RWY LSN 14/32 121 3801 75 37-04-06.7509N 120-52-22.0680W 37-03-33.1949N 120-52-00.9647W RWY MAE 08/26 255 3702 150 36-59-00.1470N 120-07-09.2510W 36-59-00.1330N 120-06-23.6270W RWY MAE 12/30 255 5545 150 36-59-38.3497N 120-07-08.9732W 36-58-59.5717N 120-06-20.6676W RWY OAR 11/29 137 3483 75 36-41-02.7937N 121-45-59.9470W 36-40-44.1889N 121-45-23.9581W RWY MPI 08/26 2254 3306 60 37-30-41.8802N 120-02-42.5598W 37-30-36.3816N 120-02-02.1206W RWY MYV 05/23 64 3314 60 39-05-48.4875N 121-34-26.7648W 39-06-01.4010N 121-33-48.1347W RWY MYV 14/32 64 6007 150 39-06-17.6780N 121-34-28.5211W 39-05-23.1198N 121-33-58.4684W RWY BAB 15/33 113 12001 300 39-09-06.1584N 121-26-36.0573W 39-07-13.7693N 121-25-47.3550W RWY M90 15/33 162 3499 50 36-45-47.9000N 120-22-24.2800W 36-45-15.0900N 120-22-10.6300W RWY MCE 12/30 155 5914 150 37-17-26.9527N 120-31-14.3475W 37-16-43.1646N 120-30-25.8596W RWY MER 13/31 191 11802 150 37-23-35.1045N 120-34-51.4498W 37-22-04.3758N 120-33-19.5014W RWY MOD 10L/28R 99 5904 150 37-37-47.0627N 120-57-36.3665W 37-37-14.3221N 120-56-35.6163W RWY MOD 10R/28L 99 3464 100 37-37-46.4407N 120-57-50.7369W 37-37-27.2315N 120-57-15.0869W RWY MRY 10L/28R 257 3503 60 36-35-18.8949N 121-50-40.6812W 36-35-05.4860N 121-50-01.0801W RWY MRY 10R/28L 257 7175 150 36-35-27.1540N 121-51-21.0030W 36-34-59.7150N 121-49-59.8680W RWY NUQ 14L/32R 37 9197 200 37-25-44.1162N 122-03-16.5762W 37-24-19.9751N 122-02-33.3448W RWY NUQ 14R/32L 37 8122 200 37-25-30.7978N 122-03-18.1025W 37-24-16.4902N 122-02-39.9285W RWY APC 06/24 35 5007 150 38-12-27.7506N 122-17-18.5464W 38-12-39.1008N 122-16-17.4819W RWY APC 18L/36R 35 2510 75 38-13-06.6828N 122-16-41.8896W 38-12-43.4757N 122-16-53.0276W RWY APC 18R/36L 35 5930 150 38-13-23.5377N 122-16-40.6654W 38-12-28.7143N 122-17-06.9774W RWY DVO 13/31 2 3300 75 38-08-50.9500N 122-33-35.9400W 38-08-22.7600N 122-33-15.0900W RWY O27 10/28 237 3013 75 37-45-28.2760N 120-48-18.2060W 37-45-17.3934N 120-47-43.2884W RWY OAK 10L/28R 9 5458 150 37-43-49.6865N 122-13-19.8481W 37-43-29.3247N 122-12-16.9329W RWY OAK 10R/28L 9 6213 150 37-43-43.3450N 122-13-33.2509W 37-43-20.1780N 122-12-21.6341W RWY OAK 12/30 9 10520 150 37-43-12.2235N 122-14-31.6115W 37-42-05.3678N 122-12-51.3186W RWY OAK 15/33 9 3376 75 37-44-25.0497N 122-13-22.1076W 37-43-52.9005N 122-13-10.8260W RWY L52 11/29 14 2325 50 35-06-11.7700N 120-37-32.0600W 35-05-58.9100N 120-37-08.8600W RWY O37 15/33 218 4500 60 39-43-34.9430N 122-08-54.0871W 39-42-51.8646N 122-08-39.7809W RWY OVE 02/20 194 6020 100 39-28-43.8564N 121-37-54.5111W 39-29-33.7674N 121-37-12.7193W RWY OVE 13/31 194 3540 100 39-29-42.7380N 121-37-07.9036W 39-29-14.5213N 121-36-41.2177W RWY PAO 13/31 7 2443 70 37-27-49.5066N 122-07-03.5484W 37-27-30.5562N 122-06-44.7693W RWY CA92 17/35 1300 3017 60 39-42-52.9377N 121-36-58.9636W 39-42-23.1354N 121-36-59.9246W RWY PRB 01/19 839 6008 150 35-39-57.9903N 120-38-08.0778W 35-40-50.1322N 120-37-33.1655W RWY PRB 13/31 839 4701 100 35-40-38.9547N 120-37-37.5476W 35-40-01.5151N 120-37-03.7781W RWY CN99 12/30 65 2873 34 37-32-57.2700N 121-09-43.4500W 37-32-37.0600N 121-09-18.3700W RWY O69 11/29 90 3602 75 38-15-38.3839N 122-36-37.5555W 38-15-17.7276N 122-36-00.7835W RWY PVF 05/23 2585 3910 75 38-43-18.3570N 120-45-33.9880W 38-43-35.9680N 120-44-50.0630W RWY 2O1 07/25 3419 4105 60 39-56-35.3387N 120-57-09.5064W 39-56-40.8737N 120-56-17.3100W RWY RIU 04/22 144 3798 75 38-29-01.0681N 121-06-29.1090W 38-29-23.6323N 121-05-50.9405W RWY L36 17/35 46 2625 42 38-40-42.9252N 121-26-42.4650W 38-40-17.0364N 121-26-44.7584W RWY O88 07/25 23 4199 75 38-11-36.4119N 121-42-34.4045W 38-11-39.5149N 121-41-41.9495W RWY O88 15/33 23 2199 60 38-11-42.9840N 121-42-27.1566W 38-11-22.5546N 121-42-17.7389W RWY SMF 16L/34R 27 8605 150 38-42-25.6973N 121-34-48.2125W 38-41-00.6506N 121-34-49.6420W RWY SMF 16R/34L 27 8598 150 38-42-26.4236N 121-36-03.8961W 38-41-01.4390N 121-36-05.3075W RWY MHR 04L/22R 98 6038 150 38-33-10.9400N 121-18-17.9400W 38-33-46.2800N 121-17-16.6600W RWY MHR 04R/22L 98 11301 150 38-32-40.9712N 121-18-48.6565W 38-33-47.0922N 121-16-53.9917W RWY SAC 02/20 24 5503 150 38-30-18.7475N 121-30-02.6274W 38-31-04.3070N 121-29-24.7979W RWY SAC 12/30 24 3837 100 38-31-06.1074N 121-29-42.2645W 38-30-40.1781N 121-29-07.0313W RWY SAC 16/34 24 3505 150 38-30-59.2571N 121-29-38.2750W 38-30-24.6093N 121-29-37.9850W RWY MCC 16/34 77 10599 150 38-40-55.8781N 121-24-02.0787W 38-39-11.1092N 121-24-02.2412W RWY SNS 08/26 84 6004 150 36-39-46.4871N 121-37-06.7407W 36-39-39.4288N 121-35-53.5799W RWY SNS 13/31 84 4825 150 36-40-06.9853N 121-36-36.0221W 36-39-26.6018N 121-36-04.4804W RWY CPU 13/31 1328 3603 60 38-09-00.7622N 120-39-06.0834W 38-08-31.2844N 120-38-40.7859W RWY SQL 12/30 5 2600 75 37-30-52.2250N 122-15-09.0861W 37-30-33.1302N 122-14-47.4839W RWY SFO 01L/19R 13 7650 200 37-36-28.4323N 122-22-58.5426W 37-37-35.3329N 122-22-14.1939W RWY SFO 01R/19L 13 8650 200 37-36-22.7876N 122-22-51.7467W 37-37-38.4319N 122-22-01.5990W RWY SFO 10L/28R 13 11870 200 37-37-43.4594N 122-23-36.2107W 37-36-48.7210N 122-21-25.7080W RWY SFO 10R/28L 13 11381 200 37-37-34.6480N 122-23-35.1796W 37-36-42.1630N 122-21-30.0570W RWY RHV 13L/31R 135 3100 75 37-20-11.4493N 121-49-21.3662W 37-19-47.0107N 121-48-58.2046W RWY RHV 13R/31L 135 3099 75 37-20-09.6541N 121-49-24.3301W 37-19-45.2266N 121-49-01.1735W RWY SJC 12L/30R 62 11000 150 37-22-29.9737N 121-56-24.6306W 37-21-08.1263N 121-54-54.9156W RWY SJC 12R/30L 62 11000 150 37-22-25.4201N 121-56-31.1528W 37-21-03.5704N 121-55-01.4378W RWY SBP 07/25 212 2500 100 35-14-12.6982N 120-39-00.9699W 35-14-12.7926N 120-38-30.8377W RWY SBP 11/29 212 6101 150 35-14-31.9696N 120-38-58.4419W 35-13-57.5621N 120-37-58.0308W RWY E16 14/32 284 3095 75 37-05-07.7164N 121-35-56.2038W 37-04-39.7163N 121-35-40.8079W RWY STS 02/20 129 5202 100 38-30-11.3946N 122-49-15.4684W 38-30-56.2896N 122-48-43.5628W RWY STS 14/32 129 6000 150 38-31-03.0634N 122-48-49.7384W 38-30-08.3904N 122-48-20.4754W RWY 0Q3 07/25 16 2700 45 38-13-23.9500N 122-27-09.1100W 38-13-23.8800N 122-26-35.2700W RWY 0Q3 17/35 16 1513 50 38-13-37.7686N 122-27-11.0207W 38-13-22.8133N 122-27-11.2693W RWY O79 03/21 4984 3260 50 39-34-43.3800N 120-21-30.1700W 39-35-04.5700N 120-20-58.7800W RWY 0Q9 08/26 20 2480 40 38-15-28.5000N 122-26-18.1000W 38-15-25.0100N 122-25-47.3200W RWY SCK 11L/29R 33 10650 150 37-54-08.4310N 121-15-03.2003W 37-53-04.2154N 121-13-17.9147W RWY SCK 11R/29L 33 4448 75 37-53-58.6710N 121-14-57.4210W 37-53-31.8556N 121-14-13.4473W RWY CN95 13/31 -24 2837 50 37-59-46.5300N 121-29-43.8000W 37-59-25.2700N 121-29-20.6900W RWY 1Q4 12/30 62 3530 60 37-40-53.2400N 121-18-18.6100W 37-40-26.7800N 121-17-49.9600W RWY CA74 12/30 35 2063 30 37-43-59.9300N 121-20-17.2700W 37-43-45.6200N 121-19-58.9700W RWY TCY 08/26 193 3438 75 37-41-25.7450N 121-26-53.8050W 37-41-25.9870N 121-26-11.0370W RWY TCY 12/30 193 4001 75 37-41-28.1200N 121-26-45.9340W 37-41-01.8928N 121-26-08.6784W RWY TRK 02/20 5901 4650 75 39-18-52.2720N 120-08-23.8990W 39-19-32.0680N 120-07-54.3350W RWY TRK 11/29 5901 7000 100 39-19-29.4440N 120-09-09.8576W 39-18-54.8707N 120-07-52.7405W RWY O15 12/30 161 2985 50 37-29-13.1062N 120-42-03.2592W 37-28-51.8688N 120-41-37.5438W RWY UKI 15/33 617 4423 150 39-07-54.8340N 123-12-08.7700W 39-07-12.0246N 123-11-57.4192W RWY 1Q5 01/19 1900 4050 200 39-26-45.4100N 122-57-29.9200W 39-27-19.6900N 122-57-03.2400W RWY VCB 02/20 117 4700 75 38-22-22.3247N 121-57-56.7113W 38-23-00.9631N 121-57-23.9357W RWY WVI 02/20 163 4501 149 36-55-44.5333N 121-47-44.8642W 36-56-22.1376N 121-47-15.2282W RWY WVI 09/27 163 3998 98 36-56-17.9780N 121-47-38.6633W 36-56-11.2350N 121-46-50.1373W RWY O28 16/34 2066 2995 75 39-27-19.5118N 123-22-21.9671W 39-26-50.0189N 123-22-18.8103W RWY WLW 13/31 141 3788 60 39-31-11.2596N 122-13-06.5041W 39-30-40.5923N 122-12-38.7904W RWY WLW 16/34 141 4125 100 39-31-17.8247N 122-13-11.7798W 39-30-37.0784N 122-13-10.1327W RWY O41 18/36 125 3759 60 38-40-43.4900N 121-52-11.7200W 38-40-08.3980N 121-52-27.3160W RWY O52 17/35 60 3045 75 39-07-40.1437N 121-36-16.8282W 39-07-10.2952N 121-36-21.8161W ILS 22L ILS/DME IMHR 111.35 38-32-32.179N 121-19-03.903W 38-33-36.464N 121-17-01.582W 92 3.13 233.59 3.00 ILS 31 ILS ISNS 108.50 36-40-17.917N 121-36-44.561W 36-39-36.352N 121-36-07.757W 78 6.00 327.93 3.00 ILS 19R LDA ICCR 108.50 37-58-57.439N 122-03-34.009W - - 23 5.00 197.76 - ILS 34L ILS/DME IHUX 111.10 38-42-36.650N 121-36-03.720W 38-41-12.501N 121-36-00.081W 22 4.16 0.75 3.00 ILS 02 ILS ISAC 110.30 38-31-13.323N 121-29-17.312W 38-30-25.582N 121-29-50.948W 20 6.00 33.01 3.00 ILS 30 ILS/DME IINB 108.70 37-43-29.873N 122-14-58.104W 37-42-09.750N 122-13-05.632W 4 3.04 310.11 3.00 ILS 12R ILS/DME ISLV 110.90 37-21-03.037N 121-55-00.853W 37-22-06.024N 121-56-14.583W 36 4.60 138.94 3.00 ILS 28R ILS IMOD 111.90 37-37-53.797N 120-57-48.867W 37-37-23.278N 120-56-42.262W 84 5.63 304.23 3.00 ILS 12 ILS IAAZ 111.90 37-42-02.254N 122-12-46.650W 37-43-02.930N 122-14-22.820W 3 3.64 130.12 2.75 ILS 25R ILS ILVK 110.50 37-41-38.229N 121-49-52.644W 37-41-35.286N 121-48-52.840W 393 6.00 270.57 3.00 ILS 33 LOC/GS IMIZ 109.50 39-09-34.740N 121-26-48.448W 39-07-25.634N 121-25-45.799W 98 3.00 341.42 3.00 ILS 30 ILS/DME IMCE 109.30 37-17-32.859N 120-31-20.887W 37-16-48.289N 120-30-37.320W 153 5.97 318.62 3.00 ILS 16 ILS IMCC 109.70 38-38-52.793N 121-24-02.271W 38-40-45.936N 121-24-08.400W 72 3.19 180.07 3.00 ILS 28X LDA/DME IFNP 110.75 37-37-16.675N 122-22-06.215W 37-36-49.944N 122-21-40.241W 9 5.00 294.82 3.00 ILS 15 ILS/DME ILHM 108.75 38-53-51.199N 121-20-50.791W 38-54-54.332N 121-21-07.404W 120 5.45 165.36 3.00 ILS 11 ILS ISBP 109.70 35-13-54.037N 120-37-51.845W 35-14-20.714N 120-38-44.490W 172 6.00 124.89 3.00 ILS 28R ILS IOAK 109.90 37-43-54.550N 122-13-34.860W 37-43-28.596N 122-12-30.621W 3 5.93 292.26 3.00 ILS 03L LOC/GS ITXV 108.35 38-16-06.768N 121-55-18.576W 38-14-40.751N 121-57-09.016W 28 3.00 47.55 2.50 ILS 19L ILS/DME ISIA 108.90 37-36-16.280N 122-22-56.061W 37-37-30.738N 122-22-11.058W 6 4.27 207.70 3.00 ILS 13L ILS ICIC 111.30 39-47-07.770N 121-50-57.490W 39-48-01.160N 121-51-47.018W 233 5.18 147.53 3.00 ILS 30L ILS/DME ISJC 110.90 37-22-27.185N 121-56-33.097W 37-21-33.003N 121-55-27.874W 49 4.61 318.93 3.00 ILS 34 ILS IFKZ 109.70 38-41-13.140N 121-24-02.049W 38-39-20.843N 121-24-08.510W 0 5.0 0.07 3.00 ILS 28R ILS/DME IGWQ 111.70 37-37-46.357N 122-23-43.119W 37-36-51.399N 122-21-43.117W 8 3.29 297.90 3.00 ILS 28L ILS/DME ISFO 109.55 37-37-37.471N 122-23-41.920W 37-36-51.277N 122-21-43.200W 8 3.43 297.90 2.85 ILS 02 LOCALIZER IAYN 108.30 36-56-25.515N 121-47-12.565W - - 159 6.00 32.21 - ILS 28L LOC/DME IHWD 111.50 37-39-46.203N 122-07-46.752W - - 42 5.00 302.62 - ILS 32 ILS ISTS 109.30 38-31-12.293N 122-48-54.678W 38-30-16.289N 122-48-28.788W 119 5.72 337.27 3.00 ILS 10R ILS/DME IMRY 110.70 36-34-57.926N 121-49-54.634W 36-35-26.107N 121-51-09.714W 164 5.37 112.85 3.00 ILS 28L LOC/DME IMTB 110.70 36-35-29.727N 121-51-28.612W - - 155 5.22 292.84 - ILS 32R LOC/GS INUQ 110.35 37-25-52.377N 122-03-20.819W 37-24-32.159N 122-02-32.905W 24 3.97 337.80 3.00 ILS 21L ILS ISUU 110.10 38-15-32.286N 121-55-47.976W 38-16-50.066N 121-54-09.119W 47 3.24 227.56 2.80 ILS 29R ILS/DME ISCK 109.10 37-54-14.449N 121-15-13.085W 37-53-20.806N 121-13-36.950W 29 3.76 307.69 2.90 ILS 16R ILS/DME ISMF 111.10 38-40-35.749N 121-36-05.732W 38-42-15.861N 121-36-09.106W 23 3.58 180.74 3.00 ILS 16L ILS/DME IMDK 111.75 38-40-50.670N 121-34-49.810W 38-42-15.230N 121-34-44.355W 22 4.17 180.75 3.00 ILS 15 LOC/DME IUKI 109.10 39-07-07.750N 123-11-56.287W - - 611 6.00 168.38 - ILS 14 ILS IMYV 110.50 39-05-14.024N 121-33-53.466W 39-06-07.544N 121-34-27.778W 59 5.72 156.86 3.00 ILS 15 LOC/GS IBAB 109.50 39-06-36.513N 121-25-31.219W 39-08-53.395N 121-26-37.415W 103 3.00 161.43 2.75 ILS 36L ILS/DME IAPC 111.30 38-13-28.161N 122-16-38.440W 38-12-38.330N 122-17-04.370W 13 6.00 20.67 3.00 ILS 14L LOCALIZER IMNQ 110.35 37-24-12.233N 122-02-29.368W - - 34 3.97 157.80 - ILS 31 LOC/GS IMER 109.50 37-23-48.041N 120-35-04.567W 37-22-15.548N 120-33-22.854W 175 3.00 321.15 3.00 NAV BSR VORTAC 36-10-52.664N 121-38-31.604W 4080 114.00 087X NAV CIC VOR/DME 39-47-23.370N 121-50-49.902W 214 109.80 035X NAV CCR VOR/DME 38-02-41.714N 122-02-42.750W 8 117.00 117X NAV CC NDB 38-02-47.060N 122-02-00.350W 5 335 - NAV SUU TACAN 38-14-44.013N 121-56-42.274W 31 116.60 113X NAV TZZ VOR 38-20-39.139N 121-48-38.641W 32 116.40 - NAV HGT NDB 35-57-40.200N 121-11-21.000W 961 209 - NAV LIN VOR/DME 38-04-28.518N 121-00-13.888W 260 114.80 095X NAV LV NDB 37-41-31.996N 121-41-02.706W 684 374 - NAV BAB TACAN 39-08-05.260N 121-26-26.721W 90 108.60 023X NAV MY NDB 39-10-09.809N 121-36-35.481W 64 222 - NAV MYV VOR/DME 39-05-55.121N 121-34-23.007W 62 110.80 045X NAV MXW VORTAC 39-19-03.261N 122-13-17.535W 110 110.00 037X NAV HYP VOR/DME 37-13-09.957N 120-24-00.786W 184 114.20 089X NAV MOD VOR/DME 37-37-38.547N 120-57-28.320W 93 114.60 093X NAV NUQ TACAN 37-25-56.692N 122-03-27.305W 4 117.60 123X NAV SGD VORTAC 38-10-45.695N 122-22-23.345W 6 112.10 058X NAV OAK VOR/DME 37-43-33.322N 122-13-24.909W 13 116.80 115X NAV PXN VORTAC 36-42-55.651N 120-46-43.261W 2060 112.60 073X NAV PRB VORTAC 35-40-20.866N 120-37-37.587W 817 114.30 090X NAV HNW VOR/DME 38-43-29.009N 120-44-57.346W 2583 115.50 102X NAV PYE VOR/DME 38-04-47.124N 122-52-04.179W 1340 113.70 084X NAV ROM VOR 36-08-25.361N 120-39-53.707W 3880 110.00 - NAV MCC VOR/DME 38-40-02.621N 121-24-14.981W 65 109.20 029X NAV SAC VORTAC 38-26-37.483N 121-33-05.938W 3 115.20 099X NAV UAD NDB 36-29-27.265N 121-28-29.674W 105 263 - NAV SNS VORTAC 36-39-49.811N 121-36-11.465W 80 117.30 120X NAV SFO VOR/DME 37-37-10.144N 122-22-26.018W 7 115.80 105X NAV SJC VOR/DME 37-22-28.961N 121-56-40.801W 34 114.10 088X NAV MQO VORTAC 35-15-08.118N 120-45-34.439W 1463 112.40 071X NAV STS VOR/DME 38-30-29.472N 122-48-38.222W 121 113.00 077X NAV SAU VOR/DME 37-51-19.203N 122-31-21.908W 1040 116.20 109X NAV SWR VOR/DME 39-10-49.162N 120-16-10.604W 8850 113.20 079X NAV ECA VOR/DME 37-50-00.978N 121-10-16.957W 47 116.00 107X NAV TCY NDB 37-41-32.630N 121-26-40.670W 169 203 - NAV UK NDB 39-16-33.538N 123-14-26.388W 873 371 - NAV ENI VORTAC 39-03-11.580N 123-16-27.576W 2985 112.30 070X NAV PDG NDB 36-54-48.852N 121-48-28.666W 105 327 - NAV ILA VORTAC 39-04-16.135N 122-01-38.079W 50 114.40 091X NAV OSI VOR/DME 37-23-33.000N 122-16-52.690W 2270 113.90 086X acm-6.0_20200416/objects/zones/usa/losangeles.txt0000644000000000000000000004241613646045023020061 0ustar rootroot# Los Angeles area scenery. # Created: 2020-04-16 # Latitude range: [30N, 35N[ # Longitude range: [120W, 115W[ # 2017-10-04 Checked against https://nfdc.faa.gov/xwiki/bin/view/NFDC/56DaySub-2017-03-02 # "56 Day NASR Subscription - Effective March 2, 2017". # ?????: TEAM1_LOC 30N 120W 000 031 # ?????: TEAM1_LOC 30N 120W 000 031 GROUND_COLOR #305030 RWY L54 11/29 1220 2500 60 32-57-26.3825N 116-17-53.9176W 32-57-14.6830N 116-17-28.0594W RWY L70 04/22 2660 4600 50 34-29-58.9300N 118-19-09.2900W 34-30-26.7400N 118-18-24.6200W RWY APV 08/26 3062 4099 60 34-34-10.4105N 117-11-38.4992W 34-34-10.4154N 117-10-49.4877W RWY APV 18/36 3062 6498 150 34-35-15.1688N 117-10-57.1640W 34-34-13.4234N 117-11-18.6816W RWY AVX 04/22 1602 3000 75 33-24-09.4400N 118-25-11.2300W 33-24-26.5400N 118-24-42.3100W RWY BNG 08/26 2222 4955 100 33-55-21.3858N 116-51-32.9146W 33-55-20.9956N 116-50-34.1119W RWY L35 08/26 6752 5850 75 34-15-49.5020N 116-51-56.5570W 34-15-49.7823N 116-50-46.8850W RWY L08 08/26 520 5011 75 33-15-32.0000N 116-19-45.0000W 33-15-33.0000N 116-18-46.0000W RWY BWC 08/26 -128 4402 60 32-59-34.5395N 115-31-26.6054W 32-59-34.6190N 115-30-34.9289W RWY BUR 08/26 778 5802 150 34-11-52.4795N 118-22-08.9142W 34-11-51.5410N 118-20-59.8552W RWY BUR 15/33 778 6886 150 34-12-44.4407N 118-21-37.6605W 34-11-38.0587N 118-21-19.3333W RWY CXL 08/26 6 4683 75 32-40-03.2391N 115-31-30.6518W 32-40-02.2838N 115-30-35.8834W RWY CLR 08/26 -182 3423 50 33-07-53.0264N 115-31-37.0863W 33-07-52.5949N 115-30-56.8390W RWY CMA 08/26 77 6013 150 34-12-49.8119N 119-06-15.4596W 34-12-49.2278N 119-05-03.8660W RWY CRQ 06/24 331 4897 150 33-07-37.1582N 117-17-16.5298W 33-07-46.2872N 117-16-19.9780W RWY CNO 03/21 650 4919 150 33-58-14.2700N 117-38-30.3918W 33-58-49.0291N 117-37-49.5151W RWY CNO 08L/26R 650 4858 150 33-58-32.5541N 117-38-48.3179W 33-58-33.0451N 117-37-50.6371W RWY CNO 08R/26L 650 7000 150 33-58-24.6455N 117-38-48.2172W 33-58-25.3419N 117-37-25.1082W RWY L77 06/24 1713 4600 50 33-39-49.2100N 115-43-02.6800W 33-39-57.9400N 115-42-09.2500W RWY CPM 07L/25R 99 3323 60 33-53-24.6060N 118-14-57.4156W 33-53-24.7912N 118-14-18.0005W RWY CPM 07R/25L 99 3322 60 33-53-22.6246N 118-14-57.4025W 33-53-22.8161N 118-14-17.9928W RWY AJO 07/25 533 3200 60 33-53-51.3496N 117-36-27.7686W 33-53-51.8347N 117-35-49.8166W RWY DAG 04/22 1930 5123 100 34-51-07.3255N 116-47-33.6340W 34-51-39.5445N 116-46-46.1966W RWY DAG 08/26 1930 6402 150 34-51-05.3398N 116-47-52.2144W 34-51-05.3398N 116-46-35.4011W RWY CN64 05/23 559 4200 50 33-44-43.0200N 115-19-53.3800W 33-45-00.6500N 115-19-08.3300W RWY EDW 04L/22R 2311 12000 200 34-54-09.8758N 117-54-17.3120W 34-55-12.3655N 117-52-14.8375W RWY EDW 04R/22L 2311 15024 300 34-53-40.4153N 117-54-18.0431W 34-54-58.6478N 117-51-44.7079W RWY 9L2 06/24 2299 5998 150 34-59-18.7100N 117-52-22.1600W 34-59-34.9400N 117-51-12.8200W RWY NJK 08/26 -42 9503 200 32-49-44.8745N 115-41-13.5789W 32-49-44.9672N 115-39-22.2104W RWY NJK 12/30 -42 6824 200 32-49-47.2090N 115-40-19.5860W 32-48-59.3490N 115-39-23.1740W RWY EMT 01/19 296 3995 75 34-04-51.7510N 118-02-15.6240W 34-05-27.4420N 118-01-55.2290W RWY L18 18/36 708 2160 60 33-21-25.3600N 117-14-59.8900W 33-21-04.6400N 117-15-06.1100W RWY FUL 06/24 96 3121 75 33-52-15.8070N 117-59-05.3000W 33-52-22.7600N 117-58-29.2410W RWY HHR 07/25 66 4956 100 33-55-20.8320N 118-20-36.0310W 33-55-23.6130N 118-19-37.3180W RWY HMT 04/22 1512 2045 25 33-44-02.0700N 117-01-30.0900W 33-44-11.0700N 117-01-08.0900W RWY HMT 05/23 1512 4314 100 33-43-50.6590N 117-01-44.8870W 33-44-10.1060N 117-00-59.4090W RWY L26 03/21 3390 3910 50 34-22-21.7800N 117-19-12.2200W 34-22-52.2000N 117-18-43.3900W RWY L04 08/26 59 6000 150 32-50-42.1100N 115-16-41.7700W 32-50-41.5200N 115-15-31.4300W RWY IPL 08/26 -54 4501 75 32-49-55.5760N 115-35-24.4371W 32-49-55.5994N 115-34-31.7016W RWY IPL 14/32 -54 5308 100 32-50-33.0441N 115-34-45.4508W 32-49-46.3804N 115-34-16.9123W RWY NRS 08/26 24 2240 151 32-34-01.0843N 117-06-49.6739W 32-33-55.2860N 117-06-24.4043W RWY NRS 09/27 24 4997 336 32-34-04.6010N 117-07-22.0893W 32-33-51.7074N 117-06-25.7206W RWY L78 07/25 2844 2562 60 32-36-55.5900N 116-10-10.8000W 32-36-58.7500N 116-09-41.0800W RWY L80 06/24 2464 2493 50 34-09-13.9700N 116-15-20.4800W 34-09-18.4600N 116-14-51.3100W RWY WJF 06/24 2351 7201 150 34-44-16.8072N 118-13-48.1415W 34-44-38.7410N 118-12-26.0652W RWY POC 08L/26R 1014 3661 75 34-05-32.5291N 117-47-12.5173W 34-05-30.5067N 117-46-29.0628W RWY POC 08R/26L 1014 4840 75 34-05-30.1703N 117-47-25.8171W 34-05-27.4966N 117-46-28.3631W RWY LGB 07L/25R 60 6191 150 33-49-21.9119N 118-09-48.6727W 33-49-21.7015N 118-08-35.2853W RWY LGB 07R/25L 60 5421 150 33-48-49.7673N 118-09-40.6882W 33-48-49.8117N 118-08-36.4141W RWY LGB 12/30 60 10003 200 33-49-34.3247N 118-09-41.5171W 33-48-24.7148N 118-08-17.3104W RWY SLI 04L/22R 36 5901 150 33-47-07.1000N 118-03-43.4260W 33-47-40.5830N 118-02-46.1250W RWY SLI 04R/22L 36 7999 200 33-47-01.6060N 118-03-36.8100W 33-47-46.9980N 118-02-19.1480W RWY LAX 06L/24R 128 8926 150 33-56-56.8049N 118-25-52.1755W 33-57-07.5741N 118-24-07.0161W RWY LAX 06R/24L 128 10885 150 33-56-48.5343N 118-26-04.8016W 33-57-01.6661N 118-23-56.5618W RWY LAX 07L/25R 128 9600 150 33-56-08.9901N 118-25-09.6303W 33-56-20.5600N 118-23-16.5500W RWY LAX 07R/25L 128 11095 200 33-56-01.1378N 118-25-08.4660W 33-56-14.5069N 118-22-57.7701W RWY WHP 12/30 1003 4120 75 34-15-48.7000N 118-25-04.5300W 34-15-18.0600N 118-24-32.1500W RWY F70 18/36 1350 6000 75 33-34-56.0285N 117-07-34.8765W 33-33-58.0608N 117-07-50.1305W RWY L88 10/28 2203 3940 60 34-56-32.4800N 119-41-29.3300W 34-56-15.1000N 119-40-46.9600W RWY NFG 03/21 78 6005 221 33-17-43.2009N 117-21-43.2234W 33-18-25.8399N 117-20-53.9500W RWY NXF 09/27 89 1513 72 33-17-09.4000N 117-27-32.1387W 33-17-07.2348N 117-27-14.5052W RWY OKB 06/24 28 2712 75 33-13-02.3744N 117-21-21.1528W 33-13-07.0550N 117-20-49.7080W RWY L90 09/27 160 2475 150 33-08-48.1600N 116-08-03.5300W 33-08-41.9400N 116-07-35.3600W RWY L90 13/31 160 4210 150 33-09-13.2500N 116-08-10.2100W 33-08-38.8700N 116-07-42.2400W RWY ONT 08L/26R 944 12197 150 34-03-24.7542N 117-37-22.1464W 34-03-24.8152N 117-34-57.1903W RWY ONT 08R/26L 944 10200 150 34-03-17.8467N 117-36-58.4095W 34-03-17.8904N 117-34-57.1886W RWY OXR 07/25 45 5953 100 34-12-03.1688N 119-13-01.4489W 34-12-02.6322N 119-11-50.5801W RWY PMD 04/22 2543 12001 150 34-37-00.8420N 118-05-29.8020W 34-38-14.2360N 118-03-36.9660W RWY PMD 07/25 2543 12002 200 34-37-50.1060N 118-06-47.0290W 34-37-57.9910N 118-04-23.7430W RWY PSP 13L/31R 476 4952 75 33-50-06.5934N 116-30-34.8014W 33-49-27.2686N 116-29-59.7986W RWY PSP 13R/31L 476 10000 150 33-50-26.4463N 116-31-02.8130W 33-49-07.0294N 116-29-52.1279W RWY UDD 10/28 73 5002 70 33-45-05.1210N 116-16-55.9620W 33-44-43.5530N 116-16-02.6510W RWY TRM 12/30 -115 4995 100 33-37-48.6196N 116-10-15.5034W 33-37-13.6654N 116-09-33.7444W RWY TRM 17/35 -115 8500 150 33-38-20.9168N 116-09-23.0602W 33-36-56.8236N 116-09-23.0950W RWY L65 15/33 1413 5100 50 33-46-17.1700N 117-13-15.7400W 33-45-28.2200N 117-13-01.1200W RWY NTD 03/21 13 11102 200 34-06-30.4160N 119-08-04.2030W 34-07-49.6542N 119-06-32.7769W RWY NTD 09/27 13 5502 200 34-07-15.1333N 119-07-26.0007W 34-07-01.0300N 119-06-22.7951W RWY RNM 09/27 1395 5001 150 33-02-25.2425N 116-55-23.8455W 33-02-16.6840N 116-54-25.9941W RWY REI 08/26 1574 4504 75 34-05-06.8199N 117-09-13.7399W 34-05-07.0822N 117-08-20.2150W RWY RAL 09/27 819 5401 100 33-57-13.9946N 117-27-07.0891W 33-57-01.9321N 117-26-04.6412W RWY RAL 16/34 819 2850 50 33-57-18.5568N 117-26-55.0968W 33-56-50.3748N 117-26-54.2398W RWY RIR 06/24 767 3190 50 33-59-16.0200N 117-24-54.1100W 33-59-23.2500N 117-24-17.2400W RWY RIV 12/30 1536 3059 100 33-53-24.9100N 117-15-38.4300W 33-53-03.5600N 117-15-12.7200W RWY RIV 14/32 1536 13302 200 33-53-47.1500N 117-16-14.2900W 33-51-53.9800N 117-14-53.8100W RWY L00 08/26 2415 3600 50 34-52-13.8200N 118-12-41.1100W 34-52-13.6900N 118-11-57.9000W RWY SAS 07/25 -84 5000 75 33-14-26.0300N 115-57-38.6600W 33-14-30.4900N 115-56-40.0200W RWY SBD 06/24 1159 10000 200 34-05-26.7169N 117-15-01.5736W 34-05-59.8411N 117-13-09.5389W RWY NUC 06/24 184 9301 200 33-01-04.1317N 118-36-08.9596W 33-01-39.6479N 118-34-28.1900W RWY SEE 09L/27R 388 5342 100 32-49-46.0537N 116-58-52.5038W 32-49-34.9929N 116-57-51.2891W RWY SEE 09R/27L 388 2738 60 32-49-38.5719N 116-58-34.4547W 32-49-32.8978N 116-58-03.0796W RWY SEE 17/35 388 4145 100 32-49-46.2477N 116-58-20.9412W 32-49-05.2395N 116-58-20.6156W RWY MYF 05/23 427 3400 75 32-48-53.4698N 117-08-45.6181W 32-49-07.6906N 117-08-09.5208W RWY MYF 10L/28R 427 4577 150 32-49-05.3884N 117-08-40.8604W 32-48-46.2624N 117-07-52.2549W RWY MYF 10R/28L 427 3401 60 32-49-00.9012N 117-08-43.3216W 32-48-46.6902N 117-08-07.2071W RWY SAN 09/27 17 9400 200 32-44-13.6413N 117-12-15.6841W 32-43-48.0086N 117-10-29.9018W RWY NKX 06L/24R 477 12000 200 32-51-52.4391N 117-09-53.4567W 32-52-22.3469N 117-07-37.3024W RWY NKX 06R/24L 477 8001 200 32-51-55.7025N 117-09-06.0198W 32-52-15.6406N 117-07-35.2368W RWY NZY 11/29 26 7501 200 32-42-08.3820N 117-13-16.5910W 32-41-29.0900N 117-12-02.1260W RWY NZY 18/36 26 8001 200 32-42-36.1250N 117-12-42.0590W 32-41-19.8330N 117-13-07.0310W RWY SDM 08L/26R 526 7972 150 32-34-25.6400N 116-59-36.3200W 32-34-17.9380N 116-58-03.6090W RWY SDM 08R/26L 526 3180 75 32-34-17.6938N 116-59-03.5966W 32-34-14.6300N 116-58-26.6100W RWY NSI 12/30 506 10002 200 33-14-56.7015N 119-28-12.8759W 33-13-49.7278N 119-26-46.1905W RWY SNA 02L/20R 56 5701 150 33-40-04.0902N 117-52-25.7898W 33-40-53.9265N 117-51-54.2126W RWY SNA 02R/20L 56 2887 75 33-40-26.3802N 117-52-04.9704W 33-40-51.6108N 117-51-48.9845W RWY SBA 07/25 13 6052 150 34-25-38.9964N 119-51-16.7098W 34-25-40.5035N 119-50-04.4836W RWY SBA 15L/33R 13 4180 75 34-25-50.8102N 119-50-25.3281W 34-25-10.7491N 119-50-12.9814W RWY SBA 15R/33L 13 4184 100 34-25-49.9454N 119-50-29.5330W 34-25-09.8460N 119-50-17.1654W RWY SMO 03/21 177 4973 150 34-00-39.4354N 118-27-25.4272W 34-01-14.4762N 118-26-43.9649W RWY SZP 04/22 248 2713 60 34-20-41.8792N 119-03-55.6287W 34-20-56.3378N 119-03-28.3609W RWY TOA 11L/29R 103 5001 150 33-48-29.0133N 118-20-44.4066W 33-47-58.2439N 118-19-57.9996W RWY TOA 11R/29L 103 3000 75 33-48-18.9881N 118-20-38.8141W 33-48-00.5334N 118-20-10.9763W RWY TNP 08/26 1888 5531 75 34-08-03.6487N 115-57-12.3774W 34-08-03.9782N 115-56-06.5936W RWY TNP 17/35 1888 3797 50 34-07-57.8579N 115-56-52.8506W 34-07-20.2981N 115-56-52.9667W RWY NXP 10/28 2051 8015 150 34-18-01.0410N 116-10-27.7360W 34-17-30.9540N 116-08-59.3490W RWY CCB 06/24 1444 3863 75 34-06-34.9854N 117-41-36.0579W 34-06-48.5968N 117-40-53.1371W RWY VNY 16L/34R 802 4013 75 34-13-08.3874N 118-29-24.0130W 34-12-28.8190N 118-29-20.2745W RWY VNY 16R/34L 802 8001 150 34-13-08.0774N 118-29-28.4639W 34-11-49.1790N 118-29-21.0078W RWY VCV 03/21 2885 9138 150 34-34-57.7456N 117-23-15.9148W 34-36-02.1758N 117-21-59.2749W RWY VCV 17/35 2885 15050 150 34-37-17.9480N 117-23-12.4277W 34-34-49.1052N 117-23-10.9199W RWY L22 06/24 3224 4363 60 34-07-39.8200N 116-24-49.1400W 34-07-54.9200N 116-24-00.5100W ILS 20R ILS/DME ISNA 111.75 33-39-54.505N 117-52-31.862W 33-40-47.562N 117-52-02.260W 43 5.90 207.80 3.00 ILS 30 ILS ILGB 110.30 33-49-37.767N 118-09-45.695W 33-48-44.429N 118-08-45.513W 32 4.72 314.85 3.00 ILS 27 LOC/DME IUBR 110.90 32-44-14.789N 117-12-20.434W - - 23 5.00 286.07 - ILS 06 ILS ISBD 109.30 34-06-06.315N 117-12-47.634W 34-05-24.982N 117-14-49.338W 1087 3.33 70.35 3.00 ILS 24R LOC/GS INKX 111.15 32-51-49.454N 117-10-07.027W 32-52-16.202N 117-07-49.051W 468 3.06 255.34 3.00 ILS 08 ILS IBUR 109.50 34-11-52.638N 118-22-20.921W 34-11-55.273N 118-21-54.253W 725 5.00 90.93 3.00 ILS 26L ILS/DME ITWO 111.35 34-03-17.841N 117-37-10.295W 34-03-21.893N 117-35-10.971W 925 3.58 269.97 3.00 ILS 27R LOC/DME ISEE 110.50 32-49-47.509N 116-59-00.560W - - 351 6.00 282.13 - ILS 25 LOCALIZER IHHR 109.10 33-55-20.829N 118-20-36.102W - - 66 5.50 266.73 - ILS 29R ILS/DME ITOA 111.90 33-48-31.939N 118-20-48.823W 33-48-09.693N 118-20-08.605W 92 5.00 308.58 3.40 ILS 26R ILS/DME IONT 109.70 34-03-24.747N 117-37-34.626W 34-03-22.008N 117-35-10.975W 926 3.03 269.97 3.00 ILS 22L LOC/GS IEDW 110.10 34-53-29.500N 117-54-39.420W 34-54-47.490N 117-51-54.620W 2276 2.34 238.11 2.50 ILS 07 ILS/DME ISBA 110.30 34-25-40.852N 119-49-47.652W 34-25-43.203N 119-51-04.898W 10 5.37 88.55 3.00 ILS 25 ILS IOXR 108.70 34-12-03.262N 119-13-13.568W 34-12-00.200N 119-12-09.968W 41 6.00 270.53 3.00 ILS 20X LDA/DME IOJW 108.30 33-40-56.459N 117-51-47.638W - - 40 6.00 194.94 - ILS 30 LOC/GS INSI 109.70 33-14-57.071N 119-28-13.347W 33-13-58.378N 119-26-52.772W 498 4.00 312.73 3.00 ILS 09 ILS IRAL 110.90 33-56-59.460N 117-25-51.860W 33-57-15.321N 117-26-58.196W 760 6.00 103.11 3.00 ILS 25L ILS/DME ILAX 109.90 33-55-59.865N 118-25-20.868W 33-56-17.774N 118-23-10.214W 97 3.30 262.97 3.00 ILS 25R ILS/DME ICFN 111.10 33-56-08.130N 118-25-18.028W 33-56-17.872N 118-23-10.225W 98 3.39 262.97 3.00 ILS 17 LOC/GS IVCV 108.75 34-34-38.682N 117-23-10.813W 34-37-07.568N 117-23-18.303W 2815 3.00 179.52 3.00 ILS 24L ILS/DME IHQB 111.70 33-56-46.746N 118-26-22.248W 33-57-02.310N 118-24-18.510W 117 3.47 262.96 3.00 ILS 24R ILS/DME IOSS 108.50 33-56-53.165N 118-26-27.684W 33-57-02.408N 118-24-18.522W 117 3.36 262.96 3.00 ILS 08L ILS IAOD 109.70 34-03-24.818N 117-34-45.067W 34-03-21.205N 117-36-59.899W 936 3.28 89.97 3.00 ILS 28R ILS/DME IMYF 111.70 32-49-07.881N 117-08-47.220W 32-48-52.124N 117-08-14.070W 419 6.00 295.08 3.00 ILS 26L ILS IPOC 110.50 34-05-30.449N 117-47-31.718W 34-05-33.915N 117-46-39.946W 1004 6.00 273.22 3.76 ILS 26R ILS ICNO 111.50 33-58-32.453N 117-38-59.062W 33-58-29.489N 117-38-02.826W 631 6.00 269.40 3.00 ILS 21 ILS/DME IRRG 109.30 34-06-21.921N 119-08-13.996W 34-07-41.406N 119-06-37.359W 9 3.26 223.68 3.00 ILS 16R ILS IVNY 111.30 34-11-40.337N 118-29-20.159W 34-12-44.877N 118-29-29.247W 784 5.36 175.52 3.50 ILS 07L ILS/DME IIAS 111.10 33-56-24.759N 118-22-35.445W 33-56-08.850N 118-24-56.440W 122 3.07 82.97 3.00 ILS 07R ILS/DME IMKZ 109.90 33-56-15.785N 118-22-45.244W 33-55-59.925N 118-24-55.049W 118 3.30 82.97 3.00 ILS 32 ILS IRIV 110.10 33-54-06.520N 117-16-28.080W 33-51-58.770N 117-15-02.720W 1484 3.00 329.43 3.00 ILS 24 ILS/DME ICRQ 108.70 33-07-36.574N 117-17-20.164W 33-07-48.120N 117-16-33.127W 315 6.00 259.09 3.20 ILS 24 LOC/DME IFUL 108.90 33-52-14.921N 117-59-09.922W - - 99 6.00 256.93 - ILS 09 ILS/DME ISAN 111.55 32-43-47.602N 117-10-28.237W 32-44-10.760N 117-11-52.140W 16 4.69 106.07 3.10 ILS 06L ILS/DME IUWU 108.50 33-57-08.577N 118-23-57.197W 33-56-54.586N 118-25-39.825W 110 4.10 82.96 3.00 ILS 06R ILS/DME IGPE 111.70 33-57-02.407N 118-23-49.316W 33-56-53.313N 118-25-47.360W 108 3.66 82.96 3.00 ILS 25 ILS IPMD 110.70 34-37-48.786N 118-07-10.911W 34-38-01.256N 118-04-40.078W 2492 3.00 266.17 3.00 NAV UR NDB 34-11-53.812N 118-22-40.410W 730 253 - NAV CMA VOR/DME 34-12-45.082N 119-05-39.678W 63 115.80 105X NAV CPM NDB 33-53-20.622N 118-14-50.190W 97 378 - NAV DAG VORTAC 34-57-44.845N 116-34-41.399W 1760 113.20 079X NAV EDW VORTAC 34-58-56.500N 117-43-57.380W 2378 116.40 111X NAV NJK TACAN 32-49-54.390N 115-40-52.210W -49 111.00 047X NAV EMT NDB 34-05-17.932N 118-01-52.342W 305 359 - NAV FIM VORTAC 34-21-24.097N 118-52-52.648W 2200 112.50 072X NAV GMN VORTAC 34-48-14.503N 118-51-40.897W 4920 116.10 108X NAV HEC VORTAC 34-47-49.265N 116-27-46.519W 1853 112.70 074X NAV IPL VORTAC 32-44-55.920N 115-30-30.895W -18 115.90 106X NAV NRS TACAN 32-33-51.025N 117-06-35.103W 21 109.20 029X NAV JLI VORTAC 33-08-25.651N 116-35-09.365W 5560 114.00 087X NAV LHS VORTAC 34-40-58.704N 118-34-36.977W 5790 108.40 021X NAV GWF NDB 34-44-19.285N 118-13-00.433W 0 282 - NAV SLI VORTAC 33-46-59.873N 118-03-17.118W 22 115.70 104X NAV LAX VORTAC 33-55-59.335N 118-25-55.241W 185 113.60 083X NAV NFG TACAN 33-16-28.509N 117-23-10.985W 502 111.80 055X NAV OCN VORTAC 33-14-26.282N 117-25-03.795W 52 115.30 100X NAV PDZ VORTAC 33-55-06.013N 117-31-47.990W 1432 112.20 059X NAV NTD TACAN 34-07-23.820N 119-07-19.110W 7 110.60 043X NAV VTU VOR/DME 34-06-54.213N 119-02-58.170W 1560 108.20 019X NAV PAI NDB 34-15-35.009N 118-24-48.295W 0 370 - NAV PSP VORTAC 33-52-12.054N 116-25-47.216W 1600 115.50 102X NAV TRM VORTAC 33-37-41.145N 116-09-36.712W -87 116.20 109X NAV PMD VORTAC 34-37-53.034N 118-03-49.761W 2498 114.50 092X NAV POM VORTAC 34-04-42.199N 117-47-13.473W 1266 110.40 041X NAV HDF VOR 33-46-34.780N 117-11-07.160W 1414 113.40 - NAV RIV TACAN 33-54-23.280N 117-16-30.140W 1543 113.00 077X NAV RAL VOR 33-57-18.650N 117-26-59.380W 778 112.40 - NAV SB NDB 34-03-23.299N 117-21-58.011W 972 397 - NAV NUC TACAN 33-01-36.951N 118-34-46.556W 161 117.60 123X NAV NSD TACAN 32-52-47.630N 118-26-27.270W 2000 113.90 86X NAV NKX TACAN 32-52-11.099N 117-09-17.513W 430 109.60 033X NAV MZB VORTAC 32-46-55.934N 117-13-31.486W 12 117.80 125X NAV NZY TACAN 32-42-09.130N 117-12-58.430W 17 117.00 117X NAV PGY VORTAC 32-36-37.216N 116-58-44.685W 580 109.80 035X NAV NSI TACAN 33-14-06.271N 119-27-30.216W 522 110.20 039X NAV ELB VOR/DME 33-40-33.707N 117-43-51.901W 336 117.20 119X NAV RZS VORTAC 34-30-34.321N 119-46-15.570W 3598 114.90 096X NAV SXC VORTAC 33-22-30.201N 118-25-11.675W 2090 111.40 051X NAV SMO VOR/DME 34-00-36.882N 118-27-24.176W 114 110.80 045X NAV TNP VORTAC 34-06-44.044N 115-46-11.658W 1374 114.20 089X NAV VNY VOR/DME 34-13-24.464N 118-29-30.016W 812 113.10 078X NAV VCV VOR/DME 34-35-38.986N 117-23-23.990W 2855 109.05 27Y NAV MXL VOR/DME 32-37-33.000N 115-13-25.000W 0 115.00 097X NAV SQN VOR 30-30-00.000N 115-57-00.000W 0 113.30 - NAV TIJ VOR/DME 32-32-24.550N 116-57-13.150W 499 116.50 112X NAV UN NDB 32-32-00.000N 117-02-00.000W 0 381 - acm-6.0_20200416/objects/zones/usa/lasvegaswest.txt0000644000000000000000000003177213646045023020440 0ustar rootroot# Las Vegas west area scenery. # Created: 2020-04-16 # Latitude range: [35N, 40N[ # Longitude range: [120W, 115W[ # 2017-10-04 Checked against https://nfdc.faa.gov/xwiki/bin/view/NFDC/56DaySub-2017-03-02 # "56 Day NASR Subscription - Effective March 2, 2017". # ?????: TEAM1_LOC 35N 120W 000 031 # ?????: TEAM1_LOC 35N 120W 000 031 GROUND_COLOR #305030 RWY 0O2 15/33 922 3157 50 35-17-25.7305N 116-04-57.6284W 35-16-55.4871N 116-04-48.1234W RWY L45 16/34 378 4000 75 35-19-49.2388N 118-59-47.9637W 35-19-09.8542N 118-59-43.3854W RWY BFL 12L/30R 510 10849 150 35-26-46.8273N 119-04-16.5846W 35-25-30.5458N 119-02-44.3966W RWY BFL 12R/30L 510 7703 100 35-26-19.4810N 119-03-56.2709W 35-25-25.3119N 119-02-50.8302W RWY BIH 08/26 4124 5567 100 37-22-25.1389N 118-22-26.8872W 37-22-24.6629N 118-21-17.9344W RWY BIH 12/30 4124 7498 100 37-22-48.5093N 118-22-24.0154W 37-21-55.6498N 118-21-18.9141W RWY BIH 17/35 4124 5600 100 37-22-50.6424N 118-21-41.9001W 37-21-55.2910N 118-21-42.4951W RWY O57 16/34 6472 3854 60 38-16-11.8000N 119-13-21.9092W 38-15-33.7061N 119-13-21.7548W RWY L62 11/29 326 3260 50 35-21-23.0100N 119-29-01.8300W 35-21-01.8800N 119-28-32.0900W RWY L71 06/24 2454 6027 60 35-08-57.0641N 118-01-35.1130W 35-09-11.9351N 118-00-24.8444W RWY NID 03/21 2284 9993 200 35-40-32.3092N 117-42-30.2161W 35-41-45.4414N 117-41-08.7391W RWY NID 08/26 2284 7702 75 35-40-59.7852N 117-42-14.7286W 35-40-58.7498N 117-40-41.3712W RWY NID 14/32 2284 9014 200 35-41-55.5275N 117-41-35.5134W 35-40-35.3200N 117-40-47.8535W RWY CRO 13/31 197 3800 50 36-06-25.0700N 119-35-53.7700W 36-05-53.9400N 119-35-27.8100W RWY 24CL 14/32 205 6815 75 36-05-50.3600N 119-32-45.7000W 36-04-48.0700N 119-32-14.0200W RWY L06 15/33 -210 3065 70 36-27-52.2900N 116-52-53.0000W 36-27-23.4100N 116-52-41.6000W RWY L09 05/23 25 3260 65 36-36-04.1200N 117-09-49.1400W 36-36-23.5500N 117-09-17.2200W RWY DLO 14/32 316 5659 75 35-45-10.0912N 119-14-23.9508W 35-44-18.0000N 119-13-58.8510W RWY O63 13/31 344 2315 40 36-14-42.9500N 119-09-04.7000W 36-14-22.9000N 119-08-51.0600W RWY L73 16/34 635 3000 60 35-36-01.8300N 119-07-41.9500W 35-35-32.1500N 119-07-41.7100W RWY FCH 12/30 280 3627 75 36-44-06.0996N 119-49-31.2941W 36-43-45.1873N 119-48-55.0969W RWY FAT 11L/29R 336 9539 150 36-47-02.4054N 119-43-48.3081W 36-46-07.8210N 119-42-12.6879W RWY FAT 11R/29L 336 8008 150 36-46-59.0199N 119-43-56.7143W 36-46-13.2055N 119-42-36.4421W RWY E79 12/30 321 2473 50 36-50-32.8000N 119-52-21.1900W 36-50-16.4700N 119-51-58.5100W RWY HJO 14/32 240 5179 75 36-19-22.6844N 119-37-54.6517W 36-18-37.6677N 119-37-24.4841W RWY 2O7 05/23 3908 1498 30 36-48-58.6200N 118-12-27.3600W 36-49-04.1000N 118-12-10.2400W RWY 2O7 14/32 3908 3533 60 36-49-14.0200N 118-12-25.7300W 36-48-41.8100N 118-12-08.9000W RWY IYK 02/20 2457 6275 75 35-38-53.7600N 117-50-00.1300W 35-39-47.0200N 117-49-21.1200W RWY IYK 10/28 2457 4150 75 35-40-04.0200N 117-50-06.2800W 35-39-46.4100N 117-49-20.8200W RWY IYK 15/33 2457 7100 75 35-40-01.4200N 117-50-03.4700W 35-38-53.3400N 117-49-42.4600W RWY L05 17/35 2614 3500 50 35-43-58.8300N 118-25-09.2600W 35-43-24.3200N 118-25-12.6600W RWY O24 15/33 6802 3920 50 37-57-46.2981N 119-06-28.4440W 37-57-09.4200N 119-06-13.3964W RWY NLC 14L/32R 230 13502 200 36-21-50.9892N 119-57-38.5207W 36-19-49.0290N 119-56-31.3682W RWY NLC 14R/32L 230 13501 200 36-20-09.4824N 119-57-44.1802W 36-18-07.5226N 119-56-37.0586W RWY O26 13/31 3710 2391 90 36-35-31.7214N 118-03-25.0563W 36-35-12.6796N 118-03-07.6953W RWY O26 16/34 3710 3991 60 36-35-37.3550N 118-02-47.5400W 36-34-57.9250N 118-02-45.8104W RWY L84 15/33 274 3020 60 35-37-43.7600N 119-41-14.3200W 35-37-14.6700N 119-41-05.9600W RWY MMH 09/27 7135 7000 100 37-37-37.8006N 118-51-00.5828W 37-37-15.3293N 118-49-38.3194W RWY M45 17/35 5872 4443 50 38-44-27.0296N 119-45-59.5314W 38-43-43.2224N 119-46-03.1882W RWY MHV 04/22 2801 4747 60 35-03-35.0422N 118-09-51.4751W 35-04-04.0852N 118-09-06.6188W RWY MHV 08/26 2801 7049 100 35-03-33.1835N 118-09-57.8640W 35-03-32.9995N 118-08-33.0874W RWY MHV 12/30 2801 12503 200 35-04-08.9250N 118-09-37.5380W 35-02-41.2770N 118-07-51.4858W RWY CN37 08/26 4074 2673 100 35-23-03.6652N 118-13-37.2373W 35-23-02.4676N 118-13-04.9947W RWY PTV 12/30 443 5960 150 36-02-07.4635N 119-04-11.2836W 36-01-25.5877N 119-03-20.2208W RWY O32 15/33 386 3300 60 36-40-31.5739N 119-27-07.8716W 36-39-59.6541N 119-26-59.4497W RWY 0Q4 10/28 305 2206 50 36-34-56.8740N 119-39-36.9576W 36-34-46.3296N 119-39-13.2840W RWY MIT 08/26 425 3672 60 35-30-38.0550N 119-11-56.8660W 35-30-38.0250N 119-11-12.4530W RWY MIT 12/30 425 4501 100 35-30-38.4368N 119-12-03.6846W 35-30-07.8764N 119-11-24.1042W RWY MIT 17/35 425 2970 100 35-30-33.5289N 119-11-09.4853W 35-30-04.1567N 119-11-09.5126W RWY L61 15/33 1568 2380 30 35-58-18.5300N 116-16-12.2200W 35-57-55.4400N 116-16-06.5400W RWY TVL 18/36 6269 8541 100 38-54-19.1587N 119-59-31.1490W 38-52-56.8960N 119-59-55.2858W RWY 1Q1 13/31 426 2000 50 36-09-53.2800N 119-03-08.2000W 36-09-35.9700N 119-02-56.4000W RWY L17 07/25 858 3283 60 35-08-27.0139N 119-26-35.6895W 35-08-32.9242N 119-25-56.7607W RWY TSP 11/29 4001 4040 75 35-08-17.2700N 118-26-41.5500W 35-07-54.6900N 118-26-01.4100W RWY L72 17/35 1718 5910 60 35-49-14.4270N 117-19-31.3494W 35-48-16.6986N 117-19-42.4548W RWY TLR 13/31 265 3901 75 36-09-39.8895N 119-19-48.6126W 36-09-07.5495N 119-19-22.6724W RWY VIS 12/30 295 6562 150 36-19-29.9545N 119-24-02.7401W 36-18-44.2320N 119-23-05.8527W RWY D86 13/31 313 3012 60 36-27-04.3800N 119-19-18.4800W 36-26-40.5700N 119-18-56.3100W RWY L19 12/30 312 3380 60 35-37-23.4058N 119-21-27.8155W 35-36-59.6318N 119-20-59.0324W RWY L92 14/32 3758 4360 60 37-22-06.6500N 115-11-58.0000W 37-21-30.0000N 115-11-29.5700W RWY TMT 18/36 5735 6000 75 39-28-32.3087N 117-11-37.2713W 39-27-36.8821N 117-12-04.3909W RWY BTY 16/34 3169 5615 60 36-52-07.8308N 116-47-11.0568W 36-51-12.3242N 116-47-11.0102W RWY CXP 09/27 4705 6101 75 39-11-39.2132N 119-44-34.9560W 39-11-25.3695N 119-43-19.5505W RWY 2Q5 06/24 4939 815 40 39-12-03.6888N 119-41-04.8844W 39-12-07.6755N 119-40-55.8898W RWY A34 05/23 4414 5343 75 39-14-07.1605N 119-33-50.3889W 39-14-29.4999N 119-32-48.8750W RWY 01U 03/21 5133 2700 75 38-50-56.3620N 115-38-09.1474W 38-51-16.2119N 115-37-46.3218W RWY 01U 15/33 5133 3400 80 38-51-32.5055N 115-38-14.8229W 38-50-59.6109N 115-38-05.9690W RWY 05U 18/36 5958 7300 60 39-36-48.9124N 116-00-04.1142W 39-35-38.1050N 116-00-21.8511W RWY NFL 07/25 3935 7003 152 39-24-47.1860N 118-42-57.1310W 39-24-49.7960N 118-41-27.9850W RWY NFL 13L/31R 3935 11078 200 39-25-50.0300N 118-42-18.4990W 39-24-20.1630N 118-40-57.9170W RWY NFL 13R/31L 3935 14004 200 39-26-08.1210N 118-42-50.2520W 39-24-14.5190N 118-41-08.3760W RWY FLX 03/21 3966 5703 75 39-29-39.6740N 118-45-23.7041W 39-30-17.0314N 118-44-29.2487W RWY FLX 13/31 3966 4207 100 39-30-11.5795N 118-45-09.2893W 39-29-37.2652N 118-44-38.9907W RWY N58 05/23 4346 2750 30 39-33-37.1645N 119-15-04.3192W 39-33-48.4341N 119-14-32.3732W RWY N58 15/33 4346 3974 40 39-33-48.8064N 119-14-30.7844W 39-33-11.2748N 119-14-15.8829W RWY 0L4 18/36 4684 6100 80 37-29-59.8490N 117-11-08.0172W 37-29-01.7741N 117-11-28.4951W RWY HTH 10/28 4230 6000 100 38-32-51.2162N 118-38-33.6417W 38-32-25.2151N 118-37-25.7845W RWY HTH 15/33 4230 3250 130 38-33-05.4265N 118-37-55.5779W 38-32-34.1233N 118-37-46.4181W RWY INS 08/26 3134 9002 150 36-35-04.0392N 115-41-44.0402W 36-35-00.4204N 115-39-53.7785W RWY INS 13/31 3134 5476 100 36-35-47.3892N 115-40-40.3220W 36-35-02.5867N 115-40-02.6339W RWY 0L7 02L/20R 2835 4600 75 35-45-48.1000N 115-20-02.1000W 35-46-26.6800N 115-19-32.5200W RWY 0L7 02R/20L 2835 3700 60 35-45-48.2000N 115-19-57.7000W 35-46-19.2300N 115-19-33.9100W RWY N15 07/25 6075 3700 80 39-12-08.7100N 117-04-42.5600W 39-12-09.0100N 117-03-55.5600W RWY N15 16/34 6075 3072 60 39-12-25.6400N 117-03-54.0500W 39-11-55.3200N 117-03-56.0300W RWY LSV 03L/21R 1869 10120 200 36-13-36.1000N 115-02-48.4900W 36-14-51.3000N 115-01-27.0000W RWY LSV 03R/21L 1869 10051 150 36-13-29.5800N 115-02-39.3200W 36-14-44.2600N 115-01-18.3800W RWY VGT 07/25 2205 5005 75 36-12-47.8622N 115-12-12.1453W 36-12-49.0762N 115-11-11.0945W RWY VGT 12L/30R 2205 4203 75 36-12-44.7219N 115-11-47.1131W 36-12-15.6816N 115-11-10.4357W RWY VGT 12R/30L 2205 5001 75 36-12-52.8379N 115-12-09.5951W 36-12-18.2877N 115-11-25.9509W RWY LAS 01L/19R 2181 8988 150 36-04-31.1694N 115-10-13.3156W 36-05-51.7657N 115-09-27.1861W RWY LAS 01R/19L 2181 9771 150 36-04-27.2649N 115-10-02.9559W 36-05-54.8802N 115-09-12.8039W RWY LAS 07L/25R 2181 14512 150 36-04-34.9216N 115-10-12.6755W 36-04-35.0697N 115-07-15.9271W RWY LAS 07R/25L 2181 10525 150 36-04-25.0625N 115-09-41.1613W 36-04-25.1662N 115-07-32.9677W RWY HND 17L/35R 2492 5001 75 35-58-51.1490N 115-07-58.6133W 35-58-01.7103N 115-07-59.2284W RWY HND 17R/35L 2492 6501 100 35-58-51.2177N 115-08-07.1314W 35-57-46.9483N 115-08-07.9226W RWY NV65 02/20 3314 7515 100 36-36-41.0000N 116-02-22.0000W 36-37-42.6000N 116-01-30.4500W RWY 3Q0 13/31 4557 4600 165 38-23-07.5912N 118-06-01.9074W 38-22-27.4702N 118-05-34.6898W RWY MEV 12/30 4731 5299 75 39-00-19.7592N 119-45-30.7566W 38-59-42.8668N 119-44-43.1385W RWY MEV 16/34 4731 7399 100 39-00-41.3162N 119-45-07.1268W 38-59-28.2010N 119-45-06.7818W RWY RNO 07/25 4415 6102 150 39-29-46.6299N 119-46-43.8220W 39-29-46.3739N 119-45-25.9978W RWY RNO 16L/34R 4415 9000 150 39-30-49.8258N 119-46-00.2660W 39-29-20.8949N 119-46-00.4971W RWY RNO 16R/34L 4415 11001 150 39-30-49.8381N 119-46-09.1937W 39-29-01.1337N 119-46-09.4750W RWY N86 17/35 4620 3418 60 39-40-33.1000N 119-43-29.1000W 39-39-59.4000N 119-43-32.1000W RWY RTS 08/26 5050 7608 150 39-39-51.6446N 119-53-31.8784W 39-39-43.9105N 119-51-55.1399W RWY RTS 14/32 5050 9000 150 39-41-00.1962N 119-52-53.7370W 39-39-40.5340N 119-52-02.5510W RWY 3L2 12/30 2599 3300 105 35-47-45.9576N 115-37-49.5311W 35-47-23.2850N 115-37-20.7057W RWY SPZ 06/24 4265 6001 75 39-24-00.3690N 119-15-40.0038W 39-24-21.5321N 119-14-28.6082W RWY TPH 11/29 5430 6195 50 38-04-03.1300N 117-05-33.0600W 38-03-28.0400N 117-04-29.5800W RWY TPH 15/33 5430 7158 80 38-04-03.1200N 117-05-33.7900W 38-02-54.7700N 117-05-10.6100W RWY TNX 14/32 5550 12001 150 37-48-50.6052N 116-47-19.5779W 37-47-01.2414N 116-46-21.7147W RWY O43 01/19 4382 5814 75 38-59-54.4620N 119-09-41.6854W 39-00-44.4516N 119-09-05.3823W ILS 30R ILS/DME IBFL 111.90 35-26-53.948N 119-04-25.194W 35-25-58.298N 119-03-24.720W 479 4.74 315.44 3.00 ILS 01L ILS/DME ICUA 110.10 36-06-00.851N 115-09-21.987W 36-04-49.142N 115-10-06.519W 2159 4.26 24.82 3.40 ILS 25R ILS/DME ILAS 110.30 36-04-34.911N 115-10-19.180W 36-04-32.081N 115-07-46.674W 2047 4.00 269.94 3.00 ILS 29R ILS/DME IFAT 111.30 36-47-08.282N 119-43-58.598W 36-46-18.838N 119-42-23.481W 332 3.91 305.48 3.00 ILS 25L ILS/DME IRLE 111.75 36-04-25.052N 115-09-53.341W 36-04-21.996N 115-07-46.661W 2051 3.48 269.94 3.00 ILS 30 ILS IVIS 108.50 36-19-32.057N 119-24-05.354W 36-18-48.502N 119-23-18.052W 293 5.00 314.93 3.00 ILS 34L ILS/DME IAGY 109.90 39-30-59.983N 119-46-09.165W 39-29-16.604N 119-46-05.345W 4403 3.63 0.12 3.54 ILS 14 LOC/GS IRVP 108.30 37-46-43.380N 116-46-12.266W 37-48-42.486N 116-47-22.045W 5482 3.00 157.32 2.75 ILS 17 LDA/DME IBIH 109.10 37-22-27.752N 118-21-11.874W - - 4100 6.00 155.72 - ILS 12L ILS/DME IHWG 110.70 36-12-12.221N 115-11-06.057W 36-12-39.989N 115-11-35.728W 2178 6.00 134.45 3.20 ILS 18 LDA/DME ITVL 108.90 38-54-36.655N 119-59-22.128W - - 6323 6.00 187.42 - ILS 11L LOC/DME IRPW 111.30 36-46-02.541N 119-42-03.438W - - 347 3.95 125.48 - ILS 21L LOC/GS IDIQ 109.10 36-13-20.020N 115-02-49.670W 36-14-32.670N 115-01-22.830W 1856 3.54 221.15 3.00 ILS 16R ILS/DME IRNO 110.90 39-28-49.534N 119-46-09.505W 39-30-28.096N 119-46-05.666W 4408 3.59 180.11 3.10 ILS 32 ILS/DME IRTS 111.90 39-41-09.490N 119-52-59.710W 39-39-59.740N 119-52-09.040W 5045 4.45 333.68 3.00 ILS 32 LOC/GS IUVV 111.70 37-49-02.077N 116-47-25.658W 37-47-04.063N 116-46-29.966W 5555 3.00 337.30 2.75 NAV AVE VOR/DME 35-38-49.112N 119-58-42.980W 710 117.10 118X NAV EHF VORTAC 35-29-04.397N 119-05-50.257W 549 115.40 101X NAV BIH VOR/DME 37-22-37.020N 118-21-59.495W 4117 109.60 033X NAV NID TACAN 35-41-16.503N 117-41-25.788W 2228 111.60 053X NAV COR NDB 36-03-57.800N 119-31-51.400W 203 205 - NAV FLW VOR/DME 35-05-35.104N 119-51-56.083W 3870 117.50 122X NAV FCH NDB 36-43-26.191N 119-50-01.207W 275 344 - NAV CZQ VORTAC 36-53-03.560N 119-48-54.523W 360 112.90 076X NAV FRA VORTAC 37-06-15.915N 119-35-43.604W 2380 115.60 103X NAV GFS VORTAC 35-07-52.123N 115-10-35.185W 4000 114.40 091X NAV NLC TACAN 36-20-38.823N 119-57-58.801W 228 113.30 080X NAV TTE VOR/DME 35-54-46.984N 119-01-14.914W 580 109.20 029X NAV VIS VOR/DME 36-22-02.350N 119-28-55.785W 259 109.40 031X NAV BTY VORTAC 36-48-02.149N 116-44-51.507W 2928 114.70 094X NAV OAL VORTAC 38-00-11.741N 117-46-13.605W 4800 117.70 124X NAV NFL TACAN 39-25-00.870N 118-42-18.270W 3929 113.50 082X NAV HZN VORTAC 39-30-59.054N 118-59-51.679W 4085 114.10 088X NAV INS TACAN 36-35-05.991N 115-40-13.193W 3102 114.00 087X NAV LAS VORTAC 36-04-46.931N 115-09-35.272W 2136 116.90 116X NAV MVA VORTAC 38-33-55.078N 118-01-58.272W 7860 115.10 098X NAV FMG VORTAC 39-31-52.598N 119-39-21.873W 5950 117.90 126X NAV TQQ VORTAC 37-47-25.438N 116-46-45.357W 5542 113.00 77X NAV TPH VORTAC 38-01-50.321N 117-02-00.627W 5344 117.20 119X acm-6.0_20200416/objects/zones/usa/dallas.txt0000644000000000000000000011344013646045023017161 0ustar rootroot# Dallas area scenery. # Created: 2020-04-16 # Latitude range: [30N, 35N[ # Longitude range: [100W, 95W[ # 2017-10-04 Checked against https://nfdc.faa.gov/xwiki/bin/view/NFDC/56DaySub-2017-03-02 # "56 Day NASR Subscription - Effective March 2, 2017". TEAM1_LOC 32-58-40.4N 096-50-25.75W 645 160 TEAM2_LOC 34-17-36.089N 097-01-25.366W 762.0 040 GROUND_COLOR #305030 # Addison: FEATURE ../../features/tower.obv 32-58-04.800N 096-50-16.800W 644 0 FEATURE ../../features/man.obv 32-58-29.000N 096-50-20.000W 644 90 RWY ADH 13/31 1016 2717 50 34-48-20.8240N 096-40-21.4487W 34-48-01.7850N 096-39-58.4550W RWY ADH 17/35 1016 6203 100 34-48-47.7850N 096-40-19.1120W 34-47-46.4390N 096-40-19.1040W RWY AXS 17/35 1433 5501 75 34-42-22.8830N 099-20-18.5833W 34-41-28.4709N 099-20-18.4105W RWY LTS 17L/35R 1382 9001 150 34-40-56.9400N 099-15-34.3800W 34-39-27.9100N 099-15-34.3100W RWY LTS 17R/35L 1382 13440 150 34-40-56.9200N 099-16-25.7700W 34-38-43.9720N 099-16-25.7160W RWY 80F 17/35 577 3298 60 34-11-49.6765N 095-38-59.5751W 34-11-17.0542N 095-38-59.4473W RWY ADM 13/31 777 9002 150 34-18-53.0881N 097-01-45.3384W 34-17-49.6766N 097-00-30.0162W RWY ADM 17/35 777 5350 100 34-18-31.6639N 097-01-24.6678W 34-17-38.7461N 097-01-25.1342W RWY 1F0 17/35 845 5014 75 34-09-13.8813N 097-07-21.9810W 34-08-24.2890N 097-07-21.1191W RWY AQR 18/36 590 3015 40 34-24-08.8100N 096-08-50.7400W 34-23-39.2300N 096-08-55.2900W RWY 37K 18/36 690 4400 75 33-55-54.9500N 097-17-42.6600W 33-55-11.9900N 097-17-51.0500W RWY 92F 17/35 1135 3400 60 34-22-24.6771N 098-40-55.7556W 34-21-51.0366N 098-40-55.7083W RWY DUC 17/35 1114 6326 100 34-28-48.0268N 097-57-35.9834W 34-27-45.4634N 097-57-35.0610W RWY DUA 17/35 699 5001 100 33-56-56.5522N 096-23-41.9862W 33-56-07.0838N 096-23-42.3239W RWY FSI 17/35 1189 5001 150 34-39-24.0908N 098-24-07.7600W 34-38-34.6202N 098-24-07.8958W RWY FDR 03/21 1258 4812 60 34-20-46.9644N 098-59-18.3817W 34-21-20.5946N 098-58-37.7712W RWY FDR 12/30 1258 4578 75 34-21-30.0278N 098-59-16.3717W 34-20-57.9846N 098-58-37.7895W RWY FDR 17/35 1258 6099 150 34-21-37.9970N 098-59-21.6106W 34-20-37.6707N 098-59-21.6656W RWY 1O1 08/26 1128 1540 75 34-14-36.7500N 098-44-40.2638W 34-14-36.7500N 098-44-21.9200W RWY 1O1 17/35 1128 3100 75 34-14-37.1463N 098-44-18.9334W 34-14-06.4827N 098-44-19.3343W RWY F32 17/35 960 3013 50 34-15-32.5000N 097-28-22.4000W 34-15-02.7000N 097-28-22.4000W RWY HBR 03/21 1563 2975 60 34-59-04.1300N 099-03-14.6400W 34-59-24.8800N 099-02-49.2700W RWY HBR 12/30 1563 5295 150 34-59-59.3472N 099-03-21.6962W 34-59-22.1457N 099-02-36.9093W RWY HBR 17/35 1563 5507 100 34-59-55.8994N 099-03-15.7724W 34-59-01.4397N 099-03-16.0394W RWY O35 17/35 1659 3008 60 34-42-33.9747N 099-54-30.7655W 34-42-04.2231N 099-54-30.9010W RWY HHW 17/35 572 4007 75 34-02-20.9323N 095-32-31.4760W 34-01-41.2913N 095-32-31.3654W RWY F31 18/36 693 3000 50 33-59-42.5938N 096-38-31.9768W 33-59-13.0608N 096-38-35.5744W RWY LAW 17/35 1110 8599 150 34-34-42.7880N 098-25-01.7490W 34-33-17.8580N 098-24-56.2250W RWY 1K2 01/19 968 3010 60 34-50-43.6500N 097-35-11.7500W 34-51-12.4000N 097-35-02.3500W RWY MLC 02/20 771 5602 100 34-52-30.6576N 095-47-12.2129W 34-53-22.6038N 095-46-48.8118W RWY 1F4 18/36 890 3005 60 34-08-40.2050N 096-48-41.3480W 34-08-10.6680N 096-48-45.3340W RWY 2K4 17/35 1644 4199 75 34-53-54.1708N 099-31-41.5188W 34-53-12.6461N 099-31-41.5993W RWY 2OK1 18/36 801 3830 40 34-11-51.2340N 096-31-07.1688W 34-11-13.3440N 096-31-07.1688W RWY O14 17/35 1200 2725 60 34-53-38.8000N 097-59-55.2500W 34-53-12.0000N 097-59-51.7500W RWY F09 17/35 1346 2000 50 34-31-11.8600N 099-26-01.8200W 34-30-52.0768N 099-26-01.8200W RWY 1F1 14/32 817 2500 48 34-04-40.2700N 097-06-30.7600W 34-04-18.6900N 097-06-16.2500W RWY PVJ 17/35 971 5001 100 34-42-52.2918N 097-13-26.7255W 34-42-02.8293N 097-13-27.1942W RWY 3O3 17/35 1143 3003 60 34-59-14.8310N 097-22-59.4010W 34-58-45.2870N 097-22-55.5950W RWY 4O1 17/35 1325 2125 30 34-37-50.3118N 099-00-50.6158W 34-37-29.2896N 099-00-50.2483W RWY 6F1 01/19 687 3300 60 34-42-12.5000N 095-04-31.9000W 34-42-43.4530N 095-04-19.3570W RWY 1O8 17/35 1248 3062 50 34-27-46.1840N 099-10-16.8220W 34-27-15.9010N 099-10-16.8010W RWY 0F9 17/35 647 3100 60 34-12-09.8700N 096-40-28.1700W 34-11-39.2200N 096-40-28.2000W RWY 3O5 16/34 1058 2900 50 34-22-23.2100N 098-24-24.2900W 34-21-54.6900N 098-24-20.5500W RWY H05 17/35 670 3000 60 34-55-27.5900N 095-23-38.1100W 34-54-57.9000N 095-23-37.9900W RWY 3R9 16/34 909 3930 70 30-21-46.0451N 097-59-44.4491W 30-21-07.8900N 097-59-35.7200W RWY 35TX 16/34 1750 1700 75 32-29-12.6000N 099-49-35.7000W 32-28-56.1500N 099-49-31.5000W RWY DYS 16/34 1790 13500 300 32-26-20.2400N 099-51-31.7900W 32-24-09.2000N 099-51-01.3400W RWY ABI 04/22 1791 3679 100 32-25-10.5631N 099-41-41.3110W 32-25-32.8373N 099-41-07.3878W RWY ABI 17L/35R 1791 7198 150 32-24-30.7115N 099-40-29.2135W 32-23-19.4925N 099-40-28.8583W RWY ABI 17R/35L 1791 7203 150 32-25-41.1041N 099-41-05.7103W 32-24-29.8343N 099-41-05.3577W RWY T23 17/35 1415 5000 75 32-43-41.6920N 099-16-04.1349W 32-42-52.2405N 099-16-02.4479W RWY 6XS2 02/20 700 1650 80 32-20-35.3000N 097-11-58.9000W 32-20-50.3500N 097-11-51.5000W RWY 6XS2 14/32 700 2300 90 32-20-58.7000N 097-12-01.9000W 32-20-39.5500N 097-11-47.4000W RWY 88XA 18/36 577 2100 45 33-20-25.2000N 096-28-48.8000W 33-20-04.4000N 096-28-48.8000W RWY GKY 16/34 628 6080 100 32-40-19.3610N 097-05-46.7890W 32-39-20.5131N 097-05-32.0325W RWY F44 17/35 444 3988 60 32-10-09.6288N 095-49-42.1646W 32-09-30.1649N 095-49-42.0139W RWY TX25 17/35 391 4850 60 31-59-45.1400N 095-57-06.2300W 31-58-57.3400N 095-57-01.1500W RWY AUS 17L/35R 542 9000 150 30-12-13.7882N 097-39-28.4087W 30-10-44.7277N 097-39-26.0760W RWY AUS 17R/35L 542 12250 150 30-12-49.0181N 097-40-45.7132W 30-10-47.7956N 097-40-42.5089W RWY EDC 13/31 620 6025 100 30-24-12.9800N 097-34-24.4500W 30-23-33.5200N 097-33-32.8600W RWY EDC 16/34 620 1550 25 30-23-49.5800N 097-34-02.5600W 30-23-34.6862N 097-33-58.2848W RWY E30 17/35 1739 3909 60 31-40-47.4814N 099-58-37.0498W 31-40-08.8029N 099-58-37.2515W RWY 18TE 08/26 390 5093 45 32-35-07.0940N 095-04-19.8870W 32-35-06.3040N 095-03-20.3680W RWY F00 17/35 618 4000 75 33-37-06.9000N 096-10-44.8800W 33-36-27.3450N 096-10-46.2500W RWY 0F2 17/35 1101 3603 60 33-36-23.7123N 097-46-34.1336W 33-35-48.2448N 097-46-29.9469W RWY BBD 08/26 1827 3520 110 31-10-47.9695N 099-19-43.0393W 31-10-45.9007N 099-19-02.5904W RWY BBD 17/35 1827 4605 75 31-11-07.0766N 099-19-28.6068W 31-10-21.5090N 099-19-28.7417W RWY BKD 04/22 1284 2398 50 32-43-00.1817N 098-53-40.4668W 32-43-17.0635N 098-53-20.7427W RWY BKD 13/31 1284 2401 50 32-43-14.2128N 098-53-43.8027W 32-42-57.5335N 098-53-23.8037W RWY BKD 17/35 1284 4997 100 32-43-32.4803N 098-53-27.5774W 32-42-43.0385N 098-53-27.1983W RWY 9XS9 15/33 275 1334 75 30-16-39.0000N 096-26-31.1500W 30-16-26.3400N 096-26-26.8200W RWY 11R 16/34 318 6003 75 30-13-40.2000N 096-22-33.0100W 30-12-41.4636N 096-22-22.6900W RWY XBP 18/36 864 4004 60 33-10-51.0030N 097-49-41.7339W 33-10-11.4037N 097-49-42.7200W RWY TX40 16/34 465 2600 40 32-15-25.1000N 095-39-23.3500W 32-15-00.1000N 095-39-16.2000W RWY BWD 13/31 1387 4608 101 31-47-50.3995N 098-57-49.1183W 31-47-18.5515N 098-57-10.9107W RWY BWD 17/35 1387 5599 100 31-48-06.7884N 098-57-18.2830W 31-47-11.3902N 098-57-17.5573W RWY CFD 15/33 367 4000 75 30-43-13.8970N 096-20-03.7420W 30-42-39.0560N 096-19-41.9780W RWY BMQ 01/19 1284 5000 75 30-43-56.3742N 098-14-26.9586W 30-44-43.9076N 098-14-11.0340W RWY 2TA0 01/19 1417 1455 65 30-50-36.0500N 098-16-25.9700W 30-50-49.1400N 098-16-19.0100W RWY 7F3 13/31 542 4000 150 33-02-27.1500N 096-14-44.0030W 33-01-58.6390N 096-14-11.4180W RWY 7F3 18/36 542 4000 75 33-02-27.6540N 096-14-42.4890W 33-01-48.0830N 096-14-43.3860W RWY RWV 15/33 391 3252 50 30-31-09.9640N 096-42-23.3346W 30-30-41.4506N 096-42-06.0837W RWY T35 16/34 402 3200 50 30-52-59.8100N 096-58-25.0900W 30-52-29.4400N 096-58-14.6600W RWY 1TA7 13/31 518 2500 40 32-37-05.7500N 095-52-15.5000W 32-36-48.2500N 095-51-54.8500W RWY 40XS 15/33 897 3000 30 30-31-17.4500N 097-46-56.7600W 30-30-49.5200N 097-46-45.1300W RWY T80 17/35 750 1580 80 33-22-43.2900N 096-43-44.1400W 33-22-27.6600N 096-43-44.2000W RWY 9S1 18/36 790 2662 100 33-22-18.9600N 096-45-16.7100W 33-21-52.6300N 096-45-17.0900W RWY 3T8 15/33 660 2450 60 31-40-53.5605N 097-21-51.8419W 31-40-32.1284N 097-21-38.5708W RWY 3F2 17/35 1621 3700 60 32-25-12.3760N 098-59-48.5615W 32-24-35.7559N 098-59-48.6697W RWY GZN 18/36 1711 6536 100 32-22-29.3615N 099-01-24.8666W 32-21-24.6983N 099-01-25.6353W RWY LBR 17/35 440 3000 50 33-35-48.3500N 095-03-51.2100W 33-35-18.6600N 095-03-50.6500W RWY CPT 15/33 854 5697 100 32-21-39.8723N 097-26-13.2781W 32-20-47.1779N 097-25-49.6998W RWY 6R3 16/34 150 4998 75 30-21-46.6632N 095-00-37.8091W 30-20-59.6829N 095-00-19.9540W RWY 06TE 09/27 132 3275 50 30-18-47.0000N 095-01-56.9000W 30-18-46.3000N 095-01-19.5500W RWY 7F7 14/32 760 3000 50 31-49-14.3000N 097-34-19.6000W 31-48-49.0500N 097-34-01.3000W RWY COM 15/33 1697 4506 75 31-50-48.3459N 099-24-23.9754W 31-50-07.8893N 099-24-02.0254W RWY CLL 04/22 321 5150 150 30-35-07.0682N 096-22-23.1323W 30-35-40.0055N 096-21-38.1734W RWY CLL 10/28 321 5158 150 30-35-29.2948N 096-22-22.0594W 30-35-12.8558N 096-21-26.1882W RWY CLL 16/34 321 7000 146 30-35-47.9019N 096-21-46.2765W 30-34-39.9213N 096-21-30.8334W RWY MKN 17/35 1387 4497 75 31-55-35.3437N 098-35-57.7337W 31-54-50.8576N 098-35-56.5207W RWY 2F7 18/36 516 3907 60 33-17-53.6465N 095-53-46.0082W 33-17-15.0312N 095-53-48.1496W RWY 34XS 18/36 225 900 50 30-23-31.4000N 095-32-22.9000W 30-23-22.5000N 095-32-23.3000W RWY CRS 02/20 449 3200 75 32-01-29.6801N 096-24-23.3339W 32-01-59.0400N 096-24-09.4100W RWY CRS 14/32 449 5004 75 32-01-59.2036N 096-24-09.5613W 32-01-18.6056N 096-23-36.2812W RWY DKR 02/20 348 4000 75 31-18-06.6433N 095-24-22.2519W 31-18-43.4668N 095-24-05.3458W RWY 1F7 13/31 510 2630 30 32-48-55.8625N 096-21-18.0952W 32-48-37.2578N 096-20-56.5391W RWY RBD 13/31 660 6451 100 32-41-14.3558N 096-52-35.1540W 32-40-29.1559N 096-51-41.8605W RWY RBD 17/35 660 3800 150 32-41-08.8827N 096-52-00.4538W 32-40-31.2830N 096-52-00.5507W RWY ADS 15/33 645 7203 100 32-58-40.2276N 096-50-25.8484W 32-57-33.3629N 096-49-56.6190W RWY TKI 18/36 589 7002 150 33-11-12.0500N 096-35-18.0400W 33-10-02.8200N 096-35-21.0800W RWY DFW 13L/31R 607 9000 200 32-54-45.1950N 097-01-17.3210W 32-53-41.9330N 097-00-03.0390W RWY DFW 13R/31L 607 9301 150 32-54-34.4720N 097-04-59.2780W 32-53-24.9700N 097-03-47.7940W RWY DFW 17C/35C 607 13401 150 32-54-56.5480N 097-01-33.4940W 32-52-43.9620N 097-01-34.2180W RWY DFW 17L/35R 607 8500 150 32-53-53.9540N 097-00-35.2040W 32-52-29.8540N 097-00-35.6710W RWY DFW 17R/35L 607 13401 200 32-54-56.6000N 097-01-47.5800W 32-52-44.0180N 097-01-48.2920W RWY DFW 18L/36R 607 13400 200 32-54-56.8770N 097-03-02.6484W 32-52-44.2980N 097-03-03.3340W RWY DFW 18R/36L 607 13400 150 32-54-56.9330N 097-03-16.7108W 32-52-44.3500N 097-03-17.4010W RWY DAL 13L/31R 487 7752 150 32-51-26.1859N 096-51-24.4828W 32-50-31.3553N 096-50-20.9479W RWY DAL 13R/31L 487 8800 150 32-51-04.7418N 096-51-48.4244W 32-50-02.5073N 096-50-36.2975W RWY DAL 18/36 487 6147 150 32-51-31.1849N 096-51-11.5861W 32-50-30.6473N 096-51-18.5243W RWY LUD 17/35 1047 4200 60 33-15-35.8642N 097-34-53.0081W 33-14-54.6700N 097-34-46.5092W RWY 09T 17/35 931 1600 40 33-17-00.6690N 097-29-48.2210W 33-16-44.8400N 097-29-47.9710W RWY 76T 17/35 888 3730 170 33-16-27.4685N 097-27-06.7557W 33-15-50.5564N 097-27-06.6562W RWY 58T 13/31 883 3000 60 33-10-07.5259N 097-29-00.7655W 33-09-47.8177N 097-28-34.3655W RWY DTO 18/36 642 7002 150 33-12-42.1900N 097-11-51.8400W 33-11-32.9260N 097-11-53.3739W RWY 6TS3 17/35 855 3200 100 33-32-26.4611N 096-40-49.5780W 33-31-54.8243N 096-40-49.4251W RWY 17XS 01/19 1422 6295 80 32-10-10.7210N 098-26-18.8480W 32-11-09.1730N 098-25-53.5120W RWY ETN 17/35 1468 5000 60 32-25-18.3300N 098-48-33.9900W 32-24-28.8757N 098-48-35.8455W RWY F41 15/33 500 3999 50 32-20-05.6790N 096-39-57.4390W 32-19-28.1570N 096-39-42.6412W RWY TX94 08/26 882 2500 100 33-27-10.0600N 097-16-46.8300W 33-27-09.2600N 097-16-17.3400W RWY TE39 17/35 887 2000 75 33-26-42.0600N 097-16-21.2000W 33-26-22.3000N 097-16-19.9100W RWY TX6 16/34 597 1264 60 33-05-40.6000N 096-23-26.2000W 33-05-28.6000N 096-23-22.0000W RWY GRK 15/33 1015 10000 200 31-04-47.7210N 097-50-06.2815W 31-03-16.3957N 097-49-22.0050W RWY HLR 16/34 924 3701 144 31-08-37.0190N 097-42-58.2170W 31-08-01.9140N 097-42-46.0690W RWY FTW 16/34 710 7502 150 32-49-48.6376N 097-21-44.9518W 32-48-35.1564N 097-21-32.5720W RWY FTW 17/35 710 4005 75 32-49-29.4222N 097-21-59.4712W 32-48-50.2115N 097-21-52.8641W RWY 50F 17/35 873 4049 60 32-35-14.4314N 097-35-30.3310W 32-34-34.8228N 097-35-23.2854W RWY 4T2 17/35 693 5943 127 32-59-08.7809N 097-29-35.0501W 32-58-10.1675N 097-29-29.4642W RWY 9F9 17/35 762 3375 30 32-37-54.0000N 097-21-13.8500W 32-37-20.6000N 097-21-15.0000W RWY 2TE2 15/33 720 2800 150 32-49-58.5400N 097-32-10.8300W 32-49-32.1800N 097-32-00.7600W RWY NFW 18/36 650 11999 200 32-47-08.4330N 097-26-28.8810W 32-45-09.7070N 097-26-30.1680W RWY FWS 17L/35R 700 4000 60 32-34-21.1000N 097-18-23.1000W 32-33-41.5000N 097-18-23.1000W RWY FWS 17R/35L 700 6002 100 32-34-21.0520N 097-18-34.7550W 32-33-21.6620N 097-18-34.8880W RWY AFW 16L/34R 722 9600 150 33-00-05.8894N 097-19-14.7023W 32-58-32.2955N 097-18-55.5436W RWY AFW 16R/34L 722 8220 150 32-59-51.3310N 097-19-18.8730W 32-58-31.1880N 097-19-02.4660W RWY 1TE9 15/33 420 1563 150 31-16-25.3200N 096-26-26.5200W 31-16-11.2800N 096-26-18.9594W RWY T82 14/32 1695 5001 75 30-14-56.3718N 098-54-48.7070W 30-14-14.9784N 098-54-17.4397W RWY GLE 13/31 846 4307 75 33-39-18.3525N 097-11-56.8889W 33-38-49.4511N 097-11-19.4554W RWY GLE 18/36 846 6000 100 33-39-40.4792N 097-11-58.1156W 33-38-41.1371N 097-11-59.5095W RWY GTU 11/29 790 4099 75 30-40-53.0065N 097-41-10.2785W 30-40-32.3794N 097-40-29.8599W RWY GTU 18/36 790 5004 100 30-41-09.2437N 097-40-40.5019W 30-40-19.8165N 097-40-44.0403W RWY GYB 17/35 484 4000 75 30-10-29.0584N 096-58-50.3404W 30-09-49.6649N 096-58-45.7906W RWY TA35 01/19 915 4000 50 32-11-41.5800N 097-50-35.1500W 32-12-20.9100N 097-50-29.7800W RWY T37 01/19 1457 3200 60 31-25-29.1000N 098-36-33.6500W 31-26-00.1700N 098-36-26.5200W RWY 3T0 07/25 640 3000 60 33-50-20.7700N 096-48-54.0000W 33-50-23.5534N 096-48-18.6000W RWY F35 02/20 1008 3500 60 32-55-09.0470N 098-26-23.1740W 32-55-38.8900N 098-26-02.3100W RWY RPH 03/21 1123 5000 75 33-06-20.5515N 098-33-34.6569W 33-06-58.6568N 098-32-57.1732W RWY RPH 18/36 1123 3317 50 33-06-53.5000N 098-33-18.2210W 33-06-20.7210N 098-33-20.0280W RWY 10F 18/36 1112 3600 200 33-01-12.2284N 098-37-33.5308W 33-00-36.6076N 098-37-34.3313W RWY GDJ 14/32 778 3603 60 32-26-55.2878N 097-49-11.5827W 32-26-24.5215N 097-48-50.3363W RWY 66TE 17/35 684 3100 50 32-22-11.1100N 097-38-44.1000W 32-21-40.6400N 097-38-39.9800W RWY 0TX1 01/19 710 3500 50 32-20-56.5000N 097-40-37.8000W 32-21-30.5500N 097-40-30.3000W RWY GPM 17/35 588 4001 75 32-42-15.4122N 097-02-48.7604W 32-41-35.8230N 097-02-49.0394W RWY GVT 17/35 535 8030 150 33-04-43.9512N 096-03-54.5590W 33-03-24.5106N 096-03-55.7595W RWY 33R 16/34 340 3500 60 31-05-20.4059N 095-09-55.7424W 31-04-46.8163N 095-09-45.8674W RWY MNZ 18/36 1305 4998 75 31-40-21.7505N 098-08-50.5893W 31-39-32.8977N 098-08-59.6341W RWY 15F 18/36 1625 3420 50 33-11-46.1129N 099-43-01.6078W 33-11-12.5925N 099-43-07.0749W RWY LHB 18/36 285 4001 75 30-52-39.2500N 096-37-19.2100W 30-51-59.6600N 096-37-20.5200W RWY 00XA 15/33 271 4200 60 30-13-45.4000N 096-01-01.0000W 30-13-07.6700N 096-00-40.9000W RWY INJ 16/34 686 3998 60 32-05-19.8851N 097-05-57.2220W 32-04-42.2375N 097-05-42.9154W RWY 0TE4 17/35 502 3018 40 31-05-05.5300N 096-12-57.5200W 31-04-36.2900N 096-12-50.3400W RWY DZB 17/35 1093 5977 100 30-32-06.9600N 098-21-30.8700W 30-31-07.8100N 098-21-32.1800W RWY T51 17/35 166 3440 50 30-02-50.9960N 095-40-02.1560W 30-02-16.9470N 095-40-01.7940W RWY IAH 08L/26R 96 9000 150 30-00-25.7787N 095-21-31.6473W 30-00-25.8580N 095-19-49.2900W RWY CXO 01/19 245 5000 100 30-20-44.2266N 095-25-10.1247W 30-21-31.5059N 095-24-53.2773W RWY CXO 14/32 245 7501 150 30-21-45.7172N 095-25-13.6153W 30-20-44.5400N 095-24-25.1014W RWY DWH 17L/35R 152 3987 35 30-03-50.1370N 095-33-08.6866W 30-03-10.9825N 095-33-03.0389W RWY DWH 17R/35L 152 7009 100 30-04-23.9281N 095-33-17.3279W 30-03-15.1018N 095-33-07.2668W RWY 57TS 17/35 275 3990 100 30-48-13.3900N 095-32-35.7300W 30-47-34.4900N 095-32-27.8500W RWY UTS 18/36 363 5005 100 30-45-13.4202N 095-35-10.8723W 30-44-24.1407N 095-35-16.6492W RWY 21F 17/35 1062 3220 75 33-13-56.2131N 098-08-45.9587W 33-13-24.4111N 098-08-48.3489W RWY JSO 14/32 678 5006 75 31-52-28.5791N 095-13-21.2922W 31-51-50.5994N 095-12-44.0271W RWY 0TE7 17/35 1515 6291 60 30-15-37.5770N 098-37-24.1470W 30-14-35.5220N 098-37-18.1300W RWY 2XS1 18/36 1188 4600 75 30-13-30.5700N 098-18-06.8100W 30-12-45.3500N 098-18-12.9200W RWY JCT 08/26 1754 2255 130 30-30-42.7076N 099-45-46.8244W 30-30-41.8670N 099-45-21.0657W RWY JCT 17/35 1754 5004 75 30-31-03.7330N 099-45-51.7896W 30-30-14.2146N 099-45-52.1226W RWY 16X 17/35 804 3000 60 33-05-05.0352N 097-21-30.1881W 33-04-35.3466N 097-21-30.3667W RWY 7XA2 16/34 810 2900 90 33-09-10.0200N 097-22-29.8800W 33-08-41.9400N 097-22-23.0200W RWY 3T6 17/35 705 1800 22 33-08-09.8558N 097-17-49.1674W 33-07-52.0432N 097-17-49.3511W RWY XA0 18/36 685 1660 60 33-09-01.6000N 097-16-48.0000W 33-08-45.2000N 097-16-48.2000W RWY ILE 01/19 848 5495 100 31-04-42.9320N 097-41-20.5540W 31-05-34.9890N 097-41-02.2900W RWY E58 17/35 895 2830 250 33-18-37.2400N 097-20-49.4100W 33-18-09.2400N 097-20-49.9100W RWY RYW 15/33 1230 3808 50 30-30-12.7629N 097-58-17.0363W 30-29-37.0653N 097-58-03.0784W RWY TX82 15/33 620 1824 150 31-51-57.2100N 097-22-57.2140W 31-51-41.2850N 097-22-47.2550W RWY 30F 18R/36L 535 2600 75 33-08-05.8007N 097-00-50.1907W 33-07-40.1201N 097-00-52.0897W RWY LZZ 16/34 1214 4202 75 31-06-42.8069N 098-11-49.1968W 31-06-01.7699N 098-11-41.4109W RWY LNC 13/31 501 6500 100 32-35-04.1300N 096-43-27.2700W 32-34-14.6400N 096-42-38.7600W RWY 7T0 17/35 885 2400 60 33-35-48.9100N 097-13-07.6175W 33-35-25.1678N 097-13-08.3049W RWY 00R 12/30 151 3704 60 30-41-20.9988N 095-01-20.6496W 30-40-57.1564N 095-00-48.4254W RWY AQO 13/31 1102 3209 150 30-47-17.3334N 098-39-37.7420W 30-46-53.7390N 098-39-13.1260W RWY AQO 17/35 1102 4202 75 30-47-22.2241N 098-39-43.6369W 30-46-40.6444N 098-39-42.9827W RWY 51R 18/36 287 3202 50 30-55-01.8100N 095-57-03.9620W 30-54-30.6110N 095-57-10.3950W RWY T15 17/35 411 3021 50 31-20-41.3894N 096-51-07.0051W 31-20-11.4972N 096-51-07.6793W RWY T92 18/36 1514 3716 50 30-44-14.3358N 099-11-03.0761W 30-43-37.5693N 099-11-03.8465W RWY T50 15/33 1930 4100 60 30-56-15.2400N 099-48-43.2800W 30-55-38.5600N 099-48-23.1600W RWY HQZ 18/36 447 5999 100 32-45-18.7410N 096-31-48.9690W 32-44-19.3890N 096-31-50.0520W RWY LXY 18/36 545 5000 75 31-38-52.6564N 096-30-47.3923W 31-38-03.8255N 096-30-56.7166W RWY T56 17/35 780 3216 36 32-31-02.0370N 096-55-36.3810W 32-30-30.2110N 096-55-36.4120W RWY JWY 18/36 727 6500 100 32-28-01.9400N 096-54-42.4565W 32-26-57.7743N 096-54-47.7259W RWY 3F9 17/35 429 3203 40 32-40-51.9020N 095-30-38.6980W 32-40-20.2180N 095-30-39.0880W RWY JDD 18/36 433 4002 60 32-44-51.7002N 095-29-46.3528W 32-44-12.1337N 095-29-48.1868W RWY MWL 13/31 974 5996 100 32-47-14.7320N 098-03-51.4120W 32-46-32.3400N 098-03-02.2700W RWY MWL 17/35 974 4188 100 32-47-14.8320N 098-03-50.3930W 32-46-33.3960N 098-03-50.9170W RWY TX36 12/30 755 3100 150 32-03-48.2000N 097-35-33.5500W 32-03-30.4500N 097-35-04.1500W RWY 6X0 12/30 590 2700 30 32-05-58.3019N 095-17-54.6669W 32-05-43.6460N 095-17-28.4146W RWY F53 13/31 412 3900 60 33-13-09.1610N 095-14-29.8149W 33-12-41.1851N 095-13-58.2001W RWY 37F 17/35 1474 3200 50 33-28-23.2649N 099-35-10.9011W 33-27-51.6100N 099-35-09.8886W RWY 60R 17/35 229 5003 75 30-22-26.4232N 096-06-47.9271W 30-21-36.9502N 096-06-45.3680W RWY 89TS 18/36 215 5200 75 31-34-26.2200N 095-45-55.9600W 31-33-35.2600N 095-46-04.0700W RWY ONY 04/22 1275 5100 75 33-20-53.8050N 098-49-28.3062W 33-21-29.2929N 098-48-45.5671W RWY ONY 13/31 1275 5099 75 33-21-12.6904N 098-49-28.1877W 33-20-36.8331N 098-48-45.9208W RWY ONY 17/35 1275 5101 75 33-21-28.4255N 098-49-12.8366W 33-20-37.9617N 098-49-13.1482W RWY PSN 09/27 423 4002 75 31-46-37.4640N 095-42-45.7507W 31-46-37.0819N 095-41-59.3904W RWY PSN 18/36 423 5005 100 31-47-19.3621N 095-42-22.5500W 31-46-29.8340N 095-42-23.0769W RWY PRX 03/21 548 4624 150 33-37-49.0036N 095-27-10.8544W 33-38-25.4568N 095-26-37.8124W RWY PRX 14/32 548 4624 150 33-38-34.4312N 095-27-11.6404W 33-37-58.7933N 095-26-37.3483W RWY PRX 17/35 548 6002 100 33-38-41.3526N 095-27-15.9519W 33-37-41.9870N 095-27-14.9310W RWY TS75 10/28 330 1000 50 30-19-04.8200N 095-51-34.2500W 30-19-02.1600N 095-51-23.2600W RWY 74T 17/35 725 2364 90 33-11-10.5400N 097-15-16.5000W 33-10-47.1400N 097-15-16.7100W RWY F01 06/24 1602 2268 70 34-16-35.7780N 099-45-47.8410W 34-16-45.5260N 099-45-23.4710W RWY F01 11/29 1602 2270 70 34-16-34.2790N 099-45-47.8410W 34-16-23.3330N 099-45-24.2220W RWY F01 17/35 1602 4445 60 34-17-02.5200N 099-45-33.2900W 34-16-18.5600N 099-45-34.4200W RWY T14 18/36 473 3120 60 32-57-24.4200N 096-05-45.0400W 32-56-53.5500N 096-05-45.3900W RWY F23 01/19 1470 3415 75 32-26-49.5400N 098-41-00.6000W 32-27-21.0800N 098-40-46.2900W RWY TA25 17/35 1476 5500 75 32-26-21.0300N 098-35-46.7400W 32-25-27.4400N 098-35-35.5500W RWY RCK 17/35 474 2962 50 30-38-07.5900N 096-59-21.0800W 30-37-38.3200N 096-59-23.2300W RWY F46 17/35 574 3373 45 32-56-06.6820N 096-26-10.3120W 32-55-33.6040N 096-26-05.1170W RWY XS75 12/30 1417 5561 75 30-27-39.8222N 098-29-48.1189W 30-27-06.1030N 098-28-57.9100W RWY 33XA 04/22 555 2800 40 32-51-15.2600N 096-18-41.4700W 32-51-34.8200N 096-18-18.2200W RWY 58F 17/35 700 3340 130 33-22-14.3292N 097-08-45.6747W 33-21-41.3510N 097-08-48.3094W RWY XA03 18/36 887 2250 100 33-25-51.0000N 097-16-15.5500W 33-25-28.8200N 097-16-17.6600W RWY 81R 13/31 1255 4205 60 31-14-23.1470N 098-43-21.1610W 31-13-54.2560N 098-42-46.2940W RWY 37TX 04/22 1418 2200 100 31-19-12.3800N 098-52-07.2800W 31-19-22.8200N 098-51-45.0300W RWY 60F 17/35 1344 4300 50 33-39-15.9200N 099-15-40.7000W 33-38-33.4000N 099-15-40.7000W RWY SWI 16/34 746 4000 75 33-37-46.0807N 096-35-15.7626W 33-37-07.6737N 096-35-04.3677W RWY GYI 13/31 749 2277 60 33-43-02.1454N 096-40-42.4906W 33-42-44.1698N 096-40-26.2500W RWY GYI 17L/35R 749 9000 150 33-43-34.7404N 096-40-21.2385W 33-42-05.7497N 096-40-24.5508W RWY 84R 17/35 323 4000 75 30-02-01.1505N 097-10-04.5436W 30-01-21.9525N 097-09-58.1313W RWY 88R 17/35 830 4185 30 30-28-46.3200N 098-07-17.7200W 30-28-04.9100N 098-07-16.6200W RWY F56 08/26 1561 2211 50 32-54-44.8465N 099-44-09.8295W 32-54-44.4765N 099-43-43.9050W RWY F56 13/31 1561 1702 50 32-54-45.0759N 099-44-03.4446W 32-54-33.0077N 099-43-49.5220W RWY F56 17/35 1561 3707 60 32-54-51.2536N 099-44-09.4282W 32-54-14.5814N 099-44-09.7332W RWY SEP 14/32 1321 4209 75 32-13-13.0494N 098-10-52.1880W 32-12-37.2818N 098-10-27.0879W RWY TS76 16/34 1460 2700 22 30-15-20.9100N 098-35-41.2300W 30-14-54.2000N 098-35-40.9400W RWY SLR 01/19 489 5001 75 33-09-11.0050N 095-37-21.0610W 33-09-59.7770N 095-37-11.1860W RWY 2KL 12/30 854 2649 110 30-36-05.4761N 098-24-44.9288W 30-35-48.9011N 098-24-21.4345W RWY T74 17/35 600 4000 75 30-34-41.2486N 097-26-36.0554W 30-34-01.6753N 097-26-34.9845W RWY 68F 15/33 525 3300 50 31-39-56.2910N 096-18-47.5726W 31-39-28.2714N 096-18-27.9419W RWY TPL 02/20 682 4740 100 31-08-51.8620N 097-24-34.0940W 31-09-33.4330N 097-24-08.8120W RWY TPL 15/33 682 7000 150 31-09-35.9700N 097-24-43.7800W 31-08-29.8500N 097-24-19.7100W RWY TRL 17/35 474 5006 75 32-42-55.3542N 096-16-01.5978W 32-42-05.8155N 096-16-01.4856W RWY 72F 17/35 1273 3723 60 33-11-06.4300N 099-08-59.0000W 33-10-29.6000N 099-08-59.2900W RWY TYR 04/22 544 7802 150 32-20-41.2000N 095-24-43.4400W 32-21-35.6779N 095-23-39.0105W RWY TYR 13/31 544 5200 150 32-21-40.3784N 095-24-19.4861W 32-21-03.9024N 095-23-36.7308W RWY TYR 17/35 544 4849 150 32-21-37.4400N 095-24-19.5534W 32-20-49.4630N 095-24-19.7054W RWY F05 02/20 1265 5099 100 34-13-11.3757N 099-17-15.9995W 34-13-54.1977N 099-16-43.9147W RWY F05 16/34 1265 4304 80 34-13-52.6692N 099-17-09.5406W 34-13-11.4078N 099-16-56.9070W RWY ACT 01/19 516 7107 150 31-36-12.7231N 097-13-47.8415W 31-37-20.8957N 097-13-27.6366W RWY ACT 14/32 516 5103 150 31-37-01.5360N 097-14-20.0650W 31-36-18.1420N 097-13-49.8780W RWY PWG 04/22 592 3484 55 31-28-45.8140N 097-19-03.9900W 31-29-10.6480N 097-18-36.0770W RWY PWG 17/35 592 5501 75 31-29-37.6540N 097-19-06.0290W 31-28-43.2210N 097-19-04.9200W RWY CNW 17L/35R 470 8600 150 31-39-05.7479N 097-04-25.7230W 31-37-40.7224N 097-04-21.4658W RWY CNW 17R/35L 470 6291 75 31-38-37.5356N 097-04-33.0001W 31-37-35.3367N 097-04-29.8764W RWY 74TE 18/36 960 4191 50 32-04-01.6781N 097-47-39.3537W 32-03-20.3520N 097-47-43.4030W RWY 51TE 10/28 555 2080 90 32-28-23.3760N 096-47-35.4120W 32-28-18.4764N 096-47-11.8176W RWY WEA 17/35 991 2892 40 32-45-00.9379N 097-40-56.7174W 32-44-32.3263N 097-40-56.9384W RWY T29 18/36 760 2395 100 33-38-01.3800N 096-56-27.2900W 33-37-37.6900N 096-56-27.7000W RWY F14 04/22 1005 3107 100 33-56-38.3460N 098-37-12.2090W 33-56-58.3450N 098-36-44.2080W RWY F14 13/31 1005 3320 40 33-57-04.5910N 098-37-12.5130W 33-56-39.0560N 098-36-47.7330W RWY F14 16/34 1005 2037 42 33-57-05.3450N 098-36-56.2090W 33-56-45.3460N 098-36-53.2080W RWY 7TX0 17/35 986 3500 45 33-50-00.2770N 098-34-21.9130W 33-49-25.6600N 098-34-21.9100W RWY CWC 17/35 1003 4450 75 33-52-00.2344N 098-29-25.3020W 33-51-16.2160N 098-29-25.5721W RWY SPS 15C/33C 1019 10002 150 34-00-22.5600N 098-29-49.7100W 33-58-50.6600N 098-29-05.6900W RWY SPS 15L/33R 1019 6000 150 34-00-40.2310N 098-29-35.7940W 33-59-45.1030N 098-29-09.3870W RWY SPS 15R/33L 1019 13100 300 34-00-13.6000N 098-29-58.2000W 33-58-13.2300N 098-29-00.5600W RWY SPS 17/35 1019 7021 150 33-58-56.7020N 098-29-44.7530W 33-57-47.2570N 098-29-45.4710W RWY 76F 17/35 522 3230 50 32-41-09.1105N 095-59-02.8840W 32-40-37.1433N 095-59-02.8329W RWY 8TE1 04/22 497 2172 27 32-44-46.5000N 096-02-46.8100W 32-45-02.3500N 096-02-29.6300W RWY F51 01/19 513 3213 50 32-56-04.6590N 095-16-49.7370W 32-56-34.9010N 095-16-38.1080W RWY 5TA6 17/35 1820 900 50 31-56-17.5000N 099-53-43.9000W 31-56-08.6000N 099-53-44.1000W RWY 77F 17/35 1871 3204 50 31-57-05.7524N 099-59-08.9346W 31-56-34.0458N 099-59-09.1857W ILS 17 LOCALIZER IBWD 109.10 31-47-03.974N 098-57-17.460W - - 1373 6.00 179.36 - ILS 17L LOC/GS IRUK 110.55 34-39-15.280N 099-15-34.310W 34-40-46.230N 099-15-28.440W 1372 3.90 179.97 3.00 ILS 16L ILS/DME IUPE 110.15 32-58-26.443N 097-18-54.347W 32-59-39.717N 097-19-13.511W 707 4.56 170.26 3.00 ILS 35 LOCALIZER IDUC 111.50 34-29-01.564N 097-57-36.183W - - 1110 6.00 359.30 - ILS 17L ILS IGYI 111.70 33-41-54.599N 096-40-24.974W 33-43-23.751N 096-40-17.203W 740 4.42 181.78 3.00 ILS 34 ILS IDYS 109.90 32-26-39.340N 099-51-36.230W 32-24-20.560N 099-51-08.740W 1784 3.00 348.90 2.50 ILS 08L ILS/DME IBZU 111.55 30-00-25.868N 095-19-36.974W 30-00-29.752N 095-21-18.694W 87 3.98 89.95 3.00 ILS 31R ILS/DME IRRA 110.90 32-54-52.665N 097-01-26.098W 32-53-51.744N 097-00-07.955W 513 4.27 315.40 3.00 ILS 35L ILS ILTS 110.30 34-41-07.010N 099-16-25.760W 34-38-54.540N 099-16-19.780W 1345 3.00 359.99 3.00 ILS 18 ILS/DME IEFE 109.35 33-09-38.030N 096-35-22.170W 33-11-00.790N 096-35-22.070W 568 4.21 182.11 3.00 ILS 35L ILS IJZW 110.95 32-34-30.971N 097-18-34.736W 32-33-30.553N 097-18-29.035W 689 5.72 0.11 3.00 ILS 31L ILS/DME ILVF 111.10 32-51-14.043N 096-51-59.215W 32-50-07.296N 096-50-47.582W 472 3.96 313.00 3.08 ILS 16 ILS/DME IFTW 109.90 32-48-20.551N 097-21-30.111W 32-49-35.905N 097-21-47.545W 698 4.46 171.94 3.00 ILS 31R ILS/DME IOVW 111.50 32-51-28.654N 096-51-27.346W 32-50-35.337N 096-50-32.117W 481 4.95 315.77 3.00 ILS 33L ILS/DME ISPS 109.70 34-00-31.944N 098-30-06.969W 33-58-25.154N 098-28-59.852W 990 3.00 338.35 3.00 ILS 35R ILS/DME IABI 110.30 32-24-42.578N 099-40-29.277W 32-23-31.005N 099-40-24.251W 1771 4.77 359.76 3.00 ILS 15 ILS/DME ITPL 111.50 31-08-20.220N 097-24-16.210W 31-09-25.643N 097-24-33.995W 679 5.00 162.70 2.90 ILS 35R LOC/GS IFNM 110.55 34-41-15.520N 099-15-34.400W 34-39-39.540N 099-15-28.340W 1345 3.68 359.96 3.00 ILS 17R ILS/DME IGFQ 110.95 30-10-36.099N 097-40-42.200W 30-12-36.062N 097-40-50.042W 527 3.00 178.69 3.00 ILS 17L ILS/DME IVNK 110.50 30-10-34.110N 097-39-25.799W 30-12-01.994N 097-39-23.543W 484 3.98 178.70 3.00 ILS 34 ILS/DME IGKY 111.55 32-40-29.140N 097-05-49.230W 32-39-28.890N 097-05-38.910W 594 5.65 348.09 3.00 ILS 17L ILS ICNW 110.70 31-37-28.869N 097-04-20.873W 31-38-55.934N 097-04-19.443W 466 4.09 177.56 3.00 ILS 15 ILS IGRK 111.10 31-03-06.753N 097-49-17.335W 31-04-36.580N 097-50-05.859W 1006 3.63 157.45 3.00 ILS 18 ILS/DME IHQZ 109.75 32-44-02.574N 096-31-50.355W 32-45-07.945N 096-31-45.532W 444 5.19 180.88 3.00 ILS 36 LOC/GS IFWH 109.30 32-47-18.760N 097-26-28.775W 32-45-21.773N 097-26-24.180W 641 3.08 358.00 3.00 ILS 13R ILS/DME ILWN 109.50 32-53-17.460N 097-03-40.070W 32-54-24.131N 097-04-54.081W 588 3.89 139.19 3.00 ILS 31 ILS IRBD 108.50 32-41-21.389N 096-52-43.452W 32-40-33.118N 096-51-51.903W 651 5.38 315.21 3.00 ILS 17 ILS/DME IGVT 110.50 33-03-10.790N 096-03-55.970W 33-04-34.489N 096-03-50.001W 521 4.90 180.73 3.00 ILS 31 ILS/DME IVMH 109.55 32-47-17.020N 098-03-54.080W 32-46-40.460N 098-03-17.990W 967 6.00 315.73 3.00 ILS 36L ILS/DME IBXN 111.90 32-55-06.870N 097-03-16.690W 32-52-54.409N 097-03-22.040W 580 2.78 0.24 3.00 ILS 36R ILS/DME IFJN 110.55 32-55-06.820N 097-03-02.590W 32-52-54.851N 097-03-07.968W 577 3.00 0.25 3.00 ILS 17R ILS IALT 111.30 34-38-31.520N 099-16-25.760W 34-40-45.540N 099-16-19.790W 1371 3.00 180.00 3.00 ILS 17R LOC/DME IHEW 110.50 30-03-08.687N 095-33-06.328W - - 158 5.24 172.79 - ILS 34 ILS/DME ICLL 110.55 30-35-59.577N 096-21-48.931W 30-34-49.308N 096-21-39.375W 303 4.89 348.93 2.90 ILS 13L ILS/DME IDAL 111.50 32-50-23.088N 096-50-11.378W 32-51-15.355N 096-51-18.489W 478 4.51 133.00 3.00 ILS 18 ILS IDTO 109.10 33-11-27.910N 097-11-53.480W 33-12-32.250N 097-11-56.770W 636 5.33 181.06 3.00 ILS 33 ILS/DME IBTJ 109.35 31-04-57.080N 097-50-10.830W 31-03-24.870N 097-49-31.100W 976 3.70 337.44 3.00 ILS 13R ILS/DME IDPX 111.10 32-49-56.957N 096-50-29.873W 32-50-52.167N 096-51-38.757W 472 4.28 135.77 3.00 ILS 15C LOC/GS ISHP 110.50 33-58-37.980N 098-28-59.630W 34-00-12.910N 098-29-41.890W 994 3.53 158.35 3.00 ILS 18 ILS/DME INFW 108.70 32-44-47.417N 097-26-30.406W 32-46-57.605N 097-26-23.131W 620 3.00 178.00 3.00 ILS 13 ILS ITYR 109.90 32-20-58.672N 095-23-30.597W 32-21-31.799N 095-24-14.758W 524 6.00 135.28 2.87 ILS 17R LOC/DME IEMB 109.75 32-24-19.760N 099-41-05.303W - - 1796 4.88 179.76 - ILS 02 LOCALIZER IMLC 108.30 34-53-25.742N 095-46-47.393W - - 766 6.00 20.29 - ILS 35C ILS/DME IPKQ 110.30 32-55-07.040N 097-01-33.450W 32-52-54.331N 097-01-29.472W 557 2.77 0.26 3.00 ILS 35L ILS/DME IUWX 111.35 32-55-07.290N 097-01-47.522W 32-52-54.983N 097-01-43.534W 559 3.00 0.26 3.00 ILS 35R ILS/DME IAJQ 111.75 32-54-04.194N 097-00-35.150W 32-52-43.440N 097-00-30.904W 559 4.20 0.27 3.00 ILS 35R ILS/DME IHCE 110.50 30-12-24.401N 097-39-28.686W 30-10-54.321N 097-39-21.770W 470 3.98 358.70 3.00 ILS 35 ILS ILAW 109.10 34-34-56.120N 098-25-02.612W 34-33-27.113N 098-25-01.612W 1069 4.03 356.94 3.00 ILS 35L ILS/DME IBSM 110.95 30-13-00.761N 097-40-46.025W 30-10-58.540N 097-40-47.349W 484 3.00 358.69 3.00 ILS 15 ILS/DME IADS 110.10 32-57-29.684N 096-49-55.022W 32-58-21.212N 096-50-21.598W 630 6.00 159.87 3.00 ILS 15 LOC/DME ICPT 111.15 32-20-36.489N 097-25-44.915W - - 859 6.01 159.29 - ILS 34R ILS/DME IJVX 110.15 33-00-09.055N 097-19-15.349W 32-58-41.552N 097-19-01.625W 666 4.04 350.26 3.00 ILS 18L ILS/DME ICIX 110.55 32-52-33.610N 097-03-03.390W 32-54-45.220N 097-03-06.820W 594 3.00 180.25 3.00 ILS 26R ILS/DME IOND 111.55 30-00-25.769N 095-21-43.965W 30-00-29.813N 095-20-02.257W 90 3.98 269.95 3.00 ILS 18R ILS/DME IVYN 111.90 32-52-33.934N 097-03-17.455W 32-54-45.470N 097-03-21.570W 600 2.77 180.25 3.00 ILS 16 ILS ITYY 109.90 32-23-51.300N 099-50-57.170W 32-26-07.770N 099-51-33.650W 1784 3.00 168.90 2.60 ILS 19 ILS/DME IACT 109.70 31-36-07.202N 097-13-49.475W 31-37-11.757N 097-13-35.357W 498 5.22 194.16 3.00 ILS 17C ILS/DME IFLQ 110.30 32-52-33.151N 097-01-34.278W 32-54-45.640N 097-01-28.770W 556 2.77 180.26 3.00 ILS 17L ILS/DME IPPZ 111.75 32-52-19.437N 097-00-35.727W 32-53-45.230N 097-00-31.140W 526 4.20 180.27 3.00 ILS 14 ILS/DME ICXO 108.70 30-20-36.305N 095-24-18.573W 30-21-40.347N 095-25-03.669W 228 6.00 145.62 3.00 ILS 17R ILS/DME IJHZ 111.35 32-52-33.240N 097-01-48.346W 32-54-45.820N 097-01-43.064W 561 3.00 180.26 3.00 ILS 34 ILS/DME IUXT 109.90 32-49-59.147N 097-21-46.725W 32-48-45.440N 097-21-38.445W 667 4.68 351.94 3.00 ILS 31 ILS IAIW 108.90 34-19-00.155N 097-01-53.742W 34-17-59.520N 097-00-35.016W 728 4.01 315.54 3.00 ILS 33 ILS/DME ITBQ 110.10 32-58-49.316N 096-50-29.808W 32-57-48.170N 096-50-07.405W 645 5.41 339.87 3.00 NAV ADH VOR/DME 34-48-09.200N 096-40-12.300W 987 117.80 125X NAV LTS VORTAC 34-39-46.540N 099-16-16.190W 1361 109.80 035X NAV ADM VORTAC 34-12-41.710N 097-10-05.621W 937 116.70 114X NAV DUC VOR/DME 34-23-04.134N 097-55-00.553W 1089 111.00 047X NAV URH VOR/DME 33-56-39.070N 096-23-30.610W 681 114.30 090X NAV PFL NDB 34-36-31.886N 098-24-13.636W 1143 425 - NAV OFZ NDB 34-46-52.969N 098-24-08.284W 1276 388 - NAV HBR VORTAC 34-51-59.596N 099-03-48.186W 1472 111.80 055X NAV HHW NDB 34-02-22.164N 095-32-22.502W 547 323 - NAV LAW VOR/DME 34-29-46.235N 098-24-47.102W 1104 109.40 031X NAV MLC VORTAC 34-50-57.987N 095-46-56.439W 782 112.00 057X NAV PVJ NDB 34-42-55.490N 097-13-44.080W 960 384 - NAV ABI VORTAC 32-28-52.781N 099-51-48.449W 1810 113.70 084X NAV TQA VOR/DME 32-14-08.675N 099-49-00.418W 2058 111.60 053X NAV AHX NDB 32-09-33.553N 095-49-48.871W 440 269 - NAV CSZ NDB 32-03-48.587N 095-57-27.435W 383 215 - NAV CWK VORTAC 30-22-42.780N 097-31-47.450W 593 112.80 075X NAV UBC NDB 31-40-49.710N 099-58-29.706W 1735 239 - NAV ABG NDB 32-35-07.783N 095-06-47.230W 424 404 - NAV BYP VORTAC 33-32-14.950N 096-14-02.740W 700 114.60 093X NAV UKW VORTAC 33-32-09.193N 097-49-16.603W 1102 112.40 071X NAV GMZ NDB 33-36-19.303N 097-46-25.389W 1090 356 - NAV BBD NDB 31-10-40.398N 099-19-21.325W 1815 380 - NAV BWD VOR/DME 31-53-33.297N 098-57-26.857W 1574 108.60 023X NAV BMQ NDB 30-44-24.990N 098-14-10.449W 0 341 - NAV MII NDB 33-02-25.425N 096-14-54.922W 541 316 - NAV CQY VORTAC 32-11-08.600N 096-13-05.170W 400 114.80 095X NAV CLL VORTAC 30-36-18.006N 096-25-14.451W 264 113.30 080X NAV CRS NDB 32-01-42.302N 096-23-40.626W 440 396 - NAV CGQ NDB 32-03-50.887N 096-25-34.676W 394 344 - NAV CVE VOR/DME 32-53-25.134N 096-54-14.270W 447 116.20 109X NAV VLY NDB 33-15-42.450N 096-35-19.710W 640 421 - NAV TTT VOR/DME 32-52-08.977N 097-02-25.812W 540 113.10 078X NAV FUZ VORTAC 32-53-22.020N 097-10-45.931W 637 115.70 104X NAV OIP NDB 32-23-54.472N 098-48-37.223W 1428 410 - NAV PYF NDB 31-51-45.587N 096-11-50.899W 350 418 - NAV HLR NDB 31-07-45.049N 097-42-29.245W 876 347 - NAV GR NDB 31-10-04.229N 097-52-41.622W 0 323 - NAV GRK VOR/DME 31-01-58.390N 097-48-49.640W 963 111.80 055X NAV NFW TACAN 32-46-17.006N 097-26-21.492W 631 108.70 024X NAV FZT VOR/DME 32-04-28.575N 095-31-50.846W 305 111.40 051X NAV GUO NDB 30-41-03.819N 097-40-47.674W 779 332 - NAV JEN VORTAC 32-09-34.520N 097-52-39.650W 1300 115.00 097X NAV GHX NDB 33-09-57.112N 098-29-47.797W 0 371 - NAV MJF TACAN 33-03-58.571N 096-03-41.030W 540 109.60 033X NAV SYW NDB 32-58-54.696N 096-04-02.307W 493 428 - NAV MNZ NDB 31-37-17.445N 098-08-56.074W 1240 251 - NAV AKL NDB 33-11-27.804N 099-43-12.025W 1622 407 - NAV DWH NDB 30-07-31.918N 095-33-57.110W 0 521 - NAV UTS NDB 30-44-26.696N 095-35-27.125W 943 308 - NAV JSO NDB 31-52-12.612N 095-12-55.805W 670 263 - NAV JCT VORTAC 30-35-52.876N 099-49-02.932W 2282 116.00 107X NAV AGJ VORTAC 31-11-07.816N 098-08-30.688W 1191 112.50 072X NAV LOA VORTAC 31-07-26.463N 095-58-04.642W 346 110.80 045X NAV LLO VORTAC 30-47-46.831N 098-47-14.599W 1207 108.20 019X NAV PQF NDB 32-48-33.721N 096-31-44.831W 445 248 - NAV GNL VOR/DME 31-34-53.316N 096-32-56.722W 514 108.80 025X NAV LXY NDB 31-38-22.504N 096-30-44.128W 532 329 - NAV MQP VORTAC 32-43-34.250N 097-59-50.790W 900 117.70 124X NAV TNV VOR/DME 30-17-18.695N 096-03-29.664W 247 115.90 106X NAV PSN NDB 31-46-50.368N 095-42-02.710W 400 375 - NAV PRX VOR/DME 33-32-32.563N 095-26-53.845W 510 113.60 083X NAV UIM VOR/DME 32-52-49.734N 095-22-00.809W 517 114.00 087X NAV JUG NDB 32-40-05.090N 096-31-56.108W 420 388 - NAV DNI NDB 33-49-35.397N 096-40-08.015W 680 341 - NAV STV VORTAC 30-12-24.334N 098-42-20.719W 1530 113.80 085X NAV SLR VOR/DME 33-11-54.817N 095-32-33.346W 508 109.00 027X NAV TPL VOR/DME 31-12-33.609N 097-25-29.881W 710 110.40 041X NAV AVZ NDB 32-45-36.460N 096-14-56.920W 491 260 - NAV TYR VOR/DME 32-21-21.121N 095-24-12.477W 564 114.20 089X NAV ROB NDB 31-30-13.701N 097-04-10.501W 392 400 - NAV ACT VORTAC 31-39-44.387N 097-16-08.531W 510 115.30 100X NAV ICF NDB 33-54-38.620N 098-27-16.800W 940 296 - NAV SKB NDB 33-46-56.186N 098-29-17.382W 983 344 - NAV SHP TACAN 33-58-57.770N 098-29-15.620W 1020 110.80 045X NAV SPS VORTAC 33-59-14.235N 098-35-36.499W 1133 112.70 074X # # To visit the ACM air museum at the Addison airport, uncomment these lines: # #FEATURE ../../missiles/aim9.obv 32-57-10.000N 096-49-59.000W 660 290 #FEATURE ../../missiles/sa10.obv 32-57-11.000N 096-49-59.000W 660 290 #FEATURE ../../missiles/sa11.obv 32-57-12.000N 096-49-59.000W 660 290 #FEATURE ../../missiles/sa2.obv 32-57-13.000N 096-49-59.000W 660 290 #FEATURE ../../features/telar1.obv 32-57-14.000N 096-49-59.000W 660 290 #FEATURE ../../tracer.obv 32-57-15.000N 096-49-59.000W 660 290 #FEATURE ../../features/hangar.obv 32-57-17.000N 096-49-59.000W 644 290 #FEATURE ../../aircraft/c172.obv 32-57-19.000N 096-49-59.000W 660 290 #FEATURE ../../aircraft/f16.obv 32-57-21.000N 096-49-59.000W 660 290 #FEATURE ../../aircraft/f18.obv 32-57-23.000N 096-49-59.000W 660 290 #FEATURE ../../aircraft/il78.obv 32-57-25.000N 096-49-59.000W 660 290 #FEATURE ../../aircraft/kc135.obv 32-57-27.000N 096-49-59.000W 660 290 #FEATURE ../../aircraft/mig23.obv 32-57-29.000N 096-49-59.000W 660 290 #FEATURE ../../aircraft/mig25.obv 32-57-31.000N 096-49-59.000W 660 290 #FEATURE ../../aircraft/mig29.obv 32-57-33.000N 096-49-59.000W 660 290 #FEATURE ../../aircraft/su30.obv 32-57-35.000N 096-49-59.000W 660 290 #FEATURE ../../aircraft/ufo.obv 32-57-37.000N 096-49-59.000W 660 290 #FEATURE ../../aircraft/b-747.obv 32-57-39.000N 096-49-59.000W 680 290 acm-6.0_20200416/objects/zones/usa/lasvegaseast.txt0000644000000000000000000001675513646045023020416 0ustar rootroot# Las Vegas east area scenery. # Created: 2020-04-16 # Latitude range: [35N, 40N[ # Longitude range: [115W, 110W[ # 2017-10-04 Checked against https://nfdc.faa.gov/xwiki/bin/view/NFDC/56DaySub-2017-03-02 # "56 Day NASR Subscription - Effective March 2, 2017". # ?????: TEAM1_LOC 35N 115W 000 031 # ?????: TEAM1_LOC 35N 115W 000 031 GROUND_COLOR #305030 RWY IFP 16/34 707 8500 150 35-09-58.5647N 114-33-36.7566W 35-08-34.6559N 114-33-30.4355W RWY A20 18/36 725 3700 42 35-00-38.6200N 114-33-54.1200W 35-00-02.0200N 114-33-54.0700W RWY AZC 02/20 4874 5099 60 36-57-12.9834N 113-01-00.6071W 36-57-57.4935N 113-00-31.1352W RWY AZC 11/29 4874 6300 75 36-57-52.9339N 113-01-25.9976W 36-57-19.4226N 113-00-20.5901W RWY FLG 03/21 7014 8800 150 35-07-52.3859N 111-40-44.1277W 35-08-57.8836N 111-39-34.4039W RWY GCN 03/21 6609 8999 150 35-56-34.7377N 112-09-24.7015W 35-57-42.2257N 112-08-13.4164W RWY 40G 01/19 5999 4199 45 35-38-42.6600N 112-09-02.2800W 35-39-21.4100N 112-08-43.9800W RWY 0V7 05/23 5688 7101 75 36-42-44.8841N 110-14-22.1965W 36-43-13.5730N 110-13-02.6308W RWY 38AZ 02/20 6581 7500 75 36-27-47.6340N 110-25-30.3650W 36-28-48.8620N 110-24-38.5300W RWY IGM 03/21 3449 6827 150 35-15-05.3465N 113-56-53.1718W 35-15-53.0746N 113-55-54.9609W RWY IGM 17/35 3449 6725 75 35-16-12.3498N 113-56-09.7601W 35-15-05.8533N 113-56-09.7987W RWY L41 03/21 3603 3715 35 36-48-25.3000N 111-38-55.3900W 36-48-52.5100N 111-38-24.7000W RWY L25 01/19 2941 2900 110 36-05-21.9300N 114-02-53.3800W 36-05-49.3400N 114-02-42.9500W RWY PGA 07/25 4316 2201 75 36-55-44.9760N 111-27-12.6780W 36-55-47.9808N 111-26-45.8295W RWY PGA 15/33 4316 5950 150 36-55-58.1511N 111-26-58.4275W 36-55-00.2051N 111-26-45.8520W RWY 1G4 17/35 4817 5000 75 35-59-34.6235N 113-48-58.0393W 35-58-45.4104N 113-49-03.7925W RWY L37 05/23 5397 5100 45 35-31-27.4800N 113-15-19.0200W 35-31-48.6100N 113-14-23.0000W RWY P10 04/22 5573 4200 50 35-47-18.0100N 110-25-45.2100W 35-47-41.4900N 110-25-03.1400W RWY P23 04/22 5237 4800 75 35-19-52.0100N 112-53-34.5100W 35-20-20.5300N 112-52-48.2700W RWY U30 18/36 1549 3500 50 36-01-30.5600N 114-20-01.2600W 36-00-56.7000N 114-20-10.1400W RWY T03 15/33 4513 6230 75 36-06-03.4900N 111-23-08.0500W 36-05-03.6100N 111-22-50.1200W RWY 1Z1 16/34 4100 4600 40 36-15-46.1500N 113-13-52.9400W 36-15-00.7400N 113-13-49.4000W RWY CMR 18/36 6691 6000 100 35-18-48.9315N 112-11-32.9523W 35-17-50.6336N 112-11-46.3479W RWY INW 04/22 4941 6236 75 35-00-51.3638N 110-44-16.3536W 35-01-23.4827N 110-43-12.3716W RWY INW 11/29 4941 7100 150 35-01-44.9039N 110-43-40.3589W 35-01-10.1599N 110-42-26.2025W RWY BVU 09/27 2204 4803 75 35-56-50.8480N 114-52-08.4984W 35-56-42.8207N 114-51-10.9298W RWY BVU 15/33 2204 3852 75 35-57-13.6471N 114-51-48.3950W 35-56-36.8011N 114-51-36.6176W RWY ELY 12/30 6259 4825 60 39-18-12.3189N 114-51-06.8433W 39-17-35.4591N 114-50-27.9267W RWY ELY 18/36 6259 6018 150 39-18-31.7649N 114-50-08.3148W 39-17-34.0123N 114-50-26.5388W RWY 67L 01/19 1978 5121 75 36-49-37.2268N 114-03-36.6060W 36-50-21.3427N 114-03-05.7318W RWY U08 13/31 1366 4811 75 36-34-25.8680N 114-26-50.5602W 36-33-44.5151N 114-26-21.4166W RWY 0L9 06/24 1535 3400 50 36-18-36.4495N 114-28-10.3968W 36-18-43.0222N 114-27-29.6462W RWY 1L1 17/35 4831 4606 60 37-47-37.4108N 114-25-10.3664W 37-46-51.9314N 114-25-12.8970W RWY 1L3 16/34 3413 5040 70 35-27-05.3003N 114-54-36.0544W 35-26-15.5855N 114-54-31.4374W RWY U52 07/25 5863 2150 50 38-13-39.8503N 112-40-50.3990W 38-13-40.9934N 112-40-23.4932W RWY U52 13/31 5863 4984 75 38-14-15.1378N 112-40-45.7753W 38-13-33.4802N 112-40-12.4771W RWY BCE 03/21 7590 7395 75 37-41-58.1583N 112-09-18.3650W 37-42-48.2511N 112-08-11.3895W RWY CDC 02/20 5622 8650 150 37-41-26.1974N 113-06-28.1454W 37-42-36.8778N 113-05-27.5542W RWY CDC 08/26 5622 4822 60 37-42-09.8213N 113-06-22.0634W 37-42-04.1730N 113-05-22.5093W RWY DTA 17/35 4759 5502 75 39-23-28.1358N 112-30-07.7830W 39-22-33.7700N 112-30-08.0955W RWY 2UT2 08/26 8280 2071 40 37-31-39.2500N 112-39-51.4500W 37-31-45.4200N 112-39-26.9300W RWY 1L7 13/31 5737 5000 60 37-45-01.9600N 111-34-32.8200W 37-44-24.3900N 111-33-52.3700W RWY FOM 04/22 4985 5040 75 38-57-14.4666N 112-22-12.9588W 38-57-44.0889N 112-21-21.6829W RWY U96 01/19 4388 5700 60 37-25-42.1700N 110-34-07.9400W 37-26-32.0100N 110-33-34.9700W RWY HVE 08/26 4446 5675 75 38-24-59.9300N 110-42-50.5400W 38-24-52.8500N 110-41-39.8100W RWY HVE 17/35 4446 2600 120 38-25-22.9300N 110-42-02.5400W 38-24-57.2900N 110-42-04.7700W RWY 69V 08/26 5915 4048 75 39-21-39.7900N 110-55-25.5900W 39-21-39.8600N 110-54-34.0400W RWY 69V 12/30 5915 3640 70 39-21-54.4300N 110-55-14.6000W 39-21-26.9800N 110-54-44.5900W RWY 69V 18/36 5915 2079 56 39-21-50.5100N 110-55-01.2800W 39-21-31.5500N 110-55-11.4800W RWY 1L8 01/19 3350 3282 40 37-08-09.4700N 113-18-28.1200W 37-08-40.3000N 113-18-15.4300W RWY KNB 01/19 4868 6193 75 37-00-09.3100N 112-32-06.9200W 37-01-06.4600N 112-31-39.6600W RWY 38U 13/31 7029 5900 75 38-22-08.7077N 111-36-07.4360W 38-21-22.6398N 111-35-21.9790W RWY 41U 03/21 5516 5021 75 39-19-35.7447N 111-37-08.1008W 39-20-10.5540N 111-36-22.5993W RWY MLF 16/34 5042 5004 75 38-26-00.6124N 113-00-47.4281W 38-25-11.1638N 113-00-48.1446W RWY U14 17/35 5022 6300 100 39-44-42.7742N 111-52-12.2896W 39-43-40.5271N 111-52-12.0761W RWY U55 18/36 6763 5700 75 37-51-09.6579N 112-23-20.3112W 37-50-15.9263N 112-23-41.6325W RWY 1L9 04/22 5930 5000 75 37-51-19.9357N 112-49-22.1182W 37-51-49.4332N 112-48-32.0706W RWY PUC 01/19 5958 8310 100 39-36-17.7155N 110-45-18.7701W 39-37-35.6868N 110-44-45.3171W RWY PUC 08/26 5958 3150 75 39-36-54.4719N 110-45-24.1566W 39-36-54.5475N 110-44-43.9008W RWY PUC 15/33 5958 4514 75 39-36-55.3742N 110-45-24.2460W 39-36-13.8352N 110-45-03.3150W RWY RIF 01/19 5318 7100 100 38-43-31.4277N 112-06-25.7660W 38-44-34.1548N 112-05-45.6348W RWY SGU 01/19 2884 9300 150 37-01-28.6316N 113-30-59.4754W 37-02-53.2769N 113-30-14.6768W RWY 44U 02/20 5159 3855 60 39-01-29.3500N 111-50-32.0700W 39-01-59.6600N 111-50-02.4600W ILS 21 LOC/GS IFLG 110.50 35-08-23.340N 111-40-16.050W 35-08-38.710N 111-39-57.314W 6999 4.60 224.59 3.00 ILS 19 ILS/DME ISGU 110.90 37-02-57.400N 113-30-18.730W 37-02-44.480N 113-30-23.370W 2875 5.00 210.15 3.10 ILS 01 ILS/DME IPUC 109.35 39-37-45.551N 110-44-41.072W 39-36-25.997N 110-45-18.924W 5820 4.28 29.00 3.00 ILS 20 ILS IECC 110.10 37-41-16.789N 113-06-36.179W 37-42-30.642N 113-05-38.147W 5593 4.09 214.13 3.00 ILS 03 LOC/GS IGCN 108.90 35-57-49.718N 112-08-05.502W 35-56-44.484N 112-09-19.709W 6534 4.01 40.54 3.00 NAV AZC NDB 36-57-36.232N 113-00-33.032W 4858 403 - NAV FLG VOR/DME 35-08-49.912N 111-40-26.986W 7026 113.85 085Y NAV GCN VOR/DME 35-57-37.223N 112-08-45.766W 6670 113.10 078X NAV IGM VOR/DME 35-15-37.847N 113-56-02.694W 3422 108.80 025X NAV PGA VOR/DME 36-55-51.758N 111-26-50.794W 4277 117.60 123X NAV PGS VOR/DME 35-37-28.963N 113-32-40.080W 4760 112.00 57X NAV TBC VORTAC 36-07-16.723N 111-16-10.516W 5045 113.50 082X NAV INW VORTAC 35-03-41.759N 110-47-42.071W 4913 112.60 073X NAV BLD VORTAC 35-59-44.845N 114-51-48.884W 3642 116.70 114X NAV ELY VOR/DME 39-17-53.249N 114-50-53.900W 6248 110.60 043X NAV MMM VORTAC 36-46-09.309N 114-16-38.828W 2106 114.30 090X NAV ILC VORTAC 38-15-00.694N 114-23-39.215W 9318 116.30 110X NAV BCE VORTAC 37-41-21.074N 112-18-14.030W 9040 112.80 075X NAV EHK VOR/DME 37-47-14.388N 113-04-05.630W 5464 117.30 120X NAV DTA VORTAC 39-18-07.960N 112-30-20.001W 4642 116.10 108X NAV HVE VORTAC 38-25-00.534N 110-41-59.038W 4430 115.90 106X NAV MLF VORTAC 38-21-37.355N 113-00-47.667W 4978 112.10 058X NAV PUC VOR/DME 39-36-11.490N 110-45-12.700W 5830 115.50 102X NAV UTI VOR/DME 37-01-03.430N 113-31-04.440W 2848 108.60 23X acm-6.0_20200416/objects/zones/usa/newyork.txt0000644000000000000000000012165413646045023017425 0ustar rootroot# New York area scenery. # Created: 2020-04-16 # Latitude range: [40N, 45N[ # Longitude range: [75W, 70W[ # 2017-10-04 Checked against https://nfdc.faa.gov/xwiki/bin/view/NFDC/56DaySub-2017-03-02 # "56 Day NASR Subscription - Effective March 2, 2017". # New York, JFK 04L: TEAM1_LOC 40-37-19.2759N 073-47-08.1083W 000 031 # Boston, BOS 22R: TEAM2_LOC 42-22-41.8759N 071-00-16.2499W 000 199 GROUND_COLOR #305030 RWY BDR 06/24 9 4677 100 41-09-25.3598N 073-07-55.0421W 41-09-58.0324N 073-07-11.7989W RWY BDR 11/29 9 4761 150 41-09-58.4586N 073-08-05.8621W 41-09-52.0542N 073-07-04.2161W RWY SNC 17/35 416 2722 50 41-23-14.0580N 072-30-26.6980W 41-22-48.6500N 072-30-14.9700W RWY DXR 08/26 457 4422 150 41-22-07.3060N 073-29-26.7358W 41-22-22.4173N 073-28-32.3223W RWY DXR 17/35 457 3135 100 41-22-35.0829N 073-29-00.0396W 41-22-07.4625N 073-28-41.4347W RWY LZD 13/31 238 2700 75 41-49-17.6665N 071-54-18.9632W 41-49-04.4735N 071-53-47.9757W RWY 42B 14/32 9 2120 50 41-26-53.1800N 072-27-36.7900W 41-26-39.3900N 072-27-15.8200W RWY 7B9 01/19 253 1800 50 41-55-22.6721N 072-27-24.5741W 41-55-40.3976N 072-27-26.5495W RWY GON 05/23 9 5000 150 41-19-30.1161N 072-02-52.8935W 41-20-11.0876N 072-02-16.2705W RWY GON 15/33 9 4000 96 41-19-59.2181N 072-03-10.8512W 41-19-31.2484N 072-02-33.8138W RWY HFD 02/20 18 4417 150 41-43-53.8973N 072-38-59.3182W 41-44-37.0017N 072-38-50.2639W RWY HFD 11/29 18 2314 71 41-44-03.0855N 072-39-27.2883W 41-43-59.5425N 072-38-57.1363W RWY MMK 18/36 103 3100 75 41-30-45.9110N 072-49-52.5260W 41-30-16.8360N 072-49-39.7190W RWY HVN 02/20 12 5600 150 41-15-21.7804N 072-53-17.6857W 41-16-17.0384N 072-53-13.9648W RWY HVN 14/32 12 3626 100 41-16-01.4303N 072-53-25.1867W 41-15-37.8395N 072-52-49.4541W RWY 11N 17/35 675 2900 50 41-34-21.8004N 073-27-52.1436W 41-33-56.2776N 073-27-34.7877W RWY OXC 18/36 726 5800 100 41-29-10.0979N 073-08-12.7783W 41-28-13.5324N 073-08-00.5659W RWY 4B8 02/20 202 3665 75 41-41-03.6106N 072-51-55.1592W 41-41-39.6581N 072-51-50.6543W RWY C44 17/35 770 1756 60 41-57-28.0758N 072-03-21.4026W 41-57-13.0039N 072-03-09.8977W RWY 4B9 03/21 195 2205 50 41-54-47.7500N 072-46-40.8900W 41-55-08.7600N 072-46-33.1400W RWY 7B6 10/28 120 3242 60 41-55-41.5500N 072-34-56.4600W 41-55-42.9800N 072-34-13.6000W RWY IJD 09/27 246 4271 100 41-44-36.2815N 072-11-06.5948W 41-44-47.6012N 072-10-12.3250W RWY IJD 18/36 246 2799 75 41-44-46.6120N 072-11-08.3954W 41-44-20.1141N 072-10-57.8508W RWY BDL 01/19 173 4268 100 41-56-01.4095N 072-40-46.6309W 41-56-43.5599N 072-40-47.5795W RWY BDL 06/24 173 9510 200 41-55-55.2512N 072-41-47.6882W 41-57-02.3920N 072-40-19.6784W RWY BDL 15/33 173 6847 150 41-56-32.6303N 072-41-35.7094W 41-55-45.3241N 072-40-30.9576W RWY 8B5 06/24 589 3027 40 42-21-12.6126N 072-08-02.8567W 42-21-33.3626N 072-07-33.8326W RWY BED 05/23 132 5107 150 42-27-48.3688N 071-17-48.7253W 42-28-28.5910N 071-17-07.5937W RWY BED 11/29 132 7011 150 42-28-18.5654N 071-18-01.2347W 42-28-09.9695N 071-16-28.4156W RWY 1M8 09/27 73 2466 50 41-50-17.2077N 071-01-50.9093W 41-50-23.9165N 071-01-19.5874W RWY BVY 09/27 107 4755 100 42-34-47.0784N 070-55-29.1191W 42-34-59.8069N 070-54-27.9431W RWY BVY 16/34 107 5001 100 42-35-31.0040N 070-55-18.9310W 42-34-52.8130N 070-54-36.5338W RWY BOS 04L/22R 19 7864 150 42-21-28.7577N 071-00-51.6187W 42-22-41.8759N 071-00-16.2499W RWY BOS 04R/22L 19 10006 150 42-21-03.8094N 071-00-42.4580W 42-22-36.8399N 070-59-57.4473W RWY BOS 09/27 19 7001 150 42-21-20.7150N 071-00-46.4187W 42-21-36.7767N 070-59-15.7276W RWY BOS 14/32 19 5000 100 42-21-23.7521N 071-01-23.7886W 42-20-54.9565N 071-00-29.6841W RWY BOS 15L/33R 19 2557 100 42-22-23.5036N 071-00-31.0069W 42-22-05.5826N 071-00-07.0019W RWY BOS 15R/33L 19 10083 150 42-22-27.3749N 071-01-04.4117W 42-21-16.7428N 070-59-29.7098W RWY FMH 05/23 130 8000 150 41-39-00.4941N 070-31-48.1193W 41-40-01.9710N 070-30-41.8887W RWY FMH 14/32 130 9501 150 41-40-02.7862N 070-32-17.8082W 41-39-05.7407N 070-30-38.4092W RWY 5B6 07/25 41 2298 40 41-35-00.9854N 070-32-37.0646W 41-35-15.1407N 070-32-13.4290W RWY FIT 02/20 348 3504 75 42-32-58.8143N 071-45-35.8666W 42-33-33.0907N 071-45-29.3344W RWY FIT 14/32 348 4510 100 42-33-27.8348N 071-45-55.5606W 42-33-00.1003N 071-45-08.4039W RWY GDM 18/36 954 3000 75 42-33-13.8618N 072-01-02.9031W 42-32-45.2655N 072-00-52.4259W RWY GBR 11/29 739 2579 50 42-11-04.6080N 073-24-28.6840W 42-11-01.7330N 073-23-54.6470W RWY 28M 18/36 71 1760 60 42-01-38.8728N 070-50-20.3362W 42-01-22.1393N 070-50-13.9859W RWY 1B6 18/36 269 3172 90 42-06-38.5550N 071-30-41.3020W 42-06-08.1050N 071-30-31.3550W RWY HYA 06/24 54 5425 150 41-39-52.5478N 070-16-57.9954W 41-40-27.1363N 070-16-03.3935W RWY HYA 15/33 54 5253 150 41-40-29.1794N 070-17-30.8321W 41-39-49.5579N 070-16-46.1408W RWY LWM 05/23 148 5001 150 42-42-39.2577N 071-07-44.0145W 42-43-18.0881N 071-07-02.6143W RWY LWM 14/32 148 3900 100 42-43-16.2633N 071-07-47.8805W 42-42-56.0207N 071-07-03.4262W RWY 1B9 04/22 122 2200 100 41-59-58.6678N 071-12-09.9458W 42-00-17.8811N 071-11-56.3104W RWY 1B9 14/32 122 3503 75 42-00-09.4306N 071-12-07.1481W 41-59-50.7927N 071-11-28.0603W RWY 9B1 14/32 285 1659 45 42-20-39.6381N 071-30-41.8051W 42-20-31.1185N 071-30-22.9320W RWY GHG 06/24 9 3900 100 42-05-37.6339N 070-40-41.5043W 42-06-04.3577N 070-40-04.2387W RWY 2B1 05/23 103 2035 50 41-40-58.1276N 070-24-09.2434W 41-41-13.4484N 070-23-55.6029W RWY 2B1 09/27 103 2700 60 41-41-03.3333N 070-24-27.2314W 41-41-10.6954N 070-23-56.2256W RWY 2B1 17/35 103 2060 60 41-41-16.0961N 070-24-14.0264W 41-41-00.1911N 070-24-03.7765W RWY 0B5 16/34 359 3200 75 42-35-42.3716N 072-31-35.7656W 42-35-17.2325N 072-31-09.8394W RWY ACK 06/24 47 6303 150 41-14-48.9863N 070-04-21.0972W 41-15-33.0124N 070-03-22.7304W RWY ACK 12/30 47 2696 50 41-15-09.9678N 070-03-43.8865W 41-15-02.1033N 070-03-10.1647W RWY ACK 15/33 47 4500 100 41-15-28.8294N 070-03-38.9543W 41-14-57.3825N 070-02-57.3061W RWY EWB 05/23 79 5400 150 41-40-16.5375N 070-57-53.8837W 41-40-58.3204N 070-57-09.6421W RWY EWB 14/32 79 5000 150 41-40-49.0738N 070-57-50.1562W 41-40-18.3320N 070-56-58.5878W RWY 2B2 10/28 11 2105 50 42-47-42.7100N 070-50-36.1100W 42-47-43.8600N 070-50-07.9200W RWY AQW 11/29 654 4300 100 42-41-48.9420N 073-10-42.5926W 42-41-44.0853N 073-09-45.3893W RWY 7B2 14/32 121 3335 50 42-19-50.8900N 072-36-58.0500W 42-19-30.7800N 072-36-22.8800W RWY OWD 10/28 49 3995 75 42-11-31.5995N 071-10-42.6240W 42-11-32.4597N 071-09-49.5600W RWY OWD 17/35 49 4008 100 42-11-37.6464N 071-10-40.3357W 42-11-01.8310N 071-10-17.6405W RWY ORE 01/19 556 4999 75 42-33-40.4620N 072-17-25.0761W 42-34-29.8396N 072-17-24.3848W RWY ORE 14/32 556 4801 75 42-34-33.4277N 072-17-37.7867W 42-34-04.8263N 072-16-46.6170W RWY 13MA 04/22 418 2475 55 42-13-13.2340N 072-18-48.6930W 42-13-34.8340N 072-18-33.2930W RWY PSF 08/26 1188 5791 100 42-25-28.4465N 073-18-00.8516W 42-25-53.2822N 073-16-51.3048W RWY PSF 14/32 1188 3496 100 42-25-46.4113N 073-17-48.1778W 42-25-27.7098N 073-17-09.0000W RWY PYM 06/24 148 4350 75 41-54-15.2483N 070-44-11.4665W 41-54-48.3795N 070-43-34.8345W RWY PYM 15/33 148 3351 75 41-54-43.9248N 070-43-48.3503W 41-54-22.8302N 070-43-14.2041W RWY PVC 07/25 8 3502 100 42-04-11.3870N 070-13-34.6087W 42-04-29.0450N 070-12-54.6840W RWY 3B0 02/20 699 3501 75 42-05-46.8699N 072-02-23.0285W 42-06-21.1226N 072-02-16.5979W RWY 60M 01/19 1040 1949 50 42-17-16.3890N 071-57-52.8480W 42-17-35.1364N 071-57-52.9051W RWY CEF 05/23 241 11598 301 42-10-38.8680N 072-32-52.8250W 42-12-13.6300N 072-31-26.2390W RWY CEF 15/33 241 7082 150 42-12-23.1740N 072-32-31.4360W 42-11-33.7090N 072-31-24.8990W RWY 3B3 16/34 459 3086 40 42-25-44.8581N 071-47-47.5912W 42-25-21.6396N 071-47-20.9349W RWY 6B6 03/21 268 2770 48 42-27-27.0700N 071-31-12.5500W 42-27-53.2900N 071-31-01.9400W RWY 6B6 12/30 268 1600 70 42-27-37.3100N 071-31-09.1400W 42-27-32.8100N 071-30-48.6800W RWY TAN 04/22 42 1900 60 41-52-31.5570N 071-01-21.7240W 41-52-48.3440N 071-01-10.5040W RWY TAN 12/30 42 3500 75 41-52-26.8885N 071-01-11.3423W 41-52-16.3914N 071-00-27.2727W RWY MVY 06/24 67 5504 100 41-23-11.9581N 070-37-09.6025W 41-23-53.2384N 070-36-22.5953W RWY MVY 15/33 67 3328 75 41-23-53.1325N 070-37-12.8822W 41-23-31.7310N 070-36-39.7436W RWY BAF 02/20 270 9000 150 42-08-43.0807N 072-43-07.7517W 42-10-10.5755N 072-42-46.5557W RWY BAF 15/33 270 5000 100 42-09-50.7851N 072-43-18.3599W 42-09-12.8399N 072-42-35.8716W RWY ORH 11/29 1009 7001 150 42-16-02.3866N 071-53-26.8657W 42-15-57.7511N 071-51-53.9652W RWY ORH 15/33 1009 5000 100 42-16-22.2435N 071-52-43.1427W 42-15-45.6872N 071-51-58.4327W RWY LEW 04/22 288 5001 100 44-02-32.0609N 070-17-17.0073W 44-03-17.0375N 070-16-48.7404W RWY LEW 17/35 288 2750 75 44-03-05.8892N 070-17-06.5343W 44-02-42.8919N 070-16-46.5057W RWY 0B1 14/32 674 3818 75 44-25-41.6898N 070-48-56.9095W 44-25-19.4109N 070-48-14.4755W RWY B19 06/24 157 3000 75 43-27-39.5900N 070-28-33.9100W 43-28-02.0310N 070-28-07.3560W RWY 3S2 12/30 418 1808 40 44-30-55.4623N 070-24-35.2991W 44-30-46.4213N 070-24-13.7906W RWY 3B4 12/30 125 2701 50 43-08-39.8770N 070-46-41.4600W 43-08-30.6900N 070-46-07.2800W RWY IZG 14/32 455 4200 75 43-59-40.4174N 070-57-15.4545W 43-59-15.7728N 070-56-29.2534W RWY 63B 11/29 292 2973 50 43-45-47.6552N 070-40-41.1049W 43-45-46.1615N 070-40-00.6509W RWY B10 02/20 324 2201 120 44-24-25.2681N 070-08-48.0884W 44-24-46.7828N 070-08-43.7530W RWY 81B 15/33 345 2997 75 44-09-36.5485N 070-29-08.0249W 44-09-16.9417N 070-28-37.2376W RWY PWM 11/29 76 7200 150 43-38-45.1032N 070-19-33.8651W 43-38-38.5209N 070-17-56.3694W RWY PWM 18/36 76 6100 150 43-39-16.1036N 070-18-26.3497W 43-38-18.4236N 070-18-02.3920W RWY 8B0 14/32 1825 3201 75 44-59-38.8973N 070-40-11.7663W 44-59-22.7327N 070-39-33.4910W RWY SFM 07/25 244 6389 100 43-23-12.0113N 070-43-11.0761W 43-23-45.1011N 070-41-57.4240W RWY SFM 14/32 244 4999 100 43-24-01.2346N 070-42-51.5048W 43-23-37.3650N 070-41-52.2291W RWY 3B5 11/29 355 2151 100 44-11-20.8805N 070-14-14.2667W 44-11-16.8859N 070-13-45.2725W RWY 3B5 12/30 355 2104 50 44-11-25.1339N 070-14-10.3598W 44-11-18.0172N 070-13-43.2327W RWY BML 18/36 1161 5200 100 44-34-55.3055N 071-10-46.1690W 44-34-07.3452N 071-10-20.5129W RWY CNH 11/29 544 3098 100 43-22-14.6616N 072-22-26.4877W 43-22-12.9693N 072-21-44.6057W RWY 4C4 04/22 1017 2466 75 44-53-03.8538N 071-30-34.4136W 44-53-26.3161N 071-30-21.2028W RWY CON 12/30 342 3200 75 43-12-27.6376N 071-30-24.8828W 43-12-19.4407N 071-29-43.1570W RWY CON 17/35 342 6005 100 43-12-29.4152N 071-30-27.5807W 43-11-35.6341N 071-29-53.3882W RWY 1B5 18/36 978 2305 150 44-11-53.2110N 071-45-04.0799W 44-11-30.6490N 071-44-59.8335W RWY 2G8 12/30 835 2822 70 44-23-41.0400N 071-12-11.6700W 44-23-32.7500N 071-11-34.5700W RWY 5B9 01/19 582 2511 58 44-04-36.3440N 072-00-25.5595W 44-05-00.9005N 072-00-30.3121W RWY 8B1 02/20 600 3260 75 43-03-24.4638N 071-54-18.7749W 43-03-56.6627N 071-54-19.7859W RWY AFN 16/34 1040 2982 134 42-48-30.9800N 072-00-21.4670W 42-48-05.9920N 072-00-00.2950W RWY EEN 02/20 488 6201 100 42-53-14.3530N 072-16-15.1370W 42-54-15.5090N 072-16-10.4340W RWY EEN 14/32 488 4001 150 42-54-20.5720N 072-16-39.3950W 42-53-56.7400N 072-15-56.5160W RWY LCI 08/26 545 5890 100 43-34-11.8400N 071-25-41.2000W 43-34-34.0600N 071-24-27.2600W RWY LEB 07/25 603 5496 100 43-37-33.0158N 072-18-43.4102W 43-38-00.7239N 072-17-39.1615W RWY LEB 18/36 603 5200 100 43-37-45.5076N 072-18-26.5069W 43-36-55.2804N 072-18-11.7787W RWY MHT 06/24 266 7651 150 42-55-41.8490N 071-26-56.6184W 42-56-37.6303N 071-25-47.2381W RWY MHT 17/35 266 9250 150 42-56-30.3568N 071-26-22.4471W 42-55-06.5585N 071-25-32.9183W RWY ASH 14/32 200 6000 100 42-47-12.6982N 071-31-24.5987W 42-46-40.6791N 071-30-16.8912W RWY 2B3 12/30 783 2140 80 43-23-25.2600N 072-11-40.6800W 43-23-19.8000N 072-11-12.6700W RWY 2B3 18/36 783 3448 50 43-23-25.0800N 072-11-14.0500W 43-22-51.9800N 072-11-03.1300W RWY 1P1 12/30 506 2347 90 43-46-43.4000N 071-45-29.7100W 43-46-40.0300N 071-44-58.0100W RWY PSM 16/34 100 11321 150 43-05-28.6003N 070-50-02.9997W 43-03-52.6772N 070-48-44.6011W RWY DAW 15/33 322 4201 75 43-17-16.8600N 070-56-07.8100W 43-16-49.6307N 070-55-24.9464W RWY 8B2 09/27 1459 2660 60 44-15-47.0005N 071-33-05.8723W 44-15-54.2608N 071-32-30.7182W RWY HIE 10/28 1072 4001 75 44-22-02.2111N 071-33-12.4256W 44-22-04.1791N 071-32-17.4102W RWY 13N 06/24 600 1924 135 40-57-50.3780N 074-47-01.8339W 40-58-05.2678N 074-46-46.2312W RWY 12N 03/21 583 1981 50 41-00-21.9160N 074-44-21.6280W 41-00-40.1460N 074-44-12.2160W RWY BLM 03/21 153 3512 50 40-10-50.1026N 074-07-28.0973W 40-11-22.3392N 074-07-11.3304W RWY BLM 14/32 153 7371 85 40-11-39.7980N 074-08-07.5318W 40-10-50.6043N 074-06-57.5074W RWY 1N7 07/25 372 3112 70 40-58-08.5723N 075-00-08.7156W 40-58-23.5863N 074-59-33.3155W RWY CDW 04/22 172 4552 80 40-52-03.9352N 074-17-10.8170W 40-52-43.0377N 074-16-41.5437W RWY CDW 10/28 172 3719 75 40-52-37.5789N 074-17-12.8333W 40-52-41.9578N 074-16-24.7665W RWY 2N6 11/29 78 1590 70 40-01-38.7101N 074-41-37.3285W 40-01-36.3837N 074-41-17.1095W RWY NEL 06/24 101 5002 150 40-01-53.4600N 074-21-23.6700W 40-02-24.8900N 074-20-34.0400W RWY NEL 15/33 101 5001 150 40-02-22.6400N 074-21-37.0300W 40-01-44.5000N 074-20-56.1400W RWY N12 06/24 42 2987 60 40-03-50.7427N 074-10-53.3103W 40-04-10.7900N 074-10-25.1100W RWY N07 01/19 182 2942 40 40-56-36.7900N 074-18-50.6900W 40-57-05.7700N 074-18-53.7700W RWY LDJ 09/27 22 4140 100 40-36-57.7599N 074-15-06.5453W 40-37-07.8766N 074-14-14.5329W RWY 47N 07/25 86 3510 50 40-31-18.3101N 074-36-12.7118W 40-31-37.6562N 074-35-34.9826W RWY MMU 05/23 187 5998 150 40-47-35.1745N 074-25-09.2717W 40-48-23.0603N 074-24-23.3114W RWY MMU 13/31 187 3997 150 40-48-03.3765N 074-25-28.3209W 40-47-47.3569N 074-24-40.8137W RWY EWR 04L/22R 17 11000 150 40-40-31.3716N 074-10-46.0209W 40-42-09.2091N 074-09-43.8255W RWY EWR 04R/22L 17 10000 150 40-40-39.2984N 074-10-27.2835W 40-42-08.2438N 074-09-30.7308W RWY EWR 11/29 17 6726 150 40-42-10.0955N 074-10-50.5467W 40-42-04.3181N 074-09-23.5515W RWY 3N6 06/24 87 3594 50 40-19-34.8660N 074-21-04.6200W 40-20-00.2880N 074-20-32.2200W RWY N40 07/25 560 2900 50 40-33-48.8000N 074-59-00.7600W 40-34-05.5520N 074-58-30.2580W RWY 39N 10/28 128 3499 75 40-23-56.5190N 074-39-55.0376W 40-23-56.9202N 074-39-09.8093W RWY 3NJ6 02/20 72 4002 60 40-00-36.0840N 074-50-31.9930W 40-01-15.3300N 074-50-25.5700W RWY N51 04/22 189 5598 50 40-34-26.5400N 074-44-25.7600W 40-35-14.6800N 074-43-50.0300W RWY N51 10/28 189 2010 100 40-34-54.6323N 074-44-36.2616W 40-34-57.7900N 074-44-10.5400W RWY N51 13/31 189 3444 200 40-35-19.1800N 074-44-32.0200W 40-35-02.4300N 074-43-53.1700W RWY N87 11/29 118 4275 75 40-12-52.2219N 074-36-33.8307W 40-12-48.1522N 074-35-38.9852W RWY SMQ 08/26 106 1923 100 40-37-34.7885N 074-40-18.3014W 40-37-41.4987N 074-39-54.9757W RWY SMQ 12/30 106 2739 65 40-37-36.8922N 074-40-30.9657W 40-37-28.0959N 074-39-57.3794W RWY SMQ 17/35 106 1700 150 40-37-37.9470N 074-40-18.4900W 40-37-22.0162N 074-40-11.4905W RWY FWN 03/21 421 3499 75 41-11-44.0940N 074-37-29.2190W 41-12-17.3370N 074-37-16.6570W RWY TEB 01/19 8 7000 150 40-50-19.2556N 074-03-37.3336W 40-51-28.2827N 074-03-32.2422W RWY TEB 06/24 8 6013 150 40-50-48.2225N 074-04-13.0579W 40-51-27.8633N 074-03-14.7450W RWY TTN 06/24 213 6006 150 40-16-11.1093N 074-49-17.6762W 40-16-51.9803N 074-48-21.4911W RWY TTN 16/34 213 4800 150 40-17-01.3754N 074-49-04.7002W 40-16-22.2122N 074-48-29.7608W RWY 4N1 06/24 790 3471 60 41-07-30.6581N 074-21-04.3220W 41-07-53.6822N 074-20-30.7005W RWY WRI 06/24 141 10014 150 40-00-15.9347N 074-35-51.1635W 40-01-24.9680N 074-34-18.9460W RWY WRI 18/36 141 7126 150 40-01-38.9716N 074-36-11.0955W 40-00-29.1074N 074-35-59.5750W RWY 7NY8 09/27 773 1400 250 42-57-48.6200N 074-07-41.3500W 42-57-50.5700N 074-07-22.6800W RWY ALB 01/19 285 8500 150 42-44-13.7922N 073-48-15.3198W 42-45-37.7058N 073-48-18.9573W RWY ALB 10/28 285 7200 150 42-44-56.9415N 073-48-43.5284W 42-44-59.1972N 073-47-07.0866W RWY 1C3 03/21 330 2400 87 43-15-04.8463N 073-28-16.8353W 43-15-27.7790N 073-28-08.5967W RWY 3C8 14/32 75 10001 200 40-55-25.7850N 072-47-38.4750W 40-54-20.7670N 072-46-00.3780W RWY 1B8 05/23 510 2130 65 43-03-00.7613N 073-21-54.8147W 43-03-18.6483N 073-21-39.6989W RWY NY02 06/24 1960 2290 40 42-29-08.9000N 074-46-56.9700W 42-29-22.9600N 074-46-33.0100W RWY 4B1 10/28 714 2600 45 42-45-34.8208N 074-08-22.1492W 42-45-36.2041N 074-07-47.3386W RWY HTO 10/28 55 4255 100 40-57-31.9776N 072-15-37.0828W 40-57-32.7662N 072-14-41.6308W RWY HTO 16/34 55 2060 75 40-57-45.7840N 072-15-05.8826W 40-57-28.3184N 072-14-52.0902W RWY 1F2 01/19 1070 2000 100 43-13-22.2128N 074-06-53.7688W 43-13-41.9699N 074-06-53.4423W RWY N89 04/22 292 3838 75 41-43-28.1070N 074-22-50.4030W 41-43-59.8630N 074-22-22.7370W RWY FRG 01/19 80 5516 150 40-43-18.2850N 073-24-51.3346W 40-44-12.7867N 073-24-52.3624W RWY FRG 14/32 80 6833 150 40-44-04.6770N 073-25-18.2521W 40-43-19.2856N 073-24-12.5504W RWY 0B8 07/25 9 1792 75 41-15-04.0560N 072-02-04.3100W 41-15-12.5720N 072-01-43.7400W RWY 0B8 12/30 9 2328 100 41-15-09.4160N 072-02-08.5930W 41-15-05.0720N 072-01-38.6640W RWY 83K 04/22 261 2200 50 43-24-26.1400N 073-32-05.8800W 43-24-44.1600N 073-31-49.2300W RWY 1I5 12/30 440 2275 22 42-21-54.2389N 074-04-08.3847W 42-21-46.6326N 074-03-39.8614W RWY GFL 01/19 328 5000 150 43-20-08.4130N 073-36-31.2446W 43-20-57.7808N 073-36-33.1024W RWY GFL 12/30 328 3999 100 43-20-29.3211N 073-37-08.6080W 43-20-15.5297N 073-36-17.8956W RWY 1H4 17/35 840 1801 75 42-25-19.8300N 074-00-24.8400W 42-25-02.0400N 074-00-24.7800W RWY 1B1 03/21 198 5350 100 42-17-02.7795N 073-42-44.3149W 42-17-54.5443N 073-42-30.0036W RWY NY0 10/28 881 4000 75 42-59-53.3608N 074-20-13.3097W 42-59-53.6407N 074-19-19.4841W RWY 20N 15/33 147 3100 60 41-59-18.6462N 073-58-04.7115W 41-58-55.1442N 073-57-38.3961W RWY LKP 14/32 1747 4196 60 44-16-04.1802N 073-58-06.1571W 44-15-40.0456N 073-57-19.2945W RWY 1A1 03/21 297 2275 75 42-08-47.0695N 073-45-05.2383W 42-09-08.9376N 073-44-58.2405W RWY MAL 05/23 790 3994 100 44-50-58.1113N 074-20-10.6677W 44-51-29.6551N 074-19-37.3865W RWY MAL 14/32 790 3250 75 44-51-21.9048N 074-19-50.1990W 44-51-02.6424N 074-19-14.1261W RWY MSS 05/23 221 5601 100 44-55-48.1043N 074-50-57.8267W 44-56-35.3934N 074-50-17.4688W RWY MSS 09/27 221 4001 100 44-56-03.9741N 074-51-16.1313W 44-56-13.3748N 074-50-22.1168W RWY 21N 01/19 30 2200 60 40-59-02.1702N 072-31-08.6720W 40-59-23.9110N 072-31-09.0754W RWY 06N 08/26 523 2811 60 41-25-48.5426N 074-23-46.0317W 41-26-01.2238N 074-23-13.2081W RWY 44N 17/35 698 3830 60 41-42-43.5590N 073-44-28.4027W 41-42-09.8954N 073-44-05.3571W RWY MTP 06/24 7 3246 75 41-04-25.1107N 071-55-29.1606W 41-04-46.9723N 071-54-58.1459W RWY MGJ 03/21 364 5006 100 41-30-16.6460N 074-16-08.6202W 41-31-04.2775N 074-15-51.0801W RWY MGJ 08/26 364 3664 100 41-30-22.5068N 074-16-05.0130W 41-30-37.1011N 074-15-20.9397W RWY MSV 15/33 1403 6298 150 41-42-30.7526N 074-48-07.0808W 41-41-41.1058N 074-47-17.0473W RWY SWF 09/27 491 11817 150 41-30-03.0200N 074-07-49.9800W 41-30-26.5380N 074-05-17.8585W RWY SWF 16/34 491 6004 150 41-30-40.2511N 074-06-05.0299W 41-29-49.2055N 074-05-24.8352W RWY ISP 06/24 99 7006 150 40-47-19.0902N 073-06-44.8159W 40-48-08.0453N 073-05-40.4068W RWY ISP 10/28 99 5034 150 40-47-33.0994N 073-06-28.8035W 40-47-33.0982N 073-05-23.3547W RWY ISP 15L/33R 99 3175 75 40-47-56.5234N 073-05-54.1792W 40-47-34.3411N 073-05-24.9865W RWY ISP 15R/33L 99 5186 150 40-48-08.0173N 073-06-26.3880W 40-47-31.7742N 073-05-38.7259W RWY JFK 04L/22R 13 12079 200 40-37-19.2759N 073-47-08.1083W 40-39-01.8337N 073-45-47.9596W RWY JFK 04R/22L 13 8400 200 40-37-31.5320N 073-46-13.2500W 40-38-42.8490N 073-45-17.5090W RWY JFK 13L/31R 13 10000 150 40-39-27.9500N 073-47-24.8900W 40-38-37.4000N 073-45-33.4100W RWY JFK 13R/31L 13 14511 200 40-38-54.1020N 073-49-00.1730W 40-37-40.7810N 073-46-18.4130W RWY LGA 04/22 21 7001 150 40-46-08.9927N 073-53-02.8304W 40-47-07.5736N 073-52-14.4209W RWY LGA 13/31 21 7003 150 40-46-56.2698N 073-52-42.6775W 40-46-19.4573N 073-51-25.6016W RWY K09 04/22 1703 3016 60 43-26-58.9472N 074-31-04.4624W 43-27-24.5624N 074-30-43.5965W RWY PBG 17/35 234 11759 200 44-39-56.9979N 073-28-36.4070W 44-38-09.7502N 073-27-34.0879W RWY PTD 06/24 474 3703 60 44-40-22.8735N 074-57-12.1926W 44-40-49.1260N 074-56-36.5288W RWY POU 06/24 164 5001 100 41-37-18.9070N 073-53-31.2070W 41-37-50.1510N 073-52-40.1930W RWY POU 07/25 164 1358 100 41-37-29.9188N 073-53-17.4370W 41-37-38.3941N 073-53-03.5904W RWY POU 15/33 164 2744 100 41-37-48.8020N 073-53-06.5544W 41-37-28.4415N 073-52-42.7076W RWY 46N 01/19 323 2664 30 41-58-51.6653N 073-50-09.8441W 41-59-17.9811N 073-50-09.2609W RWY W57 14/32 178 1927 76 42-55-58.2900N 073-46-25.1800W 42-55-46.2200N 073-46-05.1300W RWY SLK 05/23 1663 6573 150 44-22-48.7500N 074-12-47.7907W 44-23-41.9807N 074-11-56.0162W RWY SLK 09/27 1663 3998 100 44-22-49.8109N 074-12-49.8507W 44-22-57.2591N 074-11-55.7914W RWY 5B2 05/23 434 4699 100 43-02-43.5376N 073-52-02.5082W 43-03-19.8566N 073-51-23.0976W RWY 5B2 14/32 434 4000 100 43-03-15.9375N 073-52-01.7954W 43-02-51.3307N 073-51-19.6466W RWY SCH 04/22 378 7001 150 42-50-48.8299N 073-56-01.6674W 42-51-50.9853N 073-55-20.4820W RWY SCH 10/28 378 4850 150 42-50-54.3014N 073-56-26.6923W 42-50-56.0484N 073-55-21.6301W RWY B04 02/20 100 2500 90 43-03-51.2100N 073-35-03.1600W 43-04-15.8200N 073-35-00.4900W RWY HWV 06/24 81 4200 100 40-49-17.7701N 072-52-22.5022W 40-49-47.1208N 072-51-43.8781W RWY HWV 15/33 81 4222 150 40-49-20.4374N 072-52-17.9787W 40-48-50.9427N 072-51-39.1478W RWY 4B0 01/19 196 2853 60 42-33-24.6031N 073-50-00.1619W 42-33-52.6209N 073-50-04.2993W RWY 09N 02/20 450 1863 75 41-49-48.2955N 073-52-34.8494W 41-50-06.6799N 073-52-33.5622W RWY N69 06/24 358 3315 50 41-34-25.7800N 073-44-12.2300W 41-34-48.4100N 073-43-40.7000W RWY 4B6 02/20 274 4041 60 43-52-18.2337N 073-24-48.4682W 43-52-58.1043N 073-24-46.1090W RWY 5B7 18/36 440 2670 50 42-41-42.3800N 073-34-53.7319W 42-41-17.4253N 073-34-42.1357W RWY FOK 01/19 66 5001 150 40-50-05.6891N 072-38-13.1014W 40-50-55.0546N 072-38-15.9436W RWY FOK 06/24 66 9001 150 40-50-10.4696N 072-38-20.4395W 40-51-16.0334N 072-37-01.3012W RWY FOK 15/33 66 5003 150 40-50-49.8193N 072-38-22.7072W 40-50-16.4144N 072-37-34.7218W RWY HPN 11/29 439 4451 150 41-04-01.3869N 073-42-56.7374W 41-03-51.9409N 073-41-59.9931W RWY HPN 16/34 439 6549 150 41-04-31.9924N 073-42-47.9011W 41-03-36.0022N 073-42-05.0481W RWY N82 05/23 548 3591 60 41-35-37.3021N 074-27-49.2168W 41-36-06.0934N 074-27-21.5922W RWY N82 09/27 548 1101 110 41-35-53.7290N 074-27-32.1123W 41-35-56.0403N 074-27-17.9580W RWY N82 14/32 548 2092 120 41-35-53.1051N 074-27-33.5722W 41-35-40.4358N 074-27-11.8184W RWY N82 18/36 548 1250 150 41-35-50.6960N 074-27-31.6004W 41-35-38.3962N 074-27-30.1013W RWY BID 10/28 108 2502 100 41-10-03.8872N 071-34-56.4903W 41-10-06.5646N 071-34-23.9680W RWY UUU 04/22 172 2999 75 41-31-39.2985N 071-16-58.9974W 41-32-06.4015N 071-16-43.0766W RWY UUU 16/34 172 2623 75 41-32-11.7013N 071-17-06.6887W 41-31-50.8585N 071-16-46.1928W RWY OQU 05/23 18 4000 75 41-35-18.9393N 071-24-47.4694W 41-35-51.5188N 071-24-17.6735W RWY OQU 16/34 18 7504 150 41-36-27.8143N 071-25-18.0112W 41-35-27.0825N 071-24-21.3713W RWY SFZ 05/23 441 5000 100 41-54-59.8847N 071-29-44.9665W 41-55-41.7462N 071-29-09.8510W RWY SFZ 15/33 441 3211 75 41-55-17.2020N 071-29-45.4356W 41-54-53.0785N 071-29-17.8568W RWY PVD 05/23 55 7166 150 41-42-49.7723N 071-26-05.8486W 41-43-49.6961N 071-25-15.5354W RWY PVD 16/34 55 6081 150 41-43-53.9542N 071-25-55.8304W 41-43-06.8846N 071-25-05.9925W RWY WST 07/25 81 4010 100 41-20-44.1520N 071-48-38.1230W 41-21-07.8750N 071-47-56.0210W RWY WST 14/32 81 3960 75 41-21-13.9750N 071-48-27.3280W 41-20-48.7800N 071-47-47.6100W RWY 08R 11/29 130 2129 30 41-29-23.6949N 071-37-28.1457W 41-29-20.7366N 071-37-00.4473W RWY MPV 05/23 1166 3000 75 44-12-17.4985N 072-33-47.5999W 44-12-42.5200N 072-33-25.5400W RWY MPV 17/35 1166 5002 100 44-12-23.8349N 072-34-04.0190W 44-11-40.3611N 072-33-31.4575W RWY DDH 13/31 827 3704 75 42-53-37.0145N 073-15-07.7591W 42-53-19.6245N 073-14-23.9887W RWY BTV 01/19 335 4112 75 44-27-49.7731N 073-09-03.6107W 44-28-29.9208N 073-09-12.0675W RWY BTV 15/33 335 8319 150 44-28-50.4280N 073-09-57.1631W 44-27-56.7294N 073-08-30.3457W RWY FSO 01/19 228 3000 60 44-56-10.4465N 073-05-47.0472W 44-56-39.5708N 073-05-54.6689W RWY 5B1 14/32 1194 2650 120 44-47-31.1354N 071-49-50.3996W 44-47-16.6766N 071-49-19.7627W RWY CDA 02/20 1188 3302 60 44-33-52.6903N 072-01-08.0626W 44-34-24.9386N 072-01-01.3605W RWY 6B0 01/19 490 2500 50 43-58-55.5500N 073-05-43.1500W 43-59-20.2300N 073-05-44.4300W RWY MVL 01/19 733 3700 75 44-31-45.4166N 072-36-49.6420W 44-32-21.9384N 072-36-51.0982W RWY EFK 05/23 934 3996 100 44-53-04.9734N 072-14-05.4980W 44-53-39.3050N 072-13-38.1514W RWY EFK 18/36 934 5000 100 44-53-35.6402N 072-13-47.9147W 44-52-49.3837N 072-13-23.6366W RWY 2B9 05/23 696 2300 80 43-52-51.8998N 072-15-16.0780W 43-53-10.8927N 072-14-58.8394W RWY RUT 01/19 787 5003 100 43-31-29.6175N 072-56-58.2106W 43-32-19.0110N 072-56-59.9556W RWY RUT 13/31 787 3170 75 43-31-44.8253N 072-57-16.8998W 43-31-29.8200N 072-56-39.1454W RWY VT8 01/19 325 3077 60 44-21-22.1000N 073-13-31.5700W 44-21-52.0800N 073-13-38.4700W RWY VSF 05/23 578 5501 100 43-20-20.1039N 072-31-16.5741W 43-21-04.7987N 072-30-34.2521W RWY VSF 11/29 578 3000 75 43-20-30.2285N 072-31-34.8224W 43-20-25.7817N 072-30-54.6864W RWY 0B7 04/22 1470 2575 30 44-06-51.7113N 072-49-46.2555W 44-07-13.5078N 072-49-28.0583W RWY 4V8 01/19 1953 2650 75 42-55-24.8250N 072-51-53.2750W 42-55-50.6150N 072-51-59.3800W ILS 23 ILS IMMU 110.30 40-47-32.376N 074-25-11.961W 40-48-13.206N 074-24-28.622W 179 6.00 216.00 3.00 ILS 23 ILS/DME IFMH 109.55 41-38-52.551N 070-31-56.668W 41-39-57.057N 070-30-55.811W 122 4.43 218.82 3.00 ILS 16 LOC/DME IBVY 110.50 42-34-49.697N 070-54-33.073W - - 91 6.00 140.74 - ILS 22L ILS/DME ILSQ 108.70 40-40-28.953N 074-10-33.865W 40-41-43.673N 074-09-41.737W 7 4.27 205.74 3.00 ILS 11 ILS/DME IGPR 109.15 40-42-09.294N 074-10-04.985W 40-42-10.837N 074-10-35.030W 10 5.00 94.00 3.00 ILS 31R ILS/DME IRTH 111.50 40-39-30.778N 073-47-31.088W 40-38-50.324N 073-45-51.024W 10 4.20 300.87 3.00 ILS 22R ILS/DME IJNN 110.75 40-40-22.392N 074-10-51.726W 40-41-47.559N 074-09-53.883W 8 3.79 205.73 3.10 ILS 05 ILS IMSS 108.70 44-56-44.030N 074-50-10.100W 44-55-59.020N 074-50-55.007W 201 6.00 31.14 3.00 ILS 26 LOC/DME IEIF 108.30 42-25-24.329N 073-18-12.344W - - 1207 5.94 244.17 - ILS 33 ILS/DME IVOE 110.30 44-28-56.256N 073-10-06.606W 44-28-08.824N 073-08-43.042W 334 5.98 310.91 3.20 ILS 04 ILS ILGA 110.50 40-47-15.861N 073-52-07.568W 40-46-19.527N 073-52-57.966W 11 5.03 32.04 3.10 ILS 15R ILS/DME IMDC 110.70 42-21-26.359N 070-59-37.052W 42-22-14.695N 071-00-42.421W 11 4.95 133.39 3.00 ILS 22 LOC/DME IOTI 108.50 41-31-33.392N 071-17-02.472W - - 153 6.00 203.74 - ILS 35 ILS/DME IMHT 109.10 42-56-43.521N 071-26-30.231W 42-55-26.665N 071-25-39.817W 248 4.07 336.59 3.00 ILS 06 ILS/DME IBDR 110.70 41-09-55.581N 073-07-09.954W 41-09-30.188N 073-07-43.097W 4 5.00 47.00 3.00 ILS 19 ILS/DME IALB 109.50 42-44-03.937N 073-48-14.869W 42-45-27.446N 073-48-13.080W 273 4.22 178.17 3.00 ILS 05 ILS/DME IGON 111.30 41-20-16.590N 072-02-11.290W 41-19-35.205N 072-02-44.231W 4 6.00 33.91 3.00 ILS 16 ILS IPGQ 110.10 43-03-43.949N 070-48-37.478W 43-05-12.083N 070-49-53.581W 98 3.47 149.17 3.00 ILS 27 ILS/DME IDGU 111.30 42-21-18.475N 071-00-59.049W 42-21-31.295N 070-59-28.355W 12 5.03 256.52 3.00 ILS 14 ILS IASH 109.70 42-46-37.156N 071-30-09.445W 42-47-08.603N 071-31-12.833W 196 6.00 122.80 3.00 ILS 05 LOC/DME IVSF 111.30 43-20-56.840N 072-30-36.777W - - 553 6.00 36.39 - ILS 24 ILS/DME IMYQ 111.10 41-55-47.664N 072-41-57.628W 41-56-53.576N 072-40-25.963W 157 3.79 224.27 3.00 ILS 22L ILS/DME IIWY 110.90 40-37-27.509N 073-46-16.388W 40-38-32.953N 073-45-19.990W 13 4.52 210.67 3.00 ILS 03 ILS IMGJ 111.70 41-31-08.306N 074-15-49.600W 41-30-29.296N 074-16-09.090W 351 6.00 15.42 3.00 ILS 24 ILS/DME IMVY 108.70 41-23-04.360N 070-37-18.220W 41-23-47.590N 070-36-34.210W 57 6.00 220.49 3.00 ILS 13 ILS/DME IGDI 108.50 40-46-17.391N 073-51-21.276W 40-46-53.038N 073-52-30.836W 10 5.42 122.24 3.10 ILS 31L ILS IMOH 111.35 40-38-59.645N 073-49-12.422W 40-37-59.870N 073-47-09.421W 9 3.27 300.84 3.00 ILS 22R ILS/DME IJOC 109.50 40-37-44.498N 073-46-43.090W 40-38-21.280N 073-46-13.909W 9 5.50 208.41 3.00 ILS 22L ILS/DME ILQN 110.30 42-21-00.041N 071-00-44.284W 42-22-17.003N 071-00-11.988W 11 3.86 199.67 3.00 ILS 20 ILS IBAF 111.90 42-08-34.519N 072-43-09.825W 42-10-01.796N 072-42-52.053W 264 4.06 190.18 3.00 ILS 23 ILS/DME IARJ 109.30 41-42-41.020N 071-26-13.190W 41-43-39.660N 071-25-17.420W 45 4.88 212.07 3.00 ILS 06 ILS IWRI 110.10 40-01-36.661N 074-34-03.327W 40-00-21.935N 074-35-35.728W 120 3.43 45.66 3.00 ILS 24 ILS/DME IACK 109.10 41-14-45.857N 070-04-25.248W 41-15-23.778N 070-03-27.578W 46 5.93 224.90 3.00 ILS 24 ILS/DME IHYA 109.15 41-39-50.587N 070-17-01.086W 41-40-19.244N 070-16-10.645W 38 6.00 229.70 3.00 ILS 01 ILS/DME IDEJ 109.50 42-45-47.687N 073-48-19.389W 42-44-24.904N 073-48-10.432W 279 4.22 358.18 3.00 ILS 16 ILS/DME IOQU 109.50 41-35-22.410N 071-24-17.020W 41-36-20.435N 071-25-06.312W 6 4.96 145.11 3.00 ILS 31 LOC/DME IPZV 108.50 40-46-45.554N 073-52-13.516W - - 22 6.00 304.00 - ILS 14 LOC/DME IBLM 109.75 40-10-48.578N 074-06-54.305W - - 159 5.60 132.48 - ILS 07 LOC/DME IRLS 108.90 41-21-11.454N 071-47-49.663W - - 77 6.00 53.11 - ILS 06 ILS IMJE 109.95 42-56-42.363N 071-25-41.347W 42-55-53.652N 071-26-46.588W 219 5.10 42.33 3.00 ILS 33 ILS/DME IIKX 108.55 41-56-40.160N 072-41-46.010W 41-55-54.769N 072-40-38.593W 167 5.05 314.48 3.00 ILS 35 ILS ICON 108.70 43-12-32.145N 071-30-29.323W 43-11-42.136N 071-30-02.646W 331 6.00 335.13 3.00 ILS 02 LDA IHFD 109.70 41-43-57.844N 072-39-05.144W - - 11 6.00 347.00 - ILS 13L ILS/DME ITLK 111.50 40-38-30.687N 073-45-18.566W 40-39-14.757N 073-47-04.857W 10 3.90 120.86 3.00 ILS 04L ILS/DME IEWR 110.75 40-42-18.192N 074-09-38.112W 40-41-02.167N 074-10-22.759W 7 4.23 25.74 3.10 ILS 04R ILS/DME IEZA 108.70 40-42-15.943N 074-09-25.835W 40-40-57.598N 074-10-09.878W 6 4.15 25.74 2.95 ILS 34 ILS/DME IUNQ 111.50 41-43-56.351N 071-25-58.363W 41-43-14.630N 071-25-11.670W 37 6.00 321.68 3.00 ILS 08 ILS/DME ILCI 108.50 43-34-37.194N 071-24-16.835W 43-34-18.560N 071-25-31.286W 537 5.96 67.47 3.00 ILS 04 ILS ILEW 108.90 44-03-19.736N 070-16-47.048W 44-02-39.687N 070-17-07.186W 265 6.00 24.31 3.00 ILS 15 ILS/DME IBCU 108.95 41-39-41.954N 070-16-37.566W 41-40-23.433N 070-17-18.485W 49 6.00 139.89 3.10 ILS 01 ILS IGFL 110.70 43-21-09.261N 073-36-33.534W 43-20-17.952N 073-36-36.665W 320 6.00 358.43 3.00 ILS 08 LOC/DME IDXR 111.55 41-22-13.413N 073-28-52.831W - - 466 6.00 73.00 - ILS 34 ILS IPSM 110.10 43-05-40.413N 070-50-12.666W 43-04-00.512N 070-48-59.037W 78 3.16 329.15 3.00 ILS 11 ILS/DME IRSR 110.90 42-15-57.558N 071-51-50.032W 42-15-58.379N 071-53-15.888W 976 5.48 93.85 3.00 ILS 24 ILS/DME IFOK 111.70 40-50-01.496N 072-38-31.268W 40-51-02.570N 072-37-09.171W 43 3.87 222.39 3.00 ILS 06 ILS ITEB 108.90 40-51-29.818N 074-03-11.862W 40-50-57.831N 074-04-06.543W 4 5.00 48.06 3.00 ILS 07 ILS ISFM 111.50 43-23-48.331N 070-41-50.214W 43-23-15.079N 070-42-55.862W 235 5.71 58.28 3.00 ILS 14 ILS IFRG 111.90 40-43-16.324N 073-24-08.233W 40-43-54.773N 073-24-57.727W 74 6.00 132.34 3.00 ILS 35 LOC/DME IOWD 108.30 42-11-45.287N 071-10-45.168W - - 61 6.00 334.86 - ILS 24 LOC/GS IJTQ 110.10 40-00-07.131N 074-36-02.919W 40-01-14.354N 074-34-23.732W 99 3.55 226.75 3.00 ILS 05 ILS ILWM 111.70 42-43-29.869N 071-06-50.081W 42-42-44.624N 071-07-32.682W 136 6.00 38.06 3.00 ILS 23 ILS ISLK 108.90 44-22-42.263N 074-12-54.093W 44-23-34.774N 074-12-08.065W 1657 5.44 214.80 3.20 ILS 09 ILS ISWF 110.10 41-30-27.398N 074-05-12.295W 41-30-13.362N 074-07-09.214W 470 3.91 78.34 3.00 ILS 18 ILS/DME IDVR 111.90 43-36-58.274N 072-18-18.269W 43-37-37.942N 072-18-19.632W 555 6.00 171.00 3.10 ILS 04L ILS/DME IHIQ 110.90 40-39-06.966N 073-45-43.947W 40-37-31.083N 073-46-54.912W 9 3.28 30.68 3.00 ILS 04R ILS/DME IJFK 109.50 40-38-51.570N 073-45-10.684W 40-37-42.101N 073-46-11.054W 12 4.25 30.68 3.00 ILS 24 ILS IRXN 108.30 40-47-15.266N 073-06-49.836W 40-48-02.176N 073-05-52.724W 91 5.31 224.88 3.00 ILS 22X LDA/DME ITKD 111.15 40-46-06.998N 073-53-07.630W - - 40 5.00 222.00 - ILS 27 ILS/DME IJKH 109.95 41-30-01.819N 074-07-57.726W 41-30-16.951N 074-05-56.694W 462 3.85 258.33 3.00 ILS 04R ILS/DME IBOS 110.30 42-22-55.974N 070-59-48.188W 42-21-21.823N 071-00-24.548W 10 3.67 19.68 3.00 ILS 19 ILS/DME ITJL 110.15 40-50-13.363N 074-03-37.774W 40-51-10.168N 074-03-30.148W 4 6.00 183.20 3.00 ILS 23 ILS ICEF 109.90 42-10-30.293N 072-33-00.658W 42-12-02.019N 072-31-27.214W 234 3.17 214.09 3.00 ILS 29 ILS/DME IEKW 110.90 42-16-02.784N 071-53-34.864W 42-16-00.966N 071-52-06.759W 987 5.27 273.86 3.00 ILS 35 ILS/DME IFQV 109.70 44-40-06.610N 073-28-41.994W 44-38-17.154N 073-27-44.358W 157 3.00 337.54 3.00 ILS 11 ILS/DME IPWM 109.90 43-38-37.591N 070-17-42.653W 43-38-40.081N 070-19-19.844W 68 4.88 95.33 3.00 ILS 06 ILS IHWV 108.95 40-49-55.503N 072-51-32.834W 40-49-22.133N 072-52-11.702W 67 6.00 44.89 3.00 ILS 17 ILS IPBG 109.70 44-37-58.464N 073-27-27.535W 44-39-48.133N 073-28-23.766W 223 5.00 157.55 3.00 ILS 34 ILS/DME IOJZ 109.70 41-04-36.959N 073-42-51.718W 41-03-44.112N 073-42-15.776W 374 5.61 330.00 3.00 ILS 36 ILS/DME IOXC 109.55 41-29-16.406N 073-08-14.131W 41-28-26.440N 073-08-06.995W 690 6.00 350.82 3.00 ILS 07 ILS/DME IVQO 111.10 42-04-32.124N 070-12-47.713W 42-04-12.687N 070-13-23.882W 7 6.00 59.22 3.00 ILS 29 ILS/DME IGCS 109.90 43-38-46.015N 070-19-47.591W 43-38-42.166N 070-18-07.856W 42 4.88 275.32 3.00 ILS 05 LOC/DME ISFZ 111.90 41-55-44.365N 071-29-07.649W - - 414 6.00 31.98 - ILS 19 ILS/DME IRUT 111.70 43-31-25.070N 072-56-58.047W 43-32-10.237N 072-57-01.341W 777 6.00 178.53 3.20 ILS 15 ILS IMSV 109.10 41-41-38.687N 074-47-14.613W 41-42-20.443N 074-48-01.647W 1401 6.00 143.05 3.00 ILS 11 ILS/DME IBED 111.15 42-28-07.917N 071-16-06.248W 42-28-21.195N 071-17-46.814W 127 4.62 97.16 3.00 ILS 33L ILS/DME ILIP 110.70 42-22-37.562N 071-01-18.090W 42-21-26.645N 070-59-34.713W 11 3.48 315.26 3.00 ILS 05 ILS IGWJ 109.90 42-12-23.018N 072-31-17.661W 42-11-00.113N 072-32-39.849W 230 3.14 34.10 3.00 ILS 15 ILS/DME IBTV 110.30 44-27-52.767N 073-08-23.954W 44-28-42.343N 073-09-51.471W 308 4.50 130.93 3.00 ILS 27 LOC/DME IIJD 108.35 41-44-36.037N 072-11-07.754W - - 252 6.00 254.38 - ILS 22 ILS IURD 110.50 40-46-05.930N 073-53-05.361W 40-46-57.749N 073-52-18.701W 9 5.44 212.03 3.00 ILS 04 ILS ISCH 109.70 42-51-59.625N 073-55-14.751W 42-50-58.785N 073-56-00.667W 325 5.02 25.91 3.00 ILS 02 ILS/DME IHVN 109.10 41-16-26.290N 072-53-13.320W 41-15-31.816N 072-53-20.432W 2 6.00 2.91 3.00 ILS 17 ILS/DME IMNA 109.10 42-54-57.425N 071-25-27.527W 42-56-20.859N 071-26-13.020W 220 4.04 156.61 3.10 ILS 22 LOCALIZER ICDW 109.35 40-52-00.797N 074-17-13.162W - - 174 6.00 209.51 - ILS 29 ILS/DME IULJ 111.15 42-28-19.801N 071-18-14.561W 42-28-14.328N 071-16-40.608W 120 5.00 277.16 3.00 ILS 17 ILS/DME IMPV 108.70 44-11-39.128N 072-33-30.534W 44-12-18.724N 072-33-55.823W 1103 6.00 151.77 3.00 ILS 06 ILS IPOU 111.30 41-37-55.910N 073-52-30.802W 41-37-26.683N 073-53-22.675W 149 6.00 50.67 3.00 ILS 32 ILS/DME IBNX 110.75 41-40-11.807N 070-32-33.532W 41-39-15.342N 070-30-44.080W 109 3.65 307.53 3.00 ILS 06 ILS/DME IBDL 111.10 41-57-17.850N 072-39-59.405W 41-56-05.542N 072-41-41.893W 169 3.43 44.28 3.00 ILS 02 ILS IEEN 108.90 42-54-22.455N 072-16-09.898W 42-53-23.656N 072-16-10.242W 476 5.81 3.23 3.00 ILS 06 ILS ITTN 111.30 40-16-56.131N 074-48-15.784W 40-16-19.713N 074-49-10.955W 167 6.00 46.37 3.00 ILS 16 ILS/DME IHPN 109.70 41-03-27.452N 073-41-58.501W 41-04-22.243N 073-42-34.555W 422 5.31 150.01 3.00 ILS 05 ILS/DME IEWB 109.70 41-41-03.158N 070-57-04.518W 41-40-21.941N 070-57-42.861W 61 6.00 38.34 3.00 ILS 05 ILS/DME IPVD 109.30 41-43-57.102N 071-25-09.327W 41-42-56.206N 071-25-53.979W 49 4.98 32.07 3.00 ILS 06 ILS/DME IRNE 109.10 41-15-41.152N 070-03-11.948W 41-14-57.461N 070-04-04.611W 32 5.80 44.90 3.00 ILS 06 ILS/DME IPYM 109.35 41-54-56.751N 070-43-25.572W 41-54-20.555N 070-44-00.460W 133 6.00 39.46 3.00 ILS 06 ILS/DME IISP 108.30 40-48-15.313N 073-05-30.846W 40-47-28.730N 073-06-39.490W 88 4.98 44.89 3.00 NAV BDR VOR/DME 41-09-38.495N 073-07-28.188W 9 108.80 25X NAV GON VOR/DME 41-19-49.448N 072-03-07.141W 9 110.85 45Y NAV HFD VOR/DME 41-38-27.977N 072-32-50.705W 849 114.90 096X NAV MAD VOR/DME 41-18-49.811N 072-41-31.893W 220 110.40 041X NAV HVN VOR/DME 41-15-44.314N 072-53-06.659W 6 109.80 035X NAV ORW VOR/DME 41-33-23.053N 071-59-57.672W 310 110.00 037X NAV JWE NDB 41-22-56.581N 073-06-44.983W 571 362 - NAV PUT VOR/DME 41-57-19.657N 071-50-38.741W 652 117.40 121X NAV BDL VORTAC 41-56-27.638N 072-41-18.881W 160 109.00 027X NAV SKR NDB 42-27-20.617N 071-10-42.714W 341 251 - NAV BOS VOR/DME 42-21-26.820N 070-59-22.374W 28 112.70 074X NAV LQ NDB 42-27-07.347N 070-57-47.878W 15 382 - NAV CTR VOR/DME 42-17-28.747N 072-56-57.819W 1600 115.10 098X NAV FM NDB 41-43-56.185N 070-26-29.005W 75 362 - NAV FMH TACAN 41-39-34.577N 070-30-50.208W 116 115.80 105X NAV FIT NDB 42-33-03.313N 071-45-25.718W 350 365 - NAV GDM VOR/DME 42-32-45.315N 072-03-29.478W 1280 110.60 43X NAV GBR NDB 42-10-58.722N 073-24-14.509W 726 395 - NAV LWM VOR/DME 42-44-25.496N 071-05-41.550W 306 112.50 072X NAV IHM NDB 42-00-09.994N 071-11-49.581W 165 220 - NAV IMR NDB 42-05-52.822N 070-40-32.866W 3 368 - NAV ACK VOR/DME 41-16-54.794N 070-01-36.157W 99 116.20 109X NAV LFV VOR/DME 42-01-01.876N 070-02-14.037W 151 114.70 094X NAV ORE NDB 42-34-07.003N 072-17-10.088W 545 205 - NAV PVC NDB 42-04-07.740N 070-13-24.396W 9 389 - NAV CEF VORTAC 42-11-51.160N 072-31-34.730W 241 114.00 87X NAV TAN NDB 41-52-31.723N 071-00-58.203W 29 227 - NAV MVY VOR/DME 41-23-46.352N 070-36-45.774W 62 114.50 092X NAV BAF VORTAC 42-09-43.053N 072-42-58.318W 266 113.00 077X NAV SZO NDB 43-54-14.557N 070-46-56.393W 953 227 - NAV ENE VOR/DME 43-25-32.420N 070-36-48.692W 192 117.10 118X NAV PH NDB 43-31-37.311N 070-05-29.163W 0 301 - NAV RQM NDB 44-56-04.546N 070-45-04.315W 1593 221 - NAV BML VOR/DME 44-38-00.259N 071-11-10.045W 1731 110.40 041X NAV CNH NDB 43-22-09.055N 072-22-16.259W 527 233 - NAV CON VOR/DME 43-13-11.233N 071-34-31.631W 715 112.90 076X NAV CO NDB 43-07-07.597N 071-27-08.746W 355 216 - NAV EEN VORTAC 42-47-39.400N 072-17-30.400W 1380 109.40 031X NAV LC NDB 43-32-11.930N 071-32-13.310W 740 328 - NAV LAH NDB 43-42-08.150N 072-10-38.865W 1190 276 - NAV LEB VOR/DME 43-40-43.883N 072-12-57.865W 1443 113.70 084X NAV IVV NDB 43-33-36.493N 072-27-56.403W 1162 379 - NAV MHT VOR/DME 42-52-06.708N 071-22-10.324W 470 114.40 091X NAV AS NDB 42-49-24.191N 071-36-07.964W 217 359 - NAV PSM VOR/DME 43-05-04.065N 070-49-55.152W 99 116.50 112X NAV ESG NDB 43-13-12.978N 070-49-41.914W 77 260 - NAV GMA NDB 44-21-44.437N 071-41-09.260W 1425 386 - NAV CAT NDB 40-44-26.810N 074-25-47.593W 250 254 - NAV COL VOR/DME 40-18-41.877N 074-09-35.018W 129 115.40 101X NAV NEL NDB 40-02-41.496N 074-20-07.722W 76 396 - NAV NEL TACAN 40-02-13.096N 074-21-11.317W 87 111.80 055X NAV RBV VORTAC 40-12-08.648N 074-29-42.094W 248 113.80 085X NAV BWZ VOR/DME 40-47-54.358N 074-49-18.597W 1050 114.20 089X NAV SBJ VOR/DME 40-34-58.963N 074-44-30.458W 189 112.90 076X NAV SAX VORTAC 41-04-03.157N 074-32-17.926W 1400 115.70 104X NAV STW VOR/DME 40-59-44.951N 074-52-08.509W 920 109.60 033X NAV TE NDB 40-48-15.956N 074-07-56.950W 16 214 - NAV TEB VOR/DME 40-50-55.394N 074-03-44.074W 2 108.40 021X NAV GXU VORTAC 40-00-34.110N 074-35-47.440W 118 110.60 043X NAV ALB VORTAC 42-44-50.210N 073-48-11.467W 272 115.30 100X NAV BBN NDB 40-40-21.070N 073-23-03.796W 0 275 - NAV CCC VOR/DME 40-55-46.625N 072-47-55.893W 85 117.20 119X NAV CAM VOR/DME 42-59-39.440N 073-20-38.468W 1490 115.00 097X NAV CRI VOR/DME 40-36-44.900N 073-53-40.000W 10 112.30 070X NAV CMK VOR/DME 41-16-48.321N 073-34-52.773W 694 116.60 113X NAV DPK VOR/DME 40-47-30.299N 073-18-13.168W 123 117.70 124X NAV DNY VOR/DME 42-10-41.810N 074-57-24.986W 2560 112.10 058X NAV HTO VORTAC 40-55-08.385N 072-19-00.136W 22 113.60 083X NAV GFL VORTAC 43-20-30.094N 073-36-42.323W 324 110.20 039X NAV PFH NDB 42-15-11.193N 073-43-24.286W 340 272 - NAV HUO VOR/DME 41-24-34.872N 074-35-29.739W 1300 116.10 108X NAV JJH NDB 42-59-57.915N 074-19-53.152W 867 523 - NAV IGN VOR/DME 41-39-55.619N 073-49-20.008W 582 117.60 123X NAV MSS VORTAC 44-54-51.918N 074-43-21.785W 198 114.10 088X NAV MS NDB 41-46-00.005N 074-51-38.564W 1387 359 - NAV OGY NDB 40-34-05.279N 073-52-58.689W 10 414 - NAV JFK VOR/DME 40-37-58.400N 073-46-17.000W 11 115.90 106X NAV LGA VOR/DME 40-47-01.376N 073-52-06.962W 9 113.10 078X NAV SW NDB 41-29-08.950N 074-13-40.497W 405 335 - NAV SKU NDB 41-31-40.837N 074-02-41.909W 520 261 - NAV OP NDB 40-58-37.353N 073-07-06.388W 0 316 - NAV PLB VORTAC 44-41-05.800N 073-31-21.623W 343 116.90 116X NAV PTD NDB 44-43-24.203N 074-52-57.704W 360 400 - NAV PO NDB 41-34-30.463N 073-57-53.473W 9 403 - NAV PWL VOR/DME 41-46-11.177N 073-36-01.985W 1250 114.30 090X NAV SLK NDB 44-28-36.628N 074-07-26.504W 1677 395 - NAV SLK VOR/DME 44-23-04.414N 074-12-16.207W 1647 109.20 029X NAV HEU NDB 42-51-15.053N 073-56-00.556W 333 356 - NAV FOK TACAN 40-50-15.977N 072-37-54.635W 50 111.00 047X NAV ARD VOR/DME 40-15-12.033N 074-54-27.405W 294 108.20 019X NAV SEY VOR/DME 41-10-02.768N 071-34-33.908W 100 117.80 125X NAV PVD VOR/DME 41-43-27.639N 071-25-46.699W 49 115.60 103X NAV MPV VOR/DME 44-05-07.738N 072-26-57.756W 2080 110.80 045X NAV BJA TACAN 44-28-36.960N 073-09-24.350W 308 112.40 71X NAV BTV VOR/DME 44-23-49.578N 073-10-57.485W 416 117.50 122X NAV LLX NDB 44-30-14.794N 072-01-45.308W 1020 353 - NAV RUT VOR/DME 43-31-35.805N 072-57-02.464W 782 111.00 47X NAV DYO NDB 43-42-22.131N 072-57-23.766W 1138 221 - NAV SXD NDB 43-16-11.869N 072-35-10.630W 870 265 - NAV VWD NDB 42-55-39.288N 072-51-50.352W 1920 224 - acm-6.0_20200416/objects/zones/usa/tucson.txt0000644000000000000000000002430413646045023017234 0ustar rootroot# Tucson area scenery. # Created: 2020-04-16 # Latitude range: [30N, 35N[ # Longitude range: [115W, 110W[ # 2017-10-04 Checked against https://nfdc.faa.gov/xwiki/bin/view/NFDC/56DaySub-2017-03-02 # "56 Day NASR Subscription - Effective March 2, 2017". # ?????: TEAM1_LOC 30N 115W 000 031 # ?????: TEAM1_LOC 30N 115W 000 031 GROUND_COLOR #305030 RWY 27AZ 17/35 2206 3906 40 33-55-28.9800N 113-10-04.2000W 33-54-50.3400N 113-10-04.0800W RWY P01 12/30 1458 3800 60 32-27-23.7000N 112-51-56.7500W 32-26-57.1100N 112-51-25.3900W RWY E51 05/23 4196 4552 60 34-35-25.8500N 113-10-44.1800W 34-35-42.9900N 113-09-53.8500W RWY E95 10/28 3831 4002 75 32-00-01.6715N 110-21-51.4938W 31-59-54.3782N 110-21-05.8293W RWY BXK 17/35 1033 5500 75 33-25-48.3240N 112-41-09.1010W 33-24-53.9450N 112-41-11.4000W RWY A09 17/35 485 4800 50 34-53-41.2000N 114-36-59.9000W 34-52-53.7100N 114-36-59.9000W RWY CGZ 05/23 1464 5200 100 32-57-04.7376N 111-46-26.9497W 32-57-30.5264N 111-45-34.1498W RWY P19 17/35 1177 3913 60 33-18-15.3140N 111-54-55.5520W 33-17-36.5950N 111-54-55.5930W RWY CHD 04L/22R 1243 4401 75 33-15-50.8078N 111-49-11.8273W 33-16-19.0137N 111-48-32.3495W RWY CHD 04R/22L 1243 4870 75 33-15-56.6084N 111-48-50.9868W 33-16-27.8124N 111-48-07.2947W RWY P08 05/23 1576 5564 150 32-56-01.1248N 111-26-07.4813W 32-56-28.4486N 111-25-10.8140W RWY P08 17/35 1576 3873 75 32-56-21.5107N 111-25-29.6960W 32-55-43.1962N 111-25-29.8689W RWY P52 14/32 3560 4252 75 34-44-07.3361N 112-02-17.0188W 34-43-29.0548N 112-01-55.9582W RWY E60 02/20 1511 3901 75 32-48-08.9324N 111-35-25.8282W 32-48-39.4646N 111-34-57.8810W RWY FHU 03/21 4719 4285 75 31-35-10.1480N 110-20-56.2906W 31-35-44.1424N 110-20-26.7031W RWY FHU 08/26 4719 12001 150 31-35-15.2281N 110-22-01.3797W 31-35-15.4464N 110-19-42.6768W RWY FHU 12/30 4719 5366 100 31-35-34.3510N 110-20-35.7654W 31-35-02.6253N 110-19-46.0296W RWY E63 04/22 789 5200 75 32-57-22.7900N 112-40-50.8400W 32-57-50.4300N 112-39-59.3500W RWY GXF 17/35 883 8500 150 32-53-58.3100N 112-43-10.4900W 32-52-34.1900N 112-43-10.7000W RWY GEU 01/19 1071 7150 100 33-31-05.0154N 112-18-00.7754W 33-32-08.7476N 112-17-24.1442W RWY LUF 03L/21R 1085 10012 150 33-31-22.7100N 112-23-54.8300W 33-32-35.6700N 112-22-34.8400W RWY LUF 03R/21L 1085 9904 150 33-31-36.5600N 112-23-23.6000W 33-32-48.7300N 112-22-04.4700W RWY P13 09/27 3261 6500 100 33-21-17.9375N 110-40-39.9857W 33-21-04.7356N 110-39-25.0041W RWY GYR 03/21 969 8500 150 33-24-50.7219N 112-23-02.2317W 33-25-56.9013N 112-22-00.3656W RWY P14 03/21 5262 6698 75 34-56-04.7696N 110-08-41.1119W 34-56-55.7933N 110-07-49.8343W RWY P14 11/29 5262 3202 120 34-56-26.7369N 110-08-41.7726W 34-56-10.7938N 110-08-08.5592W RWY E67 08/26 1833 3400 60 33-02-51.1000N 110-54-52.5600W 33-02-48.7800N 110-54-12.7000W RWY HII 14/32 783 8001 100 34-34-50.1791N 114-21-53.9720W 34-33-41.9020N 114-21-05.6214W RWY MZJ 12/30 1893 6849 150 32-30-59.3255N 111-19-59.5715W 32-30-11.5555N 111-19-02.8462W RWY FFZ 04L/22R 1394 3799 75 33-27-29.8835N 111-44-03.0576W 33-27-53.4533N 111-43-28.1417W RWY FFZ 04R/22L 1394 5101 100 33-27-21.2342N 111-44-02.7213W 33-27-52.8681N 111-43-15.8192W RWY OLS 03/21 3955 7200 100 31-24-39.1879N 110-51-22.4518W 31-25-28.3862N 110-50-22.3869W RWY P20 01/19 458 6250 100 34-08-31.6438N 114-16-20.6603W 34-09-27.1009N 114-15-47.7911W RWY PAN 06/24 5157 5504 75 34-15-18.0170N 111-20-53.1190W 34-15-31.2000N 111-19-49.5200W RWY DVT 07L/25R 1478 4500 75 33-41-20.9760N 112-05-22.0262W 33-41-24.0728N 112-04-28.9041W RWY DVT 07R/25L 1478 8196 100 33-41-12.6032N 112-05-46.5681W 33-41-18.2430N 112-04-09.8161W RWY A39 04/22 1306 4751 50 32-59-10.2300N 111-55-28.7500W 32-59-41.7200N 111-54-47.3400W RWY IWA 12C/30C 1384 10201 150 33-19-03.4054N 111-39-57.3239W 33-17-51.3360N 111-38-33.1882W RWY IWA 12L/30R 1384 9300 150 33-19-03.3224N 111-39-40.7262W 33-17-57.6145N 111-38-24.0276W RWY IWA 12R/30L 1384 10401 150 33-19-03.6143N 111-40-22.3237W 33-17-50.1431N 111-38-56.5337W RWY PHX 07L/25R 1135 10300 150 33-25-51.8088N 112-01-37.5649W 33-25-51.7274N 111-59-36.0454W RWY PHX 07R/25L 1135 7800 150 33-25-43.8912N 112-01-37.5673W 33-25-43.8360N 112-00-05.5440W RWY PHX 08/26 1135 11489 150 33-26-27.0986N 112-01-47.2574W 33-26-26.9641N 111-59-31.6879W RWY PRC 03L/21R 5045 4846 60 34-39-23.3700N 112-25-13.6100W 34-39-59.3754N 112-24-35.3500W RWY PRC 03R/21L 5045 7619 150 34-38-47.2900N 112-25-40.8000W 34-39-43.9100N 112-24-40.6600W RWY PRC 12/30 5045 4408 75 34-39-09.8579N 112-25-40.6779W 34-38-38.2236N 112-25-04.4008W RWY 44A 17/35 163 2800 60 32-31-12.5200N 114-41-54.3800W 32-30-44.8100N 114-41-53.9800W RWY E77 11/29 3272 4207 75 32-38-22.7857N 110-39-10.6532W 32-37-59.5843N 110-38-29.8179W RWY SDL 03/21 1510 8249 100 33-36-53.0117N 111-55-11.7848W 33-37-51.7182N 111-54-04.0392W RWY SEZ 03/21 4830 5132 100 34-50-37.2207N 111-47-40.4587W 34-51-12.6197N 111-46-56.3606W RWY E78 04/22 2409 5830 60 31-55-42.0925N 111-54-08.0784W 31-56-12.4139N 111-53-10.5051W RWY SOW 03/21 6415 3938 60 34-15-38.0060N 110-00-26.9116W 34-16-04.1715N 109-59-52.1771W RWY SOW 06/24 6415 7200 100 34-15-49.5912N 110-01-07.9157W 34-16-06.8439N 109-59-44.7084W RWY TYL 03/21 5823 7001 75 34-26-44.0334N 110-07-21.9716W 34-27-35.6401N 110-06-26.2800W RWY P29 06/24 4743 4430 60 31-40-08.7100N 110-01-41.3300W 31-40-24.7400N 110-00-53.6000W RWY AVQ 03/21 2031 3892 75 32-24-12.3801N 111-13-22.3745W 32-24-39.3827N 111-12-50.0095W RWY AVQ 12/30 2031 6901 100 32-25-03.6117N 111-13-34.3560W 32-24-14.9318N 111-12-37.9188W RWY TUS 03/21 2643 7000 150 32-07-01.8010N 110-57-32.5456W 32-07-50.7389N 110-56-34.9558W RWY TUS 11L/29R 2643 10996 150 32-07-24.1321N 110-56-52.4872W 32-06-07.1639N 110-55-22.1441W RWY TUS 11R/29L 2643 8408 75 32-07-19.5718N 110-56-58.7462W 32-06-20.7202N 110-55-49.6594W RWY DMA 12/30 2704 13643 200 32-10-48.5983N 110-53-53.1245W 32-09-09.2254N 110-52-05.6973W RWY RYN 06L/24R 2419 4900 75 32-08-28.3981N 111-10-56.9801W 32-08-44.7328N 111-10-03.3287W RWY RYN 06R/24L 2419 5503 75 32-08-24.5404N 111-10-45.5085W 32-08-42.8729N 111-09-45.2563W RWY RYN 15/33 2419 4000 75 32-08-43.3311N 111-10-49.2954W 32-08-04.6228N 111-10-39.6085W RWY E25 05/23 2379 6101 75 33-57-59.3754N 112-48-13.8203W 33-58-29.1557N 112-47-10.8263W RWY NYL 03L/21R 213 13300 200 32-38-12.4170N 114-37-45.8220W 32-39-46.8960N 114-35-57.5480W RWY NYL 03R/21L 213 9240 150 32-38-55.4600N 114-36-45.1040W 32-40-01.0790N 114-35-29.8560W RWY NYL 08/26 213 6146 150 32-39-57.2420N 114-36-20.3620W 32-39-58.1650N 114-35-08.4760W RWY NYL 17/35 213 5710 150 32-40-03.7490N 114-36-14.6920W 32-39-07.2550N 114-36-13.6070W RWY LGF 06/24 433 6043 100 32-51-35.2740N 114-24-03.0350W 32-51-49.7720N 114-22-54.3070W RWY LGF 18/36 433 6142 151 32-52-32.1350N 114-23-33.8540W 32-51-32.4590N 114-23-47.4500W RWY BLH 08/26 400 6543 150 33-36-59.7683N 114-43-39.8259W 33-36-59.5333N 114-42-22.4640W RWY BLH 17/35 400 5800 100 33-37-48.1258N 114-43-00.2703W 33-36-50.7511N 114-43-00.5427W RWY 49X 16/34 638 5000 75 34-32-08.6734N 114-25-55.0446W 34-31-19.2147N 114-25-55.1295W RWY EED 02/20 983 4235 100 34-45-51.7500N 114-37-23.0500W 34-46-28.3440N 114-36-58.3250W RWY EED 11/29 983 5005 100 34-46-01.4100N 114-38-01.1140W 34-45-37.3360N 114-37-08.7050W ILS 03R LOC/GS ILUF 108.70 33-33-00.880N 112-21-51.140W 33-31-47.800N 112-23-19.310W 1069 3.46 42.43 3.00 ILS 25L ILS/DME IRJG 110.75 33-25-43.900N 112-01-50.780W 33-25-40.930N 112-00-16.870W 1120 4.49 270.04 3.00 ILS 06R ILS/DME IIVI 111.10 32-08-47.886N 111-09-28.843W 32-08-30.122N 111-10-36.625W 2398 5.72 70.22 3.00 ILS 21L ILS/DME IPRC 108.50 34-38-39.774N 112-25-48.774W 34-39-34.954N 112-24-45.537W 4960 4.65 221.14 3.00 ILS 12 LOC/GS IAFB 109.30 32-09-00.630N 110-51-56.400W 32-10-39.610N 110-53-50.520W 2594 5.0 132.00 3.00 ILS 05 ILS ICGZ 111.15 32-57-33.610N 111-45-27.831W 32-57-10.875N 111-46-21.405W 1451 6.00 59.80 3.00 ILS 11L ILS/DME ITUS 111.70 32-05-53.509N 110-55-06.122W 32-07-14.768N 110-56-48.060W 2580 4.00 135.17 3.00 ILS 08 ILS/DME ISYQ 111.75 33-26-26.946N 111-59-19.745W 33-26-29.654N 112-01-24.630W 1114 3.46 90.07 3.00 ILS 26 LOC/GS IFHU 109.90 31-35-15.199N 110-22-16.408W 31-35-11.473N 110-19-53.649W 4606 3.02 269.89 3.00 ILS 30 ILS IDMA 109.30 32-11-02.818N 110-54-08.511W 32-09-15.893N 110-52-20.807W 2691 3.00 317.53 3.00 ILS 30C LOC/GS IIWA 110.15 33-19-13.059N 111-40-08.600W 33-18-01.860N 111-38-37.226W 1376 4.25 315.70 3.00 ILS 21L LOC/GS IEMJ 110.90 33-31-25.610N 112-23-35.610W 33-32-45.240N 112-22-16.310W 1083 3.52 235.00 3.00 ILS 07R ILS/DME IAHA 110.75 33-25-43.830N 111-59-52.330W 33-25-46.630N 112-01-25.090W 1108 4.49 90.04 3.00 ILS 07L ILS/DME IPHX 111.50 33-25-51.715N 111-59-20.415W 33-25-49.051N 112-01-25.219W 1106 3.46 90.05 3.00 ILS 26 ILS/DME ICWJ 111.75 33-26-27.108N 112-01-59.227W 33-26-29.600N 111-59-44.432W 1129 3.21 270.07 3.00 ILS 21R ILS IYUM 108.30 32-38-04.046N 114-37-55.407W 32-39-42.539N 114-37-10.284W 189 3.00 223.97 3.00 NAV BXK VORTAC 33-27-12.442N 112-49-28.530W 1060 110.60 043X NAV TFD VORTAC 32-53-09.076N 111-54-31.444W 1316 114.80 095X NAV CHD NDB 33-15-59.360N 111-48-28.490W 1238 407 - NAV ARH TACAN 31-35-08.093N 110-20-20.343W 4660 111.60 053X NAV DAO NDB 31-35-08.408N 110-20-39.309W 4654 410 - NAV FHU VOR/DME 31-35-22.762N 110-21-17.793W 4665 113.60 83X NAV GBN VORTAC 32-57-22.530N 112-40-27.378W 790 116.60 113X NAV LUF TACAN 33-32-15.660N 112-22-48.760W 1076 113.00 077X NAV AVQ NDB 32-24-42.615N 111-12-56.111W 2021 245 - NAV FFZ NDB 33-27-42.773N 111-43-59.113W 1392 281 - NAV ENZ NDB 31-25-16.919N 110-50-47.170W 3918 394 - NAV OLS VOR/DME 31-24-53.835N 110-50-56.032W 3877 108.20 019X NAV PXR VORTAC 33-25-58.874N 111-58-12.716W 1182 115.60 103X NAV IWA VORTAC 33-18-11.426N 111-39-05.174W 1366 113.30 080X NAV DRK VORTAC 34-42-09.197N 112-28-49.244W 4967 114.10 088X NAV SOW NDB 34-16-02.118N 110-00-29.572W 6403 206 - NAV DMA TACAN 32-09-35.697N 110-52-51.274W 2662 117.60 123X NAV RBJ NDB 32-04-26.550N 111-21-37.108W 2607 220 - NAV RYN NDB 32-08-19.626N 111-09-41.385W 2420 338 - NAV TUS VORTAC 32-05-42.734N 110-54-53.480W 2671 116.00 107X NAV BZA VORTAC 32-46-05.187N 114-36-10.607W 130 116.80 115X NAV NYL TACAN 32-38-48.482N 114-36-48.438W 192 113.70 084X NAV BLH VORTAC 33-35-45.833N 114-45-40.584W 410 117.40 121X NAV EED VORTAC 34-45-57.615N 114-28-26.775W 620 115.20 099X NAV PKE VORTAC 34-06-07.102N 114-40-55.439W 1000 117.90 126X NAV NOG NDB 31-13-00.000N 110-59-00.000W 0 265 - NAV PPE VOR/DME 31-23-00.000N 113-30-00.000W 0 112.10 058X acm-6.0_20200416/objects/zones/middleeast/0000755000000000000000000000000013175062137016502 5ustar rootrootacm-6.0_20200416/objects/zones/middleeast/iraq.txt0000644000000000000000000000105413175056766020212 0ustar rootrootTEAM1_LOC 33.334N 44.355E 112 154 TEAM2_LOC 33.258N 44.209E 113 140 GROUND_COLOR #CCAC5E # Al-Muthanna Military Airport: RWY OOOO 14/32 112 11181 150 33.334N 44.355E 33.320N 44.378E # Camp Rustamiyah: RWY ORAS 15/33 104 8293 150 33.284N 44.498E 33.267N 44.516E # Baghdad International Airport: #RWY ORBS 15L/33R 113 12000 200 33.227N 44.236E 33.271N 44.212E #RWY ORBS 15R/33L 113 12000 200 33.223N 44.230E 33.258N 44.209E RWY ORBS 15L/33R 113 12000 200 33.271N 44.212E 33.227N 44.236E RWY ORBS 15R/33L 113 12000 200 33.258N 44.209E 33.223N 44.230E acm-6.0_20200416/objects/missiles/0000755000000000000000000000000013175062137015061 5ustar rootrootacm-6.0_20200416/objects/missiles/aim9.obv0000644000000000000000000000250513100305074016416 0ustar rootrootAIM9M 66 5 1 -0.9167 0 0 2 -0.9167 0.0833 0 3 -1 0.1667 0 4 -1.6667 0.25 0 5 -1.8333 0.25 0 6 -2.3333 0.8333 0 7 -2.4167 1 0 8 -2.4167 0.25 0 9 -7.5833 0.25 0 10 -8 1 0 11 -9 1 0 12 -9 -1 0 13 -8 -1 0 14 -7.5833 -0.25 0 15 -2.4167 -0.25 0 16 -2.4167 -1 0 17 -2.3333 -0.8333 0 18 -1.8333 -0.25 0 19 -1.6667 -0.25 0 20 -1 -0.1667 0 21 -0.9167 -0.0833 0 1 -0.9167 0 0 2 -0.9167 0 0.0833 3 -1 0 0.1667 4 -1.6667 0 0.25 5 -1.8333 0 0.25 6 -2.3333 0 0.8333 7 -2.4167 0 1 8 -2.4167 0 0.25 9 -7.5833 0 0.25 10 -8 0 1 11 -9 0 1 12 -9 0 -1 13 -8 0 -1 14 -7.5833 0 -0.25 15 -2.4167 0 -0.25 16 -2.4167 0 -1 17 -2.3333 0 -0.8333 18 -1.8333 0 -0.25 19 -1.6667 0 -0.25 20 -1 0 -0.1667 21 -0.9167 0 -0.0833 43 -9 0.25 0 44 -9 0.1768 0.1768 45 -9 0 0.25 46 -9 -0.1768 0.1768 47 -9 -0.25 0 48 -9 -0.1768 -0.1768 49 -9 0 -0.25 50 -9 0.1768 -0.1768 51 -9 -0.25 0 52 -9.75 -0.5 0 53 -12 -0.75 0 54 -13.5 -0.75 0 55 -12.75 -0.5 0 56 -15.25 -0.5 0 57 -19.9167 0 0 58 -15.0833 0.4167 0 59 -15.75 0.5 0 60 -12.5833 0.6667 0 61 -12.0833 0.5833 0 62 -9.833 0.5 0 63 -9 0.25 0 64 -12.5833 0 0.6667 65 -12.5833 -0.6667 0 66 -12.5833 0 -0.6667 white 21 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 white 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 white 8 43 44 45 46 47 48 49 50 white 13 51 52 53 54 55 56 57 58 59 60 61 62 63 white 4 60 64 65 66 acm-6.0_20200416/objects/missiles/sa10.obv0000644000000000000000000000301113100305074016314 0ustar rootrootSA10 56 12 1 -4.50593 0.0308625 0 2 -4.50593 0.216037 0 3 3.67264 0.216037 0 4 4.10471 0.185175 0 5 4.32075 0.0925875 0 6 4.35161 -0.0308625 0 7 -4.16644 0.277763 0 8 -4.13558 0.709838 0 9 -2.83935 0.709838 0 10 -2.56159 0.277763 0 11 2.40728 0.277763 0 12 2.40728 0.432075 0 13 2.90108 0.432075 0 14 3.08625 0.2469 0 15 3.08625 -0.2469 0 16 2.90108 -0.432075 0 17 2.40728 -0.432075 0 18 2.40728 -0.277763 0 19 -2.56159 -0.277763 0 20 -2.83935 -0.709838 0 21 -4.13558 -0.709838 0 22 -4.16644 -0.277763 0 23 4.35161 0.0308625 0 24 4.32075 -0.0925875 0 25 4.10471 -0.185175 0 26 3.67264 -0.216037 0 27 -4.50593 -0.216037 0 28 -4.50593 -0.0308625 0 29 -4.50593 0 0.0308625 30 -4.50593 0 0.216037 31 3.67264 0 0.216037 32 4.10471 0 0.185175 33 4.32075 0 0.0925875 34 4.35161 0 -0.0308625 35 -4.16644 0 0.277763 36 -4.13558 0 0.709838 37 -2.83935 0 0.709838 38 -2.56159 0 0.277763 39 2.40728 0 0.277763 40 2.40728 0 0.432075 41 2.90108 0 0.432075 42 3.08625 0 0.2469 43 3.08625 0 -0.2469 44 2.90108 0 -0.432075 45 2.40728 0 -0.432075 46 2.40728 0 -0.277763 47 -2.56159 0 -0.277763 48 -2.83935 0 -0.709838 49 -4.13558 0 -0.709838 50 -4.16644 0 -0.277763 51 4.35161 0 0.0308625 52 4.32075 0 -0.0925875 53 4.10471 0 -0.185175 54 3.67264 0 -0.216037 55 -4.50593 0 -0.216037 56 -4.50593 0 -0.0308625 white 6 1 2 3 4 5 6 white 4 7 8 9 10 white 4 11 12 13 14 white 4 15 16 17 18 white 4 19 20 21 22 white 6 23 24 25 26 27 28 white 6 29 30 31 32 33 34 white 4 35 36 37 38 white 4 39 40 41 42 white 4 43 44 45 46 white 4 47 48 49 50 white 6 51 52 53 54 55 56 acm-6.0_20200416/objects/missiles/sa2.obv0000644000000000000000000000434713100305074016252 0ustar rootrootSA2 96 18 1 21.62 2.1205 -0.23 2 21.62 1.8364 0.830248 3 21.62 1.06025 1.6064 4 21.62 -4.08562e-16 1.8905 5 21.62 -1.06025 1.6064 6 21.62 -1.8364 0.830248 7 21.62 -2.1205 -0.23 8 21.62 -1.8364 -1.29025 9 21.62 -1.06025 -2.0664 10 21.62 3.47278e-15 -2.3505 11 21.62 1.06025 -2.0664 12 21.62 1.8364 -1.29025 13 -36.57 3.2931 -0.23 14 -36.57 2.85191 1.41655 15 -36.57 1.64655 2.62191 16 -36.57 0 3.0631 17 -36.57 -1.64655 2.62191 18 -36.57 -2.85191 1.41655 19 -36.57 -3.2931 -0.23 20 -36.57 -2.85191 -1.87655 21 -36.57 -1.64655 -3.08191 22 -36.57 6.53699e-15 -3.5231 23 -36.57 1.64655 -3.08191 24 -36.57 2.85191 -1.87655 25 -23.69 -0 2.76 26 -31.74 0 11.27 27 -35.19 0 11.27 28 -36.34 0 2.76 29 -36.34 0 -2.76 30 -35.19 0 -11.27 31 -31.74 0 -11.27 32 -23.69 -0 -2.76 33 5.98 -0 2.07 34 0.23 0 8.51 35 -1.61 0 8.28 36 -2.99 0 2.53 37 -2.99 0 -2.53 38 -1.61 0 -8.28 39 0.23 0 -8.51 40 5.98 -0 -2.07 41 -23.69 -0 2.76 42 -31.74 0 11.27 43 -35.19 0 11.27 44 -36.34 0 2.76 45 -36.34 0 -2.76 46 -35.19 0 -11.27 47 -31.74 0 -11.27 48 -23.69 -0 -2.76 49 -8.28 -0 2.3 50 -9.2 0 4.37 51 -10.35 0 4.14 52 -10.35 0 2.3 53 -10.35 0 -2.3 54 -10.35 0 -4.14 55 -9.2 0 -4.37 56 -8.28 -0 -2.3 57 -23.69 -0 2.76 58 -31.74 0 11.27 59 -35.19 0 11.27 60 -36.34 0 2.76 61 -36.34 0 -2.76 62 -35.19 0 -11.27 63 -31.74 0 -11.27 64 -23.69 -0 -2.76 65 5.98 -0 2.07 66 0.23 0 8.51 67 -1.61 0 8.28 68 -2.99 0 2.53 69 -2.99 0 -2.53 70 -1.61 0 -8.28 71 0.23 0 -8.51 72 5.98 -0 -2.07 73 -23.69 -0 2.76 74 -31.74 0 11.27 75 -35.19 0 11.27 76 -36.34 0 2.76 77 -36.34 0 -2.76 78 -35.19 0 -11.27 79 -31.74 0 -11.27 80 -23.69 -0 -2.76 81 -37.03 0 -0 82 -36.8 0 2.76 83 -17.71 0 2.99 84 -14.49 0 2.3 85 -11.04 0 2.3 86 25.76 0 2.3 87 28.75 0 1.61 88 31.51 0 0.23 89 31.51 0 -0.23 90 28.75 0 -1.61 91 25.76 0 -2.3 92 -11.04 0 -2.3 93 -14.49 0 -2.3 94 -17.71 0 -2.99 95 -36.8 0 -2.76 96 -37.03 0 0 white 12 1 2 3 4 5 6 7 8 9 10 11 12 white 12 13 14 15 16 17 18 19 20 21 22 23 24 white 4 25 26 27 28 white 4 29 30 31 32 white 4 33 34 35 36 white 4 37 38 39 40 white 4 41 42 43 44 white 4 45 46 47 48 white 4 49 50 51 52 white 4 53 54 55 56 white 4 57 58 59 60 white 4 61 62 63 64 white 4 65 66 67 68 white 4 69 70 71 72 white 4 73 74 75 76 white 4 77 78 79 80 white 8 81 82 83 84 85 86 87 88 white 8 89 90 91 92 93 94 95 96 acm-6.0_20200416/objects/missiles/sa11.obv0000644000000000000000000000476213100305074016333 0ustar rootrootSA11 92 15 1 -3.21732 0.234596 0 2 -3.21732 0.203166 0.117298 3 -3.21732 0.117298 0.203166 4 -3.21732 0 0.234596 5 -3.21732 -0.117298 0.203166 6 -3.21732 -0.203166 0.117298 7 -3.21732 -0.234596 -2.3813e-16 8 -3.21732 -0.203166 -0.117298 9 -3.21732 -0.117298 -0.203166 10 -3.21732 4.76259e-16 -0.234596 11 -3.21732 0.117298 -0.203166 12 -3.21732 0.203166 -0.117298 13 -2.64759 0 -0.201082 14 -2.84867 0 -0.603248 15 -3.18381 0 -0.603248 16 -3.28435 0 -0.234596 17 2.88218 0 0.0335138 18 2.48002 0 -0.167569 19 2.04434 0 -0.201082 20 1.44109 0 -0.234596 21 -3.31786 0 -0.234596 22 -3.35137 0 0 23 0 0 -0.26811 24 0 0 -0.26811 25 0 0 -0.26811 26 0 0 -0.26811 27 0 0 -0.26811 28 0 0 -0.26811 29 0 0 -0.26811 30 0 0 -0.26811 31 0 0 -0.26811 32 0 0 -0.26811 33 0 0 -0.26811 34 0 0 -0.26811 35 0 -0.0335138 -0.0335138 36 0 -0.0335138 -0.0335138 37 0 -0.0335138 -0.0335138 38 0 -0.0335138 -0.0335138 39 0 -0.0335138 -0.0335138 40 0 -0.0335138 -0.0335138 41 0 -0.0335138 -0.0335138 42 0 -0.0335138 -0.0335138 43 0 -0.0335138 -0.0335138 44 0 -0.0335138 -0.0335138 45 0 -0.0335138 -0.0335138 46 0 -0.0335138 -0.0335138 47 -3.28435 0.234596 0 48 -3.18381 0.603248 0 49 -2.84867 0.603248 0 50 -2.64759 0.201082 0 51 -2.24542 0.301624 0 52 -1.9438 0.603248 0 53 -0.469193 0.603248 0 54 -0.100541 0.26811 0 55 -3.35137 -0 0 56 -3.31786 0.234596 0 57 1.44109 0.234596 0 58 2.04434 0.201082 0 59 2.48002 0.167569 0 60 2.88218 -0.0335138 0 61 2.88218 0.0335138 0 62 2.48002 -0.167569 0 63 2.04434 -0.201082 0 64 1.44109 -0.234596 0 65 -3.31786 -0.234596 0 66 -3.35137 0 0 67 -0.100541 -0.26811 0 68 -0.469193 -0.603248 0 69 -1.9438 -0.603248 0 70 -2.24542 -0.301624 0 71 -2.64759 -0.201082 0 72 -2.84867 -0.603248 0 73 -3.18381 -0.603248 0 74 -3.28435 -0.234596 0 75 -3.28435 0 0.234596 76 -3.18381 0 0.603248 77 -2.84867 0 0.603248 78 -2.64759 0 0.201082 79 -2.24542 0 0.301624 80 -1.9438 0 0.603248 81 -0.469193 0 0.603248 82 -0.100541 0 0.26811 83 -3.35137 0 -0 84 -3.31786 0 0.234596 85 1.44109 0 0.234596 86 2.04434 0 0.201082 87 2.48002 0 0.167569 88 2.88218 0 -0.0335138 89 -0.100541 0 -0.26811 90 -0.469193 0 -0.603248 91 -1.9438 0 -0.603248 92 -2.24542 0 -0.301624 white 12 1 2 3 4 5 6 7 8 9 10 11 12 white 4 13 14 15 16 white 6 17 18 19 20 21 22 white 12 23 24 25 26 27 28 29 30 31 32 33 34 white 12 35 36 37 38 39 40 41 42 43 44 45 46 white 4 47 48 49 50 white 4 51 52 53 54 white 6 55 56 57 58 59 60 white 6 61 62 63 64 65 66 white 4 67 68 69 70 white 4 71 72 73 74 white 4 75 76 77 78 white 4 79 80 81 82 white 6 83 84 85 86 87 88 white 4 89 90 91 92 acm-6.0_20200416/objects/WMM.COF0000644000000000000000000001071513646045022014223 0ustar rootroot 2020.0 WMM-2020 12/10/2019 1 0 -29404.5 0.0 6.7 0.0 1 1 -1450.7 4652.9 7.7 -25.1 2 0 -2500.0 0.0 -11.5 0.0 2 1 2982.0 -2991.6 -7.1 -30.2 2 2 1676.8 -734.8 -2.2 -23.9 3 0 1363.9 0.0 2.8 0.0 3 1 -2381.0 -82.2 -6.2 5.7 3 2 1236.2 241.8 3.4 -1.0 3 3 525.7 -542.9 -12.2 1.1 4 0 903.1 0.0 -1.1 0.0 4 1 809.4 282.0 -1.6 0.2 4 2 86.2 -158.4 -6.0 6.9 4 3 -309.4 199.8 5.4 3.7 4 4 47.9 -350.1 -5.5 -5.6 5 0 -234.4 0.0 -0.3 0.0 5 1 363.1 47.7 0.6 0.1 5 2 187.8 208.4 -0.7 2.5 5 3 -140.7 -121.3 0.1 -0.9 5 4 -151.2 32.2 1.2 3.0 5 5 13.7 99.1 1.0 0.5 6 0 65.9 0.0 -0.6 0.0 6 1 65.6 -19.1 -0.4 0.1 6 2 73.0 25.0 0.5 -1.8 6 3 -121.5 52.7 1.4 -1.4 6 4 -36.2 -64.4 -1.4 0.9 6 5 13.5 9.0 -0.0 0.1 6 6 -64.7 68.1 0.8 1.0 7 0 80.6 0.0 -0.1 0.0 7 1 -76.8 -51.4 -0.3 0.5 7 2 -8.3 -16.8 -0.1 0.6 7 3 56.5 2.3 0.7 -0.7 7 4 15.8 23.5 0.2 -0.2 7 5 6.4 -2.2 -0.5 -1.2 7 6 -7.2 -27.2 -0.8 0.2 7 7 9.8 -1.9 1.0 0.3 8 0 23.6 0.0 -0.1 0.0 8 1 9.8 8.4 0.1 -0.3 8 2 -17.5 -15.3 -0.1 0.7 8 3 -0.4 12.8 0.5 -0.2 8 4 -21.1 -11.8 -0.1 0.5 8 5 15.3 14.9 0.4 -0.3 8 6 13.7 3.6 0.5 -0.5 8 7 -16.5 -6.9 0.0 0.4 8 8 -0.3 2.8 0.4 0.1 9 0 5.0 0.0 -0.1 0.0 9 1 8.2 -23.3 -0.2 -0.3 9 2 2.9 11.1 -0.0 0.2 9 3 -1.4 9.8 0.4 -0.4 9 4 -1.1 -5.1 -0.3 0.4 9 5 -13.3 -6.2 -0.0 0.1 9 6 1.1 7.8 0.3 -0.0 9 7 8.9 0.4 -0.0 -0.2 9 8 -9.3 -1.5 -0.0 0.5 9 9 -11.9 9.7 -0.4 0.2 10 0 -1.9 0.0 0.0 0.0 10 1 -6.2 3.4 -0.0 -0.0 10 2 -0.1 -0.2 -0.0 0.1 10 3 1.7 3.5 0.2 -0.3 10 4 -0.9 4.8 -0.1 0.1 10 5 0.6 -8.6 -0.2 -0.2 10 6 -0.9 -0.1 -0.0 0.1 10 7 1.9 -4.2 -0.1 -0.0 10 8 1.4 -3.4 -0.2 -0.1 10 9 -2.4 -0.1 -0.1 0.2 10 10 -3.9 -8.8 -0.0 -0.0 11 0 3.0 0.0 -0.0 0.0 11 1 -1.4 -0.0 -0.1 -0.0 11 2 -2.5 2.6 -0.0 0.1 11 3 2.4 -0.5 0.0 0.0 11 4 -0.9 -0.4 -0.0 0.2 11 5 0.3 0.6 -0.1 -0.0 11 6 -0.7 -0.2 0.0 0.0 11 7 -0.1 -1.7 -0.0 0.1 11 8 1.4 -1.6 -0.1 -0.0 11 9 -0.6 -3.0 -0.1 -0.1 11 10 0.2 -2.0 -0.1 0.0 11 11 3.1 -2.6 -0.1 -0.0 12 0 -2.0 0.0 0.0 0.0 12 1 -0.1 -1.2 -0.0 -0.0 12 2 0.5 0.5 -0.0 0.0 12 3 1.3 1.3 0.0 -0.1 12 4 -1.2 -1.8 -0.0 0.1 12 5 0.7 0.1 -0.0 -0.0 12 6 0.3 0.7 0.0 0.0 12 7 0.5 -0.1 -0.0 -0.0 12 8 -0.2 0.6 0.0 0.1 12 9 -0.5 0.2 -0.0 -0.0 12 10 0.1 -0.9 -0.0 -0.0 12 11 -1.1 -0.0 -0.0 0.0 12 12 -0.3 0.5 -0.1 -0.1 999999999999999999999999999999999999999999999999 999999999999999999999999999999999999999999999999 acm-6.0_20200416/objects/sounds/0000755000000000000000000000000013175062137014544 5ustar rootrootacm-6.0_20200416/objects/sounds/apglock.wav0000644000000000000000000002743213175054611016711 0ustar rootrootRIFF/WAVEfmt @data.|5K5  q$m|$m{$l|$nz$oy$l|$l|$px$j~$l}$ny$h$qz$su$lz$m{$qw$su$qv$k{$o{$sv$st}$g$m{$l|$j~$o{$n|$m}$o{$qv$mz$m}$tu$oz$l~$oz$m}$o{$py$m{$ru$qu$k|$px$n|$rx$l{$m{$nz$ny$k{$ru$py$py$sv$l~$lz$g$mz$k|$k}$m{$ny$ss}$j|$oz$n|$ox$k|$pv$m{$j~$e$o|$sw$n{$rw$mz$l}$n{$ny$i$m|$j$qx$k}$sv$k}$mz$m{$h$qx$k|$l|$qv$l{$sv$m|$g$nz$m{$rt$l{$sw$qw$k}$py$i$n{$n{$i$o}$p{$oy$k~$n}$n|$o{$nz$oy$oz$px$j$oy$qv$i$k$m|$px$m|$nz$i~$o{$n{$tv$l|$mz$k}$m}$m{$py$n{$ny$i|$h~$l{$l}$o|$px$nz$k|$m{$pz$AGs]pN v$pz$n{$n{$l~$m$k$n{$nz$l}$rw$j~$n{$mz$m{$sv$nz$nz$l}$rw$rv$ru$j|$mz$qv$ru~$h$oz$mz$i~$px$px$py$m|$sv$su$l|$l|$px$l|$oy$qy$qy$n{$ny$mx$qu$i~$py$n|$l}$l{$l|$o{$nz$k|$sv$oy$k}$ny$ny$j|$m|$pz$ox$lz$ox$rt$rt$k|$py$l$oz$py$m{$m|$m{$f$oz$sw$oy$pv$mx$nz$m|$j}$j}$mz$m|$k$l}$pw$j}$j}$j$j$qw$h~$py$oy$m{$tu$l}$l{$nz$py$ox$nx$n{$qx$mz$nz$j$o|$qy$k$l~$m|$m{$j$q{$rx$m{$h$nz$qy$rw$m|$ny$k|$l|$h$nz$nz$i$oy$i}$sv$m|$qx$ox$ox$i$m|$ox$oy$qw$px$k|$k|$nx$pw$pz$qy$rv$mz$k~$vu$?Ev[pM t$j$l|$l|$j$j$nz$n{$n{$qw$m{$l|$n{$k{$i~$rw$oz$n{$ox$oy$pw$qv$my$lz$pv$sr {$h$rx$px$lz$nz$n|$o|$m}$oy$m{$l}$l}$rx$l}$m|$o{$o{$n{$qv$nx$pw$l}$qy$n|$rw$k}$n|$tv$py$l{$rx$qy$pw$my$h$kz$j}$pz$n{$l}$rw$nx$mx~$g$n{$o{$rv$m}$m}$k$i$k}$oz$py$px$qu~$j}$py$mz$kz$j|$l{$n{$k$h$qx$k~$qx$k~$h$oy$k{$pw$ox$oy$qv$ny$j}$nz$m}$nz$ow$nx$nz$m}$rv~$f$m}$rv$k$qz$j$oz$k$l$n}$pz$k~$o{$o{$n{$j$m{$oy$j$e$l{$l{$i$ox$j{$qx$qy$qx$nx$ny$m|$k$j$rv$l}$sw$l|$k{$pw$qw$tu$nz$oz$l|$py$qx$?Hq`mN x$l~$j$nz$k|$m|$pz$qw$l|$j~$n{$nx$oz$rw$l}$rx$ox$i$oy$m{$us$pw$l{$oz$su$ru$h$o|$m}$n{$py$k$o{$n{$rw$rw$sw$m|$nz$i$rx$n|$n|$n}$pw$ow$k{$i$rx$oz$l|$i$m}$oz$l|$oy$px$qw$qw$pw$ny$mx$ny$k~$oy$nx$lz$my$uq |$h$o{$ry$ox$k~$pz$n{$d$k|$l|$pz$l}$st~$j|$k}$n{$m{$l|$m{$l{$j}$k}$px$e$oz$l|$m~$py$k{$l{$ow$l{$sv$j$h$m{$m|$qw$m{$py$rv$l|$oz$h$rw$rw$m~$k$rx$oz$j$j$p{$k$l~$qy$st$lz$j$ny$lz$h$f$o{$py$l|$l{$h$qy$rw$n{$px$l{$mz$m|$m|$rv$mz$ny$h}$f$oy$n|$p|$oz$px$ny$qx$py$>Gs^nO x$qx$lz$k|$nz$j$n|$sv$nz$k}$m{$k{$mz$l{$j}$py$qw$k~$px$mz$rv$px$oz$k|$qv$qv$h$qx$nz$j}$l|$o{$pz$k~$m{$nz$oz$n{$py$n{$oz$n}$m}$oz$ox$qw$qw$k~$l$m~$qx$mz$k}$m|$n|$j~$rw$sv$qx$mz$nx$h}$mz$qw$mz$h$rv$my$qu~$k|$nz$k~$nz$n{$n|$l$h$i$h$sx$l|$qv$lz$ny$pw$j}$l{$i$m|$m{$i$su$i~$mz$i$m$rw$k{$m{$pv}$i}$tt$oz$n|$n|$k~$l|$nz$oz$l}$nz$nz$j~$oz$px$j$r{$pz$n{$o{$i$n{$l|$nz$l|$rw$oy$m|$tv$l|$k~$g$py$m{$m}$n{$l|$q{$n|$qx$mz$ny$j~$l|$k|$oy$k}$l|$l{$f$j}$oz$n|$qw$ox$l{$l}"7 >acm-6.0_20200416/objects/sounds/missile.wav0000644000000000000000000004272013175054611016733 0ustar rootrootRIFFEWAVEfmt @@dataE}}}~}~}}}zz|}{y{{|}}~{w}w{ywyzwxyz}|}zwy|~v}~vpqu{}~y{{{qmsw|vy|}ulprrsuw}vrs{xsz|yxsuwq~}rsux{volsv|ys~vlotojpqv}vxr{omu~ztxxzionfnx~{pmzxpptvx{|{~z~{mow}l`hyxobn|tltuy~zz|tkp{vtuvznhp|{phf{x|}qqw~{neektkttxz{~~yypyxnzmyrk|}wy}yv|voijkmqtxzzyqs}{~~}{}~xkgn|yt{yz}~|o|~nfmox~ywkuumq{~~ogvx|tijpz|vxtnvxpfhjzztwrsjhqp~|nrzyqd}|rxzxlry}tvytgdimwlegix~rr~xnv}{}kbrxrttx|w}znwymeo{zr{~zy}yyxrowrsvymy{pwxnvniqrrkzq_iktvr{|gbgjorz}yur|}z}|}|z~}{uhqtspryfit|msyty{jmvdkoq}vfklptfbmo{{yrnotxxknxrdhoqv|zx}|ztty}w_djx}rv~thpzzzvy}jdjlltvtyz}~rmvohx~~q_hnz|gelvvqvx{}z~~gfilor}zxuyz{|lqswk\dgkorxygly{tr{lkqrvty|v~zz~}|xfkrm~rhprwy}td|pgqqxdtwqynqt{~yyrydoq`nlrvzn{~|dfnsuqy{edohor~zy}vtvx{t}zhfvvupforzx}{g`lkrvvx|hpvx|xx||njdhoqvxrtukZhj|ts~dl|ok~r\gkm|tysltmvxk_yvpunnxvvy}lifjlqtwz|~vrrogflnrtxzz}tvppruzywz{fdo{|irt~zhjxxfv{jwibjmqtxgm~rmvtzvZ\gm|lqvtgolklpt}poxqxx{}k\bgjorvxz|~|otqo}|d`jr~pmtvz{|n_ehkoruwy|irsuoq~x_bkyhft|`dllrx~k\fio~vlxz|yqmxsxty`Zgfpnlw{l{}_jox~vwyxwx{||~l|v_golntxtxzz}~ddmjx{ot}w`mmyxmwu~zx\gklrwsvpfekq}nouuyz}lhrqptv{~}j\fhmptyzpxxs}z}~~~p`n{d`jydgfmqrwyl_msbjpxlt~bblkr}x`gpzghjpnrzyz}~kttvxyohg|rZdijqrvxzqhimqsvxxy~|}|~}||{xdn{wtx`bnmxtz|o|rm|vfmot|wu||dxfhwre~~j\jkqtx{}v||kWetrn|m}ppirusnZmjqsvz{v`vtv|h_mjrsv{zbjootxgvoeroxuwz}|bimnssxx{\`in}qrxs{y}}xvopxr|vuknswZkoopv~k`llqtv|}z|klkfqouuxz|~oib\owhmts~trz}hhytfu~nj|{qlttwyz~hxgfnnzxirtv~`twilortykt`mtxdiloZgin~xqzx~}|kytybnv\h}egjkr{xh{rkrpvvzz~zeoq}|vdrq~djexpouw}vkrttts~ggnmrsvxz|fnzjrttxx{hywq\dl}kjwj{iel`vudo{bdnlxxbiphqdqptvx{}{tjxzvozt|mnvxkrexsbpnrux{`jnsvpxw|y}o\ehkpqyjdgpmtvz_mi`novjt~{er~~vtzx}vt{w|z~qmvl\ntbmtppxxtijoqtvzqlnruvtpwfnqqvvu|q|x_rvu`{geqnonvurpmxrztrkmksubqt~{vvkv\fkrih|rzkrxkvtvrvmrtt|{v{b`qptrbtzykpp{vmvvxx{m~{m|gxtwkttvxyxmrjvrldjpnttxxz|}~z{kn|thoqr~|vigtpqu~~s_|nWpgyyx~fzkp|pixlmqs~b{qyymevogdomtu~zz~}|}~~znhld_funr~nqdq|gutxyihqbpos~mrnvuxzf}r~dxsvvp}}gs`pqr}{p|gvk_ljotg{~tX_oz_vqpnyzzqyxmyrrd~kiso{vt|x~}rZjhhpoux|gk}o{olttvxgnwtjrrvxy{~hbi}gvnerovmr|gpbrm}t}ztYgiynlys}jl{ahnnttxy|}y|odqqiwzhxddnlznnxnmxiykvrekpoyelxli_kkprux||i~bbmkrrskrrnwtvyy|qiqlwdimn}ypqpkngsszmrdktz{u\dkkssxy|ryobrlxdamkurhxzmh\lhpumszzd~lwchlrqw{g\owhltqyx|}lyx~~hpsvxshwuwwmz|k~raknqv{qaltznsxvuvsr[filprvxzmkxdnxllktsyz~}yrtzw~nucmq{sptyhn}t]llpsuzq|fdnmmd|jvxv}yytr}}~}||{{{ymeegkmrvy|~}cekkpqtvvjq|}rkpr{|xyyeckmrvy{~m`ijnqt|nbeimq~ytlqs{~~vb`finqvy{igmnrtwy{|~|sy{qnnnhhmprvx{zyx~tcejlnr|yx|||p~|mfeinptvy{}~wy~zrihmtwuprvx{|~~jnpt|k`bhkorvx{yldhlos}toruv|~nbeimquvyljrqvv~tidimpu~vt{xnltp^gjmrtxy}~~}||wd\ep{prvx{~madimqtwz}z~utzz|rjps~vw{w|{}~rerwphhmprvy{}~rmmjt{~ypntuxz~gajjoquwy{}~zutmjmp{}lafjmqtwz|{z~}|wpfahlpvzz}shljijosuxz|~~|q^^fhmptwz|~wmorsuvx|vqichlnruw}}}ysnmqsuwzpmortv}zddklprvwz|~zz{{~}ujmquwuyz|~|w~~zqnx}ibklquw{}zowmrsux}~yz{|}}~{z|v|~}|{{{z{zsiiehnqvzruwwwzz}~}znelwwkfnquxqhq|zqw{vmlqsvx|umssmkmnqtwy{m_hnyjehmqx{~}{~{sohcknrvy|~~zorzwqifjoruy{~}w{wz{rjmoruxz|}~o_dhkoruxz~~~}|r_bgkoswy|~yhehmoruxz}~{rmmjhjorvx{}zebnmkq{|uuyz|~~|qd`dimpsvx{|~xoppqrrvy|{|teeknruwz{pkhmprvw{vhen|nkjjprvy~gdnkrswz{qnstwxz}~~~z}wz}u}~}yndgnqux{}~ufdgknrux|~qjkgknrux{puvyz{}~yhdgknrtwy{|~sonnu{sopsyzwswyz}~{{}{nidgmnsuwjfinpswy{}z}}tljdglosuxz}vggkopsvx|zxz~}p`egkoruxz|sfjjnqv~~yy{|}y~~vgjmlkosvy{}~soonmkoruxz|}~tcehkoquwy{}~~|wtsoswwplrwvuz{}xmhkoptvxz~zi_hjnrtxz|~~}wkhhjklrtwy{}~}|vjedilptwy{wnknpsuwyzxuwutolortwy{}~~}}{p^dilpswy{y}~{{}||}{nlnllnrtwz{}~}|{zoadejnsyy|ywz{}~~y}zyyyury}tllpruwy}~~wnnkhjoruxz|~zvwy{}}yssvvxyuw~ytw~yz|xy~zy{{~{v}shnpz}{}||wquvyz}mu|tsvz|~}y{|}~}}}vmkosrt|~vosvx{}os||z}~}rlls}vv}smjoqtwx{}x}wv|~||xutx|}rx{x}ognqvxx|}~}}|{{zzzytty}}qfioxxx|~~~{wwztoqrssuvw{||~{x{usvz~spz~vppw}vnqv}z}|~}|{sjs{}zqoqqorvx{}sx~~}}|ulihkpv~xxvwzsbko|wx~}x{xtxy{|~}wy|srv}tx~tnnovxzwx|}}|{{yoefflosvx{}}rryz~}ytrtz|{zz|}{xy|}~|y{z~}~}||uehtvokrt}yx||sloqsuy|zvqvwxyumqtvzy|yxmr}ytvy}wwywy{qxwvzysqtxy|}~{y}{ypiw{w~~yvtzz~zzvtsvxv|~y{}~~~}|zzwoklu{vqy}~zwpx~|{{wpjotxw{|~w{}}}{|{{{{{scjz~ulsux{}{}~z|zpmq}wu{~sqtx|xu}{wwy{~{w{wppwzjiqsps~yyywy{|~ts|xspstvwy|{{}}z|ztuqrvx|}yyzxxz~{|{{|{xxzz{|~||}~|xtuwx}}~}pahku{tpsuxz|}xhdltzwtv|zuxz{}~~ty|pijqxxsvxz|}~~}vy~~|qijlnqtwz|}~utxzxqopx{zqnqtvy~~}|{vtstvvtnnsuy{}~}|{{xqpqqiipqvx{}~z|}wvuwyphlpr{~zz|}~yry{xpkls}z{|rmptvy{}~~z|ztqqrqqtwy~}|}~zuy~~~yttsmmrtx{}~tghknrxwppqwvsu{}|sqrpnptvy{}}{rklpvvwzz{ywx}urpptvxz|}~}ysnmpuwwvuuy|{|~|umijoruxz}xrnkqruwy{}~}yurqw}~{wwuuuvxwwz|~~|yyz{{ywurplkoruy|}~}|{}}}}}}}}ymiknruy{}~}|{{{{ztnruwz}vy}{x}{tqt|}xwz}}~rnrtux~{y|{yxwyxvtqquwy{}{powyzvrpqtwy{}}}|}}}|{yvw{|utrrquxz|{qortwzx~zwqnns~~~}xuvwy}yx{|~{z}~}~~~~yvrms{~xuy{}|~trv{u|~~~~~|xsnknruxz}~~}ywztjhnqtwy{}~~|vuzyywwyxwy{yxyxxxruwy{}~{z}wqv}~zspruwyyz|}sr|}}xusw{}xswyz|}xojoqsy~~~~}{uusompsy~}{vtuvyxwy{|~~}|{wmlnqw{|ywuux{~~zzxtux~}~~zz}yuuz}~}~~zxz~}zzwsqrtwusvy{}~~ummnrrrv}}yvv{|z{}y~~wrpqv{~~|wtwy{~~z}|zuqpry~}}}|~}~|zvuuvxy}|vsuxxvx{|~}yyz}}xvtqonpsvxz|~|z}~~|yx|ukmrsvz}}~~|zyz{|}~~{}~~|x{~}}xnllqtvz}}~|zxvwxxy{}~~wvz}wvusrtvuvy{}~~wstrqoqtvxz|}vmlnqsw}}{zz{}xwyzwwz{|}|~xsuttsqrvwy{~zywuvvtstwy{|~|torwww|~yvyz|~z}{|~~{wvxz{yyy}ztrrssstwz|}}yurtxz{{}|}~}zvqoqu{~~|xvw}}xzz{|}}{yy|~}}|xx{}wy{yuoosvy|{}~~|z|y}}~|yuqqswz~~~z~}vmnpw|xyyyvuwz}}}|z{|zwtsw|~||}{xvx|{ww}~wux{}|z}~~ztqrv|}wpqqtvy~~}~~}{wsrrtvwwxz|~zxvuutuvy{||}yvvx|}zuootuw||xutuvxz{|~vqrtwy{|}}|}|{yvtrtwxz~}{zwrruwy{~}zvvwyz~rnrw}}~}}~}zz|}}~|yz{zzxwwwxz|~{yz{|}~~{snmortw|xwuuy}}|{z{}zy{}}}|{z{~|||{z{}~~|urrrrtwxz|}}}|ywtrtvxz{}~yrtvwywvvz}~~~~~~}zyxwwuuwz||zyz|~~}|zwvsqrstuwy{}~~|yxy{|yxx{|utsw{}~|yxz|~~~~}||{xuuw{~~~}|~~yrprw}~}|~~}|{|}}~~zxxwwwwy|xvutuwyz||zwuvx{|~~}|||}}~}}}~~~}|||{{yyy{}~}{}~~~~}|{||}}~}z{{{||{wssvx{~{yxz~~|}~}zxz}~~}ywxz|||{zyxvvx{}~}|~~~~~~ztrsv{~~~~~~~~~}}}|xrrrswyyz|}~~|zzyzzxvwyz{|}~|zzwvuvy||yvwz}~~~}}~~|z||zyxxxxvvvy{~~}|zwxyz||}~~|z{|~}{yxxy{|~~|{{zyxyz{||||~}yyy{{{|||}}}~~~~zxyyyxz{~|{|~}|{z{~}yy{{{|}~}||}~}|}~~}||}~}{yy{}}{zxxz|~}{ywwvwyz}~~~}}~~}}|{zyzz{}~~}~~~}|~~}|}}~}{yxvuux{}}}~|yzzzyyyzzzz|}~~}|{zz{|}~{yyyz}~~~}}}}}~}|{zz|}}~~{yyyzzz{|~~}}~~~~}}|{{{zxxz~zzz{{z{|~}}}zz}~~~~~}|zzz{}}|zz{{zz{}}}~~~~}zyy{|}}~}zwvx{~~{zz{~|zz{{}~|}~}}~}{|~{{}~}|}~~|}~~~}}}~~|zz{{{|~|}zvwz}~}|zxwyz|}~~{xvwyz|~~z{{|~|{{|~}{{}}~{{~~zvuux|}{z|}~~|{{}~~}||}~~}}}}}}}}}}}~~~~}||}~}{zyyz}~|}~}||}}~~~}|{zzz}~~~}zwxz}}|}~|}~zwzz{zyz{~~|{z{{{zzzzz{|}~~~~}|}}}}~}~~|{zz}~~~~~}|}~}z|~}}}|xwxy{~}}}{zz{|}}~}~}wxxxz{~~|||}~~|||}~}{z{|}}|zyz}}|zyz|~}}~}}}~{z|~yxxxy{~~}{}~}}}}}}~~~}|}}zyy{}~~|zz|~~}|}~~~~~}{{|~~}}}|}}}|}}~~~}}}}~~~{{{||{|~~}|zz{|}~}}}}|||||}~~}{zzzzz|}~~~}|{{zz|~}{zxz}~~}~~}{z{|~}}}~||}}}|zz|~~~}~~}}~~}|}~}|{{|}~~|yxxz}~{yy{~~}}~}{|~~~~~~~~~~~}{{}~}}}{zxyz{|}~}|}~~~~~~~}}||}~~~~~|{|~~}~~~|}~~~~~~~~~~~~}|||{{|}~~~}}}}}~~~~~}||}}~~~~~~~}}}|z|~~}{{|~~~~}{{z{}~}zzz{{|~~~~~}}}~~~zy{||{|}~}|}~~}||}~|{|}~{zz|}~~~}|||||||}~~~~~~}}~~~}}||}~~~||{{zzz{|}~~~~~~~~}~~~~}~~}}~~~}|||}~~~~~~}}~~}|{}~~~~~~~~~||}~~~~~~~~}{{{|}}}}~~~~~~~}|}}~~~~}}||||{{|}~~}}}||}~}}~~~}}|{{{|}}}~~~~~~~~}~~~~~}}~~~~}|{|}}~~~~~~~}||}~~~~~}}~~}|}~~~~~~|~~~}}~~||}~~~~~~~~~~~~~~~~}|{|}~~~}|}}~~~}}}}~~~}~~~}}}}}}~~~~~~~}~~~~~~}}}}~~~~|||~~~~~~~~~}|}~~}}}~~~~}~~}||}}~~~}}}~~~~~~}~~~~~~~~~}}~~~~~~~~~~~~~~~}}}~~~~~~~~~~~~~~~~~}}}~~~~~~~}~~~~~~~}~~~~~~}~~~}}~~~~~~}~~~}~~~~}}~~~~~~~~~~~~~~~~~~~~~~}~~}}~~~~~~~~~~~}}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~acm-6.0_20200416/objects/sounds/stall.wav0000644000000000000000000001017413175054611016403 0ustar rootrootRIFFtWAVEfmt @>dataP1' -2>:*2! . 81572 1 %+ 4%:317,-2%6477&-0 )7646 %+"3 ,7847( /$*!4 /7805$ ,#2 .7615")!0 *8548( 0.$ 443808( 4 &(2 05727 # / .$ 5258/8 !/.&3239.6 ,# 1 +6638+ 60 )!$&- ' 6648 #)%" 654:( 2-*563:.6 . "+$2 ,42464827& ."  4647 $+! / 05828 ! /#)$3/674:/8$ 2 *$ 2/68+3$)$ 645:.5 ,!/ ( 64681:, 5".".% 3447 $ "2417 . &( / ,684:.8 & 1$*0(6437( 2".'6637( 1!+& 4168/6. +#426817 $. / ,5707  ,# 1 -6818 %1 &&2 *636707&0!+( 5648$."2 +6828% / /4  #                         acm-6.0_20200416/objects/sounds/warning.wav0000644000000000000000000002174613175054611016740 0ustar rootrootRIFF#WAVEfmt @data# @W f,Xg 0  # "[ﭽɨA7]gH J66o©ϸf/%66q¥Ͼ`/<tb b )J쐶סNA ]xHԆE  66r¦ϼa/< q` c  )J쒶աPA ]xHԈC 66u¢Ͽa/< vc `" )I쑶֡NA!]wHԈB!66r¦Ϻf/@ILS Outer Marker Beacon tone?0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0??0*'%'*0?acm-6.0_20200416/objects/sounds/screetch.wav0000644000000000000000000000277413175054611017073 0ustar rootrootRIFFWAVEfmt @>datagP3()ZG!*&K .| 'k,)CHX5RW `??r  zxQ~> O R f 7 X  Ja wB ^5ZOB]p; =e_/ < . &7*po)Z ߆IQ-H1-=; 6<[t> {+ K1AA%# w s#bH-%fJ /Bp*5$%1#jH J+a {Wiې8~ 3k d pVna )IGLgK`  6?k;& l</R `.R)[b,l js C"0 $ 7rZ !KR e\o b Qy> ?h) . ~_e% DoNh "#bl1tkQG1 A '  zE}3m  Q \0UYL@xQ5ZhG!\ +> _m "uY mN=kt 5O}tuS W- W ] >>$eDO.-!d&o3  h{U@%7\aN 2[n 6y ;| 'h%4 n Yfwb Yb^WLz Doacm-6.0_20200416/objects/sounds/gear_up.wav0000644000000000000000000004736313175054611016720 0ustar rootrootRIFFNWAVEfmt @@dataN~~~|~{{{z}|}}~~z}}z~~~{}{{}~}}~|{|~~||||{{}y|w{~{}{z|}|x}y}}}|{|{|{y{z{s{{r{{v{{xvy{{~{vv}x~{y|w|pw{|y~}~{zv{xx{{w}~w}~~}}}v|z}}}pz||~{|y~~xv|~}xv|~z}}~~|x~w{w{|zzxqxqy{|y||xx|{~}|~~~z{}}yxzr|||~wx|~|{}~|t|~{{w{~}~{~t{x|~|z~|y{{v~}|y}|}{u|~{~|}{{|{~~{}~{{}~||x{wv~}}q{{v~|zxz~{x{~vv{z~~{{z|~}{xwvz{{{v}{t~xu~{|{|o~|y~}~u}}uw{{{z|{|~{}~zx{}sz|t~{z~~wt{vuyyyw{{{{|{}yv|}wzuy~~~p~vx~~y~w{x|x{{w}~z~y~yor~vs~|zx{}|{~{{~~|}{xzzz}{x}}||u|~z~~|y~{}{v}|{~qtryt|w{~zp~w~~|~~z|}|{~~~u~~}||}{{~zvv}z~|{z{~z|p}z{||~~~z~{}wv{~}}v{|y~y{|~~t|}|qx}~~{zy}}v~{{~w{{}v~ty{zx}wt}x}ysy~xwz{~|y{~x~}v}t~|v|~||}}|~{{{{{~~vy{y{v|xx{|vxzp{~u|~uv{{|{vx~||{{zyw{y}}uuvp~y~|z~~~{{}w~}|zu~w}vx{z|yw~uqwz|s{{~~{{|~x}z|}ty~x~{{{{zzuy~vv~~~{zz}~z~{{z{{y|{p~zw}}~z}{~x}{{|}}{r{~yxuy}{{vz~yv~}yu~vu{{{~~|~~xy}}z~{u~}wvz~~}y}{vy|vx~zv~{vx}{{{~{z~|sz{wx}w}y{{~xy{~~~~}}{y{y~}{~w{t{}xz{}~v}{~~}{z||{}~y|w}~{{~|v~~~x}~ts~}xz~x~|~wy{~x~||wp}yv}{~wyxqu~{{~v~|tyyy}}{~~|xx~}}zw{zyz~|{~x|v{~u~x{y{}|zz|~~q}{~zxz~{}{~u}z}wyz}ty~}|x~wwv|z|||~|w{~|~z~zuw|y{~{zy}~zxv|}z|~{{p~xx}{zu}wsz~q}|y~y~|s~|w}y~~sx{x~u~y~|{syz|~|~{~}|}t~{zy{yzzuxv{~|{z~}~z{|y}u|x~|w|utxs||}||~v~x~}~|~z~}wzvuw{}}{~|y|}}{}{|~~uux||ru~|y~|}}{z}wxy{{sx~z}u{~|zsw{}~}~|~ty}v{w|}~rr{r}w{}z{~wv|}w~{}|~u}~{y}}}u{x{z{x{}|xx~{{wu{}z{x~xz~qy{{vx}x~u}{~t}yz{w}z~{yzvgv}w}zy~s}uxx{tqv}|u{yw~z}vz~vz{x}z}zu~}}zzzy}{w{z|~y{~|{y}~x|~~v|~v}}|}~{tz|u{y}{|w|yuyyou{vvy{~}|zu{~{wzys{vx~}~|wv}|t{z|{q~~~x{{xutzvv{|}|w{}~y{y|~}~{xu{{xwu}}z~}}{~xy}~}{{x~|}}}}~}~|}~~~y~~}{}x{}~|}p|w}~{~tv{~{}~wt~z{t~uwxzzq{v|}~{|{t|kuv}x}}y~x~~ssy}~{xzzxzu~vp}vw{|~z|}tz}zx{{v~}t{u|wx}z{~u{y|}}~{rx{ox}tzvvzsx~t~wov{vqt~|~x~{{{{zzuy~vv~~~{zz}~z~{{z{{y|{p~zw}}~z}{~x}{{|}}{r{~yxuy}{{vz~yv~}yu~vu{{{~~|~~xy}}z~{u~}wvz~~}y}{vy|vx~zv~{vx}{{{~{z~|sz{wx}w}y{{~xy{~~~~}}{y{y~}{~w{t{}xz{}~v}{~~}{z||{}~y|w}~{{~|v~~~x}~ts~}xz~x~|~wy{~x~||wp}yv}{~wyxqu~{{~v~|tyyy}}{~~|xx~}}zw{zyz~|{~x|v{~u~x{y{}|zz|~~q}{~zxz~{}{~u}z}wyz}ty~}|x~wwv|z|||~|w{~|~z~zuw|y{~{zy}~zxv|}z|~{{p~xx}{zu}wsz~q}|y~y~|s~|w}y~~sx{x~u~y~|{syz|~|~{~}|}t~{zy{yzzuxv{~|{z~}~z{|y}u|x~|w|utxs||}||~v~x~}~|~z~}wzvuw{}}{~|y|}}{}{|~~uux||ru~|y~|}}{z}wxy{{sx~z}u{~|zsw{}~}~|~ty}v{w|}~rr{r}w{}z{~wv|}w~{}|~u}~{y}}}u{x{z{x{}|xx~{{wu{}z{x~xz~qy{{vx}x~u}{~t}yz{w}z~{yzvgv}w}zy~s}uxx{tqv}|u{yw~z}vz~vz{x}z}zu~}}zzzy}{w{z|~y{~|{y}~x|~~v|~v}}|}~{tz|u{y}{|w|yuyyou{vvy{~}|zu{~{wzys{vx~}~|wv}|t{z|{q~~~x{{xutzvv{|}|w{}~y{y|~}~{xu{{xwu}}z~}}{~xy}~}{{x~|}}}}~}~|}~~~y~~}{}x{}~|}p|w}~{~tv{~{}~wt~z{t~uwxzzq{v|}~{|{t|kuv}x}}y~x~~ssy}~{xzzxzu~vp}vw{|~z|}tz}zx{{v~}t{u|wx}z{~u{y|}}~{rx{ox}tzvvzsx~t~wov{vqt~|~~~y~|{~|~~~z~~y}}~uz}||}zy|v}{~~|w{~}~}{u|}ws{~}{xwx|x~~wu}~~}~|z}~w{~||y|}uv{z}~{xy~x~{t|z{|{ws}yv}~|vs~|~||~|~w~y|w}~v{|}v~w{}}{}zwy}{}{zw~wr~{v{y~|{x{{w~z}}~v|vvz{z{v}y~|~u~y|~{|}}x{}~{~twvuz}wuzyx~|t~v~u}z}{r~}x~usr|xq}zxysx~z|{zuu|~|v||x~~x{~{z~{v||yut{}{msqtz{ts|{r}um}tzy~w}{vu~ww~}yz~ty|{}|}~x}vz}x|y|zx~}zy}~{~~}z{yz|}{{|z{vuu{yzw|~{{}~~tvxv~pv{vuxx|u|}oz}yov}}rvu{wru|x||wv~{y}{}}{z{~}{|y|}}{}uv}yy|~~z{z~||zvy~|z{~|~}~z{{x{}}{~y|{|{vz|}w~y{}w~yz{~{~y|~}{}~u{x}~{{~z}vzy|{y~zw|yzxw~|xv{v}zz~~zy{{}}u{vv{~z{~~rz}w~vv{{{u|zu{}w{xvyz{w|~}ywy{}|unu}tryz{vy|z|uu|vwy{yzzz{xuzw~x|}{|zt}v|{{y~~~|{}w}|ztz{vyzuy~x~|}}xvx|yz}v}xv{yyx{}{|x}{|u~z~xuz~xxzz}w{~~~{}~{yow~x{{{~}z~yz~~zuypv|z~|~}|vz}~}yy|zx~v}xuxvz~~z|~~~v}~v}|xx|u{~{v~~{y}vo~yz{s}y{{uurzurs}}~}uy~|wu~~~z||~~tx{uy}{{w{s~}}~zv||x{{x{z{}~~x{z}~yu~yv~}y{~}~y{~y{z{|~w{x{}sz|}zz{{vu~~zy{{|}x{{~~vw|z~xz{~v|~~}xvzx}syz~{yu~~{{|x~|~vz{}~}zz}}u|}t|vxvo}ws~~uu|}~~y|{y{~~x|w}{tz~~{|||~|}t}{||~}|x|ztyz}~|v{~~xu}x{}z{~{|}z}|{|yv|~~{vy~~xr}{v~y~~}|~x{w||y~{yw{~w~|{ww~xxux}{{{ruzws~|~}~~~|yuz~}~t~~~{zw|}p}|uwxv}~u{}v|~}x{~vv}vy{w~w{unwzw}}~vyyv|uy{rupy|~~y~x|x||}~~~{~zx~~{~{|v{~~zy{y{{u~q|}z||~wv|zwx||{z~{{y}}z}~{w~~|wvyzxz|x|}~xzw{{y{||x{zw~uyy~{~~{~{{|}|}z{||r|yz~yzz}xvtuz~zuy|{zz{}vxv~~}zu~}x}|vtwv|z}{v}~}}z~|z~xv~{}~|vy{vw~{~z}~{}~w~~}tz}~y{x{{v~rv{q|rxwq{~|z~v{}z|~~}yy{|u}s}~{y|u{}y~{z{~}~}wu|~|{{tz~wyvywz}z{~}}~q~~yvzzz||~z~|||~}}xyw~z|x}}~y~{v{{}u|{z|}y~~{}~~~x~{{}v{~{|x}wv}yzt~{{}vry{}~z|~w|ty{u{v}v}yz||qz}}|sx|~~~|{{s{||~|{x{{~wu}v{}wp}~u}}uw{{{z|{|~{}~zx{}sz|t~{z~~wt{vuyyyw{{{{|{}yv|}wzuy~~~p~vx~~y~w{x|x{{w}~z~y~yor~vs~|zx{}|{~{{~~|}{xzzz}{x}}||u|~z~~|y~{}{v}|{~qtryt|w{~zp~w~~|~~z|}|{~~~u~~}||}{{~zvv}z~|{z{~z|p}z{||~~~z~{}wv{~}}v{|y~y{|~~t|}|qx}~~{zy}}v~{{~w{{}v~ty{zx}wt}x}ysy~xwz{~|y{~x~}v}t~|v|~||}}|~{{{{{~~vy{y{v|xx{|vxzp{~u|~uv{{|{vx~||{{zyw{y}}uuvp~y~|z~~~{{}w~}|zu~w}vx{z|yw~uqwz|s{{~~{{|~x}z|}ty~x~{{{{zzuy~vv~~~{zz}~z~{{z{{y|{p~zw}}~z}{~x}{{|}}{r{~yxuy}{{vz~yv~}yu~vu{{{~~|~~xy}}z~{u~}wvz~~}y}{vy|vx~zv~{vx}{{{~{z~|sz{wx}w}y{{~xy{~~~~}}{y{y~}{~w{t{}xz{}~v}{~~}{z||{}~y|w}~{{~|v~~~x}~ts~}xz~x~|~wy{~x~||wp}yv}{~wyxqu~{{~v~|tyyy}}{~~|xx~}}zw{zyz~|{~x|v{~u~x{y{}|zz|~~q}{~zxz~{}{~u}z}wyz}ty~}|x~wwv|z|||~|w{~|~z~zuw|y{~{zy}~zxv|}z|~{{p~xx}{zu}wsz~q}|y~y~|s~|w}y~~sx{x~u~y~|{syz|~|~{~}|}t~{zy{yzzuxv{~|{z~}~z{|y}u|x~|w|utxs||}||~v~x~}~|~z~}wzvuw{}}{~|y|}}{}{|~~uux||ru~|y~|}}{z}wxy{{sx~z}u{~|zsw{}~}~|~ty}v{w|}~rr{r}w{}z{~wv|}w~{}|~u}~{y}}}u{x{z{x{}|xx~{{wu{}z{x~xz~qy{{vx}x~u}{~t}yz{w}z~{yzvgv}w}zy~s}uxx{tqv}|u{yw~z}vz~vz{x}z}zu~}}zzzy}{w{z|~y{~|{y}~x|~~v|~v}}|}~{tz|u{y}{|w|yuyyou{vvy{~}|zu{~{wzys{vx~}~|wv}|t{z|{q~~~x{{xutzvv{|}|w{}~y{y|~}~{xu{{xwu}}z~}}{~xy}~}{{x~|}}}}~}~|}~~~y~~}{}x{}~|}p|w}~{~tv{~{}~wt~z{t~uwxzzq{v|}~{|{t|kuv}x}}y~x~~ssy}~{xzzxzu~vp}vw{|~z|}tz}zx{{v~}t{u|wx}z{~u{y|}}~{rx{ox}tzvvzsx~t~wov{vqt~|~x~{{{{zzuy~vv~~~{zz}~z~{{z{{y|{p~zw}}~z}{~x}{{|}}{r{~yxuy}{{vz~yv~}yu~vu{{{~~|~~xy}}z~{u~}wvz~~}y}{vy|vx~zv~{vx}{{{~{z~|sz{wx}w}y{{~xy{~~~~}}{y{y~}{~w{t{}xz{}~v}{~~}{z||{}~y|w}~{{~|v~~~x}~ts~}xz~x~|~wy{~x~||wp}yv}{~wyxqu~{{~v~|tyyy}}{~~|xx~}}zw{zyz~|{~x|v{~u~x{y{}|zz|~~q}{~zxz~{}{~u}z}wyz}ty~}|x~wwv|z|||~|w{~|~z~zuw|y{~{zy}~zxv|}z|~{{p~xx}{zu}wsz~q}|y~y~|s~|w}y~~sx{x~u~y~|{syz|~|~{~}|}t~{zy{yzzuxv{~|{z~}~z{|y}u|x~|w|utxs||}||~v~x~}~|~z~}wzvuw{}}{~|y|}}{}{|~~uux||ru~|y~|}}{z}wxy{{sx~z}u{~|zsw{}~}~|~ty}v{w|}~rr{r}w{}z{~wv|}w~{}|~u}~{y}}}u{x{z{x{}|xx~{{wu{}z{x~xz~qy{{vx}x~u}{~t}yz{w}z~{yzvgv}w}zy~s}uxx{tqv}|u{yw~z}vz~vz{x}z}zu~}}zzzy}{w{z|~y{~|{y}~x|~~v|~v}}|}~{tz|u{y}{|w|yuyyou{vvy{~}|zu{~{wzys{vx~}~|wv}|t{z|{q~~~x{{xutzvv{|}|w{}~y{y|~}~{xu{{xwu}}z~}}{~xy}~}{{x~|}}}}~}~|}~~~y~~}{}x{}~|}p|w}~{~tv{~{}~wt~z{t~uwxzzq{v|}~{|{t|kuv}x}}y~x~~ssy}~{xzzxzu~vp}vw{|~z|}tz}zx{{v~}t{u|wx}z{~u{y|}}~{rx{ox}tzvvzsx~t~wov{vqt~|~~~y~|{~|~~~z~~y}}~uz}||}zy|v}{~~|w{~}~}{u|}ws{~}{xwx|x~~wu}~~}~|z}~w{~||y|}uv{z}~{xy~x~{t|z{|{ws}yv}~|vs~|~||~|~w~y|w}~v{|}v~w{}}{}zwy}{}{zw~wr~{v{y~|{x{{w~z}}~v|vvz{z{v}y~|~u~y|~{|}}x{}~{~twvuz}wuzyx~|t~v~u}z}{r~}x~usr|xq}zxysx~z|{zuu|~|v||x~~x{~{z~{v||yut{}{msqtz{ts|{r}um}tzy~w}{vu~ww~}yz~ty|{}|}~x}vz}x|y|zx~}zy}~{~~}z{yz|}{{|z{vuu{yzw|~{{}~~tvxv~pv{vuxx|u|}oz}yov}}rvu{wru|x||wv~{y}{}}{z{~}{|y|}}{}uv}yy|~~z{z~||zvy~|z{~|~}~z{{x{}}{~y|{|{vz|}w~y{}w~yz{~{~y|~}{}~u{x}~{{~z}vzy|{y~zw|yzxw~|xv{v}zz~~zy{{}}u{vv{~z{~~rz}w~vv{{{u|zu{}w{xvyz{w|~}ywy{}|unu}tryz{vy|z|uu|vwy{yzzz{xuzw~x|}{|zt}v|{{y~~~|{}w}|ztz{vyzuy~x~|}}xvx|yz}v}xv{yyx{}{|x}{|u~z~xuz~xxzz}w{~~~{}~{yow~x{{{~}z~yz~~zuypv|z~|~}|vz}~}yy|zx~v}xuxvz~~z|~~~v}~v}|xx|u{~{v~~{y}vo~yz{s}y{{uurzurs}}~}uy~|wu~~~z||~~tx{uy}{{w{s~}}~zv||x{{x{z{}~~x{z}~yu~yv~}y{~}~y{~y{z{|~w{x{}sz|}zz{{vu~~zy{{|}x{{~~vw|z~xz{~v|~~}xvzx}syz~{yu~~{{|x~|~vz{}~}zz}}u|}t|vxvo}ws~~uu|}~~y|{y{~~x|w}{tz~~{|||~|}t}{||~}|x|ztyz}~|v{~~xu}x{}z{~{|}z}|{|yv|~~{vy~~xr}{v~y~~}|~x{w||y~{yw{~w~|{ww~xxux}{{{ruzws~|~}~~~|yuz~}~t~~~{zw|}p}|uwxv}~u{}v|~}x{~vv}vy{w~w{unwzw}}~vyyv|uy{rupy|~~y~x|x||}~~~{~zx~~{~{|v{~~zy{y{{u~q|}z||~wv|zwx||{z~{{y}}z}~{w~~|wvyzxz|x|}~xzw{{y{||x{zw~uyy~{~~{~{{|}|}z{||r|yz~yzz}xvtuz~zuy|{zz{}vxv~~}zu~}x}|vtwv|z}{v}~}}z~|z~xv~{}~|vy{vw~{~z}~{}~w~~}tz}~y{x{{v~rv{q|rxwq{~|z~v{}z|~~}yy{|u}s}~{y|u{}y~{z{~}~}wu|~|{{tz~wyvywz}z{~}}~q~~yvzzz||~z~|||~}}xyw~z|x}}~y~{v{{}u|{z|}y~~{}~~~x~{{}v{~{|x}wv}yzt~{{}vry{}~z|~w|ty{u{v}v}yz||qz}}|sx|~~~|{{s{||~|{x{{~wu}v{}wpyyu{z~||}~yu|z{xy~}u~x{|wu~vq|{u}{zx|w{|vzxu|r||osz~{|}q{}|~}}}~{{|}~}~~~~y{zv}~|y{}{x{z{wu{~wz~}z~~z}|}~~vx~zv~~{}}~|~~~z{zyxx}~~w}|}{y~z~|{|{u~~{||}}~~{}~{|z{y{y|y{y|~}{{~~}x{}~}}vz~{}}~~}|}~~{y~|~||||{}~|{}}{}|}{y||~~~|{{~||x~w{{{{|~xz{~|~z{~}|{x}~}z|{~}{~}~~z||{{}{z|{~~~{{~{~x~}z|}}}}}~}{~}{y~}~}{~}}{}|}{|~~{}|}~{~z|||||{~{|~~z~z{|~{}}~~y{|~~~|{{~~~}~}~~}z}~~{~{~~|}~~{{~}}}~}}~}}{~|~}{~~|~~~~z}~|{~{|}~{{~{|||~|}|~~|}{~~~{|~~}~|~}|~z}~~~~z~~~}}~|~~~~}~~~~|}}}}~z~|~{}~|{~~~~}|~~}~~~}}||~~~{{{}~~}~~~~}~}}~~~}|{~~~}}~|{}~}|}~~}{~}~|~|}|}~~}}~~~~~~~~|}~}}|~~~~~~}}~~~}}~~~~~}~~}}}}|~~~}}|~}~}~~}~}~~~{~~~~}~~~~~~~}|~~~~~}|~}||~~~~~~~~~~~~~~~~~~~~~~~}}~~~acm-6.0_20200416/objects/sounds/rwr.wav0000644000000000000000000002174613175054611016105 0ustar rootrootRIFF#WAVEfmt @data# @W f,Xg 0  # "[ﭽɨA7]gH J66o©ϸf/%66q¥Ͼ`/<tb b )J쐶סNA ]xHԆE  66r¦ϼa/< q` c  )J쒶աPA ]xHԈC 66u¢Ͽa/< vc `" )I쑶֡NA!]wHԈB!66r¦Ϻf/@f.WIJb0:HR?k> {Y Vnp :ih]//-cz, qPgf L E 5@n$TI7} |:  T' vPF  R>Y$0>!|\ILU] 152(47 C< EdV?ks4t&u6;BM01 :pBo3z+C4[EV |6 b^ Haw$l1bp6wl<>PuO3<NTGFW QDkB|Kh^r= iA`sD\^ qqSW[A[,PNXIoha / Eg; D;jjMR|bP<"HQ=:*r-b<': gU!Iu*I:  Zp5;L-O;"B>^nW u9n)>i$"M\_XME6B6% 0^u| ok"ME U o,+>*jR#b M<+B{5HQLI3 {|7 )x(.* nEPi.? !QA JG(/= V GVBN)K3Qwt];fCNbO'kI sG6T5n\f:1g* <8Q0$V_ JAe8=3|, z^>HaPg( H/4H? ]yQ7XLjg>L3;]eU4^'sF *. &:*3q"k5/D|\B V+F5`_zUGb9_1W KkicK gM Gs] f^@|`\r"p!:NW04m_  }xK4]:&kcomuA _ 59- jt #gJXvy;f !k qT e{2t1H  h *u LMZejx|k DldaF3U<Ac6^U[m\ g}j ;fCDm|#$;rt [BxgzKseo#Os ryo0`UYA8b p= @;grG,fVnQ a6DsDV6\0x}Q9 Xd0Pcd?&^x>^(&d40{Y:`Ao'[UxUj `_+ N  4qZwJ4:$gkDLua7 PwL4{hRo \ -/- )7'xB }k iHjV<&Y@=Q#v 21/+ri6NH,1kP9f4? i&!<"~D{|{Si0.LQhge,z,(O! iEx8b\  r}L~Zg!>ZY*EOwTqo x Og]w? %l '.f7WamyPWuo0k__5"v Z~iW>J\}p{f< 3i;N'\Jjoi6X ee7_<;M QXKs+l$ }.1Q' oKI]cV`  y"*|aPB+ukF_ rnN7G`p=?jEaz =I<UUV $ /@B^+pH)T 3@  FV8$pGse+*,S&7S? C6KEi_@("/+ >>uL % *W^]&p& >  [n>SSWA 5&V7k[ n5Q[[A oz In mMq3] 0d :JyJg BTn~B'j iDY\ rU;h|f0Z^OX 'XeIwSORxUft g`6PWx FbR\xkJvm g7O '(}\ +8g{u})w 47QRdnbqy` B J Grz6R8QsXC { "`f0A!8q S"AX##vlE2bp SovpQ*+EO ;`6J:a =o*>3 CL26.(w  H#I[s]QK-$=zp SAr3Q}X nu # 9iwq L2[ 0o DHhT1^@U #(amr3& *a'X /c(T#1pgIJ vk  "Mz5" _V Mc1 $%pA|qC]).}  "u+6j $Yb0}WODh^~jGv"- f: _C$qx Fdo]Jgi_$q< [Bg1cv. C0f"/~O#EkA\5$me,?C- 0zt\> b} sR;XU+ Q"Sp I3`=cX:&0pBm@M& |=} 7q: qt GO'ZU< nCLqd }ZQmVr8&)s/R [8}UGKqShPYX )_f)7},l/K0$)2_e/hOf <:. hh+r]8C ( unCzei 9AQ 2,( W/]"qc+mvFlH=kJMs}  ?52pG@a|8t.\+/S$;;Zne_SG  ]Ok3lO<m>(;Gep  qxPU l  "(`sU~MlVU[V,]6;H7>b5+q%?-P)< r9_.&9\,>-z > DU%o :6Lj+OH@0 nv'MMU 2 L@T;2$'p37J< )U`" NQut?/ q&tI_Q2T& yB[ uaGq vcBNU]_/TNoTHp89@4]/[_#A##Ov / fb b'O ew}saN kp5%n ( !pLXvWiZ* E eF;?b(' 5?B-&WLPD@\q } 6WWL( OZ>W ^G ,JM$8zBIHCRS_Uheb3&mRN| q(C J Bx(99E8S0&G_k n@yNz MrO ?\lr7l 4_ Jhbj#_4Wg O"=ec!( rf(mN`WxJUvxWc6J6@}~ :Y ;2M`  h|$yUJ{#XL ##v #yZI1lW S?V6~FC4rO OZ],}"Tpw &%5} &sf^8U P6'<&} 8 sa o 3z4>f5%mo] W& [6 22U t64<$o3 G_,$o. j ; Z`; w)R_nxCST-0h*Gb(E6 *wrg{`)cDzn#%=Z A,}&]H i_!miFyB a*8 jb4@ t3N-&W (! b:]cQz1U, <b~:LKEF$dp1b}cmc1J|FcO e o` dv<W4#_q5\r @UeZ+  #MY* K'N"Tj|in !y> acm-6.0_20200416/objects/sounds/generic-piston-engine.wav0000644000000000000000000001753213175054611021462 0ustar rootrootRIFFRWAVEfmt @data.J ]Yei,#_"3%9  J ui Z R 5 Lij `zL:rM}B  9 4 n g  X.pPK>/OaU'$9J?Fmn A y3'ylK9Y cnX *l\CQBe;\8 3 G M @  x)d l*$ NU.!F`- D x *i4e4K Wc0cbcDPiU S + 8x&aEAj'Bn\_7v \  D ^ Z UN@iug%,*_9H#p;f  p =QX&A4; `IO5S% /I2 %B0dNIV[]vJI ,  D < _?dD60K4z=N8 Wm}Q  U G 9 ?  Kvd+Kw }IfEQX!>Lc$wR*&<z L m i ={UPQjz[+bm>='`" ! _ g  TY#dHy<*\$ y>b#{`] 001=5% 7k)#Lp&g%cC= jeb$ a " k cgB%Ihf/]S &} 3 7  HDh` ht%;/)n95Xv;  I Y bsH!'.0r&}]:t{9#\}    7^@k3xMqkN-(/+1?u\3A  z b k  -a;hX"jc@Pf,wdmn .4JX _wHyWQ>dWU@`-?M4|vm]$wh E 8 [ l3gwi6Pt>'{ V|5./8Z  E8 dkki})Vl 9~P%[\R<  l b W 6 [ zej{!wN5Xe[w aAC{{N!#D2j"x r f  6 AT<cPlx ]% 0%DRb[Zz g   # 4(%]42UFD:Ft'^P%]p%} f . 6 ; {iw*9_Xkxv_v? ~ H  U ;  qaUtr HLo3R]EP ^ G  ? 9 9 e'`HXX2d^R~U72dpuK6  7O n'{9a/|g 3 ~ ~ b < ,lCT)c& PI~;j0m(rU + g Y"*#7/g>%#;Pq/D l w GK$@k'-4=0q\6 \    l D\YR]{(M[L,|3p { \ y!ua519CU=y2Ww34J y 0 t { 5 S``YTxJ 2JD>u"gO @? hNU3hoC:">~9m0O { f& 0,nj| [\; cdJa>)Ay7  D; ! C1 ? ewzROZI*.rx9R   G  ow ,P7bvqc t x. * 0  0 5{ILya/2'$ m[' < / J  'u](HZIf+0udc29O= . t K   | h`]8m3}\Kl,"zemrR3 k I - _XHs[S'^t&: 3 Y~0 vzz ##Kzung H`d%d Y%oUQt5wbMQW~cXt[ Mi[ v0X:Sl2.VN&_^Y 7 < XvOA E8{9lNeb02sx7y \ N  ;zT kAk-Arw-MHft n - j:SvNmy q>Y %t4X!<]0d h-9q~qdcja{c`qg$:? }e  7 | >H|rI]c0`%%F Q {  j\bx/|gjaA.kF<} \~W   r 9 mEsHiGL"-@?*`pADHze+' i 8C5TF5?:H_? Jvr3 '  Q G {]I]1|d>gWLa(xA12R s  =_PbIHE}$TJ25g  D } 0 1  fy'y@0+ _# n   q & Q2tVb?]TY0~QT-t;7 $Qlacm-6.0_20200416/objects/sounds/generic-rocket-engine.wav0000644000000000000000000002642213175054611021433 0ustar rootrootRIFF -WAVEfmt s,data,qS  SVQLr`@!!V[SEy!8G.J0xi'p -6j:-^~-)r"n Cf$aGq<~sFat r+]0W'f d1lys FaeWM X@f.WIJb0:HR?k> {Y Vnp :ih]//-cz, qPgf L E 5@n$TI7} |:  T' vPF  R>Y$0>!|\ILU] 152(47 C< EdV?ks4t&u6;BM01 :pBo3z+C4[EV |6 b^ Haw$l1bp6wl<>PuO3<NTGFW QDkB|Kh^r= iA`sD\^ qqSW[A[,PNXIoha / Eg; D;jjMR|bP<"HQ=:*r-b<': gU!Iu*I:  Zp5;L-O;"B>^nW u9n)>i$"M\_XME6B6% 0^u| ok"ME U o,+>*jR#b M<+B{5HQLI3 {|7 )x(.* nEPi.? !QA JG(/= V GVBN)K3Qwt];fCNbO'kI sG6T5n\f:1g* <8Q0$V_ JAe8=3|, z^>HaPg( H/4H? ]yQ7XLjg>L3;]eU4^'sF *. &:*3q"k5/D|\B V+F5`_zUGb9_1W KkicK gM Gs] f^@|`\r"p!:NW04m_  }xK4]:&kcomuA _ 59- jt #gJXvy;f !k qT e{2t1H  h *u LMZejx|k DldaF3U<Ac6^U[m\ g}j ;fCDm|#$;rt [BxgzKseo#Os ryo0`UYA8b p= @;grG,fVnQ a6DsDV6\0x}Q9 Xd0Pcd?&^x>^(&d40{Y:`Ao'[UxUj `_+ N  4qZwJ4:$gkDLua7 PwL4{hRo \ -/- )7'xB }k iHjV<&Y@=Q#v 21/+ri6NH,1kP9f4? i&!<"~D{|{Si0.LQhge,z,(O! iEx8b\  r}L~Zg!>ZY*EOwTqo x Og]w? %l '.f7WamyPWuo0k__5"v Z~iW>J\}p{f< 3i;N'\Jjoi6X ee7_<;M QXKs+l$ }.1Q' oKI]cV`  y"*|aPB+ukF_ rnN7G`p=?jEaz =I<UUV $ /@B^+pH)T 3@  FV8$pGse+*,S&7S? C6KEi_@("/+ >>uL % *W^]&p& >  [n>SSWA 5&V7k[ n5Q[[A oz In mMq3] 0d :JyJg BTn~B'j iDY\ rU;h|f0Z^OX 'XeIwSORxUft g`6PWx FbR\xkJvm g7O '(}\ +8g{u})w 47QRdnbqy` B J Grz6R8QsXC { "`f0A!8q S"AX##vlE2bp SovpQ*+EO ;`6J:a =o*>3 CL26.(w  H#I[s]QK-$=zp SAr3Q}X nu # 9iwq L2[ 0o DHhT1^@U #(amr3& *a'X /c(T#1pgIJ vk  "Mz5" _V Mc1 $%pA|qC]).}  "u+6j $Yb0}WODh^~jGv"- f: _C$qx Fdo]Jgi_$q< [Bg1cv. C0f"/~O#EkA\5$me,?C- 0zt\> b} sR;XU+ Q"Sp I3`=cX:&0pBm@M& |=} 7q: qt GO'ZU< nCLqd }ZQmVr8&)s/R [8}UGKqShPYX )_f)7},l/K0$)2_e/hOf <:. hh+r]8C ( unCzei 9AQ 2,( W/]"qc+mvFlH=kJMs}  ?52pG@a|8t.\+/S$;;Zne_SG  ]Ok3lO<m>(;Gep  qxPU l  "(`sU~MlVU[V,]6;H7>b5+q%?-P)< r9_.&9\,>-z > DU%o :6Lj+OH@0 nv'MMU 2 L@T;2$'p37J< )U`" NQut?/ q&tI_Q2T& yB[ uaGq vcBNU]_/TNoTHp89@4]/[_#A##Ov / fb b'O ew}saN kp5%n ( !pLXvWiZ* E eF;?b(' 5?B-&WLPD@\q } 6WWL( OZ>W ^G ,JM$8zBIHCRS_Uheb3&mRN| q(C J Bx(99E8S0&G_k n@yNz MrO ?\lr7l 4_ Jhbj#_4Wg O"=ec!( rf(mN`WxJUvxWc6J6@}~ :Y ;2M`  h|$yUJ{#XL ##v #yZI1lW S?V6~FC4rO OZ],}"Tpw &%5} &sf^8U P6'<&} 8 sa o 3z4>f5%mo] W& [6 22U t64<$o3 G_,$o. j ; Z`; w)R_nxCST-0h*Gb(E6 *wrg{`)cDzn#%=Z A,}&]H i_!miFyB a*8 jb4@ t3N-&W (! b:]cQz1U, <b~:LKEF$dp1b}cmc1J|FcO e o` dv<W4#_q5\r @UeZ+  #MY* K'N"Tj|in !y> acm-6.0_20200416/objects/sounds/imarker.au0000644000000000000000000001303713175054611016527 0ustar rootroot.snd4@ILS Inner Marker Beacon toneƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7FƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7FƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7FƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7FƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7FƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7FƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7FƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7FƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7FƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7FƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7FƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7FƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7FƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7FƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7FƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7FƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7FƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7FƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7FƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7FƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7FƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7FƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7FƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7FƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7FƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7FƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7FƷM;0,(&%&(,0;MۿF7.*'&&')-4?[ͻ[?4-)'&&'*.7Facm-6.0_20200416/objects/sounds/crash.wav0000644000000000000000000003002013175054611016354 0ustar rootrootRIFF0WAVEfmt @>data/T+p[I ݘ;90XniL;(ddg37ְװ2i8i@YV;]2fF٘۰h   ]\,\02$    ',  :816  #$ !*:A0$ 0E("+0  (%!/#%- ;%   -+';13'Vg# bד[]\)  նϢ^V0Q5_LD3;]/{%fq%ſ?l#@Ն+5@MK &x4 (.#s !5AVkN7W2eBB,6f΀ԉ92cvm@4 58J5[QaR%0E,u 'FX]@ c&{;/3*">HԺ z7I$>/#(K /Ow{tcQJHm$TѰމ/سKC=3oLA@+\-"كR%)I1=$;jiպωMq'3_f}F769P)R1#EʁO%/N!Xʘxc׆#-w'XLfF u5 p_ bp +U: d2kA %  GeD[@Y2 2 ׎݉C_GSKV052!hF;'i%* d!%V h:`Y߅ ;8 EQص?\1w$N 7     "9z& { -)xx2Qj{?'e|$J$:E0mK]"'2c$"c c #(})iEP1sVwxב, 1 '`ZL>7 ?- ۺy'j7s'+#p K),QJr75vr5jO#&"`,)h  T-"шz+ mFJrO]#K<#MM7>6&0 @tKEX${ z  lal Ew"ŷ}8^ #I$D- +Jҋ.i<f [!йȹ*(}!MV}+,"; 6N+(%"?m  ,,;!; /@u®J\$1HC++Ր Dy`  t6y y/c"b:9/A(\#]g62\{ T { akp^ 1n/$..s=lBA]ҮH'6ڥާ~  "(_{ )#&&cC0xp;C;7) wR r?AH>@:ch Sxtv ߕ30c,^-(#/((!$03Sgݻ5Y1l /NO65*#Td-֐>ڤa7**2!| zϋ>44~#* ѱԶI0V'`B4("K[8;6(z?kXB#E )7:#Q8| Y\ } >w ~ 8X !Cմz U  : j!ݎ>kOrC BcS($R E+p +o4%W Բ =v{{A<8$$ u+no"( 9WhBum~GdV_g|6R !,B@*&  WB .ڊذݐKY@\x@2& v j&h&/4{g4Fӓu4 SJ(vK!ҳ z HJ ` h 5 ێ)z `"XRj-{" < [ ʴjPc iJV1Lk"bvz)-$~@ M@&ufc8 ۳N(C5 [ Q $-$?16_*#ENmxb,`uaS57+)-#:j NZRYV(Z NS #J4[$i pQźO>сlaNptEXZ~o( ^ x/|.n P Ga(DrO7 >7zo 5xZ- >5  mW|6'&$spTz)<  2*26l W D% ߆Xt3ys[o - 3'gLygQ@PnVXTcX 8 ]  QehhT T  R od3*C~ c T V pFnݡ>_E|T]^   r  z qB>:B ` av(7F;gsWo5AH 09lR:n 2  $/Z 0 ڎ$z<FI Ub Y b!S |޶H'd F $ @ C }L@tX>i|yIwg9W6K >#n L 3-(`_`B$pPRbN # W, jG%P! .x {42 ..N6 "~P !n*R t Q zOL SF9 2 *M kX(2i). S:  (KRC / X`]oa ag  [eVn =p8}fk:u g b `0\%Dg^ O K.'ba: 5 G_  = `&8-WZZ|$IyY$e&Tr8:} @ X  .T +hz ;Ebs06K J#8P| 19o}wiw!!  g7f,Er^[nD`3qR(8'! eOI^x?% v 9|~ dT& TP]~GA'Ee -  t ! o TYk'Z`bP/EslW v25Ck/ s '@Dv * s@ +J' }`R  s/ |iV@C5h 5 k > <{F` m^km!3  k<4iD|;(5_z e|9$ O#  LQK{DY(k'[v31$T+ fW404UE Vx+ 7$ Pq3=(?M$- ^ h=M O 2LS V] Ey??}|FA5  l ja\ c>!\I1cSJ; ;p & vS)F=gUg1/,{D3Y?5 J**P!!Plzt`$ftpm^"'nPg yB/$]" ZG Y7w VS N oDEv6z?RQZ  bW /'qj"!"|X#FL u-T8%j> t_UWy3AI)qeH  j X>Qp&2`<of7gd/hih0cb[; U&R$RF (z>T#,b%K<Mg , 9%"J2$  _N\{ wd^oqZk y"`>M0#s{_EqA%'MU~zWkh*OY9/Iz*^sih3yH"!J(V'W5,5y w_A=hSn{IkB6E { {?U;Slr<w=B4U4vX^~4jyo\B@P t'NC9 ~dA$!#%kv!g7V 7*NJDL[+^Z/giI:Sj;w>Q@G;AMM! *w]xeCf)A` eCADQJAOGlM 3l kwo.l\~>w=!H0;ZVI4R "d;V8`8dZ,ln.5-bJ<8O"mcGPl}|`/$ %OnbE!]d Qb99$/OKM4 &$ %I}|QD;BR.PGf+,(CheT: N[GEKMO/     (,!#       acm-6.0_20200416/objects/sounds/mmarker.au0000644000000000000000000002220713175054611016532 0ustar rootroot.snd5$R@ILS Middle Marker Beacon tone*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()*'M-&?0&77&0?&-ƧM'*ۨ)([,'F.&;4%4;&.F',ͧ[()acm-6.0_20200416/objects/sounds/gear_dn.wav0000644000000000000000000004736313175054611016675 0ustar rootrootRIFFNWAVEfmt @@dataN~~~|~{{{z}|}}~~z}}z~~~{}{{}~}}~|{|~~||||{{}y|w{~{}{z|}|x}y}}}|{|{|{y{z{s{{r{{v{{xvy{{~{vv}x~{y|w|pw{|y~}~{zv{xx{{w}~w}~~}}}v|z}}}pz||~{|y~~xv|~}xv|~z}}~~|x~w{w{|zzxqxqy{|y||xx|{~}|~~~z{}}yxzr|||~wx|~|{}~|t|~{{w{~}~{~t{x|~|z~|y{{v~}|y}|}{u|~{~|}{{|{~~{}~{{}~||x{wv~}}q{{v~|zxz~{x{~vv{z~~{{z|~}{xwvz{{{v}{t~xu~{|{|o~|y~}~u}}uw{{{z|{|~{}~zx{}sz|t~{z~~wt{vuyyyw{{{{|{}yv|}wzuy~~~p~vx~~y~w{x|x{{w}~z~y~yor~vs~|zx{}|{~{{~~|}{xzzz}{x}}||u|~z~~|y~{}{v}|{~qtryt|w{~zp~w~~|~~z|}|{~~~u~~}||}{{~zvv}z~|{z{~z|p}z{||~~~z~{}wv{~}}v{|y~y{|~~t|}|qx}~~{zy}}v~{{~w{{}v~ty{zx}wt}x}ysy~xwz{~|y{~x~}v}t~|v|~||}}|~{{{{{~~vy{y{v|xx{|vxzp{~u|~uv{{|{vx~||{{zyw{y}}uuvp~y~|z~~~{{}w~}|zu~w}vx{z|yw~uqwz|s{{~~{{|~x}z|}ty~x~{{{{zzuy~vv~~~{zz}~z~{{z{{y|{p~zw}}~z}{~x}{{|}}{r{~yxuy}{{vz~yv~}yu~vu{{{~~|~~xy}}z~{u~}wvz~~}y}{vy|vx~zv~{vx}{{{~{z~|sz{wx}w}y{{~xy{~~~~}}{y{y~}{~w{t{}xz{}~v}{~~}{z||{}~y|w}~{{~|v~~~x}~ts~}xz~x~|~wy{~x~||wp}yv}{~wyxqu~{{~v~|tyyy}}{~~|xx~}}zw{zyz~|{~x|v{~u~x{y{}|zz|~~q}{~zxz~{}{~u}z}wyz}ty~}|x~wwv|z|||~|w{~|~z~zuw|y{~{zy}~zxv|}z|~{{p~xx}{zu}wsz~q}|y~y~|s~|w}y~~sx{x~u~y~|{syz|~|~{~}|}t~{zy{yzzuxv{~|{z~}~z{|y}u|x~|w|utxs||}||~v~x~}~|~z~}wzvuw{}}{~|y|}}{}{|~~uux||ru~|y~|}}{z}wxy{{sx~z}u{~|zsw{}~}~|~ty}v{w|}~rr{r}w{}z{~wv|}w~{}|~u}~{y}}}u{x{z{x{}|xx~{{wu{}z{x~xz~qy{{vx}x~u}{~t}yz{w}z~{yzvgv}w}zy~s}uxx{tqv}|u{yw~z}vz~vz{x}z}zu~}}zzzy}{w{z|~y{~|{y}~x|~~v|~v}}|}~{tz|u{y}{|w|yuyyou{vvy{~}|zu{~{wzys{vx~}~|wv}|t{z|{q~~~x{{xutzvv{|}|w{}~y{y|~}~{xu{{xwu}}z~}}{~xy}~}{{x~|}}}}~}~|}~~~y~~}{}x{}~|}p|w}~{~tv{~{}~wt~z{t~uwxzzq{v|}~{|{t|kuv}x}}y~x~~ssy}~{xzzxzu~vp}vw{|~z|}tz}zx{{v~}t{u|wx}z{~u{y|}}~{rx{ox}tzvvzsx~t~wov{vqt~|~x~{{{{zzuy~vv~~~{zz}~z~{{z{{y|{p~zw}}~z}{~x}{{|}}{r{~yxuy}{{vz~yv~}yu~vu{{{~~|~~xy}}z~{u~}wvz~~}y}{vy|vx~zv~{vx}{{{~{z~|sz{wx}w}y{{~xy{~~~~}}{y{y~}{~w{t{}xz{}~v}{~~}{z||{}~y|w}~{{~|v~~~x}~ts~}xz~x~|~wy{~x~||wp}yv}{~wyxqu~{{~v~|tyyy}}{~~|xx~}}zw{zyz~|{~x|v{~u~x{y{}|zz|~~q}{~zxz~{}{~u}z}wyz}ty~}|x~wwv|z|||~|w{~|~z~zuw|y{~{zy}~zxv|}z|~{{p~xx}{zu}wsz~q}|y~y~|s~|w}y~~sx{x~u~y~|{syz|~|~{~}|}t~{zy{yzzuxv{~|{z~}~z{|y}u|x~|w|utxs||}||~v~x~}~|~z~}wzvuw{}}{~|y|}}{}{|~~uux||ru~|y~|}}{z}wxy{{sx~z}u{~|zsw{}~}~|~ty}v{w|}~rr{r}w{}z{~wv|}w~{}|~u}~{y}}}u{x{z{x{}|xx~{{wu{}z{x~xz~qy{{vx}x~u}{~t}yz{w}z~{yzvgv}w}zy~s}uxx{tqv}|u{yw~z}vz~vz{x}z}zu~}}zzzy}{w{z|~y{~|{y}~x|~~v|~v}}|}~{tz|u{y}{|w|yuyyou{vvy{~}|zu{~{wzys{vx~}~|wv}|t{z|{q~~~x{{xutzvv{|}|w{}~y{y|~}~{xu{{xwu}}z~}}{~xy}~}{{x~|}}}}~}~|}~~~y~~}{}x{}~|}p|w}~{~tv{~{}~wt~z{t~uwxzzq{v|}~{|{t|kuv}x}}y~x~~ssy}~{xzzxzu~vp}vw{|~z|}tz}zx{{v~}t{u|wx}z{~u{y|}}~{rx{ox}tzvvzsx~t~wov{vqt~|~~~y~|{~|~~~z~~y}}~uz}||}zy|v}{~~|w{~}~}{u|}ws{~}{xwx|x~~wu}~~}~|z}~w{~||y|}uv{z}~{xy~x~{t|z{|{ws}yv}~|vs~|~||~|~w~y|w}~v{|}v~w{}}{}zwy}{}{zw~wr~{v{y~|{x{{w~z}}~v|vvz{z{v}y~|~u~y|~{|}}x{}~{~twvuz}wuzyx~|t~v~u}z}{r~}x~usr|xq}zxysx~z|{zuu|~|v||x~~x{~{z~{v||yut{}{msqtz{ts|{r}um}tzy~w}{vu~ww~}yz~ty|{}|}~x}vz}x|y|zx~}zy}~{~~}z{yz|}{{|z{vuu{yzw|~{{}~~tvxv~pv{vuxx|u|}oz}yov}}rvu{wru|x||wv~{y}{}}{z{~}{|y|}}{}uv}yy|~~z{z~||zvy~|z{~|~}~z{{x{}}{~y|{|{vz|}w~y{}w~yz{~{~y|~}{}~u{x}~{{~z}vzy|{y~zw|yzxw~|xv{v}zz~~zy{{}}u{vv{~z{~~rz}w~vv{{{u|zu{}w{xvyz{w|~}ywy{}|unu}tryz{vy|z|uu|vwy{yzzz{xuzw~x|}{|zt}v|{{y~~~|{}w}|ztz{vyzuy~x~|}}xvx|yz}v}xv{yyx{}{|x}{|u~z~xuz~xxzz}w{~~~{}~{yow~x{{{~}z~yz~~zuypv|z~|~}|vz}~}yy|zx~v}xuxvz~~z|~~~v}~v}|xx|u{~{v~~{y}vo~yz{s}y{{uurzurs}}~}uy~|wu~~~z||~~tx{uy}{{w{s~}}~zv||x{{x{z{}~~x{z}~yu~yv~}y{~}~y{~y{z{|~w{x{}sz|}zz{{vu~~zy{{|}x{{~~vw|z~xz{~v|~~}xvzx}syz~{yu~~{{|x~|~vz{}~}zz}}u|}t|vxvo}ws~~uu|}~~y|{y{~~x|w}{tz~~{|||~|}t}{||~}|x|ztyz}~|v{~~xu}x{}z{~{|}z}|{|yv|~~{vy~~xr}{v~y~~}|~x{w||y~{yw{~w~|{ww~xxux}{{{ruzws~|~}~~~|yuz~}~t~~~{zw|}p}|uwxv}~u{}v|~}x{~vv}vy{w~w{unwzw}}~vyyv|uy{rupy|~~y~x|x||}~~~{~zx~~{~{|v{~~zy{y{{u~q|}z||~wv|zwx||{z~{{y}}z}~{w~~|wvyzxz|x|}~xzw{{y{||x{zw~uyy~{~~{~{{|}|}z{||r|yz~yzz}xvtuz~zuy|{zz{}vxv~~}zu~}x}|vtwv|z}{v}~}}z~|z~xv~{}~|vy{vw~{~z}~{}~w~~}tz}~y{x{{v~rv{q|rxwq{~|z~v{}z|~~}yy{|u}s}~{y|u{}y~{z{~}~}wu|~|{{tz~wyvywz}z{~}}~q~~yvzzz||~z~|||~}}xyw~z|x}}~y~{v{{}u|{z|}y~~{}~~~x~{{}v{~{|x}wv}yzt~{{}vry{}~z|~w|ty{u{v}v}yz||qz}}|sx|~~~|{{s{||~|{x{{~wu}v{}wp}~u}}uw{{{z|{|~{}~zx{}sz|t~{z~~wt{vuyyyw{{{{|{}yv|}wzuy~~~p~vx~~y~w{x|x{{w}~z~y~yor~vs~|zx{}|{~{{~~|}{xzzz}{x}}||u|~z~~|y~{}{v}|{~qtryt|w{~zp~w~~|~~z|}|{~~~u~~}||}{{~zvv}z~|{z{~z|p}z{||~~~z~{}wv{~}}v{|y~y{|~~t|}|qx}~~{zy}}v~{{~w{{}v~ty{zx}wt}x}ysy~xwz{~|y{~x~}v}t~|v|~||}}|~{{{{{~~vy{y{v|xx{|vxzp{~u|~uv{{|{vx~||{{zyw{y}}uuvp~y~|z~~~{{}w~}|zu~w}vx{z|yw~uqwz|s{{~~{{|~x}z|}ty~x~{{{{zzuy~vv~~~{zz}~z~{{z{{y|{p~zw}}~z}{~x}{{|}}{r{~yxuy}{{vz~yv~}yu~vu{{{~~|~~xy}}z~{u~}wvz~~}y}{vy|vx~zv~{vx}{{{~{z~|sz{wx}w}y{{~xy{~~~~}}{y{y~}{~w{t{}xz{}~v}{~~}{z||{}~y|w}~{{~|v~~~x}~ts~}xz~x~|~wy{~x~||wp}yv}{~wyxqu~{{~v~|tyyy}}{~~|xx~}}zw{zyz~|{~x|v{~u~x{y{}|zz|~~q}{~zxz~{}{~u}z}wyz}ty~}|x~wwv|z|||~|w{~|~z~zuw|y{~{zy}~zxv|}z|~{{p~xx}{zu}wsz~q}|y~y~|s~|w}y~~sx{x~u~y~|{syz|~|~{~}|}t~{zy{yzzuxv{~|{z~}~z{|y}u|x~|w|utxs||}||~v~x~}~|~z~}wzvuw{}}{~|y|}}{}{|~~uux||ru~|y~|}}{z}wxy{{sx~z}u{~|zsw{}~}~|~ty}v{w|}~rr{r}w{}z{~wv|}w~{}|~u}~{y}}}u{x{z{x{}|xx~{{wu{}z{x~xz~qy{{vx}x~u}{~t}yz{w}z~{yzvgv}w}zy~s}uxx{tqv}|u{yw~z}vz~vz{x}z}zu~}}zzzy}{w{z|~y{~|{y}~x|~~v|~v}}|}~{tz|u{y}{|w|yuyyou{vvy{~}|zu{~{wzys{vx~}~|wv}|t{z|{q~~~x{{xutzvv{|}|w{}~y{y|~}~{xu{{xwu}}z~}}{~xy}~}{{x~|}}}}~}~|}~~~y~~}{}x{}~|}p|w}~{~tv{~{}~wt~z{t~uwxzzq{v|}~{|{t|kuv}x}}y~x~~ssy}~{xzzxzu~vp}vw{|~z|}tz}zx{{v~}t{u|wx}z{~u{y|}}~{rx{ox}tzvvzsx~t~wov{vqt~|~x~{{{{zzuy~vv~~~{zz}~z~{{z{{y|{p~zw}}~z}{~x}{{|}}{r{~yxuy}{{vz~yv~}yu~vu{{{~~|~~xy}}z~{u~}wvz~~}y}{vy|vx~zv~{vx}{{{~{z~|sz{wx}w}y{{~xy{~~~~}}{y{y~}{~w{t{}xz{}~v}{~~}{z||{}~y|w}~{{~|v~~~x}~ts~}xz~x~|~wy{~x~||wp}yv}{~wyxqu~{{~v~|tyyy}}{~~|xx~}}zw{zyz~|{~x|v{~u~x{y{}|zz|~~q}{~zxz~{}{~u}z}wyz}ty~}|x~wwv|z|||~|w{~|~z~zuw|y{~{zy}~zxv|}z|~{{p~xx}{zu}wsz~q}|y~y~|s~|w}y~~sx{x~u~y~|{syz|~|~{~}|}t~{zy{yzzuxv{~|{z~}~z{|y}u|x~|w|utxs||}||~v~x~}~|~z~}wzvuw{}}{~|y|}}{}{|~~uux||ru~|y~|}}{z}wxy{{sx~z}u{~|zsw{}~}~|~ty}v{w|}~rr{r}w{}z{~wv|}w~{}|~u}~{y}}}u{x{z{x{}|xx~{{wu{}z{x~xz~qy{{vx}x~u}{~t}yz{w}z~{yzvgv}w}zy~s}uxx{tqv}|u{yw~z}vz~vz{x}z}zu~}}zzzy}{w{z|~y{~|{y}~x|~~v|~v}}|}~{tz|u{y}{|w|yuyyou{vvy{~}|zu{~{wzys{vx~}~|wv}|t{z|{q~~~x{{xutzvv{|}|w{}~y{y|~}~{xu{{xwu}}z~}}{~xy}~}{{x~|}}}}~}~|}~~~y~~}{}x{}~|}p|w}~{~tv{~{}~wt~z{t~uwxzzq{v|}~{|{t|kuv}x}}y~x~~ssy}~{xzzxzu~vp}vw{|~z|}tz}zx{{v~}t{u|wx}z{~u{y|}}~{rx{ox}tzvvzsx~t~wov{vqt~|~~~y~|{~|~~~z~~y}}~uz}||}zy|v}{~~|w{~}~}{u|}ws{~}{xwx|x~~wu}~~}~|z}~w{~||y|}uv{z}~{xy~x~{t|z{|{ws}yv}~|vs~|~||~|~w~y|w}~v{|}v~w{}}{}zwy}{}{zw~wr~{v{y~|{x{{w~z}}~v|vvz{z{v}y~|~u~y|~{|}}x{}~{~twvuz}wuzyx~|t~v~u}z}{r~}x~usr|xq}zxysx~z|{zuu|~|v||x~~x{~{z~{v||yut{}{msqtz{ts|{r}um}tzy~w}{vu~ww~}yz~ty|{}|}~x}vz}x|y|zx~}zy}~{~~}z{yz|}{{|z{vuu{yzw|~{{}~~tvxv~pv{vuxx|u|}oz}yov}}rvu{wru|x||wv~{y}{}}{z{~}{|y|}}{}uv}yy|~~z{z~||zvy~|z{~|~}~z{{x{}}{~y|{|{vz|}w~y{}w~yz{~{~y|~}{}~u{x}~{{~z}vzy|{y~zw|yzxw~|xv{v}zz~~zy{{}}u{vv{~z{~~rz}w~vv{{{u|zu{}w{xvyz{w|~}ywy{}|unu}tryz{vy|z|uu|vwy{yzzz{xuzw~x|}{|zt}v|{{y~~~|{}w}|ztz{vyzuy~x~|}}xvx|yz}v}xv{yyx{}{|x}{|u~z~xuz~xxzz}w{~~~{}~{yow~x{{{~}z~yz~~zuypv|z~|~}|vz}~}yy|zx~v}xuxvz~~z|~~~v}~v}|xx|u{~{v~~{y}vo~yz{s}y{{uurzurs}}~}uy~|wu~~~z||~~tx{uy}{{w{s~}}~zv||x{{x{z{}~~x{z}~yu~yv~}y{~}~y{~y{z{|~w{x{}sz|}zz{{vu~~zy{{|}x{{~~vw|z~xz{~v|~~}xvzx}syz~{yu~~{{|x~|~vz{}~}zz}}u|}t|vxvo}ws~~uu|}~~y|{y{~~x|w}{tz~~{|||~|}t}{||~}|x|ztyz}~|v{~~xu}x{}z{~{|}z}|{|yv|~~{vy~~xr}{v~y~~}|~x{w||y~{yw{~w~|{ww~xxux}{{{ruzws~|~}~~~|yuz~}~t~~~{zw|}p}|uwxv}~u{}v|~}x{~vv}vy{w~w{unwzw}}~vyyv|uy{rupy|~~y~x|x||}~~~{~zx~~{~{|v{~~zy{y{{u~q|}z||~wv|zwx||{z~{{y}}z}~{w~~|wvyzxz|x|}~xzw{{y{||x{zw~uyy~{~~{~{{|}|}z{||r|yz~yzz}xvtuz~zuy|{zz{}vxv~~}zu~}x}|vtwv|z}{v}~}}z~|z~xv~{}~|vy{vw~{~z}~{}~w~~}tz}~y{x{{v~rv{q|rxwq{~|z~v{}z|~~}yy{|u}s}~{y|u{}y~{z{~}~}wu|~|{{tz~wyvywz}z{~}}~q~~yvzzz||~z~|||~}}xyw~z|x}}~y~{v{{}u|{z|}y~~{}~~~x~{{}v{~{|x}wv}yzt~{{}vry{}~z|~w|ty{u{v}v}yz||qz}}|sx|~~~|{{s{||~|{x{{~wu}v{}wpyyu{z~||}~yu|z{xy~}u~x{|wu~vq|{u}{zx|w{|vzxu|r||osz~{|}q{}|~}}}~{{|}~}~~~~y{zv}~|y{}{x{z{wu{~wz~}z~~z}|}~~vx~zv~~{}}~|~~~z{zyxx}~~w}|}{y~z~|{|{u~~{||}}~~{}~{|z{y{y|y{y|~}{{~~}x{}~}}vz~{}}~~}|}~~{y~|~||||{}~|{}}{}|}{y||~~~|{{~||x~w{{{{|~xz{~|~z{~}|{x}~}z|{~}{~}~~z||{{}{z|{~~~{{~{~x~}z|}}}}}~}{~}{y~}~}{~}}{}|}{|~~{}|}~{~z|||||{~{|~~z~z{|~{}}~~y{|~~~|{{~~~}~}~~}z}~~{~{~~|}~~{{~}}}~}}~}}{~|~}{~~|~~~~z}~|{~{|}~{{~{|||~|}|~~|}{~~~{|~~}~|~}|~z}~~~~z~~~}}~|~~~~}~~~~|}}}}~z~|~{}~|{~~~~}|~~}~~~}}||~~~{{{}~~}~~~~}~}}~~~}|{~~~}}~|{}~}|}~~}{~}~|~|}|}~~}}~~~~~~~~|}~}}|~~~~~~}}~~~}}~~~~~}~~}}}}|~~~}}|~}~}~~}~}~~~{~~~~}~~~~~~~}|~~~~~}|~}||~~~~~~~~~~~~~~~~~~~~~~~}}~~~acm-6.0_20200416/objects/sounds/cannon.wav0000644000000000000000000001540413175054611016541 0ustar rootrootRIFFWAVEfmt @>data,<3@'vb7ZQH;1iVxps^d8U6`Bl,6 `.\k i?j/2%h(5q\PD{rT  M $ Od"o+`Kl  $ 7 j oi q .'< i ]KbK;`mvnLRUn(8H " xJ"b U#qW-uq,!]~Op08BU;Om< , 8     *V(i<C3lC"$B+o9Q%l! 'T4A9;=M! ]0G8&tv![NQkZ^B e x ) Dx+EX  , [xjI;sc#di;3]%.h;ci5xnl ;  VBTN,ni,SNi [ E  1  &, oN? /88V6PrT' ?G *] T5UFm?2K`Tsp4| "HfAY8gu]G f)la ;`^ s BG{Wk(MuqJvqi_@! ]  X^ < iMZ|tYF@K !/ /j - * 2;]hY% 4  :W,7'AK 4z3 UE8?e 5t -a~cwF |gX;& Y N  0Wy(rp0S xG&7Ru9NW~7GS$M^RRVpg*oiz #xQv,,F EnNS!2P P d kp$);0M*ME7A{Aa_"^ Ar H%ri K jY 8 6 yUA x/!t *"U$VqK&*:t/pp;WZnnP q  6 u V  _ j2+(s6N`0j  0 ~ (X> Jh#!=4} 6 t  }07a .pG0: _b8V:/Gcos61 p^Hm(}wEDN ys + S +X/3!C)3x9gjRp84 W 2@'=-H`NSpR&UM|iQ,A?_a0PR `|gt{9e.1  U ( a /q@>FrN2K[},\ h : e gt{O` + Wk LYLmW?h Q2 ! 8  F~.CRwrE.B&h0RM  S   eB7VRGHgV^vH9Pwj*#>LE$Tx jfb>0C  3 ^xx& ~+jd9eC  gh fT Q  KIw`L$8Qqoqd'6Z  a&0aFy5)Z A}#9.X-JbIjxM P6@@ _$ # > #  H?WT< eK]_Dz/}2P]V%Re  @wK!)e3k^`i,Bv  r {^u_b!a),#K[Rl6k#uS k Y4Mb $ x O1>;~FTf/~ Po Z j v W /m^Y)i].q!Pj 1qFX+ 4 O"W E 8zt/f"KqgDk 6Pr  " (p!%]+XR(~/PkfOwF5'UE fnIO)w-}u0,UVLD/= _mB8$xB7Yzum= /j S{y`5#-Cd]$:+Pa*4h$mb v ^R q+5Ga^CF:i{9_ l` -Pd89 .EQ2r R, N9b$&7n:' W =FMz~nCA*{\mKT"eQOH=py(@E< (   kH18GbX  @ 4 .7i%{tE5Fb[<Gv j/|;wNQ.z2j4 +  N{\ !142@S3>.Kz* ; Pjr,HY"=xs*M5!dTw,F [ t w&#nS7_2~0> pb U WvP aU k inv!5e,CLCI\}t9f$    }Dwe?_t6P D8@Q)olytxpVi^qiy&6 b!^MA0Qp  ' B Z xmKE#Q?qT f>Ab}E//}&Y_",[mCR`Qg3Bacm-6.0_20200416/objects/features/0000755000000000000000000000000013175062137015047 5ustar rootrootacm-6.0_20200416/objects/features/telar1.obv0000644000000000000000000000610610357223037016747 0ustar rootrootobject 116 22 1 11 -8.625 5.64444 2 12.0097 -8.625 5.37388 3 12.7489 -8.625 4.63472 4 13.0194 -8.625 3.625 5 12.7489 -8.625 2.61528 6 12.0097 -8.625 1.87612 7 11 -8.625 1.60556 8 9.99028 -8.625 1.87612 9 9.25112 -8.625 2.61528 10 8.98056 -8.625 3.625 11 9.25112 -8.625 4.63472 12 9.99028 -8.625 5.37388 13 -21.8769 0.25 -4.25 14 -20.9198 0.25 2.875 15 -21 -6.25 3 16 -21.5 -6 -0.75 17 -21.5 -9.375 -0.375 18 -22 -8 -4.25 19 -22 8 -4.25 20 -21.5 9.375 -0.375 21 -21.5 6 -0.75 22 -21 6.25 3 23 -20.9198 -0.25 2.875 24 -21.8769 -0.25 -4.25 25 -15.375 6.125 -8.79722 26 -15.625 2.375 -8.625 27 -4.375 2.125 -16.375 28 -4.375 6.125 -16.375 29 -4.375 -6.125 -16.375 30 -4.375 -2.125 -16.375 31 -15.625 -2.375 -8.625 32 -15.375 -6.125 -8.79722 33 -3.375 -6.25 -15.25 34 -3.375 -2.25 -15.25 35 -14.625 -2.5 -7.5 36 -14.375 -6.25 -7.67222 37 -14.375 6.25 -7.67222 38 -14.625 2.5 -7.5 39 -3.375 2.25 -15.25 40 -3.375 6.25 -15.25 41 -14.875 6.16094 -8.875 42 -14.125 6.25 -7.75 43 -3.25 6.375 -14.75 44 -4.25 6.25 -16.375 45 -4.25 -6.25 -16.375 46 -3.25 -6.375 -14.75 47 -14.125 -6.25 -7.75 48 -14.875 -6.16094 -8.875 49 -7.625 0.125 -15.5 50 -7.375 -1.5 -15.375 51 -6.625 -2.25 -14.125 52 -6.07258 -1.25 -12.875 53 -6 -0.125 -12.5 54 -6.46371 1.625 -13 55 -7.14718 2.375 -14.125 56 -7.82258 1.875 -15.5 57 19.375 5.625 -0.875 58 19.375 -5.5 -0.625 59 15.25 -6.375 3.5 60 15.5845 6.625 2.875 61 19.625 5.5 -0.625 62 19.5 -5.25 -0.5 63 12.625 -6.25 -2 64 12.625 7.125 -2.18978 65 16 -6.125 -0.75 66 15.875 -9.375 -0.25 67 5 -9.375 -0.375 68 5 9.375 -0.375 69 15.875 9.375 -0.25 70 16 6.125 -0.75 71 12.625 7.125 -2.125 72 10.625 6.5 -4.125 73 10.625 -6.375 -4.125 74 12.75 -6.25 -2 75 10.75 -0.125 -4.125 76 -22 -0.125 -4.125 77 -22.125 -8.125 -4.125 78 5.5 -8 -4.125 79 10.75 -6.5 -4.125 80 10.75 6.5 -4.125 81 5.5 8 -4.125 82 -22.125 8.125 -4.125 83 -22 0.125 -4.125 84 10.75 0.125 -4.125 85 5.5 -9.125 -0.125 86 -21.5 -9.125 -0.125 87 -22.125 -7.875 -4.125 88 5.5 -7.875 -4.125 89 5.5 7.875 -4.125 90 -22.125 7.875 -4.125 91 -21.5 9.125 -0.125 92 5.5 9.125 -0.125 93 11.75 -6.58244 -2.375 94 12.875 -6.29936 -2.25 95 12.875 -6.93003 0 96 5.625 -8.875 -0.375 97 5.25 -8 -3.875 98 10.625 -6.375 -4.25 99 10.625 6.375 -4.25 100 5.25 8 -3.875 101 5.625 8.875 -0.375 102 12.875 6.93003 0 103 12.875 6.29936 -2.25 104 11.75 6.58244 -2.375 105 59.625 0 -4.82322 106 59.7134 0 -4.84691 107 59.7781 0 -4.91161 108 59.8018 0 -5 109 59.7781 0 -5.08839 110 59.7134 0 -5.15309 111 59.625 0 -5.17678 112 59.5366 0 -5.15309 113 59.4719 0 -5.08839 114 59.4482 0 -5 115 59.4719 0 -4.91161 116 59.5366 0 -4.84691 gray44 12 1 2 3 4 5 6 7 8 9 10 11 12 gray44 6 13 14 15 16 17 18 gray44 6 19 20 21 22 23 24 gray44 4 25 26 27 28 gray44 4 29 30 31 32 gray44 4 33 34 35 36 gray44 4 37 38 39 40 gray44 4 41 42 43 44 gray44 4 45 46 47 48 gray44 8 49 50 51 52 53 54 55 56 gray44 4 57 58 59 60 gray44 4 61 62 63 64 gray44 3 65 66 67 gray44 3 68 69 70 gray44 4 71 72 73 74 gray44 5 75 76 77 78 79 gray44 5 80 81 82 83 84 gray44 4 85 86 87 88 gray44 4 89 90 91 92 gray44 6 93 94 95 96 97 98 gray44 6 99 100 101 102 103 104 gray44 12 105 106 107 108 109 110 111 112 113 114 115 116 acm-6.0_20200416/objects/features/hangar.obv0000644000000000000000000000226710357223037017023 0ustar rootrootobject 52 10 1 60.0 37.5 0 2 60.0 36 -24.75 3 60.0 0 -24.75 4 60.0 0 -60 5 60.0 27.75 -49.5 6 60.0 60.0 -30 7 60.0 60 0 8 60.0 -60 0 9 60.0 -60 -30 10 60.0 -28.5 -49.5 11 60.0 0 -60 12 60.0 0 -24.75 13 60.0 -36.75 -24.75 14 60.0 -38.25 0 15 -60.0 -38.25 0 16 -60.0 -36.75 -24.75 17 -60.0 0 -24.75 18 -60.0 0 -60 19 -60.0 -28.5 -49.5 20 -60.0 -60 -30 21 -60.0 -60 0 22 -60.0 60 0 23 -60.0 60.0 -30 24 -60.0 27.75 -49.5 25 -60.0 0 -60 26 -60.0 0 -24.75 27 -60.0 36 -24.75 28 -60.0 37.5 0 29 61.125 60.0 0 30 61.125 60.0 -30 31 -60 60.0 -30 32 -60 60.0 0 33 -60 -60.0 0 34 -60 -60.0 -30 35 61.125 -60.0 -30 36 61.125 -60.0 0 37 -60 -60 -30 38 -60 -27.375 -49.5 39 60 -27.375 -49.5 40 60 -60 -30 41 60 0 -60 42 -60 -0 -60 43 -60 -27.375 -49.5 44 60 -27.375 -49.5 45 60 27.375 -49.5 46 -60 27.375 -49.5 47 -60 0 -60 48 60 -0 -60 49 60 60 -30 50 60 27.375 -49.5 51 -60 27.375 -49.5 52 -60 60 -30 (gray44 black) 7 1 2 3 4 5 6 7 (black gray44) 7 8 9 10 11 12 13 14 (gray44 black) 7 15 16 17 18 19 20 21 (black gray44) 7 22 23 24 25 26 27 28 (black gray44) 4 29 30 31 32 (black gray44) 4 33 34 35 36 (black gray44) 4 37 38 39 40 (gray44 black) 4 41 42 43 44 (gray44 black) 4 45 46 47 48 (black gray44) 4 49 50 51 52 acm-6.0_20200416/objects/features/surface.obv0000644000000000000000000003452010357223037017210 0ustar rootroot#788b63-mass 510 3 1 158400 -274357 0 2 -158400 -274357 0 3 -158400 0 0 4 -158400 274357 0 5 158400 274357 0 6 316800 0 0 7 -43779.8 262562 0.02 8 -43779.8 262562 0.02 9 -43867.1 265104 0.02 10 -44463.8 267083 0.02 11 -45060.4 269062 0.02 12 -45452.3 271416 0.02 13 -46048.6 273395 0.02 14 -46338.5 274357 0.02 15 -81588.9 274357 0.02 16 -81990.8 273359 0.02 17 -82710.3 271574 0.02 18 -83329.1 269693 0.02 19 -83545.3 267434 0.02 20 -83459.3 264891 0.02 21 -83067.7 262629 0.02 22 -82471.9 260649 0.02 23 -81876.6 258574 0.02 24 -81585.9 256313 0.02 25 -81193.8 254050 0.02 26 -81107 251506 0.02 27 -81523.6 249435 0.02 28 -82141.1 247647 0.02 29 -82859.8 245859 0.02 30 -83579 243977 0.02 31 -84297.6 242188 0.02 32 -84914.9 240400 0.02 33 -85331.2 238327 0.02 34 -85747.4 236255 0.02 35 -85961.9 233993 0.02 36 -85874 231447 0.02 37 -85684.7 228901 0.02 38 -85899.4 226544 0.02 39 -85810.6 224092 0.02 40 -85719.8 222017 0.02 41 -84817.2 220222 0.02 42 -83506.1 219086 0.02 43 -81482.7 218608 0.02 44 -79960.6 219169 0.02 45 -77931.5 219822 0.02 46 -75903 220381 0.02 47 -73672.7 220751 0.02 48 -71341 221121 0.02 49 -69110.7 221490 0.02 50 -66779 221859 0.02 51 -64750.2 222418 0.02 52 -63326.6 223545 0.02 53 -61802 224576 0.02 54 -60882.6 226176 0.02 55 -59862.2 227680 0.02 56 -59245.2 229563 0.02 57 -58527.3 231351 0.02 58 -57607.7 232950 0.02 59 -56587.2 234454 0.02 60 -55163.4 235579 0.02 61 -53638.8 236610 0.02 62 -52113.7 237735 0.02 63 -50185.8 238387 0.02 64 -48055.8 238944 0.02 65 -45624.1 239029 0.02 66 -43194.8 238642 0.02 67 -41679.9 237694 0.02 68 -40369 236465 0.02 69 -39261.4 235047 0.02 70 -37950.3 233817 0.02 71 -36331.6 233340 0.02 72 -35109.6 234654 0.02 73 -35809.3 236635 0.02 74 -36611.1 238428 0.02 75 -37209.3 240408 0.02 76 -37298 242951 0.02 77 -37185 245305 0.02 78 -36466.9 247092 0.02 79 -35547.2 248688 0.02 80 -34526.6 250191 0.02 81 -34110.9 252260 0.02 82 -35013.3 254053 0.02 83 -36527.7 255001 0.02 84 -38347.4 255667 0.02 85 -39963 256616 0.02 86 -41475.7 257846 0.02 87 -42072.8 259825 0.02 88 135615 -6906.4 0.04 89 135007 -5398.98 0.04 90 134197 -3608.86 0.04 91 133082 -2101.36 0.04 92 132271 -405.309 0.04 93 131157 1102.36 0.04 94 129840 2327.42 0.04 95 128421 3552.57 0.04 96 127408 4966.24 0.04 97 126091 6191.54 0.04 98 124469 7134.24 0.04 99 123152 8359.7 0.04 100 121328 9114.09 0.04 101 119808 10057 0.04 102 117984 10717.2 0.04 103 115653 10906.4 0.04 104 113119 10812.8 0.04 105 110788 10436.3 0.04 106 108963 10625.3 0.04 107 108457 12605.3 0.04 108 107342 14114.2 0.04 109 106227 15623.1 0.04 110 104707 16566.6 0.04 111 103085 17510.2 0.04 112 101565 18453.7 0.04 113 99943.2 19397.4 0.04 114 98118.6 20058.4 0.04 115 96091.2 20530.9 0.04 116 94672.2 21757.6 0.04 117 93658.9 23172.7 0.04 118 91834.2 23928.2 0.04 119 89502.4 24023.8 0.04 120 87170.5 24213.8 0.04 121 85345.7 24875.1 0.04 122 84535 26101.8 0.04 123 85752.2 27421.7 0.04 124 86766.8 29024.6 0.04 125 85956.5 30817.3 0.04 126 84841.9 32327.3 0.04 127 83220 33271.8 0.04 128 81699.6 34216.3 0.04 129 79874.8 34878.1 0.04 130 77745.6 35257.1 0.04 131 75718 36013.5 0.04 132 73182.8 35826.8 0.04 133 70850.5 36017.3 0.04 134 68518.2 36207.9 0.04 135 69125.9 34697.7 0.04 136 69936.2 32904.3 0.04 137 69022.7 31300.8 0.04 138 66994.4 31207.8 0.04 139 65169.4 31964 0.04 140 63547.2 32908.9 0.04 141 61722.1 33570.8 0.04 142 59897 34232.8 0.04 143 57868.9 34706.2 0.04 144 55536.2 34802.3 0.04 145 53305.1 34992.7 0.04 146 52393.3 36786.9 0.04 147 52090.4 39052.5 0.04 148 51686.2 41318.3 0.04 149 50571.6 42829.5 0.04 150 49558.5 44340.7 0.04 151 47936.5 45475 0.04 152 46111.4 46232 0.04 153 44286.3 46894.5 0.04 154 42258 47274.1 0.04 155 40432.9 48031.2 0.04 156 39622.9 49731.4 0.04 157 40030.4 51808 0.04 158 40234.4 53129.5 0.04 159 38612.4 54075.3 0.04 160 37498.1 55587.1 0.04 161 36891.4 57570.4 0.04 162 37096.1 59364 0.04 163 37300.2 60591 0.04 164 38214.7 62194.8 0.04 165 39433.2 63514.8 0.04 166 40955.8 64645.6 0.04 167 42069.9 63133.8 0.04 168 42879.5 61433.6 0.04 169 43993.6 59921.9 0.04 170 45107.8 58410.2 0.04 171 46425.1 57181.5 0.04 172 48757.7 57084.4 0.04 173 50178.6 58120.9 0.04 174 51194.3 59724.1 0.04 175 51297.5 61517.2 0.04 176 50487.9 63217.1 0.04 177 49678.5 65011.4 0.04 178 48767.6 66805.8 0.04 179 47755 68223 0.04 180 47148.9 70300.2 0.04 181 48570 71336.3 0.04 182 50092.5 72466.4 0.04 183 50804.6 74258.4 0.04 184 50908.8 76523 0.04 185 49592 77751.9 0.04 186 47563.6 77660.9 0.04 187 46344.9 76341.6 0.04 188 45328.8 74833.2 0.04 189 44414.1 73230.1 0.04 190 42891.4 72099.8 0.04 191 41470.2 71063.6 0.04 192 38934.6 70972.9 0.04 193 37109.7 71636.4 0.04 194 35488.1 72582.8 0.04 195 33663.3 73246.3 0.04 196 31635.4 73721.3 0.04 197 30521.5 75139.1 0.04 198 30422.8 77216.2 0.04 199 29817 79199.6 0.04 200 29008.1 80994.6 0.04 201 27894.5 82506.9 0.04 202 26069.8 83170.7 0.04 203 23837.9 82796.8 0.04 204 22011 81950 0.04 205 20285.5 81103 0.04 206 18256.9 81011.8 0.04 207 15924.3 81204.4 0.04 208 14099.5 81868.3 0.04 209 12579.5 82815 0.04 210 10958.5 84045.2 0.04 211 9641.84 85275 0.04 212 8325.2 86504.8 0.04 213 7008.45 87640.3 0.04 214 5895.21 89153.1 0.04 215 4782.02 90666 0.04 216 3668.88 92178.9 0.04 217 2657.07 93597.3 0.04 218 1035.92 94544.5 0.04 219 -280.422 95774.6 0.04 220 -885.205 97853.4 0.04 221 -982.959 99836.7 0.04 222 -1282.94 102104 0.04 223 -2192.26 103900 0.04 224 -4016.53 104564 0.04 225 -5742.35 103718 0.04 226 -7468.16 102871 0.04 227 -8687.79 101551 0.04 228 -9603.67 99947 0.04 229 -10620.8 98437.6 0.04 230 -11840.3 97117.4 0.04 231 -13059.8 95797 0.04 232 -13975.6 94192.7 0.04 233 -14992.7 92588.5 0.04 234 -15098.2 90321.3 0.04 235 -14797 88525.8 0.04 236 -15002.9 86731.1 0.04 237 -16728.5 85883.5 0.04 238 -19264.4 85792.9 0.04 239 -20787.6 84661.3 0.04 240 -21500.6 82867.1 0.04 241 -20590.5 81164.9 0.04 242 -18766 80406.3 0.04 243 -16738 80025.5 0.04 244 -15116.6 79078.3 0.04 245 -14104.6 77565.1 0.04 246 -13702.2 75296.9 0.04 247 -14414.8 73502.6 0.04 248 -15329.9 71897.4 0.04 249 -16346.5 70292.3 0.04 250 -16957.5 68497.6 0.04 251 -17973.9 66892.4 0.04 252 -18888.8 65381.4 0.04 253 -19601.2 63492.1 0.04 254 -20009.3 61507.9 0.04 255 -19910.9 58956 0.04 256 -20319 56877.1 0.04 257 -21031.1 54987.5 0.04 258 -21945.6 53476.1 0.04 259 -22961.7 51870.2 0.04 260 -23572.1 50074.8 0.04 261 -23979.8 47995.6 0.04 262 -24184.9 45632.6 0.04 263 -22867.2 44497.3 0.04 264 -21549.6 43267.4 0.04 265 -20435 41754.2 0.04 266 -19117.3 40524.5 0.04 267 -18002.7 39011.3 0.04 268 -16177.2 38348.4 0.04 269 -14351.8 37685.6 0.04 270 -13744.2 36172.9 0.04 271 -13441.4 33904.4 0.04 272 -12631 32108.1 0.04 273 -11211.6 30878.6 0.04 274 -10401 29176.9 0.04 275 -10300.9 26625.1 0.04 276 -8678.32 25679.2 0.04 277 -7257.83 26245.5 0.04 278 -5938.68 27001 0.04 279 -4213.95 27378.1 0.04 280 -2185.27 26999.1 0.04 281 -1273.15 25203.2 0.04 282 -1172.85 22651.7 0.04 283 145.424 21422.7 0.04 284 2275.61 21043.8 0.04 285 3289.48 19531.6 0.04 286 3390.07 16980.3 0.04 287 4302.54 15184.7 0.04 288 3287.68 13673.1 0.04 289 2070.02 12350.5 0.04 290 852.375 10933.3 0.04 291 -60.9191 9421.48 0.04 292 -1278.48 8098.67 0.04 293 -1988.85 6208.72 0.04 294 -2191.96 3940.66 0.04 295 -2090.62 1861.58 0.04 296 -1989.21 -690.006 0.04 297 -1583.35 -2958.06 0.04 298 -467.35 -4375.51 0.04 299 1054.43 -5414.86 0.04 300 2677.66 -6359.64 0.04 301 4706.61 -6737.36 0.04 302 7039.87 -6926.04 0.04 303 9068.7 -6358.87 0.04 304 10285.9 -4941.5 0.04 305 10894.4 -3146.32 0.04 306 10792.9 -595.359 0.04 307 11807.3 1010.79 0.04 308 13024.7 2333.43 0.04 309 15053.6 2900.18 0.04 310 17082.5 2522.19 0.04 311 18908.4 1766.37 0.04 312 20227.2 538.307 0.04 313 21545.9 -689.696 0.04 314 22661.8 -2106.56 0.04 315 23270.6 -4184.6 0.04 316 22053.4 -5507.13 0.04 317 20024.6 -6074.13 0.04 318 20633.4 -7585.45 0.04 319 22155.2 -8529.81 0.04 320 23271.3 -10040.9 0.04 321 24590.3 -11268.6 0.04 322 24692 -12779.8 0.04 323 23373.5 -13630.3 0.04 324 21648.8 -12969.5 0.04 325 20329.8 -11741.8 0.04 326 18909.4 -10514.1 0.04 327 17387.6 -9569.76 0.04 328 15764.3 -8625.35 0.04 329 13938.2 -7869.86 0.04 330 12213.8 -8720.42 0.04 331 12620 -10987.8 0.04 332 13634.7 -12499.2 0.04 333 14548.2 -14293.9 0.04 334 15360.2 -15994.2 0.04 335 16172.3 -17788.8 0.04 336 17288.6 -19205.4 0.04 337 18607.8 -20433 0.04 338 19724.2 -21943.9 0.04 339 20333.7 -23927.3 0.04 340 19624.4 -25816.8 0.04 341 18103.3 -26856.7 0.04 342 16581.2 -25912.8 0.04 343 14957.7 -24968.9 0.04 344 13638.4 -23741.5 0.04 345 13029 -21757.8 0.04 346 12419.7 -20246.5 0.04 347 11911.8 -18168.2 0.04 348 11505.3 -15900.9 0.04 349 9881.93 -14956.6 0.04 350 8360.01 -14012.2 0.04 351 7750.85 -11933.7 0.04 352 6634.67 -10516.6 0.04 353 4808.51 -9761.05 0.04 354 2779.54 -9383.45 0.04 355 243.427 -9478.39 0.04 356 -1785.36 -10140.3 0.04 357 -3814.15 -10707.7 0.04 358 -6350.26 -10802.7 0.04 359 -8683.41 -11181.2 0.04 360 -8277.22 -12976.9 0.04 361 -7262.4 -14394.3 0.04 362 -6146.08 -15906.1 0.04 363 -5333.95 -17701.5 0.04 364 -4420.35 -19402.3 0.04 365 -4115.14 -21670.3 0.04 366 -4520.03 -23749.6 0.04 367 -4924.83 -25828.9 0.04 368 -5126.81 -27624.5 0.04 369 -5023.98 -30176.1 0.04 370 -5124.02 -32538.7 0.04 371 -5528.47 -34618 0.04 372 -6237.36 -36414 0.04 373 -6946.19 -38210 0.04 374 -7654.94 -40006 0.04 375 -8566.67 -41613.3 0.04 376 -9275.3 -43409.4 0.04 377 -10186.9 -45016.7 0.04 378 -10895.4 -46812.9 0.04 379 -11299.3 -48892.3 0.04 380 -11500 -51160.6 0.04 381 -10889.3 -53239 0.04 382 -9569.29 -54466.2 0.04 383 -7742.72 -55125.9 0.04 384 -5713.56 -55501.8 0.04 385 -3582.86 -55972 0.04 386 -1249.58 -56158.6 0.04 387 779.58 -56534.3 0.04 388 3112.85 -56720.8 0.04 389 5142.01 -57096.5 0.04 390 7171.26 -57566.7 0.04 391 8795.26 -58509.5 0.04 392 10621.8 -59168.7 0.04 393 12448.4 -59827.8 0.04 394 13971 -60770.5 0.04 395 15595.1 -61807.5 0.04 396 17421.6 -62466.4 0.04 397 18944.2 -63409 0.04 398 20568.2 -64351.3 0.04 399 21888.3 -65577.3 0.04 400 23005.8 -67086.7 0.04 401 23312.8 -69352.5 0.04 402 23417.4 -71901.9 0.04 403 24028.5 -73883.9 0.04 404 25348.7 -75109.3 0.04 405 27175.4 -75861.9 0.04 406 29204.4 -76236.5 0.04 407 31335 -76705.2 0.04 408 33161.5 -77363.2 0.04 409 35190.5 -77737.6 0.04 410 37017.1 -78489.8 0.04 411 38539.6 -79431.3 0.04 412 40163.6 -80372.5 0.04 413 41686.2 -81313.7 0.04 414 43310.2 -82254.8 0.04 415 44427.8 -83762.8 0.04 416 45444.1 -85270.9 0.04 417 46359.3 -86967.9 0.04 418 46970.8 -89042.7 0.04 419 47480.8 -91023.3 0.04 420 48396.2 -92814.3 0.04 421 50424.2 -92716 0.04 422 51946.8 -93656.5 0.04 423 53064.5 -95163.7 0.04 424 54182.2 -96576.5 0.04 425 55502.4 -97800.1 0.04 426 57328.8 -98551 0.04 427 59357.4 -98924 0.04 428 61689.8 -99107.6 0.04 429 64022 -99196.9 0.04 430 66049.7 -99098.2 0.04 431 68279.9 -98810.5 0.04 432 70814.5 -98710.7 0.04 433 73145.8 -98328.4 0.04 434 75680.3 -98228.6 0.04 435 77809.9 -98601.1 0.04 436 79534.5 -99351.5 0.04 437 81157.9 -100291 0.04 438 82680 -101230 0.04 439 83797.4 -102736 0.04 440 85117.1 -103958 0.04 441 86437.1 -105369 0.04 442 87554.4 -106874 0.04 443 88874.1 -108096 0.04 444 89991.5 -109601 0.04 445 91311.2 -110823 0.04 446 93338.2 -110724 0.04 447 94552.3 -109401 0.04 448 95563.4 -107797 0.04 449 95965.6 -105723 0.04 450 96367.9 -103648 0.04 451 96770.3 -101574 0.04 452 96665.3 -99029.8 0.04 453 96560.4 -96485.4 0.04 454 96456.3 -94506.4 0.04 455 96960.3 -92431.8 0.04 456 97363.1 -90357.4 0.04 457 97461.4 -88000.8 0.04 458 97864.4 -86020.6 0.04 459 98064.3 -83663.7 0.04 460 97959.9 -81118.8 0.04 461 97551.9 -78857.3 0.04 462 97245.3 -76595.4 0.04 463 96938.6 -74239.2 0.04 464 96530.8 -71977.3 0.04 465 96123 -69715.3 0.04 466 96019.2 -67170 0.04 467 95712.9 -64907.7 0.04 468 95609.2 -62362.2 0.04 469 95505.5 -59722.3 0.04 470 95605.5 -58025 0.04 471 96617.9 -56420.7 0.04 472 97833.3 -55099.1 0.04 473 99860.6 -55002.2 0.04 474 102192 -55093.5 0.04 475 103915 -54242.8 0.04 476 105130 -52921.4 0.04 477 106143 -51411.9 0.04 478 107054 -49808.2 0.04 479 108269 -48487 0.04 480 109484 -47165.9 0.04 481 110396 -45562.4 0.04 482 111408 -43958.8 0.04 483 112320 -42449.7 0.04 484 113535 -41128.8 0.04 485 114750 -39713.7 0.04 486 116777 -39146.3 0.04 487 118804 -38578.8 0.04 488 120323 -37446.5 0.04 489 121843 -36408.4 0.04 490 123058 -35087.9 0.04 491 124476 -33955.9 0.04 492 125489 -32353 0.04 493 126705 -31032.8 0.04 494 128123 -29995.1 0.04 495 129338 -28675 0.04 496 130351 -27072.4 0.04 497 131566 -25752.5 0.04 498 132478 -24150.1 0.04 499 133693 -22830.3 0.04 500 134402 -21039.7 0.04 501 133793 -18967.2 0.04 502 133996 -16705.8 0.04 503 134907 -15103.7 0.04 504 136629 -14255.1 0.04 505 138149 -13218.2 0.04 506 139668 -12087.2 0.04 507 140073 -10014.5 0.04 508 138250 -9355.46 0.04 509 136629 -8413.68 0.04 510 135615 -6906.4 0.04 #203d68 6 1 2 3 4 5 6 #788b63 81 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 #788b63 423 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 acm-6.0_20200416/objects/features/rwy-and-gnd.obv0000644000000000000000000002617210357223037017713 0ustar rootrootRunway 284 70 1 0.000000 -75.000000 0.000000 2 12000.000000 -75.000000 0.000000 3 12000.000000 75.000000 0.000000 4 0.000000 75.000000 0.000000 5 0.000000 -75.000000 0.000000 6 12000.000000 -75.000000 0.000000 7 12000.000000 -70.000000 0.000000 8 0.000000 -70.000000 0.000000 9 0.000000 75.000000 0.000000 10 12000.000000 75.000000 0.000000 11 12000.000000 70.000000 0.000000 12 0.000000 70.000000 0.000000 13 1000.000000 -66.000000 0.000000 14 1125.000000 -66.000000 0.000000 15 1125.000000 -36.000000 0.000000 16 1000.000000 -36.000000 0.000000 17 1000.000000 66.000000 0.000000 18 1125.000000 66.000000 0.000000 19 1125.000000 36.000000 0.000000 20 1000.000000 36.000000 0.000000 21 11000.000000 -66.000000 0.000000 22 10875.000000 -66.000000 0.000000 23 10875.000000 -36.000000 0.000000 24 11000.000000 -36.000000 0.000000 25 11000.000000 66.000000 0.000000 26 10875.000000 66.000000 0.000000 27 10875.000000 36.000000 0.000000 28 11000.000000 36.000000 0.000000 29 4.000000 -66.000000 0.000000 30 129.000000 -66.000000 0.000000 31 129.000000 -54.888889 0.000000 32 4.000000 -54.888889 0.000000 33 4.000000 -50.888889 0.000000 34 129.000000 -50.888889 0.000000 35 129.000000 -39.777779 0.000000 36 4.000000 -39.777779 0.000000 37 4.000000 -35.777779 0.000000 38 129.000000 -35.777779 0.000000 39 129.000000 -24.666666 0.000000 40 4.000000 -24.666666 0.000000 41 4.000000 -20.666666 0.000000 42 129.000000 -20.666666 0.000000 43 129.000000 -9.555555 0.000000 44 4.000000 -9.555555 0.000000 45 4.000000 9.555555 0.000000 46 129.000000 9.555555 0.000000 47 129.000000 20.666666 0.000000 48 4.000000 20.666666 0.000000 49 4.000000 24.666666 0.000000 50 129.000000 24.666666 0.000000 51 129.000000 35.777779 0.000000 52 4.000000 35.777779 0.000000 53 4.000000 39.777779 0.000000 54 129.000000 39.777779 0.000000 55 129.000000 50.888889 0.000000 56 4.000000 50.888889 0.000000 57 4.000000 54.888889 0.000000 58 129.000000 54.888889 0.000000 59 129.000000 66.000000 0.000000 60 4.000000 66.000000 0.000000 61 11996.000000 -66.000000 0.000000 62 11871.000000 -66.000000 0.000000 63 11871.000000 -54.888889 0.000000 64 11996.000000 -54.888889 0.000000 65 11996.000000 -50.888889 0.000000 66 11871.000000 -50.888889 0.000000 67 11871.000000 -39.777779 0.000000 68 11996.000000 -39.777779 0.000000 69 11996.000000 -35.777779 0.000000 70 11871.000000 -35.777779 0.000000 71 11871.000000 -24.666666 0.000000 72 11996.000000 -24.666666 0.000000 73 11996.000000 -20.666666 0.000000 74 11871.000000 -20.666666 0.000000 75 11871.000000 -9.555555 0.000000 76 11996.000000 -9.555555 0.000000 77 11996.000000 9.555555 0.000000 78 11871.000000 9.555555 0.000000 79 11871.000000 20.666666 0.000000 80 11996.000000 20.666666 0.000000 81 11996.000000 24.666666 0.000000 82 11871.000000 24.666666 0.000000 83 11871.000000 35.777779 0.000000 84 11996.000000 35.777779 0.000000 85 11996.000000 39.777779 0.000000 86 11871.000000 39.777779 0.000000 87 11871.000000 50.888889 0.000000 88 11996.000000 50.888889 0.000000 89 11996.000000 54.888889 0.000000 90 11871.000000 54.888889 0.000000 91 11871.000000 66.000000 0.000000 92 11996.000000 66.000000 0.000000 93 258.000000 -2.500000 0.000000 94 383.000000 -2.500000 0.000000 95 383.000000 2.500000 0.000000 96 258.000000 2.500000 0.000000 97 508.000000 -2.500000 0.000000 98 633.000000 -2.500000 0.000000 99 633.000000 2.500000 0.000000 100 508.000000 2.500000 0.000000 101 758.000000 -2.500000 0.000000 102 883.000000 -2.500000 0.000000 103 883.000000 2.500000 0.000000 104 758.000000 2.500000 0.000000 105 1008.000000 -2.500000 0.000000 106 1133.000000 -2.500000 0.000000 107 1133.000000 2.500000 0.000000 108 1008.000000 2.500000 0.000000 109 1258.000000 -2.500000 0.000000 110 1383.000000 -2.500000 0.000000 111 1383.000000 2.500000 0.000000 112 1258.000000 2.500000 0.000000 113 1508.000000 -2.500000 0.000000 114 1633.000000 -2.500000 0.000000 115 1633.000000 2.500000 0.000000 116 1508.000000 2.500000 0.000000 117 1758.000000 -2.500000 0.000000 118 1883.000000 -2.500000 0.000000 119 1883.000000 2.500000 0.000000 120 1758.000000 2.500000 0.000000 121 2008.000000 -2.500000 0.000000 122 2133.000000 -2.500000 0.000000 123 2133.000000 2.500000 0.000000 124 2008.000000 2.500000 0.000000 125 2258.000000 -2.500000 0.000000 126 2383.000000 -2.500000 0.000000 127 2383.000000 2.500000 0.000000 128 2258.000000 2.500000 0.000000 129 2508.000000 -2.500000 0.000000 130 2633.000000 -2.500000 0.000000 131 2633.000000 2.500000 0.000000 132 2508.000000 2.500000 0.000000 133 2758.000000 -2.500000 0.000000 134 2883.000000 -2.500000 0.000000 135 2883.000000 2.500000 0.000000 136 2758.000000 2.500000 0.000000 137 3008.000000 -2.500000 0.000000 138 3133.000000 -2.500000 0.000000 139 3133.000000 2.500000 0.000000 140 3008.000000 2.500000 0.000000 141 3258.000000 -2.500000 0.000000 142 3383.000000 -2.500000 0.000000 143 3383.000000 2.500000 0.000000 144 3258.000000 2.500000 0.000000 145 3508.000000 -2.500000 0.000000 146 3633.000000 -2.500000 0.000000 147 3633.000000 2.500000 0.000000 148 3508.000000 2.500000 0.000000 149 3758.000000 -2.500000 0.000000 150 3883.000000 -2.500000 0.000000 151 3883.000000 2.500000 0.000000 152 3758.000000 2.500000 0.000000 153 4008.000000 -2.500000 0.000000 154 4133.000000 -2.500000 0.000000 155 4133.000000 2.500000 0.000000 156 4008.000000 2.500000 0.000000 157 4258.000000 -2.500000 0.000000 158 4383.000000 -2.500000 0.000000 159 4383.000000 2.500000 0.000000 160 4258.000000 2.500000 0.000000 161 4508.000000 -2.500000 0.000000 162 4633.000000 -2.500000 0.000000 163 4633.000000 2.500000 0.000000 164 4508.000000 2.500000 0.000000 165 4758.000000 -2.500000 0.000000 166 4883.000000 -2.500000 0.000000 167 4883.000000 2.500000 0.000000 168 4758.000000 2.500000 0.000000 169 5008.000000 -2.500000 0.000000 170 5133.000000 -2.500000 0.000000 171 5133.000000 2.500000 0.000000 172 5008.000000 2.500000 0.000000 173 5258.000000 -2.500000 0.000000 174 5383.000000 -2.500000 0.000000 175 5383.000000 2.500000 0.000000 176 5258.000000 2.500000 0.000000 177 5508.000000 -2.500000 0.000000 178 5633.000000 -2.500000 0.000000 179 5633.000000 2.500000 0.000000 180 5508.000000 2.500000 0.000000 181 5758.000000 -2.500000 0.000000 182 5883.000000 -2.500000 0.000000 183 5883.000000 2.500000 0.000000 184 5758.000000 2.500000 0.000000 185 6008.000000 -2.500000 0.000000 186 6133.000000 -2.500000 0.000000 187 6133.000000 2.500000 0.000000 188 6008.000000 2.500000 0.000000 189 6258.000000 -2.500000 0.000000 190 6383.000000 -2.500000 0.000000 191 6383.000000 2.500000 0.000000 192 6258.000000 2.500000 0.000000 193 6508.000000 -2.500000 0.000000 194 6633.000000 -2.500000 0.000000 195 6633.000000 2.500000 0.000000 196 6508.000000 2.500000 0.000000 197 6758.000000 -2.500000 0.000000 198 6883.000000 -2.500000 0.000000 199 6883.000000 2.500000 0.000000 200 6758.000000 2.500000 0.000000 201 7008.000000 -2.500000 0.000000 202 7133.000000 -2.500000 0.000000 203 7133.000000 2.500000 0.000000 204 7008.000000 2.500000 0.000000 205 7258.000000 -2.500000 0.000000 206 7383.000000 -2.500000 0.000000 207 7383.000000 2.500000 0.000000 208 7258.000000 2.500000 0.000000 209 7508.000000 -2.500000 0.000000 210 7633.000000 -2.500000 0.000000 211 7633.000000 2.500000 0.000000 212 7508.000000 2.500000 0.000000 213 7758.000000 -2.500000 0.000000 214 7883.000000 -2.500000 0.000000 215 7883.000000 2.500000 0.000000 216 7758.000000 2.500000 0.000000 217 8008.000000 -2.500000 0.000000 218 8133.000000 -2.500000 0.000000 219 8133.000000 2.500000 0.000000 220 8008.000000 2.500000 0.000000 221 8258.000000 -2.500000 0.000000 222 8383.000000 -2.500000 0.000000 223 8383.000000 2.500000 0.000000 224 8258.000000 2.500000 0.000000 225 8508.000000 -2.500000 0.000000 226 8633.000000 -2.500000 0.000000 227 8633.000000 2.500000 0.000000 228 8508.000000 2.500000 0.000000 229 8758.000000 -2.500000 0.000000 230 8883.000000 -2.500000 0.000000 231 8883.000000 2.500000 0.000000 232 8758.000000 2.500000 0.000000 233 9008.000000 -2.500000 0.000000 234 9133.000000 -2.500000 0.000000 235 9133.000000 2.500000 0.000000 236 9008.000000 2.500000 0.000000 237 9258.000000 -2.500000 0.000000 238 9383.000000 -2.500000 0.000000 239 9383.000000 2.500000 0.000000 240 9258.000000 2.500000 0.000000 241 9508.000000 -2.500000 0.000000 242 9633.000000 -2.500000 0.000000 243 9633.000000 2.500000 0.000000 244 9508.000000 2.500000 0.000000 245 9758.000000 -2.500000 0.000000 246 9883.000000 -2.500000 0.000000 247 9883.000000 2.500000 0.000000 248 9758.000000 2.500000 0.000000 249 10008.000000 -2.500000 0.000000 250 10133.000000 -2.500000 0.000000 251 10133.000000 2.500000 0.000000 252 10008.000000 2.500000 0.000000 253 10258.000000 -2.500000 0.000000 254 10383.000000 -2.500000 0.000000 255 10383.000000 2.500000 0.000000 256 10258.000000 2.500000 0.000000 257 10508.000000 -2.500000 0.000000 258 10633.000000 -2.500000 0.000000 259 10633.000000 2.500000 0.000000 260 10508.000000 2.500000 0.000000 261 10758.000000 -2.500000 0.000000 262 10883.000000 -2.500000 0.000000 263 10883.000000 2.500000 0.000000 264 10758.000000 2.500000 0.000000 265 11008.000000 -2.500000 0.000000 266 11133.000000 -2.500000 0.000000 267 11133.000000 2.500000 0.000000 268 11008.000000 2.500000 0.000000 269 11258.000000 -2.500000 0.000000 270 11383.000000 -2.500000 0.000000 271 11383.000000 2.500000 0.000000 272 11258.000000 2.500000 0.000000 273 11508.000000 -2.500000 0.000000 274 11633.000000 -2.500000 0.000000 275 11633.000000 2.500000 0.000000 276 11508.000000 2.500000 0.000000 277 11758.000000 -2.500000 0.000000 278 11883.000000 -2.500000 0.000000 279 11883.000000 2.500000 0.000000 280 11758.000000 2.500000 0.000000 281 -211200 -211200 0 282 -211200 211200 0 283 211200 211200 0 284 211200 -211200 0 #29350B 4 281 282 283 284 black 4 1 2 3 4 white 4 5 6 7 8 white 4 9 10 11 12 white 4 13 14 15 16 white 4 17 18 19 20 white 4 21 22 23 24 white 4 25 26 27 28 white 4 29 30 31 32 white 4 33 34 35 36 white 4 37 38 39 40 white 4 41 42 43 44 white 4 45 46 47 48 white 4 49 50 51 52 white 4 53 54 55 56 white 4 57 58 59 60 white 4 61 62 63 64 white 4 65 66 67 68 white 4 69 70 71 72 white 4 73 74 75 76 white 4 77 78 79 80 white 4 81 82 83 84 white 4 85 86 87 88 white 4 89 90 91 92 white 4 93 94 95 96 white 4 97 98 99 100 white 4 101 102 103 104 white 4 105 106 107 108 white 4 109 110 111 112 white 4 113 114 115 116 white 4 117 118 119 120 white 4 121 122 123 124 white 4 125 126 127 128 white 4 129 130 131 132 white 4 133 134 135 136 white 4 137 138 139 140 white 4 141 142 143 144 white 4 145 146 147 148 white 4 149 150 151 152 white 4 153 154 155 156 white 4 157 158 159 160 white 4 161 162 163 164 white 4 165 166 167 168 white 4 169 170 171 172 white 4 173 174 175 176 white 4 177 178 179 180 white 4 181 182 183 184 white 4 185 186 187 188 white 4 189 190 191 192 white 4 193 194 195 196 white 4 197 198 199 200 white 4 201 202 203 204 white 4 205 206 207 208 white 4 209 210 211 212 white 4 213 214 215 216 white 4 217 218 219 220 white 4 221 222 223 224 white 4 225 226 227 228 white 4 229 230 231 232 white 4 233 234 235 236 white 4 237 238 239 240 white 4 241 242 243 244 white 4 245 246 247 248 white 4 249 250 251 252 white 4 253 254 255 256 white 4 257 258 259 260 white 4 261 262 263 264 white 4 265 266 267 268 white 4 269 270 271 272 white 4 273 274 275 276 white 4 277 278 279 280 acm-6.0_20200416/objects/features/man.obv0000644000000000000000000000035113074672777016350 0ustar rootrootman 1.7 m tall 12 3 1 0.3 0 -5.6 2 0.3 0 -4.6 3 1.1 0 -4.6 4 1.1 0 -2.3 5 0.6 0 -2.3 6 0.6 0 0 7 -0.3 0 -5.6 8 -0.3 0 -4.6 9 -1.1 0 -4.6 10 -1.1 0 -2.3 11 -0.6 0 -2.3 12 -0.6 0 0 #886666 4 1 2 8 7 gray44 4 9 3 4 10 black 4 11 5 6 12 acm-6.0_20200416/objects/features/tower.obv0000644000000000000000000000055513133717525016726 0ustar rootroot*-a-control-tower 12 9 1 7 7 0 2 -7 7 0 3 -7 -7 0 4 7 -7 0 5 7 7 -60 6 -7 7 -60 7 -7 -7 -60 8 7 -7 -60 9 16 16 -76 10 -16 16 -76 11 -16 -16 -76 12 16 -16 -76 (#888 clip) 4 9 10 11 12 (#bbb clip) 4 1 5 8 4 (#448 clip) 4 5 9 12 8 (#999 clip) 4 4 8 7 3 (#224 clip) 4 8 12 11 7 (#bbb clip) 4 3 7 6 2 (#448 clip) 4 6 7 11 10 (#999 clip) 4 1 2 6 5 (#224 clip) 4 5 6 10 9 acm-6.0_20200416/objects/munition-map.txt0000644000000000000000000000730413135134261016405 0ustar rootroot# munition-map.txt : maps DIS munition entity types to damage values # # Fields: # entity-type, warhead-type, explosion-size, damage-factor, warhead-class ; # # where: # # - entity-type: DIS entity type, 7 fields separated by colon; -1 = "any". # # - warhead-type: -1 means "any"; no other values currently defined. # # - explosion-size: diameter of the explosion (ft) for display rendering. # # - warhead-class: "blast" or "explosive" (that is bomb or missile), # or "kinetic" (that is cannon shells). # # Damage assessment differs between kinetic and blast (explosive) warheads, # so don't compare their damage factors directly. # # kinetic warhead damage is assessed by this equation: # # damage = 0.5 * damage_factor * v * v # # where v is the impact velocity (m/s). Damage units are a somewhat arbitrary # "structure points" value defined in the StructurePoints field of the aircraft # model description record. An F-16, for example, gets 15 structure points. # # blast warhead damage is: # # damage = damage_factor / ( r * r + 1.0 ) # # being r the distance from the target (m). #-----------------+--------+----------+-------+------------------------------+ # entity-type |warhead |explosion |damage |warhead | # |type |size(m) |factor |class | #-----------------+--------+----------+-------+------------------------------+ 2:1:222:1: 2:-1:-1, -1, 5.0, 20.0, blast ; # AA-2 Atoll 2:1:222:1:10:-1:-1, -1, 5.0, 20.0, blast ; # AA-10 Alamo 2:1:222:1:11:-1:-1, -1, 5.0, 20.0, blast ; # AA-11 Archer 2:1:222:1:12:-1:-1, -1, 5.0, 20.0, blast ; # AA-X-12 2:1:222:1:14:-1:-1, -1, 15.0, 400.0, blast ; # SA-2 Guideline 2:1:222:1:17:-1:-1, -1, 15.0, 400.0, blast ; # SA-5 Gammon 2:1:222:1:18:-1:-1, -1, 15.0, 400.0, blast ; # SA-6 Gainful 2:1:222:1:19:-1:-1, -1, 15.0, 400.0, blast ; # SA-7 Grail 2:1:222:1:23:-1:-1, -1, 15.0, 400.0, blast ; # SA-11 Gadfly 2:1:222:1:-1:-1:-1, -1, 5.0, 20.0, blast ; # all other C.I.S. SAM/AAMs 2:1:222:2: 3:-1:-1, -1, 0.0,3.0e-05, kinetic ; # C.I.S. 23mm AAA 2:1:222:2: 5:-1:-1, -1, 1.0,3.0e-05, kinetic ; # C.I.S. 25mm AAA 2:1:222:2: 6:-1:-1, -1, 5.0, 5.0, blast ; # C.I.S. 30mm AAA 2:1:222:2: 7:-1:-1, -1, 5.0, 100.0, blast ; # C.I.S. 57mm AAA 2:1:222:2: 8:-1:-1, -1, 5.0, 180.0, blast ; # C.I.S. 76mm AAA 2:1:222:2: 9:-1:-1, -1, 5.0, 200.0, blast ; # C.I.S. 85mm AAA 2:1:222:2:10:-1:-1, -1, 5.0, 300.0, blast ; # C.I.S. 100mm AAA 2:1:222:2:11:-1:-1, -1, 5.0, 400.0, blast ; # C.I.S. 130mm AAA 2:1:222:2:-1:-1:-1, -1, 1.0, 1.0, blast ; # other C.I.S. AAA munitions 2:9:222:2:-1:-1:-1, -1, 2.0, 5.0, blast ; # other C.I.S. AAA munitions 2:1:225:1: 1:-1:-1, -1, 5.0, 20.0, blast ; # AIM-9 Sidewinder 2:1:225:1: 2:-1:-1, -1, 15.0, 60.0, blast ; # AIM-120 AMRAAM 2:1:225:1: 6:-1:-1, -1, 15.0, 200.0, blast ; # MIM-23 Hawk 2:1:225:1:13:-1:-1, -1, 5.0, 60.0, blast ; # AIM-7 Sparrow 2:1:225:1:16:-1:-1, -1, 20.0, 400.0, blast ; # MIM-104 Patriot 2:1:225:1:-1:-1:-1, -1, 5.0, 20.0, blast ; # all other U.S. AAM/SAMs 2:9:225:2: 1: 1:-1, -1, 1.0,1.0e-05, kinetic ; # 20mm M-39 2:9:225:2: 1:-1:-1, -1, 2.0, 3.0, kinetic ; # 20mm shell used by ACM 2:9:225:2:73:-1:-1, -1, 50.0, 9000.0, blast ; # Mark 82 drop bomb 2:9:225:2:-1:-1:-1, -1, 2.0, 5.0, blast ; # catch all U.S.Ballistic #2:1:225:2:-1:-1:-1, -1, 1.0, 1.0, blast ; # U.S. AAA acm-6.0_20200416/objects/object-map.txt0000644000000000000000000000373113175511063016014 0ustar rootroot# This file maps DIS enumerations to rendered objects. # ACM looks here the image for DIS IDs not found in the inventory file. # # Fields (-1=any): # # kind:domain:country:category:subcategory:specific:extra , "object-name" ; # # where object-name is the file containing the .obv or .dxf image of the object. 1: 1: -1:-1:-1:-1:-1, "features/telar1.obv" ; # ground entities # U.S. Aircraft Entity Types 1: 2:225: 1: 1:-1:-1, "aircraft/f117.dxf" ; # F-117 1: 2:225: 1: 3:-1:-1, "aircraft/f16.obv" ; # any F-16 type 1: 2:225: 1: 9:-1:-1, "aircraft/f18.obv" ; # any F-18 Hornet type 1: 2:225: 4: 5:-1:-1, "aircraft/kc135.obv" ; # any KC-135 tanker type 1: 2:225:88:34: 1: 2, "aircraft/b-747.obv" ; # Boeing 747-400 1: 2:225:40: 1:-1:-1, "aircraft/c172.obv" ; # Cessna 172-RG 1: 2:225:87:32: 2: 1, "aircraft/notavailable.obv" ; # McDonnell Douglas MD-81 1: 2:222: 1: 5:-1:-1, "aircraft/mig23.obv" ; # MiG 23 Flogger 1: 2:222: 1: 4:-1:-1, "aircraft/mig25.obv" ; # MiG 25 Foxbat 1: 2:222: 1: 2:-1:-1, "aircraft/mig29.obv" ; # MiG 29 Fulcrum 1: 2:222: 2: 9:-1:-1, "aircraft/su30.obv" ; # Sukhoi Su-30 1: 2:106: 1: 1:-1:-1, "aircraft/notavailable.obv"; # AMX # C.I.S. Aircraft Entity Types 1: 2:222: 4:12:-1:-1, "aircraft/il78.obv" ; # C.I.S. Il-78 Midas 1: 2: -1: 3:-1:-1:-1, "aircraft/kc135.obv" ; # bomber aircraft 1: 2: -1: 4:-1:-1:-1, "aircraft/kc135.obv" ; # transport aircraft 1: 2: -1: 8:-1:-1:-1, "aircraft/kc135.obv" ; # airborne early warning aircraft 2: 1:222: 1:14:-1:-1, "missiles/sa2.obv" ; # SA-2 Guideline 2: 1:222: 1:22:-1:-1, "missiles/sa10.obv" ; # SA-10 Grumble 2: 1:222: 1:23:-1:-1, "missiles/sa11.obv" ; # SA-11 Gadfly 2: 1:222: 1:25:-1:-1, "missiles/sa10.obv" ; # SA-13 Gopher 2: 1:222: 1:-1:-1:-1, "missiles/aim9.obv" ; # all other CIS anti-air missiles 2: 1: -1: 1:-1:-1:-1, "missiles/aim9.obv" ; # all other anti-air missiles 2:-1: -1:-1:-1:-1:-1, "tracer.obv" ; # all other munitions -1:-1:-1:-1:-1:-1:-1, "ufo.obv" ; # anything else placeholderacm-6.0_20200416/objects/aircraft.txt0000644000000000000000000000072113646045022015562 0ustar rootroot# Aircraft Inventory. # See ACM-Bibliography for further information about the sources of this # information. Read the manual for a detailed description of the format. include "aircraft/ufo.txt" include "aircraft/mig29.txt" include "aircraft/su30.txt" include "aircraft/f16.txt" include "aircraft/amx.txt" include "aircraft/c172.txt" include "aircraft/b-747.txt" include "aircraft/md81.txt" include "aircraft/p51a.txt" include "aircraft/space-shuttle-orbiter.txt" acm-6.0_20200416/objects/zones.txt0000644000000000000000000000304313646045022015125 0ustar rootroot# This file lists all the available scenery files. For each scenery file, the # range of latitude and longitude it covers must be indicated. The ACM program # automatically loads and release data from each scenery file according to the # position of each local aircraft it is currently simulating (normally one only). # Each column must contain in the order: # # 1. Minimum latitude covered. # 2. Maximum latitude covered. # 3. Minimum longitude covered. # 4. Maximum longitude covered. # 5. File name of the scenery as path relative to this file. Example: # "../../myscene.txt". The extension of the file does not really care. # White spaces not allowed inside the path. # # Latitude and longitudes have the usual syntax, examples: # # 10N 10-20-30.400S 30.5S # 10E 10-20-30.400W 30.5W # # Fields must be separated by at least one white space. Apart from that, white # spaces are ignored. Empty lines and lines beginning with '#' are ignored. 35N 40N 125W 120W zones/usa/sfrancisco.txt 30N 35N 120W 115W zones/usa/losangeles.txt 35N 40N 120W 115W zones/usa/lasvegaswest.txt 35N 40N 115W 110W zones/usa/lasvegaseast.txt 30N 35N 115W 110W zones/usa/tucson.txt 30N 35N 100W 095W zones/usa/dallas.txt 40N 45N 075W 070W zones/usa/newyork.txt 42N 50N 005W 006E zones/europe/france.txt 47N 55N 006E 015E zones/europe/germany.txt 35N 47N 006E 019E zones/europe/italy.txt 35N 42N 010W 006E zones/europe/spain.txt 50N 60N 010W 002E zones/europe/united-kingdom.txt 30N 35N 040E 045E zones/middleeast/iraq.txtacm-6.0_20200416/objects/tracer.obv0000644000000000000000000000020210357223037015210 0ustar rootroot*a-bullet 6 3 1 0 0 0 2 -0.4 0.5 0 3 -25.0 0 0 4 -0.4 -0.5 0 5 -0.4 0 0.5 6 -0.4 0 -0.5 red 4 1 2 3 4 red 4 1 5 3 6 red 4 2 5 4 6 acm-6.0_20200416/tools/0000755000000000000000000000000013646045024012737 5ustar rootrootacm-6.0_20200416/tools/create-ils.c0000644000000000000000000001251413200762261015131 0ustar rootroot/** * Program that reads an ACM scenery file and generates on standard output * ILS records for each runway found. The generated ILS are all assumed to be * ILS/DME, then with localized antenna, glide path antenna and DME antenna. * The name and the frequency of each ILS are left as place holders to be * filled by hand in with data from other sources. * * Usage: * * ./create-ils.exe SCENERY * * This program has been used to complete the sceneries based on the * ourairports.com data base, where all the ILS are missing. * * @file * @author Umberto Salsi * @version $Date: 2017/11/09 05:16:33 $ */ #include #include #include #include "../src/util/error.h" #include "../src/util/memory.h" #include "../src/util/reader.h" #include "../src/util/units.h" #include "../src/dis/dis/earth.h" static int parseDouble(reader_Type *in, char *s, double *x) { char *tail; *x = strtod(s, &tail); if( tail == s || *tail != 0 || ! isfinite(*x) ){ fprintf(stderr, "%s:%d: invalid decimal number syntax: %s\n", reader_getPath(in), reader_getLineNumber(in), s); return 0; } return 1; } static void generateILS(char *rwy, earth_LatLonAlt *end1, earth_LatLonAlt *end2) { VPoint end1_xyz; earth_LatLonAltToXYZ(end1, &end1_xyz); VPoint end2_xyz; earth_LatLonAltToXYZ(end2, &end2_xyz); // Locator antenna 300 m away end2: VPoint fwd = end2_xyz; VSub(&fwd, &end1_xyz, &fwd); double mag = VMagnitude(&fwd); fwd.x *= 300/mag; fwd.y *= 300/mag; fwd.z *= 300/mag; VPoint loc_xyz = end2_xyz; VAdd(&loc_xyz, &fwd, &loc_xyz); earth_LatLonAlt loc; earth_XYZToLatLonAlt(&loc_xyz, &loc); VMatrix XYZToLocNED; earth_generateWorldToLocalMatrix(&loc, &XYZToLocNED); VPoint a_ned; VTransform(&end1_xyz, &XYZToLocNED, &a_ned); double bearing = atan2(-a_ned.y, -a_ned.x); if( bearing < 0 ) bearing += 2*M_PI; // GS antenna 100 m right end1: fwd = end2_xyz; VSub(&fwd, &end1_xyz, &fwd); mag = VMagnitude(&fwd); fwd.x *= 100/mag; fwd.y *= 100/mag; fwd.z *= 100/mag; VMatrix r; VIdentMatrix(&r); VRotate(&r, ZRotation, M_PI/2); VPoint gs_ned; VTransform_(&fwd, &r, &gs_ned); VAdd(&gs_ned, &a_ned, &gs_ned); VPoint gs_xyz; VReverseTransform(&gs_ned, &XYZToLocNED, &gs_xyz); earth_LatLonAlt gs; earth_XYZToLatLonAlt(&gs_xyz, &gs); char loc_lat_s[99]; earth_latitudeToString(loc_lat_s, sizeof(loc_lat_s), loc.latitude, earth_LLM_DMS); char loc_lon_s[99]; earth_longitudeToString(loc_lon_s, sizeof(loc_lon_s), loc.longitude, earth_LLM_DMS); char gs_lat_s[99]; earth_latitudeToString(gs_lat_s, sizeof(gs_lat_s), gs.latitude, earth_LLM_DMS); char gs_lon_s[99]; earth_longitudeToString(gs_lon_s, sizeof(gs_lon_s), gs.longitude, earth_LLM_DMS); printf("ILS %s ILS/DME name vhf %s %s %s %s %4.0f 5 %5.1f 3\n", rwy, loc_lat_s, loc_lon_s, gs_lat_s, gs_lon_s, gs.z, units_RADtoDEG(bearing)); } static void parseRunway(reader_Type *in, int argc, char *argv[]) { if( argc != 10 ){ fprintf(stderr, "%s:%d: invalid number of fields in RWY record: %d\n", reader_getPath(in), reader_getLineNumber(in), argc); return; } double lat1, lon1, lat2, lon2; if( ! earth_parseLatitude(argv[6], &lat1) ){ fprintf(stderr, "%s:%d: invalid latitude: %s\n", reader_getPath(in), reader_getLineNumber(in), argv[6]); return; } if( ! earth_parseLongitude(argv[7], &lon1) ){ fprintf(stderr, "%s:%d: invalid longitude: %s\n", reader_getPath(in), reader_getLineNumber(in), argv[7]); return; } if( ! earth_parseLatitude(argv[8], &lat2) ){ fprintf(stderr, "%s:%d: invalid latitude: %s\n", reader_getPath(in), reader_getLineNumber(in), argv[8]); return; } if( ! earth_parseLongitude(argv[9], &lon2) ){ fprintf(stderr, "%s:%d: invalid longitude: %s\n", reader_getPath(in), reader_getLineNumber(in), argv[9]); return; } char id1[9], id2[9]; char *id = argv[2]; char *slash = strchr(id, '/'); if( slash == NULL ){ fprintf(stderr, "%s:%d: missing slash character in runway name: %s\n", reader_getPath(in), reader_getLineNumber(in), id); strcpy(id1, "?"); strcpy(id2, "?"); } else { *slash = 0; memory_strcpy(id1, sizeof(id1), id); memory_strcpy(id2, sizeof(id2), slash+1); } double elevation; if( ! parseDouble(in, argv[3], &elevation) ) elevation = 0.0; earth_LatLonAlt end1; end1.latitude = lat1; end1.longitude = lon1; end1.z = elevation; earth_LatLonAlt end2; end2.latitude = lat2; end2.longitude = lon2; end2.z = elevation; printf("# %s:\n", argv[1]); generateILS(id1, &end1, &end2); generateILS(id2, &end2, &end1); } static int parseScenery(char *path) { reader_Type *in = reader_new(path); char line[999]; while( reader_getLine(in, line, sizeof(line)) ){ // Ignore empty and comment lines. if( line[0] == '\0' || line[0] == '#' ) continue; int argc; char *argv[99]; if( ! reader_split(line, &argc, argv, 32) ){ fprintf(stderr, "%s:%d: too many fields -- ignoring line\n", reader_getPath(in), reader_getLineNumber(in)); continue; } if( argc > 0 && strcmp(argv[0], "RWY") == 0 ) parseRunway(in, argc, argv); } if( reader_getError(in) != NULL ) fprintf(stderr, "%s: %s", reader_getPath(in), reader_getError(in)); memory_dispose(in); return 1; } int main(int argc, char** argv) { error_init(argv[0]); if( argc != 2 ){ fprintf(stderr, "ERROR: required just one argument.\n"); return 1; } return parseScenery(argv[1])? 0 : 1; } acm-6.0_20200416/tools/README.txt0000644000000000000000000000140513646045024014435 0ustar rootrootThis directory contains programs and tools that serve to some very special purpose but it worth to make them available to anyone. - U.S. chart ----- Program that generates navigation charts from ACM scenery file. Some generated charts available in the doc directory. faaairports ----------- Program that parses the US FAA airports data base and generates the ACM scenery for any given range of latitude and longitude. Also provided some script used to generate the default sceneries distributed along with the ACM-6 package, which cover only a very small part of the whole U.S. territory. create-ufo-obv.c ---------------- Creates the ufo.obv object inspired to the old '70 TV series "UFO SHADOW". ACM displays it whenever a DIS entity ".obv" shape isn't available. acm-6.0_20200416/tools/chart/0000755000000000000000000000000013175062144014037 5ustar rootrootacm-6.0_20200416/tools/chart/ps.c0000644000000000000000000001303613172245744014636 0ustar rootroot#include #include #include #include #include "../../src/util/error.h" #include "../../src/util/memory.h" #define ps_IMPORT #include "ps.h" struct ps_Type { /** * Current line width (pt). Here we check the current set value to avoid * redundant changes of the setting, making the generated PS file shorter. */ double curr_line_width; /** * Current gray level [0,1]. 0 = black, 1 = white. Here we check the * current set value to avoid redundant changes of the setting, making the * generated PS file shorter. */ double curr_gray_level; }; ps_Type * ps_new() { ps_Type * this; this = memory_allocate(sizeof(ps_Type), NULL); this->curr_gray_level = 0; this->curr_line_width = 1; printf("%%!PS-Adobe-2.0\n"); return this; } void ps_setClipRect(ps_Type *this, double x, double y, double w, double h) { printf("newpath\n"); ps_moveTo(this, x, y); ps_relativeLineTo(this, w, 0); ps_relativeLineTo(this, 0, h); ps_relativeLineTo(this, -w, 0); ps_relativeLineTo(this, 0, -h); printf("closepath\n"); printf("clip\n"); } void ps_setFontHeight(ps_Type *this, int h) { printf("/Helvetica findfont %d scalefont setfont\n", h); } void ps_setLineWidth(ps_Type *this, double w) { w = (int)(8 * w + 0.5) / 8.0; if( w == this->curr_line_width ) return; this->curr_line_width = w; printf("%.1f setlinewidth\n", w); } void ps_moveTo(ps_Type *this, double x, double y) { printf("%.1f %.1f moveto\n", x, y); } /* void rmoveto(ps_Type *this, double x, double y) { printf("%.1f %.1f rmoveto\n", x, y); } */ void ps_stroke(ps_Type *this) { printf("stroke\n"); } void ps_lineTo(ps_Type *this, double x, double y) { printf("%.1f %.1f lineto\n", x, y); } void ps_drawLine(ps_Type *this, double x1, double y1, double x2, double y2) { ps_moveTo(this, x1, y1); ps_lineTo(this, x2, y2); printf("stroke\n"); } void ps_relativeLineTo(ps_Type *this, double x, double y) { printf("%.1f %.1f rlineto\n", x, y); } void ps_setGray(ps_Type *this, double brightness) { if( !(0 <= brightness && brightness <= 1.0) ) error_internal("gray brightness out of the range: %g", brightness); brightness = (int)(brightness * 256) / 256.0; if( brightness == this->curr_gray_level ) return; this->curr_gray_level = brightness; printf("%.3f setgray\n", brightness); } void ps_drawRect(ps_Type *this, double x, double y, double w, double h) { printf("newpath\n"); printf("%.1f %.1f moveto\n", x, y); printf("%.1f 0 rlineto\n", w); printf("0 %.1f rlineto\n", h); printf("%.1f 0 rlineto\n", -w); printf("0 %.1f rlineto\n", -h); printf("closepath\n"); printf("stroke\n"); } void ps_fillRect(ps_Type *this, double x, double y, double w, double h) { printf("newpath\n"); printf("%.1f %.1f moveto\n", x, y); printf("%.1f 0 rlineto\n", w); printf("0 %.1f rlineto\n", h); printf("%.1f 0 rlineto\n", -w); printf("0 %.1f rlineto\n", -h); printf("closepath\n"); printf("fill\n"); } /** * Draws a rectangular white box with black border. */ void ps_drawFramedRect(ps_Type *this, double x, double y, double w, double h) { ps_setGray(this, 1.0); ps_fillRect(this, x, y, w, h); ps_setGray(this, 0.0); ps_setLineWidth(this, 1); ps_moveTo(this, x, y); ps_drawRect(this, x, y, w, h); //printf("stroke\n"); } void ps_drawCircumference(ps_Type *this, double x, double y, double r) { printf("newpath\n"); printf("%.1f %.1f %.1f 0 360 arc\n", x, y, r); printf("closepath\n"); printf("stroke\n"); } void ps_drawCircle(ps_Type *this, double x, double y, double r) { printf("newpath\n"); printf("%.1f %.1f %.1f 0 360 arc\n", x, y, r); printf("closepath\n"); printf("fill\n"); } /* static int indexOfChar(char *s, int c) { char *found = strchr(s, c); if( found == NULL ) return -1; else return found - s; } */ static int indexOfSubstring(char *s, char *target) { char *found = strstr(s, target); if( found == NULL ) return -1; else return found - s; } /** * Print ASCII printable only string properly PostScript escaped. * @param s */ void ps_printEscapedString(ps_Type *this, char *s) { putchar('('); while(*s){ char c = *s; if( c == '(' ){ puts("\\("); } else if( c == ')' ){ puts("\\)"); } else if( c == '\\' ){ puts("\\"); } else if( 32 <= c && c <= 126 ){ putchar(c); } else { fprintf(stderr, "Warning: non-ASCII printable code %d in string\n", c & 255); putchar('?'); } s++; } printf(") show\n"); } typedef struct { char *name; char *glyph; } ratnest_CharEntity; static ratnest_CharEntity entities[] = { {"°ree;", "/degree"}, {"&multiply;", "/multiply"}, {NULL, NULL} }; /** * Draws a string at the current location. To display the degree symbol, * caller may use the pseudo-HTML entity "°ree;" instead which is the * only one handled specially. * @param s ASCII printable chars only supported. */ void ps_drawString(ps_Type *this, char *s) { while( *s != 0 ){ int found_index = -1; ratnest_CharEntity *found_entity = entities; while(found_entity->name != NULL){ found_index = indexOfSubstring(s, found_entity->name); if( found_index >= 0 ) break; found_entity++; } if( found_index < 0 ){ ps_printEscapedString(this, s); return; } // Print chunk from beginning up to the entity (excluded): s[found_index] = 0; //ps_printEscapedString(this, s); ps_drawString(this, s); // recursive! s[found_index] = found_entity->name[0]; // Print the symbol: printf("%s glyphshow\n", found_entity->glyph); // Move past the entity: s = s + found_index + strlen(found_entity->name); } } void ps_close(ps_Type *this) { printf("showpage\n"); } acm-6.0_20200416/tools/chart/README.txt0000644000000000000000000000162313646045024015540 0ustar rootrootThis directory contains the chart program that generates navigation maps from an ACM-6 scenery file. The chart.exe program reads the specified scenery file and generates on standard output the PostScript code that draw the navigation map according to the specified command line options. The PostScript program may then be converted to handy PDF using a convertion utility like ps2pdf which is part of the Gostscript tools. Type the command $ ./chart.exe --help for more about the available options. A make-charts.pdf Bash script is also provided to create all the charts from the currently distributed sceneries. In order to execute this script you must either have: 1. Linux OS which normally provides Bash and ps2pdf "out of the box". or 2. Windows OS with either MinGW or Cygwin installed with all the required packages installed, in particular the Gostscript support. - Umberto Salsi, 2017-09-29 acm-6.0_20200416/tools/chart/ps.h0000644000000000000000000000361713166535670014652 0ustar rootroot/** * PostScript helper routines. Each function simply writes on standard output. * * @file * @author Umberto Salsi * @version $Date: 2017/10/08 23:58:48 $ */ #ifndef PS_H #define PS_H #ifdef ps_IMPORT #define EXTERN #else #define EXTERN extern #endif typedef struct ps_Type ps_Type; /** * Allocates a new ps_Type. * @return New ps_Type. Must be released with memory_dispose(). */ EXTERN ps_Type * ps_new(void); EXTERN void ps_setClipRect(ps_Type *this, double x, double y, double w, double h); EXTERN void ps_setFontHeight(ps_Type *this, int h); EXTERN void ps_setLineWidth(ps_Type *this, double w); EXTERN void ps_moveTo(ps_Type *this, double x, double y); EXTERN void ps_lineTo(ps_Type *this, double x, double y); EXTERN void ps_relativeLineTo(ps_Type *this, double x, double y); EXTERN void ps_stroke(ps_Type *this); EXTERN void ps_drawLine(ps_Type *this, double x1, double y1, double x2, double y2); EXTERN void ps_setGray(ps_Type *this, double brightness); EXTERN void ps_drawRect(ps_Type *this, double x, double y, double w, double h); EXTERN void ps_fillRect(ps_Type *this, double x, double y, double w, double h); /** * Draws a rectangular white box with black border. */ EXTERN void ps_drawFramedRect(ps_Type *this, double x, double y, double w, double h); EXTERN void ps_drawCircumference(ps_Type *this, double x, double y, double r); EXTERN void ps_drawCircle(ps_Type *this, double x, double y, double r); /** * Print ASCII printable only string properly PostScript escaped. * @param s */ EXTERN void ps_printEscapedString(ps_Type *this, char *s); /** * Draws a string at the current location. The following special entities are * recognized and translated to PostScript: "°ree;", "&multiply;". * @param s ASCII printable chars only supported. */ EXTERN void ps_drawString(ps_Type *this, char *s); EXTERN void ps_close(ps_Type *this); #undef EXTERN #endif acm-6.0_20200416/tools/chart/ratnest.h0000644000000000000000000000422213163526746015702 0ustar rootroot/** * Keeps track of zones of a rectangular area that are occupied and provides a * method to find out the available area closest to a given target point. * The rectangular area is initially empty. The client must mark the occupied * area by calling the appropriate methods of this module. * * @file * @author Umberto Salsi * @version $Date: 2017/09/29 20:32:38 $ */ #ifndef RATNEST_H #define RATNEST_H //#include "ps.h" #ifdef ratnest_IMPORT #define EXTERN #else #define EXTERN extern #endif /** * A rectangular region. This module enforces this area be non empty and point * 1 be the bottom-left point, 2 the top-right point, so x1 < x2 and y1 < y2. */ typedef struct { double x1, y1, x2, y2; } ratnest_Rect; /** * Returns the rectangle as a string. * @param r * @return Pointer to statically allocated internal string. */ EXTERN char *ratnest_RectToString(ratnest_Rect *r); /** * State of this module, created with ratnest_new(). */ typedef struct ratnest_Type ratnest_Type; /** * Creates a new empty rectangular area. * @param bounds * @return Empty rectangular area to monitor. Can be released with memory_dispose(). */ EXTERN ratnest_Type * ratnest_new(ratnest_Rect *bounds); /** * Marks as occupied a segment. * @param this * @param x1 * @param y1 * @param x2 * @param y2 */ EXTERN void ratnest_markSegment(ratnest_Type *this, double x1, double y1, double x2, double y2); /** * Marks as occupied a given rectangular area. * @param this * @param r */ EXTERN void ratnest_markRect(ratnest_Type *this, ratnest_Rect *r); /** * Search a suitable free area that may contain the given rectangle. * @param this * @param r Location of the rectangle as proposed by the client. The bottom-left * corner is assumed to be the target point. * @param found If the search succeeds, here returns the found available * free area, the same size of the proposed one but possibly in another * location within the boundaries of the monitored area. * @return */ EXTERN int ratnest_place(ratnest_Type *this, ratnest_Rect *r, ratnest_Rect *found); //EXTERN void ratnest_debug(ratnest_Type *this, ps_Type *ps); #undef EXTERN #endif acm-6.0_20200416/tools/chart/ratnest.c0000644000000000000000000001535113260344465015674 0ustar rootroot/* * IMPLEMENTATION NOTES. * * The rectangular area is split into a grid of slots of fixed size. Each slot * is initially empty, that is its value is zero. By marking some zone as "used" * the corresponding involved slots are set to 1. */ #include #include #include #include #include #include "../../src/util/memory.h" #include "../../src/util/error.h" #define ratnest_IMPORT #include "ratnest.h" /** Granularity. */ #define ratnest_N (60) struct ratnest_Type { /** Rectangular region to monitor. */ ratnest_Rect bounds; /** Size of a slot. */ double dx, dy; /** Each slot value is either 0 (not occupied) or 1 (occupied). */ char slots[ratnest_N][ratnest_N]; }; char *ratnest_RectToString(ratnest_Rect *r) { static char s[99]; snprintf(s, sizeof(s), "[%g, %g, %g, %g]", r->x1, r->y1, r->x2, r->y2); return s; } /** * This module assumes each rectangle be not empty and (x1,y1) be the bottom- * left corner. Fatal error if it is not. * @param r */ static void ratnest_checkRect(ratnest_Rect *r) { if( !(r->x1 < r->x2 && r->y1 < r->y2) ) error_internal("invalid rectangle: %s", ratnest_RectToString(r)); } /* static void ratnest_destruct(void *p) { ratnest_Type *o = (ratnest_Type *) p; } */ ratnest_Type * ratnest_new(ratnest_Rect *bounds) { ratnest_checkRect(bounds); ratnest_Type * this = memory_allocate(sizeof(ratnest_Type), NULL); this->bounds = *bounds; this->dx = (bounds->x2 - bounds->x1) / ratnest_N; this->dy = (bounds->y2 - bounds->y1) / ratnest_N; memory_zero(&this->slots); return this; } void ratnest_markSegment(ratnest_Type *this, double x1, double y1, double x2, double y2) { // FIXME: do clipping; hopefully not necessary. double deltax = x2 - x1; double deltay = y2 - y1; int nsteps_h = fabs(deltax) / this->dx; int nsteps_v = fabs(deltay) / this->dy; int nsteps = (nsteps_h < nsteps_v)? nsteps_v : nsteps_h; // This algo is simple but it does not cover all the slots the segment // pass over. Doubling the number of steps mitigates this issue giving // a result good enough. // Moreover, add 1 to force at least 1 slot be occupied by very short // segments. nsteps = 2*nsteps + 1; int i; for(i = 0; i <= nsteps; i++){ int h = (x1 + i * deltax /nsteps - this->bounds.x1) / this->dx; if( !(0 <= h && h < ratnest_N) ) continue; int v = (y1 + i * deltay /nsteps - this->bounds.y1) / this->dy; if( !(0 <= v && v < ratnest_N) ) continue; this->slots[v][h] = 1; } } /** * Clip the rectangle to the boundary. * @param this * @param r Modified in place with the clipped rectangle! * @return True if the resulting rectangle is not-empty. */ static int ratnest_clipRectToBounds(ratnest_Type *this, ratnest_Rect *r) { // left bound: if( r->x2 <= this->bounds.x1 ) return 0; if( r->x1 < this->bounds.x1 ) r->x1 = this->bounds.x1; // right bound: if( this->bounds.x2 <= r->x1 ) return 0; if( this->bounds.x2 < r->x2 ) r->x2 = this->bounds.x2; // bottom bound: if( r->y2 <= this->bounds.y1 ) return 0; if( r->y1 < this->bounds.y1 ) r->y1 = this->bounds.y1; // top bound: if( this->bounds.y2 <= r->y1 ) return 0; if( this->bounds.y2 < r->y2 ) r->y2 = this->bounds.y2; if( (r->x2 - r->x1) * (r->y2 - r->y1) <= 0 ) return 0; return 1; } void ratnest_markRect(ratnest_Type *this, ratnest_Rect *r) { ratnest_checkRect(r); ratnest_Rect r1 = *r; if( ! ratnest_clipRectToBounds(this, &r1) ) return; int h1 = (r1.x1 - this->bounds.x1) / this->dx; if( h1 >= ratnest_N ) h1 = ratnest_N - 1; int h2 = (r1.x2 - this->bounds.x1) / this->dx; if( h2 >= ratnest_N ) h2 = ratnest_N - 1; int v1 = (r1.y1 - this->bounds.y1) / this->dy; if( v1 >= ratnest_N ) v1 = ratnest_N - 1; int v2 = (r1.y2 - this->bounds.y1) / this->dy; if( v2 >= ratnest_N ) v2 = ratnest_N - 1; int h, v; for(v = v1; v <= v2; v++) for(h = h1; h <= h2; h++) this->slots[v][h] = 1; } int ratnest_place(ratnest_Type *this, ratnest_Rect *r, ratnest_Rect *found) { ratnest_checkRect(r); double req_width = r->x2 - r->x1; double req_height = r->y2 - r->y1; if( !(req_width <= this->bounds.x2 - this->bounds.x1 && req_height <= this->bounds.y2 - this->bounds.y1) ) error_internal("rectangle too big to place: %s", ratnest_RectToString(r)); // No. of slot required (width and height): int width = ceil(req_width / this->dx); int height = ceil(req_height / this->dy); // Limits of the search area among slots: int hmax = ratnest_N - width; int vmax = ratnest_N - height; // Initial search area [h1,v1,h2,v2] among slots is the slot where the // given rectangle is located; if occupied, widens the search area by // one slot and tray again with the slots added on the border of that // larger area. int h1 = (r->x1 - this->bounds.x1)/this->dx; if( h1 < 0 ) h1 = 0; else if( h1 > hmax ) h1 = hmax; int v1 = (r->y1 - this->bounds.y1)/this->dy; if( v1 < 0 ) v1 = 0; else if( v1 > vmax ) v1 = vmax; int h2 = h1; int v2 = v1; while(1){ // Search place along the border of [h1,v1,h2,v2]: int v, h; for(v = v2; v >= v1; v--){ for(h = h2; h >= h1; h--){ if( !(v == v1 || v == v2 || h == h1 || h == h2) ) // Not a slot on the border of [h1,v1,h2,v2]. continue; // Check if the slots are free: int occupied = 0; int v1, h1; for(v1 = v; v1 < v + height; v1++){ for(h1 = h; h1 < h + width; h1++){ if( this->slots[v1][h1] != 0 ){ occupied = 1; break; } } if( occupied ) break; } if( ! occupied ){ // Put the requested rectangle at the center of the available // free slots area, so we also have a bit of margin added. double avail_width = width * this->dx; double avail_height = height * this->dy; found->x1 = this->bounds.x1 + h * this->dx + (avail_width - req_width)/2; found->y1 = this->bounds.y1 + v * this->dy + (avail_height - req_height)/2; found->x2 = found->x1 + req_width; found->y2 = found->y1 + req_height; return 1; } } } // Widens search area [h1,v1,h2,v2] by one slot and retry on the border. int wider = 0; if( v1 > 0 ){ v1--; wider = 1; } if( v2 < vmax ){ v2++; wider = 1; } if( h1 > 0 ){ h1--; wider = 1; } if( h2 < hmax ){ h2++; wider = 1; } if( ! wider ){ // Cannot enlarge search area any further -- give up. return 0; } } } /** * Draws a circle on each occupied slot. * @param this * @param ps */ /* void ratnest_debug(ratnest_Type *this, ps_Type *ps) { ps_setLineWidth(ps, 0.2); int h, v; for(h = 0; h < ratnest_N; h++){ double x = this->bounds.x1 + h*this->dx; for(v = 0; v < ratnest_N; v++){ if( this->slots[v][h] == 0 ) continue; double y = this->bounds.y1 + v*this->dy; ps_drawRect(ps, x, y, this->dx, this->dy); } } } */acm-6.0_20200416/tools/chart/chart.c0000644000000000000000000010061413646045025015310 0ustar rootroot/** * Navigation chart generator for ACM flight simulator. This program reads a scenery * file and generates on standard output the PostScript program that draws * a single A4 page based on the specified command line options. * External programs (ps2pdf) may be used to convert PostScript to PDF or * other formats. * Type "chart.exe --help" for the list of the available options. * * @file * @author Umberto Salsi * @version $Date: 2020/04/16 10:35:24 $ */ #include #include #include #include #include #include #include "../../src/util/error.h" #include "../../src/util/units.h" #include "../../src/util/zulu.h" #include "../../src/wmm/wmm.h" #include "../../src/dis/dis/earth.h" #include "ps.h" #include "ratnest.h" // State of the PostScript module helper. static ps_Type *ps; #define SECtoRAD(sec) ((sec) / 3600.0 / 180.0 * M_PI) // Current date as Unix timestamp (s). Used to calculate the magnetic variation. int curr_date_timestamp; // Current date as year with fraction. Used to calculate the magnetic variation. double curr_date_year; static char *title = ""; static char *scene_file_name; static FILE *scene_file; // Current line no. of the scenery file. static int scene_line_no; // Current line read from the scenery file. static char scene_line[999]; static char *wmm_cof_file_name = "../objects/WMM.COF"; // If ILSs must be drawn. static int draw_ils = 1; // Each record read from the scenery, split into fields. #define FIELDS_MAX 20 static char *fields[FIELDS_MAX]; static int fields_no; // Coords. of the central point and delta (RAD). static double olat, olon, dlat, dlon; // Denominator of the scale factor 1:scale. This value is related to dlat. static int scale; // Geographic coordinates at the sheet edges (RAD): static double alat, alon, blat, blon; // Sheet size (A4 portrait, pt); static double hmax = 600.0; static double vmax = 840.0; // Sheet margin (pt). static int margin = 35; // Geographical radiants to pt factor. static double LON_TO_PT; // Geographical radiants to pt factor. static double LAT_TO_PT; // Map area of the sheet (pt). It occupied about 90% of the sheet space. static double map_x1, map_y1, map_x2, map_y2; /** * Label placement algorithm state used to place labels on free spaces of the * map area. Here we will collect all the occupied parts of the map while * drawing runways and NAVAIDs. Remaining free space will be available to * draw labels. */ static ratnest_Type *place; // Forward declaration, see below. typedef struct RunwayEnd RunwayEnd; /** * Runway of an airport, including both ends. Ends are listed in the same order * of the scenery. */ typedef struct { /** Airport code. */ char airportCode[8]; /** Both runways IDs, example: "12L/30R". */ char runwayIDs[8]; double altitude_ft, length_ft, width_ft; /* Each end. */ RunwayEnd *end1; RunwayEnd *end2; } Runway; /** * Specific runway end. */ typedef struct RunwayEnd { /** Runway this end belongs to. */ Runway *runway; /** Name of this runway end, example: "12L". */ char runwayEndID[8]; /* Location of this end (RAD). */ double lat, lon; /** The reciprocal end of the same runway. */ struct RunwayEnd *reciprocalEnd; } RunwayEnd; /** * A label consisting of two rows of text inside a rectangular area. * Used for NAVAIDs. */ typedef struct { ratnest_Rect r; char line1[99]; char line2[99]; } Label; /* * Labels for NAVAIDs are collected here and drawn all together once the * occupied areas of the map are finally known. The "rat nest" module helps * to do this. */ static int labels_capacity; static int labels_number; static Label **labels; /* * Runways are collected here. This list is used to find a matching runway end * for any given ILS. In fact, in the scenery file RWY records and ILS records * are not clearly related, so some guess is required. */ static int runways_capacity; static int runways_number; static Runway **runways; /** * Adds a label entry to the list of labels. The rat nest module will be used * later to place these labels on free spaces. Only two short lines of text are * allowed. * @param r Bottom-left corner is the reference point this label is related to. * @param line1 Some text to display. * @param line2 Some text to display. */ static void addLabel( ratnest_Rect *r, char *line1, char *line2) { Label *lbl = malloc(sizeof(Label)); snprintf(lbl->line1, sizeof(lbl->line1), "%s", line1); snprintf(lbl->line2, sizeof(lbl->line2), "%s", line2); lbl->r = *r; if( labels_number >= labels_capacity ){ labels_capacity += 10; labels = realloc(labels, sizeof(Label *)*labels_capacity); } labels[labels_number] = lbl; labels_number++; } /** * Adds a runway to the list of known runways. This list will be used to guess * the runway end related to any given ILS. * @param airportCode * @param runwayIDs Both ends IDS separated by slash, for example "12L/30R". * @param end1_lat Latitude of the first end, that is the "12L" runway (RAD). * @param end1_lon Longitude etc. (RAD). * @param end2_lat Latitude of the second end, that is the "30R" runway (RAD). * @param end2_lon Longitude etc. (RAD). * @param altitude_ft * @param length_ft * @param width_ft * @return Registered runway. */ static Runway * addRunway(char *airportCode, char *runwayIDs, double end1_lat, double end1_lon, double end2_lat, double end2_lon, double altitude_ft, double length_ft, double width_ft) { Runway *rwy = malloc(sizeof(Runway)); snprintf(rwy->airportCode, sizeof(rwy->airportCode), "%s", airportCode); snprintf(rwy->runwayIDs, sizeof(rwy->runwayIDs), "%s", runwayIDs); rwy->altitude_ft = altitude_ft; rwy->length_ft = length_ft; rwy->width_ft = width_ft; RunwayEnd *end1 = malloc(sizeof(RunwayEnd)); end1->runway = rwy; end1->lat = end1_lat; end1->lon = end1_lon; rwy->end1 = end1; RunwayEnd *end2 = malloc(sizeof(RunwayEnd)); end2->runway = rwy; end2->lat = end2_lat; end2->lon = end2_lon; rwy->end2 = end2; end1->reciprocalEnd = end2; end2->reciprocalEnd = end1; // Determine each end name: char *slash_ptr = strchr(runwayIDs, '/'); if( slash_ptr == NULL ){ fprintf(stderr, "%s:%d: missing '/' separator in runways identifiers: %s\n", scene_file_name, scene_line_no, runwayIDs); strcpy(end1->runwayEndID, "?"); strcpy(end2->runwayEndID, "?"); } else { // FIXME: here we assume IDs and ends are listed in the same order // which is reasonable, but we should check anyway. *slash_ptr = 0; snprintf(end1->runwayEndID, sizeof(end1->runwayEndID), "%s", runwayIDs); snprintf(end2->runwayEndID, sizeof(end2->runwayEndID), "%s", slash_ptr+1); *slash_ptr = '/'; // restore original string, just in case } // Add runway to the array: if( runways_number >= runways_capacity ){ runways_capacity += 10; runways = realloc(runways, runways_capacity * sizeof(Runway *)); } runways[runways_number] = rwy; runways_number++; return rwy; } static double sq(double x) { return x * x; } /** * Returns the distance between two points given their latitude and longitude * only; ignore altitude and assumes the Earth be a perfect sphere. * @param lat1 * @param lon1 * @param lat2 * @param lon2 * @return Distance (m). */ static double bogusDist(double lat1, double lon1, double lat2, double lon2) { double x1 = cos(lat1) * cos(lon1); double y1 = cos(lat1) * sin(lat1); double z1 = sin(lat1); double x2 = cos(lat2) * cos(lon2); double y2 = cos(lat2) * sin(lat2); double z2 = sin(lat2); return earth_MAJOR * sqrt(sq(x1-x2) + sq(y1-y2) + sq(z1-z2)); } /** * Returns the runway end the LOCATOR is serving. Search is based on the * LOCATOR position and the served runway ID. * Only runway ends with the specified runway ID and not farther than 500 m * are considered. * It is important to note that the search is performed among the runways * registered until now. * @param rwyid Runway ID this LOCATOR is serving. * @param lat Latitude of the LOCATOR antenna (RAD). * @param lon Longitude of the LOCATOR antenna (RAD). * @return Served runway end, or NULL if nothing close enough found. */ static RunwayEnd *searchILSRunwayEnd(char *rwyid, double lat, double lon) { int i; RunwayEnd *served = NULL; double served_dist = 0; for(i = 0; i < runways_number; i++){ // Search a runway end whose reciprocal end ID matches rwyid and whose // distance from the LOCATOR is not to far. RunwayEnd *end = runways[i]->end1; if( strcmp(rwyid, end->reciprocalEnd->runwayEndID) == 0 ){ double dist = bogusDist(lat, lon, end->lat, end->lon); if( served == NULL || dist < served_dist ){ served = end->reciprocalEnd; served_dist = dist; } } end = runways[i]->end2; if( strcmp(rwyid, end->reciprocalEnd->runwayEndID) == 0 ){ double dist = bogusDist(lat, lon, end->lat, end->lon); if( served == NULL || dist < served_dist ){ served = end->reciprocalEnd; served_dist = dist; } } } if( runways_number > 0 && served_dist < 500 ){ return served; } else { return NULL; } } static double parseLatitudeRad(char *s) { double lat; if( earth_parseLatitude(s, &lat) ){ return lat; } else { fprintf(stderr, "%s:%d: invalid latitude: %s\n", scene_file_name, scene_line_no, s); return 0; } } static double parseLongitudeRad(char *s) { double lon; if( earth_parseLongitude(s, &lon) ){ return lon; } else { fprintf(stderr, "%s:%d: invalid longitude: %s\n", scene_file_name, scene_line_no, s); return 0; } } /** * Returns the magnetic variation at the given location, at current set date. * @param lat Latitude (RAD). * @param lon Longitude (RAD). * @param alt Altitude over the WGS84 ellipsoid (m). It exact value does not * makes much difference, so setting zero here is generally fine. * @return Magnetic variation at the given location current time, * positive east (RAD). */ static double getMagneticVariationAt(double lat, double lon, double alt) { wmm_MagneticField mf; wmm_getMagneticField(curr_date_year, lat, lon, alt, &mf); return mf.Decl; } /** * Split line of the scenery into fields at each space. Fill global fields[] and * set fields_no. * Lines beginning with '#' are comments and produces 0 fields. * @param line */ static void splitLineIntoFields(char *line) { fields_no = 0; do { // find beginning next field: while( isspace(*line) ) line++; if( *line == 0 ) return; if( *line == '#' && fields_no == 0 ) return; if( fields_no >= FIELDS_MAX ){ fprintf(stderr, "%s:%d: too many fields, ignoring entire line\n", scene_file_name, scene_line_no); fields_no = 0; return; } fields[fields_no++] = line; // skip to end of the field: do { line++; if( *line == 0 ) return; if( isspace(*line) ){ *line = 0; line++; break; } }while(1); }while(1); } /** * Draws a generic mark, with circle and cross. * @param lat_rad * @param lon_rad * @param descr */ static void drawMark(double lat_rad, double lon_rad, char *descr) { if ( lat_rad < alat || lat_rad > blat || lon_rad < alon || lon_rad > blon ) return; double h = map_x1 + LON_TO_PT * (lon_rad - alon); double v = map_y1 + LAT_TO_PT * (lat_rad - alat); double r = 5; ps_setLineWidth(ps, 1); ps_setGray(ps, 0); ps_drawLine(ps, h - 2*r, v, h + 2*r, v); ps_drawLine(ps, h, v - 2*r, h, v + 2*r); ps_drawCircumference(ps, h, v, r); addLabel(&(ratnest_Rect){h, v, h + 75, v + 13}, "", descr); } /** * Draws a grid of parallels and meridians in the map area of the sheet. */ static void drawGrid() { int degrees, primes; double v, h; int lato; char s[99]; // Compute a suitable latitude step interval. int suitable_steps_sec[] = { 60, 2*60, 5*60, 10*60, 20*60, 60*60, 120*60, 0 }; int coord_step_sec; int i = 0; do { coord_step_sec = suitable_steps_sec[i]; if( LAT_TO_PT * SECtoRAD(coord_step_sec) > 72 ) break; // Lines too close, try next interval. i++; if( suitable_steps_sec[i] == 0 ) break; } while(1); ps_setLineWidth(ps, 0.3); int lat_sec = (int) (alat / M_PI * 180 * 3600) / coord_step_sec * coord_step_sec; double lat_rad = SECtoRAD(lat_sec); while (lat_rad < blat) { if( alat < lat_rad && lat_rad < blat ){ v = map_y1 + LAT_TO_PT * (lat_rad - alat); ps_drawLine(ps, map_x1, v, map_x2, v); if (lat_sec >= 0) { lato = 'N'; degrees = lat_sec / 3600; primes = (lat_sec / 60) % 60; } else { lato = 'S'; degrees = -lat_sec / 3600; primes = (-lat_sec / 60) % 60; } ps_moveTo(ps, map_x1 + 10, v + 2); sprintf(s, "%d°ree; %02d' %c", degrees, primes, lato); ps_drawString(ps, s); } lat_sec = lat_sec + coord_step_sec; lat_rad = SECtoRAD(lat_sec); } int lon_sec = (int) (alon / M_PI * 180 * 3600) / coord_step_sec * coord_step_sec; double lon_rad = SECtoRAD(lon_sec); while (lon_rad < blon) { if( alon < lon_rad && lon_rad < blon ){ h = map_x1 + LON_TO_PT * (lon_rad - alon); ps_drawLine(ps, h, map_y1, h, map_y2); if (lon_sec >= 0) { lato = 'E'; degrees = lon_sec / 3600; primes = (lon_sec / 60) % 60; } else { lato = 'W'; degrees = -lon_sec / 3600; primes = (-lon_sec / 60) % 60; } ps_moveTo(ps, h - 2, map_y1 + 10); printf("gsave 90 rotate\n"); sprintf(s, "%d°ree; %02d' %c", degrees, primes, lato); ps_drawString(ps, s); printf("grestore stroke\n"); } lon_sec = lon_sec + coord_step_sec; lon_rad = SECtoRAD(lon_sec); } } // Size of the magnetic variation box. #define BOX_W 58 #define BOX_H 60 /** * Draws a box with the magnetic variation calculated at the center of this chart, * assumed to be the average of the depicted area. * @param line */ static void drawMagneticVariationBox() { ps_setFontHeight(ps, 7); double magnetic_variation = getMagneticVariationAt(olat, olon, 0); int x0 = hmax - margin - BOX_W; int y0 = vmax - margin - BOX_H; double r = BOX_H * 40.0 / 100; ps_drawFramedRect(ps, x0, y0, BOX_W, BOX_H); ps_setLineWidth(ps, 0.5); ps_moveTo(ps, x0 + BOX_W / 2, y0 + BOX_H - BOX_H * 10.0 / 100); ps_relativeLineTo(ps, 0, -r); double dx = r*sin(magnetic_variation); double dy = r*cos(magnetic_variation); ps_relativeLineTo(ps, dx, dy); if( magnetic_variation >= 0 ){ dx = 0.3*r*sin(magnetic_variation + units_DEGtoRAD(160)); dy = 0.3*r*cos(magnetic_variation + units_DEGtoRAD(160)); } else { dx = 0.3*r*sin(magnetic_variation - units_DEGtoRAD(160)); dy = 0.3*r*cos(magnetic_variation - units_DEGtoRAD(160)); } ps_relativeLineTo(ps, dx, dy); ps_stroke(ps); char s[99]; snprintf(s, sizeof(s), "TH = MH %c %.1f°ree;", magnetic_variation >= 0? '-' : '+', units_RADtoDEG(fabs(magnetic_variation)) ); ps_moveTo(ps, x0 + 3, y0 + 15); ps_drawString(ps, s); zulu_Date d; zulu_timestampToDate(curr_date_timestamp, &d); snprintf(s, sizeof(s), "at %d-%02d-%02d", d.year, d.month, d.day); ps_moveTo(ps, x0 + 3, y0 + 5); ps_drawString(ps, s); } /** * Draws a runway. * @param rwy */ static void drawRunway(Runway *rwy) { double y1 = rwy->end1->lat; double x1 = rwy->end1->lon; double y2 = rwy->end2->lat; double x2 = rwy->end2->lon; // Draw the runway if both ends are visible. if ( y1 < alat || y1 > blat || x1 < alon || x1 > blon ) return; if ( y2 < alat || y2 > blat || x2 < alon || x2 > blon ) return; double h1 = map_x1 + LON_TO_PT * (x1-alon); double v1 = map_y1 + LAT_TO_PT * (y1-alat); double h2 = map_x1 + LON_TO_PT * (x2-alon); double v2 = map_y1 + LAT_TO_PT * (y2-alat); double width_pt = LAT_TO_PT * rwy->width_ft / units_NmToFeetFactor / 60 / 180 * M_PI; if( width_pt < 3 ) width_pt = 3; ps_setLineWidth(ps, width_pt); ps_setGray(ps, 0.5); ps_drawLine(ps, h1, v1, h2, v2); ps_setGray(ps, 0); ratnest_markSegment(place, h1, v1, h2, v2); // Place runway name and basic data. double h = (h1+h2)/2; double v = (v1+v2)/2; char line1[99]; snprintf(line1, sizeof(line1), "%s %s", rwy->airportCode, rwy->runwayIDs); char line2[99]; snprintf(line2, sizeof(line2), "%.0f&multiply;%.0f ft %.0f ft", rwy->length_ft, rwy->width_ft, rwy->altitude_ft); addLabel(&(ratnest_Rect){h, v, h + 75, v + 22}, line1, line2); } /** * Parse and draw RWY record. */ static void drawRWY() { if( fields_no != 10 ){ fprintf(stderr, "%s:%d: expected 10 fields in RWY but found %d\n", scene_file_name, scene_line_no, fields_no); return; } // Add all the known runways to the array, just in case we draw an ILS: double altitude_ft = atof(fields[3]); double length_ft = atof(fields[4]); double width_ft = atof(fields[5]); double y1 = parseLatitudeRad(fields[6]); double x1 = parseLongitudeRad(fields[7]); double y2 = parseLatitudeRad(fields[8]); double x2 = parseLongitudeRad(fields[9]); Runway *rwy = addRunway(fields[1], fields[2], y1, x1, y2, x2, altitude_ft, length_ft, width_ft); // Finally, draw: drawRunway(rwy); } /** * Parse and draw RWY2 record. */ static void drawRWY2() { if( fields_no != 9 ){ fprintf(stderr, "%s:%d: expected 9 fields in RWY2 but found %d\n", scene_file_name, scene_line_no, fields_no); return; } char *len_ft = fields[4]; double altitude_ft = atof(fields[3]); double length_ft = atof(fields[4]); double width_ft = atof(fields[5]); double center_lat_rad = parseLatitudeRad( fields[6] ); double center_lon_rad = parseLongitudeRad( fields[7] ); double heading_rad = units_DEGtoRAD( atof( fields[8] ) ); // Normalize heading range to [0,180[ so runway ends can be listed in // the correct order. if( !(0 <= heading_rad && heading_rad <= 2*M_PI) ){ printf("%s:%d: runway heading out of the range: %s\n", scene_file_name, scene_line_no, fields[8]); return; } if( heading_rad >= M_PI ) heading_rad -= M_PI; // FIXME: valid only for small lengths double half_len_m = 0.5 * units_FEETtoMETERS( atof( len_ft ) ); double delta_lat_rad = half_len_m * cos(heading_rad) / earth_MAJOR; double delta_lon_rad = half_len_m * sin(heading_rad) / (earth_MAJOR * cos(center_lat_rad)); // Add all the known runways to the array, just in case: Runway *rwy = addRunway(fields[1], fields[2], center_lat_rad - delta_lat_rad, center_lon_rad - delta_lon_rad, center_lat_rad + delta_lat_rad, center_lon_rad + delta_lon_rad, altitude_ft, length_ft, width_ft); // Finally, draw: drawRunway(rwy); } static void drawNDB(double h, double v) { double r = 5; ps_setLineWidth(ps, 1); ps_drawCircumference(ps, h, v, r); ps_drawCircumference(ps, h, v, r/2); ratnest_markRect(place, &(ratnest_Rect){h-r, v-r, h+r, v+r}); } static void drawDME(double h, double v) { double r = 7; ps_setLineWidth(ps, 1); ps_drawRect(ps, h - r, v - r, 2*r, 2*r); ratnest_markRect(place, &(ratnest_Rect){h-r, v-r, h+r, v+r}); } static void drawVOR(double h, double v) { int r = 7; ps_setLineWidth(ps, 1); ps_moveTo(ps, h, v-r); ps_lineTo(ps, h+r, v-r/2); ps_lineTo(ps, h+r, v+r/2); ps_lineTo(ps, h, v+r); ps_lineTo(ps, h-r, v+r/2); ps_lineTo(ps, h-r, v-r/2); ps_lineTo(ps, h, v-r); ps_stroke(ps); ratnest_markRect(place, &(ratnest_Rect){h-r, v-r, h+r, v+r}); } /** * Parse and draw NAV record. */ static void drawNAV() { if( fields_no != 8 ){ fprintf(stderr, "%s:%d: expected 8 fields in NAV record but found %d\n", scene_file_name, scene_line_no, fields_no); return; } char *id = fields[1]; char *type = fields[2]; char *vhf = fields[6]; //char *alt = fields[5]; double y = parseLatitudeRad(fields[3]); double x = parseLongitudeRad(fields[4]); if ( y < alat || y > blat || x < alon || x > blon ) return; double h = map_x1 + LON_TO_PT * (x-alon); double v = map_y1 + LAT_TO_PT * (y-alat); char *freq_unit = NULL; if( strcmp(type, "VOR") == 0 ){ drawVOR(h, v); freq_unit = "MHz"; } else if( strcmp(type, "DME") == 0 ){ drawDME(h, v); freq_unit = "MHz"; } else if( strcmp(type, "VOR/DME") == 0 ){ drawVOR(h, v); drawDME(h, v); freq_unit = "MHz"; } else if( strcmp(type, "VORTAC") == 0 ){ drawVOR(h, v); drawDME(h, v); freq_unit = "MHz"; } else if( strcmp(type, "TACAN") == 0 ){ drawVOR(h, v); drawDME(h, v); freq_unit = "MHz"; } else if( strcmp(type, "NDB") == 0 ){ drawNDB(h, v); freq_unit = "KHz"; } else if( strcmp(type, "OMARKER") == 0 ){ drawNDB(h, v); freq_unit = "KHz"; } else if( strcmp(type, "OMARKER/COMLO") == 0 ){ drawNDB(h, v); freq_unit = "KHz"; } else if( strcmp(type, "MMARKER") == 0 ){ drawNDB(h, v); freq_unit = "KHz"; } else if( strcmp(type, "IMARKER") == 0 ){ drawNDB(h, v); freq_unit = "KHz"; } else { fprintf(stderr, "%s:%d: unexpected/unsupported NAVAID type %s\n", scene_file_name, scene_line_no, type); return; } char line1[99]; snprintf(line1, sizeof(line1), "%s %s", id, type); char line2[99]; snprintf(line2, sizeof(line2), "%s %s", vhf, freq_unit); addLabel(&(ratnest_Rect){h, v, h+85, v+22}, line1, line2); } static void drawFeature() { if( fields_no != 6 ){ fprintf(stderr, "%s:%d: expected 6 fields in FEATURE record but found %d\n", scene_file_name, scene_line_no, fields_no); return; } drawMark(parseLatitudeRad(fields[2]), parseLongitudeRad(fields[3]), fields[1]); } static void drawTeamLoc() { if( fields_no != 5 ){ fprintf(stderr, "%s:%d: expected 5 fields in TEAM1_LOC record but found %d\n", scene_file_name, scene_line_no, fields_no); return; } drawMark(parseLatitudeRad(fields[1]), parseLongitudeRad(fields[2]), fields[0]); } /** * Returns the angle x (RAD) as readable, rounded DEG angle in the range [0,359]. * @param x * @return */ static int normalizeAngle(double rad) { int deg = (int)(units_RADtoDEG(rad) + 0.5); while(deg > 359) deg -= 360; while(deg < 0) deg += 360; return deg; } /** * Parse and drw ILS record. */ static void drawILS() { if( ! draw_ils ) return; if( fields_no != 13 ){ fprintf(stderr, "%s:%d: expected 13 fields in ILS record but found %d\n", scene_file_name, scene_line_no, fields_no); return; } char *rwyid = fields[1]; char *type = fields[2]; char *id = fields[3]; char *vhf = fields[4]; char *alt = fields[9]; double lat = parseLatitudeRad(fields[5]); double lon = parseLongitudeRad(fields[6]); if ( lat < alat || lat > blat || lon < alon || lon > blon ) return; // Draw glide slope antenna location. /* if( strcmp(fields[7], "-") != 0 && strcmp(fields[8], "-") != 0 ){ double gs_lat_rad = parseLatitudeRad(fields[7]); double gs_lon_rad = parseLongitudeRad(fields[8]); drawMark(gs_lat_rad, gs_lon_rad, "GP"); } */ double h, v; double bearing_deg = atof(fields[11]); // Determines the reference point the big ILS arrows points to. if( strcmp(type, "LDA") == 0 || strcmp(type, "LDA/DME") == 0 || strcmp(type, "SDF") == 0 || strcmp(type, "SDF/DME") == 0 ){ // Use locator antenna as reference point. h = map_x1 + LON_TO_PT * (lon-alon); v = map_y1 + LAT_TO_PT * (lat-alat); } else { // Search the runway end point (h,v) where this locator is located. RunwayEnd *landingEnd = searchILSRunwayEnd(rwyid, lat, lon); if( landingEnd != NULL ){ // Use reciprocal end as reference point: h = map_x1 + LON_TO_PT * (landingEnd->lon - alon); v = map_y1 + LAT_TO_PT * (landingEnd->lat - alat); } else { fprintf(stderr, "%s:%d: Warning: no runway end found for ILS %s in the scene file as scanned so far. Hint: the runway must be defined before the ILS record; the runway ID of the ILS must match one of the runway ends; the distance of the locator from the runway end be less than 500 m.\n", scene_file_name, scene_line_no, fields[3]); // Use locator antenna as reference point. h = map_x1 + LON_TO_PT * (lon-alon); v = map_y1 + LAT_TO_PT * (lat-alat); } } // Draw big arrow pointing to the landing end of the runway. // Locator outbound bearing in the coordinate system of the sheet // (attention! x right, y top): double sheet_bearing = units_DEGtoRAD(270 - bearing_deg); double r1 = 70.0; double r2 = 0.75 * r1; double da = units_DEGtoRAD(5); double ah = h + r1 * cos(sheet_bearing - da); double av = v + r1 * sin(sheet_bearing - da); double bh = h + r1 * cos(sheet_bearing + da); double bv = v + r1 * sin(sheet_bearing + da); double ch = h + r2 * cos(sheet_bearing); double cv = v + r2 * sin(sheet_bearing); ps_setGray(ps, 0); ps_setLineWidth(ps, 1); ps_moveTo(ps, ch, cv); ps_lineTo(ps, ah, av); ps_lineTo(ps, h, v); ps_lineTo(ps, bh, bv); ps_lineTo(ps, ch, cv); ps_lineTo(ps, h, v); ps_stroke(ps); ratnest_markSegment(place, h, v, ah, av); ratnest_markSegment(place, h, v, bh, bv); double magnetic_variation = getMagneticVariationAt(lat, lon, units_FEETtoMETERS(atoi(alt))); char line1[99]; snprintf(line1, sizeof(line1), "%s %s %s", id, type, rwyid); char line2[99]; snprintf(line2, sizeof(line1), "%d°ree; %s MHz", normalizeAngle(units_DEGtoRAD(bearing_deg) - magnetic_variation), vhf); double dh = h + 0.7 * r2 * cos(sheet_bearing); double dv = v + 0.7 * r2 * sin(sheet_bearing); addLabel(&(ratnest_Rect){dh, dv, dh + 75, dv + 22}, line1, line2); } /** * Draw fancy line connecting a rectangle (containing labels) to the point it * is associated to. Among the 4 edges of the rectangular area, choose the * middle point nearest to the target (x,y); from this point starts a Bézier * smooth curve that ends on the target. * @param r Label area. * @param x Target point, x coordinate (pt). * @param y Target point, y coordinate (pt). */ static void drawRectToPointReferenceLine(ratnest_Rect *r, double x, double y) { // First, the center of the rectangle (x0,y0): double x0 = (r->x1 + r->x2)/2; double y0 = (r->y1 + r->y2)/2; // Choose one middle point from one of the sides and set (x1,y1) so the // curve is perpendicular to the edge: double x1, y1; double radial = units_RADtoDEG( atan2(y - y0, x - x0) ); if( 45 <= radial && radial <= 135 ){ y0 = r->y2; x1 = x0; y1 = y0 + 10; } else if( -45 <= radial && radial <= 45 ){ x0 = r->x2; x1 = x0 + 10; y1 = y0; } else if( -135 <= radial && radial <= -45 ){ y0 = r->y1; x1 = x0; y1 = y0 - 10; } else { x0 = r->x1; x1 = x0 - 10; y1 = y0; } // The second control point is simply the middle point between 1 and target: double x2 = (x1 + x)/2; double y2 = (y1 + y)/2; ps_drawCircle(ps, x0, y0, 2); ps_drawCircle(ps, x, y, 1); printf("%.1f %.1f moveto %.1f %.1f %.1f %.1f %.1f %.1f curveto stroke\n", x0, y0, x1, y1, x2, y2, x, y); } /** * Place all the labels on the remaining free space of the map. */ static void drawLabels() { // Place each label box and draw reference line: ps_setLineWidth(ps, 0.5); int i; for(i = 0; i < labels_number; i++){ Label *lbl = labels[i]; // Save reference point: double x0 = lbl->r.x1; double y0 = lbl->r.y1; ratnest_Rect r; // Add a margin to the requested rectangle: lbl->r.x1 -= 5; lbl->r.y1 -= 5; lbl->r.x2 += 5; lbl->r.y2 += 5; if( ! ratnest_place(place, &lbl->r, &r) ){ fprintf(stderr, "Warning: no space left in map to place the rectangle %s\n", ratnest_RectToString(&lbl->r)); continue; } // Restore original size: r.x1 += 5; r.y1 += 5; r.x2 -= 5; r.y2 -= 5; ratnest_markRect(place, &r); drawRectToPointReferenceLine(&r, x0, y0); lbl->r = r; } // Actually draw labels' boxes: for(i = 0; i < labels_number; i++){ Label *lbl = labels[i]; ps_drawFramedRect(ps, lbl->r.x1, lbl->r.y1, lbl->r.x2 - lbl->r.x1, lbl->r.y2 - lbl->r.y1); ps_moveTo(ps, lbl->r.x1 + 5, lbl->r.y1 + 12); ps_drawString(ps, lbl->line1); ps_moveTo(ps, lbl->r.x1 + 5, lbl->r.y1 + 4); ps_drawString(ps, lbl->line2); } } /** * Draws title etc. */ static void drawHeader() { double v = vmax - margin - 14; double h = margin; char s[999]; ps_setFontHeight(ps, 14); ps_moveTo(ps, h, v); ps_drawString(ps, title); ps_setFontHeight(ps, 10); double lineHeight = 14; v -= lineHeight; snprintf(s, sizeof(s), "Scenery file: %s Scale: 1:%d", scene_file_name, scale); ps_moveTo(ps, h, v); ps_drawString(ps, s); zulu_Date d; zulu_timestampToDate(time(NULL), &d); v -= lineHeight; snprintf(s, sizeof(s), "Date created: %d-%02d-%02d", d.year, d.month, d.day); ps_moveTo(ps, h, v); ps_drawString(ps, s); v -= lineHeight; snprintf(s, sizeof(s), "Applicability: ACM flight simulator, see http://www.icosaedro.it/acm/download.html for more."); ps_moveTo(ps, h, v); ps_drawString(ps, s); } static void help() { printf( "char.exe - Navigation map generator for ACM-6.\n" "\n" "Generates a navigation chart from ACM-6 scenery file.\n" "The PostScript code is sent to standard output on a single A4 format page.\n" "Non-zero exit status indicates error.\n" "\n" "Syntax:\n" " chart.exe [OPTIONS]\n" "\n" "Options:\n" " --scene FILE Scenery file. MANDATORY.\n" " --wmm-cof FILE World Magnetic Model Coefficients file.\n" " Default: \"%s\".\n" " --title TITLE Title of the chart. Default: \"%s\".\n" " --olat LAT Latitude of the center of the chart.\n" " Example: \"32-30-00.000N\". Default: \"0N\".\n" " --olon LON Longitude of the center of the chart.\n" " Example: \"096-40-00.000W\". Default: \"0E\".\n" " --scale N Denominator of the scale factor 1:N. Default: %d.\n" " --dlat SEC Half-latitude range as number of arc-seconds.\n" " Default: %d.\n" " --date-year Y Magnetic variation calculated for the specified fractional\n" " year, example: 2017.5 stands for 2017-07-02.\n" " Default: today date.\n" " --date-timestamp T Magnetic variation calculated for the specified date\n" " given as Unix timestamp. Default: today date.\n" " --no-ils Does not draw ILS. Handy for wide area maps.\n" " --help | -h This help.\n\n", wmm_cof_file_name, title, scale, (int) (dlat/M_PI*180*3600+0.5) ); } #define RADtoPTFactor (180*60/M_PI*1853000/25.4*72) int main(int argc, char** argv) { int i; error_init(argv[0]); curr_date_timestamp = time(NULL); curr_date_year = zulu_timestampToYear(curr_date_timestamp); map_x1 = margin; map_x2 = hmax - margin; map_y1 = margin; map_y2 = margin + 0.9*(vmax - 2*margin); double map_w = map_x2 - map_x1; double map_h = map_y2 - map_y1; scale = 500000; dlat = scale * map_h / (2*RADtoPTFactor); for(i = 1; i < argc; i++){ char *a = argv[i]; char *v = (i+1) < argc? argv[i+1] : "?"; if( strcmp(a, "--help") == 0 || strcmp(a, "-h") == 0 ){ help(); } else if( strcmp(a, "--wmm-cof") == 0 ){ wmm_cof_file_name = v; i++; } else if( strcmp(a, "--scene") == 0 ){ scene_file_name = v; i++; } else if( strcmp(a, "--title") == 0 ){ title = v; i++; } else if( strcmp(a, "--olat") == 0 ){ olat = parseLatitudeRad(v); i++; } else if( strcmp(a, "--olon") == 0 ){ olon = parseLongitudeRad(v); i++; } else if( strcmp(a, "--dlat") == 0 ){ dlat = SECtoRAD(atof(v)); scale = 2*dlat/map_h*RADtoPTFactor; i++; } else if( strcmp(a, "--scale") == 0 ){ scale = atoi(v); dlat = scale * map_h / (2*RADtoPTFactor); i++; } else if( strcmp(a, "--date-year") == 0 ){ curr_date_year = atof(v); curr_date_timestamp = zulu_yearToTimestamp(curr_date_year); i++; } else if( strcmp(a, "--date-timestamp") == 0 ){ curr_date_timestamp = atoi(v); curr_date_year = zulu_timestampToYear(curr_date_timestamp); i++; } else if( strcmp(a, "--no-ils") == 0 ){ draw_ils = 0; } else { error_external("unknown option: %s", a); } } LAT_TO_PT = map_h / (2 * dlat); dlon = map_w / (2 * LAT_TO_PT * cos(olat)); LON_TO_PT = map_w / (2 * dlon); alat = olat - dlat; alon = olon - dlon; blat = olat + dlat; blon = olon + dlon; scene_file = fopen(scene_file_name, "r"); if( scene_file == NULL ) error_system("opening scenery file %s", scene_file_name); wmm_init(wmm_cof_file_name); ps = ps_new(); place = ratnest_new(&(ratnest_Rect){map_x1, map_y1, map_x2, map_y2}); drawHeader(); drawMagneticVariationBox(); ps_setFontHeight(ps, 7); ps_setClipRect(ps, map_x1, map_y1, map_w, map_h); drawGrid(); do { if( fgets(scene_line, sizeof(scene_line), scene_file) == NULL ) break; scene_line_no++; splitLineIntoFields(scene_line); if( fields_no == 0 ) continue; if( strcmp(fields[0], "RWY") == 0 ){ drawRWY(); } else if( strcmp(fields[0], "RWY2") == 0 ){ drawRWY2(); } else if( strcmp(fields[0], "ILS") == 0 ){ drawILS(); } else if( strcmp(fields[0], "NAV") == 0 ){ drawNAV(); } else if( strcmp(fields[0], "FEATURE") == 0 ){ drawFeature(); } else if( strcmp(fields[0], "TEAM1_LOC") == 0 ){ drawTeamLoc(); } else if( strcmp(fields[0], "TEAM2_LOC") == 0 ){ drawTeamLoc(); } else if( strcmp(fields[0], "GROUND_COLOR") == 0 ){ } else { fprintf(stderr, "%s:%d: unknown/unsupported record %s\n", scene_file_name, scene_line_no, fields[0]); } }while(1); if( ferror(scene_file) ) error_system("reading %s", scene_file_name); fclose(scene_file); drawLabels(); //ratnest_debug(place, ps); ps_close(ps); return 0; } acm-6.0_20200416/tools/chart/Makefile0000644000000000000000000000253113172245765015511 0ustar rootroot# This file generated by make-makefile, do not edit! # Create Makefile-include.txt instead for your customizations. CC := gcc CFLAGS := -Wall -Werror -g -fmax-errors=99 -Wuninitialized -Wmissing-prototypes -Wredundant-decls LIBS := .PHONY: all all: make chart.exe ps.o ratnest.o #include Makefile-include.txt .PHONY: test test: chart.exe ./chart.exe .PHONY: clean clean: rm -f *.o *.exe *.stackdump chart chart.o: chart.c ../../src/V/Vlibmath.h ../../src/dis/dis/earth.h ../../src/util/error.h ../../src/util/units.h ../../src/util/zulu.h ../../src/wmm/wmm.h ps.h ratnest.h $(CC) $(CFLAGS) -c chart.c -o chart.o chart.exe: ../../src/V/Vlibmath.o ../../src/dis/dis/earth.o ../../src/util/error.o ../../src/util/memory.o ../../src/util/units.o ../../src/util/zulu.o ../../src/wmm/Geomagnetism.o ../../src/wmm/wmm.o chart.o ps.o ratnest.o $(CC) $(CFLAGS) -o chart.exe ../../src/V/Vlibmath.o ../../src/dis/dis/earth.o ../../src/util/error.o ../../src/util/memory.o ../../src/util/units.o ../../src/util/zulu.o ../../src/wmm/Geomagnetism.o ../../src/wmm/wmm.o chart.o ps.o ratnest.o $(LIBS) -lm ps.o: ps.c ps.h ../../src/util/error.h ../../src/util/memory.h $(CC) $(CFLAGS) -c ps.c -o ps.o ratnest.o: ratnest.c ratnest.h ../../src/util/error.h ../../src/util/memory.h $(CC) $(CFLAGS) -c ratnest.c -o ratnest.o # Checksum of the original file: 1006174725 acm-6.0_20200416/tools/chart/make-charts.sh0000644000000000000000000000533613260344465016605 0ustar rootroot#!/bin/bash # ACM root directory: base=../.. # Destination directory of the generated charts to be set per zone: dst= # Chart program common options: opts="--wmm-cof $base/objects/WMM.COF" # Generates PDF of a navigation chart. # Global variables: # $dst: destination directory of the PDF. # $opts: global options for chart.exe. # Parameters: # $1: scenery file. # $2: destination PDF file name without extension. # $3: title. # $4: central latitude. # $5: central longitude. # $6: scale. # $7, $8, $9: optional further parameters for the chart.exe program. function f { echo "Generating $1 --> $dst/$2.pdf" ./chart.exe $opts \ --scene "$1" \ --title "$3" \ --olat $4 \ --olon $5 \ --scale $6 \ $7 $8 $9 > $dst/$2.ps || exit 1 ps2pdf -sPAPERSIZE=a4 $dst/$2.ps $dst/$2.pdf || exit 1 rm $dst/$2.ps } function italy() { local src src=$base/objects/zones/europe/italy.txt dst=$base/doc/charts/europe/italy # Navigation charts: f $src italy "Italy" 43-00N 13-00E 5000000 --no-ils f $src A "Italy/A" 44-10N 09-50E 2000000 --no-ils f $src B "Italy/B" 44-10N 14-50E 2000000 --no-ils f $src C "Italy/C" 39-10N 09-50E 2000000 --no-ils f $src D "Italy/D" 39-10N 14-50E 2000000 --no-ils # Instrumental landing: f $src alghero-fertilia "Alghero-Fertilia (LIEA - AHO)" 40-37N 8-17E 250000 f $src ancona-falconara "Ancona-Falconara (LIPY - AOI)" 43-37N 13-25E 250000 f $src bari-palese "Bari-Palese (LIBD - BRI)" 41-07N 16-45E 250000 f $src bergamo-orio-al-serio "Bergamo-Orio al Serio (LIME - BGY)" 45-40N 09-42E 250000 f $src bologna-borgopanigale "Bologna-Borgo Panigale (LIPE - BLQ)" 44-32N 11-15E 250000 f $src brindisi-casale "Brindisi-Casale (LIBR - BDS)" 40-40N 17-55E 250000 f $src cagliari-elmas "Cagliari-Elmas (LIEE - CAG)" 39-15N 09-03E 250000 f $src catania-fontanarossa "Catania-Fontanarossa (LICC - CTA)" 37-27N 15-00E 250000 f $src firenze-peretola "Firenze-Peretola (LIRQ - FLR)" 43-50N 11-10E 250000 f $src genova-sestri "Genova-Sestri (LIMJ - GOA)" 44-25N 08-55E 250000 f $src milano-linate "Milano-Linate (LIML - LIN)" 45-27N 09-15E 250000 f $src milano-malpensa "Milano-Malpensa (LIMC - MXP)" 45-35N 8-45E 250000 f $src napoli-capodichino "Napoli-Capodichino (LIRN - NAP)" 40-50N 14-17E 250000 f $src palermo-puntaraisi "Palermo-Punta Raisi (LICJ - PMO)" 38-10N 13-05E 250000 f $src reggiocalabria "Reggio Calabria (LICR - REG)" 38-05N 15-40E 250000 f $src roma-ciampino "Roma-Ciampino (LIRA - CIA)" 41-55N 12-30E 250000 f $src roma-fiumicino "Roma-Fiumicino (LIRF-FCO)" 41-52N 12-22E 250000 f $src torino-caselle "Torino-Caselle (LIMF - TRN)" 45-05N 07-45E 250000 f $src venezia-tessera "Venezia-Tessera (LIPZ)" 45-30N 12-15E 250000 f $src verona-villafranca "Verona-Villafranca (LIPX - VRN)" 45-20N 10-50E 250000 } italy acm-6.0_20200416/tools/build-doxygen-docs.sh0000644000000000000000000000263613605271605017003 0ustar rootroot#!/bin/bash # Generates the documentation from the sources with Doxygen. # These documents are not really useful per se, but the generation # process helps detecting missing or invalid documentation. PROJECT=acm if [ ! -d src ]; then echo "$0: ERROR: this script must be started from the root directory of the project." >&2 exit 1 fi # Doxygen program: DOXYGEN=doxygen # Docs dest dir: HTML_OUTPUT=doc/doxygen-html # Create the Doxygen config file: CONFIG=build-doxygen-docs-cfg.txt { echo "# This file was generated by the $0 script" echo "PROJECT_NAME=$PROJECT" echo "JAVADOC_AUTOBRIEF=YES" echo "QUIET=YES" echo "WARN_NO_PARAMDOC=YES" echo "INPUT=src" echo "RECURSIVE=YES" echo "EXCLUDE_SYMBOLS=EXTERN" echo "EXCLUDE_SYMLINKS=YES" echo "STRIP_CODE_COMMENTS=NO" echo "REFERENCED_BY_RELATION=YES" echo "HTML_OUTPUT=$HTML_OUTPUT" echo "DOCSET_PUBLISHER_ID=it.icosaedro" echo "DOCSET_PUBLISHER_NAME=icosaedro.it di Umberto Salsi" echo "SEARCHENGINE=NO" echo "GENERATE_LATEX=NO" } > $CONFIG # Errors log file: ERRORS=build-doxygen-docs-errors.txt rm -f -r $HTML_OUTPUT $DOXYGEN $CONFIG 2> $ERRORS rm $CONFIG if [ -d $HTML_OUTPUT ]; then echo "Generated documents available under: $HTML_OUTPUT/index.html" fi if [ -s "$ERRORS" ]; then echo "ERROR: see $ERRORS for details" sort $ERRORS > new-$ERRORS mv new-$ERRORS $ERRORS else rm -f $ERRORS echo "Doxygen documents generated successfully." fi # THE END acm-6.0_20200416/tools/faaairports/0000755000000000000000000000000013260344465015255 5ustar rootrootacm-6.0_20200416/tools/faaairports/README.txt0000644000000000000000000001226713172240075016755 0ustar rootrootThis directory contains the "faaairports" program that parses the U.S. FAA airports data base, as available in textual format from https://nfdc.faa.gov/xwiki/bin/view/NFDC and generate a valid ACM scenery file for each given range of latitude and longitude. Some Bash scripts are also included to create the basic sceneries included in the distributed package. Syntax of the command ===================== Lline continuation char '\' added for readability: faaairports.exe \ --lat-min LAT_MIN \ --lat-max LAT_MAX \ --lon-min LON_MIN \ --lon-max LON_MAX \ --src-dir DIR_FAA_DB where: LAT_MIN, LAT_MAX, LON_MIN, LON_MAX is the range of latitude and longiture of the items to extract (more about this next). The syntax is that usual, examples: 10.5N 10-30N 10-30-00.000N 96W etc. DIR_FAA_DB is the directory containing the FAA data base in its textual format. The following files are read from that directory: APT.txt, ILS.txt, NAV.txt. The resulting ACM scenery file is written on standard output, while errors are sent to standard error. Features ======== An item located at (lat,lon) is included in the generated output only if lies in the indicated range of latitude and longitude, that is: LAT_MIN <= lat < LAT_MAX and LON_MIN <= lon < LON_MAX Note that there is no way to include an item if it is located exactly at the north pole; this does not seem to be a severe limitation, though. Items located exactly on the 180E meridian are excluded too, but it seems there are not items there in the U.S. FAA data base. VOR and NDB are included if their location is in the range; the possible DME, if any, does not matter as under ACM the location of this latter must coincide with its respective VOR or NDB antenna. ILS are included based on the location of the LOCATOR antenna only; the locations of the associate GS and DME attennas do not matter. Runways are included if their middle point lies in the range. For runways very close to the edges of the zone it may happen some related ILS be missing from the resulting scenery because it falls outside the zone; this is not a problem for acm.exe because nearby zones are loaded (if available!), but it is a problem for the chart program which can "see" only one scenery at a time. Issues ====== Precise ILS bearing determination. ---------------------------------- For each ILS, its magnetic bearing MH is provided with a very hight accuracy of 0.01 DEG, but the corresponding magnetic deviation VAR is given with only 1 DEG of precision; the resulting calculated true bearing TH=MH+VAR is then affected by a quite large error of 1 DEG, which means 32 m of deviation for a runway 1 NM long. To fix this issue and allow the airplane to land closer to the middle of the runway, the following heuristic applies: The program also calculates the true bearing TH2 as the bearing of the line joining the locator to the served runway end position, if available. If this TH2 differs less than 1 DEG from the nominal TH, the difference is assumed to be due to the issue above only, and this calculated TH2 overrides the nominal value TH. Otherwise, if the calculated TH2 differs more than 1 DEG, the difference cannot be due to a rounding problem of the VAR, and the nominal TH is kept; a warning is displayed for precision approaches ILSs. SDF and LDA are assumed non-precision approaches. ILS name "I-XXX" silently changed to "IXXX" to comply with ACM requirements. ---------------------------------------------------------------------------- ILSs beams width is mostly missing. ----------------------------------- If beam width is missing, 5 DEG is silently assumed. Cope with current ACM ILS record limitations. --------------------------------------------- In the real world an ILS consists of up to 3 antennas: locator, GS and DME. Each antenna has its own location (latitude and longitude) and its own elevation. Unfortunately, the current format of the ACM ILS record allows to specify the location of the locator and GS and provides only one elevation field; distance is calculated using locator location + available elevation; landing point is calculated using GS location + available elevation. We remedy as follows depending on the type of ILS: 1. LOCATOR only ILS. No problem at all; the elevation field is set with the elevation of the locator. 2. LOCATOR + GS. Elevation field is set with the GS elevation for precise touch down point simulation; actual locator altitude is usually very close and does not care too much anyway. 3. LOCATOR + DME. ACM assumes the DME antenna coincides with the locator, which is already a source of error for precise distance measurement; to mitigate this, the elevation field is set with the actual DME elevation; actual locator altitude is usually very close and does not care too much anyway. 4. LOCATOR + GS + DME. Just like LOCATOR + GS for precise touch down point. Further complication: the elevation field is blank in many cases, so we take the value available in the following order of preference: GS, DME, LOCATOR. If no value available at all, zero is assumed and a warning is displayed. "VOT" FAA test facility NAVAIDs are not reported. ------------------------------------------------- - Umberto Salsi acm-6.0_20200416/tools/faaairports/faaairports.c0000644000000000000000000012210013646045025017726 0ustar rootroot/** * This program parses the U.S. FAA airports data base in its textual format and * generates a valid ACM scenery. Starts the program with the --help * option for more. * * * IMPLEMENTATION NOTES * * NOTE 1. LOCATOR misalignment issue workaround. * The FAA DB reports the magnetic bearing of the locator as degrees with * apparent very high precision (one hundred of degree, ex: "123.45") and the * local magnetic deviation at a given date, but this latter with very low * precision (1 degree only, ex: "09E" which means a magnetic deviation of * +9 DEG). * The true bearing can be calculate adding the magnetic deviation to the * magnetic bearing so obtaining the nominal true bearing: * * nominal_true_bearing = nominal_magnetic_bearing + nominal_mag_dev * = 123.45 + 9 = 132 +/- 1 DEG * * This nominal true bearing has then a very poor precision of only 1 degree, * which means 32 m of error over a distance of 1 NM. Such an error is * acceptable only for non precision approaches (ILS types LDA, SDF), but we * expect at least a precision ten times better than that for precision * approaches. * To get a better precision, this program calculates the actual true bearing * of the locator as the direction of the line joining the served runway end * to the locator position. The heuristics is then the following: * * 1. For non-precision ILS (LDA, SDF) use the nominal true bearing. * * 2. For any other type of ILS, calculate the actual true bearing as stated * above; if the result differs less than a degree from the nominal true bearing * we assume our value is simply a more accurate value than the nominal one; * if the difference is greater, keeps the nominal true bearing assuming the * misalignment be a design feature of the installation to preserve but displays * a warning. * * NOTE 2. Cope with current ILS record limitations. * In the real world an ILS consists of up to 3 antennas: locator, GS and DME. * Each antenna has its own location (latitude and longitude) and its own * elevation. Unfortunately, the current format of the ACM ILS record allows to * specify the location of the locator and GS and provides only one elevation * field; distance is calculated using locator location + available elevation; * landing point is calculated using GS location + available elevation. * We remedy as follows depending on the type of ILS: * * 1. LOCATOR only ILS. No problem at all; the elevation field is set with the * elevation of the locator. * * 2. LOCATOR + GS. Elevation field is set with the GS elevation for precise * touch down point simulation; actual locator altitude is usually very close * and does not care too much anyway. * * 3. LOCATOR + DME. ACM assumes the DME antenna coincides with the locator, * which is already a source of error for precise distance measurement; * to mitigate this, the elevation field is set with the actual DME elevation; * actual locator altitude is usually very close and does not care too much * anyway. * * 4. LOCATOR + GS + DME. Just like LOCATOR + GS for precise touch down point. * * Further complication: the elevation field is blank in many cases, so we * take the value available in the following order of preference: * GS, DME, LOCATOR. If no value available at all, zero is assumed and a * warning is displayed. * * @file * @author Umberto Salsi * @version $Date: 2018/09/23 13:05:36 $ */ #include #include #include #include #include #include "../../src/util/error.h" #include "../../src/util/units.h" #include "../../src/util/memory.h" #include "../../src/util/hashtable.h" #include "../../src/dis/dis/earth.h" /** * State of the string pattern matcher. Our custom implementation of the regex * is simple, fast an portable across Windows an Linux. */ typedef struct { /** * Next char to parse. Each match_X() function increments this pointer * whenever the parsing of X succeeded. */ char *c; } match_Type; /** * Initializes the string pattern matcher. * @param this * @param s Subject string to parse. */ static void match_init(match_Type *this, char *s) { this->c = s; } /** * Matches the end of the subject string. * @param this * @return True if currently at the end of the subject string. */ static int match_end(match_Type *this) { return *this->c == 0; } /** * Matches a char. * @param this * @param c * @return */ static int match_char(match_Type *this, char c) { if( *this->c == c ){ this->c++; return 1; } else { return 0; } } /** * Matches a set of chars. * @param this * @param set Set of chars. * @return */ static int match_set(match_Type *this, char *set) { while( *set != 0 && *set != *this->c ) set++; if( *set != 0 ){ this->c++; return 1; } else { return 0; } } /** * Matches a capital letter. * @param this * @return */ static int match_capital(match_Type *this) { if( 'A' <= *this->c && *this->c <= 'Z' ){ this->c++; return 1; } else { return 0; } } /** * Matches a digit. * @param this * @return */ static int match_digit(match_Type *this) { if( '0' <= *this->c && *this->c <= '9' ){ this->c++; return 1; } else { return 0; } } /** * Matches digits. * @param this * @param min Minimum number of digits to parse. * @param max Maximum number of digits to parse. * @return */ static int match_digits(match_Type *this, int min, int max) { char *back = this->c; int i = 0; while( i < max ){ if( ! match_digit(this) ){ if( i < min ){ this->c = back; return 0; } else { return 1; } } i++; } return 1; } /** * Matches one or more digits and a possible decimal part. Note that the number * must start with a digit, so ".5" isn't valid. */ static int match_decimal(match_Type *this) { char *back = this->c; if( match_digits(this, 1, 9) && ((match_char(this, '.') && match_digits(this, 1, 9)) || 1) ){ return 1; } else { this->c = back; return 0; } } /** * Returns true if the string is a decimal number. Note that the number * must start with a digit, so ".5" isn't valid. */ static int isDecimal(char *s) { match_Type m; match_init(&m, s); return match_decimal(&m) && match_end(&m); } /** * Returns true if the string is a decimal number with possible leading sign. * Note that the number must have at least one digit in its integral part, so * "+.5" isn't valid (rationale: the standard atof() function does not support * this abbreviated format). */ static int isSignedDecimal(char *s) { match_Type m; match_init(&m, s); return (match_set(&m, "+-") || 1) && match_decimal(&m) && match_end(&m); } /** * Returns true if the string is a valid latitude. Ex.: "12-34-56.78N". * FIXME: does not check range. */ static int isLatitude(char *s) { match_Type m; match_init(&m, s); return match_digits(&m, 1, 2) && match_char(&m, '-') && match_digits(&m, 1, 2) && match_char(&m, '-') && match_digits(&m, 1, 3) && ( ! match_char(&m, '.') || match_digits(&m, 1, 4) ) && match_set(&m, "NS") && match_end(&m); } /** * Returns true if the string is a valid longitude. Ex.: "12-34-56.78E". * FIXME: does not check range. */ static int isLongitude(char *s) { match_Type m; match_init(&m, s); return match_digits(&m, 1, 3) && match_char(&m, '-') && match_digits(&m, 1, 2) && match_char(&m, '-') && match_digits(&m, 1, 3) && ( ! match_char(&m, '.') || match_digits(&m, 1, 4) ) && match_set(&m, "WE") && match_end(&m); } /** * Matches a runway end identifier. Valid identifiers must contain 1 or 2 digits * and a possible letter among "LRCX"; the "X" letter seems used for LDA ILS only. * @param this * @return */ static int match_runwayEndID(match_Type *this) { return match_digit(this) && (match_digit(this) || 1) && (match_set(this, "LRCX") || 1); } /** * Returns true if the string is a valid runway end identifier. * @param s * @return */ static int isRunwayEndID(char *s) { match_Type m; match_init(&m, s); return match_runwayEndID(&m) && match_end(&m); } /** * Returns true if the string is a valid runway identifier. Valid * identifiers must contain two valid runway end IDs separated by "/". * @param s * @return */ static int isRunwayID(char *s) { match_Type m; match_init(&m, s); return match_runwayEndID(&m) && match_char(&m, '/') && match_runwayEndID(&m) && match_end(&m); } /** * Returns true if the string contains a valid ILS identifier. */ static int isILSID(char *s) { match_Type m; match_init(&m, s); return match_char(&m, 'I') && match_char(&m, '-') && match_capital(&m) && match_capital(&m) && match_capital(&m) && match_end(&m); } /* * Range of latitude and longitude of the items we are interested to extract. * The value must be greater or equal to the minimum, and strictly less than the * maximum. * For runways, the base end is compared. * For ILS, the position of the localized antenna is compared. * For NDB and VOR with associated DME, the location of the NDB or VOR antenna * is compared. */ static double lat_min = units_DEGtoRAD(-90); static double lat_max = units_DEGtoRAD(91); static double lon_min = units_DEGtoRAD(-180); static double lon_max = units_DEGtoRAD(181); /* * State of the input file we are parsing. Since we parse one file at a time, * one only set of global variables make this program simpler. Moreover, * the program abort at any error, and this further simplifies things. */ static char line[9999]; // current line to parse static int line_len; // length of the current line static int line_no; // no. of the current line, first is no. 1 static char *in_filename; // filename of the current file static FILE *in; // current file /** * Opens the file to parse. Aborts on error. * @param filename */ static void openFile(char *filename) { in_filename = filename; in = fopen(in_filename, "r"); if( in == NULL ) error_system("opening %s", in_filename); line_no = 0; line[0] = 0; } /** * Reads the next line and makes it available in global variables. * Aborts on error. * @return True if a new line is available, false at end of the file. */ static int readLine() { if( fgets(line, sizeof(line), in) == NULL ){ if( feof(in) ){ line[0] = 0; return 0; } else { error_external("%s:%d: file read error", in_filename, line_no); return 0; // prevents gcc -Wall complain } } else { line_no++; line_len = strlen(line); // Removes trailing "\r\n" or "\n": if( line_len > 0 && line[line_len-1] == '\n' ){ line[line_len-1] = 0; line_len--; if( line_len > 0 && line[line_len-1] == '\r' ){ line[line_len-1] = 0; line_len--; } } return 1; } } /** * Extracts a field from the current line. Aborts if the current line is too * short. Aborts if the destination field cannot contain the source field and * the trailing NUL byte even after leading and trailing white space have been * removed. * @param start Byte offset of the beginning. * @param len Length of the field. * @param field Destination of the field; leading and trailing white spaces are * removed and a trailing NUL byte is added. * @param field_capacity Capacity of the destination field, including terminating * NUL byte. */ static void getField(int start, int len, char *field, int field_capacity) { assert( len + 1 <= field_capacity ); if( start + len > line_len ) error_external("%s:%d: cannot parse field at offset %d length %d because line input length too short: %d", in_filename, line_no, start, len, line_len); int a = start; int b = start + len; while( a < b && isspace(line[a]) ) a++; while( b > a && isspace(line[b-1]) ) b--; int field_len = b - a; if( field_len > 0 ) memcpy(field, line + a, field_len); field[field_len] = 0; } static int getLatitudeField(int start, int len, char *field, int field_capacity) { getField(start, len, field, field_capacity); if( isLatitude(field) ){ return 1; } else { fprintf(stderr, "%s:%d: invalid latitude: %s\n", in_filename, line_no, field); return 0; } } static int getLongitudeField(int start, int len, char *field, int field_capacity) { getField(start, len, field, field_capacity); if( isLongitude(field) ){ return 1; } else { fprintf(stderr, "%s:%d: invalid longitude: %s\n", in_filename, line_no, field); return 0; } } /** * Normalize angle to the canonical range [0,2*M_PI[. */ static double normalizeAngle(double a) { if( ! isfinite(a) ) error_internal("cannot normalize non-finite angle: %g", a); if(a <= -2*M_PI) a = a + 2*M_PI*floor(-a / (2*M_PI)); else if(a >= 2*M_PI) a = a - 2*M_PI*floor(a / (2*M_PI)); if( a < 0 ) a = a + 2*M_PI; else if( a >= 2*M_PI ) a = a - 2*M_PI; return a; } // ------------------------ RWY ---------------------------- typedef struct { char pk[12]; // airport primary key of the data base char id[29]; char type[14]; char elev[8]; } Airport; /** * Maps airport's pk to the allocated Airport. */ static hashtable_Type *airports; /** * Runway end. The airport and end ID are the key of the entry. * Used to calculate the actual true bearing of the locator (see implementation * note 1). */ typedef struct { char pk[12]; // airport primary key of the data base char id[4]; // runway end ID double lat; double lon; } RunwayEnd; /** Maps airport pk + runway end ID to runway end. */ static hashtable_Type *runwayends; /** Get hash of runway end callback. */ static int getHashOfRunwayEnd(void *rwyend_) { RunwayEnd *rwyend = (RunwayEnd *) rwyend_; return hashtable_getHashOfString(rwyend->pk)*3 + hashtable_getHashOfString(rwyend->id); } /** Compare runway ends callback. */ static int equalRunwayEnd(void *a_, void *b_) { RunwayEnd *a = (RunwayEnd *) a_; RunwayEnd *b = (RunwayEnd *) b_; return strcmp(a->pk, b->pk) == 0 && strcmp(a->id, b->id) == 0; } /** Add runway end to hash table. */ static void addRunwayEnd(char *airport_pk, char *id, double lat, double lon) { RunwayEnd *rwyend = memory_allocate(sizeof(RunwayEnd), NULL); memory_strcpy(rwyend->pk, sizeof(rwyend->pk), airport_pk); memory_strcpy(rwyend->id, sizeof(rwyend->id), id); rwyend->lat = lat; rwyend->lon = lon; if( hashtable_get(runwayends, rwyend) != NULL ) fprintf(stderr, "%s:%d: ERROR: duplicated runway end\n", in_filename, line_no); hashtable_put(runwayends, rwyend, rwyend); } /** * Parses the airports data base file "APT.txt" and send to standard output * the filtered list of the RWY records. As a side effect, the global airports * array remains available, although currently not used elsewhere here. */ static void parseAPT(char *apt_filename) { airports = hashtable_new(hashtable_getHashOfString, hashtable_equalStrings); runwayends = hashtable_new(getHashOfRunwayEnd, equalRunwayEnd); openFile(apt_filename); // Step 1: parse all airports. Generate airports hash table. while( readLine() ){ if( ! memory_startsWith(line, "APT") ) continue; Airport *airport = memory_allocate(sizeof(Airport), NULL); getField(3, 11, airport->pk, sizeof(airport->pk)); getField(27, 4, airport->id, sizeof(airport->id)); getField(14, 13, airport->type, sizeof(airport->type)); getField(578, 7, airport->elev, sizeof(airport->elev)); hashtable_put(airports, airport->pk, airport); } // Step 2: parse runways and runway ends. Generate runway ends hash table // and RWY output records. rewind(in); line_no = 0; while( readLine() ){ if( ! memory_startsWith(line, "RWY") ) continue; // RWY id: char id[8]; getField(16, 7, id, sizeof(id)); if( ! isRunwayID(id) ){ // Silently discards helicopter, sea, balloon, ice runways. continue; } // RWY latitude 1: char lat1_text[16]; getField(88, 15, lat1_text, sizeof(lat1_text)); if( lat1_text[0] == 0 ) continue; double lat1; if( ! earth_parseLatitude(lat1_text, &lat1) ){ fprintf(stderr, "%s:%d: failed to parse RWY %s latitude: %s - ignore\n", in_filename, line_no, id, lat1_text); continue; } // RWY longitude 1: char lon1_text[16]; getField(115, 15, lon1_text, sizeof(lon1_text)); double lon1; if( ! earth_parseLongitude(lon1_text, &lon1) ){ fprintf(stderr, "%s:%d: failed to parse RWY longitude: %s - ignore\n", in_filename, line_no, lon1_text); continue; } char pk[12]; getField(3, 11, pk, sizeof(pk)); Airport *airport = hashtable_get(airports, pk); if( airport == NULL ){ fprintf(stderr, "%s:%d: RWY record refers to unknown airport primary key: %s - ignore\n", in_filename, line_no, pk); continue; } if( !(strcmp(airport->type, "AIRPORT") == 0 || strcmp(airport->type, "ULTRALIGHT") == 0) ) continue; char len[6]; getField(23, 5, len, sizeof(len)); char width[5]; getField(28, 4, width, sizeof(width)); // RWY latitude 2: char lat2_text[16]; if( ! getLatitudeField(310, 15, lat2_text, sizeof(lat2_text)) ) continue; double lat2; if( ! earth_parseLatitude(lat2_text, &lat2) ){ fprintf(stderr, "%s:%d: failed to parse RWY %s latitude: %s - ignore\n", in_filename, line_no, id, lat2_text); continue; } // RWY longitude 2: char lon2_text[16]; getField(337, 15, lon2_text, sizeof(lon2_text)); double lon2; if( ! earth_parseLongitude(lon2_text, &lon2) ){ fprintf(stderr, "%s:%d: failed to parse RWY longitude: %s - ignore\n", in_filename, line_no, lon2_text); continue; } // Ignore runway if middle point lies outside the range: double center_lat = (lat1 + lat2)/2; double center_lon = (lon1 + lon2)/2; if( !(lat_min <= center_lat && center_lat < lat_max && lon_min <= center_lon && center_lon < lon_max) ) continue; char id1[4]; getField(65, 3, id1, sizeof(id1)); char id2[4]; getField(287, 3, id2, sizeof(id2)); addRunwayEnd(pk, id1, lat1, lon1); addRunwayEnd(pk, id2, lat2, lon2); printf("RWY %s %s %.0f %s %s %s %s %s %s\n", airport->id, id, atof(airport->elev), // rounding to integral foot len, width, lat1_text, lon1_text, lat2_text, lon2_text); } fclose(in); } // ------------------- ILS --------------------------- /** * Key that univocally identifies a ILS. Informations about a single ILS are * split among several records: this key allows to rejoin these records * together. */ typedef struct { char airport_pk[12]; char runwayEndId[4]; char type[11]; } ILSKey; /** Get ILS hash callback. */ static int getILSKeyHash(void *ilskey_) { ILSKey *ilskey = (ILSKey *) ilskey_; return (hashtable_getHashOfString(ilskey->airport_pk) * 3 + hashtable_getHashOfString(ilskey->runwayEndId)) * 3 + hashtable_getHashOfString(ilskey->type); } /** Compare ILS key callback. */ static int equalILSKeys(void *a_, void *b_) { ILSKey *a = (ILSKey *) a_; ILSKey *b = (ILSKey *) b_; return strcmp(a->airport_pk, b->airport_pk) == 0 && strcmp(a->runwayEndId, b->runwayEndId) == 0 && strcmp(a->type, b->type) == 0; } /** * Collected data about an ILS. Note that in the ILS record of out scenery * format there is only one elevation field available for all the antennas and * there are no fields for the location of the DME, then ACM shows the distance * from the LOCALIZER instead. Then, we collect all the elevations of all the * antennas and use the first one available among these (in order of preference): * 1. GS elevation, so the landing spot is at the planned distance from the * runway threshold. * 2. DME elevation, so the displayed distance closely matches the expected value. * 3. LOCALIZER elevation as last resort. */ typedef struct { ILSKey key; // key shared by records referring to a specific ILS char airport_pk[12]; char id[7]; // name of the ILS, typically "I-XXX" double nominal_true_bearing; // nominal true bearing // LOCALIZER data: int loc_line_no; // line no. in the file for error messages char loc_status[23]; char loc_lat[15]; char loc_lon[15]; char loc_elev[8]; char loc_freq[8]; char loc_width[6]; // GS data: int gs_line_no; // line no. in the file for error messages char gs_status[23]; char gs_lat[15]; char gs_lon[15]; char gs_elev[8]; char gs_angle[6]; // DME data: char dme_elev[8]; } ILS; /** * Dictionary that maps our ILS key into the allocated ILS. */ hashtable_Type *ilss; /** * Parse the ILS key fields from the current line, searches the dictionary * for a matching ILS or allocates a new one if not found. * @return Allocated ILS data structure that matches the key, or NULL if * parsing failed. */ static ILS * parseILSKey() { ILSKey key; getField(4, 11, key.airport_pk, sizeof(key.airport_pk)); if( key.airport_pk[0] == 0 ){ fprintf(stderr, "%s:%d: empty airport primary key\n", in_filename, line_no); return NULL; } getField(15, 3, key.runwayEndId, sizeof(key.runwayEndId)); if( ! isRunwayEndID(key.runwayEndId) ){ fprintf(stderr, "%s:%d: invalid runway end ID: %s\n", in_filename, line_no, key.runwayEndId); return NULL; } getField(18, 10, key.type, sizeof(key.type)); if( key.type[0] == 0 ){ fprintf(stderr, "%s:%d: empty airport type\n", in_filename, line_no); return NULL; } ILS *ils = hashtable_get(ilss, &key); if( ils == NULL ){ ils = memory_allocate(sizeof(ILS), NULL); memset(ils, 0, sizeof(*ils)); ils->key = key; hashtable_put(ilss, &ils->key, ils); } return ils; } /** * Parse magnetic bearing and magnetic variation and returns the true bearing. * @param bearing_mag_deg Ex. "012". * @param mag_var Ex. "09E". * @return True bearing in [0,2*M_PI[, or -1 if parsing failed. */ static double computeTrueBearing(char *bearing_mag_deg, char *mag_var) { // Parse bearing: match_Type m; match_init(&m, bearing_mag_deg); if( !( match_decimal(&m) && match_end(&m) ) ) return -1; double bearing_true_deg = atof(bearing_mag_deg); // Parse magnetic variation: match_init(&m, mag_var); if( !(match_decimal(&m) && match_set(&m, "EW") && match_end(&m) ) ) return -1; int mag_var_len = strlen(mag_var); char sign = mag_var[mag_var_len-1]; // Calculate true bearing: mag_var[mag_var_len-1] = 0; if( sign == 'E' ) bearing_true_deg += atof(mag_var); else bearing_true_deg -= atof(mag_var); mag_var[mag_var_len-1] = sign; // restore original return normalizeAngle( units_DEGtoRAD(bearing_true_deg) ); } /** * Returns the true bearing going from (lat1,lon1) to (lat2,lon2). * Used to calculate the actual bearing from runway end to locator. */ static double trueBearing(double lat1, double lon1, double lat2, double lon2) { double dlat = lat2 - lat1; double dlon = lon2 - lon1; return normalizeAngle( atan2(dlon * cos(lat1), dlat) ); } static int isILSFreq(char *s) { match_Type m; match_init(&m, s); if( !(match_digits(&m, 1, 3) && (!match_char(&m, '.') || match_digits(&m, 1, 2)) && match_end(&m)) ) return 0; int freq = floor(atof(s) * 100 + 0.5); // tenth of KHz return 10800 <= freq && freq <= 11795; } static void parseILS(char *ils_filename) { // Step 1: collect data for each specific ILS, spread among several records. ilss = hashtable_new(getILSKeyHash, equalILSKeys); openFile(ils_filename); while( readLine() ){ if( memory_startsWith(line, "ILS1") ){ ILS *ils = parseILSKey(); if( ils == NULL ) continue; getField(4, 11, ils->airport_pk, sizeof(ils->airport_pk)); getField(28, 6, ils->id, sizeof(ils->id)); if( ! isILSID(ils->id) ){ fprintf(stderr, "%s:%d: invalid ILS ID '%s', check!\n", in_filename, line_no, ils->id); } char bearing_mag_deg[7]; getField(281, 6, bearing_mag_deg, sizeof(bearing_mag_deg)); char mag_var[7]; getField(287, 3, mag_var, sizeof(mag_var)); ils->nominal_true_bearing = computeTrueBearing(bearing_mag_deg, mag_var); if( ils->nominal_true_bearing < 0 ){ fprintf(stderr, "%s:%d: invalid magnetic bearing ('%s') or magnetic variation ('%s') for ILS %s, check!\n", in_filename, line_no, bearing_mag_deg, mag_var, ils->id); ils->nominal_true_bearing = 0; } } else if( memory_startsWith(line, "ILS2") ){ // LOCALIZER ILS *ils = parseILSKey(); if( ils == NULL ) continue; ils->loc_line_no = line_no; getField(28, 22, ils->loc_status, sizeof(ils->loc_status)); if( ! getLatitudeField(60, 14, ils->loc_lat, sizeof(ils->loc_lat)) ) continue; if( ! getLongitudeField(85, 14, ils->loc_lon, sizeof(ils->loc_lon)) ) continue; getField(126, 7, ils->loc_elev, sizeof(ils->loc_elev)); if( ! isSignedDecimal(ils->loc_elev) ){ fprintf(stderr, "%s:%d: invalid localizer elevation '%s' for ILS %s -- assuming zero\n", in_filename, line_no, ils->loc_elev, ils->id); strcpy(ils->loc_elev, "0"); } getField(133, 7, ils->loc_freq, sizeof(ils->loc_freq)); if( ! isDecimal(ils->loc_freq) ){ fprintf(stderr, "%s:%d: invalid frequency '%s' for ILS %s -- assuming zero\n", in_filename, line_no, ils->loc_freq, ils->id); strcpy(ils->loc_freq, "0"); } getField(155, 5, ils->loc_width, sizeof(ils->loc_width)); if( ! isDecimal(ils->loc_width) ){ if( *(ils->loc_width) != 0 ) fprintf(stderr, "%s:%d: invalid beam width '%s' for ILS %s -- assuming 5.0\n", in_filename, line_no, ils->loc_width, ils->id); strcpy(ils->loc_width, "5.0"); } } else if( memory_startsWith(line, "ILS3") ){ // GS ILS *ils = parseILSKey(); if( ils == NULL ) continue; ils->gs_line_no = line_no; getField(28, 22, ils->gs_status, sizeof(ils->gs_status)); if( ! getLatitudeField(60, 14, ils->gs_lat, sizeof(ils->gs_lat)) ) continue; if( ! getLongitudeField(85, 14, ils->gs_lon, sizeof(ils->gs_lon)) ) continue; getField(126, 7, ils->gs_elev, sizeof(ils->gs_elev)); if( ! isSignedDecimal(ils->gs_elev) ){ fprintf(stderr, "%s:%d: invalid GS elevation '%s' for ILS %s -- assuming zero\n", in_filename, line_no, ils->gs_elev, ils->id); strcpy(ils->gs_elev, "0"); } getField(148, 5, ils->gs_angle, sizeof(ils->gs_angle)); } else if( memory_startsWith(line, "ILS4") ){ // DME ILS *ils = parseILSKey(); if( ils == NULL ) continue; getField(126, 7, ils->dme_elev, sizeof(ils->dme_elev)); if( ! isSignedDecimal(ils->dme_elev) ){ fprintf(stderr, "%s:%d: invalid DME elevation '%s' for ILS %s -- assuming zero\n", in_filename, line_no, ils->dme_elev, ils->id); strcpy(ils->dme_elev, "0"); } } else if( memory_startsWith(line, "ILS5") ){ } else if( memory_startsWith(line, "ILS6") ){ } else { fprintf(stderr, "%s:%d: not a valid record ILS1...6 line -- ignore\n", in_filename, line_no); } } fclose(in); // Step 2: generate the output by filtering the wanted ILS. ILSKey *key; for(key = hashtable_firstKey(ilss); key != NULL; key = hashtable_nextKey(ilss)){ ILS *ils = hashtable_get(ilss, key); if( ! memory_startsWith(ils->loc_status, "OPERATIONAL") ) continue; double lat; if( ! earth_parseLatitude(ils->loc_lat, &lat) ){ fprintf(stderr, "%s:%d: invalid latitude %s -- ignore\n", in_filename, ils->loc_line_no, ils->loc_lat); continue; } if( !(lat_min <= lat && lat < lat_max) ) continue; double lon; if( ! earth_parseLongitude(ils->loc_lon, &lon) ){ fprintf(stderr, "%s:%d: invalid longitude %s -- ignore\n", in_filename, ils->loc_line_no, ils->loc_lon); continue; } if( !(lon_min <= lon && lon < lon_max) ) continue; if( ! isILSFreq(ils->loc_freq) ){ fprintf(stderr, "%s:%d: %s %s: invalid frequency: %s -- ignore\n", in_filename, line_no, ils->key.type, ils->id, ils->loc_freq); continue; } /* * If this ILS claims to have an operational GS, its type must match * this fact, otherwise ACM would complain. Fix as needed. */ int has_gs = memory_startsWith(ils->gs_status, "OPERATIONAL"); if( ! has_gs && (memory_startsWith(ils->key.type, "ILS") || strcmp(ils->key.type, "LOC/GS") == 0) ){ fprintf(stderr, "%s:%d: GS not operational for ILS %s -- ignore\n", in_filename, ils->loc_line_no, ils->id); continue; } // Remove leading "I-" from ID: char id[7]; memory_strcpy(id, sizeof(id), ils->id); if( memory_startsWith(id, "I-") ){ memmove(id + 1, id + 2, strlen(id) -1); } // Chose elevation (see implementation note 2): char *elev_ptr; if( ils->gs_elev[0] != 0 ) elev_ptr = ils->gs_elev; else if( ils->dme_elev[0] != 0 ) elev_ptr = ils->dme_elev; else elev_ptr = ils->loc_elev; if( *elev_ptr == 0 ){ fprintf(stderr, "%s: no elevation available for ILS %s -- using zero\n", in_filename, ils->id); elev_ptr = "0"; } char elev[9]; snprintf(elev, sizeof(elev), "%.0f", atof(elev_ptr)); // Compute the actual true bearing and compare with the nominal true // bearing and decide which one to report (see implementation note 1). double true_bearing = ils->nominal_true_bearing; RunwayEnd rwyendkey; memory_strcpy(rwyendkey.pk, sizeof(rwyendkey.pk), ils->airport_pk); memory_strcpy(rwyendkey.id, sizeof(rwyendkey.id), ils->key.runwayEndId); RunwayEnd *rwyend = hashtable_get(runwayends, &rwyendkey); if( rwyend == NULL ){ fprintf(stderr, "%s:%d: Warning: ILS %s, no runway end found for airport pk %s and runway end ID %s. Cannot calculate actual true bearing of the locator, using nominal.", in_filename, ils->loc_line_no, ils->id, ils->airport_pk, ils->key.runwayEndId); } else { int precision_approach = !( memory_startsWith(ils->key.type, "LDA") || memory_startsWith(ils->key.type, "SDF") ); // Compute actual geographic bearing: double actual_true_bearing = trueBearing(rwyend->lat, rwyend->lon, lat, lon); double delta = fabs( actual_true_bearing - true_bearing ); if( delta > M_PI ) delta = 2*M_PI - delta; // Which bearing to take? if( delta < units_DEGtoRAD(1) ){ // Very small misalignment. if( precision_approach ) true_bearing = actual_true_bearing; } else { // Quite large misalignment. if( precision_approach ) fprintf(stderr, "%s:%d: Warning: ILS %s of type %s:\n" "\t- nominal true bearing is %03.2f DEG,\n" "\t- locator to runway end %s true bearing is %03.2f DEG,\n" "\t- delta %.2f DEG.\n", in_filename, ils->loc_line_no, ils->id, ils->key.type, units_RADtoDEG(ils->nominal_true_bearing), rwyend->id, units_RADtoDEG(actual_true_bearing), units_RADtoDEG(delta)); } } printf("ILS %s %s %s %s %s %s %s %s %s %s %03.2f %s\n", ils->key.runwayEndId, ils->key.type, id, ils->loc_freq, ils->loc_lat, ils->loc_lon, has_gs? ils->gs_lat : "-", has_gs? ils->gs_lon : "-", elev, ils->loc_width, units_RADtoDEG(true_bearing), has_gs? ils->gs_angle : "-" ); } } // --------------------- NAV ---------------------------------- /** Channel to frequency map. */ static char *channels[][2] = { {"17X", "108.00"}, {"17Y", "108.05"}, {"18X", "108.10"}, {"18Y", "108.15"}, {"19X", "108.20"}, {"19Y", "108.25"}, {"20X", "108.30"}, {"20Y", "108.35"}, {"21X", "108.40"}, {"21Y", "108.45"}, {"22X", "108.50"}, {"22Y", "108.55"}, {"23X", "108.60"}, {"23Y", "108.65"}, {"24X", "108.70"}, {"24Y", "108.75"}, {"25X", "108.80"}, {"25Y", "108.85"}, {"26X", "108.90"}, {"26Y", "108.95"}, {"27X", "109.00"}, {"27Y", "109.05"}, {"28X", "109.10"}, {"28Y", "109.15"}, {"29X", "109.20"}, {"29Y", "109.25"}, {"30X", "109.30"}, {"30Y", "109.35"}, {"31X", "109.40"}, {"31Y", "109.45"}, {"32X", "109.50"}, {"32Y", "109.55"}, {"33X", "109.60"}, {"33Y", "109.65"}, {"34X", "109.70"}, {"34Y", "109.75"}, {"35X", "109.80"}, {"35Y", "109.85"}, {"36X", "109.90"}, {"36Y", "109.95"}, {"37X", "110.00"}, {"37Y", "110.05"}, {"38X", "110.10"}, {"38Y", "110.15"}, {"39X", "110.20"}, {"39Y", "110.25"}, {"40X", "110.30"}, {"40Y", "110.35"}, {"41X", "110.40"}, {"41Y", "110.45"}, {"42X", "110.50"}, {"42Y", "110.55"}, {"43X", "110.60"}, {"43Y", "110.65"}, {"44X", "110.70"}, {"44Y", "110.75"}, {"45X", "110.80"}, {"45Y", "110.85"}, {"46X", "110.90"}, {"46Y", "110.95"}, {"47X", "111.00"}, {"47Y", "111.05"}, {"48X", "111.10"}, {"48Y", "111.15"}, {"49X", "111.20"}, {"49Y", "111.25"}, {"50X", "111.30"}, {"50Y", "111.35"}, {"51X", "111.40"}, {"51Y", "111.45"}, {"52X", "111.50"}, {"52Y", "111.55"}, {"53X", "111.60"}, {"53Y", "111.65"}, {"54X", "111.70"}, {"54Y", "111.75"}, {"55X", "111.80"}, {"55Y", "111.85"}, {"56X", "111.90"}, {"56Y", "111.95"}, {"57X", "112.00"}, {"57Y", "112.05"}, {"58X", "112.10"}, {"58Y", "112.15"}, {"59X", "112.20"}, {"59Y", "112.25"}, {"70X", "112.30"}, {"70Y", "112.35"}, {"71X", "112.40"}, {"71Y", "112.45"}, {"72X", "112.50"}, {"72Y", "112.55"}, {"73X", "112.60"}, {"73Y", "112.65"}, {"74X", "112.70"}, {"74Y", "112.75"}, {"75X", "112.80"}, {"75Y", "112.85"}, {"76X", "112.90"}, {"76Y", "112.95"}, {"77X", "113.00"}, {"77Y", "113.05"}, {"78X", "113.10"}, {"78Y", "113.15"}, {"79X", "113.20"}, {"79Y", "113.25"}, {"80X", "113.30"}, {"80Y", "113.35"}, {"81X", "113.40"}, {"81Y", "113.45"}, {"82X", "113.50"}, {"82Y", "113.55"}, {"83X", "113.60"}, {"83Y", "113.65"}, {"84X", "113.70"}, {"84Y", "113.75"}, {"85X", "113.80"}, {"85Y", "113.85"}, {"86X", "113.90"}, {"86Y", "113.95"}, {"87X", "114.00"}, {"87Y", "114.05"}, {"88X", "114.10"}, {"88Y", "114.15"}, {"89X", "114.20"}, {"89Y", "114.25"}, {"90X", "114.30"}, {"90Y", "114.35"}, {"91X", "114.40"}, {"91Y", "114.45"}, {"92X", "114.50"}, {"92Y", "114.55"}, {"93X", "114.60"}, {"93Y", "114.65"}, {"94X", "114.70"}, {"94Y", "114.75"}, {"95X", "114.80"}, {"95Y", "114.85"}, {"96X", "114.90"}, {"96Y", "114.95"}, {"97X", "115.00"}, {"97Y", "115.05"}, {"98X", "115.10"}, {"98Y", "115.15"}, {"99X", "115.20"}, {"99Y", "115.25"}, {"100X", "115.30"}, {"100Y", "115.35"}, {"101X", "115.40"}, {"101Y", "115.45"}, {"102X", "115.50"}, {"102Y", "115.55"}, {"103X", "115.60"}, {"103Y", "115.65"}, {"104X", "115.70"}, {"104Y", "115.75"}, {"105X", "115.80"}, {"105Y", "115.85"}, {"106X", "115.90"}, {"106Y", "115.95"}, {"107X", "116.00"}, {"107Y", "116.05"}, {"108X", "116.10"}, {"108Y", "116.15"}, {"109X", "116.20"}, {"109Y", "116.25"}, {"110X", "116.30"}, {"110Y", "116.35"}, {"111X", "116.40"}, {"111Y", "116.45"}, {"112X", "116.50"}, {"112Y", "116.55"}, {"113X", "116.60"}, {"113Y", "116.65"}, {"114X", "116.70"}, {"114Y", "116.75"}, {"115X", "116.80"}, {"115Y", "116.85"}, {"116X", "116.90"}, {"116Y", "116.95"}, {"117X", "117.00"}, {"117Y", "117.05"}, {"118X", "117.10"}, {"118Y", "117.15"}, {"119X", "117.20"}, {"119Y", "117.25"}, {"120X", "117.30"}, {"120Y", "117.35"}, {"121X", "117.40"}, {"121Y", "117.45"}, {"122X", "117.50"}, {"122Y", "117.55"}, {"123X", "117.60"}, {"123Y", "117.65"}, {"124X", "117.70"}, {"124Y", "117.75"}, {"125X", "117.80"}, {"125Y", "117.85"}, {"126X", "117.90"}, {"126Y", "117.95"}, {NULL, NULL} }; static int mapChannelToFrequency(char *channel, char *freq, int freq_capacity) { // Skip leading zeros: while( *channel == '0' ) channel++; int i = 0; while(channels[i][0] != NULL){ if( strcmp(channels[i][0], channel) == 0 ){ memory_strcpy(freq, freq_capacity, channels[i][1]); return 1; } i++; } return 0; } // VOR, VORTAC, DME. static int isNAVFreq(char *s) { match_Type m; match_init(&m, s); if( !(match_digits(&m, 1, 3) && (!match_char(&m, '.') || match_digits(&m, 1, 2)) && match_end(&m)) ) return 0; int freq = floor(atof(s) * 100 + 0.5); // tenth of KHz return 10800 <= freq && freq <= 11795; } static int isNDBFreq(char *s) { match_Type m; match_init(&m, s); if( !(match_digits(&m, 3, 3) && match_end(&m)) ) return 0; int freq = atoi(s); return 200 <= freq && freq <= 529; } static void parseNAV(char *nav_filename) { openFile(nav_filename); while( readLine() ){ if( ! memory_startsWith(line, "NAV1") ) continue; char type[21]; getField(8, 20, type, sizeof(type)); if( strcmp(type, "FAN MARKER") == 0 ) // Unsure what they are, but no freq and no channel available; // currently only 6 remaining, but it seems are going to be removed. continue; char id[5]; getField(28, 4, id, sizeof(id)); char lat[15]; if( ! getLatitudeField(371, 14, lat, sizeof(lat)) ) continue; char lon[15]; if( ! getLongitudeField(396, 14, lon, sizeof(lon)) ) continue; char elev[8]; getField(472, 7, elev, sizeof(elev)); char freq[7]; getField(533, 6, freq, sizeof(freq)); char channel[5]; getField(529, 4, channel, sizeof(channel)); // True if have to add a dummy DME for some special type of NDB. int add_dme = 0; if( strcmp(type, "VORTAC") == 0 || strcmp(type, "VOR/DME") == 0 || strcmp(type, "NDB") == 0 || strcmp(type, "TACAN") == 0 || strcmp(type, "VOR") == 0 || strcmp(type, "DME") == 0 ){ // ok } else if( strcmp(type, "FAN MARKER") == 0 || strcmp(type, "MARINE NDB") == 0 || strcmp(type, "UHF/NDB") == 0){ strcpy(type, "NDB"); } else if( strcmp(type, "CONSOLAN") == 0 || strcmp(type, "VOT") == 0 ){ // FAA test facility. Ignore. continue; } else if( strcmp(type, "MARINE NDB/DME") == 0 || strcmp(type, "NDB/DME") == 0 ){ strcpy(type, "NDB"); add_dme = 1; } else { fprintf(stderr, "%s:%d: unknown type of NAVAID: %s -- ignore\n", in_filename, line_no, type); continue; } double lat_rad; if( ! earth_parseLatitude(lat, &lat_rad) ){ fprintf(stderr, "%s:%d: invalid latitude -- ignore\n", in_filename, line_no); continue; } if( !(lat_min <= lat_rad && lat_rad < lat_max) ) continue; double lon_rad; if( ! earth_parseLongitude(lon, &lon_rad) ){ fprintf(stderr, "%s:%d: invalid longitude -- ignore\n", in_filename, line_no); continue; } if( !(lon_min <= lon_rad && lon_rad < lon_max) ) continue; // Elevation is missing on some NDB, but it does not care too much // when there is no associated DME. // Workaround: if( elev[0] == 0 ){ if( ! add_dme && strcmp(type, "NDB") == 0 ){ strcpy(elev, "0"); } else { //fprintf(stderr, "%s:%d: elevation field is empty -- ignore\n", // in_filename, line_no); //continue; // We currently do not support NDB/DME and report NDB only anyway, // so continue: strcpy(elev, "0"); } } if( freq[0] == 0 ){ if( channel[0] == 0 ){ fprintf(stderr, "%s:%d: missing both frequency and channel -- ignore\n", in_filename, line_no); continue; } else { if( ! mapChannelToFrequency(channel, freq, sizeof(freq)) ){ fprintf(stderr, "%s:%d: invalid channel: %s -- ignore\n", in_filename, line_no, channel); continue; } } } if( (memory_startsWith(type, "VOR") || memory_startsWith(type, "DME")) && ! isNAVFreq(freq) ){ fprintf(stderr, "%s:%d: %s %s: invalid frequency: %s -- ignore\n", in_filename, line_no, type, id, freq); continue; } if( strcmp(type, "NDB") == 0 && ! isNDBFreq(freq) ){ fprintf(stderr, "%s:%d: %s %s: invalid frequency: %s -- ignore\n", in_filename, line_no, type, id, freq); continue; } char elev_rounded[9]; snprintf(elev_rounded, sizeof(elev_rounded), "%.0f", atof(elev)); printf("NAV %s %s %s %s %s %s %s\n", id, type, lat, lon, elev_rounded, freq, channel[0] == 0? "-" : channel); // FIXME: unsure what to do with NDB+DME: they cannot share the same freq! if( add_dme ) fprintf(stderr, "%s:%d: Warning: unsupported DME associated to NDB -- reporting NDB only antenna instead.\n", in_filename, line_no); } fclose(in); } static void help() { puts( "This program parses the U.S. FAA data base in its textual format and generates\n" "an ACM scenery. The FAA data base can be downloaded from\n" "https://nfdc.faa.gov/xwiki/bin/view/NFDC\n" "Download and decompress the APT.zip, ILS.zip and NAV.zip files in a folder,\n" "then start this program with the following command line parameters:\n" "\n" " --lat-min DEG Minimum latitude, default 90S.\n" " --lat-max DEG Maximum latitude, default 90N.\n" " --lon-min DEG Minimum longitude, default 180W.\n" " --lon-max DEG maximum longitude, default 180E.\n" " --src-dir PATH Path to the directory of the decompressed FAA data base,\n" " default . (current directory).\n" "\n" "The program collects all the runways, ILS and NAVAID in the given range of\n" "latitude and longitude and writes the scenery on standard output; errors and\n" "warnings are sent to standard error. Only the RWY, RWY2, ILS and NAV records\n" "are generated. You may want to add the TEAM1_LOC, TEAM2_LOC and GROUND_COLOR\n" "records to complete the scenery.\n" ); } int main(int argc, char** argv) { error_init(argv[0]); char *src_dir = "."; int i = 1; while( i < argc ){ char *a = argv[i]; char *v = i < argc? argv[i+1] : NULL; if( strcmp(a, "--help") == 0 || strcmp(a, "-h") == 0 ){ help(); return 0; } else if( strcmp(a, "--lat-min") == 0 && v != NULL ){ if( ! earth_parseLatitude(v, &lat_min) ) error_external("invalid latitude: %s", v); i += 2; } else if( strcmp(a, "--lat-max") == 0 && v != NULL ){ if( ! earth_parseLatitude(v, &lat_max) ) error_external("invalid latitude: %s", v); i += 2; } else if( strcmp(a, "--lon-min") == 0 && v != NULL ){ if( ! earth_parseLongitude(v, &lon_min) ) error_external("invalid longitude: %s", v); i += 2; } else if( strcmp(a, "--lon-max") == 0 && v != NULL ){ if( ! earth_parseLongitude(v, &lon_max) ) error_external("invalid longitude: %s", v); i += 2; } else if( strcmp(a, "--src-dir") == 0 && v != NULL ){ src_dir = v; i += 2; } else { error_external("unknown option/value: %s", a); } } if( !(lat_min < lat_max && lon_min < lon_max) ) error_external("invalid latitude [%g,%g[ DEG or longitude [%g,%g[ DEG ranges", units_RADtoDEG(lat_min), units_RADtoDEG(lat_max), units_RADtoDEG(lon_min), units_RADtoDEG(lon_max)); char path[999]; snprintf(path, sizeof(path), "%s/APT.txt", src_dir); parseAPT(path); snprintf(path, sizeof(path), "%s/ILS.txt", src_dir); parseILS(path); snprintf(path, sizeof(path), "%s/NAV.txt", src_dir); parseNAV(path); } acm-6.0_20200416/tools/faaairports/Makefile0000644000000000000000000000207313172230174016710 0ustar rootroot# This file generated by make-makefile, do not edit! # Create Makefile-include.txt instead for your customizations. CC := gcc CFLAGS := -Wall -Werror -g -fmax-errors=99 -Wuninitialized -Wmissing-prototypes -Wredundant-decls LIBS := .PHONY: all all: make faaairports.exe #include Makefile-include.txt .PHONY: test test: faaairports.exe ./faaairports.exe .PHONY: clean clean: rm -f *.o *.exe *.stackdump faaairports faaairports.o: faaairports.c ../../src/V/Vlibmath.h ../../src/dis/dis/earth.h ../../src/util/error.h ../../src/util/hashtable.h ../../src/util/memory.h ../../src/util/units.h $(CC) $(CFLAGS) -c faaairports.c -o faaairports.o faaairports.exe: ../../src/V/Vlibmath.o ../../src/dis/dis/earth.o ../../src/util/error.o ../../src/util/hashtable.o ../../src/util/memory.o ../../src/util/units.o faaairports.o $(CC) $(CFLAGS) -o faaairports.exe ../../src/V/Vlibmath.o ../../src/dis/dis/earth.o ../../src/util/error.o ../../src/util/hashtable.o ../../src/util/memory.o ../../src/util/units.o faaairports.o $(LIBS) -lm # Checksum of the original file: 3055807014 acm-6.0_20200416/tools/faaairports/make-zones.sh0000644000000000000000000002403513646045025017664 0ustar rootroot#!/bin/bash # Creates several USA zones and charts from the FAA airports data base. # FAA data base directory. FAA_DB=../../../FAA-airports-database # Destination dir. of the creates sceneries: ZONES_DIR=../../objects/zones # Destination dir. of the created charts: CHARTS_DIR=../../doc/charts # WMM coefficients: WMM_COF=../../objects/WMM.COF # Generates PDF of a navigation chart. # Parameters: # $1: scenery file. # $2: destination PDF file name without extension. # $3: title. # $4: central latitude. # $5: central longitude. # $6: scale. # $7, $8, $9: optional further parameters for the chart.exe program. function doChart { local dst dst=$2 echo "Generating chart $dst.pdf ..." ../chart/chart.exe --wmm-cof $WMM_COF \ --scene "$1" \ --title "$3" \ --olat $4 \ --olon $5 \ --scale $6 \ $7 $8 $9 > $dst.ps || exit 1 ps2pdf -sPAPERSIZE=a4 $dst.ps $dst.pdf || exit 1 rm $dst.ps } function newyork() { local lat_min lat_max lon_min lon_max scenery dst lat_min=40N lat_max=45N lon_min=75W lon_max=70W scenery=$ZONES_DIR/usa/newyork.txt { echo "# New York area scenery." echo "# Created: " $(date +%Y-%m-%d) echo "# Latitude range: [$lat_min, $lat_max[" echo "# Longitude range: [$lon_min, $lon_max[" echo "# 2017-10-04 Checked against https://nfdc.faa.gov/xwiki/bin/view/NFDC/56DaySub-2017-03-02" echo "# \"56 Day NASR Subscription - Effective March 2, 2017\"." echo echo "# New York, JFK 04L:" echo "TEAM1_LOC 40-37-19.2759N 073-47-08.1083W 000 031" echo "# Boston, BOS 22R:" echo "TEAM2_LOC 42-22-41.8759N 071-00-16.2499W 000 199" echo "GROUND_COLOR #305030" ./faaairports.exe \ --lat-min $lat_min \ --lat-max $lat_max \ --lon-min $lon_min \ --lon-max $lon_max \ --src-dir $FAA_DB } > $scenery dst=$CHARTS_DIR/usa/newyork if [ ! -d $dst ]; then mkdir $dst || exit 1 fi doChart $scenery $dst/new-york "New York area" 40-40N 73-45W 250000 doChart $scenery $dst/boston "Boston area" 42-22N 71-05W 250000 } function dallas() { local lat_min lat_max lon_min lon_max scenery dst lat_min=30N lat_max=35N lon_min=100W lon_max=95W scenery=../../objects/zones/usa/dallas.txt { echo "# Dallas area scenery." echo "# Created: " $(date +%Y-%m-%d) echo "# Latitude range: [$lat_min, $lat_max[" echo "# Longitude range: [$lon_min, $lon_max[" echo "# 2017-10-04 Checked against https://nfdc.faa.gov/xwiki/bin/view/NFDC/56DaySub-2017-03-02" echo "# \"56 Day NASR Subscription - Effective March 2, 2017\"." echo echo "TEAM1_LOC 32-58-40.4N 096-50-25.75W 645 160" echo "TEAM2_LOC 34-17-36.089N 097-01-25.366W 762.0 040" echo "GROUND_COLOR #305030" echo echo "# Addison:" echo "FEATURE ../../features/tower.obv 32-58-04.800N 096-50-16.800W 644 0" echo "FEATURE ../../features/man.obv 32-58-29.000N 096-50-20.000W 644 90" echo ./faaairports.exe \ --lat-min $lat_min \ --lat-max $lat_max \ --lon-min $lon_min \ --lon-max $lon_max \ --src-dir $FAA_DB echo echo "#" echo "# To visit the ACM air museum at the Addison airport, uncomment these lines:" echo "#" echo "#FEATURE ../../missiles/aim9.obv 32-57-10.000N 096-49-59.000W 660 290" echo "#FEATURE ../../missiles/sa10.obv 32-57-11.000N 096-49-59.000W 660 290" echo "#FEATURE ../../missiles/sa11.obv 32-57-12.000N 096-49-59.000W 660 290" echo "#FEATURE ../../missiles/sa2.obv 32-57-13.000N 096-49-59.000W 660 290" echo "#FEATURE ../../features/telar1.obv 32-57-14.000N 096-49-59.000W 660 290" echo "#FEATURE ../../tracer.obv 32-57-15.000N 096-49-59.000W 660 290" echo "#FEATURE ../../features/hangar.obv 32-57-17.000N 096-49-59.000W 644 290" echo "#FEATURE ../../aircraft/c172.obv 32-57-19.000N 096-49-59.000W 660 290" echo "#FEATURE ../../aircraft/f16.obv 32-57-21.000N 096-49-59.000W 660 290" echo "#FEATURE ../../aircraft/f18.obv 32-57-23.000N 096-49-59.000W 660 290" echo "#FEATURE ../../aircraft/il78.obv 32-57-25.000N 096-49-59.000W 660 290" echo "#FEATURE ../../aircraft/kc135.obv 32-57-27.000N 096-49-59.000W 660 290" echo "#FEATURE ../../aircraft/mig23.obv 32-57-29.000N 096-49-59.000W 660 290" echo "#FEATURE ../../aircraft/mig25.obv 32-57-31.000N 096-49-59.000W 660 290" echo "#FEATURE ../../aircraft/mig29.obv 32-57-33.000N 096-49-59.000W 660 290" echo "#FEATURE ../../aircraft/su30.obv 32-57-35.000N 096-49-59.000W 660 290" echo "#FEATURE ../../aircraft/ufo.obv 32-57-37.000N 096-49-59.000W 660 290" echo "#FEATURE ../../aircraft/b-747.obv 32-57-39.000N 096-49-59.000W 680 290" } > $scenery dst=$CHARTS_DIR/usa/dallas if [ ! -d $dst ]; then mkdir $dst || exit 1 fi # Navigation charts: ###doChart $scenery $dst/O O 32-30-00.000N 096-40-00.000W 2500000 --no-ils doChart $scenery $dst/A A 33-25-00.000N 097-55-00.000W 1000000 --no-ils doChart $scenery $dst/B B 33-25-00.000N 095-55-00.000W 1000000 --no-ils doChart $scenery $dst/C C 32-15-00.000N 097-55-00.000W 1000000 --no-ils doChart $scenery $dst/D D 32-15-00.000N 095-55-00.000W 1000000 --no-ils # Instrumental landing: doChart $scenery $dst/AA "Wichita Falls Area" 33-59-00N 98-31-30W 250000 doChart $scenery $dst/AB "Ardmore (KADM, ADM)" 34-15-00N 97-00-00W 250000 doChart $scenery $dst/BA "Dallas, Addison, Love Field" 32-52-00.000N 096-56-00.000W 250000 doChart $scenery $dst/BB "Dallas, Ft. Worth (KDFW, DFW)" 32-54-00.000N 097-02-20.000W 100000t doChart $scenery $dst/BC "Texas, Paris (KPRX, PRX)" 33-37-00.000N 095-27-20.000W 100000 doChart $scenery $dst/CA "Waco Regional Airport (KACT, ACT)" 31-40-00N 97-10-00W 250000 doChart $scenery $dst/DA "Tyler Pounds Regional Airport (KTYR, TYR)" 32-22-00N 95-24-00W 100000hart doChart $scenery $dst/CB "Temple, Draughon-Miller (KTPL, TPL)" 31-10-00N 97-25-00W 250000 } function sfrancisco() { local lat_min lat_max lon_min lon_max scenery lat_min=35N lat_max=40N lon_min=125W lon_max=120W scenery=$ZONES_DIR/usa/sfrancisco.txt { echo "# S. Francisco area scenery." echo "# Created: " $(date +%Y-%m-%d) echo "# Latitude range: [$lat_min, $lat_max[" echo "# Longitude range: [$lon_min, $lon_max[" echo "# 2017-10-04 Checked against https://nfdc.faa.gov/xwiki/bin/view/NFDC/56DaySub-2017-03-02" echo "# \"56 Day NASR Subscription - Effective March 2, 2017\"." echo echo "# ?????:" echo "TEAM1_LOC 35N 125W 000 031" echo "# ?????:" echo "TEAM1_LOC 35N 125W 000 031" echo "GROUND_COLOR #305030" ./faaairports.exe \ --lat-min $lat_min \ --lat-max $lat_max \ --lon-min $lon_min \ --lon-max $lon_max \ --src-dir $FAA_DB } > $scenery } function losangeles() { local lat_min lat_max lon_min lon_max scenery dst lat_min=30N lat_max=35N lon_min=120W lon_max=115W scenery=$ZONES_DIR/usa/losangeles.txt { echo "# Los Angeles area scenery." echo "# Created: " $(date +%Y-%m-%d) echo "# Latitude range: [$lat_min, $lat_max[" echo "# Longitude range: [$lon_min, $lon_max[" echo "# 2017-10-04 Checked against https://nfdc.faa.gov/xwiki/bin/view/NFDC/56DaySub-2017-03-02" echo "# \"56 Day NASR Subscription - Effective March 2, 2017\"." echo echo "# ?????:" echo "TEAM1_LOC 30N 120W 000 031" echo "# ?????:" echo "TEAM1_LOC 30N 120W 000 031" echo "GROUND_COLOR #305030" ./faaairports.exe \ --lat-min $lat_min \ --lat-max $lat_max \ --lon-min $lon_min \ --lon-max $lon_max \ --src-dir $FAA_DB } > $scenery dst=$CHARTS_DIR/usa/losangeles if [ ! -d $dst ]; then mkdir $dst || exit 1 fi doChart $scenery $dst/los-angeles-area "Los Angeles area" 34-01N 118-18W 250000 doChart $scenery $dst/los-angeles "Los Angeles airport" 33-57N 118-24W 100000 } function lasvegaswest() { local lat_min lat_max lon_min lon_max scenery lat_min=35N lat_max=40N lon_min=120W lon_max=115W scenery=$ZONES_DIR/usa/lasvegaswest.txt { echo "# Las Vegas west area scenery." echo "# Created: " $(date +%Y-%m-%d) echo "# Latitude range: [$lat_min, $lat_max[" echo "# Longitude range: [$lon_min, $lon_max[" echo "# 2017-10-04 Checked against https://nfdc.faa.gov/xwiki/bin/view/NFDC/56DaySub-2017-03-02" echo "# \"56 Day NASR Subscription - Effective March 2, 2017\"." echo echo "# ?????:" echo "TEAM1_LOC 35N 120W 000 031" echo "# ?????:" echo "TEAM1_LOC 35N 120W 000 031" echo "GROUND_COLOR #305030" ./faaairports.exe \ --lat-min $lat_min \ --lat-max $lat_max \ --lon-min $lon_min \ --lon-max $lon_max \ --src-dir $FAA_DB } > $scenery } function lasvegaseast() { local lat_min lat_max lon_min lon_max scenery lat_min=35N lat_max=40N lon_min=115W lon_max=110W scenery=$ZONES_DIR/usa/lasvegaseast.txt { echo "# Las Vegas east area scenery." echo "# Created: " $(date +%Y-%m-%d) echo "# Latitude range: [$lat_min, $lat_max[" echo "# Longitude range: [$lon_min, $lon_max[" echo "# 2017-10-04 Checked against https://nfdc.faa.gov/xwiki/bin/view/NFDC/56DaySub-2017-03-02" echo "# \"56 Day NASR Subscription - Effective March 2, 2017\"." echo echo "# ?????:" echo "TEAM1_LOC 35N 115W 000 031" echo "# ?????:" echo "TEAM1_LOC 35N 115W 000 031" echo "GROUND_COLOR #305030" ./faaairports.exe \ --lat-min $lat_min \ --lat-max $lat_max \ --lon-min $lon_min \ --lon-max $lon_max \ --src-dir $FAA_DB } > $scenery } function tucson() { local lat_min lat_max lon_min lon_max scenery lat_min=30N lat_max=35N lon_min=115W lon_max=110W scenery=$ZONES_DIR/usa/tucson.txt { echo "# Tucson area scenery." echo "# Created: " $(date +%Y-%m-%d) echo "# Latitude range: [$lat_min, $lat_max[" echo "# Longitude range: [$lon_min, $lon_max[" echo "# 2017-10-04 Checked against https://nfdc.faa.gov/xwiki/bin/view/NFDC/56DaySub-2017-03-02" echo "# \"56 Day NASR Subscription - Effective March 2, 2017\"." echo echo "# ?????:" echo "TEAM1_LOC 30N 115W 000 031" echo "# ?????:" echo "TEAM1_LOC 30N 115W 000 031" echo "GROUND_COLOR #305030" ./faaairports.exe \ --lat-min $lat_min \ --lat-max $lat_max \ --lon-min $lon_min \ --lon-max $lon_max \ --src-dir $FAA_DB } > $scenery } if [ ! -d $ZONES_DIR/usa ]; then mkdir $ZONES_DIR/usa || exit 1 fi if [ ! -d $CHARTS_DIR/usa ]; then mkdir $CHARTS_DIR/usa || exit 1 fi newyork dallas sfrancisco losangeles lasvegaswest lasvegaseast tucson acm-6.0_20200416/tools/create-ufo-obv.c0000644000000000000000000000503213175511065015721 0ustar rootroot/** * Creates the U.F.O. object in obv format as required by our Vlib. * Basically a cone with 8 round "shields" (or laser beam thrower, or whatever * they are) all around, 4 red to the right, 4 green to the left. * Sends its output to stdout, so one has to redirect it to * ../objects/aircraft/ufo.obv by hand. * * @file * @author Umberto Salsi * @version $Date: 2017/10/30 02:17:57 $ */ /* * LINKER_OPTIONS -lm */ #include #include #include #include #include "../src/V/Vlibmath.h" //#include "../src/V/VObjects.h" // Height (ft): #define H (20.0) // Base radius: #define R (1.1*H) // Shields' radius: #define S (0.25*H) static int no_of_points; static int no_of_polygons; static char this_polygon_color[100]; static int this_polygon_no_vertices; static char this_polygon_vertices[2000]; static char points[2000]; static char polygons[2000]; static void openPolygon(char *colors) { strcpy(this_polygon_color, colors); this_polygon_no_vertices = 0; strcpy(this_polygon_vertices, ""); } static void addPoint(VPoint *p) { char s[100]; no_of_points++; sprintf(s, "%d %.2f %.2f %.2f\n", no_of_points, p->x, p->y, p->z); strcat(points, s); sprintf(s, " %d", no_of_points); strcat(this_polygon_vertices, s); this_polygon_no_vertices++; } static void closePolygon() { char s[1000]; sprintf(s, "%s %d%s\n", this_polygon_color, this_polygon_no_vertices, this_polygon_vertices); strcat(polygons, s); no_of_polygons++; } static void writeAll() { printf("%d %d\n", no_of_points, no_of_polygons); printf("%s", points); printf("%s", polygons); } int main(int argc, char** argv) { int i, j; double da; VPoint shield[6]; printf("ufo\n"); // The fuselage is a cone with vertex (0,0,-H) and base on the xy plane: da = 2 * M_PI / 8; for(i = 0; i < 8; i++){ openPolygon("(gray44 clip)"); addPoint(&(VPoint){R*cos(i*da+da), R*sin(i*da+da), 0}); addPoint(&(VPoint) {0, 0, -H}); addPoint(&(VPoint){R*cos(i*da), R*sin(i*da), 0}); closePolygon(); } // Vertices of an hexagonal shield located along x: for(i = 0; i < 6; i++){ double a = - 2 * M_PI / 6 * i; shield[i] = (VPoint) {1.1*R, S*cos(a), S*sin(a)}; } // Place 8 shields around the base, right red, left green: for(i = 0; i < 8; i++){ VMatrix m; VPoint q; VIdentMatrix(&m); VRotate(&m, 3, 2*M_PI/16 + i * da); openPolygon(i < 4? "(red clip)" : "(green clip)"); for(j = 0; j < 6; j++){ VTransform(&shield[j], &m, &q); addPoint(&q); } closePolygon(); } writeAll(); return 0; } acm-6.0_20200416/tools/Makefile0000644000000000000000000000276613260344465014415 0ustar rootroot# This file generated by make-makefile, do not edit! # Create Makefile-include.txt instead for your customizations. CC := gcc CFLAGS := -Wall -Werror -g -fmax-errors=99 -Wuninitialized -Wmissing-prototypes -Wredundant-decls LIBS := .PHONY: all all: cd ./chart && make all cd ./faaairports && make all cd ./ourairports_com && make all make create-ils.exe create-ufo-obv.exe #include Makefile-include.txt .PHONY: test test: create-ils.exe create-ufo-obv.exe ./create-ils.exe ./create-ufo-obv.exe .PHONY: clean clean: rm -f *.o *.exe *.stackdump create-ils create-ufo-obv cd ./chart && make clean cd ./faaairports && make clean cd ./ourairports_com && make clean create-ils.o: create-ils.c ../src/V/Vlibmath.h ../src/dis/dis/earth.h ../src/util/error.h ../src/util/memory.h ../src/util/reader.h ../src/util/units.h $(CC) $(CFLAGS) -c create-ils.c -o create-ils.o create-ils.exe: ../src/V/Vlibmath.o ../src/dis/dis/earth.o ../src/util/error.o ../src/util/memory.o ../src/util/reader.o ../src/util/units.o create-ils.o $(CC) $(CFLAGS) -o create-ils.exe ../src/V/Vlibmath.o ../src/dis/dis/earth.o ../src/util/error.o ../src/util/memory.o ../src/util/reader.o ../src/util/units.o create-ils.o $(LIBS) -lm create-ufo-obv.o: create-ufo-obv.c ../src/V/Vlibmath.h $(CC) $(CFLAGS) -c create-ufo-obv.c -o create-ufo-obv.o create-ufo-obv.exe: ../src/V/Vlibmath.o create-ufo-obv.o $(CC) $(CFLAGS) -o create-ufo-obv.exe ../src/V/Vlibmath.o create-ufo-obv.o $(LIBS) -lm # Checksum of the original file: 1491430480 acm-6.0_20200416/tools/ourairports_com/0000755000000000000000000000000013260344465016171 5ustar rootrootacm-6.0_20200416/tools/ourairports_com/README.txt0000644000000000000000000000221513200762501017654 0ustar rootrootThis directory contains the ourairports_com.exe command line program to parse the world airports database as provided by: http://ourairports.com Data downloaded 2017-11-01. The following files are required by this program and must be store in a single directory whose path must be indicated on the command line: airports.csv, navaids.csv, runways.csv. Writes to standard output the generated scenery file with RWY and NAV records only. For a detailed description of the command line options, use --help. Unfortunately, ILS antennas are missing from that database, so only RWY and NAV records are generated. The only purpose of the airports file is to get the average elevation of its runways, as the ACM does not support (or, it behaves badly) close runways at different elevation (see the reference manual for more about this issue). The make-zones.sh Bash shell script generates some sample zones and also add some ILS antennas for major airports from data collected by hand; the tools/create-ils.exe program has been used here to generate the basic entries for all the ILS and the interesting ones have been selected for completion and added to the script. acm-6.0_20200416/tools/ourairports_com/ourairports_com.c0000644000000000000000000005331513203342525021563 0ustar rootroot/** * Command line program to parse the world airports database as provided by: * http://ourairports.com * * Data downloaded 2017-11-01. The following files are required by this * program and must be stored in a single directory whose path must be indicated * on the command line: airports.csv, navaids.csv, runways.csv. * * Writes to standard output the generated scenery file with RWY and NAV records * only. For a detailed description of the command line options, use --help. * * Unfortunately, ILS antennas are missing from that database, so only RWY and * NAV records are generated. * * The only purpose of the airports file is to get the average elevation of its * runways, as the ACM does not support (or, it behaves badly) close runways at * different elevation (see the reference manual for more about this issue). * * @file * @author Umberto Salsi * @version $Date: 2017/11/16 17:05:25 $ */ #include #include #include // LINKER_OPTIONS -lm #include "../../src/util/error.h" #include "../../src/util/hashtable.h" #include "../../src/util/memory.h" #include "../../src/util/reader.h" #include "../../src/util/units.h" #include "../../src/dis/dis/earth.h" #define MAX_FIELDS 99 /* * Range of latitude and longitude of the items we are interested to extract. * The value must be greater or equal to the minimum, and strictly less than the * maximum. * For runways, the base end is compared. * For ILS, the position of the localized antenna is compared. * For NDB and VOR with associated DME, the location of the NDB or VOR antenna * is compared. */ static double lat_min = units_DEGtoRAD(-90); static double lat_max = units_DEGtoRAD(91); static double lon_min = units_DEGtoRAD(-180); static double lon_max = units_DEGtoRAD(181); static long parseLong(char *s, long *l) { char *tail; *l = strtol(s, &tail, 10); return tail != s && *tail == 0; } static int parseDouble(char *s, double *d) { char *tail; *d = strtod(s, &tail); return tail != s && *tail == 0 && isfinite(*d); } static int foundExpectdHeaderFields(reader_Type *in, char **exp_fields, int got_fields_number, char **got_fields) { int err = 0; int i = 0; while(exp_fields[i] != NULL){ if( i >= got_fields_number ){ fprintf(stderr, "%s:%d: missing expected fields: ", reader_getPath(in), reader_getLineNumber(in)); do { fprintf(stderr, " %d)%s", i+1, exp_fields[i]); i++; } while(exp_fields[i] != NULL); fprintf(stderr, "\n"); return 0; } if( strcmp(exp_fields[i], got_fields[i]) != 0 ){ fprintf(stderr, "%s:%d: expected field no. %d \"%s\" but got \"%s\"\n", reader_getPath(in), reader_getLineNumber(in), i+1, exp_fields[i], got_fields[i]); err++; } i++; } if( i < got_fields_number ){ fprintf(stderr, "%s:%d: unexpected further fields: ", reader_getPath(in), reader_getLineNumber(in)); do { fprintf(stderr, " %d)%s", i+1, got_fields[i]); i++; } while(i < got_fields_number); fprintf(stderr, "\n"); } return err == 0; } typedef struct { char *pk; // airport primary key of the data base int line_no; // line no. in the airports file (for duplicates error reporting) int elevation; // average elevation assumed for all the runways of this airport (ft) int isAvailable; // if open, operational, fixed-wings airport } Airport; /** * Maps airport's pk to the allocated Airport. */ static hashtable_Type *airports; static int parseAirports(char *path) { airports = hashtable_new(hashtable_getHashOfString, hashtable_equalStrings); reader_Type *in = reader_new(path); char line[999]; while( reader_getLine(in, line, sizeof(line)) ){ int argc; char *argv[MAX_FIELDS]; if( ! reader_splitDoubleQuotedCommaSeparated(line, &argc, argv, MAX_FIELDS) ){ fprintf(stderr, "%s:%d: more than %d fields found\n", reader_getPath(in), reader_getLineNumber(in), MAX_FIELDS); return 0; } if( reader_getLineNumber(in) == 1 ){ if( ! foundExpectdHeaderFields(in, (char *[]){ /*00*/ "id", /*01*/ "ident", /*02*/ "type", /*03*/ "name", /*04*/ "latitude_deg", /*05*/ "longitude_deg", /*06*/ "elevation_ft", /*07*/ "continent", /*08*/ "iso_country", /*09*/ "iso_region", /*10*/ "municipality", /*11*/ "scheduled_service", /*12*/ "gps_code", /*13*/ "iata_code", /*14*/ "local_code", /*15*/ "home_link", /*16*/ "wikipedia_link", /*17*/ "keywords", NULL }, argc, argv) ) return 1; } // At if( argc < 7 ){ fprintf(stderr, "%s:%d: less than 7 fields in this record, so no elevation fro this airport\n", reader_getPath(in), reader_getLineNumber(in)); } // Empty id are silently ignored: char *id = argv[0]; if( strlen(id) == 0 ) continue; // Invalid elevation values assumed zero: double elevation; if( ! parseDouble(argv[6], &elevation) ) elevation = 0.0; // Deeper known airfield in this DB is the Bar Yehuda Airfield 31.33N 35.39E // at -1266 ft under the WGS-84 ellipsoid (roughly, under the sea level)! // So, -1300 seems a safe lower limit to check for; +24000 definitely too hight! if( !(-1300 <= elevation && elevation <= 24000) ){ fprintf(stderr, "%s:%d: airport elevation out of range: %g ft -- ignoring\n", reader_getPath(in), reader_getLineNumber(in), elevation); continue; } Airport *airport = hashtable_get(airports, id); if( airport != NULL ){ fprintf(stderr, "%s:%d: duplicated airport pk %s in line %d\n", reader_getPath(in), reader_getLineNumber(in), id, airport->line_no); } // Check if type of airport is operational, fixed-wings; int isAvailable = 1; if( strcmp(argv[2], "closed") == 0 || strcmp(argv[2], "heliport") == 0 || strcmp(argv[2], "balloonport") == 0 ){ isAvailable = 0; } else if( strcmp(argv[2], "small_airport") == 0 || strcmp(argv[2], "medium_airport") == 0 || strcmp(argv[2], "large_airport") == 0 || strcmp(argv[2], "seaplane_base") == 0 ){ isAvailable = 1; } else { isAvailable = 0; fprintf(stderr, "%s:%d: unknown airport type: %s -- ignoring\n", reader_getPath(in), reader_getLineNumber(in), argv[2]); } airport = memory_allocate(sizeof(Airport), NULL); airport->pk = memory_strdup(id); airport->line_no = reader_getLineNumber(in); airport->elevation = (int) round(elevation); airport->isAvailable = isAvailable; hashtable_put(airports, airport->pk, airport); /* if( reader_getLineNumber(in) <= 30 ){ printf("Line no. %d:\n", reader_getLineNumber(in)); int i; for(i = 0; i < argc; i++){ printf(" %d)%s", i, argv[i]); } printf("\n"); } */ } if( reader_getError(in) != NULL ){ fprintf(stderr, "%s:%d: %s\n", reader_getPath(in), reader_getLineNumber(in), reader_getError(in)); return 0; } memory_dispose(in); return 1; } static int parseRunways(char *path) { reader_Type *in = reader_new(path); char line[999]; while( reader_getLine(in, line, sizeof(line)) ){ int argc; char *argv[MAX_FIELDS]; if( ! reader_splitDoubleQuotedCommaSeparated(line, &argc, argv, MAX_FIELDS) ){ fprintf(stderr, "%s:%d: more than %d fields found\n", reader_getPath(in), reader_getLineNumber(in), MAX_FIELDS); return 0; } if( reader_getLineNumber(in) == 1 ){ if( ! foundExpectdHeaderFields(in, (char *[]){ /*00*/ "id", /*01*/ "airport_ref", /*02*/ "airport_ident", /*03*/ "length_ft", /*04*/ "width_ft", /*05*/ "surface", /*06*/ "lighted", /*07*/ "closed", /*08*/ "le_ident", /*09*/ "le_latitude_deg", /*10*/ "le_longitude_deg", /*11*/ "le_elevation_ft", /*12*/ "le_heading_degT", /*13*/ "le_displaced_threshold_ft", /*14*/ "he_ident", /*15*/ "he_latitude_deg", /*16*/ "he_longitude_deg", /*17*/ "he_elevation_ft", /*18*/ "he_heading_degT", /*19*/ "he_displaced_threshold_ft", NULL }, argc, argv) ) return 0; } else { if( argc < 17 ){ fprintf(stderr, "%s:%d: missing fields -- ignoring\n", reader_getPath(in), reader_getLineNumber(in)); continue; } // Most lat/lon are missing, we may safely silently ignore. if( argv[9][0] == 0 || argv[10][0] == 0 || argv[15][0] == 0 || argv[16][0] == 0 ) continue; double end1_lat; if( ! parseDouble(argv[9], &end1_lat) || !(-90 <= end1_lat && end1_lat <= 90) ){ fprintf(stderr, "%s:%d: invalid runway latitude: %s -- ignoring\n", reader_getPath(in), reader_getLineNumber(in), argv[9]); continue; } double end1_lon; if( ! parseDouble(argv[10], &end1_lon) || !(-180 <= end1_lon && end1_lon <= 180) ){ fprintf(stderr, "%s:%d: invalid runway longitude: %s -- ignoring\n", reader_getPath(in), reader_getLineNumber(in), argv[10]); continue; } double end2_lat; if( ! parseDouble(argv[15], &end2_lat) || !(-90 <= end2_lat && end2_lat <= 90) ){ fprintf(stderr, "%s:%d: invalid runway latitude: %s -- ignoring\n", reader_getPath(in), reader_getLineNumber(in), argv[15]); continue; } double end2_lon; if( ! parseDouble(argv[16], &end2_lon) || !(-180 <= end2_lon && end2_lon <= 180) ){ fprintf(stderr, "%s:%d: invalid runway longitude: %s -- ignoring\n", reader_getPath(in), reader_getLineNumber(in), argv[16]); continue; } end1_lat = units_DEGtoRAD(end1_lat); end1_lon = units_DEGtoRAD(end1_lon); end2_lat = units_DEGtoRAD(end2_lat); end2_lon = units_DEGtoRAD(end2_lon); // Detects N/S and W/E mismatches (there are some): if( fabs(end1_lat - end2_lat) > 1 ){ fprintf(stderr, "%s:%d: runway ends latitudes too far -- ignoring\n", reader_getPath(in), reader_getLineNumber(in)); continue; } if( fabs(end1_lon - end2_lon) * cos(end1_lat) > 1 ){ fprintf(stderr, "%s:%d: runway ends longitudes too far -- ignoring\n", reader_getPath(in), reader_getLineNumber(in)); continue; } // Ignore runway if middle point lies outside the range: double center_lat = (end1_lat + end2_lat)/2; double center_lon = (end1_lon + end2_lon)/2; if( !(lat_min <= center_lat && center_lat < lat_max && lon_min <= center_lon && center_lon < lon_max) ) continue; char *surface = argv[5]; // ACCEPT THESE SURFACES: if( memory_startsWith(surface, "CONC") || memory_startsWith(surface, "CON") || memory_startsWith(surface, "ASP") || memory_startsWith(surface, "Asphalt") || strcmp(surface, "asphalt") == 0 || strcmp(surface, "concrete") == 0 || strcmp(surface, "BIT") == 0 // bitumen? || strcmp(surface, "GRE") == 0 // ? || strcmp(surface, "GRS") == 0 // ? || strcmp(surface, "PEM") == 0 // ? ){ // SILENTLY REJECT THESE SURFACES: } else if( memory_startsWith(surface, "WATER") || memory_startsWith(surface, "TURF") || memory_startsWith(surface, "Turf") || memory_startsWith(surface, "DIRT") || strcmp(surface, "GRASS") == 0 || memory_startsWith(surface, "Grass") || strcmp(surface, "Gravel") == 0 || memory_startsWith(surface, "GRAVEL") || memory_startsWith(surface, "GRVL") || memory_startsWith(surface, "GVL") || strcmp(surface, "MATS") == 0 ){ continue; // ERROR ON ANY OTHER UNEXPECTED SURFACE TYPE: } else { fprintf(stderr, "%s:%d: unknown runway surface: %s -- ignoring\n", reader_getPath(in), reader_getLineNumber(in), surface); continue; } char *airport_ident = argv[2]; if( strlen(airport_ident) < 3 ){ fprintf(stderr, "%s:%d: airport code too short: %s -- ignoring\n", reader_getPath(in), reader_getLineNumber(in), airport_ident); continue; } if( strlen(airport_ident) > 4 ){ fprintf(stderr, "%s:%d: airport code too long: %s -- ignoring\n", reader_getPath(in), reader_getLineNumber(in), airport_ident); continue; } char *end1_id = argv[8]; if( strlen(end1_id) < 2 || strlen(end1_id) > 3 ){ fprintf(stderr, "%s:%d: invalid runway ID length: %s -- ignoring\n", reader_getPath(in), reader_getLineNumber(in), end1_id); continue; } char *end2_id = argv[14]; if( strlen(end2_id) < 2 || strlen(end2_id) > 3 ){ fprintf(stderr, "%s:%d: invalid runway ID length: %s -- ignoring\n", reader_getPath(in), reader_getLineNumber(in), end2_id); continue; } char stripe[8]; snprintf(stripe, sizeof(stripe), "%s/%s", end1_id, end2_id); int elevation = 0; char *airport_pk = argv[1]; Airport *airport = hashtable_get(airports, airport_pk); if( airport == NULL ){ fprintf(stderr, "%s:%d: airport pk %s not found in the airports file\n", reader_getPath(in), reader_getLineNumber(in), airport_pk); continue; } else if( ! airport->isAvailable ){ continue; } else { elevation = airport->elevation; } double length; if( ! parseDouble(argv[3], &length) ){ fprintf(stderr, "%s:%d: invalid runway length: %s -- ignoring\n", reader_getPath(in), reader_getLineNumber(in), argv[3]); continue; } double width; if( ! parseDouble(argv[4], &width) ){ fprintf(stderr, "%s:%d: invalid runway width: %s -- ignoring\n", reader_getPath(in), reader_getLineNumber(in), argv[4]); continue; } char lat1[99], lon1[99], lat2[99], lon2[99]; earth_latitudeToString(lat1, sizeof(lat1), end1_lat, earth_LLM_DMS); earth_longitudeToString(lon1, sizeof(lon1), end1_lon, earth_LLM_DMS); earth_latitudeToString(lat2, sizeof(lat2), end2_lat, earth_LLM_DMS); earth_longitudeToString(lon2, sizeof(lon2), end2_lon, earth_LLM_DMS); printf("RWY %-4s %-7s %4d %5.0f %3.0f %s %s %s %s\n", airport_ident, stripe, elevation, length, width, lat1, lon1, lat2, lon2); } /* if( reader_getLineNumber(in) <= 90 ){ printf("Line no. %d:\n", reader_getLineNumber(in)); int i; for(i = 0; i < argc; i++){ printf("/ *%02d* / \"%s\"\n", i, argv[i]); } } */ } if( reader_getError(in) != NULL ){ fprintf(stderr, "%s:%d: %s\n", reader_getPath(in), reader_getLineNumber(in), reader_getError(in)); return 0; } memory_dispose(in); return 1; } static int parseNavaids(char *path) { reader_Type *in = reader_new(path); char line[999]; while( reader_getLine(in, line, sizeof(line)) ){ int argc; char *argv[MAX_FIELDS]; if( ! reader_splitDoubleQuotedCommaSeparated(line, &argc, argv, MAX_FIELDS) ){ fprintf(stderr, "%s:%d: more than %d fields found\n", reader_getPath(in), reader_getLineNumber(in), MAX_FIELDS); return 0; } if( reader_getLineNumber(in) == 1 ){ if( ! foundExpectdHeaderFields(in, (char *[]){ /*00*/ "id", /*01*/ "filename", /*02*/ "ident", /*03*/ "name", /*04*/ "type", /*05*/ "frequency_khz", /*06*/ "latitude_deg", /*07*/ "longitude_deg", /*08*/ "elevation_ft", /*09*/ "iso_country", /*10*/ "dme_frequency_khz", /*11*/ "dme_channel", /*12*/ "dme_latitude_deg", /*13*/ "dme_longitude_deg", /*14*/ "dme_elevation_ft", /*15*/ "slaved_variation_deg", /*16*/ "magnetic_variation_deg", /*17*/ "usageType", /*18*/ "power", /*19*/ "associated_airport", NULL }, argc, argv) ) return 0; } else { if( argc < 14 ){ fprintf(stderr, "%s:%d: missing fields -- ignoring\n", reader_getPath(in), reader_getLineNumber(in)); continue; } // Most lat/lon are missing, we may safely silently ignore. if( argv[6][0] == 0 || argv[7][0] == 0 ) continue; double lat; if( ! parseDouble(argv[6], &lat) || !(-90 <= lat && lat <= 90) ){ fprintf(stderr, "%s:%d: invalid latitude: %s -- ignoring\n", reader_getPath(in), reader_getLineNumber(in), argv[6]); continue; } double lon; if( ! parseDouble(argv[7], &lon) || !(-180 <= lon && lon <= 180) ){ fprintf(stderr, "%s:%d: invalid longitude: %s -- ignoring\n", reader_getPath(in), reader_getLineNumber(in), argv[7]); continue; } lat = units_DEGtoRAD(lat); lon = units_DEGtoRAD(lon); if( !(lat_min <= lat && lat < lat_max && lon_min <= lon && lon < lon_max) ) continue; int mhz = 0; // 0=KHz, 1=MHz char *type = argv[4]; // ACCEPT THESE TYPES: if( strcmp(type, "VORTAC") == 0 || strcmp(type, "TACAN") == 0 || strcmp(type, "DME") == 0 || strcmp(type, "VOR") == 0 ){ mhz = 1; } else if( strcmp(type, "NDB") == 0 ){ mhz = 0; } else if( strcmp(type, "NDB-DME") == 0 ){ // No support for NDB/DME under ACM, sorry. type = "NDB"; mhz = 0; } else if( strcmp(type, "NDB-DME") == 0 ){ // No support for NDB/DME under ACM, sorry. type = "NDB"; mhz = 0; } else if( strcmp(type, "VOR-DME") == 0 ){ type = "VOR/DME"; mhz = 1; // SILENTLY REJECT THESE TYPES: } else if( memory_startsWith(type, "xxxxx") ){ continue; // ERROR ON ANY OTHER UNEXPECTED NAVAID TYPE: } else { fprintf(stderr, "%s:%d: unknown NAVAID type: %s -- ignoring\n", reader_getPath(in), reader_getLineNumber(in), type); continue; } char *name = argv[2]; if( strlen(name) < 2 ){ fprintf(stderr, "%s:%d: NAVAID name too short: %s -- ignoring\n", reader_getPath(in), reader_getLineNumber(in), name); continue; } if( strlen(name) > 4 ){ fprintf(stderr, "%s:%d: NAVAID name too long: %s -- ignoring\n", reader_getPath(in), reader_getLineNumber(in), name); continue; } long freq_khz; if( ! parseLong(argv[5], &freq_khz) ){ fprintf(stderr, "%s:%d: failed to parse NAVAID frequency as an integral number of KHz: %s -- ignoring\n", reader_getPath(in), reader_getLineNumber(in), argv[5]); continue; } char freq[9]; if( mhz ){ if( !(108000 <= freq_khz && freq_khz <= 117950) ){ fprintf(stderr, "%s:%d: DME or VOR frequency out of the range [108000,117950] KHz: %ld -- ignoring\n", reader_getPath(in), reader_getLineNumber(in), freq_khz); continue; } if( (freq_khz % 50) != 0 ){ fprintf(stderr, "%s:%d: invalid DME or VOR frequency, expected multiple of 50 KHz: %ld -- ignoring\n", reader_getPath(in), reader_getLineNumber(in), freq_khz); continue; } snprintf(freq, sizeof(freq), "%.2f", freq_khz / 1000.0); } else { if( !(200 <= freq_khz && freq_khz <= 529) ){ fprintf(stderr, "%s:%d: NDB frequency out of the range [200,529] KHz: %ld -- ignoring\n", reader_getPath(in), reader_getLineNumber(in), freq_khz); continue; } snprintf(freq, sizeof(freq), "%ld", freq_khz); } double elevation; if( argv[8][0] == 0 ){ // Most altitudes are blank. Silently set zero. elevation = 0; } else if( ! parseDouble(argv[8], &elevation) ){ fprintf(stderr, "%s:%d: cannot parse NAVAID altitude: %s -- assuming zero\n", reader_getPath(in), reader_getLineNumber(in), argv[8]); elevation = 0; } char lat_s[99], lon_s[99]; earth_latitudeToString(lat_s, sizeof(lat_s), lat, earth_LLM_DMS); earth_longitudeToString(lon_s, sizeof(lon_s), lon, earth_LLM_DMS); printf("NAV %-4s %-7s %s %s %4.0f %6s -\n", name, type, lat_s, lon_s, elevation, freq); } /* if( reader_getLineNumber(in) <= 9 ){ printf("Line no. %d:\n", reader_getLineNumber(in)); int i; for(i = 0; i < argc; i++){ printf(" %d)%s", i, argv[i]); } printf("\n"); } */ } if( reader_getError(in) != NULL ){ fprintf(stderr, "%s:%d: %s\n", reader_getPath(in), reader_getLineNumber(in), reader_getError(in)); return 0; } memory_dispose(in); return 1; } static void help() { puts( "This program parses the ourairports.com data base in its textual format and generates\n" "an ACM scenery. The ourairports-com data base can be downloaded from\n" "https://ourairports.com\n" "Download the airports.csv, runways.csv and navaids.csv files in a folder,\n" "then start this program with the following command line parameters:\n" "\n" " --lat-min DEG Minimum latitude, default 90S.\n" " --lat-max DEG Maximum latitude, default 90N.\n" " --lon-min DEG Minimum longitude, default 180W.\n" " --lon-max DEG maximum longitude, default 180E.\n" " --src-dir PATH Path to the directory of the data base CSV files,\n" " default . (current directory).\n" "\n" "The program collects all the runways and NAVAID in the given range of\n" "latitude and longitude and writes the scenery on standard output; errors and\n" "warnings are sent to standard error. Only the RWY and NAV records\n" "are generated. You may want to add the TEAM1_LOC, TEAM2_LOC and GROUND_COLOR\n" "records to complete the scenery; ILS must be added by hand, sorry.\n" ); } int main(int argc, char** argv) { error_init(argv[0]); char *src_dir = "."; int i = 1; while( i < argc ){ char *a = argv[i]; char *v = i < argc? argv[i+1] : NULL; if( strcmp(a, "--help") == 0 || strcmp(a, "-h") == 0 ){ help(); return 0; } else if( strcmp(a, "--lat-min") == 0 && v != NULL ){ if( ! earth_parseLatitude(v, &lat_min) ) error_external("invalid latitude: %s", v); i += 2; } else if( strcmp(a, "--lat-max") == 0 && v != NULL ){ if( ! earth_parseLatitude(v, &lat_max) ) error_external("invalid latitude: %s", v); i += 2; } else if( strcmp(a, "--lon-min") == 0 && v != NULL ){ if( ! earth_parseLongitude(v, &lon_min) ) error_external("invalid longitude: %s", v); i += 2; } else if( strcmp(a, "--lon-max") == 0 && v != NULL ){ if( ! earth_parseLongitude(v, &lon_max) ) error_external("invalid longitude: %s", v); i += 2; } else if( strcmp(a, "--src-dir") == 0 && v != NULL ){ src_dir = v; i += 2; } else { error_external("unknown option/value: %s", a); } } if( !(lat_min < lat_max && lon_min < lon_max) ) error_external("invalid latitude [%g,%g[ DEG or longitude [%g,%g[ DEG ranges", units_RADtoDEG(lat_min), units_RADtoDEG(lat_max), units_RADtoDEG(lon_min), units_RADtoDEG(lon_max)); char path[999]; snprintf(path, sizeof(path), "%s/airports.csv", src_dir); if( ! parseAirports(path) ) return 1; snprintf(path, sizeof(path), "%s/runways.csv", src_dir); if( ! parseRunways(path) ) return 1; snprintf(path, sizeof(path), "%s/navaids.csv", src_dir); if( ! parseNavaids(path) ) return 1; return 0; } acm-6.0_20200416/tools/ourairports_com/Makefile0000644000000000000000000000226313200762346017630 0ustar rootroot# This file generated by make-makefile, do not edit! # Create Makefile-include.txt instead for your customizations. CC := gcc CFLAGS := -Wall -Werror -g -fmax-errors=99 -Wuninitialized -Wmissing-prototypes -Wredundant-decls LIBS := .PHONY: all all: make ourairports_com.exe #include Makefile-include.txt .PHONY: test test: ourairports_com.exe ./ourairports_com.exe .PHONY: clean clean: rm -f *.o *.exe *.stackdump ourairports_com ourairports_com.o: ourairports_com.c ../../src/V/Vlibmath.h ../../src/dis/dis/earth.h ../../src/util/error.h ../../src/util/hashtable.h ../../src/util/memory.h ../../src/util/reader.h ../../src/util/units.h $(CC) $(CFLAGS) -c ourairports_com.c -o ourairports_com.o ourairports_com.exe: ../../src/V/Vlibmath.o ../../src/dis/dis/earth.o ../../src/util/error.o ../../src/util/hashtable.o ../../src/util/memory.o ../../src/util/reader.o ../../src/util/units.o ourairports_com.o $(CC) $(CFLAGS) -o ourairports_com.exe ../../src/V/Vlibmath.o ../../src/dis/dis/earth.o ../../src/util/error.o ../../src/util/hashtable.o ../../src/util/memory.o ../../src/util/reader.o ../../src/util/units.o ourairports_com.o $(LIBS) -lm # Checksum of the original file: 4182609461 acm-6.0_20200416/tools/ourairports_com/make-zones.sh0000644000000000000000000002365113203342354020575 0ustar rootroot#!/bin/bash # Creates several zones and charts from the ourairports.com data base. # ILS are missing from that data base; some have been added using the # tools/create-ils.exe program and then completed by hand for some selected # major airport. # Destination dir. of the creates sceneries: ZONES_DIR=../../objects/zones # Destination dir. of the created charts: CHARTS_DIR=../../doc/charts # WMM coefficients: WMM_COF=../../objects/WMM.COF # Creates a scenery for the given range of geographical coordinates. function create_zone() { local scenery title lat_min lat_max lon_min lon_max scenery=$1 title=$2 lat_min=$3 lat_max=$4 lon_min=$5 lon_max=$6 echo "Generating zone $dst ..." { echo "# $title." echo "# Created: " $(date +%Y-%m-%d) echo "# Latitude range: [$lat_min, $lat_max[" echo "# Longitude range: [$lon_min, $lon_max[" echo "# 2017-11-01 Source: http://ourairports.com" echo echo "GROUND_COLOR #305030" echo ./ourairports_com.exe \ --lat-min $lat_min \ --lat-max $lat_max \ --lon-min $lon_min \ --lon-max $lon_max \ --src-dir ../../../ourairports.com } > $scenery } # Generates PDF of a navigation chart. # Parameters: # $1: scenery file. # $2: destination PDF file name without extension. # $3: title. # $4: central latitude. # $5: central longitude. # $6: scale. # $7, $8, $9: optional further parameters for the chart.exe program. function doChart { local dst dst=$2 echo "Generating chart $dst.pdf ..." ../chart/chart.exe --wmm-cof $WMM_COF \ --scene "$1" \ --title "$3" \ --olat $4 \ --olon $5 \ --scale $6 \ $7 $8 $9 > $dst.ps || exit 1 ps2pdf -sPAPERSIZE=a4 $dst.ps $dst.pdf || exit 1 rm $dst.ps } function france() { locale scenery dst scenery=$ZONES_DIR/europe/france.txt create_zone $scenery "France zone" 42N 50N 005W 006E { echo "# Paris, Charles De Gaulle (LFPG):" echo "ILS 08L ILS GLE 108.70 48-59-56.47N 002-36-51.36E 48-59-41.31N 002-33-09.34E 387 5 85.3 3" echo "ILS 26R ILS GAU 109.10 48-59-43.72N 002-32-55.15E 48-59-58.89N 002-36-37.18E 397 5 265.3 3" echo "ILS 08R ILS/DME DSE 108.55 48-59-42.44N 002-36-23.46E 48-59-31.23N 002-33-55.86E 387 5 85.3 3" echo "ILS 26L ILS/DME DSU 108.35 48-59-33.64N 002-33-41.67E 48-59-44.85N 002-36-09.28E 397 5 265.3 3" echo "ILS 09L ILS/DME PNE 109.35 49-01-36.92N 002-33-56.80E 49-01-25.71N 002-31-29.08E 387 5 85.3 3" echo "ILS 27R ILS/DME PNW 110.35 49-01-28.12N 002-31-14.88E 49-01-39.33N 002-33-42.61E 397 5 265.3 3" echo "ILS 09R ILS/DME CGE 110.10 49-01-26.11N 002-34-27.76E 49-01-10.95N 002-30-46.50E 387 5 85.3 3" echo "ILS 27L ILS/DME PNW 110.35 49-01-13.36N 002-30-32.31E 49-01-28.53N 002-34-13.57E 397 5 265.3 3" echo "# Paris, Le Bourget (LFPB):" echo "ILS 07 ILS/DME LBG 109.50 48-58-30.07N 002-27-43.36E 48-57-46.72N 002-25-11.45E 193 5 67.8 3" echo "ILS 25 ILS LBW 111.10 48-57-46.01N 002-24-59.39E 48-58-29.35N 002-27-31.30E 243 5 247.8 3" echo "ILS 27 ILS/DME RGE 110.55 48-57-48.50N 002-24-58.74E 48-57-57.57N 002-26-44.79E 224 5 265.2 3" echo "# Paris, Orly (LFPO):" echo "ILS 02 ILS OLN 110.30 48-44-26.02N 002-23-17.71E 48-43-02.08N 002-22-32.57E 228 5 18.3 3" echo "ILS 06 ILS/DME ORE 108.50 48-44-12.38N 002-21-51.40E 48-43-09.19N 002-18-59.00E 260 5 61.9 3" echo "ILS 24 ILS/DME OLO 110.90 48-43-07.41N 002-18-47.97E 48-44-10.60N 002-21-40.36E 322 5 241.8 3" echo "ILS 08 LOCALIZER OLE 108.15 48-43-41.24N 002-24-21.59E 48-43-06.75N 002-21-29.74E 273 5 74.5 3" echo "ILS 26 ILS/DME OLW 111.75 48-43-07.24N 002-21-16.78E 48-43-41.73N 002-24-08.63E 309 5 254.4 3" } >> $scenery local src dst src=$ZONES_DIR/europe/france.txt dst=$CHARTS_DIR/europe/france # Navigation charts: doChart $src $dst/france-nw "France North-West area" 49N 002-30E 500000 --no-ils doChart $src $dst/france-ne "France North-East area" 48N 004-30E 1500000 --no-ils doChart $src $dst/france-sw "France South-West area" 44N 004E 1500000 --no-ils doChart $src $dst/france-se "France South-East area" 44N 005E 1000000 --no-ils doChart $src $dst/paris Paris/France 48-55N 002-20E 250000 doChart $src $dst/degaulle "Paris, De Gaulle" 49-01N 002-34E 100000 doChart $src $dst/lebourget "Paris, Le Bourget" 49-00N 002-28E 100000 } function germany() { create_zone $ZONES_DIR/europe/germany.txt "Germany zone" 47N 55N 006E 015E { echo "# Dusseldorf (EDDL):" echo "ILS 05L ILS/DME IDNE 110.95 51-18-00.10N 006-46-59.08E 51-16-58.94N 006-44-52.49E 109 5 52.9 3" echo "ILS 23R ILS/DME IDNW 109.30 51-16-55.45N 006-44-43.06E 51-17-56.62N 006-46-49.64E 185 5 232.8 3" echo "ILS 05R ILS/DME IDSE 111.50 51-17-51.11N 006-47-22.72E 51-16-44.18N 006-45-04.26E 109 5 52.8 3" echo "ILS 23L ILS/DME IDSW 109.90 51-16-40.69N 006-44-54.84E 51-17-47.62N 006-47-13.29E 185 5 232.8 3" echo "# Frankfurt (EDDF):" echo "ILS 07C ILS/DME IFCE 110.55 50-02-45.73N 008-35-27.27E 50-01-54.49N 008-32-02.65E 342 5 69.7 3" echo "ILS 25C ILS/DME IFCW 111.55 50-01-53.98N 008-31-50.54E 50-02-45.23N 008-35-15.16E 386 5 249.6 3" echo "ILS 07L ILS/DME IFNE 111.75 50-02-48.24N 008-32-15.54E 50-02-10.68N 008-29-47.48E 342 5 69.8 3" echo "ILS 25R ILS/DME IFNW 111.35 50-02-10.20N 008-29-35.35E 50-02-47.76N 008-32-03.41E 386 5 249.7 3" echo "ILS 07R ILS/DME IFSE 110.95 50-02-27.75N 008-35-25.63E 50-01-36.13N 008-32-00.98E 342 5 69.5 3" echo "ILS 25L ILS/DME IFSW 111.15 50-01-35.60N 008-31-48.89E 50-02-27.23N 008-35-13.55E 387 5 249.5 3" echo "# Munich (EDDM):" echo "ILS 08L ILS/DME IMNE 109.50 48-22-01.94N 011-49-30.80E 48-21-42.99N 011-46-01.97E 1479 5 83.5 3" echo "ILS 26R ILS/DME IMNW 108.70 48-21-44.97N 011-45-48.88E 48-22-03.93N 011-49-17.71E 1495 5 263.4 3" echo "ILS 08R ILS/DME IMSE 109.30 48-20-42.38N 011-48-31.03E 48-20-23.43N 011-45-02.21E 1479 5 83.5 3" echo "ILS 26L ILS/DME IMSW 108.30 48-20-25.41N 011-44-49.13E 48-20-44.37N 011-48-17.95E 1495 5 263.4 3" } >> $ZONES_DIR/europe/germany.txt local src dst src=$ZONES_DIR/europe/germany.txt dst=$CHARTS_DIR/europe/germany # Navigation charts: doChart $src $dst/frankfurt "Frankfurt area" 50-02N 008-31E 250000 doChart $src $dst/munich "Munich area" 48-20N 011-50E 250000 doChart $src $dst/dusseldorf "Dusseldorf area" 51-17N 006-44E 250000 } function spain() { locale zone zone=$ZONES_DIR/europe/spain.txt create_zone $zone "Spain zone" 35N 42N 010W 006E { # LEMD: echo "ILS 32R ILS/DME MBB 109.10 40-29-49.32N 003-33-36.14W 40-28-13.88N 003-31-59.62W 1938 5 322.2 3" echo "ILS 32L ILS/DME MAA 109.90 40-29-13.32N 003-34-41.44W 40-27-22.40N 003-32-49.30W 1938 5 322.2 3" echo "ILS 18L ILS/DME IML 111.50 40-29-54.24N 003-33-33.11W 40-31-57.48N 003-33-31.01W 2074 5 179.8 3" echo "ILS 18R ILS/DME IMR 110.70 40-29-23.64N 003-34-28.62W 40-31-54.60N 003-34-26.71W 2074 5 179.8 3" # LEBL: echo "ILS 02 ILS/DME BLT 108.75 41-18-43.03N 002-05-45.16E 41-17-15.10N 002-05-02.69E 59 5 19.0 3" echo "ILS 07L ILS/DME QAA 110.30 41-18-24.53N 002-06-25.18E 41-17-30.08N 002-03-53.09E 19 5 65.6 3" echo "ILS 25R ILS/DME BCA 109.50 41-17-28.98N 002-03-42.66E 41-18-23.44N 002-06-14.74E 43 5 245.6 3" echo "ILS 07R ILS/DME BLE 110.75 41-17-35.94N 002-06-23.55E 41-16-53.36N 002-04-26.35E 19 5 65.6 3" echo "ILS 25L ILS/DME BLW 111.50 41-16-52.26N 002-04-15.92E 41-17-34.84N 002-06-13.12E 43 5 245.6 3" # LEPA: echo "ILS 06L ILS/DME PLM 110.90 39-33-50.08N 002-44-46.20E 39-32-46.85N 002-42-37.07E 13 5 58.5 3" echo "ILS 24R ILS PAA 109.90 39-32-44.48N 002-42-27.92E 39-33-47.71N 002-44-37.04E 67 5 238.5 3" echo "ILS 24L ILS/DME IPAL 109.30 39-32-23.63N 002-43-43.52E 39-33-21.80N 002-45-43.06E 67 5 238.7 3" # LEMG: echo "ILS 13 ILS/DME GMM 109.50 36-39-48.99N 004-28-59.91W 36-41-01.88N 004-30-43.49W 106 5 131.5 3" echo "ILS 31 ILS/DME GAA 109.90 36-41-10.65N 004-30-54.37W 36-39-57.76N 004-29-10.77W 0 5 311.5 3" } >> $zone # Navigation charts: local dst dst=$CHARTS_DIR/europe/spain doChart $zone $dst/madrid-barajas "Madrid, Barajas (LEMD)" 40-29N 003-33W 250000 doChart $zone $dst/barcelona-elprat "Barcelona, El Prat (LEBL)" 41-17N 002-05E 250000 doChart $zone $dst/palmademallorca "Palma de Mallorca (LEPA)" 39-33N 002-44E 250000 doChart $zone $dst/malaga "Malaga (LEMG)" 36-40N 004-30W 250000 } function united_kingdom() { create_zone $ZONES_DIR/europe/united-kingdom.txt "United Kingdom zone" 50N 60N 010W 002E { echo "# Heathrow (EGLL):" echo "ILS 09L ILS/DME IAA 110.30 51-28-39.77N 000-25-44.21W 51-28-35.76N 000-29-21.92W 83 5 89.7 3" echo "ILS 27R ILS/DME IRR 110.30 51-28-38.94N 000-29-37.48W 51-28-42.96N 000-25-59.76W 83 5 269.7 3" echo "ILS 09R ILS/DME IBB 109.50 51-27-54.03N 000-25-47.13W 51-27-50.40N 000-29-12.35W 83 5 89.8 3" echo "ILS 27L ILS/DME ILL 109.50 51-27-53.61N 000-29-27.92W 51-27-57.24N 000-26-02.70W 83 5 269.8 3" echo "# Gatwick (EGKK):" echo "ILS 08R ILS IGG 110.90 51-09-06.40N 000-09-50.41W 51-08-39.20N 000-12-45.17W 189 5 77.6 3" echo "ILS 26L ILS IWW 110.90 51-08-40.27N 000-12-59.40W 51-09-07.48N 000-10-04.64W 215 5 257.6 3" echo "# Manchester (EGCC):" echo "ILS 05L ILS/DME IMM 108.50 53-21-50.76N 002-15-13.11W 53-20-39.78N 002-17-36.42W 219 5 50.9 3" echo "ILS 23R ILS/DME INN 109.50 53-20-36.24N 002-17-46.44W 53-21-47.21N 002-15-23.13W 295 5 230.9 3" echo "ILS 05R ILS/DME IMC 111.55 53-21-02.82N 002-16-17.30W 53-19-52.61N 002-18-40.92W 220 5 51.3 3" echo "# Stansted (EGSS):" echo "ILS 04 ILS ISED 110.50 51-53-49.84N 000-15-10.83E 51-52-28.17N 000-13-08.70E 303 5 42.9 3" echo "ILS 22 ILS ISX 110.50 51-52-23.24N 000-13-01.07E 51-53-44.91N 000-15-03.19E 393 5 222.8 3" } >> $ZONES_DIR/europe/united-kingdom.txt local src dst src=$ZONES_DIR/europe/united-kingdom.txt dst=$CHARTS_DIR/europe/united-kingdom # Navigation charts: doChart $src $dst/Heathrow London/Heathrow 51-28N 000-28W 250000 doChart $src $dst/Gatwick London/Gatwick 51-08N 000-12W 250000 doChart $src $dst/Stansted London/Stansted 51-53N 000-15E 250000 doChart $src $dst/Manchester London/Manchester 53-20N 002-20W 250000 } france germany spain united_kingdom acm-6.0_20200416/test/0000755000000000000000000000000013175062144012555 5ustar rootrootacm-6.0_20200416/test/acm/0000755000000000000000000000000013175062144013315 5ustar rootrootacm-6.0_20200416/test/acm/astro-test.c0000644000000000000000000002155713173770000015573 0ustar rootroot#include #include #include #include "../../src/acm/astro.h" #include "../../src/dis/dis/earth.h" #include "../../src/util/units.h" // Max err on Sun lat and lon (DEG): #define LAT_ERR_MAX 0.1 #define LON_ERR_MAX 0.2 static int err; /** * Evaluates Sun ephemeris. * @param line Caller line number for error reporting. * @param date Ephemeris date (ISO 8601 format). * @param exp_latlon Expected latitude and longitude (usual ACM formats). */ static void test_getSun(int line, char *date, char *exp_latlon) { // Parse expected values: zulu_Date date_zulu; if( ! zulu_dateParse(date, &date_zulu) ){ fprintf(stderr, "%d: invalid date: %s\n", line, date); err++; return; } earth_LatLonAlt exp_sun_w; if( ! earth_parseLatLon(exp_latlon, &exp_sun_w) ){ fprintf(stderr, "%d: invalid latitude or longitude: %s\n", line, exp_latlon); err++; return; } // Init astro module: astro_init(0, &date_zulu); VPoint got_sun_xyz; // Calculate Sun ephemeris: astro_getSun(0, &got_sun_xyz); earth_LatLonAlt got_sun_w; // FIXME: earth_XYZToLatLonAlt() returns NaN for large dists! // Workaround with a bit of precision loss: /* double scale = 3*earth_MAJOR / VMagnitude(&got_sun_xyz); VPoint scaled = got_sun_xyz; scaled.x *= scale; scaled.y *= scale; scaled.z *= scale; earth_XYZToLatLonAlt(&scaled, &got_sun_w); */ /* * Workaround: for very distant points, bare atan() work well enough: */ got_sun_w.latitude = earth_normalizeLatitude( atan(got_sun_xyz.z / sqrt(got_sun_xyz.x * got_sun_xyz.x + got_sun_xyz.y * got_sun_xyz.y)) ); got_sun_w.longitude = earth_normalizeLongitude( atan2(got_sun_xyz.y, got_sun_xyz.x) ); got_sun_w.z = 0; // Compare vs. expected Sun ephemeris: double lat_err_deg = units_RADtoDEG(got_sun_w.latitude - exp_sun_w.latitude); double lon_err_deg = units_RADtoDEG(got_sun_w.longitude - exp_sun_w.longitude); if( lon_err_deg > 180 ) lon_err_deg = 360 - lon_err_deg; if( lon_err_deg < -180 ) lon_err_deg = 360 + lon_err_deg; if( fabs(lat_err_deg) > LAT_ERR_MAX || fabs(lon_err_deg) > LON_ERR_MAX ){ err++; char date_zulu_s[20]; zulu_dateFormat(&date_zulu, date_zulu_s, sizeof(date_zulu_s)); fprintf(stderr, "%d: Sun ephemeris for %s:\n", line, date_zulu_s); char s[99], t[99]; fprintf(stderr, "\texp %s %s\n", earth_latitudeToString(s, sizeof(s), exp_sun_w.latitude, earth_LLM_DMS), earth_longitudeToString(t, sizeof(t), exp_sun_w.longitude, earth_LLM_DMS)); //fprintf(stderr, "\texp %g %g\n", exp_sun_w.latitude, exp_sun_w.longitude); fprintf(stderr, "\tgot %s %s (err %.02g DEG, %.02g DEG)\n", earth_latitudeToString(s, sizeof(s), got_sun_w.latitude, earth_LLM_DMS), earth_longitudeToString(t, sizeof(t), got_sun_w.longitude, earth_LLM_DMS), lat_err_deg, lon_err_deg); //fprintf(stderr, "\t cartesian: %g, %g, %g\n", // got_sun_xyz.x, got_sun_xyz.y, got_sun_xyz.z); } } int main(int argc, char** argv) { // Source: ALMANACCO NAUTICO - ITALIAN EPHEMERIDES AND NAUTICAL YEARBOOK // 2010 - Ulisse Quadri, Bassano Bresciano Astronomical Observatory test_getSun(__LINE__, "2010-01-01T00:00", "23-01-36S 179-10-30W"); test_getSun(__LINE__, "2010-01-01T06:00", "23-00-24S 090-51-18E"); test_getSun(__LINE__, "2010-01-01T12:00", "22-59-12S 000-53-01E"); test_getSun(__LINE__, "2010-01-01T18:00", "22-57-54S 089-05-12W"); test_getSun(__LINE__, "2010-04-01T00:00", "04-24-54N 178-59-30W"); test_getSun(__LINE__, "2010-04-01T06:00", "04-30-42N 090-59-24E"); test_getSun(__LINE__, "2010-04-01T12:00", "04-36-30N 000-58-18E"); test_getSun(__LINE__, "2010-04-01T18:00", "04-42-18N 089-02-48W"); test_getSun(__LINE__, "2010-07-01T00:00", "23-07-42N 179-03-48W"); test_getSun(__LINE__, "2010-07-01T06:00", "23-06-42N 090-56-54E"); test_getSun(__LINE__, "2010-07-01T12:00", "23-05-42N 000-57-36E"); test_getSun(__LINE__, "2010-07-01T18:00", "23-04-36N 089-01-42W"); test_getSun(__LINE__, "2010-10-01T00:00", "03-03-42S 177-27-42E"); test_getSun(__LINE__, "2010-10-01T06:00", "03-09-30S 087-26-30E"); test_getSun(__LINE__, "2010-10-01T12:00", "03-15-18S 002-34-42W"); test_getSun(__LINE__, "2010-10-01T18:00", "03-21-06S 092-35-54W"); test_getSun(__LINE__, "2010-12-31T00:00", "23-07-12S 179-19-30W"); test_getSun(__LINE__, "2010-12-31T06:00", "23-06-06S 090-42-18E"); test_getSun(__LINE__, "2010-12-31T12:00", "23-05-00S 000-44-06E"); test_getSun(__LINE__, "2010-12-31T18:00", "23-03-54S 089-14-06W"); // Source: https://www.thenauticalalmanac.com/ from here on: test_getSun(__LINE__, "2017-01-01T00:00", "22-59-54S 179-08-24W"); test_getSun(__LINE__, "2017-01-01T06:00", "22-58-42S 090-53-24E"); test_getSun(__LINE__, "2017-01-01T12:00", "22-57-24S 000-55-12E"); test_getSun(__LINE__, "2017-02-01T00:00", "17-06-12S 176-37-00W"); test_getSun(__LINE__, "2017-02-01T06:00", "17-01-54S 093-23-30E"); test_getSun(__LINE__, "2017-02-01T12:00", "16-57-36S 003-24-00E"); test_getSun(__LINE__, "2017-03-01T00:00", "07-35-42S 176-54-18W"); test_getSun(__LINE__, "2017-03-01T06:00", "07-30-00S 093-05-00E"); test_getSun(__LINE__, "2017-03-20T10:00", "00-00-30S 031-51-18E"); test_getSun(__LINE__, "2017-03-21T12:00", "00-25-12N 001-46-30E"); test_getSun(__LINE__, "2017-04-01T00:00", "04-31-48N 179-00-42W"); test_getSun(__LINE__, "2017-04-01T06:00", "04-37-36N 090-58-12E"); test_getSun(__LINE__, "2017-04-01T12:00", "04-43-24N 000-52-36E"); test_getSun(__LINE__, "2017-05-01T00:00", "15-04-00N 179-16-54E"); test_getSun(__LINE__, "2017-05-01T06:00", "15-08-36N 089-10-24E"); test_getSun(__LINE__, "2017-05-01T12:00", "15-13-06N 000-44-00W"); test_getSun(__LINE__, "2017-06-01T00:00", "22-02-48N 179-26-48E"); test_getSun(__LINE__, "2017-06-01T06:00", "22-04-48N 089-27-24E"); test_getSun(__LINE__, "2017-06-21T04:24", "23-26-06N 114-26-08E"); test_getSun(__LINE__, "2017-06-21T12:00", "23-26-00N 000-27-18E"); test_getSun(__LINE__, "2017-07-01T00:00", "23-06-12N 179-02-48W"); test_getSun(__LINE__, "2017-07-01T06:00", "23-05-12N 090-57-54E"); test_getSun(__LINE__, "2017-07-01T12:00", "23-04-12N 000-58-36E"); test_getSun(__LINE__, "2017-08-01T00:00", "18-01-00N 178-24-42W"); test_getSun(__LINE__, "2017-08-01T06:00", "17-57-12N 091-35-06E"); test_getSun(__LINE__, "2017-08-01T12:00", "17-53-24N 001-34-48E"); test_getSun(__LINE__, "2017-09-01T00:00", "08-17-06N 179-58-36W"); test_getSun(__LINE__, "2017-09-01T06:00", "08-11-42N 090-00-12E"); test_getSun(__LINE__, "2017-09-01T12:00", "08-06-12N 000-01-00W"); test_getSun(__LINE__, "2017-09-21T12:00", "00-31-12N 001-45-06W"); test_getSun(__LINE__, "2017-09-22T20:00", "00-00-00N 121-52-06W"); test_getSun(__LINE__, "2017-10-01T00:00", "03-10-36S 177-26-24E"); test_getSun(__LINE__, "2017-10-01T06:00", "03-16-24S 087-25-12E"); test_getSun(__LINE__, "2017-10-01T12:00", "03-22-12S 002-36-00W"); // Whole 2017-10-23 day: test_getSun(__LINE__, "2017-10-23T00:00", "11-23-24S 176-05-42E"); test_getSun(__LINE__, "2017-10-23T01:00", "11-24-18S 161-05-36E"); test_getSun(__LINE__, "2017-10-23T02:00", "11-25-12S 146-05-30E"); test_getSun(__LINE__, "2017-10-23T03:00", "11-26-00S 131-05-24E"); test_getSun(__LINE__, "2017-10-23T04:00", "11-26-54S 116-05-36E"); test_getSun(__LINE__, "2017-10-23T05:00", "11-27-48S 101-05-18E"); test_getSun(__LINE__, "2017-10-23T06:00", "11-28-42S 086-05-12E"); test_getSun(__LINE__, "2017-10-23T07:00", "11-29-30S 071-05-06E"); test_getSun(__LINE__, "2017-10-23T08:00", "11-30-24S 056-05-00E"); test_getSun(__LINE__, "2017-10-23T09:00", "11-31-18S 041-04-54E"); test_getSun(__LINE__, "2017-10-23T10:00", "11-32-12S 026-04-48E"); test_getSun(__LINE__, "2017-10-23T11:00", "11-33-00S 011-04-48E"); test_getSun(__LINE__, "2017-10-23T12:00", "11-33-54S 003-55-18W"); test_getSun(__LINE__, "2017-10-23T13:00", "11-34-48S 018-55-24W"); test_getSun(__LINE__, "2017-10-23T14:00", "11-35-42S 033-55-30W"); test_getSun(__LINE__, "2017-10-23T15:00", "11-36-30S 048-55-36W"); test_getSun(__LINE__, "2017-10-23T16:00", "11-37-24S 063-55-42W"); test_getSun(__LINE__, "2017-10-23T17:00", "11-38-18S 078-55-42W"); test_getSun(__LINE__, "2017-10-23T18:00", "11-39-06S 093-55-48W"); test_getSun(__LINE__, "2017-10-23T19:00", "11-40-00S 108-55-54W"); test_getSun(__LINE__, "2017-10-23T20:00", "11-40-54S 123-56-00W"); test_getSun(__LINE__, "2017-10-23T21:00", "11-41-48S 138-56-06W"); test_getSun(__LINE__, "2017-10-23T22:00", "11-42-36S 153-56-12W"); test_getSun(__LINE__, "2017-10-23T23:00", "11-43-30S 168-56-12W"); test_getSun(__LINE__, "2017-11-01T00:00", "14-25-00S 175-54-06E"); test_getSun(__LINE__, "2017-11-01T06:00", "14-29-48S 085-54-00E"); test_getSun(__LINE__, "2017-11-01T12:00", "14-34-36S 004-06-06W"); test_getSun(__LINE__, "2017-12-01T00:00", "21-47-30S 177-13-54E"); test_getSun(__LINE__, "2017-12-01T06:00", "21-49-48S 087-15-18E"); test_getSun(__LINE__, "2017-12-01T12:00", "21-52-06S 002-43-18W"); test_getSun(__LINE__, "2017-12-21T12:00", "23-26-06S 000-27-12W"); test_getSun(__LINE__, "2017-12-21T16:00", "23-26-06S 060-26-00W"); return err==0? 0 : 1; } acm-6.0_20200416/test/acm/dis_if-test.c0000644000000000000000000001761013154073366015705 0ustar rootroot/* * Copyright (C) 1995 Mats Lofkvist CelsiusTech Electronics AB * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /* FIXME: what this test program should do? */ #include #include #include #include #include #include #include "../../src/acm/dis_if.h" #include "../../src/acm/pm.h" #include "../../src/util/units.h" #define REALTIME #define ABSOLUTETIME #define DT 0.05 #define RSKIP 10 #define MAX_ENTITY 256 #ifndef DEVICE #define DEVICE "le0" #endif static double sysTime(void) { struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec + tv.tv_usec / 1000000.0; } #ifdef SOL2 #include #include #include void usleep(unsigned useconds) { struct timeval tv; fd_set myset; int seconds; seconds = 0; while (useconds >= 1000000) { seconds++; useconds -= 1000000; } tv.tv_sec = seconds; tv.tv_usec = useconds; FD_ZERO(&myset); select(1, &myset, &myset, &myset, &tv); } #endif static double simtime = 0.0; typedef struct { dis_entity_type etype; int force; int remote; } Entity; static Entity inUse[MAX_ENTITY]; static void entityEnterCb(int eid, dis_entity_type * etype, int force, craft ** cptr) { printf(" %5.2f: enter %d <>\n", fmod(simtime, 60.0), eid); if (inUse[eid].force != -1) fprintf(stderr, "duplicate eid\n"); if (eid >= MAX_ENTITY) fprintf(stderr, "too large eid\n"); inUse[eid].etype = *etype; inUse[eid].force = force; inUse[eid].remote = 1; } /* static void entityExitCb(int eid) { printf(" %4.1f: exit %d <>\n", fmod(simtime, 60.0), eid); inUse[eid].force = -1; } */ /* static void fireCb(int ftype, int firingEid, int targetEid, double time, int rounds, double location[3], double velocity[3], double range) { } */ static void detonationCb(int ftype, craft *firing, craft *target, double time, double worldLocation[3], double entityLocation[3], craft * munition, dis_detonation_pdu *dpdu) { printf(" %4.1f: detonation %d @ %.0f %.0f %.0f (%d from %d)\n", fmod(simtime, 60.0), target->disId, worldLocation[0], worldLocation[1], worldLocation[2], ftype, firing->disId); } static void cleanup(int sign) { dis_if_close(); exit(0); } int main(int argc, char *argv[]) { int sendresult, eid, loop, teid, err; double position[3] = {0, 0, 0}; double velocity[3] = {100, 0, 0}; double acceleration[3] = {0, 1, 0}; double attitude[3] = {0, 0, units_DEGtoRAD(90.0)}; /* rotation = angular velocity */ double rotation[3] = {units_DEGtoRAD(60.0), units_DEGtoRAD(10.0), units_DEGtoRAD(-13.0)}; double roteul[3]; VMatrix curmat, rotmat; double rpos[3], rvel[3], ratt[3]; double lasttime, dt, halfdtsq; double wloc[3], eloc[3]; dis_entity_type f16 = {1, 2, 225, 1, 3, 3, 0}; dis_entity_type MiG29 = {1, 2, 222, 1, 2, 5, 0}; int team_one = 1; VEulerToMatrix(attitude[0], attitude[1], attitude[2], &curmat); for (eid = 0; eid < MAX_ENTITY; eid++) inUse[eid].force = -1; //if (dis_if_init(DEVICE, 3000, 1, 1, argc, entityEnterCb, entityExitCb, // fireCb, detonationCb) != 0) { if (dis_if_init(NULL, 0, 1, 1, 1, entityEnterCb, detonationCb, NULL) != 0) { fprintf(stderr, "dis_init failed\n"); exit(17); } signal(SIGINT, cleanup); dis_if_setDRThresholds(5.0, units_DEGtoRAD(0.5)); #ifdef REALTIME simtime = sysTime(); #else simtime = 0.0; #endif #ifdef ABSOLUTETIME dis_if_setTimeAbsolute(); #else dis_setTime(simtime); #endif if (argc > 1) { dis_if_entityEnter(team_one, NULL, &f16, &MiG29, position, velocity, acceleration, attitude, rotation, &eid); if (eid >= MAX_ENTITY) { fprintf(stderr, "to big eid\n"); exit(17); } inUse[eid].etype = f16; inUse[eid].force = team_one; inUse[eid].remote = 0; } loop = 0; while (1) { loop++; #ifdef WINNT // usleep() is deprecated by POSIX, tells MinGW. Workaround: Sleep(1000000 * DT); #else // Under Linux, it's simpler to continue using usleep :-) usleep(1000000 * DT); #endif lasttime = simtime; #ifdef REALTIME simtime = sysTime(); #else simtime += DT; #endif dt = simtime - lasttime; #ifdef ABSOLUTETIME dis_if_setTimeAbsolute(); #else dis_setTime(simtime); #endif err = dis_if_receive(); if (err != 0) printf("receive err = %d\n", err); for (eid = 0; eid < MAX_ENTITY; eid++) if (inUse[eid].force != -1) { if (inUse[eid].remote == 1) { /* remote */ if (loop % RSKIP == 0) { if (dis_if_getEntityState(eid, rpos, rvel, ratt) != 0) { printf("bar! %d\n", eid); exit(17); } printf("R %5.2f: %d @ %.0f %.0f %.0f [ %.2f %.2f %.2f ]\n", fmod(simtime, 60.0), eid, rpos[0], rpos[1], rpos[2], units_RADtoDEG(ratt[0]), units_RADtoDEG(ratt[1]), units_RADtoDEG(ratt[2])); } } /* if remote == 1 */ else { /* local */ halfdtsq = dt * dt / 2; position[0] += dt * velocity[0] + halfdtsq * acceleration[0]; position[1] += dt * velocity[1] + halfdtsq * acceleration[1]; position[2] += dt * velocity[2] + halfdtsq * acceleration[2]; velocity[0] += dt * acceleration[0]; velocity[1] += dt * acceleration[1]; velocity[2] += dt * acceleration[2]; roteul[0] = rotation[2]; roteul[1] = rotation[1]; roteul[2] = rotation[0]; VEulerToMatrix(dt*roteul[0], dt*roteul[1], dt*roteul[2], &rotmat); VMatrixMult(&curmat, &rotmat, &curmat); VMatrixToEuler(&curmat, &attitude[0], &attitude[1], &attitude[2]); sendresult = dis_if_setEntityState(eid, position, velocity, acceleration, attitude, rotation); if (sendresult == 1) printf("T %5.2f: %d @ %5.0f %5.0f %5.0f" " [ %8.2f %8.2f %8.2f ]\n", fmod(simtime, 60.0), eid, position[0], position[1], position[2], units_RADtoDEG(attitude[2]), units_RADtoDEG(attitude[1]), units_RADtoDEG(attitude[0])); else if (sendresult < 0) { fprintf(stderr, " %5.2f foo? %d\n", fmod(simtime, 60.0), eid); exit(17); } if ((loop % 100) == 0) { for (teid = 0; teid < MAX_ENTITY; teid++) if (inUse[teid].force != -1 && inUse[teid].remote == 1) break; if (teid < MAX_ENTITY) { /* found a target */ wloc[0] = 1000; wloc[1] = 2000; wloc[2] = 3000; eloc[0] = 4; eloc[1] = 5; eloc[2] = 6; if ((loop % 200) == 0) { printf(" %5.2f %d detonating M61A1 at %d ", fmod(simtime, 60.0), eid, teid); /* err = dis_if_detonation(dis_if_FIRE_M61A1, eid, teid, 0, 0, wloc, eloc); */ err = dis_if_detonation( &f16, eid, teid, dis_if_FIRE_M61A1, wloc, eloc, NULL); printf("%d\n", err); } else { printf(" %5.2f %d detonating AIM9M at %d ", fmod(simtime, 60.0), eid, teid); err = dis_if_detonation(&f16, dis_if_FIRE_AIM9M, eid, teid, wloc, eloc, NULL); printf("%d\n", err); } } /* if found target */ } /* if loop % 100 == 0 */ /* 1000 = 50s with DT = 0.05 */ if (loop == 1000) { printf(" %5.2f exiting %d\n", fmod(simtime, 60.0), eid); dis_if_entityExit(eid); inUse[eid].force = -1; } } /* if remote != 1 */ } /* if etype != -1 */ } /* while 1 */ return 0; } acm-6.0_20200416/test/acm/Makefile0000644000000000000000000002325213173130667014765 0ustar rootroot# This file generated by make-makefile, do not edit! # Create Makefile-include.txt instead for your customizations. CC := gcc CFLAGS := -Wall -Werror -g -fmax-errors=99 -Wuninitialized -Wmissing-prototypes -Wredundant-decls LIBS := .PHONY: all all: make astro-test.exe dis_if-test.exe zones-test.exe include Makefile-include.txt .PHONY: test test: astro-test.exe dis_if-test.exe zones-test.exe ./astro-test.exe ./dis_if-test.exe ./zones-test.exe .PHONY: clean clean: rm -f *.o *.exe *.stackdump astro-test dis_if-test zones-test astro-test.o: astro-test.c ../../src/V/Vlibmath.h ../../src/acm/astro.h ../../src/dis/dis/earth.h ../../src/util/units.h ../../src/util/zulu.h $(CC) $(CFLAGS) -c astro-test.c -o astro-test.o astro-test.exe: ../../src/V/Vlibmath.o ../../src/acm/astro.o ../../src/dis/dis/earth.o ../../src/util/error.o ../../src/util/memory.o ../../src/util/units.o ../../src/util/zulu.o astro-test.o $(CC) $(CFLAGS) -o astro-test.exe ../../src/V/Vlibmath.o ../../src/acm/astro.o ../../src/dis/dis/earth.o ../../src/util/error.o ../../src/util/memory.o ../../src/util/units.o ../../src/util/zulu.o astro-test.o $(LIBS) -lm dis_if-test.o: dis_if-test.c ../../src/V/Alib.h ../../src/V/VColor.h ../../src/V/VObjects.h ../../src/V/VPoly.h ../../src/V/Vlib.h ../../src/V/Vlibmath.h ../../src/acm/air.h ../../src/acm/dis_if.h ../../src/acm/interpolate.h ../../src/acm/inventory.h ../../src/acm/manifest.h ../../src/acm/pm.h ../../src/acm/scale.h ../../src/acm/zone.h ../../src/acm/zones.h ../../src/dis/dis/dis.h ../../src/dis/dis/disx.h ../../src/dis/dis/earth.h ../../src/util/gui.h ../../src/util/units.h ../../src/util/varray.h $(CC) $(CFLAGS) -c dis_if-test.c -o dis_if-test.o dis_if-test.exe: ../../src/V/Alib.o ../../src/V/VColor.o ../../src/V/VGlyph.o ../../src/V/VObjects.o ../../src/V/VPoly.o ../../src/V/VRoman.o ../../src/V/Vlib.o ../../src/V/Vlibmath.o ../../src/acm/adf.o ../../src/acm/aim120.o ../../src/acm/aim9m.o ../../src/acm/air.o ../../src/acm/alarm.o ../../src/acm/aps.o ../../src/acm/astro.o ../../src/acm/box.o ../../src/acm/browse.o ../../src/acm/ccip.o ../../src/acm/commands.o ../../src/acm/damage.o ../../src/acm/dis_if.o ../../src/acm/draw.o ../../src/acm/drone.o ../../src/acm/effects.o ../../src/acm/events.o ../../src/acm/flaps.o ../../src/acm/gear.o ../../src/acm/hsi.o ../../src/acm/hud.o ../../src/acm/init.o ../../src/acm/instruments.o ../../src/acm/interpolate.o ../../src/acm/inventory.o ../../src/acm/joystick.o ../../src/acm/list.o ../../src/acm/m61a1.o ../../src/acm/magnetic_compass.o ../../src/acm/manifest.o ../../src/acm/missile.o ../../src/acm/mouse.o ../../src/acm/navaid.o ../../src/acm/panel.o ../../src/acm/patchlevel.o ../../src/acm/place.o ../../src/acm/planes.o ../../src/acm/players.o ../../src/acm/pm.o ../../src/acm/prompt.o ../../src/acm/radar.o ../../src/acm/render.o ../../src/acm/runway.o ../../src/acm/scale.o ../../src/acm/sounds.o ../../src/acm/terminal.o ../../src/acm/terrain.o ../../src/acm/update.o ../../src/acm/viewer.o ../../src/acm/vpath.o ../../src/acm/vpath_gallery.o ../../src/acm/weapon.o ../../src/acm/weapon_null.o ../../src/acm/windows.o ../../src/acm/zone.o ../../src/acm/zones.o ../../src/dis/dis/datum.o ../../src/dis/dis/dis.o ../../src/dis/dis/disx.o ../../src/dis/dis/earth.o ../../src/dis/dis/xdr.o ../../src/dis/dis/xdr_dis.o ../../src/util/audio.o ../../src/util/error.o ../../src/util/gui.o ../../src/util/memory.o ../../src/util/prng.o ../../src/util/reader.o ../../src/util/sparsearray.o ../../src/util/timer.o ../../src/util/units.o ../../src/util/varray.o ../../src/util/wav.o ../../src/util/zulu.o ../../src/wmm/Geomagnetism.o ../../src/wmm/wmm.o dis_if-test.o $(CC) $(CFLAGS) -o dis_if-test.exe ../../src/V/Alib.o ../../src/V/VColor.o ../../src/V/VGlyph.o ../../src/V/VObjects.o ../../src/V/VPoly.o ../../src/V/VRoman.o ../../src/V/Vlib.o ../../src/V/Vlibmath.o ../../src/acm/adf.o ../../src/acm/aim120.o ../../src/acm/aim9m.o ../../src/acm/air.o ../../src/acm/alarm.o ../../src/acm/aps.o ../../src/acm/astro.o ../../src/acm/box.o ../../src/acm/browse.o ../../src/acm/ccip.o ../../src/acm/commands.o ../../src/acm/damage.o ../../src/acm/dis_if.o ../../src/acm/draw.o ../../src/acm/drone.o ../../src/acm/effects.o ../../src/acm/events.o ../../src/acm/flaps.o ../../src/acm/gear.o ../../src/acm/hsi.o ../../src/acm/hud.o ../../src/acm/init.o ../../src/acm/instruments.o ../../src/acm/interpolate.o ../../src/acm/inventory.o ../../src/acm/joystick.o ../../src/acm/list.o ../../src/acm/m61a1.o ../../src/acm/magnetic_compass.o ../../src/acm/manifest.o ../../src/acm/missile.o ../../src/acm/mouse.o ../../src/acm/navaid.o ../../src/acm/panel.o ../../src/acm/patchlevel.o ../../src/acm/place.o ../../src/acm/planes.o ../../src/acm/players.o ../../src/acm/pm.o ../../src/acm/prompt.o ../../src/acm/radar.o ../../src/acm/render.o ../../src/acm/runway.o ../../src/acm/scale.o ../../src/acm/sounds.o ../../src/acm/terminal.o ../../src/acm/terrain.o ../../src/acm/update.o ../../src/acm/viewer.o ../../src/acm/vpath.o ../../src/acm/vpath_gallery.o ../../src/acm/weapon.o ../../src/acm/weapon_null.o ../../src/acm/windows.o ../../src/acm/zone.o ../../src/acm/zones.o ../../src/dis/dis/datum.o ../../src/dis/dis/dis.o ../../src/dis/dis/disx.o ../../src/dis/dis/earth.o ../../src/dis/dis/xdr.o ../../src/dis/dis/xdr_dis.o ../../src/util/audio.o ../../src/util/error.o ../../src/util/gui.o ../../src/util/memory.o ../../src/util/prng.o ../../src/util/reader.o ../../src/util/sparsearray.o ../../src/util/timer.o ../../src/util/units.o ../../src/util/varray.o ../../src/util/wav.o ../../src/util/zulu.o ../../src/wmm/Geomagnetism.o ../../src/wmm/wmm.o dis_if-test.o $(LIBS) -lm zones-test.o: zones-test.c ../../src/V/Vlibmath.h ../../src/acm/zones.h ../../src/dis/dis/earth.h ../../src/util/memory.h ../../src/util/units.h $(CC) $(CFLAGS) -c zones-test.c -o zones-test.o zones-test.exe: ../../src/V/Alib.o ../../src/V/VColor.o ../../src/V/VGlyph.o ../../src/V/VObjects.o ../../src/V/VPoly.o ../../src/V/VRoman.o ../../src/V/Vlib.o ../../src/V/Vlibmath.o ../../src/acm/adf.o ../../src/acm/aim120.o ../../src/acm/aim9m.o ../../src/acm/air.o ../../src/acm/alarm.o ../../src/acm/aps.o ../../src/acm/astro.o ../../src/acm/box.o ../../src/acm/browse.o ../../src/acm/ccip.o ../../src/acm/commands.o ../../src/acm/damage.o ../../src/acm/dis_if.o ../../src/acm/draw.o ../../src/acm/drone.o ../../src/acm/effects.o ../../src/acm/events.o ../../src/acm/flaps.o ../../src/acm/gear.o ../../src/acm/hsi.o ../../src/acm/hud.o ../../src/acm/init.o ../../src/acm/instruments.o ../../src/acm/interpolate.o ../../src/acm/inventory.o ../../src/acm/joystick.o ../../src/acm/list.o ../../src/acm/m61a1.o ../../src/acm/magnetic_compass.o ../../src/acm/manifest.o ../../src/acm/missile.o ../../src/acm/mouse.o ../../src/acm/navaid.o ../../src/acm/panel.o ../../src/acm/patchlevel.o ../../src/acm/place.o ../../src/acm/planes.o ../../src/acm/players.o ../../src/acm/pm.o ../../src/acm/prompt.o ../../src/acm/radar.o ../../src/acm/render.o ../../src/acm/runway.o ../../src/acm/scale.o ../../src/acm/sounds.o ../../src/acm/terminal.o ../../src/acm/terrain.o ../../src/acm/update.o ../../src/acm/viewer.o ../../src/acm/vpath.o ../../src/acm/vpath_gallery.o ../../src/acm/weapon.o ../../src/acm/weapon_null.o ../../src/acm/windows.o ../../src/acm/zone.o ../../src/acm/zones.o ../../src/dis/dis/datum.o ../../src/dis/dis/dis.o ../../src/dis/dis/disx.o ../../src/dis/dis/earth.o ../../src/dis/dis/xdr.o ../../src/dis/dis/xdr_dis.o ../../src/util/audio.o ../../src/util/error.o ../../src/util/gui.o ../../src/util/memory.o ../../src/util/prng.o ../../src/util/reader.o ../../src/util/sparsearray.o ../../src/util/timer.o ../../src/util/units.o ../../src/util/varray.o ../../src/util/wav.o ../../src/util/zulu.o ../../src/wmm/Geomagnetism.o ../../src/wmm/wmm.o zones-test.o $(CC) $(CFLAGS) -o zones-test.exe ../../src/V/Alib.o ../../src/V/VColor.o ../../src/V/VGlyph.o ../../src/V/VObjects.o ../../src/V/VPoly.o ../../src/V/VRoman.o ../../src/V/Vlib.o ../../src/V/Vlibmath.o ../../src/acm/adf.o ../../src/acm/aim120.o ../../src/acm/aim9m.o ../../src/acm/air.o ../../src/acm/alarm.o ../../src/acm/aps.o ../../src/acm/astro.o ../../src/acm/box.o ../../src/acm/browse.o ../../src/acm/ccip.o ../../src/acm/commands.o ../../src/acm/damage.o ../../src/acm/dis_if.o ../../src/acm/draw.o ../../src/acm/drone.o ../../src/acm/effects.o ../../src/acm/events.o ../../src/acm/flaps.o ../../src/acm/gear.o ../../src/acm/hsi.o ../../src/acm/hud.o ../../src/acm/init.o ../../src/acm/instruments.o ../../src/acm/interpolate.o ../../src/acm/inventory.o ../../src/acm/joystick.o ../../src/acm/list.o ../../src/acm/m61a1.o ../../src/acm/magnetic_compass.o ../../src/acm/manifest.o ../../src/acm/missile.o ../../src/acm/mouse.o ../../src/acm/navaid.o ../../src/acm/panel.o ../../src/acm/patchlevel.o ../../src/acm/place.o ../../src/acm/planes.o ../../src/acm/players.o ../../src/acm/pm.o ../../src/acm/prompt.o ../../src/acm/radar.o ../../src/acm/render.o ../../src/acm/runway.o ../../src/acm/scale.o ../../src/acm/sounds.o ../../src/acm/terminal.o ../../src/acm/terrain.o ../../src/acm/update.o ../../src/acm/viewer.o ../../src/acm/vpath.o ../../src/acm/vpath_gallery.o ../../src/acm/weapon.o ../../src/acm/weapon_null.o ../../src/acm/windows.o ../../src/acm/zone.o ../../src/acm/zones.o ../../src/dis/dis/datum.o ../../src/dis/dis/dis.o ../../src/dis/dis/disx.o ../../src/dis/dis/earth.o ../../src/dis/dis/xdr.o ../../src/dis/dis/xdr_dis.o ../../src/util/audio.o ../../src/util/error.o ../../src/util/gui.o ../../src/util/memory.o ../../src/util/prng.o ../../src/util/reader.o ../../src/util/sparsearray.o ../../src/util/timer.o ../../src/util/units.o ../../src/util/varray.o ../../src/util/wav.o ../../src/util/zulu.o ../../src/wmm/Geomagnetism.o ../../src/wmm/wmm.o zones-test.o $(LIBS) -lm # Checksum of the original file: 2035087630 acm-6.0_20200416/test/acm/Makefile-include.txt0000644000000000000000000000046513172246306017222 0ustar rootroot# OS specific compilation options: ifeq ($(OS),Windows_NT) CC = c:/mingw/bin/gcc CFLAGS += -mconsole -mwindows LIBS += -lws2_32 -lwinmm else UNAME_S := $(shell uname -s) ifeq ($(UNAME_S),Linux) CFLAGS += LIBS += -lX11 -lasound -pthread else CFLAGS += LIBS += -lX11 -lasound -pthread endif endifacm-6.0_20200416/test/dis/0000755000000000000000000000000013175062144013334 5ustar rootrootacm-6.0_20200416/test/dis/dis/0000755000000000000000000000000013175062144014113 5ustar rootrootacm-6.0_20200416/test/dis/dis/xdr_dis-stress-test.c0000644000000000000000000000761513107615567020232 0ustar rootroot/* * DIS PDU packet decoding stress-test. We must prepare to sustain the hostile * environment of the net: ill formed packets must be detected and rejected to * protect program safety and security. * * Random packets are currently detected mostly because: * * - The length field does not match the actual length of the packet (checked * in dis_readPDU()). * * - The type field does not match any supported DIS PDU type (checked by * xdr_dis_pdu()). * * - Packet too short for the stated variable length array. * * On failed decoding, the xdr module guarantees any dynamically allocated * memory be released. It is still responsibility of the ACM program to * release successfully decoded DIS PDU through the dis_freePDUComponents(). */ #include #include #include #include #include "../../../src/util/memory.h" #include "../../../src/util/error.h" #include "../../../src/util/prng.h" #include "../../../src/dis/dis/xdr_dis.h" #include "../../../src/dis/dis/datum.h" #include "../../../src/dis/dis/xdr.h" #define IS_LITTLE_ENDIAN (((char *)&(int){1})[0] == 1) static int err; static int packets_decoded, packets_successfully_decoded; /** * Tries to decode the packet as a DIS PDU. * * Note that the packet so generated has a random header where only the type is * set, not the length; in ACM the length field of the received packets is * checked in dis_readPDU() and not in xdr_dis_pdu(), this latter being the * object of our tests now. * * Note that many arrays in the packet gets unexpectedly successfully decoded * despite all the controls operated by xdr_var_array() just because the length * filed giving their length is a small u_char; the chance decreases rapidly * with larger length fields. * @param line Source line no. of this test. * @param packet Random packet. * @param packet_len Length of the random packet. * @param pdu_type Type of DIS PDU to be set in the packet. */ static void decodePacket(int line, char *packet, int packet_len, u_char pdu_type) { packet[2] = pdu_type; xdr_Type *xdr = xdr_new(packet, packet_len, xdr_DECODE); dis_pdu pdu; //printf("Parsing PDU:\n"); packets_decoded++; if( xdr_dis_pdu(xdr, &pdu) ){ packets_successfully_decoded++; //printf("in line %d successfully decoded pdu type %d, %d bytes decoded\n", line, pdu_type, xdr_getpos(xdr)); dis_freePDUComponents(&pdu); } else { //("in line %d failed decoding pdu type %d: %s\n", line, pdu_type, xdr_getErrorDescription(xdr)); } xdr_free(xdr); } int main(int argc, char** argv) { int i; error_prog_name = argv[0]; prng_setSeed(123456789); for(i = 0; i < 100000; i++){ /* Use the same max packet length the dis_readPDU() accepts. */ char packet[2048]; prng_fill(packet, sizeof(packet)); /* Test all the DIS PDU types supported by xdr_dis_pdu(): */ decodePacket(__LINE__, packet, sizeof(packet), PDUTypeOther); decodePacket(__LINE__, packet, sizeof(packet), PDUTypeEntityState); decodePacket(__LINE__, packet, sizeof(packet), PDUTypeCollision); decodePacket(__LINE__, packet, sizeof(packet), PDUTypeFire); decodePacket(__LINE__, packet, sizeof(packet), PDUTypeDetonation); decodePacket(__LINE__, packet, sizeof(packet), PDUTypeCreateEntity); decodePacket(__LINE__, packet, sizeof(packet), PDUTypeRemoveEntity); decodePacket(__LINE__, packet, sizeof(packet), PDUTypeStopFreeze); decodePacket(__LINE__, packet, sizeof(packet), PDUTypeStartResume); decodePacket(__LINE__, packet, sizeof(packet), PDUTypeSetData); decodePacket(__LINE__, packet, sizeof(packet), PDUTypeComment); decodePacket(__LINE__, packet, sizeof(packet), PDUTypeEmission); decodePacket(__LINE__, packet, sizeof(packet), PDUTypeTransferControl); decodePacket(__LINE__, packet, sizeof(packet), PDUTypeAcknowledge); } //printf("successfully decoded %d of %d\n", packets_successfully_decoded, packets_decoded); err += memory_report(); return err == 0? 0 : 1; } acm-6.0_20200416/test/dis/dis/dis-test.c0000644000000000000000000000266213100126042016003 0ustar rootroot#include #include #include #include #include #include "../../../src/dis/dis/dis.h" int main(int argc, char** argv) { dis_entity_type et; assert( ! dis_parseEntityType(NULL, &et) ); assert( ! dis_parseEntityType("", &et) ); assert( ! dis_parseEntityType("......", &et) ); assert( ! dis_parseEntityType("zzzz", &et) ); assert( dis_parseEntityType(" 1.2.3.4.5.6.7 ", &et) ); assert( strcmp(dis_entityTypeToString(&et), "1.2.3.4.5.6.7") == 0 ); // min assert( dis_parseEntityType("0.0.0.0.0.0.0", &et) ); assert( strcmp(dis_entityTypeToString(&et), "0.0.0.0.0.0.0") == 0 ); // max assert( dis_parseEntityType("255.255.65535.255.255.255.255", &et) ); assert( strcmp(dis_entityTypeToString(&et), "255.255.65535.255.255.255.255") == 0 ); // out of the range: assert( ! dis_parseEntityType("999.0.0.0.0.0.0", &et) ); assert( ! dis_parseEntityType("0.999.0.0.0.0.0", &et) ); assert( ! dis_parseEntityType("0.0.99999.0.0.0.0", &et) ); assert( ! dis_parseEntityType("0.0.0.999.0.0.0", &et) ); assert( ! dis_parseEntityType("0.0.0.0.999.0.0", &et) ); assert( ! dis_parseEntityType("0.0.0.0.0.999.0", &et) ); assert( ! dis_parseEntityType("0.0.0.0.0.0.999", &et) ); // too many digits: assert( ! dis_parseEntityType("999999.0.0.0.0.0.0", &et) ); et = (dis_entity_type){0, 0, 0, 0, 0, 0, 0}; assert( strcmp(dis_entityTypeToString(&et), "0.0.0.0.0.0.0") == 0 ); return 0; } acm-6.0_20200416/test/dis/dis/xdr-test.c0000644000000000000000000001225513107242037016032 0ustar rootroot/* * Basically, the XDR encoding works in words of 32 bits with bytes in big * endian order (that is, high order byte comes first in memory). Smaller * quantities (char, short) are then padded with zero bytes. Larger quantities * (that is, double precision floating point numbers) take 2 words for a total * of 64 bites. * * The stdint.h defines several common useful int types with names that are self * explanatory and helps resolving ambiguities (xdr libraries should have used * them just from the start, it would helped very much): * * signed: int8_t, int16_t, int32_t, int64_t * unsigned: uint8_t, uint16_t, uint32_t, uint64_t */ #include #include #include #include #include "../../../src/dis/dis/xdr.h" #include "../../../src/util/memory.h" static int err; static void printbuf(char *b, int blen) { int i; for(i = 0; i < blen; i++) printf(" 0x%02x", (uint8_t) b[i]); } static void cmp(int line, char *got, int gotlen, char *exp, int explen) { if( gotlen == explen && memcmp(got, exp, explen) == 0 ) return; printf("test failed in line %d:", line); printf("\n got: "); printbuf(got, gotlen); printf("\n exp: "); printbuf(exp, explen); printf("\n"); err++; } /** * Test memory allocation roll-back on decoding error. */ static void decoding_error_recovery_test() { char buf[99]; xdr_Type *xdr; int buflen; /* * First, create a test packet: */ xdr = xdr_new(buf, sizeof(buf), xdr_ENCODE); char *s_in = "ABCD"; assert( xdr_putBytes(xdr, s_in, strlen(s_in)) ); //int32_t arr_in[] = {1, 2}; int32_t *arr_in = (int32_t[]){1, 2}; assert( xdr_var_array(xdr, (void **)&arr_in, 2, sizeof(int32_t), (xdr_Callback) xdr_int32) ); buflen = xdr_getpos(xdr); xdr_free(xdr); /* * ...then decode that packet: */ xdr = xdr_new(buf, buflen, xdr_DECODE); char *s_out; assert( xdr_getBytesAllocated(xdr, (void **)&s_out, 4, 1) ); assert( strcmp(s_out, s_in) == 0 ); int32_t *arr_out; assert( xdr_var_array(xdr, (void **)&arr_out, 2, sizeof(int32_t), (xdr_Callback) xdr_int32) ); assert( arr_out[0] == 1 ); /* * Read one more data that does not exist in the packet, so intentionally * triggering an error: */ int32_t does_not_exist_in_packet; assert( ! xdr_int32(xdr, &does_not_exist_in_packet) ); // ... causing the expected "premature end of the buffer": //printf("Expected error: %s\n", xdr_getErrorDescription(xdr) ); xdr_free(xdr); /* * Now all the dynamically allocated memory should have been released and * the program should exit with no memory leaks whatsoever. */ } int main(int argc, char** argv) { char buf[99]; xdr_Type *xdr; int buflen; //printf("sizeof(long) = %ld\n", sizeof(long)); uint8_t uc; memset(buf, 255, sizeof(buf)); xdr = xdr_new(buf, sizeof(buf), xdr_ENCODE); uc = 0x12; assert( xdr_char(xdr, (char *) &uc) ); uc = 0x34; assert( xdr_char(xdr, (char *) &uc ) ); buflen = xdr_getpos(xdr); cmp(__LINE__, buf, buflen, "\x00\x00\x00\x12\x00\x00\x00\x34", 8); xdr_free(xdr); // now decoding: xdr = xdr_new(buf, buflen, xdr_DECODE); assert( xdr_char(xdr, (char *) &uc) ); assert( uc == 0x12 ); assert( xdr_char(xdr, (char *) &uc) ); assert( uc == 0x34 ); assert( ! xdr_char(xdr, (char *) &uc) ); // reading beyond buffer end must fail xdr_free(xdr); uint32_t ui; memset(buf, 255, sizeof(buf)); xdr = xdr_new(buf, sizeof(buf), xdr_ENCODE); ui = 0x01020304; assert( xdr_uint32(xdr, &ui ) ); buflen = xdr_getpos(xdr); cmp(__LINE__, buf, buflen, "\x01\x02\x03\x04", 4); xdr_free(xdr); // now decoding: xdr = xdr_new(buf, buflen, xdr_DECODE); assert( xdr_uint32(xdr, &ui) ); assert( ui == 0x01020304 ); assert( ! xdr_char(xdr, (char *) &uc) ); // reading beyond buffer end must fail xdr_free(xdr); // same as above, but "negative" int memset(buf, 255, sizeof(buf)); xdr = xdr_new(buf, sizeof(buf), xdr_ENCODE); ui = 0x10203040; // note high bit set assert( xdr_uint32(xdr, &ui ) ); buflen = xdr_getpos(xdr); cmp(__LINE__, buf, buflen, "\x10\x20\x30\x40", 4); xdr_free(xdr); // now decoding: xdr = xdr_new(buf, buflen, xdr_DECODE); assert( xdr_uint32(xdr, &ui) ); assert( ui == 0x10203040 ); assert( ! xdr_char(xdr, (char *) &uc) ); // reading beyond buffer end must fail xdr_free(xdr); float f = 7.0; memset(buf, 255, sizeof(buf)); xdr = xdr_new(buf, sizeof(buf), xdr_ENCODE); assert( xdr_float(xdr, &f ) ); buflen = xdr_getpos(xdr); cmp(__LINE__, buf, buflen, "\x40\xe0\x00\x00", 4); xdr_free(xdr); // now decoding: xdr = xdr_new(buf, buflen, xdr_DECODE); assert( xdr_float(xdr, &f) ); assert( f == 7.0 ); assert( ! xdr_char(xdr, (char *) &uc) ); // reading beyond buffer end must fail xdr_free(xdr); double d = 7.0; memset(buf, 255, sizeof(buf)); xdr = xdr_new(buf, sizeof(buf), xdr_ENCODE); assert( xdr_double(xdr, &d ) ); buflen = xdr_getpos(xdr); cmp(__LINE__, buf, buflen, "\x40\x1c\x00\x00\x00\x00\x00\x00", 8); xdr_free(xdr); // now decoding: xdr = xdr_new(buf, buflen, xdr_DECODE); assert( xdr_double(xdr, &d) ); assert( d == 7.0 ); assert( ! xdr_char(xdr, (char *) &uc) ); // reading beyond buffer end must fail xdr_free(xdr); decoding_error_recovery_test(); err += memory_report(); return err? 1 : 0; } acm-6.0_20200416/test/dis/dis/Makefile0000644000000000000000000001020113107243210015533 0ustar rootroot# This file generated by make-makefile, do not edit! # Create Makefile-include.txt instead for your customizations. CC := gcc CFLAGS := -Wall -Werror -g -fmax-errors=99 -Wuninitialized -Wmissing-prototypes -Wredundant-decls LIBS := .PHONY: all all: make dis-test.exe earth-test.exe xdr-test.exe xdr_dis-stress-test.exe xdr_dis-test.exe include Makefile-include.txt .PHONY: test test: dis-test.exe earth-test.exe xdr-test.exe xdr_dis-stress-test.exe xdr_dis-test.exe ./dis-test.exe ./earth-test.exe ./xdr-test.exe ./xdr_dis-stress-test.exe ./xdr_dis-test.exe .PHONY: clean clean: rm -f *.o *.exe *.stackdump dis-test earth-test xdr-test xdr_dis-stress-test xdr_dis-test dis-test.o: dis-test.c ../../../src/V/Vlibmath.h ../../../src/dis/dis/dis.h ../../../src/dis/dis/earth.h $(CC) $(CFLAGS) -c dis-test.c -o dis-test.o dis-test.exe: ../../../src/V/Vlibmath.o ../../../src/dis/dis/datum.o ../../../src/dis/dis/dis.o ../../../src/dis/dis/earth.o ../../../src/dis/dis/xdr.o ../../../src/dis/dis/xdr_dis.o ../../../src/util/error.o ../../../src/util/memory.o ../../../src/util/units.o dis-test.o $(CC) $(CFLAGS) -o dis-test.exe ../../../src/V/Vlibmath.o ../../../src/dis/dis/datum.o ../../../src/dis/dis/dis.o ../../../src/dis/dis/earth.o ../../../src/dis/dis/xdr.o ../../../src/dis/dis/xdr_dis.o ../../../src/util/error.o ../../../src/util/memory.o ../../../src/util/units.o dis-test.o $(LIBS) -lm earth-test.o: earth-test.c ../../../src/dis/dis/earth.h ../../../src/util/memory.h ../../../src/util/units.h $(CC) $(CFLAGS) -c earth-test.c -o earth-test.o earth-test.exe: ../../../src/dis/dis/earth.o ../../../src/util/error.o ../../../src/util/memory.o ../../../src/util/units.o earth-test.o $(CC) $(CFLAGS) -o earth-test.exe ../../../src/dis/dis/earth.o ../../../src/util/error.o ../../../src/util/memory.o ../../../src/util/units.o earth-test.o $(LIBS) -lm xdr-test.o: xdr-test.c ../../../src/dis/dis/xdr.h ../../../src/util/memory.h $(CC) $(CFLAGS) -c xdr-test.c -o xdr-test.o xdr-test.exe: ../../../src/dis/dis/xdr.o ../../../src/util/error.o ../../../src/util/memory.o xdr-test.o $(CC) $(CFLAGS) -o xdr-test.exe ../../../src/dis/dis/xdr.o ../../../src/util/error.o ../../../src/util/memory.o xdr-test.o $(LIBS) xdr_dis-stress-test.o: xdr_dis-stress-test.c ../../../src/V/Vlibmath.h ../../../src/dis/dis/datum.h ../../../src/dis/dis/dis.h ../../../src/dis/dis/earth.h ../../../src/dis/dis/xdr.h ../../../src/dis/dis/xdr_dis.h ../../../src/util/error.h ../../../src/util/memory.h ../../../src/util/prng.h $(CC) $(CFLAGS) -c xdr_dis-stress-test.c -o xdr_dis-stress-test.o xdr_dis-stress-test.exe: ../../../src/V/Vlibmath.o ../../../src/dis/dis/datum.o ../../../src/dis/dis/dis.o ../../../src/dis/dis/earth.o ../../../src/dis/dis/xdr.o ../../../src/dis/dis/xdr_dis.o ../../../src/util/error.o ../../../src/util/memory.o ../../../src/util/prng.o ../../../src/util/units.o xdr_dis-stress-test.o $(CC) $(CFLAGS) -o xdr_dis-stress-test.exe ../../../src/V/Vlibmath.o ../../../src/dis/dis/datum.o ../../../src/dis/dis/dis.o ../../../src/dis/dis/earth.o ../../../src/dis/dis/xdr.o ../../../src/dis/dis/xdr_dis.o ../../../src/util/error.o ../../../src/util/memory.o ../../../src/util/prng.o ../../../src/util/units.o xdr_dis-stress-test.o $(LIBS) -lm xdr_dis-test.o: xdr_dis-test.c ../../../src/V/Vlibmath.h ../../../src/dis/dis/datum.h ../../../src/dis/dis/dis.h ../../../src/dis/dis/earth.h ../../../src/dis/dis/xdr.h ../../../src/dis/dis/xdr_dis.h ../../../src/util/error.h ../../../src/util/memory.h $(CC) $(CFLAGS) -c xdr_dis-test.c -o xdr_dis-test.o xdr_dis-test.exe: ../../../src/V/Vlibmath.o ../../../src/dis/dis/datum.o ../../../src/dis/dis/dis.o ../../../src/dis/dis/earth.o ../../../src/dis/dis/xdr.o ../../../src/dis/dis/xdr_dis.o ../../../src/util/error.o ../../../src/util/memory.o ../../../src/util/units.o xdr_dis-test.o $(CC) $(CFLAGS) -o xdr_dis-test.exe ../../../src/V/Vlibmath.o ../../../src/dis/dis/datum.o ../../../src/dis/dis/dis.o ../../../src/dis/dis/earth.o ../../../src/dis/dis/xdr.o ../../../src/dis/dis/xdr_dis.o ../../../src/util/error.o ../../../src/util/memory.o ../../../src/util/units.o xdr_dis-test.o $(LIBS) -lm # Checksum of the original file: 2750412422 acm-6.0_20200416/test/dis/dis/Makefile-include.txt0000644000000000000000000000063413131075231020006 0ustar rootroot# OS specific compilation options: ifeq ($(OS),Windows_NT) CFLAGS += LIBS += -lws2_32 else UNAME_S := $(shell uname -s) ifeq ($(UNAME_S),Linux) CFLAGS += LIBS += else CFLAGS += LIBS += endif endif .PHONY: rebuild rebuild: clean find . -mindepth 1 -type d \ | while read d; do \ if [ -f $$d/Makefile ]; then \ echo "$$d"; \ (cd $$d; check-included && make-makefile); \ fi \ done make acm-6.0_20200416/test/dis/dis/xdr_dis-test.c0000644000000000000000000010115713260344465016701 0ustar rootroot#include #include #include #include #include "../../../src/util/memory.h" #include "../../../src/util/error.h" #include "../../../src/dis/dis/xdr_dis.h" #include "../../../src/dis/dis/datum.h" #include "../../../src/dis/dis/xdr.h" #define IS_LITTLE_ENDIAN (((char *)&(int){1})[0] == 1) static int err; static void fill(void *block, int block_len) { unsigned char *p = block; unsigned char b = 1; while(block_len > 0){ *p = b; b++; if( b == 0 ) b = 1; p++; block_len--; } } static void printbuf(char *b, int blen) { int i; for(i = 0; i < blen; i++){ if( i != 0 && i % 16 == 0 ) printf("\n"); printf(" 0x%02x", b[i]&255); } } static int findDiffOffset(char *a, int alen, char *b, int blen) { int i; for(i = 0; i < alen && i < blen; i++) if( a[i] != b[i] ) return i; return i; } static void cmp(int line, void *got, int gotlen, void *exp, int explen) { if( gotlen == explen && memcmp(got, exp, explen) == 0 ) return; int offset = findDiffOffset((char *) got, gotlen, (char *) exp, explen); printf("test failed in line %d at byte offset %d:", line, offset); printf("\n got: "); printbuf(got, gotlen); printf("\n exp: "); printbuf(exp, explen); printf("\n"); err++; } static void test_dis_entity_state_pdu() { char buf[2000]; xdr_Type *xdr; int buf_len_in, buf_len_out; dis_entity_state_pdu es_in, es_out; //dis_articulation_parm ap_in, ap_out; fill(&es_in, sizeof(es_in)); es_in.hdr.protocol_version = DISProtocolVersionIEEE1278_95; es_in.hdr.pdu_type = PDUTypeEntityState; es_in.hdr.protocol_family = PDUFamilyEntityInformation; es_in.hdr.length = 0; // set below es_in.hdr.padding = 0; // xdr_dis_articulation_parm() not implemented. es_in.art_parm_count = 0; es_in.art_parm = NULL; xdr = xdr_new(buf, sizeof(buf), xdr_ENCODE); assert( xdr_dis_pdu(xdr, (dis_pdu *) &es_in) ); buf_len_in = xdr_getpos(xdr); xdr_free(xdr); /* * Now for a hack. We need to insert the correct packet length into * the PDU header. The header is somewhat stable from one protocol release * to the next, so I've just hard-coded it here. */ es_in.hdr.length = buf_len_in; *((u_short *) &buf[8]) = htons(buf_len_in); //printf("generated buf:\n"); printbuf(buf, buf_len_in); printf("\n"); if( IS_LITTLE_ENDIAN ){ // sorry, only little endian cpu here // Compares the generated packet with the expected one: char *exp_buf = "\x05\x02\x01\x01\x08\x07\x06\x05\x00\x90\x00\x00\x0e\x0d\x10\x0f" "\x12\x11\x13\x00\x15\x16\x18\x17\x19\x1a\x1b\x1c\x1d\x1e\x20\x1f" "\x21\x22\x23\x24\x28\x27\x26\x25\x2c\x2b\x2a\x29\x30\x2f\x2e\x2d" "\x38\x37\x36\x35\x34\x33\x32\x31\x40\x3f\x3e\x3d\x3c\x3b\x3a\x39" "\x48\x47\x46\x45\x44\x43\x42\x41\x4c\x4b\x4a\x49\x50\x4f\x4e\x4d" "\x54\x53\x52\x51\x58\x57\x56\x55\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60" "\x61\x62\x63\x64\x65\x66\x67\x68\x6c\x6b\x6a\x69\x70\x6f\x6e\x6d" "\x74\x73\x72\x71\x78\x77\x76\x75\x7c\x7b\x7a\x79\x80\x7f\x7e\x7d" "\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x90\x8f\x8e\x8d"; int exp_buf_len = 9*16; cmp(__LINE__, buf, buf_len_in, exp_buf, exp_buf_len); } // Decodes the generated packet: memory_zero(&es_out); xdr = xdr_new(buf, buf_len_in, xdr_DECODE); assert( xdr_dis_pdu(xdr, (dis_pdu *) &es_out) ); buf_len_out = xdr_getpos(xdr); xdr_free(xdr); // Compares the decoded data with the original data: assert(buf_len_out == buf_len_in); cmp(__LINE__, &es_out.hdr, sizeof(es_out.hdr), &es_in.hdr, sizeof(es_in.hdr)); cmp(__LINE__, &es_out.id, sizeof(es_out.id), &es_in.id, sizeof(es_in.id)); cmp(__LINE__, &es_out.type, sizeof(es_out.type), &es_in.type, sizeof(es_in.type)); cmp(__LINE__, &es_out.alt_type, sizeof(es_out.alt_type), &es_in.alt_type, sizeof(es_in.alt_type)); cmp(__LINE__, &es_out.vel, sizeof(es_out.vel), &es_in.vel, sizeof(es_in.vel)); cmp(__LINE__, &es_out.pos, sizeof(es_out.pos), &es_in.pos, sizeof(es_in.pos)); cmp(__LINE__, &es_out.orientation, sizeof(es_out.orientation), &es_in.orientation, sizeof(es_in.orientation)); cmp(__LINE__, &es_out.appearance, sizeof(es_out.appearance), &es_in.appearance, sizeof(es_in.appearance)); cmp(__LINE__, &es_out.dr_parm, sizeof(es_out.dr_parm), &es_in.dr_parm, sizeof(es_in.dr_parm)); cmp(__LINE__, &es_out.marking, sizeof(es_out.marking), &es_in.marking, sizeof(es_in.marking)); cmp(__LINE__, &es_out.capabilities, sizeof(es_out.capabilities), &es_in.capabilities, sizeof(es_in.capabilities)); cmp(__LINE__, &es_out.art_parm, sizeof(es_out.art_parm), &es_in.art_parm, sizeof(es_in.art_parm)); dis_freePDUComponents((dis_pdu *) &es_out); } static void test_dis_fire_pdu() { char buf[2000]; xdr_Type *xdr; int buf_len_in, buf_len_out; dis_fire_pdu fire_in, fire_out; fill(&fire_in, sizeof(fire_in)); fire_in.hdr.protocol_version = DISProtocolVersionIEEE1278_95; fire_in.hdr.pdu_type = PDUTypeFire; // pkt offset 2 fire_in.hdr.protocol_family = PDUFamilyWarfare; // pkt offset 3 fire_in.hdr.length = 0; // set below fire_in.hdr.padding = 0; xdr = xdr_new(buf, sizeof(buf), xdr_ENCODE); assert( xdr_dis_pdu(xdr, (dis_pdu *) &fire_in) ); buf_len_in = xdr_getpos(xdr); xdr_free(xdr); /* * Now for a hack. We need to insert the correct packet length into * the PDU header. The header is somewhat stable from one protocol release * to the next, so I've just hard-coded it here. */ fire_in.hdr.length = buf_len_in; *((u_short *) &buf[8]) = htons(buf_len_in); //printf("generated buf:\n"); printbuf(buf, buf_len_in); printf("\n"); if( IS_LITTLE_ENDIAN ){ // sorry, only little endian cpu here // Compares the generated packet with the expected one: char *exp_buf = "\x05\x02\x02\x02\x08\x07\x06\x05\x00\x60\x00\x00\x0e\x0d\x10\x0f" "\x12\x11\x14\x13\x16\x15\x18\x17\x1a\x19\x1c\x1b\x1e\x1d\x20\x1f" "\x22\x21\x24\x23\x28\x27\x26\x25\x30\x2f\x2e\x2d\x2c\x2b\x2a\x29" "\x38\x37\x36\x35\x34\x33\x32\x31\x40\x3f\x3e\x3d\x3c\x3b\x3a\x39" "\x41\x42\x44\x43\x45\x46\x47\x48\x4a\x49\x4c\x4b\x4e\x4d\x50\x4f" "\x54\x53\x52\x51\x58\x57\x56\x55\x5c\x5b\x5a\x59\x60\x5f\x5e\x5d"; int exp_buf_len = 6*16; cmp(__LINE__, buf, buf_len_in, exp_buf, exp_buf_len); } // Decodes the generated packet: memory_zero(&fire_out); xdr = xdr_new(buf, buf_len_in, xdr_DECODE); assert( xdr_dis_pdu(xdr, (dis_pdu *) &fire_out) ); buf_len_out = xdr_getpos(xdr); xdr_free(xdr); // Compares the decoded data with the original data: assert(buf_len_out == buf_len_in); cmp(__LINE__, &fire_out.hdr, sizeof(fire_out.hdr), &fire_in.hdr, sizeof(fire_in.hdr)); cmp(__LINE__, &fire_out.firing_id, sizeof(fire_out.firing_id), &fire_in.firing_id, sizeof(fire_in.firing_id)); cmp(__LINE__, &fire_out.target_id, sizeof(fire_out.target_id), &fire_in.target_id, sizeof(fire_in.target_id)); cmp(__LINE__, &fire_out.munition_id, sizeof(fire_out.munition_id), &fire_in.munition_id, sizeof(fire_in.munition_id)); cmp(__LINE__, &fire_out.event, sizeof(fire_out.event), &fire_in.event, sizeof(fire_in.event)); cmp(__LINE__, &fire_out.fire_mission_index, sizeof(fire_out.fire_mission_index), &fire_in.fire_mission_index, sizeof(fire_in.fire_mission_index)); cmp(__LINE__, &fire_out.burst, sizeof(fire_out.burst), &fire_in.burst, sizeof(fire_in.burst)); cmp(__LINE__, &fire_out.vel, sizeof(fire_out.vel), &fire_in.vel, sizeof(fire_in.vel)); cmp(__LINE__, &fire_out.range, sizeof(fire_out.range), &fire_in.range, sizeof(fire_in.range)); dis_freePDUComponents((dis_pdu *) &fire_out); } static void test_dis_detonation_pdu() { char buf[2000]; xdr_Type *xdr; int buf_len_in, buf_len_out; dis_detonation_pdu det_in, det_out; fill(&det_in, sizeof(det_in)); det_in.hdr.protocol_version = DISProtocolVersionIEEE1278_95; det_in.hdr.pdu_type = PDUTypeDetonation; // pkt offset 2 det_in.hdr.protocol_family = PDUFamilyWarfare; // pkt offset 3 det_in.hdr.length = 0; // set below det_in.hdr.padding = 0; det_in.num_art_parms = 0; det_in.art_parm = NULL; xdr = xdr_new(buf, sizeof(buf), xdr_ENCODE); assert( xdr_dis_pdu(xdr, (dis_pdu *) &det_in) ); buf_len_in = xdr_getpos(xdr); xdr_free(xdr); /* * Now for a hack. We need to insert the correct packet length into * the PDU header. The header is somewhat stable from one protocol release * to the next, so I've just hard-coded it here. */ det_in.hdr.length = buf_len_in; *((u_short *) &buf[8]) = htons(buf_len_in); //printf("generated buf:\n"); printbuf(buf, buf_len_in); printf("\n"); if( IS_LITTLE_ENDIAN ){ // sorry, only little endian cpu here // Compares the generated packet with the expected one: char *exp_buf = "\x05\x02\x03\x02\x08\x07\x06\x05\x00\x68\x00\x00\x0e\x0d\x10\x0f" "\x12\x11\x14\x13\x16\x15\x18\x17\x1a\x19\x1c\x1b\x1e\x1d\x20\x1f" "\x22\x21\x24\x23\x28\x27\x26\x25\x2c\x2b\x2a\x29\x30\x2f\x2e\x2d" "\x38\x37\x36\x35\x34\x33\x32\x31\x40\x3f\x3e\x3d\x3c\x3b\x3a\x39" "\x48\x47\x46\x45\x44\x43\x42\x41\x49\x4a\x4c\x4b\x4d\x4e\x4f\x50" "\x52\x51\x54\x53\x56\x55\x58\x57\x5c\x5b\x5a\x59\x60\x5f\x5e\x5d" "\x64\x63\x62\x61\x65\x00\x68\x67"; int exp_buf_len = 6*16+8; cmp(__LINE__, buf, buf_len_in, exp_buf, exp_buf_len); } // Decodes the generated packet: memory_zero(&det_out); xdr = xdr_new(buf, buf_len_in, xdr_DECODE); assert( xdr_dis_pdu(xdr, (dis_pdu *) &det_out) ); buf_len_out = xdr_getpos(xdr); xdr_free(xdr); // Compares the decoded data with the original data: assert(buf_len_out == buf_len_in); cmp(__LINE__, &det_out.hdr, sizeof(det_out.hdr), &det_in.hdr, sizeof(det_in.hdr)); cmp(__LINE__, &det_out.firing_id, sizeof(det_out.firing_id), &det_in.firing_id, sizeof(det_in.firing_id)); cmp(__LINE__, &det_out.target_id, sizeof(det_out.target_id), &det_in.target_id, sizeof(det_in.target_id)); cmp(__LINE__, &det_out.munition_id, sizeof(det_out.munition_id), &det_in.munition_id, sizeof(det_in.munition_id)); cmp(__LINE__, &det_out.event, sizeof(det_out.event), &det_in.event, sizeof(det_in.event)); cmp(__LINE__, &det_out.pos, sizeof(det_out.pos), &det_in.pos, sizeof(det_in.pos)); cmp(__LINE__, &det_out.burst, sizeof(det_out.burst), &det_in.burst, sizeof(det_in.burst)); cmp(__LINE__, &det_out.loc, sizeof(det_out.loc), &det_in.loc, sizeof(det_in.loc)); cmp(__LINE__, &det_out.result, sizeof(det_out.result), &det_in.result, sizeof(det_in.result)); cmp(__LINE__, &det_out.num_art_parms, sizeof(det_out.num_art_parms), &det_in.num_art_parms, sizeof(det_in.num_art_parms)); cmp(__LINE__, &det_out.pad, sizeof(det_out.pad), &det_in.pad, sizeof(det_in.pad)); cmp(__LINE__, &det_out.art_parm, sizeof(det_out.art_parm), &det_in.art_parm, sizeof(det_in.art_parm)); dis_freePDUComponents((dis_pdu *) &det_out); } static void test_dis_emission_pdu() { char buf[2000]; xdr_Type *xdr; int buf_len_in, buf_len_out; dis_em_emission_pdu em_in, em_out; dis_track_info tracked_target_in; dis_beam_info beam_in; dis_em_system_info system_in; fill(&em_in, sizeof(em_in)); em_in.hdr.protocol_version = DISProtocolVersionIEEE1278_95; em_in.hdr.pdu_type = PDUTypeEmission; // pkt offset 2 em_in.hdr.protocol_family = PDUFamilyDistributedEmissionRegeneration; // pkt offset 3 em_in.hdr.length = 0; // set below em_in.hdr.padding = 0; fill(&tracked_target_in, sizeof(tracked_target_in)); fill(&beam_in, sizeof(beam_in)); beam_in.num_targets = 1; beam_in.tracked_target = &tracked_target_in; fill(&system_in, sizeof(system_in)); system_in.num_beams = 1; system_in.beam = &beam_in; em_in.num_systems = 1; em_in.system = &system_in; dis_addPDUSizes((dis_pdu *) &em_in); xdr = xdr_new(buf, sizeof(buf), xdr_ENCODE); assert( xdr_dis_pdu(xdr, (dis_pdu *) &em_in) ); buf_len_in = xdr_getpos(xdr); xdr_free(xdr); /* * Now for a hack. We need to insert the correct packet length into * the PDU header. The header is somewhat stable from one protocol release * to the next, so I've just hard-coded it here. */ em_in.hdr.length = buf_len_in; *((u_short *) &buf[8]) = htons(buf_len_in); //printf("generated buf:\n"); printbuf(buf, buf_len_in); printf("\n"); if( IS_LITTLE_ENDIAN ){ // sorry, only little endian cpu here // Compares the generated packet with the expected one: char *exp_buf = "\x05\x02\x17\x06\x08\x07\x06\x05\x00\x6c\x00\x00\x0e\x0d\x10\x0f" "\x12\x11\x14\x13\x16\x15\x18\x17\x19\x01\x1c\x1b\x14\x01\x04\x03" "\x06\x05\x07\x08\x0c\x0b\x0a\x09\x10\x0f\x0e\x0d\x14\x13\x12\x11" "\x0f\x02\x04\x03\x08\x07\x06\x05\x0c\x0b\x0a\x09\x10\x0f\x0e\x0d" "\x14\x13\x12\x11\x18\x17\x16\x15\x1c\x1b\x1a\x19\x20\x1f\x1e\x1d" "\x24\x23\x22\x21\x28\x27\x26\x25\x2c\x2b\x2a\x29\x2d\x01\x2f\x30" "\x34\x33\x32\x31\x02\x01\x04\x03\x06\x05\x07\x08"; int exp_buf_len = 6*16+12; cmp(__LINE__, buf, buf_len_in, exp_buf, exp_buf_len); } // Decodes the generated packet: memory_zero(&em_out); xdr = xdr_new(buf, buf_len_in, xdr_DECODE); assert( xdr_dis_pdu(xdr, (dis_pdu *) &em_out) ); buf_len_out = xdr_getpos(xdr); xdr_free(xdr); // Compares the decoded data with the original data: assert(buf_len_out == buf_len_in); cmp(__LINE__, &em_out.hdr, sizeof(em_out.hdr), &em_in.hdr, sizeof(em_in.hdr)); cmp(__LINE__, &em_out.emitter_id, sizeof(em_out.emitter_id), &em_in.emitter_id, sizeof(em_in.emitter_id)); cmp(__LINE__, &em_out.event, sizeof(em_out.event), &em_in.event, sizeof(em_in.event)); cmp(__LINE__, &em_out.state_update, sizeof(em_out.state_update), &em_in.state_update, sizeof(em_in.state_update)); cmp(__LINE__, &em_out.num_systems, sizeof(em_out.num_systems), &em_in.num_systems, sizeof(em_in.num_systems)); //cmp(__LINE__, &em_out.pad, sizeof(em_out.pad), &em_in.pad, sizeof(em_in.pad)); cmp(__LINE__, &em_out.system[0].sys_data_length, sizeof(em_out.system[0].sys_data_length), &em_in.system[0].sys_data_length, sizeof(em_in.system[0].sys_data_length)); cmp(__LINE__, &em_out.system[0].num_beams, sizeof(em_out.system[0].num_beams), &em_in.system[0].num_beams, sizeof(em_in.system[0].num_beams)); cmp(__LINE__, &em_out.system[0].emitter_system, sizeof(em_out.system[0].emitter_system), &em_in.system[0].emitter_system, sizeof(em_in.system[0].emitter_system)); cmp(__LINE__, &em_out.system[0].location, sizeof(em_out.system[0].location), &em_in.system[0].location, sizeof(em_in.system[0].location)); dis_beam_info *beam_out = &em_out.system[0].beam[0]; cmp(__LINE__, &beam_out->beam_data_length, sizeof(beam_out->beam_data_length), &beam_out->beam_data_length, sizeof(beam_out->beam_data_length)); cmp(__LINE__, &beam_out->beam_id, sizeof(beam_out->beam_id), &beam_out->beam_id, sizeof(beam_out->beam_id)); cmp(__LINE__, &beam_out->beam_parm_index, sizeof(beam_out->beam_parm_index), &beam_out->beam_parm_index, sizeof(beam_out->beam_parm_index)); cmp(__LINE__, &beam_out->fundamental, sizeof(beam_out->fundamental), &beam_out->fundamental, sizeof(beam_out->fundamental)); cmp(__LINE__, &beam_out->beam_function, sizeof(beam_out->beam_function), &beam_out->beam_function, sizeof(beam_out->beam_function)); cmp(__LINE__, &beam_out->num_targets, sizeof(beam_out->num_targets), &beam_out->num_targets, sizeof(beam_out->num_targets)); cmp(__LINE__, &beam_out->high_density_track_jam, sizeof(beam_out->high_density_track_jam), &beam_out->high_density_track_jam, sizeof(beam_out->high_density_track_jam)); cmp(__LINE__, &beam_out->jamming_mode, sizeof(beam_out->jamming_mode), &beam_out->jamming_mode, sizeof(beam_out->jamming_mode)); dis_track_info *tracked_target_out = &beam_out->tracked_target[0]; cmp(__LINE__, &tracked_target_out->target, sizeof(tracked_target_out->target), &tracked_target_out->target, sizeof(tracked_target_out->target)); cmp(__LINE__, &tracked_target_out->emitter_id, sizeof(tracked_target_out->emitter_id), &tracked_target_out->emitter_id, sizeof(tracked_target_out->emitter_id)); cmp(__LINE__, &tracked_target_out->beam_id, sizeof(tracked_target_out->beam_id), &tracked_target_out->beam_id, sizeof(tracked_target_out->beam_id)); dis_freePDUComponents((dis_pdu *) &em_out); } static void test_dis_set_data_pdu() { xdr_Type *xdr; char buf[2000]; int buf_len_in, buf_len_out; dis_set_data_pdu sd_in, sd_out; dis_fixed_datum fixed_datum_in; dis_variable_datum variable_datum_in; fill(&sd_in, sizeof(sd_in)); sd_in.hdr.protocol_version = DISProtocolVersionIEEE1278_95; sd_in.hdr.pdu_type = PDUTypeSetData; // pkt offset 2 sd_in.hdr.protocol_family = PDUFamilySimulationManagement; // pkt offset 3 sd_in.hdr.length = 0; // set below sd_in.hdr.padding = 0; fill(&fixed_datum_in, sizeof(fixed_datum_in)); fill(&variable_datum_in, sizeof(variable_datum_in)); variable_datum_in.datum_id = datum_Name; /* * "The length field shall specify the length of the variable datum in bits. * The field of Variable Datum Value shall be padded at the end to make the * length a multiple of 64-bits." */ char *s = "AAAAAA"; variable_datum_in.value.ptr_value = (unsigned char *) s; variable_datum_in.value_length = 8*strlen(s); sd_in.datum_info.num_fixed_data = 1; sd_in.datum_info.num_variable_data = 1; sd_in.datum_info.fixed_datum = &fixed_datum_in; sd_in.datum_info.variable_datum = &variable_datum_in; xdr = xdr_new(buf, sizeof(buf), xdr_ENCODE); assert( xdr_dis_pdu(xdr, (dis_pdu *) &sd_in) ); buf_len_in = xdr_getpos(xdr); xdr_free(xdr); /* * Now for a hack. We need to insert the correct packet length into * the PDU header. The header is somewhat stable from one protocol release * to the next, so I've just hard-coded it here. */ sd_in.hdr.length = buf_len_in; *((u_short *) &buf[8]) = htons(buf_len_in); if( IS_LITTLE_ENDIAN ){ // sorry, only little endian cpu here // Compares the generated packet with the expected one: char *exp_buf = "\x05\x02\x13\x05\x08\x07\x06\x05\x00\x3c\x00\x00\x0e\x0d\x10\x0f" "\x12\x11\x14\x13\x16\x15\x18\x17\x1c\x1b\x1a\x19\x00\x00\x00\x01" "\x00\x00\x00\x01\x04\x03\x02\x01\x08\x07\x06\x05\x00\x00\xa8\x5c" "\x00\x00\x00\x30\x41\x41\x41\x41\x41\x41\x00\x00"; int exp_buf_len = 3*16+12; cmp(__LINE__, buf, buf_len_in, exp_buf, exp_buf_len); } // Decodes the generated packet: memory_zero(&sd_out); xdr = xdr_new(buf, buf_len_in, xdr_DECODE); assert( xdr_dis_pdu(xdr, (dis_pdu *) &sd_out) ); buf_len_out = xdr_getpos(xdr); xdr_free(xdr); // Compares the decoded data with the original data: assert(buf_len_out == buf_len_in); cmp(__LINE__, &sd_out.hdr, sizeof(sd_out.hdr), &sd_in.hdr, sizeof(sd_in.hdr)); cmp(__LINE__, &sd_out.orig_id, sizeof(sd_out.orig_id), &sd_in.orig_id, sizeof(sd_in.orig_id)); cmp(__LINE__, &sd_out.recv_id, sizeof(sd_out.recv_id), &sd_in.recv_id, sizeof(sd_in.recv_id)); cmp(__LINE__, &sd_out.request_id, sizeof(sd_out.request_id), &sd_in.request_id, sizeof(sd_in.request_id)); cmp(__LINE__, &sd_out.datum_info.num_fixed_data, sizeof(sd_out.datum_info.num_fixed_data), &sd_in.datum_info.num_fixed_data, sizeof(sd_in.datum_info.num_fixed_data)); cmp(__LINE__, &sd_out.datum_info.num_variable_data, sizeof(sd_out.datum_info.num_variable_data), &sd_in.datum_info.num_variable_data, sizeof(sd_in.datum_info.num_variable_data)); dis_fixed_datum *fixed_datum_out = sd_out.datum_info.fixed_datum; cmp(__LINE__, fixed_datum_out, sizeof(*fixed_datum_out), &fixed_datum_in, sizeof(fixed_datum_in)); dis_variable_datum *var_out = sd_out.datum_info.variable_datum; cmp(__LINE__, &var_out->datum_id, sizeof(var_out->datum_id), &variable_datum_in.datum_id, sizeof(variable_datum_in.datum_id)); cmp(__LINE__, &var_out->value_length, sizeof(var_out->value_length), &variable_datum_in.value_length, sizeof(variable_datum_in.value_length)); cmp(__LINE__, var_out->value.ptr_value, var_out->value_length/8, variable_datum_in.value.ptr_value, variable_datum_in.value_length/8); //printf("value=%8s..., len=%ju\n", var_out->value.ptr_value, // (uintmax_t) var_out->value_length); dis_freePDUComponents((dis_pdu *) &sd_out); } static void test_dis_stop_pdu() { xdr_Type *xdr; char buf[2000]; int buf_len_in, buf_len_out; dis_stop_pdu stop_in, stop_out; fill(&stop_in, sizeof(stop_in)); stop_in.hdr.protocol_version = DISProtocolVersionIEEE1278_95; stop_in.hdr.pdu_type = PDUTypeStopFreeze; // pkt offset 2 stop_in.hdr.protocol_family = PDUFamilySimulationManagement; // pkt offset 3 stop_in.hdr.length = 0; // set below stop_in.hdr.padding = 0; xdr = xdr_new(buf, sizeof(buf), xdr_ENCODE); assert( xdr_dis_pdu(xdr, (dis_pdu *) &stop_in) ); buf_len_in = xdr_getpos(xdr); xdr_free(xdr); /* * Now for a hack. We need to insert the correct packet length into * the PDU header. The header is somewhat stable from one protocol release * to the next, so I've just hard-coded it here. */ stop_in.hdr.length = buf_len_in; *((u_short *) &buf[8]) = htons(buf_len_in); if( IS_LITTLE_ENDIAN ){ // sorry, only little endian cpu here // Compares the generated packet with the expected one: char *exp_buf = "\x05\x02\x0e\x05\x08\x07\x06\x05\x00\x28\x00\x00\x0e\x0d\x10\x0f" "\x12\x11\x14\x13\x16\x15\x18\x17\x1c\x1b\x1a\x19\x20\x1f\x1e\x1d" "\x21\x22\x23\x24\x28\x27\x26\x25"; int exp_buf_len = 2*16+8; cmp(__LINE__, buf, buf_len_in, exp_buf, exp_buf_len); } // Decodes the generated packet: memory_zero(&stop_out); xdr = xdr_new(buf, buf_len_in, xdr_DECODE); assert( xdr_dis_pdu(xdr, (dis_pdu *) &stop_out) ); buf_len_out = xdr_getpos(xdr); xdr_free(xdr); // Compares the decoded data with the original data: assert(buf_len_out == buf_len_in); cmp(__LINE__, &stop_out.hdr, sizeof(stop_out.hdr), &stop_in.hdr, sizeof(stop_in.hdr)); cmp(__LINE__, &stop_out.orig_id, sizeof(stop_out.orig_id), &stop_in.orig_id, sizeof(stop_in.orig_id)); cmp(__LINE__, &stop_out.recv_id, sizeof(stop_out.recv_id), &stop_in.recv_id, sizeof(stop_in.recv_id)); cmp(__LINE__, &stop_out.real_time, sizeof(stop_out.real_time), &stop_in.real_time, sizeof(stop_in.real_time)); cmp(__LINE__, &stop_out.reason, sizeof(stop_out.reason), &stop_in.reason, sizeof(stop_in.reason)); cmp(__LINE__, &stop_out.behavior, sizeof(stop_out.behavior), &stop_in.behavior, sizeof(stop_in.behavior)); cmp(__LINE__, &stop_out.request_id, sizeof(stop_out.request_id), &stop_in.request_id, sizeof(stop_in.request_id)); dis_freePDUComponents((dis_pdu *) &stop_out); } static void test_dis_start_pdu() { xdr_Type *xdr; char buf[2000]; int buf_len_in, buf_len_out; dis_start_pdu start_in, start_out; fill(&start_in, sizeof(start_in)); start_in.hdr.protocol_version = DISProtocolVersionIEEE1278_95; start_in.hdr.pdu_type = PDUTypeStartResume; // pkt offset 2 start_in.hdr.protocol_family = PDUFamilySimulationManagement; // pkt offset 3 start_in.hdr.length = 0; // set below start_in.hdr.padding = 0; xdr = xdr_new(buf, sizeof(buf), xdr_ENCODE); assert( xdr_dis_pdu(xdr, (dis_pdu *) &start_in) ); buf_len_in = xdr_getpos(xdr); xdr_free(xdr); /* * Now for a hack. We need to insert the correct packet length into * the PDU header. The header is somewhat stable from one protocol release * to the next, so I've just hard-coded it here. */ start_in.hdr.length = buf_len_in; *((u_short *) &buf[8]) = htons(buf_len_in); if( IS_LITTLE_ENDIAN ){ // sorry, only little endian cpu here // Compares the generated packet with the expected one: char *exp_buf = "\x05\x02\x0d\x05\x08\x07\x06\x05\x00\x2c\x00\x00\x0e\x0d\x10\x0f" "\x12\x11\x14\x13\x16\x15\x18\x17\x1c\x1b\x1a\x19\x20\x1f\x1e\x1d" "\x24\x23\x22\x21\x28\x27\x26\x25\x2c\x2b\x2a\x29"; int exp_buf_len = 2*16+12; cmp(__LINE__, buf, buf_len_in, exp_buf, exp_buf_len); } // Decodes the generated packet: memory_zero(&start_out); xdr = xdr_new(buf, buf_len_in, xdr_DECODE); assert( xdr_dis_pdu(xdr, (dis_pdu *) &start_out) ); buf_len_out = xdr_getpos(xdr); xdr_free(xdr); // Compares the decoded data with the original data: assert(buf_len_out == buf_len_in); cmp(__LINE__, &start_out.hdr, sizeof(start_out.hdr), &start_in.hdr, sizeof(start_in.hdr)); cmp(__LINE__, &start_out.orig_id, sizeof(start_out.orig_id), &start_in.orig_id, sizeof(start_in.orig_id)); cmp(__LINE__, &start_out.recv_id, sizeof(start_out.recv_id), &start_in.recv_id, sizeof(start_in.recv_id)); cmp(__LINE__, &start_out.real_time, sizeof(start_out.real_time), &start_in.real_time, sizeof(start_in.real_time)); cmp(__LINE__, &start_out.sim_time, sizeof(start_out.sim_time), &start_in.sim_time, sizeof(start_in.sim_time)); cmp(__LINE__, &start_out.request_id, sizeof(start_out.request_id), &start_in.request_id, sizeof(start_in.request_id)); dis_freePDUComponents((dis_pdu *) &start_out); } static void test_dis_transfer_control_pdu() { xdr_Type *xdr; char buf[2000]; int buf_len_in, buf_len_out; dis_transfer_control_pdu tc_in, tc_out; fill(&tc_in, sizeof(tc_in)); tc_in.hdr.protocol_version = DISProtocolVersionIEEE1278_95; tc_in.hdr.pdu_type = PDUTypeTransferControl; // pkt offset 2 tc_in.hdr.protocol_family = PDUFamilyOther; // pkt offset 3 tc_in.hdr.length = 0; // set below tc_in.hdr.padding = 0; xdr = xdr_new(buf, sizeof(buf), xdr_ENCODE); assert( xdr_dis_pdu(xdr, (dis_pdu *) &tc_in) ); buf_len_in = xdr_getpos(xdr); xdr_free(xdr); /* * Now for a hack. We need to insert the correct packet length into * the PDU header. The header is somewhat stable from one protocol release * to the next, so I've just hard-coded it here. */ tc_in.hdr.length = buf_len_in; *((u_short *) &buf[8]) = htons(buf_len_in); if( IS_LITTLE_ENDIAN ){ // sorry, only little endian cpu here // Compares the generated packet with the expected one: char *exp_buf = "\x05\x02\x9c\x00\x08\x07\x06\x05\x00\x28\x00\x00\x0e\x0d\x10\x0f" "\x12\x11\x14\x13\x16\x15\x18\x17\x1c\x1b\x1a\x19\x1d\x1e\x20\x1f" "\x22\x21\x24\x23\x28\x27\x26\x25"; int exp_buf_len = 2*16+8; cmp(__LINE__, buf, buf_len_in, exp_buf, exp_buf_len); } // Decodes the generated packet: memory_zero(&tc_out); xdr = xdr_new(buf, buf_len_in, xdr_DECODE); assert( xdr_dis_pdu(xdr, (dis_pdu *) &tc_out) ); buf_len_out = xdr_getpos(xdr); xdr_free(xdr); // Compares the decoded data with the original data: assert(buf_len_out == buf_len_in); cmp(__LINE__, &tc_out.hdr, sizeof(tc_out.hdr), &tc_in.hdr, sizeof(tc_in.hdr)); cmp(__LINE__, &tc_out.orig_id, sizeof(tc_out.orig_id), &tc_in.orig_id, sizeof(tc_in.orig_id)); cmp(__LINE__, &tc_out.recv_id, sizeof(tc_out.recv_id), &tc_in.recv_id, sizeof(tc_in.recv_id)); cmp(__LINE__, &tc_out.request_id, sizeof(tc_out.request_id), &tc_in.request_id, sizeof(tc_in.request_id)); cmp(__LINE__, &tc_out.reliability_service, sizeof(tc_out.reliability_service), &tc_in.reliability_service, sizeof(tc_in.reliability_service)); cmp(__LINE__, &tc_out.transfer_type, sizeof(tc_out.transfer_type), &tc_in.transfer_type, sizeof(tc_in.transfer_type)); cmp(__LINE__, &tc_out.target_id, sizeof(tc_out.target_id), &tc_in.target_id, sizeof(tc_in.target_id)); cmp(__LINE__, &tc_out.num_record_sets, sizeof(tc_out.num_record_sets), &tc_in.num_record_sets, sizeof(tc_in.num_record_sets)); dis_freePDUComponents((dis_pdu *) &tc_out); } static void test_dis_acknowledge_pdu() { xdr_Type *xdr; char buf[2000]; int buf_len_in, buf_len_out; dis_acknowledge_pdu ack_in, ack_out; fill(&ack_in, sizeof(ack_in)); ack_in.hdr.protocol_version = DISProtocolVersionIEEE1278_95; ack_in.hdr.pdu_type = PDUTypeAcknowledge; // pkt offset 2 ack_in.hdr.protocol_family = PDUFamilySimulationManagement; // pkt offset 3 ack_in.hdr.length = 0; // set below ack_in.hdr.padding = 0; xdr = xdr_new(buf, sizeof(buf), xdr_ENCODE); assert( xdr_dis_pdu(xdr, (dis_pdu *) &ack_in) ); buf_len_in = xdr_getpos(xdr); xdr_free(xdr); /* * Now for a hack. We need to insert the correct packet length into * the PDU header. The header is somewhat stable from one protocol release * to the next, so I've just hard-coded it here. */ ack_in.hdr.length = buf_len_in; *((u_short *) &buf[8]) = htons(buf_len_in); if( IS_LITTLE_ENDIAN ){ // sorry, only little endian cpu here // Compares the generated packet with the expected one: char *exp_buf = "\x05\x02\x0f\x05\x08\x07\x06\x05\x00\x20\x00\x00\x0e\x0d\x10\x0f" "\x12\x11\x14\x13\x16\x15\x18\x17\x1a\x19\x1c\x1b\x20\x1f\x1e\x1d"; int exp_buf_len = 2*16; cmp(__LINE__, buf, buf_len_in, exp_buf, exp_buf_len); } // Decodes the generated packet: memory_zero(&ack_out); xdr = xdr_new(buf, buf_len_in, xdr_DECODE); assert( xdr_dis_pdu(xdr, (dis_pdu *) &ack_out) ); buf_len_out = xdr_getpos(xdr); xdr_free(xdr); // Compares the decoded data with the original data: assert(buf_len_out == buf_len_in); cmp(__LINE__, &ack_out.hdr, sizeof(ack_out.hdr), &ack_in.hdr, sizeof(ack_in.hdr)); cmp(__LINE__, &ack_out.orig_id, sizeof(ack_out.orig_id), &ack_in.orig_id, sizeof(ack_in.orig_id)); cmp(__LINE__, &ack_out.recv_id, sizeof(ack_out.recv_id), &ack_in.recv_id, sizeof(ack_in.recv_id)); cmp(__LINE__, &ack_out.acknowledge_flag, sizeof(ack_out.acknowledge_flag), &ack_in.acknowledge_flag, sizeof(ack_in.acknowledge_flag)); cmp(__LINE__, &ack_out.resp_flag, sizeof(ack_out.resp_flag), &ack_in.resp_flag, sizeof(ack_in.resp_flag)); cmp(__LINE__, &ack_out.request_id, sizeof(ack_out.request_id), &ack_in.request_id, sizeof(ack_in.request_id)); dis_freePDUComponents((dis_pdu *) &ack_out); } static void test_dis_comment_pdu() { xdr_Type *xdr; char buf[2000]; int buf_len_in, buf_len_out; dis_comment_pdu msg_in, msg_out; dis_fixed_datum fixed_datum_in; dis_variable_datum variable_datum_in; fill(&msg_in, sizeof(msg_in)); msg_in.hdr.protocol_version = DISProtocolVersionIEEE1278_95; msg_in.hdr.pdu_type = PDUTypeComment; // pkt offset 2 msg_in.hdr.protocol_family = PDUFamilySimulationManagement; // pkt offset 3 msg_in.hdr.length = 0; // set below msg_in.hdr.padding = 0; msg_in.num_fixed_data = 1; fill(&fixed_datum_in, sizeof(fixed_datum_in)); msg_in.fixed_datum = &fixed_datum_in; msg_in.num_variable_data = 1; msg_in.variable_datum = &variable_datum_in; variable_datum_in.datum_id = datum_Name; /* * "The length field shall specify the length of the variable datum in bits. * The field of Variable Datum Value shall be padded at the end to make the * length a multiple of 64-bits." */ char *s = "AAAAAAAA"; variable_datum_in.value.ptr_value = (unsigned char *) s; variable_datum_in.value_length = 8*strlen(s); xdr = xdr_new(buf, sizeof(buf), xdr_ENCODE); assert( xdr_dis_pdu(xdr, (dis_pdu *) &msg_in) ); buf_len_in = xdr_getpos(xdr); xdr_free(xdr); /* * Now for a hack. We need to insert the correct packet length into * the PDU header. The header is somewhat stable from one protocol release * to the next, so I've just hard-coded it here. */ msg_in.hdr.length = buf_len_in; *((u_short *) &buf[8]) = htons(buf_len_in); if( IS_LITTLE_ENDIAN ){ // sorry, only little endian cpu here // Compares the generated packet with the expected one: char *exp_buf = "\x05\x02\x16\x05\x08\x07\x06\x05\x00\x38\x00\x00\x0e\x0d\x10\x0f" "\x12\x11\x14\x13\x16\x15\x18\x17\x00\x00\x00\x01\x00\x00\x00\x01" "\x04\x03\x02\x01\x08\x07\x06\x05\x00\x00\xa8\x5c\x00\x00\x00\x40" "\x41\x41\x41\x41\x41\x41\x41\x41"; int exp_buf_len = 3*16 + 8; cmp(__LINE__, buf, buf_len_in, exp_buf, exp_buf_len); } // Decodes the generated packet: memory_zero(&msg_out); xdr = xdr_new(buf, buf_len_in, xdr_DECODE); assert( xdr_dis_pdu(xdr, (dis_pdu *) &msg_out) ); buf_len_out = xdr_getpos(xdr); xdr_free(xdr); // Compares the decoded data with the original data: assert(buf_len_out == buf_len_in); cmp(__LINE__, &msg_out.hdr, sizeof(msg_out.hdr), &msg_in.hdr, sizeof(msg_in.hdr)); cmp(__LINE__, &msg_out.orig_id, sizeof(msg_out.orig_id), &msg_in.orig_id, sizeof(msg_in.orig_id)); cmp(__LINE__, &msg_out.recv_id, sizeof(msg_out.recv_id), &msg_in.recv_id, sizeof(msg_in.recv_id)); cmp(__LINE__, &msg_out.num_fixed_data, sizeof(msg_out.num_fixed_data), &msg_in.num_fixed_data, sizeof(msg_in.num_fixed_data)); cmp(__LINE__, &msg_out.num_variable_data, sizeof(msg_out.num_variable_data), &msg_in.num_variable_data, sizeof(msg_in.num_variable_data)); dis_fixed_datum *fixed_datum_out = msg_out.fixed_datum; cmp(__LINE__, &fixed_datum_out->datum_id, sizeof(fixed_datum_out->datum_id), &fixed_datum_in.datum_id, sizeof(fixed_datum_in.datum_id)); cmp(__LINE__, &fixed_datum_out->value, sizeof(fixed_datum_out->value), &fixed_datum_in.value, sizeof(fixed_datum_in.value)); dis_variable_datum *variable_datum_out = &msg_out.variable_datum[0]; cmp(__LINE__, &variable_datum_out->datum_id, sizeof(variable_datum_out->datum_id), &variable_datum_in.datum_id, sizeof(variable_datum_in.datum_id)); cmp(__LINE__, &variable_datum_out->value_length, sizeof(variable_datum_out->value_length), &variable_datum_in.value_length, sizeof(variable_datum_in.value_length)); cmp(__LINE__, variable_datum_out->value.ptr_value, variable_datum_out->value_length/8, variable_datum_in.value.ptr_value, variable_datum_in.value_length/8); dis_freePDUComponents((dis_pdu *) &msg_out); } int main(int argc, char** argv) { error_prog_name = argv[0]; test_dis_entity_state_pdu(); test_dis_fire_pdu(); test_dis_detonation_pdu(); test_dis_emission_pdu(); test_dis_set_data_pdu(); test_dis_stop_pdu(); test_dis_start_pdu(); test_dis_transfer_control_pdu(); test_dis_acknowledge_pdu(); test_dis_comment_pdu(); err += memory_report(); return err == 0? 0 : 1; } acm-6.0_20200416/test/dis/dis/earth-test.c0000644000000000000000000001353413172245454016351 0ustar rootroot/* * Test code for the 'earth' module. * Exits with status code 0 on success, 1 on failure. */ #include #include #include #include #include "../../../src/dis/dis/earth.h" #include "../../../src/util/units.h" #include "../../../src/util/memory.h" static int err = 0; #ifdef xxxxxxxxxxxxxxxxxxxxxx void earth_XYZToLatLonAlt(VPoint * loc, earth_LatLonAlt * p) { double a2 = earth_MAJOR * earth_MAJOR; double e4 = earth_ECCENTRICITY_SQR * earth_ECCENTRICITY_SQR; double zeta = (1 - earth_ECCENTRICITY_SQR) * loc->z / a2; double p2 = loc->x * loc->x + loc->y * loc->y; double p = sqrt(p); double rho = (p2 / a2 + zeta - e4) / 6; double s = e4 * zeta * p2 / (4 * a2); double t = pow(rho*rho*rho + s + sqrt(s*(s+2*rho*rho*rho))); double u = rho + t + rho*rho/t; double v = sqrt(u*u + e4*zeta); double w = earth_ECCENTRICITY_SQR*(u+v-zeta)/(2*v); double k = 1 + earth_ECCENTRICITY_SQR*(sqrt(u+v+w*w) + w) / (u+v); p->latitude = atan2(k*loc->z, w); p->longitude = atan2(loc->y, loc->x); p->z = 1; } #endif /** * Check numerical conversions of Cartesian to geographic coordinates back and forth. */ static void coordsConversionsTest(int line) { double latitude_deg, longitude_deg; double z = 1000.0; for(latitude_deg = -80; latitude_deg <= 80; latitude_deg += 10){ for(longitude_deg = -180; longitude_deg <= 180; longitude_deg += 10){ // Converts geographic to Cartesian: earth_LatLonAlt geographic; geographic.latitude = units_DEGtoRAD(latitude_deg); geographic.longitude = units_DEGtoRAD(longitude_deg); geographic.z = z; VPoint cartesian; earth_LatLonAltToXYZ(&geographic, &cartesian); // Convert back to geographic: earth_LatLonAlt geographic2; earth_XYZToLatLonAlt(&cartesian, &geographic2); // Evaluate error on the resulting geographic coordinates: double err_latitude_deg = units_RADtoDEG(geographic2.latitude - geographic.latitude); double err_longitude_deg = units_RADtoDEG(geographic2.longitude - geographic.longitude); double err_z = geographic2.z - geographic.z; if( fabs(err_latitude_deg) > 1e-6 // about 0.1 m || fabs(err_longitude_deg) > 1e-6 // about 0.1 m || fabs(err_z) > 0.1){ err++; printf("in line %d, %g,%g,%g --> %g,%g,%g (err: %g,%g,%g)\n", line, units_RADtoDEG(geographic.latitude), units_RADtoDEG(geographic.longitude), geographic.z, units_RADtoDEG(geographic2.latitude), units_RADtoDEG(geographic2.longitude), geographic2.z, err_latitude_deg, err_longitude_deg, err_z ); } } } } static double sqr(double x) { return x * x; } static double distance(earth_LatLonAlt *a, earth_LatLonAlt *b) { VPoint p, q; earth_LatLonAltToXYZ(a, &p); earth_LatLonAltToXYZ(b, &q); return sqrt( sqr(p.x - q.x) + sqr(p.y - q.y) + sqr(p.z - q.z) ); } /** * Testing Cartesian to geographic string conversion forth and back. * Testing earth_updateLatLon(). */ static void test_conversions(int line, VPoint *xyz, char *exp_xyz, char *exp_geo) { char xyz_s[99]; VPoint xyz2; char xyz2_s[99]; earth_LatLonAlt geo; char geo_s[99]; earth_LatLonAlt geo2; char geo2_s[99]; double step, delta; /* Convert Cartesian to string and check: */ earth_XYZToString(xyz_s, sizeof(xyz_s), xyz); if( strcmp(xyz_s, exp_xyz) != 0 ){ err++; printf("in line %d formatted Cartesian:\n\tgot: %s\n\texp: %s\n", line, xyz_s, exp_xyz); } /* Convert Cartesian to geographic and check: */ earth_XYZToLatLonAlt(xyz, &geo); earth_LatLonAltToString(geo_s, sizeof(geo_s), &geo, earth_LLM_D); if( strcmp(geo_s, exp_geo) != 0 ){ err++; printf("in line %d converting to geographic:\n\tgot: %s\n\texp: %s\n", line, geo_s, exp_geo); printf("lon=%g\n", geo.longitude); } /* Convert back geographic to Cartesian and check: */ earth_LatLonAltToXYZ(&geo, &xyz2); earth_XYZToString(xyz2_s, sizeof(xyz2_s), &xyz2); if( strcmp(xyz2_s, exp_xyz) != 0 ){ err++; printf("in line %d converting back to Cartesian:\n\tgot: %s\n\texp: %s\n", line, xyz2_s, exp_xyz); } /* * Move E, N, S, W, returning to the same point. * FIXME: Skip this test near the poles because the behavior of * earth_updateLatLon() is undefined there and the result are completely * random numbers. */ if( fabs(geo.latitude) < units_DEGtoRAD(89) ){ geo2 = geo; step = units_NMtoMETERS(120); earth_updateLatLon(&geo2, 0.0, 1.0, step); earth_updateLatLon(&geo2, 1.0, 0.0, step); earth_updateLatLon(&geo2, -1.0, 0.0, step); earth_updateLatLon(&geo2, 0.0, -1.0, step); delta = distance(&geo2, &geo); if( delta > 10.0 /* m */ ){ earth_LatLonAltToString(geo2_s, sizeof(geo2_s), &geo2, earth_LLM_D); err++; printf("in line %d after a closed loop:\n\tgot: %s\n\texp: %s\n\tdst: %g m\n", line, geo2_s, geo_s, delta); } } } int main() { coordsConversionsTest(__LINE__); VPoint xyz; //parser_test(); /* North pole, sea level: */ xyz.x = 0.0; xyz.y = 0.0; xyz.z = earth_MINOR; test_conversions(__LINE__, &xyz, "0 m, 0 m, 6356752 m", "90.0 N 0.0 E 0 m"); /* South pole, sea level: */ xyz.x = 0.0; xyz.y = 0.0; xyz.z = - earth_MINOR; test_conversions(__LINE__, &xyz, "0 m, 0 m, -6356752 m", "90.0 S 0.0 E 0 m"); /* Greenwich crossing equator: */ xyz.x = earth_MAJOR; xyz.y = 0.0; xyz.z = 0.0; test_conversions(__LINE__, &xyz, "6378137 m, 0 m, 0 m", "0.0 N 0.0 E 0 m"); /* 90E meridian crossing equator: */ xyz.x = 0.0; xyz.y = earth_MAJOR; xyz.z = 0.0; test_conversions(__LINE__, &xyz, "0 m, 6378137 m, 0 m", "0.0 N 90.0 E 0 m"); /* 180E meridian crossing equator: */ xyz.x = - earth_MAJOR; xyz.y = 0.0; xyz.z = 0.0; test_conversions(__LINE__, &xyz, "-6378137 m, 0 m, 0 m", "0.0 N 180.0 E 0 m"); /* 90W meridian crossing equator: */ xyz.x = 0.0; xyz.y = - earth_MAJOR; xyz.z = 0.0; test_conversions(__LINE__, &xyz, "0 m, -6378137 m, 0 m", "0.0 N 90.0 W 0 m"); err += memory_report(); return err == 0? 0 : 1; }acm-6.0_20200416/test/dis/Makefile0000644000000000000000000000064713106475701015004 0ustar rootroot# This file generated by make-makefile, do not edit! # Create Makefile-include.txt instead for your customizations. CC := gcc CFLAGS := -Wall -Werror -g -fmax-errors=99 -Wuninitialized -Wmissing-prototypes -Wredundant-decls LIBS := .PHONY: all all: cd ./dis && make all #include Makefile-include.txt .PHONY: clean clean: rm -f *.o *.exe *.stackdump cd ./dis && make clean # Checksum of the original file: 2754672170 acm-6.0_20200416/test/V/0000755000000000000000000000000013175511160012757 5ustar rootrootacm-6.0_20200416/test/V/animate.c0000644000000000000000000001752113260344465014556 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991,1992 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /* FIXME: what this test program should do? */ #include #include #include #include static char *id = "V library animation test -- Riley Rainey"; #define STRING "V library test" #define BORDER 1 #define FONT "fixed" #define ARG_FONT "font" #define ARG_BORDER_COLOR "borderColor" #define ARG_BACKGROUND "background" #define ARG_BORDER "borderWidth" #define ARG_GEOMETRY "geometry" #define DEFAULT_BACKGROUND "#29350B" #define DEFAULT_BORDER "black" #define SW_BORDER 1 #define SW_BG 3 #define SW_GEOM 4 struct { char *sw; int value; } switches[] = { "-bw", SW_BORDER, "-bg", SW_BG, "-geometry", SW_GEOM, NULL, 0}, *swp; char *background = NULL, *filename; int borderWidth = 1; int mono; /* * This structure forms the WM_HINTS property of the window, * letting the window manager know how to handle this window. * See Section 9.1 of the Xlib manual. */ XWMHints xwmh = { (InputHint|StateHint), /* flags */ False, /* input */ NormalState, /* initial_state */ 0, /* icon pixmap */ 0, /* icon window */ 0, 0, /* icon location */ 0, /* icon mask */ 0, /* Window group */ }; Display *dpy; /* X server connection */ Window win; /* Window ID */ GC gc; /* GC to draw with */ XGCValues gcv; XSizeHints xsh; /* Size hints for window manager */ Colormap cmap; static unsigned long planemask [6]; /* plane masks from XAllocColorCells */ static unsigned long pixels [16]; /* pixel values from XAllocColorCells */ GC curGC; main(argc,argv) int argc; char **argv; { char *fontName; /* Name of font for string */ XFontStruct *fontstruct; /* Font descriptor */ unsigned long ftw, fth, pad;/* Font size parameters */ unsigned long bg, bd; /* Pixel values */ unsigned long bw; /* Border width */ char *tempstr; /* Temporary string */ XColor color; /* Temporary color */ char *geomSpec = NULL;/* Window geometry string */ XSetWindowAttributes xswa; /* Temporary Set Window Attribute struct */ char **c; /* * Parse command line */ for (c= &argv[1]; *c != (char *) NULL; ++c) if (**c == '-') { for (swp= &switches[0]; swp->value != 0; ++swp) if (strcmp (swp->sw, *c) == 0) { switch (swp->value) { case SW_GEOM: geomSpec = *(++c); break; case SW_BG: background = *(++c); break; case SW_BORDER: borderWidth = atoi (*(++c)); break; } break; } if (swp->value == 0) { fprintf (stderr, "%s: invalid switch %s", argv[0], *c); exit (1); } } else filename = *c; /* * Open the display using the $DISPLAY environment variable to locate * the X server. See Section 2.1. */ if ((dpy = XOpenDisplay(NULL)) == NULL) { fprintf(stderr, "%s: can't open %s\n", argv[0], XDisplayName(NULL)); exit(1); } mono = (DisplayPlanes(dpy, 0) < 2) ? 1 : 0; /* * Load the font to use. See Sections 10.2 & 6.5.1 */ if ((fontName = XGetDefault(dpy, argv[0], ARG_FONT)) == NULL) { fontName = FONT; } if ((fontstruct = XLoadQueryFont(dpy, fontName)) == NULL) { fprintf(stderr, "%s: display %s doesn't know font %s\n", argv[0], DisplayString(dpy), fontName); exit(1); } fth = fontstruct->max_bounds.ascent + fontstruct->max_bounds.descent; ftw = fontstruct->max_bounds.width; /* * Select colors for the border, the window background, and the * foreground. We use the default colormap to allocate the colors in. * See Sections 2.2.1, 5.1.2, & 10.4. */ cmap = DefaultColormap(dpy, DefaultScreen(dpy)); if ((tempstr = XGetDefault(dpy, argv[0], ARG_BORDER_COLOR)) == NULL) tempstr = DEFAULT_BORDER; if (XParseColor(dpy, cmap, tempstr, &color) == 0) { fprintf (stderr, "Can't get border color %s\n", tempstr); exit (1); } bd = color.pixel; /* * Allocate Color Planes and one extra cell for the border color. */ if (mono == 0) if (XAllocColorCells (dpy, cmap, False, planemask, 0, pixels, 1) == 0) { fprintf (stderr, "Cannot allocate color cells\n"); exit (1); } bg = WhitePixel (dpy, 0); /* * Store border color */ if (mono) bd = BlackPixel (dpy, 0); else { bd = color.pixel = pixels [0]; XStoreColor (dpy, cmap, &color); } /* * Background Color (pixels [0] defines this). */ if (background == NULL) background = XGetDefault (dpy, argv[0], ARG_BACKGROUND); if (background == NULL) background = DEFAULT_BACKGROUND; /* * Set the border width of the window, and the gap between the text * and the edge of the window, "pad". */ pad = BORDER; if ((tempstr = XGetDefault(dpy, argv[0], ARG_BORDER)) == NULL) bw = 1; else bw = atoi(tempstr); /* * Deal with providing the window with an initial position & size. * Fill out the XSizeHints struct to inform the window manager. See * Sections 9.1.6 & 10.3. */ if (geomSpec == NULL) geomSpec = XGetDefault(dpy, argv[0], ARG_GEOMETRY); if (geomSpec == NULL) { /* * The defaults database doesn't contain a specification of the * initial size & position - fit the window to the text and locate * it in the center of the screen. */ xsh.flags = (PPosition | PSize); xsh.height = 499; xsh.width = 1200; xsh.x = (DisplayWidth(dpy, DefaultScreen(dpy)) - xsh.width) / 2; xsh.y = (DisplayHeight(dpy, DefaultScreen(dpy)) - xsh.height) / 2; } else { int bitmask; memset(&xsh, 0, sizeof(xsh)); bitmask = XGeometry(dpy, DefaultScreen(dpy), geomSpec, geomSpec, bw, ftw, fth, pad, pad, &(xsh.x), &(xsh.y), &(xsh.width), &(xsh.height)); if (bitmask & (XValue | YValue)) { xsh.flags |= USPosition; } if (bitmask & (WidthValue | HeightValue)) { xsh.flags |= USSize; } } /* * Create the Window with the information in the XSizeHints, the * border width, and the border & background pixels. See Section 3.3. */ win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), xsh.x, xsh.y, xsh.width, xsh.height, bw, bd, bg); /* * Set the standard properties for the window managers. See Section * 9.1. */ XSetStandardProperties(dpy, win, STRING, STRING, None, argv, argc, &xsh); XSetWMHints(dpy, win, &xwmh); /* * Ensure that the window's colormap field points to the default * colormap, so that the window manager knows the correct colormap to * use for the window. See Section 3.2.9. Also, set the window's Bit * Gravity to reduce Expose events. */ xswa.colormap = DefaultColormap(dpy, DefaultScreen(dpy)); xswa.bit_gravity = NorthWestGravity; XChangeWindowAttributes(dpy, win, (CWColormap | CWBitGravity), &xswa); /* * Create the GC for drawing the picture. */ gcv.font = fontstruct->fid; curGC = XCreateGC(dpy, win, GCFont, &gcv); /* * Specify the event types we're interested in - only Exposures. See * Sections 8.5 & 8.4.5.1 */ XSelectInput(dpy, win, ExposureMask); /* * Map the window to make it visible. See Section 3.5. */ XMapWindow(dpy, win); app(background); exit(1); } acm-6.0_20200416/test/V/app.c0000644000000000000000000002117213067725727013726 0ustar rootroot/* * acm : an aerial combat simulator for X * Copyright (C) 1991,1992 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ /* FIXME: what this test program should do? */ #include "../../src/V/Vlib.h" #include #include #include #define VIEW1 extern Display *dpy; extern Window win; extern GC curGC; extern XSizeHints xsh; extern int mono; VPolygon *poly[2048]; double lastTime = 1000.0; double frameCount = 0.0; double minInterval = 10000.0; double maxInterval = 0.0; double elapsedTotal = 0.0; static VPoint origin = { 0.0, 0.0, 0.0 }; void TimeIntervalAccounting() { struct itimerval itv; double thisTime, elapsedTime; getitimer (ITIMER_REAL, &itv); thisTime = (double) itv.it_value.tv_sec + (double) itv.it_value.tv_usec / 1000000.0; elapsedTime = lastTime - thisTime; if (elapsedTime > maxInterval) maxInterval = elapsedTime; if (elapsedTime < minInterval) minInterval = elapsedTime; elapsedTotal += elapsedTime; frameCount += 1; lastTime = thisTime; } void PrintStatistics () { printf ("Total time for %g frames was %g seconds.\n\n", frameCount, elapsedTotal); printf ("Average frame rate was %g frames per second\n", frameCount / elapsedTotal); printf ("Maximum frame rate was %g frames per second\n", 1.0 / minInterval); printf ("Minimum frame rate was %g frames per second\n", 1.0 / maxInterval); } VPoint *normal; Viewport *vx; void placeObject (v, obj, loc, roll, pitch, yaw, poly, cnt) Viewport *v; VObject *obj; VPoint loc; double roll; double pitch; double yaw; VPolygon **poly; int *cnt; { int i, j, k, offset, aspect, n; VPoint *q, tmp, center, nc; VMatrix mtx, mtx1; register double dist; VPolygon **p; j = *cnt; VIdentMatrix (&mtx); if (roll != 0.0) VRotate (&mtx, XRotation, roll); if (pitch != 0.0) VRotate (&mtx, YRotation, pitch); if (yaw != 0.0) VRotate (&mtx, ZRotation, yaw); VTranslatePoint (&mtx, loc); VMatrixMult (&mtx, &v->eyeSpace, &mtx1); VTransform (&obj->center, &mtx, &tmp); VTransform (&tmp, &v->eyeSpace, ¢er); for (i=0; i<4; ++i) { dist = VPointToClipPlaneDistance (¢er, &(normal[i])); if (dist > obj->extent) { return; } } n = obj->numPolys; p = obj->polygon; if (obj->order) { VTransform (&origin, &mtx1, &nc); VTransform_ (&_VUnitVectorI, &mtx1, &obj->xaxis); VTransform_ (&_VUnitVectorJ, &mtx1, &obj->yaxis); VTransform_ (&_VUnitVectorK, &mtx1, &obj->zaxis); aspect = VComputeObjectAspect (obj, &nc); #ifdef notdef printf ("%s: %s\n", obj->name, VGetAspectName(aspect)); #endif offset = aspect * n; } for (i=0; iorder) ? VCopyPolygon(p[obj->order[offset + i]]) : VCopyPolygon(p[i]); for ((k=0, q=poly[j]->vertex); knumVtces; (++k, ++q)) { VTransform(q, &mtx1, &tmp); *q = tmp; } if (poly[j]->flags & PolyNormalValid) { VTransform_ (&poly[j]->normal, &mtx1, &tmp); poly[j]->normal = tmp; } ++j; } *cnt = j; } app(background) char *background; { int i, cnt, black; unsigned int j, curPixel = 0; char *str; FILE *file; VObject *obj, *ftr, *mig; VPoint viewPt, centerInt, up, ftrLoc, ftrLoc2, ftrLoc3, migLoc1, migLoc2; Viewport *v; double dist, p, migV, v1, a, migRoll; double updateRate = 10.0; Colormap cmap; long screen; ZInfo z; VColor *vsky; unsigned long skypixel; struct itimerval timeval; XSegment seg[2]; str = "../../objects/rwy-and-gnd.obv"; if ((file = fopen(str, "r")) == (FILE *) NULL) { perror ("Cannot open object file"); exit (1); } if ((obj = VReadObject(file)) == (VObject *) NULL) { fprintf (stderr, "Error reading the object definition.\n"); exit (1); } fclose (file); str = "../../objects/f16.obv"; if ((file = fopen(str, "r")) == (FILE *) NULL) { perror ("Cannot open object file"); exit (1); } if ((ftr = VReadObject(file)) == (VObject *) NULL) { fprintf (stderr, "Error reading the object definition.\n"); exit (1); } fclose (file); str = "../../objects/mig29.obv"; if ((file = fopen(str, "r")) == (FILE *) NULL) { perror ("Cannot open object file"); exit (1); } if ((mig = VReadObject(file)) == (VObject *) NULL) { fprintf (stderr, "Error reading the object definition.\n"); exit (1); } fclose (file); _VDefaultWorkContext->usePixmaps = 0; screen = DefaultScreen (dpy); cmap = DefaultColormap (dpy, screen); v = VOpenViewport (dpy, screen, win, cmap, DefaultVisual (dpy, screen), UNITS_FEET, 1.5, 1.0, xsh.width, xsh.height); normal = v->clipNormals; vx = v; vsky = VAllocColor ("skyblue"); if (VBindColors (v, background) < 0) { fprintf (stderr, "Error in binding colors.\n"); exit (1); } skypixel = v->pixel[vsky->cIndex]; ftrLoc.x = 80.0; ftrLoc.y = -110.0; ftrLoc.z = -7.0; ftrLoc2.x = 475.0; ftrLoc2.y = 3.7; ftrLoc2.z = -7.0; migLoc1.z = -310.0; migLoc2.z = -320.0; migV = 370.0 / 3600.0 * 5280.0 / updateRate; /* mig speed in fps */ migV = migV / (2500.0 * 3.14 * 2.0); /* mig speed in rad/update */ migRoll = 28.0 * 3.14 / 180.0; a = 90.0 * 3.14 / 180.0; v1 = 130.0 / 3600.0 * 5280.0 / updateRate; centerInt.x = 80.0; centerInt.y = -90.0; centerInt.z = -6.0; dist = -10000.0; p = 0; getitimer (ITIMER_REAL, &timeval); timeval.it_value.tv_sec = 1000; timeval.it_value.tv_usec = 0; setitimer (ITIMER_REAL, &timeval, (struct itimerval *) NULL); mono = 0; while (1) { if (mono == 0) { z.depth = MaxDepth; z.color = skypixel; FillRectangle (v->w, 0, 0, xsh.width, xsh.height, &z); } ftrLoc3.x = dist+150.0; ftrLoc3.y = -15.0; ftrLoc3.z = (dist+150.0) * 50.0 / 1000.0 - 40.0; if (ftrLoc3.z > -13.0) ftrLoc3.z = -13.0; viewPt.x = dist; viewPt.y = 15.0; viewPt.z = dist * 50.0 / 1000.0 - 50.0; if (viewPt.z > -13.0) viewPt.z = -13.0; up = viewPt; up.z = up.z - 1.0; if (viewPt.z < -14.0) up.y = up.y + 0.1 * sin(p); p = p + 0.03; dist = dist + v1; if (dist > 10000.0) { PrintStatistics (); exit (0); } migLoc1.x = 0.0 + 2200.0 * cos (a); migLoc1.y = -800.0 + 2200.0 * sin (a); migLoc2.x = 0.0 + 2225.0 * cos (a-0.04); migLoc2.y = -800.0 + 2225.0 * sin (a-0.04); a = a + migV; /* * Calculate eye space information based on our current viewpoint. */ #ifdef VIEW1 VGetEyeSpace (v, viewPt, centerInt, up); #endif #ifdef VIEW2 up = migLoc2; up.z = up.z - 1.0; VGetEyeSpace (v, migLoc2, viewPt, up); #endif #ifdef VIEW3 up = ftrLoc; up.z = up.z - 1.0; VGetEyeSpace (v, ftrLoc, viewPt, up); #endif /* * Now create a vector containing all polygons from the objects. */ cnt = 0; placeObject (v, obj, origin, 0.0, 0.0, 0.0, poly, &cnt); #ifndef VIEW3 placeObject (v, ftr, ftrLoc, 0.0, 0.0, 90.0*3.14/180.0, poly, &cnt); #endif placeObject (v, ftr, ftrLoc2, 0.0, 0.0, -3.0*3.14/180.0, poly, &cnt); placeObject (v, ftr, ftrLoc3, 0.0, -11.0*3.14/180.0, 0.0, poly, &cnt); #ifndef VIEW1 placeObject (v, ftr, viewPt, 0.0, -11.0*3.14/180.0, 0.0, poly, &cnt); #endif placeObject (v, mig, migLoc1, migRoll, 0.0, a+90.0*3.14/180.0, poly, &cnt); #ifndef VIEW2 placeObject (v, mig, migLoc2, migRoll, 0.0, a+90.0*3.14/180.0, poly, &cnt); #endif black = BlackPixel(dpy, 0); /* * First clip, then draw each polygon. */ for (i=0; iclipPoly); if (poly[i]) { #ifdef notdef if (mono == 0 && curPixel != (j=v->pixel[poly[i]->color->cIndex])) { XSetForeground (dpy, curGC, j); curPixel = j; } #endif if (mono) VDrawPolygon (v, win, curGC, poly[i]); else VFillPolygon (v, win, curGC, poly[i]); } } VExposeBuffer (v, curGC); TimeIntervalAccounting(); /* * Erase the un-displayed planes. */ #ifdef notdef if (mono == 0) { curPixel = *(v->pixel); XSetForeground (dpy, curGC, curPixel); if ( _VDefaultWorkContext->usePixmaps == 1) XFillRectangle (dpy, v->monoPixmap, curGC, 0, 0, xsh.width, xsh.height); else XFillRectangle (dpy, win, curGC, 0, 0, xsh.width, xsh.height); } #endif } } acm-6.0_20200416/test/V/Makefile0000644000000000000000000000332013155536400014417 0ustar rootroot# This file generated by make-makefile, do not edit! # Create Makefile-include.txt instead for your customizations. CC := gcc CFLAGS := -Wall -Werror -g -fmax-errors=99 -Wuninitialized -Wmissing-prototypes -Wredundant-decls LIBS := .PHONY: all all: make Vlibmath-test.exe animate.exe app.exe #include Makefile-include.txt .PHONY: test test: Vlibmath-test.exe animate.exe app.exe ./Vlibmath-test.exe ./animate.exe ./app.exe .PHONY: clean clean: rm -f *.o *.exe *.stackdump Vlibmath-test animate app Vlibmath-test.o: Vlibmath-test.c ../../src/V/Vlibmath.h $(CC) $(CFLAGS) -c Vlibmath-test.c -o Vlibmath-test.o Vlibmath-test.exe: ../../src/V/Vlibmath.o Vlibmath-test.o $(CC) $(CFLAGS) -o Vlibmath-test.exe ../../src/V/Vlibmath.o Vlibmath-test.o $(LIBS) -lm animate.o: animate.c $(CC) $(CFLAGS) -c animate.c -o animate.o animate.exe: animate.o $(CC) $(CFLAGS) -o animate.exe animate.o $(LIBS) app.o: app.c ../../src/V/Alib.h ../../src/V/VColor.h ../../src/V/VPoly.h ../../src/V/Vlib.h ../../src/V/Vlibmath.h ../../src/util/gui.h ../../src/util/units.h $(CC) $(CFLAGS) -c app.c -o app.o app.exe: ../../src/V/Alib.o ../../src/V/VColor.o ../../src/V/VGlyph.o ../../src/V/VPoly.o ../../src/V/VRoman.o ../../src/V/Vlib.o ../../src/V/Vlibmath.o ../../src/util/error.o ../../src/util/gui.o ../../src/util/memory.o ../../src/util/sparsearray.o ../../src/util/units.o app.o $(CC) $(CFLAGS) -o app.exe ../../src/V/Alib.o ../../src/V/VColor.o ../../src/V/VGlyph.o ../../src/V/VPoly.o ../../src/V/VRoman.o ../../src/V/Vlib.o ../../src/V/Vlibmath.o ../../src/util/error.o ../../src/util/gui.o ../../src/util/memory.o ../../src/util/sparsearray.o ../../src/util/units.o app.o $(LIBS) -lm # Checksum of the original file: 2997635812 acm-6.0_20200416/test/V/Vlibmath-test.c0000644000000000000000000000671313173130642015655 0ustar rootroot#include #include #include "../../src/V/Vlibmath.h" static int err = 0; #define EPSILON 1e-6 static int VPointEquals(VPoint *a, VPoint *b) { return fabs(a->x - b->x) < EPSILON && fabs(a->y - b->y) < EPSILON && fabs(a->z - b->z) < EPSILON; } /** * Transforms the point according to the matrix and compares with expected. * @param line Line of this source (for error reporting). * @param a Point to transform. * @param m Transformation matrix. * @param exp Expected transformed point. */ static void transform_test(int line, VPoint *a, VMatrix *m, VPoint *exp) { VPoint got; VTransform(a, m, &got); if( ! VPointEquals(exp, &got) ){ err++; printf("in line %d\n\tgot {%g, %g, %g}\n\texp {%g, %g, %g}\n", line, got.x, got.y, got.z, exp->x, exp->y, exp->z); } } static void eulerangles_test(int line, VMatrix *m, double exp_phi, double exp_theta, double exp_psi) { double got_phi, got_theta, got_psi; VMatrixToEuler(m, &got_phi, &got_theta, &got_psi); if( !( fabs(got_phi - exp_phi ) < EPSILON && fabs(got_theta - exp_theta) < EPSILON && fabs(got_psi - exp_psi ) < EPSILON )){ err++; printf("in line %d\n\tgot phi,theta,psi=%g, %g, %g\n\texp phi,theta,psi=%g, %g, %g\n", line, got_phi, got_theta, got_psi, exp_phi, exp_theta, exp_psi); } } static void rotateAroundAxis_test() { VMatrix m; // Rotating (1,0,0) by 90 DEG around z axis gives (0,1,0): VIdentMatrix(&m); VRotateAroundAxis(&m, &(VPoint){0,0,1}, M_PI/2); VPoint p = (VPoint){1,0,0}; VTransform(&p, &m, &p); VSub(&p, &(VPoint){0,1,0}, &p); assert(VMagnitude(&p) < 1e-15); // Rotating (0,0,1) by 90 DEG around y axis gives (1,0,0): VIdentMatrix(&m); VRotateAroundAxis(&m, &(VPoint){0,1,0}, M_PI/2); p = (VPoint){0,0,1}; VTransform(&p, &m, &p); VSub(&p, &(VPoint){1,0,0}, &p); assert(VMagnitude(&p) < 1e-15); // Rotating (0,1,0) by 90 DEG around x axis gives (0,0,1): VIdentMatrix(&m); VRotateAroundAxis(&m, &(VPoint){1,0,0}, M_PI/2); p = (VPoint){0,1,0}; VTransform(&p, &m, &p); VSub(&p, &(VPoint){0,0,1}, &p); assert(VMagnitude(&p) < 1e-15); } int main(int argc, char **argv) { VMatrix m; double sin60; /* Identity matrix transforms {1,1,1} in itself: */ VEulerToMatrix(0.0, 0.0, 0.0, &m); transform_test(__LINE__, &(VPoint){1.0, 1.0, 1.0}, &m, &(VPoint){1.0, 1.0, 1.0}); /* Roll +90 DEG: */ VEulerToMatrix(M_PI/2, 0.0, 0.0, &m); transform_test(__LINE__, &(VPoint){1.0, 0.0, 0.0}, &m, &(VPoint){1.0, 0.0, 0.0}); transform_test(__LINE__, &(VPoint){0.0, 1.0, 0.0}, &m, &(VPoint){0.0, 0.0, 1.0}); transform_test(__LINE__, &(VPoint){0.0, 0.0, 1.0}, &m, &(VPoint){0.0, -1.0, 0.0}); eulerangles_test(__LINE__, &m, M_PI/2, 0.0, 0.0); /* Pitch +60 DEG: */ VEulerToMatrix(0.0, M_PI/3, 0.0, &m); sin60 = sin(M_PI/3); transform_test(__LINE__, &(VPoint){1.0, 0.0, 0.0}, &m, &(VPoint){0.5, 0.0, -sin60}); transform_test(__LINE__, &(VPoint){0.0, 1.0, 0.0}, &m, &(VPoint){0.0, 1.0, 0.0}); transform_test(__LINE__, &(VPoint){0.0, 0.0, 1.0}, &m, &(VPoint){sin60, 0.0, 0.5}); eulerangles_test(__LINE__, &m, 0.0, M_PI/3, 0.0); /* Yaw +90 DEG: */ VEulerToMatrix(0.0, 0.0, M_PI/2, &m); transform_test(__LINE__, &(VPoint){1.0, 0.0, 0.0}, &m, &(VPoint){0.0, 1.0, 0.0}); transform_test(__LINE__, &(VPoint){0.0, 1.0, 0.0}, &m, &(VPoint){-1.0, 0.0, 0.0}); transform_test(__LINE__, &(VPoint){0.0, 0.0, 1.0}, &m, &(VPoint){0.0, 0.0, 1.0}); eulerangles_test(__LINE__, &m, 0.0, 0.0, M_PI/2); rotateAroundAxis_test(); return err == 0? 0 : 1; } acm-6.0_20200416/test/wmm/0000755000000000000000000000000013175062144013355 5ustar rootrootacm-6.0_20200416/test/wmm/wmm-test.c0000644000000000000000000000672213161734355015312 0ustar rootroot#include #include #include #include #include "../../src/util/memory.h" #include "../../src/util/timer.h" #include "../../src/util/units.h" #include "../../src/wmm/wmm.h" static int err; struct Sample { double date; // year double altitude; // km double latitude; // deg double longitude; // deg double X, Y, Z; // nT double Incl; // deg double Decl; // deg }; static struct Sample samples[] = { // Test data from the file WMM2015testvalues.pdf: {2015.0, 0, 80, 0, 6627.1, -445.9, 54432.3, 83.04, -3.85}, {2015.0, 0, 0, 120, 39518.2, 392.9, -11252.4, -15.89, 0.57}, {2015.0, 0, -80, 240, 5797.3, 15761.1, -52919.1, -72.39, 69.81}, {2015.0, 100, 80, 0, 6314.3, -471.6, 52269.8, 83.09, -4.27}, {2015.0, 100, 0, 120, 37535.6, 364.4, -10773.4, -16.01, 0.56}, {2015.0, 100, -80, 240, 5613.1, 14791.5, -50378.6, -72.57, 69.22}, {2017.5, 0, 80, 0, 6599.4, -317.1, 54459.2, 83.08, -2.75}, {2017.5, 0, 0, 120, 39571.4, 222.5, -11030.1, -15.57, 0.32}, {2017.5, 0, -80, 240, 5873.8, 15781.4, -52687.9, -72.28, 69.58}, {2017.5, 100, 80, 0, 6290.5, -348.5, 52292.7, 83.13, -3.17}, {2017.5, 100, 0, 120, 37585.5, 209.5, -10564.2, -15.70, 0.32}, {2017.5, 100, -80, 240, 5683.5, 14808.8, -50163.0, -72.45, 69.00}, // My samples: {2017.5, 0.200, 44.5, 11.4, 23044.1, 1162.9, 41210.9, 60.75, 2.88}, // near Bologna {0, 0, 0, 0, 0, 0, 0, 0, 0} // date=0 marks the end of the data }; /** * Checks if the got value is close enough to the expected value. * Error must be within 1%, which is quite arbitrary limit. */ static void compare(int sample_no, char *value_name, double exp, double got) { int e = 100 * (got - exp)/exp; if( !(-1 <= e && e <= 1) ){ printf("sample no. %d, %s: exp %g, got %g, error %d%%\n", sample_no, value_name, exp, got, e); err++; } } static void testSample(int i, struct Sample *s) { wmm_MagneticField mf; wmm_getMagneticField(s->date, units_DEGtoRAD(s->latitude), units_DEGtoRAD(s->longitude), 1000.0 * s->altitude, &mf); compare(i, "X (nT)", s->X, mf.X); compare(i, "Y (nT)", s->Y, mf.Y); compare(i, "Z (nT)", s->Z, mf.Z); compare(i, "Incl (DEG)", s->Incl, units_RADtoDEG(mf.Incl)); compare(i, "Decl (DEG)", s->Decl, units_RADtoDEG(mf.Decl)); } /** * Speed test evaluating the magnetic field along a very long journey. * @param samples How many computations along the journey. */ static void journey(int samples) { double date = 2017.5, fromLat = units_DEGtoRAD(+80), fromLon = units_DEGtoRAD(-90), toLat = units_DEGtoRAD(-80), toLon = units_DEGtoRAD(+90), alt = 2000.0; int i; for(i = 0; i < samples; i++){ double lat = fromLat + (toLat - fromLat) * i / (samples - 1); double lon = fromLon + (toLon - fromLon) * i / (samples - 1); wmm_MagneticField mf; wmm_getMagneticField(date, lat, lon, alt, &mf); //printf("lat %+06.2f lon %+06.2f --> mag var %+5.1f\n", // units_RADtoDEG(lat), units_RADtoDEG(lon), units_RADtoDEG(mf.Decl)); } } int main(int argc, char** argv) { wmm_init("../../objects/WMM.COF"); // Test with samples: int i; for (i = 0; samples[i].date != 0.0; i++){ testSample(i, &samples[i]); } // Speed test: { timer_Type *t = timer_new(); timer_start(t); int computations = 0; do { journey(1000); computations += 1000; } while( computations < 1000 && timer_getElapsedMilliseconds(t) < 1000 ); timer_stop(t); printf("Speed test: %d computations per second\n", 1000 * computations / timer_getElapsedMilliseconds(t)); } return err ? 1 : 0; } acm-6.0_20200416/test/wmm/Makefile0000644000000000000000000000200313161734342015011 0ustar rootroot# This file generated by make-makefile, do not edit! # Create Makefile-include.txt instead for your customizations. CC := gcc CFLAGS := -Wall -Werror -g -fmax-errors=99 -Wuninitialized -Wmissing-prototypes -Wredundant-decls LIBS := .PHONY: all all: make wmm-test.exe #include Makefile-include.txt .PHONY: test test: wmm-test.exe ./wmm-test.exe .PHONY: clean clean: rm -f *.o *.exe *.stackdump wmm-test wmm-test.o: wmm-test.c ../../src/util/memory.h ../../src/util/timer.h ../../src/util/units.h ../../src/wmm/wmm.h $(CC) $(CFLAGS) -c wmm-test.c -o wmm-test.o wmm-test.exe: ../../src/util/error.o ../../src/util/memory.o ../../src/util/timer.o ../../src/util/units.o ../../src/util/zulu.o ../../src/wmm/Geomagnetism.o ../../src/wmm/wmm.o wmm-test.o $(CC) $(CFLAGS) -o wmm-test.exe ../../src/util/error.o ../../src/util/memory.o ../../src/util/timer.o ../../src/util/units.o ../../src/util/zulu.o ../../src/wmm/Geomagnetism.o ../../src/wmm/wmm.o wmm-test.o $(LIBS) -lm # Checksum of the original file: 3360288102 acm-6.0_20200416/test/util/0000755000000000000000000000000013175062144013532 5ustar rootrootacm-6.0_20200416/test/util/audio-test.c0000644000000000000000000000271113153246504015755 0ustar rootroot#include #include "../../src/util/error.h" #include "../../src/util/memory.h" #include "../../src/util/audio.h" static char *wav_filename; static audio_Type *wave; static int menu() { printf("%s, %d s, %d Hz:\n", wav_filename, (audio_getOriginalLengthMilliseconds(wave) + 500) / 1000, audio_getCurrentSamplesPerSecond(wave)); printf(" p)lay, P)ause, l)oop, o)ne-shot, r)ewind, +-)pitch, q)uit: "); char c; scanf("%c", &c); printf("\n"); return c; } int main(int argc, char *argv[]) { if (argc == 1) { wav_filename = "audio-sine-400hz-2sec.wav"; } else if (argc == 2) { wav_filename = argv[1]; } else { printf("Usage: audio-test.exe [WAV_FILE]\n"); exit(1); } wave = audio_new(wav_filename); if( wave == NULL ){ printf("ERROR: audio_new(%s) failed\n", wav_filename); return 1; } int quit = 0; while( ! quit ) { int c = menu(); switch(c){ case 'q': quit = 1; break; case 'p': audio_play(wave); break; case 'P': audio_pause(wave); break; case 'l': audio_loop(wave, 1); break; case 'o': audio_loop(wave, 0); break; case 'r': audio_setCurrentPositionMilliseconds(wave, 0); break; case '+': audio_setCurrentSamplesPerSecond(wave, 1.2 * audio_getCurrentSamplesPerSecond(wave)); break; case '-': audio_setCurrentSamplesPerSecond(wave, audio_getCurrentSamplesPerSecond(wave) / 1.2); break; } } memory_dispose(wave); return 0; } acm-6.0_20200416/test/util/statistics.h0000644000000000000000000001044013150543140016065 0ustar rootroot/** * Evaluate basic statistical parameters about a set of samples. * Histogram generation can also be enabled to display a very basic ASCII-art * histogram. * Usage: create the samples collector, then put the samples on it one by one. * Statistic data can be retrieved ad any moment by calling the getter methods. * * @author Umberto Salsi * @version $Date: 2017/08/27 13:17:20 $ * @file */ #ifndef STATISTICS_H #define STATISTICS_H #ifdef statistics_IMPORT #define EXTERN #else #define EXTERN extern #endif typedef struct statistics_Type statistics_Type; /** * Creates a new, empty samples collector. Can be released with memory_dispose(). * @return Statistical samples collector. */ EXTERN statistics_Type * statistics_new(void); /** * Add a sample to the set. * @param this Samples collector. * @param x Sample to add. */ EXTERN void statistics_put(statistics_Type *this, double x); /** * Returns the number of samples accounted so far. * @param this Samples collector. * @return Number of sample accounted so far. */ EXTERN int statistics_count(statistics_Type *this); /** * Minimum value accounted so far. * Fatal error if there are still no samples. * @param this Samples collector. * @return Minimum value accounted so far. */ EXTERN double statistics_min(statistics_Type *this); /** * Maximum value accounted so far. * Fatal error if there are still no samples. * @param this Samples collector. * @return Maximum value accounted so far. */ EXTERN double statistics_max(statistics_Type *this); /** * Mean value of the samples accounted so far. * Fatal error if there are less than two samples available. * @param this Samples collector. * @return Mean value of the samples accounted so far. */ EXTERN double statistics_mean(statistics_Type *this); /** * Returns the mean squared deviation of the samples accounted so far. * Fatal error if there are less than two samples available. * @param this Samples collector. * @return Mean squared deviation of the samples accounted so far. */ EXTERN double statistics_variance(statistics_Type *this); /** * Returns the standard deviation of the samples accounted so far. * It is the square root of the mean squared deviation. * Fatal error if there are less than two samples available. * @param this Samples collector. * @return Standard deviation of the samples accounted so far. */ EXTERN double statistics_deviation(statistics_Type *this); /** * Returns a summary of the statistical parameters of the samples * accounted so far. * @param this Samples collector. * @return One-line message including number of samples, * min, max, mean and deviation (when available). */ EXTERN char * statistics_toString(statistics_Type *this); /** * Enables histogram generation for the interval [min,max[ of values. * Fatal error if already enabled. * Fatal error if there are already samples in the set. * @param this Samples collector. * @param min Minimum value to display. * @param max Values equal or greater than this aren't displayed. Must be greater * than the minimum value. * @param number_of_intervals Number of intervals. Must be at least 1. */ EXTERN void statistics_histogramEnable(statistics_Type *this, double min, double max, int number_of_intervals); /** * Returns the number of samples that fell in the range of the histogram. * This value can be less than the total number of samples submitted whenever * some sample fell outside histogram range. * Fatal error if histogram not enabled. * @param this Samples collector. * @return Number of samples that fell in the range of the histogram. */ EXTERN int statistics_histogramNumberOfSamples(statistics_Type *this); /** * Returns the number of samples that fell in the i-th interval of the histogram. * Fatal error if histogram not enabled. * Fatal error if the index is out of the range [0,number_of_intervals[. * @param this Samples collector. * @param i Index of the interval. * @return Number of samples that fell in the i-th interval of the histogram. */ EXTERN int statistics_histogramBar(statistics_Type *this, int i); /** * Displays the histogram on standard output. * Does nothing if histogram has not been enabled. * @param this Samples collector. * @param this */ EXTERN void statistics_histogramPrint(statistics_Type *this); #undef EXTERN #endif acm-6.0_20200416/test/util/zulu-test.c0000644000000000000000000001031013173130656015647 0ustar rootroot#include #include #include #include #include #include #include "../../src/util/zulu.h" static int err; /** * Compares all the conversion routines together and vs. the expected values. * @param exp_ts Expected timestamp. * @param exp_year Expected year. * @param exp_d Expected date. */ static void test_all(int exp_ts, double exp_year, zulu_Date *exp_d) { /* printf("testing: ts=%d, year=%.14g, %d-%02d-%02d %02d:%02d:%02d\n", ts, year, d->year, d->month, d->day, d->hour, d->minutes, d->seconds); */ zulu_Date got_d; // half second max err assert( fabs( zulu_timestampToYear(exp_ts) - exp_year ) < 0.5/(365*86400) ); zulu_timestampToDate(exp_ts, &got_d); assert( zulu_dateCompare(&got_d, exp_d) == 0 ); assert(zulu_yearToTimestamp(exp_year) == exp_ts); zulu_yearToDate(exp_year, &got_d); assert( zulu_dateCompare(&got_d, exp_d) == 0 ); assert(zulu_dateToTimestamp(exp_d) == exp_ts); // half second max err assert( fabs( zulu_dateToYear(exp_d) - exp_year) < 0.5/(365*86400)); } static void test_dateParse(char *s, int exp_n, zulu_Date *exp_d) { zulu_Date got_d; int got_n = zulu_dateParse(s, &got_d); if( got_n != exp_n ){ err++; printf("FAILED parsing date %s:\n\tgot_n=%d,\n\texp_n=%d\n", s, got_n, exp_n); return; } if( exp_n == 0 ) return; if( zulu_dateCompare(&got_d, exp_d) != 0 ){ err++; char got_d_s[20], exp_d_s[20]; zulu_dateFormat(&got_d, got_d_s, sizeof(got_d_s)); zulu_dateFormat( exp_d, exp_d_s, sizeof(exp_d_s)); printf("FAILED parsing date %s:\n\tgot %s,\n\texp %s\n", s, got_d_s, exp_d_s); } } int main(int argc, char** argv) { // 1970-01-01 00:00:00 UTC test_all(0, 1970.0, &(zulu_Date){1970, 1, 1, 0, 0, 0}); // Test negative ts. test_all( //-31404304, // $ date --date="1969-01-02T12:34:56Z" +%s -365*86400.0 + 86400.0 + 12*3600 + 34*60 + 56, 1969.0 + (86400.0 + 12*3600 + 34*60 + 56)/(365*86400), &(zulu_Date){1969, 1, 2, 12, 34, 56} ); // Check max timestamp only for 32-bits int (for 64-bits int our // dumb loops would take a while to complete... :-): test_all(INT32_MIN, 1901.9503155758, &(zulu_Date){1901, 12, 13, 20, 45, 52}); test_all(INT32_MAX, 2038.0496843924, &(zulu_Date){2038, 1, 19, 3, 14, 7}); // Exact middle of the year 2017. test_all( 1498996800, // $ date --date="2017-07-02T12:00:00Z" +%s 2017.5, &(zulu_Date){2017, 7, 2, 12, 0, 0} ); // 1970-01-01T12:34:56Z test_all( 12 * 3600 + 34 * 60 + 56, 1970 + (12 * 3600 + 34 * 60 + 56) / (365.0 * 86400), &(zulu_Date){1970, 1, 1, 12, 34, 56} ); // Brute force test, only on the basic conversions functions: from ts to // year and date and back. // Step by a bit less than a day/hour/min to exercise all the fields of the date. { int ts; for(ts = INT32_MIN; 1 <= ts && ts <= INT32_MAX; ts += 80000){ double year = zulu_timestampToYear(ts); zulu_Date d; zulu_timestampToDate(ts, &d); assert(zulu_dateToTimestamp(&d) == ts); assert( zulu_yearToTimestamp(year) == ts ); } } // Invalid date and time strings: test_dateParse(NULL, 0, NULL); test_dateParse("", 0, NULL); test_dateParse(" ", 0, NULL); test_dateParse("x", 0, NULL); test_dateParse("200-01", 0, NULL); // year: few digits test_dateParse("20000-01", 0, NULL); // year: too many digits test_dateParse("1582-1", 0, NULL); // year not in range test_dateParse("2000-1", 0, NULL); // month: few digits test_dateParse("2000-001", 0, NULL); // month: too many digits test_dateParse("2000-00", 0, NULL); // month: not in range test_dateParse("2000-01-0", 0, NULL); // day: few digits test_dateParse("2000-01-001", 0, NULL); // day: too many digits test_dateParse("2000-01-00", 0, NULL); // day: not in range test_dateParse("2001-02-29", 0, NULL); // not a leap year test_dateParse("2001-01-01T", 0, NULL); // missing expected hour test_dateParse("2001-01-01T99", 0, NULL); // hour: out or range // Valid date and time strings: test_dateParse("2017-10-20T12:34:56", 6, &(zulu_Date){2017,10,20,12,34,56}); test_dateParse("2017-10-20T12:34", 5, &(zulu_Date){2017,10,20,12,34,0}); test_dateParse("2017-10-20", 3, &(zulu_Date){2017,10,20,0,0,0}); test_dateParse("2017-10", 2, &(zulu_Date){2017,10,1,0,0,0}); return err == 0? 0 : 1; } acm-6.0_20200416/test/util/varray-test.c0000644000000000000000000000762613072324232016165 0ustar rootroot#include #include #include #include #include "../../src/util/memory.h" #include "../../src/util/varray.h" static int err; /** * Create array with up to 3 strings: "a", "b" and "c". * @param n Actual number of strings to put in the array, [0,3]. * @param a Here returns handle first string. * @param b Here returns handle second string. * @param c Here returns handle third string. * @return Created array. */ static varray_Type *createABC(int n, int *a, int*b, int *c) { varray_Type *va = varray_new(); *a = (n < 1)? 0 : varray_addValue(va, "a"); *b = (n < 2)? 0 : varray_addValue(va, "b"); *c = (n < 3)? 0 : varray_addValue(va, "c"); return va; } /** * Returns a (statically allocated) string with the content of the array, * assuming each entry contains a pointer to a single char. Also checks the * number of entries equals the length of the array. * @param va * @return */ static char * vaToString(varray_Type *va) { static char res[99]; char *s; int gotlen = 0; int i; s = res; for(i = varray_firstHandle(va); i != 0; i = varray_nextHandle(va)){ *s = *((char *) varray_getValue(va, i)); s++; gotlen++; } *s = 0; assert( gotlen == varray_length(va) ); return res; } /** * Test if the array content equals the given string. * @param line * @param va * @param exp */ static void vaEqualsString(int line, varray_Type *va, char *exp) { char *got = vaToString(va); if( strcmp(got, exp) != 0 ){ err++; printf("in line %d\n\tgot %s\n\texp %s\n", line, got, exp); } } static void vaDispose(varray_Type *va) { int i; for(i = varray_firstHandle(va); i != 0; i = varray_nextHandle(va)) varray_detach(va, i); memory_dispose(va); } int main(int argc, char** argv) { varray_Type *va; int a, b, c, a2; /* Empty array tests. */ va = createABC(0, &a, &b, &c); vaEqualsString(__LINE__, va, ""); assert( varray_length(va) == 0 ); assert( ! varray_isValidHandle(va, 0) ); assert( ! varray_isValidHandle(va, -1) ); assert( ! varray_isValidHandle(va, 1) ); vaDispose(va); /* 1 entry tests. */ va = createABC(1, &a, &b, &c); vaEqualsString(__LINE__, va, "a"); assert( ! varray_isValidHandle(va, 0) ); /* remove that only entry: */ varray_detach(va, a); assert( varray_length(va) == 0 ); /* recycle last detached, resulting in a new handle: */ a2 = varray_getDetachedHandle(va); assert( a2 != a ); varray_setValue(va, a2, "z"); vaEqualsString(__LINE__, va, "z"); vaDispose(va); /* Array with 3 entries "abc". */ va = createABC(3, &a, &b, &c); vaEqualsString(__LINE__, va, "abc"); // Detach first entry: varray_detach(va, a); vaEqualsString(__LINE__, va, "bc"); // Add entry replacing detached one; new entry added last: varray_setValue(va, varray_getDetachedHandle(va), "d"); vaEqualsString(__LINE__, va, "bcd"); // Add new entry; new entry added last: varray_addValue(va, "e"); vaEqualsString(__LINE__, va, "bcde"); vaDispose(va); /* Array with 3 entries "abc". */ va = createABC(3, &a, &b, &c); vaEqualsString(__LINE__, va, "abc"); // Detach middle entry: varray_detach(va, b); vaEqualsString(__LINE__, va, "ac"); // Add entry replacing detached one; new entry added last: varray_setValue(va, varray_getDetachedHandle(va), "d"); vaEqualsString(__LINE__, va, "acd"); // Add new entry; new entry added last: varray_addValue(va, "e"); vaEqualsString(__LINE__, va, "acde"); vaDispose(va); /* Array with 3 entries "abc". */ va = createABC(3, &a, &b, &c); vaEqualsString(__LINE__, va, "abc"); // Detach last entry: varray_detach(va, c); vaEqualsString(__LINE__, va, "ab"); // Add entry replacing detached one; new entry added last: varray_setValue(va, varray_getDetachedHandle(va), "d"); vaEqualsString(__LINE__, va, "abd"); // Add new entry; new entry added last: varray_addValue(va, "e"); vaEqualsString(__LINE__, va, "abde"); vaDispose(va); err += memory_report(); return err == 0? 0 : 1; } acm-6.0_20200416/test/util/audio-sine-400hz-2sec.wav0000644000000000000000000003725413153246504020016 0ustar rootrootRIFF>WAVEfmt @data>%<<%]&d%<<%f']%<<%_%e%<<%`$ b%<<%e%_%<<%_$ c%<<%`#!a%<<%e$a%<<%a$e%<<%a$f%<<%g%b%<<%b$d%<<%b "c%<<%d%_%<<%Z(a%<<%d $_%<<%`#!e%<<%_$ d%<<%b"!b%<<%`$!a%<<%f$a%<<% V*b%<<%]%c%<<%`$ e%<<%b %]%<<%`$ c%<<%a%b%<<%a"$_%<<%]&i%<<%`"#`%<<%]&c%<<%c!!e%<<%^$!a%<<%c!$`%<<%_##a%<<%h$_%<<%^&c%<<%b#!b%<<%`#"_%<<%\(h%<<%a"!c%<<%a"#b%<<%b!#`%<<%a"$\%<<%^$!b%<<%b"#`%<<%])i%<<%g$`%<<%b"!c%<<%i&_%<<%c $`%<<%c #`%<<%a $`%<<%f&`%<<%^% d%<<%a#!b%<<%d" d%<<%g#b%<<%e "b%<<%_%f%<<%d #`%<<%`##_%<<%`%g%<<%b""a%<<%f#b%<<%a""a%<<%^&b%<<%_##a%<<%f&^%<<%a"#`%<<%a# c%<<%e']%<<%`$!b%<<%e$`%<<%c #`%<<%`##^%<<%^#"b%<<%e #b%<<%b# c%<<%c'[%<<%g(]%<<%_% b%<<%c!#b%<<%a!$`%<<%b""`%<<%a#!b%<<%]'d%<<%a"#`%<<%`% b%<<%`"$^%<<%a!$`%<<%h$a%<<%`%f%<<%a# e%<<%^$"`%<<%d"g%<<%b""b%<<%]%!a%<<%d" c%<<%`"$`%<<%h+Y%<<%a%g%<<%d']%<<%c %^%<<%_&d%<<%a#!b%<<%b&^%<<%e&]%<<%e$`%<<%a""b%<<%f)]%<<%a"!d%<<%c $`%<<%`# c%<<%f#c%<<%b"!c%<<%b!$_%<<%a# c%<<%e([%<<%a"#`%<<%a$ e%<<%d!!c%<<%d$b%<<%g%`%<<%d!"b%<<%c $`%<<%]%!a%<<%b#!b%<<%a"#a%<<%]& c%<<%c!$_%<<%b#e%<<%a""c%<<%b!#_%<<%d&`%<<%X-h%<<%e&]%<<%a#!b%<<%a""a%<<%e" d%<<%d&_%<<%d%a%<<%\(f%<<%c!#b%<<%d $^%<<%_#"b%<<%`%f%<<%`#"b%<<%a!#b%<<%g%`%<<%c!#`%<<%a %`%<<%b""`%<<%b%c%<<%`"#a%<<%e&_%<<%_$!a%<<%b"!c%<<%`# e%<<%d $^%<<%c" d%<<%e%^%<<%^#$^%<<%a#!b%<<%f$`%<<%g&`%<<%`&e%<<%f#c%<<%_&g%<<%a""a%<<%c!"c%<<%`"#_%<<%^&c%<<%c# d%<<%^%!c%<<%`&h%<<%c!#a%<<%c!#`%<<%c#d%<<%b$d%<<%a"#a%<<%d$b%<<%c %_%<<%^$"`%<<%h&_%<<%d)Z%<<%c $_%<<%b &[%<<%b!#_%<<%`""a%<<%c""c%<<%a!#a%<<%d%_%<<%](f%<<%a!#`%<<%]#$^%<<%e #a%<<%`#"b%<<%\' b%<<%f'_%<<%b""a%<<%`$ d%<<%a"#`%<<%_'f%<<%^% c%<<%b""a%<<%_&a%<<%d!"c%<<%c%`%<<%b"!d%<<%c'^%<<%f "b%<<%e%^%<<%f !c%<<%b#e%<<%` %`%<<%^'b%<<%_%e%<<%d! e%<<%f$a%<<%a"#`%<<%[(g%<<%d$a%<<%b!#`%<<%c $`%<<%d $_%<<%^&c%<<%b!#`%<<%a#f%<<%_##`%<<%_$"_%<<%`%f%<<%](f%<<%c!"b%<<%b!$_%<<%a#"a%<<%c!!d%<<%d%_%<<%c!"a%<<%^#"`%<<%`!$]%<<%g$a%<<%d #a%<<%a%g%<<%g)]%<<%b"!c%<<%d $`%<<%b"#_%<<%a""b%<<%b#e%<<%b &\%<<%h%`%<<%c""a%<<%a#!a%<<%`#"a%<<%e$a%<<%a#"_%<<%g&`%<<%^'g%<<%]%"_%<<%c #b%<<%`%f%<<%a#!c%<<%a!$_%<<%b $`%<<%\%#]%<<%]%!a%<<%g$`%<<%d "e%<<%b"!c%<<%a!$`%<<%c" d%<<%c" d%<<%^$"`%<<%d&]%<<%c&a%<<%c!#`%<<%f#c%<<%d']%<<%^& a%<<%_$ d%<<%^&c%<<%d" e%<<%b %^%<<%h%_%<<%_% d%<<%e%_%<<%\%"_%<<%`$ d%<<%b"#^%<<%b!#b%<<%a#!b%<<%b!"c%<<%d #`%<<%_#!b%<<%a"#_%<<%a# e%<<%_$ d%<<%d$a%<<%c#!a%<<%a""a%<<%a!%^%<<%b $`%<<%`$ e%<<%f$a%<<%_$"_%<<%d "d%<<%]&c%<<%a$e%<<%d "c%<<%c!!c%<<%c"!b%<<%b!"e%<<%\&g%<<%c"!c%<<%b#"a%<<%b"!b%<<%`#!c%<<%b"!c%<<%c #a%<<%d#c%<<%a"#_%<<%_$!c%<<%`""c%<<%c"!b%<<%b""b%<<%_%d%<<%]&c%<<%b!#a%<<%a $a%<<%a!$_%<<%b" e%<<%_&c%<<%`$d%<<%e "b%<<%\'e%<<%_% b%<<%b""a%<<%a!"b%<<%b$h%<<%\'f%<<%a#e%<<%]&d%<<%b#g%<<%^&e%<<%b $`%<<%_#!c%<<%^% c%<<%e$_%<<%^$"`%<<%e !e%<<%`$ e%<<%c!!c%<<%c!$^%<<%^$"b%<<%b #b%<<%`#!c%<<%`$!a%<<%c!!d%<<%e&_%<<%f']%<<%b"#`%<<%`$c%<<%d%`%<<%b""b%<<%a%f%<<%b# d%<<%b""a%<<%_&f%<<%c!"b%<<%`#!d%<<%^$"`%<<%d$b%<<%b$c%<<%e$_%<<%a"#`%<<%d $_%<<%`$ c%<<%c!#`%<<%e #a%<<%`$!a%<<%a""a%<<%c $_%<<%^&f%<<%c" e%<<%a$ c%<<%e&_%<<%a!$`%<<%f #a%<<%c!#a%<<%e%`%<<%c!#c%<<%a &]%<<%c $_%<<%^%!a%<<%`$ d%<<%b!$_%<<%g g%<<%_&d%<<%_%d%<<%_%c%<<%c%`%<<%`%e%<<%]'f%<<%e! e%<<%`#"a%<<%i)\%<<%^$!b%<<%b"!a%<<%c%`%<<%b"!c%<<%b""b%<<%a"!c%<<%^&f%<<%]*g%<<%_% c%<<%e "c%<<%a!$b%<<%`# e%<<%a#!c%<<%d #a%<<%^% c%<<%d #c%<<%d!"b%<<%d$`%<<%f$`%<<%_#$^%<<%f%`%<<%d %`%<<%b"#a%<<%c""a%<<%_$"_%<<%`#"`%<<%f&_%<<%e$a%<<%c $`%<<%d #a%<<%b']%<<%`$e%<<%c%`%<<%a#!c%<<%d #a%<<%c" f%<<%b!"c%<<%e !e%<<%b""a%<<%f"d%<<%g']%<<%g']%<<%`#!b%<<%b $`%<<%`$ d%<<%e(\%<<%b!#a%<<%`"#b%<<%^&f%<<%a$f%<<%`$!a%<<%h%`%<<%]& a%<<%b"!c%<<%d $_%<<%f#b%<<%e&^%<<%a"#a%<<%_% c%<<%d%`%<<%]& a%<<%^&f%<<%f&`%<<%b# c%<<%d $^%<<%_% b%<<%b'^%<<%b$ b%<<%h$b%<<%_$ d%<<%^'d%<<%a#!d%<<%_% b%<<%e #_%<<%c!#`%<<%b $b%<<%a!#b%<<%f !e%<<%a!$_%<<%_%f%<<%`"$_%<<%c""a%<<%d'\%<<%`'j%<<%h&_%<<%f'^%<<%_$!a%<<%a"!d%<<%i&^%<<%a%e%<<%a!%^%<<%a!$^%<<%e "d%<<%_##_%<<%_&d%<<%d"h%<<%\'d%<<%](c%<<%a#"`%<<%d%^%<<%a"#`%<<%a# d%<<%b!$`%<<%f"c%<<%a"$]%<<%_$ c%<<%`$ c%<<%_% a%<<%c $`%<<%c"!b%<<%c"e%<<%a"#_%<<%a$ c%<<%`"#a%<<%_$!a%<<%e%^%<<%a#"_%<<%b!"c%<<%d%^%<<%c%^%<<%`"$_%<<%_&g%<<%d'[%<<%d #`%<<%e%a%<<%c!$`%<<%_$ e%<<%_##a%<<%c #b%<<%\&e%<<%`$ d%<<%c!#a%<<%^'h%<<%b!#a%<<%`$e%<<%a!#a%<<%e! e%<<%f&_%<<%]&b%<<%c!"a%<<%c $b%<<%`$e%<<%d'^%<<%_%d%<<%\& b%<<%f%a%<<%a"!e%<<%b!$^%<<% W*a%<<%b#!`%<<%c$`%<<%\%"_%<<%^$"_%<<%a#!b%<<%c $^%<<%d "e%<<%c" c%<<%a!&]%<<%b# d%<<%^%g%<<%a""a%<<%^%d%<<%`$d%<<%f%_%<<%f#a%<<%^&e%<<%b!"a%<<%d*X%<<%e$a%<<%d $`%<<%b# d%<<%`#"b%<<%c([%<<%f"c%<<%]%!a%<<%`%g%<<%b$h%<<%b!%^%<<%b# d%<<%a $`%<<%b# c%<<%a""b%<<%a" e%<<%_&i%<<%b"!c%<<%b$d%<<%a# e%<<%`""b%<<%\&!a%<<%e$`%<<%`#!a%<<%b!$_%<<%^##`%<<%`%e%<<%f%_%<<%^$!a%<<%e!#b%<<%]'g%<<%c #a%<<%c!!c%<<%`$ b%<<%e+X%<<%a#!b%<<%b &]%<<%b# d%<<%a$e%<<%d$b%<<%_$!a%<<%a# d%<<%c $`%<<%b %]%<<%b!"c%<<%g#b%<<%^&f%<<%e'_%<<%c %_%<<%a""a%<<%b#!c%<<%b" d%<<%`% b%<<%c" d%<<%`# f%<<%^%e%<<%`$d%<<%_%d%<<%d%_%<<%]'c%<<%b""a%<<%a#!b%<<%f&`%<<%f$`%<<%_$ e%<<%b""b%<<%f!e%<<%e#c%<<%`$e%<<%^% c%<<%`#"a%<<%^&d%<<%d "b%<<%]& a%<<%_$e%<<%c #c%<<%]'h%<<%^$!`%<<%c #`%<<%a!&\%<<%^'f%<<%`#!b%<<%_"#a%<<%a"#a%<<%c"!d%<<%`$!b%<<%a"!e%<<%^'e%<<%e'\%<<%c%`%<<%b$d%<<%f%`%<<%d%_%<<%d! f%<<%`"#`%<<%^&e%<<%d!"c%<<%a# c%<<%c"!b%<<%_$ c%<<%_$!b%<<%_%c%<<%_%e%<<%\)i%<<%f&_%<<%^& b%<<%b$ b%<<%a"!d%<<%^'d%<<%d #b%<<%e&_%<<%_%d%<<%f%`%<<%c#d%<<%`"#`%<<%_&g%<<%_ '\%<<%^% c%<<%a#!`%<<%]'i%<<%c #b%<<%a"#`%<<%c #b%<<%d!"`%<<%b%^%<<%^(h%<<%b""a%<<%c #`%<<%`&i%<<%`&f%<<%d!"a%<<%e'\%<<%`&f%<<%c!"c%<<%_#"c%<<%c"!c%<<%b"!c%<<%\% d%<<%^%f%<<%d%_%<<%_$ e%<<%c!$_%<<%c%`%<<%b""c%<<%`$!a%<<%d #b%<<%e&]%<<%c!!d%<<%b" e%<<%c %^%<<%]&d%<<%a%h%<<%`%e%<<%d $`%<<%b!"b%<<%c$h%<<%_$ b%<<%d!!c%<<%h#e%<<%c $`%<<%b"#]%<<%^% c%<<%f$a%<<%[(c%<<%_%c%<<%b%`%<<%b#e%<<%b"!d%<<%b"!b%<<%f#b%<<%^##_%<<%b &]%<<%]*i%<<%b" f%<<%`#!b%<<%f'\%<<%d #`%<<%`%e%<<%a$e%<<%a""b%<<%a"#`%<<%_#"b%<<%f%a%<<%f!!c%<<%_"#a%<<%b"!c%<<%b#e%<<%d#c%<<%\'e%<<%a# d%<<%f$b%<<%`$ b%<<%d!!d%<<%b!$]%<<%c([%<<%b $`%<<%a!#`%<<%i"d%<<%_$e%<<%c $a%<<%d!#_%<<%a""a%<<%^% b%<<%g(\%<<%c!"`%<<%b$f%<<%a#!d%<<%a"$^%<<%_&g%<<%`$!`%<<%b([%<<%i'^%<<%\(e%<<%c$e%<<%a"!b%<<%c""a%<<%_#"`%<<%e$a%<<%_#"b%<<%d%^%<<%['c%<<%d!!c%<<%h']%<<%c!#b%<<%f$b%<<%`%bacm-6.0_20200416/test/util/sparsearray-test.c0000644000000000000000000000166013141045314017203 0ustar rootroot#include #include #include #include #include "../../src/util/memory.h" #include "../../src/util/sparsearray.h" static int err; int main(int argc, char** argv) { // Empty SA create and release: sparsearray_Type *sa = sparsearray_new(0, 0); memory_dispose(sa); sa = sparsearray_new(9999, 0); memory_dispose(sa); // SA with one element: sa = sparsearray_new(123, 1); char *one = memory_strdup("one"); sparsearray_set(sa, 1, one); assert( sparsearray_get(sa, 1) == one ); assert( sparsearray_get(sa, 2) == NULL ); memory_dispose(sa); // SA with 2 elements: sa = sparsearray_new(123, 1); one = memory_strdup("one"); char *two = memory_strdup("two"); sparsearray_set(sa, 1, one); assert( sparsearray_get(sa, 11) == one ); assert( sparsearray_get(sa, 22) == two ); assert( sparsearray_get(sa, 33) == NULL ); memory_dispose(sa); err += memory_report(); return 0; } acm-6.0_20200416/test/util/timer-test.c0000644000000000000000000000420013145734314015771 0ustar rootroot#include #include #include #include #include #include "../../src/util/error.h" #include "../../src/util/memory.h" #include "../../src/util/timer.h" static int err; // Quite short delay corresponding to 20 Hz. #define DELAY_MS 50 /** * Test timer against the sleep() function on a short delay. Measured delay * should be close to the issued delay time. */ static void testSleep() { timer_Type *t = timer_new(); timer_start(t); timer_sleepMilliseconds(DELAY_MS); timer_stop(t); int ms = timer_getElapsedMilliseconds(t); int64_t us = timer_getElapsedMicroseconds(t); int64_t ns = timer_getElapsedNanoseconds(t); // The time module should round ns to get ms and us -- check: if( !(ms == (ns + 500000)/1000000 && us == (ns + 500)/1000) ){ err++; printf("ERROR: timings units mismatch, bad rounding:" " %d ms, %" PRId64 " us, %" PRId64 " ns\n", ms, us, ns); } int delta = ms - DELAY_MS; if( !(-5 <= delta && delta <= 10) ){ err++; printf("ERROR timing the 'sleep' function: expected %d ms, got %d ms (%+d ms)\n", DELAY_MS, ms, delta); printf("This may happen if the system is busy -- check for running processes and try again.\n"); } memory_dispose(t); }; #define granularity_N 100 /** * Check timer granularity better than 1 ms. */ static void testGranularity() { timer_Type *t = timer_new(); int i, min, max, sum = 0; for(i = 0; i < granularity_N; i++){ // Get a sample of the smaller detectable time interval: timer_reset(t); timer_start(t); int64_t dt_ns = 0; do { dt_ns = timer_getElapsedNanoseconds(t); } while(dt_ns <= 0); // Update the statistics: sum += dt_ns; if( i == 0 ){ min = max = dt_ns; } else if( dt_ns < min ){ min = dt_ns; } else if( dt_ns > max ){ max = dt_ns; } } if( max >= 1000000 ){ err++; printf("ERROR: coarse timer granularity detected on %d samples: min=%d ns, max=%d ns, avg=%g ns\n", granularity_N, min, max, (double)sum/granularity_N); } memory_dispose(t); } int main(int argc, char** argv) { testSleep(); testGranularity(); err += memory_report(); return err == 0? 0 : 1; }; acm-6.0_20200416/test/util/Makefile0000644000000000000000000000776013161734343015206 0ustar rootroot# This file generated by make-makefile, do not edit! # Create Makefile-include.txt instead for your customizations. CC := gcc CFLAGS := -Wall -Werror -g -fmax-errors=99 -Wuninitialized -Wmissing-prototypes -Wredundant-decls LIBS := .PHONY: all all: make audio-test.exe gui-test.exe hashtable-test.exe prng-test.exe sparsearray-test.exe statistics.o timer-test.exe varray-test.exe zulu-test.exe include Makefile-include.txt .PHONY: test test: audio-test.exe gui-test.exe hashtable-test.exe prng-test.exe sparsearray-test.exe timer-test.exe varray-test.exe zulu-test.exe ./audio-test.exe ./gui-test.exe ./hashtable-test.exe ./prng-test.exe ./sparsearray-test.exe ./timer-test.exe ./varray-test.exe ./zulu-test.exe .PHONY: clean clean: rm -f *.o *.exe *.stackdump audio-test gui-test hashtable-test prng-test sparsearray-test timer-test varray-test zulu-test audio-test.o: audio-test.c ../../src/util/audio.h ../../src/util/error.h ../../src/util/memory.h $(CC) $(CFLAGS) -c audio-test.c -o audio-test.o audio-test.exe: ../../src/util/audio.o ../../src/util/error.o ../../src/util/memory.o ../../src/util/wav.o audio-test.o $(CC) $(CFLAGS) -o audio-test.exe ../../src/util/audio.o ../../src/util/error.o ../../src/util/memory.o ../../src/util/wav.o audio-test.o $(LIBS) gui-test.o: gui-test.c ../../src/util/error.h ../../src/util/gui.h ../../src/util/memory.h $(CC) $(CFLAGS) -c gui-test.c -o gui-test.o gui-test.exe: ../../src/util/error.o ../../src/util/gui.o ../../src/util/memory.o gui-test.o $(CC) $(CFLAGS) -o gui-test.exe ../../src/util/error.o ../../src/util/gui.o ../../src/util/memory.o gui-test.o $(LIBS) -lm hashtable-test.o: hashtable-test.c ../../src/util/hashtable.h ../../src/util/memory.h $(CC) $(CFLAGS) -c hashtable-test.c -o hashtable-test.o hashtable-test.exe: ../../src/util/error.o ../../src/util/hashtable.o ../../src/util/memory.o hashtable-test.o $(CC) $(CFLAGS) -o hashtable-test.exe ../../src/util/error.o ../../src/util/hashtable.o ../../src/util/memory.o hashtable-test.o $(LIBS) prng-test.o: prng-test.c ../../src/util/memory.h ../../src/util/prng.h statistics.h $(CC) $(CFLAGS) -c prng-test.c -o prng-test.o prng-test.exe: ../../src/util/error.o ../../src/util/memory.o ../../src/util/prng.o prng-test.o statistics.o $(CC) $(CFLAGS) -o prng-test.exe ../../src/util/error.o ../../src/util/memory.o ../../src/util/prng.o prng-test.o statistics.o $(LIBS) -lm sparsearray-test.o: sparsearray-test.c ../../src/util/memory.h ../../src/util/sparsearray.h $(CC) $(CFLAGS) -c sparsearray-test.c -o sparsearray-test.o sparsearray-test.exe: ../../src/util/error.o ../../src/util/memory.o ../../src/util/sparsearray.o sparsearray-test.o $(CC) $(CFLAGS) -o sparsearray-test.exe ../../src/util/error.o ../../src/util/memory.o ../../src/util/sparsearray.o sparsearray-test.o $(LIBS) statistics.o: statistics.c statistics.h ../../src/util/error.h ../../src/util/memory.h $(CC) $(CFLAGS) -c statistics.c -o statistics.o timer-test.o: timer-test.c ../../src/util/error.h ../../src/util/memory.h ../../src/util/timer.h $(CC) $(CFLAGS) -c timer-test.c -o timer-test.o timer-test.exe: ../../src/util/error.o ../../src/util/memory.o ../../src/util/timer.o timer-test.o $(CC) $(CFLAGS) -o timer-test.exe ../../src/util/error.o ../../src/util/memory.o ../../src/util/timer.o timer-test.o $(LIBS) varray-test.o: varray-test.c ../../src/util/memory.h ../../src/util/varray.h $(CC) $(CFLAGS) -c varray-test.c -o varray-test.o varray-test.exe: ../../src/util/error.o ../../src/util/memory.o ../../src/util/varray.o varray-test.o $(CC) $(CFLAGS) -o varray-test.exe ../../src/util/error.o ../../src/util/memory.o ../../src/util/varray.o varray-test.o $(LIBS) zulu-test.o: zulu-test.c ../../src/util/zulu.h $(CC) $(CFLAGS) -c zulu-test.c -o zulu-test.o zulu-test.exe: ../../src/util/error.o ../../src/util/memory.o ../../src/util/zulu.o zulu-test.o $(CC) $(CFLAGS) -o zulu-test.exe ../../src/util/error.o ../../src/util/memory.o ../../src/util/zulu.o zulu-test.o $(LIBS) # Checksum of the original file: 943495741 acm-6.0_20200416/test/util/prng-test.c0000644000000000000000000004304013326036423015621 0ustar rootroot#include #include #include #include #include #include #include "../../src/util/memory.h" #include "../../src/util/prng.h" #include "statistics.h" static int err; /* * How much statistical figures may deviate from the expected theorical values. * Much depends on the specific PRNG algorithm chosen in the prng module * and on the number of samples submitted for analysis. * 3% results to be the minimum value using either the Windows 7 or the built-in * generator in the prng module and 10000 samples for all the cases. */ #define FAIL_THRESHOLD 0.03 /* * Turns on detailed statistics reporting and histograms. */ static int display_histograms = 0; /** * Test int PRNG uniform distribution. * @param line * @param min * @param max * @param number_of_samples */ static void int_uniform_test(int line, int min, int max, int number_of_samples) { // The generated random numbers should have a uniform distribution. statistics_Type *uniform = statistics_new(); if( display_histograms ) statistics_histogramEnable(uniform, min - 0.5, max + 0.5, 15); // The difference between two successive generated random numbers should // have the same distribution of the difference between two arbitrary // numbers in the range. statistics_Type *difference = statistics_new(); if( display_histograms ) statistics_histogramEnable(difference, (double) min - max - 0.5, (double) max - min + 0.5, 15); // Collect data from our PRNG. int i, r_prev = 0; for(i = 0; i < number_of_samples; i++){ int r = prng_getIntInRange(min, max); assert(min <= r && r <= max); statistics_put(uniform, r); if( i > 0 ) statistics_put(difference, (double) r - r_prev); r_prev = r; } // Retrieve statistics from the statistics module: double got_average = statistics_mean(uniform); double got_variance = statistics_variance(uniform); double got_difference_average = statistics_mean(difference); double got_difference_variance = statistics_variance(difference); if( display_histograms ){ printf("\n\n%d int random numbers in the range [%d,%d]:\n", number_of_samples, min, max); printf("Samples distribution: %s\n", statistics_toString(uniform)); statistics_histogramPrint(uniform); printf("Difference distribution: %s\n", statistics_toString(difference)); statistics_histogramPrint(difference); } memory_dispose(uniform); memory_dispose(difference); /* * Expected statistics figures (using Mathematica or Mathics notation): * n = max - min + 1 * exp_average = min + Sum[i, {i, 0, n-1}] / n = min + (n-1)/2 * exp_variance = Sum[(i - exp_average)^2, {i, 0, n-1}] / n = (n^2 - 1)/12 * exp_difference_average = Sum[ Sum[i-j, {j, 0, n-1}], {i, 0, n-1}] / n^2 = 0 * exp_difference_variance = Sum[ Sum[(i-j)^2, {j, 0, n-1}], {i, 0, n-1}] / n^2 * = (n^2 - 1) / 6 */ double n = (double) max - min + 1; double exp_average = min + (n-1) / 2; double exp_variance = (n*n - 1) / 12; double exp_difference_average = 0; double exp_difference_variance = (n * n - 1) / 6; // Compare expected and got values: if( fabs(got_average - exp_average) / exp_average > FAIL_THRESHOLD ){ err++; printf("in line %d got average %g, exp average %g\n", line, got_average, exp_average); } if( fabs(got_variance - exp_variance) / exp_variance > FAIL_THRESHOLD ){ err++; printf("in line %d got variance %g, exp variance %g\n", line, got_variance, exp_variance); } if( fabs(got_difference_average) / n > FAIL_THRESHOLD ){ err++; printf("in line %d got average difference %g, exp average difference %g\n", line, got_difference_average, exp_difference_average); } if( fabs(got_difference_variance - exp_difference_variance) / exp_difference_variance > FAIL_THRESHOLD ){ err++; printf("in line %d got difference variance %g, exp difference variance %g\n", line, got_difference_variance, exp_difference_variance); } } /** * Test PRNG double precision floating point numbers uniform distribution. * @param line * @param min * @param max * @param number_of_samples */ static void double_uniform_test(int line, int number_of_samples) { // The generated random numbers should have a uniform distribution. statistics_Type *uniform = statistics_new(); if( display_histograms ) statistics_histogramEnable(uniform, 0, 1, 15); // The difference between two successive generated random numbers should // have the same distribution of the difference between two arbitrary // numbers in the range. statistics_Type *difference = statistics_new(); if( display_histograms ) statistics_histogramEnable(difference, -1, 1, 15); // Collect data from our PRNG. int i; double r_prev = 0; for(i = 0; i < number_of_samples; i++){ double r = prng_getDouble(); assert(0.0 <= r && r < 1.0); statistics_put(uniform, r); if( i > 0 ) statistics_put(difference, r - r_prev); r_prev = r; } // Retrieve statistics from the statistics module: double got_average = statistics_mean(uniform); double got_variance = statistics_variance(uniform); double got_difference_average = statistics_mean(difference); double got_difference_variance = statistics_variance(difference); if( display_histograms ){ printf("\n\n%d double random numbers in the range [0,1[:\n", number_of_samples); printf("Samples distribution: %s\n", statistics_toString(uniform)); statistics_histogramPrint(uniform); printf("Difference distribution: %s\n", statistics_toString(difference)); statistics_histogramPrint(difference); } memory_dispose(uniform); memory_dispose(difference); // Expected statistics figure: double exp_average = 0.5; double exp_variance = 1.0 / 12; double exp_difference_average = 0.0; double exp_difference_variance = 1.0 / 6; if( fabs(got_average - exp_average) / exp_average > FAIL_THRESHOLD ){ err++; printf("in line %d got average %g, exp average %g\n", line, got_average, exp_average); } if( fabs(got_variance - exp_variance) / exp_variance > FAIL_THRESHOLD ){ err++; printf("in line %d got variance %g, exp variance %g\n", line, got_variance, exp_variance); } if( fabs(got_difference_average) > FAIL_THRESHOLD ){ err++; printf("in line %d got average difference %g, exp average difference %g\n", line, got_difference_average, exp_difference_average); } if( fabs(got_difference_variance - exp_difference_variance) / exp_difference_variance > FAIL_THRESHOLD ){ err++; printf("in line %d got difference variance %g, exp difference variance %g\n", line, got_difference_variance, exp_difference_variance); } } /** * Simple but very effective test proposed by Joshua Bloch, "Effective Java", * second edition, p. 215. By generating 1 million of random numbers on a very * wide range of the int spectrum, about half of them should fall before the * middle. The typical naive implementation rand() % n to get a value in the * range [0,n-1] does not work and retrieves something like 666666 rather than * the expected 500000. */ static void modulo_bias_test(int line) { int n = 2 * (INT_MAX / 3); int low = 0; int i; for(i = 0; i < 1000000; i++) if( prng_getIntInRange(0, n) < n/2 ) low++; if( fabs(low - 500000) > 10000 ){ err++; printf("in line %d got low %d exp 500000\n", line, low); } } /** * Test prng_fill() by filling-in an array of n int numbers then do statistics. * @param line * @param n */ static void fill_test(int line, int number_of_samples) { int buffer[number_of_samples]; /* Generate array of n random int: */ prng_fill(buffer, number_of_samples*sizeof(int)); /* Basic statistics on this array: */ int min = INT_MIN; int max = INT_MAX; int i; statistics_Type *uniform = statistics_new(); for(i = number_of_samples; i > 0; i--){ int r = buffer[i]; assert(min <= r && r <= max); statistics_put(uniform, r); } double got_average = statistics_mean(uniform); double got_variance = statistics_variance(uniform); memory_dispose(uniform); /* * See discussion above about how the expected values are defined. */ double n = (double) max - min + 1; double exp_average = min + (n-1) / 2; double exp_variance = (n*n - 1) / 12; if( fabs(got_average - exp_average) / exp_average > FAIL_THRESHOLD ){ err++; printf("in line %d got average %g, exp average %g\n", line, got_average, exp_average); } if( fabs(got_variance - exp_variance) / exp_variance > FAIL_THRESHOLD ){ err++; printf("in line %d got variance %g, exp variance %g\n", line, got_variance, exp_variance); } } /* * From here on are the U.S. FIPS 140-1 statistical tests as explained in * Handbook of Applied Cryptography, note 5.32. * FIXME: update to FIPS 140-2. */ /** * Returns the total number of bits set. * @param sample Sample of random bits. * @param sample_len Number of 32-bits words in the sample, for a total of * 32*sample_len bits. * @return Total number of bits set. */ static int monobit_test(uint32_t sample[], int sample_len) { static int ones_per_nibble[] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4}; int ones = 0; int i; for(i = 0; i < sample_len; i++){ uint32_t w = sample[i]; int j; for(j = 0; j < 8; j++){ ones += ones_per_nibble[ w & 15 ]; w = w >> 4; } } return ones; } /** * Performs the poker test. * @param sample Sample of random bits. * @param sample_len Number of 32-bits words in the sample, for a total of * 32*sample_len bits. * @param m Length in bits of each subsample. * @return Poker test statistic figure. */ static double poker_test(uint32_t sample[], int sample_len, int m) { // There are 2^m = 1<> 1; subsample = (subsample << 1) | bit; subsample_len++; if( subsample_len == m ){ n[subsample]++; subsample = 0; subsample_len = 0; } } } double sum = 0.0; for(i = 0; i < number_of_subsamples; i++){ sum += n[i] * n[i]; } int k = 32 * sample_len / m; return sum * number_of_subsamples / k - k; } /** * Performs the long run test. * @param sample Sample of random bits. Bits are scanned starting from the least * significant bit of each word. * @param sample_len Number of 32-bits words in the sample, for a total of * 32*sample_len bits. * @param runs Here save the results of the runs lengths counts found in the sample. * Each entry runs[i] contains the number of gaps and blocks: * runs[i][0] is the number of consecutive zeros (gaps) of length "i"; * runs[i][1] is the number of consecutive ones (blocks) of length "i". * runs[0][*] always returns zero. * The last entry runs[runs_len-1][*] accounts for runs gaps and blocks that are * (runs_len-1) or more bits long. * @param runs_len Number of entries in the runs array. */ static void runs_test(uint32_t sample[], int sample_len, int runs[][2], int runs_len) { int bit, i; for(bit = 0; bit <= 1; bit++) for(i = 0; i < runs_len; i++) runs[i][bit] = 0; int curr_run_bit = 0; int curr_run_len = 0; for(i = 0; i < sample_len; i++){ uint32_t word = sample[i]; int j; for(j = 0; j < 32; j++){ bit = word & 1; word = word >> 1; if( curr_run_len == 0 ){ curr_run_bit = bit; curr_run_len = 1; } else { if( bit == curr_run_bit ){ curr_run_len++; } else { if( curr_run_len < runs_len ) runs[curr_run_len][curr_run_bit]++; else runs[runs_len-1][curr_run_bit]++; curr_run_bit = bit; curr_run_len = 1; } } } } if( curr_run_len > 0 ){ if( curr_run_len < runs_len ) runs[curr_run_len][curr_run_bit]++; else runs[runs_len-1][curr_run_bit]++; } } /** * Performs the FIPS 140-1 statistical tests as explained in Handbook of Applied * Cryptography, par. 5.32. */ static void FIPS_140_1_tests() { // First check if our routines do really work comparing with example 5.31. // ----------------------------------------------------------------------- // The book uses this sample that must be repeated four times. Note that the // first char of the string here becomes the bit zero of the first word; // the other routines here assume bits are ordered in this same way. char *bits = "11100 01100 01000 10100 11101 11100 10010 01001"; // Build the sample array one 32-bits word at a time, cycling over the // bits string to get each bit. The first bit of the sample becomes the // bit 0 of the first word. uint32_t sample[5]; int i; char *next_bit = bits; for(i = 0; i < 5; i++){ // Built the next 32-bits word reading the bits string. uint32_t word = 0; int mask = 1; int j; for(j = 0; j < 32; j++){ // Loops over the bits string extracting the next bit. int bit = 0; do { if( *next_bit == 0 ) next_bit = bits; if( *next_bit == '1' ){ bit = 1; break; } else if( *next_bit == '0' ){ bit = 0; break; } else { next_bit++; } } while(1); next_bit++; if( bit ) word = word | mask; mask = mask << 1; } sample[i] = word; } int ones = monobit_test(sample, 5); if( ones != 76 ){ err++; printf("in line %d monobit test (internal check, NOT the PRNG): found %d ones\n", __LINE__, ones); } double X3 = poker_test(sample, 5, 3); if( fabs(X3 - 9.6415) > 0.001 ){ err++; printf("in line %d poker test (internal check, NOT the PRNG): X3=%g\n", __LINE__, X3); } int got_runs[6][2]; runs_test(sample, 5, got_runs, 6); // Example 5.31-iv; here we also add the counts for gaps (0) and blocks (7) of // length 4; extra entry for blocks of length >=5 (zero gaps, zero blocks). int exp_runs[][2] = { {0,0}, {8,25}, {20,4}, {12,5}, {0,7}, {0,0}}; int bit; for(bit = 0; bit <= 1; bit++){ for(i = 0; i < 6; i++){ if( got_runs[i][bit] != exp_runs[i][bit] ){ err++; printf("in line %d long run test (internal check, NOT the PRNG):" " run len %d bit %d got %d, exp %d\n", __LINE__, i, bit, got_runs[i][bit], exp_runs[i][bit]); } } } // Now the real FIPS 140-1 tests applied to our PRNG module. // --------------------------------------------------------- // Create sample of 20000 random bits. uint32_t fips_sample[625]; prng_fill(fips_sample, sizeof(fips_sample)); // Monobit test. ones = monobit_test(fips_sample, 625); if( !(9654 < ones && ones < 10346) ){ err++; printf("in line %d monobit test: found %d ones\n", __LINE__, ones); } // Poker test. X3 = poker_test(fips_sample, 625, 4); if( !(1.03 < X3 && X3 < 57.4) ){ err++; printf("in line %d poker test: X3=%g\n", __LINE__, X3); } // Runs test. int got_fips_runs[7][2]; runs_test(fips_sample, 625, got_fips_runs, 7); int exp_fips_runs_min[] = {0, 2267, 1079, 502, 223, 90, 90}; // 5.32-iii int exp_fips_runs_max[] = {0, 2733, 1421, 748, 402, 223, 223}; // 5.32-iii for(bit = 0; bit <= 1; bit++){ for(i = 0; i < 7; i++){ if( !(exp_fips_runs_min[i] <= got_fips_runs[i][bit] && got_fips_runs[i][bit] <= exp_fips_runs_max[i]) ){ err++; printf("in line %d runs test: run len %d bit %d count got %d, exp [%d,%d]\n", __LINE__, i, bit, got_fips_runs[i][bit], exp_fips_runs_min[i], exp_fips_runs_max[i]); } } } // Long run test. if( got_fips_runs[6][0] > 0 || got_fips_runs[6][1] > 0 ){ int got_fips_long_run[35][2]; runs_test(fips_sample, 625, got_fips_long_run, 35); for(bit = 0; bit <= 1; bit++){ if( got_fips_long_run[34][bit] != 0 ){ err++; printf("in line %d long run bit %d test 34-bits or more: got %d subsamples, exp zero\n", __LINE__, bit, got_fips_long_run[34][bit]); } } } } int main(int argc, char** argv) { int a, b, r; prng_setSeed(123456789); /* Range 1: */ assert( prng_getIntInRange(0, 0) == 0 ); assert( prng_getIntInRange(1, 1) == 1 ); assert( prng_getIntInRange(-1, -1) == -1 ); assert( prng_getIntInRange(10000000, 10000000) == 10000000 ); assert( prng_getIntInRange(-10000000, -10000000) == -10000000 ); /* Range 2: */ a = 0; b = 1; r = prng_getIntInRange(a, b); assert( a <= r && r <= b ); a = -1; b = 0; r = prng_getIntInRange(a, b); assert( a <= r && r <= b ); /* Wider range using statistics: */ int_uniform_test(__LINE__, 0, 1, 10000); int_uniform_test(__LINE__, 0, 99, 10000); int_uniform_test(__LINE__, -9, 99, 10000); int_uniform_test(__LINE__, 0, INT_MAX/4, 10000); int_uniform_test(__LINE__, 0, INT_MAX/3, 10000); int_uniform_test(__LINE__, 0, INT_MAX/2, 10000); int_uniform_test(__LINE__, 0, INT_MAX - INT_MAX/4, 10000); int_uniform_test(__LINE__, INT_MIN, INT_MAX, 10000); /* Bit generator test: among 100000 bits, half 0, half 1: */ r = 0; for(a = 0; a < 100000; a++) if( prng_getIntInRange(0, 1) ) r++; assert( 50000 - 1000 < r && r < 50000 + 1000 ); double_uniform_test(__LINE__, 10000); modulo_bias_test(__LINE__); fill_test(__LINE__, 10000); FIPS_140_1_tests(); /* { // Generate 1 MB file of random bytes. // Compression algorithm, for example zip, gzip, should generate // a file even larger. char sample[1024*1024]; prng_fill(sample, sizeof(sample)); char *fn = "prng-test-sample.bin"; FILE *f = fopen(fn, "wb"); assert(f != NULL); assert( fwrite(sample, 1024, 1024, f) == 1024 ); fclose(f); printf("Generated file %s\n", fn); } */ err += memory_report(); return err == 0? 0 : 1; } acm-6.0_20200416/test/util/gui-test.c0000644000000000000000000000303413155077562015447 0ustar rootroot#include #include #include #include "../../src/util/gui.h" #include "../../src/util/memory.h" #include "../../src/util/error.h" int main(int argc, char **argv) { error_init(argv[0]); gui_Type *g = gui_new("gui test", 400, 300); gui_DisplayDimensions dd; gui_getDisplayDimensions(g, &dd); printf("Display dimensions: %dx%d pixels, %dx%d mm\n", dd.widthPixels, dd.heightPixels, dd.widthMillimiters, dd.heightMillimiters); printf("Display resolution: %dx%d dpi\n", (int)(25.4 * dd.widthPixels / dd.widthMillimiters + 0.5), (int)(25.4 * dd.heightPixels / dd.heightMillimiters + 0.5)); int pen = gui_getColorIndexString(g, "red"); gui_Event e; int quit = 0; while( ! quit ){ gui_drawLine(g, 1, 2, 2, 1, pen); gui_drawLine(g, 4, 2, 3, 3, pen); e.code = 1111; if( gui_getEvent(g, &e) ){ switch(e.code){ case gui_EVENT_KEYDOWN: printf("Key: %d\n", e.key); break; case gui_EVENT_LBUTTONDOWN: printf("drawing cross at %d,%d\n", e.x, e.y); gui_drawLine(g, e.x - 10, e.y, e.x + 10, e.y, pen); gui_drawLine(g, e.x, e.y - 10, e.x, e.y + 10, pen); break; case gui_EVENT_WINDOW_FOCUS_IN: printf("focus in\n"); break; case gui_EVENT_WINDOW_FOCUS_OUT: printf("focus out\n"); break; case gui_EVENT_WINDOW_CLOSE: quit = 1; break; default: break; } } else { if( gui_isVisible(g) ) printf("is visible\n"); else printf("is not visible\n"); sleep(1); } } memory_dispose(g); return 0; } acm-6.0_20200416/test/util/Makefile-include.txt0000644000000000000000000000155313153616756017447 0ustar rootroot# OS specific compilation options: ifeq ($(OS),Windows_NT) CC = c:/mingw/bin/gcc CFLAGS += -mconsole -mwindows LIBS += -lws2_32 -lwinmm else UNAME_S := $(shell uname -s) ifeq ($(UNAME_S),Linux) CFLAGS += LIBS += -lX11 -lasound -pthread else CFLAGS += LIBS += -lX11 -lasound -pthread endif endif # Some numeric tests involving functions returning "double" may give different # results if the following flag is or is not set. For example, if not set the # optimization is "on" and the following code fails: # # static double f(double a, int n) # { # return a / n; # } # # ... # # double a = 497816; # int n = 10000; # double r = a/n; # assert(r - f(a,n) == 0); --> abort # # because the difference is made among the 64-bits rounded "double" value r # and the 80-bits value f(a,n) gcc knows is still in the register of the FPU. #CFLAGS += -ffloat-storeacm-6.0_20200416/test/util/hashtable-test.c0000644000000000000000000000547713074200416016615 0ustar rootroot#include #include #include #include #include "../../src/util/hashtable.h" #include "../../src/util/memory.h" static int err; static int equalString(char *a, char *b) { return strcmp(a, b) == 0; } /** * Builds hash kay/value hash table with value being int, and key being the * string representation of that int, then check if all the keys matches the * corresponding value. */ static void test_1() { hashtable_Type *ht; int i; char s[10]; char *key; int *value; //printf("string to int map:\n"); ht = hashtable_new( (hashtable_getKeyHash) hashtable_getHashOfString, (hashtable_equalKeys) equalString); /* Create: key=string of the number, value=the number: */ for(i = -500; i <= 500; i += 3){ /* Builds a (key,value) pair of the form ("123",123): */ sprintf(s, "%d", i); key = memory_strdup(s); value = memory_allocate(sizeof(int), NULL); *value = i; hashtable_put(ht, key, value); } /* Check if each key matches the value: */ for(i = -500; i <= 500; i += 3){ sprintf(s, "%d", i); value = hashtable_get(ht, s); assert(*value == i); } //hashtable_report(ht); memory_dispose(ht); } /** * Read my own source code line by line in a key/value hash table with key and * value being the line read, then remove entries whose value contains "printf" * and check if the resulting length of the hash table matches the removed * entries; finally, check that all the remaining entries actually do not * contain "printf" anymore. */ static void test_2() { hashtable_Type *ht = hashtable_new( (hashtable_getKeyHash) hashtable_getHashOfString, (hashtable_equalKeys) equalString); char line[999]; //printf("string to string map:\n"); FILE *f = fopen(__FILE__, "rb"); while( fgets(line, sizeof(line), f) != NULL ){ if( hashtable_get(ht, line) == NULL ) hashtable_put(ht, memory_strdup(line), memory_strdup(line)); } fclose(f); f = fopen(__FILE__, "rb"); while( fgets(line, sizeof(line), f) != NULL ){ assert( strcmp(line, hashtable_get(ht, line)) == 0 ); } fclose(f); // Remove entries containing "printf": int len_before = hashtable_length(ht); int len_after = len_before; char *key = hashtable_firstKey(ht); while(key != NULL){ char *value = hashtable_get(ht, key); if( strstr("printf", value) != NULL ){ hashtable_remove(ht, key); len_after--; } key = hashtable_nextKey(ht); } assert(len_after == hashtable_length(ht)); // Check remaining values actually do not contain "printf" anymore: key = hashtable_firstKey(ht); while(key != NULL){ char *value = hashtable_get(ht, key); assert( strstr("printf", value) == NULL ); key = hashtable_nextKey(ht); } //hashtable_report(ht); memory_dispose(ht); } int main(int argc, char** argv) { test_1(); test_2(); err += memory_report(); return err == 0? 0 : 1; } acm-6.0_20200416/test/util/statistics.c0000644000000000000000000001266613260344465016107 0ustar rootroot#include #include #include #include "../../src/util/memory.h" #include "../../src/util/error.h" // LINKER_OPTIONS -lm #define statistics_IMPORT #include "statistics.h" struct statistics_Type { int n; double min_x; double max_x; double sum_x; double sum_x_2; int hist_enabled; // is histogram enabled? int hist_number_of_intervals; double hist_min, hist_max; // accounts values in [hist_min,hist_max[. int hist_samples; // no. of samples in the histogram int *hist_intervals; // histogram's bars }; static void statistics_destruct(void *p) { statistics_Type *this = p; memory_dispose(this->hist_intervals); } statistics_Type * statistics_new() { statistics_Type *this = memory_allocate(sizeof(*this), statistics_destruct); this->n = 0; this->min_x = 0; this->max_x = 0; this->sum_x = 0; this->sum_x_2 = 0; this->hist_enabled = 0; this->hist_intervals = NULL; return this; } void statistics_put(statistics_Type *this, double x) { if( this->n == 0 ){ this->min_x = x; this->max_x = x; } else { if( x < this->min_x ) this->min_x = x; else if( x > this->max_x ) this->max_x = x; } this->sum_x += x; this->sum_x_2 += x * x; this->n++; if( this->n <= 0 ) error_internal("counter overflow -- too much data", 0); if( this->hist_enabled ){ double interval_number = floor( (x - this->hist_min) / (this->hist_max - this->hist_min) * this->hist_number_of_intervals ); if( 0 <= interval_number && interval_number < this->hist_number_of_intervals ){ this->hist_intervals[(int) interval_number]++; this->hist_samples++; } } } int statistics_count(statistics_Type *this) { return this->n; } double statistics_min(statistics_Type *this) { if( this->n == 0 ) error_internal("no sample", 0); return this->min_x; } double statistics_max(statistics_Type *this) { if( this->n == 0 ) error_internal("no sample", 0); return this->max_x; } double statistics_mean(statistics_Type *this) { if( this->n == 0 ) error_internal("no sample", 0); return this->sum_x / this->n; } double statistics_variance(statistics_Type *this) { if( this->n < 2 ) error_internal("less than 2 samples available", 0); double m = statistics_mean(this); return (this->sum_x_2 + this->n * m * m - 2.0 * m * this->sum_x) / this->n; } double statistics_deviation(statistics_Type *this) { return sqrt( statistics_variance(this) ); } // Buffer for statistics_toString(). static char *statistics_s; static void statistics_cleanup() { memory_dispose(statistics_s); } char * statistics_toString(statistics_Type *this) { if( statistics_count(this) == 0 ) return "n=0"; if( statistics_s == NULL ){ statistics_s = memory_allocate(200, NULL); memory_registerCleanup(statistics_cleanup); } snprintf(statistics_s, 200, "n=%d min=%g max=%g mean=%g", statistics_count(this), statistics_min(this), statistics_max(this), statistics_mean(this)); if( statistics_count(this) >= 2 ){ int len = strlen(statistics_s); snprintf(statistics_s + len, 200 - len, " dev=%g", statistics_deviation(this)); } return statistics_s; } void statistics_histogramEnable(statistics_Type *this, double min, double max, int number_of_intervals) { if( this->hist_enabled ) error_internal("histogram already enabled", 0); if( this->n > 0 ) error_internal("cannot enable histogram: there ar already samples!", 0); if( !(min < max) ) error_internal("invalid range [%g,%g]", min, max); if( number_of_intervals < 1 ) error_internal("invalid number of intervals: %d", number_of_intervals); this->hist_enabled = 1; this->hist_min = min; this->hist_max = max; this->hist_samples = 0; this->hist_number_of_intervals = number_of_intervals; this->hist_intervals = memory_allocate(number_of_intervals * sizeof(int), NULL); memset(this->hist_intervals, 0, number_of_intervals * sizeof(int)); } /** * Returns the number of samples that fell in the range of the histogram. * Fatal error if histogram not enabled. * @param this Samples collector. * @return Number of samples that fell in the range of the histogram. */ int statistics_histogramNumberOfSamples(statistics_Type *this) { if( ! this->hist_enabled ) error_internal("histogram not enabled", 0); return this->hist_samples; } /** * Returns the number of samples that fell in the i-th interval of the histogram. * Fatal error if histogram not enabled. * Fatal error if the index is out of the range [0,number_of_intervals[. * @param this Samples collector. * @param i Index of the interval. * @return Number of samples that fell in the i-th interval of the histogram. */ int statistics_histogramBar(statistics_Type *this, int i) { if( ! this->hist_enabled ) error_internal("histogram not enabled", 0); if( !(0 <= i && i < this->hist_number_of_intervals) ) error_internal("bar index out of the range: %d", i); return this->hist_intervals[i]; } void statistics_histogramPrint(statistics_Type *this) { if( ! this->hist_enabled ) return; int max = 0; int i; for(i = 0; i < this->hist_number_of_intervals; i++) if( this->hist_intervals[i] > max ) max = this->hist_intervals[i]; double k = 0; if( max > 0 ) k = 60.9 / max; double k_bar = 0; if( this->n > 0 ) k_bar = 100.0 / this->n; printf("%g\n", this->hist_min); for(i = 0; i < this->hist_number_of_intervals; i++){ printf("|"); int bar_len = k * this->hist_intervals[i]; int j; for(j = 0; j < bar_len; j++) printf("-"); printf(" %g%%\n", k_bar * this->hist_intervals[i]); } printf("%g\n", this->hist_max); }acm-6.0_20200416/test/README0000644000000000000000000000122413067725702013442 0ustar rootrootThis directory contains test programs. Each program has name MODULE-test.c where MODULE is the name of the source tested by that program, typically a library module. The directories tree mirrors the src/ tree, so making easier to locate each module test program. Each program should perform its test silently and terminate with exit code zero on success, or non-zero on error (in this latter case some diagnostic message should be sent to stdout or stderr). To launch all the test program in a directory: $ make test To launch only a specific test: $ make MODULE-test && ./MODULE-test FIXME: there are some unfinished test programs here and there.

First look and basic usage

Pilot's Operating Handbook

Inside the program