Clifford Wolf:

Improved DXF support



git-svn-id: http://svn.clifford.at/openscad/trunk@61 b57f626f-c46c-0410-a088-ec61d464b74c
stl_dim
clifford 2009-07-20 17:45:39 +00:00
parent 4c03dac385
commit bd89f254ef
7 changed files with 145 additions and 26 deletions

View File

@ -60,7 +60,7 @@ void Context::set_variable(QString name, Value value)
variables[name] = value;
}
Value Context::lookup_variable(QString name) const
Value Context::lookup_variable(QString name, bool silent) const
{
if (name.startsWith("$")) {
for (int i = ctx_stack.size()-1; i >= 0; i--) {
@ -73,7 +73,8 @@ Value Context::lookup_variable(QString name) const
return variables[name];
if (parent)
return parent->lookup_variable(name);
PRINTA("WARNING: Ignoring unkown variable '%1'.", name);
if (!silent)
PRINTA("WARNING: Ignoring unkown variable '%1'.", name);
return Value();
}

View File

@ -22,7 +22,7 @@
#include <QFile>
DxfData::DxfData(double /* fn */, double /* fs */, double /* fa */, QString filename, QString layername)
DxfData::DxfData(double fn, double fs, double fa, QString filename, QString layername, double xorigin, double yorigin, double scale)
{
QFile f(filename);
@ -38,6 +38,9 @@ DxfData::DxfData(double /* fn */, double /* fs */, double /* fa */, QString file
QString mode, layer;
double x1 = 0, x2 = 0, y1 = 0, y2 = 0;
double radius = 0, start_angle = 0, stop_angle = 0;
bool in_entities_section = false;
QHash<QString, int> unsupported_entities_list;
while (!f.atEnd())
{
@ -56,26 +59,72 @@ DxfData::DxfData(double /* fn */, double /* fs */, double /* fa */, QString file
if (mode == "LINE" && (layername.isNull() || layername == layer)) {
lines.append(Line(p(x1, y1), p(x2, y2)));
}
if (mode == "CIRCLE" && (layername.isNull() || layername == layer)) {
int n = get_fragments_from_r(radius, fn, fs, fa);
for (int i = 0; i < n; i++) {
double a1 = (2*M_PI*i)/n;
double a2 = (2*M_PI*(i+1))/n;
lines.append(Line(p(cos(a1)*radius + x1, sin(a1)*radius + y1),
p(cos(a2)*radius + x1, sin(a2)*radius + y1)));
}
}
if (mode == "ARC" && (layername.isNull() || layername == layer)) {
int n = get_fragments_from_r(radius, fn, fs, fa);
while (start_angle > stop_angle)
stop_angle += 360.0;
n = ceil(n * 360 / (stop_angle-start_angle));
for (int i = 0; i < n; i++) {
double a1 = ((stop_angle-start_angle)*i)/n;
double a2 = ((stop_angle-start_angle)*(i+1))/n;
a1 = (start_angle + a1) * M_PI / 180.0;
a2 = (start_angle + a2) * M_PI / 180.0;
lines.append(Line(p(cos(a1)*radius + x1, sin(a1)*radius + y1),
p(cos(a2)*radius + x1, sin(a2)*radius + y1)));
}
}
if (in_entities_section) {
if (data != "SECTION" && data != "ENDSEC" &&
data != "LINE" && data != "ARC" && data != "CIRCLE")
unsupported_entities_list[data]++;
}
mode = data;
break;
case 2:
in_entities_section = data == "ENTITIES";
case 8:
layer = data;
break;
case 10:
x1 = data.toDouble();
x1 = (data.toDouble() - xorigin) * scale;
break;
case 11:
x2 = data.toDouble();
x2 = (data.toDouble() - xorigin) * scale;
break;
case 20:
y1 = data.toDouble();
y1 = (data.toDouble() - yorigin) * scale;
break;
case 21:
y2 = data.toDouble();
y2 = (data.toDouble() - yorigin) * scale;
break;
case 40:
radius = data.toDouble() * scale;
break;
case 50:
start_angle = data.toDouble();
break;
case 51:
stop_angle = data.toDouble();
break;
}
}
QHashIterator<QString, int> i(unsupported_entities_list);
while (i.hasNext()) {
i.next();
PRINTA("WARNING: Unsupported DXF Entity `%1' (%2x) in `%3'.",
i.key(), QString::number(i.value()), filename);
}
// extract all open paths
while (lines.count() > 0)
{
@ -84,6 +133,8 @@ DxfData::DxfData(double /* fn */, double /* fs */, double /* fa */, QString file
for (int i = 0; i < lines.count(); i++) {
for (int j = 0; j < 2; j++) {
for (int k = 0; k < lines.count(); k++) {
if (i == k)
continue;
if (lines[i].p[j] == lines[k].p[0])
goto next_open_path_j;
if (lines[i].p[j] == lines[k].p[1])
@ -174,7 +225,7 @@ DxfData::DxfData(double /* fn */, double /* fs */, double /* fa */, QString file
min_x_point = j;
}
}
// rotate points if the path is not in non-standard rotation
// rotate points if the path is in non-standard rotation
int b = min_x_point;
int a = b == 0 ? paths[i].points.count() - 2 : b - 1;
int c = b == paths[i].points.count() - 1 ? 1 : b + 1;

View File

@ -34,8 +34,15 @@ class DxfLinearExtrudeNode : public AbstractPolyNode
public:
int convexity;
double fn, fs, fa, height;
double origin_x, origin_y, scale;
bool center;
QString filename, layername;
DxfLinearExtrudeNode(const ModuleInstanciation *mi) : AbstractPolyNode(mi) { }
DxfLinearExtrudeNode(const ModuleInstanciation *mi) : AbstractPolyNode(mi) {
convexity = 0;
fn = fs = fa = height = 0;
origin_x = origin_y = scale = 0;
center = false;
}
virtual PolySet *render_polyset(render_mode_e mode) const;
virtual QString dump(QString indent) const;
};
@ -44,7 +51,7 @@ AbstractNode *DxfLinearExtrudeModule::evaluate(const Context *ctx, const ModuleI
{
DxfLinearExtrudeNode *node = new DxfLinearExtrudeNode(inst);
QVector<QString> argnames = QVector<QString>() << "file" << "layer" << "height";
QVector<QString> argnames = QVector<QString>() << "file" << "layer" << "height" << "origin" << "scale" << "center";
QVector<Expression*> argexpr;
Context c(ctx);
@ -55,14 +62,22 @@ AbstractNode *DxfLinearExtrudeModule::evaluate(const Context *ctx, const ModuleI
node->fa = c.lookup_variable("$fa").num;
Value file = c.lookup_variable("file");
Value layer = c.lookup_variable("layer");
Value height = c.lookup_variable("height");
Value convexity = c.lookup_variable("convexity");
Value layer = c.lookup_variable("layer", true);
Value height = c.lookup_variable("height", true);
Value convexity = c.lookup_variable("convexity", true);
Value origin = c.lookup_variable("origin", true);
Value scale = c.lookup_variable("scale", true);
Value center = c.lookup_variable("center", true);
node->filename = file.text;
node->layername = layer.text;
node->height = height.num;
node->convexity = convexity.num;
origin.getv2(node->origin_x, node->origin_y);
node->scale = scale.num;
if (center.type == Value::BOOL)
node->center = center.b;
if (node->height <= 0)
node->height = 100;
@ -70,6 +85,9 @@ AbstractNode *DxfLinearExtrudeModule::evaluate(const Context *ctx, const ModuleI
if (node->convexity <= 0)
node->convexity = 1;
if (node->scale <= 0)
node->scale = 1;
return node;
}
@ -319,20 +337,30 @@ static void tess(PolySet *ps, DxfData *dxf, bool up, double h)
PolySet *DxfLinearExtrudeNode::render_polyset(render_mode_e) const
{
DxfData dxf(fn, fs, fa, filename, layername);
DxfData dxf(fn, fs, fa, filename, layername, origin_x, origin_y, scale);
PolySet *ps = new PolySet();
ps->convexity = convexity;
double h1, h2;
if (center) {
h1 = -height/2.0;
h2 = -height/2.0;
} else {
h1 = 0;
h2 = height;
}
for (int i = 0; i < dxf.paths.count(); i++)
{
if (!dxf.paths[i].is_closed)
continue;
add_slice(ps, &dxf.paths[i], 0, height);
add_slice(ps, &dxf.paths[i], h1, h2);
}
tess(ps, &dxf, false, 0);
tess(ps, &dxf, true, height);
tess(ps, &dxf, false, h1);
tess(ps, &dxf, true, h2);
return ps;
}
@ -342,9 +370,10 @@ QString DxfLinearExtrudeNode::dump(QString indent) const
if (dump_cache.isEmpty()) {
QString text;
text.sprintf("dxf_linear_extrude(file = \"%s\", layer = \"%s\", height = %f, "
"origin = [ %f %f ], scale = %f, "
"$fn = %f, $fa = %f, $fs = %f);\n",
filename.toAscii().data(), layername.toAscii().data(),
height, fn, fs, fa);
height, origin_x, origin_y, scale, fn, fs, fa);
((AbstractNode*)this)->dump_cache = indent + QString("n%1: ").arg(idx) + text;
}
return dump_cache;

View File

@ -34,8 +34,13 @@ class DxfRotateExtrudeNode : public AbstractPolyNode
public:
int convexity;
double fn, fs, fa;
double origin_x, origin_y, scale;
QString filename, layername;
DxfRotateExtrudeNode(const ModuleInstanciation *mi) : AbstractPolyNode(mi) { }
DxfRotateExtrudeNode(const ModuleInstanciation *mi) : AbstractPolyNode(mi) {
convexity = 0;
fn = fs = fa = 0;
origin_x = origin_y = scale = 0;
}
virtual PolySet *render_polyset(render_mode_e mode) const;
virtual QString dump(QString indent) const;
};
@ -44,7 +49,7 @@ AbstractNode *DxfRotateExtrudeModule::evaluate(const Context *ctx, const ModuleI
{
DxfRotateExtrudeNode *node = new DxfRotateExtrudeNode(inst);
QVector<QString> argnames = QVector<QString>() << "file" << "layer";
QVector<QString> argnames = QVector<QString>() << "file" << "layer" << "origin" << "scale";
QVector<Expression*> argexpr;
Context c(ctx);
@ -55,16 +60,23 @@ AbstractNode *DxfRotateExtrudeModule::evaluate(const Context *ctx, const ModuleI
node->fa = c.lookup_variable("$fa").num;
Value file = c.lookup_variable("file");
Value layer = c.lookup_variable("layer");
Value convexity = c.lookup_variable("convexity");
Value layer = c.lookup_variable("layer", true);
Value convexity = c.lookup_variable("convexity", true);
Value origin = c.lookup_variable("origin", true);
Value scale = c.lookup_variable("scale", true);
node->filename = file.text;
node->layername = layer.text;
node->convexity = convexity.num;
origin.getv2(node->origin_x, node->origin_y);
node->scale = scale.num;
if (node->convexity <= 0)
node->convexity = 1;
if (node->scale <= 0)
node->scale = 1;
return node;
}
@ -75,7 +87,7 @@ void register_builtin_dxf_rotate_extrude()
PolySet *DxfRotateExtrudeNode::render_polyset(render_mode_e) const
{
DxfData dxf(fn, fs, fa, filename, layername);
DxfData dxf(fn, fs, fa, filename, layername, origin_x, origin_y, scale);
PolySet *ps = new PolySet();
ps->convexity = convexity;
@ -143,8 +155,10 @@ QString DxfRotateExtrudeNode::dump(QString indent) const
if (dump_cache.isEmpty()) {
QString text;
text.sprintf("dxf_rotate_extrude(file = \"%s\", layer = \"%s\", "
"origin = [ %f %f ], scale = %f, "
"$fn = %f, $fa = %f, $fs = %f);\n",
filename.toAscii().data(), layername.toAscii().data(),fn, fs, fa);
filename.toAscii().data(), layername.toAscii().data(),
origin_x, origin_y, scale, fn, fs, fa);
((AbstractNode*)this)->dump_cache = indent + QString("n%1: ").arg(idx) + text;
}
return dump_cache;

View File

@ -124,6 +124,7 @@ public:
Value inv() const;
bool getnum(double &v) const;
bool getv2(double &x, double &y) const;
bool getv3(double &x, double &y, double &z) const;
QString dump() const;
@ -284,7 +285,7 @@ public:
void args(const QVector<QString> &argnames, const QVector<Expression*> &argexpr, const QVector<QString> &call_argnames, const QVector<Value> &call_argvalues);
void set_variable(QString name, Value value);
Value lookup_variable(QString name) const;
Value lookup_variable(QString name, bool silent = false) const;
Value evaluate_function(QString name, const QVector<QString> &argnames, const QVector<Value> &argvalues) const;
AbstractNode *evaluate_module(const ModuleInstanciation *inst) const;
@ -312,7 +313,7 @@ public:
QList<Point> points;
QList<Path> paths;
DxfData(double fn, double fs, double fa, QString filename, QString layername = QString());
DxfData(double fn, double fs, double fa, QString filename, QString layername = QString(), double xorigin = 0.0, double yorigin = 0.0, double scale = 1.0);
Point *p(double x, double y);
};

View File

@ -23,3 +23,6 @@ QMAKE_CXXFLAGS += -O0
QT += opengl
target.path = /usr/local/bin/
INSTALLS += target

View File

@ -255,8 +255,28 @@ bool Value::getnum(double &v) const
return true;
}
bool Value::getv2(double &x, double &y) const
{
if (type != VECTOR || vec.size() != 2)
return false;
if (vec[0]->type != NUMBER)
return false;
if (vec[1]->type != NUMBER)
return false;
x = vec[0]->num;
y = vec[1]->num;
return true;
}
bool Value::getv3(double &x, double &y, double &z) const
{
if (type == VECTOR && vec.size() == 2) {
if (getv2(x, y)) {
z = 0;
return true;
}
return false;
}
if (type != VECTOR || vec.size() != 3)
return false;
if (vec[0]->type != NUMBER)