当前位置: 首页 > 知识库问答 >
问题:

如何使用ooxml apache poi通过精确坐标旋转90度来创建弯曲连接器

袁宜
2023-03-14

最近,我正在与Apache POI合作,我在旋转弯曲的连接器时遇到了一个问题,需要精确定位。我想将bent connector表示为形状之间的流动级别,我在可视化方面有一个问题,所以我的基本问题是在使用ooxml apache poi绘制形状连接器时,它被描述如下

我期待下面的结果,有人能提供一些建议来解决这个问题吗

ooxml和apache poi PPT

共有1个答案

谭成业
2023-03-14

为了获得您想要的弯曲连接,默认的BENT_CONNECTOR_3需要水平翻转,然后逆时针旋转90度。

下面的完整示例说明了这一点。注意代码中的注释。

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.BENT_CONNECTOR_3); // bent connector having one handle
  connector.setAnchor(new Rectangle2D.Double( //connector is diagonal in a rectangle
   shape1.getAnchor().getCenterX(), // top left x of that rectangle is center x position of shape1
   shape1.getAnchor().getMaxY(), // top left y of that rectangle is bottom y of shape1
   shape2.getAnchor().getCenterX()-shape1.getAnchor().getCenterX(), // width of that rectanle is center x of shape2 minus center x of shape1
   shape2.getAnchor().getY()-shape1.getAnchor().getMaxY() // height of that rectanle is top y of shape2 minus bottom y of shape1
   ));
  // the rectangle needs to be flipped horizontally as the default bent connector having one handle is like so:
  // ----+
  //     |
  //     +----
  connector.setFlipHorizontal(true);
  // now it is like so:
  //     +----
  //     |
  // ----+
  // and needs to be rotated 90 deg counter-clockwise 
  connector.setRotation(-90.00);
  // now it is like so:
  // |
  // +---+
  //     |
  // now we fix the connecting points
  CTConnector ctConnector = (CTConnector)connector.getXmlObject();
  CTNonVisualConnectorProperties cx = ctConnector.getNvCxnSpPr().getCNvCxnSpPr();
  CTConnection start = cx.addNewStCxn();
  start.setId(shape1.getShapeId());
  start.setIdx(2); // connecting point 2 is center of bottom edge
  CTConnection end = cx.addNewEndCxn();
  end.setId(shape2.getShapeId());
  end.setIdx(0); // connecting point 0 is center of top 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.BLUE);
  shape1.setAnchor(new Rectangle(50, 50, 150, 50));
  
  XSLFAutoShape shape2 = slide.createAutoShape();
  shape2.setShapeType(ShapeType.RECT);
  shape2.setFillColor(Color.BLUE);
  shape2.setAnchor(new Rectangle(150, 200, 150, 50));
  
  // create connector 
  XSLFConnectorShape connector1 = createConnector(slide, shape1, shape2);
 
  FileOutputStream out = new FileOutputStream("CreatePPTXConnectorShapes.pptx");
  slideShow.write(out);
  out.close();
 }
}

它产生:

很明显,如果包含连接件的矩形(作为对角线)是正方形,那么旋转就很容易。这就是为什么上面的代码可以工作,并显示了主要原则。我将把它留在答案中,以免一开始就让它复杂化,并且有代码显示当包含连接线的矩形(作为对角线)不是正方形时的问题。

如果包含连接件作为对角线的矩形不是正方形,则需要考虑旋转时左上角位置和尺寸的变化来设置锚定。我们有TL1,旋转后所需的位置,可以根据形状的位置和尺寸来计算。我们需要TL0,旋转前的左上角点。对于尺寸,需要考虑旋转后宽度和高度的交换。

           TL0*-------+
              |   .   |
              |   .   |
              |   .   |
 TL1*---------------------------+
    |         |   .   |         |
    h- - - - - - -+rp- - - - - -|
    |         |   .   |         |
    +-------------w-------------+
              |   .   |
              |   .   |
              |   .   |
              +-------+
we have TL1, which can get calculated from the shape position and dimension
TL1X, TL1Y, w: width, h: height
we need TL0, which is the top left point before rotating (rp = rotation point)
TL0X = TL1X + (w/2 - h/2) = TL1X + (w - h) / 2
TL0Y = TL1Y - (w/2 - h/2) = TL1Y - (w - h) / 2
width and height simply get swapped

