diff --git a/classes.cpp b/classes.cpp index ae1d0124..a6f38a76 100644 --- a/classes.cpp +++ b/classes.cpp @@ -960,7 +960,7 @@ EX vector ginf = { #if HDR namespace mf { static const flagtype azimuthal = 1; - static const flagtype cylindrical = 2; + static const flagtype cylindrical = 2; /* usually you want 'band' */ static const flagtype equiarea = 4; static const flagtype equidistant = 8; static const flagtype conformal = 16; @@ -968,15 +968,22 @@ namespace mf { static const flagtype space = 64; static const flagtype hyper_only = 128; static const flagtype hyper_or_torus = 256; - static const flagtype pseudocylindrical = 512; /* includes cylindrical */ + static const flagtype pseudocylindrical = 512; /* includes cylindrical; usually you want 'band' or 'pseudoband' */ static const flagtype equivolume = 1024; static const flagtype twopoint = 2048; static const flagtype uses_bandshift = 4096; static const flagtype broken = 8192; /* in spherical case, these are broken along the meridian 180 deg */ static const flagtype technical = 16384; /* don't display in the list */ + static const flagtype product_special = (1<<15); + static const flagtype axial = (1<<16); + static const flagtype perspective = (1<<17); + static const flagtype orientation = (1<<18); + static const flagtype transition = (1<<19); + static const flagtype werner = (1<<20); + static const flagtype horocyclic = (1<<21); - static const flagtype band = (cylindrical | pseudocylindrical | uses_bandshift); - static const flagtype pseudoband = (pseudocylindrical | uses_bandshift); + static const flagtype band = (cylindrical | pseudocylindrical | uses_bandshift | orientation); + static const flagtype pseudoband = (pseudocylindrical | uses_bandshift | orientation); } struct modelinfo { @@ -986,11 +993,6 @@ struct modelinfo { flagtype flags; - int is_azimuthal; - int is_band; - int is_equiarea; - int is_equidistant; - int is_conformal; const char* name; }; @@ -1025,16 +1027,16 @@ enum eModel : int { // (other bits are used for other information) #define X3(x) x, x, x -#define DEFAULTS 0, 0, 0, 0, 0, nullptr +#define DEFAULTS nullptr /** list of available models (i.e., projections) */ EX vector mdinf = { {"disk/Gans", "general perspective", "general perspective", mf::azimuthal | mf::conformal, DEFAULTS}, - {"half-plane", "inversion", "stereographic projection [VR]", mf::conformal, DEFAULTS}, - {"band", "band", "Mercator", mf::band | mf::conformal, DEFAULTS}, - {X3("polygonal"), mf::conformal, DEFAULTS}, + {"half-plane", "inversion", "stereographic projection [VR]", mf::conformal | mf::orientation | mf::horocyclic, DEFAULTS}, + {"band", "band", "Mercator", mf::band | mf::conformal | mf::transition, DEFAULTS}, + {X3("polygonal"), mf::conformal | mf::orientation, DEFAULTS}, {X3("formula"), 0, DEFAULTS}, - {X3("azimuthal equidistant"), mf::azimuthal | mf::equidistant | mf::euc_boring, DEFAULTS}, + {X3("azimuthal equidistant"), mf::azimuthal | mf::equidistant | mf::euc_boring | mf::product_special, DEFAULTS}, {X3("azimuthal equi-area"), mf::azimuthal | mf::equiarea | mf::euc_boring, DEFAULTS}, {X3("ball model"), mf::conformal | mf::azimuthal | mf::space, DEFAULTS}, {"Minkowski hyperboloid", "plane", "sphere", mf::conformal | mf::space | mf::euc_boring, DEFAULTS}, @@ -1042,47 +1044,47 @@ EX vector mdinf = { {X3("band equidistant"), mf::band | mf::equidistant | mf::euc_boring, DEFAULTS}, {X3("band equi-area"), mf::band | mf::equiarea | mf::euc_boring, DEFAULTS}, {X3("sinusoidal"), mf::pseudoband | mf::equiarea | mf::euc_boring, DEFAULTS}, - {X3("two-point equidistant"), mf::equidistant | mf::euc_boring | mf::twopoint, DEFAULTS}, + {X3("two-point equidistant"), mf::equidistant | mf::euc_boring | mf::twopoint | mf::orientation, DEFAULTS}, {X3("fisheye"), 0, DEFAULTS}, - {X3("Joukowsky transform"), mf::hyper_only | mf::conformal, DEFAULTS}, - {X3("Joukowsky+inversion"), mf::hyper_only | mf::conformal, DEFAULTS}, - {X3("rotated hyperboles"), mf::hyper_only, DEFAULTS}, - {X3("spiral/ring"), mf::hyper_or_torus | mf::uses_bandshift, DEFAULTS}, - {X3("native perspective"), 0, DEFAULTS}, + {X3("Joukowsky transform"), mf::hyper_only | mf::conformal | mf::transition | mf::orientation, DEFAULTS}, + {X3("Joukowsky+inversion"), mf::hyper_only | mf::conformal | mf::transition | mf::orientation, DEFAULTS}, + {X3("rotated hyperboles"), mf::hyper_only | mf::orientation, DEFAULTS}, + {X3("spiral/ring"), mf::hyper_or_torus | mf::uses_bandshift | mf::orientation, DEFAULTS}, + {X3("native perspective"), mf::perspective | mf::product_special, DEFAULTS}, {X3("azimuthal equi-volume"), mf::azimuthal | mf::equivolume | mf::euc_boring, DEFAULTS}, {X3("central inversion"), mf::azimuthal | mf::conformal, DEFAULTS}, - {X3("two-point azimuthal"), mf::euc_boring | mf::twopoint, DEFAULTS}, - {X3("two-point hybrid"), mf::euc_boring | mf::twopoint, DEFAULTS}, - {X3("geodesic"), 0, DEFAULTS}, + {X3("two-point azimuthal"), mf::euc_boring | mf::azimuthal | mf::twopoint | mf::orientation, DEFAULTS}, + {X3("two-point hybrid"), mf::euc_boring | mf::azimuthal | mf::equidistant | mf::twopoint | mf::orientation, DEFAULTS}, + {X3("geodesic"), mf::perspective | mf::product_special, DEFAULTS}, {X3("Mollweide"), mf::euc_boring | mf::pseudoband | mf::equiarea, DEFAULTS}, {X3("central cylindrical"), mf::euc_boring | mf::band, DEFAULTS}, {X3("Collignon"), mf::pseudoband | mf::equiarea, DEFAULTS}, - {X3("horocyclic coordinates"), mf::euc_boring, DEFAULTS}, - {X3("quadrant coordinates"), mf::euc_boring, DEFAULTS}, - {X3("axial coordinates"), mf::euc_boring, DEFAULTS}, - {X3("anti-axial coordinates"), mf::euc_boring, DEFAULTS}, - {X3("Werner projection"), mf::euc_boring | mf::broken, DEFAULTS}, // keep distances from pole, and distances along parallels - {X3("Aitoff projection"), mf::euc_boring | mf::broken, DEFAULTS}, // halve longitudes, do azequid, double x - {X3("Hammer projection"), mf::euc_boring | mf::broken, DEFAULTS}, // halve longitudes, do azequia, double x - {X3("loximuthal projection"), mf::euc_boring | mf::broken, DEFAULTS}, // map loxodromes azimuthally and equidistantly + {X3("horocyclic coordinates"), mf::euc_boring | mf::orientation | mf::horocyclic, DEFAULTS}, + {X3("quadrant coordinates"), mf::euc_boring | mf::orientation, DEFAULTS}, + {X3("axial coordinates"), mf::euc_boring | mf::transition | mf::orientation, DEFAULTS}, + {X3("anti-axial coordinates"), mf::euc_boring | mf::orientation, DEFAULTS}, + {X3("Werner projection"), mf::euc_boring | mf::broken | mf::werner | mf::orientation, DEFAULTS}, // keep distances from pole, and distances along parallels + {X3("Aitoff projection"), mf::euc_boring | mf::broken | mf::orientation, DEFAULTS}, // halve longitudes, do azequid, double x + {X3("Hammer projection"), mf::euc_boring | mf::broken | mf::orientation, DEFAULTS}, // halve longitudes, do azequia, double x + {X3("loximuthal projection"), mf::euc_boring | mf::broken | mf::orientation, DEFAULTS}, // map loxodromes azimuthally and equidistantly {X3("Miller projection"), mf::euc_boring | mf::band, DEFAULTS}, // scale latitude 4/5 -> Mercator -> 5/4 {X3("Gall stereographic"), mf::euc_boring | mf::band, DEFAULTS}, // like central cylindrical but stereographic - {X3("Winkel tripel"), mf::euc_boring | mf::broken, DEFAULTS}, // mean of equirec and Aitoff - {X3("Poor man's square"), mf::euc_boring, DEFAULTS}, // - {X3("Panini projection"), mf::euc_boring, DEFAULTS}, // - {X3("Craig retroazimuthal"), mf::euc_boring | mf::broken, DEFAULTS}, // retroazimuthal cylindrical - {X3("Littrow retroazimuthal"), mf::euc_boring | mf::broken, DEFAULTS}, // retroazimuthal conformal - {X3("Hammer retroazimuthal"), mf::euc_boring, DEFAULTS}, // retroazimuthal equidistant - {X3("three-point equidistant"), mf::euc_boring, DEFAULTS}, - {X3("Lie perspective"), mf::euc_boring, DEFAULTS}, + {X3("Winkel tripel"), mf::euc_boring | mf::broken | mf::orientation, DEFAULTS}, // mean of equirec and Aitoff + {X3("Poor man's square"), mf::euc_boring | mf::orientation, DEFAULTS}, // https://archive.bridgesmathart.org/2018/bridges2018-59.html + {X3("Panini projection"), mf::euc_boring | mf::orientation, DEFAULTS}, + {X3("Craig retroazimuthal"), mf::euc_boring | mf::broken | mf::pseudoband, DEFAULTS}, // retroazimuthal cylindrical + {X3("Littrow retroazimuthal"), mf::euc_boring | mf::broken | mf::pseudoband, DEFAULTS}, // retroazimuthal conformal + {X3("Hammer retroazimuthal"), mf::euc_boring | mf::pseudoband, DEFAULTS}, // retroazimuthal equidistant + {X3("three-point equidistant"), mf::euc_boring | mf::equidistant | mf::orientation | mf::product_special | mf::twopoint, DEFAULTS}, + {X3("Lie perspective"), mf::euc_boring | mf::perspective, DEFAULTS}, {X3("Lie orthogonal"), mf::euc_boring, DEFAULTS}, - {X3("relativistic perspective"), mf::euc_boring, DEFAULTS}, + {X3("relativistic perspective"), mf::euc_boring | mf::perspective, DEFAULTS}, {X3("relativistic orthogonal"), mf::euc_boring, DEFAULTS}, - {X3("horocyclic equal-area"), mf::euc_boring, DEFAULTS}, + {X3("horocyclic equal-area"), mf::euc_boring | mf::equiarea | mf::orientation | mf::horocyclic, DEFAULTS}, {X3("guard"), mf::technical, DEFAULTS}, {X3("pixel"), mf::technical, DEFAULTS}, {X3("hypflat"), mf::technical, DEFAULTS}, - {X3("polynomial"), mf::technical | mf::conformal, DEFAULTS}, + {X3("polynomial"), mf::technical | mf::conformal | mf::orientation, DEFAULTS}, {X3("manual"), mf::technical, DEFAULTS}, }; diff --git a/models.cpp b/models.cpp index 23bf03b3..f91a37d0 100644 --- a/models.cpp +++ b/models.cpp @@ -108,7 +108,7 @@ EX namespace polygonal { EX } #if HDR -inline bool mdAzimuthalEqui() { return among(pmodel, mdEquidistant, mdEquiarea, mdEquivolume); } +inline bool mdAzimuthalEqui() { return (mdinf[pmodel].flags & mf::azimuthal) && (mdinf[pmodel].flags & (mf::equidistant | mf::equiarea | mf::equivolume) && !(mdinf[pmodel].flags & mf::twopoint)); } inline bool mdBandAny() { return mdinf[pmodel].flags & mf::pseudoband; } inline bool mdPseudocylindrical() { return mdBandAny() && !(mdinf[pmodel].flags & mf::cylindrical); } #endif @@ -198,8 +198,8 @@ EX namespace models { if(hyperbolic && desitter_projections && among(pm, mdRelPerspective, mdRelOrthogonal)) return true; if(sl2) return among(pm, mdGeodesic, mdEquidistant, mdRelPerspective, mdRelOrthogonal, mdHorocyclic, mdPerspective); if(nonisotropic) return among(pm, mdDisk, mdPerspective, mdHorocyclic, mdGeodesic, mdEquidistant, mdFisheye, mdLiePerspective, mdLieOrthogonal); - if(sphere && (pm == mdHalfplane || pm == mdBall)) - return false; + if(sphere && pm == pmBall) return false; + if(sphere && (mdinf[pm].flags & mf::horocyclic)) return false; if(GDIM == 2 && is_perspective(pm)) return false; if(pm == mdGeodesic && !nonisotropic) return false; if(pm == mdLiePerspective && sphere) return false; @@ -214,17 +214,14 @@ EX namespace models { } EX bool has_orientation(eModel m) { - if(among(m, mdHorocyclic, mdHorocyclicEqa, mdLieOrthogonal, mdLiePerspective)) - return hyperbolic || in_h2xe(); if(is_perspective(m) && panini_alpha) return true; - return - among(m, mdHalfplane, mdPolynomial, mdPolygonal, mdTwoPoint, mdJoukowsky, mdJoukowskyInverted, mdSpiral, mdSimulatedPerspective, mdTwoHybrid, mdHorocyclic, mdHorocyclicEqa, mdAxial, mdAntiAxial, mdQuadrant, - mdWerner, mdAitoff, mdHammer, mdLoximuthal, mdWinkelTripel, mdThreePoint) || mdBandAny(); + if(nonisotropic) return false; + return (mdinf[m].flags & mf::orientation); } /** @brief returns the broken coordinate, or zero */ EX int get_broken_coord(eModel m) { - if(m == mdWerner) return 1; + if(mdinf[m].flags & mf::werner) return 1; if(sphere) return (mdinf[m].flags & mf::broken) ? 2 : 0; return 0; } @@ -234,7 +231,7 @@ EX namespace models { } EX bool is_perspective(eModel m) { - return among(m, mdPerspective, mdGeodesic, mdLiePerspective, mdRelPerspective); + return mdinf[m].flags & mf::perspective; } EX bool is_3d(const projection_configuration& p) { @@ -243,12 +240,12 @@ EX namespace models { } EX bool has_transition(eModel m) { - return among(m, mdJoukowsky, mdJoukowskyInverted, mdBand, mdAxial) && GDIM == 2; + return (mdinf[m].flags & mf::transition) && GDIM == 2; } EX bool product_model(eModel m) { if(!gproduct) return false; - if(among(m, mdPerspective, mdHyperboloid, mdEquidistant, mdThreePoint)) return false; + if(mdinf[m].flags & mf::product_special) return false; return true; } @@ -270,7 +267,7 @@ EX namespace models { return XLAT(mdinf[m].name_spherical); if(euclid) return XLAT(mdinf[m].name_euclidean); - if(hyperbolic) + if(hyperbolic) return XLAT(mdinf[m].name_hyperbolic); return "?"; } @@ -624,10 +621,10 @@ EX namespace models { if(vpmodel == mdJoukowskyInverted) add_edit(vpconf.dualfocus_autoscale); - if(vpmodel == mdHemisphere && euclid) + if(vpmodel == mdHemisphere && euclid) add_edit(vpconf.euclid_to_sphere); - if(among(vpmodel, mdTwoPoint, mdSimulatedPerspective, mdTwoHybrid, mdThreePoint)) + if(mdinf[vpmodel].flags & mf::twopoint) add_edit(vpconf.twopoint_param); if(vpmodel == mdFisheye)