// 圆角代码
        public void Round(System.Drawing.Region region)
        {
            // -----------------------------------------------------------------------------------------------
            // 已经是.net提供给我们的最容易的改窗体的属性了(以前要自己调API)
            System.Drawing.Drawing2D.GraphicsPath oPath = new System.Drawing.Drawing2D.GraphicsPath();
            int x          = 0;
            int y          = 0;
            int thisWidth  = this.Width;
            int thisHeight = this.Height;
            int angle      = _Radius;

            if (angle > 0)
            {
                oPath.AddEllipse(x, y, this.Width, this.Height);        // 左下角
                oPath.CloseAllFigures();
                Region = new System.Drawing.Region(oPath);
            }
            // -----------------------------------------------------------------------------------------------
            else
            {
                oPath.AddLine(x + angle, y, thisWidth - angle, y);                   // 顶端
                oPath.AddLine(thisWidth, y + angle, thisWidth, thisHeight - angle);  // 右边
                oPath.AddLine(thisWidth - angle, thisHeight, x + angle, thisHeight); // 底边
                oPath.AddLine(x, y + angle, x, thisHeight - angle);
                oPath.Flatten();                                                     // 左边
                oPath.CloseAllFigures();
                Region = new System.Drawing.Region(oPath);
            }
        }
Beispiel #2
0
        //-------------------------------------------------------------------------------------------------------------------------------------------------
        //------------------------------------------- DRAWING CURVE  ------------------------------------------------------------------------------
        //-------------------------------------------------------------------------------------------------------------------------------------------------
        public void DrawCurve(List <System.Drawing.Point> points, Color color, float thickness, float worldScale)
        {
            System.Drawing.Drawing2D.GraphicsPath path = new System.Drawing.Drawing2D.GraphicsPath(System.Drawing.Drawing2D.FillMode.Winding);
            path.AddCurve(points.ToArray());
            path.Flatten();
            PointF[] finalPoints = path.PathPoints;
            path.Dispose();

            //Convert point to vector2
            if (finalPoints.Length < 2)
            {
                return;
            }

            float finalThickness = thickness * worldScale;

            if (finalThickness < 1)
            {
                finalThickness = 1;
            }

            Vector2D vectorThickNess = new Vector2D(finalThickness, finalThickness);

            for (int i = 1; i < finalPoints.Length; i++)
            {
                Gorgon.CurrentRenderTarget.Line((int)((float)finalPoints[i - 1].X * worldScale), (int)((float)finalPoints[i - 1].Y * worldScale),
                                                (int)(((float)finalPoints[i].X - (float)finalPoints[i - 1].X) * worldScale),
                                                (int)(((float)finalPoints[i].Y - (float)finalPoints[i - 1].Y) * worldScale), color, vectorThickNess);
            }
        }
