/// <summary>
        /// rule coordinates (x:[0..1], y:axis)
        /// </summary>
        /// <param name="icrc">The context.</param>
        void IRequireTransforms.Transforms(IChartRenderContext icrc)
        {
            if (ValueAxis == null)
            {
                return;
            }
            var matx = MatrixSupport.TransformFor(icrc.SeriesArea, ValueAxis);

            _trace.Verbose($"transforms sy:{matx.M22:F3} matx:{matx} sa:{icrc.SeriesArea}");
            if (ClipToDataRegion)
            {
                Path.Clip = new RectangleGeometry()
                {
                    Rect = icrc.SeriesArea
                };
            }
            var vx     = ValueAxis.For(Value);
            var offset = matx.Transform(new Point(0, vx));

            Rule.SetValue(Canvas.TopProperty, offset.Y);
            matx.OffsetY   = 0;
            Rule.Transform = new MatrixTransform()
            {
                Matrix = matx
            };
        }
예제 #2
0
        /// <summary>
        /// Scale the NDC rectangle to the dimensions given.
        /// </summary>
        /// <param name="icrc">Context.</param>
        void IRequireTransforms.Transforms(IChartRenderContext icrc)
        {
            var matx = MatrixSupport.ProjectForQuadrant(4, icrc.SeriesArea);

            Rectangle.Transform = new MatrixTransform()
            {
                Matrix = matx
            };
        }
        /// <summary>
        /// Adjust transforms for the various components.
        /// Geometry: scaled to actual values in cartesian coordinates as indicated by axes.
        /// </summary>
        /// <param name="icrc"></param>
        void IRequireTransforms.Transforms(IChartRenderContext icrc)
        {
            if (CategoryAxis == null || ValueAxis == null)
            {
                return;
            }
            if (ItemState.Count == 0)
            {
                return;
            }
            var mp = MatrixSupport.DataArea(CategoryAxis, ValueAxis, icrc.Area, 1);
            // cancel x-offset
            var proj2 = mp.Item2;

            proj2.OffsetX = 0;
            // get the local marker matrix
            var marker = MatrixSupport.LocalFor(mp.Item1, MarkerWidth, icrc.Area, -MarkerOrigin.X, -MarkerOrigin.Y);
            // get the offset matrix
            var mato = MatrixSupport.Multiply(mp.Item1, proj2);

            foreach (var state in ItemState)
            {
                // assemble Mk * M * P transform for this path
                var iworld = (state as IItemStateMatrix).World;
                var model  = MatrixSupport.Multiply(marker, iworld);
                var matx   = MatrixSupport.Multiply(model, proj2);
                var mt     = new MatrixTransform()
                {
                    Matrix = matx
                };
                if (state.Element.DataContext is GeometryWithOffsetShim <Geometry> gs)
                {
                    gs.GeometryTransform = mt;
                    var output = mato.Transform(new Point(state.XValue, 0));
                    gs.Offset = icrc.Area.Left + output.X;
                }
                else
                {
                    state.Element.Data.Transform = mt;
                }
                if (ClipToDataRegion)
                {
                    state.Element.Clip = new RectangleGeometry()
                    {
                        Rect = icrc.SeriesArea
                    };
                }
            }
            _trace.Verbose($"{Name} mat:{mp.Item1} clip:{icrc.SeriesArea}");
        }
        /// <summary>
        /// The geometry is a circle of radius 10 centered at (0,0).
        /// </summary>
        /// <param name="area">Projection area.</param>
        /// <returns>MP matrix for this component's geometry.</returns>
        Matrix IProvideCustomTransform.TransformFor(Rect area)
        {
            var range = 2.0 * RADIUS;
            var mmatx = new Matrix(1.0 / range, 0, 0, -1.0 / range, RADIUS / range, RADIUS / range);
            var pmatx = MatrixSupport.ProjectForQuadrant(4, area);
            // lock aspect ratio to smallest dimension so it's a circle
            var scale = Math.Min(pmatx.M11, pmatx.M22);

            pmatx.M11 = pmatx.M22 = scale;
            // TODO adjust offset so it's centered
            var matx = MatrixSupport.Multiply(mmatx, pmatx);

            _trace.Verbose($"{Name} mat:{matx} M:{mmatx} P:{pmatx}");
            return(matx);
        }
        void IRequireAfterAxesFinalized.AxesFinalized(IChartRenderContext icrc)
        {
            if (icrc.Type == RenderType.TransformsOnly)
            {
                return;
            }
            var mat   = MatrixSupport.DataArea(CategoryAxis1, CategoryAxis2, icrc.SeriesArea, 4);
            var matmp = MatrixSupport.Multiply(mat.Item1, mat.Item2);

            _trace.Verbose($"{Name} matmp:{matmp} clip:{icrc.SeriesArea}");
            var mt = new MatrixTransform()
            {
                Matrix = matmp
            };

            StyleGenerator?.Reset();
            foreach (var istate in ItemState)
            {
                if (istate.Element.DataContext is GeometryWith2OffsetShim <RectangleGeometry> gs)
                {
                    gs.GeometryTransform = mt;
                }
                else
                {
                    istate.Element.Data.Transform = mt;
                }
                if (StyleGenerator != null)
                {
                    var style = StyleGenerator.For(new Category2StyleContext(CategoryAxis1, CategoryAxis2, this, new double[3] {
                        istate.Value, istate.XValue, (istate as IProvideYValue).YValue
                    }));
                    if (style != null)
                    {
                        istate.Element.Style = style;
                    }
                    else
                    {
                        if (PathStyle != null)
                        {
                            BindTo(this, nameof(PathStyle), istate.Element, FrameworkElement.StyleProperty);
                        }
                    }
                }
            }
            StyleGenerator?.UpdateLegend(new Category2StyleContext(CategoryAxis1, CategoryAxis2, this, new double[0]));
        }
        /// <summary>
        /// Adjust transforms for the various components.
        /// Geometry: scaled to actual values in cartesian coordinates as indicated by axes.
        /// </summary>
        /// <param name="icrc"></param>
        void IRequireTransforms.Transforms(IChartRenderContext icrc)
        {
            if (CategoryAxis1 == null || CategoryAxis2 == null)
            {
                return;
            }
            if (ItemState.Count == 0)
            {
                return;
            }
            // TODO quad depends on orientations of both axes this is assuming default orientations
            var mat   = MatrixSupport.DataArea(CategoryAxis1, CategoryAxis2, icrc.SeriesArea, 4);
            var matmp = MatrixSupport.Multiply(mat.Item1, mat.Item2);

            _trace.Verbose($"{Name} matmp:{matmp} clip:{icrc.SeriesArea}");
            var mt = new MatrixTransform()
            {
                Matrix = matmp
            };

            foreach (var state in ItemState)
            {
                if (state.Element.DataContext is GeometryWith2OffsetShim <RectangleGeometry> gs)
                {
                    gs.GeometryTransform = mt;
                    var output = matmp.Transform(new Point(state.XValue, (state as IProvideYValue).YValue));
                    gs.Offset  = output.X - icrc.SeriesArea.Left;
                    gs.Offset2 = output.Y - icrc.SeriesArea.Top;
                }
                else
                {
                    state.Element.Data.Transform = mt;
                }
                if (ClipToDataRegion)
                {
                    var cg = new RectangleGeometry()
                    {
                        Rect = icrc.SeriesArea
                    };
                    state.Element.Clip = cg;
                }
            }
        }
