~ubuntu-branches/ubuntu/maverick/freecad/maverick

« back to all changes in this revision

Viewing changes to src/Mod/Sketcher/App/sketchflat/curve.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Teemu Ikonen
  • Date: 2009-07-16 18:37:41 UTC
  • Revision ID: james.westby@ubuntu.com-20090716183741-oww9kcxqrk991i1n
Tags: upstream-0.8.2237
ImportĀ upstreamĀ versionĀ 0.8.2237

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//-----------------------------------------------------------------------------
 
2
// Copyright 2008 Jonathan Westhues
 
3
//
 
4
// This file is part of SketchFlat.
 
5
// 
 
6
// SketchFlat is free software: you can redistribute it and/or modify
 
7
// it under the terms of the GNU General Public License as published by
 
8
// the Free Software Foundation, either version 3 of the License, or
 
9
// (at your option) any later version.
 
10
// 
 
11
// SketchFlat is distributed in the hope that it will be useful,
 
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
// GNU General Public License for more details.
 
15
// 
 
16
// You should have received a copy of the GNU General Public License
 
17
// along with SketchFlat.  If not, see <http://www.gnu.org/licenses/>.
 
18
//------
 
19
//
 
20
// Routines to work with our parametric curves. When we get the curves, they
 
21
// already have constant numerical coefficients.
 
22
// Jonathan Westhues, April 2007
 
23
//-----------------------------------------------------------------------------
 
24
#include "PreCompiled.h"
 
25
#ifndef _PreComp_
 
26
#endif
 
27
 
 
28
#include "sketchflat.h"
 
29
 
 
30
#define CHORD_TOLERANCE_IN_PIXELS 0.25
 
31
 
 
32
static DoublePoint TransX, TransY, TransOffset;
 
33
 
 
34
static DoublePoint ImportMin, ImportMax;
 
35
 
 
36
void CurveEval(SketchCurve *c, double t, double *xp, double *yp);
 
37
 
 
38
static void AddPwl(hEntity id, hLayer layer, BOOL construction,
 
39
                                double x0, double y0, double x1, double y1);
 
40
 
 
41
static void Zero(SketchCurve *c)
 
42
{
 
43
    c->x.A = 0;
 
44
    c->x.B = 0;
 
45
    c->x.C = 0;
 
46
    c->x.D = 0;
 
47
    c->x.R = 0;
 
48
    c->x.Rl = 0;
 
49
    c->x.phi = 0;
 
50
 
 
51
    c->y.A = 0;
 
52
    c->y.B = 0;
 
53
    c->y.C = 0;
 
54
    c->y.D = 0;
 
55
    c->y.R = 0;
 
56
    c->y.Rl = 0;
 
57
    c->y.phi = 0;
 
58
 
 
59
    c->omega = 0;
 
60
}
 
61
 
 
62
static void AddCurve(SketchCurve *c)
 
63
{
 
64
    SketchEntity *e = EntityById(c->id);
 
65
    // The curve is on whatever layer the entity that generates it is on.
 
66
    c->layer = e->layer;
 
67
    // and has the same construction flag.
 
68
    c->construction = e->construction;
 
69
 
 
70
    int i = SK->curves;
 
71
    if(i < (MAX_CURVES_IN_SKETCH-1)) {
 
72
        memcpy(&(SK->curve[i]), c, sizeof(*c));
 
73
        SK->curves = i + 1;
 
74
    }
 
75
}
 
76
 
 
77
static void AddBezierCubic(hEntity he, double *x, double *y)
 