Beispiel #3
0
        /// <summary>
        /// takes in a parsed path and returns a list of points that can be used to draw the path
        /// </summary>
        /// <returns>The drawing points.</returns>
        /// <param name="segments">Segments.</param>
        public Vector2[] GetDrawingPoints(List <SvgPathSegment> segments, float flatness = 3)
        {
            var path = new System.Drawing.Drawing2D.GraphicsPath();

            for (var j = 0; j < segments.Count; j++)
            {
                var segment = segments[j];
                if (segment is SvgMoveToSegment)
                {
                    path.StartFigure();
                }
                else if (segment is SvgCubicCurveSegment)
                {
                    var cubicSegment = segment as SvgCubicCurveSegment;
                    path.AddBezier(ToDrawPoint(segment.Start), ToDrawPoint(cubicSegment.FirstCtrlPoint),
                                   ToDrawPoint(cubicSegment.SecondCtrlPoint), ToDrawPoint(segment.End));
                }
                else if (segment is SvgClosePathSegment)
                {
                    // important for custom line caps. Force the path the close with an explicit line, not just an implicit close of the figure.
                    if (path.PointCount > 0 && !path.PathPoints[0].Equals(path.PathPoints[path.PathPoints.Length - 1]))
                    {
                        var i = path.PathTypes.Length - 1;
                        while (i >= 0 && path.PathTypes[i] > 0)
                        {
                            i--;
                        }
                        if (i < 0)
                        {
                            i = 0;
                        }
                        path.AddLine(path.PathPoints[path.PathPoints.Length - 1], path.PathPoints[i]);
                    }

                    path.CloseFigure();
                }
                else if (segment is SvgLineSegment)
                {
                    path.AddLine(ToDrawPoint(segment.Start), ToDrawPoint(segment.End));
                }
                else if (segment is SvgQuadraticCurveSegment)
                {
                    var quadSegment = segment as SvgQuadraticCurveSegment;
                    path.AddBezier(ToDrawPoint(segment.Start), ToDrawPoint(quadSegment.FirstCtrlPoint),
                                   ToDrawPoint(quadSegment.SecondCtrlPoint), ToDrawPoint(segment.End));
                }
                else
                {
                    Debug.Warn("unknown type in getDrawingPoints");
                }
            }

            path.Flatten(new System.Drawing.Drawing2D.Matrix(), flatness);

            return(System.Array.ConvertAll(path.PathPoints, i => new Vector2(i.X, i.Y)));
        }
Beispiel #4
0
 public void TabControl7_GetTabRegion(object sender, Thinksea.Windows.Forms.MdiTabControl.TabControl.GetTabRegionEventArgs e)
 {
     System.Drawing.Drawing2D.GraphicsPath x = new System.Drawing.Drawing2D.GraphicsPath();
     x.AddArc(new Rectangle(0, 0, e.TabWidth, e.TabHeight * 2 / 3), 0, -180);
     x.Flatten();
     System.Drawing.Point[] temp_array = e.Points;
     Array.Resize(ref temp_array, x.PointCount);
     e.Points = temp_array;
     for (int i = 0; i <= x.PointCount - 1; i++)
     {
         e.Points[i] = new Point(System.Convert.ToInt32(x.PathPoints[i].X), System.Convert.ToInt32(x.PathPoints[i].Y));
     }
 }
Beispiel #5
0
		/// <summary>
		/// takes in a parsed path and returns a list of points that can be used to draw the path
		/// </summary>
		/// <returns>The drawing points.</returns>
		/// <param name="segments">Segments.</param>
		public Vector2[] getDrawingPoints( List<SvgPathSegment> segments, float flatness = 3 )
		{
			var path = new System.Drawing.Drawing2D.GraphicsPath();
			for( var j = 0; j < segments.Count; j++ )
			{
				var segment = segments[j];
				if( segment is SvgMoveToSegment )
				{
					path.StartFigure();
				}
				else if( segment is SvgCubicCurveSegment )
				{
					var cubicSegment = segment as SvgCubicCurveSegment;
					path.AddBezier( toDrawPoint( segment.start ), toDrawPoint( cubicSegment.firstCtrlPoint ), toDrawPoint( cubicSegment.secondCtrlPoint ), toDrawPoint( segment.end ) );
				}
				else if( segment is SvgClosePathSegment )
				{
					// important for custom line caps. Force the path the close with an explicit line, not just an implicit close of the figure.
					if( path.PointCount > 0 && !path.PathPoints[0].Equals( path.PathPoints[path.PathPoints.Length - 1] ) )
					{
						var i = path.PathTypes.Length - 1;
						while( i >= 0 && path.PathTypes[i] > 0 )
							i--;
						if( i < 0 )
							i = 0;
						path.AddLine( path.PathPoints[path.PathPoints.Length - 1], path.PathPoints[i] );
					}
					path.CloseFigure();
				}
				else if( segment is SvgLineSegment )
				{
					path.AddLine( toDrawPoint( segment.start ), toDrawPoint( segment.end ) );
				}
				else if( segment is SvgQuadraticCurveSegment )
				{
					var quadSegment = segment as SvgQuadraticCurveSegment;
					path.AddBezier( toDrawPoint( segment.start ), toDrawPoint( quadSegment.firstCtrlPoint ), toDrawPoint( quadSegment.secondCtrlPoint ), toDrawPoint( segment.end ) );
				}
				else
				{
					Debug.warn( "unknown type in getDrawingPoints" );
				}
			}

			path.Flatten( new System.Drawing.Drawing2D.Matrix(), flatness );

			return System.Array.ConvertAll( path.PathPoints, i => new Vector2( i.X, i.Y ) );
		}
