Esempio n. 1
0
        /// <summary>
        /// Constructs the optimal ITransform2D object for the supplied x and y axes.
        /// </summary>
        /// <param name="xAxis">The xAxis to use for the world to physical transform.</param>
        /// <param name="yAxis">The yAxis to use for the world to physical transform.</param>
        /// <returns>An ITransform2D derived object for converting from world to physical coordinates.</returns>
        public static ITransform2D GetTransformer(PhysicalAxis xAxis, PhysicalAxis yAxis)
        {
            ITransform2D ret = null;

            //			if (xAxis.Axis.IsLinear && yAxis.Axis.IsLinear && !xAxis.Axis.Reversed && !yAxis.Axis.Reversed)
            //				ret = new FastTransform2D( xAxis, yAxis );
            //			else
            //				ret = new DefaultTransform2D( xAxis, yAxis );

            ret = new DefaultTransform2D (xAxis, yAxis);
            return ret;
        }
Esempio n. 2
0
        /// <summary>
        /// Construct from a fully-blown physical axis.
        /// </summary>
        /// <param name="physicalAxis">the physical axis to get initial values from.</param>
        public PageAlignedPhysicalAxis(PhysicalAxis physicalAxis)
        {
            worldMin_ = physicalAxis.Axis.WorldMin;
            worldMax_ = physicalAxis.Axis.WorldMax;
            worldLength_ = worldMax_ - worldMin_;

            if (physicalAxis.PhysicalMin.X == physicalAxis.PhysicalMax.X) {
                pMin_ = physicalAxis.PhysicalMin.Y;
                pMax_ = physicalAxis.PhysicalMax.Y;
            }
            else if (physicalAxis.PhysicalMin.Y == physicalAxis.PhysicalMax.Y) {
                pMin_ = physicalAxis.PhysicalMin.X;
                pMax_ = physicalAxis.PhysicalMax.X;
            }
            else {
                throw new XwPlotException( "Physical axis is not page aligned" );
            }
            pLength_ = pMax_ - pMin_;
        }
Esempio n. 3
0
        /// <summary>
        /// Draws the line plot using the Context and Physical Axes provided
        /// </summary>
        /// <param name="ctx">The Drawing Context with which to draw.</param>
        /// <param name="xAxis">The X-Axis to draw against.</param>
        /// <param name="yAxis">The Y-Axis to draw against.</param>
        /// <param name="drawShadow">If true draw the shadow for the line. If false, draw line.</param>
        public void DrawLineOrShadow(Context ctx, PhysicalAxis xAxis, PhysicalAxis yAxis, bool drawShadow)
        {
            SequenceAdapter data = new SequenceAdapter (DataSource, DataMember, OrdinateData, AbscissaData);

            ITransform2D t = Transform2D.GetTransformer (xAxis, yAxis);

            int numberPoints = data.Count;

            if (data.Count == 0) {
                return;
            }

            ctx.Save ();
            ctx.SetLineWidth (lineWidth);
            if (lineDash != null) {
                ctx.SetLineDash (0, lineDash);
            }

            if (numberPoints == 1) {
                Point physical = t.Transform (data[0]);

                if (drawShadow) {
                    ctx.SetColor (shadowColor);
                    ctx.MoveTo (physical.X - 0.5 + ShadowOffset.X, physical.Y + ShadowOffset.Y);
                    ctx.LineTo (physical.X + 0.5 + ShadowOffset.X, physical.Y + ShadowOffset.Y);
                    ctx.Stroke ();
                }
                else {
                    ctx.SetColor (lineColor);
                    ctx.MoveTo (physical.X-0.5, physical.Y);
                    ctx.LineTo (physical.X+0.5, physical.Y);
                    ctx.Stroke ();
                }
            }
            else {
                // prepare for clipping
                double leftCutoff = xAxis.PhysicalToWorld (xAxis.PhysicalMin, false);
                double rightCutoff = xAxis.PhysicalToWorld (xAxis.PhysicalMax, false);
                if (leftCutoff > rightCutoff) {
                    Utils.Swap (ref leftCutoff, ref rightCutoff);
                }
                if (drawShadow) {
                    // correct cut-offs
                    double shadowCorrection =
                        xAxis.PhysicalToWorld (ShadowOffset, false) - xAxis.PhysicalToWorld (new Point(0,0), false);
                    leftCutoff -= shadowCorrection;
                    rightCutoff -= shadowCorrection;
                }

                for (int i = 1; i < numberPoints; ++i) {
                    // check to see if any values null. If so, then continue.
                    double dx1 = data[i-1].X;
                    double dx2 = data[i].X;
                    double dy1 = data[i-1].Y;
                    double dy2 = data[i].Y;
                    if (Double.IsNaN(dx1) || Double.IsNaN(dy1) || Double.IsNaN(dx2) || Double.IsNaN(dy2)) {
                        continue;
                    }

                    // do horizontal clipping here, to speed up
                    if ((dx1 < leftCutoff && dx2 < leftCutoff) || (rightCutoff < dx1 && rightCutoff < dx2)) {
                        continue;
                    }

                    // else draw line.
                    Point p1 = t.Transform (data[i-1]);
                    Point p2 = t.Transform (data[i]);

                    // when very far zoomed in, points can fall ontop of each other,
                    // and g.DrawLine throws an overflow exception
                    if (p1.Equals(p2)) {
                        continue;
                    }

                    if (drawShadow) {
                        ctx.SetColor (shadowColor);
                        ctx.MoveTo (p1.X + ShadowOffset.X, p1.Y + ShadowOffset.Y);
                        ctx.LineTo (p2.X + ShadowOffset.X, p2.Y + ShadowOffset.Y);
                        ctx.Stroke ();
                    }
                    else {
                        ctx.SetColor (lineColor);
                        ctx.MoveTo (p1.X, p1.Y);
                        ctx.LineTo (p2.X, p2.Y);
                        ctx.Stroke ();
                    }
                }
            }
            ctx.Restore ();
        }
Esempio n. 4
0
 /// <summary>
 /// Applies the constraint to the axes. Must be overriden.
 /// </summary>
 /// <param name="pXAxis1">The bottom x-axis.</param>
 /// <param name="pYAxis1">The left y-axis.</param>
 /// <param name="pXAxis2">The top x-axis.</param>
 /// <param name="pYAxis2">The right y-axis.</param>
 public abstract void ApplyConstraint(PhysicalAxis pXAxis1, PhysicalAxis pYAxis1, PhysicalAxis pXAxis2, PhysicalAxis pYAxis2 );
Esempio n. 5
0
            /// <summary>
            /// Applies the constraint to the axes.
            /// </summary>
            /// <param name="pXAxis1">The bottom x-axis.</param>
            /// <param name="pYAxis1">The left y-axis.</param>
            /// <param name="pXAxis2">The top x-axis.</param>
            /// <param name="pYAxis2">The right y-axis.</param>
            public override void ApplyConstraint( 
				PhysicalAxis pXAxis1, PhysicalAxis pYAxis1, 
				PhysicalAxis pXAxis2, PhysicalAxis pYAxis2 )
            {
                double desiredLength = pXAxis1.Axis.WorldLength/pWorldLength_;
                double currentLength = pXAxis1.PhysicalLength;
                double delta = currentLength - desiredLength;

                double changeLeft = delta / 2;
                double changeRight = delta / 2;
                if (holdFixedY_ != null) {
                    if ((YAxisPosition)holdFixedY_ == YAxisPosition.Left) {
                        changeLeft = 0;
                        changeRight = delta;
                    }
                    else {
                        changeLeft = delta;
                        changeRight = 0;
                    }
                }

                pXAxis1.PhysicalMin = new Point (pXAxis1.PhysicalMin.X+changeLeft, pXAxis1.PhysicalMin.Y);
                pXAxis1.PhysicalMax = new Point (pXAxis1.PhysicalMax.X-changeRight, pXAxis1.PhysicalMax.Y);
                pXAxis2.PhysicalMin = new Point (pXAxis2.PhysicalMin.X+changeLeft, pXAxis2.PhysicalMin.Y);
                pXAxis2.PhysicalMax = new Point (pXAxis2.PhysicalMax.X-changeRight, pXAxis2.PhysicalMax.Y);

                pYAxis1.PhysicalMin = new Point (pYAxis1.PhysicalMin.X+changeLeft, pYAxis1.PhysicalMin.Y);
                pYAxis1.PhysicalMax = new Point (pYAxis1.PhysicalMax.X+changeLeft, pYAxis1.PhysicalMax.Y);
                pYAxis2.PhysicalMin = new Point (pYAxis2.PhysicalMin.X-changeRight, pYAxis2.PhysicalMin.Y);
                pYAxis2.PhysicalMax = new Point (pYAxis2.PhysicalMax.X-changeRight, pYAxis2.PhysicalMax.Y);
            }
Esempio n. 6
0
            /// <summary>
            /// Applies the constraint to the axes.
            /// </summary>
            /// <param name="pXAxis1">The bottom x-axis.</param>
            /// <param name="pYAxis1">The left y-axis.</param>
            /// <param name="pXAxis2">The top x-axis.</param>
            /// <param name="pYAxis2">The right y-axis.</param>
            public override void ApplyConstraint( 
				PhysicalAxis pXAxis1, PhysicalAxis pYAxis1, 
				PhysicalAxis pXAxis2, PhysicalAxis pYAxis2 )
            {
                double xWorldRange = Math.Abs (pXAxis1.Axis.WorldMax - pXAxis1.Axis.WorldMin);
                double xPhysicalRange = Math.Abs (pXAxis1.PhysicalMax.X - pXAxis1.PhysicalMin.X);
                double xDirPixelSize =	xWorldRange / xPhysicalRange;

                double yWorldRange = Math.Abs (pYAxis1.Axis.WorldMax - pYAxis1.Axis.WorldMin);
                double yPhysicalRange = Math.Abs (pYAxis1.PhysicalMax.Y - pYAxis1.PhysicalMin.Y);
                double yDirPixelSize =	yWorldRange / yPhysicalRange;

                double currentAspectRatio = yDirPixelSize / xDirPixelSize;

                // we want to change the current aspect ratio to be the desired.
                // to do this, we may only add the world pixel lengths.

                if (a_ > currentAspectRatio) {
                    // want to increase aspect ratio. Therefore, want to add some amount
                    // to yDirPixelSize (numerator).

                    double toAdd = (a_ - currentAspectRatio) * xDirPixelSize;
                    double newHeight =
                        Math.Abs (pYAxis1.Axis.WorldMax - pYAxis1.Axis.WorldMin) / (yDirPixelSize + toAdd);
                    double changeInHeight = yPhysicalRange - newHeight;

                    double changeBottom = changeInHeight/2;
                    double changeTop = changeInHeight/2;
                    if (holdFixedX_ != null) {
                        if ((XAxisPosition)holdFixedX_ == XAxisPosition.Bottom) {
                            changeBottom = 0;
                            changeTop = changeInHeight;
                        }
                        else {
                            changeBottom = changeInHeight;
                            changeTop = 0;
                        }
                    }

                    pYAxis1.PhysicalMin = new Point (pYAxis1.PhysicalMin.X, pYAxis1.PhysicalMin.Y-changeBottom );
                    pYAxis1.PhysicalMax = new Point (pYAxis1.PhysicalMax.X, pYAxis1.PhysicalMax.Y+changeTop );
                    pYAxis2.PhysicalMin = new Point (pYAxis2.PhysicalMin.X, pYAxis2.PhysicalMin.Y-changeBottom );
                    pYAxis2.PhysicalMax = new Point (pYAxis2.PhysicalMax.X, pYAxis2.PhysicalMax.Y+changeTop );

                    pXAxis1.PhysicalMin = new Point (pXAxis1.PhysicalMin.X, pXAxis1.PhysicalMin.Y-changeBottom );
                    pXAxis1.PhysicalMax = new Point (pXAxis1.PhysicalMax.X, pXAxis1.PhysicalMax.Y-changeBottom );
                    pXAxis2.PhysicalMin = new Point (pXAxis2.PhysicalMin.X, pXAxis2.PhysicalMin.Y+changeTop );
                    pXAxis2.PhysicalMax = new Point (pXAxis2.PhysicalMax.X, pXAxis2.PhysicalMax.Y+changeTop );

                }
                else {

                    // want to decrease aspect ratio. Therefore, want to add some amount
                    // to xDirPixelSize (denominator).

                    double toAdd = yDirPixelSize / this.a_ - xDirPixelSize;
                    double newWidth =
                        Math.Abs(pXAxis1.Axis.WorldMax - pXAxis1.Axis.WorldMin) / (xDirPixelSize + toAdd);
                    double changeInWidth = xPhysicalRange - newWidth;

                    double changeLeft = changeInWidth / 2;
                    double changeRight = changeInWidth / 2;
                    if (holdFixedY_ != null) {
                        if ((YAxisPosition)holdFixedY_ == YAxisPosition.Left) {
                            changeLeft = 0;
                            changeRight = changeInWidth;
                        } else {
                            changeLeft = changeInWidth;
                            changeRight = 0;
                        }
                    }

                    pXAxis1.PhysicalMin = new Point (pXAxis1.PhysicalMin.X+changeLeft, pXAxis1.PhysicalMin.Y );
                    pXAxis1.PhysicalMax = new Point (pXAxis1.PhysicalMax.X-changeRight, pXAxis1.PhysicalMax.Y );
                    pXAxis2.PhysicalMin = new Point (pXAxis2.PhysicalMin.X+changeLeft, pXAxis2.PhysicalMin.Y );
                    pXAxis2.PhysicalMax = new Point (pXAxis2.PhysicalMax.X-changeRight, pXAxis2.PhysicalMax.Y );

                    pYAxis1.PhysicalMin = new Point (pYAxis1.PhysicalMin.X+changeLeft, pYAxis1.PhysicalMin.Y );
                    pYAxis1.PhysicalMax = new Point (pYAxis1.PhysicalMax.X+changeLeft, pYAxis1.PhysicalMax.Y );
                    pYAxis2.PhysicalMin = new Point (pYAxis2.PhysicalMin.X-changeRight, pYAxis2.PhysicalMin.Y );
                    pYAxis2.PhysicalMax = new Point (pYAxis2.PhysicalMax.X-changeRight, pYAxis2.PhysicalMax.Y );

                }
            }
