00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104 #include "camtypes.h"
00105 #include <stdio.h>
00106 #include <stdlib.h>
00107 #include <math.h>
00108
00109 #include "fitcurve.h"
00110
00111 #include "pathtrap.h"
00112
00113
00114
00115 DECLARE_SOURCE("$Revision: 1282 $");
00116
00117
00118 #define STEP_SIZE 6
00119 #define ERROR_STEP 6
00120
00121
00122 CC_IMPLEMENT_MEMDUMP(CurveFitObject, CC_CLASS_MEMDUMP)
00123 CC_IMPLEMENT_MEMDUMP(FitPoint, CC_CLASS_MEMDUMP)
00124
00125 #define new CAM_DEBUG_NEW
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139 FitPoint FitPoint::operator - ()
00140 {
00141 FitPoint Result;
00142
00143
00144 Result.x = -x;
00145 Result.y = -y;
00146
00147
00148 return Result;
00149 }
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166 FitPoint FitPoint::operator * (double Factor)
00167 {
00168 FitPoint Result;
00169
00170
00171 Result.x = x*Factor;
00172 Result.y = y*Factor;
00173
00174
00175 return Result;
00176 }
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192 FitPoint FitPoint::SetLength( double NewLen )
00193 {
00194 FitPoint Result(x, y);
00195
00196 double Len = Length();
00197 if (Len != 0.0)
00198 {
00199 Len = NewLen/Len ;
00200 Result.x *= Len;
00201 Result.y *= Len;
00202 }
00203
00204 return Result;
00205 }
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222 FitPoint operator + (const FitPoint& Point1, const FitPoint& Point2)
00223 {
00224 FitPoint Result;
00225
00226
00227 Result.x = Point1.x + Point2.x;
00228 Result.y = Point1.y + Point2.y;
00229
00230
00231 return Result;
00232 }
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250 FitPoint operator - (const FitPoint& Point1, const FitPoint& Point2)
00251 {
00252 FitPoint Result;
00253
00254
00255 Result.x = Point1.x - Point2.x;
00256 Result.y = Point1.y - Point2.y;
00257
00258
00259 return Result;
00260 }
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274 void FitPoint::Dump()
00275 {
00276 TRACEALL( _T("FitPoint Object (%7.2f, %7.2f)\n"), x, y );
00277 }
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305 CurveFitObject::CurveFitObject( Path* ThePath, double MaxError )
00306 {
00307
00308 LongPath = ThePath;
00309 Error = MaxError;
00310
00311
00312 Distances = NULL;
00313 PathArray = NULL;
00314 LineArray = NULL;
00315
00316 TotalStraightLines = 0;
00317 TotalCoords = 0;
00318 }
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333 CurveFitObject::~CurveFitObject()
00334 {
00335 if (Distances!=NULL)
00336 delete Distances;
00337
00338 if (PathArray!=NULL)
00339 delete PathArray;
00340
00341 if (LineArray!=NULL)
00342 delete LineArray;
00343 }
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365 BOOL CurveFitObject::Initialise(Path* CopyPath, INT32 NumPoints)
00366 {
00367
00368 PathArray = new DocCoord[NumPoints];
00369 if (PathArray==NULL)
00370 return FALSE;
00371
00372
00373 CopyPath->FindStartOfPath();
00374 DocCoord* Coords = CopyPath->GetCoordArray();
00375
00376
00377
00378 PathFlags* Flags = CopyPath->GetFlagArray();
00379 TotalStraightLines = 0;
00380 for (INT32 i=0; i<NumPoints; i++)
00381 {
00382 if (Flags[i].Spare1==TRUE)
00383 TotalStraightLines++;
00384 }
00385
00386
00387 if (TotalStraightLines>0)
00388 {
00389 LineArray = new INT32[TotalStraightLines];
00390 if (LineArray==NULL)
00391 {
00392 delete PathArray;
00393 PathArray = NULL;
00394 return FALSE;
00395 }
00396 }
00397
00398
00399 PathArray[0].x = Coords[0].x;
00400 PathArray[0].y = Coords[0].y;
00401
00402 INT32 IncludePoint = 1;
00403 INT32 StraightLinePos = 0;
00404 for (INT32 i=1; i<NumPoints; i++)
00405 {
00406
00407 if (Flags[i].Spare1==TRUE)
00408 {
00409 LineArray[StraightLinePos] = IncludePoint;
00410 StraightLinePos++;
00411 }
00412
00413
00414 if ((Coords[i].x != PathArray[IncludePoint-1].x) || (Coords[i].y != PathArray[IncludePoint-1].y) &&
00415 (i!=NumPoints-1))
00416 {
00417
00418 PathArray[IncludePoint].x = Coords[i].x;
00419 PathArray[IncludePoint].y = Coords[i].y;
00420
00421 IncludePoint++;
00422 }
00423 }
00424
00425
00426 if ((PathArray[IncludePoint-1].x != Coords[NumPoints-1].x) ||
00427 (PathArray[IncludePoint-1].y != Coords[NumPoints-1].y))
00428 {
00429 PathArray[IncludePoint].x = Coords[NumPoints-1].x;
00430 PathArray[IncludePoint].y = Coords[NumPoints-1].y;
00431 IncludePoint++;
00432 }
00433
00434
00435
00436 NumPoints = IncludePoint;
00437 if (NumPoints<2)
00438 {
00439 delete PathArray;
00440 delete LineArray;
00441 PathArray = NULL;
00442 LineArray = NULL;
00443 return FALSE;
00444 }
00445
00446
00447 Distances = new INT32[NumPoints];
00448 if (Distances==NULL)
00449 {
00450 delete PathArray;
00451 delete LineArray;
00452 PathArray = NULL;
00453 LineArray = NULL;
00454 return FALSE;
00455 }
00456
00457 Distances[0] = 0;
00458 INT32 dx, dy, min;
00459 for (INT32 i=1; i<NumPoints; i++)
00460 {
00461
00462
00463
00464
00465 dx = abs(PathArray[i].x - PathArray[i-1].x);
00466 dy = abs(PathArray[i].y - PathArray[i-1].y);
00467
00468
00469 if (dx>dy)
00470 min = dy>>1;
00471 else
00472 min = dx>>1;
00473
00474 Distances[i] = Distances[i-1] + dx + dy - min;
00475 }
00476
00477
00478 LongPath->ClearPath();
00479 LongPath->FindStartOfPath();
00480 LongPath->InsertMoveTo(PathArray[0]);
00481
00482
00483 TotalCoords = NumPoints;
00484
00485 return TRUE;
00486 }
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503 void CurveFitObject::FitCurve()
00504 {
00505 FitPoint Tangent1, Tangent2;
00506 double Angle1, Angle2;
00507 INT32 Start = 0;
00508 INT32 StraightLinePos = 0;
00509
00510 for (INT32 i=1; i<TotalCoords-1; i++)
00511 {
00512 if ((TotalStraightLines>0) && (i==LineArray[StraightLinePos]))
00513 {
00514
00515 if (Start != (i-1))
00516 {
00517
00518 Tangent1 = LeftTangent(Start);
00519 Tangent2 = RightTangent(i-1);
00520
00521
00522 FitCubic(Start, i-1, Tangent1, Tangent2);
00523 }
00524
00525
00526 InsertStraightLine(PathArray[i]);
00527 StraightLinePos++;
00528 Start = i;
00529 }
00530 else
00531 {
00532
00533 Angle1 = atan2((double)PathArray[i].y-PathArray[i-1].y, (double)PathArray[i].x-PathArray[i-1].x);
00534 Angle2 = atan2((double)PathArray[i+1].y-PathArray[i].y, (double)PathArray[i+1].x-PathArray[i].x);
00535
00536
00537 if (Angle1 < -PI) Angle1 += 2*PI;
00538 if (Angle1 > PI) Angle1 -= 2*PI;
00539 if (Angle2 < -PI) Angle2 += 2*PI;
00540 if (Angle2 > PI) Angle2 -= 2*PI;
00541
00542
00543 if ((fabs(Angle2-Angle1) > (PI/2)) && (fabs(Angle2-Angle1) <= PI))
00544 {
00545
00546 Tangent1 = LeftTangent(Start);
00547 Tangent2 = RightTangent(i);
00548
00549
00550 FitCubic(Start, i, Tangent1, Tangent2);
00551 Start = i;
00552 }
00553 }
00554 }
00555
00556
00557 INT32 End = TotalCoords-1;
00558 if ((TotalStraightLines>0) && (End==LineArray[StraightLinePos]))
00559 {
00560
00561 if (Start != (End-1))
00562 {
00563
00564 Tangent1 = LeftTangent(Start);
00565 Tangent2 = RightTangent(End-1);
00566
00567
00568 FitCubic(Start, End-1, Tangent1, Tangent2);
00569 }
00570
00571
00572 InsertStraightLine(PathArray[End]);
00573 }
00574 else
00575 {
00576
00577 Tangent1 = LeftTangent(Start);
00578 Tangent2 = RightTangent(End);
00579
00580
00581 FitCubic(Start, End, Tangent1, Tangent2);
00582 }
00583 }
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612 void CurveFitObject::FitCubic(INT32 FirstPoint, INT32 LastPoint, FitPoint Tangent1, FitPoint Tangent2,
00613 BOOL IsStartCusp, BOOL IsEndCusp)
00614 {
00615
00616 FitPoint Bezier[4];
00617 INT32 NumPoints = LastPoint - FirstPoint + 1;
00618
00619
00620 if ( NumPoints == 2 )
00621 {
00622 InsertLine(PathArray[FirstPoint], PathArray[LastPoint], Tangent1, Tangent2, IsStartCusp, IsEndCusp);
00623 return;
00624 }
00625
00626
00627 if ( NumPoints == 3 )
00628 {
00629 INT32 Distance = (Distances[LastPoint] - Distances[FirstPoint]) / 3;
00630
00631
00632 Bezier[0] = PathArray[FirstPoint];
00633 Bezier[3] = PathArray[LastPoint];
00634
00635
00636 Bezier[1] = Bezier[0] + Tangent1.SetLength(Distance);
00637 Bezier[2] = Bezier[3] + Tangent2.SetLength(Distance);
00638
00639
00640 InsertBezier(Bezier, IsStartCusp, IsEndCusp);
00641 return;
00642 }
00643
00644
00645 INT32 SplitPoint;
00646 GenerateBezier(FirstPoint, LastPoint, Tangent1, Tangent2, Bezier);
00647 double MaxError = CalcMaxError(FirstPoint, LastPoint, Bezier, &SplitPoint);
00648
00649 if (MaxError < Error)
00650 {
00651
00652 InsertBezier(Bezier, IsStartCusp, IsEndCusp);
00653 return;
00654 }
00655
00656
00657 FitPoint CentTangent = CentreTangent(SplitPoint);
00658 FitCubic(FirstPoint, SplitPoint, Tangent1, CentTangent, IsStartCusp, FALSE);
00659
00660 CentTangent = -CentTangent;
00661 FitCubic(SplitPoint, LastPoint, CentTangent, Tangent2, FALSE, IsEndCusp);
00662 }
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688 void CurveFitObject::GenerateBezier(INT32 FirstPoint, INT32 LastPoint, FitPoint Tangent1,
00689 FitPoint Tangent2, FitPoint* Bezier)
00690 {
00691 INT32 NumPoints = LastPoint - FirstPoint + 1;
00692
00693
00694 FitPoint A[STEP_SIZE+1][2];
00695 double Offsets[STEP_SIZE+1];
00696
00697 INT32 step = (NumPoints+STEP_SIZE) / STEP_SIZE;
00698 INT32 i, pos = 0;
00699
00700
00701 const INT32 DistToEnd = Distances[LastPoint] - Distances[FirstPoint];
00702 for (i=FirstPoint; i<LastPoint+1; i+=step)
00703 {
00704 Offsets[pos] = Distances[i] - Distances[FirstPoint];
00705 Offsets[pos] /= DistToEnd;
00706
00707
00708 A[pos][0] = Tangent1.SetLength( Bezier1(Offsets[pos]) );
00709 A[pos][1] = Tangent2.SetLength( Bezier2(Offsets[pos]) );
00710
00711
00712 pos++;
00713 }
00714
00715
00716
00717
00718
00719 double C[2][2];
00720 double X[2];
00721
00722 C[0][0] = 0.0;
00723 C[0][1] = 0.0;
00724 C[1][0] = 0.0;
00725 C[1][1] = 0.0;
00726 X[0] = 0.0;
00727 X[1] = 0.0;
00728
00729 FitPoint FirstCoord = PathArray[FirstPoint];
00730 FitPoint LastCoord = PathArray[LastPoint];
00731 FitPoint ThisCoord, Combo;
00732
00733 pos = 0;
00734 for (i=0; i<NumPoints; i+=step)
00735 {
00736 C[0][0] += A[pos][0].SquaredLength();
00737 C[0][1] += A[pos][0].Dot(A[pos][1]);
00738
00739 C[1][1] += A[pos][1].SquaredLength();
00740
00741
00742 ThisCoord = PathArray[FirstPoint+i];
00743 Combo = ThisCoord - ((FirstCoord * Bezier0(Offsets[pos]))
00744 + (FirstCoord * Bezier1(Offsets[pos]))
00745 + (LastCoord * Bezier2(Offsets[pos]))
00746 + (LastCoord * Bezier3(Offsets[pos])));
00747
00748
00749 X[0] += A[pos][0].Dot( Combo );
00750 X[1] += A[pos][1].Dot( Combo );
00751
00752 pos++;
00753 }
00754
00755
00756 C[1][0] = C[0][1];
00757
00758
00759 double det_C0_C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1];
00760 double det_C0_X = C[0][0] * X[1] - C[0][1] * X[0];
00761 double det_X_C1 = X[0] * C[1][1] - X[1] * C[0][1];
00762
00763
00764 if (det_C0_C1 == 0.0)
00765 det_C0_C1 = (C[0][0] * C[1][1]) * 10e-12;
00766
00767 double AlphaLeft = det_X_C1 / det_C0_C1;
00768 double AlphaRight = det_C0_X / det_C0_C1;
00769
00770 Bezier[0] = PathArray[FirstPoint];
00771 Bezier[3] = PathArray[LastPoint];
00772
00773
00774
00775 if ( AlphaLeft < 0.0 || AlphaRight < 0.0)
00776 {
00777 INT32 Distance = (Distances[LastPoint] - Distances[FirstPoint]) / 3;
00778
00779 Bezier[1] = Bezier[0] + Tangent1.SetLength(Distance);
00780 Bezier[2] = Bezier[3] + Tangent2.SetLength(Distance);
00781 }
00782 else
00783 {
00784 Bezier[1] = Bezier[0] + Tangent1.SetLength(AlphaLeft);
00785 Bezier[2] = Bezier[3] + Tangent2.SetLength(AlphaRight);
00786 }
00787 }
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808 FitPoint CurveFitObject::BezierPoint( FitPoint* Bez, double u)
00809 {
00810 double OneMinus = 1.0-u;
00811 double uSquared = u*u;
00812 double OneMinusSquared = OneMinus*OneMinus;
00813
00814 FitPoint Coord;
00815 Coord = Bez[0]*(OneMinusSquared*OneMinus);
00816 Coord = Coord + Bez[1]*(3.0*u*OneMinusSquared);
00817 Coord = Coord + Bez[2]*(3.0*uSquared*OneMinus);
00818 Coord = Coord + Bez[3]*(uSquared*u);
00819
00820 return Coord;
00821 }
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843 double CurveFitObject::CalcMaxError(INT32 FirstPoint, INT32 LastPoint, FitPoint* Bezier, INT32* SplitPoint)
00844 {
00845 double Distance;
00846 double MaxDist = 0.0;
00847 double RTotalLength = 1.0/(Distances[LastPoint] - Distances[FirstPoint]);
00848 FitPoint Point;
00849
00850
00851 INT32 NumPoints = LastPoint - FirstPoint + 1;
00852 *SplitPoint = NumPoints / 2;
00853 INT32 step = (NumPoints+ERROR_STEP) / ERROR_STEP;
00854
00855
00856 for (INT32 i=FirstPoint+1; i<LastPoint; i+=step)
00857 {
00858
00859 double Offset = Distances[i] - Distances[FirstPoint];
00860 Offset *= RTotalLength;
00861
00862
00863 FitPoint Coord = PathArray[i];
00864 Point = BezierPoint(Bezier, Offset);
00865 Distance = (Point - Coord).SquaredLength();
00866 if ( Distance >= MaxDist)
00867 {
00868 MaxDist = Distance;
00869 *SplitPoint = i;
00870 }
00871 }
00872
00873 return MaxDist;
00874 }
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890 FitPoint CurveFitObject::LeftTangent(INT32 Start)
00891 {
00892 FitPoint Tangent;
00893
00894
00895 if (TotalCoords == 0)
00896 {
00897 Tangent.x = 1;
00898 Tangent.y = 0;
00899
00900 return Tangent;
00901 }
00902
00903
00904 if ((Start >= TotalCoords) || (Start < 0))
00905 Start = TotalCoords / 2;
00906
00907
00908 INT32 Forward = Start+2;
00909 if (Forward > TotalCoords-1)
00910 Forward = TotalCoords-1;
00911
00912
00913 Tangent.x = PathArray[Forward].x - PathArray[Start].x;
00914 Tangent.y = PathArray[Forward].y - PathArray[Start].y;
00915
00916
00917 if ((Tangent.x==0) && (Tangent.y==0))
00918 {
00919 TRACEALL( _T("Tangent was a zero length vector in the curve fitter (left)\n"));
00920 Tangent.x = 1;
00921 }
00922
00923 return Tangent;
00924 }
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940 FitPoint CurveFitObject::RightTangent(INT32 End)
00941 {
00942 FitPoint Tangent;
00943
00944
00945 INT32 Backward = End-2;
00946 if (Backward<0)
00947 Backward = 0;
00948
00949 Tangent.x = PathArray[Backward].x - PathArray[End].x;
00950 Tangent.y = PathArray[Backward].y - PathArray[End].y;
00951
00952
00953 if ((Tangent.x==0) && (Tangent.y==0))
00954 {
00955 TRACEALL( _T("Tangent was a zero length vector in the curve fitter (Right)\n"));
00956 Tangent.x = -1;
00957 }
00958
00959 return Tangent;
00960 }
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977 FitPoint CurveFitObject::CentreTangent(INT32 Centre)
00978 {
00979 DocCoord Left, Right;
00980 FitPoint CentreTang;
00981
00982
00983 if (TotalCoords == 0)
00984 {
00985 CentreTang.x = 1;
00986 CentreTang.y = 0;
00987
00988 return CentreTang;
00989 }
00990
00991
00992 if ((Centre >= TotalCoords) || (Centre < 0))
00993 Centre = TotalCoords / 2;
00994
00995
00996 INT32 Forward = Centre+2;
00997 if (Forward > TotalCoords-1)
00998 Forward = TotalCoords-1;
00999
01000
01001 INT32 Backward = Centre-2;
01002 if (Backward < 0)
01003 Backward = 0;
01004
01005
01006 Left.x = PathArray[Backward].x - PathArray[Centre].x;
01007 Left.y = PathArray[Backward].y - PathArray[Centre].y;
01008
01009
01010 Right.x = PathArray[Centre].x - PathArray[Forward].x;
01011 Right.y = PathArray[Centre].y - PathArray[Forward].y;
01012
01013
01014 CentreTang.x = (Left.x + Right.x) / 2.0;
01015 CentreTang.y = (Left.y + Right.y) / 2.0;
01016
01017
01018 if ((CentreTang.x==0) && (CentreTang.y==0))
01019 {
01020 TRACEALL( _T("Tangent was a zero length vector in the curve fitter (Cent)\n"));
01021 CentreTang.x = 1;
01022 }
01023
01024
01025 return CentreTang;
01026 }
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043
01044
01045 void CurveFitObject::InsertBezier(FitPoint* Bezier, BOOL IsStartCusp, BOOL IsEndCusp)
01046 {
01047
01048 PathFlags Flags;
01049 Flags.IsSelected = FALSE;
01050 Flags.IsSmooth = FALSE;
01051 Flags.IsRotate = TRUE;
01052
01053
01054 LongPath->InsertCurveTo( DocCoord( (INT32)Bezier[1].x, (INT32)Bezier[1].y),
01055 DocCoord( (INT32)Bezier[2].x, (INT32)Bezier[2].y),
01056 DocCoord( (INT32)Bezier[3].x, (INT32)Bezier[3].y), &Flags);
01057
01058
01059 if (IsStartCusp || IsEndCusp)
01060 {
01061
01062 PathFlags* AllFlags = LongPath->GetFlagArray();
01063 INT32 NumCoords = LongPath->GetNumCoords();
01064
01065 if (IsStartCusp)
01066 {
01067
01068 AllFlags[NumCoords-3].IsRotate = FALSE;
01069 }
01070
01071 if (IsEndCusp)
01072 {
01073
01074 AllFlags[NumCoords-2].IsRotate = FALSE;
01075 AllFlags[NumCoords-1].IsRotate = FALSE;
01076 }
01077 }
01078 }
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102 void CurveFitObject::InsertLine(const DocCoord& Start, const DocCoord& End,
01103 FitPoint Tangent1, FitPoint Tangent2, BOOL IsStartCusp, BOOL IsEndCusp)
01104 {
01105
01106 PathFlags Flags;
01107 Flags.IsSelected = FALSE;
01108 Flags.IsSmooth = FALSE;
01109 Flags.IsRotate = TRUE;
01110
01111
01112 FitPoint StartPos(Start);
01113 FitPoint EndPos(End);
01114 FitPoint DistanceVect = EndPos - StartPos;
01115 INT32 Length = (INT32)DistanceVect.Length() / 3;
01116
01117
01118 Tangent1 = Tangent1.SetLength(Length);
01119 Tangent2 = Tangent2.SetLength(Length);
01120
01121
01122 StartPos = StartPos + Tangent1;
01123 EndPos = EndPos + Tangent2;
01124
01125
01126 LongPath->InsertCurveTo( DocCoord( (INT32)StartPos.x, (INT32)StartPos.y ),
01127 DocCoord( (INT32)EndPos.x, (INT32)EndPos.y ),
01128 End, &Flags);
01129
01130
01131 if (IsStartCusp || IsEndCusp)
01132 {
01133
01134 PathFlags* AllFlags = LongPath->GetFlagArray();
01135 INT32 NumCoords = LongPath->GetNumCoords();
01136
01137 if (IsStartCusp)
01138 {
01139
01140 AllFlags[NumCoords-3].IsRotate = FALSE;
01141 }
01142
01143 if (IsEndCusp)
01144 {
01145
01146 AllFlags[NumCoords-2].IsRotate = FALSE;
01147 AllFlags[NumCoords-1].IsRotate = FALSE;
01148 }
01149 }
01150 }
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169 void CurveFitObject::InsertStraightLine(const DocCoord& End)
01170 {
01171
01172 PathFlags Flags;
01173 Flags.IsSelected = FALSE;
01174 Flags.IsRotate = FALSE;
01175 Flags.IsSmooth = FALSE;
01176
01177
01178 LongPath->InsertLineTo(End, &Flags);
01179 }
01180
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195 void FitCurveNoChangeGeometry::SmoothPath(Path * pPath, double Error)
01196 {
01197 Path SubPath;
01198 SubPath.Initialise();
01199
01200 Path QuantPath;
01201 QuantPath.Initialise();
01202
01203 Path RetnPath;
01204 RetnPath.Initialise();
01205
01206
01207 INT32 NumSubPaths = pPath->GetNumSubpaths();
01208 for (INT32 i = 0; i < NumSubPaths ; i++)
01209 {
01210
01211 SubPath.ClearPath();
01212 pPath->MakePathFromSubPath(i, &SubPath);
01213
01214
01215 QuantPath.ClearPath();
01216 SubPath.Quantise(20, &QuantPath);
01217
01218 SmoothPathNoChangeGeometry(&QuantPath, Error);
01219 EliminateColinearPointsFromPath(&QuantPath);
01220
01221 RetnPath.MergeTwoPaths(QuantPath);
01222 }
01223
01224 pPath->ClearPath();
01225 pPath->CloneFrom(RetnPath);
01226 }
01227
01228
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241 void FitCurveNoChangeGeometry::SmoothPathNoChangeGeometry(Path * pPath, double Error)
01242 {
01243 INT32 StartIndex = 0;
01244 INT32 EndIndex = 0;
01245
01246 NormCoord Vec1;
01247 NormCoord Vec2;
01248
01249 double dot = 0;
01250
01251
01252 const double Thres = cos(30.0 * 3.142 / 180.0);
01253
01254 for (INT32 i = 0 ; i < pPath->GetNumCoords(); i++)
01255 {
01256 if (i < pPath->GetNumCoords() - 2)
01257 {
01258 Vec1.x = pPath->GetCoordArray()[i+1].x - pPath->GetCoordArray()[i].x;
01259 Vec1.y = pPath->GetCoordArray()[i+1].y - pPath->GetCoordArray()[i].y;
01260
01261 Vec2.x = pPath->GetCoordArray()[i+2].x - pPath->GetCoordArray()[i+1].x;
01262 Vec2.y = pPath->GetCoordArray()[i+2].y - pPath->GetCoordArray()[i+1].y;
01263
01264 Vec1.Normalise();
01265 Vec2.Normalise();
01266
01267 dot = (Vec1.x * Vec2.x) + (Vec1.y * Vec2.y);
01268
01269 if (dot < Thres)
01270 {
01271
01272 }
01273 else
01274 {
01275 StartIndex = i;
01276
01277
01278 while (dot > Thres && i < (pPath->GetNumCoords() - 2))
01279 {
01280 i++;
01281 Vec1 = Vec2;
01282 Vec2.x = pPath->GetCoordArray()[i+2].x - pPath->GetCoordArray()[i+1].x;
01283 Vec2.y = pPath->GetCoordArray()[i+2].y - pPath->GetCoordArray()[i+1].y;
01284 Vec2.Normalise();
01285
01286 dot = (Vec1.x * Vec2.x) + (Vec1.y * Vec2.y);
01287 }
01288
01289 i--;
01290
01291 EndIndex = i+1;
01292
01293
01294 if (EndIndex > StartIndex && EndIndex < pPath->GetNumCoords())
01295 {
01296 pPath->SmoothSection(StartIndex, &EndIndex, Error, 0);
01297 }
01298
01299 i = EndIndex+1;
01300 }
01301 }
01302 }
01303 }
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313
01314
01315
01316 void FitCurveNoChangeGeometry::EliminateColinearPointsFromPath(Path * pPath)
01317 {
01318
01319 pPath->InitialiseFlags();
01320
01321 NormCoord Vec1, Vec2;
01322 double dot = 0;
01323
01324
01325 BOOL bClose = FALSE;
01326
01327 if ((pPath->GetVerbArray()[pPath->GetNumCoords() - 1] & PT_CLOSEFIGURE) != 0)
01328 {
01329 pPath->GetVerbArray()[pPath->GetNumCoords() - 1] -= PT_CLOSEFIGURE;
01330 bClose = TRUE;
01331 }
01332
01333 INT32 StartIndex = 0;
01334 INT32 MidIndex = 0;
01335 INT32 EndIndex = 0;
01336
01337
01338 const double Thres = cos (1.0 * 3.142 / 180.0);
01339
01340 BOOL bDelete = FALSE;
01341
01342 for (INT32 i = 0 ; i < pPath->GetNumCoords() - 2;
01343 i ++)
01344 {
01345
01346 StartIndex = -1;
01347 MidIndex = -1;
01348 EndIndex = -1;
01349
01350 if (pPath->GetVerbArray()[i] == PT_MOVETO ||
01351 pPath->GetVerbArray()[i] == PT_LINETO)
01352 {
01353 StartIndex = i;
01354 MidIndex = i+1;
01355 }
01356 else if (pPath->GetVerbArray()[i] == PT_BEZIERTO)
01357 {
01358 if (pPath->GetFlagArray()[i].IsEndPoint)
01359 {
01360 StartIndex = i;
01361 MidIndex = i + 1;
01362 }
01363 else if (i < pPath->GetNumCoords()-1 && pPath->GetFlagArray()[i+1].IsEndPoint)
01364 {
01365 StartIndex = i + 1;
01366 MidIndex = i + 2;
01367 }
01368 else if (i < pPath->GetNumCoords()-2 && pPath->GetFlagArray()[i+2].IsEndPoint)
01369 {
01370 StartIndex = i + 2;
01371 MidIndex = i + 3;
01372 }
01373 else
01374 {
01375 ERROR3("Path Flags not initialised");
01376 }
01377 }
01378 else
01379 {
01380 ERROR3("Unrecognised path element");
01381 }
01382
01383
01384 if (StartIndex >= 0 && MidIndex >= 0)
01385 {
01386 if (pPath->GetVerbArray()[MidIndex] == PT_LINETO ||
01387 pPath->GetVerbArray()[MidIndex] == PT_MOVETO)
01388 {
01389 EndIndex = MidIndex + 1;
01390 }
01391 else if (pPath->GetVerbArray()[MidIndex] == PT_BEZIERTO)
01392 {
01393 EndIndex = MidIndex + 3;
01394 }
01395 else
01396 {
01397 ERROR3("Unrecognised path element");
01398 }
01399 }
01400
01401
01402 if (StartIndex >= 0 && MidIndex >= 0 && EndIndex >= 0)
01403 {
01404 bDelete = TRUE;
01405
01406 if (EndIndex < StartIndex + 2)
01407 bDelete = FALSE;
01408
01409 for (INT32 j = StartIndex; j <= EndIndex-2; j++)
01410 {
01411 if (j == StartIndex)
01412 {
01413 Vec1.x = pPath->GetCoordArray()[j+1].x - pPath->GetCoordArray()[j].x;
01414 Vec1.y = pPath->GetCoordArray()[j+1].y - pPath->GetCoordArray()[j].y;
01415 Vec1.Normalise();
01416 }
01417 else
01418 {
01419 Vec1 = Vec2;
01420 }
01421
01422 Vec2.x = pPath->GetCoordArray()[j+2].x - pPath->GetCoordArray()[j+1].x;
01423 Vec2.y = pPath->GetCoordArray()[j+2].y - pPath->GetCoordArray()[j+1].y;
01424
01425 Vec2.Normalise();
01426
01427 dot = (Vec1.x * Vec2.x) + (Vec1.y * Vec2.y);
01428
01429 if (dot < Thres)
01430 {
01431
01432 bDelete = FALSE;
01433 break;
01434 }
01435 else
01436 {
01437 bDelete = TRUE;
01438 }
01439 }
01440
01441 if (bDelete)
01442 {
01443 if (pPath->GetVerbArray()[MidIndex] == PT_LINETO)
01444 {
01445
01446 pPath->DeleteSection(MidIndex, 1);
01447 }
01448 else if (pPath->GetVerbArray()[MidIndex] == PT_BEZIERTO)
01449 {
01450 pPath->DeleteSection(MidIndex, 3);
01451 }
01452
01453
01454 i --;
01455 }
01456 }
01457 }
01458
01459 if (bClose)
01460 {
01461 pPath->GetVerbArray()[pPath->GetNumCoords() - 1] |= PT_CLOSEFIGURE;
01462 }
01463 }