Beispiel #6
0
        public override System.Drawing.RectangleF GetTransformedVObjectBounds()
        {
            //
            // We cannot use evident way to get bounds of the Path, something like this:
            //
            // return this.Path.GetBounds(_matrix, _pen);
            //
            // because this implementation returns wrong values. It seems that the GraphicsPath algorithm
            // first finds bounds and after that applies matrix! Also it returns wrong (too large)
            // rectangle for curves (e.g. for ellipse). To avoid first issue we have to clone path
            // and manually transform it. To avoid second problem we have to use Flatten() method.
            //

            using (System.Drawing.Drawing2D.GraphicsPath c = (System.Drawing.Drawing2D.GraphicsPath) this.Path.Clone())
            {
                c.Flatten(_matrix, 1.0f);
                return(c.GetBounds(_identityMatrix, _pen));
            }
        }
        /// <summary>
        /// Repaints the form with cool background and stuff
        /// </summary>
        /// <param name="graph">The graphics object to paint to, the element will be drawn to 0,0</param>
        override public void Paint(Graphics graph)
        {
            //Draws Rectangular Shapes
            if (Shape == ModelShapes.Arrow)
            {
                _arrowPath = new System.Drawing.Drawing2D.GraphicsPath();

                //Draws the basic shape
                Pen arrowPen;
                if (Highlight < 1)
                    arrowPen = new Pen(Color.Cyan, 3F);
                else
                    arrowPen = new Pen(Color.Black, 3F);

                //Draws the curved arrow
                Point[] lineArray = new Point[4];
                lineArray[0] = new Point(_startPoint.X, _startPoint.Y);
                lineArray[1] = new Point(_startPoint.X - ((_startPoint.X - _stopPoint.X) / 3), _startPoint.Y);
                lineArray[2] = new Point(_stopPoint.X - ((_stopPoint.X - _startPoint.X) / 3), _stopPoint.Y);
                lineArray[3] = new Point(_stopPoint.X, _stopPoint.Y);
                graph.DrawBeziers(arrowPen, lineArray);
                _arrowPath.AddBeziers(lineArray);
                _arrowPath.Flatten();
 
                //Draws the arrow head
                Point[] arrowArray = new Point[3];
                arrowArray[0] = _stopPoint;
                arrowArray[1] = new Point(_stopPoint.X - (5 * Math.Sign(_stopPoint.X - _startPoint.X)),_stopPoint.Y - 2);
                arrowArray[2] = new Point(_stopPoint.X - (5 * Math.Sign(_stopPoint.X - _startPoint.X)), _stopPoint.Y + 2);
                graph.DrawPolygon(arrowPen,arrowArray);

                //Garbage collection
                arrowPen.Dispose();
            }
        }
