Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Scientific Software
Takin
TAS-Paths
Commits
2f284b53
Verified
Commit
2f284b53
authored
Nov 30, 2021
by
Tobias WEBER
Browse files
ensuring that retraction points are far enough from any wall
parent
98d2c09e
Changes
3
Hide whitespace changes
Inline
Side-by-side
src/core/PathsBuilder.cpp
View file @
2f284b53
...
...
@@ -621,7 +621,7 @@ bool PathsBuilder::CalculateVoronoi(bool group_lines, VoronoiBackend backend,
std
::
string
message
{
"Calculating Voronoi diagram..."
};
(
*
m_sigProgress
)(
CalculationState
::
STEP_STARTED
,
0
,
message
);
// is the ve
ctor
in a forbidden region?
// is the ve
rtex
in a forbidden region?
std
::
function
<
bool
(
const
t_vec2
&
)
>
region_func
=
[
this
](
const
t_vec2
&
vec
)
->
bool
{
if
(
vec
[
0
]
<
0
||
vec
[
1
]
<
0
)
...
...
@@ -640,6 +640,13 @@ bool PathsBuilder::CalculateVoronoi(bool group_lines, VoronoiBackend backend,
return
false
;
};
// validation function that checks if (voronoi) vertices are far enough from any wall
std
::
function
<
bool
(
const
t_vec2
&
)
>
validation_func
=
[
this
](
const
t_vec2
&
vec
)
->
bool
{
t_real
dist_to_walls
=
GetDistToNearestWall
(
vec
);
return
dist_to_walls
>=
m_min_angular_dist_to_walls
;
};
geo
::
VoronoiLinesRegions
<
t_vec2
,
t_line
>
regions
{};
regions
.
SetGroupLines
(
group_lines
);
regions
.
SetRemoveVoronoiVertices
(
true
);
...
...
@@ -647,6 +654,7 @@ bool PathsBuilder::CalculateVoronoi(bool group_lines, VoronoiBackend backend,
regions
.
SetPointsOutsideRegions
(
&
m_points_outside_regions
);
regions
.
SetInvertedRegions
(
&
m_inverted_regions
);
regions
.
SetRegionFunc
(
use_region_function
?
&
region_func
:
nullptr
);
regions
.
SetValidateFunc
(
&
validation_func
);
if
(
backend
==
VoronoiBackend
::
BOOST
)
{
...
...
@@ -662,6 +670,12 @@ bool PathsBuilder::CalculateVoronoi(bool group_lines, VoronoiBackend backend,
m_lines
,
m_eps
,
m_voroedge_eps
,
&
regions
);
}
#endif
else
{
// invalid backend selected
(
*
m_sigProgress
)(
CalculationState
::
FAILED
,
1
,
message
);
return
false
;
}
(
*
m_sigProgress
)(
CalculationState
::
STEP_SUCCEEDED
,
1
,
message
);
return
true
;
...
...
@@ -851,6 +865,7 @@ InstrumentPath PathsBuilder::FindPath(
return
path
;
}
// convert angles to degrees
a2_i
*=
180.
/
tl2
::
pi
<
t_real
>
;
a4_i
*=
180.
/
tl2
::
pi
<
t_real
>
;
...
...
@@ -964,22 +979,9 @@ InstrumentPath PathsBuilder::FindPath(
const
t_vec2
&
vertex1
=
voro_vertices
[
idx1
];
const
t_vec2
&
vertex2
=
voro_vertices
[
idx2
];
// get the wall vertices that are closest to the current voronoi vertices
auto
nearest_vertices1
=
m_wallsindextree
.
Query
(
vertex1
,
1
);
auto
nearest_vertices2
=
m_wallsindextree
.
Query
(
vertex2
,
1
);
if
(
nearest_vertices1
.
size
()
<
1
||
nearest_vertices2
.
size
()
<
1
)
return
weight
;
// get angular coordinates
t_vec2
vertex1_angle
=
this
->
PixelToAngle
(
vertex1
);
t_vec2
vertex2_angle
=
this
->
PixelToAngle
(
vertex2
);
t_vec2
nearest_vertex1_angle
=
this
->
PixelToAngle
(
nearest_vertices1
[
0
]);
t_vec2
nearest_vertex2_angle
=
this
->
PixelToAngle
(
nearest_vertices2
[
0
]);
// get minimum angular distances
t_real
dist1
=
GetPathLength
(
nearest_vertex1_angle
-
vertex1_angle
);
t_real
dist2
=
GetPathLength
(
nearest_vertex2_angle
-
vertex2_angle
);
// get the distances to the wall vertices that are closest to the current voronoi vertices
t_real
dist1
=
GetDistToNearestWall
(
vertex1
);
t_real
dist2
=
GetDistToNearestWall
(
vertex2
);
t_real
min_dist
=
std
::
min
(
dist1
,
dist2
);
// modify edge weights using the minimum distance to the next wall
...
...
@@ -1057,6 +1059,7 @@ InstrumentPath PathsBuilder::FindPath(
const
t_vec2
&
vert1
=
voro_vertices
[
idx1
];
const
t_vec2
&
vert2
=
voro_vertices
[
idx2
];
// if the voronoi vertices belong to a linear bisector,
// find the closest point by projecting 'vec' onto it
t_real
param_lin
=
-
1
;
...
...
@@ -1065,16 +1068,90 @@ InstrumentPath PathsBuilder::FindPath(
{
t_vec2
dir
=
vert2
-
vert1
;
t_real
dir_len
=
tl2
::
norm
<
t_vec2
>
(
dir
);
// the query point lies on the voronoi vertex
if
(
dir_len
<
m_eps_angular
)
return
std
::
make_tuple
(
0
,
0
,
true
);
dir
/=
dir_len
;
auto
[
ptProj
,
_dist_lin
,
paramProj
]
=
auto
[
_
ptProj
,
_dist_lin
,
paramProj
]
=
tl2
::
project_line
<
t_vec2
,
t_real
>
(
vec
,
vert1
,
dir
,
true
);
param_lin
=
paramProj
/
dir_len
;
dist_lin
=
_dist_lin
;
// look for another parameter if the projected vertex is too close to a wall
t_real
new_param_lin
=
param_lin
;
bool
new_param_found
=
false
;
const
t_real
delta_param
=
0.025
;
// initial distance to walls
//t_vec2 vertex_1 = vert1 + dir*new_param_lin*dir_len;
t_real
dist_to_walls_1
=
GetDistToNearestWall
(
/*vertex_1*/
_ptProj
);
// direction for parameter search
const
t_real
param_range
[
2
]
=
{
-
1.
,
1.
};
bool
increase_param
=
true
;
if
(
new_param_lin
<
param_range
[
0
])
increase_param
=
true
;
else
if
(
new_param_lin
>
param_range
[
1
])
increase_param
=
false
;
else
{
// find direction for parameter search which decreases the distance to the walls
t_vec2
vertex_2
=
vert1
+
dir
*
(
new_param_lin
+
delta_param
)
*
dir_len
;
t_real
dist_to_walls_2
=
GetDistToNearestWall
(
vertex_2
);
increase_param
=
(
dist_to_walls_2
>
dist_to_walls_1
);
}
while
(
dist_to_walls_1
<
m_min_angular_dist_to_walls
)
{
if
(
increase_param
)
new_param_lin
+=
delta_param
;
else
new_param_lin
-=
delta_param
;
// vertex is far enough from any wall?
t_vec2
new_vertex
=
vert1
+
dir
*
new_param_lin
*
dir_len
;
t_real
dist_to_walls
=
GetDistToNearestWall
(
new_vertex
);
// found a better position?
if
(
dist_to_walls
>
dist_to_walls_1
)
{
new_param_found
=
true
;
// out of critical distance?
if
(
dist_to_walls
>=
m_min_angular_dist_to_walls
)
break
;
}
// not yet in target range?
if
((
increase_param
&&
new_param_lin
<
param_range
[
0
])
||
(
!
increase_param
&&
new_param_lin
>
param_range
[
1
]))
continue
;
// end of parameter search?
if
(
new_param_lin
>
param_range
[
1
]
||
new_param_lin
<
param_range
[
0
])
break
;
}
// a new parameter farther from the walls has been found
if
(
new_param_found
)
{
new_param_lin
=
tl2
::
clamp
<
t_real
>
(
new_param_lin
,
param_range
[
0
],
param_range
[
1
]);
t_vec2
new_vertex
=
vert1
+
dir
*
new_param_lin
*
dir_len
;
param_lin
=
new_param_lin
;
dist_lin
=
tl2
::
norm
<
t_vec2
>
(
new_vertex
-
vec
);
}
}
// if the voronoi vertices belong to a quadratic bisector,
// find the closest vertex along its segment
t_real
param_quadr
=
-
1
;
...
...
@@ -1096,6 +1173,12 @@ InstrumentPath PathsBuilder::FindPath(
t_real
dist2
=
tl2
::
inner
<
t_vec2
>
(
path_vertex
-
vec
,
path_vertex
-
vec
);
if
(
dist2
<
min_dist2
)
{
t_real
dist_to_walls
=
GetDistToNearestWall
(
path_vertex
);
// reject vertex if the minimum distance to the walls is undercut
if
(
dist_to_walls
<
m_min_angular_dist_to_walls
)
continue
;
min_dist2
=
dist2
;
min_idx
=
vertidx
;
}
...
...
@@ -1108,6 +1191,7 @@ InstrumentPath PathsBuilder::FindPath(
param_quadr
=
1.
-
param_quadr
;
}
if
(
dist_lin
<
dist_quadr
)
return
std
::
make_tuple
(
param_lin
,
dist_lin
,
true
);
else
...
...
@@ -1115,6 +1199,7 @@ InstrumentPath PathsBuilder::FindPath(
};
// find the retractionn points from the start/end point towards the path mesh
if
(
path
.
voronoi_indices
.
size
()
>=
2
)
{
// find closest start point
...
...
@@ -1157,6 +1242,7 @@ InstrumentPath PathsBuilder::FindPath(
path
.
param_i
=
tl2
::
clamp
<
t_real
>
(
path
.
param_i
,
0.
,
1.
);
path
.
is_linear_i
=
is_linear_bisector_begin
;
// find closest end point
std
::
size_t
vert_idx1_end
=
*
(
path
.
voronoi_indices
.
rbegin
()
+
1
);
std
::
size_t
vert_idx2_end
=
*
path
.
voronoi_indices
.
rbegin
();
...
...
@@ -1196,12 +1282,35 @@ InstrumentPath PathsBuilder::FindPath(
path
.
is_linear_f
=
is_linear_bisector_end
;
}
return
path
;
}
/**
* get the angular distance of a vertex to the nearest wall
*/
t_real
PathsBuilder
::
GetDistToNearestWall
(
const
t_vec2
&
vertex
,
bool
deg
)
const
{
// get the wall vertices that are closest to the given vertex
if
(
auto
nearest_walls
=
m_wallsindextree
.
Query
(
vertex
,
1
);
nearest_walls
.
size
()
>=
1
)
{
// get angular distance to wall
t_vec2
angle
=
PixelToAngle
(
vertex
,
deg
,
false
);
t_vec2
nearest_wall_angle
=
PixelToAngle
(
nearest_walls
[
0
],
false
,
false
);
t_real
dist
=
GetPathLength
(
nearest_wall_angle
-
angle
);
return
dist
;
}
// no wall found
return
std
::
numeric_limits
<
t_real
>::
max
();
}
/**
* get individual vertices on an instrument path
* (in angular coordinates)
*/
std
::
vector
<
t_vec2
>
PathsBuilder
::
GetPathVertices
(
const
InstrumentPath
&
path
,
bool
subdivide_lines
,
bool
deg
)
const
...
...
@@ -1449,7 +1558,8 @@ std::vector<t_vec2> PathsBuilder::GetPathVertices(
}
}
if
(
minimum_found
&&
!
DoesDirectPathCollide
(
path_vertices
[
start_idx
],
path_vertices
[
min_idx
],
deg
))
if
(
minimum_found
&&
!
DoesDirectPathCollide
(
path_vertices
[
start_idx
],
path_vertices
[
min_idx
],
deg
))
{
// a shortcut was found
path_vertices
.
erase
(
path_vertices
.
begin
()
+
min_idx
+
1
,
path_vertices
.
begin
()
+
start_idx
);
...
...
@@ -1499,17 +1609,11 @@ bool PathsBuilder::DoesDirectPathCollide(const t_vec2& vert1, const t_vec2& vert
// look for the closest wall
t_vec2
pix
=
tl2
::
create
<
t_vec2
>
({
t_real
(
x
),
t_real
(
y
)});
if
(
auto
nearest_walls
=
m_wallsindextree
.
Query
(
pix
,
1
);
nearest_walls
.
size
()
>=
1
)
{
// get angular distance to wall
t_vec2
angle
=
PixelToAngle
(
pix
,
false
,
false
);
t_vec2
nearest_wall_angle
=
PixelToAngle
(
nearest_walls
[
0
],
false
,
false
);
t_real
dist
=
GetPathLength
(
nearest_wall_angle
-
angle
);
// reject path if the minimum distance to the walls is undercut
if
(
dist
<
m_min_angular_dist_to_walls
)
return
true
;
}
t_real
dist_to_walls
=
GetDistToNearestWall
(
pix
);
// reject path if the minimum distance to the walls is undercut
if
(
dist_to_walls
<
m_min_angular_dist_to_walls
)
return
true
;
last_x
=
x
;
last_y
=
y
;
...
...
src/core/PathsBuilder.h
View file @
2f284b53
...
...
@@ -49,7 +49,7 @@ struct InstrumentPath
// path mesh ok?
bool
ok
=
false
;
// initial and final vertices on path
// initial and final vertices on path
(in pixel coordinates)
t_vec2
vec_i
;
t_vec2
vec_f
;
...
...
@@ -122,6 +122,9 @@ protected:
// 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
;
// get the angular distance of a vertex to the nearest wall
t_real
GetDistToNearestWall
(
const
t_vec2
&
vertex
,
bool
deg
=
false
)
const
;
public:
PathsBuilder
();
...
...
@@ -292,7 +295,7 @@ private:
t_real
m_monoScatteringRange
[
2
]{
0
,
tl2
::
pi
<
t_real
>
};
t_real
m_sampleScatteringRange
[
2
]{
0
,
tl2
::
pi
<
t_real
>
};
// index tree for wall positions
// index tree for wall positions
(in pixel coordinates)
geo
::
ClosestPixelTreeResults
<
t_contourvec
>
m_wallsindextree
{};
// wall contours in configuration space
...
...
src/libs/voronoi_lines.h
View file @
2f284b53
...
...
@@ -6,7 +6,7 @@
* @license GPLv3, see 'LICENSE' file
*
* References for the algorithms:
* - (Klein 2005) R. Klein, "Algorithmische Geometrie" (2005),
* - (Klein 2005) R. Klein, "Algorithmische Geometrie" (2005),
* ISBN: 978-3540209560 (http://dx.doi.org/10.1007/3-540-27619-X).
* - (FUH 2020) R. Klein, C. Icking, "Algorithmische Geometrie" (2020),
* Kurs 1840, Fernuni Hagen (https://vu.fernuni-hagen.de/lvuweb/lvu/app/Kurs/1840).
...
...
@@ -262,6 +262,19 @@ public:
}
/**
* call the external validation function on the vertex
* TODO: move this into its own option struct (and out of VoronoiLinesRegions)
*/
bool
ValidateVertex
(
const
t_vec
&
vert
)
const
{
if
(
!
validate_func
)
return
true
;
return
(
*
validate_func
)(
vert
);
}
// ------------------------------------------------------------------------
// getters & setters
// ------------------------------------------------------------------------
...
...
@@ -277,6 +290,9 @@ public:
void
SetPointsOutsideRegions
(
const
std
::
vector
<
t_vec
>*
p
)
{
points_outside_regions
=
p
;
}
void
SetInvertedRegions
(
const
std
::
vector
<
bool
>*
r
)
{
inverted_regions
=
r
;
}
void
SetRegionFunc
(
const
std
::
function
<
bool
(
const
t_vec
&
vert
)
>*
f
)
{
region_func
=
f
;
}
// TODO: move this into its own option struct (and out of VoronoiLinesRegions)
void
SetValidateFunc
(
const
std
::
function
<
bool
(
const
t_vec
&
vert
)
>*
f
)
{
validate_func
=
f
;
}
// ------------------------------------------------------------------------
...
...
@@ -293,6 +309,10 @@ private:
// alternate callback function for defining regions
const
std
::
function
<
bool
(
const
t_vec
&
vert
)
>*
region_func
=
nullptr
;
// external vertex validation function
// TODO: move this into its own option struct (and out of VoronoiLinesRegions)
const
std
::
function
<
bool
(
const
t_vec
&
vert
)
>*
validate_func
=
nullptr
;
};
...
...
@@ -822,35 +842,51 @@ requires tl2::is_vec<t_vec> && is_graph<t_graph>
const
auto
*
vert1
=
edge
.
vertex1
();
auto
vert0idx
=
get_vertex_idx
(
vert0
);
auto
vert1idx
=
get_vertex_idx
(
vert1
);
bool
valid_vertices
=
vert0idx
&&
vert1idx
;
// line groups defined?
if
(
regions
&&
regions
->
GetLineGroups
()
->
size
()
)
if
(
regions
)
{
// get index of the segment
auto
seg1idx
=
get_segment_idx
(
edge
,
false
);
auto
seg2idx
=
get_segment_idx
(
edge
,
true
);
bool
vert_1_invalid
=
false
;
bool
vert_2_invalid
=
false
;
if
(
seg1idx
&&
seg2idx
)
// remove vertices that don't satisfy the external validation function
if
(
vert0idx
&&
!
regions
->
ValidateVertex
(
vertices
[
*
vert0idx
]))
vert_1_invalid
=
true
;
if
(
vert1idx
&&
!
regions
->
ValidateVertex
(
vertices
[
*
vert1idx
]))
vert_2_invalid
=
true
;
if
(
vert_1_invalid
&&
vert_2_invalid
)
continue
;
// remove vertices inside regions
if
(
regions
->
GetLineGroups
()
->
size
())
{
// get
the group
index of the segment
s
auto
r
eg
ion1
=
get_
group_idx
(
*
seg1idx
);
auto
r
eg
ion2
=
get_
group_idx
(
*
seg2idx
);
// get index of the segment
auto
s
eg
1idx
=
get_
segment_idx
(
edge
,
false
);
auto
s
eg
2idx
=
get_
segment_idx
(
edge
,
true
);
if
(
r
eg
ions
->
GetGroupLines
()
)
if
(
s
eg
1idx
&&
seg2idx
)
{
// are the generating line segments part of the same group?
// if so, ignore this voronoi edge and skip to next one
if
(
region1
&&
region2
&&
*
region1
==
*
region2
)
continue
;
// get the group index of the segments
auto
region1
=
get_group_idx
(
*
seg1idx
);
auto
region2
=
get_group_idx
(
*
seg2idx
);
if
(
regions
->
GetGroupLines
())
{
// are the generating line segments part of the same group?
// if so, ignore this voronoi edge and skip to next one
if
(
region1
&&
region2
&&
*
region1
==
*
region2
)
continue
;
}
}
}
if
(
regions
->
IsVertexInRegion
(
lines
,
vertices
,
vert0idx
,
vert1idx
,
eps
))
continue
;
if
(
regions
->
IsVertexInRegion
(
lines
,
vertices
,
vert0idx
,
vert1idx
,
eps
))
continue
;
}
}
bool
valid_vertices
=
vert0idx
&&
vert1idx
;
if
(
valid_vertices
)
{
// add edge to graph
...
...
@@ -1268,7 +1304,7 @@ template<class t_vec,
class
t_graph
=
AdjacencyMatrix
<
typename
t_vec
::
value_type
>
,
class
t_int
=
int
>
VoronoiLinesResults
<
t_vec
,
t_line
,
t_graph
>
calc_voro_cgal
(
const
std
::
vector
<
t_line
>&
lines
,
calc_voro_cgal
(
const
std
::
vector
<
t_line
>&
lines
,
typename
t_vec
::
value_type
eps
=
std
::
sqrt
(
std
::
numeric_limits
<
typename
t_vec
::
value_type
>::
epsilon
()),
typename
t_vec
::
value_type
para_edge_eps
=
1e-2
,
const
VoronoiLinesRegions
<
t_vec
,
t_line
>*
regions
=
nullptr
)
...
...
@@ -1440,11 +1476,27 @@ requires tl2::is_vec<t_vec> && is_graph<t_graph>
bool
valid_vertices
=
vert0idx
&&
vert1idx
;
// line groups defined?
if
(
regions
&&
regions
->
GetLineGroups
()
->
size
()
)
if
(
regions
)
{
if
(
regions
->
IsVertexInRegion
(
lines
,
vertices
,
vert0idx
,
vert1idx
,
eps
))
bool
vert_1_invalid
=
false
;
bool
vert_2_invalid
=
false
;
// remove vertices that don't satisfy the external validation function
if
(
vert0idx
&&
!
regions
->
ValidateVertex
(
vertices
[
*
vert0idx
]))
vert_1_invalid
=
true
;
if
(
vert1idx
&&
!
regions
->
ValidateVertex
(
vertices
[
*
vert1idx
]))
vert_2_invalid
=
true
;
if
(
vert_1_invalid
&&
vert_2_invalid
)
continue
;
// remove vertices inside regions
if
(
regions
->
GetLineGroups
()
->
size
())
{
if
(
regions
->
IsVertexInRegion
(
lines
,
vertices
,
vert0idx
,
vert1idx
,
eps
))
continue
;
}
}
if
(
valid_vertices
)
...
...
@@ -1498,11 +1550,27 @@ requires tl2::is_vec<t_vec> && is_graph<t_graph>
bool
valid_vertices
=
vert0idx
&&
vert1idx
;
// line groups defined?
if
(
regions
&&
regions
->
GetLineGroups
()
->
size
()
)
if
(
regions
)
{
if
(
regions
->
IsVertexInRegion
(
lines
,
vertices
,
vert0idx
,
vert1idx
,
eps
))
bool
vert_1_invalid
=
false
;
bool
vert_2_invalid
=
false
;
// remove vertices that don't satisfy the external validation function
if
(
vert0idx
&&
!
regions
->
ValidateVertex
(
vertices
[
*
vert0idx
]))
vert_1_invalid
=
true
;
if
(
vert1idx
&&
!
regions
->
ValidateVertex
(
vertices
[
*
vert1idx
]))
vert_2_invalid
=
true
;
if
(
vert_1_invalid
&&
vert_2_invalid
)
continue
;
// remove vertices inside regions
if
(
regions
->
GetLineGroups
()
->
size
())
{
if
(
regions
->
IsVertexInRegion
(
lines
,
vertices
,
vert0idx
,
vert1idx
,
eps
))
continue
;
}
}
// add graph edges
...
...
@@ -1543,11 +1611,27 @@ requires tl2::is_vec<t_vec> && is_graph<t_graph>
bool
valid_vertices
=
vert0idx
&&
vert1idx
;
// line groups defined?
if
(
regions
&&
regions
->
GetLineGroups
()
->
size
()
)
if
(
regions
)
{
if
(
regions
->
IsVertexInRegion
(
lines
,
vertices
,
vert0idx
,
vert1idx
,
eps
))
bool
vert_1_invalid
=
false
;
bool
vert_2_invalid
=
false
;
// remove vertices that don't satisfy the external validation function
if
(
vert0idx
&&
!
regions
->
ValidateVertex
(
vertices
[
*
vert0idx
]))
vert_1_invalid
=
true
;
if
(
vert1idx
&&
!
regions
->
ValidateVertex
(
vertices
[
*
vert1idx
]))
vert_2_invalid
=
true
;
if
(
vert_1_invalid
&&
vert_2_invalid
)
continue
;
// remove vertices inside regions
if
(
regions
->
GetLineGroups
()
->
size
())
{
if
(
regions
->
IsVertexInRegion
(
lines
,
vertices
,
vert0idx
,
vert1idx
,
eps
))
continue
;
}
}
// add graph edges
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment