Verified Commit f276b54f authored by Tobias WEBER's avatar Tobias WEBER
Browse files

more cleanups in paths builder

parent 9f8c8dcc
......@@ -1412,7 +1412,8 @@ std::vector<t_vec2> PathsBuilder::GetPathVertices(
const t_vec2 angle = PixelToAngle(vertex, deg);
bool insert_vertex = true;
// check the generated vertex for collisions
// check the generated vertex for collisions, and
// remove it in that case
if(this->m_verifypath)
{
const t_vec2 _angle = PixelToAngle(vertex, false, true);
......@@ -1421,29 +1422,37 @@ std::vector<t_vec2> PathsBuilder::GetPathVertices(
Instrument& instr = instrspace_cpy.GetInstrument();
// set scattering angles
// set scattering and crystal angles
if(kf_fixed)
{
instr.GetMonochromator().SetAxisAngleOut(a2);
else
instr.GetAnalyser().SetAxisAngleOut(a2);
instr.GetSample().SetAxisAngleOut(a4);
// set crystal angles
if(kf_fixed)
instr.GetMonochromator().SetAxisAngleInternal(0.5 * a2);
}
else
{
instr.GetAnalyser().SetAxisAngleOut(a2);
instr.GetAnalyser().SetAxisAngleInternal(0.5 * a2);
}
instr.GetSample().SetAxisAngleOut(a4);
//instr.GetSample().SetAxisAngleInternal(a3);
bool angle_ok = instrspace_cpy.CheckAngularLimits();
bool colliding = instrspace_cpy.CheckCollision2D();
if(!angle_ok || colliding)
{
insert_vertex = false;
//std::cout << "Collision at a2/6 = " << a2/tl2::pi<t_real>*180.
// << " and a4 = " << a4/tl2::pi<t_real>*180. << std::endl;
}
}
if(insert_vertex)
{
path_vertices.emplace_back(std::move(angle));
}
};
......@@ -1559,100 +1568,139 @@ std::vector<t_vec2> PathsBuilder::GetPathVertices(
if(m_directpath)
{
// test if a shortcut between the first and any other vertex on the path is possible
if(path_vertices.size() > 2)
{
const std::size_t start_idx = 0;
std::size_t min_idx = start_idx;
t_real min_dist_to_start = std::numeric_limits<t_real>::max();
bool distance_falling = false;
bool minimum_found = false;
RemovePathLoops(path_vertices, deg, false);
for(std::size_t idx = start_idx+1; idx<path_vertices.size(); ++idx)
{
t_real dist = GetPathLength(path_vertices[idx] - path_vertices[start_idx]);
// test if a shortcut between the last and any other vertex on the path is possible
RemovePathLoops(path_vertices, deg, true);
}
if(dist < min_dist_to_start)
{
// lengths become smaller
min_idx = idx;
min_dist_to_start = dist;
// ignore first index
if(idx > start_idx + 1)
distance_falling = true;
}
else
{
// distance was falling, but is rising again -> minimum found
if(distance_falling)
{
minimum_found = true;
break;
}
}
}
// interpolate points on path line segments
if(subdivide_lines)
{
path_vertices = geo::subdivide_lines<t_vec2>(path_vertices, m_subdiv_len);
path_vertices = geo::remove_close_vertices<t_vec2>(path_vertices, m_subdiv_len);
}
if(minimum_found && !DoesDirectPathCollide(path_vertices[start_idx], path_vertices[min_idx], deg))
{
// a shortcut was found
path_vertices.erase(path_vertices.begin()+start_idx+1, path_vertices.begin()+min_idx);
}
// final verification (this only works with path subdivision also active)
if(m_verifypath)
{
for(const t_vec2& pos : path_vertices)
{
if(DoesPositionCollide(pos, deg))
return {};
}
}
return path_vertices;
}
// test if a shortcut between the last and any other vertex on the path is possible
if(path_vertices.size() > 2)
{
const std::size_t start_idx = path_vertices.size() - 1;
std::size_t min_idx = start_idx;
t_real min_dist_to_start = std::numeric_limits<t_real>::max();
bool distance_falling = false;
bool minimum_found = false;
/**
* find and remove loops near the retraction points in the path
*/
void PathsBuilder::RemovePathLoops(std::vector<t_vec2>& path_vertices, bool deg, bool reverse) const
{
std::size_t N = path_vertices.size();
if(N <= 2)
return;
for(std::ptrdiff_t idx = (std::ptrdiff_t)start_idx-1; idx>=0; --idx)
// maximum angular search radius
t_real max_radius = m_directpath_search_radius;
if(deg)
max_radius = max_radius / tl2::pi<t_real> * t_real(180);
const std::size_t first_pt_idx = reverse ? N - 1 : 0;
const std::size_t second_pt_idx = reverse ? first_pt_idx-1 : first_pt_idx+1;
t_real min_dist_to_start = GetPathLength(path_vertices[second_pt_idx] - path_vertices[first_pt_idx]);
std::size_t min_idx = second_pt_idx;
bool distance_falling = false;
bool minimum_found = false;
std::size_t iter_idx = second_pt_idx;
// find first local minimum after first local maximum
// TODO: use peak finder for this
while(true)
{
t_real dist = GetPathLength(path_vertices[iter_idx] - path_vertices[first_pt_idx]);
if(dist < min_dist_to_start)
{
// lengths become smaller
min_idx = iter_idx;
min_dist_to_start = dist;
distance_falling = true;
}
else
{
// distance was falling, but is rising again -> minimum found
if(distance_falling)
{
t_real dist = GetPathLength(path_vertices[idx] - path_vertices[start_idx]);
//std::cout << "minimum index: " << min_idx << ", distance: " << min_dist_to_start << std::endl;
if(dist < min_dist_to_start)
{
// lengths become smaller
min_idx = idx;
min_dist_to_start = dist;
// within search radius?
if(dist <= max_radius)
minimum_found = true;
// ignore first index
if(idx < (std::ptrdiff_t)start_idx - 1)
distance_falling = true;
}
else
{
// distance was falling, but is rising again -> minimum found
if(distance_falling)
{
minimum_found = true;
break;
}
}
break;
}
if(minimum_found &&
!DoesDirectPathCollide(path_vertices[start_idx], path_vertices[min_idx], deg))
// initially rising distance
else
{
// a shortcut was found
path_vertices.erase(path_vertices.begin()+min_idx+1, path_vertices.begin()+start_idx);
min_dist_to_start = dist;
}
}
}
if(reverse)
{
if(iter_idx == 0)
break;
--iter_idx;
}
else
{
if(iter_idx >= N-1)
break;
++iter_idx;
}
}
// interpolate points on path line segments
if(subdivide_lines)
if(minimum_found && !DoesDirectPathCollide(path_vertices[first_pt_idx], path_vertices[min_idx], deg))
{
path_vertices = geo::subdivide_lines<t_vec2>(path_vertices, m_subdiv_len);
path_vertices = geo::remove_close_vertices<t_vec2>(path_vertices, m_subdiv_len);
std::size_t range_start = first_pt_idx;
std::size_t range_end = min_idx;
if(reverse)
std::swap(range_start, range_end);
// a shortcut was found
if(range_start+1 < range_end)
path_vertices.erase(path_vertices.begin()+range_start+1, path_vertices.begin()+range_end);
}
}
return path_vertices;
/**
* check if a position leads to a collision
*/
bool PathsBuilder::DoesPositionCollide(const t_vec2& pos, bool deg) const
{
t_vec2 pix = AngleToPixel(pos, deg, false);
t_int x = (t_int)pix[0];
t_int y = (t_int)pix[1];
if(x<0 || x>=(t_int)m_img.GetWidth() || y<0 || y>=(t_int)m_img.GetHeight())
return true;
// TODO: test if collision happens inside epsilon-circles, not just for the pixels
if(m_img.GetPixel(x, y) != PIXEL_VALUE_NOCOLLISION)
return true;
return false;
}
......
......@@ -120,6 +120,9 @@ protected:
// get path length, taking into account the motor speeds
t_real GetPathLength(const t_vec2& vec) const;
// check if a position leads to a collision
bool DoesPositionCollide(const t_vec2& pos, bool deg = false) const;
// check if a direct path between the two vertices leads to a collision
bool DoesDirectPathCollide(const t_vec2& vert1, const t_vec2& vert2, bool deg = false) const;
......@@ -136,6 +139,9 @@ protected:
FindClosestSegment(std::size_t vert_idx_1, std::size_t vert_idx_2,
const t_vec& vert, bool reversed_order = false) const;
// find and remove loops near the retraction points in the path
void RemovePathLoops(std::vector<t_vec2>& path_vertices, bool deg = false, bool reverse = false) const;
public:
PathsBuilder();
......@@ -244,6 +250,9 @@ public:
bool GetTryDirectPath() const { return m_directpath; }
void SetTryDirectPath(bool directpath) { m_directpath = directpath; }
t_real GetMaxDirectPathRadius() const { return m_directpath_search_radius; }
void SetMaxDirectPathRadius(t_real dist) { m_directpath_search_radius = dist; }
bool GetVerifyPath() const { return m_verifypath; }
void SetVerifyPath(bool verify) { m_verifypath = verify; }
......@@ -350,6 +359,9 @@ private:
// try to find a direct path if possible
bool m_directpath = true;
// radius inside with to search for direct paths
t_real m_directpath_search_radius = 20. / t_real(180.) * tl2::pi<t_real>;
// check the generated path for collisions
bool m_verifypath = true;
......
......@@ -1793,6 +1793,7 @@ void PathsTool::InitSettings()
m_pathsbuilder.SetVoronoiEdgeEpsilon(g_eps_voronoiedge);
m_pathsbuilder.SetSubdivisionLength(g_line_subdiv_len);
m_pathsbuilder.SetTryDirectPath(g_try_direct_path != 0);
m_pathsbuilder.SetMaxDirectPathRadius(g_directpath_search_radius);
m_pathsbuilder.SetVerifyPath(g_verifypath != 0);
m_pathsbuilder.SetMinDistToWalls(g_min_dist_to_walls);
m_pathsbuilder.SetRemoveBisectorsBelowMinWallDist(g_remove_bisectors_below_min_wall_dist != 0);
......@@ -2245,8 +2246,14 @@ void PathsTool::CalculatePath()
// get the vertices on the path
SetTmpStatus("Retrieving path vertices.");
m_pathvertices = m_pathsbuilder.GetPathVertices(path, true, false);
emit PathAvailable(m_pathvertices.size());
if(!m_pathvertices.size())
{
QMessageBox::critical(this, "Error", "No valid path could be found.");
SetTmpStatus("Error: No valid path could be found.");
return;
}
emit PathAvailable(m_pathvertices.size());
SetTmpStatus("Path calculated.");
}
......
......@@ -74,7 +74,7 @@ int g_voronoi_backend = 0;
int g_use_region_function = 1;
// use bisector verification function
int g_remove_bisectors_below_min_wall_dist = 1;
int g_remove_bisectors_below_min_wall_dist = 0;
// path-finding options
......@@ -82,6 +82,10 @@ int g_pathstrategy = 0;
int g_try_direct_path = 1;
int g_verifypath = 1;
// maximum angular search radius for direct paths
t_real g_directpath_search_radius = 20. / t_real(180.) * tl2::pi<t_real>;
// minimum distance to keep from the walls
t_real g_min_dist_to_walls = 5. / t_real(180.) * tl2::pi<t_real>;
......
......@@ -96,6 +96,9 @@ extern int g_pathstrategy;
// choose a direct path if possible
extern int g_try_direct_path;
// maximum angular search radius for direct paths
extern t_real g_directpath_search_radius;
// verify the generated path?
extern int g_verifypath;
......@@ -150,7 +153,7 @@ extern int g_nested_docks;
// ----------------------------------------------------------------------------
// variables register
// ----------------------------------------------------------------------------
constexpr std::array<SettingsVariable, 26> g_settingsvariables
constexpr std::array<SettingsVariable, 27> g_settingsvariables
{{
// epsilons and precisions
{
......@@ -246,7 +249,7 @@ constexpr std::array<SettingsVariable, 26> g_settingsvariables
.editor = SettingsVariableEditor::YESNO,
},
{
.description = "Remove bisectors close to walls",
.description = "Remove bisectors close to walls (careful!)",
.key = "settings/remove_bisectors_below_min_wall_dist",
.value = &g_remove_bisectors_below_min_wall_dist,
.editor = SettingsVariableEditor::YESNO,
......@@ -266,6 +269,12 @@ constexpr std::array<SettingsVariable, 26> g_settingsvariables
.value = &g_try_direct_path,
.editor = SettingsVariableEditor::YESNO,
},
{
.description = "Angular search radius for direct path",
.key = "settings/direct_path_search_radius",
.value = &g_directpath_search_radius,
.is_angle = true,
},
{
.description = "Verify generated path",
.key = "settings/verify_path",
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment