mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-22 16:21:24 -06:00
Can rasterize polygons with holes using AGG. Export is raw ppm for now.
This commit is contained in:
parent
cee965f5ac
commit
c3a944ef97
131 changed files with 45962 additions and 102 deletions
|
@ -12,11 +12,14 @@
|
|||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
// For png export of the sliced model
|
||||
#include <fstream>
|
||||
#include <wx/dcmemory.h>
|
||||
#include <wx/bitmap.h>
|
||||
#include <wx/image.h>
|
||||
#include <wx/graphics.h>
|
||||
|
||||
#include "Rasterizer/Rasterizer.hpp"
|
||||
|
||||
#include <omp.h>
|
||||
|
||||
namespace Slic3r {
|
||||
|
@ -1260,55 +1263,88 @@ public:
|
|||
|
||||
template<>
|
||||
class FilePrinter<Print::FilePrinterFormat::PNG> {
|
||||
wxBitmap bitmap_;
|
||||
std::unique_ptr<wxMemoryDC> dc_;
|
||||
std::unique_ptr<wxGraphicsContext> gc_;
|
||||
double pxw_;
|
||||
double pxh_;
|
||||
std::unique_ptr<Raster> rst_;
|
||||
Raster::Resolution res_;
|
||||
Raster::PixelDim pxdim_;
|
||||
public:
|
||||
inline FilePrinter(unsigned width_px, unsigned height_px,
|
||||
double width_mm, double height_mm):
|
||||
bitmap_(width_px, height_px),
|
||||
dc_(new wxMemoryDC(bitmap_)),
|
||||
gc_(wxGraphicsContext::Create(*dc_)),
|
||||
pxw_(width_mm/width_px),
|
||||
pxh_(height_mm/width_px)
|
||||
{
|
||||
gc_->SetAntialiasMode(wxANTIALIAS_DEFAULT);
|
||||
}
|
||||
double width_mm, double height_mm):
|
||||
res_(width_px, height_px),
|
||||
pxdim_(width_mm/width_px, height_mm/height_px) {}
|
||||
|
||||
FilePrinter(const FilePrinter& ) = delete;
|
||||
FilePrinter(FilePrinter&& m):
|
||||
bitmap_(std::move(m.bitmap_)), dc_(std::move(m.dc_)),
|
||||
gc_(std::move(m.gc_)), pxw_(m.pxw_), pxh_(m.pxh_) {}
|
||||
rst_(std::move(m.rst_)),
|
||||
res_(m.res_),
|
||||
pxdim_(m.pxdim_) {}
|
||||
|
||||
void drawPolygon(const Polygon& p) {
|
||||
|
||||
gc_->SetPen(*wxWHITE_PEN);
|
||||
std::vector<wxPoint2DDouble> points;
|
||||
points.reserve(p.points.size());
|
||||
|
||||
for(auto pp : p.points) {
|
||||
points.emplace_back(
|
||||
std::round(pp.x * SCALING_FACTOR/pxw_),
|
||||
std::round(pp.y * SCALING_FACTOR/pxh_)
|
||||
);
|
||||
}
|
||||
|
||||
gc_->DrawLines(points.size(), points.data());
|
||||
inline void drawPolygon(const Polygon& p) {
|
||||
if(!rst_) rst_.reset(new Raster(res_, pxdim_));
|
||||
rst_->draw(p);
|
||||
}
|
||||
|
||||
void finish() {
|
||||
|
||||
inline void finish() {
|
||||
rst_.reset();
|
||||
}
|
||||
|
||||
void save(const std::string& path) {
|
||||
if(!bitmap_.SaveFile(path, wxBITMAP_TYPE_PNG)) {
|
||||
std::cout << "fail for " << path << std::endl;
|
||||
}
|
||||
inline void save(const std::string& path) {
|
||||
std::fstream out(path, std::fstream::out | std::fstream::binary);
|
||||
rst_->save(out);
|
||||
out.close();
|
||||
}
|
||||
};
|
||||
|
||||
//template<>
|
||||
//class FilePrinter<Print::FilePrinterFormat::PNG> {
|
||||
// wxBitmap bitmap_;
|
||||
// std::unique_ptr<wxMemoryDC> dc_;
|
||||
// std::unique_ptr<wxGraphicsContext> gc_;
|
||||
// double pxw_;
|
||||
// double pxh_;
|
||||
//public:
|
||||
// inline FilePrinter(unsigned width_px, unsigned height_px,
|
||||
// double width_mm, double height_mm):
|
||||
// bitmap_(width_px, height_px),
|
||||
// dc_(new wxMemoryDC(bitmap_)),
|
||||
// gc_(wxGraphicsContext::Create(*dc_)),
|
||||
// pxw_(width_mm/width_px),
|
||||
// pxh_(height_mm/width_px)
|
||||
// {
|
||||
// gc_->SetAntialiasMode(wxANTIALIAS_DEFAULT);
|
||||
// }
|
||||
|
||||
// FilePrinter(const FilePrinter& ) = delete;
|
||||
// FilePrinter(FilePrinter&& m):
|
||||
// bitmap_(std::move(m.bitmap_)), dc_(std::move(m.dc_)),
|
||||
// gc_(std::move(m.gc_)), pxw_(m.pxw_), pxh_(m.pxh_) {}
|
||||
|
||||
// void drawPolygon(const Polygon& p) {
|
||||
|
||||
// gc_->SetPen(*wxWHITE_PEN);
|
||||
// std::vector<wxPoint2DDouble> points;
|
||||
// points.reserve(p.points.size());
|
||||
|
||||
// for(auto pp : p.points) {
|
||||
// points.emplace_back(
|
||||
// std::round(pp.x * SCALING_FACTOR/pxw_),
|
||||
// std::round(pp.y * SCALING_FACTOR/pxh_)
|
||||
// );
|
||||
// }
|
||||
|
||||
// gc_->DrawLines(points.size(), points.data());
|
||||
// }
|
||||
|
||||
// void finish() {
|
||||
|
||||
// }
|
||||
|
||||
// void save(const std::string& path) {
|
||||
// if(!bitmap_.SaveFile(path, wxBITMAP_TYPE_PNG)) {
|
||||
// std::cout << "fail for " << path << std::endl;
|
||||
// }
|
||||
// }
|
||||
//};
|
||||
|
||||
template<Print::FilePrinterFormat format, class...Args>
|
||||
void Print::print_to(std::string dirpath, Args...args)
|
||||
{
|
||||
|
@ -1338,8 +1374,10 @@ void Print::print_to(std::string dirpath, Args...args)
|
|||
|
||||
std::vector<FilePrinter<format>> printers;
|
||||
printers.reserve(layers.size());
|
||||
for(unsigned i = 0; i < layers.size(); i++)
|
||||
|
||||
for(unsigned i = 0; i < layers.size(); i++) {
|
||||
printers.emplace_back(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
#pragma omp parallel for
|
||||
for(int layer_id = 0; layer_id < layers.size(); layer_id++) {
|
||||
|
@ -1378,54 +1416,10 @@ void Print::print_to(std::string dirpath, Args...args)
|
|||
});
|
||||
});
|
||||
|
||||
printers[layer_id].save(dir + "layer" + std::to_string(layer_id) + ".ppm");
|
||||
printer.finish();
|
||||
|
||||
// layer_id++;
|
||||
// if ($layer->slice_z == -1) {
|
||||
// printf $fh qq{ <g id="layer%d">\n}, $layer_id;
|
||||
// } else {
|
||||
// printf $fh qq{ <g id="layer%d" slic3r:z="%s">\n}, $layer_id, unscale($layer->slice_z);
|
||||
// }
|
||||
|
||||
// my @current_layer_slices = ();
|
||||
// # sort slices so that the outermost ones come first
|
||||
// my @slices = sort { $a->contour->contains_point($b->contour->first_point) ? 0 : 1 } @{$layer->slices};
|
||||
// foreach my $copy (@{$layer->object->_shifted_copies}) {
|
||||
// foreach my $slice (@slices) {
|
||||
// my $expolygon = $slice->clone;
|
||||
// $expolygon->translate(@$copy);
|
||||
// $expolygon->translate(-$print_bb->x_min, -$print_bb->y_min);
|
||||
// $print_polygon->($expolygon->contour, 'contour');
|
||||
// $print_polygon->($_, 'hole') for @{$expolygon->holes};
|
||||
// push @current_layer_slices, $expolygon;
|
||||
// }
|
||||
// }
|
||||
// # generate support material
|
||||
// if ($self->has_support_material && $layer->id > 0) {
|
||||
// my (@supported_slices, @unsupported_slices) = ();
|
||||
// foreach my $expolygon (@current_layer_slices) {
|
||||
// my $intersection = intersection_ex(
|
||||
// [ map @$_, @previous_layer_slices ],
|
||||
// [ @$expolygon ],
|
||||
// );
|
||||
// @$intersection
|
||||
// ? push @supported_slices, $expolygon
|
||||
// : push @unsupported_slices, $expolygon;
|
||||
// }
|
||||
// my @supported_points = map @$_, @$_, @supported_slices;
|
||||
// foreach my $expolygon (@unsupported_slices) {
|
||||
// # look for the nearest point to this island among all
|
||||
// # supported points
|
||||
// my $contour = $expolygon->contour;
|
||||
// my $support_point = $contour->first_point->nearest_point(\@supported_points)
|
||||
// or next;
|
||||
// my $anchor_point = $support_point->nearest_point([ @$contour ]);
|
||||
// printf $fh qq{ <line x1="%s" y1="%s" x2="%s" y2="%s" style="stroke-width: 2; stroke: white" />\n},
|
||||
// map @$_, $support_point, $anchor_point;
|
||||
// }
|
||||
// }
|
||||
// print $fh qq{ </g>\n};
|
||||
// @previous_layer_slices = @current_layer_slices;
|
||||
// std::cout << "processed layers: " << layer_id + 1 << std::endl;
|
||||
previous_layer_slices = current_layer_slices;
|
||||
}
|
||||
|
||||
|
@ -1434,8 +1428,9 @@ void Print::print_to(std::string dirpath, Args...args)
|
|||
}
|
||||
|
||||
void Print::print_to_png(std::string dirpath, long width_px, long height_px,
|
||||
Pointf pixel_size_mm) {
|
||||
print_to<FilePrinterFormat::PNG>(dirpath, 2560, 1440, 700, 400);
|
||||
double width_mm, double height_mm) {
|
||||
print_to<FilePrinterFormat::PNG>(dirpath, width_px, height_px,
|
||||
width_mm, height_mm);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -319,11 +319,11 @@ public:
|
|||
void print_to(std::string dirpath, Args...args);
|
||||
|
||||
void print_to_png(std::string dirpath, long width_px, long height_px,
|
||||
Pointf pixel_size_mm);
|
||||
double width_mm, double height_mm);
|
||||
|
||||
void print_to_png(std::string dirpath) {
|
||||
// Where should this be specified?
|
||||
print_to_png(dirpath, 2560, 1440, Pointf{2560/700.0, 2560/400.0});
|
||||
print_to_png(dirpath, 2560, 1440, 70.0, 40.0);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -1,40 +1,156 @@
|
|||
#include "Rasterizer.hpp"
|
||||
|
||||
#include <png.h>
|
||||
#include <cstdint>
|
||||
|
||||
// For rasterizing
|
||||
#include <agg/agg_basics.h>
|
||||
#include <agg/agg_rendering_buffer.h>
|
||||
#include <agg/agg_pixfmt_gray.h>
|
||||
#include <agg/agg_pixfmt_rgb.h>
|
||||
#include <agg/agg_renderer_base.h>
|
||||
#include <agg/agg_renderer_primitives.h>
|
||||
#include <agg/agg_renderer_scanline.h>
|
||||
|
||||
#include <agg/agg_scanline_p.h>
|
||||
#include <agg/agg_rasterizer_scanline_aa.h>
|
||||
#include <agg/agg_path_storage.h>
|
||||
|
||||
// For compression
|
||||
#include <png.h>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class Raster::Impl {
|
||||
public:
|
||||
using TBuffer = std::vector<std::array<std::uint8_t,3>>;
|
||||
using TPixelRenderer = agg::pixfmt_rgb24;
|
||||
using TRawRenderer = agg::renderer_base<TPixelRenderer>;
|
||||
using TRenderer = agg::renderer_primitives<TRawRenderer>;
|
||||
using TPixel = TPixelRenderer::color_type;
|
||||
using TRawBuffer = agg::rendering_buffer;
|
||||
|
||||
using TRendererAA = agg::renderer_scanline_aa_solid<TRawRenderer>;
|
||||
|
||||
static const TPixel ColorWhite;
|
||||
static const TPixel ColorBlack;
|
||||
|
||||
private:
|
||||
Raster::Resolution resolution_;
|
||||
Raster::PixelDim pxdim_;
|
||||
TBuffer buf_;
|
||||
TRawBuffer rbuf_;
|
||||
TPixelRenderer pixfmt_;
|
||||
TRawRenderer raw_renderer_;
|
||||
public:
|
||||
inline Impl(const Raster::Resolution& res, const Raster::PixelDim &pd):
|
||||
resolution_(res), pxdim_(pd),
|
||||
buf_(res.pixels()),
|
||||
rbuf_(reinterpret_cast<std::uint8_t*>(buf_.data()),
|
||||
res.width_px, res.height_px, res.width_px*sizeof(TBuffer::value_type)),
|
||||
pixfmt_(rbuf_),
|
||||
raw_renderer_(pixfmt_)
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void draw(const Polygon &p) {
|
||||
TRendererAA ren_aa(raw_renderer_);
|
||||
agg::rasterizer_scanline_aa<> ras;
|
||||
agg::scanline_p8 scanlines;
|
||||
|
||||
agg::path_storage paths;
|
||||
|
||||
// ras.gamma(agg::gamma_power(1.0));
|
||||
|
||||
auto it = p.points.begin();
|
||||
auto itnext = std::next(it);
|
||||
|
||||
{
|
||||
double xf = std::round(it->x * SCALING_FACTOR/pxdim_.w_mm);
|
||||
double yf = std::round(it->y * SCALING_FACTOR/pxdim_.h_mm);
|
||||
double nxf = std::round(itnext->x * SCALING_FACTOR/pxdim_.w_mm);
|
||||
double nyf = std::round(itnext->y * SCALING_FACTOR/pxdim_.h_mm);
|
||||
|
||||
paths.move_to(xf, yf);
|
||||
paths.line_to(nxf, nyf);
|
||||
|
||||
++it, ++itnext;
|
||||
}
|
||||
while(itnext != p.points.end() ) {
|
||||
// double xf = std::round(it->x * SCALING_FACTOR/pxdim_.w_mm);
|
||||
// double yf = std::round(it->y * SCALING_FACTOR/pxdim_.h_mm);
|
||||
// auto x = renderer_.coord(xf);
|
||||
// auto y = renderer_.coord(yf);
|
||||
|
||||
double nxf = std::round(itnext->x * SCALING_FACTOR/pxdim_.w_mm);
|
||||
double nyf = std::round(itnext->y * SCALING_FACTOR/pxdim_.h_mm);
|
||||
// auto nx = renderer_.coord(nxf);
|
||||
// auto ny = renderer_.coord(nyf);
|
||||
|
||||
// renderer_.move_to(x, y);
|
||||
// renderer_.line_to(nx, ny);
|
||||
|
||||
// paths.move_to(xf, yf);
|
||||
paths.line_to(nxf, nyf);
|
||||
|
||||
/*++it,*/ ++itnext;
|
||||
}
|
||||
|
||||
paths.close_polygon();
|
||||
ras.add_path(paths);
|
||||
|
||||
ren_aa.color(ColorWhite);
|
||||
agg::render_scanlines(ras, scanlines, ren_aa);
|
||||
}
|
||||
|
||||
inline void clear() {
|
||||
raw_renderer_.clear(ColorBlack);
|
||||
}
|
||||
|
||||
inline const TBuffer& buffer() const { return buf_; }
|
||||
|
||||
inline const Raster::Resolution resolution() { return resolution_; }
|
||||
};
|
||||
|
||||
Raster::Raster(const Raster::Resolution &r, const Raster::PixelDim &pd):
|
||||
impl_(new Impl), resolution_(r), pxdim_(pd) {}
|
||||
const Raster::Impl::TPixel Raster::Impl::ColorWhite = Raster::Impl::TPixel(255, 255, 255);
|
||||
const Raster::Impl::TPixel Raster::Impl::ColorBlack = Raster::Impl::TPixel(0, 0, 0);
|
||||
|
||||
Raster::Raster(const Resolution &r, const PixelDim &pd):
|
||||
impl_(new Impl(r, pd)) {}
|
||||
|
||||
Raster::~Raster() {}
|
||||
|
||||
Raster::Raster(const Raster &cpy): resolution_(cpy.resolution_),
|
||||
pxdim_(cpy.pxdim_) {
|
||||
Raster::Raster(const Raster &cpy) {
|
||||
*impl_ = *(cpy.impl_);
|
||||
}
|
||||
|
||||
Raster::Raster(Raster &&m):
|
||||
impl_(std::move(m.impl_)), resolution_(m.resolution_), pxdim_(m.pxdim_) {}
|
||||
impl_(std::move(m.impl_)) {}
|
||||
|
||||
void Raster::clear()
|
||||
{
|
||||
|
||||
impl_->clear();
|
||||
}
|
||||
|
||||
void Raster::draw(const Polygon &poly)
|
||||
{
|
||||
png_image ifo;
|
||||
impl_->draw(poly);
|
||||
}
|
||||
|
||||
void Raster::finish()
|
||||
void Raster::save(std::ostream& stream, Compression comp)
|
||||
{
|
||||
switch(comp) {
|
||||
case Compression::RAW:
|
||||
case Compression::PNG:
|
||||
stream << "P6 "
|
||||
<< impl_->resolution().width_px << " "
|
||||
<< impl_->resolution().height_px << " "
|
||||
<< "255 ";
|
||||
|
||||
stream.write(reinterpret_cast<const char*>(impl_->buffer().data()),
|
||||
impl_->buffer().size()*sizeof(Impl::TBuffer::value_type));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef RASTERIZER_HPP
|
||||
#define RASTERIZER_HPP
|
||||
|
||||
#include <ostream>
|
||||
#include <Polygon.hpp>
|
||||
|
||||
namespace Slic3r {
|
||||
|
@ -10,10 +11,18 @@ class Raster {
|
|||
std::unique_ptr<Impl> impl_;
|
||||
public:
|
||||
|
||||
enum class Compression {
|
||||
RAW,
|
||||
PNG
|
||||
};
|
||||
|
||||
struct Resolution {
|
||||
unsigned width_px;
|
||||
unsigned height_px;
|
||||
inline Resolution(unsigned w, unsigned h): width_px(w), height_px(h) {}
|
||||
inline unsigned pixels() const /*noexcept*/ {
|
||||
return width_px * height_px;
|
||||
}
|
||||
};
|
||||
|
||||
struct PixelDim {
|
||||
|
@ -23,7 +32,7 @@ public:
|
|||
w_mm(px_width_mm), h_mm(px_height_mm) {}
|
||||
};
|
||||
|
||||
inline explicit Raster(const Resolution& r, const PixelDim& pd );
|
||||
explicit Raster(const Resolution& r, const PixelDim& pd );
|
||||
~Raster();
|
||||
Raster(const Raster& cpy);
|
||||
Raster(Raster&& m);
|
||||
|
@ -32,11 +41,7 @@ public:
|
|||
|
||||
void draw(const Polygon& poly);
|
||||
|
||||
void finish();
|
||||
|
||||
private:
|
||||
Resolution resolution_;
|
||||
PixelDim pxdim_;
|
||||
void save(std::ostream& stream, Compression comp = Compression::RAW);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue