-
Notifications
You must be signed in to change notification settings - Fork 49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP: Add Axis-Aligned Bounding Box option to Plane-Slicer Planner #123
base: master
Are you sure you want to change the base?
Changes from 8 commits
812f52e
4e32857
4e5c022
a52ac5a
12181b3
40551b3
54dffd5
7dd640d
0a88246
8693919
08c6a00
3ac6cf9
308194e
f804f23
4ffd272
14746af
acf9da4
37ccd05
80d33a4
7b03eae
5d0911f
c698b1c
4999eae
d76613e
9f8c123
327acf9
f58ccca
2b1527f
bf3547d
6bee60f
4ccb86a
725267d
d423984
d8ab78e
e3bc666
694c15a
510511a
2b26ffa
793fdb4
2320237
2861348
f28beac
a3bea86
734f27c
f805353
9ef7316
7b64064
d845ba5
e9671a0
3688fa4
78b6fc2
01bec84
ef6fa61
49837e1
8cc8584
b79f539
6419c78
ef05d02
b53758d
8ea64ab
07e3f7f
caad679
d6a59f1
189eef2
224d6fb
4f0a139
fdbf72e
74246a1
e41a18e
5899b4d
41a65ae
e751fc6
958d584
f033397
6713141
0135230
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,18 @@ | ||
float64 raster_spacing # Offset between two rasters | ||
float64 point_spacing # Required spacing between path points | ||
float64 raster_rot_offset # Specifies the direction of the raster path in radians | ||
float64 min_segment_size # The minimum segment size to allow when finding intersections; small segments will be discarded | ||
float64 min_hole_size # A path may pass over holes smaller than this, but must be broken when larger holes are encounterd. | ||
float64 tool_offset # How far off the surface the tool needs to be | ||
float64 raster_spacing # Offset between two rasters | ||
float64 point_spacing # Required spacing between path points | ||
float64 raster_rot_offset # Specifies the direction of the raster path in radians. Rotates about short dimension of bounding box. | ||
float64 min_segment_size # The minimum segment size to allow when finding intersections; small segments will be discarded | ||
float64 min_hole_size # A path may pass over holes smaller than this, but must be broken when larger holes are encounterd. | ||
float64 tool_offset # How far off the surface the tool needs to be | ||
bool generate_extra_rasters # Whether an extra raster stroke should be added to the beginning and end of the raster pattern | ||
|
||
# When set to TRUE: initial cuts are determined using an axis-aligned bounding box. (global axes) | ||
# When set to FALSE: initial cuts are determined using an object-oriented bounding box and the | ||
# principal axes of the part. (Note that ROS sets message fields to 0/False by default.) | ||
bool raster_wrt_global_axes | ||
|
||
# Normal of the cutting planes. Points from the first raster to the second raster, not the | ||
# direction from the first point in one raster to the second point of the same raster. X is the | ||
# longest direction of the bounding box, Z is the shortest, Y is middle, following right hand rule. | ||
# If left as 0 (magnitude < 0.000001), defaults to [0,1,0], the mid direction of the bounding box. | ||
geometry_msgs/Vector3 raster_direction |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -66,6 +66,9 @@ class HalfedgeEdgeGenerator : public PathGenerator | |
|
||
/**@brief point distance parameter used in conjunction with the spacing method */ | ||
double point_dist = 0.01; | ||
|
||
/** @brief maximum segment length */ | ||
double max_segment_length = 1.0; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this parameter used for in the Plane Slicer? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is in the halfedge edge generator header, which is used for generating edge paths. I assume based on the description that it is the max allows edge segment size. @drchrislewis Is this correct? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this controls the maximum length of an edge segment. There are alternate parameters and methods for subdividing edges that may result in better performance, but each had corner cases that were more complex, so I went with the simplest method to get us going. For example, since exterior edges always start and end at the same point, we could simply sub-divide by some number whenever there was a circuit. It would be really nice to find the best places to subdivide rather than do it evenly. Again these are complex. One could also classify edges and horizontal-left, hor-rt, ver-up and vert-down. and break them up into 4. Once again this is complex to implement, but may be necessary for some applications/customers. |
||
}; | ||
|
||
HalfedgeEdgeGenerator() = default; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,6 +26,7 @@ | |
#include <vtkSmartPointer.h> | ||
#include <vtkPolyData.h> | ||
#include <boost/optional.hpp> | ||
#include <Eigen/Dense> | ||
#include <pcl/PolygonMesh.h> | ||
#include <shape_msgs/Mesh.h> | ||
#include <vtkCellLocator.h> | ||
|
@@ -45,6 +46,8 @@ class PlaneSlicerRasterGenerator : public PathGenerator | |
static constexpr double DEFAULT_MIN_SEGMENT_SIZE = 0.01; | ||
static constexpr double DEFAULT_SEARCH_RADIUS = 0.01; | ||
static constexpr double DEFAULT_MIN_HOLE_SIZE = 1e-2; | ||
static constexpr bool DEFAULT_RASTER_WRT_GLOBAL_AXES = false; | ||
static constexpr bool DEFAULT_GENERATE_EXTRA_RASTERS = true; | ||
|
||
public: | ||
struct Config | ||
|
@@ -55,7 +58,9 @@ class PlaneSlicerRasterGenerator : public PathGenerator | |
double min_segment_size{ DEFAULT_MIN_SEGMENT_SIZE }; | ||
double search_radius{ DEFAULT_SEARCH_RADIUS }; | ||
double min_hole_size{ DEFAULT_MIN_HOLE_SIZE }; | ||
|
||
bool raster_wrt_global_axes{ DEFAULT_RASTER_WRT_GLOBAL_AXES }; | ||
Eigen::Vector3d raster_direction{ Eigen::Vector3d::UnitY() }; | ||
bool generate_extra_rasters{ DEFAULT_GENERATE_EXTRA_RASTERS }; | ||
Json::Value toJson() const | ||
{ | ||
Json::Value jv(Json::ValueType::objectValue); | ||
|
@@ -65,6 +70,12 @@ class PlaneSlicerRasterGenerator : public PathGenerator | |
jv["min_segment_size"] = min_segment_size; | ||
jv["search_radius"] = search_radius; | ||
jv["min_hole_size"] = min_hole_size; | ||
jv["raster_wrt_global_axes"] = raster_wrt_global_axes; | ||
Json::Value raster_dir(Json::ValueType::objectValue); | ||
raster_dir["x"] = raster_direction.x(); | ||
raster_dir["y"] = raster_direction.y(); | ||
raster_dir["z"] = raster_direction.z(); | ||
jv["raster_direction"] = raster_dir; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this will work, yaml might've been a better choice as it can directly casts to std vectors and maps |
||
|
||
return jv; | ||
} | ||
|
@@ -100,6 +111,26 @@ class PlaneSlicerRasterGenerator : public PathGenerator | |
DEFAULT_SEARCH_RADIUS; | ||
min_hole_size = validate(jv, "min_hole_size", Json::ValueType::realValue) ? jv["min_hole_size"].asDouble() : | ||
DEFAULT_MIN_HOLE_SIZE; | ||
raster_wrt_global_axes = validate(jv, "raster_wrt_global_axes", Json::ValueType::booleanValue) ? | ||
jv["raster_wrt_global_axes"].asBool() : | ||
DEFAULT_RASTER_WRT_GLOBAL_AXES; | ||
if (jv["raster_direction"].isNull() || jv["raster_direction"].type() != Json::ValueType::objectValue) | ||
{ | ||
ROS_ERROR("Malformed Raster Direction in Json value"); | ||
return false; | ||
} | ||
if (validate(jv["raster_direction"], "x", Json::ValueType::objectValue) && | ||
validate(jv["raster_direction"], "y", Json::ValueType::objectValue) && | ||
validate(jv["raster_direction"], "z", Json::ValueType::objectValue)) | ||
{ | ||
raster_direction.x() = jv["raster_direction"]["x"].asDouble(); | ||
raster_direction.y() = jv["raster_direction"]["y"].asDouble(); | ||
raster_direction.z() = jv["raster_direction"]["z"].asDouble(); | ||
} | ||
else | ||
{ | ||
raster_direction = Eigen::Vector3d::UnitY(); | ||
} | ||
return true; | ||
} | ||
|
||
|
@@ -121,6 +152,11 @@ class PlaneSlicerRasterGenerator : public PathGenerator | |
ss << "raster_rot_offset: " << raster_rot_offset << std::endl; | ||
ss << "min_segment_size: " << min_segment_size << std::endl; | ||
ss << "search_radius: " << search_radius << std::endl; | ||
ss << "raster_wrt_global_axes: " << raster_wrt_global_axes << std::endl; | ||
ss << "raster_direction: " << std::endl; | ||
ss << " x: " << raster_direction.x() << std::endl; | ||
ss << " y: " << raster_direction.y() << std::endl; | ||
ss << " z: " << raster_direction.z() << std::endl; | ||
return ss.str(); | ||
} | ||
}; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -409,7 +409,6 @@ void PlaneSlicerRasterGenerator::setInput(vtkSmartPointer<vtkPolyData> mesh) | |
} | ||
else | ||
{ | ||
CONSOLE_BRIDGE_logWarn("%s generating normal data", getName().c_str()); | ||
vtkSmartPointer<vtkPolyDataNormals> normal_generator = vtkSmartPointer<vtkPolyDataNormals>::New(); | ||
normal_generator->SetInputData(mesh_data_); | ||
normal_generator->ComputePointNormalsOn(); | ||
|
@@ -453,10 +452,43 @@ boost::optional<ToolPaths> PlaneSlicerRasterGenerator::generate() | |
{ | ||
CONSOLE_BRIDGE_logDebug("%s No mesh data has been provided", getName().c_str()); | ||
} | ||
// computing mayor axis using oob | ||
vtkSmartPointer<vtkOBBTree> oob = vtkSmartPointer<vtkOBBTree>::New(); | ||
Vector3d corner, x_dir, y_dir, z_dir, sizes; // x is longest, y is mid and z is smallest | ||
oob->ComputeOBB(mesh_data_, corner.data(), x_dir.data(), y_dir.data(), z_dir.data(), sizes.data()); | ||
// Assign the longest axis of the bounding box to x, middle to y, and shortest to z. | ||
Vector3d corner, x_dir, y_dir, z_dir, sizes; | ||
if (config_.raster_wrt_global_axes) | ||
{ | ||
// Determine extent of mesh along axes of current coordinate frame | ||
VectorXd bounds(6); | ||
std::vector<Vector3d> extents; | ||
mesh_data_->GetBounds(bounds.data()); | ||
extents.push_back(Vector3d::UnitX() * (bounds[1] - bounds[0])); // Extent in x-direction of supplied mesh | ||
// coordinate frame | ||
extents.push_back(Vector3d::UnitY() * (bounds[3] - bounds[2])); // Extent in y-direction of supplied mesh | ||
// coordinate frame | ||
extents.push_back(Vector3d::UnitZ() * (bounds[5] - bounds[4])); // Extent in z-direction of supplied mesh | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It might be good to call cwise.abs() to ensure that the values of extends only have positive values even though theoretically it should always be positive |
||
// coordinate frame | ||
|
||
// find min and max magnitude. | ||
int max = 0; | ||
int min = 0; | ||
for (std::size_t i = 1; i < extents.size(); ++i) | ||
{ | ||
if (extents[max].squaredNorm() < extents[i].squaredNorm()) | ||
max = i; | ||
else if (extents[min].squaredNorm() > extents[i].squaredNorm()) | ||
min = i; | ||
} | ||
|
||
// Assign the axes in order. Computing y saves comparisons and guarantees right-handedness. | ||
x_dir = extents[max].normalized(); | ||
z_dir = extents[min].normalized(); | ||
y_dir = z_dir.cross(x_dir).normalized(); | ||
} | ||
else | ||
{ | ||
// computing major axes using oob and assign to x_dir, y_dir, z_dir | ||
vtkSmartPointer<vtkOBBTree> oob = vtkSmartPointer<vtkOBBTree>::New(); | ||
oob->ComputeOBB(mesh_data_, corner.data(), x_dir.data(), y_dir.data(), z_dir.data(), sizes.data()); | ||
} | ||
|
||
// Compute the center of mass | ||
Vector3d origin; | ||
|
@@ -492,10 +524,11 @@ boost::optional<ToolPaths> PlaneSlicerRasterGenerator::generate() | |
half_ext = sizes / 2.0; | ||
center = Eigen::Vector3d(bounds[0], bounds[2], bounds[3]) + half_ext; | ||
|
||
// now cutting the mesh with planes along the y axis | ||
// @todo This should be calculated instead of being fixed along the y-axis | ||
// Apply the rotation offset about the short direction (new Z axis) of the bounding box | ||
Isometry3d rotation_offset = Isometry3d::Identity() * AngleAxisd(config_.raster_rot_offset, Vector3d::UnitZ()); | ||
Vector3d raster_dir = (rotation_offset * Vector3d::UnitY()).normalized(); | ||
|
||
// Calculate direction of raster strokes, rotated by the above-specified amount | ||
Vector3d raster_dir = (rotation_offset * config_.raster_direction).normalized(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure what kind of results you would get if your raster_direction vector has more than one non-zero component or if it is (0, 0, 1)? Perhaps we should impose some restrictions on what values the raster_dir vector can take |
||
|
||
// Calculate all 8 corners projected onto the raster direction vector | ||
Eigen::VectorXd dist(8); | ||
|
@@ -681,7 +714,15 @@ boost::optional<ToolPaths> PlaneSlicerRasterGenerator::generate() | |
} | ||
|
||
// converting to poses msg now | ||
rasters = convertToPoses(rasters_data_vec); | ||
if (config_.generate_extra_rasters) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO: make extra_rasters an unsigned integer, defaulted to zero, when non-zero, generate as many as requested |
||
{ | ||
ToolPaths temp_rasters = convertToPoses(rasters_data_vec); | ||
rasters = addExtraPaths(temp_rasters, config_.raster_spacing); | ||
} | ||
else | ||
{ | ||
rasters = convertToPoses(rasters_data_vec); | ||
} | ||
return rasters; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -496,7 +496,11 @@ int findClosestPoint(const std::vector<double>& pt, const std::vector<std::vecto | |
return index; | ||
} | ||
|
||
bool SurfaceWalkRasterGenerator::setConfiguration(const Config& config) { config_ = config; } | ||
bool SurfaceWalkRasterGenerator::setConfiguration(const Config& config) | ||
{ | ||
config_ = config; | ||
return true; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. newer compiler seems to flag these as errors |
||
} | ||
|
||
void SurfaceWalkRasterGenerator::setInput(pcl::PolygonMesh::ConstPtr mesh) | ||
{ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This perhaps could be made to be num_of_extra_rasters so that more than one could be added if needed. Zero would be the default case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good idea. thanks