Пример #1
0
        /// <summary>
        /// Updates the cached coordinate system while trying to keep the axis positions and tick positions.
        /// </summary>
        /// <param name="newSystem">The new coordinate system.</param>
        /// <param name="GetNewAxisLineIDFromOldAxisLineID">Gets a new axis line identifier, using the old one as parameter.</param>
        /// <param name="GetNewAxisSideFromOldAxisSide">Gets the new axis side (for instance of ticks), using the old axis line id as parameter1, the old axis side as parameter2 and the new axis line id as parameter3.
        /// The return value is the new axis side. This function can return null, in this case no corresponding axis side has been found.</param>
        /// <exception cref="System.ArgumentNullException">
        /// </exception>
        public void UpdateCoordinateSystemKeepingAxisPositions(
            G3DCoordinateSystem newSystem,
            Func <CSLineID, CSLineID> GetNewAxisLineIDFromOldAxisLineID,
            Func <CSLineID, CSAxisSide, CSLineID, CSAxisSide?> GetNewAxisSideFromOldAxisSide)
        {
            if (null == newSystem)
            {
                throw new ArgumentNullException(nameof(newSystem));
            }
            if (null == GetNewAxisLineIDFromOldAxisLineID)
            {
                throw new ArgumentNullException(nameof(GetNewAxisLineIDFromOldAxisLineID));
            }

            foreach (var axisStyle in _axisStyles)
            {
                var oldAxisLineID = axisStyle.StyleID;
                var newAxisLineID = GetNewAxisLineIDFromOldAxisLineID(oldAxisLineID);
                if (null != newAxisLineID)
                {
                    axisStyle.CachedAxisInformation = newSystem.GetAxisStyleInformation(newAxisLineID);
                    axisStyle.ChangeStyleIdentifier(newAxisLineID, oldAxisSide => GetNewAxisSideFromOldAxisSide(oldAxisLineID, oldAxisSide, newAxisLineID));
                }
            }

            UpdateCoordinateSystem(newSystem);
        }
Пример #2
0
        public void UpdateCoordinateSystem(G3DCoordinateSystem cs)
        {
            _cachedCoordinateSystem = cs;

            foreach (AxisStyle style in _axisStyles)
            {
                style.CachedAxisInformation = _cachedCoordinateSystem.GetAxisStyleInformation(style.StyleID);
            }
        }
Пример #3
0
        private void CopyFrom(AxisStyleCollection from)
        {
            if (object.ReferenceEquals(this, from))
            {
                return;
            }

            _axisStyles.Clear();
            for (int i = 0; i < from._axisStyles.Count; ++i)
            {
                Add((AxisStyle)from._axisStyles[i].Clone());
            }

            //this._parent = from._parent;
            _cachedCoordinateSystem = from._cachedCoordinateSystem;
        }
