added missing definition of the upArrow shape, moved support for line decorations to XSLFSimpleShape

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1204477 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Yegor Kozlov 2011-11-21 13:10:14 +00:00
parent 12c58c96e3
commit 66b79be517
7 changed files with 313 additions and 311 deletions

View File

@ -51,6 +51,9 @@ public class PresetGeometries extends LinkedHashMap<String, CustomGeometry> {
String name = def.getDomNode().getLocalName(); String name = def.getDomNode().getLocalName();
CTCustomGeometry2D geom = CTCustomGeometry2D.Factory.parse(def.toString()); CTCustomGeometry2D geom = CTCustomGeometry2D.Factory.parse(def.toString());
if(containsKey(name)) {
System.out.println("Duplicate definoition of " + name) ;
}
put(name, new CustomGeometry(geom)); put(name, new CustomGeometry(geom));
} }
} }

View File

@ -120,7 +120,7 @@ class RenderableShape {
else if (obj instanceof CTGradientFillProperties) { else if (obj instanceof CTGradientFillProperties) {
CTGradientFillProperties gradFill = (CTGradientFillProperties) obj; CTGradientFillProperties gradFill = (CTGradientFillProperties) obj;
if (gradFill.isSetLin()) { if (gradFill.isSetLin()) {
paint = createLinearGradientPaint(gradFill, anchor, theme, phClr); paint = createLinearGradientPaint(graphics, gradFill, anchor, theme, phClr);
} else if (gradFill.isSetPath()){ } else if (gradFill.isSetPath()){
CTPathShadeProperties ps = gradFill.getPath(); CTPathShadeProperties ps = gradFill.getPath();
if(ps.getPath() == STPathShadeType.CIRCLE){ if(ps.getPath() == STPathShadeType.CIRCLE){
@ -166,6 +166,7 @@ class RenderableShape {
} }
private static Paint createLinearGradientPaint( private static Paint createLinearGradientPaint(
Graphics2D graphics,
CTGradientFillProperties gradFill, Rectangle2D anchor, CTGradientFillProperties gradFill, Rectangle2D anchor,
XSLFTheme theme, CTSchemeColor phClr) { XSLFTheme theme, CTSchemeColor phClr) {
double angle = gradFill.getLin().getAng() / 60000; double angle = gradFill.getLin().getAng() / 60000;
@ -204,13 +205,30 @@ class RenderableShape {
fractions[i] = stop.getPos() / 100000.f; fractions[i] = stop.getPos() / 100000.f;
} }
AffineTransform grAt;
if(gradFill.getRotWithShape()) grAt = new AffineTransform();
else {
// gradient fill is not rotated with the shape
try {
grAt = graphics.getTransform().createInverse();
} catch (Exception e){
// should not happen.
grAt = new AffineTransform();
}
}
// Trick to return GradientPaint on JDK 1.5 and LinearGradientPaint on JDK 1.6+ // Trick to return GradientPaint on JDK 1.5 and LinearGradientPaint on JDK 1.6+
Paint paint; Paint paint;
try { try {
Class clz = Class.forName("java.awt.LinearGradientPaint"); Class clz = Class.forName("java.awt.LinearGradientPaint");
Class clzCycleMethod = Class.forName("java.awt.MultipleGradientPaint$CycleMethod");
Class clzColorSpaceType = Class.forName("java.awt.MultipleGradientPaint$ColorSpaceType");
Constructor c = Constructor c =
clz.getConstructor(Point2D.class, Point2D.class, float[].class, Color[].class); clz.getConstructor(Point2D.class, Point2D.class, float[].class, Color[].class,
paint = (Paint) c.newInstance(p1, p2, fractions, colors); clzCycleMethod, clzColorSpaceType, AffineTransform.class);
paint = (Paint) c.newInstance(p1, p2, fractions, colors,
Enum.valueOf(clzCycleMethod, "NO_CYCLE"),
Enum.valueOf(clzColorSpaceType, "SRGB"), grAt);
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
paint = new GradientPaint(p1, colors[0], p2, colors[colors.length - 1]); paint = new GradientPaint(p1, colors[0], p2, colors[colors.length - 1]);
} catch (Exception e) { } catch (Exception e) {
@ -504,9 +522,12 @@ class RenderableShape {
} }
private Collection<Outline> computeOutlines() { private Collection<Outline> computeOutlines() {
CustomGeometry geom = _shape.getGeometry();
Collection<Outline> lst = new ArrayList<Outline>(); Collection<Outline> lst = new ArrayList<Outline>();
CustomGeometry geom = _shape.getGeometry();
if(geom == null) {
return lst;
}
Rectangle2D anchor = _shape.getAnchor(); Rectangle2D anchor = _shape.getAnchor();
for (Path p : geom) { for (Path p : geom) {

View File

@ -80,4 +80,9 @@ public class XSLFAutoShape extends XSLFTextShape {
} }
return txBody; return txBody;
} }
@Override
public String toString(){
return "[" + getClass().getSimpleName() + "] " + getShapeName();
}
} }

View File

@ -75,262 +75,6 @@ public class XSLFConnectorShape extends XSLFSimpleShape {
return ct; return ct;
} }
/**
* Specifies the line end decoration, such as a triangle or arrowhead.
*/
public void setLineHeadDecoration(LineDecoration style) {
CTLineProperties ln = getSpPr().getLn();
CTLineEndProperties lnEnd = ln.isSetHeadEnd() ? ln.getHeadEnd() : ln.addNewHeadEnd();
if (style == null) {
if (lnEnd.isSetType()) lnEnd.unsetType();
} else {
lnEnd.setType(STLineEndType.Enum.forInt(style.ordinal() + 1));
}
}
public LineDecoration getLineHeadDecoration() {
CTLineProperties ln = getSpPr().getLn();
if (ln == null || !ln.isSetHeadEnd()) return LineDecoration.NONE;
STLineEndType.Enum end = ln.getHeadEnd().getType();
return end == null ? LineDecoration.NONE : LineDecoration.values()[end.intValue() - 1];
}
/**
* specifies decorations which can be added to the head of a line.
*/
public void setLineHeadWidth(LineEndWidth style) {
CTLineProperties ln = getSpPr().getLn();
CTLineEndProperties lnEnd = ln.isSetHeadEnd() ? ln.getHeadEnd() : ln.addNewHeadEnd();
if (style == null) {
if (lnEnd.isSetW()) lnEnd.unsetW();
} else {
lnEnd.setW(STLineEndWidth.Enum.forInt(style.ordinal() + 1));
}
}
public LineEndWidth getLineHeadWidth() {
CTLineProperties ln = getSpPr().getLn();
if (ln == null || !ln.isSetHeadEnd()) return LineEndWidth.MEDIUM;
STLineEndWidth.Enum w = ln.getHeadEnd().getW();
return w == null ? LineEndWidth.MEDIUM : LineEndWidth.values()[w.intValue() - 1];
}
/**
* Specifies the line end width in relation to the line width.
*/
public void setLineHeadLength(LineEndLength style) {
CTLineProperties ln = getSpPr().getLn();
CTLineEndProperties lnEnd = ln.isSetHeadEnd() ? ln.getHeadEnd() : ln.addNewHeadEnd();
if (style == null) {
if (lnEnd.isSetLen()) lnEnd.unsetLen();
} else {
lnEnd.setLen(STLineEndLength.Enum.forInt(style.ordinal() + 1));
}
}
public LineEndLength getLineHeadLength() {
CTLineProperties ln = getSpPr().getLn();
if (ln == null || !ln.isSetHeadEnd()) return LineEndLength.MEDIUM;
STLineEndLength.Enum len = ln.getHeadEnd().getLen();
return len == null ? LineEndLength.MEDIUM : LineEndLength.values()[len.intValue() - 1];
}
/**
* Specifies the line end decoration, such as a triangle or arrowhead.
*/
public void setLineTailDecoration(LineDecoration style) {
CTLineProperties ln = getSpPr().getLn();
CTLineEndProperties lnEnd = ln.isSetTailEnd() ? ln.getTailEnd() : ln.addNewTailEnd();
if (style == null) {
if (lnEnd.isSetType()) lnEnd.unsetType();
} else {
lnEnd.setType(STLineEndType.Enum.forInt(style.ordinal() + 1));
}
}
public LineDecoration getLineTailDecoration() {
CTLineProperties ln = getSpPr().getLn();
if (ln == null || !ln.isSetTailEnd()) return LineDecoration.NONE;
STLineEndType.Enum end = ln.getTailEnd().getType();
return end == null ? LineDecoration.NONE : LineDecoration.values()[end.intValue() - 1];
}
/**
* specifies decorations which can be added to the tail of a line.
*/
public void setLineTailWidth(LineEndWidth style) {
CTLineProperties ln = getSpPr().getLn();
CTLineEndProperties lnEnd = ln.isSetTailEnd() ? ln.getTailEnd() : ln.addNewTailEnd();
if (style == null) {
if (lnEnd.isSetW()) lnEnd.unsetW();
} else {
lnEnd.setW(STLineEndWidth.Enum.forInt(style.ordinal() + 1));
}
}
public LineEndWidth getLineTailWidth() {
CTLineProperties ln = getSpPr().getLn();
if (ln == null || !ln.isSetTailEnd()) return LineEndWidth.MEDIUM;
STLineEndWidth.Enum w = ln.getTailEnd().getW();
return w == null ? LineEndWidth.MEDIUM : LineEndWidth.values()[w.intValue() - 1];
}
/**
* Specifies the line end width in relation to the line width.
*/
public void setLineTailLength(LineEndLength style) {
CTLineProperties ln = getSpPr().getLn();
CTLineEndProperties lnEnd = ln.isSetTailEnd() ? ln.getTailEnd() : ln.addNewTailEnd();
if (style == null) {
if (lnEnd.isSetLen()) lnEnd.unsetLen();
} else {
lnEnd.setLen(STLineEndLength.Enum.forInt(style.ordinal() + 1));
}
}
public LineEndLength getLineTailLength() {
CTLineProperties ln = getSpPr().getLn();
if (ln == null || !ln.isSetTailEnd()) return LineEndLength.MEDIUM;
STLineEndLength.Enum len = ln.getTailEnd().getLen();
return len == null ? LineEndLength.MEDIUM : LineEndLength.values()[len.intValue() - 1];
}
Outline getTailDecoration() {
LineEndLength tailLength = getLineTailLength();
LineEndWidth tailWidth = getLineTailWidth();
double lineWidth = Math.max(2.5, getLineWidth());
Rectangle2D anchor = getAnchor();
double x2 = anchor.getX() + anchor.getWidth(),
y2 = anchor.getY() + anchor.getHeight();
double alpha = Math.atan(anchor.getHeight() / anchor.getWidth());
AffineTransform at = new AffineTransform();
Shape shape = null;
Path p = null;
Rectangle2D bounds;
double scaleY = Math.pow(2, tailWidth.ordinal());
double scaleX = Math.pow(2, tailLength.ordinal());
switch (getLineTailDecoration()) {
case OVAL:
p = new Path();
shape = new Ellipse2D.Double(0, 0, lineWidth * scaleX, lineWidth * scaleY);
bounds = shape.getBounds2D();
at.translate(x2 - bounds.getWidth() / 2, y2 - bounds.getHeight() / 2);
at.rotate(alpha, bounds.getX() + bounds.getWidth() / 2, bounds.getY() + bounds.getHeight() / 2);
break;
case ARROW:
p = new Path();
GeneralPath arrow = new GeneralPath();
arrow.moveTo((float) (-lineWidth * 3), (float) (-lineWidth * 2));
arrow.lineTo(0, 0);
arrow.lineTo((float) (-lineWidth * 3), (float) (lineWidth * 2));
shape = arrow;
at.translate(x2, y2);
at.rotate(alpha);
break;
case TRIANGLE:
p = new Path();
scaleY = tailWidth.ordinal() + 1;
scaleX = tailLength.ordinal() + 1;
GeneralPath triangle = new GeneralPath();
triangle.moveTo((float) (-lineWidth * scaleX), (float) (-lineWidth * scaleY / 2));
triangle.lineTo(0, 0);
triangle.lineTo((float) (-lineWidth * scaleX), (float) (lineWidth * scaleY / 2));
triangle.closePath();
shape = triangle;
at.translate(x2, y2);
at.rotate(alpha);
break;
default:
break;
}
if (shape != null) {
shape = at.createTransformedShape(shape);
}
return shape == null ? null : new Outline(shape, p);
}
Outline getHeadDecoration() {
LineEndLength headLength = getLineHeadLength();
LineEndWidth headWidth = getLineHeadWidth();
double lineWidth = Math.max(2.5, getLineWidth());
Rectangle2D anchor = getAnchor();
double x1 = anchor.getX(),
y1 = anchor.getY();
double alpha = Math.atan(anchor.getHeight() / anchor.getWidth());
AffineTransform at = new AffineTransform();
Shape shape = null;
Path p = null;
Rectangle2D bounds;
double scaleY = 1;
double scaleX = 1;
switch (getLineHeadDecoration()) {
case OVAL:
p = new Path();
shape = new Ellipse2D.Double(0, 0, lineWidth * scaleX, lineWidth * scaleY);
bounds = shape.getBounds2D();
at.translate(x1 - bounds.getWidth() / 2, y1 - bounds.getHeight() / 2);
at.rotate(alpha, bounds.getX() + bounds.getWidth() / 2, bounds.getY() + bounds.getHeight() / 2);
break;
case STEALTH:
case ARROW:
p = new Path(false, true);
GeneralPath arrow = new GeneralPath();
arrow.moveTo((float) (lineWidth * 3 * scaleX), (float) (-lineWidth * scaleY * 2));
arrow.lineTo(0, 0);
arrow.lineTo((float) (lineWidth * 3 * scaleX), (float) (lineWidth * scaleY * 2));
shape = arrow;
at.translate(x1, y1);
at.rotate(alpha);
break;
case TRIANGLE:
p = new Path();
scaleY = headWidth.ordinal() + 1;
scaleX = headLength.ordinal() + 1;
GeneralPath triangle = new GeneralPath();
triangle.moveTo((float) (lineWidth * scaleX), (float) (-lineWidth * scaleY / 2));
triangle.lineTo(0, 0);
triangle.lineTo((float) (lineWidth * scaleX), (float) (lineWidth * scaleY / 2));
triangle.closePath();
shape = triangle;
at.translate(x1, y1);
at.rotate(alpha);
break;
default:
break;
}
if (shape != null) {
shape = at.createTransformedShape(shape);
}
return shape == null ? null : new Outline(shape, p);
}
private List<Outline> getDecorationOutlines(){
List<Outline> lst = new ArrayList<Outline>();
Outline head = getHeadDecoration();
if(head != null) lst.add(head);
Outline tail = getTailDecoration();
if(tail != null) lst.add(tail);
return lst;
}
/** /**
* YK: dashing of lines is suppressed for now. * YK: dashing of lines is suppressed for now.
@ -341,22 +85,4 @@ public class XSLFConnectorShape extends XSLFSimpleShape {
return null; return null;
} }
@Override
public void draw(Graphics2D graphics){
super.draw(graphics);
// draw line decorations
Color lineColor = getLineColor();
if(lineColor != null) {
graphics.setPaint(lineColor);
for(Outline o : getDecorationOutlines()){
if(o.getPath().isFilled()){
graphics.fill(o.getOutline());
}
if(o.getPath().isStroked()){
graphics.draw(o.getOutline());
}
}
}
}
} }

View File

@ -35,25 +35,7 @@ import org.apache.poi.openxml4j.opc.TargetMode;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.POIXMLException; import org.apache.poi.POIXMLException;
import org.apache.xmlbeans.XmlObject; import org.apache.xmlbeans.XmlObject;
import org.openxmlformats.schemas.drawingml.x2006.main.CTEffectStyleItem; import org.openxmlformats.schemas.drawingml.x2006.main.*;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGeomGuide;
import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTOuterShadowEffect;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetLineDashProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor;
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeStyle;
import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrix;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
import org.openxmlformats.schemas.drawingml.x2006.main.STLineCap;
import org.openxmlformats.schemas.drawingml.x2006.main.STPresetLineDashVal;
import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType;
import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip;
import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder; import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType; import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;
import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture; import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture;
@ -63,8 +45,10 @@ import java.awt.Graphics2D;
import java.awt.Paint; import java.awt.Paint;
import java.awt.Shape; import java.awt.Shape;
import java.awt.geom.AffineTransform; import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath; import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -555,6 +539,20 @@ public abstract class XSLFSimpleShape extends XSLFShape {
public void draw(Graphics2D graphics) { public void draw(Graphics2D graphics) {
RenderableShape rShape = new RenderableShape(this); RenderableShape rShape = new RenderableShape(this);
rShape.render(graphics); rShape.render(graphics);
// draw line decorations
Color lineColor = getLineColor();
if(lineColor != null) {
graphics.setPaint(lineColor);
for(Outline o : getDecorationOutlines()){
if(o.getPath().isFilled()){
graphics.fill(o.getOutline());
}
if(o.getPath().isStroked()){
graphics.draw(o.getOutline());
}
}
}
} }
@ -696,4 +694,262 @@ public abstract class XSLFSimpleShape extends XSLFShape {
} }
} }
/**
* Specifies the line end decoration, such as a triangle or arrowhead.
*/
public void setLineHeadDecoration(LineDecoration style) {
CTLineProperties ln = getSpPr().getLn();
CTLineEndProperties lnEnd = ln.isSetHeadEnd() ? ln.getHeadEnd() : ln.addNewHeadEnd();
if (style == null) {
if (lnEnd.isSetType()) lnEnd.unsetType();
} else {
lnEnd.setType(STLineEndType.Enum.forInt(style.ordinal() + 1));
}
}
public LineDecoration getLineHeadDecoration() {
CTLineProperties ln = getSpPr().getLn();
if (ln == null || !ln.isSetHeadEnd()) return LineDecoration.NONE;
STLineEndType.Enum end = ln.getHeadEnd().getType();
return end == null ? LineDecoration.NONE : LineDecoration.values()[end.intValue() - 1];
}
/**
* specifies decorations which can be added to the head of a line.
*/
public void setLineHeadWidth(LineEndWidth style) {
CTLineProperties ln = getSpPr().getLn();
CTLineEndProperties lnEnd = ln.isSetHeadEnd() ? ln.getHeadEnd() : ln.addNewHeadEnd();
if (style == null) {
if (lnEnd.isSetW()) lnEnd.unsetW();
} else {
lnEnd.setW(STLineEndWidth.Enum.forInt(style.ordinal() + 1));
}
}
public LineEndWidth getLineHeadWidth() {
CTLineProperties ln = getSpPr().getLn();
if (ln == null || !ln.isSetHeadEnd()) return LineEndWidth.MEDIUM;
STLineEndWidth.Enum w = ln.getHeadEnd().getW();
return w == null ? LineEndWidth.MEDIUM : LineEndWidth.values()[w.intValue() - 1];
}
/**
* Specifies the line end width in relation to the line width.
*/
public void setLineHeadLength(LineEndLength style) {
CTLineProperties ln = getSpPr().getLn();
CTLineEndProperties lnEnd = ln.isSetHeadEnd() ? ln.getHeadEnd() : ln.addNewHeadEnd();
if (style == null) {
if (lnEnd.isSetLen()) lnEnd.unsetLen();
} else {
lnEnd.setLen(STLineEndLength.Enum.forInt(style.ordinal() + 1));
}
}
public LineEndLength getLineHeadLength() {
CTLineProperties ln = getSpPr().getLn();
if (ln == null || !ln.isSetHeadEnd()) return LineEndLength.MEDIUM;
STLineEndLength.Enum len = ln.getHeadEnd().getLen();
return len == null ? LineEndLength.MEDIUM : LineEndLength.values()[len.intValue() - 1];
}
/**
* Specifies the line end decoration, such as a triangle or arrowhead.
*/
public void setLineTailDecoration(LineDecoration style) {
CTLineProperties ln = getSpPr().getLn();
CTLineEndProperties lnEnd = ln.isSetTailEnd() ? ln.getTailEnd() : ln.addNewTailEnd();
if (style == null) {
if (lnEnd.isSetType()) lnEnd.unsetType();
} else {
lnEnd.setType(STLineEndType.Enum.forInt(style.ordinal() + 1));
}
}
public LineDecoration getLineTailDecoration() {
CTLineProperties ln = getSpPr().getLn();
if (ln == null || !ln.isSetTailEnd()) return LineDecoration.NONE;
STLineEndType.Enum end = ln.getTailEnd().getType();
return end == null ? LineDecoration.NONE : LineDecoration.values()[end.intValue() - 1];
}
/**
* specifies decorations which can be added to the tail of a line.
*/
public void setLineTailWidth(LineEndWidth style) {
CTLineProperties ln = getSpPr().getLn();
CTLineEndProperties lnEnd = ln.isSetTailEnd() ? ln.getTailEnd() : ln.addNewTailEnd();
if (style == null) {
if (lnEnd.isSetW()) lnEnd.unsetW();
} else {
lnEnd.setW(STLineEndWidth.Enum.forInt(style.ordinal() + 1));
}
}
public LineEndWidth getLineTailWidth() {
CTLineProperties ln = getSpPr().getLn();
if (ln == null || !ln.isSetTailEnd()) return LineEndWidth.MEDIUM;
STLineEndWidth.Enum w = ln.getTailEnd().getW();
return w == null ? LineEndWidth.MEDIUM : LineEndWidth.values()[w.intValue() - 1];
}
/**
* Specifies the line end width in relation to the line width.
*/
public void setLineTailLength(LineEndLength style) {
CTLineProperties ln = getSpPr().getLn();
CTLineEndProperties lnEnd = ln.isSetTailEnd() ? ln.getTailEnd() : ln.addNewTailEnd();
if (style == null) {
if (lnEnd.isSetLen()) lnEnd.unsetLen();
} else {
lnEnd.setLen(STLineEndLength.Enum.forInt(style.ordinal() + 1));
}
}
public LineEndLength getLineTailLength() {
CTLineProperties ln = getSpPr().getLn();
if (ln == null || !ln.isSetTailEnd()) return LineEndLength.MEDIUM;
STLineEndLength.Enum len = ln.getTailEnd().getLen();
return len == null ? LineEndLength.MEDIUM : LineEndLength.values()[len.intValue() - 1];
}
Outline getTailDecoration() {
LineEndLength tailLength = getLineTailLength();
LineEndWidth tailWidth = getLineTailWidth();
double lineWidth = Math.max(2.5, getLineWidth());
Rectangle2D anchor = getAnchor();
double x2 = anchor.getX() + anchor.getWidth(),
y2 = anchor.getY() + anchor.getHeight();
double alpha = Math.atan(anchor.getHeight() / anchor.getWidth());
AffineTransform at = new AffineTransform();
Shape shape = null;
Path p = null;
Rectangle2D bounds;
double scaleY = Math.pow(2, tailWidth.ordinal());
double scaleX = Math.pow(2, tailLength.ordinal());
switch (getLineTailDecoration()) {
case OVAL:
p = new Path();
shape = new Ellipse2D.Double(0, 0, lineWidth * scaleX, lineWidth * scaleY);
bounds = shape.getBounds2D();
at.translate(x2 - bounds.getWidth() / 2, y2 - bounds.getHeight() / 2);
at.rotate(alpha, bounds.getX() + bounds.getWidth() / 2, bounds.getY() + bounds.getHeight() / 2);
break;
case ARROW:
p = new Path();
GeneralPath arrow = new GeneralPath();
arrow.moveTo((float) (-lineWidth * 3), (float) (-lineWidth * 2));
arrow.lineTo(0, 0);
arrow.lineTo((float) (-lineWidth * 3), (float) (lineWidth * 2));
shape = arrow;
at.translate(x2, y2);
at.rotate(alpha);
break;
case TRIANGLE:
p = new Path();
scaleY = tailWidth.ordinal() + 1;
scaleX = tailLength.ordinal() + 1;
GeneralPath triangle = new GeneralPath();
triangle.moveTo((float) (-lineWidth * scaleX), (float) (-lineWidth * scaleY / 2));
triangle.lineTo(0, 0);
triangle.lineTo((float) (-lineWidth * scaleX), (float) (lineWidth * scaleY / 2));
triangle.closePath();
shape = triangle;
at.translate(x2, y2);
at.rotate(alpha);
break;
default:
break;
}
if (shape != null) {
shape = at.createTransformedShape(shape);
}
return shape == null ? null : new Outline(shape, p);
}
Outline getHeadDecoration() {
LineEndLength headLength = getLineHeadLength();
LineEndWidth headWidth = getLineHeadWidth();
double lineWidth = Math.max(2.5, getLineWidth());
Rectangle2D anchor = getAnchor();
double x1 = anchor.getX(),
y1 = anchor.getY();
double alpha = Math.atan(anchor.getHeight() / anchor.getWidth());
AffineTransform at = new AffineTransform();
Shape shape = null;
Path p = null;
Rectangle2D bounds;
double scaleY = 1;
double scaleX = 1;
switch (getLineHeadDecoration()) {
case OVAL:
p = new Path();
shape = new Ellipse2D.Double(0, 0, lineWidth * scaleX, lineWidth * scaleY);
bounds = shape.getBounds2D();
at.translate(x1 - bounds.getWidth() / 2, y1 - bounds.getHeight() / 2);
at.rotate(alpha, bounds.getX() + bounds.getWidth() / 2, bounds.getY() + bounds.getHeight() / 2);
break;
case STEALTH:
case ARROW:
p = new Path(false, true);
GeneralPath arrow = new GeneralPath();
arrow.moveTo((float) (lineWidth * 3 * scaleX), (float) (-lineWidth * scaleY * 2));
arrow.lineTo(0, 0);
arrow.lineTo((float) (lineWidth * 3 * scaleX), (float) (lineWidth * scaleY * 2));
shape = arrow;
at.translate(x1, y1);
at.rotate(alpha);
break;
case TRIANGLE:
p = new Path();
scaleY = headWidth.ordinal() + 1;
scaleX = headLength.ordinal() + 1;
GeneralPath triangle = new GeneralPath();
triangle.moveTo((float) (lineWidth * scaleX), (float) (-lineWidth * scaleY / 2));
triangle.lineTo(0, 0);
triangle.lineTo((float) (lineWidth * scaleX), (float) (lineWidth * scaleY / 2));
triangle.closePath();
shape = triangle;
at.translate(x1, y1);
at.rotate(alpha);
break;
default:
break;
}
if (shape != null) {
shape = at.createTransformedShape(shape);
}
return shape == null ? null : new Outline(shape, p);
}
private List<Outline> getDecorationOutlines(){
List<Outline> lst = new ArrayList<Outline>();
Outline head = getHeadDecoration();
if(head != null) lst.add(head);
Outline tail = getTailDecoration();
if(tail != null) lst.add(tail);
return lst;
}
} }

View File

@ -39,7 +39,7 @@ public class TestPresetGeometries extends TestCase {
public void testRead(){ public void testRead(){
Map<String, CustomGeometry> shapes = PresetGeometries.getInstance(); Map<String, CustomGeometry> shapes = PresetGeometries.getInstance();
assertEquals(186, shapes.size()); assertEquals(187, shapes.size());
for(String name : shapes.keySet()) { for(String name : shapes.keySet()) {

View File

@ -18822,7 +18822,7 @@
</pathLst> </pathLst>
</upArrowCallout> </upArrowCallout>
<upDownArrow> <upArrow>
<avLst xmlns="http://schemas.openxmlformats.org/drawingml/2006/main"> <avLst xmlns="http://schemas.openxmlformats.org/drawingml/2006/main">
<gd name="adj1" fmla="val 50000" /> <gd name="adj1" fmla="val 50000" />
<gd name="adj2" fmla="val 50000" /> <gd name="adj2" fmla="val 50000" />
@ -18890,19 +18890,10 @@
<pt x="x2" y="y2" /> <pt x="x2" y="y2" />
</lnTo> </lnTo>
<lnTo> <lnTo>
<pt x="x2" y="y3" /> <pt x="x2" y="b" />
</lnTo> </lnTo>
<lnTo> <lnTo>
<pt x="r" y="y3" /> <pt x="x1" y="b" />
</lnTo>
<lnTo>
<pt x="hc" y="b" />
</lnTo>
<lnTo>
<pt x="l" y="y3" />
</lnTo>
<lnTo>
<pt x="x1" y="y3" />
</lnTo> </lnTo>
<lnTo> <lnTo>
<pt x="x1" y="y2" /> <pt x="x1" y="y2" />
@ -18910,7 +18901,7 @@
<close /> <close />
</path> </path>
</pathLst> </pathLst>
</upDownArrow> </upArrow>
<upDownArrow> <upDownArrow>
<avLst xmlns="http://schemas.openxmlformats.org/drawingml/2006/main"> <avLst xmlns="http://schemas.openxmlformats.org/drawingml/2006/main">
<gd name="adj1" fmla="val 50000" /> <gd name="adj1" fmla="val 50000" />