Beispiel #8
0
		protected void PaintOneRange(int axisNumber, Graphics g, IPlotArea layer, IPlotRange range, Processed2DPlotData pdata)
		{
			const double logicalClampMinimum = -10;
			const double logicalClampMaximum = 11;

			_skipFrequency = Math.Max(1, _skipFrequency);

			// Plot error bars for the dependent variable (y)
			var ptArray = pdata.PlotPointsInAbsoluteLayerCoordinates;
			var posErrCol = PositiveErrorColumn;
			var negErrCol = NegativeErrorColumn;

			if (null != posErrCol && !typeof(double).IsAssignableFrom(posErrCol.ItemType))
				posErrCol = null; // TODO make this an runtime paint error to be reported

			if (null != negErrCol && !typeof(double).IsAssignableFrom(negErrCol.ItemType))
				negErrCol = null; // TODO make this an runtime paint error to be reported

			if (posErrCol == null && negErrCol == null)
				return; // nothing to do if both error columns are null

			var strokePen = _pen.Clone();

			System.Drawing.Drawing2D.GraphicsPath errorBarPath = new System.Drawing.Drawing2D.GraphicsPath();

			Region oldClippingRegion = g.Clip;
			Region newClip = (Region)oldClippingRegion.Clone();


			int lower = range.LowerBound;
			int upper = range.UpperBound;

			for (int j = lower; j < upper; j += _skipFrequency)
			{
				int originalRowIndex = range.GetOriginalRowIndexFromPlotPointIndex(j);
				double symbolSize = null == _cachedSymbolSizeForIndexFunction ? _symbolSize : _cachedSymbolSizeForIndexFunction(originalRowIndex);
				strokePen.Width = (_lineWidth1Offset + _lineWidth1Factor * symbolSize);

				if (null != _cachedColorForIndexFunction)
					strokePen.Color = GdiColorHelper.ToNamedColor(_cachedColorForIndexFunction(originalRowIndex), "VariableColor");
				if (null != strokePen.EndCap)
					strokePen.EndCap = strokePen.EndCap.WithMinimumAbsoluteAndRelativeSize(symbolSize * _endCapSizeFactor + _endCapSizeOffset, 1 + 1E-6);

				AltaxoVariant vMeanPhysical = pdata.GetPhysical(axisNumber, originalRowIndex);
				Logical3D logicalMean = layer.GetLogical3D(pdata, originalRowIndex);
				logicalMean.RX += _cachedLogicalShiftX;
				logicalMean.RY += _cachedLogicalShiftY;

				if (!Calc.RMath.IsInIntervalCC(logicalMean.RX, logicalClampMinimum, logicalClampMaximum))
					continue;
				if (!Calc.RMath.IsInIntervalCC(logicalMean.RY, logicalClampMinimum, logicalClampMaximum))
					continue;

				var vMeanLogical = logicalMean.GetR(axisNumber);

				Logical3D logicalPos = logicalMean;
				Logical3D logicalNeg = logicalMean;
				bool logicalPosValid = false;
				bool logicalNegValid = false;

				switch (_meaningOfValues)
				{
					case ValueInterpretation.AbsoluteError:
						{
							if (posErrCol != null)
							{
								var vPosLogical = layer.Scales[axisNumber].PhysicalVariantToNormal(vMeanPhysical + Math.Abs(posErrCol[originalRowIndex]));
								vPosLogical = Calc.RMath.ClampToInterval(vPosLogical, logicalClampMinimum, logicalClampMaximum);
								logicalPos.SetR(axisNumber, vPosLogical);
								logicalPosValid = !logicalPos.IsNaN && vPosLogical != vMeanLogical;
							}

							if (negErrCol != null)
							{
								var vNegLogical = layer.Scales[axisNumber].PhysicalVariantToNormal(vMeanPhysical - Math.Abs(negErrCol[originalRowIndex]));
								vNegLogical = Calc.RMath.ClampToInterval(vNegLogical, logicalClampMinimum, logicalClampMaximum);
								logicalNeg.SetR(axisNumber, vNegLogical);
								logicalNegValid = !logicalNeg.IsNaN && vNegLogical != vMeanLogical;
							}
						}
						break;

					case ValueInterpretation.RelativeError:
						{
							if (posErrCol != null)
							{
								var vPosLogical = layer.Scales[axisNumber].PhysicalVariantToNormal(vMeanPhysical * (1 + Math.Abs(posErrCol[originalRowIndex])));
								vPosLogical = Calc.RMath.ClampToInterval(vPosLogical, logicalClampMinimum, logicalClampMaximum);
								logicalPos.SetR(axisNumber, vPosLogical);
								logicalPosValid = !logicalPos.IsNaN && vPosLogical != vMeanLogical;
							}

							if (negErrCol != null)
							{
								var vNegLogical = layer.Scales[axisNumber].PhysicalVariantToNormal(vMeanPhysical * (1 - Math.Abs(negErrCol[originalRowIndex])));
								vNegLogical = Calc.RMath.ClampToInterval(vNegLogical, logicalClampMinimum, logicalClampMaximum);
								logicalNeg.SetR(axisNumber, vNegLogical);
								logicalNegValid = !logicalNeg.IsNaN && vNegLogical != vMeanLogical;
							}
						}
						break;

					case ValueInterpretation.AbsoluteValue:
						{
							if (posErrCol != null)
							{
								var vPosLogical = layer.Scales[axisNumber].PhysicalVariantToNormal(posErrCol[originalRowIndex]);
								vPosLogical = Calc.RMath.ClampToInterval(vPosLogical, logicalClampMinimum, logicalClampMaximum);
								logicalPos.SetR(axisNumber, vPosLogical);
								logicalPosValid = !logicalPos.IsNaN && vPosLogical != vMeanLogical;
							}

							if (negErrCol != null)
							{
								var vNegLogical = layer.Scales[axisNumber].PhysicalVariantToNormal(negErrCol[originalRowIndex]);
								vNegLogical = Calc.RMath.ClampToInterval(vNegLogical, logicalClampMinimum, logicalClampMaximum);
								logicalNeg.SetR(axisNumber, vNegLogical);
								logicalNegValid = !logicalNeg.IsNaN && vNegLogical != vMeanLogical;
							}

							if (object.ReferenceEquals(negErrCol, posErrCol))
							{
								logicalNegValid = false; // then we need only to plot the positive column, since both colums are identical
							}
						}
						break;
				} // end switch

				if (!(logicalPosValid || logicalNegValid))
					continue; // nothing to do for this point if both pos and neg logical point are invalid.

				if (logicalNegValid)
				{
					errorBarPath.Reset();
					layer.CoordinateSystem.GetIsoline(errorBarPath, logicalMean, logicalNeg);
					PointF[] shortenedPathPoints = null;
					bool shortenedPathPointsCalculated = false;
					if (_useSymbolGap)
					{
						double gap = _symbolGapOffset + _symbolGapFactor * symbolSize;
						if (gap > 0)
						{
							errorBarPath.Flatten();
							var pathPoints = errorBarPath.PathPoints;
							shortenedPathPoints = GdiExtensionMethods.ShortenedBy(pathPoints, RADouble.NewAbs(gap / 2), RADouble.NewAbs(0));
							shortenedPathPointsCalculated = true;
							if (null == shortenedPathPoints && _forceVisibilityOfEndCap && !(strokePen.EndCap is Altaxo.Graph.Gdi.LineCaps.FlatCap))
							{
								var totalLineLength = GdiExtensionMethods.TotalLineLength(pathPoints);
								var shortTheLineBy = Math.Max(0, totalLineLength - 0.125 * strokePen.Width);
								shortenedPathPoints = GdiExtensionMethods.ShortenedBy(pathPoints, RADouble.NewAbs(shortTheLineBy), RADouble.NewAbs(0));
							}
						}
					}

					if (shortenedPathPointsCalculated)
					{
						if (null != shortenedPathPoints)
						{
							g.DrawLines(strokePen, shortenedPathPoints);
						}
					}
					else
					{
						g.DrawPath(strokePen, errorBarPath);
					}
				}

				if (logicalPosValid)
				{
					errorBarPath.Reset();
					layer.CoordinateSystem.GetIsoline(errorBarPath, logicalMean, logicalPos);
					PointF[] shortenedPathPoints = null;
					bool shortenedPathPointsCalculated = false;


					if (_useSymbolGap)
					{
						double gap = _symbolGapOffset + _symbolGapFactor * symbolSize;
						if (gap > 0)
						{
							errorBarPath.Flatten();
							var pathPoints = errorBarPath.PathPoints;
							shortenedPathPoints = GdiExtensionMethods.ShortenedBy(pathPoints, RADouble.NewAbs(gap / 2), RADouble.NewAbs(0));
							shortenedPathPointsCalculated = true;
							if (null == shortenedPathPoints && _forceVisibilityOfEndCap && !(strokePen.EndCap is Altaxo.Graph.Gdi.LineCaps.FlatCap))
							{
								var totalLineLength = GdiExtensionMethods.TotalLineLength(pathPoints);
								var shortTheLineBy = Math.Max(0, totalLineLength - 0.125 * strokePen.Width);
								shortenedPathPoints = GdiExtensionMethods.ShortenedBy(pathPoints, RADouble.NewAbs(shortTheLineBy), RADouble.NewAbs(0));
							}

						}
					}

					if (shortenedPathPointsCalculated)
					{
						if (null != shortenedPathPoints)
						{
							g.DrawLines(strokePen, shortenedPathPoints);
						}
					}
					else
					{
						g.DrawPath(strokePen, errorBarPath);
					}
				}
			}

			g.Clip = oldClippingRegion;

		}
