in code/cpp/tools/scene_annotation_tool/main.cpp [2149:2519]
bool mouse_up(igl::opengl::glfw::Viewer& viewer, int button, int modifier) {
if (g_mouse_drawing_create) {
if (g_segmentation_layer == SEGMENTATION_LAYER_SEMANTIC_INSTANCE) {
g_semantic_instance_id = create_new_semantic_instance_segmentation_id();
g_updated_semantic_instance_id = true;
}
}
if (g_mouse_drawing) {
if (g_mouse_drawing_positions.size() == 0) {
g_mouse_rotation = false;
g_mouse_translation = false;
g_mouse_drawing = false;
g_mouse_drawing_create = false;
return true;
}
//
// raycasting setup
//
int width_window, height_window;
glfwGetFramebufferSize(viewer.window, &width_window, &height_window);
arma::vec camera_look_from_position = { viewer.core().camera_eye(0), viewer.core().camera_eye(1), viewer.core().camera_eye(2) };
arma::vec camera_look_at_position = { viewer.core().camera_center(0), viewer.core().camera_center(1), viewer.core().camera_center(2) };
arma::vec camera_look_at_dir = arma::normalise(camera_look_at_position - camera_look_from_position);
arma::vec camera_up_hint = { 0, 0, 1 };
// The convention here is that the camera's positive x axis points right, the positive y
// axis points up, and the positive z axis points away from where the camera is looking.
arma::vec camera_z_axis = -arma::normalise(camera_look_at_dir);
arma::vec camera_x_axis = -arma::normalise(arma::cross(camera_z_axis, camera_up_hint));
arma::vec camera_y_axis = arma::normalise(arma::cross(camera_z_axis, camera_x_axis));
arma::mat R_world_from_cam = arma::ones<arma::mat>(3,3) * std::numeric_limits<float>::infinity();
R_world_from_cam.col(0) = camera_x_axis;
R_world_from_cam.col(1) = camera_y_axis;
R_world_from_cam.col(2) = camera_z_axis;
auto fov_y = viewer.core().camera_view_angle * (igl::PI/180.0);
auto fov_x = 2.0 * std::atan(width_window * std::tan(fov_y/2.0) / height_window);
auto uv_min = -1.0;
auto uv_max = 1.0;
auto half_du = 0.5 * (uv_max - uv_min) / width_window;
auto half_dv = 0.5 * (uv_max - uv_min) / height_window;
arma::vec u = arma::linspace(uv_min+half_du, uv_max-half_du, width_window);
arma::vec v = arma::reverse(arma::linspace(uv_min+half_dv, uv_max-half_dv, height_window));
//
// eyedropper is a special case because it doesn't actually do any drawing
//
if (g_tool == TOOL_EYEDROPPER) {
arma::ivec p = g_mouse_drawing_positions.back();
auto s_x = p(0);
auto s_y = p(1);
auto u_ = u(s_x);
auto v_ = v(s_y);
arma::vec ray_cam = { u_*std::tan(fov_x/2.0), v_*std::tan(fov_y/2.0), -1.0 };
arma::vec ray_world = arma::normalise(R_world_from_cam*ray_cam);
// initialize ray
arma::vec ray_position = camera_look_from_position;
arma::vec ray_direction_normalized = ray_world;
RTCRayHit rtc_ray_hit;
rtc_ray_hit.ray.org_x = (float)ray_position(0);
rtc_ray_hit.ray.org_y = (float)ray_position(1);
rtc_ray_hit.ray.org_z = (float)ray_position(2);
rtc_ray_hit.ray.dir_x = (float)ray_direction_normalized(0);
rtc_ray_hit.ray.dir_y = (float)ray_direction_normalized(1);
rtc_ray_hit.ray.dir_z = (float)ray_direction_normalized(2);
rtc_ray_hit.ray.tnear = 0.0f;
rtc_ray_hit.ray.tfar = std::numeric_limits<float>::infinity();
rtc_ray_hit.ray.time = 0.0f;
rtc_ray_hit.ray.mask = 0;
rtc_ray_hit.ray.id = 0;
rtc_ray_hit.ray.flags = 0;
rtc_ray_hit.hit.Ng_x = std::numeric_limits<float>::infinity();
rtc_ray_hit.hit.Ng_y = std::numeric_limits<float>::infinity();
rtc_ray_hit.hit.Ng_z = std::numeric_limits<float>::infinity();
rtc_ray_hit.hit.u = std::numeric_limits<float>::infinity();
rtc_ray_hit.hit.v = std::numeric_limits<float>::infinity();
rtc_ray_hit.hit.primID = RTC_INVALID_GEOMETRY_ID;
rtc_ray_hit.hit.geomID = RTC_INVALID_GEOMETRY_ID;
rtc_ray_hit.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
// intersect ray with scene
rtcIntersect1(g_rtc_scene, &g_rtc_intersect_context, &rtc_ray_hit);
if (rtc_ray_hit.ray.tfar < std::numeric_limits<float>::infinity()) {
assert(rtc_ray_hit.hit.primID != RTC_INVALID_GEOMETRY_ID);
assert(rtc_ray_hit.hit.geomID != RTC_INVALID_GEOMETRY_ID);
} else {
assert(rtc_ray_hit.hit.primID == RTC_INVALID_GEOMETRY_ID);
assert(rtc_ray_hit.hit.geomID == RTC_INVALID_GEOMETRY_ID);
}
if (rtc_ray_hit.hit.geomID != RTC_INVALID_GEOMETRY_ID) {
auto face_id = rtc_ray_hit.hit.primID;
if (g_segmentation_layer == SEGMENTATION_LAYER_SEMANTIC_INSTANCE) {
if (g_segmentation_state_curr.mesh_objects_sii(g_faces_oi_curr(face_id)) != -1) {
g_semantic_instance_id = g_segmentation_state_curr.mesh_objects_sii(g_faces_oi_curr(face_id));
g_updated_semantic_instance_id = true;
}
}
if (g_segmentation_layer == SEGMENTATION_LAYER_SEMANTIC) {
if (g_segmentation_state_curr.mesh_objects_si(g_faces_oi_curr(face_id)) != -1) {
g_semantic_id = g_segmentation_state_curr.mesh_objects_si(g_faces_oi_curr(face_id));
}
}
}
}
//
// for the pen and line tools, approximately rasterize lines by oversampling, rather than implementing an exact rasterization algorithm like DDA
//
std::set<std::pair<int,int>> covered_pixels;
if (g_tool == TOOL_PEN) {
if (g_mouse_drawing_positions.size() == 1) {
arma::ivec p = g_mouse_drawing_positions.at(0);
covered_pixels.insert({p(0), p(1)});
} else {
auto k = 4; // number of samples per unit of screen space distance
for (int i = 0; i < g_mouse_drawing_positions.size() - 1; i++) {
arma::ivec p0 = g_mouse_drawing_positions.at(i);
arma::ivec p1 = g_mouse_drawing_positions.at(i+1);
arma::vec p0_ = arma::conv_to<arma::vec>::from(p0);
arma::vec p1_ = arma::conv_to<arma::vec>::from(p1);
auto num_samples = (int)(k*arma::norm(p1_ - p0_) + 1);
arma::vec x_vals = arma::linspace(p0_(0), p1_(0), num_samples);
arma::vec y_vals = arma::linspace(p0_(1), p1_(1), num_samples);
for (int j = 0; j < num_samples; j++) {
arma::ivec p = {(int)x_vals(j), (int)y_vals(j)};
covered_pixels.insert({p(0), p(1)});
}
}
}
}
if (g_tool == TOOL_LINE) {
if (g_mouse_drawing_positions.size() == 1) {
arma::ivec p = g_mouse_drawing_positions.at(0);
covered_pixels.insert({p(0), p(1)});
} else {
auto k = 4; // number of samples per unit of screen space distance
arma::ivec p0 = g_mouse_drawing_positions.front();
arma::ivec p1 = g_mouse_drawing_positions.back();
arma::vec p0_ = arma::conv_to<arma::vec>::from(p0);
arma::vec p1_ = arma::conv_to<arma::vec>::from(p1);
auto num_samples = (int)(k*arma::norm(p1_ - p0_) + 1);
arma::vec x_vals = arma::linspace(p0_(0), p1_(0), num_samples);
arma::vec y_vals = arma::linspace(p0_(1), p1_(1), num_samples);
for (int j = 0; j < num_samples; j++) {
arma::ivec p = {(int)x_vals(j), (int)y_vals(j)};
covered_pixels.insert({p(0), p(1)});
}
}
}
if (g_tool == TOOL_RECTANGLE) {
if (g_mouse_drawing_positions.size() == 1) {
arma::ivec p = g_mouse_drawing_positions.at(0);
covered_pixels.insert({p(0), p(1)});
} else {
arma::ivec p0 = g_mouse_drawing_positions.front();
arma::ivec p1 = g_mouse_drawing_positions.back();
auto x_min = std::min(p0(0), p1(0));
auto y_min = std::min(p0(1), p1(1));
auto x_max = std::max(p0(0), p1(0));
auto y_max = std::max(p0(1), p1(1));
for (int y = y_min; y <= y_max; y++) {
for (int x = x_min; x <= x_max; x++) {
covered_pixels.insert({x, y});
}
}
}
}
g_mouse_drawing_positions.clear();
if (g_tool == TOOL_PEN || g_tool == TOOL_LINE || g_tool == TOOL_RECTANGLE) {
//
// perform raycasting for each covered pixel
//
std::set<int> covered_face_ids;
for (auto p : covered_pixels) {
auto s_x = p.first;
auto s_y = p.second;
auto u_ = u(s_x);
auto v_ = v(s_y);
arma::vec ray_cam = { u_*std::tan(fov_x/2.0), v_*std::tan(fov_y/2.0), -1.0 };
arma::vec ray_world = arma::normalise(R_world_from_cam*ray_cam);
// initialize ray
arma::vec ray_position = camera_look_from_position;
arma::vec ray_direction_normalized = ray_world;
RTCRayHit rtc_ray_hit;
rtc_ray_hit.ray.org_x = (float)ray_position(0);
rtc_ray_hit.ray.org_y = (float)ray_position(1);
rtc_ray_hit.ray.org_z = (float)ray_position(2);
rtc_ray_hit.ray.dir_x = (float)ray_direction_normalized(0);
rtc_ray_hit.ray.dir_y = (float)ray_direction_normalized(1);
rtc_ray_hit.ray.dir_z = (float)ray_direction_normalized(2);
rtc_ray_hit.ray.tnear = 0.0f;
rtc_ray_hit.ray.tfar = std::numeric_limits<float>::infinity();
rtc_ray_hit.ray.time = 0.0f;
rtc_ray_hit.ray.mask = 0;
rtc_ray_hit.ray.id = 0;
rtc_ray_hit.ray.flags = 0;
rtc_ray_hit.hit.Ng_x = std::numeric_limits<float>::infinity();
rtc_ray_hit.hit.Ng_y = std::numeric_limits<float>::infinity();
rtc_ray_hit.hit.Ng_z = std::numeric_limits<float>::infinity();
rtc_ray_hit.hit.u = std::numeric_limits<float>::infinity();
rtc_ray_hit.hit.v = std::numeric_limits<float>::infinity();
rtc_ray_hit.hit.primID = RTC_INVALID_GEOMETRY_ID;
rtc_ray_hit.hit.geomID = RTC_INVALID_GEOMETRY_ID;
rtc_ray_hit.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
// intersect ray with scene
rtcIntersect1(g_rtc_scene, &g_rtc_intersect_context, &rtc_ray_hit);
if (rtc_ray_hit.ray.tfar < std::numeric_limits<float>::infinity()) {
assert(rtc_ray_hit.hit.primID != RTC_INVALID_GEOMETRY_ID);
assert(rtc_ray_hit.hit.geomID != RTC_INVALID_GEOMETRY_ID);
} else {
assert(rtc_ray_hit.hit.primID == RTC_INVALID_GEOMETRY_ID);
assert(rtc_ray_hit.hit.geomID == RTC_INVALID_GEOMETRY_ID);
}
if (rtc_ray_hit.hit.geomID != RTC_INVALID_GEOMETRY_ID) {
auto face_id = rtc_ray_hit.hit.primID;
covered_face_ids.insert(face_id);
}
}
//
// perform selection logic for each covered face
//
std::set<int> selected_mesh_object_ids;
for (auto f : covered_face_ids) {
auto select_face = true;
if (g_select_only_null_semantic_instance_id && g_segmentation_state_curr.mesh_objects_sii(g_faces_oi_curr(f)) != -1) {
select_face = false;
}
if (g_select_only_valid_semantic_instance_id && g_segmentation_state_curr.mesh_objects_sii(g_faces_oi_curr(f)) == -1) {
select_face = false;
}
if (g_select_only_null_semantic_id && g_segmentation_state_curr.mesh_objects_si(g_faces_oi_curr(f)) != -1) {
select_face = false;
}
if (g_select_only_valid_semantic_id && g_segmentation_state_curr.mesh_objects_si(g_faces_oi_curr(f)) == -1) {
select_face = false;
}
if (select_face) {
if (g_prefer_select_faces_by_mode == PREFER_SELECT_FACES_BY_MODE_OBJECT_MESH_ID) {
selected_mesh_object_ids.insert(g_faces_oi_curr(f));
}
if (g_prefer_select_faces_by_mode == PREFER_SELECT_FACES_BY_MODE_SEMANTIC_INSTANCE_ID) {
if (g_segmentation_state_curr.mesh_objects_sii(g_faces_oi_curr(f)) == -1) {
selected_mesh_object_ids.insert(g_faces_oi_curr(f));
} else {
arma::uvec indices = arma::find(g_segmentation_state_curr.mesh_objects_sii == g_segmentation_state_curr.mesh_objects_sii(g_faces_oi_curr(f)));
for (auto i : indices) {
selected_mesh_object_ids.insert(i);
}
}
}
if (g_prefer_select_faces_by_mode == PREFER_SELECT_FACES_BY_MODE_SEMANTIC_ID) {
if (g_segmentation_state_curr.mesh_objects_si(g_faces_oi_curr(f)) == -1) {
selected_mesh_object_ids.insert(g_faces_oi_curr(f));
} else {
arma::uvec indices = arma::find(g_segmentation_state_curr.mesh_objects_si == g_segmentation_state_curr.mesh_objects_si(g_faces_oi_curr(f)));
for (auto i : indices) {
selected_mesh_object_ids.insert(i);
}
}
}
}
}
//
// save segmentation state
//
g_segmentation_state_prev = g_segmentation_state_curr;
g_can_undo = true;
g_can_redo = false;
//
// update segmentation state
//
auto updated_segmentation_state = false;
for (auto m : selected_mesh_object_ids) {
updated_segmentation_state = true;
if (g_segmentation_layer == SEGMENTATION_LAYER_SEMANTIC_INSTANCE) {
int layer_index_val;
if (g_erase_mode) {
layer_index_val = -1;
} else {
if (g_assign_unique_semantic_instance_ids_to_each_mesh_object) {
g_semantic_instance_id = create_new_semantic_instance_segmentation_id();
g_updated_semantic_instance_id = true;
}
layer_index_val = g_semantic_instance_id;
}
g_segmentation_state_curr.mesh_objects_sii(m) = layer_index_val;
}
if (g_segmentation_layer == SEGMENTATION_LAYER_SEMANTIC) {
int layer_index_val;
if (g_erase_mode) {
layer_index_val = -1;
} else {
layer_index_val = g_semantic_id;
}
g_segmentation_state_curr.mesh_objects_si(m) = layer_index_val;
}
}
if (updated_segmentation_state) {
update_derived_segmentation_state(selected_mesh_object_ids);
set_viewer_mesh_colors();
}
}
}
g_mouse_rotation = false;
g_mouse_translation = false;
g_mouse_drawing = false;
g_mouse_drawing_create = false;
return true;
}