2

Recently i am working with Apache POI with Spring Boot and i am facing an issue. I want to represent database connections between entities, and i have a problem with visualizing multiple connections.
So the basic problem of mine is separating connections.

Here is my starting: 1

You can't see but there is multiple connections between this two rectangles, but because of the same start and end point, they are uncover each others.

The generated XML-code is the following:

<p:cxnSp>
   <p:nvCxnSpPr>
       <p:cNvPr name="Connector 7" id="7" />
       <p:cNvCxnSpPr>
           <a:stCxn id="2" idx="3" />
           <a:endCxn id="3" idx="1" />
       </p:cNvCxnSpPr>
       <p:nvPr />
   </p:nvCxnSpPr>
   <p:spPr>
       <a:xfrm flipV="1">
           <a:off y="2199409" x="2616200" />
           <a:ext cy="1318491" cx="2413000" />
       </a:xfrm>
       <a:prstGeom prst="curvedConnector3">
           <a:avLst />
       </a:prstGeom>
       <a:ln w="9525">
           <a:solidFill>
               <a:srgbClr val="000000" />
           </a:solidFill>
       </a:ln>
   </p:spPr>
</p:cxnSp> 

So what i want to do is set the curved conectors midpoint in a different values, like in this image (i do this manually for the example): 2

I try to add some other GeomGuide element to the connector but the result is an unstable pptx file with this:

<a:prstGeom prst="curvedConnector3">
    <a:avLst>
        <a:gd name="adj1" fmla="val 57365" />
    </a:avLst>
</a:prstGeom>

Relevant java code snippet for this:

XSLFConnectorShape connector1 = slide.createConnector();
CTNonVisualConnectorProperties cx = ctConnector.getNvCxnSpPr().getCNvCxnSpPr();
        CTConnection start = cx.addNewStCxn();
        start.setId(shapeIdStart);
        start.setIdx(rel.getStartSide());

        CTConnection end = cx.addNewEndCxn();
        end.setId(shapeIdEnd);
        end.setIdx(rel.getEndSide());


         CTGeomGuideList ctGeomGuideList = ctConnector.getSpPr().getPrstGeom().getAvLst();
         CTGeomGuide ctGeomGuide = ctGeomGuideList.addNewGd();
         ctGeomGuide.setName("adj");
         ctGeomGuide.setFmla("val 45000");