Esempio n. 7
0
        /// <summary>
        /// Draws the candle plot with the specified Drawing Context and X,Y axes
        /// </summary>
        /// <param name="ctx">The Drawing Context with which to draw</param>
        /// <param name="xAxis">The physical X-Axis to draw against</param>
        /// <param name="yAxis">The physical Y-Axis to draw against</param>
        public void Draw(Context ctx, PhysicalAxis xAxis, PhysicalAxis yAxis)
        {
            CandleDataAdapter cd = new CandleDataAdapter (DataSource, DataMember,
                AbscissaData, OpenData, LowData, HighData, CloseData);

            double offset = 0;
            if (Centered) {
                offset = CalculatePhysicalSeparation (cd,xAxis)/2;
            }

            double addAmount = StickWidth/2;
            double stickWidth = StickWidth;

            if (StickWidth == AutoScaleStickWidth) {
                // default
                addAmount = 2;
                stickWidth = 4;

                double minDist = CalculatePhysicalSeparation (cd, xAxis);

                addAmount = minDist / 3;
                stickWidth = addAmount * 2;
            }

            ctx.Save ();
            ctx.SetLineWidth (1);

            /*
            // brant hyatt proposed.
            if (Style == Styles.Stick)
            {
                p.Width = stickWidth;
                addAmount = stickWidth + 2;
            }
            */

            for (int i=0; i<cd.Count; ++i) {

                PointOLHC point = (PointOLHC)cd [i];
                if ((!double.IsNaN (point.Open)) && (!double.IsNaN(point.High))
                 && (!double.IsNaN (point.Low)) && (!double.IsNaN(point.Close))) {
                    double xPos = (xAxis.WorldToPhysical (point.X, false)).X;

                    if (xPos + offset + addAmount < xAxis.PhysicalMin.X || xAxis.PhysicalMax.X < xPos + offset - addAmount) {
                        continue;
                    }

                    double yLo  = (yAxis.WorldToPhysical (point.Low,  false)).Y;
                    double yHi  = (yAxis.WorldToPhysical (point.High, false)).Y;
                    double yOpn = (yAxis.WorldToPhysical (point.Open, false)).Y;
                    double yCls = (yAxis.WorldToPhysical (point.Close,false)).Y;

                    if (Style == Styles.Stick) {
                        /*
                        // brant hyatt proposed.
                        if (i > 0)
                        {
                            if ( ((PointOLHC)cd[i]).Close > ((PointOLHC)cd[i-1]).Close)
                            {
                                p.Color = BullishColor;
                            }
                            else
                            {
                                p.Color = BearishColor;
                            }
                        }
                        */
                        ctx.SetColor (Color);
                        ctx.MoveTo (xPos+offset, yLo);
                        ctx.LineTo (xPos+offset, yHi);		// Low to High line

                        ctx.MoveTo (xPos-addAmount+offset, yOpn);
                        ctx.LineTo (xPos+offset, yOpn);		// Open line

                        ctx.MoveTo (xPos+addAmount+offset, yCls);
                        ctx.LineTo (xPos+offset, yCls);		// Close line
                        ctx.Stroke ();
                    }
                    else if (Style == Styles.Filled) {
                        ctx.MoveTo (xPos+offset, yLo);
                        ctx.LineTo (xPos+offset, yHi);
                        ctx.Stroke ();
                        if (yOpn > yCls) {
                            ctx.SetColor (BullishColor);
                            ctx.Rectangle (xPos-addAmount+offset, yCls, stickWidth, yOpn - yCls);
                            ctx.FillPreserve ();
                            ctx.SetColor (Color);
                            ctx.Stroke ();
                        }
                        else if (yOpn < yCls) {
                            ctx.SetColor (BearishColor);
                            ctx.Rectangle (xPos-addAmount+offset, yOpn, stickWidth, yCls - yOpn);
                            ctx.FillPreserve ();
                            ctx.SetColor (Color);
                            ctx.Stroke ();
                        }
                        else {	// Cls == Opn
                            ctx.MoveTo (xPos-addAmount+offset, yOpn);
                            ctx.LineTo (xPos-addAmount+stickWidth+offset, yCls);
                            ctx.Stroke ();
                        }
                    }
                }
            }
            ctx.Restore ();
        }
Esempio n. 8
0
            /// <summary>
            /// Applies the constraint to the axes.
            /// </summary>
            /// <param name="pXAxis1">The bottom x-axis.</param>
            /// <param name="pYAxis1">The left y-axis.</param>
            /// <param name="pXAxis2">The top x-axis.</param>
            /// <param name="pYAxis2">The right y-axis.</param>
            public override void ApplyConstraint(
                PhysicalAxis pXAxis1, PhysicalAxis pYAxis1,
                PhysicalAxis pXAxis2, PhysicalAxis pYAxis2)
            {
                double xWorldRange    = Math.Abs(pXAxis1.Axis.WorldMax - pXAxis1.Axis.WorldMin);
                double xPhysicalRange = Math.Abs(pXAxis1.PhysicalMax.X - pXAxis1.PhysicalMin.X);
                double xDirPixelSize  = xWorldRange / xPhysicalRange;

                double yWorldRange    = Math.Abs(pYAxis1.Axis.WorldMax - pYAxis1.Axis.WorldMin);
                double yPhysicalRange = Math.Abs(pYAxis1.PhysicalMax.Y - pYAxis1.PhysicalMin.Y);
                double yDirPixelSize  = yWorldRange / yPhysicalRange;

                double currentAspectRatio = yDirPixelSize / xDirPixelSize;

                // we want to change the current aspect ratio to be the desired.
                // to do this, we may only add the world pixel lengths.

                if (a_ > currentAspectRatio)
                {
                    // want to increase aspect ratio. Therefore, want to add some amount
                    // to yDirPixelSize (numerator).

                    double toAdd     = (a_ - currentAspectRatio) * xDirPixelSize;
                    double newHeight =
                        Math.Abs(pYAxis1.Axis.WorldMax - pYAxis1.Axis.WorldMin) / (yDirPixelSize + toAdd);
                    double changeInHeight = yPhysicalRange - newHeight;

                    double changeBottom = changeInHeight / 2;
                    double changeTop    = changeInHeight / 2;
                    if (holdFixedX_ != null)
                    {
                        if ((XAxisPosition)holdFixedX_ == XAxisPosition.Bottom)
                        {
                            changeBottom = 0;
                            changeTop    = changeInHeight;
                        }
                        else
                        {
                            changeBottom = changeInHeight;
                            changeTop    = 0;
                        }
                    }

                    pYAxis1.PhysicalMin = new Point(pYAxis1.PhysicalMin.X, pYAxis1.PhysicalMin.Y - changeBottom);
                    pYAxis1.PhysicalMax = new Point(pYAxis1.PhysicalMax.X, pYAxis1.PhysicalMax.Y + changeTop);
                    pYAxis2.PhysicalMin = new Point(pYAxis2.PhysicalMin.X, pYAxis2.PhysicalMin.Y - changeBottom);
                    pYAxis2.PhysicalMax = new Point(pYAxis2.PhysicalMax.X, pYAxis2.PhysicalMax.Y + changeTop);

                    pXAxis1.PhysicalMin = new Point(pXAxis1.PhysicalMin.X, pXAxis1.PhysicalMin.Y - changeBottom);
                    pXAxis1.PhysicalMax = new Point(pXAxis1.PhysicalMax.X, pXAxis1.PhysicalMax.Y - changeBottom);
                    pXAxis2.PhysicalMin = new Point(pXAxis2.PhysicalMin.X, pXAxis2.PhysicalMin.Y + changeTop);
                    pXAxis2.PhysicalMax = new Point(pXAxis2.PhysicalMax.X, pXAxis2.PhysicalMax.Y + changeTop);
                }
                else
                {
                    // want to decrease aspect ratio. Therefore, want to add some amount
                    // to xDirPixelSize (denominator).

                    double toAdd    = yDirPixelSize / this.a_ - xDirPixelSize;
                    double newWidth =
                        Math.Abs(pXAxis1.Axis.WorldMax - pXAxis1.Axis.WorldMin) / (xDirPixelSize + toAdd);
                    double changeInWidth = xPhysicalRange - newWidth;

                    double changeLeft  = changeInWidth / 2;
                    double changeRight = changeInWidth / 2;
                    if (holdFixedY_ != null)
                    {
                        if ((YAxisPosition)holdFixedY_ == YAxisPosition.Left)
                        {
                            changeLeft  = 0;
                            changeRight = changeInWidth;
                        }
                        else
                        {
                            changeLeft  = changeInWidth;
                            changeRight = 0;
                        }
                    }

                    pXAxis1.PhysicalMin = new Point(pXAxis1.PhysicalMin.X + changeLeft, pXAxis1.PhysicalMin.Y);
                    pXAxis1.PhysicalMax = new Point(pXAxis1.PhysicalMax.X - changeRight, pXAxis1.PhysicalMax.Y);
                    pXAxis2.PhysicalMin = new Point(pXAxis2.PhysicalMin.X + changeLeft, pXAxis2.PhysicalMin.Y);
                    pXAxis2.PhysicalMax = new Point(pXAxis2.PhysicalMax.X - changeRight, pXAxis2.PhysicalMax.Y);

                    pYAxis1.PhysicalMin = new Point(pYAxis1.PhysicalMin.X + changeLeft, pYAxis1.PhysicalMin.Y);
                    pYAxis1.PhysicalMax = new Point(pYAxis1.PhysicalMax.X + changeLeft, pYAxis1.PhysicalMax.Y);
                    pYAxis2.PhysicalMin = new Point(pYAxis2.PhysicalMin.X - changeRight, pYAxis2.PhysicalMin.Y);
                    pYAxis2.PhysicalMax = new Point(pYAxis2.PhysicalMax.X - changeRight, pYAxis2.PhysicalMax.Y);
                }
            }
Esempio n. 9
0
        void DeterminePhysicalAxesToDraw(Rectangle bounds, 
			Axis XAxis1, Axis XAxis2, Axis YAxis1, Axis YAxis2,
			out PhysicalAxis pXAxis1, out PhysicalAxis pXAxis2, 
			out PhysicalAxis pYAxis1, out PhysicalAxis pYAxis2 )
        {
            Rectangle cb = bounds;

            pXAxis1 = new PhysicalAxis (XAxis1,
                new Point (cb.Left, cb.Bottom), new Point (cb.Right, cb.Bottom) );
            pYAxis1 = new PhysicalAxis (YAxis1,
                new Point (cb.Left, cb.Bottom), new Point (cb.Left, cb.Top) );
            pXAxis2 = new PhysicalAxis (XAxis2,
                new Point (cb.Left, cb.Top), new Point (cb.Right, cb.Top) );
            pYAxis2 = new PhysicalAxis (YAxis2,
                new Point (cb.Right, cb.Bottom), new Point (cb.Right, cb.Top) );

            double bottomIndent = Padding;
            if (!pXAxis1.Axis.Hidden) {
                // evaluate its bounding box
                Rectangle bb = pXAxis1.GetBoundingBox ();
                // finally determine its indentation from the bottom
                bottomIndent = bottomIndent + bb.Bottom - cb.Bottom;
            }

            double leftIndent = Padding;
            if (!pYAxis1.Axis.Hidden) {
                // evaluate its bounding box
                Rectangle bb = pYAxis1.GetBoundingBox();
                // finally determine its indentation from the left
                leftIndent = leftIndent - bb.Left + cb.Left;
            }

            // determine title size
            double scale = DetermineScaleFactor (bounds.Width, bounds.Height);
            Font scaled_font;
            if (AutoScaleTitle) {
                scaled_font = TitleFont.WithScaledSize (scale);
            }
            else {
                scaled_font = TitleFont;
            }

            Size titleSize;
            using (TextLayout layout = new TextLayout ()) {
                layout.Font = scaled_font;
                layout.Text = Title;
                titleSize = layout.GetSize ();
            };
            double topIndent = Padding;

            if (!pXAxis2.Axis.Hidden) {
                // evaluate its bounding box
                Rectangle bb = pXAxis2.GetBoundingBox();
                topIndent = topIndent - bb.Top + cb.Top;

                // finally determine its indentation from the top
                // correct top indendation to take into account plot title
                if (Title != "" ) {
                    topIndent += titleSize.Height * 1.3;
                }
            }

            double rightIndent = Padding;
            if (!pYAxis2.Axis.Hidden) {
                // evaluate its bounding box
                Rectangle bb = pYAxis2.GetBoundingBox();

                // finally determine its indentation from the right
                rightIndent += (bb.Right-cb.Right);
            }

            // now we have all the default calculated positions and we can proceed to
            // "move" the axes to their right places

            // primary axes (bottom, left)
            pXAxis1.PhysicalMin = new Point (cb.Left+leftIndent, cb.Bottom-bottomIndent);
            pXAxis1.PhysicalMax = new Point (cb.Right-rightIndent, cb.Bottom-bottomIndent);
            pYAxis1.PhysicalMin = new Point (cb.Left+leftIndent, cb.Bottom-bottomIndent);
            pYAxis1.PhysicalMax = new Point (cb.Left+leftIndent, cb.Top+topIndent);

            // secondary axes (top, right)
            pXAxis2.PhysicalMin = new Point (cb.Left+leftIndent, cb.Top+topIndent);
            pXAxis2.PhysicalMax = new Point (cb.Right-rightIndent, cb.Top+topIndent);
            pYAxis2.PhysicalMin = new Point (cb.Right-rightIndent, cb.Bottom-bottomIndent);
            pYAxis2.PhysicalMax = new Point (cb.Right-rightIndent, cb.Top+topIndent);
        }
