Skip to content

Instantly share code, notes, and snippets.

@lhartmann
Last active February 12, 2021 13:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save lhartmann/9834f4554d32b2fdd52613e27c319a0e to your computer and use it in GitHub Desktop.
Save lhartmann/9834f4554d32b2fdd52613e27c319a0e to your computer and use it in GitHub Desktop.
Simple HPGL parser with GCODE output
// (c) 2020 Lucas V. Hartmann, github.com/lhartmann
// MIT license.
// Use:
// hpgl2gcode --scale=1 --up=1 --down=0 < in.hpgl > out.gcode
// --scale=1 Sets how many HPGL units for 1 GCODE unit.
// --up=1 Sets Z for pen-up.
// --down=0 Sets Z for pen down.
// Values shown are defaults.
//
// GCODE output is partial:
// - absolute moves only.
// - Dimensions (inches/mm) are NOT set.
#include <iostream>
#include <iomanip>
#include <deque>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <iterator>
#include <stdint.h>
using namespace std;
struct hpglParser {
struct point_t {
int32_t x, y;
bool operator==(const point_t &other) const {
return x == other.x && y == other.y;
}
};
typedef deque<point_t> poly_t;
typedef deque<poly_t> set_t;
set_t polygons;
string s;
bool penDown{false};
point_t pos{0,0};
void feed(char ch) {
if (ch != ';') {
if (isalnum(ch) || ch == ',') {
s += ch;
}
return;
}
if (s == "PU")
penDown = false;
else if (s == "PD")
penDown = true;
else if (string(s,0,2) == "PA") {
auto a = s.begin()+2;
auto b = find(a, s.end(), ',');
auto c = find(b, s.end(), ',');
poly_t P;
P.push_back(pos);
while (true) {
auto b = find(a, s.end(), ',');
if (b == s.end())
break;
auto c = find(b+1, s.end(), ',');
pos.x = atoi(string(a, b).c_str());
pos.y = atoi(string(b+1, c).c_str());
P.push_back(pos);
a = c+1;
}
if (P.size() && penDown) {
// Look for coincident start/stop points
bool found = false;
for (auto &other : polygons) {
if (P.front() == other.back()) {
copy(P.begin()+1, P.end(), back_inserter(other));
found = true;
break;
} else if (P.front() == other.front()) {
copy(P.begin()+1, P.end(), front_inserter(other));
found = true;
break;
} else if (P.back() == other.front()) {
copy(P.rbegin()+1, P.rend(), front_inserter(other));
found = true;
break;
} else if (P.back() == other.back()) {
copy(P.rbegin()+1, P.rend(), back_inserter(other));
found = true;
break;
}
}
if (!found) {
polygons.push_back(P);
}
}
}
s = "";
}
auto begin() { return polygons.begin(); }
auto end() { return polygons.end(); }
};
bool chkOpt(string &s, string opt) {
if (s.find(opt) != 0)
return false;
s = s.substr(opt.size());
return true;
}
int main(int argc, char *argv[]) {
double scale=1, up=1, down=0;
for (int i=1; i<argc; i++) {
string s(argv[i]);
if (chkOpt(s, "--scale=")) {
scale = stod(s);
} else if (chkOpt(s,"--up=")) {
up = stod(s);
} else if (chkOpt(s, "--down=")) {
down = stod(s);
}
}
char ch;
hpglParser parser;
while(cin.get(ch)) {
parser.feed(ch);
}
cout << "G90" << endl;
for (auto &P : parser) {
if (!P.size()) continue;
cout << "G0 Z" << up << endl;
cout << "G0 X" << P.front().x/scale << " Y" << P.front().y/scale << endl;
cout << "G1 Z" << down << endl;
for (auto &pt : P) {
cout << "G1 X" << pt.x/scale << " Y" << pt.y/scale << endl;
}
}
cout << "G0 Z" << up << endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment