Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a signed distance function to RectT #1015

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

notlion
Copy link
Contributor

@notlion notlion commented Jul 7, 2015

Sometimes it's useful to know how far a point lies inside a rectangle. Alternatively, I'd like to replace the plain distance function. It currently returns 0 for points inside which could be achieved just by max(x,0)'ing the signed version. Although, I can understand this might be unexpected for people used to the current behavior.

A 3d version should probably be added to AxisAlignedBox. Happy to do that as well.

Demo Sketch:

#include "cinder/app/App.h"
#include "cinder/app/RendererGl.h"
#include "cinder/gl/gl.h"
#include "cinder/Vector.h"

using namespace ci;
using namespace ci::app;
using namespace std;

class TestRectSignedDistApp : public App {
public:
  void draw() override;
};

void TestRectSignedDistApp::draw() {
  gl::clear(Color(0, 0, 0));

  float t = getElapsedSeconds();
  float s = glm::length(vec2(getWindowSize())) / 4.0f;
  Rectf rect = { glm::rotate(vec2(s, 0), t * 0.8234f),
                 glm::rotate(vec2(0, s * 0.75f), t * 0.3345f) };
  rect.offset(getWindowCenter());
  rect.canonicalize();

  vec2 p = getMousePos() - getWindowPos();
  auto d = rect.distance(p);
  auto sd = rect.distanceSigned(p);

  gl::color(1, 1, 1);
  gl::drawStrokedRect(rect);

  gl::color(0, 1, 1);
  gl::drawStrokedCircle(p, glm::abs(sd), 64);
  gl::drawString("sd: " + std::to_string(sd), p + vec2(0, 40));

  gl::color(1, 0, 0);
  gl::drawStrokedCircle(p, d, 64);
  gl::drawString("d: " + std::to_string(d), p + vec2(0, 20));
}

CINDER_APP(TestRectSignedDistApp, RendererGl)

@notlion
Copy link
Contributor Author

notlion commented Jul 7, 2015

In my benchmarks on x86_64/release distanceSigned is pretty comparable speed wise, taking about 0.9 to 1.1 times as long as distance. It's slightly slower for points outside of the rectangle and slightly faster for points inside. Bench sketch is here.

@richardeakin
Copy link
Collaborator

It does indeed seem useful to know the distance of a point to the closest edge of a Rect. To open a discussion about what api choice is best, I'm trying to think how you'd use this in practice - would you check for the result being negative, then branch and negate the returned distance?

One thing that comes to mind is that when evaluating the return of RectT::distance(), checking == 0 isn't very good, seems > 0 gives more of an indication that the point is outside (if Ryan's proposed changes were to happen).

Looking at the impls, both seem to be doing about the same math, most importantly they both use a sqrt.

@notlion
Copy link
Contributor Author

notlion commented Jul 8, 2015

To get the unsigned distance to the closest edge you'd simply do a glm::abs(rect.distanceSigned(pt)).

My current use case is the implementation of Starcraft-style edge panning where the camera moves when the user moves the mouse close to the edge of the view. In this case, it's useful to know the signed distance for detecting when the cursor is close, as well as how much to move the camera. You want signed distance here, not just unsigned distance to edge, because it allows dragging beyond the edge to work seamlessly, as well as the ability to offset the rectangle in either direction (distance wise).

@notlion
Copy link
Contributor Author

notlion commented Jul 8, 2015

Also I agree that distance > 0 is a better indicator that the point lies outside.

@richardeakin
Copy link
Collaborator

I suppose the current use case for distance returning 0 for inside is when you are using it as a scalar, in which case 0 would mean no scaling. This would break any apps that relied on that, whereas they would be scaling by a negative number if distance() returned signed distance. Again, just discussing the pros and cons. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants