mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2025-01-04 14:30:35 +00:00
subfolder system to organize presentations
This commit is contained in:
parent
a57b2b9d7f
commit
30dcfe9ada
114
tour.cpp
114
tour.cpp
@ -35,7 +35,7 @@ enum presmode {
|
|||||||
/** \brief slide definition */
|
/** \brief slide definition */
|
||||||
struct slide {
|
struct slide {
|
||||||
/** \brief title of this slide */
|
/** \brief title of this slide */
|
||||||
const char *name;
|
string name;
|
||||||
/** \brief ID (currently unused */
|
/** \brief ID (currently unused */
|
||||||
int unused_id;
|
int unused_id;
|
||||||
/** \brief various flags */
|
/** \brief various flags */
|
||||||
@ -118,12 +118,39 @@ EX void presentation(presmode mode) {
|
|||||||
callhooks(hooks_slide, mode);
|
callhooks(hooks_slide, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string parent_folder(const string& s) {
|
||||||
|
for(int k=isize(s)-2; k>=0; k--) if(s[k] == '/') return s.substr(0, k+1);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
string get_slidename(const string& s) {
|
||||||
|
int i = 0;
|
||||||
|
for(int k=0; k<isize(s); k++) if(s[k] == '/') i = k+1;
|
||||||
|
return s.substr(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
string get_foldername(const string& s) {
|
||||||
|
int i = 0;
|
||||||
|
for(int k=0; k<isize(s); k++) if(s[k] == '/') i = k+1;
|
||||||
|
return s.substr(0, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool in_folder(const string& s, const string& folder) {
|
||||||
|
return s.substr(0, isize(folder)) == folder;
|
||||||
|
}
|
||||||
|
|
||||||
|
string get_subname(const string& s, const string& folder) {
|
||||||
|
for(int k=isize(folder); k<isize(s); k++) if(s[k] == '/')
|
||||||
|
return s.substr(isize(folder), k+1 - isize(folder));
|
||||||
|
return s.substr(isize(folder));
|
||||||
|
}
|
||||||
|
|
||||||
/** \brief display the help text for the current slide if texts enabled */
|
/** \brief display the help text for the current slide if texts enabled */
|
||||||
EX void slidehelp() {
|
EX void slidehelp() {
|
||||||
if(texts && slides[currentslide].help[0])
|
if(texts && slides[currentslide].help[0])
|
||||||
gotoHelp(
|
gotoHelp(
|
||||||
help =
|
help =
|
||||||
helptitle(XLAT(slides[currentslide].name), 0xFF8000) +
|
helptitle(XLAT(get_slidename(slides[currentslide].name)), 0xFF8000) +
|
||||||
XLAT(slides[currentslide].help)
|
XLAT(slides[currentslide].help)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -230,8 +257,8 @@ bool handleKeyTour(int sym, int uni) {
|
|||||||
presentation(pmGeometryStart);
|
presentation(pmGeometryStart);
|
||||||
string x;
|
string x;
|
||||||
if(slides[currentslide].flags & USE_SLIDE_NAME) {
|
if(slides[currentslide].flags & USE_SLIDE_NAME) {
|
||||||
if(NUMBERKEY == '1') x = XLAT("Spherical version of %the1. ", s0 + "'" + slides[currentslide].name + "'");
|
if(NUMBERKEY == '1') x = XLAT("Spherical version of %the1. ", s0 + "'" + get_slidename(slides[currentslide].name) + "'");
|
||||||
if(NUMBERKEY == '2') x = XLAT("Euclidean version of %the1. ", s0 + "'" + slides[currentslide].name + "'");
|
if(NUMBERKEY == '2') x = XLAT("Euclidean version of %the1. ", s0 + "'" + get_slidename(slides[currentslide].name) + "'");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(NUMBERKEY == '1') x = XLAT("Spherical version of %the1. ", cwt.at->land);
|
if(NUMBERKEY == '1') x = XLAT("Spherical version of %the1. ", cwt.at->land);
|
||||||
@ -299,6 +326,7 @@ bool handleKeyTour(int sym, int uni) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if(NUMBERKEY == '9') {
|
if(NUMBERKEY == '9') {
|
||||||
|
ss::current_folder = get_foldername(slides[currentslide].name);
|
||||||
pushScreen(ss::showMenu);
|
pushScreen(ss::showMenu);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -328,7 +356,9 @@ EX void checkGoodLand(eLand l) {
|
|||||||
EX namespace ss {
|
EX namespace ss {
|
||||||
EX slide *wts;
|
EX slide *wts;
|
||||||
|
|
||||||
string slidechars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ23456789!@#$%^&*(";
|
EX string current_folder;
|
||||||
|
|
||||||
|
string slidechars = "abcdefghijklmnopqrsvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ23456789!@#$%^&*(";
|
||||||
|
|
||||||
EX hookset<int(bool)> *extra_slideshows;
|
EX hookset<int(bool)> *extra_slideshows;
|
||||||
|
|
||||||
@ -346,9 +376,33 @@ EX namespace ss {
|
|||||||
|
|
||||||
dialog::init(XLAT("slides"), forecolor, 150, 100);
|
dialog::init(XLAT("slides"), forecolor, 150, 100);
|
||||||
|
|
||||||
for(int i=0;; i++) {
|
if(current_folder != "") {
|
||||||
dialog::addBoolItem(XLAT(wts[i].name), wts == slides && i == currentslide, slidechars[i]);
|
dialog::addTitle(current_folder, 0xFFFFFFFF, 120);
|
||||||
dialog::add_action([i] {
|
dialog::addItem(XLAT("go up"), 'u');
|
||||||
|
dialog::add_action([] { current_folder = parent_folder(current_folder); });
|
||||||
|
dialog::addBreak(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
string last = "";
|
||||||
|
|
||||||
|
int key = 0;
|
||||||
|
|
||||||
|
for(int i=0; (i==0 || !(wts[i-1].flags & FINALSLIDE)); i++) {
|
||||||
|
if(!in_folder(wts[i].name, current_folder)) continue;
|
||||||
|
string sf = get_subname(wts[i].name, current_folder);
|
||||||
|
if(sf == last) continue;
|
||||||
|
last = sf;
|
||||||
|
string sfd;
|
||||||
|
|
||||||
|
if(sf.back() == '/') sfd = XLAT(sf.substr(0, isize(sf)-1)) + "/ ";
|
||||||
|
else sfd = XLAT(sf);
|
||||||
|
|
||||||
|
dialog::addBoolItem(XLAT(sf), wts == slides && in_folder(slides[currentslide].name, current_folder+sf), slidechars[key++]);
|
||||||
|
dialog::add_action([i, sf] {
|
||||||
|
if(sf.back() == '/') {
|
||||||
|
current_folder += sf;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(gamestack::pushed()) {
|
if(gamestack::pushed()) {
|
||||||
gamestack::pop();
|
gamestack::pop();
|
||||||
presentation(pmGeometryReset);
|
presentation(pmGeometryReset);
|
||||||
@ -364,7 +418,6 @@ EX namespace ss {
|
|||||||
presentation(pmStart);
|
presentation(pmStart);
|
||||||
slidehelp();
|
slidehelp();
|
||||||
});
|
});
|
||||||
if(wts[i].flags & FINALSLIDE) break;
|
|
||||||
}
|
}
|
||||||
dialog::addBreak(50);
|
dialog::addBreak(50);
|
||||||
bool b = false;
|
bool b = false;
|
||||||
@ -396,6 +449,11 @@ EX void start() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string bog = "Basics of Gameplay/";
|
||||||
|
string shapes = "Hyperbolic Shapes/";
|
||||||
|
string models = "Projections of Hyperbolic Space/";
|
||||||
|
string pcg = "Procedural Generation/";
|
||||||
|
|
||||||
/** \brief the default presentation (the Guided Tour) */
|
/** \brief the default presentation (the Guided Tour) */
|
||||||
EX slide default_slides[] = {
|
EX slide default_slides[] = {
|
||||||
#if ISMOBILE
|
#if ISMOBILE
|
||||||
@ -435,7 +493,7 @@ EX slide default_slides[] = {
|
|||||||
SHOWLAND( l == laIce );
|
SHOWLAND( l == laIce );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{"Basics of gameplay", 11, LEGAL::ANY,
|
{bog+"Basics of gameplay", 11, LEGAL::ANY,
|
||||||
"The game starts in the Icy Lands. Collect the Ice Diamonds "
|
"The game starts in the Icy Lands. Collect the Ice Diamonds "
|
||||||
"(press F1 if you do not know how to move). "
|
"(press F1 if you do not know how to move). "
|
||||||
"After you collect many of them, monsters will start to pose a challenge.\n"
|
"After you collect many of them, monsters will start to pose a challenge.\n"
|
||||||
@ -456,7 +514,7 @@ EX slide default_slides[] = {
|
|||||||
SHOWLAND( l == laIce );
|
SHOWLAND( l == laIce );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{"Hypersian Rug model", 21, LEGAL::HYPERBOLIC,
|
{bog+"Hypersian Rug model", 21, LEGAL::HYPERBOLIC,
|
||||||
"New players think that the action of HyperRogue takes place on a sphere. "
|
"New players think that the action of HyperRogue takes place on a sphere. "
|
||||||
#if CAP_RUG
|
#if CAP_RUG
|
||||||
"This is not true -- the next slide will show the surface HyperRogue "
|
"This is not true -- the next slide will show the surface HyperRogue "
|
||||||
@ -483,7 +541,7 @@ EX slide default_slides[] = {
|
|||||||
SHOWLAND( l == laIce );
|
SHOWLAND( l == laIce );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{"Expansion", 22, LEGAL::ANY | USE_SLIDE_NAME,
|
{bog+"Expansion", 22, LEGAL::ANY | USE_SLIDE_NAME,
|
||||||
"The next slide shows the number of cells in distance 1, 2, 3, ... from you. "
|
"The next slide shows the number of cells in distance 1, 2, 3, ... from you. "
|
||||||
"It grows exponentially: there are more than 10^100 cells "
|
"It grows exponentially: there are more than 10^100 cells "
|
||||||
"in radius 1000 around you, and you will move further away during the game!\n\n"
|
"in radius 1000 around you, and you will move further away during the game!\n\n"
|
||||||
@ -503,7 +561,7 @@ EX slide default_slides[] = {
|
|||||||
SHOWLAND( l == laIce );
|
SHOWLAND( l == laIce );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{"Tiling and Tactics", 23, LEGAL::ANY | USE_SLIDE_NAME,
|
{bog+"Tiling and Tactics", 23, LEGAL::ANY | USE_SLIDE_NAME,
|
||||||
"The tactics of fighting simple monsters, such as the Yetis from the Icy Lands, "
|
"The tactics of fighting simple monsters, such as the Yetis from the Icy Lands, "
|
||||||
"might appear shallow, but hyperbolic geometry is essential even there. "
|
"might appear shallow, but hyperbolic geometry is essential even there. "
|
||||||
"In the next slide, you are attacked by two monsters at once. "
|
"In the next slide, you are attacked by two monsters at once. "
|
||||||
@ -519,7 +577,7 @@ EX slide default_slides[] = {
|
|||||||
SHOWLAND( l == laCanvas );
|
SHOWLAND( l == laCanvas );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{"Straight Lines", 24, LEGAL::ANY,
|
{shapes+"Straight Lines", 24, LEGAL::ANY,
|
||||||
"Hyperbolic geometry has been discovered by the 19th century mathematicians who "
|
"Hyperbolic geometry has been discovered by the 19th century mathematicians who "
|
||||||
"wondered about the nature of paralellness. Take a line L and a point A. "
|
"wondered about the nature of paralellness. Take a line L and a point A. "
|
||||||
"Can a world exist where there is more than one line passing through A "
|
"Can a world exist where there is more than one line passing through A "
|
||||||
@ -546,7 +604,7 @@ EX slide default_slides[] = {
|
|||||||
SHOWLAND( l == laCrossroads || l == laIce );
|
SHOWLAND( l == laCrossroads || l == laIce );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{"Running Dogs", 25, LEGAL::ANY,
|
{shapes+"Running Dogs", 25, LEGAL::ANY,
|
||||||
"To learn more about straight lines, "
|
"To learn more about straight lines, "
|
||||||
"wander further, and you should find the Land of Eternal Motion. "
|
"wander further, and you should find the Land of Eternal Motion. "
|
||||||
"Try to run in a straight line, with a Running Dog next to you. "
|
"Try to run in a straight line, with a Running Dog next to you. "
|
||||||
@ -568,7 +626,7 @@ EX slide default_slides[] = {
|
|||||||
SHOWLAND( l == laCrossroads || l == laMotion );
|
SHOWLAND( l == laCrossroads || l == laMotion );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{"Equidistants", 27, LEGAL::ANY,
|
{shapes+"Equidistants", 27, LEGAL::ANY,
|
||||||
"Equidistants are curves which are at some fixed distance from a "
|
"Equidistants are curves which are at some fixed distance from a "
|
||||||
"straight line. Some lands in HyperRogue are based on equidistants; "
|
"straight line. Some lands in HyperRogue are based on equidistants; "
|
||||||
"you should see them after wandering a bit more.\n\n"
|
"you should see them after wandering a bit more.\n\n"
|
||||||
@ -585,7 +643,7 @@ EX slide default_slides[] = {
|
|||||||
SHOWLAND( l == laCrossroads || l == laDungeon || l == laOcean || l == laIvoryTower || l == laEndorian );
|
SHOWLAND( l == laCrossroads || l == laDungeon || l == laOcean || l == laIvoryTower || l == laEndorian );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{"Circles", 26, LEGAL::ANY,
|
{shapes+"Circles", 26, LEGAL::ANY,
|
||||||
"Circles are strange in hyperbolic geometry too. "
|
"Circles are strange in hyperbolic geometry too. "
|
||||||
"Look for the Castle of Camelot in the Crossroads; "
|
"Look for the Castle of Camelot in the Crossroads; "
|
||||||
"the Round Table inside is a circle of radius 28. "
|
"the Round Table inside is a circle of radius 28. "
|
||||||
@ -608,7 +666,7 @@ EX slide default_slides[] = {
|
|||||||
SHOWLAND( l == laCrossroads || l == laCamelot );
|
SHOWLAND( l == laCrossroads || l == laCamelot );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{"Horocycles", 28, LEGAL::ANY,
|
{shapes+"Horocycles", 28, LEGAL::ANY,
|
||||||
"Horocycles are similar to circles, but you cannot reach their center at all -- "
|
"Horocycles are similar to circles, but you cannot reach their center at all -- "
|
||||||
"they can be understood as limit circles of infinite radius centered in some point "
|
"they can be understood as limit circles of infinite radius centered in some point "
|
||||||
"in infinity (also called an ideal point).\n\n"
|
"in infinity (also called an ideal point).\n\n"
|
||||||
@ -627,7 +685,7 @@ EX slide default_slides[] = {
|
|||||||
SHOWLAND ( l == laCrossroads || l == laRlyeh || l == laTemple );
|
SHOWLAND ( l == laCrossroads || l == laRlyeh || l == laTemple );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{"Half-plane model", 47, LEGAL::HYPERBOLIC,
|
{shapes+"Half-plane model", 47, LEGAL::HYPERBOLIC,
|
||||||
"The game is normally displayed in the so called Poincaré disk model, "
|
"The game is normally displayed in the so called Poincaré disk model, "
|
||||||
"which is a kind of a map of the infinite hyperbolic world. "
|
"which is a kind of a map of the infinite hyperbolic world. "
|
||||||
"There are many projections of Earth, but since Earth is curved, "
|
"There are many projections of Earth, but since Earth is curved, "
|
||||||
@ -668,7 +726,7 @@ EX slide default_slides[] = {
|
|||||||
SHOWLAND ( l == laCrossroads || l == laBurial );
|
SHOWLAND ( l == laCrossroads || l == laBurial );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{"Periodic patterns", 30, LEGAL::UNLIMITED | USE_SLIDE_NAME,
|
{pcg+"Periodic patterns", 30, LEGAL::UNLIMITED | USE_SLIDE_NAME,
|
||||||
"Hyperbolic geometry yields much more interesting periodic patterns "
|
"Hyperbolic geometry yields much more interesting periodic patterns "
|
||||||
"than Euclidean.",
|
"than Euclidean.",
|
||||||
[] (presmode mode) {
|
[] (presmode mode) {
|
||||||
@ -682,7 +740,7 @@ EX slide default_slides[] = {
|
|||||||
SHOWLAND ( l == laCanvas );
|
SHOWLAND ( l == laCanvas );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{"Periodic patterns: application", 31, LEGAL::ANY,
|
{pcg+"Periodic patterns: application", 31, LEGAL::ANY,
|
||||||
"Many lands in HyperRogue are based around periodic patterns. "
|
"Many lands in HyperRogue are based around periodic patterns. "
|
||||||
"For example, both Zebra and Windy Plains are based on the pattern "
|
"For example, both Zebra and Windy Plains are based on the pattern "
|
||||||
"shown in the previous slide. "
|
"shown in the previous slide. "
|
||||||
@ -702,7 +760,7 @@ EX slide default_slides[] = {
|
|||||||
l == laEmerald || l == laWineyard || l == laPower );
|
l == laEmerald || l == laWineyard || l == laPower );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{"Fractal landscapes", 32, LEGAL::UNLIMITED | USE_SLIDE_NAME,
|
{pcg+"Fractal landscapes", 32, LEGAL::UNLIMITED | USE_SLIDE_NAME,
|
||||||
"On the following slide, the colors change smoothly in the whole infinite world. "
|
"On the following slide, the colors change smoothly in the whole infinite world. "
|
||||||
"Again, this works better than in Euclidean geometry.",
|
"Again, this works better than in Euclidean geometry.",
|
||||||
[] (presmode mode) {
|
[] (presmode mode) {
|
||||||
@ -710,7 +768,7 @@ EX slide default_slides[] = {
|
|||||||
SHOWLAND ( l == laCanvas );
|
SHOWLAND ( l == laCanvas );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{"Fractal landscapes: application", 33, LEGAL::ANY,
|
{pcg+"Fractal landscapes: application", 33, LEGAL::ANY,
|
||||||
"This is applied in HyperRogue to create landscapes, such as the chasms in the "
|
"This is applied in HyperRogue to create landscapes, such as the chasms in the "
|
||||||
"land of Reptiles or the Dragon Chasms, which you should find quickly. "
|
"land of Reptiles or the Dragon Chasms, which you should find quickly. "
|
||||||
"Also in the Dragon Chasms, you can find a Baby Tortoise, and try to find "
|
"Also in the Dragon Chasms, you can find a Baby Tortoise, and try to find "
|
||||||
@ -738,7 +796,7 @@ EX slide default_slides[] = {
|
|||||||
SHOWLAND ( l == laCrossroads || l == laReptile || l == laDragon || l == laTortoise );
|
SHOWLAND ( l == laCrossroads || l == laReptile || l == laDragon || l == laTortoise );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{"Poincaré Ball model", 41, LEGAL::HYPERBOLIC,
|
{models+"Poincaré Ball model", 41, LEGAL::HYPERBOLIC,
|
||||||
"The Poincaré disk model is a model of a hyperbolic *plane* -- you "
|
"The Poincaré disk model is a model of a hyperbolic *plane* -- you "
|
||||||
"might wonder why are the walls rendered in 3D then.\n\n"
|
"might wonder why are the walls rendered in 3D then.\n\n"
|
||||||
"HyperRogue actually assumes that the floor level is an equidistant surface "
|
"HyperRogue actually assumes that the floor level is an equidistant surface "
|
||||||
@ -752,7 +810,7 @@ EX slide default_slides[] = {
|
|||||||
if(mode == 3) pmodel = mdDisk;
|
if(mode == 3) pmodel = mdDisk;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{"Hyperboloid model", 42, LEGAL::ANY,
|
{models+"Hyperboloid model", 42, LEGAL::ANY,
|
||||||
"Let's see more models of the hyperbolic plane. "
|
"Let's see more models of the hyperbolic plane. "
|
||||||
"This model uses a hyperboloid in the Minkowski geometry; "
|
"This model uses a hyperboloid in the Minkowski geometry; "
|
||||||
"it is used internally by HyperRogue.",
|
"it is used internally by HyperRogue.",
|
||||||
@ -761,14 +819,14 @@ EX slide default_slides[] = {
|
|||||||
if(mode == 3) pmodel = mdDisk;
|
if(mode == 3) pmodel = mdDisk;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{"Beltrami-Klein model", 43, LEGAL::ANY | USE_SLIDE_NAME,
|
{models+"Beltrami-Klein model", 43, LEGAL::ANY | USE_SLIDE_NAME,
|
||||||
"This model renders straight lines as straight, but it distorts angles.",
|
"This model renders straight lines as straight, but it distorts angles.",
|
||||||
[] (presmode mode) {
|
[] (presmode mode) {
|
||||||
if(mode == 1 || mode == pmGeometryReset || mode == pmGeometry) vid.alpha = 0;
|
if(mode == 1 || mode == pmGeometryReset || mode == pmGeometry) vid.alpha = 0;
|
||||||
if(mode == 3) vid.alpha = 1;
|
if(mode == 3) vid.alpha = 1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{"Gans model", 44, LEGAL::ANY | USE_SLIDE_NAME,
|
{models+"Gans model", 44, LEGAL::ANY | USE_SLIDE_NAME,
|
||||||
"Yet another model, which corresponds to orthographic projection of the "
|
"Yet another model, which corresponds to orthographic projection of the "
|
||||||
"sphere. Poincaré disk model, Beltrami-Klein model, and the Gans "
|
"sphere. Poincaré disk model, Beltrami-Klein model, and the Gans "
|
||||||
"model are all obtained by looking at either the hyperboloid model or an "
|
"model are all obtained by looking at either the hyperboloid model or an "
|
||||||
@ -778,7 +836,7 @@ EX slide default_slides[] = {
|
|||||||
if(mode == 3) vid.alpha = vid.scale = 1;
|
if(mode == 3) vid.alpha = vid.scale = 1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{"Band model", 45, LEGAL::NONEUC | USE_SLIDE_NAME,
|
{models+"Band model", 45, LEGAL::NONEUC | USE_SLIDE_NAME,
|
||||||
"The band model is the hyperbolic analog of the Mercator projection of the sphere: "
|
"The band model is the hyperbolic analog of the Mercator projection of the sphere: "
|
||||||
"a given straight line is rendered as a straight line, and the rest of the "
|
"a given straight line is rendered as a straight line, and the rest of the "
|
||||||
"world is mapped conformally, that is, angles are not distorted. "
|
"world is mapped conformally, that is, angles are not distorted. "
|
||||||
|
Loading…
Reference in New Issue
Block a user