1
package latexDraw.figures;
3
import static java.lang.Math.PI;
4
import static java.lang.Math.atan;
5
import static java.lang.Math.toDegrees;
8
import java.awt.geom.GeneralPath;
9
import java.awt.geom.Line2D;
10
import java.awt.geom.Point2D;
11
import java.awt.geom.Rectangle2D;
12
import java.io.Serializable;
14
import javax.swing.JLabel;
16
import latexDraw.figures.properties.Arrowable;
17
import latexDraw.figures.properties.Drawable;
18
import latexDraw.lang.LaTeXDrawLang;
19
import latexDraw.psTricks.DviPsColors;
20
import latexDraw.psTricks.PSTricksConstants;
21
import latexDraw.ui.components.Delimitor;
22
import latexDraw.ui.components.LaTeXDrawComboBox;
23
import latexDraw.ui.components.LabelListCellRenderer;
24
import latexDraw.ui.components.MagneticGrid;
25
import latexDraw.util.LaTeXDrawException;
26
import latexDraw.util.LaTeXDrawPoint2D;
27
import latexDraw.util.LaTeXDrawResources;
30
* This class defines what it is, in general, a figure.<br>
32
* This file is part of LaTeXDraw<br>
33
* Copyright (c) 2005-2008 Arnaud BLOUIN<br>
35
* LaTeXDraw is free software; you can redistribute it and/or modify it under
36
* the terms of the GNU General Public License as published by the Free Software
37
* Foundation; either version 2 of the License, or (at your option) any later
40
* LaTeXDraw is distributed without any warranty; without even the implied
41
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
42
* General Public License for more details.<br>
45
* @author Arnaud BLOUIN<br>
48
public abstract class Figure implements Serializable, Cloneable, Drawable
50
private static final long serialVersionUID = 1L;
52
/** The number by default of pixels per cm. */
53
public static final int PPC = 50;
55
/** Corresponds to the thickness of the borders of the figure (in pixels). */
56
protected float thickness;
58
/** Corresponds to the selected delimiter (if there is a one selected) */
59
protected Delimitor dSelected;
61
/** Allows to know if the figure is selected */
62
protected boolean isSelected;
64
/** Allows to know if the figure can be filled by a colour */
65
protected boolean canBeFilled;
67
/** Allows to know if the figure is filled by a colour */
68
protected boolean isFilled;
70
/** Allows to know if the thickness of the figure can be changed */
71
protected boolean isThicknessable;
73
/** Allows to know if the borders of the figure are movable */
74
protected boolean isBordersMovable;
76
/** The colour of the borders */
77
protected Color linesColor;
79
/** The colour of the interior of the figure */
80
protected Color interiorColor;
82
/** The number of the figure. */
85
/** The meter of figures */
86
private static int meter = 0;
88
/** Allows to know if the figure is customisable or not */
89
protected boolean isCustomizable;
91
/** Allows to know if the bounds are double */
92
protected boolean hasDoubleBoundary;
94
/** Allows to know if the figure can have double boundary */
95
protected boolean isDoubleBoundaryable;
97
/** The colour of the double boundary */
98
protected Color doubleColor;
100
/** The position of the double boundary */
101
protected String bordersPosition;
103
/** Allows to know if the figure can be dotted or dashed */
104
protected boolean isDashableOrDotable;
106
/** The colour of the hatch */
107
protected Color hatchingColor;
109
/** The angle of the hatch (in rad). */
110
protected double hatchingAngle;
112
/** The width of the lines of the hatch (in pixels). */
113
protected float hatchingWidth;
115
/** Allows to know if the figure is resizable or not */
116
protected boolean isResizable;
118
/** The kind of hatch used by the figure */
119
protected String hatchingStyle;
121
/** True if the figure has a shadow. */
122
protected boolean hasShadow;
124
/** The size of the shadow (in pixels). */
125
protected double shadowSize;
127
/** The angle of the shadow (in rad). */
128
protected double shadowAngle;
130
/** The colour of the shadow. */
131
protected Color shadowColor;
133
/** Define if the figure can have a shadow. */
134
protected boolean canHaveShadow;
136
/** The angle of the gradient (in rad). */
137
protected double gradientAngle;
139
/** The position of the midpoint, as a fraction of the distance from
140
top to bottom. Should be between 0 and 1. */
141
protected double gradientMidPoint;
143
/** The first colour of the gradient. */
144
protected Color gradientStartColor;
146
/** The second colour of the gradient. */
147
protected Color gradientEndColor;
149
/** The position of the midpoint, as a fraction of the distance from
150
top to bottom. Should be between 0 and 1. */
151
public static final double DEFAULT_GRADIENT_MID_POINT = 1;
153
/** The angle of the gradient in radian. */
154
public static final double DEFAULT_GRADIENT_ANGLE = Math.toRadians(PSTricksConstants.DEFAULT_GRADIENT_ANGLE);
156
/** The value by default of hasShadow. */
157
public static final boolean DEFAULT_SHADOW_HAS = PSTricksConstants.DEFAULT_SHADOW;
159
/** The value by default of shadowSize (in pixels). */
160
public static final double DEFAULT_SHADOW_SIZE = PSTricksConstants.DEFAULT_SHADOW_SIZE*PPC;
162
/** The value by default of shadowAngle (in rad). */
163
public static final double DEFAULT_SHADOW_ANGLE = Math.toRadians(PSTricksConstants.DEFAULT_SHADOW_ANGLE);
165
/** The value by default of shadowAngle. */
166
public static final Color DEFAULT_SHADOW_COLOR = PSTricksConstants.DEFAULT_SHADOW_COLOR;
168
/** The position by default of the double boundary */
169
public static final String DEFAULT_BORDERS_POSITION = PSTricksConstants.BORDERS_INSIDE;
171
/** The colour of the double boundary of the figure by default */
172
public static final Color DEFAULT_DOUBLE_COLOR = PSTricksConstants.DEFAULT_DOUBLE_COLOR;
174
/** The value by default of the attribute hasDoubleBoudary */
175
public static final boolean DEFAULT_HAS_DOUBLE_BOUNDARY = false;
177
/** The angle of the lines of the hatch by default */
178
public static final double DEFAULT_HATCH_ANGLE = 0.;
180
/** The size of the separation between the hatching by default. */
181
public static final double DEFAULT_HATCH_SEP = PSTricksConstants.DEFAULT_HATCH_SEP*PPC;
183
/** A figure is customisable by default ? */
184
public static final boolean DEFAULT_IS_CUSTOMISABLE = true;
186
/** The borders of the figure are movable by default */
187
public static final boolean DEFAULT_IS_BORDERS_MOVABLE = true;
189
/** The colour by default of the borders of the figure */
190
public static final Color DEFAULT_BORDERS_COL = Color.BLACK;
192
/** The colour by default of the interior of the figure */
193
public static final Color DEFAULT_INTERIOR_COL = Color.WHITE;
195
/** The colour by default of the hatch of the figure */
196
public static final Color DEFAULT_HATCH_COL = Color.BLACK;
198
/** The value by default of the attribute isThicknessable */
199
public static final boolean DEFAULT_IS_THICKNESSABLE = true;
201
/** value of the thickness by default (in pixels). */
202
public static final float DEFAULT_THICKNESS = 2;
204
/** The style of the lines of the figure */
205
protected String lineStyle;
207
/** The style of lines by default */
208
public static final String DEFAULT_LINE_STYLE = PSTricksConstants.LINE_NONE_STYLE;
210
/** If a figure is filled by default */
211
public static final boolean DEFAULT_IS_FILLED = false;
213
/** The label of the ComboBox containing all kinds of hatches */
214
public static final String LABEL_HATCH_CHOICE = "Hatch choice"; //$NON-NLS-1$
216
/** The label of the field which allows to change the width of the hatch */
217
public static final String LABEL_HATCH_WIDTH = "Hatch width"; //$NON-NLS-1$
219
/** The label of the hatch used by default */
220
public static final String DEFAULT_HATCH_STYLE = PSTricksConstants.TOKEN_FILL_NONE;
222
/** The value by default of the width of the hatch (in pixels). */
223
public static final float DEFAULT_HATCH_WIDTH = DEFAULT_THICKNESS;
225
/** The value by default of the attribute isResizable */
226
public static final boolean DEFAULT_ISRESIZABLE = true;
228
/** The value by default of the attribute isHatched */
229
public static final boolean DEFAULT_IS_HATCHED = false;
231
/** The label of double boundary choice */
232
public static final String LABEL_BORDERS_POSITION_CHOICE = LaTeXDrawLang.getOthersString("Figure.boundPos"); //$NON-NLS-1$
234
/** The centre of the rotation */
235
protected LaTeXDrawPoint2D gravityCenter;
237
/** The angle of rotation (in rad) */
238
public double rotationAngle;
240
/** Allows to know if the figure is on rotation */
241
protected boolean isOnRotation;
243
/** The size of the separation between the double line in pixels */
244
protected double doubleSep;
246
/** The value by default of the attribute doubleLine */
247
public static final boolean DEFAULT_DOUBLELINE = false;
249
/** The value by default of the attribute doubleSep (in pixels). */
250
public static final double DEFAULT_DOUBLESEP = 6;
252
/** The angle of rotation by default */
253
public static final double DEFAULT_ROTATION_ANGLE = 0.;
255
public static final float DEFAULT_BLACK_DASH_LGTH = 8;
257
public static final float DEFAULT_WHITE_DASH_LGTH = 8;
259
/** The separator between dots by default (in pixels). */
260
public static final float DEFAULT_DOT_SEP = 8;
262
/** The length of the black dash of a line (in pixels). */
263
protected float blackDashLength;
265
/** The length of the white dash of a line (in pixels). */
266
protected float whiteDashLength;
268
/** The separation between two dots in a dotted line (in pixels). */
269
protected float dotSep;
271
/** The borders of the figure */
272
protected LaTeXDrawRectangle borders;
274
/** The shape of the figure */
275
protected transient Shape shape;
277
/** The size of the separation between the hatching (in pixels). */
278
protected double hatchingSep;
280
/** Define if the shape can have arrows. */
281
protected boolean canHaveArrow;
283
/** The token used for Horizontal hatch in LaTeXDraw 1.5.1.1, 1.5.1 and 1.5.<br>
284
* Useful to read file ldp of these versions of LaTeXDraw.*/
285
public static final String DECREPETED_FILL_HORIZ = "Horizontal hatch";//$NON-NLS-1$
287
/** The token used for Vertical hatch in LaTeXDraw 1.5.1.1, 1.5.1 and 1.5.<br>
288
* Useful to read file ldp of these versions of LaTeXDraw.*/
289
public static final String DECREPETED_FILL_VERT = "Vertical hatch";//$NON-NLS-1$
291
/** The token used for Cross hatch in LaTeXDraw 1.5.1.1, 1.5.1 and 1.5.<br>
292
* Useful to read file ldp of these versions of LaTeXDraw.*/
293
public static final String DECREPETED_FILL_CROSS = "Cross hatch";//$NON-NLS-1$
295
/** The token used for No hatch in LaTeXDraw 1.5.1.1, 1.5.1 and 1.5.<br>
296
* Useful to read file ldp of these versions of LaTeXDraw.*/
297
public static final String DECREPETED_FILL_NO = "No hatch";//$NON-NLS-1$
299
public static final short DELIMITOR_ORIENTATION_NONE = -1;
301
public static final short DELIMITOR_ORIENTATION_WEST = 0;
303
public static final short DELIMITOR_ORIENTATION_EAST = 2;
305
public static final short DELIMITOR_ORIENTATION_NORTH = 3;
307
public static final short DELIMITOR_ORIENTATION_SOUTH = 8;
309
public static final short DELIMITOR_ORIENTATION_NW = 4;
311
public static final short DELIMITOR_ORIENTATION_SW = 5;
313
public static final short DELIMITOR_ORIENTATION_NE = 6;
315
public static final short DELIMITOR_ORIENTATION_SE = 7;
317
public static final short DELIMITOR_ROTATION = 9;
323
* @param increaseMeter If the figure must increase the meter of figure {@literal number}.
325
protected Figure(boolean increaseMeter)
327
canHaveArrow = false;
328
hatchingSep = DEFAULT_HATCH_SEP;
329
isBordersMovable = DEFAULT_IS_BORDERS_MOVABLE;
330
bordersPosition = DEFAULT_BORDERS_POSITION;
331
doubleColor = DEFAULT_DOUBLE_COLOR;
332
isResizable = DEFAULT_ISRESIZABLE;
333
doubleSep = DEFAULT_DOUBLESEP;
334
isDashableOrDotable = true;
335
isDoubleBoundaryable = true;
336
isCustomizable = DEFAULT_IS_CUSTOMISABLE;
337
isOnRotation = false;
338
isThicknessable = DEFAULT_IS_THICKNESSABLE;
339
rotationAngle = DEFAULT_ROTATION_ANGLE;
341
interiorColor = DEFAULT_INTERIOR_COL;
342
linesColor = DEFAULT_BORDERS_COL;
343
hatchingColor = DEFAULT_BORDERS_COL;
344
hatchingStyle = DEFAULT_HATCH_STYLE;
345
isFilled = DEFAULT_IS_FILLED;
348
number = increaseMeter ? meter++ : -1;
349
blackDashLength = DEFAULT_BLACK_DASH_LGTH;
350
whiteDashLength = DEFAULT_WHITE_DASH_LGTH;
351
lineStyle = PSTricksConstants.LINE_NONE_STYLE;
352
dotSep = DEFAULT_DOT_SEP;
353
thickness = DEFAULT_THICKNESS;
354
hatchingWidth = DEFAULT_HATCH_WIDTH;
355
gravityCenter = new LaTeXDrawPoint2D();
357
shadowAngle = DEFAULT_SHADOW_ANGLE;
358
shadowColor = DEFAULT_SHADOW_COLOR;
359
shadowSize = DEFAULT_SHADOW_SIZE;
360
hasShadow = DEFAULT_SHADOW_HAS;
361
canHaveShadow = true;
362
gradientAngle = DEFAULT_GRADIENT_ANGLE;
363
gradientEndColor = PSTricksConstants.DEFAULT_GRADIENT_END_COLOR;
364
gradientStartColor = PSTricksConstants.DEFAULT_GRADIENT_START_COLOR;
365
gradientMidPoint = DEFAULT_GRADIENT_MID_POINT;
372
* Creates a figure from one another (but do not create the gravity centre, the border and the shape).
373
* @param f The figure to copy.
374
* @param sameNumber True is the new figure must have the same number as the other.
375
* @throws IllegalArgumentException If f is null.
377
protected Figure(Figure f, boolean sameNumber)
380
throw new IllegalArgumentException();
382
canBeFilled = f.canBeFilled;
383
canHaveShadow = f.canHaveShadow;
384
isBordersMovable= f.isBordersMovable;
385
isCustomizable = f.isCustomizable;
386
isDashableOrDotable = f.isDashableOrDotable;
387
isDoubleBoundaryable= f.isDoubleBoundaryable;
388
isFilled = f.isFilled;
389
isOnRotation = f.isOnRotation;
390
isResizable = f.isResizable;
391
isSelected = f.isSelected;
392
interiorColor = f.interiorColor;
393
isThicknessable = f.isThicknessable;
394
blackDashLength = f.blackDashLength;
395
bordersPosition = f.bordersPosition;
397
doubleColor = f.doubleColor;
398
doubleSep = f.doubleSep;
399
gradientAngle = f.gradientAngle;
400
gradientEndColor= f.gradientEndColor;
401
gradientMidPoint= f.gradientMidPoint;
402
gradientStartColor=f.gradientStartColor;
403
hasDoubleBoundary=f.hasDoubleBoundary;
404
hasShadow = f.hasShadow;
405
hatchingAngle = f.hatchingAngle;
406
hatchingColor = f.hatchingColor;
407
hatchingStyle = f.hatchingStyle;
408
hatchingWidth = f.hatchingWidth;
409
hatchingSep = f.hatchingSep;
410
linesColor = f.linesColor;
411
lineStyle = f.lineStyle;
412
number = sameNumber ? f.number : meter++;
413
rotationAngle = f.rotationAngle;
414
shadowAngle = f.shadowAngle;
415
shadowColor = f.shadowColor;
416
shadowSize = f.shadowSize;
417
thickness = f.thickness;
418
whiteDashLength = f.whiteDashLength;
424
* Allows to know if the new position is a valid borders position.
425
* @param pos The position to check.
426
* @return True is the position is valid.
428
public static boolean isValidBordersPosition(String pos)
430
return pos.equals(PSTricksConstants.BORDERS_INSIDE)
431
|| pos.equals(PSTricksConstants.BORDERS_MIDDLE)
432
|| pos.equals(PSTricksConstants.BORDERS_OUTSIDE);
439
* @return True if the figure is in rotation.
441
public boolean isOnRotation()
450
* @return True if the figure is hatched.
452
public synchronized boolean isHatched()
454
return !hatchingStyle.equals(PSTricksConstants.TOKEN_FILL_NONE) &&
455
!hatchingStyle.equals(PSTricksConstants.TOKEN_FILL_SOLID) &&
456
!hatchingStyle.equals(PSTricksConstants.TOKEN_FILL_GRADIENT) ;
463
* Allows to set if the figure must be in rotation or not.
464
* @param on True : the figure must be on rotation.
466
public synchronized void setOnRotation(boolean on)
469
borders.setOnRotation(on);
472
updateStyleOfDelimitors();
479
* Allows to change the style of the delimiters following the actions to do (rotation, ...).
481
public void updateStyleOfDelimitors()
484
borders.updateStyleOfDelimitors();
491
* Allows to create a Java Swing shape from the figure.
492
* @return The Java Swing shape.
494
public abstract Shape createShape2D();
499
* Allows to create a java swing shape from the figure (without any rotation).
500
* @return The java swing shape.
502
public abstract Shape createNonRotatedShape2D();
507
public Object clone() throws CloneNotSupportedException
509
Figure f = (Figure)super.clone();
511
f.isOnRotation = isOnRotation;
512
f.rotationAngle = rotationAngle;
513
f.isSelected = isSelected;
514
f.interiorColor = interiorColor;
515
f.linesColor = linesColor;
516
f.isFilled = isFilled;
517
f.canBeFilled = canBeFilled;
519
f.blackDashLength = blackDashLength;
520
f.whiteDashLength = whiteDashLength;
521
f.lineStyle = lineStyle;
523
f.thickness = thickness;
524
f.gravityCenter = (LaTeXDrawPoint2D)gravityCenter.clone();
526
f.doubleColor = doubleColor;
527
f.doubleSep = doubleSep;
528
f.hasDoubleBoundary = hasDoubleBoundary;
529
f.hatchingAngle = hatchingAngle;
530
f.hatchingColor = hatchingColor;
531
f.hatchingStyle = hatchingStyle;
532
f.hatchingWidth = hatchingWidth;
533
f.isBordersMovable = isBordersMovable;
534
f.isCustomizable = isCustomizable;
535
f.isDashableOrDotable = isDashableOrDotable;
536
f.isDoubleBoundaryable = isDoubleBoundaryable;
537
f.isResizable = isResizable;
538
f.isThicknessable = isThicknessable;
539
f.bordersPosition = bordersPosition;
541
f.hasShadow = hasShadow;
542
f.shadowAngle = shadowAngle;
543
f.shadowColor = shadowColor;
544
f.shadowSize = shadowSize;
545
f.canHaveShadow = canHaveShadow;
546
f.gradientAngle = gradientAngle;
547
f.gradientEndColor = gradientEndColor;
548
f.gradientStartColor = gradientStartColor;
549
f.gradientMidPoint = gradientMidPoint;
551
f.hatchingSep = hatchingSep;
560
* Allows to know if the figure can be filled or not.
561
* @return True if the figure can be filled.
563
public boolean canBeFilled()
572
* Allows to know if the figure can be hatched or not
573
* @return True if the figure can be hatched (for most of figures, if it can be filled, it can be hatched)
575
public boolean canBeHatched()
584
* Allows to get the number of the figure
585
* @return The number of the figure
587
public synchronized int getNumber()
596
* Allows to get a point of the borders
597
* @param id The position of the point (-1 : return the last point, in fact the south-east point)
600
public synchronized LaTeXDrawPoint2D getBordersPoint(int id)
606
return borders.getPoint(borders.getNbPoints()-1);
608
if(id<0 || id>LaTeXDrawRectangle.NB_POINTS_FRAME-1)
609
throw new IllegalArgumentException();
611
return borders.getPoint(id);
618
* Allows to get the angle of rotation (in rad).
619
* @return The angle of rotation.
621
public synchronized double getRotationAngle()
623
return rotationAngle;
630
* Allows to set the angle of rotation
631
* @param theta The new angle of rotation in radian.
633
public synchronized void setRotationAngle(double theta)
635
if(!Double.isInfinite(theta) && !Double.isNaN(theta))
637
rotationAngle = theta%(PI*2.);
640
borders.setRotationAngle(rotationAngle);
648
* Allows to set the variable isSelected
649
* @param state The new value of isSelected
651
public synchronized void setSelected(boolean state)
656
onDelimitorRelease();
662
borders.setSelected(state);
671
* Allows to set the colour of the borders of the figure
672
* @param c The new colour of the borders
674
public synchronized void setLinesColor(Color c)
684
* Allows to set the colour of the interior of the figure
685
* @param c The new colour of the interior
687
public synchronized void setInteriorColor(Color c)
698
* Allows to set the style of the lines of the figure
699
* @param style The new style of the lines of the figure
700
* @throws IllegalArgumentException If the style is invalid.
702
public synchronized void setLineStyle(String style)
704
if(isValidStyle(style))
707
throw new IllegalArgumentException();
714
* Allows to change the kid of hatch of the figure.
715
* @param style The new style.
716
* @throws IllegalArgumentException If the style is invalid.
718
public synchronized void setHatchingStyle(String style)
720
if(PSTricksConstants.isValidFillStyle(style))
721
hatchingStyle = style;
723
throw new IllegalArgumentException();
730
* Allows to set the attribute isFilled
731
* @param state The new value of
733
public synchronized void setIsFilled(boolean state)
742
* Allows to set the colour of the hatch of the figure
743
* @param color The new colour of the hatch
745
public synchronized void setHatchingColor(Color color)
747
if(canBeFilled() && color!=null)
748
hatchingColor = color;
755
* Allows to set the width of the hatch.
756
* @param width The new width of the hatch.
758
public synchronized void setHatchingWidth(float width)
760
if(width>0 && !Double.isInfinite(width) && !Double.isNaN(width))
761
hatchingWidth = width;
768
* Allows to set the thickness of the figure
769
* @param value The new
771
public synchronized void setThickness(float value)
773
if(value<=0 || Float.isInfinite(value) || Float.isNaN(value))
777
borders.setThickness(value);
786
* Defines the actions to do when the figure is dragged.
787
* @param formerPt The former position of the cursor.
788
* @param newPt The new position of the cursor.
791
public abstract void onDragged(Point formerPt, Point newPt) throws Exception;
797
* Allows to draw the figure.
798
* @param g The graphic
799
* @param antiAlias The antialiasing value
800
* @param rendering The rendering value
801
* @param alphaInter The alpha interpolation value
802
* @param colorRendering The colour rendering value
804
public abstract void draw(Graphics2D g, Object antiAlias, Object rendering, Object alphaInter, Object colorRendering);
810
* Allows to set the last point of the figure
811
* @param pt The new point
813
public synchronized void setLastPoint(LaTeXDrawPoint2D pt)
815
setLastPoint(pt.x, pt.y);
822
* Allows to set the last point of the figure
823
* @param x The X-coordinates of the new point
824
* @param y The Y-coordinates of the new point
826
public abstract void setLastPoint(double x, double y);
831
* @return The last point, null if there is no last point.
833
public abstract LaTeXDrawPoint2D getLastPoint();
838
* Allows to set the first point of the figure
839
* @param pt The new point
841
public synchronized void setFirstPoint(LaTeXDrawPoint2D pt)
843
setFirstPoint(pt.x, pt.y);
850
* Allows to set the first point of the figure
851
* @param x The X-coordinates of the new point
852
* @param y The Y-coordinates of the new point
854
public abstract void setFirstPoint(double x, double y);
860
* Allows to gap the figure
861
* @param shiftX The X-coordinates gap
862
* @param shiftY The Y-coordinates gap
864
public abstract void shift(double shiftX, double shiftY);
870
* Allows to gap the figure.
871
* @param formerPt The former position of the figure.
872
* @param newPt The new position of the figure.
873
* @throws IllegalArgumentException If one of the point is null.
875
public void shift(LaTeXDrawPoint2D formerPt, LaTeXDrawPoint2D newPt)
877
if(formerPt==null || newPt==null)
878
throw new IllegalArgumentException();
880
shift(newPt.x - formerPt.x, newPt.y - formerPt.y);
887
* Allows to gap the figure
889
* @param formerPt The former position of the figure
890
* @param newPt The new position of the figure
892
public void shift(Point formerPt, Point newPt)
894
shift(newPt.x - formerPt.x, newPt.y - formerPt.y);
901
* Allows to rescale the polygon in width
902
* @param formerX The old value of the X-coordinate to change
903
* @param newX The X-coordinate of the point which rescale the figure. It's
904
* Useful for determinate of which side (east or west) we must enlarge thecfigure
905
* @param percent The new width of the figure in percent
906
* @param bound The reference for moving points (the borders of the figure
907
* or, for example, the borders of the drawing containing the figure)
909
public abstract void rescaleX(double formerX, double newX, double percent, LaTeXDrawRectangle bound);
915
* Allows to rescale the polygon in width
916
* @param formerY The former value of the y
917
* @param newY The Y-coordinate of the point which rescale the polygon. It's
918
* Useful for determinate of which side (east or west) we must enlarge the polygon
919
* @param percent The new width of the polygon in percent
920
* @param bound The reference for moving points (the borders of the figure
921
* or, for example, the borders of the drawing containing the figure)
923
public abstract void rescaleY(double formerY, double newY, double percent, LaTeXDrawRectangle bound);
929
* Allows to rotate, following the angle of rotation, the given point.
930
* @param p The point to rotate.
931
* @return The new point rotated.
933
public LaTeXDrawPoint2D rotatePoint(LaTeXDrawPoint2D p)
935
return rotatePoint(p, gravityCenter, rotationAngle);
942
* Allows to rotate a point with the gravity centre of the figure.
943
* @param p The point to rotate.
944
* @param theta The angle of rotation.
945
* @return The rotated point.
947
public synchronized LaTeXDrawPoint2D rotatePoint(LaTeXDrawPoint2D p, double theta)
949
return rotatePoint(p, getGravityCenter(), theta);
956
* Allows to rotate a point with as reference an other point.
957
* @param p The point to rotate.
958
* @param gravityC The point of reference.
959
* @param theta The angle of rotation (in rad).
960
* @return The rotated point.
962
public static LaTeXDrawPoint2D rotatePoint(LaTeXDrawPoint2D p, LaTeXDrawPoint2D gravityC, double theta)
964
LaTeXDrawPoint2D pt = new LaTeXDrawPoint2D();
969
theta = 2.*PI + theta;
971
if((theta%(2.*PI))==0.)
972
return (LaTeXDrawPoint2D)p.clone();
974
if(Math.abs(theta%(2.*PI)-PI/2.)<0.000001)
981
if(Math.abs(theta%(2.*PI)-PI)<0.000001)
988
if(Math.abs(theta%(2.*PI)-(3.*PI/2.))<0.000001)
995
cosTheta = Math.cos(theta);
996
sinTheta = Math.sin(theta);
1001
pt.x = cosTheta * (p.x - gravityC.x) - sinTheta * (p.y - gravityC.y) + gravityC.x;
1002
pt.y = sinTheta * (p.x - gravityC.x) + cosTheta * (p.y - gravityC.y) + gravityC.y;
1011
* Allows to rotate, following the negation of angle of rotation, the given point.
1012
* @param p The point to rotate.
1013
* @return The new point rotated.
1015
public LaTeXDrawPoint2D rotateInvertPoint(LaTeXDrawPoint2D p)
1017
LaTeXDrawPoint2D pt = new LaTeXDrawPoint2D();
1018
double angle = -rotationAngle;
1023
angle = 2.*PI + angle;
1025
angle = angle%(2.*PI);
1028
return (LaTeXDrawPoint2D)p.clone();
1030
if(Math.abs(angle-(PI/2.))<0.000001)
1037
if(Math.abs(angle-PI)<0.000001)
1044
if(Math.abs(angle-(3.*PI/2.))<0.000001)
1051
cosTheta = Math.cos(angle);
1052
sinTheta = Math.sin(angle);
1057
pt.x = cosTheta * (p.x - gravityCenter.x) - sinTheta * (p.y - gravityCenter.y) + gravityCenter.x;
1058
pt.y = sinTheta * (p.x - gravityCenter.x) + cosTheta * (p.y - gravityCenter.y) + gravityCenter.y;
1067
* Allows to rotate, following the angle of rotation, the given point.
1068
* @param p The point to rotate.
1069
* @return The new point rotated.
1071
public LaTeXDrawPoint2D rotatePoint(Point p)
1073
return rotatePoint(new LaTeXDrawPoint2D(p.x, p.y));
1080
* Allows to rotate, following the negation of the angle of rotation, the given point.
1081
* @param p The point to rotate.
1082
* @return The new point rotated.
1084
public LaTeXDrawPoint2D rotateInvertPoint(Point p)
1086
return rotateInvertPoint(new LaTeXDrawPoint2D(p.x, p.y));
1093
* Actions to do when the figure is released.
1095
public synchronized void onDelimitorRelease()
1097
updateStyleOfDelimitors();
1100
borders.onDelimitorRelease();
1108
* @param g The graphics.
1109
* @param antiAlias The antialiasing value.
1110
* @param rendering The rendering value.
1111
* @param alphaInter The alpha interpolation value.
1112
* @param colorRendering The colour rendering value.
1113
* @param s The pattern of the figure to fill.
1115
protected void fillFigure(Graphics2D g, Object antiAlias, Object rendering, Object alphaInter, Object colorRendering, Shape s)
1117
Color formerColor = g.getColor();
1118
GeneralPath p = new GeneralPath(s);
1119
p.setWindingRule(GeneralPath.WIND_NON_ZERO);
1123
if(!hatchingStyle.equals(PSTricksConstants.TOKEN_FILL_NONE))
1125
if(hatchingStyle.equals(PSTricksConstants.TOKEN_FILL_SOLID))
1127
g.setColor(interiorColor);
1129
g.setColor(formerColor);
1133
if(hatchingStyle.equals(PSTricksConstants.TOKEN_FILL_GRADIENT))
1135
LaTeXDrawPoint2D NW = getTheNWPoint();
1136
LaTeXDrawPoint2D SE = getTheSEPoint();
1137
LaTeXDrawPoint2D pt1 = new LaTeXDrawPoint2D((NW.x+SE.x)/2., NW.y);
1138
LaTeXDrawPoint2D pt2 = new LaTeXDrawPoint2D((NW.x+SE.x)/2., SE.y);
1139
double angle = gradientAngle%(2*PI);
1140
double gradMidPt = gradientMidPoint;
1142
angle = 2*PI + angle;
1146
gradMidPt = 1 - gradientMidPoint;
1152
if((angle%(PI/2.))==0)
1154
pt1 = new LaTeXDrawPoint2D(NW.x, (NW.y+SE.y)/2.);
1155
pt2 = new LaTeXDrawPoint2D(SE.x, (NW.y+SE.y)/2.);
1157
pt1.x = pt2.x - Point2D.distance(pt2.x, pt2.y, SE.x,(NW.y+SE.y)/2.);
1158
pt2.x = (NW.x+(SE.x-NW.x)*gradMidPt);
1162
LaTeXDrawPoint2D cg = getGravityCenter();
1165
pt1 = Figure.rotatePoint(pt1, cg, -angle);
1166
pt2 = Figure.rotatePoint(pt2, cg, -angle);
1167
l = new Line(pt1, pt2, false);
1169
if(angle>=0 && angle<(PI/2.))
1170
l2 = l.getPerpendicularLine(NW, false);
1171
else l2 = l.getPerpendicularLine(new LaTeXDrawPoint2D(NW.x,SE.y), false);
1173
pt1 = l.getIntersection(l2);
1174
double distance = Point2D.distance(cg.x, cg.y, pt1.x, pt1.y);
1175
l.setPointAt(pt1, 0);
1176
LaTeXDrawPoint2D[] pts = l.findPoints(pt1, 2*distance*gradMidPt);
1180
pt1 = Figure.rotatePoint(pt1, gravityCenter, PI);
1186
pt1.y = pt2.y - Point2D.distance(pt2.x, pt2.y, (NW.x+SE.x)/2.,SE.y);
1187
pt2.y = (NW.y+(SE.y-NW.y)*gradMidPt);
1190
g.setPaint(new GradientPaint(
1191
(float)pt1.x, (float)pt1.y, gradientStartColor,
1192
(float)pt2.x, (float)pt2.y, gradientEndColor,true));
1194
g.setColor(formerColor);
1198
Shape oldClip = g.getClip();
1199
Rectangle2D bounds = s.getBounds2D();
1202
if(isFilled() || hasShadow())
1204
g.setColor(interiorColor);
1210
Stroke oldStroke = g.getStroke();
1212
if(hatchingStyle.equals(PSTricksConstants.TOKEN_FILL_VLINES) ||
1213
hatchingStyle.equals(PSTricksConstants.TOKEN_FILL_VLINES_F))
1214
paintHatchings2(g, hatchingAngle, bounds);
1216
if(hatchingStyle.equals(PSTricksConstants.TOKEN_FILL_HLINES) ||
1217
hatchingStyle.equals(PSTricksConstants.TOKEN_FILL_HLINES_F))
1218
paintHatchings2(g, hatchingAngle>0?hatchingAngle-Math.PI/2.:hatchingAngle+Math.PI/2., bounds);
1220
if(hatchingStyle.equals(PSTricksConstants.TOKEN_FILL_CROSSHATCH) ||
1221
hatchingStyle.equals(PSTricksConstants.TOKEN_FILL_CROSSHATCH_F))
1223
paintHatchings2(g, hatchingAngle, bounds);
1224
paintHatchings2(g, hatchingAngle>0?hatchingAngle-Math.PI/2.:hatchingAngle+Math.PI/2., bounds);
1227
g.setStroke(oldStroke);
1235
g.setColor(interiorColor);
1238
}catch(LaTeXDrawException e)
1240
e.printStackTrace();
1242
g.setColor(formerColor);
1248
* Paints the hatchings.
1249
* @param g The graphics to paint.
1250
* @param angle The angle of the hatchings (in radian).
1251
* @param clip The clip box.
1253
private void paintHatchings2(Graphics2D g, double angle, Rectangle2D clip)
1255
if(g==null || clip==null)
1258
double angle2 = angle%(Math.PI*2.);
1259
float halphPI = (float)(Math.PI/2.);
1263
if((float)angle2>3f*halphPI)
1264
angle2 = angle2-Math.PI*2.;
1266
if((float)angle2>halphPI)
1267
angle2 = angle2-Math.PI;
1270
if((float)angle2<-3f*halphPI)
1271
angle2 = angle2+Math.PI*2.;
1273
if((float)angle2<-halphPI)
1274
angle2 = angle2+Math.PI;
1276
Line2D.Double line = new Line2D.Double();
1277
double val = hatchingWidth+hatchingSep;
1278
float fAngle = (float)angle2;
1280
g.setStroke(new BasicStroke(hatchingWidth, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER));
1281
g.setPaint(getHatchingColor());
1285
line.y1 = clip.getMinY();
1286
line.y2 = clip.getMaxY();
1287
double maxX = clip.getMaxX();
1289
for(double x = clip.getMinX(); x<maxX; x+=val)
1291
line.x1 = line.x2 = x;
1296
if(fAngle==halphPI || fAngle==-halphPI)
1298
line.x1 = clip.getMinX();
1299
line.x2 = clip.getMaxX();
1300
double maxY = clip.getMaxY();
1302
for(double y = clip.getMinY(); y<maxY; y+=val)
1304
line.y1 = line.y2 = y;
1310
double incX = val/Math.cos(angle2);
1311
double incY = val/Math.sin(angle2);
1316
line.y1 = clip.getMinY();
1317
maxX = clip.getMaxX() + (clip.getMaxY()-(clip.getMinY()<0?clip.getMinY():0)) * Math.tan(angle2);
1321
line.y1 = clip.getMaxY();
1322
maxX = clip.getMaxX() - clip.getMaxY() * Math.tan(angle2);
1325
line.x1 = clip.getMinX();
1329
if(((float)incX)<=0f)
1332
while(line.x2 < maxX)
1344
* Allows to know if the point pt is in (or on) the figure.
1345
* @param pt The point
1346
* @return true: if the point is in or on the figure.
1348
public boolean isIn(Point pt)
1350
return isIn(new LaTeXDrawPoint2D(pt.x, pt.y));
1357
* Allows to know if the point pt is in(or on) the figure.
1358
* @param pt The point
1359
* @return true : if the point is in or on the figure.
1361
public abstract boolean isIn(LaTeXDrawPoint2D pt);
1367
* @return True if the figure is filled by a colour.
1369
public synchronized boolean isFilled()
1378
* @return True if a delimiter is selected.
1380
public synchronized boolean isADelimitorSelected()
1382
return dSelected != null;
1389
* Allows to know if the figure intersects the given shape.
1390
* @param r The shape.
1391
* @return True if the figure intersects the shape.
1393
public boolean intersected(Rectangle2D.Double r)
1398
Shape s = createShape2D();
1400
Shape sTooSmall = getTooSmallShape(s);
1405
BasicStroke wideline = new BasicStroke(thickness);
1406
Shape outline = wideline.createStrokedShape(s);
1408
return outline.intersects(r) && !outline.contains(r);
1415
* Allows to check if the style is possible.
1416
* @param style The style to check.
1417
* @return True if the style is valid.
1419
public static boolean isValidStyle(String style)
1421
if(style.equals(PSTricksConstants.LINE_NONE_STYLE)||
1422
style.equals(PSTricksConstants.LINE_DASHED_STYLE) ||
1423
style.equals(PSTricksConstants.LINE_DOTTED_STYLE))
1433
* Allows to create a list of the different position of the borders.
1436
public static LaTeXDrawComboBox createBordersPositionChoice()
1438
LaTeXDrawComboBox dbPositionChoice = new LaTeXDrawComboBox();
1439
dbPositionChoice.setRenderer(new LabelListCellRenderer());
1441
JLabel label = new JLabel(PSTricksConstants.BORDERS_OUTSIDE);
1442
label.setName(PSTricksConstants.BORDERS_OUTSIDE);
1443
label.setIcon(LaTeXDrawResources.innerIcon);
1444
dbPositionChoice.addItem(label);
1446
label = new JLabel(PSTricksConstants.BORDERS_INSIDE);
1447
label.setName(PSTricksConstants.BORDERS_INSIDE);
1448
label.setIcon(LaTeXDrawResources.outerIcon);
1449
dbPositionChoice.addItem(label);
1451
label = new JLabel(PSTricksConstants.BORDERS_MIDDLE);
1452
label.setName(PSTricksConstants.BORDERS_MIDDLE);
1453
label.setIcon(LaTeXDrawResources.middleIcon);
1454
dbPositionChoice.addItem(label);
1456
dbPositionChoice.setName(Figure.LABEL_BORDERS_POSITION_CHOICE);
1457
dbPositionChoice.setActionCommand(Figure.LABEL_BORDERS_POSITION_CHOICE);
1458
dbPositionChoice.setSelectedItem(Figure.DEFAULT_BORDERS_POSITION);
1460
return dbPositionChoice;
1467
* Allows to create a list of the different style of line.
1470
public static LaTeXDrawComboBox createStyleLineChoice()
1472
LaTeXDrawComboBox lineChoice = new LaTeXDrawComboBox();
1473
lineChoice.setRenderer(new LabelListCellRenderer());
1474
JLabel label = new JLabel(PSTricksConstants.LINE_NONE_STYLE);
1475
label.setName(PSTricksConstants.LINE_NONE_STYLE);
1476
label.setIcon(LaTeXDrawResources.lineStyleNoneIcon);
1477
lineChoice.addItem(label);
1478
label = new JLabel(PSTricksConstants.LINE_DASHED_STYLE);
1479
label.setName(PSTricksConstants.LINE_DASHED_STYLE);
1480
label.setIcon(LaTeXDrawResources.lineStyleDashedIcon);
1481
lineChoice.addItem(label);
1482
label = new JLabel(PSTricksConstants.LINE_DOTTED_STYLE);
1483
label.setName(PSTricksConstants.LINE_DOTTED_STYLE);
1484
label.setIcon(LaTeXDrawResources.lineStyleDottedIcon);
1485
lineChoice.addItem(label);
1487
lineChoice.setSelectedItem(PSTricksConstants.LINE_NONE_STYLE);
1496
* Allows to create a list containing all kinds of hatch.
1497
* @return A JComboBox.
1499
public static LaTeXDrawComboBox createFillChoice()
1501
LaTeXDrawComboBox list = new LaTeXDrawComboBox();
1502
list.setRenderer(new LabelListCellRenderer());
1503
list.setName(LABEL_HATCH_CHOICE);
1504
list.setActionCommand(LABEL_HATCH_CHOICE);
1506
JLabel l = new JLabel(PSTricksConstants.TOKEN_FILL_NONE);
1507
l.setName(PSTricksConstants.TOKEN_FILL_NONE);
1508
l.setIcon(LaTeXDrawResources.hatchNoneIcon);
1510
l = new JLabel(PSTricksConstants.TOKEN_FILL_CROSSHATCH);
1511
l.setName(PSTricksConstants.TOKEN_FILL_CROSSHATCH);
1512
l.setIcon(LaTeXDrawResources.hatchCrossIcon);
1514
l = new JLabel(PSTricksConstants.TOKEN_FILL_HLINES);
1515
l.setName(PSTricksConstants.TOKEN_FILL_HLINES);
1516
l.setIcon(LaTeXDrawResources.hatchHorizIcon);
1518
l = new JLabel(PSTricksConstants.TOKEN_FILL_VLINES);
1519
l.setName(PSTricksConstants.TOKEN_FILL_VLINES);
1520
l.setIcon(LaTeXDrawResources.hatchVertIcon);
1522
l = new JLabel(PSTricksConstants.TOKEN_FILL_GRADIENT);
1523
l.setName(PSTricksConstants.TOKEN_FILL_GRADIENT);
1524
l.setIcon(LaTeXDrawResources.gradientIcon);
1534
* Allows to obtain the point most to the North and on the West of the figure.
1535
* @return the point most to the North and on the West of the figure.
1537
public LaTeXDrawPoint2D getTheNWPoint()
1540
return borders.getTheNWPoint();
1548
* Allows to get the south-east point by taking into account the angle of rotation.
1549
* @return The south-east point of the rotated rectangle.
1551
public synchronized LaTeXDrawPoint2D getTheSERotatedPoint()
1554
return borders.getTheSERotatedPoint();
1562
* Allows to get the north-west point by taking into account the angle of rotation.
1563
* @return The north-west point of the rotated rectangle.
1565
public LaTeXDrawPoint2D getTheNWRotatedPoint()
1568
return borders.getTheNWRotatedPoint();
1576
* Allows to get a clone of the centre of gravity of the figure.
1577
* @return The centre of gravity of the figure.
1579
public synchronized LaTeXDrawPoint2D getGravityCenter()
1581
updateGravityCenter();
1582
return (LaTeXDrawPoint2D)gravityCenter.clone();
1589
* Allows to get the LaTeX code of the figure.
1590
* @return the LaTeX code of the figure.
1592
public abstract String getCodePSTricks(DrawBorders drawBorders, float ppc);
1598
* Allows to get the colour of the borders of the figure.
1599
* @return The colour of the borders of the figure.
1601
public synchronized Color getLinesColor()
1610
* @return The borders of the figure.
1612
public synchronized LaTeXDrawRectangle getBorders()
1620
* @return The colour of the interior of the figure.
1622
public synchronized Color getInteriorColor()
1624
return interiorColor;
1630
* @return The style of the lines of the figure.
1632
public synchronized String getLineStyle()
1640
* @return The kind of hatch.
1642
public synchronized String getHatchingStyle()
1644
return hatchingStyle;
1650
* @return The colour of the hatch.
1652
public synchronized Color getHatchingColor()
1654
return hatchingColor;
1660
* @return The width of the lines of the hatch.
1662
public synchronized float getHatchingWidth()
1664
return hatchingWidth;
1670
* @return The thickness of the figure.
1672
public synchronized float getThickness()
1680
* Corresponds to what to do when the user click on the figure.
1681
* @param pt The clicked point.
1683
public synchronized void onClick(Point pt)
1687
if (borders != null)
1688
borders.onClick(pt);
1695
* Corresponds to what to do when the user release the mouse.
1697
public synchronized void onRelease()
1699
setOnRotation(false);
1703
borders.onRelease();
1710
* Allows to obtain the point most to the South and on the East of the figure.
1711
* @return the point most to the South and on the East of the figure.
1713
public synchronized LaTeXDrawPoint2D getTheSEPoint()
1716
return borders.getTheSEPoint();
1724
* @return True if the figure is selected.
1726
public synchronized boolean isSelected()
1735
* Allows to update the centre of gravity of the figure (Useful for rotation).
1737
public synchronized void updateGravityCenter()
1742
borders.updateGravityCenter();
1744
LaTeXDrawPoint2D gc = borders.getGravityCenter();
1746
if(gravityCenter!=null)
1749
gravityCenter.setLocation(gc);
1751
else gravityCenter = gc;
1757
* @return Returns the isCustomizable.
1759
public synchronized boolean isCustomizable()
1761
return isCustomizable;
1767
* @return Returns the isThicknessable.
1769
public synchronized boolean isThicknessable()
1771
return isThicknessable;
1777
* @return Returns the doubleSep.
1779
public synchronized double getDoubleSep()
1787
* @param doubleSep The doubleSep to set.
1789
public synchronized void setDoubleSep(double doubleSep)
1791
if(!Double.isInfinite(doubleSep) && !Double.isNaN(doubleSep))
1792
this.doubleSep = doubleSep;
1798
* @return Returns the hasDoubleBoundary.
1800
public synchronized boolean hasDoubleBoundary()
1802
return hasDoubleBoundary;
1808
* @param hasDoubleBoundary The hasDoubleBoundary to set.
1810
public synchronized void setHasDoubleBoundary(boolean hasDoubleBoundary)
1812
this.hasDoubleBoundary = hasDoubleBoundary;
1819
* @return Returns the isDashableOrDotable.
1821
public synchronized boolean isDashableOrDotable()
1823
return isDashableOrDotable;
1829
* @return Returns the isDoubleBoundaryable.
1831
public synchronized boolean isDoubleBoundaryable()
1833
return isDoubleBoundaryable;
1839
* @param isCustomizable The isCustomizable to set.
1841
public synchronized void setCustomizable(boolean isCustomizable)
1843
this.isCustomizable = isCustomizable;
1849
* @return Returns the isResizable.
1851
public synchronized boolean isResizable()
1859
* @param isResizable The isResizable to set.
1861
public synchronized void setResizable(boolean isResizable)
1863
this.isResizable = isResizable;
1869
* @return Returns the doubleColor.
1871
public synchronized Color getDoubleColor()
1879
* @param doublecolor The doubleColor to set.
1881
public synchronized void setDoubleColor(Color doublecolor)
1883
if(doublecolor!=null)
1884
this.doubleColor = doublecolor;
1890
* @return Returns the doubleLinePosition.
1892
public synchronized String getBordersPosition()
1894
return bordersPosition;
1900
* @param doubleLinePosition The doubleLinePosition to set.
1902
public synchronized void setBordersPosition(String doubleLinePosition)
1904
if(isValidBordersPosition(doubleLinePosition) && isBordersMovable)
1906
this.bordersPosition = doubleLinePosition;
1914
* Allows to get the north-westiest point of the bounds of the figure (the
1915
* bounds consider the thickness of the figure and the position of the borders).
1916
* @return The north-westiest point of the bounds of the figure
1918
public LaTeXDrawPoint2D getTheNWBoundPoint()
1920
Rectangle2D bounds = createShape2D().getBounds2D();
1928
LaTeXDrawPoint2D cg = getGravityCenter();
1929
LaTeXDrawPoint2D shadowCg = (LaTeXDrawPoint2D)cg.clone();
1930
shadowCg.setLocation(cg.x+shadowSize, cg.y);
1931
shadowCg = Figure.rotatePoint(shadowCg, cg, shadowAngle);
1932
dx = shadowCg.x-cg.x;
1933
dy = cg.y-shadowCg.y;
1934
Rectangle2D.Double bounds2 = new Rectangle2D.Double(bounds.getX()+dx,bounds.getY()+dy,
1935
bounds.getWidth(), bounds.getHeight());
1936
bounds2.add(bounds);
1940
return new LaTeXDrawPoint2D(bounds.getX()-thickness/2., bounds.getY()-thickness/2.);
1947
* Allows to get the north-westiest point of the bounds of the figure (the
1948
* bounds consider the thickness of the figure and the position of the
1949
* borders), without any rotation of the figure. It doesn't take account of the shadow.
1951
public LaTeXDrawPoint2D getTheNWNonRotatedBoundPoint()
1953
Rectangle2D bounds = createNonRotatedShape2D().getBounds2D();
1958
return new LaTeXDrawPoint2D(bounds.getMinX() - thickness / 2.,
1959
bounds.getMinY() - thickness / 2.);
1967
* Allows to get the south-eastiest point of the bounds of the figure (the
1968
* bounds consider the thickness of the figure and the position of the
1969
* borders), without any rotation of the figure. It doesn't take account of the shadow.
1970
* @return The south-eastiest point of the bounds of the figure.
1972
public LaTeXDrawPoint2D getTheSENonRotatedBoundPoint()
1974
Rectangle2D bounds = createNonRotatedShape2D().getBounds2D();
1979
return new LaTeXDrawPoint2D(bounds.getMaxX() + thickness / 2., bounds.getMaxY() + thickness / 2.);
1986
* Allows to get the south-eastiest point of the bounds of the figure (the
1987
* bounds consider the thickness of the figure and the position of the borders).
1988
* @return The south-eastiest point of the bounds of the figure.
1990
public LaTeXDrawPoint2D getTheSEBoundPoint()
1992
Rectangle2D bounds = createShape2D().getBounds2D();
2000
LaTeXDrawPoint2D cg = getGravityCenter();
2001
LaTeXDrawPoint2D shadowCg = (LaTeXDrawPoint2D)cg.clone();
2002
shadowCg.setLocation(cg.x+shadowSize, cg.y);
2003
shadowCg = Figure.rotatePoint(shadowCg, cg, shadowAngle);
2004
dx = shadowCg.x-cg.x;
2005
dy = cg.y-shadowCg.y;
2006
Rectangle2D.Double bounds2 = new Rectangle2D.Double(bounds.getX()+dx,bounds.getY()+dy,
2007
bounds.getWidth(), bounds.getHeight());
2008
bounds2.add(bounds);
2012
return new LaTeXDrawPoint2D(bounds.getX() + thickness / 2.
2013
+ bounds.getWidth(), bounds.getY() + thickness / 2. + bounds.getHeight());
2019
* @return True if the borders of the figure can move.
2021
public synchronized boolean isBordersMovable()
2023
return isBordersMovable;
2029
* Allows to change the number of the figure.
2031
public synchronized void changeMeter()
2039
* Allows to compute the angle of the point pt.
2040
* @param pt The point of reference.
2041
* @param gravityC The centre of gravity of the trigonometric circle.
2042
* @return The angle.
2044
public static double computeAngle(Point pt, LaTeXDrawPoint2D gravityC)
2046
double c = gravityC.y-pt.y;
2047
double b = gravityC.x-pt.x;
2056
* Allows to compute the angle of rotation between two points.
2057
* using the gravity centre of the figure.
2058
* @param formerPt The first point.
2059
* @param newPt The second point.
2060
* @return The rotation point.
2061
* @throws IllegalArgumentException If formerPt or newPt are null.
2063
public double computeRotationAngle(Point formerPt, Point newPt) throws IllegalArgumentException
2065
double thetaOld = Figure.computeAngle(formerPt, gravityCenter);
2066
double thetaNew = Figure.computeAngle(newPt, gravityCenter);
2068
if((thetaNew-thetaOld)>(PI/2.) || (thetaNew-thetaOld)<-(PI/2.))
2069
return thetaNew+thetaOld;
2071
return thetaNew-thetaOld;
2078
* Allows to rotate the figure around its gravity centre.
2079
* @param formerPt The former point.
2080
* @param newPt The new point.
2081
* @throws IllegalArgumentException If formerPt or newPt is null.
2083
public void rotate(Point formerPt, Point newPt) throws IllegalArgumentException
2085
setRotationAngle(rotationAngle+computeRotationAngle(formerPt, newPt));
2092
* Allows rotate the figure around the point gravityC.
2093
* @param gravityC The point of reference of the rotation.
2094
* @param angle The angle of the rotation.
2096
public void rotate(LaTeXDrawPoint2D gravityC, double angle)
2098
if(!gravityC.equals(gravityCenter))
2099
{// We must rotate the position of the figure
2100
LaTeXDrawPoint2D rotGC = rotatePoint(gravityCenter, gravityC, angle);
2101
shift(gravityCenter, rotGC);
2102
updateGravityCenter();
2105
setRotationAngle(rotationAngle+angle);
2111
* @return the blackDashLength.
2113
public synchronized float getBlackDashLength()
2115
return blackDashLength;
2121
* @param blackDashLength the blackDashLength to set.
2123
public synchronized void setBlackDashLength(float blackDashLength)
2125
if(blackDashLength>0 && !Float.isInfinite(blackDashLength) && !Float.isNaN(blackDashLength))
2126
this.blackDashLength = blackDashLength;
2132
* @return the hatchingAngle.
2134
public synchronized double getHatchingAngle()
2136
return hatchingAngle;
2142
* @param hatchingAngle the hatchingAngle to set.
2144
public synchronized void setHatchingAngle(double hatchingAngle)
2146
if(!Double.isInfinite(hatchingAngle) && !Double.isNaN(hatchingAngle))
2147
this.hatchingAngle = hatchingAngle%(Math.PI*2.);
2153
* @return the whiteDashLength.
2155
public synchronized float getWhiteDashLength()
2157
return whiteDashLength;
2163
* @param whiteDashLength the whiteDashLength to set.
2165
public synchronized void setWhiteDashLength(float whiteDashLength)
2167
if(whiteDashLength>0 && !Float.isInfinite(whiteDashLength) && !Float.isNaN(whiteDashLength))
2168
this.whiteDashLength = whiteDashLength;
2174
* @return the dotSep.
2176
public synchronized float getDotSep()
2184
* @param dotSep the dotSep to set.
2186
public synchronized void setDotSep(float dotSep)
2188
if(dotSep>0 && !Float.isInfinite(dotSep) && !Float.isNaN(dotSep))
2189
this.dotSep = dotSep;
2195
* Allows to update the shape of the figure.
2197
public abstract void updateShape();
2201
* Allows to know if the figure is too small to be rescaled.
2202
* @return True if the figure is too small to be rescaled.
2204
public abstract boolean isTooSmallToBeRescaled();
2209
* @return the hasShadow.
2212
public synchronized boolean hasShadow()
2220
* @param hasShadow the hasShadow to set.
2223
public synchronized void setHasShadow(boolean hasShadow)
2225
this.hasShadow = hasShadow;
2231
* @return The shadowAngle (in rad).
2234
public synchronized double getShadowAngle()
2242
* @param shadowAngle the shadowAngle to set in radian.
2245
public synchronized void setShadowAngle(double shadowAngle)
2247
if(!Double.isInfinite(shadowAngle) && !Double.isNaN(shadowAngle))
2248
this.shadowAngle = shadowAngle%(2*Math.PI);
2254
* @return the shadowColor.
2257
public synchronized Color getShadowColor()
2265
* @param shadowColor the shadowColor to set.
2268
public synchronized void setShadowColor(Color shadowColor)
2270
if(shadowColor!=null)
2271
this.shadowColor = shadowColor;
2277
* @return the shadowSize.
2280
public synchronized double getShadowSize()
2288
* @param shadowSize the shadowSize to set.
2291
public synchronized void setShadowSize(double shadowSize)
2293
if(!Double.isInfinite(shadowSize) && !Double.isNaN(shadowSize))
2294
this.shadowSize = shadowSize;
2300
* @return the canHaveShadow.
2303
public boolean canHaveShadow()
2305
return canHaveShadow;
2311
* Allows to create a shape corresponding to the shadow of the figure.
2312
* @return The shadow.
2315
public Shape createShadowShape()
2317
if(!canHaveShadow || !hasShadow) return shape;
2319
Rectangle2D shadowS = createShape2D().getBounds2D();
2321
LaTeXDrawPoint2D cg = getGravityCenter();
2322
LaTeXDrawPoint2D shadowCg = (LaTeXDrawPoint2D)cg.clone();
2323
shadowCg.setLocation(cg.x+shadowSize, cg.y);
2324
shadowCg = Figure.rotatePoint(shadowCg, cg, shadowAngle);
2325
dx = shadowCg.x-cg.x;
2326
dy = cg.y-shadowCg.y;
2327
Rectangle2D.Double bounds2 = new Rectangle2D.Double(shadowS.getX()+dx-thickness/2.,
2328
shadowS.getY()+dy-thickness/2.,
2329
shadowS.getWidth()+thickness, shadowS.getHeight()+thickness);
2336
* @return the gradientAngle.
2339
public synchronized double getGradientAngle()
2341
return gradientAngle;
2347
* @param gradientAngle the gradientAngle to set (in radian).
2350
public synchronized void setGradientAngle(double gradientAngle)
2352
if(!Double.isInfinite(gradientAngle) && !Double.isNaN(gradientAngle))
2353
this.gradientAngle = gradientAngle;
2359
* @return the gradientEndColor.
2362
public synchronized Color getGradientEndColor()
2364
return gradientEndColor;
2370
* @param gradientEndColor the gradientEndColor to set.
2373
public synchronized void setGradientEndColor(Color gradientEndColor)
2375
if(gradientEndColor!=null)
2376
this.gradientEndColor = gradientEndColor;
2382
* @return the gradientMidPoint.
2385
public synchronized double getGradientMidPoint()
2387
return gradientMidPoint;
2393
* @param gradientMidPoint the gradientMidPoint to set.
2396
public synchronized void setGradientMidPoint(double gradientMidPoint)
2398
if(gradientMidPoint>=0 && gradientMidPoint<=1)
2399
this.gradientMidPoint = gradientMidPoint;
2405
* @return the gradientStartColor.
2408
public synchronized Color getGradientStartColor()
2410
return gradientStartColor;
2416
* @param gradientStartColor the gradientStartColor to set.
2419
public synchronized void setGradientStartColor(Color gradientStartColor)
2421
if(gradientStartColor!=null)
2422
this.gradientStartColor = gradientStartColor;
2428
* @return The PSTricks code for the filling of the figure.
2431
public String getPSTricksCodeFilling(float ppc)
2433
String str="fillstyle=";//$NON-NLS-1$
2435
if(hatchingStyle.equals(PSTricksConstants.TOKEN_FILL_NONE))
2438
str += "solid"; //$NON-NLS-1$
2439
else str = "";//$NON-NLS-1$
2442
if(hatchingStyle.equals(PSTricksConstants.TOKEN_FILL_GRADIENT))
2444
str+= "gradient,gradlines=2000";//$NON-NLS-1$
2446
if(!gradientStartColor.equals(PSTricksConstants.DEFAULT_GRADIENT_START_COLOR))
2448
String name = DviPsColors.getColourName(gradientStartColor);
2451
name = "color"+number+'g';//$NON-NLS-1$
2452
DviPsColors.addUserColour(gradientStartColor, name);
2454
str += ",gradbegin=" + name; //$NON-NLS-1$
2457
if(!gradientEndColor.equals(PSTricksConstants.DEFAULT_GRADIENT_END_COLOR))
2459
String name = DviPsColors.getColourName(gradientEndColor);
2462
name = "color"+number+'f';//$NON-NLS-1$
2463
DviPsColors.addUserColour(gradientEndColor, name);
2465
str += ",gradend=" + name; //$NON-NLS-1$
2468
if(gradientMidPoint!=PSTricksConstants.DEFAULT_GRADIENT_MID_POINT)
2469
str+=",gradmidpoint="+(float)gradientMidPoint;//$NON-NLS-1$
2471
if(gradientAngle!=PSTricksConstants.DEFAULT_GRADIENT_ANGLE)
2472
str+=",gradangle="+(float)toDegrees(gradientAngle);//$NON-NLS-1$
2476
if(hatchingStyle.equals(PSTricksConstants.TOKEN_FILL_CROSSHATCH))
2477
str += "crosshatch"; //$NON-NLS-1$
2479
if (hatchingStyle.equals(PSTricksConstants.TOKEN_FILL_HLINES))
2480
str += "hlines"; //$NON-NLS-1$
2482
str += "vlines"; //$NON-NLS-1$
2485
str += "*"; //$NON-NLS-1$
2487
str += ",hatchwidth=" + (getHatchingWidth()/ppc) + ",hatchangle=" + //$NON-NLS-1$ //$NON-NLS-2$
2488
(float)Math.toDegrees(hatchingAngle);
2490
if(((float)hatchingSep)!=((float)DEFAULT_HATCH_SEP))
2491
str+=",hatchsep="+(float)(hatchingSep/PPC); //$NON-NLS-1$
2493
if(!hatchingColor.equals(PSTricksConstants.DEFAULT_HATCHING_COLOR))
2495
String name = DviPsColors.getColourName(hatchingColor);
2498
name = "color"+number+'c';//$NON-NLS-1$
2499
DviPsColors.addUserColour(hatchingColor, name);
2501
str += ",hatchcolor=" + name; //$NON-NLS-1$
2507
if(!interiorColor.equals(PSTricksConstants.DEFAULT_INTERIOR_COLOR))
2509
String name = DviPsColors.getColourName(interiorColor);
2512
name = "color"+number+'b';//$NON-NLS-1$
2513
DviPsColors.addUserColour(interiorColor, name);
2515
str += ",fillcolor=" + name; //$NON-NLS-1$
2526
* @return The PSTricks code for the shape of the lines of the figure.
2529
public String getPSTricksCodeLine(float ppc)
2531
String str = "";//$NON-NLS-1$
2532
boolean coma = false;
2534
if(!linesColor.equals(PSTricksConstants.DEFAULT_LINE_COLOR))
2536
String name = DviPsColors.getColourName(linesColor);
2539
name = "color"+number;//$NON-NLS-1$
2540
DviPsColors.addUserColour(linesColor, name);
2542
str += "linecolor=" + name; //$NON-NLS-1$
2546
if(lineStyle.equals(PSTricksConstants.LINE_DOTTED_STYLE))
2547
str += (coma ? "," : "")+ "linestyle=" + lineStyle + ",dotsep=" + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
2548
(getDotSep() / ppc) + "cm"; //$NON-NLS-1$
2550
if (lineStyle.equals(PSTricksConstants.LINE_DASHED_STYLE))
2551
str += (coma ? "," : "") +"linestyle=" + lineStyle + ",dash=" + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
2552
(getBlackDashLength() / ppc) + "cm " + //$NON-NLS-1$
2553
(getWhiteDashLength() / ppc) + "cm"; //$NON-NLS-1$
2562
* @return True if the current style of the interior of the figure is a gradient.
2565
public synchronized boolean hasGradient()
2567
return hatchingStyle.equals(PSTricksConstants.TOKEN_FILL_GRADIENT);
2574
* @return The borders of the figure (taking account of the thickness, the double borders, ...).
2577
public LaTeXDrawRectangle getBoundBorders()
2579
LaTeXDrawPoint2D NW = getTheNWBoundPoint(), SE = getTheSEBoundPoint();
2580
return new LaTeXDrawRectangle(NW, SE, false);
2588
* @return the hatchingSep.
2591
public synchronized double getHatchingSep()
2599
* @param hatchSep the hatchingSep to set.
2602
public synchronized void setHatchingSep(double hatchSep)
2604
if(hatchSep>0 && !Double.isInfinite(hatchSep) && !Double.isNaN(hatchSep))
2605
this.hatchingSep = hatchSep;
2611
* @return the canHaveArrow.
2613
public synchronized boolean canHaveArrow()
2615
return canHaveArrow;
2621
* Returns horizontally the figure.
2623
* @param origin The location of the horizontal axe.
2625
public abstract void mirrorHorizontal(LaTeXDrawPoint2D origin);
2630
* Returns vertically the figure.
2632
* @param origin The location of the vertical axe.
2634
public abstract void mirrorVertical(LaTeXDrawPoint2D origin);
2639
* Updates the coordinates of the figure to the grid given in parameter.<br>
2640
* Nothing will be done if the magnetic grid is not activated.
2642
* @param grid The magnetic grid.
2644
public abstract void updateToGrid(MagneticGrid grid);
2650
* Checks if the parameters of the figures are equals.
2651
* @param f The figure to compare.
2652
* @param considerShadow True if the parameters of the shadows must be considered.
2653
* @param considerArrow True if the parameters of the arrows must be considered.
2654
* @return True if the parameters are equals.
2657
public boolean isParametersEquals(Figure f, boolean considerShadow, boolean considerArrow)
2659
boolean lineOk = !f.isDashableOrDotable || !isDashableOrDotable ||
2660
(lineStyle.equals(f.lineStyle) && thickness==f.thickness &&
2661
(lineStyle.equals(PSTricksConstants.LINE_NONE_STYLE) ||
2662
(lineStyle.equals(PSTricksConstants.LINE_DOTTED_STYLE) && dotSep==f.dotSep) ||
2663
(lineStyle.equals(PSTricksConstants.LINE_DASHED_STYLE) &&
2664
blackDashLength==f.blackDashLength && whiteDashLength==f.whiteDashLength)));
2666
boolean filledOk = !f.canBeFilled || !canBeFilled ||
2667
(isFilled==f.isFilled && interiorColor.equals(f.interiorColor));
2669
boolean dblbndOk = !f.isDoubleBoundaryable || f.isDoubleBoundaryable ||
2670
(f.hasDoubleBoundary==hasDoubleBoundary &&
2671
doubleColor.equals(f.doubleColor) && doubleSep==f.doubleSep);
2673
boolean arrowOk = !considerArrow || !f.canHaveArrow || !canHaveArrow ||
2674
(((Arrowable)f).getArrowHead1().equals(((Arrowable)this).getArrowHead1()) &&
2675
((Arrowable)f).getArrowHead2().equals(((Arrowable)this).getArrowHead2()));
2677
boolean hatchOk = (!f.canBeFilled || !canBeFilled ||
2678
((f.hatchingStyle.equals(hatchingStyle) && (!isHatched() ||
2679
(f.hatchingAngle==hatchingAngle && f.hatchingColor.equals(hatchingColor) &&
2680
((float)f.hatchingSep)==((float)hatchingSep) && f.hatchingWidth==hatchingWidth))) &&
2681
(hasGradient()==f.hasGradient() &&(!hasGradient() ||
2682
(gradientAngle==f.gradientAngle && gradientEndColor.equals(f.gradientEndColor) &&
2683
gradientMidPoint==f.gradientMidPoint && gradientStartColor.equals(f.gradientStartColor))))));
2685
boolean shadowOk = !considerShadow || !f.canHaveShadow || !canHaveArrow ||
2686
(hasShadow==f.hasShadow && shadowAngle==f.shadowAngle &&
2687
shadowColor.equals(f.shadowColor) && ((float)shadowSize)==((float)f.shadowSize));
2689
return linesColor.equals(f.linesColor) && lineOk && filledOk && dblbndOk && shadowOk &&
2690
hatchOk && arrowOk ;
2696
* @return True is a delimiter is selected.
2699
public boolean isDelimitorSelected()
2701
return dSelected!=null || (borders==null ? false : borders.isDelimitorSelected());
2707
* @return The position of the selected delimiter.
2710
public int getSelectedDelimitorOrientation()
2713
return DELIMITOR_ROTATION;
2715
return DELIMITOR_ORIENTATION_NONE;
2721
* Sometimes a rectangle is too small to be drawn; this method check if the given shape is too small
2722
* and if it is the case, it return a visible shape based on the given shape.
2723
* @param s The shape to check.
2724
* @return A visible check if the given shape is too small or null if it is not the case.
2727
protected Shape getTooSmallShape(Shape s)
2729
Rectangle2D bds = s.getBounds2D();
2731
if(bds.getHeight()<=0)
2733
if(bds.getWidth()<=0)
2734
return new Line2D.Double(bds.getMinX(), bds.getMinY(), bds.getMinX()+1, bds.getMinY()+1);
2735
return new Line2D.Double(bds.getMinX(), bds.getMaxY(), bds.getMaxX(), bds.getMaxY());
2738
if(bds.getWidth()<=0)
2739
return new Line2D.Double(bds.getMaxX(), bds.getMinY(), bds.getMaxX(), bds.getMaxY());
2747
* Gives a gradient to the shape.
2750
protected void setHasGradient()
2752
hatchingStyle = PSTricksConstants.TOKEN_FILL_GRADIENT;
2758
public int hashCode()
2760
return (int)thickness+(int)doubleSep+(linesColor.hashCode()^interiorColor.hashCode()^
2761
hatchingStyle.hashCode()^lineStyle.hashCode());
2768
* Given a right-rectangle ABC right in A, it computes the gap created by the corner of the triangle in B
2769
* based on an initial gap.
2770
* @param a The point A.
2771
* @param b The point B.
2772
* @param c The point C.
2773
* @param gap The initial gap (for example, the thickness, the double border gap,...).
2774
* @return The gap created by the corner of the point B.
2777
public static double getCornerGap(Point2D a, Point2D b, Point2D c, double gap)
2779
if(a==null || b==null || c==null)
2782
return gap / Triangle.getAltitude(a, b, c) * a.distance(b);
2789
* @return True if when the shape has a shadow, then it is filled.
2792
public boolean shadowFillsShape()
2799
* @return the shape.
2802
public synchronized Shape getShape()
2809
* @param number the number to set.
2812
public synchronized void setNumber(int number)
2814
this.number = number;
2818
public void setNewNumber()
2826
public String toString()
2828
return getClass().getName() + "#" + getNumber() + "[thick=" + getThickness() + ", bordCol=" + getLinesColor() + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
2829
", intCol=" + getInteriorColor() + ", dbleCol=" + getDoubleColor() + ", shadCol=" + getShadowColor() + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
2830
", isFilled=" + isFilled() + ", hasShad=" + hasShadow() + ", hasDble=" + hasDoubleBoundary() + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
2831
", shadSize=" + getShadowSize() + ", shadAngle=" + getShadowAngle() + ", gradAngle=" + getGradientAngle() + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
2832
", gradMP=" + getGradientMidPoint() + ", gradCol1=" + getGradientStartColor() + ", gradCol2=" + getGradientEndColor() + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
2833
", bordPos=" + getBordersPosition() + ", blackDash=" + getBlackDashLength() + ", dotSep=" + getDotSep() + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
2834
", dbleSep=" + getDoubleSep() + ", hatchAngle=" + getHatchingAngle() + ", hatchSep=" + getHatchingSep() + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
2835
", hatchStyle=" + getHatchingStyle() + ", hatchWidth=" + getHatchingWidth() + ", lineStyle=" + getLineStyle() + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
2836
", rotAngle=" + getRotationAngle() + ", whiteDash=" + getWhiteDashLength() + ", gc=" + getGravityCenter() + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
2837
", isHatched=" + isHatched() + "]"; //$NON-NLS-1$ //$NON-NLS-2$