Calculate distance from point to (closest point of) shape


#1

Hi everyone!
Please help me to solve this thing. How to calculate distance from point to (closest point of) shape/curve/type?


#2

if you use PVector ( and vertext for draw )
and calc all in absolut coordinates ( never use translate rotate shear scale )
it is easy.

// https://discourse.processing.org/t/calculate-distance-from-point-to-closest-point-of-shape/7201
// Calculate distance from point to (closest point of) shape 


// -1- make a ellipse by a PVector array
// -2- draw it by vertex
// -3- move it by PVector ( not translate....)
// -4- make mouse PVector
// -5- calc min distance between mouse and obj PVector array
// -6- draw obj and line ( obj(nearest) , mouse )


int steps = 360;
PVector[] myobj = new PVector[steps];
float ang,my_ra = 100, my_rb = 50;
PVector mouse = new PVector(0,0);
int nearest = 0;

void make_obj(float posX, float posY) {
  for (int i =0;i<steps;i++) {
    ang = TWO_PI*i/float(steps);
    myobj[i]= new PVector(
    my_ra * sin(ang),
    my_rb * cos(ang)
    );
  }
  // move it
  PVector moveto = new PVector(posX,posY);
  for (int i =0;i<steps;i++) {
    myobj[i] = myobj[i].add(moveto);
  }
}

int calc_min_mouse_dist() {
  int minpos = -1;
  float mind = 10000;
  
  for (int i =0;i<steps;i++) {
    float d = myobj[i].dist(mouse);
    if ( d < mind ) { 
      mind = d;
      minpos = i;
    }
  }
  return minpos;
}

void draw_obj() {
  beginShape();
  stroke(0,200,0);
  strokeWeight(3);
  fill(0,0,200);
  for (int i =0;i<steps;i++) {
    vertex(myobj[i].x,myobj[i].y);
  }
  endShape(CLOSE);
  
  // draw mouse
  stroke(200,0,0);
  line(myobj[nearest].x,myobj[nearest].y,mouse.x,mouse.y);
}

void setup() {
  size(300,300);
  make_obj(width/2,height/2);
}

void draw() {
  background(200,200,0);
  draw_obj();
}

void mouseMoved() {
  mouse.set(mouseX,mouseY);
  nearest = calc_min_mouse_dist();
}



update
// https://discourse.processing.org/t/calculate-distance-from-point-to-closest-point-of-shape/7201
// Calculate distance from point to (closest point of) shape 


// -1- make a ellipse by a PVector array
// -2- draw it by vertex
// -3- move it by PVector ( not translate....)
// -4- make mouse PVector
// -5- calc min distance between mouse and obj PVector array
// -6- draw obj 
// -7- and line ( obj(nearest) , mouse )
// -8- print distance near mouse pos
// -9- make obj fancy ( https://en.wikipedia.org/wiki/Lissajous_curve ?)

int steps = 360;
PVector[] myobj = new PVector[steps];
float mind, ang, my_ra = 100, my_rb = 50;
PVector mouse = new PVector(0, 0);
int nearest = 0;

void make_obj(float posX, float posY) {
  for (int i =0; i<steps; i++) {
    ang = TWO_PI*i/float(steps);
    myobj[i]= new PVector(
// original ellipse
//      my_ra * sin(ang), 
//      my_rb * cos(ang)
      my_ra * sin(ang)+my_rb * cos(ang*3)/5, 
      my_rb * cos(ang)+my_ra * sin(ang*7)/3
      );
  }
  // move it
  PVector moveto = new PVector(posX, posY);
  for (int i =0; i<steps; i++) {
    myobj[i] = myobj[i].add(moveto);
  }
}

int calc_min_mouse_dist() {
  int minpos = -1;
  mind = 10000;

  for (int i =0; i<steps; i++) {
    float d = myobj[i].dist(mouse);
    if ( d < mind ) { 
      mind = d;
      minpos = i;
    }
  }
  return minpos;
}

