3c3d9187e96a9356f551472a826748d5432c6c79
Stefan Schuermans initial version, DXFs can b...

Stefan Schuermans authored 11 years ago

1) /* drawing (DXF) to G-code (NGC) converter
2)  * Copyright 2013 Stefan Schuermans <stefan@schuermans.info>
3)  * Copyleft: CC-BY-SA http://creativecommons.org/licenses/by-sa/3.0/
4)  */
5) 
Stefan Schuermans implement finer approximati...

Stefan Schuermans authored 11 years ago

6) #include <dime/entities/Circle.h>
Stefan Schuermans initial version, DXFs can b...

Stefan Schuermans authored 11 years ago

7) #include <dime/entities/Entity.h>
8) #include <dime/State.h>
Stefan Schuermans implement finer approximati...

Stefan Schuermans authored 11 years ago

9) #include <dime/util/Linear.h>
10) #include <iostream>
11) #include <math.h>
Stefan Schuermans initial version, DXFs can b...

Stefan Schuermans authored 11 years ago

12) #include <string>
13) 
14) #include "drawing.h"
15) #include "layer.h"
16) #include "path.h"
Stefan Schuermans implement finer approximati...

Stefan Schuermans authored 11 years ago

17) #include "point.h"
Stefan Schuermans initial version, DXFs can b...

Stefan Schuermans authored 11 years ago

18) #include "traverse.h"
19) 
Stefan Schuermans implement finer approximati...

Stefan Schuermans authored 11 years ago

20) /// minimum number of segments to approximate circle with
21) #define TRAVERSE_CIRCLE_NUM_SEG_MIN (16)
22) 
23) /// maximum number of segments to approximate circle with
24) #define TRAVERSE_CIRCLE_NUM_SEG_MAX (4096)
25) 
Stefan Schuermans initial version, DXFs can b...

Stefan Schuermans authored 11 years ago

26) /**
27)  * @brief process an entity during DXF traversal
28)  * @param[in] state current state of libdime
29)  * @param[in] entity pointer to entity
30)  * @param[in] vp_ctx context pointer, must point to traverse_ctx structure
31)  * @return if to continue enumeration
32)  */
Stefan Schuermans implement finer approximati...

Stefan Schuermans authored 11 years ago

33) bool traverse_entity(const class dimeState *const state, dimeEntity *entity,
Stefan Schuermans initial version, DXFs can b...

Stefan Schuermans authored 11 years ago

34)                      void *vp_ctx)
35) {
36)   struct traverse_ctx *p_ctx = (struct traverse_ctx *)vp_ctx;
37) 
38)   // get layer
39)   std::string strLayerName = entity->getLayerName();
40)   Layer &layer = p_ctx->mpDrawing->mLayers[strLayerName];
41) 
42)   // get transformation matrix
43)   dimeMatrix matrix;
44)   state->getMatrix(matrix);
45) 
Stefan Schuermans implement finer approximati...

Stefan Schuermans authored 11 years ago

46)   /* special handling for some entities
47)      to avoid libdime's inexact conversion to lines */
48)   dimeArc     *arc;
49)   dimeCircle  *circle;
50)   dimeEllipse *ellipse;
51)   if ((arc = dynamic_cast<dimeArc *>(entity)))
52)     traverse_arc(arc, matrix, p_ctx->precision, layer);
53)   else if ((circle = dynamic_cast<dimeCircle *>(entity)))
54)     traverse_circle(circle, matrix, p_ctx->precision, layer);
55)   else if ((ellipse = dynamic_cast<dimeEllipse *>(entity)))
56)     traverse_ellipse(ellipse, matrix, p_ctx->precision, layer);
57)   else
58)     traverse_generic(entity, matrix, layer); // default: libdime conversion
59) 
60)   return true; // continue enumeration
61) }
62) 
63) /**
64)  * @brief process a generic geometric object during DXF traversal
65)  * @param[in] entity pointer to entity
66)  * @param[in] matrix current DXF transformation matrix
67)  * @param[in] layer layer to add the entitiy to
68)  */
69) void traverse_generic(dimeEntity *entity, const dimeMatrix &matrix,
70)                       Layer &layer)
71) {
Stefan Schuermans initial version, DXFs can b...

Stefan Schuermans authored 11 years ago

72)   // get geometry data
73)   dimeArray<dimeVec3f> vertices;
74)   dimeArray<int> indices;
75)   dimeVec3f extrusionDir;
76)   dxfdouble thickness;
77)   entity->extractGeometry(vertices, indices, extrusionDir, thickness);
78) 
79)   // transform geometry data
80)   for (int v = 0; v < vertices.count(); ++v)
81)     matrix.multMatrixVec(vertices[v]);
82) 
83)   // no indices -> entire vertices array forms a path
84)   if (indices.count() == 0) {
85)     Path &path = layer.addPath();
86)     for (int v = 0; v < vertices.count(); ++v)
87)       path.addPoint(vertices[v].x, vertices[v].y);
88)   }
89) 
90)   // indices available: paths given by indices
91)   else {
92)     Path *path = &layer.addPath();
93)     for (int i = 0; i < indices.count(); ++i) {
94)       int v = indices[i];
95)       // valid index: add to path
96)       if (v >= 0 || v < vertices.count())
97)         path->addPoint(vertices[v].x, vertices[v].y);
98)       // invalid index: start new path
99)       else
100)         path = &layer.addPath();
101)     }
102)   }
Stefan Schuermans implement finer approximati...