Пример #4
0
        /// <summary>
        /// This will create a point list out of the data, which can be used to plot the data. In order to create this list,
        /// the function must have knowledge how to calculate the points out of the data. This will be done
        /// by a function provided by the calling function.
        /// </summary>
        /// <param name="layer">The plot layer.</param>
        /// <returns>An array of plot points in layer coordinates.</returns>
        public Processed3DPlotData GetRangesAndPoints(
            IPlotArea layer)
        {
            const double MaxRelativeValue = 1E2;

            Altaxo.Data.IReadableColumn xColumn = XColumn;
            Altaxo.Data.IReadableColumn yColumn = YColumn;
            Altaxo.Data.IReadableColumn zColumn = ZColumn;

            if (null == xColumn || null == yColumn || null == zColumn)
            {
                return(null); // this plotitem is only for x and y double columns
            }
            var result     = new Processed3DPlotData();
            var myPlotData = new MyPlotData(xColumn, yColumn, zColumn);

            result.XPhysicalAccessor = new IndexedPhysicalValueAccessor(myPlotData.GetXPhysical);
            result.YPhysicalAccessor = new IndexedPhysicalValueAccessor(myPlotData.GetYPhysical);
            result.ZPhysicalAccessor = new IndexedPhysicalValueAccessor(myPlotData.GetZPhysical);
            PlotRangeList rangeList = null;

            // allocate an array PointF to hold the line points
            // _tlsBufferedPlotData is a static buffer that is allocated per thread
            // and thus is only used temporary here in this routine
            if (null == _tlsBufferedPlotData)
            {
                _tlsBufferedPlotData = new List <PointD3D>();
            }
            else
            {
                _tlsBufferedPlotData.Clear();
            }

            // Fill the array with values
            // only the points where x and y are not NaNs are plotted!

            bool weAreInsideSegment = false;
            int  rangeStart         = 0;
            int  rangeOffset        = 0;

            rangeList        = new PlotRangeList();
            result.RangeList = rangeList;

            Scale xAxis = layer.XAxis;
            Scale yAxis = layer.YAxis;
            Scale zAxis = layer.ZAxis;
            G3DCoordinateSystem coordsys = layer.CoordinateSystem;

            int maxRowIndex  = GetMaximumRowIndexFromDataColumns();
            int plotArrayIdx = 0;

            foreach ((int start, int endExclusive) in _dataRowSelection.GetSelectedRowIndexSegmentsFromTo(0, maxRowIndex, _dataTable?.Document?.DataColumns, maxRowIndex))
            {
                for (int dataRowIdx = start; dataRowIdx < endExclusive; ++dataRowIdx)
                {
                    if (xColumn.IsElementEmpty(dataRowIdx) || yColumn.IsElementEmpty(dataRowIdx) || zColumn.IsElementEmpty(dataRowIdx))
                    {
                        if (weAreInsideSegment)
                        {
                            weAreInsideSegment = false;
                            rangeList.Add(new PlotRange(rangeStart, plotArrayIdx, rangeOffset));
                        }
                        continue;
                    }

                    double x_rel, y_rel, z_rel;

                    x_rel = xAxis.PhysicalVariantToNormal(xColumn[dataRowIdx]);
                    y_rel = yAxis.PhysicalVariantToNormal(yColumn[dataRowIdx]);
                    z_rel = zAxis.PhysicalVariantToNormal(zColumn[dataRowIdx]);

                    // chop relative values to an range of about -+ 10^6
                    if (x_rel > MaxRelativeValue)
                    {
                        x_rel = MaxRelativeValue;
                    }
                    if (x_rel < -MaxRelativeValue)
                    {
                        x_rel = -MaxRelativeValue;
                    }
                    if (y_rel > MaxRelativeValue)
                    {
                        y_rel = MaxRelativeValue;
                    }
                    if (y_rel < -MaxRelativeValue)
                    {
                        y_rel = -MaxRelativeValue;
                    }
                    if (z_rel > MaxRelativeValue)
                    {
                        z_rel = MaxRelativeValue;
                    }
                    if (z_rel < -MaxRelativeValue)
                    {
                        z_rel = -MaxRelativeValue;
                    }

                    // after the conversion to relative coordinates it is possible
                    // that with the choosen axis the point is undefined
                    // (for instance negative values on a logarithmic axis)
                    // in this case the returned value is NaN
                    if (coordsys.LogicalToLayerCoordinates(new Logical3D(x_rel, y_rel, z_rel), out var coord))
                    {
                        if (!weAreInsideSegment)
                        {
                            weAreInsideSegment = true;
                            rangeStart         = plotArrayIdx;
                            rangeOffset        = dataRowIdx - plotArrayIdx;
                        }
                        _tlsBufferedPlotData.Add(coord);
                        plotArrayIdx++;
                    }
                    else
                    {
                        if (weAreInsideSegment)
                        {
                            weAreInsideSegment = false;
                            rangeList.Add(new PlotRange(rangeStart, plotArrayIdx, rangeOffset));
                        }
                    }
                } // end for
                if (weAreInsideSegment)
                {
                    weAreInsideSegment = false;
                    rangeList.Add(new PlotRange(rangeStart, plotArrayIdx, rangeOffset)); // add the last range
                }
            } // end foreach

            result.PlotPointsInAbsoluteLayerCoordinates = _tlsBufferedPlotData.ToArray();

            return(result);
        }
