mirror of https://github.com/CGAL/cgal
752 lines
24 KiB
C++
752 lines
24 KiB
C++
#include "Scene_polylines_item.h"
|
|
#include "Scene_spheres_item.h"
|
|
|
|
#include <CGAL/bounding_box.h>
|
|
#include <CGAL/Three/Three.h>
|
|
#include <QMenu>
|
|
#include <QSlider>
|
|
#include <QWidgetAction>
|
|
#include <QAction>
|
|
#include <QInputDialog>
|
|
#include <QApplication>
|
|
|
|
struct Scene_polylines_item_private {
|
|
typedef Scene_polylines_item::K K;
|
|
typedef K::Point_3 Point_3;
|
|
|
|
Scene_polylines_item_private(Scene_polylines_item *parent) :
|
|
draw_extremities(false),
|
|
spheres_drawn_square_radius(0)
|
|
{
|
|
line_Slider = new QSlider(Qt::Horizontal);
|
|
line_Slider->setValue(CGAL::Three::Three::getDefaultLinesWidth());
|
|
line_Slider->setMaximum(2000);
|
|
line_Slider->setMinimum(1);
|
|
item = parent;
|
|
invalidate_stats();
|
|
}
|
|
|
|
void invalidate_stats()
|
|
{
|
|
nb_vertices = 0;
|
|
nb_edges = 0;
|
|
min_length = std::numeric_limits<double>::max();
|
|
max_length = 0;
|
|
mean_length = 0;
|
|
computed_stats = false;
|
|
}
|
|
|
|
enum VAOs {
|
|
Edges=0,
|
|
NbOfVaos
|
|
};
|
|
enum VBOs {
|
|
Edges_Vertices = 0,
|
|
NbOfVbos
|
|
};
|
|
|
|
mutable Scene_spheres_item *spheres;
|
|
mutable std::vector<float> positions_lines;
|
|
mutable std::size_t nb_lines;
|
|
typedef std::map<Point_3, int> Point_to_int_map;
|
|
typedef Point_to_int_map::iterator iterator;
|
|
void computeSpheres();
|
|
void initializeBuffers(CGAL::Three::Viewer_interface *viewer) const;
|
|
void computeElements() const;
|
|
bool draw_extremities;
|
|
double spheres_drawn_square_radius;
|
|
Scene_polylines_item *item;
|
|
mutable std::size_t nb_vertices;
|
|
mutable std::size_t nb_edges;
|
|
mutable double min_length;
|
|
mutable double max_length;
|
|
mutable double mean_length;
|
|
mutable bool computed_stats;
|
|
QSlider* line_Slider;
|
|
};
|
|
|
|
|
|
void
|
|
Scene_polylines_item_private::initializeBuffers(CGAL::Three::Viewer_interface *viewer = 0) const
|
|
{
|
|
float lineWidth[2];
|
|
if(!viewer->isOpenGL_4_3())
|
|
viewer->glGetFloatv(GL_LINE_WIDTH_RANGE, lineWidth);
|
|
else
|
|
{
|
|
lineWidth[0] = 0;
|
|
lineWidth[1] = 10;
|
|
}
|
|
line_Slider->setMaximum(lineWidth[1]);
|
|
QOpenGLShaderProgram *program;
|
|
//vao for the lines
|
|
{
|
|
if(viewer->isOpenGL_4_3())
|
|
program = item->getShaderProgram(Scene_polylines_item::PROGRAM_SOLID_WIREFRAME, viewer);
|
|
else
|
|
program = item->getShaderProgram(Scene_polylines_item::PROGRAM_NO_SELECTION, viewer);
|
|
program->bind();
|
|
|
|
item->vaos[Edges]->bind();
|
|
item->buffers[Edges_Vertices].bind();
|
|
item->buffers[Edges_Vertices].allocate(positions_lines.data(),
|
|
static_cast<int>(positions_lines.size()*sizeof(float)));
|
|
program->enableAttributeArray("vertex");
|
|
program->setAttributeBuffer("vertex",GL_FLOAT,0,4);
|
|
item->buffers[Edges_Vertices].release();
|
|
item->vaos[Edges]->release();
|
|
program->release();
|
|
|
|
nb_lines = positions_lines.size();
|
|
positions_lines.clear();
|
|
positions_lines.swap(positions_lines);
|
|
}
|
|
item->are_buffers_filled = true;
|
|
}
|
|
void
|
|
Scene_polylines_item_private::computeElements() const
|
|
{
|
|
const CGAL::qglviewer::Vec offset = static_cast<CGAL::Three::Viewer_interface*>(CGAL::QGLViewer::QGLViewerPool().first())->offset();
|
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
|
positions_lines.resize(0);
|
|
double mean = 0;
|
|
bool all_equal=true;
|
|
//Fills the VBO with the lines
|
|
for(std::list<std::vector<Point_3> >::const_iterator it = item->polylines.begin();
|
|
it != item->polylines.end();
|
|
++it)
|
|
{
|
|
if(it->empty()) continue;
|
|
if(it->front() == it->back())
|
|
nb_vertices += it->size() - 1;
|
|
else
|
|
nb_vertices += it->size();
|
|
|
|
for(size_t i = 0, end = it->size()-1;
|
|
i < end; ++i)
|
|
{
|
|
const Point_3& a = (*it)[i];
|
|
const Point_3& b = (*it)[i+1];
|
|
if(a!=b)
|
|
all_equal = false;
|
|
if(!computed_stats)
|
|
{
|
|
++nb_edges;
|
|
double length = CGAL::sqrt(
|
|
(a.x()-b.x()) * (a.x()-b.x()) +
|
|
(a.y()-b.y()) * (a.y()-b.y()) +
|
|
(a.z()-b.z()) * (a.z()-b.z()) );
|
|
if(max_length < length)
|
|
max_length = length;
|
|
if(min_length > length)
|
|
min_length = length;
|
|
mean += length;
|
|
}
|
|
|
|
positions_lines.push_back(a.x()+offset.x);
|
|
positions_lines.push_back(a.y()+offset.y);
|
|
positions_lines.push_back(a.z()+offset.z);
|
|
positions_lines.push_back(1.0);
|
|
|
|
positions_lines.push_back(b.x()+offset.x);
|
|
positions_lines.push_back(b.y()+offset.y);
|
|
positions_lines.push_back(b.z()+offset.z);
|
|
positions_lines.push_back(1.0);
|
|
}
|
|
|
|
}
|
|
if(all_equal)
|
|
item->setPointsMode();
|
|
if(!computed_stats)
|
|
mean_length = mean/double(nb_edges);
|
|
computed_stats = true;
|
|
QApplication::restoreOverrideCursor();
|
|
}
|
|
|
|
void
|
|
Scene_polylines_item_private::computeSpheres()
|
|
{
|
|
const CGAL::qglviewer::Vec v_offset = static_cast<CGAL::Three::Viewer_interface*>(CGAL::QGLViewer::QGLViewerPool().first())->offset();
|
|
K::Vector_3 offset(v_offset.x, v_offset.y, v_offset.z);
|
|
|
|
spheres->clear_spheres();
|
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
|
// FIRST, count the number of incident cycles and polylines
|
|
// for all extremities.
|
|
typedef std::map<Point_3, int> Point_to_int_map;
|
|
typedef Point_to_int_map::iterator iterator;
|
|
Point_to_int_map corner_polyline_nb;
|
|
|
|
{ // scope to fill corner_polyline_nb'
|
|
Point_to_int_map corner_cycles_nb;
|
|
|
|
for(std::list<std::vector<Point_3> >::const_iterator
|
|
it = item->polylines.begin(),
|
|
end = item->polylines.end();
|
|
it != end; ++it)
|
|
{
|
|
const K::Point_3& a = *it->begin();
|
|
const K::Point_3& b = *it->rbegin();
|
|
if(a == b) {
|
|
if ( it->size()>1 )
|
|
++corner_cycles_nb[a];
|
|
else
|
|
++corner_polyline_nb[a];
|
|
}
|
|
else {
|
|
++corner_polyline_nb[a];
|
|
++corner_polyline_nb[b];
|
|
}
|
|
}
|
|
// THEN, ignore points that are incident to one cycle only.
|
|
for(iterator
|
|
c_it = corner_cycles_nb.begin(),
|
|
end = corner_cycles_nb.end();
|
|
c_it != end; ++c_it)
|
|
{
|
|
const Point_3& a = c_it->first;
|
|
|
|
iterator p_it = corner_polyline_nb.find(a);
|
|
|
|
// If the point 'a'=c_it->first has only incident cycles...
|
|
if(p_it == corner_polyline_nb.end()) {
|
|
// ...then count it as a corner only if it has two incident cycles
|
|
// or more.
|
|
if(c_it->second > 1) {
|
|
corner_polyline_nb[a] = c_it->second;
|
|
}
|
|
} else {
|
|
// else add the number of cycles.
|
|
p_it->second += c_it->second;
|
|
}
|
|
}
|
|
}
|
|
// At this point, 'corner_polyline_nb' gives the multiplicity of all
|
|
// corners.
|
|
//Finds the centers of the spheres and their color
|
|
for(iterator
|
|
p_it = corner_polyline_nb.begin(),
|
|
end = corner_polyline_nb.end();
|
|
p_it != end; ++p_it)
|
|
{
|
|
const K::Point_3& center = p_it->first;
|
|
unsigned char colors[3];
|
|
switch(p_it->second) {
|
|
case 1:
|
|
colors[0] = 0; // black
|
|
colors[1] = 0;
|
|
colors[2] = 0;
|
|
break;
|
|
case 2:
|
|
colors[0] = 0; // green
|
|
colors[1] = 200;
|
|
colors[2] = 0;
|
|
break;
|
|
case 3:
|
|
colors[0] = 0; // blue
|
|
colors[1] = 0;
|
|
colors[2] = 200;
|
|
break;
|
|
case 4:
|
|
colors[0] = 200; //red
|
|
colors[1] = 0;
|
|
colors[2] = 0;
|
|
break;
|
|
default:
|
|
colors[0] = 200; //fuschia
|
|
colors[1] = 0;
|
|
colors[2] = 200;
|
|
}
|
|
|
|
CGAL::Color c(colors[0], colors[1], colors[2]);
|
|
spheres->add_sphere(K::Sphere_3(center+offset, spheres_drawn_square_radius), c);
|
|
}
|
|
spheres->setToolTip(
|
|
QString("<p>Legend of endpoints colors: <ul>"
|
|
"<li>black: one incident polyline</li>"
|
|
"<li>green: two incident polylines</li>"
|
|
"<li>blue: three incident polylines</li>"
|
|
"<li>red: four incident polylines</li>"
|
|
"<li>fuchsia: five or more incident polylines</li>"
|
|
"</ul></p>"
|
|
"<p>Tip: To erase this item, set its radius to 0 or less. </p>")
|
|
);
|
|
QApplication::restoreOverrideCursor();
|
|
}
|
|
|
|
Scene_polylines_item::Scene_polylines_item()
|
|
:CGAL::Three::Scene_group_item("unnamed",Scene_polylines_item_private::NbOfVbos,Scene_polylines_item_private::NbOfVaos)
|
|
,d(new Scene_polylines_item_private(this))
|
|
{
|
|
setRenderingMode(FlatPlusEdges);
|
|
d->nb_lines = 0;
|
|
d->spheres = NULL;
|
|
invalidateOpenGLBuffers();
|
|
|
|
}
|
|
|
|
Scene_polylines_item::~Scene_polylines_item()
|
|
{
|
|
delete d->line_Slider;
|
|
delete d;
|
|
|
|
}
|
|
|
|
bool
|
|
Scene_polylines_item::isEmpty() const {
|
|
return polylines.empty();
|
|
}
|
|
|
|
void
|
|
Scene_polylines_item::compute_bbox() const {
|
|
typedef K::Iso_cuboid_3 Iso_cuboid_3;
|
|
|
|
if(isEmpty())
|
|
{
|
|
_bbox =Bbox();
|
|
return;
|
|
}
|
|
std::list<Point_3> boxes;
|
|
for(std::list<std::vector<Point_3> >::const_iterator it = polylines.begin();
|
|
it != polylines.end();
|
|
++it){
|
|
if(it->begin() != it->end()) {
|
|
Iso_cuboid_3 cub = CGAL::bounding_box(it->begin(), it->end());
|
|
boxes.push_back((cub.min)());
|
|
boxes.push_back((cub.max)());
|
|
}
|
|
}
|
|
Iso_cuboid_3 bbox =
|
|
boxes.begin() != boxes.end() ?
|
|
CGAL::bounding_box(boxes.begin(), boxes.end()) :
|
|
Iso_cuboid_3();
|
|
|
|
_bbox = Bbox(bbox.xmin(),
|
|
bbox.ymin(),
|
|
bbox.zmin(),
|
|
bbox.xmax(),
|
|
bbox.ymax(),
|
|
bbox.zmax());
|
|
}
|
|
|
|
Scene_item::Bbox Scene_polylines_item::bbox() const
|
|
{
|
|
if(!is_bbox_computed)
|
|
compute_bbox();
|
|
is_bbox_computed = true;
|
|
return _bbox;
|
|
}
|
|
Scene_polylines_item*
|
|
Scene_polylines_item::clone() const {
|
|
Scene_polylines_item* item = new Scene_polylines_item;
|
|
item->polylines = polylines;
|
|
QVariant metadata_variant = property("polylines metadata");
|
|
if(metadata_variant.type() == QVariant::StringList)
|
|
{
|
|
item->setProperty("polylines metadata", metadata_variant);
|
|
}
|
|
return item;
|
|
}
|
|
|
|
QString
|
|
Scene_polylines_item::toolTip() const {
|
|
QString s =
|
|
tr("<p><b>%1</b> (mode: %2, color: %3)<br />"
|
|
"<i>Polylines</i></p>"
|
|
"<p>Number of polylines: %4</p>")
|
|
.arg(this->name())
|
|
.arg(this->renderingModeName())
|
|
.arg(this->color().name())
|
|
.arg(polylines.size());
|
|
if(polylines.size() == 1 )
|
|
{
|
|
double length = 0;
|
|
for(std::size_t i=1; i<polylines.front().size(); ++i)
|
|
{
|
|
K::Vector_3 vec(polylines.front()[i-1], polylines.front()[i]);
|
|
length += CGAL::sqrt(vec.squared_length());
|
|
}
|
|
QString vertices_info = tr("<p>Number of vertices: %1<br />"
|
|
"Polyline's length: %2</p>")
|
|
.arg(polylines.front().size())
|
|
.arg(length);
|
|
s.append(vertices_info);
|
|
|
|
}
|
|
return s;
|
|
}
|
|
|
|
bool
|
|
Scene_polylines_item::supportsRenderingMode(RenderingMode m) const {
|
|
return (m == Wireframe ||
|
|
m == FlatPlusEdges ||
|
|
m == Points);
|
|
}
|
|
|
|
// Shaded OpenGL drawing: only draw spheres
|
|
void
|
|
Scene_polylines_item::draw(CGAL::Three::Viewer_interface* viewer) const {
|
|
if(!visible())
|
|
return;
|
|
if(!are_buffers_filled)
|
|
{
|
|
d->computeElements();
|
|
d->initializeBuffers(viewer);
|
|
}
|
|
if(d->draw_extremities)
|
|
{
|
|
Scene_group_item::draw(viewer);
|
|
}
|
|
}
|
|
|
|
// Wireframe OpenGL drawing
|
|
void
|
|
Scene_polylines_item::drawEdges(CGAL::Three::Viewer_interface* viewer) const {
|
|
if(!visible())
|
|
return;
|
|
if(renderingMode() == Wireframe
|
|
|| renderingMode() == FlatPlusEdges)
|
|
{
|
|
if(!are_buffers_filled)
|
|
{
|
|
d->computeElements();
|
|
d->initializeBuffers(viewer);
|
|
}
|
|
|
|
vaos[Scene_polylines_item_private::Edges]->bind();
|
|
if(!viewer->isOpenGL_4_3())
|
|
{
|
|
attribBuffers(viewer, PROGRAM_NO_SELECTION);
|
|
}
|
|
else
|
|
{
|
|
attribBuffers(viewer, PROGRAM_SOLID_WIREFRAME);
|
|
}
|
|
QOpenGLShaderProgram *program = viewer->isOpenGL_4_3() ? getShaderProgram(PROGRAM_SOLID_WIREFRAME)
|
|
: getShaderProgram(PROGRAM_NO_SELECTION);
|
|
program->bind();
|
|
if(viewer->isOpenGL_4_3())
|
|
{
|
|
QVector2D vp(viewer->width(), viewer->height());
|
|
program->setUniformValue("viewport", vp);
|
|
program->setUniformValue("near",(GLfloat)viewer->camera()->zNear());
|
|
program->setUniformValue("far",(GLfloat)viewer->camera()->zFar());
|
|
program->setUniformValue("width", GLfloat(d->line_Slider->value()));
|
|
}
|
|
program->setAttributeValue("colors", this->color());
|
|
viewer->glDrawArrays(GL_LINES, 0, static_cast<GLsizei>(d->nb_lines/4));
|
|
program->release();
|
|
vaos[Scene_polylines_item_private::Edges]->release();
|
|
}
|
|
if(d->draw_extremities)
|
|
{
|
|
Scene_group_item::drawEdges(viewer);
|
|
}
|
|
}
|
|
|
|
void
|
|
Scene_polylines_item::drawPoints(CGAL::Three::Viewer_interface* viewer) const {
|
|
if(!visible())
|
|
return;
|
|
if(renderingMode() == Points)
|
|
{
|
|
if(!are_buffers_filled)
|
|
{
|
|
d->computeElements();
|
|
d->initializeBuffers(viewer);
|
|
}
|
|
GLfloat point_size;
|
|
viewer->glGetFloatv(GL_POINT_SIZE, &point_size);
|
|
viewer->setGlPointSize(GLfloat(5));
|
|
vaos[Scene_polylines_item_private::Edges]->bind();
|
|
attribBuffers(viewer, PROGRAM_NO_SELECTION);
|
|
QOpenGLShaderProgram *program = getShaderProgram(PROGRAM_NO_SELECTION);
|
|
program->bind();
|
|
QColor temp = this->color();
|
|
program->setAttributeValue("colors", temp);
|
|
viewer->glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(d->nb_lines/4));
|
|
// Clean-up
|
|
vaos[Scene_polylines_item_private::Edges]->release();
|
|
program->release();
|
|
viewer->setGlPointSize(point_size);
|
|
}
|
|
if(d->draw_extremities)
|
|
{
|
|
Scene_group_item::drawPoints(viewer);
|
|
}
|
|
}
|
|
|
|
QMenu* Scene_polylines_item::contextMenu()
|
|
{
|
|
const char* prop_name = "Menu modified by Scene_polylines_item.";
|
|
|
|
QMenu* menu = Scene_item::contextMenu();
|
|
|
|
// Use dynamic properties:
|
|
// http://doc.qt.io/qt-5/qobject.html#property
|
|
bool menuChanged = menu->property(prop_name).toBool();
|
|
|
|
if(!menuChanged) {
|
|
menu->addSeparator();
|
|
// TODO: add actions to display corners
|
|
QAction* action = menu->addAction(tr("Display corners with radius..."));
|
|
connect(action, SIGNAL(triggered()),
|
|
this, SLOT(change_corner_radii()));
|
|
|
|
QAction* actionSmoothPolylines =
|
|
menu->addAction(tr("Smooth polylines"));
|
|
actionSmoothPolylines->setObjectName("actionSmoothPolylines");
|
|
connect(actionSmoothPolylines, SIGNAL(triggered()),this, SLOT(smooth()));
|
|
|
|
QMenu *container = new QMenu(tr("Line Width"));
|
|
QWidgetAction *sliderAction = new QWidgetAction(0);
|
|
connect(d->line_Slider, &QSlider::valueChanged, this, &Scene_polylines_item::itemChanged);
|
|
|
|
sliderAction->setDefaultWidget(d->line_Slider);
|
|
|
|
container->addAction(sliderAction);
|
|
menu->addMenu(container);
|
|
|
|
menu->setProperty(prop_name, true);
|
|
}
|
|
return menu;
|
|
}
|
|
|
|
void Scene_polylines_item::invalidateOpenGLBuffers()
|
|
{
|
|
are_buffers_filled = false;
|
|
d->invalidate_stats();
|
|
compute_bbox();
|
|
|
|
|
|
}
|
|
|
|
void Scene_polylines_item::change_corner_radii() {
|
|
bool ok = true;
|
|
double proposed_radius = std::sqrt(d->spheres_drawn_square_radius);
|
|
if(proposed_radius == 0) {
|
|
CGAL::Three::Scene_interface::Bbox b = bbox();
|
|
proposed_radius = (std::max)(b.xmax() - b.xmin(),
|
|
proposed_radius);
|
|
proposed_radius = (std::max)(b.ymax() - b.ymin(),
|
|
proposed_radius);
|
|
proposed_radius = (std::max)(b.zmax() - b.zmin(),
|
|
proposed_radius);
|
|
proposed_radius /= 100;
|
|
}
|
|
double r = QInputDialog::getDouble(NULL,
|
|
tr("Display corners with new radius..."),
|
|
tr("Radius:"),
|
|
proposed_radius, // value
|
|
0., // min
|
|
2147483647., // max
|
|
10, // decimals
|
|
&ok);
|
|
if(ok) {
|
|
change_corner_radii(r);
|
|
}
|
|
}
|
|
|
|
void Scene_polylines_item::change_corner_radii(double r) {
|
|
if(r >= 0) {
|
|
d->spheres_drawn_square_radius = r*r;
|
|
d->draw_extremities = (r > 0);
|
|
if(r>0 && !d->spheres)
|
|
{
|
|
d->spheres = new Scene_spheres_item(this, false);
|
|
d->spheres->setName("Corner spheres");
|
|
d->spheres->setRenderingMode(Gouraud);
|
|
connect(d->spheres, SIGNAL(destroyed()), this, SLOT(reset_spheres()));
|
|
scene->addItem(d->spheres);
|
|
scene->changeGroup(d->spheres, this);
|
|
lockChild(d->spheres);
|
|
d->computeSpheres();
|
|
d->spheres->invalidateOpenGLBuffers();
|
|
}
|
|
else if(r>0 && d->spheres)
|
|
{
|
|
d->computeSpheres();
|
|
d->spheres->invalidateOpenGLBuffers();
|
|
}
|
|
else if (r<=0 && d->spheres!=NULL)
|
|
{
|
|
unlockChild(d->spheres);
|
|
scene->erase(scene->item_id(d->spheres));
|
|
}
|
|
Q_EMIT itemChanged();
|
|
}
|
|
}
|
|
|
|
void Scene_polylines_item::split_at_sharp_angles()
|
|
{
|
|
typedef Polylines_container Bare_polyline_container;
|
|
typedef Polyline Bare_polyline;
|
|
Polylines_container& bare_polylines = polylines;
|
|
|
|
int counter = 0;
|
|
for(Bare_polyline_container::iterator
|
|
bare_polyline_it = bare_polylines.begin();
|
|
bare_polyline_it != bare_polylines.end(); // the end changes
|
|
// during the loop
|
|
++counter /* bare_polyline_it is incremented in the loop */)
|
|
{
|
|
Bare_polyline_container::iterator current_polyline_it =
|
|
bare_polyline_it;
|
|
Bare_polyline& bare_polyline = *bare_polyline_it;
|
|
Bare_polyline::iterator it = boost::next(bare_polyline.begin());
|
|
|
|
if(boost::next(bare_polyline.begin()) == bare_polyline.end())
|
|
{
|
|
std::cerr << "WARNING: Isolated point in polylines\n";
|
|
bare_polyline_it = bare_polylines.erase(bare_polyline_it);
|
|
continue;
|
|
}
|
|
else
|
|
++bare_polyline_it;
|
|
if(it != bare_polyline.end()) {
|
|
for(; it != boost::prior(bare_polyline.end()); ++it) {
|
|
const Point_3 pv = *it;
|
|
const Point_3 pa = *boost::prior(it);
|
|
const Point_3 pb = *boost::next(it);
|
|
const K::Vector_3 av = pv - pa;
|
|
const K::Vector_3 bv = pv - pb;
|
|
const K::FT sc_prod = av * bv;
|
|
if( sc_prod >= 0 ||
|
|
(sc_prod < 0 &&
|
|
CGAL::square(sc_prod) < (av * av) * (bv * bv) / 4 ) )
|
|
{
|
|
#ifdef PROTECTION_DEBUG
|
|
std::cerr << "Split polyline (small angle) "
|
|
<< std::acos(sqrt(CGAL::square(sc_prod) /
|
|
((av*av) * (bv*bv)))) * 180 /CGAL_PI
|
|
<< " degres\n";
|
|
#endif
|
|
Bare_polyline new_polyline;
|
|
std::copy(it, bare_polyline.end(),
|
|
std::back_inserter(new_polyline));
|
|
|
|
if(*bare_polyline.begin() == *bare_polyline.rbegin()) {
|
|
// if the polyline is a cycle, test if its beginning is a sharp
|
|
// angle...
|
|
const Point_3 pv = *bare_polyline.begin();
|
|
const Point_3 pa = *boost::prior(boost::prior(bare_polyline.end()));
|
|
const Point_3 pb = *boost::next(bare_polyline.begin());
|
|
const K::Vector_3 av = pv - pa;
|
|
const K::Vector_3 bv = pv - pb;
|
|
const K::FT sc_prod = av * bv;
|
|
if( sc_prod >= 0 ||
|
|
(sc_prod < 0 &&
|
|
CGAL::square(sc_prod) < (av * av) * (bv * bv) / 4 ) )
|
|
{
|
|
// if its beginning is a sharp angle, then split
|
|
bare_polyline.erase(boost::next(it), bare_polyline.end());
|
|
}
|
|
else {
|
|
// ...if not, modifies its beginning
|
|
std::copy(boost::next(bare_polyline.begin()),
|
|
boost::next(it),
|
|
std::back_inserter(new_polyline));
|
|
bare_polylines.erase(current_polyline_it);
|
|
}
|
|
}
|
|
else {
|
|
bare_polyline.erase(boost::next(it), bare_polyline.end());
|
|
}
|
|
bare_polylines.push_back(new_polyline);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Q_EMIT itemChanged();
|
|
}
|
|
|
|
void
|
|
Scene_polylines_item::merge(Scene_polylines_item* other_item) {
|
|
if(other_item == 0) return;
|
|
std::copy(other_item->polylines.begin(),
|
|
other_item->polylines.end(),
|
|
std::back_inserter(polylines));
|
|
QVariant other_metadata_variant = other_item->property("polylines metadata");
|
|
if(other_metadata_variant.type() == QVariant::StringList)
|
|
{
|
|
QStringList metadata = property("polylines metadata").toStringList();
|
|
metadata.append(other_metadata_variant.toStringList());
|
|
setProperty("polylines metadata", metadata);
|
|
}
|
|
invalidateOpenGLBuffers();
|
|
}
|
|
|
|
void Scene_polylines_item::reset_spheres()
|
|
{
|
|
d->spheres = NULL;
|
|
}
|
|
|
|
void Scene_polylines_item::smooth(){
|
|
for (Polylines_container::iterator pit=polylines.begin(),pit_end=polylines.end();pit!=pit_end;++pit)
|
|
smooth(*pit);
|
|
invalidateOpenGLBuffers();
|
|
Q_EMIT itemChanged();
|
|
}
|
|
|
|
void Scene_polylines_item::smooth(std::vector<Point_3>& polyline){
|
|
bool is_closed = polyline.front()==polyline.back();
|
|
typedef K::Vector_3 Vector_3;
|
|
|
|
std::size_t start = is_closed ? 0:1;
|
|
std::size_t end = polyline.size()-1;
|
|
|
|
Vector_3 prev = (is_closed ? polyline[end-1] : polyline[0]) - CGAL::ORIGIN;
|
|
|
|
for (std::size_t i=start; i!=end; ++i)
|
|
{
|
|
Vector_3 curr = polyline[i] - CGAL::ORIGIN;
|
|
Vector_3 next = polyline[i+1] - CGAL::ORIGIN;
|
|
|
|
polyline[i] = CGAL::ORIGIN+(prev+2*curr+next)/4;
|
|
prev=curr;
|
|
}
|
|
|
|
if (is_closed) polyline[end]=polyline[0];
|
|
}
|
|
|
|
QString Scene_polylines_item::computeStats(int type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case NB_VERTICES:
|
|
return QString::number(d->nb_vertices);
|
|
case NB_EDGES:
|
|
return QString::number(d->nb_edges);
|
|
case MIN_LENGTH:
|
|
return QString::number(d->min_length);
|
|
case MAX_LENGTH:
|
|
return QString::number(d->max_length);
|
|
case MEAN_LENGTH:
|
|
return QString::number(d->mean_length);
|
|
default:
|
|
return QString();
|
|
}
|
|
}
|
|
CGAL::Three::Scene_item::Header_data Scene_polylines_item::header() const
|
|
{
|
|
CGAL::Three::Scene_item::Header_data data;
|
|
//categories
|
|
data.categories.append(std::pair<QString,int>(QString("Properties"),5));
|
|
|
|
|
|
//titles
|
|
data.titles.append(QString("#Vertices"));
|
|
data.titles.append(QString("#Segment Edges"));
|
|
data.titles.append(QString("Shortest Segment Edge Length"));
|
|
data.titles.append(QString("Longest Segment Edge Length"));
|
|
data.titles.append(QString("Average Segment Edge Length"));
|
|
return data;
|
|
}
|
|
|
|
void Scene_polylines_item::setWidth( int i)
|
|
{
|
|
d->line_Slider->setValue(i);
|
|
redraw();
|
|
}
|