Esempio n. 10
0
        /// <summary>
        /// Draw the the PlotSurface and contents (axes, drawables, and legend) using the
        /// Drawing Context supplied and the bounding rectangle for the PlotSurface to cover
        /// </summary>
        /// <param name="ctx">The Drawing Context with which to draw.</param>
        /// <param name="bounds">The rectangle within which to draw</param>
        public void Draw(Context ctx, Rectangle bounds)
        {
            Point titleOrigin = Point.Zero;

            ctx.Save ();

            // determine font sizes and tick scale factor.
            double scale = DetermineScaleFactor (bounds.Width, bounds.Height);

            // if there is nothing to plot, draw title and return.
            if (drawables.Count == 0) {
                // draw title
                //TODO: Title should be centred here - not its origin
                Point origin = Point.Zero;
                titleOrigin.X = bounds.Width/2;
                titleOrigin.Y = bounds.Height/2;
                DrawTitle (ctx, titleOrigin, scale);
                ctx.Restore ();
                return;
            }

            // determine the [non physical] axes to draw based on the axis properties set.
            Axis XAxis1 = null;
            Axis XAxis2 = null;
            Axis YAxis1 = null;
            Axis YAxis2 = null;
            DetermineAxesToDraw (out XAxis1, out XAxis2, out YAxis1, out YAxis2);

            // apply scale factor to axes as desired.

            if (XAxis1.AutoScaleTicks) {
                XAxis1.TickScale = scale;
            }
            if (XAxis1.AutoScaleText) {
                XAxis1.FontScale = scale;
            }
            if (YAxis1.AutoScaleTicks) {
                YAxis1.TickScale = scale;
            }
            if (YAxis1.AutoScaleText) {
                YAxis1.FontScale = scale;
            }
            if (XAxis2.AutoScaleTicks) {
                XAxis2.TickScale = scale;
            }
            if (XAxis2.AutoScaleText) {
                XAxis2.FontScale = scale;
            }
            if (YAxis2.AutoScaleTicks) {
                YAxis2.TickScale = scale;
            }
            if (YAxis2.AutoScaleText) {
                YAxis2.FontScale = scale;
            }

            // determine the default physical positioning of those axes.
            PhysicalAxis pXAxis1 = null;
            PhysicalAxis pYAxis1 = null;
            PhysicalAxis pXAxis2 = null;
            PhysicalAxis pYAxis2 = null;
            DeterminePhysicalAxesToDraw (
                bounds, XAxis1, XAxis2, YAxis1, YAxis2,
                out pXAxis1, out pXAxis2, out pYAxis1, out pYAxis2 );

            double oldXAxis2Height = pXAxis2.PhysicalMin.Y;

            // Apply axes constraints
            for (int i=0; i<axesConstraints.Count; ++i) {
                ((AxesConstraint)axesConstraints[i]).ApplyConstraint(
                    pXAxis1, pYAxis1, pXAxis2, pYAxis2 );
            }

            // draw legend if have one.
            // Note: this will update axes if necessary.
            Point legendPosition = new Point(0,0);
            if (legend != null) {
                legend.UpdateAxesPositions (
                    pXAxis1, pYAxis1, pXAxis2, pYAxis2,
                    drawables, scale, Padding, bounds,
                    out legendPosition );
            }

            double newXAxis2Height = pXAxis2.PhysicalMin.Y;
            double titleExtraOffset = oldXAxis2Height - newXAxis2Height;

            // now we are ready to define the clipping region
            plotAreaBoundingBoxCache = new Rectangle (
                Math.Min (pXAxis1.PhysicalMin.X, pXAxis1.PhysicalMax.X),
                Math.Min (pYAxis1.PhysicalMax.Y, pYAxis1.PhysicalMin.Y),
                Math.Abs (pXAxis1.PhysicalMax.X - pXAxis1.PhysicalMin.X + 1),
                Math.Abs (pYAxis1.PhysicalMin.Y - pYAxis1.PhysicalMax.Y + 1)
            );
            bbXAxis1Cache = pXAxis1.GetBoundingBox ();
            bbXAxis2Cache = pXAxis2.GetBoundingBox ();
            bbYAxis1Cache = pYAxis1.GetBoundingBox ();
            bbYAxis2Cache = pYAxis2.GetBoundingBox ();

            Rectangle plotBounds = (Rectangle)plotAreaBoundingBoxCache;

            // set the clipping region.. (necessary for zoom)
            // Note: although clipping is enforced by the clip region, it is probably more efficient
            // for each Drawable to check against the plotBounds and not draw if points are outside.
            // This hasn't yet been implemented
            ctx.Save ();
            ctx.Rectangle (plotBounds);
            ctx.Clip ();

            // Fill in the plot background.
            if (plotBackImage != null) {
                // Ensure plotBounds has integer size for correct tiling/drawing
                plotBounds.Width = Math.Truncate (plotBounds.Width);
                plotBounds.Height = Math.Truncate (plotBounds.Height);
                ctx.DrawImage (Utils.TiledImage (plotBackImage , plotBounds.Size), plotBounds);
            }
            else if (plotBackGradient != null) {
                // Scale plotBackGradient to plotBounds
                double startX = plotBounds.X + (plotBackGradient.StartPoint.X * plotBounds.Width);
                double startY = plotBounds.Y + (plotBackGradient.StartPoint.Y * plotBounds.Height);
                double endX = plotBounds.X + (plotBackGradient.EndPoint.X * plotBounds.Width);
                double endY = plotBounds.Y + (plotBackGradient.EndPoint.Y * plotBounds.Height);
                LinearGradient g = new LinearGradient (startX, startY, endX, endY);
                g.AddColorStop (0, plotBackGradient.StartColor);
                g.AddColorStop (1, plotBackGradient.EndColor);
                ctx.Rectangle (plotBounds);
                ctx.Pattern = g;
                ctx.Fill ();
            }
            else {
                ctx.Rectangle (plotBounds);
                ctx.SetColor (plotBackColor);
                ctx.Fill ();
            }

            // draw title at centre of Physical X-axis and at top of plot

            titleOrigin.X = (pXAxis2.PhysicalMax.X + pXAxis2.PhysicalMin.X)/2.0;
            titleOrigin.Y = bounds.Top + Padding - titleExtraOffset;
            Size s = DrawTitle (ctx, titleOrigin, scale);

            bbTitleCache = new Rectangle (titleOrigin.X-s.Width/2, titleOrigin.Y, s.Width, s.Height);

            // draw drawables..
            bool legendDrawn = false;

            for (int i_o = 0; i_o < ordering.Count; ++i_o) {

                int i = (int)ordering.GetByIndex (i_o);
                double zOrder = (double)ordering.GetKey (i_o);
                if (zOrder > legendZOrder) {
                    // draw legend.
                    if (!legendDrawn && legend != null) {
                        legend.Draw (ctx, legendPosition, drawables, scale);
                        legendDrawn = true;
                    }
                }

                IDrawable drawable = (IDrawable)drawables[i];
                XAxisPosition xap = (XAxisPosition)xAxisPositions[i];
                YAxisPosition yap = (YAxisPosition)yAxisPositions[i];

                PhysicalAxis drawXAxis;
                PhysicalAxis drawYAxis;

                if (xap == XAxisPosition.Bottom) {
                    drawXAxis = pXAxis1;
                }
                else {
                    drawXAxis = pXAxis2;
                }

                if (yap == YAxisPosition.Left) {
                    drawYAxis = pYAxis1;
                }
                else {
                    drawYAxis = pYAxis2;
                }

                drawable.Draw (ctx, drawXAxis, drawYAxis);

            }

            if (!legendDrawn && legend != null) {
                legend.Draw (ctx, legendPosition, drawables, scale);
            }

            ctx.Restore ();		// end of clipping region

            // cache the physical axes we used on this draw;
            pXAxis1Cache = pXAxis1;
            pYAxis1Cache = pYAxis1;
            pXAxis2Cache = pXAxis2;
            pYAxis2Cache = pYAxis2;

            // now draw axes.
            Rectangle axisBounds;
            pXAxis1.Draw (ctx, out axisBounds);
            pXAxis2.Draw (ctx, out axisBounds);
            pYAxis1.Draw (ctx, out axisBounds);
            pYAxis2.Draw (ctx, out axisBounds);

            #if DEBUG_BOUNDING_BOXES
            ctx.SetColor (Colors.Orange);
            ctx.Rectangle ((Rectangle)bbXAxis1Cache);
            ctx.Rectangle ((Rectangle)bbXAxis2Cache);
            ctx.Rectangle ((Rectangle)bbYAxis1Cache);
            ctx.Rectangle ((Rectangle)bbYAxis2Cache);
            ctx.Stroke ();
            ctx.SetColor (Colors.Red);
            ctx.Rectangle ((Rectangle)plotAreaBoundingBoxCache);
            ctx.Rectangle ((Rectangle)bbTitleCache);
            ctx.Stroke ();
            #endif
            ctx.Restore ();
        }
Esempio n. 11
0
        /// <summary>
        /// OnButtonPressed method for AxisDrag interaction
        /// </summary>
        public override bool OnButtonPressed(ButtonEventArgs args, PlotCanvas pc)
        {
            // if the mouse is inside the plot area (the tick marks may be here,
            // and are counted as part of the axis), then *don't* invoke scaling
            if (pc.PlotAreaBoundingBoxCache.Contains(args.X, args.Y)) {
                return false;
            }

            if (args.Button == PointerButton.Left) {
                // see if hit with axis. NB Only one axis object will be returned
                ArrayList objects = pc.HitTest (new Point(args.X, args.Y));
                foreach (object o in objects) {
                    if (o is Axis) {
                        dragging = true;
                        Axis axis = (Axis)o;
                        if (pc.PhysicalXAxis1Cache.Axis == axis) {
                            physicalAxis = pc.PhysicalXAxis1Cache;
                            translateX = true;
                        }
                        else if (pc.PhysicalXAxis2Cache.Axis == axis) {
                            physicalAxis = pc.PhysicalXAxis2Cache;
                            translateX = true;
                        }
                        else if (pc.PhysicalYAxis1Cache.Axis == axis) {
                            physicalAxis = pc.PhysicalYAxis1Cache;
                            translateY = true;
                        }
                        else if (pc.PhysicalYAxis2Cache.Axis == axis) {
                            physicalAxis = pc.PhysicalYAxis2Cache;
                            translateY = true;
                        }
                        lastPoint = new Point (args.X, args.Y);
                        return false;
                    }
                }
            }
            return false;
        }
Esempio n. 12
0
 /// <summary>
 /// OnButtonReleased method for AxisDrag interaction
 /// </summary>
 public override bool OnButtonReleased(ButtonEventArgs args, PlotCanvas pc)
 {
     if (dragging) {
         physicalAxis = null;
         lastPoint = unset;
         dragging = false;
         translateX = false;
         translateY = false;
     }
     return false;
 }
Esempio n. 13
0
        /// <summary>
        /// Draws the line plot using the Context and Physical Axes provided
        /// </summary>
        /// <param name="ctx">The Drawing Context with which to draw.</param>
        /// <param name="xAxis">The X-Axis to draw against.</param>
        /// <param name="yAxis">The Y-Axis to draw against.</param>
        /// <param name="drawShadow">If true draw the shadow for the line. If false, draw line.</param>
        public void DrawLineOrShadow(Context ctx, PhysicalAxis xAxis, PhysicalAxis yAxis, bool drawShadow)
        {
            SequenceAdapter data = new SequenceAdapter(DataSource, DataMember, OrdinateData, AbscissaData);

            ITransform2D t = Transform2D.GetTransformer(xAxis, yAxis);

            int numberPoints = data.Count;

            if (data.Count == 0)
            {
                return;
            }

            ctx.Save();
            ctx.SetLineWidth(lineWidth);
            if (lineDash != null)
            {
                ctx.SetLineDash(0, lineDash);
            }

            if (numberPoints == 1)
            {
                Point physical = t.Transform(data[0]);

                if (drawShadow)
                {
                    ctx.SetColor(shadowColor);
                    ctx.MoveTo(physical.X - 0.5 + ShadowOffset.X, physical.Y + ShadowOffset.Y);
                    ctx.LineTo(physical.X + 0.5 + ShadowOffset.X, physical.Y + ShadowOffset.Y);
                    ctx.Stroke();
                }
                else
                {
                    ctx.SetColor(lineColor);
                    ctx.MoveTo(physical.X - 0.5, physical.Y);
                    ctx.LineTo(physical.X + 0.5, physical.Y);
                    ctx.Stroke();
                }
            }
            else
            {
                // prepare for clipping
                double leftCutoff  = xAxis.PhysicalToWorld(xAxis.PhysicalMin, false);
                double rightCutoff = xAxis.PhysicalToWorld(xAxis.PhysicalMax, false);
                if (leftCutoff > rightCutoff)
                {
                    Utils.Swap(ref leftCutoff, ref rightCutoff);
                }
                if (drawShadow)
                {
                    // correct cut-offs
                    double shadowCorrection =
                        xAxis.PhysicalToWorld(ShadowOffset, false) - xAxis.PhysicalToWorld(new Point(0, 0), false);
                    leftCutoff  -= shadowCorrection;
                    rightCutoff -= shadowCorrection;
                }

                for (int i = 1; i < numberPoints; ++i)
                {
                    // check to see if any values null. If so, then continue.
                    double dx1 = data[i - 1].X;
                    double dx2 = data[i].X;
                    double dy1 = data[i - 1].Y;
                    double dy2 = data[i].Y;
                    if (Double.IsNaN(dx1) || Double.IsNaN(dy1) || Double.IsNaN(dx2) || Double.IsNaN(dy2))
                    {
                        continue;
                    }

                    // do horizontal clipping here, to speed up
                    if ((dx1 < leftCutoff && dx2 < leftCutoff) || (rightCutoff < dx1 && rightCutoff < dx2))
                    {
                        continue;
                    }

                    // else draw line.
                    Point p1 = t.Transform(data[i - 1]);
                    Point p2 = t.Transform(data[i]);

                    // when very far zoomed in, points can fall ontop of each other,
                    // and g.DrawLine throws an overflow exception
                    if (p1.Equals(p2))
                    {
                        continue;
                    }

                    if (drawShadow)
                    {
                        ctx.SetColor(shadowColor);
                        ctx.MoveTo(p1.X + ShadowOffset.X, p1.Y + ShadowOffset.Y);
                        ctx.LineTo(p2.X + ShadowOffset.X, p2.Y + ShadowOffset.Y);
                        ctx.Stroke();
                    }
                    else
                    {
                        ctx.SetColor(lineColor);
                        ctx.MoveTo(p1.X, p1.Y);
                        ctx.LineTo(p2.X, p2.Y);
                        ctx.Stroke();
                    }
                }
            }
            ctx.Restore();
        }
Esempio n. 14
0
        /// <summary>
        /// Draws the histogram.
        /// </summary>
        /// <param name="ctx">The Drawing Context with which to draw</param>
        /// <param name="xAxis">The X-Axis to draw against.</param>
        /// <param name="yAxis">The Y-Axis to draw against.</param>
        public void Draw(Context ctx, PhysicalAxis xAxis, PhysicalAxis yAxis)
        {
            double          yoff;
            SequenceAdapter data = new SequenceAdapter(DataSource, DataMember, OrdinateData, AbscissaData);

            ctx.Save();
            ctx.SetLineWidth(1);

            for (int i = 0; i < data.Count; ++i)
            {
                // (1) determine the top left hand point of the bar (assuming not centered)
                Point p1 = data[i];
                if (double.IsNaN(p1.X) || double.IsNaN(p1.Y))
                {
                    continue;
                }

                // (2) determine the top right hand point of the bar (assuming not centered)
                Point p2 = Point.Zero;;
                if (i + 1 != data.Count)
                {
                    p2 = data[i + 1];
                    if (double.IsNaN(p2.X) || double.IsNaN(p2.Y))
                    {
                        continue;
                    }
                    p2.Y = p1.Y;
                }
                else if (i != 0)
                {
                    p2 = data[i - 1];
                    if (double.IsNaN(p2.X) || double.IsNaN(p2.Y))
                    {
                        continue;
                    }
                    double offset = p1.X - p2.X;
                    p2.X = p1.X + offset;
                    p2.Y = p1.Y;
                }
                else
                {
                    double offset = 1.0;
                    p2.X = p1.X + offset;
                    p2.Y = p1.Y;
                }

                // (3) now account for plots this may be stacked on top of.
                HistogramPlot currentPlot = this;
                yoff = 0.0;
                double yval = 0.0;
                while (currentPlot.IsStacked)
                {
                    SequenceAdapter stackedToData = new SequenceAdapter(
                        currentPlot.stackedTo.DataSource,
                        currentPlot.stackedTo.DataMember,
                        currentPlot.stackedTo.OrdinateData,
                        currentPlot.stackedTo.AbscissaData);

                    yval       += stackedToData[i].Y;
                    yoff        = yAxis.WorldToPhysical(yval, false).Y;
                    p1.Y       += stackedToData[i].Y;
                    p2.Y       += stackedToData[i].Y;
                    currentPlot = currentPlot.stackedTo;
                }

                // (4) now account for centering
                if (Center)
                {
                    double offset = (p2.X - p1.X) / 2.0;
                    p1.X -= offset;
                    p2.X -= offset;
                }

                // (5) now account for BaseOffset (shift of bar sideways).
                p1.X += BaseOffset;
                p2.X += BaseOffset;

                // (6) now get physical coordinates of top two points.
                Point xPos1 = xAxis.WorldToPhysical(p1.X, false);
                Point yPos1 = yAxis.WorldToPhysical(p1.Y, false);
                Point xPos2 = xAxis.WorldToPhysical(p2.X, false);

                if (IsStacked)
                {
                    currentPlot = this;
                    while (currentPlot.IsStacked)
                    {
                        currentPlot = currentPlot.stackedTo;
                    }
                    baseWidth = currentPlot.baseWidth;
                }

                double width = xPos2.X - xPos1.X;
                double height;
                if (IsStacked)
                {
                    height = -yPos1.Y + yoff;
                }
                else
                {
                    height = -yPos1.Y + yAxis.PhysicalMin.Y;
                }

                double    xoff = (1.0 - baseWidth) / 2.0 * width;
                Rectangle bar  = new Rectangle(xPos1.X + xoff, yPos1.Y, width - 2 * xoff, height);

                ctx.Rectangle(bar);
                if (Filled)
                {
                    if (bar.Height != 0 && bar.Width != 0)
                    {
                        if (FillGradient != null)
                        {
                            // Scale FillGradient to bar rectangle
                            double         sX = bar.X + fillGradient.StartPoint.X * bar.Width;
                            double         sY = bar.Y + fillGradient.StartPoint.Y * bar.Height;
                            double         eX = bar.X + fillGradient.EndPoint.X * bar.Width;
                            double         eY = bar.Y + fillGradient.EndPoint.Y * bar.Height;
                            LinearGradient g  = new LinearGradient(sX, sY, eX, eY);
                            g.AddColorStop(0, FillGradient.StartColor);
                            g.AddColorStop(1, FillGradient.EndColor);
                            ctx.Pattern = g;
                        }
                        else
                        {
                            ctx.SetColor(FillColor);
                        }
                        ctx.FillPreserve();
                    }
                }
                ctx.SetColor(BorderColor);
                ctx.Stroke();
            }
            ctx.Restore();
        }