void draw_obj() {
  beginShape();
  stroke(0, 200, 0);
  strokeWeight(2);
  noFill();                               //fill(0,0,200);
  for (int i =0; i<steps; i++) vertex(myobj[i].x, myobj[i].y);
  endShape(CLOSE);

  // draw mouse
  stroke(200, 0, 0);
  line(myobj[nearest].x, myobj[nearest].y, mouse.x, mouse.y);
  fill(200, 0, 0);
  text(int(mind), mouse.x+10, mouse.y-10);   // ?? not work inside filled ellipse
}

void setup() {
  size(300, 300);
  make_obj(120, 200); //width/2,height/2);
}

void draw() {
  background(200, 200, 0);
  draw_obj();
}

void mouseMoved() {
  mouse.set(mouseX, mouseY);
  nearest = calc_min_mouse_dist();
}



#3

Thanks! Does this approach allow me to use something but vertex drawing? like type or .svg shapes?


#4

the idea was to have a long array of XYpoints
where the min distance check is easy math.

actually what you do with that points is up to you.

  • besides beginshape … vertext … endshape
  • can do line( x-1,y-1,x,y) // but not too long …

with your wording

type or .svg shapes

i have no big idea, but yes you can export to .svg file

rev10
// https://discourse.processing.org/t/calculate-distance-from-point-to-closest-point-of-shape/7201
// Calculate distance from point to (closest point of) shape 


// -1- make a ellipse by a PVector array
// -2- draw it by vertex
// -3- move it by PVector ( not translate....)
// -4- make mouse PVector
// -5- calc min distance between mouse and obj PVector array
// -6- draw obj 
// -7- and line ( obj(nearest) , mouse )
// -8- print distance near mouse pos
// -9- make obj fancy ( https://en.wikipedia.org/wiki/Lissajous_curve ?)
// -10- export to SVG use key [r]


import processing.svg.*;
boolean record;
String outfilename = "data/oneframe.svg";

int steps = 360;
PVector[] myobj = new PVector[steps];
float mind, ang, my_ra = 100, my_rb = 50;
PVector mouse = new PVector(0, 0);
int nearest = 0;

void make_obj(float posX, float posY) {
  for (int i =0; i<steps; i++) {
    ang = TWO_PI*i/float(steps);
    myobj[i]= new PVector(
// original ellipse
//      my_ra * sin(ang), 
//      my_rb * cos(ang)
      my_ra * sin(ang)+my_rb * cos(ang*3)/5, 
      my_rb * cos(ang)+my_ra * sin(ang*7)/3
      );
  }
  // move it
  PVector moveto = new PVector(posX, posY);
  for (int i =0; i<steps; i++) {
    myobj[i] = myobj[i].add(moveto);
  }
}

int calc_min_mouse_dist() {
  int minpos = -1;
  mind = 10000;

  for (int i =0; i<steps; i++) {
    float d = myobj[i].dist(mouse);
    if ( d < mind ) { 
      mind = d;
      minpos = i;
    }
  }
  return minpos;
}

void draw_obj() {
  beginShape();
  stroke(0, 200, 0);
  strokeWeight(2);
  noFill();                               //fill(0,0,200);
  for (int i =0; i<steps; i++) vertex(myobj[i].x, myobj[i].y);
  endShape(CLOSE);

  // draw mouse
  stroke(200, 0, 0);
  line(myobj[nearest].x, myobj[nearest].y, mouse.x, mouse.y);
  fill(200, 0, 0);
  text(int(mind), mouse.x+10, mouse.y-10);   // ?? not work inside filled ellipse
}

void setup() {
  size(300, 300);
  make_obj(120, 200); //width/2,height/2);
  println("use: key [r] for print to svg file");
}

void draw() {
  if (record) {
    beginRecord(SVG, outfilename);  //"data/frame-####.svg");
  }

  background(200, 200, 0);
  draw_obj();
  
  if (record) {
    endRecord();
  record = false;
  println("pls find "+outfilename);
  }

}

void mouseMoved() {
  mouse.set(mouseX, mouseY);
  nearest = calc_min_mouse_dist();
}

void keyReleased() {
  if ( key == 'r' ) record = true;
}



#5

I mean how to get an array of XYpoints from loadShape(“xxx.svg”)?
not export svg


#6

so now it looks like i completely misunderstood your question?
forget all above

pls post your code here using

</>