Stefan Schuermans authored 11 years ago

103) }
Stefan Schuermans initial version, DXFs can b...

Stefan Schuermans authored 11 years ago

104) 
Stefan Schuermans implement finer approximati...

Stefan Schuermans authored 11 years ago

105) /**
106)  * @brief process an arc during DXF traversal
107)  * @param[in] circle pointer to arc entity
108)  * @param[in] matrix current DXF transformation matrix
109)  * @param[in] precision precision for conversion to lines
110)  * @param[in] layer layer to add the entitiy to
111)  */
112) void traverse_arc(dimeArc *arc, const dimeMatrix &matrix,
113)                   double precision, Layer &layer)
114) {
115)   // get parameters (not yet transformed)
116)   dimeVec3f center;
117)   arc->getCenter(center);
118)   double radius = arc->getRadius();
119)   double start = arc->getStartAngle() * M_PI / 180.0;
120)   double end = arc->getEndAngle() * M_PI / 180.0;
121) 
122)   // add arc to layer
123)   traverse_add_circle(center, radius, start, end, precision, matrix, layer);
124) }
125) 
126) /**
127)  * @brief process a circle during DXF traversal
128)  * @param[in] circle pointer to circle entity
129)  * @param[in] matrix current DXF transformation matrix
130)  * @param[in] precision precision for conversion to lines
131)  * @param[in] layer layer to add the entitiy to
132)  */
133) void traverse_circle(dimeCircle *circle, const dimeMatrix &matrix,
134)                      double precision, Layer &layer)
135) {
136)   // get parameters and transform vertices
137)   dimeVec3f center = circle->getCenter();
138)   double radius = circle->getRadius();
139) 
140)   // add circle to layer
141)   traverse_add_circle(center, radius, 0.0, 2.0 * M_PI,
142)                       precision, matrix, layer);
143) }
144) 
145) /**
146)  * @brief process an ellipse during DXF traversal
147)  * @param[in] circle pointer to ellipse entity
148)  * @param[in] matrix current DXF transformation matrix
149)  * @param[in] precision precision for conversion to lines
150)  * @param[in] layer layer to add the entitiy to
151)  */
152) void traverse_ellipse(dimeEllipse *ellipse, const dimeMatrix &matrix,
153)                       double precision, Layer &layer)
154) {
155)   // get parameters (not yet transformed)
156)   dimeVec3f center = ellipse->getCenter();
157)   dimeVec3f majorEnd = ellipse->getMajorAxisEndpoint();
158)   double ratio = ellipse->getMinorMajorRatio();
159)   double start = ellipse->getStartParam();
160)   double end = ellipse->getEndParam();
161) 
162)   // add circle to layer
163)   traverse_add_ellipse(center, majorEnd, ratio, start, end,
164)                        precision, matrix, layer);
165) }
166) 
167) /**
168)  * @brief add a circle to the layer
169)  * @param[in] center center point
170)  * @param[in] radius radius
171)  * @param[in] start start angle in radians
172)  * @param[in] end end angle in radians
173)  * @param[in] precision precision for conversion to lines
174)  * @param[in] matrix current DXF transformation matrix
175)  * @param[in] layer layer to add the entitiy to
176)  */
177) void traverse_add_circle(const dimeVec3f &center,
178)                          double radius, double start, double end,
179)                          double precision, const dimeMatrix &matrix,
180)                          Layer &layer)
181) {
182)   // calculate number of segments to approximate part of circle with
183)   unsigned int num_seg = traverse_calc_num_seg(radius, start, end, precision);
184) 
185)   // loop over all angles to calculate point for
186)   if (end <= start)
187)     end += 2.0 * M_PI;
188)   unsigned int seg;
189)   Path &path = layer.addPath();
190)   for (seg = 0; seg <= num_seg; ++seg) {
191)     double angle = (start * (num_seg - seg) + end * seg) / num_seg;
192) 
193)     // get point
194)     double x = center.x + radius * cos(angle);
195)     double y = center.y + radius * sin(angle);
196) 
197)     // transform point via current matrix and add it to path
198)     dimeVec3f vertex(x, y, 0.0);
199)     matrix.multMatrixVec(vertex);
200)     path.addPoint(vertex.x, vertex.y);
201) 
202)   } // for seg
203) }
204) 
205) /**
206)  * @brief add ellipse to the layer
207)  * @param[in] center center point
208)  * @param[in] majorEnd endpoint of major axis
209)  * @param[in] ratio ratio of minor to major axis
210)  * @param[in] start start angle in radians
211)  * @param[in] end end angle in radians
212)  * @param[in] precision precision for conversion to lines
213)  * @param[in] matrix current DXF transformation matrix
214)  * @param[in] layer layer to add the entitiy to
215)  */
216) void traverse_add_ellipse(const dimeVec3f &center, const dimeVec3f &majorEnd,
217)                           double ratio, double start, double end,
218)                           double precision, const dimeMatrix &matrix,
219)                           Layer &layer)
220) {
221)   // calculate number of segments to approximate part of ellipse with
222)   double majorRadius = (majorEnd - center).length();
223)   double maxRadius = ratio <= 1.0 ? majorRadius : majorRadius * ratio;
224)   unsigned int num_seg = traverse_calc_num_seg(maxRadius, start, end,
225)                                                precision);
226) 
227)   // build transformation matrix: union circle -> ellipse
228)   double maj_x = majorEnd.x;
229)   double maj_y = majorEnd.y;
230)   double min_x = -ratio * maj_y;
231)   double min_y =  ratio * maj_x;
232) 
233)   // loop over all angles to calculate point for
234)   if (end <= start)
235)     end += 2.0 * M_PI;
236)   unsigned int seg;
237)   Path &path = layer.addPath();
238)   for (seg = 0; seg <= num_seg; ++seg) {
239)     double angle = (start * (num_seg - seg) + end * seg) / num_seg;
240) 
241)     // get point on union circle
242)     double uc_x = cos(angle);
243)     double uc_y = sin(angle);
244)     // transformation: union circle -> ellipse
245)     double x = maj_x * uc_x + min_x * uc_y;
246)     double y = maj_y * uc_x + min_y * uc_y;
247)     // translate: move to center
248)     x += center.x;
249)     y += center.y;
250) 
251)     // transform point via current matrix and add it to path
252)     dimeVec3f vertex(x, y, 0.0);
253)     matrix.multMatrixVec(vertex);
254)     path.addPoint(vertex.x, vertex.y);
255) 
256)   } // for seg
257) }
258) 
259) /**
260)  * @brief calculate number of segments to approx. part of circle/ellipse with
261)  * @param[in] maxRadius radius of circle / maximum radius of ellipse
262)  * @param[in] start start angle in radians
263)  * @param[in] end end angle in radians
264)  * @param[in] precision precision for conversion to lines
265)  * @return number of segments to approximate circle/ellipse with
266)  */
267) unsigned int traverse_calc_num_seg(double maxRadius, double start, double end,
268)                                    double precision)
269) {
270)   // calculate number of segments for full circle/ellipse
271)   unsigned int num_seg;
272)   double dist;
273)   // double number of segments until precision is met (or maximum reached)
274)   for (num_seg = TRAVERSE_CIRCLE_NUM_SEG_MIN;
275)        num_seg < TRAVERSE_CIRCLE_NUM_SEG_MAX; num_seg *= 2) {
276)     // maximum distance of circle and regular polygon with num_seg sides
277)     dist = maxRadius * (1.0 - cos(M_PI / num_seg));
278)     // precision met -> done
279)     if (dist < precision)
280)       break;
281)   }
282) 
283)   // calculate number of segments for part of cirlce/ellipse
284)   double angle = start < end ? end - start : 2.0 * M_PI + end - start;
285)   num_seg = (unsigned int)ceil((double)num_seg * angle / (2.0 * M_PI));
286) 
287)   return num_seg;