78
{
 
79
    // The cubic has the form 
 
80
    //   P[0]*(1-t)^3 + 3*P[1]*t*(1-t)^2 + 3*P[2]*t^2*(1-t) + P[3]*t^3
 
81
    // or, expanding,
 
82
    //   (-P[0]+3*P[1]-3*P[2]+P[3])     * t^3 + 
 
83
    //   (3*P[0]+3*P[2]-6*P[1])         * t^2 + 
 
84
    //   (-3*P[0]+3*P[1])               * t   + 
 
85
    //   P[0]
 
86
 
 
87
    SketchCurve c;
 
88
    Zero(&c);
 
89
    c.id = he;
 
90
 
 
91
    c.x.A =   -x[0] + 3*x[1] - 3*x[2] + x[3];
 
92
    c.y.A =   -y[0] + 3*y[1] - 3*y[2] + y[3];
 
93
 
 
94
    c.x.B =  3*x[0] - 6*x[1] + 3*x[2];
 
95
    c.y.B =  3*y[0] - 6*y[1] + 3*y[2];
 
96
 
 
97
    c.x.C = -3*x[0] + 3*x[1];
 
98
    c.y.C = -3*y[0] + 3*y[1];
 
99
    
 
100
    c.x.D =    x[0];
 
101
    c.y.D =    y[0];
 
102
 
 
103
    AddCurve(&c);
 
104
}
 
105
 
 
106
static void FromTtfTransform(int xi, int yi, double *xo, double *yo)
 
107
{
 
108
    double xf, yf;
 
109
 
 
110
    xf = (xi / 1024.0);
 
111
    yf = (yi / 1024.0);
 
112
 
 
113
    // output = xf*TransX + yf*TransY
 
114
    *xo = xf*(TransX.x) + yf*(TransY.x) + TransOffset.x;
 
115
    *yo = xf*(TransX.y) + yf*(TransY.y) + TransOffset.y;
 
116
}
 
117
 
 
118
static void FromImportedTransform(double *x, double *y)
 
119
{
 
120
    double xi = *x, yi = *y;
 
121
 
 
122
    xi -= ImportMin.x;
 
123
    yi -= ImportMin.y;
 
124
 
 
125
    double scale = (ImportMax.y - ImportMin.y);
 
126
    if(scale == 0) scale = 1;
 
127
    xi /= scale;
 
128
    yi /= scale;
 
129
 
 
130
    *x = (xi*TransX.x) + (yi*TransY.x) + TransOffset.x;
 
131
    *y = (xi*TransX.y) + (yi*TransY.y) + TransOffset.y;
 
132
}
 
133
 
 
134
void TtfLineSegment(DWORD ref, int x0, int y0, int x1, int y1)
 
135
{
 
136
    double x0f, y0f, x1f, y1f;
 
137
 
 
138
    FromTtfTransform(x0, y0, &x0f, &y0f);
 
139
    FromTtfTransform(x1, y1, &x1f, &y1f);
 
140
 
 
141
    SketchCurve c;
 
142
    Zero(&c);
 
143
 
 
144
    c.x.D = x0f;
 
145
    c.y.D = y0f;
 
146
    c.x.C = x1f - x0f;
 
147
    c.y.C = y1f - y0f;
 
148
 
 
149
    c.id = ref;
 
150
 
 
151
    AddCurve(&c);
 
152
}
 
153
 
 
154
void TtfBezier(DWORD ref, int x0, int y0, int x1, int y1, int x2, int y2)
 
155
{
 
156
    double x0f, y0f, x1f, y1f, x2f, y2f;
 
157
 
 
158
    FromTtfTransform(x0, y0, &x0f, &y0f);
 
159
    FromTtfTransform(x1, y1, &x1f, &y1f);
 
160
    FromTtfTransform(x2, y2, &x2f, &y2f);
 
161
 
 
162
    SketchCurve c;
 
163
    Zero(&c);
 
164
    
 
165
    // The Bezier curve has the form:
 
166
    //
 
167
    //     P(t) = P0*(1 - t)^2 + P1*2*t*(1 - t) + P2*t^2
 
168
    //          = P0 - P0*2*t + P0*t^2 + P1*2*t - P1*2*t^2 + P2*t^2
 
169
    //          = P0 + t*(-P0*2 + P1*2) + (t^2)*(P0 - P1*2 + P2)
 
170
    //
 
171
    // Of course it would be better to evaluate with de Casteljau's or
 
172
    // whatever, but this is more general.
 
173
 
 
174
    c.x.D = x0f;
 
175
    c.y.D = y0f;
 
176
    c.x.C = (-x0f*2 + x1f*2);
 
177
    c.y.C = (-y0f*2 + y1f*2);
 
178
    c.x.B = (x0f - x1f*2 + x2f);
 
179
    c.y.B = (y0f - y1f*2 + y2f);
 
180
 
 
181
    c.id = ref;
 
182
 
 
183
    AddCurve(&c);
 
184
}
 