Пример #5
0
        /// <summary>
        /// Paints the axis style labels.
        /// </summary>
        /// <param name="g">Graphics environment.</param>
        /// <param name="coordSyst">The coordinate system. Used to get the path along the axis.</param>
        /// <param name="scale">Scale.</param>
        /// <param name="tickSpacing">If not <c>null</c>, this parameter provides a custom tick spacing that is used instead of the default tick spacing of the scale.</param>
        /// <param name="styleInfo">Information about begin of axis, end of axis.</param>
        /// <param name="outerDistance">Distance between axis and labels.</param>
        /// <param name="useMinorTicks">If true, minor ticks are shown.</param>
        public virtual void Paint(IGraphicsContext3D g, G3DCoordinateSystem coordSyst, Scale scale, TickSpacing tickSpacing, CSAxisInformation styleInfo, double outerDistance, bool useMinorTicks)
        {
            _cachedAxisStyleInfo = styleInfo;
            CSLineID    styleID = styleInfo.Identifier;
            Scale       raxis   = scale;
            TickSpacing ticking = tickSpacing;

            var math = Matrix4x3.Identity;

            Logical3D r0 = styleID.GetLogicalPoint(styleInfo.LogicalValueAxisOrg);
            Logical3D r1 = styleID.GetLogicalPoint(styleInfo.LogicalValueAxisEnd);

            Logical3D outer;

            double[]        relpositions;
            AltaxoVariant[] ticks;
            if (useMinorTicks)
            {
                relpositions = ticking.GetMinorTicksNormal(raxis);
                ticks        = ticking.GetMinorTicksAsVariant();
            }
            else
            {
                relpositions = ticking.GetMajorTicksNormal(raxis);
                ticks        = ticking.GetMajorTicksAsVariant();
            }

            if (!_suppressedLabels.IsEmpty)
            {
                var filteredTicks        = new List <AltaxoVariant>();
                var filteredRelPositions = new List <double>();

                for (int i = 0; i < ticks.Length; i++)
                {
                    if (_suppressedLabels.ByValues.Contains(ticks[i]))
                    {
                        continue;
                    }
                    if (_suppressedLabels.ByNumbers.Contains(i))
                    {
                        continue;
                    }
                    if (_suppressedLabels.ByNumbers.Contains(i - ticks.Length))
                    {
                        continue;
                    }

                    filteredTicks.Add(ticks[i]);
                    filteredRelPositions.Add(relpositions[i]);
                }
                ticks        = filteredTicks.ToArray();
                relpositions = filteredRelPositions.ToArray();
            }

            IMeasuredLabelItem[] labels = _labelFormatting.GetMeasuredItems(g, _font, ticks);

            double     emSize        = _font.Size;
            CSAxisSide labelSide     = null != _labelSide ? _labelSide.Value : styleInfo.PreferredLabelSide;
            var        labelOutlines = new RectangularObjectOutline[ticks.Length];

            for (int i = 0; i < ticks.Length; i++)
            {
                double r = relpositions[i];

                if (!Altaxo.Calc.RMath.IsInIntervalCC(r, -1000, 1000))
                {
                    continue;
                }

                outer = coordSyst.GetLogicalDirection(styleID.ParallelAxisNumber, labelSide);
                PointD3D tickorg = coordSyst.GetPositionAndNormalizedDirection(r0, r1, r, outer, out var outVector);
                PointD3D tickend = tickorg + outVector * outerDistance;

                var msize = labels[i].Size;
                var morg  = tickend;

                if (_automaticRotationShift)
                {
                    // if this option is choosen, we have to find a shift value that shifts the center of the text outwards so that the bounding box of the text will not cross the plane that is
                    // defined by the tickend point and the normal vector outVector

                    // Assume that the text is now centered x, y, and z around the point tickend (but here we use origin instead tickend)
                    math = Matrix4x3.NewRotation(_rotationX, _rotationY, _rotationZ);
                    // we have to find all points with negative distance to the plane spanned by tickend and the vector outVector (but again instead of tickend we use origin)
                    var msizePad = msize + new VectorD3D(
                        (_font.Size * 1) / 3,                                            // whereas above and below text no padding is neccessary, it is optically nicer to have left and right padding of the string by 1/6 of font size.
                        0,
                        (_font.Size * 1) / 3                                             // same padding applies to z
                        );
                    var crect = new RectangleD3D((PointD3D)(-0.5 * msizePad), msizePad); // our text centered around origin

                    double shift = 0;
                    foreach (PointD3D p in crect.Vertices)
                    {
                        PointD3D ps       = math.Transform(p);
                        double   distance = Math3D.GetDistancePointToPlane(ps, PointD3D.Empty, outVector);
                        if (-distance > shift)
                        {
                            shift = -distance; // only negative distances will count here
                        }
                    }
                    morg += outVector * shift;
                }
                else
                {
                    morg = morg.WithXPlus(outVector.X * _font.Size / 3);
                }

                var mrect = new RectangleD3D(morg, msize);
                if (_automaticRotationShift)
                {
                    mrect = AdjustRectangle(mrect, Alignment.Center, Alignment.Center, Alignment.Center);
                }
                else
                {
                    mrect = AdjustRectangle(mrect, _alignmentX, _alignmentY, _alignmentZ);
                }

                math = Matrix4x3.Identity;
                math.TranslatePrepend(morg.X, morg.Y, morg.Z);

                if (_rotationZ != 0)
                {
                    math.RotationZDegreePrepend(_rotationZ);
                }
                if (_rotationY != 0)
                {
                    math.RotationYDegreePrepend(_rotationY);
                }
                if (_rotationX != 0)
                {
                    math.RotationXDegreePrepend(_rotationX);
                }

                math.TranslatePrepend((mrect.X - morg.X + emSize * _offsetX), (mrect.Y - morg.Y + emSize * _offsetY), (mrect.Z - morg.Z + emSize * _offsetZ));

                var gs = g.SaveGraphicsState();
                g.PrependTransform(math);

                if (_backgroundStyle != null)
                {
                    var itemRectangle = new RectangleD3D(PointD3D.Empty, msize);
                    _backgroundStyle.Measure(itemRectangle);
                    _backgroundStyle.Draw(g, itemRectangle);
                }

                labels[i].Draw(g, _brush, PointD3D.Empty);
                labelOutlines[i] = new RectangularObjectOutline(new RectangleD3D(PointD3D.Empty, msize), math);
                g.RestoreGraphicsState(gs); // Restore the graphics state
            }

            _cachedLabelOutlines = labelOutlines;
        }