예제 #7
0
        Matrix ProjectionForAxis(Rect area, double scale)
        {
            switch (Side)
            {
            case Side.Bottom:
                return(MatrixSupport.ProjectionFor(area.Left, area.Top + AxisMargin, scale, 1));

            case Side.Top:
                return(MatrixSupport.ProjectionFor(area.Left, area.Bottom - AxisMargin, scale, 1));

            case Side.Left:
                return(MatrixSupport.ProjectionFor(area.Right - AxisMargin, area.Top, 1, scale));

            case Side.Right:
                return(MatrixSupport.ProjectionFor(area.Left + AxisMargin, area.Top, 1, scale));

            default:
                throw new NotImplementedException($"Not Implemented: {Side}");
            }
        }
        void IRequireAfterAxesFinalized.AxesFinalized(IChartRenderContext icrc)
        {
            if (CategoryAxis == null || ValueAxis == null)
            {
                return;
            }
            if (ItemState.Count == 0)
            {
                return;
            }
            var world = MatrixSupport.ModelFor(CategoryAxis, ValueAxis);

            foreach (var state in ItemState)
            {
                if (state is IItemStateMatrix ism)
                {
                    ism.World = MatrixSupport.Translate(world, state.XOffset, state.Value);
                }
            }
        }
예제 #9
0
        /// <summary>
        /// Adjust transforms for the various components.
        /// Geometry: scaled to actual values in cartesian coordinates as indicated by axes.
        /// </summary>
        /// <param name="icrc"></param>
        void IRequireTransforms.Transforms(IChartRenderContext icrc)
        {
            if (CategoryAxis == null || ValueAxis == null)
            {
                return;
            }
            if (ItemState.Count == 0)
            {
                return;
            }
            var mp = MatrixSupport.DataArea(CategoryAxis, ValueAxis, icrc.Area, 1);
            // get the offset matrix
            var mato = MatrixSupport.Multiply(mp.Item1, mp.Item2);
            // TODO preserve aspect ratio of image; will require ImageOpened evh
            var dimx = MarkerWidth * mato.M11;

            _trace.Verbose($"dimx {dimx}");
            foreach (var state in ItemState)
            {
                if (state.Element.DataContext is ImageSourceShim iss)
                {
                    var output = mato.Transform(new Point(state.XValue + MarkerOffset, state.Value));
                    _trace.Verbose($"output {output.X:F1},{output.Y:F1}  value {state.XValue},{state.Value}  image {state.Element.ActualWidth:F1}x{state.Element.ActualHeight:F1}");
                    var hw = dimx * MarkerOrigin.X;
                    var hh = dimx * MarkerOrigin.Y;
                    // these have bindings so effect is immediate
                    iss.OffsetX = output.X - hw;
                    iss.OffsetY = output.Y - hh;
                    iss.Width   = dimx;
                    iss.Height  = dimx;
                }
                if (ClipToDataRegion)
                {
                    state.Element.Clip = new RectangleGeometry()
                    {
                        Rect = icrc.SeriesArea
                    };
                }
            }
            _trace.Verbose($"{Name} mat:{mp.Item1} clip:{icrc.SeriesArea}");
        }
