implementing better triangulation
This commit is contained in:
@@ -140,7 +140,7 @@ bool App::key_down(kKey key)
|
|||||||
e.m_type = kEventType::KeyDown;
|
e.m_type = kEventType::KeyDown;
|
||||||
e.m_key = key;
|
e.m_key = key;
|
||||||
auto ret = layout[main_id]->on_event(&e);
|
auto ret = layout[main_id]->on_event(&e);
|
||||||
//layout[main_id]->update();
|
layout[main_id]->update();
|
||||||
return ret == kEventResult::Consumed;
|
return ret == kEventResult::Consumed;
|
||||||
}
|
}
|
||||||
bool App::key_up(kKey key)
|
bool App::key_up(kKey key)
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
#include "node_canvas.h"
|
#include "node_canvas.h"
|
||||||
#include "app.h"
|
#include "app.h"
|
||||||
#include <poly2tri.h>
|
|
||||||
|
|
||||||
NodeCanvas* CanvasMode::node;
|
NodeCanvas* CanvasMode::node;
|
||||||
ui::Canvas* CanvasMode::canvas;
|
ui::Canvas* CanvasMode::canvas;
|
||||||
@@ -375,6 +374,145 @@ char get_line_intersection(float p0_x, float p0_y, float p1_x, float p1_y,
|
|||||||
return 0; // No collision
|
return 0; // No collision
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SegmentCount = 0;
|
||||||
|
std::vector<ui::Shape::vertex_t> CanvasModeFill::triangulate(const std::vector<std::shared_ptr<p2t::Point>>& points)
|
||||||
|
{
|
||||||
|
struct Segment
|
||||||
|
{
|
||||||
|
std::shared_ptr<p2t::Point> a = nullptr;
|
||||||
|
std::shared_ptr<p2t::Point> b = nullptr;
|
||||||
|
Segment* prev = nullptr;
|
||||||
|
std::shared_ptr<Segment> next = nullptr;
|
||||||
|
bool end = false;
|
||||||
|
Segment()
|
||||||
|
{
|
||||||
|
SegmentCount++;
|
||||||
|
}
|
||||||
|
~Segment()
|
||||||
|
{
|
||||||
|
SegmentCount--;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::shared_ptr<Segment> root = std::make_shared<Segment>();
|
||||||
|
std::shared_ptr<Segment> node = root;
|
||||||
|
for (int i = 0; i < points.size(); i++)
|
||||||
|
{
|
||||||
|
node->a = points[i];
|
||||||
|
if (i == points.size() - 1)
|
||||||
|
{
|
||||||
|
node->b = points[0];
|
||||||
|
node->next = root;
|
||||||
|
node->end = true;
|
||||||
|
root->prev = node.get();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node->b = points[i + 1];
|
||||||
|
node->next = std::make_shared<Segment>();
|
||||||
|
node->next->prev = node.get();
|
||||||
|
}
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = root;
|
||||||
|
std::stack<std::shared_ptr<Segment>> todo;
|
||||||
|
std::vector<std::shared_ptr<Segment>> polys;
|
||||||
|
todo.push(root);
|
||||||
|
while (!todo.empty())
|
||||||
|
{
|
||||||
|
node = todo.top();
|
||||||
|
todo.pop();
|
||||||
|
polys.push_back(node);
|
||||||
|
while (node)
|
||||||
|
{
|
||||||
|
std::shared_ptr<Segment> other = node->next;
|
||||||
|
while (other)
|
||||||
|
{
|
||||||
|
if (*node->a == *other->a || *node->a == *other->b ||
|
||||||
|
*node->b == *other->a || *node->b == *other->b)
|
||||||
|
{
|
||||||
|
other = other->end ? nullptr : other->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
glm::vec2 s0a(node->a->x, node->a->y);
|
||||||
|
glm::vec2 s0b(node->b->x, node->b->y);
|
||||||
|
glm::vec2 s1a(other->a->x, other->a->y);
|
||||||
|
glm::vec2 s1b(other->b->x, other->b->y);
|
||||||
|
glm::vec2 is;
|
||||||
|
if (segments_intersect(s0a, s0b, s1a, s1b, is))
|
||||||
|
{
|
||||||
|
auto p = std::make_shared<p2t::Point>(is.x, is.y);
|
||||||
|
auto poly_root = std::make_shared<Segment>();
|
||||||
|
poly_root->a = p;
|
||||||
|
poly_root->b = node->b;
|
||||||
|
poly_root->next = node->next;
|
||||||
|
todo.push(poly_root);
|
||||||
|
other->a = p;
|
||||||
|
node->b = p;
|
||||||
|
auto poly_end = std::make_shared<Segment>();
|
||||||
|
poly_end->a = other->prev->b;
|
||||||
|
poly_end->b = p;
|
||||||
|
poly_end->end = true;
|
||||||
|
poly_end->prev = other->prev;
|
||||||
|
other->prev->next = poly_end;
|
||||||
|
other->prev = node.get();
|
||||||
|
node->next = other;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
other = other->end ? nullptr : other->next;
|
||||||
|
}
|
||||||
|
node = node->end ? nullptr : node->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ui::Shape::vertex_t> vertices;
|
||||||
|
for (auto poly : polys)
|
||||||
|
{
|
||||||
|
std::vector<p2t::Point*> outline;
|
||||||
|
node = poly;
|
||||||
|
while (node)
|
||||||
|
{
|
||||||
|
outline.push_back(new p2t::Point(*node->a));
|
||||||
|
auto current = node;
|
||||||
|
node = node->end ? nullptr : node->next;
|
||||||
|
current->next = nullptr;
|
||||||
|
}
|
||||||
|
LOG("poly %ld", outline.size());
|
||||||
|
|
||||||
|
if (outline.size() > 2)
|
||||||
|
{
|
||||||
|
p2t::CDT* cdt = new p2t::CDT(outline);
|
||||||
|
cdt->Triangulate();
|
||||||
|
auto tr = cdt->GetTriangles();
|
||||||
|
for (auto t : tr)
|
||||||
|
{
|
||||||
|
ui::Shape::vertex_t vertex;
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
auto p = t->GetPoint(i);
|
||||||
|
|
||||||
|
glm::vec3 ro, rd, hit_o, hit_d;
|
||||||
|
glm::vec2 hit_fb;
|
||||||
|
int plane_id;
|
||||||
|
if (canvas->point_trace({p->x, p->y}, ro, rd, hit_o, hit_fb, hit_d, plane_id))
|
||||||
|
{
|
||||||
|
m_dirty_planes[plane_id]++;
|
||||||
|
vertex.pos = glm::vec4(hit_o, 1);
|
||||||
|
vertices.push_back(vertex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete cdt;
|
||||||
|
}
|
||||||
|
for (auto p : outline)
|
||||||
|
delete p;
|
||||||
|
}
|
||||||
|
|
||||||
|
return vertices;
|
||||||
|
}
|
||||||
|
|
||||||
void CanvasModeFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
void CanvasModeFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
||||||
{
|
{
|
||||||
static glm::vec2 oldpos;
|
static glm::vec2 oldpos;
|
||||||
@@ -432,32 +570,14 @@ void CanvasModeFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
|||||||
m_dragging = false;
|
m_dragging = false;
|
||||||
if (m_points2d.size() > 3)
|
if (m_points2d.size() > 3)
|
||||||
{
|
{
|
||||||
std::vector<p2t::Point*> points;
|
std::vector<std::shared_ptr<p2t::Point>> points;
|
||||||
for (int i = 0; i < (int)m_points2d.size() - 1; i++)
|
for (int i = 0; i < (int)m_points2d.size() - 1; i++)
|
||||||
points.push_back(new p2t::Point(m_points2d[i].x, m_points2d[i].y));
|
points.emplace_back(std::make_shared<p2t::Point>(m_points2d[i].x, m_points2d[i].y));
|
||||||
p2t::CDT cdt(points);
|
auto v = triangulate(points);
|
||||||
cdt.Triangulate();
|
LOG("leaked segments: %d", SegmentCount);
|
||||||
auto triangles = cdt.GetTriangles();
|
LOG("%d points", (int)v.size());
|
||||||
std::vector<ui::Shape::vertex_t> v;
|
|
||||||
for (auto t : triangles)
|
m_shape.update_vertices(v.data(), (int)v.size());
|
||||||
{
|
|
||||||
ui::Shape::vertex_t vertex;
|
|
||||||
for (int i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
auto p = t->GetPoint(i);
|
|
||||||
|
|
||||||
glm::vec3 ro, rd, hit_o, hit_d;
|
|
||||||
glm::vec2 hit_fb;
|
|
||||||
int plane_id;
|
|
||||||
if (canvas->point_trace({p->x, p->y}, ro, rd, hit_o, hit_fb, hit_d, plane_id))
|
|
||||||
{
|
|
||||||
m_dirty_planes[plane_id]++;
|
|
||||||
vertex.pos = glm::vec4(hit_o, 1);
|
|
||||||
v.push_back(vertex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_shape.update_vertices(v.data(), v.size());
|
|
||||||
|
|
||||||
if (!m_points.empty())
|
if (!m_points.empty())
|
||||||
{
|
{
|
||||||
@@ -513,7 +633,7 @@ void CanvasModeFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
|||||||
m_points.push_back(vert);
|
m_points.push_back(vert);
|
||||||
m_points.push_back(vert);
|
m_points.push_back(vert);
|
||||||
}
|
}
|
||||||
m_shape.update_vertices(m_points.data(), m_points.size());
|
m_shape.update_vertices(m_points.data(), (int)m_points.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -551,14 +671,14 @@ if (canvas->point_trace_plane(loc, ro, rd, hit_o, hit_d, hit_fb, 0))
|
|||||||
if (m_dragging)
|
if (m_dragging)
|
||||||
{
|
{
|
||||||
m_points.pop_back();
|
m_points.pop_back();
|
||||||
m_shape.update_vertices(m_points.data(), m_points.size());
|
m_shape.update_vertices(m_points.data(), (int)m_points.size());
|
||||||
}
|
}
|
||||||
m_dragging = false;
|
m_dragging = false;
|
||||||
node->mouse_release();
|
node->mouse_release();
|
||||||
if (m_points.size() < 4)
|
if (m_points.size() < 4)
|
||||||
{
|
{
|
||||||
m_points.clear();
|
m_points.clear();
|
||||||
m_shape.update_vertices(m_points.data(), m_points.size());
|
m_shape.update_vertices(m_points.data(), (int)m_points.size());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "event.h"
|
#include "event.h"
|
||||||
#include "shape.h"
|
#include "shape.h"
|
||||||
#include "brush.h"
|
#include "brush.h"
|
||||||
|
#include <poly2tri.h>
|
||||||
|
|
||||||
NS_START
|
NS_START
|
||||||
class Canvas;
|
class Canvas;
|
||||||
@@ -100,4 +101,5 @@ public:
|
|||||||
virtual void on_MouseEvent(MouseEvent* me, glm::vec2& loc) override;
|
virtual void on_MouseEvent(MouseEvent* me, glm::vec2& loc) override;
|
||||||
virtual void init() override;
|
virtual void init() override;
|
||||||
virtual void leave() override;
|
virtual void leave() override;
|
||||||
|
std::vector<ui::Shape::vertex_t> triangulate(const std::vector<std::shared_ptr<p2t::Point>>& points);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -50,36 +50,31 @@ kEventResult Node::on_event(Event* e)
|
|||||||
{
|
{
|
||||||
kEventResult ret = kEventResult::Available;
|
kEventResult ret = kEventResult::Available;
|
||||||
|
|
||||||
if (e->m_cat == kEventCategory::MouseEvent)
|
if (current_mouse_capture)
|
||||||
|
return current_mouse_capture->on_event(e);
|
||||||
|
|
||||||
|
bool skip_children = false;
|
||||||
|
skip_children |= (e->m_cat == kEventCategory::MouseEvent || e->m_cat == kEventCategory::GestureEvent) &&
|
||||||
|
(m_mouse_captured) && (root()->current_mouse_capture == this) && m_capture_children;
|
||||||
|
|
||||||
|
if (!skip_children)
|
||||||
{
|
{
|
||||||
|
for (auto it = m_children.rbegin(); it != m_children.rend(); ++it)
|
||||||
{
|
{
|
||||||
if (current_mouse_capture)
|
if ((*it)->on_event(e) == kEventResult::Consumed)
|
||||||
return current_mouse_capture->on_event(e);
|
|
||||||
|
|
||||||
bool skip_children = false;
|
|
||||||
skip_children |= (e->m_cat == kEventCategory::MouseEvent || e->m_cat == kEventCategory::GestureEvent) &&
|
|
||||||
(m_mouse_captured) && (root()->current_mouse_capture == this) && m_capture_children;
|
|
||||||
|
|
||||||
if (!skip_children)
|
|
||||||
{
|
{
|
||||||
for (auto it = m_children.rbegin(); it != m_children.rend(); ++it)
|
if (m_flood_events)
|
||||||
{
|
{
|
||||||
if ((*it)->on_event(e) == kEventResult::Consumed)
|
ret = kEventResult::Consumed;
|
||||||
{
|
}
|
||||||
if (m_flood_events)
|
else
|
||||||
{
|
{
|
||||||
ret = kEventResult::Consumed;
|
return kEventResult::Consumed;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return kEventResult::Consumed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (ret == kEventResult::Consumed)
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (ret == kEventResult::Consumed)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (e->m_cat)
|
switch (e->m_cat)
|
||||||
|
|||||||
@@ -190,6 +190,10 @@ void NodeDialogSave::init_controls()
|
|||||||
destroy();
|
destroy();
|
||||||
};
|
};
|
||||||
input = find<NodeTextInput>("txt-input");
|
input = find<NodeTextInput>("txt-input");
|
||||||
|
input->on_return = [&](NodeTextInput* target){
|
||||||
|
if (btn_ok->on_click)
|
||||||
|
btn_ok->on_click(btn_ok);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
void NodeDialogSave::loaded()
|
void NodeDialogSave::loaded()
|
||||||
{
|
{
|
||||||
@@ -223,6 +227,10 @@ void NodeDialogNewDoc::init_controls()
|
|||||||
destroy();
|
destroy();
|
||||||
};
|
};
|
||||||
input = find<NodeTextInput>("txt-input");
|
input = find<NodeTextInput>("txt-input");
|
||||||
|
input->on_return = [&](NodeTextInput* target){
|
||||||
|
if (btn_ok->on_click)
|
||||||
|
btn_ok->on_click(btn_ok);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
void NodeDialogNewDoc::loaded()
|
void NodeDialogNewDoc::loaded()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ void NodePanelBrushPreset::init()
|
|||||||
brush->m_brush.m_tip_flow = .2;
|
brush->m_brush.m_tip_flow = .2;
|
||||||
brush->m_brush.m_tip_opacity = 1;
|
brush->m_brush.m_tip_opacity = 1;
|
||||||
brush->m_brush.m_tip_spacing = 0.03;
|
brush->m_brush.m_tip_spacing = 0.03;
|
||||||
brush->m_brush.m_jitter_spread = (rand() % 1000) * 0.0001;
|
//brush->m_brush.m_jitter_spread = (rand() % 1000) * 0.0001;
|
||||||
brush->m_preview->m_brush = brush->m_brush;
|
brush->m_preview->m_brush = brush->m_brush;
|
||||||
brush->m_preview->draw_stroke();
|
brush->m_preview->draw_stroke();
|
||||||
brush->m_thumb->m_path = path;
|
brush->m_thumb->m_path = path;
|
||||||
|
|||||||
@@ -75,6 +75,11 @@ kEventResult NodeTextInput::handle_event(Event* e)
|
|||||||
m_text->set_text(m_string.c_str());
|
m_text->set_text(m_string.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (ke->m_char == '\n' || ke->m_char == '\r') // enter/return
|
||||||
|
{
|
||||||
|
if (on_return)
|
||||||
|
on_return(this);
|
||||||
|
}
|
||||||
else if (ke->m_char >= 32 && ke->m_char < (32 + 96))
|
else if (ke->m_char >= 32 && ke->m_char < (32 + 96))
|
||||||
{
|
{
|
||||||
m_string += (char)ke->m_char;
|
m_string += (char)ke->m_char;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ class NodeTextInput : public NodeBorder
|
|||||||
public:
|
public:
|
||||||
NodeText* m_text;
|
NodeText* m_text;
|
||||||
std::string m_string;
|
std::string m_string;
|
||||||
|
std::function<void(NodeTextInput*target)> on_return;
|
||||||
virtual Node* clone_instantiate() const override;
|
virtual Node* clone_instantiate() const override;
|
||||||
virtual void clone_finalize(Node* dest) const override;
|
virtual void clone_finalize(Node* dest) const override;
|
||||||
virtual void init() override;
|
virtual void init() override;
|
||||||
|
|||||||
Reference in New Issue
Block a user