/// <summary> /// Sets the fixed source or target terminal point on the given edge. /// </summary> /// <param name="edge">State whose terminal point should be updated.</param> /// <param name="terminal">State which represents the actual terminal.</param> /// <param name="source">Boolean that specifies if the terminal is the source.</param> /// <param name="constraint">Constraint that specifies the connection.</param> public void UpdateFixedTerminalPoint(mxCellState edge, mxCellState terminal, bool source, mxConnectionConstraint constraint) { mxPoint pt = null; if (constraint != null) { pt = graph.GetConnectionPoint(terminal, constraint); } if (pt == null && terminal == null) { mxPoint orig = edge.Origin; mxGeometry geo = graph.GetCellGeometry(edge.Cell); pt = geo.GetTerminalPoint(source); if (pt != null) { pt = new mxPoint(scale * (translate.X + pt.X + orig.X), scale * (translate.Y + pt.Y + orig.Y)); } } edge.SetAbsoluteTerminalPoint(pt, source); }
/// <summary> /// Transforms the given control point to an absolute point. /// </summary> public mxPoint TransformControlPoint(mxCellState state, mxPoint pt) { mxPoint orig = state.Origin; return(new mxPoint(scale * (pt.X + translate.X + orig.X), scale * (pt.Y + translate.Y + orig.Y))); }
/// <summary> /// Updates the absolute points in the given state using the specified array /// of points as the relative points. /// </summary> /// <param name="edge">Cell state whose absolute points should be updated.</param> /// <param name="points">Array of points that constitute the relative points.</param> /// <param name="source">Cell that represents the source terminal.</param> /// <param name="target">Cell that represents the target terminal.</param> public void UpdatePoints(mxCellState edge, List <mxPoint> points, mxCellState source, mxCellState target) { if (edge != null) { List <mxPoint> pts = new List <mxPoint>(); pts.Add(edge.AbsolutePoints[0]); mxEdgeStyleFunction edgeStyle = GetEdgeStyle(edge, points, source, target); if (edgeStyle != null) { mxCellState src = GetTerminalPort(edge, source, true); mxCellState trg = GetTerminalPort(edge, target, false); ((mxEdgeStyleFunction)edgeStyle)(edge, src, trg, points, pts); } else if (points != null) { for (int i = 0; i < points.Count; i++) { if (points[i] is mxPoint) { mxPoint pt = points[i].Clone(); pts.Add(TransformControlPoint(edge, pt)); } } } List <mxPoint> tmp = edge.AbsolutePoints; pts.Add(tmp[tmp.Count - 1]); edge.AbsolutePoints = pts; } }
/// <summary> /// Draws the shadow. /// </summary> /// <param name="canvas"></param> /// <param name="state"></param> /// <param name="rotation"></param> /// <param name="flipH"></param> /// <param name="flipV"></param> /// <param name="bounds"></param> /// <param name="alpha"></param> protected void DrawShadow(mxGdiCanvas2D canvas, mxCellState state, double rotation, bool flipH, bool flipV, mxRectangle bounds, double alpha, bool filled) { // Requires background in generic shape for shadow, looks like only one // fillAndStroke is allowed per current path, try working around that // Computes rotated shadow offset double rad = rotation * Math.PI / 180; double cos = Math.Cos(-rad); double sin = Math.Sin(-rad); mxPoint offset = mxUtils.GetRotatedPoint(new mxPoint(mxConstants.SHADOW_OFFSETX, mxConstants.SHADOW_OFFSETY), cos, sin); if (flipH) { offset.X *= -1; } if (flipV) { offset.Y *= -1; } // TODO: Use save/restore instead of negative offset to restore (requires fix for HTML canvas) canvas.Translate(offset.X, offset.Y); // Returns true if a shadow has been painted (path has been created) if (DrawShape(canvas, state, bounds, true)) { canvas.Alpha = mxConstants.STENCIL_SHADOW_OPACITY * alpha; // TODO: Implement new shadow //canvas.Shadow(mxConstants.STENCIL_SHADOWCOLOR, filled); } canvas.Translate(-offset.X, -offset.Y); }
/// <summary> /// Returns a point that defines the location of the intersection point between /// the perimeter and the line between the center of the shape and the given point. /// </summary> /// <param name="terminal">State for the source or target terminal.</param> /// <param name="next">Point that lies outside of the given terminal.</param> /// <param name="orthogonal">Specifies if the orthogonal projection onto /// the perimeter should be returned. If this is false then the intersection /// of the perimeter and the line between the next and the center point is /// returned.</param> /// <param name="border">Optional border between the perimeter and the shape.</param> public mxPoint GetPerimeterPoint(mxCellState terminal, mxPoint next, bool orthogonal, double border) { mxPoint point = null; if (terminal != null) { mxPerimeterFunction perimeter = GetPerimeterFunction(terminal); if (perimeter != null && next != null) { mxRectangle bounds = GetPerimeterBounds(terminal, border); if (bounds.Width > 0 || bounds.Height > 0) { point = perimeter(bounds, terminal, next, orthogonal); } } if (point == null) { point = GetPoint(terminal); } } return(point); }
/// <summary> /// Returns the absolute, cummulated origin for the children inside the /// given parent. /// </summary> public mxPoint GetOrigin(Object cell) { mxPoint result = null; if (cell != null) { result = GetOrigin(GetParent(cell)); if (!IsEdge(cell)) { mxGeometry geo = GetGeometry(cell); if (geo != null) { result.X += geo.X; result.Y += geo.Y; } } } else { result = new mxPoint(); } return(result); }
/// <summary> /// Parses the bounds, absolute points and label information from the style /// of the state into its respective fields and returns the label of the /// cell. /// </summary> public string ParseState(mxCellState state, bool edge) { Dictionary <string, object> style = state.Style; // Parses the bounds state.X = mxUtils.GetDouble(style, "x"); state.Y = mxUtils.GetDouble(style, "y"); state.Width = mxUtils.GetDouble(style, "width"); state.Height = mxUtils.GetDouble(style, "height"); // Parses the absolute points list List <mxPoint> pts = ParsePoints(mxUtils.GetString(style, "points")); if (pts.Count > 0) { state.AbsolutePoints = pts; } // Parses the label and label bounds string label = mxUtils.GetString(style, "label"); if (label != null && label.Length > 0) { mxPoint offset = new mxPoint(mxUtils.GetDouble(style, "dx"), mxUtils.GetDouble(style, "dy")); mxRectangle vertexBounds = (!edge) ? state : null; state.LabelBounds = mxUtils.GetLabelPaintBounds(label, style, mxUtils.IsTrue(style, "html", false), offset, vertexBounds, scale); } return(label); }
/// <summary> /// /// </summary> public void QuadTo(double x1, double y1, double x2, double y2) { if (currentPath != null) { mxPoint nextPoint = new mxPoint((state.dx + x2) * state.scale, (state.dy + y2) * state.scale); if (lastPoint != null) { double cpx0 = lastPoint.X; double cpy0 = lastPoint.Y; double qpx1 = (state.dx + x1) * state.scale; double qpy1 = (state.dy + y1) * state.scale; double cpx1 = cpx0 + 2f / 3f * (qpx1 - cpx0); double cpy1 = cpy0 + 2f / 3f * (qpy1 - cpy0); double cpx2 = nextPoint.X + 2f / 3f * (qpx1 - nextPoint.X); double cpy2 = nextPoint.Y + 2f / 3f * (qpy1 - nextPoint.Y); currentPath.AddBezier((float)cpx0, (float)cpy0, (float)cpx1, (float)cpy1, (float)cpx2, (float)cpy2, (float)nextPoint.X, (float)nextPoint.Y); } lastPoint = nextPoint; } }
/// <summary> /// /// </summary> public void MoveTo(double x, double y) { if (currentPath != null) { // StartFigure avoids connection between last figure and new figure currentPath.StartFigure(); lastPoint = new mxPoint((state.dx + x) * state.scale, (state.dy + y) * state.scale); } }
/// <summary> /// Inner helper method to update the parent of the specified edge to the /// nearest-common-ancestor of its two terminals. /// </summary> /// <param name="edge">Specifies the edge to be updated.</param> /// <param name="root">Current root of the model.</param> public void UpdateEdgeParent(Object edge, Object root) { Object source = GetTerminal(edge, true); Object target = GetTerminal(edge, false); Object cell = null; // Uses the first non-relative descendants of the source terminal while (source != null && !IsEdge(source) && GetGeometry(source) != null && GetGeometry(source).Relative) { source = GetParent(source); } // Uses the first non-relative descendants of the target terminal while (target != null && !IsEdge(target) && GetGeometry(target) != null && GetGeometry(target).Relative) { target = GetParent(target); } if (IsAncestor(root, source) && IsAncestor(root, target)) { if (source == target) { cell = GetParent(source); } else { cell = GetNearestCommonAncestor(source, target); } if (cell != null && GetParent(cell) != root && GetParent(edge) != cell) { mxGeometry geo = GetGeometry(edge); if (geo != null) { mxPoint origin1 = GetOrigin(GetParent(edge)); mxPoint origin2 = GetOrigin(cell); double dx = origin2.X - origin1.X; double dy = origin2.Y - origin1.Y; geo = (mxGeometry)geo.Clone(); geo.Translate(-dx, -dy); SetGeometry(edge, geo); } Add(cell, edge, GetChildCount(cell)); } } }
/// <summary> /// Returns true if the given object equals this point. /// </summary> /// <returns>Returns true if obj is equal.</returns> new public Boolean Equals(Object obj) { if (obj is mxPoint) { mxPoint pt = (mxPoint)obj; return(pt.X == X && pt.Y == Y); } return(false); }
/// <summary> /// Sets the sourcePoint or targetPoint to the given point and returns the /// new point. /// </summary> /// <param name="point">Point to be used as the new source or target point.</param> /// <param name="source">Boolean that specifies if the source or target point /// should be set.</param> /// <returns>Returns the new point.</returns> public mxPoint SetTerminalPoint(mxPoint point, bool source) { if (source) { sourcePoint = point; } else { targetPoint = point; } return(point); }
/// <summary> /// Updates the absolute terminal point in the given state for the given /// start and end state, where start is the source if source is true. /// </summary> /// <param name="edge">State whose terminal point should be updated.</param> /// <param name="start">for the terminal on "this" side of the edge.</param> /// <param name="end">for the terminal on the other side of the edge.</param> /// <param name="source">Boolean indicating if start is the source terminal state.</param> public void UpdateFloatingTerminalPoint(mxCellState edge, mxCellState start, mxCellState end, bool source) { start = GetTerminalPort(edge, start, source); mxPoint next = GetNextPoint(edge, end, source); double border = mxUtils.GetDouble(edge.Style, mxConstants.STYLE_PERIMETER_SPACING); border += mxUtils.GetDouble(edge.Style, (source) ? mxConstants.STYLE_SOURCE_PERIMETER_SPACING : mxConstants.STYLE_TARGET_PERIMETER_SPACING); mxPoint pt = GetPerimeterPoint(start, next, graph.IsOrthogonal(edge), border); edge.SetAbsoluteTerminalPoint(pt, source); }
/// <summary> /// /// </summary> public void LineTo(double x, double y) { if (currentPath != null) { mxPoint nextPoint = new mxPoint((state.dx + x) * state.scale, (state.dy + y) * state.scale); if (lastPoint != null) { currentPath.AddLine((float)lastPoint.X, (float)lastPoint.Y, (float)nextPoint.X, (float)nextPoint.Y); } lastPoint = nextPoint; } }
/// <summary> /// Updates the terminal points in the given state after the edge style was /// computed for the edge. /// </summary> /// <param name="state">State whose terminal points should be updated.</param> /// <param name="source">State that represents the source terminal.</param> /// <param name="target">State that represents the target terminal.</param> public void UpdateFloatingTerminalPoints(mxCellState state, mxCellState source, mxCellState target) { mxPoint p0 = state.AbsolutePoints[0]; mxPoint pe = state.AbsolutePoints[state.AbsolutePointCount() - 1]; if (pe == null && target != null) { UpdateFloatingTerminalPoint(state, target, source, false); } if (p0 == null && source != null) { UpdateFloatingTerminalPoint(state, source, target, true); } }
/// <summary> /// Returns the nearest point in the list of absolute points or the center /// of the opposite terminal. /// </summary> /// <param name="edge">State that represents the edge.</param> /// <param name="opposite">State that represents the opposite terminal.</param> /// <param name="source">Boolean indicating if the next point for the source or target /// should be returned.</param> public mxPoint GetNextPoint(mxCellState edge, mxCellState opposite, bool source) { List <mxPoint> pts = edge.AbsolutePoints; mxPoint point = null; if (pts != null && pts.Count >= 2) { int count = pts.Count; int index = (source) ? Math.Min(1, count - 1) : Math.Max(0, count - 2); point = pts[index]; } if (point == null && opposite != null) { point = new mxPoint(opposite.GetCenterX(), opposite.GetCenterY()); } return(point); }
/// <summary> /// /// </summary> public void CurveTo(double x1, double y1, double x2, double y2, double x3, double y3) { if (currentPath != null) { mxPoint nextPoint = new mxPoint((state.dx + x3) * state.scale, (state.dy + y3) * state.scale); if (lastPoint != null) { currentPath.AddBezier((float)lastPoint.X, (float)lastPoint.Y, (float)((state.dx + x1) * state.scale), (float)((state.dy + y1) * state.scale), (float)((state.dx + x2) * state.scale), (float)((state.dy + y2) * state.scale), (float)nextPoint.X, (float)nextPoint.Y); } lastPoint = nextPoint; } }
/// <summary> /// Translates the geometry by the specified amount. That is, x and y of the /// geometry, the sourcePoint, targetPoint and all elements of points are /// translated by the given amount. X and y are only translated if the /// geometry is not relative. If TRANSLATE_CONTROL_POINTS is false, then /// are not modified by this function. /// </summary> /// <param name="dx">Integer that specifies the x-coordinate of the translation.</param> /// <param name="dy">Integer that specifies the y-coordinate of the translation.</param> public void Translate(double dx, double dy) { // Translates the geometry if (!Relative) { x += dx; y += dy; } // Translates the source point if (sourcePoint != null) { sourcePoint.X += dx; sourcePoint.Y += dy; } // Translates the target point if (targetPoint != null) { targetPoint.X += dx; targetPoint.Y += dy; } // Translate the control points if (TRANSLATE_CONTROL_POINTS && points != null) { int count = points.Count; for (int i = 0; i < count; i++) { mxPoint pt = points[i]; pt.X += dx; pt.Y += dy; } } }
/// <summary> /// Sets the first or last point in the list of points depending on source. /// </summary> /// <param name="point">Point that represents the terminal point.</param> /// <param name="source">Boolean that specifies if the first or last point should /// be assigned.</param> public void SetAbsoluteTerminalPoint(mxPoint point, bool source) { if (source) { if (absolutePoints == null) { absolutePoints = new List <mxPoint>(); } if (absolutePoints == null || absolutePoints.Count == 0) { absolutePoints.Add(point); } else { absolutePoints[0] = point; } } else { if (absolutePoints == null) { absolutePoints = new List <mxPoint>(); absolutePoints.Add(null); absolutePoints.Add(point); } else if (absolutePoints.Count == 1) { absolutePoints.Add(point); } else { absolutePoints[absolutePoints.Count - 1] = point; } } }
/// <summary> /// Constructs a copy of the given geometry. /// </summary> /// <param name="geometry">Geometry to construct a copy of.</param> public mxGeometry(mxGeometry geometry) : base(geometry.X, geometry.Y, geometry.Width, geometry .Height) { if (geometry.points != null) { points = new List <mxPoint>(geometry.points.Count); foreach (mxPoint pt in geometry.points) { points.Add(pt.Clone()); } } if (geometry.sourcePoint != null) { sourcePoint = geometry.sourcePoint.Clone(); } if (geometry.targetPoint != null) { targetPoint = geometry.targetPoint.Clone(); } if (geometry.offset != null) { offset = geometry.offset.Clone(); } if (geometry.alternateBounds != null) { alternateBounds = geometry.alternateBounds.Clone(); } relative = geometry.relative; }
/// <summary> /// Returns a point that defines the location of the intersection point between /// the perimeter and the line between the center of the shape and the given point. /// </summary> public mxPoint GetPerimeterPoint(mxCellState terminal, mxPoint next, bool orthogonal) { return(GetPerimeterPoint(terminal, next, orthogonal, 0)); }
/// <summary> /// /// </summary> public void QuadTo(double x1, double y1, double x2, double y2) { if (currentPath != null) { mxPoint nextPoint = new mxPoint(state.dx + x2 * state.scale, state.dy + y2 * state.scale); if (lastPoint != null) { double cpx0 = lastPoint.X; double cpy0 = lastPoint.Y; double qpx1 = state.dx + x1 * state.scale; double qpy1 = state.dy + y1 * state.scale; double cpx1 = cpx0 + 2f/3f * (qpx1 - cpx0); double cpy1 = cpy0 + 2f/3f * (qpy1 - cpy0); double cpx2 = nextPoint.X + 2f/3f * (qpx1 - nextPoint.X); double cpy2 = nextPoint.Y + 2f/3f * (qpy1 - nextPoint.Y); currentPath.AddBezier((float)cpx0, (float)cpy0, (float)cpx1, (float)cpy1, (float)cpx2, (float)cpy2, (float)nextPoint.X, (float)nextPoint.Y); } lastPoint = nextPoint; } }
/// <summary> /// Validates the bounds of the given parent's child using the given parent /// state as the origin for the child. The validation is carried out /// recursively for all non-collapsed descendants. /// </summary> /// <param name="parentState">Cell state for the given parent.</param> /// <param name="cell">Cell for which the bounds in the state should be updated.</param> public void ValidateBounds(mxCellState parentState, Object cell) { mxIGraphModel model = graph.Model; mxCellState state = GetState(cell, true); if (state != null) { if (!graph.IsCellVisible(cell)) { RemoveState(cell); } else if (parentState != null) { state.AbsoluteOffset.X = 0; state.AbsoluteOffset.Y = 0; state.Origin = new mxPoint(parentState.Origin.X, parentState.Origin.Y); mxGeometry geo = graph.GetCellGeometry(cell); if (geo != null) { if (!model.IsEdge(cell)) { mxPoint origin = state.Origin; mxPoint offset = geo.Offset; if (offset == null) { offset = EMPTY_POINT; } if (geo.Relative) { origin.X += geo.X * parentState.Width / Scale + offset.X; origin.Y += geo.Y * parentState.Height / Scale + offset.Y; } else { state.AbsoluteOffset = new mxPoint( scale * offset.X, scale * offset.Y); origin.X += geo.X; origin.Y += geo.Y; } } // Updates the cell state's bounds state.X = scale * (translate.X + state.Origin.X); state.Y = scale * (translate.Y + state.Origin.Y); state.Width = scale * geo.Width; state.Height = scale * geo.Height; if (model.IsVertex(cell)) { UpdateVertexLabelOffset(state); } } } // Applies child offset to origin mxPoint childOffset = graph.GetChildOffsetForCell(cell); if (childOffset != null) { state.Origin.X += childOffset.X; state.Origin.Y += childOffset.Y; } } // Recursively validates the child bounds if (state != null && !graph.IsCellCollapsed(cell)) { int childCount = model.GetChildCount(cell); for (int i = 0; i < childCount; i++) { ValidateBounds(state, model.GetChildAt(cell, i)); } } }
/// <summary> /// /// </summary> public void MoveTo(double x, double y) { if (currentPath != null) { // StartFigure avoids connection between last figure and new figure currentPath.StartFigure(); lastPoint = new mxPoint(state.dx + x * state.scale, state.dy + y * state.scale); } }
/// <summary> /// /// </summary> public void CurveTo(double x1, double y1, double x2, double y2, double x3, double y3) { if (currentPath != null) { mxPoint nextPoint = new mxPoint(state.dx + x3 * state.scale, state.dy + y3 * state.scale); if (lastPoint != null) { currentPath.AddBezier((float)lastPoint.X, (float)lastPoint.Y, (float)(state.dx + x1 * state.scale), (float)(state.dy + y1 * state.scale), (float)(state.dx + x2 * state.scale), (float)(state.dy + y2 * state.scale), (float)nextPoint.X, (float)nextPoint.Y); } lastPoint = nextPoint; } }
/// <summary> /// Returns the paint bounds for the given label. /// </summary> /// <returns></returns> public static mxRectangle GetLabelPaintBounds(String label, Dictionary<string, Object> style, bool isHtml, mxPoint offset, mxRectangle vertexBounds, double scale) { bool horizontal = mxUtils.IsTrue(style, mxConstants.STYLE_HORIZONTAL, true); int w = 0; if (vertexBounds != null && GetString(style, mxConstants.STYLE_WHITE_SPACE, "nowrap").Equals("wrap")) { if (horizontal) { w = (int)(vertexBounds.Width / scale); } else { w = (int)(vertexBounds.Height / scale); } } mxRectangle size = mxUtils.GetLabelSize(label, style, w); double x = offset.X; double y = offset.Y; double width = 0; double height = 0; if (vertexBounds != null) { x += vertexBounds.X; y += vertexBounds.Y; // Limits the label to the swimlane title if (mxUtils.GetString(style, mxConstants.STYLE_SHAPE, "").Equals( mxConstants.SHAPE_SWIMLANE)) { double start = mxUtils.GetDouble(style, mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_STARTSIZE) * scale; if (horizontal) { width += vertexBounds.Width; height += start; } else { width += start; height += vertexBounds.Height; } } else { width += vertexBounds.Width; height += vertexBounds.Height; } } return mxUtils.GetScaledLabelBounds(x, y, size, width, height, style, scale); }
/// <summary> /// Returns a point that defines the location of the intersection point between /// the perimeter and the line between the center of the shape and the given point. /// </summary> /// <param name="terminal">State for the source or target terminal.</param> /// <param name="next">Point that lies outside of the given terminal.</param> /// <param name="orthogonal">Specifies if the orthogonal projection onto /// the perimeter should be returned. If this is false then the intersection /// of the perimeter and the line between the next and the center point is /// returned.</param> /// <param name="border">Optional border between the perimeter and the shape.</param> public mxPoint GetPerimeterPoint(mxCellState terminal, mxPoint next, bool orthogonal, double border) { mxPoint point = null; if (terminal != null) { mxPerimeterFunction perimeter = GetPerimeterFunction(terminal); if (perimeter != null && next != null) { mxRectangle bounds = GetPerimeterBounds(terminal, border); if (bounds.Width > 0 || bounds.Height > 0) { point = perimeter(bounds, terminal, next, orthogonal); } } if (point == null) { point = GetPoint(terminal); } } return point; }
/// <summary> /// Returns the nearest point in the list of absolute points or the center /// of the opposite terminal. /// </summary> /// <param name="vertex">Cell state that represents the vertex.</param> /// <param name="constraint">Connection constraint that represents the connection /// point constraint as returned by getConnectionConstraint.</param> public mxPoint GetConnectionPoint(mxCellState vertex, mxConnectionConstraint constraint) { mxPoint point = null; if (vertex != null && constraint.Point != null) { point = new mxPoint(vertex.X + constraint.Point.X * vertex.Width, vertex.Y + constraint.Point.Y * vertex.Height); } if (point != null && constraint.Perimeter) { point = View.GetPerimeterPoint(vertex, point, false); } return point; }
/// <summary> /// Rotates the given point by the given cos and sin. /// </summary> public static mxPoint GetRotatedPoint(mxPoint pt, double cos, double sin, mxPoint c) { double x = pt.X - c.X; double y = pt.Y - c.Y; double x1 = x * cos - y * sin; double y1 = y * cos + x * sin; return new mxPoint(x1 + c.X, y1 + c.Y); }
/// <summary> /// Draws the given lines as segments between all points of the given list /// of mxPoints. /// </summary> /// <param name="pts">List of points that define the line.</param> /// <param name="style">Style to be used for painting the line.</param> public void DrawLine(List<mxPoint> pts, Dictionary<string, Object> style) { Color? penColor = mxUtils.GetColor(style, mxConstants.STYLE_STROKECOLOR, Color.Black); float penWidth = mxUtils.GetFloat(style, mxConstants.STYLE_STROKEWIDTH, 1); Boolean rounded = mxUtils.IsTrue(style, mxConstants.STYLE_ROUNDED, false); if (penColor != null && penWidth > 0) { Pen pen = new Pen((Color)penColor, (float)(penWidth * scale)); if (mxUtils.IsTrue(style, mxConstants.STYLE_DASHED, false)) { float[] tmp = { (float)(3 * scale), (float)(3 * scale) }; pen.DashPattern = tmp; } // Draws the shape string shape = mxUtils.GetString(style, mxConstants.STYLE_SHAPE, ""); switch (shape) { case (mxConstants.SHAPE_ARROW): { // Base vector (between end points) mxPoint p0 = pts[0]; mxPoint pe = pts[pts.Count - 1]; int x = (int) Math.Min(p0.X, pe.X); int y = (int) Math.Min(p0.Y, pe.Y); int x1 = (int) Math.Max(p0.X, pe.X); int y1 = (int) Math.Max(p0.Y, pe.Y); int w = x1 - x; int h = y1 - y; Rectangle bounds = new Rectangle(x, y, w, h); bool shadow = mxUtils.IsTrue(style, mxConstants.STYLE_SHADOW, false); Color? fillColor = mxUtils.GetColor(style, mxConstants.STYLE_FILLCOLOR); float opacity = mxUtils.GetFloat(style, mxConstants.STYLE_OPACITY, 100); int alpha = (int)(255 * opacity / 100); Brush brush = null; if (fillColor != null) { Color fill = (Color)fillColor; if (opacity != 100) { fill = Color.FromArgb(alpha, fill.R, fill.G, fill.B); } Color? gradientColor = mxUtils.GetColor(style, mxConstants.STYLE_GRADIENTCOLOR); if (gradientColor != null) { String gradientDirection = mxUtils.GetString(style, mxConstants.STYLE_GRADIENT_DIRECTION); LinearGradientMode mode = LinearGradientMode.ForwardDiagonal; if (gradientDirection != null && !gradientDirection .Equals(mxConstants.DIRECTION_SOUTH)) { if (gradientDirection.Equals(mxConstants.DIRECTION_EAST)) { mode = LinearGradientMode.BackwardDiagonal; } else if (gradientDirection.Equals(mxConstants.DIRECTION_NORTH)) { mode = LinearGradientMode.Horizontal; } else if (gradientDirection.Equals(mxConstants.DIRECTION_WEST)) { mode = LinearGradientMode.Vertical; } } brush = new LinearGradientBrush(bounds, fill, (Color)gradientColor, mode); } else { brush = new SolidBrush(fill); } } // Geometry of arrow double spacing = mxConstants.ARROW_SPACING * scale; double width = mxConstants.ARROW_WIDTH * scale; double arrow = mxConstants.ARROW_SIZE * scale; double dx = pe.X - p0.X; double dy = pe.Y - p0.Y; double dist = Math.Sqrt(dx * dx + dy * dy); double length = dist - 2 * spacing - arrow; // Computes the norm and the inverse norm double nx = dx / dist; double ny = dy / dist; double basex = length * nx; double basey = length * ny; double floorx = width * ny / 3; double floory = -width * nx / 3; // Computes points double p0x = p0.X - floorx / 2 + spacing * nx; double p0y = p0.Y - floory / 2 + spacing * ny; double p1x = p0x + floorx; double p1y = p0y + floory; double p2x = p1x + basex; double p2y = p1y + basey; double p3x = p2x + floorx; double p3y = p2y + floory; // p4 not necessary double p5x = p3x - 3 * floorx; double p5y = p3y - 3 * floory; Point[] poly = new Point[]{ new Point((int) p0x, (int) p0y), new Point((int) p1x, (int) p1y), new Point((int) p2x, (int) p2y), new Point((int) p3x, (int) p3y), new Point((int) (pe.X - spacing * nx), (int) (pe .Y - spacing * ny)), new Point((int) p5x, (int) p5y), new Point((int) (p5x + floorx), (int) (p5y + floory))}; DrawPolygon(poly, brush, pen, shadow); break; } default: { // TODO: Move code into DrawConnector method // Draws the start marker Object marker = mxUtils.GetString(style, mxConstants.STYLE_STARTARROW); mxPoint p0 = pts[0]; mxPoint pt = pts[1]; mxPoint offset = null; if (marker != null) { float size = (float) (mxUtils.GetFloat(style, mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_MARKERSIZE)); offset = DrawMarker(marker, pt, p0, size, pen); } else { double dx = pt.X - p0.X; double dy = pt.Y - p0.Y; double dist = Math.Max(1, Math.Sqrt(dx * dx + dy * dy)); double nx = dx * penWidth * scale / dist; double ny = dy * penWidth * scale / dist; offset = new mxPoint(nx / 2, ny / 2); } // Applies offset to point if (offset != null) { p0 = p0.Clone(); p0.X += offset.X; p0.Y += offset.Y; offset = null; } // Draws the end marker marker = mxUtils.GetString(style, mxConstants.STYLE_ENDARROW); mxPoint pe = pts[pts.Count - 1]; pt = pts[pts.Count - 2]; if (marker != null) { float size = (float) (mxUtils.GetFloat(style, mxConstants.STYLE_ENDSIZE, mxConstants.DEFAULT_MARKERSIZE)); offset = DrawMarker(marker, pt, pe, size, pen); } else { double dx = pt.X - p0.X; double dy = pt.Y - p0.Y; double dist = Math.Max(1, Math.Sqrt(dx * dx + dy * dy)); double nx = dx * penWidth * scale / dist; double ny = dy * penWidth * scale / dist; offset = new mxPoint(nx / 2, ny / 2); } // Applies offset to the point if (offset != null) { pe = pe.Clone(); pe.X += offset.X; pe.Y += offset.Y; offset = null; } // Draws the line using a GraphicsPath GraphicsPath path = new GraphicsPath(); double arcSize = mxConstants.LINE_ARCSIZE * scale; pt = p0; for (int i = 1; i < pts.Count - 1; i++) { mxPoint tmp = pts[i]; double dx = pt.X - tmp.X; double dy = pt.Y - tmp.Y; if ((rounded && i < pts.Count - 1) && (dx != 0 || dy != 0) && scale > 0.3) { // Draws a line from the last point to the current point with a // spacing of size off the current point into direction of the // last point double dist = Math.Sqrt(dx * dx + dy * dy); double nx1 = dx * Math.Min(arcSize, dist / 2) / dist; double ny1 = dy * Math.Min(arcSize, dist / 2) / dist; path.AddLine((float)(pt.X), (float)(pt.Y), (float)(tmp.X + nx1), (float)(tmp.Y + ny1)); // Draws a line from the last point to the current point with a // spacing of size off the current point into direction of the // last point mxPoint next = pts[i + 1]; dx = next.X - tmp.X; dy = next.Y - tmp.Y; dist = Math.Max(1, Math.Sqrt(dx * dx + dy * dy)); double nx2 = dx * Math.Min(arcSize, dist / 2) / dist; double ny2 = dy * Math.Min(arcSize, dist / 2) / dist; path.AddBezier( (float)(tmp.X + nx1), (float)(tmp.Y + ny1), (float)(tmp.X), (float)(tmp.Y), (float)(tmp.X), (float)(tmp.Y), (float)(tmp.X + nx2), (float)(tmp.Y + ny2)); tmp = new mxPoint(tmp.X + nx2, tmp.Y + ny2); } else { path.AddLine((float)(pt.X), (float)(pt.Y), (float)(tmp.X), (float)(tmp.Y)); } pt = tmp; } path.AddLine((float)(pt.X), (float)(pt.Y), (float)(pe.X), (float)(pe.Y)); g.DrawPath(pen, path); break; } } } }
/// <summary> /// Draws the given type of marker. /// </summary> /// <param name="type"></param> /// <param name="p0"></param> /// <param name="pe"></param> /// <param name="size"></param> /// <param name="pen"></param> /// <returns></returns> public mxPoint DrawMarker(Object type, mxPoint p0, mxPoint pe, float size, Pen pen) { Brush brush = new SolidBrush(pen.Color); float strokeWidth = (float) (pen.Width / scale); mxPoint offset = null; // Computes the norm and the inverse norm double dx = pe.X - p0.X; double dy = pe.Y - p0.Y; double dist = Math.Max(1, Math.Sqrt(dx * dx + dy * dy)); double absSize = size * scale; double nx = dx * absSize / dist; double ny = dy * absSize / dist; pe = (mxPoint)pe.Clone(); pe.X -= nx * strokeWidth / (2 * size); pe.Y -= ny * strokeWidth / (2 * size); nx *= 0.5 + strokeWidth / 2; ny *= 0.5 + strokeWidth / 2; if (type.Equals(mxConstants.ARROW_CLASSIC)) { GraphicsPath path = new GraphicsPath(); path.AddLines(new Point[]{ new Point((int)Math.Round(pe.X), (int)Math.Round(pe.Y)), new Point((int)Math.Round(pe.X - nx - ny / 2), (int)Math.Round(pe.Y - ny + nx / 2)), new Point((int)Math.Round(pe.X - nx * 3 / 4), (int)Math.Round(pe.Y - ny * 3 / 4)), new Point((int)Math.Round(pe.X + ny / 2 - nx), (int)Math.Round(pe.Y - ny - nx / 2))}); path.CloseFigure(); g.FillPath(brush, path); g.DrawPath(pen, path); offset = new mxPoint(-nx * 3 / 4, -ny * 3 / 4); } else if (type.Equals(mxConstants.ARROW_BLOCK)) { GraphicsPath path = new GraphicsPath(); path.AddLines(new Point[]{ new Point((int)Math.Round(pe.X), (int)Math.Round(pe.Y)), new Point((int)Math.Round(pe.X - nx - ny / 2), (int)Math.Round(pe.Y - ny + nx / 2)), new Point((int)Math.Round(pe.X + ny / 2 - nx), (int)Math.Round(pe.Y - ny - nx / 2))}); path.CloseFigure(); g.FillPath(brush, path); g.DrawPath(pen, path); offset = new mxPoint(-nx * 3 / 4, -ny * 3 / 4); } else if (type.Equals(mxConstants.ARROW_OPEN)) { nx *= 1.2; ny *= 1.2; g.DrawLine(pen, (int)Math.Round(pe.X - nx - ny / 2), (int)Math.Round(pe.Y - ny + nx / 2), (int)Math.Round(pe.X - nx / 6), (int)Math.Round(pe.Y - ny / 6)); g.DrawLine(pen, (int)Math.Round(pe.X - nx / 6), (int)Math.Round(pe.Y - ny / 6), (int)Math.Round(pe.X + ny / 2 - nx), (int)Math.Round(pe.Y - ny - nx / 2)); offset = new mxPoint(-nx / 4, -ny / 4); } else if (type.Equals(mxConstants.ARROW_OVAL)) { nx *= 1.2; ny *= 1.2; absSize *= 1.2; int cx = (int)Math.Round(pe.X - nx / 2); int cy = (int)Math.Round(pe.Y - ny / 2); int a = (int)Math.Round(absSize / 2); int a2 = (int)Math.Round(absSize); g.FillEllipse(brush, cx - a, cy - a, a2, a2); g.DrawEllipse(pen, cx - a, cy - a, a2, a2); offset = new mxPoint(-nx / 2, -ny / 2); } else if (type.Equals(mxConstants.ARROW_DIAMOND)) { nx *= 1.2; ny *= 1.2; Point[] poly = new Point[]{ new Point((int)Math.Round(pe.X + nx / 2), (int)Math.Round(pe.Y + ny / 2)), new Point((int)Math.Round(pe.X - ny / 2), (int)Math.Round(pe.Y + nx / 2)), new Point((int)Math.Round(pe.X - nx / 2), (int)Math.Round(pe.Y - ny / 2)), new Point((int)Math.Round(pe.X + ny / 2), (int)Math.Round(pe.Y - nx / 2))}; g.FillPolygon(brush, poly); g.DrawPolygon(pen, poly); } return offset; }
/// <summary> /// Transforms the given control point to an absolute point. /// </summary> public mxPoint TransformControlPoint(mxCellState state, mxPoint pt) { mxPoint orig = state.Origin; return new mxPoint(scale * (pt.X + translate.X + orig.X), scale * (pt.Y + translate.Y + orig.Y)); }
/// <summary> /// /// </summary> public void Begin() { currentPath = new GraphicsPath(); lastPoint = null; }
/// <summary> /// Returns the bounding box of the rotated rectangle. /// </summary> public static mxRectangle GetBoundingBox(mxRectangle rect, double rotation) { // TODO: Check use of GraphicsPath (see mxGdiCanvas.DrawText) mxRectangle result = null; if (rect != null && rotation != 0) { double rad = ToRadians(rotation); double cos = Math.Cos(rad); double sin = Math.Sin(rad); mxPoint cx = new mxPoint(rect.X + rect.Width / 2, rect.Y + rect.Height / 2); mxPoint p1 = new mxPoint(rect.X, rect.Y); mxPoint p2 = new mxPoint(rect.X + rect.Width, rect.Y); mxPoint p3 = new mxPoint(p2.X, rect.Y + rect.Height); mxPoint p4 = new mxPoint(rect.X, p3.Y); p1 = GetRotatedPoint(p1, cos, sin, cx); p2 = GetRotatedPoint(p2, cos, sin, cx); p3 = GetRotatedPoint(p3, cos, sin, cx); p4 = GetRotatedPoint(p4, cos, sin, cx); result = new mxRectangle((int)p1.X, (int)p1.Y, 0, 0); result.Add(new mxRectangle(p2.X, p2.Y, 0, 0)); result.Add(new mxRectangle(p3.X, p3.Y, 0, 0)); result.Add(new mxRectangle(p4.X, p4.Y, 0, 0)); } return result; }
/// <summary> /// Validates the points for the state of the given cell recursively if the /// cell is not collapsed and returns the bounding box of all visited states /// as a rectangle. /// </summary> public mxRectangle ValidatePoints(mxCellState parentState, Object cell) { mxIGraphModel model = graph.Model; mxCellState state = GetState(cell); mxRectangle bbox = null; if (state != null) { mxGeometry geo = graph.GetCellGeometry(cell); if (geo != null && model.IsEdge(cell)) { // Updates the points on the source terminal if its an edge mxCellState source = GetState(GetVisibleTerminal(cell, true)); if (source != null && model.IsEdge(source.Cell) && !model.IsAncestor(source, cell)) { mxCellState tmp = GetState(model.GetParent(source.Cell)); ValidatePoints(tmp, source.Cell); } // Updates the points on the target terminal if its an edge mxCellState target = GetState(GetVisibleTerminal(cell, false)); if (target != null && model.IsEdge(target.Cell) && !model.IsAncestor(target.Cell, cell)) { mxCellState tmp = GetState(model.GetParent(target.Cell)); ValidatePoints(tmp, target.Cell); } UpdateFixedTerminalPoints(state, source, target); UpdatePoints(state, geo.Points, source, target); UpdateFloatingTerminalPoints(state, source, target); UpdateEdgeBounds(state); state.AbsoluteOffset = GetPoint(state, geo); } else if (geo != null && geo.Relative && parentState != null && model.IsEdge(parentState.Cell)) { mxPoint origin = GetPoint(parentState, geo); if (origin != null) { state.X = origin.X; state.Y = origin.Y; origin.X = (origin.X / scale) - translate.X; origin.Y = (origin.Y / scale) - translate.Y; state.Origin = origin; childMoved(parentState, state); } } if (model.IsEdge(cell) || model.IsVertex(cell)) { UpdateLabelBounds(state); bbox = new mxRectangle(UpdateBoundingBox(state)); } } if (state != null && !graph.IsCellCollapsed(cell)) { int childCount = model.GetChildCount(cell); for (int i = 0; i < childCount; i++) { Object child = model.GetChildAt(cell, i); mxRectangle bounds = ValidatePoints(state, child); if (bounds != null) { if (bbox == null) { bbox = bounds; } else { bbox.Add(bounds); } } } } return(bbox); }
/// <summary> /// Rotates the given point by the given cos and sin. /// </summary> public static mxPoint GetRotatedPoint(mxPoint pt, double cos, double sin) { return GetRotatedPoint(pt, cos, sin, new mxPoint()); }
/// <summary> /// Returns the absolute, cummulated origin for the children inside the /// given parent. /// </summary> public mxPoint GetOrigin(Object cell) { mxPoint result = null; if (cell != null) { result = GetOrigin(GetParent(cell)); if (!IsEdge(cell)) { mxGeometry geo = GetGeometry(cell); if (geo != null) { result.X += geo.X; result.Y += geo.Y; } } } else { result = new mxPoint(); } return result; }
/// <summary> /// Returns a connection constraint that describes the given connection /// point. This result can then be passed to getConnectionPoint. /// </summary> /// <param name="edge">Cell state that represents the edge.</param> /// <param name="terminal">Cell state that represents the terminal.</param> /// <param name="source">Boolean indicating if the terminal is the source or target.</param> /// <returns></returns> public mxConnectionConstraint GetConnectionConstraint(mxCellState edge, mxCellState terminal, bool source) { mxPoint point = null; string key = (source) ? mxConstants.STYLE_EXIT_X : mxConstants.STYLE_ENTRY_X; if (edge.Style.ContainsKey(key)) { double x = mxUtils.GetDouble(edge.Style, key); key = (source) ? mxConstants.STYLE_EXIT_Y : mxConstants.STYLE_ENTRY_Y; if (edge.Style.ContainsKey(key)) { double y = mxUtils.GetDouble(edge.Style, key); point = new mxPoint(x, y); } } bool perimeter = false; if (point != null) { perimeter = mxUtils.IsTrue(edge.Style, (source) ? mxConstants.STYLE_EXIT_PERIMETER : mxConstants.STYLE_ENTRY_PERIMETER, true); } return new mxConnectionConstraint(point, perimeter); }
/// <summary> /// Constructs a new point at the location of the given point. /// </summary> /// <param name="point">Point that specifies the location.</param> public mxPoint(mxPoint point) : this(point.X, point.Y) { }
/// <summary> /// Parses the bounds, absolute points and label information from the style /// of the state into its respective fields and returns the label of the /// cell. /// </summary> public string ParseState(mxCellState state, bool edge) { Dictionary<string, object> style = state.Style; // Parses the bounds state.X = mxUtils.GetDouble(style, "x"); state.Y = mxUtils.GetDouble(style, "y"); state.Width = mxUtils.GetDouble(style, "width"); state.Height = mxUtils.GetDouble(style, "height"); // Parses the absolute points list List<mxPoint> pts = ParsePoints(mxUtils.GetString(style, "points")); if (pts.Count > 0) { state.AbsolutePoints = pts; } // Parses the label and label bounds string label = mxUtils.GetString(style, "label"); if (label != null && label.Length > 0) { mxPoint offset = new mxPoint(mxUtils.GetDouble(style, "dx"), mxUtils.GetDouble(style, "dy")); mxRectangle vertexBounds = (!edge) ? state : null; state.LabelBounds = mxUtils.GetLabelPaintBounds(label, style, mxUtils.IsTrue(style, "html", false), offset, vertexBounds, scale); } return label; }
/// <summary> /// Sets the sourcePoint or targetPoint to the given point and returns the /// new point. /// </summary> /// <param name="point">Point to be used as the new source or target point.</param> /// <param name="source">Boolean that specifies if the source or target point /// should be set.</param> /// <returns>Returns the new point.</returns> public mxPoint SetTerminalPoint(mxPoint point, bool source) { if (source) { sourcePoint = point; } else { targetPoint = point; } return point; }
/// <summary> /// Returns a point that defines the location of the intersection point between /// the perimeter and the line between the center of the shape and the given point. /// </summary> public mxPoint GetPerimeterPoint(mxCellState terminal, mxPoint next, bool orthogonal) { return GetPerimeterPoint(terminal, next, orthogonal, 0); }
/// <summary> /// Returns the nearest point in the list of absolute points or the center /// of the opposite terminal. /// </summary> /// <param name="edge">State that represents the edge.</param> /// <param name="opposite">State that represents the opposite terminal.</param> /// <param name="source">Boolean indicating if the next point for the source or target /// should be returned.</param> public mxPoint GetNextPoint(mxCellState edge, mxCellState opposite, bool source) { List<mxPoint> pts = edge.AbsolutePoints; mxPoint point = null; if (pts != null && (source || pts.Count > 2 || opposite == null)) { int count = pts.Count; int index = (source) ? Math.Min(1, count - 1) : Math.Max(0, count - 2); point = pts[index]; } if (point == null && opposite != null) { point = new mxPoint(opposite.GetCenterX(), opposite.GetCenterY()); } return point; }
/// <summary> /// Updates the given state using the bounding box of the absolute points. /// Also updates terminal distance, length and segments. /// </summary> /// <param name="state">Cell state whose bounds should be updated.</param> public void UpdateEdgeBounds(mxCellState state) { List <mxPoint> points = state.AbsolutePoints; mxPoint p0 = points[0]; mxPoint pe = points[points.Count - 1]; if (p0 == null || pe == null) { // Note: This is an error that normally occurs // if a connected edge has a null-terminal, ie. // edge.source == null or edge.target == null. states.Remove(state.Cell); } else { if (p0.X != pe.X || p0.Y != pe.Y) { double dx = pe.X - p0.X; double dy = pe.Y - p0.Y; state.TerminalDistance = Math.Sqrt(dx * dx + dy * dy); } else { state.TerminalDistance = 0; } double length = 0; double[] segments = new double[points.Count - 1]; mxPoint pt = p0; if (pt != null) { double minX = pt.X; double minY = pt.Y; double maxX = minX; double maxY = minY; for (int i = 1; i < points.Count; i++) { mxPoint tmp = points[i]; if (tmp != null) { double dx = pt.X - tmp.X; double dy = pt.Y - tmp.Y; double segment = Math.Sqrt(dx * dx + dy * dy); segments[i - 1] = segment; length += segment; pt = tmp; minX = Math.Min(pt.X, minX); minY = Math.Min(pt.Y, minY); maxX = Math.Max(pt.X, maxX); maxY = Math.Max(pt.Y, maxY); } } state.Length = length; state.Segments = segments; double markerSize = 1; // TODO: include marker size state.X = minX; state.Y = minY; state.Width = Math.Max(markerSize, maxX - minX); state.Height = Math.Max(markerSize, maxY - minY); } else { state.Length = 0; } } }
/// <summary> /// /// </summary> public void LineTo(double x, double y) { if (currentPath != null) { mxPoint nextPoint = new mxPoint(state.dx + x * state.scale, state.dy + y * state.scale); if (lastPoint != null) { currentPath.AddLine((float) lastPoint.X, (float) lastPoint.Y, (float) nextPoint.X, (float) nextPoint.Y); } lastPoint = nextPoint; } }
/// <summary> /// Sets the first or last point in the list of points depending on source. /// </summary> /// <param name="point">Point that represents the terminal point.</param> /// <param name="source">Boolean that specifies if the first or last point should /// be assigned.</param> public void SetAbsoluteTerminalPoint(mxPoint point, bool source) { if (source) { if (absolutePoints == null) { absolutePoints = new List<mxPoint>(); } if (absolutePoints == null || absolutePoints.Count == 0) { absolutePoints.Add(point); } else { absolutePoints[0] = point; } } else { if (absolutePoints == null) { absolutePoints = new List<mxPoint>(); absolutePoints.Add(null); absolutePoints.Add(point); } else if (absolutePoints.Count == 1) { absolutePoints.Add(point); } else { absolutePoints[absolutePoints.Count - 1] = point; } } }
/// <summary> /// Returns the absolute point on the edge for the given relative /// geometry as a point. The edge is represented by the given cell state. /// </summary> /// <param name="state">Represents the state of the parent edge.</param> /// <param name="geometry">Represents the relative location.</param> public mxPoint GetPoint(mxCellState state, mxGeometry geometry) { double x = state.GetCenterX(); double y = state.GetCenterY(); if (state.Segments != null && (geometry == null || geometry.Relative)) { double gx = (geometry != null) ? geometry.X / 2 : 0; int pointCount = state.AbsolutePoints.Count; double dist = (gx + 0.5) * state.Length; double[] segments = state.Segments; double segment = segments[0]; double length = 0; int index = 1; while (dist > length + segment && index < pointCount - 1) { length += segment; segment = segments[index++]; } double factor = (segment == 0) ? 0 : (dist - length) / segment; mxPoint p0 = state.AbsolutePoints[index - 1]; mxPoint pe = state.AbsolutePoints[index]; if (p0 != null && pe != null) { double gy = 0; double offsetX = 0; double offsetY = 0; if (geometry != null) { gy = geometry.Y; mxPoint offset = geometry.Offset; if (offset != null) { offsetX = offset.X; offsetY = offset.Y; } } double dx = pe.X - p0.X; double dy = pe.Y - p0.Y; double nx = (segment == 0) ? 0 : dy / segment; double ny = (segment == 0) ? 0 : dx / segment; x = p0.X + dx * factor + (nx * gy + offsetX) * scale; y = p0.Y + dy * factor - (ny * gy - offsetY) * scale; } } else if (geometry != null) { mxPoint offset = geometry.Offset; if (offset != null) { x += offset.X; y += offset.Y; } } return(new mxPoint(x, y)); }
/// <summary> /// Updates the given cell state. /// </summary> /// <param name="state"></param> public void UpdateCellState(mxCellState state, mxCellState source, mxCellState target) { state.AbsoluteOffset.X = 0; state.AbsoluteOffset.Y = 0; state.Origin.X = 0; state.Origin.Y = 0; state.Length = 0; mxIGraphModel model = graph.Model; mxCellState pState = GetState(model.GetParent(state.Cell)); if (pState != null) { state.Origin.X += pState.Origin.X; state.Origin.Y += pState.Origin.Y; } mxPoint offset = graph.GetChildOffsetForCell(state.Cell); if (offset != null) { state.Origin.X += offset.X; state.Origin.Y += offset.Y; } mxGeometry geo = graph.GetCellGeometry(state.Cell); if (geo != null) { if (!model.IsEdge(state.Cell)) { mxPoint origin = state.Origin; offset = geo.Offset; if (offset == null) { offset = EMPTY_POINT; } if (geo.Relative && pState != null) { if (model.IsEdge(pState.Cell)) { mxPoint orig = GetPoint(pState, geo); if (orig != null) { origin.X += (orig.X / scale) - pState.Origin.X - translate.X; origin.Y += (orig.Y / scale) - pState.Origin.Y - translate.Y; } } else { origin.X += geo.X * pState.Width / scale + offset.X; origin.Y += geo.Y * pState.Height / scale + offset.Y; } } else { state.AbsoluteOffset = new mxPoint(scale * offset.X, scale * offset.Y); origin.X += geo.X; origin.Y += geo.Y; } } state.X = scale * (translate.X + state.Origin.X); state.Y = scale * (translate.Y + state.Origin.Y); state.Width = scale * geo.Width; state.Height = scale * geo.Height; if (model.IsVertex(state.Cell)) { UpdateVertexState(state, geo); } if (model.IsEdge(state.Cell)) { UpdateEdgeState(state, geo, source, target); } } }
/// <summary> /// Constructs a copy of the given geometry. /// </summary> /// <param name="geometry">Geometry to construct a copy of.</param> public mxGeometry(mxGeometry geometry) : base(geometry.X, geometry.Y, geometry.Width, geometry .Height) { if (geometry.points != null) { points = new List<mxPoint>(geometry.points.Count); foreach (mxPoint pt in geometry.points) { points.Add(pt.Clone()); } } if (geometry.sourcePoint != null) { sourcePoint = geometry.sourcePoint.Clone(); } if (geometry.targetPoint != null) { targetPoint = geometry.targetPoint.Clone(); } if (geometry.offset != null) { offset = geometry.offset.Clone(); } if (geometry.alternateBounds != null) { alternateBounds = geometry.alternateBounds.Clone(); } relative = geometry.relative; }