diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 376bc86d12b8..c39601d15129 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,7 +14,7 @@ jobs: steps: - name: message result in slack id: slack - uses: slackapi/slack-github-action@v1.27.0 + uses: slackapi/slack-github-action@v2.0.0 env: SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} with: diff --git a/.vscode/cesiumjs.code-snippets b/.vscode/cesiumjs.code-snippets new file mode 100644 index 000000000000..154d4b1ba084 --- /dev/null +++ b/.vscode/cesiumjs.code-snippets @@ -0,0 +1,44 @@ +{ + // Place your workspace snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and + // description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope + // is left empty or omitted, the snippet gets applied to all languages. The prefix is what is + // used to trigger the snippet and the body will be expanded and inserted. Possible variables are: + // $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. + // Placeholders with the same ids are connected. + // Example: + // "Print to console": { + // "scope": "javascript,typescript", + // "prefix": "log", + // "body": [ + // "console.log('$1');", + // "$2" + // ], + // "description": "Log output to console" + // } + "Debug Pragma": { + "scope": "javascript", + "prefix": "pragdebug", + "description": "Insert or wrap selection with debug pragma comments", + "body": [ + "//>>includeStart('debug', pragmas.debug);", + "${TM_SELECTED_TEXT}$0", + "//>>includeEnd('debug')" + ] + }, + "Check type": { + "prefix": "check", + "body": [ + "Check.typeOf.${2:string}(\"${1:value}\", ${1:value});" + ], + "description": "Check Type of a variable" + }, + "Check type if defined": { + "prefix": "checkifdef", + "body": [ + "if (defined(${1:value})) {", + " Check.typeOf.${2:string}(\"${1:value}\", ${1:value});", + "}" + ], + "description": "Check type of a variable if it's defined" + } +} diff --git a/Apps/SampleData/tracking.czml b/Apps/SampleData/tracking.czml new file mode 100644 index 000000000000..11fff8a3f146 --- /dev/null +++ b/Apps/SampleData/tracking.czml @@ -0,0 +1,4010 @@ + +[ + { + "id":"document", + "name":"tracking", + "version":"1.0", + "clock":{ + "interval":"2012-03-15T10:00:00Z/2012-03-16T10:00:00Z", + "currentTime":"2012-03-15T10:00:00Z", + "range":"LOOP_STOP" + } + }, + { + "id":"Satellite/ISS", + "name":"ISS", + "availability":"2012-03-15T10:00:00Z/2012-03-16T10:00:00Z", + "description":"\r\n

The International Space Station (ISS) is a space station, or a habitable artificial satellite in low Earth orbit. It is a modular structure whose first component was launched in 1998. Now the largest artificial body in orbit, it can often be seen at the appropriate time with the naked eye from Earth. The ISS consists of pressurised modules, external trusses, solar arrays and other components. ISS components have been launched by American Space Shuttles as well as Russian Proton and Soyuz rockets. In 1984 the ESA was invited to participate in Space Station Freedom. In 1993, after the USSR ended, the United States and Russia merged Mir-2 and Freedom together.\r\nThe ISS serves as a microgravity and space environment research laboratory in which crew members conduct experiments in biology, human biology, physics, astronomy, meteorology and other fields. The station is suited for the testing of spacecraft systems and equipment required for missions to the Moon and Mars.

\r\n\r\n

Since the arrival of Expedition 1 on 2 November 2000, the station has been continuously occupied for 13 years and 86 days, the longest continuous human presence in space. (In 2010, the station surpassed the previous record of almost 10 years (or 3,634 days) held by Mir.) The station is serviced by a variety of visiting spacecraft: Soyuz, Progress, the Automated Transfer Vehicle, the H-II Transfer Vehicle, Dragon, and Cygnus. It has been visited by astronauts and cosmonauts from 15 different nations.

\r\n\r\n

After the U.S. Space Shuttle program ended in 2011, Soyuz rockets became the only provider of transport for astronauts at the International Space Station.\r\nThe ISS programme is a joint project among five participating space agencies: NASA, Roskosmos, JAXA, ESA, and CSA. The ownership and use of the space station is established by intergovernmental treaties and agreements. The station is divided into two sections, the Russian Orbital Segment (ROS) and the United States Orbital Segment (USOS), which is shared by many nations. The ISS maintains an orbit with an altitude of between 330 km (205 mi) and 435 km (270 mi) by means of reboost manoeuvres using the engines of the Zvezda module or visiting spacecraft. It completes 15.410 orbits per day. The ISS is funded until 2024, and may operate until 2028. The Russian Federal Space Agency, Roskosmos (RKA) has proposed using the ISS to commission modules for a new space station, called OPSEK, before the remainder of the ISS is deorbited. ISS is the ninth space station to be inhabited by crews, following the Soviet and later Russian Salyut, Almaz, and Mir stations, and Skylab from the US.

", + "billboard":{ + "eyeOffset":{ + "cartesian":[ + 0,0,0 + ] + }, + "horizontalOrigin":"CENTER", + "image":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADJSURBVDhPnZHRDcMgEEMZjVEYpaNklIzSEfLfD4qNnXAJSFWfhO7w2Zc0Tf9QG2rXrEzSUeZLOGm47WoH95x3Hl3jEgilvDgsOQUTqsNl68ezEwn1vae6lceSEEYvvWNT/Rxc4CXQNGadho1NXoJ+9iaqc2xi2xbt23PJCDIB6TQjOC6Bho/sDy3fBQT8PrVhibU7yBFcEPaRxOoeTwbwByCOYf9VGp1BYI1BA+EeHhmfzKbBoJEQwn1yzUZtyspIQUha85MpkNIXB7GizqDEECsAAAAASUVORK5CYII=", + "pixelOffset":{ + "cartesian2":[ + 0,0 + ] + }, + "scale":1.5, + "show":true, + "verticalOrigin":"CENTER" + }, + "label":{ + "fillColor":{ + "rgba":[ + 255,0,255,255 + ] + }, + "font":"11pt Lucida Console", + "horizontalOrigin":"LEFT", + "outlineColor":{ + "rgba":[ + 0,0,0,255 + ] + }, + "outlineWidth":2, + "pixelOffset":{ + "cartesian2":[ + 12,0 + ] + }, + "show":true, + "style":"FILL_AND_OUTLINE", + "text":"ISS", + "verticalOrigin":"CENTER" + }, + "path":{ + "show":[ + { + "interval":"2012-03-15T10:00:00Z/2012-03-16T10:00:00Z", + "boolean":true + } + ], + "width":1, + "material":{ + "solidColor":{ + "color":{ + "rgba":[ + 255,0,255,255 + ] + } + } + }, + "resolution":120, + "leadTime":[ + { + "interval":"2012-03-15T10:00:00Z/2012-03-15T10:44:56.1031157730031Z", + "epoch":"2012-03-15T10:00:00Z", + "number":[ + 0,5537.546684141998, + 5537.546684141998,0 + ] + }, + { + "interval":"2012-03-15T10:44:56.1031157730031Z/2012-03-15T12:17:13.6497999150015Z", + "epoch":"2012-03-15T10:44:56.1031157730031Z", + "number":[ + 0,5537.546684141998, + 5537.546684141998,0 + ] + }, + { + "interval":"2012-03-15T12:17:13.6497999150015Z/2012-03-15T13:49:31.2088613029919Z", + "epoch":"2012-03-15T12:17:13.6497999150015Z", + "number":[ + 0,5537.55906138799, + 5537.55906138799,0 + ] + }, + { + "interval":"2012-03-15T13:49:31.2088613029919Z/2012-03-15T15:21:48.776005533Z", + "epoch":"2012-03-15T13:49:31.2088613029919Z", + "number":[ + 0,5537.567144230008, + 5537.567144230008,0 + ] + }, + { + "interval":"2012-03-15T15:21:48.776005533Z/2012-03-15T16:54:06.33371177400113Z", + "epoch":"2012-03-15T15:21:48.776005533Z", + "number":[ + 0,5537.557706241001, + 5537.557706241001,0 + ] + }, + { + "interval":"2012-03-15T16:54:06.33371177400113Z/2012-03-15T18:26:23.8819795500021Z", + "epoch":"2012-03-15T16:54:06.33371177400113Z", + "number":[ + 0,5537.548267776001, + 5537.548267776001,0 + ] + }, + { + "interval":"2012-03-15T18:26:23.8819795500021Z/2012-03-15T19:58:41.3312553199939Z", + "epoch":"2012-03-15T18:26:23.8819795500021Z", + "number":[ + 0,5537.449275769992, + 5537.449275769992,0 + ] + }, + { + "interval":"2012-03-15T19:58:41.3312553199939Z/2012-03-15T21:30:58.8527762320009Z", + "epoch":"2012-03-15T19:58:41.3312553199939Z", + "number":[ + 0,5537.521520912007, + 5537.521520912007,0 + ] + }, + { + "interval":"2012-03-15T21:30:58.8527762320009Z/2012-03-15T23:03:16.3758652800025Z", + "epoch":"2012-03-15T21:30:58.8527762320009Z", + "number":[ + 0,5537.523089048002, + 5537.523089048002,0 + ] + }, + { + "interval":"2012-03-15T23:03:16.3758652800025Z/2012-03-16T00:35:33.8758586170152Z", + "epoch":"2012-03-15T23:03:16.3758652800025Z", + "number":[ + 0,5537.499993337013, + 5537.499993337013,0 + ] + }, + { + "interval":"2012-03-16T00:35:33.8758586170152Z/2012-03-16T02:07:51.3639393709891Z", + "epoch":"2012-03-16T00:35:33.8758586170152Z", + "number":[ + 0,5537.488080753974, + 5537.488080753974,0 + ] + }, + { + "interval":"2012-03-16T02:07:51.3639393709891Z/2012-03-16T03:40:08.84424079000019Z", + "epoch":"2012-03-16T02:07:51.3639393709891Z", + "number":[ + 0,5537.480301419011, + 5537.480301419011,0 + ] + }, + { + "interval":"2012-03-16T03:40:08.84424079000019Z/2012-03-16T05:12:26.2685025699902Z", + "epoch":"2012-03-16T03:40:08.84424079000019Z", + "number":[ + 0,5537.42426177999, + 5537.42426177999,0 + ] + }, + { + "interval":"2012-03-16T05:12:26.2685025699902Z/2012-03-16T06:44:43.7279617500026Z", + "epoch":"2012-03-16T05:12:26.2685025699902Z", + "number":[ + 0,5537.459459180012, + 5537.459459180012,0 + ] + }, + { + "interval":"2012-03-16T06:44:43.7279617500026Z/2012-03-16T08:17:01.17765616998076Z", + "epoch":"2012-03-16T06:44:43.7279617500026Z", + "number":[ + 0,5537.449694419978, + 5537.449694419978,0 + ] + }, + { + "interval":"2012-03-16T08:17:01.17765616998076Z/2012-03-16T08:27:42.5600708879647Z", + "epoch":"2012-03-16T08:17:01.17765616998076Z", + "number":[ + 0,5537.439929112035, + 5537.439929112035,0 + ] + }, + { + "interval":"2012-03-16T08:27:42.5600708879647Z/2012-03-16T10:00:00Z", + "epoch":"2012-03-16T08:27:42.5600708879647Z", + "number":[ + 0,5537.439929112035, + 5537.439929112035,0 + ] + } + ], + "trailTime":[ + { + "interval":"2012-03-15T10:00:00Z/2012-03-15T10:44:56.1031157730031Z", + "epoch":"2012-03-15T10:00:00Z", + "number":[ + 0,0, + 5537.546684141998,5537.546684141998 + ] + }, + { + "interval":"2012-03-15T10:44:56.1031157730031Z/2012-03-15T12:17:13.6497999150015Z", + "epoch":"2012-03-15T10:44:56.1031157730031Z", + "number":[ + 0,0, + 5537.546684141998,5537.546684141998 + ] + }, + { + "interval":"2012-03-15T12:17:13.6497999150015Z/2012-03-15T13:49:31.2088613029919Z", + "epoch":"2012-03-15T12:17:13.6497999150015Z", + "number":[ + 0,0, + 5537.55906138799,5537.55906138799 + ] + }, + { + "interval":"2012-03-15T13:49:31.2088613029919Z/2012-03-15T15:21:48.776005533Z", + "epoch":"2012-03-15T13:49:31.2088613029919Z", + "number":[ + 0,0, + 5537.567144230008,5537.567144230008 + ] + }, + { + "interval":"2012-03-15T15:21:48.776005533Z/2012-03-15T16:54:06.33371177400113Z", + "epoch":"2012-03-15T15:21:48.776005533Z", + "number":[ + 0,0, + 5537.557706241001,5537.557706241001 + ] + }, + { + "interval":"2012-03-15T16:54:06.33371177400113Z/2012-03-15T18:26:23.8819795500021Z", + "epoch":"2012-03-15T16:54:06.33371177400113Z", + "number":[ + 0,0, + 5537.548267776001,5537.548267776001 + ] + }, + { + "interval":"2012-03-15T18:26:23.8819795500021Z/2012-03-15T19:58:41.3312553199939Z", + "epoch":"2012-03-15T18:26:23.8819795500021Z", + "number":[ + 0,0, + 5537.449275769992,5537.449275769992 + ] + }, + { + "interval":"2012-03-15T19:58:41.3312553199939Z/2012-03-15T21:30:58.8527762320009Z", + "epoch":"2012-03-15T19:58:41.3312553199939Z", + "number":[ + 0,0, + 5537.521520912007,5537.521520912007 + ] + }, + { + "interval":"2012-03-15T21:30:58.8527762320009Z/2012-03-15T23:03:16.3758652800025Z", + "epoch":"2012-03-15T21:30:58.8527762320009Z", + "number":[ + 0,0, + 5537.523089048002,5537.523089048002 + ] + }, + { + "interval":"2012-03-15T23:03:16.3758652800025Z/2012-03-16T00:35:33.8758586170152Z", + "epoch":"2012-03-15T23:03:16.3758652800025Z", + "number":[ + 0,0, + 5537.499993337013,5537.499993337013 + ] + }, + { + "interval":"2012-03-16T00:35:33.8758586170152Z/2012-03-16T02:07:51.3639393709891Z", + "epoch":"2012-03-16T00:35:33.8758586170152Z", + "number":[ + 0,0, + 5537.488080753974,5537.488080753974 + ] + }, + { + "interval":"2012-03-16T02:07:51.3639393709891Z/2012-03-16T03:40:08.84424079000019Z", + "epoch":"2012-03-16T02:07:51.3639393709891Z", + "number":[ + 0,0, + 5537.480301419011,5537.480301419011 + ] + }, + { + "interval":"2012-03-16T03:40:08.84424079000019Z/2012-03-16T05:12:26.2685025699902Z", + "epoch":"2012-03-16T03:40:08.84424079000019Z", + "number":[ + 0,0, + 5537.42426177999,5537.42426177999 + ] + }, + { + "interval":"2012-03-16T05:12:26.2685025699902Z/2012-03-16T06:44:43.7279617500026Z", + "epoch":"2012-03-16T05:12:26.2685025699902Z", + "number":[ + 0,0, + 5537.459459180012,5537.459459180012 + ] + }, + { + "interval":"2012-03-16T06:44:43.7279617500026Z/2012-03-16T08:17:01.17765616998076Z", + "epoch":"2012-03-16T06:44:43.7279617500026Z", + "number":[ + 0,0, + 5537.449694419978,5537.449694419978 + ] + }, + { + "interval":"2012-03-16T08:17:01.17765616998076Z/2012-03-16T08:27:42.5600708879647Z", + "epoch":"2012-03-16T08:17:01.17765616998076Z", + "number":[ + 0,0, + 5537.439929112035,5537.439929112035 + ] + }, + { + "interval":"2012-03-16T08:27:42.5600708879647Z/2012-03-16T10:00:00Z", + "epoch":"2012-03-16T08:27:42.5600708879647Z", + "number":[ + 0,0, + 5537.439929112035,5537.439929112035 + ] + } + ] + }, + "position":{ + "interpolationAlgorithm":"LAGRANGE", + "interpolationDegree":5, + "referenceFrame":"INERTIAL", + "epoch":"2012-03-15T10:00:00Z", + "cartesian":[ + 0,3849424.41859634,5535808.90838488,-469609.955032837, + 300,2403397.25163735,5923118.10887596,-2208538.08732886, + 600,681059.355577534,5629683.78882362,-3693007.85438243, + 900,-1119416.00777462,4691252.20079689,-4753268.77825646, + 1200,-2792163.54303408,3217045.3927905,-5269236.9636378, + 1500,-4146946.26695958,1376355.11151994,-5183333.77414211, + 1800,-5030073.80001301,-620907.843850796,-4506185.20959366, + 2100,-5341141.73000766,-2547536.97322381,-3315102.27876197, + 2400,-5044213.41576254,-4184126.46337638,-1745607.20300478, + 2700,-4172245.63939562,-5343667.09365887,23409.7618660682, + 3e3,-2823903.53321619,-5893019.5858321,1789694.91494771, + 3300,-1152706.81297821,-5768551.08921845,3350719.50403451, + 3494.253024000005,12647.226754864,-5331683.91916414,4165940.89199221, + 3494.253024000005,13029.0479309608,-5331460.99207657,4166115.22224224, + 3600,650789.93624267,-4983501.3435969,4527207.45547157, + 3900,2379305.75017934,-3627537.39864893,5183179.25792976, + 4200,3834777.21946002,-1855400.2986254,5242729.69023172, + 4500,4849528.23059951,129890.673107136,4698090.47721749, + 4800,5306015.3961238,2100167.56572551,3611124.18995888, + 5100,5150830.60792791,3828302.31094784,2106711.608498, + 5400,4401482.39688381,5114829.18540188,358590.197694369, + 5700,3144674.02408614,5811702.89808911,-1431035.79418686, + 6e3,1525939.53461617,5839838.69437877,-3055607.33495769, + 6300,-267980.182214884,5197915.25437212,-4328682.71628229, + 6600,-2031365.29937242,3961512.87223799,-5105391.73521875, + 6900,-3563213.2763466,2273344.0489862,-5298337.5762072, + 7200,-4689612.83519006,326428.771682565,-4886617.47645177, + 7500,-5282712.94306229,-1657607.93044914,-3917600.03751163, + 7800,-5274754.21237056,-3453007.99287842,-2501594.33092912, + 8100,-4665873.02143146,-4854971.98019869,-799823.217818969, + 8400,-3524604.66138732,-5702910.41801334,993421.369702083, + 8700,-1980586.46565429,-5899120.57098636,2672770.77875102, + 9e3,-209990.19226424,-5420375.16312849,4045403.0406125, + 9300,1584620.06155972,-4320812.37191124,4953336.17627952, + 9600,3197482.28308901,-2725830.9633234,5291644.93513457, + 9868.731839999993,4335118.12525452,-1025094.03550352,5076957.01479314, + 9868.731839999993,4335018.61132235,-1025343.9674375,5077035.18396777, + 9900,4443038.65402268,-818152.432440461,5020664.08503109, + 10200,5177638.17976653,1183789.15226985,4170531.37630724, + 10500,5315710.52847893,3049293.68665747,2838570.0655117, + 10800,4840686.89080989,4563082.50771604,1178298.7746302, + 11100,3807316.87231764,5550567.89507109,-618291.216385065, + 11400,2335314.9664624,5898676.67948854,-2343522.82794638, + 11700,594874.272254555,5568974.91052142,-3798788.25566978, + 1.2e4,-1213816.81950858,4601359.80120866,-4817778.43040243, + 12300,-2884021.70130156,3108323.14089662,-5285177.51260314, + 12600,-4225824.88397817,1261219.92433772,-5148934.77411409, + 12900,-5086993.72268719,-729358.459941565,-4425364.0696591, + 13200,-5369574.39231539,-2636958.95100008,-3197030.8918885, + 13500,-5040837.5197212,-4244298.60262776,-1603714.85512284, + 13800,-4137366.34626142,-5367663.54403821,172926.470930942, + 14100,-2761453.19106198,-5878037.05106202,1929714.21010032, + 14400,-1069805.86733299,-5716261.93867886,3465173.51384947, + 14700,744271.014577194,-4900133.10733316,4602797.70766243, + 1.5e4,2473015.24637326,-3522493.14212366,5211428.32266375, + 15300,3917949.69750226,-1740717.11167563,5220362.57351654, + 15600,4912565.91990974,241050.018704089,4627633.87425256, + 15900,5341597.95913848,2195004.16751206,3500652.18680438, + 16200,5154794.33140615,3895859.5271688,1968954.32783606, + 16500,4373342.05884918,5147295.39445405,209470.919840542, + 16800,3087689.85826338,5805357.43044991,-1574278.60237672, + 17100,1446707.2746503,5795488.70465371,-3176466.52098232, + 17400,-360344.060295147,5120757.79185039,-4413311.43252235, + 17700,-2126304.75226283,3860467.52125647,-5144165.18525407, + 1.8e4,-3649929.17406843,2159984.45316722,-5286887.516213, + 18300,-4758250.11234169,213666.927990528,-4826271.90544669, + 18600,-5325442.2368479,-1756947.10457405,-3815218.86999272, + 18900,-5286657.22396492,-3527602.31698614,-2368820.19001619, + 19200,-4645531.30247392,-4896282.29010561,-651797.787645176, + 19500,-3474297.5624219,-5706180.57236849,1139766.03637674, + 19800,-1906047.93477498,-5863954.29703593,2800659.87029817, + 20100,-119747.901651559,-5350794.90309783,4140162.20596163, + 20400,1680229.19009525,-4224790.44649401,5004082.8628856, + 20700,3287489.2688369,-2614368.27497782,5292531.03251418, + 2.1e4,4517178.30183363,-703777.87584566,4971465.55836947, + 21300,5227207.6648385,1287704.84490596,4076902.01656837, + 21600,5334936.82012406,3130764.60758613,2711278.57345959, + 21900,4827322.58105028,4612697.10330622,1032051.24412722, + 22200,3762924.29010265,5562626.91720275,-766576.689609238, + 22500,2265064.29180843,5871878.64924006,-2476730.65325254, + 22800,506889.553310488,5506538.13251038,-3901627.75375881, + 23100,-1309445.00056429,4510579.15516774,-4878537.15731657, + 23400,-2976402.0280992,2999662.91419282,-5297002.64945855, + 23700,-4304470.18896784,1147095.47806632,-5110539.63058255, + 2.4e4,-5142960.39846207,-835961.695152393,-4341133.17124268, + 24300,-5396449.98957973,-2723906.04437019,-3076534.5475795, + 24600,-5035483.62935387,-4301650.42679393,-1460666.86361877, + 24900,-4100316.26536105,-5388815.78416569,322191.929261417, + 25200,-2696886.30431052,-5860507.97233297,2068100.06234624, + 25500,-985081.652542641,-5662006.20709315,3576793.69154155, + 25800,839459.79250942,-4815326.71580347,4674816.27413303, + 26100,2567753.67880419,-3416822.63632586,5235537.19861624, + 26400,4001341.22224643,-1626275.18017047,5193737.27589445, + 26700,4974974.97424557,351131.478884937,4553277.35585279, + 2.7e4,5375773.87995422,2288048.26911964,3387088.9792563, + 27300,5156748.02950663,3961120.50809531,1829282.25467229, + 27600,4342845.19099752,5177245.67392912,59844.5828064916, + 27900,3028302.49713101,5796600.98139539,-1716563.33131291, + 28200,1365322.17124008,5749152.32120273,-3295029.47245872, + 28500,-454356.746329476,5042305.03137088,-4494597.38838164, + 28800,-2222206.15141325,3758992.7975105,-5178961.77341337, + 29100,-3736821.45847435,2047123.49588175,-5271303.16981529, + 29400,-4826265.95502002,102278.864630022,-4762117.1900019, + 29700,-5366821.81471981,-1854191.86229829,-3709788.89699013, + 3e4,-5296624.22229263,-3599613.59225076,-2234100.76820595, + 30300,-4622868.06480404,-4934799.73886552,-503148.170247627, + 30600,-3421525.18024483,-5706740.4426866,1285341.92829746, + 30900,-1829161.56261067,-5826434.6682239,2926465.90021911, + 31200,-27531.7144464045,-5279448.44528641,4231743.23526868, + 31500,1777212.57374346,-4127757.02234495,5050893.77551254, + 31800,3378103.15780159,-2502741.69029747,5289147.73077336, + 32100,4590977.0373709,-590348.657122951,4918217.20823007, + 32400,5275639.5121592,1389896.8820238,3979865.19308717, + 32517.176831999997,5380098.10478572,2132117.88500271,3480583.59052128, + 32517.176831999997,5380206.78578959,2132704.3566004,3480214.1472366, + 32700,5352360.16433155,3210451.03192908,2581202.47700398, + 3.3e4,4811544.23241305,4660070.40187028,884306.337985066, + 33300,3715810.92574891,5572272.00925959,-914895.68071231, + 33600,2192116.57709469,5842799.91924153,-2608513.17260553, + 33900,416546.428105066,5442236.06083956,-4001762.78504694, + 34200,-1406826.18080549,4418569.09511053,-4935635.03993958, + 34500,-3069733.06488903,2890544.87472284,-5304630.80211245, + 34800,-4383150.76083569,1033328.47975256,-5067879.38290912, + 35100,-5198026.54631352,-941436.515002387,-4253036.88764016, + 35400,-5421566.35735171,-2809075.63112747,-2952995.28558899, + 35700,-5027683.84810168,-4356761.26153088,-1315734.4678681, + 3.6e4,-4060387.62186786,-5407495.6825644,471970.041286316, + 36300,-2629319.40278933,-5840532.63387188,2205562.40102441, + 36600,-897570.045732632,-5605588.3371927,3686149.6135249, + 36900,936905.974602788,-4728874.88306931,4743478.4381812, + 37200,2663958.50480543,-3310205.62360817,5255575.29216226, + 37500,4085238.3175096,-1511695.74486031,5162794.69942285, + 37800,5036875.39765442,460520.818091434,4474863.60855029, + 38100,5408500.33456106,2379649.35813026,3270213.33641568, + 38400,5156502.71194835,4024363.44431024,1687442.37949306, + 38700,4309680.88869103,5204857.1289682,-90545.1306030105, + 3.9e4,2966108.87124662,5785482.51478768,-1858122.30706417, + 39300,1281325.49457454,5700727.20671709,-3411474.84408673, + 39600,-550487.037507769,4962289.69345522,-4572632.48528492, + 39900,-2319493.54179972,3656660.3548582,-5209753.83240227, + 40200,-3824209.81967054,1934199.65577177,-5251412.62186567, + 40500,-4893820.53403162,-8376.93057750767,-4693829.85242935, + 40800,-5406813.43654749,-1949991.09651749,-3600851.87830257, + 41100,-5304406.66726997,-3669618.40613288,-2096885.03389831, + 41400,-4597445.30923729,-4970957.56266923,-353291.724895338, + 41700,-3365711.80596329,-5704831.98690261,1430694.68133986, + 4.2e4,-1749287.19006089,-5786596.35823912,3050635.62042371, + 42300,67282.5104014716,-5206179.73592197,4320450.99966826, + 42600,1876105.53012849,-4029407.41454288,5093914.31300927, + 42900,3469716.53426206,-2390553.98308505,5281488.26936128, + 43200,4664751.44925217,-477181.808910395,4860703.76300645, + 43500,5323035.79623726,1491029.49886786,3879079.76320608, + 43589.759328,5402440.40004548,2056528.00645199,3491627.46684942, + 43589.759328,5402442.54264444,2056738.81686484,3491501.88840014, + 43800,5367840.30507371,3287565.24128733,2449044.98994153, + 44100,4793466.89948304,4704669.22750442,735845.196386836, + 44400,3666300.68694606,5579254.94649742,-1062487.36725239, + 44700,2116947.48184928,5811477.8903838,-2738215.22897224, + 4.5e4,324410.396313805,5376371.6825418,-4098714.1870081, + 45300,-1505371.25160745,4325863.56124646,-4988825.53074582, + 45600,-3163474.68055926,2781685.31685159,-5308091.27375613, + 45900,-4461454.46450387,920751.44587914,-5021285.15291004, + 46200,-5251987.83068379,-1044921.21948849,-4161708.55588854, + 46500,-5444995.16922548,-2891682.7271746,-2827313.90974466, + 46800,-5017826.0163413,-4409036.76825887,-1170010.47688321, + 47100,-4018281.61998877,-5423402.43984196,621088.759416269, + 47400,-2559714.28446385,-5818173.19291614,2340985.6034906, + 47700,-808395.704630906,-5547450.9983423,3792317.64641595, + 4.8e4,1035447.9983595,-4641558.91633002,4808162.62725822, + 48300,2760561.62652593,-3203667.07367331,5271287.27659829, + 48600,4168777.2937882,-1398117.80362934,5127654.23537955, + 48900,5097682.07585487,568104.375379669,4392842.08078676, + 49200,5439501.08861285,2468843.96703679,3150719.8955131, + 49500,5154080.72531675,4084868.12117622,1544267.87631319, + 49800,4274129.47939295,5229707.06682862,-240836.86870874, + 50100,2901588.51435516,5771894.9813108,-1998167.08917933, + 50400,1195328.12796693,5650411.99973262,-3525172.89029405, + 50700,-648065.863983004,4881185.95588798,-4647015.40064705, + 5.1e4,-2417518.44559387,3554173.1319714,-5236422.66927976, + 51300,-3911551.304888,1822079.84885746,-5227416.31542318, + 51600,-4960563.96410311,-117355.616655456,-4621941.65755199, + 51900,-5445340.36795493,-2043429.44720356,-3489249.35182206, + 52200,-5310257.97873623,-3736852.07785834,-1958261.33112716, + 52500,-4569863.84912929,-5004260.18152329,-203458.693372594, + 52800,-3307771.80391093,-5700321.82377175,1574588.75070263, + 53100,-1667567.39473325,-5744714.10305482,3172075.82670534, + 53400,163448.429505371,-5131656.78603713,4405467.10195982, + 53700,1975699.17700698,-3930727.12204608,5132693.71663132, + 5.4e4,3561290.10873786,-2278985.1022354,5269506.88509915, + 54148.15468800001,4203184.07952978,-1353489.53750881,5111445.70468465, + 54148.15468800001,4203191.30262867,-1353475.88589412,5111442.33629379, + 54300,4737737.78046698,-365490.542263622,4799257.56458761, + 54600,5368954.89050152,1589986.17944729,3775186.07047606, + 54900,5381374.56347384,3362167.42325737,2314799.09999447, + 55200,4773053.93352827,4746514.12880929,586645.025608239, + 55500,3614326.93479997,5583552.91481526,-1209386.38537695, + 55800,2039459.06568354,5777834.14557876,-2865875.35129307, + 56100,230353.889530254,5308792.26549321,-4192506.0039312, + 56400,-1605224.578801,4232218.88985275,-5038088.76435784, + 56700,-3257760.70626935,2672746.16024074,-5307286.16717191, + 5.7e4,-4539466.63964283,808949.683395425,-4970553.24732222, + 57300,-5304842.68965046,-1146866.91911664,-4066828.54766123, + 57600,-5466621.8198026,-2972159.5559343,-2699069.09611406, + 57900,-5005678.8581936,-4458833.52479963,-1023009.64607344, + 58200,-3973672.67017912,-5436774.1321751,770044.593415393, + 58500,-2487694.32678156,-5793531.7276185,2474823.52441331, + 58800,-717183.268044322,-5487571.46315032,3895667.50970416, + 59100,1135412.94462176,-4553265.36963682,4869134.29479731, + 59400,2857811.44872052,-3097047.54964928,5282836.82355544, + 59700,4252118.60571663,-1285377.68188911,5088396.78826617, + 6e4,5157476.03077594,674020.929380886,4307236.20275876, + 60300,5468795.1088992,2555731.77859298,3028596.47954634, + 60600,5149455.18246455,4142690.87191001,1399724.51609549, + 60900,4236126.95591789,5251805.34781038,-391079.885552966, + 61200,2834641.93086904,5755792.45957505,-2136754.611779, + 61500,1107196.05353689,5598088.16121645,-3636173.0202672, + 61800,-747252.788966703,4798784.15922154,-4717761.53669296, + 62100,-2516443.11881422,3451220.61614222,-5258915.3231165, + 62400,-3998974.76917799,1710361.73025264,-5199160.16474836, + 62700,-5026550.13601721,-225119.029858565,-4546178.07138944, + 6.3e4,-5482346.83102871,-2134976.21105312,-3374589.79519268, + 63300,-5313997.06814827,-3801730.99838127,-1817750.19592382, + 63600,-4539827.85846879,-5035017.86954231,-53130.9301591509, + 63900,-3247330.33885153,-5693382.22989429,1717523.54805407, + 64200,-1583599.98060968,-5700819.30944626,3291216.20615931, + 64500,261342.090524228,-5055794.75166179,4487118.85260636, + 64800,2076301.68267285,-3831557.43126966,5167447.81526317, + 65100,3653042.56435939,-2167848.84674734,5253319.62533565, + 65400,4810049.038801,-255142.390547666,4733934.55166336, + 65700,5413446.99440722,1686864.70430337,3668199.77871656, + 6.6e4,5392862.16834428,3434394.71396246,2178475.13297448, + 66300,4750196.32199498,4785751.66545322,436744.445152622, + 66600,3559796.52739365,5585316.7296347,-1355528.90652471, + 66900,1959597.20578925,5742025.63690215,-2991415.6046114, + 67200,134376.536240933,5239666.35451623,-4283065.85614241, + 67500,-1706331.07059426,4137818.56427346,-5083382.64756209, + 67800,-3352491.96081032,2563922.03332514,-5302226.99750498, + 68100,-4617064.16569915,698116.184533239,-4915763.52743991, + 68400,-5356466.08495862,-1247101.52462867,-3968546.00809847, + 68700,-5486336.41852137,-3050374.47831377,-2568465.25001707, + 6.9e4,-4991155.60227331,-4506072.59048139,-874966.280892015, + 69106.00003200001,-4675088.88357972,-4904462.29220647,-242107.371110211, + 69106.00003200001,-4674963.43006193,-4904676.83927901,-241826.66183195, + 69300,-3926327.89260015,-5447739.6656541,918866.020571072, + 69600,-2413003.0971971,-5766684.33045901,2607080.91832284, + 69900,-623679.307706445,-5425959.09823221,3996179.06378573, + 70200,1237024.11335224,-4463927.32507537,4926346.27837966, + 70500,2955874.28281264,-2990202.28421801,5290146.7654427, + 70800,4335347.20816686,-1173262.20585629,5044913.31517192, + 71100,5216242.70405186,778530.799227653,4217907.07731278, + 71400,5496260.69417988,2640589.40930168,2903682.37616923, + 71700,5142403.54666242,4198089.22501779,1253644.11189087, + 7.2e4,4195371.21443519,5271357.13164593,-541431.220697357, + 72300,2764921.48219317,5737302.94797553,-2274011.7559695, + 72600,1016577.67885122,5543794.51304654,-3744557.13007387, + 72900,-848361.242067968,4715035.78742378,-4784900.89171273, + 73200,-2616507.19175234,3347680.53244974,-5277212.503935, + 73500,-4086622.1877807,1598870.37343154,-5166586.67068703, + 73800,-5091813.77614537,-331870.766672772,-4466459.62473102, + 74100,-5517764.43038847,-2224840.34855441,-3256788.83205051, + 74400,-5315467.41998746,-3864448.48360322,-1675276.49132697, + 74700,-4507114.79181934,-5063389.5046787,97748.034459793, + 7.5e4,-3184124.73189051,-5684120.41792651,1859531.62860591, + 75300,-1497109.88999113,-5654952.06546536,3408062.23671877, + 75600,361222.120358981,-4978554.80719553,4565381.47677838, + 75900,2178126.06100545,-3731775.80119291,5198117.73976067, + 76200,3745113.46822549,-2056944.55535702,5232830.32818793, + 76500,4881743.39892134,-145833.276595929,4664585.42136462, + 76800,5456445.04082095,1782000.8778115,3557929.78632622, + 77100,5402144.12356169,3504373.03321367,2039988.19446098, + 77400,4724667.04921966,4822486.7484427,286049.40318698, + 77700,3502425.90876414,5584603.2025813,-1501008.43043863, + 7.8e4,1877042.16532639,5704035.19530578,-3114913.22994025, + 78300,36152.4433097746,5168885.3009109,-4370435.33319926, + 78600,-1808985.8806344,4042459.56852687,-5124695.32426894, + 78900,-3447895.4230698,2454929.90464636,-5292838.48153945, + 79200,-4694376.04083089,587917.246969181,-4856779.60954812, + 79500,-5406874.18834785,-1345971.57419841,-3866678.85024478, + 79800,-5504046.34498431,-3126649.11627623,-2435299.58352432, + 80100,-4974076.82345692,-4551020.79550854,-725685.023696793, + 80400,-3876520.14799315,-5456025.84259603,1066926.93178847, + 80700,-2336019.11244069,-5737550.10811308,2737230.19518184, + 8.1e4,-528308.767769235,-5362697.09411111,4093467.41014218, + 81300,1339863.00009893,-4373750.04288914,4979577.30146014, + 81600,3054380.83966471,-2883413.7415267,5293162.12728486, + 81900,4418177.53111484,-1062089.46683839,4997306.49647254, + 82200,5273810.55541913,881318.380504194,4125099.72024297, + 82500,5521868.59835782,2723142.07392809,2776343.07581227, + 82800,5133062.42720615,4250871.17037253,1106480.61319088, + 83100,4152176.15897934,5288297.93859615,-691394.68983223, + 83400,2692908.6058646,5716530.34787588,-2409460.98637571, + 83700,924084.940881169,5487829.34165832,-3849936.15782554, + 8.4e4,-950712.293476668,4630433.68817126,-4848200.08467262, + 84300,-2717045.86353999,3244208.36976243,-5291286.81070567, + 84600,-4173926.65526437,1488361.55584656,-5129895.26438968, + 84900,-5155955.37745777,-436837.457277556,-4383197.33262401, + 85200,-5551402.34469437,-2312317.78907392,-3136419.38414599, + 85500,-5314693.03520338,-3924443.17760687,-1531500.88583952, + 85800,-4471936.40864901,-5089002.50775752,248512.950876881, + 86100,-3118503.91090586,-5672365.37553485,2000019.0666746, + 86400,-1408522.57228522,-5607125.68800775,3522147.91298588 + ] + } + }, + { + "id":"CesiumDrone", + "availability":"2012-03-15T10:00:00Z/2012-03-16T10:00:00Z", + "path":{ + "material":{ + "solidColor":{ + "color":{ + "interval":"2012-03-15T10:00:00Z/2012-03-16T10:00:00Z", + "rgba":[ + 255,255,0,255 + ] + } + } + }, + "width":[ + { + "interval":"2012-03-15T10:00:00Z/2012-03-16T10:00:00Z", + "number":2 + } + ], + "show":[ + { + "interval":"2012-03-15T10:00:00Z/2012-03-16T10:00:00Z", + "boolean":true + } + ] + }, + "model":{ + "gltf":"models/CesiumDrone/CesiumDrone.glb", + "minimumPixelSize":64, + "maximumScale":20000 + }, + "position":{ + "interpolationAlgorithm":"LINEAR", + "epoch":"2012-03-15T10:00:00Z", + "cartesian":[ + 0, -2001494.7936076433, -4745182.384226333, 3752246.7106542974, + 0.01, -2001494.6749603446, -4745182.387314641, 3752246.472892279, + 0.02, -2001494.5645944183, -4745182.367867421, 3752246.251494708, + 0.03, -2001494.462462647, -4745182.326031295, 3752246.046368467, + 0.04, -2001494.3685178126, -4745182.261952886, 3752245.8574204384, + 0.05, -2001494.2827126977, -4745182.1757788155, 3752245.6845575054, + 0.06, -2001494.2050000841, -4745182.067655706, 3752245.527686548, + 0.07, -2001494.1353327534, -4745181.93773018, 3752245.38671445, + 0.08, -2001494.0736634883, -4745181.786148861, 3752245.2615480954, + 0.09, -2001494.0199450708, -4745181.6130583715, 3752245.1520943646, + 0.1, -2001493.974130283, -4745181.418605333, 3752245.05826014, + 0.11, -2001493.9361719068, -4745181.202936369, 3752244.979952306, + 0.12, -2001493.9060227247, -4745180.966198101, 3752244.9170777425, + 0.13, -2001493.8836355186, -4745180.708537152, 3752244.8695433345, + 0.14, -2001493.8689630704, -4745180.430100145, 3752244.8372559627, + 0.15, -2001493.8619581622, -4745180.131033702, 3752244.8201225093, + 0.16, -2001493.8625735764, -4745179.811484443, 3752244.818049858, + 0.17, -2001493.870762095, -4745179.471598997, 3752244.83094489, + 0.18, -2001493.8864765004, -4745179.111523979, 3752244.858714489, + 0.19, -2001493.9096695741, -4745178.731406017, 3752244.901265537, + 0.2, -2001493.9402940986, -4745178.331391732, 3752244.9585049157, + 0.21, -2001493.9783028557, -4745177.911627744, 3752245.0303395083, + 0.22, -2001494.0236486276, -4745177.472260679, 3752245.1166761965, + 0.23, -2001494.0762841967, -4745177.0134371575, 3752245.2174218637, + 0.24, -2001494.1361623448, -4745176.535303803, 3752245.332483392, + 0.25, -2001494.203235854, -4745176.038007238, 3752245.461767663, + 0.26, -2001494.277457507, -4745175.521694084, 3752245.605181561, + 0.27, -2001494.3587800849, -4745174.986510963, 3752245.7626319663, + 0.28, -2001494.4471563704, -4745174.4326045, 3752245.9340257626, + 0.29, -2001494.5425391458, -4745173.860121314, 3752246.119269832, + 0.3, -2001494.6448811926, -4745173.269208032, 3752246.318271057, + 0.31, -2001494.7541352934, -4745172.660011273, 3752246.5309363203, + 0.32, -2001494.8702542305, -4745172.032677661, 3752246.757172504, + 0.33, -2001494.993190785, -4745171.387353817, 3752246.9968864904, + 0.34, -2001495.1228977398, -4745170.724186365, 3752247.2499851626, + 0.35000000000000003, -2001495.2593278768, -4745170.043321926, 3752247.5163754015, + 0.36, -2001495.4024339784, -4745169.344907125, 3752247.795964092, + 0.37, -2001495.552168826, -4745168.629088583, 3752248.088658114, + 0.38, -2001495.7084852026, -4745167.896012922, 3752248.394364352, + 0.39, -2001495.8713358897, -4745167.145826766, 3752248.7129896865, + 0.4, -2001496.0406736694, -4745166.378676737, 3752249.0444410015, + 0.41000000000000003, -2001496.2164513243, -4745165.594709455, 3752249.388625179, + 0.42, -2001496.3986216357, -4745164.794071546, 3752249.745449101, + 0.43, -2001496.5871373867, -4745163.976909631, 3752250.114819651, + 0.44, -2001496.7819513585, -4745163.143370332, 3752250.4966437095, + 0.45, -2001496.9830163338, -4745162.293600273, 3752250.890828161, + 0.46, -2001497.1902850943, -4745161.427746075, 3752251.2972798864, + 0.47000000000000003, -2001497.4037104223, -4745160.545954361, 3752251.7159057693, + 0.48, -2001497.6232451003, -4745159.648371754, 3752252.1466126917, + 0.49, -2001497.8488419093, -4745158.735144875, 3752252.5893075354, + 0.5, -2001498.0804536324, -4745157.8064203495, 3752253.043897184, + 0.51, -2001498.3180330514, -4745156.862344796, 3752253.5102885184, + 0.52, -2001498.5615329486, -4745155.9030648405, 3752253.9883884233, + 0.53, -2001498.8109061054, -4745154.928727103, 3752254.4781037783, + 0.54, -2001499.0661053048, -4745153.939478209, 3752254.979341468, + 0.55, -2001499.3270833283, -4745152.935464778, 3752255.4920083745, + 0.56, -2001499.5937929589, -4745151.916833434, 3752256.01601138, + 0.5700000000000001, -2001499.866186977, -4745150.883730797, 3752256.551257367, + 0.58, -2001500.1442181661, -4745149.836303494, 3752257.097653216, + 0.59, -2001500.4278393078, -4745148.774698145, 3752257.655105813, + 0.6, -2001500.7170031848, -4745147.699061372, 3752258.2235220387, + 0.61, -2001501.0116625784, -4745146.609539798, 3752258.8028087746, + 0.62, -2001501.311770271, -4745145.506280047, 3752259.392872905, + 0.63, -2001501.6172790448, -4745144.3894287385, 3752259.99362131, + 0.64, -2001501.9281416822, -4745143.259132497, 3752260.6049608747, + 0.65, -2001502.2443109641, -4745142.115537945, 3752261.226798479, + 0.66, -2001502.565739674, -4745140.958791705, 3752261.8590410072, + 0.67, -2001502.8923805936, -4745139.789040399, 3752262.5015953407, + 0.68, -2001503.2241865045, -4745138.606430649, 3752263.1543683624, + 0.6900000000000001, -2001503.5611101894, -4745137.411109079, 3752263.817266955, + 0.7000000000000001, -2001503.90310443, -4745136.20322231, 3752264.4901980013, + 0.71, -2001504.2501220086, -4745134.982916965, 3752265.1730683814, + 0.72, -2001504.6021157072, -4745133.750339667, 3752265.8657849813, + 0.73, -2001504.9590383081, -4745132.5056370385, 3752266.5682546794, + 0.74, -2001505.3208425934, -4745131.2489557015, 3752267.2803843617, + 0.75, -2001505.6874813447, -4745129.980442279, 3752268.002080909, + 0.76, -2001506.0589073447, -4745128.700243392, 3752268.7332512033, + 0.77, -2001506.4350733752, -4745127.408505664, 3752269.4738021283, + 0.78, -2001506.815932219, -4745126.105375719, 3752270.2236405653, + 0.79, -2001507.2014366568, -4745124.791000178, 3752270.9826733973, + 0.8, -2001507.5915394716, -4745123.465525664, 3752271.7508075065, + 0.81, -2001507.9861934455, -4745122.129098799, 3752272.527949776, + 0.8200000000000001, -2001508.3853513605, -4745120.781866206, 3752273.3140070876, + 0.8300000000000001, -2001508.7889659987, -4745119.423974507, 3752274.108886324, + 0.84, -2001509.1969901423, -4745118.055570323, 3752274.912494367, + 0.85, -2001509.6093765735, -4745116.67680028, 3752275.7247380996, + 0.86, -2001510.026078074, -4745115.287810999, 3752276.545524404, + 0.87, -2001510.4470474261, -4745113.888749102, 3752277.3747601635, + 0.88, -2001510.872237412, -4745112.479761211, 3752278.2123522596, + 0.89, -2001511.3016008136, -4745111.060993951, 3752279.0582075743, + 0.9, -2001511.7350904134, -4745109.632593941, 3752279.912232992, + 0.91, -2001512.172658993, -4745108.194707805, 3752280.7743353923, + 0.92, -2001512.6142593345, -4745106.747482166, 3752281.64442166, + 0.93, -2001513.0598442205, -4745105.291063646, 3752282.5223986763, + 0.9400000000000001, -2001513.509366433, -4745103.825598869, 3752283.408173325, + 0.9500000000000001, -2001513.9627787536, -4745102.351234455, 3752284.301652487, + 0.96, -2001514.420033965, -4745100.868117028, 3752285.202743045, + 0.97, -2001514.881084849, -4745099.376393211, 3752286.1113518816, + 0.98, -2001515.3458841878, -4745097.876209625, 3752287.02738588, + 0.99, -2001515.8143847631, -4745096.367712893, 3752287.950751922, + 1, -2001516.286539358, -4745094.851049638, 3752288.881356889, + 1.01, -2001516.7623007535, -4745093.326366483, 3752289.8191076657, + 1.02, -2001517.2416217327, -4745091.793810048, 3752290.7639111327, + 1.03, -2001517.7244550765, -4745090.253526959, 3752291.715674173, + 1.04, -2001518.210753568, -4745088.7056638375, 3752292.6743036695, + 1.05, -2001518.7004699889, -4745087.150367304, 3752293.6397065036, + 1.06, -2001519.1935571216, -4745085.587783982, 3752294.6117895595, + 1.07, -2001519.6899677478, -4745084.018060493, 3752295.590459718, + 1.08, -2001520.1896546497, -4745082.441343465, 3752296.5756238624, + 1.09, -2001520.69257061, -4745080.857779513, 3752297.567188874, + 1.1, -2001521.1986684096, -4745079.267515263, 3752298.565061636, + 1.11, -2001521.7079008317, -4745077.670697339, 3752299.5691490313, + 1.12, -2001522.220220658, -4745076.06747236, 3752300.5793579416, + 1.1300000000000001, -2001522.7355806706, -4745074.457986952, 3752301.5955952494, + 1.1400000000000001, -2001523.2539336514, -4745072.842387734, 3752302.617767838, + 1.1500000000000001, -2001523.775232383, -4745071.22082133, 3752303.6457825885, + 1.16, -2001524.299429647, -4745069.593434365, 3752304.6795463846, + 1.17, -2001524.8264782259, -4745067.9603734575, 3752305.718966108, + 1.18, -2001525.3563309014, -4745066.321785234, 3752306.7639486413, + 1.19, -2001525.8889404559, -4745064.677816312, 3752307.8144008666, + 1.2, -2001526.424259672, -4745063.028613319, 3752308.870229667, + 1.21, -2001526.9622413304, -4745061.374322874, 3752309.9313419247, + 1.22, -2001527.5028382144, -4745059.715091602, 3752310.9976445218, + 1.23, -2001528.0460031058, -4745058.051066124, 3752312.0690443404, + 1.24, -2001528.5916887866, -4745056.382393062, 3752313.1454482647, + 1.25, -2001529.1398480386, -4745054.709219039, 3752314.226763175, + 1.26, -2001529.690433645, -4745053.031690679, 3752315.312895955, + 1.27, -2001530.2433983868, -4745051.349954603, 3752316.403753487, + 1.28, -2001530.7986950462, -4745049.664157433, 3752317.499242652, + 1.29, -2001531.3562764057, -4745047.974445794, 3752318.5992703354, + 1.3, -2001531.9160952475, -4745046.280966306, 3752319.703743417, + 1.31, -2001532.478104353, -4745044.583865592, 3752320.8125687805, + 1.32, -2001533.042256505, -4745042.883290276, 3752321.9256533077, + 1.33, -2001533.6085044858, -4745041.179386979, 3752323.0429038815, + 1.34, -2001534.1768010769, -4745039.472302323, 3752324.1642273846, + 1.35, -2001534.7470990603, -4745037.762182932, 3752325.289530698, + 1.36, -2001535.3193512184, -4745036.049175427, 3752326.418720706, + 1.37, -2001535.8935103333, -4745034.333426434, 3752327.55170429, + 1.3800000000000001, -2001536.469529187, -4745032.615082571, 3752328.6883883313, + 1.3900000000000001, -2001537.0473605623, -4745030.894290462, 3752329.8286797157, + 1.4000000000000001, -2001537.6269572403, -4745029.171196731, 3752330.972485322, + 1.41, -2001538.2082720036, -4745027.445947998, 3752332.1197120347, + 1.42, -2001538.7912576338, -4745025.718690887, 3752333.2702667355, + 1.43, -2001539.375866914, -4745023.989572022, 3752334.4240563074, + 1.44, -2001539.9620526256, -4745022.258738022, 3752335.580987633, + 1.45, -2001540.5497675505, -4745020.526335513, 3752336.740967593, + 1.46, -2001541.1389644712, -4745018.792511116, 3752337.903903072, + 1.47, -2001541.7295961701, -4745017.057411453, 3752339.0697009508, + 1.48, -2001542.3216154287, -4745015.321183145, 3752340.238268113, + 1.49, -2001542.9149750294, -4745013.583972818, 3752341.4095114414, + 1.5, -2001543.5096277539, -4745011.845927093, 3752342.5833378164, + 1.51, -2001544.1055263847, -4745010.107192593, 3752343.7596541224, + 1.52, -2001544.7026237042, -4745008.36791594, 3752344.93836724, + 1.53, -2001545.3008724942, -4745006.628243755, 3752346.119384054, + 1.54, -2001545.9002255364, -4745004.888322663, 3752347.302611445, + 1.55, -2001546.5006356132, -4745003.148299283, 3752348.487956296, + 1.56, -2001547.102055507, -4745001.4083202435, 3752349.675325489, + 1.57, -2001547.7044379995, -4744999.668532162, 3752350.8646259075, + 1.58, -2001548.307735873, -4744997.929081662, 3752352.055764433, + 1.59, -2001548.9119019099, -4744996.190115367, 3752353.2486479487, + 1.6, -2001549.5168888916, -4744994.451779898, 3752354.443183336, + 1.61, -2001550.1226496007, -4744992.71422188, 3752355.6392774777, + 1.62, -2001550.7291368193, -4744990.977587933, 3752356.8368372573, + 1.6300000000000001, -2001551.336303329, -4744989.242024681, 3752358.0357695557, + 1.6400000000000001, -2001551.944101913, -4744987.507678745, 3752359.2359812562, + 1.6500000000000001, -2001552.552485352, -4744985.77469675, 3752360.437379241, + 1.6600000000000001, -2001553.1614064288, -4744984.043225315, 3752361.6398703926, + 1.67, -2001553.7708179257, -4744982.313411066, 3752362.843361594, + 1.68, -2001554.3806726248, -4744980.585400623, 3752364.047759726, + 1.69, -2001554.990923308, -4744978.859340611, 3752365.2529716725, + 1.7, -2001555.6015227572, -4744977.13537765, 3752366.4589043153, + 1.71, -2001556.2124237546, -4744975.413658364, 3752367.6654645377, + 1.72, -2001556.8235790825, -4744973.694329374, 3752368.872559221, + 1.73, -2001557.434941523, -4744971.977537303, 3752370.080095248, + 1.74, -2001558.0464638583, -4744970.263428776, 3752371.2879795013, + 1.75, -2001558.65809887, -4744968.5521504115, 3752372.4961188645, + 1.76, -2001559.2697993407, -4744966.843848835, 3752373.704420217, + 1.77, -2001559.8815180522, -4744965.138670668, 3752374.9127904447, + 1.78, -2001560.4932077872, -4744963.436762533, 3752376.1211364274, + 1.79, -2001561.1048213267, -4744961.738271052, 3752377.3293650486, + 1.8, -2001561.7163114536, -4744960.043342849, 3752378.5373831904, + 1.81, -2001562.32763095, -4744958.352124545, 3752379.745097736, + 1.82, -2001562.9387325977, -4744956.664762763, 3752380.9524155674, + 1.83, -2001563.549569179, -4744954.981404126, 3752382.1592435664, + 1.84, -2001564.160093476, -4744953.302195256, 3752383.3654886163, + 1.85, -2001564.7702582711, -4744951.627282775, 3752384.5710575995, + 1.86, -2001565.3800163455, -4744949.956813306, 3752385.7758573983, + 1.87, -2001565.9893204821, -4744948.29093347, 3752386.9797948953, + 1.8800000000000001, -2001566.5981234626, -4744946.6297898935, 3752388.1827769713, + 1.8900000000000001, -2001567.2063780697, -4744944.973529196, 3752389.3847105107, + 1.9000000000000001, -2001567.8140370846, -4744943.322298, 3752390.5855023963, + 1.9100000000000001, -2001568.4210532904, -4744941.676242929, 3752391.785059509, + 1.92, -2001569.0273794683, -4744940.035510604, 3752392.983288732, + 1.93, -2001569.6329684006, -4744938.40024765, 3752394.1800969467, + 1.94, -2001570.2377728699, -4744936.770600688, 3752395.3753910367, + 1.95, -2001570.841745658, -4744935.14671634, 3752396.5690778843, + 1.96, -2001571.4448395472, -4744933.528741228, 3752397.7610643706, + 1.97, -2001572.047007319, -4744931.916821978, 3752398.9512573807, + 1.98, -2001572.648201756, -4744930.3111052085, 3752400.139563795, + 1.99, -2001573.2483756403, -4744928.711737543, 3752401.3258904964, + 2, -2001573.847481754, -4744927.118865605, 3752402.510144368, + 2.0100000000000002, -2001574.4454728789, -4744925.5326360185, 3752403.692232291, + 2.02, -2001575.0423017975, -4744923.9531954015, 3752404.8720611483, + 2.0300000000000002, -2001575.6379212916, -4744922.380690381, 3752406.0495378226, + 2.04, -2001576.2322841436, -4744920.815267576, 3752407.224569196, + 2.05, -2001576.825343135, -4744919.257073613, 3752408.3970621517, + 2.06, -2001577.417051049, -4744917.706255108, 3752409.566923571, + 2.07, -2001578.0073606663, -4744916.162958691, 3752410.7340603373, + 2.08, -2001578.5962247702, -4744914.62733098, 3752411.898379333, + 2.09, -2001579.1835961423, -4744913.099518599, 3752413.059787439, + 2.1, -2001579.7694275647, -4744911.579668171, 3752414.21819154, + 2.11, -2001580.3536718194, -4744910.067926316, 3752415.373498517, + 2.12, -2001580.9362816887, -4744908.564439657, 3752416.525615253, + 2.13, -2001581.5172099548, -4744907.06935482, 3752417.6744486303, + 2.14, -2001582.0964093998, -4744905.582818424, 3752418.8199055307, + 2.15, -2001582.6738328054, -4744904.104977094, 3752419.9618928377, + 2.16, -2001583.249432954, -4744902.635977449, 3752421.1003174335, + 2.17, -2001583.8231626276, -4744901.175966115, 3752422.2350862, + 2.18, -2001584.3949746087, -4744899.725089713, 3752423.36610602, + 2.19, -2001584.9648216788, -4744898.2834948655, 3752424.493283775, + 2.2, -2001585.5326566203, -4744896.851328195, 3752425.616526349, + 2.21, -2001586.0984322154, -4744895.428736324, 3752426.735740623, + 2.22, -2001586.6621012457, -4744894.015865876, 3752427.850833481, + 2.23, -2001587.223616494, -4744892.612863472, 3752428.961711805, + 2.24, -2001587.7829307423, -4744891.219875734, 3752430.0682824757, + 2.25, -2001588.3399967724, -4744889.837049288, 3752431.1704523778, + 2.2600000000000002, -2001588.8947673663, -4744888.464530752, 3752432.2681283923, + 2.27, -2001589.4471953067, -4744887.102466752, 3752433.361217403, + 2.2800000000000002, -2001589.9972333747, -4744885.75100391, 3752434.4496262902, + 2.29, -2001590.5448343533, -4744884.410288846, 3752435.5332619385, + 2.3000000000000003, -2001591.0899510244, -4744883.080468183, 3752436.6120312293, + 2.31, -2001591.6327160893, -4744881.76141283, 3752437.686150879, + 2.32, -2001592.1776619446, -4744880.446213825, 3752438.7634201646, + 2.33, -2001592.7267464276, -4744879.131811127, 3752439.8472201196, + 2.34, -2001593.279928921, -4744877.818192568, 3752440.937492629, + 2.35, -2001593.83716881, -4744876.505345976, 3752442.0341795776, + 2.36, -2001594.3984254773, -4744875.193259181, 3752443.13722285, + 2.37, -2001594.963658308, -4744873.881920016, 3752444.246564331, + 2.38, -2001595.5328266846, -4744872.571316311, 3752445.3621459045, + 2.39, -2001596.1058899916, -4744871.261435894, 3752446.4839094565, + 2.4, -2001596.6828076139, -4744869.952266599, 3752447.6117968694, + 2.41, -2001597.2635389336, -4744868.643796251, 3752448.745750031, + 2.42, -2001597.8480433356, -4744867.336012685, 3752449.8857108233, + 2.43, -2001598.4362802038, -4744866.028903729, 3752451.0316211325, + 2.44, -2001599.0282089214, -4744864.722457214, 3752452.183422842, + 2.45, -2001599.623788873, -4744863.416660971, 3752453.341057838, + 2.46, -2001600.222979442, -4744862.11150283, 3752454.5044680038, + 2.47, -2001600.8257400123, -4744860.80697062, 3752455.6735952245, + 2.48, -2001601.4320299681, -4744859.503052173, 3752456.848381385, + 2.49, -2001602.0418086934, -4744858.199735317, 3752458.028768371, + 2.5, -2001602.6550355714, -4744856.897007885, 3752459.214698064, + 2.5100000000000002, -2001603.271669987, -4744855.594857707, 3752460.4061123524, + 2.52, -2001603.8916713228, -4744854.293272612, 3752461.602953118, + 2.5300000000000002, -2001604.5149989636, -4744852.992240431, 3752462.8051622473, + 2.54, -2001605.1416122927, -4744851.691748995, 3752464.0126816235, + 2.5500000000000003, -2001605.7714706946, -4744850.391786134, 3752465.2254531323, + 2.56, -2001606.4045335527, -4744849.092339676, 3752466.4434186583, + 2.57, -2001607.0407602508, -4744847.793397455, 3752467.666520086, + 2.58, -2001607.6801101733, -4744846.494947298, 3752468.8946993, + 2.59, -2001608.3225427035, -4744845.19697704, 3752470.1278981846, + 2.6, -2001608.9680172259, -4744843.899474505, 3752471.3660586253, + 2.61, -2001609.6164931231, -4744842.602427528, 3752472.609122506, + 2.62, -2001610.2679297808, -4744841.305823939, 3752473.8570317114, + 2.63, -2001610.9222865815, -4744840.009651566, 3752475.1097281273, + 2.64, -2001611.5795229096, -4744838.7138982415, 3752476.367153636, + 2.65, -2001612.239598149, -4744837.418551795, 3752477.629250125, + 2.66, -2001612.9024716835, -4744836.123600055, 3752478.895959477, + 2.67, -2001613.5681028967, -4744834.8290308565, 3752480.1672235783, + 2.68, -2001614.2364511734, -4744833.534832025, 3752481.442984311, + 2.69, -2001614.907475896, -4744832.240991393, 3752482.7231835625, + 2.7, -2001615.5811364495, -4744830.94749679, 3752484.0077632153, + 2.71, -2001616.2573922176, -4744829.65433605, 3752485.296665156, + 2.72, -2001616.936202584, -4744828.361496998, 3752486.5898312675, + 2.73, -2001617.6175269322, -4744827.068967466, 3752487.887203435, + 2.74, -2001618.301324647, -4744825.776735286, 3752489.188723544, + 2.75, -2001618.9875551118, -4744824.484788287, 3752490.4943334786, + 2.7600000000000002, -2001619.6761777098, -4744823.193114301, 3752491.8039751234, + 2.77, -2001620.367151826, -4744821.901701155, 3752493.117590363, + 2.7800000000000002, -2001621.0604368434, -4744820.610536682, 3752494.4351210827, + 2.79, -2001621.7559921464, -4744819.319608712, 3752495.756509166, + 2.8000000000000003, -2001622.4537771186, -4744818.028905075, 3752497.081696498, + 2.81, -2001623.1537511442, -4744816.7384136, 3752498.4106249646, + 2.82, -2001623.855873607, -4744815.44812212, 3752499.7432364486, + 2.83, -2001624.5601038905, -4744814.158018464, 3752501.079472836, + 2.84, -2001625.266401379, -4744812.868090463, 3752502.41927601, + 2.85, -2001625.974725456, -4744811.578325945, 3752503.762587857, + 2.86, -2001626.6850355056, -4744810.288712743, 3752505.109350261, + 2.87, -2001627.3972909115, -4744808.999238685, 3752506.459505106, + 2.88, -2001628.111451058, -4744807.709891603, 3752507.812994277, + 2.89, -2001628.8274753282, -4744806.420659328, 3752509.169759659, + 2.9, -2001629.5453231072, -4744805.131529689, 3752510.529743138, + 2.91, -2001630.2649537777, -4744803.842490517, 3752511.8928865953, + 2.92, -2001630.9863267243, -4744802.553529641, 3752513.2591319177, + 2.93, -2001631.7094013302, -4744801.264634892, 3752514.6284209904, + 2.94, -2001632.43413698, -4744799.975794102, 3752516.0006956975, + 2.95, -2001633.160493057, -4744798.686995099, 3752517.3758979226, + 2.96, -2001633.8884289453, -4744797.398225715, 3752518.7539695515, + 2.97, -2001634.6179040289, -4744796.10947378, 3752520.134852469, + 2.98, -2001635.3488776917, -4744794.820727122, 3752521.5184885585, + 2.99, -2001636.081309317, -4744793.531973574, 3752522.9048197055, + 3, -2001636.8151582892, -4744792.243200966, 3752524.293787795, + 3.0100000000000002, -2001637.5503839923, -4744790.954397128, 3752525.6853347123, + 3.02, -2001638.2869458098, -4744789.665549891, 3752527.07940234, + 3.0300000000000002, -2001639.024803126, -4744788.376647083, 3752528.4759325637, + 3.04, -2001639.7639153244, -4744787.087676537, 3752529.874867269, + 3.0500000000000003, -2001640.5042417888, -4744785.798626083, 3752531.2761483383, + 3.06, -2001641.245741903, -4744784.509483549, 3752532.6797176586, + 3.0700000000000003, -2001641.9883750516, -4744783.220236768, 3752534.0855171145, + 3.08, -2001642.732100618, -4744781.930873568, 3752535.493488589, + 3.09, -2001643.4768779862, -4744780.641381782, 3752536.9035739675, + 3.1, -2001644.22266654, -4744779.351749239, 3752538.315715136, + 3.11, -2001644.9694256624, -4744778.061963769, 3752539.729853976, + 3.12, -2001645.7171147391, -4744776.772013201, 3752541.1459323764, + 3.13, -2001646.465693152, -4744775.481885369, 3752542.5638922174, + 3.14, -2001647.2151202867, -4744774.191568101, 3752543.9836753868, + 3.15, -2001647.965355526, -4744772.9010492265, 3752545.4052237687, + 3.16, -2001648.7163582544, -4744771.610316578, 3752546.8284792467, + 3.17, -2001649.4680878553, -4744770.319357984, 3752548.2533837063, + 3.18, -2001650.2205037123, -4744769.028161276, 3752549.6798790325, + 3.19, -2001650.9735652106, -4744767.736714284, 3752551.1079071094, + 3.2, -2001651.7272317328, -4744766.4450048385, 3752552.5374098215, + 3.21, -2001652.481462663, -4744765.15302077, 3752553.9683290534, + 3.22, -2001653.2362173854, -4744763.860749909, 3752555.4006066895, + 3.23, -2001653.9914552837, -4744762.568180083, 3752556.8341846163, + 3.24, -2001654.7471357416, -4744761.275299125, 3752558.269004716, + 3.25, -2001655.5032181435, -4744759.982094867, 3752559.705008876, + 3.2600000000000002, -2001656.2596618726, -4744758.688555134, 3752561.1421389775, + 3.27, -2001657.0164263134, -4744757.394667762, 3752562.5803369083, + 3.2800000000000002, -2001657.7734708497, -4744756.100420579, 3752564.019544552, + 3.29, -2001658.5307548651, -4744754.805801415, 3752565.459703793, + 3.3000000000000003, -2001659.2882377428, -4744753.5107981, 3752566.900756515, + 3.31, -2001660.0458788679, -4744752.215398465, 3752568.342644605, + 3.3200000000000003, -2001660.8036376238, -4744750.919590341, 3752569.7853099452, + 3.33, -2001661.5614733943, -4744749.623361556, 3752571.2286944217, + 3.34, -2001662.3193455637, -4744748.326699944, 3752572.6727399197, + 3.35, -2001663.0772135153, -4744747.029593333, 3752574.117388323, + 3.36, -2001663.8350366333, -4744745.732029552, 3752575.562581516, + 3.37, -2001664.5927743008, -4744744.433996432, 3752577.0082613835, + 3.38, -2001665.350385903, -4744743.135481808, 3752578.4543698104, + 3.39, -2001666.1078308225, -4744741.836473504, 3752579.900848681, + 3.4, -2001666.865068445, -4744740.536959354, 3752581.3476398815, + 3.41, -2001667.6220581515, -4744739.236927187, 3752582.794685294, + 3.42, -2001668.3787593287, -4744737.936364833, 3752584.241926805, + 3.43, -2001669.135131359, -4744736.635260124, 3752585.6893062997, + 3.44, -2001669.891133627, -4744735.333600888, 3752587.1367656607, + 3.45, -2001670.6467255158, -4744734.0313749565, 3752588.5842467733, + 3.46, -2001671.4018664092, -4744732.72857016, 3752590.0316915233, + 3.47, -2001672.1565156921, -4744731.42517433, 3752591.4790417934, + 3.48, -2001672.9106327477, -4744730.121175296, 3752592.926239471, + 3.49, -2001673.6641769598, -4744728.816560886, 3752594.3732264386, + 3.5, -2001674.4171077125, -4744727.511318934, 3752595.819944582, + 3.5100000000000002, -2001675.1693843897, -4744726.205437266, 3752597.266335785, + 3.52, -2001675.9209663752, -4744724.898903716, 3752598.7123419326, + 3.5300000000000002, -2001676.6718130526, -4744723.591706115, 3752600.1579049095, + 3.54, -2001677.4218838066, -4744722.28383229, 3752601.602966601, + 3.5500000000000003, -2001678.171138019, -4744720.975270073, 3752603.0474688895, + 3.56, -2001678.9195350765, -4744719.666007295, 3752604.4913536627, + 3.5700000000000003, -2001679.6670343617, -4744718.356031785, 3752605.9345628037, + 3.58, -2001680.4135952583, -4744717.045331374, 3752607.3770381976, + 3.59, -2001681.1591771494, -4744715.733893892, 3752608.818721728, + 3.6, -2001681.903739421, -4744714.42170717, 3752610.2595552807, + 3.61, -2001682.647241455, -4744713.108759037, 3752611.69948074, + 3.62, -2001683.3896426363, -4744711.7950373255, 3752613.138439991, + 3.63, -2001684.1309023486, -4744710.480529864, 3752614.5763749173, + 3.64, -2001684.8709799754, -4744709.165224483, 3752616.013227404, + 3.65, -2001685.609834901, -4744707.849109014, 3752617.4489393365, + 3.66, -2001686.3474265097, -4744706.532171288, 3752618.8834525994, + 3.67, -2001687.083714184, -4744705.21439913, 3752620.3167090756, + 3.68, -2001687.8186573084, -4744703.895780376, 3752621.7486506514, + 3.69, -2001688.552215268, -4744702.576302855, 3752623.1792192124, + 3.7, -2001689.2843474443, -4744701.255954396, 3752624.608356641, + 3.71, -2001690.0150132228, -4744699.934722832, 3752626.0360048222, + 3.72, -2001690.7441719878, -4744698.612595991, 3752627.462105642, + 3.73, -2001691.471783122, -4744697.289561704, 3752628.886600985, + 3.74, -2001692.19780601, -4744695.9656078005, 3752630.3094327343, + 3.75, -2001692.9222000348, -4744694.640722111, 3752631.730542776, + 3.7600000000000002, -2001693.6449245815, -4744693.314892468, 3752633.149872994, + 3.77, -2001694.3659390335, -4744691.9881067, 3752634.567365274, + 3.7800000000000002, -2001695.085202773, -4744690.660352635, 3752635.982961498, + 3.79, -2001695.8026751874, -4744689.33161811, 3752637.3966035554, + 3.8000000000000003, -2001696.518315657, -4744688.001890948, 3752638.8082333254, + 3.81, -2001697.2320835681, -4744686.671158982, 3752640.217792696, + 3.8200000000000003, -2001697.9439383033, -4744685.339410045, 3752641.625223551, + 3.83, -2001698.6538392473, -4744684.006631965, 3752643.0304677757, + 3.84, -2001699.361745783, -4744682.672812573, 3752644.433467254, + 3.85, -2001700.0676172958, -4744681.337939697, 3752645.8341638716, + 3.86, -2001700.7714131677, -4744680.002001171, 3752647.232499512, + 3.87, -2001701.4730927837, -4744678.664984823, 3752648.6284160595, + 3.88, -2001702.1726155272, -4744677.326878484, 3752650.0218554, + 3.89, -2001702.8699407831, -4744675.987669984, 3752651.4127594177, + 3.9, -2001703.565027934, -4744674.647347153, 3752652.8010699977, + 3.91, -2001704.2578363644, -4744673.305897824, 3752654.186729023, + 3.92, -2001704.9483254577, -4744671.963309822, 3752655.5696783806, + 3.93, -2001705.636454599, -4744670.619570982, 3752656.9498599544, + 3.94, -2001706.3221831704, -4744669.274669133, 3752658.3272156273, + 3.95, -2001707.0054705571, -4744667.928592104, 3752659.7016872857, + 3.96, -2001707.6862761425, -4744666.58132773, 3752661.0732168145, + 3.97, -2001708.3645593105, -4744665.232863835, 3752662.441746097, + 3.98, -2001709.0402794452, -4744663.883188252, 3752663.8072170196, + 3.99, -2001709.7133959297, -4744662.532288813, 3752665.1695714653, + 4, -2001710.3838681488, -4744661.180153347, 3752666.52875132, + 4.01, -2001711.051655486, -4744659.826769683, 3752667.8846984673, + 4.0200000000000005, -2001711.7167173256, -4744658.472125653, 3752669.2373547936, + 4.03, -2001712.3790130506, -4744657.116209087, 3752670.586662181, + 4.04, -2001713.0385020457, -4744655.759007814, 3752671.932562516, + 4.05, -2001713.6951436945, -4744654.400509668, 3752673.2749976823, + 4.0600000000000005, -2001714.3488973803, -4744653.040702475, 3752674.613909566, + 4.07, -2001714.9997224878, -4744651.679574068, 3752675.9492400507, + 4.08, -2001715.6475784003, -4744650.3171122745, 3752677.28093102, + 4.09, -2001716.2924245019, -4744648.95330493, 3752678.608924361, + 4.1, -2001716.9342201767, -4744647.58813986, 3752679.9331619563, + 4.11, -2001717.5729248088, -4744646.221604898, 3752681.253585693, + 4.12, -2001718.208497781, -4744644.85368787, 3752682.5701374523, + 4.13, -2001718.840898478, -4744643.484376612, 3752683.882759121, + 4.14, -2001719.4700862837, -4744642.113658951, 3752685.1913925842, + 4.15, -2001720.0960205814, -4744640.741522716, 3752686.495979725, + 4.16, -2001720.7186607558, -4744639.367955741, 3752687.796462429, + 4.17, -2001721.3379661902, -4744637.992945855, 3752689.092782582, + 4.18, -2001721.9538962683, -4744636.616480886, 3752690.3848820664, + 4.19, -2001722.5664103746, -4744635.238548667, 3752691.6727027674, + 4.2, -2001723.175467892, -4744633.859137026, 3752692.95618657, + 4.21, -2001723.7810282058, -4744632.478233797, 3752694.23527536, + 4.22, -2001724.3830506988, -4744631.095826808, 3752695.5099110208, + 4.23, -2001724.9814947553, -4744629.71190389, 3752696.7800354376, + 4.24, -2001725.5763197588, -4744628.326452871, 3752698.0455904943, + 4.25, -2001726.1674850932, -4744626.939461582, 3752699.306518076, + 4.26, -2001726.7549501434, -4744625.550917858, 3752700.5627600676, + 4.2700000000000005, -2001727.3386742922, -4744624.160809525, 3752701.814258354, + 4.28, -2001727.9186169228, -4744622.769124413, 3752703.0609548185, + 4.29, -2001728.494737421, -4744621.375850354, 3752704.302791348, + 4.3, -2001729.0669951695, -4744619.980975179, 3752705.539709825, + 4.3100000000000005, -2001729.6353495521, -4744618.584486716, 3752706.771652135, + 4.32, -2001730.199759953, -4744617.186372796, 3752707.9985601623, + 4.33, -2001730.7601857563, -4744615.786621251, 3752709.2203757935, + 4.34, -2001731.3165863454, -4744614.385219909, 3752710.43704091, + 4.3500000000000005, -2001731.8689211044, -4744612.982156602, 3752711.648497399, + 4.36, -2001732.4171494169, -4744611.577419161, 3752712.854687144, + 4.37, -2001732.961230667, -4744610.170995413, 3752714.05555203, + 4.38, -2001733.5011242393, -4744608.762873193, 3752715.251033943, + 4.39, -2001734.0367895162, -4744607.353040327, 3752716.441074765, + 4.4, -2001734.568185883, -4744605.941484649, 3752717.6256163823, + 4.41, -2001735.0952727222, -4744604.528193985, 3752718.804600679, + 4.42, -2001735.6180094192, -4744603.1131561715, 3752719.977969541, + 4.43, -2001736.1363553563, -4744601.696359032, 3752721.145664851, + 4.44, -2001736.6502699184, -4744600.2777904, 3752722.307628495, + 4.45, -2001737.1597124883, -4744598.857438105, 3752723.463802356, + 4.46, -2001737.6646424516, -4744597.435289981, 3752724.614128322, + 4.47, -2001738.165019191, -4744596.011333853, 3752725.758548274, + 4.48, -2001738.6608020905, -4744594.585557555, 3752726.8970040996, + 4.49, -2001739.1519505344, -4744593.157948917, 3752728.029437681, + 4.5, -2001739.6384239064, -4744591.728495766, 3752729.1557909055, + 4.51, -2001740.1201815906, -4744590.297185939, 3752730.276005657, + 4.5200000000000005, -2001740.5971829693, -4744588.864007259, 3752731.390023817, + 4.53, -2001741.069387429, -4744587.428947561, 3752732.497787275, + 4.54, -2001741.5367543516, -4744585.991994673, 3752733.599237912, + 4.55, -2001741.9992431207, -4744584.553136425, 3752734.6943176123, + 4.5600000000000005, -2001742.4568131221, -4744583.112360651, 3752735.782968265, + 4.57, -2001742.909423738, -4744581.669655177, 3752736.8651317502, + 4.58, -2001743.3570343528, -4744580.225007836, 3752737.940749955, + 4.59, -2001743.7996043516, -4744578.778406458, 3752739.009764764, + 4.6000000000000005, -2001744.2370931157, -4744577.329838871, 3752740.07211806, + 4.61, -2001744.669460031, -4744575.879292907, 3752741.12775173, + 4.62, -2001745.0970869055, -4744574.427482435, 3752742.1766900457, + 4.63, -2001745.5229124152, -4744572.979474777, 3752743.2194917803, + 4.64, -2001745.947499207, -4744571.5361846825, 3752744.256312205, + 4.65, -2001746.370836397, -4744570.09753558, 3752745.2871995918, + 4.66, -2001746.7929131014, -4744568.663450893, 3752746.312202213, + 4.67, -2001747.213718437, -4744567.233854045, 3752747.33136834, + 4.68, -2001747.6332415189, -4744565.808668458, 3752748.344746246, + 4.69, -2001748.0514714646, -4744564.387817559, 3752749.3523842026, + 4.7, -2001748.4683973899, -4744562.971224771, 3752750.354330481, + 4.71, -2001748.8840084113, -4744561.558813518, 3752751.3506333544, + 4.72, -2001749.298293645, -4744560.150507223, 3752752.341341094, + 4.73, -2001749.7112422076, -4744558.746229312, 3752753.3265019734, + 4.74, -2001750.1228432148, -4744557.3459032085, 3752754.306164263, + 4.75, -2001750.5330857832, -4744555.949452334, 3752755.280376236, + 4.76, -2001750.9419590293, -4744554.556800118, 3752756.2491861633, + 4.7700000000000005, -2001751.3494520697, -4744553.167869979, 3752757.212642318, + 4.78, -2001751.7555540195, -4744551.782585344, 3752758.1707929717, + 4.79, -2001752.1602539963, -4744550.400869635, 3752759.123686397, + 4.8, -2001752.5635411157, -4744549.022646281, 3752760.0713708648, + 4.8100000000000005, -2001752.965404494, -4744547.6478387, 3752761.013894649, + 4.82, -2001753.3658332478, -4744546.2763703205, 3752761.9513060204, + 4.83, -2001753.7648164935, -4744544.908164563, 3752762.883653251, + 4.84, -2001754.1623433472, -4744543.543144854, 3752763.8109846143, + 4.8500000000000005, -2001754.558402925, -4744542.181234618, 3752764.73334838, + 4.86, -2001754.9529843435, -4744540.822357276, 3752765.650792822, + 4.87, -2001755.3460767188, -4744539.466436255, 3752766.563366211, + 4.88, -2001755.7376691673, -4744538.113394978, 3752767.471116821, + 4.89, -2001756.1277508056, -4744536.7631568685, 3752768.3740929225, + 4.9, -2001756.5163107496, -4744535.4156453535, 3752769.272342788, + 4.91, -2001756.9033381157, -4744534.070783853, 3752770.1659146897, + 4.92, -2001757.2888220204, -4744532.728495793, 3752771.0548569, + 4.93, -2001757.67275158, -4744531.388704599, 3752771.939217691, + 4.94, -2001758.05511591, -4744530.051333691, 3752772.819045333, + 4.95, -2001758.4359041278, -4744528.7163064955, 3752773.6943881004, + 4.96, -2001758.8151053495, -4744527.383546439, 3752774.565294264, + 4.97, -2001759.192708691, -4744526.052976942, 3752775.4318120973, + 4.98, -2001759.5687032687, -4744524.724521429, 3752776.2939898698, + 4.99, -2001759.943078199, -4744523.398103327, 3752777.151875856, + 5, -2001760.315822598, -4744522.073646057, 3752778.0055183265, + 5.01, -2001760.6869255826, -4744520.751073043, 3752778.854965554, + 5.0200000000000005, -2001761.0563762684, -4744519.4303077115, 3752779.7002658104, + 5.03, -2001761.4241637725, -4744518.111273485, 3752780.541467368, + 5.04, -2001761.7902772103, -4744516.793893786, 3752781.3786184983, + 5.05, -2001762.1547056986, -4744515.478092042, 3752782.2117674747, + 5.0600000000000005, -2001762.5174383537, -4744514.163791675, 3752783.0409625676, + 5.07, -2001762.8784642918, -4744512.850916111, 3752783.8662520503, + 5.08, -2001763.2377726294, -4744511.539388769, 3752784.6876841947, + 5.09, -2001763.5953524825, -4744510.229133078, 3752785.5053072725, + 5.1000000000000005, -2001763.9511929674, -4744508.9200724615, 3752786.3191695563, + 5.11, -2001764.305283201, -4744507.612130342, 3752787.1293193162, + 5.12, -2001764.6576122986, -4744506.305230144, 3752787.935804827, + 5.13, -2001765.0081693777, -4744504.999295292, 3752788.73867436, + 5.14, -2001765.3569435535, -4744503.69424921, 3752789.5379761863, + 5.15, -2001765.703923943, -4744502.390015322, 3752790.3337585786, + 5.16, -2001766.0490996623, -4744501.086517052, 3752791.1260698093, + 5.17, -2001766.3924598277, -4744499.783677824, 3752791.9149581497, + 5.18, -2001766.7339935554, -4744498.481421062, 3752792.7004718725, + 5.19, -2001767.0736899623, -4744497.17967019, 3752793.4826592496, + 5.2, -2001767.4115381637, -4744495.878348634, 3752794.2615685533, + 5.21, -2001767.7475272764, -4744494.577379814, 3752795.0372480545, + 5.22, -2001768.0816464168, -4744493.276687157, 3752795.809746027, + 5.23, -2001768.4138847017, -4744491.976194088, 3752796.579110742, + 5.24, -2001768.7442312462, -4744490.675824029, 3752797.3453904726, + 5.25, -2001769.0726751674, -4744489.375500403, 3752798.1086334884, + 5.26, -2001769.3992055818, -4744488.075146639, 3752798.8688880643, + 5.2700000000000005, -2001769.723811605, -4744486.774686155, 3752799.6262024706, + 5.28, -2001770.046482354, -4744485.474042379, 3752800.38062498, + 5.29, -2001770.3672069444, -4744484.173138733, 3752801.132203864, + 5.3, -2001770.685974493, -4744482.871898643, 3752801.880987395, + 5.3100000000000005, -2001771.002774116, -4744481.570245531, 3752802.627023846, + 5.32, -2001771.3175949298, -4744480.268102823, 3752803.3703614883, + 5.33, -2001771.6304260504, -4744478.965393941, 3752804.111048593, + 5.34, -2001771.9412565944, -4744477.662042311, 3752804.8491334333, + 5.3500000000000005, -2001772.250075678, -4744476.357971357, 3752805.5846642824, + 5.36, -2001772.5568724177, -4744475.053104502, 3752806.3176894095, + 5.37, -2001772.8616359294, -4744473.747365169, 3752807.0482570897, + 5.38, -2001773.16435533, -4744472.440676786, 3752807.7764155935, + 5.39, -2001773.465019735, -4744471.132962774, 3752808.5022131917, + 5.4, -2001773.7636182613, -4744469.824146556, 3752809.225698159, + 5.41, -2001774.0601400253, -4744468.514151559, 3752809.946918766, + 5.42, -2001774.3545741427, -4744467.202901205, 3752810.6659232853, + 5.43, -2001774.6469097305, -4744465.89031892, 3752811.3827599883, + 5.44, -2001774.937135904, -4744464.576328126, 3752812.0974771474, + 5.45, -2001775.2252417807, -4744463.260852248, 3752812.8101230348, + 5.46, -2001775.5112164766, -4744461.943814711, 3752813.520745923, + 5.47, -2001775.7950491074, -4744460.625138938, 3752814.2293940824, + 5.48, -2001776.07672879, -4744459.304748353, 3752814.9361157883, + 5.49, -2001776.3562446402, -4744457.98256638, 3752815.6409593094, + 5.5, -2001776.633585775, -4744456.658516442, 3752816.34397292, + 5.51, -2001776.9087413105, -4744455.332521968, 3752817.045204891, + 5.5200000000000005, -2001777.1817003624, -4744454.004506376, 3752817.744703495, + 5.53, -2001777.4524520475, -4744452.674393092, 3752818.4425170035, + 5.54, -2001777.7209854822, -4744451.342105541, 3752819.138693689, + 5.55, -2001777.9872897821, -4744450.007567149, 3752819.8332818234, + 5.5600000000000005, -2001778.2513540646, -4744448.670701335, 3752820.5263296794, + 5.57, -2001778.5131674453, -4744447.331431527, 3752821.217885528, + 5.58, -2001778.7727190405, -4744445.989681147, 3752821.907997643, + 5.59, -2001779.029997967, -4744444.645373621, 3752822.5967142945, + 5.6000000000000005, -2001779.2849933403, -4744443.298432372, 3752823.284083755, + 5.61, -2001779.5376942775, -4744441.9487808235, 3752823.970154298, + 5.62, -2001779.7880898947, -4744440.596342401, 3752824.6549741942, + 5.63, -2001780.0361693078, -4744439.241040526, 3752825.338591716, + 5.64, -2001780.2819216338, -4744437.882798627, 3752826.0210551354, + 5.65, -2001780.5253359883, -4744436.521540123, 3752826.7024127254, + 5.66, -2001780.766401488, -4744435.157188442, 3752827.382712756, + 5.67, -2001781.0051072487, -4744433.789667005, 3752828.062003501, + 5.68, -2001781.241442388, -4744432.418899238, 3752828.7403332326, + 5.69, -2001781.47539602, -4744431.044808565, 3752829.417750222, + 5.7, -2001781.706957264, -4744429.66731841, 3752830.094302742, + 5.71, -2001781.9361152337, -4744428.286352197, 3752830.7700390634, + 5.72, -2001782.1628590466, -4744426.90183335, 3752831.44500746, + 5.73, -2001782.3871778185, -4744425.513685291, 3752832.1192562026, + 5.74, -2001782.609060666, -4744424.121831448, 3752832.792833564, + 5.75, -2001782.8284967048, -4744422.726195241, 3752833.4657878154, + 5.76, -2001783.0454750527, -4744421.326700099, 3752834.13816723, + 5.7700000000000005, -2001783.259984825, -4744419.923269441, 3752834.810020079, + 5.78, -2001783.4720151378, -4744418.515826694, 3752835.4813946346, + 5.79, -2001783.6815551072, -4744417.10429528, 3752836.1523391698, + 5.8, -2001783.888593851, -4744415.688598626, 3752836.8229019553, + 5.8100000000000005, -2001784.093120484, -4744414.268660154, 3752837.4931312646, + 5.82, -2001784.2951241226, -4744412.844403289, 3752838.163075368, + 5.83, -2001784.4945938839, -4744411.4157514535, 3752838.832782538, + 5.84, -2001784.691518884, -4744409.982628074, 3752839.5023010494, + 5.8500000000000005, -2001784.885888239, -4744408.544956572, 3752840.1716791713, + 5.86, -2001785.0776910651, -4744407.102660374, 3752840.8409651765, + 5.87, -2001785.2669164788, -4744405.655662902, 3752841.5102073373, + 5.88, -2001785.4535535963, -4744404.203887582, 3752842.179453925, + 5.89, -2001785.6375915336, -4744402.747257836, 3752842.848753213, + 5.9, -2001785.8190194075, -4744401.285697089, 3752843.518153473, + 5.91, -2001785.9978263343, -4744399.819128765, 3752844.1877029757, + 5.92, -2001786.1740014304, -4744398.347476289, 3752844.8574499954, + 5.93, -2001786.3475338123, -4744396.870663084, 3752845.5274428027, + 5.94, -2001786.5184125947, -4744395.388612574, 3752846.19772967, + 5.95, -2001786.686626896, -4744393.901248184, 3752846.86835887, + 5.96, -2001786.852165831, -4744392.408493337, 3752847.5393786724, + 5.97, -2001787.015018517, -4744390.910271457, 3752848.2108373526, + 5.98, -2001787.1751740696, -4744389.406505971, 3752848.882783181, + 5.99, -2001787.3326216058, -4744387.897120299, 3752849.5552644297, + 6, -2001787.4873502413, -4744386.382037868, 3752850.228329371, + 6.01, -2001787.6393490927, -4744384.861182096, 3752850.9020262756, + 6.0200000000000005, -2001787.788607276, -4744383.334476418, 3752851.576403419, + 6.03, -2001787.9351139076, -4744381.801844249, 3752852.25150907, + 6.04, -2001788.0788581045, -4744380.263209017, 3752852.9273915016, + 6.05, -2001788.219828982, -4744378.718494144, 3752853.6040989864, + 6.0600000000000005, -2001788.358015657, -4744377.167623056, 3752854.2816797956, + 6.07, -2001788.4934072462, -4744375.610519176, 3752854.9601822025, + 6.08, -2001788.6259928644, -4744374.047105929, 3752855.6396544785, + 6.09, -2001788.75576163, -4744372.477306738, 3752856.3201448955, + 6.1000000000000005, -2001788.882702657, -4744370.901045026, 3752857.0017017256, + 6.11, -2001789.0068050632, -4744369.31824422, 3752857.6843732414, + 6.12, -2001789.1280579655, -4744367.728827743, 3752858.3682077145, + 6.13, -2001789.2464504782, -4744366.1327190185, 3752859.053253417, + 6.140000000000001, -2001789.3619717192, -4744364.52984147, 3752859.7395586213, + 6.15, -2001789.4746108036, -4744362.920118521, 3752860.427171598, + 6.16, -2001789.5843568495, -4744361.303473598, 3752861.1161406217, + 6.17, -2001789.6911989716, -4744359.679830125, 3752861.8065139633, + 6.18, -2001789.795126287, -4744358.049111525, 3752862.4983398947, + 6.19, -2001789.8961279108, -4744356.41124122, 3752863.1916666874, + 6.2, -2001789.9941929616, -4744354.766142638, 3752863.886542615, + 6.21, -2001790.0893105536, -4744353.113739202, 3752864.5830159476, + 6.22, -2001790.1814698034, -4744351.4539543325, 3752865.2811349584, + 6.23, -2001790.2706598283, -4744349.786711458, 3752865.9809479206, + 6.24, -2001790.3568697446, -4744348.111934002, 3752866.6825031047, + 6.25, -2001790.4400886674, -4744346.429545386, 3752867.3858487825, + 6.26, -2001790.5203057139, -4744344.739469034, 3752868.091033227, + 6.2700000000000005, -2001790.5975100002, -4744343.041628374, 3752868.798104711, + 6.28, -2001790.6716906424, -4744341.335946825, 3752869.5071115047, + 6.29, -2001790.7428367576, -4744339.622347817, 3752870.2181018814, + 6.3, -2001790.8109374605, -4744337.900754769, 3752870.9311241126, + 6.3100000000000005, -2001790.8759818687, -4744336.171091108, 3752871.646226471, + 6.32, -2001790.9379590987, -4744334.433280257, 3752872.3634572285, + 6.33, -2001790.9968582657, -4744332.687245638, 3752873.082864656, + 6.34, -2001791.0526684872, -4744330.932910679, 3752873.8044970282, + 6.3500000000000005, -2001791.1053788788, -4744329.1701988, 3752874.5284026144, + 6.36, -2001791.154978557, -4744327.39903343, 3752875.2546296883, + 6.37, -2001791.201456638, -4744325.619337989, 3752875.983226522, + 6.38, -2001791.244802238, -4744323.831035903, 3752876.7142413864, + 6.390000000000001, -2001791.285004473, -4744322.034050594, 3752877.447722554, + 6.4, -2001791.3220524606, -4744320.228305489, 3752878.183718298, + 6.41, -2001791.3559353156, -4744318.413724009, 3752878.922276889, + 6.42, -2001791.3866421557, -4744316.590229581, 3752879.6634465996, + 6.43, -2001791.4141620966, -4744314.757745627, 3752880.4072757033, + 6.44, -2001791.4384842534, -4744312.916195571, 3752881.1538124694, + 6.45, -2001791.4595977443, -4744311.065502839, 3752881.903105172, + 6.46, -2001791.4774916845, -4744309.205590854, 3752882.655202083, + 6.47, -2001791.4921551906, -4744307.33638304, 3752883.4101514723, + 6.48, -2001791.503577379, -4744305.45780282, 3752884.168001616, + 6.49, -2001791.5117473663, -4744303.569773621, 3752884.928800783, + 6.5, -2001791.516654268, -4744301.672218864, 3752885.6925972463, + 6.51, -2001791.5182872007, -4744299.765061974, 3752886.4594392776, + 6.5200000000000005, -2001791.516635281, -4744297.848226375, 3752887.22937515, + 6.53, -2001791.5116876247, -4744295.921635492, 3752888.0024531344, + 6.54, -2001791.5034333493, -4744293.985212748, 3752888.778721505, + 6.55, -2001791.49186157, -4744292.038881569, 3752889.558228531, + 6.5600000000000005, -2001791.4769614034, -4744290.0825653775, 3752890.341022486, + 6.57, -2001791.458721965, -4744288.116187595, 3752891.127151641, + 6.58, -2001791.4371323725, -4744286.13967165, 3752891.9166642693, + 6.59, -2001791.4121817413, -4744284.152940964, 3752892.7096086433, + 6.6000000000000005, -2001791.3838591883, -4744282.155918963, 3752893.506033034, + 6.61, -2001791.3521538295, -4744280.1485290695, 3752894.305985715, + 6.62, -2001791.3170547811, -4744278.130694709, 3752895.109514956, + 6.63, -2001791.2785511592, -4744276.102339302, 3752895.9166690297, + 6.640000000000001, -2001791.236632081, -4744274.063386278, 3752896.7274962105, + 6.65, -2001791.1912866617, -4744272.013759056, 3752897.5420447667, + 6.66, -2001791.1425040183, -4744269.953381063, 3752898.3603629735, + 6.67, -2001791.0902732671, -4744267.882175723, 3752899.182499103, + 6.68, -2001791.034583524, -4744265.800066458, 3752900.0085014254, + 6.69, -2001790.9754239055, -4744263.706976695, 3752900.8384182127, + 6.7, -2001790.9127835277, -4744261.602829854, 3752901.672297738, + 6.71, -2001790.8466515082, -4744259.487549366, 3752902.510188274, + 6.72, -2001790.777016962, -4744257.361058649, 3752903.352138093, + 6.73, -2001790.703869005, -4744255.2232811265, 3752904.1981954644, + 6.74, -2001790.6271967539, -4744253.074140226, 3752905.048408662, + 6.75, -2001790.5469893261, -4744250.91355937, 3752905.902825958, + 6.76, -2001790.4632358365, -4744248.741461984, 3752906.761495624, + 6.7700000000000005, -2001790.375925403, -4744246.557771492, 3752907.624465935, + 6.78, -2001790.2850471397, -4744244.362411315, 3752908.491785157, + 6.79, -2001790.1905901649, -4744242.155304878, 3752909.363501567, + 6.8, -2001790.0925435943, -4744239.9363756105, 3752910.239663436, + 6.8100000000000005, -2001789.9908965426, -4744237.705546928, 3752911.120319034, + 6.82, -2001789.8856381287, -4744235.462742261, 3752912.005516637, + 6.83, -2001789.7767574685, -4744233.2078850325, 3752912.8953045146, + 6.84, -2001789.6642436762, -4744230.940898663, 3752913.7897309386, + 6.8500000000000005, -2001789.5480858698, -4744228.661706581, 3752914.688844181, + 6.86, -2001789.4282731651, -4744226.370232207, 3752915.5926925144, + 6.87, -2001789.3047946782, -4744224.066398967, 3752916.5013242112, + 6.88, -2001789.1776395265, -4744221.7501302855, 3752917.4147875435, + 6.890000000000001, -2001789.0467968257, -4744219.421349588, 3752918.3331307834, + 6.9, -2001788.9122556911, -4744217.079980292, 3752919.256402202, + 6.91, -2001788.7740052405, -4744214.725945828, 3752920.1846500724, + 6.92, -2001788.6320345898, -4744212.35916962, 3752921.117922667, + 6.93, -2001788.4864809366, -4744209.976717252, 3752922.055688722, + 6.94, -2001788.337780564, -4744207.570156753, 3752922.996241048, + 6.95, -2001788.1859653976, -4744205.139151266, 3752923.939449168, + 6.96, -2001788.0310383285, -4744202.683933324, 3752924.8852960533, + 6.97, -2001787.8730022493, -4744200.204735457, 3752925.833764673, + 6.98, -2001787.711860052, -4744197.701790199, 3752926.7848379994, + 6.99, -2001787.5476146284, -4744195.175330079, 3752927.738498999, + 7, -2001787.3802688706, -4744192.625587633, 3752928.6947306436, + 7.01, -2001787.209825671, -4744190.052795391, 3752929.653515903, + 7.0200000000000005, -2001787.036287921, -4744187.457185883, 3752930.614837746, + 7.03, -2001786.8596585125, -4744184.838991646, 3752931.578679145, + 7.04, -2001786.6799403385, -4744182.198445207, 3752932.545023068, + 7.05, -2001786.4971362904, -4744179.535779101, 3752933.513852485, + 7.0600000000000005, -2001786.31124926, -4744176.851225859, 3752934.485150367, + 7.07, -2001786.1222821395, -4744174.145018011, 3752935.4588996833, + 7.08, -2001785.9302378213, -4744171.417388093, 3752936.4350834037, + 7.09, -2001785.7351191966, -4744168.6685686335, 3752937.4136844985, + 7.1000000000000005, -2001785.5369291585, -4744165.898792167, 3752938.394685938, + 7.11, -2001785.3356705979, -4744163.108291224, 3752939.3780706916, + 7.12, -2001785.1313464076, -4744160.2972983355, 3752940.363821729, + 7.13, -2001784.9239594792, -4744157.466046038, 3752941.3519220212, + 7.140000000000001, -2001784.7135127052, -4744154.614766859, 3752942.3423545375, + 7.15, -2001784.500008977, -4744151.743693331, 3752943.3351022475, + 7.16, -2001784.2834511872, -4744148.853057987, 3752944.330148122, + 7.17, -2001784.063842227, -4744145.9430933595, 3752945.32747513, + 7.18, -2001783.8411849895, -4744143.014031979, 3752946.327066242, + 7.19, -2001783.6154823657, -4744140.06610638, 3752947.3289044285, + 7.2, -2001783.3867372482, -4744137.099549091, 3752948.332972659, + 7.21, -2001783.1549525291, -4744134.114592648, 3752949.3392539024, + 7.22, -2001782.9201311, -4744131.111469579, 3752950.34773113, + 7.23, -2001782.682275853, -4744128.090412417, 3752951.3583873115, + 7.24, -2001782.4413896804, -4744125.051653697, 3752952.371205417, + 7.25, -2001782.1974754743, -4744121.995425948, 3752953.3861684157, + 7.26, -2001781.950536126, -4744118.921961702, 3752954.4032592787, + 7.2700000000000005, -2001781.700574528, -4744115.831493492, 3752955.422460975, + 7.28, -2001781.4475935728, -4744112.724253851, 3752956.443756474, + 7.29, -2001781.1915961516, -4744109.600475308, 3752957.467128748, + 7.3, -2001780.9325851568, -4744106.460390397, 3752958.492560765, + 7.3100000000000005, -2001780.6705634804, -4744103.304231652, 3752959.520035495, + 7.32, -2001780.4055340139, -4744100.132231601, 3752960.5495359083, + 7.33, -2001780.1374996505, -4744096.9446227765, 3752961.5810449757, + 7.34, -2001779.8664632807, -4744093.741637712, 3752962.6145456666, + 7.3500000000000005, -2001779.5924277978, -4744090.523508941, 3752963.650020951, + 7.36, -2001779.3153960933, -4744087.290468993, 3752964.687453797, + 7.37, -2001779.0353710596, -4744084.0427504, 3752965.7268271777, + 7.38, -2001778.752355588, -4744080.780585696, 3752966.768124061, + 7.390000000000001, -2001778.4663525708, -4744077.50420741, 3752967.8113274183, + 7.4, -2001778.1773649, -4744074.213848076, 3752968.8564202175, + 7.41, -2001777.885395468, -4744070.909740226, 3752969.9033854306, + 7.42, -2001777.5904471665, -4744067.592116391, 3752970.9522060254, + 7.43, -2001777.2925228872, -4744064.261209104, 3752972.0028649746, + 7.44, -2001776.991625523, -4744060.917250898, 3752973.055345247, + 7.45, -2001776.6877579652, -4744057.560474301, 3752974.1096298113, + 7.46, -2001776.3809231056, -4744054.19111185, 3752975.165701639, + 7.47, -2001776.0711238375, -4744050.809396073, 3752976.223543699, + 7.48, -2001775.7583630509, -4744047.415559504, 3752977.283138962, + 7.49, -2001775.4426436399, -4744044.009834675, 3752978.344470398, + 7.5, -2001775.123968495, -4744040.592454117, 3752979.4075209764, + 7.51, -2001774.802340509, -4744037.163650362, 3752980.4722736673, + 7.5200000000000005, -2001774.4777625736, -4744033.723655944, 3752981.5387114417, + 7.53, -2001774.1502375815, -4744030.272703392, 3752982.6068172683, + 7.54, -2001773.8197684232, -4744026.8110252395, 3752983.676574117, + 7.55, -2001773.486357992, -4744023.3388540195, 3752984.7479649587, + 7.5600000000000005, -2001773.1500091795, -4744019.856422263, 3752985.820972762, + 7.57, -2001772.8107248782, -4744016.363962501, 3752986.8955804994, + 7.58, -2001772.468507979, -4744012.861707267, 3752987.9717711373, + 7.59, -2001772.123361375, -4744009.349889092, 3752989.0495276484, + 7.6000000000000005, -2001771.7752879576, -4744005.828740509, 3752990.1288330024, + 7.61, -2001771.4242906198, -4744002.298494049, 3752991.2096701683, + 7.62, -2001771.070372252, -4743998.759382246, 3752992.2920221165, + 7.63, -2001770.7135357477, -4743995.211637629, 3752993.375871816, + 7.640000000000001, -2001770.3537839982, -4743991.655492731, 3752994.4612022387, + 7.65, -2001769.9911198951, -4743988.091180086, 3752995.5479963524, + 7.66, -2001769.6255463315, -4743984.518932224, 3752996.6362371296, + 7.67, -2001769.2570661986, -4743980.938981676, 3752997.7259075376, + 7.68, -2001768.8856823882, -4743977.351560975, 3752998.816990548, + 7.69, -2001768.5113977934, -4743973.756902656, 3752999.9094691304, + 7.7, -2001768.1342153053, -4743970.155239246, 3753001.0033262554, + 7.71, -2001767.7541378164, -4743966.546803281, 3753002.0985448915, + 7.72, -2001767.3711682183, -4743962.931827289, 3753003.195108009, + 7.73, -2001766.9853094036, -4743959.310543806, 3753004.2929985793, + 7.74, -2001766.5965642636, -4743955.683185362, 3753005.3921995703, + 7.75, -2001766.2049356906, -4743952.04998449, 3753006.4926939537, + 7.76, -2001765.8104265772, -4743948.41117372, 3753007.5944646993, + 7.7700000000000005, -2001765.4130398142, -4743944.766985586, 3753008.697494776, + 7.78, -2001765.012778295, -4743941.117652618, 3753009.8017671537, + 7.79, -2001764.6096449108, -4743937.463407352, 3753010.9072648035, + 7.8, -2001764.2036425539, -4743933.804482317, 3753012.0139706945, + 7.8100000000000005, -2001763.7947741153, -4743930.141110042, 3753013.121867797, + 7.82, -2001763.3830424887, -4743926.4735230645, 3753014.230939082, + 7.83, -2001762.9684505651, -4743922.801953914, 3753015.341167517, + 7.84, -2001762.5510012368, -4743919.126635123, 3753016.4525360735, + 7.8500000000000005, -2001762.1306973954, -4743915.447799223, 3753017.5650277226, + 7.86, -2001761.7075419337, -4743911.765678746, 3753018.6786254314, + 7.87, -2001761.2815377433, -4743908.080506224, 3753019.7933121724, + 7.88, -2001760.8526877158, -4743904.39251419, 3753020.9090709137, + 7.890000000000001, -2001760.4209947437, -4743900.701935174, 3753022.0258846274, + 7.9, -2001759.9864617188, -4743897.0090017095, 3753023.143736281, + 7.91, -2001759.5490915338, -4743893.313946328, 3753024.2626088466, + 7.92, -2001759.10888708, -4743889.617001561, 3753025.3824852933, + 7.930000000000001, -2001758.665851249, -4743885.918399942, 3753026.5033485903, + 7.94, -2001758.2199869337, -4743882.218374003, 3753027.625181709, + 7.95, -2001757.7712970264, -4743878.517156275, 3753028.7479676176, + 7.96, -2001757.3197844175, -4743874.81497929, 3753029.871689288, + 7.97, -2001756.8654520006, -4743871.112075578, 3753030.9963296885, + 7.98, -2001756.408302667, -4743867.408677675, 3753032.1218717904, + 7.99, -2001755.9483393093, -4743863.705018111, 3753033.2482985626, + 8, -2001755.4855648184, -4743860.001329418, 3753034.375592976, + 8.01, -2001755.0199820877, -4743856.297844127, 3753035.503738, + 8.02, -2001754.5515940078, -4743852.594794771, 3753036.6327166045, + 8.03, -2001754.080403472, -4743848.8924138835, 3753037.762511759, + 8.040000000000001, -2001753.6064133714, -4743845.190933993, 3753038.8931064345, + 8.05, -2001753.1296265984, -4743841.490587636, 3753040.0244836006, + 8.06, -2001752.650046045, -4743837.791607341, 3753041.156626228, + 8.07, -2001752.1676746034, -4743834.094225641, 3753042.2895172844, + 8.08, -2001751.6825151658, -4743830.398675067, 3753043.423139742, + 8.09, -2001751.1945706229, -4743826.705188152, 3753044.55747657, + 8.1, -2001750.7038438679, -4743823.01399743, 3753045.692510738, + 8.11, -2001750.2103377925, -4743819.325335429, 3753046.8282252164, + 8.120000000000001, -2001749.7140552895, -4743815.639434683, 3753047.964602975, + 8.13, -2001749.2149992504, -4743811.956527727, 3753049.1016269843, + 8.14, -2001748.713172566, -4743808.276847086, 3753050.239280213, + 8.15, -2001748.2085781298, -4743804.600625298, 3753051.377545632, + 8.16, -2001747.701218833, -4743800.928094892, 3753052.516406211, + 8.17, -2001747.1910975683, -4743797.259488401, 3753053.655844921, + 8.18, -2001746.6782172266, -4743793.595038356, 3753054.7958447295, + 8.19, -2001746.162580702, -4743789.934977291, 3753055.936388609, + 8.2, -2001745.6441908844, -4743786.279537736, 3753057.077459528, + 8.21, -2001745.1230506666, -4743782.628952226, 3753058.2190404567, + 8.22, -2001744.599162941, -4743778.98345329, 3753059.361114366, + 8.23, -2001744.0725305993, -4743775.343273459, 3753060.503664225, + 8.24, -2001743.5431565335, -4743771.708645269, 3753061.6466730027, + 8.25, -2001743.0110436354, -4743768.079801249, 3753062.7901236713, + 8.26, -2001742.476194797, -4743764.456973931, 3753063.933999199, + 8.27, -2001741.9386129112, -4743760.840395848, 3753065.078282557, + 8.28, -2001741.3983008687, -4743757.230299532, 3753066.2229567133, + 8.290000000000001, -2001740.8552615624, -4743753.626917516, 3753067.3680046406, + 8.3, -2001740.309497884, -4743750.03048233, 3753068.5134093063, + 8.31, -2001739.7610127255, -4743746.441226507, 3753069.6591536817, + 8.32, -2001739.2098089796, -4743742.859382579, 3753070.805220737, + 8.33, -2001738.6558895372, -4743739.285183077, 3753071.951593442, + 8.34, -2001738.0992572906, -4743735.718860532, 3753073.0982547654, + 8.35, -2001737.5399151328, -4743732.160647481, 3753074.2451876784, + 8.36, -2001736.9778659546, -4743728.6107764505, 3753075.392375151, + 8.370000000000001, -2001736.4131126488, -4743725.069479975, 3753076.539800153, + 8.38, -2001735.8456581063, -4743721.536990588, 3753077.6874456527, + 8.39, -2001735.275505221, -4743718.013540817, 3753078.835294624, + 8.4, -2001734.702656883, -4743714.499363199, 3753079.9833300323, + 8.41, -2001734.1271159858, -4743710.994690264, 3753081.1315348516, + 8.42, -2001733.5488854207, -4743707.499754541, 3753082.2798920483, + 8.43, -2001732.9679680795, -4743704.014788566, 3753083.4283845956, + 8.44, -2001732.3843668543, -4743700.540024869, 3753084.576995461, + 8.45, -2001731.7980846376, -4743697.075695983, 3753085.725707614, + 8.46, -2001731.2091243214, -4743693.622034441, 3753086.874504028, + 8.47, -2001730.6174887968, -4743690.179272772, 3753088.0233676694, + 8.48, -2001730.0231809577, -4743686.747643511, 3753089.1722815107, + 8.49, -2001729.4262036937, -4743683.327379187, 3753090.32122852, + 8.5, -2001728.8265598982, -4743679.918712334, 3753091.470191668, + 8.51, -2001728.2242524636, -4743676.521875484, 3753092.619153925, + 8.52, -2001727.6192842806, -4743673.137101168, 3753093.7680982603, + 8.53, -2001727.0116582424, -4743669.764621918, 3753094.917007645, + 8.540000000000001, -2001726.401377241, -4743666.404670268, 3753096.0658650477, + 8.55, -2001725.7884441668, -4743663.057478747, 3753097.214653438, + 8.56, -2001725.172861914, -4743659.72327989, 3753098.3633557884, + 8.57, -2001724.5546333736, -4743656.402306229, 3753099.5119550675, + 8.58, -2001723.9337614374, -4743653.094790291, 3753100.6604342437, + 8.59, -2001723.310248997, -4743649.8009646125, 3753101.8087762888, + 8.6, -2001722.6840989464, -4743646.521061726, 3753102.9569641724, + 8.61, -2001722.0553141753, -4743643.255314159, 3753104.1049808636, + 8.620000000000001, -2001721.423897577, -4743640.00395445, 3753105.2528093336, + 8.63, -2001720.7898520438, -4743636.767215126, 3753106.400432552, + 8.64, -2001720.1531804663, -4743633.54532872, 3753107.5478334874, + 8.65, -2001719.5138857374, -4743630.338527764, 3753108.6949951123, + 8.66, -2001718.8719707492, -4743627.147044791, 3753109.8419003948, + 8.67, -2001718.2274383937, -4743623.971112332, 3753110.988532305, + 8.68, -2001717.580291563, -4743620.810962921, 3753112.1348738135, + 8.69, -2001716.9305331483, -4743617.666829087, 3753113.2809078903, + 8.700000000000001, -2001716.2781660426, -4743614.538943363, 3753114.426617505, + 8.71, -2001715.623193138, -4743611.427538284, 3753115.5719856275, + 8.72, -2001714.9656173254, -4743608.332846376, 3753116.716995227, + 8.73, -2001714.3054414978, -4743605.255100176, 3753117.861629275, + 8.74, -2001713.642668547, -4743602.194532214, 3753119.0058707413, + 8.75, -2001712.9773013652, -4743599.151375023, 3753120.149702595, + 8.76, -2001712.3093428437, -4743596.125861134, 3753121.2931078067, + 8.77, -2001711.6387958748, -4743593.118223079, 3753122.4360693456, + 8.78, -2001710.9656633511, -4743590.128693392, 3753123.5785701815, + 8.790000000000001, -2001710.2899481636, -4743587.1575046, 3753124.7205932857, + 8.8, -2001709.6116532055, -4743584.204889241, 3753125.862121627, + 8.81, -2001708.930781368, -4743581.271079843, 3753127.0031381766, + 8.82, -2001708.2473355434, -4743578.356308941, 3753128.1436259034, + 8.83, -2001707.5613186231, -4743575.460809062, 3753129.2835677764, + 8.84, -2001706.8727334999, -4743572.584812743, 3753130.422946768, + 8.85, -2001706.1815830662, -4743569.728552514, 3753131.5617458466, + 8.86, -2001705.4878702126, -4743566.892260907, 3753132.6999479826, + 8.870000000000001, -2001704.7915978325, -4743564.076170456, 3753133.8375361455, + 8.88, -2001704.092768817, -4743561.280513689, 3753134.9744933057, + 8.89, -2001703.391386059, -4743558.505523142, 3753136.110802434, + 8.9, -2001702.6874524492, -4743555.751431344, 3753137.246446498, + 8.91, -2001701.980970881, -4743553.0184708275, 3753138.3814084707, + 8.92, -2001701.2719442458, -4743550.306874127, 3753139.5156713193, + 8.93, -2001700.5603754355, -4743547.616873773, 3753140.649218016, + 8.94, -2001699.8462673416, -4743544.948702295, 3753141.7820315277, + 8.950000000000001, -2001699.1296228576, -4743542.302592228, 3753142.914094828, + 8.96, -2001698.4104448743, -4743539.678776104, 3753144.045390885, + 8.97, -2001697.6887362842, -4743537.077486454, 3753145.175902669, + 8.98, -2001696.964499979, -4743534.4989558095, 3753146.305613149, + 8.99, -2001696.2377388505, -4743531.943416702, 3753147.4345052955, + 9, -2001695.5084557922, -4743529.411101666, 3753148.5625620796, + 9.01, -2001694.7766536942, -4743526.902243231, 3753149.6897664703, + 9.02, -2001694.0423354497, -4743524.4170739325, 3753150.8161014374, + 9.03, -2001693.3055039507, -4743521.955826298, 3753151.941549952, + 9.040000000000001, -2001692.5661620882, -4743519.518732861, 3753153.066094982, + 9.05, -2001691.8243127556, -4743517.106026157, 3753154.189719499, + 9.06, -2001691.0799588435, -4743514.717938712, 3753155.3124064724, + 9.07, -2001690.3331032454, -4743512.354703062, 3753156.434138872, + 9.08, -2001689.5837488524, -4743510.01655174, 3753157.55489967, + 9.09, -2001688.831898556, -4743507.703717271, 3753158.674671831, + 9.1, -2001688.0775552497, -4743505.416432197, 3753159.7934383317, + 9.11, -2001687.3207218244, -4743503.154929044, 3753160.911182137, + 9.120000000000001, -2001686.5614011725, -4743500.919440344, 3753162.0278862184, + 9.13, -2001685.7995961853, -4743498.710198629, 3753163.143533545, + 9.14, -2001685.0353097557, -4743496.527436432, 3753164.2581070885, + 9.15, -2001684.2685447766, -4743494.371386287, 3753165.3715898204, + 9.16, -2001683.499304138, -4743492.242280723, 3753166.483964706, + 9.17, -2001682.7275907327, -4743490.140352272, 3753167.595214719, + 9.18, -2001681.9534074534, -4743488.065833468, 3753168.705322827, + 9.19, -2001681.1767571906, -4743486.018956843, 3753169.8142720014, + 9.200000000000001, -2001680.3976428383, -4743483.999954928, 3753170.9220452122, + 9.21, -2001679.6160672875, -4743482.009060253, 3753172.0286254287, + 9.22, -2001678.8320334295, -4743480.046505352, 3753173.13399562, + 9.23, -2001678.0455441566, -4743478.112522756, 3753174.2381387576, + 9.24, -2001677.2557244743, -4743476.203254122, 3753175.341785286, + 9.25, -2001676.4614136573, -4743474.3132385155, 3753176.44592696, + 9.26, -2001675.662629569, -4743472.4423387945, 3753177.550563227, + 9.27, -2001674.85939619, -4743470.59044589, 3753178.655688354, + 9.28, -2001674.0517374997, -4743468.75745073, 3753179.761296606, + 9.290000000000001, -2001673.2396774783, -4743466.943244247, 3753180.8673822535, + 9.3, -2001672.4232401066, -4743465.147717371, 3753181.973939559, + 9.31, -2001671.6024493638, -4743463.37076103, 3753183.080962793, + 9.32, -2001670.7773292304, -4743461.612266157, 3753184.1884462214, + 9.33, -2001669.9479036864, -4743459.872123679, 3753185.2963841096, + 9.34, -2001669.1141967124, -4743458.15022453, 3753186.4047707263, + 9.35, -2001668.2762322882, -4743456.446459638, 3753187.5136003373, + 9.36, -2001667.4340343936, -4743454.760719932, 3753188.62286721, + 9.370000000000001, -2001666.5876270088, -4743453.092896344, 3753189.7325656107, + 9.38, -2001665.7370341145, -4743451.442879805, 3753190.8426898075, + 9.39, -2001664.8822796906, -4743449.8105612425, 3753191.953234066, + 9.4, -2001664.0233877164, -4743448.195831589, 3753193.064192653, + 9.41, -2001663.1603821728, -4743446.598581774, 3753194.1755598374, + 9.42, -2001662.2932870402, -4743445.018702727, 3753195.287329884, + 9.43, -2001661.4221262976, -4743443.456085378, 3753196.3994970606, + 9.44, -2001660.5469239263, -4743441.910620658, 3753197.512055633, + 9.450000000000001, -2001659.6677039056, -4743440.382199498, 3753198.6249998696, + 9.46, -2001658.784490216, -4743438.870712825, 3753199.7383240364, + 9.47, -2001657.8973068374, -4743437.376051573, 3753200.8520223997, + 9.48, -2001657.0061777502, -4743435.89810667, 3753201.9660892272, + 9.49, -2001656.1111269342, -4743434.436769048, 3753203.080518787, + 9.5, -2001655.2121783695, -4743432.9919296345, 3753204.1953053437, + 9.51, -2001654.3093560368, -4743431.56347936, 3753205.3104431657, + 9.52, -2001653.402683915, -4743430.151309158, 3753206.425926519, + 9.53, -2001652.4921859857, -4743428.755309954, 3753207.541749671, + 9.540000000000001, -2001651.577886228, -4743427.375372682, 3753208.657906888, + 9.55, -2001650.6598086227, -4743426.011388271, 3753209.7743924377, + 9.56, -2001649.7379771492, -4743424.6632476505, 3753210.891200586, + 9.57, -2001648.8124157875, -4743423.330841749, 3753212.008325601, + 9.58, -2001647.8831485189, -4743422.014061501, 3753213.1257617488, + 9.59, -2001646.9501993223, -4743420.712797835, 3753214.2435032963, + 9.6, -2001646.0135921782, -4743419.426941679, 3753215.361544511, + 9.61, -2001645.073351067, -4743418.156383965, 3753216.4798796587, + 9.620000000000001, -2001644.1294999686, -4743416.901015623, 3753217.598503007, + 9.63, -2001643.1820628631, -4743415.660727584, 3753218.7174088224, + 9.64, -2001642.2310637308, -4743414.435410776, 3753219.836591372, + 9.65, -2001641.2765265515, -4743413.224956132, 3753220.956044924, + 9.66, -2001640.3184753053, -4743412.029254579, 3753222.0757637424, + 9.67, -2001639.3569339726, -4743410.848197049, 3753223.1957420968, + 9.68, -2001638.391926533, -4743409.681674472, 3753224.3159742528, + 9.69, -2001637.4234769673, -4743408.52957778, 3753225.4364544763, + 9.700000000000001, -2001636.451609255, -4743407.391797899, 3753226.5571770365, + 9.71, -2001635.476347377, -4743406.268225762, 3753227.678136198, + 9.72, -2001634.497715313, -4743405.1587523, 3753228.7993262294, + 9.73, -2001633.5157370425, -4743404.06326844, 3753229.920741397, + 9.74, -2001632.5304365468, -4743402.981665116, 3753231.042375968, + 9.75, -2001631.5418378047, -4743401.913833255, 3753232.164224209, + 9.76, -2001630.549964797, -4743400.859663788, 3753233.286280386, + 9.77, -2001629.5548415042, -4743399.819047647, 3753234.408538767, + 9.78, -2001628.5564919056, -4743398.791875759, 3753235.5309936185, + 9.790000000000001, -2001627.5549399818, -4743397.778039056, 3753236.653639207, + 9.8, -2001626.5502097134, -4743396.77742847, 3753237.776469801, + 9.81, -2001625.5423250794, -4743395.7899349285, 3753238.8994796653, + 9.82, -2001624.5313100603, -4743394.815449362, 3753240.022663068, + 9.83, -2001623.5171886368, -4743393.853862701, 3753241.146014276, + 9.84, -2001622.4999847882, -4743392.905065876, 3753242.2695275564, + 9.85, -2001621.4797224952, -4743391.968949816, 3753243.393197174, + 9.86, -2001620.4564257374, -4743391.045405453, 3753244.517017398, + 9.870000000000001, -2001619.4301184954, -4743390.134323717, 3753245.6409824947, + 9.88, -2001618.4008247496, -4743389.235595536, 3753246.76508673, + 9.89, -2001617.3685684786, -4743388.349111842, 3753247.889324372, + 9.9, -2001616.3333736644, -4743387.474763566, 3753249.013689687, + 9.91, -2001615.2952642858, -4743386.612441636, 3753250.1381769427, + 9.92, -2001614.2542643235, -4743385.762036984, 3753251.262780405, + 9.93, -2001613.2103977576, -4743384.923440539, 3753252.3874943405, + 9.94, -2001612.1636885682, -4743384.096543231, 3753253.512313017, + 9.950000000000001, -2001611.114160735, -4743383.281235991, 3753254.6372307017, + 9.96, -2001610.0618382387, -4743382.477409748, 3753255.7622416597, + 9.97, -2001609.006745059, -4743381.684955435, 3753256.8873401596, + 9.98, -2001607.948905176, -4743380.903763979, 3753258.0125204674, + 9.99, -2001606.88834257, -4743380.133726311, 3753259.137776851, + 10, -2001605.8250812213, -4743379.374733363, 3753260.2631035764, + 10.01, -2001604.7591451097, -4743378.626676063, 3753261.3884949097, + 10.02, -2001603.6905582154, -4743377.889445341, 3753262.5139451204, + 10.03, -2001602.6193445185, -4743377.1629321305, 3753263.639448472, + 10.040000000000001, -2001601.5455279988, -4743376.447027356, 3753264.7649992337, + 10.05, -2001600.4691326376, -4743375.741621954, 3753265.8905916717, + 10.06, -2001599.3901824136, -4743375.046606851, 3753267.0162200537, + 10.07, -2001598.3087013073, -4743374.361872977, 3753268.141878645, + 10.08, -2001597.2247132992, -4743373.687311263, 3753269.2675617132, + 10.09, -2001596.138242369, -4743373.022812638, 3753270.393263526, + 10.1, -2001595.0493124966, -4743372.368268035, 3753271.518978349, + 10.11, -2001593.9579476635, -4743371.723568383, 3753272.64470045, + 10.120000000000001, -2001592.8641718484, -4743371.0886046095, 3753273.770424096, + 10.13, -2001591.7680090314, -4743370.463267649, 3753274.896143552, + 10.14, -2001590.669483194, -4743369.847448428, 3753276.0218530875, + 10.15, -2001589.5686183146, -4743369.241037879, 3753277.147546967, + 10.16, -2001588.4654383739, -4743368.6439269325, 3753278.2732194597, + 10.17, -2001587.3599673526, -4743368.056006515, 3753279.3988648313, + 10.18, -2001586.2522292302, -4743367.477167562, 3753280.524477348, + 10.19, -2001585.1422479874, -4743366.907300999, 3753281.650051279, + 10.200000000000001, -2001584.0300476039, -4743366.34629776, 3753282.775580887, + 10.21, -2001582.9156520595, -4743365.794048771, 3753283.9010604434, + 10.22, -2001581.799085335, -4743365.2504449645, 3753285.026484213, + 10.23, -2001580.6803714097, -4743364.715377272, 3753286.151846462, + 10.24, -2001579.5595342643, -4743364.188736621, 3753287.2771414584, + 10.25, -2001578.436597879, -4743363.670413944, 3753288.40236347, + 10.26, -2001577.311586233, -4743363.16030017, 3753289.527506761, + 10.27, -2001576.1845233084, -4743362.658286229, 3753290.6525656004, + 10.28, -2001575.0554330836, -4743362.164263053, 3753291.7775342544, + 10.290000000000001, -2001573.9243395384, -4743361.678121568, 3753292.9024069896, + 10.3, -2001572.7912666542, -4743361.199752709, 3753294.0271780724, + 10.31, -2001571.6562384106, -4743360.729047402, 3753295.1518417723, + 10.32, -2001570.5192787875, -4743360.26589658, 3753296.2763923532, + 10.33, -2001569.380411765, -4743359.810191172, 3753297.400824083, + 10.34, -2001568.2396613231, -4743359.36182211, 3753298.5251312293, + 10.35, -2001567.097051443, -4743358.920680322, 3753299.649308058, + 10.36, -2001565.9526061038, -4743358.486656738, 3753300.7733488376, + 10.370000000000001, -2001564.806349286, -4743358.059642291, 3753301.8972478337, + 10.38, -2001563.6583049695, -4743357.639527908, 3753303.0209993115, + 10.39, -2001562.5084971348, -4743357.22620452, 3753304.1445975406, + 10.4, -2001561.3569497608, -4743356.819563057, 3753305.268036787, + 10.41, -2001560.203686829, -4743356.419494452, 3753306.3913113177, + 10.42, -2001559.048732319, -4743356.025889632, 3753307.514415399, + 10.43, -2001557.8921102106, -4743355.638639526, 3753308.6373432977, + 10.44, -2001556.7338444842, -4743355.25763507, 3753309.7600892824, + 10.450000000000001, -2001555.5739591205, -4743354.882767188, 3753310.8826476177, + 10.46, -2001554.4124780986, -4743354.513926813, 3753312.005012571, + 10.47, -2001553.2494253991, -4743354.151004875, 3753313.127178411, + 10.48, -2001552.0848250026, -4743353.793892304, 3753314.2491394025, + 10.49, -2001550.918700888, -4743353.4424800305, 3753315.370889814, + 10.5, -2001549.7510770366, -4743353.096658984, 3753316.4924239106, + 10.51, -2001548.5819774275, -4743352.756320094, 3753317.61373596, + 10.52, -2001547.4114260415, -4743352.421354294, 3753318.7348202304, + 10.53, -2001546.2394468584, -4743352.09165251, 3753319.8556709867, + 10.540000000000001, -2001545.0660638588, -4743351.767105675, 3753320.9762824965, + 10.55, -2001543.8913010224, -4743351.447604718, 3753322.0966490265, + 10.56, -2001542.715182329, -4743351.133040568, 3753323.2167648436, + 10.57, -2001541.5377317604, -4743350.823304159, 3753324.3366242163, + 10.58, -2001540.3589732938, -4743350.518286417, 3753325.4562214087, + 10.59, -2001539.1789309117, -4743350.217878276, 3753326.5755506903, + 10.6, -2001537.997628593, -4743349.921970662, 3753327.6946063256, + 10.61, -2001536.8150903187, -4743349.630454507, 3753328.813382583, + 10.620000000000001, -2001535.6313400688, -4743349.343220742, 3753329.9318737295, + 10.63, -2001534.446401822, -4743349.060160296, 3753331.0500740297, + 10.64, -2001533.2602995601, -4743348.7811641, 3753332.1679777545, + 10.65, -2001532.073057263, -4743348.506123086, 3753333.285579168, + 10.66, -2001530.8846989092, -4743348.23492818, 3753334.4028725373, + 10.67, -2001529.6952484811, -4743347.967470316, 3753335.5198521297, + 10.68, -2001528.5047299569, -4743347.703640421, 3753336.6365122115, + 10.69, -2001527.3131673182, -4743347.443329427, 3753337.7528470503, + 10.700000000000001, -2001526.1205845443, -4743347.186428266, 3753338.8688509134, + 10.71, -2001524.927005615, -4743346.932827861, 3753339.984518065, + 10.72, -2001523.7324545113, -4743346.682419152, 3753341.0998427765, + 10.73, -2001522.5369552132, -4743346.435093063, 3753342.214819312, + 10.74, -2001521.3405317003, -4743346.190740524, 3753343.329441937, + 10.75, -2001520.1432079526, -4743345.9492524685, 3753344.4437049218, + 10.76, -2001518.9450079503, -4743345.710519823, 3753345.5576025313, + 10.77, -2001517.7459556747, -4743345.474433522, 3753346.671129032, + 10.78, -2001516.5460751047, -4743345.240884491, 3753347.7842786917, + 10.790000000000001, -2001515.3453902197, -4743345.009763665, 3753348.897045777, + 10.8, -2001514.1439250018, -4743344.780961969, 3753350.009424555, + 10.81, -2001512.94170343, -4743344.554370336, 3753351.121409291, + 10.82, -2001511.7387494843, -4743344.329879697, 3753352.232994255, + 10.83, -2001510.5350871447, -4743344.107380982, 3753353.3441737117, + 10.84, -2001509.3307403922, -4743343.886765118, 3753354.454941928, + 10.85, -2001508.1257332054, -4743343.667923038, 3753355.565293171, + 10.86, -2001506.9200895664, -4743343.450745672, 3753356.6752217077, + 10.870000000000001, -2001505.7138334538, -4743343.235123951, 3753357.7847218057, + 10.88, -2001504.506988848, -4743343.020948802, 3753358.8937877305, + 10.89, -2001503.29957973, -4743342.808111159, 3753360.00241375, + 10.9, -2001502.0916300784, -4743342.596501948, 3753361.110594131, + 10.91, -2001500.8831638745, -4743342.386012103, 3753362.21832314, + 10.92, -2001499.6742050976, -4743342.1765325535, 3753363.3255950445, + 10.93, -2001498.464777729, -4743341.967954228, 3753364.43240411, + 10.94, -2001497.2549057475, -4743341.760168058, 3753365.5387446056, + 10.950000000000001, -2001496.0446131343, -4743341.553064972, 3753366.644610796, + 10.96, -2001494.8339238686, -4743341.346535903, 3753367.749996949, + 10.97, -2001493.6228619306, -4743341.140471778, 3753368.854897332, + 10.98, -2001492.411451301, -4743340.93476353, 3753369.9593062107, + 10.99, -2001491.19971596, -4743340.729302088, 3753371.063217853, + 11, -2001489.987679887, -4743340.523978381, 3753372.1666265256, + 11.01, -2001488.7753670625, -4743340.31868334, 3753373.269526495, + 11.02, -2001487.5628014663, -4743340.113307896, 3753374.371912028, + 11.03, -2001486.3500070788, -4743339.907742981, 3753375.4737773924, + 11.040000000000001, -2001485.1370078805, -4743339.701879519, 3753376.5751168528, + 11.05, -2001483.9238278507, -4743339.495608446, 3753377.6759246793, + 11.06, -2001482.7104909702, -4743339.28882069, 3753378.776195137, + 11.07, -2001481.4970212183, -4743339.08140718, 3753379.8759224922, + 11.08, -2001480.2834425757, -4743338.873258849, 3753380.975101013, + 11.09, -2001479.0697790233, -4743338.6642666245, 3753382.0737249656, + 11.1, -2001477.8560545396, -4743338.454321438, 3753383.171788618, + 11.11, -2001476.642293106, -4743338.243314221, 3753384.269286236, + 11.120000000000001, -2001475.4285187013, -4743338.031135902, 3753385.3662120863, + 11.13, -2001474.214755307, -4743337.817677409, 3753386.4625604353, + 11.14, -2001473.0010269028, -4743337.602829677, 3753387.558325552, + 11.15, -2001471.7873574677, -4743337.386483633, 3753388.653501701, + 11.16, -2001470.5737709831, -4743337.168530207, 3753389.748083151, + 11.17, -2001469.360291429, -4743336.9488603305, 3753390.842064168, + 11.18, -2001468.1469427855, -4743336.727364935, 3753391.9354390195, + 11.19, -2001466.9337490315, -4743336.503934946, 3753393.0282019703, + 11.200000000000001, -2001465.7207341492, -4743336.278461299, 3753394.1203472903, + 11.21, -2001464.5079221174, -4743336.050834921, 3753395.211869244, + 11.22, -2001463.2953369159, -4743335.820946743, 3753396.3027621, + 11.23, -2001462.0830025254, -4743335.588687693, 3753397.3930201232, + 11.24, -2001460.8709429263, -4743335.353948707, 3753398.4826375823, + 11.25, -2001459.659182098, -4743335.116620708, 3753399.571608744, + 11.26, -2001458.4477440212, -4743334.876594632, 3753400.6599278743, + 11.27, -2001457.2366526758, -4743334.633761406, 3753401.747589241, + 11.28, -2001456.0259320417, -4743334.388011961, 3753402.8345871097, + 11.290000000000001, -2001454.815606099, -4743334.139237228, 3753403.9209157485, + 11.3, -2001453.6056988286, -4743333.887328135, 3753405.0065694237, + 11.31, -2001452.3962342092, -4743333.632175612, 3753406.091542402, + 11.32, -2001451.1872362227, -4743333.373670595, 3753407.1758289514, + 11.33, -2001449.9787288478, -4743333.111704008, 3753408.259423338, + 11.34, -2001448.770736065, -4743332.846166782, 3753409.342319828, + 11.35, -2001447.5632818541, -4743332.576949849, 3753410.424512689, + 11.36, -2001446.356390196, -4743332.303944138, 3753411.5059961877, + 11.370000000000001, -2001445.1500850702, -4743332.027040578, 3753412.5867645913, + 11.38, -2001443.9443904578, -4743331.746130104, 3753413.6668121666, + 11.39, -2001442.739330337, -4743331.461103641, 3753414.74613318, + 11.4, -2001441.5349286892, -4743331.171852122, 3753415.824721899, + 11.41, -2001440.3312094952, -4743330.878266476, 3753416.902572591, + 11.42, -2001439.1281967333, -4743330.580237634, 3753417.979679521, + 11.43, -2001437.9259143851, -4743330.2776565235, 3753419.056036958, + 11.44, -2001436.72438643, -4743329.970414079, 3753420.1316391677, + 11.450000000000001, -2001435.5236368482, -4743329.658401227, 3753421.2064804155, + 11.46, -2001434.3236896205, -4743329.341508901, 3753422.2805549717, + 11.47, -2001433.1245687257, -4743329.0196280265, 3753423.3538571005, + 11.48, -2001431.9262981457, -4743328.69264954, 3753424.426381072, + 11.49, -2001430.7289018582, -4743328.360464365, 3753425.4981211475, + 11.5, -2001429.5324038453, -4743328.022963436, 3753426.5690715997, + 11.51, -2001428.336828086, -4743327.680037682, 3753427.6392266913, + 11.52, -2001427.1421985622, -4743327.331578035, 3753428.7085806928, + 11.53, -2001425.9485392515, -4743326.977475421, 3753429.7771278676, + 11.540000000000001, -2001424.7558621974, -4743326.617740015, 3753430.8448787816, + 11.55, -2001423.5635479514, -4743326.258631781, 3753431.912694144, + 11.56, -2001422.3712286633, -4743325.903725544, 3753432.9810555647, + 11.57, -2001421.1788934444, -4743325.552999445, 3753434.049950868, + 11.58, -2001419.9865314038, -4743325.2064316245, 3753435.11936788, + 11.59, -2001418.794131653, -4743324.864000223, 3753436.1892944253, + 11.6, -2001417.6016833028, -4743324.525683377, 3753437.25971833, + 11.61, -2001416.409175462, -4743324.191459229, 3753438.3306274205, + 11.620000000000001, -2001415.2165972425, -4743323.861305918, 3753439.402009521, + 11.63, -2001414.023937754, -4743323.535201581, 3753440.473852456, + 11.64, -2001412.8311861071, -4743323.213124364, 3753441.5461440533, + 11.65, -2001411.6383314119, -4743322.895052401, 3753442.618872137, + 11.66, -2001410.4453627786, -4743322.580963833, 3753443.6920245313, + 11.67, -2001409.2522693186, -4743322.270836802, 3753444.7655890645, + 11.68, -2001408.0590401415, -4743321.964649445, 3753445.839553559, + 11.69, -2001406.8656643576, -4743321.662379904, 3753446.9139058436, + 11.700000000000001, -2001405.6721310776, -4743321.364006317, 3753447.9886337407, + 11.71, -2001404.4784294122, -4743321.069506824, 3753449.063725077, + 11.72, -2001403.2845484712, -4743320.778859566, 3753450.139167678, + 11.73, -2001402.090477365, -4743320.49204268, 3753451.2149493685, + 11.74, -2001400.8962052043, -4743320.209034309, 3753452.291057974, + 11.75, -2001399.7017210994, -4743319.9298125915, 3753453.3674813206, + 11.76, -2001398.507014161, -4743319.654355666, 3753454.444207234, + 11.77, -2001397.312073499, -4743319.382641674, 3753455.521223539, + 11.78, -2001396.1168882237, -4743319.114648753, 3753456.5985180605, + 11.790000000000001, -2001394.9214474466, -4743318.850355046, 3753457.6760786246, + 11.8, -2001393.7257402765, -4743318.589738689, 3753458.753893057, + 11.81, -2001392.529755825, -4743318.332777823, 3753459.8319491823, + 11.82, -2001391.3334832022, -4743318.079450591, 3753460.9102348266, + 11.83, -2001390.1369115177, -4743317.829735128, 3753461.988737815, + 11.84, -2001388.9400298828, -4743317.583609577, 3753463.067445973, + 11.85, -2001387.7428274076, -4743317.341052076, 3753464.146347126, + 11.86, -2001386.545293203, -4743317.102040766, 3753465.2254291, + 11.870000000000001, -2001385.3474163786, -4743316.866553783, 3753466.3046797197, + 11.88, -2001384.1491860452, -4743316.634569272, 3753467.3840868096, + 11.89, -2001382.950591313, -4743316.406065371, 3753468.463638198, + 11.9, -2001381.751621293, -4743316.181020219, 3753469.543321708, + 11.91, -2001380.5522650946, -4743315.9594119545, 3753470.6231251657, + 11.92, -2001379.3525118288, -4743315.741218718, 3753471.7030363963, + 11.93, -2001378.152350606, -4743315.526418652, 3753472.7830432253, + 11.94, -2001376.9517705361, -4743315.314989892, 3753473.8631334784, + 11.950000000000001, -2001375.7507607301, -4743315.106910582, 3753474.943294981, + 11.96, -2001374.5493102986, -4743314.902158857, 3753476.023515558, + 11.97, -2001373.347408351, -4743314.70071286, 3753477.103783035, + 11.98, -2001372.1450439987, -4743314.502550731, 3753478.184085238, + 11.99, -2001370.9422063513, -4743314.307650607, 3753479.2644099924, + 12, -2001369.73888452, -4743314.11599063, 3753480.3447451233, + 12.01, -2001368.5350676142, -4743313.92754894, 3753481.425078456, + 12.02, -2001367.330744745, -4743313.742303674, 3753482.5053978153, + 12.030000000000001, -2001366.1259050227, -4743313.560232975, 3753483.585691028, + 12.040000000000001, -2001364.9205375577, -4743313.381314981, 3753484.6659459188, + 12.05, -2001363.7146314606, -4743313.205527832, 3753485.7461503134, + 12.06, -2001362.508175841, -4743313.032849667, 3753486.8262920366, + 12.07, -2001361.30115981, -4743312.863258625, 3753487.9063589144, + 12.08, -2001360.0935724778, -4743312.696732851, 3753488.986338773, + 12.09, -2001358.8854029544, -4743312.533250478, 3753490.0662194355, + 12.1, -2001357.6766403513, -4743312.372789649, 3753491.14598873, + 12.11, -2001356.4672737778, -4743312.215328503, 3753492.2256344804, + 12.120000000000001, -2001355.2572923447, -4743312.060845182, 3753493.305144512, + 12.13, -2001354.0466851625, -4743311.909317822, 3753494.3845066507, + 12.14, -2001352.8354413414, -4743311.760724565, 3753495.4637087225, + 12.15, -2001351.6235499915, -4743311.615043551, 3753496.5427385513, + 12.16, -2001350.411000224, -4743311.4722529175, 3753497.621583964, + 12.17, -2001349.1977811486, -4743311.332330807, 3753498.7002327857, + 12.18, -2001347.983881876, -4743311.195255357, 3753499.7786728414, + 12.19, -2001346.7692915166, -4743311.0610047085, 3753500.856891957, + 12.200000000000001, -2001345.553999181, -4743310.929557, 3753501.934877957, + 12.21, -2001344.3379939792, -4743310.800890375, 3753503.012618669, + 12.22, -2001343.1212650212, -4743310.674982966, 3753504.090101915, + 12.23, -2001341.9038014181, -4743310.55181292, 3753505.1673155227, + 12.24, -2001340.6855922805, -4743310.431358373, 3753506.2442473173, + 12.25, -2001339.4666267175, -4743310.313597465, 3753507.3208851255, + 12.26, -2001338.2468938413, -4743310.198508337, 3753508.39721677, + 12.27, -2001337.026382761, -4743310.086069127, 3753509.473230078, + 12.280000000000001, -2001335.8050825873, -4743309.976257976, 3753510.548912874, + 12.290000000000001, -2001334.5829824307, -4743309.869053024, 3753511.6242529843, + 12.3, -2001333.3600714016, -4743309.76443241, 3753512.6992382337, + 12.31, -2001332.1363386107, -4743309.662374272, 3753513.7738564485, + 12.32, -2001330.9117731678, -4743309.562856753, 3753514.848095453, + 12.33, -2001329.6863641832, -4743309.465857991, 3753515.9219430736, + 12.34, -2001328.4601007677, -4743309.371356126, 3753516.995387134, + 12.35, -2001327.2329720322, -4743309.279329299, 3753518.068415462, + 12.36, -2001326.0049670862, -4743309.1897556465, 3753519.141015882, + 12.370000000000001, -2001324.77607504, -4743309.102613311, 3753520.213176219, + 12.38, -2001323.5462850048, -4743309.017880432, 3753521.2848842978, + 12.39, -2001322.3155860908, -4743308.935535148, 3753522.3561279457, + 12.4, -2001321.0839674077, -4743308.8555556, 3753523.4268949875, + 12.41, -2001319.8514180668, -4743308.777919926, 3753524.497173249, + 12.42, -2001318.6179271778, -4743308.702606267, 3753525.566950553, + 12.43, -2001317.3834838513, -4743308.629592763, 3753526.636214729, + 12.44, -2001316.148077198, -4743308.558857553, 3753527.704953599, + 12.450000000000001, -2001314.9116963279, -4743308.490378777, 3753528.77315499, + 12.46, -2001313.6743303519, -4743308.424134575, 3753529.8408067273, + 12.47, -2001312.43596838, -4743308.360103087, 3753530.9078966365, + 12.48, -2001311.1965995221, -4743308.29826245, 3753531.9744125423, + 12.49, -2001309.9562128896, -4743308.238590807, 3753533.0403422713, + 12.5, -2001308.7147975923, -4743308.181066296, 3753534.1056736475, + 12.51, -2001307.4723427403, -4743308.12566706, 3753535.1703944984, + 12.52, -2001306.2288374451, -4743308.072371232, 3753536.234492646, + 12.530000000000001, -2001304.984270816, -4743308.021156959, 3753537.297955919, + 12.540000000000001, -2001303.7386319642, -4743307.972002377, 3753538.3607721413, + 12.55, -2001302.4919099994, -4743307.924885624, 3753539.422929139, + 12.56, -2001301.2440940323, -4743307.879784844, 3753540.4844147367, + 12.57, -2001299.9951731735, -4743307.836678174, 3753541.54521676, + 12.58, -2001298.745136533, -4743307.795543754, 3753542.6053230357, + 12.59, -2001297.4939732214, -4743307.756359725, 3753543.664721388, + 12.6, -2001296.2416723487, -4743307.719104226, 3753544.7233996424, + 12.61, -2001294.988223026, -4743307.683755396, 3753545.7813456245, + 12.620000000000001, -2001293.7336143632, -4743307.650291376, 3753546.838547159, + 12.63, -2001292.4778354715, -4743307.618690303, 3753547.894992072, + 12.64, -2001291.2208754595, -4743307.588930319, 3753548.9506681887, + 12.65, -2001289.9627234393, -4743307.560989566, 3753550.005563336, + 12.66, -2001288.7033685213, -4743307.53484618, 3753551.0596653377, + 12.67, -2001287.4427998143, -4743307.510478302, 3753552.112962019, + 12.68, -2001286.1810064302, -4743307.4878640715, 3753553.165441206, + 12.69, -2001284.917977479, -4743307.466981627, 3753554.2170907245, + 12.700000000000001, -2001283.653702071, -4743307.447809111, 3753555.2678984, + 12.71, -2001282.3881693163, -4743307.4303246625, 3753556.3178520557, + 12.72, -2001281.121368326, -4743307.414506419, 3753557.3669395205, + 12.73, -2001279.8532882098, -4743307.400332523, 3753558.4151486163, + 12.74, -2001278.5839180788, -4743307.3877811115, 3753559.462467172, + 12.75, -2001277.313247042, -4743307.376830327, 3753560.5088830106, + 12.76, -2001276.0412642115, -4743307.367458307, 3753561.554383958, + 12.77, -2001274.7679586965, -4743307.359643194, 3753562.5989578404, + 12.780000000000001, -2001273.4933196083, -4743307.353363125, 3753563.6425924827, + 12.790000000000001, -2001272.2173360565, -4743307.348596239, 3753564.68527571, + 12.8, -2001270.9399971527, -4743307.345320679, 3753565.7269953485, + 12.81, -2001269.6612920053, -4743307.343514582, 3753566.767739223, + 12.82, -2001268.3812097267, -4743307.34315609, 3753567.807495158, + 12.83, -2001267.0997394258, -4743307.34422334, 3753568.846250982, + 12.84, -2001265.8168702135, -4743307.346694475, 3753569.883994517, + 12.85, -2001264.5325912007, -4743307.350547631, 3753570.9207135905, + 12.86, -2001263.246891497, -4743307.3557609515, 3753571.956396028, + 12.870000000000001, -2001261.9597602137, -4743307.362312574, 3753572.9910296537, + 12.88, -2001260.6711864606, -4743307.3701806385, 3753574.0246022926, + 12.89, -2001259.381159348, -4743307.379343284, 3753575.0571017726, + 12.9, -2001258.0896679861, -4743307.389778652, 3753576.088515917, + 12.91, -2001256.7967014862, -4743307.401464881, 3753577.1188325523, + 12.92, -2001255.5022489578, -4743307.414380112, 3753578.1480395026, + 12.93, -2001254.206299512, -4743307.428502483, 3753579.176124595, + 12.94, -2001252.9088422586, -4743307.443810134, 3753580.2030756543, + 12.950000000000001, -2001251.6098663083, -4743307.460281205, 3753581.228880505, + 12.96, -2001250.3093607717, -4743307.477893837, 3753582.2535269735, + 12.97, -2001249.0073147588, -4743307.496626169, 3753583.2770028855, + 12.98, -2001247.7037173798, -4743307.5164563395, 3753584.299296066, + 12.99, -2001246.3985577459, -4743307.537362489, 3753585.3203943404, + 13, -2001245.091824967, -4743307.559322758, 3753586.340285534, + 13.01, -2001243.7835081527, -4743307.582315285, 3753587.3589574723, + 13.02, -2001242.473596415, -4743307.606318211, 3753588.3763979813, + 13.030000000000001, -2001241.1620788628, -4743307.631309673, 3753589.392594885, + 13.040000000000001, -2001239.8489446077, -4743307.657267815, 3753590.4075360107, + 13.05, -2001238.5341827595, -4743307.684170773, 3753591.4212091826, + 13.06, -2001237.2177824283, -4743307.7119966885, 3753592.433602225, + 13.07, -2001235.8997327252, -4743307.740723701, 3753593.444702966, + 13.08, -2001234.5800227607, -4743307.770329952, 3753594.4544992307, + 13.09, -2001233.2586416441, -4743307.800793578, 3753595.4629788427, + 13.1, -2001231.9355784864, -4743307.832092719, 3753596.470129628, + 13.11, -2001230.6108223982, -4743307.864205517, 3753597.4759394126, + 13.120000000000001, -2001229.2843624898, -4743307.89711011, 3753598.4803960226, + 13.13, -2001227.9561878715, -4743307.930784638, 3753599.4834872806, + 13.14, -2001226.6262876538, -4743307.965207242, 3753600.4852010156, + 13.15, -2001225.2946509467, -4743308.0003560595, 3753601.48552505, + 13.16, -2001223.9612668615, -4743308.036209232, 3753602.4844472115, + 13.17, -2001222.6261245077, -4743308.0727449, 3753603.481955325, + 13.18, -2001221.2892129952, -4743308.109941199, 3753604.4780372144, + 13.19, -2001219.950521436, -4743308.147776274, 3753605.472680708, + 13.200000000000001, -2001218.6100389399, -4743308.186228262, 3753606.465873628, + 13.21, -2001217.2677546167, -4743308.225275302, 3753607.457603801, + 13.22, -2001215.9236575768, -4743308.264895536, 3753608.4478590544, + 13.23, -2001214.577736931, -4743308.3050671015, 3753609.4366272097, + 13.24, -2001213.2299817905, -4743308.34576814, 3753610.423896097, + 13.25, -2001211.8803812645, -4743308.386976791, 3753611.4096535384, + 13.26, -2001210.528924463, -4743308.428671192, 3753612.3938873606, + 13.27, -2001209.1756004982, -4743308.470829486, 3753613.376585388, + 13.280000000000001, -2001207.8203984783, -4743308.513429808, 3753614.357735446, + 13.290000000000001, -2001206.4633075155, -4743308.556450305, 3753615.3373253625, + 13.3, -2001205.1043167193, -4743308.59986911, 3753616.31534296, + 13.31, -2001203.743415201, -4743308.6436643675, 3753617.2917760666, + 13.32, -2001202.3805920698, -4743308.687814213, 3753618.266612505, + 13.33, -2001201.0158364363, -4743308.73229679, 3753619.2398401024, + 13.34, -2001199.6491374113, -4743308.777090235, 3753620.2114466834, + 13.35, -2001198.2804841055, -4743308.822172689, 3753621.181420075, + 13.36, -2001196.909865628, -4743308.867522293, 3753622.1497480995, + 13.370000000000001, -2001195.5372710908, -4743308.913117184, 3753623.116418585, + 13.38, -2001194.1626896034, -4743308.958935505, 3753624.0814193552, + 13.39, -2001192.7861102761, -4743309.004955394, 3753625.0447382377, + 13.4, -2001191.40752222, -4743309.051154991, 3753626.0063630557, + 13.41, -2001190.026914545, -4743309.097512436, 3753626.966281638, + 13.42, -2001188.6442763614, -4743309.144005867, 3753627.924481805, + 13.43, -2001187.2595967795, -4743309.190613425, 3753628.8809513855, + 13.44, -2001185.8728649097, -4743309.23731325, 3753629.8356782044, + 13.450000000000001, -2001184.484069863, -4743309.284083482, 3753630.788650087, + 13.46, -2001183.0932007497, -4743309.330902259, 3753631.739854858, + 13.47, -2001181.7002466794, -4743309.377747722, 3753632.6892803432, + 13.48, -2001180.305196763, -4743309.424598012, 3753633.6369143697, + 13.49, -2001178.9080401114, -4743309.4714312665, 3753634.582744761, + 13.5, -2001177.5087658342, -4743309.518225627, 3753635.5267593428, + 13.51, -2001176.1073630424, -4743309.564959232, 3753636.4689459414, + 13.52, -2001174.703820845, -4743309.611610221, 3753637.4092923813, + 13.530000000000001, -2001173.2981283541, -4743309.658156734, 3753638.347786488, + 13.540000000000001, -2001171.8902746798, -4743309.704576911, 3753639.2844160874, + 13.55, -2001170.480248932, -4743309.750848892, 3753640.219169004, + 13.56, -2001169.068040221, -4743309.796950816, 3753641.1520330645, + 13.57, -2001167.6536376574, -4743309.842860824, 3753642.0829960937, + 13.58, -2001166.237030352, -4743309.888557055, 3753643.012045918, + 13.59, -2001164.8182074146, -4743309.934017648, 3753643.9391703606, + 13.6, -2001163.397157956, -4743309.979220744, 3753644.8643572493, + 13.61, -2001161.9738710853, -4743310.02414448, 3753645.787594407, + 13.620000000000001, -2001160.548335915, -4743310.068766999, 3753646.7088696617, + 13.63, -2001159.1205415549, -4743310.11306644, 3753647.628170837, + 13.64, -2001157.6904771142, -4743310.157020942, 3753648.5454857596, + 13.65, -2001156.2581317048, -4743310.2006086465, 3753649.4608022557, + 13.66, -2001154.823494436, -4743310.243807689, 3753650.374108148, + 13.67, -2001153.3865544181, -4743310.286596213, 3753651.2853912627, + 13.68, -2001151.9473007624, -4743310.328952357, 3753652.194639427, + 13.69, -2001150.505722579, -4743310.370854262, 3753653.1018404653, + 13.700000000000001, -2001149.0618089784, -4743310.412280067, 3753654.0069822036, + 13.71, -2001147.6155490698, -4743310.453207908, 3753654.910052464, + 13.72, -2001146.1669319656, -4743310.493615932, 3753655.8110390776, + 13.73, -2001144.7159467745, -4743310.533482272, 3753656.7099298644, + 13.74, -2001143.2625826076, -4743310.572785071, 3753657.606712653, + 13.75, -2001141.8068285757, -4743310.611502469, 3753658.5013752696, + 13.76, -2001140.3486737877, -4743310.649612604, 3753659.393905536, + 13.77, -2001138.8881073557, -4743310.687093616, 3753660.284291281, + 13.780000000000001, -2001137.425118389, -4743310.723923648, 3753661.172520328, + 13.790000000000001, -2001135.9596959988, -4743310.760080834, 3753662.058580503, + 13.8, -2001134.4918292952, -4743310.795543319, 3753662.942459633, + 13.81, -2001133.0215073884, -4743310.83028924, 3753663.8241455415, + 13.82, -2001131.5487193887, -4743310.864296738, 3753664.7036260534, + 13.83, -2001130.0734544063, -4743310.89754395, 3753665.580888996, + 13.84, -2001128.5957015522, -4743310.930009019, 3753666.4559221934, + 13.85, -2001127.1153956298, -4743310.961701492, 3753667.328879416, + 13.86, -2001125.6319948758, -4743310.992924557, 3753668.201399741, + 13.870000000000001, -2001124.145378771, -4743311.023772612, 3753669.0738912895, + 13.88, -2001122.6555678023, -4743311.054262057, 3753669.9463370605, + 13.89, -2001121.1625824564, -4743311.084409297, 3753670.8187200553, + 13.9, -2001119.6664432203, -4743311.114230735, 3753671.6910232743, + 13.91, -2001118.1671705807, -4743311.1437427765, 3753672.563229717, + 13.92, -2001116.664785025, -4743311.172961823, 3753673.4353223844, + 13.93, -2001115.1593070398, -4743311.201904279, 3753674.307284277, + 13.94, -2001113.650757112, -4743311.230586549, 3753675.179098395, + 13.950000000000001, -2001112.1391557285, -4743311.259025038, 3753676.0507477378, + 13.96, -2001110.624523377, -4743311.287236147, 3753676.9222153067, + 13.97, -2001109.106880543, -4743311.315236281, 3753677.7934841015, + 13.98, -2001107.5862477145, -4743311.343041844, 3753678.6645371234, + 13.99, -2001106.0626453778, -4743311.37066924, 3753679.535357373, + 14, -2001104.5360940201, -4743311.39813487, 3753680.4059278485, + 14.01, -2001103.0066141284, -4743311.425455144, 3753681.276231552, + 14.02, -2001101.4742261893, -4743311.4526464585, 3753682.1462514834, + 14.030000000000001, -2001099.9389506904, -4743311.479725222, 3753683.015970643, + 14.040000000000001, -2001098.4008081178, -4743311.506707837, 3753683.8853720315, + 14.05, -2001096.8598189591, -4743311.533610708, 3753684.7544386485, + 14.06, -2001095.3160037005, -4743311.560450235, 3753685.6231534947, + 14.07, -2001093.7693828295, -4743311.587242827, 3753686.491499571, + 14.08, -2001092.2199768329, -4743311.614004885, 3753687.359459877, + 14.09, -2001090.6678061972, -4743311.640752813, 3753688.2270174124, + 14.1, -2001089.1128914093, -4743311.667503013, 3753689.094155179, + 14.11, -2001087.5552529572, -4743311.694271893, 3753689.960856177, + 14.120000000000001, -2001085.9949113268, -4743311.721075854, 3753690.8271034057, + 14.13, -2001084.4318870055, -4743311.747931302, 3753691.6928798654, + 14.14, -2001082.8662004797, -4743311.774854636, 3753692.558168558, + 14.15, -2001081.2978722365, -4743311.801862265, 3753693.4229524815, + 14.16, -2001079.7269227633, -4743311.828970588, 3753694.287214639, + 14.17, -2001078.1533725462, -4743311.856196014, 3753695.1509380294, + 14.18, -2001076.577242073, -4743311.883554943, 3753696.014105652, + 14.19, -2001074.99855183, -4743311.911063781, 3753696.876700509, + 14.200000000000001, -2001073.4173223043, -4743311.938738929, 3753697.7387055987, + 14.21, -2001071.833573983, -4743311.966596792, 3753698.6001039236, + 14.22, -2001070.2473273526, -4743311.994653775, 3753699.4608784826, + 14.23, -2001068.6586029006, -4743312.022926282, 3753700.321012277, + 14.24, -2001067.0674211131, -4743312.051430714, 3753701.180488307, + 14.25, -2001065.4738024776, -4743312.080183477, 3753702.0392895713, + 14.26, -2001063.8777674811, -4743312.109200975, 3753702.897399072, + 14.27, -2001062.27933661, -4743312.138499611, 3753703.7547998102, + 14.280000000000001, -2001060.678530352, -4743312.168095788, 3753704.6114747836, + 14.290000000000001, -2001059.0753691932, -4743312.198005911, 3753705.4674069937, + 14.3, -2001057.4698736211, -4743312.2282463815, 3753706.3225794416, + 14.31, -2001055.862064122, -4743312.258833607, 3753707.1769751264, + 14.32, -2001054.2519611833, -4743312.289783988, 3753708.03057705, + 14.33, -2001052.6395852922, -4743312.321113931, 3753708.8833682113, + 14.34, -2001051.0249569349, -4743312.352839838, 3753709.7353316117, + 14.35, -2001049.4080965987, -4743312.384978113, 3753710.5864502504, + 14.36, -2001047.7890247705, -4743312.41754516, 3753711.436707129, + 14.370000000000001, -2001046.167761937, -4743312.450557381, 3753712.286085246, + 14.38, -2001044.5443285855, -4743312.484031184, 3753713.134567603, + 14.39, -2001042.9187452025, -4743312.517982967, 3753713.9821372014, + 14.4, -2001041.2910322754, -4743312.55242914, 3753714.8287770394, + 14.41, -2001039.6612102906, -4743312.587386103, 3753715.6744701187, + 14.42, -2001038.029299735, -4743312.622870259, 3753716.519199439, + 14.43, -2001036.395321096, -4743312.658898015, 3753717.3629480014, + 14.44, -2001034.7592948608, -4743312.695485773, 3753718.205698805, + 14.450000000000001, -2001033.121241515, -4743312.732649935, 3753719.0474348506, + 14.46, -2001031.4811815473, -4743312.770406907, 3753719.8881391394, + 14.47, -2001029.8391354429, -4743312.808773094, 3753720.7277946714, + 14.48, -2001028.1951236897, -4743312.847764897, 3753721.5663844463, + 14.49, -2001026.5491667744, -4743312.887398722, 3753722.4038914647, + 14.5, -2001024.9012851834, -4743312.92769097, 3753723.240298727, + 14.51, -2001023.2514994044, -4743312.968658046, 3753724.0755892326, + 14.52, -2001021.599829924, -4743313.010316355, 3753724.909745984, + 14.530000000000001, -2001019.946297229, -4743313.0526823, 3753725.7427519797, + 14.540000000000001, -2001018.2909218066, -4743313.095772284, 3753726.5745902206, + 14.55, -2001016.6337241437, -4743313.139602712, 3753727.405243707, + 14.56, -2001014.9747247272, -4743313.184189987, 3753728.234695439, + 14.57, -2001013.3139440436, -4743313.229550513, 3753729.0629284186, + 14.58, -2001011.6514025803, -4743313.275700695, 3753729.889925644, + 14.59, -2001009.987120824, -4743313.322656935, 3753730.7156701162, + 14.6, -2001008.3211192612, -4743313.370435635, 3753731.5401448356, + 14.61, -2001006.6534183798, -4743313.4190532025, 3753732.363332802, + 14.620000000000001, -2001004.984038666, -4743313.46852604, 3753733.185217017, + 14.63, -2001003.3130006073, -4743313.518870552, 3753734.00578048, + 14.64, -2001001.64032469, -4743313.570103141, 3753734.825006191, + 14.65, -2000999.9660314007, -4743313.622240211, 3753735.642877152, + 14.66, -2000998.2901412274, -4743313.675298165, 3753736.459376362, + 14.67, -2000996.6126746559, -4743313.729293407, 3753737.274486821, + 14.68, -2000994.933652174, -4743313.784242343, 3753738.0881915297, + 14.69, -2000993.2530942683, -4743313.840161375, 3753738.9004734894, + 14.700000000000001, -2000991.5710214253, -4743313.897066906, 3753739.7113156994, + 14.71, -2000989.8874541332, -4743313.954975341, 3753740.5207011597, + 14.72, -2000988.2024128772, -4743314.013903083, 3753741.328612872, + 14.73, -2000986.515918146, -4743314.073866538, 3753742.1350338357, + 14.74, -2000984.8279904246, -4743314.134882106, 3753742.939947051, + 14.75, -2000983.1386502013, -4743314.196966195, 3753743.7433355185, + 14.76, -2000981.4479179627, -4743314.260135205, 3753744.545182239, + 14.77, -2000979.7558141954, -4743314.324405541, 3753745.3454702115, + 14.780000000000001, -2000978.0623593868, -4743314.389793608, 3753746.144182438, + 14.790000000000001, -2000976.3675740235, -4743314.456315808, 3753746.941301918, + 14.8, -2000974.6714785923, -4743314.523988546, 3753747.7368116514, + 14.81, -2000972.9740935804, -4743314.592828226, 3753748.5306946402, + 14.82, -2000971.2754394745, -4743314.66285125, 3753749.322933882, + 14.83, -2000969.5755367614, -4743314.734074023, 3753750.11351238, + 14.84, -2000967.874405929, -4743314.806512949, 3753750.9024131326, + 14.85, -2000966.1720674625, -4743314.8801844325, 3753751.6896191402, + 14.86, -2000964.4685418503, -4743314.955104874, 3753752.4751134044, + 14.870000000000001, -2000962.7638495786, -4743315.031290681, 3753753.258878925, + 14.88, -2000961.0580111349, -4743315.108758256, 3753754.0408987016, + 14.89, -2000959.3510470053, -4743315.187524002, 3753754.8211557353, + 14.9, -2000957.6429776775, -4743315.267604324, 3753755.5996330264, + 14.91, -2000955.933823637, -4743315.349015622, 3753756.376313574, + 14.92, -2000954.2236053727, -4743315.431774305, 3753757.1511803805, + 14.93, -2000952.5123433706, -4743315.515896775, 3753757.9242164455, + 14.94, -2000950.8000581171, -4743315.601399435, 3753758.6954047685, + 14.950000000000001, -2000949.0867700998, -4743315.688298688, 3753759.4647283503, + 14.96, -2000947.3724998063, -4743315.776610942, 3753760.2321701916, + 14.97, -2000945.6572677218, -4743315.866352594, 3753760.9977132925, + 14.98, -2000943.9410943338, -4743315.957540054, 3753761.761340653, + 14.99, -2000942.2240001298, -4743316.050189722, 3753762.523035274, + 15, -2000940.5060055964, -4743316.144318002, 3753763.2827801555, + 15.01, -2000938.787131221, -4743316.2399413, 3753764.040558298, + 15.02, -2000937.0673974887, -4743316.337076018, 3753764.7963527013, + 15.030000000000001, -2000935.3468248886, -4743316.43573856, 3753765.550146366, + 15.040000000000001, -2000933.625433907, -4743316.535945331, 3753766.301922293, + 15.05, -2000931.9032450304, -4743316.637712732, 3753767.0516634816, + 15.06, -2000930.1802787455, -4743316.74105717, 3753767.799352933, + 15.07, -2000928.4565555402, -4743316.845995046, 3753768.544973648, + 15.08, -2000926.7320959007, -4743316.952542767, 3753769.288508626, + 15.09, -2000925.006920314, -4743317.060716733, 3753770.0299408673, + 15.1, -2000923.2810492662, -4743317.170533351, 3753770.7692533727, + 15.11, -2000921.5545032462, -4743317.282009022, 3753771.5064291423, + 15.120000000000001, -2000919.8273027393, -4743317.395160153, 3753772.2414511754, + 15.13, -2000918.0994682326, -4743317.510003144, 3753772.974302474, + 15.14, -2000916.371020214, -4743317.626554401, 3753773.7049660385, + 15.15, -2000914.6419791693, -4743317.744830327, 3753774.4334248677, + 15.16, -2000912.9123655856, -4743317.864847328, 3753775.1596619636, + 15.17, -2000911.1821999503, -4743317.986621804, 3753775.883660325, + 15.18, -2000909.4515027504, -4743318.110170162, 3753776.605402954, + 15.19, -2000907.7202944718, -4743318.235508803, 3753777.324872848, + 15.200000000000001, -2000905.988595603, -4743318.362654135, 3753778.042053011, + 15.21, -2000904.25642663, -4743318.491622557, 3753778.7569264406, + 15.22, -2000902.5238080393, -4743318.622430474, 3753779.4694761382, + 15.23, -2000900.790760318, -4743318.755094293, 3753780.179685104, + 15.24, -2000899.0573039541, -4743318.889630414, 3753780.8875363385, + 15.25, -2000897.3234594325, -4743319.026055241, 3753781.5930128414, + 15.26, -2000895.589247242, -4743319.16438518, 3753782.2960976143, + 15.27, -2000893.854687869, -4743319.304636634, 3753782.9967736565, + 15.280000000000001, -2000892.1198018, -4743319.446826005, 3753783.6950239684, + 15.290000000000001, -2000890.384609522, -4743319.590969699, 3753784.3908315506, + 15.3, -2000888.6491315227, -4743319.737084119, 3753785.0841794037, + 15.31, -2000886.913388288, -4743319.885185669, 3753785.775050527, + 15.32, -2000885.1774003056, -4743320.035290753, 3753786.463427922, + 15.33, -2000883.4411880611, -4743320.187415772, 3753787.1492945882, + 15.34, -2000881.704772043, -4743320.341577134, 3753787.8326335275, + 15.35, -2000879.9681727372, -4743320.49779124, 3753788.5134277367, + 15.36, -2000878.2314106317, -4743320.656074494, 3753789.1916602203, + 15.370000000000001, -2000876.4945062117, -4743320.816443302, 3753789.8673139764, + 15.38, -2000874.7574799657, -4743320.978914064, 3753790.5403720047, + 15.39, -2000873.0203523797, -4743321.143503186, 3753791.2108173072, + 15.4, -2000871.2831439413, -4743321.310227072, 3753791.878632884, + 15.41, -2000869.5458751372, -4743321.479102126, 3753792.5438017347, + 15.42, -2000867.8085664539, -4743321.65014475, 3753793.2063068603, + 15.43, -2000866.071238378, -4743321.823371351, 3753793.866131261, + 15.44, -2000864.3339113975, -4743321.998798328, 3753794.5232579354, + 15.450000000000001, -2000862.5966059992, -4743322.1764420895, 3753795.1776698865, + 15.46, -2000860.8593426694, -4743322.356319036, 3753795.8293501134, + 15.47, -2000859.122141895, -4743322.538445572, 3753796.4782816162, + 15.48, -2000857.3850241632, -4743322.722838103, 3753797.124447395, + 15.49, -2000855.648009961, -4743322.909513031, 3753797.7678304524, + 15.5, -2000853.911119775, -4743323.09848676, 3753798.4084137855, + 15.51, -2000852.1743740926, -4743323.289775695, 3753799.046180397, + 15.52, -2000850.4377933997, -4743323.483396236, 3753799.681113286, + 15.530000000000001, -2000848.7013981855, -4743323.679364793, 3753800.3131954535, + 15.540000000000001, -2000846.9652089342, -4743323.877697766, 3753800.9424098986, + 15.55, -2000845.2292461342, -4743324.078411556, 3753801.5687396233, + 15.56, -2000843.4935302716, -4743324.281522572, 3753802.1921676267, + 15.57, -2000841.7580818343, -4743324.487047216, 3753802.8126769103, + 15.58, -2000840.0229213086, -4743324.695001889, 3753803.4302504733, + 15.59, -2000838.2880691816, -4743324.905402999, 3753804.044871317, + 15.6, -2000836.55354594, -4743325.118266948, 3753804.656522441, + 15.610000000000001, -2000834.8193720705, -4743325.33361014, 3753805.265186846, + 15.620000000000001, -2000833.085568061, -4743325.551448977, 3753805.8708475325, + 15.63, -2000831.3521543983, -4743325.771799865, 3753806.473487499, + 15.64, -2000829.6191515685, -4743325.994679208, 3753807.0730897496, + 15.65, -2000827.8865800581, -4743326.220103407, 3753807.669637281, + 15.66, -2000826.1544603547, -4743326.448088868, 3753808.263113095, + 15.67, -2000824.4228129461, -4743326.678651994, 3753808.853500192, + 15.68, -2000822.691658318, -4743326.91180919, 3753809.4407815724, + 15.69, -2000820.9610169579, -4743327.147576859, 3753810.0249402365, + 15.700000000000001, -2000819.2309093522, -4743327.385971403, 3753810.6059591835, + 15.71, -2000817.5013559884, -4743327.627009228, 3753811.1838214155, + 15.72, -2000815.772377353, -4743327.870706737, 3753811.758509932, + 15.73, -2000814.0439939331, -4743328.1170803355, 3753812.330007734, + 15.74, -2000812.316226216, -4743328.366146425, 3753812.8982978202, + 15.75, -2000810.589094688, -4743328.617921409, 3753813.4633631925, + 15.76, -2000808.8626198354, -4743328.872421692, 3753814.02518685, + 15.77, -2000807.1368221468, -4743329.129663677, 3753814.5837517944, + 15.780000000000001, -2000805.4117221083, -4743329.389663771, 3753815.1390410247, + 15.790000000000001, -2000803.6873402062, -4743329.652438374, 3753815.6910375427, + 15.8, -2000801.9636969282, -4743329.918003892, 3753816.2397243474, + 15.81, -2000800.2408127608, -4743330.186376726, 3753816.7850844394, + 15.82, -2000798.5187081916, -4743330.457573284, 3753817.3271008204, + 15.83, -2000796.797403707, -4743330.7316099685, 3753817.8657564884, + 15.84, -2000795.0769197932, -4743331.00850318, 3753818.401034445, + 15.85, -2000793.3572769389, -4743331.288269325, 3753818.932917691, + 15.860000000000001, -2000791.6384956287, -4743331.570924807, 3753819.461389225, + 15.870000000000001, -2000789.9205963518, -4743331.85648603, 3753819.9864320504, + 15.88, -2000788.2035995943, -4743332.144969397, 3753820.5080291647, + 15.89, -2000786.4875258424, -4743332.436391314, 3753821.026163569, + 15.9, -2000784.7723955836, -4743332.730768179, 3753821.540818264, + 15.91, -2000783.0582293049, -4743333.028116403, 3753822.0519762505, + 15.92, -2000781.3450474925, -4743333.328452383, 3753822.5596205266, + 15.93, -2000779.6328706346, -4743333.631792529, 3753823.063734096, + 15.94, -2000777.9217192174, -4743333.938153243, 3753823.5642999574, + 15.950000000000001, -2000776.2116137277, -4743334.247550926, 3753824.06130111, + 15.96, -2000774.5025746522, -4743334.560001982, 3753824.5547205545, + 15.97, -2000772.7946224783, -4743334.8755228175, 3753825.0445412924, + 15.98, -2000771.087777693, -4743335.194129838, 3753825.5307463245, + 15.99, -2000769.382060783, -4743335.51583944, 3753826.01331865, + 16, -2000767.6774922344, -4743335.840668033, 3753826.4922412676, + 16.01, -2000765.974092536, -4743336.168632019, 3753826.967497181, + 16.02, -2000764.2718821734, -4743336.499747804, 3753827.4390693894, + 16.03, -2000762.5708816329, -4743336.834031788, 3753827.90694089, + 16.04, -2000760.8711114032, -4743337.171500377, 3753828.3710946892, + 16.05, -2000759.1725919703, -4743337.512169975, 3753828.831513782, + 16.06, -2000757.4753438209, -4743337.856056984, 3753829.2881811713, + 16.07, -2000755.779387442, -4743338.20317781, 3753829.741079856, + 16.080000000000002, -2000754.08474332, -4743338.553548854, 3753830.190192837, + 16.09, -2000752.3914319437, -4743338.907186525, 3753830.6355031165, + 16.1, -2000750.699473798, -4743339.26410722, 3753831.076993692, + 16.11, -2000749.0088893704, -4743339.624327346, 3753831.514647565, + 16.12, -2000747.3196991484, -4743339.987863308, 3753831.9484477364, + 16.13, -2000745.6319236192, -4743340.3547315085, 3753832.3783772066, + 16.14, -2000743.9455832674, -4743340.724948349, 3753832.8044189736, + 16.15, -2000742.260698583, -4743341.098530239, 3753833.2265560413, + 16.16, -2000740.5767601717, -4743341.475411961, 3753833.6449435316, + 16.17, -2000738.89172496, -4743341.855280523, 3753834.060243794, + 16.18, -2000737.2054019573, -4743342.238093842, 3753834.472528759, + 16.19, -2000735.5178070434, -4743342.623841046, 3753834.881803666, + 16.2, -2000733.8289560992, -4743343.012511262, 3753835.2880737577, + 16.21, -2000732.138865005, -4743343.404093615, 3753835.691344274, + 16.22, -2000730.4475496402, -4743343.798577233, 3753836.0916204583, + 16.23, -2000728.755025886, -4743344.195951244, 3753836.4889075523, + 16.240000000000002, -2000727.0613096226, -4743344.596204774, 3753836.8832107964, + 16.25, -2000725.3664167293, -4743344.999326949, 3753837.274535432, + 16.26, -2000723.670363088, -4743345.405306897, 3753837.662886701, + 16.27, -2000721.9731645775, -4743345.814133746, 3753838.0482698446, + 16.28, -2000720.274837079, -4743346.225796622, 3753838.430690105, + 16.29, -2000718.5753964721, -4743346.640284649, 3753838.8101527235, + 16.3, -2000716.874858638, -4743347.057586959, 3753839.1866629412, + 16.31, -2000715.1732394558, -4743347.477692675, 3753839.560226, + 16.32, -2000713.4705548065, -4743347.9005909255, 3753839.930847141, + 16.330000000000002, -2000711.7668205705, -4743348.326270838, 3753840.298531607, + 16.34, -2000710.0620526276, -4743348.754721539, 3753840.6632846375, + 16.35, -2000708.3562668585, -4743349.185932155, 3753841.0251114755, + 16.36, -2000706.649479143, -4743349.619891812, 3753841.3840173623, + 16.37, -2000704.9417053617, -4743350.056589639, 3753841.740007539, + 16.38, -2000703.2329613953, -4743350.49601476, 3753842.0930872457, + 16.39, -2000701.5232631231, -4743350.938156307, 3753842.4432617263, + 16.4, -2000699.8126264259, -4743351.383003401, 3753842.790536222, + 16.41, -2000698.101067184, -4743351.830545172, 3753843.134915974, + 16.42, -2000696.388601278, -4743352.280770747, 3753843.4764062236, + 16.43, -2000694.675244587, -4743352.733669253, 3753843.815012212, + 16.44, -2000692.9610129925, -4743353.189229816, 3753844.150739181, + 16.45, -2000691.2459223745, -4743353.647441563, 3753844.483592372, + 16.46, -2000689.5299886134, -4743354.108293622, 3753844.813577027, + 16.47, -2000687.8132275888, -4743354.571775117, 3753845.140698387, + 16.48, -2000686.0956551814, -4743355.037875179, 3753845.464961694, + 16.490000000000002, -2000684.3772872712, -4743355.5065829335, 3753845.7863721894, + 16.5, -2000682.6581397392, -4743355.977887505, 3753846.104935114, + 16.51, -2000680.9382284647, -4743356.451778023, 3753846.42065571, + 16.52, -2000679.2175693288, -4743356.928243614, 3753846.733539218, + 16.53, -2000677.4961782114, -4743357.407273405, 3753847.0435908814, + 16.54, -2000675.7740709928, -4743357.888856522, 3753847.35081594, + 16.55, -2000674.0512635538, -4743358.372982091, 3753847.6552196355, + 16.56, -2000672.3277717738, -4743358.859639243, 3753847.9568072106, + 16.57, -2000670.6036115335, -4743359.348817102, 3753848.2555839056, + 16.580000000000002, -2000668.8787987127, -4743359.840504794, 3753848.551554963, + 16.59, -2000667.1533491928, -4743360.334691448, 3753848.8447256233, + 16.6, -2000665.4272788528, -4743360.83136619, 3753849.135101128, + 16.61, -2000663.7006035738, -4743361.330518147, 3753849.422686719, + 16.62, -2000661.9733392359, -4743361.832136446, 3753849.7074876386, + 16.63, -2000660.2455017199, -4743362.336210212, 3753849.9895091276, + 16.64, -2000658.5171069046, -4743362.842728575, 3753850.2687564264, + 16.65, -2000656.788170671, -4743363.351680661, 3753850.5452347794, + 16.66, -2000655.0587089001, -4743363.863055596, 3753850.818949424, + 16.67, -2000653.3287374717, -4743364.376842508, 3753851.089905606, + 16.68, -2000651.5982722656, -4743364.893030523, 3753851.3581085643, + 16.69, -2000649.8673291625, -4743365.411608769, 3753851.6235635406, + 16.7, -2000648.135924043, -4743365.932566372, 3753851.8862757776, + 16.71, -2000646.404072787, -4743366.455892459, 3753852.1462505157, + 16.72, -2000644.6717912743, -4743366.981576156, 3753852.4034929965, + 16.73, -2000642.9390953863, -4743367.509606591, 3753852.6580084627, + 16.740000000000002, -2000641.206001002, -4743368.039972894, 3753852.9098021546, + 16.75, -2000639.472524003, -4743368.572664185, 3753853.158879313, + 16.76, -2000637.7386802684, -4743369.107669597, 3753853.405245182, + 16.77, -2000636.0044856793, -4743369.644978255, 3753853.6489050006, + 16.78, -2000634.2699561152, -4743370.184579284, 3753853.8898640117, + 16.79, -2000632.5351074568, -4743370.726461812, 3753854.128127456, + 16.8, -2000630.799955585, -4743371.27061497, 3753854.3637005757, + 16.81, -2000629.064516379, -4743371.817027877, 3753854.596588612, + 16.82, -2000627.32880572, -4743372.365689666, 3753854.8267968064, + 16.830000000000002, -2000625.5928394871, -4743372.916589462, 3753855.0543304, + 16.84, -2000623.8566335617, -4743373.469716394, 3753855.279194636, + 16.85, -2000622.1202038238, -4743374.0250595845, 3753855.5013947543, + 16.86, -2000620.3835661535, -4743374.582608164, 3753855.7209359957, + 16.87, -2000618.6467364312, -4743375.142351258, 3753855.9378236034, + 16.88, -2000616.9097305366, -4743375.704277993, 3753856.1520628184, + 16.89, -2000615.1725643512, -4743376.268377499, 3753856.363658882, + 16.9, -2000613.435253754, -4743376.834638898, 3753856.5726170354, + 16.91, -2000611.6978146262, -4743377.403051322, 3753856.7789425217, + 16.92, -2000609.9602628474, -4743377.973603893, 3753856.98264058, + 16.93, -2000608.222614298, -4743378.546285741, 3753857.1837164536, + 16.94, -2000606.4848848593, -4743379.121085994, 3753857.3821753836, + 16.95, -2000604.7470904097, -4743379.697993775, 3753857.5780226113, + 16.96, -2000603.0092468313, -4743380.276998214, 3753857.771263378, + 16.97, -2000601.2713700032, -4743380.858088437, 3753857.9619029257, + 16.98, -2000599.5334758067, -4743381.441253572, 3753858.1499464964, + 16.990000000000002, -2000597.7955801203, -4743382.026482742, 3753858.3353993306, + 17, -2000596.057698826, -4743382.6137650795, 3753858.51826667, + 17.01, -2000594.3198478038, -4743383.2030897075, 3753858.698553757, + 17.02, -2000592.582042933, -4743383.794445754, 3753858.876265831, + 17.03, -2000590.844300095, -4743384.387822348, 3753859.0514081353, + 17.04, -2000589.1066351694, -4743384.983208612, 3753859.2239859113, + 17.05, -2000587.369064037, -4743385.580593675, 3753859.3940044, + 17.06, -2000585.6316025776, -4743386.179966667, 3753859.5614688434, + 17.07, -2000583.8942666715, -4743386.781316711, 3753859.726384483, + 17.080000000000002, -2000582.157072199, -4743387.384632934, 3753859.888756559, + 17.09, -2000580.4200350412, -4743387.989904464, 3753860.0485903155, + 17.1, -2000578.6831710765, -4743388.597120428, 3753860.205890991, + 17.11, -2000576.9464961872, -4743389.206269955, 3753860.3606638294, + 17.12, -2000575.2100262523, -4743389.817342168, 3753860.5129140713, + 17.13, -2000573.4737771528, -4743390.430326196, 3753860.6626469577, + 17.14, -2000571.7377647688, -4743391.045211166, 3753860.8098677318, + 17.150000000000002, -2000570.00200498, -4743391.661986203, 3753860.9545816323, + 17.16, -2000568.2665136675, -4743392.280640438, 3753861.096793903, + 17.17, -2000566.5313067106, -4743392.901162993, 3753861.236509785, + 17.18, -2000564.7963999908, -4743393.523542998, 3753861.3737345194, + 17.19, -2000563.0618093873, -4743394.14776958, 3753861.5084733483, + 17.2, -2000561.3275507812, -4743394.773831865, 3753861.6407315126, + 17.21, -2000559.5936400522, -4743395.40171898, 3753861.770514254, + 17.22, -2000557.860093081, -4743396.031420051, 3753861.897826814, + 17.23, -2000556.1269257471, -4743396.662924206, 3753862.0226744344, + 17.240000000000002, -2000554.3941539319, -4743397.296220573, 3753862.1450623563, + 17.25, -2000552.6617935153, -4743397.931298276, 3753862.2649958218, + 17.26, -2000550.9298603768, -4743398.568146445, 3753862.3824800714, + 17.27, -2000549.1983703969, -4743399.206754205, 3753862.4975203467, + 17.28, -2000547.4673394565, -4743399.847110684, 3753862.6101218904, + 17.29, -2000545.736783436, -4743400.489205008, 3753862.720289943, + 17.3, -2000544.0067182153, -4743401.133026303, 3753862.828029746, + 17.31, -2000542.2771596746, -4743401.778563699, 3753862.9333465425, + 17.32, -2000540.548123694, -4743402.425806321, 3753863.0362455733, + 17.330000000000002, -2000538.8196261541, -4743403.074743296, 3753863.136732077, + 17.34, -2000537.0916829356, -4743403.725363751, 3753863.2348112995, + 17.35, -2000535.3643099174, -4743404.377656812, 3753863.33048848, + 17.36, -2000533.6375229806, -4743405.031611607, 3753863.423768859, + 17.37, -2000531.9113380061, -4743405.687217264, 3753863.514657681, + 17.38, -2000530.1857708734, -4743406.344462907, 3753863.603160185, + 17.39, -2000528.4608374627, -4743407.003337665, 3753863.6892816126, + 17.400000000000002, -2000526.736553655, -4743407.663830666, 3753863.773027207, + 17.41, -2000525.0129353297, -4743408.325931033, 3753863.8544022087, + 17.42, -2000523.2899983674, -4743408.989627896, 3753863.9334118594, + 17.43, -2000521.567758649, -4743409.654910383, 3753864.0100614, + 17.44, -2000519.8462320534, -4743410.321767617, 3753864.084356073, + 17.45, -2000518.1254344622, -4743410.990188728, 3753864.1563011194, + 17.46, -2000516.4053817552, -4743411.660162843, 3753864.2259017816, + 17.47, -2000514.686089813, -4743412.331679086, 3753864.2931632996, + 17.48, -2000512.9675745151, -4743413.004726586, 3753864.3580909143, + 17.490000000000002, -2000511.249851742, -4743413.679294471, 3753864.42068987, + 17.5, -2000509.5329373744, -4743414.3553718645, 3753864.480965406, + 17.51, -2000507.8168472922, -4743415.032947898, 3753864.538922765, + 17.52, -2000506.1015973764, -4743415.712011695, 3753864.5945671876, + 17.53, -2000504.3872035067, -4743416.392552383, 3753864.647903916, + 17.54, -2000502.6736815628, -4743417.074559091, 3753864.6989381914, + 17.55, -2000500.961047426, -4743417.758020942, 3753864.7476752554, + 17.56, -2000499.249316976, -4743418.442927067, 3753864.7941203495, + 17.57, -2000497.5385060932, -4743419.129266589, 3753864.838278715, + 17.580000000000002, -2000495.8286306579, -4743419.817028639, 3753864.8801555936, + 17.59, -2000494.1197065501, -4743420.50620234, 3753864.9197562267, + 17.6, -2000492.411749651, -4743421.196776822, 3753864.9570858562, + 17.61, -2000490.7047758396, -4743421.888741212, 3753864.9921497237, + 17.62, -2000488.9988009972, -4743422.582084634, 3753865.02495307, + 17.63, -2000487.2938410034, -4743423.276796217, 3753865.055501137, + 17.64, -2000485.5899117386, -4743423.972865087, 3753865.083799166, + 17.650000000000002, -2000483.8870290834, -4743424.670280372, 3753865.1098523987, + 17.66, -2000482.1852089183, -4743425.369031199, 3753865.1336660767, + 17.67, -2000480.484467123, -4743426.069106693, 3753865.155245442, + 17.68, -2000478.7848195776, -4743426.770495983, 3753865.1745957355, + 17.69, -2000477.0862821625, -4743427.4731881935, 3753865.1917221975, + 17.7, -2000475.3888707587, -4743428.177172456, 3753865.2066300716, + 17.71, -2000473.6926012463, -4743428.882437892, 3753865.2193245986, + 17.72, -2000471.9974895043, -4743429.58897363, 3753865.229811019, + 17.73, -2000470.3035514145, -4743430.2967688, 3753865.238094576, + 17.740000000000002, -2000468.6108028563, -4743431.005812527, 3753865.2441805103, + 17.75, -2000466.9192597107, -4743431.716093936, 3753865.248074063, + 17.76, -2000465.228937857, -4743432.427602156, 3753865.2497804766, + 17.77, -2000463.5398531766, -4743433.140326314, 3753865.249304992, + 17.78, -2000461.8520215494, -4743433.854255536, 3753865.246652851, + 17.79, -2000460.1654588548, -4743434.569378949, 3753865.2418292942, + 17.8, -2000458.4801809741, -4743435.28568568, 3753865.2348395633, + 17.81, -2000456.7962037877, -4743436.003164856, 3753865.2256889013, + 17.82, -2000455.1135431742, -4743436.721805604, 3753865.214382549, + 17.830000000000002, -2000453.4322150156, -4743437.441597051, 3753865.200925746, + 17.84, -2000451.7522351923, -4743438.162528325, 3753865.1853237376, + 17.85, -2000450.0736195832, -4743438.884588551, 3753865.1675817617, + 17.86, -2000448.39638407, -4743439.607766857, 3753865.147705062, + 17.87, -2000446.720544531, -4743440.332052369, 3753865.1256988784, + 17.88, -2000445.046116849, -4743441.057434215, 3753865.101568454, + 17.89, -2000443.3731169028, -4743441.783901521, 3753865.075319029, + 17.900000000000002, -2000441.7015605723, -4743442.511443414, 3753865.046955846, + 17.91, -2000440.031463739, -4743443.240049022, 3753865.016484146, + 17.92, -2000438.362842282, -4743443.96970747, 3753864.98390917, + 17.93, -2000436.6957120826, -4743444.700407888, 3753864.949236161, + 17.94, -2000435.0300890205, -4743445.4321394, 3753864.912470359, + 17.95, -2000433.3659889763, -4743446.164891135, 3753864.8736170065, + 17.96, -2000431.7034278298, -4743446.898652217, 3753864.832681344, + 17.97, -2000430.0424214618, -4743447.633411777, 3753864.789668614, + 17.98, -2000428.382985752, -4743448.3691589385, 3753864.744584058, + 17.990000000000002, -2000426.7251365816, -4743449.10588283, 3753864.6974329166, + 18, -2000425.0688898293, -4743449.843572577, 3753864.6482204315, + 18.01, -2000423.4142613767, -4743450.58221731, 3753864.596951845, + 18.02, -2000421.7612671037, -4743451.32180615, 3753864.543632398, + 18.03, -2000420.1099228908, -4743452.062328229, 3753864.488267333, + 18.04, -2000418.4602446181, -4743452.803772671, 3753864.4308618894, + 18.05, -2000416.8122481655, -4743453.5461286055, 3753864.3714213106, + 18.06, -2000415.1659494143, -4743454.289385157, 3753864.3099508374, + 18.07, -2000413.5213642435, -4743455.033531455, 3753864.2464557122, + 18.080000000000002, -2000411.878508534, -4743455.778556624, 3753864.1809411747, + 18.09, -2000410.2373981662, -4743456.524449793, 3753864.1134124678, + 18.1, -2000408.59804902, -4743457.271200085, 3753864.043874833, + 18.11, -2000406.9604769761, -4743458.018796631, 3753863.9723335113, + 18.12, -2000405.3246979145, -4743458.767228558, 3753863.8987937444, + 18.13, -2000403.6907277158, -4743459.516484989, 3753863.823260774, + 18.14, -2000402.0585822598, -4743460.266555055, 3753863.745739841, + 18.150000000000002, -2000400.428277427, -4743461.01742788, 3753863.666236187, + 18.16, -2000398.799829098, -4743461.769092593, 3753863.5847550547, + 18.17, -2000397.173253152, -4743462.52153832, 3753863.5013016844, + 18.18, -2000395.5485654704, -4743463.274754189, 3753863.415881318, + 18.19, -2000393.9257819331, -4743464.028729326, 3753863.3284991966, + 18.2, -2000392.3049184203, -4743464.783452855, 3753863.239160563, + 18.21, -2000390.6859908132, -4743465.53891391, 3753863.1478706575, + 18.22, -2000389.0690149902, -4743466.295101612, 3753863.0546347215, + 18.23, -2000387.4540068328, -4743467.052005087, 3753862.9594579963, + 18.240000000000002, -2000385.8409822213, -4743467.809613469, 3753862.8623457258, + 18.25, -2000384.229957036, -4743468.567915878, 3753862.7633031495, + 18.26, -2000382.6209471563, -4743469.326901443, 3753862.662335509, + 18.27, -2000381.013968463, -4743470.086559292, 3753862.559448044, + 18.28, -2000379.4090368375, -4743470.846878553, 3753862.454646001, + 18.29, -2000377.8061681578, -4743471.607848348, 3753862.3479346163, + 18.3, -2000376.2053783066, -4743472.36945781, 3753862.239319135, + 18.31, -2000374.6066831625, -4743473.131696061, 3753862.1288047964, + 18.32, -2000373.0100986059, -4743473.89455223, 3753862.0163968424, + 18.330000000000002, -2000371.4156405176, -4743474.658015443, 3753861.9021005165, + 18.34, -2000369.8233247781, -4743475.422074829, 3753861.7859210577, + 18.35, -2000368.2331672676, -4743476.186719515, 3753861.66786371, + 18.36, -2000366.6451838652, -4743476.951938625, 3753861.5479337117, + 18.37, -2000365.0593904522, -4743477.717721287, 3753861.4261363056, + 18.38, -2000363.4758029094, -4743478.48405663, 3753861.3024767344, + 18.39, -2000361.8944371159, -4743479.2509337785, 3753861.1769602397, + 18.400000000000002, -2000360.3153089532, -4743480.018341862, 3753861.0495920614, + 18.41, -2000358.7384342998, -4743480.786270003, 3753860.9203774417, + 18.42, -2000357.1638290372, -4743481.554707331, 3753860.7893216214, + 18.43, -2000355.5915090463, -4743482.323642974, 3753860.656429844, + 18.44, -2000354.0214902058, -4743483.093066058, 3753860.5217073495, + 18.45, -2000352.4537883967, -4743483.862965709, 3753860.3851593793, + 18.46, -2000350.8884195, -4743484.633331055, 3753860.2467911756, + 18.47, -2000349.3259461168, -4743485.404341739, 3753860.1060796715, + 18.48, -2000347.7673171097, -4743486.176330707, 3753859.96210507, + 18.490000000000002, -2000346.2125148326, -4743486.949308207, 3753859.814863847, + 18.5, -2000344.6615033622, -4743487.723278251, 3753859.664369979, + 18.51, -2000343.1142467745, -4743488.498244845, 3753859.510637441, + 18.52, -2000341.5707091454, -4743489.274212003, 3753859.3536802097, + 18.53, -2000340.0308545511, -4743490.051183731, 3753859.193512259, + 18.54, -2000338.4946470675, -4743490.829164038, 3753859.0301475655, + 18.55, -2000336.9620507716, -4743491.608156934, 3753858.863600104, + 18.56, -2000335.4330297385, -4743492.38816643, 3753858.6938838526, + 18.57, -2000333.9075480448, -4743493.169196533, 3753858.5210127835, + 18.580000000000002, -2000332.385569766, -4743493.9512512535, 3753858.3450008733, + 18.59, -2000330.8670589793, -4743494.734334601, 3753858.165862099, + 18.6, -2000329.3519797598, -4743495.518450582, 3753857.9836104335, + 18.61, -2000327.8402961842, -4743496.3036032105, 3753857.7982598552, + 18.62, -2000326.3319723287, -4743497.089796494, 3753857.6098243375, + 18.63, -2000324.8269722688, -4743497.877034439, 3753857.4183178577, + 18.64, -2000323.325260081, -4743498.665321059, 3753857.223754389, + 18.650000000000002, -2000321.8267998416, -4743499.45466036, 3753857.02614791, + 18.66, -2000320.3315556264, -4743500.2450563535, 3753856.8255123934, + 18.67, -2000318.8394915112, -4743501.036513046, 3753856.621861817, + 18.68, -2000317.3505715728, -4743501.82903445, 3753856.4152101544, + 18.69, -2000315.864759887, -4743502.622624574, 3753856.2055713823, + 18.7, -2000314.3820205303, -4743503.417287428, 3753855.9929594765, + 18.71, -2000312.9023175782, -4743504.213027018, 3753855.777388412, + 18.72, -2000311.4256151072, -4743505.009847357, 3753855.558872164, + 18.73, -2000309.951877193, -4743505.807752452, 3753855.3374247095, + 18.740000000000002, -2000308.4810679122, -4743506.606746313, 3753855.1130600222, + 18.75, -2000307.0131513407, -4743507.406832949, 3753854.8857920794, + 18.76, -2000305.5480915545, -4743508.208016372, 3753854.6556348545, + 18.77, -2000304.0858526297, -4743509.010300586, 3753854.422602326, + 18.78, -2000302.6263986428, -4743509.813689605, 3753854.1867084666, + 18.79, -2000301.1696936698, -4743510.618187438, 3753853.9479672536, + 18.8, -2000299.7157017868, -4743511.42379809, 3753853.7063926617, + 18.81, -2000298.2643870693, -4743512.230525576, 3753853.461998667, + 18.82, -2000296.8157135942, -4743513.038373901, 3753853.214799245, + 18.830000000000002, -2000295.369645437, -4743513.847347075, 3753852.9648083705, + 18.84, -2000293.9261466742, -4743514.657449109, 3753852.712040019, + 18.85, -2000292.485181382, -4743515.468684012, 3753852.456508168, + 18.86, -2000291.0467136363, -4743516.281055791, 3753852.198226792, + 18.87, -2000289.6107075133, -4743517.094568459, 3753851.9372098655, + 18.88, -2000288.1771270896, -4743517.909226024, 3753851.6734713647, + 18.89, -2000286.7459364403, -4743518.7250324935, 3753851.4070252655, + 18.900000000000002, -2000285.3170996418, -4743519.541991878, 3753851.1378855435, + 18.91, -2000283.8905807703, -4743520.3601081865, 3753850.866066173, + 18.92, -2000282.4663439025, -4743521.179385429, 3753850.591581132, + 18.93, -2000281.0443531142, -4743521.999827616, 3753850.314444394, + 18.94, -2000279.6245724803, -4743522.821438752, 3753850.034669935, + 18.95, -2000278.206966079, -4743523.644222852, 3753849.7522717305, + 18.96, -2000276.7914979854, -4743524.468183922, 3753849.4672637573, + 18.97, -2000275.378132275, -4743525.293325972, 3753849.179659989, + 18.98, -2000273.966833025, -4743526.119653012, 3753848.8894744026, + 18.990000000000002, -2000272.5575643107, -4743526.947169051, 3753848.596720972, + 19, -2000271.1502902084, -4743527.775878096, 3753848.3014136744, + 19.01, -2000269.744974795, -4743528.60578416, 3753848.003566486, + 19.02, -2000268.3415821453, -4743529.436891251, 3753847.7031933805, + 19.03, -2000266.9400763367, -4743530.269203378, 3753847.400308334, + 19.04, -2000265.540421444, -4743531.102724549, 3753847.094925322, + 19.05, -2000264.142581545, -4743531.937458776, 3753846.787058321, + 19.06, -2000262.7465207144, -4743532.773410066, 3753846.4767213054, + 19.07, -2000261.352203028, -4743533.61058243, 3753846.163928251, + 19.080000000000002, -2000259.9595925633, -4743534.448979876, 3753845.848693134, + 19.09, -2000258.5686533952, -4743535.288606414, 3753845.531029929, + 19.1, -2000257.179349601, -4743536.129466053, 3753845.210952612, + 19.11, -2000255.7916452563, -4743536.971562802, 3753844.8884751587, + 19.12, -2000254.4055044365, -4743537.814900672, 3753844.5636115447, + 19.13, -2000253.0208912191, -4743538.659483669, 3753844.236375746, + 19.14, -2000251.6377696786, -4743539.505315806, 3753843.9067817363, + 19.150000000000002, -2000250.2561038919, -4743540.352401091, 3753843.5748434924, + 19.16, -2000248.8758579355, -4743541.200743532, 3753843.240574991, + 19.17, -2000247.496995885, -4743542.05034714, 3753842.903990206, + 19.18, -2000246.119481817, -4743542.901215923, 3753842.565103113, + 19.19, -2000244.7432798073, -4743543.753353891, 3753842.2239276897, + 19.2, -2000243.3683539312, -4743544.606765052, 3753841.8804779085, + 19.21, -2000241.9946682667, -4743545.461453419, 3753841.534767746, + 19.22, -2000240.6221868885, -4743546.317422997, 3753841.18681118, + 19.23, -2000239.2508738728, -4743547.1746777985, 3753840.8366221823, + 19.240000000000002, -2000237.8806932962, -4743548.03322183, 3753840.484214732, + 19.25, -2000236.511609234, -4743548.893059103, 3753840.129602801, + 19.26, -2000235.1435857632, -4743549.754193625, 3753839.772800369, + 19.27, -2000233.7765869596, -4743550.616629408, 3753839.4138214085, + 19.28, -2000232.410576899, -4743551.480370459, 3753839.0526798964, + 19.29, -2000231.0455196586, -4743552.345420788, 3753838.689389807, + 19.3, -2000229.6813793136, -4743553.211784405, 3753838.323965118, + 19.31, -2000228.3181199396, -4743554.079465318, 3753837.9564198027, + 19.32, -2000226.955705614, -4743554.948467535, 3753837.586767838, + 19.330000000000002, -2000225.594100412, -4743555.818795069, 3753837.2150231996, + 19.34, -2000224.23326841, -4743556.690451927, 3753836.8411998614, + 19.35, -2000222.873173684, -4743557.563442119, 3753836.4653118006, + 19.36, -2000221.5137803103, -4743558.437769655, 3753836.0873729927, + 19.37, -2000220.1550523648, -4743559.313438542, 3753835.7073974125, + 19.38, -2000218.796953924, -4743560.190452792, 3753835.3253990356, + 19.39, -2000217.4394490635, -4743561.068816411, 3753834.941391838, + 19.400000000000002, -2000216.0825018599, -4743561.948533413, 3753834.5553897955, + 19.41, -2000214.7260763887, -4743562.829607802, 3753834.167406882, + 19.42, -2000213.3701367266, -4743563.712043592, 3753833.7774570757, + 19.43, -2000212.0146469495, -4743564.595844789, 3753833.38555435, + 19.44, -2000210.6595711338, -4743565.481015405, 3753832.9917126815, + 19.45, -2000209.3048733552, -4743566.367559446, 3753832.5959460447, + 19.46, -2000207.95051769, -4743567.255480924, 3753832.198268417, + 19.47, -2000206.5964682135, -4743568.144783848, 3753831.798693772, + 19.48, -2000205.2426890035, -4743569.035472226, 3753831.397236086, + 19.490000000000002, -2000203.8891441347, -4743569.927550067, 3753830.993909335, + 19.5, -2000202.535797684, -4743570.821021385, 3753830.5887274947, + 19.51, -2000201.182613727, -4743571.715890181, 3753830.18170454, + 19.52, -2000199.82955634, -4743572.612160473, 3753829.772854446, + 19.53, -2000198.476589599, -4743573.509836264, 3753829.3621911886, + 19.54, -2000197.1236775804, -4743574.408921567, 3753828.9497287455, + 19.55, -2000195.7707843601, -4743575.309420389, 3753828.535481088, + 19.56, -2000194.417874015, -4743576.211336741, 3753828.1194621953, + 19.57, -2000193.0649106193, -4743577.1146746315, 3753827.7016860414, + 19.580000000000002, -2000191.711858251, -4743578.019438069, 3753827.2821666026, + 19.59, -2000190.3586809856, -4743578.925631064, 3753826.860917853, + 19.6, -2000189.005342899, -4743579.833257626, 3753826.43795377, + 19.61, -2000187.651808067, -4743580.742321763, 3753826.013288328, + 19.62, -2000186.2980405665, -4743581.652827486, 3753825.586935503, + 19.63, -2000184.9440044735, -4743582.564778803, 3753825.1589092705, + 19.64, -2000183.5896638632, -4743583.478179723, 3753824.7292236052, + 19.650000000000002, -2000182.2349828132, -4743584.393034257, 3753824.2978924853, + 19.66, -2000180.8799253982, -4743585.309346411, 3753823.864929883, + 19.67, -2000179.524455695, -4743586.2271202, 3753823.430349775, + 19.68, -2000178.16853778, -4743587.146359628, 3753822.9941661386, + 19.69, -2000176.8121357283, -4743588.067068706, 3753822.5563929463, + 19.7, -2000175.4552136175, -4743588.989251444, 3753822.117044176, + 19.71, -2000174.097735522, -4743589.912911851, 3753821.6761338026, + 19.72, -2000172.739665519, -4743590.838053936, 3753821.2336758017, + 19.73, -2000171.380967685, -4743591.764681708, 3753820.789684149, + 19.740000000000002, -2000170.0216060951, -4743592.692799177, 3753820.3441728195, + 19.75, -2000168.6615448259, -4743593.622410353, 3753819.8971557897, + 19.76, -2000167.3007479531, -4743594.553519243, 3753819.4486470325, + 19.77, -2000165.9391795534, -4743595.486129859, 3753818.998660528, + 19.78, -2000164.5768037026, -4743596.420246209, 3753818.547210248, + 19.79, -2000163.213584477, -4743597.3558723, 3753818.094310169, + 19.8, -2000161.8494859524, -4743598.293012145, 3753817.639974267, + 19.81, -2000160.4844722054, -4743599.231669752, 3753817.184216518, + 19.82, -2000159.1185073117, -4743600.171849132, 3753816.7270508963, + 19.830000000000002, -2000157.7515553478, -4743601.11355429, 3753816.268491379, + 19.84, -2000156.383580389, -4743602.056789239, 3753815.8085519397, + 19.85, -2000155.0145465117, -4743603.001557986, 3753815.347246555, + 19.86, -2000153.6444177926, -4743603.947864542, 3753814.884589201, + 19.87, -2000152.273158308, -4743604.895712916, 3753814.420593852, + 19.88, -2000150.900732133, -4743605.845107116, 3753813.955274486, + 19.89, -2000149.5271033447, -4743606.796051154, 3753813.4886450754, + 19.900000000000002, -2000148.1522360183, -4743607.748549037, 3753813.0207195976, + 19.91, -2000146.77609423, -4743608.702604773, 3753812.5515120267, + 19.92, -2000145.398642057, -4743609.658222376, 3753812.0810363404, + 19.93, -2000144.0198435744, -4743610.615405853, 3753811.609306514, + 19.94, -2000142.639662858, -4743611.5741592115, 3753811.1363365212, + 19.95, -2000141.258063985, -4743612.534486461, 3753810.6621403378, + 19.96, -2000139.875011031, -4743613.496391613, 3753810.1867319406, + 19.97, -2000138.4904680715, -4743614.459878676, 3753809.7101253048, + 19.98, -2000137.104399184, -4743615.42495166, 3753809.232334406, + 19.990000000000002, -2000135.716768444, -4743616.391614572, 3753808.753373219, + 20, -2000134.327539927, -4743617.359871424, 3753808.2732557207, + 20.01, -2000132.9366777092, -4743618.329726223, 3753807.7919958853, + 20.02, -2000131.5441458682, -4743619.30118298, 3753807.3096076897, + 20.03, -2000130.1499084777, -4743620.274245704, 3753806.8261051085, + 20.04, -2000128.7539296157, -4743621.248918402, 3753806.3415021165, + 20.05, -2000127.3561733582, -4743622.225205086, 3753805.8558126907, + 20.06, -2000125.95660378, -4743623.203109765, 3753805.369050806, + 20.07, -2000124.5551849578, -4743624.182636448, 3753804.881230438, + 20.080000000000002, -2000123.1518809693, -4743625.163789146, 3753804.392365563, + 20.09, -2000121.7466558877, -4743626.1465718625, 3753803.902470155, + 20.1, -2000120.339473792, -4743627.130988614, 3753803.4115581918, + 20.11, -2000118.9302987563, -4743628.117043405, 3753802.919643647, + 20.12, -2000117.5190948576, -4743629.104740247, 3753802.426740497, + 20.13, -2000116.105826172, -4743630.094083148, 3753801.932862716, + 20.14, -2000114.690456775, -4743631.085076119, 3753801.438024282, + 20.150000000000002, -2000113.2729507438, -4743632.077723168, 3753800.942239169, + 20.16, -2000111.8532721533, -4743633.072028304, 3753800.445521352, + 20.17, -2000110.4313850803, -4743634.067995538, 3753799.9478848083, + 20.18, -2000109.0072536003, -4743635.065628877, 3753799.4493435114, + 20.19, -2000107.5808417904, -4743636.064932331, 3753798.949911438, + 20.2, -2000106.1521137264, -4743637.065909913, 3753798.449602565, + 20.21, -2000104.7210334842, -4743638.068565626, 3753797.9484308655, + 20.22, -2000103.2875651398, -4743639.072903484, 3753797.4464103165, + 20.23, -2000101.8516727688, -4743640.078927494, 3753796.943554892, + 20.240000000000002, -2000100.4133204487, -4743641.0866416665, 3753796.439878571, + 20.25, -2000098.9724722551, -4743642.096050011, 3753795.9353953255, + 20.26, -2000097.5290922634, -4743643.107156536, 3753795.430119132, + 20.27, -2000096.0831445502, -4743644.11996525, 3753794.9240639666, + 20.28, -2000094.634593192, -4743645.134480164, 3753794.417243805, + 20.29, -2000093.1834022638, -4743646.150705285, 3753793.9096726216, + 20.3, -2000091.7295358435, -4743647.168644626, 3753793.401364393, + 20.31, -2000090.2729580055, -4743648.188302193, 3753792.892333096, + 20.32, -2000088.8136328268, -4743649.209681998, 3753792.382592703, + 20.330000000000002, -2000087.351524383, -4743650.232788048, 3753791.872157192, + 20.34, -2000085.8865967507, -4743651.257624352, 3753791.361040537, + 20.35, -2000084.4188140056, -4743652.284194922, 3753790.8492567153, + 20.36, -2000082.948140224, -4743653.312503766, 3753790.3368197004, + 20.37, -2000081.474539482, -4743654.342554892, 3753789.82374347, + 20.38, -2000079.9979758565, -4743655.374352311, 3753789.310041998, + 20.39, -2000078.5184134224, -4743656.407900031, 3753788.7957292604, + 20.400000000000002, -2000077.035816256, -4743657.4432020625, 3753788.2808192335, + 20.41, -2000075.550148434, -4743658.480262414, 3753787.7653258913, + 20.42, -2000074.061374032, -4743659.519085095, 3753787.2492632116, + 20.43, -2000072.5694571263, -4743660.559674115, 3753786.7326451675, + 20.44, -2000071.0743617928, -4743661.602033484, 3753786.215485736, + 20.45, -2000069.5760521078, -4743662.646167209, 3753785.6977988924, + 20.46, -2000068.0744921486, -4743663.692079302, 3753785.1795986127, + 20.47, -2000066.5696459892, -4743664.73977377, 3753784.6608988717, + 20.48, -2000065.0614777065, -4743665.789254625, 3753784.1417136444, + 20.490000000000002, -2000063.5499513776, -4743666.840525874, 3753783.6220569084, + 20.5, -2000062.035031077, -4743667.893591527, 3753783.1019426375, + 20.51, -2000060.5166808823, -4743668.948455594, 3753782.581384808, + 20.52, -2000058.9948648687, -4743670.005122082, 3753782.0603973954, + 20.53, -2000057.469547112, -4743671.063595002, 3753781.5389943738, + 20.54, -2000055.9406916893, -4743672.123878365, 3753781.017189721, + 20.55, -2000054.4082626766, -4743673.185976177, 3753780.4949974115, + 20.56, -2000052.8722241493, -4743674.24989245, 3753779.972431421, + 20.57, -2000051.3325401838, -4743675.315631192, 3753779.4495057254, + 20.580000000000002, -2000049.7891748562, -4743676.383196412, 3753778.9262342993, + 20.59, -2000048.2420922434, -4743677.4525921205, 3753778.4026311203, + 20.6, -2000046.6912564202, -4743678.523822326, 3753777.8787101605, + 20.61, -2000045.136631464, -4743679.596891038, 3753777.354485398, + 20.62, -2000043.5781814493, -4743680.671802265, 3753776.8299708087, + 20.63, -2000042.015870454, -4743681.748560018, 3753776.305180366, + 20.64, -2000040.449662553, -4743682.8271683045, 3753775.780128047, + 20.650000000000002, -2000038.8795218233, -4743683.907631136, 3753775.254827828, + 20.66, -2000037.3054123397, -4743684.989952518, 3753774.729293682, + 20.67, -2000035.7272981796, -4743686.074136463, 3753774.203539587, + 20.68, -2000034.1451434186, -4743687.160186981, 3753773.677579517, + 20.69, -2000032.5589121324, -4743688.248108079, 3753773.1514274483, + 20.7, -2000030.9685683982, -4743689.337903766, 3753772.6250973567, + 20.71, -2000029.3740762922, -4743690.429578056, 3753772.0986032183, + 20.72, -2000027.7753998886, -4743691.5231349515, 3753771.571959006, + 20.73, -2000026.1725032646, -4743692.618578466, 3753771.0451786974, + 20.740000000000002, -2000024.565350497, -4743693.715912607, 3753770.518276268, + 20.75, -2000022.953905661, -4743694.815141385, 3753769.991265693, + 20.76, -2000021.3381328334, -4743695.916268812, 3753769.464160949, + 20.77, -2000019.7180074397, -4743697.019296763, 3753768.9369726786, + 20.78, -2000018.0956883358, -4743698.123818795, 3753768.409069499, + 20.79, -2000016.4727928457, -4743699.229533625, 3753767.8799743624, + 20.8, -2000014.8493070295, -4743700.336446589, 3753767.3496879246, + 20.81, -2000013.2252169454, -4743701.444563032, 3753766.818210838, + 20.82, -2000011.6005086545, -4743702.553888294, 3753766.285543757, + 20.830000000000002, -2000009.9751682165, -4743703.66442772, 3753765.751687338, + 20.84, -2000008.3491816905, -4743704.776186648, 3753765.216642234, + 20.85, -2000006.7225351364, -4743705.889170422, 3753764.6804090985, + 20.86, -2000005.0952146144, -4743707.003384384, 3753764.1429885854, + 20.87, -2000003.4672061838, -4743708.118833875, 3753763.604381351, + 20.88, -2000001.838495905, -4743709.235524237, 3753763.0645880476, + 20.89, -2000000.2090698364, -4743710.353460811, 3753762.5236093304, + 20.900000000000002, -1999998.5789140395, -4743711.47264894, 3753761.981445853, + 20.91, -1999996.948014573, -4743712.593093964, 3753761.43809827, + 20.92, -1999995.3163574967, -4743713.714801228, 3753760.893567236, + 20.93, -1999993.6839288706, -4743714.8377760695, 3753760.347853404, + 20.94, -1999992.0507147545, -4743715.962023834, 3753759.800957429, + 20.95, -1999990.4167012072, -4743717.08754986, 3753759.2528799656, + 20.96, -1999988.7818742904, -4743718.214359493, 3753758.7036216687, + 20.97, -1999987.1462200624, -4743719.342458072, 3753758.1531831897, + 20.98, -1999985.5097245832, -4743720.47185094, 3753757.601565185, + 20.990000000000002, -1999983.8723739127, -4743721.602543439, 3753757.0487683085, + 21, -1999982.2341541105, -4743722.734540908, 3753756.4947932134, + 21.01, -1999980.5950512362, -4743723.867848692, 3753755.939640556, + 21.02, -1999978.9550513502, -4743725.002472132, 3753755.383310989, + 21.03, -1999977.314140512, -4743726.138416571, 3753754.8258051663, + 21.04, -1999975.6723047805, -4743727.275687346, 3753754.267123743, + 21.05, -1999974.029530217, -4743728.414289804, 3753753.7072673733, + 21.06, -1999972.38580288, -4743729.554229286, 3753753.146236711, + 21.07, -1999970.7411088299, -4743730.69551113, 3753752.5840324103, + 21.080000000000002, -1999969.095434126, -4743731.838140681, 3753752.020655126, + 21.09, -1999967.4487648283, -4743732.982123281, 3753751.4561055116, + 21.1, -1999965.8010869962, -4743734.127464271, 3753750.890384222, + 21.11, -1999964.1523866905, -4743735.274168992, 3753750.32349191, + 21.12, -1999962.50264997, -4743736.422242788, 3753749.755429232, + 21.13, -1999960.8518628946, -4743737.571690997, 3753749.1861968404, + 21.14, -1999959.2000115244, -4743738.722518964, 3753748.61579539, + 21.150000000000002, -1999957.5470819187, -4743739.87473203, 3753748.044225536, + 21.16, -1999955.8930601375, -4743741.028335536, 3753747.4714879305, + 21.17, -1999954.2379322406, -4743742.183334825, 3753746.89758323, + 21.18, -1999952.5816842879, -4743743.339735238, 3753746.3225120874, + 21.19, -1999950.9243023384, -4743744.497542116, 3753745.7462751563, + 21.2, -1999949.2657724526, -4743745.6567608025, 3753745.1688730926, + 21.21, -1999947.6060806906, -4743746.817396639, 3753744.59030655, + 21.22, -1999945.945213111, -4743747.979454965, 3753744.010576181, + 21.23, -1999944.2831557742, -4743749.142941125, 3753743.4296826427, + 21.240000000000002, -1999942.61989474, -4743750.30786046, 3753742.847626587, + 21.25, -1999940.9554160682, -4743751.474218312, 3753742.264408669, + 21.26, -1999939.289705818, -4743752.642020021, 3753741.680029543, + 21.27, -1999937.62275005, -4743753.811270932, 3753741.0944898636, + 21.28, -1999935.9545348233, -4743754.981976384, 3753740.507790284, + 21.29, -1999934.285046198, -4743756.154141719, 3753739.9199314592, + 21.3, -1999932.614270234, -4743757.327772279, 3753739.3309140424, + 21.31, -1999930.9421929903, -4743758.502873408, 3753738.740738689, + 21.32, -1999929.2688005273, -4743759.679450445, 3753738.149406053, + 21.330000000000002, -1999927.5940789047, -4743760.857508732, 3753737.5569167878, + 21.34, -1999925.918014182, -4743762.037053612, 3753736.963271549, + 21.35, -1999924.2405924194, -4743763.218090427, 3753736.3684709896, + 21.36, -1999922.561799676, -4743764.400624518, 3753735.7725157635, + 21.37, -1999920.8816220122, -4743765.584661228, 3753735.175406527, + 21.38, -1999919.2000454878, -4743766.7702058945, 3753734.577143932, + 21.39, -1999917.5170561618, -4743767.9572638655, 3753733.977728634, + 21.400000000000002, -1999915.8326400942, -4743769.145840478, 3753733.377161287, + 21.41, -1999914.1467833451, -4743770.335941076, 3753732.775442545, + 21.42, -1999912.4594719743, -4743771.527571, 3753732.1725730626, + 21.43, -1999910.7706920411, -4743772.720735594, 3753731.568553493, + 21.44, -1999909.0804296054, -4743773.915440197, 3753730.9633844914, + 21.45, -1999907.3886707276, -4743775.111690153, 3753730.357066712, + 21.46, -1999905.6954014667, -4743776.309490802, 3753729.7496008086, + 21.47, -1999904.0006078826, -4743777.508847486, 3753729.1409874363, + 21.48, -1999902.3042760352, -4743778.70976555, 3753728.5312272473, + 21.490000000000002, -1999900.6063919843, -4743779.912250331, 3753727.920320898, + 21.5, -1999898.9069417892, -4743781.116307175, 3753727.308269042, + 21.51, -1999897.20591151, -4743782.3219414195, 3753726.6950723324, + 21.52, -1999895.5032872066, -4743783.529158409, 3753726.080731425, + 21.53, -1999893.7990549384, -4743784.737963484, 3753725.465246973, + 21.54, -1999892.0932007656, -4743785.94836199, 3753724.848619631, + 21.55, -1999890.385710748, -4743787.160359263, 3753724.230850053, + 21.56, -1999888.6765709447, -4743788.373960649, 3753723.611938894, + 21.57, -1999886.9657674157, -4743789.589171489, 3753722.991886807, + 21.580000000000002, -1999885.253286221, -4743790.805997123, 3753722.3706944464, + 21.59, -1999883.5391134203, -4743792.024442894, 3753721.748362467, + 21.6, -1999881.8232350731, -4743793.244514144, 3753721.1248915223, + 21.61, -1999880.1056372393, -4743794.466216213, 3753720.500282268, + 21.62, -1999878.3863059788, -4743795.689554446, 3753719.8745353566, + 21.63, -1999876.6652273515, -4743796.914534183, 3753719.247651444, + 21.64, -1999874.942387417, -4743798.141160765, 3753718.619631183, + 21.650000000000002, -1999873.2177722347, -4743799.369439536, 3753717.9904752285, + 21.66, -1999871.4913678644, -4743800.599375835, 3753717.360184234, + 21.67, -1999869.7631603659, -4743801.830975005, 3753716.7287588543, + 21.68, -1999868.0331357995, -4743803.064242389, 3753716.0961997434, + 21.69, -1999866.3012802247, -4743804.299183327, 3753715.462507556, + 21.7, -1999864.5675797008, -4743805.535803162, 3753714.8276829463, + 21.71, -1999862.8320202883, -4743806.7741072355, 3753714.191726567, + 21.72, -1999861.0945880462, -4743808.014100887, 3753713.554639075, + 21.73, -1999859.3552690344, -4743809.2557894625, 3753712.916421122, + 21.740000000000002, -1999857.6140493131, -4743810.499178301, 3753712.2770733633, + 21.75, -1999855.870914942, -4743811.744272743, 3753711.6365964524, + 21.76, -1999854.1258519806, -4743812.9910781365, 3753710.9949910454, + 21.77, -1999852.3788464884, -4743814.239599816, 3753710.3522577956, + 21.78, -1999850.629884526, -4743815.489843125, 3753709.708397355, + 21.79, -1999848.878952152, -4743816.741813408, 3753709.0634103813, + 21.8, -1999847.1260354272, -4743817.995516005, 3753708.4172975263, + 21.81, -1999845.371120411, -4743819.250956259, 3753707.770059446, + 21.82, -1999843.614193163, -4743820.50813951, 3753707.1216967925, + 21.830000000000002, -1999841.8552397427, -4743821.7670711, 3753706.472210222, + 21.84, -1999840.0942462103, -4743823.027756372, 3753705.8216003873, + 21.85, -1999838.3311986257, -4743824.290200667, 3753705.169867943, + 21.86, -1999836.5660830482, -4743825.554409327, 3753704.517013544, + 21.87, -1999834.798885538, -4743826.820387693, 3753703.8630378447, + 21.88, -1999833.029592155, -4743828.088141108, 3753703.2079414977, + 21.89, -1999831.258188958, -4743829.3576749135, 3753702.551725159, + 21.900000000000002, -1999829.484662007, -4743830.62899445, 3753701.894389481, + 21.91, -1999827.7089973628, -4743831.902105061, 3753701.2359351194, + 21.92, -1999825.931181084, -4743833.177012088, 3753700.5763627263, + 21.93, -1999824.1511992305, -4743834.453720872, 3753699.91567296, + 21.94, -1999822.3690378629, -4743835.732236755, 3753699.2538664714, + 21.95, -1999820.5846830402, -4743837.012565078, 3753698.5909439153, + 21.96, -1999818.7981208228, -4743838.294711185, 3753697.9269059463, + 21.97, -1999817.0093372697, -4743839.578680416, 3753697.2617532187, + 21.98, -1999815.2183184405, -4743840.864478112, 3753696.595486386, + 21.990000000000002, -1999813.4250503955, -4743842.152109617, 3753695.928106103, + 22, -1999811.629519195, -4743843.441580272, 3753695.2596130245, + 22.01, -1999809.8317108976, -4743844.732895419, 3753694.590007803, + 22.02, -1999808.0316115639, -4743846.026060399, 3753693.9192910944, + 22.03, -1999806.2292072529, -4743847.321080553, 3753693.2474635527, + 22.04, -1999804.4244840257, -4743848.617961226, 3753692.5745258313, + 22.05, -1999802.6174279405, -4743849.916707755, 3753691.9004785847, + 22.06, -1999800.8080250574, -4743851.217325485, 3753691.225322467, + 22.07, -1999798.9962614372, -4743852.519819759, 3753690.5490581333, + 22.080000000000002, -1999797.182123138, -4743853.824195915, 3753689.871686237, + 22.09, -1999795.365596221, -4743855.130459297, 3753689.193207432, + 22.1, -1999793.5466667456, -4743856.438615247, 3753688.513622373, + 22.11, -1999791.7253207709, -4743857.7486691065, 3753687.832931714, + 22.12, -1999789.9015443576, -4743859.060626217, 3753687.15113611, + 22.13, -1999788.075323565, -4743860.374491921, 3753686.468236215, + 22.14, -1999786.2466444522, -4743861.690271557, 3753685.784232682, + 22.150000000000002, -1999784.4154930806, -4743863.007970473, 3753685.0991261667, + 22.16, -1999782.5818555085, -4743864.3275940055, 3753684.412917323, + 22.17, -1999780.7457177956, -4743865.6491474975, 3753683.725606804, + 22.18, -1999778.9070660025, -4743866.972636292, 3753683.0371952644, + 22.19, -1999777.0658861888, -4743868.298065729, 3753682.3476833594, + 22.2, -1999775.2221644137, -4743869.625441152, 3753681.657071742, + 22.21, -1999773.3758867374, -4743870.954767901, 3753680.965361067, + 22.22, -1999771.5270392203, -4743872.286051322, 3753680.27255199, + 22.23, -1999769.6756079209, -4743873.619296749, 3753679.5786451623, + 22.240000000000002, -1999767.8215788992, -4743874.95450953, 3753678.8836412397, + 22.25, -1999765.9649382154, -4743876.291695007, 3753678.187540877, + 22.26, -1999764.105671929, -4743877.630858519, 3753677.490344727, + 22.27, -1999762.2437661006, -4743878.972005409, 3753676.792053446, + 22.28, -1999760.3792067883, -4743880.315141018, 3753676.092667686, + 22.29, -1999758.5119800533, -4743881.660270688, 3753675.392188102, + 22.3, -1999756.6420719547, -4743883.007399761, 3753674.6906153485, + 22.31, -1999754.769468552, -4743884.3565335795, 3753673.987950079, + 22.32, -1999752.8941559056, -4743885.707677483, 3753673.2841929477, + 22.330000000000002, -1999751.0161200755, -4743887.060836818, 3753672.5793446116, + 22.34, -1999749.13534712, -4743888.41601692, 3753671.873405721, + 22.35, -1999747.2518231005, -4743889.773223136, 3753671.1663769325, + 22.36, -1999745.365534076, -4743891.132460805, 3753670.4582589, + 22.37, -1999743.476466106, -4743892.493735269, 3753669.7490522764, + 22.38, -1999741.5846052505, -4743893.857051869, 3753669.038757717, + 22.39, -1999739.6899375694, -4743895.22241595, 3753668.327375876, + 22.400000000000002, -1999737.7924491223, -4743896.589832851, 3753667.6149074063, + 22.41, -1999735.8921259693, -4743897.959307916, 3753666.901352965, + 22.42, -1999733.9889541694, -4743899.330846484, 3753666.1867132033, + 22.43, -1999732.0829197832, -4743900.704453898, 3753665.470988778, + 22.44, -1999730.1740088698, -4743902.080135498, 3753664.75418034, + 22.45, -1999728.26220749, -4743903.457896631, 3753664.036288548, + 22.46, -1999726.3475017024, -4743904.837742635, 3753663.3173140525, + 22.47, -1999724.4298775669, -4743906.219678851, 3753662.597257509, + 22.48, -1999722.5093211434, -4743907.6037106225, 3753661.8761195717, + 22.490000000000002, -1999720.5858184923, -4743908.989843292, 3753661.1539008957, + 22.5, -1999718.6593556716, -4743910.378082198, 3753660.4306021333, + 22.51, -1999716.7299187437, -4743911.768432686, 3753659.70622394, + 22.52, -1999714.7974937663, -4743913.1609000955, 3753658.9807669697, + 22.53, -1999712.8620667993, -4743914.555489767, 3753658.2542318758, + 22.54, -1999710.9236239034, -4743915.952207047, 3753657.526619315, + 22.55, -1999708.9821511386, -4743917.351057272, 3753656.7979299393, + 22.56, -1999707.037634563, -4743918.752045789, 3753656.068164403, + 22.57, -1999705.0900602378, -4743920.155177935, 3753655.337323362, + 22.580000000000002, -1999703.1394142222, -4743921.560459055, 3753654.6054074685, + 22.59, -1999701.185682576, -4743922.967894489, 3753653.872417378, + 22.6, -1999699.2288513584, -4743924.377489579, 3753653.1383537436, + 22.61, -1999697.2689066299, -4743925.789249667, 3753652.403217221, + 22.62, -1999695.3058344498, -4743927.203180094, 3753651.6670084624, + 22.63, -1999693.3396208794, -4743928.619286205, 3753650.9297281243, + 22.64, -1999691.370251976, -4743930.037573338, 3753650.1913768593, + 22.650000000000002, -1999689.3977138011, -4743931.458046836, 3753649.4519553226, + 22.66, -1999687.4219924137, -4743932.880712041, 3753648.711464167, + 22.67, -1999685.4430738734, -4743934.305574294, 3753647.969904049, + 22.68, -1999683.460944241, -4743935.732638939, 3753647.2272756216, + 22.69, -1999681.475589575, -4743937.161911316, 3753646.4835795374, + 22.7, -1999679.4869959361, -4743938.593396767, 3753645.738816454, + 22.71, -1999677.4951493838, -4743940.027100634, 3753644.9929870227, + 22.72, -1999675.500035977, -4743941.463028259, 3753644.2460918985, + 22.73, -1999673.5016417764, -4743942.901184982, 3753643.4981317357, + 22.740000000000002, -1999671.4999528418, -4743944.341576148, 3753642.74910719, + 22.75, -1999669.4949552328, -4743945.784207094, 3753641.9990189136, + 22.76, -1999667.4866350088, -4743947.229083167, 3753641.247867562, + 22.77, -1999665.4749782293, -4743948.676209707, 3753640.495653787, + 22.78, -1999663.4599709555, -4743950.125592055, 3753639.7423782465, + 22.79, -1999661.4415992452, -4743951.577235552, 3753638.988041592, + 22.8, -1999659.4198491601, -4743953.03114554, 3753638.2326444793, + 22.81, -1999657.3947067584, -4743954.487327362, 3753637.4761875607, + 22.82, -1999655.3661581005, -4743955.945786362, 3753636.7186714928, + 22.830000000000002, -1999653.3341892462, -4743957.406527877, 3753635.960096928, + 22.84, -1999651.2987862553, -4743958.869557252, 3753635.2004645215, + 22.85, -1999649.259935187, -4743960.334879826, 3753634.4397749268, + 22.86, -1999647.2176221025, -4743961.802500945, 3753633.6780288, + 22.87, -1999645.1718330598, -4743963.272425947, 3753632.9152267925, + 22.88, -1999643.1225541192, -4743964.744660173, 3753632.1513695586, + 22.89, -1999641.069771341, -4743966.21920897, 3753631.386457756, + 22.900000000000002, -1999639.0134707852, -4743967.6960776765, 3753630.6204920365, + 22.91, -1999636.9536385098, -4743969.175271632, 3753629.8534730533, + 22.92, -1999634.8902605758, -4743970.656796182, 3753629.085401462, + 22.93, -1999632.8233230435, -4743972.140656666, 3753628.3162779165, + 22.94, -1999630.7528119716, -4743973.626858426, 3753627.5461030705, + 22.95, -1999628.6787134204, -4743975.1154068075, 3753626.774877581, + 22.96, -1999626.6010134502, -4743976.606307147, 3753626.0026020985, + 22.97, -1999624.5196981188, -4743978.099564788, 3753625.2292772783, + 22.98, -1999622.4347534883, -4743979.595185075, 3753624.4549037763, + 22.990000000000002, -1999620.346165617, -4743981.093173347, 3753623.6794822454, + 23, -1999618.253920565, -4743982.593534945, 3753622.9030133393, + 23.01, -1999616.1580043924, -4743984.096275215, 3753622.125497714, + 23.02, -1999614.0584031588, -4743985.601399494, 3753621.3469360215, + 23.03, -1999611.9551029229, -4743987.108913125, 3753620.567328917, + 23.04, -1999609.8480897455, -4743988.61882145, 3753619.7866770537, + 23.05, -1999607.7373496876, -4743990.131129814, 3753619.00498109, + 23.06, -1999605.6228688064, -4743991.645843553, 3753618.222241675, + 23.07, -1999603.5046331626, -4743993.1629680125, 3753617.438459464, + 23.080000000000002, -1999601.3825793418, -4743994.682725542, 3753616.653388917, + 23.09, -1999599.2559600156, -4743996.2083701035, 3753615.8633412733, + 23.1, -1999597.124548982, -4743997.740940886, 3753615.067131906, + 23.11, -1999594.988373824, -4743999.280372861, 3753614.26482786, + 23.12, -1999592.8474621237, -4744000.826600997, 3753613.4564961824, + 23.13, -1999590.7018414652, -4744002.379560261, 3753612.642203919, + 23.14, -1999588.5515394295, -4744003.939185622, 3753611.8220181162, + 23.150000000000002, -1999586.3965836, -4744005.50541205, 3753610.9960058196, + 23.16, -1999584.23700156, -4744007.078174513, 3753610.164234075, + 23.17, -1999582.0728208916, -4744008.657407979, 3753609.3267699294, + 23.18, -1999579.9040691778, -4744010.243047416, 3753608.4836804275, + 23.19, -1999577.7307740015, -4744011.835027795, 3753607.6350326166, + 23.2, -1999575.5529629453, -4744013.433284084, 3753606.780893542, + 23.21, -1999573.3706635924, -4744015.037751251, 3753605.92133025, + 23.22, -1999571.1839035242, -4744016.6483642645, 3753605.0564097855, + 23.23, -1999568.9927103247, -4744018.265058094, 3753604.186199196, + 23.240000000000002, -1999566.7971115767, -4744019.887767708, 3753603.3107655277, + 23.25, -1999564.597134862, -4744021.516428074, 3753602.4301758255, + 23.26, -1999562.392807764, -4744023.150974162, 3753601.5444971365, + 23.27, -1999560.1841578658, -4744024.791340941, 3753600.6537965056, + 23.28, -1999557.9712127494, -4744026.437463377, 3753599.7581409793, + 23.29, -1999555.7539999976, -4744028.089276441, 3753598.8575976044, + 23.3, -1999553.532547194, -4744029.746715101, 3753597.952233426, + 23.31, -1999551.3068819207, -4744031.409714328, 3753597.0421154904, + 23.32, -1999549.0770317605, -4744033.078209087, 3753596.1273108427, + 23.330000000000002, -1999546.8430242958, -4744034.752134348, 3753595.207886531, + 23.34, -1999544.6048871097, -4744036.431425082, 3753594.2839095998, + 23.35, -1999542.3626477856, -4744038.116016254, 3753593.355447096, + 23.36, -1999540.1163339051, -4744039.805842834, 3753592.422566065, + 23.37, -1999537.8659730516, -4744041.50083979, 3753591.485333553, + 23.38, -1999535.6115928083, -4744043.2009420935, 3753590.543816606, + 23.39, -1999533.353220757, -4744044.906084711, 3753589.5980822695, + 23.400000000000002, -1999531.0908844809, -4744046.61620261, 3753588.648197591, + 23.41, -1999528.8246115623, -4744048.331230762, 3753587.694229616, + 23.42, -1999526.5544295849, -4744050.051104135, 3753586.736245389, + 23.43, -1999524.2803661304, -4744051.775757696, 3753585.774311958, + 23.44, -1999522.002448782, -4744053.505126413, 3753584.808496368, + 23.45, -1999519.720705123, -4744055.239145258, 3753583.838865665, + 23.46, -1999517.435162736, -4744056.977749199, 3753582.865486896, + 23.47, -1999515.1458492028, -4744058.720873201, 3753581.8884271057, + 23.48, -1999512.8527921068, -4744060.468452238, 3753580.9077533414, + 23.490000000000002, -1999510.556019031, -4744062.220421274, 3753579.923532649, + 23.5, -1999508.2555575576, -4744063.976715282, 3753578.935832073, + 23.51, -1999505.9514352693, -4744065.7372692255, 3753577.944718661, + 23.52, -1999503.6436797495, -4744067.502018077, 3753576.950259458, + 23.53, -1999501.3323185807, -4744069.270896805, 3753575.952521511, + 23.54, -1999499.0173793456, -4744071.043840378, 3753574.9515718655, + 23.55, -1999496.6988896271, -4744072.820783761, 3753573.9474775675, + 23.56, -1999494.3768770078, -4744074.601661928, 3753572.9403056637, + 23.57, -1999492.05136907, -4744076.386409845, 3753571.9301231992, + 23.580000000000002, -1999489.722393397, -4744078.174962482, 3753570.916997221, + 23.59, -1999487.3899775718, -4744079.967254804, 3753569.900994774, + 23.6, -1999485.0541491765, -4744081.763221785, 3753568.8821829045, + 23.61, -1999482.7149357938, -4744083.562798388, 3753567.86062866, + 23.62, -1999480.3723650074, -4744085.365919588, 3753566.836399084, + 23.63, -1999478.0264643996, -4744087.17252035, 3753565.809561225, + 23.64, -1999475.6772615528, -4744088.982535642, 3753564.7801821274, + 23.650000000000002, -1999473.3247840498, -4744090.795900433, 3753563.748328837, + 23.66, -1999470.9690594734, -4744092.612549694, 3753562.7140684025, + 23.67, -1999468.6101154066, -4744094.432418392, 3753561.6774678673, + 23.68, -1999466.247979432, -4744096.255441495, 3753560.6385942777, + 23.69, -1999463.8826791323, -4744098.081553971, 3753559.5975146806, + 23.7, -1999461.5142420905, -4744099.910690793, 3753558.554296121, + 23.71, -1999459.1426958893, -4744101.742786924, 3753557.509005646, + 23.72, -1999456.7680681108, -4744103.577777337, 3753556.461710301, + 23.73, -1999454.390386339, -4744105.415596999, 3753555.412477133, + 23.740000000000002, -1999452.0096781554, -4744107.25618088, 3753554.3613731875, + 23.75, -1999449.6259711431, -4744109.099463945, 3753553.308465509, + 23.76, -1999447.2392928852, -4744110.945381166, 3753552.253821146, + 23.77, -1999444.8496709648, -4744112.793867512, 3753551.197507143, + 23.78, -1999442.4571329632, -4744114.644857949, 3753550.139590546, + 23.79, -1999440.0617064647, -4744116.498287447, 3753549.0801384016, + 23.8, -1999437.663419052, -4744118.354090976, 3753548.0192177566, + 23.81, -1999435.2622983062, -4744120.212203502, 3753546.9568956555, + 23.82, -1999432.8583718117, -4744122.072559996, 3753545.893239145, + 23.830000000000002, -1999430.4516671507, -4744123.935095425, 3753544.828315271, + 23.84, -1999428.0422119058, -4744125.79974476, 3753543.7621910796, + 23.85, -1999425.6300336597, -4744127.666442967, 3753542.694933617, + 23.86, -1999423.215159996, -4744129.535125017, 3753541.6266099294, + 23.87, -1999420.7976184965, -4744131.405725877, 3753540.5572870616, + 23.88, -1999418.3774367443, -4744133.278180514, 3753539.4870320614, + 23.89, -1999415.9546423217, -4744135.1524239015, 3753538.415911974, + 23.900000000000002, -1999413.5292628126, -4744137.028391005, 3753537.3439938454, + 23.91, -1999411.1013257983, -4744138.906016793, 3753536.2713447213, + 23.92, -1999408.6708588623, -4744140.785236236, 3753535.198031648, + 23.93, -1999406.2378895879, -4744142.6659843, 3753534.124121672, + 23.94, -1999403.802445557, -4744144.548195955, 3753533.0496818395, + 23.95, -1999401.3645543521, -4744146.431806171, 3753531.9747791947, + 23.96, -1999398.9242435577, -4744148.3167499155, 3753530.8994807857, + 23.97, -1999396.4815407544, -4744150.202962157, 3753529.823853658, + 23.98, -1999394.0364735262, -4744152.0903778635, 3753528.747964857, + 23.990000000000002, -1999391.5890694554, -4744153.978932006, 3753527.6718814294, + 24, -1999389.1393561247, -4744155.868559551, 3753526.5956704207, + 24.01, -1999386.687361117, -4744157.759195468, 3753525.5193988774, + 24.02, -1999384.2331120153, -4744159.650774726, 3753524.4431338455, + 24.03, -1999381.7766364026, -4744161.543232292, 3753523.3669423712, + 24.04, -1999379.3179618604, -4744163.4365031365, 3753522.2908914993, + 24.05, -1999376.8571159728, -4744165.330522228, 3753521.2150482773, + 24.060000000000002, -1999374.3941263221, -4744167.225224535, 3753520.1394797512, + 24.07, -1999371.9290204907, -4744169.120545024, 3753519.064252965, + 24.080000000000002, -1999369.4618260614, -4744171.016418668, 3753517.9894349677, + 24.09, -1999366.9925706177, -4744172.912780432, 3753516.9150928035, + 24.1, -1999364.521281741, -4744174.809565286, 3753515.8412935184, + 24.11, -1999362.0479870155, -4744176.7067082, 3753514.7681041593, + 24.12, -1999359.572714023, -4744178.604144138, 3753513.6955917715, + 24.13, -1999357.0954903474, -4744180.501808075, 3753512.6238234015, + 24.14, -1999354.6163435697, -4744182.399634976, 3753511.552866095, + 24.150000000000002, -1999352.1353012738, -4744184.297559809, 3753510.4827868985, + 24.16, -1999349.652391042, -4744186.195517545, 3753509.4136528573, + 24.17, -1999347.1676404576, -4744188.093443152, 3753508.3455310185, + 24.18, -1999344.6810771024, -4744189.991271596, 3753507.278488427, + 24.19, -1999342.192728561, -4744191.888937851, 3753506.21259213, + 24.2, -1999339.7026224146, -4744193.786376882, 3753505.1479091723, + 24.21, -1999337.210786246, -4744195.683523657, 3753504.0845066006, + 24.22, -1999334.7172476382, -4744197.580313146, 3753503.022451461, + 24.23, -1999332.2220341736, -4744199.476680318, 3753501.9618107993, + 24.240000000000002, -1999329.7251734363, -4744201.372560143, 3753500.902651662, + 24.25, -1999327.2266930072, -4744203.267887586, 3753499.8450410934, + 24.26, -1999324.7266204702, -4744205.162597618, 3753498.7890461423, + 24.27, -1999322.2249834079, -4744207.056625207, 3753497.734733852, + 24.28, -1999319.721809403, -4744208.949905323, 3753496.6821712707, + 24.29, -1999317.217126038, -4744210.842372933, 3753495.631425443, + 24.3, -1999314.7109608967, -4744212.733963007, 3753494.582563416, + 24.310000000000002, -1999312.2033415602, -4744214.6246105125, 3753493.5356522356, + 24.32, -1999309.6942956122, -4744216.514250418, 3753492.490758947, + 24.330000000000002, -1999307.1838506348, -4744218.402817694, 3753491.447950597, + 24.34, -1999304.672034212, -4744220.290247307, 3753490.4072942305, + 24.35, -1999302.1588739257, -4744222.176474228, 3753489.368856895, + 24.36, -1999299.6443973582, -4744224.061433423, 3753488.3327056356, + 24.37, -1999297.1286320938, -4744225.945059864, 3753487.2989074993, + 24.38, -1999294.611605714, -4744227.827288516, 3753486.2675295314, + 24.39, -1999292.0933458016, -4744229.70805435, 3753485.2386387773, + 24.400000000000002, -1999289.5738799395, -4744231.587292333, 3753484.2123022843, + 24.41, -1999287.0532357106, -4744233.464937436, 3753483.1885870984, + 24.42, -1999284.5314406974, -4744235.340924626, 3753482.167560264, + 24.43, -1999282.0085224828, -4744237.215188871, 3753481.149288829, + 24.44, -1999279.4845086501, -4744239.087665143, 3753480.133839838, + 24.45, -1999276.9594267819, -4744240.958288407, 3753479.121280339, + 24.46, -1999274.4333044603, -4744242.826993635, 3753478.1116773766, + 24.47, -1999271.906169268, -4744244.693715791, 3753477.1050979956, + 24.48, -1999269.3780487871, -4744246.558389846, 3753476.1016092435, + 24.490000000000002, -1999266.848970603, -4744248.420950772, 3753475.101278167, + 24.5, -1999264.3189622965, -4744250.281333533, 3753474.1041718116, + 24.51, -1999261.7880514502, -4744252.1394731, 3753473.110357223, + 24.52, -1999259.256265647, -4744253.995304441, 3753472.119901447, + 24.53, -1999256.7236324707, -4744255.848762525, 3753471.1328715305, + 24.54, -1999254.190179503, -4744257.69978232, 3753470.149334519, + 24.55, -1999251.6559343273, -4744259.548298795, 3753469.169357458, + 24.560000000000002, -1999249.120924526, -4744261.39424692, 3753468.1930073947, + 24.57, -1999246.5851776814, -4744263.237561661, 3753467.2203513742, + 24.580000000000002, -1999244.0487213766, -4744265.0781779885, 3753466.251456443, + 24.59, -1999241.511583195, -4744266.916030872, 3753465.2863896475, + 24.6, -1999238.9737907182, -4744268.751055276, 3753464.3252180316, + 24.61, -1999236.4353715302, -4744270.583186176, 3753463.3680086443, + 24.62, -1999233.8963532133, -4744272.4123585345, 3753462.4148285305, + 24.63, -1999231.3567633503, -4744274.238507322, 3753461.465744735, + 24.64, -1999228.8166295232, -4744276.06156751, 3753460.5208243066, + 24.650000000000002, -1999226.275979315, -4744277.881474063, 3753459.5801342884, + 24.66, -1999223.7348403088, -4744279.698161951, 3753458.643741727, + 24.67, -1999221.1932400875, -4744281.511566144, 3753457.7117136708, + 24.68, -1999218.6512062335, -4744283.321621611, 3753456.784117162, + 24.69, -1999216.10876633, -4744285.128263317, 3753455.86101925, + 24.7, -1999213.5659479592, -4744286.9314262355, 3753454.9424869795, + 24.71, -1999211.0227787045, -4744288.731045332, 3753454.0285873963, + 24.72, -1999208.479286148, -4744290.527055576, 3753453.119387548, + 24.73, -1999205.9354978728, -4744292.319391936, 3753452.2149544787, + 24.740000000000002, -1999203.3914414614, -4744294.107989382, 3753451.3153552343, + 24.75, -1999200.8471444966, -4744295.89278288, 3753450.420656862, + 24.76, -1999198.3026345617, -4744297.673707401, 3753449.530926408, + 24.77, -1999195.757939238, -4744299.450697913, 3753448.6462309165, + 24.78, -1999193.2130861108, -4744301.223689385, 3753447.766637437, + 24.79, -1999190.66810276, -4744302.992616784, 3753446.8922130116, + 24.8, -1999188.1230167712, -4744304.75741508, 3753446.02302469, + 24.810000000000002, -1999185.5778557241, -4744306.518019242, 3753445.1591395144, + 24.82, -1999183.0326472037, -4744308.274364239, 3753444.3006245336, + 24.830000000000002, -1999180.487418792, -4744310.026385038, 3753443.4475467927, + 24.84, -1999177.9421980716, -4744311.774016609, 3753442.5999733377, + 24.85, -1999175.3970126256, -4744313.51719392, 3753441.757971216, + 24.86, -1999172.8518900366, -4744315.255851939, 3753440.921607471, + 24.87, -1999170.3068578865, -4744316.989925637, 3753440.09094915, + 24.88, -1999167.7619437603, -4744318.71934998, 3753439.2660633, + 24.89, -1999165.2171752385, -4744320.444059939, 3753438.447016966, + 24.900000000000002, -1999162.672579905, -4744322.163990482, 3753437.6338771945, + 24.91, -1999160.1281853423, -4744323.879076576, 3753436.826711031, + 24.92, -1999157.5840191324, -4744325.589253192, 3753436.0255855215, + 24.93, -1999155.0401088593, -4744327.294455298, 3753435.2305677133, + 24.94, -1999152.496482105, -4744328.994617861, 3753434.4417246506, + 24.95, -1999149.9531664527, -4744330.689675852, 3753433.659123381, + 24.96, -1999147.4101894856, -4744332.379564237, 3753432.88283095, + 24.97, -1999144.8675787854, -4744334.064217988, 3753432.112914404, + 24.98, -1999142.3253619343, -4744335.743572071, 3753431.3494407865, + 24.990000000000002, -1999139.7835665166, -4744337.417561457, 3753430.5924771465, + 25, -1999137.2422201142, -4744339.086121111, 3753429.84209053, + 25.01, -1999134.7013503101, -4744340.749186006, 3753429.0983479815, + 25.02, -1999132.1609846875, -4744342.406691108, 3753428.3613165477, + 25.03, -1999129.621150828, -4744344.058571387, 3753427.6310632746, + 25.04, -1999127.081876315, -4744345.70476181, 3753426.9076552074, + 25.05, -1999124.5431887326, -4744347.345197348, 3753426.191159395, + 25.060000000000002, -1999122.0051156613, -4744348.979812967, 3753425.4816428805, + 25.07, -1999119.4676846848, -4744350.608543637, 3753424.7791727106, + 25.080000000000002, -1999116.9309233855, -4744352.231324328, 3753424.0838159313, + 25.09, -1999114.3948593468, -4744353.848090007, 3753423.395639589, + 25.1, -1999111.859520151, -4744355.45877564, 3753422.7147107297, + 25.11, -1999109.324933381, -4744357.063316202, 3753422.041096399, + 25.12, -1999106.7911266198, -4744358.661646658, 3753421.374863644, + 25.13, -1999104.2581274502, -4744360.2537019765, 3753420.7160795103, + 25.14, -1999101.725963454, -4744361.839417127, 3753420.064811043, + 25.150000000000002, -1999099.1946622147, -4744363.418727077, 3753419.421125289, + 25.16, -1999096.6642513154, -4744364.991566798, 3753418.7850892944, + 25.17, -1999094.1347583379, -4744366.557871255, 3753418.1567701045, + 25.18, -1999091.6062108662, -4744368.117575419, 3753417.536234768, + 25.19, -1999089.078636482, -4744369.670614257, 3753416.9235503264, + 25.2, -1999086.552062768, -4744371.216922741, 3753416.318783829, + 25.21, -1999084.0265173076, -4744372.756435836, 3753415.7220023195, + 25.22, -1999081.5020276827, -4744374.28908851, 3753415.133272846, + 25.23, -1999078.9786214777, -4744375.814815738, 3753414.552662456, + 25.240000000000002, -1999076.4563262737, -4744377.3335524835, 3753413.9802381913, + 25.25, -1999073.9351696535, -4744378.845233712, 3753413.4160670997, + 25.26, -1999071.4151792016, -4744380.349794403, 3753412.860216229, + 25.27, -1999068.8963824988, -4744381.847169513, 3753412.312752624, + 25.28, -1999066.3788071286, -4744383.337294018, 3753411.7737433296, + 25.29, -1999063.862480673, -4744384.8201028835, 3753411.243255392, + 25.3, -1999061.347430717, -4744386.295531081, 3753410.7213558597, + 25.310000000000002, -1999058.8336848416, -4744387.763513579, 3753410.2081117774, + 25.32, -1999056.3212706293, -4744389.223985341, 3753409.7035901896, + 25.330000000000002, -1999053.810215663, -4744390.676881342, 3753409.2078581434, + 25.34, -1999051.300547526, -4744392.122136547, 3753408.720982685, + 25.35, -1999048.7922938014, -4744393.559685928, 3753408.2430308624, + 25.36, -1999046.2854820709, -4744394.989464448, 3753407.774069717, + 25.37, -1999043.780139918, -4744396.411407082, 3753407.314166299, + 25.38, -1999041.2762949257, -4744397.825448796, 3753406.863387653, + 25.39, -1999038.7730570685, -4744399.232521531, 3753406.421034405, + 25.400000000000002, -1999036.265726805, -4744400.637723978, 3753405.983190532, + 25.41, -1999033.753683776, -4744402.041762884, 3753405.549296805, + 25.42, -1999031.2369827465, -4744403.444613973, 3753405.119354753, + 25.43, -1999028.7156784823, -4744404.84625297, 3753404.693365905, + 25.44, -1999026.1898257497, -4744406.246655599, 3753404.271331787, + 25.45, -1999023.6594793138, -4744407.645797585, 3753403.8532539313, + 25.46, -1999021.1246939404, -4744409.04365465, 3753403.4391338625, + 25.47, -1999018.585524395, -4744410.440202522, 3753403.028973112, + 25.48, -1999016.0420254434, -4744411.835416922, 3753402.6227732077, + 25.490000000000002, -1999013.4942518515, -4744413.229273576, 3753402.2205356774, + 25.5, -1999010.9422583843, -4744414.621748209, 3753401.8222620497, + 25.51, -1999008.3860998084, -4744416.012816543, 3753401.4279538537, + 25.52, -1999005.8258308882, -4744417.402454301, 3753401.0376126184, + 25.53, -1999003.2615063908, -4744418.790637212, 3753400.6512398715, + 25.54, -1999000.6931810814, -4744420.177340998, 3753400.2688371427, + 25.55, -1998998.1209097253, -4744421.562541383, 3753399.890405958, + 25.560000000000002, -1998995.544747088, -4744422.946214092, 3753399.5159478486, + 25.57, -1998992.964747936, -4744424.328334847, 3753399.145464342, + 25.580000000000002, -1998990.3809670347, -4744425.708879377, 3753398.778956966, + 25.59, -1998987.793459149, -4744427.087823402, 3753398.416427251, + 25.6, -1998985.2022790455, -4744428.465142648, 3753398.057876724, + 25.61, -1998982.6074814894, -4744429.840812838, 3753397.703306914, + 25.62, -1998980.0091212466, -4744431.214809697, 3753397.35271935, + 25.63, -1998977.4072530833, -4744432.587108952, 3753397.0061155595, + 25.64, -1998974.8019317635, -4744433.957686322, 3753396.6634970717, + 25.650000000000002, -1998972.1932120542, -4744435.326517534, 3753396.324865415, + 25.66, -1998969.5811487213, -4744436.693578314, 3753395.990222119, + 25.67, -1998966.9657965293, -4744438.058844385, 3753395.6595687107, + 25.68, -1998964.347210245, -4744439.42229147, 3753395.3329067193, + 25.69, -1998961.725444633, -4744440.783895294, 3753395.010237673, + 25.7, -1998959.1005544602, -4744442.143631583, 3753394.691563101, + 25.71, -1998956.4725944917, -4744443.501476059, 3753394.376884531, + 25.72, -1998953.841619493, -4744444.857404446, 3753394.066203492, + 25.73, -1998951.2076842296, -4744446.211392472, 3753393.7595215137, + 25.740000000000002, -1998948.5708434677, -4744447.563415856, 3753393.4568401235, + 25.75, -1998945.9311519724, -4744448.913450327, 3753393.1581608485, + 25.76, -1998943.28866451, -4744450.261471607, 3753392.8634852204, + 25.77, -1998940.6434358456, -4744451.607455418, 3753392.572814765, + 25.78, -1998937.9955207456, -4744452.95137749, 3753392.2861510124, + 25.79, -1998935.3449739749, -4744454.293213543, 3753392.00349549, + 25.8, -1998932.6918503004, -4744455.632939302, 3753391.7248497284, + 25.810000000000002, -1998930.0362044857, -4744456.970530492, 3753391.450215253, + 25.82, -1998927.378091298, -4744458.305962837, 3753391.179593596, + 25.830000000000002, -1998924.7175655025, -4744459.639212062, 3753390.9129862823, + 25.84, -1998922.054681865, -4744460.970253889, 3753390.650394843, + 25.85, -1998919.3894951514, -4744462.299064046, 3753390.391820806, + 25.86, -1998916.722060127, -4744463.625618254, 3753390.1372656994, + 25.87, -1998914.0524315576, -4744464.949892239, 3753389.8867310523, + 25.88, -1998911.380664209, -4744466.271861722, 3753389.6402183934, + 25.89, -1998908.7068128465, -4744467.591502433, 3753389.39772925, + 25.900000000000002, -1998906.0309322362, -4744468.908790091, 3753389.1592651526, + 25.91, -1998903.3530771434, -4744470.223700426, 3753388.924827628, + 25.92, -1998900.6733023338, -4744471.536209157, 3753388.694418205, + 25.93, -1998897.9916625735, -4744472.846292009, 3753388.4680384127, + 25.94, -1998895.308212628, -4744474.153924709, 3753388.2456897795, + 25.95, -1998892.6230072626, -4744475.459082978, 3753388.027373834, + 25.96, -1998889.9361012438, -4744476.761742543, 3753387.8130921046, + 25.97, -1998887.2475493362, -4744478.061879128, 3753387.6028461205, + 25.98, -1998884.557406306, -4744479.359468456, 3753387.396637409, + 25.990000000000002, -1998881.8657269187, -4744480.654486252, 3753387.1944675, + 26, -1998879.17256594, -4744481.94690824, 3753386.99633792, + 26.01, -1998876.4779781357, -4744483.236710144, 3753386.8022502004, + 26.02, -1998873.7820182722, -4744484.523867691, 3753386.6122058677, + 26.03, -1998871.084741114, -4744485.808356601, 3753386.426206451, + 26.04, -1998868.3862014269, -4744487.090152601, 3753386.2442534785, + 26.05, -1998865.6864539776, -4744488.369231414, 3753386.066348479, + 26.060000000000002, -1998862.9855535305, -4744489.645568765, 3753385.8924929826, + 26.07, -1998860.283554852, -4744490.919140378, 3753385.722688515, + 26.080000000000002, -1998857.5805127076, -4744492.189921978, 3753385.5569366068, + 26.09, -1998854.8764818625, -4744493.457889288, 3753385.3952387855, + 26.1, -1998852.1715170834, -4744494.723018034, 3753385.23759658, + 26.11, -1998849.4656731354, -4744495.985283939, 3753385.084011519, + 26.12, -1998846.7590047838, -4744497.244662728, 3753384.934485131, + 26.13, -1998844.0515667952, -4744498.501130125, 3753384.7890189444, + 26.14, -1998841.3434139346, -4744499.7546618525, 3753384.6476144874, + 26.150000000000002, -1998838.6346009672, -4744501.005233637, 3753384.5102732894, + 26.16, -1998835.9251826596, -4744502.252821204, 3753384.376996879, + 26.17, -1998833.2152137773, -4744503.4974002745, 3753384.2477867836, + 26.18, -1998830.5047490858, -4744504.738946576, 3753384.122644533, + 26.19, -1998827.7938433506, -4744505.977435829, 3753384.001571655, + 26.2, -1998825.0825513375, -4744507.212843761, 3753383.8845696775, + 26.21, -1998822.370927813, -4744508.445146094, 3753383.771640131, + 26.22, -1998819.6590275415, -4744509.674318555, 3753383.662784542, + 26.23, -1998816.9469052888, -4744510.900336866, 3753383.5580044407, + 26.240000000000002, -1998814.2346158207, -4744512.123176753, 3753383.4573013536, + 26.25, -1998811.522213904, -4744513.342813939, 3753383.360676811, + 26.26, -1998808.8097543025, -4744514.559224148, 3753383.2681323416, + 26.27, -1998806.0972917834, -4744515.772383106, 3753383.179669474, + 26.28, -1998803.3848811118, -4744516.982266534, 3753383.0952897347, + 26.29, -1998800.6725770535, -4744518.188850161, 3753383.014994654, + 26.3, -1998797.9604343746, -4744519.392109706, 3753382.9387857597, + 26.310000000000002, -1998795.2485078392, -4744520.592020899, 3753382.866664582, + 26.32, -1998792.5368522145, -4744521.788559459, 3753382.7986326464, + 26.330000000000002, -1998789.8255222659, -4744522.981701115, 3753382.734691485, + 26.34, -1998787.1145727583, -4744524.1714215875, 3753382.6748426235, + 26.35, -1998784.404058458, -4744525.357696603, 3753382.619087592, + 26.36, -1998781.694034131, -4744526.540501884, 3753382.5674279183, + 26.37, -1998778.9845545422, -4744527.719813156, 3753382.519865131, + 26.38, -1998776.2756744584, -4744528.895606143, 3753382.4764007586, + 26.39, -1998773.567448644, -4744530.06785657, 3753382.437036331, + 26.400000000000002, -1998770.8599318648, -4744531.23654016, 3753382.4017733755, + 26.41, -1998768.1531788872, -4744532.40163264, 3753382.3706134204, + 26.42, -1998765.4472444763, -4744533.56310973, 3753382.343557994, + 26.43, -1998762.7421833978, -4744534.720947157, 3753382.320608626, + 26.44, -1998760.0380504183, -4744535.875120645, 3753382.3017668445, + 26.45, -1998757.3349003019, -4744537.025605918, 3753382.287034177, + 26.46, -1998754.6327878162, -4744538.1723787, 3753382.276412155, + 26.47, -1998751.9317677252, -4744539.315414716, 3753382.269902304, + 26.48, -1998749.2318947949, -4744540.45468969, 3753382.2675061533, + 26.490000000000002, -1998746.5332237917, -4744541.590179346, 3753382.269225232, + 26.5, -1998743.8358094802, -4744542.7218594095, 3753382.2750610686, + 26.51, -1998741.139706627, -4744543.849705603, 3753382.2850151923, + 26.52, -1998738.4449699973, -4744544.973693651, 3753382.299089129, + 26.53, -1998735.751654357, -4744546.093799279, 3753382.3172844104, + 26.54, -1998733.0598144713, -4744547.20999821, 3753382.3396025626, + 26.55, -1998730.3695051074, -4744548.32226617, 3753382.3660451164, + 26.560000000000002, -1998727.6807810294, -4744549.430578883, 3753382.3966135993, + 26.57, -1998724.993697003, -4744550.534912071, 3753382.431309538, + 26.580000000000002, -1998722.308307794, -4744551.635241461, 3753382.470134464, + 26.59, -1998719.6246681686, -4744552.7315427745, 3753382.5130899046, + 26.6, -1998716.9428328928, -4744553.8237917395, 3753382.5601773886, + 26.61, -1998714.262856731, -4744554.911964077, 3753382.611398444, + 26.62, -1998711.5847944496, -4744555.996035513, 3753382.6667546, + 26.63, -1998708.908700815, -4744557.07598177, 3753382.7262473847, + 26.64, -1998706.2346305912, -4744558.151778574, 3753382.7898783265, + 26.650000000000002, -1998703.562638545, -4744559.22340165, 3753382.8576489547, + 26.66, -1998700.8927794418, -4744560.29082672, 3753382.929560797, + 26.67, -1998698.2251080472, -4744561.35402951, 3753383.005615382, + 26.68, -1998695.5596791278, -4744562.412985743, 3753383.085814239, + 26.69, -1998692.8965474474, -4744563.467671145, 3753383.170158896, + 26.7, -1998690.235767773, -4744564.518061439, 3753383.258650882, + 26.71, -1998687.5773948706, -4744565.564132349, 3753383.351291725, + 26.72, -1998684.9214835046, -4744566.605859599, 3753383.448082953, + 26.73, -1998682.2680884413, -4744567.643218916, 3753383.5490260962, + 26.740000000000002, -1998679.6172644468, -4744568.676186021, 3753383.654122682, + 26.75, -1998676.9690662862, -4744569.704736642, 3753383.7633742397, + 26.76, -1998674.3235487258, -4744570.728846499, 3753383.876782296, + 26.77, -1998671.6807665299, -4744571.748491318, 3753383.9943483816, + 26.78, -1998669.040774466, -4744572.763646825, 3753384.1160740242, + 26.79, -1998666.403627298, -4744573.774288742, 3753384.2419607528, + 26.8, -1998663.769379794, -4744574.780392795, 3753384.372010095, + 26.810000000000002, -1998661.1380867166, -4744575.7819347065, 3753384.50622358, + 26.82, -1998658.5098028337, -4744576.778890202, 3753384.6446027365, + 26.830000000000002, -1998655.8845829098, -4744577.771235005, 3753384.787149092, + 26.84, -1998653.2624817109, -4744578.758944841, 3753384.9338641763, + 26.85, -1998650.643554003, -4744579.741995433, 3753385.0847495175, + 26.86, -1998648.027854552, -4744580.720362507, 3753385.239806644, + 26.87, -1998645.4154381226, -4744581.694021786, 3753385.3990370845, + 26.88, -1998642.8063594815, -4744582.662948992, 3753385.562442368, + 26.89, -1998640.2006733937, -4744583.627119854, 3753385.7300240216, + 26.900000000000002, -1998637.5984346245, -4744584.586510094, 3753385.9017835753, + 26.91, -1998634.9996979414, -4744585.541095436, 3753386.0777225574, + 26.92, -1998632.4045181077, -4744586.490851605, 3753386.2578424956, + 26.93, -1998629.8129498905, -4744587.435754323, 3753386.442144919, + 26.94, -1998627.2250480545, -4744588.375779319, 3753386.6306313565, + 26.95, -1998624.6408673672, -4744589.310902313, 3753386.823303337, + 26.96, -1998622.0604625929, -4744590.241099031, 3753387.0201623873, + 26.97, -1998619.4838884966, -4744591.166345196, 3753387.2212100374, + 26.98, -1998616.9111998456, -4744592.086616535, 3753387.4264478153, + 26.990000000000002, -1998614.3424514043, -4744593.001888769, 3753387.6358772498, + 27, -1998611.777697939, -4744593.912137625, 3753387.8494998696, + 27.01, -1998609.2169942153, -4744594.817338826, 3753388.0673172027, + 27.02, -1998606.6603949987, -4744595.717468096, 3753388.289330778, + 27.03, -1998604.107955055, -4744596.61250116, 3753388.515542125, + 27.04, -1998601.5597291498, -4744597.502413742, 3753388.7459527696, + 27.05, -1998599.0157720495, -4744598.387181567, 3753388.980564243, + 27.060000000000002, -1998596.476138519, -4744599.266780358, 3753389.2193780732, + 27.07, -1998593.9408833233, -4744600.141185839, 3753389.4623957863, + 27.080000000000002, -1998591.4100612286, -4744601.010373737, 3753389.709618914, + 27.09, -1998588.8837270015, -4744601.874319773, 3753389.961048985, + 27.1, -1998586.3619354074, -4744602.732999674, 3753390.216687525, + 27.11, -1998583.8447412108, -4744603.586389163, 3753390.476536065, + 27.12, -1998581.3321991784, -4744604.434463963, 3753390.7405961314, + 27.13, -1998578.8243640757, -4744605.2771998, 3753391.0088692545, + 27.14, -1998576.3212906679, -4744606.114572398, 3753391.2813569624, + 27.150000000000002, -1998573.823033722, -4744606.946557483, 3753391.5580607844, + 27.16, -1998571.3296480018, -4744607.773130776, 3753391.8389822473, + 27.17, -1998568.8411882739, -4744608.594268003, 3753392.124122881, + 27.18, -1998566.357709304, -4744609.409944887, 3753392.413484213, + 27.19, -1998563.8792658579, -4744610.220137155, 3753392.707067773, + 27.2, -1998561.4059127008, -4744611.024820529, 3753393.0048750886, + 27.21, -1998558.9377045995, -4744611.823970733, 3753393.306907689, + 27.22, -1998556.4746963184, -4744612.617563494, 3753393.6131671024, + 27.23, -1998554.016942623, -4744613.405574533, 3753393.923654858, + 27.240000000000002, -1998551.5644982802, -4744614.187979575, 3753394.238372483, + 27.25, -1998549.117418055, -4744614.964754348, 3753394.557321507, + 27.26, -1998546.6757567127, -4744615.735874571, 3753394.8805034584, + 27.27, -1998544.2395690198, -4744616.501315971, 3753395.207919865, + 27.28, -1998541.8089097417, -4744617.261054273, 3753395.5395722566, + 27.29, -1998539.3838336437, -4744618.015065201, 3753395.8754621614, + 27.3, -1998536.9643954919, -4744618.763324475, 3753396.2155911075, + 27.310000000000002, -1998534.550650052, -4744619.505807825, 3753396.5599606233, + 27.32, -1998532.142652089, -4744620.242490974, 3753396.908572238, + 27.330000000000002, -1998529.7404563692, -4744620.973349645, 3753397.2614274793, + 27.34, -1998527.3441176577, -4744621.69835956, 3753397.618527876, + 27.35, -1998524.9536907212, -4744622.417496449, 3753397.9798749583, + 27.36, -1998522.5692303241, -4744623.1307360325, 3753398.345470252, + 27.37, -1998520.1907912334, -4744623.838054036, 3753398.715315288, + 27.38, -1998517.818428214, -4744624.5394261805, 3753399.089411593, + 27.39, -1998515.452196031, -4744625.234828196, 3753399.467760697, + 27.400000000000002, -1998513.0921494514, -4744625.924235803, 3753399.850364127, + 27.41, -1998510.73834324, -4744626.607624727, 3753400.2372234142, + 27.42, -1998508.3908321627, -4744627.284970692, 3753400.6283400846, + 27.43, -1998506.049670985, -4744627.956249422, 3753401.0237156674, + 27.44, -1998503.714914473, -4744628.6214366425, 3753401.4233516916, + 27.45, -1998501.3866173918, -4744629.280508076, 3753401.8272496853, + 27.46, -1998499.0648345072, -4744629.933439445, 3753402.235411176, + 27.47, -1998496.7496205857, -4744630.58020648, 3753402.647837695, + 27.48, -1998494.4410303915, -4744631.2207849, 3753403.064530769, + 27.490000000000002, -1998492.1391186917, -4744631.855150432, 3753403.4854919277, + 27.5, -1998489.8439402515, -4744632.4832788, 3753403.910722698, + 27.51, -1998487.5555498358, -4744633.105145726, 3753404.3402246097, + 27.52, -1998485.2740022105, -4744633.720726934, 3753404.7739991895, + 27.53, -1998482.9993521424, -4744634.329998154, 3753405.212047969, + 27.54, -1998480.731654396, -4744634.932935104, 3753405.6543724737, + 27.55, -1998478.4709637382, -4744635.529513512, 3753406.1009742343, + 27.560000000000002, -1998476.2173349336, -4744636.1197091015, 3753406.551854779, + 27.57, -1998473.9708227473, -4744636.703497592, 3753407.0070156343, + 27.580000000000002, -1998471.7314819465, -4744637.280854717, 3753407.4664583323, + 27.59, -1998469.499367296, -4744637.851756195, 3753407.9301843992, + 27.6, -1998467.274533562, -4744638.416177749, 3753408.398195363, + 27.61, -1998465.057035509, -4744638.974095105, 3753408.8704927536, + 27.62, -1998462.8469279045, -4744639.525483991, 3753409.3470781003, + 27.63, -1998460.6442655127, -4744640.070320126, 3753409.82795293, + 27.64, -1998458.4491031002, -4744640.608579237, 3753410.3131187716, + 27.650000000000002, -1998456.261495432, -4744641.140237047, 3753410.8025771533, + 27.66, -1998454.081497273, -4744641.665269281, 3753411.296329604, + 27.67, -1998451.9091633912, -4744642.183651663, 3753411.7943776543, + 27.68, -1998449.7445485503, -4744642.695359917, 3753412.296722829, + 27.69, -1998447.5877075163, -4744643.200369769, 3753412.8033666587, + 27.7, -1998445.433017133, -4744643.699055944, 3753413.3168119914, + 27.71, -1998443.2676029825, -4744644.192324118, 3753413.842729245, + 27.72, -1998441.0911479944, -4744644.680216775, 3753414.3812327306, + 27.73, -1998438.9038473605, -4744645.162740763, 3753414.932210633, + 27.740000000000002, -1998436.70589627, -4744645.639902925, 3753415.495551139, + 27.75, -1998434.4974899136, -4744646.111710112, 3753416.071142433, + 27.76, -1998432.2788234823, -4744646.578169169, 3753416.6588727017, + 27.77, -1998430.0500921654, -4744647.039286946, 3753417.25863013, + 27.78, -1998427.811491154, -4744647.495070285, 3753417.870302905, + 27.79, -1998425.5632156383, -4744647.94552604, 3753418.4937792104, + 27.8, -1998423.3054608079, -4744648.390661055, 3753419.128947233, + 27.810000000000002, -1998421.038421854, -4744648.830482176, 3753419.775695159, + 27.82, -1998418.7622939667, -4744649.264996251, 3753420.433911173, + 27.830000000000002, -1998416.4772723361, -4744649.69421013, 3753421.1034834613, + 27.84, -1998414.1835521525, -4744650.118130658, 3753421.784300209, + 27.85, -1998411.8813286065, -4744650.53676468, 3753422.476249602, + 27.86, -1998409.5707968888, -4744650.950119049, 3753423.179219827, + 27.87, -1998407.2521521884, -4744651.358200607, 3753423.8930990687, + 27.88, -1998404.9255896974, -4744651.761016205, 3753424.617775512, + 27.89, -1998402.5913046047, -4744652.158572687, 3753425.3531373446, + 27.900000000000002, -1998400.2494921014, -4744652.550876902, 3753426.0990727507, + 27.91, -1998397.9003473767, -4744652.937935699, 3753426.855469916, + 27.92, -1998395.5440656226, -4744653.319755921, 3753427.622217027, + 27.93, -1998393.1808420287, -4744653.69634442, 3753428.3992022695, + 27.94, -1998390.810871785, -4744654.06770804, 3753429.186313827, + 27.95, -1998388.4343500822, -4744654.433853629, 3753429.9834398883, + 27.96, -1998386.051472111, -4744654.794788035, 3753430.7904686364, + 27.97, -1998383.6624330604, -4744655.150518104, 3753431.607288259, + 27.98, -1998381.2674281218, -4744655.501050685, 3753432.4337869403, + 27.990000000000002, -1998378.8666524854, -4744655.846392625, 3753433.2698528673, + 28, -1998376.460301341, -4744656.186550771, 3753434.1153742247, + 28.01, -1998374.0485698797, -4744656.521531969, 3753434.9702391988, + 28.02, -1998371.6316532919, -4744656.851343067, 3753435.834335975, + 28.03, -1998369.2097467666, -4744657.175990913, 3753436.707552738, + 28.04, -1998366.7830454956, -4744657.495482354, 3753437.5897776755, + 28.05, -1998364.351744669, -4744657.809824237, 3753438.480898971, + 28.060000000000002, -1998361.9160394762, -4744658.11902341, 3753439.380804812, + 28.07, -1998359.4761251085, -4744658.423086719, 3753440.2893833835, + 28.080000000000002, -1998357.0321967555, -4744658.722021012, 3753441.2065228713, + 28.09, -1998354.5844496086, -4744659.015833138, 3753442.1321114614, + 28.1, -1998352.1330788564, -4744659.304529941, 3753443.0660373378, + 28.11, -1998349.6782796907, -4744659.588118269, 3753444.008188688, + 28.12, -1998347.2202473013, -4744659.866604972, 3753444.9584536976, + 28.13, -1998344.7591768792, -4744660.139996895, 3753445.9167205514, + 28.14, -1998342.2952636133, -4744660.408300884, 3753446.8828774355, + 28.150000000000002, -1998339.8287026952, -4744660.671523789, 3753447.856812535, + 28.16, -1998337.3596893148, -4744660.929672456, 3753448.838414036, + 28.17, -1998334.888418662, -4744661.182753732, 3753449.8275701255, + 28.18, -1998332.4150859278, -4744661.430774467, 3753450.8241689876, + 28.19, -1998329.9398863025, -4744661.6737415055, 3753451.8280988075, + 28.2, -1998327.4630149757, -4744661.911661695, 3753452.839247773, + 28.21, -1998324.984667139, -4744662.144541881, 3753453.8575040675, + 28.22, -1998322.505037981, -4744662.372388917, 3753454.8827558784, + 28.23, -1998320.0243226937, -4744662.595209643, 3753455.9148913906, + 28.240000000000002, -1998317.5427164661, -4744662.8130109105, 3753456.953798789, + 28.25, -1998315.0604144896, -4744663.025799566, 3753457.999366261, + 28.26, -1998312.577611954, -4744663.233582457, 3753459.051481991, + 28.27, -1998310.0945040493, -4744663.43636643, 3753460.1100341654, + 28.28, -1998307.6112859666, -4744663.634158333, 3753461.1749109696, + 28.29, -1998305.128152896, -4744663.826965012, 3753462.2460005893, + 28.3, -1998302.6453000277, -4744664.014793315, 3753463.32319121, + 28.310000000000002, -1998300.1629225519, -4744664.19765009, 3753464.4063710175, + 28.32, -1998297.6812156588, -4744664.375542183, 3753465.495428198, + 28.330000000000002, -1998295.200374539, -4744664.548476445, 3753466.5902509363, + 28.34, -1998292.7205943828, -4744664.716459717, 3753467.6907274183, + 28.35, -1998290.2420703806, -4744664.8794988515, 3753468.7967458307, + 28.36, -1998287.7649977226, -4744665.037600693, 3753469.908194358, + 28.37, -1998285.289571599, -4744665.190772091, 3753471.024961186, + 28.38, -1998282.8159872014, -4744665.339019889, 3753472.1469345004, + 28.39, -1998280.344439718, -4744665.482350939, 3753473.274002488, + 28.400000000000002, -1998277.8751243404, -4744665.620772085, 3753474.406053332, + 28.41, -1998275.4082362584, -4744665.754290176, 3753475.542975221, + 28.42, -1998272.9439706628, -4744665.8829120565, 3753476.684656339, + 28.43, -1998270.4825227438, -4744666.00664458, 3753477.8309848728, + 28.44, -1998268.0240876914, -4744666.125494586, 3753478.981849006, + 28.45, -1998265.5688606966, -4744666.239468926, 3753480.137136926, + 28.46, -1998263.1170369496, -4744666.348574448, 3753481.2967368183, + 28.47, -1998260.6688116402, -4744666.452817997, 3753482.460536868, + 28.48, -1998258.2243799588, -4744666.552206421, 3753483.628425262, + 28.490000000000002, -1998255.7839370961, -4744666.646746569, 3753484.800290184, + 28.5, -1998253.3476782418, -4744666.736445286, 3753485.976019822, + 28.51, -1998250.915798587, -4744666.821309421, 3753487.15550236, + 28.52, -1998248.488493322, -4744666.901345819, 3753488.338625984, + 28.53, -1998246.065957636, -4744666.976561329, 3753489.5252788793, + 28.54, -1998243.648386721, -4744667.046962799, 3753490.715349233, + 28.55, -1998241.2359757666, -4744667.112557075, 3753491.9087252296, + 28.560000000000002, -1998238.828919963, -4744667.173351003, 3753493.1052950555, + 28.57, -1998236.4274144997, -4744667.229351433, 3753494.304946895, + 28.580000000000002, -1998234.0316545684, -4744667.280565211, 3753495.507568935, + 28.59, -1998231.6418353587, -4744667.326999184, 3753496.713049362, + 28.6, -1998229.2581520616, -4744667.3686602, 3753497.92127636, + 28.61, -1998226.8807998665, -4744667.405555107, 3753499.132138115, + 28.62, -1998224.5099739644, -4744667.437690751, 3753500.3455228135, + 28.63, -1998222.1458695459, -4744667.4650739785, 3753501.56131864, + 28.64, -1998219.7886818002, -4744667.487711638, 3753502.779413781, + 28.650000000000002, -1998217.4386059183, -4744667.505610576, 3753503.9996964224, + 28.66, -1998215.0958370904, -4744667.518777641, 3753505.2220547493, + 28.67, -1998212.760570507, -4744667.52721968, 3753506.4463769477, + 28.68, -1998210.4330013585, -4744667.530943541, 3753507.672551203, + 28.69, -1998208.1133248352, -4744667.529956069, 3753508.9004657017, + 28.7, -1998205.8017361274, -4744667.524264111, 3753510.1300086286, + 28.71, -1998203.4984304255, -4744667.513874519, 3753511.3610681687, + 28.72, -1998201.2036029191, -4744667.498794134, 3753512.5935325096, + 28.73, -1998198.9174487994, -4744667.479029807, 3753513.8272898355, + 28.740000000000002, -1998196.6401632563, -4744667.454588385, 3753515.062228333, + 28.75, -1998194.3719414803, -4744667.425476717, 3753516.298236187, + 28.76, -1998192.1129786617, -4744667.391701645, 3753517.535201584, + 28.77, -1998189.863469991, -4744667.353270021, 3753518.773012709, + 28.78, -1998187.623610658, -4744667.310188691, 3753520.0115577476, + 28.79, -1998185.3935958538, -4744667.262464501, 3753521.250724886, + 28.8, -1998183.1736207684, -4744667.210104301, 3753522.4904023097, + 28.810000000000002, -1998180.9638805913, -4744667.153114934, 3753523.730478204, + 28.82, -1998178.7645705144, -4744667.091503253, 3753524.9708407554, + 28.830000000000002, -1998176.5758857266, -4744667.025276101, 3753526.211378149, + 28.84, -1998174.3980214186, -4744666.954440324, 3753527.4519785703, + 28.85, -1998172.2311727814, -4744666.879002775, 3753528.692530206, + 28.86, -1998170.0755350047, -4744666.798970298, 3753529.93292124, + 28.87, -1998167.9313032795, -4744666.714349738, 3753531.1730398596, + 28.88, -1998165.7986727953, -4744666.625147946, 3753532.41277425, + 28.89, -1998163.6778387425, -4744666.531371768, 3753533.652012597, + 28.900000000000002, -1998161.5689963119, -4744666.433028051, 3753534.8906430854, + 28.91, -1998159.4723406935, -4744666.330123641, 3753536.1285539023, + 28.92, -1998157.3880670778, -4744666.222665387, 3753537.3656332316, + 28.93, -1998155.3163706553, -4744666.110660139, 3753538.601769261, + 28.94, -1998153.2574466157, -4744665.994114738, 3753539.8368501747, + 28.95, -1998151.21149015, -4744665.873036036, 3753541.07076416, + 28.96, -1998149.1786964484, -4744665.74743088, 3753542.3033993994, + 28.97, -1998147.1592607012, -4744665.617306113, 3753543.5346440827, + 28.98, -1998145.1533780983, -4744665.482668588, 3753544.764386392, + 28.990000000000002, -1998143.1612438303, -4744665.343525148, 3753545.9925145153, + 29, -1998141.1830530872, -4744665.199882641, 3753547.218916638, + 29.01, -1998139.2190010604, -4744665.051747918, 3753548.4434809443, + 29.02, -1998137.2692829391, -4744664.899127822, 3753549.666095622, + 29.03, -1998135.3340939141, -4744664.742029204, 3753550.886648854, + 29.04, -1998133.4136291759, -4744664.5804589065, 3753552.105028829, + 29.05, -1998131.5080839149, -4744664.4144237805, 3753553.321123731, + 29.060000000000002, -1998129.6176533208, -4744664.243930672, 3753554.534821746, + 29.07, -1998127.7425325844, -4744664.068986429, 3753555.746011059, + 29.080000000000002, -1998125.8829168952, -4744663.8895978965, 3753556.9545798567, + 29.09, -1998124.039001445, -4744663.705771926, 3753558.160416324, + 29.1, -1998122.210981423, -4744663.51751536, 3753559.3634086484, + 29.11, -1998120.3990520204, -4744663.32483505, 3753560.5634450135, + 29.12, -1998118.6034084265, -4744663.12773784, 3753561.7604136053, + 29.13, -1998116.8242458324, -4744662.926230579, 3753562.95420261, + 29.14, -1998115.061759428, -4744662.720320114, 3753564.1447002133, + 29.150000000000002, -1998113.3161444038, -4744662.510013292, 3753565.331794601, + 29.16, -1998111.5875959506, -4744662.295316961, 3753566.5153739583, + 29.17, -1998109.8763092575, -4744662.076237966, 3753567.6953264712, + 29.18, -1998108.1824795157, -4744661.852783158, 3753568.871540325, + 29.19, -1998106.5063019157, -4744661.624959381, 3753570.0439037057, + 29.2, -1998104.8479716475, -4744661.392773486, 3753571.2123047994, + 29.21, -1998103.2076839018, -4744661.156232315, 3753572.376631791, + 29.22, -1998101.5856338681, -4744660.915342719, 3753573.536772866, + 29.23, -1998099.9820167376, -4744660.670111546, 3753574.6926162113, + 29.240000000000002, -1998098.3970277, -4744660.42054564, 3753575.8440500116, + 29.25, -1998096.8308619459, -4744660.1666518515, 3753576.9909624527, + 29.26, -1998095.2837146656, -4744659.908437026, 3753578.1332417205, + 29.27, -1998093.7557810494, -4744659.64590801, 3753579.270776001, + 29.28, -1998092.2472562876, -4744659.379071653, 3753580.403453479, + 29.29, -1998090.7583355706, -4744659.107934801, 3753581.531162341, + 29.3, -1998089.2892140893, -4744658.832504301, 3753582.653790772, + 29.310000000000002, -1998087.8400870329, -4744658.552787, 3753583.771226959, + 29.32, -1998086.4111495924, -4744658.268789747, 3753584.883359086, + 29.330000000000002, -1998085.0025969578, -4744657.980519389, 3753585.9900753386, + 29.34, -1998083.6146243203, -4744657.687982771, 3753587.0912639047, + 29.35, -1998082.2474268689, -4744657.391186742, 3753588.1868129675, + 29.36, -1998080.901199795, -4744657.09013815, 3753589.276610715, + 29.37, -1998079.5761382882, -4744656.784843842, 3753590.36054533, + 29.38, -1998078.2724375394, -4744656.475310663, 3753591.438505001, + 29.39, -1998076.9902927387, -4744656.161545463, 3753592.510377912, + 29.400000000000002, -1998075.7298990763, -4744655.843555087, 3753593.57605225, + 29.41, -1998074.4914517428, -4744655.521346386, 3753594.6354161985, + 29.42, -1998073.275145928, -4744655.194926202, 3753595.6883579455, + 29.43, -1998072.081176823, -4744654.864301388, 3753596.7347656754, + 29.44, -1998070.9097396175, -4744654.5294787865, 3753597.7745275744, + 29.45, -1998069.7610295021, -4744654.190465247, 3753598.807531828, + 29.46, -1998068.6352416673, -4744653.847267617, 3753599.8336666212, + 29.47, -1998067.5325713027, -4744653.499892742, 3753600.8528201412, + 29.48, -1998066.4532135995, -4744653.148347471, 3753601.864880573, + 29.490000000000002, -1998065.3973637477, -4744652.792638651, 3753602.8697361015, + 29.5, -1998064.3652169378, -4744652.43277313, 3753603.867274913, + 29.51, -1998063.356968359, -4744652.068757753, 3753604.857385193, + 29.52, -1998062.3728132034, -4744651.70059937, 3753605.8399551283, + 29.53, -1998061.4129466605, -4744651.328304825, 3753606.814872903, + 29.54, -1998060.4775639204, -4744650.951880969, 3753607.7820267035, + 29.55, -1998059.566860174, -4744650.571334648, 3753608.741304715, + 29.560000000000002, -1998058.6810306106, -4744650.186672706, 3753609.692595124, + 29.57, -1998057.8202704214, -4744649.7979019955, 3753610.635786116, + 29.580000000000002, -1998056.9847747965, -4744649.405029359, 3753611.5707658757, + 29.59, -1998056.1747389266, -4744649.008061649, 3753612.4974225904, + 29.6, -1998055.3903580015, -4744648.607005708, 3753613.415644445, + 29.61, -1998054.6318272115, -4744648.201868387, 3753614.325319624, + 29.62, -1998053.8993417474, -4744647.79265653, 3753615.2263363143, + 29.63, -1998053.193096799, -4744647.379376985, 3753616.1185827022, + 29.64, -1998052.5132875573, -4744646.962036601, 3753617.001946973, + 29.650000000000002, -1998051.8601092116, -4744646.540642224, 3753617.876317311, + 29.66, -1998051.2337569534, -4744646.115200702, 3753618.7415819033, + 29.67, -1998050.6344259726, -4744645.685718882, 3753619.5976289352, + 29.68, -1998050.0623114589, -4744645.252203611, 3753620.444346593, + 29.69, -1998049.5176086035, -4744644.814661737, 3753621.281623061, + 29.7, -1998049.0005125962, -4744644.373100107, 3753622.1093465257, + 29.71, -1998048.5112186274, -4744643.927525567, 3753622.927405173, + 29.72, -1998048.049921888, -4744643.477944965, 3753623.7356871883, + 29.73, -1998047.6168175675, -4744643.024365149, 3753624.5340807564, + 29.740000000000002, -1998047.2121008562, -4744642.566792965, 3753625.322474065, + 29.75, -1998046.8359669454, -4744642.105235262, 3753626.100755298, + 29.76, -1998046.4886110246, -4744641.639698887, 3753626.8688126416, + 29.77, -1998046.1702282846, -4744641.170190685, 3753627.6265342827, + 29.78, -1998045.8810139152, -4744640.696717507, 3753628.3738084054, + 29.79, -1998045.6211631072, -4744640.219286199, 3753629.1105231955, + 29.8, -1998045.3908710503, -4744639.737903605, 3753629.8365668384, + 29.810000000000002, -1998045.190332936, -4744639.252576577, 3753630.5518275215, + 29.82, -1998045.0197439534, -4744638.763311959, 3753631.2561934297, + 29.830000000000002, -1998044.8792992935, -4744638.270116598, 3753631.949552747, + 29.84, -1998044.7691941466, -4744637.772997345, 3753632.6317936615, + 29.85, -1998044.689623703, -4744637.271961044, 3753633.302804358, + 29.86, -1998044.6407831525, -4744636.7670145435, 3753633.962473022, + 29.87, -1998044.6228676857, -4744636.258164689, 3753634.6106878384, + 29.88, -1998044.6360724939, -4744635.745418332, 3753635.247336995, + 29.89, -1998044.680592766, -4744635.228782315, 3753635.8723086747, + 29.900000000000002, -1998044.756623693, -4744634.7082634885, 3753636.4854910662, + 29.91, -1998044.8643604652, -4744634.183868698, 3753637.086772353, + 29.92, -1998045.0039982728, -4744633.655604791, 3753637.676040721, + 29.93, -1998045.1757323064, -4744633.123478617, 3753638.2531843563, + 29.94, -1998045.3797577564, -4744632.58749702, 3753638.818091445, + 29.95, -1998045.6162698125, -4744632.04766685, 3753639.3706501727, + 29.96, -1998045.8854636655, -4744631.503994952, 3753639.910748725, + 29.97, -1998046.1875345055, -4744630.956488174, 3753640.4382752865, + 29.98, -1998046.522677523, -4744630.405153365, 3753640.9531180435, + 29.990000000000002, -1998046.8910879083, -4744629.8499973705, 3753641.4551651827, + 30, -1998047.292960852, -4744629.291027037, 3753641.9443048886 + ] + }, + "orientation":{ + "epoch":"2012-03-15T10:00:00Z", + "unitQuaternion":[ + 0, 0.8026163128314372, 0.18330478351001372, -0.49318981173780907, 0.28101640577952014, + 0.1, 0.0013227646593040121, 0.20465333268019117, 0.6193138482890999, 0.7580010692828163, + 0.2, 0.14805073875752459, 0.032300514271327595, 0.7385492073899783, 0.6569495595514115, + 0.30000000000000004, 0.17355355592732385, -0.05104583424031879, 0.7626609480497291, 0.6209845121672356, + 0.4, 0.16947966984115298, -0.11121210780218886, 0.7671945539255669, 0.6085400767539294, + 0.5, 0.15426075361944108, -0.1631131557431578, 0.7639919881654778, 0.6049082247210986, + 0.6000000000000001, 0.13426973328087502, -0.21015756562913537, 0.7563939241318947, 0.6047095731587785, + 0.7000000000000001, 0.11285359128701503, -0.25269046943366874, 0.7461204953873578, 0.6055706399371912, + 0.8, 0.09234638181887836, -0.2900659301208146, 0.7345961182978961, 0.606384733424063, + 0.9, 0.07466093948263473, -0.32130559320797963, 0.7232631985907602, 0.6066949855183423, + 1, 0.061495499357606405, -0.34532774265387983, 0.7136187732766212, 0.6063953332105259, + 1.1, 0.05381222716603362, -0.36170807190591103, 0.7067847673866889, 0.6055797284550427, + 1.2000000000000002, 0.050136142704081524, -0.3726618837060894, 0.7022725191866236, 0.6045021062185464, + 1.3, 0.049784075738039876, -0.3792969766572864, 0.699829793992119, 0.6032359478201702, + 1.4000000000000001, 0.05217817771993951, -0.3824959528237085, 0.6991552259468161, 0.6017941956138878, + 1.5, 0.0567292057096438, -0.38309538179407604, 0.6998733019734289, 0.6001642165711094, + 1.6, 0.0628445879023309, -0.3819092454230839, 0.701569955665762, 0.5983272376709068, + 1.7000000000000002, 0.06993530428579314, -0.3797472939845786, 0.7038176413752424, 0.5962732373793362, + 1.8, 0.07742288857403613, -0.3774284621814729, 0.7061907479288617, 0.5940101680946679, + 1.9000000000000001, 0.08474741203378244, -0.375789926011837, 0.7082714808211619, 0.591566832333417, + 2, 0.09137730696427464, -0.37569276438208987, 0.7096457901438533, 0.5889889532869071, + 2.1, 0.09684612458055361, -0.37799688798901293, 0.7099036534895767, 0.5863241284362263, + 2.2, 0.10140445067024235, -0.3827953304617482, 0.709028492234192, 0.5834924760106645, + 2.3000000000000003, 0.10599160891316653, -0.3897461523799926, 0.7073102670635416, 0.5801516195370753, + 2.4000000000000004, 0.11439457296843608, -0.4018705750214778, 0.7054864139824301, 0.572453353814516, + 2.5, 0.12147992560512556, -0.41253179555842723, 0.7034971208926875, 0.5658197117669307, + 2.6, 0.1277948092491125, -0.42119405100070234, 0.7017825713968118, 0.5601475525379718, + 2.7, 0.13393755450627692, -0.4273874873850118, 0.7007994285593584, 0.5552304278860095, + 2.8000000000000003, 0.14047981312236815, -0.43061454442635516, 0.7009984429398919, 0.5508518124046016, + 2.9000000000000004, 0.1479711034552336, -0.430343879966814, 0.7028059368165552, 0.5467837897128567, + 3, 0.1569413990177578, -0.4260003698654657, 0.706599768177656, 0.5427797433214673, + 3.1, 0.1679012902716786, -0.4169521810102855, 0.7126789347664845, 0.5385617619326318, + 3.2, 0.18262261802701021, -0.4007606528101461, 0.7221918246466992, 0.5333655847142907, + 3.3000000000000003, 0.20173658579392026, -0.37625139051791273, 0.7351504139214007, 0.5265843806995634, + 3.4000000000000004, 0.22369848088073704, -0.3451311432171494, 0.7497856727674533, 0.518328977142829, + 3.5, 0.24700702394937873, -0.30923501625556565, 0.7644548344195202, 0.5088909912483369, + 3.6, 0.27023751432591453, -0.2705711694685063, 0.7777920527283017, 0.49880101324685633, + 3.7, 0.2920671637807144, -0.23131473899791494, 0.7888087635222512, 0.4888465996137369, + 3.8000000000000003, 0.311282982573062, -0.19376131069265956, 0.7969369774878138, 0.4800530316034566, + 3.9000000000000004, 0.32676051337166306, -0.160258272560693, 0.8020086381195531, 0.47363171067673393, + 4, 0.3374042707881186, -0.13313296511892284, 0.8041683734402181, 0.4709004128381023, + 4.1000000000000005, 0.3420454434700293, -0.11463198534523242, 0.803721932300741, 0.47317594832785487, + 4.2, 0.33902901892938636, -0.10732560725409071, 0.8008666504204158, 0.4818227335812437, + 4.3, 0.32695473906413597, -0.11252648999576274, 0.7956345800742264, 0.4973972282219173, + 4.4, 0.30679096440373316, -0.12697365251524007, 0.7881865303302032, 0.5181881792681129, + 4.5, 0.27971315954521303, -0.14706961432116386, 0.778545495265609, 0.5422158137884637, + 4.6000000000000005, 0.2471461943144619, -0.169246838753502, 0.7668894705379993, 0.567586827001624, + 4.7, 0.21549660760536837, -0.20062219332767262, 0.7593870950811222, 0.5802096065037415, + 4.800000000000001, 0.18482488491348364, -0.23002886820061688, 0.7511771947499561, 0.5904737960304821, + 4.9, 0.15736005776602288, -0.2537106678141853, 0.7430602115471189, 0.5989409246935004, + 5, 0.13572289098009896, -0.26880877576124834, 0.7365829421156337, 0.6056126718638078, + 5.1000000000000005, 0.12261173135194393, -0.2725652727754013, 0.7333074292012131, 0.6106838377508101, + 5.2, 0.12079800867730636, -0.2621830795333186, 0.7344327639819201, 0.6142282874436019, + 5.300000000000001, 0.13196401471494046, -0.2360454456349536, 0.7398639143479536, 0.6160109046608144, + 5.4, 0.15424840501258907, -0.19658942278074576, 0.7472504960707735, 0.6157732736355064, + 5.5, 0.18510815517414897, -0.14704778803020596, 0.7538830250593448, 0.6130026944890359, + 5.6000000000000005, 0.22186524210263692, -0.09092692085512054, 0.7574763016724899, 0.6072378132289789, + 5.7, 0.26173566134266985, -0.031990488268471805, 0.7565654210262149, 0.5983977071724843, + 5.800000000000001, 0.30191043446552224, 0.02589262062757947, 0.7507337369417806, 0.5870081072483629, + 5.9, 0.339665942682864, 0.07896661026781632, 0.74064955527192, 0.5743078948784173, + 6, 0.37245614565085816, 0.12378623145346937, 0.7279116247355297, 0.5622259821853988, + 6.1000000000000005, 0.3979295810145343, 0.15731566655501464, 0.7147298583624284, 0.5532314697982857, + 6.2, 0.4138225313862037, 0.176884023182489, 0.7034820639516097, 0.5500690325388938, + 6.300000000000001, 0.4186405998326521, 0.18117297447292016, 0.6958765530777875, 0.5546820930668028, + 6.4, 0.4137099708512149, 0.17274662506883376, 0.6917525950297994, 0.5661104228109151, + 6.5, 0.4007149139995117, 0.15460586470428359, 0.6900925812640191, 0.5824919000138697, + 6.6000000000000005, 0.38138786163808835, 0.12959953658219756, 0.6896520568588154, 0.6017701384941024, + 6.7, 0.35769147928168704, 0.1005312691502165, 0.6893009837683767, 0.621944067700845, + 6.800000000000001, 0.33191166310439535, 0.07020835818379521, 0.6882489746524377, 0.6412634273263045, + 6.9, 0.30666480730840157, 0.04143832565180753, 0.6861571215354098, 0.6583524631167688, + 7, 0.27608292422241193, 0.022253027658890864, 0.6844140215927809, 0.6744334427947734, + 7.1000000000000005, 0.2522000787587729, 0.009598194814733, 0.6825543055302947, 0.6858736144016799, + 7.2, 0.23949206207470905, 0.005611335275419284, 0.6805781936886633, 0.6924055079179446, + 7.300000000000001, 0.24006922499994723, 0.0125926067141514, 0.6785317703271688, 0.694120184204973, + 7.4, 0.25161685764513875, 0.02851449703506895, 0.6761131889573211, 0.6919153388425385, + 7.5, 0.2718030996187378, 0.0513828702697077, 0.6727988500675951, 0.6861665854792222, + 7.6000000000000005, 0.29846313485838855, 0.07935188790899497, 0.6680491126228517, 0.6770032630199074, + 7.7, 0.3294354878175312, 0.11052597264138378, 0.6614729498594526, 0.6646125227095376, + 7.800000000000001, 0.3626206669035055, 0.14299201377844387, 0.6529452115252101, 0.6494013294383845, + 7.9, 0.39604532945888743, 0.17486614780357396, 0.6426730868532727, 0.6320927390823482, + 8, 0.42792132912375824, 0.20434387253960062, 0.631209369353421, 0.6137602543965617, + 8.1, 0.45668415782441985, 0.22973841767076045, 0.619413661185587, 0.5958074821408359, + 8.200000000000001, 0.48099509404503693, 0.2494927484637174, 0.6083658861580388, 0.579903471732814, + 8.3, 0.4998179035488868, 0.26228473616793097, 0.5991811326511696, 0.5677770255480368, + 8.4, 0.5153915062829271, 0.27021557425669385, 0.5913605763414079, 0.5582542498089008, + 8.5, 0.5293763665472611, 0.274771679379433, 0.5843573699565268, 0.5502614387086532, + 8.6, 0.5423825676483213, 0.2762660780517051, 0.5779995438763418, 0.5435206819504519, + 8.700000000000001, 0.555043376088737, 0.2749321129311381, 0.5720484930513677, 0.5376799285233695, + 8.8, 0.5680388033146356, 0.2709015178024342, 0.5662064704929277, 0.5323105469114393, + 8.9, 0.5821229529891739, 0.26416524767037786, 0.5601176781972635, 0.5268944639083986, + 9, 0.5981546159466657, 0.25450483474839575, 0.5533614140249088, 0.5207969757782225, + 9.1, 0.6171274085023837, 0.2413731595333155, 0.5454343611415811, 0.5132193655914711, + 9.200000000000001, 0.640185491016869, 0.223688313014744, 0.5357163643064415, 0.5031242915288392, + 9.3, 0.6635433348964241, 0.2052216350534476, 0.5241325355367032, 0.49282797040386017, + 9.4, 0.6879575542508394, 0.18789632924412697, 0.5111815679296037, 0.47969029343402203, + 9.5, 0.7150149428783158, 0.1721100229822161, 0.4967371724522814, 0.46085133498113273, + 9.600000000000001, 0.7425098869583621, 0.15631419357696186, 0.48178608674007206, 0.4383230626822553, + 9.700000000000001, 0.7684599898964599, 0.139259821492294, 0.46714583912470375, 0.4145488041651352, + 9.8, 0.7912502689379767, 0.12001129690440633, 0.4534205379634592, 0.39233928719136624, + 9.9, 0.8096525473815799, 0.09788633200971208, 0.44094470446437006, 0.37476497452274293, + 10, 0.8227207862084482, 0.07236889074104355, 0.4297258062245779, 0.36500545620319197, + 10.100000000000001, 0.829557977236087, 0.043024913217439564, 0.41939473999545107, 0.36618365789689644, + 10.200000000000001, 0.8289692412441273, 0.009451713006919854, 0.4091624330847702, 0.38119124536710136, + 10.3, 0.8190313206455379, -0.02871228049806171, 0.39777553356724116, 0.41247778806321633, + 10.4, 0.7950794383176973, -0.07297511177002391, 0.38322675948100093, 0.4643926901279334, + 10.5, 0.7457111544586073, -0.127024548722111, 0.36133116103800933, 0.5451783471497005, + 10.600000000000001, 0.6669601846814854, -0.18517400284559987, 0.32872468325453025, 0.6425066406964098, + 10.700000000000001, 0.5587871993126285, -0.24068888525165083, 0.284635919521435, 0.7408158473729174, + 10.8, 0.4261674782473371, -0.2878366999189346, 0.23125278219058773, 0.8258652828356422, + 10.9, 0.2792555026010198, -0.3230179113240686, 0.17327250868702276, 0.8874978484279236, + 11, 0.13170408260073882, -0.3454602886864599, 0.11678801892476501, 0.9217764274500593, + 11.100000000000001, -0.001989657494709099, -0.3571178563556985, 0.0680071664584487, 0.9315781788155287, + 11.200000000000001, -0.10885622847025046, -0.36176249010302386, 0.03235072585712956, 0.9253278623354042, + 11.3, -0.17847984307342335, -0.36351116689520185, 0.014253655617692262, 0.9142217512510338, + 11.4, -0.20234086511224567, -0.36504206130741024, 0.017585151575939928, 0.9085665799632497, + 11.5, -0.17746150671200733, -0.3658283982573714, 0.043987834690173755, 0.9125470218368039, + 11.600000000000001, -0.10343674515391595, -0.36186569712437355, 0.06952650785852305, 0.9238615273414376, + 11.700000000000001, 0.007804559037678183, -0.35302288868798143, 0.09946025581253531, 0.9302803805489641, + 11.8, 0.1426412425253905, -0.3380213372056471, 0.13765318428594062, 0.9200253542052307, + 11.9, 0.28835875587704596, -0.3157889324819249, 0.17915319422583242, 0.8860195884006457, + 12, 0.4312436727052139, -0.28685045094613115, 0.219183264771386, 0.8268642028700216, + 12.100000000000001, 0.5589000253819172, -0.25355081728274853, 0.25379335347070786, 0.747617334214125, + 12.200000000000001, 0.6625314685998834, -0.21973391154205568, 0.280421858906862, 0.6588874276236646, + 12.3, 0.7380824019544231, -0.19006395318362243, 0.298062430272877, 0.5746902202797866, + 12.4, 0.7855753774460935, -0.169269141193261, 0.3068688818232648, 0.5099517364993114, + 12.5, 0.8114190217313466, -0.15839628167367298, 0.3088389006667134, 0.47024283360778063, + 12.600000000000001, 0.8262959099968311, -0.15322935014383765, 0.30728936847846444, 0.4464628533227737, + 12.700000000000001, 0.8332391589396612, -0.15259862329947516, 0.30303878672062, 0.43657033559270353, + 12.8, 0.8342394883377178, -0.15529642204284128, 0.2966287614913599, 0.4381082916983156, + 12.9, 0.8307519196185837, -0.16009477297221508, 0.28850552435179927, 0.4483140351756862, + 13, 0.8240296911447206, -0.16580756983190156, 0.2791238027707388, 0.4642982022635636, + 13.100000000000001, 0.8153706355023084, -0.17133873601017086, 0.269006194462171, 0.4831660497634117, + 13.200000000000001, 0.8062661061820637, -0.1757160250974464, 0.25875952490229237, 0.5020979514181533, + 13.3, 0.7984517779140391, -0.17810601568003942, 0.2490534045031854, 0.5183873139167897, + 13.4, 0.7938649046916416, -0.1778058611626899, 0.24056851204630192, 0.52942457427565, + 13.5, 0.7935671919474836, -0.1746254966129012, 0.23361293268448036, 0.5340243865965669, + 13.600000000000001, 0.7935224247585138, -0.17050985861785178, 0.2268085209004143, 0.5383367388228815, + 13.700000000000001, 0.7931392669611409, -0.1657221926243782, 0.21998001196091763, 0.5432081115132462, + 13.8, 0.7925869633829067, -0.1601939239948456, 0.21320230905013723, 0.5483507888261729, + 13.9, 0.7915761313675379, -0.15619392115666142, 0.2083238683667239, 0.5528217191026713, + 14, 0.7905526138949678, -0.15367673588862418, 0.20441362129005577, 0.5564396615460993, + 14.100000000000001, 0.790013639293712, -0.1513546176913871, 0.200362480815779, 0.5593077021772056, + 14.200000000000001, 0.7901576796556822, -0.14914265160057613, 0.196207729389728, 0.5611682792910029, + 14.3, 0.7911819264533698, -0.14696679063166562, 0.1919830349255833, 0.5617601231893599, + 14.4, 0.7932785903195773, -0.14476378282892327, 0.18771858515623965, 0.5608157077940883, + 14.5, 0.7966391260056421, -0.14247824103213824, 0.1834433114532673, 0.5580453433480241, + 14.600000000000001, 0.8016850514199598, -0.13998626586096757, 0.17924455647213433, 0.5527895735948594, + 14.700000000000001, 0.8082665744348602, -0.13735437396038203, 0.1750662647059742, 0.5451520187683302, + 14.8, 0.815958794652413, -0.1347339830027881, 0.1707888929516153, 0.5356203443652485, + 14.9, 0.8243455214793896, -0.13227097071139943, 0.16630011421907387, 0.5246933614356678, + 15, 0.8330296784122903, -0.13010487883197763, 0.1614946627764397, 0.5128876575656282, + 15.100000000000001, 0.8416404977499994, -0.1283673003157531, 0.1562731143458356, 0.5007412730037657, + 15.200000000000001, 0.8498373085262991, -0.12717952435781404, 0.15053963149684488, 0.4888146243410583, + 15.3, 0.8573096709144672, -0.12664946548780592, 0.14419874955876893, 0.4776889800632504, + 15.4, 0.863773614446678, -0.12686786799921362, 0.13715132248918915, 0.46796282095324865, + 15.5, 0.8689637830367286, -0.1279036957419353, 0.12928981708504877, 0.46024638139171353, + 15.600000000000001, 0.8729171080126423, -0.1297201756476976, 0.12057759333635522, 0.4545871121732205, + 15.700000000000001, 0.8761232275660844, -0.1321559625327215, 0.11110413302438643, 0.45010972363540036, + 15.8, 0.8786761985609237, -0.13516548327459846, 0.1008496253467368, 0.44664055266073993, + 15.9, 0.8806491769745997, -0.13870931045799106, 0.08978709734858797, 0.44402143128000493, + 16, 0.8821066692978742, -0.1427515976892017, 0.07788680662745101, 0.44208986721114657, + 16.1, 0.8831054266583971, -0.1472605886491663, 0.06511764464319697, 0.44067994825418794, + 16.2, 0.8837078730928298, -0.15088285816503716, 0.05265098684329775, 0.4399120727260424, + 16.3, 0.8839756660312651, -0.15339333115777418, 0.04127023919055074, 0.43972067858818875, + 16.400000000000002, 0.8839920740365718, -0.15576376699014038, 0.030268201837494693, 0.4397493580337398, + 16.5, 0.8838519347610062, -0.15799241473807155, 0.019648220371435807, 0.43983872242072414, + 16.6, 0.8835529799612515, -0.16008706696173503, 0.009380921455918484, 0.44002075054003903, + 16.7, 0.8826008577909064, -0.16205300106944306, -0.0007431995821290671, 0.44130941336609236, + 16.8, 0.8810494712786278, -0.16386324793469445, -0.010735449882067441, 0.44360502167105037, + 16.900000000000002, 0.8790639516216942, -0.1655013842461443, -0.02056209396042035, 0.44657928866420193, + 17, 0.8768105474041924, -0.16696584238613746, -0.03018557317273661, 0.44990499286991864, + 17.1, 0.8744586315449575, -0.1682691424520501, -0.039565127841200344, 0.4532573199341422, + 17.2, 0.8721814936211576, -0.16943706217551108, -0.04865742662488005, 0.45631456143798765, + 17.3, 0.8701559309962738, -0.17050772527968305, -0.05741710882958388, 0.45875815740497494, + 17.400000000000002, 0.8685606578960501, -0.17153058886752898, -0.06579716806652397, 0.4602720644492398, + 17.5, 0.8675735472259526, -0.17256531896260704, -0.07374910228233754, 0.46054144304032074, + 17.6, 0.8673743939646827, -0.17368171610208083, -0.08122024420757107, 0.45923805821937075, + 17.7, 0.8684404153380028, -0.17501698688707856, -0.08803767985860061, 0.45544447107593694, + 17.8, 0.870691834717031, -0.1766215598726277, -0.09422705412842129, 0.44924583004801466, + 17.900000000000002, 0.8737147071100198, -0.17846523031108308, -0.09993983088282996, 0.44134431270015945, + 18, 0.8771072836310416, -0.18049478304196895, -0.10533131443902503, 0.4324462515672384, + 18.1, 0.880491043404794, -0.18263750013008803, -0.11056226837764327, 0.42326711523736305, + 18.2, 0.8835159219474432, -0.18480326707412884, -0.11580019210979567, 0.41453309114161463, + 18.3, 0.8858596050942937, -0.18688520630825559, -0.12121998322367324, 0.4069796007081374, + 18.400000000000002, 0.8872207566340081, -0.18875873410071947, -0.12700374267828704, 0.40134712985666104, + 18.5, 0.8870791545579698, -0.19076184818232517, -0.13579931687269858, 0.3978178431942057, + 18.6, 0.8850536612404124, -0.19272232114643476, -0.14793522501063572, 0.39705578053709845, + 18.7, 0.88210630077556, -0.194207262623056, -0.1601489710718591, 0.39815112751459303, + 18.8, 0.8799275325870334, -0.1958521457738144, -0.17153904877234388, 0.39742147543554757, + 18.900000000000002, 0.8779714033314864, -0.19745852417743223, -0.18229337009013863, 0.3961634427644611, + 19, 0.8756248784029074, -0.19872965126325515, -0.19265212338966797, 0.3958190967906057, + 19.1, 0.8722756376006697, -0.19930567091898782, -0.20287131983684337, 0.39781363623628385, + 19.200000000000003, 0.8672846158630236, -0.19876895196443956, -0.21321505419064768, 0.403543850763167, + 19.3, 0.8599360705550634, -0.1966458701686457, -0.22394007156774787, 0.41435636914395957, + 19.400000000000002, 0.8493668441165748, -0.19240513476387552, -0.23527135988846543, 0.43151316949564494, + 19.5, 0.8344778558518805, -0.1854537381320896, -0.24736758494139047, 0.4561391202538394, + 19.6, 0.8138331617890655, -0.1751331039979646, -0.2602752053456938, 0.4891429219959213, + 19.700000000000003, 0.7846921563021088, -0.1602749902411784, -0.27413089040122474, 0.5323743065447176, + 19.8, 0.7389768993844568, -0.13737863441334214, -0.28974746908648674, 0.5925256594788408, + 19.900000000000002, 0.6750481961363872, -0.10682129821630587, -0.3049006935376056, 0.6632757422224032, + 20, 0.5940311129406909, -0.07035920241521051, -0.31706221507474086, 0.7359675069361677, + 20.1, 0.49921326878608474, -0.03041054265566663, -0.3243719925853828, 0.8028973294198258, + 20.200000000000003, 0.3961542702604587, 0.010143176784476916, -0.32599575155576904, 0.8583039555348161, + 20.3, 0.2921847408614224, 0.04830681924681446, -0.3222813157939426, 0.8991269553917979, + 20.400000000000002, 0.1955430875518302, 0.08133868730874558, -0.3146692062326356, 0.9252730459202357, + 20.5, 0.11449183809537226, 0.10699605996341494, -0.30537918267051706, 0.9392481125630943, + 20.6, 0.056730430364313564, 0.12356498961250467, -0.2969448152876766, 0.9451651328135782, + 20.700000000000003, 0.029275779846792895, 0.12965568878616782, -0.2916747921433784, 0.9472371121888455, + 20.8, 0.03713389867781724, 0.12635804209110568, -0.2921778928608792, 0.9472522355166362, + 20.900000000000002, 0.07597486091524928, 0.11626199827658162, -0.2985312466644934, 0.9442404688587478, + 21, 0.13809564624398693, 0.0980726783405286, -0.30698648209693713, 0.9365204974058591, + 21.1, 0.2160069962986056, 0.07352075896027499, -0.31557930273311663, 0.9210566645100828, + 21.200000000000003, 0.30190091499697236, 0.04465081882520493, -0.32257138759005644, 0.8959965635037085, + 21.3, 0.3880480097987539, 0.013856246649106339, -0.3268286709706944, 0.8616320365164905, + 21.400000000000002, 0.4674060006995052, -0.016242437669675466, -0.32805498945281186, 0.8207604629998672, + 21.5, 0.5341643580927372, -0.04299764863987044, -0.3268360484558285, 0.7784586297193934, + 21.6, 0.583930097245805, -0.06390653571517327, -0.3244770837588107, 0.7413880349309447, + 21.700000000000003, 0.6133504709693217, -0.07666120784091272, -0.32265180358692974, 0.7168124389379588, + 21.8, 0.621958018449096, -0.0803248930330997, -0.3225752576924416, 0.7089861338353171, + 21.900000000000002, 0.6161623508530293, -0.07749869189042609, -0.32394782923306553, 0.713719632686201, + 22, 0.5987818678760578, -0.06949223115501779, -0.32630953377168004, 0.7281161944921056, + 22.1, 0.5721094209977494, -0.05751165138303021, -0.3290562116675161, 0.7490695761568744, + 22.200000000000003, 0.5384909869391269, -0.04280194510281597, -0.3315933839047045, 0.7734605860878548, + 22.3, 0.5005641970320234, -0.026667101984526674, -0.33346725031974106, 0.7984509648598489, + 22.400000000000002, 0.4613606205932492, -0.010461178506956628, -0.33444743228093926, 0.8216945031766638, + 22.5, 0.4242898526070885, 0.004440299258745161, -0.3345570346580271, 0.8414451825745842, + 22.6, 0.3930403756574744, 0.016672925854721195, -0.3340471482336593, 0.8565359183381828, + 22.700000000000003, 0.3714366240421479, 0.024904106043190398, -0.3333160674227681, 0.8662072610063842, + 22.8, 0.36313752924371157, 0.02788653084494616, -0.3327713088599097, 0.8698371872091174, + 22.900000000000002, 0.3682991841869814, 0.025650895570142863, -0.33255765687910166, 0.8678151573547993, + 23, 0.3837282891686025, 0.019409484008025245, -0.33250699248083365, 0.8612868116798437, + 23.1, 0.4061014216001908, 0.011811994916959969, -0.3346319562128909, 0.8502726421751554, + 23.200000000000003, 0.4319814043056616, 0.005021521823946826, -0.3407741666569788, 0.8350088730019113, + 23.3, 0.4579234745532665, -0.0030372654407598053, -0.34561895966802897, 0.8190509148946088, + 23.400000000000002, 0.4809366150289463, -0.010900110344773, -0.34925770194332406, 0.8041145549934033, + 23.5, 0.49823837621255784, -0.01708669324327141, -0.35188194378322984, 0.7922409122371932, + 23.6, 0.5071728764347497, -0.02013019311016587, -0.35374452464889816, 0.7856432141978793, + 23.700000000000003, 0.5050420306443867, -0.018595674388908807, -0.3550624689239858, 0.7864587664577335, + 23.8, 0.4888541242880317, -0.011089079437157097, -0.3558660608155668, 0.7964031794533655, + 23.900000000000002, 0.4551259990956647, 0.003683534343208996, -0.35579926509224974, 0.8162436152777738, + 24, 0.40448506040674054, 0.024827186932872787, -0.3540391485260097, 0.8428711218257116, + 24.1, 0.3395075246888604, 0.05045824431228341, -0.3496984654972196, 0.8717221974284324, + 24.200000000000003, 0.26331924792778416, 0.07855305890666925, -0.3421520232567473, 0.8985679626986852, + 24.3, 0.1797678420847072, 0.10703642545960439, -0.3312362043974822, 0.9200594021438983, + 24.400000000000002, 0.09334580708495738, 0.1339178717270794, -0.3173458612355177, 0.9341542529413625, + 24.5, 0.008929181420615459, 0.15743732687999507, -0.3014209898354472, 0.9403611777985406, + 24.6, -0.06856092880708597, 0.1761738037431548, -0.28483245437072435, 0.9397513835333937, + 24.700000000000003, -0.13445019898925947, 0.1890780764457467, -0.269191865177845, 0.9347236836206719, + 24.8, -0.1844488952510596, 0.19540989180766533, -0.25611767231783816, 0.9285458077827247, + 24.900000000000002, -0.21695728385984536, 0.19522229536700392, -0.24648066382101372, 0.9241564124833789, + 25, -0.23742182018270397, 0.19029255356642694, -0.2392816974360784, 0.9220433247035679, + 25.1, -0.24817996780549975, 0.18134025179357888, -0.23391223773957104, 0.9223922602099225, + 25.200000000000003, -0.2512186580514651, 0.16888383631518725, -0.22969945251773854, 0.9249895119358583, + 25.3, -0.24847676839161237, 0.15335871087230413, -0.2259239688622168, 0.9293539485377948, + 25.400000000000002, -0.2414609977516161, 0.1369973269449718, -0.2225555680185413, 0.9345572952573165, + 25.5, -0.23093370345476796, 0.12560423030256035, -0.22114544884970683, 0.9391421044718571, + 25.6, -0.2201030141646485, 0.11448712959395849, -0.2195740075408293, 0.9435224509917253, + 25.700000000000003, -0.21101101540317968, 0.10406663845153304, -0.21760711093421214, 0.9472547869558552, + 25.8, -0.20572692670036777, 0.09474797015341663, -0.21509469471365236, 0.9499650130864132, + 25.900000000000002, -0.20580422297193918, 0.086794121449366, -0.21200122808527924, 0.9514025864895905, + 26, -0.20728257418722573, 0.0792359304564174, -0.20878097102925258, 0.9524526801364493, + 26.1, -0.20890788832354473, 0.07174516708550173, -0.20554676763262783, 0.9533942791478502, + 26.200000000000003, -0.21070518066482474, 0.06428321024022157, -0.20228427205686308, 0.9542285203244765, + 26.3, -0.2126992009237447, 0.056810627411537244, -0.1989791442440866, 0.9549549218132752, + 26.400000000000002, -0.21491454768667917, 0.049286474031641846, -0.19561684122378234, 0.9555713642108516, + 26.5, -0.217375773819389, 0.04166753982343298, -0.19218239539726165, 0.9560740117694106, + 26.6, -0.22010748364665567, 0.0339075222896977, -0.18866017799553458, 0.9564571672655311, + 26.700000000000003, -0.2231344233468726, 0.02595609599759116, -0.18503363742516746, 0.9567130516614866, + 26.8, -0.22648156335239047, 0.01775784878038131, -0.18128500839584702, 0.9568314930012849, + 26.900000000000002, -0.2301745562745589, 0.009251121387412579, -0.17739497541910848, 0.9567994111060789, + 27, -0.2345459223607131, 0.00042202518547417717, -0.17334218076283361, 0.9565252325825444, + 27.1, -0.2397371710465477, -0.008791985912791449, -0.16911302665432565, 0.9559547970579577, + 27.200000000000003, -0.24555276960992437, -0.018525540427990428, -0.16469021860172983, 0.9551113932864903, + 27.3, -0.251797734122386, -0.028923557847150054, -0.16004518209898655, 0.9540161783634473, + 27.400000000000002, -0.25827801281407164, -0.04014371067597356, -0.1551361401900636, 0.9526876343255993, + 27.5, -0.26480075153268695, -0.05235927649664873, -0.1499054748629852, 0.9511400615884995, + 27.6, -0.27117441154437866, -0.06576235904986227, -0.1442762249620151, 0.9493809148947893, + 27.700000000000003, -0.27745494584286867, -0.08210432753008022, -0.13750603658799546, 0.9472960056550567, + 27.8, -0.2839231108466924, -0.10489679161076483, -0.12809332231540582, 0.9444450386417974, + 27.900000000000002, -0.28884331329282215, -0.12451042845215224, -0.11999652641157305, 0.9416302497381034, + 28, -0.2936596721843858, -0.14157818476138417, -0.11302663291958004, 0.9385864876414388, + 28.1, -0.30196080211805887, -0.15632410580422967, -0.10753231007080652, 0.9342479597085361, + 28.200000000000003, -0.3124386997786558, -0.16943556755397898, -0.10323370814226623, 0.9289867861447122, + 28.3, -0.32346700138116535, -0.18150092889350564, -0.09972873119921363, 0.923298809704457, + 28.400000000000002, -0.33343981129173417, -0.19301947501110728, -0.09655271344948832, 0.9177357724518044, + 28.5, -0.3407787519282435, -0.20443523332521302, -0.09318187866864103, 0.9129037271789819, + 28.6, -0.34392839231451144, -0.21615582773983438, -0.08902544395037218, 0.9094308051872345, + 28.700000000000003, -0.34134025573588067, -0.22855732608046547, -0.08340670274301326, 0.907905116433788, + 28.8, -0.3314479714099161, -0.241974739098902, -0.07553201172098656, 0.9087823628854439, + 28.900000000000002, -0.31264040199391196, -0.256676127145548, -0.06444545052285347, 0.9122609981258402, + 29, -0.2828810033276124, -0.27283526786250323, -0.04885705284212366, 0.9182332181719094, + 29.1, -0.23754408311458275, -0.29047509152540096, -0.026340989906403156, 0.9265544679247482, + 29.200000000000003, -0.17849451517445208, -0.3089355588869762, 0.004035906226898256, 0.9341746303388657, + 29.3, -0.10974403675336492, -0.3275321980072597, 0.04292767455713392, 0.9374625968126549, + 29.400000000000002, -0.03601004133140633, -0.345892906326113, 0.09144763968288808, 0.933112374514996, + 29.5, 0.03706564918267122, -0.3641920311550104, 0.15171395686383027, 0.9181357075000269, + 29.6, 0.10249196669818912, -0.38332932771198647, 0.2277924299554667, 0.8891932479125095, + 29.700000000000003, 0.15087636350782774, -0.4046948384535172, 0.32677174069651416, 0.8406418025210889, + 29.8, 0.16881151361728666, -0.42808331370548564, 0.45697830616533924, 0.7611952292884058, + 29.900000000000002, 0.1423466349130348, -0.44576957339756496, 0.6122577860814612, 0.6373125813480508, + 30, 0.09343174999255299, -0.4420021955623113, 0.7327630102924036, 0.5088840122843713 + ] + } + } +] \ No newline at end of file diff --git a/Apps/Sandcastle/Sandcastle-header.js b/Apps/Sandcastle/Sandcastle-header.js index 5c9c0ad51570..9ab0530ec2aa 100644 --- a/Apps/Sandcastle/Sandcastle-header.js +++ b/Apps/Sandcastle/Sandcastle-header.js @@ -105,7 +105,7 @@ ) ) { window.location = - "https://github.com/CesiumGS/cesium/wiki/Contributor%27s-Guide"; + "https://github.com/CesiumGS/cesium/blob/main/Documentation/Contributors/BuildGuide/README.md#quickstart"; } } })(); diff --git a/Apps/Sandcastle/gallery/3D Tiles NGA GPM Visualization.html b/Apps/Sandcastle/gallery/3D Tiles NGA GPM Visualization.html new file mode 100644 index 000000000000..40f008469ef3 --- /dev/null +++ b/Apps/Sandcastle/gallery/3D Tiles NGA GPM Visualization.html @@ -0,0 +1,1351 @@ + + + + + + + + + Cesium Demo + + + + + + + +
+
+

Loading...

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Cesium GPM Visualization

+
Data set + + + +
Anchor point ellipsoid + + + +
Shader mode + +
+
+ Uncertainty information is stored as GPM metadata in the tiles.
+
+ The anchor points provide information about the low-frequency + error.
+ This error is visualized as ellipsoids.
+
+ The high-frequency error is represented as + Per-Point Error textures.
+ This error can be visualized with custom shaders. The 'uncertainty'
+ shaders visualize the horizontal or vertical uncertainty with a color
+ scale. The 'threshold' shaders highlight areas where the selected
+ error threshold is exceeded. Picking a point on the tileset will show
+ a label with the actual error values. +
+
+ + + diff --git a/Apps/Sandcastle/gallery/3D Tiles NGA GPM Visualization.jpg b/Apps/Sandcastle/gallery/3D Tiles NGA GPM Visualization.jpg new file mode 100644 index 000000000000..5b2daea52ce0 Binary files /dev/null and b/Apps/Sandcastle/gallery/3D Tiles NGA GPM Visualization.jpg differ diff --git a/Apps/Sandcastle/gallery/3D Tiles Vertical Exaggeration.html b/Apps/Sandcastle/gallery/3D Tiles Vertical Exaggeration.html index 4e636b2f001c..41f67a60a1b6 100644 --- a/Apps/Sandcastle/gallery/3D Tiles Vertical Exaggeration.html +++ b/Apps/Sandcastle/gallery/3D Tiles Vertical Exaggeration.html @@ -78,6 +78,7 @@

Loading...

animation: false, sceneModePicker: false, baseLayerPicker: false, + geocoder: Cesium.IonGeocodeProviderType.GOOGLE, // The globe does not need to be displayed, // since the Photorealistic 3D Tiles include terrain globe: false, @@ -104,7 +105,10 @@

Loading...

// Add Photorealistic 3D Tiles try { - const tileset = await Cesium.createGooglePhotorealistic3DTileset(); + const tileset = await Cesium.createGooglePhotorealistic3DTileset({ + // Only the Google Geocoder can be used with Google Photorealistic 3D Tiles. Set the `geocode` property of the viewer constructor options to IonGeocodeProviderType.GOOGLE. + onlyUsingWithGoogleGeocoder: true, + }); scene.primitives.add(tileset); } catch (error) { console.log(`Error loading Photorealistic 3D Tiles tileset. diff --git a/Apps/Sandcastle/gallery/AEC Architectural Design.html b/Apps/Sandcastle/gallery/AEC Architectural Design.html new file mode 100644 index 000000000000..a1aff825bb57 --- /dev/null +++ b/Apps/Sandcastle/gallery/AEC Architectural Design.html @@ -0,0 +1,250 @@ + + + + + + + + + + Cesium Demo + + + + + + +
+

Loading...

+
+ + + diff --git a/Apps/Sandcastle/gallery/AEC Architectural Design.jpg b/Apps/Sandcastle/gallery/AEC Architectural Design.jpg new file mode 100644 index 000000000000..e6753bb4f5c9 Binary files /dev/null and b/Apps/Sandcastle/gallery/AEC Architectural Design.jpg differ diff --git a/Apps/Sandcastle/gallery/AEC Clipping.html b/Apps/Sandcastle/gallery/AEC Clipping.html index 0fa60bf14964..d373bd2a589a 100644 --- a/Apps/Sandcastle/gallery/AEC Clipping.html +++ b/Apps/Sandcastle/gallery/AEC Clipping.html @@ -32,6 +32,7 @@ animation: false, sceneModePicker: false, baseLayerPicker: false, + geocoder: Cesium.IonGeocodeProviderType.GOOGLE, // The globe does not need to be displayed, // since the Photorealistic 3D Tiles include terrain globe: false, @@ -48,7 +49,10 @@ // Add Photorealistic 3D Tiles let googleTileset; try { - googleTileset = await Cesium.createGooglePhotorealistic3DTileset(); + googleTileset = await Cesium.createGooglePhotorealistic3DTileset({ + // Only the Google Geocoder can be used with Google Photorealistic 3D Tiles. Set the `geocode` property of the viewer constructor options to IonGeocodeProviderType.GOOGLE. + onlyUsingWithGoogleGeocoder: true, + }); viewer.scene.primitives.add(googleTileset); } catch (error) { console.log(`Error loading Photorealistic 3D Tiles tileset. diff --git a/Apps/Sandcastle/gallery/AEC Isolate by Category.html b/Apps/Sandcastle/gallery/AEC Isolate by Category.html new file mode 100644 index 000000000000..70170c1c7fc6 --- /dev/null +++ b/Apps/Sandcastle/gallery/AEC Isolate by Category.html @@ -0,0 +1,165 @@ + + + + + + + + + + Cesium Demo + + + + + + +
+

Loading...

+
+ + + diff --git a/Apps/Sandcastle/gallery/AEC Isolate by Category.jpg b/Apps/Sandcastle/gallery/AEC Isolate by Category.jpg new file mode 100644 index 000000000000..81f2db7cedf7 Binary files /dev/null and b/Apps/Sandcastle/gallery/AEC Isolate by Category.jpg differ diff --git a/Apps/Sandcastle/gallery/AEC Metadata Styling.html b/Apps/Sandcastle/gallery/AEC Metadata Styling.html new file mode 100644 index 000000000000..ff8dd8fe0cc6 --- /dev/null +++ b/Apps/Sandcastle/gallery/AEC Metadata Styling.html @@ -0,0 +1,205 @@ + + + + + + + + + + Cesium Demo + + + + + + +
+

Loading...

+
+
+ + +
+
+ + +
+
+ + + diff --git a/Apps/Sandcastle/gallery/AEC Metadata Styling.jpg b/Apps/Sandcastle/gallery/AEC Metadata Styling.jpg new file mode 100644 index 000000000000..4fa9750411e0 Binary files /dev/null and b/Apps/Sandcastle/gallery/AEC Metadata Styling.jpg differ diff --git a/Apps/Sandcastle/gallery/Ambient Occlusion.html b/Apps/Sandcastle/gallery/Ambient Occlusion.html index c6017addff93..4737974cff33 100644 --- a/Apps/Sandcastle/gallery/Ambient Occlusion.html +++ b/Apps/Sandcastle/gallery/Ambient Occlusion.html @@ -62,38 +62,38 @@ - Step Size + Step Count - Bias + Direction Count - Blur Step Size + Bias @@ -106,7 +106,11 @@ //Sandcastle_Begin const viewer = new Cesium.Viewer("cesiumContainer"); - viewer.clock.currentTime = Cesium.JulianDate.fromIso8601("2022-08-01T00:00:00Z"); + const { canvas, camera, clock, scene } = viewer; + camera.frustum.near = 1.0; + scene.debugShowFramesPerSecond = true; + + clock.currentTime = Cesium.JulianDate.fromIso8601("2022-08-01T00:00:00Z"); if (!Cesium.PostProcessStageLibrary.isAmbientOcclusionSupported(viewer.scene)) { window.alert( @@ -119,9 +123,9 @@ ambientOcclusionOnly: false, intensity: 3.0, bias: 0.1, - lengthCap: 0.03, - stepSize: 1.0, - blurStepSize: 0.86, + lengthCap: 0.26, + directionCount: 8, + stepCount: 32, }; Cesium.knockout.track(viewModel); @@ -134,7 +138,7 @@ } function updatePostProcess() { - const ambientOcclusion = viewer.scene.postProcessStages.ambientOcclusion; + const ambientOcclusion = scene.postProcessStages.ambientOcclusion; ambientOcclusion.enabled = Boolean(viewModel.show) || Boolean(viewModel.ambientOcclusionOnly); ambientOcclusion.uniforms.ambientOcclusionOnly = Boolean( @@ -143,12 +147,11 @@ ambientOcclusion.uniforms.intensity = Number(viewModel.intensity); ambientOcclusion.uniforms.bias = Number(viewModel.bias); ambientOcclusion.uniforms.lengthCap = Number(viewModel.lengthCap); - ambientOcclusion.uniforms.stepSize = Number(viewModel.stepSize); - ambientOcclusion.uniforms.blurStepSize = Number(viewModel.blurStepSize); + ambientOcclusion.uniforms.directionCount = Number(viewModel.directionCount); + ambientOcclusion.uniforms.stepCount = Number(viewModel.stepCount); } updatePostProcess(); - const camera = viewer.scene.camera; camera.position = new Cesium.Cartesian3( 1234127.2294710164, -5086011.666443127, @@ -173,7 +176,7 @@ try { // Power Plant design model provided by Bentley Systems const tileset = await Cesium.Cesium3DTileset.fromIonAssetId(2464651); - viewer.scene.primitives.add(tileset); + scene.primitives.add(tileset); } catch (error) { console.log(`Error loading tileset: ${error}`); } //Sandcastle_End diff --git a/Apps/Sandcastle/gallery/Bing Maps Labels Only.html b/Apps/Sandcastle/gallery/Bing Maps Labels Only.html index f4c12739f24f..7f92188196ba 100644 --- a/Apps/Sandcastle/gallery/Bing Maps Labels Only.html +++ b/Apps/Sandcastle/gallery/Bing Maps Labels Only.html @@ -67,6 +67,7 @@ baseLayer: false, baseLayerPicker: false, infoBox: false, + geocoder: Cesium.IonGeocodeProviderType.BING, }); const layers = viewer.imageryLayers; diff --git a/Apps/Sandcastle/gallery/Callback Position Property.html b/Apps/Sandcastle/gallery/Callback Position Property.html index 272509b8b934..4786dfd84822 100644 --- a/Apps/Sandcastle/gallery/Callback Position Property.html +++ b/Apps/Sandcastle/gallery/Callback Position Property.html @@ -134,7 +134,7 @@ } // Create the entity and bind its position to the callback position property - viewer.entities.add({ + const entity = viewer.entities.add({ availability: new Cesium.TimeIntervalCollection([ new Cesium.TimeInterval({ start: start, @@ -158,35 +158,11 @@ leadTime: 1, trailTime: 0.1, }, + trackingReferenceFrame: Cesium.TrackingReferenceFrame.INERTIAL, + viewFrom: new Cesium.Cartesian3(-100, 0, 10), }); - const camera = viewer.camera; - const scene = viewer.scene; - - const scratchPosition = new Cesium.Cartesian3(); - const scratchOrientation = new Cesium.Quaternion(); - const scratchTransform = new Cesium.Matrix4(); - const offset = new Cesium.Cartesian3(-100, 0, 10); - - // Update camera to follow entity's position and orientation - viewer.clock.onTick.addEventListener(function (clock) { - if (scene.mode === Cesium.Scene.MORPHING) { - return; - } - const time = clock.currentTime; - const entityPosition = position.getValue(time, scratchPosition); - const entityOrientation = orientation.getValue(time, scratchOrientation); - if (entityPosition === undefined || entityOrientation === undefined) { - return; - } - const transform = Cesium.Matrix4.fromTranslationQuaternionRotationScale( - entityPosition, - entityOrientation, - Cesium.Cartesian3.ONE, - scratchTransform, - ); - camera.lookAtTransform(transform, offset); - }); + viewer.trackedEntity = entity; //Sandcastle_End }; if (typeof Cesium !== "undefined") { diff --git a/Apps/Sandcastle/gallery/Clamp Entities to Ground.html b/Apps/Sandcastle/gallery/Clamp Entities to Ground.html index 0a048fbe0d93..e38e8709c464 100644 --- a/Apps/Sandcastle/gallery/Clamp Entities to Ground.html +++ b/Apps/Sandcastle/gallery/Clamp Entities to Ground.html @@ -41,6 +41,7 @@ timeline: false, animation: false, baseLayerPicker: false, + geocoder: Cesium.IonGeocodeProviderType.GOOGLE, }); const scene = viewer.scene; scene.globe.depthTestAgainstTerrain = true; @@ -56,7 +57,10 @@ let worldTileset; try { - worldTileset = await Cesium.createGooglePhotorealistic3DTileset(); + worldTileset = await Cesium.createGooglePhotorealistic3DTileset({ + // Only the Google Geocoder can be used with Google Photorealistic 3D Tiles. Set the `geocode` property of the viewer constructor options to IonGeocodeProviderType.GOOGLE. + onlyUsingWithGoogleGeocoder: true, + }); viewer.scene.primitives.add(worldTileset); } catch (error) { console.log(`Error loading Photorealistic 3D Tiles tileset. diff --git a/Apps/Sandcastle/gallery/Clipping Regions.html b/Apps/Sandcastle/gallery/Clipping Regions.html index 97dba26b3ce9..f56a5c886b27 100644 --- a/Apps/Sandcastle/gallery/Clipping Regions.html +++ b/Apps/Sandcastle/gallery/Clipping Regions.html @@ -43,6 +43,7 @@ animation: false, sceneModePicker: false, baseLayerPicker: false, + geocoder: Cesium.IonGeocodeProviderType.GOOGLE, }); const scene = viewer.scene; @@ -60,7 +61,10 @@ let worldTileset; try { - worldTileset = await Cesium.createGooglePhotorealistic3DTileset(); + worldTileset = await Cesium.createGooglePhotorealistic3DTileset({ + // Only the Google Geocoder can be used with Google Photorealistic 3D Tiles. Set the `geocode` property of the viewer constructor options to IonGeocodeProviderType.GOOGLE. + onlyUsingWithGoogleGeocoder: true, + }); scene.primitives.add(worldTileset); } catch (error) { console.log(`Error loading Photorealistic 3D Tiles tileset. diff --git a/Apps/Sandcastle/gallery/Entity tracking.html b/Apps/Sandcastle/gallery/Entity tracking.html new file mode 100644 index 000000000000..6e894c642e9d --- /dev/null +++ b/Apps/Sandcastle/gallery/Entity tracking.html @@ -0,0 +1,117 @@ + + + + + + + + + Cesium Demo + + + + + + +
+

Loading...

+
+ + + diff --git a/Apps/Sandcastle/gallery/Entity tracking.jpg b/Apps/Sandcastle/gallery/Entity tracking.jpg new file mode 100644 index 000000000000..4fe477db6de5 Binary files /dev/null and b/Apps/Sandcastle/gallery/Entity tracking.jpg differ diff --git a/Apps/Sandcastle/gallery/Globe Interior.html b/Apps/Sandcastle/gallery/Globe Interior.html index 0deb07a51e34..9a4ff467d784 100644 --- a/Apps/Sandcastle/gallery/Globe Interior.html +++ b/Apps/Sandcastle/gallery/Globe Interior.html @@ -34,6 +34,7 @@ //Sandcastle_Begin const viewer = new Cesium.Viewer("cesiumContainer", { orderIndependentTranslucency: false, + geocoder: Cesium.IonGeocodeProviderType.BING, }); const scene = viewer.scene; diff --git a/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles with Building Insert.html b/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles with Building Insert.html index 6437a2fb7c19..a75c993a8afa 100644 --- a/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles with Building Insert.html +++ b/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles with Building Insert.html @@ -32,6 +32,7 @@ animation: false, sceneModePicker: false, baseLayerPicker: false, + geocoder: Cesium.IonGeocodeProviderType.GOOGLE, // The globe does not need to be displayed, // since the Photorealistic 3D Tiles include terrain globe: false, @@ -42,7 +43,10 @@ // Add Photorealistic 3D Tiles try { - const googleTileset = await Cesium.createGooglePhotorealistic3DTileset(); + const googleTileset = await Cesium.createGooglePhotorealistic3DTileset({ + // Only the Google Geocoder can be used with Google Photorealistic 3D Tiles. Set the `geocode` property of the viewer constructor options to IonGeocodeProviderType.GOOGLE. + onlyUsingWithGoogleGeocoder: true, + }); viewer.scene.primitives.add(googleTileset); } catch (error) { console.log(`Error loading Photorealistic 3D Tiles tileset. diff --git a/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles.html b/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles.html index d4d68c1c97d6..2f9da653dc9c 100644 --- a/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles.html +++ b/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles.html @@ -32,6 +32,7 @@ animation: false, sceneModePicker: false, baseLayerPicker: false, + geocoder: Cesium.IonGeocodeProviderType.GOOGLE, // The globe does not need to be displayed, // since the Photorealistic 3D Tiles include terrain globe: false, @@ -42,7 +43,10 @@ // Add Photorealistic 3D Tiles try { - const tileset = await Cesium.createGooglePhotorealistic3DTileset(); + const tileset = await Cesium.createGooglePhotorealistic3DTileset({ + // Only the Google Geocoder can be used with Google Photorealistic 3D Tiles. Set the `geocode` property of the viewer constructor options to IonGeocodeProviderType.GOOGLE. + onlyUsingWithGoogleGeocoder: true, + }); viewer.scene.primitives.add(tileset); } catch (error) { console.log(`Error loading Photorealistic 3D Tiles tileset. diff --git a/Apps/Sandcastle/gallery/Imagery Color To Alpha.html b/Apps/Sandcastle/gallery/Imagery Color To Alpha.html index 8fa3ed032883..c28533a3c4a9 100644 --- a/Apps/Sandcastle/gallery/Imagery Color To Alpha.html +++ b/Apps/Sandcastle/gallery/Imagery Color To Alpha.html @@ -51,7 +51,9 @@ window.startup = async function (Cesium) { "use strict"; //Sandcastle_Begin - const viewer = new Cesium.Viewer("cesiumContainer"); + const viewer = new Cesium.Viewer("cesiumContainer", { + geocoder: Cesium.IonGeocodeProviderType.BING, + }); const layers = viewer.scene.imageryLayers; diff --git a/Apps/Sandcastle/gallery/Imagery Layers Manipulation.html b/Apps/Sandcastle/gallery/Imagery Layers Manipulation.html index 4e309a339dd7..9b1f026cdbab 100644 --- a/Apps/Sandcastle/gallery/Imagery Layers Manipulation.html +++ b/Apps/Sandcastle/gallery/Imagery Layers Manipulation.html @@ -106,6 +106,7 @@ //Sandcastle_Begin const viewer = new Cesium.Viewer("cesiumContainer", { baseLayerPicker: false, + geocoder: false, }); const imageryLayers = viewer.imageryLayers; diff --git a/Apps/Sandcastle/gallery/Imagery Layers Split.html b/Apps/Sandcastle/gallery/Imagery Layers Split.html index 37927116fc29..15375661bb5f 100644 --- a/Apps/Sandcastle/gallery/Imagery Layers Split.html +++ b/Apps/Sandcastle/gallery/Imagery Layers Split.html @@ -58,6 +58,7 @@ ), baseLayerPicker: false, infoBox: false, + geocoder: false, }); const layers = viewer.imageryLayers; diff --git a/Apps/Sandcastle/gallery/Interpolation.html b/Apps/Sandcastle/gallery/Interpolation.html index d0559b27d7a8..f21a5dd259c3 100644 --- a/Apps/Sandcastle/gallery/Interpolation.html +++ b/Apps/Sandcastle/gallery/Interpolation.html @@ -154,6 +154,21 @@ viewer.trackedEntity = entity; }); + Sandcastle.addToolbarMenu([ + { + text: "Tracking reference frame: East-North-Up", + onselect: function () { + entity.trackingReferenceFrame = Cesium.TrackingReferenceFrame.ENU; + }, + }, + { + text: "Tracking reference frame: Inertial", + onselect: function () { + entity.trackingReferenceFrame = Cesium.TrackingReferenceFrame.INERTIAL; + }, + }, + ]); + //Add a combo box for selecting each interpolation mode. Sandcastle.addToolbarMenu( [ diff --git a/Apps/Sandcastle/gallery/development/3D Tiles Picking.html b/Apps/Sandcastle/gallery/development/3D Tiles Picking.html index 10c3b2367a66..ce77a1cc5f35 100644 --- a/Apps/Sandcastle/gallery/development/3D Tiles Picking.html +++ b/Apps/Sandcastle/gallery/development/3D Tiles Picking.html @@ -34,6 +34,7 @@ animation: false, baseLayerPicker: false, globe: false, + geocoder: false, }); const scene = viewer.scene; @@ -44,7 +45,10 @@ onselect: async () => { scene.primitives.remove(tileset); try { - tileset = await Cesium.createGooglePhotorealistic3DTileset(); + tileset = await Cesium.createGooglePhotorealistic3DTileset({ + // Only the Google Geocoder can be used with Google Photorealistic 3D Tiles. Set the `geocode` property of the viewer constructor options to IonGeocodeProviderType.GOOGLE. + onlyUsingWithGoogleGeocoder: true, + }); scene.primitives.add(tileset); } catch (error) { console.log(error); diff --git a/Apps/Sandcastle/gallery/iModel Mesh Export Service.html b/Apps/Sandcastle/gallery/iModel Mesh Export Service.html new file mode 100644 index 000000000000..b445ff763ad7 --- /dev/null +++ b/Apps/Sandcastle/gallery/iModel Mesh Export Service.html @@ -0,0 +1,322 @@ + + + + + + + + + iModel Mesh Export Service + + + + + +
+

Loading...

+
+
+
+
+
+ + + diff --git a/Apps/Sandcastle/gallery/iModel Mesh Export Service.jpg b/Apps/Sandcastle/gallery/iModel Mesh Export Service.jpg new file mode 100644 index 000000000000..ec74f8279e2b Binary files /dev/null and b/Apps/Sandcastle/gallery/iModel Mesh Export Service.jpg differ diff --git a/CHANGES.md b/CHANGES.md index 0cdd0ec2e29c..c2fad0a5d1c1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,56 @@ # Change Log +### 1.124 - 2024-12-02 + +#### @cesium/engine + +##### Additions :tada: + +- Added an integration with the [iTwin Platform](https://developer.bentley.com/) to load iModels as 3D Tiles. Use `ITwinPlatform.defaultAccessToken` to set the access token. Use `ITwinData.createTilesetFromIModelId(iModelId)` to load the iModel as a `Cesium3DTileset`. [#12289](https://github.com/CesiumGS/cesium/pull/12289) +- Added `getSample` to `SampledProperty` to get the time of samples. [#12253](https://github.com/CesiumGS/cesium/pull/12253) +- Added `Entity.trackingReferenceFrame` property to allow tracking entities in various reference frames. [#12194](https://github.com/CesiumGS/cesium/pull/12194), [#12314](https://github.com/CesiumGS/cesium/pull/12314) + - `TrackingReferenceFrame.AUTODETECT` (default): uses either VVLH or ENU depending on entity's dynamic. Use `TrackingReferenceFrame.ENU` if your camera orientation flips abruptly from time to time. + - `TrackingReferenceFrame.ENU`: uses the entity's local East-North-Up reference frame. + - `TrackingReferenceFrame.INERTIAL`: uses the entity's inertial reference frame. + - `TrackingReferenceFrame.VELOCITY`: uses entity's `VelocityOrientationProperty` as orientation. +- Added `GoogleGeocoderService` for standalone usage of Google geocoder. [#12299](https://github.com/CesiumGS/cesium/pull/12299) + +##### Breaking Changes :mega: + +- `PostProcessStageCollection.ambientOcclusion` has been updated with a new algorithm to provide better results at all scales, with tunable performance cost. To approximate the appearance and performance of the old algorithm, set the following values for `scene.postProcessStages.ambientOcclusion.uniforms`: `{ lengthCap: 0.02, directionCount: 6, stepCount: 8 }`. For best results at long distances, consider setting `Viewer.camera.frustum.near` to `1.0` or more, to improve precision in the depth buffer. [#12316](https://github.com/CesiumGS/cesium/pull/12316) +- `Rectangle.validate` has been removed. + +##### Fixes :wrench: + +- Fixed bug where shared external textures from glTF files were not accounted for in resource statistics. [#12331](https://github.com/CesiumGS/cesium/pull/12331) +- Fixed lag or crashes when loading many models in the same frame. [#12320](https://github.com/CesiumGS/cesium/pull/12320) +- Fix point cloud filtering performance on certain hardware [#12317](https://github.com/CesiumGS/cesium/pull/12317) +- Fix label rendering bug in WebGL1 contexts. [#12301](https://github.com/CesiumGS/cesium/pull/12301) +- Updated WMS example URL in UrlTemplateImageryProvider documentation to use an active service. [#12323](https://github.com/CesiumGS/cesium/pull/12323) + +##### Deprecated :hourglass_flowing_sand: + +- `createGooglePhotorealistic3DTileset(key)` has been deprecated. Use `createGooglePhotorealistic3DTileset({key})` instead. It will be removed in 1.126. + +#### @cesium/widgets + +##### Additions :tada: + +- Added the ability to choose between Bing and Google geocoders. Updated `Viewer` constructor to also accept `IonGeocoderProvider` [#12299](https://github.com/CesiumGS/cesium/pull/12299) + +##### Fixes :wrench: + +- Added a `DeveloperError` when `globe` is set to `false` and a `baseLayer` is provided in `Viewer` options. This prevents errors caused by attempting to use a `baseLayer` without a globe. [#12274](https://github.com/CesiumGS/cesium/pull/12274) + +### 1.123.1 - 2024-11-07 + +#### @cesium/engine + +##### Additions :tada: + +- Added fallback diffuse lighting, `DynamicEnvironmentMapManager.DEFAULT_SPHERICAL_HARMONIC_COEFFICIENTS`, that is used when `DynamicEnvironmentMapManager` is disabled or unsupported. [#12292](https://github.com/CesiumGS/cesium/pull/12292) +- Added `DynamicEnvironmentMapManager.isDynamicUpdateSupported` to check if dynamic environment map updates are supported. [#12292](https://github.com/CesiumGS/cesium/pull/12292) + ### 1.123 - 2024-11-01 #### @cesium/engine @@ -37,9 +88,12 @@ - Fix flickering issue caused by bounding sphere retrieval being blocked by the bounding sphere of another entity. [#12230](https://github.com/CesiumGS/cesium/pull/12230) - Fixed `ImageBasedLighting.imageBasedLightingFactor` not affecting lighting. [#12129](https://github.com/CesiumGS/cesium/pull/12129) - - Fix error with normalization of corner points for lines and corridors with collinear points. [#12255](https://github.com/CesiumGS/cesium/pull/12255) +##### Fixes :wrench: + +- Properly handle `offset` and `scale` properties when picking metadata from property textures. [#12237](https://github.com/CesiumGS/cesium/pull/12237) + ### 1.122 - 2024-10-01 #### @cesium/engine diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 5bd6a8a5cdaf..bc8598aeda78 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -168,6 +168,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to Cesiu - [Siddhesh Ranade](https://github.com/siddheshranade) - [Adam Morris](https://github.com/weegeekps) - [Luke McKinstry](https://github.com/lukemckinstry) + - [Ryan Veenstra](https://github.com/r-veenstra) - [Northrop Grumman](http://www.northropgrumman.com) - [Joseph Stein](https://github.com/nahgrin) - [EOX IT Services GmbH](https://eox.at) @@ -414,4 +415,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to Cesiu - [Adam Wirth](https://github.com/adamwirth) - [Javier Sanchez](https://github.com/jvrjsanchez) - [Jérôme Fayot](https://github.com/jfayot) +- [Michael Nusair](https://github.com/mnpcmw6444) - [Kirn Kim](https://github.com/squrki) +- [Emanuele Mastaglia](https://github.com/Masty88) +- [Connor Manning](https://github.com/connormanning) diff --git a/Documentation/Contributors/VSCodeGuide/README.md b/Documentation/Contributors/VSCodeGuide/README.md index c759beb8da91..51d4931c6c3c 100644 --- a/Documentation/Contributors/VSCodeGuide/README.md +++ b/Documentation/Contributors/VSCodeGuide/README.md @@ -46,6 +46,10 @@ restart VSCode after you are done installing extensions. - **[Shader languages support for VS Code](https://marketplace.visualstudio.com/items?itemName=slevesque.shader)** by slevesque - This extension provides syntax highlighting for CesiumJS's shader code. - **[glTF Extension for VS Code](https://marketplace.visualstudio.com/items?itemName=cesium.gltf-vscode)** by CesiumJS.org - This extension adds features for previewing and editing 3D models in glTF files. +## Snippets + +We have a small (but growing) collection of snippets to make it easier to write code in CesiumJS. For example, `pragdebug` which will expand to the debug pragma we use to strip out code in production builds. These are stored in `.vscode/cesiumjs.code-snippets`. Refer to that file for the full list available and feel free to add to it for common code constructs you find yourself writing. + ## VSCode Tasks and Files You can launch any of CesiumJS's npm tasks from within VSCode by pressing diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithSharedTextures/plane-0.glb b/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithSharedTextures/plane-0.glb new file mode 100644 index 000000000000..084e4ffb427b Binary files /dev/null and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithSharedTextures/plane-0.glb differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithSharedTextures/plane-1.glb b/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithSharedTextures/plane-1.glb new file mode 100644 index 000000000000..e322a254caeb Binary files /dev/null and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithSharedTextures/plane-1.glb differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithSharedTextures/plane-2.glb b/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithSharedTextures/plane-2.glb new file mode 100644 index 000000000000..9463bfd11fbf Binary files /dev/null and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithSharedTextures/plane-2.glb differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithSharedTextures/plane-3.glb b/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithSharedTextures/plane-3.glb new file mode 100644 index 000000000000..05df860076b5 Binary files /dev/null and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithSharedTextures/plane-3.glb differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithSharedTextures/texture0.png b/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithSharedTextures/texture0.png new file mode 100644 index 000000000000..6c7e5ee581b0 Binary files /dev/null and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithSharedTextures/texture0.png differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithSharedTextures/texture1.png b/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithSharedTextures/texture1.png new file mode 100644 index 000000000000..97288521cd3c Binary files /dev/null and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithSharedTextures/texture1.png differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithSharedTextures/tileset.json b/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithSharedTextures/tileset.json new file mode 100644 index 000000000000..280e75b7b61d --- /dev/null +++ b/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithSharedTextures/tileset.json @@ -0,0 +1,116 @@ +{ + "asset": { + "version": "1.1" + }, + "geometricError": 4096, + "root": { + "boundingVolume": { + "box": [ + 3.5, + 0, + 0.5, + 3.5, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0.5 + ] + }, + "geometricError": 1024, + "children": [ + { + "boundingVolume": { + "box": [ + 0.5, + 0, + 0.5, + 0.5, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0.5 + ] + }, + "geometricError": 512, + "content": { + "uri": "plane-0.glb" + } + }, + { + "boundingVolume": { + "box": [ + 2.5, + 0, + 0.5, + 0.5, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0.5 + ] + }, + "geometricError": 512, + "content": { + "uri": "plane-1.glb" + } + }, + { + "boundingVolume": { + "box": [ + 4.5, + 0, + 0.5, + 0.5, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0.5 + ] + }, + "geometricError": 512, + "content": { + "uri": "plane-2.glb" + } + }, + { + "boundingVolume": { + "box": [ + 6.5, + 0, + 0.5, + 0.5, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0.5 + ] + }, + "geometricError": 512, + "content": { + "uri": "plane-3.glb" + } + } + ], + "refine": "ADD" + } +} \ No newline at end of file diff --git a/ThirdParty.json b/ThirdParty.json index 99be04b43dfc..ed72a070a4c1 100644 --- a/ThirdParty.json +++ b/ThirdParty.json @@ -44,7 +44,7 @@ "license": [ "Apache-2.0" ], - "version": "3.1.7", + "version": "3.2.2", "url": "https://www.npmjs.com/package/dompurify", "notes": "dompurify is available as both MPL-2.0 OR Apache-2.0" }, @@ -77,7 +77,7 @@ "license": [ "MIT" ], - "version": "1.3.9", + "version": "1.4.0", "url": "https://www.npmjs.com/package/jsep" }, { diff --git a/package.json b/package.json index 9ed3be76bceb..5f1ed19eb0bd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cesium", - "version": "1.123.0", + "version": "1.124.0", "description": "CesiumJS is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.", "homepage": "http://cesium.com/cesiumjs/", "license": "Apache-2.0", @@ -51,8 +51,8 @@ "./Specs/**/*" ], "dependencies": { - "@cesium/engine": "^12.0.0", - "@cesium/widgets": "^9.0.0" + "@cesium/engine": "^13.0.0", + "@cesium/widgets": "^10.0.0" }, "devDependencies": { "@playwright/test": "^1.41.1", @@ -90,7 +90,7 @@ "karma-safari-launcher": "^1.0.0", "karma-sourcemap-loader": "^0.4.0", "karma-spec-reporter": "^0.0.36", - "markdownlint-cli": "^0.42.0", + "markdownlint-cli": "^0.43.0", "merge-stream": "^2.0.0", "mkdirp": "^3.0.1", "node-fetch": "^3.2.10", @@ -159,4 +159,4 @@ "packages/engine", "packages/widgets" ] -} \ No newline at end of file +} diff --git a/packages/engine/Source/Core/BingMapsGeocoderService.js b/packages/engine/Source/Core/BingMapsGeocoderService.js index 647658fcd2d3..bd299d874026 100644 --- a/packages/engine/Source/Core/BingMapsGeocoderService.js +++ b/packages/engine/Source/Core/BingMapsGeocoderService.js @@ -10,6 +10,8 @@ const url = "https://dev.virtualearth.net/REST/v1/Locations"; /** * Provides geocoding through Bing Maps. + * + * @see {@link https://www.microsoft.com/en-us/maps/bing-maps/product|Microsoft Bing Maps Platform APIs Terms Of Use} * @alias BingMapsGeocoderService * @constructor * diff --git a/packages/engine/Source/Core/GoogleGeocoderService.js b/packages/engine/Source/Core/GoogleGeocoderService.js new file mode 100644 index 000000000000..67326e496e1c --- /dev/null +++ b/packages/engine/Source/Core/GoogleGeocoderService.js @@ -0,0 +1,110 @@ +import Check from "./Check.js"; +import Credit from "./Credit.js"; +import defaultValue from "./defaultValue.js"; +import Rectangle from "./Rectangle.js"; +import Resource from "./Resource.js"; +import defined from "./defined.js"; +import DeveloperError from "./DeveloperError.js"; +import RuntimeError from "./RuntimeError.js"; + +const API_URL = "https://maps.googleapis.com/maps/api/geocode/json"; +const CREDIT_HTML = `Google`; + +/** + * Provides geocoding through Google. + * + * @see {@link https://developers.google.com/maps/documentation/geocoding/policies|Google Geocoding Policies} + * @alias GoogleGeocoderService + * @constructor + * + * @param {object} options Object with the following properties: + * @param {string} options.key An API key to use with the Google geocoding service + */ +function GoogleGeocoderService(options) { + options = defaultValue(options, defaultValue.EMPTY_OBJECT); + const key = options.key; + //>>includeStart('debug', pragmas.debug); + if (!defined(key)) { + throw new DeveloperError("options.key is required."); + } + //>>includeEnd('debug'); + + this._resource = new Resource({ + url: API_URL, + queryParameters: { key }, + }); + + this._credit = new Credit(CREDIT_HTML, true); +} + +Object.defineProperties(GoogleGeocoderService.prototype, { + /** + * Gets the credit to display after a geocode is performed. Typically this is used to credit + * the geocoder service. + * @memberof GoogleGeocoderService.prototype + * @type {Credit|undefined} + * @readonly + */ + credit: { + get: function () { + return this._credit; + }, + }, +}); + +/** + * Get a list of possible locations that match a search string. + * + * @function + * + * @param {string} query The query to be sent to the geocoder service + * @returns {Promise} + * @throws {RuntimeError} If the services returns a status other than OK or ZERO_RESULTS + */ +GoogleGeocoderService.prototype.geocode = async function (query) { + // See API documentation at https://developers.google.com/maps/documentation/geocoding/requests-geocoding + + //>>includeStart('debug', pragmas.debug); + Check.typeOf.string("query", query); + //>>includeEnd('debug'); + + const resource = this._resource.getDerivedResource({ + queryParameters: { + address: query, + }, + }); + + const response = await resource.fetchJson(); + + if (response.status === "ZERO_RESULTS") { + return []; + } + + if (response.status !== "OK") { + throw new RuntimeError( + `GoogleGeocoderService got a bad response ${response.status}: ${response.error_message}`, + ); + } + + const results = response.results.map((result) => { + const southWest = result.geometry.viewport.southwest; + const northEast = result.geometry.viewport.northeast; + return { + displayName: result.formatted_address, + destination: Rectangle.fromDegrees( + southWest.lng, + southWest.lat, + northEast.lng, + northEast.lat, + ), + attribution: { + html: CREDIT_HTML, + collapsible: false, + }, + }; + }); + + return results; +}; + +export default GoogleGeocoderService; diff --git a/packages/engine/Source/Core/ITwinPlatform.js b/packages/engine/Source/Core/ITwinPlatform.js new file mode 100644 index 000000000000..c6e9e44ba4a5 --- /dev/null +++ b/packages/engine/Source/Core/ITwinPlatform.js @@ -0,0 +1,359 @@ +import Check from "./Check.js"; +import defined from "./defined.js"; +import DeveloperError from "./DeveloperError.js"; +import Resource from "./Resource.js"; +import RuntimeError from "./RuntimeError.js"; + +/** + * Default settings for accessing the iTwin platform. + * + * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy. + * + * @see ITwinData + * @namespace ITwinPlatform + */ +const ITwinPlatform = {}; + +/** + * Status states for a mesh-export export. + * Valid values are: NotStarted, InProgress, Complete, Invalid + * @enum {string} + */ +ITwinPlatform.ExportStatus = Object.freeze({ + NotStarted: "NotStarted", + InProgress: "InProgress", + Complete: "Complete", + Invalid: "Invalid", +}); + +/** + * Types of mesh-export exports. CesiumJS only supports loading 3DTILES type exports. + * Valid values are: IMODEL, CESIUM, 3DTILES + * @enum {string} + */ +ITwinPlatform.ExportType = Object.freeze({ + IMODEL: "IMODEL", + CESIUM: "CESIUM", + "3DTILES": "3DTILES", +}); + +/** + * Types of Reality data + * @see https://developer.bentley.com/apis/reality-management/rm-rd-details/#types + * @enum {string} + */ +ITwinPlatform.RealityDataType = Object.freeze({ + Cesium3DTiles: "Cesium3DTiles", + PNTS: "PNTS", + OPC: "OPC", + RealityMesh3DTiles: "RealityMesh3DTiles", + Terrain3DTiles: "Terrain3DTiles", + "3MX": "3MX", + "3SM": "3SM", + CCCloudProject: "CCCloudProject", + CCImageCollection: "CCImageCollection", + CCOrientations: "CCOrientations", + ContextCaptureInputs: "ContextCaptureInputs", + ContextDetector: "ContextDetector", + ContextScene: "ContextScene", + DAE: "DAE", + DGN: "DGN", + DSM: "DSM", + FBX: "FBX", + GLB: "GLB", + GLTF: "GLTF", + KML: "KML", + LAS: "LAS", + LAZ: "LAZ", + LOD: "LOD", + LodTree: "LodTree", + OBJ: "OBJ", + OMI: "OMI", + OMR: "OMR", + Orthophoto: "Orthophoto", + OrthophotoDSM: "OrthophotoDSM", + OSGB: "OSGB", + OVF: "OVF", + OBT: "OBT", + PLY: "PLY", + PointCloud: "PointCloud", + S3C: "S3C", + ScanCollection: "ScanCollection", + SHP: "SHP", + SLPK: "SLPK", + SpaceEyes3D: "SpaceEyes3D", + STL: "STL", + TSM: "TSM", + Unstructured: "Unstructured", + Other: "Other", +}); + +/** + * Gets or sets the default iTwin access token. This token should have the itwin-platform scope. + * + * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy. + * + * @type {string|undefined} + */ +ITwinPlatform.defaultAccessToken = undefined; + +/** + * Gets or sets the default iTwin API endpoint. + * + * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy. + * + * @type {string|Resource} + * @default "https://api.bentley.com" + */ +ITwinPlatform.apiEndpoint = new Resource({ + url: "https://api.bentley.com", +}); + +/** + * @typedef {Object} ExportRequest + * @private + * @property {string} iModelId + * @property {string} changesetId + * @property {ITwinPlatform.ExportType} exportType Type of the export. CesiumJS only supports the 3DTILES type + */ + +/** + * @typedef {Object} Link + * @private + * @property {string} href + */ + +/** + * @typedef {Object} ExportRepresentation + * The export objects from get-exports when using return=representation + * @private + * @property {string} id Export id + * @property {string} displayName Name of the iModel + * @property {ITwinPlatform.ExportStatus} status Status of this export + * @property {string} lastModified + * @property {ExportRequest} request Object containing info about the export itself + * @property {{mesh: Link}} _links Object containing relevant links. For Exports this includes the access url for the mesh itself + */ + +/** + * @typedef {Object} GetExportsResponse + * @private + * @property {ExportRepresentation[]} exports The list of exports for the current page + * @property {{self: Link, next: Link | undefined, prev: Link | undefined}} _links Pagination links + */ + +/** + * Get the list of exports for the specified iModel at it's most current version. + * This will only return the top 5 exports with {@link ITwinPlatform.ExportType} of 3DTILES. + * + * @private + * + * @param {string} iModelId iModel id + * @returns {Promise} + * + * @throws {RuntimeError} If the iTwin API request is not successful + */ +ITwinPlatform.getExports = async function (iModelId) { + //>>includeStart('debug', pragmas.debug); + Check.typeOf.string("iModelId", iModelId); + if (!defined(ITwinPlatform.defaultAccessToken)) { + throw new DeveloperError("Must set ITwinPlatform.defaultAccessToken first"); + } + //>>includeEnd('debug') + + const resource = new Resource({ + url: `${ITwinPlatform.apiEndpoint}mesh-export`, + headers: { + Authorization: `Bearer ${ITwinPlatform.defaultAccessToken}`, + Accept: "application/vnd.bentley.itwin-platform.v1+json", + Prefer: "return=representation", + }, + queryParameters: { + iModelId: iModelId, + exportType: ITwinPlatform.ExportType["3DTILES"], + // With the export auto-generation it will auto-delete the 6th export so + // there should never be more than 5 results. Just request them all and parse + // for ones that are COMPLETE + $top: "5", + client: "CesiumJS", + }, + }); + /* global CESIUM_VERSION */ + if (typeof CESIUM_VERSION !== "undefined") { + resource.appendQueryParameters({ clientVersion: CESIUM_VERSION }); + } + + try { + const response = await resource.fetchJson(); + return response; + } catch (error) { + const result = JSON.parse(error.response); + if (error.statusCode === 401) { + throw new RuntimeError( + `Unauthorized, bad token, wrong scopes or headers bad. ${result.error.details[0].code}`, + ); + } else if (error.statusCode === 403) { + console.error(result.error.code, result.error.message); + throw new RuntimeError("Not allowed, forbidden"); + } else if (error.statusCode === 422) { + throw new RuntimeError( + `Unprocessable Entity:${result.error.code} ${result.error.message}`, + ); + } else if (error.statusCode === 429) { + throw new RuntimeError("Too many requests"); + } + throw new RuntimeError(`Unknown request failure ${error.statusCode}`); + } +}; + +/** + * @typedef {Object} RealityDataExtent + * @private + * @property {{latitude: number, longitude: number}} southWest + * @property {{latitude: number, longitude: number}} northEast + */ + +/** + * @typedef {Object} RealityDataRepresentation + * @private + * @property {string} id "95d8dccd-d89e-4287-bb5f-3219acbc71ae", + * @property {string} displayName "Name of reality data", + * @property {string} dataset "Dataset", + * @property {string} group "73d09423-28c3-4fdb-ab4a-03a47a5b04f8", + * @property {string} description "Description of reality data", + * @property {string} rootDocument "Directory/SubDirectory/realityData.3mx", + * @property {number} size 6521212, + * @property {string} classification "Model", + * @property {ITwinPlatform.RealityDataType} type "3MX", + * @property {{startDateTime: string, endDateTime: string, acquirer: string}} acquisition + * @property {RealityDataExtent} extent + * @property {boolean} authoring false, + * @property {string} dataCenterLocation "North Europe", + * @property {string} modifiedDateTime "2021-04-09T19:03:12Z", + * @property {string} lastAccessedDateTime "2021-04-09T00:00:00Z", + * @property {string} createdDateTime "2021-02-22T20:03:40Z", + * @property {string} ownerId "f1d49cc7-f9b3-494f-9c67-563ea5597063", + */ + +/** + * Load the full metadata for the given iTwin id and reality data id. + * + * @private + * + * @param {string} iTwinId The id of the iTwin to load data from + * @param {string} realityDataId The id of the reality data to load + * @returns {Promise} + */ +ITwinPlatform.getRealityDataMetadata = async function (iTwinId, realityDataId) { + //>>includeStart('debug', pragmas.debug); + Check.typeOf.string("iTwinId", iTwinId); + Check.typeOf.string("realityDataId", realityDataId); + if (!defined(ITwinPlatform.defaultAccessToken)) { + throw new DeveloperError("Must set ITwinPlatform.defaultAccessToken first"); + } + //>>includeEnd('debug') + + const resource = new Resource({ + url: `${ITwinPlatform.apiEndpoint}reality-management/reality-data/${realityDataId}`, + headers: { + Authorization: `Bearer ${ITwinPlatform.defaultAccessToken}`, + Accept: "application/vnd.bentley.itwin-platform.v1+json", + }, + queryParameters: { iTwinId: iTwinId }, + }); + + try { + const response = await resource.fetchJson(); + return response.realityData; + } catch (error) { + const result = JSON.parse(error.response); + if (error.statusCode === 401) { + throw new RuntimeError( + `Unauthorized, bad token, wrong scopes or headers bad. ${result.error.details[0].code}`, + ); + } else if (error.statusCode === 403) { + console.error(result.error.code, result.error.message); + throw new RuntimeError("Not allowed, forbidden"); + } else if (error.statusCode === 404) { + throw new RuntimeError( + `Reality data not found: ${iTwinId}, ${realityDataId}`, + ); + } else if (error.statusCode === 422) { + throw new RuntimeError( + `Unprocessable Entity:${result.error.code} ${result.error.message}`, + ); + } else if (error.statusCode === 429) { + throw new RuntimeError("Too many requests"); + } + throw new RuntimeError(`Unknown request failure ${error.statusCode}`); + } +}; + +/** + * Request the access url for the given iTwin id, reality data id and root document. + * The root document can be requested from the list using return=representation + * or the metadata route from {@link ITwinPlatform.getRealityDataMetadata} + * + * @private + * + * @param {string} iTwinId The id of the iTwin to load data from + * @param {string} realityDataId The id of the reality data to load + * @param {string} rootDocument The path of the root document for this reality data + * @returns {Promise} + */ +ITwinPlatform.getRealityDataURL = async function ( + iTwinId, + realityDataId, + rootDocument, +) { + //>>includeStart('debug', pragmas.debug); + Check.typeOf.string("iTwinId", iTwinId); + Check.typeOf.string("realityDataId", realityDataId); + Check.typeOf.string("rootDocument", rootDocument); + if (!defined(ITwinPlatform.defaultAccessToken)) { + throw new DeveloperError("Must set ITwinPlatform.defaultAccessToken first"); + } + //>>includeEnd('debug') + + const resource = new Resource({ + url: `${ITwinPlatform.apiEndpoint}reality-management/reality-data/${realityDataId}/readaccess`, + headers: { + Authorization: `Bearer ${ITwinPlatform.defaultAccessToken}`, + Accept: "application/vnd.bentley.itwin-platform.v1+json", + }, + queryParameters: { iTwinId: iTwinId }, + }); + + try { + const result = await resource.fetchJson(); + + const containerUrl = result._links.containerUrl.href; + const tilesetUrl = new URL(containerUrl); + tilesetUrl.pathname = `${tilesetUrl.pathname}/${rootDocument}`; + + return tilesetUrl.toString(); + } catch (error) { + const result = JSON.parse(error.response); + if (error.statusCode === 401) { + throw new RuntimeError( + `Unauthorized, bad token, wrong scopes or headers bad. ${result.error.details[0].code}`, + ); + } else if (error.statusCode === 403) { + console.error(result.error.code, result.error.message); + throw new RuntimeError("Not allowed, forbidden"); + } else if (error.statusCode === 404) { + throw new RuntimeError( + `Reality data not found: ${iTwinId}, ${realityDataId}`, + ); + } else if (error.statusCode === 422) { + throw new RuntimeError( + `Unprocessable Entity:${result.error.code} ${result.error.message}`, + ); + } else if (error.statusCode === 429) { + throw new RuntimeError("Too many requests"); + } + throw new RuntimeError(`Unknown request failure ${error.statusCode}`); + } +}; + +export default ITwinPlatform; diff --git a/packages/engine/Source/Core/Ion.js b/packages/engine/Source/Core/Ion.js index 064a7d82f729..78da25b95607 100644 --- a/packages/engine/Source/Core/Ion.js +++ b/packages/engine/Source/Core/Ion.js @@ -8,7 +8,7 @@ let defaultTokenCredit; const cesiumWebsiteToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI3ODZkMDQzOS03ZGJjLTQzZWUtYjlmYy04ZmM5Y2UwNzNhMmYiLCJpZCI6MjU5LCJpYXQiOjE2MzgyMDYwMDB9.cK1hsaFBgz0l2dG9Ry5vBFHWp-HF2lwjLC0tcK8Z8tY"; const defaultAccessToken = - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJiZjBmMDE4Ny05M2JlLTRlMzgtYjIxYi05YmJjM2QwMzJkYWMiLCJpZCI6MjU5LCJpYXQiOjE3MzA0NjY3MDl9.t-7gCGPUe-oGCyCoeXPtYmlMVdgqUQD9mn-Da23yUoI"; + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI0ZDdmNWJiNy0wMmNlLTQ1MWUtODM2YS02NGM1MTBlOGMwMWQiLCJpZCI6MjU5LCJpYXQiOjE3MzMxNTc4OTV9.B3URHf0VdHDtGckb-hv7uqATdn8KfvkiuoAFZUq8tAo"; /** * Default settings for accessing the Cesium ion API. * diff --git a/packages/engine/Source/Core/IonGeocodeProviderType.js b/packages/engine/Source/Core/IonGeocodeProviderType.js new file mode 100644 index 000000000000..2dc9bf35d775 --- /dev/null +++ b/packages/engine/Source/Core/IonGeocodeProviderType.js @@ -0,0 +1,33 @@ +/** + * Underlying geocoding services that can be used via Cesium ion. + * + * @enum {string} + */ +const IonGeocodeProviderType = { + /** + * Google geocoder, for use with Google data. + * + * @type {string} + * @constant + */ + GOOGLE: "GOOGLE", + + /** + * Bing geocoder, for use with Bing data. + * + * @type {string} + * @constant + */ + BING: "BING", + + /** + * Use the default geocoder as set on the server. Used when neither Bing or + * Google data is used. + * + * @type {string} + * @constant + */ + DEFAULT: "DEFAULT", +}; + +export default Object.freeze(IonGeocodeProviderType); diff --git a/packages/engine/Source/Core/IonGeocoderService.js b/packages/engine/Source/Core/IonGeocoderService.js index 81da96b7dbba..f473d80005b3 100644 --- a/packages/engine/Source/Core/IonGeocoderService.js +++ b/packages/engine/Source/Core/IonGeocoderService.js @@ -2,10 +2,45 @@ import Check from "./Check.js"; import Credit from "./Credit.js"; import defaultValue from "./defaultValue.js"; import defined from "./defined.js"; +import DeveloperError from "./DeveloperError.js"; import Ion from "./Ion.js"; +import IonGeocodeProviderType from "./IonGeocodeProviderType.js"; import PeliasGeocoderService from "./PeliasGeocoderService.js"; import Resource from "./Resource.js"; +/** + * @param {*} geocodeProviderType + * @throws {DeveloperError} + * @private + */ +function validateIonGeocodeProviderType(geocodeProviderType) { + if ( + !Object.values(IonGeocodeProviderType).some( + (value) => value === geocodeProviderType, + ) + ) { + throw new DeveloperError( + `Invalid geocodeProviderType: "${geocodeProviderType}"`, + ); + } +} + +const providerToParameterMap = Object.freeze({ + [IonGeocodeProviderType.GOOGLE]: "google", + [IonGeocodeProviderType.BING]: "bing", + [IonGeocodeProviderType.DEFAULT]: undefined, +}); + +function providerToQueryParameter(provider) { + return providerToParameterMap[provider]; +} + +function queryParameterToProvider(parameter) { + return Object.entries(providerToParameterMap).find( + (entry) => entry[1] === parameter, + )[0]; +} + /** * Provides geocoding through Cesium ion. * @alias IonGeocoderService @@ -15,6 +50,7 @@ import Resource from "./Resource.js"; * @param {Scene} options.scene The scene * @param {string} [options.accessToken=Ion.defaultAccessToken] The access token to use. * @param {string|Resource} [options.server=Ion.defaultServer] The resource to the Cesium ion API server. + * @param {IonGeocodeProviderType} [options.geocodeProviderType=IonGeocodeProviderType.DEFAULT] The geocoder the Cesium ion API server should use to fulfill this request. * * @see Ion */ @@ -25,6 +61,14 @@ function IonGeocoderService(options) { Check.typeOf.object("options.scene", options.scene); //>>includeEnd('debug'); + const geocodeProviderType = defaultValue( + options.geocodeProviderType, + IonGeocodeProviderType.DEFAULT, + ); + //>>includeStart('debug', pragmas.debug); + validateIonGeocodeProviderType(geocodeProviderType); + //>>includeEnd('debug'); + const accessToken = defaultValue(options.accessToken, Ion.defaultAccessToken); const server = Resource.createIfNeeded( defaultValue(options.server, Ion.defaultServer), @@ -49,6 +93,9 @@ function IonGeocoderService(options) { this._accessToken = accessToken; this._server = server; this._pelias = new PeliasGeocoderService(searchEndpoint); + // geocoderProviderType isn't stored here directly but instead relies on the + // query parameters of this._pelias.url. Use the setter logic to update value. + this.geocodeProviderType = geocodeProviderType; } Object.defineProperties(IonGeocoderService.prototype, { @@ -64,6 +111,31 @@ Object.defineProperties(IonGeocoderService.prototype, { return undefined; }, }, + /** + * The geocoding service that Cesium ion API server should use to fulfill geocding requests. + * @memberof IonGeocoderService.prototype + * @type {IonGeocodeProviderType} + * @default IonGeocodeProviderType.DEFAULT + */ + geocodeProviderType: { + get: function () { + return queryParameterToProvider( + this._pelias.url.queryParameters["geocoder"], + ); + }, + set: function (geocodeProviderType) { + validateIonGeocodeProviderType(geocodeProviderType); + const query = { + ...this._pelias.url.queryParameters, + geocoder: providerToQueryParameter(geocodeProviderType), + }; + // Delete the geocoder parameter to prevent sending &geocoder=undefined in the query + if (!defined(query.geocoder)) { + delete query.geocoder; + } + this._pelias.url.setQueryParameters(query); + }, + }, }); /** diff --git a/packages/engine/Source/Core/Rectangle.js b/packages/engine/Source/Core/Rectangle.js index 915a5289f909..70cd68fafaa6 100644 --- a/packages/engine/Source/Core/Rectangle.js +++ b/packages/engine/Source/Core/Rectangle.js @@ -7,7 +7,6 @@ import Ellipsoid from "./Ellipsoid.js"; import CesiumMath from "./Math.js"; import Transforms from "./Transforms.js"; import Matrix4 from "./Matrix4.js"; -import deprecationWarning from "./deprecationWarning.js"; /** * A two dimensional region specified as longitude and latitude coordinates. @@ -533,25 +532,6 @@ Rectangle.prototype.equalsEpsilon = function (other, epsilon) { return Rectangle.equalsEpsilon(this, other, epsilon); }; -/** - * Checks a Rectangle's properties and throws if they are not in valid ranges. - * - * @param {Rectangle} rectangle The rectangle to validate - * - * @exception {DeveloperError} north must be in the interval [-Pi/2, Pi/2]. - * @exception {DeveloperError} south must be in the interval [-Pi/2, Pi/2]. - * @exception {DeveloperError} east must be in the interval [-Pi, Pi]. - * @exception {DeveloperError} west must be in the interval [-Pi, Pi]. - * @deprecated This function is deprecated and will be removed in Cesium 1.124. See Issue 4921 - */ -Rectangle.validate = function (rectangle) { - deprecationWarning( - "Rectangle.validate", - "Rectangle.validate is a no-op and has been deprecated. It will be removed in Cesium 1.124.", - ); - return Rectangle._validate(rectangle); -}; - /** * Checks a Rectangle's properties and throws if they are not in valid ranges. * diff --git a/packages/engine/Source/Core/TrackingReferenceFrame.js b/packages/engine/Source/Core/TrackingReferenceFrame.js new file mode 100644 index 000000000000..d16be08b853b --- /dev/null +++ b/packages/engine/Source/Core/TrackingReferenceFrame.js @@ -0,0 +1,45 @@ +/** + * Constants for identifying well-known tracking reference frames. + * + * @enum {number} + */ +const TrackingReferenceFrame = { + /** + * Auto-detect algorithm. The reference frame used to track the Entity will + * be automatically selected based on its trajectory: near-surface slow moving + * objects will be tracked in the entity's local east-north-up reference + * frame, while faster objects like satellites will use VVLH (Vehicle Velocity, + * Local Horizontal). + * + * @type {number} + * @constant + */ + AUTODETECT: 0, + + /** + * The entity's local East-North-Up reference frame. + * + * @type {number} + * @constant + */ + ENU: 1, + + /** + * The entity's inertial reference frame. If entity has no defined orientation + * property, it falls back to auto-detect algorithm. + * + * @type {number} + * @constant + */ + INERTIAL: 2, + + /** + * The entity's inertial reference frame with orientation fixed to its + * {@link VelocityOrientationProperty}, ignoring its own orientation. + * + * @type {number} + * @constant + */ + VELOCITY: 3, +}; +export default Object.freeze(TrackingReferenceFrame); diff --git a/packages/engine/Source/DataSources/Entity.js b/packages/engine/Source/DataSources/Entity.js index b2b7433e29ba..d8c9fab17f9e 100644 --- a/packages/engine/Source/DataSources/Entity.js +++ b/packages/engine/Source/DataSources/Entity.js @@ -10,6 +10,7 @@ import CesiumMath from "../Core/Math.js"; import Matrix3 from "../Core/Matrix3.js"; import Matrix4 from "../Core/Matrix4.js"; import Quaternion from "../Core/Quaternion.js"; +import TrackingReferenceFrame from "../Core/TrackingReferenceFrame.js"; import Transforms from "../Core/Transforms.js"; import GroundPolylinePrimitive from "../Scene/GroundPolylinePrimitive.js"; import GroundPrimitive from "../Scene/GroundPrimitive.js"; @@ -73,8 +74,9 @@ function createPropertyTypeDescriptor(name, Type) { * @property {string} [name] A human readable name to display to users. It does not have to be unique. * @property {TimeIntervalCollection} [availability] The availability, if any, associated with this object. * @property {boolean} [show] A boolean value indicating if the entity and its children are displayed. + * @property {TrackingReferenceFrame} [trackingReferenceFrame=TrackingReferenceFrame.AUTODETECT] The reference frame used when this entity is being tracked.
If undefined, reference frame is determined based on entity velocity: near-surface slow moving entities are tracked using the local east-north-up reference frame, whereas fast moving entities such as satellites are tracked using VVLH (Vehicle Velocity, Local Horizontal). * @property {Property | string} [description] A string Property specifying an HTML description for this entity. - * @property {PositionProperty | Cartesian3 | CallbackProperty} [position] A Property specifying the entity position. + * @property {PositionProperty | Cartesian3 | CallbackPositionProperty} [position] A Property specifying the entity position. * @property {Property | Quaternion} [orientation=Transforms.eastNorthUpToFixedFrame(position)] A Property specifying the entity orientation in respect to Earth-fixed-Earth-centered (ECEF). If undefined, east-north-up at entity position is used. * @property {Property | Cartesian3} [viewFrom] A suggested initial offset for viewing this object. * @property {Entity} [parent] A parent entity to associate with this entity. @@ -122,6 +124,10 @@ function Entity(options) { this._definitionChanged = new Event(); this._name = options.name; this._show = defaultValue(options.show, true); + this._trackingReferenceFrame = defaultValue( + options.trackingReferenceFrame, + TrackingReferenceFrame.AUTODETECT, + ); this._parent = undefined; this._propertyNames = [ "billboard", @@ -296,6 +302,14 @@ Object.defineProperties(Entity.prototype, { this._definitionChanged.raiseEvent(this, "show", value, !value); }, }, + /** + * Gets or sets the entity's tracking reference frame. + * @demo {@link https://sandcastle.cesium.com/index.html?src=Entity tracking.html|Cesium Sandcastle Entity tracking Demo} + * + * @memberof Entity.prototype + * @type {TrackingReferenceFrame} + */ + trackingReferenceFrame: createRawPropertyDescriptor("trackingReferenceFrame"), /** * Gets whether this entity is being displayed, taking into account * the visibility of any ancestor entities. diff --git a/packages/engine/Source/DataSources/EntityView.js b/packages/engine/Source/DataSources/EntityView.js index eb4fd4c5c207..9e7ae33234b5 100644 --- a/packages/engine/Source/DataSources/EntityView.js +++ b/packages/engine/Source/DataSources/EntityView.js @@ -8,8 +8,11 @@ import JulianDate from "../Core/JulianDate.js"; import CesiumMath from "../Core/Math.js"; import Matrix3 from "../Core/Matrix3.js"; import Matrix4 from "../Core/Matrix4.js"; +import Quaternion from "../Core/Quaternion.js"; +import TrackingReferenceFrame from "../Core/TrackingReferenceFrame.js"; import Transforms from "../Core/Transforms.js"; import SceneMode from "../Scene/SceneMode.js"; +import VelocityVectorProperty from "./VelocityVectorProperty.js"; const updateTransformMatrix3Scratch1 = new Matrix3(); const updateTransformMatrix3Scratch2 = new Matrix3(); @@ -21,6 +24,9 @@ const updateTransformCartesian3Scratch3 = new Cartesian3(); const updateTransformCartesian3Scratch4 = new Cartesian3(); const updateTransformCartesian3Scratch5 = new Cartesian3(); const updateTransformCartesian3Scratch6 = new Cartesian3(); +const updateTransformOrientationScratch = new Quaternion(); +const velocityScratch = new Cartesian3(); +const rotationScratch = new Matrix3(); const deltaTime = new JulianDate(); const northUpAxisFactor = 1.25; // times ellipsoid's maximum radius @@ -30,6 +36,9 @@ function updateTransform( updateLookAt, saveCamera, positionProperty, + velocityProperty, + orientationProperty, + trackingReferenceFrame, time, ellipsoid, ) { @@ -228,7 +237,44 @@ function updateTransform( } const transform = updateTransformMatrix4Scratch; - if (hasBasis) { + + let orientation; + if (defined(orientationProperty)) { + orientation = orientationProperty.getValue( + time, + updateTransformOrientationScratch, + ); + } + + const velocity = velocityProperty.getValue(time, velocityScratch); + + if ( + trackingReferenceFrame === TrackingReferenceFrame.INERTIAL && + defined(orientation) + ) { + Matrix4.fromTranslationQuaternionRotationScale( + cartesian, + orientation, + Cartesian3.ONE, + transform, + ); + } else if ( + trackingReferenceFrame === TrackingReferenceFrame.VELOCITY && + defined(velocity) + ) { + const rotation = Transforms.rotationMatrixFromPositionVelocity( + cartesian, + velocity, + ellipsoid, + rotationScratch, + ); + Matrix4.fromRotationTranslation(rotation, cartesian, transform); + } else if ( + trackingReferenceFrame === TrackingReferenceFrame.ENU || + !hasBasis + ) { + Transforms.eastNorthUpToFixedFrame(cartesian, ellipsoid, transform); + } else { transform[0] = xBasis.x; transform[1] = xBasis.y; transform[2] = xBasis.z; @@ -245,9 +291,6 @@ function updateTransform( transform[13] = cartesian.y; transform[14] = cartesian.z; transform[15] = 0.0; - } else { - // Stationary or slow-moving, low-altitude objects use East-North-Up. - Transforms.eastNorthUpToFixedFrame(cartesian, ellipsoid, transform); } camera._setTransform(transform); @@ -316,6 +359,8 @@ function EntityView(entity, scene, ellipsoid) { this._lastCartesian = new Cartesian3(); this._defaultOffset3D = undefined; + this._velocityProperty = new VelocityVectorProperty(entity.position, true); + this._offset3D = new Cartesian3(); } @@ -362,10 +407,13 @@ EntityView.prototype.update = function (time, boundingSphere) { } const entity = this.entity; + const trackingReferenceFrame = entity.trackingReferenceFrame; const positionProperty = entity.position; if (!defined(positionProperty)) { return; } + const velocityProperty = this._velocityProperty; + const orientationProperty = entity.orientation; const objectChanged = entity !== this._lastEntity; const sceneModeChanged = sceneMode !== this._mode; @@ -419,6 +467,9 @@ EntityView.prototype.update = function (time, boundingSphere) { updateLookAt, saveCamera, positionProperty, + velocityProperty, + orientationProperty, + trackingReferenceFrame, time, ellipsoid, ); diff --git a/packages/engine/Source/DataSources/SampledProperty.js b/packages/engine/Source/DataSources/SampledProperty.js index 803555188725..dde0676d987e 100644 --- a/packages/engine/Source/DataSources/SampledProperty.js +++ b/packages/engine/Source/DataSources/SampledProperty.js @@ -674,6 +674,30 @@ SampledProperty.prototype.addSamples = function ( this._definitionChanged.raiseEvent(this); }; +/** + * Retrieves the time of the provided sample associated with the index. A negative index accesses the list of samples in reverse order. + * + * @param {number} index The index of samples list. + * @returns {JulianDate | undefined} The JulianDate time of the sample, or undefined if failed. + */ +SampledProperty.prototype.getSample = function (index) { + //>>includeStart('debug', pragmas.debug); + Check.typeOf.number("index", index); + //>>includeEnd('debug'); + + const times = this._times; + const len = times.length; + if (!defined(len)) { + return undefined; + } + + if (index < 0) { + index += len; + } + + return times[index]; +}; + /** * Adds samples as a single packed array where each new sample is represented as a date, * followed by the packed representation of the corresponding value and derivatives. diff --git a/packages/engine/Source/Renderer/ContextLimits.js b/packages/engine/Source/Renderer/ContextLimits.js index b6c5e5731f13..c435971762ac 100644 --- a/packages/engine/Source/Renderer/ContextLimits.js +++ b/packages/engine/Source/Renderer/ContextLimits.js @@ -44,7 +44,7 @@ Object.defineProperties(ContextLimits, { }, /** - * The approximate maximum cube mape width and height supported by this WebGL implementation. + * The approximate maximum cube map width and height supported by this WebGL implementation. * The minimum is 16, but most desktop and laptop implementations will support much larger sizes like 8,192. * @memberof ContextLimits * @type {number} diff --git a/packages/engine/Source/Renderer/Texture.js b/packages/engine/Source/Renderer/Texture.js index b4b1259d5001..1e5eed6dd71d 100644 --- a/packages/engine/Source/Renderer/Texture.js +++ b/packages/engine/Source/Renderer/Texture.js @@ -27,6 +27,7 @@ import TextureMinificationFilter from "./TextureMinificationFilter.js"; * @property {number} [width] The pixel width of the texture. If not supplied, must be available from the source. * @property {number} [height] The pixel height of the texture. If not supplied, must be available from the source. * @property {boolean} [preMultiplyAlpha] If true, the alpha channel will be multiplied into the other channels. + * @property {string} [id] A unique identifier for the texture. If this is not given, then a GUID will be created. * * @private */ @@ -216,7 +217,7 @@ function Texture(options) { ? PixelFormat.compressedTextureSizeInBytes(pixelFormat, width, height) : PixelFormat.textureSizeInBytes(pixelFormat, pixelDatatype, width, height); - this._id = createGuid(); + this._id = options.id ?? createGuid(); this._context = context; this._textureFilterAnisotropic = context._textureFilterAnisotropic; this._textureTarget = gl.TEXTURE_2D; @@ -343,7 +344,7 @@ function loadBufferSource(texture, source) { gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); - let arrayBufferView = source.arrayBufferView; + let { arrayBufferView } = source; if (flipY) { arrayBufferView = PixelFormat.flipY( arrayBufferView, @@ -386,6 +387,62 @@ function loadBufferSource(texture, source) { } } +/** + * Load texel data from a buffer into part of a texture + * + * @param {Texture} texture The texture to which texel values will be loaded. + * @param {TypedArray} arrayBufferView The texel values to be loaded into the texture. + * @param {number} xOffset The texel x coordinate of the lower left corner of the subregion of the texture to be updated. + * @param {number} yOffset The texel y coordinate of the lower left corner of the subregion of the texture to be updated. + * @param {number} width The width of the source data, in pixels. + * @param {number} width The height of the source data, in pixels. + * + * @private + */ +function loadPartialBufferSource( + texture, + arrayBufferView, + xOffset, + yOffset, + width, + height, +) { + const context = texture._context; + const gl = context._gl; + + const { pixelFormat, pixelDatatype } = texture; + + const unpackAlignment = PixelFormat.alignmentInBytes( + pixelFormat, + pixelDatatype, + width, + ); + gl.pixelStorei(gl.UNPACK_ALIGNMENT, unpackAlignment); + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); + + if (texture.flipY) { + arrayBufferView = PixelFormat.flipY( + arrayBufferView, + pixelFormat, + pixelDatatype, + width, + height, + ); + } + gl.texSubImage2D( + texture._textureTarget, + 0, + xOffset, + yOffset, + width, + height, + pixelFormat, + PixelDatatype.toWebGLConstant(pixelDatatype, context), + arrayBufferView, + ); +} + /** * Load texel data from a framebuffer into a texture. * @@ -448,6 +505,35 @@ function loadImageSource(texture, source) { ); } +/** + * Load texel data from an Image into part of a texture + * + * @param {Texture} texture The texture to which texel values will be loaded. + * @param {ImageData|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} source The source for texel values to be loaded into the texture. + * @param {number} xOffset The texel x coordinate of the lower left corner of the subregion of the texture to be updated. + * @param {number} yOffset The texel y coordinate of the lower left corner of the subregion of the texture to be updated. + * + * @private + */ +function loadPartialImageSource(texture, source, xOffset, yOffset) { + const context = texture._context; + const gl = context._gl; + + gl.pixelStorei(gl.UNPACK_ALIGNMENT, 4); + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.preMultiplyAlpha); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, texture.flipY); + + gl.texSubImage2D( + texture._textureTarget, + 0, + xOffset, + yOffset, + texture.pixelFormat, + PixelDatatype.toWebGLConstant(texture.pixelDatatype, context), + source, + ); +} + /** * Compute a dimension of the image for the next mip level. * @@ -812,7 +898,6 @@ Texture.prototype.copyFrom = function (options) { gl.bindTexture(target, this._texture); let { width, height } = source; - const arrayBufferView = source.arrayBufferView; // Make sure we are using the element's intrinsic width and height where available if (defined(source.videoWidth) && defined(source.videoHeight)) { @@ -823,25 +908,6 @@ Texture.prototype.copyFrom = function (options) { height = source.naturalHeight; } - const textureWidth = this._width; - const textureHeight = this._height; - const internalFormat = this._internalFormat; - const pixelFormat = this._pixelFormat; - const pixelDatatype = this._pixelDatatype; - - const preMultiplyAlpha = this._preMultiplyAlpha; - const flipY = this._flipY; - - let unpackAlignment = 4; - if (defined(arrayBufferView)) { - unpackAlignment = PixelFormat.alignmentInBytes( - pixelFormat, - pixelDatatype, - width, - ); - } - gl.pixelStorei(gl.UNPACK_ALIGNMENT, unpackAlignment); - if (skipColorSpaceConversion) { gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE); } else { @@ -853,94 +919,40 @@ Texture.prototype.copyFrom = function (options) { let uploaded = false; if (!this._initialized) { - let pixels; if ( xOffset === 0 && yOffset === 0 && - width === textureWidth && - height === textureHeight + width === this._width && + height === this._height ) { // initialize the entire texture - if (defined(arrayBufferView)) { - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); - gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); - if (flipY) { - pixels = PixelFormat.flipY( - arrayBufferView, - pixelFormat, - pixelDatatype, - textureWidth, - textureHeight, - ); - } else { - pixels = arrayBufferView; - } + if (defined(source.arrayBufferView)) { + loadBufferSource(this, source); } else { - // Only valid for DOM-Element uploads - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, preMultiplyAlpha); - gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY); - pixels = source; + loadImageSource(this, source); } uploaded = true; } else { gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); - // initialize the entire texture to zero - pixels = PixelFormat.createTypedArray( - pixelFormat, - pixelDatatype, - textureWidth, - textureHeight, - ); + loadNull(this); } - gl.texImage2D( - target, - 0, - internalFormat, - textureWidth, - textureHeight, - 0, - pixelFormat, - PixelDatatype.toWebGLConstant(pixelDatatype, context), - pixels, - ); this._initialized = true; } if (!uploaded) { - let pixels; - if (defined(arrayBufferView)) { - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); - gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); - - if (flipY) { - pixels = PixelFormat.flipY( - arrayBufferView, - pixelFormat, - pixelDatatype, - width, - height, - ); - } else { - pixels = arrayBufferView; - } + if (defined(source.arrayBufferView)) { + loadPartialBufferSource( + this, + source.arrayBufferView, + xOffset, + yOffset, + width, + height, + ); } else { - // Only valid for DOM-Element uploads - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, preMultiplyAlpha); - gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY); - pixels = source; + loadPartialImageSource(this, source, xOffset, yOffset); } - gl.texSubImage2D( - target, - 0, - xOffset, - yOffset, - width, - height, - pixelFormat, - PixelDatatype.toWebGLConstant(pixelDatatype, context), - pixels, - ); } gl.bindTexture(target, null); diff --git a/packages/engine/Source/Scene/ArcGisMapService.js b/packages/engine/Source/Scene/ArcGisMapService.js index ce4f8c0a2e75..738ca6952569 100644 --- a/packages/engine/Source/Scene/ArcGisMapService.js +++ b/packages/engine/Source/Scene/ArcGisMapService.js @@ -8,7 +8,7 @@ const cesiumWebsiteToken = let defaultTokenCredit; const defaultAccessToken = - "AAPTxy8BH1VEsoebNVZXo8HurEOF051kAEKlhkOhBEc9BmQpcUfxe1Yndhf82d5oKkQJ4_7VPaBQGYSISOMaRew7Sy-eTX1JQ4XwaC8v5aCvV72O6LCPs5Ss1pXXH-0uEw6bSRhTeQYHOmikutC2OMyZt6lu0VfT7FA-jVMO_UsunWNTf2cycP2O4IeDN_UV9G-VNmUu2jRvCHioi8o72ua4238s2219cYLEmcoGRJGVJTA.AT1_PjLvyih0"; + "AAPTxy8BH1VEsoebNVZXo8HurEOF051kAEKlhkOhBEc9BmSrZYLHFXe7j_lQcsSJKc8-7rwh0IFSNWLGZErkzXRnYjMjURTz-hGiKMEeAJIZBG7uiYEn0Mt1rrwlJGIpirZQC4iO428519DlO3QC9DnRBqLXGTBhirgoU7-Z2209sy87s49kw6NOC8_Eew6nCLf-pZ883DRPRyAYH7LC8cvRLInud0EdndtUFa4y83TamrA.AT1_ahjrWDrq"; /** * Default options for accessing the ArcGIS image tile service. * diff --git a/packages/engine/Source/Scene/Cesium3DTilesetStatistics.js b/packages/engine/Source/Scene/Cesium3DTilesetStatistics.js index ed80f3fc67fd..f7c0d93834b9 100644 --- a/packages/engine/Source/Scene/Cesium3DTilesetStatistics.js +++ b/packages/engine/Source/Scene/Cesium3DTilesetStatistics.js @@ -1,4 +1,5 @@ import defined from "../Core/defined.js"; +import Model3DTileContent from "./Model/Model3DTileContent.js"; /** * @private @@ -29,6 +30,7 @@ function Cesium3DTilesetStatistics() { // Memory statistics this.geometryByteLength = 0; this.texturesByteLength = 0; + this.texturesReferenceCounterById = {}; this.batchTableByteLength = 0; // batch textures and any binary metadata properties not otherwise accounted for } @@ -45,61 +47,123 @@ Cesium3DTilesetStatistics.prototype.clear = function () { this.numberOfTilesCulledWithChildrenUnion = 0; }; -function updatePointAndFeatureCounts(statistics, content, decrement, load) { +/** + * Increment the counters for the points, triangles, and features + * that are currently selected for rendering. + * + * This will be called recursively for the given content and + * all its inner contents + * + * @param {Cesium3DTileContent} content + */ +Cesium3DTilesetStatistics.prototype.incrementSelectionCounts = function ( + content, +) { + this.numberOfFeaturesSelected += content.featuresLength; + this.numberOfPointsSelected += content.pointsLength; + this.numberOfTrianglesSelected += content.trianglesLength; + + // Recursive calls on all inner contents const contents = content.innerContents; - const pointsLength = content.pointsLength; - const trianglesLength = content.trianglesLength; - const featuresLength = content.featuresLength; - const geometryByteLength = content.geometryByteLength; - const texturesByteLength = content.texturesByteLength; - const batchTableByteLength = content.batchTableByteLength; + if (defined(contents)) { + const length = contents.length; + for (let i = 0; i < length; ++i) { + this.incrementSelectionCounts(contents[i]); + } + } +}; - if (load) { - statistics.numberOfFeaturesLoaded += decrement - ? -featuresLength - : featuresLength; - statistics.numberOfPointsLoaded += decrement ? -pointsLength : pointsLength; - statistics.geometryByteLength += decrement - ? -geometryByteLength - : geometryByteLength; - statistics.texturesByteLength += decrement - ? -texturesByteLength - : texturesByteLength; - statistics.batchTableByteLength += decrement - ? -batchTableByteLength - : batchTableByteLength; +/** + * Increment the counters for the number of features and points that + * are currently loaded, and the lengths (size in bytes) of the + * occupied memory. + * + * This will be called recursively for the given content and + * all its inner contents + * + * @param {Cesium3DTileContent} content + */ +Cesium3DTilesetStatistics.prototype.incrementLoadCounts = function (content) { + this.numberOfFeaturesLoaded += content.featuresLength; + this.numberOfPointsLoaded += content.pointsLength; + this.geometryByteLength += content.geometryByteLength; + this.batchTableByteLength += content.batchTableByteLength; + + // When the content is not a `Model3DTileContent`, then its + // textures byte length is added directly + if (!(content instanceof Model3DTileContent)) { + this.texturesByteLength += content.texturesByteLength; } else { - statistics.numberOfFeaturesSelected += decrement - ? -featuresLength - : featuresLength; - statistics.numberOfPointsSelected += decrement - ? -pointsLength - : pointsLength; - statistics.numberOfTrianglesSelected += decrement - ? -trianglesLength - : trianglesLength; + // When the content is a `Model3DTileContent`, then increment the + // reference counter for all its textures. The byte length of any + // newly tracked texture to the total textures byte length + const textureIds = content.getTextureIds(); + for (const textureId of textureIds) { + const referenceCounter = + this.texturesReferenceCounterById[textureId] ?? 0; + if (referenceCounter === 0) { + const textureByteLength = content.getTextureByteLengthById(textureId); + this.texturesByteLength += textureByteLength; + } + this.texturesReferenceCounterById[textureId] = referenceCounter + 1; + } } + // Recursive calls on all inner contents + const contents = content.innerContents; if (defined(contents)) { const length = contents.length; for (let i = 0; i < length; ++i) { - updatePointAndFeatureCounts(statistics, contents[i], decrement, load); + this.incrementLoadCounts(contents[i]); } } -} - -Cesium3DTilesetStatistics.prototype.incrementSelectionCounts = function ( - content, -) { - updatePointAndFeatureCounts(this, content, false, false); -}; - -Cesium3DTilesetStatistics.prototype.incrementLoadCounts = function (content) { - updatePointAndFeatureCounts(this, content, false, true); }; +/** + * Decrement the counters for the number of features and points that + * are currently loaded, and the lengths (size in bytes) of the + * occupied memory. + * + * This will be called recursively for the given content and + * all its inner contents + * + * @param {Cesium3DTileContent} content + */ Cesium3DTilesetStatistics.prototype.decrementLoadCounts = function (content) { - updatePointAndFeatureCounts(this, content, true, true); + this.numberOfFeaturesLoaded -= content.featuresLength; + this.numberOfPointsLoaded -= content.pointsLength; + this.geometryByteLength -= content.geometryByteLength; + this.batchTableByteLength -= content.batchTableByteLength; + + // When the content is not a `Model3DTileContent`, then its + // textures byte length is subtracted directly + if (!(content instanceof Model3DTileContent)) { + this.texturesByteLength -= content.texturesByteLength; + } else { + // When the content is a `Model3DTileContent`, then decrement the + // reference counter for all its textures. The byte length of any + // texture that is no longer references is subtracted from the + // total textures byte length + const textureIds = content.getTextureIds(); + for (const textureId of textureIds) { + const referenceCounter = this.texturesReferenceCounterById[textureId]; + if (referenceCounter === 1) { + delete this.texturesReferenceCounterById[textureId]; + const textureByteLength = content.getTextureByteLengthById(textureId); + this.texturesByteLength -= textureByteLength; + } else { + this.texturesReferenceCounterById[textureId] = referenceCounter - 1; + } + } + } + // Recursive calls on all inner contents + const contents = content.innerContents; + if (defined(contents)) { + const length = contents.length; + for (let i = 0; i < length; ++i) { + this.decrementLoadCounts(contents[i]); + } + } }; Cesium3DTilesetStatistics.clone = function (statistics, result) { @@ -124,6 +188,9 @@ Cesium3DTilesetStatistics.clone = function (statistics, result) { statistics.numberOfTilesCulledWithChildrenUnion; result.geometryByteLength = statistics.geometryByteLength; result.texturesByteLength = statistics.texturesByteLength; + result.texturesReferenceCounterById = { + ...statistics.texturesReferenceCounterById, + }; result.batchTableByteLength = statistics.batchTableByteLength; }; export default Cesium3DTilesetStatistics; diff --git a/packages/engine/Source/Scene/DerivedCommand.js b/packages/engine/Source/Scene/DerivedCommand.js index 8d70e283ac6a..8e3478fc65f3 100644 --- a/packages/engine/Source/Scene/DerivedCommand.js +++ b/packages/engine/Source/Scene/DerivedCommand.js @@ -1,3 +1,4 @@ +import { MetadataComponentType } from "@cesium/engine"; import defined from "../Core/defined.js"; import DrawCommand from "../Renderer/DrawCommand.js"; import RenderState from "../Renderer/RenderState.js"; @@ -416,6 +417,98 @@ function getGlslType(classProperty) { return `ivec${componentCount}`; } +/** + * Returns a shader statement that applies the inverse of the + * value transform to the given value, based on the given offset + * and scale. + * + * @param {string} input The input value + * @param {string} offset The offset + * @param {string} scale The scale + * @returns {string} The statement + */ +function unapplyValueTransform(input, offset, scale) { + return `((${input} - float(${offset})) / float(${scale}))`; +} + +/** + * Returns a shader statement that applies the inverse of the + * normalization, based on the given component type + * + * @param {string} input The input value + * @param {string} componentType The component type + * @returns {string} The statement + */ +function unnormalize(input, componentType) { + const max = MetadataComponentType.getMaximum(componentType); + return `(${input}) / float(${max})`; +} + +/** + * Creates a shader statement that returns the value of the specified + * property, normalized to the range [0, 1]. + * + * @param {MetadataClassProperty} classProperty The class property + * @param {object} metadataProperty The metadata property, either + * a `PropertyTextureProperty` or a `PropertyAttributeProperty` + * @returns {string} The string + */ +function getSourceValueStringScalar(classProperty, metadataProperty) { + let result = `float(value)`; + + // The 'hasValueTransform' indicates whether the property + // (or its class property) did define an 'offset' or 'scale'. + // Even when they had not been defined in the JSON, they are + // defined in the object, with default values. + if (metadataProperty.hasValueTransform) { + const offset = metadataProperty.offset; + const scale = metadataProperty.scale; + result = unapplyValueTransform(result, offset, scale); + } + if (!classProperty.normalized) { + result = unnormalize(result, classProperty.componentType); + } + return result; +} + +/** + * Creates a shader statement that returns the value of the specified + * component of the given property, normalized to the range [0, 1]. + * + * @param {MetadataClassProperty} classProperty The class property + * @param {object} metadataProperty The metadata property, either + * a `PropertyTextureProperty` or a `PropertyAttributeProperty` + * @param {string} componentName The name, in ["x", "y", "z", "w"] + * @returns {string} The string + */ +function getSourceValueStringComponent( + classProperty, + metadataProperty, + componentName, +) { + const valueString = `value.${componentName}`; + let result = `float(${valueString})`; + + // The 'hasValueTransform' indicates whether the property + // (or its class property) did define an 'offset' or 'scale'. + // Even when they had not been defined in the JSON, they are + // defined in the object, with default values + // Note that in the 'PropertyTextureProperty' and the + // 'PropertyAttributeProperty', these values are + // stored as "object types" (like 'Cartesian2'), whereas + // in the 'MetadataClassProperty', they are stored as + // "array types", e.g. a `[number, number]` + if (metadataProperty.hasValueTransform) { + const offset = metadataProperty.offset[componentName]; + const scale = metadataProperty.scale[componentName]; + result = unapplyValueTransform(result, offset, scale); + } + if (!classProperty.normalized) { + result = unnormalize(result, classProperty.componentType); + } + return result; +} + /** * Creates a new `ShaderProgram` from the given input that renders metadata * values into the frame buffer, according to the given picked metadata info. @@ -452,34 +545,34 @@ function getPickMetadataShaderProgram( return shader; } + const metadataProperty = pickedMetadataInfo.metadataProperty; const classProperty = pickedMetadataInfo.classProperty; const glslType = getGlslType(classProperty); // Define the components that will go into the output `metadataValues`. + // This will be the 'color' that is written into the frame buffer, + // meaning that the values should be in [0.0, 1.0], and will become + // values in [0, 255] in the frame buffer. // By default, all of them are 0.0. const sourceValueStrings = ["0.0", "0.0", "0.0", "0.0"]; const componentCount = getComponentCount(classProperty); if (componentCount === 1) { - // When the property is a scalar, store its value directly - // in `metadataValues.x` - sourceValueStrings[0] = `float(value)`; + // When the property is a scalar, store the source value + // string directly in `metadataValues.x` + sourceValueStrings[0] = getSourceValueStringScalar( + classProperty, + metadataProperty, + ); } else { // When the property is an array, store the array elements // in `metadataValues.x/y/z/w` - const components = ["x", "y", "z", "w"]; - for (let i = 0; i < componentCount; i++) { - const component = components[i]; - const valueString = `value.${component}`; - sourceValueStrings[i] = `float(${valueString})`; - } - } - - // Make sure that the `metadataValues` components are all in - // the range [0, 1] (which will result in RGBA components - // in [0, 255] during rendering) - if (!classProperty.normalized) { + const componentNames = ["x", "y", "z", "w"]; for (let i = 0; i < componentCount; i++) { - sourceValueStrings[i] += " / 255.0"; + sourceValueStrings[i] = getSourceValueStringComponent( + classProperty, + metadataProperty, + componentNames[i], + ); } } diff --git a/packages/engine/Source/Scene/DynamicEnvironmentMapManager.js b/packages/engine/Source/Scene/DynamicEnvironmentMapManager.js index d8d140ce29f9..f3897e2ff0c3 100644 --- a/packages/engine/Source/Scene/DynamicEnvironmentMapManager.js +++ b/packages/engine/Source/Scene/DynamicEnvironmentMapManager.js @@ -12,6 +12,7 @@ import PixelFormat from "../Core/PixelFormat.js"; import SceneMode from "./SceneMode.js"; import Transforms from "../Core/Transforms.js"; import ComputeCommand from "../Renderer/ComputeCommand.js"; +import ContextLimits from "../Renderer/ContextLimits.js"; import CubeMap from "../Renderer/CubeMap.js"; import Framebuffer from "../Renderer/Framebuffer.js"; import Texture from "../Renderer/Texture.js"; @@ -79,7 +80,11 @@ function DynamicEnvironmentMapManager(options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - const mipmapLevels = defaultValue(options.mipmapLevels, 10); + const mipmapLevels = Math.min( + defaultValue(options.mipmapLevels, 10), + Math.log2(ContextLimits.maximumCubeMapSize), + ); + this._mipmapLevels = mipmapLevels; this._radianceMapComputeCommands = new Array(6); this._convolutionComputeCommands = new Array((mipmapLevels - 1) * 6); @@ -95,7 +100,8 @@ function DynamicEnvironmentMapManager(options) { this._radianceCubeMap = undefined; this._irradianceMapTexture = undefined; - this._sphericalHarmonicCoefficients = new Array(9); + this._sphericalHarmonicCoefficients = + DynamicEnvironmentMapManager.DEFAULT_SPHERICAL_HARMONIC_COEFFICIENTS.slice(); this._lastTime = new JulianDate(); const width = Math.pow(2, mipmapLevels - 1); @@ -294,6 +300,63 @@ Object.defineProperties(DynamicEnvironmentMapManager.prototype, { }, }); +// Internally manage a queue of commands across all instances to prevent too many commands from being added in a single frame and using too much memory at once. +DynamicEnvironmentMapManager._maximumComputeCommandCount = 8; // This value is updated once a context is created. +DynamicEnvironmentMapManager._activeComputeCommandCount = 0; +DynamicEnvironmentMapManager._nextFrameCommandQueue = []; +/** + * Add a command to the queue. If possible, it will be added to the list of commands for the next frame. Otherwise, it will be added to a backlog + * and attempted next frame. + * @private + * @param {ComputeCommand} command The created command + * @param {FrameState} frameState The current frame state + */ +DynamicEnvironmentMapManager._queueCommand = (command, frameState) => { + if ( + DynamicEnvironmentMapManager._activeComputeCommandCount >= + DynamicEnvironmentMapManager._maximumComputeCommandCount + ) { + // Command will instead be scheduled next frame + DynamicEnvironmentMapManager._nextFrameCommandQueue.push(command); + return; + } + + frameState.commandList.push(command); + DynamicEnvironmentMapManager._activeComputeCommandCount++; +}; +/** + * If there are any backlogged commands, queue up as many as possible for the next frame. + * @private + * @param {FrameState} frameState The current frame state + */ +DynamicEnvironmentMapManager._updateCommandQueue = (frameState) => { + DynamicEnvironmentMapManager._maximumComputeCommandCount = Math.log2( + ContextLimits.maximumCubeMapSize, + ); // Scale relative to GPU resources available + + if ( + DynamicEnvironmentMapManager._nextFrameCommandQueue.length > 0 && + DynamicEnvironmentMapManager._activeComputeCommandCount < + DynamicEnvironmentMapManager._maximumComputeCommandCount + ) { + let command = DynamicEnvironmentMapManager._nextFrameCommandQueue.shift(); + while ( + defined(command) && + DynamicEnvironmentMapManager._activeComputeCommandCount < + DynamicEnvironmentMapManager._maximumComputeCommandCount + ) { + if (command.canceled) { + command = DynamicEnvironmentMapManager._nextFrameCommandQueue.shift(); + continue; + } + + frameState.commandList.push(command); + DynamicEnvironmentMapManager._activeComputeCommandCount++; + command = DynamicEnvironmentMapManager._nextFrameCommandQueue.shift(); + } + } +}; + /** * Sets the owner for the input DynamicEnvironmentMapManager if there wasn't another owner. * Destroys the owner's previous DynamicEnvironmentMapManager if setting is successful. @@ -333,15 +396,25 @@ DynamicEnvironmentMapManager.setOwner = function ( DynamicEnvironmentMapManager.prototype.reset = function () { let length = this._radianceMapComputeCommands.length; for (let i = 0; i < length; ++i) { + if (defined(this._radianceMapComputeCommands[i])) { + this._radianceMapComputeCommands[i].canceled = true; + DynamicEnvironmentMapManager._activeComputeCommandCount--; + } this._radianceMapComputeCommands[i] = undefined; } length = this._convolutionComputeCommands.length; for (let i = 0; i < length; ++i) { + if (defined(this._convolutionComputeCommands[i])) { + this._convolutionComputeCommands[i].canceled = true; + DynamicEnvironmentMapManager._activeComputeCommandCount--; + } this._convolutionComputeCommands[i] = undefined; } if (defined(this._irradianceComputeCommand)) { + this._irradianceComputeCommand.canceled = true; + DynamicEnvironmentMapManager._activeComputeCommandCount--; this._irradianceComputeCommand = undefined; } @@ -519,14 +592,17 @@ function updateRadianceMap(manager, frameState) { framebuffer._unBind(); framebuffer.destroy(); + DynamicEnvironmentMapManager._activeComputeCommandCount--; + if (!commands.some(defined)) { manager._convolutionsCommandsDirty = true; manager._shouldRegenerateShaders = true; } }, }); - frameState.commandList.push(command); + manager._radianceMapComputeCommands[i] = command; + DynamicEnvironmentMapManager._queueCommand(command, frameState); i++; } manager._radianceCommandsDirty = false; @@ -553,7 +629,7 @@ function updateSpecularMaps(manager, frameState) { const getPostExecute = (index, texture, face, level) => () => { // Copy output texture to corresponding face and mipmap level const commands = manager._convolutionComputeCommands; - if (!defined(commands[index])) { + if (!defined(commands[index]) || commands[index].canceled) { // This command was cancelled return; } @@ -561,6 +637,7 @@ function updateSpecularMaps(manager, frameState) { radianceCubeMap.copyFace(frameState, texture, face, level); facesCopied++; + DynamicEnvironmentMapManager._activeComputeCommandCount--; // All faces and levels have been copied if (facesCopied === manager._specularMapTextures.length) { @@ -610,7 +687,7 @@ function updateSpecularMaps(manager, frameState) { owner: manager, uniformMap: { u_roughness: () => level / (mipmapLevels - 1), - u_radianceTexture: () => radianceCubeMap, + u_radianceTexture: () => radianceCubeMap ?? context.defaultTexture, u_faceDirection: () => { return CubeMap.getDirection(face, scratchCartesian); }, @@ -618,7 +695,7 @@ function updateSpecularMaps(manager, frameState) { postExecute: getPostExecute(index, texture, face, level), }); manager._convolutionComputeCommands[index] = command; - frameState.commandList.push(command); + DynamicEnvironmentMapManager._queueCommand(command, frameState); ++index; } @@ -663,7 +740,7 @@ function updateIrradianceResources(manager, frameState) { fragmentShaderSource: fs, outputTexture: texture, uniformMap: { - u_radianceMap: () => manager._radianceCubeMap, + u_radianceMap: () => manager._radianceCubeMap ?? context.defaultTexture, }, postExecute: () => { if (!defined(manager._irradianceComputeCommand)) { @@ -673,10 +750,12 @@ function updateIrradianceResources(manager, frameState) { manager._irradianceTextureDirty = false; manager._irradianceComputeCommand = undefined; manager._sphericalHarmonicCoefficientsDirty = true; + + DynamicEnvironmentMapManager._activeComputeCommandCount--; }, }); manager._irradianceComputeCommand = command; - frameState.commandList.push(command); + DynamicEnvironmentMapManager._queueCommand(command, frameState); manager._irradianceTextureDirty = true; } @@ -727,8 +806,13 @@ function updateSphericalHarmonicCoefficients(manager, frameState) { */ DynamicEnvironmentMapManager.prototype.update = function (frameState) { const mode = frameState.mode; + const isSupported = + // A FrameState type works here because the function only references the context parameter. + // @ts-ignore + DynamicEnvironmentMapManager.isDynamicUpdateSupported(frameState); if ( + !isSupported || !this.enabled || !this.shouldUpdate || !defined(this._position) || @@ -738,6 +822,8 @@ DynamicEnvironmentMapManager.prototype.update = function (frameState) { return; } + DynamicEnvironmentMapManager._updateCommandQueue(frameState); + const dynamicLighting = frameState.atmosphere.dynamicLighting; const regenerateEnvironmentMap = atmosphereNeedsUpdate(this, frameState) || @@ -841,12 +927,48 @@ DynamicEnvironmentMapManager.prototype.destroy = function () { return destroyObject(this); }; +/** + * Returns true if dynamic updates are supported in the current WebGL rendering context. + * Dynamic updates requires the EXT_color_buffer_float or EXT_color_buffer_half_float extension. + * + * @param {Scene} scene The object containing the rendering context + * @returns {boolean} true if supported + */ +DynamicEnvironmentMapManager.isDynamicUpdateSupported = function (scene) { + const context = scene.context; + return context.halfFloatingPointTexture || context.colorBufferFloat; +}; + /** * Average hue of ground color on earth, a warm green-gray. * @type {Color} + * @readonly */ DynamicEnvironmentMapManager.AVERAGE_EARTH_GROUND_COLOR = Object.freeze( Color.fromCssColorString("#717145"), ); +/** + * The default third order spherical harmonic coefficients used for the diffuse color of image-based lighting, a white ambient light with low intensity. + *

+ * There are nine Cartesian3 coefficients. + * The order of the coefficients is: L0,0, L1,-1, L1,0, L1,1, L2,-2, L2,-1, L2,0, L2,1, L2,2 + *

+ * @readonly + * @type {Cartesian3[]} + * @see {@link https://graphics.stanford.edu/papers/envmap/envmap.pdf|An Efficient Representation for Irradiance Environment Maps} + */ +DynamicEnvironmentMapManager.DEFAULT_SPHERICAL_HARMONIC_COEFFICIENTS = + Object.freeze([ + Object.freeze(new Cartesian3(0.35449, 0.35449, 0.35449)), + Cartesian3.ZERO, + Cartesian3.ZERO, + Cartesian3.ZERO, + Cartesian3.ZERO, + Cartesian3.ZERO, + Cartesian3.ZERO, + Cartesian3.ZERO, + Cartesian3.ZERO, + ]); + export default DynamicEnvironmentMapManager; diff --git a/packages/engine/Source/Scene/GltfTextureLoader.js b/packages/engine/Source/Scene/GltfTextureLoader.js index 4c07eef67629..afa6dad8f177 100644 --- a/packages/engine/Source/Scene/GltfTextureLoader.js +++ b/packages/engine/Source/Scene/GltfTextureLoader.js @@ -170,6 +170,7 @@ GltfTextureLoader.prototype.load = async function () { function CreateTextureJob() { this.gltf = undefined; this.textureInfo = undefined; + this.textureId = undefined; this.image = undefined; this.context = undefined; this.texture = undefined; @@ -178,12 +179,14 @@ function CreateTextureJob() { CreateTextureJob.prototype.set = function ( gltf, textureInfo, + textureId, image, mipLevels, context, ) { this.gltf = gltf; this.textureInfo = textureInfo; + this.textureId = textureId; this.image = image; this.mipLevels = mipLevels; this.context = context; @@ -193,13 +196,21 @@ CreateTextureJob.prototype.execute = function () { this.texture = createTexture( this.gltf, this.textureInfo, + this.textureId, this.image, this.mipLevels, this.context, ); }; -function createTexture(gltf, textureInfo, image, mipLevels, context) { +function createTexture( + gltf, + textureInfo, + textureId, + image, + mipLevels, + context, +) { // internalFormat is only defined for CompressedTextureBuffer const internalFormat = image.internalFormat; @@ -261,6 +272,7 @@ function createTexture(gltf, textureInfo, image, mipLevels, context) { } texture = Texture.create({ + id: textureId, context: context, source: { arrayBufferView: image.bufferView, // Only defined for CompressedTextureBuffer @@ -276,6 +288,7 @@ function createTexture(gltf, textureInfo, image, mipLevels, context) { image = resizeImageToNextPowerOfTwo(image); } texture = Texture.create({ + id: textureId, context: context, source: image, sampler: sampler, @@ -332,6 +345,7 @@ GltfTextureLoader.prototype.process = function (frameState) { textureJob.set( this._gltf, this._textureInfo, + this._cacheKey, this._image, this._mipLevels, frameState.context, @@ -346,6 +360,7 @@ GltfTextureLoader.prototype.process = function (frameState) { texture = createTexture( this._gltf, this._textureInfo, + this._cacheKey, this._image, this._mipLevels, frameState.context, diff --git a/packages/engine/Source/Scene/ITwinData.js b/packages/engine/Source/Scene/ITwinData.js new file mode 100644 index 000000000000..1b53f27e4c9e --- /dev/null +++ b/packages/engine/Source/Scene/ITwinData.js @@ -0,0 +1,138 @@ +import Cesium3DTileset from "./Cesium3DTileset.js"; +import defined from "../Core/defined.js"; +import Resource from "../Core/Resource.js"; +import ITwinPlatform from "../Core/ITwinPlatform.js"; +import RuntimeError from "../Core/RuntimeError.js"; +import Check from "../Core/Check.js"; + +/** + * Methods for loading iTwin platform data into CesiumJS + * + * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy. + * + * @see ITwinPlatform + * @namespace ITwinData + */ +const ITwinData = {}; + +/** + * Create a {@link Cesium3DTileset} for the given iModel id using iTwin's Mesh Export API. + * + * If there is not a completed export available for the given iModel id, the returned promise will resolve to undefined. + * We recommend waiting 10-20 seconds and trying to load the tileset again. + * If all exports are Invalid this will throw an error. + * + * @example + * const tileset = await Cesium.ITwinData.createTilesetFromIModelId(iModelId); + * if (Cesium.defined(tileset)) { + * viewer.scene.primitives.add(tileset); + * } + * + * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy. + * + * @param {string} iModelId The id of the iModel to load + * @param {Cesium3DTileset.ConstructorOptions} [options] Object containing options to pass to the internally created {@link Cesium3DTileset}. + * @returns {Promise} A promise that will resolve to the created 3D tileset or undefined if there is no completed export for the given iModel id + * + * @throws {RuntimeError} If all exports for the given iModel are Invalid + * @throws {RuntimeError} If the iTwin API request is not successful + */ +ITwinData.createTilesetFromIModelId = async function (iModelId, options) { + const { exports } = await ITwinPlatform.getExports(iModelId); + + if ( + exports.length > 0 && + exports.every((exportObj) => { + return exportObj.status === ITwinPlatform.ExportStatus.Invalid; + }) + ) { + throw new RuntimeError( + `All exports for this iModel are Invalid: ${iModelId}`, + ); + } + + const completeExport = exports.find((exportObj) => { + return exportObj.status === ITwinPlatform.ExportStatus.Complete; + }); + + if (!defined(completeExport)) { + return; + } + + // Convert the link to the tileset url while preserving the search paramaters + // This link is only valid 1 hour + const baseUrl = new URL(completeExport._links.mesh.href); + baseUrl.pathname = `${baseUrl.pathname}/tileset.json`; + const tilesetUrl = baseUrl.toString(); + + const resource = new Resource({ + url: tilesetUrl, + }); + + return Cesium3DTileset.fromUrl(resource, options); +}; + +/** + * Create a tileset for the specified reality data id. This function only works + * with 3D Tiles meshes and point clouds. + * + * If the type or rootDocument are not provided this function + * will first request the full metadata for the specified reality data to fill these values. + * + * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy. + * + * @param {string} iTwinId The id of the iTwin to load data from + * @param {string} realityDataId The id of the reality data to load + * @param {ITwinPlatform.RealityDataType} [type] The type of this reality data + * @param {string} [rootDocument] The path of the root document for this reality data + * @returns {Promise} + */ +ITwinData.createTilesetForRealityDataId = async function ( + iTwinId, + realityDataId, + type, + rootDocument, +) { + //>>includeStart('debug', pragmas.debug); + Check.typeOf.string("iTwinId", iTwinId); + Check.typeOf.string("realityDataId", realityDataId); + if (defined(type)) { + Check.typeOf.string("type", type); + } + if (defined(rootDocument)) { + Check.typeOf.string("rootDocument", rootDocument); + } + //>>includeEnd('debug') + + if (!defined(type) || !defined(rootDocument)) { + const metadata = await ITwinPlatform.getRealityDataMetadata( + iTwinId, + realityDataId, + ); + rootDocument = metadata.rootDocument; + type = metadata.type; + } + + const supportedRealityDataTypes = [ + ITwinPlatform.RealityDataType.Cesium3DTiles, + ITwinPlatform.RealityDataType.PNTS, + ITwinPlatform.RealityDataType.RealityMesh3DTiles, + ITwinPlatform.RealityDataType.Terrain3DTiles, + ]; + + if (!supportedRealityDataTypes.includes(type)) { + throw new RuntimeError(`Reality data type is not a mesh type: ${type}`); + } + + const tilesetAccessUrl = await ITwinPlatform.getRealityDataURL( + iTwinId, + realityDataId, + rootDocument, + ); + + return Cesium3DTileset.fromUrl(tilesetAccessUrl, { + maximumScreenSpaceError: 4, + }); +}; + +export default ITwinData; diff --git a/packages/engine/Source/Scene/Label.js b/packages/engine/Source/Scene/Label.js index 7196877768a9..61168a5ff2c0 100644 --- a/packages/engine/Source/Scene/Label.js +++ b/packages/engine/Source/Scene/Label.js @@ -400,8 +400,7 @@ Object.defineProperties(Label.prototype, { if (this._text !== value) { this._text = value; - // Strip soft-hyphen (auto-wrap) characters from input string - const renderedValue = value.replace(/\u00ad/g, ""); + const renderedValue = Label.filterUnsupportedCharacters(value); this._renderedText = Label.enableRightToLeftDetection ? reverseRtl(renderedValue) : renderedValue; @@ -1346,6 +1345,21 @@ Label.getScreenSpaceBoundingBox = function ( return result; }; +/** + * Removes control characters and soft hyphon (auto-wrap) characters, which will cause an error when rendering a glyph. This does not remove tabs, carriage returns, or newlines. + * @private + * @param {string} text The original label text + * @returns {string} The renderable filtered text + */ +Label.filterUnsupportedCharacters = function (text) { + const problematicCharactersRegex = new RegExp( + // eslint-disable-next-line no-control-regex + /[\u0000-\u0008\u000E-\u001F\u00ad\u202a-\u206f\u200b-\u200f]/, + "g", + ); + return text.replace(problematicCharactersRegex, ""); +}; + /** * Determines if this label equals another label. Labels are equal if all their properties * are equal. Labels in different collections can be equal. @@ -1502,7 +1516,7 @@ function reverseBrackets(bracket) { } } -//To add another language, simply add its Unicode block range(s) to the below regex. +// To add another language, add its Unicode block range(s) to the below regex. const hebrew = "\u05D0-\u05EA"; const arabic = "\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF"; const rtlChars = new RegExp(`[${hebrew}${arabic}]`); diff --git a/packages/engine/Source/Scene/MetadataClassProperty.js b/packages/engine/Source/Scene/MetadataClassProperty.js index dec9b1393e3e..b51a79884817 100644 --- a/packages/engine/Source/Scene/MetadataClassProperty.js +++ b/packages/engine/Source/Scene/MetadataClassProperty.js @@ -438,6 +438,10 @@ Object.defineProperties(MetadataClassProperty.prototype, { /** * The offset to be added to property values as part of the value transform. * + * This is always defined, even when `hasValueTransform` is `false`. If + * the class property JSON itself did not define it, then it will be + * initialized to the default value. + * * @memberof MetadataClassProperty.prototype * @type {number|number[]|number[][]} * @readonly @@ -451,6 +455,10 @@ Object.defineProperties(MetadataClassProperty.prototype, { /** * The scale to be multiplied to property values as part of the value transform. * + * This is always defined, even when `hasValueTransform` is `false`. If + * the class property JSON itself did not define it, then it will be + * initialized to the default value. + * * @memberof MetadataClassProperty.prototype * @type {number|number[]|number[][]} * @readonly @@ -1139,6 +1147,24 @@ function normalizeInPlace(values, valueType, normalizeFunction) { } /** + * Applies the value transform that is defined with the given offsets + * and scales to the given values. + * + * If the given values are not an array, then the given transformation + * function will be applied directly. + * + * If the values are an array, then this function will be called recursively + * with the array elements, boiling down to a component-wise application + * of the transformation function to the innermost array elements. + * + * @param {number|number[]|number[][]} values The input values + * @param {number|number[]|number[][]} offsets The offsets + * @param {number|number[]|number[][]} scales The scales + * @param {Function} transformationFunction The function with the signature + * `(value:number, offset:number, scale:number) : number` that will be + * applied to the innermost elements + * @returns The input values (or the result of applying the transformation + * function to a single value if the values have not been an array). * @private */ MetadataClassProperty.valueTransformInPlace = function ( diff --git a/packages/engine/Source/Scene/MetadataPicking.js b/packages/engine/Source/Scene/MetadataPicking.js index 87f33a91d7d3..1ecbb639a57a 100644 --- a/packages/engine/Source/Scene/MetadataPicking.js +++ b/packages/engine/Source/Scene/MetadataPicking.js @@ -6,6 +6,7 @@ import Matrix2 from "../Core/Matrix2.js"; import Matrix3 from "../Core/Matrix3.js"; import Matrix4 from "../Core/Matrix4.js"; import RuntimeError from "../Core/RuntimeError.js"; +import MetadataClassProperty from "./MetadataClassProperty.js"; import MetadataComponentType from "./MetadataComponentType.js"; import MetadataType from "./MetadataType.js"; @@ -29,6 +30,10 @@ const MetadataPicking = {}; * @param {DataView} dataView The data view * @param {number} index The index (byte offset) * @returns {number|bigint|undefined} The value + * @throws RuntimeError If the given component type is not a valid + * `MetadataComponentType` + * @throws RangeError If reading the data from the given data view would + * cause an out-of-bounds access * * @private */ @@ -43,21 +48,21 @@ MetadataPicking.decodeRawMetadataValue = function ( case MetadataComponentType.UINT8: return dataView.getUint8(index); case MetadataComponentType.INT16: - return dataView.getInt16(index); + return dataView.getInt16(index, true); case MetadataComponentType.UINT16: - return dataView.getUint16(index); + return dataView.getUint16(index, true); case MetadataComponentType.INT32: - return dataView.getInt32(index); + return dataView.getInt32(index, true); case MetadataComponentType.UINT32: - return dataView.getUint32(index); + return dataView.getUint32(index, true); case MetadataComponentType.INT64: - return dataView.getBigInt64(index); + return dataView.getBigInt64(index, true); case MetadataComponentType.UINT64: - return dataView.getBigUint64(index); + return dataView.getBigUint64(index, true); case MetadataComponentType.FLOAT32: - return dataView.getFloat32(index); + return dataView.getFloat32(index, true); case MetadataComponentType.FLOAT64: - return dataView.getFloat64(index); + return dataView.getFloat64(index, true); } throw new RuntimeError(`Invalid component type: ${componentType}`); }; @@ -77,6 +82,10 @@ MetadataPicking.decodeRawMetadataValue = function ( * @param {number} dataViewOffset The byte offset within the data view from * which the component should be read * @returns {number|bigint|undefined} The metadata value component + * @throws RuntimeError If the component of the given property is not + * a valid `MetadataComponentType` + * @throws RangeError If reading the data from the given data view would + * cause an out-of-bounds access */ MetadataPicking.decodeRawMetadataValueComponent = function ( classProperty, @@ -114,6 +123,11 @@ MetadataPicking.decodeRawMetadataValueComponent = function ( * @param {number} elementIndex The index of the element. This is the index * inside the array for array-typed properties, and 0 for non-array types. * @returns {number|number[]|bigint|bigint[]|undefined} The decoded metadata value element + * @throws RuntimeError If the component of the given property is not + * a valid `MetadataComponentType` + * @throws RangeError If reading the data from the given data view would + * cause an out-of-bounds access + * */ MetadataPicking.decodeRawMetadataValueElement = function ( classProperty, @@ -183,6 +197,7 @@ MetadataPicking.decodeRawMetadataValueElement = function ( * @param {MetadataClassProperty} classProperty The `MetadataClassProperty` * @param {Uint8Array} rawPixelValues The raw values * @returns {number|bigint|number[]|bigint[]|undefined} The value + * @throws RuntimeError If the class property has an invalid component type * * @private */ @@ -229,7 +244,8 @@ MetadataPicking.decodeRawMetadataValues = function ( * * @param {string} type The `ClassProperty` type * @param {number|bigint|number[]|bigint[]|undefined} value The input value - * @returns {any} The object representation + * @returns {undefined|number|bigint|string|boolean|Cartesian2|Cartesian3|Cartesian4|Matrix2|Matrix3|Matrix4} The object representation + * @throws RuntimeError If the type is not a valid `MetadataType` */ MetadataPicking.convertToObjectType = function (type, value) { if (!defined(value)) { @@ -250,7 +266,7 @@ MetadataPicking.convertToObjectType = function (type, value) { case MetadataType.VEC3: return Cartesian3.unpack(numbers, 0, new Cartesian3()); case MetadataType.VEC4: - return Cartesian4.unpack(numbers, 0, new Cartesian3()); + return Cartesian4.unpack(numbers, 0, new Cartesian4()); case MetadataType.MAT2: return Matrix2.unpack(numbers, 0, new Matrix2()); case MetadataType.MAT3: @@ -259,29 +275,104 @@ MetadataPicking.convertToObjectType = function (type, value) { return Matrix4.unpack(numbers, 0, new Matrix4()); } // Should never happen: - return value; + throw new RuntimeError(`Invalid metadata object type: ${type}`); +}; + +/** + * Converts the given type into a raw value or array representation. + * + * For `VECn/MATn` types, the given value is converted into an array. + * For other types, the value is returned directly + * + * @param {string} type The `ClassProperty` type + * @param {undefined|number|bigint|string|boolean|Cartesian2|Cartesian3|Cartesian4|Matrix2|Matrix3|Matrix4} value The input value + * @returns {undefined|number|bigint|string|boolean|number[]} The array representation + * @throws RuntimeError If the type is not a valid `MetadataType` + */ +MetadataPicking.convertFromObjectType = function (type, value) { + if (!defined(value)) { + return value; + } + if ( + type === MetadataType.SCALAR || + type === MetadataType.STRING || + type === MetadataType.BOOLEAN || + type === MetadataType.ENUM + ) { + return value; + } + switch (type) { + case MetadataType.VEC2: + return Cartesian2.pack(value, Array(2)); + case MetadataType.VEC3: + return Cartesian3.pack(value, Array(3)); + case MetadataType.VEC4: + return Cartesian4.pack(value, Array(4)); + case MetadataType.MAT2: + return Matrix2.pack(value, Array(4)); + case MetadataType.MAT3: + return Matrix3.pack(value, Array(9)); + case MetadataType.MAT4: + return Matrix4.pack(value, Array(16)); + } + // Should never happen: + throw new RuntimeError(`Invalid metadata object type: ${type}`); }; /** * Decode the given raw values into a metadata property value. * - * This just converts the result of `decodeRawMetadataValues` - * from array-based types into object types like `CartesianN`. + * This applies the value transform (offset/scale) to the result + * of `decodeRawMetadataValues`, and converts this from array-based + * types into object types like `CartesianN`. * * @param {MetadataClassProperty} classProperty The `MetadataClassProperty` + * @param {object} metadataProperty The + * `PropertyTextureProperty` or `PropertyAttributeProperty` * @param {Uint8Array} rawPixelValues The raw values - * @returns {any} The value + * @returns {MetadataValue} The value + * @throws RuntimeError If the class property has an invalid type + * or component type + * @throws RangeError If the given pixel values do not have sufficient + * size to contain the expected value type * * @private */ MetadataPicking.decodeMetadataValues = function ( classProperty, + metadataProperty, rawPixelValues, ) { - const arrayBasedResult = MetadataPicking.decodeRawMetadataValues( + let arrayBasedResult = MetadataPicking.decodeRawMetadataValues( classProperty, rawPixelValues, ); + + if (metadataProperty.hasValueTransform) { + // In the MetadataClassProperty, these offset/scale are always in + // their array-based form (e.g. a number[3] for `VEC3`). But for + // the PropertyTextureProperty and PropertyAttributeProperty, + // the type of the offset/scale is defined to be + // number|Cartesian2|Cartesian3|Cartesian4|Matrix2|Matrix3|Matrix4 + // So these types are converted into their array-based form here, before + // applying them with `MetadataClassProperty.valueTransformInPlace` + + const offset = MetadataPicking.convertFromObjectType( + classProperty.type, + metadataProperty.offset, + ); + const scale = MetadataPicking.convertFromObjectType( + classProperty.type, + metadataProperty.scale, + ); + arrayBasedResult = MetadataClassProperty.valueTransformInPlace( + arrayBasedResult, + offset, + scale, + MetadataComponentType.applyValueTransform, + ); + } + if (classProperty.isArray) { const arrayLength = classProperty.arrayLength; const result = Array(arrayLength); @@ -295,11 +386,11 @@ MetadataPicking.decodeMetadataValues = function ( } return result; } - const result = MetadataPicking.convertToObjectType( + const objectResult = MetadataPicking.convertToObjectType( classProperty.type, arrayBasedResult, ); - return result; + return objectResult; }; export default Object.freeze(MetadataPicking); diff --git a/packages/engine/Source/Scene/MetadataType.js b/packages/engine/Source/Scene/MetadataType.js index 9bb0a2e8c7d5..c00e91f2cb1e 100644 --- a/packages/engine/Source/Scene/MetadataType.js +++ b/packages/engine/Source/Scene/MetadataType.js @@ -7,6 +7,26 @@ import Matrix2 from "../Core/Matrix2.js"; import Matrix3 from "../Core/Matrix3.js"; import Matrix4 from "../Core/Matrix4.js"; +/** + * An instance of a metadata value.
+ *
+ * This can be one of the following types: + *
    + *
  • number for type SCALAR and numeric component types except for INT64 or UINT64
  • + *
  • bigint for type SCALAR and component type INT64 or UINT64
  • + *
  • string for type STRING or ENUM
  • + *
  • boolean for type BOOLEAN
  • + *
  • Cartesian2 for type VEC2
  • + *
  • Cartesian3 for type VEC3
  • + *
  • Cartesian4 for type VEC4
  • + *
  • Matrix2 for type MAT2
  • + *
  • Matrix3 for type MAT3
  • + *
  • Matrix4 for type MAT4
  • + *
  • Arrays of these types when the metadata value is an array
  • + *
+ * @typedef {(number|bigint|string|boolean|Cartesian2|Cartesian3|Cartesian4|Matrix2|Matrix3|Matrix4|number[]|bigint[]|string[]|boolean[]|Cartesian2[]|Cartesian3[]|Cartesian4[]|Matrix2[]|Matrix3[]|Matrix4[])} MetadataValue + */ + /** * An enum of metadata types. These metadata types are containers containing * one or more components of type {@link MetadataComponentType} diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js index 7be022144311..944d99ab23b7 100644 --- a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js +++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js @@ -234,7 +234,7 @@ GltfMeshPrimitiveGpmLoader.ppeTexturesMetadataSchemaCache = new Map(); * Create the JSON description of a metadata class that treats * the given PPE texture as a property texture property. * - * @param {any} ppeTexture - The PPE texture + * @param {PpeTexture} ppeTexture - The PPE texture * @param {number} index - The index of the texture in the extension * @returns The class JSON */ @@ -268,9 +268,9 @@ GltfMeshPrimitiveGpmLoader._createPpeTextureClassJson = function ( // property values when they are `normalized`, the values will be // declared as `normalized` here. // The normalization factor will later have to be cancelled out, - // when integrating the `scale` into the actual property texture - // property. In the property texture property, the `scale` has to - // be multiplied by 255. + // with the `scale` being multiplied by 255. + const offset = ppeTexture.offset ?? 0.0; + const scale = (ppeTexture.scale ?? 1.0) * 255.0; const classJson = { name: `PPE texture class ${index}`, properties: { @@ -279,6 +279,8 @@ GltfMeshPrimitiveGpmLoader._createPpeTextureClassJson = function ( type: "SCALAR", componentType: "UINT8", normalized: true, + offset: offset, + scale: scale, min: traits.min, max: traits.max, }, @@ -406,19 +408,12 @@ GltfMeshPrimitiveGpmLoader._convertToStructuralMetadata = function ( const ppePropertyName = traits.source; const metadataClass = ppeTexturesMetadataSchema.classes[classId]; - // The class property has been declared as `normalized`, so - // that `offset` and `scale` can be applied. The normalization - // factor has to be cancelled out here, by multiplying the - // `scale` with 255. - const scale = (ppeTexture.scale ?? 1.0) * 255.0; const ppeTextureAsPropertyTexture = { class: classId, properties: { [ppePropertyName]: { index: ppeTexture.index, texCoord: ppeTexture.texCoord, - offset: ppeTexture.offset, - scale: scale, }, }, }; diff --git a/packages/engine/Source/Scene/Model/Model3DTileContent.js b/packages/engine/Source/Scene/Model/Model3DTileContent.js index e4266704bdad..143acbe8cb48 100644 --- a/packages/engine/Source/Scene/Model/Model3DTileContent.js +++ b/packages/engine/Source/Scene/Model/Model3DTileContent.js @@ -152,12 +152,34 @@ Object.defineProperties(Model3DTileContent.prototype, { }, }); +/** + * Returns an array containing the `texture.id` values for all textures + * that are part of this content. + * + * @returns {string[]} The texture IDs + */ +Model3DTileContent.prototype.getTextureIds = function () { + return this._model.statistics.getTextureIds(); +}; + +/** + * Returns the length, in bytes, of the texture data for the texture with + * the given ID that is part of this content, or `undefined` if this + * content does not contain the texture with the given ID. + * + * @param {string} textureId The texture ID + * @returns {number|undefined} The texture byte length + */ +Model3DTileContent.prototype.getTextureByteLengthById = function (textureId) { + return this._model.statistics.getTextureByteLengthById(textureId); +}; + /** * Returns the object that was created for the given extension. * * The given name may be the name of a glTF extension, like `"EXT_example_extension"`. * If the specified extension was present in the root of the underlying glTF asset, - * and a loder for the specified extension has processed the extension data, then + * and a loader for the specified extension has processed the extension data, then * this will return the model representation of the extension. * * @param {string} extensionName The name of the extension diff --git a/packages/engine/Source/Scene/Model/ModelStatistics.js b/packages/engine/Source/Scene/Model/ModelStatistics.js index 3188895efc5a..b8a60af26df0 100644 --- a/packages/engine/Source/Scene/Model/ModelStatistics.js +++ b/packages/engine/Source/Scene/Model/ModelStatistics.js @@ -61,7 +61,15 @@ function ModelStatistics() { // Sets of buffers and textures that have already been counted. // This is to prevent double-counting cached assets. this._bufferIdSet = {}; - this._textureIdSet = {}; + + /** + * The mapping from `texture.id` strings to the byte length of the + * respective texture + * + * @type {object} + * @private + */ + this._textureIdByteLengths = {}; // Associated array of batch textures that have already been counted. // This allows for quick look-up to check if a texture has been counted, @@ -111,7 +119,7 @@ ModelStatistics.prototype.clear = function () { this.propertyTablesByteLength = 0; this._bufferIdSet = {}; - this._textureIdSet = {}; + this._textureIdByteLengths = {}; this._batchTextureIdMap.removeAll(); }; @@ -160,12 +168,32 @@ ModelStatistics.prototype.addTexture = function (texture) { Check.typeOf.object("texture", texture); //>>includeEnd('debug'); - if (!this._textureIdSet.hasOwnProperty(texture._id)) { + if (!this._textureIdByteLengths.hasOwnProperty(texture._id)) { this.texturesByteLength += texture.sizeInBytes; + this._textureIdByteLengths[texture._id] = texture.sizeInBytes; } +}; - // Simulate set insertion. - this._textureIdSet[texture._id] = true; +/** + * Returns an array containing the `texture.id` values for all textures + * that are part of the model. + * + * @returns {string[]} The texture IDs + */ +ModelStatistics.prototype.getTextureIds = function () { + return Object.keys(this._textureIdByteLengths); +}; + +/** + * Returns the length, in bytes, of the texture data for the texture with + * the given ID that is part of the model, or `undefined` if the model + * does not contain the texture with the given ID. + * + * @param {string} textureId The texture ID + * @returns {number|undefined} The texture byte length + */ +ModelStatistics.prototype.getTextureByteLengthById = function (textureId) { + return this._textureIdByteLengths[textureId]; }; /** diff --git a/packages/engine/Source/Scene/Model/PointCloudStylingPipelineStage.js b/packages/engine/Source/Scene/Model/PointCloudStylingPipelineStage.js index 967e07fcfe98..c89786f88f05 100644 --- a/packages/engine/Source/Scene/Model/PointCloudStylingPipelineStage.js +++ b/packages/engine/Source/Scene/Model/PointCloudStylingPipelineStage.js @@ -333,9 +333,10 @@ function addShaderFunctionsAndDefines(shaderBuilder, shaderFunctionInfo) { shaderBuilder.addDefine( "HAS_POINT_CLOUD_SHOW_STYLE", undefined, - ShaderDestination.VERTEX, + ShaderDestination.BOTH, ); shaderBuilder.addVertexLines(showStyleFunction); + shaderBuilder.addVarying("float", "v_pointCloudShow"); } const pointSizeStyleFunction = shaderFunctionInfo.pointSizeStyleFunction; diff --git a/packages/engine/Source/Scene/PickedMetadataInfo.js b/packages/engine/Source/Scene/PickedMetadataInfo.js index 1e8de1902b17..d58fa33e0451 100644 --- a/packages/engine/Source/Scene/PickedMetadataInfo.js +++ b/packages/engine/Source/Scene/PickedMetadataInfo.js @@ -6,11 +6,17 @@ * the metadata values of an object into the picking frame buffer. The * raw values are read from that buffer, and are then translated back into * proper metadata values in `Picking.pickMetadata`, using the structural - * information about the metadata `classProperty` that is stored here. + * information about the metadata that is stored here. * * @private */ -function PickedMetadataInfo(schemaId, className, propertyName, classProperty) { +function PickedMetadataInfo( + schemaId, + className, + propertyName, + classProperty, + metadataProperty, +) { /** * The optional ID of the metadata schema * @@ -29,11 +35,23 @@ function PickedMetadataInfo(schemaId, className, propertyName, classProperty) { * @type {string} */ this.propertyName = propertyName; + /** - * The optional ID of the metadata schema + * The the `MetadataClassProperty` that is described by this + * structure, as obtained from the `MetadataSchema` * * @type {MetadataClassProperty} */ this.classProperty = classProperty; + + /** + * The `PropertyTextureProperty` or `PropertyAttributeProperty` that + * is described by this structure, as obtained from the property texture + * or property attribute of the `StructuralMetadata` that matches the + * class name and property name. + * + * @type {object} + */ + this.metadataProperty = metadataProperty; } export default PickedMetadataInfo; diff --git a/packages/engine/Source/Scene/Picking.js b/packages/engine/Source/Scene/Picking.js index fc38a4a90955..c31490f9851c 100644 --- a/packages/engine/Source/Scene/Picking.js +++ b/packages/engine/Source/Scene/Picking.js @@ -426,9 +426,14 @@ Picking.prototype.pickVoxelCoordinate = function ( * - For `VEC3`, the return type will be a `Cartesian3` * - For `VEC4`, the return type will be a `Cartesian4` * + * Future implementations may additionally return `string`- or + * `boolean` types, and `MATn` values as `MatrixN` objects, + * and arrays of the respective types. + * * @param {Cartesian2} windowPosition Window coordinates to perform picking on. * @param {PickedMetadataInfo} pickedMetadataInfo Information about the picked metadata. - * @returns {any} The metadata values + * @returns {MetadataValue|undefined} The metadata value, or `undefined` + * when no matching metadata value could be picked at the given position * * @private */ @@ -517,6 +522,7 @@ Picking.prototype.pickMetadata = function ( const metadataValue = MetadataPicking.decodeMetadataValues( pickedMetadataInfo.classProperty, + pickedMetadataInfo.metadataProperty, rawMetadataPixel, ); diff --git a/packages/engine/Source/Scene/PostProcessStage.js b/packages/engine/Source/Scene/PostProcessStage.js index 44012ca77b56..454822ca4e8f 100644 --- a/packages/engine/Source/Scene/PostProcessStage.js +++ b/packages/engine/Source/Scene/PostProcessStage.js @@ -94,9 +94,16 @@ import PostProcessStageSampleMode from "./PostProcessStageSampleMode.js"; function PostProcessStage(options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); const { + name = createGuid(), fragmentShader, + uniforms, textureScale = 1.0, + forcePowerOfTwo = false, + sampleMode = PostProcessStageSampleMode.NEAREST, pixelFormat = PixelFormat.RGBA, + pixelDatatype = PixelDatatype.UNSIGNED_BYTE, + clearColor = Color.BLACK, + scissorRectangle, } = options; //>>includeStart('debug', pragmas.debug); @@ -113,19 +120,13 @@ function PostProcessStage(options) { //>>includeEnd('debug'); this._fragmentShader = fragmentShader; - this._uniforms = options.uniforms; + this._uniforms = uniforms; this._textureScale = textureScale; - this._forcePowerOfTwo = defaultValue(options.forcePowerOfTwo, false); - this._sampleMode = defaultValue( - options.sampleMode, - PostProcessStageSampleMode.NEAREST, - ); + this._forcePowerOfTwo = forcePowerOfTwo; + this._sampleMode = sampleMode; this._pixelFormat = pixelFormat; - this._pixelDatatype = defaultValue( - options.pixelDatatype, - PixelDatatype.UNSIGNED_BYTE, - ); - this._clearColor = defaultValue(options.clearColor, Color.BLACK); + this._pixelDatatype = pixelDatatype; + this._clearColor = clearColor; this._uniformMap = undefined; this._command = undefined; @@ -143,18 +144,14 @@ function PostProcessStage(options) { const passState = new PassState(); passState.scissorTest = { enabled: true, - rectangle: defined(options.scissorRectangle) - ? BoundingRectangle.clone(options.scissorRectangle) + rectangle: defined(scissorRectangle) + ? BoundingRectangle.clone(scissorRectangle) : new BoundingRectangle(), }; this._passState = passState; this._ready = false; - let name = options.name; - if (!defined(name)) { - name = createGuid(); - } this._name = name; this._logDepthChanged = undefined; diff --git a/packages/engine/Source/Scene/PostProcessStageCollection.js b/packages/engine/Source/Scene/PostProcessStageCollection.js index 59ca0e293923..20019fa840cd 100644 --- a/packages/engine/Source/Scene/PostProcessStageCollection.js +++ b/packages/engine/Source/Scene/PostProcessStageCollection.js @@ -155,32 +155,20 @@ Object.defineProperties(PostProcessStageCollection.prototype, { * surface receives light and regardless of the light's position. *

*

- * The uniforms have the following properties: intensity, bias, lengthCap, - * stepSize, frustumLength, ambientOcclusionOnly, - * delta, sigma, and blurStepSize. - *

+ * The uniforms have the following properties: *
    *
  • intensity is a scalar value used to lighten or darken the shadows exponentially. Higher values make the shadows darker. The default value is 3.0.
  • - * *
  • bias is a scalar value representing an angle in radians. If the dot product between the normal of the sample and the vector to the camera is less than this value, * sampling stops in the current direction. This is used to remove shadows from near planar edges. The default value is 0.1.
  • - * *
  • lengthCap is a scalar value representing a length in meters. If the distance from the current sample to first sample is greater than this value, * sampling stops in the current direction. The default value is 0.26.
  • - * - *
  • stepSize is a scalar value indicating the distance to the next texel sample in the current direction. The default value is 1.95.
  • - * - *
  • frustumLength is a scalar value in meters. If the current fragment has a distance from the camera greater than this value, ambient occlusion is not computed for the fragment. - * The default value is 1000.0.
  • - * + *
  • directionCount is the number of directions along which the ray marching will search for occluders. The default value is 8.
  • + *
  • stepCount is the number of steps the ray marching will take along each direction. The default value is 32.
  • + *
  • randomTexture is a texture where the red channel is a random value in [0.0, 1.0]. The default value is undefined. This texture needs to be set.
  • *
  • ambientOcclusionOnly is a boolean value. When true, only the shadows generated are written to the output. When false, the input texture is modulated * with the ambient occlusion. This is a useful debug option for seeing the effects of changing the uniform values. The default value is false.
  • *
*

- * delta, sigma, and blurStepSize are the same properties as {@link PostProcessStageLibrary#createBlurStage}. - * The blur is applied to the shadows generated from the image to make them smoother. - *

- *

* When enabled, this stage will execute before all others. *

* diff --git a/packages/engine/Source/Scene/PostProcessStageLibrary.js b/packages/engine/Source/Scene/PostProcessStageLibrary.js index f4329daee77f..9168c068da54 100644 --- a/packages/engine/Source/Scene/PostProcessStageLibrary.js +++ b/packages/engine/Source/Scene/PostProcessStageLibrary.js @@ -476,27 +476,19 @@ PostProcessStageLibrary.createBloomStage = function () { * surface receives light and regardless of the light's position. *

*

- * The uniforms have the following properties: intensity, bias, lengthCap, - * stepSize, frustumLength, randomTexture, ambientOcclusionOnly, - * delta, sigma, and blurStepSize. - *

+ * The uniforms have the following properties: *
    *
  • intensity is a scalar value used to lighten or darken the shadows exponentially. Higher values make the shadows darker. The default value is 3.0.
  • *
  • bias is a scalar value representing an angle in radians. If the dot product between the normal of the sample and the vector to the camera is less than this value, * sampling stops in the current direction. This is used to remove shadows from near planar edges. The default value is 0.1.
  • *
  • lengthCap is a scalar value representing a length in meters. If the distance from the current sample to first sample is greater than this value, * sampling stops in the current direction. The default value is 0.26.
  • - *
  • stepSize is a scalar value indicating the distance to the next texel sample in the current direction. The default value is 1.95.
  • - *
  • frustumLength is a scalar value in meters. If the current fragment has a distance from the camera greater than this value, ambient occlusion is not computed for the fragment. - * The default value is 1000.0.
  • + *
  • directionCount is the number of directions along which the ray marching will search for occluders. The default value is 8.
  • + *
  • stepCount is the number of steps the ray marching will take along each direction. The default value is 32.
  • *
  • randomTexture is a texture where the red channel is a random value in [0.0, 1.0]. The default value is undefined. This texture needs to be set.
  • *
  • ambientOcclusionOnly is a boolean value. When true, only the shadows generated are written to the output. When false, the input texture is modulated * with the ambient occlusion. This is a useful debug option for seeing the effects of changing the uniform values. The default value is false.
  • *
- *

- * delta, sigma, and blurStepSize are the same properties as {@link PostProcessStageLibrary#createBlurStage}. - * The blur is applied to the shadows generated from the image to make them smoother. - *

* @return {PostProcessStageComposite} A post-process stage that applies an ambient occlusion effect. * * @private @@ -509,24 +501,18 @@ PostProcessStageLibrary.createAmbientOcclusionStage = function () { intensity: 3.0, bias: 0.1, lengthCap: 0.26, - stepSize: 1.95, - frustumLength: 1000.0, + directionCount: 8, + stepCount: 32, randomTexture: undefined, }, }); - const blur = createBlur("czm_ambient_occlusion_blur"); - blur.uniforms.stepSize = 0.86; - const generateAndBlur = new PostProcessStageComposite({ - name: "czm_ambient_occlusion_generate_blur", - stages: [generate, blur], - }); const ambientOcclusionModulate = new PostProcessStage({ name: "czm_ambient_occlusion_composite", fragmentShader: AmbientOcclusionModulate, uniforms: { ambientOcclusionOnly: false, - ambientOcclusionTexture: generateAndBlur.name, + ambientOcclusionTexture: generate.name, }, }); @@ -556,20 +542,20 @@ PostProcessStageLibrary.createAmbientOcclusionStage = function () { generate.uniforms.lengthCap = value; }, }, - stepSize: { + directionCount: { get: function () { - return generate.uniforms.stepSize; + return generate.uniforms.directionCount; }, set: function (value) { - generate.uniforms.stepSize = value; + generate.uniforms.directionCount = value; }, }, - frustumLength: { + stepCount: { get: function () { - return generate.uniforms.frustumLength; + return generate.uniforms.stepCount; }, set: function (value) { - generate.uniforms.frustumLength = value; + generate.uniforms.stepCount = value; }, }, randomTexture: { @@ -580,30 +566,6 @@ PostProcessStageLibrary.createAmbientOcclusionStage = function () { generate.uniforms.randomTexture = value; }, }, - delta: { - get: function () { - return blur.uniforms.delta; - }, - set: function (value) { - blur.uniforms.delta = value; - }, - }, - sigma: { - get: function () { - return blur.uniforms.sigma; - }, - set: function (value) { - blur.uniforms.sigma = value; - }, - }, - blurStepSize: { - get: function () { - return blur.uniforms.stepSize; - }, - set: function (value) { - blur.uniforms.stepSize = value; - }, - }, ambientOcclusionOnly: { get: function () { return ambientOcclusionModulate.uniforms.ambientOcclusionOnly; @@ -616,7 +578,7 @@ PostProcessStageLibrary.createAmbientOcclusionStage = function () { return new PostProcessStageComposite({ name: "czm_ambient_occlusion", - stages: [generateAndBlur, ambientOcclusionModulate], + stages: [generate, ambientOcclusionModulate], inputPreviousStageTexture: false, uniforms: uniforms, }); diff --git a/packages/engine/Source/Scene/PropertyAttributeProperty.js b/packages/engine/Source/Scene/PropertyAttributeProperty.js index 607fb8611470..70c04cfd1ab4 100644 --- a/packages/engine/Source/Scene/PropertyAttributeProperty.js +++ b/packages/engine/Source/Scene/PropertyAttributeProperty.js @@ -80,7 +80,7 @@ Object.defineProperties(PropertyAttributeProperty.prototype, { * True if offset/scale should be applied. If both offset/scale were * undefined, they default to identity so this property is set false * - * @memberof MetadataClassProperty.prototype + * @memberof PropertyAttributeProperty.prototype * @type {boolean} * @readonly * @private @@ -94,7 +94,13 @@ Object.defineProperties(PropertyAttributeProperty.prototype, { /** * The offset to be added to property values as part of the value transform. * - * @memberof MetadataClassProperty.prototype + * This is always defined, even when `hasValueTransform` is `false`. If + * the property JSON itself did not define it, then it will inherit the + * value from the `MetadataClassProperty`. There, it also is always + * defined, and initialized to the default value if it was not contained + * in the class property JSON. + * + * @memberof PropertyAttributeProperty.prototype * @type {number|Cartesian2|Cartesian3|Cartesian4|Matrix2|Matrix3|Matrix4} * @readonly * @private @@ -108,7 +114,13 @@ Object.defineProperties(PropertyAttributeProperty.prototype, { /** * The scale to be multiplied to property values as part of the value transform. * - * @memberof MetadataClassProperty.prototype + * This is always defined, even when `hasValueTransform` is `false`. If + * the property JSON itself did not define it, then it will inherit the + * value from the `MetadataClassProperty`. There, it also is always + * defined, and initialized to the default value if it was not contained + * in the class property JSON. + * + * @memberof PropertyAttributeProperty.prototype * @type {number|Cartesian2|Cartesian3|Cartesian4|Matrix2|Matrix3|Matrix4} * @readonly * @private diff --git a/packages/engine/Source/Scene/PropertyTextureProperty.js b/packages/engine/Source/Scene/PropertyTextureProperty.js index 765c2507313e..cbb7508cc11e 100644 --- a/packages/engine/Source/Scene/PropertyTextureProperty.js +++ b/packages/engine/Source/Scene/PropertyTextureProperty.js @@ -111,6 +111,12 @@ Object.defineProperties(PropertyTextureProperty.prototype, { /** * The offset to be added to property values as part of the value transform. * + * This is always defined, even when `hasValueTransform` is `false`. If + * the property JSON itself did not define it, then it will inherit the + * value from the `MetadataClassProperty`. There, it also is always + * defined, and initialized to the default value if it was not contained + * in the class property JSON. + * * @memberof PropertyTextureProperty.prototype * @type {number|Cartesian2|Cartesian3|Cartesian4|Matrix2|Matrix3|Matrix4} * @readonly @@ -125,6 +131,12 @@ Object.defineProperties(PropertyTextureProperty.prototype, { /** * The scale to be multiplied to property values as part of the value transform. * + * This is always defined, even when `hasValueTransform` is `false`. If + * the property JSON itself did not define it, then it will inherit the + * value from the `MetadataClassProperty`. There, it also is always + * defined, and initialized to the default value if it was not contained + * in the class property JSON. + * * @memberof PropertyTextureProperty.prototype * @type {number|Cartesian2|Cartesian3|Cartesian4|Matrix2|Matrix3|Matrix4} * @readonly diff --git a/packages/engine/Source/Scene/Scene.js b/packages/engine/Source/Scene/Scene.js index e751dda94087..e438fdf87e32 100644 --- a/packages/engine/Source/Scene/Scene.js +++ b/packages/engine/Source/Scene/Scene.js @@ -79,6 +79,7 @@ import VoxelCell from "./VoxelCell.js"; import VoxelPrimitive from "./VoxelPrimitive.js"; import getMetadataClassProperty from "./getMetadataClassProperty.js"; import PickedMetadataInfo from "./PickedMetadataInfo.js"; +import getMetadataProperty from "./getMetadataProperty.js"; const requestRenderAfterFrame = function (scene) { return function () { @@ -4402,7 +4403,8 @@ Scene.prototype.pickVoxel = function (windowPosition, width, height) { * values from * @param {string} propertyName The name of the metadata property to pick * values from - * @returns The metadata value + * @returns {MetadataValue|undefined} The metadata value, or `undefined` when + * no matching metadata was found at the given position * * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy. */ @@ -4426,7 +4428,11 @@ Scene.prototype.pickMetadata = function ( // Check if the picked object is a model that has structural // metadata, with a schema that contains the specified // property. - const schema = pickedObject.detail?.model?.structuralMetadata?.schema; + const structuralMetadata = pickedObject.detail?.model?.structuralMetadata; + if (!defined(structuralMetadata)) { + return undefined; + } + const schema = structuralMetadata.schema; const classProperty = getMetadataClassProperty( schema, schemaId, @@ -4436,12 +4442,21 @@ Scene.prototype.pickMetadata = function ( if (!defined(classProperty)) { return undefined; } + const metadataProperty = getMetadataProperty( + structuralMetadata, + className, + propertyName, + ); + if (!defined(metadataProperty)) { + return undefined; + } const pickedMetadataInfo = new PickedMetadataInfo( schemaId, className, propertyName, classProperty, + metadataProperty, ); const pickedMetadataValues = this._picking.pickMetadata( diff --git a/packages/engine/Source/Scene/SkyBox.js b/packages/engine/Source/Scene/SkyBox.js index aa175b9d405b..39ca3c8b942e 100644 --- a/packages/engine/Source/Scene/SkyBox.js +++ b/packages/engine/Source/Scene/SkyBox.js @@ -81,6 +81,8 @@ function SkyBox(options) { this._attributeLocations = undefined; this._useHdr = undefined; + this._hasError = false; + this._error = undefined; } /** @@ -111,6 +113,15 @@ SkyBox.prototype.update = function (frameState, useHdr) { return undefined; } + // Throw any errors that had previously occurred asynchronously so they aren't + // ignored when running. See https://github.com/CesiumGS/cesium/pull/12307 + if (this._hasError) { + const error = this._error; + this._hasError = false; + this._error = undefined; + throw error; + } + if (this._sources !== this.sources) { this._sources = this.sources; const sources = this.sources; @@ -141,10 +152,18 @@ SkyBox.prototype.update = function (frameState, useHdr) { if (typeof sources.positiveX === "string") { // Given urls for cube-map images. Load them. - loadCubeMap(context, this._sources).then(function (cubeMap) { - that._cubeMap = that._cubeMap && that._cubeMap.destroy(); - that._cubeMap = cubeMap; - }); + loadCubeMap(context, this._sources) + .then(function (cubeMap) { + that._cubeMap = that._cubeMap && that._cubeMap.destroy(); + that._cubeMap = cubeMap; + }) + .catch((error) => { + // Defer throwing the error until the next call to update to prevent + // test from failing in `afterAll` if this is rejected after the test + // using the Skybox ends. See https://github.com/CesiumGS/cesium/pull/12307 + this._hasError = true; + this._error = error; + }); } else { this._cubeMap = this._cubeMap && this._cubeMap.destroy(); this._cubeMap = new CubeMap({ diff --git a/packages/engine/Source/Scene/UrlTemplateImageryProvider.js b/packages/engine/Source/Scene/UrlTemplateImageryProvider.js index 48dcab645f46..e11c00dfa138 100644 --- a/packages/engine/Source/Scene/UrlTemplateImageryProvider.js +++ b/packages/engine/Source/Scene/UrlTemplateImageryProvider.js @@ -159,13 +159,13 @@ const pickFeaturesTags = combine(tags, { * }); * // Access a Web Map Service (WMS) server. * const wms = new Cesium.UrlTemplateImageryProvider({ - * url : 'https://programs.communications.gov.au/geoserver/ows?tiled=true&' + - * 'transparent=true&format=image%2Fpng&exceptions=application%2Fvnd.ogc.se_xml&' + - * 'styles=&service=WMS&version=1.1.1&request=GetMap&' + - * 'layers=public%3AMyBroadband_Availability&srs=EPSG%3A3857&' + + * url : 'https://services.ga.gov.au/gis/services/NM_Hydrology_and_Marine_Points/MapServer/WMSServer?' + + * 'tiled=true&transparent=true&format=image%2Fpng&exceptions=application%2Fvnd.ogc.se_xml&' + + * 'styles=&service=WMS&version=1.3.0&request=GetMap&' + + * 'layers=Bores&crs=EPSG%3A3857&' + * 'bbox={westProjected}%2C{southProjected}%2C{eastProjected}%2C{northProjected}&' + * 'width=256&height=256', - * rectangle : Cesium.Rectangle.fromDegrees(96.799393, -43.598214999057824, 153.63925700000001, -9.2159219997013) + * rectangle : Cesium.Rectangle.fromDegrees(95.0, -55.0, 170.0, -1.0) // From GetCapabilities EX_GeographicBoundingBox * }); * // Using custom tags in your template url. * const custom = new Cesium.UrlTemplateImageryProvider({ diff --git a/packages/engine/Source/Scene/createGooglePhotorealistic3DTileset.js b/packages/engine/Source/Scene/createGooglePhotorealistic3DTileset.js index f762d748dc36..9c7bad99e30d 100644 --- a/packages/engine/Source/Scene/createGooglePhotorealistic3DTileset.js +++ b/packages/engine/Source/Scene/createGooglePhotorealistic3DTileset.js @@ -4,23 +4,37 @@ import defined from "../Core/defined.js"; import IonResource from "../Core/IonResource.js"; import GoogleMaps from "../Core/GoogleMaps.js"; import Resource from "../Core/Resource.js"; +import oneTimeWarning from "../Core/oneTimeWarning.js"; +import deprecationWarning from "../Core/deprecationWarning.js"; /** - * Creates a {@link Cesium3DTileset} instance for the Google Photorealistic 3D Tiles tileset. + * Creates a {@link Cesium3DTileset} instance for the Google Photorealistic 3D + * Tiles tileset. + * + * Google Photorealistic 3D Tiles can only be used with the Google geocoder. To + * confirm that you are aware of this restriction pass + * `usingOnlyWithGoogleGeocoder: true` to the apiOptions. Otherwise a one time + * warning will be displayed when this function is called. * * @function * - * @param {string} [key=GoogleMaps.defaultApiKey] Your API key to access Google Photorealistic 3D Tiles. See {@link https://developers.google.com/maps/documentation/javascript/get-api-key} for instructions on how to create your own key. - * @param {Cesium3DTileset.ConstructorOptions} [options] An object describing initialization options. + * @param {object} [apiOptions] + * @param {string} [apiOptions.key=GoogleMaps.defaultApiKey] Your API key to access Google Photorealistic 3D Tiles. See {@link https://developers.google.com/maps/documentation/javascript/get-api-key} for instructions on how to create your own key. + * @param {true} [apiOptions.onlyUsingWithGoogleGeocoder] Confirmation that this tileset will only be used with the Google geocoder. + * @param {Cesium3DTileset.ConstructorOptions} [tilesetOptions] An object describing initialization options. * @returns {Promise} * * @see GoogleMaps * * @example - * const viewer = new Cesium.Viewer("cesiumContainer"); + * const viewer = new Cesium.Viewer("cesiumContainer", { + * geocoder: Cesium.IonGeocodeProviderType.GOOGLE + * }); * * try { - * const tileset = await Cesium.createGooglePhotorealistic3DTileset(); + * const tileset = await Cesium.createGooglePhotorealistic3DTileset({ + * onlyUsingWithGoogleGeocoder: true, + * }); * viewer.scene.primitives.add(tileset)); * } catch (error) { * console.log(`Error creating tileset: ${error}`); @@ -30,27 +44,52 @@ import Resource from "../Core/Resource.js"; * // Use your own Google Maps API key * Cesium.GoogleMaps.defaultApiKey = "your-api-key"; * - * const viewer = new Cesium.Viewer("cesiumContainer"); + * const viewer = new Cesium.Viewer("cesiumContainer". { + * geocoder: Cesium.IonGeocodeProviderType.GOOGLE + * }); * * try { - * const tileset = await Cesium.createGooglePhotorealistic3DTileset(); + * const tileset = await Cesium.createGooglePhotorealistic3DTileset({ + * onlyUsingWithGoogleGeocoder: true, + * }); * viewer.scene.primitives.add(tileset)); * } catch (error) { * console.log(`Error creating tileset: ${error}`); * } */ -async function createGooglePhotorealistic3DTileset(key, options) { - options = defaultValue(options, {}); - options.cacheBytes = defaultValue(options.cacheBytes, 1536 * 1024 * 1024); - options.maximumCacheOverflowBytes = defaultValue( - options.maximumCacheOverflowBytes, +async function createGooglePhotorealistic3DTileset(apiOptions, tilesetOptions) { + tilesetOptions = defaultValue(tilesetOptions, {}); + tilesetOptions.cacheBytes = defaultValue( + tilesetOptions.cacheBytes, + 1536 * 1024 * 1024, + ); + tilesetOptions.maximumCacheOverflowBytes = defaultValue( + tilesetOptions.maximumCacheOverflowBytes, 1024 * 1024 * 1024, ); - options.enableCollision = defaultValue(options.enableCollision, true); + tilesetOptions.enableCollision = defaultValue( + tilesetOptions.enableCollision, + true, + ); - key = defaultValue(key, GoogleMaps.defaultApiKey); + apiOptions = defaultValue(apiOptions, defaultValue.EMPTY_OBJECT); + if (typeof apiOptions === "string") { + deprecationWarning( + "createGooglePhotorealistic3DTileset(key)", + "createGooglePhotorealistic3DTileset(key) has been deprecated. It is replaced by createGooglePhotorealistic3DTileset({key}). It will be removed in Cesium 1.126.", + ); + apiOptions = { key: apiOptions }; + } + if (!apiOptions.onlyUsingWithGoogleGeocoder) { + oneTimeWarning( + "google-tiles-with-google-geocoder", + "Only the Google geocoder can be used with Google Photorealistic 3D Tiles. Set the `geocode` property of Viewer constructor options. You can set additionalOptions.onlyUsingWithGoogleGeocoder to hide this warning once you have configured the geocoder.", + ); + } + + const key = defaultValue(apiOptions.key, GoogleMaps.defaultApiKey); if (!defined(key)) { - return requestCachedIonTileset(options); + return requestCachedIonTileset(tilesetOptions); } let credits; @@ -67,7 +106,7 @@ async function createGooglePhotorealistic3DTileset(key, options) { credits: credits, }); - return Cesium3DTileset.fromUrl(resource, options); + return Cesium3DTileset.fromUrl(resource, tilesetOptions); } const metadataCache = {}; diff --git a/packages/engine/Source/Scene/getMetadataProperty.js b/packages/engine/Source/Scene/getMetadataProperty.js new file mode 100644 index 000000000000..291f4f639851 --- /dev/null +++ b/packages/engine/Source/Scene/getMetadataProperty.js @@ -0,0 +1,48 @@ +import defined from "../Core/defined.js"; + +/** + * Return the `PropertyTextureProperty` from the given `StructuralMetadata` + * that matches the given description. + * + * If the given structural metadata is `undefined`, then `undefined` is returned. + * + * Otherwise, this method will check all the property textures in the given + * structural metadata. + * + * If it finds a property texture that has a class with an `_id` that matches + * the given name, and that contains a property for the given property name, then + * this property is returned. + * + * Otherwise, `undefined` is returned + * + * @param {StructuralMetadata} structuralMetadata The structural metadata + * @param {string} className The name of the metadata class + * @param {string} propertyName The name of the metadata property + * @returns {PropertyTextureProperty|undefined} + * @private + */ +function getMetadataProperty(structuralMetadata, className, propertyName) { + if (!defined(structuralMetadata)) { + return undefined; + } + const propertyTextures = structuralMetadata.propertyTextures; + for (const propertyTexture of propertyTextures) { + const metadataClass = propertyTexture.class; + if (metadataClass.id === className) { + const properties = propertyTexture.properties; + const property = properties[propertyName]; + if (defined(property)) { + return property; + } + } + } + // Note: This could check for property attributes in a similar + // way. But since picking arbitrary property attributes via the + // frame buffer is not supported yet, returning "undefined" here + // causes the picking to bail out early and safely when no + // property texture was found. + // See https://github.com/CesiumGS/cesium/issues/12225 + return undefined; +} + +export default getMetadataProperty; diff --git a/packages/engine/Source/Shaders/Builtin/Functions/reverseLogDepth.glsl b/packages/engine/Source/Shaders/Builtin/Functions/reverseLogDepth.glsl index d28f45494104..41bdfd7a0072 100644 --- a/packages/engine/Source/Shaders/Builtin/Functions/reverseLogDepth.glsl +++ b/packages/engine/Source/Shaders/Builtin/Functions/reverseLogDepth.glsl @@ -4,7 +4,7 @@ float czm_reverseLogDepth(float logZ) float near = czm_currentFrustum.x; float far = czm_currentFrustum.y; float log2Depth = logZ * czm_log2FarDepthFromNearPlusOne; - float depthFromNear = pow(2.0, log2Depth) - 1.0; + float depthFromNear = exp2(log2Depth) - 1.0; return far * (1.0 - near / (depthFromNear + near)) / (far - near); #endif return logZ; diff --git a/packages/engine/Source/Shaders/ConvolveSpecularMapFS.glsl b/packages/engine/Source/Shaders/ConvolveSpecularMapFS.glsl index 5eb290ecf3e1..5bb664548a11 100644 --- a/packages/engine/Source/Shaders/ConvolveSpecularMapFS.glsl +++ b/packages/engine/Source/Shaders/ConvolveSpecularMapFS.glsl @@ -62,7 +62,7 @@ void main() { float NdotL = max(dot(V, L), 0.0); if (NdotL > 0.0) { - color += vec4(texture(u_radianceTexture, L).rgb, 1.0) * NdotL; + color += vec4(czm_textureCube(u_radianceTexture, L).rgb, 1.0) * NdotL; weight += NdotL; } } diff --git a/packages/engine/Source/Shaders/Model/ModelFS.glsl b/packages/engine/Source/Shaders/Model/ModelFS.glsl index 0500c0b9f1ff..a6cb2827f60f 100644 --- a/packages/engine/Source/Shaders/Model/ModelFS.glsl +++ b/packages/engine/Source/Shaders/Model/ModelFS.glsl @@ -28,6 +28,13 @@ SelectedFeature selectedFeature; void main() { + #ifdef HAS_POINT_CLOUD_SHOW_STYLE + if (v_pointCloudShow == 0.0) + { + discard; + } + #endif + #ifdef HAS_MODEL_SPLITTER modelSplitterStage(); #endif diff --git a/packages/engine/Source/Shaders/Model/ModelVS.glsl b/packages/engine/Source/Shaders/Model/ModelVS.glsl index b95b329f59ff..2164da1024bc 100644 --- a/packages/engine/Source/Shaders/Model/ModelVS.glsl +++ b/packages/engine/Source/Shaders/Model/ModelVS.glsl @@ -145,5 +145,13 @@ void main() gl_PointSize *= show; #endif - gl_Position = show * positionClip; + // Important NOT to compute gl_Position = show * positionClip or we hit: + // https://github.com/CesiumGS/cesium/issues/11270 + // + // We will discard points with v_pointCloudShow == 0 in the fragment shader. + gl_Position = positionClip; + + #ifdef HAS_POINT_CLOUD_SHOW_STYLE + v_pointCloudShow = show; + #endif } diff --git a/packages/engine/Source/Shaders/PostProcessStages/AmbientOcclusionGenerate.glsl b/packages/engine/Source/Shaders/PostProcessStages/AmbientOcclusionGenerate.glsl index 42535230cbdc..149de02fa560 100644 --- a/packages/engine/Source/Shaders/PostProcessStages/AmbientOcclusionGenerate.glsl +++ b/packages/engine/Source/Shaders/PostProcessStages/AmbientOcclusionGenerate.glsl @@ -5,16 +5,21 @@ uniform sampler2D depthTexture; uniform float intensity; uniform float bias; uniform float lengthCap; -uniform float stepSize; -uniform float frustumLength; +uniform int stepCount; +uniform int directionCount; -vec3 pixelToEye(vec2 screenCoordinate) +vec4 pixelToEye(vec2 screenCoordinate) { vec2 uv = screenCoordinate / czm_viewport.zw; float depth = czm_readDepth(depthTexture, uv); vec2 xy = 2.0 * uv - vec2(1.0); vec4 posEC = czm_inverseProjection * vec4(xy, depth, 1.0); - return posEC.xyz / posEC.w; + posEC = posEC / posEC.w; + // Avoid numerical error at far plane + if (depth >= 1.0) { + posEC.z = czm_currentFrustum.y; + } + return posEC; } // Reconstruct surface normal in eye coordinates, avoiding edges @@ -22,10 +27,10 @@ vec3 getNormalXEdge(vec3 positionEC) { // Find the 3D surface positions at adjacent screen pixels vec2 centerCoord = gl_FragCoord.xy; - vec3 positionLeft = pixelToEye(centerCoord + vec2(-1.0, 0.0)); - vec3 positionRight = pixelToEye(centerCoord + vec2(1.0, 0.0)); - vec3 positionUp = pixelToEye(centerCoord + vec2(0.0, 1.0)); - vec3 positionDown = pixelToEye(centerCoord + vec2(0.0, -1.0)); + vec3 positionLeft = pixelToEye(centerCoord + vec2(-1.0, 0.0)).xyz; + vec3 positionRight = pixelToEye(centerCoord + vec2(1.0, 0.0)).xyz; + vec3 positionUp = pixelToEye(centerCoord + vec2(0.0, 1.0)).xyz; + vec3 positionDown = pixelToEye(centerCoord + vec2(0.0, -1.0)).xyz; // Compute potential tangent vectors vec3 dx0 = positionEC - positionLeft; @@ -40,22 +45,35 @@ vec3 getNormalXEdge(vec3 positionEC) return normalize(cross(dx, dy)); } +const float sqrtTwoPi = sqrt(czm_twoPi); + +float gaussian(float x, float standardDeviation) { + float argument = x / standardDeviation; + return exp(-0.5 * argument * argument) / (sqrtTwoPi * standardDeviation); +} + void main(void) { - vec3 positionEC = pixelToEye(gl_FragCoord.xy); + vec4 positionEC = pixelToEye(gl_FragCoord.xy); - if (positionEC.z > frustumLength) + // Exit if we are too close to the back of the frustum, where the depth value is invalid. + float maxValidDepth = czm_currentFrustum.y - lengthCap; + if (-positionEC.z > maxValidDepth) { out_FragColor = vec4(1.0); return; } - vec3 normalEC = getNormalXEdge(positionEC); + vec3 normalEC = getNormalXEdge(positionEC.xyz); + float gaussianVariance = lengthCap * sqrt(-positionEC.z); + // Choose a step length such that the marching stops just before 3 * variance. + float stepLength = 3.0 * gaussianVariance / (float(stepCount) + 1.0); + float metersPerPixel = czm_metersPerPixel(positionEC, 1.0); + // Minimum step is 1 pixel to avoid double sampling + float pixelsPerStep = max(stepLength / metersPerPixel, 1.0); + stepLength = pixelsPerStep * metersPerPixel; - float ao = 0.0; - - const int ANGLE_STEPS = 4; - float angleStepScale = 1.0 / float(ANGLE_STEPS); + float angleStepScale = 1.0 / float(directionCount); float angleStep = angleStepScale * czm_twoPi; float cosStep = cos(angleStep); float sinStep = sin(angleStep); @@ -67,48 +85,59 @@ void main(void) float randomVal = texture(randomTexture, randomTexCoord).x; vec2 sampleDirection = vec2(cos(angleStep * randomVal), sin(angleStep * randomVal)); + float ao = 0.0; // Loop over sampling directions - for (int i = 0; i < ANGLE_STEPS; i++) +#if __VERSION__ == 300 + for (int i = 0; i < directionCount; i++) + { +#else + for (int i = 0; i < 16; i++) { + if (i >= directionCount) { + break; + } +#endif sampleDirection = rotateStep * sampleDirection; float localAO = 0.0; - vec2 radialStep = stepSize * sampleDirection; + vec2 radialStep = pixelsPerStep * sampleDirection; - for (int j = 0; j < 6; j++) +#if __VERSION__ == 300 + for (int j = 0; j < stepCount; j++) + { +#else + for (int j = 0; j < 64; j++) { + if (j >= stepCount) { + break; + } +#endif // Step along sampling direction, away from output pixel - vec2 newCoords = floor(gl_FragCoord.xy + float(j + 1) * radialStep) + vec2(0.5); + vec2 samplePixel = floor(gl_FragCoord.xy + float(j + 1) * radialStep) + vec2(0.5); // Exit if we stepped off the screen - if (clamp(newCoords, vec2(0.0), czm_viewport.zw) != newCoords) - { + if (clamp(samplePixel, vec2(0.0), czm_viewport.zw) != samplePixel) { break; } - vec3 stepPositionEC = pixelToEye(newCoords); - vec3 stepVector = stepPositionEC - positionEC; - float stepLength = length(stepVector); - - if (stepLength > lengthCap) - { - break; - } + // Compute step vector from output point to sampled point + vec4 samplePositionEC = pixelToEye(samplePixel); + vec3 stepVector = samplePositionEC.xyz - positionEC.xyz; + // Estimate the angle from the surface normal. float dotVal = clamp(dot(normalEC, normalize(stepVector)), 0.0, 1.0); - if (dotVal < bias) - { - dotVal = 0.0; - } + dotVal = czm_branchFreeTernary(dotVal > bias, dotVal, 0.0); + dotVal = czm_branchFreeTernary(-samplePositionEC.z <= maxValidDepth, dotVal, 0.0); - float weight = stepLength / lengthCap; - weight = 1.0 - weight * weight; - localAO = max(localAO, dotVal * weight); + // Weight contribution based on the distance from the output point + float sampleDistance = length(stepVector); + float weight = gaussian(sampleDistance, gaussianVariance); + localAO += weight * dotVal; } ao += localAO; } - ao *= angleStepScale; + ao *= angleStepScale * stepLength; ao = 1.0 - clamp(ao, 0.0, 1.0); ao = pow(ao, intensity); out_FragColor = vec4(vec3(ao), 1.0); diff --git a/packages/engine/Specs/Core/GoogleGeocoderServicesSpec.js b/packages/engine/Specs/Core/GoogleGeocoderServicesSpec.js new file mode 100644 index 000000000000..5260dc265742 --- /dev/null +++ b/packages/engine/Specs/Core/GoogleGeocoderServicesSpec.js @@ -0,0 +1,84 @@ +import { + createGuid, + GeocoderService, + GoogleGeocoderService, + Resource, + Rectangle, +} from "../../index.js"; + +describe("Core/GoogleGeocoderService", function () { + it("conforms to GeocoderService interface", function () { + expect(GoogleGeocoderService).toConformToInterface(GeocoderService); + }); + + it("constructor throws without key", function () { + expect(function () { + return new GoogleGeocoderService({}); + }).toThrowDeveloperError(); + }); + + it("constructor sets key on _resource", function () { + const key = createGuid(); + const service = new GoogleGeocoderService({ key }); + expect(service._resource.toString()).toEqual( + `https://maps.googleapis.com/maps/api/geocode/json?key=${key}`, + ); + }); + + it("geocode returns results for status=OK", async function () { + const key = createGuid(); + const query = createGuid(); + const service = new GoogleGeocoderService({ key }); + + spyOn(Resource.prototype, "fetchJson").and.resolveTo({ + results: [ + { + formatted_address: + "1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA", + geometry: { + viewport: { + northeast: { + lat: 37.4237349802915, + lng: -122.083183169709, + }, + southwest: { + lat: 37.4210370197085, + lng: -122.085881130292, + }, + }, + }, + }, + ], + status: "OK", + }); + + const results = await service.geocode(query); + + expect(results).toEqual([ + { + displayName: "1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA", + destination: Rectangle.fromDegrees( + -122.085881130292, + 37.4210370197085, + -122.083183169709, + 37.4237349802915, + ), + attribution: { + html: `Google`, + collapsible: false, + }, + }, + ]); + }); + + it("returns empty array for status=ZERO_RESULTS", async function () { + const service = new GoogleGeocoderService({ key: "key" }); + + spyOn(Resource.prototype, "fetchJson").and.resolveTo({ + status: "ZERO_RESULTS", + }); + + const results = await service.geocode("test"); + expect(results).toEqual([]); + }); +}); diff --git a/packages/engine/Specs/Core/ITwinPlatformSpec.js b/packages/engine/Specs/Core/ITwinPlatformSpec.js new file mode 100644 index 000000000000..b43089c3f881 --- /dev/null +++ b/packages/engine/Specs/Core/ITwinPlatformSpec.js @@ -0,0 +1,414 @@ +import { + ITwinPlatform, + RequestErrorEvent, + Resource, + RuntimeError, +} from "../../index.js"; + +describe("ITwinPlatform", () => { + let previousAccessToken; + beforeEach(() => { + previousAccessToken = ITwinPlatform.defaultAccessToken; + ITwinPlatform.defaultAccessToken = "default-access-token"; + }); + + afterEach(() => { + ITwinPlatform.defaultAccessToken = previousAccessToken; + }); + + describe("getExports", () => { + let requestSpy; + beforeEach(() => { + requestSpy = spyOn(Resource.prototype, "fetchJson"); + }); + + it("rejects with no iModelId", async () => { + await expectAsync( + ITwinPlatform.getExports(undefined), + ).toBeRejectedWithDeveloperError( + "Expected iModelId to be typeof string, actual typeof was undefined", + ); + }); + + it("rejects with no default access token set", async () => { + ITwinPlatform.defaultAccessToken = undefined; + await expectAsync( + ITwinPlatform.getExports("imodel-id-1"), + ).toBeRejectedWithDeveloperError( + "Must set ITwinPlatform.defaultAccessToken first", + ); + }); + + it("rejects for API 401 errors", async () => { + requestSpy.and.rejectWith( + new RequestErrorEvent( + 401, + JSON.stringify({ + error: { message: "failed", details: [{ code: "InvalidToken" }] }, + }), + ), + ); + await expectAsync( + ITwinPlatform.getExports("imodel-id-1"), + ).toBeRejectedWithError(RuntimeError, /Unauthorized/); + }); + + it("rejects for API 403 errors", async () => { + requestSpy.and.rejectWith( + new RequestErrorEvent( + 403, + JSON.stringify({ + error: { message: "failed", code: "Forbidden" }, + }), + ), + ); + await expectAsync( + ITwinPlatform.getExports("imodel-id-1"), + ).toBeRejectedWithError(RuntimeError, /forbidden/); + }); + + it("rejects for API 422 errors", async () => { + requestSpy.and.rejectWith( + new RequestErrorEvent( + 422, + JSON.stringify({ + error: { message: "failed", code: "BadEntity" }, + }), + ), + ); + await expectAsync( + ITwinPlatform.getExports("imodel-id-1"), + ).toBeRejectedWithError(RuntimeError, /Unprocessable/); + }); + + it("rejects for API 429 errors", async () => { + requestSpy.and.rejectWith( + new RequestErrorEvent( + 429, + JSON.stringify({ + error: { message: "" }, + }), + ), + ); + await expectAsync( + ITwinPlatform.getExports("imodel-id-1"), + ).toBeRejectedWithError(RuntimeError, /Too many/); + }); + + it("uses the default access token for the API request", async () => { + let resource; + requestSpy.and.callFake(function () { + resource = this; + return { exports: [] }; + }); + await ITwinPlatform.getExports("imodel-id-1"); + expect(resource).toBeDefined(); + expect(resource.headers["Authorization"]).toEqual( + "Bearer default-access-token", + ); + }); + + it("uses the imodel id in the API request", async () => { + let resource; + requestSpy.and.callFake(function () { + resource = this; + return JSON.stringify({ exports: [] }); + }); + await ITwinPlatform.getExports("imodel-id-1"); + expect(resource).toBeDefined(); + expect(resource.url).toContain("imodel-id-1"); + }); + }); + + describe("getRealityDataMetadata", () => { + let requestSpy; + beforeEach(() => { + requestSpy = spyOn(Resource.prototype, "fetchJson"); + }); + + it("rejects with no iTwinId", async () => { + await expectAsync( + ITwinPlatform.getRealityDataMetadata(undefined), + ).toBeRejectedWithDeveloperError( + "Expected iTwinId to be typeof string, actual typeof was undefined", + ); + }); + + it("rejects with no realityDataId", async () => { + await expectAsync( + ITwinPlatform.getRealityDataMetadata("itwin-id-1", undefined), + ).toBeRejectedWithDeveloperError( + "Expected realityDataId to be typeof string, actual typeof was undefined", + ); + }); + + it("rejects with no default access token set", async () => { + ITwinPlatform.defaultAccessToken = undefined; + await expectAsync( + ITwinPlatform.getRealityDataMetadata("itwin-id-1", "reality-data-id-1"), + ).toBeRejectedWithDeveloperError( + "Must set ITwinPlatform.defaultAccessToken first", + ); + }); + + it("rejects for API 401 errors", async () => { + requestSpy.and.rejectWith( + new RequestErrorEvent( + 401, + JSON.stringify({ + error: { message: "failed", details: [{ code: "InvalidToken" }] }, + }), + ), + ); + await expectAsync( + ITwinPlatform.getRealityDataMetadata("itwin-id-1", "reality-data-id-1"), + ).toBeRejectedWithError(RuntimeError, /Unauthorized/); + }); + + it("rejects for API 403 errors", async () => { + requestSpy.and.rejectWith( + new RequestErrorEvent( + 403, + JSON.stringify({ + error: { message: "failed", code: "Forbidden" }, + }), + ), + ); + await expectAsync( + ITwinPlatform.getRealityDataMetadata("itwin-id-1", "reality-data-id-1"), + ).toBeRejectedWithError(RuntimeError, /forbidden/); + }); + + it("rejects for API 404 errors", async () => { + requestSpy.and.rejectWith( + new RequestErrorEvent( + 404, + JSON.stringify({ + error: { message: "" }, + }), + ), + ); + await expectAsync( + ITwinPlatform.getRealityDataMetadata("itwin-id-1", "reality-data-id-1"), + ).toBeRejectedWithError(RuntimeError, /not found/); + }); + + it("rejects for API 422 errors", async () => { + requestSpy.and.rejectWith( + new RequestErrorEvent( + 422, + JSON.stringify({ + error: { message: "failed", code: "BadEntity" }, + }), + ), + ); + await expectAsync( + ITwinPlatform.getRealityDataMetadata("itwin-id-1", "reality-data-id-1"), + ).toBeRejectedWithError(RuntimeError, /Unprocessable/); + }); + + it("rejects for API 429 errors", async () => { + requestSpy.and.rejectWith( + new RequestErrorEvent( + 429, + JSON.stringify({ + error: { message: "" }, + }), + ), + ); + await expectAsync( + ITwinPlatform.getRealityDataMetadata("itwin-id-1", "reality-data-id-1"), + ).toBeRejectedWithError(RuntimeError, /Too many/); + }); + + it("uses the default access token for the API request", async () => { + let resource; + requestSpy.and.callFake(function () { + resource = this; + return { realityData: {} }; + }); + await ITwinPlatform.getRealityDataMetadata( + "itwin-id-1", + "reality-data-id-1", + ); + expect(resource).toBeDefined(); + expect(resource.headers["Authorization"]).toEqual( + "Bearer default-access-token", + ); + }); + }); + + describe("getRealityDataURL", () => { + let requestSpy; + beforeEach(() => { + requestSpy = spyOn(Resource.prototype, "fetchJson"); + }); + + it("rejects with no iTwinId", async () => { + await expectAsync( + ITwinPlatform.getRealityDataURL(undefined), + ).toBeRejectedWithDeveloperError( + "Expected iTwinId to be typeof string, actual typeof was undefined", + ); + }); + + it("rejects with no realityDataId", async () => { + await expectAsync( + ITwinPlatform.getRealityDataURL("itwin-id-1", undefined), + ).toBeRejectedWithDeveloperError( + "Expected realityDataId to be typeof string, actual typeof was undefined", + ); + }); + it("rejects with no rootDocument", async () => { + await expectAsync( + ITwinPlatform.getRealityDataURL( + "itwin-id-1", + "reality-data-id-1", + undefined, + ), + ).toBeRejectedWithDeveloperError( + "Expected rootDocument to be typeof string, actual typeof was undefined", + ); + }); + + it("rejects with no default access token set", async () => { + ITwinPlatform.defaultAccessToken = undefined; + await expectAsync( + ITwinPlatform.getRealityDataURL( + "itwin-id-1", + "reality-data-id-1", + "root/document/path.json", + ), + ).toBeRejectedWithDeveloperError( + "Must set ITwinPlatform.defaultAccessToken first", + ); + }); + + it("rejects for API 401 errors", async () => { + requestSpy.and.rejectWith( + new RequestErrorEvent( + 401, + JSON.stringify({ + error: { message: "failed", details: [{ code: "InvalidToken" }] }, + }), + ), + ); + await expectAsync( + ITwinPlatform.getRealityDataURL( + "itwin-id-1", + "reality-data-id-1", + "root/document/path.json", + ), + ).toBeRejectedWithError(RuntimeError, /Unauthorized/); + }); + + it("rejects for API 403 errors", async () => { + requestSpy.and.rejectWith( + new RequestErrorEvent( + 403, + JSON.stringify({ + error: { message: "failed", code: "Forbidden" }, + }), + ), + ); + await expectAsync( + ITwinPlatform.getRealityDataURL( + "itwin-id-1", + "reality-data-id-1", + "root/document/path.json", + ), + ).toBeRejectedWithError(RuntimeError, /forbidden/); + }); + + it("rejects for API 404 errors", async () => { + requestSpy.and.rejectWith( + new RequestErrorEvent( + 404, + JSON.stringify({ + error: { message: "" }, + }), + ), + ); + await expectAsync( + ITwinPlatform.getRealityDataURL( + "itwin-id-1", + "reality-data-id-1", + "root/document/path.json", + ), + ).toBeRejectedWithError(RuntimeError, /not found/); + }); + + it("rejects for API 422 errors", async () => { + requestSpy.and.rejectWith( + new RequestErrorEvent( + 422, + JSON.stringify({ + error: { message: "failed", code: "BadEntity" }, + }), + ), + ); + await expectAsync( + ITwinPlatform.getRealityDataURL( + "itwin-id-1", + "reality-data-id-1", + "root/document/path.json", + ), + ).toBeRejectedWithError(RuntimeError, /Unprocessable/); + }); + + it("rejects for API 429 errors", async () => { + requestSpy.and.rejectWith( + new RequestErrorEvent( + 429, + JSON.stringify({ + error: { message: "" }, + }), + ), + ); + await expectAsync( + ITwinPlatform.getRealityDataURL( + "itwin-id-1", + "reality-data-id-1", + "root/document/path.json", + ), + ).toBeRejectedWithError(RuntimeError, /Too many/); + }); + + it("uses the default access token for the API request", async () => { + let resource; + requestSpy.and.callFake(function () { + resource = this; + return { + _links: { + containerUrl: { href: "https://example.com/base/path?auth=token" }, + }, + }; + }); + await ITwinPlatform.getRealityDataURL( + "itwin-id-1", + "reality-data-id-1", + "root/document/path.json", + ); + expect(resource).toBeDefined(); + expect(resource.headers["Authorization"]).toEqual( + "Bearer default-access-token", + ); + }); + + it("combines the rootDocument with the access url", async () => { + requestSpy.and.resolveTo({ + _links: { + containerUrl: { href: "https://example.com/base/path?auth=token" }, + }, + }); + const tilesetUrl = await ITwinPlatform.getRealityDataURL( + "itwin-id-1", + "reality-data-id-1", + "root/document/path.json", + ); + expect(tilesetUrl).toEqual( + "https://example.com/base/path/root/document/path.json?auth=token", + ); + }); + }); +}); diff --git a/packages/engine/Specs/Core/IonGeocoderServiceSpec.js b/packages/engine/Specs/Core/IonGeocoderServiceSpec.js index 17951c615c02..719a762daffc 100644 --- a/packages/engine/Specs/Core/IonGeocoderServiceSpec.js +++ b/packages/engine/Specs/Core/IonGeocoderServiceSpec.js @@ -1,7 +1,9 @@ import { + DeveloperError, GeocoderService, GeocodeType, Ion, + IonGeocodeProviderType, IonGeocoderService, } from "../../index.js"; @@ -26,20 +28,24 @@ describe("Core/IonGeocoderService", function () { expect(service._accessToken).toEqual(Ion.defaultAccessToken); expect(service._server.url).toEqual(Ion.defaultServer.url); + expect(service.geocodeProviderType).toEqual(IonGeocodeProviderType.DEFAULT); }); it("creates with specified parameters", function () { const accessToken = "123456"; const server = "http://not.ion.invalid/"; + const geocodeProviderType = IonGeocodeProviderType.GOOGLE; const service = new IonGeocoderService({ accessToken: accessToken, server: server, scene: scene, + geocodeProviderType, }); expect(service._accessToken).toEqual(accessToken); expect(service._server.url).toEqual(server); + expect(service.geocodeProviderType).toEqual(geocodeProviderType); }); it("calls inner geocoder and returns result", async function () { @@ -64,4 +70,47 @@ describe("Core/IonGeocoderService", function () { expect(service.credit).toBeUndefined(); }); + + it("setting geocodeProviderType updates _pelias.url for GOOGLE", function () { + const service = new IonGeocoderService({ + scene, + geocoder: IonGeocodeProviderType.DEFAULT, + }); + + service.geocodeProviderType = IonGeocodeProviderType.GOOGLE; + expect(service._pelias.url.queryParameters["geocoder"]).toEqual("google"); + }); + + it("setting geocodeProviderType updates _pelias.url for BING", function () { + const service = new IonGeocoderService({ + scene, + geocoder: IonGeocodeProviderType.DEFAULT, + }); + + service.geocodeProviderType = IonGeocodeProviderType.BING; + expect(service._pelias.url.queryParameters["geocoder"]).toEqual("bing"); + }); + + it("setting geocodeProviderType updates _pelias.url for DEFAULT", function () { + const service = new IonGeocoderService({ + scene, + geocoder: IonGeocodeProviderType.GOOGLE, + }); + + service.geocodeProviderType = IonGeocodeProviderType.DEFAULT; + const queryParameters = service._pelias.url.queryParameters; + expect(queryParameters.geocoder).toBeUndefined(); + // Make sure that it isn't 'geocoder: undefined' + expect(queryParameters.hasOwnProperty("geocoder")).toBeFalse(); + }); + + it("throws if setting invalid geocodeProviderType", function () { + expect( + () => new IonGeocoderService({ scene, geocodeProviderType: "junk" }), + ).toThrowError(DeveloperError, /Invalid geocodeProviderType/); + expect(() => { + const service = new IonGeocoderService({ scene }); + service.geocodeProviderType = "junk"; + }).toThrowError(DeveloperError, /Invalid geocodeProviderType/); + }); }); diff --git a/packages/engine/Specs/DataSources/EntitySpec.js b/packages/engine/Specs/DataSources/EntitySpec.js index 4edfdbffc4da..33ce89a6d98e 100644 --- a/packages/engine/Specs/DataSources/EntitySpec.js +++ b/packages/engine/Specs/DataSources/EntitySpec.js @@ -4,6 +4,7 @@ import { Matrix3, Matrix4, Quaternion, + TrackingReferenceFrame, TimeInterval, TimeIntervalCollection, Transforms, @@ -54,11 +55,15 @@ describe("DataSources/Entity", function () { expect(entity.viewFrom).toBeUndefined(); expect(entity.wall).toBeUndefined(); expect(entity.entityCollection).toBeUndefined(); + expect(entity.trackingReferenceFrame).toBe( + TrackingReferenceFrame.AUTODETECT, + ); const options = { id: "someId", name: "bob", show: false, + trackingReferenceFrame: TrackingReferenceFrame.INERTIAL, availability: new TimeIntervalCollection(), parent: new Entity(), customProperty: {}, @@ -88,6 +93,7 @@ describe("DataSources/Entity", function () { expect(entity.id).toEqual(options.id); expect(entity.name).toEqual(options.name); expect(entity.show).toBe(options.show); + expect(entity.trackingReferenceFrame).toBe(options.trackingReferenceFrame); expect(entity.availability).toBe(options.availability); expect(entity.parent).toBe(options.parent); expect(entity.customProperty).toBe(options.customProperty); @@ -114,6 +120,7 @@ describe("DataSources/Entity", function () { expect(entity.wall).toBeInstanceOf(WallGraphics); expect(entity.entityCollection).toBeUndefined(); + expect(entity.trackingReferenceFrame).toBe(TrackingReferenceFrame.INERTIAL); }); it("isAvailable is always true if no availability defined.", function () { diff --git a/packages/engine/Specs/DataSources/EntityViewSpec.js b/packages/engine/Specs/DataSources/EntityViewSpec.js index 1406cf8207d3..61223cc1dd0b 100644 --- a/packages/engine/Specs/DataSources/EntityViewSpec.js +++ b/packages/engine/Specs/DataSources/EntityViewSpec.js @@ -6,6 +6,7 @@ import { ConstantPositionProperty, Entity, EntityView, + TrackingReferenceFrame, } from "../../index.js"; import createScene from "../../../../Specs/createScene.js"; @@ -74,6 +75,18 @@ describe( const view = new EntityView(entity, scene); view.update(JulianDate.now()); expect(view.scene.camera.position).toEqualEpsilon(sampleOffset, 1e-10); + + entity.trackingReferenceFrame = TrackingReferenceFrame.INERTIAL; + view.update(JulianDate.now()); + expect(view.scene.camera.position).toEqualEpsilon(sampleOffset, 1e-10); + + entity.trackingReferenceFrame = TrackingReferenceFrame.VELOCITY; + view.update(JulianDate.now()); + expect(view.scene.camera.position).toEqualEpsilon(sampleOffset, 1e-10); + + entity.trackingReferenceFrame = TrackingReferenceFrame.ENU; + view.update(JulianDate.now()); + expect(view.scene.camera.position).toEqualEpsilon(sampleOffset, 1e-10); }); it("uses entity bounding sphere", function () { @@ -92,6 +105,27 @@ describe( new BoundingSphere(new Cartesian3(3, 4, 5), 6), ); expect(view.scene.camera.position).toEqualEpsilon(sampleOffset, 1e-10); + + entity.trackingReferenceFrame = TrackingReferenceFrame.INERTIAL; + view.update( + JulianDate.now(), + new BoundingSphere(new Cartesian3(3, 4, 5), 6), + ); + expect(view.scene.camera.position).toEqualEpsilon(sampleOffset, 1e-10); + + entity.trackingReferenceFrame = TrackingReferenceFrame.VELOCITY; + view.update( + JulianDate.now(), + new BoundingSphere(new Cartesian3(3, 4, 5), 6), + ); + expect(view.scene.camera.position).toEqualEpsilon(sampleOffset, 1e-10); + + entity.trackingReferenceFrame = TrackingReferenceFrame.ENU; + view.update( + JulianDate.now(), + new BoundingSphere(new Cartesian3(3, 4, 5), 6), + ); + expect(view.scene.camera.position).toEqualEpsilon(sampleOffset, 1e-10); }); it("uses entity viewFrom if available and boundingsphere is supplied", function () { @@ -109,6 +143,18 @@ describe( ); view.update(JulianDate.now()); expect(view.scene.camera.position).toEqualEpsilon(sampleOffset, 1e-10); + + entity.trackingReferenceFrame = TrackingReferenceFrame.INERTIAL; + view.update(JulianDate.now()); + expect(view.scene.camera.position).toEqualEpsilon(sampleOffset, 1e-10); + + entity.trackingReferenceFrame = TrackingReferenceFrame.VELOCITY; + view.update(JulianDate.now()); + expect(view.scene.camera.position).toEqualEpsilon(sampleOffset, 1e-10); + + entity.trackingReferenceFrame = TrackingReferenceFrame.ENU; + view.update(JulianDate.now()); + expect(view.scene.camera.position).toEqualEpsilon(sampleOffset, 1e-10); }); it("update throws without time parameter", function () { diff --git a/packages/engine/Specs/DataSources/SampledPropertySpec.js b/packages/engine/Specs/DataSources/SampledPropertySpec.js index 3caa5d99fe6c..e6ee6edc9335 100644 --- a/packages/engine/Specs/DataSources/SampledPropertySpec.js +++ b/packages/engine/Specs/DataSources/SampledPropertySpec.js @@ -110,6 +110,28 @@ describe("DataSources/SampledProperty", function () { expect(property.getValue(new JulianDate(0.5, 0))).toEqual(7.5); }); + it("getSample works", function () { + const times = [ + new JulianDate(0, 0), + new JulianDate(1, 0), + new JulianDate(2, 0), + ]; + const values = [7, 8, 9]; + + const property = new SampledProperty(Number); + property.addSamples(times, values); + + expect(property.getSample(0)).toEqual(times[0]); + expect(property.getSample(1)).toEqual(times[1]); + expect(property.getSample(2)).toEqual(times[2]); + expect(property.getSample(3)).toBe(undefined); + + expect(property.getSample(-1)).toBe(times[2]); + expect(property.getSample(-2)).toBe(times[1]); + expect(property.getSample(-3)).toBe(times[0]); + expect(property.getSample(-4)).toBe(undefined); + }); + it("can remove a sample at a date", function () { const times = [ new JulianDate(0, 0), diff --git a/packages/engine/Specs/Renderer/TextureSpec.js b/packages/engine/Specs/Renderer/TextureSpec.js index 609a6a95da47..b9cd1b386199 100644 --- a/packages/engine/Specs/Renderer/TextureSpec.js +++ b/packages/engine/Specs/Renderer/TextureSpec.js @@ -16,1075 +16,1203 @@ import { } from "../../index.js"; import createContext from "../../../../Specs/createContext.js"; +import createWebglVersionHelper from "../createWebglVersionHelper.js"; describe( "Renderer/Texture", function () { - let context; - let greenImage; - let blueImage; - let blueAlphaImage; - let blueOverRedImage; - let blueOverRedFlippedImage; - let red16x16Image; - - let greenKTX2Image; - let greenBasisKTX2Image; - - const fs = - "uniform sampler2D u_texture;" + - "void main() { out_FragColor = texture(u_texture, vec2(0.0)); }"; - const fsLuminanceAlpha = - "uniform sampler2D u_texture;" + - "void main() { out_FragColor = vec4(texture(u_texture, vec2(0.0)).ra, 0.0, 1.0); }"; - let texture; - const uniformMap = { - u_texture: function () { - return texture; - }, - }; - - beforeAll(function () { - context = createContext(); - const promises = []; - promises.push( - Resource.fetchImage("./Data/Images/Green.png").then(function (image) { - greenImage = image; - }), - ); - promises.push( - Resource.fetchImage("./Data/Images/Blue.png").then(function (image) { - blueImage = image; - }), - ); - promises.push( - Resource.fetchImage("./Data/Images/BlueAlpha.png").then( - function (image) { - blueAlphaImage = image; - }, - ), - ); - promises.push( - Resource.fetchImage("./Data/Images/BlueOverRed.png").then( - function (image) { - blueOverRedImage = image; - }, - ), - ); - // Load this image as an ImageBitmap - promises.push( - Resource.fetchImage({ - url: "./Data/Images/BlueOverRed.png", - preferImageBitmap: true, - }).then(function (image) { - blueOverRedFlippedImage = image; - }), - ); - promises.push( - Resource.fetchImage("./Data/Images/Red16x16.png").then( - function (image) { - red16x16Image = image; - }, - ), - ); - - const resource = Resource.createIfNeeded("./Data/Images/Green4x4.ktx2"); - const loadPromise = resource.fetchArrayBuffer(); - promises.push( - loadPromise.then(function (buffer) { - const promise = KTX2Transcoder.transcode(buffer, {}); - return promise.then(function (result) { - greenKTX2Image = result; - }); - }), - ); + createWebglVersionHelper(createTextureSpecs); + + function createTextureSpecs(contextOptions) { + let context; + let greenImage; + let blueImage; + let blueAlphaImage; + let blueOverRedImage; + let blueOverRedFlippedImage; + let red16x16Image; + + let greenKTX2Image; + let greenBasisKTX2Image; + + const fs = + "uniform sampler2D u_texture;" + + "void main() { out_FragColor = texture(u_texture, vec2(0.0)); }"; + const fsLuminanceAlpha = + "uniform sampler2D u_texture;" + + "void main() { out_FragColor = vec4(texture(u_texture, vec2(0.0)).ra, 0.0, 1.0); }"; + let texture; + const uniformMap = { + u_texture: function () { + return texture; + }, + }; - if (context.supportsBasis) { + beforeAll(function () { + context = createContext(contextOptions); + const promises = []; promises.push( - loadKTX2("./Data/Images/Green4x4_ETC1S.ktx2").then(function (image) { - greenBasisKTX2Image = image; + Resource.fetchImage("./Data/Images/Green.png").then(function (image) { + greenImage = image; }), ); - } - - return Promise.all(promises); - }); - - afterAll(function () { - context.destroyForSpecs(); - }); - - let blueImageHeight, blueImageWidth; - beforeEach(function () { - blueImageHeight = blueImage.height; - blueImageWidth = blueImage.width; - }); - - afterEach(function () { - blueImage.height = blueImageHeight; - blueImage.width = blueImageWidth; - texture = texture && texture.destroy(); - }); - - it("has expected default values for pixel format and datatype", function () { - texture = new Texture({ - context: context, - source: blueImage, - }); - - expect(texture.id).toBeDefined(); - expect(texture.pixelFormat).toEqual(PixelFormat.RGBA); - expect(texture.pixelDatatype).toEqual(PixelDatatype.UNSIGNED_BYTE); - }); - - it("can create a texture from the framebuffer", function () { - const command = new ClearCommand({ - color: Color.RED, - }); - command.execute(context); - - texture = Texture.fromFramebuffer({ - context: context, - }); - - const expectedWidth = context.canvas.clientWidth; - const expectedHeight = context.canvas.clientHeight; - expect(texture.width).toEqual(expectedWidth); - expect(texture.height).toEqual(expectedHeight); - expect(texture.sizeInBytes).toEqual( - expectedWidth * - expectedHeight * - PixelFormat.componentsLength(texture.pixelFormat), - ); - - command.color = Color.WHITE; - command.execute(context); - expect(context).toReadPixels([255, 255, 255, 255]); - - expect({ - context: context, - fragmentShader: fs, - uniformMap: uniformMap, - }).contextToRender([255, 0, 0, 255]); - }); - - it("can copy from the framebuffer", function () { - texture = new Texture({ - context: context, - source: blueImage, - pixelFormat: PixelFormat.RGB, - }); - - // Render blue - expect({ - context: context, - fragmentShader: fs, - uniformMap: uniformMap, - }).contextToRender([0, 0, 255, 255]); - - // Clear to red - const command = new ClearCommand({ - color: Color.RED, - }); - command.execute(context); - expect(context).toReadPixels(Color.RED.toBytes()); - - texture.copyFromFramebuffer(); - - const expectedWidth = context.canvas.clientWidth; - const expectedHeight = context.canvas.clientHeight; - expect(texture.width).toEqual(expectedWidth); - expect(texture.height).toEqual(expectedHeight); - expect(texture.sizeInBytes).toEqual( - expectedWidth * - expectedHeight * - PixelFormat.componentsLength(texture.pixelFormat), - ); - - // Clear to white - command.color = Color.WHITE; - command.execute(context); - expect(context).toReadPixels(Color.WHITE.toBytes()); - - // Render red - expect({ - context: context, - fragmentShader: fs, - uniformMap: uniformMap, - }).contextToRender([255, 0, 0, 255]); - }); - - it("draws the expected texture color", function () { - texture = new Texture({ - context: context, - source: blueImage, - pixelFormat: PixelFormat.RGBA, - }); - - expect({ - context: context, - fragmentShader: fs, - uniformMap: uniformMap, - }).contextToRender([0, 0, 255, 255]); - }); - - it("cannot flip texture when using ImageBitmap", function () { - const topColor = new Color(0.0, 0.0, 1.0, 1.0); - let bottomColor = new Color(1.0, 0.0, 0.0, 1.0); - - return Resource.supportsImageBitmapOptions().then( - function (supportsImageBitmapOptions) { - if (supportsImageBitmapOptions) { - // When imageBitmapOptions is supported, flipY on texture upload is ignored. - bottomColor = topColor; - } - - texture = new Texture({ - context: context, - source: blueOverRedFlippedImage, - pixelFormat: PixelFormat.RGBA, - flipY: false, - }); + promises.push( + Resource.fetchImage("./Data/Images/Blue.png").then(function (image) { + blueImage = image; + }), + ); + promises.push( + Resource.fetchImage("./Data/Images/BlueAlpha.png").then( + function (image) { + blueAlphaImage = image; + }, + ), + ); + promises.push( + Resource.fetchImage("./Data/Images/BlueOverRed.png").then( + function (image) { + blueOverRedImage = image; + }, + ), + ); + // Load this image as an ImageBitmap + promises.push( + Resource.fetchImage({ + url: "./Data/Images/BlueOverRed.png", + preferImageBitmap: true, + }).then(function (image) { + blueOverRedFlippedImage = image; + }), + ); + promises.push( + Resource.fetchImage("./Data/Images/Red16x16.png").then( + function (image) { + red16x16Image = image; + }, + ), + ); - expect({ - context: context, - fragmentShader: fs, - uniformMap: uniformMap, - }).contextToRender(topColor.toBytes()); + const resource = Resource.createIfNeeded("./Data/Images/Green4x4.ktx2"); + const loadPromise = resource.fetchArrayBuffer(); + promises.push( + loadPromise.then(function (buffer) { + const promise = KTX2Transcoder.transcode(buffer, {}); + return promise.then(function (result) { + greenKTX2Image = result; + }); + }), + ); - // Flip the texture. - texture = new Texture({ - context: context, - source: blueOverRedFlippedImage, - pixelFormat: PixelFormat.RGBA, - flipY: true, - }); + if (context.supportsBasis) { + promises.push( + loadKTX2("./Data/Images/Green4x4_ETC1S.ktx2").then( + function (image) { + greenBasisKTX2Image = image; + }, + ), + ); + } + + return Promise.all(promises); + }); - expect({ - context: context, - fragmentShader: fs, - uniformMap: uniformMap, - }).contextToRender(bottomColor.toBytes()); - }, - ); - }); + afterAll(function () { + context.destroyForSpecs(); + }); - it("draws the expected floating-point texture color", function () { - if (!context.floatingPointTexture) { - return; - } + let blueImageHeight, blueImageWidth; + beforeEach(function () { + blueImageHeight = blueImage.height; + blueImageWidth = blueImage.width; + }); - const color = new Color(0.2, 0.4, 0.6, 1.0); - const floats = new Float32Array([ - color.red, - color.green, - color.blue, - color.alpha, - ]); - - texture = new Texture({ - context: context, - pixelFormat: PixelFormat.RGBA, - pixelDatatype: PixelDatatype.FLOAT, - source: { - width: 1, - height: 1, - arrayBufferView: floats, - }, + afterEach(function () { + blueImage.height = blueImageHeight; + blueImage.width = blueImageWidth; + texture = texture && texture.destroy(); }); - expect(texture.sizeInBytes).toEqual(16); + it("has expected default values for pixel format and datatype", function () { + texture = new Texture({ + context: context, + source: blueImage, + }); - expect({ - context: context, - fragmentShader: fs, - uniformMap: uniformMap, - }).contextToRender(color.toBytes()); - }); + expect(texture.id).toBeDefined(); + expect(texture.pixelFormat).toEqual(PixelFormat.RGBA); + expect(texture.pixelDatatype).toEqual(PixelDatatype.UNSIGNED_BYTE); + }); - it("draws the expected floating-point texture color with linear filtering", function () { - if (!context.floatingPointTexture) { - return; - } + it("can create a texture from the framebuffer", function () { + const command = new ClearCommand({ + color: Color.RED, + }); + command.execute(context); - const color0 = new Color(0.2, 0.4, 0.6, 1.0); - const color1 = new Color(0.1, 0.3, 0.5, 1.0); - const floats = new Float32Array([ - color0.red, - color0.green, - color0.blue, - color0.alpha, - color1.red, - color1.green, - color1.blue, - color1.alpha, - ]); - - texture = new Texture({ - context: context, - pixelFormat: PixelFormat.RGBA, - pixelDatatype: PixelDatatype.FLOAT, - source: { - width: 2, - height: 1, - arrayBufferView: floats, - }, - sampler: new Sampler({ - wrapS: TextureWrap.CLAMP_TO_EDGE, - wrapT: TextureWrap.CLAMP_TO_EDGE, - minificationFilter: TextureMinificationFilter.LINEAR, - magnificationFilter: TextureMagnificationFilter.LINEAR, - }), - }); + texture = Texture.fromFramebuffer({ + context: context, + }); - expect(texture.sizeInBytes).toEqual(32); + const expectedWidth = context.canvas.clientWidth; + const expectedHeight = context.canvas.clientHeight; + expect(texture.width).toEqual(expectedWidth); + expect(texture.height).toEqual(expectedHeight); + expect(texture.sizeInBytes).toEqual( + expectedWidth * + expectedHeight * + PixelFormat.componentsLength(texture.pixelFormat), + ); - const fs = - "uniform sampler2D u_texture;" + - "void main() { out_FragColor = texture(u_texture, vec2(0.5, 0.0)); }"; + command.color = Color.WHITE; + command.execute(context); + expect(context).toReadPixels([255, 255, 255, 255]); - if (!context.textureFloatLinear) { expect({ context: context, fragmentShader: fs, uniformMap: uniformMap, - epsilon: 1, - }).contextToRender(color1.toBytes()); - } else { - Color.multiplyByScalar(color0, 1.0 - 0.5, color0); - Color.multiplyByScalar(color1, 0.5, color1); - Color.add(color0, color1, color1); + }).contextToRender([255, 0, 0, 255]); + }); + + it("can copy from the framebuffer", function () { + texture = new Texture({ + context: context, + source: blueImage, + pixelFormat: PixelFormat.RGB, + }); + + // Render blue expect({ context: context, fragmentShader: fs, uniformMap: uniformMap, - }).contextToRender(color1.toBytes()); - } - }); + }).contextToRender([0, 0, 255, 255]); - it("draws the expected half floating-point texture color", function () { - if (!context.halfFloatingPointTexture) { - return; - } + // Clear to red + const command = new ClearCommand({ + color: Color.RED, + }); + command.execute(context); + expect(context).toReadPixels(Color.RED.toBytes()); + + texture.copyFromFramebuffer(); + + const expectedWidth = context.canvas.clientWidth; + const expectedHeight = context.canvas.clientHeight; + expect(texture.width).toEqual(expectedWidth); + expect(texture.height).toEqual(expectedHeight); + expect(texture.sizeInBytes).toEqual( + expectedWidth * + expectedHeight * + PixelFormat.componentsLength(texture.pixelFormat), + ); - const color = new Color(0.2, 0.4, 0.6, 1.0); - const floats = new Uint16Array([12902, 13926, 14541, 15360]); + // Clear to white + command.color = Color.WHITE; + command.execute(context); + expect(context).toReadPixels(Color.WHITE.toBytes()); - texture = new Texture({ - context: context, - pixelFormat: PixelFormat.RGBA, - pixelDatatype: PixelDatatype.HALF_FLOAT, - source: { - width: 1, - height: 1, - arrayBufferView: floats, - }, - flipY: false, + // Render red + expect({ + context: context, + fragmentShader: fs, + uniformMap: uniformMap, + }).contextToRender([255, 0, 0, 255]); }); - expect(texture.sizeInBytes).toEqual(8); - - expect({ - context: context, - fragmentShader: fs, - uniformMap: uniformMap, - }).contextToRender(color.toBytes()); - }); + it("draws the expected texture color", function () { + texture = new Texture({ + context: context, + source: blueImage, + pixelFormat: PixelFormat.RGBA, + }); - it("draws the expected half floating-point texture color with linear filtering", function () { - if (!context.halfFloatingPointTexture) { - return; - } + expect({ + context: context, + fragmentShader: fs, + uniformMap: uniformMap, + }).contextToRender([0, 0, 255, 255]); + }); - const color0 = new Color(0.2, 0.4, 0.6, 1.0); - const color1 = new Color(0.1, 0.3, 0.5, 1.0); - const floats = new Uint16Array([ - 12902, 13926, 14541, 15360, 11878, 13517, 14336, 15360, - ]); - - texture = new Texture({ - context: context, - pixelFormat: PixelFormat.RGBA, - pixelDatatype: PixelDatatype.HALF_FLOAT, - source: { - width: 2, - height: 1, - arrayBufferView: floats, - }, - flipY: false, + it("cannot flip texture when using ImageBitmap", function () { + const topColor = new Color(0.0, 0.0, 1.0, 1.0); + let bottomColor = new Color(1.0, 0.0, 0.0, 1.0); + + return Resource.supportsImageBitmapOptions().then( + function (supportsImageBitmapOptions) { + if (supportsImageBitmapOptions) { + // When imageBitmapOptions is supported, flipY on texture upload is ignored. + bottomColor = topColor; + } + + texture = new Texture({ + context: context, + source: blueOverRedFlippedImage, + pixelFormat: PixelFormat.RGBA, + flipY: false, + }); + + expect({ + context: context, + fragmentShader: fs, + uniformMap: uniformMap, + }).contextToRender(topColor.toBytes()); + + // Flip the texture. + texture = new Texture({ + context: context, + source: blueOverRedFlippedImage, + pixelFormat: PixelFormat.RGBA, + flipY: true, + }); + + expect({ + context: context, + fragmentShader: fs, + uniformMap: uniformMap, + }).contextToRender(bottomColor.toBytes()); + }, + ); }); - expect(texture.sizeInBytes).toEqual(16); + it("draws the expected floating-point texture color", function () { + if (!context.floatingPointTexture) { + return; + } - const fs = - "uniform sampler2D u_texture;" + - "void main() { out_FragColor = texture(u_texture, vec2(0.5, 0.0)); }"; + const color = new Color(0.2, 0.4, 0.6, 1.0); + const floats = new Float32Array([ + color.red, + color.green, + color.blue, + color.alpha, + ]); - if (!context.textureHalfFloatLinear) { - expect({ + texture = new Texture({ context: context, - fragmentShader: fs, - uniformMap: uniformMap, - epsilon: 1, - }).contextToRender(color1.toBytes()); - } else { - Color.multiplyByScalar(color0, 1.0 - 0.5, color0); - Color.multiplyByScalar(color1, 0.5, color1); - Color.add(color0, color1, color1); + pixelFormat: PixelFormat.RGBA, + pixelDatatype: PixelDatatype.FLOAT, + source: { + width: 1, + height: 1, + arrayBufferView: floats, + }, + }); + + expect(texture.sizeInBytes).toEqual(16); + expect({ context: context, fragmentShader: fs, uniformMap: uniformMap, - }).contextToRender(color1.toBytes()); - } - }); + }).contextToRender(color.toBytes()); + }); - it("draws the expected Basis compressed texture color", function () { - if (!context.supportsBasis) { - return; - } + it("draws the expected floating-point texture color with linear filtering", function () { + if (!context.floatingPointTexture) { + return; + } + + const color0 = new Color(0.2, 0.4, 0.6, 1.0); + const color1 = new Color(0.1, 0.3, 0.5, 1.0); + const floats = new Float32Array([ + color0.red, + color0.green, + color0.blue, + color0.alpha, + color1.red, + color1.green, + color1.blue, + color1.alpha, + ]); - texture = new Texture({ - context: context, - pixelFormat: greenBasisKTX2Image.internalFormat, - source: { - width: greenBasisKTX2Image.width, - height: greenBasisKTX2Image.height, - arrayBufferView: greenBasisKTX2Image.bufferView, - }, - }); + texture = new Texture({ + context: context, + pixelFormat: PixelFormat.RGBA, + pixelDatatype: PixelDatatype.FLOAT, + source: { + width: 2, + height: 1, + arrayBufferView: floats, + }, + sampler: new Sampler({ + wrapS: TextureWrap.CLAMP_TO_EDGE, + wrapT: TextureWrap.CLAMP_TO_EDGE, + minificationFilter: TextureMinificationFilter.LINEAR, + magnificationFilter: TextureMagnificationFilter.LINEAR, + }), + }); - expect(texture.sizeInBytes).toBe(8); + expect(texture.sizeInBytes).toEqual(32); - expect({ - context: context, - fragmentShader: fs, - uniformMap: uniformMap, - }).contextToRenderAndCall(function (color) { - return expect(color).toEqualEpsilon([2, 255, 2, 255], 2); - }); - }); + const fs = + "uniform sampler2D u_texture;" + + "void main() { out_FragColor = texture(u_texture, vec2(0.5, 0.0)); }"; - it("draws the expected KTX2 uncompressed texture color", function () { - texture = new Texture({ - context: context, - pixelFormat: greenKTX2Image.internalFormat, - source: { - width: greenKTX2Image.width, - height: greenKTX2Image.height, - arrayBufferView: greenKTX2Image.bufferView, - }, + if (!context.textureFloatLinear) { + expect({ + context: context, + fragmentShader: fs, + uniformMap: uniformMap, + epsilon: 1, + }).contextToRender(color1.toBytes()); + } else { + Color.multiplyByScalar(color0, 1.0 - 0.5, color0); + Color.multiplyByScalar(color1, 0.5, color1); + Color.add(color0, color1, color1); + expect({ + context: context, + fragmentShader: fs, + uniformMap: uniformMap, + }).contextToRender(color1.toBytes()); + } }); - expect(texture.sizeInBytes).toBe(48); + it("draws the expected half floating-point texture color", function () { + if (!context.halfFloatingPointTexture) { + return; + } - expect({ - context: context, - fragmentShader: fs, - uniformMap: uniformMap, - }).contextToRenderAndCall(function (color) { - return expect(color).toEqualEpsilon([0, 255, 24, 255], 2); - }); - }); + const color = new Color(0.2, 0.4, 0.6, 1.0); + const floats = new Uint16Array([12902, 13926, 14541, 15360]); - it("renders with premultiplied alpha", function () { - const cxt = createContext({ - webgl: { - alpha: true, - }, - }); - const texture = new Texture({ - context: cxt, - source: blueAlphaImage, - pixelFormat: PixelFormat.RGBA, - preMultiplyAlpha: true, - }); - const uniformMap = { - u_texture: function () { - return texture; - }, - }; + texture = new Texture({ + context: context, + pixelFormat: PixelFormat.RGBA, + pixelDatatype: PixelDatatype.HALF_FLOAT, + source: { + width: 1, + height: 1, + arrayBufferView: floats, + }, + flipY: false, + }); - expect(texture.preMultiplyAlpha).toEqual(true); - expect({ - context: cxt, - fragmentShader: fs, - uniformMap: uniformMap, - epsilon: 1, - }).contextToRender([0, 0, 127, 127]); - - texture.destroy(); - cxt.destroyForSpecs(); - }); - - it("draws textured blue and red points", function () { - texture = new Texture({ - context: context, - source: blueOverRedImage, - pixelFormat: PixelFormat.RGBA, - }); - - let fragmentShaderSource = ""; - fragmentShaderSource += "uniform sampler2D u_texture;"; - fragmentShaderSource += "uniform mediump vec2 u_txCoords;"; - fragmentShaderSource += - "void main() { out_FragColor = texture(u_texture, u_txCoords); }"; - - let txCoords; - const um = { - u_texture: function () { - return texture; - }, - u_txCoords: function () { - return txCoords; - }, - }; + expect(texture.sizeInBytes).toEqual(8); - // Blue on top - txCoords = new Cartesian2(0.5, 0.75); - expect({ - context: context, - fragmentShader: fragmentShaderSource, - uniformMap: um, - }).contextToRender([0, 0, 255, 255]); - - // Red on bottom - txCoords = new Cartesian2(0.5, 0.25); - expect({ - context: context, - fragmentShader: fragmentShaderSource, - uniformMap: um, - }).contextToRender([255, 0, 0, 255]); - }); - - it("draws the expected luminance texture color", function () { - const color = new Color(0.6, 0.6, 0.6, 1.0); - const arrayBufferView = new Uint8Array([153]); - - texture = new Texture({ - context: context, - pixelFormat: PixelFormat.LUMINANCE, - pixelDatatype: PixelDatatype.UNSIGNED_BYTE, - source: { - width: 1, - height: 1, - arrayBufferView: arrayBufferView, - }, - flipY: false, + expect({ + context: context, + fragmentShader: fs, + uniformMap: uniformMap, + }).contextToRender(color.toBytes()); }); - expect({ - context: context, - fragmentShader: fs, - uniformMap: uniformMap, - }).contextToRender(color.toBytes()); - }); + it("draws the expected half floating-point texture color with linear filtering", function () { + if (!context.halfFloatingPointTexture) { + return; + } - it("draws the expected luminance alpha texture color", function () { - const color = new Color(0.6, 0.8, 0.0, 1.0); - const arrayBufferView = new Uint8Array([153, 204]); + const color0 = new Color(0.2, 0.4, 0.6, 1.0); + const color1 = new Color(0.1, 0.3, 0.5, 1.0); + const floats = new Uint16Array([ + 12902, 13926, 14541, 15360, 11878, 13517, 14336, 15360, + ]); - texture = new Texture({ - context: context, - pixelFormat: PixelFormat.LUMINANCE_ALPHA, - pixelDatatype: PixelDatatype.UNSIGNED_BYTE, - source: { - width: 1, - height: 1, - arrayBufferView: arrayBufferView, - }, - flipY: false, - }); + texture = new Texture({ + context: context, + pixelFormat: PixelFormat.RGBA, + pixelDatatype: PixelDatatype.HALF_FLOAT, + source: { + width: 2, + height: 1, + arrayBufferView: floats, + }, + flipY: false, + }); - expect({ - context: context, - fragmentShader: fsLuminanceAlpha, - uniformMap: uniformMap, - }).contextToRender(color.toBytes()); - }); + expect(texture.sizeInBytes).toEqual(16); - it("can be created from a typed array", function () { - const bytes = new Uint8Array([0, 255, 0, 255]); + const fs = + "uniform sampler2D u_texture;" + + "void main() { out_FragColor = texture(u_texture, vec2(0.5, 0.0)); }"; - texture = new Texture({ - context: context, - pixelFormat: PixelFormat.RGBA, - pixelDatatype: PixelDatatype.UNSIGNED_BYTE, - source: { - width: 1, - height: 1, - arrayBufferView: bytes, - }, + if (!context.textureHalfFloatLinear) { + expect({ + context: context, + fragmentShader: fs, + uniformMap: uniformMap, + epsilon: 1, + }).contextToRender(color1.toBytes()); + } else { + Color.multiplyByScalar(color0, 1.0 - 0.5, color0); + Color.multiplyByScalar(color1, 0.5, color1); + Color.add(color0, color1, color1); + expect({ + context: context, + fragmentShader: fs, + uniformMap: uniformMap, + }).contextToRender(color1.toBytes()); + } }); - expect(texture.width).toEqual(1); - expect(texture.height).toEqual(1); - expect(texture.sizeInBytes).toEqual(4); + it("draws the expected Basis compressed texture color", function () { + if (!context.supportsBasis) { + return; + } - expect({ - context: context, - fragmentShader: fs, - uniformMap: uniformMap, - }).contextToRender([0, 255, 0, 255]); - }); + texture = new Texture({ + context: context, + pixelFormat: greenBasisKTX2Image.internalFormat, + source: { + width: greenBasisKTX2Image.width, + height: greenBasisKTX2Image.height, + arrayBufferView: greenBasisKTX2Image.bufferView, + }, + }); - it("can copy from a typed array", function () { - texture = new Texture({ - context: context, - pixelFormat: PixelFormat.RGBA, - pixelDatatype: PixelDatatype.UNSIGNED_BYTE, - width: 1, - height: 1, - }); + expect(texture.sizeInBytes).toBe(8); - const bytes = new Uint8Array(Color.NAVY.toBytes()); - texture.copyFrom({ - source: { - width: 1, - height: 1, - arrayBufferView: bytes, - }, + expect({ + context: context, + fragmentShader: fs, + uniformMap: uniformMap, + }).contextToRenderAndCall(function (color) { + return expect(color).toEqualEpsilon([2, 255, 2, 255], 2); + }); }); - expect(texture.width).toEqual(1); - expect(texture.height).toEqual(1); - expect(texture.sizeInBytes).toEqual(4); - - expect({ - context: context, - fragmentShader: fs, - uniformMap: uniformMap, - }).contextToRender(Color.NAVY.toBytes()); - }); + it("draws the expected KTX2 uncompressed texture color", function () { + texture = new Texture({ + context: context, + pixelFormat: greenKTX2Image.internalFormat, + source: { + width: greenKTX2Image.width, + height: greenKTX2Image.height, + arrayBufferView: greenKTX2Image.bufferView, + }, + }); - it("can copy from a DOM element", function () { - texture = new Texture({ - context: context, - pixelFormat: PixelFormat.RGB, - pixelDatatype: PixelDatatype.UNSIGNED_BYTE, - width: blueImage.width, - height: blueImage.height, - }); + expect(texture.sizeInBytes).toBe(48); - texture.copyFrom({ - source: blueImage, + expect({ + context: context, + fragmentShader: fs, + uniformMap: uniformMap, + }).contextToRenderAndCall(function (color) { + return expect(color).toEqualEpsilon([0, 255, 24, 255], 2); + }); }); - expect({ - context: context, - fragmentShader: fs, - uniformMap: uniformMap, - epsilon: 1, - }).contextToRender([0, 0, 255, 255]); - }); + it("renders with premultiplied alpha", function () { + const alphaContextOptions = Object.assign( + { + webgl: { + alpha: true, + }, + }, + contextOptions, + ); + const alphaContext = createContext(alphaContextOptions); + const texture = new Texture({ + context: alphaContext, + source: blueAlphaImage, + pixelFormat: PixelFormat.RGBA, + preMultiplyAlpha: true, + }); + const uniformMap = { + u_texture: function () { + return texture; + }, + }; - it("can copy from a DOM element when display dimensions are 0", function () { - blueImage.height = 0; - blueImage.width = 0; + expect(texture.preMultiplyAlpha).toEqual(true); + expect({ + context: alphaContext, + fragmentShader: fs, + uniformMap: uniformMap, + epsilon: 1, + }).contextToRender([0, 0, 127, 127]); - texture = new Texture({ - context: context, - pixelFormat: PixelFormat.RGB, - pixelDatatype: PixelDatatype.UNSIGNED_BYTE, - source: blueImage, + texture.destroy(); + alphaContext.destroyForSpecs(); }); - texture.copyFrom({ - source: blueImage, - }); + it("draws textured blue and red points", function () { + texture = new Texture({ + context: context, + source: blueOverRedImage, + pixelFormat: PixelFormat.RGBA, + }); - expect({ - context: context, - fragmentShader: fs, - uniformMap: uniformMap, - epsilon: 1, - }).contextToRender([0, 0, 255, 255]); - }); + let fragmentShaderSource = ""; + fragmentShaderSource += "uniform sampler2D u_texture;"; + fragmentShaderSource += "uniform mediump vec2 u_txCoords;"; + fragmentShaderSource += + "void main() { out_FragColor = texture(u_texture, u_txCoords); }"; - it("can replace a subset of a texture", function () { - texture = new Texture({ - context: context, - source: blueOverRedImage, - pixelFormat: PixelFormat.RGBA, - }); + let txCoords; + const um = { + u_texture: function () { + return texture; + }, + u_txCoords: function () { + return txCoords; + }, + }; - let fragmentShaderSource = ""; - fragmentShaderSource += "uniform sampler2D u_texture;"; - fragmentShaderSource += "uniform mediump vec2 u_txCoords;"; - fragmentShaderSource += - "void main() { out_FragColor = texture(u_texture, u_txCoords); }"; + // Blue on top + txCoords = new Cartesian2(0.5, 0.75); + expect({ + context: context, + fragmentShader: fragmentShaderSource, + uniformMap: um, + }).contextToRender([0, 0, 255, 255]); - let txCoords; - const um = { - u_texture: function () { - return texture; - }, - u_txCoords: function () { - return txCoords; - }, - }; + // Red on bottom + txCoords = new Cartesian2(0.5, 0.25); + expect({ + context: context, + fragmentShader: fragmentShaderSource, + uniformMap: um, + }).contextToRender([255, 0, 0, 255]); + }); - // Blue on top - txCoords = new Cartesian2(0.5, 0.75); - expect({ - context: context, - fragmentShader: fragmentShaderSource, - uniformMap: um, - }).contextToRender([0, 0, 255, 255]); - - // Red on bottom - txCoords = new Cartesian2(0.5, 0.25); - expect({ - context: context, - fragmentShader: fragmentShaderSource, - uniformMap: um, - }).contextToRender([255, 0, 0, 255]); - - // After copy... - texture.copyFrom({ - source: greenImage, - xOffset: 0, - yOffset: 1, - }); - - // Now green on top - txCoords = new Cartesian2(0.5, 0.75); - expect({ - context: context, - fragmentShader: fragmentShaderSource, - uniformMap: um, - }).contextToRender(Color.LIME.toBytes()); - - // Still red on bottom - txCoords = new Cartesian2(0.5, 0.25); - expect({ - context: context, - fragmentShader: fragmentShaderSource, - uniformMap: um, - }).contextToRender([255, 0, 0, 255]); - }); - - it("can generate mipmaps", function () { - texture = new Texture({ - context: context, - source: red16x16Image, - pixelFormat: PixelFormat.RGBA, - sampler: new Sampler({ - minificationFilter: TextureMinificationFilter.NEAREST_MIPMAP_LINEAR, - }), - }); - texture.generateMipmap(); - expect(texture.sizeInBytes).toEqualEpsilon( - (16 * 16 + 8 * 8 + 4 * 4 + 2 * 2 + 1) * 4, - 1, - ); - - expect({ - context: context, - fragmentShader: fs, - uniformMap: uniformMap, - }).contextToRender([255, 0, 0, 255]); - }); - - it("can set a sampler property", function () { - texture = new Texture({ - context: context, - source: blueImage, - pixelFormat: PixelFormat.RGBA, - }); - - const sampler = new Sampler({ - wrapS: TextureWrap.REPEAT, - wrapT: TextureWrap.MIRRORED_REPEAT, - minificationFilter: TextureMinificationFilter.NEAREST, - magnificationFilter: TextureMagnificationFilter.NEAREST, - maximumAnisotropy: 2.0, - }); - texture.sampler = sampler; - - const s = texture.sampler; - expect(s.wrapS).toEqual(sampler.wrapS); - expect(s.wrapT).toEqual(sampler.wrapT); - expect(s.minificationFilter).toEqual(sampler.minificationFilter); - expect(s.magnificationFilter).toEqual(sampler.magnificationFilter); - expect(s.maximumAnisotropy).toEqual(2.0); - }); - - it("can set sampler at construction", function () { - texture = new Texture({ - context: context, - source: blueImage, - pixelFormat: PixelFormat.RGBA, - sampler: new Sampler({ - wrapS: TextureWrap.REPEAT, - wrapT: TextureWrap.MIRRORED_REPEAT, - minificationFilter: TextureMinificationFilter.NEAREST, - magnificationFilter: TextureMagnificationFilter.NEAREST, - maximumAnisotropy: 2.0, - }), - }); - - const s = texture.sampler; - expect(s.wrapS).toEqual(TextureWrap.REPEAT); - expect(s.wrapT).toEqual(TextureWrap.MIRRORED_REPEAT); - expect(s.minificationFilter).toEqual(TextureMinificationFilter.NEAREST); - expect(s.magnificationFilter).toEqual(TextureMagnificationFilter.NEAREST); - expect(s.maximumAnisotropy).toEqual(2.0); - }); - - it("can get width and height", function () { - texture = new Texture({ - context: context, - source: blueOverRedImage, - pixelFormat: PixelFormat.RGBA, - }); - - expect(texture.width).toEqual(1); - expect(texture.height).toEqual(2); - }); - - it("can get whether Y is flipped", function () { - texture = new Texture({ - context: context, - source: blueOverRedImage, - pixelFormat: PixelFormat.RGBA, - flipY: true, - }); - - expect(texture.flipY).toEqual(true); - }); - - it("can get the dimensions of a texture", function () { - texture = new Texture({ - context: context, - width: 64, - height: 16, - }); - - expect(texture.dimensions).toEqual(new Cartesian2(64, 16)); - }); - - function expectTextureByteSize( - width, - height, - pixelFormat, - pixelDatatype, - expectedSize, - ) { - texture = new Texture({ - context: context, - width: width, - height: height, - pixelFormat: pixelFormat, - pixelDatatype: pixelDatatype, - }); - expect(texture.sizeInBytes).toBe(expectedSize); - texture = texture && texture.destroy(); - } + it("draws the expected luminance texture color", function () { + const color = new Color(0.6, 0.6, 0.6, 1.0); + const arrayBufferView = new Uint8Array([153]); - it("can get the size in bytes of a texture", function () { - // Depth textures - if (context.depthTexture) { - expectTextureByteSize( - 16, - 16, - PixelFormat.DEPTH_COMPONENT, - PixelDatatype.UNSIGNED_SHORT, - 256 * 2, - ); - expectTextureByteSize( - 16, - 16, - PixelFormat.DEPTH_COMPONENT, - PixelDatatype.UNSIGNED_INT, - 256 * 4, - ); - expectTextureByteSize( - 16, - 16, - PixelFormat.DEPTH_STENCIL, - PixelDatatype.UNSIGNED_INT_24_8, - 256 * 4, - ); - } + texture = new Texture({ + context: context, + pixelFormat: PixelFormat.LUMINANCE, + pixelDatatype: PixelDatatype.UNSIGNED_BYTE, + source: { + width: 1, + height: 1, + arrayBufferView: arrayBufferView, + }, + flipY: false, + }); + + expect({ + context: context, + fragmentShader: fs, + uniformMap: uniformMap, + }).contextToRender(color.toBytes()); + }); + + it("draws the expected luminance alpha texture color", function () { + const color = new Color(0.6, 0.8, 0.0, 1.0); + const arrayBufferView = new Uint8Array([153, 204]); - // Uncompressed formats - expectTextureByteSize( - 16, - 16, - PixelFormat.ALPHA, - PixelDatatype.UNSIGNED_BYTE, - 256, - ); - expectTextureByteSize( - 16, - 16, - PixelFormat.RGB, - PixelDatatype.UNSIGNED_BYTE, - 256 * 3, - ); - expectTextureByteSize( - 16, - 16, - PixelFormat.RGBA, - PixelDatatype.UNSIGNED_BYTE, - 256 * 4, - ); - expectTextureByteSize( - 16, - 16, - PixelFormat.LUMINANCE, - PixelDatatype.UNSIGNED_BYTE, - 256, - ); - expectTextureByteSize( - 16, - 16, - PixelFormat.LUMINANCE_ALPHA, - PixelDatatype.UNSIGNED_BYTE, - 256 * 2, - ); - }); - - it("can be destroyed", function () { - const t = new Texture({ - context: context, - source: blueImage, - pixelFormat: PixelFormat.RGBA, - }); - - expect(t.isDestroyed()).toEqual(false); - t.destroy(); - expect(t.isDestroyed()).toEqual(true); - }); - - it("throws when creating a texture without a options", function () { - expect(function () { - texture = new Texture(); - }).toThrowDeveloperError(); - }); - - it("throws when creating a texture without a source", function () { - expect(function () { texture = new Texture({ context: context, + pixelFormat: PixelFormat.LUMINANCE_ALPHA, + pixelDatatype: PixelDatatype.UNSIGNED_BYTE, + source: { + width: 1, + height: 1, + arrayBufferView: arrayBufferView, + }, + flipY: false, }); - }).toThrowDeveloperError(); - }); - it("throws when creating a texture with width and no height", function () { - expect(function () { + expect({ + context: context, + fragmentShader: fsLuminanceAlpha, + uniformMap: uniformMap, + }).contextToRender(color.toBytes()); + }); + + it("can be created from a typed array", function () { + const bytes = new Uint8Array([0, 255, 0, 255]); + texture = new Texture({ context: context, - width: 16, + pixelFormat: PixelFormat.RGBA, + pixelDatatype: PixelDatatype.UNSIGNED_BYTE, + source: { + width: 1, + height: 1, + arrayBufferView: bytes, + }, }); - }).toThrowDeveloperError(); - }); - it("throws when creating a texture with height and no width", function () { - expect(function () { + expect(texture.width).toEqual(1); + expect(texture.height).toEqual(1); + expect(texture.sizeInBytes).toEqual(4); + + expect({ + context: context, + fragmentShader: fs, + uniformMap: uniformMap, + }).contextToRender([0, 255, 0, 255]); + }); + + it("can copy from a typed array", function () { texture = new Texture({ context: context, - height: 16, + pixelFormat: PixelFormat.RGBA, + pixelDatatype: PixelDatatype.UNSIGNED_BYTE, + width: 1, + height: 1, }); - }).toThrowDeveloperError(); - }); - it("throws when creating a texture with zero width", function () { - expect(function () { + const bytes = new Uint8Array(Color.NAVY.toBytes()); + texture.copyFrom({ + source: { + width: 1, + height: 1, + arrayBufferView: bytes, + }, + }); + + expect(texture.width).toEqual(1); + expect(texture.height).toEqual(1); + expect(texture.sizeInBytes).toEqual(4); + + expect({ + context: context, + fragmentShader: fs, + uniformMap: uniformMap, + }).contextToRender(Color.NAVY.toBytes()); + }); + + it("can copy from a DOM element", function () { texture = new Texture({ context: context, - width: 0, - height: 16, + pixelFormat: PixelFormat.RGB, + pixelDatatype: PixelDatatype.UNSIGNED_BYTE, + width: blueImage.width, + height: blueImage.height, }); - }).toThrowDeveloperError(); - }); - it("throws when creating a texture with width larger than the maximum texture size", function () { - expect(function () { + texture.copyFrom({ + source: blueImage, + }); + + expect({ + context: context, + fragmentShader: fs, + uniformMap: uniformMap, + epsilon: 1, + }).contextToRender([0, 0, 255, 255]); + }); + + it("can copy from a DOM element when display dimensions are 0", function () { + blueImage.height = 0; + blueImage.width = 0; + texture = new Texture({ context: context, - width: ContextLimits.maximumTextureSize + 1, - height: 16, + pixelFormat: PixelFormat.RGB, + pixelDatatype: PixelDatatype.UNSIGNED_BYTE, + source: blueImage, }); - }).toThrowDeveloperError(); - }); - it("throws when creating a texture with zero height", function () { - expect(function () { + texture.copyFrom({ + source: blueImage, + }); + + expect({ + context: context, + fragmentShader: fs, + uniformMap: uniformMap, + epsilon: 1, + }).contextToRender([0, 0, 255, 255]); + }); + + it("can replace a subset of a texture", function () { texture = new Texture({ context: context, - width: 16, - height: 0, + source: blueOverRedImage, + pixelFormat: PixelFormat.RGBA, }); - }).toThrowDeveloperError(); - }); - it("throws when creating a texture with height larger than the maximum texture size", function () { - expect(function () { + let fragmentShaderSource = ""; + fragmentShaderSource += "uniform sampler2D u_texture;"; + fragmentShaderSource += "uniform mediump vec2 u_txCoords;"; + fragmentShaderSource += + "void main() { out_FragColor = texture(u_texture, u_txCoords); }"; + + let txCoords; + const um = { + u_texture: function () { + return texture; + }, + u_txCoords: function () { + return txCoords; + }, + }; + + // Blue on top + txCoords = new Cartesian2(0.5, 0.75); + expect({ + context: context, + fragmentShader: fragmentShaderSource, + uniformMap: um, + }).contextToRender([0, 0, 255, 255]); + + // Red on bottom + txCoords = new Cartesian2(0.5, 0.25); + expect({ + context: context, + fragmentShader: fragmentShaderSource, + uniformMap: um, + }).contextToRender([255, 0, 0, 255]); + + // After copy... + texture.copyFrom({ + source: greenImage, + xOffset: 0, + yOffset: 1, + }); + + // Now green on top + txCoords = new Cartesian2(0.5, 0.75); + expect({ + context: context, + fragmentShader: fragmentShaderSource, + uniformMap: um, + }).contextToRender(Color.LIME.toBytes()); + + // Still red on bottom + txCoords = new Cartesian2(0.5, 0.25); + expect({ + context: context, + fragmentShader: fragmentShaderSource, + uniformMap: um, + }).contextToRender([255, 0, 0, 255]); + }); + + it("can generate mipmaps", function () { texture = new Texture({ context: context, - width: 16, - height: ContextLimits.maximumTextureSize + 1, + source: red16x16Image, + pixelFormat: PixelFormat.RGBA, + sampler: new Sampler({ + minificationFilter: TextureMinificationFilter.NEAREST_MIPMAP_LINEAR, + }), }); - }).toThrowDeveloperError(); - }); + texture.generateMipmap(); + expect(texture.sizeInBytes).toEqualEpsilon( + (16 * 16 + 8 * 8 + 4 * 4 + 2 * 2 + 1) * 4, + 1, + ); + + expect({ + context: context, + fragmentShader: fs, + uniformMap: uniformMap, + }).contextToRender([255, 0, 0, 255]); + }); - it("throws when creating a texture with an invalid pixel format", function () { - expect(function () { + it("can set a sampler property", function () { texture = new Texture({ context: context, source: blueImage, - pixelFormat: "invalid PixelFormat", + pixelFormat: PixelFormat.RGBA, + }); + + const sampler = new Sampler({ + wrapS: TextureWrap.REPEAT, + wrapT: TextureWrap.MIRRORED_REPEAT, + minificationFilter: TextureMinificationFilter.NEAREST, + magnificationFilter: TextureMagnificationFilter.NEAREST, + maximumAnisotropy: 2.0, }); - }).toThrowDeveloperError(); - }); + texture.sampler = sampler; + + const s = texture.sampler; + expect(s.wrapS).toEqual(sampler.wrapS); + expect(s.wrapT).toEqual(sampler.wrapT); + expect(s.minificationFilter).toEqual(sampler.minificationFilter); + expect(s.magnificationFilter).toEqual(sampler.magnificationFilter); + expect(s.maximumAnisotropy).toEqual(2.0); + }); - it("throws when creating a texture with an invalid pixel datatype", function () { - expect(function () { + it("can set sampler at construction", function () { texture = new Texture({ context: context, source: blueImage, pixelFormat: PixelFormat.RGBA, - pixelDatatype: "invalid pixelDatatype", + sampler: new Sampler({ + wrapS: TextureWrap.REPEAT, + wrapT: TextureWrap.MIRRORED_REPEAT, + minificationFilter: TextureMinificationFilter.NEAREST, + magnificationFilter: TextureMagnificationFilter.NEAREST, + maximumAnisotropy: 2.0, + }), }); - }).toThrowDeveloperError(); - }); - it("throws when creating if pixelFormat is DEPTH_COMPONENT and pixelDatatype is not UNSIGNED_SHORT or UNSIGNED_INT", function () { - expect(function () { - texture = new Texture({ - context: context, - pixelFormat: PixelFormat.DEPTH_COMPONENT, - pixelDatatype: PixelDatatype.UNSIGNED_BYTE, - }); - }).toThrowDeveloperError(); - }); + const s = texture.sampler; + expect(s.wrapS).toEqual(TextureWrap.REPEAT); + expect(s.wrapT).toEqual(TextureWrap.MIRRORED_REPEAT); + expect(s.minificationFilter).toEqual(TextureMinificationFilter.NEAREST); + expect(s.magnificationFilter).toEqual( + TextureMagnificationFilter.NEAREST, + ); + expect(s.maximumAnisotropy).toEqual(2.0); + }); + + it("can get width and height", function () { + texture = new Texture({ + context: context, + source: blueOverRedImage, + pixelFormat: PixelFormat.RGBA, + }); + + expect(texture.width).toEqual(1); + expect(texture.height).toEqual(2); + }); + + it("can get whether Y is flipped", function () { + texture = new Texture({ + context: context, + source: blueOverRedImage, + pixelFormat: PixelFormat.RGBA, + flipY: true, + }); + + expect(texture.flipY).toEqual(true); + }); + + it("can get the dimensions of a texture", function () { + texture = new Texture({ + context: context, + width: 64, + height: 16, + }); + + expect(texture.dimensions).toEqual(new Cartesian2(64, 16)); + }); + + function expectTextureByteSize( + width, + height, + pixelFormat, + pixelDatatype, + expectedSize, + ) { + texture = new Texture({ + context: context, + width: width, + height: height, + pixelFormat: pixelFormat, + pixelDatatype: pixelDatatype, + }); + expect(texture.sizeInBytes).toBe(expectedSize); + texture = texture && texture.destroy(); + } + + it("can get the size in bytes of a texture", function () { + // Depth textures + if (context.depthTexture) { + expectTextureByteSize( + 16, + 16, + PixelFormat.DEPTH_COMPONENT, + PixelDatatype.UNSIGNED_SHORT, + 256 * 2, + ); + expectTextureByteSize( + 16, + 16, + PixelFormat.DEPTH_COMPONENT, + PixelDatatype.UNSIGNED_INT, + 256 * 4, + ); + expectTextureByteSize( + 16, + 16, + PixelFormat.DEPTH_STENCIL, + PixelDatatype.UNSIGNED_INT_24_8, + 256 * 4, + ); + } + + // Uncompressed formats + expectTextureByteSize( + 16, + 16, + PixelFormat.ALPHA, + PixelDatatype.UNSIGNED_BYTE, + 256, + ); + expectTextureByteSize( + 16, + 16, + PixelFormat.RGB, + PixelDatatype.UNSIGNED_BYTE, + 256 * 3, + ); + expectTextureByteSize( + 16, + 16, + PixelFormat.RGBA, + PixelDatatype.UNSIGNED_BYTE, + 256 * 4, + ); + expectTextureByteSize( + 16, + 16, + PixelFormat.LUMINANCE, + PixelDatatype.UNSIGNED_BYTE, + 256, + ); + expectTextureByteSize( + 16, + 16, + PixelFormat.LUMINANCE_ALPHA, + PixelDatatype.UNSIGNED_BYTE, + 256 * 2, + ); + }); + + it("can be destroyed", function () { + const t = new Texture({ + context: context, + source: blueImage, + pixelFormat: PixelFormat.RGBA, + }); + + expect(t.isDestroyed()).toEqual(false); + t.destroy(); + expect(t.isDestroyed()).toEqual(true); + }); + + it("throws when creating a texture without a options", function () { + expect(function () { + texture = new Texture(); + }).toThrowDeveloperError(); + }); + + it("throws when creating a texture without a source", function () { + expect(function () { + texture = new Texture({ + context: context, + }); + }).toThrowDeveloperError(); + }); + + it("throws when creating a texture with width and no height", function () { + expect(function () { + texture = new Texture({ + context: context, + width: 16, + }); + }).toThrowDeveloperError(); + }); + + it("throws when creating a texture with height and no width", function () { + expect(function () { + texture = new Texture({ + context: context, + height: 16, + }); + }).toThrowDeveloperError(); + }); + + it("throws when creating a texture with zero width", function () { + expect(function () { + texture = new Texture({ + context: context, + width: 0, + height: 16, + }); + }).toThrowDeveloperError(); + }); + + it("throws when creating a texture with width larger than the maximum texture size", function () { + expect(function () { + texture = new Texture({ + context: context, + width: ContextLimits.maximumTextureSize + 1, + height: 16, + }); + }).toThrowDeveloperError(); + }); + + it("throws when creating a texture with zero height", function () { + expect(function () { + texture = new Texture({ + context: context, + width: 16, + height: 0, + }); + }).toThrowDeveloperError(); + }); + + it("throws when creating a texture with height larger than the maximum texture size", function () { + expect(function () { + texture = new Texture({ + context: context, + width: 16, + height: ContextLimits.maximumTextureSize + 1, + }); + }).toThrowDeveloperError(); + }); + + it("throws when creating a texture with an invalid pixel format", function () { + expect(function () { + texture = new Texture({ + context: context, + source: blueImage, + pixelFormat: "invalid PixelFormat", + }); + }).toThrowDeveloperError(); + }); + + it("throws when creating a texture with an invalid pixel datatype", function () { + expect(function () { + texture = new Texture({ + context: context, + source: blueImage, + pixelFormat: PixelFormat.RGBA, + pixelDatatype: "invalid pixelDatatype", + }); + }).toThrowDeveloperError(); + }); + + it("throws when creating if pixelFormat is DEPTH_COMPONENT and pixelDatatype is not UNSIGNED_SHORT or UNSIGNED_INT", function () { + expect(function () { + texture = new Texture({ + context: context, + pixelFormat: PixelFormat.DEPTH_COMPONENT, + pixelDatatype: PixelDatatype.UNSIGNED_BYTE, + }); + }).toThrowDeveloperError(); + }); + + it("throws when creating if pixelFormat is DEPTH_STENCIL and pixelDatatype is not UNSIGNED_INT_24_8", function () { + expect(function () { + texture = new Texture({ + context: context, + pixelFormat: PixelFormat.DEPTH_STENCIL, + pixelDatatype: PixelDatatype.UNSIGNED_BYTE, + }); + }).toThrowDeveloperError(); + }); + + it("throws when creating if pixelFormat is DEPTH_COMPONENT or DEPTH_STENCIL, and source is provided", function () { + expect(function () { + texture = new Texture({ + context: context, + source: blueImage, + pixelFormat: PixelFormat.DEPTH_COMPONENT, + pixelDatatype: PixelDatatype.UNSIGNED_SHORT, + }); + }).toThrowDeveloperError(); + }); + + it("throws when creating if pixelFormat is DEPTH_COMPONENT or DEPTH_STENCIL, and WEBGL_depth_texture is not supported", function () { + if (!context.depthTexture) { + expect(function () { + texture = new Texture({ + context: context, + width: 1, + height: 1, + pixelFormat: PixelFormat.DEPTH_COMPONENT, + pixelDatatype: PixelDatatype.UNSIGNED_SHORT, + }); + }).toThrowDeveloperError(); + } + }); + + it("throws when creating if pixelDatatype is FLOAT, and OES_texture_float is not supported", function () { + if (!context.floatingPointTexture) { + expect(function () { + texture = new Texture({ + context: context, + width: 1, + height: 1, + pixelFormat: PixelFormat.RGBA, + pixelDatatype: PixelDatatype.FLOAT, + }); + }).toThrowDeveloperError(); + } + }); + + it("throws when creating if pixelDatatype = HALF_FLOAT, and OES_texture_half_float is not supported", function () { + if (!context.halfFloatingPointTexture) { + expect(function () { + texture = new Texture({ + context: context, + width: 1, + height: 1, + pixelFormat: PixelDatatype.RGBA, + pixelDatatype: PixelDatatype.HALF_FLOAT, + }); + }).toThrowDeveloperError(); + } + }); + + it("throws when creating compressed texture and the array buffer source is undefined", function () { + expect(function () { + texture = new Texture({ + context: context, + width: 4, + height: 4, + pixelFormat: PixelFormat.RGBA_DXT3, + }); + }).toThrowDeveloperError(); + }); + + it("throws when creating from the framebuffer with an invalid pixel format", function () { + expect(function () { + texture = Texture.fromFramebuffer({ + context: context, + pixelFormat: "invalid PixelFormat", + }); + }).toThrowDeveloperError(); + }); + + it("throws when creating from the framebuffer if PixelFormat is DEPTH_COMPONENT or DEPTH_STENCIL", function () { + expect(function () { + texture = Texture.fromFramebuffer({ + context: context, + pixelFormat: PixelFormat.DEPTH_COMPONENT, + }); + }).toThrowDeveloperError(); + }); + + it("throws when creating from the framebuffer with a negative framebufferXOffset", function () { + expect(function () { + texture = Texture.fromFramebuffer({ + context: context, + pixelFormat: PixelFormat.RGB, + framebufferXOffset: -1, + }); + }).toThrowDeveloperError(); + }); - it("throws when creating if pixelFormat is DEPTH_STENCIL and pixelDatatype is not UNSIGNED_INT_24_8", function () { - expect(function () { - texture = new Texture({ - context: context, - pixelFormat: PixelFormat.DEPTH_STENCIL, - pixelDatatype: PixelDatatype.UNSIGNED_BYTE, - }); - }).toThrowDeveloperError(); - }); + it("throws when creating from the framebuffer with a negative framebufferYOffset", function () { + expect(function () { + texture = Texture.fromFramebuffer({ + context: context, + pixelFormat: PixelFormat.RGB, + framebufferXOffset: 0, + framebufferYOffset: -1, + }); + }).toThrowDeveloperError(); + }); - it("throws when creating if pixelFormat is DEPTH_COMPONENT or DEPTH_STENCIL, and source is provided", function () { - expect(function () { - texture = new Texture({ - context: context, - source: blueImage, - pixelFormat: PixelFormat.DEPTH_COMPONENT, - pixelDatatype: PixelDatatype.UNSIGNED_SHORT, - }); - }).toThrowDeveloperError(); - }); + it("throws when creating from the framebuffer with a width greater than the canvas clientWidth", function () { + expect(function () { + texture = Texture.fromFramebuffer({ + context: context, + pixelFormat: PixelFormat.RGB, + framebufferXOffset: 0, + framebufferYOffset: 0, + width: context.canvas.clientWidth + 1, + }); + }).toThrowDeveloperError(); + }); - it("throws when creating if pixelFormat is DEPTH_COMPONENT or DEPTH_STENCIL, and WEBGL_depth_texture is not supported", function () { - if (!context.depthTexture) { + it("throws when creating from the framebuffer with a height greater than the canvas clientHeight", function () { expect(function () { + texture = Texture.fromFramebuffer({ + context: context, + pixelFormat: PixelFormat.RGB, + framebufferXOffset: 0, + framebufferYOffset: 0, + width: 1, + height: context.canvas.clientHeight + 1, + }); + }).toThrowDeveloperError(); + }); + + it("throws when copying to a texture from the framebuffer with a DEPTH_COMPONENT or DEPTH_STENCIL pixel format", function () { + if (context.depthTexture) { texture = new Texture({ context: context, width: 1, @@ -1092,13 +1220,33 @@ describe( pixelFormat: PixelFormat.DEPTH_COMPONENT, pixelDatatype: PixelDatatype.UNSIGNED_SHORT, }); - }).toThrowDeveloperError(); - } - }); - it("throws when creating if pixelDatatype is FLOAT, and OES_texture_float is not supported", function () { - if (!context.floatingPointTexture) { - expect(function () { + expect(function () { + texture.copyFromFramebuffer(); + }).toThrowDeveloperError(); + } + }); + + it("throws when copying to a texture from the framebuffer with a compressed pixel format", function () { + if (context.supportsBasis) { + texture = new Texture({ + context: context, + width: greenBasisKTX2Image.width, + height: greenBasisKTX2Image.height, + pixelFormat: greenBasisKTX2Image.internalFormat, + source: { + arrayBufferView: greenBasisKTX2Image.bufferView, + }, + }); + + expect(function () { + texture.copyFromFramebuffer(); + }).toThrowDeveloperError(); + } + }); + + it("throws when copying to a texture from the framebuffer with a FLOAT pixel data type", function () { + if (context.floatingPointTexture) { texture = new Texture({ context: context, width: 1, @@ -1106,454 +1254,313 @@ describe( pixelFormat: PixelFormat.RGBA, pixelDatatype: PixelDatatype.FLOAT, }); - }).toThrowDeveloperError(); - } - }); - it("throws when creating if pixelDatatype = HALF_FLOAT, and OES_texture_half_float is not supported", function () { - if (!context.halfFloatingPointTexture) { - expect(function () { + expect(function () { + texture.copyFromFramebuffer(); + }).toThrowDeveloperError(); + } + }); + + it("throws when copying to a texture from the framebuffer with a HALF_FLOAT pixel data type", function () { + if (context.halfFloatingPointTexture) { texture = new Texture({ context: context, width: 1, height: 1, - pixelFormat: PixelDatatype.RGBA, + pixelFormat: PixelFormat.RGBA, pixelDatatype: PixelDatatype.HALF_FLOAT, }); - }).toThrowDeveloperError(); - } - }); - - it("throws when creating compressed texture and the array buffer source is undefined", function () { - expect(function () { - texture = new Texture({ - context: context, - width: 4, - height: 4, - pixelFormat: PixelFormat.RGBA_DXT3, - }); - }).toThrowDeveloperError(); - }); - - it("throws when creating from the framebuffer with an invalid pixel format", function () { - expect(function () { - texture = Texture.fromFramebuffer({ - context: context, - pixelFormat: "invalid PixelFormat", - }); - }).toThrowDeveloperError(); - }); - it("throws when creating from the framebuffer if PixelFormat is DEPTH_COMPONENT or DEPTH_STENCIL", function () { - expect(function () { - texture = Texture.fromFramebuffer({ - context: context, - pixelFormat: PixelFormat.DEPTH_COMPONENT, - }); - }).toThrowDeveloperError(); - }); + expect(function () { + texture.copyFromFramebuffer(); + }).toThrowDeveloperError(); + } + }); - it("throws when creating from the framebuffer with a negative framebufferXOffset", function () { - expect(function () { - texture = Texture.fromFramebuffer({ + it("throws when copying from the framebuffer with a negative xOffset", function () { + texture = new Texture({ context: context, - pixelFormat: PixelFormat.RGB, - framebufferXOffset: -1, + source: blueImage, }); - }).toThrowDeveloperError(); - }); - it("throws when creating from the framebuffer with a negative framebufferYOffset", function () { - expect(function () { - texture = Texture.fromFramebuffer({ - context: context, - pixelFormat: PixelFormat.RGB, - framebufferXOffset: 0, - framebufferYOffset: -1, - }); - }).toThrowDeveloperError(); - }); + expect(function () { + texture.copyFromFramebuffer(-1); + }).toThrowDeveloperError(); + }); - it("throws when creating from the framebuffer with a width greater than the canvas clientWidth", function () { - expect(function () { - texture = Texture.fromFramebuffer({ + it("throws when copying from the framebuffer with a negative yOffset", function () { + texture = new Texture({ context: context, - pixelFormat: PixelFormat.RGB, - framebufferXOffset: 0, - framebufferYOffset: 0, - width: context.canvas.clientWidth + 1, + source: blueImage, }); - }).toThrowDeveloperError(); - }); - it("throws when creating from the framebuffer with a height greater than the canvas clientHeight", function () { - expect(function () { - texture = Texture.fromFramebuffer({ - context: context, - pixelFormat: PixelFormat.RGB, - framebufferXOffset: 0, - framebufferYOffset: 0, - width: 1, - height: context.canvas.clientHeight + 1, - }); - }).toThrowDeveloperError(); - }); + expect(function () { + texture.copyFromFramebuffer(0, -1); + }).toThrowDeveloperError(); + }); - it("throws when copying to a texture from the framebuffer with a DEPTH_COMPONENT or DEPTH_STENCIL pixel format", function () { - if (context.depthTexture) { + it("throws when copying from the framebuffer with a negative framebufferXOffset", function () { texture = new Texture({ context: context, - width: 1, - height: 1, - pixelFormat: PixelFormat.DEPTH_COMPONENT, - pixelDatatype: PixelDatatype.UNSIGNED_SHORT, + source: blueImage, }); expect(function () { - texture.copyFromFramebuffer(); + texture.copyFromFramebuffer(0, 0, -1); }).toThrowDeveloperError(); - } - }); + }); - it("throws when copying to a texture from the framebuffer with a compressed pixel format", function () { - if (context.supportsBasis) { + it("throws when copying from the framebuffer with a negative framebufferYOffset", function () { texture = new Texture({ context: context, - width: greenBasisKTX2Image.width, - height: greenBasisKTX2Image.height, - pixelFormat: greenBasisKTX2Image.internalFormat, - source: { - arrayBufferView: greenBasisKTX2Image.bufferView, - }, + source: blueImage, }); expect(function () { - texture.copyFromFramebuffer(); + texture.copyFromFramebuffer(0, 0, 0, -1); }).toThrowDeveloperError(); - } - }); + }); - it("throws when copying to a texture from the framebuffer with a FLOAT pixel data type", function () { - if (context.floatingPointTexture) { + it("throws when copying from the framebuffer with a larger width", function () { texture = new Texture({ context: context, - width: 1, - height: 1, - pixelFormat: PixelFormat.RGBA, - pixelDatatype: PixelDatatype.FLOAT, + source: blueImage, }); expect(function () { - texture.copyFromFramebuffer(); + texture.copyFromFramebuffer(0, 0, 0, 0, texture.width + 1); }).toThrowDeveloperError(); - } - }); + }); - it("throws when copying to a texture from the framebuffer with a HALF_FLOAT pixel data type", function () { - if (context.halfFloatingPointTexture) { + it("throws when copying from the framebuffer with a larger height", function () { texture = new Texture({ context: context, - width: 1, - height: 1, - pixelFormat: PixelFormat.RGBA, - pixelDatatype: PixelDatatype.HALF_FLOAT, + source: blueImage, }); expect(function () { - texture.copyFromFramebuffer(); + texture.copyFromFramebuffer(0, 0, 0, 0, 0, texture.height + 1); }).toThrowDeveloperError(); - } - }); - - it("throws when copying from the framebuffer with a negative xOffset", function () { - texture = new Texture({ - context: context, - source: blueImage, - }); - - expect(function () { - texture.copyFromFramebuffer(-1); - }).toThrowDeveloperError(); - }); - - it("throws when copying from the framebuffer with a negative yOffset", function () { - texture = new Texture({ - context: context, - source: blueImage, - }); - - expect(function () { - texture.copyFromFramebuffer(0, -1); - }).toThrowDeveloperError(); - }); - - it("throws when copying from the framebuffer with a negative framebufferXOffset", function () { - texture = new Texture({ - context: context, - source: blueImage, - }); - - expect(function () { - texture.copyFromFramebuffer(0, 0, -1); - }).toThrowDeveloperError(); - }); - - it("throws when copying from the framebuffer with a negative framebufferYOffset", function () { - texture = new Texture({ - context: context, - source: blueImage, }); - expect(function () { - texture.copyFromFramebuffer(0, 0, 0, -1); - }).toThrowDeveloperError(); - }); + it("throws when copying to a texture with a DEPTH_COMPONENT or DEPTH_STENCIL pixel format", function () { + if (context.depthTexture) { + texture = new Texture({ + context: context, + width: 1, + height: 1, + pixelFormat: PixelFormat.DEPTH_COMPONENT, + pixelDatatype: PixelDatatype.UNSIGNED_SHORT, + }); - it("throws when copying from the framebuffer with a larger width", function () { - texture = new Texture({ - context: context, - source: blueImage, + expect(function () { + texture.copyFrom({ + source: { + arrayBufferView: new Uint16Array([0]), + width: 1, + height: 1, + }, + }); + }).toThrowDeveloperError(); + } }); - expect(function () { - texture.copyFromFramebuffer(0, 0, 0, 0, texture.width + 1); - }).toThrowDeveloperError(); - }); + it("throws when copyFrom is not given any options", function () { + texture = new Texture({ + context: context, + source: blueImage, + }); - it("throws when copying from the framebuffer with a larger height", function () { - texture = new Texture({ - context: context, - source: blueImage, + expect(function () { + texture.copyFrom(); + }).toThrowDeveloperError(); }); - expect(function () { - texture.copyFromFramebuffer(0, 0, 0, 0, 0, texture.height + 1); - }).toThrowDeveloperError(); - }); - - it("throws when copying to a texture with a DEPTH_COMPONENT or DEPTH_STENCIL pixel format", function () { - if (context.depthTexture) { + it("throws when copyFrom is not given a source", function () { texture = new Texture({ context: context, - width: 1, - height: 1, - pixelFormat: PixelFormat.DEPTH_COMPONENT, - pixelDatatype: PixelDatatype.UNSIGNED_SHORT, + source: blueImage, }); expect(function () { texture.copyFrom({ - source: { - arrayBufferView: new Uint16Array([0]), - width: 1, - height: 1, - }, + xOffset: 0, + yOffset: 2, }); }).toThrowDeveloperError(); - } - }); - - it("throws when copyFrom is not given any options", function () { - texture = new Texture({ - context: context, - source: blueImage, - }); - - expect(function () { - texture.copyFrom(); - }).toThrowDeveloperError(); - }); - - it("throws when copyFrom is not given a source", function () { - texture = new Texture({ - context: context, - source: blueImage, - }); - - expect(function () { - texture.copyFrom({ - xOffset: 0, - yOffset: 2, - }); - }).toThrowDeveloperError(); - }); - - it("throws when copyFrom is given a negative xOffset", function () { - texture = new Texture({ - context: context, - source: blueImage, }); - expect(function () { - texture.copyFrom({ + it("throws when copyFrom is given a negative xOffset", function () { + texture = new Texture({ + context: context, source: blueImage, - xOffset: -1, }); - }).toThrowDeveloperError(); - }); - it("throws when copyFrom is given a negative yOffset", function () { - texture = new Texture({ - context: context, - source: blueImage, + expect(function () { + texture.copyFrom({ + source: blueImage, + xOffset: -1, + }); + }).toThrowDeveloperError(); }); - expect(function () { - texture.copyFrom({ + it("throws when copyFrom is given a negative yOffset", function () { + texture = new Texture({ + context: context, source: blueImage, - xOffset: 0, - yOffset: -1, }); - }).toThrowDeveloperError(); - }); - it("throws when copyFrom is given a source with larger width", function () { - texture = new Texture({ - context: context, - source: blueImage, - }); - const image = new Image(); - image.width = blueImage.width + 1; - - expect(function () { - texture.copyFrom({ - source: image, - }); - }).toThrowDeveloperError(); - }); - - it("throws when copyFrom is given a source with larger height", function () { - texture = new Texture({ - context: context, - source: blueImage, + expect(function () { + texture.copyFrom({ + source: blueImage, + xOffset: 0, + yOffset: -1, + }); + }).toThrowDeveloperError(); }); - const image = new Image(); - image.height = blueImage.height + 1; - - expect(function () { - texture.copyFrom({ - source: image, - }); - }).toThrowDeveloperError(); - }); - it("throws when copyFrom is given a source with a compressed pixel format", function () { - if (context.supportsBasis) { + it("throws when copyFrom is given a source with larger width", function () { texture = new Texture({ context: context, - width: greenBasisKTX2Image.width, - height: greenBasisKTX2Image.height, - pixelFormat: greenBasisKTX2Image.internalFormat, - source: { - arrayBufferView: greenBasisKTX2Image.bufferView, - }, + source: blueImage, }); - const image = new Image(); + image.width = blueImage.width + 1; + expect(function () { texture.copyFrom({ source: image, }); }).toThrowDeveloperError(); - } - }); + }); - it("throws when generating mipmaps with a DEPTH_COMPONENT or DEPTH_STENCIL pixel format", function () { - if (context.depthTexture) { + it("throws when copyFrom is given a source with larger height", function () { texture = new Texture({ context: context, - width: 1, - height: 1, - pixelFormat: PixelFormat.DEPTH_COMPONENT, - pixelDatatype: PixelDatatype.UNSIGNED_SHORT, + source: blueImage, }); + const image = new Image(); + image.height = blueImage.height + 1; expect(function () { - texture.generateMipmap(); + texture.copyFrom({ + source: image, + }); }).toThrowDeveloperError(); - } - }); + }); - it("throws when generating mipmaps with a compressed pixel format", function () { - if (context.supportsBasis) { - texture = new Texture({ - context: context, - width: greenBasisKTX2Image.width, - height: greenBasisKTX2Image.height, - pixelFormat: greenBasisKTX2Image.internalFormat, - source: { - arrayBufferView: greenBasisKTX2Image.bufferView, - }, - }); + it("throws when copyFrom is given a source with a compressed pixel format", function () { + if (context.supportsBasis) { + texture = new Texture({ + context: context, + width: greenBasisKTX2Image.width, + height: greenBasisKTX2Image.height, + pixelFormat: greenBasisKTX2Image.internalFormat, + source: { + arrayBufferView: greenBasisKTX2Image.bufferView, + }, + }); - expect(function () { - texture.generateMipmap(); - }).toThrowDeveloperError(); - } - }); + const image = new Image(); + expect(function () { + texture.copyFrom({ + source: image, + }); + }).toThrowDeveloperError(); + } + }); - describe("WebGL1", function () { - let webgl1Context; + it("throws when generating mipmaps with a DEPTH_COMPONENT or DEPTH_STENCIL pixel format", function () { + if (context.depthTexture) { + texture = new Texture({ + context: context, + width: 1, + height: 1, + pixelFormat: PixelFormat.DEPTH_COMPONENT, + pixelDatatype: PixelDatatype.UNSIGNED_SHORT, + }); - beforeAll(() => { - webgl1Context = createContext({ - requestWebgl1: true, - }); + expect(function () { + texture.generateMipmap(); + }).toThrowDeveloperError(); + } }); - afterAll(() => { - webgl1Context.destroyForSpecs(); + it("throws when generating mipmaps with a compressed pixel format", function () { + if (context.supportsBasis) { + texture = new Texture({ + context: context, + width: greenBasisKTX2Image.width, + height: greenBasisKTX2Image.height, + pixelFormat: greenBasisKTX2Image.internalFormat, + source: { + arrayBufferView: greenBasisKTX2Image.bufferView, + }, + }); + + expect(function () { + texture.generateMipmap(); + }).toThrowDeveloperError(); + } }); - it("throws when generating mipmaps with a non-power of two width", function () { - texture = new Texture({ - context: webgl1Context, - width: 3, - height: 2, + describe("WebGL1", function () { + it("throws when generating mipmaps with a non-power of two width", function () { + if (context.webgl2) { + return; + } + texture = new Texture({ + context: context, + width: 3, + height: 2, + }); + + expect(function () { + texture.generateMipmap(); + }).toThrowDeveloperError(); }); - expect(function () { - texture.generateMipmap(); - }).toThrowDeveloperError(); + it("throws when generating mipmaps with a non-power of two height", function () { + if (context.webgl2) { + return; + } + texture = new Texture({ + context: context, + width: 2, + height: 3, + }); + + expect(function () { + texture.generateMipmap(); + }).toThrowDeveloperError(); + }); }); - it("throws when generating mipmaps with a non-power of two height", function () { + it("throws when generating mipmaps with an invalid hint", function () { texture = new Texture({ - context: webgl1Context, - width: 2, - height: 3, + context: context, + source: blueImage, }); expect(function () { - texture.generateMipmap(); + texture.generateMipmap("invalid hint"); }).toThrowDeveloperError(); }); - }); - it("throws when generating mipmaps with an invalid hint", function () { - texture = new Texture({ - context: context, - source: blueImage, - }); + it("throws when destroy is called after destroying", function () { + const t = new Texture({ + context: context, + source: blueImage, + pixelFormat: PixelFormat.RGBA, + }); - expect(function () { - texture.generateMipmap("invalid hint"); - }).toThrowDeveloperError(); - }); + t.destroy(); - it("throws when destroy is called after destroying", function () { - const t = new Texture({ - context: context, - source: blueImage, - pixelFormat: PixelFormat.RGBA, + expect(function () { + t.destroy(); + }).toThrowDeveloperError(); }); - - t.destroy(); - - expect(function () { - t.destroy(); - }).toThrowDeveloperError(); - }); + } }, "WebGL", ); diff --git a/packages/engine/Specs/Scene/Cesium3DTilesetSpec.js b/packages/engine/Specs/Scene/Cesium3DTilesetSpec.js index 1f70a75175c3..a05b1be4dc28 100644 --- a/packages/engine/Specs/Scene/Cesium3DTilesetSpec.js +++ b/packages/engine/Specs/Scene/Cesium3DTilesetSpec.js @@ -91,6 +91,10 @@ describe( const tilesetOfTilesetsUrl = "Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/tileset.json"; + // A tileset that refers to 4 GLB files which share two (external) textures + const tilesetUrlWithSharedTextures = + "Data/Cesium3DTiles/Tilesets/TilesetWithSharedTextures/tileset.json"; + const withoutBatchTableUrl = "Data/Cesium3DTiles/Batched/BatchedWithoutBatchTable/tileset.json"; const withBatchTableUrl = @@ -211,9 +215,6 @@ describe( options = { cullRequestsWhileMoving: false, - environmentMapOptions: { - enabled: scene.highDynamicRangeSupported, - }, }; }); @@ -966,6 +967,78 @@ describe( ); }); + it("verify memory usage statistics for shared textures", async function () { + // One buffer view with 4 positions, 4 normals, and 4 texture coordinates, + // using a common byte stride of 12 (resulting in 144 bytes) + // and 2*3 unsigned short indices, resulting in a total of 156 bytes + const singleGeometryByteLength = 156; + + // One texture with 128x128 * RGBA pixels = 65536 bytes + const singleTexturesByteLength = 65536; + + // Basic camera setup + const camera = scene.camera; + + // NOTE: This is really, really important. There are some + // random calls in "beforeEach" and other parts of these + // specs that affect the camera transform. And the camera + // transform is NOT maintained to be consistent with the + // other properties in any way. So reset it here... + camera.lookAtTransform(Matrix4.IDENTITY); + + camera.position = new Cartesian3(0, -1, 0); + camera.direction = Cartesian3.clone(Cartesian3.UNIT_Y); + camera.up = Cartesian3.clone(Cartesian3.UNIT_Z); + camera.frustum.near = 0.01; + camera.frustum.far = 100.0; + + // Move the camera to see no tiles + camera.position = new Cartesian3(100, -1, 100); + + const tileset = await Cesium3DTilesTester.loadTileset( + scene, + tilesetUrlWithSharedTextures, + ); + + const statistics = tileset._statistics; + + // No tiles loaded + expect(statistics.geometryByteLength).toEqual(0); + expect(statistics.texturesByteLength).toEqual(0); + + // Move the camera to stare at the center of the first tile + camera.position = new Cartesian3(0.5, -1, 0.5); + await Cesium3DTilesTester.waitForTilesLoaded(scene, tileset); + + // A single tile and texture was loaded + expect(statistics.geometryByteLength).toEqual(singleGeometryByteLength); + expect(statistics.texturesByteLength).toEqual(singleTexturesByteLength); + + // Move the camera back to see all tiles + camera.position = new Cartesian3(3.5, -14, 0.5); + await Cesium3DTilesTester.waitForTilesLoaded(scene, tileset); + + // All tiles have been loaded: 4 times the geometry, BUT + // ONLY 2 times the texture + expect(statistics.geometryByteLength).toEqual( + singleGeometryByteLength * 4, + ); + expect(statistics.texturesByteLength).toEqual( + singleTexturesByteLength * 2, + ); + + // Move the camera back to stare at the center of the first tile again + camera.position = new Cartesian3(0.5, -1, 0.5); + + // Trim any previously loaded tiles + tileset.trimLoadedTiles(); + await Cesium3DTilesTester.waitForTilesLoaded(scene, tileset); + + // Again, only a single tile and texture should be loaded + expect(statistics.geometryByteLength).toEqual(singleGeometryByteLength); + expect(statistics.texturesByteLength).toEqual(singleTexturesByteLength); + }); + it("verify memory usage statistics for shared resources", function () { ResourceCache.statistics.clear(); // Six tiles total: diff --git a/packages/engine/Specs/Scene/DynamicEnvironmentMapManagerSpec.js b/packages/engine/Specs/Scene/DynamicEnvironmentMapManagerSpec.js index 57ea8ee5354f..0783774b7482 100644 --- a/packages/engine/Specs/Scene/DynamicEnvironmentMapManagerSpec.js +++ b/packages/engine/Specs/Scene/DynamicEnvironmentMapManagerSpec.js @@ -2,6 +2,7 @@ import { Cartesian3, Cartographic, Color, + ContextLimits, CubeMap, DynamicAtmosphereLightingType, DynamicEnvironmentMapManager, @@ -31,21 +32,59 @@ describe("Scene/DynamicEnvironmentMapManager", function () { expect(manager.groundAlbedo).toBe(0.31); }); + it("constructs with options", function () { + const manager = new DynamicEnvironmentMapManager({ + enabled: false, + maximumSecondsDifference: 0, + maximumPositionEpsilon: 0, + atmosphereScatteringIntensity: 0, + gamma: 0, + brightness: 0, + saturation: 0, + groundColor: Color.BLUE, + groundAlbedo: 0, + }); + + expect(manager.enabled).toBeFalse(); + expect(manager.shouldUpdate).toBeTrue(); + expect(manager.maximumSecondsDifference).toBe(0); + expect(manager.maximumPositionEpsilon).toBe(0); + expect(manager.atmosphereScatteringIntensity).toBe(0); + expect(manager.gamma).toBe(0); + expect(manager.brightness).toBe(0); + expect(manager.saturation).toBe(0); + expect(manager.groundColor).toEqual(Color.BLUE); + expect(manager.groundAlbedo).toBe(0); + }); + + it("uses default spherical harmonic coefficients", () => { + const manager = new DynamicEnvironmentMapManager(); + + expect(manager.sphericalHarmonicCoefficients.length).toBe(9); + expect(manager.sphericalHarmonicCoefficients).toEqual( + DynamicEnvironmentMapManager.DEFAULT_SPHERICAL_HARMONIC_COEFFICIENTS, + ); + }); + describe( "render tests", () => { const time = JulianDate.fromIso8601("2024-08-30T10:45:00Z"); - let scene; + let scene, orginalMaximumCubeMapSize; beforeAll(() => { scene = createScene({ skyBox: false, }); + orginalMaximumCubeMapSize = ContextLimits.maximumCubeMapSize; + // To keep tests fast, don't throttle + ContextLimits._maximumCubeMapSize = Number.POSITIVE_INFINITY; }); afterAll(() => { scene.destroyForSpecs(); + ContextLimits._maximumCubeMapSize = orginalMaximumCubeMapSize; }); afterEach(() => { @@ -53,7 +92,7 @@ describe("Scene/DynamicEnvironmentMapManager", function () { scene.atmosphere = new Atmosphere(); }); - // Allows the compute commands to be added to the command list at the right point in the pipeline + // A pared-down Primitive. Allows the compute commands to be added to the command list at the right point in the pipeline. function EnvironmentMockPrimitive(manager) { this.update = function (frameState) { manager.update(frameState); @@ -64,8 +103,74 @@ describe("Scene/DynamicEnvironmentMapManager", function () { }; } + it("does not update if position is undefined", async function () { + const manager = new DynamicEnvironmentMapManager(); + + const primitive = new EnvironmentMockPrimitive(manager); + scene.primitives.add(primitive); + + scene.renderForSpecs(); + + expect(manager.radianceCubeMap).toBeUndefined(); + + scene.renderForSpecs(); + + expect(manager.sphericalHarmonicCoefficients).toEqual( + DynamicEnvironmentMapManager.DEFAULT_SPHERICAL_HARMONIC_COEFFICIENTS, + ); + }); + + it("does not update if enabled is false", async function () { + const manager = new DynamicEnvironmentMapManager(); + + const cartographic = Cartographic.fromDegrees(-75.165222, 39.952583); + manager.position = + Ellipsoid.WGS84.cartographicToCartesian(cartographic); + manager.enabled = false; + + const primitive = new EnvironmentMockPrimitive(manager); + scene.primitives.add(primitive); + + scene.renderForSpecs(); + + expect(manager.radianceCubeMap).toBeUndefined(); + + scene.renderForSpecs(); + + expect(manager.sphericalHarmonicCoefficients).toEqual( + DynamicEnvironmentMapManager.DEFAULT_SPHERICAL_HARMONIC_COEFFICIENTS, + ); + }); + + it("does not update if requires extensions are not available", async function () { + spyOn( + DynamicEnvironmentMapManager, + "isDynamicUpdateSupported", + ).and.returnValue(false); + + const manager = new DynamicEnvironmentMapManager(); + + const cartographic = Cartographic.fromDegrees(-75.165222, 39.952583); + manager.position = + Ellipsoid.WGS84.cartographicToCartesian(cartographic); + + const primitive = new EnvironmentMockPrimitive(manager); + scene.primitives.add(primitive); + + scene.renderForSpecs(); + + expect(manager.radianceCubeMap).toBeUndefined(); + + scene.renderForSpecs(); + + expect(manager.sphericalHarmonicCoefficients).toEqual( + DynamicEnvironmentMapManager.DEFAULT_SPHERICAL_HARMONIC_COEFFICIENTS, + ); + }); + it("creates environment map and spherical harmonics at surface in Philadelphia with static lighting", async function () { - if (!scene.highDynamicRangeSupported) { + // Skip if required WebGL extensions are not supported + if (!DynamicEnvironmentMapManager.isDynamicUpdateSupported(scene)) { return; } @@ -146,7 +251,8 @@ describe("Scene/DynamicEnvironmentMapManager", function () { }); it("creates environment map and spherical harmonics at altitude in Philadelphia with static lighting", async function () { - if (!scene.highDynamicRangeSupported) { + // Skip if required WebGL extensions are not supported + if (!DynamicEnvironmentMapManager.isDynamicUpdateSupported(scene)) { return; } @@ -231,7 +337,8 @@ describe("Scene/DynamicEnvironmentMapManager", function () { }); it("creates environment map and spherical harmonics above Earth's atmosphere with static lighting", async function () { - if (!scene.highDynamicRangeSupported) { + // Skip if required WebGL extensions are not supported + if (!DynamicEnvironmentMapManager.isDynamicUpdateSupported(scene)) { return; } @@ -317,7 +424,8 @@ describe("Scene/DynamicEnvironmentMapManager", function () { }); it("creates environment map and spherical harmonics at surface in Philadelphia with dynamic lighting", async function () { - if (!scene.highDynamicRangeSupported) { + // Skip if required WebGL extensions are not supported + if (!DynamicEnvironmentMapManager.isDynamicUpdateSupported(scene)) { return; } @@ -401,7 +509,8 @@ describe("Scene/DynamicEnvironmentMapManager", function () { }); it("creates environment map and spherical harmonics at surface in Sydney with dynamic lighting", async function () { - if (!scene.highDynamicRangeSupported) { + // Skip if required WebGL extensions are not supported + if (!DynamicEnvironmentMapManager.isDynamicUpdateSupported(scene)) { return; } @@ -485,7 +594,8 @@ describe("Scene/DynamicEnvironmentMapManager", function () { }); it("lighting uses atmosphere properties", async function () { - if (!scene.highDynamicRangeSupported) { + // Skip if required WebGL extensions are not supported + if (!DynamicEnvironmentMapManager.isDynamicUpdateSupported(scene)) { return; } @@ -572,10 +682,10 @@ describe("Scene/DynamicEnvironmentMapManager", function () { }); it("lighting uses atmosphereScatteringIntensity value", async function () { - if (!scene.highDynamicRangeSupported) { + // Skip if required WebGL extensions are not supported + if (!DynamicEnvironmentMapManager.isDynamicUpdateSupported(scene)) { return; } - const manager = new DynamicEnvironmentMapManager(); manager.atmosphereScatteringIntensity = 1.0; @@ -654,7 +764,8 @@ describe("Scene/DynamicEnvironmentMapManager", function () { }); it("lighting uses gamma value", async function () { - if (!scene.highDynamicRangeSupported) { + // Skip if required WebGL extensions are not supported + if (!DynamicEnvironmentMapManager.isDynamicUpdateSupported(scene)) { return; } @@ -736,7 +847,8 @@ describe("Scene/DynamicEnvironmentMapManager", function () { }); it("lighting uses brightness value", async function () { - if (!scene.highDynamicRangeSupported) { + // Skip if required WebGL extensions are not supported + if (!DynamicEnvironmentMapManager.isDynamicUpdateSupported(scene)) { return; } @@ -818,7 +930,8 @@ describe("Scene/DynamicEnvironmentMapManager", function () { }); it("lighting uses saturation value", async function () { - if (!scene.highDynamicRangeSupported) { + // Skip if required WebGL extensions are not supported + if (!DynamicEnvironmentMapManager.isDynamicUpdateSupported(scene)) { return; } @@ -900,7 +1013,8 @@ describe("Scene/DynamicEnvironmentMapManager", function () { }); it("lighting uses ground color value", async function () { - if (!scene.highDynamicRangeSupported) { + // Skip if required WebGL extensions are not supported + if (!DynamicEnvironmentMapManager.isDynamicUpdateSupported(scene)) { return; } @@ -982,7 +1096,8 @@ describe("Scene/DynamicEnvironmentMapManager", function () { }); it("lighting uses ground albedo value", async function () { - if (!scene.highDynamicRangeSupported) { + // Skip if required WebGL extensions are not supported + if (!DynamicEnvironmentMapManager.isDynamicUpdateSupported(scene)) { return; } @@ -1064,18 +1179,6 @@ describe("Scene/DynamicEnvironmentMapManager", function () { }); it("destroys", function () { - if (!scene.highDynamicRangeSupported) { - const manager = new DynamicEnvironmentMapManager(); - const cartographic = Cartographic.fromDegrees(-75.165222, 39.952583); - manager.position = - Ellipsoid.WGS84.cartographicToCartesian(cartographic); - - manager.destroy(); - - expect(manager.isDestroyed()).toBe(true); - return; - } - const manager = new DynamicEnvironmentMapManager(); const cartographic = Cartographic.fromDegrees(-75.165222, 39.952583); manager.position = diff --git a/packages/engine/Specs/Scene/ITwinDataSpec.js b/packages/engine/Specs/Scene/ITwinDataSpec.js new file mode 100644 index 000000000000..8eb4322c5778 --- /dev/null +++ b/packages/engine/Specs/Scene/ITwinDataSpec.js @@ -0,0 +1,224 @@ +import { + ITwinPlatform, + RuntimeError, + Cesium3DTileset, + ITwinData, +} from "../../index.js"; + +function createMockExport( + id, + status, + exportType = ITwinPlatform.ExportType["3DTILES"], +) { + return { + id: `${id}`, + displayName: `export ${id}`, + status: status, + lastModified: "2024-11-04T12:00Z", + request: { + iModelId: "imodel-id-1", + changesetId: "changeset-id", + exportType, + }, + _links: { + mesh: { + // The API returns some important query params for auth that we + // need to make sure are preserved when the path is modified + href: `https://example.com/link/to/mesh/${id}?query=param`, + }, + }, + }; +} + +describe("ITwinData", () => { + let previousAccessToken; + beforeEach(() => { + previousAccessToken = ITwinPlatform.defaultAccessToken; + ITwinPlatform.defaultAccessToken = "default-access-token"; + }); + + afterEach(() => { + ITwinPlatform.defaultAccessToken = previousAccessToken; + }); + + describe("createTilesetFromIModelId", () => { + it("rejects when all exports are invalid", async () => { + spyOn(ITwinPlatform, "getExports").and.resolveTo({ + exports: [ + createMockExport(1, ITwinPlatform.ExportStatus.Invalid), + createMockExport(2, ITwinPlatform.ExportStatus.Invalid), + createMockExport(3, ITwinPlatform.ExportStatus.Invalid), + createMockExport(4, ITwinPlatform.ExportStatus.Invalid), + createMockExport(5, ITwinPlatform.ExportStatus.Invalid), + ], + }); + await expectAsync( + ITwinData.createTilesetFromIModelId("imodel-id-1"), + ).toBeRejectedWithError(RuntimeError, /All exports for this iModel/); + }); + + it("returns undefined when no exports returned", async () => { + spyOn(ITwinPlatform, "getExports").and.resolveTo({ + exports: [], + }); + const tileset = await ITwinData.createTilesetFromIModelId("imodel-id-1"); + expect(tileset).toBeUndefined(); + }); + + it("returns undefined when no exports are complete", async () => { + spyOn(ITwinPlatform, "getExports").and.resolveTo({ + exports: [ + createMockExport(1, ITwinPlatform.ExportStatus.InProgress), + createMockExport(2, ITwinPlatform.ExportStatus.NotStarted), + ], + }); + const tileset = await ITwinData.createTilesetFromIModelId("imodel-id-1"); + expect(tileset).toBeUndefined(); + }); + + it("returns undefined when no exports are complete", async () => { + spyOn(ITwinPlatform, "getExports").and.resolveTo({ + exports: [ + createMockExport(1, ITwinPlatform.ExportStatus.InProgress), + createMockExport(2, ITwinPlatform.ExportStatus.NotStarted), + ], + }); + const tileset = await ITwinData.createTilesetFromIModelId("imodel-id-1"); + expect(tileset).toBeUndefined(); + }); + + it("creates a tileset for the first complete export", async () => { + spyOn(ITwinPlatform, "getExports").and.resolveTo({ + exports: [ + createMockExport(1, ITwinPlatform.ExportStatus.Invalid), + createMockExport(2, ITwinPlatform.ExportStatus.Complete), + ], + }); + const tilesetSpy = spyOn(Cesium3DTileset, "fromUrl"); + await ITwinData.createTilesetFromIModelId("imodel-id-1"); + expect(tilesetSpy).toHaveBeenCalledTimes(1); + // Check that the resource url created is for the second export because + // the first is invalid + expect(tilesetSpy.calls.mostRecent().args[0].toString()).toEqual( + "https://example.com/link/to/mesh/2/tileset.json?query=param", + ); + expect(tilesetSpy.calls.mostRecent().args[1]).toBeUndefined(); + }); + + it("passes tileset options through to the tileset constructor", async () => { + spyOn(ITwinPlatform, "getExports").and.resolveTo({ + exports: [createMockExport(1, ITwinPlatform.ExportStatus.Complete)], + }); + const tilesetSpy = spyOn(Cesium3DTileset, "fromUrl"); + const tilesetOptions = { show: false }; + await ITwinData.createTilesetFromIModelId("imodel-id-1", tilesetOptions); + expect(tilesetSpy).toHaveBeenCalledTimes(1); + expect(tilesetSpy.calls.mostRecent().args[1]).toEqual(tilesetOptions); + }); + }); + + describe("createTilesetForRealityDataId", () => { + let getMetadataSpy; + let getUrlSpy; + let tilesetSpy; + beforeEach(() => { + getMetadataSpy = spyOn(ITwinPlatform, "getRealityDataMetadata"); + getUrlSpy = spyOn(ITwinPlatform, "getRealityDataURL"); + tilesetSpy = spyOn(Cesium3DTileset, "fromUrl"); + }); + + it("rejects if the type is not supported", async () => { + await expectAsync( + ITwinData.createTilesetForRealityDataId( + "imodel-id-1", + "reality-data-id-1", + ITwinPlatform.RealityDataType.DGN, + "root/path.json", + ), + ).toBeRejectedWithError(RuntimeError, /type is not/); + }); + + it("does not fetch metadata if type and rootDocument are defined", async () => { + await ITwinData.createTilesetForRealityDataId( + "itwin-id-1", + "reality-data-id-1", + ITwinPlatform.RealityDataType.Cesium3DTiles, + "root/document/path.json", + ); + + expect(getMetadataSpy).not.toHaveBeenCalled(); + expect(getUrlSpy).toHaveBeenCalledOnceWith( + "itwin-id-1", + "reality-data-id-1", + "root/document/path.json", + ); + }); + + it("fetches metadata if type is undefined", async () => { + getMetadataSpy.and.resolveTo({ + iModelId: "itwin-id-1", + id: "reality-data-id-1", + type: ITwinPlatform.RealityDataType.Cesium3DTiles, + rootDocument: "root/document/path.json", + }); + await ITwinData.createTilesetForRealityDataId( + "itwin-id-1", + "reality-data-id-1", + undefined, + "root/document/path.json", + ); + + expect(getMetadataSpy).toHaveBeenCalledOnceWith( + "itwin-id-1", + "reality-data-id-1", + ); + expect(getUrlSpy).toHaveBeenCalledOnceWith( + "itwin-id-1", + "reality-data-id-1", + "root/document/path.json", + ); + }); + + it("fetches metadata if rootDocument is undefined", async () => { + getMetadataSpy.and.resolveTo({ + iModelId: "itwin-id-1", + id: "reality-data-id-1", + type: ITwinPlatform.RealityDataType.Cesium3DTiles, + rootDocument: "root/document/path.json", + }); + await ITwinData.createTilesetForRealityDataId( + "itwin-id-1", + "reality-data-id-1", + ITwinPlatform.RealityDataType.Cesium3DTiles, + undefined, + ); + + expect(getMetadataSpy).toHaveBeenCalledOnceWith( + "itwin-id-1", + "reality-data-id-1", + ); + expect(getUrlSpy).toHaveBeenCalledOnceWith( + "itwin-id-1", + "reality-data-id-1", + "root/document/path.json", + ); + }); + + it("creates a tileset from the constructed blob url", async () => { + const tilesetUrl = + "https://example.com/root/document/path.json?auth=token"; + getUrlSpy.and.resolveTo(tilesetUrl); + + await ITwinData.createTilesetForRealityDataId( + "itwin-id-1", + "reality-data-id-1", + ITwinPlatform.RealityDataType.Cesium3DTiles, + "root/document/path.json", + ); + + expect(tilesetSpy).toHaveBeenCalledOnceWith(tilesetUrl, { + maximumScreenSpaceError: 4, + }); + }); + }); +}); diff --git a/packages/engine/Specs/Scene/LabelCollectionSpec.js b/packages/engine/Specs/Scene/LabelCollectionSpec.js index 3f163690e81e..68c7d7dbf6dd 100644 --- a/packages/engine/Specs/Scene/LabelCollectionSpec.js +++ b/packages/engine/Specs/Scene/LabelCollectionSpec.js @@ -2560,6 +2560,84 @@ describe( }); }); + it("filterUnsupportedCharacters removes unicode characters from text only if they cause render issues", function () { + const text = "a😀b"; + const expectedText = "a😀b"; + expect(Label.filterUnsupportedCharacters(text)).toEqual(expectedText); + }); + + it("filterUnsupportedCharacters removes unicode characters from text only if they cause render issues", function () { + const text = "awe2!$34f❤️b"; + const expectedText = "awe2!$34f❤️b"; + expect(Label.filterUnsupportedCharacters(text)).toEqual(expectedText); + }); + + it("filterUnsupportedCharacters removes unicode characters from text only if they cause render issues", function () { + const text = "lakneklf\u200fsldknfklf"; + const expectedText = "lakneklfsldknfklf"; + expect(Label.filterUnsupportedCharacters(text)).toEqual(expectedText); + }); + + it("filterUnsupportedCharacters removes unicode characters from text only if they cause render issues", function () { + const text = "test \u200f - with Right-to-Left Mark (RLM)"; + const expectedText = "test - with Right-to-Left Mark (RLM)"; + expect(Label.filterUnsupportedCharacters(text)).toEqual(expectedText); + }); + + it("filterUnsupportedCharacters removes unicode characters from text only if they cause render issues", function () { + const text = "test \u200b - with Zero-Width Space"; + const expectedText = "test - with Zero-Width Space"; + expect(Label.filterUnsupportedCharacters(text)).toEqual(expectedText); + }); + + it("filterUnsupportedCharacters removes unicode characters from text only if they cause render issues", function () { + const text = "test \u202a - with Left-to-Right Embedding"; + const expectedText = "test - with Left-to-Right Embedding"; + expect(Label.filterUnsupportedCharacters(text)).toEqual(expectedText); + }); + + it("filterUnsupportedCharacters removes unicode characters from text only if they cause render issues", function () { + const text = "test 😀 - Emoji"; + const expectedText = "test 😀 - Emoji"; + expect(Label.filterUnsupportedCharacters(text)).toEqual(expectedText); + }); + + it("filterUnsupportedCharacters removes unicode characters from text only if they cause render issues", function () { + const text = "test ❤️ - Emoji"; + const expectedText = "test ❤️ - Emoji"; + expect(Label.filterUnsupportedCharacters(text)).toEqual(expectedText); + }); + + it("filterUnsupportedCharacters removes unicode characters from text only if they cause render issues", function () { + const text = "test 🌍 - Emoji"; + const expectedText = "test 🌍 - Emoji"; + expect(Label.filterUnsupportedCharacters(text)).toEqual(expectedText); + }); + + it("filterUnsupportedCharacters removes unicode characters from text only if they cause render issues", function () { + const text = "test \u2060 - with Word Joiner"; + const expectedText = "test - with Word Joiner"; + expect(Label.filterUnsupportedCharacters(text)).toEqual(expectedText); + }); + + it("filterUnsupportedCharacters removes unicode characters from text only if they cause render issues", function () { + const text = "test \u0000 - with Null Character"; + const expectedText = "test - with Null Character"; + expect(Label.filterUnsupportedCharacters(text)).toEqual(expectedText); + }); + + it("filterUnsupportedCharacters removes unicode characters from text only if they cause render issues", function () { + const text = "test \u000E - with Shift Out (SO)"; + const expectedText = "test - with Shift Out (SO)"; + expect(Label.filterUnsupportedCharacters(text)).toEqual(expectedText); + }); + + it("filterUnsupportedCharacters removes unicode characters from text only if they cause render issues", function () { + const text = "test \u001F - with Unit Separator (US)"; + const expectedText = "test - with Unit Separator (US)"; + expect(Label.filterUnsupportedCharacters(text)).toEqual(expectedText); + }); + describe("height referenced labels", function () { beforeEach(function () { scene.globe = new Globe(); diff --git a/packages/engine/Specs/Scene/MetadataPickingSpec.js b/packages/engine/Specs/Scene/MetadataPickingSpec.js new file mode 100644 index 000000000000..5f1cb8bd5a72 --- /dev/null +++ b/packages/engine/Specs/Scene/MetadataPickingSpec.js @@ -0,0 +1,1492 @@ +import { + Cartesian2, + Cartesian3, + Cartesian4, + Matrix2, + Matrix3, + Matrix4, + MetadataComponentType, + MetadataPicking, + MetadataType, +} from "../../index.js"; + +// The precision for Jasmine `toBeCloseTo` calls. Note that this +// is not an "epsilon", but described as "The number of decimal +// points to check" ... +const precision = 3; + +describe("Scene/MetadataPicking", function () { + describe("decodeRawMetadataValue", function () { + it("throws for invalid component type", function () { + expect(function () { + const componentType = "NOT_A_COMPONENT_TYPE"; + const array = new Uint8Array([12, 23]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const index = 0; + MetadataPicking.decodeRawMetadataValue(componentType, dataView, index); + }).toThrowError(); + }); + + it("throws for invalid index", function () { + expect(function () { + const componentType = MetadataComponentType.INT8; + const array = new Uint8Array([12, 23]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const index = 1234; + MetadataPicking.decodeRawMetadataValue(componentType, dataView, index); + }).toThrowError(); + }); + + it("decodes raw value with component type INT8", function () { + const array = new Int8Array([12, 23]); + const componentType = MetadataComponentType.INT8; + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const index = 1; + const value = MetadataPicking.decodeRawMetadataValue( + componentType, + dataView, + index, + ); + expect(value).toBe(23); + }); + + it("decodes raw value with component type UINT8", function () { + const array = new Uint8Array([12, 23]); + const componentType = MetadataComponentType.UINT8; + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const index = 1; + const value = MetadataPicking.decodeRawMetadataValue( + componentType, + dataView, + index, + ); + expect(value).toBe(23); + }); + + it("decodes raw value with component type INT16", function () { + const array = new Int16Array([1234, 2345]); + const componentType = MetadataComponentType.INT16; + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const index = 2; + const value = MetadataPicking.decodeRawMetadataValue( + componentType, + dataView, + index, + ); + expect(value).toBe(2345); + }); + + it("decodes raw value with component type UINT16", function () { + const array = new Uint16Array([1234, 2345]); + const componentType = MetadataComponentType.UINT16; + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const index = 2; + const value = MetadataPicking.decodeRawMetadataValue( + componentType, + dataView, + index, + ); + expect(value).toBe(2345); + }); + + it("decodes raw value with component type INT32", function () { + const array = new Int32Array([123456, 234567]); + const componentType = MetadataComponentType.INT32; + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const index = 4; + const value = MetadataPicking.decodeRawMetadataValue( + componentType, + dataView, + index, + ); + expect(value).toBe(234567); + }); + + it("decodes raw value with component type UINT32", function () { + const array = new Uint32Array([123456, 234567]); + const componentType = MetadataComponentType.UINT32; + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const index = 4; + const value = MetadataPicking.decodeRawMetadataValue( + componentType, + dataView, + index, + ); + expect(value).toBe(234567); + }); + + it("decodes raw value with component type INT64", function () { + const array = new BigInt64Array([12345678900n, 23456789000n]); + const componentType = MetadataComponentType.INT64; + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const index = 8; + const value = MetadataPicking.decodeRawMetadataValue( + componentType, + dataView, + index, + ); + expect(value).toBe(23456789000n); + }); + + it("decodes raw value with component type UINT64", function () { + const array = new BigUint64Array([12345678900n, 23456789000n]); + const componentType = MetadataComponentType.UINT64; + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const index = 8; + const value = MetadataPicking.decodeRawMetadataValue( + componentType, + dataView, + index, + ); + expect(value).toBe(23456789000n); + }); + + it("decodes raw value with component type FLOAT32", function () { + const array = new Float32Array([1.23, 2.34]); + const componentType = MetadataComponentType.FLOAT32; + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const index = 4; + const value = MetadataPicking.decodeRawMetadataValue( + componentType, + dataView, + index, + ); + expect(value).toBeCloseTo(2.34, precision); + }); + + it("decodes raw value with component type FLOAT64", function () { + const array = new Float64Array([1.23, 2.34]); + const componentType = MetadataComponentType.FLOAT64; + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const index = 8; + const value = MetadataPicking.decodeRawMetadataValue( + componentType, + dataView, + index, + ); + expect(value).toBeCloseTo(2.34, precision); + }); + }); + + describe("decodeRawMetadataValueComponent", function () { + it("throws for invalid component type", function () { + expect(function () { + const classProperty = { + componentType: "NOT_A_COMPONENT_TYPE", + normalized: false, + }; + const array = new Uint8Array([12, 23]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const dataViewOffset = 0; + MetadataPicking.decodeRawMetadataValueComponent( + classProperty, + dataView, + dataViewOffset, + ); + }).toThrowError(); + }); + + it("throws for invalid offset", function () { + expect(function () { + const classProperty = { + componentType: MetadataComponentType.INT8, + normalized: false, + }; + const array = new Uint8Array([12, 23]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const dataViewOffset = 1234; + MetadataPicking.decodeRawMetadataValueComponent( + classProperty, + dataView, + dataViewOffset, + ); + }).toThrowError(); + }); + + it("decodes component with componentType INT8", function () { + const classProperty = { + componentType: MetadataComponentType.INT8, + normalized: false, + }; + const array = new Uint8Array([12, 23]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const dataViewOffset = 1; + const value = MetadataPicking.decodeRawMetadataValueComponent( + classProperty, + dataView, + dataViewOffset, + ); + expect(value).toBe(23); + }); + + it("decodes component with componentType normalized INT8", function () { + const classProperty = { + componentType: MetadataComponentType.INT8, + normalized: true, + }; + const array = new Uint8Array([12, 23]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const dataViewOffset = 1; + const value = MetadataPicking.decodeRawMetadataValueComponent( + classProperty, + dataView, + dataViewOffset, + ); + expect(value).toBeCloseTo(23 / 127.0, precision); + }); + + it("decodes component with componentType UINT8", function () { + const classProperty = { + componentType: MetadataComponentType.UINT8, + normalized: false, + }; + const array = new Uint8Array([12, 23]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const dataViewOffset = 1; + const value = MetadataPicking.decodeRawMetadataValueComponent( + classProperty, + dataView, + dataViewOffset, + ); + expect(value).toBe(23); + }); + + it("decodes component with componentType normalized UINT8", function () { + const classProperty = { + componentType: MetadataComponentType.UINT8, + normalized: true, + }; + const array = new Uint8Array([12, 23]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const dataViewOffset = 1; + const value = MetadataPicking.decodeRawMetadataValueComponent( + classProperty, + dataView, + dataViewOffset, + ); + expect(value).toBeCloseTo(23 / 255.0, precision); + }); + + it("decodes component with componentType INT16", function () { + const classProperty = { + componentType: MetadataComponentType.INT16, + normalized: false, + }; + const array = new Int16Array([1234, 2345]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const dataViewOffset = 2; + const value = MetadataPicking.decodeRawMetadataValueComponent( + classProperty, + dataView, + dataViewOffset, + ); + expect(value).toBe(2345); + }); + + it("decodes component with componentType normalized INT16", function () { + const classProperty = { + componentType: MetadataComponentType.INT16, + normalized: true, + }; + const array = new Int16Array([1234, 2345]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const dataViewOffset = 2; + const value = MetadataPicking.decodeRawMetadataValueComponent( + classProperty, + dataView, + dataViewOffset, + ); + expect(value).toBeCloseTo(2345 / 32767.0, precision); + }); + + it("decodes component with componentType UINT16", function () { + const classProperty = { + componentType: MetadataComponentType.UINT16, + normalized: false, + }; + const array = new Uint16Array([1234, 2345]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const dataViewOffset = 2; + const value = MetadataPicking.decodeRawMetadataValueComponent( + classProperty, + dataView, + dataViewOffset, + ); + expect(value).toBe(2345); + }); + + it("decodes component with componentType normalized UINT16", function () { + const classProperty = { + componentType: MetadataComponentType.UINT16, + normalized: true, + }; + const array = new Uint16Array([1234, 2345]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const dataViewOffset = 2; + const value = MetadataPicking.decodeRawMetadataValueComponent( + classProperty, + dataView, + dataViewOffset, + ); + expect(value).toBeCloseTo(2345 / 65535.0, precision); + }); + + it("decodes component with componentType INT32", function () { + const classProperty = { + componentType: MetadataComponentType.INT32, + normalized: false, + }; + const array = new Int32Array([123456, 234567]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const dataViewOffset = 4; + const value = MetadataPicking.decodeRawMetadataValueComponent( + classProperty, + dataView, + dataViewOffset, + ); + expect(value).toBe(234567); + }); + + it("decodes component with componentType normalized INT32", function () { + const classProperty = { + componentType: MetadataComponentType.INT32, + normalized: true, + }; + const array = new Int32Array([123456, 234567]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const dataViewOffset = 4; + const value = MetadataPicking.decodeRawMetadataValueComponent( + classProperty, + dataView, + dataViewOffset, + ); + expect(value).toBeCloseTo(234567 / 2147483647.0, precision); + }); + + it("decodes component with componentType UINT32", function () { + const classProperty = { + componentType: MetadataComponentType.UINT32, + normalized: false, + }; + const array = new Uint32Array([123456, 234567]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const dataViewOffset = 4; + const value = MetadataPicking.decodeRawMetadataValueComponent( + classProperty, + dataView, + dataViewOffset, + ); + expect(value).toBe(234567); + }); + + it("decodes component with componentType normalized UINT32", function () { + const classProperty = { + componentType: MetadataComponentType.UINT32, + normalized: true, + }; + const array = new Uint32Array([123456, 234567]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const dataViewOffset = 4; + const value = MetadataPicking.decodeRawMetadataValueComponent( + classProperty, + dataView, + dataViewOffset, + ); + expect(value).toBeCloseTo(234567 / 4294967295.0, precision); + }); + + it("decodes component with componentType INT64", function () { + const classProperty = { + componentType: MetadataComponentType.INT64, + normalized: false, + }; + const array = new BigInt64Array([12345678900n, 23456789000n]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const dataViewOffset = 8; + const value = MetadataPicking.decodeRawMetadataValueComponent( + classProperty, + dataView, + dataViewOffset, + ); + expect(value).toBe(23456789000n); + }); + + it("decodes component with componentType normalized INT64", function () { + const classProperty = { + componentType: MetadataComponentType.INT64, + normalized: true, + }; + const array = new BigInt64Array([12345678900n, 23456789000n]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const dataViewOffset = 8; + const value = MetadataPicking.decodeRawMetadataValueComponent( + classProperty, + dataView, + dataViewOffset, + ); + expect(Number(value)).toBeCloseTo( + Number(23456789000n / 9223372036854775807n), + precision, + ); + }); + + it("decodes component with componentType UINT64", function () { + const classProperty = { + componentType: MetadataComponentType.UINT64, + normalized: false, + }; + const array = new BigUint64Array([12345678900n, 23456789000n]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const dataViewOffset = 8; + const value = MetadataPicking.decodeRawMetadataValueComponent( + classProperty, + dataView, + dataViewOffset, + ); + expect(value).toBe(23456789000n); + }); + + it("decodes component with componentType normalized UINT64", function () { + const classProperty = { + componentType: MetadataComponentType.UINT64, + normalized: true, + }; + const array = new BigUint64Array([12345678900n, 23456789000n]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const dataViewOffset = 8; + const value = MetadataPicking.decodeRawMetadataValueComponent( + classProperty, + dataView, + dataViewOffset, + ); + expect(Number(value)).toBeCloseTo( + Number(23456789000n / 18446744073709551615n), + precision, + ); + }); + + it("decodes component with componentType FLOAT32", function () { + const classProperty = { + componentType: MetadataComponentType.FLOAT32, + normalized: false, + }; + const array = new Float32Array([1.23, 2.34]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const dataViewOffset = 4; + const value = MetadataPicking.decodeRawMetadataValueComponent( + classProperty, + dataView, + dataViewOffset, + ); + expect(value).toBeCloseTo(2.34, precision); + }); + + it("decodes component with componentType FLOAT64", function () { + const classProperty = { + componentType: MetadataComponentType.FLOAT64, + normalized: false, + }; + const array = new Float64Array([1.23, 2.34]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const dataViewOffset = 8; + const value = MetadataPicking.decodeRawMetadataValueComponent( + classProperty, + dataView, + dataViewOffset, + ); + expect(value).toBeCloseTo(2.34, precision); + }); + }); + + describe("decodeRawMetadataValueElement", function () { + it("throws for invalid component type", function () { + expect(function () { + const classProperty = { + type: "SCALAR", + componentType: "NOT_A_COMPONENT_TYPE", + normalized: false, + }; + const array = new Int8Array([12, 23]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const elementIndex = 0; + MetadataPicking.decodeRawMetadataValueElement( + classProperty, + dataView, + elementIndex, + ); + }).toThrowError(); + }); + + it("throws for invalid element index", function () { + expect(function () { + const classProperty = { + type: "SCALAR", + componentType: MetadataComponentType.INT8, + normalized: false, + }; + const array = new Int8Array([12, 23]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const elementIndex = 1234; + MetadataPicking.decodeRawMetadataValueElement( + classProperty, + dataView, + elementIndex, + ); + }).toThrowError(); + }); + + it("decodes element with type SCALAR and component type INT8", function () { + const classProperty = { + type: MetadataType.SCALAR, + componentType: MetadataComponentType.INT8, + normalized: false, + }; + const array = new Int8Array([0, 1]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const elementIndex = 1; + const value = MetadataPicking.decodeRawMetadataValueElement( + classProperty, + dataView, + elementIndex, + ); + expect(value).toBe(1); + }); + + it("decodes element with type VEC2 and component type INT8", function () { + const classProperty = { + type: MetadataType.VEC2, + componentType: MetadataComponentType.INT8, + normalized: false, + }; + const array = new Int8Array([0, 1, 2, 3]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const elementIndex = 1; + const value = MetadataPicking.decodeRawMetadataValueElement( + classProperty, + dataView, + elementIndex, + ); + expect(value).toEqual([2, 3]); + }); + + it("decodes element with type VEC3 and component type INT8", function () { + const classProperty = { + type: MetadataType.VEC3, + componentType: MetadataComponentType.INT8, + normalized: false, + }; + const array = new Int8Array([0, 1, 2, 3, 4, 5]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const elementIndex = 1; + const value = MetadataPicking.decodeRawMetadataValueElement( + classProperty, + dataView, + elementIndex, + ); + expect(value).toEqual([3, 4, 5]); + }); + + it("decodes element with type VEC4 and component type INT8", function () { + const classProperty = { + type: MetadataType.VEC4, + componentType: MetadataComponentType.INT8, + normalized: false, + }; + const array = new Int8Array([0, 1, 2, 3, 4, 5, 6, 7]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const elementIndex = 1; + const value = MetadataPicking.decodeRawMetadataValueElement( + classProperty, + dataView, + elementIndex, + ); + expect(value).toEqual([4, 5, 6, 7]); + }); + + it("decodes element with type MAT2 and component type INT8", function () { + const classProperty = { + type: MetadataType.MAT2, + componentType: MetadataComponentType.INT8, + normalized: false, + }; + const array = new Int8Array([0, 1, 2, 3, 4, 5, 6, 7]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const elementIndex = 1; + const value = MetadataPicking.decodeRawMetadataValueElement( + classProperty, + dataView, + elementIndex, + ); + expect(value).toEqual([4, 5, 6, 7]); + }); + + it("decodes element with type MAT3 and component type INT8", function () { + const classProperty = { + type: MetadataType.MAT3, + componentType: MetadataComponentType.INT8, + normalized: false, + }; + const array = new Int8Array([ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + ]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const elementIndex = 1; + const value = MetadataPicking.decodeRawMetadataValueElement( + classProperty, + dataView, + elementIndex, + ); + expect(value).toEqual([9, 10, 11, 12, 13, 14, 15, 16, 17]); + }); + + it("decodes element with type MAT4 and component type INT8", function () { + const classProperty = { + type: MetadataType.MAT4, + componentType: MetadataComponentType.INT8, + normalized: false, + }; + const array = new Int8Array([ + 0, 1, 2, 3, 4, 5, 6, 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, + ]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const elementIndex = 1; + const value = MetadataPicking.decodeRawMetadataValueElement( + classProperty, + dataView, + elementIndex, + ); + expect(value).toEqual([ + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + ]); + }); + + it("decodes element with type SCALAR and component type FLOAT32", function () { + const classProperty = { + type: MetadataType.SCALAR, + componentType: MetadataComponentType.FLOAT32, + normalized: false, + }; + const array = new Float32Array([0, 1]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const elementIndex = 1; + const value = MetadataPicking.decodeRawMetadataValueElement( + classProperty, + dataView, + elementIndex, + ); + expect(value).toBe(1); + }); + + it("decodes element with type VEC2 and component type FLOAT32", function () { + const classProperty = { + type: MetadataType.VEC2, + componentType: MetadataComponentType.FLOAT32, + normalized: false, + }; + const array = new Float32Array([0, 1, 2, 3]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const elementIndex = 1; + const value = MetadataPicking.decodeRawMetadataValueElement( + classProperty, + dataView, + elementIndex, + ); + expect(value).toEqual([2, 3]); + }); + + it("decodes element with type VEC3 and component type FLOAT32", function () { + const classProperty = { + type: MetadataType.VEC3, + componentType: MetadataComponentType.FLOAT32, + normalized: false, + }; + const array = new Float32Array([0, 1, 2, 3, 4, 5]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const elementIndex = 1; + const value = MetadataPicking.decodeRawMetadataValueElement( + classProperty, + dataView, + elementIndex, + ); + expect(value).toEqual([3, 4, 5]); + }); + + it("decodes element with type VEC4 and component type FLOAT32", function () { + const classProperty = { + type: MetadataType.VEC4, + componentType: MetadataComponentType.FLOAT32, + normalized: false, + }; + const array = new Float32Array([0, 1, 2, 3, 4, 5, 6, 7]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const elementIndex = 1; + const value = MetadataPicking.decodeRawMetadataValueElement( + classProperty, + dataView, + elementIndex, + ); + expect(value).toEqual([4, 5, 6, 7]); + }); + + it("decodes element with type MAT2 and component type FLOAT32", function () { + const classProperty = { + type: MetadataType.MAT2, + componentType: MetadataComponentType.FLOAT32, + normalized: false, + }; + const array = new Float32Array([0, 1, 2, 3, 4, 5, 6, 7]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const elementIndex = 1; + const value = MetadataPicking.decodeRawMetadataValueElement( + classProperty, + dataView, + elementIndex, + ); + expect(value).toEqual([4, 5, 6, 7]); + }); + + it("decodes element with type MAT3 and component type FLOAT32", function () { + const classProperty = { + type: MetadataType.MAT3, + componentType: MetadataComponentType.FLOAT32, + normalized: false, + }; + const array = new Float32Array([ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + ]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const elementIndex = 1; + const value = MetadataPicking.decodeRawMetadataValueElement( + classProperty, + dataView, + elementIndex, + ); + expect(value).toEqual([9, 10, 11, 12, 13, 14, 15, 16, 17]); + }); + + it("decodes element with type MAT4 and component type FLOAT32", function () { + const classProperty = { + type: MetadataType.MAT4, + componentType: MetadataComponentType.FLOAT32, + normalized: false, + }; + const array = new Float32Array([ + 0, 1, 2, 3, 4, 5, 6, 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, + ]); + const dataView = new DataView( + array.buffer, + array.byteOffset, + array.byteLength, + ); + const elementIndex = 1; + const value = MetadataPicking.decodeRawMetadataValueElement( + classProperty, + dataView, + elementIndex, + ); + expect(value).toEqual([ + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + ]); + }); + }); + + describe("decodeRawMetadataValues", function () { + it("throws for invalid component type", function () { + expect(function () { + const classProperty = { + type: "SCALAR", + componentType: "NOT_A_COMPONENT_TYPE", + normalized: false, + }; + const rawPixelValues = new Uint8Array([0, 1, 2, 3]); + MetadataPicking.decodeRawMetadataValues(classProperty, rawPixelValues); + }).toThrowError(); + }); + + it("throws for invalid input length", function () { + expect(function () { + const classProperty = { + type: MetadataType.VEC2, + componentType: MetadataComponentType.UINT8, + normalized: false, + }; + const rawPixelValues = new Uint8Array([0]); + MetadataPicking.decodeRawMetadataValues(classProperty, rawPixelValues); + }).toThrowError(); + }); + + it("decodes raw values with type SCALAR and component type INT8", function () { + const classProperty = { + type: MetadataType.SCALAR, + componentType: MetadataComponentType.INT8, + normalized: false, + }; + const rawPixelValues = new Uint8Array([12, 23, 34, 45]); + const value = MetadataPicking.decodeRawMetadataValues( + classProperty, + rawPixelValues, + ); + expect(value).toEqual(12); + }); + + it("decodes raw values with type VEC2 and component type INT8", function () { + const classProperty = { + type: MetadataType.VEC2, + componentType: MetadataComponentType.INT8, + normalized: false, + }; + const rawPixelValues = new Uint8Array([0, 1, 2, 3]); + const value = MetadataPicking.decodeRawMetadataValues( + classProperty, + rawPixelValues, + ); + expect(value).toEqual([0, 1]); + }); + + it("decodes raw values with type VEC3 and component type INT8", function () { + const classProperty = { + type: MetadataType.VEC3, + componentType: MetadataComponentType.INT8, + normalized: false, + }; + const rawPixelValues = new Uint8Array([0, 1, 2, 3]); + const value = MetadataPicking.decodeRawMetadataValues( + classProperty, + rawPixelValues, + ); + expect(value).toEqual([0, 1, 2]); + }); + + it("decodes raw values with type VEC4 and component type INT8", function () { + const classProperty = { + type: MetadataType.VEC4, + componentType: MetadataComponentType.INT8, + normalized: false, + }; + const rawPixelValues = new Uint8Array([0, 1, 2, 3]); + const value = MetadataPicking.decodeRawMetadataValues( + classProperty, + rawPixelValues, + ); + expect(value).toEqual([0, 1, 2, 3]); + }); + }); + + describe("convertToObjectType", function () { + it("throws for invalid type", function () { + expect(function () { + const type = "NOT_A_TYPE"; + const value = 0; + MetadataPicking.convertToObjectType(type, value); + }).toThrowError(); + }); + + it("returns SCALAR, STRING, BOOLEAN, and ENUM types (and arrays thereof) unmodified", function () { + const value0 = MetadataPicking.convertToObjectType( + MetadataType.SCALAR, + 123, + ); + const value1 = MetadataPicking.convertToObjectType( + MetadataType.STRING, + "Value", + ); + const value2 = MetadataPicking.convertToObjectType( + MetadataType.SCALAR, + true, + ); + const value3 = MetadataPicking.convertToObjectType( + MetadataType.ENUM, + "VALUE", + ); + + expect(value0).toEqual(123); + expect(value1).toEqual("Value"); + expect(value2).toEqual(true); + expect(value3).toEqual("VALUE"); + + const value0a = MetadataPicking.convertToObjectType( + MetadataType.SCALAR, + [123, 234], + ); + const value1a = MetadataPicking.convertToObjectType(MetadataType.STRING, [ + "Value0", + "Value1", + ]); + const value2a = MetadataPicking.convertToObjectType(MetadataType.SCALAR, [ + true, + false, + ]); + const value3a = MetadataPicking.convertToObjectType(MetadataType.ENUM, [ + "VALUE_A", + "VALUE_B", + ]); + + expect(value0a).toEqual([123, 234]); + expect(value1a).toEqual(["Value0", "Value1"]); + expect(value2a).toEqual([true, false]); + expect(value3a).toEqual(["VALUE_A", "VALUE_B"]); + }); + + it("converts array-based VEC2 input into a Cartesian2", function () { + const array = [0, 1]; + const expected = Cartesian2.unpack(array, 0, new Cartesian2()); + const actual = MetadataPicking.convertToObjectType( + MetadataType.VEC2, + array, + ); + expect(actual).toEqual(expected); + }); + + it("converts array-based VEC3 input into a Cartesian3", function () { + const array = [0, 1, 2]; + const expected = Cartesian3.unpack(array, 0, new Cartesian3()); + const actual = MetadataPicking.convertToObjectType( + MetadataType.VEC3, + array, + ); + expect(actual).toEqual(expected); + }); + + it("converts array-based VEC4 input into a Cartesian4", function () { + const array = [0, 1, 2, 3]; + const expected = Cartesian4.unpack(array, 0, new Cartesian4()); + const actual = MetadataPicking.convertToObjectType( + MetadataType.VEC4, + array, + ); + expect(actual).toEqual(expected); + }); + + it("converts array-based MAT2 input into a Matrix2", function () { + const array = [0, 1, 2, 3]; + const expected = Matrix2.unpack(array, 0, new Matrix2()); + const actual = MetadataPicking.convertToObjectType( + MetadataType.MAT2, + array, + ); + expect(actual).toEqual(expected); + }); + + it("converts array-based MAT3 input into a Matrix3", function () { + const array = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + const expected = Matrix3.unpack(array, 0, new Matrix3()); + const actual = MetadataPicking.convertToObjectType( + MetadataType.MAT3, + array, + ); + expect(actual).toEqual(expected); + }); + + it("converts array-based MAT4 input into a Matrix4", function () { + const array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + const expected = Matrix4.unpack(array, 0, new Matrix4()); + const actual = MetadataPicking.convertToObjectType( + MetadataType.MAT4, + array, + ); + expect(actual).toEqual(expected); + }); + }); + + describe("convertFromObjectType", function () { + it("throws for invalid type", function () { + expect(function () { + const type = "NOT_A_TYPE"; + const value = new Cartesian2(); + MetadataPicking.convertFromObjectType(type, value); + }).toThrowError(); + }); + + it("returns SCALAR, STRING, BOOLEAN, and ENUM types (and arrays thereof) unmodified", function () { + const value0 = MetadataPicking.convertFromObjectType( + MetadataType.SCALAR, + 123, + ); + const value1 = MetadataPicking.convertFromObjectType( + MetadataType.STRING, + "Value", + ); + const value2 = MetadataPicking.convertFromObjectType( + MetadataType.SCALAR, + true, + ); + const value3 = MetadataPicking.convertFromObjectType( + MetadataType.ENUM, + "VALUE", + ); + + expect(value0).toEqual(123); + expect(value1).toEqual("Value"); + expect(value2).toEqual(true); + expect(value3).toEqual("VALUE"); + + const value0a = MetadataPicking.convertFromObjectType( + MetadataType.SCALAR, + [123, 234], + ); + const value1a = MetadataPicking.convertFromObjectType( + MetadataType.STRING, + ["Value0", "Value1"], + ); + const value2a = MetadataPicking.convertFromObjectType( + MetadataType.SCALAR, + [true, false], + ); + const value3a = MetadataPicking.convertFromObjectType(MetadataType.ENUM, [ + "VALUE_A", + "VALUE_B", + ]); + + expect(value0a).toEqual([123, 234]); + expect(value1a).toEqual(["Value0", "Value1"]); + expect(value2a).toEqual([true, false]); + expect(value3a).toEqual(["VALUE_A", "VALUE_B"]); + }); + + it("converts Cartesian2 into array-based VEC2", function () { + const expected = [0, 1]; + const value = Cartesian2.unpack(expected, 0, new Cartesian2()); + const actual = MetadataPicking.convertFromObjectType( + MetadataType.VEC2, + value, + ); + expect(actual).toEqual(expected); + }); + + it("converts Cartesian3 into array-based VEC3", function () { + const expected = [0, 1, 2]; + const value = Cartesian3.unpack(expected, 0, new Cartesian3()); + const actual = MetadataPicking.convertFromObjectType( + MetadataType.VEC3, + value, + ); + expect(actual).toEqual(expected); + }); + + it("converts Cartesian4 into array-based VEC4", function () { + const expected = [0, 1, 2, 3]; + const value = Cartesian4.unpack(expected, 0, new Cartesian4()); + const actual = MetadataPicking.convertFromObjectType( + MetadataType.VEC4, + value, + ); + expect(actual).toEqual(expected); + }); + + it("converts Matrix2 into array-based MAT2", function () { + const expected = [0, 1, 2, 3]; + const value = Matrix2.unpack(expected, 0, new Matrix2()); + const actual = MetadataPicking.convertFromObjectType( + MetadataType.MAT2, + value, + ); + expect(actual).toEqual(expected); + }); + + it("converts Matrix3 into array-based MAT3", function () { + const expected = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + const value = Matrix3.unpack(expected, 0, new Matrix3()); + const actual = MetadataPicking.convertFromObjectType( + MetadataType.MAT3, + value, + ); + expect(actual).toEqual(expected); + }); + + it("converts Matrix4 into array-based MAT4", function () { + const expected = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + const value = Matrix4.unpack(expected, 0, new Matrix4()); + const actual = MetadataPicking.convertFromObjectType( + MetadataType.MAT4, + value, + ); + expect(actual).toEqual(expected); + }); + }); + + describe("decodeMetadataValues", function () { + it("throws for invalid type", function () { + expect(function () { + const classProperty = { + type: "NOT_A_TYPE", + componentType: MetadataComponentType.UINT8, + normalized: false, + }; + const metadataProperty = { + hasValueTransform: false, + }; + const rawPixelValues = new Uint8Array([0, 1, 2, 3]); + MetadataPicking.decodeMetadataValues( + classProperty, + metadataProperty, + rawPixelValues, + ); + }).toThrowError(); + }); + + it("decodes values with type SCALAR and component type INT8", function () { + const classProperty = { + type: MetadataType.SCALAR, + componentType: MetadataComponentType.INT8, + normalized: false, + }; + const metadataProperty = { + hasValueTransform: false, + }; + const rawPixelValues = new Uint8Array([12, 23, 34, 45]); + const value = MetadataPicking.decodeMetadataValues( + classProperty, + metadataProperty, + rawPixelValues, + ); + expect(value).toEqual(12); + }); + + it("decodes values with type VEC2 and component type INT8", function () { + const classProperty = { + type: MetadataType.VEC2, + componentType: MetadataComponentType.INT8, + normalized: false, + }; + const metadataProperty = { + hasValueTransform: false, + }; + const rawPixelValues = new Uint8Array([12, 23, 34, 45]); + const value = MetadataPicking.decodeMetadataValues( + classProperty, + metadataProperty, + rawPixelValues, + ); + expect(value).toEqual(new Cartesian2(12, 23)); + }); + + it("decodes values with type VEC3 and component type INT8", function () { + const classProperty = { + type: MetadataType.VEC3, + componentType: MetadataComponentType.INT8, + normalized: false, + }; + const metadataProperty = { + hasValueTransform: false, + }; + const rawPixelValues = new Uint8Array([12, 23, 34, 45]); + const value = MetadataPicking.decodeMetadataValues( + classProperty, + metadataProperty, + rawPixelValues, + ); + expect(value).toEqual(new Cartesian3(12, 23, 34)); + }); + + it("decodes values with type VEC4 and component type INT8", function () { + const classProperty = { + type: MetadataType.VEC4, + componentType: MetadataComponentType.INT8, + normalized: false, + }; + const metadataProperty = { + hasValueTransform: false, + }; + const rawPixelValues = new Uint8Array([12, 23, 34, 45]); + const value = MetadataPicking.decodeMetadataValues( + classProperty, + metadataProperty, + rawPixelValues, + ); + expect(value).toEqual(new Cartesian4(12, 23, 34, 45)); + }); + + it("decodes values with type SCALAR and component type INT8 and offset and scale", function () { + const classProperty = { + type: MetadataType.SCALAR, + componentType: MetadataComponentType.INT8, + normalized: false, + }; + const offset = 100; + const scale = 2; + const metadataProperty = { + hasValueTransform: true, + offset: offset, + scale: scale, + }; + const rawPixelValues = new Uint8Array([12, 23, 34, 45]); + const value = MetadataPicking.decodeMetadataValues( + classProperty, + metadataProperty, + rawPixelValues, + ); + expect(value).toEqual(offset + 12 * scale); + }); + + it("decodes values with type VEC2 and component type INT8 and offset and scale", function () { + const classProperty = { + type: MetadataType.VEC2, + componentType: MetadataComponentType.INT8, + normalized: false, + }; + const offset = new Cartesian2(100, 200); + const scale = new Cartesian2(2, 3); + const metadataProperty = { + hasValueTransform: true, + offset: offset, + scale: scale, + }; + const rawPixelValues = new Uint8Array([12, 23, 34, 45]); + const value = MetadataPicking.decodeMetadataValues( + classProperty, + metadataProperty, + rawPixelValues, + ); + const expected = new Cartesian2( + offset.x + 12 * scale.x, + offset.y + 23 * scale.y, + ); + expect(value).toEqual(expected); + }); + + it("decodes values with type VEC3 and component type INT8 and offset and scale", function () { + const classProperty = { + type: MetadataType.VEC3, + componentType: MetadataComponentType.INT8, + normalized: false, + }; + const offset = new Cartesian3(100, 200, 300); + const scale = new Cartesian3(2, 3, 4); + const metadataProperty = { + hasValueTransform: true, + offset: offset, + scale: scale, + }; + const rawPixelValues = new Uint8Array([12, 23, 34, 45]); + const value = MetadataPicking.decodeMetadataValues( + classProperty, + metadataProperty, + rawPixelValues, + ); + const expected = new Cartesian3( + offset.x + 12 * scale.x, + offset.y + 23 * scale.y, + offset.z + 34 * scale.z, + ); + expect(value).toEqual(expected); + }); + + it("decodes values with type VEC4 and component type INT8 and offset and scale", function () { + const classProperty = { + type: MetadataType.VEC4, + componentType: MetadataComponentType.INT8, + normalized: false, + }; + const offset = new Cartesian4(100, 200, 300, 400); + const scale = new Cartesian4(2, 3, 4, 5); + const metadataProperty = { + hasValueTransform: true, + offset: offset, + scale: scale, + }; + const rawPixelValues = new Uint8Array([12, 23, 34, 45]); + const value = MetadataPicking.decodeMetadataValues( + classProperty, + metadataProperty, + rawPixelValues, + ); + const expected = new Cartesian4( + offset.x + 12 * scale.x, + offset.y + 23 * scale.y, + offset.z + 34 * scale.z, + offset.w + 45 * scale.w, + ); + expect(value).toEqual(expected); + }); + }); +}); diff --git a/packages/engine/Specs/Scene/Model/ModelSpec.js b/packages/engine/Specs/Scene/Model/ModelSpec.js index 2f31aa01b5fa..7af9758fdad9 100644 --- a/packages/engine/Specs/Scene/Model/ModelSpec.js +++ b/packages/engine/Specs/Scene/Model/ModelSpec.js @@ -3113,10 +3113,13 @@ describe( { gltf: boxTexturedGltfUrl, lightColor: Cartesian3.ZERO, - imageBasedLighting: undefined, }, scene, ); + + // ignore any image-based lighting– Test directional light only + model.imageBasedLighting.imageBasedLightingFactor = Cartesian2.ZERO; + verifyRender(model, false); }); @@ -3125,6 +3128,10 @@ describe( { gltf: boxTexturedGltfUrl, imageBasedLighting: undefined }, scene, ); + + // ignore any image-based lighting– Test directional light only + model.imageBasedLighting.imageBasedLightingFactor = Cartesian2.ZERO; + model.lightColor = Cartesian3.ZERO; verifyRender(model, false); @@ -3193,7 +3200,7 @@ describe( it("changing imageBasedLighting works", async function () { const imageBasedLighting = new ImageBasedLighting({ sphericalHarmonicCoefficients: [ - new Cartesian3(0.35449, 0.35449, 0.35449), + new Cartesian3(1.0, 0.0, 0.0), Cartesian3.ZERO, Cartesian3.ZERO, Cartesian3.ZERO, diff --git a/packages/engine/Specs/Scene/Model/ModelStatisticsSpec.js b/packages/engine/Specs/Scene/Model/ModelStatisticsSpec.js index d471effc9773..c83454747c6d 100644 --- a/packages/engine/Specs/Scene/Model/ModelStatisticsSpec.js +++ b/packages/engine/Specs/Scene/Model/ModelStatisticsSpec.js @@ -15,7 +15,7 @@ describe("Scene/Model/ModelStatistics", function () { expect(statistics.propertyTablesByteLength).toBe(0); expect(statistics.batchTexturesByteLength).toBe(0); expect(statistics._bufferIdSet).toEqual({}); - expect(statistics._textureIdSet).toEqual({}); + expect(statistics._textureIdByteLengths).toEqual({}); expect(statistics._batchTextureIdMap).toEqual(emptyMap); }); @@ -27,7 +27,7 @@ describe("Scene/Model/ModelStatistics", function () { statistics.texturesByteLength = 10; statistics.propertyTablesByteLength = 10; statistics._bufferIdSet = { uuid1: true, uuid2: true }; - statistics._textureIdSet = { uuid3: true }; + statistics._textureIdByteLengths = { uuid3: 1234 }; const map = new AssociativeArray(); map.set("uuid", {}); @@ -41,7 +41,7 @@ describe("Scene/Model/ModelStatistics", function () { expect(statistics.propertyTablesByteLength).toBe(0); expect(statistics.batchTexturesByteLength).toBe(0); expect(statistics._bufferIdSet).toEqual({}); - expect(statistics._textureIdSet).toEqual({}); + expect(statistics._textureIdByteLengths).toEqual({}); expect(statistics._batchTextureIdMap).toEqual(emptyMap); }); @@ -78,7 +78,7 @@ describe("Scene/Model/ModelStatistics", function () { expect(statistics.propertyTablesByteLength).toBe(0); expect(statistics.batchTexturesByteLength).toBe(0); expect(statistics._bufferIdSet).toEqual({ uuid: true }); - expect(statistics._textureIdSet).toEqual({}); + expect(statistics._textureIdByteLengths).toEqual({}); expect(statistics._batchTextureIdMap).toEqual(emptyMap); }); @@ -99,7 +99,7 @@ describe("Scene/Model/ModelStatistics", function () { expect(statistics.propertyTablesByteLength).toBe(0); expect(statistics.batchTexturesByteLength).toBe(0); expect(statistics._bufferIdSet).toEqual({ uuid: true }); - expect(statistics._textureIdSet).toEqual({}); + expect(statistics._textureIdByteLengths).toEqual({}); expect(statistics._batchTextureIdMap).toEqual(emptyMap); }); @@ -129,7 +129,7 @@ describe("Scene/Model/ModelStatistics", function () { expect(statistics.propertyTablesByteLength).toBe(0); expect(statistics.batchTexturesByteLength).toBe(0); expect(statistics._bufferIdSet).toEqual({ uuid1: true, uuid2: true }); - expect(statistics._textureIdSet).toEqual({}); + expect(statistics._textureIdByteLengths).toEqual({}); expect(statistics._batchTextureIdMap).toEqual(emptyMap); }); @@ -158,7 +158,7 @@ describe("Scene/Model/ModelStatistics", function () { expect(statistics.propertyTablesByteLength).toBe(0); expect(statistics.batchTexturesByteLength).toBe(0); expect(statistics._bufferIdSet).toEqual({}); - expect(statistics._textureIdSet).toEqual({ uuid: true }); + expect(statistics._textureIdByteLengths).toEqual({ uuid: 10 }); expect(statistics._batchTextureIdMap).toEqual(emptyMap); }); @@ -188,7 +188,7 @@ describe("Scene/Model/ModelStatistics", function () { expect(statistics.propertyTablesByteLength).toBe(0); expect(statistics.batchTexturesByteLength).toBe(0); expect(statistics._bufferIdSet).toEqual({}); - expect(statistics._textureIdSet).toEqual({ uuid1: true, uuid2: true }); + expect(statistics._textureIdByteLengths).toEqual({ uuid1: 2, uuid2: 3 }); expect(statistics._batchTextureIdMap).toEqual(emptyMap); }); @@ -219,7 +219,7 @@ describe("Scene/Model/ModelStatistics", function () { expect(statistics.propertyTablesByteLength).toBe(0); expect(statistics.batchTexturesByteLength).toBe(0); expect(statistics._bufferIdSet).toEqual({}); - expect(statistics._textureIdSet).toEqual({}); + expect(statistics._textureIdByteLengths).toEqual({}); expect(statistics._batchTextureIdMap).toEqual(expectedMap); // Simulate creating a batch texture @@ -265,7 +265,7 @@ describe("Scene/Model/ModelStatistics", function () { expect(statistics.propertyTablesByteLength).toBe(0); expect(statistics.batchTexturesByteLength).toBe(0); expect(statistics._bufferIdSet).toEqual({}); - expect(statistics._textureIdSet).toEqual({}); + expect(statistics._textureIdByteLengths).toEqual({}); expect(statistics._batchTextureIdMap).toEqual(expectedMap); // Simulate creating first batch texture diff --git a/packages/engine/Specs/Scene/Model/PointCloudStylingPipelineStageSpec.js b/packages/engine/Specs/Scene/Model/PointCloudStylingPipelineStageSpec.js index 11cf22014bd7..ae7deeead20b 100644 --- a/packages/engine/Specs/Scene/Model/PointCloudStylingPipelineStageSpec.js +++ b/packages/engine/Specs/Scene/Model/PointCloudStylingPipelineStageSpec.js @@ -314,7 +314,9 @@ describe( "HAS_POINT_CLOUD_SHOW_STYLE", "COMPUTE_POSITION_WC_STYLE", ]); - ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, []); + ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [ + "HAS_POINT_CLOUD_SHOW_STYLE", + ]); ShaderBuilderTester.expectHasVertexUniforms(shaderBuilder, [ "uniform vec4 model_pointCloudParameters;", diff --git a/packages/engine/Specs/Scene/Model/loadAndZoomToModelAsync.js b/packages/engine/Specs/Scene/Model/loadAndZoomToModelAsync.js index e50ab6a8cf5c..514f53df64f5 100644 --- a/packages/engine/Specs/Scene/Model/loadAndZoomToModelAsync.js +++ b/packages/engine/Specs/Scene/Model/loadAndZoomToModelAsync.js @@ -1,28 +1,12 @@ -import { Model, ImageBasedLighting, Cartesian3 } from "../../../index.js"; +import { Model } from "../../../index.js"; import pollToPromise from "../../../../../Specs/pollToPromise.js"; -// A white ambient light with low intensity -const defaultIbl = new ImageBasedLighting({ - sphericalHarmonicCoefficients: [ - new Cartesian3(0.35449, 0.35449, 0.35449), - Cartesian3.ZERO, - Cartesian3.ZERO, - Cartesian3.ZERO, - Cartesian3.ZERO, - Cartesian3.ZERO, - Cartesian3.ZERO, - Cartesian3.ZERO, - Cartesian3.ZERO, - ], -}); - async function loadAndZoomToModelAsync(options, scene) { options = { environmentMapOptions: { enabled: false, // disable other diffuse lighting by default ...options.environmentMapOptions, }, - imageBasedLighting: defaultIbl, ...options, }; diff --git a/packages/engine/Specs/Scene/PostProcessStageLibrarySpec.js b/packages/engine/Specs/Scene/PostProcessStageLibrarySpec.js index 3350a5a2eb54..5b6f4d040389 100644 --- a/packages/engine/Specs/Scene/PostProcessStageLibrarySpec.js +++ b/packages/engine/Specs/Scene/PostProcessStageLibrarySpec.js @@ -392,32 +392,23 @@ describe( expect(ao.uniforms.intensity).toEqual(3.0); expect(ao.uniforms.bias).toEqual(0.1); expect(ao.uniforms.lengthCap).toEqual(0.26); - expect(ao.uniforms.stepSize).toEqual(1.95); - expect(ao.uniforms.frustumLength).toEqual(1000.0); + expect(ao.uniforms.directionCount).toEqual(8); + expect(ao.uniforms.stepCount).toEqual(32); expect(ao.uniforms.randomTexture).not.toBeDefined(); - expect(ao.uniforms.delta).toEqual(1.0); - expect(ao.uniforms.sigma).toEqual(2.0); - expect(ao.uniforms.blurStepSize).toEqual(0.86); ao.uniforms.ambientOcclusionOnly = true; ao.uniforms.intensity = 4.0; ao.uniforms.bias = 0.2; ao.uniforms.lengthCap = 0.3; - ao.uniforms.stepSize = 2.0; - ao.uniforms.frustumLength = 1001.0; - ao.uniforms.delta = 2.0; - ao.uniforms.sigma = 3.0; - ao.uniforms.blurStepSize = 2.0; + ao.uniforms.directionCount = 9; + ao.uniforms.stepCount = 33; expect(ao.uniforms.ambientOcclusionOnly).toEqual(true); expect(ao.uniforms.intensity).toEqual(4.0); expect(ao.uniforms.bias).toEqual(0.2); expect(ao.uniforms.lengthCap).toEqual(0.3); - expect(ao.uniforms.stepSize).toEqual(2.0); - expect(ao.uniforms.frustumLength).toEqual(1001.0); - expect(ao.uniforms.delta).toEqual(2.0); - expect(ao.uniforms.sigma).toEqual(3.0); - expect(ao.uniforms.blurStepSize).toEqual(2.0); + expect(ao.uniforms.directionCount).toEqual(9); + expect(ao.uniforms.stepCount).toEqual(33); }); it("bloom", function () { diff --git a/packages/engine/Specs/Scene/SceneSpec.js b/packages/engine/Specs/Scene/SceneSpec.js index 3fc9c31602aa..7f2d30742baa 100644 --- a/packages/engine/Specs/Scene/SceneSpec.js +++ b/packages/engine/Specs/Scene/SceneSpec.js @@ -271,26 +271,64 @@ function createPropertyTextureGltfScalar() { type: "SCALAR", componentType: "UINT8", }, + }, + }, + }, + }; + const properties = { + example_UINT8_SCALAR: { + index: 0, + texCoord: 0, + channels: [0], + }, + }; + return createPropertyTextureGltf(schema, properties); +} + +/** + * Creates the glTF for the normalized 'scalar' test case + * + * @param {number|undefined} classPropertyOffset The optional offset + * that will be defined in the class property definition + * @param {number|undefined} classPropertyScale The optional scale + * that will be defined in the class property definition + * @param {number|undefined} metadataPropertyOffset The optional offset + * that will be defined in the property texture property definition + * @param {number|undefined} metadataPropertyScale The optional scale + * that will be defined in the property texture property definition + * @returns The glTF + */ +function createPropertyTextureGltfNormalizedScalar( + classPropertyOffset, + classPropertyScale, + metadataPropertyOffset, + metadataPropertyScale, +) { + const schema = { + id: "ExampleSchema", + classes: { + exampleClass: { + name: "Example class", + properties: { example_normalized_UINT8_SCALAR: { name: "Example SCALAR property with normalized UINT8 components", type: "SCALAR", componentType: "UINT8", normalized: true, + offset: classPropertyOffset, + scale: classPropertyScale, }, }, }, }, }; const properties = { - example_UINT8_SCALAR: { - index: 0, - texCoord: 0, - channels: [0], - }, example_normalized_UINT8_SCALAR: { index: 0, texCoord: 0, - channels: [1], + channels: [0], + offset: metadataPropertyOffset, + scale: metadataPropertyScale, }, }; return createPropertyTextureGltf(schema, properties); @@ -329,6 +367,57 @@ function createPropertyTextureGltfScalarArray() { return createPropertyTextureGltf(schema, properties); } +/** + * Creates the glTF for the 'normalized scalar array' test case + * + * @param {number[]|undefined} classPropertyOffset The optional offset + * that will be defined in the class property definition + * @param {number[]|undefined} classPropertyScale The optional scale + * that will be defined in the class property definition + * @param {number[]|undefined} metadataPropertyOffset The optional offset + * that will be defined in the property texture property definition + * @param {number[]|undefined} metadataPropertyScale The optional scale + * that will be defined in the property texture property definition + * @returns The glTF + */ +function createPropertyTextureGltfNormalizedScalarArray( + classPropertyOffset, + classPropertyScale, + metadataPropertyOffset, + metadataPropertyScale, +) { + const schema = { + id: "ExampleSchema", + classes: { + exampleClass: { + name: "Example class", + properties: { + example_fixed_length_normalized_UINT8_SCALAR_array: { + name: "Example fixed-length SCALAR array property with normalized INT8 components", + type: "SCALAR", + componentType: "UINT8", + array: true, + count: 3, + normalized: true, + offset: classPropertyOffset, + scale: classPropertyScale, + }, + }, + }, + }, + }; + const properties = { + example_fixed_length_normalized_UINT8_SCALAR_array: { + index: 0, + texCoord: 0, + channels: [0, 1, 2], + offset: metadataPropertyOffset, + scale: metadataPropertyScale, + }, + }; + return createPropertyTextureGltf(schema, properties); +} + /** * Creates the glTF for the 'vec2' test case * @@ -363,9 +452,22 @@ function createPropertyTextureGltfVec2() { /** * Creates the glTF for the normalized 'vec2' test case * + * @param {number[]|undefined} classPropertyOffset The optional offset + * that will be defined in the class property definition + * @param {number[]|undefined} classPropertyScale The optional scale + * that will be defined in the class property definition + * @param {number[]|undefined} metadataPropertyOffset The optional offset + * that will be defined in the property texture property definition + * @param {number[]|undefined} metadataPropertyScale The optional scale + * that will be defined in the property texture property definition * @returns The glTF */ -function createPropertyTextureGltfNormalizedVec2() { +function createPropertyTextureGltfNormalizedVec2( + classPropertyOffset, + classPropertyScale, + metadataPropertyOffset, + metadataPropertyScale, +) { const schema = { id: "ExampleSchema", classes: { @@ -377,6 +479,8 @@ function createPropertyTextureGltfNormalizedVec2() { type: "VEC2", componentType: "UINT8", normalized: true, + offset: classPropertyOffset, + scale: classPropertyScale, }, }, }, @@ -387,6 +491,8 @@ function createPropertyTextureGltfNormalizedVec2() { index: 0, texCoord: 0, channels: [0, 1], + offset: metadataPropertyOffset, + scale: metadataPropertyScale, }, }; return createPropertyTextureGltf(schema, properties); @@ -3115,7 +3221,16 @@ describe( const schemaId = undefined; const className = "exampleClass"; const propertyName = "example_normalized_UINT8_SCALAR"; - const gltf = createPropertyTextureGltfScalar(); + const classPropertyOffset = undefined; + const classPropertyScale = undefined; + const metadataPropertyOffset = undefined; + const metadataPropertyScale = undefined; + const gltf = createPropertyTextureGltfNormalizedScalar( + classPropertyOffset, + classPropertyScale, + metadataPropertyOffset, + metadataPropertyScale, + ); const canvasSizeX = textureSizeX * canvasScaling; const canvasSizeY = textureSizeY * canvasScaling; @@ -3145,16 +3260,16 @@ describe( schemaId, className, propertyName, - 3, 0, + 1, ); const actualMetadataValue2 = pickMetadataAt( scene, schemaId, className, propertyName, - 6, 0, + 2, ); const expectedMetadataValue0 = 0.0; const expectedMetadataValue1 = 0.5; @@ -3175,6 +3290,165 @@ describe( scene.destroyForSpecs(); }); + it("picks normalized UINT8 SCALAR from a property texture with offset and scale in class property", async function () { + if (webglStub) { + return; + } + const schemaId = undefined; + const className = "exampleClass"; + const propertyName = "example_normalized_UINT8_SCALAR"; + const classPropertyOffset = 100.0; + const classPropertyScale = 2.0; + const metadataPropertyOffset = undefined; + const metadataPropertyScale = undefined; + const gltf = createPropertyTextureGltfNormalizedScalar( + classPropertyOffset, + classPropertyScale, + metadataPropertyOffset, + metadataPropertyScale, + ); + + const canvasSizeX = textureSizeX * canvasScaling; + const canvasSizeY = textureSizeY * canvasScaling; + const scene = createScene({ + canvas: createCanvas(canvasSizeX, canvasSizeY), + contextOptions: { + requestWebgl1: true, + }, + }); + + await loadAsModel(scene, gltf); + fitCameraToUnitSquare(scene.camera); + + scene.initializeFrame(); + scene.render(defaultDate); + + const actualMetadataValue0 = pickMetadataAt( + scene, + schemaId, + className, + propertyName, + 0, + 0, + ); + const actualMetadataValue1 = pickMetadataAt( + scene, + schemaId, + className, + propertyName, + 0, + 1, + ); + const actualMetadataValue2 = pickMetadataAt( + scene, + schemaId, + className, + propertyName, + 0, + 2, + ); + const expectedMetadataValue0 = + classPropertyOffset + classPropertyScale * 0.0; + const expectedMetadataValue1 = + classPropertyOffset + classPropertyScale * 0.5; + const expectedMetadataValue2 = + classPropertyOffset + classPropertyScale * 1.0; + + expect(actualMetadataValue0).toEqualEpsilon( + expectedMetadataValue0, + propertyValueEpsilon, + ); + expect(actualMetadataValue1).toEqualEpsilon( + expectedMetadataValue1, + propertyValueEpsilon, + ); + expect(actualMetadataValue2).toEqualEpsilon( + expectedMetadataValue2, + propertyValueEpsilon, + ); + scene.destroyForSpecs(); + }); + + it("picks normalized UINT8 SCALAR from a property texture with offset and scale in property texture property", async function () { + if (webglStub) { + return; + } + const schemaId = undefined; + const className = "exampleClass"; + const propertyName = "example_normalized_UINT8_SCALAR"; + const classPropertyOffset = 100.0; + const classPropertyScale = 200.0; + // These should override the values from the class property: + const metadataPropertyOffset = 200.0; + const metadataPropertyScale = 3.0; + const gltf = createPropertyTextureGltfNormalizedScalar( + classPropertyOffset, + classPropertyScale, + metadataPropertyOffset, + metadataPropertyScale, + ); + + const canvasSizeX = textureSizeX * canvasScaling; + const canvasSizeY = textureSizeY * canvasScaling; + const scene = createScene({ + canvas: createCanvas(canvasSizeX, canvasSizeY), + contextOptions: { + requestWebgl1: true, + }, + }); + + await loadAsModel(scene, gltf); + fitCameraToUnitSquare(scene.camera); + + scene.initializeFrame(); + scene.render(defaultDate); + + const actualMetadataValue0 = pickMetadataAt( + scene, + schemaId, + className, + propertyName, + 0, + 0, + ); + const actualMetadataValue1 = pickMetadataAt( + scene, + schemaId, + className, + propertyName, + 0, + 1, + ); + const actualMetadataValue2 = pickMetadataAt( + scene, + schemaId, + className, + propertyName, + 0, + 2, + ); + const expectedMetadataValue0 = + metadataPropertyOffset + metadataPropertyScale * 0.0; + const expectedMetadataValue1 = + metadataPropertyOffset + metadataPropertyScale * 0.5; + const expectedMetadataValue2 = + metadataPropertyOffset + metadataPropertyScale * 1.0; + + expect(actualMetadataValue0).toEqualEpsilon( + expectedMetadataValue0, + propertyValueEpsilon, + ); + expect(actualMetadataValue1).toEqualEpsilon( + expectedMetadataValue1, + propertyValueEpsilon, + ); + expect(actualMetadataValue2).toEqualEpsilon( + expectedMetadataValue2, + propertyValueEpsilon, + ); + scene.destroyForSpecs(); + }); + it("picks fixed length UINT8 SCALAR array from a property texture", async function () { if (webglStub) { return; @@ -3242,6 +3516,82 @@ describe( scene.destroyForSpecs(); }); + it("picks fixed length normalized UINT8 SCALAR array from a property texture", async function () { + if (webglStub) { + return; + } + const schemaId = undefined; + const className = "exampleClass"; + const propertyName = "example_fixed_length_normalized_UINT8_SCALAR_array"; + const classPropertyOffset = undefined; + const classPropertyScale = undefined; + const metadataPropertyOffset = undefined; + const metadataPropertyScale = undefined; + const gltf = createPropertyTextureGltfNormalizedScalarArray( + classPropertyOffset, + classPropertyScale, + metadataPropertyOffset, + metadataPropertyScale, + ); + + const canvasSizeX = textureSizeX * canvasScaling; + const canvasSizeY = textureSizeY * canvasScaling; + const scene = createScene({ + canvas: createCanvas(canvasSizeX, canvasSizeY), + contextOptions: { + requestWebgl1: true, + }, + }); + + await loadAsModel(scene, gltf); + fitCameraToUnitSquare(scene.camera); + + scene.initializeFrame(); + scene.render(defaultDate); + + const actualMetadataValue0 = pickMetadataAt( + scene, + schemaId, + className, + propertyName, + 0, + 0, + ); + const actualMetadataValue1 = pickMetadataAt( + scene, + schemaId, + className, + propertyName, + 1, + 1, + ); + const actualMetadataValue2 = pickMetadataAt( + scene, + schemaId, + className, + propertyName, + 2, + 2, + ); + const expectedMetadataValue0 = [0, 0, 0]; + const expectedMetadataValue1 = [0.5, 0, 0.5]; + const expectedMetadataValue2 = [1.0, 0, 1.0]; + + expect(actualMetadataValue0).toEqualEpsilon( + expectedMetadataValue0, + propertyValueEpsilon, + ); + expect(actualMetadataValue1).toEqualEpsilon( + expectedMetadataValue1, + propertyValueEpsilon, + ); + expect(actualMetadataValue2).toEqualEpsilon( + expectedMetadataValue2, + propertyValueEpsilon, + ); + scene.destroyForSpecs(); + }); + it("picks UINT8 VEC2 from a property texture", async function () { if (webglStub) { return; @@ -3318,7 +3668,16 @@ describe( const schemaId = undefined; const className = "exampleClass"; const propertyName = "example_normalized_UINT8_VEC2"; - const gltf = createPropertyTextureGltfNormalizedVec2(); + const classPropertyOffset = undefined; + const classPropertyScale = undefined; + const metadataPropertyOffset = undefined; + const metadataPropertyScale = undefined; + const gltf = createPropertyTextureGltfNormalizedVec2( + classPropertyOffset, + classPropertyScale, + metadataPropertyOffset, + metadataPropertyScale, + ); const canvasSizeX = textureSizeX * canvasScaling; const canvasSizeY = textureSizeY * canvasScaling; @@ -3379,6 +3738,181 @@ describe( scene.destroyForSpecs(); }); + it("picks normalized UINT8 VEC2 from a property texture with offset and scale in class property", async function () { + if (webglStub) { + return; + } + + const schemaId = undefined; + const className = "exampleClass"; + const propertyName = "example_normalized_UINT8_VEC2"; + const classPropertyOffset = [100.0, 200.0]; + const classPropertyScale = [2.0, 3.0]; + const metadataPropertyOffset = undefined; + const metadataPropertyScale = undefined; + const gltf = createPropertyTextureGltfNormalizedVec2( + classPropertyOffset, + classPropertyScale, + metadataPropertyOffset, + metadataPropertyScale, + ); + + const canvasSizeX = textureSizeX * canvasScaling; + const canvasSizeY = textureSizeY * canvasScaling; + const scene = createScene({ + canvas: createCanvas(canvasSizeX, canvasSizeY), + contextOptions: { + requestWebgl1: true, + }, + }); + + await loadAsModel(scene, gltf); + fitCameraToUnitSquare(scene.camera); + + scene.initializeFrame(); + scene.render(defaultDate); + + const actualMetadataValue0 = pickMetadataAt( + scene, + schemaId, + className, + propertyName, + 0, + 0, + ); + const actualMetadataValue1 = pickMetadataAt( + scene, + schemaId, + className, + propertyName, + 1, + 1, + ); + const actualMetadataValue2 = pickMetadataAt( + scene, + schemaId, + className, + propertyName, + 2, + 2, + ); + + const expectedMetadataValue0 = new Cartesian2( + classPropertyOffset[0] + classPropertyScale[0] * 0.0, + classPropertyOffset[1] + classPropertyScale[1] * 0.0, + ); + const expectedMetadataValue1 = new Cartesian2( + classPropertyOffset[0] + classPropertyScale[0] * 0.5, + classPropertyOffset[1] + classPropertyScale[1] * 0.0, + ); + const expectedMetadataValue2 = new Cartesian2( + classPropertyOffset[0] + classPropertyScale[0] * 1.0, + classPropertyOffset[1] + classPropertyScale[1] * 0.0, + ); + + expect(actualMetadataValue0).toEqualEpsilon( + expectedMetadataValue0, + propertyValueEpsilon, + ); + expect(actualMetadataValue1).toEqualEpsilon( + expectedMetadataValue1, + propertyValueEpsilon, + ); + expect(actualMetadataValue2).toEqualEpsilon( + expectedMetadataValue2, + propertyValueEpsilon, + ); + scene.destroyForSpecs(); + }); + + it("picks normalized UINT8 VEC2 from a property texture with offset and scale in property texture property", async function () { + if (webglStub) { + return; + } + + const schemaId = undefined; + const className = "exampleClass"; + const propertyName = "example_normalized_UINT8_VEC2"; + const classPropertyOffset = [100.0, 200.0]; + const classPropertyScale = [2.0, 3.0]; + // These should override the values from the class property: + const metadataPropertyOffset = [300.0, 400.0]; + const metadataPropertyScale = [4.0, 5.0]; + const gltf = createPropertyTextureGltfNormalizedVec2( + classPropertyOffset, + classPropertyScale, + metadataPropertyOffset, + metadataPropertyScale, + ); + + const canvasSizeX = textureSizeX * canvasScaling; + const canvasSizeY = textureSizeY * canvasScaling; + const scene = createScene({ + canvas: createCanvas(canvasSizeX, canvasSizeY), + contextOptions: { + requestWebgl1: true, + }, + }); + + await loadAsModel(scene, gltf); + fitCameraToUnitSquare(scene.camera); + + scene.initializeFrame(); + scene.render(defaultDate); + + const actualMetadataValue0 = pickMetadataAt( + scene, + schemaId, + className, + propertyName, + 0, + 0, + ); + const actualMetadataValue1 = pickMetadataAt( + scene, + schemaId, + className, + propertyName, + 1, + 1, + ); + const actualMetadataValue2 = pickMetadataAt( + scene, + schemaId, + className, + propertyName, + 2, + 2, + ); + + const expectedMetadataValue0 = new Cartesian2( + metadataPropertyOffset[0] + metadataPropertyScale[0] * 0.0, + metadataPropertyOffset[1] + metadataPropertyScale[1] * 0.0, + ); + const expectedMetadataValue1 = new Cartesian2( + metadataPropertyOffset[0] + metadataPropertyScale[0] * 0.5, + metadataPropertyOffset[1] + metadataPropertyScale[1] * 0.0, + ); + const expectedMetadataValue2 = new Cartesian2( + metadataPropertyOffset[0] + metadataPropertyScale[0] * 1.0, + metadataPropertyOffset[1] + metadataPropertyScale[1] * 0.0, + ); + + expect(actualMetadataValue0).toEqualEpsilon( + expectedMetadataValue0, + propertyValueEpsilon, + ); + expect(actualMetadataValue1).toEqualEpsilon( + expectedMetadataValue1, + propertyValueEpsilon, + ); + expect(actualMetadataValue2).toEqualEpsilon( + expectedMetadataValue2, + propertyValueEpsilon, + ); + scene.destroyForSpecs(); + }); + it("picks UINT8 VEC3 from a property texture", async function () { if (webglStub) { return; diff --git a/packages/engine/Specs/Scene/ShadowMapSpec.js b/packages/engine/Specs/Scene/ShadowMapSpec.js index 2a66f528b10d..1b142d13152b 100644 --- a/packages/engine/Specs/Scene/ShadowMapSpec.js +++ b/packages/engine/Specs/Scene/ShadowMapSpec.js @@ -11,7 +11,6 @@ import { HeadingPitchRange, HeadingPitchRoll, HeightmapTerrainData, - ImageBasedLighting, JulianDate, Math as CesiumMath, Matrix4, @@ -282,26 +281,11 @@ describe( } async function loadModel(options) { - // A white ambient light with low intensity - const defaultIbl = new ImageBasedLighting({ - sphericalHarmonicCoefficients: [ - new Cartesian3(0.35449, 0.35449, 0.35449), - Cartesian3.ZERO, - Cartesian3.ZERO, - Cartesian3.ZERO, - Cartesian3.ZERO, - Cartesian3.ZERO, - Cartesian3.ZERO, - Cartesian3.ZERO, - Cartesian3.ZERO, - ], - }); const model = scene.primitives.add( await Model.fromGltfAsync({ environmentMapOptions: { enabled: false, }, - imageBasedLighting: defaultIbl, ...options, }), ); diff --git a/packages/engine/Specs/Scene/SkyBoxSpec.js b/packages/engine/Specs/Scene/SkyBoxSpec.js index 4db7c8702d18..9691fb035594 100644 --- a/packages/engine/Specs/Scene/SkyBoxSpec.js +++ b/packages/engine/Specs/Scene/SkyBoxSpec.js @@ -1,6 +1,7 @@ -import { Resource, SceneMode, SkyBox } from "../../index.js"; +import { defined, Resource, SceneMode, SkyBox } from "../../index.js"; import createScene from "../../../../Specs/createScene.js"; +import pollToPromise from "../../../../Specs/pollToPromise.js"; describe( "Scene/SkyBox", @@ -10,8 +11,6 @@ describe( let loadedImage; beforeAll(function () { - scene = createScene(); - return Resource.fetchImage("./Data/Images/Blue.png").then( function (image) { loadedImage = image; @@ -19,17 +18,15 @@ describe( ); }); - afterAll(function () { - scene.destroyForSpecs(); - }); - beforeEach(function () { + scene = createScene(); scene.mode = SceneMode.SCENE3D; }); afterEach(function () { skyBox = skyBox && skyBox.destroy(); scene.skyBox = undefined; + scene.destroyForSpecs(); }); it("draws a sky box from Images", function () { @@ -355,6 +352,32 @@ describe( return scene.render(); }).toThrowDeveloperError(); }); + + it("defers throwing error when Resources fail to load until next call to update", async () => { + const error = new Error("intentional error for test"); + spyOn(Resource.prototype, "fetchImage").and.rejectWith(error); + + skyBox = new SkyBox({ + sources: { + positiveX: "./Data/Images/Blue.png", + negativeX: "./Data/Images/Blue.png", + positiveY: "./Data/Images/Blue.png", + negativeY: "./Data/Images/Blue.png", + positiveZ: "./Data/Images/Blue.png", + negativeZ: "./Data/Images/Blue.png", + }, + }); + + scene.frameState.passes.render = true; + scene.skyBox = skyBox; + skyBox.update(scene.frameState); + + await pollToPromise(() => defined(skyBox._cubeMap) || skyBox._hasError); + + expect(skyBox._hasError).toBeTrue(); + expect(skyBox._error).toEqual(error); + expect(() => skyBox.update(scene.frameState)).toThrow(error); + }); }, "WebGL", ); diff --git a/packages/engine/package.json b/packages/engine/package.json index acc1c285479d..f95090f5176f 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@cesium/engine", - "version": "12.0.0", + "version": "13.0.0", "description": "CesiumJS is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.", "keywords": [ "3D", diff --git a/packages/widgets/Source/Viewer/Viewer.js b/packages/widgets/Source/Viewer/Viewer.js index 4574ef6aadc7..b00646389215 100644 --- a/packages/widgets/Source/Viewer/Viewer.js +++ b/packages/widgets/Source/Viewer/Viewer.js @@ -18,6 +18,7 @@ import { Math as CesiumMath, Property, ScreenSpaceEventType, + IonGeocoderService, } from "@cesium/engine"; import Animation from "../Animation/Animation.js"; import AnimationViewModel from "../Animation/AnimationViewModel.js"; @@ -280,7 +281,7 @@ function enableVRUI(viewer, enabled) { * @property {boolean} [baseLayerPicker=true] If set to false, the BaseLayerPicker widget will not be created. * @property {boolean} [fullscreenButton=true] If set to false, the FullscreenButton widget will not be created. * @property {boolean} [vrButton=false] If set to true, the VRButton widget will be created. - * @property {boolean|GeocoderService[]} [geocoder=true] If set to false, the Geocoder widget will not be created. + * @property {boolean|IonGeocodeProviderType|GeocoderService[]} [geocoder=IonGeocodeProviderType.DEFAULT] The geocoding service or services to use when searching with the Geocoder widget. If set to false, the Geocoder widget will not be created. * @property {boolean} [homeButton=true] If set to false, the HomeButton widget will not be created. * @property {boolean} [infoBox=true] If set to false, the InfoBox widget will not be created. * @property {boolean} [sceneModePicker=true] If set to false, the SceneModePicker widget will not be created. @@ -295,7 +296,7 @@ function enableVRUI(viewer, enabled) { * @property {ProviderViewModel[]} [imageryProviderViewModels=createDefaultImageryProviderViewModels()] The array of ProviderViewModels to be selectable from the BaseLayerPicker. This value is only valid if `baseLayerPicker` is set to true. * @property {ProviderViewModel} [selectedTerrainProviderViewModel] The view model for the current base terrain layer, if not supplied the first available base layer is used. This value is only valid if `baseLayerPicker` is set to true. * @property {ProviderViewModel[]} [terrainProviderViewModels=createDefaultTerrainProviderViewModels()] The array of ProviderViewModels to be selectable from the BaseLayerPicker. This value is only valid if `baseLayerPicker` is set to true. - * @property {ImageryLayer|false} [baseLayer=ImageryLayer.fromWorldImagery()] The bottommost imagery layer applied to the globe. If set to false, no imagery provider will be added. This value is only valid if `baseLayerPicker` is set to false. + * @property {ImageryLayer|false} [baseLayer=ImageryLayer.fromWorldImagery()] The bottommost imagery layer applied to the globe. If set to false, no imagery provider will be added. This value is only valid if `baseLayerPicker` is set to false. Cannot be used when `globe` is set to false. * @property {Ellipsoid} [ellipsoid = Ellipsoid.default] The default ellipsoid. * @property {TerrainProvider} [terrainProvider=new EllipsoidTerrainProvider()] The terrain provider to use * @property {Terrain} [terrain] A terrain object which handles asynchronous terrain provider. Can only specify if options.terrainProvider is undefined. @@ -402,6 +403,16 @@ function Viewer(container, options) { container = getElement(container); options = defaultValue(options, defaultValue.EMPTY_OBJECT); + //>>includeStart('debug', pragmas.debug); + if ( + options.globe === false && + defined(options.baseLayer) && + options.baseLayer !== false + ) { + throw new DeveloperError("Cannot use baseLayer when globe is disabled."); + } + //>>includeEnd('debug') + const createBaseLayerPicker = (!defined(options.globe) || options.globe !== false) && (!defined(options.baseLayerPicker) || options.baseLayerPicker !== false); @@ -557,7 +568,17 @@ Either specify options.terrainProvider instead or set options.baseLayerPicker to geocoderContainer.className = "cesium-viewer-geocoderContainer"; toolbar.appendChild(geocoderContainer); let geocoderService; - if (defined(options.geocoder) && typeof options.geocoder !== "boolean") { + if (typeof options.geocoder === "string") { + geocoderService = [ + new IonGeocoderService({ + scene, + geocodeProviderType: options.geocoder, + }), + ]; + } else if ( + defined(options.geocoder) && + typeof options.geocoder !== "boolean" + ) { geocoderService = Array.isArray(options.geocoder) ? options.geocoder : [options.geocoder]; diff --git a/packages/widgets/Specs/Viewer/ViewerSpec.js b/packages/widgets/Specs/Viewer/ViewerSpec.js index 49df43f46eb2..822df41c034b 100644 --- a/packages/widgets/Specs/Viewer/ViewerSpec.js +++ b/packages/widgets/Specs/Viewer/ViewerSpec.js @@ -18,6 +18,8 @@ import { ImageryLayerCollection, SceneMode, ShadowMode, + IonGeocodeProviderType, + IonGeocoderService, } from "@cesium/engine"; import { @@ -354,6 +356,19 @@ describe( expect(viewer.geocoder.viewModel._geocoderServices.length).toBe(1); }); + it("constructs geocoder with IonGeocodeProviderType", function () { + viewer = createViewer(container, { + geocoder: IonGeocodeProviderType.GOOGLE, + }); + expect(viewer.geocoder).toBeDefined(); + expect(viewer.geocoder.viewModel._geocoderServices.length).toBe(1); + const geocoderService = viewer.geocoder.viewModel._geocoderServices[0]; + expect(geocoderService).toBeInstanceOf(IonGeocoderService); + expect(geocoderService.geocodeProviderType).toEqual( + IonGeocodeProviderType.GOOGLE, + ); + }); + it("constructs geocoder with geocoder service option", function () { const service = new CartographicGeocoderService(); viewer = createViewer(container, { @@ -542,6 +557,23 @@ describe( ); }); + it("throws when baseLayer is provided with globe: false", function () { + expect(function () { + viewer = createViewer(container, { + globe: false, + baseLayer: new ImageryLayer(testProvider), + }); + }).toThrowDeveloperError(); + }); + + it("does not throw when globe is false and baseLayer is not provided", function () { + expect(function () { + viewer = createViewer(container, { + globe: false, + }); + }).not.toThrowDeveloperError(); + }); + it("can set baseLayer to false when BaseLayerPicker is disabled", function () { viewer = createViewer(container, { baseLayerPicker: false, diff --git a/packages/widgets/package.json b/packages/widgets/package.json index 42736b0c563a..eecf87e2728d 100644 --- a/packages/widgets/package.json +++ b/packages/widgets/package.json @@ -1,6 +1,6 @@ { "name": "@cesium/widgets", - "version": "9.0.0", + "version": "10.0.0", "description": "A widgets library for use with CesiumJS. CesiumJS is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.", "keywords": [ "3D", @@ -28,7 +28,7 @@ "node": ">=14.0.0" }, "dependencies": { - "@cesium/engine": "^12.0.0", + "@cesium/engine": "^13.0.0", "nosleep.js": "^0.12.0" }, "type": "module",