Пример #6
0
		/// <summary>
		/// Paints the axis style labels.
		/// </summary>
		/// <param name="g">Graphics environment.</param>
		/// <param name="coordSyst">The coordinate system. Used to get the path along the axis.</param>
		/// <param name="scale">Scale.</param>
		/// <param name="tickSpacing">If not <c>null</c>, this parameter provides a custom tick spacing that is used instead of the default tick spacing of the scale.</param>
		/// <param name="styleInfo">Information about begin of axis, end of axis.</param>
		/// <param name="outerDistance">Distance between axis and labels.</param>
		/// <param name="useMinorTicks">If true, minor ticks are shown.</param>
		public virtual void Paint(IGraphicsContext3D g, G3DCoordinateSystem coordSyst, Scale scale, TickSpacing tickSpacing, CSAxisInformation styleInfo, double outerDistance, bool useMinorTicks)
		{
			_cachedAxisStyleInfo = styleInfo;
			CSLineID styleID = styleInfo.Identifier;
			Scale raxis = scale;
			TickSpacing ticking = tickSpacing;

			var math = Matrix4x3.Identity;

			Logical3D r0 = styleID.GetLogicalPoint(styleInfo.LogicalValueAxisOrg);
			Logical3D r1 = styleID.GetLogicalPoint(styleInfo.LogicalValueAxisEnd);

			VectorD3D outVector;
			Logical3D outer;

			double[] relpositions;
			AltaxoVariant[] ticks;
			if (useMinorTicks)
			{
				relpositions = ticking.GetMinorTicksNormal(raxis);
				ticks = ticking.GetMinorTicksAsVariant();
			}
			else
			{
				relpositions = ticking.GetMajorTicksNormal(raxis);
				ticks = ticking.GetMajorTicksAsVariant();
			}

			if (!_suppressedLabels.IsEmpty)
			{
				List<AltaxoVariant> filteredTicks = new List<AltaxoVariant>();
				List<double> filteredRelPositions = new List<double>();

				for (int i = 0; i < ticks.Length; i++)
				{
					if (_suppressedLabels.ByValues.Contains(ticks[i]))
						continue;
					if (_suppressedLabels.ByNumbers.Contains(i))
						continue;
					if (_suppressedLabels.ByNumbers.Contains(i - ticks.Length))
						continue;

					filteredTicks.Add(ticks[i]);
					filteredRelPositions.Add(relpositions[i]);
				}
				ticks = filteredTicks.ToArray();
				relpositions = filteredRelPositions.ToArray();
			}

			IMeasuredLabelItem[] labels = _labelFormatting.GetMeasuredItems(g, _font, ticks);

			double emSize = _font.Size;
			CSAxisSide labelSide = null != _labelSide ? _labelSide.Value : styleInfo.PreferredLabelSide;
			var labelOutlines = new RectangularObjectOutline[ticks.Length];
			for (int i = 0; i < ticks.Length; i++)
			{
				double r = relpositions[i];

				if (!Altaxo.Calc.RMath.IsInIntervalCC(r, -1000, 1000))
					continue;

				outer = coordSyst.GetLogicalDirection(styleID.ParallelAxisNumber, labelSide);
				PointD3D tickorg = coordSyst.GetPositionAndNormalizedDirection(r0, r1, r, outer, out outVector);
				PointD3D tickend = tickorg + outVector * outerDistance;

				var msize = labels[i].Size;
				var morg = tickend;

				if (_automaticRotationShift)
				{
					// if this option is choosen, we have to find a shift value that shifts the center of the text outwards so that the bounding box of the text will not cross the plane that is
					// defined by the tickend point and the normal vector outVector

					// Assume that the text is now centered x, y, and z around the point tickend (but here we use origin instead tickend)
					math = Matrix4x3.NewRotation(_rotationX, _rotationY, _rotationZ);
					// we have to find all points with negative distance to the plane spanned by tickend and the vector outVector (but again instead of tickend we use origin)
					var msizePad = msize + new VectorD3D(
					(_font.Size * 1) / 3, // whereas above and below text no padding is neccessary, it is optically nicer to have left and right padding of the string by 1/6 of font size.
					0,
					(_font.Size * 1) / 3 // same padding applies to z
					);
					var crect = new RectangleD3D((PointD3D)(-0.5 * msizePad), msizePad); // our text centered around origin

					double shift = 0;
					foreach (PointD3D p in crect.Vertices)
					{
						PointD3D ps = math.Transform(p);
						double distance = Math3D.GetDistancePointToPlane(ps, PointD3D.Empty, outVector);
						if (-distance > shift)
							shift = -distance; // only negative distances will count here
					}
					morg += outVector * shift;
				}
				else
				{
					morg = morg.WithXPlus(outVector.X * _font.Size / 3);
				}

				var mrect = new RectangleD3D(morg, msize);
				if (_automaticRotationShift)
					mrect = AdjustRectangle(mrect, Alignment.Center, Alignment.Center, Alignment.Center);
				else
					mrect = AdjustRectangle(mrect, _alignmentX, _alignmentY, _alignmentZ);

				math = Matrix4x3.Identity;
				math.TranslatePrepend(morg.X, morg.Y, morg.Z);

				if (this._rotationZ != 0)
					math.RotationZDegreePrepend(this._rotationZ);
				if (this._rotationY != 0)
					math.RotationYDegreePrepend(this._rotationY);
				if (this._rotationX != 0)
					math.RotationXDegreePrepend(this._rotationX);

				math.TranslatePrepend((mrect.X - morg.X + emSize * _offsetX), (mrect.Y - morg.Y + emSize * _offsetY), (mrect.Z - morg.Z + emSize * _offsetZ));

				var gs = g.SaveGraphicsState();
				g.PrependTransform(math);

				if (this._backgroundStyle != null)
				{
					var itemRectangle = new RectangleD3D(PointD3D.Empty, msize);
					_backgroundStyle.Measure(itemRectangle);
					_backgroundStyle.Draw(g, itemRectangle);
				}

				labels[i].Draw(g, _brush, PointD3D.Empty);
				labelOutlines[i] = new RectangularObjectOutline(new RectangleD3D(PointD3D.Empty, msize), math);
				g.RestoreGraphicsState(gs); // Restore the graphics state
			}

			_cachedLabelOutlines = labelOutlines;
		}