0001:
0002:
0003:
0004:
0005:
0006:
0007:
0008:
0009:
0010:
0011:
0012:
0013:
0014:
0015:
0016:
0017:
0018:
0019:
0020:
0021:
0022:
0023:
0024:
0025:
0026:
0027:
0028:
0029:
0030:
0031:
0032:
0033:
0034:
0035:
0036:
0037:
0038:
0039:
0040:
0041:
0042:
0043:
0044:
0045:
0046:
0047:
0048:
0049:
0050:
0051:
0052:
0053:
0054:
0055:
0056:
0057:
0058:
0059:
0060:
0061:
0062:
0063:
0064:
0065:
0066:
0067:
0068:
0069:
0070:
0071:
0072:
0073:
0074:
0075:
0076:
0077:
0078:
0079:
0080:
0081:
0082:
0083:
0084:
0085:
0086:
0087:
0088:
0089:
0090:
0091:
0092:
0093:
0094:
0095:
0096:
0097:
0098:
0099:
0100:
0101:
0102:
0103:
0104:
0105:
0106:
0107:
0108:
0109:
0110:
0111:
0112:
0113:
0114:
0115:
0116:
0117:
0118:
0119:
0120:
0121:
0122:
0123:
0124:
0125:
0126:
0127:
0128:
0129:
0130:
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:
0402:
0403:
0404:
0405:
0406:
0407:
0408:
0409:
0410:
0411:
0412:
0413:
0414:
0415:
0416:
0417:
0418:
0419:
0420:
0421:
0422:
0423:
0424:
0425:
0426:
0427:
0428:
0429:
0430:
0431:
0432:
0433:
0434:
0435:
0436:
0437:
0438:
0439:
0440:
0441:
0442:
0443:
0444:
0445:
0446:
0447:
0448:
0449:
0450:
0451:
0452:
0453:
0454:
0455:
0456:
0457:
0458:
0459:
0460:
0461:
0462:
0463:
0464:
0465:
0466:
0467:
0468:
0469:
0470:
0471:
0472:
0473:
0474:
0475:
0476:
0477:
0478:
0479:
0480:
0481:
0482:
0483:
0484:
0485:
0486:
0487:
0488:
0489:
0490:
0491:
0492:
0493:
0494:
0495:
0496:
0497:
0498:
0499:
0500:
0501:
0502:
0503:
0504:
0505:
0506:
0507:
0508:
0509:
0510:
0511:
0512:
0513:
0514:
0515:
0516:
0517:
0518:
0519:
0520:
0521:
0522:
0523:
0524:
0525:
0526:
0527:
0528:
0529:
0530:
0531:
0532:
0533:
0534:
0535:
0536:
0537:
0538:
0539:
0540:
0541:
0542:
0543:
0544:
0545:
0546:
0547:
0548:
0549:
0550:
0551:
0552:
0553:
0554:
0555:
0556:
0557:
0558:
0559:
0560:
0561:
0562:
0563:
0564:
0565:
0566:
0567:
0568:
0569:
0570:
0571:
0572:
0573:
0574:
0575:
0576:
0577:
0578:
0579:
0580:
0581:
0582:
0583:
0584:
0585:
0586:
0587:
0588:
0589:
0590:
0591:
0592:
0593:
0594:
0595:
0596:
0597:
0598:
0599:
0600:
0601:
0602:
0603:
0604:
0605:
0606:
0607:
0608:
0609:
0610:
0611:
0612:
0613:
0614:
0615:
0616:
0617:
0618:
0619:
0620:
0621:
0622:
0623:
0624:
0625:
0626:
0627:
0628:
0629:
0630:
0631:
0632:
0633:
0634:
0635:
0636:
0637:
0638:
0639:
0640:
0641:
0642:
0643:
0644:
0645:
0646:
0647:
0648:
0649:
0650:
0651:
0652:
0653:
0654:
0655:
0656:
0657:
0658:
0659:
0660:
0661:
0662:
0663:
0664:
0665:
0666:
0667:
0668:
0669:
0670:
0671:
0672:
0673:
0674:
0675:
0676:
0677:
0678:
0679:
0680:
0681:
0682:
0683:
0684:
0685:
0686:
0687:
0688:
0689:
0690:
0691:
0692:
0693:
0694:
0695:
0696:
0697:
0698:
0699:
0700:
0701:
0702:
0703:
0704:
0705:
0706:
0707:
0708:
0709:
0710:
0711:
0712:
0713:
0714:
0715:
0716:
0717:
0718:
0719:
0720:
0721:
0722:
0723:
0724:
0725:
0726:
0727:
0728:
0729:
0730:
0731:
0732:
0733:
0734:
0735:
0736:
0737:
0738:
0739:
0740:
0741:
0742:
0743:
0744:
0745:
0746:
0747:
0748:
0749:
0750:
0751:
0752:
0753:
0754:
0755:
0756:
0757:
0758:
0759:
0760:
0761:
0762:
0763:
0764:
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:
0800:
0801:
0802:
0803:
0804:
0805:
0806:
0807:
0808:
0809:
0810:
0811:
0812:
0813:
0814:
0815:
0816:
0817:
0818:
0819:
0820:
0821:
0822:
0823:
0824:
0825:
0826:
0827:
0828:
0829:
0830:
0831:
0832:
0833:
0834:
0835:
0836:
0837:
0838:
0839:
0840:
0841:
0842:
0843:
0844:
0845:
0846:
0847:
0848:
0849:
0850:
0851:
0852:
0853:
0854:
0855:
0856:
0857:
0858:
0859:
0860:
0861:
0862:
0863:
0864:
0865:
0866:
0867:
0868:
0869:
0870:
0871:
0872:
0873:
0874:
0875:
0876:
0877:
0878:
0879:
0880:
0881:
0882:
0883:
0884:
0885:
0886:
0887:
0888:
0889:
0890:
0891:
0892:
0893:
0894:
0895:
0896:
0897:
0898:
0899:
0900:
0901:
0902:
0903:
0904:
0905:
0906:
0907:
0908:
0909:
0910:
0911:
0912:
0913:
0914:
0915:
0916:
0917:
0918:
0919:
0920:
0921:
0922:
0923:
0924:
0925:
0926:
0927:
0928:
0929:
0930:
0931:
0932:
0933:
0934:
0935:
0936:
0937:
0938:
0939:
0940:
0941:
0942:
0943:
0944:
0945:
0946:
0947:
0948:
0949:
0950:
0951:
0952:
0953:
0954:
0955:
0956:
0957:
0958:
0959:
0960:
0961:
0962:
0963:
0964:
0965:
0966:
0967:
0968:
0969:
0970:
0971:
0972:
0973:
0974:
0975:
0976:
0977:
0978:
0979:
0980:
0981:
0982:
0983:
0984:
0985:
0986:
0987:
0988:
0989:
0990:
0991:
0992:
0993:
0994:
0995:
0996:
0997:
0998:
0999:
1000:
1001:
1002:
1003:
1004:
1005:
1006:
1007:
1008:
1009:
1010:
1011:
1012:
1013:
1014:
1015:
1016:
1017:
1018:
1019:
1020:
1021:
1022:
1023:
1024:
1025:
1026:
1027:
1028:
1029:
1030:
1031:
1032:
1033:
1034:
1035:
1036:
1037:
1038:
1039:
1040:
1041:
1042:
1043:
1044:
1045:
1046:
1047:
1048:
1049:
1050:
1051:
1052:
1053:
1054:
1055:
1056:
1057:
1058:
1059:
1060:
1061:
1062:
1063:
1064:
1065:
1066:
1067:
1068:
1069:
1070:
1071:
1072:
1073:
1074:
1075:
1076:
1077:
1078:
1079:
1080:
1081:
1082:
1083:
1084:
1085:
1086:
1087:
1088:
1089:
1090:
1091:
1092:
1093:
1094:
1095:
1096:
1097:
1098:
1099:
1100:
1101:
1102:
1103:
1104:
1105:
1106:
1107:
1108:
1109:
1110:
1111:
1112:
1113:
1114:
1115:
1116:
1117:
1118:
1119:
1120:
1121:
1122:
1123:
1124:
1125:
1126:
1127:
1128:
1129:
1130:
1131:
1132:
1133:
1134:
1135:
1136:
1137:
1138:
1139:
1140:
1141:
1142:
1143:
1144:
1145:
1146:
1147:
1148:
1149:
1150:
1151:
1152:
1153:
1154:
1155:
1156:
1157:
1158:
1159:
1160:
1161:
1162:
1163:
1164:
1165:
1166:
1167:
1168:
1169:
1170:
1171:
1172:
1173:
1174:
1175:
1176:
1177:
1178:
1179:
1180:
1181:
1182:
1183:
1184:
1185:
1186:
1187:
1188:
1189:
1190:
1191:
1192:
1193:
1194:
1195:
1196:
1197:
1198:
1199:
1200:
1201:
1202:
1203:
Min/Max


















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