185
 
 
186
//-----------------------------------------------------------------------------
 
187
// For the HPGL/DXF import: we want to scale the artwork as we import it,
 
188
// to put the two reference points at the corners of its bounding box. So
 
189
// we need to calculate the bounding box of the file, which we do on our
 
190
// first pass through.
 
191
//-----------------------------------------------------------------------------
 
192
static void RecordBounds(double x0, double y0, double x1, double y1)
 
193
{
 
194
    int i;
 
195
    for(i = 0; i < 2; i++) {
 
196
        double x, y;
 
197
        if(i == 0) {
 
198
            x = x0; y = y0;
 
199
        } else {
 
200
            x = x1; y = y1;
 
201
        }
 
202
 
 
203
        if(x > ImportMax.x) ImportMax.x = x;
 
204
        if(x < ImportMin.x) ImportMin.x = x;
 
205
        if(y > ImportMax.y) ImportMax.y = y;
 
206
        if(y < ImportMin.y) ImportMin.y = y;
 
207
    }
 
208
}
 
209
 
 
210
//-----------------------------------------------------------------------------
 
211
// Import an HPGL file. If justGetBound is TRUE, then we don't generate pwls,
 
212
// but call RecordBounds() to measure the bounding box.
 
213
//-----------------------------------------------------------------------------
 
214
static BOOL ImportFromHpgl(hEntity he, hLayer hl, char *file, BOOL justGetBound)
 
215
{
 
216
    FILE *f = fopen(file, "r");
 
217
    if(!f) return FALSE;
 
218
 
 
219
    double prevX = 0, prevY = 0;
 
220
 
 
221
#define GET_CHAR_INTO(c) (c) = fgetc(f); if((c) < 0) goto done
 
222
    for(;;) {
 
223
        int now, prev = -1;
 
224
 
 
225
        // First, look for a command.
 
226
        for(;;) {
 
227
            GET_CHAR_INTO(now);
 
228
            now = tolower(now);
 
229
            if(prev == 'p' && (now == 'd' || now == 'u')) break;
 
230
            prev = now;
 
231
        }
 
232
        // Is it followed by a number?
 
233
        char xbuf[100];
 
234
        int xbufp = 0;
 
235
        for(;;) {
 
236
            int c;
 
237
            GET_CHAR_INTO(c);
 
238
            if(isdigit(c) || c == '.' || c == '-') {
 
239
                if(xbufp > 10) break;
 
240
                xbuf[xbufp++] = c;
 
241
            } else {
 
242
                break;
 
243
            }
 
244
        }
 
245
        // Burn extra separators
 
246
        for(;;) {
 
247
            int c;
 
248
            GET_CHAR_INTO(c);
 
249
            if(c == ',' || c == ' ') {
 
250
                // do nothing
 
251
            } else {
 
252
                ungetc(c, f);
 
253
                break;
 
254
            }
 
255
        }
 
256
        // And then get the y
 
257
        char ybuf[100];
 
258
        int ybufp = 0;
 
259
        for(;;) {
 
260
            int c;
 
261
            GET_CHAR_INTO(c);
 
262
            if(isdigit(c) || c == '.' || c == '-') {
 
263
                if(ybufp > 10) break;
 
264
                ybuf[ybufp++] = c;
 
265
            } else {
 
266
                break;
 
267
            }
 
268
        }
 
269
 
 
270
        double x, y;
 
271
        xbuf[xbufp] = '\0';
 
272
        x = atof(xbuf);
 
273
        ybuf[ybufp] = '\0';
 
274
        y = atof(ybuf);
 
275
 
 
276
        if(justGetBound) {
 
277
            RecordBounds(prevX, prevY, x, y);
 
278
        } else {
 
279
            FromImportedTransform(&x, &y);
 
280
            if(now == 'd') {
 
281
                AddPwl(he, hl, FALSE, prevX, prevY, x, y);
 
282
            }
 
283
        } 
 
284
        prevX = x;
 
285
        prevY = y;
 
286
    }
 
287
 
 
288
done:
 
289
    fclose(f);
 
290
    return TRUE;
 
291
}
 
