bevtrap.cpp

Go to the documentation of this file.
00001 // $Id: bevtrap.cpp 1282 2006-06-09 09:46:49Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 #include "camtypes.h"
00099 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00100 #include "pathproc.h"
00101 #include "pathtrap.h"
00102 #include "bevtrap.h"
00103 #include "beveler.h"
00104 #include "ppbevel.h"
00105 
00106 CC_IMPLEMENT_DYNCREATE(CCreateBevelTrapezoids, CCObject)
00107 
00108 /********************************************************************************************
00109 >   BOOL CCreateBevelTrapezoids::ProcessPath(Path * pPath, TrapsList *RetnTraps, INT32 indent);
00110 
00111     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00112     Created:    20/11/98
00113     Purpose:    Turns the path into trapezoids which can be used for the bevelling
00114     Inputs:     The source path and the trapezoid list (already initialised) to use
00115     Returns:    -
00116     Coments:    Only works on single paths i.e. only ones with PT_MOVETO as coord (0) and
00117                 no-where else. In other words, no sub-paths are allowed.
00118     SeeAlso:    -
00119 
00120 ********************************************************************************************/
00121 #if 0 // It is not clear what was commented out here and when and why - there are 3 ProcessPath functions! - AB20060106
00122 /*
00123 BOOL CCreateBevelTrapezoids::ProcessPath(Path * pPath, TrapsList *RetnTraps, INT32 indent,
00124                                          BOOL bOuterBevel, JointType jType)
00125 {
00126     if (!pPath)
00127         return TRUE;
00128 
00129     if (pPath->GetNumCoords() < 3)
00130         return TRUE;
00131 
00132     BevelHelpers::EliminateMultiplePoints(pPath);
00133     
00134     // calculate all the normals
00135     TrapEdgeList * pEdgeList = RetnTraps->AddEdgeList();
00136     TrapEdge     * pEdge     = NULL;
00137     TrapEdge     * pEdgeBefore   = NULL;
00138     TrapEdge     * pEdgeAfter    = NULL;
00139 
00140     NormCoord nctmp1;
00141     NormCoord nctmp2;
00142     NormCoord nc1;
00143     NormCoord nc2;
00144     NormCoord nc3;
00145 
00146     double len1 = 0.0;
00147     double len2 = 0.0;
00148     double dot = 0.0;
00149     double len = 0.0;
00150 
00151     for (INT32 i = 0; i < pPath->GetNumCoords()-1; i++)
00152     {
00153         nc1.x = -(pPath->GetCoordArray()[AlterIndex(i, pPath->GetNumCoords()-1, -1)].x - pPath->GetCoordArray()[i].x);
00154         nc1.y = -(pPath->GetCoordArray()[AlterIndex(i, pPath->GetNumCoords()-1, -1)].y - pPath->GetCoordArray()[i].y);
00155         nc2.x = +(pPath->GetCoordArray()[AlterIndex(i, pPath->GetNumCoords()-1, +1)].x - pPath->GetCoordArray()[i].x);
00156         nc2.y = +(pPath->GetCoordArray()[AlterIndex(i, pPath->GetNumCoords()-1, +1)].y - pPath->GetCoordArray()[i].y);
00157         len1 = nc1.GetLength();
00158         len2 = nc2.GetLength();
00159 
00160         if (len1 > 0.0 &&
00161             len2 > 0.0 &&
00162             (nc1.x != 0 || nc1.y != 0) &&
00163             (nc2.x != 0 || nc2.y != 0))
00164         {
00165             nc1.x /= len1;
00166             nc1.y /= len1;
00167             nc2.x /= len2;
00168             nc2.y /= len2;
00169 
00170             NormCoord nc4( -nc1.y,+nc1.x ) ;
00171             NormCoord nc5( -nc2.y,+nc2.x ) ;
00172 
00173             dot = nc1.x*nc2.x+nc1.y*nc2.y;
00174 
00175             if ( bOuterBevel != nc2.y*nc1.x>nc2.x*nc1.y )
00176                 if ( jType==RoundJoin )
00177                 {
00178                     AddEdgeToList  (pEdgeList, &(pPath->GetCoordArray()[i]), &nc4,       0);
00179                     CreateRoundJoin(pEdgeList, &(pPath->GetCoordArray()[i]), &nc4, &nc5   );
00180                     AddEdgeToList  (pEdgeList, &(pPath->GetCoordArray()[i]),       &nc5, 0);
00181                     
00182                 }
00183                 else if ( jType==BevelledJoin )
00184 //              else if ( (jType==BevelledJoin || jType==MitreJoin && dot<-0.707) )
00185                 {
00186                     AddEdgeToList(pEdgeList, &(pPath->GetCoordArray()[i]), &nc4, 0);
00187                     AddEdgeToList(pEdgeList, &(pPath->GetCoordArray()[i]), &nc5, 0);
00188                 }
00189                 else
00190                 {
00191                     if ( dot+1.0>0.0 )
00192                     {
00193                         len = 1.0/(dot+1.0) ;
00194                         nc3.x = (nc4.x+nc5.x)*len;
00195                         nc3.y = (nc4.y+nc5.y)*len;
00196                         AddEdgeToList(pEdgeList, &(pPath->GetCoordArray()[i]), &nc3, 0);
00197                     }
00198                 }
00199             else
00200             {
00201                 // add a single edge to the list to be coped with later
00202                 // marking it with position 1
00203                 AddEdgeToList(pEdgeList, &(pPath->GetCoordArray()[i]), &nc4, 0);
00204                 AddEdgeToList(pEdgeList, &(pPath->GetCoordArray()[i]), &nc5, 0);
00205             }
00206         }
00207     }
00208 
00209     // add first edge as the last edge in the list
00210     if (pEdgeList && pEdgeList->GetNumEdges() > 0)
00211     {
00212         pEdge = pEdgeList->GetTrapEdge(0);
00213         if (pEdge)
00214             AddEdgeToList(pEdgeList, &(pEdge->Centre), &(pEdge->Normal), pEdge->Position);
00215     }
00216 
00217     return TRUE;
00218 }
00219 */
00220 /*
00221 BOOL CCreateBevelTrapezoids::ProcessPath(Path * pPath, TrapsList *RetnTraps, INT32 indent,
00222                                          BOOL bOuterBevel, JointType jType)
00223 {
00224     if (!pPath)
00225         return TRUE;
00226 
00227     if (pPath->GetNumCoords() < 3)
00228         return TRUE;
00229     
00230     // calculate all the normals
00231     TrapEdgeList * pEdgeList = RetnTraps->AddEdgeList();
00232     TrapEdge     * pEdge     = NULL;
00233     TrapEdge     * pEdge2    = NULL;
00234 
00235     for (INT32 i = 0; i < pPath->GetNumCoords()-1; i++)
00236     {
00237         NormCoord nc1;
00238         NormCoord nc2;
00239         nc1.x = -(pPath->GetCoordArray()[AlterIndex(i, pPath->GetNumCoords()-1, -1)].x - pPath->GetCoordArray()[i].x);
00240         nc1.y = -(pPath->GetCoordArray()[AlterIndex(i, pPath->GetNumCoords()-1, -1)].y - pPath->GetCoordArray()[i].y);
00241         nc2.x = +(pPath->GetCoordArray()[AlterIndex(i, pPath->GetNumCoords()-1, +1)].x - pPath->GetCoordArray()[i].x);
00242         nc2.y = +(pPath->GetCoordArray()[AlterIndex(i, pPath->GetNumCoords()-1, +1)].y - pPath->GetCoordArray()[i].y);
00243         double len1 = nc1.GetLength();
00244         double len2 = nc2.GetLength();
00245 
00246         if (len1 > 0.0 &&
00247             len2 > 0.0 &&
00248             (nc1.x != 0 || nc1.y != 0) &&
00249             (nc2.x != 0 || nc2.y != 0))
00250         {
00251             nc1.x /= len1;
00252             nc1.y /= len1;
00253             nc2.x /= len2;
00254             nc2.y /= len2;
00255 
00256             NormCoord nc4( -nc1.y,+nc1.x ) ;
00257             NormCoord nc5( -nc2.y,+nc2.x ) ;
00258 
00259             bool bOuter = bOuterBevel != nc2.y*nc1.x>nc2.x*nc1.y ;
00260 
00261             if ( bOuter && jType==RoundJoin )
00262             {
00263                 AddEdgeToList  (pEdgeList, &(pPath->GetCoordArray()[i]), &nc4,       0);
00264                 CreateRoundJoin(pEdgeList, &(pPath->GetCoordArray()[i]), &nc4, &nc5   );
00265                 AddEdgeToList  (pEdgeList, &(pPath->GetCoordArray()[i]),       &nc5, 0);
00266             }
00267             else if ( bOuter && jType==BevelledJoin )
00268 //          else if ( bOuter && (jType==BevelledJoin || jType==MitreJoin && dot<-0.707) )
00269             {
00270                 AddEdgeToList(pEdgeList, &(pPath->GetCoordArray()[i]), &nc4, 0);
00271                 AddEdgeToList(pEdgeList, &(pPath->GetCoordArray()[i]), &nc5, 0);
00272             }
00273             else
00274             {
00275                 double dot = nc1.x*nc2.x+nc1.y*nc2.y;
00276                 if ( dot!=-1.0 )
00277                 {
00278                     double len = 1.0/(dot+1.0) ;
00279                     NormCoord nc3;
00280                     nc3.x = (nc4.x+nc5.x)*len;
00281                     nc3.y = (nc4.y+nc5.y)*len;
00282                     AddEdgeToList(pEdgeList, &(pPath->GetCoordArray()[i]), &nc3, 0);
00283     //              AddEdgeToList(pEdgeList, &(pPath->GetCoordArray()[i]), &nc3, !bOuter);
00284                 }
00285             }
00286         }
00287     }
00288 
00289 //  FlattenInnerPoints(pEdgeList, indent, bOuterBevel);
00290 
00291     // add first edge as the last edge in the list
00292     if (pEdgeList && pEdgeList->GetNumEdges() > 0)
00293     {
00294         pEdge = pEdgeList->GetTrapEdge(0);
00295         if (pEdge)
00296         {
00297             // MUST do it this way since the original edge memory allocation may
00298             // change with a change in the list
00299             DocCoord Centre2 = pEdge->Centre;
00300             NormCoord Normal2 = pEdge->Normal;
00301 
00302             AddEdgeToList(pEdgeList, &Centre2, &Normal2, 0);
00303         }
00304     }
00305 
00306     return TRUE;
00307 }
00308 */
00309 /*
00310 BOOL CCreateBevelTrapezoids::ProcessPath(Path * pPath, TrapsList *RetnTraps, INT32 indent,
00311                                          BOOL bOuterBevel, JointType jType)
00312 {
00313     if (!pPath)
00314         return TRUE;
00315 
00316     if (pPath->GetNumCoords() < 3)
00317         return TRUE;
00318     
00319     // calculate all the normals
00320     TrapEdgeList * pEdgeList = RetnTraps->AddEdgeList();
00321     TrapEdge     * pEdge     = NULL;
00322     TrapEdge     * pEdge2    = NULL;
00323 
00324     NormCoord nc1;
00325     NormCoord nc2;
00326     NormCoord nc3;
00327 
00328     NormCoord nc4;
00329     NormCoord nc5;
00330 
00331     double dot = 0;
00332     double len1 = 0;
00333     double len2 = 0;
00334     double len3 = 0;
00335     double len  = 0;
00336 
00337     BOOL bOuter = FALSE;
00338 
00339     double dTmp = 0;
00340 
00341     for (INT32 i = 0; i < pPath->GetNumCoords()-1; i++)
00342     {
00343         nc1.x = pPath->GetCoordArray()[AlterIndex(i, pPath->GetNumCoords()-1, -1)].x - pPath->GetCoordArray()[i].x;
00344         nc1.y = pPath->GetCoordArray()[AlterIndex(i, pPath->GetNumCoords()-1, -1)].y - pPath->GetCoordArray()[i].y;
00345         nc1.x = -nc1.x;
00346         nc1.y = -nc1.y;
00347 
00348         len1 = nc1.GetLength();
00349 
00350         nc2.x = pPath->GetCoordArray()[AlterIndex(i, pPath->GetNumCoords()-1, +1)].x - pPath->GetCoordArray()[i].x;
00351         nc2.y = pPath->GetCoordArray()[AlterIndex(i, pPath->GetNumCoords()-1, +1)].y - pPath->GetCoordArray()[i].y;
00352         len2 = nc2.GetLength();
00353 
00354         if (len1 > 0.0 &&
00355             len2 > 0.0 &&
00356             (nc1.x != 0 || nc1.y != 0) &&
00357             (nc2.x != 0 || nc2.y != 0))
00358         {
00359             nc1.x /= len1;
00360             nc1.y /= len1;
00361             nc2.x /= len2;
00362             nc2.y /= len2;
00363 
00364             dot = nc1.x * nc2.x + nc1.y * nc2.y;
00365 
00366             bOuter = bOuterBevel^IsOuterTurn(&nc1, &nc2);
00367             
00368             nc3.x = (-nc1.x) + nc2.x;
00369             nc3.y = (-nc1.y) + nc2.y;
00370 
00371             if (dot >= 0.05)
00372             {
00373                 // flat cap, for large outer turn
00374                 // rotate both normals in & out by 90 degrees
00375                 
00376                 nc4.x = -nc1.y;
00377                 nc4.y = nc1.x;
00378                 
00379                 nc5.x = -nc2.y;
00380                 nc5.y = nc2.x;
00381 
00382                 if (bOuter)
00383                 {
00384                     
00385                     nc3.x = (nc4.x + nc5.x) / 2.0;
00386                     nc3.y = (nc4.y + nc5.y) / 2.0;
00387                     
00388                     len = nc3.GetLength();
00389 
00390                     if (len > 0)
00391                     {
00392                         nc3.x /= len;
00393                         nc3.y /= len;
00394                     }
00395 
00396                     if (len > 0)
00397                     {
00398                         if (jType == RoundJoin)
00399                         {
00400                             AddEdgeToList(pEdgeList, &(pPath->GetCoordArray()[i]), &nc4, 0);
00401                             CreateRoundJoin(pEdgeList, &(pPath->GetCoordArray()[i]), &nc4, &nc5, &nc3);
00402                             AddEdgeToList(pEdgeList, &(pPath->GetCoordArray()[i]), &nc5, 0);
00403                         }
00404                         else if (jType == MitreJoin)
00405                         {
00406                             AddEdgeToList(pEdgeList, &(pPath->GetCoordArray()[i]), &nc3, 0);
00407                         }
00408                         else if (jType == BevelledJoin)
00409                         {
00410                             AddEdgeToList(pEdgeList, &(pPath->GetCoordArray()[i]), &nc4, 0);
00411                             AddEdgeToList(pEdgeList, &(pPath->GetCoordArray()[i]), &nc5, 0);
00412                         }                           
00413                     }
00414                 }
00415                 else
00416                 {
00417                     
00418                     nc3.x = (nc4.x + nc5.x);
00419                     nc3.y = (nc4.y + nc5.y);
00420 
00421                     len = nc3.GetLength();
00422                     if (len > 0)
00423                     {
00424                         if (!bOuterBevel || dot > 0.707)
00425                         {
00426                             nc3.x /= len;
00427                             nc3.y /= len;                   
00428                         }
00429                         AddEdgeToList(pEdgeList, &(pPath->GetCoordArray()[i]), &nc3, 1);
00430                     }
00431                 }
00432             }
00433             else
00434             {
00435                 
00436                 nc4.x = -nc1.y;
00437                 nc4.y = nc1.x;
00438                 
00439                 nc5.x = -nc2.y;
00440                 nc5.y = nc2.x;
00441                 
00442                 // calculate the centre point
00443                 nc3.x = nc2.x - nc1.x;
00444                 nc3.y = nc2.y - nc1.y;
00445                 
00446                 if (!bOuterBevel)
00447                 {
00448                     if (bOuter)
00449                     {
00450                         len3 = nc3.GetLength();                     
00451                         if (len3 > 0)
00452                         {
00453                             nc3.x /= len3;
00454                             nc3.y /= len3;
00455                             
00456                         }
00457 
00458                         if (jType == RoundJoin)
00459                         {
00460                             AddEdgeToList(pEdgeList, &(pPath->GetCoordArray()[i]), &nc4, 0);
00461                             CreateRoundJoin(pEdgeList, &(pPath->GetCoordArray()[i]), &nc4, &nc5, &nc3);
00462                             AddEdgeToList(pEdgeList, &(pPath->GetCoordArray()[i]), &nc5, 0);
00463                         }
00464                         else if (jType == MitreJoin)
00465                         {
00466                             AddEdgeToList(pEdgeList, &(pPath->GetCoordArray()[i]), &nc3, 0);
00467                         }
00468                         else if (jType == BevelledJoin)
00469                         {
00470                             AddEdgeToList(pEdgeList, &(pPath->GetCoordArray()[i]), &nc4, 0);
00471                             AddEdgeToList(pEdgeList, &(pPath->GetCoordArray()[i]), &nc5, 0);
00472                         }                           
00473                     }
00474                     else
00475                     {
00476                         nc3.x = -nc3.x;
00477                         nc3.y = -nc3.y;
00478 
00479                         len = nc3.GetLength();
00480 
00481                         AddEdgeToList(pEdgeList, &(pPath->GetCoordArray()[i]), &nc3, 1);
00482                     }
00483                 }
00484                 else
00485                 {
00486                     // rotate these by 90 degrees
00487                     nc4.x = nc1.x;
00488                     nc4.y = nc1.y;
00489                         
00490                     dTmp = nc4.x;
00491                     nc4.x = -nc4.y;
00492                     nc4.y = dTmp;
00493                         
00494                     nc5.x = -nc2.x;
00495                     nc5.y = -nc2.y;
00496                         
00497                     nc3.x = -nc3.x;
00498                     nc3.y = -nc3.y;
00499                         
00500                     dTmp = nc5.x;
00501                     
00502                     nc5.x = nc5.y;
00503                     nc5.y = -dTmp;
00504                     
00505                     if (bOuter)
00506                     {
00507                         len3 = nc3.GetLength();
00508                         if (len3 > 0)
00509                         {
00510                             nc3.x /= len3;
00511                             nc3.y /= len3;
00512                         }
00513 
00514                         if (jType == RoundJoin)
00515                         {
00516                             AddEdgeToList(pEdgeList, &(pPath->GetCoordArray()[i]), &nc4, 0);
00517                             CreateRoundJoin(pEdgeList, &(pPath->GetCoordArray()[i]), &nc4, &nc5, &nc3);
00518                             AddEdgeToList(pEdgeList, &(pPath->GetCoordArray()[i]), &nc5, 0);
00519                         }
00520                         else if (jType == MitreJoin)
00521                         {
00522                             AddEdgeToList(pEdgeList, &(pPath->GetCoordArray()[i]), &nc3, 0);
00523                         }
00524                         else if (jType == BevelledJoin)
00525                         {
00526                             nc4.x = -nc1.y;
00527                             nc4.y = nc1.x;
00528 
00529                             nc5.x = -nc2.y;
00530                             nc5.y = nc2.x;
00531                             AddEdgeToList(pEdgeList, &(pPath->GetCoordArray()[i]), &nc4, 0);
00532                             AddEdgeToList(pEdgeList, &(pPath->GetCoordArray()[i]), &nc5, 0);
00533                         }                                           
00534                     }
00535                     else
00536                     {   
00537                         nc3.x = -nc3.x;
00538                         nc3.y = -nc3.y;
00539 
00540                         len = nc3.GetLength();
00541 
00542                         if (len > 0)
00543                         {
00544                             if (!bOuterBevel || dot < -0.707)
00545                             {
00546                                 nc3.x /= len;
00547                                 nc3.y /= len;
00548                             }
00549                         }
00550 
00551                         if (len > 0)
00552                         {
00553                             AddEdgeToList(pEdgeList, &(pPath->GetCoordArray()[i]), &nc3, 1);
00554                         }
00555                         
00556                     }
00557                 }
00558             }       
00559         }
00560     }
00561 
00562     FlattenInnerPoints(pEdgeList, indent, bOuterBevel);
00563 
00564     // add first edge as the last edge in the list
00565     if (pEdgeList)
00566     {
00567         if (pEdgeList->GetNumEdges() > 0)
00568         {
00569             pEdge = pEdgeList->GetTrapEdge(0);
00570 
00571             if (pEdge)
00572             {
00573                 AddEdgeToList(pEdgeList, &(pEdge->Centre), &(pEdge->Normal), pEdge->Position);
00574             }
00575         }
00576     }
00577 
00578     return TRUE;
00579 }
00580 */
00581 
00582 /********************************************************************************************
00583 >   void CCreateBevelTrapezoids::ProcessTrapsForBevelling(Path * pPath, 
00584                         TrapsList *RetnTraps, INT32 indent)
00585 
00586     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00587     Created:    25/10/98
00588     Purpose:    Takes a path and gives out the trapezoid list to use
00589     Inputs:     The traps list to use as source, the traps list to enter the data into
00590                 and the indent to use (if negative, then this denotes an outer bevel).
00591     Returns:    -
00592     Coments:    'Rounds' corners according to line cap.
00593                 Inner turns are rounded so that highlights occur
00594                 Outer turns are capped
00595     SeeAlso:    -
00596 
00597 ********************************************************************************************/
00598 
00599 BOOL CCreateBevelTrapezoids::ProcessTrapsForBevelling(Path *pPath, TrapsList *RetnTraps, 
00600                                                       INT32 indent, JointType jType,
00601                                                       BOOL bOuter)
00602 {
00603     if (!pPath || !RetnTraps || indent == 0)
00604         return FALSE;
00605 
00606     BOOL bSmooth = FALSE;
00607 
00608     if (bOuter || CBeveler::m_bQuick)
00609         bSmooth = FALSE;
00610     
00611     // temporary traps list
00612     TrapsList * pTmpTraps = new TrapsList;
00613 
00614     // first, flatten the path
00615     Path FlatPath;
00616     FlatPath.Initialise();
00617 
00618     ProcessFlatten pf(BEVEL_FLATNESS);
00619     ProcessFlags pfFlags(TRUE, FALSE, FALSE);
00620     pf.FlattenPath(pfFlags, pPath, &FlatPath);
00621 
00622     Path SubPath;
00623     SubPath.Initialise();
00624 
00625     Path EliminatedPath;
00626     EliminatedPath.Initialise();
00627 
00628     EliminateMultpilePoints(&FlatPath, &EliminatedPath);
00629     pPath = &EliminatedPath;
00630 
00631     DocCoord LastPoint(0,0);
00632     DocCoord ThisPoint;
00633     DocCoord dc1;
00634     DocCoord dc2;
00635 
00636     TrapsList * pDestTraps = NULL;
00637 
00638     // don't do smoothing when told not to
00639     if (!bSmooth)
00640     {
00641         pDestTraps = RetnTraps;
00642     }
00643     else
00644     {
00645         pDestTraps = pTmpTraps;
00646     }
00647     
00648     // need to seperate subpaths out, and then use ProcessPath to turn them into trapezoid lists
00649     for (INT32 i = 0 ; i < FlatPath.GetNumCoords(); i++)
00650     {
00651         // new sub-path ?
00652         if (FlatPath.GetVerbArray()[i] == PT_MOVETO || (i == FlatPath.GetNumCoords() - 1))
00653         {
00654             // make sure we don't miss the last point
00655             if (i == FlatPath.GetNumCoords() - 1)
00656             {
00657                 // since path has been flattened, then just add the points in as line-tos
00658                 ThisPoint = FlatPath.GetCoordArray()[i];
00659 
00660                 if (ThisPoint.x != LastPoint.x ||
00661                     ThisPoint.y != LastPoint.y)
00662                 {
00663                     SubPath.AddLineTo(ThisPoint);
00664                 }
00665 
00666                 LastPoint = ThisPoint;
00667             }
00668             
00669             // process the path into trapezoids
00670             if (SubPath.GetNumCoords() > 0 && i > 0)
00671             {
00672                 // call process path
00673                 // but check that the first point & last points in the paths are
00674                 // the same (i.e. it is closed !)
00675                 dc1 = SubPath.GetCoordArray()[0];
00676                 dc2 = SubPath.GetCoordArray()[SubPath.GetNumCoords() - 1];
00677 
00678                 if (dc1.x != dc2.x ||
00679                     dc1.y != dc2.y)
00680                 {
00681                     SubPath.AddLineTo(dc1);
00682                 }
00683     
00684                 if (!ProcessPath(&SubPath, pDestTraps, indent, bOuter, jType))
00685                 {
00686                     delete pTmpTraps;
00687                     pTmpTraps = NULL;
00688                     return FALSE;
00689                 }
00690             }
00691             
00692             // clear the path and add the new point
00693             SubPath.ClearPath(FALSE);
00694             SubPath.AddMoveTo(FlatPath.GetCoordArray()[i]);
00695         }
00696         else
00697         {
00698             // since path has been flattened, then just add the points in as line-tos
00699             ThisPoint = FlatPath.GetCoordArray()[i];
00700 
00701             if (ThisPoint.x != LastPoint.x ||
00702                 ThisPoint.y != LastPoint.y)
00703             {
00704                 SubPath.AddLineTo(ThisPoint);
00705             }
00706 
00707             LastPoint = ThisPoint;
00708         }
00709     }
00710 
00711     if (bSmooth)
00712     {
00713         if (!SmoothCorners(pDestTraps, RetnTraps, (double)indent, bOuter))
00714         {
00715             delete pTmpTraps;
00716             pTmpTraps = NULL;
00717             return FALSE;
00718         }
00719     }
00720         
00721     delete pTmpTraps;
00722     pTmpTraps = NULL;
00723     
00724     return TRUE;
00725 }
00726 #endif
00727 
00728 /********************************************************************************************
00729 >   void CCreateBevelTrapezoids::CalculateIntersection(DocCoord * start1, NormCoord * dir1,
00730                                                    DocCoord * start2, NormCoord * dir2,
00731                                                    DocCoord * point, double * p, double * q)
00732 
00733     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00734     Created:    24/9/98
00735     Purpose:    Calculates the intersection between 2 lines
00736     Inputs:     Start point and direction of each of the lines
00737     Returns:    The point in *point and the distance along dir1 from start1 of this point.
00738                 Also returns FALSE if the lines are in the same direction (i.e. no intersection)
00739     SeeAlso:    -
00740 
00741 ********************************************************************************************/
00742 
00743 BOOL CCreateBevelTrapezoids::CalculateIntersection(const DocCoord * start1, const NormCoord * dir1,
00744                                                    const DocCoord * start2, const NormCoord * dir2,
00745                                                    DocCoord * point, double * p, double * q)
00746 {
00747     // just turning the start points into doubles
00748     NormCoord nStart1;
00749     NormCoord nStart2;
00750         
00751     nStart1.x = start1->x;
00752     nStart1.y = start1->y;
00753 
00754     nStart2.x = start2->x;
00755     nStart2.y = start2->y;
00756 
00757     double div = (dir2->y * dir1->x - dir2->x * dir1->y);
00758     if (div == 0)
00759         return FALSE;
00760     
00761     // find the parametric value for the first line defining the point
00762     double rdiv = 1.0/div;
00763 
00764     double a = dir2->y * (nStart2.x - nStart1.x) + dir2->x * (nStart1.y - nStart2.y);
00765     a *= rdiv;
00766 
00767     point->x = (INT32)(nStart1.x + dir1->x * a);
00768     point->y = (INT32)(nStart1.y + dir1->y * a);
00769 
00770     *p = a;
00771 
00772     a = dir1->y * (nStart2.x - nStart1.x) + dir1->x * (nStart1.y - nStart2.y);
00773     a *= rdiv;
00774 
00775     *q = a;
00776 
00777     return TRUE;
00778 }
00779 #if 0
00780 /********************************************************************************************
00781 >   BOOL CCreateBevelTrapezoids::IsOuterTurn(NormCoord * nc1, NormCoord * nc2);
00782                 
00783     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00784     Created:    26/10/98
00785     Purpose:    Given the two vectors, from the trapezoid list, returns whether a right
00786                 or left turn exists (right turns are outer)
00787     Inputs:     Two direction vectors, in & out of a single point
00788     Returns:    TRUE for outer & FALSE for inner turns
00789     SeeAlso:    -
00790 
00791 ********************************************************************************************/
00792 
00793 BOOL CCreateBevelTrapezoids::IsOuterTurn(NormCoord * nc1, NormCoord * nc2)
00794 {
00795     return nc2->y*nc1->x > nc2->x*nc1->y ;
00796 }
00797 
00798 /********************************************************************************************
00799 >   BOOL CCreateBevelTrapezoids::AddEdgeToList(TrapEdgeList * pList, DocCoord * Centre, 
00800                                            NormCoord * Normal, double Position,
00801                                            NormCoord * pNormal2=NULL)
00802 
00803                 
00804     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00805     Created:    26/10/98
00806     Purpose:    Adds an edge to the given list
00807     Inputs:     Traps list to add this to, the centre point, normal and position of the edge
00808                 Can also use a secondary normal - used when marking points
00809     Returns:    TRUE for success
00810     SeeAlso:    -
00811 
00812 ********************************************************************************************/
00813 
00814 BOOL CCreateBevelTrapezoids::AddEdgeToList(TrapEdgeList * pList, DocCoord * Centre, 
00815                                            NormCoord * Normal, double Position, NormCoord * pNormal2)
00816 {
00817     if (!Normal || !pList || !Centre)
00818         return TRUE;
00819 
00820     if (Normal->x == 0 && Normal->y == 0)
00821     {
00822         return TRUE;
00823     }
00824 
00825     if (!pList->AddEdge(Centre, TrapJoin_MitredOrBevelled))
00826     {
00827         ERROR3("Add edge failed");
00828         return FALSE;
00829     }
00830 
00831     TrapEdge * pNewEdge = pList->GetTrapEdge(pList->GetNumEdges()-1);
00832 
00833     if (pNewEdge)
00834     {
00835         pNewEdge->Normal.x = Normal->x;
00836         pNewEdge->Normal.y = Normal->y;
00837         pNewEdge->Position = Position;
00838 
00839         if (pNormal2)
00840         {
00841             pNewEdge->Normal2.x = pNormal2->x;
00842             pNewEdge->Normal2.y = pNormal2->y;
00843         }
00844     }
00845     else
00846     {
00847         return FALSE;
00848     }
00849 
00850     return TRUE;
00851 }
00852 
00853 /********************************************************************************************
00854 >   BOOL CCreateBevelTrapezoids::SmoothCorners(TrapsList * pList, TrapsList * RetnList, 
00855                 double Indent, BOOL bOuterBevel)
00856 
00857                 
00858     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
00859     Created:    10/11/98
00860     Purpose:    Creates a traps list with the corners smoothed out
00861     Inputs:     Input traps list and output traps list
00862     Returns:    TRUE for success
00863     SeeAlso:    -
00864 
00865 ********************************************************************************************/
00866 
00867 BOOL CCreateBevelTrapezoids::SmoothCorners(TrapsList * pList, TrapsList * RetnList, double Indent,
00868                                            BOOL bOuterBevel)
00869 {
00870     TrapEdgeList * pEdgeList    = NULL;
00871     TrapEdge     * pEdge        = NULL;
00872     TrapEdge     * pEdgeBefore  = NULL;
00873     TrapEdge     * pEdgeAfter   = NULL;
00874     TrapEdge     * pTmpEdge     = NULL;
00875 
00876     TrapEdgeList * pNewEdgeList = NULL;
00877 
00878     NormCoord ncBefore;
00879     NormCoord ncAfter;
00880 
00881     // perpendiculars to the above
00882     NormCoord ncPerpBefore;
00883     NormCoord ncPerpAfter;
00884 
00885     NormCoord ncNormal;
00886 
00887     DocCoord dcInnerPoint;
00888 
00889     DocCoord dcIntersection;
00890 
00891     double MOneDivIndent = -1/Indent;
00892 
00893     // parametric variables
00894     double p = 0;
00895     double q = 0;
00896 
00897     double dot = 0;
00898     UINT32 j = 0;
00899 
00900     BOOL bOuter = FALSE;
00901 
00902     for (UINT32 i = 0; i < pList->GetNumTraps(); i++)
00903     {
00904         pEdgeList = pList->GetTrapEdgeList(i);
00905 
00906         pNewEdgeList = RetnList->AddEdgeList();
00907 
00908         for (j = 0; j < pEdgeList->GetNumEdges()-1; j++)
00909         {
00910             pEdge = pEdgeList->GetTrapEdge(j);
00911             
00912             if (pEdge)
00913             {
00914                 
00915                 // set up the before and after edges (start & end edges are the same so
00916                 // need treating differently)
00917                 if (j == 0)
00918                 {
00919                     pEdgeBefore = pEdgeList->GetTrapEdge(pEdgeList->GetNumEdges() - 2);
00920                     pEdgeAfter  = pEdgeList->GetTrapEdge(1);
00921                 }
00922                 else
00923                 {
00924                     pEdgeAfter = pEdgeList->GetTrapEdge(j + 1);
00925                     pEdgeBefore = pEdgeList->GetTrapEdge(j - 1);
00926                 }
00927                 
00928                 // ok, now we work out the vectors before and after the point on the path
00929                 if (pEdgeBefore)
00930                 {
00931                     ncBefore.x = pEdgeBefore->Centre.x - pEdge->Centre.x;
00932                     ncBefore.y = pEdgeBefore->Centre.y - pEdge->Centre.y;
00933                 }
00934                 else
00935                 {
00936                     ncBefore.x = 0;
00937                     ncBefore.y = 0;
00938                 }
00939                 
00940                 if (pEdgeAfter)
00941                 {
00942                     ncAfter.x = pEdgeAfter->Centre.x - pEdge->Centre.x ;
00943                     ncAfter.y = pEdgeAfter->Centre.y - pEdge->Centre.y ;
00944                 }
00945                 else
00946                 {
00947                     ncAfter.x = 0;
00948                     ncAfter.y = 0;
00949                 }
00950                 
00951                 // calculate the inner point according to the edge normal
00952                 dcInnerPoint.x = (INT32)(((double)(pEdge->Centre.x)) - (pEdge->Normal.x * Indent));
00953                 dcInnerPoint.y = (INT32)(((double)(pEdge->Centre.y)) - (pEdge->Normal.y * Indent));
00954                 
00955                 // now, calculate the perpendicular intersections with the before & after lines
00956                 ncPerpBefore.x = ncBefore.y;
00957                 ncPerpBefore.y = -ncBefore.x;
00958                 
00959                 ncPerpAfter.x = -ncAfter.y;
00960                 ncPerpAfter.y = ncAfter.x;
00961                 
00962                 // is this an inner or outer turn ?
00963                 bOuter = bOuterBevel^IsOuterTurn(&ncPerpBefore, &ncPerpAfter);
00964                 
00965                 // get the dot product - only do on near to 90 degree angles
00966                 dot = ncBefore.x * ncAfter.x + ncBefore.y * ncAfter.y;
00967                 
00968                 // calculate the intersection before
00969                 if (CalculateIntersection(&dcInnerPoint, &ncPerpBefore,
00970                     &(pEdge->Centre), &ncBefore,
00971                     &dcIntersection, &p, &q) && !bOuter && dot > -0.1 && dot < 0.1)
00972                 {
00973                     // ok, intersection successful so add the point in
00974                     // only add the point up to half way along the outside path, otherwise we
00975                     // generate overlaps
00976                     if (q > 0.5)
00977                     {
00978                         // recalculate intersection
00979                         dcIntersection.x = (INT32)( (ncBefore.x * 0.5) + pEdge->Centre.x );
00980                         dcIntersection.y = (INT32)( (ncBefore.y * 0.5) + pEdge->Centre.y );
00981                     }
00982                     
00983                     // start half way along
00984                     // dcIntersection.x = (dcIntersection.x + pEdge->Centre.x) / 2;
00985                     // dcIntersection.y = (dcIntersection.y + pEdge->Centre.y) / 2;
00986                     
00987                     RecursivelyAddEdges(pNewEdgeList, &dcIntersection, &(pEdge->Centre), 
00988                         &dcInnerPoint, MOneDivIndent, 0);
00989                 }
00990                 
00991                 // insert the original edge
00992                 AddEdgeToList(pNewEdgeList, &(pEdge->Centre), &(pEdge->Normal), pEdge->Position);
00993                 
00994                 // calculate the intersection after
00995                 if (CalculateIntersection(&dcInnerPoint, &ncPerpAfter,
00996                     &(pEdge->Centre), &ncAfter,
00997                     &dcIntersection, &p, &q) && !bOuter && dot > -0.1 && dot < 0.1)
00998                 {
00999                     // ok, intersection successful so add the point in
01000                     // only add the point up to half way along the outside path, otherwise we
01001                     // generate overlaps
01002                     
01003                     if (q > 0.5)
01004                     {
01005                         // recalculate intersection
01006                         dcIntersection.x = (INT32)( (ncAfter.x * 0.5) + pEdge->Centre.x );
01007                         dcIntersection.y = (INT32)( (ncAfter.y * 0.5) + pEdge->Centre.y );
01008                     }
01009                     
01010                     // start half way along
01011                     // dcIntersection.x = (dcIntersection.x + pEdge->Centre.x) / 2;
01012                     // dcIntersection.y = (dcIntersection.y + pEdge->Centre.y) / 2;
01013                     
01014                     RecursivelyAddEdges(pNewEdgeList, &(pEdge->Centre), &dcIntersection,
01015                         &dcInnerPoint, MOneDivIndent, 0);
01016                 }
01017             }
01018 
01019             // all done !
01020         }
01021 
01022         // add the first edge in for the last edge
01023         pEdge = pNewEdgeList->GetTrapEdge(0);
01024 
01025         if (pEdge)
01026         {
01027             AddEdgeToList(pNewEdgeList, &(pEdge->Centre), &(pEdge->Normal), pEdge->Position);
01028         }
01029     }
01030 
01031     return TRUE;
01032 }
01033 
01034 #ifdef _DEBUG
01035 void CCreateBevelTrapezoids::DumpList(TrapsList * pList)
01036 {
01037     // dump the traps list
01038     TrapEdgeList * pEdgeList = NULL;
01039     TrapEdge     * pEdge = NULL;
01040     for (UINT32 i = 0 ; i < pList->GetNumTraps(); i++)
01041     {
01042         pEdgeList = pList->GetTrapEdgeList(i);
01043         TRACE( _T("//////////////////////\nEdge list %d\n"), i);
01044 
01045         for (UINT32 j = 0 ; j < pEdgeList->GetNumEdges(); j++)
01046         {
01047             pEdge = pEdgeList->GetTrapEdge(j);
01048             
01049             TRACE( _T("Edge : %d : %d %d, %f %f\n"),
01050                 j, pEdge->Centre.x, pEdge->Centre.y, pEdge->Normal.x, pEdge->Normal.y);
01051         }
01052     }
01053 }
01054 
01055 #endif
01056 
01057 /********************************************************************************************
01058 >   void CCreateBevelTrapezoids::CalcInnerPoint(TrapEdge * pEdge, INT32 indent, DocCoord *dc)
01059                                            
01060 
01061                 
01062     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01063     Created:    20/11/98
01064     Purpose:    Calculates the inner point of an edge and puts it indc
01065     Inputs:     
01066     Returns:    
01067     SeeAlso:    -
01068 
01069 ********************************************************************************************/
01070 
01071 void CCreateBevelTrapezoids::CalcInnerPoint(TrapEdge * pEdge, INT32 indent, DocCoord *dc,
01072                                             BOOL bOuter)
01073 {
01074     if (!bOuter)
01075     {
01076         dc->x = (INT32)((double)pEdge->Centre.x - pEdge->Normal.x * indent);
01077         dc->y = (INT32)((double)pEdge->Centre.y - pEdge->Normal.y * indent);
01078     }
01079     else
01080     {
01081         dc->x = (INT32)((double)pEdge->Centre.x + pEdge->Normal.x * indent);
01082         dc->y = (INT32)((double)pEdge->Centre.y + pEdge->Normal.y * indent);
01083     }
01084 
01085 }
01086 
01087 /********************************************************************************************
01088 >   void CCreateBevelTrapezoids::RecursivelyAddEdges(TrapEdgeList * pList, 
01089                              DocCoord * pCentre1, DocCoord * pCentre2,
01090                              DocCoord * pInnerPoint, double MOneDivIndent, INT32 depth = 0);
01091                                            
01092 
01093                 
01094     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01095     Created:    20/1/98
01096     Purpose:    Recursively adds edges between centre1 and centre 2 with the same inner point
01097     Inputs:     
01098     Returns:    
01099     SeeAlso:    -
01100 
01101 ********************************************************************************************/
01102 
01103 void CCreateBevelTrapezoids::RecursivelyAddEdges(TrapEdgeList * pList, DocCoord * pCentre1, DocCoord * pCentre2,
01104                              DocCoord * pInnerPoint, double MOneDivIndent, INT32 depth)
01105 {
01106     // calculate centre point
01107     DocCoord dcIntersection;
01108     dcIntersection.x = (INT32)((pCentre1->x + pCentre2->x) * 0.5);
01109     dcIntersection.y = (INT32)((pCentre1->y + pCentre2->y) * 0.5);
01110 
01111     NormCoord ncNormal;
01112     ncNormal.x = pInnerPoint->x - dcIntersection.x;
01113     ncNormal.y = pInnerPoint->y - dcIntersection.y;
01114 
01115     ncNormal.x *= MOneDivIndent;
01116     ncNormal.y *= MOneDivIndent;
01117 
01118     if (depth >= 2)
01119     {
01120         AddEdgeToList(pList, &dcIntersection, &ncNormal, 1);
01121         return;
01122     }
01123 
01124     RecursivelyAddEdges(pList, pCentre1, &dcIntersection, pInnerPoint, MOneDivIndent, depth + 1);
01125     AddEdgeToList(pList, &dcIntersection, &ncNormal, 1);
01126     RecursivelyAddEdges(pList, &dcIntersection, pCentre2, pInnerPoint, MOneDivIndent, depth + 1);
01127 }
01128 
01129 
01130 
01131 INT32 CCreateBevelTrapezoids::AlterIndex(INT32 index, INT32 max, INT32 offset)
01132 {
01133     index += offset;
01134 
01135     while (index >= max)
01136     {
01137         index -= max;
01138     }
01139 
01140     while (index < 0)
01141     {
01142         index += max;
01143     }
01144 
01145     return index;
01146 }
01147 
01148 /********************************************************************************************
01149 >   BOOL CCreateBevelTrapezoids::EliminateMultpilePoints(Path * pSrc, Path * pDest);
01150                                            
01151 
01152                 
01153     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01154     Created:    22/11/98
01155     Purpose:    Eliminates any multiple points in the given path
01156     Inputs:     Source path to eliminate the multiple points and the destination path
01157                 to put the new path into : pDest must be cleared & initialised
01158     Returns:    
01159     SeeAlso:    -
01160 
01161 ********************************************************************************************/
01162 
01163 BOOL CCreateBevelTrapezoids::EliminateMultpilePoints(Path * pSrc, Path * pDest)
01164 {
01165     if (!pSrc || !pDest)
01166     {
01167         return FALSE;
01168     }
01169 
01170     pDest->ClearPath(FALSE);
01171 
01172     DocCoord dcLastCoord = pSrc->GetCoordArray()[0];
01173 
01174     // add first point into the new path
01175     pDest->AddMoveTo(dcLastCoord);
01176 
01177     for (INT32 i = 1 ; i < pSrc->GetNumCoords(); i++)
01178     {
01179         if (pSrc->GetVerbArray()[i] == PT_MOVETO)
01180         {
01181             dcLastCoord = pSrc->GetCoordArray()[i];
01182             pDest->AddMoveTo(dcLastCoord);
01183         }
01184         else
01185         {
01186             // ok, is this point the same as the last ?
01187             if (dcLastCoord.x != pSrc->GetCoordArray()[i].x ||
01188                 dcLastCoord.y != pSrc->GetCoordArray()[i].y)
01189             {
01190                 dcLastCoord = pSrc->GetCoordArray()[i];
01191                 pDest->AddLineTo(dcLastCoord);
01192             }
01193             else
01194             {
01195             }
01196         }
01197     }
01198 
01199     return TRUE;
01200 }
01201 
01202 /********************************************************************************************
01203 >   void CCreateBevelTrapezoids::CreateRoundJoin(TrapEdgeList * pList, DocCoord * pCentre, 
01204         DocCoord * pStartNorm,
01205         DocCoord * pEndNorm, INT32 depth)
01206                                        
01207 
01208                 
01209     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01210     Created:    24/11/98
01211     Purpose:    Creates a round join at end of the given list
01212     Inputs:     pList       -   The trap edge list to add the join to
01213                 pCentre     -   The centre point of the join
01214                 pStartNorm  -   The starting normal
01215                 pEndNorm    -   The end normal
01216                 depth       -   The recursion depth
01217 
01218     Returns:    
01219     SeeAlso:    -
01220 
01221 ********************************************************************************************/
01222 
01223 void CCreateBevelTrapezoids::CreateRoundJoin(TrapEdgeList * pList, DocCoord * pCentre, 
01224                                              NormCoord * pStartNorm, NormCoord * pEndNorm, 
01225                                              INT32 depth)
01226 {
01227     double dot = pStartNorm->x*pEndNorm->x+pStartNorm->y*pEndNorm->y;
01228 
01229     if ( dot<0.9915 && depth<6 )        // Rely on angle (arccos dot) not depth as
01230     {                                   // limit of recursion. Angle is about 7.5 degrees.
01231 
01232         // Work out the centre normal coordinate
01233         NormCoord nc;
01234         nc.x = pStartNorm->x+pEndNorm->x ;
01235         nc.y = pStartNorm->y+pEndNorm->y ;
01236 
01237         double len = nc.GetLength();
01238         if ( len==0.0 )
01239             return ;
01240         len = 1.0/len ;
01241         nc.x *= len;
01242         nc.y *= len;
01243         // Recurse downwards, add in the centre point and recurse rightwards
01244         CreateRoundJoin(pList, pCentre, pStartNorm, &nc,           depth + 1);
01245         AddEdgeToList  (pList, pCentre,             &nc,           0        );  
01246         CreateRoundJoin(pList, pCentre,             &nc, pEndNorm, depth + 1);
01247     }
01248 }
01249 
01250 /********************************************************************************************
01251 >   void CCreateBevelTrapezoids::FlattenInnerPoints(TrapEdgeList * pList, INT32 indent)
01252 
01253     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01254     Created:    2/12/98
01255     Purpose:    Takes a trap edge list, and flattens all inner points so that they are 
01256                 consistant with the distances of the outer points
01257     Inputs:     The trap edge list to flatten, and the indent we're using
01258     Returns:    -
01259     Coments:    All inner points must be defined with their normals
01260     SeeAlso:    
01261 
01262 ********************************************************************************************/
01263 
01264 void CCreateBevelTrapezoids::FlattenInnerPoints(TrapEdgeList * pList, INT32 indent, BOOL bOuter)
01265 {
01266     if (!pList || indent == 0)
01267         return;
01268 
01269     // find the first outer edge
01270     UINT32 StartIndex = 0;
01271     BOOL bFound = FALSE;
01272 
01273     TrapEdge * pEdge = NULL;
01274     TrapEdge * pNextEdge = NULL;
01275     TrapEdge * pNextEdge2 = NULL;
01276 
01277     for (UINT32 i = 0 ; i < pList->GetNumEdges()-1; i++)
01278     {
01279         pEdge = pList->GetTrapEdge(i);
01280 
01281         if (pEdge)
01282         {
01283             if (pEdge->Position == 0)
01284             {
01285                 // ok, we've found an outer point
01286                 StartIndex = i;
01287                 i = pList->GetNumEdges();
01288                 bFound = TRUE;
01289             }
01290         }
01291     }
01292 
01293     if (!bFound)
01294     {
01295         // no outer points found, so exit
01296         return;
01297     }
01298 
01299     DocCoord dc1;
01300     
01301     NormCoord nc1;
01302     NormCoord nc2;
01303 
01304     DocCoord intersection;
01305     double p = 0;
01306     double q = 0;
01307     double nc1RLen = 0;
01308     double len = 0;
01309     double OldLen = 0;
01310     double dot = 0;
01311     DocRect BevBounds;
01312 
01313     pEdge = pList->GetTrapEdge(0);
01314     CalcInnerPoint(pEdge, indent, &dc1, bOuter);
01315     BevBounds.lo.x = dc1.x;
01316     BevBounds.lo.y = dc1.y;
01317     BevBounds.hi.x = dc1.x + 1;
01318     BevBounds.hi.y = dc1.y + 1;
01319 
01320     // get the bounding rect for the traps list
01321     for (i = 1 ; i < pList->GetNumEdges(); i++)
01322     {
01323         pEdge = pList->GetTrapEdge(i);
01324         CalcInnerPoint(pEdge, indent, &dc1, bOuter);
01325         BevBounds.IncludePoint(dc1);
01326     }
01327 
01328     for (i = 0; i < pList->GetNumEdges()-1; i++)
01329     {
01330         // get the trap edge and the next trap edge
01331         pEdge     = pList->GetTrapEdge(AlterIndex(i, pList->GetNumEdges(), StartIndex    ));
01332         pNextEdge = pList->GetTrapEdge(AlterIndex(i, pList->GetNumEdges(), StartIndex + 1));
01333         if (pEdge && pNextEdge)
01334         {
01335             // indicates an inner point
01336             if (pNextEdge->Position == 1)
01337             {
01338                 CalcInnerPoint(pEdge, indent, &dc1, bOuter);
01339                 
01340                 // calculate the vector between the two centres
01341                 nc1.x = pNextEdge->Centre.x - pEdge->Centre.x;
01342                 nc1.y = pNextEdge->Centre.y - pEdge->Centre.y;
01343                 nc1RLen = 1/nc1.GetLength();
01344                 
01345                 // now, do the intersection
01346                 if (nc1Len > 0)
01347                 {
01348                     nc1.x *= nc1Len;
01349                     nc1.y *= nc1Len;
01350 
01351                     pNextEdge->Normal.Normalise();
01352 
01353                     // check for the dot product being zero
01354                     if (CalculateIntersection(&dc1, &nc1,
01355                         &(pNextEdge->Centre), &(pNextEdge->Normal),
01356                         &intersection, &p, &q))
01357                     {
01358                         // check that the intersection point is inside the bounds of
01359                         // the original list - if not it's probably a glitch
01360                         if (BevBounds.lo.x <= intersection.x &&
01361                             BevBounds.lo.y <= intersection.y &&
01362                             BevBounds.hi.x >= intersection.x &&
01363                             BevBounds.hi.y >= intersection.y)
01364                         {       
01365                             // alter the normal to the intersection point
01366                             nc2.x = pNextEdge->Centre.x - intersection.x;
01367                             nc2.y = pNextEdge->Centre.y - intersection.y;
01368                             
01369                             double R = 1/(double)indent;
01370                             nc2.x *= R;
01371                             nc2.y *= R;
01372                             
01373                             if (bOuter)
01374                             {
01375                                 nc2.x = -nc2.x;
01376                                 nc2.y = -nc2.y;
01377                             }
01378                             
01379                             pNextEdge->Normal = nc2;
01380                         }
01381                     }
01382                 }
01383                 
01384             }
01385         }
01386     }
01387 }
01388 
01389 /********************************************************************************************
01390 >   void CCreateBevelTrapezoids::GetPathFromTraps(const TrapsList * pTraps, 
01391                                               const MILLIPOINT Width, 
01392                                               Path * pPath)
01393 
01394     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01395     Created:    2/12/98
01396     Purpose:    Builds a path from 
01397     Inputs:     The trap list to use, the width to generate (can be negative) and
01398                 the path to deliver the result into (must have been initialised)
01399     Returns:    -
01400     Coments:    
01401     SeeAlso:    
01402 
01403 ********************************************************************************************/
01404 
01405 void CCreateBevelTrapezoids::GetPathFromTraps(TrapsList * pTraps, const MILLIPOINT Width, 
01406                                               Path * pPath)
01407 {
01408     pPath->ClearPath();
01409 
01410     UINT32 i = 0;
01411     INT32 j = 0;
01412     
01413     // builds a path from all the given trapezoid list
01414     UINT32 NumTraps = pTraps->GetNumTraps();
01415 
01416     INT32 NumEdges = 0;
01417 
01418     TrapEdgeList* pEdgeList = NULL;
01419     TrapEdge*     pEdge     = 0;
01420 
01421     double dX = 0;
01422     double dY = 0;
01423 
01424     DocCoord dc;
01425     DocCoord Start;
01426 
01427     // first, find out how many faces are required
01428     for (i = 0 ; i < NumTraps; i++)
01429     {
01430         pEdgeList = pTraps->GetTrapEdgeList(i);
01431         NumEdges = static_cast<INT32> ( pEdgeList->GetNumEdges() );
01432 
01433         pEdge = pEdgeList->GetTrapEdge(0);
01434 
01435         /*
01436         pPath->AddMoveTo(pEdge->Centre);
01437 
01438         for (j = 1; j < NumEdges; j++)
01439         {
01440             // do the start points first
01441             pEdge = pEdgeList->GetTrapEdge(j);
01442 
01443             pPath->AddLineTo(pEdge->Centre);
01444         }
01445 
01446         pEdge = pEdgeList->GetTrapEdge(0);
01447 
01448         pPath->AddLineTo(pEdge->Centre);
01449         */
01450 
01451         // now, add in the outer path
01452         for (j = NumEdges - 1; j >= 0; j--)
01453         {
01454             pEdge = pEdgeList->GetTrapEdge(j);
01455 
01456             dX = pEdge->Centre.x;
01457             dX += pEdge->Normal.x * Width;
01458             dY = pEdge->Centre.y;
01459             dY += pEdge->Normal.y * Width;
01460 
01461             dc.x = (MILLIPOINT)dX;
01462             dc.y = (MILLIPOINT)dY;
01463 
01464             if (j == NumEdges - 1)
01465             {
01466                 pPath->AddMoveTo(dc);
01467                 Start = dc;
01468             }
01469             else
01470                 pPath->AddLineTo(dc);
01471         }
01472     }
01473 }
01474 
01475 #endif

Generated on Sat Nov 10 03:44:19 2007 for Camelot by  doxygen 1.4.4