/*
* Copyright (c), Zeriph Enterprises
* All rights reserved.
*
* Contributor(s):
* Zechariah Perez, omni (at) zeriph (dot) com
*
* THIS SOFTWARE IS PROVIDED BY ZERIPH AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ZERIPH AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if !defined(OMNI_QUADRILATERAL_HPP)
#define OMNI_QUADRILATERAL_HPP 1
#include <omni/defs/global.hpp>
#include <omni/defs/class_macros.hpp>
#include <omni/geometry/point2d.hpp>
#include <omni/geometry/circle.hpp>

#if defined(OMNI_SAFE_QUADRANGLE)
    #include <omni/sync/basic_lock.hpp>
    #define OMNI_SAFE_QUADRMTX_FW ,m_mtx()
    #define OMNI_SAFE_QUADRLOCK_FW this->m_mtx.lock();
    #define OMNI_SAFE_QUADRUNLOCK_FW this->m_mtx.unlock();
    #define OMNI_SAFE_QUADRALOCK_FW omni::sync::scoped_basic_lock uuid12345(&this->m_mtx);
    #define OMNI_SAFE_QUADROALOCK_FW(o) omni::sync::scoped_basic_lock uuid54321(&o.m_mtx);
#else
    #define OMNI_SAFE_QUADRMTX_FW
    #define OMNI_SAFE_QUADRLOCK_FW
    #define OMNI_SAFE_QUADRUNLOCK_FW
    #define OMNI_SAFE_QUADRALOCK_FW
    #define OMNI_SAFE_QUADROALOCK_FW(o)
#endif

#if defined(OMNI_QUADRILATERAL_USE_SA)
    #define OMNI_QUADR_SA_FW ,m_sides(), m_angle()
    #define OMNI_QUADR_SACP_FW(cp) ,m_sides(cp.m_sides), m_angle(cp.m_angle)
    #define OMNI_QUADR_SA_CALC_FW this->_recalc_sas()
#else
    #define OMNI_QUADR_SA_FW
    #define OMNI_QUADR_SACP_FW(cp)
    #define OMNI_QUADR_SA_CALC_FW
#endif

// DEV_NOTE: overflows are not checked in this class due to double's and raw_point2d's being used, no need to check for overflow

namespace omni {
    namespace geometry {
        template < typename T >
        class quadrilateral
        {
            public:
                typedef T coordinate_t;
                typedef omni_sequence_t< omni::geometry::point2d< T > > path_t;

                quadrilateral() :
                    OMNI_CTOR_FW(omni::geometry::quadrilateral<T>)
                    m_a(), m_b(), m_c(), m_d()
                    OMNI_QUADR_SA_FW
                    OMNI_SAFE_QUADRMTX_FW
                { }

                quadrilateral(const omni::geometry::quadrilateral<T>& cp) :
                    OMNI_CPCTOR_FW(cp)
                    m_a(cp.a()), m_b(cp.b()), m_c(cp.c()), m_d(cp.d())
                    OMNI_QUADR_SACP_FW(cp)
                    OMNI_SAFE_QUADRMTX_FW
                { }

                OMNI_EXPLICIT quadrilateral(const omni::math::dimensional<T, 8>& cp) :
                    OMNI_CTOR_FW(omni::geometry::quadrilateral<T>)
                    m_a(cp[0], cp[1]), m_b(cp[2], cp[3]), m_c(cp[4], cp[5]), m_d(cp[6], cp[7])
                    OMNI_QUADR_SA_FW
                    OMNI_SAFE_QUADRMTX_FW
                {
                    OMNI_QUADR_SA_CALC_FW
                }

                quadrilateral(const omni::math::dimensional<T, 2>& a, const omni::math::dimensional<T, 2>& b, const omni::math::dimensional<T, 2>& c, const omni::math::dimensional<T, 2>& d) :
                    OMNI_CTOR_FW(omni::geometry::quadrilateral<T>)
                    m_a(a[0], a[1]), m_b(b[0], b[1]), m_c(c[0], c[1]), m_d(d[0], d[1])
                    OMNI_QUADR_SA_FW
                    OMNI_SAFE_QUADRMTX_FW
                {
                    OMNI_QUADR_SA_CALC_FW
                }

                quadrilateral(const omni::geometry::point2d<T>& a, const omni::geometry::point2d<T>& b, const omni::geometry::point2d<T>& c, const omni::geometry::point2d<T>& d) :
                    OMNI_CTOR_FW(omni::geometry::quadrilateral<T>)
                    m_a(a.x(), a.y()), m_b(b.x(), b.y()), m_c(c.x(), c.y()), m_d(d.x(), d.y())
                    OMNI_QUADR_SA_FW
                    OMNI_SAFE_QUADRMTX_FW
                {
                    OMNI_QUADR_SA_CALC_FW
                }

                quadrilateral(const omni::geometry::raw_point2d<T>& a, const omni::geometry::raw_point2d<T>& b, const omni::geometry::raw_point2d<T>& c, const omni::geometry::raw_point2d<T>& d) :
                    OMNI_CTOR_FW(omni::geometry::quadrilateral<T>)
                    m_a(a.x, a.y), m_b(b.x, b.y), m_c(c.x, c.y), m_d(d.x, d.y)
                    OMNI_QUADR_SA_FW
                    OMNI_SAFE_QUADRMTX_FW
                {
                    OMNI_QUADR_SA_CALC_FW
                }

                quadrilateral(T x1, T y1, T x2, T y2, T x3, T y3, T x4, T y4) :
                    OMNI_CTOR_FW(omni::geometry::quadrilateral<T>)
                    m_a(x1, y1), m_b(x2, y2), m_c(x3, y3), m_d(x4, y4)
                    OMNI_QUADR_SA_FW
                    OMNI_SAFE_QUADRMTX_FW
                {
                    OMNI_QUADR_SA_CALC_FW
                }

                ~quadrilateral()
                {
                    OMNI_TRY_FW
                    OMNI_DTOR_FW
                    OMNI_CATCH_FW
                    OMNI_D5_FW("destroyed");
                }

                omni::geometry::raw_point2d<T> a() const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    return this->m_a;
                }

                double angle_a() const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    return this->_angle_a();
                }

                double angle_b() const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    return this->_angle_b();
                }

                double angle_c() const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    return this->_angle_c();
                }

                double angle_d() const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    return this->_angle_d();
                }

                double area() const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    return this->_area();
                }

                omni::geometry::raw_point2d<T> b() const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    return this->m_b;
                }

                double base() const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    return this->_base();
                }

                omni::geometry::raw_point2d<T> c() const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    return this->m_c;
                }

                omni::geometry::point2d<double> centroid() const
                {
                    double x, y;
                    OMNI_SAFE_QUADRALOCK_FW
                    omni::math::quadrilateral_get_centroid<double>(
                        this->m_a.x, this->m_a.y,
                        this->m_b.x, this->m_b.y,
                        this->m_c.x, this->m_c.y,
                        this->m_d.x, this->m_d.y,
                        x, y);
                    return omni::geometry::point2d<double>(x, y);
                }
                
                omni::geometry::point2d<double> circumcenter() const
                {
                    double x, y;
                    OMNI_SAFE_QUADRALOCK_FW
                    omni::math::quadrilateral_get_circumcenter<double>(
                        this->m_a.x, this->m_a.y,
                        this->m_b.x, this->m_b.y,
                        this->m_c.x, this->m_c.y,
                        this->m_d.x, this->m_d.y,
                        x, y);
                    return omni::geometry::point2d<double>(x, y);
                }

                omni::geometry::circle<double> circle_from_circumcenter() const
                {
                    double x, y;
                    OMNI_SAFE_QUADRALOCK_FW
                    omni::math::quadrilateral_get_circumcenter<double>(
                        this->m_a.x, this->m_a.y,
                        this->m_b.x, this->m_b.y,
                        this->m_c.x, this->m_c.y,
                        this->m_d.x, this->m_d.y,
                        x, y
                    );
                    double a = this->_side_a();
                    double b = this->_side_b();
                    double c = this->_side_c();
                    double d = this->_side_d();
                    return omni::geometry::circle<double>(x, y,
                        ((a * b * c * d) / std::sqrt(
                            (a + b + c + d) *
                            (b + c + d - a) *
                            (c + d + a - b) *
                            (d + a + b - c) *
                            (a + b + c - d)
                        ))
                    );
                }

                omni::geometry::circle<double> circle_from_incenter() const
                {
                    double x, y;
                    OMNI_SAFE_QUADRALOCK_FW
                    omni::math::quadrilateral_get_incenter<double>(
                        this->m_a.x, this->m_a.y,
                        this->m_b.x, this->m_b.y,
                        this->m_c.x, this->m_c.y,
                        this->m_d.x, this->m_d.y,
                        x, y
                    );
                    return omni::geometry::circle<double>(x, y,
                        (
                            (this->_area() * 2.0) /
                            (this->_side_a() + this->_side_b() + this->_side_c() + this->_side_d())
                        )
                    );
                }

                omni::math::shape_comparator compare(const omni::geometry::quadrilateral<T>& quad) const
                {
                    if (this == &quad) { return omni::math::shape_comparator::SIMILAR_CONGRUENT; }
                    omni::math::shape_comparator ret = omni::math::shape_comparator::NOT_EQUAL;
                    OMNI_SAFE_QUADRALOCK_FW
                    OMNI_SAFE_QUADROALOCK_FW(quad)
                    double ta = this->_angle_a(); double oa = quad._angle_a();
                    double tb = this->_angle_b(); double ob = quad._angle_b();
                    double tc = this->_angle_c(); double oc = quad._angle_c();
                    double td = this->_angle_d(); double od = quad._angle_d();

                    if (
                        // a
                        (omni::math::are_equal(ta, oa) || omni::math::are_equal(ta, ob) || omni::math::are_equal(ta, oc) || omni::math::are_equal(ta, od)) &&
                        // b
                        (omni::math::are_equal(tb, oa) || omni::math::are_equal(tb, ob) || omni::math::are_equal(tb, oc) || omni::math::are_equal(tb, od)) &&
                        // c
                        (omni::math::are_equal(tc, oa) || omni::math::are_equal(tc, ob) || omni::math::are_equal(tc, oc) || omni::math::are_equal(tc, od)) &&
                        // d
                        (omni::math::are_equal(td, oa) || omni::math::are_equal(td, ob) || omni::math::are_equal(td, oc) || omni::math::are_equal(td, od))
                    )
                    {
                        ret = omni::math::shape_comparator::SIMILAR;
                    }
                    
                    ta = this->_side_a(); oa = quad._side_a();
                    tb = this->_side_b(); ob = quad._side_b();
                    tc = this->_side_c(); oc = quad._side_c();
                    td = this->_side_d(); od = quad._side_d();

                    if (
                        // a
                        (omni::math::are_equal(ta, oa) || omni::math::are_equal(ta, ob) || omni::math::are_equal(ta, oc) || omni::math::are_equal(ta, od)) &&
                        // b
                        (omni::math::are_equal(tb, oa) || omni::math::are_equal(tb, ob) || omni::math::are_equal(tb, oc) || omni::math::are_equal(tb, od)) &&
                        // c
                        (omni::math::are_equal(tc, oa) || omni::math::are_equal(tc, ob) || omni::math::are_equal(tc, oc) || omni::math::are_equal(tc, od)) &&
                        // d
                        (omni::math::are_equal(td, oa) || omni::math::are_equal(td, ob) || omni::math::are_equal(td, oc) || omni::math::are_equal(td, od))
                    )
                    {
                        ret |= omni::math::shape_comparator::CONGRUENT;
                    }

                    return ret;
                }

                bool contains(T x, T y) const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    return omni::math::quadrilateral_contains_point(
                        x, y,
                        this->m_a.x, this->m_a.y,
                        this->m_b.x, this->m_b.y,
                        this->m_c.x, this->m_c.y,
                        this->m_d.x, this->m_d.y
                    );
                }

                bool contains(const omni::math::dimensional<T, 2>& point) const
                {
                    return this->contains(point[0], point[1]);
                }

                bool contains(const omni::geometry::point2d<T>& point) const
                {
                    return this->contains(point.x(), point.y());
                }

                bool contains(const omni::geometry::raw_point2d<T>& point) const
                {
                    return this->contains(point.x, point.y);
                }

                bool contains(const omni::geometry::quadrilateral<T>& quad) const
                {
                    if (&quad == this) { return true; }
                    OMNI_SAFE_QUADRALOCK_FW
                    OMNI_SAFE_QUADROALOCK_FW(quad)
                    return
                        omni::math::quadrilateral_contains_point(
                            quad.m_a.x, quad.m_a.y,
                            this->m_a.x, this->m_a.y,
                            this->m_b.x, this->m_b.y,
                            this->m_c.x, this->m_c.y,
                            this->m_d.x, this->m_d.y
                        ) &&
                        omni::math::quadrilateral_contains_point(
                            quad.m_b.x, quad.m_b.y,
                            this->m_a.x, this->m_a.y,
                            this->m_b.x, this->m_b.y,
                            this->m_c.x, this->m_c.y,
                            this->m_d.x, this->m_d.y
                        ) &&
                        omni::math::quadrilateral_contains_point(
                            quad.m_c.x, quad.m_c.y,
                            this->m_a.x, this->m_a.y,
                            this->m_b.x, this->m_b.y,
                            this->m_c.x, this->m_c.y,
                            this->m_d.x, this->m_d.y
                        ) &&
                        omni::math::quadrilateral_contains_point(
                            quad.m_d.x, quad.m_d.y,
                            this->m_a.x, this->m_a.y,
                            this->m_b.x, this->m_b.y,
                            this->m_c.x, this->m_c.y,
                            this->m_d.x, this->m_d.y
                        );
                }

                omni::geometry::raw_point2d<T> d() const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    return this->m_d;
                }

                omni::geometry::quadrilateral<T>& deflate(double percent)
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    double factor = (1.0 - (percent / 100.0));
                    double x, y;
                    omni::math::quadrilateral_get_incenter<double>(
                        this->m_a.x, this->m_a.y,
                        this->m_b.x, this->m_b.y,
                        this->m_c.x, this->m_c.y,
                        this->m_d.x, this->m_d.y,
                        x, y);
                    omni::math::extend_line<double>(x, y, this->m_a.x, this->m_a.y, (omni::math::distance_between_2_points(x, y, this->m_a.x, this->m_a.y) * factor), this->m_a.x, this->m_a.y);
                    omni::math::extend_line<double>(x, y, this->m_b.x, this->m_b.y, (omni::math::distance_between_2_points(x, y, this->m_b.x, this->m_b.y) * factor), this->m_b.x, this->m_b.y);
                    omni::math::extend_line<double>(x, y, this->m_c.x, this->m_c.y, (omni::math::distance_between_2_points(x, y, this->m_c.x, this->m_c.y) * factor), this->m_c.x, this->m_c.y);
                    omni::math::extend_line<double>(x, y, this->m_d.x, this->m_d.y, (omni::math::distance_between_2_points(x, y, this->m_d.x, this->m_d.y) * factor), this->m_d.x, this->m_d.y);
                    OMNI_QUADR_SA_CALC_FW
                    return *this;
                }

                bool empty() const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    return this->m_a.empty() &&
                         this->m_b.empty() &&
                         this->m_c.empty() &&
                         this->m_d.empty()
                    #if defined(OMNI_QUADRILATERAL_USE_SA)
                        &&
                        omni::math::are_equal(m_sides[0], 0) &&
                        omni::math::are_equal(m_sides[1], 0) &&
                        omni::math::are_equal(m_sides[2], 0) &&
                        omni::math::are_equal(m_sides[3], 0) &&

                        omni::math::are_equal(m_angle[0], 0) &&
                        omni::math::are_equal(m_angle[1], 0) &&
                        omni::math::are_equal(m_angle[2], 0) &&
                        omni::math::are_equal(m_angle[3], 0)
                    #endif
                    ;
                }

                bool equals(T ax, T ay, T bx, T by, T cx, T cy, T dx, T dy) const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    return
                        omni::math::are_equal(this->m_a.x, ax) &&
                        omni::math::are_equal(this->m_a.y, ay) &&
                        omni::math::are_equal(this->m_b.x, bx) &&
                        omni::math::are_equal(this->m_b.y, by) &&
                        omni::math::are_equal(this->m_c.x, cx) &&
                        omni::math::are_equal(this->m_c.y, cy) &&
                        omni::math::are_equal(this->m_d.x, dx) &&
                        omni::math::are_equal(this->m_d.y, dy);
                }

                bool equals(const omni::math::dimensional<T, 2>& a, const omni::math::dimensional<T, 2>& b, const omni::math::dimensional<T, 2>& c, const omni::math::dimensional<T, 2>& d) const
                {
                    return this->equals(a[0], a[1], b[0], b[1], c[0], c[1], d[0], d[1]);
                }

                bool equals(const omni::geometry::point2d<T>& a, const omni::geometry::point2d<T>& b, const omni::geometry::point2d<T>& c, const omni::geometry::point2d<T>& d) const
                {
                    return this->equals(a.x(), a.y(), b.x(), b.y(), c.x(), c.y(), d.x(), d.y());
                }

                bool equals(const omni::geometry::raw_point2d<T>& a, const omni::geometry::raw_point2d<T>& b, const omni::geometry::raw_point2d<T>& c, const omni::geometry::raw_point2d<T>& d) const
                {
                    return this->equals(a.x, a.y, b.x, b.y, c.x, c.y, d.x, d.y);
                }

                int32_t hash_code() const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    return (
                        m_a.hash_code() ^ m_b.hash_code() ^ m_c.hash_code() ^ m_d.hash_code()
                    );
                }

                double height() const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    return (this->_area() * 2.0) / this->_base();
                }

                omni::geometry::point2d<double> incenter() const
                {
                    double x, y;
                    OMNI_SAFE_QUADRALOCK_FW
                    omni::math::quadrilateral_get_incenter<double>(
                        this->m_a.x, this->m_a.y,
                        this->m_b.x, this->m_b.y,
                        this->m_c.x, this->m_c.y,
                        this->m_d.x, this->m_d.y,
                        x, y);
                    return omni::geometry::point2d<double>(x, y);
                }

                void inflate(double percent)
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    double factor = percent / 100.0;
                    double x, y;
                    omni::math::quadrilateral_get_incenter<double>(
                        this->m_a.x, this->m_a.y,
                        this->m_b.x, this->m_b.y,
                        this->m_c.x, this->m_c.y,
                        this->m_d.x, this->m_d.y,
                        x, y);
                    omni::math::extend_line<double>(x, y, this->m_a.x, this->m_a.y, (omni::math::distance_between_2_points(x, y, this->m_a.x, this->m_a.y) * factor), this->m_a.x, this->m_a.y);
                    omni::math::extend_line<double>(x, y, this->m_b.x, this->m_b.y, (omni::math::distance_between_2_points(x, y, this->m_b.x, this->m_b.y) * factor), this->m_b.x, this->m_b.y);
                    omni::math::extend_line<double>(x, y, this->m_c.x, this->m_c.y, (omni::math::distance_between_2_points(x, y, this->m_c.x, this->m_c.y) * factor), this->m_c.x, this->m_c.y);
                    omni::math::extend_line<double>(x, y, this->m_d.x, this->m_d.y, (omni::math::distance_between_2_points(x, y, this->m_d.x, this->m_d.y) * factor), this->m_d.x, this->m_d.y);
                    OMNI_QUADR_SA_CALC_FW
                }

                omni::geometry::quadrilateral<T>& intersect(const omni::geometry::quadrilateral<T>& quad)
                {
                    if (this == &quad) { return *this; }
                    OMNI_SAFE_QUADRALOCK_FW
                    OMNI_SAFE_QUADROALOCK_FW(quad)
                    if (this->_intersects_with(quad.m_a.x, quad.m_a.y, quad.m_b.x, quad.m_b.y,
                                             quad.m_c.x, quad.m_c.y, quad.m_d.x, quad.m_d.y))
                    {
                        if (this->m_a.x < quad.m_a.x) { this->m_a.x = quad.m_a.x; }
                        if (this->m_a.y < quad.m_a.y) { this->m_a.y = quad.m_a.y; }
                        if (this->m_b.x < quad.m_b.x) { this->m_b.x = quad.m_b.x; }
                        if (this->m_b.y < quad.m_b.y) { this->m_b.y = quad.m_b.y; }
                        if (this->m_c.x < quad.m_c.x) { this->m_c.x = quad.m_c.x; }
                        if (this->m_c.y < quad.m_c.y) { this->m_c.y = quad.m_c.y; }
                        if (this->m_d.x < quad.m_d.x) { this->m_d.x = quad.m_d.x; }
                        if (this->m_d.y < quad.m_d.y) { this->m_d.y = quad.m_d.y; }
                        OMNI_QUADR_SA_CALC_FW
                    } else {
                        this->m_a.x = 0; this->m_a.y = 0;
                        this->m_b.x = 0; this->m_b.y = 0;
                        this->m_c.x = 0; this->m_c.y = 0;
                        this->m_d.x = 0; this->m_d.y = 0;
                        #if defined(OMNI_QUADRILATERAL_USE_SA)
                            std::memset(this->m_sides, 0, sizeof(this->m_sides));
                            std::memset(this->m_angle, 0, sizeof(this->m_angle));
                        #endif
                    }
                    return *this;
                }

                bool intersects_with(const omni::geometry::quadrilateral<T>& quad) const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    OMNI_SAFE_QUADROALOCK_FW(quad)
                    return this->_intersects_with(
                        quad.m_a.x, quad.m_a.y,
                        quad.m_b.x, quad.m_b.y,
                        quad.m_c.x, quad.m_c.y,
                        quad.m_d.x, quad.m_d.y
                    );
                }

                bool is_kite() const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    return (
                        (
                            omni::math::are_equal(this->_angle_a(), this->_angle_c()) &&
                            omni::math::are_equal(this->_angle_b(), this->_angle_d())
                        ) && (
                            omni::math::are_equal(this->_side_a(), this->_side_d()) &&
                            omni::math::are_equal(this->_angle_b(), this->_side_c())
                        )
                    );
                }

                bool is_parallelogram() const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    return (
                        (
                            omni::math::are_equal(this->_angle_a(), this->_angle_c()) &&
                            omni::math::are_equal(this->_angle_b(), this->_angle_d())
                        ) && (
                            omni::math::are_equal(this->_side_a(), this->_side_c()) &&
                            omni::math::are_equal(this->_angle_b(), this->_side_d())
                        )
                    );
                }

                bool is_rectangle() const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    return (
                        (
                            omni::math::are_equal(this->_angle_a(), 90.0) &&
                            omni::math::are_equal(this->_angle_b(), 90.0) &&
                            omni::math::are_equal(this->_angle_c(), 90.0) &&
                            omni::math::are_equal(this->_angle_d(), 90.0)
                        ) &&
                        (
                            (omni::math::are_equal(this->_side_a(), this->_side_b()) ||
                            omni::math::are_equal(this->_angle_a(), this->_side_c()) ||
                            omni::math::are_equal(this->_angle_a(), this->_side_d()))
                            &&
                            (omni::math::are_equal(this->_side_b(), this->_side_a()) ||
                            omni::math::are_equal(this->_angle_b(), this->_side_c()) ||
                            omni::math::are_equal(this->_angle_b(), this->_side_d()))
                            &&
                            (omni::math::are_equal(this->_side_c(), this->_side_a()) ||
                            omni::math::are_equal(this->_angle_c(), this->_side_b()) ||
                            omni::math::are_equal(this->_angle_c(), this->_side_d()))
                            &&
                            (omni::math::are_equal(this->_side_d(), this->_side_a()) ||
                            omni::math::are_equal(this->_angle_d(), this->_side_b()) ||
                            omni::math::are_equal(this->_angle_d(), this->_side_c()))
                        )
                    );
                }

                bool is_rhombus() const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    return (
                        (
                            omni::math::are_equal(this->_angle_a(), this->_angle_c()) &&
                            omni::math::are_equal(this->_angle_b(), this->_angle_d())
                        ) &&
                        (
                            omni::math::are_equal(this->_side_a(), this->_side_b()) &&
                            omni::math::are_equal(this->_angle_a(), this->_side_c()) &&
                            omni::math::are_equal(this->_angle_a(), this->_side_d())
                        )
                    );
                }

                bool is_square() const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    return (
                        (
                            omni::math::are_equal(this->_angle_a(), 90.0) &&
                            omni::math::are_equal(this->_angle_b(), 90.0) &&
                            omni::math::are_equal(this->_angle_c(), 90.0) &&
                            omni::math::are_equal(this->_angle_d(), 90.0)
                        ) &&
                        (
                            omni::math::are_equal(this->_side_a(), this->_side_b()) &&
                            omni::math::are_equal(this->_angle_a(), this->_side_c()) &&
                            omni::math::are_equal(this->_angle_a(), this->_side_d())
                        )
                    );
                }

                bool is_trapezoid() const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    return (
                        omni::math::are_equal(
                            omni::math::slope(this->m_a.x, this->m_a.y, this->m_b.x, this->m_b.y),
                            omni::math::slope(this->m_c.x, this->m_c.y, this->m_d.x, this->m_d.y)
                        ) ||
                        omni::math::are_equal(
                            omni::math::slope(this->m_b.x, this->m_b.y, this->m_c.x, this->m_c.y),
                            omni::math::slope(this->m_d.x, this->m_d.y, this->m_a.x, this->m_a.y)
                        )
                    );
                }

                path_t path() const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    return omni::geometry::path::quadrilateral(
                        this->m_a.x, this->m_a.y,
                        this->m_b.x, this->m_b.y,
                        this->m_c.x, this->m_c.y,
                        this->m_d.x, this->m_d.y
                    );
                }

                double perimeter() const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    return this->_side_a() + this->_side_b() + this->_side_c() + this->_side_d();
                }

                omni::geometry::quadrilateral<T>& rotate_on_a(double degrees, const omni::math::rotation_direction& dir)
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    omni::math::quadrilateral_rotate_abcd(
                        degrees, this->m_a.x, this->m_a.y, dir,
                        this->m_b.x, this->m_b.y,
                        this->m_c.x, this->m_c.y,
                        this->m_d.x, this->m_d.y
                    );
                    return *this;
                }

                omni::geometry::quadrilateral<T>& rotate_on_b(double degrees, const omni::math::rotation_direction& dir)
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    omni::math::quadrilateral_rotate_abcd(
                        degrees, this->m_b.x, this->m_b.y, dir,
                        this->m_a.x, this->m_a.y,
                        this->m_c.x, this->m_c.y,
                        this->m_d.x, this->m_d.y
                    );
                    return *this;
                }

                omni::geometry::quadrilateral<T>& rotate_on_c(double degrees, const omni::math::rotation_direction& dir)
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    omni::math::quadrilateral_rotate_abcd(
                        degrees, this->m_c.x, this->m_c.y, dir,
                        this->m_a.x, this->m_a.y,
                        this->m_b.x, this->m_b.y,
                        this->m_d.x, this->m_d.y
                    );
                    return *this;
                }

                omni::geometry::quadrilateral<T>& rotate_on_d(double degrees, const omni::math::rotation_direction& dir)
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    omni::math::quadrilateral_rotate_abcd(
                        degrees, this->m_d.x, this->m_d.y, dir,
                        this->m_a.x, this->m_a.y,
                        this->m_b.x, this->m_b.y,
                        this->m_c.x, this->m_c.y
                    );
                    return *this;
                }

                omni::geometry::quadrilateral<T>& rotate_centroid(double degrees, const omni::math::rotation_direction& dir)
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    omni::math::quadrilateral_rotate_centroid(
                        degrees, dir,
                        this->m_a.x, this->m_a.y,
                        this->m_b.x, this->m_b.y,
                        this->m_c.x, this->m_c.y,
                        this->m_d.x, this->m_d.y
                    );
                    return *this;
                }

                omni::geometry::quadrilateral<T>& rotate_circumcenter(double degrees, const omni::math::rotation_direction& dir)
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    omni::math::quadrilateral_rotate_circumcenter(
                        degrees, dir,
                        this->m_a.x, this->m_a.y,
                        this->m_b.x, this->m_b.y,
                        this->m_c.x, this->m_c.y,
                        this->m_d.x, this->m_d.y
                    );
                    return *this;
                }

                omni::geometry::quadrilateral<T>& rotate_incenter(double degrees, const omni::math::rotation_direction& dir)
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    omni::math::quadrilateral_rotate_incenter(
                        degrees, dir,
                        this->m_a.x, this->m_a.y,
                        this->m_b.x, this->m_b.y,
                        this->m_c.x, this->m_c.y,
                        this->m_d.x, this->m_d.y
                    );
                    return *this;
                }

                omni::geometry::quadrilateral<T>& rotate_origin(double degrees, const omni::math::rotation_direction& dir)
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    omni::math::quadrilateral_rotate_origin(
                        degrees, dir,
                        this->m_a.x, this->m_a.y,
                        this->m_b.x, this->m_b.y,
                        this->m_c.x, this->m_c.y,
                        this->m_d.x, this->m_d.y
                    );
                    return *this;
                }

                omni::geometry::quadrilateral<T>& rotate_point(double degrees, T x, T y, const omni::math::rotation_direction& dir)
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    omni::math::quadrilateral_rotate_point(
                        degrees, x, y, dir,
                        this->m_a.x, this->m_a.y,
                        this->m_b.x, this->m_b.y,
                        this->m_c.x, this->m_c.y,
                        this->m_d.x, this->m_d.y
                    );
                    return *this;
                }

                omni::geometry::quadrilateral<T>& reflect()
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    omni::math::quadrilateral_reflect(
                        this->m_a.x, this->m_a.y,
                        this->m_b.x, this->m_b.y,
                        this->m_c.x, this->m_c.y,
                        this->m_d.x, this->m_d.y
                    );
                    return *this;
                }

                double side_a() const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    return this->_side_a();
                }

                double side_b() const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    return this->_side_b();
                }

                double side_c() const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    return this->_side_c();
                }

                double side_d() const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    return this->_side_d();
                }

                void swap(quadrilateral<T>& o)
                {
                    if (this != &o) {
                        OMNI_SAFE_QUADRALOCK_FW
                        OMNI_SAFE_QUADROALOCK_FW(o)
                        std::swap(this->m_a, o.m_a);
                        std::swap(this->m_b, o.m_b);
                        std::swap(this->m_c, o.m_c);
                        std::swap(this->m_d, o.m_d);
                        #if defined(OMNI_QUADRILATERAL_USE_SA)
                            std::swap(this->m_sides, o.m_sides);
                            std::swap(this->m_angle, o.m_angle);
                        #endif
                    }
                }

                omni::geometry::quadrilateral<T>& translate_xy(T x, T y)
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    omni::math::quadrilateral_translate_xy(
                        x, y,
                        this->m_a.x, this->m_a.y,
                        this->m_b.x, this->m_b.y,
                        this->m_c.x, this->m_c.y,
                        this->m_d.x, this->m_d.y
                    );
                    return *this;
                }

                omni::geometry::quadrilateral<T>& translate_angle(float angle, T distance)
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    omni::math::quadrilateral_translate_angle(
                        angle, distance,
                        this->m_a.x, this->m_a.y,
                        this->m_b.x, this->m_b.y,
                        this->m_c.x, this->m_c.y,
                        this->m_d.x, this->m_d.y
                    );
                    return *this;
                }

                omni::string_t to_string_t() const
                {
                    omni::sstream_t s;
                    OMNI_SAFE_QUADRALOCK_FW
                    s << "{[A:" << this->m_a << "],[B:" << this->m_b << "],[C:" << this->m_c << "],[D:" << this->m_d << "]}";
                    return s.str();
                }

                std::string to_string() const
                {
                    std::stringstream s;
                    OMNI_SAFE_QUADRALOCK_FW
                    s << "{[A:" << this->m_a << "],[B:" << this->m_b << "],[C:" << this->m_c << "],[D:" << this->m_d << "]}";
                    return s.str();
                }

                std::wstring to_wstring() const
                {
                    std::wstringstream s;
                    OMNI_SAFE_QUADRALOCK_FW
                    s << "{[A:" << this->m_a << "],[B:" << this->m_b << "],[C:" << this->m_c << "],[D:" << this->m_d << "]}";
                    return s.str();
                }

                operator std::string() const
                {
                    return this->to_string();
                }

                operator std::wstring() const
                {
                    return this->to_wstring();
                }
                
                bool operator!=(const omni::geometry::quadrilateral<T>& val) const
                {
                    return !(*this == val);
                }

                bool operator==(const omni::geometry::quadrilateral<T>& val) const
                {
                    if (this == &val) { return true; }
                    OMNI_SAFE_QUADRALOCK_FW
                    OMNI_SAFE_QUADROALOCK_FW(val)
                    return (
                        (this->m_a == val.m_a) &&
                        (this->m_b == val.m_b) &&
                        (this->m_c == val.m_c) &&
                        (this->m_d == val.m_d))
                    OMNI_EQUAL_FW(val);
                }

                omni::geometry::quadrilateral<T>& operator=(const omni::geometry::quadrilateral<T>& val)
                {
                    if (this != &val) {
                        OMNI_SAFE_QUADRALOCK_FW
                        OMNI_SAFE_QUADROALOCK_FW(val)
                        OMNI_ASSIGN_FW(val)
                        this->m_a = val.m_a;
                        this->m_b = val.m_b;
                        this->m_c = val.m_c;
                        this->m_d = val.m_d;
                        OMNI_QUADR_SA_CALC_FW
                    }
                    return *this;
                }

                bool operator<(const omni::geometry::quadrilateral<T>& val) const
                {
                    if (this == &val) { return false; }
                    OMNI_SAFE_QUADRALOCK_FW
                    OMNI_SAFE_QUADROALOCK_FW(val)
                    return (this->m_a < val.m_a) &&
                         (this->m_b < val.m_b) &&
                         (this->m_c < val.m_c) &&
                         (this->m_d < val.m_d);
                }

                bool operator<=(const omni::geometry::quadrilateral<T>& val) const
                {
                    if (this == &val) { return false; }
                    OMNI_SAFE_QUADRALOCK_FW
                    OMNI_SAFE_QUADROALOCK_FW(val)
                    return (this->m_a <= val.m_a) &&
                         (this->m_b <= val.m_b) &&
                         (this->m_c <= val.m_c) &&
                         (this->m_d <= val.m_d);
                }

                bool operator>(const omni::geometry::quadrilateral<T>& val) const
                {
                    if (this == &val) { return false; }
                    OMNI_SAFE_QUADRALOCK_FW
                    OMNI_SAFE_QUADROALOCK_FW(val)
                    return (this->m_a > val.m_a) &&
                         (this->m_b > val.m_b) &&
                         (this->m_c > val.m_c) &&
                         (this->m_d > val.m_d);
                }

                bool operator>=(const omni::geometry::quadrilateral<T>& val) const
                {
                    if (this == &val) { return false; }
                    OMNI_SAFE_QUADRALOCK_FW
                    OMNI_SAFE_QUADROALOCK_FW(val)
                    return (this->m_a >= val.m_a) &&
                         (this->m_b >= val.m_b) &&
                         (this->m_c >= val.m_c) &&
                         (this->m_d >= val.m_d);
                }

                omni::geometry::quadrilateral<T> operator+(const omni::geometry::point2d<T>& val) const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    omni::geometry::quadrilateral<T> ret(*this);
                    ret.translate_xy(val.x(), val.y());
                    return ret;
                }

                omni::geometry::quadrilateral<T> operator-(const omni::geometry::point2d<T>& val) const
                {
                    OMNI_SAFE_QUADRALOCK_FW
                    omni::geometry::quadrilateral<T> ret(*this);
                    ret.translate_xy(-val.x(), -val.y());
                    return ret;
                }

                omni::geometry::quadrilateral<T>& operator+=(const omni::geometry::point2d<T>& val)
                {
                    this->translate_xy(val.x(), val.y());
                    return *this;
                }

                omni::geometry::quadrilateral<T>& operator-=(const omni::geometry::point2d<T>& val)
                {
                    this->translate_xy(val.x(), val.y());
                    return *this;
                }

                static omni::geometry::quadrilateral<T> deflate(const omni::geometry::quadrilateral<T>& quad, double percent)
                {
                    return omni::geometry::quadrilateral<T>(quad, percent, true);
                }

                static omni::geometry::quadrilateral<T> inflate(const omni::geometry::quadrilateral<T>& quad, double percent)
                {
                    return omni::geometry::quadrilateral<T>(quad, percent, false);
                }

                static omni::geometry::quadrilateral<T> intersect(const omni::geometry::quadrilateral<T>& a, const omni::geometry::quadrilateral<T>& b)
                {
                    return omni::geometry::quadrilateral<T>(a, b);
                }

                OMNI_MEMBERS_FW(omni::geometry::quadrilateral<T>) // disposing,name,type(),hash()

                OMNI_OSTREAM_FW(omni::geometry::quadrilateral<T>)

            private:
                omni::geometry::raw_point2d<T> m_a;
                omni::geometry::raw_point2d<T> m_b;
                omni::geometry::raw_point2d<T> m_c;
                omni::geometry::raw_point2d<T> m_d;
                #if defined(OMNI_QUADRILATERAL_USE_SA)
                    double m_sides[4];
                    double m_angle[4];
                #endif
                #if defined(OMNI_SAFE_QUADRANGLE)
                    mutable omni::sync::basic_lock m_mtx;
                #endif

                quadrilateral(const omni::geometry::quadrilateral<T>& a, const omni::geometry::quadrilateral<T>& b) :
                    OMNI_CTOR_FW(omni::geometry::quadrilateral<T>)
                    m_a(a.a()), m_b(a.b()), m_c(a.c()), m_d(a.d())
                    OMNI_QUADR_SA_FW
                    OMNI_SAFE_QUADRMTX_FW
                {
                    this->intersect(b);
                }

                quadrilateral(const omni::geometry::quadrilateral<T>& a, double percent, bool deflate) :
                    OMNI_CTOR_FW(omni::geometry::quadrilateral<T>)
                    m_a(a.a()), m_b(a.b()), m_c(a.c()), m_d(a.d())
                    OMNI_QUADR_SA_FW
                    OMNI_SAFE_QUADRMTX_FW
                {
                    if (deflate) {
                        this->deflate(percent);
                    } else {
                        this->inflate(percent);
                    }
                }

                #if defined(OMNI_QUADRILATERAL_USE_SA)
                    void _recalc_sas()
                    {
                        this->m_sides[0] = this->_calc_side_a();
                        this->m_sides[1] = this->_calc_side_b();
                        this->m_sides[2] = this->_calc_side_c();
                        this->m_sides[3] = this->_calc_side_d();

                        this->m_angle[0] = omni::math::calculate_angle(this->m_a.x, this->m_a.y, this->m_b.x, this->m_b.y, this->m_c.x, this->m_c.y);
                        this->m_angle[1] = omni::math::calculate_angle(this->m_b.x, this->m_b.y, this->m_c.x, this->m_c.y, this->m_d.x, this->m_d.y);
                        this->m_angle[2] = omni::math::calculate_angle(this->m_c.x, this->m_c.y, this->m_d.x, this->m_d.y, this->m_a.x, this->m_a.y);
                        this->m_angle[3] = omni::math::calculate_angle(this->m_d.x, this->m_d.y, this->m_a.x, this->m_a.y, this->m_b.x, this->m_b.y);
                    }
                #endif

                double _area() const
                {
                    #if defined(OMNI_QUADRILATERAL_USE_SA)
                        return omni::math::area_of_quadrilateral(this->m_sides[0], this->m_sides[1], this->m_sides[2], this->m_sides[3], this->m_angle[0], this->m_angle[2]);
                    #else
                        return omni::math::area_of_quadrilateral(this->_side_a(), this->_side_b(), this->_side_c(), this->_side_d(), this->_angle_a(), this->_angle_c());
                    #endif
                }

                double _angle_a() const
                {
                    #if defined(OMNI_QUADRILATERAL_USE_SA)
                        return this->m_angle[0];
                    #else
                        return omni::math::calculate_angle(this->m_a.x, this->m_a.y, this->m_b.x, this->m_b.y, this->m_c.x, this->m_c.y);
                    #endif
                }

                double _angle_b() const
                {
                    #if defined(OMNI_QUADRILATERAL_USE_SA)
                        return this->m_angle[1];
                    #else
                        return omni::math::calculate_angle(this->m_b.x, this->m_b.y, this->m_c.x, this->m_c.y, this->m_d.x, this->m_d.y);
                    #endif
                }

                double _angle_c() const
                {
                    #if defined(OMNI_QUADRILATERAL_USE_SA)
                        return this->m_angle[2];
                    #else
                        return omni::math::calculate_angle(this->m_c.x, this->m_c.y, this->m_d.x, this->m_d.y, this->m_a.x, this->m_a.y);
                    #endif
                }

                double _angle_d() const
                {
                    #if defined(OMNI_QUADRILATERAL_USE_SA)
                        return this->m_angle[3];
                    #else
                        return omni::math::calculate_angle(this->m_d.x, this->m_d.y, this->m_a.x, this->m_a.y, this->m_b.x, this->m_b.y);
                    #endif
                }

                double _base() const
                {
                    #if defined(OMNI_QUADRILATERAL_USE_SA)
                        return std::max(this->m_sides[0], std::max(this->m_sides[1], std::max(this->m_sides[2], this->m_sides[3])));
                    #else
                        return std::max(this->_side_a(), std::max(this->_side_b(), std::max(this->_side_c(), this->_side_d())));
                    #endif
                }

                double _calc_side_a() const
                {
                    if (this->m_a >= this->m_b) {
                        return omni::math::distance_between_2_points(this->m_a.x, this->m_a.y, this->m_b.x, this->m_b.y);
                    }
                    return omni::math::distance_between_2_points(this->m_b.x, this->m_b.y, this->m_a.x, this->m_a.y);
                }

                double _calc_side_b() const
                {
                    if (this->m_b >= this->m_c) {
                        return omni::math::distance_between_2_points(this->m_b.x, this->m_b.y, this->m_c.x, this->m_c.y);
                    }
                    return omni::math::distance_between_2_points(this->m_c.x, this->m_c.y, this->m_b.x, this->m_b.y);
                }

                double _calc_side_c() const
                {
                    if (this->m_c >= this->m_d) {
                        return omni::math::distance_between_2_points(this->m_c.x, this->m_c.y, this->m_d.x, this->m_d.y);
                    }
                    return omni::math::distance_between_2_points(this->m_d.x, this->m_d.y, this->m_c.x, this->m_c.y);
                }

                double _calc_side_d() const
                {
                    if (this->m_d >= this->m_a) {
                        return omni::math::distance_between_2_points(this->m_d.x, this->m_d.y, this->m_a.x, this->m_a.y);
                    }
                    return omni::math::distance_between_2_points(this->m_a.x, this->m_a.y, this->m_d.x, this->m_d.y);
                }

                bool _intersects_with(T ax, T ay, T bx, T by, T cx, T cy, T dx, T dy) const
                {
                    return omni::math::quadrilateral_intersects(
                        this->m_a.x, this->m_a.y,
                        this->m_b.x, this->m_b.y,
                        this->m_c.x, this->m_c.y,
                        this->m_d.x, this->m_d.y,
                        ax, ay,
                        bx, by,
                        cx, cy,
                        dx, dy
                    );
                }

                inline double _side_a() const
                {
                    #if defined(OMNI_QUADRILATERAL_USE_SA)
                        return this->m_sides[0];
                    #else    
                        return this->_calc_side_a();
                    #endif
                }

                inline double _side_b() const
                {
                    #if defined(OMNI_QUADRILATERAL_USE_SA)
                        return this->m_sides[1];
                    #else    
                        return this->_calc_side_b();
                    #endif
                }

                inline double _side_c() const
                {
                    #if defined(OMNI_QUADRILATERAL_USE_SA)
                        return this->m_sides[2];
                    #else    
                        return this->_calc_side_c();
                    #endif
                }

                inline double _side_d() const
                {
                    #if defined(OMNI_QUADRILATERAL_USE_SA)
                        return this->m_sides[3];
                    #else    
                        return this->_calc_side_d();
                    #endif
                }
        };

        typedef omni::geometry::quadrilateral<int32_t> quadrilateral_t;
        typedef omni::geometry::quadrilateral<int64_t> quadrilateral64_t;
        typedef omni::geometry::quadrilateral<float> quadrilateralF_t;
        typedef omni::geometry::quadrilateral<double> quadrilateralD_t;
    }
}

namespace std {
    template < typename T >
    inline void swap(omni::geometry::quadrilateral<T>& o1, omni::geometry::quadrilateral<T>& o2)
    {
        o1.swap(o2);
    }
}

#endif // OMNI_QUADRILATERAL_HPP