Parcourir la source

Updated vsdx import and added gae-stub

David Benson il y a 8 ans
Parent
commit
adc2e9d5f9

+ 3 - 0
.gitmodules

@@ -0,0 +1,3 @@
+[submodule "gae-stub"]
+	path = gae-stub
+	url = https://github.com/jgraph/gae-stub.git

+ 1 - 0
gae-stub

@@ -0,0 +1 @@
+Subproject commit e8338484ae3810b4c0fe1d8c6efc9152405e2c4e

+ 49 - 24
src/com/mxgraph/io/mxVsdxCodec.java

@@ -30,12 +30,18 @@ import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 import org.xml.sax.SAXException;
 
-import com.mxgraph.io.vsdx.Shape;
+import com.google.appengine.api.images.Image;
+import com.google.appengine.api.images.ImagesService;
+import com.google.appengine.api.images.ImagesService.OutputEncoding;
+import com.google.appengine.api.images.ImagesServiceFactory;
+import com.google.appengine.api.images.Transform;
+import com.google.appengine.api.utils.SystemProperty;
 import com.mxgraph.io.vsdx.ShapePageId;
 import com.mxgraph.io.vsdx.VsdxShape;
 import com.mxgraph.io.vsdx.mxPathDebug;
 import com.mxgraph.io.vsdx.mxVsdxConnect;
 import com.mxgraph.io.vsdx.mxVsdxConstants;
+import com.mxgraph.io.vsdx.mxVsdxGeometry;
 import com.mxgraph.io.vsdx.mxVsdxMaster;
 import com.mxgraph.io.vsdx.mxVsdxModel;
 import com.mxgraph.io.vsdx.mxVsdxPage;
@@ -162,21 +168,23 @@ public class mxVsdxCodec
 					{
 						try 
 						{
-//							if (GaeUtils.isGae())
-//							{
-//								ImagesService imagesService = ImagesServiceFactory.getImagesService();
-//								
-//								Image image = ImagesServiceFactory.makeImage(out.toByteArray());
-//
-//								//dummy transform
-//								Transform transform = ImagesServiceFactory.makeCrop(0.0, 0.0, 1.0, 1.0);
-//
-//								//Use PNG format as it is lossless similar to BMP but compressed
-//								Image newImage = imagesService.applyTransform(transform, image, OutputEncoding.PNG);
-//
-//								base64Str = StringUtils.newStringUtf8(Base64.encodeBase64(newImage.getImageData(), false));
-//							}
-//							else
+							String environ = SystemProperty.environment.get();
+
+							if (environ.equals("Production") || environ.equals("Development"))
+							{
+								ImagesService imagesService = ImagesServiceFactory.getImagesService();
+								
+								Image image = ImagesServiceFactory.makeImage(out.toByteArray());
+
+								//dummy transform
+								Transform transform = ImagesServiceFactory.makeCrop(0.0, 0.0, 1.0, 1.0);
+
+								//Use PNG format as it is lossless similar to BMP but compressed
+								Image newImage = imagesService.applyTransform(transform, image, OutputEncoding.PNG);
+
+								base64Str = StringUtils.newStringUtf8(Base64.encodeBase64(newImage.getImageData(), false));
+							}
+							else
 							{
 								//Use ImageIO as it is normally available in other servlet containers (e.g.; Tomcat)
 								ByteArrayInputStream bis = new ByteArrayInputStream(out.toByteArray());
@@ -590,19 +598,32 @@ public class mxVsdxCodec
 		//Define dimensions
 		mxPoint d = shape.getDimensions();
 		mxVsdxMaster master = shape.getMaster();
-		Shape masterSubShape = master == null ? null : master.getSubShape(shape.getShapeMasterId());
-		boolean masterHasGeom = masterSubShape == null ? false : masterSubShape.hasGeom();
-		boolean hasGeom = shape.hasGeom() || masterHasGeom;
+		//Shape inherit its master geometry, so we don't need to check its master
+		boolean hasGeom = shape.hasGeomList();
 
 		//Define style
 		Map<String, String> styleMap = shape.getStyleFromShape();
 		
-		if (!hasGeom)
+		boolean noFill = true, noLine = true;
+		if (hasGeom)
+		{
+			for (mxVsdxGeometry geo : shape.getGeomList())
+			{
+				noFill &= (geo.isNoFill() || geo.isNoShow());
+				noLine &= (geo.isNoLine() || geo.isNoShow());
+			}
+		}
+		
+		if (noFill)
 		{
 			styleMap.put(mxConstants.STYLE_FILLCOLOR, "none");
-			styleMap.put(mxConstants.STYLE_STROKECOLOR, "none");
 			styleMap.put(mxConstants.STYLE_GRADIENTCOLOR, "none");
 		}
+		
+		if (noLine)
+		{
+			styleMap.put(mxConstants.STYLE_STROKECOLOR, "none");
+		}
 
 		styleMap.put("html", "1");
 		styleMap.put(mxConstants.STYLE_WHITE_SPACE, "wrap");
@@ -611,7 +632,7 @@ public class mxVsdxCodec
 
 		mxCell group = null;
 		Map<Integer, VsdxShape> children = shape.getChildShapes();
-		boolean hasChildren = false;//children != null && children.size() > 0;
+		boolean hasChildren = children != null && children.size() > 0;
 		boolean subLabel = shape.isDisplacedLabel() || shape.isRotatedLabel() || hasChildren;
 		mxPoint o = shape.getOriginPoint(parentHeight, true);
 
@@ -683,6 +704,10 @@ public class mxVsdxCodec
 							subShape);
 					parentsMap.put(new ShapePageId(pageId, Id), group);
 				}
+				else
+				{
+					addUnconnectedEdge(graph, group, subShape, parentHeight);
+				}
 			}
 		}
 		