292
 
 
293
//-----------------------------------------------------------------------------
 
294
// Import a DXF file. If justGetBound is TRUE, then we don't generate pwls,
 
295
// but call RecordBounds() to measure the bounding box.
 
296
//-----------------------------------------------------------------------------
 
297
static BOOL ImportFromDxf(hEntity he, hLayer hl, char *file, BOOL justGetBound)
 
298
{
 
299
    FILE *f = fopen(file, "r");
 
300
    if(!f) return FALSE;
 
301
 
 
302
    char line[MAX_STRING];
 
303
 
 
304
#define GET_LINE_INTO(s) if(!fgets(s, sizeof(s), f)) goto done
 
305
    for(;;) {
 
306
        GET_LINE_INTO(line);
 
307
        
 
308
        char *s = line;
 
309
        while(isspace(*s)) s++;
 
310
        while(isspace(s[strlen(s)-1])) s[strlen(s)-1] = '\0';
 
311
 
 
312
        if(strcmp(s, "LINE")==0) {
 
313
            char x0[MAX_STRING] = "", y0[MAX_STRING] = "";
 
314
            char x1[MAX_STRING] = "", y1[MAX_STRING] = "";
 
315
            BYTE have = 0;
 
316
            
 
317
            for(;;) {
 
318
                GET_LINE_INTO(line);
 
319
                switch(atoi(line)) {
 
320
                    case 10:    GET_LINE_INTO(x0); have |= 1; break;
 
321
                    case 20:    GET_LINE_INTO(y0); have |= 2; break;
 
322
                    case 11:    GET_LINE_INTO(x1); have |= 4; break;
 
323
                    case 21:    GET_LINE_INTO(y1); have |= 8; break;
 
324
                    case 0:
 
325
                        goto break_loop;
 
326
 
 
327
                    default:    GET_LINE_INTO(line); break;
 
328
                }
 
329
 
 
330
                // Do we have all four paramter values?
 
331
                if(have == 0xf) break;
 
332
            }
 
333
 
 
334
            double x0f, y0f, x1f, y1f;
 
335
            x0f = atof(x0);
 
336
            y0f = atof(y0);
 
337
            x1f = atof(x1);
 
338
            y1f = atof(y1);
 
339
 
 
340
            if(justGetBound) {
 
341
                RecordBounds(x0f, y0f, x1f, y1f);
 
342
            } else {
 
343
                FromImportedTransform(&x0f, &y0f);
 
344
                FromImportedTransform(&x1f, &y1f);
 
345
                AddPwl(he, hl, FALSE, x0f, y0f, x1f, y1f);
 
346
            }
 
347
        }
 
348
break_loop:;
 
349
    }
 
350
 
 
351
done:
 
352
    fclose(f);
 
353
    return TRUE;
 
354
}
 
355
 
 
356
//-----------------------------------------------------------------------------
 
357
// Import some type of file, determining which according to its extension. If
 
358
// the file import fails, then draw an X, as an indication to the user that
 
359
// something broke. Also record the extent of the imported file, to display
 
360
// in the measurement view, since the user might want to use that to scale
 
