Repo created
This commit is contained in:
parent
4af19165ec
commit
68073add76
12458 changed files with 12350765 additions and 2 deletions
222
tools/topography_generator/marching_squares/square.hpp
Normal file
222
tools/topography_generator/marching_squares/square.hpp
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
#pragma once
|
||||
|
||||
#include "topography_generator/marching_squares/contours_builder.hpp"
|
||||
|
||||
namespace topography_generator
|
||||
{
|
||||
template <typename ValueType>
|
||||
class Square
|
||||
{
|
||||
public:
|
||||
Square(ValueType minValue, ValueType valueStep, std::string const & debugId)
|
||||
: m_minValue(minValue)
|
||||
, m_valueStep(valueStep)
|
||||
, m_debugId(debugId)
|
||||
{
|
||||
static_assert(std::is_integral<ValueType>::value && std::is_signed<ValueType>::value);
|
||||
}
|
||||
|
||||
void Init(double left, double bottom, double right, double top, ValueType lb, ValueType rb, ValueType lt,
|
||||
ValueType rt, ValueType invalid)
|
||||
{
|
||||
m_isValid = true;
|
||||
|
||||
m_left = left;
|
||||
m_bottom = bottom;
|
||||
m_right = right;
|
||||
m_top = top;
|
||||
|
||||
m_valueLB = GetValue(lb, invalid);
|
||||
m_valueRB = GetValue(rb, invalid);
|
||||
m_valueLT = GetValue(lt, invalid);
|
||||
m_valueRT = GetValue(rt, invalid);
|
||||
}
|
||||
|
||||
void GenerateSegments(ContoursBuilder & builder) const
|
||||
{
|
||||
if (!m_isValid)
|
||||
return;
|
||||
|
||||
ValueType minVal = std::min(m_valueLB, std::min(m_valueLT, std::min(m_valueRT, m_valueRB)));
|
||||
ValueType maxVal = std::max(m_valueLB, std::max(m_valueLT, std::max(m_valueRT, m_valueRB)));
|
||||
|
||||
ToLevelsRange(m_valueStep, minVal, maxVal);
|
||||
|
||||
CHECK_GREATER_OR_EQUAL(minVal, m_minValue, (m_debugId));
|
||||
|
||||
for (auto val = minVal; val < maxVal; val += m_valueStep)
|
||||
AddSegments(val, (val - m_minValue) / m_valueStep, builder);
|
||||
}
|
||||
|
||||
static void ToLevelsRange(ValueType step, ValueType & minVal, ValueType & maxVal)
|
||||
{
|
||||
if (minVal > 0)
|
||||
minVal = step * ((minVal + step - 1) / step);
|
||||
else
|
||||
minVal = step * (minVal / step);
|
||||
|
||||
if (maxVal > 0)
|
||||
maxVal = step * ((maxVal + step) / step);
|
||||
else
|
||||
maxVal = step * ((maxVal + 1) / step);
|
||||
}
|
||||
|
||||
private:
|
||||
enum class Rib
|
||||
{
|
||||
None,
|
||||
Left,
|
||||
Top,
|
||||
Right,
|
||||
Bottom,
|
||||
Unclear,
|
||||
};
|
||||
|
||||
ValueType GetValue(ValueType val, ValueType invalid)
|
||||
{
|
||||
// If a contour goes right through the corner of the square false segments can be generated.
|
||||
// Shift the value slightly from the corner.
|
||||
if (val == invalid)
|
||||
{
|
||||
// LOG(LWARNING, ("Invalid value at the position", pos, m_debugId));
|
||||
m_isValid = false;
|
||||
return val;
|
||||
}
|
||||
|
||||
if (abs(val) % m_valueStep == 0)
|
||||
return val + 1;
|
||||
return val;
|
||||
}
|
||||
|
||||
void AddSegments(ValueType val, uint16_t ind, ContoursBuilder & builder) const
|
||||
{
|
||||
// Segment is a vector directed so that higher values is on the right.
|
||||
static std::pair<Rib, Rib> const intersectedRibs[] = {
|
||||
{Rib::None, Rib::None}, // 0000
|
||||
{Rib::Left, Rib::Bottom}, // 0001
|
||||
{Rib::Top, Rib::Left}, // 0010
|
||||
{Rib::Top, Rib::Bottom}, // 0011
|
||||
{Rib::Right, Rib::Top}, // 0100
|
||||
{Rib::Unclear, Rib::Unclear}, // 0101
|
||||
{Rib::Right, Rib::Left}, // 0110
|
||||
{Rib::Right, Rib::Bottom}, // 0111
|
||||
{Rib::Bottom, Rib::Right}, // 1000
|
||||
{Rib::Left, Rib::Right}, // 1001
|
||||
{Rib::Unclear, Rib::Unclear}, // 1010
|
||||
{Rib::Top, Rib::Right}, // 1011
|
||||
{Rib::Bottom, Rib::Top}, // 1100
|
||||
{Rib::Left, Rib::Top}, // 1101
|
||||
{Rib::Bottom, Rib::Left}, // 1110
|
||||
{Rib::None, Rib::None}, // 1111
|
||||
};
|
||||
|
||||
uint8_t const pattern = (m_valueLB > val ? 1u : 0u) | ((m_valueLT > val ? 1u : 0u) << 1u) |
|
||||
((m_valueRT > val ? 1u : 0u) << 2u) | ((m_valueRB > val ? 1u : 0u) << 3u);
|
||||
|
||||
auto const ribs = intersectedRibs[pattern];
|
||||
|
||||
if (ribs.first == Rib::None)
|
||||
return;
|
||||
|
||||
if (ribs.first != Rib::Unclear)
|
||||
{
|
||||
builder.AddSegment(ind, InterpolatePoint(ribs.first, val), InterpolatePoint(ribs.second, val));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const leftPos = InterpolatePoint(Rib::Left, val);
|
||||
auto const rightPos = InterpolatePoint(Rib::Right, val);
|
||||
auto const bottomPos = InterpolatePoint(Rib::Bottom, val);
|
||||
auto const topPos = InterpolatePoint(Rib::Top, val);
|
||||
|
||||
ValueType const avVal = (m_valueLB + m_valueLT + m_valueRT + m_valueRB) / 4;
|
||||
if (avVal > val)
|
||||
{
|
||||
if (m_valueLB > val)
|
||||
{
|
||||
builder.AddSegment(ind, leftPos, topPos);
|
||||
builder.AddSegment(ind, rightPos, bottomPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AddSegment(ind, bottomPos, leftPos);
|
||||
builder.AddSegment(ind, topPos, rightPos);
|
||||
}
|
||||
}
|
||||
else if (m_valueLB > val)
|
||||
{
|
||||
builder.AddSegment(ind, leftPos, bottomPos);
|
||||
builder.AddSegment(ind, rightPos, topPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AddSegment(ind, topPos, leftPos);
|
||||
builder.AddSegment(ind, bottomPos, rightPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ms::LatLon InterpolatePoint(Square::Rib rib, ValueType val) const
|
||||
{
|
||||
double val1;
|
||||
double val2;
|
||||
double lat;
|
||||
double lon;
|
||||
|
||||
switch (rib)
|
||||
{
|
||||
case Rib::Left:
|
||||
val1 = static_cast<double>(m_valueLB);
|
||||
val2 = static_cast<double>(m_valueLT);
|
||||
lon = m_left;
|
||||
break;
|
||||
case Rib::Right:
|
||||
val1 = static_cast<double>(m_valueRB);
|
||||
val2 = static_cast<double>(m_valueRT);
|
||||
lon = m_right;
|
||||
break;
|
||||
case Rib::Top:
|
||||
val1 = static_cast<double>(m_valueLT);
|
||||
val2 = static_cast<double>(m_valueRT);
|
||||
lat = m_top;
|
||||
break;
|
||||
case Rib::Bottom:
|
||||
val1 = static_cast<double>(m_valueLB);
|
||||
val2 = static_cast<double>(m_valueRB);
|
||||
lat = m_bottom;
|
||||
break;
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
|
||||
CHECK_NOT_EQUAL(val, val2, (m_debugId));
|
||||
double const coeff = (val1 - val) / (val - val2);
|
||||
|
||||
switch (rib)
|
||||
{
|
||||
case Rib::Left:
|
||||
case Rib::Right: lat = (m_bottom + m_top * coeff) / (1 + coeff); break;
|
||||
case Rib::Bottom:
|
||||
case Rib::Top: lon = (m_left + m_right * coeff) / (1 + coeff); break;
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
|
||||
return {lat, lon};
|
||||
}
|
||||
|
||||
double m_left;
|
||||
double m_right;
|
||||
double m_bottom;
|
||||
double m_top;
|
||||
|
||||
ValueType m_valueLB;
|
||||
ValueType m_valueLT;
|
||||
ValueType m_valueRT;
|
||||
ValueType m_valueRB;
|
||||
|
||||
ValueType m_minValue;
|
||||
ValueType m_valueStep;
|
||||
std::string m_debugId;
|
||||
|
||||
bool m_isValid;
|
||||
};
|
||||
} // namespace topography_generator
|
||||
Loading…
Add table
Add a link
Reference in a new issue