@@ -964,7 +989,7 @@ public class mxVsdxCodec
 		}
 		
 		mxGeometry edgeGeometry = graph.getModel().getGeometry(edge);
-		edgeGeometry.setPoints(edgeShape.getRoutingPoints(parentHeight, beginXY));
+		edgeGeometry.setPoints(edgeShape.getRoutingPoints(parentHeight, beginXY, edgeShape.getRotation()));
 
 		if (fromConstraint != null)
 		{
@@ -1061,7 +1086,7 @@ public class mxVsdxCodec
 			edge = graph.insertEdge(parent, null, edgeShape.getTextLabel(), null, null, mxVsdxUtils.getStyleString(styleMap, "="));
 		}
 		mxGeometry edgeGeometry = graph.getModel().getGeometry(edge);
-		edgeGeometry.setPoints(edgeShape.getRoutingPoints(parentHeight, beginXY));
+		edgeGeometry.setPoints(edgeShape.getRoutingPoints(parentHeight, beginXY, edgeShape.getRotation()));
 		
 		edgeGeometry.setTerminalPoint(beginXY, true);
 		edgeGeometry.setTerminalPoint(endXY, false);

+ 51 - 9
src/com/mxgraph/io/vsdx/Shape.java

@@ -68,6 +68,9 @@ public class Shape extends Style
 	
 	protected List<Element> geom;
 	
+	protected List<mxVsdxGeometry> geomList = null;
+	protected boolean geomListProcessed = false;
+	
 	protected Map<String, String> imageData;
 
 	protected mxVsdxTheme theme;
@@ -98,6 +101,45 @@ public class Shape extends Style
 		return theme;
 	}
 	
