# [Committed] New Feature: Measurement Tools

This is something that, while useful now, will be infinitely more useful once we start talking about scene editors and the such.

Includes the ability to set the general scale of all the included units as well as converting between all of them.  If one artist sets their working units to centimeters when everyone else is working in inches, this will bring some relief in translating the objects

For now, it should be helpful in wrangling assets and being able to relate "meters to meters" rather than trying to think in "meters in terms of Vector3f"

Currently implemented units of measure:

• Millimeter

• Centimeter

• Decimeter

• Meter

• Kilometer

• Inch

• Foot

• Yard

• Mile

• Nautical Mile

Here's abstract class of a unit of Length:

``` package com.jme.scene.measure; /**  * <p><code>LengthUnit</code> forms the base class for implementing  * scaled measure in a jME scenegraph.</p>  *  * <p><code>LengthUnit</code> can be used in the instantiation  * of a <code>Vector3f</code> as such:<p>  * <code>  * Vector3f myScaledVector = new Vector3f(<br>  *                                 new Foot(2).convertToFloat(),<br>  *                                 new Foot(1).convertToFloat(),<br>  *                                 new Inch(3).convertToFloat());<br>  * </code>  * @author <a href="mailto:skye.book@gmail.com">Skye Book  *  */ abstract public class LengthUnit {    public enum Units{       MILLIMETER, DECIMETER, CENTIMETER, METER, KILOMETER,       INCH, FOOT, YARD, MILE, NAUTICAL_MILE    }        protected float numberOfUnits;        /**     * <code>metersPerFoot</code> is the general multiplier for     * the scale of the unit system.  The default is 1 meter for     * each whole number.     */    protected float metersPerFloat = 1;    /**     * Constructor creates a <code>LengthUnit</code> of a specified length     * and unit, allowing you to convert easily between popular measures of     * distance.     */    public LengthUnit(float length) {       this.numberOfUnits = length;    }        /**     * Converts the current <code>LengthUnit</code> into another form.     * (e.g: Meters -> Feet)     * @param targetUnit The measurement being converted into     * @return The LengthUnit created in the form of the targetUnit     */    public abstract LengthUnit convert(Units targetUnit);        /**     * Converts a LengthUnit into a float that is useful in defining     * spaces in the scenegraph.     * @return A scaled float which can be used to construct     * a <code>Vector3f</code>.     */    public abstract float convertToFloat();    /**     * @return the metersPerFloat     */    public float getMetersPerFloat() {       return metersPerFloat;    }    /**     * Sets the general scale in terms of what is actually contained     * in a Vector3f.  For example, setting this to 5 would mean that     * 15 meters in all directions could be reproduced with     * <code>Vector3f(3,3,3)</code>     *     * @param metersPerFloat The general multiplier for     * the scale of the unit system.  The default is 1 meter for     * each whole number.     */    public void setMetersPerFloat(float metersPerFloat) {       this.metersPerFloat = metersPerFloat;    }    public float getNumberOfUnits() {       return numberOfUnits;    }    public void setNumberOfUnits(float numberOfUnits) {       this.numberOfUnits = numberOfUnits;    } } ```

