Missing max function for Point

For layout purposes, it is inevitable to merge the minimum extents of components, so they work with all modes of Grid and FlexBox. I am missing a bool Point::max (const Point& other) function or an overload to jmax for Point.

It is totally a no brainer, so maybe someone could add it to the code base?

namespace juce
{
    /** Returns a Point with the larger of two coordinates of two points. */
    template <typename Type>
    JUCE_CONSTEXPR Point<Type> jmax (Point<Type> a, Point<Type> b) { return { jmax (a.x,b.x), jmax (a.y,b.y) }; }
    
     /** Returns a Point with the smaller of two coordinates of two points. */
    template <typename Type>
    JUCE_CONSTEXPR Point<Type> jmin (Point<Type> a, Point<Type> b) { return { jmin (a.x,b.x), jmin (a.y,b.y) }; }
}

The above code does seem to do the trick.

Two remarks:

  • I would advice against putting your own stuff into the juce namespace, it is perfectly fine to put it into your own namespace
  • I think the maximum of two points is ambiguous, hence I would not use jmax here
    • it could refer to max for each component (like you did)
    • it could refer to the one with the longest euclidean distance from the origin
    • or some other definition I missed…

But if you need that for your use case, it is perfectly fine to have that in your code base

3 Likes

Though it’s probably better to use another name. Suppose you do use the jmax name and afterwards this symbol is also added to JUCE with different semantics…

Oh, I’m even putting my own stuff in the std namespace :wink: Isn’t that how template specialisation works?

But I see how the “merged area” semantics of my case might not be obvious. Although a vector comparison sematics would certainly be a completely different thing. IMHO, max should not consider anything but x and y to be trivial enough to justify using the same name.

In the end it’s a matter of definition.

SIMD and shader languages, all have min max for Vectors.

I think conceptually a Point is something different of a vector.
And a max of a vector would be the max of all it’s components, so it is even different from the max of two points.

A Point is not a vector hey? Interesting. :slight_smile:
The OP wants a Point returning, just like in GLSL or HLSL, or SIMD.

a vector is a n-tuple of values.
A point in a n-dimensional space can be represented by a n-tuple, speak vector.
Mathematically this is a vector attached to the origin.
A point has a location, a vector doesn’t.

std::vector<float> v { 1, 2, 3 };
auto max = *std::max_element (v.begin(), v.end());

I understood the question as the OP wants to get a point, where each dimension is the maximum (kind of the enclosing rectangular space if you wish).

In this field of ambiguous terms it pays off to be precise.

Oh you’re thinking in terms of C++ std::vector.

I think in both terms… std::vector is the same concept: a tuple of values, that can adjust it’s dimension.
Mathematically it is the same. A point is not a vector. A point as location in euclidean space can be represented by a vector attached to the origin. But still, what would the max version of two points return? just like in GLSL or HLSL, or SIMD.

1 Like

A point is a vector in the graphics world.
In SIMD and Shader languages, it returns the max of each one individually. That’s all they were asking for.

I leave it here, since obviously the way computer graphics were taught at my university are different from your understanding.

I don’t believe that there is an unambiguous definition of a max of two pointers, but ultimately, this is not my say, not my API, so others will decide if they follow your argument.

I agree with @daniel here; what does it mean to have a max between two points, and how should that be done? There are different possibilities for what that would look like and it would be ambiguous to figure out which one using a function name like jmax and jmin. Do you compare the x or the y from a Point in min/max functions? How do you know which component should be used to compare, and how do you know when to choose?

To refer back to to GLSL: you have this set of functions to pick from for finding a maximum. It’s really ambiguous what the vecN overloads might do.

float max(float x, float y);
vec2 max(vec2 x, float y); //Which would be a Point in juce terms.
vec3 max(vec3 x, float y); //Which would be a Vector3D in juce terms.
vec4 max(vec4 x, float y);
vec2 max(vec2 x, vec2 y);
vec3 max(vec3 x, vec3 y);
vec4 max(vec4 x, vec4 y);

Ok, in GLSL:

    vec2 v1  =vec2(0.2, 1.0);
    vec2 v2  =vec2(1,  0.2);
    v1 = max(v1, v2);

Would result in v1 = (1.0, 1.0)
Similarly with

	SIMDRegister<double>v1 = SIMDRegister<double>::fromNative({0.2, 1.0});
	SIMDRegister<double>v2 = SIMDRegister<double>::fromNative({1.0, 0.2});
	v1 = SIMDRegister<double>::max(v1,v2);

If you just supply a single float in one of them, it will just convert it to a vec2 before doing the max.
So

    vec2 v1  =vec2(.5, 1.0);
    float a = 1.;
    v1 = max(v1, a);

Would give the same result. 1.0,1.0

@ans just wants some simple functionality. We all use Juce as a tool, nothing more, an excellent one at that, but just a tool.

Nope, Daniel’s point (ahem) is the right one here.

It’s all about semantics. There’s no unambiguous meaning for “the maximum of two points” and we can’t go around adding confusing functions just because people request them!

I’d be highly suspicious of whether a max (Point, Point) function would ever be the appropriate name for such a thing anyway. The only use-case I can think of is would be if you’re finding the bounding rectangle of two points, but for that we already have things like Rectangle::findAreaContainingPoints(), or the Rectangle constructor which takes two corners.

Oh well, it was’t me that wanted it, I use my own. :slightly_smiling_face:

I agree that ‘max’ may not be the appropriate name here. Something along the lines of ‘merge’ would be a better match.

There are countless cases where the notion of ‘extent’ (size) is extremely helpful. Juce Rectangles using a point for origin, but separate width and height for extent is making things more complicated than necessary. A high number of occurrences of x, y, w, h in the code are a sure sign that something is not normalized. Once those are collapsed into points (or however you name them), code size will shrink, be less verbose and more mathematically sound. It will magically make many things nicely fall into line.

Where coordinates must be passed individually, arguments can be aggregated as {x,y} or {w,h}. So why bother with passing their parts along separately across the entire API?

I see how a fundamental change like this is a no go this late in the development of an established library. I can live with that. Still, I’m often finding myself writing a lot of unnecessary code when porting simple single-line return statements from other languages.

Oh, I completely agree that we should have a Size class - I should have added one 10 years ago! And of course a max (Size, Size) would make a lot more sense than a max (Point, Point)

But the fix for not having a Size class is not to add confusing methods to Point just because you can sort of use a Point instead of a Size because it’s kind of got the same members in it…!