mirror of
https://github.com/apache/poi.git
synced 2026-02-27 20:40:08 +08:00
[github-604] XDGF: add support for poly lines. Thanks to Dmitrii Komarov. This closes #604
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1916146 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
baae7b0301
commit
d0a5b622ca
@ -27,6 +27,9 @@ import com.microsoft.schemas.office.visio.x2012.main.RowType;
|
|||||||
|
|
||||||
public class PolyLineTo implements GeometryRow {
|
public class PolyLineTo implements GeometryRow {
|
||||||
|
|
||||||
|
private static final String POLYLINE_FORMULA_PREFIX = "POLYLINE(";
|
||||||
|
private static final String POLYLINE_FORMULA_SUFFIX = ")";
|
||||||
|
|
||||||
PolyLineTo _master;
|
PolyLineTo _master;
|
||||||
|
|
||||||
// The x-coordinate of the ending vertex of a polyline.
|
// The x-coordinate of the ending vertex of a polyline.
|
||||||
@ -96,6 +99,39 @@ public class PolyLineTo implements GeometryRow {
|
|||||||
public void addToPath(java.awt.geom.Path2D.Double path, XDGFShape parent) {
|
public void addToPath(java.awt.geom.Path2D.Double path, XDGFShape parent) {
|
||||||
if (getDel())
|
if (getDel())
|
||||||
return;
|
return;
|
||||||
throw new POIXMLException("Polyline support not implemented");
|
|
||||||
|
// A polyline formula: POLYLINE(xType, yType, x1, y1, x2, y2, ...)
|
||||||
|
String formula = getA().trim();
|
||||||
|
if (!formula.startsWith(POLYLINE_FORMULA_PREFIX) || !formula.endsWith(POLYLINE_FORMULA_SUFFIX)) {
|
||||||
|
throw new POIXMLException("Invalid POLYLINE formula: " + formula);
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] components = formula
|
||||||
|
.substring(POLYLINE_FORMULA_PREFIX.length(), formula.length() - POLYLINE_FORMULA_SUFFIX.length())
|
||||||
|
.split(",");
|
||||||
|
|
||||||
|
if (components.length < 2) {
|
||||||
|
throw new POIXMLException("Invalid POLYLINE formula (not enough arguments): " + formula);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (components.length % 2 != 0) {
|
||||||
|
throw new POIXMLException("Invalid POLYLINE formula -- need 2 + n*2 arguments, got " + components.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (components.length > 2) {
|
||||||
|
// If xType is zero, the X coordinates are interpreted as relative coordinates
|
||||||
|
double xScale = Integer.parseInt(components[0].trim()) == 0 ? parent.getWidth() : 1.0;
|
||||||
|
// If yType is zero, the Y coordinates are interpreted as relative coordinates
|
||||||
|
double yScale = Integer.parseInt(components[1].trim()) == 0 ? parent.getHeight() : 1.0;
|
||||||
|
|
||||||
|
for (int i = 2; i < components.length - 1; i += 2) {
|
||||||
|
double x = Double.parseDouble(components[i].trim());
|
||||||
|
double y = Double.parseDouble(components[i + 1].trim());
|
||||||
|
|
||||||
|
path.lineTo(x * xScale, y * yScale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
path.lineTo(getX(), getY());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,7 +19,9 @@ package org.apache.poi.xdgf.usermodel.section.geometry;
|
|||||||
|
|
||||||
import com.microsoft.schemas.office.visio.x2012.main.CellType;
|
import com.microsoft.schemas.office.visio.x2012.main.CellType;
|
||||||
import com.microsoft.schemas.office.visio.x2012.main.RowType;
|
import com.microsoft.schemas.office.visio.x2012.main.RowType;
|
||||||
|
import com.microsoft.schemas.office.visio.x2012.main.ShapeSheetType;
|
||||||
import org.apache.poi.util.LocaleUtil;
|
import org.apache.poi.util.LocaleUtil;
|
||||||
|
import org.apache.poi.xdgf.usermodel.XDGFShape;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
|
||||||
import java.awt.geom.Path2D;
|
import java.awt.geom.Path2D;
|
||||||
@ -99,4 +101,19 @@ public final class GeometryTestUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mocks a shape for testing geometries with relative coordinates.
|
||||||
|
*/
|
||||||
|
public static XDGFShape mockShape(double width, double height) {
|
||||||
|
ShapeSheetType shapeSheet = ShapeSheetType.Factory.newInstance();
|
||||||
|
CellType[] cells = {
|
||||||
|
createCell("Width", Double.toString(width)),
|
||||||
|
createCell("Height", Double.toString(height))
|
||||||
|
};
|
||||||
|
shapeSheet.setCellArray(cells);
|
||||||
|
|
||||||
|
// Parent page and document is not used during parsing. It's safe to leave them as nulls for mocking
|
||||||
|
return new XDGFShape(shapeSheet, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,109 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
==================================================================== */
|
||||||
|
|
||||||
|
package org.apache.poi.xdgf.usermodel.section.geometry;
|
||||||
|
|
||||||
|
import com.microsoft.schemas.office.visio.x2012.main.RowType;
|
||||||
|
import org.apache.poi.ooxml.POIXMLException;
|
||||||
|
import org.apache.poi.xdgf.usermodel.XDGFShape;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
|
|
||||||
|
import java.awt.geom.Path2D;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class TestPolylineTo {
|
||||||
|
|
||||||
|
private static final double X0 = 0.0;
|
||||||
|
private static final double Y0 = 0.0;
|
||||||
|
private static final double X = 100.0;
|
||||||
|
private static final double Y = 100.0;
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@ValueSource(strings = {
|
||||||
|
"POLYLINE(1, 1, 0.0, 50.0, 100.0, 50.0)",
|
||||||
|
"POLYLINE(1, 0, 0.0, 0.5, 100.0, 0.5)",
|
||||||
|
"POLYLINE(0, 1, 0.0, 50.0, 1.0, 50.0)",
|
||||||
|
"POLYLINE(0, 0, 0.0, 0.5, 1.0, 0.5)"
|
||||||
|
})
|
||||||
|
public void shouldAddMultipleLinesToPath(String formula) {
|
||||||
|
PolyLineTo polyLine = createPolyLine(formula);
|
||||||
|
|
||||||
|
XDGFShape parent = GeometryTestUtils.mockShape(X - X0, Y - Y0);
|
||||||
|
|
||||||
|
Path2D.Double actualPath = new Path2D.Double();
|
||||||
|
actualPath.moveTo(X0, Y0);
|
||||||
|
|
||||||
|
polyLine.addToPath(actualPath, parent);
|
||||||
|
|
||||||
|
Path2D expectedPath = new Path2D.Double();
|
||||||
|
expectedPath.moveTo(X0, Y0);
|
||||||
|
expectedPath.lineTo(0.0, 50.0);
|
||||||
|
expectedPath.lineTo(100.0, 50.0);
|
||||||
|
expectedPath.lineTo(X, Y);
|
||||||
|
|
||||||
|
GeometryTestUtils.assertPath(expectedPath, actualPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldAddSingleLineToPath() {
|
||||||
|
PolyLineTo polyLine = createPolyLine("POLYLINE(1, 1)");
|
||||||
|
|
||||||
|
XDGFShape parent = GeometryTestUtils.mockShape(X - X0, Y - Y0);
|
||||||
|
|
||||||
|
Path2D.Double actualPath = new Path2D.Double();
|
||||||
|
actualPath.moveTo(X0, Y0);
|
||||||
|
|
||||||
|
polyLine.addToPath(actualPath, parent);
|
||||||
|
|
||||||
|
Path2D expectedPath = new Path2D.Double();
|
||||||
|
expectedPath.moveTo(X0, Y0);
|
||||||
|
expectedPath.lineTo(X, Y);
|
||||||
|
|
||||||
|
GeometryTestUtils.assertPath(expectedPath, actualPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@ValueSource(strings = {
|
||||||
|
"1, 1)", // Does not start with POLYLINE(
|
||||||
|
"POLYLINE(1, 1", // Does not end with )
|
||||||
|
"POLYLINE()", // Empty arguments
|
||||||
|
"POLYLINE(1)", // Not enough arguments (less than two)
|
||||||
|
"POLYLINE(1, 1, 100.0)", // Odd number of arguments
|
||||||
|
})
|
||||||
|
public void shouldThrowExceptionWhenPolyLineFormulaIsIncorrect(String formula) {
|
||||||
|
PolyLineTo polyLine = createPolyLine(formula);
|
||||||
|
|
||||||
|
Path2D.Double path = new Path2D.Double();
|
||||||
|
Assertions.assertThrows(POIXMLException.class, () -> polyLine.addToPath(path, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PolyLineTo createPolyLine(String formula) {
|
||||||
|
RowType row = GeometryTestUtils.createRow(
|
||||||
|
0L,
|
||||||
|
new HashMap<String, Object>() {{
|
||||||
|
put("X", X);
|
||||||
|
put("Y", Y);
|
||||||
|
put("A", formula);
|
||||||
|
}}
|
||||||
|
);
|
||||||
|
return new PolyLineTo(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user