And an example of one of the units of measure (they're all the same, just the calculations change... one should suffice)

``` package com.jme.scene.measure; /**  * @author <a href="mailto:skye.book@gmail.com">Skye Book  *  */ public class Meter extends LengthUnit {    /**     * Constructor creates a specified number of Meters,     * allowing you to convert easily between popular measures of     * distance.     *     *@param length The number of meters.     */    public Meter(float length) {       super(length);       // TODO Auto-generated constructor stub    }    /* (non-Javadoc)     * @see com.jme.scene.measure.LengthUnit#convert(com.jme.scene.measure.LengthUnit.Units)     */    @Override    public LengthUnit convert(Units targetUnit) {       if(targetUnit.equals(Units.MILLIMETER))       {          return new Millimeter(numberOfUnits*1000f);       }       else if(targetUnit.equals(Units.CENTIMETER))       {          return new Centimeter(numberOfUnits*100f);       }       else if(targetUnit.equals(Units.DECIMETER))       {          return new Decimeter(numberOfUnits*10f);       }       else if(targetUnit.equals(Units.METER))       {          return this;       }       else if(targetUnit.equals(Units.KILOMETER))       {          return new Kilometer(numberOfUnits*0.001f);       }       else if(targetUnit.equals(Units.INCH))       {          return new Inch(numberOfUnits*39.3700787f);       }       else if(targetUnit.equals(Units.FOOT))       {          return new Foot(numberOfUnits*3.2808399f);       }       else if(targetUnit.equals(Units.YARD))       {          return new Yard(numberOfUnits*1.0936133f);       }       else if(targetUnit.equals(Units.MILE))       {          return new Mile(numberOfUnits*0.000621371192f);       }       else if(targetUnit.equals(Units.NAUTICAL_MILE))       {          return new NauticalMile(numberOfUnits*0.000539956803f);       }       else          return null;    }    /* (non-Javadoc)     * @see com.jme.scene.measure.LengthUnit#convertToFloat()     */    @Override    public float convertToFloat() {       return numberOfUnits*metersPerFloat;    } } ```

That would be a very nice to have feature

Will you integrate this into core?

And could you implement maybe converting whole Vector3fs at once?

so you have sth like this:

`Vector3f inchVector = Meter.convertToInch(new Vector3f(0,10,5)).convertToVector3f();`

?
tim8dev said:
And could you implement maybe converting whole Vector3fs at once?

so you have sth like this:

`Vector3f inchVector = Meter.convertToInch(new Vector3f(0,10,5)).convertToVector3f();`

?

:-o most certainly, definitely makes a lot of sense to have that

shocked most certainly, definitely makes a lot of sense to have that

In fact, that would be how i would use it :D (If i use it at all, cause we always use meter...)

Alright, here it is:

``` /**  * Copyright 2008-2009 Brooklyn eXperimental Media Center  * Betaville Project by Brooklyn eXperimental Media Center at NYU-Poly  * http://bxmc.poly.edu  */ package com.jme.scene.measure; import com.jme.math.Vector3f; /**  * <p><code>LengthUnit</code> forms the base class for implementing  * scaled measure in a jME scenegraph.</p>  *  * <p><code>LengthUnit</code> can be used in the instantiation  * of a <code>Vector3f</code> as such:<p>  * <code>  * Vector3f myScaledVector = new Vector3f(<br>  *                                 new Foot(2).convertToFloat(),<br>  *                                 new Foot(1).convertToFloat(),<br>  *                                 new Inch(3).convertToFloat());<br>  * </code>  * @author <a href="mailto:skye.book@gmail.com">Skye Book  *  */ abstract public class LengthUnit {    public enum Units{       MILLIMETER, DECIMETER, CENTIMETER, METER, KILOMETER,       INCH, FOOT, YARD, MILE, NAUTICAL_MILE    }        protected float numberOfUnits;        /**     * <code>metersPerFoot</code> is the general multiplier for     * the scale of the unit system.  The default is 1 meter for     * each whole number.     */    protected float metersPerFloat = 1;    /**     * Constructor creates a <code>LengthUnit</code> of a specified length     * and unit, allowing you to convert easily between popular measures of     * distance.     */    public LengthUnit(float length) {       this.numberOfUnits = length;    }        /**     * Converts the current <code>LengthUnit</code> into another form.     * (e.g: Meters -> Feet)     * @param targetUnit The measurement being converted into     * @return The LengthUnit created in the form of the targetUnit     */    public abstract LengthUnit convert(Units targetUnit);        /**     *     * @param vectorToConvert A <code>Vector3f</code> to be scaled to     * another unit of measure.     * @param startUnit The unit being converted from.     * @param targetUnit The unit being converted to.     * @return A Vector3f with values in the converted unit of measure.     */    public static Vector3f convertVectorUnits(Vector3f vectorToConvert, Units startUnit, Units targetUnit)    {       /* instantiate blank units.  All enumeration values are        * present here, so there's no reason why you should        * get a converted Inch of length 0 returned..        */       LengthUnit xUnit = new Inch(0);       LengthUnit yUnit = new Inch(0);       LengthUnit zUnit = new Inch(0);       if(startUnit.equals(Units.MILLIMETER))       {          xUnit = new Millimeter(vectorToConvert.x);          yUnit = new Millimeter(vectorToConvert.y);          zUnit = new Millimeter(vectorToConvert.z);       }       else if(startUnit.equals(Units.CENTIMETER))       {          xUnit = new Centimeter(vectorToConvert.x);          yUnit = new Centimeter(vectorToConvert.y);          zUnit = new Centimeter(vectorToConvert.z);       }       else if(startUnit.equals(Units.DECIMETER))       {          xUnit = new Decimeter(vectorToConvert.x);          yUnit = new Decimeter(vectorToConvert.y);          zUnit = new Decimeter(vectorToConvert.z);       }       else if(startUnit.equals(Units.METER))       {          xUnit = new Meter(vectorToConvert.x);          yUnit = new Meter(vectorToConvert.y);          zUnit = new Meter(vectorToConvert.z);       }       else if(startUnit.equals(Units.KILOMETER))       {          xUnit = new Kilometer(vectorToConvert.x);          yUnit = new Kilometer(vectorToConvert.y);          zUnit = new Kilometer(vectorToConvert.z);       }       else if(startUnit.equals(Units.INCH))       {          xUnit = new Inch(vectorToConvert.x);          yUnit = new Inch(vectorToConvert.y);          zUnit = new Inch(vectorToConvert.z);       }       else if(startUnit.equals(Units.FOOT))       {          xUnit = new Foot(vectorToConvert.x);          yUnit = new Foot(vectorToConvert.y);          zUnit = new Foot(vectorToConvert.z);       }       else if(startUnit.equals(Units.YARD))       {          xUnit = new Yard(vectorToConvert.x);          yUnit = new Yard(vectorToConvert.y);          zUnit = new Yard(vectorToConvert.z);       }       else if(startUnit.equals(Units.MILE))       {          xUnit = new Mile(vectorToConvert.x);          yUnit = new Mile(vectorToConvert.y);          zUnit = new Mile(vectorToConvert.z);       }       else if(startUnit.equals(Units.NAUTICAL_MILE))       {          xUnit = new NauticalMile(vectorToConvert.x);          yUnit = new NauticalMile(vectorToConvert.y);          zUnit = new NauticalMile(vectorToConvert.z);       }       else          return vectorToConvert;              return new Vector3f(xUnit.convert(targetUnit).convertToFloat(),                      yUnit.convert(targetUnit).convertToFloat(),                      zUnit.convert(targetUnit).convertToFloat());    }        /**     * Converts a LengthUnit into a float that is useful in defining     * spaces in the scenegraph.     * @return A scaled float which can be used to construct     * a <code>Vector3f</code>.     */    public abstract float convertToFloat();    /**     * @return the metersPerFloat     */    public float getMetersPerFloat() {       return metersPerFloat;    }    /**     * Sets the general scale in terms of what is actually contained     * in a Vector3f.  For example, setting this to 5 would mean that     * 15 meters in all directions could be reproduced with     * <code>Vector3f(3,3,3)</code>     *     * @param metersPerFloat The general multiplier for     * the scale of the unit system.  The default is 1 meter for     * each whole number.     */    public void setMetersPerFloat(float metersPerFloat) {       this.metersPerFloat = metersPerFloat;    }    public float getNumberOfUnits() {       return numberOfUnits;    }    public void setNumberOfUnits(float numberOfUnits) {       this.numberOfUnits = numberOfUnits;    } } ```

You could make code easier if you have a "standard" LenghtUnit, e.g. Meter.

Than each implementing class have a static constant

`public static double toMeter`

For each convertion you then first convert to Meter (the standard unit), than from Meter to the Unit you want.

What do you think?

It's better extendible I think.

tim8dev said:

For each convertion you then first convert to Meter (the standard unit), than from Meter to the Unit you want.
:D

What do you think?

It's better extendible I think.

The problem with this is that we're doubling the number of calculations needed to convert a unit of measure..  As far as "better" extendible, your method does make it slightly simpler to create new measure types, though it's adding work for the JVM to process.  I'm not so sure that formulating a few extra multipliers when writing the code isn't worth the small time investment when it comes to performance later on ;)
The problem with this is that we're doubling the number of calculations needed to convert a unit of measure..  As far as "better" extendible, your method does make it slightly simpler to create new measure types, though it's adding work for the JVM to process.  I'm not so sure that formulating a few extra multipliers when writing the code isn't worth the small time investment when it comes to performance later on Wink

