diff --git a/src/main/org/atriasoft/etk/BorderRadius.java b/src/main/org/atriasoft/etk/BorderRadius.java new file mode 100644 index 0000000..987ecf5 --- /dev/null +++ b/src/main/org/atriasoft/etk/BorderRadius.java @@ -0,0 +1,448 @@ + +package org.atriasoft.etk; + +import org.atriasoft.etk.math.FMath; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import edu.umd.cs.findbugs.annotations.CheckReturnValue; + +public record BorderRadius( + float topLeft, + float topRight, + float bottomRight, + float bottomLeft) { + final static Logger LOGGER = LoggerFactory.getLogger(BorderRadius.class); + + public static BorderRadius valueOf(String value) { + float val1 = 0; + float val2 = 0; + float val3 = 0; + float val4 = 0; + // copy to permit to modify it : + while (value.length() > 0 && value.charAt(0) == '(') { + value = value.substring(1); + } + while (value.length() > 0 && value.charAt(0) == ')') { + value = value.substring(0, value.length() - 1); + } + final String[] values = value.split(",| "); + if (values.length > 3) { + LOGGER.error("Can not parse Constraint4f with more than 3 values: '" + value + "'"); + } + if (values.length == 1) { + // no coma ... + // in every case, we parse the first element : + val1 = Float.valueOf(values[0]); + val2 = val1; + val3 = val1; + val4 = val1; + } else if (values.length == 2) { + // no coma ... + // in every case, we parse the first element : + val1 = Float.valueOf(values[0]); + val2 = Float.valueOf(values[1]); + val3 = val2; + val4 = val2; + } else if (values.length == 3) { + val1 = Float.valueOf(values[0]); + val2 = Float.valueOf(values[1]); + val3 = Float.valueOf(values[2]); + val4 = val3; + } else { + val1 = Float.valueOf(values[0]); + val2 = Float.valueOf(values[1]); + val3 = Float.valueOf(values[2]); + val4 = Float.valueOf(values[3]); + } + return new BorderRadius(val1, val2, val3, val4); + } + + /** + * Constructor from scalars + * @param value unique value for X,Y and Z value + */ + public BorderRadius(final float value) { + this(value, value, value, value); + } + + public BorderRadius(final float topLeft, final float topRight, final float bottomRight, final float bottomLeft) { + this.topLeft = topLeft; + this.topRight = topRight; + this.bottomRight = bottomRight; + this.bottomLeft = bottomLeft; + } + + /** + * Return a vector will the absolute values of each element + * @return the curent reference + */ + @CheckReturnValue + public BorderRadius abs() { + return new BorderRadius(Math.abs(this.topLeft), Math.abs(this.topRight), Math.abs(this.bottomRight), + Math.abs(this.bottomLeft)); + } + + @CheckReturnValue + public BorderRadius add(final float value) { + return new BorderRadius(this.topLeft + value, this.topRight + value, this.bottomRight + value, + this.bottomLeft + value); + } + + @CheckReturnValue + public BorderRadius add(final float xxx, final float yyy, final float zzz, final float www) { + return new BorderRadius(this.topLeft + xxx, this.topRight + yyy, this.bottomRight + zzz, this.bottomLeft + www); + } + + @CheckReturnValue + public BorderRadius clipInteger() { + return new BorderRadius((int) this.topLeft, (int) this.topRight, (int) this.bottomRight, (int) this.bottomLeft); + } + + /** + * Add a vector to this one + * @param obj The vector to add to this one + */ + @CheckReturnValue + public BorderRadius add(final BorderRadius obj) { + return new BorderRadius(this.topLeft + obj.topLeft, this.topRight + obj.topRight, + this.bottomRight + obj.bottomLeft, this.bottomRight + obj.bottomLeft); + } + + /** + * Return the axis with the largest ABSOLUTE value + * @return values 0,1,2 for x, y, or z + */ + @CheckReturnValue + public int closestAxis() { + return abs().getMaxAxis(); + } + + /** + * Return the distance between the ends of this and another vector This + * is symantically treating the vector like a point + * @param obj The other vector to compare distance + * @return the distance of the 2 points + */ + @CheckReturnValue + public float distance(final BorderRadius obj) { + return (float) Math.sqrt(distance2(obj)); + } + + /** + * Return the distance squared between the ends of this and another + * vector This is symantically treating the vector like a point + * @param obj The other vector to compare distance + * @return the square distance of the 2 points + */ + @CheckReturnValue + public float distance2(final BorderRadius obj) { + final float deltaX = obj.topLeft - this.topLeft; + final float deltaY = obj.topRight - this.topRight; + final float deltaZ = obj.bottomRight - this.bottomRight; + final float deltaW = obj.bottomLeft - this.bottomLeft; + return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ + deltaW * deltaW; + } + + @CheckReturnValue + public boolean isZero() { + return this.topLeft == 0.0f && this.topRight == 0.0f && this.bottomRight == 0.0f && this.bottomLeft == 0.0f; + } + + /** + * Inversely scale the vector + * @param val Scale factor to divide by + */ + @CheckReturnValue + public BorderRadius divide(final float val) { + if (val != 0.0f) { + return new BorderRadius(this.topLeft / val, this.topRight / val, this.bottomRight / val, + this.bottomLeft / val); + } + throw new IllegalArgumentException("divice by 0 (BorderRadius)"); + } + + /** + * Inversely scale the vector + * @param val Scale factor to divide by + */ + @CheckReturnValue + public BorderRadius divide(final BorderRadius val) { + return new BorderRadius(this.topLeft / val.topLeft, this.topRight / val.topRight, + this.bottomRight / val.bottomLeft, this.bottomRight / val.bottomLeft); + } + + /** + * Return the dot product + * @param obj The other vector in the dot product + * @return Dot product value + */ + @CheckReturnValue + public float dot(final BorderRadius obj) { + return this.topLeft * obj.topLeft + this.topRight * obj.topRight + this.bottomRight * obj.bottomRight + + this.bottomLeft * obj.bottomLeft; + } + + /** + * Return the axis with the smallest ABSOLUTE value + * @return values 0,1,2 for x, y, or z + */ + @CheckReturnValue + public int furthestAxis() { + return abs().getMinAxis(); + } + + /** + * get the value with his index + * @param index Index of the value (0: x, 1: y, 2: z) + * @return The value associated + */ + @CheckReturnValue + public float get(final int index) { + if (index == 0) { + return this.topLeft; + } else if (index == 1) { + return this.topRight; + } else if (index == 2) { + return this.bottomRight; + } else if (index == 3) { + return this.bottomLeft; + } + throw new IllegalArgumentException("Unknown index: " + index); + } + + /** + * Get the maximum value of the vector (x, y, z) + * @return The max value + */ + @CheckReturnValue + public float getMax() { + return Math.max(Math.max(Math.max(this.topLeft, this.topRight), this.bottomRight), this.bottomLeft); + } + + /** + * Get the Axis id with the maximum value + * @return Axis ID 0,1,2 + */ + @CheckReturnValue + public int getMaxAxis() { + return (this.topLeft < this.topRight + ? (this.topRight < this.bottomRight ? (this.bottomLeft < this.bottomRight ? 2 : 3) + : (this.bottomLeft < this.topRight ? 1 : 3)) + : (this.topLeft < this.bottomRight ? (this.bottomLeft < this.bottomRight ? 2 : 3) + : (this.bottomLeft < this.topLeft ? 0 : 3))); + } + + /** + * Get the minimum value of the vector (x, y, z) + * @return The min value + */ + @CheckReturnValue + public float getMin() { + return Math.min(Math.min(Math.min(this.topLeft, this.topRight), this.bottomRight), this.bottomLeft); + } + + /** + * Get the Axis id with the minimum value + * @return Axis ID 0,1,2 + */ + @CheckReturnValue + public int getMinAxis() { + return (this.topLeft < this.topRight + ? (this.topLeft < this.bottomRight ? (this.bottomLeft < this.topLeft ? 3 : 0) + : (this.bottomLeft < this.bottomRight ? 3 : 2)) + : (this.topRight < this.bottomRight ? (this.bottomLeft < this.topRight ? 3 : 1) + : (this.bottomLeft < this.bottomRight ? 3 : 2))); + } + + // Overloaded operator for the negative of a vector + @CheckReturnValue + public BorderRadius invert() { + return new BorderRadius(-this.topLeft, -this.topRight, -this.bottomRight, -this.bottomLeft); + } + + /** + * In-Equality compare operator with an other object. + * @param obj Reference on the comparing object + * @return true The Objects are NOT identical + * @return false The Objects are identical + */ + @CheckReturnValue + public boolean isDifferent(final BorderRadius obj) { + return ((this.bottomRight != obj.bottomRight) || (this.topRight != obj.topRight) + || (this.topLeft != obj.topLeft) || (this.bottomLeft != obj.bottomLeft)); + } + + /** + * Equality compare operator with an other object. + * @param obj Reference on the comparing object + * @return true The Objects are identical + * @return false The Objects are NOT identical + */ + @CheckReturnValue + public boolean isEqual(final BorderRadius obj) { + return ((this.bottomRight == obj.bottomRight) && (this.topRight == obj.topRight) + && (this.topLeft == obj.topLeft) && (this.bottomLeft == obj.bottomLeft)); + } + + /** + * Return the linear interpolation between this and another vector + * @param obj The other vector + * @param ratio The ratio of this to obj (ratio = 0 => return copy of this, + * ratio=1 => return other) + * @return New vector containing the value + */ + @CheckReturnValue + public BorderRadius lerp(final BorderRadius obj, final float ratio) { + return new BorderRadius(this.topLeft + (obj.topLeft - this.topLeft) * ratio, + this.topRight + (obj.topRight - this.topRight) * ratio, + this.bottomRight + (obj.bottomRight - this.bottomRight) * ratio, + this.bottomLeft + (obj.bottomLeft - this.bottomLeft) * ratio); + } + + @CheckReturnValue + public BorderRadius less(final float value) { + return new BorderRadius(this.topLeft - value, this.topRight - value, this.bottomRight - value, + this.bottomLeft - value); + } + + @CheckReturnValue + public BorderRadius less(final float xxx, final float yyy, final float zzz, final float www) { + return new BorderRadius(this.topLeft - xxx, this.topRight - yyy, this.bottomRight - zzz, this.bottomLeft - www); + } + + /** + * Subtract a vector from this one + * @param obj The vector to subtract + * @return A new vector with the data + */ + @CheckReturnValue + public BorderRadius less(final BorderRadius obj) { + return new BorderRadius(this.topLeft - obj.topLeft, this.topRight - obj.topRight, + this.bottomRight - obj.bottomRight, this.bottomLeft - obj.bottomLeft); + } + + /** + * Scale the vector + * @param val Scale factor + * @return A new vector with the data + */ + @CheckReturnValue + public BorderRadius multiply(final float val) { + return new BorderRadius(this.topLeft * val, this.topRight * val, this.bottomRight * val, this.bottomLeft * val); + } + + /** + * Elementwise multiply this vector by the other + * @param obj The other vector + */ + @CheckReturnValue + public BorderRadius multiply(final BorderRadius obj) { + return new BorderRadius(this.topLeft * obj.topLeft, this.topRight * obj.topRight, + this.bottomRight * obj.bottomLeft, this.bottomRight * obj.bottomLeft); + } + + /** + * Set each element to the max of the current values and the values of + * another Vector4f + * @param obj The other Vector4f to compare with + */ + @CheckReturnValue + public BorderRadius max(final BorderRadius obj) { + return new BorderRadius(Math.max(this.topLeft, obj.topLeft), Math.max(this.topRight, obj.topRight), + Math.max(this.bottomRight, obj.bottomRight), Math.max(this.bottomLeft, obj.bottomLeft)); + } + + @CheckReturnValue + public static BorderRadius max(final BorderRadius obj1, final BorderRadius obj2) { + return new BorderRadius(Math.max(obj1.topLeft, obj2.topLeft), Math.max(obj1.topRight, obj2.topRight), + Math.max(obj1.bottomRight, obj2.bottomRight), Math.max(obj1.bottomLeft, obj2.bottomLeft)); + } + + @CheckReturnValue + public static BorderRadius min(final BorderRadius obj1, final BorderRadius obj2) { + return new BorderRadius(Math.min(obj1.topLeft, obj2.topLeft), Math.min(obj1.topRight, obj2.topRight), + Math.min(obj1.bottomRight, obj2.bottomRight), Math.min(obj1.bottomLeft, obj2.bottomLeft)); + } + + /** + * Set each element to the min of the current values and the values of + * another Vector4f + * @param obj The other Vector4f to compare with + */ + @CheckReturnValue + public BorderRadius min(final BorderRadius obj) { + return new BorderRadius(Math.min(this.topLeft, obj.topLeft), Math.min(this.topRight, obj.topRight), + Math.min(this.bottomRight, obj.bottomRight), Math.min(this.bottomLeft, obj.bottomLeft)); + } + + @CheckReturnValue + public BorderRadius withTopLeft(final float value) { + return new BorderRadius(value, this.topRight, this.bottomRight, this.bottomLeft); + } + + @CheckReturnValue + public BorderRadius withTopRight(final float value) { + return new BorderRadius(this.topLeft, value, this.bottomRight, this.bottomLeft); + } + + @CheckReturnValue + public BorderRadius withBottomRight(final float value) { + return new BorderRadius(this.topLeft, this.topRight, value, this.bottomLeft); + } + + @CheckReturnValue + public BorderRadius withBottomLeft(final float value) { + return new BorderRadius(this.topLeft, this.topRight, this.bottomRight, value); + } + + /** + * Set 0 value on all the vector + */ + public static final BorderRadius ZERO = new BorderRadius(0, 0, 0, 0); + public static final BorderRadius ONE = new BorderRadius(1, 1, 1, 1); + public static final BorderRadius ONE_W = new BorderRadius(0, 0, 0, 1); + public static final BorderRadius VALUE_2 = new BorderRadius(2, 2, 2, 2); + public static final BorderRadius VALUE_4 = new BorderRadius(4, 4, 4, 4); + public static final BorderRadius VALUE_8 = new BorderRadius(8, 8, 8, 8); + public static final BorderRadius VALUE_16 = new BorderRadius(16, 16, 16, 16); + public static final BorderRadius VALUE_32 = new BorderRadius(32, 32, 32, 32); + public static final BorderRadius VALUE_64 = new BorderRadius(64, 64, 64, 64); + public static final BorderRadius VALUE_128 = new BorderRadius(128, 128, 128, 128); + public static final BorderRadius VALUE_256 = new BorderRadius(256, 256, 256, 256); + public static final BorderRadius VALUE_512 = new BorderRadius(512, 512, 512, 512); + public static final BorderRadius VALUE_1024 = new BorderRadius(1024, 1024, 1024, 1024); + public static final BorderRadius MAX_VALUE = new BorderRadius(Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, + Float.MAX_VALUE); + + @Override + public String toString() { + return "BorderRadius(" + FMath.floatToString(this.topLeft) + "," + FMath.floatToString(this.topRight) + "," + + FMath.floatToString(this.bottomRight) + ")"; + } + + /** + * Return the triple product between this and another vector and another + * @param obj1 The other vector 1 + * @param obj2 The other vector 2 + * @return Value with the result of the triple product + */ + @CheckReturnValue + public float triple(final BorderRadius obj1, final BorderRadius obj2) { + return this.topLeft * (obj1.topRight * obj2.bottomRight - obj1.bottomRight * obj2.topRight) + + this.topRight * (obj1.bottomRight * obj2.topLeft - obj1.topLeft * obj2.bottomRight) + + this.bottomRight * (obj1.topLeft * obj2.topRight - obj1.topRight * obj2.topLeft); + } + + public static BorderRadius valueOf( + final String valuesX, + final String valuesY, + final String valuesZ, + final String valuesW) { + final float val1 = Float.valueOf(valuesX); + final float val2 = Float.valueOf(valuesY); + final float val3 = Float.valueOf(valuesZ); + final float val4 = Float.valueOf(valuesW); + return new BorderRadius(val1, val2, val3, val4); + } +} diff --git a/src/main/org/atriasoft/etk/DimensionBorderRadius.java b/src/main/org/atriasoft/etk/DimensionBorderRadius.java new file mode 100644 index 0000000..72aec6b --- /dev/null +++ b/src/main/org/atriasoft/etk/DimensionBorderRadius.java @@ -0,0 +1,275 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +package org.atriasoft.etk; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * in the dimension class we store the data as the more usefull unit (pixel) + * but one case need to be dynamic the %, then when requested in % the register the % value + */ +public record DimensionBorderRadius( + BorderRadius size, + Distance type) { + final static Logger LOGGER = LoggerFactory.getLogger(DimensionBorderRadius.class); + + public static final DimensionBorderRadius ZERO = new DimensionBorderRadius(BorderRadius.ZERO, Distance.PIXEL); + private static BorderRadius ratio = new BorderRadius(9999999, 888888, 7777777, 66666666); + private static BorderRadius invRatio = BorderRadius.ONE; + private static DimensionBorderRadius windowsSize = new DimensionBorderRadius(BorderRadius.MAX_VALUE, + Distance.PIXEL); + + public static final float INCH_TO_MILLIMETER = 1.0f / 25.4f; + public static final float FOOT_TO_MILLIMETER = 1.0f / 304.8f; + public static final float METER_TO_MILLIMETER = 1.0f / 1000.0f; + public static final float CENTIMETER_TO_MILLIMETER = 1.0f / 10.0f; + public static final float KILOMETER_TO_MILLIMETER = 1.0f / 1000000.0f; + public static final float MILLIMETER_TO_INCH = 25.4f; + public static final float MILLIMETER_TO_FOOT = 304.8f; + public static final float MILLIMETER_TO_METER = 1000.0f; + public static final float MILLIMETER_TO_CENTIMETER = 10.0f; + public static final float MILLIMETER_TO_KILOMETER = 1000000.0f; + /** + * basic init + */ + static { + final DimensionBorderRadius conversion = new DimensionBorderRadius(new BorderRadius(72, 72, 72, 72), + Distance.INCH); + ratio = conversion.getMillimeter(); + invRatio = new BorderRadius(1.0f / ratio.topLeft(), 1.0f / ratio.topRight(), 1.0f / ratio.bottomRight(), + 1.0f / ratio.bottomLeft()); + windowsSize = new DimensionBorderRadius(new BorderRadius(200, 200, 200, 200), Distance.PIXEL); + } + + /** + * set the current Windows size + * @param size size of the current windows in pixel. + */ + public static void setPixelWindowsSize(final BorderRadius size) { + windowsSize = new DimensionBorderRadius(size); + } + + /** + * Constructor (default :0,0 mode pixel) + */ + public DimensionBorderRadius() { + this(BorderRadius.ZERO, Distance.PIXEL); + } + + /** + * Constructor + * @param size Requested dimension + */ + public DimensionBorderRadius(final float size) { + this(new BorderRadius(size, size, size, size), Distance.PIXEL); + } + + public DimensionBorderRadius(final BorderRadius size) { + this(size, Distance.PIXEL); + } + + public DimensionBorderRadius(final BorderRadius size, final Distance type) { + this.size = size; + this.type = type; + } + + /** + * get the current dimension in requested type + * @param type Type of unit requested. + * @return dimension requested. + */ + public BorderRadius get(final Distance type) { + return switch (type) { + case POURCENT -> getPourcent(); + case PIXEL -> getPixel(); + case METER -> getMeter(); + case CENTIMETER -> getCentimeter(); + case MILLIMETER -> getMillimeter(); + case KILOMETER -> getKilometer(); + case INCH -> getInch(); + case FOOT -> getFoot(); + case ELEMENT -> throw new UnsupportedOperationException("Unimplemented case: " + type); + case EX -> throw new UnsupportedOperationException("Unimplemented case: " + type); + case PC -> { + LOGGER.error("Does not support other than Px and % type of dimention : " + type + + " automaticly convert with {72,72} pixel/inch"); + yield null; + } + case POINT -> throw new UnsupportedOperationException("Unimplemented case: " + type); + default -> throw new IllegalArgumentException("Unexpected value: " + type); + }; + } + + /** + * get the current dimension in Centimeter + * @return dimension in Centimeter + */ + public BorderRadius getCentimeter() { + return getMillimeter().multiply(MILLIMETER_TO_CENTIMETER); + } + + /** + * get the current dimension in Foot + * @return dimension in Foot + */ + public BorderRadius getFoot() { + return getMillimeter().multiply(MILLIMETER_TO_FOOT); + } + + /** + * get the current dimension in Inch + * @return dimension in Inch + */ + public BorderRadius getInch() { + return getMillimeter().multiply(MILLIMETER_TO_INCH); + } + + /** + * get the current dimension in Kilometer + * @return dimension in Kilometer + */ + public BorderRadius getKilometer() { + return getMillimeter().multiply(MILLIMETER_TO_KILOMETER); + } + + /** + * get the current dimension in Meter + * @return dimension in Meter + */ + public BorderRadius getMeter() { + return getMillimeter().multiply(MILLIMETER_TO_METER); + } + + /** + * get the current dimension in Millimeter + * @return dimension in Millimeter + */ + public BorderRadius getMillimeter() { + return new BorderRadius(getPixel().topLeft() * invRatio.topLeft(), getPixel().topRight() * invRatio.topRight(), + getPixel().bottomRight() * invRatio.bottomRight(), getPixel().bottomLeft() * invRatio.bottomLeft()); + } + + /** + * get the current dimension in pixel + * @return dimension in Pixel + */ + public BorderRadius getPixel() { + if (this.type != Distance.POURCENT) { + return this.size; + } + return getPixel(windowsSize.getPixel()); + } + + public BorderRadius getPixel(final BorderRadius uppersize) { + if (this.type != Distance.POURCENT) { + return this.size; + } + final BorderRadius res = new BorderRadius(uppersize.topLeft() * this.size.topLeft() * 0.01f, + uppersize.topRight() * this.size.topRight() * 0.01f, + uppersize.bottomRight() * this.size.bottomRight() * 0.01f, + uppersize.bottomLeft() * this.size.bottomLeft() * 0.01f); + //GALE_DEBUG("Get % : " + m_data + " / " + windDim + " == > " + res); + return res; + } + + /** + * get the current dimension in Pourcent + * @return dimension in Pourcent + */ + public BorderRadius getPourcent() { + if (this.type != Distance.POURCENT) { + final BorderRadius windDim = windowsSize.getPixel(); + //GALE_DEBUG(" windows dimension : " /*+ windowsSize*/ + " == > " + windDim + "px"); // ==> infinite loop ... + //printf(" windows dimension : %f,%f", windDim.topLeft(),windDim.topRight()); + //printf(" data : %f,%f", m_data.topLeft(),m_data.topRight()); + return new BorderRadius((this.size.topLeft() / windDim.topLeft()) * 100.0f, + (this.size.topRight() / windDim.topRight()) * 100.0f, + (this.size.bottomRight() / windDim.bottomRight()) * 100.0f, + (this.size.bottomLeft() / windDim.bottomLeft()) * 100.0f); + } + return new BorderRadius(this.size.topLeft() * 100.0f, this.size.topRight() * 100.0f, + this.size.bottomRight() * 100.0f, this.size.bottomLeft() * 100.0f); + } + + /** + * get the dimension type + * @return the type + */ + public Distance getType() { + return this.type; + } + + /** + * set the current dimension in requested type + * @param config dimension configuration. + */ + public static DimensionBorderRadius valueOf(String config) { + final Distance type = Distance.parseEndSmallString(config); + config = type.removeEndString(config); + if (type == Distance.UNKNOW) { + LOGGER.error("Can not parse dimension : '" + config + "'"); + return null; + } + final BorderRadius tmp = BorderRadius.valueOf(config); + final DimensionBorderRadius ret = new DimensionBorderRadius(tmp, type); + return ret; + } + + public DimensionBorderRadius withSize(final BorderRadius size) { + return new DimensionBorderRadius(size, this.type); + } + + public DimensionBorderRadius withType(final Distance type) { + return new DimensionBorderRadius(this.size, type); + } + + /** + * string cast : + */ + @Override + public String toString() { + return get(getType()).toString() + getType().toSmallString(); + } + + public static DimensionBorderRadius valueOf( + String contentX, + final String contentY, + final String contentZ, + final String contentW) { + + final Distance typeX = Distance.parseEndSmallString(contentX); + contentX = typeX.removeEndString(contentX); + final float tmpX = Float.valueOf(contentX); + + final Distance typeY = Distance.parseEndSmallString(contentY); + contentX = typeY.removeEndString(contentY); + final float tmpY = Float.valueOf(contentY); + + final Distance typeZ = Distance.parseEndSmallString(contentZ); + contentX = typeZ.removeEndString(contentZ); + final float tmpZ = Float.valueOf(contentZ); + + final Distance typeW = Distance.parseEndSmallString(contentW); + contentX = typeW.removeEndString(contentZ); + final float tmpW = Float.valueOf(contentZ); + + if (typeX != Distance.UNKNOW) { + return new DimensionBorderRadius(new BorderRadius(tmpX, tmpY, tmpZ, tmpW), typeX); + } + if (typeY != Distance.UNKNOW) { + return new DimensionBorderRadius(new BorderRadius(tmpX, tmpY, tmpZ, tmpW), typeY); + } + if (typeZ != Distance.UNKNOW) { + return new DimensionBorderRadius(new BorderRadius(tmpX, tmpY, tmpZ, tmpW), typeZ); + } + if (typeW != Distance.UNKNOW) { + return new DimensionBorderRadius(new BorderRadius(tmpX, tmpY, tmpZ, tmpW), typeW); + } + return new DimensionBorderRadius(new BorderRadius(tmpX, tmpY, tmpZ, tmpW), Distance.PIXEL); + } + +} diff --git a/src/main/org/atriasoft/etk/DimensionInsets.java b/src/main/org/atriasoft/etk/DimensionInsets.java new file mode 100644 index 0000000..73cb47c --- /dev/null +++ b/src/main/org/atriasoft/etk/DimensionInsets.java @@ -0,0 +1,272 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +package org.atriasoft.etk; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * in the dimension class we store the data as the more usefull unit (pixel) + * but one case need to be dynamic the %, then when requested in % the register the % value + */ +public record DimensionInsets( + Insets size, + Distance type) { + final static Logger LOGGER = LoggerFactory.getLogger(DimensionInsets.class); + + public static final DimensionInsets ZERO = new DimensionInsets(Insets.ZERO, Distance.PIXEL); + private static Insets ratio = new Insets(9999999, 888888, 7777777, 66666666); + private static Insets invRatio = Insets.ONE; + private static DimensionInsets windowsSize = new DimensionInsets(Insets.MAX_VALUE, Distance.PIXEL); + + public static final float INCH_TO_MILLIMETER = 1.0f / 25.4f; + public static final float FOOT_TO_MILLIMETER = 1.0f / 304.8f; + public static final float METER_TO_MILLIMETER = 1.0f / 1000.0f; + public static final float CENTIMETER_TO_MILLIMETER = 1.0f / 10.0f; + public static final float KILOMETER_TO_MILLIMETER = 1.0f / 1000000.0f; + public static final float MILLIMETER_TO_INCH = 25.4f; + public static final float MILLIMETER_TO_FOOT = 304.8f; + public static final float MILLIMETER_TO_METER = 1000.0f; + public static final float MILLIMETER_TO_CENTIMETER = 10.0f; + public static final float MILLIMETER_TO_KILOMETER = 1000000.0f; + /** + * basic init + */ + static { + final DimensionInsets conversion = new DimensionInsets(new Insets(72, 72, 72, 72), Distance.INCH); + ratio = conversion.getMillimeter(); + invRatio = new Insets(1.0f / ratio.top(), 1.0f / ratio.right(), 1.0f / ratio.bottom(), 1.0f / ratio.left()); + windowsSize = new DimensionInsets(new Insets(200, 200, 200, 200), Distance.PIXEL); + } + + /** + * set the current Windows size + * @param size size of the current windows in pixel. + */ + public static void setPixelWindowsSize(final Insets size) { + windowsSize = new DimensionInsets(size); + } + + /** + * Constructor (default :0,0 mode pixel) + */ + public DimensionInsets() { + this(Insets.ZERO, Distance.PIXEL); + } + + /** + * Constructor + * @param size Requested dimension + */ + public DimensionInsets(final float size) { + this(new Insets(size, size, size, size), Distance.PIXEL); + } + + public DimensionInsets(final Insets size) { + this(size, Distance.PIXEL); + } + + public DimensionInsets(final Insets size, final Distance type) { + this.size = size; + this.type = type; + } + + /** + * get the current dimension in requested type + * @param type Type of unit requested. + * @return dimension requested. + */ + public Insets get(final Distance type) { + return switch (type) { + case POURCENT -> getPourcent(); + case PIXEL -> getPixel(); + case METER -> getMeter(); + case CENTIMETER -> getCentimeter(); + case MILLIMETER -> getMillimeter(); + case KILOMETER -> getKilometer(); + case INCH -> getInch(); + case FOOT -> getFoot(); + case ELEMENT -> throw new UnsupportedOperationException("Unimplemented case: " + type); + case EX -> throw new UnsupportedOperationException("Unimplemented case: " + type); + case PC -> { + LOGGER.error("Does not support other than Px and % type of dimention : " + type + + " automaticly convert with {72,72} pixel/inch"); + yield null; + } + case POINT -> throw new UnsupportedOperationException("Unimplemented case: " + type); + default -> throw new IllegalArgumentException("Unexpected value: " + type); + }; + } + + /** + * get the current dimension in Centimeter + * @return dimension in Centimeter + */ + public Insets getCentimeter() { + return getMillimeter().multiply(MILLIMETER_TO_CENTIMETER); + } + + /** + * get the current dimension in Foot + * @return dimension in Foot + */ + public Insets getFoot() { + return getMillimeter().multiply(MILLIMETER_TO_FOOT); + } + + /** + * get the current dimension in Inch + * @return dimension in Inch + */ + public Insets getInch() { + return getMillimeter().multiply(MILLIMETER_TO_INCH); + } + + /** + * get the current dimension in Kilometer + * @return dimension in Kilometer + */ + public Insets getKilometer() { + return getMillimeter().multiply(MILLIMETER_TO_KILOMETER); + } + + /** + * get the current dimension in Meter + * @return dimension in Meter + */ + public Insets getMeter() { + return getMillimeter().multiply(MILLIMETER_TO_METER); + } + + /** + * get the current dimension in Millimeter + * @return dimension in Millimeter + */ + public Insets getMillimeter() { + return new Insets(getPixel().top() * invRatio.top(), getPixel().right() * invRatio.right(), + getPixel().bottom() * invRatio.bottom(), getPixel().left() * invRatio.left()); + } + + /** + * get the current dimension in pixel + * @return dimension in Pixel + */ + public Insets getPixel() { + if (this.type != Distance.POURCENT) { + return this.size; + } + return getPixel(windowsSize.getPixel()); + } + + public Insets getPixel(final Insets uppersize) { + if (this.type != Distance.POURCENT) { + return this.size; + } + final Insets res = new Insets(uppersize.top() * this.size.top() * 0.01f, + uppersize.right() * this.size.right() * 0.01f, uppersize.bottom() * this.size.bottom() * 0.01f, + uppersize.left() * this.size.left() * 0.01f); + //GALE_DEBUG("Get % : " + m_data + " / " + windDim + " == > " + res); + return res; + } + + /** + * get the current dimension in Pourcent + * @return dimension in Pourcent + */ + public Insets getPourcent() { + if (this.type != Distance.POURCENT) { + final Insets windDim = windowsSize.getPixel(); + return new Insets(// + (this.size.top() / windDim.top()) * 100.0f, // + (this.size.right() / windDim.right()) * 100.0f, // + (this.size.bottom() / windDim.bottom()) * 100.0f, // + (this.size.left() / windDim.left()) * 100.0f); + } + return new Insets(// + this.size.top() * 100.0f, // + this.size.right() * 100.0f, // + this.size.bottom() * 100.0f, // + this.size.left() * 100.0f); + } + + /** + * get the dimension type + * @return the type + */ + public Distance getType() { + return this.type; + } + + /** + * set the current dimension in requested type + * @param config dimension configuration. + */ + public static DimensionInsets valueOf(String config) { + final Distance type = Distance.parseEndSmallString(config); + config = type.removeEndString(config); + if (type == Distance.UNKNOW) { + LOGGER.error("Can not parse dimension : '" + config + "'"); + return null; + } + final Insets tmp = Insets.valueOf(config); + final DimensionInsets ret = new DimensionInsets(tmp, type); + return ret; + } + + public DimensionInsets withSize(final Insets size) { + return new DimensionInsets(size, this.type); + } + + public DimensionInsets withType(final Distance type) { + return new DimensionInsets(this.size, type); + } + + /** + * string cast : + */ + @Override + public String toString() { + return get(getType()).toString() + getType().toSmallString(); + } + + public static DimensionInsets valueOf( + String contentX, + final String contentY, + final String contentZ, + final String contentW) { + + final Distance typeX = Distance.parseEndSmallString(contentX); + contentX = typeX.removeEndString(contentX); + final float tmpX = Float.valueOf(contentX); + + final Distance typeY = Distance.parseEndSmallString(contentX); + contentX = typeY.removeEndString(contentY); + final float tmpY = Float.valueOf(contentY); + + final Distance typeZ = Distance.parseEndSmallString(contentX); + contentX = typeZ.removeEndString(contentZ); + final float tmpZ = Float.valueOf(contentZ); + + final Distance typeW = Distance.parseEndSmallString(contentX); + contentX = typeW.removeEndString(contentW); + final float tmpW = Float.valueOf(contentW); + + if (typeX != Distance.UNKNOW) { + return new DimensionInsets(new Insets(tmpX, tmpY, tmpZ, tmpW), typeX); + } + if (typeY != Distance.UNKNOW) { + return new DimensionInsets(new Insets(tmpX, tmpY, tmpZ, tmpW), typeY); + } + if (typeZ != Distance.UNKNOW) { + return new DimensionInsets(new Insets(tmpX, tmpY, tmpZ, tmpW), typeZ); + } + if (typeW != Distance.UNKNOW) { + return new DimensionInsets(new Insets(tmpX, tmpY, tmpZ, tmpW), typeW); + } + return new DimensionInsets(new Insets(tmpX, tmpY, tmpZ, tmpW), Distance.PIXEL); + } + +} diff --git a/src/main/org/atriasoft/etk/Insets.java b/src/main/org/atriasoft/etk/Insets.java new file mode 100644 index 0000000..d10cb30 --- /dev/null +++ b/src/main/org/atriasoft/etk/Insets.java @@ -0,0 +1,433 @@ + +package org.atriasoft.etk; + +import org.atriasoft.etk.math.FMath; +import org.atriasoft.etk.math.Vector2f; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import edu.umd.cs.findbugs.annotations.CheckReturnValue; + +public record Insets( + float top, + float right, + float bottom, + float left) { + final static Logger LOGGER = LoggerFactory.getLogger(Insets.class); + + public Vector2f toVector2f() { + return new Vector2f(this.left + this.right, this.top + this.bottom); + } + + public static Insets valueOf(String value) { + float val1 = 0; + float val2 = 0; + float val3 = 0; + float val4 = 0; + // copy to permit to modify it : + while (value.length() > 0 && value.charAt(0) == '(') { + value = value.substring(1); + } + while (value.length() > 0 && value.charAt(0) == ')') { + value = value.substring(0, value.length() - 1); + } + final String[] values = value.split(",| "); + if (values.length > 3) { + LOGGER.error("Can not parse Constraint4f with more than 3 values: '" + value + "'"); + } + if (values.length == 1) { + // no coma ... + // in every case, we parse the first element : + val1 = Float.valueOf(values[0]); + val2 = val1; + val3 = val1; + val4 = val1; + } else if (values.length == 2) { + // no coma ... + // in every case, we parse the first element : + val1 = Float.valueOf(values[0]); + val2 = Float.valueOf(values[1]); + val3 = val2; + val4 = val2; + } else if (values.length == 3) { + val1 = Float.valueOf(values[0]); + val2 = Float.valueOf(values[1]); + val3 = Float.valueOf(values[2]); + val4 = val3; + } else { + val1 = Float.valueOf(values[0]); + val2 = Float.valueOf(values[1]); + val3 = Float.valueOf(values[2]); + val4 = Float.valueOf(values[3]); + } + return new Insets(val1, val2, val3, val4); + } + + /** + * Constructor from scalars + * @param value unique value for X,Y and Z value + */ + public Insets(final float value) { + this(value, value, value, value); + } + + public Insets(final float top, final float right, final float bottom, final float left) { + this.top = top; + this.right = right; + this.bottom = bottom; + this.left = left; + } + + /** + * Return a vector will the absolute values of each element + * @return the curent reference + */ + @CheckReturnValue + public Insets abs() { + return new Insets(Math.abs(this.top), Math.abs(this.right), Math.abs(this.bottom), Math.abs(this.left)); + } + + @CheckReturnValue + public Insets add(final float value) { + return new Insets(this.top + value, this.right + value, this.bottom + value, this.left + value); + } + + @CheckReturnValue + public Insets add(final float xxx, final float yyy, final float zzz, final float www) { + return new Insets(this.top + xxx, this.right + yyy, this.bottom + zzz, this.left + www); + } + + @CheckReturnValue + public Insets clipInteger() { + return new Insets((int) this.top, (int) this.right, (int) this.bottom, (int) this.left); + } + + /** + * Add a vector to this one + * @param obj The vector to add to this one + */ + @CheckReturnValue + public Insets add(final Insets obj) { + return new Insets(this.top + obj.top, this.right + obj.right, this.bottom + obj.left, this.bottom + obj.left); + } + + /** + * Return the axis with the largest ABSOLUTE value + * @return values 0,1,2 for x, y, or z + */ + @CheckReturnValue + public int closestAxis() { + return abs().getMaxAxis(); + } + + /** + * Return the distance between the ends of this and another vector This + * is symantically treating the vector like a point + * @param obj The other vector to compare distance + * @return the distance of the 2 points + */ + @CheckReturnValue + public float distance(final Insets obj) { + return (float) Math.sqrt(distance2(obj)); + } + + /** + * Return the distance squared between the ends of this and another + * vector This is symantically treating the vector like a point + * @param obj The other vector to compare distance + * @return the square distance of the 2 points + */ + @CheckReturnValue + public float distance2(final Insets obj) { + final float deltaX = obj.top - this.top; + final float deltaY = obj.right - this.right; + final float deltaZ = obj.bottom - this.bottom; + final float deltaW = obj.left - this.left; + return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ + deltaW * deltaW; + } + + /** + * Inversely scale the vector + * @param val Scale factor to divide by + */ + @CheckReturnValue + public Insets divide(final float val) { + if (val != 0.0f) { + return new Insets(this.top / val, this.right / val, this.bottom / val, this.left / val); + } + throw new IllegalArgumentException("divice by 0 (Vector4f)"); + } + + /** + * Inversely scale the vector + * @param val Scale factor to divide by + */ + @CheckReturnValue + public Insets divide(final Insets val) { + return new Insets(this.top / val.top, this.right / val.right, this.bottom / val.left, this.bottom / val.left); + } + + /** + * Return the dot product + * @param obj The other vector in the dot product + * @return Dot product value + */ + @CheckReturnValue + public float dot(final Insets obj) { + return this.top * obj.top + this.right * obj.right + this.bottom * obj.bottom + this.left * obj.left; + } + + /** + * Return the axis with the smallest ABSOLUTE value + * @return values 0,1,2 for x, y, or z + */ + @CheckReturnValue + public int furthestAxis() { + return abs().getMinAxis(); + } + + /** + * get the value with his index + * @param index Index of the value (0: x, 1: y, 2: z) + * @return The value associated + */ + @CheckReturnValue + public float get(final int index) { + if (index == 0) { + return this.top; + } else if (index == 1) { + return this.right; + } else if (index == 2) { + return this.bottom; + } else if (index == 3) { + return this.left; + } + throw new IllegalArgumentException("Unknown index: " + index); + } + + /** + * Get the maximum value of the vector (x, y, z) + * @return The max value + */ + @CheckReturnValue + public float getMax() { + return Math.max(Math.max(Math.max(this.top, this.right), this.bottom), this.left); + } + + /** + * Get the Axis id with the maximum value + * @return Axis ID 0,1,2 + */ + @CheckReturnValue + public int getMaxAxis() { + return (this.top < this.right + ? (this.right < this.bottom ? (this.left < this.bottom ? 2 : 3) : (this.left < this.right ? 1 : 3)) + : (this.top < this.bottom ? (this.left < this.bottom ? 2 : 3) : (this.left < this.top ? 0 : 3))); + } + + /** + * Get the minimum value of the vector (x, y, z) + * @return The min value + */ + @CheckReturnValue + public float getMin() { + return Math.min(Math.min(Math.min(this.top, this.right), this.bottom), this.left); + } + + /** + * Get the Axis id with the minimum value + * @return Axis ID 0,1,2 + */ + @CheckReturnValue + public int getMinAxis() { + return (this.top < this.right + ? (this.top < this.bottom ? (this.left < this.top ? 3 : 0) : (this.left < this.bottom ? 3 : 2)) + : (this.right < this.bottom ? (this.left < this.right ? 3 : 1) : (this.left < this.bottom ? 3 : 2))); + } + + // Overloaded operator for the negative of a vector + @CheckReturnValue + public Insets invert() { + return new Insets(-this.top, -this.right, -this.bottom, -this.left); + } + + /** + * In-Equality compare operator with an other object. + * @param obj Reference on the comparing object + * @return true The Objects are NOT identical + * @return false The Objects are identical + */ + @CheckReturnValue + public boolean isDifferent(final Insets obj) { + return ((this.bottom != obj.bottom) || (this.right != obj.right) || (this.top != obj.top) + || (this.left != obj.left)); + } + + /** + * Equality compare operator with an other object. + * @param obj Reference on the comparing object + * @return true The Objects are identical + * @return false The Objects are NOT identical + */ + @CheckReturnValue + public boolean isEqual(final Insets obj) { + return ((this.bottom == obj.bottom) && (this.right == obj.right) && (this.top == obj.top) + && (this.left == obj.left)); + } + + /** + * Return the linear interpolation between this and another vector + * @param obj The other vector + * @param ratio The ratio of this to obj (ratio = 0 => return copy of this, + * ratio=1 => return other) + * @return New vector containing the value + */ + @CheckReturnValue + public Insets lerp(final Insets obj, final float ratio) { + return new Insets(this.top + (obj.top - this.top) * ratio, this.right + (obj.right - this.right) * ratio, + this.bottom + (obj.bottom - this.bottom) * ratio, this.left + (obj.left - this.left) * ratio); + } + + @CheckReturnValue + public Insets less(final float value) { + return new Insets(this.top - value, this.right - value, this.bottom - value, this.left - value); + } + + @CheckReturnValue + public Insets less(final float xxx, final float yyy, final float zzz, final float www) { + return new Insets(this.top - xxx, this.right - yyy, this.bottom - zzz, this.left - www); + } + + /** + * Subtract a vector from this one + * @param obj The vector to subtract + * @return A new vector with the data + */ + @CheckReturnValue + public Insets less(final Insets obj) { + return new Insets(this.top - obj.top, this.right - obj.right, this.bottom - obj.bottom, this.left - obj.left); + } + + /** + * Scale the vector + * @param val Scale factor + * @return A new vector with the data + */ + @CheckReturnValue + public Insets multiply(final float val) { + return new Insets(this.top * val, this.right * val, this.bottom * val, this.left * val); + } + + /** + * Elementwise multiply this vector by the other + * @param obj The other vector + */ + @CheckReturnValue + public Insets multiply(final Insets obj) { + return new Insets(this.top * obj.top, this.right * obj.right, this.bottom * obj.left, this.bottom * obj.left); + } + + /** + * Set each element to the max of the current values and the values of + * another Vector4f + * @param obj The other Vector4f to compare with + */ + @CheckReturnValue + public Insets max(final Insets obj) { + return new Insets(Math.max(this.top, obj.top), Math.max(this.right, obj.right), + Math.max(this.bottom, obj.bottom), Math.max(this.left, obj.left)); + } + + @CheckReturnValue + public static Insets max(final Insets obj1, final Insets obj2) { + return new Insets(Math.max(obj1.top, obj2.top), Math.max(obj1.right, obj2.right), + Math.max(obj1.bottom, obj2.bottom), Math.max(obj1.left, obj2.left)); + } + + @CheckReturnValue + public static Insets min(final Insets obj1, final Insets obj2) { + return new Insets(Math.min(obj1.top, obj2.top), Math.min(obj1.right, obj2.right), + Math.min(obj1.bottom, obj2.bottom), Math.min(obj1.left, obj2.left)); + } + + /** + * Set each element to the min of the current values and the values of + * another Vector4f + * @param obj The other Vector4f to compare with + */ + @CheckReturnValue + public Insets min(final Insets obj) { + return new Insets(Math.min(this.top, obj.top), Math.min(this.right, obj.right), + Math.min(this.bottom, obj.bottom), Math.min(this.left, obj.left)); + } + + @CheckReturnValue + public Insets withTop(final float value) { + return new Insets(value, this.right, this.bottom, this.left); + } + + @CheckReturnValue + public Insets withRight(final float value) { + return new Insets(this.top, value, this.bottom, this.left); + } + + @CheckReturnValue + public Insets withBottom(final float value) { + return new Insets(this.top, this.right, value, this.left); + } + + @CheckReturnValue + public Insets withLeft(final float value) { + return new Insets(this.top, this.right, this.bottom, value); + } + + /** + * Set 0 value on all the vector + */ + public static final Insets ZERO = new Insets(0, 0, 0, 0); + public static final Insets ONE = new Insets(1, 1, 1, 1); + public static final Insets ONE_W = new Insets(0, 0, 0, 1); + public static final Insets VALUE_2 = new Insets(2, 2, 2, 2); + public static final Insets VALUE_4 = new Insets(4, 4, 4, 4); + public static final Insets VALUE_8 = new Insets(8, 8, 8, 8); + public static final Insets VALUE_16 = new Insets(16, 16, 16, 16); + public static final Insets VALUE_32 = new Insets(32, 32, 32, 32); + public static final Insets VALUE_64 = new Insets(64, 64, 64, 64); + public static final Insets VALUE_128 = new Insets(128, 128, 128, 128); + public static final Insets VALUE_256 = new Insets(256, 256, 256, 256); + public static final Insets VALUE_512 = new Insets(512, 512, 512, 512); + public static final Insets VALUE_1024 = new Insets(1024, 1024, 1024, 1024); + public static final Insets MAX_VALUE = new Insets(Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, + Float.MAX_VALUE); + + @Override + public String toString() { + return "Vector4f(" + FMath.floatToString(this.top) + "," + FMath.floatToString(this.right) + "," + + FMath.floatToString(this.bottom) + ")"; + } + + /** + * Return the triple product between this and another vector and another + * @param obj1 The other vector 1 + * @param obj2 The other vector 2 + * @return Value with the result of the triple product + */ + @CheckReturnValue + public float triple(final Insets obj1, final Insets obj2) { + return this.top * (obj1.right * obj2.bottom - obj1.bottom * obj2.right) + + this.right * (obj1.bottom * obj2.top - obj1.top * obj2.bottom) + + this.bottom * (obj1.top * obj2.right - obj1.right * obj2.top); + } + + public static Insets valueOf( + final String valuesX, + final String valuesY, + final String valuesZ, + final String valuesW) { + final float val1 = Float.valueOf(valuesX); + final float val2 = Float.valueOf(valuesY); + final float val3 = Float.valueOf(valuesZ); + final float val4 = Float.valueOf(valuesW); + return new Insets(val1, val2, val3, val4); + } +} diff --git a/src/main/org/atriasoft/etk/math/Vector2i.java b/src/main/org/atriasoft/etk/math/Vector2i.java index 15c1dff..0694a2a 100644 --- a/src/main/org/atriasoft/etk/math/Vector2i.java +++ b/src/main/org/atriasoft/etk/math/Vector2i.java @@ -9,7 +9,7 @@ public record Vector2i( int x, int y) { final static Logger LOGGER = LoggerFactory.getLogger(Vector2i.class); - + public static Vector2i valueOf(String value) throws NumberFormatException { int val1 = 0; int val2 = 0; @@ -35,30 +35,31 @@ public record Vector2i( } return new Vector2i(val1, val2); } - + /* * **************************************************** Constructor *****************************************************/ public Vector2i() { this(0, 0); } - + public Vector2i(final int x, final int y) { this.x = x; this.y = y; } - + public Vector2f toVector2f() { return new Vector2f(this.x, this.y); } + public static Vector2i max(final Vector2i obj1, final Vector2i obj2) { return new Vector2i(Math.max(obj1.x, obj2.x), Math.max(obj1.y, obj2.y)); } - + public static Vector2i min(final Vector2i obj1, final Vector2i obj2) { return new Vector2i(Math.min(obj1.x, obj2.x), Math.min(obj1.y, obj2.y)); } - + /** * Return a vector will the absolute values of each element * @return New vector containing the value @@ -67,22 +68,22 @@ public record Vector2i( public Vector2i absolute() { return new Vector2i(Math.abs(this.x), Math.abs(this.y)); } - + @CheckReturnValue public Vector2i add(final int val) { return new Vector2i(this.x + val, this.y + val); } - + @CheckReturnValue public Vector2i add(final Vector2i obj) { return new Vector2i(this.x + obj.x, this.y + obj.y); } - + @CheckReturnValue public Vector2i add(final int xxx, final int yyy) { return new Vector2i(this.x + xxx, this.y + yyy); } - + /** * Return the axis with the largest ABSOLUTE value * @return values 0,1 for x or y @@ -91,7 +92,7 @@ public record Vector2i( public int closestAxis() { return absolute().maxAxis(); } - + /** * Return the cross product / determinant * @param obj The other vector in the cross product @@ -101,7 +102,7 @@ public record Vector2i( public int cross(final Vector2i obj) { return this.x * obj.y - this.y * obj.x; } - + /** * Decrementation of this vector (-1 of 2 elements) */ @@ -109,17 +110,17 @@ public record Vector2i( public Vector2i decrement() { return new Vector2i(this.x - 1, this.y - 1); } - + @CheckReturnValue public Vector2i devide(final int val) { return new Vector2i(this.x / val, this.y / val); } - + @CheckReturnValue public Vector2i devide(final Vector2i obj) { return new Vector2i(this.x / obj.x, this.y / obj.y); } - + /** * Return the distance between the ends of this and another vector This * is symantically treating the vector like a point @@ -130,7 +131,7 @@ public record Vector2i( public int distance(final Vector2i obj) { return (int) Math.sqrt(distance2(obj)); } - + /** * Return the distance squared between the ends of this and another * vector This is symantically treating the vector like a point @@ -143,7 +144,7 @@ public record Vector2i( final int deltaY = obj.y - this.y; return deltaX * deltaX + deltaY * deltaY; } - + /** * Return the dot product * @param obj The other vector in the dot product @@ -153,7 +154,7 @@ public record Vector2i( public int dot(final Vector2i obj) { return this.x * obj.x + this.y * obj.y; } - + /** * Return the axis with the smallest ABSOLUTE value * @return values 0,1 for x, or z @@ -162,7 +163,7 @@ public record Vector2i( public int furthestAxis() { return absolute().minAxis(); } - + /** * Incrementation of this vector (+1 of 2 elements) */ @@ -170,7 +171,7 @@ public record Vector2i( public Vector2i increment() { return new Vector2i(this.x + 1, this.y + 1); } - + /** * In-Equality compare operator with an other object. * @param obj Reference on the comparing object @@ -181,7 +182,7 @@ public record Vector2i( public boolean isDifferent(final Vector2i obj) { return (obj.x != this.x || obj.y != this.y); } - + /** * Equality compare operator with an other object. * @param obj Reference on the comparing object @@ -192,27 +193,27 @@ public record Vector2i( public boolean isEqual(final Vector2i obj) { return (obj.x == this.x && obj.y == this.y); } - + @CheckReturnValue public boolean isGreater(final Vector2i obj) { return (this.x > obj.x && this.y > obj.y); } - + @CheckReturnValue public boolean isGreaterOrEqual(final Vector2i obj) { return (this.x >= obj.x && this.y >= obj.y); } - + @CheckReturnValue public boolean isLower(final Vector2i obj) { return (this.x < obj.x && this.y < obj.y); } - + @CheckReturnValue public boolean isLowerOrEqual(final Vector2i obj) { return (this.x <= obj.x && this.y <= obj.y); } - + /** * Check if the vector is equal to (0,0) * @return true The value is equal to (0,0) @@ -222,7 +223,7 @@ public record Vector2i( public boolean isZero() { return this.x == 0 && this.y == 0; } - + /** * Get the length of the vector * @return Length value @@ -231,7 +232,7 @@ public record Vector2i( public int length() { return (int) Math.sqrt(length2()); } - + /** * Get the length of the vector squared * @return Squared length value. @@ -240,22 +241,22 @@ public record Vector2i( public int length2() { return dot(this); } - + @CheckReturnValue public Vector2i less(final int val) { return new Vector2i(this.x - val, this.y - val); } - + @CheckReturnValue public Vector2i less(final int xxx, final int yyy) { return new Vector2i(this.x - xxx, this.y - yyy); } - + @CheckReturnValue public Vector2i less(final Vector2i obj) { return new Vector2i(this.x - obj.x, this.y - obj.y); } - + /** * Return the axis with the largest value * @return values are 0,1 for x or y @@ -264,7 +265,7 @@ public record Vector2i( public int maxAxis() { return this.x < this.y ? 1 : 0; } - + /** * Return the axis with the smallest value * @return values are 0,1 for x or y @@ -273,17 +274,17 @@ public record Vector2i( public int minAxis() { return this.x < this.y ? 0 : 1; } - + @CheckReturnValue public Vector2i multiply(final int val) { return new Vector2i(this.x * val, this.y * val); } - + @CheckReturnValue public Vector2i multiply(final Vector2i obj) { return new Vector2i(this.x * obj.x, this.y * obj.y); } - + /** * Normalize this vector x^2 + y^2 = 1 * @return New vector containing the value @@ -292,7 +293,7 @@ public record Vector2i( public Vector2i normalize() { return this.devide(length()); } - + /** * Normalize this vector x^2 + y^2 = 1 (check if not deviding by 0, if it * is the case ==> return (1,0)) @@ -306,17 +307,17 @@ public record Vector2i( } return new Vector2i(1, 0); }; - + @CheckReturnValue public Vector2i max(final int xxx, final int yyy) { return new Vector2i(Math.max(this.x, xxx), Math.max(this.y, yyy)); } - + @CheckReturnValue public Vector2i min(final int xxx, final int yyy) { return new Vector2i(Math.min(this.x, xxx), Math.min(this.y, yyy)); } - + /** * Set 0 value on all the vector */ @@ -332,17 +333,17 @@ public record Vector2i( public static final Vector2i VALUE_256 = new Vector2i(256, 256); public static final Vector2i VALUE_512 = new Vector2i(512, 512); public static final Vector2i VALUE_1024 = new Vector2i(1024, 1024); - + @Override public String toString() { return "Vector2i(" + this.x + "," + this.y + ")"; } - + @CheckReturnValue public Vector2i withX(final int xxx) { return new Vector2i(xxx, this.y); } - + @CheckReturnValue public Vector2i withY(final int yyy) { return new Vector2i(this.x, yyy);