All Downloads are FREE. Search and download functionalities are using the official Maven repository.

repicea.simulation.stemtaper.StemTaperSegmentList Maven / Gradle / Ivy

There is a newer version: 1.1.1
Show newest version
/*
 * This file is part of the repicea-foresttools library.
 *
 * Copyright (C) 2009-2014 Mathieu Fortin for Rouge-Epicea
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed with the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU Lesser General Public
 * License for more details.
 *
 * Please see the license at http://www.gnu.org/copyleft/lesser.html.
 */
package repicea.simulation.stemtaper;

import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.List;

public class StemTaperSegmentList extends ArrayList {

	private static final long serialVersionUID = 20120713L;

	/**
	 * This method returns a List of Double instance that corresponds to the heights (m) across all
	 * segments.
	 * @return a List of Double instances
	 */
	protected List getHeights() {
		List heights= new ArrayList();
		for (StemTaperSegment segments : this) {
			heights.addAll(segments.getHeightsToEvaluate());
		}

		return heights;
	}
	
	
	/**
	 * This method returns a List of Double instance that corresponds to the heights (m) across all
	 * segments without replicates.	This method is essential to avoid having the matrices singular.
	 * @return a List of Double instances
	 */
	public List getHeightsWithoutReplicates() {
		List heightsWithoutReplicates = new ArrayList();
		List originalHeights = getHeights();
		for (Double height : originalHeights) {
			if (!heightsWithoutReplicates.contains(height)) {
				heightsWithoutReplicates.add(height);
			}
		}
		return heightsWithoutReplicates;
	}

	
	/**
	 * This method returns a List of Double instances that correspond to the weights across the segments.
	 * @return a List of Double
	 */
	protected List getWeightsAcrossSegments() {
		List weights = new ArrayList();
		for (StemTaperSegment segment : this) {
			weights.addAll(segment.getWeights());
		}
		return weights;
	}

	
	/**
	 * This method returns a List of Double instances that correspond to the rescaling factors across the segments.
	 * @return a List of Double
	 */
	protected List getRescalingFactorsAcrossSegments() {
		List rescalingFactors = new ArrayList();
		for (StemTaperSegment segment : this) {
			rescalingFactors.addAll(segment.getRescalingFactors());
		}
		return rescalingFactors;
	}

	/**
	 * This static methods provides a list of StemTaperSegment instances embedded in a StemTaperSegmentList.
	 * The method optimizes the integration by using CompositeSimpsonRule numerical integration whenever possible. 
	 * Otherwise, it uses TrapezoidalRule numerical integration.
	 * @param heights a List of Double instances that represent the heights along the bole
	 * @param optimize if false it disables the CompositeSimpsonRule and only the TrapezoidalRule is enabled
	 * @return a StemTaperSegmentList instance
	 */
	public static StemTaperSegmentList createStemTaperSegmentList(List heights, boolean optimize) {
		if (heights == null || heights.size() <= 1) {
			throw new InvalidParameterException("The height list must contains at least two values!");
		}

		StemTaperSegmentList segments = new StemTaperSegmentList();
		List tempList = new ArrayList();
		boolean wereTwoLastEqual = false;
		boolean areTwoLastEqual = false;
		int numberOfHeightsToConsider;
		for (Double point : heights) {
			tempList.add(point);
			if (optimize) {
				if (tempList.size() > 2) {
					areTwoLastEqual = areDistancesEqual(tempList);
					if (tempList.size() == 3) {
						wereTwoLastEqual = areTwoLastEqual;
					}
					if (areTwoLastEqual && !wereTwoLastEqual) {			// means we have a trapezoidal rule here
						numberOfHeightsToConsider = tempList.size() - 2;
						segments.add(StemTaperSegment.createSegment(tempList, false, numberOfHeightsToConsider));
						areTwoLastEqual = true;
						wereTwoLastEqual = true;

					} else if (!areTwoLastEqual && wereTwoLastEqual) {
						numberOfHeightsToConsider = tempList.size() - 1;
						segments.add(StemTaperSegment.createSegment(tempList, true, numberOfHeightsToConsider));
						areTwoLastEqual = false;
						wereTwoLastEqual = false;
					}
				}
			}
		}
		while (tempList.size() > 1) {
			segments.add(StemTaperSegment.createSegment(tempList, wereTwoLastEqual, tempList.size()));
			wereTwoLastEqual = false;
		}
		return segments;
	}

	
	private static boolean areDistancesEqual(List points) {
		double previousDiff = Double.NaN;
		double diff;
		for (int i = points.size() - 2; i < points.size(); i++) {
			diff = points.get(i) - points.get(i - 1); 
			if (Double.isNaN(previousDiff)) {
				previousDiff = diff;
			} else {
				if (Math.abs(diff-previousDiff) > StemTaperSegment.VERY_SMALL) {
					return false;
				}
			}
		}
		return true;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy