diff --git a/chartfx-chart/src/main/java/io/fair_acc/chartfx/XYChart.java b/chartfx-chart/src/main/java/io/fair_acc/chartfx/XYChart.java index 690dd715a..bfbd43aa4 100644 --- a/chartfx-chart/src/main/java/io/fair_acc/chartfx/XYChart.java +++ b/chartfx-chart/src/main/java/io/fair_acc/chartfx/XYChart.java @@ -1,7 +1,6 @@ package io.fair_acc.chartfx; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -26,7 +25,6 @@ import io.fair_acc.chartfx.axes.Axis; import io.fair_acc.chartfx.renderer.PolarTickStep; import io.fair_acc.chartfx.renderer.Renderer; -import io.fair_acc.chartfx.renderer.spi.ErrorDataSetRenderer; import io.fair_acc.chartfx.renderer.spi.GridRenderer; import io.fair_acc.chartfx.renderer.spi.LabelledMarkerRenderer; import io.fair_acc.chartfx.ui.geometry.Side; @@ -311,10 +309,8 @@ protected void redrawCanvas() { } // Data - int dataSetOffset = 0; for (final Renderer renderer : getRenderers()) { - final List drawnDataSets = renderer.render(gc, this, dataSetOffset, getDatasets()); - dataSetOffset += drawnDataSets == null ? 0 : drawnDataSets.size(); + renderer.render(gc, this, renderer.getIndexOffset(), FXCollections.emptyObservableList()); } // Top grid diff --git a/chartfx-chart/src/main/java/io/fair_acc/chartfx/plugins/measurements/DataSetMeasurements.java b/chartfx-chart/src/main/java/io/fair_acc/chartfx/plugins/measurements/DataSetMeasurements.java index 89a3474b9..660ae205f 100644 --- a/chartfx-chart/src/main/java/io/fair_acc/chartfx/plugins/measurements/DataSetMeasurements.java +++ b/chartfx-chart/src/main/java/io/fair_acc/chartfx/plugins/measurements/DataSetMeasurements.java @@ -169,7 +169,6 @@ public DataSetMeasurements(final ParameterMeasurements plugin, final Measurement yAxis.setAutoRanging(true); yAxis.setAutoUnitScaling(true); renderer.getAxes().addAll(xAxis, yAxis); - renderer.setDrawChartDataSets(false); renderer.getDatasets().add(isTrending ? trendingDataSet : mathDataSet); localChart.addListener(localChartChangeListener); diff --git a/chartfx-chart/src/main/java/io/fair_acc/chartfx/renderer/spi/AbstractErrorDataSetRendererParameter.java b/chartfx-chart/src/main/java/io/fair_acc/chartfx/renderer/spi/AbstractErrorDataSetRendererParameter.java index 7ca9e7f49..c5845f5f6 100644 --- a/chartfx-chart/src/main/java/io/fair_acc/chartfx/renderer/spi/AbstractErrorDataSetRendererParameter.java +++ b/chartfx-chart/src/main/java/io/fair_acc/chartfx/renderer/spi/AbstractErrorDataSetRendererParameter.java @@ -52,7 +52,6 @@ public abstract class AbstractErrorDataSetRendererParameter polyLineStyle = css().createEnumProperty(this, "polyLineStyle", LineStyle.NORMAL, false, LineStyle.class); - private final BooleanProperty drawChartDataSets = new SimpleBooleanProperty(this, "drawChartDataSets", true); private final BooleanProperty drawBars = css().createBooleanProperty(this, "drawBars", false); private final BooleanProperty shiftBar = css().createBooleanProperty(this, "shiftBar", true); private final IntegerProperty shiftBarOffset = css().createIntegerProperty(this, "shiftBarOffset", 3); @@ -77,7 +76,6 @@ public AbstractErrorDataSetRendererParameter() { markerSize, drawMarker, polyLineStyle, - drawChartDataSets, drawBars, shiftBar, shiftBarOffset, @@ -122,13 +120,6 @@ public BooleanProperty drawBubblesProperty() { return drawBubbles; } - /** - * @return the drawChartDataSets state, ie. if all or only the DataSets attached to the Renderer shall be drawn - */ - public BooleanProperty drawChartDataSetsProperty() { - return drawChartDataSets; - } - /** * @return the drawMarker state */ @@ -256,14 +247,6 @@ public boolean isDrawBubbles() { return drawBubblesProperty().get(); } - /** - * - * @return whether all or only the DataSets attached to the Renderer shall be drawn - */ - public boolean isDrawChartDataSets() { - return drawChartDataSetsProperty().get(); - } - /** * @return true if point reduction is on (default) else false. */ @@ -374,14 +357,6 @@ public R setDrawBubbles(final boolean state) { return getThis(); } - /** - * - * @param state whether all (true) or only the DataSets attached to the Renderer shall be drawn (false) - */ - public void setDrawChartDataSets(final boolean state) { - drawChartDataSetsProperty().set(state); - } - /** * @param state true -> draws markers * @return itself (fluent design) @@ -498,7 +473,6 @@ protected R bind(final R other) { markerSizeProperty().bind(other.markerSizeProperty()); drawMarkerProperty().bind(other.drawMarkerProperty()); polyLineStyleProperty().bind(other.polyLineStyleProperty()); - drawChartDataSetsProperty().bind(other.drawChartDataSetsProperty()); drawBarsProperty().bind(other.drawBarsProperty()); drawBubblesProperty().bind(other.drawBubblesProperty()); allowNaNsProperty().bind(other.allowNaNsProperty()); @@ -535,7 +509,6 @@ protected R unbind() { markerSizeProperty().unbind(); drawMarkerProperty().unbind(); polyLineStyleProperty().unbind(); - drawChartDataSetsProperty().unbind(); drawBarsProperty().unbind(); drawBubblesProperty().unbind(); allowNaNsProperty().unbind(); diff --git a/chartfx-chart/src/main/java/io/fair_acc/chartfx/renderer/spi/AbstractRenderer.java b/chartfx-chart/src/main/java/io/fair_acc/chartfx/renderer/spi/AbstractRenderer.java index d4c77fe4a..25c2e89fb 100644 --- a/chartfx-chart/src/main/java/io/fair_acc/chartfx/renderer/spi/AbstractRenderer.java +++ b/chartfx-chart/src/main/java/io/fair_acc/chartfx/renderer/spi/AbstractRenderer.java @@ -1,7 +1,6 @@ package io.fair_acc.chartfx.renderer.spi; import io.fair_acc.chartfx.Chart; -import io.fair_acc.chartfx.XYChart; import io.fair_acc.chartfx.axes.Axis; import io.fair_acc.chartfx.renderer.Renderer; import io.fair_acc.chartfx.ui.css.CssPropertyFactory; @@ -13,6 +12,7 @@ import io.fair_acc.dataset.events.ChartBits; import io.fair_acc.dataset.spi.DoubleDataSet; import io.fair_acc.dataset.spi.DoubleErrorDataSet; +import io.fair_acc.dataset.utils.AssertUtils; import io.fair_acc.dataset.utils.NoDuplicatesList; import io.fair_acc.dataset.utils.ProcessingProfiler; import javafx.beans.property.*; @@ -108,6 +108,16 @@ protected ObservableList getDatasetsCopy(final ObservableList return dataSets; } + public Axis getFirstHorizontalAxis() { + AssertUtils.notNull("chart", getChart()); + return getFirstAxis(Orientation.HORIZONTAL, getChart()); + } + + public Axis getFirstVerticalAxis() { + AssertUtils.notNull("chart", getChart()); + return getFirstAxis(Orientation.VERTICAL, getChart()); + } + public Axis getFirstAxis(final Orientation orientation) { for (final Axis axis : getAxes()) { if (axis.getSide() == null) { @@ -142,7 +152,7 @@ public Axis getFirstAxis(final Orientation orientation) { * @param fallback The chart from which to get the axis if no axis is present * @return The requested axis */ - protected Axis getFirstAxis(final Orientation orientation, final XYChart fallback) { + protected Axis getFirstAxis(final Orientation orientation, final Chart fallback) { final Axis axis = getFirstAxis(orientation); if (axis == null) { return fallback.getFirstAxis(orientation); diff --git a/chartfx-chart/src/main/java/io/fair_acc/chartfx/renderer/spi/CachedDataPoints.java b/chartfx-chart/src/main/java/io/fair_acc/chartfx/renderer/spi/CachedDataPoints.java index 209143b01..a637e3b57 100644 --- a/chartfx-chart/src/main/java/io/fair_acc/chartfx/renderer/spi/CachedDataPoints.java +++ b/chartfx-chart/src/main/java/io/fair_acc/chartfx/renderer/spi/CachedDataPoints.java @@ -2,6 +2,7 @@ import static io.fair_acc.dataset.DataSet.DIM_X; import static io.fair_acc.dataset.DataSet.DIM_Y; +import static io.fair_acc.math.ArrayUtils.*; import java.util.ArrayList; import java.util.List; @@ -17,9 +18,7 @@ import io.fair_acc.dataset.DataSet; import io.fair_acc.dataset.DataSetError; import io.fair_acc.dataset.DataSetError.ErrorType; -import io.fair_acc.dataset.utils.ArrayCache; import io.fair_acc.dataset.utils.CachedDaemonThreadFactory; -import io.fair_acc.dataset.utils.DoubleArrayCache; import io.fair_acc.dataset.utils.ProcessingProfiler; import io.fair_acc.math.ArrayUtils; @@ -31,8 +30,6 @@ */ @SuppressWarnings({ "PMD.TooManyMethods", "PMD.TooManyFields" }) // designated purpose of this class class CachedDataPoints { - private static final String STYLES2 = "styles"; - private static final String SELECTED2 = "selected"; private static final double DEG_TO_RAD = Math.PI / 180.0; protected double[] xValues; @@ -67,21 +64,35 @@ class CachedDataPoints { protected int maxDataCount; protected int actualDataCount; // number of data points that remain after data reduction - public CachedDataPoints(final int indexMin, final int indexMax, final int dataLength, final boolean full) { - maxDataCount = dataLength; - xValues = DoubleArrayCache.getInstance().getArrayExact(maxDataCount); - yValues = DoubleArrayCache.getInstance().getArrayExact(maxDataCount); - styles = ArrayCache.getCachedStringArray(STYLES2, dataLength); + public void trim() { + xValues = clearIfLarger(xValues, maxDataCount); + yValues = clearIfLarger(yValues, maxDataCount); + errorYNeg = clearIfLarger(errorYNeg, maxDataCount); + errorYPos = clearIfLarger(errorYPos, maxDataCount); + errorXNeg = clearIfLarger(errorXNeg, maxDataCount); + errorXPos = clearIfLarger(errorXPos, maxDataCount); + selected = clearIfLarger(selected, maxDataCount); + styles = clearIfLarger(styles, maxDataCount); + errorType = clearIfLarger(errorType, 10); // depends on ds dimensions + } + + public CachedDataPoints resizeMin(final int indexMin, final int indexMax, final int dataLength, final boolean full) { this.indexMin = indexMin; this.indexMax = indexMax; - errorYNeg = DoubleArrayCache.getInstance().getArrayExact(maxDataCount); - errorYPos = DoubleArrayCache.getInstance().getArrayExact(maxDataCount); + maxDataCount = dataLength; + xValues = ArrayUtils.resizeMin(xValues, dataLength); + yValues = ArrayUtils.resizeMin(yValues, dataLength); + errorYNeg = ArrayUtils.resizeMin(errorYNeg, dataLength); + errorYPos = ArrayUtils.resizeMin(errorYPos, dataLength); if (full) { - errorXNeg = DoubleArrayCache.getInstance().getArrayExact(maxDataCount); - errorXPos = DoubleArrayCache.getInstance().getArrayExact(maxDataCount); + errorXNeg = ArrayUtils.resizeMin(errorXNeg, dataLength); + errorXPos = ArrayUtils.resizeMin(errorXPos, dataLength); } - selected = ArrayCache.getCachedBooleanArray(SELECTED2, dataLength); - ArrayUtils.fillArray(styles, null); + selected = ArrayUtils.resizeMin(selected, dataLength); + + // TODO: do we really need to extract all point styles? + styles = ArrayUtils.resizeMinNulled(styles, dataLength, String[]::new); + return this; } protected void computeBoundaryVariables(final Axis xAxis, final Axis yAxis) { @@ -493,17 +504,6 @@ protected void reduce(final RendererDataReducer cruncher, final boolean isReduce minDataPointDistanceX(); } - public void release() { - DoubleArrayCache.getInstance().add(xValues); - DoubleArrayCache.getInstance().add(yValues); - DoubleArrayCache.getInstance().add(errorYNeg); - DoubleArrayCache.getInstance().add(errorYPos); - DoubleArrayCache.getInstance().add(errorXNeg); - DoubleArrayCache.getInstance().add(errorXPos); - ArrayCache.release(SELECTED2, selected); - ArrayCache.release(STYLES2, styles); - } - private void setBoundaryConditions(final Axis xAxis, final Axis yAxis, final DataSet dataSet, final int dsIndex, final int min, final int max, final ErrorStyle rendererErrorStyle, final boolean isPolarPlot, final boolean doAllowForNaNs) { @@ -519,12 +519,11 @@ private void setBoundaryConditions(final Axis xAxis, final Axis yAxis, final Dat } protected void setErrorType(final DataSet dataSet, final ErrorStyle errorStyle) { - errorType = new ErrorType[dataSet.getDimension()]; + errorType = ArrayUtils.resizeMinNulled(errorType, dataSet.getDimension(), ErrorType[]::new); if (dataSet instanceof DataSetError) { final DataSetError ds = (DataSetError) dataSet; for (int dimIndex = 0; dimIndex < ds.getDimension(); dimIndex++) { - final int tmpIndex = dimIndex; - errorType[dimIndex] = ds.getErrorType(tmpIndex); + errorType[dimIndex] = ds.getErrorType(dimIndex); } } else if (errorStyle == ErrorStyle.NONE) { // special case where users does not want error bars diff --git a/chartfx-chart/src/main/java/io/fair_acc/chartfx/renderer/spi/ErrorDataSetRenderer.java b/chartfx-chart/src/main/java/io/fair_acc/chartfx/renderer/spi/ErrorDataSetRenderer.java index ac97d5eb0..71aecca11 100644 --- a/chartfx-chart/src/main/java/io/fair_acc/chartfx/renderer/spi/ErrorDataSetRenderer.java +++ b/chartfx-chart/src/main/java/io/fair_acc/chartfx/renderer/spi/ErrorDataSetRenderer.java @@ -2,11 +2,9 @@ import java.security.InvalidParameterException; import java.util.*; -import java.util.function.Supplier; import io.fair_acc.chartfx.ui.css.DataSetNode; import javafx.collections.ObservableList; -import javafx.geometry.Orientation; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.paint.Color; @@ -19,7 +17,6 @@ import io.fair_acc.chartfx.XYChart; import io.fair_acc.chartfx.XYChartCss; import io.fair_acc.chartfx.axes.Axis; -import io.fair_acc.chartfx.axes.spi.CategoryAxis; import io.fair_acc.chartfx.marker.DefaultMarker; import io.fair_acc.chartfx.marker.Marker; import io.fair_acc.chartfx.renderer.ErrorStyle; @@ -50,7 +47,6 @@ public class ErrorDataSetRenderer extends AbstractErrorDataSetRendererParameter< implements Renderer { private static final Logger LOGGER = LoggerFactory.getLogger(ErrorDataSetRenderer.class); private Marker marker = DefaultMarker.DEFAULT; - private long stopStamp; /** * Creates new ErrorDataSetRenderer. @@ -129,31 +125,20 @@ public Marker getMarker() { } @Override - public List render(final GraphicsContext gc, final Chart chart, final int dataSetOffset, - final ObservableList datasets) { + public List render(final GraphicsContext gc, final Chart chart, final int unusedOffset, + final ObservableList unusedDataSets) { if (!(chart instanceof XYChart)) { throw new InvalidParameterException("must be derivative of XYChart for renderer - " + this.getClass().getSimpleName()); } - // make local copy and add renderer specific data sets - final List localDataSetList = isDrawChartDataSets() ? new ArrayList<>(datasets) : new ArrayList<>(); - localDataSetList.addAll(super.getDatasets()); - // If there are no data sets - if (localDataSetList.isEmpty()) { + if (getDatasets().isEmpty()) { return Collections.emptyList(); } - Axis xAxisTemp = getFirstAxis(Orientation.HORIZONTAL); - if (xAxisTemp == null) { - xAxisTemp = chart.getFirstAxis(Orientation.HORIZONTAL); - } - final Axis xAxis = xAxisTemp; - Axis yAxisTemp = getFirstAxis(Orientation.VERTICAL); - if (yAxisTemp == null) { - yAxisTemp = chart.getFirstAxis(Orientation.VERTICAL); - } - final Axis yAxis = yAxisTemp; + final Axis xAxis = getFirstHorizontalAxis(); + final Axis yAxis = getFirstVerticalAxis(); + final long start = ProcessingProfiler.getTimeStamp(); final double xAxisWidth = xAxis.getWidth(); final boolean xAxisInverted = xAxis.isInvertedAxis(); @@ -164,10 +149,8 @@ public List render(final GraphicsContext gc, final Chart chart, final i ProcessingProfiler.getTimeDiff(start, "init"); } - for (int dataSetIndex = localDataSetList.size() - 1; dataSetIndex >= 0; dataSetIndex--) { - final int ldataSetIndex = dataSetIndex; - stopStamp = ProcessingProfiler.getTimeStamp(); - final DataSet dataSet = localDataSetList.get(dataSetIndex); + for (int dataSetIndex = getDatasetNodes().size() - 1; dataSetIndex >= 0; dataSetIndex--) { + DataSetNode dataSet = getDatasetNodes().get(dataSetIndex); if (!dataSet.isVisible()) { continue; } @@ -176,83 +159,61 @@ public List render(final GraphicsContext gc, final Chart chart, final i // detecting redundant or too frequent render updates) // System.err.println(String.format("render for range [%f,%f] and dataset = '%s'", xMin, xMax, dataSet.getName())); - // update categories in case of category axes for the first (index == '0') indexed data set - if (dataSetIndex == 0) { - if (getFirstAxis(Orientation.HORIZONTAL) instanceof CategoryAxis) { - final CategoryAxis axis = (CategoryAxis) getFirstAxis(Orientation.HORIZONTAL); - axis.updateCategories(dataSet); - } - - if (getFirstAxis(Orientation.VERTICAL) instanceof CategoryAxis) { - final CategoryAxis axis = (CategoryAxis) getFirstAxis(Orientation.VERTICAL); - axis.updateCategories(dataSet); - } + var timestamp = ProcessingProfiler.getTimeStamp(); + final var data = dataSet.getDataSet(); + int indexMin; + int indexMax; /* indexMax is excluded in the drawing */ + if (isAssumeSortedData()) { + indexMin = Math.max(0, data.getIndex(DataSet.DIM_X, xMin) - 1); + indexMax = Math.min(data.getIndex(DataSet.DIM_X, xMax) + 2, data.getDataCount()); + } else { + indexMin = 0; + indexMax = data.getDataCount(); } - // check for potentially reduced data range we are supposed to plot - Supplier> cachedPoints = () -> { - int indexMin; - int indexMax; /* indexMax is excluded in the drawing */ - if (isAssumeSortedData()) { - indexMin = Math.max(0, dataSet.getIndex(DataSet.DIM_X, xMin) - 1); - indexMax = Math.min(dataSet.getIndex(DataSet.DIM_X, xMax) + 2, dataSet.getDataCount()); - } else { - indexMin = 0; - indexMax = dataSet.getDataCount(); - } - - if (indexMax - indexMin <= 0) { - // zero length/range data set -> nothing to be drawn - return Optional.empty(); - } - - if (ProcessingProfiler.getDebugState()) { - stopStamp = ProcessingProfiler.getTimeDiff(stopStamp, - "get min/max" + String.format(" from:%d to:%d", indexMin, indexMax)); - } - - final CachedDataPoints localCachedPoints = new CachedDataPoints(indexMin, indexMax, - dataSet.getDataCount(), true); - if (ProcessingProfiler.getDebugState()) { - stopStamp = ProcessingProfiler.getTimeDiff(stopStamp, "get CachedPoints"); - } - - // compute local screen coordinates - final boolean isPolarPlot = ((XYChart) chart).isPolarPlot(); - if (isParallelImplementation()) { - localCachedPoints.computeScreenCoordinatesInParallel(xAxis, yAxis, dataSet, - dataSetOffset + ldataSetIndex, indexMin, indexMax, getErrorType(), isPolarPlot, - isallowNaNs()); - } else { - localCachedPoints.computeScreenCoordinates(xAxis, yAxis, dataSet, dataSetOffset + ldataSetIndex, - indexMin, indexMax, getErrorType(), isPolarPlot, isallowNaNs()); - } - if (ProcessingProfiler.getDebugState()) { - stopStamp = ProcessingProfiler.getTimeDiff(stopStamp, "computeScreenCoordinates()"); - } - return Optional.of(localCachedPoints); - }; + // zero length/range data set -> nothing to be drawn + if (indexMax - indexMin <= 0) { + continue; + } - cachedPoints.get().ifPresent(value -> { - // invoke data reduction algorithm - value.reduce(rendererDataReducerProperty().get(), isReducePoints(), - getMinRequiredReductionSize()); + if (ProcessingProfiler.getDebugState()) { + timestamp = ProcessingProfiler.getTimeDiff(timestamp, + "get min/max" + String.format(" from:%d to:%d", indexMin, indexMax)); + } - // draw individual plot components - drawChartCompontents(gc, value); + final CachedDataPoints points = STATIC_POINTS_CACHE.resizeMin(indexMin, indexMax, data.getDataCount(), true); + if (ProcessingProfiler.getDebugState()) { + timestamp = ProcessingProfiler.getTimeDiff(timestamp, "get CachedPoints"); + } - value.release(); - }); + // compute local screen coordinates + final boolean isPolarPlot = ((XYChart) chart).isPolarPlot(); + if (isParallelImplementation()) { + points.computeScreenCoordinatesInParallel(xAxis, yAxis, data, + dataSet.getColorIndex(), indexMin, indexMax, getErrorType(), isPolarPlot, + isallowNaNs()); + } else { + points.computeScreenCoordinates(xAxis, yAxis, data, dataSet.getColorIndex(), + indexMin, indexMax, getErrorType(), isPolarPlot, isallowNaNs()); + } + if (ProcessingProfiler.getDebugState()) { + timestamp = ProcessingProfiler.getTimeDiff(timestamp, "computeScreenCoordinates()"); + } - stopStamp = ProcessingProfiler.getTimeStamp(); + // invoke data reduction algorithm + points.reduce(rendererDataReducerProperty().get(), isReducePoints(), + getMinRequiredReductionSize()); + // draw individual plot components + drawChartCompontents(gc, points); if (ProcessingProfiler.getDebugState()) { - ProcessingProfiler.getTimeDiff(stopStamp, "localCachedPoints.release()"); + timestamp = ProcessingProfiler.getTimeDiff(timestamp, "drawChartComponents()"); } + } // end of 'dataSetIndex' loop ProcessingProfiler.getTimeDiff(start); - return localDataSetList; + return getDatasets(); } /** @@ -998,4 +959,15 @@ private static void compactVector(final double[] input, final int stopIndex) { System.arraycopy(input, input.length - stopIndex, input, stopIndex, stopIndex); } } + + // The points cache is thread-safe from the JavaFX thread and can be shared across all instances + private static final CachedDataPoints STATIC_POINTS_CACHE = new CachedDataPoints(); + + /** + * Deletes all arrays that are larger than necessary for the last drawn dataset + */ + public static void trimPointsCache() { + STATIC_POINTS_CACHE.trim(); + } + } diff --git a/chartfx-chart/src/main/java/io/fair_acc/chartfx/ui/css/DataSetNode.java b/chartfx-chart/src/main/java/io/fair_acc/chartfx/ui/css/DataSetNode.java index 80041fc67..1468c4b7a 100644 --- a/chartfx-chart/src/main/java/io/fair_acc/chartfx/ui/css/DataSetNode.java +++ b/chartfx-chart/src/main/java/io/fair_acc/chartfx/ui/css/DataSetNode.java @@ -8,7 +8,6 @@ import io.fair_acc.dataset.events.ChartBits; import io.fair_acc.dataset.events.StateListener; import io.fair_acc.dataset.utils.AssertUtils; -import javafx.beans.binding.Bindings; /** * A dataset wrapper that lives in the SceneGraph for CSS styling diff --git a/chartfx-math/src/main/java/io/fair_acc/math/ArrayUtils.java b/chartfx-math/src/main/java/io/fair_acc/math/ArrayUtils.java index 22e149804..9e92af375 100644 --- a/chartfx-math/src/main/java/io/fair_acc/math/ArrayUtils.java +++ b/chartfx-math/src/main/java/io/fair_acc/math/ArrayUtils.java @@ -2,6 +2,9 @@ import io.fair_acc.dataset.utils.AssertUtils; +import java.util.Arrays; +import java.util.function.IntFunction; + /** * Utility class containing only static functions used to manipulate arrays. * @@ -343,4 +346,69 @@ public static void fillArray(final T[] array, final T value) { final int len = array.length; ArrayUtils.fillArray(array, 0, len, value); } + + /** + * @param array current value + * @param minSize minimum size + * @return a new array if the existing one is not large enough + */ + public static boolean[] resizeMin(boolean[] array, int minSize) { + if(array != null && array.length >= minSize) { + return array; + } + return new boolean[minSize]; + } + + /** + * @param array current value + * @param minSize minimum size + * @return a new array if the existing one is not large enough + */ + public static double[] resizeMin(double[] array, int minSize) { + if(array != null && array.length >= minSize) { + return array; + } + return new double[minSize]; + } + + /** + * @param array current value + * @param minSize minimum size + * @return a new array if the existing one is not large enough + */ + public static T[] resizeMinNulled(T[] array, int minSize, IntFunction constructor) { + if(array != null && array.length >= minSize) { + Arrays.fill(array, 0, minSize, null); + return array; + } + return constructor.apply(minSize); + } + + /** + * @param array existing array + * @param maxSize max size + * @return existing array or null if it is larger than the max size + */ + public static boolean[] clearIfLarger(boolean[] array, int maxSize) { + return array != null && array.length > maxSize ? null : array; + } + + /** + * @param array existing array + * @param maxSize max size + * @return existing array or null if it is larger than the max size + */ + public static double[] clearIfLarger(double[] array, int maxSize) { + return array != null && array.length > maxSize ? null : array; + } + + /** + * @param array existing array + * @param maxSize max size + * @return existing array or null if it is larger than the max size + */ + public static T[] clearIfLarger(T[] array, int maxSize) { + return array != null && array.length > maxSize ? null : array; + } + }