361
// back to 1:1.
 
362
//-----------------------------------------------------------------------------
 
363
static BOOL ImportFromFile(hEntity he, hLayer hl, char *file)
 
364
{
 
365
    char *ext = file + strlen(file) - 4;
 
366
 
 
367
    ImportMax.x = VERY_NEGATIVE;
 
368
    ImportMax.y = VERY_NEGATIVE;
 
369
    ImportMin.x = VERY_POSITIVE;
 
370
    ImportMin.y = VERY_POSITIVE;
 
371
 
 
372
    int SKpwls0 = SK->pwls;
 
373
 
 
374
    // Guess the file type from the extension.
 
375
    if(_stricmp(ext, ".plt")==0 || _stricmp(ext, "hpgl")==0) {
 
376
        ImportFromHpgl(he, hl, file, TRUE);
 
377
        ImportFromHpgl(he, hl, file, FALSE);
 
378
    } else if(_stricmp(ext, ".dxf")==0) {
 
379
        ImportFromDxf(he, hl, file, TRUE);
 
380
        ImportFromDxf(he, hl, file, FALSE);
 
381
    }
 
382
 
 
383
    // If we didn't generate any piecewise linear segments, then probably
 
384
    // something broke. Show an X in construction line segments, so that the
 
385
    // user still has something to grab and select.
 
386
    if(SKpwls0 == SK->pwls) {
 
387
        double x0, y0, x1, y1;
 
388
        ImportMax.x = 1; ImportMax.y = 1;
 
389
        ImportMin.x = 0; ImportMin.y = 0;
 
390
        x0 = 0; y0 = 0; x1 = 1; y1 = 1;
 
391
        FromImportedTransform(&x0, &y0);
 
392
        FromImportedTransform(&x1, &y1);
 
393
        AddPwl(he, hl, TRUE, x0, y0, x1, y1);
 
394
        x0 = 1; y0 = 0; x1 = 0; y1 = 1;
 
395
        FromImportedTransform(&x0, &y0);
 
396
        FromImportedTransform(&x1, &y1);
 
397
        AddPwl(he, hl, TRUE, x0, y0, x1, y1);
 
398
    }
 
399
 
 
400
    // Record the original bounding box of the imported file; the measure
 
401
    // stuff will display it from here.
 
402
    SketchEntity *e = EntityById(he);
 
403
    if(e) {
 
404
        sprintf(e->text, "    (%.3f, %.3f)\r\n"
 
405
                         "    (%.3f, %.3f)\r\n"
 
406
                         "  so dy = %.3f",
 
407
            ImportMin.x, ImportMin.y,
 
408
            ImportMax.x, ImportMax.y,
 
409
            ImportMax.y - ImportMin.y);
 
410
    }
 
411
 
 
412
    return TRUE;
 
413
}
 
414
 
 
415
void GenerateCurvesFromEntity(SketchEntity *e)
 