+	public List<mxVsdxGeometry> getGeomList()
+	{
+		return geomList;
+	}
+	
+	protected void processGeomList(List<mxVsdxGeometry> parentGeo)
+	{
+		if (!geomListProcessed)
+		{
+			if (geom != null)
+			{
+				geomList = new ArrayList<>(geom.size());
+				
+				for (int i = 0; i < geom.size(); i++)
+				{
+					if (parentGeo != null && i < parentGeo.size())
+					{
+						geomList.add(parentGeo.get(i));
+					}
+					else
+					{
+						geomList.add(null);
+					}
+				}
+				
+				for (Element geoElem : geom)
+				{
+					mxVsdxGeometry geo = new mxVsdxGeometry(geoElem, parentGeo);
+					geomList.set(geo.getIndex(), geo);
+				}
+			}
+			else
+			{
+				geomList = parentGeo;
+			}
+			geomListProcessed = true;
+		}
+	}
+	
 	/**
 	 * Caches the specified element
 	 * @param elem the element to cache
@@ -232,7 +274,7 @@ public class Shape extends Style
 
 			this.geom.add(elem);
 		}
-		if (n.equals("Field"))
+		else if (n.equals("Field"))
 		{
 			ArrayList<Element> rows = mxVsdxUtils.getDirectChildNamedElements(elem, "Row");
 			
@@ -1041,14 +1083,14 @@ public class Shape extends Style
 		return !(this.geom == null || this.geom.isEmpty());
 	}
 	
-	
-	
-	
-	
-	
-	
-	
-	
+	/**
+	 * Returns whether or not this shape or its master has a geometry defined
+	 * @return whether the shape has a geometry
+	 */
+	public boolean hasGeomList()
+	{
+		return !(this.geomList == null || this.geomList.isEmpty());
+	}
 	
 	/**
 	 * Last cp IX referenced in the Text Element.

+ 1 - 1
src/com/mxgraph/io/vsdx/Style.java

@@ -464,7 +464,7 @@ public class Style
 				{
 					inherit = true;
 				}
-				else if (form.equals("THEMEVAL()") && value.equals("Themed") && style != null)
+				else if (form.contains("THEMEVAL()") && value.equals("Themed") && style != null)
 				{
 					//Handle theme here
 					//FIXME this is a very hacky way to test themes until fully integrating themes

+ 60 - 89
src/com/mxgraph/io/vsdx/VsdxShape.java

@@ -27,6 +27,9 @@ import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
+import com.mxgraph.io.vsdx.geometry.LineTo;
+import com.mxgraph.io.vsdx.geometry.MoveTo;
+import com.mxgraph.io.vsdx.geometry.Row;
 import com.mxgraph.io.vsdx.theme.Color;
 import com.mxgraph.model.mxCell;
 import com.mxgraph.model.mxGeometry;
@@ -204,6 +207,17 @@ public class VsdxShape extends Shape
 		int variant = page.getCellIntValue("VariationColorIndex", 0);
 		
 		setThemeAndVariant(theme, variant);
+		
+		//process shape geometry
+		if (masterShape != null)
+		{
+			masterShape.processGeomList(null);
+			processGeomList(masterShape.getGeomList());
+		}
+		else
+		{
+			processGeomList(null);
+		}
 	}
 	
 	/**
@@ -1430,15 +1444,18 @@ public class VsdxShape extends Shape
 				// String foreignType = "";
 				this.styleDebug("shape type = " + type);
 
-				if (this.imageData != null)
+				//The master may contain the foreign object data
+				if (this.imageData != null || (mxVsdxConstants.FOREIGN.equals(type) && masterShape.imageData != null))
 				{
+					Map<String, String> imageData = this.imageData != null? this.imageData : masterShape.imageData;
+					
 					result.put("shape", "image");
 					result.put("aspect", "fixed");
-					String iType = this.imageData.get("iType");
-					String iData = this.imageData.get("iData");
+					String iType = imageData.get("iType");
+					String iData = imageData.get("iData");
 					
 					result.put("image", "data:image/" + iType + "," + iData);
-					return result;
+					return result;					
 				}
 						
 				String parsedGeom = "";
@@ -1726,116 +1743,70 @@ public class VsdxShape extends Shape
 		return new mxPoint(endX, endY);
 	}
 	
+	private void rotatedPoint(mxPoint pt, double cos, double sin)
+	{
+		double x1 = pt.getX() * cos - pt.getY() * sin;
+		double y1 = pt.getY() * cos + pt.getX() * sin;
+
+		pt.setX(x1);
+		pt.setY(y1);
+	}
+	
 	/**
 	 * Returns the list of routing points of a edge shape.
 	 * @param parentHeight Height of the parent of the shape.
 	 * @return List of mxPoint that represents the routing points.
 	 */