Beispiel #9
0
        /// <summary>
        /// This is the method that actually does the work.
        /// </summary>
        /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param>
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            string S = "";

            DA.GetData(0, ref S);
            string fontString = "";

            DA.GetData(1, ref fontString);
            bool close = false;

            DA.GetData(2, ref close);
            double size = 0.0;

            DA.GetData(3, ref size);
            double precision = 0.0;

            DA.GetData(4, ref precision);
            Plane basePlane = new Plane();

            DA.GetData(5, ref basePlane);
            int J = 0;

            DA.GetData(6, ref J);

            float fS         = size == 0 ? 1 : (float)size;
            Font  local_font = new Font(fontString, (float)fS);

            System.Drawing.Drawing2D.GraphicsPath path = new System.Drawing.Drawing2D.GraphicsPath();
            path.AddString(S, local_font.FontFamily, (int)local_font.Style, local_font.Size, new PointF(0, 0), new StringFormat());

            System.Drawing.Drawing2D.Matrix matrix = new System.Drawing.Drawing2D.Matrix(); // transformation matrix
            matrix.Reset();                                                                 // build identity matrix

            // __________________ autoList part __________________

            // variable for the list
            Grasshopper.Kernel.Special.GH_ValueList vList;
            // tries to cast input as list
            try
            {
                // if the list is not the first parameter then change Input[6] to the corresponding value
                vList = Params.Input[6].Sources[0] as Grasshopper.Kernel.Special.GH_ValueList;

                // check if the list must be created

                if (!vList.NickName.Equals("Justification"))
                {
                    vList.ClearData();
                    vList.ListItems.Clear();
                    vList.NickName = "Justification";

                    for (int i = 0; i < justification.Length; i++)
                    {
                        vList.ListItems.Add(new Grasshopper.Kernel.Special.GH_ValueListItem(justification[i][0], justification[i][1]));
                    }

                    //var item1 = new Grasshopper.Kernel.Special.GH_ValueListItem("TopLeft", "0");
                    //var item2 = new Grasshopper.Kernel.Special.GH_ValueListItem("MiddleLeft", "1");
                    //var item3 = new Grasshopper.Kernel.Special.GH_ValueListItem("BottomLeft", "2");
                    //var item4 = new Grasshopper.Kernel.Special.GH_ValueListItem("TopCenter", "3");
                    //var item5 = new Grasshopper.Kernel.Special.GH_ValueListItem("MiddleCenter", "4");
                    //var item6 = new Grasshopper.Kernel.Special.GH_ValueListItem("BottomCenter", "5");
                    //var item7 = new Grasshopper.Kernel.Special.GH_ValueListItem("TopRight", "6");
                    //var item8 = new Grasshopper.Kernel.Special.GH_ValueListItem("MiddleRight", "7");
                    //var item9 = new Grasshopper.Kernel.Special.GH_ValueListItem("BottomRight", "8");
                    //vList.ListItems.Add(item1);
                    //vList.ListItems.Add(item2);
                    //vList.ListItems.Add(item3);
                    //vList.ListItems.Add(item4);
                    //vList.ListItems.Add(item5);
                    //vList.ListItems.Add(item6);
                    //vList.ListItems.Add(item7);
                    //vList.ListItems.Add(item8);
                    //vList.ListItems.Add(item9);

                    vList.ListItems[0].Value.CastTo(out J);
                }
            }
            catch
            {
                // handles anything that is not a value list
            }

            // ______________ text justification ______________

            RectangleF rec = path.GetBounds(); // bounding rectangle for text
            float      dX = Convert.ToSingle(rec.Width * -0.5), dY = Convert.ToSingle(rec.Height * 0.5);

            switch (J)
            {
            case 0:    // top left
                dX = 0;
                dY = fS;
                break;

            case 1:     // middle left
                dX = 0;
                dY = Convert.ToSingle((-rec.Height) * 0.5 + fS);
                break;

            case 2:      // bottom left
                dX = 0;
                dY = Convert.ToSingle(-rec.Height + fS * 0.5);
                break;

            case 3:     // top center
                dX = Convert.ToSingle(rec.Width * -0.5);
                dY = fS;
                break;

            case 4:     // middle center
                dX = Convert.ToSingle(rec.Width * -0.5);
                dY = Convert.ToSingle((-rec.Height) * 0.5 + fS);
                break;

            case 5:     // bottom center
                dX = Convert.ToSingle(rec.Width * -0.5);
                dY = Convert.ToSingle(-rec.Height + fS * 0.5);
                break;

            case 6:     // top right
                dX = Convert.ToSingle(rec.Width * -1);
                dY = fS;
                break;

            case 7:     // middle right
                dX = Convert.ToSingle(rec.Width * -1);
                dY = Convert.ToSingle((-rec.Height) * 0.5 + fS);
                break;

            case 8:     // bottom right
                dX = Convert.ToSingle(rec.Width * -1);
                dY = Convert.ToSingle(-rec.Height + fS * 0.5);
                break;
            }
            //float dX = Convert.ToSingle(rec.Width * -0.5);
            //float dY = Convert.ToSingle(rec.Height * 0.5);
            System.Drawing.Drawing2D.Matrix mTrans = new System.Drawing.Drawing2D.Matrix(1, 0, 0, 1, dX, dY); // build transformation matrix
            path.Transform(mTrans);                                                                           // transform text path

            // ______________ convert to polylines ______________

            path.Flatten(matrix, (float)(size / precision)); // turns the path into a polyline that approximates the path

            PointF[]        pts     = path.PathPoints;       // get path points
            Byte[]          tps     = path.PathTypes;        // get path point types
            List <Polyline> strokes = new List <Polyline>(); // List for strokes
            Polyline        stroke  = new Polyline();

            Byte typ_start = Convert.ToByte(System.Drawing.Drawing2D.PathPointType.Start);// find start points condition

            // the conversion loop
            for (int i = 0; i < pts.Length; i++)
            {
                // if a start point is found, and the existing polyline is not null nor a single point,
                // add polyline to the strokes and create a new polyline
                if (tps[i] == typ_start)
                {
                    if (stroke != null && stroke.Count > 1)
                    {
                        if (close && !stroke.IsClosed)
                        {
                            stroke.Add(stroke[0]);                            // close polyline if necessary
                        }
                        strokes.Add(stroke);
                    }
                    stroke = new Polyline();
                }
                // in any other case add the next point to a polyline
                stroke.Add(pts[i].X, -pts[i].Y + size, 0);
                // add last stroke to the list
                if (i == pts.Length - 1)
                {
                    if (close && !stroke.IsClosed)
                    {
                        stroke.Add(stroke[0]);                            // and close it if necessary
                    }
                    strokes.Add(stroke);
                }
            }


            // ______________ align strokes to given plane ______________

            Transform align = Transform.PlaneToPlane(Plane.WorldXY, basePlane); // align transformation

            for (int j = 0; j < strokes.Count; j++)
            {
                strokes[j].Transform(align);
            }

            DA.SetDataList(0, strokes);
        }