Logo Search packages:      
Sourcecode: latexdraw version File versions  Download package

BezierCurve.java

package latexDraw.figures;

import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Vector;

import javax.swing.JLabel;

import latexDraw.figures.properties.Arrowable;
import latexDraw.psTricks.DviPsColors;
import latexDraw.psTricks.PSTricksConstants;
import latexDraw.ui.LaTeXDrawFrame;
import latexDraw.ui.components.Delimitor;
import latexDraw.ui.components.LaTeXDrawComboBox;
import latexDraw.ui.components.LabelListCellRenderer;
import latexDraw.ui.components.MagneticGrid;
import latexDraw.util.LaTeXDrawException;
import latexDraw.util.LaTeXDrawNumber;
import latexDraw.util.LaTeXDrawPoint2D;
import latexDraw.util.LaTeXDrawResources;


/**
 * The class defines a new kind of figure, Bézier curves.
 *<br>
 * This file is part of LaTeXDraw.<br>
 * Copyright(c) 2005-2008 Arnaud BLOUIN<br>
 *<br>
 *  LaTeXDraw is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  any later version.<br>
 *<br>
 *  LaTeXDraw is distributed without any warranty; without even the 
 *  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
 *  PURPOSE. See the GNU General Public License for more details.<br>
 *<br>
 * 07/25/06<br>
 * @author Arnaud BLOUIN<br>
 * @version 2.0.0<br>
 */