예제 #10
0
        /// <summary>
        /// Adjust transforms for the various components.
        /// Geometry: scaled to actual values in cartesian coordinates as indicated by axes.
        /// </summary>
        /// <param name="icrc"></param>
        void IRequireTransforms.Transforms(IChartRenderContext icrc)
        {
            if (CategoryAxis == null || ValueAxis == null)
            {
                return;
            }
            var matx = MatrixSupport.TransformFor(icrc.Area, CategoryAxis, ValueAxis);

            _trace.Verbose($"{Name} mat:{matx} clip:{icrc.SeriesArea}");
            Geometry.Transform = new MatrixTransform()
            {
                Matrix = matx
            };
            if (ClipToDataRegion)
            {
                Segments.Clip = new RectangleGeometry()
                {
                    Rect = icrc.SeriesArea
                };
            }
        }
예제 #11
0
        Matrix ProjectionFor(Rect area, bool reverse = false)
        {
            switch (Side)
            {
            case Side.Bottom:
                return(MatrixSupport.ProjectionFor(
                           reverse ? area.Right : area.Left,
                           area.Top + AxisLineThickness + 2 * AxisMargin,
                           reverse ? -1 : 1,
                           1
                           ));

            case Side.Top:
                return(MatrixSupport.ProjectionFor(
                           reverse ? area.Right : area.Left,
                           area.Top + AxisLineThickness + 2 * AxisMargin,
                           reverse ? -1 : 1,
                           -1
                           ));

            case Side.Left:
                return(MatrixSupport.ProjectionFor(
                           area.Right,
                           area.Top,
                           -area.Width - AxisLineThickness - 2 * AxisMargin,
                           reverse ? -1 : 1
                           ));

            case Side.Right:
                return(MatrixSupport.ProjectionFor(
                           area.Left + AxisLineThickness + 2 * AxisMargin,
                           area.Top,
                           1,
                           reverse ? -1 : 1
                           ));

            default:
                throw new NotImplementedException($"Not Implemented: {Side}");
            }
        }
        /// <summary>
        /// Adjust transforms for the various components.
        /// Geometry: scaled to actual values in cartesian coordinates as indicated by axes.
        /// </summary>
        /// <param name="icrc"></param>
        void IRequireTransforms.Transforms(IChartRenderContext icrc)
        {
            if (CategoryAxis == null || ValueAxis == null)
            {
                return;
            }
            if (ItemState.Count == 0)
            {
                return;
            }
            var matx = MatrixSupport.TransformForOffsetX(icrc.Area, CategoryAxis, ValueAxis);

            _trace.Verbose($"{Name} mat:{matx} clip:{icrc.SeriesArea}");
            var mt = new MatrixTransform()
            {
                Matrix = matx
            };

            foreach (var state in ItemState)
            {
                if (state.Element.DataContext is GeometryWithOffsetShim <RectangleGeometry> gs)
                {
                    gs.GeometryTransform = mt;
                    var output = matx.Transform(new Point(state.XValue, 0));
                    gs.Offset = icrc.Area.Left + output.X;
                }
                else
                {
                    state.Element.Data.Transform = mt;
                }
                if (ClipToDataRegion)
                {
                    var cg = new RectangleGeometry()
                    {
                        Rect = icrc.SeriesArea
                    };
                    state.Element.Clip = cg;
                }
            }
        }
        /// <summary>
        /// rule coordinates (x:[0..1], y:axis)
        /// </summary>
        /// <param name="icrc">The context.</param>
        void IRequireTransforms.Transforms(IChartRenderContext icrc)
        {
            if (ValueAxis == null)
            {
                return;
            }
            var matx = MatrixSupport.TransformFor(icrc.SeriesArea, ValueAxis);

            _trace.Verbose($"transforms sy:{matx.M22:F3} matx:{matx} sa:{icrc.SeriesArea}");
            if (ClipToDataRegion)
            {
                Value1Path.Clip = new RectangleGeometry()
                {
                    Rect = icrc.SeriesArea
                };
                Value2Path.Clip = new RectangleGeometry()
                {
                    Rect = icrc.SeriesArea
                };
                BandPath.Clip = new RectangleGeometry()
                {
                    Rect = icrc.SeriesArea
                };
            }
#if true
            var vmin    = ValueAxis.For(Value2);
            var vmax    = ValueAxis.For(Value1);
            var mmin    = DoMinMax ? Math.Min(vmin, vmax) : vmin;
            var mmax    = DoMinMax ? Math.Max(vmin, vmax) : vmax;
            var offset1 = matx.Transform(new Point(0, vmin));
            Value1Path.SetValue(Canvas.TopProperty, offset1.Y);
            var offset2 = matx.Transform(new Point(0, vmax));
            Value2Path.SetValue(Canvas.TopProperty, offset2.Y);
            var matx2 = matx;
            matx2.OffsetY        = 0;
            Value1Rule.Transform = new MatrixTransform()
            {
                Matrix = matx2
            };
            Value2Rule.Transform = new MatrixTransform()
            {
                Matrix = matx2
            };
            BandPath.SetValue(Canvas.TopProperty, offset1.Y);
            Band.Transform = new MatrixTransform()
            {
                Matrix = matx2
            };
#else
            Value1Rule.Transform = new MatrixTransform()
            {
                Matrix = matx
            };
            Value2Rule.Transform = new MatrixTransform()
            {
                Matrix = matx
            };
            Band.Transform = new MatrixTransform()
            {
                Matrix = matx
            };
#endif
        }