/// <summary> /// Reset AxisMargin, keeping TotalLength the same. /// </summary> /// <param name="newScale"></param> internal void ResetAxisMargin(Thickness1D newMargin) { AxisPadding = newMargin; double axisLength = AxisTotalLength - newMargin.Total(); Scale = axisLength / (MaxTransformed - MinTransformed); Offset = Scale * MinTransformed - AxisPadding.Lower; }
/// <summary> /// Increase axis margins by amount necessary to ensure both that there is room /// for labels and that the necessary axes are aligned. /// </summary> /// <param name="alignedAxes">List of axes that need to be aligned.</param> private static void ExpandAxisMargins(List <Axis2D> alignedAxes, double plotLength) { // Calculate margins Thickness1D margin = new Thickness1D(alignedAxes.Max(axis => axis.AxisPadding.Lower), alignedAxes.Max(axis => axis.AxisPadding.Upper)); double minPlotLength = 1.0; if (plotLength > minPlotLength) { double newTotalLength = plotLength + margin.Total(); foreach (Axis2D axis in alignedAxes) { axis.AxisTotalLength = newTotalLength; } } else if ((alignedAxes[0].AxisTotalLength - margin.Total()) < minPlotLength) { foreach (Axis2D axis in alignedAxes) { axis.AxisTotalLength = margin.Total() + minPlotLength; } } // Set the margin and update Scale and Offset. foreach (Axis2D axis in alignedAxes) { axis.ResetAxisMargin(margin); } int tickIndex = 0; int maxTickIndex = alignedAxes.Max(axis => axis.Ticks.Length) / 2; int[] tickPair = new int[2]; Axis2D limitingLowerAxis = null; int limitingLowerTickIndex = 0; double limitingLowerSemiWidth = margin.Lower; Axis2D limitingUpperAxis = null; int limitingUpperTickIndex = 0; double limitingUpperSemiWidth = margin.Upper; double offsetLower = 0; double deltaLower = alignedAxes[0].MaxTransformed - alignedAxes[0].MinTransformed; double deltaUpper = deltaLower; double axisTotalLength = alignedAxes[0].AxisTotalLength; double offsetUpper = 0; int nRescales = 0; // for diagnosic purposes only while ((tickIndex <= maxTickIndex) && (nRescales < 10)) { bool reset = false; // if a rescaling is required, start again from the beginning. for (int i = 0; i < alignedAxes.Count; ++i) { Axis2D currentAxis = alignedAxes[i]; tickPair[0] = tickIndex; tickPair[1] = currentAxis.TicksTransformed.Length - 1 - tickIndex; if ((currentAxis.TicksTransformed.Length - 1 - tickIndex) < tickIndex) { continue; } for (int j = 0; j <= 1; ++j) { int index = tickPair[j]; if (!currentAxis.LabelsVisible || currentAxis.TickLabelCache[index].Label.Text == "" || !currentAxis.TickLabelCache[index].IsShown) { continue; } if ((currentAxis.Scale * currentAxis.TicksTransformed[index] - currentAxis.Offset - currentAxis.LimitingTickLabelSizeForLength(index) / 2) < -0.1) { // need to rescale axes limitingLowerAxis = currentAxis; limitingLowerTickIndex = index; limitingLowerSemiWidth = currentAxis.LimitingTickLabelSizeForLength(index) / 2; offsetLower = currentAxis.TicksTransformed[index] - currentAxis.MinTransformed; deltaLower = currentAxis.MaxTransformed - currentAxis.MinTransformed; } else if ((currentAxis.Scale * currentAxis.TicksTransformed[index] - currentAxis.Offset + currentAxis.LimitingTickLabelSizeForLength(index) / 2) > (currentAxis.AxisTotalLength + 0.1)) { // need to rescale axes limitingUpperAxis = currentAxis; limitingUpperTickIndex = index; limitingUpperSemiWidth = currentAxis.LimitingTickLabelSizeForLength(index) / 2; offsetUpper = currentAxis.MaxTransformed - currentAxis.TicksTransformed[index]; deltaUpper = currentAxis.MaxTransformed - currentAxis.MinTransformed; } else { continue; } // Reset required: reset = true; nRescales++; double offsetUpperPrime = offsetUpper * deltaLower / deltaUpper; // scale for lower-limiting axis double newScale = (axisTotalLength - limitingLowerSemiWidth - limitingUpperSemiWidth) / (deltaLower - offsetLower - offsetUpperPrime); if (plotLength > minPlotLength) { // Axis is fixed to plotLength. newScale = plotLength / deltaLower; margin = new Thickness1D(limitingLowerSemiWidth - offsetLower * newScale, limitingUpperSemiWidth - offsetUpperPrime * newScale); foreach (Axis2D axis in alignedAxes) { axis.AxisTotalLength = plotLength + margin.Total(); } } if (newScale * deltaLower <= minPlotLength) { // Axis is fixed to minPlotLength newScale = minPlotLength / deltaLower; margin = new Thickness1D(limitingLowerSemiWidth - offsetLower * newScale, limitingUpperSemiWidth - offsetUpperPrime * newScale); foreach (Axis2D axis in alignedAxes) { axis.AxisTotalLength = minPlotLength + margin.Total(); } } // otherwise, axis is unfixed. margin = new Thickness1D(limitingLowerSemiWidth - offsetLower * newScale, limitingUpperSemiWidth - offsetUpperPrime * newScale); foreach (Axis2D axis in alignedAxes) { axis.RescaleAxis(newScale * deltaLower / (axis.MaxTransformed - axis.MinTransformed), margin); } break; } if (reset == true) { break; } } if (reset == true) { tickIndex = 0; } else { tickIndex++; } } if (nRescales == 10) { Console.WriteLine("Many rescales..."); } }
/// <summary> /// Change margins and scale, keeping total length constant. /// </summary> /// <param name="newScale"></param> internal void RescaleAxis(double newScale, Thickness1D newMargin) { AxisPadding = newMargin; Scale = newScale; Offset = Scale * MinTransformed - AxisPadding.Lower; }
internal void OverrideAxisScaling(double scale, double offset, Thickness1D axisPadding) { this.Scale = scale; this.Offset = offset; this.AxisPadding = axisPadding; }
/// <summary> /// Increase axis margins by amount necessary to ensure both that there is room /// for labels and that the necessary axes are aligned. /// </summary> /// <param name="alignedAxes">List of axes that need to be aligned.</param> private static void ExpandAxisMargins(List<Axis2D> alignedAxes, double plotLength) { // Calculate margins Thickness1D margin = new Thickness1D(alignedAxes.Max(axis => axis.AxisPadding.Lower), alignedAxes.Max(axis => axis.AxisPadding.Upper)); double minPlotLength = 1.0; if (plotLength > minPlotLength) { double newTotalLength = plotLength + margin.Total(); foreach (Axis2D axis in alignedAxes) axis.AxisTotalLength = newTotalLength; } else if ((alignedAxes[0].AxisTotalLength - margin.Total()) < minPlotLength) { foreach (Axis2D axis in alignedAxes) axis.AxisTotalLength = margin.Total() + minPlotLength; } // Set the margin and update Scale and Offset. foreach (Axis2D axis in alignedAxes) axis.ResetAxisMargin(margin); int tickIndex = 0; int maxTickIndex = alignedAxes.Max(axis => axis.Ticks.Length) / 2; int[] tickPair = new int[2]; Axis2D limitingLowerAxis = null; int limitingLowerTickIndex = 0; double limitingLowerSemiWidth = margin.Lower; Axis2D limitingUpperAxis = null; int limitingUpperTickIndex = 0; double limitingUpperSemiWidth = margin.Upper; double offsetLower = 0; double deltaLower = alignedAxes[0].MaxTransformed - alignedAxes[0].MinTransformed; double deltaUpper = deltaLower; double axisTotalLength = alignedAxes[0].AxisTotalLength; double offsetUpper = 0; int nRescales = 0; // for diagnosic purposes only while ((tickIndex <= maxTickIndex) && (nRescales < 10)) { bool reset = false; // if a rescaling is required, start again from the beginning. for (int i = 0; i < alignedAxes.Count; ++i) { Axis2D currentAxis = alignedAxes[i]; tickPair[0] = tickIndex; tickPair[1] = currentAxis.TicksTransformed.Length - 1 - tickIndex; if ((currentAxis.TicksTransformed.Length - 1 - tickIndex) < tickIndex) continue; for (int j = 0; j <= 1; ++j) { int index = tickPair[j]; if (!currentAxis.LabelsVisible || currentAxis.TickLabelCache[index].Label.Text == "" || !currentAxis.TickLabelCache[index].IsShown) continue; if ((currentAxis.Scale * currentAxis.TicksTransformed[index] - currentAxis.Offset - currentAxis.LimitingTickLabelSizeForLength(index) / 2) < -0.1) { // need to rescale axes limitingLowerAxis = currentAxis; limitingLowerTickIndex = index; limitingLowerSemiWidth = currentAxis.LimitingTickLabelSizeForLength(index) / 2; offsetLower = currentAxis.TicksTransformed[index] - currentAxis.MinTransformed; deltaLower = currentAxis.MaxTransformed - currentAxis.MinTransformed; } else if ((currentAxis.Scale * currentAxis.TicksTransformed[index] - currentAxis.Offset + currentAxis.LimitingTickLabelSizeForLength(index) / 2) > (currentAxis.AxisTotalLength + 0.1)) { // need to rescale axes limitingUpperAxis = currentAxis; limitingUpperTickIndex = index; limitingUpperSemiWidth = currentAxis.LimitingTickLabelSizeForLength(index) / 2; offsetUpper = currentAxis.MaxTransformed - currentAxis.TicksTransformed[index]; deltaUpper = currentAxis.MaxTransformed - currentAxis.MinTransformed; } else continue; // Reset required: reset = true; nRescales++; double offsetUpperPrime = offsetUpper * deltaLower / deltaUpper; // scale for lower-limiting axis double newScale = (axisTotalLength - limitingLowerSemiWidth - limitingUpperSemiWidth) / (deltaLower - offsetLower - offsetUpperPrime); if (plotLength > minPlotLength) { // Axis is fixed to plotLength. newScale = plotLength / deltaLower; margin = new Thickness1D(limitingLowerSemiWidth - offsetLower * newScale, limitingUpperSemiWidth - offsetUpperPrime * newScale); foreach (Axis2D axis in alignedAxes) axis.AxisTotalLength = plotLength + margin.Total(); } if (newScale * deltaLower <= minPlotLength) { // Axis is fixed to minPlotLength newScale = minPlotLength / deltaLower; margin = new Thickness1D(limitingLowerSemiWidth - offsetLower * newScale, limitingUpperSemiWidth - offsetUpperPrime * newScale); foreach (Axis2D axis in alignedAxes) axis.AxisTotalLength = minPlotLength + margin.Total(); } // otherwise, axis is unfixed. margin = new Thickness1D(limitingLowerSemiWidth - offsetLower * newScale, limitingUpperSemiWidth - offsetUpperPrime * newScale); foreach (Axis2D axis in alignedAxes) axis.RescaleAxis(newScale * deltaLower / (axis.MaxTransformed - axis.MinTransformed), margin); break; } if (reset == true) break; } if (reset == true) tickIndex = 0; else tickIndex++; } if (nRescales == 10) { Console.WriteLine("Many rescales..."); } }