/// <summary> /// Generate polygon from path /// </summary> /// <param name="path">path</param> /// <param name="averageScale">average scale of transform, this to decrease number of point generate for curve ...</param> /// <returns></returns> public double[][] Generate(DrawingPath path, double averageScale) { RawPolygonList polygonList = new RawPolygonList(); DrawingPathCommand[] commands = path.Commands; double[] coordinates = path.Coordinates; int commandCount = path.CommandCount; int coordinateCount = path.CoordinateCount; int coordinateIndex = 0; //foreach(PathCommand command in commands) for (int commandIndex = 0; commandIndex < commandCount; commandIndex++) { switch (commands[commandIndex]) { case DrawingPathCommand.MoveTo: case DrawingPathCommand.NewFigure: #region move to if (path.Commands[commandIndex + 1] == DrawingPathCommand.ArcTo) { coordinateIndex += 2; break; } polygonList.MoveTo(coordinates[coordinateIndex++], coordinates[coordinateIndex++]); break; #endregion case DrawingPathCommand.NewFigureAndCloseLast: #region close last and new figure // close last polygonList.CloseCurrentPolygon(); // move to polygonList.MoveTo(coordinates[coordinateIndex++], coordinates[coordinateIndex++]); break; #endregion case DrawingPathCommand.LineTo: #region line to polygonList.LineTo(coordinates[coordinateIndex++], coordinates[coordinateIndex++]); #endregion break; case DrawingPathCommand.ArcTo: #region arc to BuildArc(polygonList, coordinates[coordinateIndex - 2], // start x coordinates[coordinateIndex - 1], // start y coordinates[coordinateIndex++], // radius x coordinates[coordinateIndex++], // radius y coordinates[coordinateIndex++], // angle coordinates[coordinateIndex++] == DrawingPath.IsLargeArc, // is large arc coordinates[coordinateIndex++] == DrawingPath.IsSweepLeftSide, // is sweep left side coordinates[coordinateIndex++], // dest x coordinates[coordinateIndex++], // dest y averageScale); #endregion break; case DrawingPathCommand.CurveTo: #region curve to BuildCurve(polygonList, coordinates[coordinateIndex - 2], // start x coordinates[coordinateIndex - 1], // start y coordinates[coordinateIndex++], // control point 1 x coordinates[coordinateIndex++], // control point 1 y coordinates[coordinateIndex++], // control point 2 x coordinates[coordinateIndex++], // control point 2 y coordinates[coordinateIndex++], // end x coordinates[coordinateIndex++], // end y averageScale); #endregion break; case DrawingPathCommand.QuadraticTo: #region quadratic bezier BuildQuadratic(polygonList, coordinates[coordinateIndex - 2], // start x coordinates[coordinateIndex - 1], // start y coordinates[coordinateIndex++], // control point x coordinates[coordinateIndex++], // control point y coordinates[coordinateIndex++], // end x coordinates[coordinateIndex++], // end y averageScale); #endregion break; } } // finish generation polygonList.Finish(); return polygonList.RawDatas; }
/// <summary> /// Generate polygon from path /// </summary> /// <param name="path">path</param> /// <param name="averageScale">average scale of transform, this to decrease number of point generate for curve ...</param> /// <returns></returns> public double[][] Generate(DrawingPath path, double averageScale) { RawPolygonList polygonList = new RawPolygonList(); DrawingPathCommand[] commands = path.Commands; double[] coordinates = path.Coordinates; int commandCount = path.CommandCount; int coordinateCount = path.CoordinateCount; int coordinateIndex = 0; //foreach(PathCommand command in commands) for (int commandIndex = 0; commandIndex < commandCount; commandIndex++) { switch (commands[commandIndex]) { case DrawingPathCommand.MoveTo: case DrawingPathCommand.NewFigure: #region move to if (path.Commands[commandIndex + 1] == DrawingPathCommand.ArcTo) { coordinateIndex += 2; break; } polygonList.MoveTo(coordinates[coordinateIndex++], coordinates[coordinateIndex++]); break; #endregion case DrawingPathCommand.NewFigureAndCloseLast: #region close last and new figure // close last polygonList.CloseCurrentPolygon(); // move to polygonList.MoveTo(coordinates[coordinateIndex++], coordinates[coordinateIndex++]); break; #endregion case DrawingPathCommand.LineTo: #region line to polygonList.LineTo(coordinates[coordinateIndex++], coordinates[coordinateIndex++]); #endregion break; case DrawingPathCommand.ArcTo: #region arc to BuildArc(polygonList, coordinates[coordinateIndex - 2], // start x coordinates[coordinateIndex - 1], // start y coordinates[coordinateIndex++], // radius x coordinates[coordinateIndex++], // radius y coordinates[coordinateIndex++], // angle coordinates[coordinateIndex++] == DrawingPath.IsLargeArc, // is large arc coordinates[coordinateIndex++] == DrawingPath.IsSweepLeftSide, // is sweep left side coordinates[coordinateIndex++], // dest x coordinates[coordinateIndex++], // dest y averageScale); #endregion break; case DrawingPathCommand.CurveTo: #region curve to BuildCurve(polygonList, coordinates[coordinateIndex - 2], // start x coordinates[coordinateIndex - 1], // start y coordinates[coordinateIndex++], // control point 1 x coordinates[coordinateIndex++], // control point 1 y coordinates[coordinateIndex++], // control point 2 x coordinates[coordinateIndex++], // control point 2 y coordinates[coordinateIndex++], // end x coordinates[coordinateIndex++], // end y averageScale); #endregion break; case DrawingPathCommand.QuadraticTo: #region quadratic bezier BuildQuadratic(polygonList, coordinates[coordinateIndex - 2], // start x coordinates[coordinateIndex - 1], // start y coordinates[coordinateIndex++], // control point x coordinates[coordinateIndex++], // control point y coordinates[coordinateIndex++], // end x coordinates[coordinateIndex++], // end y averageScale); #endregion break; } } // finish generation polygonList.Finish(); return(polygonList.RawDatas); }
/// <summary> /// build arc to beziers /// </summary> /// <param name="polygonList">polygon List</param> /// <param name="centerX">coordinate X of center point</param> /// <param name="centerY">coordinate Y of center point</param> /// <param name="radiusX">radius X</param> /// <param name="radiusY">radius Y</param> /// <param name="angle">angle of arc</param> /// <param name="startAngle">angle start sweep</param> /// <param name="sweepAngle">angle sweep</param> /// <param name="scale">scale</param> private void BuildBezierArc(RawPolygonList polygonList, double centerX, double centerY, double radiusX, double radiusY, double angle, double startAngle, double sweepAngle, double scale) { #region variable int numberVertices; double tempCenterX = centerX; double tempCenterY = centerY; centerX = centerY = 0.0; double[] vertices = new double[26]; #endregion #region recalculate start angle and sweep angle startAngle = startAngle % TwoPi; if (sweepAngle > TwoPi) sweepAngle = TwoPi; else if (sweepAngle < -TwoPi) sweepAngle = -TwoPi; #endregion #region if sweep angle < 1e -10 then cannot draw arc if (Math.Abs(sweepAngle) < 1e-10) { numberVertices = 4; polygonList.LineTo( centerX + radiusX * Math.Cos(startAngle), centerY + radiusY * Math.Sin(startAngle)); polygonList.LineTo( centerX + radiusX * Math.Cos(startAngle + sweepAngle) , centerY + radiusY * Math.Sin(startAngle + sweepAngle)); return; } #endregion #region calculate all control point in bezier double totalSweep = 0.0, localSweep = 0.0; double prevSweep; numberVertices = 2; double x0, y0, tx, ty, sn, cs, tempX; bool done = false; #region when sweep angle less than 0 if (sweepAngle > 0) { do { prevSweep = totalSweep; localSweep = SmallStepAngle; totalSweep += localSweep; if (totalSweep >= sweepAngle - 0.01) { localSweep = sweepAngle - prevSweep; done = true; } #region create new control points in beziers x0 = Math.Cos(localSweep / 2.0); y0 = Math.Sin(localSweep / 2.0); tx = (1.0 - x0) * 4.0 / 3.0; ty = y0 - tx * x0 / y0; tempX = x0 + tx; //calculate sin and code of middle angle sn = Math.Sin(startAngle + localSweep / 2.0); cs = Math.Cos(startAngle + localSweep / 2.0); vertices[numberVertices - 2] = radiusX * (x0 * cs + y0 * sn); vertices[numberVertices - 1] = radiusY * (x0 * sn - y0 * cs); vertices[numberVertices] = radiusX * (tempX * cs + ty * sn); vertices[numberVertices + 1] = radiusY * (tempX * sn - ty * cs); vertices[numberVertices + 2] = radiusX * (tempX * cs - ty * sn); vertices[numberVertices + 3] = radiusY * (tempX * sn + ty * cs); vertices[numberVertices + 4] = radiusX * (x0 * cs - y0 * sn); vertices[numberVertices + 5] = radiusY * (x0 * sn + y0 * cs); #endregion numberVertices += 6; startAngle += localSweep; } while (!done && numberVertices < 26); } #endregion #region when negative sweep angle else { do { prevSweep = totalSweep; localSweep = SmallStepAngleNegative; totalSweep += localSweep; if (totalSweep <= sweepAngle + 0.01) { localSweep = sweepAngle - prevSweep; done = true; } #region create new control points in beziers x0 = Math.Cos(localSweep / 2.0); y0 = Math.Sin(localSweep / 2.0); tx = (1.0 - x0) * 4.0 / 3.0; ty = y0 - tx * x0 / y0; tempX = x0 + tx; //calculate sin and code of middle angle sn = Math.Sin(startAngle + localSweep / 2.0); cs = Math.Cos(startAngle + localSweep / 2.0); vertices[numberVertices - 2] = radiusX * (x0 * cs + y0 * sn); vertices[numberVertices - 1] = radiusY * (x0 * sn - y0 * cs); vertices[numberVertices] = radiusX * (tempX * cs + ty * sn); vertices[numberVertices + 1] = radiusY * (tempX * sn - ty * cs); vertices[numberVertices + 2] = radiusX * (tempX * cs - ty * sn); vertices[numberVertices + 3] = radiusY * (tempX * sn + ty * cs); vertices[numberVertices + 4] = radiusX * (x0 * cs - y0 * sn); vertices[numberVertices + 5] = radiusY * (x0 * sn + y0 * cs); #endregion numberVertices += 6; startAngle += localSweep; } while (!done && numberVertices < 26); } #endregion #endregion #region generate points from control points of bezier curves double cosAngle = Math.Cos(angle); double sinAngle = Math.Sin(angle); int i = 0; polygonList.MoveTo(vertices[0] * cosAngle - vertices[1] * sinAngle + tempCenterX, vertices[0] * sinAngle + vertices[1] * cosAngle + tempCenterY); while (i + 7 < numberVertices) { BuildCurve(polygonList, vertices[i + 0] * cosAngle - vertices[i + 1] * sinAngle + tempCenterX, vertices[i + 0] * sinAngle + vertices[i + 1] * cosAngle + tempCenterY, vertices[i + 2] * cosAngle - vertices[i + 3] * sinAngle + tempCenterX, vertices[i + 2] * sinAngle + vertices[i + 3] * cosAngle + tempCenterY, vertices[i + 4] * cosAngle - vertices[i + 5] * sinAngle + tempCenterX, vertices[i + 4] * sinAngle + vertices[i + 5] * cosAngle + tempCenterY, vertices[i + 6] * cosAngle - vertices[i + 7] * sinAngle + tempCenterX, vertices[i + 6] * sinAngle + vertices[i + 7] * cosAngle + tempCenterY, scale); i += 6; } #endregion }
/// <summary> /// build arc to beziers /// </summary> /// <param name="polygonList">polygon List</param> /// <param name="centerX">coordinate X of center point</param> /// <param name="centerY">coordinate Y of center point</param> /// <param name="radiusX">radius X</param> /// <param name="radiusY">radius Y</param> /// <param name="angle">angle of arc</param> /// <param name="startAngle">angle start sweep</param> /// <param name="sweepAngle">angle sweep</param> /// <param name="scale">scale</param> private void BuildBezierArc(RawPolygonList polygonList, double centerX, double centerY, double radiusX, double radiusY, double angle, double startAngle, double sweepAngle, double scale) { #region variable int numberVertices; double tempCenterX = centerX; double tempCenterY = centerY; centerX = centerY = 0.0; double[] vertices = new double[26]; #endregion #region recalculate start angle and sweep angle startAngle = startAngle % TwoPi; if (sweepAngle > TwoPi) { sweepAngle = TwoPi; } else if (sweepAngle < -TwoPi) { sweepAngle = -TwoPi; } #endregion #region if sweep angle < 1e -10 then cannot draw arc if (Math.Abs(sweepAngle) < 1e-10) { numberVertices = 4; polygonList.LineTo( centerX + radiusX * Math.Cos(startAngle), centerY + radiusY * Math.Sin(startAngle)); polygonList.LineTo( centerX + radiusX * Math.Cos(startAngle + sweepAngle) , centerY + radiusY * Math.Sin(startAngle + sweepAngle)); return; } #endregion #region calculate all control point in bezier double totalSweep = 0.0, localSweep = 0.0; double prevSweep; numberVertices = 2; double x0, y0, tx, ty, sn, cs, tempX; bool done = false; #region when sweep angle less than 0 if (sweepAngle > 0) { do { prevSweep = totalSweep; localSweep = SmallStepAngle; totalSweep += localSweep; if (totalSweep >= sweepAngle - 0.01) { localSweep = sweepAngle - prevSweep; done = true; } #region create new control points in beziers x0 = Math.Cos(localSweep / 2.0); y0 = Math.Sin(localSweep / 2.0); tx = (1.0 - x0) * 4.0 / 3.0; ty = y0 - tx * x0 / y0; tempX = x0 + tx; //calculate sin and code of middle angle sn = Math.Sin(startAngle + localSweep / 2.0); cs = Math.Cos(startAngle + localSweep / 2.0); vertices[numberVertices - 2] = radiusX * (x0 * cs + y0 * sn); vertices[numberVertices - 1] = radiusY * (x0 * sn - y0 * cs); vertices[numberVertices] = radiusX * (tempX * cs + ty * sn); vertices[numberVertices + 1] = radiusY * (tempX * sn - ty * cs); vertices[numberVertices + 2] = radiusX * (tempX * cs - ty * sn); vertices[numberVertices + 3] = radiusY * (tempX * sn + ty * cs); vertices[numberVertices + 4] = radiusX * (x0 * cs - y0 * sn); vertices[numberVertices + 5] = radiusY * (x0 * sn + y0 * cs); #endregion numberVertices += 6; startAngle += localSweep; }while (!done && numberVertices < 26); } #endregion #region when negative sweep angle else { do { prevSweep = totalSweep; localSweep = SmallStepAngleNegative; totalSweep += localSweep; if (totalSweep <= sweepAngle + 0.01) { localSweep = sweepAngle - prevSweep; done = true; } #region create new control points in beziers x0 = Math.Cos(localSweep / 2.0); y0 = Math.Sin(localSweep / 2.0); tx = (1.0 - x0) * 4.0 / 3.0; ty = y0 - tx * x0 / y0; tempX = x0 + tx; //calculate sin and code of middle angle sn = Math.Sin(startAngle + localSweep / 2.0); cs = Math.Cos(startAngle + localSweep / 2.0); vertices[numberVertices - 2] = radiusX * (x0 * cs + y0 * sn); vertices[numberVertices - 1] = radiusY * (x0 * sn - y0 * cs); vertices[numberVertices] = radiusX * (tempX * cs + ty * sn); vertices[numberVertices + 1] = radiusY * (tempX * sn - ty * cs); vertices[numberVertices + 2] = radiusX * (tempX * cs - ty * sn); vertices[numberVertices + 3] = radiusY * (tempX * sn + ty * cs); vertices[numberVertices + 4] = radiusX * (x0 * cs - y0 * sn); vertices[numberVertices + 5] = radiusY * (x0 * sn + y0 * cs); #endregion numberVertices += 6; startAngle += localSweep; }while (!done && numberVertices < 26); } #endregion #endregion #region generate points from control points of bezier curves double cosAngle = Math.Cos(angle); double sinAngle = Math.Sin(angle); int i = 0; polygonList.MoveTo(vertices[0] * cosAngle - vertices[1] * sinAngle + tempCenterX, vertices[0] * sinAngle + vertices[1] * cosAngle + tempCenterY); while (i + 7 < numberVertices) { BuildCurve(polygonList, vertices[i + 0] * cosAngle - vertices[i + 1] * sinAngle + tempCenterX, vertices[i + 0] * sinAngle + vertices[i + 1] * cosAngle + tempCenterY, vertices[i + 2] * cosAngle - vertices[i + 3] * sinAngle + tempCenterX, vertices[i + 2] * sinAngle + vertices[i + 3] * cosAngle + tempCenterY, vertices[i + 4] * cosAngle - vertices[i + 5] * sinAngle + tempCenterX, vertices[i + 4] * sinAngle + vertices[i + 5] * cosAngle + tempCenterY, vertices[i + 6] * cosAngle - vertices[i + 7] * sinAngle + tempCenterX, vertices[i + 6] * sinAngle + vertices[i + 7] * cosAngle + tempCenterY, scale); i += 6; } #endregion }