Esempio n. 15
0
        /// <summary>
        /// Draws the plot using the Drawing Context and X, Y axes supplied.
        /// </summary>
        public override void Draw(Context ctx, PhysicalAxis xAxis, PhysicalAxis yAxis)
        {
            SequenceAdapter data =
                new SequenceAdapter(this.DataSource, this.DataMember, this.OrdinateData, this.AbscissaData);

            TextDataAdapter textData =
                new TextDataAdapter(this.DataSource, this.DataMember, this.TextData);

            TextLayout layout = new TextLayout();

            layout.Font = Font;

            ctx.Save();
            ctx.SetColor(Colors.Black);

            for (int i = 0; i < data.Count; ++i)
            {
                try {
                    Point p = data[i];
                    if (!Double.IsNaN(p.X) && !Double.IsNaN(p.Y))
                    {
                        Point xPos = xAxis.WorldToPhysical(p.X, false);
                        Point yPos = yAxis.WorldToPhysical(p.Y, false);
                        // first plot the marker
                        Marker.Draw(ctx, xPos.X, yPos.Y);
                        // then the label
                        if (textData[i] != "")
                        {
                            layout.Text = textData[i];
                            Size size = layout.GetSize();
                            switch (labelTextPosition)
                            {
                            case LabelPositions.Above:
                                p.X = xPos.X - size.Width / 2;
                                p.Y = yPos.Y - size.Height - Marker.Size * 2 / 3;
                                break;

                            case LabelPositions.Below:
                                p.X = xPos.X - size.Width / 2;
                                p.Y = yPos.Y + Marker.Size * 2 / 3;
                                break;

                            case LabelPositions.Left:
                                p.X = xPos.X - size.Width - Marker.Size * 2 / 3;
                                p.Y = yPos.Y - size.Height / 2;
                                break;

                            case LabelPositions.Right:
                                p.X = xPos.X + Marker.Size * 2 / 3;
                                p.Y = yPos.Y - size.Height / 2;
                                break;
                            }
                            ctx.DrawTextLayout(layout, p);
                        }
                    }
                }
                catch {
                    throw new XwPlotException("Error in TextPlot.Draw");
                }
            }
            ctx.Restore();
        }
Esempio n. 16
0
        /// <summary>
        /// OnButtonPressed method for AxisScale interaction
        /// </summary>
        public override bool OnButtonPressed(ButtonEventArgs args, PlotCanvas pc)
        {
            // if the mouse is inside the plot area (the tick marks may be here,
            // and are counted as part of the axis), then *don't* invoke scaling
            if (pc.PlotAreaBoundingBoxCache.Contains(args.X, args.Y)) {
                return false;
            }

            if (args.Button == PointerButton.Left) {
                // see if hit with axis. NB Only one axis object will be returned
                ArrayList objects = pc.HitTest (new Point(args.X, args.Y));

                foreach (object o in objects) {
                    if (o is Axis) {
                        dragging = true;
                        axis = (Axis)o;
                        if (pc.PhysicalXAxis1Cache.Axis == axis) {
                            physicalAxis = pc.PhysicalXAxis1Cache;
                            //pc.plotCursor = CursorType.LeftRight;
                        }
                        else if (pc.PhysicalXAxis2Cache.Axis == axis) {
                            physicalAxis = pc.PhysicalXAxis2Cache;
                            //ps.plotCursor = CursorType.LeftRight;
                        }
                        else if (pc.PhysicalYAxis1Cache.Axis == axis) {
                            physicalAxis = pc.PhysicalYAxis1Cache;
                            //pc.plotCursor = CursorType.UpDown;
                        }
                        else if (pc.PhysicalYAxis2Cache.Axis == axis) {
                            physicalAxis = pc.PhysicalYAxis2Cache;
                            //pc.plotCursor = CursorType.UpDown;
                        }

                        startPoint = new Point (args.X, args.Y);
                        lastPoint = startPoint;

                        // evaluate focusRatio about which axis is expanded
                        double  x = startPoint.X - physicalAxis.PhysicalMin.X;
                        double  y = startPoint.Y - physicalAxis.PhysicalMin.Y;
                        double r = Math.Sqrt(x*x + y*y);
                        focusRatio = r/physicalAxis.PhysicalLength;
                        return false;
                    }
                }
            }
            return false;
        }
Esempio n. 17
0
        void Init()
        {
            drawables = new ArrayList ();
            xAxisPositions = new ArrayList ();
            yAxisPositions = new ArrayList ();
            zPositions = new ArrayList ();
            ordering = new SortedList ();

            PlotBackColor = Colors.White;
            TitleFont = Font.SystemSansSerifFont.WithSize (14);
            TitleColor = Colors.Black;
            Padding = 10;
            Title = "";
            Legend = null;

            autoScaletitle = false;
            autoScaleAutoGeneratedAxes = false;
            XAxis1 = null;
            XAxis2 = null;
            YAxis1 = null;
            YAxis2 = null;
            pXAxis1Cache = null;
            pYAxis1Cache = null;
            pXAxis2Cache = null;
            pYAxis2Cache = null;

            axesConstraints = new ArrayList ();
        }
Esempio n. 18
0
        /// <summary>
        /// Draws the arrow on a plot surface.
        /// </summary>
        /// <param name="ctx">the Drawing Context with which to draw</param>
        /// <param name="xAxis">The X-Axis to draw against.</param>
        /// <param name="yAxis">The Y-Axis to draw against.</param>
        public void Draw(Context ctx, PhysicalAxis xAxis, PhysicalAxis yAxis )
        {
            if (To.X > xAxis.Axis.WorldMax || To.X < xAxis.Axis.WorldMin) {
                return;
            }
            if (To.Y > yAxis.Axis.WorldMax || To.Y < yAxis.Axis.WorldMin) {
                return;
            }

            ctx.Save ();

            TextLayout layout = new TextLayout ();
            layout.Font = textFont_;
            layout.Text = text_;

            double angle = angle_;
            if (angle_ < 0.0) {
                int mul = -(int)(angle_ / 360.0) + 2;
                angle = angle_ + 360.0 * (double)mul;
            }

            double normAngle = (double)angle % 360.0;	// angle in range 0 -> 360.

            Point toPoint = new Point (
                xAxis.WorldToPhysical (to_.X, true).X,
                yAxis.WorldToPhysical (to_.Y, true).Y);

            double xDir = Math.Cos (normAngle * 2.0 * Math.PI / 360.0);
            double yDir = Math.Sin (normAngle * 2.0 * Math.PI / 360.0);

            toPoint.X += xDir*headOffset_;
            toPoint.Y += yDir*headOffset_;

            double xOff = physicalLength_ * xDir;
            double yOff = physicalLength_ * yDir;

            Point fromPoint = new Point(
                (int)(toPoint.X + xOff),
                (int)(toPoint.Y + yOff) );

            ctx.SetLineWidth (1);
            ctx.SetColor (arrowColor_);
            ctx.MoveTo (fromPoint);
            ctx.LineTo (toPoint);
            ctx.Stroke ();

            xOff = headSize_ * Math.Cos ((normAngle-headAngle_/2) * 2.0 * Math.PI / 360.0);
            yOff = headSize_ * Math.Sin ((normAngle-headAngle_/2) * 2.0 * Math.PI / 360.0);

            ctx.LineTo (toPoint.X + xOff, toPoint.Y + yOff);

            double xOff2 = headSize_ * Math.Cos ((normAngle+headAngle_/2) * 2.0 * Math.PI / 360.0);
            double yOff2 = headSize_ * Math.Sin ((normAngle+headAngle_/2) * 2.0 * Math.PI / 360.0);

            ctx.LineTo (toPoint.X + xOff2, toPoint.Y + yOff2);
            ctx.LineTo (toPoint);
            ctx.ClosePath ();
            ctx.SetColor (arrowColor_);
            ctx.Fill ();

            Size textSize = layout.GetSize ();
            Size halfSize = new Size (textSize.Width/2, textSize.Height/2);

            double quadrantSlideLength = halfSize.Width + halfSize.Height;

            double quadrantD = normAngle / 90.0;		// integer part gives quadrant.
            int quadrant = (int)quadrantD;				// quadrant in.
            double prop = quadrantD - (double)quadrant;	// proportion of way through this qadrant.
            double dist = prop * quadrantSlideLength;	// distance along quarter of bounds rectangle.

            // now find the offset from the middle of the text box that the
            // rear end of the arrow should end at (reverse this to get position
            // of text box with respect to rear end of arrow).
            //
            // There is almost certainly an elgant way of doing this involving
            // trig functions to get all the signs right, but I'm about ready to
            // drop off to sleep at the moment, so this blatent method will have
            // to do.
            Point offsetFromMiddle = new Point (0, 0);
            switch (quadrant) {
            case 0:
                if (dist > halfSize.Height) {
                    dist -= halfSize.Height;
                    offsetFromMiddle = new Point ( -halfSize.Width + dist, halfSize.Height );
                }
                else {
                    offsetFromMiddle = new Point ( -halfSize.Width, - dist );
                }
                break;
            case 1:
                if (dist > halfSize.Width) {
                    dist -= halfSize.Width;
                    offsetFromMiddle = new Point ( halfSize.Width, halfSize.Height - dist );
                }
                else {
                    offsetFromMiddle = new Point ( dist, halfSize.Height );
                }
                break;
            case 2:
                if (dist > halfSize.Height) {
                    dist -= halfSize.Height;
                    offsetFromMiddle = new Point ( halfSize.Width - dist, -halfSize.Height );
                }
                else {
                    offsetFromMiddle = new Point ( halfSize.Width, -dist );
                }
                break;
            case 3:
                if (dist > halfSize.Width) {
                    dist -= halfSize.Width;
                    offsetFromMiddle = new Point ( -halfSize.Width, -halfSize.Height + dist );
                }
                else {
                    offsetFromMiddle = new Point ( -dist, -halfSize.Height );
                }
                break;
            default:
                throw new XwPlotException( "Programmer error." );
            }

            ctx.SetColor (textColor_);
            double x = fromPoint.X - halfSize.Width - offsetFromMiddle.X;
            double y = fromPoint.Y - halfSize.Height + offsetFromMiddle.Y;
            ctx.DrawTextLayout (layout, x, y);

            ctx.Restore ();
        }
Esempio n. 19
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="xAxis">The x-axis to use for transforms</param>
 /// <param name="yAxis">The y-axis to use for transforms</param>
 public FastTransform2D(PhysicalAxis xAxis, PhysicalAxis yAxis)
 {
     xAxis_ = new PageAlignedPhysicalAxis(xAxis);
     yAxis_ = new PageAlignedPhysicalAxis(yAxis);
 }
Esempio n. 20
0
        /// <summary>
        /// Draw using the Drawing Context and Axes supplied
        /// </summary>
        /// <remarks>TODO: block positions may be off by a pixel or so. maybe. Re-think calculations</remarks>
        public void Draw(Context ctx, PhysicalAxis xAxis, PhysicalAxis yAxis)
        {
            if (data == null || data.GetLength(0) == 0 || data.GetLength(1) == 0)
            {
                return;
            }

            double worldWidth          = xAxis.Axis.WorldMax - xAxis.Axis.WorldMin;
            double numBlocksHorizontal = worldWidth / xStep;
            double worldHeight         = yAxis.Axis.WorldMax - yAxis.Axis.WorldMin;
            double numBlocksVertical   = worldHeight / yStep;

            double physicalWidth = xAxis.PhysicalMax.X - xAxis.PhysicalMin.X;
            double blockWidth    = physicalWidth / numBlocksHorizontal;
            bool   wPositive     = true;

            if (blockWidth < 0.0)
            {
                wPositive = false;
            }
            blockWidth = Math.Abs(blockWidth) + 1;

            double physicalHeight = yAxis.PhysicalMax.Y - yAxis.PhysicalMin.Y;
            double blockHeight    = physicalHeight / numBlocksVertical;
            bool   hPositive      = true;

            if (blockHeight < 0.0)
            {
                hPositive = false;
            }
            blockHeight = Math.Abs(blockHeight) + 1;

            ctx.Save();
            for (int i = 0; i < data.GetLength(0); ++i)
            {
                for (int j = 0; j < data.GetLength(1); ++j)
                {
                    double wX = (double)j * xStep + xStart;
                    double wY = (double)i * yStep + yStart;
                    if (!hPositive)
                    {
                        wY += yStep;
                    }
                    if (!wPositive)
                    {
                        wX += xStep;
                    }
                    if (Center)
                    {
                        wX -= xStep / 2.0;
                        wY -= yStep / 2.0;
                    }
                    Color color = Gradient.GetColor((data[i, j] - DataMin) / (DataMax - DataMin));
                    ctx.SetColor(color);
                    double x = xAxis.WorldToPhysical(wX, false).X;
                    double y = yAxis.WorldToPhysical(wY, false).Y;
                    ctx.Rectangle(x, y, blockWidth, blockHeight);
                    ctx.Fill();
                }
            }
            ctx.Restore();
        }
Esempio n. 21
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="xAxis">The x-axis to use for transforms</param>
 /// <param name="yAxis">The y-axis to use for transforms</param>
 public DefaultTransform2D(PhysicalAxis xAxis, PhysicalAxis yAxis)
 {
     xAxis_ = xAxis;
     yAxis_ = yAxis;
 }