formatter
and also provide the needed file.


#7

Thanks for the patience :slight_smile:
This is not completely misunderstanding, you help a lot.
Right now code looks like this. But it is not working because of NullPointerException error!

Can’t upload .svg file, but it is like this

import geomerative.*;

RShape text;
RPoint [] points;
PVector[] Vpoints;
PVector mouse = new PVector(0,0);

int nearest = 0;

void make_obj(float posX, float posY) {
  for (int i=0; i < points.length; i++) {
    Vpoints [i] = new PVector (points[i].x,points[i].y);
  }
  PVector moveto = new PVector(posX,posY);
  for (int i =0;i<points.length;i++) {
    Vpoints[i] = Vpoints[i].add(moveto);
  }
}

int calc_min_mouse_dist() {
  int minpos = -1;
  float mind = 10000;
  
  for (int i =0;i<points.length;i++) {
    float d = Vpoints[i].dist(mouse);
    if ( d < mind ) { 
      mind = d;
      minpos = i;
    }
  }
  return minpos;
}

void draw_obj() {
  beginShape();
  stroke(0,200,0);
  strokeWeight(3);
  fill(0,0,200);
  for (int i=0 ; i<points.length; i++) {
    vertex(Vpoints[i].x, Vpoints[i].y);
  }
  endShape(CLOSE);
  
  // draw mouse
  stroke(200,0,0);
  line(Vpoints[nearest].x,Vpoints[nearest].y,mouse.x,mouse.y);
}

void mouseMoved() {
  mouse.set(mouseX,mouseY);
  nearest = calc_min_mouse_dist();
}

void setup () {
  size (640,480);
  noLoop();
  
  RG.init(this);
  
  text = RG.loadShape ("sample_text.svg");
  points = text.getPoints();
  
  ellipseMode(CENTER);
}

void draw () {
  println (points.length);
  
   draw_obj();
  
}

This is actually your code, but instead of using vertex for draw I used geomerative library to load points from svg file to an array


#8

a svg file is text!
so you can post it ( its content ) here same as like code

anyhow i was able to combine the
processing loadshape svg example with the
geomerative library
and my mouse line of min distance code

// https://discourse.processing.org/t/calculate-distance-from-point-to-closest-point-of-shape/7201/7

import geomerative.*;

RShape myshape;
RPoint [] points;
boolean diagpoints = true;
RPoint mouse = new RPoint(0,0);


float mind;
int nearest = -1;

int calc_min_mouse_dist() {
  int minpos = -1;
  mind = 10000;

  for (int i =0; i<points.length; i++) {
    float d = points[i].dist(mouse);
    if ( d < mind ) { 
      mind = d;
      minpos = i;
    }
  }
  return minpos;
}



void setup () {
  size (640,480); 
  RG.init(this);
  myshape = RG.loadShape ("data/bot1.svg");
  points = myshape.getPoints();
  println(points.length);
  //printArray(points);
}

void draw() {
  background(200,200,0);
  myshape.draw();
  // If there are any points
  if(points != null ){
    noFill();
    stroke(0,200,0);
    beginShape();
  if ( diagpoints )    for(int i=0; i<points.length; i++) vertex(points[i].x, points[i].y);
    endShape();
  
    fill(0,0,200);
    stroke(0,0,200);
  if ( diagpoints )    for(int i=0; i<points.length; i++)   ellipse(points[i].x, points[i].y,2,2);  
    draw_mouseline();
  }
}

void mouseMoved() {
  mouse= new RPoint(float(mouseX), float(mouseY));
  nearest = calc_min_mouse_dist();
}

void draw_mouseline() {
  stroke(200, 0, 0);
  if (nearest > -1 ) line(points[nearest].x, points[nearest].y, mouse.x, mouse.y);
  fill(200, 0, 0);
  text(int(mind), mouse.x+10, mouse.y-10);   // ?? not work inside filled ellipse
 
}

2019-01-05_20-42-38_snap

so if your svg file contains POINTS and not TEXT it will work.


#9

Thank you! It works perfectly
But i didn’t get what the diagpoints do. For what it needed?


#10

its to show the points,
i made a boolean you can set to false, to disable that