如果形状2位于形状1的右下方,则以下操作应该有效。接头从形状1的下边缘中心到形状2的上边缘中心。

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 CreatePPTXConnectorShapes2 {
    
 private static XSLFConnectorShape createConnector(XSLFSlide slide, XSLFAutoShape shape1, XSLFAutoShape shape2) {
  XSLFConnectorShape connector = slide.createConnector(); 
  // if shape2 is on the right below shape1; connector is from center of bottom edge of shape1 to center of top edge of shape2
  if (shape2.getAnchor().getX() >= shape1.getAnchor().getCenterX() && shape2.getAnchor().getY() >= shape1.getAnchor().getMaxY()) {
   connector.setShapeType(ShapeType.BENT_CONNECTOR_3); // bent connector having one handle
   // the rectangle needs to be flipped horizontally as the default bent connector having one handle is like so:
   // ----+
   //     |
   //     +----
   connector.setFlipHorizontal(true);
   // now it is like so:
   //     +----
   //     |
   // ----+
   // and needs to be rotated 90 deg counter-clockwise 
   connector.setRotation(-90.00);
   // now it is like so:
   // |
   // |
   // +---+
   //     |
   //     |
   // set the anchor after rotating
   //connector is diagonal in a rectangle
   //before rotating it would be:
   double topLeftX = shape1.getAnchor().getCenterX(); // top left x of that rectangle is center x position of shape1
   double topLeftY = shape1.getAnchor().getMaxY(); // top left y of that rectangle is bottom y of shape1
   double width = shape2.getAnchor().getCenterX()-shape1.getAnchor().getCenterX(); // width of that rectanle is center x of shape2 minus center x of shape1
   double height = shape2.getAnchor().getY()-shape1.getAnchor().getMaxY(); // height of that rectanle is top y of shape2 minus bottom y of shape1
   //considering the rotation it is:
   topLeftX = topLeftX + (width - height) / 2;
   topLeftY = topLeftY - (width - height) / 2;
   double w = width;
   width = height;
   height = w;  
   connector.setAnchor(new Rectangle2D.Double(topLeftX, topLeftY, width, height));
   // now it is like so:
   // |
   // +-------+
   //         |  
   // now we fix the connecting points
   CTConnector ctConnector = (CTConnector)connector.getXmlObject();
   CTNonVisualConnectorProperties cx = ctConnector.getNvCxnSpPr().getCNvCxnSpPr();
   CTConnection start = cx.addNewStCxn();
   start.setId(shape1.getShapeId());
   start.setIdx(2); // connecting point 2 is center of bottom edge
   CTConnection end = cx.addNewEndCxn();
   end.setId(shape2.getShapeId());
   end.setIdx(0); // connecting point 0 is center of top 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.BLUE);
  shape1.setAnchor(new Rectangle(50, 50, 150, 50));
  
  XSLFAutoShape shape2 = slide.createAutoShape();
  shape2.setShapeType(ShapeType.RECT);
  shape2.setFillColor(Color.BLUE);
  shape2.setAnchor(new Rectangle(150, 200, 150, 50));
  
  XSLFAutoShape shape3 = slide.createAutoShape();
  shape3.setShapeType(ShapeType.RECT);
  shape3.setFillColor(Color.BLUE);
  shape3.setAnchor(new Rectangle(400, 200, 150, 50));
  
  // create connectors
  XSLFConnectorShape connector1 = createConnector(slide, shape1, shape2);
  XSLFConnectorShape connector2 = createConnector(slide, shape1, shape3);
 
  FileOutputStream out = new FileOutputStream("CreatePPTXConnectorShapes.pptx");
  slideShow.write(out);
  out.close();
 }
}

它产生:

免责声明:正如我在这里的所有代码示例一样,这不是一个在生产环境中使用的适用于所有产品的解决方案,而只是一个展示原则的工作草案。为了创造一个可以有效使用的解决方案,你必须自己努力。

 类似资料:
  • 我正在尝试使用Surfaceview和canvas drawing在Android中创建自定义组件。这些组件可以通过触摸来调整大小和旋转。考虑创建一个图像视图,它的上、右、下和左边缘可通过触摸和拖动所需的边缘来缩放。我使用< code>RectF来保持组件的边界,对于旋转,我使用< code>canvas.rotate(angle,bounds.centerX()、bounds.centerY()

  • 给定的是一个旋转的矩形,该矩形内接到另一个矩形中<两个矩形都有自己的坐标系 在该区域中 我对变换矩阵的尝试(setRotate() 如何计算P点相对于外矩形的位置? 提前感谢!

  • 问题内容: 我想在Oracle 11g中旋转一个表。枢纽选项需要汇总。这是我的原始表: 旋转后,表格应如下所示: 现在,如您所见,分组应该在项目列上进行。无需折叠或计算值。只需旋转即可。那么,枢轴选择正确的事情了吗? 问题答案: 是的,我想是这样。使用汇总很容易进行这样的枢轴操作: 否则,您必须在max聚合内执行case语句。像这样: 这几乎和做。但我宁愿做在..

  • 这是我当前的代码: 我一辈子都不知道如何旋转这个。我看了其他几个论坛,但没有其他机构讨论这个问题。 据我所知,没有办法旋转JPanel或JFrame,所以我运气不好吗? 这就是它现在的样子: 数字时钟 我想把它旋转90度。基本上是垂直的。 编辑:解决方案:

  • 我目前正在用js尝试SVG路径,我想用一条曲线连接两点。以下是我目前的进展: CodePen版本在这里 看来我需要在路径中添加另一条曲线。 我还找到了这个工作的CodePen。