AbsVector.java

package org.djunits.vecmat.def;

import java.lang.reflect.Array;
import java.util.Iterator;
import java.util.NoSuchElementException;

import org.djunits.formatter.VectorFormat;
import org.djunits.formatter.VectorFormatter;
import org.djunits.quantity.def.AbsQuantity;
import org.djunits.quantity.def.Quantity;
import org.djunits.quantity.def.Reference;
import org.djunits.unit.Unit;
import org.djunits.value.Value;
import org.djutils.exceptions.Throw;

/**
 * AbsVector contains the contract for Vector classes with absolute values.
 * <p>
 * Copyright (c) 2025-2026 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
 * for project information <a href="https://djunits.org" target="_blank">https://djunits.org</a>. The DJUNITS project is
 * distributed under a <a href="https://djunits.org/docs/license.html" target="_blank">three-clause BSD-style license</a>.
 * @author Alexander Verbraeck
 * @param <A> the absolute quantity type
 * @param <Q> the corresponding relative quantity type
 * @param <VA> the absolute vector or matrix type
 * @param <VQ> the relative vector or matrix type
 * @param <VAT> the type of the transposed version of the absolute vector
 */
public abstract class AbsVector<A extends AbsQuantity<A, Q, ?>, Q extends Quantity<Q>, VA extends AbsVector<A, Q, VA, VQ, VAT>,
        VQ extends Vector<Q, VQ, ?, ?, ?>, VAT extends AbsVector<A, Q, VAT, ?, VA>> extends AbsVectorMatrix<A, Q, VA, VQ, VAT>
        implements Iterable<A>
{
    /** */
    private static final long serialVersionUID = 600L;

    /**
     * Create a new vector of absolute values with a reference point.
     * @param vector the underlying relative vector with SI values relative to the reference point
     * @param reference the reference point for the absolute values
     */
    public AbsVector(final VQ vector, final Reference<?, A, Q> reference)
    {
        super(vector, reference);
    }

    /**
     * Retrieve the size of the vector.
     * @return the size of the vector
     */
    public int size()
    {
        return getRelativeVecMat().size();
    }

    /**
     * Return whether this vector is a column vector.
     * @return whether this vector is a column vector
     */
    public boolean isColumnVector()
    {
        return getRelativeVecMat().isColumnVector();
    }

    /**
     * Return whether this vector is a row vector.
     * @return whether this vector is a row vector
     */
    public boolean isRowVector()
    {
        return getRelativeVecMat().isRowVector();
    }

    /**
     * Retrieve an si-value from the vector.
     * @param index the index (0-based) to retrieve the value from
     * @return the value as a Scalar
     * @throws IndexOutOfBoundsException in case index is out of bounds
     */
    public double si(final int index) throws IndexOutOfBoundsException
    {
        return getRelativeVecMat().si(index);
    }

    /**
     * Retrieve an si-value from the vector, based on a 1-valued index.
     * @param mIndex the index (1-based) to retrieve the value from
     * @return the value as a Scalar
     * @throws IndexOutOfBoundsException in case index is out of bounds
     */
    public double msi(final int mIndex) throws IndexOutOfBoundsException
    {
        return getRelativeVecMat().msi(mIndex);
    }

    /**
     * Retrieve a value from the vector.
     * @param index the index (0-based) to retrieve the value from
     * @return the value as a Scalar
     * @throws IndexOutOfBoundsException in case index is out of bounds
     */
    public A get(final int index) throws IndexOutOfBoundsException
    {
        return getReference().instantiate(getDisplayUnit().ofSi(si(index))).setDisplayUnit(getDisplayUnit());
    }

    /**
     * Retrieve a value from the vector, based on a 1-valued index.
     * @param mIndex the index (1-based) to retrieve the value from
     * @return the value as a Scalar
     * @throws IndexOutOfBoundsException in case index is out of bounds
     */
    public A mget(final int mIndex) throws IndexOutOfBoundsException
    {
        return getReference().instantiate(getDisplayUnit().ofSi(si(mIndex - 1))).setDisplayUnit(getDisplayUnit());
    }

    /**
     * Return the vector as an array of scalars.
     * @return the vector as an array of scalars
     */
    @SuppressWarnings("unchecked")
    public A[] getScalarArray()
    {
        // Determine the runtime type of Q using the first cell; constructors guarantee rows, cols >= 0.
        final A first = getReference().instantiate(getDisplayUnit().ofSi(0.0));
        final Class<?> aClass = first.getClass();
        final A[] out = (A[]) Array.newInstance(aClass, size());
        for (int i = 0; i < size(); i++)
        {
            out[i] = get(i);
        }
        return out;
    }

    /**
     * Return the vector as an array of SI values.
     * @return the vector as an array of SI valies
     */
    public double[] getSiArray()
    {
        final double[] out = new double[size()];
        for (int i = 0; i < size(); i++)
        {
            out[i] = si(i);
        }
        return out;
    }

    /* *********************************************************************************/
    /* ************************************ ITERATOR ***********************************/
    /* *********************************************************************************/

    /**
     * Create and return an iterator over the scalars in this vector in proper sequence.
     * @return an iterator over the scalars in this vector in proper sequence
     */
    @Override
    public Iterator<A> iterator()
    {
        return new AbsVectorIterator();
    }

    /** The iterator class for elements of an absolute vector. */
    class AbsVectorIterator implements Iterator<A>
    {
        /** The index for iteration. */
        private int index = 0;

        @Override
        public boolean hasNext()
        {
            return this.index < size();
        }

        @Override
        public A next()
        {
            Throw.when(!hasNext(), NoSuchElementException.class, "No more elements in absolute vector");
            return get(this.index++);
        }
    }

    /* *********************************************************************************/
    /* ************************** STRING AND FORMATTING METHODS ************************/
    /* *********************************************************************************/

    /**
     * Formatting methods for absolute column vector.
     * @param <V> the vector type
     * @param <Q> the quantity type
     */
    public interface Col<V extends Value<V, Q>, Q extends Quantity<Q>> extends Value<V, Q>
    {
        /**
         * Concise description of this vector.
         * @return a String with the vector, with the unit attached.
         */
        @Override
        default String format()
        {
            return format(VectorFormat.Col.defaults());
        }

        /**
         * String representation of this vector after applying the format.
         * @param format the format to apply for the vector
         * @return a String representation of this vector, formatted according to the given format
         */
        default String format(final VectorFormat.Col format)
        {
            return VectorFormatter.format((AbsVector<?, ?, ?, ?, ?>) this, format);
        }

        /**
         * String representation of this vector, expressed in the specified unit.
         * @param targetUnit the unit into which the values of the vector are converted for display
         * @return printable string with the vector's values expressed in the specified unit
         */
        @Override
        default String format(final Unit<?, Q> targetUnit)
        {
            return format(VectorFormat.Col.defaults().setDisplayUnit(targetUnit));
        }
    }

    /**
     * Formatting methods for absolute row vector.
     * @param <V> the vector type
     * @param <Q> the quantity type
     */
    public interface Row<V extends Value<V, Q>, Q extends Quantity<Q>> extends Value<V, Q>
    {
        /**
         * Concise description of this vector.
         * @return a String with the vector, with the unit attached.
         */
        @Override
        default String format()
        {
            return format(VectorFormat.Row.defaults());
        }

        /**
         * String representation of this vector after applying the format.
         * @param format the format to apply for the vector
         * @return a String representation of this vector, formatted according to the given format
         */
        default String format(final VectorFormat.Row format)
        {
            return VectorFormatter.format((AbsVector<?, ?, ?, ?, ?>) this, format);
        }

        /**
         * String representation of this vector, expressed in the specified unit.
         * @param targetUnit the unit into which the values of the vector are converted for display
         * @return printable string with the vector's values expressed in the specified unit
         */
        @Override
        default String format(final Unit<?, Q> targetUnit)
        {
            return format(VectorFormat.Row.defaults().setDisplayUnit(targetUnit));
        }
    }

}