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 #include "camtypes.h"
00101
00102 #include "pathstrk.h"
00103
00104
00105 #include "pathtrap.h"
00106 #include "valfunc.h"
00107
00108
00109
00110 #include "colormgr.h"
00111 #include "dbugtree.h"
00112
00113
00114 #include "layer.h"
00115 #include "nodepath.h"
00116
00117
00118
00119 CC_IMPLEMENT_MEMDUMP(PathStroker, CC_CLASS_MEMDUMP)
00120 CC_IMPLEMENT_MEMDUMP(PathStrokerVector, PathStroker)
00121
00122
00123
00124 #define new CAM_DEBUG_NEW
00125
00126
00128
00130
00131 const double Flatness = 350.0;
00132 const double Flatness2 = Flatness*Flatness;
00133
00134 const INT32 MaxRecursionDepth = 20;
00135
00136
00137
00138
00140
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155 PathStroker::PathStroker()
00156 {
00157 ERROR3("Please don't use this PathStroker constructor again");
00158 }
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176 PathStroker::PathStroker(ValueFunction *WidthFunction, INT32 LineWidth, LineCapType CapType)
00177 {
00178 ERROR3IF(WidthFunction == NULL, "Illegal NULL param");
00179 pWidthFunction = WidthFunction;
00180
00181 MaxWidth = LineWidth / 2;
00182
00183 CapStyle = CapType;
00184
00185 RecursionDepth = 0;
00186 }
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231 BOOL PathStroker::StrokePath(TrapsList *pTraps, Path *pOutput)
00232 {
00233 ERROR3IF(pTraps == NULL || pOutput == NULL, "Illegal NULL params");
00234
00235
00236 for (UINT32 Index = 0; Index < pTraps->GetNumTraps(); Index++)
00237 {
00238 TrapEdgeList *pTrapEdges = pTraps->GetTrapEdgeList(Index);
00239 if (pTrapEdges->GetNumEdges() < 2)
00240 {
00241 ERROR3("No map traps when stroking! Subpath stripped\n");
00242 continue;
00243 }
00244
00245 #if FALSE
00246
00247 {
00248 for (UINT32 i = 0; i < pTrapEdges->GetNumEdges(); i++)
00249 {
00250 TrapEdge *pEdge = pTrapEdges->GetTrapEdge(i);
00251 TRACE(_T("Edge % 5d Position = %g Type = %s Centre = (%d, %d) Normal = (%g, %g)\n"),
00252 i, pEdge->Position,
00253 (pEdge->PrevTrapJoin == TrapJoin_None ? _T("N") :
00254 pEdge->PrevTrapJoin == TrapJoin_Round ? _T("R") :
00255 pEdge->PrevTrapJoin == TrapJoin_MitredOrBevelled ? _T("M") : _T("U")),
00256 pEdge->Centre.x, pEdge->Centre.y,
00257 pEdge->Normal.x, pEdge->Normal.y);
00258 }
00259 }
00260 #endif
00261
00262
00263 LineCapType CapType = CapStyle;
00264 TrapEdge *pEdge = pTrapEdges->GetLastTrapEdge();
00265 if (pEdge->PrevTrapJoin != TrapJoin_None)
00266 CapType = LineCapButt;
00267
00268
00269 pEdge = pTrapEdges->GetTrapEdge(0);
00270 INT32 Width = (INT32) (MaxWidth * pWidthFunction->GetValue(pEdge->Position));
00271 INT32 dx = (INT32) (pEdge->Normal.x * Width);
00272 INT32 dy = (INT32) (pEdge->Normal.y * Width);
00273 DocCoord StartPoint(pEdge->Centre.x + dx, pEdge->Centre.y + dy);
00274 pOutput->AddMoveTo(StartPoint);
00275
00276
00277 MapLineForwards(pTrapEdges, pOutput);
00278
00279
00280 MapLineCap(CapType, pTrapEdges->GetLastTrapEdge(), FALSE, pOutput);
00281
00282
00283 MapLineBackwards(pTrapEdges, pOutput);
00284
00285
00286 MapLineCap(CapType, pTrapEdges->GetTrapEdge(0), TRUE, pOutput);
00287
00288
00289 INT32 indCoord = pOutput->GetNumCoords() - 1;
00290 PathVerb *pVerbs = pOutput->GetVerbArray();
00291 pVerbs[indCoord] |= PT_CLOSEFIGURE;
00292 }
00293
00294 pOutput->IsFilled = TRUE;
00295 pOutput->IsStroked = FALSE;
00296
00297 #ifdef _DEBUG
00298 if(pTraps && pTraps->GetNumTraps() > 0 && pOutput)
00299 {
00300 TRACEUSER( "Matt", _T("Path stroked: %ld subpaths, (1st is %ld Traps) -> %ld Coords\n"),
00301 pTraps->GetNumTraps(), pTraps->GetTrapEdgeList(0)->GetNumEdges(),
00302 pOutput->GetNumCoords());
00303 }
00304 #endif
00305
00306 return(TRUE);
00307 }
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334 BOOL PathStroker::MapLineForwards(TrapEdgeList *pTraps, Path *pOutput)
00335 {
00336 TrapEdge *pEdge = NULL;
00337 TrapEdge *pLastEdge = NULL;
00338 INT32 Width;
00339 DocCoord LastPoint;
00340 DocCoord NewPoint;
00341
00342 for (UINT32 Index = 0; Index < pTraps->GetNumEdges(); Index++)
00343 {
00344 pLastEdge = pEdge;
00345 pEdge = pTraps->GetTrapEdge(Index);
00346
00347 Width = (INT32) (MaxWidth * pWidthFunction->GetValue(pEdge->Position));
00348 NewPoint.x = pEdge->Centre.x + (INT32) (pEdge->Normal.x * Width);
00349 NewPoint.y = pEdge->Centre.y + (INT32) (pEdge->Normal.y * Width);
00350
00351
00352
00353 if (pLastEdge != NULL)
00354 {
00355 RecursionDepth = 0;
00356 RecursiveMapLineForwards(pLastEdge, LastPoint, pEdge, NewPoint, pOutput);
00357 }
00358
00359 LastPoint = NewPoint;
00360 }
00361
00362 return(TRUE);
00363 }
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392 void PathStroker::RecursiveMapLineForwards( TrapEdge *pEdge1, DocCoord &Point1, TrapEdge *pEdge2, DocCoord &Point2, Path *pOutput)
00393 {
00394 ERROR3IF(pEdge1 == NULL || pEdge2 == NULL || pOutput == NULL, "Illegal NULL params");
00395
00396
00397
00398 TrapEdge MidEdge;
00399 MidEdge.Position = (pEdge1->Position + pEdge2->Position) / 2.0;
00400
00401
00402 MidEdge.Normal.x = (pEdge1->Normal.x + pEdge2->Normal.x) / 2.0;
00403 MidEdge.Normal.y = (pEdge1->Normal.y + pEdge2->Normal.y) / 2.0;
00404
00405 MidEdge.PrevTrapJoin = pEdge2->PrevTrapJoin;
00406 if (MidEdge.PrevTrapJoin == TrapJoin_MitredOrBevelled)
00407 {
00408
00409 double Val = (pEdge1->Normal.x * pEdge2->Normal.y) - (pEdge1->Normal.y * pEdge2->Normal.x);
00410 if (Val > 0.0)
00411 {
00412
00413
00414
00415
00416 if (fabs(pEdge2->Normal.GetLength() - 1.0) > 0.0001)
00417 return;
00418
00419 MidEdge.Normal.Normalise();
00420 }
00421 }
00422 else
00423 {
00424 MidEdge.Normal.Normalise();
00425 }
00426
00427
00428 MidEdge.Centre.x = (pEdge1->Centre.x / 2) + (pEdge2->Centre.x / 2);
00429 MidEdge.Centre.y = (pEdge1->Centre.y / 2) + (pEdge2->Centre.y / 2);
00430
00431
00432 const INT32 Width = (INT32) (MaxWidth * pWidthFunction->GetValue(MidEdge.Position));
00433 DocCoord MidPoint(MidEdge.Centre);
00434 MidPoint.x += (INT32) (MidEdge.Normal.x * Width);
00435 MidPoint.y += (INT32) (MidEdge.Normal.y * Width);
00436
00437
00438 DocCoord ApproximateMidPoint(Point1.x/2 + Point2.x/2, Point1.y/2 + Point2.y/2);
00439
00440
00441 const double dx = MidPoint.x - ApproximateMidPoint.x;
00442 const double dy = MidPoint.y - ApproximateMidPoint.y;
00443 const double Dist2 = dx * dx + dy * dy;
00444
00445 RecursionDepth++;
00446
00447
00448
00449 if ( MidEdge.PrevTrapJoin!=TrapJoin_MitredOrBevelled &&
00450 (Dist2>Flatness2 || RecursionDepth<=pWidthFunction->GetMinimumRecursionDepth()) &&
00451 RecursionDepth<=MaxRecursionDepth )
00452 {
00453
00454 RecursiveMapLineForwards(pEdge1, Point1, &MidEdge, MidPoint, pOutput);
00455 RecursiveMapLineForwards(&MidEdge, MidPoint, pEdge2, Point2, pOutput);
00456 }
00457 else
00458 {
00459 pOutput->AddLineTo(Point2);
00460 }
00461
00462 RecursionDepth--;
00463 }
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490 BOOL PathStroker::MapLineBackwards(TrapEdgeList *pTraps, Path *pOutput)
00491 {
00492 TrapEdge *pEdge = NULL;
00493 TrapEdge *pLastEdge = NULL;
00494 INT32 Width;
00495 DocCoord LastPoint;
00496 DocCoord NewPoint;
00497
00498 for (INT32 Index = pTraps->GetNumEdges() - 1; Index >= 0; Index--)
00499 {
00500 pLastEdge = pEdge;
00501 pEdge = pTraps->GetTrapEdge(Index);
00502
00503 Width = (INT32) (MaxWidth * pWidthFunction->GetValue(pEdge->Position));
00504 NewPoint.x = pEdge->Centre.x - (INT32) (pEdge->Normal.x * Width);
00505 NewPoint.y = pEdge->Centre.y - (INT32) (pEdge->Normal.y * Width);
00506
00507
00508
00509 if (pLastEdge != NULL)
00510 {
00511 RecursionDepth = 0;
00512 RecursiveMapLineBackwards(pLastEdge, LastPoint, pEdge, NewPoint, pOutput);
00513 }
00514
00515 LastPoint = NewPoint;
00516 }
00517
00518 return(TRUE);
00519 }
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548 void PathStroker::RecursiveMapLineBackwards(TrapEdge *pEdge1, DocCoord &Point1, TrapEdge *pEdge2, DocCoord &Point2, Path *pOutput)
00549 {
00550 ERROR3IF(pEdge1 == NULL || pEdge2 == NULL || pOutput == NULL, "Illegal NULL params");
00551
00552
00553
00554 TrapEdge MidEdge;
00555 MidEdge.Position = (pEdge1->Position + pEdge2->Position) / 2.0;
00556
00557
00558 MidEdge.Normal.x = (pEdge1->Normal.x + pEdge2->Normal.x) / 2.0;
00559 MidEdge.Normal.y = (pEdge1->Normal.y + pEdge2->Normal.y) / 2.0;
00560
00561
00562 MidEdge.PrevTrapJoin = pEdge1->PrevTrapJoin;
00563 if (MidEdge.PrevTrapJoin == TrapJoin_MitredOrBevelled)
00564 {
00565
00566 double Val = (pEdge1->Normal.x * pEdge2->Normal.y) - (pEdge1->Normal.y * pEdge2->Normal.x);
00567 if (Val > 0.0)
00568 {
00569
00570
00571
00572
00573 if (fabs(pEdge2->Normal.GetLength() - 1.0) > 0.0001)
00574 return;
00575
00576 MidEdge.Normal.Normalise();
00577 }
00578 }
00579 else
00580 {
00581 MidEdge.Normal.Normalise();
00582 }
00583
00584
00585 MidEdge.Centre.x = (pEdge1->Centre.x / 2) + (pEdge2->Centre.x / 2);
00586 MidEdge.Centre.y = (pEdge1->Centre.y / 2) + (pEdge2->Centre.y / 2);
00587
00588
00589 const INT32 Width = (INT32) (MaxWidth * pWidthFunction->GetValue(MidEdge.Position));
00590 DocCoord MidPoint(MidEdge.Centre);
00591 MidPoint.x -= (INT32) (MidEdge.Normal.x * Width);
00592 MidPoint.y -= (INT32) (MidEdge.Normal.y * Width);
00593
00594
00595 DocCoord ApproximateMidPoint(Point1.x/2 + Point2.x/2, Point1.y/2 + Point2.y/2);
00596
00597
00598 const double dx = MidPoint.x - ApproximateMidPoint.x;
00599 const double dy = MidPoint.y - ApproximateMidPoint.y;
00600 const double Dist2 = dx * dx + dy * dy;
00601
00602 RecursionDepth++;
00603
00604
00605
00606 if ( MidEdge.PrevTrapJoin!=TrapJoin_MitredOrBevelled &&
00607 (Dist2>Flatness2 || RecursionDepth<=pWidthFunction->GetMinimumRecursionDepth()) &&
00608 RecursionDepth<=MaxRecursionDepth )
00609 {
00610
00611
00612 RecursiveMapLineBackwards(pEdge1, Point1, &MidEdge, MidPoint, pOutput);
00613 RecursiveMapLineBackwards(&MidEdge, MidPoint, pEdge2, Point2, pOutput);
00614 }
00615 else
00616 {
00617 pOutput->AddLineTo(Point2);
00618 }
00619
00620 RecursionDepth--;
00621 }
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662 BOOL PathStroker::MapLineCap(LineCapType CapType, TrapEdge *pEdge, BOOL IsStartCap, Path *pOutput)
00663 {
00664 ERROR3IF(pEdge == NULL || pOutput == NULL, "Illegal NULL params");
00665
00666
00667
00668 const INT32 Width = (INT32) (MaxWidth * pWidthFunction->GetValue(pEdge->Position));
00669 const INT32 Orientation = (IsStartCap) ? 1 : -1;
00670 const INT32 dx = Orientation * (INT32) (pEdge->Normal.x * Width);
00671 const INT32 dy = Orientation * (INT32) (pEdge->Normal.y * Width);
00672
00673
00674 DocCoord EndPoint(pEdge->Centre.x + dx, pEdge->Centre.y + dy);
00675
00676 switch (CapType)
00677 {
00678 case LineCapButt:
00679
00680 pOutput->AddLineTo(EndPoint);
00681 break;
00682
00683
00684 case LineCapRound:
00685 {
00686
00687
00688
00689 DocCoord StartPoint(pEdge->Centre.x - dx, pEdge->Centre.y - dy);
00690 DocCoord MidPoint(pEdge->Centre.x - dy, pEdge->Centre.y + dx);
00691
00692
00693
00694 const INT32 CPdx = (INT32) ( ((double)dx) * 0.552 );
00695 const INT32 CPdy = (INT32) ( ((double)dy) * 0.552 );
00696
00697
00698 DocCoord Control1(StartPoint.x - CPdy, StartPoint.y + CPdx);
00699 DocCoord Control2(MidPoint.x - CPdx, MidPoint.y - CPdy);
00700 pOutput->AddCurveTo(Control1, Control2, MidPoint);
00701
00702
00703 DocCoord Control3(MidPoint.x + CPdx, MidPoint.y + CPdy);
00704 DocCoord Control4(EndPoint.x - CPdy, EndPoint.y + CPdx);
00705 pOutput->AddCurveTo(Control3, Control4, EndPoint);
00706 }
00707 break;
00708
00709
00710 case LineCapSquare:
00711 {
00712
00713 DocCoord StartPoint(pEdge->Centre.x - dx, pEdge->Centre.y - dy);
00714
00715 pOutput->AddLineTo(DocCoord(StartPoint.x - dy, StartPoint.y + dx));
00716 pOutput->AddLineTo(DocCoord(EndPoint.x - dy, EndPoint.y + dx));
00717 pOutput->AddLineTo(EndPoint);
00718 }
00719 break;
00720
00721 default:
00722 ERROR3("Unknown line cap style");
00723 break;
00724 }
00725
00726 return(TRUE);
00727 }
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749 BOOL PathStroker::StrokeSmoothPath(TrapsList *pTraps, Path *pOutput)
00750 {
00751 ERROR3IF(pTraps == NULL || pOutput == NULL, "Illegal NULL params");
00752
00753
00754 for (UINT32 Index = 0; Index < pTraps->GetNumTraps(); Index++)
00755 {
00756 TrapEdgeList *pTrapEdges = pTraps->GetTrapEdgeList(Index);
00757 if (pTrapEdges->GetNumEdges() < 2)
00758 {
00759 ERROR3("No map traps when stroking! Subpath stripped\n");
00760 continue;
00761 }
00762
00763
00764 LineCapType CapType = CapStyle;
00765 TrapEdge *pEdge = pTrapEdges->GetLastTrapEdge();
00766 if (pEdge->PrevTrapJoin != TrapJoin_None)
00767 CapType = LineCapButt;
00768
00769
00770 pEdge = pTrapEdges->GetTrapEdge(0);
00771 INT32 Width = (INT32) (MaxWidth * pWidthFunction->GetValue(pEdge->Position));
00772 INT32 dx = (INT32) (pEdge->Normal.x * Width);
00773 INT32 dy = (INT32) (pEdge->Normal.y * Width);
00774 DocCoord StartPoint(pEdge->Centre.x + dx, pEdge->Centre.y + dy);
00775 pOutput->AddMoveTo(StartPoint);
00776
00777 INT32 first = 0;
00778 INT32 last = -1;
00779
00780
00781 MapLineForwards(pTrapEdges, pOutput);
00782 pOutput->SmoothSection(first, &last, 1.25 * Flatness, 0);
00783
00784
00785
00786 double height = pWidthFunction->GetValue(1);
00787 if (height > 0.05)
00788 {
00789 MapLineCap(CapType, pTrapEdges->GetLastTrapEdge(), FALSE, pOutput);
00790 }
00791
00792
00793 first = pOutput->GetNumCoords() - 1;
00794 MapLineBackwards(pTrapEdges, pOutput);
00795 last = -1l;
00796 pOutput->SmoothSection(first, &last, 1.25 * Flatness, 0);
00797
00798
00799 INT32 indCoord;
00800 PathVerb *pVerbs = pOutput->GetVerbArray();
00801
00802
00803 for( indCoord = 0; indCoord < pOutput->GetNumCoords() - 2; indCoord++ )
00804 {
00805 pVerbs[indCoord] &= ~PT_CLOSEFIGURE;
00806 }
00807
00808 indCoord = pOutput->GetNumCoords() - 1;
00809
00810
00811 if (!(pVerbs[indCoord] & PT_CLOSEFIGURE))
00812 {
00813
00814 MapLineCap(CapType, pTrapEdges->GetTrapEdge(0), TRUE, pOutput);
00815
00816
00817 indCoord = pOutput->GetNumCoords() - 1;
00818 PathVerb *pVerbs = pOutput->GetVerbArray();
00819 pVerbs[indCoord] |= PT_CLOSEFIGURE;
00820 }
00821 }
00822
00823 pOutput->IsFilled = TRUE;
00824 pOutput->IsStroked = FALSE;
00825
00826 TRACEUSER( "Matt", _T("Path SMOOTHLY stroked: %ld subpaths, (1st is %ld Traps) -> %ld Coords\n"),
00827 pTraps->GetNumTraps(), pTraps->GetTrapEdgeList(0)->GetNumEdges(),
00828 pOutput->GetNumCoords());
00829
00830 return(TRUE);
00831 }
00832
00833
00834
00835
00836
00837
00839
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860 PathStrokerVector::PathStrokerVector(ValueFunction *WidthFunction, INT32 LineWidth,
00861 LineCapType CapType, DocRect *pSourceBounds)
00862 : PathStroker(WidthFunction, LineWidth, CapType)
00863
00864 {
00865 ERROR3IF(pSourceBounds == NULL , "Illegal NULL params");
00866
00867 pPath = NULL;
00868 pBounds = pSourceBounds;
00869 BoundsYCentre = (double) (pSourceBounds->lo.y/2 + pSourceBounds->hi.y/2);
00870 BoundsWidth = (double) pSourceBounds->Width();
00871 BoundsHalfHeight = (double) pSourceBounds->Height() / 2.0;
00872 pOutput = NULL;
00873 pCurrentEdgeList = NULL;
00874 FirstEdge = 0;
00875 LastEdge = 0;
00876 }
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902 void PathStrokerVector::PrepareToStroke(TrapEdgeList *pTraps)
00903 {
00904
00905 ERROR3IF(pTraps == NULL, "Illegal NULL param");
00906 pCurrentEdgeList = pTraps;
00907
00908
00909 FirstEdge = LastEdge = 0;
00910 }
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925 BOOL PathStrokerVector::StrokePath(TrapsList *pTraps, Path *pOutput)
00926 {
00927 ERROR2(FALSE, "Do not call this variant of Strokepath()");
00928 }
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973 BOOL PathStrokerVector::StrokePath(Path *pSourceVector, Path *pOutputPath)
00974 {
00975 ERROR3IF(pCurrentEdgeList == NULL || pBounds == NULL, "Call PrepareToStroke first!");
00976 ERROR3IF(pSourceVector == NULL || pOutputPath == NULL, "Illegal NULL params");
00977
00978 if (BoundsWidth <= 0.0 || BoundsHalfHeight <= 0.0)
00979 return(FALSE);
00980
00981 pPath = pSourceVector;
00982 pOutput = pOutputPath;
00983
00984
00985 DocRect PathBounds = pPath->GetBoundingRect();
00986 const double MinPathPos = ((double)(PathBounds.lo.x - pBounds->lo.x)) / BoundsWidth;
00987 const double MaxPathPos = ((double)(PathBounds.hi.x - pBounds->lo.x)) / BoundsWidth;
00988
00989
00990
00991
00992 {
00993 TrapEdge *pLastEdge = pCurrentEdgeList->GetLastTrapEdge();
00994 if (pLastEdge != NULL && MinPathPos > pLastEdge->Position)
00995 return(TRUE);
00996 }
00997
00998
00999
01000 DocCoord *pCoords = pPath->GetCoordArray();
01001 PathVerb *pVerbs = pPath->GetVerbArray();
01002 const INT32 NumCoords = pPath->GetNumCoords();
01003
01004
01005
01006 FirstEdge = pCurrentEdgeList->FindTrapEdge(MinPathPos, 0, 0);
01007 LastEdge = pCurrentEdgeList->FindTrapEdge(MaxPathPos, FirstEdge, pCurrentEdgeList->GetNumEdges() - 1);
01008
01009
01010 INT32 Element = 0;
01011 while (Element < NumCoords)
01012 {
01013 switch (pVerbs[Element] & ~PT_CLOSEFIGURE)
01014 {
01015 case PT_MOVETO:
01016 MapMove(&pCoords[Element]);
01017 break;
01018
01019 case PT_LINETO:
01020 {
01021 ERROR3IF(Element < 1, "Path has LINETO as first element?!");
01022
01023 RecursionDepth = 0;
01024 MapLine(&pCoords[Element-1], &pCoords[Element]);
01025
01026 if ((pVerbs[Element] & PT_CLOSEFIGURE) != 0)
01027 {
01028
01029 PathVerb *pOutVerbs = pOutput->GetVerbArray();
01030 ERROR3IF(pOutVerbs == NULL || pOutput->GetNumCoords() < 1, "Oh dear. That shouldn't be like that");
01031 pOutVerbs[pOutput->GetNumCoords() - 1] |= PT_CLOSEFIGURE;
01032 }
01033 }
01034 break;
01035
01036 case PT_BEZIERTO:
01037 {
01038 ERROR3IF(Element < 1, "Path has BEZIERTO as first element?!");
01039
01040 RecursionDepth = 0;
01041 MapBezier(&pCoords[Element-1]);
01042
01043 if ((pVerbs[Element+2] & PT_CLOSEFIGURE) != 0)
01044 {
01045
01046 PathVerb *pOutVerbs = pOutput->GetVerbArray();
01047 ERROR3IF(pOutVerbs == NULL || pOutput->GetNumCoords() < 1, "Oh dear. That shouldn't be like that");
01048 pOutVerbs[pOutput->GetNumCoords() - 1] |= PT_CLOSEFIGURE;
01049 }
01050
01051 Element += 2;
01052 }
01053 break;
01054
01055 default:
01056 ERROR3("PathStrokerVector::StrokePath() - unknown path verb!");
01057 break;
01058 }
01059
01060 Element++;
01061 }
01062
01063 pOutput->IsFilled = pSourceVector->IsFilled;
01064 pOutput->IsStroked = pSourceVector->IsStroked;
01065
01066 return(TRUE);
01067 }
01068
01069
01070
01071
01072
01073
01074
01075
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
01103 void PathStrokerVector::FindEdgeForCoord(DocCoord *pCoord, UINT32 StartIndex, INT32 Direction,
01104 TrapEdge *pOutput)
01105 {
01106 ERROR3IF(pCurrentEdgeList == NULL || pBounds == NULL, "Call PrepareToStroke first!");
01107 ERROR3IF(pCoord == NULL || pOutput == NULL, "Illegal NULL params");
01108
01109
01110 pOutput->Position = ((double)(pCoord->x - pBounds->lo.x)) / BoundsWidth;
01111
01112
01113
01114
01115 if (pOutput->Position < 0.0 || pOutput->Position > 1.0)
01116 {
01117
01118 TrapEdge *pEdge1;
01119 if (pOutput->Position > 1.0)
01120 {
01121 pEdge1 = pCurrentEdgeList->GetLastTrapEdge();
01122 pOutput->Position -= 1.0;
01123 }
01124 else
01125 pEdge1 = pCurrentEdgeList->GetTrapEdge(0);
01126
01127
01128
01129 const double PathLength = pCurrentEdgeList->GetPathLength();
01130 pOutput->Centre.x = pEdge1->Centre.x - (INT32) (pOutput->Position * PathLength * (-pEdge1->Normal.y));
01131 pOutput->Centre.y = pEdge1->Centre.y - (INT32) (pOutput->Position * PathLength * pEdge1->Normal.x);
01132
01133
01134 pOutput->Normal = pEdge1->Normal;
01135 pOutput->PrevTrapJoin = pEdge1->PrevTrapJoin;
01136
01137
01138
01139 if (pOutput->Position < 0.0)
01140 pOutput->Position = 0.0;
01141 else
01142 pOutput->Position = 1.0;
01143 return;
01144 }
01145
01146
01147
01148
01149
01150
01151 UINT32 TrapIndex = pCurrentEdgeList->FindTrapEdge(pOutput->Position, StartIndex, 0);
01152 TrapEdge *pEdge1 = pCurrentEdgeList->GetTrapEdge(TrapIndex);
01153
01154
01155 if (pOutput->Position <= pEdge1->Position || (TrapIndex >= pCurrentEdgeList->GetNumEdges() - 1))
01156 {
01157
01158
01159
01160
01161 pOutput->Normal = pEdge1->Normal;
01162 pOutput->Centre = pEdge1->Centre;
01163 if (Direction > 0 && TrapIndex < pCurrentEdgeList->GetNumEdges() - 1)
01164 {
01165 TrapEdge *pEdge2 = pCurrentEdgeList->GetTrapEdge(TrapIndex+1);
01166 pOutput->PrevTrapJoin = pEdge2->PrevTrapJoin;
01167 }
01168 else
01169 pOutput->PrevTrapJoin = pEdge1->PrevTrapJoin;
01170 }
01171 else
01172 {
01173
01174
01175 TrapEdge *pEdge2 = pCurrentEdgeList->GetTrapEdge(TrapIndex+1);
01176 ERROR3IF(pEdge2->Position <= pEdge1->Position, "Non-ascending trapezoid positions?!");
01177
01178
01179 const double Fraction = (pOutput->Position - pEdge1->Position) / (pEdge2->Position - pEdge1->Position);
01180 const double InvFraction = 1.0 - Fraction;
01181
01182
01183 pOutput->Normal.x = (InvFraction * pEdge1->Normal.x) + (Fraction * pEdge2->Normal.x);
01184 pOutput->Normal.y = (InvFraction * pEdge1->Normal.y) + (Fraction * pEdge2->Normal.y);
01185 pOutput->Normal.Normalise();
01186
01187
01188 pOutput->Centre.x = (INT32) ((InvFraction * (double)pEdge1->Centre.x) + (Fraction * (double)pEdge2->Centre.x));
01189 pOutput->Centre.y = (INT32) ((InvFraction * (double)pEdge1->Centre.y) + (Fraction * (double)pEdge2->Centre.y));
01190
01191
01192
01193 if (Direction > 0)
01194 pOutput->PrevTrapJoin = pEdge2->PrevTrapJoin;
01195 else
01196 pOutput->PrevTrapJoin = pEdge1->PrevTrapJoin;
01197 }
01198 }
01199
01200
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233
01234
01235
01236
01237 DocCoord PathStrokerVector::MapCoord(DocCoord *pCoord)
01238 {
01239 ERROR3IF(pCurrentEdgeList == NULL || pBounds == NULL, "Call PrepareToStroke first!");
01240
01241
01242 TrapEdge MapEdge;
01243 FindEdgeForCoord(pCoord, FirstEdge, +1, &MapEdge);
01244 ERROR3IF(MapEdge.Position < 0.0 || MapEdge.Position > 1.0, "Position value was not properly clipped");
01245
01246
01247
01248 const double SourceDist = (((double)pCoord->y) - BoundsYCentre) / BoundsHalfHeight;
01249 const double MappedDist = ((double)MaxWidth) * SourceDist * pWidthFunction->GetValue(MapEdge.Position);
01250
01251
01252 return(DocCoord(MapEdge.Centre.x + (INT32)(MapEdge.Normal.x * MappedDist),
01253 MapEdge.Centre.y + (INT32)(MapEdge.Normal.y * MappedDist) ));
01254 }
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281 double PathStrokerVector::GetScaleFactor(void)
01282 {
01283 if (BoundsHalfHeight < 1.0)
01284 return(1.0);
01285
01286 return( ((double) MaxWidth) / BoundsHalfHeight );
01287 }
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304 void PathStrokerVector::MapMove(DocCoord *pCoord)
01305 {
01306 pOutput->AddMoveTo(MapCoord(pCoord));
01307 }
01308
01309
01310
01311
01312
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327 void PathStrokerVector::MapLine(DocCoord *pCoord1, DocCoord *pCoord2)
01328 {
01329
01330 double Position1 = ((double)(pCoord1->x - pBounds->lo.x)) / BoundsWidth;
01331 double Position2 = ((double)(pCoord2->x - pBounds->lo.x)) / BoundsWidth;
01332
01333
01334
01335
01336 const double PosRange = Position2 - Position1;
01337 if (PosRange == 0.0)
01338 {
01339 pOutput->AddLineTo(MapCoord(pCoord2));
01340 return;
01341 }
01342
01343
01344 UINT32 TrapIndex = pCurrentEdgeList->FindTrapEdge(Position1, FirstEdge, LastEdge);
01345 ERROR3IF(TrapIndex < FirstEdge || TrapIndex > LastEdge, "TrapIndex outside expected range");
01346
01347 UINT32 EndIndex = pCurrentEdgeList->FindTrapEdge(Position2, FirstEdge, LastEdge);
01348 ERROR3IF(EndIndex < FirstEdge || EndIndex > LastEdge, "Trap EndIndex outside expected range");
01349
01350
01351 TrapEdge FirstEdgeData;
01352 TrapEdge LastEdgeData;
01353 const INT32 Direction = (PosRange > 0.0) ? +1 : -1;
01354 FindEdgeForCoord(pCoord1, TrapIndex, Direction, &FirstEdgeData);
01355 FindEdgeForCoord(pCoord2, EndIndex, Direction, &LastEdgeData);
01356
01357
01358 TrapEdge *pLastEdge = &FirstEdgeData;
01359 double LastWidth = ((double)MaxWidth) *
01360 (((double)pCoord1->y - BoundsYCentre) / BoundsHalfHeight);
01361 double BaseWidth = LastWidth * pWidthFunction->GetValue(pLastEdge->Position);
01362 DocCoord LastPoint( (INT32) (pLastEdge->Centre.x + pLastEdge->Normal.x * BaseWidth),
01363 (INT32) (pLastEdge->Centre.y + pLastEdge->Normal.y * BaseWidth) );
01364
01365 TrapEdge *pEdge = NULL;
01366
01367
01368
01369 if (PosRange > 0.0)
01370 {
01371
01372
01373 TrapIndex++;
01374
01375 while (TrapIndex <= EndIndex)
01376 {
01377 pEdge = pCurrentEdgeList->GetTrapEdge(TrapIndex);
01378
01379
01380
01381
01382 const double Fraction = (pEdge->Position - Position1) / PosRange;
01383 const double Y = ((1.0 - Fraction) * (double)pCoord1->y) + (Fraction * (double)pCoord2->y);
01384 const double CentreDist = (Y - BoundsYCentre) / BoundsHalfHeight;
01385 BaseWidth = ((double)MaxWidth) * CentreDist;
01386 const double Width = BaseWidth * pWidthFunction->GetValue(pEdge->Position);
01387
01388 DocCoord NewPoint(pEdge->Centre.x + (INT32) (pEdge->Normal.x * Width),
01389 pEdge->Centre.y + (INT32) (pEdge->Normal.y * Width) );
01390
01391 RecursiveMapLine(pLastEdge, LastPoint, LastWidth,
01392 pEdge, NewPoint, BaseWidth,
01393 +1, pOutput);
01394
01395 pLastEdge = pEdge;
01396 LastWidth = BaseWidth;
01397 LastPoint = NewPoint;
01398
01399 TrapIndex++;
01400 }
01401 }
01402 else
01403 {
01404
01405
01406 while (TrapIndex > EndIndex)
01407 {
01408 pEdge = pCurrentEdgeList->GetTrapEdge(TrapIndex);
01409
01410
01411
01412
01413 const double Fraction = (pEdge->Position - Position1) / PosRange;
01414 const double Y = ((1.0 - Fraction) * (double)pCoord1->y) + (Fraction * (double)pCoord2->y);
01415 const double CentreDist = (Y - BoundsYCentre) / BoundsHalfHeight;
01416 BaseWidth = ((double)MaxWidth) * CentreDist;
01417 const double Width = BaseWidth * pWidthFunction->GetValue(pEdge->Position);
01418
01419 DocCoord NewPoint(pEdge->Centre.x + (INT32) (pEdge->Normal.x * Width),
01420 pEdge->Centre.y + (INT32) (pEdge->Normal.y * Width) );
01421
01422 RecursiveMapLine(pLastEdge, LastPoint, LastWidth,
01423 pEdge, NewPoint, BaseWidth,
01424 -1, pOutput);
01425
01426 pLastEdge = pEdge;
01427 LastWidth = BaseWidth;
01428 LastPoint = NewPoint;
01429
01430 TrapIndex--;
01431 }
01432 }
01433
01434
01435 pEdge = &LastEdgeData;
01436
01437
01438 const double CentreDist = (pCoord2->y - BoundsYCentre) / BoundsHalfHeight;
01439 BaseWidth = ((double)MaxWidth) * CentreDist;
01440 const double Width = BaseWidth * pWidthFunction->GetValue(pEdge->Position);
01441
01442 DocCoord NewPoint(pEdge->Centre.x + (INT32) (pEdge->Normal.x * Width),
01443 pEdge->Centre.y + (INT32) (pEdge->Normal.y * Width) );
01444
01445 RecursiveMapLine(pLastEdge, LastPoint, LastWidth,
01446 pEdge, NewPoint, BaseWidth,
01447 (PosRange > 0) ? +1 : -1, pOutput);
01448 }
01449
01450
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460
01461
01462
01463
01464
01465
01466
01467
01468
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484 void PathStrokerVector::RecursiveMapLine(TrapEdge *pEdge1, DocCoord &Point1, double Width1,
01485 TrapEdge *pEdge2, DocCoord &Point2, double Width2,
01486 INT32 Direction, Path *pOutput)
01487 {
01488 ERROR3IF(pEdge1 == NULL || pEdge2 == NULL || pOutput == NULL, "Illegal NULL params");
01489
01490
01491
01492
01493
01494
01495 RecursionDepth++;
01496 if (RecursionDepth > MaxRecursionDepth)
01497 {
01498 TRACEUSER( "Jason", _T(">> Recursion limit hit when stroking\n"));
01499 pOutput->AddLineTo(Point2);
01500 return;
01501 }
01502
01503
01504
01505 TrapEdge MidEdge;
01506 MidEdge.Position = (pEdge1->Position + pEdge2->Position) / 2.0;
01507
01508
01509 MidEdge.Normal.x = (pEdge1->Normal.x + pEdge2->Normal.x) / 2.0;
01510 MidEdge.Normal.y = (pEdge1->Normal.y + pEdge2->Normal.y) / 2.0;
01511
01512
01513
01514
01515
01516
01517
01518 if (Direction > 0)
01519 MidEdge.PrevTrapJoin = pEdge2->PrevTrapJoin;
01520 else
01521 MidEdge.PrevTrapJoin = pEdge1->PrevTrapJoin;
01522 if (MidEdge.PrevTrapJoin != TrapJoin_MitredOrBevelled)
01523 MidEdge.Normal.Normalise();
01524
01525
01526
01527
01528
01529 MidEdge.Centre.x = (pEdge1->Centre.x / 2) + (pEdge2->Centre.x / 2);
01530 MidEdge.Centre.y = (pEdge1->Centre.y / 2) + (pEdge2->Centre.y / 2);
01531
01532
01533 const INT32 MidWidth = (INT32) ((Width1 + Width2) / 2.0);
01534 const INT32 MidWidthAll = (INT32) ((double)MidWidth * pWidthFunction->GetValue(MidEdge.Position));
01535 DocCoord MidPoint(MidEdge.Centre);
01536 MidPoint.x += (INT32) (MidEdge.Normal.x * MidWidthAll);
01537 MidPoint.y += (INT32) (MidEdge.Normal.y * MidWidthAll);
01538
01539
01540 DocCoord ApproximateMidPoint(Point1.x/2 + Point2.x/2, Point1.y/2 + Point2.y/2);
01541
01542
01543 const double dx = MidPoint.x - ApproximateMidPoint.x;
01544 const double dy = MidPoint.y - ApproximateMidPoint.y;
01545 const double Dist2 = dx * dx + dy * dy;
01546
01547
01548
01549
01550
01551 if ( Dist2>Flatness2 || fabs(pEdge1->Position-pEdge2->Position)>0.10 )
01552 {
01553
01554 RecursiveMapLine(pEdge1, Point1, Width1, &MidEdge, MidPoint, MidWidth, Direction, pOutput);
01555 RecursiveMapLine(&MidEdge, MidPoint, MidWidth, pEdge2, Point2, Width2, Direction, pOutput);
01556 }
01557 else
01558 pOutput->AddLineTo(Point2);
01559
01560
01561 RecursionDepth--;
01562 }
01563
01564
01565
01566
01567
01568
01569
01570
01571
01572
01573
01574
01575
01576
01577
01578
01579
01580 void PathStrokerVector::MapBezier(DocCoord *pCoords)
01581 {
01582 RecursiveMapBezier(pCoords, &pCoords[0], 0.0, &pCoords[3], 1.0);
01583 }
01584
01585
01586
01587
01588
01589
01590
01591
01592
01593
01594
01595
01596
01597
01598
01599
01600
01601
01602
01603
01604
01605
01606
01607
01608
01609
01610
01611 void PathStrokerVector::RecursiveMapBezier(DocCoord *pCoords, DocCoord *p1, double t1, DocCoord *p2, double t2)
01612 {
01613
01614
01615 RecursionDepth++;
01616 if (RecursionDepth > MaxRecursionDepth)
01617 {
01618 TRACEUSER( "Jason", _T(">> Recursion limit hit when stroking\n"));
01619 pOutput->AddLineTo(MapCoord(p2));
01620 return;
01621 }
01622
01623 #define x0 (pCoords[0].x)
01624 #define y0 (pCoords[0].y)
01625 #define x1 (pCoords[1].x)
01626 #define y1 (pCoords[1].y)
01627 #define x2 (pCoords[2].x)
01628 #define y2 (pCoords[2].y)
01629 #define x3 (pCoords[3].x)
01630 #define y3 (pCoords[3].y)
01631
01632
01633 const double t = (t1 + t2) / 2.0;
01634
01635 const double tx = x1+t*(x2-x1);
01636 const double ty = y1+t*(y2-y1);
01637
01638 const double Lx1 = x0 + t*(x1-x0);
01639 const double Ly1 = y0 + t*(y1-y0);
01640 const double Rx2 = x2 + t*(x3-x2);
01641 const double Ry2 = y2 + t*(y3-y2);
01642 const double Lx2 = Lx1 + t*(tx-Lx1);
01643 const double Ly2 = Ly1 + t*(ty-Ly1);
01644 const double Rx1 = tx + t*(Rx2-tx);
01645 const double Ry1 = ty + t*(Ry2-ty);
01646 const double Rx0 = Lx2 + t*(Rx1-Lx2);
01647 const double Ry0 = Ly2 + t*(Ry1-Ly2);
01648
01649 DocCoord MidPoint((INT32)(Rx0+0.5), (INT32)(Ry0+0.5));
01650
01651 #undef x0
01652 #undef y0
01653 #undef x1
01654 #undef y1
01655 #undef x2
01656 #undef y2
01657 #undef x3
01658 #undef y3
01659
01660
01661
01662
01663
01664 double Dist2 = Flatness2;
01665
01666 if (t2 - t1 < 0.45)
01667 {
01668
01669 DocCoord ApproxMidPoint(p1->x/2 + p2->x/2, p1->y/2 + p2->y/2);
01670
01671
01672 DocCoord MappedMid = MapCoord(&MidPoint);
01673 DocCoord MappedApprox = MapCoord(&ApproxMidPoint);
01674
01675
01676 const double dx = MappedMid.x - MappedApprox.x;
01677 const double dy = MappedMid.y - MappedApprox.y;
01678 Dist2 = dx*dx + dy*dy;
01679 }
01680
01681
01682 if (Dist2 >= Flatness2)
01683 {
01684 RecursiveMapBezier(pCoords, p1, t1, &MidPoint, t);
01685 RecursiveMapBezier(pCoords, &MidPoint, t, p2, t2);
01686 }
01687 else
01688 MapLine(p1, p2);
01689
01690
01691 RecursionDepth--;
01692 }
01693
01694
01695
01696
01697
01699
01701
01702 StrokeHandle PathStrokerVector::CurrentStroke = StrokeHandle_NoStroke;
01703
01704 void PathStrokerVector::BodgeRipSelection(BOOL Repeating)
01705 {
01706 SelRange *pSel = GetApplication()->FindSelection();
01707
01708 Node *pNode = pSel->FindFirst();
01709 if (pNode == NULL || !IS_A(pNode, NodeGroup))
01710 {
01711 ERROR3("Brush can only be made from a selected GROUP");
01712 return;
01713 }
01714
01715 NodeGroup* pNewGroup = new NodeGroup;
01716 if (pNewGroup == NULL)
01717 {
01718 ERROR3("Couldn't create new brush (1)");
01719 return;
01720 }
01721
01722 NodeGroup* pNewGroup1 = new NodeGroup;
01723 if (pNewGroup1 == NULL)
01724 {
01725 ERROR3("Couldn't create new brush (2)");
01726 delete pNewGroup;
01727 return;
01728 }
01729
01730
01731 pNewGroup->AttachNode(pNode, NEXT);
01732 pNewGroup1->AttachNode(pNewGroup, FIRSTCHILD);
01733
01734
01735
01736
01737
01738
01739 if (!pNode->CopyChildrenTo(pNewGroup1) ||
01740 !pNewGroup->MakeAttributeComplete(NULL, TRUE, NULL, TRUE))
01741 {
01742
01743 ERROR3("Couldn't create new brush (3)");
01744 pNewGroup->CascadeDelete();
01745 delete pNewGroup;
01746 return;
01747 }
01748
01749
01750
01751 {
01752 Node *pCurNode = pNewGroup->FindFirstDepthFirst();
01753 Node *pNextNode;
01754
01755 while (pCurNode !=NULL)
01756 {
01757
01758 pNextNode = pCurNode->FindNextDepthFirst(pNewGroup);
01759
01760
01761 if (pCurNode->IsAnAttribute())
01762 {
01763 UINT32 Context = 0;
01764 NodeAttribute *pNodeAttr = (NodeAttribute *) pCurNode;
01765
01766
01767 DocColour *pColour = pNodeAttr->EnumerateColourFields(Context++);
01768
01769 while (pColour != NULL)
01770 {
01771
01772
01773 if (pColour->FindParentIndexedColour() != NULL)
01774 {
01775 ColourGeneric ColDef;
01776 ColourContext *cc = ColourManager::GetColourContext(pColour->GetColourModel());
01777 ERROR3IF(cc == NULL, "Can't find colour context?!");
01778
01779
01780 cc->ConvertColour(pColour->FindParentIndexedColour(), &ColDef);
01781
01782
01783 *pColour = DocColour(pColour->GetColourModel(), &ColDef);
01784 }
01785
01786 pColour = pNodeAttr->EnumerateColourFields(Context++);
01787 }
01788 }
01789 pCurNode = pNextNode;
01790 }
01791 }
01792
01793
01794 pNewGroup->UnlinkNodeFromTree();
01795
01796
01797
01798 Spread *pBrush = new Spread;
01799 if (pBrush == NULL)
01800 {
01801 ERROR3("Couldn't create new brush (4)");
01802 pNewGroup->CascadeDelete();
01803 delete pNewGroup;
01804 return;
01805 }
01806
01807 Layer *pBrushLayer = new Layer(pBrush, FIRSTCHILD, String_256(TEXT("Jason did this")));
01808 if (pBrushLayer == NULL)
01809 {
01810 ERROR3("Couldn't create new brush (5)");
01811 delete pBrush;
01812 pNewGroup->CascadeDelete();
01813 delete pNewGroup;
01814 return;
01815 }
01816
01817
01818 pNewGroup->AttachNode(pBrushLayer, FIRSTCHILD, FALSE, TRUE);
01819
01820 StrokeDefinition *pStrokeDef = new StrokeDefinition(pBrush, Repeating);
01821 if (pStrokeDef == NULL)
01822 {
01823 ERROR3("Couldn't create new brush (6)");
01824 pBrush->CascadeDelete();
01825 delete pBrush;
01826 return;
01827 }
01828
01829 CurrentStroke = StrokeComponent::AddNewStroke(pStrokeDef);
01830
01831
01832 }
01833
01834 StrokeHandle PathStrokerVector::GetCurrentBrush(void)
01835 {
01836 return(CurrentStroke);
01837 }
01838