00047 public class BezierCurve extends LaTeXDrawPolygon implements Arrowable
{
      private static final long serialVersionUID = 1L;

      /** This vector contains the points which allows to change the angles of the curves */
00052       protected Vector<LaTeXDrawPoint2D> ctrlPts;
      
      /** Contains the second control points of each points; useful for closed curve. @since 1.9 */
00055       protected Vector<LaTeXDrawPoint2D> secondCtrlPts;
      
      /** This vector contains the lines which allows to change the angles of the curves */
00058       protected Vector<Line> ctrlLines;
      
      /** Contains the second control lines of each point; useful for closed curve. @since 1.9 */
00061       protected transient Vector<Line> secondCtrlLines;
      
      /** If true, the control lines are displayed */
00064       protected boolean showPoints;
      
      /** the arrowhead of the first point. */
00067       protected ArrowHead arrowHead1;
      
      /** The arrow head of the second point. */
00070       protected ArrowHead arrowHead2;
      
      /** Define if the path must be closed or not. @since 1.9 */
00073       protected boolean open;
      
      /** 
       * Define the shape of the closing path. 
       * @since 1.9
       * @see BezierCurve#CLOSE_TYPE_CURVE
       * @see BezierCurve#CLOSE_TYPE_LINE  
       */
00081       protected int closeType;
      
      /** 
       * Define the gap between a control point and its point in pixel when using {@link #equilibrate()} 
       * method. 
       * @since 1.9
       */
00088       protected int equilibrateGap;
      
      
      public static final int DEFAULT_EQUILIBRATE_GAP = 50;
      
      /** The value of showPoints by default */
00094       public static final boolean DEFAULT_SHOWPOINTS = false;
      
      /** The gap of the control point by default */
00097       public static final int DEFAULT_POSITION_CTRL = 40;
      
      /** The value by default of <code>open</code>. */
00100       public static final boolean DEFAULT_OPEN = false;
      
      /** The closing path will be a line. */
00103       public static final short CLOSE_TYPE_LINE  = 0;
      
      /** The closing path will be a Bézier curve. */
00106       public static final short CLOSE_TYPE_CURVE = 1;
      
      /** The value of <code>closeType</code> by default. */
00109       public static final short DEFAULT_CLOSE_TYPE = CLOSE_TYPE_CURVE;
      
      public static final String LABEL_CLOSE_CHOICE = "closeBezierCh";//$NON-NLS-1$
      
      
      
      /** 
       * The constructor by default.
       */
00118       public BezierCurve(boolean increaseMeter)
      {
            this(new LaTeXDrawPoint2D(), new LaTeXDrawPoint2D(), increaseMeter);
      }

      
      
      
      /**
       * @param pt1 The first point.
       * @param pt2 The second point.
       */
00130       public BezierCurve(LaTeXDrawPoint2D pt1, LaTeXDrawPoint2D pt2, boolean increaseMeter)
      {
            this(pt1, pt2, DEFAULT_OPEN, increaseMeter);
      }


      
      
      /**
       * @param pt1 The first point.
       * @param pt2 The second point.
       * @param isOpen Defines if the curve will be open or not.
       * @since 1.9
       */
00144       public BezierCurve(LaTeXDrawPoint2D pt1, LaTeXDrawPoint2D pt2, boolean isOpen, boolean increaseMeter)
      {
            super(pt1, pt2, increaseMeter);
            equilibrateGap    = DEFAULT_EQUILIBRATE_GAP;
            closeType         = DEFAULT_CLOSE_TYPE;
            canHaveArrow      = true;
            isBordersMovable= false;
            showPoints        = DEFAULT_SHOWPOINTS;
            LaTeXDrawPoint2D pt1b = new LaTeXDrawPoint2D(pt1), pt2b = new LaTeXDrawPoint2D(pt2);
            arrowHead1 = new ArrowHead(pt1b, new Line(pt1b, getFirstControlPoint(0), false), this);
            arrowHead2 = new ArrowHead(pt2b, new Line(pt2b, getFirstControlPoint(-1), false), this);
            
            updateBorders();
            setOpen(isOpen);
      }
      
      
      /**
       * Allows to add a control line.
       * @param pt The new point of the Bézier curve.
       * @param ctrlPt The new control point of the new point pt.
       * @param pos The position of the new line in the vector (if -1 the line is
       * put at the end of the vector).
       */
00168       protected void addCtrlLineAt(LaTeXDrawPoint2D pt, LaTeXDrawPoint2D ctrlPt, LaTeXDrawPoint2D ctrlPt2, int pos)
      {
            if(ctrlLines == null) 
            {
                  secondCtrlLines   = new Vector<Line>();
                  ctrlLines         = new Vector<Line>();
            }
            
            if(pos<-1 || pos>ctrlPts.size())
                  throw new IllegalArgumentException("Invalid position");//$NON-NLS-1$
            
            Line l  = new Line(pt, ctrlPt, false);
            Line l2 = new Line(pt, ctrlPt2, false);
            double dim = Math.max(6,1.33*thickness+3.33 +1.);
            
            if(pos==-1 || pos==ctrlPts.size()-1)
            {
                  ctrlLines.add(l);
                  secondCtrlLines.add(l2);
            }
            else 
            {
                  ctrlLines.add(pos, l);
                  secondCtrlLines.add(pos, l2);
            }
            
            l.setLinesColor(Color.GRAY);
            l.setLineStyle(PSTricksConstants.LINE_DASHED_STYLE);
            l.setThickness(1);
            l.delimiters.firstElement().setDim(dim);
            l.delimiters.lastElement().setDim(dim);
            l2.setLinesColor(Color.GRAY);
            l2.setLineStyle(PSTricksConstants.LINE_DASHED_STYLE);
            l2.setThickness(1);
            l2.delimiters.firstElement().setDim(dim);
            l2.delimiters.lastElement().setDim(dim);
      }
      

      
      
      /**
       * Allows to add a control line at the end of the vector.
       * @param pt The new point of the Bézier curve.
       * @param ctrlPt The new control point of the new point point.
       */
00214       protected void addCtrlLine(LaTeXDrawPoint2D pt, LaTeXDrawPoint2D ctrlPt, LaTeXDrawPoint2D ctrlPt2)
      {
            addCtrlLineAt(pt, ctrlPt, ctrlPt2, -1);
      }
      
      


      @Override
00223       public boolean addPointAt(LaTeXDrawPoint2D pt, int id)
      {
            if(pt!=null)
            {
                  if(ctrlPts==null) 
                  {
                        ctrlPts                 = new Vector<LaTeXDrawPoint2D>();
                        secondCtrlPts     = new Vector<LaTeXDrawPoint2D>();
                  }
                  
                  if(super.addPointAt(pt, id))
                  {
                        LaTeXDrawPoint2D ctrlPt  = new LaTeXDrawPoint2D(pt.x, pt.y+DEFAULT_POSITION_CTRL);
                        LaTeXDrawPoint2D ctrlPt2 = ctrlPt.centralSymmetry(pt);
                        
                        if(id==pts.size()-2 || pts.isEmpty())
                        {
                              ctrlPts.add(ctrlPt);
                              secondCtrlPts.add(ctrlPt2);
                              addCtrlLine(pt, ctrlPt, ctrlPt2);
                        }
                        else
                        {
                              ctrlPts.add(id, ctrlPt);
                              secondCtrlPts.add(id, ctrlPt2);
                              addCtrlLineAt(pt, ctrlPt, ctrlPt2, id);
                        }
                        
                        if(id==0 && arrowHead1!=null)
                        {
                              LaTeXDrawPoint2D pt2 = new LaTeXDrawPoint2D(pts.firstElement()); 
                              arrowHead1.setPosition(pt2);
                              arrowHead1.setLine(new Line(pt2, ctrlPts.firstElement(), false));
                        }
                        else
                              if(arrowHead2!=null && id==pts.size()-2)
                              {
                                    LaTeXDrawPoint2D pt2 = new LaTeXDrawPoint2D(pt); 
                                    arrowHead2.setPosition(pt2);
                                    arrowHead2.setLine(new Line(pt2, ctrlPts.lastElement(), false));
                              }

                        
                        return true;
                  }
            }
            return false;
      }
      


      @Override
      public Object clone() throws CloneNotSupportedException
      {
            BezierCurve b     = (BezierCurve)super.clone();
            b.equilibrateGap= equilibrateGap;
            b.ctrlPts         = new Vector<LaTeXDrawPoint2D>();
            b.secondCtrlPts = new Vector<LaTeXDrawPoint2D>();
            b.ctrlLines       = new Vector<Line>();
            b.secondCtrlLines       = new Vector<Line>();
            b.arrowHead1      = (ArrowHead)arrowHead1.clone();
            b.arrowHead2      = (ArrowHead)arrowHead2.clone();
            int i, size       = ctrlPts.size();
            
            for(i=0; i<size; i++)
            {
                  b.ctrlPts.add((LaTeXDrawPoint2D)ctrlPts.elementAt(i).clone());
                  b.secondCtrlPts.add((LaTeXDrawPoint2D)secondCtrlPts.elementAt(i).clone());
            }
            
            for(i=0; i<size; i++)
                  b.addCtrlLine(b.pts.elementAt(i), b.ctrlPts.elementAt(i), b.secondCtrlPts.elementAt(i));
            
            LaTeXDrawPoint2D pt1b = new LaTeXDrawPoint2D(b.getPoint(0));
            LaTeXDrawPoint2D pt2b = new LaTeXDrawPoint2D(b.getPoint(-1));
            
            b.arrowHead1.setPosition(pt1b);
            b.arrowHead2.setPosition(pt2b);
            b.arrowHead1.setLine(new Line(pt1b, b.getFirstControlPoint(0), false));
            b.arrowHead2.setLine(new Line(pt2b, b.getFirstControlPoint(-1), false));
            b.arrowHead1.setFigure(b);
            b.arrowHead2.setFigure(b);
            
            b.open            = open;
            b.closeType = closeType;
            b.updateBorders();
            b.updateShape();
            
            return b;
      }



      @Override
00317       public void draw(Graphics2D g, Object antiAlias, Object rendering, Object alphaInter, Object colorRendering)
      {
            Color formerCol = g.getColor();
            double dx=0, dy=0;
            LaTeXDrawPoint2D formerPt1 = new LaTeXDrawPoint2D(getPoint(0));
            LaTeXDrawPoint2D formerPt2 = new LaTeXDrawPoint2D(getPoint(-1));
            String arrowHead1Style = arrowHead1.getArrowStyle();
            String arrowHead2Style = arrowHead2.getArrowStyle();
            boolean arrow1Drawable = arrowHead1.isDrawable() && !arrowHead1Style.equals(PSTricksConstants.NONEARROW_STYLE) && pts.size()>1;
            boolean arrow2Drawable = arrowHead2.isDrawable() && !arrowHead2Style.equals(PSTricksConstants.NONEARROW_STYLE) && 
                                                      pts.size()>1 && isOpen();

            if(lineStyle.equals(PSTricksConstants.LINE_NONE_STYLE))
                  g.setStroke(new BasicStroke(thickness, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER));
            else 
            if(lineStyle.equals(PSTricksConstants.LINE_DOTTED_STYLE))
                  g.setStroke(new BasicStroke(thickness, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER,
                              1.f, new float[]{0,thickness+dotSep}, 0));
            else
            if(lineStyle.equals(PSTricksConstants.LINE_DASHED_STYLE))
                  g.setStroke(new BasicStroke(thickness, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
                              1.f, new float[]{blackDashLength, whiteDashLength}, 0));
            
            int i, size = getNbPoints();
            
            if(shape==null)
                  shape = getSimpleShape();
            
            g.setColor(linesColor);
            
            boolean update=false;
            
            if(arrow1Drawable)
            {
                  double lgth = arrowHead1.getArrowHeadLength();
                  
                  try
                  {
                        LaTeXDrawPoint2D[] points = arrowHead1.getLine().findPoints(arrowHead1.getPosition(), lgth);
                        LaTeXDrawPoint2D newPt=null;
                        
                        if(points.length==1)
                              newPt=points[0];
                        else
                              newPt=points[0].distance(getFirstControlPoint(0))<points[1].distance(getFirstControlPoint(0))
                                                ?points[0]:points[1];
                                                
                        getPoint(0).setLocation(newPt);
                        update=true;
                        
                  }catch(LaTeXDrawException e)
                  {
                        e.printStackTrace();
                        return ;
                  }
            }
            
            if(arrow2Drawable)
            {
                  double lgth = arrowHead2.getArrowHeadLength();

                  try
                  {
                        LaTeXDrawPoint2D[] points = arrowHead2.getLine().findPoints(arrowHead2.getPosition(), lgth);
                        LaTeXDrawPoint2D newPt=null;
                        
                        if(points.length==1)
                              newPt=points[0];
                        else
                              newPt=points[0].distance(getFirstControlPoint(-1))<
                                                points[1].distance(getFirstControlPoint(-1)) ? points[0]:points[1];
                        
                        getPoint(-1).setLocation(newPt);
                        update=true;
                        
                  }catch(LaTeXDrawException e)
                  {
                        e.printStackTrace();
                        return ;
                  }
            }
            
            if(update)
                  shape = getSimpleShape();
            
            if(showPoints)// When show points, the curve must be dashed too :s.
            {
                  double thick = hasDoubleBoundary?(float)(doubleSep+thickness*2.):thickness;
                  Stroke formerS = g.getStroke();
                  
                  g.setStroke(new BasicStroke((float)(thick/2.), BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
                                    1.f, new float[]{blackDashLength, whiteDashLength}, 0));
                  g.setColor(linesColor);
                  g.draw(shape);
                  g.setStroke(formerS);
            }
            
            if(hasShadow)
            {
                  LaTeXDrawPoint2D cg = getGravityCenter();
                  LaTeXDrawPoint2D shadowCg = (LaTeXDrawPoint2D)cg.clone();
                  shadowCg.setLocation(cg.x+shadowSize, cg.y);
                  shadowCg = Figure.rotatePoint(shadowCg, cg, shadowAngle);
                  dx = shadowCg.x-cg.x;
                  dy = cg.y-shadowCg.y;
            }
            
            if(hasDoubleBoundary)
            {
                  g.setColor(linesColor);
                  BasicStroke wideline=null;
                  
                  if(lineStyle.equals(PSTricksConstants.LINE_NONE_STYLE))
                        wideline = new BasicStroke((float)(doubleSep+thickness*2.), BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);
                  else 
                  if(lineStyle.equals(PSTricksConstants.LINE_DOTTED_STYLE))
                        wideline = new BasicStroke((float)(thickness*2+doubleSep), BasicStroke.CAP_ROUND,
                                    BasicStroke.JOIN_MITER, 1.f, new float[] { 0, (float)(thickness*2+doubleSep + dotSep) }, 0);
                  else
                        wideline = new BasicStroke((float)(doubleSep+thickness*2.), BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
                                    1.f, new float[]{blackDashLength, whiteDashLength}, 0);
                  
                  if(hasShadow)
                  {
                        BasicStroke wideline2 = new BasicStroke((float)(doubleSep+thickness*2.), BasicStroke.CAP_BUTT, 
                                                                                    BasicStroke.JOIN_MITER);
                        Shape outline2 = wideline2.createStrokedShape(shape);
                        Stroke stroke = g.getStroke();
                        g.setStroke(new BasicStroke(thickness, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER));
                        g.translate(dx, dy);
                        g.setColor(shadowColor);
                        if(isFilled() || isHatched() || hasGradient()) g.fill(shape);
                        g.fill(outline2);
                        
                        if(arrow1Drawable)
                        {
                              Stroke stroke2 = g.getStroke();
                              g.setStroke(new BasicStroke((float)(doubleSep+thickness*2.), BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER));
                              arrowHead1.draw(g, interiorColor, true);
                              g.setStroke(stroke2);
                        }
                        
                        if(arrow2Drawable)
                        {
                              Stroke stroke2 = g.getStroke();
                              g.setStroke(new BasicStroke((float)(doubleSep+thickness*2.), BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER));
                              arrowHead2.draw(g, interiorColor, true);
                              g.setStroke(stroke2);
                        }
                        
                        g.translate(-dx, -dy);
                        
                        if(isFilled() || isHatched() || hasGradient()) 
                        {
                              g.setColor(interiorColor);
                              g.setStroke(new BasicStroke((float)(thickness*2+doubleSep), BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER));
                              g.draw(shape);
                        }
                        
                        g.setStroke(stroke);
                  }
                        
                  Shape outline = wideline.createStrokedShape(shape);
                  fillFigure(g, antiAlias, rendering, alphaInter, colorRendering, shape);
                  g.setColor(linesColor);
                  g.fill(outline);
                  g.setColor(doubleColor);
                  wideline = new BasicStroke((float)doubleSep, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);
              outline = wideline.createStrokedShape(shape);
                  g.fill(outline);
            }
            else
            {
                  if(hasShadow)
                  {
                        g.translate(dx, dy);
                        Stroke formerS = g.getStroke();
                        g.setStroke(new BasicStroke(thickness, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER));
                        g.setColor(shadowColor);
                        
                        if(isFilled() || isHatched() || hasGradient()) 
                              g.fill(shape);
                        
                        g.draw(shape);
                        
                        if(arrow1Drawable)
                              arrowHead1.draw(g, interiorColor, true);
                        
                        if(arrow2Drawable)
                              arrowHead2.draw(g, interiorColor, true);

                        g.translate(-dx, -dy);
                        
                        if(isFilled() || isHatched() || hasGradient()) 
                        {
                              g.setColor(interiorColor);
                              g.draw(shape);
                        }
                        
                        g.setStroke(formerS);
                  }

                  fillFigure(g, antiAlias, rendering, alphaInter, colorRendering, shape);
                  g.setColor(linesColor);
                  g.draw(shape);
            }
            
            if(arrow1Drawable)
            {
                  g.setStroke(new BasicStroke(hasDoubleBoundary?(float)(doubleSep+thickness*2.):thickness, 
                                                            BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER));
                  arrowHead1.draw(g, interiorColor, false);
            }
            
            if(arrow2Drawable)
            {
                  g.setStroke(new BasicStroke(hasDoubleBoundary?(float)(doubleSep+thickness*2.):thickness, 
                              BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER));
                  arrowHead2.draw(g, interiorColor, false);
            }
            
            if(showPoints)
            {
                  double thick = hasDoubleBoundary?(float)(doubleSep+thickness*2.):thickness;
                  float width = (float)(arrowHead1.getDotSizeDim() + arrowHead1.getDotSizeNum()*thick);
                  Dot d = new Dot(false);
                  Line2D.Double line = new Line2D.Double();
                  
                  d.setLinesColor(linesColor);
                  d.setWidth(width);
                  
                  g.setStroke(new BasicStroke((float)(thick/2.), BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
                              1.f, new float[]{blackDashLength, whiteDashLength}, 0));
                  g.setColor(linesColor);
            
                  for(i=3; i<size; i+=2)
                  {
                        line.setLine(getPoint(i-1), getSecondControlPoint(i-1));
                        g.draw(line);
                        line.setLine(getSecondControlPoint(i-1), getFirstControlPoint(i));
                        g.draw(line);
                        line.setLine(getFirstControlPoint(i), getPoint(i));
                        g.draw(line);
                  }
                  
                  for(i=2; i<size; i+=2)
                  {
                        line.setLine(getPoint(i-1), getSecondControlPoint(i-1));
                        g.draw(line);
                        line.setLine(getSecondControlPoint(i-1), getFirstControlPoint(i));
                        g.draw(line);
                        line.setLine(getFirstControlPoint(i), getPoint(i));
                        g.draw(line);
                  }
                  
                  if(!open && closeType==CLOSE_TYPE_CURVE)
                  {
                        line.setLine(getPoint(-1), getSecondControlPoint(-1));
                        g.draw(line);
                        line.setLine(getSecondControlPoint(-1), getSecondControlPoint(0));
                        g.draw(line);
                        line.setLine(getSecondControlPoint(0), getPoint(0));
                        g.draw(line);
                  }
                  
                  line.setLine(getPoint(0), getFirstControlPoint(0));
                  g.draw(line);
                  line.setLine(getFirstControlPoint(0), getFirstControlPoint(1));
                  g.draw(line);
                  line.setLine(getFirstControlPoint(1), getPoint(1));
                  g.draw(line);
                  
                  if(!arrow1Drawable || (!open && closeType==CLOSE_TYPE_CURVE))
                  {
                        d.setCenter(getPoint(0));
                        d.draw(g, antiAlias, rendering, alphaInter, colorRendering);
                  }
                  
                  if(!arrow2Drawable || (!open && closeType==CLOSE_TYPE_CURVE))
                  {
                        d.setCenter(getPoint(-1));
                        d.draw(g, antiAlias, rendering, alphaInter, colorRendering);
                  }
                  
                  for(i=1; i<size-1; i++)
                  {
                        d.setCenter(pts.elementAt(i));
                        d.draw(g, antiAlias, rendering, alphaInter, colorRendering);
                        d.setCenter(secondCtrlPts.elementAt(i));
                        d.draw(g, antiAlias, rendering, alphaInter, colorRendering);
                  }
                  
                  for(i=0; i<size; i++)
                  {
                        d.setCenter(ctrlPts.elementAt(i));
                        d.draw(g, antiAlias, rendering, alphaInter, colorRendering);
                  }
                  
                  if(!open && closeType==CLOSE_TYPE_CURVE)
                  {
                        d.setCenter(secondCtrlPts.lastElement());
                        d.draw(g, antiAlias, rendering, alphaInter, colorRendering);
                        d.setCenter(secondCtrlPts.firstElement());
                        d.draw(g, antiAlias, rendering, alphaInter, colorRendering);
                  }
            }
            
            g.setColor(formerCol);
            getPoint(0).setLocation(formerPt1);
            getPoint(-1).setLocation(formerPt2);

            if(isSelected)
            {
                  int sizeD = delimiters.size();
                  for(i=0; i<sizeD; i++)
                        delimiters.elementAt(i).draw(g);
                  
                  if(!isOnRotation)
                        if(open)
                        {
                              if(size>1)
                              {
                                    ctrlLines.firstElement().draw(g, antiAlias, rendering, alphaInter, colorRendering);
                                    ctrlLines.firstElement().delimiters.elementAt(1).draw(g);
                                    
                                    for(i=1; i<size-1; i++)
                                    {
                                          ctrlLines.elementAt(i).draw(g, antiAlias, rendering, alphaInter, colorRendering);
                                          ctrlLines.elementAt(i).delimiters.elementAt(1).draw(g);
                                          secondCtrlLines.elementAt(i).draw(g, antiAlias, rendering, alphaInter, colorRendering);
                                          secondCtrlLines.elementAt(i).delimiters.elementAt(1).draw(g);
                                    }
                                    
                                    ctrlLines.lastElement().draw(g, antiAlias, rendering, alphaInter, colorRendering);
                                    ctrlLines.lastElement().delimiters.elementAt(1).draw(g);
                              }
                        }
                        else
                              for(i=0; i<size; i++)
                              {
                                    ctrlLines.elementAt(i).draw(g, antiAlias, rendering, alphaInter, colorRendering);
                                    ctrlLines.elementAt(i).delimiters.elementAt(1).draw(g);
                                    secondCtrlLines.elementAt(i).draw(g, antiAlias, rendering, alphaInter, colorRendering);
                                    secondCtrlLines.elementAt(i).delimiters.elementAt(1).draw(g);
                              }
                  
                  if(borders!=null)
                        borders.draw(g, false, antiAlias, rendering, alphaInter, colorRendering);
            }//if(selected)
      }





      @Override
00673       public void onClick(Point pt)
      {
            super.onClick(pt);

            if(dSelected!=null)
                  return ;
            
            int i, size = ctrlLines.size(), j;
            boolean ok = false;
            Line l;
            
            for(i = 0; i<size && !ok; i++)
            {
                  l  = ctrlLines.elementAt(i);

                  if(dSelected==null)
                        for(j=0; j<Line.LINE_NB_POINTS && !ok; j++)
                              if(l.delimiters.elementAt(j).isIn(pt))
                              {
                                    dSelected = l.delimiters.elementAt(j);
                                    ok = true;
                              }
            }//for
            
            if(open)
            {
                  i=1;
                  size--;
            }
            else
                  i=0;
            
            for(; i<size && !ok; i++)
            {
                  l = secondCtrlLines.elementAt(i);
                  
                  for(j=0; j<Line.LINE_NB_POINTS && !ok; j++)
                        if(l.delimiters.elementAt(j).isIn(pt))
                        {
                              dSelected = l.delimiters.elementAt(j);
                              ok = true;
                        }
            }
      }




      

      @Override
00724       public boolean isIn(LaTeXDrawPoint2D pt)
      {
            int i, size = ctrlLines.size();
            
            if(isSelected)
            {
                  if(borders.dNE.isIn(pt) || borders.dNW.isIn(pt) || borders.dSE.isIn(pt) || borders.dSW.isIn(pt) || borders.dS.isIn(pt) || 
                        borders.dN.isIn(pt) || borders.dE.isIn(pt) || borders.dW.isIn(pt))
                              return true;
                  
                  for(Delimitor d : delimiters)
                        if(d.isIn(pt))
                              return true;
                  
                  if(open)
                  {
                        for(i=0; i<size; i++)
                              if(ctrlLines.elementAt(i).delimiters.elementAt(1).isIn(pt)) 
                                    return true;
                        
                        for(i=1; i<size-1; i++)
                              if(secondCtrlLines.elementAt(i).delimiters.elementAt(1).isIn(pt)) 
                                    return true;
                  }
                  else
                        for(i=0; i<size; i++)
                        {
                              if(ctrlLines.elementAt(i).delimiters.elementAt(1).isIn(pt)) 
                                    return true;
                              if(secondCtrlLines.elementAt(i).delimiters.elementAt(1).isIn(pt)) 
                                    return true;
                        }           
            }
            
            boolean in=false;
            BasicStroke wideline = new BasicStroke(hasDoubleBoundary ? (float)(doubleSep/2.+thickness*2) : thickness);
            in = wideline.createStrokedShape(shape).contains(pt);
            
            if(in) return true;
            
            if(isFilled() || hasGradient() || isHatched())
                  in = shape.contains(pt);
            
            return in;
      }



      
      

      @Override
00776       public void onDragged(Point formerPt, Point newPt) throws Exception
      {
            if(formerPt.equals(newPt)) return;
            
            if(isOnRotation || dSelected==null)
                  super.onDragged(formerPt, newPt);
            else
            {
                  boolean again = true;
                  int size = pts.size(), i=0;
                  
                  while(again && i<size)
                        if(dSelected.getCenter().equals(secondCtrlPts.elementAt(i)))
                              again = false;
                        else
                              i++;

                  if(again)// no second ctrl pt selected
                  {
                        i=0;
                        while(again && i<size)
                              if(dSelected.getCenter().equals(pts.elementAt(i)))
                              {
                                    ctrlPts.elementAt(i).x += newPt.x-formerPt.x;
                                    ctrlPts.elementAt(i).y += newPt.y-formerPt.y;
                                    secondCtrlPts.elementAt(i).x += newPt.x-formerPt.x;
                                    secondCtrlPts.elementAt(i).y += newPt.y-formerPt.y;
                                    again = false;
                              }
                              else
                                    i++;
                        
                        if(again)//no point selected
                        {
                              i=0;
                              while(again && i<size)
                                    if(dSelected.getCenter().equals(ctrlPts.elementAt(i)))
                                    {
                                          secondCtrlPts.elementAt(i).x += formerPt.x-newPt.x;
                                          secondCtrlPts.elementAt(i).y += formerPt.y-newPt.y;
                                          again = false;
                                    }
                                    else
                                          i++;
                        }
                        
                        dSelected.getCenter().x = newPt.x;
                        dSelected.getCenter().y = newPt.y;
                  }
                  else
                  {
                        dSelected.getCenter().x += newPt.x-formerPt.x;
                        dSelected.getCenter().y += newPt.y-formerPt.y;
                        ctrlPts.elementAt(i).x += formerPt.x-newPt.x;
                        ctrlPts.elementAt(i).y += formerPt.y-newPt.y;
                  }
                  
                  updateBorders();
                  updateShape();
            }

            updateSecondControlPoints();
            arrowHead1.getPosition().setLocation(getPoint(0));
            arrowHead2.getPosition().setLocation(getPoint(-1));
      }


      
      
      /**
       * Update the second control points by using the first control points.
       * @since 1.9
       */
00849       public void updateSecondControlPoints()
      {
            int size = pts.size(), i;
            
            for(i=0; i<size; i++)
                  secondCtrlPts.elementAt(i).setLocation(ctrlPts.elementAt(i).centralSymmetry(pts.elementAt(i)));
      }
      
      
      
      /**
       * Create the shape of the Bézier curve without double boundaries.
       * @return The shape.
       */
00863       private GeneralPath getSimpleShape()
      {
            if(ctrlPts==null || getNbPoints()<2 || ctrlPts.size()<2)
                  return null;
            
            int size = pts.size(), i;
            GeneralPath gp = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
            LaTeXDrawPoint2D ctrl1;
            
            //JAVA6 : put in moveto(double, double,...)
            gp.moveTo((float)pts.elementAt(0).x, (float)pts.elementAt(0).y);
            gp.curveTo((float)ctrlPts.elementAt(0).x, (float)ctrlPts.elementAt(0).y, 
                           (float)ctrlPts.elementAt(1).x, (float)ctrlPts.elementAt(1).y, 
                           (float)pts.elementAt(1).x, (float)pts.elementAt(1).y);
            
            for(i=2; i<size; i++)
            {
                  ctrl1 = secondCtrlPts.elementAt(i-1);
                  gp.curveTo((float)ctrl1.x, (float)ctrl1.y, 
                                 (float)ctrlPts.elementAt(i).x, (float)ctrlPts.elementAt(i).y, 
                                 (float)pts.elementAt(i).x, (float)pts.elementAt(i).y);
            }
            
            if(!open)
            {
                  if(getCloseType()==CLOSE_TYPE_CURVE)
                  {
                        LaTeXDrawPoint2D ctrl1b = ctrlPts.firstElement().centralSymmetry(pts.firstElement());
                        LaTeXDrawPoint2D ctrl2b = ctrlPts.lastElement().centralSymmetry(pts.lastElement());
                        
                        gp.curveTo((float)ctrl2b.x, (float)ctrl2b.y, (float)ctrl1b.x, 
                                    (float)ctrl1b.y, (float)pts.firstElement().x, (float)pts.firstElement().y);
                  }
                  
                  gp.closePath();
            }

            if(gp.getBounds().width==0 && gp.getBounds().height==0)
                  gp.lineTo((float)getPoint(0).x+1, (float)getPoint(0).y+1);
            
            return gp;
      }
      
      


      @Override
00910       public Shape createShape2D()
      {
            Shape s = getSimpleShape();
            
            if(hasDoubleBoundary)
            {
                  BasicStroke wideline = new BasicStroke((float)(doubleSep+thickness));
              Shape outline = wideline.createStrokedShape(s);
              return outline;
            }
            
            return s;
      }




      @Override
00928       public void removePointAt(int id)
      {
            super.removePointAt(id);

            if(ctrlLines.isEmpty()||ctrlPts.isEmpty())
                  return ;
            
            if(id>=ctrlLines.size() || id<-1)
                  throw new IllegalArgumentException();

            if(id==-1)
                  id = ctrlLines.size()-1;
            
            ctrlLines.remove(id);
            secondCtrlLines.remove(id);
            ctrlPts.remove(id);           
            secondCtrlPts.remove(id);
            
            if(id==pts.size())
            {
                  LaTeXDrawPoint2D pt2 = new LaTeXDrawPoint2D(pts.lastElement());
                  arrowHead2.setPosition(pt2);
                  arrowHead2.setLine(new Line(pt2, ctrlPts.lastElement(), false));
            }
            
            updateBorders();
            updateShape();
      }




      @Override
00961       public synchronized void setLastPoint(LaTeXDrawPoint2D pt)
      {
            double oldX = pts.lastElement().x;
            double oldY = pts.lastElement().y;
            
            super.setLastPoint(pt);
            // We move the last ctrl points of the Bézier curve
            if(!ctrlPts.isEmpty())
            {
                  LaTeXDrawPoint2D lastPt = ctrlPts.lastElement();
                  lastPt.x += pt.x - oldX;
                  lastPt.y += pt.y - oldY;
                  
                  secondCtrlPts.lastElement().setLocation(lastPt.centralSymmetry(pts.lastElement()));
                  arrowHead2.getPosition().setLocation(pt.x, pt.y);
                  updateBorders();
                  updateShape();
                  updateGravityCenter();
            }     
      }




      @Override
00986       public synchronized void setPointAt(LaTeXDrawPoint2D pt, int id)
      {
            super.setPointAt(pt, id);
            
            if(id<0 || id>=ctrlPts.size())
                  throw new IllegalArgumentException("Invalid id");//$NON-NLS-1$
            
            LaTeXDrawPoint2D ctrlPt  = new LaTeXDrawPoint2D(pt.x, pt.y+DEFAULT_POSITION_CTRL);
            LaTeXDrawPoint2D ctrlPt2 = ctrlPt.centralSymmetry(pt);
            ctrlPts.setElementAt(ctrlPt, id);
            secondCtrlPts.setElementAt(ctrlPt2, id);
            addCtrlLineAt(pt, ctrlPt, ctrlPt2, id);
            arrowHead1.getPosition().setLocation(getPoint(0));
            arrowHead2.getPosition().setLocation(getPoint(-1));
            shape = getSimpleShape();
      }


      
      
      @Override
01007       public String getCodePSTricks(DrawBorders drawBorders, float ppc)
      {
            LaTeXDrawPoint2D d = drawBorders.getOriginPoint();
            String coord, add="", arrowsCode = ""; //$NON-NLS-1$ //$NON-NLS-2$
            int i, size = getNbPoints();
            String start = "";//$NON-NLS-1$ 
            LaTeXDrawPoint2D pt, ctrlPt1, ctrlPt2;
            String showPointsCode = "";//$NON-NLS-1$ 
            String arrowParams = "";//$NON-NLS-1$ 
            boolean hasArrow1Style = !arrowHead1.isWithoutStyle();
            boolean hasArrow2Style = !arrowHead2.isWithoutStyle() && isOpen();
            double threshold = 0.001;
            
            if(size<2) return null;
            
            if(!linesColor.equals(PSTricksConstants.DEFAULT_LINE_COLOR))
            {
                  String name = DviPsColors.getColourName(linesColor);
                  if(name==null)
                  {
                        name = "color"+number;//$NON-NLS-1$
                        DviPsColors.addUserColour(linesColor, name); 
                  }
                  add += ",linecolor="+name; //$NON-NLS-1$
            }
            
            if(hasShadow)
            {
                  add+=",shadow=true";//$NON-NLS-1$
                  if(Math.toDegrees(shadowAngle)!=PSTricksConstants.DEFAULT_SHADOW_ANGLE)
                        add+=",shadowangle="+(float)Math.toDegrees(shadowAngle);//$NON-NLS-1$
                  
                  if(((float)shadowSize)!=((float)DEFAULT_SHADOW_SIZE))
                        add+=",shadowsize="+(float)(shadowSize/PPC);//$NON-NLS-1$
                  
                  if(!shadowColor.equals(PSTricksConstants.DEFAULT_SHADOW_COLOR))
                  {
                        String name = DviPsColors.getColourName(shadowColor);
                        if(name==null)
                        {
                              name = "color"+number+'e';//$NON-NLS-1$
                              DviPsColors.addUserColour(shadowColor, name); 
                        }
                        add += ",shadowcolor=" + name; //$NON-NLS-1$
                  }
            }
            
            String arrowHead1Style = arrowHead1.getArrowStyle();
            String arrowHead2Style = arrowHead2.getArrowStyle();
            
            if(!isOpen())
                  arrowHead2Style = PSTricksConstants.NONEARROW_STYLE;
            
            if(hasArrow1Style || hasArrow2Style)
            {
                  if(arrowHead2Style.equals(PSTricksConstants.DLARROW_STYLE))
                        arrowHead2Style = PSTricksConstants.DRARROW_STYLE;
                  else if(arrowHead2Style.equals(PSTricksConstants.DRARROW_STYLE))
                        arrowHead2Style = PSTricksConstants.DLARROW_STYLE;
                  else if(arrowHead2Style.equals(PSTricksConstants.RARROW_STYLE))
                        arrowHead2Style = PSTricksConstants.LARROW_STYLE;
                  else if(arrowHead2Style.equals(PSTricksConstants.LARROW_STYLE))
                        arrowHead2Style = PSTricksConstants.RARROW_STYLE;
                  else if(arrowHead2Style.equals(PSTricksConstants.DLARROW_STYLE))
                        arrowHead2Style = PSTricksConstants.DRARROW_STYLE;
                  else if(arrowHead2Style.equals(PSTricksConstants.LRBRACKET_STYLE))
                        arrowHead2Style = PSTricksConstants.RRBRACKET_STYLE;
                  else if(arrowHead2Style.equals(PSTricksConstants.RRBRACKET_STYLE))
                        arrowHead2Style = PSTricksConstants.LRBRACKET_STYLE;
                  else if(arrowHead2Style.equals(PSTricksConstants.RSBRACKET_STYLE))
                        arrowHead2Style = PSTricksConstants.LSBRACKET_STYLE;
                  else if(arrowHead2Style.equals(PSTricksConstants.LSBRACKET_STYLE))
                        arrowHead2Style = PSTricksConstants.RSBRACKET_STYLE;
                  
                  String paramsR = ","+ arrowHead1.getParametersCode(); //$NON-NLS-1$
                  String paramsL = ","+ arrowHead2.getParametersCode(); //$NON-NLS-1$
                  if(paramsR.equals(",")) paramsR = ""; //$NON-NLS-1$ //$NON-NLS-2$
                  if(paramsL.equals(",")) paramsL = ""; //$NON-NLS-1$ //$NON-NLS-2$
                  
                  if(hasArrow1Style)
                  {
                        arrowsCode="{"+arrowHead1Style+'-'; //$NON-NLS-1$
                        
                        if(hasArrow2Style)
                              arrowsCode+=arrowHead2Style;
                        arrowsCode+='}';
                        
                        if(!arrowHead1.isOfTheSameTypeAs(arrowHead2))
                        {
                              if((arrowHead2Style.equals(PSTricksConstants.LRBRACKET_STYLE) ||
                                    arrowHead2Style.equals(PSTricksConstants.RRBRACKET_STYLE)  ||
                                    arrowHead2Style.equals(PSTricksConstants.RSBRACKET_STYLE)  ||
                                    arrowHead2Style.equals(PSTricksConstants.RSBRACKET_STYLE))  &&
                                    (arrowHead1Style.equals(PSTricksConstants.BAREND_STYLE) ||
                                    arrowHead1Style.equals(PSTricksConstants.BARIN_STYLE) ||
                                    arrowHead1Style.equals(PSTricksConstants.LRBRACKET_STYLE) ||
                                    arrowHead1Style.equals(PSTricksConstants.RRBRACKET_STYLE)  ||
                                    arrowHead1Style.equals(PSTricksConstants.RSBRACKET_STYLE)  ||
                                    arrowHead1Style.equals(PSTricksConstants.RSBRACKET_STYLE)))
                                    arrowParams = paramsR;
                              else
                                    arrowParams = paramsL + paramsR;
                        }else arrowParams = paramsR;
                  }
                  else 
                        if(hasArrow2Style)
                        {
                              arrowParams = paramsL;
                              arrowsCode = "{-"+arrowHead2Style+'}'; //$NON-NLS-1$
                        }
            }
            
            String str = getPSTricksCodeFilling(ppc);
            if(str.length()>0) add=add+','+str;
            
            if(showPoints)
            {
                  showPointsCode=",showpoints=true"; //$NON-NLS-1$
                  
                  if(!arrowHead1.isArrowShapeDot() && !arrowHead2.isArrowShapeDot())
                        showPointsCode += ',' + arrowHead1.getDotParameters();
            }
            
            if(lineStyle.equals(PSTricksConstants.LINE_DOTTED_STYLE))
                  add += ",linestyle="+lineStyle+",dotsep="+ //$NON-NLS-1$ //$NON-NLS-2$
                  (dotSep/ppc)+ "cm";     //$NON-NLS-1$
            else
            if(lineStyle.equals(PSTricksConstants.LINE_DASHED_STYLE))
                  add += ",linestyle="+lineStyle+",dash=" + //$NON-NLS-1$ //$NON-NLS-2$
                  (blackDashLength/ppc) + "cm "+ //$NON-NLS-1$
                  (whiteDashLength/ppc) + "cm";//$NON-NLS-1$

            if(hasDoubleBoundary)
            {
                  add+=",doubleline=true,doublesep="+(float)(doubleSep/ppc); //$NON-NLS-1$
                  
                  if(doubleColor!=PSTricksConstants.DEFAULT_DOUBLE_COLOR)
                  {
                        String name = DviPsColors.getColourName(doubleColor);
                        if(name==null)
                        {
                              name = "color"+number+'d';//$NON-NLS-1$
                              DviPsColors.addUserColour(doubleColor, name); 
                        }
                        add+= ",doublecolor="+name; //$NON-NLS-1$
                  }
            }           
            
            if(!isFilled && hasShadow() && isHatched())
            {
                  String name = DviPsColors.getColourName(interiorColor);
                  if(name==null)
                  {
                        name = "color"+number+'b';//$NON-NLS-1$
                        DviPsColors.addUserColour(interiorColor, name); 
                  }
                  add += ",fillcolor=" + name; //$NON-NLS-1$
            }
            
            coord = "(" + LaTeXDrawNumber.getCutNumber((float)((pts.firstElement().x-d.x)/ppc), threshold) +","+ //$NON-NLS-1$ //$NON-NLS-2$
                              LaTeXDrawNumber.getCutNumber((float)((d.y-pts.firstElement().y)/ppc), threshold)+")("+ //$NON-NLS-1$
                              LaTeXDrawNumber.getCutNumber((float)((ctrlPts.firstElement().x-d.x)/ppc), threshold)+","+ //$NON-NLS-1$
                              LaTeXDrawNumber.getCutNumber((float)((d.y-ctrlPts.firstElement().y)/ppc), threshold)+")("+ //$NON-NLS-1$
                              LaTeXDrawNumber.getCutNumber((float)((ctrlPts.elementAt(1).x-d.x)/ppc), threshold)+","+ //$NON-NLS-1$
                              LaTeXDrawNumber.getCutNumber((float)((d.y-ctrlPts.elementAt(1).y)/ppc), threshold)+")("+ //$NON-NLS-1$
                              LaTeXDrawNumber.getCutNumber((float)((pts.elementAt(1).x-d.x)/ppc), threshold)+","+ //$NON-NLS-1$
                              LaTeXDrawNumber.getCutNumber((float)((d.y-pts.elementAt(1).y)/ppc), threshold)+')';

            for(i=2; i<size; i++)
            {
                  ctrlPt1 = ctrlPts.elementAt(i);
                  ctrlPt2 = secondCtrlPts.elementAt(i-1);
                  pt = pts.elementAt(i-1);
                  
                  coord += "("+ //$NON-NLS-1$
                              LaTeXDrawNumber.getCutNumber((float)((ctrlPt2.x-d.x)/ppc), threshold)+","+ //$NON-NLS-1$
                              LaTeXDrawNumber.getCutNumber((float)((d.y-ctrlPt2.y)/ppc), threshold)+")("+ //$NON-NLS-1$
                              LaTeXDrawNumber.getCutNumber((float)((ctrlPt1.x-d.x)/ppc), threshold)+","+ //$NON-NLS-1$
                              LaTeXDrawNumber.getCutNumber((float)((d.y-ctrlPt1.y)/ppc), threshold)+")("; //$NON-NLS-1$
                  
                  pt = pts.elementAt(i);
                  coord += LaTeXDrawNumber.getCutNumber((float)((pt.x-d.x)/ppc), threshold)+","+ //$NON-NLS-1$
                              LaTeXDrawNumber.getCutNumber((float)((d.y-pt.y)/ppc), threshold)+')';
            }
            
            if(!isOpen())
                  if(closeType==CLOSE_TYPE_CURVE)
                  {
                        ctrlPt1 = secondCtrlPts.firstElement();
                        ctrlPt2 = secondCtrlPts.lastElement();
                        pt = pts.lastElement();
                        
                        coord += "(" + LaTeXDrawNumber.getCutNumber((float)((ctrlPt2.x-d.x)/ppc), threshold)+","+ //$NON-NLS-1$//$NON-NLS-2$
                                    LaTeXDrawNumber.getCutNumber((float)((d.y-ctrlPt2.y)/ppc), threshold)+")("+ //$NON-NLS-1$
                                    LaTeXDrawNumber.getCutNumber((float)((ctrlPt1.x-d.x)/ppc), threshold)+","+ //$NON-NLS-1$
                                  LaTeXDrawNumber.getCutNumber((float)((d.y-ctrlPt1.y)/ppc), threshold)+")("; //$NON-NLS-1$
            
                        pt = pts.firstElement();
                        coord += LaTeXDrawNumber.getCutNumber((float)((pt.x-d.x)/ppc), threshold)+","+ //$NON-NLS-1$
                                     LaTeXDrawNumber.getCutNumber((float)((d.y-pt.y)/ppc), threshold)+')';
                  }
                  else
                  {
                        LaTeXDrawPoint2D tmp = pts.lastElement();
                        pt = pts.firstElement();
                        
                        start = "\\psline[linewidth=" + (thickness/ppc)+add+"](" +//$NON-NLS-1$//$NON-NLS-2$
                                    LaTeXDrawNumber.getCutNumber((float)((tmp.x-d.x)/ppc), threshold)+","+ //$NON-NLS-1$
                                    LaTeXDrawNumber.getCutNumber((float)((d.y-tmp.y)/ppc), threshold)+")("+ //$NON-NLS-1$
                                    LaTeXDrawNumber.getCutNumber((float)((pt.x-d.x)/ppc), threshold)+","+ //$NON-NLS-1$
                                  LaTeXDrawNumber.getCutNumber((float)((d.y-pt.y)/ppc), threshold)+")\n"; //$NON-NLS-1$
                  }
            
            if(!isFilled && !interiorColor.equals(PSTricksConstants.DEFAULT_INTERIOR_COLOR))
            {
                  String name = DviPsColors.getColourName(interiorColor);
                  
                  if(name==null)
                  {
                        name = "color"+number+'b';//$NON-NLS-1$
                        DviPsColors.addUserColour(interiorColor, name);
                  }
                  add += ",fillcolor="+name; //$NON-NLS-1$
            }
            
            return start + "\\psbezier[linewidth=" + (thickness/ppc) + add + showPointsCode +  //$NON-NLS-1$
                        arrowParams + "]" + arrowsCode + coord; //$NON-NLS-1$
      }
      



      @Override
01240       public void shift(double shiftX, double shiftY)
      {
            if(shiftX==0 && shiftY==0) return ;
            
            int i, size = ctrlPts.size();
            LaTeXDrawPoint2D pt;
            
            for(i=0; i<size; i++)
            {
                  pt = pts.elementAt(i);
                  pt.x+=shiftX;
                  pt.y+=shiftY;
                  pt = ctrlPts.elementAt(i);
                  pt.x+=shiftX;
                  pt.y+=shiftY;
                  pt = secondCtrlPts.elementAt(i);
                  pt.x+=shiftX;
                  pt.y+=shiftY;
            }
            
            shape = getSimpleShape();
            updateBorders();
            updateGravityCenter();
            arrowHead1.getPosition().setLocation(getPoint(0));
            arrowHead2.getPosition().setLocation(getPoint(-1));
      }




      @Override
01271       public void updateBorders()
      {
            if(!pts.isEmpty())
            {
                  LaTeXDrawPoint2D pt = getPoint(0);
                  int i, size = pts.size();
                  double NWx, NWy, SEy, SEx;
                  NWx = SEx = pt.x;       
                  SEy = NWy = pt.y;
                  
                  for(i=0; i<size; i++)
                  {
                        pt = getPoint(i);
                        
                        if(pt.x<NWx) NWx = pt.x;
                        else if(pt.x>SEx) SEx = pt.x;
                        if(pt.y<NWy) NWy = pt.y;
                        else if(pt.y>SEy) SEy = pt.y;
                  }
                  
                  size = ctrlPts.size();
                  for(i=0; i<size; i++)
                  {                             
                        pt = ctrlPts.elementAt(i);
                        
                        if(pt.x<NWx) NWx = pt.x;
                        else if(pt.x>SEx) SEx = pt.x;
                        if(pt.y<NWy) NWy = pt.y;
                        else if(pt.y>SEy) SEy = pt.y;
                  }
                  
                  if(!open && size>0)
                  {
                        pt = secondCtrlPts.firstElement();
                        
                        if(pt.x<NWx) NWx = pt.x;
                        else if(pt.x>SEx) SEx = pt.x;
                        if(pt.y<NWy) NWy = pt.y;
                        else if(pt.y>SEy) SEy = pt.y;
                        
                        pt = secondCtrlPts.lastElement();
                        
                        if(pt.x<NWx) NWx = pt.x;
                        else if(pt.x>SEx) SEx = pt.x;
                        if(pt.y<NWy) NWy = pt.y;
                        else if(pt.y>SEy) SEy = pt.y;
                  }
                  
                  for(i=1; i<size-1; i++)
                  {
                        pt = secondCtrlPts.elementAt(i);
                        
                        if(pt.x<NWx) NWx = pt.x;
                        else if(pt.x>SEx) SEx = pt.x;
                        if(pt.y<NWy) NWy = pt.y;
                        else if(pt.y>SEy) SEy = pt.y;
                  }
                  
                  if(showPoints)
                  {
                        double width = (arrowHead1.getDotSizeDim() + arrowHead1.getDotSizeNum()*thickness)/2.;
                        NWx-=width;
                        NWy-=width;
                        SEx+=width;
                        SEy+=width;
                  }
                  
                  if(borders==null)
                        borders = new LaTeXDrawRectangle(new LaTeXDrawPoint2D(NWx, NWy),
                                                                        new LaTeXDrawPoint2D(SEx, SEy), false);
                  else
                  {
                        borders.setLastPoint(SEx, SEy);
                        borders.setFirstPoint(NWx, NWy);
                  }
            }
      }




      @Override
01353       public void updateBorders(LaTeXDrawPoint2D pt)
      {
            updateBorders();
      }




      @Override
      public void addRotationAngle(double theta)
      {
            int i, size = pts.size();
            LaTeXDrawPoint2D p, pRot;
            LaTeXDrawPoint2D cg = (LaTeXDrawPoint2D)gravityCenter.clone();
            theta%=(Math.PI*2);

            for(i=0; i<size; i++)
            {
                  p = getPoint(i);
                  pRot = rotatePoint(p, cg, theta);
                  p.setLocation(pRot.x, pRot.y);
                  
                  p = ctrlPts.elementAt(i);
                  pRot = rotatePoint(p, cg, theta);
                  p.setLocation(pRot.x, pRot.y);
                  
                  p = secondCtrlPts.elementAt(i);
                  pRot = rotatePoint(p, cg, theta);
                  p.setLocation(pRot.x, pRot.y);
            }
            
            arrowHead1.getPosition().setLocation(rotatePoint(arrowHead1.getPosition(), cg, theta));
            arrowHead2.getPosition().setLocation(rotatePoint(arrowHead2.getPosition(), cg, theta));
            
            rotationAngle+=theta;
            rotationAngle%=(Math.PI*2);
            
            updateShape();
            updateBorders();
            updateGravityCenter();
            
            if(gravityCenter.equals(cg, 0.0000001))
            {
                  shift(gravityCenter, cg);
                  gravityCenter.setLocation(cg);
            }
      }




      /**
       * @return Returns the showPoints.
       */
01407       public boolean isShowPoints()
      {
            return showPoints;
      }




      /**
       * @param showPoints The showPoints to set.
       */
01418       public synchronized void setShowPoints(boolean showPoints)
      {
            this.showPoints = showPoints;
            updateShape();
            updateBorders();
            updateGravityCenter();
      }

      
      
      /**
       * Allow to get the first control point at the identifier <code>id</code> in the vector <code>ctrlPts</code>.
       * @param id The identifier of the asked point (-1 = the last point).
       * @return The point asked.
       */
01433       public LaTeXDrawPoint2D getFirstControlPoint(int id)
      {
            if(ctrlPts==null) return null;
            
            if(id==-1) return ctrlPts.lastElement();
            if(id<0 || id>=ctrlPts.size())
                  throw new ArrayIndexOutOfBoundsException(id);
            
            return ctrlPts.elementAt(id);
      }
      
      
      
      /**
       * Allow to get the second control point at the identifier <code>id</code> in the vector <code>ctrlPts</code>.
       * @param id The identifier of the asked point (-1 = the last point).
       * @return The point asked.
       */
01451       public LaTeXDrawPoint2D getSecondControlPoint(int id)
      {
            if(secondCtrlPts==null) return null;
            
            if(id==-1) return secondCtrlPts.lastElement();
            if(id<0 || id>=secondCtrlPts.size())
                  throw new ArrayIndexOutOfBoundsException(id);
            
            return secondCtrlPts.elementAt(id);
      }
      
      
      
      @Override
01465       public void rescaleX(double formerX, double newX, double percent, LaTeXDrawRectangle bound)
      {
            if(percent==1.) return ;
            
            if(bound==null) 
                  throw new IllegalArgumentException();
            
            int i, size = getNbPoints();

            if(size>0)
            {
                  LaTeXDrawPoint2D NW = bound.getTheNWPoint(), SE = bound.getTheSEPoint(),farest,p;
      
                  if(formerX == SE.x)
                        farest = NW;
                  else
                        if(formerX == NW.x)
                              farest = SE;
                        else
                              throw new IllegalArgumentException();
                  
                  for(i=0; i<size; i++)
                  {// We rescale each point
                        p = getPoint(i);
                        if(p.x!=farest.x)
                              p.x = farest.x+(p.x-farest.x)*percent;
                        
                        p = getFirstControlPoint(i);
                        if(p.x!=farest.x)
                              p.x = farest.x+(p.x-farest.x)*percent;
                        
                        p = getSecondControlPoint(i);
                        if(p.x!=farest.x)
                              p.x = farest.x+(p.x-farest.x)*percent;
                  }
                  updateBorders();
                  arrowHead1.getPosition().setLocation(getPoint(0));
                  arrowHead2.getPosition().setLocation(getPoint(-1));
                  updateShape();
            }
      }
      
      
      
      
      
      

      @Override
01514       public void rescaleY(double formerY, double newY, double percent, LaTeXDrawRectangle bound)
      {
            if(percent==1.) return ;
            
            if(bound==null) 
                  throw new IllegalArgumentException();
            
            int i, size = getNbPoints();
            
            if(size>0)
            {
                  LaTeXDrawPoint2D NW = bound.getTheNWPoint(), SE = bound.getTheSEPoint(),farest,p;
      
                  if(formerY == SE.y)
                        farest = NW;
                  else
                        if(formerY == NW.y)
                              farest = SE;
                        else
                              throw new IllegalArgumentException();
                  
                  for(i=0; i<size; i++)
                  {// We rescale each point
                        p = getPoint(i);
                        if(p.y!=farest.y)
                              p.y = farest.y+(p.y-farest.y)*percent;
                        
                        p = getFirstControlPoint(i);
                        if(p.y!=farest.y)
                              p.y = farest.y+(p.y-farest.y)*percent;
                        
                        p = getSecondControlPoint(i);
                        if(p.y!=farest.y)
                              p.y = farest.y+(p.y-farest.y)*percent;
                  }
                  updateBorders();
                  arrowHead1.getPosition().setLocation(getPoint(0));
                  arrowHead2.getPosition().setLocation(getPoint(-1));
                  updateShape();
            }
      }
      
      
      
      
      
      @SuppressWarnings("unchecked")
      private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException
      {
            canHaveShadow     = true;
            canHaveArrow      = true;
            canBeFilled       = true;
            interiorColor     = (Color) ois.readObject();
            lineStyle         = (String) ois.readObject();
            rotationAngle     = ois.readDouble();
            thickness         = ois.readFloat();
            isFilled          = ois.readBoolean();
            isSelected        = ois.readBoolean();
            isOnRotation      = ois.readBoolean();
            linesColor        = (Color) ois.readObject();
            blackDashLength = ois.readFloat();
            dotSep                  = ois.readFloat();
            whiteDashLength = ois.readFloat();
            
            pts                     = (Vector<LaTeXDrawPoint2D>) ois.readObject();
            ctrlPts                       = (Vector<LaTeXDrawPoint2D>) ois.readObject();
            hasDoubleBoundary       = ois.readBoolean();
            doubleColor             = (Color)ois.readObject();
            doubleSep               = ois.readDouble();
            showPoints              = ois.readBoolean();
            
            if(LaTeXDrawFrame.getVersionOfFile().compareTo("1.7")>=0) //$NON-NLS-1$
            {
                  hasShadow   = ois.readBoolean();
                  shadowAngle = ois.readDouble();
                  shadowSize  = ois.readDouble();
                  shadowColor = (Color)ois.readObject();
            }
            else
            {
                  hasShadow   = DEFAULT_SHADOW_HAS;
                  shadowAngle = DEFAULT_SHADOW_ANGLE;
                  shadowSize  = DEFAULT_SHADOW_SIZE;
                  shadowColor = DEFAULT_SHADOW_COLOR;
            }
            
            if(LaTeXDrawFrame.getVersionOfFile().compareTo("1.8")>=0) //$NON-NLS-1$
            {
                  hatchingAngle = ois.readDouble();
                  hatchingColor = (Color)ois.readObject();
                  hatchingStyle = (String)ois.readObject();
                  hatchingWidth = ois.readFloat();
                  gradientEndColor = (Color)ois.readObject();
                  gradientStartColor = (Color)ois.readObject();
                  gradientAngle = ois.readDouble();
                  gradientMidPoint = ois.readDouble();
                  hatchingSep = ois.readDouble();
                  arrowHead1 = (ArrowHead)ois.readObject();
                  arrowHead2 = (ArrowHead)ois.readObject();
            }
            else
            {
                  hatchingSep = DEFAULT_HATCH_SEP;
                  hatchingAngle = DEFAULT_HATCH_ANGLE;
                  hatchingColor = DEFAULT_HATCH_COL;
                  hatchingStyle = DEFAULT_HATCH_STYLE;
                  hatchingWidth = DEFAULT_HATCH_WIDTH;
                  gradientEndColor = PSTricksConstants.DEFAULT_GRADIENT_END_COLOR;
                  gradientStartColor = PSTricksConstants.DEFAULT_GRADIENT_START_COLOR;
                  gradientAngle = DEFAULT_GRADIENT_ANGLE;
                  gradientMidPoint = DEFAULT_GRADIENT_MID_POINT;
                  LaTeXDrawPoint2D pt1 = new LaTeXDrawPoint2D(getPoint(0));
                  LaTeXDrawPoint2D pt2 = new LaTeXDrawPoint2D(getPoint(-1));
                  arrowHead1 = new ArrowHead(pt1, new Line(pt1, getFirstControlPoint(0), false), this);
                  arrowHead2 = new ArrowHead(pt2, new Line(pt2, getFirstControlPoint(-1), false), this);
            }
            
            if(LaTeXDrawFrame.getVersionOfFile().compareTo("1.9")>=0) //$NON-NLS-1$
            {
                  closeType         = ois.readInt();
                  open              = ois.readBoolean();
                  secondCtrlPts     = (Vector<LaTeXDrawPoint2D>) ois.readObject();
                  equilibrateGap    = ois.readInt();
            }
            else
            {
                  int i, size = pts.size();
                  
                  closeType         = DEFAULT_CLOSE_TYPE;
                  open              = true;
                  secondCtrlPts     = new Vector<LaTeXDrawPoint2D>();
                  equilibrateGap    = DEFAULT_EQUILIBRATE_GAP;
                  
                  for(i=0; i<size; i++)
                        secondCtrlPts.add(ctrlPts.elementAt(i).centralSymmetry(pts.elementAt(i)));
            }
            
            delimiters = new Vector<Delimitor>();
            for(int i=0, size = pts.size();i<size; i++)
            {
                  addCtrlLine(pts.elementAt(i), ctrlPts.elementAt(i), secondCtrlPts.elementAt(i));
                  delimiters.add(new Delimitor(pts.elementAt(i)));
            }
            
            setThickness(thickness);
            updateSecondControlPoints();
            updateShape();
      }
      
      
      
      
      @Override
01667       public Shape[] getDbleBoundariesMiddle(Shape classicBord)
      {
            return null;
      }
      
      
      
      
      @Override
01676       public synchronized void setThickness(float val) 
      {
            super.setThickness(val);
            
            if(!Double.isInfinite(val) && !Double.isNaN(val) && val>0 && delimiters!=null && !delimiters.isEmpty() && ctrlLines!=null)
            {
                  double dim = delimiters.elementAt(0).getDim();
      
                  for(Line l : ctrlLines)
                        for(Delimitor d : l.delimiters)
                              d.setDim(dim);
                  
                  for(Line l : secondCtrlLines)
                        for(Delimitor d : l.delimiters)
                              d.setDim(dim);
                  
                  updateBorders();
                  shape = getSimpleShape();
            }
      }


      
      @Override
01700       protected GeneralPath getBorders(double gap, boolean into)
      {
            return getSimpleShape();
      }
      
      
      
      @Override
01708       public Shape createShadowShape()
      {
            if(!hasShadow) return shape;
            
            double dx, dy;
            LaTeXDrawPoint2D cg = getGravityCenter();
            LaTeXDrawPoint2D shadowCg = (LaTeXDrawPoint2D)cg.clone();
            shadowCg.setLocation(cg.x+shadowSize, cg.y);
            shadowCg = Figure.rotatePoint(shadowCg, cg, shadowAngle);
            dx = shadowCg.x-cg.x;
            dy = cg.y-shadowCg.y;
            Shape outline = null;
            
            if(hasDoubleBoundary)
            {
                  Stroke wideline = new BasicStroke((float)(doubleSep+thickness*2.), BasicStroke.CAP_BUTT, 
                                                            BasicStroke.JOIN_MITER);
                  outline = wideline.createStrokedShape(shape);
            }
            else outline = shape;
      
            AffineTransform at = new AffineTransform();
            at.translate(dx, dy);
            return at.createTransformedShape(outline);
      }

      

01736       public String getArrow1Style()
      {
            return arrowHead1.getArrowStyle();
      }

      

01743       public String getArrow2Style()
      {
            return arrowHead2.getArrowStyle();
      }

      
      

01751       public ArrowHead getArrowHead1()
      {
            return arrowHead1;
      }

      
      

01759       public ArrowHead getArrowHead2()
      {
            return arrowHead2;
      }


      
01766       public void setArrow1Style(String style)
      {
            arrowHead1.setArrowStyle(style);    
            updateShape();
            updateBorders();
      }

      

01775       public void setArrow2Style(String style)
      {
            arrowHead2.setArrowStyle(style);    
            updateShape();
            updateBorders();
      }




      @Override
01786       public synchronized void setFirstPoint(double x, double y)
      {
            super.setFirstPoint(x, y);
            updateBorders();
            arrowHead1.getPosition().setLocation(x, y);
      }




      @Override
01797       public void mirrorHorizontal(LaTeXDrawPoint2D origin)
      {
            for(LaTeXDrawPoint2D pt : ctrlPts)
                  pt.setLocation(pt.horizontalSymmetry(origin));
            
            arrowHead1.getPosition().setLocation(arrowHead1.getPosition().horizontalSymmetry(origin));
            arrowHead2.getPosition().setLocation(arrowHead2.getPosition().horizontalSymmetry(origin));
            
            super.mirrorHorizontal(origin);
            
            updateSecondControlPoints();
            updateShape();
            updateBorders();
      }




      @Override
01816       public void mirrorVertical(LaTeXDrawPoint2D origin)
      {
            for(LaTeXDrawPoint2D pt : ctrlPts)
                  pt.setLocation(pt.verticalSymmetry(origin));
            
            arrowHead1.getPosition().setLocation(arrowHead1.getPosition().verticalSymmetry(origin));
            arrowHead2.getPosition().setLocation(arrowHead2.getPosition().verticalSymmetry(origin));
            
            super.mirrorVertical(origin);
            
            updateSecondControlPoints();
            updateShape();
            updateBorders();
      }




      @Override
01835       public void updateToGrid(MagneticGrid grid)
      {
            super.updateToGrid(grid);
            
            for(LaTeXDrawPoint2D pt : ctrlPts)
                  pt.setLocation(grid.getTransformedPointToGrid(pt, false));
            
            updateBorders();
            updateShape();
      }


      
      /**
       * @return The borders of the Bézier curve but without the control points, just the curve.
       */
01851       public Rectangle2D getBezierBorders()
      {
            if(getNbPoints()<2 || ctrlPts==null || ctrlPts.size()<2)
                  return new Rectangle2D.Double();
            
            Vector<LaTeXDrawPoint2D> points = new Vector<LaTeXDrawPoint2D>();
            points.add(pts.elementAt(0));
            points.add(ctrlPts.elementAt(0));
            points.add(ctrlPts.elementAt(1));
            points.add(pts.elementAt(1));
            double[] minMax = getBezierCurveMinMax(points, 3);
            
            return new Rectangle2D.Double(minMax[0], minMax[1], minMax[2]-minMax[0], minMax[3]-minMax[1]);
      }

      
      
      /**
       * Define the min and the max coordinates of the borders of the Bézier curve.
       * @param points The initial control points.
       * @param level The level of resolution.
       * @return The maximum and the minimum coordinates of the Bézier curve; 
       * <code>[minX, minY, maxX, maxY]</code> 
       */
01875       protected double[] getBezierCurveMinMax(Vector<LaTeXDrawPoint2D> points, int level)
      {
            if(level<=0)
            {
                  double x1 = points.elementAt(0).x + 0.5;
                  double y1 = points.elementAt(0).y + 0.5;
                  double x2 = points.elementAt(3).x + 0.5;
                  double y2 = points.elementAt(3).y + 0.5;
                  
                  return new double[]{Math.min(x1, x2), Math.min(y1, y2), Math.max(x1, x2), Math.max(y1, y2)};
            }
            
            Vector<LaTeXDrawPoint2D> left       = new Vector<LaTeXDrawPoint2D>();
            Vector<LaTeXDrawPoint2D> right      = new Vector<LaTeXDrawPoint2D>();    
            
            LaTeXDrawPoint2D l1 = new LaTeXDrawPoint2D(), l2 = new LaTeXDrawPoint2D();
            LaTeXDrawPoint2D l3 = new LaTeXDrawPoint2D(), l4 = new LaTeXDrawPoint2D();
            LaTeXDrawPoint2D r1 = new LaTeXDrawPoint2D(), r2 = new LaTeXDrawPoint2D();
            LaTeXDrawPoint2D r3 = new LaTeXDrawPoint2D(), r4 = new LaTeXDrawPoint2D();
            LaTeXDrawPoint2D p0 = points.elementAt(0);
            LaTeXDrawPoint2D p1 = points.elementAt(1);
            LaTeXDrawPoint2D p2 = points.elementAt(2);
            LaTeXDrawPoint2D p3 = points.elementAt(3);
            
            l1.x = p0.x;
            l1.y = p0.y;
            l2.x = (p0.x + p1.x) / 2;
            l2.y = (p0.y + p1.y) / 2;
            l3.x = (p0.x + 2*p1.x + p2.x) / 4;
            l3.y = (p0.y + 2*p1.y + p2.y) / 4;
            l4.x = (p0.x + 3*p1.x + 3*p2.x + p3.x) / 8;
            l4.y = (p0.y + 3*p1.y + 3*p2.y + p3.y) / 8;
            r1.x = p3.x;
            r1.y = p3.y;
            r2.x = (p1.x + 2*p2.x + p3.x) / 4;
            r2.y = (p1.y + 2*p2.y + p3.y) / 4;
            r3.x = (p2.x + p3.x) / 2;
            r3.y = (p2.y + p3.y) / 2;
            r4.x = p3.x;
            r4.y = p3.y;
        
            left.add(l1);
            left.add(l2);
            left.add(l3);
            left.add(l4);
            right.add(r1);
            right.add(r2);
            right.add(r3);
            right.add(r4);
            
        double mmLeft[]       = getBezierCurveMinMax(left, level-1);
        double mmRight[]      = getBezierCurveMinMax(right, level-1);
            
            return new double[] {Math.min(mmLeft[0], mmRight[0]), Math.min(mmLeft[1], mmRight[1]),
                                           Math.max(mmLeft[2], mmRight[2]), Math.max(mmLeft[3], mmRight[3])};
      }

      
      
      /**
       * Create a list of choice in order to select the type of closing of the curve.
       * @return The created list.
       * @since 1.9
       */
01939       public static LaTeXDrawComboBox createTypeChoice()
      {
            LaTeXDrawComboBox typeChoice = new LaTeXDrawComboBox();
            typeChoice.setRenderer(new LabelListCellRenderer());
            typeChoice.setName(LABEL_CLOSE_CHOICE);
            typeChoice.setActionCommand(LABEL_CLOSE_CHOICE);
            
            JLabel l = new JLabel(String.valueOf(CLOSE_TYPE_CURVE));
            l.setIcon(LaTeXDrawResources.closeCurveIcon);
            typeChoice.addItem(l);
            l = new JLabel(String.valueOf(CLOSE_TYPE_LINE));
            l.setIcon(LaTeXDrawResources.closeLineIcon);
            typeChoice.addItem(l);
            
            return typeChoice;
      }



      /**
       * @return the open.
       * @since 1.9
       */
01962       public synchronized boolean isOpen()
      {
            return open;
      }



      /**
       * @param open the open to set.<br>When the curve is closed, it cannot have double boundaries yet.
       * @since 1.9
       */
01973       public synchronized void setOpen(boolean open)
      {
            this.open = open;
            updateShape();
      }



      /**
       * @return the closeType.
       * @since 1.9
       */
01985       public synchronized int getCloseType()
      {
            return closeType;
      }



      /**
       * @param closeType the closeType to set.
       * @since 1.9
       * @exception IllegalArgumentException If the type is not valid.
       */
01997       public synchronized void setCloseType(int closeType)
      {
            if(closeType==CLOSE_TYPE_CURVE || closeType==CLOSE_TYPE_LINE)
            {
                  this.closeType = closeType;
                  updateShape();
            }
            else
                  throw new IllegalArgumentException();
      }



      @Override
02011       public int getSelectedDelimitorOrientation()
      {
            int del = super.getSelectedDelimitorOrientation();
            
            if(del!=DELIMITOR_ORIENTATION_NONE)
                  return del;
            
            boolean again = true;
            int i, size = pts.size();
            
            if(size<2)
                  return DELIMITOR_ORIENTATION_NONE;
            
            again = ctrlLines.firstElement().delimiters.lastElement()!=dSelected &&
                        ctrlLines.lastElement().delimiters.lastElement()!=dSelected;
            
            if(!open)
                  again &= secondCtrlLines.firstElement().delimiters.lastElement()!=dSelected &&
                               secondCtrlLines.lastElement().delimiters.lastElement()!=dSelected;
            
            for(i=1; i<size-1 && again; i++)
                  again = ctrlLines.elementAt(i).delimiters.lastElement()!=dSelected &&
                              secondCtrlLines.elementAt(i).delimiters.lastElement()!=dSelected;
            
            if(!again)
                  return DELIMITOR_ORIENTATION_NONE;
            
            if(borders.dSelected!=null)
                  return borders.getSelectedDelimitorOrientation();
            
            return DELIMITOR_ORIENTATION_NONE;
      }
      
      
      
      /**
       * Set the X-coordinate of one of the first control point.
       * @param x The new X-coordinate.
       * @param id The position of the point to set.
       * @since 1.9
       */
02052       public void setXCoordFirstCtrl(double x, int id)
      {
            if(id<0 || id>=getNbPoints())
                  throw new IllegalArgumentException();
            
            ctrlPts.elementAt(id).x = x;
            secondCtrlPts.elementAt(id).setLocation(ctrlPts.elementAt(id).centralSymmetry(pts.elementAt(id)));
            updateBorders();
            updateShape();
      }
      
      
      /**
       * Set the Y-coordinate of one of the first control point.
       * @param y The new Y-coordinate.
       * @param id The position of the point to set.
       * @since 1.9
       */
02070       public void setYCoordFirstCtrl(double y, int id)
      {
            if(id<0 || id>=getNbPoints())
                  throw new IllegalArgumentException();
            
            ctrlPts.elementAt(id).y = y;
            secondCtrlPts.elementAt(id).setLocation(ctrlPts.elementAt(id).centralSymmetry(pts.elementAt(id)));
            updateBorders();
            updateShape();
      }
      
      
      
      /**
       * Set the X-coordinate of one of the second control point.
       * @param x The new X-coordinate.
       * @param id The position of the point to set.
       * @since 1.9
       */
02089       public void setXCoordSecondCtrl(double x, int id)
      {
            if(id<0 || id>=getNbPoints())
                  throw new IllegalArgumentException();
            
            LaTeXDrawPoint2D pt = secondCtrlPts.elementAt(id);
            
            pt.x = x;
            ctrlPts.elementAt(id).setLocation(pt.centralSymmetry(pts.elementAt(id)));
            updateBorders();
            updateShape();
      }
      
      
      
      /**
       * Set the Y-coordinate of one of the second control point.
       * @param y The new Y-coordinate.
       * @param id The position of the point to set.
       * @since 1.9
       */
02110       public void setYCoordSecondCtrl(double y, int id)
      {
            if(id<0 || id>=getNbPoints())
                  throw new IllegalArgumentException();
            
            LaTeXDrawPoint2D pt = secondCtrlPts.elementAt(id);
            
            pt.y = y;
            ctrlPts.elementAt(id).setLocation(pt.centralSymmetry(pts.elementAt(id)));
            updateBorders();
            updateShape();
      }




      /**
       * Balance all the control points in order the create a round curve.
       * @since 1.9
       */
02130       public void equilibrate()
      {
            int size = pts.size();
            
            if(size>2)//Works only with more than 2 points.
            {
                  Vector<Line> lines = new Vector<Line>();
                  int i;
                  
                  for(i=0; i<size-1; i++)// Creates the lines of the polygon.
                        lines.add(new Line(pts.elementAt(i), pts.elementAt(i+1), false));
                  lines.add(new Line(pts.lastElement(), pts.firstElement(), false));
                  
                  try
                  {
                        size = lines.size();
                        Line l1, l2;
                        
                        /*
                         * It works by creating the angle bisectors of each points. It creates the perpendicular
                         * line of the angle bisector and shift it to the current point. Then you have a line
                         * allowing to get the two control points.
                         */
                        for(i=1; i<size; i++)
                        {
                              l1 = lines.elementAt(i-1);
                              l2 = lines.elementAt(i);
                              // To create the angle bisector, we must have one point one each of the two lines
                              // at equal distance.
                              LaTeXDrawPoint2D[] pts1 = l1.findPoints(l1.getPt2(), equilibrateGap);
                              LaTeXDrawPoint2D[] pts2 = l2.findPoints(l2.getPt1(), equilibrateGap);
                              LaTeXDrawPoint2D pt1, pt2;
                        
                              if(pts1==null || pts2==null)
                                    continue;
                              
                              pt1 = pts1.length==1 ? pts1[0] : pts1[0].distance(l1.getPt1())<
                                                                               pts1[1].distance(l1.getPt1()) ? pts1[0] : pts1[1];
                              
                              pt2 = pts2.length==1 ? pts2[0] : pts2[0].distance(l2.getPt2())<
                                                                               pts2[1].distance(l2.getPt2()) ? pts2[0] : pts2[1];
            
                              // This line is perpendicular to the angle bisector (and consequently
                              // parallel to the wanted control points), so it is useless to create it.
                              Line l = new Line(pt1, pt2, false);
                              
                              if(Double.isNaN(l.getA()))
                                    return ;
                        
                              // We translate the line to the current point.
                              double b = l2.getPt1().y - l.getA()*l2.getPt1().x;
                              Line l3  = new Line(b, l2.getPt1(), false);
                              LaTeXDrawPoint2D[] ctrlP = l3.findPoints(l3.getPt1(), equilibrateGap);
                        
                              if(ctrlP==null)
                                    continue;

                              if(ctrlP.length==1)
                                    continue;

                              // We just have to get the two control points.
                              LaTeXDrawPoint2D oldCtrl1 = ctrlPts.elementAt(i);
                              
                              if(oldCtrl1.distance(ctrlP[0])<oldCtrl1.distance(ctrlP[1]))
                              {
                                    ctrlPts.elementAt(i).setLocation(ctrlP[0]);
                                    secondCtrlPts.elementAt(i).setLocation(ctrlP[1]);
                              }
                              else
                              {
                                    ctrlPts.elementAt(i).setLocation(ctrlP[1]);
                                    secondCtrlPts.elementAt(i).setLocation(ctrlP[0]);
                              }
                        }//for
                        
                        if(!open)
                        {
                              // We repeat the same process for the first point with the first and the last line.
                              l1 = lines.lastElement();
                              l2 = lines.firstElement();
                              
                              //We move the control points of the first point.
                              LaTeXDrawPoint2D[] pts1 = l1.findPoints(l1.getPt2(), equilibrateGap);
                              LaTeXDrawPoint2D[] pts2 = l2.findPoints(l2.getPt1(), equilibrateGap);
                              LaTeXDrawPoint2D pt1, pt2;
                              
                              if(pts1!=null && pts2!=null)
                              {
                                    pt1 = pts1.length==1 ? pts1[0] : pts1[0].distance(l1.getPt1())<
                                                                              pts1[1].distance(l1.getPt1()) ? pts1[0] : pts1[1];
      
                                    pt2 = pts2.length==1 ? pts2[0] : pts2[0].distance(l2.getPt2())<
                                                                               pts2[1].distance(l2.getPt2()) ? pts2[0] : pts2[1];
                                                
                                    Line l = new Line(pt1, pt2, false);
                                    
                                    if(Double.isNaN(l.getA()))
                                          return ;
                                    
                                    double b = l2.getPt1().y - l.getA()*l2.getPt1().x;
                                    Line l3  = new Line(b, lines.firstElement().getPt1(), false);
                                    LaTeXDrawPoint2D[] ctrlP = l3.findPoints(l3.getPt1(), equilibrateGap);
                                    
                                    if(ctrlP!=null && ctrlP.length>1)
                                    {
                                          LaTeXDrawPoint2D oldCtrl1 = ctrlPts.firstElement();
                                          
                                          if(oldCtrl1.distance(ctrlP[0])<oldCtrl1.distance(ctrlP[1]))
                                          {
                                                ctrlPts.firstElement().setLocation(ctrlP[0]);
                                                secondCtrlPts.firstElement().setLocation(ctrlP[1]);
                                          }
                                          else
                                          {
                                                ctrlPts.firstElement().setLocation(ctrlP[1]);
                                                secondCtrlPts.firstElement().setLocation(ctrlP[0]);
                                          }
                                    }
                              }
                        }//if(!open)
                        
                        updateShape();
                        
                        // The position of the resulting control points can be inverted; so we have to invert
                        // the inverted control points (if there are inverted, the curve has a loop).
                        BasicStroke wideline;
                        
                        if(hasDoubleBoundary && open)
                              wideline = new BasicStroke((float)(doubleSep/2.+thickness*2));
                        else
                              wideline = new BasicStroke(thickness);
                        
                        Shape outline = wideline.createStrokedShape(shape);
                        LaTeXDrawPoint2D pt1, pt2;
                        
                        for(i=1; i<pts.size(); i++)
                        {
                              pt1 = ctrlPts.elementAt(i);
                              pt2 = secondCtrlPts.elementAt(i);
                              
                              // A loop can occurred only when the two control points are outside the shape.
                              if(!outline.contains(pt1) && !outline.contains(pt2))
                                    // The first control point must be closer than the second control point
                                    // to the previous point. Else we invert them.
                                    if(pt1.distance(pts.elementAt(i-1)) > pt2.distance(pts.elementAt(i-1)))
                                    {
                                          LaTeXDrawPoint2D tmp = new LaTeXDrawPoint2D(pt1);
                                          pt1.setLocation(pt2);
                                          pt2.setLocation(tmp);
                                    }
                        }
                        
                        if(!open)
                        {// We treat the first point (if the curve is closed).
                              pt1 = ctrlPts.firstElement();
                              pt2 = secondCtrlPts.firstElement();
                        
                              // A loop can occurred only when the two control points are outside the shape.
                              if(!outline.contains(pt1) && !outline.contains(pt2))
                                    // The first control point must be closer than the second control point
                                    // to the previous point. Else we invert them.
                                    if(pt1.distance(pts.elementAt(1)) > pt2.distance(pts.elementAt(1)))
                                    {
                                          LaTeXDrawPoint2D tmp = new LaTeXDrawPoint2D(pt1);
                                          pt1.setLocation(pt2);
                                          pt2.setLocation(tmp);
                                    }
                        }
                        
                        updateShape();
                        
                  }catch(Exception e)
                  {
                        e.printStackTrace();
                  }
            }
      }




      /**
       * @return the equilibrateGap.
       * @since 1.9
       */
02315       public synchronized int getEquilibrateGap()
      {
            return equilibrateGap;
      }




      /**
       * @param equilibrateGap the equilibrateGap to set.
       * @exception IllegalArgumentException If the value is lesser than 1.
       * @since 1.9
       */
02328       public synchronized void setEquilibrateGap(int equilibrateGap)
      {
            if(equilibrateGap<1)
                  throw new IllegalArgumentException();
            
            this.equilibrateGap = equilibrateGap;
      }




      /**
       * Check if the two Bézier curves have, at least, one extremity in common; if it is the case,
       * the control points must be symmetric. Curves are not considered as joined if at the joining point
       * there is an arrow.
       * @param bc The second Bézier curve.
       * @return 1, if the two Bézier curves have, at least, one extremity in common and symmetric 
       * control points;<br>
       * 0, if the two Bézier curves don't have any extremity shared;<br>
       * 2, if they have an extremity shared but the control points are not symmetric.
       * @since 1.9
       */
02350       public int isJoined(BezierCurve bc)
      {
            boolean isStrictJoined  = false;
            boolean isJoined        = false;
            boolean hasB1NoArrow1 = arrowHead1.isWithoutStyle();
            boolean hasB1NoArrow2 = arrowHead2.isWithoutStyle();
            boolean hasB2NoArrow1 = bc.arrowHead1.isWithoutStyle();
            boolean hasB2NoArrow2 = bc.arrowHead2.isWithoutStyle();
            
            if(pts.firstElement().equals(bc.pts.firstElement(), 0.0001) && hasB1NoArrow1 && hasB2NoArrow1)
            {
                  isJoined = true;
                  
                  if(ctrlPts.firstElement().equals(bc.secondCtrlPts.firstElement(), 5))
                        isStrictJoined = true;
            }
            
            if(pts.firstElement().equals(bc.pts.lastElement(), 0.0001) && hasB1NoArrow1 && hasB2NoArrow2)
            {
                  isJoined = true;
                  
                  if(ctrlPts.firstElement().equals(bc.secondCtrlPts.lastElement(), 5))
                        isStrictJoined = true;
            }
            
            if(pts.lastElement().equals(bc.pts.firstElement(), 0.0001) && hasB1NoArrow2 && hasB2NoArrow1)
            {
                  isJoined = true;
                  
                  if(ctrlPts.lastElement().equals(bc.secondCtrlPts.firstElement(), 5))
                        isStrictJoined = true;
            }
            
            if(pts.lastElement().equals(bc.pts.lastElement(), 0.0001) && hasB1NoArrow2 && hasB2NoArrow2)
            {
                  isJoined = true;
                  
                  if(ctrlPts.lastElement().equals(bc.secondCtrlPts.lastElement(), 5))
                        isStrictJoined = true;
            }

            if(isStrictJoined && isJoined)
                  return 1;
            
            if(isJoined)
                  return 2;
            
            return 0;
      }




      /**
       * Join the second curve to the first (the second curve is not changed, points are added to the first);
       * if they are at all joined, two points are added to the given
       * curve. If they are joined at one point and if at this point the controls points are symmetric,
       * only one point is added; if the control points are not symmetric, a point is added to solve this
       * problem.
       * TODO For the moment only the case where the Bézier curve have a point in common and if at this
       * point the control points are symmetric is managed.
       * @param bc The Bézier curve to
       * @since 1.9
       */
02414       public void join(BezierCurve bc)
      {
            if(bc==null)
                  throw new IllegalArgumentException();
            
            switch(isJoined(bc))
            {
                  case 0:
                        break;
                        
                  case 1:
                        LaTeXDrawPoint2D p1a = pts.firstElement(), p1b = pts.lastElement();
                        LaTeXDrawPoint2D p2a = bc.pts.firstElement(), p2b = bc.pts.lastElement();
                        int i, size = bc.pts.size();
                        
                        if(p1b.equals(p2b, 0.0001) && ctrlPts.lastElement().equals(bc.secondCtrlPts.lastElement(), 5))
                        {
                        
                              for(i=size-2; i>=0; i--)
                              {
                                    addPoint((LaTeXDrawPoint2D)bc.pts.elementAt(i).clone());
                                    ctrlPts.lastElement().setLocation(bc.ctrlPts.elementAt(i));
                              }
                        
                              if(!bc.arrowHead2.isWithoutStyle() && arrowHead2.isWithoutStyle())
                                    arrowHead2.copyArrowParameters(bc.arrowHead1);
                              
                              if(!bc.arrowHead1.isWithoutStyle() && arrowHead1.isWithoutStyle())
                                    arrowHead1.copyArrowParameters(bc.arrowHead2);
                        }     
                        else
                        if(p1a.equals(p2a, 0.0001) && ctrlPts.firstElement().equals(bc.secondCtrlPts.firstElement(), 5))
                        {
                              ctrlPts.firstElement().setLocation(secondCtrlPts.firstElement());
                              
                              for(i=1; i<size; i++)
                              {
                                    addPointAt((LaTeXDrawPoint2D)bc.pts.elementAt(i).clone(), 0);
                                    ctrlPts.firstElement().setLocation(bc.secondCtrlPts.elementAt(i));
                              }
                              
                              ctrlPts.firstElement().setLocation(bc.ctrlPts.lastElement());
                              
                              if(!bc.arrowHead2.isWithoutStyle() && arrowHead1.isWithoutStyle())
                                    arrowHead1.copyArrowParameters(bc.arrowHead2);
                              
                              if(!bc.arrowHead1.isWithoutStyle() && arrowHead2.isWithoutStyle())
                                    arrowHead2.copyArrowParameters(bc.arrowHead1);
                        }
                        else
                        if(p1a.equals(p2b, 0.0001) && ctrlPts.firstElement().equals(bc.secondCtrlPts.lastElement(), 5))
                        {
                              ctrlPts.firstElement().setLocation(secondCtrlPts.firstElement());
                              
                              for(i=size-2; i>=0; i--)
                              {
                                    addPointAt((LaTeXDrawPoint2D)bc.pts.elementAt(i).clone(), 0);
                                    ctrlPts.firstElement().setLocation(bc.ctrlPts.elementAt(i));
                              }
                  
                              if(!bc.arrowHead2.isWithoutStyle() && arrowHead2.isWithoutStyle())
                                    arrowHead2.copyArrowParameters(bc.arrowHead2);
                              
                              if(!bc.arrowHead1.isWithoutStyle() && arrowHead1.isWithoutStyle())
                                    arrowHead1.copyArrowParameters(bc.arrowHead1);
                        }
                        else
                        if(p1b.equals(p2a, 0.0001) && ctrlPts.lastElement().equals(bc.secondCtrlPts.firstElement(), 5))
                        {
                        
                              for(i=1; i<size; i++)
                              {
                                    addPoint((LaTeXDrawPoint2D)bc.pts.elementAt(i).clone());
                                    ctrlPts.lastElement().setLocation(bc.ctrlPts.elementAt(i));
                              }
                        
                              if(!bc.arrowHead2.isWithoutStyle() && arrowHead2.isWithoutStyle())
                                    arrowHead2.copyArrowParameters(bc.arrowHead2);
                              
                              if(!bc.arrowHead1.isWithoutStyle() && arrowHead1.isWithoutStyle())
                                    arrowHead1.copyArrowParameters(bc.arrowHead1);
                        }
                        
                        updateSecondControlPoints();
                        updateShape();
                        updateBorders();
                        break;
                        
                  case 2:
                        break;
            }
      }
      
      
      
      /**
       * If the last and the first point are equals (their control points too), the last point
       * is replaced by a automatic closing (attribute <code>open</code> is set the false).
       * @since 1.9
       */
02514       public void replaceLastPointByClosing()
      {
            if(pts.firstElement().equals(pts.lastElement(), 1) &&
                  ctrlPts.firstElement().equals(secondCtrlPts.lastElement(), 5) && getNbPoints()>1)
            {
                  int last = pts.size()-1;
                  pts.remove(last);
                  ctrlPts.remove(last);
                  secondCtrlPts.remove(last);
                  secondCtrlLines.remove(last);
                  ctrlLines.remove(last);
                  delimiters.remove(last);
                  LaTeXDrawPoint2D pt = new LaTeXDrawPoint2D(pts.lastElement());
                  arrowHead2.setPosition(pt);
                  arrowHead2.setLine(new Line(pt, ctrlPts.lastElement(), false));
                  setOpen(false);
                  updateShape();
            }
      }
      
      
      @Override
      public int hashCode()
      {
            return super.hashCode()*5;
      }
      
      
      
      
      /**
       * @param line The line to check.
       * @return True if the given line closes the Bézier curve (and return false if the line is null or if
       * the curve is closed).
       * @since 1.9
       */
02550       public boolean isLineClosingCurve(Line line)
      {
            if(line==null || !isOpen())
                  return false;
            
            LaTeXDrawPoint2D pt1 = line.getPt1();
            LaTeXDrawPoint2D pt2 = line.getPt2();
            LaTeXDrawPoint2D pt1b = pts.firstElement();
            LaTeXDrawPoint2D pt2b = pts.lastElement();
            double gap = 0.0001;
            
            return (pt1.equals(pt1b, gap) && pt2.equals(pt2b, gap)) ||
                        (pt1.equals(pt2b, gap) && pt2.equals(pt1b, gap));
      }
      
      
      
      
      @Override
02569       public void setPoint(double x, double y, int id)
      {
            if(id<0 || id>=pts.size())
                  throw new IllegalArgumentException();
            
            LaTeXDrawPoint2D old = (LaTeXDrawPoint2D)pts.elementAt(id).clone();
            super.setPoint(x, y, id);
            double diffX = pts.elementAt(id).x - old.x;
            double diffY = pts.elementAt(id).y - old.y;
            
            ctrlPts.elementAt(id).x += diffX;
            ctrlPts.elementAt(id).y += diffY;
            secondCtrlPts.elementAt(id).x += diffX;
            secondCtrlPts.elementAt(id).y += diffY;
            
            if(id==0)
                  arrowHead1.getPosition().setLocation(x, y);
            else
                  if(id==pts.size()-1)
                        arrowHead2.getPosition().setLocation(x, y);
            
            updateShape();
            updateBorders();
            updateGravityCenter();
      }


      
      /**
       * @see #setPoint(double, double, int)
       * @param moveAll True: the control point move too.
       * @since 1.9.2
       */
02602       public void setPoint(double x, double y, int id, boolean moveAll)
      {
            if(moveAll)
                  setPoint(x, y, id);
            
            if(id<0 || id>=pts.size())
                  throw new IllegalArgumentException();
            
            super.setPoint(x, y, id);
            
            secondCtrlPts.elementAt(id).setLocation(ctrlPts.elementAt(id).centralSymmetry(pts.elementAt(id)));
            
            if(id==0)
                  arrowHead1.getPosition().setLocation(x, y);
            else
                  if(id==pts.size()-1)
                        arrowHead2.getPosition().setLocation(x, y);
            
            updateShape();
            updateBorders();
            updateGravityCenter();
      }
      


      
      /**
       * @param bc The given curve.
       * @return 1 if, the given curve closes the initial curve and if their control points coincide.
       * 0, if the given curve closes the initial curve but if one of the control points of the closure
       * does not coincide. -1 if the given curve does not close the initial curve.<br>
       * It does not take care of the arrows.
       * @since 1.9
       */
02636       public int isCurveClosingCurve(BezierCurve bc)
      {
            if(pts.firstElement().equals(bc.pts.firstElement(), 5) && 
                  pts.lastElement().equals(bc.pts.lastElement(), 5))
            {
                  if(ctrlPts.firstElement().equals(bc.secondCtrlPts.firstElement(), 5) &&
                        ctrlPts.lastElement().equals(bc.secondCtrlPts.lastElement(), 5))
                        return 1;
                  return 0;
            }
            
            if(pts.firstElement().equals(bc.pts.lastElement(), 5) &&
                  pts.lastElement().equals(bc.pts.firstElement(), 5))
            {
                  if(ctrlPts.firstElement().equals(bc.secondCtrlPts.lastElement(), 5) &&
                        ctrlPts.lastElement().equals(bc.secondCtrlPts.firstElement(), 5))
                        return 1;
                  return 0;
            }
            
            return -1;
      }
      
      
02660       public boolean hasTwoLeftArrows()
      {
            return true;
      }
      
      
      
      @Override
02668       public boolean intersected(Rectangle2D.Double r)
      {
            if(r==null)
                  return false;
            
            BasicStroke wideline = new BasicStroke(hasDoubleBoundary() ? (float)(thickness*2+doubleSep) : thickness);
        Shape outline = wideline.createStrokedShape(shape);
        
        boolean ok = outline.intersects(r);
        
        if(!ok && isOpen() && (isFilled() || isHatched() || hasGradient()))
        {
            Line2D.Double l = new Line2D.Double(pts.firstElement(), pts.lastElement());
            
            if(l.intersects(r))
                  ok = true;
        }
        
        return ok;
      }
      
      
      @Override
02691       public boolean shadowFillsShape()
      {
            return false;
      }
}

Generated by  Doxygen 1.6.0   Back to index