List of usage examples for java.awt.geom Rectangle2D.Double getWidth
public abstract double getWidth();
From source file:Main.java
public static boolean isPosible(Rectangle2D.Double r) { if ((r.getMaxX() > Integer.MAX_VALUE) || (r.getMaxY() > Integer.MAX_VALUE) || (r.getMinX() < Integer.MIN_VALUE) || (r.getMinY() < Integer.MIN_VALUE) || (r.getWidth() > Integer.MAX_VALUE) || (r.getHeight() > Integer.MAX_VALUE)) { return false; }//from w ww.j a va 2 s.co m return true; }
From source file:com.hp.autonomy.frontend.reports.powerpoint.PowerPointServiceImpl.java
/** * Utility function to compute bounds for a shape in PowerPoint coordinates, given the bounds of the original * free space available and a measure of the shape's height. * @param pageAnchor the available bounds in PowerPoint coordinates. * @param space the height of the shape. * @return the bounds for the shape.//from w w w . j a v a 2 s . c o m */ private static Rectangle2D.Double startingSpace(final Rectangle2D.Double pageAnchor, final double space) { return new Rectangle2D.Double(pageAnchor.getMinX(), pageAnchor.getMinY(), pageAnchor.getWidth(), space); }
From source file:com.hp.autonomy.frontend.reports.powerpoint.PowerPointServiceImpl.java
/** * Utility function to compute the bounds for the remaining space, given the bounds of the original * free space available and the amount of vertical height already taken. * @param pageAnchor the available bounds in PowerPoint coordinates. * @param usedSpace how much height is already taken. * @return the bounds for the remaining space under the used space. */// w w w . j av a 2 s . c o m private static Rectangle2D.Double remainingSpace(final Rectangle2D.Double pageAnchor, final double usedSpace) { return new Rectangle2D.Double(pageAnchor.getMinX(), pageAnchor.getMinY() + usedSpace, pageAnchor.getWidth(), Math.max(1, pageAnchor.getHeight() - usedSpace)); }
From source file:com.hp.autonomy.frontend.reports.powerpoint.PowerPointServiceImpl.java
/** * Internal implementation to add a table to a slide. * @param slide the slide to add to./* w ww . ja v a 2 s .c o m*/ * @param anchor bounding rectangle to draw onto, in PowerPoint coordinates. * @param rows number of rows. * @param cols number of columns. * @param data the data for each cell, laid out row-by-row. * @param crop whether we should try and crop the table to the bounding rectangle by removing extra rows. * This doesn't guarantee an exact match, since the font metrics may not exactly match. */ private static void addTable(final XSLFSlide slide, final Rectangle2D.Double anchor, final int rows, final int cols, final String[] data, final boolean crop) { final XSLFTable table = slide.createTable(rows, cols); int idx = 0; double availWidth = anchor.getWidth(); double tableW = 0; if (cols == 2) { // In the most common situation, there's a count column which should be relatively smaller. // Make it take 10%, or 70 pixels, whichever is bigger, unless that's more than 50% of the overall space. final double minCountWidth = 70; final double countColWidth = Math.min(0.5 * availWidth, Math.max(minCountWidth, availWidth * 0.1)); table.setColumnWidth(0, availWidth - countColWidth); table.setColumnWidth(1, countColWidth); tableW += table.getColumnWidth(0); tableW += table.getColumnWidth(1); } else { for (int col = 0; col < cols; ++col) { table.setColumnWidth(col, availWidth / cols); tableW += table.getColumnWidth(col); } } // PowerPoint won't auto-shrink the table for you; and the POI API can't calculate the heights, so we just // have to assume the total row heights add up to be the table height. double tableH = 0; for (int row = 0; row < rows; ++row) { for (int col = 0; col < cols; ++col) { final XSLFTableCell cell = table.getCell(row, col); cell.setText(data[idx++]); for (final TableCell.BorderEdge edge : TableCell.BorderEdge.values()) { cell.setBorderColor(edge, Color.BLACK); } } final double nextH = tableH + table.getRowHeight(row); if (crop && nextH > anchor.getHeight() && row < rows - 1) { // If it doesn't fit, merge all the final row cells together and label them with an ellipsis. table.mergeCells(row, row, 0, cols - 1); table.getCell(row, 0).setText("\u2026"); break; } else { tableH = nextH; } } final double width = Math.min(tableW, availWidth); table.setAnchor(new Rectangle2D.Double(anchor.getMinX() + 0.5 * (availWidth - width), anchor.getMinY(), width, Math.min(tableH, anchor.getHeight()))); }
From source file:com.hp.autonomy.frontend.reports.powerpoint.PowerPointServiceImpl.java
/** * Internal implementation to add an image (a world map, though other image data is also fine) to a slide. * Preserves the original image's aspect ratio, leaving blank space below and to the sides of the image. * @param slide the slide to add to.// www. j a v a 2 s .c o m * @param anchor bounding rectangle to draw onto, in PowerPoint coordinates. * @param picture the picture data. * @param markers an array of markers to draw over the map. * @param polygons * @return the picture shape object added to the slide. */ private static XSLFPictureShape addMap(final XSLFSlide slide, final Rectangle2D.Double anchor, final XSLFPictureData picture, final Marker[] markers, final MapData.Polygon[] polygons) { double tgtW = anchor.getWidth(), tgtH = anchor.getHeight(); final Dimension size = picture.getImageDimension(); final double ratio = size.getWidth() / size.getHeight(); if (ratio > tgtW / tgtH) { // source image is wider than target, clip fixed width variable height tgtH = tgtW / ratio; } else { tgtW = tgtH * ratio; } final XSLFPictureShape canvas = slide.createPicture(picture); // Vertically align top, horizontally-align center final double offsetX = anchor.getMinX() + 0.5 * (anchor.getWidth() - tgtW), offsetY = anchor.getMinY(); canvas.setAnchor(new Rectangle2D.Double(offsetX, offsetY, tgtW, tgtH)); if (polygons != null) { for (MapData.Polygon polygon : polygons) { final Color color = Color.decode(polygon.getColor()); final double[][] shapes = polygon.getPoints(); // The ESRI spec version 1.2.1 from http://www.opengeospatial.org/standards/sfa has section 6.1.11.1, // which defines polygons as follows: /// A Polygon is a planar Surface defined by 1 exterior boundary and 0 or more interior boundaries. // Each interior boundary defines a hole in the Polygon. A Triangle is a polygon with 3 distinct, // non-collinear vertices and no interior boundary. /// The exterior boundary LinearRing defines the top? of the surface which is the side of the surface // from which the exterior boundary appears to traverse the boundary in a counter clockwise direction. // The interior LinearRings will have the opposite orientation, and appear as clockwise // when viewed from the top? // so it's even-odd winding (whereas the Path2D default is non-zero-winding). final Path2D.Double path = new Path2D.Double(Path2D.WIND_EVEN_ODD); for (final double[] points : shapes) { for (int ii = 0; ii < points.length; ii += 2) { final double x1 = offsetX + points[ii] * tgtW; final double y1 = offsetY + points[ii + 1] * tgtH; if (ii == 0) { path.moveTo(x1, y1); } else { path.lineTo(x1, y1); } } path.closePath(); } final XSLFFreeformShape freeform = slide.createFreeform(); freeform.setPath(path); freeform.setStrokeStyle(0.5); // There's a 0.5 alpha transparency on the stroke, and a 0.2 alpha transparency on the polygon fill. freeform.setLineColor(transparentColor(color, 128)); freeform.setFillColor(transparentColor(color, 51)); if (StringUtils.isNotEmpty(polygon.getText())) { final PackageRelationship rel = freeform.getSheet().getPackagePart().addRelationship( slide.getPackagePart().getPartName(), TargetMode.INTERNAL, XSLFRelation.SLIDE.getRelation()); // We create a hyperlink which links back to this slide; so we get hover-over-detail-text on the polygon final CTHyperlink link = ((CTShape) freeform.getXmlObject()).getNvSpPr().getCNvPr() .addNewHlinkClick(); link.setTooltip(polygon.getText()); link.setId(rel.getId()); link.setAction("ppaction://hlinksldjump"); } } } for (Marker marker : markers) { final Color color = Color.decode(marker.getColor()); final double centerX = offsetX + marker.getX() * tgtW; final double centerY = offsetY + marker.getY() * tgtH; if (marker.isCluster()) { final XSLFGroupShape group = slide.createGroup(); double halfMark = 10; double mark = halfMark * 2; double innerHalfMark = 7; double innerMark = innerHalfMark * 2; // align these so the middle is the latlng position final Rectangle2D.Double groupAnchor = new Rectangle2D.Double(centerX - halfMark, centerY - halfMark, mark, mark); group.setAnchor(groupAnchor); group.setInteriorAnchor(groupAnchor); final XSLFAutoShape shape = group.createAutoShape(); shape.setShapeType(ShapeType.ELLIPSE); final boolean fade = marker.isFade(); // There's a 0.3 alpha transparency (255 * 0.3 is 76) when a marker is faded out final int FADE_ALPHA = 76; shape.setFillColor(transparentColor(color, fade ? 47 : 154)); shape.setAnchor(groupAnchor); final XSLFAutoShape inner = group.createAutoShape(); inner.setFillColor(fade ? transparentColor(color, FADE_ALPHA) : color); inner.setLineWidth(0.1); inner.setLineColor(new Color((int) (color.getRed() * 0.9), (int) (color.getGreen() * 0.9), (int) (color.getBlue() * 0.9), fade ? FADE_ALPHA : 255)); inner.setShapeType(ShapeType.ELLIPSE); inner.setHorizontalCentered(true); inner.setWordWrap(false); inner.setVerticalAlignment(VerticalAlignment.MIDDLE); inner.clearText(); final XSLFTextParagraph para = inner.addNewTextParagraph(); para.setTextAlign(TextParagraph.TextAlign.CENTER); final XSLFTextRun text = para.addNewTextRun(); text.setFontSize(6.0); final Color fontColor = Color.decode(StringUtils.defaultString(marker.getFontColor(), "#000000")); text.setFontColor(fade ? transparentColor(fontColor, FADE_ALPHA) : fontColor); text.setText(marker.getText()); inner.setAnchor(new Rectangle2D.Double(centerX - innerHalfMark, centerY - innerHalfMark, innerMark, innerMark)); } else { final XSLFGroupShape group = slide.createGroup(); final XSLFFreeformShape shape = group.createFreeform(); shape.setHorizontalCentered(true); shape.setWordWrap(false); shape.setVerticalAlignment(VerticalAlignment.BOTTOM); shape.setLineWidth(0.5); shape.setLineColor(color.darker()); shape.setFillColor(transparentColor(color, 210)); final double halfMark = 8, mark = halfMark * 2, extension = 0.85, markerHeight = (0.5 + extension) * mark, angle = Math.asin(0.5 / extension) * 180 / Math.PI; // Set group position group.setAnchor( new Rectangle2D.Double(centerX - halfMark, centerY - markerHeight, mark, markerHeight)); group.setInteriorAnchor(new Rectangle2D.Double(0, 0, mark, markerHeight)); // Draw a semicircle and a triangle to represent the marker, pointing at the precise x,y location final Path2D.Double path = new Path2D.Double(); path.moveTo(halfMark, markerHeight); path.append(new Arc2D.Double(0, 0, mark, mark, -angle, 180 + angle + angle, Arc2D.OPEN), true); path.lineTo(halfMark, markerHeight); shape.setPath(path); shape.setAnchor(new Rectangle2D.Double(0, 0, mark, markerHeight)); final XSLFAutoShape disc = group.createAutoShape(); disc.setShapeType(ShapeType.DONUT); final double discRadius = 0.25 * mark; final double discDiameter = 2 * discRadius; disc.setAnchor(new Rectangle2D.Double(halfMark - discRadius, halfMark - discRadius, discDiameter, discDiameter)); disc.setFillColor(Color.WHITE); disc.setLineColor(Color.WHITE); if (StringUtils.isNotEmpty(marker.getText())) { final PackageRelationship rel = shape.getSheet().getPackagePart().addRelationship( slide.getPackagePart().getPartName(), TargetMode.INTERNAL, XSLFRelation.SLIDE.getRelation()); // We create a hyperlink which links back to this slide; so we get hover-over-detail-text on the marker // Annoyingly, you can't put a link on the group, just on the individual shapes. for (XSLFShape clickable : group.getShapes()) { final CTHyperlink link = ((CTShape) clickable.getXmlObject()).getNvSpPr().getCNvPr() .addNewHlinkClick(); link.setTooltip(marker.getText()); link.setId(rel.getId()); link.setAction("ppaction://hlinksldjump"); } } } } return canvas; }
From source file:com.hp.autonomy.frontend.reports.powerpoint.PowerPointServiceImpl.java
/** * Internal implementation to add a topic map to a slide. * @param slide the slide to add to./*w w w . java 2 s . c o m*/ * @param anchor bounding rectangle to draw onto, in PowerPoint coordinates. * @param data the topic map data. */ private static void addTopicMap(final XSLFSlide slide, final Rectangle2D.Double anchor, final TopicMapData data) { for (final TopicMapData.Path reqPath : data.getPaths()) { final XSLFFreeformShape shape = slide.createFreeform(); final Path2D.Double path = new Path2D.Double(); boolean first = true; for (double[] point : reqPath.getPoints()) { final double x = point[0] * anchor.getWidth() + anchor.getMinX(); final double y = point[1] * anchor.getHeight() + anchor.getMinY(); if (first) { path.moveTo(x, y); first = false; } else { path.lineTo(x, y); } } path.closePath(); shape.setPath(path); shape.setStrokeStyle(2); shape.setLineColor(Color.GRAY); shape.setHorizontalCentered(true); shape.setVerticalAlignment(VerticalAlignment.MIDDLE); shape.setTextAutofit(TextShape.TextAutofit.NORMAL); final XSLFTextParagraph text = shape.addNewTextParagraph(); final XSLFTextRun textRun = text.addNewTextRun(); textRun.setText(reqPath.name); textRun.setFontColor(Color.WHITE); textRun.setBold(true); final CTShape cs = (CTShape) shape.getXmlObject(); double max = 100, min = 1, scale = 100; final CTTextNormalAutofit autoFit = cs.getTxBody().getBodyPr().getNormAutofit(); final double availHeight = path.getBounds2D().getHeight(); final int RESIZE_ATTEMPTS = 7; for (int attempts = 0; attempts < RESIZE_ATTEMPTS; ++attempts) { // PowerPoint doesn't resize the text till you edit it once, which means the text initially looks too // large when you first view the slide; so we binary-chop to get a sensible initial approximation. // OpenOffice does the text resize on load so it doesn't have this problem. autoFit.setFontScale(Math.max(1, (int) (scale * 1000))); final double textHeight = shape.getTextHeight(); if (textHeight < availHeight) { min = scale; scale = 0.5 * (min + max); } else if (textHeight > availHeight) { max = scale; scale = 0.5 * (min + max); } else { break; } } final int opacity = (int) (100000 * reqPath.getOpacity()); final Color c1 = Color.decode(reqPath.getColor()); final Color c2 = Color.decode(reqPath.getColor2()); final CTGradientFillProperties gFill = cs.getSpPr().addNewGradFill(); gFill.addNewLin().setAng(3300000); final CTGradientStopList list = gFill.addNewGsLst(); final CTGradientStop stop1 = list.addNewGs(); stop1.setPos(0); final CTSRgbColor color1 = stop1.addNewSrgbClr(); color1.setVal(new byte[] { (byte) c1.getRed(), (byte) c1.getGreen(), (byte) c1.getBlue() }); color1.addNewAlpha().setVal(opacity); final CTGradientStop stop2 = list.addNewGs(); stop2.setPos(100000); final CTSRgbColor color2 = stop2.addNewSrgbClr(); color2.setVal(new byte[] { (byte) c2.getRed(), (byte) c2.getGreen(), (byte) c2.getBlue() }); color2.addNewAlpha().setVal(opacity); if (reqPath.level > 0) { // The nodes which aren't leaf nodes can be clicked on to hide them so you can see the nodes underneath. // This only works in PowerPoint; OpenOffice doesn't seem to support it. OpenOffice has its own syntax // to do something similar, but we don't use it since PowerPoint treats it as corrupt. final String shapeId = Integer.toString(shape.getShapeId()); final CTSlide slXML = slide.getXmlObject(); final CTTimeNodeList childTnLst; final CTBuildList bldLst; if (!slXML.isSetTiming()) { final CTSlideTiming timing = slXML.addNewTiming(); final CTTLCommonTimeNodeData ctn = timing.addNewTnLst().addNewPar().addNewCTn(); ctn.setDur("indefinite"); ctn.setRestart(STTLTimeNodeRestartTypeImpl.NEVER); ctn.setNodeType(STTLTimeNodeType.TM_ROOT); childTnLst = ctn.addNewChildTnLst(); bldLst = timing.addNewBldLst(); } else { final CTSlideTiming timing = slXML.getTiming(); childTnLst = timing.getTnLst().getParArray(0).getCTn().getChildTnLst(); bldLst = timing.getBldLst(); } final CTTLTimeNodeSequence seq = childTnLst.addNewSeq(); seq.setConcurrent(true); seq.setNextAc(STTLNextActionType.SEEK); final CTTLCommonTimeNodeData common = seq.addNewCTn(); common.setRestart(STTLTimeNodeRestartType.WHEN_NOT_ACTIVE); common.setFill(STTLTimeNodeFillType.HOLD); common.setEvtFilter("cancelBubble"); common.setNodeType(STTLTimeNodeType.INTERACTIVE_SEQ); final CTTLTimeConditionList condList = common.addNewStCondLst(); final CTTLTimeCondition cond = condList.addNewCond(); cond.setEvt(STTLTriggerEvent.ON_CLICK); cond.setDelay(0); cond.addNewTgtEl().addNewSpTgt().setSpid(shapeId); final CTTLTimeCondition endSync = common.addNewEndSync(); endSync.setEvt(STTLTriggerEvent.END); endSync.setDelay(0); endSync.addNewRtn().setVal(STTLTriggerRuntimeNode.ALL); // These holdCtn* 'hold' transitions with zero delay might seem redundant; but they're exported in the // PowerPoint XML, and the online PowerPoint Office365 viewer won't support the click animations // unless they're present (e.g. from the 'Start Slide Show' button in the browser). final CTTLCommonTimeNodeData holdCtn1 = common.addNewChildTnLst().addNewPar().addNewCTn(); holdCtn1.setFill(STTLTimeNodeFillType.HOLD); holdCtn1.addNewStCondLst().addNewCond().setDelay(0); final CTTLCommonTimeNodeData holdCtn2 = holdCtn1.addNewChildTnLst().addNewPar().addNewCTn(); holdCtn2.setFill(STTLTimeNodeFillType.HOLD); holdCtn2.addNewStCondLst().addNewCond().setDelay(0); final CTTLCommonTimeNodeData clickCtn = holdCtn2.addNewChildTnLst().addNewPar().addNewCTn(); clickCtn.setPresetID(10); clickCtn.setPresetClass(STTLTimeNodePresetClassType.EXIT); clickCtn.setPresetSubtype(0); clickCtn.setFill(STTLTimeNodeFillType.HOLD); clickCtn.setGrpId(0); clickCtn.setNodeType(STTLTimeNodeType.CLICK_EFFECT); clickCtn.addNewStCondLst().addNewCond().setDelay(0); final CTTimeNodeList clickChildTnList = clickCtn.addNewChildTnLst(); final CTTLAnimateEffectBehavior animEffect = clickChildTnList.addNewAnimEffect(); animEffect.setTransition(STTLAnimateEffectTransition.OUT); animEffect.setFilter("fade"); final CTTLCommonBehaviorData cBhvr = animEffect.addNewCBhvr(); final CTTLCommonTimeNodeData bhvrCtn = cBhvr.addNewCTn(); bhvrCtn.setDur(500); cBhvr.addNewTgtEl().addNewSpTgt().setSpid(shapeId); final CTTLSetBehavior clickSet = clickChildTnList.addNewSet(); final CTTLCommonBehaviorData clickSetBhvr = clickSet.addNewCBhvr(); final CTTLCommonTimeNodeData hideCtn = clickSetBhvr.addNewCTn(); hideCtn.setDur(1); hideCtn.setFill(STTLTimeNodeFillType.HOLD); hideCtn.addNewStCondLst().addNewCond().setDelay(499); clickSetBhvr.addNewTgtEl().addNewSpTgt().setSpid(shapeId); clickSetBhvr.addNewAttrNameLst().addAttrName("style.visibility"); clickSet.addNewTo().addNewStrVal().setVal("hidden"); final CTTLBuildParagraph bldP = bldLst.addNewBldP(); bldP.setSpid(shapeId); bldP.setGrpId(0); bldP.setAnimBg(true); } } }
From source file:com.hp.autonomy.frontend.reports.powerpoint.PowerPointServiceImpl.java
@Override public XMLSlideShow report(final ReportData report, final boolean slidePerVisualizer) throws TemplateLoadException { final SlideShowTemplate template = loadTemplate(); final XMLSlideShow ppt = template.getSlideShow(); final Rectangle2D.Double pageAnchor = createPageAnchor(ppt); double width = pageAnchor.getWidth(); double height = pageAnchor.getHeight(); if (!slidePerVisualizer) { // If drawing multiple visualizations on a single slide, we need to render the charts first since adding // chart objects directly via XML after calling slide.getShapes() or createShape() etc. will break things. Arrays.sort(report.getChildren(), Comparator.comparingInt(PowerPointServiceImpl::prioritizeCharts)); }/*from ww w.j a v a 2s . c om*/ // As above, we need to have a separate slide to place our sizing textbox for calculations. XSLFSlide sizingSlide = ppt.createSlide(); // This is the slide to draw on. XSLFSlide slide = ppt.createSlide(); int shapeId = 1; boolean first = true; for (final ReportData.Child child : report.getChildren()) { if (slidePerVisualizer && !first) { sizingSlide = ppt.createSlide(); slide = ppt.createSlide(); } first = false; final ComposableElement data = child.getData(); final Rectangle2D.Double anchor = new Rectangle2D.Double(pageAnchor.getMinX() + width * child.getX(), pageAnchor.getMinY() + height * child.getY(), width * child.getWidth(), height * child.getHeight()); if (child.getMargin() >= 0) { final double margin = child.getMargin(); final double marginX2 = margin * 2; final double textMargin = child.getTextMargin(); if (anchor.getWidth() > marginX2) { double xCursor = anchor.getMinX() + margin, xWidthAvail = anchor.getWidth() - marginX2, yCursor = anchor.getMinY() + margin, yHeightAvail = anchor.getHeight() - marginX2; XSLFTextBox sizingBox = null; final String title = child.getTitle(); if (StringUtils.isNotEmpty(title) && yHeightAvail > 0) { sizingBox = sizingSlide.createTextBox(); final Rectangle2D.Double sizingAnchor = new Rectangle2D.Double(xCursor, yCursor, xWidthAvail, yHeightAvail); sizingBox.setAnchor(sizingAnchor); sizingBox.clearText(); addTextRun(sizingBox.addNewTextParagraph(), title, child.getFontSize(), Color.BLACK) .setFontFamily(child.getFontFamily()); final double textHeight = sizingBox.getTextHeight() + textMargin; yCursor += textHeight; yHeightAvail -= textHeight; } if (yHeightAvail > 0) { anchor.setRect(xCursor, yCursor, xWidthAvail, yHeightAvail); } else if (sizingBox != null) { sizingSlide.removeShape(sizingBox); } } } if (data instanceof DategraphData) { addDategraph(template, slide, anchor, (DategraphData) data, shapeId, "relId" + shapeId); shapeId++; } else if (data instanceof ListData) { final ListData listData = (ListData) data; addList(imageSource, ppt, slide, anchor, false, listData, null, null); } else if (data instanceof MapData) { final MapData mapData = (MapData) data; addMap(slide, anchor, addPictureData(imageSource, ppt, mapData.getImage()), mapData.getMarkers(), mapData.getPolygons()); } else if (data instanceof SunburstData) { addSunburst(template, slide, anchor, (SunburstData) data, shapeId, "relId" + shapeId); shapeId++; } else if (data instanceof TableData) { final TableData tableData = (TableData) data; addTable(slide, anchor, tableData.getRows(), tableData.getCols(), tableData.getCells(), true); } else if (data instanceof TopicMapData) { addTopicMap(slide, anchor, (TopicMapData) data); } else if (data instanceof TextData) { addTextData(slide, anchor, (TextData) data); } if (slidePerVisualizer) { transferSizedTextboxes(ppt, slide, sizingSlide); } } if (!slidePerVisualizer) { transferSizedTextboxes(ppt, slide, sizingSlide); } return ppt; }
From source file:com.hp.autonomy.frontend.reports.powerpoint.SlideShowTemplate.java
/** * Utility function to clone the graphical object which represents a chart on a slide. * @param base the object to clone.//from w ww . j a v a 2s .c o m * @param relId the new relation ID we should insert. * @param shapeId the new shape ID we should insert. * @param shapeName the new shape name we should insert. * @param anchor the bounds of the new shape object in PowerPoint coordinates, if set, or null to use the existing clone's bounds. * @return a new clone object with the desired properties. */ private CTGraphicalObjectFrame cloneShapeXML(final CTGraphicalObjectFrame base, final String relId, final int shapeId, final String shapeName, final Rectangle2D.Double anchor) { /* Based on viewing the raw chart. <p:graphicFrame> <p:nvGraphicFramePr> <p:cNvPr id="4" name="Chart 3"/> <p:cNvGraphicFramePr/> <p:nvPr> <p:extLst> <p:ext uri="{D42A27DB-BD31-4B8C-83A1-F6EECF244321}"> <p14:modId xmlns:p14="http://schemas.microsoft.com/office/powerpoint/2010/main" val="866141002"/> </p:ext> </p:extLst> </p:nvPr> </p:nvGraphicFramePr> <p:xfrm> <a:off x="0" y="0"/> <a:ext cx="12192000" cy="6858000"/> </p:xfrm> <a:graphic> <a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/chart"> <c:chart xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" r:id="rId2"/> </a:graphicData> </a:graphic> </p:graphicFrame> */ final CTGraphicalObjectFrame copy = (CTGraphicalObjectFrame) base.copy(); final CTNonVisualDrawingProps cNvPr = copy.getNvGraphicFramePr().getCNvPr(); cNvPr.setName(shapeName); cNvPr.setId(shapeId); final XmlObject[] children = copy.getGraphic().getGraphicData() .selectChildren(new QName(XSSFRelation.NS_CHART, "chart")); if (anchor != null) { final CTPoint2D off = copy.getXfrm().getOff(); off.setX((int) (anchor.getX() * EMU_PER_POINT)); off.setY((int) (anchor.getY() * EMU_PER_POINT)); final CTPositiveSize2D ext = copy.getXfrm().getExt(); ext.setCx((int) (anchor.getWidth() * EMU_PER_POINT)); ext.setCy((int) (anchor.getHeight() * EMU_PER_POINT)); } for (final XmlObject child : children) { child.getDomNode().getAttributes().getNamedItemNS(RELATION_NAMESPACE, "id").setNodeValue(relId); } return copy; }