diff --git a/src/canvas_modes.cpp b/src/canvas_modes.cpp index f800a84..af2b181 100644 --- a/src/canvas_modes.cpp +++ b/src/canvas_modes.cpp @@ -433,7 +433,33 @@ void CanvasModeGrid::on_MouseEvent(MouseEvent* me, glm::vec2& loc) glm::vec2 fb_pos; if (Canvas::I->point_trace(loc, ro, rd, hit_o, fb_pos, hit_d, m_plane_id)) { - m_lines.push_back({ hit_o, hit_d }); + m_action = std::make_unique(); + m_action->m_mode = this; + m_action->m_highlight = m_highlight; + m_action->m_selected_index = m_selected_index; + m_action->m_lines = m_lines; + + int select = -1; + for (int i = 0; i < m_lines.size(); i++) + { + auto const& l = m_lines[i]; + float d = lines_distance(ro, ro+rd*10.f, l.o-l.d*10.f, l.o+l.d*10.f); + if (d < 0.03f) + select = i; + } + if (select == -1) + { + m_lines.push_back({ hit_o, hit_d }); + m_selected_index = (int)m_lines.size() - 1; + m_highlight = false; + m_added = true; + } + else + { + m_selected_index = select; + m_highlight = true; + m_added = false; + } origin = hit_o; dir = hit_d; m_dragging = true; @@ -443,6 +469,7 @@ void CanvasModeGrid::on_MouseEvent(MouseEvent* me, glm::vec2& loc) case kEventType::MouseUpL: node->mouse_release(); m_dragging = false; + ActionManager::add(m_action.release()); //commit(); break; case kEventType::MouseMove: @@ -451,7 +478,7 @@ void CanvasModeGrid::on_MouseEvent(MouseEvent* me, glm::vec2& loc) glm::vec2 hit_fb; if (m_dragging && Canvas::I->point_trace_plane(loc, ro, rd, hit_o, hit_d, hit_fb, m_plane_id)) { - m_lines.back() = { hit_o, hit_d }; + m_lines[m_selected_index] = { hit_o, hit_d }; origin = hit_o; dir = hit_d; m_dragging = true; @@ -459,7 +486,7 @@ void CanvasModeGrid::on_MouseEvent(MouseEvent* me, glm::vec2& loc) break; } case kEventType::MouseCancel: - if (m_dragging) + if (m_dragging && m_selected_index == m_lines.size() - 1) m_lines.pop_back(); m_dragging = false; node->mouse_release(); @@ -471,14 +498,16 @@ void CanvasModeGrid::on_MouseEvent(MouseEvent* me, glm::vec2& loc) void CanvasModeGrid::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera) { - //if (m_dragging) - for (auto l : m_lines) + const glm::vec4 blue(0, 0, 1, 1); + const glm::vec4 red(1, 0, 0, 1); + for (int i = 0; i < m_lines.size(); i++) { + auto const& l = m_lines[i]; auto origin = l.o; auto dir = l.d; ShaderManager::use(kShader::Color); ShaderManager::u_mat4(kShaderUniform::MVP, proj * camera); - ShaderManager::u_vec4(kShaderUniform::Col, {1, 0, 0, 1}); + ShaderManager::u_vec4(kShaderUniform::Col, m_highlight && i == m_selected_index ? blue : red); static glm::vec4 AB[2]; AB[0] = {origin - dir * 10.f, 1}; AB[1] = {origin + dir * 10.f, 1 }; @@ -512,6 +541,41 @@ void CanvasModeGrid::clear() m_lines.clear(); } +void CanvasModeGrid::on_KeyEvent(KeyEvent* ke) +{ + if ((ke->m_key == kKey::KeyBackspace || ke->m_key == kKey::KeyDel) + && ke->m_type == kEventType::KeyUp) + { + if (m_highlight) + { + auto a = new ActionModeGrid; + a->m_mode = this; + a->m_highlight = m_highlight; + a->m_selected_index = m_selected_index; + a->m_lines = m_lines; + ActionManager::add(a); + m_lines.erase(m_lines.begin() + m_selected_index); + m_highlight = false; + } + } +} + +Action* ActionModeGrid::get_redo() +{ + auto a = new ActionModeGrid; + a->m_mode = m_mode; + a->m_highlight = m_mode->m_highlight; + a->m_selected_index = m_mode->m_selected_index; + a->m_lines = m_mode->m_lines; + return a; +} +void ActionModeGrid::undo() +{ + m_mode->m_highlight = m_highlight; + m_mode->m_selected_index = m_selected_index; + m_mode->m_lines = m_lines; +} + //////////////////////////////////////////////////////////////////// void CanvasModeMaskFree::init() diff --git a/src/canvas_modes.h b/src/canvas_modes.h index 69de7f6..66b75fd 100644 --- a/src/canvas_modes.h +++ b/src/canvas_modes.h @@ -3,6 +3,7 @@ #include "shape.h" #include "brush.h" #include "texture.h" +#include "action.h" #include enum class kCanvasMode @@ -106,6 +107,7 @@ public: virtual void leave(kCanvasMode next) override; }; +struct ray_t { glm::vec3 o, d; }; class CanvasModeGrid : public CanvasMode { LineSegment m_line; @@ -113,15 +115,30 @@ class CanvasModeGrid : public CanvasMode glm::vec3 dir; int m_plane_id; bool m_dragging = false; - struct ray_t { glm::vec3 o, d; }; - std::vector m_lines; + bool m_added = false; + std::unique_ptr m_action; public: + bool m_highlight = false; + int m_selected_index; + std::vector m_lines; virtual void on_MouseEvent(MouseEvent* me, glm::vec2& loc) override; + virtual void on_KeyEvent(KeyEvent* ke) override; virtual void on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera) override; virtual void init() override; void commit(); void clear(); }; +struct ActionModeGrid : public Action +{ + CanvasModeGrid* m_mode; + bool m_highlight; + int m_selected_index; + std::vector m_lines; + virtual void run() override { } + virtual Action* get_redo() override; + virtual void undo() override; + virtual size_t memory() override { return 0; } +}; class CanvasModeCamera : public CanvasMode { diff --git a/src/event.h b/src/event.h index 6116d2f..c7e0eac 100644 --- a/src/event.h +++ b/src/event.h @@ -74,6 +74,7 @@ enum class kKey : uint8_t KeyTab, KeyEnter, KeyBackspace, + KeyDel, }; enum class kEventResult : uint8_t diff --git a/src/keymap.h b/src/keymap.h index 9e132fb..b3392fe 100644 --- a/src/keymap.h +++ b/src/keymap.h @@ -191,7 +191,7 @@ kKey convert_key(int key) CASE(kVK_Return, kKey::KeyEnter); CASE(kVK_Tab, kKey::KeyTab); CASE(kVK_Space, kKey::Unknown); - CASE(kVK_Delete, kKey::Unknown); + CASE(kVK_Delete, kKey::KeyDel); CASE(kVK_Escape, kKey::Unknown); CASE(kVK_Command, kKey::KeyCtrl); CASE(kVK_Shift, kKey::KeyShift); @@ -277,7 +277,7 @@ kKey convert_key(int key) CASE(VK_EXECUTE, kKey::Unknown); CASE(VK_SNAPSHOT, kKey::Unknown); CASE(VK_INSERT, kKey::Unknown); - CASE(VK_DELETE, kKey::Unknown); + CASE(VK_DELETE, kKey::KeyDel); CASE(VK_HELP, kKey::Unknown); CASE('0', kKey::Key0); CASE('1', kKey::Key1); @@ -432,6 +432,230 @@ kKey convert_key(int key) CASE(VK_NONAME, kKey::Unknown); CASE(VK_PA1, kKey::Unknown); CASE(VK_OEM_CLEAR, kKey::Unknown); +#elif defined(__ANDROID__) + CASE(AKEYCODE_UNKNOWN, kKey::Unknown); + CASE(AKEYCODE_SOFT_LEFT, kKey::Unknown); + CASE(AKEYCODE_SOFT_RIGHT, kKey::Unknown); + CASE(AKEYCODE_HOME, kKey::AndroidHome); + CASE(AKEYCODE_BACK, kKey::AndroidBack); + CASE(AKEYCODE_CALL, kKey::Unknown); + CASE(AKEYCODE_ENDCALL, kKey::Unknown); + CASE(AKEYCODE_0, kKey::Unknown); + CASE(AKEYCODE_1, kKey::Unknown); + CASE(AKEYCODE_2, kKey::Unknown); + CASE(AKEYCODE_3, kKey::Unknown); + CASE(AKEYCODE_4, kKey::Unknown); + CASE(AKEYCODE_5, kKey::Unknown); + CASE(AKEYCODE_6, kKey::Unknown); + CASE(AKEYCODE_7, kKey::Unknown); + CASE(AKEYCODE_8, kKey::Unknown); + CASE(AKEYCODE_9, kKey::Unknown); + CASE(AKEYCODE_STAR, kKey::Unknown); + CASE(AKEYCODE_POUND, kKey::Unknown); + CASE(AKEYCODE_DPAD_UP, kKey::Unknown); + CASE(AKEYCODE_DPAD_DOWN, kKey::Unknown); + CASE(AKEYCODE_DPAD_LEFT, kKey::Unknown); + CASE(AKEYCODE_DPAD_RIGHT, kKey::Unknown); + CASE(AKEYCODE_DPAD_CENTER, kKey::Unknown); + CASE(AKEYCODE_VOLUME_UP, kKey::AndroidVolumeUp); + CASE(AKEYCODE_VOLUME_DOWN, kKey::AndroidVolumeDown); + CASE(AKEYCODE_POWER, kKey::Unknown); + CASE(AKEYCODE_CAMERA, kKey::Unknown); + CASE(AKEYCODE_CLEAR, kKey::Unknown); + CASE(AKEYCODE_A, kKey::Unknown); + CASE(AKEYCODE_B, kKey::Unknown); + CASE(AKEYCODE_C, kKey::Unknown); + CASE(AKEYCODE_D, kKey::Unknown); + CASE(AKEYCODE_E, kKey::Unknown); + CASE(AKEYCODE_F, kKey::Unknown); + CASE(AKEYCODE_G, kKey::Unknown); + CASE(AKEYCODE_H, kKey::Unknown); + CASE(AKEYCODE_I, kKey::Unknown); + CASE(AKEYCODE_J, kKey::Unknown); + CASE(AKEYCODE_K, kKey::Unknown); + CASE(AKEYCODE_L, kKey::Unknown); + CASE(AKEYCODE_M, kKey::Unknown); + CASE(AKEYCODE_N, kKey::Unknown); + CASE(AKEYCODE_O, kKey::Unknown); + CASE(AKEYCODE_P, kKey::Unknown); + CASE(AKEYCODE_Q, kKey::Unknown); + CASE(AKEYCODE_R, kKey::Unknown); + CASE(AKEYCODE_S, kKey::Unknown); + CASE(AKEYCODE_T, kKey::Unknown); + CASE(AKEYCODE_U, kKey::Unknown); + CASE(AKEYCODE_V, kKey::Unknown); + CASE(AKEYCODE_W, kKey::Unknown); + CASE(AKEYCODE_X, kKey::Unknown); + CASE(AKEYCODE_Y, kKey::Unknown); + CASE(AKEYCODE_Z, kKey::Unknown); + CASE(AKEYCODE_COMMA, kKey::Unknown); + CASE(AKEYCODE_PERIOD, kKey::Unknown); + CASE(AKEYCODE_ALT_LEFT, kKey::Unknown); + CASE(AKEYCODE_ALT_RIGHT, kKey::Unknown); + CASE(AKEYCODE_SHIFT_LEFT, kKey::Unknown); + CASE(AKEYCODE_SHIFT_RIGHT, kKey::Unknown); + CASE(AKEYCODE_TAB, kKey::Unknown); + CASE(AKEYCODE_SPACE, kKey::Unknown); + CASE(AKEYCODE_SYM, kKey::Unknown); + CASE(AKEYCODE_EXPLORER, kKey::Unknown); + CASE(AKEYCODE_ENVELOPE, kKey::Unknown); + CASE(AKEYCODE_ENTER, kKey::KeyEnter); + CASE(AKEYCODE_DEL, kKey::KeyBackspace); + CASE(AKEYCODE_GRAVE, kKey::Unknown); + CASE(AKEYCODE_MINUS, kKey::Unknown); + CASE(AKEYCODE_EQUALS, kKey::Unknown); + CASE(AKEYCODE_LEFT_BRACKET, kKey::Unknown); + CASE(AKEYCODE_RIGHT_BRACKET, kKey::Unknown); + CASE(AKEYCODE_BACKSLASH, kKey::Unknown); + CASE(AKEYCODE_SEMICOLON, kKey::Unknown); + CASE(AKEYCODE_APOSTROPHE, kKey::Unknown); + CASE(AKEYCODE_SLASH, kKey::Unknown); + CASE(AKEYCODE_AT, kKey::Unknown); + CASE(AKEYCODE_NUM, kKey::Unknown); + CASE(AKEYCODE_HEADSETHOOK, kKey::Unknown); + CASE(AKEYCODE_FOCUS, kKey::Unknown); + CASE(AKEYCODE_PLUS, kKey::Unknown); + CASE(AKEYCODE_MENU, kKey::Unknown); + CASE(AKEYCODE_NOTIFICATION, kKey::Unknown); + CASE(AKEYCODE_SEARCH, kKey::Unknown); + CASE(AKEYCODE_MEDIA_PLAY_PAUSE, kKey::Unknown); + CASE(AKEYCODE_MEDIA_STOP, kKey::Unknown); + CASE(AKEYCODE_MEDIA_NEXT, kKey::Unknown); + CASE(AKEYCODE_MEDIA_PREVIOUS, kKey::Unknown); + CASE(AKEYCODE_MEDIA_REWIND, kKey::Unknown); + CASE(AKEYCODE_MEDIA_FAST_FORWARD, kKey::Unknown); + CASE(AKEYCODE_MUTE, kKey::Unknown); + CASE(AKEYCODE_PAGE_UP, kKey::Unknown); + CASE(AKEYCODE_PAGE_DOWN, kKey::Unknown); + CASE(AKEYCODE_PICTSYMBOLS, kKey::Unknown); + CASE(AKEYCODE_SWITCH_CHARSET, kKey::Unknown); + CASE(AKEYCODE_BUTTON_A, kKey::Unknown); + CASE(AKEYCODE_BUTTON_B, kKey::Unknown); + CASE(AKEYCODE_BUTTON_C, kKey::Unknown); + CASE(AKEYCODE_BUTTON_X, kKey::Unknown); + CASE(AKEYCODE_BUTTON_Y, kKey::Unknown); + CASE(AKEYCODE_BUTTON_Z, kKey::Unknown); + CASE(AKEYCODE_BUTTON_L1, kKey::Unknown); + CASE(AKEYCODE_BUTTON_R1, kKey::Unknown); + CASE(AKEYCODE_BUTTON_L2, kKey::Unknown); + CASE(AKEYCODE_BUTTON_R2, kKey::Unknown); + CASE(AKEYCODE_BUTTON_THUMBL, kKey::Unknown); + CASE(AKEYCODE_BUTTON_THUMBR, kKey::Unknown); + CASE(AKEYCODE_BUTTON_START, kKey::Unknown); + CASE(AKEYCODE_BUTTON_SELECT, kKey::Unknown); + CASE(AKEYCODE_BUTTON_MODE, kKey::Unknown); + CASE(AKEYCODE_ESCAPE, kKey::Unknown); + CASE(AKEYCODE_FORWARD_DEL, kKey::Unknown); + CASE(AKEYCODE_CTRL_LEFT, kKey::Unknown); + CASE(AKEYCODE_CTRL_RIGHT, kKey::Unknown); + CASE(AKEYCODE_CAPS_LOCK, kKey::Unknown); + CASE(AKEYCODE_SCROLL_LOCK, kKey::Unknown); + CASE(AKEYCODE_META_LEFT, kKey::Unknown); + CASE(AKEYCODE_META_RIGHT, kKey::Unknown); + CASE(AKEYCODE_FUNCTION, kKey::Unknown); + CASE(AKEYCODE_SYSRQ, kKey::Unknown); + CASE(AKEYCODE_BREAK, kKey::Unknown); + CASE(AKEYCODE_MOVE_HOME, kKey::Unknown); + CASE(AKEYCODE_MOVE_END, kKey::Unknown); + CASE(AKEYCODE_INSERT, kKey::Unknown); + CASE(AKEYCODE_FORWARD, kKey::Unknown); + CASE(AKEYCODE_MEDIA_PLAY, kKey::Unknown); + CASE(AKEYCODE_MEDIA_PAUSE, kKey::Unknown); + CASE(AKEYCODE_MEDIA_CLOSE, kKey::Unknown); + CASE(AKEYCODE_MEDIA_EJECT, kKey::Unknown); + CASE(AKEYCODE_MEDIA_RECORD, kKey::Unknown); + CASE(AKEYCODE_F1, kKey::Unknown); + CASE(AKEYCODE_F2, kKey::Unknown); + CASE(AKEYCODE_F3, kKey::Unknown); + CASE(AKEYCODE_F4, kKey::Unknown); + CASE(AKEYCODE_F5, kKey::Unknown); + CASE(AKEYCODE_F6, kKey::Unknown); + CASE(AKEYCODE_F7, kKey::Unknown); + CASE(AKEYCODE_F8, kKey::Unknown); + CASE(AKEYCODE_F9, kKey::Unknown); + CASE(AKEYCODE_F10, kKey::Unknown); + CASE(AKEYCODE_F11, kKey::Unknown); + CASE(AKEYCODE_F12, kKey::Unknown); + CASE(AKEYCODE_NUM_LOCK, kKey::Unknown); + CASE(AKEYCODE_NUMPAD_0, kKey::Unknown); + CASE(AKEYCODE_NUMPAD_1, kKey::Unknown); + CASE(AKEYCODE_NUMPAD_2, kKey::Unknown); + CASE(AKEYCODE_NUMPAD_3, kKey::Unknown); + CASE(AKEYCODE_NUMPAD_4, kKey::Unknown); + CASE(AKEYCODE_NUMPAD_5, kKey::Unknown); + CASE(AKEYCODE_NUMPAD_6, kKey::Unknown); + CASE(AKEYCODE_NUMPAD_7, kKey::Unknown); + CASE(AKEYCODE_NUMPAD_8, kKey::Unknown); + CASE(AKEYCODE_NUMPAD_9, kKey::Unknown); + CASE(AKEYCODE_NUMPAD_DIVIDE, kKey::Unknown); + CASE(AKEYCODE_NUMPAD_MULTIPLY, kKey::Unknown); + CASE(AKEYCODE_NUMPAD_SUBTRACT, kKey::Unknown); + CASE(AKEYCODE_NUMPAD_ADD, kKey::Unknown); + CASE(AKEYCODE_NUMPAD_DOT, kKey::Unknown); + CASE(AKEYCODE_NUMPAD_COMMA, kKey::Unknown); + CASE(AKEYCODE_NUMPAD_ENTER, kKey::Unknown); + CASE(AKEYCODE_NUMPAD_EQUALS, kKey::Unknown); + CASE(AKEYCODE_NUMPAD_LEFT_PAREN, kKey::Unknown); + CASE(AKEYCODE_NUMPAD_RIGHT_PAREN, kKey::Unknown); + CASE(AKEYCODE_VOLUME_MUTE, kKey::Unknown); + CASE(AKEYCODE_INFO, kKey::Unknown); + CASE(AKEYCODE_CHANNEL_UP, kKey::Unknown); + CASE(AKEYCODE_CHANNEL_DOWN, kKey::Unknown); + CASE(AKEYCODE_ZOOM_IN, kKey::Unknown); + CASE(AKEYCODE_ZOOM_OUT, kKey::Unknown); + CASE(AKEYCODE_TV, kKey::Unknown); + CASE(AKEYCODE_WINDOW, kKey::Unknown); + CASE(AKEYCODE_GUIDE, kKey::Unknown); + CASE(AKEYCODE_DVR, kKey::Unknown); + CASE(AKEYCODE_BOOKMARK, kKey::Unknown); + CASE(AKEYCODE_CAPTIONS, kKey::Unknown); + CASE(AKEYCODE_SETTINGS, kKey::Unknown); + CASE(AKEYCODE_TV_POWER, kKey::Unknown); + CASE(AKEYCODE_TV_INPUT, kKey::Unknown); + CASE(AKEYCODE_STB_POWER, kKey::Unknown); + CASE(AKEYCODE_STB_INPUT, kKey::Unknown); + CASE(AKEYCODE_AVR_POWER, kKey::Unknown); + CASE(AKEYCODE_AVR_INPUT, kKey::Unknown); + CASE(AKEYCODE_PROG_RED, kKey::Unknown); + CASE(AKEYCODE_PROG_GREEN, kKey::Unknown); + CASE(AKEYCODE_PROG_YELLOW, kKey::Unknown); + CASE(AKEYCODE_PROG_BLUE, kKey::Unknown); + CASE(AKEYCODE_APP_SWITCH, kKey::Unknown); + CASE(AKEYCODE_BUTTON_1, kKey::Unknown); + CASE(AKEYCODE_BUTTON_2, kKey::Unknown); + CASE(AKEYCODE_BUTTON_3, kKey::Unknown); + CASE(AKEYCODE_BUTTON_4, kKey::Unknown); + CASE(AKEYCODE_BUTTON_5, kKey::Unknown); + CASE(AKEYCODE_BUTTON_6, kKey::Unknown); + CASE(AKEYCODE_BUTTON_7, kKey::Unknown); + CASE(AKEYCODE_BUTTON_8, kKey::Unknown); + CASE(AKEYCODE_BUTTON_9, kKey::Unknown); + CASE(AKEYCODE_BUTTON_10, kKey::Unknown); + CASE(AKEYCODE_BUTTON_11, kKey::Unknown); + CASE(AKEYCODE_BUTTON_12, kKey::Unknown); + CASE(AKEYCODE_BUTTON_13, kKey::Unknown); + CASE(AKEYCODE_BUTTON_14, kKey::Unknown); + CASE(AKEYCODE_BUTTON_15, kKey::Unknown); + CASE(AKEYCODE_BUTTON_16, kKey::Unknown); + CASE(AKEYCODE_LANGUAGE_SWITCH, kKey::Unknown); + CASE(AKEYCODE_MANNER_MODE, kKey::Unknown); + CASE(AKEYCODE_3D_MODE, kKey::Unknown); + CASE(AKEYCODE_CONTACTS, kKey::Unknown); + CASE(AKEYCODE_CALENDAR, kKey::Unknown); + CASE(AKEYCODE_MUSIC, kKey::Unknown); + CASE(AKEYCODE_CALCULATOR, kKey::Unknown); + CASE(AKEYCODE_ZENKAKU_HANKAKU, kKey::Unknown); + CASE(AKEYCODE_EISU, kKey::Unknown); + CASE(AKEYCODE_MUHENKAN, kKey::Unknown); + CASE(AKEYCODE_HENKAN, kKey::Unknown); + CASE(AKEYCODE_KATAKANA_HIRAGANA, kKey::Unknown); + CASE(AKEYCODE_YEN, kKey::Unknown); + CASE(AKEYCODE_RO, kKey::Unknown); + CASE(AKEYCODE_KANA, kKey::Unknown); + CASE(AKEYCODE_ASSIST, kKey::Unknown); + CASE(AKEYCODE_BRIGHTNESS_DOWN, kKey::Unknown); + CASE(AKEYCODE_BRIGHTNESS_UP, kKey::Unknown); + CASE(AKEYCODE_MEDIA_AUDIO_TRACK, kKey::Unknown); #endif default: return kKey::Unknown; diff --git a/src/node_canvas.cpp b/src/node_canvas.cpp index eb2cc01..941ae92 100644 --- a/src/node_canvas.cpp +++ b/src/node_canvas.cpp @@ -584,7 +584,9 @@ kEventResult NodeCanvas::handle_event(Event* e) ActionManager::undo(); if (ke->m_key == kKey::KeyAlt && m_mouse_focus) App::I.show_cursor(); - break; + for (auto& mode : *m_canvas->m_mode) + mode->on_KeyEvent(ke); + break; case kEventType::KeyUp: if (ke->m_key == kKey::KeyAlt && m_mouse_focus) m_canvas->m_current_mode == kCanvasMode::Draw || @@ -618,6 +620,8 @@ kEventResult NodeCanvas::handle_event(Event* e) App::I.dialog_save_ver(); } } + for (auto& mode : *m_canvas->m_mode) + mode->on_KeyEvent(ke); break; case kEventType::GestureStart: mouse_capture(); diff --git a/src/util.cpp b/src/util.cpp index 0039129..7bb48f0 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -75,6 +75,76 @@ bool ray_intersect(glm::vec3 ray_origin, glm::vec3 ray_dir, glm::vec3 plane_orig return true; }; +// see: http://geomalgorithms.com/a07-_distance.html +// dist3D_Line_to_Line(): get the 3D minimum distance between 2 lines +// Input: two 3D lines L1 and L2 +// Return: the shortest distance between L1 and L2 +float lines_distance(const glm::vec3& p0a, const glm::vec3& p0b, + const glm::vec3& p1a, const glm::vec3& p1b) +{ + glm::vec3 u = p0b - p0a; + glm::vec3 v = p1b - p1a; + glm::vec3 w = p0a - p1a; + float a = glm::dot(u,u); // always >= 0 + float b = glm::dot(u,v); + float c = glm::dot(v,v); // always >= 0 + float d = glm::dot(u,w); + float e = glm::dot(v,w); + float D = a*c - b*b; // always >= 0 + float sc, tc; + + // compute the line parameters of the two closest points + if (D < 0.00001f) { // the lines are almost parallel + sc = 0.0; + tc = (b>c ? d/b : e/c); // use the largest denominator + } + else { + sc = (b*e - c*d) / D; + tc = (a*e - b*d) / D; + } + + // get the difference of the two closest points + glm::vec3 dP = w + (sc * u) - (tc * v); // = L1(sc) - L2(tc) + + return glm::length(dP); // return the closest distance +} + +bool segments_intersect_3d(const glm::vec3& p0a, const glm::vec3& p0b, + const glm::vec3& p1a, const glm::vec3& p1b, glm::vec3& out_pt, glm::vec2& out_hit_uv) +{ + float denom = ((p1b.y - p1a.y)*(p0b.x - p0a.x)) - + ((p1b.x - p1a.x)*(p0b.y - p0a.y)); + + float nume_a = ((p1b.x - p1a.x)*(p0a.y - p1a.y)) - + ((p1b.y - p1a.y)*(p0b.x - p1a.x)); + + float nume_b = ((p0b.x - p0a.x)*(p0a.y - p1a.y)) - + ((p0b.y - p0a.y)*(p0a.x - p1a.x)); + + if(denom == 0.0f) + { + if(nume_a == 0.0f && nume_b == 0.0f) + { + return 0;//COINCIDENT; + } + return 0;//PARALLEL; + } + + float ua = nume_a / denom; + float ub = nume_b / denom; + + if(ua >= 0.0f && ua <= 1.0f && ub >= 0.0f && ub <= 1.0f) + { + // Get the intersection point. + out_pt.x = p0a.x + ua*(p0b.x - p0a.x); + out_pt.y = p0a.y + ua*(p0b.y - p0a.y); + + return 1;//INTERESECTING; + } + + return 0;//NOT_INTERESECTING; +} + // see: https://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect bool segments_intersect(const glm::vec2& p0a, const glm::vec2& p0b, const glm::vec2& p1a, const glm::vec2& p1b, glm::vec2& out_pt, glm::vec2& out_hit_uv) diff --git a/src/util.h b/src/util.h index e2a2f1e..2fc713d 100644 --- a/src/util.h +++ b/src/util.h @@ -57,6 +57,10 @@ glm::vec4 box_union(glm::vec4 a, glm::vec4 b); glm::vec4 box_intersection(glm::vec4 a, glm::vec4 b); bool ray_intersect(glm::vec3 ray_origin, glm::vec3 ray_dir, glm::vec3 plane_origin, glm::vec3 plane_normal, glm::vec3 plane_tangent, glm::vec3& out_hit, float& out_t); +float lines_distance(const glm::vec3& p0a, const glm::vec3& p0b, + const glm::vec3& p1a, const glm::vec3& p1b); +bool segments_intersect_3d(const glm::vec3& p0a, const glm::vec3& p0b, + const glm::vec3& p1a, const glm::vec3& p1b, glm::vec3& out_pt, glm::vec2& out_hit_uv); bool segments_intersect(const glm::vec2& p0a, const glm::vec2& p0b, const glm::vec2& p1a, const glm::vec2& p1b, glm::vec2& out_pt, glm::vec2& out_hit_uv); bool point_side(glm::vec2 a, glm::vec2 b, glm::vec2 p);