Esempio n. 22
0
        /// <summary>
        /// Draw the the PlotSurface and contents (axes, drawables, and legend) using the
        /// Drawing Context supplied and the bounding rectangle for the PlotSurface to cover
        /// </summary>
        /// <param name="ctx">The Drawing Context with which to draw.</param>
        /// <param name="bounds">The rectangle within which to draw</param>
        public void Draw(Context ctx, Rectangle bounds)
        {
            Point titleOrigin = Point.Zero;

            ctx.Save();

            // determine font sizes and tick scale factor.
            double scale = DetermineScaleFactor(bounds.Width, bounds.Height);

            // if there is nothing to plot, draw title and return.
            if (drawables.Count == 0)
            {
                // draw title
                //TODO: Title should be centred here - not its origin
                Point origin = Point.Zero;
                titleOrigin.X = bounds.Width / 2;
                titleOrigin.Y = bounds.Height / 2;
                DrawTitle(ctx, titleOrigin, scale);
                ctx.Restore();
                return;
            }

            // determine the [non physical] axes to draw based on the axis properties set.
            Axis XAxis1 = null;
            Axis XAxis2 = null;
            Axis YAxis1 = null;
            Axis YAxis2 = null;

            DetermineAxesToDraw(out XAxis1, out XAxis2, out YAxis1, out YAxis2);

            // apply scale factor to axes as desired.

            if (XAxis1.AutoScaleTicks)
            {
                XAxis1.TickScale = scale;
            }
            if (XAxis1.AutoScaleText)
            {
                XAxis1.FontScale = scale;
            }
            if (YAxis1.AutoScaleTicks)
            {
                YAxis1.TickScale = scale;
            }
            if (YAxis1.AutoScaleText)
            {
                YAxis1.FontScale = scale;
            }
            if (XAxis2.AutoScaleTicks)
            {
                XAxis2.TickScale = scale;
            }
            if (XAxis2.AutoScaleText)
            {
                XAxis2.FontScale = scale;
            }
            if (YAxis2.AutoScaleTicks)
            {
                YAxis2.TickScale = scale;
            }
            if (YAxis2.AutoScaleText)
            {
                YAxis2.FontScale = scale;
            }

            // determine the default physical positioning of those axes.
            PhysicalAxis pXAxis1 = null;
            PhysicalAxis pYAxis1 = null;
            PhysicalAxis pXAxis2 = null;
            PhysicalAxis pYAxis2 = null;

            DeterminePhysicalAxesToDraw(
                bounds, XAxis1, XAxis2, YAxis1, YAxis2,
                out pXAxis1, out pXAxis2, out pYAxis1, out pYAxis2);

            double oldXAxis2Height = pXAxis2.PhysicalMin.Y;

            // Apply axes constraints
            for (int i = 0; i < axesConstraints.Count; ++i)
            {
                ((AxesConstraint)axesConstraints[i]).ApplyConstraint(
                    pXAxis1, pYAxis1, pXAxis2, pYAxis2);
            }

            // draw legend if have one.
            // Note: this will update axes if necessary.
            Point legendPosition = new Point(0, 0);

            if (legend != null)
            {
                legend.UpdateAxesPositions(
                    pXAxis1, pYAxis1, pXAxis2, pYAxis2,
                    drawables, scale, Padding, bounds,
                    out legendPosition);
            }

            double newXAxis2Height  = pXAxis2.PhysicalMin.Y;
            double titleExtraOffset = oldXAxis2Height - newXAxis2Height;

            // now we are ready to define the clipping region
            plotAreaBoundingBoxCache = new Rectangle(
                Math.Min(pXAxis1.PhysicalMin.X, pXAxis1.PhysicalMax.X),
                Math.Min(pYAxis1.PhysicalMax.Y, pYAxis1.PhysicalMin.Y),
                Math.Abs(pXAxis1.PhysicalMax.X - pXAxis1.PhysicalMin.X + 1),
                Math.Abs(pYAxis1.PhysicalMin.Y - pYAxis1.PhysicalMax.Y + 1)
                );
            bbXAxis1Cache = pXAxis1.GetBoundingBox();
            bbXAxis2Cache = pXAxis2.GetBoundingBox();
            bbYAxis1Cache = pYAxis1.GetBoundingBox();
            bbYAxis2Cache = pYAxis2.GetBoundingBox();

            Rectangle plotBounds = (Rectangle)plotAreaBoundingBoxCache;

            // set the clipping region.. (necessary for zoom)
            // Note: although clipping is enforced by the clip region, it is probably more efficient
            // for each Drawable to check against the plotBounds and not draw if points are outside.
            // This hasn't yet been implemented
            ctx.Save();
            ctx.Rectangle(plotBounds);
            ctx.Clip();

            // Fill in the plot background.
            if (plotBackImage != null)
            {
                // Ensure plotBounds has integer size for correct tiling/drawing
                plotBounds.Width  = Math.Truncate(plotBounds.Width);
                plotBounds.Height = Math.Truncate(plotBounds.Height);
                ctx.DrawImage(Utils.TiledImage(plotBackImage, plotBounds.Size), plotBounds);
            }
            else if (plotBackGradient != null)
            {
                // Scale plotBackGradient to plotBounds
                double         startX = plotBounds.X + (plotBackGradient.StartPoint.X * plotBounds.Width);
                double         startY = plotBounds.Y + (plotBackGradient.StartPoint.Y * plotBounds.Height);
                double         endX   = plotBounds.X + (plotBackGradient.EndPoint.X * plotBounds.Width);
                double         endY   = plotBounds.Y + (plotBackGradient.EndPoint.Y * plotBounds.Height);
                LinearGradient g      = new LinearGradient(startX, startY, endX, endY);
                g.AddColorStop(0, plotBackGradient.StartColor);
                g.AddColorStop(1, plotBackGradient.EndColor);
                ctx.Rectangle(plotBounds);
                ctx.Pattern = g;
                ctx.Fill();
            }
            else
            {
                ctx.Rectangle(plotBounds);
                ctx.SetColor(plotBackColor);
                ctx.Fill();
            }

            // draw title at centre of Physical X-axis and at top of plot

            titleOrigin.X = (pXAxis2.PhysicalMax.X + pXAxis2.PhysicalMin.X) / 2.0;
            titleOrigin.Y = bounds.Top + Padding - titleExtraOffset;
            Size s = DrawTitle(ctx, titleOrigin, scale);

            bbTitleCache = new Rectangle(titleOrigin.X - s.Width / 2, titleOrigin.Y, s.Width, s.Height);

            // draw drawables..
            bool legendDrawn = false;

            for (int i_o = 0; i_o < ordering.Count; ++i_o)
            {
                int    i      = (int)ordering.GetByIndex(i_o);
                double zOrder = (double)ordering.GetKey(i_o);
                if (zOrder > legendZOrder)
                {
                    // draw legend.
                    if (!legendDrawn && legend != null)
                    {
                        legend.Draw(ctx, legendPosition, drawables, scale);
                        legendDrawn = true;
                    }
                }

                IDrawable     drawable = (IDrawable)drawables[i];
                XAxisPosition xap      = (XAxisPosition)xAxisPositions[i];
                YAxisPosition yap      = (YAxisPosition)yAxisPositions[i];

                PhysicalAxis drawXAxis;
                PhysicalAxis drawYAxis;

                if (xap == XAxisPosition.Bottom)
                {
                    drawXAxis = pXAxis1;
                }
                else
                {
                    drawXAxis = pXAxis2;
                }

                if (yap == YAxisPosition.Left)
                {
                    drawYAxis = pYAxis1;
                }
                else
                {
                    drawYAxis = pYAxis2;
                }

                drawable.Draw(ctx, drawXAxis, drawYAxis);
            }

            if (!legendDrawn && legend != null)
            {
                legend.Draw(ctx, legendPosition, drawables, scale);
            }

            ctx.Restore();                      // end of clipping region

            // cache the physical axes we used on this draw;
            pXAxis1Cache = pXAxis1;
            pYAxis1Cache = pYAxis1;
            pXAxis2Cache = pXAxis2;
            pYAxis2Cache = pYAxis2;

            // now draw axes.
            Rectangle axisBounds;

            pXAxis1.Draw(ctx, out axisBounds);
            pXAxis2.Draw(ctx, out axisBounds);
            pYAxis1.Draw(ctx, out axisBounds);
            pYAxis2.Draw(ctx, out axisBounds);

#if DEBUG_BOUNDING_BOXES
            ctx.SetColor(Colors.Orange);
            ctx.Rectangle((Rectangle)bbXAxis1Cache);
            ctx.Rectangle((Rectangle)bbXAxis2Cache);
            ctx.Rectangle((Rectangle)bbYAxis1Cache);
            ctx.Rectangle((Rectangle)bbYAxis2Cache);
            ctx.Stroke();
            ctx.SetColor(Colors.Red);
            ctx.Rectangle((Rectangle)plotAreaBoundingBoxCache);
            ctx.Rectangle((Rectangle)bbTitleCache);
            ctx.Stroke();
#endif
            ctx.Restore();
        }
Esempio n. 23
0
        /// <summary>
        /// Draw the filled region
        /// </summary>
        /// <param name="g">The Drawing Context with which to draw.</param>
        /// <param name="xAxis">The X-Axis to draw against.</param>
        /// <param name="yAxis">The Y-Axis to draw against.</param>
        public void Draw(Context ctx, PhysicalAxis xAxis, PhysicalAxis yAxis)
        {
            ITransform2D t = Transform2D.GetTransformer (xAxis, yAxis);

            ctx.Save ();

            if (hl1 != null && hl2 != null) {
                ctx.MoveTo (t.Transform (xAxis.Axis.WorldMin, hl1.OrdinateValue));
                ctx.LineTo (t.Transform (xAxis.Axis.WorldMax, hl1.OrdinateValue));
                ctx.LineTo (t.Transform (xAxis.Axis.WorldMax, hl2.OrdinateValue));
                ctx.LineTo (t.Transform (xAxis.Axis.WorldMin, hl2.OrdinateValue));
                ctx.ClosePath ();
            } else if (vl1 != null && vl2 != null) {
                ctx.MoveTo (t.Transform (vl1.AbscissaValue, yAxis.Axis.WorldMin));
                ctx.LineTo (t.Transform (vl1.AbscissaValue, yAxis.Axis.WorldMax));
                ctx.LineTo (t.Transform (vl2.AbscissaValue, yAxis.Axis.WorldMax));
                ctx.LineTo (t.Transform (vl2.AbscissaValue, yAxis.Axis.WorldMin));
                ctx.ClosePath ();
            } else if (lp1 != null && lp2 != null) {

                SequenceAdapter a1 = new SequenceAdapter (lp1.DataSource, lp1.DataMember, lp1.OrdinateData, lp1.AbscissaData);
                SequenceAdapter a2 = new SequenceAdapter (lp2.DataSource, lp2.DataMember, lp2.OrdinateData, lp2.AbscissaData);

                // Start at first point of LinePlot 1 within plot bounds
                int start = 0;
                while (t.Transform (a1 [start]).X < xAxis.PhysicalMin.X) {
                    ++start;
                }
                Point first = t.Transform (a1 [start]);
                ctx.MoveTo (first);
                // Join LinePlot 1 points in ascending order
                Point next;
                for (int i = start+1; i < a1.Count-1; ++i) {
                    next = t.Transform (a1 [i]);
                    if (next.X > xAxis.PhysicalMax.X)
                        break;
                    ctx.LineTo (next);
                }
                // Then join LinePlot 2 points in descending order
                int end = a2.Count-1;
                while (t.Transform (a2 [end]).X > xAxis.PhysicalMax.X) {
                    --end;
                }
                for (int i = end; i > 0; --i) {
                    next = t.Transform (a2 [i]);
                    if (next.X < xAxis.PhysicalMin.X)
                        break;
                    ctx.LineTo (next);
                }
                ctx.LineTo (first);
                ctx.ClosePath ();
            }
            else {
                throw new XwPlotException ("Filled Region bounds not defined");
            }
            ctx.SetColor (FillColor);
            ctx.Fill ();
            ctx.Restore ();
        }
Esempio n. 24
0
            /// <summary>
            /// Applies the constraint to the axes.
            /// </summary>
            /// <param name="pXAxis1">The bottom x-axis.</param>
            /// <param name="pYAxis1">The left y-axis.</param>
            /// <param name="pXAxis2">The top x-axis.</param>
            /// <param name="pYAxis2">The right y-axis.</param>
            public override void ApplyConstraint( 
				PhysicalAxis pXAxis1, PhysicalAxis pYAxis1, 
				PhysicalAxis pXAxis2, PhysicalAxis pYAxis2 )
            {
                if (xAxisPosition_ != null) {

                    if ((XAxisPosition)xAxisPosition_ == XAxisPosition.Bottom) {
                        pXAxis1.PhysicalMin = new Point (pXAxis1.PhysicalMin.X, position_ );
                        pXAxis1.PhysicalMax = new Point (pXAxis1.PhysicalMax.X, position_ );

                        pYAxis1.PhysicalMin = new Point (pYAxis1.PhysicalMin.X, position_ );
                        pYAxis2.PhysicalMin = new Point (pYAxis2.PhysicalMin.X, position_ );
                    }
                    else {
                        pXAxis2.PhysicalMin = new Point (pXAxis2.PhysicalMin.X, position_ );
                        pXAxis2.PhysicalMax = new Point (pXAxis2.PhysicalMax.X, position_ );

                        pYAxis1.PhysicalMax = new Point (pYAxis1.PhysicalMax.X, position_ );
                        pYAxis2.PhysicalMax = new Point (pYAxis2.PhysicalMax.X, position_ );
                    }

                }
                else if (yAxisPosition_ != null) {

                    if ((YAxisPosition)yAxisPosition_ == YAxisPosition.Left) {
                        pYAxis1.PhysicalMin = new Point (position_, pYAxis1.PhysicalMin.Y );
                        pYAxis1.PhysicalMax = new Point (position_, pYAxis1.PhysicalMax.Y );

                        pXAxis1.PhysicalMin = new Point (position_, pXAxis1.PhysicalMin.Y );
                        pXAxis2.PhysicalMin = new Point (position_, pXAxis2.PhysicalMin.Y );
                    }
                    else {
                        pYAxis2.PhysicalMin = new Point (position_, pYAxis2.PhysicalMin.Y );
                        pYAxis2.PhysicalMax = new Point (position_, pYAxis2.PhysicalMax.Y );

                        pXAxis1.PhysicalMax = new Point (position_, pXAxis1.PhysicalMax.Y );
                        pXAxis2.PhysicalMax = new Point (position_, pXAxis2.PhysicalMax.Y );
                    }

                }
            }
Esempio n. 25
0
        /// <summary>
        /// Draws the step plot using a Drawing Context against the provided x and y axes.
        /// </summary>
        /// <param name="ctx">The Drawing Context with which to draw.</param>
        /// <param name="xAxis">The X-Axis to draw against.</param>
        /// <param name="yAxis">The Y-Axis to draw against.</param>
        public virtual void Draw(Context ctx, PhysicalAxis xAxis, PhysicalAxis yAxis)
        {
            SequenceAdapter data =
                new SequenceAdapter(DataSource, DataMember, OrdinateData, AbscissaData);

            double leftCutoff  = xAxis.PhysicalToWorld(xAxis.PhysicalMin, false);
            double rightCutoff = xAxis.PhysicalToWorld(xAxis.PhysicalMax, false);

            ctx.Save();
            ctx.SetColor(Color);
            ctx.SetLineWidth(1);

            for (int i = 0; i < data.Count; ++i)
            {
                Point p1 = data[i];
                if (Double.IsNaN(p1.X) || Double.IsNaN(p1.Y))
                {
                    continue;
                }

                Point p2;
                Point p3;
                if (i + 1 != data.Count)
                {
                    p2 = data[i + 1];
                    if (Double.IsNaN(p2.X) || Double.IsNaN(p2.Y))
                    {
                        continue;
                    }
                    p2.Y = p1.Y;
                    p3   = data[i + 1];
                }
                else
                {
                    // Check that we are not dealing with a DataSource of 1 point.
                    // This check is done here so it is only checked on the end
                    // condition and not for every point in the DataSource.
                    if (data.Count > 1)
                    {
                        p2 = data[i - 1];
                    }
                    else
                    {
                        p2 = p1;
                    }
                    double offset = p1.X - p2.X;
                    p2.X = p1.X + offset;
                    p2.Y = p1.Y;
                    p3   = p2;
                }

                if (centre)
                {
                    double offset = (p2.X - p1.X) / 2.0;
                    p1.X -= offset;
                    p2.X -= offset;
                    p3.X -= offset;
                }

                Point xPos1 = xAxis.WorldToPhysical(p1.X, false);
                Point yPos1 = yAxis.WorldToPhysical(p1.Y, false);
                Point xPos2 = xAxis.WorldToPhysical(p2.X, false);
                Point yPos2 = yAxis.WorldToPhysical(p2.Y, false);
                Point xPos3 = xAxis.WorldToPhysical(p3.X, false);
                Point yPos3 = yAxis.WorldToPhysical(p3.Y, false);

                // do horizontal clipping here, to speed up
                if ((p1.X < leftCutoff && p2.X < leftCutoff && p3.X < leftCutoff) || (p1.X > rightCutoff && p2.X > rightCutoff && p3.X > rightCutoff))
                {
                    continue;
                }

                if (!this.hideHorizontalSegments)
                {
                    if (scale != 1)
                    {
                        double middle = (xPos2.X + xPos1.X) / 2;
                        double width  = xPos2.X - xPos1.X;
                        width *= this.scale;
                        ctx.MoveTo(middle - width / 2, yPos1.Y);
                        ctx.LineTo(middle + width / 2, yPos2.Y);
                    }
                    else
                    {
                        ctx.MoveTo(xPos1.X, yPos1.Y);
                        ctx.LineTo(xPos2.X, yPos2.Y);
                    }
                    ctx.Stroke();
                }

                if (!this.hideVerticalSegments)
                {
                    ctx.MoveTo(xPos2.X, yPos2.Y);
                    ctx.LineTo(xPos3.X, yPos3.Y);
                    ctx.Stroke();
                }
            }
            ctx.Restore();
        }
