mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-17 03:59:19 +02:00
refactor(editor): alignment::join builds its candidates (straight, single arc, fitted curve, Bezier fallback) in separate functions, alignment_store::load reads each //$h line kind in its own function
This commit is contained in:
@@ -18,6 +18,7 @@ http:
|
||||
#include <cstdio>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
|
||||
namespace alignment
|
||||
{
|
||||
@@ -932,133 +933,165 @@ void spread_rolls(std::vector<segment_data> &Pieces, double const Start, double
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct join_frame
|
||||
{
|
||||
join_request const &request;
|
||||
glm::dvec2 start_direction;
|
||||
glm::dvec2 end_direction;
|
||||
glm::dvec2 chord;
|
||||
double distance;
|
||||
double tolerance;
|
||||
double heading;
|
||||
double rise;
|
||||
};
|
||||
|
||||
std::optional<join_result> straight_join(join_frame const &Frame)
|
||||
{
|
||||
auto const &a{Frame.request.start};
|
||||
auto const &b{Frame.request.end};
|
||||
if (std::abs(geometry::signed_angle(Frame.start_direction, Frame.chord)) > Frame.tolerance || std::abs(geometry::signed_angle(Frame.chord, Frame.end_direction)) > Frame.tolerance)
|
||||
return std::nullopt;
|
||||
join_result straight;
|
||||
straight.kind = join_kind::straight;
|
||||
segment_data path;
|
||||
path.points[segment_data::point::start] = a.position;
|
||||
path.points[segment_data::point::end] = b.position;
|
||||
straight.pieces = {path};
|
||||
spread_rolls(straight.pieces, a.roll, b.roll);
|
||||
straight.length = glm::distance(a.position, b.position);
|
||||
return straight;
|
||||
}
|
||||
|
||||
std::optional<join_result> arc_join(join_frame const &Frame)
|
||||
{
|
||||
auto const &a{Frame.request.start};
|
||||
auto const &b{Frame.request.end};
|
||||
auto const lateral{cross(Frame.start_direction, Frame.chord)};
|
||||
if (std::abs(lateral) <= 1e-6)
|
||||
return std::nullopt;
|
||||
auto const angle{2.0 * std::atan2(std::abs(lateral), glm::dot(Frame.start_direction, Frame.chord))};
|
||||
int const side{lateral > 0.0 ? 1 : -1};
|
||||
auto const radius{Frame.distance * Frame.distance / (2.0 * std::abs(lateral))};
|
||||
if (angle >= kPi - 1e-3 || std::abs(geometry::signed_angle(turned(Frame.start_direction, side * angle), Frame.end_direction)) > Frame.tolerance)
|
||||
return std::nullopt;
|
||||
join_result arc;
|
||||
arc.kind = join_kind::arc;
|
||||
arc.pieces = geometry::arc_pieces(a.position, Frame.start_direction, Frame.rise / (radius * angle), radius, angle, side);
|
||||
arc.pieces.back().points[segment_data::point::end] = b.position;
|
||||
spread_rolls(arc.pieces, a.roll, b.roll);
|
||||
arc.radius = radius;
|
||||
arc.length = radius * angle;
|
||||
return arc;
|
||||
}
|
||||
|
||||
design join_design(join_frame const &Frame, join_kind const Kind)
|
||||
{
|
||||
auto const &request{Frame.request};
|
||||
design shape;
|
||||
shape.norms = request.norms;
|
||||
shape.shape = request.shape;
|
||||
shape.speed = request.speed;
|
||||
shape.arc_piece_angle = 90.0;
|
||||
shape.start = request.start.position;
|
||||
shape.end = request.end.position;
|
||||
shape.start_direction = Frame.start_direction;
|
||||
shape.end_direction = Frame.end_direction;
|
||||
shape.start_grade = Frame.rise / Frame.distance;
|
||||
shape.end_grade = shape.start_grade;
|
||||
vertex corner;
|
||||
corner.radius = request.radius > 0.0 ? request.radius : 100000.0;
|
||||
if (Kind == join_kind::curve)
|
||||
shape.vertices = {corner};
|
||||
else
|
||||
{
|
||||
corner.offset = Frame.distance / 3.0;
|
||||
shape.vertices = {corner, corner};
|
||||
}
|
||||
return shape;
|
||||
}
|
||||
|
||||
std::optional<join_result> fitted_join(join_frame const &Frame, join_kind const Kind)
|
||||
{
|
||||
auto shape{join_design(Frame, Kind)};
|
||||
auto const r{compute_recommended(shape, Frame.request.transitions)};
|
||||
auto const sharp{std::any_of(r.curves.begin(), r.curves.end(), [](curve_report const &Report) { return Report.radius < 10.0; })};
|
||||
if (false == r.valid || sharp || turning(r) > Frame.heading + kPi + 1e-6 || r.length > 3.0 * Frame.distance + 1.0)
|
||||
return std::nullopt;
|
||||
join_result curve;
|
||||
curve.kind = Kind;
|
||||
curve.pieces = pieces(r, shape, 0);
|
||||
if (curve.pieces.empty())
|
||||
return curve;
|
||||
curve.pieces.front().rolls[0] = static_cast<float>(Frame.request.start.roll);
|
||||
curve.pieces.back().rolls[1] = static_cast<float>(Frame.request.end.roll);
|
||||
curve.length = r.length;
|
||||
curve.speed = shape.speed;
|
||||
curve.warnings = r.warnings;
|
||||
curve.radius = r.curves.empty() ? 0.0 : std::numeric_limits<double>::max();
|
||||
for (auto const &report : r.curves)
|
||||
{
|
||||
curve.radius = std::min(curve.radius, report.radius);
|
||||
curve.transition = std::max({curve.transition, report.transition_in, report.transition_out});
|
||||
}
|
||||
for (auto const &e : r.elements)
|
||||
curve.cant = std::max(curve.cant, e.cant);
|
||||
return curve;
|
||||
}
|
||||
|
||||
std::optional<join_result> curve_join(join_frame const &Frame)
|
||||
{
|
||||
design probe;
|
||||
probe.start = Frame.request.start.position;
|
||||
probe.end = Frame.request.end.position;
|
||||
probe.start_direction = Frame.start_direction;
|
||||
probe.end_direction = Frame.end_direction;
|
||||
glm::dvec2 intersection;
|
||||
return fitted_join(Frame, tangent_intersection(probe, intersection) ? join_kind::curve : join_kind::reverse_curve);
|
||||
}
|
||||
|
||||
join_result bezier_join(join_frame const &Frame)
|
||||
{
|
||||
auto const &a{Frame.request.start};
|
||||
auto const &b{Frame.request.end};
|
||||
join_result fallback;
|
||||
fallback.kind = join_kind::bezier;
|
||||
auto const grade{Frame.rise / Frame.distance};
|
||||
auto const handle{Frame.distance / 3.0};
|
||||
segment_data path;
|
||||
path.points[segment_data::point::start] = a.position;
|
||||
path.points[segment_data::point::end] = b.position;
|
||||
path.points[segment_data::point::control1] = glm::dvec3{Frame.start_direction.x, grade, Frame.start_direction.y} * handle;
|
||||
path.points[segment_data::point::control2] = -glm::dvec3{Frame.end_direction.x, grade, Frame.end_direction.y} * handle;
|
||||
fallback.pieces = {path};
|
||||
spread_rolls(fallback.pieces, a.roll, b.roll);
|
||||
fallback.length = Frame.distance;
|
||||
return fallback;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
join_result join(join_request const &Request)
|
||||
{
|
||||
join_result chosen;
|
||||
auto const &a{Request.start};
|
||||
auto const &b{Request.end};
|
||||
auto const chord{plan_of(b.position) - plan_of(a.position)};
|
||||
auto const distance{glm::length(chord)};
|
||||
if (distance < 0.05 || glm::length(a.direction) < 1e-9 || glm::length(b.direction) < 1e-9)
|
||||
return chosen;
|
||||
return {};
|
||||
auto const startdirection{glm::normalize(a.direction)};
|
||||
auto const enddirection{glm::normalize(b.direction)};
|
||||
auto const tolerance{glm::radians(Request.kink)};
|
||||
auto const heading{std::abs(geometry::signed_angle(startdirection, enddirection))};
|
||||
auto const rise{b.position.y - a.position.y};
|
||||
join_frame const frame{Request, startdirection, enddirection, chord, distance, glm::radians(Request.kink), std::abs(geometry::signed_angle(startdirection, enddirection)), b.position.y - a.position.y};
|
||||
std::vector<join_result> candidates;
|
||||
|
||||
if (std::abs(geometry::signed_angle(startdirection, chord)) <= tolerance && std::abs(geometry::signed_angle(chord, enddirection)) <= tolerance)
|
||||
{
|
||||
join_result straight;
|
||||
straight.kind = join_kind::straight;
|
||||
segment_data path;
|
||||
path.points[segment_data::point::start] = a.position;
|
||||
path.points[segment_data::point::end] = b.position;
|
||||
straight.pieces = {path};
|
||||
spread_rolls(straight.pieces, a.roll, b.roll);
|
||||
straight.length = glm::distance(a.position, b.position);
|
||||
candidates.push_back(straight);
|
||||
}
|
||||
|
||||
auto const lateral{cross(startdirection, chord)};
|
||||
auto const along{glm::dot(startdirection, chord)};
|
||||
if (std::abs(lateral) > 1e-6)
|
||||
{
|
||||
auto const angle{2.0 * std::atan2(std::abs(lateral), along)};
|
||||
int const side{lateral > 0.0 ? 1 : -1};
|
||||
auto const radius{distance * distance / (2.0 * std::abs(lateral))};
|
||||
if (angle < kPi - 1e-3 && std::abs(geometry::signed_angle(turned(startdirection, side * angle), enddirection)) <= tolerance)
|
||||
{
|
||||
join_result arc;
|
||||
arc.kind = join_kind::arc;
|
||||
arc.pieces = geometry::arc_pieces(a.position, startdirection, rise / (radius * angle), radius, angle, side);
|
||||
arc.pieces.back().points[segment_data::point::end] = b.position;
|
||||
spread_rolls(arc.pieces, a.roll, b.roll);
|
||||
arc.radius = radius;
|
||||
arc.length = radius * angle;
|
||||
candidates.push_back(arc);
|
||||
}
|
||||
}
|
||||
|
||||
auto const fitted = [&](join_kind const Kind) {
|
||||
join_result curve;
|
||||
design shape;
|
||||
shape.norms = Request.norms;
|
||||
shape.shape = Request.shape;
|
||||
shape.speed = Request.speed;
|
||||
shape.arc_piece_angle = 90.0;
|
||||
shape.start = a.position;
|
||||
shape.end = b.position;
|
||||
shape.start_direction = startdirection;
|
||||
shape.end_direction = enddirection;
|
||||
shape.start_grade = shape.end_grade = rise / distance;
|
||||
vertex corner;
|
||||
corner.radius = Request.radius > 0.0 ? Request.radius : 100000.0;
|
||||
if (Kind == join_kind::curve)
|
||||
shape.vertices = {corner};
|
||||
else
|
||||
{
|
||||
corner.offset = distance / 3.0;
|
||||
shape.vertices = {corner, corner};
|
||||
}
|
||||
auto const r{compute_recommended(shape, Request.transitions)};
|
||||
auto const sharp{std::any_of(r.curves.begin(), r.curves.end(), [](curve_report const &Report) { return Report.radius < 10.0; })};
|
||||
if (false == r.valid || sharp || turning(r) > heading + kPi + 1e-6 || r.length > 3.0 * distance + 1.0)
|
||||
return curve;
|
||||
curve.kind = Kind;
|
||||
curve.pieces = pieces(r, shape, 0);
|
||||
if (curve.pieces.empty())
|
||||
return curve;
|
||||
curve.pieces.front().rolls[0] = static_cast<float>(a.roll);
|
||||
curve.pieces.back().rolls[1] = static_cast<float>(b.roll);
|
||||
curve.length = r.length;
|
||||
curve.speed = shape.speed;
|
||||
curve.warnings = r.warnings;
|
||||
curve.radius = std::numeric_limits<double>::max();
|
||||
for (auto const &report : r.curves)
|
||||
{
|
||||
curve.radius = std::min(curve.radius, report.radius);
|
||||
curve.transition = std::max({curve.transition, report.transition_in, report.transition_out});
|
||||
}
|
||||
for (auto const &e : r.elements)
|
||||
curve.cant = std::max(curve.cant, e.cant);
|
||||
if (r.curves.empty())
|
||||
curve.radius = 0.0;
|
||||
return curve;
|
||||
};
|
||||
design probe;
|
||||
probe.start = a.position;
|
||||
probe.end = b.position;
|
||||
probe.start_direction = startdirection;
|
||||
probe.end_direction = enddirection;
|
||||
glm::dvec2 intersection;
|
||||
if (tangent_intersection(probe, intersection))
|
||||
{
|
||||
if (auto curve{fitted(join_kind::curve)}; curve.kind != join_kind::none)
|
||||
candidates.push_back(curve);
|
||||
}
|
||||
else if (auto curve{fitted(join_kind::reverse_curve)}; curve.kind != join_kind::none)
|
||||
candidates.push_back(curve);
|
||||
|
||||
for (auto const &candidate : {straight_join(frame), arc_join(frame), curve_join(frame)})
|
||||
if (candidate.has_value())
|
||||
candidates.push_back(*candidate);
|
||||
if (candidates.empty())
|
||||
{
|
||||
join_result fallback;
|
||||
fallback.kind = join_kind::bezier;
|
||||
auto const grade{rise / distance};
|
||||
auto const handle{distance / 3.0};
|
||||
segment_data path;
|
||||
path.points[segment_data::point::start] = a.position;
|
||||
path.points[segment_data::point::end] = b.position;
|
||||
path.points[segment_data::point::control1] = glm::dvec3{startdirection.x, grade, startdirection.y} * handle;
|
||||
path.points[segment_data::point::control2] = -glm::dvec3{enddirection.x, grade, enddirection.y} * handle;
|
||||
fallback.pieces = {path};
|
||||
spread_rolls(fallback.pieces, a.roll, b.roll);
|
||||
fallback.length = distance;
|
||||
candidates.push_back(fallback);
|
||||
}
|
||||
candidates.push_back(bezier_join(frame));
|
||||
auto const count{static_cast<int>(candidates.size())};
|
||||
chosen = candidates[((Request.variant % count) + count) % count];
|
||||
auto chosen{candidates[((Request.variant % count) + count) % count]};
|
||||
chosen.variants = count;
|
||||
if (chosen.speed <= 0.0)
|
||||
chosen.speed = Request.speed;
|
||||
|
||||
@@ -264,6 +264,124 @@ void reset()
|
||||
g_loaded = false;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
std::optional<record> read_start(std::istringstream &Line, scene::layer_context const &Context, scene::layer_handle const Layer)
|
||||
{
|
||||
record entry;
|
||||
entry.layer = Layer;
|
||||
glm::dvec3 start;
|
||||
glm::dvec3 end;
|
||||
Line >> start.x >> start.y >> start.z >> end.x >> end.y >> end.z;
|
||||
if (Line.fail())
|
||||
return std::nullopt;
|
||||
entry.design.start = Context.to_world(start);
|
||||
entry.design.end = Context.to_world(end);
|
||||
return entry;
|
||||
}
|
||||
|
||||
std::optional<alignment::vertex> read_vertex(std::istringstream &Line, scene::layer_context const &Context)
|
||||
{
|
||||
alignment::vertex vertex;
|
||||
glm::dvec3 position{0.0};
|
||||
int reverse{0};
|
||||
int compound{0};
|
||||
std::size_t arcs{0};
|
||||
Line >> position.x >> position.z >> vertex.offset >> vertex.radius >> vertex.transition_in >> vertex.transition_out >> vertex.cant >> reverse >> compound >> vertex.share >> arcs;
|
||||
for (std::size_t i = 0; i < arcs && false == Line.fail(); ++i)
|
||||
{
|
||||
alignment::compound_arc arc;
|
||||
Line >> arc.radius >> arc.transition >> arc.share;
|
||||
vertex.arcs.push_back(arc);
|
||||
}
|
||||
if (Line.fail())
|
||||
return std::nullopt;
|
||||
position = Context.to_world(position);
|
||||
vertex.position = {position.x, position.z};
|
||||
vertex.reverse_turn = (reverse != 0);
|
||||
vertex.compound = (compound != 0);
|
||||
return vertex;
|
||||
}
|
||||
|
||||
void read_part(record &Entry, std::string const &Keyword, std::istringstream &Line, scene::layer_context const &Context)
|
||||
{
|
||||
auto &design{Entry.design};
|
||||
std::string word;
|
||||
if (Keyword == "source")
|
||||
{
|
||||
std::string shape;
|
||||
Line >> Entry.source >> word >> Entry.origin >> word >> shape >> word >> design.speed;
|
||||
design.shape = shape == "clothoid" ? alignment::transition_shape::clothoid : alignment::transition_shape::cubic_parabola;
|
||||
}
|
||||
else if (Keyword == "ends")
|
||||
{
|
||||
glm::dvec2 startdirection;
|
||||
glm::dvec2 enddirection;
|
||||
Line >> startdirection.x >> startdirection.y >> enddirection.x >> enddirection.y >> design.start_grade >> design.end_grade >> design.start_radius >> design.end_radius;
|
||||
design.start_direction = world_direction(Context, Context.to_local(design.start), startdirection);
|
||||
design.end_direction = world_direction(Context, Context.to_local(design.end), enddirection);
|
||||
}
|
||||
else if (Keyword == "norms")
|
||||
{
|
||||
auto &norms{design.norms};
|
||||
Line >> norms.gauge >> norms.unbalanced >> norms.cant_max >> norms.cant_rate >> norms.ramp_factor >> norms.jerk >> norms.tangent_min_time >> norms.arc_min >> norms.arc_min_factor;
|
||||
}
|
||||
else if (Keyword == "pieces")
|
||||
Line >> design.transition_pieces >> design.arc_piece_angle;
|
||||
else if (Keyword == "vertex")
|
||||
{
|
||||
if (auto const vertex{read_vertex(Line, Context)})
|
||||
design.vertices.push_back(*vertex);
|
||||
}
|
||||
else if (Keyword == "element")
|
||||
{
|
||||
stored_element e;
|
||||
Line >> e.kind >> e.vertex >> e.chainage >> e.length >> e.radius_start >> e.radius_end >> e.cant;
|
||||
if (false == Line.fail())
|
||||
Entry.elements.push_back(e);
|
||||
}
|
||||
}
|
||||
|
||||
void close_record(record &Entry, std::string const &Layer)
|
||||
{
|
||||
finish(Entry);
|
||||
if (false == Entry.result.valid || Entry.result.elements.empty())
|
||||
{
|
||||
WriteLog("Editor: a horizontal alignment in " + Layer + " doesn't make a line, left out", logtype::generic);
|
||||
return;
|
||||
}
|
||||
Entry.consistent = agrees(Entry.elements, Entry.result.elements);
|
||||
if (false == Entry.consistent)
|
||||
WriteLog("Editor: the elements of a horizontal alignment in " + Layer + " differ from the ones its design makes now", logtype::generic);
|
||||
g_records.push_back(std::move(Entry));
|
||||
}
|
||||
|
||||
void load_layer(scene::layer_handle const Layer)
|
||||
{
|
||||
auto const &context{scene::Layers.layer(Layer).context_insert()};
|
||||
std::optional<record> current;
|
||||
for (auto const &text : scene::Layers.marked(Layer, kMark))
|
||||
{
|
||||
std::istringstream line{text};
|
||||
std::string keyword;
|
||||
line >> keyword;
|
||||
if (keyword == "alignment")
|
||||
current = read_start(line, context, Layer);
|
||||
else if (false == current.has_value())
|
||||
continue;
|
||||
else if (keyword == "end")
|
||||
{
|
||||
close_record(*current, scene::Layers.layer(Layer).name);
|
||||
current.reset();
|
||||
}
|
||||
else
|
||||
read_part(*current, keyword, line, context);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void load()
|
||||
{
|
||||
if (g_loaded || scene::Layers.empty())
|
||||
@@ -271,102 +389,7 @@ void load()
|
||||
g_loaded = true;
|
||||
g_records.clear();
|
||||
for (auto const layer : scene::Layers.marked_layers(kMark))
|
||||
{
|
||||
auto const &context{scene::Layers.layer(layer).context_insert()};
|
||||
std::optional<record> current;
|
||||
std::vector<std::string> made;
|
||||
for (auto const &text : scene::Layers.marked(layer, kMark))
|
||||
{
|
||||
std::istringstream line{text};
|
||||
std::string keyword, word;
|
||||
line >> keyword;
|
||||
if (keyword == "alignment")
|
||||
{
|
||||
record entry;
|
||||
entry.layer = layer;
|
||||
glm::dvec3 start, end;
|
||||
line >> start.x >> start.y >> start.z >> end.x >> end.y >> end.z;
|
||||
if (line.fail())
|
||||
{
|
||||
current.reset();
|
||||
continue;
|
||||
}
|
||||
entry.design.start = context.to_world(start);
|
||||
entry.design.end = context.to_world(end);
|
||||
current = entry;
|
||||
continue;
|
||||
}
|
||||
if (false == current.has_value())
|
||||
continue;
|
||||
auto &entry{*current};
|
||||
auto &design{entry.design};
|
||||
if (keyword == "source")
|
||||
{
|
||||
std::string shape;
|
||||
line >> entry.source >> word >> entry.origin >> word >> shape >> word >> design.speed;
|
||||
design.shape = shape == "clothoid" ? alignment::transition_shape::clothoid : alignment::transition_shape::cubic_parabola;
|
||||
}
|
||||
else if (keyword == "ends")
|
||||
{
|
||||
glm::dvec2 startdirection, enddirection;
|
||||
line >> startdirection.x >> startdirection.y >> enddirection.x >> enddirection.y >> design.start_grade >> design.end_grade >> design.start_radius >> design.end_radius;
|
||||
design.start_direction = world_direction(context, context.to_local(design.start), startdirection);
|
||||
design.end_direction = world_direction(context, context.to_local(design.end), enddirection);
|
||||
}
|
||||
else if (keyword == "norms")
|
||||
{
|
||||
auto &norms{design.norms};
|
||||
line >> norms.gauge >> norms.unbalanced >> norms.cant_max >> norms.cant_rate >> norms.ramp_factor >> norms.jerk >> norms.tangent_min_time >> norms.arc_min >> norms.arc_min_factor;
|
||||
}
|
||||
else if (keyword == "pieces")
|
||||
{
|
||||
line >> design.transition_pieces >> design.arc_piece_angle;
|
||||
}
|
||||
else if (keyword == "vertex")
|
||||
{
|
||||
alignment::vertex vertex;
|
||||
glm::dvec3 position{0.0};
|
||||
int reverse{0}, compound{0};
|
||||
std::size_t arcs{0};
|
||||
line >> position.x >> position.z >> vertex.offset >> vertex.radius >> vertex.transition_in >> vertex.transition_out >> vertex.cant >> reverse >> compound >> vertex.share >> arcs;
|
||||
for (std::size_t i = 0; i < arcs && false == line.fail(); ++i)
|
||||
{
|
||||
alignment::compound_arc arc;
|
||||
line >> arc.radius >> arc.transition >> arc.share;
|
||||
vertex.arcs.push_back(arc);
|
||||
}
|
||||
if (line.fail())
|
||||
continue;
|
||||
position = context.to_world(position);
|
||||
vertex.position = {position.x, position.z};
|
||||
vertex.reverse_turn = (reverse != 0);
|
||||
vertex.compound = (compound != 0);
|
||||
design.vertices.push_back(vertex);
|
||||
}
|
||||
else if (keyword == "element")
|
||||
{
|
||||
stored_element e;
|
||||
line >> e.kind >> e.vertex >> e.chainage >> e.length >> e.radius_start >> e.radius_end >> e.cant;
|
||||
if (false == line.fail())
|
||||
entry.elements.push_back(e);
|
||||
}
|
||||
else if (keyword == "end")
|
||||
{
|
||||
finish(entry);
|
||||
if (false == entry.result.valid || entry.result.elements.empty())
|
||||
{
|
||||
WriteLog("Editor: a horizontal alignment in " + scene::Layers.layer(layer).name + " doesn't make a line, left out", logtype::generic);
|
||||
current.reset();
|
||||
continue;
|
||||
}
|
||||
entry.consistent = agrees(entry.elements, entry.result.elements);
|
||||
if (false == entry.consistent)
|
||||
WriteLog("Editor: the elements of a horizontal alignment in " + scene::Layers.layer(layer).name + " differ from the ones its design makes now", logtype::generic);
|
||||
g_records.push_back(std::move(entry));
|
||||
current.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
load_layer(layer);
|
||||
g_base = g_records;
|
||||
g_changed = false;
|
||||
if (false == g_records.empty())
|
||||
|
||||
Reference in New Issue
Block a user