416
{
 
417
    SketchCurve c;
 
418
    hPoint pt0, pt1;
 
419
    hParam prm0;
 
420
 
 
421
    Zero(&c);
 
422
    switch(e->type) {
 
423
        case ENTITY_DATUM_POINT:
 
424
            // No curves associated with this entity.
 
425
            break;
 
426
 
 
427
        case ENTITY_DATUM_LINE:
 
428
            // No curves associated with this entity (infinitely long lines
 
429
            // are a special case, distinct from line segments).
 
430
            break;
 
431
 
 
432
        case ENTITY_LINE_SEGMENT:
 
433
            pt0 = POINT_FOR_ENTITY(e->id, 0);
 
434
            pt1 = POINT_FOR_ENTITY(e->id, 1);
 
435
 
 
436
            Zero(&c);
 
437
            c.x.D = EvalParam(X_COORD_FOR_PT(pt0));
 
438
            c.y.D = EvalParam(Y_COORD_FOR_PT(pt0));
 
439
            c.x.C = EvalParam(X_COORD_FOR_PT(pt1)) - c.x.D;
 
440
            c.y.C = EvalParam(Y_COORD_FOR_PT(pt1)) - c.y.D;
 
441
            c.id = e->id;
 
442
 
 
443
            AddCurve(&c);
 
444
            break;
 
445
 
 
446
        case ENTITY_CIRCLE:
 
447
            pt0 = POINT_FOR_ENTITY(e->id, 0);
 
448
            prm0 = PARAM_FOR_ENTITY(e->id, 0);
 
449
 
 
450
            Zero(&c);
 
451
            EvalPoint(pt0, &(c.x.D), &(c.y.D));
 
452
            c.x.R = c.y.R = EvalParam(prm0);
 
453
            c.x.phi = 0;
 
454
            c.y.phi = PI/2;
 
455
            c.omega = 2*PI;
 
456
            c.id = e->id;
 
457
 
 
458
            AddCurve(&c);
 
459
            break;
 
460
 
 
461
        case ENTITY_CIRCULAR_ARC: {
 
462
            double x0, y0, x1, y1;
 
463
            EvalPoint(POINT_FOR_ENTITY(e->id, 0), &x0, &y0);
 
464
            EvalPoint(POINT_FOR_ENTITY(e->id, 1), &x1, &y1);
 
465
            double xc, yc;
 
466
            EvalPoint(POINT_FOR_ENTITY(e->id, 2), &xc, &yc);
 
467
 
 
468
            double r0 = Distance(xc, yc, x0, y0);
 
469
            double r1 = Distance(xc, yc, x1, y1);
 
470
 
 
471
            double phi0 = atan2(y0 - yc, x0 - xc);
 
472
            double phi1 = atan2(y1 - yc, x1 - xc);
 
473
 
 
474
            double dphi = phi0 - phi1;
 
475
            while(dphi < 0) dphi += 2*PI;
 
476
            while(dphi >= 2*PI) dphi -= 2*PI;
 
477
            
 
478
            Zero(&c);
 
479
            c.x.D = xc;
 
480
            c.y.D = yc;
 
481
            c.x.R = r0;
 
482
            c.x.Rl = r1 - r0;
 
483
            c.y.R = -r0;
 
484
            c.y.Rl = -(r1 - r0);
 
485
            c.x.phi = 0 + phi0;
 
486
            c.y.phi = PI/2 + phi0;
 
487
            c.omega = -dphi;
 
488
            c.id = e->id;
 
489
 
 
490
            AddCurve(&c);
 
491
            break;
 
492
        }
 
493
 
 
494
        case ENTITY_CUBIC_SPLINE: {
 
495
            double x[4], y[4];
 
496
            double xnp, ynp;    // previous oN curve point
 
497
            double xfp, yfp;    // previous oFf curve point
 
498
 
 
499
            int i;
 
500
 
 
501
            int pt = 0;
 
502
            int max = (e->points - 2) / 2;
 
503
            for(i = 0; i < max; i++) {
 
504
                if(i == 0) {
 
505
                    EvalPoint(POINT_FOR_ENTITY(e->id, pt), &(x[0]), &(y[0]));
 
506
                    pt++;
 
507
                    EvalPoint(POINT_FOR_ENTITY(e->id, pt), &(x[1]), &(y[1]));
 
508
                    pt++;
 
509
                } else {
 
510
                    x[0] = xnp;
 
511
                    y[0] = ynp;
 
512
                    x[1] = xfp;
 
513
                    y[1] = yfp;
 
514
                }
 
515
 
 
516
                if(i == (max - 1)) {
 
517
                    EvalPoint(POINT_FOR_ENTITY(e->id, pt), &(x[2]), &(y[2]));
 
518
                    pt++;
 
519
                    EvalPoint(POINT_FOR_ENTITY(e->id, pt), &(x[3]), &(y[3]));
 
520
                    pt++;
 
521
                } else {
 
522
                    EvalPoint(POINT_FOR_ENTITY(e->id, pt), &(x[2]), &(y[2]));
 
523
                    pt++;
 
524
                    EvalPoint(POINT_FOR_ENTITY(e->id, pt), &xfp, &yfp);
 
525
                    pt++;
 
526
                    xnp = x[3] = (xfp + x[2]) / 2;
 
527
                    ynp = y[3] = (yfp + y[2]) / 2;
 
528
                }
 
529
 
 
530
                AddBezierCubic(e->id, x, y);
 
531
            }
 
532
 
 
533
            break;
 
534
        }
 
535
 
 
536
        case ENTITY_TTF_TEXT:
 
537
        case ENTITY_IMPORTED: {
 
538
            double x0, y0, x1, y1;
 
539
            EvalPoint(POINT_FOR_ENTITY(e->id, 0), &x0, &y0);
 
540
            EvalPoint(POINT_FOR_ENTITY(e->id, 1), &x1, &y1);
 
541
 
 
542
            TransY.x = x1 - x0;
 
543
            TransY.y = y1 - y0;
 
544
 
 
545
            TransX.x =  TransY.y;
 
546
            TransX.y = -TransY.x;
 
547
 
 
548
            TransOffset.x = x0;
 
549
            TransOffset.y = y0;
 
550
 
 
551
            if(e->type == ENTITY_TTF_TEXT) {
 
552
                TtfSelectFont(e->file);
 
553
                TtfPlotString(e->id, e->text, e->spacing);
 
554
            } else {
 
555
                ImportFromFile(e->id, e->layer, e->file);
 
556
            }
 
557
            break;
 
558
        }
 
559
 
 
560
        default:
 
561
            oopsnf();
 
562
            break;
 
563
    }
 
564
}
 
