File indexing completed on 2025-01-18 09:36:48
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 #ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_HPP
0017 #define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_HPP
0018
0019 #include <algorithm>
0020 #include <type_traits>
0021
0022 #include <boost/config.hpp>
0023 #include <boost/concept_check.hpp>
0024
0025 #include <boost/geometry/core/cs.hpp>
0026 #include <boost/geometry/core/access.hpp>
0027 #include <boost/geometry/core/coordinate_promotion.hpp>
0028 #include <boost/geometry/core/radian_access.hpp>
0029 #include <boost/geometry/core/tags.hpp>
0030
0031 #include <boost/geometry/formulas/spherical.hpp>
0032
0033 #include <boost/geometry/strategies/distance.hpp>
0034 #include <boost/geometry/strategies/concepts/distance_concept.hpp>
0035 #include <boost/geometry/strategies/spherical/distance_haversine.hpp>
0036 #include <boost/geometry/strategies/spherical/point_in_point.hpp>
0037 #include <boost/geometry/strategies/spherical/intersection.hpp>
0038
0039 #include <boost/geometry/util/math.hpp>
0040 #include <boost/geometry/util/select_calculation_type.hpp>
0041
0042 #ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK
0043 # include <boost/geometry/io/dsv/write.hpp>
0044 #endif
0045
0046
0047 namespace boost { namespace geometry
0048 {
0049
0050 namespace strategy { namespace distance
0051 {
0052
0053 #ifndef DOXYGEN_NO_DETAIL
0054 namespace detail
0055 {
0056 template <typename CalculationType>
0057 struct compute_cross_track_pair
0058 {
0059 template <typename Point, typename PointOfSegment>
0060 static inline auto apply(Point const& p,
0061 PointOfSegment const& sp1,
0062 PointOfSegment const& sp2)
0063 {
0064 CalculationType lon1 = geometry::get_as_radian<0>(sp1);
0065 CalculationType lat1 = geometry::get_as_radian<1>(sp1);
0066 CalculationType lon2 = geometry::get_as_radian<0>(sp2);
0067 CalculationType lat2 = geometry::get_as_radian<1>(sp2);
0068 CalculationType lon = geometry::get_as_radian<0>(p);
0069 CalculationType lat = geometry::get_as_radian<1>(p);
0070
0071 CalculationType const crs_AD = geometry::formula::spherical_azimuth
0072 <
0073 CalculationType,
0074 false
0075 >(lon1, lat1, lon, lat).azimuth;
0076
0077 auto result = geometry::formula::spherical_azimuth
0078 <
0079 CalculationType,
0080 true
0081 >(lon1, lat1, lon2, lat2);
0082
0083 CalculationType crs_AB = result.azimuth;
0084 CalculationType crs_BA = result.reverse_azimuth -
0085 geometry::math::pi<CalculationType>();
0086
0087 CalculationType crs_BD = geometry::formula::spherical_azimuth
0088 <
0089 CalculationType,
0090 false
0091 >(lon2, lat2, lon, lat).azimuth;
0092
0093 CalculationType d_crs1 = crs_AD - crs_AB;
0094 CalculationType d_crs2 = crs_BD - crs_BA;
0095
0096 return std::pair<CalculationType, CalculationType>(d_crs1, d_crs2);
0097 }
0098 };
0099
0100 struct compute_cross_track_distance
0101 {
0102 template <typename CalculationType>
0103 static inline auto apply(CalculationType const& d_crs1,
0104 CalculationType const& d1)
0105 {
0106 CalculationType const half(0.5);
0107 CalculationType const quarter(0.25);
0108
0109 CalculationType sin_d_crs1 = sin(d_crs1);
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120 CalculationType d1_x_sin = d1 * sin_d_crs1;
0121 CalculationType d = d1_x_sin * (sin_d_crs1 - d1_x_sin);
0122 return d / (half + math::sqrt(quarter - d));
0123 }
0124 };
0125
0126 }
0127 #endif
0128
0129
0130 namespace comparable
0131 {
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387
0388
0389
0390
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400
0401 template
0402 <
0403 typename CalculationType = void,
0404 typename Strategy = comparable::haversine<double, CalculationType>
0405 >
0406 class cross_track
0407 {
0408 public:
0409 template <typename Point, typename PointOfSegment>
0410 struct return_type
0411 : promote_floating_point
0412 <
0413 typename select_calculation_type
0414 <
0415 Point,
0416 PointOfSegment,
0417 CalculationType
0418 >::type
0419 >
0420 {};
0421
0422 using radius_type = typename Strategy::radius_type;
0423
0424 cross_track() = default;
0425
0426 explicit inline cross_track(typename Strategy::radius_type const& r)
0427 : m_strategy(r)
0428 {}
0429
0430 inline cross_track(Strategy const& s)
0431 : m_strategy(s)
0432 {}
0433
0434
0435
0436
0437
0438
0439 template <typename Point, typename PointOfSegment>
0440 inline typename return_type<Point, PointOfSegment>::type
0441 apply(Point const& p, PointOfSegment const& sp1, PointOfSegment const& sp2) const
0442 {
0443
0444 #if !defined(BOOST_MSVC)
0445 BOOST_CONCEPT_ASSERT
0446 (
0447 (concepts::PointDistanceStrategy<Strategy, Point, PointOfSegment>)
0448 );
0449 #endif
0450
0451 using return_type = typename return_type<Point, PointOfSegment>::type;
0452
0453
0454 return_type d1 = m_strategy.apply(sp1, p);
0455 return_type d3 = m_strategy.apply(sp1, sp2);
0456
0457 if (geometry::math::equals(d3, 0.0))
0458 {
0459
0460 return d1;
0461 }
0462
0463 return_type d2 = m_strategy.apply(sp2, p);
0464
0465 auto d_crs_pair = detail::compute_cross_track_pair<return_type>::apply(
0466 p, sp1, sp2);
0467
0468
0469 return_type projection1 = cos(d_crs_pair.first) * d1 / d3;
0470 return_type projection2 = cos(d_crs_pair.second) * d2 / d3;
0471
0472 #ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK
0473 std::cout << "Course " << dsv(sp1) << " to " << dsv(p) << " "
0474 << crs_AD * geometry::math::r2d<return_type>() << std::endl;
0475 std::cout << "Course " << dsv(sp1) << " to " << dsv(sp2) << " "
0476 << crs_AB * geometry::math::r2d<return_type>() << std::endl;
0477 std::cout << "Course " << dsv(sp2) << " to " << dsv(sp1) << " "
0478 << crs_BA * geometry::math::r2d<return_type>() << std::endl;
0479 std::cout << "Course " << dsv(sp2) << " to " << dsv(p) << " "
0480 << crs_BD * geometry::math::r2d<return_type>() << std::endl;
0481 std::cout << "Projection AD-AB " << projection1 << " : "
0482 << d_crs1 * geometry::math::r2d<return_type>() << std::endl;
0483 std::cout << "Projection BD-BA " << projection2 << " : "
0484 << d_crs2 * geometry::math::r2d<return_type>() << std::endl;
0485 std::cout << " d1: " << (d1 )
0486 << " d2: " << (d2 )
0487 << std::endl;
0488 #endif
0489
0490 if (projection1 > 0.0 && projection2 > 0.0)
0491 {
0492 #ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK
0493 return_type XTD = radius() * geometry::math::abs( asin( sin( d1 ) * sin( d_crs1 ) ));
0494
0495 std::cout << "Projection ON the segment" << std::endl;
0496 std::cout << "XTD: " << XTD
0497 << " d1: " << (d1 * radius())
0498 << " d2: " << (d2 * radius())
0499 << std::endl;
0500 #endif
0501 return detail::compute_cross_track_distance::apply(
0502 d_crs_pair.first, d1);
0503 }
0504 else
0505 {
0506 #ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK
0507 std::cout << "Projection OUTSIDE the segment" << std::endl;
0508 #endif
0509
0510 return return_type( (std::min)( d1 , d2 ) );
0511 }
0512 }
0513
0514 template <typename T1, typename T2>
0515 inline radius_type vertical_or_meridian(T1 lat1, T2 lat2) const
0516 {
0517 return m_strategy.radius() * (lat1 - lat2);
0518 }
0519
0520 inline typename Strategy::radius_type radius() const
0521 { return m_strategy.radius(); }
0522
0523 private :
0524 Strategy m_strategy;
0525 };
0526
0527 }
0528
0529
0530
0531
0532
0533
0534
0535
0536
0537
0538
0539
0540
0541
0542
0543
0544 template
0545 <
0546 typename CalculationType = void,
0547 typename Strategy = haversine<double, CalculationType>
0548 >
0549 class cross_track
0550 {
0551 public :
0552
0553 template <typename Point, typename PointOfSegment>
0554 struct return_type
0555 : promote_floating_point
0556 <
0557 typename select_calculation_type
0558 <
0559 Point,
0560 PointOfSegment,
0561 CalculationType
0562 >::type
0563 >
0564 {};
0565
0566 using radius_type = typename Strategy::radius_type;
0567
0568 inline cross_track()
0569 {}
0570
0571 explicit inline cross_track(typename Strategy::radius_type const& r)
0572 : m_strategy(r)
0573 {}
0574
0575 inline cross_track(Strategy const& s)
0576 : m_strategy(s)
0577 {}
0578
0579
0580
0581
0582
0583
0584 template <typename Point, typename PointOfSegment>
0585 inline auto apply(Point const& p,
0586 PointOfSegment const& sp1,
0587 PointOfSegment const& sp2) const
0588 {
0589
0590 #if !defined(BOOST_MSVC)
0591 BOOST_CONCEPT_ASSERT
0592 (
0593 (concepts::PointDistanceStrategy<Strategy, Point, PointOfSegment>)
0594 );
0595 #endif
0596 using return_type = typename return_type<Point, PointOfSegment>::type;
0597 using this_type = cross_track<CalculationType, Strategy>;
0598
0599 using comparable_type = typename services::comparable_type
0600 <
0601 this_type
0602 >::type;
0603
0604 comparable_type cstrategy
0605 = services::get_comparable<this_type>::apply(m_strategy);
0606
0607 return_type const a = cstrategy.apply(p, sp1, sp2);
0608 return_type const c = return_type(2.0) * asin(math::sqrt(a));
0609 return c * radius();
0610 }
0611
0612 template <typename T1, typename T2>
0613 inline radius_type vertical_or_meridian(T1 lat1, T2 lat2) const
0614 {
0615 return m_strategy.radius() * (lat1 - lat2);
0616 }
0617
0618 inline typename Strategy::radius_type radius() const
0619 { return m_strategy.radius(); }
0620
0621 private :
0622
0623 Strategy m_strategy;
0624 };
0625
0626
0627
0628 #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
0629 namespace services
0630 {
0631
0632 template <typename CalculationType, typename Strategy>
0633 struct tag<cross_track<CalculationType, Strategy> >
0634 {
0635 using type = strategy_tag_distance_point_segment;
0636 };
0637
0638
0639 template <typename CalculationType, typename Strategy, typename P, typename PS>
0640 struct return_type<cross_track<CalculationType, Strategy>, P, PS>
0641 : cross_track<CalculationType, Strategy>::template return_type<P, PS>
0642 {};
0643
0644
0645 template <typename CalculationType, typename Strategy>
0646 struct comparable_type<cross_track<CalculationType, Strategy> >
0647 {
0648 using type = comparable::cross_track
0649 <
0650 CalculationType, typename comparable_type<Strategy>::type
0651 > ;
0652 };
0653
0654
0655 template
0656 <
0657 typename CalculationType,
0658 typename Strategy
0659 >
0660 struct get_comparable<cross_track<CalculationType, Strategy> >
0661 {
0662 using comparable_type = typename comparable_type
0663 <
0664 cross_track<CalculationType, Strategy>
0665 >::type;
0666 public :
0667 static inline comparable_type
0668 apply(cross_track<CalculationType, Strategy> const& strategy)
0669 {
0670 return comparable_type(strategy.radius());
0671 }
0672 };
0673
0674
0675 template
0676 <
0677 typename CalculationType,
0678 typename Strategy,
0679 typename P,
0680 typename PS
0681 >
0682 struct result_from_distance<cross_track<CalculationType, Strategy>, P, PS>
0683 {
0684 private :
0685 using return_type = typename cross_track
0686 <
0687 CalculationType, Strategy
0688 >::template return_type<P, PS>::type;
0689 public :
0690 template <typename T>
0691 static inline return_type
0692 apply(cross_track<CalculationType, Strategy> const& , T const& distance)
0693 {
0694 return distance;
0695 }
0696 };
0697
0698
0699
0700 template <typename RadiusType, typename CalculationType>
0701 struct tag<comparable::cross_track<RadiusType, CalculationType> >
0702 {
0703 using type = strategy_tag_distance_point_segment;
0704 };
0705
0706
0707 template
0708 <
0709 typename RadiusType,
0710 typename CalculationType,
0711 typename P,
0712 typename PS
0713 >
0714 struct return_type<comparable::cross_track<RadiusType, CalculationType>, P, PS>
0715 : comparable::cross_track
0716 <
0717 RadiusType, CalculationType
0718 >::template return_type<P, PS>
0719 {};
0720
0721
0722 template <typename RadiusType, typename CalculationType>
0723 struct comparable_type<comparable::cross_track<RadiusType, CalculationType> >
0724 {
0725 using type = comparable::cross_track<RadiusType, CalculationType>;
0726 };
0727
0728
0729 template <typename RadiusType, typename CalculationType>
0730 struct get_comparable<comparable::cross_track<RadiusType, CalculationType> >
0731 {
0732 private :
0733 using this_type = comparable::cross_track<RadiusType, CalculationType>;
0734 public :
0735 static inline this_type apply(this_type const& input)
0736 {
0737 return input;
0738 }
0739 };
0740
0741
0742 template
0743 <
0744 typename RadiusType,
0745 typename CalculationType,
0746 typename P,
0747 typename PS
0748 >
0749 struct result_from_distance
0750 <
0751 comparable::cross_track<RadiusType, CalculationType>, P, PS
0752 >
0753 {
0754 private :
0755 using strategy_type = comparable::cross_track<RadiusType, CalculationType>;
0756 using return_type = typename return_type<strategy_type, P, PS>::type;
0757 public :
0758 template <typename T>
0759 static inline return_type apply(strategy_type const& strategy,
0760 T const& distance)
0761 {
0762 return_type const s
0763 = sin( (distance / strategy.radius()) / return_type(2.0) );
0764 return s * s;
0765 }
0766 };
0767
0768
0769
0770
0771
0772
0773
0774
0775
0776
0777
0778
0779
0780
0781
0782
0783
0784
0785
0786
0787
0788
0789
0790
0791
0792
0793
0794
0795
0796
0797
0798
0799 template <typename Point, typename PointOfSegment, typename Strategy>
0800 struct default_strategy
0801 <
0802 point_tag, segment_tag, Point, PointOfSegment,
0803 spherical_equatorial_tag, spherical_equatorial_tag,
0804 Strategy
0805 >
0806 {
0807 using type = cross_track
0808 <
0809 void,
0810 std::conditional_t
0811 <
0812 std::is_void<Strategy>::value,
0813 typename default_strategy
0814 <
0815 point_tag, point_tag, Point, PointOfSegment,
0816 spherical_equatorial_tag, spherical_equatorial_tag
0817 >::type,
0818 Strategy
0819 >
0820 >;
0821 };
0822
0823
0824 template <typename PointOfSegment, typename Point, typename Strategy>
0825 struct default_strategy
0826 <
0827 segment_tag, point_tag, PointOfSegment, Point,
0828 spherical_equatorial_tag, spherical_equatorial_tag,
0829 Strategy
0830 >
0831 {
0832 using type = typename default_strategy
0833 <
0834 point_tag, segment_tag, Point, PointOfSegment,
0835 spherical_equatorial_tag, spherical_equatorial_tag,
0836 Strategy
0837 >::type;
0838 };
0839
0840
0841 }
0842 #endif
0843
0844 }}
0845
0846 }}
0847
0848 #endif