Esempio n. 26
0
            /// <summary>
            /// Applies the constraint to the axes.
            /// </summary>
            /// <param name="pXAxis1">The bottom x-axis.</param>
            /// <param name="pYAxis1">The left y-axis.</param>
            /// <param name="pXAxis2">The top x-axis.</param>
            /// <param name="pYAxis2">The right y-axis.</param>
            public override void ApplyConstraint( 
				PhysicalAxis pXAxis1, PhysicalAxis pYAxis1, 
				PhysicalAxis pXAxis2, PhysicalAxis pYAxis2 )
            {
                double desiredLength = pYAxis1.Axis.WorldLength/pWorldLength_;
                double currentLength = pYAxis1.PhysicalLength;
                double delta = currentLength - desiredLength;

                double changeBottom = -delta / 2;
                double changeTop = -delta / 2;
                if (holdFixedX_ != null) {
                    if ((XAxisPosition)holdFixedX_ == XAxisPosition.Bottom) {
                        changeBottom = 0;
                        changeTop = -delta;
                    }
                    else {
                        changeBottom = -delta;
                        changeTop = 0;
                    }
                }

                pYAxis1.PhysicalMin = new Point( pYAxis1.PhysicalMin.X, pYAxis1.PhysicalMin.Y+changeBottom );
                pYAxis1.PhysicalMax = new Point( pYAxis1.PhysicalMax.X, pYAxis1.PhysicalMax.Y-changeTop );
                pYAxis2.PhysicalMin = new Point( pYAxis2.PhysicalMin.X, pYAxis2.PhysicalMin.Y+changeBottom );
                pYAxis2.PhysicalMax = new Point( pYAxis2.PhysicalMax.X, pYAxis2.PhysicalMax.Y-changeTop );

                pXAxis1.PhysicalMin = new Point( pXAxis1.PhysicalMin.X, pXAxis1.PhysicalMin.Y+changeBottom );
                pXAxis1.PhysicalMax = new Point( pXAxis1.PhysicalMax.X, pXAxis1.PhysicalMax.Y+changeBottom );
                pXAxis2.PhysicalMin = new Point( pXAxis2.PhysicalMin.X, pXAxis2.PhysicalMin.Y-changeTop );
                pXAxis2.PhysicalMax = new Point( pXAxis2.PhysicalMax.X, pXAxis2.PhysicalMax.Y-changeTop );
            }
Esempio n. 27
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="xAxis">The x-axis to use for transforms</param>
 /// <param name="yAxis">The y-axis to use for transforms</param>
 public FastTransform2D(PhysicalAxis xAxis, PhysicalAxis yAxis)
 {
     xAxis_ = new PageAlignedPhysicalAxis (xAxis);
     yAxis_ = new PageAlignedPhysicalAxis (yAxis);
 }
Esempio n. 28
0
 /// <summary>
 /// Draws the line plot using the Context and Physical Axes provided
 /// </summary>
 /// <param name="ctx">The Drawing Context with which to draw.</param>
 /// <param name="xAxis">The X-Axis to draw against.</param>
 /// <param name="yAxis">The Y-Axis to draw against.</param>
 public void Draw(Context ctx, PhysicalAxis xAxis, PhysicalAxis yAxis)
 {
     if (shadow) {
         DrawLineOrShadow (ctx, xAxis, yAxis, true);
     }
     DrawLineOrShadow (ctx, xAxis, yAxis, false);
 }
Esempio n. 29
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="xAxis">The x-axis to use for transforms</param>
 /// <param name="yAxis">The y-axis to use for transforms</param>
 public DefaultTransform2D(PhysicalAxis xAxis, PhysicalAxis yAxis)
 {
     xAxis_ = xAxis;
     yAxis_ = yAxis;
 }
Esempio n. 30
0
        /// <summary>
        /// Draws the arrow on a plot surface.
        /// </summary>
        /// <param name="ctx">the Drawing Context with which to draw</param>
        /// <param name="xAxis">The X-Axis to draw against.</param>
        /// <param name="yAxis">The Y-Axis to draw against.</param>
        public void Draw(Context ctx, PhysicalAxis xAxis, PhysicalAxis yAxis)
        {
            if (To.X > xAxis.Axis.WorldMax || To.X < xAxis.Axis.WorldMin)
            {
                return;
            }
            if (To.Y > yAxis.Axis.WorldMax || To.Y < yAxis.Axis.WorldMin)
            {
                return;
            }

            ctx.Save();

            TextLayout layout = new TextLayout();

            layout.Font = textFont_;
            layout.Text = text_;

            double angle = angle_;

            if (angle_ < 0.0)
            {
                int mul = -(int)(angle_ / 360.0) + 2;
                angle = angle_ + 360.0 * (double)mul;
            }

            double normAngle = (double)angle % 360.0;                   // angle in range 0 -> 360.

            Point toPoint = new Point(
                xAxis.WorldToPhysical(to_.X, true).X,
                yAxis.WorldToPhysical(to_.Y, true).Y);


            double xDir = Math.Cos(normAngle * 2.0 * Math.PI / 360.0);
            double yDir = Math.Sin(normAngle * 2.0 * Math.PI / 360.0);

            toPoint.X += xDir * headOffset_;
            toPoint.Y += yDir * headOffset_;

            double xOff = physicalLength_ * xDir;
            double yOff = physicalLength_ * yDir;

            Point fromPoint = new Point(
                (int)(toPoint.X + xOff),
                (int)(toPoint.Y + yOff));

            ctx.SetLineWidth(1);
            ctx.SetColor(arrowColor_);
            ctx.MoveTo(fromPoint);
            ctx.LineTo(toPoint);
            ctx.Stroke();

            xOff = headSize_ * Math.Cos((normAngle - headAngle_ / 2) * 2.0 * Math.PI / 360.0);
            yOff = headSize_ * Math.Sin((normAngle - headAngle_ / 2) * 2.0 * Math.PI / 360.0);

            ctx.LineTo(toPoint.X + xOff, toPoint.Y + yOff);

            double xOff2 = headSize_ * Math.Cos((normAngle + headAngle_ / 2) * 2.0 * Math.PI / 360.0);
            double yOff2 = headSize_ * Math.Sin((normAngle + headAngle_ / 2) * 2.0 * Math.PI / 360.0);

            ctx.LineTo(toPoint.X + xOff2, toPoint.Y + yOff2);
            ctx.LineTo(toPoint);
            ctx.ClosePath();
            ctx.SetColor(arrowColor_);
            ctx.Fill();

            Size textSize = layout.GetSize();
            Size halfSize = new Size(textSize.Width / 2, textSize.Height / 2);

            double quadrantSlideLength = halfSize.Width + halfSize.Height;

            double quadrantD = normAngle / 90.0;                        // integer part gives quadrant.
            int    quadrant  = (int)quadrantD;                          // quadrant in.
            double prop      = quadrantD - (double)quadrant;            // proportion of way through this qadrant.
            double dist      = prop * quadrantSlideLength;              // distance along quarter of bounds rectangle.

            // now find the offset from the middle of the text box that the
            // rear end of the arrow should end at (reverse this to get position
            // of text box with respect to rear end of arrow).
            //
            // There is almost certainly an elgant way of doing this involving
            // trig functions to get all the signs right, but I'm about ready to
            // drop off to sleep at the moment, so this blatent method will have
            // to do.
            Point offsetFromMiddle = new Point(0, 0);

            switch (quadrant)
            {
            case 0:
                if (dist > halfSize.Height)
                {
                    dist            -= halfSize.Height;
                    offsetFromMiddle = new Point(-halfSize.Width + dist, halfSize.Height);
                }
                else
                {
                    offsetFromMiddle = new Point(-halfSize.Width, -dist);
                }
                break;

            case 1:
                if (dist > halfSize.Width)
                {
                    dist            -= halfSize.Width;
                    offsetFromMiddle = new Point(halfSize.Width, halfSize.Height - dist);
                }
                else
                {
                    offsetFromMiddle = new Point(dist, halfSize.Height);
                }
                break;

            case 2:
                if (dist > halfSize.Height)
                {
                    dist            -= halfSize.Height;
                    offsetFromMiddle = new Point(halfSize.Width - dist, -halfSize.Height);
                }
                else
                {
                    offsetFromMiddle = new Point(halfSize.Width, -dist);
                }
                break;

            case 3:
                if (dist > halfSize.Width)
                {
                    dist            -= halfSize.Width;
                    offsetFromMiddle = new Point(-halfSize.Width, -halfSize.Height + dist);
                }
                else
                {
                    offsetFromMiddle = new Point(-dist, -halfSize.Height);
                }
                break;

            default:
                throw new XwPlotException("Programmer error.");
            }

            ctx.SetColor(textColor_);
            double x = fromPoint.X - halfSize.Width - offsetFromMiddle.X;
            double y = fromPoint.Y - halfSize.Height + offsetFromMiddle.Y;

            ctx.DrawTextLayout(layout, x, y);

            ctx.Restore();
        }
Esempio n. 31
0
        /// <summary>
        /// Draws the grid
        /// </summary>
        /// <param name="ctx">The Drawing Context with which to draw</param>
        /// <param name="xAxis">The physical x axis to draw horizontal lines parallel to.</param>
        /// <param name="yAxis">The physical y axis to draw vertical lines parallel to.</param>
        public void Draw(Context ctx, PhysicalAxis xAxis, PhysicalAxis yAxis)
        {
            ArrayList xLargePositions = null;
            ArrayList yLargePositions = null;
            ArrayList xSmallPositions = null;
            ArrayList ySmallPositions = null;

            ctx.Save ();

            // Draw MajorGrid
            gridColor = MajorGridColor;
            gridDash = majorGridDash;
            if (horizontalGridType != GridType.None) {
                xAxis.Axis.WorldTickPositions_FirstPass (xAxis.PhysicalMin, xAxis.PhysicalMax, out xLargePositions, out xSmallPositions);
                DrawGridLines (ctx, xAxis, yAxis, xLargePositions, true);
            }

            if (verticalGridType != GridType.None) {
                yAxis.Axis.WorldTickPositions_FirstPass (yAxis.PhysicalMin, yAxis.PhysicalMax, out yLargePositions, out ySmallPositions);
                DrawGridLines (ctx, yAxis, xAxis, yLargePositions, false);
            }

            // Draw MinorGrid
            gridColor = MinorGridColor;
            gridDash = minorGridDash;
            if (horizontalGridType == GridType.Fine) {
                xAxis.Axis.WorldTickPositions_SecondPass (xAxis.PhysicalMin, xAxis.PhysicalMax, xLargePositions, ref xSmallPositions);
                DrawGridLines(ctx, xAxis, yAxis, xSmallPositions, true);
            }

            if (verticalGridType == GridType.Fine) {
                yAxis.Axis.WorldTickPositions_SecondPass (yAxis.PhysicalMin, yAxis.PhysicalMax, yLargePositions, ref ySmallPositions);
                DrawGridLines (ctx, yAxis, xAxis, ySmallPositions, false);
            }
            ctx.Restore ();
        }
Esempio n. 32
0
 /// <summary>
 /// OnButtonReleased method for AxisScale interaction
 /// </summary>
 public override bool OnButtonReleased(ButtonEventArgs args, PlotCanvas pc)
 {
     if (dragging) {
         dragging = false;
         axis = null;
         physicalAxis = null;
         lastPoint = new Point();
         //pc.plotCursor = CursorType.LeftPointer;
     }
     return false;
 }
Esempio n. 33
0
        /// <summary>
        /// Does all the work in drawing grid lines.
        /// </summary>
        /// <param name="ctx">The graphics context with which to draw</param>
        /// <param name="axis">TODO</param>
        /// <param name="orthogonalAxis">TODO</param>
        /// <param name="a">the list of world values to draw grid lines at.</param>
        /// <param name="horizontal">true if want horizontal lines, false otherwise.</param>
        /// <param name="color">the color to draw the grid lines.</param>
        private void DrawGridLines(Context ctx,
			PhysicalAxis axis, PhysicalAxis orthogonalAxis,
			System.Collections.ArrayList a, bool horizontal)
        {
            for (int i=0; i<a.Count; ++i) {
                Point p1 = axis.WorldToPhysical ((double)a[i], true);
                Point p2 = p1;
                Point p3 = orthogonalAxis.PhysicalMax;
                Point p4 = orthogonalAxis.PhysicalMin;
                if (horizontal) {
                    p1.Y = p4.Y;
                    p2.Y = p3.Y;
                }
                else {
                    p1.X = p4.X;
                    p2.X = p3.X;
                }
                ctx.MoveTo (p1);
                ctx.LineTo (p2);
            }
            ctx.SetLineWidth (1);
            ctx.SetColor (gridColor);
            ctx.SetLineDash (0, gridDash);
            ctx.Stroke ();
        }