That mustn't be true, because it will get rid of all the checks :D

All it requires is one float multiplikation, but will save about ~12/2 = 6 checks..

It's almost the same :D

You'd still need to check for which unit you want to convert to, so which checks would be eliminated?  (Now you've got me curious about how much those checks slow it down lol)

Every unit class have a constant toMeter and fromMeter.

Than the code is

```LengthUnit convert( LenghtUnit toUnit ) {     return toUnit.new( numerOfUnits * toMeter * toUnit.fromMeter ); } ```

or something similar.

Now clear enough?

BTW: the checks need no (or at least close to null) computation time.
But one double operation needs 1 CPU-Cycle, so it's close to null, too.

Ok, I see what you're saying.  I'm gonna stick with this for now due to the reduced amount of cycles it takes (no matter how close to null it is ;))

I think, my version is more elegant

But it doesn't really matter, because I don't see any needs for extending it. ( all well known lengthUnit are supported, aren't they? )

Maybe, if you want to create your own LenghtUnit (y should u?) you want to extend it

Well, you could extend it the other way round

So you have not only LengthUnit but other physicalUnits supportedā¦

If I had time, I would like to do thisā¦

but currently i'm messed up with cell-and-portal

tim8dev said:

If I had time, I would like to do this..
but currently i'm messed up with cell-and-portal

another topic i'm watching with some interest :D
Quote from: tim8dev on Today at 05:35:03 pm
If I had time, I would like to do this..
but currently i'm messed up with cell-and-portal

another topic i'm watching with some interest Cheesy

Haha, nice to know that!

Well.. my frustum culling worked :D (well, i thought it works, cause in my test-scene everything worked fine ;))
But then I wrote a JUnit TestCase....

