pathutil.cpp

Go to the documentation of this file.
00001 // $Id: pathutil.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 // Implementation file for functions which operate on sub path elements
00099 // ie lines and curves
00100 
00101 /*
00102 */
00103 
00104 #include "camtypes.h"
00105 //#include "paths.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00106 #include "pathutil.h"
00107 #include <math.h>
00108 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 #include "macros.h"
00110 
00111 #define EPSILON (ldexp(1.0,-MAXDEPTH-1))    // Flatness control value
00112 #define DEGREE 3                            // Cubic Bezier curve
00113 #define W_DEGREE 5                          // Degree of eqn to find roots of
00114 
00115 const INT32 MAXDEPTH = 64;                  // Maximum depth for recursion
00116 
00117 
00118 
00119 /********************************************************************************************
00120 
00121 >   DocCoord RampItem::PointOnSemiCircle(const DocCoord& centre, const DocCoord& radialp, double t)
00122 
00123     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00124     Created:    05/03/97
00125     Inputs:     centre  = the centre point of the circle
00126                 radialp = another point (anywhere, but assumed to be somewhere on the radius of
00127                           the circle.
00128                 t       = a parameter (0..1) defining the parametric locus about the centre from
00129                           0 to pi radians.
00130     Outputs:    -
00131     Returns:    A new doc coord which is a point on the circles perimeter which corresponds to
00132                 the parameter t. 
00133                   At t==1 the function will evaluate to radialp
00134                   At t==0 the function will evaluate to centre-(radialp-centre)
00135     Purpose:    Find a point on the circumference of a semicircle. 
00136                 The semicircle is specified by two points, it's centre and a point on the 
00137                 circumference. If c=0,0 and p=(1,0) then the semicircle exists in the y positive
00138                 half of the plane from sweeping from (-1,0) at t==0 to (1.0) at t==1.0
00139     Errors:     None.
00140 
00141 ********************************************************************************************/
00142 
00143 DocCoord PathUtil::PointOnSemiCircle(const DocCoord& centre, const DocCoord& radialp, double t)
00144 {
00145     double X = (double)(radialp.x - centre.x);
00146     double Y = (double)(radialp.y - centre.y);
00147     double p = t * XS_PI;
00148 
00149     // spin clockwise.
00150     double s =  sin(p);
00151     double c = -cos(p);
00152 
00153     DocCoord r;
00154 
00155     // circular rounding maybe?
00156     r.x = (INT32)(X*c - Y*s) + centre.x;
00157     r.y = (INT32)(X*s + Y*c) + centre.y;
00158 
00159     return r;
00160 }
00161 
00162 
00163 
00164 /********************************************************************************************
00165 
00166 >   double PathUtil::SqrDistanceToSemiCircle(const DocCoord* plist,
00167                                              const DocCoord& p1, 
00168                                              double* param )
00169 
00170     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00171     Created:    22/08/94
00172     Inputs:     plist   = a pointer to two doc coordinates describing a half circle
00173                 p1      = the point to find the squared distance to
00174     Outputs:    param   = the parameter at which the closest point exists
00175     Returns:    a double, the distance a given point is away from a line element
00176     Purpose:    Calculates the distance p1 is away from a semi circle segment. 
00177                 plist[0] describes the centre of the semi circle
00178                 plist[1] describes a point on the circumference of the circle.
00179                 For instance say c the centre is (0,0) and cp the circumference point is
00180                 (1,0) then the semicircle exists in the positive y half of the place and
00181                 sweeps from (-1,0) to (1,0). Parameter space is 
00182                   param==0   at (-1,0)
00183                   param==1   at ( 1,0)
00184                   param==0.5 at ( 0,1)
00185                     
00186 ********************************************************************************************/
00187 
00188 double PathUtil::SqrDistanceToSemiCircle(const DocCoord* plist,
00189                                          const DocCoord& p,
00190                                          double *param)
00191 {
00192     double ex,ey,px,py,Px,Py,l,t;
00193 
00194     DocCoord c = plist[0];      // the centre point
00195     DocCoord e = plist[1];      // the end point
00196     DocCoord q;
00197     
00198     // translate to origin
00199     ex = e.x-c.x;
00200     ey = e.y-c.y;
00201     px = p.x-c.x;
00202     py = p.y-c.y;
00203     
00204     // build a (ex,ey) based transform
00205     l = sqrt(ex*ex+ey*ey);
00206     if (l!=0)
00207     {
00208         ex=ex/l;
00209         ey=ex/l;
00210     }
00211     
00212     // transform the click point to local canonical
00213     Px = px*ex+py*ey;
00214     Py = py*ex-px*ey;
00215     
00216     // are we below the half circle
00217     if (Py>0)
00218     {
00219         // no then calculate the dot product angle
00220         l = sqrt(Px*Px+Py*Py);
00221         if (l!=0)
00222             Px=Px/l;
00223         t = (XS_PI - acos(Px))/XS_PI;
00224         q = PathUtil::PointOnSemiCircle(c,p,t);
00225     }
00226     else
00227     {
00228         // yes then decide start point or endpoint
00229         if (Px>0)
00230         {
00231             t=1.0;
00232             q=e;
00233         }
00234         else
00235         {
00236             t=0.0;
00237             q=e-(c-e);
00238         }
00239     }
00240     
00241     // set the output parameter
00242     (*param)=t;
00243     // calculate the squared distance
00244     return PathUtil::SqrDistance(p,q);
00245 }
00246 
00247 
00248 
00249 
00250 /********************************************************************************************
00251 
00252 > double PathUtil::SqrDistance(const Coord& Coord)
00253 
00254     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00255     Created:    20/8/94
00256     Inputs:     two coordinates
00257     Outputs:    None
00258     Returns:    the squared distance between the two coordinates
00259     Purpose:    Accurate squared distance function.
00260     Errors:     None.
00261 
00262 ********************************************************************************************/
00263 
00264 double PathUtil::SqrDistance(const DocCoord& p1, const DocCoord& p2)
00265 {
00266     double dx = (double) (p2.x - p1.x);
00267     double dy = (double) (p2.y - p1.y);
00268 
00269     return ((dx*dx)+(dy*dy));
00270 
00271 }
00272 
00273 
00274 /********************************************************************************************
00275 
00276 >   BOOL PathUtil::SplitLine(const double t,
00277                              const DocCoord* plist,
00278                              UINT32* NumElements,
00279                              PathVerb* OutVerbs,
00280                              DocCoord* OutCoords)
00281 
00282     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00283     Created:    22/08/94
00284     Inputs:     t           = parameter at which to split the line
00285                 plist       = pointer to 2 doc coords describing the line 
00286     Outputs:    NumElements = number of elements generated after split
00287                 OutVerbs    = pointer to verbs list to output data to
00288                 OutCoords   = pointer to coords list to output data to
00289     Returns:    True if the line can be split, False if not.
00290     Purpose:    Splits a line element into two lines, returning the lists of new
00291                 coord points and verbs.
00292 
00293 ********************************************************************************************/
00294 /*
00295 Technical notes:
00296 
00297     Two lineto coordinates will be returned as follows
00298 
00299         Verbs   Coords
00300         Lineto  OA
00301         Lineto  OB = IA
00302         
00303     and can be inserted as follows
00304     
00305             Input               Output        
00306         Verbs   Coords      Verbs   Coords
00307         ....    IA          ....    IA
00308         Lineto  IB          Lineto  OA
00309         ...     XX          Lineto  OB
00310                             ...     XX
00311 
00312     OB is returned in the output list in order to allow removal of the split element and
00313     complete replacement with the generated elements 
00314      
00315 ********************************************************************************************/
00316 
00317 BOOL PathUtil::SplitLine(const double t, 
00318                          const DocCoord* plist,
00319                          UINT32* NumElements,
00320                          PathVerb* Verbs,
00321                          DocCoord* Coords)
00322 {
00323     // check t is in range for this split.
00324 
00325     if (t < SPLIT_EPSILON) return FALSE;
00326     if (t > (1.0 - SPLIT_EPSILON)) return FALSE;
00327 
00328     // read the lines start and end points
00329     
00330     INT32 x0,y0,x1,y1;
00331 
00332     x0 = plist[0].x;
00333     y0 = plist[0].y;
00334     x1 = plist[1].x;
00335     y1 = plist[1].y;  
00336 
00337     // fill in the output block details
00338 
00339     Verbs[0] = PT_LINETO;
00340     Coords[0].x = x0 + (INT32)(t*(x1-x0)+0.5);
00341     Coords[0].y = y0 + (INT32)(t*(y1-y0)+0.5);
00342 
00343     Verbs[1] = PT_LINETO;
00344     Coords[1].x = x1;
00345     Coords[1].y = y1;
00346 
00347     *NumElements = 2;
00348 
00349     return TRUE;
00350 
00351 }
00352 
00353 
00354 /********************************************************************************************
00355 
00356 >   BOOL PathUtil::SplitCurve(const double t,
00357                               const DocCoord* plist,
00358                               UINT32* NumElements,
00359                               PathVerb* OutVerbs,
00360                               DocCoord* OutCoords)
00361 
00362     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00363     Created:    22/08/94
00364     Inputs:     t           = parameter at which to split the curve
00365                 plist       = pointer to 4 curve control points to split
00366     Outputs:    NumElements = number of elements generated
00367                 OutVerbs    = output verbs list
00368                 OutCoords   = output coords list
00369     Returns:    True if the curve could be split, False if not.
00370     Purpose:    Splits a curve element into two curves, returning the lists of new
00371                 control points and verbs.
00372 
00373 ********************************************************************************************/
00374 /*              
00375 
00376 Technical notes:
00377 
00378     Six bezier control points will be returned as follows:
00379 
00380                 Input     Output
00381                 IA        OA
00382                 IB        OB
00383                 IC        OC
00384                 ID        OD
00385                           OE
00386                           OF = ID
00387 
00388                 The resultant curve control lists should be encorperated by the caller
00389                 as follows:
00390 
00391                     Input               Output        
00392                 Verbs   Coords      Verbs   Coords
00393                 ....    IA          ....    IA
00394                 Bez     IB          Bez     OA
00395                 Bez     IC          Bez     OB
00396                 Bez     ID          Bez     OC
00397                 ...     XX          Bez     OD
00398                 ...     XX          Bez     OE
00399                                     Bez     OF
00400                                     ...     XX
00401                                     ...     XX
00402 
00403 ********************************************************************************************/
00404 
00405 
00406 BOOL PathUtil::SplitCurve(const double t,
00407                           const DocCoord* plist,
00408                           UINT32* NumElements,
00409                           PathVerb* OutVerbs,
00410                           DocCoord* OutCoords)
00411 {
00412     // check t is in range for this split.
00413 
00414     if (t < SPLIT_EPSILON) return FALSE;
00415     if (t > (1.0 - SPLIT_EPSILON)) return FALSE;
00416 
00417     // fill in the path verb array, these are all curveto's
00418 
00419     for (INT32 i=0; i<6; i++)
00420         OutVerbs[i] = PT_BEZIERTO;
00421 
00422     // read the four curve control points
00423 
00424     INT32 x0,y0,x1,y1,x2,y2,x3,y3;
00425 
00426     x0 = plist[0].x;                        // note this should be move,line,curve
00427     y0 = plist[0].y;
00428     x1 = plist[1].x;                        // these should all be curveto's
00429     y1 = plist[1].y;
00430     x2 = plist[2].x;
00431     y2 = plist[2].y;
00432     x3 = plist[3].x;
00433     y3 = plist[3].y;
00434 
00435     // now calculate six new coordinates from the given 4  
00436 
00437     double tx,ty;
00438 
00439     tx = x1+t*(x2-x1);
00440     ty = y1+t*(y2-y1);
00441 
00442     double Lx1,Ly1,Lx2,Ly2,Rx0,Ry0,Rx1,Ry1,Rx2,Ry2;
00443 
00444     Lx1 = x0+t*(x1-x0);
00445     Ly1 = y0+t*(y1-y0);
00446     Rx2 = x2+t*(x3-x2);
00447     Ry2 = y2+t*(y3-y2);
00448     Lx2 = Lx1+t*(tx-Lx1);
00449     Ly2 = Ly1+t*(ty-Ly1);
00450     Rx1 = tx+t*(Rx2-tx);
00451     Ry1 = ty+t*(Ry2-ty);
00452     Rx0 = Lx2+t*(Rx1-Lx2);
00453     Ry0 = Ly2+t*(Ry1-Ly2);
00454 
00455     // set the return values
00456 
00457     OutCoords[0].x = (INT32)(Lx1+0.5);
00458     OutCoords[0].y = (INT32)(Ly1+0.5);
00459     OutCoords[1].x = (INT32)(Lx2+0.5);
00460     OutCoords[1].y = (INT32)(Ly2+0.5);
00461     OutCoords[2].x = (INT32)(Rx0+0.5);
00462     OutCoords[2].y = (INT32)(Ry0+0.5);
00463     OutCoords[3].x = (INT32)(Rx1+0.5);
00464     OutCoords[3].y = (INT32)(Ry1+0.5);
00465     OutCoords[4].x = (INT32)(Rx2+0.5);
00466     OutCoords[4].y = (INT32)(Ry2+0.5);
00467     OutCoords[5].x = x3;
00468     OutCoords[5].y = y3;
00469 
00470     // Set the output number of elements.
00471 
00472     *NumElements = 6;
00473 
00474     return TRUE;
00475 }
00476 
00477 
00478 
00479 /********************************************************************************************
00480 
00481 >   void PathUtil::GetCurveCoefs(const DocCoord* coords, PtCoefs* coefs )
00482 
00483     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00484     Created:    22/08/94
00485     Inputs:     coords  = a pointer to 4 control point doccoords defining a curve
00486     Outputs:    coefs   = a set of curve coefficients.
00487     Returns:    None
00488     Purpose:    Converts a curve from Bezier form to Canonical form
00489 
00490 ********************************************************************************************/
00491 
00492 void PathUtil::GetCurveCoefs(const DocCoord* coords, PtCoefs* coefs )
00493 {
00494     // Read the curve coordinates.
00495 
00496     INT32 X0,Y0,X1,Y1,X2,Y2,X3,Y3;
00497 
00498     X0 = coords->x;
00499     Y0 = coords->y;
00500     coords++;
00501     X1 = coords->x;
00502     Y1 = coords->y;
00503     coords++;
00504     X2 = coords->x;
00505     Y2 = coords->y;
00506     coords++;
00507     X3 = coords->x;
00508     Y3 = coords->y;
00509 
00510     // Calculate the curve coefficients.
00511 
00512     coefs->ax = X3-X0+3*(X1-X2);
00513     coefs->ay = Y3-Y0+3*(Y1-Y2);
00514     coefs->bx = 3*(X2-2*X1+X0);
00515     coefs->by = 3*(Y2-2*Y1+Y0);
00516     coefs->cx = 3*(X1-X0);
00517     coefs->cy = 3*(Y1-Y0);
00518 
00519 }
00520 
00521 
00522 /********************************************************************************************
00523 
00524 >   double PathUtil::SqrDistanceToLine(const DocCoord* plist,
00525                                        const DocCoord& p1, 
00526                                        double* t )
00527 
00528     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00529     Created:    22/08/94
00530     Inputs:     plist   = a pointer to two doc coordinates describing a line
00531                 p1      = the point to find the squared distance to
00532     Outputs:    t       = the parameter at which the closest point exists
00533     Returns:    a double, the distance a given point is away from a line element
00534     Purpose:    Calculates the distance p1 is away from a line segment. The perpendicular
00535                 distance is returned only when p1 is within the volume created by sweeping
00536                 the line in the orthoganal direction. Otherwise the distance to the
00537                 closest end point is returned.
00538     
00539 ********************************************************************************************/
00540 
00541 double PathUtil::SqrDistanceToLine(const DocCoord* plist,
00542                                    const DocCoord& p1, 
00543                                    double* t )
00544 
00545 {
00546 
00547     // get hold of the lines end point coordinates
00548 
00549     INT32 x0,y0,x1,y1;
00550 
00551     x0 = plist[0].x;
00552     y0 = plist[0].y;
00553     x1 = plist[1].x;
00554     y1 = plist[1].y;
00555 
00556     INT32 pdx = (x1-x0);
00557     INT32 pdy = (y1-y0);
00558 
00559     // calculate the parameter at which the closest point exists
00560     // on an infinite line passing through (x0,y0),(x1,y1)
00561     // t=numdot/dendot.
00562 
00563     double numdot,dendot;
00564 
00565     numdot = (double)(p1.x - plist[0].x)*pdx + (double)(p1.y-plist[0].y)*pdy;
00566     dendot = (double)pdx*pdx + (double)pdy*pdy;
00567 
00568     // if t is less then zero then the closest point lies behind
00569     // the start point of the vector, hence return the squared
00570     // distance to the startpoint
00571     
00572     if (numdot<=0 || dendot<=0)
00573     {
00574         *t = 0.0;
00575         return (SqrDistance(p1, plist[0]));
00576     }
00577 
00578     // if t is greater than or equal to 1 then the closest point
00579     // lies beyond the line segment, ie on the projected line
00580     // beyond (x1,y1). So return the squared distance to that end
00581     // point.
00582     
00583     if (dendot<=numdot)
00584     {
00585         *t = 1.0;
00586         return (SqrDistance(p1,plist[1]));
00587     }
00588 
00589     // ok the closest point lies somewhere inside the line segment
00590     // (x0,y0),(x1,y1) so return its parameter and the squared
00591     // distance to it.
00592       
00593     *t = numdot/dendot;
00594 
00595     double c = (double)pdy*p1.x - (double)pdx*p1.y;
00596     double d = (double)y1*x0 - (double)y0*x1;
00597     double e = (c-d)*(c-d);
00598 
00599     return fabs(e/dendot);
00600 
00601 }
00602 
00603 
00604 
00605 /********************************************************************************************
00606 
00607 >   DocCoord PathUtil::PointOnLine(const double t, const DocCoord* startpt)
00608 
00609     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00610     Created:    22/08/94
00611     Inputs:     t       = parameter at which to evaluate point
00612                 ptlist  = pointer to two doc coords describing start and end of the line
00613     Outputs:
00614     Returns:    DocCoord, an evaluation of a point on the specified line
00615     Purpose:    Given a parameter t go and evaluate the point on the described line segment
00616                 If t is out of range, ie t>1 or t<0 the end points of the line will be
00617                 returned. ie the routine will not evaluate unbounded points.
00618         
00619 ********************************************************************************************/
00620 
00621 DocCoord PathUtil::PointOnLine(const double t, const DocCoord* ptlist)
00622 {
00623     INT32 x0,y0,x1,y1;
00624 
00625     x0 = ptlist[0].x;
00626     y0 = ptlist[0].y;
00627     x1 = ptlist[1].x;
00628     y1 = ptlist[1].y;
00629 
00630     DocCoord d;
00631 
00632     if (t<=0.0)
00633     {
00634         d.x = x0;
00635         d.y = y0;
00636         return d;
00637     }
00638 
00639     if (t>=1.0)
00640     {
00641         d.x = x1;
00642         d.y = y1;
00643         return d;
00644     }
00645 
00646     d.x = x0 + (INT32)(t*(x1-x0)+0.5);
00647     d.y = y0 + (INT32)(t*(y1-y0)+0.5);
00648 
00649     return d;
00650 }
00651 
00652 
00653 
00654 /********************************************************************************************
00655 
00656 >   double PathUtil::SqrDistanceToCurve(const UINT32 step, 
00657                                         const DocCoord* plist, 
00658                                         const DocCoord& p1, 
00659                                         double* t)
00660 
00661     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00662     Created:    22/08/94
00663     Inputs:     step    =   value between 2 and 256 dictates the corseness of stepping
00664                             internally across the curve.
00665                 plist   =   pointer to 4 doccoord control points describing the curve
00666                 p1      =   coordinate reference used to find closest coordinate to.
00667     Outputs:    t holds the parameter value of the closest point on the curve, 0<=t<=1  
00668     Returns:    a double being the distance of the closest point on the curve.
00669     Purpose:    This function returns the distance to the closest point on the curve and
00670                 the parameter of this point
00671 
00672 
00673 ********************************************************************************************/
00674 /*
00675 
00676 Technical notes:
00677 
00678     If   Qx(t) = X0*(1-t)^3 + 3*X1*t*(1-t)^2 + 3*X2*t^2*(1-t) + X3*t^3
00679     and  Qy(t) is similar
00680 
00681     Then Qx(t) = (X0 - 3*X0*t + 3*X0*t^2 - X0*t^3) +
00682                  (3*X1*t - 6*X1*t^2 + 3*X1*t^3 ) +
00683                  (3*X2*t^2 - 3*X2*t^3) +
00684                  X3*t^3
00685 
00686     Collecting terms in t
00687 
00688          Qx(t) = t^3*(X3-X0+3*(X1-X2)) +
00689                  t^2*(3*X0-6*X1+3*X2) +
00690                  t  *(3*X1-3*X0) +
00691                  X0
00692 
00693     For forward differencing
00694 
00695     Let  Ax = X3-X0+3*(X1-X2)
00696          Bx = 3*(X0-2*X1+X2)
00697          Cx = 3*(X1-X0)
00698          Dx = X0
00699 
00700     Then Q(t) = A*t^3 + B*t^2 + C*t + D
00701               = t*(C+t*(B+t*A)) + D
00702     
00703     Ok, having got this calculate the terms involved in
00704 
00705         D(t) = Q(t+delta)-Q(t)
00706 
00707     The terms involved in D(t) will give forward differences which can be
00708     used to walk the curve Q(t)
00709 
00710 ********************************************************************************************/
00711 
00712 /* double PathUtil::SqrDistanceToCurve(const UINT32 step, 
00713                                     const DocCoord* plist, 
00714                                     const DocCoord& p1, 
00715                                     double* t )
00716 
00717 {
00718 
00719 
00720     ENSURE(step>1 && step<257,"curve step is out of range");
00721 
00722     // Calculate the curve coefficients for this curve element
00723 
00724     PtCoefs CurveC;
00725     PathUtil::GetCurveCoefs(plist, &CurveC);
00726 
00727     double t0;
00728     double t1;
00729     double dist = PathUtil::CurveClosestRange(step, &CurveC, p1, plist[0].x, plist[0].y, t, &t0, &t1);
00730 
00731 // TRACE( _T("T0 = %f\n"),t0);
00732 // TRACE( _T("T  = %f\n"),*t);
00733 // TRACE( _T("T1 = %f\n"),t1);
00734 
00735     if (t0 >= t1) return dist;
00736     if ((*t==t0) || (*t==t1)) return dist;
00737     if ((*t==0.0) || (*t==1.0)) return dist;
00738 
00739     INT32 x0,y0,x1,y1,x2,y2,x3,y3;
00740 
00741     x0 = plist[0].x;                        // note this should be move,line,curve
00742     y0 = plist[0].y;
00743     x1 = plist[1].x;                        // these should all be curveto's
00744     y1 = plist[1].y;
00745     x2 = plist[2].x;
00746     y2 = plist[2].y;
00747     x3 = plist[3].x;
00748     y3 = plist[3].y;
00749 
00750     // now calculate the coordinates of a bezier curve
00751     // lying between t0 and t1
00752     
00753     double tx,ty;
00754 
00755     tx = x1+t0*(x2-x1);
00756     ty = y1+t0*(y2-y1);
00757 
00758     double Qx0,Qy0,Qx1,Qy1;
00759     double Rx1,Ry1,Rx2,Ry2,Lx1,Ly1,Lx2,Ly2;
00760 
00761     Lx1 = x0+t0*(x1-x0);
00762     Ly1 = y0+t0*(y1-y0);
00763     Rx2 = x2+t0*(x3-x2);
00764     Ry2 = y2+t0*(y3-y2);
00765     Lx2 = Lx1+t0*(tx-Lx1);
00766     Ly2 = Ly1+t0*(ty-Ly1);
00767     Qx1 = tx+t0*(Rx2-tx);
00768     Qy1 = ty+t0*(Ry2-ty);
00769     Qx0 = Lx2+t0*(Qx1-Lx2);
00770     Qy0 = Ly2+t0*(Qy1-Ly2);
00771 
00772     tx = x1+t1*(x2-x1);
00773     ty = y1+t1*(y2-y1);
00774 
00775     double Qx2,Qy2,Qx3,Qy3;
00776 
00777     Lx1 = x0+t1*(x1-x0);
00778     Ly1 = y0+t1*(y1-y0);
00779     Rx1 = x2+t1*(x3-x2);
00780     Ry1 = y2+t1*(y3-y2);
00781     Rx2 = tx+t1*(Rx1-tx);
00782     Ry2 = ty+t1*(Ry1-ty);
00783     Qx2 = Lx1+t1*(tx-Lx1);
00784     Qy2 = Ly1+t1*(ty-Ly1);
00785     Qx3 = Qx2+t1*(Rx2-Qx2);
00786     Qy3 = Qy2+t1*(Ry2-Qy2);
00787 
00788     // now home in a little bit closer
00789     
00790     CurveC.ax = Qx3-Qx0+3*(Qx1-Qx2);
00791     CurveC.ay = Qy3-Qy0+3*(Qy1-Qy2);
00792     CurveC.bx = 3*(Qx2-2*Qx1+Qx0);
00793     CurveC.by = 3*(Qy2-2*Qy1+Qy0);
00794     CurveC.cx = 3*(Qx1-Qx0);
00795     CurveC.cy = 3*(Qy1-Qy0);
00796 
00797     double t2;
00798     double t3;
00799     dist = PathUtil::CurveClosestRange(step, &CurveC, p1, Qx0, Qy0, t, &t2, &t3);
00800 
00801     *t = (1.0-(*t))*t0 + (*t)*t1;
00802 
00803 // TRACE( _T("T' = %f\n\n"),*t);
00804 
00805     return dist;
00806 }
00807 
00808 
00809 double PathUtil::CurveClosestRange(const UINT32 step,
00810                                    PtCoefs* CurveC,
00811                                    const DocCoord& p1,
00812                                    const double dx,
00813                                    const double dy,
00814                                    double* t,
00815                                    double* t0,
00816                                    double* t1)
00817 
00818 {
00819 
00820     // Calculate the step rate across the curve given the users
00821     // step value
00822 
00823     double Delta=(double) 1/step;
00824 
00825     // Calculate the forward difference factors for curve stepping
00826 
00827     double X0,Y0,X1,Y1,X2,Y2,X3,Y3;
00828 
00829     X3 = 6*Delta*Delta*Delta*CurveC->ax;
00830     Y3 = 6*Delta*Delta*Delta*CurveC->ay;
00831     X2 = 2*Delta*Delta*CurveC->bx+X3;
00832     Y2 = 2*Delta*Delta*CurveC->by+Y3;
00833 
00834     // Evaluate the first differenced point on the curve
00835 
00836     X1 = Delta*(CurveC->cx+Delta*(CurveC->bx+Delta*CurveC->ax));
00837     Y1 = Delta*(CurveC->cy+Delta*(CurveC->by+Delta*CurveC->ay));
00838     X0 = dx;
00839     Y0 = dy;
00840 
00841     // find the distance from the first point on the curve
00842 
00843     double Cdist=(p1.x - dx)*(p1.x - dx) + (p1.y - dy)*(p1.y - dy);
00844     double Fdist;
00845     INT32 Cpt=0;
00846 
00847     for (UINT32 i=1; i<=step; i++)
00848     {
00849         X0+=X1;
00850         Y0+=Y1;
00851         X1+=X2;
00852         Y1+=Y2;
00853         X2+=X3;
00854         Y2+=Y3;
00855         Fdist = (X0-p1.x)*(X0-p1.x);        // Is this point closer?
00856         if (Cdist>Fdist) 
00857         {
00858             Fdist += (Y0-p1.y)*(Y0-p1.y);
00859             if (Cdist>Fdist)
00860             {
00861                 Cdist=Fdist;
00862                 Cpt=i;
00863             }
00864         }
00865     }
00866 
00867     INT32  tl = Cpt-2;
00868     UINT32 tr = Cpt+2;
00869     if (tl<0) tl=0;
00870     if (tr>step) tr=step;
00871 
00872     *t1 = (double) tr/step;
00873     *t0 = (double) tl/step;
00874     *t  = (double) Cpt/step;                // set the point parameter
00875 
00876     return Cdist;                           // return the point distance
00877 }
00878 
00879 */
00880 
00881 
00882 /********************************************************************************************
00883 
00884 >   DocCoord PathUtil::PointOnCurve(double t, const DocCoord* plist)
00885 
00886     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00887     Created:    22/08/94
00888     Inputs:     t       = parameter to evaluate curve at
00889                 plist   = pointer to list of 4 curve control points.
00890     Outputs:
00891     Returns:    A DocCoord describing the point on the curve    
00892     Purpose:    Evaluate a bezier curve, given a pointer to a set of control points and
00893                 a parameter value. 
00894 
00895 ********************************************************************************************/
00896 
00897 DocCoord PathUtil::PointOnCurve(double t, const DocCoord* plist)
00898 {
00899     PtCoefs p;
00900     DocCoord c;
00901 
00902     PathUtil::GetCurveCoefs(plist, &p);                 // calculate coefs block
00903 
00904     if (t<0) t=0;                                       // clamp range of parameter
00905     if (t>1) t=1;
00906 
00907     // Eval bezier at specified parameter
00908 
00909     double dx = t*(p.cx+t*(p.bx+t*p.ax));
00910     double dy = t*(p.cy+t*(p.by+t*p.ay));
00911 
00912     c.x = plist->x + (INT32)(dx+0.5);
00913     c.y = plist->y + (INT32)(dy+0.5);
00914     
00915     return c;
00916 }
00917 
00918 
00919 /********************************************************************************************
00920     Quick local vector functions to calculate various properties of vectors
00921 ********************************************************************************************/
00922 
00923 Point2 V2ScaleII( Point2 *v, double s)
00924 {
00925     Point2 result;
00926 
00927     result.x = v->x * s; 
00928     result.y = v->y * s;
00929 
00930     return (result);
00931 }
00932 
00933 
00934 double V2SquaredLength(Point2* a)
00935 {
00936     return( a->x*a->x + a->y*a->y );
00937 }
00938 
00939 
00940 Point2 *V2Sub(Point2* a, Point2* b, Point2* c)
00941 {
00942   c->x = a->x - b->x;
00943   c->y = a->y - b->y;
00944   return(c);
00945 }
00946 
00947 
00948 double V2Dot(Point2* a, Point2* b)
00949 {
00950   return (a->x*b->x + a->y*b->y);
00951 }
00952 
00953 
00954 
00955 /********************************************************************************************
00956 
00957     Point2 Bezier( Point2 *V, INT32 degree, double t, Point2 *Left, Point2 *Right)  
00958 
00959     Author:     Unattributed (Xara Group Ltd) <camelotdev@xara.com>
00960     Created:    22/08/94
00961     Inputs:     V       = Control points of cubic Bezier
00962                 degree  = The degree of the polynomial
00963                 t       = Parameter value   
00964     Outputs:    Left    = RETURN left half ctl pts (if NULL return none)
00965                 Right   = RETURN right half ctl pts (if NULL return none)
00966     Returns:    Q(t), a point on the curve
00967     Purpose:    Evaluate a Bezier curve at a particular parameter value
00968                 Fill in control points for resulting sub-curves if "Left" and
00969                 "Right" are non-null.
00970 
00971 ********************************************************************************************/
00972 
00973 Point2 Bezier( Point2 *V, INT32 degree, double t,   Point2 *Left, Point2 *Right)    
00974 {
00975     INT32   i, j;       // Index variables
00976     Point2  Vtemp[W_DEGREE+1][W_DEGREE+1];
00977 
00978     // Copy control points
00979 
00980     for (j =0; j <= degree; j++) 
00981     {
00982         Vtemp[0][j] = V[j];
00983     }
00984 
00985     // Triangle computation
00986 
00987     for (i = 1; i <= degree; i++) 
00988     {   
00989         for (j =0 ; j <= degree - i; j++) 
00990         {
00991             Vtemp[i][j].x = (1.0 - t) * Vtemp[i-1][j].x + t * Vtemp[i-1][j+1].x;
00992             Vtemp[i][j].y = (1.0 - t) * Vtemp[i-1][j].y + t * Vtemp[i-1][j+1].y;
00993         }
00994     }
00995     
00996     if (Left != NULL) 
00997     {
00998         for (j = 0; j <= degree; j++) 
00999         {
01000             Left[j]  = Vtemp[j][0];
01001         }
01002     }
01003     if (Right != NULL) 
01004     {
01005         for (j = 0; j <= degree; j++) 
01006         {
01007             Right[j] = Vtemp[degree-j][j];
01008         }
01009     }
01010 
01011     return (Vtemp[degree][0]);
01012 }
01013 
01014 
01015 
01016 /********************************************************************************************
01017 
01018     double ComputeXIntercept(Point2 *V, INT32 degree)
01019  
01020     Author:     
01021     Created:    22/08/94
01022     Inputs:     V       = Control points of cubic Bezier
01023                 degree  = The degree of the polynomial
01024     Outputs:
01025     Returns:    
01026     Purpose:    Compute intersection of chord from first control point to last
01027                 with 0-axis.
01028 
01029 ********************************************************************************************/
01030 
01031 double ComputeXIntercept(Point2 *V, INT32 degree)
01032 {
01033     double  XLK, YLK, XNM, YNM, XMK, YMK;
01034     double  det, detInv;
01035     double  S, T;
01036     double  X, Y;
01037 
01038     XLK = 1.0 - 0.0;
01039     YLK = 0.0 - 0.0;
01040     XNM = V[degree].x - V[0].x;
01041     YNM = V[degree].y - V[0].y;
01042     XMK = V[0].x - 0.0;
01043     YMK = V[0].y - 0.0;
01044 
01045     det = XNM*YLK - YNM*XLK;
01046     detInv = 1.0/det;
01047 
01048     S = (XNM*YMK - YNM*XMK) * detInv;
01049     T = (XLK*YMK - YLK*XMK) * detInv;
01050     
01051     X = 0.0 + XLK * S;
01052     Y = 0.0 + YLK * S;
01053 
01054     return X;
01055 }
01056 
01057 
01058 
01059 
01060 
01061 /********************************************************************************************
01062 
01063     INT32 CrossingCount( Point2 *V, INT32 degree)   
01064  
01065     Author:     
01066     Created:    22/08/94
01067     Inputs:     V       = Control points of cubic Bezier
01068                 degree  = The degree of the polynomial
01069     Outputs:
01070     Returns:    number of crossings
01071     Purpose:    Count the number of times a Bezier control polygon 
01072                 crosses the 0-axis. This number is >= the number of roots.
01073 
01074 
01075 *********************************************************************************************/
01076 
01077 
01078 INT32 CrossingCount( Point2 *V, INT32 degree)   
01079 {
01080     INT32 i;    
01081     INT32 n_crossings = 0;  //  Number of zero-crossings
01082     INT32   sign, old_sign;     //  Sign of coefficients
01083 
01084     sign = old_sign = SGN(V[0].y);
01085     for (i = 1; i <= degree; i++) 
01086     {
01087         sign = SGN(V[i].y);
01088         if (sign != old_sign) n_crossings++;
01089         old_sign = sign;
01090     }
01091     return n_crossings;
01092 }
01093 
01094 
01095 
01096 
01097 /********************************************************************************************
01098 
01099     INT32 ControlPolygonFlatEnough(Point2 *V, INT32 degree) 
01100  
01101     Author:     
01102     Created:    22/08/94
01103     Inputs:     V       = Control points of cubic Bezier
01104                 degree  = The degree of the polynomial
01105     Outputs:
01106     Returns:    
01107     Purpose:    Check if the control polygon of a Bezier curve is flat enough
01108                 for recursive subdivision to bottom out.
01109 
01110 ********************************************************************************************/
01111 
01112 
01113 INT32 ControlPolygonFlatEnough(Point2 *V, INT32 degree) 
01114 {
01115     INT32   i;                      // Index variable
01116     double  *distance;              // Distances from pts to line
01117     double  max_distance_above;     // maximum of these
01118     double  max_distance_below;
01119     double  error;                  // Precision of root
01120     double  intercept_1,
01121             intercept_2,
01122             left_intercept,
01123             right_intercept;
01124     double  a, b, c;                // Coefficients of implicit
01125                                     // eqn for line from V[0]-V[deg]
01126 
01127     /* Find the  perpendicular distance
01128        from each interior control point to
01129        line connecting V[0] and V[degree]   */
01130 
01131     distance = (double *)CCMalloc((unsigned)(degree + 1) * sizeof(double));
01132     {
01133     double  abSquared;
01134 
01135     // Derive the implicit equation for line connecting first
01136     // and last control points
01137 
01138     a = V[0].y - V[degree].y;
01139     b = V[degree].x - V[0].x;
01140     c = V[0].x * V[degree].y - V[degree].x * V[0].y;
01141 
01142     abSquared = (a * a) + (b * b);
01143 
01144         for (i = 1; i < degree; i++)
01145         {
01146         // Compute distance from each of the points to that line
01147             distance[i] = a * V[i].x + b * V[i].y + c;
01148             if (distance[i] > 0.0) 
01149             {
01150                 distance[i] = (distance[i] * distance[i]) / abSquared;
01151             }
01152             if (distance[i] < 0.0) 
01153             {
01154                 distance[i] = -((distance[i] * distance[i]) / abSquared);
01155             }
01156         }
01157     }
01158 
01159 
01160     // Find the largest distance
01161 
01162     max_distance_above = 0.0;
01163     max_distance_below = 0.0;
01164     for (i = 1; i < degree; i++) 
01165     {
01166         if (distance[i] < 0.0) 
01167         {
01168             max_distance_below = MIN(max_distance_below, distance[i]);
01169         };
01170         if (distance[i] > 0.0) 
01171         {
01172             max_distance_above = MAX(max_distance_above, distance[i]);
01173         }
01174     }
01175     CCFree((char *)distance);
01176 
01177     {
01178     double  det, dInv;
01179     double  a1, b1, c1, a2, b2, c2;
01180 
01181     //  Implicit equation for zero line
01182 
01183     a1 = 0.0;
01184     b1 = 1.0;
01185     c1 = 0.0;
01186 
01187     //  Implicit equation for "above" line
01188 
01189     a2 = a;
01190     b2 = b;
01191     c2 = c + max_distance_above;
01192 
01193     det = a1 * b2 - a2 * b1;
01194     dInv = 1.0/det;
01195     
01196     intercept_1 = (b1 * c2 - b2 * c1) * dInv;
01197 
01198     //  Implicit equation for "below" line
01199 
01200     a2 = a;
01201     b2 = b;
01202     c2 = c + max_distance_below;
01203     
01204     det = a1 * b2 - a2 * b1;
01205     dInv = 1.0/det;
01206     
01207     intercept_2 = (b1 * c2 - b2 * c1) * dInv;
01208     }
01209 
01210     // Compute intercepts of bounding box
01211 
01212     left_intercept = MIN(intercept_1, intercept_2);
01213     right_intercept = MAX(intercept_1, intercept_2);
01214 
01215     error = 0.5 * (right_intercept-left_intercept);    
01216     if (error < EPSILON) 
01217     {
01218         return 1;
01219     }
01220     else 
01221     {
01222         return 0;
01223     }
01224 }
01225 
01226 
01227 
01228 /********************************************************************************************
01229 
01230     INT32 FindRoots( Point2* w, INT32 degree, double* t, INT32 depth)
01231  
01232     Author:     
01233     Created:    22/08/94
01234     Inputs:     w       = Control points of cubic Bezier
01235                 degree  = The degree of the polynomial
01236                 depth   = The depth of the recursion
01237     Outputs:    t       = a list of candidate t-values
01238     Returns:
01239     Purpose:    Given a 5th-degree equation in Bernstein-Bezier form, find
01240                 all of the roots in the interval [0, 1].  Return the number
01241                 of roots found.
01242  
01243  ********************************************************************************************/
01244 
01245 INT32 FindRoots( Point2* w, INT32 degree, double* t, INT32 depth) 
01246 {  
01247     INT32   i;
01248     Point2  Left[W_DEGREE+1],       // New left and right
01249             Right[W_DEGREE+1];      // control polygons
01250     INT32   left_count,             // Solution count from children
01251             right_count;
01252     double  left_t[W_DEGREE+1],     // Solutions from kids
01253             right_t[W_DEGREE+1];
01254 
01255     switch (CrossingCount(w, degree)) 
01256     {
01257         case 0 : 
01258         {   // No solutions here
01259          return 0;  
01260          break;
01261         }
01262         case 1 : 
01263         {   // Unique solution
01264             // Stop recursion when the tree is deep enough
01265             // if deep enough, return 1 solution at midpoint
01266             if (depth >= MAXDEPTH) 
01267             {
01268                 t[0] = (w[0].x + w[W_DEGREE].x) / 2.0;
01269                 return 1;
01270             }
01271             if (ControlPolygonFlatEnough(w, degree)) 
01272             {
01273                 t[0] = ComputeXIntercept(w, degree);
01274                 return 1;
01275             }
01276             break;
01277         }
01278     }
01279 
01280     // Otherwise, solve recursively after
01281     // subdividing control polygon
01282 
01283     Bezier(w, degree, 0.5, Left, Right);
01284     left_count  = FindRoots(Left,  degree, left_t, depth+1);
01285     right_count = FindRoots(Right, degree, right_t, depth+1);
01286 
01287 
01288     /* Gather solutions together    */
01289     for (i = 0; i < left_count; i++) 
01290     {
01291         t[i] = left_t[i];
01292     }
01293     for (i = 0; i < right_count; i++) 
01294     {
01295         t[i+left_count] = right_t[i];
01296     }
01297 
01298     /* Send back total number of solutions  */
01299     return (left_count+right_count);
01300 }
01301 
01302 
01303 
01304 
01305 /********************************************************************************************
01306 
01307     Point2 *ConvertToBezierForm( Point2 P, Point2* V )
01308 
01309     Author:     
01310     Created:    22/08/94
01311     Inputs:     P   =  The point to find t for
01312                 V   =  Control points of cubic Bezier
01313     Outputs:
01314     Returns:
01315     Purpose:    Given a point and a Bezier curve, generate a 5th-degree
01316                 Bezier-format equation whose solution finds the point on the
01317                 curve nearest the user-defined point.
01318 
01319  *******************************************************************************************/
01320 
01321 Point2 *ConvertToBezierForm( Point2 P, Point2* V )
01322 {
01323     INT32 i, j, k, m, n, ub, lb;    
01324     INT32 row, column;          // Table indices
01325     Vector2 c[DEGREE+1];        // V(i)'s - P
01326     Vector2 d[DEGREE];          // V(i+1) - V(i)
01327     Point2 *w;                  // Ctrl pts of 5th-degree curve
01328     double cdTable[3][4];       // Dot product of c, d
01329     static double z[3][4] = {   // Precomputed "z" for cubics
01330         {1.0, 0.6, 0.3, 0.1},
01331         {0.4, 0.6, 0.6, 0.4},
01332         {0.1, 0.3, 0.6, 1.0},
01333     };
01334 
01335 
01336     // Determine the c's -- these are vectors created by subtracting
01337     // point P from each of the control points
01338 
01339     for (i = 0; i <= DEGREE; i++) 
01340     {
01341         V2Sub(&V[i], &P, &c[i]);
01342     }
01343     
01344     // Determine the d's -- these are vectors created by subtracting
01345     // each control point from the next
01346 
01347     for (i = 0; i <= DEGREE - 1; i++) 
01348     { 
01349         d[i] = V2ScaleII(V2Sub(&V[i+1], &V[i], &d[i]), 3.0);
01350     }
01351 
01352     // Create the c,d table -- this is a table of dot products of the
01353     // c's and d's
01354     
01355     for (row = 0; row <= DEGREE - 1; row++) 
01356     {
01357         for (column = 0; column <= DEGREE; column++) 
01358         {
01359             cdTable[row][column] = V2Dot(&d[row], &c[column]);
01360         }
01361     }
01362 
01363     // Now, apply the z's to the dot products, on the skew diagonal
01364     // Also, set up the x-values, making these "points"
01365 
01366     w = (Point2 *)CCMalloc((unsigned)(W_DEGREE+1) * sizeof(Point2));
01367     for (i = 0; i <= W_DEGREE; i++) 
01368     {
01369         w[i].y = 0.0;
01370         w[i].x = (double)(i) / W_DEGREE;
01371     }
01372 
01373     n = DEGREE;
01374     m = DEGREE-1;
01375     for (k = 0; k <= n + m; k++) 
01376     {
01377         lb = MAX(0, k - m);
01378         ub = MIN(k, n);
01379         for (i = lb; i <= ub; i++) 
01380         {
01381             j = k - i;
01382             w[i+j].y += cdTable[j][i] * z[j][i];
01383         }
01384     }
01385 
01386     return (w);
01387 }
01388 
01389 
01390 /*******************************************************************************************
01391 
01392 >   double PathUtil::SqrDistanceToCurve(DocCoord* V, DocCoord& P, double* mu )
01393 
01394     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01395     Created:    22/08/94
01396     Inputs:     split =  max level at which to split the curve (usually 64)
01397                 P     =  The user-supplied point
01398                 V     =  Control points of cubic Bezier
01399     Outputs:    mu holds the parameter value of the closest point on the curve, 0<=mu<=1    
01400     Returns:    The squared distance to the curve
01401     Purpose:    Compute the parameter value of the point on a Bezier
01402                 curve segment closest to some arbtitrary, user-input point.
01403                 Return the squared distance to the curve.
01404  
01405  *******************************************************************************************/
01406 
01407 double PathUtil::SqrDistanceToCurve(const UINT32 split,
01408                                     const DocCoord* V,
01409                                     const DocCoord& P,
01410                                     double* mu )
01411 {
01412     Point2  *w;                             // Ctrl pts for 5th-degree equ
01413     Point2  lcurve[DEGREE+1];               // Local double version of control polygon
01414     double  t_candidate[W_DEGREE];          // Possible roots     
01415     INT32   n_solutions;                    // Number of roots found
01416     double  t;                              // Parameter value of closest pt
01417     double  dist;                           // Closest squared distance to curve
01418 
01419     // Convert control polygon to double type
01420 
01421     for (INT32 i=0; i < DEGREE+1; i++)
01422     {
01423         lcurve[i].x = (double) V[i].x;
01424         lcurve[i].y = (double) V[i].y;
01425     }
01426 
01427     Point2 p;
01428     p.x = (double) P.x;
01429     p.y = (double) P.y;
01430 
01431     //  Convert problem to 5th-degree Bezier form
01432 
01433     w = ConvertToBezierForm(p, lcurve);
01434 
01435     // Find all possible roots of 5th-degree equation
01436 
01437     n_solutions = FindRoots(w, W_DEGREE, t_candidate, 0);
01438     CCFree((char *)w);
01439 
01440     // Compare distances of P to all candidates, and to t=0, and t=1
01441 
01442     {   double  new_dist;
01443         Point2  q;
01444         Vector2 v;
01445 
01446     // Check distance to beginning of curve, where t = 0
01447 
01448         dist = V2SquaredLength(V2Sub(&p, lcurve, &v));
01449         t = 0.0;
01450 
01451     // Find distances for candidate points
01452 
01453         for (INT32 i = 0; i < n_solutions; i++) 
01454         {
01455             q = Bezier(lcurve, DEGREE, t_candidate[i], NULL, NULL);
01456             new_dist = V2SquaredLength(V2Sub(&p, &q, &v));
01457             if (new_dist < dist)
01458             {
01459                     dist = new_dist;
01460                     t = t_candidate[i];
01461             }
01462         }
01463 
01464     // Finally, look at distance to end point, where t = 1
01465 
01466         new_dist = V2SquaredLength(V2Sub(&p, &(lcurve[DEGREE]), &v));
01467         if (new_dist < dist)
01468         {
01469             dist = new_dist;
01470             t = 1.0;
01471         }
01472     }
01473 
01474    *mu = t;
01475    return dist;
01476 
01477 }

Generated on Sat Nov 10 03:46:29 2007 for Camelot by  doxygen 1.4.4