Esempio n. 34
0
        /// <summary>
        /// Updates the PlotSurface axes to compensate for the legend.
        /// </summary>
        /// <param name="pXAxis1">the bottom x axis</param>
        /// <param name="pYAxis1">the left y axis</param>
        /// <param name="pXAxis2">the top x axis</param>
        /// <param name="pYAxis2">the right y axis</param>
        /// <param name="plots">list of plots.</param>
        /// <param name="scale">scale parameter (for text and other)</param>
        /// <param name="padding">padding around plot within bounds.</param>
        /// <param name="bounds">graphics surface bounds</param>
        /// <param name="position">legend position</param>
        public void UpdateAxesPositions( 
			PhysicalAxis pXAxis1,
			PhysicalAxis pYAxis1,
			PhysicalAxis pXAxis2,
			PhysicalAxis pYAxis2,
			ArrayList plots,
			double scale,
			double padding,
			Rectangle bounds,
			out Point position)
        {
            double leftIndent = 0;
            double rightIndent = 0;
            double bottomIndent = 0;
            double topIndent = 0;

            position = new Point (0,0);

            // now determine if legend should change any of these (legend should be fully
            // visible at all times), and draw legend.

            Rectangle legendWidthHeight = GetBoundingBox (new Point(0,0), plots, scale);

            if (legendWidthHeight.Width > bounds.Width) {
                legendWidthHeight.Width = bounds.Width;
            }

            // (1) calculate legend position.

            // y
            position.Y = this.yOffset_;

            if (xAttach_ == XAxisPosition.Bottom) {
                position.Y += pYAxis1.PhysicalMin.Y;
                if (horizontalEdgePlacement_ == Legend.Placement.Inside) {
                    position.Y -= legendWidthHeight.Height;
                }
            }
            else {
                position.Y += pYAxis1.PhysicalMax.Y;
                if (horizontalEdgePlacement_ == Legend.Placement.Outside) {
                    position.Y -= legendWidthHeight.Height;
                }
            }

            // x
            position.X = xOffset_;

            if (yAttach_ == YAxisPosition.Left) {
                if (verticalEdgePlacement_ == Legend.Placement.Outside)  {
                    position.X -= legendWidthHeight.Width;
                }
                position.X += pXAxis1.PhysicalMin.X;
            }
            else {
                if (verticalEdgePlacement_ == Legend.Placement.Inside) {
                    position.X -= legendWidthHeight.Width;
                }
                position.X += pXAxis1.PhysicalMax.X;
            }

            // determine update amounts for axes

            if (!neverShiftAxes_) {
                if (position.X < padding) {
                    double changeAmount = -position.X + padding;
                    // only allow axes to move away from bounds.
                    if (changeAmount > 0) {
                        leftIndent = changeAmount;
                    }
                    position.X += changeAmount;
                }

                if (position.X + legendWidthHeight.Width > bounds.Right - padding) {
                    double changeAmount = (position.X - bounds.Right + legendWidthHeight.Width + padding);
                    // only allow axes to move away from bounds.
                    if (changeAmount > 0) {
                        rightIndent = changeAmount;
                    }
                    position.X -= changeAmount;
                }

                if (position.Y < padding) {
                    double changeAmount = -position.Y + padding;
                    // only allow axes to move away from bounds.
                    if (changeAmount > 0) {
                        topIndent = changeAmount;
                    }
                    position.Y += changeAmount;
                }

                if (position.Y + legendWidthHeight.Height > bounds.Bottom - padding)
                {
                    double changeAmount = (position.Y - bounds.Bottom + legendWidthHeight.Height + padding);
                    // only allow axes to move away from bounds.
                    if (changeAmount > 0) {
                        bottomIndent = changeAmount;
                    }
                    position.Y -= changeAmount;
                }

                // update axes.

                pXAxis1.PhysicalMin = new Point (pXAxis1.PhysicalMin.X + leftIndent, pXAxis1.PhysicalMin.Y - bottomIndent);
                pXAxis1.PhysicalMax = new Point (pXAxis1.PhysicalMax.X - rightIndent, pXAxis1.PhysicalMax.Y - bottomIndent);
                pYAxis1.PhysicalMin = new Point (pYAxis1.PhysicalMin.X + leftIndent, pYAxis1.PhysicalMin.Y - bottomIndent);
                pYAxis1.PhysicalMax = new Point (pYAxis1.PhysicalMax.X + leftIndent, pYAxis1.PhysicalMax.Y + topIndent);

                pXAxis2.PhysicalMin = new Point (pXAxis2.PhysicalMin.X + leftIndent, pXAxis2.PhysicalMin.Y + topIndent);
                pXAxis2.PhysicalMax = new Point (pXAxis2.PhysicalMax.X - rightIndent, pXAxis2.PhysicalMax.Y + topIndent);
                pYAxis2.PhysicalMin = new Point (pYAxis2.PhysicalMin.X - rightIndent, pYAxis2.PhysicalMin.Y - bottomIndent);
                pYAxis2.PhysicalMax = new Point (pYAxis2.PhysicalMax.X - rightIndent, pYAxis2.PhysicalMax.Y + topIndent);
            }
        }
Esempio n. 35
0
        /// <summary>
        /// Draw using the Drawing Context and Axes supplied
        /// </summary>
        /// <remarks>TODO: block positions may be off by a pixel or so. maybe. Re-think calculations</remarks>
        public void Draw(Context ctx, PhysicalAxis xAxis, PhysicalAxis yAxis)
        {
            if (data==null || data.GetLength(0) == 0 || data.GetLength(1) == 0) {
                return;
            }

            double worldWidth = xAxis.Axis.WorldMax - xAxis.Axis.WorldMin;
            double numBlocksHorizontal = worldWidth / xStep;
            double worldHeight = yAxis.Axis.WorldMax - yAxis.Axis.WorldMin;
            double numBlocksVertical = worldHeight / yStep;

            double physicalWidth = xAxis.PhysicalMax.X - xAxis.PhysicalMin.X;
            double blockWidth = physicalWidth / numBlocksHorizontal;
            bool wPositive = true;
            if (blockWidth < 0.0) {
                wPositive = false;
            }
            blockWidth = Math.Abs (blockWidth)+1;

            double physicalHeight = yAxis.PhysicalMax.Y - yAxis.PhysicalMin.Y;
            double blockHeight = physicalHeight / numBlocksVertical;
            bool hPositive = true;
            if (blockHeight < 0.0) {
                hPositive = false;
            }
            blockHeight = Math.Abs(blockHeight)+1;

            ctx.Save ();
            for (int i=0; i<data.GetLength(0); ++i) {
                for (int j=0; j<data.GetLength(1); ++j) {
                    double wX = (double)j*xStep + xStart;
                    double wY = (double)i*yStep + yStart;
                    if (!hPositive) {
                        wY += yStep;
                    }
                    if (!wPositive ) {
                        wX += xStep;
                    }
                    if (Center) {
                        wX -= xStep/2.0;
                        wY -= yStep/2.0;
                    }
                    Color color = Gradient.GetColor ((data[i,j]-DataMin)/(DataMax-DataMin));
                    ctx.SetColor (color);
                    double x = xAxis.WorldToPhysical(wX,false).X;
                    double y = yAxis.WorldToPhysical(wY,false).Y;
                    ctx.Rectangle (x, y, blockWidth, blockHeight);
                    ctx.Fill ();
                }
            }
            ctx.Restore ();
        }
Esempio n. 36
0
 /// <summary>
 /// Applies the constraint to the axes. Must be overriden.
 /// </summary>
 /// <param name="pXAxis1">The bottom x-axis.</param>
 /// <param name="pYAxis1">The left y-axis.</param>
 /// <param name="pXAxis2">The top x-axis.</param>
 /// <param name="pYAxis2">The right y-axis.</param>
 public abstract void ApplyConstraint(PhysicalAxis pXAxis1, PhysicalAxis pYAxis1, PhysicalAxis pXAxis2, PhysicalAxis pYAxis2);
Esempio n. 37
0
        /// <summary>
        /// Draws the point plot using the Drawing Context and x and y axes supplied
        /// </summary>
        /// <param name="ctx">The Drawing Context with which to draw.</param>
        /// <param name="xAxis">The X-Axis to draw against.</param>
        /// <param name="yAxis">The Y-Axis to draw against.</param>
        public virtual void Draw(Context ctx, PhysicalAxis xAxis, PhysicalAxis yAxis)
        {
            SequenceAdapter data_ = new SequenceAdapter (DataSource, DataMember, OrdinateData, AbscissaData );

            double leftCutoff_ = xAxis.PhysicalMin.X - marker.Size;
            double rightCutoff_ = xAxis.PhysicalMax.X + marker.Size;

            ctx.Save ();
            ctx.SetColor (marker.LineColor);
            ctx.SetLineWidth (marker.LineWidth);

            for (int i=0; i<data_.Count; ++i) {
                if (!Double.IsNaN(data_[i].X) && !Double.IsNaN(data_[i].Y)) {
                    Point xPos = xAxis.WorldToPhysical (data_[i].X, false);
                    if (xPos.X < leftCutoff_ || rightCutoff_ < xPos.X) {
                        continue;
                    }

                    Point yPos = yAxis.WorldToPhysical (data_[i].Y, false);
                    marker.Draw (ctx, xPos.X, yPos.Y);
                    if (marker.DropLine) {
                        Point yMin = new Point (data_[i].X, Math.Max (0.0, yAxis.Axis.WorldMin));
                        Point yStart = yAxis.WorldToPhysical (yMin.Y, false);
                        ctx.MoveTo (xPos.X, yStart.Y);
                        ctx.LineTo (xPos.X, yPos.Y);
                        ctx.Stroke ();
                    }
                }
            }
            ctx.Restore ();
        }
Esempio n. 38
0
        /// <summary>
        /// Draws the marker on a plot surface.
        /// </summary>
        /// <param name="ctx">The Drawing Context with which to draw</param>
        /// <param name="xAxis">The X-Axis to draw against.</param>
        /// <param name="yAxis">The Y-Axis to draw against.</param>
        public void Draw(Context ctx, PhysicalAxis xAxis, PhysicalAxis yAxis)
        {
            Point point = new Point (
                xAxis.WorldToPhysical (x_, true).X,
                yAxis.WorldToPhysical (y_, true ).Y);

            marker_.Draw (ctx, point.X, point.Y );
        }
Esempio n. 39
0
        /// <summary>
        /// Draws the candle plot with the specified Drawing Context and X,Y axes
        /// </summary>
        /// <param name="ctx">The Drawing Context with which to draw</param>
        /// <param name="xAxis">The physical X-Axis to draw against</param>
        /// <param name="yAxis">The physical Y-Axis to draw against</param>
        public void Draw(Context ctx, PhysicalAxis xAxis, PhysicalAxis yAxis)
        {
            CandleDataAdapter cd = new CandleDataAdapter(DataSource, DataMember,
                                                         AbscissaData, OpenData, LowData, HighData, CloseData);

            double offset = 0;

            if (Centered)
            {
                offset = CalculatePhysicalSeparation(cd, xAxis) / 2;
            }

            double addAmount  = StickWidth / 2;
            double stickWidth = StickWidth;

            if (StickWidth == AutoScaleStickWidth)
            {
                // default
                addAmount  = 2;
                stickWidth = 4;

                double minDist = CalculatePhysicalSeparation(cd, xAxis);

                addAmount  = minDist / 3;
                stickWidth = addAmount * 2;
            }

            ctx.Save();
            ctx.SetLineWidth(1);

            /*
             * // brant hyatt proposed.
             * if (Style == Styles.Stick)
             * {
             *      p.Width = stickWidth;
             *      addAmount = stickWidth + 2;
             * }
             */

            for (int i = 0; i < cd.Count; ++i)
            {
                PointOLHC point = (PointOLHC)cd [i];
                if ((!double.IsNaN(point.Open)) && (!double.IsNaN(point.High)) &&
                    (!double.IsNaN(point.Low)) && (!double.IsNaN(point.Close)))
                {
                    double xPos = (xAxis.WorldToPhysical(point.X, false)).X;

                    if (xPos + offset + addAmount < xAxis.PhysicalMin.X || xAxis.PhysicalMax.X < xPos + offset - addAmount)
                    {
                        continue;
                    }

                    double yLo  = (yAxis.WorldToPhysical(point.Low, false)).Y;
                    double yHi  = (yAxis.WorldToPhysical(point.High, false)).Y;
                    double yOpn = (yAxis.WorldToPhysical(point.Open, false)).Y;
                    double yCls = (yAxis.WorldToPhysical(point.Close, false)).Y;

                    if (Style == Styles.Stick)
                    {
                        /*
                         * // brant hyatt proposed.
                         * if (i > 0)
                         * {
                         *      if ( ((PointOLHC)cd[i]).Close > ((PointOLHC)cd[i-1]).Close)
                         *      {
                         *              p.Color = BullishColor;
                         *      }
                         *      else
                         *      {
                         *              p.Color = BearishColor;
                         *      }
                         * }
                         */
                        ctx.SetColor(Color);
                        ctx.MoveTo(xPos + offset, yLo);
                        ctx.LineTo(xPos + offset, yHi);                                 // Low to High line

                        ctx.MoveTo(xPos - addAmount + offset, yOpn);
                        ctx.LineTo(xPos + offset, yOpn);                                // Open line

                        ctx.MoveTo(xPos + addAmount + offset, yCls);
                        ctx.LineTo(xPos + offset, yCls);                                // Close line
                        ctx.Stroke();
                    }
                    else if (Style == Styles.Filled)
                    {
                        ctx.MoveTo(xPos + offset, yLo);
                        ctx.LineTo(xPos + offset, yHi);
                        ctx.Stroke();
                        if (yOpn > yCls)
                        {
                            ctx.SetColor(BullishColor);
                            ctx.Rectangle(xPos - addAmount + offset, yCls, stickWidth, yOpn - yCls);
                            ctx.FillPreserve();
                            ctx.SetColor(Color);
                            ctx.Stroke();
                        }
                        else if (yOpn < yCls)
                        {
                            ctx.SetColor(BearishColor);
                            ctx.Rectangle(xPos - addAmount + offset, yOpn, stickWidth, yCls - yOpn);
                            ctx.FillPreserve();
                            ctx.SetColor(Color);
                            ctx.Stroke();
                        }
                        else                            // Cls == Opn
                        {
                            ctx.MoveTo(xPos - addAmount + offset, yOpn);
                            ctx.LineTo(xPos - addAmount + stickWidth + offset, yCls);
                            ctx.Stroke();
                        }
                    }
                }
            }
            ctx.Restore();
        }
Esempio n. 40
0
        /// <summary>
        /// Calculates the physical (not world) separation between abscissa values.
        /// </summary>
        /// <param name="cd">Candle adapter containing data</param>
        /// <param name="xAxis">Physical x axis the data is plotted against.</param>
        /// <returns>physical separation between abscissa values.</returns>
        private static double CalculatePhysicalSeparation(CandleDataAdapter cd, PhysicalAxis xAxis)
        {
            if (cd.Count > 1) {
                double xPos1 = (xAxis.WorldToPhysical( ((PointOLHC)cd[0]).X, false )).X;
                double xPos2 = (xAxis.WorldToPhysical( ((PointOLHC)cd[1]).X, false )).X;
                double minDist = xPos2 - xPos1;

                if (cd.Count > 2) {  // to be pretty sure we get the smallest gap.
                    double xPos3 = (xAxis.WorldToPhysical(((PointOLHC)cd[2]).X, false)).X;
                    if (xPos3 - xPos2 < minDist) {
                        minDist = xPos3 - xPos2;
                    }

                    if (cd.Count > 3) {
                        double xPos4 = (xAxis.WorldToPhysical(((PointOLHC)cd[3]).X, false)).X;
                        if (xPos4 - xPos3 < minDist) {
                            minDist = xPos4 - xPos3;
                        }
                    }
                }
                return minDist;
            }
            return 0;
        }