And discover one bug after the other.. so that I have to re-structure my code a bit..
everything takes it time  :'(

So, since I've more or less paused my cell-and-portal implementation, because I want to wait till the SceneManager's from Ogli comes out

I've implemented the LengthUnit's in "my Way":

The result's:

New classes can be made damn fast!

But performance is about 2 times better with the "old" implementation:

( The problem is not in multiplying twice but it's in the cloneing of the instances )

// The test first generates 10 million NauticalMile's and then convert them twice (through the old and new Way) to Foot

```Iterations: 10000000 Test results: (all times in millies) Time used for Generation: 2117 Time used for Converting(newWay): 1700 Time used for Converting(oldWay): 960 ```

So if anyone interested in an easy to use framework for building own unit's ( not only LengthUnit ) and can accept the worse performance, please just say a "yes, i want" :wink:

Of course the old method's for converting can still be used. (But it will throw an UnsupportedOperationException if you try to convert to or from a "new" LengthUnit like LightYear or AstronomicalUnit)

As I don't have committing rights, I still have to wait for getting more attention from the committersā¦

So:

New classes:

TimeUnit(s): Second, Minute, Hour

LengthUnit(s): AstronomicalUnit, LightYear

Velocity: MetersPerSecond, Knots, KilometersPerHour

new Method's for converting from and converting locally (speed gain, even faster than the old way of converting ;))

Still nobody interested?