Lorin
  • 21
  • 3
  • Not provided a [Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example), so no answer possible. But I guess it would must be `ctGeomGuide.setName("adj1");`. – Axel Richter Mar 04 '21 at 19:34
  • Thanks, i didn't write this but i tried with this param name and still didin't work. I will update my answer to be reproducible. – Lorin Mar 05 '21 at 06:38
  • Please [edit] your question: provide the complete code (properly formatted) and clarify your current issue. We need to see what is missing to your goal. Means `set the curved connectors midpoint in a different values` you want 2 curves that are both having same connection-points to the 2 rectangles, but __with different ["curvatures"](https://www.csegrecorder.com/assets/images/articles/2007-11-seismic-curvature-fig01.jpg)__ = one is positive and bending upwards, the other negative and bending downwards. Isn't this issue related to the _formula_ set with `fmla` attribute ? – hc_dev Mar 05 '21 at 07:37

1 Answers1

1

Your provided code snippet is not complete. So it is not clear whether this is the one and only problem. But ctGeomGuide.setName("adj"); is wrong in any case. The adjust handles are numbered and there is no adjust handle called adj only. It would must be ctGeomGuide.setName("adj1");.

Folowing code is a Minimal, Reproducible Example which works and creates your wanted result.

import java.io.FileOutputStream;

import org.apache.poi.xslf.usermodel.*;
import org.apache.poi.sl.usermodel.*;
import org.openxmlformats.schemas.presentationml.x2006.main.*;
import org.openxmlformats.schemas.drawingml.x2006.main.*;

import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.awt.Color;

public class CreatePPTXConnectorShapes {
    
 private static XSLFConnectorShape createConnector(XSLFSlide slide, XSLFAutoShape shape1, XSLFAutoShape shape2) {
  XSLFConnectorShape connector = slide.createConnector();
  connector.setShapeType(ShapeType.CURVED_CONNECTOR_3);
  connector.setAnchor(new Rectangle2D.Double( //connector is diagonal in a rectangle
   shape1.getAnchor().getMaxX(), // top left x of that rectangle is x position of right edge of shape1
   shape2.getAnchor().getCenterY(), // top left y of that rectangle is center y of shape2 as shape2 is above shape1
   shape2.getAnchor().getX()-shape1.getAnchor().getMaxX(), // width of that rectanle is x of shape2 minus x position of right edge of shape1 as shape2 is right of shape1
   shape1.getAnchor().getCenterY()-shape2.getAnchor().getCenterY() // height of that rectanle is center y of shape1 minus center y of shape2 as shape2 is above shape1
   ));
  connector.setFlipVertical(true); // the rectangle needs to be flipped vertically as the connector shall be diagonal from bottom left to top right

  CTConnector ctConnector = (CTConnector)connector.getXmlObject();
  CTNonVisualConnectorProperties cx = ctConnector.getNvCxnSpPr().getCNvCxnSpPr();
  CTConnection start = cx.addNewStCxn();
  start.setId(shape1.getShapeId());
  start.setIdx(3); // connecting point 3 is center of right edge
  CTConnection end = cx.addNewEndCxn();
  end.setId(shape2.getShapeId());
  end.setIdx(1); // connecting point 1 is center of left edge
  return connector;  
 }

 public static void main(String[] args) throws Exception {

  XMLSlideShow slideShow = new XMLSlideShow();

  XSLFSlide slide = slideShow.createSlide();

  XSLFAutoShape shape1 = slide.createAutoShape();
  shape1.setShapeType(ShapeType.RECT);
  shape1.setFillColor(Color.GREEN);
  shape1.setAnchor(new Rectangle(50, 150, 150, 100));
  
  XSLFAutoShape shape2 = slide.createAutoShape();
  shape2.setShapeType(ShapeType.RECT);
  shape2.setFillColor(Color.GREEN);
  shape2.setAnchor(new Rectangle(500, 50, 150, 100));
  
  // first connector 
  XSLFConnectorShape connector1 = createConnector(slide, shape1, shape2);
  CTConnector ctConnector = (CTConnector)connector1.getXmlObject(); 
  CTGeomGuideList ctGeomGuideList = ctConnector.getSpPr().getPrstGeom().getAvLst();
  CTGeomGuide ctGeomGuide = ctGeomGuideList.addNewGd();
  ctGeomGuide.setName("adj1");
  ctGeomGuide.setFmla("val 45000");
  
  //second connector
  XSLFConnectorShape connector2 = createConnector(slide, shape1, shape2);
  ctConnector = (CTConnector)connector2.getXmlObject();  
  ctGeomGuideList = ctConnector.getSpPr().getPrstGeom().getAvLst();
  ctGeomGuide = ctGeomGuideList.addNewGd();
  ctGeomGuide.setName("adj1");
  ctGeomGuide.setFmla("val 57365");

  FileOutputStream out = new FileOutputStream("CreatePPTXConnectorShapes.pptx");
  slideShow.write(out);
  out.close();
 }
}

Result: enter image description here

Axel Richter
  • 56,077
  • 6
  • 60
  • 87
  • Well commented example code. Not sure if the question/issue is about the _Shape Guide Name_ only ([`CtGeomGuide#name`](https://poi.apache.org/apidocs/dev/org/apache/poi/sl/draw/binding/CTGeomGuide.html#setName-java.lang.String-)). According to [MS OOXML docs](https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.drawing.shapeguide?view=openxml-2.8.1) the _name_ is just used as reference, so `` seems valid. – hc_dev Mar 05 '21 at 07:25
  • @hc_dev: Yes `` is valid but `` is not. In that case the shape guide has special meaning and it's name must refer the available adjust-handles. – Axel Richter Mar 05 '21 at 07:32