Esempio n. 41
0
        /// <summary>
        /// Draws the histogram.
        /// </summary>
        /// <param name="ctx">The Drawing Context with which to draw</param>
        /// <param name="xAxis">The X-Axis to draw against.</param>
        /// <param name="yAxis">The Y-Axis to draw against.</param>
        public void Draw(Context ctx, PhysicalAxis xAxis, PhysicalAxis yAxis)
        {
            double yoff;
            SequenceAdapter data = new SequenceAdapter (DataSource, DataMember, OrdinateData, AbscissaData);

            ctx.Save ();
            ctx.SetLineWidth (1);

            for (int i=0; i<data.Count; ++i ) {

                // (1) determine the top left hand point of the bar (assuming not centered)
                Point p1 = data[i];
                if (double.IsNaN(p1.X) || double.IsNaN(p1.Y)) {
                    continue;
                }

                // (2) determine the top right hand point of the bar (assuming not centered)
                Point p2 = Point.Zero;;
                if (i+1 != data.Count) {
                    p2 = data[i+1];
                    if (double.IsNaN(p2.X) || double.IsNaN(p2.Y)) {
                        continue;
                    }
                    p2.Y = p1.Y;
                }
                else if (i != 0) {
                    p2 = data[i-1];
                    if (double.IsNaN(p2.X) || double.IsNaN(p2.Y)) {
                        continue;
                    }
                    double offset = p1.X - p2.X;
                    p2.X = p1.X + offset;
                    p2.Y = p1.Y;
                }
                else {
                    double offset = 1.0;
                    p2.X = p1.X + offset;
                    p2.Y = p1.Y;
                }

                // (3) now account for plots this may be stacked on top of.
                HistogramPlot currentPlot = this;
                yoff = 0.0;
                double yval = 0.0;
                while (currentPlot.IsStacked) {
                    SequenceAdapter stackedToData = new SequenceAdapter (
                        currentPlot.stackedTo.DataSource,
                        currentPlot.stackedTo.DataMember,
                        currentPlot.stackedTo.OrdinateData,
                        currentPlot.stackedTo.AbscissaData );

                    yval += stackedToData[i].Y;
                    yoff = yAxis.WorldToPhysical (yval, false).Y;
                    p1.Y += stackedToData[i].Y;
                    p2.Y += stackedToData[i].Y;
                    currentPlot = currentPlot.stackedTo;
                }

                // (4) now account for centering
                if (Center) {
                    double offset = (p2.X - p1.X) / 2.0;
                    p1.X -= offset;
                    p2.X -= offset;
                }

                // (5) now account for BaseOffset (shift of bar sideways).
                p1.X += BaseOffset;
                p2.X += BaseOffset;

                // (6) now get physical coordinates of top two points.
                Point xPos1 = xAxis.WorldToPhysical (p1.X, false);
                Point yPos1 = yAxis.WorldToPhysical (p1.Y, false);
                Point xPos2 = xAxis.WorldToPhysical (p2.X, false);

                if (IsStacked) {
                    currentPlot = this;
                    while (currentPlot.IsStacked) {
                        currentPlot = currentPlot.stackedTo;
                    }
                    baseWidth = currentPlot.baseWidth;
                }

                double width = xPos2.X - xPos1.X;
                double height;
                if (IsStacked) {
                    height = -yPos1.Y+yoff;
                }
                else {
                    height = -yPos1.Y+yAxis.PhysicalMin.Y;
                }

                double xoff = (1.0 - baseWidth)/2.0*width;
                Rectangle bar = new Rectangle (xPos1.X+xoff, yPos1.Y, width-2*xoff, height);

                ctx.Rectangle (bar);
                if (Filled) {
                    if (bar.Height != 0 && bar.Width != 0) {
                        if (FillGradient != null) {
                            // Scale FillGradient to bar rectangle
                            double sX = bar.X + fillGradient.StartPoint.X * bar.Width;
                            double sY = bar.Y + fillGradient.StartPoint.Y * bar.Height;
                            double eX = bar.X + fillGradient.EndPoint.X * bar.Width;
                            double eY = bar.Y + fillGradient.EndPoint.Y * bar.Height;
                            LinearGradient g = new LinearGradient (sX, sY, eX, eY);
                            g.AddColorStop (0, FillGradient.StartColor);
                            g.AddColorStop (1, FillGradient.EndColor);
                            ctx.Pattern = g;
                        } else {
                            ctx.SetColor (FillColor);
                        }
                        ctx.FillPreserve ();
                    }
                }
                ctx.SetColor (BorderColor);
                ctx.Stroke ();
            }
            ctx.Restore ();
        }
Esempio n. 42
0
        /// <summary>
        /// Draw the filled region
        /// </summary>
        /// <param name="g">The Drawing Context with which to draw.</param>
        /// <param name="xAxis">The X-Axis to draw against.</param>
        /// <param name="yAxis">The Y-Axis to draw against.</param>
        public void Draw(Context ctx, PhysicalAxis xAxis, PhysicalAxis yAxis)
        {
            ITransform2D t = Transform2D.GetTransformer(xAxis, yAxis);

            ctx.Save();

            if (hl1 != null && hl2 != null)
            {
                ctx.MoveTo(t.Transform(xAxis.Axis.WorldMin, hl1.OrdinateValue));
                ctx.LineTo(t.Transform(xAxis.Axis.WorldMax, hl1.OrdinateValue));
                ctx.LineTo(t.Transform(xAxis.Axis.WorldMax, hl2.OrdinateValue));
                ctx.LineTo(t.Transform(xAxis.Axis.WorldMin, hl2.OrdinateValue));
                ctx.ClosePath();
            }
            else if (vl1 != null && vl2 != null)
            {
                ctx.MoveTo(t.Transform(vl1.AbscissaValue, yAxis.Axis.WorldMin));
                ctx.LineTo(t.Transform(vl1.AbscissaValue, yAxis.Axis.WorldMax));
                ctx.LineTo(t.Transform(vl2.AbscissaValue, yAxis.Axis.WorldMax));
                ctx.LineTo(t.Transform(vl2.AbscissaValue, yAxis.Axis.WorldMin));
                ctx.ClosePath();
            }
            else if (lp1 != null && lp2 != null)
            {
                SequenceAdapter a1 = new SequenceAdapter(lp1.DataSource, lp1.DataMember, lp1.OrdinateData, lp1.AbscissaData);
                SequenceAdapter a2 = new SequenceAdapter(lp2.DataSource, lp2.DataMember, lp2.OrdinateData, lp2.AbscissaData);

                // Start at first point of LinePlot 1 within plot bounds
                int start = 0;
                while (t.Transform(a1 [start]).X < xAxis.PhysicalMin.X)
                {
                    ++start;
                }
                Point first = t.Transform(a1 [start]);
                ctx.MoveTo(first);
                // Join LinePlot 1 points in ascending order
                Point next;
                for (int i = start + 1; i < a1.Count - 1; ++i)
                {
                    next = t.Transform(a1 [i]);
                    if (next.X > xAxis.PhysicalMax.X)
                    {
                        break;
                    }
                    ctx.LineTo(next);
                }
                // Then join LinePlot 2 points in descending order
                int end = a2.Count - 1;
                while (t.Transform(a2 [end]).X > xAxis.PhysicalMax.X)
                {
                    --end;
                }
                for (int i = end; i > 0; --i)
                {
                    next = t.Transform(a2 [i]);
                    if (next.X < xAxis.PhysicalMin.X)
                    {
                        break;
                    }
                    ctx.LineTo(next);
                }
                ctx.LineTo(first);
                ctx.ClosePath();
            }
            else
            {
                throw new XwPlotException("Filled Region bounds not defined");
            }
            ctx.SetColor(FillColor);
            ctx.Fill();
            ctx.Restore();
        }
Esempio n. 43
0
        /// <summary>
        /// Updates the PlotSurface axes to compensate for the legend.
        /// </summary>
        /// <param name="pXAxis1">the bottom x axis</param>
        /// <param name="pYAxis1">the left y axis</param>
        /// <param name="pXAxis2">the top x axis</param>
        /// <param name="pYAxis2">the right y axis</param>
        /// <param name="plots">list of plots.</param>
        /// <param name="scale">scale parameter (for text and other)</param>
        /// <param name="padding">padding around plot within bounds.</param>
        /// <param name="bounds">graphics surface bounds</param>
        /// <param name="position">legend position</param>
        public void UpdateAxesPositions(
            PhysicalAxis pXAxis1,
            PhysicalAxis pYAxis1,
            PhysicalAxis pXAxis2,
            PhysicalAxis pYAxis2,
            ArrayList plots,
            double scale,
            double padding,
            Rectangle bounds,
            out Point position)
        {
            double leftIndent   = 0;
            double rightIndent  = 0;
            double bottomIndent = 0;
            double topIndent    = 0;

            position = new Point(0, 0);

            // now determine if legend should change any of these (legend should be fully
            // visible at all times), and draw legend.

            Rectangle legendWidthHeight = GetBoundingBox(new Point(0, 0), plots, scale);

            if (legendWidthHeight.Width > bounds.Width)
            {
                legendWidthHeight.Width = bounds.Width;
            }

            // (1) calculate legend position.

            // y
            position.Y = this.yOffset_;

            if (xAttach_ == XAxisPosition.Bottom)
            {
                position.Y += pYAxis1.PhysicalMin.Y;
                if (horizontalEdgePlacement_ == Legend.Placement.Inside)
                {
                    position.Y -= legendWidthHeight.Height;
                }
            }
            else
            {
                position.Y += pYAxis1.PhysicalMax.Y;
                if (horizontalEdgePlacement_ == Legend.Placement.Outside)
                {
                    position.Y -= legendWidthHeight.Height;
                }
            }

            // x
            position.X = xOffset_;

            if (yAttach_ == YAxisPosition.Left)
            {
                if (verticalEdgePlacement_ == Legend.Placement.Outside)
                {
                    position.X -= legendWidthHeight.Width;
                }
                position.X += pXAxis1.PhysicalMin.X;
            }
            else
            {
                if (verticalEdgePlacement_ == Legend.Placement.Inside)
                {
                    position.X -= legendWidthHeight.Width;
                }
                position.X += pXAxis1.PhysicalMax.X;
            }


            // determine update amounts for axes

            if (!neverShiftAxes_)
            {
                if (position.X < padding)
                {
                    double changeAmount = -position.X + padding;
                    // only allow axes to move away from bounds.
                    if (changeAmount > 0)
                    {
                        leftIndent = changeAmount;
                    }
                    position.X += changeAmount;
                }

                if (position.X + legendWidthHeight.Width > bounds.Right - padding)
                {
                    double changeAmount = (position.X - bounds.Right + legendWidthHeight.Width + padding);
                    // only allow axes to move away from bounds.
                    if (changeAmount > 0)
                    {
                        rightIndent = changeAmount;
                    }
                    position.X -= changeAmount;
                }

                if (position.Y < padding)
                {
                    double changeAmount = -position.Y + padding;
                    // only allow axes to move away from bounds.
                    if (changeAmount > 0)
                    {
                        topIndent = changeAmount;
                    }
                    position.Y += changeAmount;
                }

                if (position.Y + legendWidthHeight.Height > bounds.Bottom - padding)
                {
                    double changeAmount = (position.Y - bounds.Bottom + legendWidthHeight.Height + padding);
                    // only allow axes to move away from bounds.
                    if (changeAmount > 0)
                    {
                        bottomIndent = changeAmount;
                    }
                    position.Y -= changeAmount;
                }

                // update axes.

                pXAxis1.PhysicalMin = new Point(pXAxis1.PhysicalMin.X + leftIndent, pXAxis1.PhysicalMin.Y - bottomIndent);
                pXAxis1.PhysicalMax = new Point(pXAxis1.PhysicalMax.X - rightIndent, pXAxis1.PhysicalMax.Y - bottomIndent);
                pYAxis1.PhysicalMin = new Point(pYAxis1.PhysicalMin.X + leftIndent, pYAxis1.PhysicalMin.Y - bottomIndent);
                pYAxis1.PhysicalMax = new Point(pYAxis1.PhysicalMax.X + leftIndent, pYAxis1.PhysicalMax.Y + topIndent);

                pXAxis2.PhysicalMin = new Point(pXAxis2.PhysicalMin.X + leftIndent, pXAxis2.PhysicalMin.Y + topIndent);
                pXAxis2.PhysicalMax = new Point(pXAxis2.PhysicalMax.X - rightIndent, pXAxis2.PhysicalMax.Y + topIndent);
                pYAxis2.PhysicalMin = new Point(pYAxis2.PhysicalMin.X - rightIndent, pYAxis2.PhysicalMin.Y - bottomIndent);
                pYAxis2.PhysicalMax = new Point(pYAxis2.PhysicalMax.X - rightIndent, pYAxis2.PhysicalMax.Y + topIndent);
            }
        }
Esempio n. 44
0
        /// <summary>
        /// Draws the horizontal line plot using the Context and the x and y axes specified
        /// </summary>
        /// <param name="ctx">The Context with which to draw.</param>
        /// <param name="xAxis">The X-Axis to draw against.</param>
        /// <param name="yAxis">The Y-Axis to draw against.</param>
        public void Draw(Context ctx, PhysicalAxis xAxis, PhysicalAxis yAxis)
        {
            double xMin = xAxis.PhysicalMin.X;
            double xMax = xAxis.PhysicalMax.X;

            xMin += pixelIndent_;
            xMax -= pixelIndent_;

            double length = Math.Abs (xMax - xMin);
            double lengthDiff = length - length*scale_;
            double indentAmount = lengthDiff/2;

            xMin += indentAmount;
            xMax -= indentAmount;

            double yPos = yAxis.WorldToPhysical (value_, false).Y;

            ctx.Save ();
            ctx.SetLineWidth (1);
            ctx.SetColor (color_);
            ctx.MoveTo (xMin, yPos);
            ctx.LineTo (xMax, yPos);
            ctx.Stroke ();
            ctx.Restore ();

            // todo:  clip and proper logic for flipped axis min max.
        }
Esempio n. 45
0
        void DeterminePhysicalAxesToDraw(Rectangle bounds,
                                         Axis XAxis1, Axis XAxis2, Axis YAxis1, Axis YAxis2,
                                         out PhysicalAxis pXAxis1, out PhysicalAxis pXAxis2,
                                         out PhysicalAxis pYAxis1, out PhysicalAxis pYAxis2)
        {
            Rectangle cb = bounds;

            pXAxis1 = new PhysicalAxis(XAxis1,
                                       new Point(cb.Left, cb.Bottom), new Point(cb.Right, cb.Bottom));
            pYAxis1 = new PhysicalAxis(YAxis1,
                                       new Point(cb.Left, cb.Bottom), new Point(cb.Left, cb.Top));
            pXAxis2 = new PhysicalAxis(XAxis2,
                                       new Point(cb.Left, cb.Top), new Point(cb.Right, cb.Top));
            pYAxis2 = new PhysicalAxis(YAxis2,
                                       new Point(cb.Right, cb.Bottom), new Point(cb.Right, cb.Top));

            double bottomIndent = Padding;

            if (!pXAxis1.Axis.Hidden)
            {
                // evaluate its bounding box
                Rectangle bb = pXAxis1.GetBoundingBox();
                // finally determine its indentation from the bottom
                bottomIndent = bottomIndent + bb.Bottom - cb.Bottom;
            }

            double leftIndent = Padding;

            if (!pYAxis1.Axis.Hidden)
            {
                // evaluate its bounding box
                Rectangle bb = pYAxis1.GetBoundingBox();
                // finally determine its indentation from the left
                leftIndent = leftIndent - bb.Left + cb.Left;
            }

            // determine title size
            double scale = DetermineScaleFactor(bounds.Width, bounds.Height);
            Font   scaled_font;

            if (AutoScaleTitle)
            {
                scaled_font = TitleFont.WithScaledSize(scale);
            }
            else
            {
                scaled_font = TitleFont;
            }

            Size titleSize;

            using (TextLayout layout = new TextLayout()) {
                layout.Font = scaled_font;
                layout.Text = Title;
                titleSize   = layout.GetSize();
            };
            double topIndent = Padding;

            if (!pXAxis2.Axis.Hidden)
            {
                // evaluate its bounding box
                Rectangle bb = pXAxis2.GetBoundingBox();
                topIndent = topIndent - bb.Top + cb.Top;

                // finally determine its indentation from the top
                // correct top indendation to take into account plot title
                if (Title != "")
                {
                    topIndent += titleSize.Height * 1.3;
                }
            }

            double rightIndent = Padding;

            if (!pYAxis2.Axis.Hidden)
            {
                // evaluate its bounding box
                Rectangle bb = pYAxis2.GetBoundingBox();

                // finally determine its indentation from the right
                rightIndent += (bb.Right - cb.Right);
            }

            // now we have all the default calculated positions and we can proceed to
            // "move" the axes to their right places

            // primary axes (bottom, left)
            pXAxis1.PhysicalMin = new Point(cb.Left + leftIndent, cb.Bottom - bottomIndent);
            pXAxis1.PhysicalMax = new Point(cb.Right - rightIndent, cb.Bottom - bottomIndent);
            pYAxis1.PhysicalMin = new Point(cb.Left + leftIndent, cb.Bottom - bottomIndent);
            pYAxis1.PhysicalMax = new Point(cb.Left + leftIndent, cb.Top + topIndent);

            // secondary axes (top, right)
            pXAxis2.PhysicalMin = new Point(cb.Left + leftIndent, cb.Top + topIndent);
            pXAxis2.PhysicalMax = new Point(cb.Right - rightIndent, cb.Top + topIndent);
            pYAxis2.PhysicalMin = new Point(cb.Right - rightIndent, cb.Bottom - bottomIndent);
            pYAxis2.PhysicalMax = new Point(cb.Right - rightIndent, cb.Top + topIndent);
        }