565
void GenerateCurves(void)
 
566
{
 
567
    SK->curves = 0;
 
568
 
 
569
    int i;
 
570
    for(i = 0; i < SK->entities; i++) {
 
571
        GenerateCurvesFromEntity(&(SK->entity[i]));
 
572
    }
 
573
}
 
574
 
 
575
void CurveEval(SketchCurve *c, double t, double *xp, double *yp)
 
576
{
 
577
    double x, y;
 
578
 
 
579
    x  = c->x.A; x *= t;
 
580
    x += c->x.B; x *= t;
 
581
    x += c->x.C; x *= t;
 
582
    x += c->x.D;
 
583
    x += (c->x.R + (c->x.Rl)*t) * cos((c->omega)*t + c->x.phi);
 
584
 
 
585
    y  = c->y.A; y *= t;
 
586
    y += c->y.B; y *= t;
 
587
    y += c->y.C; y *= t;
 
588
    y += c->y.D;
 
589
    y += (c->y.R + (c->y.Rl)*t) * cos((c->omega)*t + c->y.phi);
 
590
 
 
591
    *xp = x;
 
592
    *yp = y;
 
593
}
 
594
 
 
595
static void AddPwl(hEntity id, hLayer layer, BOOL construction,
 
596
                                double x0, double y0, double x1, double y1)
 
597
{
 
598
    int i = SK->pwls;
 
599
    
 
600
    if(i >= (MAX_PWLS_IN_SKETCH-1)) return;
 
601
 
 
602
    SketchPwl *p = &(SK->pwl[i]);
 
603
 
 
604
    p->id = id;
 
605
    p->layer = layer;
 
606
    p->construction = construction;
 
607
 
 
608
    p->x0 = x0;
 
609
    p->y0 = y0;
 
610
    p->x1 = x1;
 
611
    p->y1 = y1;
 
612
 
 
613
    SK->pwls = i + 1;
 
614
}
 
615
 
 
616
//-----------------------------------------------------------------------------
 
617
// Break a curve down in to its piecewise linear representation. The number
 
618
// of points is determined by a "chord tolerance". We initially try to
 
619
// generate a single line for the entire curve, but halve the remaining
 
