mirror of
https://github.com/bdnugget/freeminer.git
synced 2026-11-07 06:57:27 +00:00
mapgen_earth
This commit is contained in:
1 parent
fefbb53805
commit
a4f487a891
9 files changed
+774
-1
No files matched your search
@@ -188,6 +188,8 @@ LOCAL_SRC_FILES += \
|
||||
jni/src/log_types.cpp \
|
||||
jni/src/mapgen_indev.cpp \
|
||||
jni/src/mapgen_math.cpp \
|
||||
jni/src/mapgen_earth.cpp \
|
||||
jni/src/earth/hgt.cpp \
|
||||
jni/src/threading/lock.cpp \
|
||||
jni/src/threading/thread_vector.cpp \
|
||||
jni/src/circuit.cpp \
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
set(mapgen_SRCS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mapgen_indev.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mapgen_math.cpp
|
||||
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mapgen_earth.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/earth/hgt.cpp
|
||||
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/cavegen.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/dungeongen.cpp
|
||||
|
||||
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
Copyright (C) 2024 proller <proler@gmail.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
This file is part of Freeminer.
|
||||
|
||||
Freeminer is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Freeminer is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Freeminer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Some code got from https://github.com/zbycz/srtm-hgt-reader
|
||||
|
||||
#include "hgt.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <ios>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <math.h>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <sys/wait.h>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include "debug/iostream_debug_helpers.h"
|
||||
|
||||
#include "filesys.h"
|
||||
#include "httpfetch.h"
|
||||
#include "log.h"
|
||||
#include "settings.h"
|
||||
#include "threading/concurrent_set.h"
|
||||
#include "util/timetaker.h"
|
||||
|
||||
hgts::hgts(const std::string &folder) : folder{folder}
|
||||
{
|
||||
fs::CreateAllDirs(folder);
|
||||
}
|
||||
|
||||
hgt *hgts::get(hgt::ll_t lat, hgt::ll_t lon)
|
||||
{
|
||||
if (map[lat].contains(lon)) {
|
||||
return &map[lat][lon].value();
|
||||
}
|
||||
auto lock = std::unique_lock(mutex);
|
||||
if (map[lat].contains(lon)) {
|
||||
return &map[lat][lon].value();
|
||||
}
|
||||
// DUMP("insert", (long)this, lat, lon, folder, map.size(), map[lat].size());
|
||||
map[lat][lon].emplace(folder, lat, lon).get(lat, lon);
|
||||
return &map[lat][lon].value();
|
||||
}
|
||||
|
||||
hgt::hgt(const std::string &folder, ll_t lat, ll_t lon) : folder{folder}
|
||||
{
|
||||
const int lat_dec = (int)floor(lat);
|
||||
const int lon_dec = (int)floor(lon);
|
||||
if (load(lat_dec, lon_dec)) {
|
||||
static thread_local auto once = 0;
|
||||
if (!once--)
|
||||
DUMP("load failed", lat_dec, lon_dec);
|
||||
}
|
||||
}
|
||||
|
||||
std::basic_string<uint8_t> exec_to_string(const std::string &cmd)
|
||||
{
|
||||
std::array<uint8_t, 1000000> buffer;
|
||||
std::basic_stringstream<uint8_t> result;
|
||||
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
|
||||
if (!pipe) {
|
||||
throw std::runtime_error("popen() failed!");
|
||||
}
|
||||
size_t sz = 0;
|
||||
while ((sz = read(pipe.get()->_fileno, buffer.data(),
|
||||
static_cast<int>(buffer.size()))) > 0) {
|
||||
result << std::basic_string<uint8_t>{buffer.data(), sz};
|
||||
}
|
||||
return result.str();
|
||||
}
|
||||
|
||||
bool hgt::load(int lat_dec, int lon_dec)
|
||||
{
|
||||
//DUMP(lat_dec, lon_dec);
|
||||
if (lat_loaded == lat_dec && lon_loaded == lon_dec) {
|
||||
return false;
|
||||
}
|
||||
auto lock = std::unique_lock(mutex);
|
||||
//DUMP(lat_dec, lon_dec);
|
||||
if (lat_loaded == lat_dec && lon_loaded == lon_dec) {
|
||||
return false;
|
||||
}
|
||||
if (lat_loading == lat_dec && lon_loading == lon_dec) {
|
||||
//DUMP(lat_dec, lon_dec);
|
||||
return true;
|
||||
}
|
||||
// DUMP((long)this, lat_dec, lon_dec, lat_loading, lon_loading, lat_loaded, lon_loaded);
|
||||
TimeTaker timer("hgt load");
|
||||
|
||||
lat_loading = lat_dec;
|
||||
lon_loading = lon_dec;
|
||||
|
||||
const auto gen_zip_name = [](int lat_dec, int lon_dec) {
|
||||
std::string zipname;
|
||||
if (lat_dec < 0) {
|
||||
zipname += 'S';
|
||||
zipname += char('A' + abs(ceil(lat_dec / 90.0 * 23)));
|
||||
} else {
|
||||
zipname += char('A' + abs(floor(lat_dec / 90.0 * 23)));
|
||||
}
|
||||
zipname += std::to_string(int(floor((((lon_dec + 180) / 360.0)) * 60) + 1));
|
||||
return zipname;
|
||||
};
|
||||
|
||||
#if GEN_TEST
|
||||
{
|
||||
size_t fails = 0;
|
||||
for (const auto &t : {
|
||||
std::pair{std::pair{36, 30}, "J36"},
|
||||
std::pair{std::pair{39, 35}, "J36"},
|
||||
std::pair{std::pair{36, 24}, "J35"},
|
||||
std::pair{std::pair{39, 29}, "J35"},
|
||||
std::pair{std::pair{40, 18}, "K34"},
|
||||
std::pair{std::pair{80, 25}, "U26"},
|
||||
std::pair{std::pair{83, 30}, "U26"},
|
||||
std::pair{std::pair{68, 163}, "R03"}, // TODO!!!
|
||||
std::pair{std::pair{70, 164}, "R03"},
|
||||
}) {
|
||||
std::string r;
|
||||
if (r = gen_zip_name(t.first.first, t.first.second); t.second != r) {
|
||||
DUMP("fail", t, r);
|
||||
++fails;
|
||||
}
|
||||
}
|
||||
DUMP(fails);
|
||||
}
|
||||
#endif
|
||||
|
||||
const auto zipname = gen_zip_name(lat_dec, lon_dec);
|
||||
|
||||
std::string zipfile = zipname + ".zip";
|
||||
std::string zipfull = folder + "/" + zipfile;
|
||||
|
||||
std::string filename(255, 0);
|
||||
sprintf(filename.data(), "%c%02d%c%03d.hgt", lat_dec > 0 ? 'N' : 'S', abs(lat_dec),
|
||||
lon_dec > 0 ? 'E' : 'W', abs(lon_dec));
|
||||
std::string filefull = folder + "/" + filename;
|
||||
// DUMP(lat_dec, lon_dec, filename, zipname, zipfull);
|
||||
|
||||
std::basic_string<uint8_t> srtmTile;
|
||||
size_t filesize = 0;
|
||||
|
||||
auto set_ratio = [&]() {
|
||||
if (filesize == 2884802) {
|
||||
seconds_per_px = 3;
|
||||
} else if (filesize == 25934402) {
|
||||
seconds_per_px = 1;
|
||||
} else {
|
||||
throw std::logic_error("unknown file size " + std::to_string(filesize));
|
||||
}
|
||||
|
||||
side_length = sqrt(filesize >> 1);
|
||||
};
|
||||
|
||||
// DUMP(filefull, zipfull);
|
||||
if (!std::filesystem::exists(filefull) && !std::filesystem::exists(zipfull)) {
|
||||
const auto http_to_file = [](const std::string &url, const std::string &zipfull) {
|
||||
HTTPFetchRequest req;
|
||||
req.url = url;
|
||||
req.connect_timeout = req.timeout =
|
||||
g_settings->getS32("curl_file_download_timeout");
|
||||
actionstream << "Downloading map from " << req.url << "\n";
|
||||
|
||||
HTTPFetchResult res;
|
||||
|
||||
if (1) {
|
||||
// TODO: why sync does not work?
|
||||
req.caller = HTTPFETCH_SYNC;
|
||||
httpfetch_sync(req, res);
|
||||
} else {
|
||||
req.caller = httpfetch_caller_alloc();
|
||||
httpfetch_async(req);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
HTTPFetchResult res;
|
||||
while (!httpfetch_async_get(req.caller, res)) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
}
|
||||
httpfetch_caller_free(req.caller);
|
||||
}
|
||||
|
||||
actionstream << req.url << " " << res.succeeded << " " << res.response_code
|
||||
<< " " << res.data.size() << "\n";
|
||||
if (!res.succeeded)
|
||||
return uintmax_t{0};
|
||||
|
||||
if (!res.data.size())
|
||||
return uintmax_t{0};
|
||||
|
||||
std::ofstream(zipfull) << res.data;
|
||||
if (!std::filesystem::exists(zipfull))
|
||||
return uintmax_t{0};
|
||||
return std::filesystem::file_size(zipfull);
|
||||
};
|
||||
|
||||
// TODO: https://viewfinderpanoramas.org/Coverage%20map%20viewfinderpanoramas_org15.htm
|
||||
static concurrent_set<std::string> http_failed;
|
||||
if (!http_failed.contains(zipfile))
|
||||
if (!http_to_file("http://build.freeminer.org/earth/" + zipfile, zipfull))
|
||||
if (!http_to_file(
|
||||
"https://viewfinderpanoramas.org/dem1/" + zipfile, zipfull))
|
||||
if (!http_to_file("https://viewfinderpanoramas.org/dem3/" + zipfile,
|
||||
zipfull)) {
|
||||
errorstream << "Not found " << zipfile << "\n"
|
||||
<< "try to download manually: \n"
|
||||
<< "curl -o " << zipfull
|
||||
<< " https://viewfinderpanoramas.org/dem1/" << zipfile
|
||||
<< " || " << "curl -o " << zipfull
|
||||
<< " https://viewfinderpanoramas.org/dem3/" << zipfile
|
||||
<< "\n";
|
||||
http_failed.insert(zipfile);
|
||||
}
|
||||
}
|
||||
|
||||
if (!std::filesystem::exists(filefull) && std::filesystem::exists(zipfull)) {
|
||||
|
||||
// TODO: use some available in server and client zip lib to extract files
|
||||
|
||||
//auto fs = RenderingEngine::get_raw_device()->getFileSystem();
|
||||
//bool ok = fs::extractZipFile(fs, zipfile, destination);
|
||||
|
||||
std::string cmd{"unzip -C -b -p " + zipfull + " " + zipname + "/" + filename};
|
||||
|
||||
srtmTile = exec_to_string(cmd);
|
||||
filesize = srtmTile.size();
|
||||
if (filesize) {
|
||||
set_ratio();
|
||||
}
|
||||
}
|
||||
// TODO: first try load unpached file, then unpack zip
|
||||
if (srtmTile.empty()) {
|
||||
|
||||
if (!std::filesystem::exists(filename)) {
|
||||
static thread_local auto once = 0;
|
||||
if (!once++) {
|
||||
std::cerr << "Missing file " << filename << " for " << lat_dec << ","
|
||||
<< lon_dec << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
filesize = std::filesystem::file_size(filename);
|
||||
|
||||
set_ratio();
|
||||
|
||||
std::ifstream istrm(filename, std::ios::binary);
|
||||
|
||||
if (!istrm.good()) {
|
||||
std::cerr << "Error opening " << filename << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
srtmTile.resize(filesize);
|
||||
istrm.read(reinterpret_cast<char *>(srtmTile.data()), filesize);
|
||||
}
|
||||
|
||||
if (srtmTile.empty()) {
|
||||
static thread_local auto once = 0;
|
||||
if (!once++) {
|
||||
std::cerr << "Missing file " << filename << " " << zipname << " for "
|
||||
<< lat_dec << "," << lon_dec << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
heights.resize(filesize >> 1);
|
||||
for (uint32_t i = 0; i < filesize >> 1; ++i) {
|
||||
int16_t height = (srtmTile[i << 1] << 8) | (srtmTile[(i << 1) + 1]);
|
||||
if (height == -32768) {
|
||||
height = 0;
|
||||
}
|
||||
heights[i] = height;
|
||||
}
|
||||
lat_loaded = lat_dec;
|
||||
lon_loaded = lon_dec;
|
||||
// DUMP("loadok", (long)this, heights.size(), lat_loaded, lon_loaded, filesize, zipname, filename, seconds_per_px, get(lat_dec, lon_dec));
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Pixel idx from left bottom corner (0-1200) */
|
||||
int16_t hgt::read(int16_t y, int16_t x)
|
||||
{
|
||||
const int row = (side_length - 1) - y;
|
||||
const int col = x;
|
||||
const int pos = (row * side_length + col);
|
||||
return heights[pos];
|
||||
}
|
||||
|
||||
float hgt::get(ll_t lat, ll_t lon)
|
||||
{
|
||||
const int lat_dec = (int)floor(lat);
|
||||
const int lon_dec = (int)floor(lon);
|
||||
|
||||
if (lat_loaded != lat_dec || lon_loaded != lon_dec) {
|
||||
// DUMP("notloaded", lat, lon, lat_dec, lon_dec, lat_loaded, lon_loaded, lat_loading, lon_loading, heights.size());
|
||||
return {};
|
||||
}
|
||||
|
||||
const ll_t lat_seconds = (lat - (ll_t)lat_dec) * 60 * 60;
|
||||
const ll_t lon_seconds = (lon - (ll_t)lon_dec) * 60 * 60;
|
||||
|
||||
const int y = lat_seconds / seconds_per_px;
|
||||
const int x = lon_seconds / seconds_per_px;
|
||||
|
||||
const int16_t height[] = {
|
||||
read(y + 1, x),
|
||||
read(y + 1, x + 1),
|
||||
read(y, x),
|
||||
read(y, x + 1),
|
||||
};
|
||||
// return height[2]; // debug not interpolated
|
||||
|
||||
// ratio where X lays
|
||||
const float dy = fmod(lat_seconds, seconds_per_px) / seconds_per_px;
|
||||
const float dx = fmod(lon_seconds, seconds_per_px) / seconds_per_px;
|
||||
|
||||
// Bilinear interpolation
|
||||
// h0------------h1
|
||||
// |
|
||||
// |--dx-- .
|
||||
// | |
|
||||
// | dy
|
||||
// | |
|
||||
// h2------------h3
|
||||
return height[0] * dy * (1 - dx) + height[1] * dy * (dx) +
|
||||
height[2] * (1 - dy) * (1 - dx) + height[3] * (1 - dy) * dx;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
Copyright (C) 2024 proller <proler@gmail.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
This file is part of Freeminer.
|
||||
|
||||
Freeminer is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Freeminer is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Freeminer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class hgt
|
||||
{
|
||||
public:
|
||||
using ll_t = float;
|
||||
|
||||
private:
|
||||
uint16_t side_length = 0; // = 3601;
|
||||
uint8_t seconds_per_px = 0;
|
||||
const std::string folder;
|
||||
int lat_loaded = 200;
|
||||
int lon_loaded = 200;
|
||||
int lat_loading = 200;
|
||||
int lon_loading = 200;
|
||||
std::mutex mutex; //, mutex2;
|
||||
std::vector<int16_t> heights;
|
||||
|
||||
bool load(int lat_dec, int lon_dec);
|
||||
int16_t read(int16_t y, int16_t x);
|
||||
|
||||
public:
|
||||
hgt(const std::string &folder, ll_t lat, ll_t lon);
|
||||
float get(ll_t lat, ll_t lon);
|
||||
};
|
||||
|
||||
class hgts
|
||||
{
|
||||
std::map<int, std::map<int, std::optional<hgt>>> map;
|
||||
const std::string folder;
|
||||
std::mutex mutex;
|
||||
|
||||
public:
|
||||
hgts(const std::string &folder);
|
||||
hgt *get(hgt::ll_t lat, hgt::ll_t lon);
|
||||
};
|
||||
@@ -57,6 +57,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "log_types.h"
|
||||
#include "mapgen_indev.h"
|
||||
#include "mapgen_math.h"
|
||||
#include "mapgen_earth.h"
|
||||
#include "serverenvironment.h"
|
||||
|
||||
|
||||
@@ -108,6 +109,7 @@ static MapgenDesc g_reg_mapgens[] = {
|
||||
|
||||
{"indev", true},
|
||||
{"math", true},
|
||||
{"earth", true},
|
||||
};
|
||||
|
||||
static_assert(
|
||||
@@ -186,6 +188,8 @@ Mapgen *Mapgen::createMapgen(MapgenType mgtype, MapgenParams *params,
|
||||
return new MapgenIndev((MapgenIndevParams *)params, emerge);
|
||||
case MAPGEN_MATH:
|
||||
return new MapgenMath((MapgenMathParams *)params, emerge);
|
||||
case MAPGEN_EARTH:
|
||||
return new MapgenEarth((MapgenEarthParams *)params, emerge);
|
||||
|
||||
case MAPGEN_CARPATHIAN:
|
||||
return new MapgenCarpathian((MapgenCarpathianParams *)params, emerge);
|
||||
@@ -217,6 +221,8 @@ MapgenParams *Mapgen::createMapgenParams(MapgenType mgtype)
|
||||
return new MapgenIndevParams;
|
||||
case MAPGEN_MATH:
|
||||
return new MapgenMathParams;
|
||||
case MAPGEN_EARTH:
|
||||
return new MapgenEarthParams;
|
||||
|
||||
case MAPGEN_CARPATHIAN:
|
||||
return new MapgenCarpathianParams;
|
||||
|
||||
@@ -117,6 +117,7 @@ enum MapgenType {
|
||||
|
||||
MAPGEN_INDEV,
|
||||
MAPGEN_MATH,
|
||||
MAPGEN_EARTH,
|
||||
|
||||
MAPGEN_INVALID,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
Copyright (C) 2024 proller <proler@gmail.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
This file is part of Freeminer.
|
||||
|
||||
Freeminer is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Freeminer is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Freeminer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
#include "debug/iostream_debug_helpers.h"
|
||||
#include "filesys.h"
|
||||
#include "irr_v2d.h"
|
||||
#include "irrlichttypes.h"
|
||||
#include "mapgen/earth/hgt.h"
|
||||
#include "mapgen_earth.h"
|
||||
#include "voxel.h"
|
||||
#include "mapblock.h"
|
||||
#include "mapnode.h"
|
||||
#include "map.h"
|
||||
#include "nodedef.h"
|
||||
#include "voxelalgorithms.h"
|
||||
#include "settings.h"
|
||||
#include "emerge.h"
|
||||
#include "serverenvironment.h"
|
||||
#include "mg_biome.h"
|
||||
#include "log_types.h"
|
||||
|
||||
void MapgenEarthParams::setDefaultSettings(Settings *settings)
|
||||
{
|
||||
settings->setDefault("mgearth_spflags", flagdesc_mapgen_v7, 0);
|
||||
}
|
||||
|
||||
void MapgenEarthParams::readParams(const Settings *settings)
|
||||
{
|
||||
try {
|
||||
MapgenV7Params::readParams(settings);
|
||||
} catch (...) {
|
||||
}
|
||||
auto mg_earth = settings->getJson("mg_earth");
|
||||
if (!mg_earth.isNull())
|
||||
params = mg_earth;
|
||||
}
|
||||
|
||||
void MapgenEarthParams::writeParams(Settings *settings) const
|
||||
{
|
||||
settings->setJson("mg_earth", params);
|
||||
try {
|
||||
MapgenV7Params::writeParams(settings);
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
// Utility function for converting degrees to radians
|
||||
long double toRadians(const long double degree)
|
||||
{
|
||||
// cmath library in C++ defines the constant M_PI as the value of pi accurate to 1e-30
|
||||
long double one_deg = (M_PI) / 180;
|
||||
return (one_deg * degree);
|
||||
}
|
||||
|
||||
long double distance(
|
||||
long double lat1, long double long1, long double lat2, long double long2)
|
||||
{
|
||||
DUMP(lat1, long1, lat2, long2);
|
||||
// Convert the latitudes and longitudes from degree to radians.
|
||||
lat1 = toRadians(lat1);
|
||||
long1 = toRadians(long1);
|
||||
lat2 = toRadians(lat2);
|
||||
long2 = toRadians(long2);
|
||||
|
||||
// Haversine Formula
|
||||
long double dlong = long2 - long1;
|
||||
long double dlat = lat2 - lat1;
|
||||
|
||||
long double ans =
|
||||
pow(sin(dlat / 2), 2) + cos(lat1) * cos(lat2) * pow(sin(dlong / 2), 2);
|
||||
|
||||
ans = 2 * asin(sqrt(ans));
|
||||
|
||||
// Radius of Earth in Kilometers, R = 6371 Use R = 3956 for miles long double R =
|
||||
// 6371;
|
||||
constexpr double R{6378137.0};
|
||||
|
||||
// Calculate the result
|
||||
ans = ans * R;
|
||||
return ans;
|
||||
}
|
||||
*/
|
||||
|
||||
MapgenEarth::MapgenEarth(MapgenEarthParams *params_, EmergeParams *emerge) :
|
||||
MapgenV7((MapgenV7Params *)params_, emerge),
|
||||
hgt_reader(porting::path_share + DIR_DELIM + "earth")
|
||||
{
|
||||
ndef = emerge->ndef;
|
||||
// mg_params = (MapgenEarthParams *)params_->sparams;
|
||||
mg_params = params_;
|
||||
|
||||
Json::Value ¶ms = mg_params->params;
|
||||
|
||||
if (params.get("light", 0).asBool())
|
||||
this->flags &= ~MG_LIGHT;
|
||||
|
||||
n_air = MapNode(ndef->getId(params.get("air", "air").asString()), LIGHT_SUN);
|
||||
n_water = MapNode(
|
||||
ndef->getId(params.get("water_source", "mapgen_water_source").asString()),
|
||||
LIGHT_SUN);
|
||||
n_stone = MapNode(
|
||||
ndef->getId(params.get("stone", "mapgen_stone").asString()), LIGHT_SUN);
|
||||
|
||||
if (params.get("center", Json::Value()).isObject())
|
||||
center = {params["center"]["x"].asDouble(), params["center"]["y"].asDouble(),
|
||||
params["center"]["z"].asDouble()};
|
||||
|
||||
if (params.get("scale", Json::Value()).isObject())
|
||||
scale = {params["scale"]["x"].asDouble(), params["scale"]["y"].asDouble(),
|
||||
params["scale"]["z"].asDouble()};
|
||||
|
||||
/* todomake test
|
||||
static bool shown = 0;
|
||||
if (!shown) {
|
||||
shown = true;
|
||||
std::vector<std::pair<int, int>> a{{0, 0}, {0, 1000}, {1000, 0}, {0, 30000},
|
||||
{30000, 0}, {-30000, -30000}, {-30000, 30000}, {30000, -30000},
|
||||
{30000, 30000}};
|
||||
|
||||
auto p0 = pos_to_ll(0, 0);
|
||||
for (const auto &c : a) {
|
||||
|
||||
// auto p1 = posToLl(30000, 0);
|
||||
// auto p2 = posToLl(0, 30000);
|
||||
// auto p3 = posToLl(0, 0);
|
||||
auto p = pos_to_ll(c.first, c.second);
|
||||
auto dist1 = distance(p0.lat, p0.lon, p.lat, p.lon);
|
||||
// auto dist2 = distance(p0.lat, p0.lat, p.lat, p.lon);
|
||||
auto h = get_height(c.first, c.second);
|
||||
DUMP(c.first, c.second, p0, p, dist1, h);
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
hgt_reader.debug = 1;
|
||||
std::vector<std::pair<int, int>> a{
|
||||
{0, 0}, {-30000, -30000}, {-30000, 30000}, {30000, -30000}, {30000, 30000}};
|
||||
|
||||
for (const auto &c : a) {
|
||||
|
||||
const auto tc = posToLl(c.first, c.second);
|
||||
// DUMP(x, z, tc.lat, tc.lon, center);
|
||||
// auto y = hgt_reader.srtmGetElevation(tc.lat, tc.lon);
|
||||
// if (!(x % 100) && !(z % 100)) {
|
||||
// auto url = std::string{"https://www.google.com/maps/@"} +
|
||||
// std::to_string(tc.lat) +"," + std::to_string(tc.lon) + ",11z";
|
||||
auto url = std::string{"https://yandex.ru/maps/?ll="} + std::to_string(tc.lon) +
|
||||
"%2C" + std::to_string(tc.lat) + "&z=11";
|
||||
auto h = getHeight(c.first, c.second);
|
||||
|
||||
DUMP(h, c.first, c.second, tc.lat, tc.lon, scale, center, url);
|
||||
}
|
||||
hgt_reader.debug = 0;
|
||||
*/
|
||||
}
|
||||
|
||||
MapgenEarth::~MapgenEarth()
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////// Map generator
|
||||
|
||||
MapNode MapgenEarth::layers_get(float value, float max)
|
||||
{
|
||||
auto layer_index = rangelim((unsigned int)myround((value / max) * layers_node_size),
|
||||
0, layers_node_size - 1);
|
||||
return layers_node[layer_index];
|
||||
}
|
||||
|
||||
bool MapgenEarth::visible(const v3pos_t &p)
|
||||
{
|
||||
return p.Y < get_height(p.X, p.Z);
|
||||
}
|
||||
|
||||
const MapNode &MapgenEarth::visible_content(const v3pos_t &p)
|
||||
{
|
||||
const auto v = visible(p);
|
||||
const auto vw = visible_water_level(p);
|
||||
if (!v && !vw)
|
||||
return visible_transparent;
|
||||
auto heat = 10;
|
||||
heat += p.Y / -100; // upper=colder, lower=hotter, 3c per 1000
|
||||
|
||||
if (!v && p.Y < water_level)
|
||||
return heat < 0 ? visible_ice : visible_water;
|
||||
const auto humidity = 60;
|
||||
return heat < 0 ? (humidity < 20 ? visible_surface : visible_surface_cold)
|
||||
: heat < 10 ? visible_surface
|
||||
: heat < 40 ? (humidity < 20 ? visible_surface_dry : visible_surface_green)
|
||||
: visible_surface_hot;
|
||||
}
|
||||
|
||||
ll MapgenEarth::pos_to_ll(const pos_t x, const pos_t z)
|
||||
{
|
||||
constexpr double EQUATOR_LEN{40075696.0};
|
||||
const auto lon = ((ll_t)x * scale.X) / (EQUATOR_LEN / 360) + center.X;
|
||||
const auto lat = ((ll_t)z * scale.Z) / (EQUATOR_LEN / 360) + center.Z;
|
||||
return {(ll_t)lat, (ll_t)lon};
|
||||
}
|
||||
|
||||
pos_t MapgenEarth::get_height(pos_t x, pos_t z)
|
||||
{
|
||||
const auto tc = pos_to_ll(x, z);
|
||||
auto y = hgt_reader.get(tc.lat, tc.lon)->get(tc.lat, tc.lon);
|
||||
return y * scale.Y - center.Y;
|
||||
}
|
||||
|
||||
int MapgenEarth::getSpawnLevelAtPoint(v2pos_t p)
|
||||
{
|
||||
return get_height(p.X, p.Y) + 2;
|
||||
}
|
||||
|
||||
int MapgenEarth::generateTerrain()
|
||||
{
|
||||
MapNode n_ice(c_ice);
|
||||
u32 index = 0;
|
||||
v3pos_t em = vm->m_area.getExtent();
|
||||
//auto zstride_1d = csize.X * (csize.Y + 1);
|
||||
|
||||
for (pos_t z = node_min.Z; z <= node_max.Z; z++) {
|
||||
for (pos_t x = node_min.X; x <= node_max.X; x++, index++) {
|
||||
s16 heat =
|
||||
m_emerge->env->m_use_weather
|
||||
? m_emerge->env->getServerMap().updateBlockHeat(m_emerge->env,
|
||||
v3pos_t(x, node_max.Y, z), nullptr, &heat_cache)
|
||||
: 0;
|
||||
auto height = get_height(x, z);
|
||||
u32 i = vm->m_area.index(x, node_min.Y, z);
|
||||
for (pos_t y = node_min.Y; y <= node_max.Y; y++) {
|
||||
// auto [have, d] = calc_point(x,y,z);
|
||||
bool underground = height >= y;
|
||||
|
||||
if (underground) {
|
||||
if (!vm->m_data[i]) {
|
||||
vm->m_data[i] = layers_get(0, 1);
|
||||
}
|
||||
} else if (y <= water_level) {
|
||||
vm->m_data[i] = (heat < 0 && y > heat / 3) ? n_ice : n_water;
|
||||
} else {
|
||||
vm->m_data[i] = n_air;
|
||||
}
|
||||
vm->m_area.add_y(em, i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
Copyright (C) 2024 proller <proler@gmail.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
This file is part of Freeminer.
|
||||
|
||||
Freeminer is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Freeminer is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Freeminer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "config.h"
|
||||
#include "mapgen/earth/hgt.h"
|
||||
#include "mapgen/mapgen.h"
|
||||
#include "mapgen/mapgen_v7.h"
|
||||
#include "json/json.h"
|
||||
|
||||
using ll_t = float;
|
||||
struct ll
|
||||
{
|
||||
ll_t lat = 0;
|
||||
ll_t lon = 0;
|
||||
};
|
||||
inline std::ostream &operator<<(std::ostream &s, const ll &p)
|
||||
{
|
||||
s << "(" << p.lat << "," << p.lon << ")";
|
||||
return s;
|
||||
}
|
||||
|
||||
struct MapgenEarthParams : public MapgenV7Params
|
||||
{
|
||||
|
||||
MapgenEarthParams(){};
|
||||
~MapgenEarthParams(){};
|
||||
|
||||
Json::Value params;
|
||||
|
||||
void readParams(const Settings *settings) override;
|
||||
void writeParams(Settings *settings) const override;
|
||||
void setDefaultSettings(Settings *settings) override;
|
||||
};
|
||||
|
||||
class MapgenEarth : public MapgenV7
|
||||
{
|
||||
public:
|
||||
MapgenEarthParams *mg_params;
|
||||
|
||||
virtual MapgenType getType() const override { return MAPGEN_EARTH; }
|
||||
MapgenEarth(MapgenEarthParams *mg_params, EmergeParams *emerge);
|
||||
~MapgenEarth();
|
||||
|
||||
virtual int generateTerrain() override;
|
||||
int getSpawnLevelAtPoint(v2s16 p) override;
|
||||
|
||||
v3d scale{1, 1, 1};
|
||||
v3d center{0, 0, 0};
|
||||
bool no_layers = false;
|
||||
|
||||
MapNode n_air, n_water, n_stone;
|
||||
|
||||
MapNode layers_get(float value, float max);
|
||||
bool visible(const v3pos_t &p) override;
|
||||
const MapNode &visible_content(const v3pos_t &p) override;
|
||||
|
||||
hgts hgt_reader;
|
||||
|
||||
pos_t get_height(pos_t x, pos_t z);
|
||||
ll pos_to_ll(pos_t x, pos_t z);
|
||||
};
|
||||
@@ -99,6 +99,7 @@ public:
|
||||
virtual MapgenType getType() const { return MAPGEN_V7; }
|
||||
|
||||
virtual void makeChunk(BlockMakeData *data);
|
||||
virtual
|
||||
int getSpawnLevelAtPoint(v2s16 p);
|
||||
|
||||
float baseTerrainLevelAtPoint(s16 x, s16 z);
|
||||
|
||||
Reference in new issue
Block a user