/////////////////////////////////////////////////////////////////////////// // Requires Moduls: // * JsGraph (JsGraph.inc) for FlatEarth or // * JsGraphX3D (JsGraphX3D.inc) for Globe Earth var EarthMap = { Type: 'EarthMap', Radius: 1, FEMode: 0, // 0 -> use Polygon, 1 -> SplineCurve, 2 -> PolygonOnPlane, 3 -> SplineCurveOnPlane SplineTension: 0.5, WaterColor: '#a6c4ea', WaterBorderColor: '#729cd2', WaterBorderWidth: 1, WaterDrawMode: 3, LandColor: '#8cbe5d', // '#72a653', LandBorderColor: '#689a54', LandBorderWidth: 1, LandDrawMode: 3, // fill and border LakeColor: '#a6c4ea', LakeBorderColor: '#72a653', LakeBorderWidth: 1, LakeDrawMode: 3, Trans: null, // JsgMat3 ClipPlane: null, NContourPoints: 96, // globe contour resolution ContinentList: [ { Type: 'Continent', Name: 'America', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, LandList: [ { Type: 'Land', Name: 'NorthAmerica', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 12, 14, 22, 15, 21, 25, 26, 29, 32, 40, 44, 49, 49, 53, 51, 56, 56, 60, 63, 64, 66, 70, 71, 65, 67, 70, 75, 74, 83, 86, 88, 92, 95, 99, 100, 97, 96, 97, 95, 91, 93, 93, 90, 89, 85, 82, 83, 86, 89, 91, 91, 97, 99, 100, 99, 99, 105, 104, 106, 110, 109, 114, 114, 120, 120, 117, 115, 116, 113, 113, 120, 121, 127, 127, 124, 124, 115, 113, 110, 107, 102, 102, 104, 101, 101, 98, 98, 88, 85, 90, 93, 97, 100, 96, 99, 98, 100, 104, 106, 108, 102, 102, 106, 110, 115, 116, 113, 113, 117, 119, 111, 99, 106, 118, 103, 86, 80, 68, 57, 52, 42, 24, 14 ], PolyY: [ 24, 30, 32, 36, 34, 32, 34, 31, 30, 30, 33, 38, 36, 39, 39, 42, 50, 56, 57, 60, 63, 67, 67, 59, 59, 63, 68, 70, 74, 74, 76, 77, 80, 83, 82, 80, 78, 75, 74, 74, 69, 68, 69, 71, 72, 68, 62, 60, 61, 61, 60, 60, 65, 64, 60, 58, 55, 53, 50, 49, 47, 45, 47, 44, 43, 44, 43, 41, 41, 40, 40, 42, 43, 41, 38, 37, 30, 32, 29, 28, 28, 31, 34, 35, 38, 37, 35, 33, 30, 26, 26, 28, 26, 25, 23, 22, 21, 23, 22, 23, 25, 26, 26, 28, 29, 26, 25, 24, 25, 24, 19, 16, 11, 8, 7, 9, 11, 11, 14, 20, 21, 19, 21 ], ClosePath: true, LakeList: [ { Type: 'Lake', PolyX: [ 88, 92, 94, 96, 93, 92 ], PolyY: [ 43, 41, 41, 43, 44, 43 ], ClosePath: true, }, { Type: 'Lake', PolyX: [ 92, 92, 93, 99, 100, 98, 97, 97, 95, 94, 94, 93 ], PolyY: [ 48, 46, 44, 44, 45, 47, 46, 45, 44, 45, 48, 49 ], ClosePath: true, }, ], // end LakeList }, // end Land { Type: 'Land', Name: 'Greenland', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 107, 112, 120, 123, 125, 126, 126, 129, 132, 135, 137, 138, 140, 144, 148, 155, 158, 158, 160, 162, 161, 163, 167, 167, 162, 161, 157, 157, 145, 127, 119, 118, 115, 112, 115, 114, 110 ], PolyY: [ 12, 14, 14, 16, 20, 22, 24, 27, 29, 30, 30, 27, 25, 24, 22, 21, 20, 17, 16, 14, 11, 9, 9, 8, 8, 9, 9, 7, 6, 8, 8, 9, 9, 10, 10, 11, 11 ], ClosePath: true, LakeList: [ ], // end LakeList }, // end Land { Type: 'Land', Name: 'Cuba', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 95, 99, 103, 106, 100, 97 ], PolyY: [ 68, 68, 70, 70, 67, 67 ], ClosePath: true, LakeList: [], }, // end Land { Type: 'Land', Name: 'DominicanRepublic', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 106, 111, 112, 109, 107, 107 ], PolyY: [ 72, 72, 71, 70, 70, 71 ], ClosePath: true, LakeList: [], }, // end Land { Type: 'Land', Name: 'SouthAmerica', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 100, 102, 103, 99, 99, 101, 104, 110, 109, 108, 106, 105, 105, 106, 109, 112, 115, 113, 111, 114, 114, 113, 115, 115, 118, 118, 122, 123, 123, 124, 125, 128, 132, 132, 135, 138, 140, 141, 141, 145, 145, 144, 143, 140, 136, 132, 131, 129, 125, 123, 119, 116, 112, 110, 108, 105, 103, 102, 100, 99 ], PolyY: [ 81, 82, 85, 91, 96, 98, 105, 108, 118, 125, 129, 136, 140, 143, 145, 146, 145, 144, 141, 138, 137, 136, 134, 131, 131, 129, 128, 127, 126, 125, 125, 123, 117, 115, 113, 113, 109, 106, 103, 99, 96, 95, 95, 93, 92, 90, 87, 85, 84, 84, 80, 79, 79, 78, 78, 79, 82, 81, 80, 81 ], ClosePath: true, LakeList: [ ], // end LakeList }, // end Land { Type: 'Land', Name: 'Falkland', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 119, 122, 122, 120 ], PolyY: [ 142, 142, 141, 141 ], ClosePath: true, LakeList: [ ], // end LakeList }, // end Land ], // end LandList }, // end Continent { Type: 'Continent', Name: 'Africa', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, LandList: [ { Type: 'Land', Name: 'Africa', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 163, 172, 175, 179, 182, 185, 186, 189, 190, 189, 192, 192, 193, 193, 194, 194, 192, 192, 194, 195, 195, 198, 198, 200, 202, 207, 210, 213, 213, 216, 215, 217, 219, 221, 221, 219, 219, 224, 227, 231, 231, 224, 223, 219, 219, 217, 217, 216, 214, 212, 212, 210, 209, 203, 201, 200, 200, 199, 196, 195, 191, 191, 183, 178, 175, 174, 173, 171, 170, 170, 168, 167, 163, 163, 164, 163 ], PolyY: [ 79, 86, 85, 85, 84, 84, 86, 85, 87, 91, 95, 96, 98, 100, 101, 102, 105, 108, 112, 115, 117, 121, 124, 125, 124, 124, 121, 118, 115, 114, 110, 108, 107, 105, 101, 98, 95, 89, 87, 81, 78, 80, 77, 74, 72, 71, 68, 67, 63, 60, 58, 58, 59, 57, 57, 58, 59, 60, 59, 58, 56, 53, 53, 55, 55, 54, 56, 57, 59, 60, 62, 62, 68, 69, 72, 75 ], ClosePath: true, LakeList: [ { Type: 'Lake', PolyX: [ 212, 212, 214, 214, 213 ], PolyY: [ 92, 90, 90, 91, 92 ], ClosePath: true, }, ], // end LakeList }, // end Land { Type: 'Land', Name: 'Madagaskar', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 223, 224, 225, 227, 230, 231, 230, 229, 227, 224, 224 ], PolyY: [ 112, 115, 116, 115, 106, 106, 103, 102, 105, 106, 111 ], ClosePath: true, LakeList: [ ], // end LakeList }, // end Land ], // end LandList }, // end Continent { Type: 'Continent', Name: 'Eurasia', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, LandList: [ { Type: 'Land', Name: 'EuropeAsia', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 360, 356, 342, 340, 333, 329, 320, 318, 313, 311, 310, 311, 304, 303, 294, 293, 294, 291, 284, 266, 265, 252, 251, 250, 246, 248, 248, 244, 239, 240, 229, 223, 220, 215, 213, 218, 220, 221, 221, 214, 209, 203, 201, 199, 193, 195, 190, 185, 185, 186, 188, 191, 193, 196, 197, 199, 199, 197, 197, 201, 202, 204, 205, 201, 201, 208, 207, 202, 201, 194, 191, 190, 190, 188, 188, 185, 182, 180, 178, 178, 175, 178, 179, 178, 172, 171, 171, 170, 171, 171, 173, 174, 178, 180, 180, 183, 183, 186, 188, 190, 192, 196, 196, 192, 195, 196, 197, 198, 196, 194, 192, 193, 195, 199, 199, 201, 201, 203, 204, 203, 205, 206, 207, 210, 213, 215, 216, 215, 214, 212, 212, 214, 215, 215, 219, 219, 223, 223, 225, 232, 238, 240, 237, 236, 234, 232, 230, 230, 228, 230, 231, 235, 236, 237, 237, 242, 246, 251, 252, 256, 256, 257, 258, 260, 260, 261, 262, 260, 260, 267, 272, 274, 274, 277, 278, 278, 280, 281, 284, 284, 283, 281, 280, 279, 280, 281, 284, 284, 285, 289, 289, 286, 286, 288, 289, 289, 288, 289, 291, 291, 295, 297, 301, 303, 302, 301, 299, 300, 303, 303, 301, 299, 299, 301, 301, 305, 305, 306, 306, 307, 310, 308, 308, 310, 311, 314, 318, 320, 320, 321, 322, 322, 323, 323, 324, 323, 321, 320, 317, 316, 323, 334, 337, 340, 340, 342, 344, 344, 341, 335, 336, 337, 339, 340, 340, 342, 342, 343, 343, 342, 344, 350, 356, 359, 360, 358, 360 ], PolyY: [ 21, 20, 20, 19, 19, 17, 17, 18, 18, 19, 18, 17, 16, 17, 17, 16, 14, 13, 12, 15, 16, 17, 16, 16, 19, 21, 22, 20, 20, 21, 21, 22, 25, 25, 23, 24, 24, 23, 22, 21, 19, 19, 20, 20, 22, 22, 26, 28, 31, 32, 32, 31, 34, 34, 31, 31, 30, 29, 28, 26, 24, 24, 25, 27, 30, 30, 31, 31, 35, 36, 36, 35, 33, 33, 36, 37, 39, 41, 40, 41, 41, 43, 45, 47, 46, 47, 50, 51, 52, 53, 53, 54, 53, 51, 50, 48, 47, 47, 46, 46, 48, 50, 52, 52, 53, 52, 50, 50, 48, 47, 45, 44, 46, 48, 50, 52, 53, 54, 52, 50, 49, 50, 53, 54, 54, 53, 54, 58, 59, 59, 60, 62, 60, 62, 67, 69, 74, 77, 77, 75, 71, 68, 66, 64, 66, 66, 64, 63, 61, 60, 62, 64, 63, 63, 64, 65, 65, 70, 70, 80, 81, 82, 82, 80, 84, 84, 83, 79, 75, 69, 69, 72, 75, 75, 77, 82, 84, 87, 89, 88, 85, 83, 81, 80, 77, 77, 80, 82, 82, 79, 75, 72, 70, 69, 69, 70, 71, 72, 70, 69, 67, 67, 63, 59, 56, 55, 55, 54, 54, 53, 52, 52, 51, 49, 51, 50, 52, 53, 56, 56, 54, 51, 50, 49, 47, 47, 44, 41, 39, 38, 39, 44, 44, 41, 41, 36, 37, 36, 36, 35, 31, 31, 28, 28, 29, 29, 28, 29, 30, 34, 39, 39, 37, 37, 36, 36, 34, 34, 32, 32, 30, 30, 28, 28, 27, 25, 25 ], ClosePath: false, LakeList: [ { Type: 'Lake', PolyX: [ 208, 208, 211, 213, 213, 214, 215, 217, 221, 222, 221, 217, 215, 213, 211 ], PolyY: [ 49, 47, 44, 44, 46, 46, 45, 45, 47, 48, 49, 49, 48, 48, 49 ], ClosePath: true, }, { Type: 'Lake', PolyX: [ 229, 229, 230, 227, 227, 231, 233, 233, 230, 233, 234, 234, 233, 233, 234, 234, 232 ], PolyY: [ 53, 51, 50, 47, 45, 43, 43, 44, 46, 48, 48, 49, 49, 51, 51, 53, 54 ], ClosePath: true, }, ], // end LakeList }, // end Land { Type: 'Land', Name: 'EuropeAsiaContinued', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 0, 4, 5, 8, 10, 8, 6, 0 ], PolyY: [ 25, 25, 26, 26, 24, 23, 23, 21 ], ClosePath: false, LakeList: [ ], // end LakeList }, // end Land { Type: 'Land', Name: 'Iceland', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 157, 160, 162, 166, 167, 164, 159, 157, 156, 156 ], PolyY: [ 26, 27, 27, 26, 25, 24, 24, 23, 24, 25 ], ClosePath: true, LakeList: [ ], // end LakeList }, // end Land { Type: 'Land', Name: 'GreatBritain', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 174, 181, 182, 182, 180, 180, 178, 177, 179, 176, 177, 175, 174, 174, 176, 177, 175, 176, 174, 176 ], PolyY: [ 40, 39, 38, 37, 37, 36, 34, 34, 32, 32, 31, 31, 33, 34, 36, 37, 37, 38, 38, 39 ], ClosePath: true, LakeList: [ ], // end LakeList }, // end Land { Type: 'Land', Name: 'Ireland', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 169, 170, 174, 174, 175, 174, 172, 171, 170, 170, 171 ], PolyY: [ 38, 39, 38, 36, 36, 35, 35, 36, 36, 37, 37 ], ClosePath: true, LakeList: [ ], // end LakeList }, // end Land { Type: 'Land', Name: 'OstrovNakhodka', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 315, 321, 328, 332, 336, 336, 329, 320, 316, 313, 313 ], PolyY: [ 16, 15, 16, 17, 16, 15, 14, 14, 12, 13, 14 ], ClosePath: true, LakeList: [ ], // end LakeList }, // end Land { Type: 'Land', Name: 'ZalivHedentrom', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 271, 275, 280, 279, 284, 286, 284, 281, 280, 280, 277, 277, 273 ], PolyY: [ 10, 11, 11, 12, 12, 12, 11, 11, 11, 10, 10, 9, 9 ], ClosePath: true, LakeList: [ ], // end LakeList }, // end Land { Type: 'Land', Name: 'Svalbard', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 191, 196, 197, 199, 200, 201, 204, 205, 203, 200, 206, 207, 191 ], PolyY: [ 11, 14, 14, 12, 12, 13, 13, 12, 12, 11, 11, 10, 10 ], ClosePath: true, LakeList: [ ], // end LakeList }, // end Land { Type: 'Land', Name: 'RegionSjaelland', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 191, 192, 192, 191 ], PolyY: [ 35, 35, 34, 34 ], ClosePath: true, LakeList: [ ], // end LakeList }, // end Land { Type: 'Land', Name: 'Sardinia', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 188, 190, 190, 189, 190, 189, 188, 189, 188 ], PolyY: [ 51, 51, 49, 49, 48, 47, 48, 49, 49 ], ClosePath: true, LakeList: [ ], // end LakeList }, // end Land { Type: 'Land', Name: 'Majorca', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 182, 183, 184, 183 ], PolyY: [ 51, 51, 50, 50 ], ClosePath: true, LakeList: [ ], // end LakeList }, // end Land { Type: 'Land', Name: 'Sumatra', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 275, 275, 278, 279, 281, 284, 286, 285, 288, 294, 297, 302, 306, 295, 294, 292, 291, 290, 289, 288, 286, 286, 287, 286, 284, 284, 280, 278 ], PolyY: [ 84, 85, 88, 90, 93, 96, 96, 97, 98, 99, 99, 99, 98, 98, 97, 97, 96, 97, 97, 96, 96, 93, 93, 91, 91, 89, 87, 85 ], ClosePath: true, LakeList: [ ], // end LakeList }, // end Land { Type: 'Land', Name: 'Indonesia', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 289, 290, 292, 296, 296, 298, 299, 298, 298, 299, 297, 292, 291, 291, 289 ], PolyY: [ 91, 93, 94, 94, 92, 89, 89, 88, 86, 85, 83, 87, 87, 88, 88 ], ClosePath: true, LakeList: [ ], // end LakeList }, // end Land { Type: 'Land', Name: 'Sulawesi', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 299, 300, 300, 302, 303, 303, 302, 304, 304, 305, 305, 304, 300, 300, 303, 301, 299 ], PolyY: [ 96, 96, 93, 96, 96, 94, 92, 91, 90, 89, 88, 89, 89, 90, 90, 91, 91 ], ClosePath: true, LakeList: [ ], // end LakeList }, // end Land { Type: 'Land', Name: 'Philippines', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 304, 306, 307, 306, 306, 304, 302, 301, 302, 302, 301, 300, 300, 301, 303, 302, 304 ], PolyY: [ 84, 84, 83, 80, 78, 76, 76, 74, 73, 72, 72, 74, 75, 77, 81, 83, 83 ], ClosePath: true, LakeList: [ ], // end LakeList }, // end Land { Type: 'Land', Name: 'Taiwan', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 300, 301, 302, 301, 300 ], PolyY: [ 68, 68, 65, 65, 67 ], ClosePath: true, LakeList: [ ], // end LakeList }, // end Land { Type: 'Land', Name: 'Japan', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 310, 311, 312, 313, 320, 321, 322, 322, 321, 323, 325, 326, 324, 322, 321, 320, 320, 318, 316, 312, 309 ], PolyY: [ 59, 59, 57, 57, 55, 54, 51, 50, 48, 48, 47, 46, 46, 45, 47, 47, 51, 53, 54, 55, 57 ], ClosePath: true, LakeList: [ ], // end LakeList }, // end Land ], // end LandList }, // end Continent { Type: 'Continent', Name: 'Australia', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, LandList: [ { Type: 'Land', Name: 'Australia', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 295, 296, 298, 300, 304, 304, 306, 308, 309, 311, 314, 315, 316, 317, 317, 318, 320, 323, 325, 326, 327, 328, 330, 330, 333, 334, 333, 331, 330, 329, 328, 326, 326, 325, 324, 323, 322, 321, 320, 315, 317, 315, 313, 310, 310, 309, 306, 302, 302, 301, 299, 295, 293, 293, 295, 295, 296, 296 ], PolyY: [ 124, 125, 125, 124, 124, 123, 122, 122, 121, 121, 123, 125, 125, 124, 125, 125, 128, 129, 128, 129, 129, 128, 128, 126, 122, 118, 115, 112, 112, 110, 110, 109, 107, 104, 104, 101, 101, 107, 108, 105, 102, 102, 101, 101, 103, 104, 104, 107, 108, 110, 110, 111, 114, 116, 119, 121, 122, 123 ], ClosePath: true, LakeList: [ ], // end LakeList }, // end Land { Type: 'Land', Name: 'PapuaNewGuinea', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 312, 313, 317, 318, 318, 317, 318, 319, 320, 321, 323, 324, 326, 327, 331, 331, 329, 327, 328, 328, 331, 333, 332, 331, 328, 328, 327, 323, 317, 316, 315, 314, 314, 313, 312, 310, 311 ], PolyY: [ 92, 94, 95, 96, 97, 98, 99, 98, 98, 99, 99, 98, 98, 100, 101, 100, 99, 97, 97, 96, 96, 94, 94, 95, 95, 96, 96, 93, 91, 93, 93, 92, 91, 90, 90, 91, 92 ], ClosePath: true, LakeList: [ ], // end LakeList }, // end Land { Type: 'Land', Name: 'Tasmania', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 324, 326, 327, 328, 328, 327, 326, 325 ], PolyY: [ 131, 134, 134, 133, 130, 131, 131, 130 ], ClosePath: true, LakeList: [ ], // end LakeList }, // end Land { Type: 'Land', Name: 'NewZealand', SpanPole: '', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 346, 349, 351, 352, 353, 353, 354, 354, 355, 357, 357, 358, 359, 358, 357, 356, 355, 354, 352, 355, 354, 355, 355, 354, 353, 353, 350, 348 ], PolyY: [ 136, 137, 136, 134, 134, 133, 132, 131, 132, 130, 129, 129, 127, 127, 128, 128, 127, 125, 124, 128, 129, 130, 131, 131, 131, 130, 133, 134 ], ClosePath: true, LakeList: [ ], // end LakeList }, // end Land ], // end LandList }, // end Continent { Type: 'Continent', Name: 'Antarctica', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, LandList: [ { Type: 'Land', Name: 'Antarctica', SpanPole: 'S', Color: null, BorderColor: null, BorderWidth: null, DrawMode: null, PolyX: [ 360, 350, 350, 349, 346, 344, 343, 344, 346, 349, 351, 349, 346, 341, 334, 330, 330, 328, 320, 317, 315, 315, 308, 307, 300, 296, 297, 289, 285, 280, 277, 276, 276, 267, 263, 262, 261, 262, 257, 254, 250, 240, 236, 231, 219, 211, 204, 195, 184, 179, 178, 166, 165, 154, 155, 152, 153, 143, 136, 129, 119, 120, 120, 118, 120, 123, 123, 116, 113, 113, 111, 110, 107, 104, 105, 107, 107, 101, 97, 91, 85, 83, 78, 76, 73, 62, 55, 52, 52, 37, 27, 23, 21, 4, 0 ], PolyY: [ 167, 167, 166, 166, 167, 167, 166, 164, 164, 163, 161, 161, 160, 160, 158, 158, 156, 157, 157, 155, 155, 156, 156, 155, 157, 157, 155, 157, 155, 156, 154, 155, 156, 156, 157, 156, 156, 157, 159, 159, 158, 157, 156, 156, 159, 159, 160, 159, 160, 159, 160, 161, 162, 164, 165, 165, 166, 168, 168, 167, 165, 163, 157, 155, 155, 154, 153, 155, 157, 159, 160, 159, 159, 160, 162, 162, 163, 162, 164, 163, 162, 161, 161, 163, 164, 164, 163, 163, 164, 164, 166, 166, 168, 168, 167 ], ClosePath: false, LakeList: [ ], // end LakeList }, // end Land ], // end LandList }, // end Continent ], // end ContinentList // private working objects (cache) clippedPolyList: new JsgPolygonList( true ), workPoly: new JsgPolygon(), plane: null, p: [ 0, 0, 0 ], p1: [ 0, 0, 0 ], p2: [ 0, 0, 0 ], p3: [ 0, 0, 0 ], shadowIsClipped: false, ToRad: Math.PI / 180, ToDeg: 180 / Math.PI, GetContinent: function( name ) { for (var c = 0; c < this.ContinentList.length; c++) { if (this.ContinentList[c].Name == name) return this.ContinentList[c]; } return null; }, GetLand: function( name ) { for (var c = 0; c < this.ContinentList.length; c++) { var continent = this.ContinentList[c]; for (var l = 0; l < continent.LandList.length; l++) { if (continent.LandList[l].Name == name) return continent.LandList[l]; } } return null; }, SetColor: function( landColor, landBorderColor, landBorderWidth, landDrawMode ) { this.LandColor = xDefStr( landColor, this.LandColor ); this.LandBorderColor = xDefStr( landBorderColor, this.LandBorderColor ); this.LandBorderWidth = xDefNum( landBorderWidth, this.LandBorderWidth ); this.LandDrawMode = xDefNum( landDrawMode, this.LandDrawMode ); for (var c = 0; c < this.ContinentList.length; c++) { var continent = this.ContinentList[c]; continent.Color = null; continent.BorderColor = null; continent.BorderWidth = null; continent.DrawMode = null; for (var l = 0; l < continent.LandList.length; l++) { var land = continent.LandList[l]; land.Color = null; land.BorderColor = null; land.BorderWidth = null; land.DrawMode = null; } } }, SetWaterColor: function( color, borderColor, borderWidth, drawMode ) { this.WaterColor = xDefStr( color, this.WaterColor ); this.WaterBorderColor = xDefStr( borderColor, this.WaterBorderColor ); this.WaterBorderWidth = xDefNum( borderWidth, this.WaterBorderWidth ); this.WaterDrawMode = xDefNum( drawMode, this.WaterDrawMode ); }, SetLakeColor: function( color, borderColor, borderWidth, drawMode ) { this.LakeColor = xDefStr( color, this.LakeColor ); this.LakeBorderColor = xDefStr( borderColor, this.LakeBorderColor ); this.LakeBorderWidth = xDefNum( borderWidth, this.LakeBorderWidth ); this.LakeDrawMode = xDefNum( drawMode, this.LakeDrawMode ); }, SetContinentColor: function( name, colors, borderColors, borderWidths, drawModes ) { // name: null or string; null -> set color for all contients according colors // colors, borderColors: string or array of string or null // borderWidths, drawModes: int or array of int or null // undefined values set attributes to parent attribute (null) if (name) { // set color for single continent if (xArray(colors)) colors = colors[0]; if (xArray(borderColors)) borderColors = borderColors[0]; if (xArray(borderWidths)) borderWidths = borderWidths[0]; if (xArray(drawModes)) drawModes = drawModes[0]; var continent = this.GetContinent( name ); if (!continent) return; continent.Color = xDefStr( colors, null ); continent.BorderColor = xDefStr( borderColors, null ); continent.BorderWidth = xDefNum( borderWidths, null ); continent.DrawMode = xDefNum( drawModes, null ); for (var l = 0; l < continent.LandList.length; l++) { var land = continent.LandList[l]; land.Color = null; land.BorderColor = null; land.BorderWidth = null; land.DrawMode = null; } } else { // set color for all continents if (!colors) colors = null; if (!borderColors) borderColors = null; if (!borderWidths) borderWidths = null; if (!drawModes) drawModes = null; if (!xArray(colors)) colors = [ colors ]; if (!xArray(borderColors)) borderColors = [ borderColors ]; if (!xArray(borderWidths)) borderWidths = [ borderWidths ]; if (!xArray(drawModes)) drawModes = [ drawModes ]; var nColors = colors.length; var nBorderColors = borderColors.length; var nBorderWidths = borderWidths.length; var nDrawModes = drawModes.length; for (var c = 0; c < this.ContinentList.length; c++) { var continent = this.ContinentList[c]; continent.Color = colors[c % nColors]; continent.BorderColor = borderColors[c % nBorderColors]; continent.BorderWidth = borderWidths[c % nBorderWidths]; continent.DrawMode = drawModes[c % nDrawModes]; for (var l = 0; l < continent.LandList.length; l++) { var land = continent.LandList[l]; land.Color = null; land.BorderColor = null; land.BorderWidth = null; land.DrawMode = null; } } } }, SetLandColor: function( name, color, borderColor, borderWidth, drawMode ) { // name: string; land name // color, borderColor: string or null or undefined // borderWidth, drawMode: number or null or undefined // undefined or null attributes -> null -> set to parent attributes var land = this.GetLand( name ); if (!land) return; land.Color = xDefStr( color, null ); land.BorderColor = xDefStr( borderColor, null ); land.BorderWidth = xDefNum( borderWidth, null ); land.DrawMode = xDefNum( drawMode, null ); }, DrawGlobe: function( g ) { g.SaveTrans3D( true ); // compute clipping plane this.CompClipPlane( g ); // draw sea water g.SetAreaAttr( this.WaterColor, this.WaterBorderColor, this.WaterBorderWidth ); g.SetPlane( this.ClipPlane ); g.CircleOnPlane( 0, 0, this.ClipPlane.Radius, this.WaterDrawMode ); // draw continents var nContinents = this.ContinentList.length; for (var i = 0; i < nContinents; i++) { this.DrawGlobeContinent( g, this.ContinentList[i] ); } g.RestoreTrans3D(); }, DrawGlobeEquator: function( g, saveTrans ) { // set attributes before calling this function this.DrawGlobeLatitude( g, 0, saveTrans ); }, DrawGlobeMeridian: function( g, lng, asGreatCircle, saveTrans ) { // set attributes before calling this function lng = xDefNum( lng, 0 ); asGreatCircle = xDefBool( asGreatCircle, false ); this.DrawGlobeLongitude( g, lng, asGreatCircle, saveTrans ); }, DrawGlobeGrid: function( g, dLng, dLat ) { g.SaveTrans3D(); g.SetTrans3D( this.Trans, true ); dLng = xDefNum( dLng, 15 ); dLat = xDefNum( dLat, dLng ); dLat = Math.abs( dLat ); dLng = Math.abs( dLng ); var limit = 90 - dLat / 2; for (var a = 0; a < limit; a += dLat) { this.DrawGlobeLatitude( g, a, false ); } var limit = -(90 - dLat / 2); for (var a = -dLat; a > limit; a -= dLat) { this.DrawGlobeLatitude( g, a, false ); } var limit = 180 - dLng / 2; for (var a = 0; a < limit; a += dLng) { this.DrawGlobeLongitude( g, a, true, false ); } g.RestoreTrans3D(); }, DrawGlobeLatitude: function( g, lat, saveTrans ) { // set attributes before calling this function saveTrans = xDefBool( saveTrans, true ); if (saveTrans) { g.SaveTrans3D(); } g.SetTrans3D( this.Trans, true ); g.NewPoly3D( true ); var dAng = 360 / this.NContourPoints; var lastAng = 360 + dAng / 2; for (var lng = 0; lng < lastAng; lng += dAng) { g.AddPointToPoly3D( this.PointOnGlobe( lat, lng ) ); } g.ResetTrans3D(); this.GlobeClipAndDrawPoly( g ); if (saveTrans) { g.RestoreTrans3D(); } }, DrawGlobeLongitude: function( g, lng, asGreatCircle, saveTrans ) { // set attributes before calling this function saveTrans = xDefBool( saveTrans, true ); if (saveTrans) { g.SaveTrans3D(); } g.SetTrans3D( this.Trans, true ); g.NewPoly3D( true ); var dAng = 360 / this.NContourPoints; var lastAng = 90 + dAng / 2; if (asGreatCircle) lastAng += 180; for (var lat = -90; lat < lastAng; lat += dAng) { g.AddPointToPoly3D( this.PointOnGlobe( lat, lng ) ); } g.ResetTrans3D(); this.GlobeClipAndDrawPoly( g ); if (saveTrans) { g.RestoreTrans3D(); } }, DrawGlobeShadow: function( g, sunVect, sunDist, drawMode ) { // sunVect: JsgVect3; direction from earth center to sun // if sunDist = 0 then sun is treated as infinte far in the distance sunVect // if sunDist > 0 then sun is treated as sunDist from earth origin g.SaveTrans3D( true ); // compute shadow plane var shadowPlane = this.CompPlane( sunVect, sunDist ); // create shadow terminator circle on shadow plane var dAng = 2 * Math.PI / this.NContourPoints; var lastAng = 2 * Math.PI - dAng / 2; g.NewPoly3D(); for (var a = 0; a < lastAng; a += dAng) { var x = shadowPlane.Radius * Math.cos(a); var y = shadowPlane.Radius * Math.sin(a); var p = JsgVect3.CopyTo( shadowPlane.Pos, this.p ); JsgVect3.AddTo( p, JsgVect3.Scale( shadowPlane.XDir, x ) ); JsgVect3.AddTo( p, JsgVect3.Scale( shadowPlane.YDir, y ) ); g.AddPointToPoly3D( p ); } g.Poly3D.GetFirstPoint3D( p ); g.AddPointToPoly3D( p ); // clip shadow terminator and compute clip plane contour of shadow this.clippedPolyList.Reset(); this.shadowIsClipped = false; this.ClipPlane.ClipArea( g.Poly3D, this.clippedPolyList, this.GlobeShadowClipFunc, this ); if (this.clippedPolyList.IsEmpty()) { // lit part lies behind clip plane if (JsgVect3.ScalarProd( shadowPlane.Normal, this.ClipPlane.Normal ) < 0) { // sun is shining from into face of camera, so the whole earth is in shadow as seen from camera this.AddFullShadow( this.clippedPolyList ); } else if (shadowPlane.Radius < this.ClipPlane.Radius) { // sun is shining from behind the camera, // so the radius of the shadow-clip defines whether shadow is visible or not // here the shadow circle is smaller than the earth and behind clip plane, // so the visible part of the earth is fully in shadow this.AddFullShadow( this.clippedPolyList ); } } else { // lit part is at least partially visible if (!this.shadowIsClipped) { // if lit part is not clipped then some ring shadow is visible, so make this ring this.AddFullShadow( this.clippedPolyList ); } } if (!this.clippedPolyList.IsEmpty()) { drawMode = xDefNum( drawMode, 2 ); g.PolygonList3D( this.clippedPolyList, drawMode ); } g.RestoreTrans3D(); }, DrawGlobeMarker: function( g, lat, lng, mode ) { // set marker attributes before mode = mode || 3; g.Marker3D( this.PointOnGlobe( lat, lng ), mode ); }, DrawGlobeGreatCircleArc: function( g, lat1, lng1, lat2, lng2, big ) { // draws a great circle line // line attributes must be set // changes g.Plane to draw // returns true if arc could be drawn, // returns false if points are identical or opposite so the arc is undefined var p1 = this.PointOnGlobe( lat1, lng1, this.p1 ); var p2 = this.PointOnGlobe( lat2, lng2, this.p2 ); var plane = this.GetGlobeGreatCirclePlane( p1, p2, this.plane, true ); // assert: this.p1 and this.p2 get normed by GetGreatCirclePlane() if (!plane) return false; var a = this.GetGlobeGreatCircleAngle( p1, p2, true ); if (g.AngleMeasure == 'deg') a *= this.ToDeg; g.SetPlane( plane ); if (big) { ae = g.AngleMeasure == 'deg' ? 360 : 2 * Math.PI; g.ArcOnPlane( 0, 0, this.Radius, a, ae, 1 ); } else { g.ArcOnPlane( 0, 0, this.Radius, 0, a, 1 ); } return true; }, GetGlobeGreatCircleAngle: function( p1, p2, isInternal ) { // returns the angle in rad between p1 and p2 // isInternal can be set to true if p1, p2 are in this.p1, this.p2 and normed var p1normed, p2normed; if (isInternal) { p1normed = this.p1; p2normed = this.p2; } else { p1normed = JsgVect3.CopyTo( p1, this.p1 ); p2normed = JsgVect3.CopyTo( p2, this.p2 ); JsgVect3.NormTo( p1normed ); JsgVect3.NormTo( p2normed ); } return Math.acos( this.RangePM1( JsgVect3.ScalarProd( p1normed, p2normed ) ) ); }, GetGlobeGreatCirclePlane: function( p1, p2, plane, isInternal ) { // returns a plane through the center of the globe which contains p1 and p2 // this plane can be used to draw a great circle arc // returns null if p1, p2 are identical or opposite so no unique plane can be computed // p1, p2: JsgVect3; // plane: JsgPlane or undefined // returns plane or this.plane or null // isInternal can be set to true if p1, p2 are in this.p1, this.p2 if (!plane) { if (!this.plane) this.plane = new JsgPlane( [0,0,0], [1,0,0], [0,1,0], false ); plane = this.plane; } var p1normed, p2normed; if (isInternal) { p1normed = this.p1; p2normed = this.p2; } else { p1normed = JsgVect3.CopyTo( p1, this.p1 ); p2normed = JsgVect3.CopyTo( p2, this.p2 ); } JsgVect3.NormTo( p1normed ); JsgVect3.NormTo( p2normed ); var n = JsgVect3.MultTo( this.p, p1normed, p2normed ); if (JsgVect3.Length( n ) < 1e-8) { return null; } JsgVect3.NormTo( n ); var y = JsgVect3.MultTo( this.p3, n, p1normed ); plane.Set( [0,0,0], p1normed, y, false ); return plane; }, GetClipPointAngle: function( plane, clipPoint ) { // compute angle in range 0..2Pi as measured from planes x-axis CCW var x = JsgVect3.ScalarProd( plane.XDir, JsgVect3.Sub( clipPoint, plane.Pos ) ); var y = JsgVect3.ScalarProd( plane.YDir, JsgVect3.Sub( clipPoint, plane.Pos ) ); var ang = JsgVect2.Angle( [1,0], [x,y], true ); if (ang < 0) ang += 2 * Math.PI; return ang; }, AddFullShadow: function( clippedPolyList ) { var dAng = 2 * Math.PI / this.NContourPoints; var limitAng = 0 - dAng; for (var a = 2*Math.PI; a > limitAng; a -= dAng) { var px = this.ClipPlane.Radius * Math.cos( a ); var py = this.ClipPlane.Radius * Math.sin( a ); clippedPolyList.AddPoint3D( this.ClipPlane.PointOnPlane( px, py ) ); } clippedPolyList.Close(); }, GlobeShadowClipFunc: function( plane, clippedPolyList, earth ) { // create surface circle between intersection points plane.ExitPoint and plane.EnterPoint // always clockwise and add them to clippedPolyList. // earth: this EarthMap var enterAng = earth.GetClipPointAngle( plane, plane.EnterPoint ); var exitAng = earth.GetClipPointAngle( plane, plane.ExitPoint ); var dAng = 2 * Math.PI / earth.NContourPoints; if (exitAng < enterAng) { exitAng += 2 * Math.PI; } // assert exitAng > enterAng var angOffset = ((exitAng - enterAng) % dAng) / 2; for (var a = exitAng - angOffset; a > enterAng; a -= dAng) { var px = plane.Radius * Math.cos( a ); var py = plane.Radius * Math.sin( a ); clippedPolyList.AddPoint3D( plane.PointOnPlane( px, py ) ); } earth.shadowIsClipped = true; }, CompClipPlane: function( g ) { this.ClipPlane = this.CompPlane( g.Camera.CamPos, -1 ); }, CompPlane: function( vDest, dDest ) { // creates a JsgPlane where planes normal is facing vDest // adds properties Radius and Offset to JsgPlane // if dDest < 0 then vDest is treated as a point and dDest is computed as vDest-globe_origin // if dDest = 0 then vDest is treated as a vector and dDest as infinte // if dDest > 0 then vDest is treated as a vector and dDest gived the distance from globe_origin var origin = JsgVect3.Null(); if (this.Trans) { // plane origin is moved to m[i][3] var m = this.Trans; JsgVect3.Set( origin, m[0][3], m[1][3], m[2][3] ); } if (dDest < 0) { vDest = JsgVect3.Sub( vDest, origin ); dDest = JsgVect3.Length( vDest ); } var dPlane = 0; var rPlane = this.Radius; if (dDest > this.Radius) { var r2 = this.Radius * this.Radius; dPlane = r2 / dDest; rPlane = Math.sqrt( r2 - dPlane * dPlane ); } var oPlane = JsgVect3.Add( origin, JsgVect3.Scale( JsgVect3.Norm(vDest), dPlane ) ); var xPlane = JsgVect3.Mult( [0,0,1], vDest ); var yPlane = JsgVect3.Mult( vDest, xPlane ); var plane = new JsgPlane( oPlane, xPlane, yPlane, true ); plane.Radius = rPlane; plane.Offset = dPlane; return plane; }, DrawGlobeContinent: function( g, continent ) { var color = this.LandColor; var borderColor = this.LandBorderColor; var borderWidth = this.LandBorderWidth; var drawMode = this.LandDrawMode; if (continent.Color) color = continent.Color; if (continent.BorderColor) borderColor = continent.BorderColor; if (continent.BorderWidth) borderWidth = continent.BorderWidth; if (continent.DrawMode) drawMode = continent.DrawMode; var nLands = continent.LandList.length; for (var i = 0; i < nLands; i++) { this.DrawGlobeLand( g, continent.LandList[i], color, borderColor, borderWidth, drawMode ); } }, GlobeClipAndDrawArea: function( g, drawMode ) { // clip g.Poly3D at globe clipping plane and draw it this.clippedPolyList.Reset(); this.ClipPlane.ClipArea( g.Poly3D, this.clippedPolyList, this.GlobeClipFunc, this ); g.PolygonList3D( this.clippedPolyList, drawMode ); }, GlobeClipAndDrawPoly: function( g ) { // clip g.Poly3D at globe clipping plane and draw it this.clippedPolyList.Reset(); this.ClipPlane.ClipPoly( g.Poly3D, this.clippedPolyList ); g.PolygonList3D( this.clippedPolyList, 1 ); }, DrawGlobeLand: function( g, land, color, borderColor, borderWidth, drawMode ) { if (land.Color) color = land.Color; if (land.BorderColor) borderColor = land.BorderColor; if (land.BorderWidth) borderWidth = land.BorderWidth; if (land.DrawMode) drawMode = land.DrawMode; // build land polygon // note: this.Trans is used in g.AddPointToPoly3D() -> see NewPoly3D(true) g.SetTrans3D( this.Trans, true ); g.NewPoly3D( true ); var nLandPoints = land.PolyX.length; for (var i = 0; i < nLandPoints; i++) { g.AddPointToPoly3D( this.PointOnGlobe( 90-land.PolyY[i], land.PolyX[i]-180 ) ); } g.AddPointToPoly3D( this.PointOnGlobe( 90-land.PolyY[0], land.PolyX[0]-180 ) ); // g.Poly3D containes this.Trans transformed polygon, so it needs not to be transformed again g.ResetTrans3D(); // clip land at clip plane and draw it g.SetAreaAttr( color, borderColor, borderWidth ); // GlobeClipAndDrawArea uses g.Poly3D where the geom is stored this.GlobeClipAndDrawArea( g, drawMode ); // draw lakes var nLakes = land.LakeList.length; if (nLakes > 0) { g.SetAreaAttr( this.LakeColor, this.LakeBorderColor, this.LakeBorderWidth ); for (var i = 0; i < nLakes; i++) { this.DrawGlobeLake( g, land.LakeList[i] ); } } }, DrawGlobeLake: function( g, lake ) { // build lake polygon // note: this.Trans is used in g.AddPointToPoly3D() -> see NewPoly3D(true) g.SetTrans3D( this.Trans, true ); g.NewPoly3D( true ); var nLakePoints = lake.PolyX.length; for (var i = 0; i < nLakePoints; i++) { g.AddPointToPoly3D( this.PointOnGlobe( 90-lake.PolyY[i], lake.PolyX[i]-180 ) ); } g.AddPointToPoly3D( this.PointOnGlobe( 90-lake.PolyY[0], lake.PolyX[0]-180 ) ); // g.Poly3D containes this.Trans transformed polygon, so it needs not to be transformed again g.ResetTrans3D(); // clip lake at clip plane and // GlobeClipAndDrawArea uses g.Poly3D where the geom is stored this.GlobeClipAndDrawArea( g, this.LakeDrawMode ); }, GlobeClipFunc: function( plane, clippedPolyList, earth ) { // create surface circle between intersection points plane.ExitPoint and plane.EnterPoint // and add them to clippedPolyList. // earth: this EarthMap // Note: this function is not perfectly correct, because it interpolates along the earth clip circle // always the shorter way between Exit- and EnterPoint. // This works well as long as the clip circle is not fully inside an area. var enterAng = earth.GetClipPointAngle( plane, plane.EnterPoint ); var exitAng = earth.GetClipPointAngle( plane, plane.ExitPoint ); var dAng = 2 * Math.PI / earth.NContourPoints; var angRange = Math.abs( enterAng - exitAng ); var angOffset; if (angRange < Math.PI) { angOffset = (angRange % dAng) / 2; if (enterAng < exitAng) { dAng = -dAng; angOffset = -angOffset; } } else { if (enterAng < exitAng) { enterAng += 2 * Math.PI; // assert enterAng > exitAng angRange = enterAng - exitAng; angOffset = (angRange % dAng) / 2; } else { exitAng += 2 * Math.PI; // asser exitAng > enterAng angRange = exitAng - enterAng; angOffset = -(angRange % dAng) / 2; dAng = -dAng; } } for (var a = exitAng + angOffset; dAng > 0 ? a < enterAng : a > enterAng; a += dAng) { var px = earth.ClipPlane.Radius * Math.cos( a ); var py = earth.ClipPlane.Radius * Math.sin( a ); clippedPolyList.AddPoint3D( plane.PointOnPlane( px, py ) ); } }, PointOnGlobe: function( lat, lng, p ) { // lat, lng in deg // p: JsgVect3 or undefined // return p or this.p p = p || this.p; var rr = this.Radius * Math.cos( this.ToRad * lat ); p[0] = rr * Math.cos( this.ToRad * lng ); p[1] = rr * Math.sin( this.ToRad * lng ); p[2] = this.Radius * Math.sin( this.ToRad * lat ); return p; }, GlobeCoordOfPoint: function( p, coord ) { // p: JsgVect3; p[0] is direction 0-Meridian, p[1] is direction x rot 90 deg east, p[2] is dir north // coord: JsgVect2 or undefined // returns coord or this.p: JsgVect2 // return[0] -> latitude, return[1] -> longitude coord = coord || this.p; var pNormed = JsgVect3.Set( this.p1, p[0], p[1], p[2] ); Jsgvect3.NormTo( pNormed ); var sp = JsgVect3.ScalarProd( [0,0,1], pNormed ); coord[0] = (Math.PI/2 - Math.acos( this.RangePM1(sp) ) ) * this.ToDeg; var pXYplane = JsgVect3.Set( this.p2, pNormed[0], pNormed[1], 0 ); JsgVect3.NormTo( pXYplane ); var sp = JsgVect3.ScalarProd( [1,0,0], pXYplane ); coord[1] = Math.acos( this.RangePM1(sp) ) * this.ToDeg; if (pXYplane[1] < 0) coord[1] *= -1; return coord; }, GlobeCoordOfPointXYZ: function( x, y, z, coord ) { // see GlobeCoordOfPoint() above JsgVect3.Set( this.p2, x, y, z ); return this.GlobeCoordOfPoint( this.p2, coord ); }, DrawFlatEarth: function( g ) { // draw sea water g.SetAreaAttr( this.WaterColor, this.WaterBorderColor, this.WaterBorderWidth ); if (this.FEMode >= 2) { g.CircleOnPlane( 0, 0, this.Radius, this.WaterDrawMode ); } else { g.Circle( 0, 0, this.Radius, this.WaterDrawMode ); } var nContinents = this.ContinentList.length; for (var c = 0; c < nContinents; c++) { this.DrawFlatEarthContinent( g, this.ContinentList[c] ); } }, DrawFlatEarthContinent: function( g, continent ) { var color = this.LandColor; var borderColor = this.LandBorderColor; var borderWidth = this.LandBorderWidth; var drawMode = this.LandDrawMode; if (continent.Color) color = continent.Color; if (continent.BorderColor) borderColor = continent.BorderColor; if (continent.BorderWidth) borderWidth = continent.BorderWidth; if (continent.DrawMode) drawMode = continent.DrawMode; var nLands = continent.LandList.length; for (var i = 0; i < nLands; i++) { this.DrawFlatEarthLand( g, continent.LandList[i], color, borderColor, borderWidth, drawMode ); } }, DrawFlatEarthLand: function( g, land, color, borderColor, borderWidth, drawMode ) { // this.FEMode: 0 -> use Polygon, 1 -> SplineCurve, 2 -> PolygonOnPlane, 3 -> SplineCurveOnPlane if (land.Color) color = land.Color; if (land.BorderColor) borderColor = land.BorderColor; if (land.BorderWidth) borderWidth = land.BorderWidth; if (land.DrawMode) drawMode = land.DrawMode; g.SetAreaAttr( color, borderColor, borderWidth ); if (this.FEMode >= 2) { g.OpenPath3D(); } else { g.OpenPath(); } var lmode = drawMode & 2; // fill if (land.SpanPole == '') lmode += drawMode & 1; // border if (land.ClosePath) lmode += 4; // close this.DrawFlatEarthArea( g, land, lmode ); // handle pole areas: fill and draw border separately if (land.SpanPole == 'S') { if (this.FEMode >= 2) { g.CircleOnPlane( 0, 0, this.Radius ); } else { g.Circle( 0, 0, this.Radius, this.WaterDrawMode ); } if (this.FEMode >= 2) { g.Path3D( lmode ); // fill with pole area g.OpenPath3D(); } else { g.Path( lmode ); // fill with pole area g.OpenPath(); } lmode = 1; // border if (land.ClosePath) lmode += 4; // close this.DrawFlatEarthArea( g, land, lmode ); // earth border if (this.FEMode >= 2) { g.CircleOnPlane( 0, 0, this.Radius, 1 ); } else { g.Circle( 0, 0, this.Radius, 1 ); } } if (this.FEMode >= 2) { g.Path3D( lmode ); // fill with pole area } else { g.Path( lmode ); // fill with pole area } // draw lakes var nLakes = land.LakeList.length; if (nLakes > 0) { g.SetAreaAttr( this.LakeColor, this.LakeBorderColor, this.LakeBorderWidth ); for (var i = 0; i < nLakes; i++) { var lake = land.LakeList[i]; var mode = this.LakeDrawMode; if (lake.ClosePath) mode += 4; this.DrawFlatEarthArea( g, lake, mode ); } } }, DrawFlatEarthArea: function( g, area, mode ) { var poly = this.MapToFE( area ); if (this.FEMode == 0) { g.Polygon( poly, mode ); } else if (this.FEMode == 1) { g.SplineCurve( poly, this.SplineTension, mode ); } else if (this.FEMode == 2) { g.PolygonOnPlane( poly, mode ); } else { g.SplineCurveOnPlane( poly, this.SplineTension, mode ); } }, MapToFE: function( geom ) { var poly = this.workPoly.Reset(); var size = geom.PolyX.length; for (var i = 0; i < size; i++) { var a = geom.PolyX[i]; // 0..360 180 = 0 meridian var r = geom.PolyY[i]; // 0..180 0 = north r *= this.Radius / 180; a = (a+90) * this.ToRad; poly.AddPoint( r * Math.cos(a), r * Math.sin(a) ); } return poly; }, PointOnFE: function( lat, lng, p ) { // lat: -90..90, 0 = equator // lng: -180..180, 0 = meridian // p: JsgVect2 or undefined // returns p: JsgVect2 or this.p p = p || this.p; var r = (90 - lat) * this.Radius / 180; var a = (lng - 90) * this.ToRad; p[0] = r * Math.cos(a); p[1] = r * Math.sin(a); return p; }, RangePM1: function( x ) { if (x > 1) { x = 1; } else if (x < -1) { x = -1; } return x; }, FECoordOfPoint: function( p, coord ) { // p: JsgVect2; p[0] is direction 0-Meridian, p[1] is direction x rot 90 deg left // coord: JsgVect2 or undefined // returns coord or this.p: JsgVect2 // return[0] -> latitude, return[1] -> longitude coord = coord || this.p; coord[0] = (1 - JsgVect2.Length(p) / this.Radius) * 90; var sp = JsgVect2.ScalarProd( [1,0], p ); coord[1] = Math.acos( this.RangePM1(sp) ) * this.ToDeg; if (p[1] < 0) coord[1] *= -1; return coord; }, FECoordOfPointXY: function( x, y, coord ) { // see FECoordOfPoint() above JsgVect2.Set( this.p1, x, y ); return this.FECoordOfPoint( this.p1, coord ); }, DrawFlatEarthMarker: function( g, lat, lng, mode ) { // set marker attributes before mode = mode || 3; var p = this.PointOnFE( lat, lng ); if (this.FEMode >= 2) { g.MarkerOnPlane( p, mode ); } else { g.Marker( p, mode ); } }, DrawFlatEarthLine: function( g, lat1, lng1, lat2, lng2 ) { // set attributes before var p1 = this.PointOnFE( lat1, lng1, this.p1 ); var p2 = this.PointOnFE( lat2, lng2, this.p2 ); if (this.FEMode >= 2) { g.LineOnPlane( p1, p2 ); } else { g.Line( p1, p2 ); } }, DrawFlatEarthGrid: function( g, dLat, dLng ) { // set attributes before dLng = xDefNum( dLng, 15 ); dLat = xDefNum( dLat, dLng ); dLat = Math.abs( dLat ); dLng = Math.abs( dLng ); var limit = 90 - dLat / 2; for (var a = 0; a < limit; a += dLat) { this.DrawFlatEarthLatitude( g, a ); } var limit = -(90 - dLat / 2); for (var a = -dLat; a > limit; a -= dLat) { this.DrawFlatEarthLatitude( g, a ); } var limit = 180 - dLng / 2; for (var a = 0; a < limit; a += dLng) { this.DrawFlatEarthLongitude( g, a, true ); } }, DrawFlatEarthEquator: function( g ) { this.DrawFlatEarthLatitude( g, 0 ); }, DrawFlatEarthBorder: function( g ) { this.DrawFlatEarthLatitude( g, -90 ); }, DrawFlatEarthMeridian: function( g ) { this.DrawFlatEarthLongitude( g, 0 ); }, DrawFlatEarthLatitude: function( g, lat ) { // set attributes before var r = (90 - lat) * this.Radius / 180; if (this.FEMode >= 2) { g.CircleOnPlane( 0, 0, r, 1 ); } else { g.Circle( 0, 0, r, 1 ); } }, DrawFlatEarthLongitude: function( g, lng, asGreatCircle ) { // set attributes before var p1 = JsgVect2.Set( this.p1, 0, 0 ); var p2 = this.PointOnFE( -90, lng, this.p2 ); if (asGreatCircle) { JsgVect2.Set( p1, -p2[0], -p2[1] ); } if (this.FEMode >= 2) { g.LineOnPlane( p1, p2 ); } else { g.Line( p1, p2 ); } }, } // end EarthMap