620
// interval each time we fail.
 
621
//-----------------------------------------------------------------------------
 
622
static void GeneratePwlsFromCurve(SketchCurve *c, double chordTol)
 
623
{
 
624
    int pts = 0;
 
625
    int iters = 0;
 
626
 
 
627
    double from = 0;
 
628
    double finalTo = 1;
 
629
 
 
630
    double tryTo = finalTo;
 
631
 
 
632
    int pwls0 = SK->pwls;
 
633
 
 
634
    while(from < (finalTo - 0.001)) {
 
635
        double xi, yi;      // Starting point of the line we are considering
 
636
        double xf, yf;      // Ending point of the line we are considering
 
637
        double xm, ym;      // A point on the curve midway between start, end
 
638
        double xml, yml;    // The midpoint of the line we are considering
 
639
        
 
640
        if(c->x.A != 0 || c->y.A != 0) {
 
641
            // A cubic might pass through the midpoint of the line connecting 
 
642
            // its endpoints, but deviate from that line elsewhere.
 
643
            if(tryTo - from > 0.1) {
 
644
                tryTo = std::min<double>(finalTo, from + 0.1);
 
645
            }
 
646
        }
 
647
 
 
648
        CurveEval(c, from, &xi, &yi);
 
649
        CurveEval(c, tryTo, &xf, &yf);
 
650
        CurveEval(c, (from + tryTo)/2, &xm, &ym);
 
651
/*
 
652
        dbp("from (%.3f, %.3f) at %.3f to (%.3f, %.3f) at %.3f",
 
653
            xi, yi, from,
 
654
            xf, yf, tryTo); */
 
655
 
 
656
        xml = (xi + xf)/2;
 
657
        yml = (yi + yf)/2;
 
658
 
 
659
        if(Distance(xm, ym, xml, yml) < chordTol) {
 
660
            // Looks good
 
661
            AddPwl(c->id, c->layer, c->construction, xi, yi, xf, yf);
 
662
            from = tryTo;
 
663
            tryTo = finalTo;
 
664
            pts++;
 
665
        } else {
 
666
            tryTo = from + (tryTo - from)/2;
 
667
            // And try again
 
668
        }
 
669
 
 
670
        iters++;
 
671
        if(pts > 200 || iters > 1000) {
 
672
            // If we get too many points trying to plot the thing cleverly
 
673
            // and adaptively, then give up and just generate 200 evenly
 
674
            // spaced points.
 
675
            SK->pwls = pwls0;
 
676
            double t;
 
677
            CurveEval(c, 0, &xi, &yi);
 
678
            double steps = 200;
 
679
            double dt = 1.0/steps;
 
680
            for(t = dt; t < 1 + dt; t += dt) {
 
681
                CurveEval(c, t, &xf, &yf);
 
682
                AddPwl(c->id, c->layer, c->construction, xi, yi, xf, yf);
 
683
                xi = xf;
 
684
                yi = yf;
 
685
            }
 
686
            break;
 
687
        }
 
688
    }
 
689
}
 
690
void GenerateCurvesAndPwls(double chordTol)
 
691
{
 
692
    SK->pwls = 0;
 
693
 
 
694
    // First, create the various curves.
 
695
    GenerateCurves();
 
696
 
 
697
    // Then break them down to piecewise linear segments. The chord
 
698
    // tolerance with which we do this is caller-configurable.
 
699
 
 
700
    if(chordTol < 0) {
 
701
        // They want our default display tolerance.
 
702
        chordTol = 
 
703
            toMicronsNotAffine((int)(CHORD_TOLERANCE_IN_PIXELS*100))/100.0;
 
704
    }
 
705
   
 
706
    // And adaptive-pwl each curve.
 
707
    int i;
 
708
    for(i = 0; i < SK->curves; i++) {
 
709
        GeneratePwlsFromCurve(&(SK->curve[i]), chordTol);
 
710
    }
 
711
}