mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-06 11:38:38 +01:00
feat(editor): crossover snaps to parallel straight
This commit is contained in:
@@ -415,6 +415,8 @@ class editor_mode : public application_mode
|
|||||||
glm::dvec2 direction{0.0, 1.0};
|
glm::dvec2 direction{0.0, 1.0};
|
||||||
double grade{0.0};
|
double grade{0.0};
|
||||||
glm::dvec3 mouse{0.0};
|
glm::dvec3 mouse{0.0};
|
||||||
|
int path{0};
|
||||||
|
bool atend{true};
|
||||||
};
|
};
|
||||||
extend_tool m_extend;
|
extend_tool m_extend;
|
||||||
void render_switch_ui();
|
void render_switch_ui();
|
||||||
@@ -422,9 +424,22 @@ class editor_mode : public application_mode
|
|||||||
void finish_switch_placement();
|
void finish_switch_placement();
|
||||||
std::vector<segment_data> switch_preview() const;
|
std::vector<segment_data> switch_preview() const;
|
||||||
void insert_switch(editor_track::straight const &Line, double const Along, int const Direction, int const Side);
|
void insert_switch(editor_track::straight const &Line, double const Along, int const Direction, int const Side);
|
||||||
|
bool place_switch_on_straight(editor_track::straight const &Line, editor_track::switch_template const &Shape, TTrack const *Style, double const Along, int const Direction, int const Side, bool const Snap, std::vector<std::pair<TTrack *, editor_track::state>> &States, std::vector<TTrack *> &Created, std::vector<TTrack *> &Removed);
|
||||||
|
struct crossover_plan
|
||||||
|
{
|
||||||
|
editor_track::straight target;
|
||||||
|
editor_track::switch_template shape;
|
||||||
|
double along{0.0};
|
||||||
|
int direction{1};
|
||||||
|
int side{1};
|
||||||
|
segment_data insert;
|
||||||
|
std::vector<segment_data> paths;
|
||||||
|
};
|
||||||
|
bool plan_crossover(crossover_plan &Plan) const;
|
||||||
bool start_extend();
|
bool start_extend();
|
||||||
void finish_extend();
|
void finish_extend();
|
||||||
std::vector<segment_data> extend_pieces() const;
|
std::vector<segment_data> extend_pieces() const;
|
||||||
|
bool extend_snap(editor_track::snap_target &Target) const;
|
||||||
void update_build_tools();
|
void update_build_tools();
|
||||||
void draw_build_overlay() const;
|
void draw_build_overlay() const;
|
||||||
enum class track_tab { straights, route, path, turnout };
|
enum class track_tab { straights, route, path, turnout };
|
||||||
|
|||||||
@@ -2448,6 +2448,8 @@ bool editor_mode::start_extend()
|
|||||||
if (glm::length(planar) < 1e-6)
|
if (glm::length(planar) < 1e-6)
|
||||||
return false;
|
return false;
|
||||||
m_extend.active = true;
|
m_extend.active = true;
|
||||||
|
m_extend.path = i;
|
||||||
|
m_extend.atend = atend;
|
||||||
m_extend.track = track;
|
m_extend.track = track;
|
||||||
m_extend.point = position;
|
m_extend.point = position;
|
||||||
m_extend.direction = glm::normalize(planar);
|
m_extend.direction = glm::normalize(planar);
|
||||||
@@ -2459,10 +2461,53 @@ bool editor_mode::start_extend()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool editor_mode::extend_snap(editor_track::snap_target &Target) const
|
||||||
|
{
|
||||||
|
auto const &tool{m_extend};
|
||||||
|
if (false == tool.active || tool.track == nullptr)
|
||||||
|
return false;
|
||||||
|
Target = editor_track::find_snap_target(*tool.track, tool.mouse, 5.0, {tool.track});
|
||||||
|
return Target.track != nullptr && glm::distance(Target.position, tool.point) > 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<segment_data> editor_mode::extend_pieces() const
|
std::vector<segment_data> editor_mode::extend_pieces() const
|
||||||
{
|
{
|
||||||
std::vector<segment_data> result;
|
std::vector<segment_data> result;
|
||||||
auto const &tool{m_extend};
|
auto const &tool{m_extend};
|
||||||
|
editor_track::snap_target target;
|
||||||
|
if (extend_snap(target))
|
||||||
|
{
|
||||||
|
alignment::design design;
|
||||||
|
design.norms = m_route.design.norms;
|
||||||
|
design.shape = m_route.design.shape;
|
||||||
|
design.arc_piece_angle = 90.0;
|
||||||
|
design.start = tool.point;
|
||||||
|
design.end = target.position;
|
||||||
|
design.start_direction = tool.direction;
|
||||||
|
design.end_direction = glm::normalize(glm::dvec2{target.direction.x, target.direction.z});
|
||||||
|
auto const speed{editor_track::velocity(*tool.track)};
|
||||||
|
design.speed = speed > 0.0 ? speed : 100.0;
|
||||||
|
if (false == alignment::collinear(design))
|
||||||
|
{
|
||||||
|
alignment::vertex vertex;
|
||||||
|
vertex.radius = 100000.0;
|
||||||
|
auto const recommended{alignment::recommend(design.speed, 1000.0, design.norms)};
|
||||||
|
vertex.transition_in = vertex.transition_out = recommended.transition;
|
||||||
|
glm::dvec2 intersection;
|
||||||
|
if (alignment::tangent_intersection(design, intersection))
|
||||||
|
{
|
||||||
|
design.vertices.push_back(vertex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vertex.offset = glm::distance(glm::dvec2{design.start.x, design.start.z}, glm::dvec2{design.end.x, design.end.z}) / 3.0;
|
||||||
|
design.vertices = {vertex, vertex};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto const shape{alignment::compute(design)};
|
||||||
|
if (shape.valid)
|
||||||
|
return alignment::pieces(shape, design, 0);
|
||||||
|
}
|
||||||
glm::dvec2 const offset{tool.mouse.x - tool.point.x, tool.mouse.z - tool.point.z};
|
glm::dvec2 const offset{tool.mouse.x - tool.point.x, tool.mouse.z - tool.point.z};
|
||||||
auto const chord{glm::length(offset)};
|
auto const chord{glm::length(offset)};
|
||||||
if (chord < 0.5)
|
if (chord < 0.5)
|
||||||
@@ -2517,6 +2562,28 @@ std::vector<segment_data> editor_mode::extend_pieces() const
|
|||||||
|
|
||||||
void editor_mode::finish_extend()
|
void editor_mode::finish_extend()
|
||||||
{
|
{
|
||||||
|
crossover_plan plan;
|
||||||
|
editor_track::snap_target target;
|
||||||
|
if (false == extend_snap(target) && plan_crossover(plan))
|
||||||
|
{
|
||||||
|
auto *origin{m_extend.track};
|
||||||
|
m_extend.active = false;
|
||||||
|
std::vector<std::pair<TTrack *, editor_track::state>> states;
|
||||||
|
std::vector<TTrack *> created;
|
||||||
|
std::vector<TTrack *> removed;
|
||||||
|
if (false == place_switch_on_straight(plan.target, plan.shape, origin, plan.along, plan.direction, plan.side, false, states, created, removed))
|
||||||
|
return;
|
||||||
|
if (glm::distance(plan.insert.points[segment_data::point::start], plan.insert.points[segment_data::point::end]) > 0.01)
|
||||||
|
{
|
||||||
|
auto *insert{editor_track::create_path(*origin, plan.insert)};
|
||||||
|
editor_track::commit({insert});
|
||||||
|
created.push_back(insert);
|
||||||
|
}
|
||||||
|
push_track_snapshot(std::move(states), std::move(created));
|
||||||
|
m_history.back().removed = std::move(removed);
|
||||||
|
straight_refresh();
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto const pieces{extend_pieces()};
|
auto const pieces{extend_pieces()};
|
||||||
auto *style{m_extend.track};
|
auto *style{m_extend.track};
|
||||||
m_extend.active = false;
|
m_extend.active = false;
|
||||||
@@ -2577,12 +2644,23 @@ void editor_mode::finish_switch_placement()
|
|||||||
|
|
||||||
void editor_mode::insert_switch(editor_track::straight const &Line, double const Along, int const Direction, int const Side)
|
void editor_mode::insert_switch(editor_track::straight const &Line, double const Along, int const Direction, int const Side)
|
||||||
{
|
{
|
||||||
auto &state{m_straights};
|
std::vector<std::pair<TTrack *, editor_track::state>> states;
|
||||||
state.status.clear();
|
std::vector<TTrack *> created;
|
||||||
auto const &shape{m_switch.templates[m_switch.armed]};
|
std::vector<TTrack *> removed;
|
||||||
if (shape.length > Line.length - 0.02)
|
if (false == place_switch_on_straight(Line, m_switch.templates[m_switch.armed], nullptr, Along, Direction, Side, true, states, created, removed))
|
||||||
return;
|
return;
|
||||||
|
push_track_snapshot(std::move(states), std::move(created));
|
||||||
|
m_history.back().removed = std::move(removed);
|
||||||
|
straight_refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool editor_mode::place_switch_on_straight(editor_track::straight const &Line, editor_track::switch_template const &Shape, TTrack const *Style, double const Along, int const Direction, int const Side, bool const Snap, std::vector<std::pair<TTrack *, editor_track::state>> &States, std::vector<TTrack *> &Created, std::vector<TTrack *> &Removed)
|
||||||
|
{
|
||||||
|
auto const &shape{Shape};
|
||||||
|
if (shape.length > Line.length - 0.02)
|
||||||
|
return false;
|
||||||
auto from{std::clamp(Direction > 0 ? Along : Along - shape.length, 0.0, Line.length - shape.length)};
|
auto from{std::clamp(Direction > 0 ? Along : Along - shape.length, 0.0, Line.length - shape.length)};
|
||||||
|
if (Snap)
|
||||||
{
|
{
|
||||||
std::vector<double> joints{0.0, Line.length};
|
std::vector<double> joints{0.0, Line.length};
|
||||||
for (std::size_t i = 0; i < Line.tracks.size(); ++i)
|
for (std::size_t i = 0; i < Line.tracks.size(); ++i)
|
||||||
@@ -2636,12 +2714,12 @@ void editor_mode::insert_switch(editor_track::straight const &Line, double const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (first < 0)
|
if (first < 0)
|
||||||
return;
|
return false;
|
||||||
editor_track::chain chain;
|
editor_track::chain chain;
|
||||||
for (int i = first; i <= last; ++i)
|
for (int i = first; i <= last; ++i)
|
||||||
{
|
{
|
||||||
if (spans[i].track->eType != tt_Normal)
|
if (spans[i].track->eType != tt_Normal)
|
||||||
return;
|
return false;
|
||||||
chain.tracks.push_back(spans[i].track);
|
chain.tracks.push_back(spans[i].track);
|
||||||
chain.forward.push_back(spans[i].forward);
|
chain.forward.push_back(spans[i].forward);
|
||||||
}
|
}
|
||||||
@@ -2651,22 +2729,20 @@ void editor_mode::insert_switch(editor_track::straight const &Line, double const
|
|||||||
bool const hasafter{after > 0.01};
|
bool const hasafter{after > 0.01};
|
||||||
auto const point = [&](double const Distance) { return Line.start + glm::dvec3{Line.direction.x, Line.grade, Line.direction.y} * Distance; };
|
auto const point = [&](double const Distance) { return Line.start + glm::dvec3{Line.direction.x, Line.grade, Line.direction.y} * Distance; };
|
||||||
glm::dvec2 const direction{Line.direction * static_cast<double>(Direction)};
|
glm::dvec2 const direction{Line.direction * static_cast<double>(Direction)};
|
||||||
|
auto const &style{Style != nullptr ? *Style : *spans[first].track};
|
||||||
if (false == hasbefore && false == hasafter)
|
if (false == hasbefore && false == hasafter)
|
||||||
{
|
{
|
||||||
for (auto *track : chain.tracks)
|
for (auto *track : chain.tracks)
|
||||||
editor_track::retire(*track);
|
editor_track::retire(*track);
|
||||||
|
Removed.insert(Removed.end(), chain.tracks.begin(), chain.tracks.end());
|
||||||
auto const paths{editor_track::place_switch(shape, point(origin), direction, Side, Line.grade * Direction)};
|
auto const paths{editor_track::place_switch(shape, point(origin), direction, Side, Line.grade * Direction)};
|
||||||
auto *track{editor_track::create_switch(shape, paths, *spans[first].track)};
|
auto *track{editor_track::create_switch(shape, paths, style)};
|
||||||
std::vector<TTrack *> created;
|
|
||||||
if (track != nullptr)
|
if (track != nullptr)
|
||||||
{
|
{
|
||||||
editor_track::commit({track});
|
editor_track::commit({track});
|
||||||
created.push_back(track);
|
Created.push_back(track);
|
||||||
}
|
}
|
||||||
push_track_snapshot({}, std::move(created));
|
return true;
|
||||||
m_history.back().removed = chain.tracks;
|
|
||||||
straight_refresh();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
auto const count{std::max<std::size_t>(chain.tracks.size(), (hasbefore ? 1 : 0) + (hasafter ? 1 : 0))};
|
auto const count{std::max<std::size_t>(chain.tracks.size(), (hasbefore ? 1 : 0) + (hasafter ? 1 : 0))};
|
||||||
std::size_t countbefore{0};
|
std::size_t countbefore{0};
|
||||||
@@ -2689,20 +2765,18 @@ void editor_mode::insert_switch(editor_track::straight const &Line, double const
|
|||||||
if (hasafter)
|
if (hasafter)
|
||||||
straight(to, spans[last].to, count - countbefore);
|
straight(to, spans[last].to, count - countbefore);
|
||||||
|
|
||||||
std::vector<std::pair<TTrack *, editor_track::state>> states;
|
|
||||||
for (auto *track : chain.tracks)
|
for (auto *track : chain.tracks)
|
||||||
states.emplace_back(track, editor_track::capture(*track));
|
States.emplace_back(track, editor_track::capture(*track));
|
||||||
auto created{editor_track::relay(chain, pieces)};
|
auto const relaid{editor_track::relay(chain, pieces)};
|
||||||
|
Created.insert(Created.end(), relaid.begin(), relaid.end());
|
||||||
auto const paths{editor_track::place_switch(shape, point(origin), direction, Side, Line.grade * Direction)};
|
auto const paths{editor_track::place_switch(shape, point(origin), direction, Side, Line.grade * Direction)};
|
||||||
auto *track{editor_track::create_switch(shape, paths, *spans[first].track)};
|
auto *track{editor_track::create_switch(shape, paths, style)};
|
||||||
if (track != nullptr)
|
if (track != nullptr)
|
||||||
{
|
{
|
||||||
editor_track::commit({track});
|
editor_track::commit({track});
|
||||||
created.push_back(track);
|
Created.push_back(track);
|
||||||
}
|
}
|
||||||
push_track_snapshot(std::move(states), std::move(created));
|
return true;
|
||||||
straight_refresh();
|
|
||||||
state.status = "Switch inserted";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void editor_mode::draw_build_overlay() const
|
void editor_mode::draw_build_overlay() const
|
||||||
@@ -2719,8 +2793,29 @@ void editor_mode::draw_build_overlay() const
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (m_extend.active)
|
if (m_extend.active)
|
||||||
for (auto const &piece : extend_pieces())
|
{
|
||||||
drawpath(piece, IM_COL32(255, 210, 60, 255));
|
crossover_plan plan;
|
||||||
|
editor_track::snap_target target;
|
||||||
|
if (extend_snap(target))
|
||||||
|
{
|
||||||
|
ImVec2 screen;
|
||||||
|
if (projection.project(target.position, screen))
|
||||||
|
drawlist->AddCircle(screen, 14.0f, IM_COL32(255, 60, 255, 255), 20, 3.0f);
|
||||||
|
for (auto const &piece : extend_pieces())
|
||||||
|
drawpath(piece, IM_COL32(255, 210, 60, 255));
|
||||||
|
}
|
||||||
|
else if (plan_crossover(plan))
|
||||||
|
{
|
||||||
|
for (auto const &piece : plan.paths)
|
||||||
|
drawpath(piece, IM_COL32(255, 210, 60, 255));
|
||||||
|
drawpath(plan.insert, IM_COL32(60, 230, 90, 255));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (auto const &piece : extend_pieces())
|
||||||
|
drawpath(piece, IM_COL32(255, 210, 60, 255));
|
||||||
|
}
|
||||||
|
}
|
||||||
if (m_switch.placing)
|
if (m_switch.placing)
|
||||||
for (auto const &piece : switch_preview())
|
for (auto const &piece : switch_preview())
|
||||||
drawpath(piece, IM_COL32(255, 210, 60, 255));
|
drawpath(piece, IM_COL32(255, 210, 60, 255));
|
||||||
@@ -2992,3 +3087,102 @@ void editor_mode::update_curve_fit(glm::dvec3 const &Start, glm::dvec3 const &En
|
|||||||
design.vertices = {before, after};
|
design.vertices = {before, after};
|
||||||
route_update();
|
route_update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool editor_mode::plan_crossover(crossover_plan &Plan) const
|
||||||
|
{
|
||||||
|
auto const &tool{m_extend};
|
||||||
|
if (false == tool.active || tool.track == nullptr || tool.track->eType != tt_Switch || tool.track->m_paths.size() < 2 || tool.path != 1 || false == tool.atend)
|
||||||
|
return false;
|
||||||
|
auto const &own{*tool.track};
|
||||||
|
auto const &main{own.m_paths[0]};
|
||||||
|
auto const &diverging{own.m_paths[1]};
|
||||||
|
auto const plan = [](glm::dvec3 const &Point) { return glm::dvec2{Point.x, Point.z}; };
|
||||||
|
auto const cross = [](glm::dvec2 const &A, glm::dvec2 const &B) { return A.x * B.y - A.y * B.x; };
|
||||||
|
auto const origin{main.points[segment_data::point::start]};
|
||||||
|
auto const axis{glm::normalize(plan(main.points[segment_data::point::end] - origin))};
|
||||||
|
glm::dvec2 const perpendicular{-axis.y, axis.x};
|
||||||
|
auto const &frog{diverging.points[segment_data::point::end]};
|
||||||
|
auto const lateral{glm::dot(plan(frog - origin), perpendicular)};
|
||||||
|
if (std::abs(lateral) < 0.01)
|
||||||
|
return false;
|
||||||
|
auto const side{lateral > 0.0 ? 1.0 : -1.0};
|
||||||
|
auto const normal{perpendicular * side};
|
||||||
|
auto const offset{std::abs(lateral)};
|
||||||
|
auto const &control{diverging.points[segment_data::point::control2]};
|
||||||
|
auto const tangent{glm::normalize(control != glm::dvec3{} ? -plan(control) : plan(frog - origin))};
|
||||||
|
auto const angle{std::atan2(std::abs(cross(axis, tangent)), glm::dot(axis, tangent))};
|
||||||
|
if (angle < 1e-4)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto const ground{tool.mouse};
|
||||||
|
TTrack *target{nullptr};
|
||||||
|
double best{8.0};
|
||||||
|
auto const sections{simulation::Region->sections(ground, 40.f)};
|
||||||
|
for (auto *section : sections)
|
||||||
|
{
|
||||||
|
for (auto const &cell : section->m_cells)
|
||||||
|
{
|
||||||
|
for (auto *track : cell.m_paths)
|
||||||
|
{
|
||||||
|
if (track == &own || track->eType != tt_Normal || track->m_editorremoved || false == editor_track::is_straight(*track, m_straights.tolerance))
|
||||||
|
continue;
|
||||||
|
auto const &path{track->m_paths.front()};
|
||||||
|
auto const a{plan(path.points[segment_data::point::start])};
|
||||||
|
auto const b{plan(path.points[segment_data::point::end])};
|
||||||
|
auto const segment{b - a};
|
||||||
|
auto const t{std::clamp(glm::dot(plan(ground) - a, segment) / std::max(1e-9, glm::dot(segment, segment)), 0.0, 1.0)};
|
||||||
|
auto const distance{glm::distance(plan(ground), a + segment * t)};
|
||||||
|
if (distance < best)
|
||||||
|
{
|
||||||
|
best = distance;
|
||||||
|
target = track;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (target == nullptr)
|
||||||
|
return false;
|
||||||
|
Plan.target = editor_track::find_straight(*target, m_straights.tolerance);
|
||||||
|
auto const &line{Plan.target};
|
||||||
|
if (line.tracks.empty() || std::abs(cross(line.direction, axis)) > std::sin(glm::radians(1.0)))
|
||||||
|
return false;
|
||||||
|
auto const distance{glm::dot(plan(line.start) - plan(origin), normal)};
|
||||||
|
auto const remaining{distance - 2.0 * offset};
|
||||||
|
if (remaining < 0.01)
|
||||||
|
return false;
|
||||||
|
auto const length{remaining / std::sin(angle)};
|
||||||
|
glm::dvec2 const crossing{axis * std::cos(angle) + normal * std::sin(angle)};
|
||||||
|
auto const alongfrog{glm::dot(plan(frog - origin), axis)};
|
||||||
|
auto const otherfrog{plan(frog) + crossing * length};
|
||||||
|
auto const otherorigin{otherfrog + axis * alongfrog + normal * offset};
|
||||||
|
Plan.along = glm::dot(otherorigin - plan(line.start), line.direction);
|
||||||
|
if (Plan.along < 0.0 || Plan.along > line.length)
|
||||||
|
return false;
|
||||||
|
Plan.direction = glm::dot(-axis, line.direction) > 0.0 ? 1 : -1;
|
||||||
|
glm::dvec2 const direction{line.direction * static_cast<double>(Plan.direction)};
|
||||||
|
Plan.side = glm::dot(glm::dvec2{-direction.y, direction.x}, -normal) > 0.0 ? 1 : -1;
|
||||||
|
|
||||||
|
editor_track::switch_template shape;
|
||||||
|
shape.source = tool.track;
|
||||||
|
shape.length = glm::dot(plan(main.points[segment_data::point::end] - origin), axis);
|
||||||
|
for (int i = 0; i < 2; ++i)
|
||||||
|
{
|
||||||
|
auto const &path{own.m_paths[i]};
|
||||||
|
auto &local{shape.local[i]};
|
||||||
|
local = path;
|
||||||
|
auto const tolocal = [&](glm::dvec3 const &Vector) { return glm::dvec3{glm::dot(plan(Vector), perpendicular) * side, Vector.y, glm::dot(plan(Vector), axis)}; };
|
||||||
|
local.points[segment_data::point::start] = tolocal(path.points[segment_data::point::start] - origin);
|
||||||
|
local.points[segment_data::point::end] = tolocal(path.points[segment_data::point::end] - origin);
|
||||||
|
local.points[segment_data::point::control1] = tolocal(path.points[segment_data::point::control1]);
|
||||||
|
local.points[segment_data::point::control2] = tolocal(path.points[segment_data::point::control2]);
|
||||||
|
if (side < 0.0)
|
||||||
|
local.rolls = {-local.rolls[0], -local.rolls[1]};
|
||||||
|
}
|
||||||
|
Plan.shape = shape;
|
||||||
|
auto const station{line.start + glm::dvec3{line.direction.x, line.grade, line.direction.y} * Plan.along};
|
||||||
|
Plan.paths = editor_track::place_switch(shape, station, direction, Plan.side, line.grade * Plan.direction);
|
||||||
|
Plan.insert = segment_data{};
|
||||||
|
Plan.insert.points[segment_data::point::start] = frog;
|
||||||
|
Plan.insert.points[segment_data::point::end] = Plan.paths[1].points[segment_data::point::end];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@@ -217,21 +217,21 @@ glm::dvec2 blossom(std::array<glm::dvec2, 4> const &Points, double const A, doub
|
|||||||
return glm::mix(s[0], s[1], C);
|
return glm::mix(s[0], s[1], C);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t element_pieces(element const &Element, transition_shape const Shape, int const Transitions)
|
std::size_t element_pieces(element const &Element, transition_shape const Shape, int const Transitions, double const Arcangle)
|
||||||
{
|
{
|
||||||
if (Element.length < 1e-3)
|
if (Element.length < 1e-3)
|
||||||
return 0;
|
return 0;
|
||||||
switch (Element.kind)
|
switch (Element.kind)
|
||||||
{
|
{
|
||||||
case element_kind::arc:
|
case element_kind::arc:
|
||||||
return static_cast<std::size_t>(std::max(1.0, std::ceil(Element.length / Element.radius / (10.0 * kPi / 180.0) - 1e-9)));
|
return static_cast<std::size_t>(std::max(1.0, std::ceil(Element.length / Element.radius / (Arcangle * kPi / 180.0) - 1e-9)));
|
||||||
case element_kind::transition_in:
|
case element_kind::transition_in:
|
||||||
case element_kind::transition_out:
|
case element_kind::transition_out:
|
||||||
return std::max<std::size_t>(std::max(1, Transitions), Shape == transition_shape::cubic_parabola ? 1 : static_cast<std::size_t>(std::max(1.0, std::ceil(Element.length / 20.0 - 1e-9))));
|
return std::max<std::size_t>(std::max(1, Transitions), Shape == transition_shape::cubic_parabola ? 1 : static_cast<std::size_t>(std::max(1.0, std::ceil(Element.length / 20.0 - 1e-9))));
|
||||||
case element_kind::spiral:
|
case element_kind::spiral:
|
||||||
{
|
{
|
||||||
auto const turn{(Element.curvature_start + Element.curvature_end) * 0.5 * Element.length};
|
auto const turn{(Element.curvature_start + Element.curvature_end) * 0.5 * Element.length};
|
||||||
auto const count{static_cast<std::size_t>(std::max({1.0, std::ceil(turn / (10.0 * kPi / 180.0) - 1e-9), std::ceil(Element.length / 20.0 - 1e-9)}))};
|
auto const count{static_cast<std::size_t>(std::max({1.0, std::ceil(turn / (Arcangle * kPi / 180.0) - 1e-9), std::ceil(Element.length / 20.0 - 1e-9)}))};
|
||||||
return Element.curvature_start != Element.curvature_end ? std::max<std::size_t>(count, std::max(1, Transitions)) : count;
|
return Element.curvature_start != Element.curvature_end ? std::max<std::size_t>(count, std::max(1, Transitions)) : count;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -855,7 +855,7 @@ std::size_t minimum_pieces(result const &Result, design const &Design)
|
|||||||
{
|
{
|
||||||
std::size_t count{0};
|
std::size_t count{0};
|
||||||
for (auto const &e : Result.elements)
|
for (auto const &e : Result.elements)
|
||||||
count += element_pieces(e, Design.shape, Design.transition_pieces);
|
count += element_pieces(e, Design.shape, Design.transition_pieces, Design.arc_piece_angle);
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -876,7 +876,7 @@ std::vector<segment_data> pieces(result const &Result, design const &Design, std
|
|||||||
for (std::size_t i = 0; i < Result.elements.size(); ++i)
|
for (std::size_t i = 0; i < Result.elements.size(); ++i)
|
||||||
{
|
{
|
||||||
auto const &e{Result.elements[i]};
|
auto const &e{Result.elements[i]};
|
||||||
auto const count{element_pieces(e, Design.shape, Design.transition_pieces)};
|
auto const count{element_pieces(e, Design.shape, Design.transition_pieces, Design.arc_piece_angle)};
|
||||||
for (std::size_t j = 0; j < count; ++j)
|
for (std::size_t j = 0; j < count; ++j)
|
||||||
spans.push_back({i, e.length * j / count, e.length * (j + 1) / count});
|
spans.push_back({i, e.length * j / count, e.length * (j + 1) / count});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ struct design
|
|||||||
transition_shape shape{transition_shape::cubic_parabola};
|
transition_shape shape{transition_shape::cubic_parabola};
|
||||||
double speed{100.0};
|
double speed{100.0};
|
||||||
int transition_pieces{1};
|
int transition_pieces{1};
|
||||||
|
double arc_piece_angle{10.0};
|
||||||
limits norms;
|
limits norms;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user