Skip to content

Commit

Permalink
Implemented evg-thin library
Browse files Browse the repository at this point in the history
  • Loading branch information
alranel committed Jan 9, 2014
1 parent 11f065c commit afb0cda
Show file tree
Hide file tree
Showing 13 changed files with 1,360 additions and 10 deletions.
2 changes: 1 addition & 1 deletion lib/Slic3r/ExPolygon.pm
Expand Up @@ -46,7 +46,7 @@ sub bounding_box {
# this method only works for expolygons having only a contour or
# a contour and a hole, and not being thicker than the supplied
# width. it returns a polyline or a polygon
sub medial_axis {
sub ____medial_axis {
my ($self, $width) = @_;
return $self->_medial_axis_voronoi($width);
}
Expand Down
3 changes: 2 additions & 1 deletion lib/Slic3r/Layer/Region.pm
Expand Up @@ -223,7 +223,8 @@ sub make_perimeters {

# process thin walls by collapsing slices to single passes
if (@thin_walls) {
my @p = map $_->medial_axis($pspacing), @thin_walls;
#my @p = map $_->medial_axis($pspacing), @thin_walls;
my @p = map @{$_->medial_axis}, @thin_walls;
my @paths = ();
for my $p (@p) {
next if $p->length <= $pspacing * 2;
Expand Down
4 changes: 4 additions & 0 deletions xs/MANIFEST
Expand Up @@ -24,6 +24,10 @@ src/ExtrusionEntity.cpp
src/ExtrusionEntity.hpp
src/ExtrusionEntityCollection.cpp
src/ExtrusionEntityCollection.hpp
src/evg-thin/datatypes.hpp
src/evg-thin/evg-thin.cpp
src/evg-thin/evg-thin.hpp
src/evg-thin/heap.hpp
src/Flow.cpp
src/Flow.hpp
src/Geometry.cpp
Expand Down
125 changes: 124 additions & 1 deletion xs/src/ExPolygon.cpp
@@ -1,19 +1,32 @@
#include "ExPolygon.hpp"
#include "Polygon.hpp"
#include "ClipperUtils.hpp"
#include "evg-thin/evg-thin.hpp"
#include <stdlib.h>

namespace Slic3r {

ExPolygon::operator Polygons() const
{
Polygons polygons(this->holes.size() + 1);
Polygons polygons;
polygons.push_back(this->contour);
for (Polygons::const_iterator it = this->holes.begin(); it != this->holes.end(); ++it) {
polygons.push_back(*it);
}
return polygons;
}

ExPolygon::operator Points() const
{
Points points;
Polygons pp = *this;
for (Polygons::const_iterator poly = pp.begin(); poly != pp.end(); ++poly) {
for (Points::const_iterator point = poly->points.begin(); point != poly->points.end(); ++point)
points.push_back(*point);
}
return points;
}

void
ExPolygon::scale(double factor)
{
Expand Down Expand Up @@ -119,6 +132,116 @@ ExPolygon::simplify(double tolerance, ExPolygons &expolygons) const
expolygons.insert(expolygons.end(), ep.begin(), ep.end());
}

void
ExPolygon::medial_axis(Polylines* polylines) const
{
// clone this expolygon and scale it down
ExPolygon scaled_this = *this;
#define MEDIAL_AXIS_SCALE 0.0001
scaled_this.scale(MEDIAL_AXIS_SCALE);

// get our bounding box and compute our size
BoundingBox bb(scaled_this);
Size size = bb.size();

// init grid to be as large as our size
EVG_THIN::grid_type grid;
grid.resize(size.x + 1);
for (coord_t x=0; x <= size.x; x++) {
grid[x].resize(size.y + 1);
for (coord_t y=0; y <= size.y; y++)
grid[x][y] = EVG_THIN::Free;
}

// draw polygons
Polygons pp = scaled_this;
for (Polygons::const_iterator p = pp.begin(); p != pp.end(); ++p) {
Lines lines = p->lines();
for (Lines::iterator line = lines.begin(); line != lines.end(); ++line) {
coord_t x1 = line->a.x - bb.min.x;
coord_t y1 = line->a.y - bb.min.y;
coord_t x2 = line->b.x - bb.min.x;
coord_t y2 = line->b.y - bb.min.y;

// Bresenham's line algorithm
const bool steep = (abs(y2 - y1) > abs(x2 - x1));
if (steep) {
std::swap(x1, y1);
std::swap(x2, y2);
}
if (x1 > x2) {
std::swap(x1, x2);
std::swap(y1, y2);
}

const double dx = x2 - x1;
const double dy = abs(y2 - y1);
double error = dx / 2.0f;
const coord_t ystep = (y1 < y2) ? 1 : -1;
coord_t y = (coord_t)y1;
const coord_t maxX = (coord_t)x2;

for (coord_t x = (coord_t)x1; x < maxX; x++) {
if (steep) {
grid[y][x] = EVG_THIN::Occupied;
} else {
grid[x][y] = EVG_THIN::Occupied;
}

error -= dy;
if (error < 0) {
y += ystep;
error += dx;
}
}
}
}
printf("Drawn\n");
// compute skeleton
EVG_THIN::evg_thin thin(grid, 0.0, FLT_MAX, false, false, -1, -1);
EVG_THIN::skeleton_type skel = thin.generate_skeleton();

// emulate a lambda function to allow recursion
struct PolyBuilder {
EVG_THIN::skeleton_type skel;
Polylines* polylines;
BoundingBox bb;

void follow (size_t node_id) {
EVG_THIN::node* node = &this->skel.at(node_id);
Polyline polyline;
polyline.points.push_back(Point(node->x + this->bb.min.x, node->y + this->bb.min.y));
while (node->children.size() == 1) {
node = &this->skel.at(node->children.front());
polyline.points.push_back(Point(node->x + this->bb.min.x, node->y + this->bb.min.y));
}
if (polyline.is_valid()) this->polylines->push_back(polyline);
if (node->children.size() > 1) {
for (std::vector<unsigned int>::const_iterator child_id = node->children.begin(); child_id != node->children.end(); ++child_id)
this->follow(*child_id);
}
}
} pb;
pb.skel = skel;
pb.polylines = polylines;
pb.bb = bb;

// build polylines
for (EVG_THIN::skeleton_type::const_iterator node = skel.begin(); node != skel.end(); ++node) {
printf("[%zu] x = %d, y = %d, parent = %d, children count = %zu\n", node - skel.begin(), node->x, node->y, node->parent, node->children.size());
if (node->parent == -1)
pb.follow(node - skel.begin());
}
for (Polylines::iterator it = polylines->begin(); it != polylines->end(); ++it)
it->scale(1/MEDIAL_AXIS_SCALE);
}

BoundingBox
ExPolygon::bounding_box() const
{
return BoundingBox(*this);
}

#ifdef SLIC3RXS
SV*
ExPolygon::to_AV() {
Expand Down
4 changes: 4 additions & 0 deletions xs/src/ExPolygon.hpp
@@ -1,6 +1,7 @@
#ifndef slic3r_ExPolygon_hpp_
#define slic3r_ExPolygon_hpp_

#include "BoundingBox.hpp"
#include "Polygon.hpp"
#include <vector>

Expand All @@ -15,6 +16,7 @@ class ExPolygon
Polygon contour;
Polygons holes;
operator Polygons() const;
operator Points() const;
void scale(double factor);
void translate(double x, double y);
void rotate(double angle, Point* center);
Expand All @@ -25,6 +27,8 @@ class ExPolygon
Polygons simplify_p(double tolerance) const;
ExPolygons simplify(double tolerance) const;
void simplify(double tolerance, ExPolygons &expolygons) const;
void medial_axis(Polylines* polylines) const;
BoundingBox bounding_box() const;

#ifdef SLIC3RXS
void from_SV(SV* poly_sv);
Expand Down
6 changes: 3 additions & 3 deletions xs/src/TriangleMesh.cpp
Expand Up @@ -580,10 +580,10 @@ TriangleMesh::slice(const std::vector<double> &z, std::vector<ExPolygons>* layer
#ifdef SLIC3R_DEBUG
size_t holes_count = 0;
for (ExPolygons::const_iterator e = ex_slices.begin(); e != ex_slices.end(); ++e) {
holes_count += e->holes.count();
holes_count += e->holes.size();
}
printf("Layer %d (slice_z = %.2f): %d surface(s) having %d holes detected from %d polylines\n",
layer_id, z[layer_id], ex_slices.count(), holes_count, loops->count());
printf("Layer %zu (slice_z = %.2f): %zu surface(s) having %zu holes detected from %zu polylines\n",
layer_id, z[layer_id], ex_slices.size(), holes_count, loops->size());
#endif

ExPolygons* layer = &(*layers)[layer_id];
Expand Down
91 changes: 91 additions & 0 deletions xs/src/evg-thin/datatypes.hpp
@@ -0,0 +1,91 @@
/*********************************************************************
EVG-THIN v1.1: A Thinning Approximation to the Extended Voronoi Graph
Copyright (C) 2006 - Patrick Beeson (pbeeson@cs.utexas.edu)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA
*********************************************************************/


#ifndef datatypes_hh
#define datatypes_hh

#include <vector>

using namespace std;

namespace EVG_THIN {

typedef unsigned int uint;

// GRID DATA TYPES

// Each cell belongs to one of three states.
typedef enum {Occupied, Unknown, Free} cell_type;

typedef vector<cell_type> column_type;

/**
The cells of a grid basically have three possible states: occupied,
free, or unknown. Free cells are light cells in a greyscale image
(129-255), occupied cells are dark (0-126), and (by default)
unknown cells are light grey (127&128). These ranges can be
changed at the command line.
**/
typedef vector<column_type> grid_type;




// SKELETON DATA TYPES

/**
This data type holds the data for a single node in a skeleton graph
(e.g. Voronoi graph of free space). Graphs are meant to be non-cyclic
graphs represented as trees. Each node has a location, a radius
(distance to nearest obstacle), a parent, some children, a tag of
whether it touches the edge of the LPM, and a distance to the root
node. Coordinates and distances are in occ. grid coordinates.
**/
class node {
public:
int x,y; //!< location in grid_coords
float radius; //!< distance to nearest obstacle (in number of cells)
float distance; //!< shortest depth in graph to graph root
int parent; //!< index of parant in list
/**
Basically, exactly equal to children.size() by the time the
skeleton is made. However, when making the skeleton, there may
times when the number of estimated children is known, but
children hasn't been fully filled out (e.g. doing a depth first
crawl over the raw skeleton to get a pruned skeleton).
**/
unsigned int num_children;
vector<unsigned int> children; //!< if # children > 1, graph branches

friend bool operator>(const node& n1, const node& n2) {
return n1.distance>n2.distance;
}
};

typedef vector<node> skeleton_type;

} // end namespace EVG_THIN

#endif

0 comments on commit afb0cda

Please sign in to comment.