diff --git a/CutDialog.cpp b/CutDialog.cpp
index 71c932c3..7a915db4 100644
--- a/CutDialog.cpp
+++ b/CutDialog.cpp
@@ -4,6 +4,7 @@
CutDialog::CutDialog(QWidget* parent) : QDialog(parent), ui(new Ui::CutDialog)
{
ui->setupUi(this);
+ ui->mediaCombo->setCurrentIndex(5);
// ui->mediaCombo->setCurrentIndex(ProgramOptions::Instance().getMedia());
// ui->speedSlider->setValue(ProgramOptions::Instance().getSpeed());
// ui->pressureSlider->setValue(ProgramOptions::Instance().getPressure());
@@ -68,6 +69,14 @@ bool CutDialog::trackEnhancing() const
return ui->trackEnhancingCheckbox->isChecked();
}
+void CutDialog::setRegMarks(QRectF bounding) const
+{
+ ui->regMarksGroup->setEnabled(!bounding.isNull());
+ ui->regMarksGroup->setChecked(!bounding.isNull());
+ ui->regWidthSpinner->setValue(bounding.width());
+ ui->regHeightSpinner->setValue(bounding.height());
+}
+
bool CutDialog::regMark() const
{
return ui->regMarksGroup->isChecked();
diff --git a/CutDialog.h b/CutDialog.h
index 8ac5a41d..86d2a70b 100644
--- a/CutDialog.h
+++ b/CutDialog.h
@@ -36,6 +36,8 @@ class CutDialog : public QDialog
double regWidth() const;
double regHeight() const;
+ void setRegMarks(QRectF bounding) const;
+
protected:
void changeEvent(QEvent* e) override;
diff --git a/CutDialog.ui b/CutDialog.ui
index 196b620e..10c81e26 100644
--- a/CutDialog.ui
+++ b/CutDialog.ui
@@ -403,7 +403,7 @@
300.000000000000000
- 180.000000000000000
+ 190.000000000000000
@@ -435,7 +435,7 @@
1000.000000000000000
- 240.000000000000000
+ 275.000000000000000
diff --git a/CuttingThread.h b/CuttingThread.h
index a3c6af5d..47334c83 100644
--- a/CuttingThread.h
+++ b/CuttingThread.h
@@ -26,6 +26,8 @@ struct CutParams
bool regsearch = false;
double regwidth = 0.0;
double regheight = 0.0;
+ double regstroke = 0.0;
+ QPointF regoffset = QPointF(0.0,0.0);
};
class CuttingThread : public QThread
diff --git a/MainWindow.cpp b/MainWindow.cpp
index d7701229..82e8fa42 100644
--- a/MainWindow.cpp
+++ b/MainWindow.cpp
@@ -244,20 +244,12 @@ void MainWindow::loadFile(QString filename)
QSizeF mediaSize(render.widthMm, render.heightMm);
loadedState.mediaSize = mediaSize;
- loadedState.paths = std::move(render.paths);
+ loadedState.showpaths = std::move(render.showpaths);
+ loadedState.cutpaths = std::move(render.cutpaths);
loadedState.filename = filename;
-
- // Transform the paths from user units to mm.
- for (auto& path : loadedState.paths)
- {
- for (auto& vertex : path)
- {
- vertex = QPointF(
- (vertex.x() - render.viewBox.x()) * render.widthMm / render.viewBox.width(),
- (vertex.y() - render.viewBox.y()) * render.heightMm / render.viewBox.height());
- }
- }
-
+ loadedState.markPosition = render.markPosition;
+ loadedState.markOffset = render.markOffset;
+ loadedState.markStroke = render.markStroke;
QPointF startingPoint(0.0, 0.0);
// Sort the paths with the following goals:
@@ -267,7 +259,8 @@ void MainWindow::loadFile(QString filename)
// 3. Try not to travel too much in the Y direction (it can lead to accumulation of
// errors due to the vinyl slipping in the rollers).
//
- loadedState.sortedPaths = sortPaths(loadedState.paths, sortMethod, startingPoint);
+ loadedState.sortedCutPaths = sortPaths(loadedState.cutpaths, sortMethod, startingPoint);
+ loadedState.sortedShowPaths = loadedState.showpaths;
// Set the default zoom.
auto viewSize = ui->centralWidget->size();
@@ -279,7 +272,7 @@ void MainWindow::loadFile(QString filename)
// Clear the scene.
clearScene();
- QRectF pageRect(0.0, 0.0, mediaSize.width(), mediaSize.height());
+ QRectF pageRect(0.0, 0.0, mediaSize.width()*96/90, mediaSize.height()*96/90);
// And reset the sceneRect, which it doesn't do by default.
scene->setSceneRect(pageRect.adjusted(-20, -20, 20, 20));
@@ -293,7 +286,7 @@ void MainWindow::loadFile(QString filename)
dimensionsItem = scene->addText(
QString::number(mediaSize.width()) + " × " + QString::number(mediaSize.height()) + " mm",
QFont("Helvetica", 10));
- dimensionsItem->setPos(0.0, mediaSize.height());
+ dimensionsItem->setPos(0.0, mediaSize.height()*96/90);
dimensionsItem->setVisible(dimensionsEnabled);
// Add the rulers.
@@ -307,22 +300,12 @@ void MainWindow::loadFile(QString filename)
QList gridSquares;
- // Add the centimetre grid.
- for (int x = 0; x < mediaSize.width() / 10; ++x)
- {
- for (int y = x % 2; y < mediaSize.height() / 10; y += 2)
- {
- int w = static_cast(std::min(10.0, mediaSize.width() - x * 10.0));
- int h = static_cast(std::min(10.0, mediaSize.height() - y * 10.0));
- gridSquares.append(scene->addRect(
- x * 10,
- mediaSize.height() - y * 10 - h,
- w,
- h,
- Qt::NoPen,
- QBrush(QColor::fromRgb(240, 240, 240))));
- }
- }
+ QPen mmPen = QPen(QBrush(QColor::fromRgb(240, 240, 240)), 0.0);
+ QPen cmPen = QPen(QBrush(QColor::fromRgb(200, 200, 200)), 0.0);
+ for (int x=0; x<=mediaSize.width()*96/90; x++)
+ gridSquares.append(scene->addLine(x,0,x,mediaSize.height()*96/90, (x%10==0)?cmPen:mmPen));
+ for (int y=0; y<=mediaSize.height()*96/90; y++)
+ gridSquares.append(scene->addLine(0,y,mediaSize.width()*96/90,y, (y%10==0)?cmPen:mmPen));
gridItem = scene->createItemGroup(gridSquares);
gridItem->setVisible(gridEnabled);
@@ -396,6 +379,9 @@ void MainWindow::on_actionCut_triggered()
if (!cutDialog)
cutDialog = new CutDialog(this);
+ if (!s->markPosition.isNull()) std::cout << "Found regmarks in SVG!" << std::endl;
+ cutDialog->setRegMarks(s->markPosition);
+
if (cutDialog->exec() != QDialog::Accepted)
return;
@@ -404,7 +390,7 @@ void MainWindow::on_actionCut_triggered()
CuttingDialog* cuttingDlg = new CuttingDialog(this);
CutParams params;
- params.cuts = s->sortedPaths;
+ params.cuts = s->sortedCutPaths;
params.mediawidth = s->mediaSize.width();
params.mediaheight = s->mediaSize.height();
params.media = cutDialog->media();
@@ -412,7 +398,9 @@ void MainWindow::on_actionCut_triggered()
params.regwidth = cutDialog->regWidth();
params.regheight = cutDialog->regHeight();
params.regmark = cutDialog->regMark();
+ params.regoffset = s->markOffset;
params.regsearch = cutDialog->regSearch();
+ params.regstroke = s->markStroke;
params.speed = cutDialog->speed();
params.trackenhancing = cutDialog->trackEnhancing();
@@ -495,7 +483,7 @@ void MainWindow::animate()
auto& m = s->cutMarkerPos;
// Make sure the current position is sane.
- if (m.poly >= s->sortedPaths.size() * 2 + 1)
+ if (m.poly >= s->sortedCutPaths.size() * 2 + 1)
{
// If not, reset it.
m.poly = 0;
@@ -522,20 +510,20 @@ void MainWindow::animate()
if (m.poly == 0)
a = startingPoint;
else
- a = s->sortedPaths[(m.poly / 2) - 1].back();
+ a = s->sortedCutPaths[(m.poly / 2) - 1].back();
- if (m.poly >= s->sortedPaths.size() * 2)
+ if (m.poly >= s->sortedCutPaths.size() * 2)
b = startingPoint;
else
- b = s->sortedPaths[(m.poly / 2)].front();
+ b = s->sortedCutPaths[(m.poly / 2)].front();
cutMarker->setOpacity(0.2);
}
else
{
auto pathIndex = (m.poly - 1) / 2;
- a = s->sortedPaths[pathIndex][m.line];
- b = s->sortedPaths[pathIndex][m.line + 1];
+ a = s->sortedCutPaths[pathIndex][m.line];
+ b = s->sortedCutPaths[pathIndex][m.line + 1];
cutMarker->setOpacity(1.0);
}
@@ -546,13 +534,13 @@ void MainWindow::animate()
{
distanceRemaining -= (ln.length() - m.distance);
m.distance = 0.0;
- if (m.poly % 2 != 0 && m.line < s->sortedPaths[(m.poly - 1) / 2].size() - 2)
+ if (m.poly % 2 != 0 && m.line < s->sortedCutPaths[(m.poly - 1) / 2].size() - 2)
{
++m.line;
}
else
{
- m.poly = (m.poly + 1) % (s->sortedPaths.size() * 2 + 1);
+ m.poly = (m.poly + 1) % (s->sortedCutPaths.size() * 2 + 1);
m.line = 0;
}
continue;
@@ -633,7 +621,7 @@ void MainWindow::addPathItemsToScene()
QList pathLines;
- for (const auto& path : s->sortedPaths)
+ for (const auto& path : s->sortedShowPaths)
{
QPen pen(QColor::fromHsvF(static_cast(hue), 1.0f, 0.7f));
@@ -664,7 +652,7 @@ void MainWindow::addPathItemsToScene()
// Don't change the pen width with zoom.
pen.setCosmetic(true);
pen.setWidthF(3.0);
- for (const auto& path : s->sortedPaths)
+ for (const auto& path : s->sortedShowPaths)
{
cutterPathLines.append(scene->addLine(QLineF(currentPoint, path.first()), pen));
currentPoint = path.last();
@@ -752,7 +740,7 @@ void MainWindow::onSortMethodTriggered(QAction* action)
// Resort the paths.
QPointF startingPoint(0.0, 0.0);
- s->sortedPaths = sortPaths(s->paths, sortMethod, startingPoint);
+ s->sortedCutPaths = sortPaths(s->cutpaths, sortMethod, startingPoint);
// Remove the path items and re-add them.
addPathItemsToScene();
@@ -893,7 +881,7 @@ void MainWindow::on_actionExport_HPGL_triggered()
if (filename.isEmpty())
return;
- auto hpgl = renderToHPGL2(s->sortedPaths, s->mediaSize.width(), s->mediaSize.height());
+ auto hpgl = renderToHPGL2(s->sortedShowPaths, s->mediaSize.width(), s->mediaSize.height());
QSaveFile file(filename);
if (!file.open(QIODevice::WriteOnly))
diff --git a/MainWindow.h b/MainWindow.h
index 5b2e5087..4ba5b95f 100644
--- a/MainWindow.h
+++ b/MainWindow.h
@@ -48,17 +48,23 @@ struct StateFileLoaded
// Filename it was loaded from.
QString filename;
// The polygons to cut, in mm.
- QList paths;
+ QList cutpaths;
+ QList showpaths;
// The page size in mm.
QSizeF mediaSize;
// The default zoom for this document, which is based on its size.
double defaultZoom = 1.0;
// The sorted paths.
- QList sortedPaths;
+ QList sortedCutPaths;
+ QList sortedShowPaths;
// Position of the cut marker for the animate feature.
CutMarkerPos cutMarkerPos;
+
+ QRectF markPosition;
+ QPointF markOffset;
+ double markStroke;
};
class MainWindow : public QMainWindow
diff --git a/Plotter.cpp b/Plotter.cpp
index ed6983b7..0d23d85f 100644
--- a/Plotter.cpp
+++ b/Plotter.cpp
@@ -8,9 +8,13 @@
#include
#include
+#include
+
namespace
{
+int noPressure = 0;
+
std::string UsbError(int e)
{
switch (e)
@@ -154,6 +158,11 @@ SResult UsbOpen()
if (PRODUCT_ID_LIST.count(desc.idProduct) == 0)
continue;
+ if (desc.idProduct == 0x110a) {
+ std::cout<< "CC200-20 detected - Pressure set to maximum\n";
+ noPressure = 1;
+ } else noPressure = 0;
+
libusb_device_handle* handle = nullptr;
// Currently use the first device found.
@@ -311,6 +320,9 @@ SResult<> Cut(CutParams p)
if (!handleRes)
return handleRes;
+ if (noPressure != 0)
+ p.pressure = 33;
+
auto handle = std::move(handleRes.unwrap());
// TODO: Renable this.
@@ -362,7 +374,7 @@ SResult<> Cut(CutParams p)
return Err(std::string("Moving, please try again."));
if (resp == "2\x03")
return Err(std::string("Empty tray, please load media.")); // Silhouette Cameo
- return Err("Unexpected response from plotter: '" + resp + "' (" + string_to_hex(resp) + ")");
+ return Err("1 Unexpected response from plotter: '" + resp + "' (" + string_to_hex(resp) + ") instead "+ string_to_hex("1\x03"));
}
// Home the cutter.
@@ -406,11 +418,6 @@ SResult<> Cut(CutParams p)
if (!e)
return e;
- // Set to portrait. FN1 does landscape but it's easier just to rotate the image.
- e = UsbSend(handle, "FN0\x03");
- if (!e)
- return e;
-
e = UsbSend(handle, "FE0\x03"); // No idea what this does.
if (!e)
return e;
@@ -425,14 +432,19 @@ SResult<> Cut(CutParams p)
resp = sr.unwrap();
- if (resp != " 0, 0\x03")
- return Err("Unexpected response from plotter: '" + resp + "' (" + string_to_hex(resp) + ")");
+ if (resp != " 1, 0\x03")
+ return Err("2 Unexpected response from plotter: '" + resp + "' (" + string_to_hex(resp) + ") instead "+ string_to_hex(" 0, 0\x03"));
// Begin page definition.
e = UsbSend(handle, "FA\x03");
if (!e)
return e;
+ // Set to portrait. FN1 does landscape but it's easier just to rotate the image.
+ e = UsbSend(handle, "FN0\x03");
+ if (!e)
+ return e;
+
// Page size: height,width in 20ths of a mm minus a margin. This is for A4. TODO: Find maximum and use that.
std::stringstream page;
@@ -449,13 +461,21 @@ SResult<> Cut(CutParams p)
if (!e)
return e;
+ //flushing USB for clean pipe state
+ while (UsbReceive(handle, 500));
+
if (p.regmark)
{
+ //Get current position
std::stringstream regmarkstr;
regmarkstr.precision(0);
std::string searchregchar = "23,";
int regw = static_cast(lround(p.regwidth * 20.0));
int regl = static_cast(lround(p.regheight * 20.0));
+
+ //flushing USB for clean pipe state
+ while (UsbReceive(handle, 500));
+
e = UsbSend(handle, "TB50,381\x03"); // only with registration (it was TB50,1) ???
if (!e)
return e;
@@ -478,35 +498,23 @@ SResult<> Cut(CutParams p)
sr = UsbReceive(handle, 40000); // Allow 40s for reply...
if (!sr)
return sr;
-
- resp = sr.unwrap();
- if (resp != " 0, 0\x03")
- {
- std::cout << resp << "\n";
- return Err(std::string("Couldn't find registration marks."));
- }
- // Looks like if the reg marks work it gets 3 messages back (if it fails it times out because it only gets the
- // first message)
- sr = UsbReceive(handle, 40000); // Allow 40s for reply...
- if (!sr)
- return sr;
-
resp = sr.unwrap();
if (resp != " 0\x03")
{
std::cout << resp << "\n";
- return Err(std::string("Couldn't find registration marks."));
+ e = UsbSend(handle, "TT");
+ return Err(std::string("Couldn't find registration marks - Back to Home."));
}
sr = UsbReceive(handle, 40000); // Allow 40s for reply...
if (!sr)
return sr;
-
resp = sr.unwrap();
if (resp != " 1\x03")
{
std::cout << resp << "\n";
- return Err(std::string("Couldn't find registration marks."));
+ e = UsbSend(handle, "TT");
+ return Err(std::string("Couldn't find registration marks - Back to Home."));
}
}
else
@@ -526,53 +534,40 @@ SResult<> Cut(CutParams p)
// Set the "factor" to 100,100,100, whatever that means.
// \0,0 is "write lower left". Z is "write upper right", so I think this sets the bounds in some way.
page << "&100,100,100,\\0,0,Z" << ItoS(width) << "," << ItoS(height) << ",L0";
+
for (const auto& cut : p.cuts)
{
if (cut.size() < 2)
continue;
-
for (int i = 0; i < cut.size(); ++i)
{
- double x = cut[i].x() * 20.0;
- double y = cut[i].y() * 20.0;
-
+ std::cout<<"cut " << p.regoffset.x() - cut[i].x() << "," << cut[i].y()-p.regoffset.y() << std::endl;
+ double x = (p.regoffset.x() - cut[i].x()) * 20.0;
+ double y = (cut[i].y()-p.regoffset.y()) * 20.0;
// double xorigin = 0;//ProgramOptions::Instance().getRegOriginWidthMM();
// double yorigin = 0;//ProgramOptions::Instance().getRegOriginHeightMM();
- // if (p.regmark)
- // {
- // x -= (xorigin * 20.0);
- // y -= (yorigin * 20.0);
- // }
-
// Squash to page boundaries.
x = std::min(std::max(x, 0.0), double(width));
y = std::min(std::max(y, 0.0), double(height));
- // Mirror x/y.
- x = width - x;
-
page << (i == 0 ? ",M" : ",D") << x << "," << y;
}
}
// &1,1,1 is "Factor". TB50,0 is something to do with registration.
// I suspect this command resets some settings at the end.
- page << "&1,1,1,TB50,0\x03";
+ // set the regmarks stroke based on svg extract
+ page << "&1,1,1,TB50,0\x03TB53,"<< static_cast(lround(p.regstroke * 20.0)) <<"\0x3";
// std::cout << page.str() << "\n";
-
e = UsbSend(handle, page.str());
if (!e)
return e;
- // Feed the page out.
- e = UsbSend(handle, "FO0\x03");
- if (!e)
- return e;
-
// Home.
- e = UsbSend(handle, "H,");
+ std::cout<<"Back to origin"<
#include
#include
+#include
+#include
+
+#include
+
+#include
#include "PathPaintDevice.h"
@@ -89,6 +95,9 @@ struct SvgXmlData
{
QString widthAttribute;
QString heightAttribute;
+ QString cutElementId = QString();
+ QString markElementId = QString();
+ double markStroke;
bool hasTspanPosition = false;
@@ -136,7 +145,24 @@ SvgXmlData scanSvgElements(const QByteArray& svgContents, bool searchForTspans)
return data;
}
}
-
+ else if ((xml.name() == u"g") && attr.hasAttribute("id") && attr.value("inkscape:label").contains(QString("cut"),Qt::CaseInsensitive))
+ {
+ data.cutElementId = attr.value("id").toString();
+ }
+ else if ((xml.name() == u"g") && attr.hasAttribute("id") && attr.value("inkscape:label").contains(QString("regmarks"),Qt::CaseInsensitive))
+ {
+ data.markElementId = attr.value("id").toString();
+ }
+ else if ((xml.name() == u"path") && attr.hasAttribute("style") && attr.value("inkscape:label").contains(QString("RightMarkH"),Qt::CaseInsensitive))
+ {
+ std::cout<< "found mark" << std::endl;
+ auto style = attr.value("style").toString();
+ QRegularExpression re("stroke-width:(\\d+(\\.\\d+)?)");
+ QRegularExpressionMatch match = re.match(style);
+ if (match.hasMatch()) {
+ data.markStroke = match.captured(1).toDouble();
+ }
+ }
break;
}
default:
@@ -180,6 +206,9 @@ SResult svgToPaths(const QString& filename, bool searchForTspans)
render.widthAttribute = xmlData.widthAttribute;
render.heightAttribute = xmlData.heightAttribute;
render.hasTspanPosition = xmlData.hasTspanPosition;
+ render.cutElementId = xmlData.cutElementId;
+ render.markElementId = xmlData.markElementId;
+ render.markStroke = xmlData.markStroke;
QSvgRenderer renderer;
if (!renderer.load(svgContents))
@@ -187,22 +216,85 @@ SResult svgToPaths(const QString& filename, bool searchForTspans)
render.viewBox = renderer.viewBoxF();
- // Give the size of the canvas. We just use 1 user unit per pixel and
- // then convert later.
PathPaintDevice pg(render.viewBox.width(), render.viewBox.height());
QPainter p(&pg);
- // Render, this will assume 1 user unit = 1px.
- renderer.render(&p, render.viewBox);
+ if (!render.markElementId.isEmpty()) {
+ double x0,y0,x1,y1;
+ PathPaintDevice pgmark(render.viewBox.width(), render.viewBox.height());
+ QPainter pmark(&pgmark);
+ QRectF bound1 = renderer.boundsOnElement(render.markElementId);
+ QTransform transf = renderer.transformForElement(render.markElementId);
+ render.markPosition = transf.mapRect(bound1);
+ renderer.render(&pmark, render.markElementId, render.markPosition);
+ render.markPosition.getCoords(&x0, &y0, &x1, &y1);
+ render.markPosition.setCoords(x0* MM_PER_PX, y0* MM_PER_PX, x1* MM_PER_PX, y1* MM_PER_PX);
+ bool start = true;
+ for ( auto polygon : pgmark.paths() ) {
+ for ( QPointF point : polygon ) {
+ if (start) {
+ render.markOffset = point;
+ start = false;
+ } else {
+ if ((point.x() >= render.markOffset.x()) && (point.y() <= render.markOffset.y()))
+ render.markOffset = point;
+ }
+ }
+ }
+ render.markOffset = QPointF(
+ (render.markOffset.x()+(render.markStroke/2.0)) * MM_PER_PX,
+ (render.markOffset.y()+(render.markStroke/2.0)) * MM_PER_PX);
+ std::cout<<"markOffset " < paths;
+ QList showpaths;
+ QList cutpaths;
// The view box (the visible portal of the SVG) in user units.
QRectF viewBox;
@@ -21,6 +22,15 @@ struct SvgRender
QString widthAttribute;
QString heightAttribute;
+ //The Cut Layer only
+ QString cutElementId = QString();
+
+ //The Registration marks layer only
+ QString markElementId = QString();
+ QRectF markPosition = QRectF();
+ QPointF markOffset;
+ double markStroke;
+
// The width and height in mm if they have been specified. This is calculated
// from the width= and height= attributes, if they have physical units. If they
// are in user units then it is assumed to be mm. If they are in % or are not present
diff --git a/examples/Registration marks A4 portrait.svg b/examples/Registration marks A4 portrait.svg
new file mode 100644
index 00000000..737e503f
--- /dev/null
+++ b/examples/Registration marks A4 portrait.svg
@@ -0,0 +1,285 @@
+
+