summaryrefslogtreecommitdiff
path: root/dxfdata.cc
diff options
context:
space:
mode:
authorkintel <kintel@b57f626f-c46c-0410-a088-ec61d464b74c>2010-01-30 04:17:05 (GMT)
committerkintel <kintel@b57f626f-c46c-0410-a088-ec61d464b74c>2010-01-30 04:17:05 (GMT)
commit6940d171812565209efe679a5d923417c3f47d4a (patch)
tree2a05d2f8865ff1127f854db41bf31143f64ccf2d /dxfdata.cc
parent2b19f33ee1ddce246c2bfe0a05fe379d0117a741 (diff)
reorganized file structure layout. more to follow...
git-svn-id: http://svn.clifford.at/openscad/trunk@364 b57f626f-c46c-0410-a088-ec61d464b74c
Diffstat (limited to 'dxfdata.cc')
-rw-r--r--dxfdata.cc514
1 files changed, 0 insertions, 514 deletions
diff --git a/dxfdata.cc b/dxfdata.cc
deleted file mode 100644
index 864ee7b..0000000
--- a/dxfdata.cc
+++ /dev/null
@@ -1,514 +0,0 @@
-/*
- * OpenSCAD (www.openscad.at)
- * Copyright (C) 2009 Clifford Wolf <clifford@clifford.at>
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include "openscad.h"
-#include "printutils.h"
-
-#include <QFile>
-#include <QTextStream>
-
-struct Line {
- typedef DxfData::Point Point;
- Point *p[2];
- bool disabled;
- Line(Point *p1, Point *p2) { p[0] = p1; p[1] = p2; disabled = false; }
- Line() { p[0] = NULL; p[1] = NULL; disabled = false; }
-};
-
-DxfData::DxfData()
-{
-}
-
-/*!
- Reads a layer from the given file, or all layers if layename.isNull()
- */
-DxfData::DxfData(double fn, double fs, double fa, QString filename, QString layername, double xorigin, double yorigin, double scale)
-{
- handle_dep(filename); // Register ourselves as a dependency
-
- QFile f(filename);
- if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) {
- PRINTF("WARNING: Can't open DXF file `%s'.", filename.toUtf8().data());
- return;
- }
- QTextStream stream(&f);
-
- Grid2d< QVector<int> > grid(GRID_COARSE);
- QList<Line> lines; // Global lines
- QHash< QString, QList<Line> > blockdata; // Lines in blocks
-
- bool in_entities_section = false;
- bool in_blocks_section = false;
- QString current_block;
-
-#define ADD_LINE(_x1, _y1, _x2, _y2) do { \
- double _p1x = _x1, _p1y = _y1, _p2x = _x2, _p2y = _y2; \
- if (!in_entities_section && !in_blocks_section) \
- break; \
- if (in_entities_section && \
- !(layername.isNull() || layername == layer)) \
- break; \
- grid.align(_p1x, _p1y); \
- grid.align(_p2x, _p2y); \
- grid.data(_p1x, _p1y).append(lines.count()); \
- grid.data(_p2x, _p2y).append(lines.count()); \
- if (in_entities_section) \
- lines.append( \
- Line(addPoint(_p1x, _p1y), addPoint(_p2x, _p2y))); \
- if (in_blocks_section && !current_block.isNull()) \
- blockdata[current_block].append( \
- Line(addPoint(_p1x, _p1y), addPoint(_p2x, _p2y))); \
- } while (0)
-
- QString mode, layer, name, iddata;
- int dimtype = 0;
- double coords[7][2]; // Used by DIMENSION entities
- QVector<double> xverts;
- QVector<double> yverts;
- double radius = 0;
- double arc_start_angle = 0, arc_stop_angle = 0;
- double ellipse_start_angle = 0, ellipse_stop_angle = 0;
-
- for (int i = 0; i < 7; i++)
- for (int j = 0; j < 2; j++)
- coords[i][j] = 0;
-
- QHash<QString, int> unsupported_entities_list;
-
-
- //
- // Parse DXF file. Will populate this->points, this->dims, lines and blockdata
- //
- while (!stream.atEnd())
- {
- QString id_str = stream.readLine();
- QString data = stream.readLine();
-
- bool status;
- int id = id_str.toInt(&status);
-
- if (!status) {
- PRINTA("WARNING: Illegal ID `%1' in `%3'.", id_str, filename);
- break;
- }
-
- if (id >= 10 && id <= 16) {
- if (in_blocks_section)
- coords[id-10][0] = data.toDouble();
- else if (id == 11 || id == 12 || id == 16)
- coords[id-10][0] = data.toDouble() * scale;
- else
- coords[id-10][0] = (data.toDouble() - xorigin) * scale;
- }
-
- if (id >= 20 && id <= 26) {
- if (in_blocks_section)
- coords[id-20][1] = data.toDouble();
- else if (id == 21 || id == 22 || id == 26)
- coords[id-20][1] = data.toDouble() * scale;
- else
- coords[id-20][1] = (data.toDouble() - yorigin) * scale;
- }
-
- switch (id)
- {
- case 0:
- if (mode == "SECTION") {
- in_entities_section = iddata == "ENTITIES";
- in_blocks_section = iddata == "BLOCKS";
- }
- else if (mode == "LINE") {
- ADD_LINE(xverts[0], yverts[0], xverts[1], yverts[1]);
- }
- else if (mode == "LWPOLYLINE") {
- assert(xverts.size() == yverts.size());
- // polyline flag is stored in 'dimtype'
- int numverts = xverts.size();
- for (int i=1;i<numverts;i++) {
- ADD_LINE(xverts[i-1], yverts[i-1], xverts[i%numverts], yverts[i%numverts]);
- }
- if (dimtype & 0x01) { // closed polyline
- ADD_LINE(xverts[numverts-1], yverts[numverts-1], xverts[0], yverts[0]);
- }
- }
- else if (mode == "CIRCLE") {
- int n = get_fragments_from_r(radius, fn, fs, fa);
- Point center(xverts[0], yverts[0]);
- for (int i = 0; i < n; i++) {
- double a1 = (2*M_PI*i)/n;
- double a2 = (2*M_PI*(i+1))/n;
- ADD_LINE(cos(a1)*radius + center.x, sin(a1)*radius + center.y,
- cos(a2)*radius + center.x, sin(a2)*radius + center.y);
- }
- }
- else if (mode == "ARC") {
- Point center(xverts[0], yverts[0]);
- int n = get_fragments_from_r(radius, fn, fs, fa);
- while (arc_start_angle > arc_stop_angle)
- arc_stop_angle += 360.0;
- n = (int)ceil(n * (arc_stop_angle-arc_start_angle) / 360);
- for (int i = 0; i < n; i++) {
- double a1 = ((arc_stop_angle-arc_start_angle)*i)/n;
- double a2 = ((arc_stop_angle-arc_start_angle)*(i+1))/n;
- a1 = (arc_start_angle + a1) * M_PI / 180.0;
- a2 = (arc_start_angle + a2) * M_PI / 180.0;
- ADD_LINE(cos(a1)*radius + center.x, sin(a1)*radius + center.y,
- cos(a2)*radius + center.x, sin(a2)*radius + center.y);
- }
- }
- else if (mode == "ELLIPSE") {
- // Commented code is meant as documentation of vector math
- while (ellipse_start_angle > ellipse_stop_angle) ellipse_stop_angle += 2 * M_PI;
-// Vector2d center(xverts[0], yverts[0]);
- Point center(xverts[0], yverts[0]);
-// Vector2d ce(xverts[1], yverts[1]);
- Point ce(xverts[1], yverts[1]);
-// double r_major = ce.length();
- double r_major = sqrt(ce.x*ce.x + ce.y*ce.y);
-// double rot_angle = ce.angle();
- double rot_angle;
- {
-// double dot = ce.dot(Vector2d(1.0, 0.0));
- double dot = ce.x;
- double cosval = dot / r_major;
- if (cosval > 1.0) cosval = 1.0;
- if (cosval < -1.0) cosval = -1.0;
- rot_angle = acos(cosval);
- if (ce.y < 0.0) rot_angle = 2 * M_PI - rot_angle;
- }
-
- // the ratio stored in 'radius; due to the parser code not checking entity type
- double r_minor = r_major * radius;
- double sweep_angle = ellipse_stop_angle-ellipse_start_angle;
- int n = get_fragments_from_r(r_major, fn, fs, fa);
- n = (int)ceil(n * sweep_angle / (2 * M_PI));
-// Vector2d p1;
- Point p1;
- for (int i=0;i<=n;i++) {
- double a = (ellipse_start_angle + sweep_angle*i/n);
-// Vector2d p2(cos(a)*r_major, sin(a)*r_minor);
- Point p2(cos(a)*r_major, sin(a)*r_minor);
-// p2.rotate(rot_angle);
- Point p2_rot(cos(rot_angle)*p2.x - sin(rot_angle)*p2.y,
- sin(rot_angle)*p2.x + cos(rot_angle)*p2.y);
-// p2 += center;
- p2_rot.x += center.x;
- p2_rot.y += center.y;
- if (i > 0) {
-// ADD_LINE(p1[0], p1[1], p2[0], p2[1]);
- ADD_LINE(p1.x, p1.y, p2_rot.x, p2_rot.y);
- }
-// p1 = p2;
- p1.x = p2_rot.x;
- p1.y = p2_rot.y;
- }
- }
- else if (mode == "INSERT") {
- // scale is stored in ellipse_start|stop_angle, rotation in arc_start_angle;
- // due to the parser code not checking entity type
- int n = blockdata[iddata].size();
- for (int i = 0; i < n; i++) {
- double a = arc_start_angle * M_PI / 180.0;
- double lx1 = blockdata[iddata][i].p[0]->x * ellipse_start_angle;
- double ly1 = blockdata[iddata][i].p[0]->y * ellipse_stop_angle;
- double lx2 = blockdata[iddata][i].p[1]->x * ellipse_start_angle;
- double ly2 = blockdata[iddata][i].p[1]->y * ellipse_stop_angle;
- double px1 = (cos(a)*lx1 - sin(a)*ly1) * scale + xverts[0];
- double py1 = (sin(a)*lx1 + cos(a)*ly1) * scale + yverts[0];
- double px2 = (cos(a)*lx2 - sin(a)*ly2) * scale + xverts[0];
- double py2 = (sin(a)*lx2 + cos(a)*ly2) * scale + yverts[0];
- ADD_LINE(px1, py1, px2, py2);
- }
- }
- else if (mode == "DIMENSION" &&
- (layername.isNull() || layername == layer)) {
- this->dims.append(Dim());
- this->dims.last().type = dimtype;
- for (int i = 0; i < 7; i++)
- for (int j = 0; j < 2; j++)
- this->dims.last().coords[i][j] = coords[i][j];
- this->dims.last().angle = arc_start_angle;
- this->dims.last().length = radius;
- this->dims.last().name = name;
- }
- else if (mode == "BLOCK") {
- current_block = iddata;
- }
- else if (mode == "ENDBLK") {
- current_block = QString();
- }
- else if (mode == "ENDSEC") {
- }
- else if (in_blocks_section || (in_entities_section &&
- (layername.isNull() || layername == layer))) {
- unsupported_entities_list[mode]++;
- }
- mode = data;
- layer = QString();
- name = QString();
- iddata = QString();
- dimtype = 0;
- for (int i = 0; i < 7; i++)
- for (int j = 0; j < 2; j++)
- coords[i][j] = 0;
- xverts.clear();
- yverts.clear();
- radius = arc_start_angle = arc_stop_angle = 0;
- ellipse_start_angle = ellipse_stop_angle = 0;
- if (mode == "INSERT") {
- ellipse_start_angle = ellipse_stop_angle = 1.0; // scale
- }
- break;
- case 1:
- name = data;
- break;
- case 2:
- iddata = data;
- break;
- case 8:
- layer = data;
- break;
- case 10:
- if (in_blocks_section)
- xverts.append((data.toDouble()));
- else
- xverts.append((data.toDouble() - xorigin) * scale);
- break;
- case 11:
- if (in_blocks_section)
- xverts.append((data.toDouble()));
- else
- xverts.append((data.toDouble() - xorigin) * scale);
- break;
- case 20:
- if (in_blocks_section)
- yverts.append((data.toDouble()));
- else
- yverts.append((data.toDouble() - yorigin) * scale);
- break;
- case 21:
- if (in_blocks_section)
- yverts.append((data.toDouble()));
- else
- yverts.append((data.toDouble() - yorigin) * scale);
- break;
- case 40:
- // CIRCLE, ARC: radius
- // ELLIPSE: minor to major ratio
- // DIMENSION (radial, diameter): Leader length
- radius = data.toDouble();
- if (!in_blocks_section) radius *= scale;
- break;
- case 41:
- // ELLIPSE: start_angle
- // INSERT: X scale
- ellipse_start_angle = data.toDouble();
- break;
- case 50:
- // ARC: start_angle
- // INSERT: rot angle
- // DIMENSION: linear and rotated: angle
- arc_start_angle = data.toDouble();
- break;
- case 42:
- // ELLIPSE: stop_angle
- // INSERT: Y scale
- ellipse_stop_angle = data.toDouble();
- break;
- case 51: // ARC
- arc_stop_angle = data.toDouble();
- break;
- case 70:
- // LWPOLYLINE: polyline flag
- // DIMENSION: dimension type
- dimtype = data.toInt();
- break;
- }
- }
-
- QHashIterator<QString, int> i(unsupported_entities_list);
- while (i.hasNext()) {
- i.next();
- if (layername.isNull()) {
- PRINTA("WARNING: Unsupported DXF Entity `%1' (%2x) in `%3'.",
- i.key(), QString::number(i.value()), filename);
- } else {
- PRINTA("WARNING: Unsupported DXF Entity `%1' (%2x) in layer `%3' of `%4'.",
- i.key(), QString::number(i.value()), layername, filename);
- }
- }
-
- // Extract paths from parsed data
-
- QHash<int, int> enabled_lines;
- for (int i = 0; i < lines.count(); i++) {
- enabled_lines[i] = i;
- }
-
- // extract all open paths
- while (enabled_lines.count() > 0)
- {
- int current_line, current_point;
-
- foreach (int i, enabled_lines) {
- for (int j = 0; j < 2; j++) {
- QVector<int> *lv = &grid.data(lines[i].p[j]->x, lines[i].p[j]->y);
- for (int ki = 0; ki < lv->count(); ki++) {
- int k = lv->at(ki);
- if (k == i || lines[k].disabled)
- continue;
- goto next_open_path_j;
- }
- current_line = i;
- current_point = j;
- goto create_open_path;
- next_open_path_j:;
- }
- }
-
- break;
-
- create_open_path:
- this->paths.append(Path());
- Path *this_path = &this->paths.last();
-
- this_path->points.append(lines[current_line].p[current_point]);
- while (1) {
- this_path->points.append(lines[current_line].p[!current_point]);
- Point *ref_point = lines[current_line].p[!current_point];
- lines[current_line].disabled = true;
- enabled_lines.remove(current_line);
- QVector<int> *lv = &grid.data(ref_point->x, ref_point->y);
- for (int ki = 0; ki < lv->count(); ki++) {
- int k = lv->at(ki);
- if (lines[k].disabled)
- continue;
- if (grid.eq(ref_point->x, ref_point->y, lines[k].p[0]->x, lines[k].p[0]->y)) {
- current_line = k;
- current_point = 0;
- goto found_next_line_in_open_path;
- }
- if (grid.eq(ref_point->x, ref_point->y, lines[k].p[1]->x, lines[k].p[1]->y)) {
- current_line = k;
- current_point = 1;
- goto found_next_line_in_open_path;
- }
- }
- break;
- found_next_line_in_open_path:;
- }
- }
-
- // extract all closed paths
- while (enabled_lines.count() > 0)
- {
- int current_line = enabled_lines.begin().value(), current_point = 0;
-
- this->paths.append(Path());
- Path *this_path = &this->paths.last();
- this_path->is_closed = true;
-
- this_path->points.append(lines[current_line].p[current_point]);
- while (1) {
- this_path->points.append(lines[current_line].p[!current_point]);
- Point *ref_point = lines[current_line].p[!current_point];
- lines[current_line].disabled = true;
- enabled_lines.remove(current_line);
- QVector<int> *lv = &grid.data(ref_point->x, ref_point->y);
- for (int ki = 0; ki < lv->count(); ki++) {
- int k = lv->at(ki);
- if (lines[k].disabled)
- continue;
- if (grid.eq(ref_point->x, ref_point->y, lines[k].p[0]->x, lines[k].p[0]->y)) {
- current_line = k;
- current_point = 0;
- goto found_next_line_in_closed_path;
- }
- if (grid.eq(ref_point->x, ref_point->y, lines[k].p[1]->x, lines[k].p[1]->y)) {
- current_line = k;
- current_point = 1;
- goto found_next_line_in_closed_path;
- }
- }
- break;
- found_next_line_in_closed_path:;
- }
- }
-
- fixup_path_direction();
-
-#if 0
- printf("----- DXF Data -----\n");
- for (int i = 0; i < this->paths.count(); i++) {
- printf("Path %d (%s):\n", i, this->paths[i].is_closed ? "closed" : "open");
- for (int j = 0; j < this->paths[i].points.count(); j++)
- printf(" %f %f\n", this->paths[i].points[j]->x, this->paths[i].points[j]->y);
- }
- printf("--------------------\n");
- fflush(stdout);
-#endif
-}
-
-/*!
- Ensures that all paths have the same vertex ordering.
- FIXME: CW or CCW?
-*/
-void DxfData::fixup_path_direction()
-{
- for (int i = 0; i < this->paths.count(); i++) {
- if (!this->paths[i].is_closed)
- break;
- this->paths[i].is_inner = true;
- double min_x = this->paths[i].points[0]->x;
- int min_x_point = 0;
- for (int j = 1; j < this->paths[i].points.count(); j++) {
- if (this->paths[i].points[j]->x < min_x) {
- min_x = this->paths[i].points[j]->x;
- min_x_point = j;
- }
- }
- // rotate points if the path is in non-standard rotation
- int b = min_x_point;
- int a = b == 0 ? this->paths[i].points.count() - 2 : b - 1;
- int c = b == this->paths[i].points.count() - 1 ? 1 : b + 1;
- double ax = this->paths[i].points[a]->x - this->paths[i].points[b]->x;
- double ay = this->paths[i].points[a]->y - this->paths[i].points[b]->y;
- double cx = this->paths[i].points[c]->x - this->paths[i].points[b]->x;
- double cy = this->paths[i].points[c]->y - this->paths[i].points[b]->y;
-#if 0
- printf("Rotate check:\n");
- printf(" a/b/c indices = %d %d %d\n", a, b, c);
- printf(" b->a vector = %f %f (%f)\n", ax, ay, atan2(ax, ay));
- printf(" b->c vector = %f %f (%f)\n", cx, cy, atan2(cx, cy));
-#endif
- // FIXME: atan2() usually takes y,x. This variant probably makes the path clockwise..
- if (atan2(ax, ay) < atan2(cx, cy)) {
- for (int j = 0; j < this->paths[i].points.count()/2; j++)
- this->paths[i].points.swap(j, this->paths[i].points.count()-1-j);
- }
- }
-}
-
-DxfData::Point *DxfData::addPoint(double x, double y)
-{
- this->points.append(Point(x, y));
- return &this->points.last();
-}
-
contact: Jan Huwald // Impressum