-	public List<mxPoint> getRoutingPoints(double parentHeight, mxPoint startPoint)
+	public List<mxPoint> getRoutingPoints(double parentHeight, mxPoint startPoint, double rotation/*, boolean flibX, boolean flibY*/)
 	{
 		List<mxPoint> points = new ArrayList<mxPoint>();
 		
-		if (!(this.hasGeom()))
+		if (!(this.hasGeomList()))
 		{
 			return points;
 		}
 		
-		int controlPointCount = 0;
-		int currentPointCount = 0;
-		double lastX = startPoint.getX();
-		double lastY = startPoint.getY();
 		double offsetX = 0;
 		double offsetY = 0;
 		
-		for (int i = 0; i < 2; i++)
+		for (mxVsdxGeometry geo : geomList)
 		{
-			for (int j = 0; j < geom.size(); j++)
+			if (!geo.isNoShow())
 			{
-				Node child = geom.get(j).getFirstChild();
+				ArrayList<Row> rows = geo.getRows();
 				
-				while (child != null)
+				for (Row row : rows)
 				{
-					if (child instanceof Element)
+					if (row instanceof MoveTo)
+					{
+						offsetX = row.getX() != null? row.getX() : 0;
+						offsetY = row.getY() != null? row.getY() : 0;
+					}
+					else if (row instanceof LineTo)
 					{
-						Element childElem = (Element) child;
-						String childName = childElem.getNodeName();
-						String del = childElem.getAttribute("Del");
 						
-						if (childName.equals("Cell"))
-						{
-							childName = childElem.getAttribute("N");
-						}
-						else if (childName.equals("Row"))
+						double x = row.getX() != null? row.getX() : 0, y = row.getY() != null? row.getY() : 0;
+
+						mxPoint p = new mxPoint(x, y);
+						if (rotation != 0)
 						{
-							childName = childElem.getAttribute("T");
+							rotation = Math.toRadians(360 - rotation);
+							rotatedPoint(p, Math.cos(rotation), Math.sin(rotation));
 						}
+
+						x = (p.getX() - offsetX) * mxVsdxUtils.conversionFactor;
+						x += startPoint.getX();
+
+						y = ((p.getY() - offsetY) * mxVsdxUtils.conversionFactor) * -1;
+						y += startPoint.getY();
+
+						x = Math.round(x * 100.0) / 100.0;
+						y = Math.round(y * 100.0) / 100.0;
 						
-						if (!del.equals("1"))
-						{
-							switch (childName)
-							{
-								case "MoveTo":
-									{
-										// Initial moveto behaves as a offset to the whole connector
-										Map <String, String> children = getChildValues(childElem, null);
-										String xValue = children.get("X");
-										String yValue = children.get("Y");
-										
-										offsetX = xValue != null ? Double.parseDouble(xValue) : 0;
-										offsetY = yValue != null ? Double.parseDouble(yValue) : 0;
-									}
-									break;
-								case "LineTo":
-									{
-										if (i == 0)
-										{
-											controlPointCount++;
-										}
-										else if (currentPointCount < controlPointCount - 1)
-										{
-											Map <String, String> children = getChildValues(childElem, null);
-											String xValue = children.get("X");
-											String yValue = children.get("Y");
-											double x = 0, y = 0;
-												
-											if (xValue != null)
-											{
-												x = (Double.parseDouble(xValue) - offsetX) * mxVsdxUtils.conversionFactor;
-												lastX = x;
-												x += startPoint.getX();
-											}
-											else
-											{
-												x = lastX;
-											}
-											
-											if (yValue != null)
-											{
-												y = ((Double.parseDouble(yValue) - offsetY) * mxVsdxUtils.conversionFactor) * -1;
-												lastY = y;
-												y += startPoint.getY();
-											}
-											else
-											{
-												y = lastY;
-											}
-											
-											x = Math.round(x * 100.0) / 100.0;
-											y = Math.round(y * 100.0) / 100.0;
-				
-											points.add(new mxPoint(x, y));
-											currentPointCount++;
-										}
-									}
-									break;
-								default:
-									break;
-									
-							}
-						}
+						p.setX(x);
+						p.setY(y);
+						points.add(p);						
 					}
-	
-					child = child.getNextSibling();
 				}
 			}
 		}

+ 17 - 0
src/com/mxgraph/io/vsdx/geometry/ArcTo.java

@@ -0,0 +1,17 @@
+package com.mxgraph.io.vsdx.geometry;
+
+public class ArcTo extends Row 
+{
+	public ArcTo(int index, Double x, Double y, Double a) 
+	{
+		super(index, x, y);
+		this.a = a;
+	}
+
+	@Override
+	public void handle() 
+	{
+		
+	}
+
+}

+ 14 - 0
src/com/mxgraph/io/vsdx/geometry/DelRow.java

@@ -0,0 +1,14 @@
+package com.mxgraph.io.vsdx.geometry;
+
+public class DelRow extends Row{
+
+	public DelRow(int index) {
+		super(index, null, null);
+	}
+
+	@Override
+	public void handle() {
+		//Nothing
+	}
+
+}

+ 20 - 0
src/com/mxgraph/io/vsdx/geometry/Ellipse.java

@@ -0,0 +1,20 @@
+package com.mxgraph.io.vsdx.geometry;
+
+public class Ellipse extends Row 
+{
+	public Ellipse(int index, Double x, Double y, Double a, Double b, Double c, Double d) 
+	{
+		super(index, x, y);
+		this.a = a;
+		this.b = b;
+		this.c = c;
+		this.d = d;
+	}
+
+	@Override
+	public void handle() 
+	{
+		
+	}
+
+}

+ 20 - 0
src/com/mxgraph/io/vsdx/geometry/EllipticalArcTo.java

@@ -0,0 +1,20 @@
+package com.mxgraph.io.vsdx.geometry;
+
+public class EllipticalArcTo extends Row 
+{
+	public EllipticalArcTo(int index, Double x, Double y, Double a, Double b, Double c, Double d) 
+	{
+		super(index, x, y);
+		this.a = a;
+		this.b = b;
+		this.c = c;
+		this.d = d;
+	}
+
+	@Override
+	public void handle() 
+	{
+		
+	}
+
+}

+ 18 - 0
src/com/mxgraph/io/vsdx/geometry/InfiniteLine.java

@@ -0,0 +1,18 @@
+package com.mxgraph.io.vsdx.geometry;
+
+public class InfiniteLine extends Row 
+{
+	public InfiniteLine(int index, Double x, Double y, Double a, Double b) 
+	{
+		super(index, x, y);
+		this.a = a;
+		this.b = b;
+	}
+
+	@Override
+	public void handle() 
+	{
+		
+	}
+
+}

+ 17 - 0
src/com/mxgraph/io/vsdx/geometry/LineTo.java

@@ -0,0 +1,17 @@
+package com.mxgraph.io.vsdx.geometry;
+
+public class LineTo extends Row 
+{
+
+	public LineTo(int index, Double x, Double y)
+	{
+		super(index, x, y);
+	}
+
+	@Override
+	public void handle() 
+	{
+		
+	}
+
+}

+ 15 - 0
src/com/mxgraph/io/vsdx/geometry/MoveTo.java

@@ -0,0 +1,15 @@
+package com.mxgraph.io.vsdx.geometry;
+
+public class MoveTo extends Row 
+{
+	public MoveTo(int index, Double x, Double y) 
+	{
+		super(index, x, y);
+	}
+
+	@Override
+	public void handle() 
+	{
+		
+	}
+}

+ 21 - 0
src/com/mxgraph/io/vsdx/geometry/NURBSTo.java

@@ -0,0 +1,21 @@
+package com.mxgraph.io.vsdx.geometry;
+
+public class NURBSTo extends Row 
+{
+	public NURBSTo(int index, Double x, Double y, Double a, Double b, Double c, Double d, String e) 
+	{
+		super(index, x, y);
+		this.a = a;
+		this.b = b;
+		this.c = c;
+		this.d = d;
+		this.formulaE = e;
+	}
+
+	@Override
+	public void handle() 
+	{
+		
+	}
+
+}

+ 17 - 0
src/com/mxgraph/io/vsdx/geometry/PolylineTo.java

@@ -0,0 +1,17 @@
+package com.mxgraph.io.vsdx.geometry;
+
+public class PolylineTo extends Row 
+{
+	public PolylineTo(int index, Double x, Double y, String a) 
+	{
+		super(index, x, y);
+		this.formulaA = a;
+	}
+
+	@Override
+	public void handle() 
+	{
+		
+	}
+
+}

+ 20 - 0
src/com/mxgraph/io/vsdx/geometry/RelCubBezTo.java

@@ -0,0 +1,20 @@
+package com.mxgraph.io.vsdx.geometry;
+
+public class RelCubBezTo extends Row 
+{
+	public RelCubBezTo(int index, Double x, Double y, Double a, Double b, Double c, Double d) 
+	{
+		super(index, x, y);
+		this.a = a;
+		this.b = b;
+		this.c = c;
+		this.d = d;
+	}
+
+	@Override
+	public void handle() 
+	{
+		
+	}
+
+}

+ 20 - 0
src/com/mxgraph/io/vsdx/geometry/RelEllipticalArcTo.java

@@ -0,0 +1,20 @@
+package com.mxgraph.io.vsdx.geometry;
+
+public class RelEllipticalArcTo extends Row 
+{
+	public RelEllipticalArcTo(int index, Double x, Double y, Double a, Double b, Double c, Double d) 
+	{
+		super(index, x, y);
+		this.a = a;
+		this.b = b;
+		this.c = c;
+		this.d = d;
+	}
+
+	@Override
+	public void handle() 
+	{
+		
+	}
+
+}

+ 17 - 0
src/com/mxgraph/io/vsdx/geometry/RelLineTo.java

@@ -0,0 +1,17 @@
+package com.mxgraph.io.vsdx.geometry;
+
+public class RelLineTo extends Row 
+{
+
+	public RelLineTo(int index, Double x, Double y) 
+	{
+		super(index, x, y);
+	}
+
+	@Override
+	public void handle() 
+	{
+		
+	}
+
+}

+ 17 - 0
src/com/mxgraph/io/vsdx/geometry/RelMoveTo.java

@@ -0,0 +1,17 @@
+package com.mxgraph.io.vsdx.geometry;
+
+public class RelMoveTo extends Row 
+{
+
+	public RelMoveTo(int index, Double x, Double y) 
+	{
+		super(index, x, y);
+	}
+
+	@Override
+	public void handle() 
+	{
+		
+	}
+
+}

+ 18 - 0
src/com/mxgraph/io/vsdx/geometry/RelQuadBezTo.java

@@ -0,0 +1,18 @@
+package com.mxgraph.io.vsdx.geometry;
+
+public class RelQuadBezTo extends Row 
+{
+	public RelQuadBezTo(int index, Double x, Double y, Double a, Double b)
+	{
+		super(index, x, y);
+		this.a = a;
+		this.b = b;
+	}
+
+	@Override
+	public void handle() 
+	{
+		
+	}
+
+}

+ 56 - 0
src/com/mxgraph/io/vsdx/geometry/Row.java

@@ -0,0 +1,56 @@
+package com.mxgraph.io.vsdx.geometry;
+
+public abstract class Row 
+{
+	protected Double x, y, a, b, c, d;
+	protected String formulaA, formulaE; 
+	protected int index;
+	
+	public Row(int index, Double x, Double y) 
+	{
+		this.index = index;
+		this.x = x;
+		this.y = y;
+	}
+
+	public abstract void handle();
+
+	public Double getX() 
+	{
+		return x;
+	}
+
+	public Double getY() 
+	{
+		return y;
+	}
+
+	public Double getA() {
+		return a;
+	}
+
+	public Double getB() {
+		return b;
+	}
+
+	public Double getC() {
+		return c;
+	}
+
+	public Double getD() {
+		return d;
+	}
+
+	public String getFormulaA() {
+		return formulaA;
+	}
+
+	public String getFormulaE() {
+		return formulaE;
+	}
+
+	public int getIndex() 
+	{
+		return index;
+	}
+}

+ 153 - 0
src/com/mxgraph/io/vsdx/geometry/RowFactory.java

@@ -0,0 +1,153 @@
+package com.mxgraph.io.vsdx.geometry;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.w3c.dom.Element;
+
+import com.mxgraph.io.vsdx.mxVsdxUtils;
+
+public class RowFactory 
+{
+	private static Double getDoubleVal(String val)
+	{
+		try
+		{
+			if (val != null && !val.isEmpty())
+			{
+				return Double.valueOf(val);
+			}
+		}
+		catch (Exception e) 
+		{
+			//nothing
+		}
+		return null;
+	}
+	
+	public static Row getRowObj(Element elem, List<Row> pRows) 
+	{
+		String rowType = elem.getAttribute("T");
+		int index = Integer.parseInt(elem.getAttribute("IX"));
+		String del = elem.getAttribute("Del");
+		if (!del.equals("1"))
+		{
+			Row parentObj = null;
+			
+			if (index <= pRows.size())
+			{
+				parentObj = pRows.get(index - 1);
+			}
+			
+			Double x = null, y = null, a = null, b = null, c = null, d = null;
+			String formulaE = null, formulaA = null;;
+			ArrayList<Element> cells = mxVsdxUtils.getDirectChildElements(elem);
+			
+			for (Element cell : cells)
+			{
+				String name = cell.getAttribute("N");
+				String val = cell.getAttribute("V");
+				
+				switch (name)
+				{
+					case "X":
+						x = getDoubleVal(val);
+						
+						if (x == null && parentObj != null) 
+						{
+							x = parentObj.getX();
+						}
+					break;
+					case "Y":
+						y = getDoubleVal(val);
+
+						if (y == null && parentObj != null) 
+						{
+							y = parentObj.getY();
+						}
+					break;
+					case "A":
+						a = getDoubleVal(val);
+						formulaA = val;
+
+						if (a == null && parentObj != null) 
+						{
+							a = parentObj.getA();
+						}
+						if (formulaA == null && parentObj != null) 
+						{
+							formulaA = parentObj.getFormulaA();
+						}
+					break;
+					case "B":
+						b = getDoubleVal(val);
+						
+						if (b == null && parentObj != null) 
+						{
+							b = parentObj.getB();
+						}
+					break;
+					case "C":
+						c = getDoubleVal(val);
+
+						if (c == null && parentObj != null) 
+						{
+							c = parentObj.getC();
+						}
+					break;
+					case "D":
+						d = getDoubleVal(val);
+						
+						if (d == null && parentObj != null) 
+						{
+							d = parentObj.getD();
+						}
+					break;
+					case "E":
+						formulaE = val;
+						
+						if (formulaE == null && parentObj != null) 
+						{
+							formulaE = parentObj.getFormulaE();
+						}
+					break;
+				}
+			}
+			
+			switch (rowType)
+			{
+				case "MoveTo":
+					return new MoveTo(index, x, y);
+				case "LineTo":
+					return new LineTo(index, x, y);
+				case "ArcTo":
+					return new ArcTo(index, x, y, a);
+				case "Ellipse":
+					return new Ellipse(index, x, y, a, b, c, d);
+				case "EllipticalArcTo":
+					return new EllipticalArcTo(index, x, y, a, b, c, d);
+				case "InfiniteLine":
+					return new InfiniteLine(index, x, y, a, b);
+				case "NURBSTo":
+					return new NURBSTo(index, x, y, a, b, c, d, formulaE);
+				case "PolylineTo":
+					return new PolylineTo(index, x, y, formulaA);
+				case "RelCubBezTo":
+					return new RelCubBezTo(index, x, y, a, b, c, d);
+				case "RelEllipticalArcTo ":
+					return new RelEllipticalArcTo(index, x, y, a, b, c, d);
+				case "RelLineTo":
+					return new RelLineTo(index, x, y);
+				case "RelMoveTo":
+					return new RelMoveTo(index, x, y);
+				case "RelQuadBezTo":
+					return new RelQuadBezTo(index, x, y, a, b);
+				case "SplineKnot":
+					return new SplineKnot(index, x, y, a);
+				case "SplineStart":
+					return new SplineStart(index, x, y, a, b, c, d);
+			}
+		}
+		return new DelRow(index);
+	}
+}

+ 17 - 0
src/com/mxgraph/io/vsdx/geometry/SplineKnot.java

@@ -0,0 +1,17 @@
+package com.mxgraph.io.vsdx.geometry;
+
+public class SplineKnot extends Row 
+{
+	public SplineKnot(int index, Double x, Double y, Double a)
+	{
+		super(index, x, y);
+		this.a = a;
+	}
+
+	@Override
+	public void handle() 
+	{
+		
+	}
+
+}

+ 20 - 0
src/com/mxgraph/io/vsdx/geometry/SplineStart.java

@@ -0,0 +1,20 @@
+package com.mxgraph.io.vsdx.geometry;
+
+public class SplineStart extends Row 
+{
+	public SplineStart(int index, Double x, Double y, Double a, Double b, Double c, Double d) 
+	{
+		super(index, x, y);
+		this.a = a;
+		this.b = b;
+		this.c = c;
+		this.d = d;
+	}
+
+	@Override
+	public void handle() 
+	{
+		
+	}
+
+}

+ 154 - 0
src/com/mxgraph/io/vsdx/mxVsdxGeometry.java

@@ -0,0 +1,154 @@
+package com.mxgraph.io.vsdx;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
+import org.w3c.dom.Element;
+
+import com.mxgraph.io.vsdx.geometry.Row;
+import com.mxgraph.io.vsdx.geometry.RowFactory;
+
+public class mxVsdxGeometry {
+	private int index;
+	
+	private boolean noFill = false, noLine = false, noShow = false, noSnap = false, noQuickDrag = false;
+	
+	private ArrayList<Row> rows = null;
+	
+	public mxVsdxGeometry(Element elem)
+	{
+		index = Integer.parseInt(elem.getAttribute("IX"));
+		processGeoElem(elem);
+	}
+
+	public mxVsdxGeometry(Element elem, List<mxVsdxGeometry> parentGeo)
+	{
+		index = Integer.parseInt(elem.getAttribute("IX"));
+		if (parentGeo != null && index < parentGeo.size())
+		{
+			//inherit all parent values including 
+			this.inheritGeo(parentGeo.get(index));			
+		}
+		processGeoElem(elem);
+	}
+
+	private void processGeoElem(Element elem)
+	{		
+		ArrayList<Element> cellElems = mxVsdxUtils.getDirectChildNamedElements(elem, "Cell");
+		ArrayList<Element> rowElems = mxVsdxUtils.getDirectChildNamedElements(elem, "Row");
+		
+		if (rows == null)
+		{
+			rows = new ArrayList<>(rowElems.size());
+			
+			//set the list size to row size
+			for (int i = 0; i < rowElems.size(); i++)
+			{
+				rows.add(null);
+			}
+		}
+		
+		for (Element cellElem : cellElems)
+		{
+			String name = cellElem.getAttribute("N");
+			String val =  cellElem.getAttribute("V");
+			switch (name)
+			{
+				case "NoFill":
+					noFill = "1".equals(val);
+				break;
+				case "NoLine":
+					noLine = "1".equals(val);
+				break;
+				case "NoShow":
+					noShow = "1".equals(val);
+				break;
+				case "NoSnap":
+					noSnap = "1".equals(val);
+				break;
+				case "NoQuickDrag":
+					noQuickDrag = "1".equals(val);
+				break;
+			}
+		}
+		
+		int rowsLen = rows.size();
+		boolean sortNeeded = false;
+		
+		for (Element rowElem : rowElems)
+		{
+			Row row = RowFactory.getRowObj(rowElem, rows);
+			
+			//this can happen when child geo has more rows than parent
+			if (row.getIndex() > rowsLen)
+			{
+				rows.add(row);
+				sortNeeded = true;
+			}
+			else
+			{
+				rows.set(row.getIndex() - 1, row);
+			}
+		}
+		
+		if (sortNeeded)
+		{
+			rows.sort(new Comparator<Row>() 
+			{
+				@Override
+				public int compare(Row r1, Row r2) 
+				{
+					return r1.getIndex() - r2.getIndex();
+				}
+			});
+		}
+	}
+	
+	private void inheritGeo(mxVsdxGeometry parent)
+	{
+		this.noFill = parent.noFill;
+		this.noLine = parent.noLine;
+		this.noShow = parent.noShow;
+		this.noSnap = parent.noSnap;
+		this.noQuickDrag = parent.noQuickDrag;
+		rows = new ArrayList<>();
+		this.rows.addAll(parent.rows);
+	}
+
+	public int getIndex() 
+	{
+		return index;
+	}
+
+	public boolean isNoFill() 
+	{
+		return noFill;
+	}
+
+	public boolean isNoLine() 
+	{
+		return noLine;
+	}
+
+	public boolean isNoShow() 
+	{
+		return noShow;
+	}
+
+	public boolean isNoSnap() 
+	{
+		return noSnap;
+	}
+
+	public boolean isNoQuickDrag() 
+	{
+		return noQuickDrag;
+	}
+
+	public ArrayList<Row> getRows() 
+	{
+		return rows;
+	}
+
+}