RPTools / maptool

Virtual Tabletop for playing roleplaying games with remote players or face to face.
http://rptools.net
GNU Affero General Public License v3.0
782 stars 259 forks source link

[Refactoring]: We need (I want) a Vector class #4866

Open bubblobill opened 1 month ago

bubblobill commented 1 month ago

Describe the problem

Disambiguation: Vectors = Magnitude And Direction

  1. Funky stuff can often be easier using vectors and vector maths.
  2. Java does not have native vectors outside the experimental stage.
  3. The libraries we have contain a couple of vector classes but they tend to be a bit naff. 3.1 We already use AWT's Point2D a fair bit, but it does not extend well to encompass integers and is hardly fully featured for operations. 3.2 JavaFX has Point2D/3D which are well featured but has annoying final fields and functions that cannot be overridden, as well as some basic missing features like setX/Y().
  4. We are still working with integer points a lot of the time based on AbstractPoint which don't scale well due to integer maths.

The improvement you'd like to see

Make AbstractPoint an extension of a new class AbstractVector. AbstractVector can be defined using generic types (I believe) to make it easier to deal with extracting the numeric type you want without having to convert stuff between Int/Float/Double/BigDecimal.

Expected Benefits

One point to rule them all. No longer have to accommodate fiddly bits to shoehorn existing classes or create repetitious classes to do with complex operations. Can be exposed to macro functions to perform vector maths. More accurate conversions to output integer points

Additional Context

I've written (stolen) one, and am looking at getting it to work. Hoping other people will chime in and tell me if I am wasting my time or make comment on what it should and shouldn't be.

cwisniew commented 1 month ago

org.locationtech.jts.math.Vector2D is already available in one of the libraries in use by MapTool.

bubblobill commented 1 month ago

org.locationtech.jts.math.Vector2D is already available in one of the libraries in use by MapTool.

I checked it out and it mostly has what I want but still has some irritating foibles. Unsurprisingly it is well plumbed into the jts ecosystem which comes with things both useful and superfluous. I'm inclined to use it as a delegate and tack on the other bits I want. Still requires me creating a new class though, not sure if it will be more or less work.

cwisniew commented 1 month ago

org.locationtech.jts.math.Vector2D is already available in one of the libraries in use by MapTool.

I checked it out and it mostly has what I want but still has some irritating foibles. Unsurprisingly it is well plumbed into the jts ecosystem which comes with things both useful and superfluous. I'm inclined to use it as a delegate and tack on the other bits I want. Still requires me creating a new class though, not sure if it will be more or less work.

Looking at the class it seems pretty complete, what is it missing that you wanted?

bubblobill commented 1 month ago

It's designed for doing GIS stuff, so it overdoes some things and misses some graphical operations that are inappropriate for its target purpose. Examples:

Getting things into and out of it is painful. It doesn't deal directly with Point, Point2D, or Point3D. Seems to require a different transform class, generator, or builder in order to talk to half the types we use. jts uses it's own point class "coordinate" which is a geo-something point 3D with an extra dimension which again is overkill for most simple operations and I had to dig deep to find IdentityPointTransformation.transfom(Coordinate, Point2d) which only goes one way.

Personal beefs with this and other vector classes:

That's why I'm thinking delegate. That way I can write the annoying stuff once to make it transparent, and I can staple on any other neat bits as and when they become useful.

cwisniew commented 1 month ago

It's designed for doing GIS stuff, so it overdoes some things and misses some graphical operations that are inappropriate for its target purpose. Examples:

  • "interpolate" is for points along a path which is a bit heavy handed when you want distance along a line.
  • Has no homography (that I could find). The one truly complex operation I want is nowhere to be found.
  • Don't see any gains in the precision of a custom DoubleDouble number type either.

Getting things into and out of it is painful. It doesn't deal directly with Point, Point2D, or Point3D. Seems to require a different transform class, generator, or builder in order to talk to half the types we use. jts uses it's own point class "coordinate" which is a geo-something point 3D with an extra dimension which again is overkill for most simple operations and I had to dig deep to find IdentityPointTransformation.transfom(Coordinate, Point2d) which only goes one way.

Personal beefs with this and other vector classes:

  • it has no setX/Y()
  • Coordinate is comparable (strangely, only in 2 dimensions) but its vectors are not.
  • Vector2D and 3D are either; not interchangeable, or provide no conversion methods. Before you point out they shouldn't be: A 2D vector is the same as a 3D vector with z=0

Ok, what should I do before I point out that is not strictly correct :)

Also, what is the cross product of two 2D vectors? An incovenient vector perpendicular to both axes, i.e 3D.

There is a certain Nathan Fillion GIF I want to insert :) By definition, you can't do a cross-product of 2D vectors

But I digress... What did you need the vector class for / to do? Then we can see if we can find anything useful or, if not, write one.

bubblobill commented 1 month ago

There is a certain Nathan Fillion GIF I want to insert :) By definition, you can't do a cross-product of 2D vectors

I know, I know, but often working with 2D vectors is actually working in a 3D space and ignoring one axis until reality rudely intrudes and you have to go back to 3D.

But I digress... What did you need the vector class for / to do? Then we can see if we can find anything useful or, if not, write one.

I just wrote a nice long set of cogent examples until the GitHub app swallowed it all and did nothing. Hopefully I remember the salient points.

Two distinct use cases.

  1. For use in MT Script through the creation of vector/geometry functions. This is my first reason for wanting vector functionality. I had to write my own vector library token for a bunch of vector calculation UDFs. As you can imagine, it wasn't too quick. (There's probably a feature request for it buried in the forum somewhere.)
  2. For use in MT. Mostly for simple stuff manipulating points (This is the bit you care about and for which I am disatisfied with losing).
    1. I remember a bunch of times when working on grid rendering and halos that there was stuff that would have been easier using vectors.
    2. Areas, e.g. footprints, templates, etc. Sometimes areas would be more easily stored as either a) a collection of relative vectors, or b) a vector function.
    3. Graphics - particularly non-affine transforms, e.g. perspective(keystone) deformation, pincushion, blah blah.
    4. Simple things like
      1. no need for writing convenience methods like GraphicsUtil.getPointAtVector, and GraphicsUtil.getProjectedPoint.
      2. mouse events. p1 = dragStart, p2 = dragStop, p3 = p2.subtract(p1).
      3. scaling. newMapOrigin = originPoint.multiply(p3.length()), or
      4. translate. newGridOffset = p3.