I made a quick example that is almost working but only implemented one bounding shape. I actually cannot figure out why it sometimes does not correctly do the bounding test on the left side of the bounding shape. My guess would be that maybe at a vertex of the bounding shape two intersections happen instead of one causing the logic for inside / outside to break. Maybe someone else can look at it and try to figure out what is going on. I put the line that is doing something weird in red below.
A quick summary:
- The general idea is to make the bounding shape be a polygon
- When you want to draw a point you test if it is inside the polygon or not
- If you imagine the point you want to place as a line that goes from the mouse to somewhere arbitrarily far away (outside the polygon, in my code it goes to the width of the screen) then you count how many times it intersects the bounding shape. If the number of intersections is odd then the point is inside the bounding shape.
I recently explained the logic in the code below in this post:
http://forum.processing.org/topic/visual-creation-of-a-triangle-filled-circle
- ArrayList<PVector> boundingShape = new ArrayList<PVector>();
- ArrayList<PVector> doodles = new ArrayList<PVector>();
- float minThreshold = 10.0;
- boolean addingBoundShape = true;
- void setup() {
- size(600, 600);
- }
- void draw() {
- background(255);
- // For this example, the first shape is always the bounding one
- if (mousePressed) {
- if (addingBoundShape) {
- // Limit making too many vertices
- boolean shouldAdd = true;
- for (int i = 0; i < boundingShape.size(); i++) {
- PVector bi = boundingShape.get(i);
- if (sqrt(sq(bi.x-mouseX)+sq(bi.y-mouseY)) < minThreshold) {
- shouldAdd = false;
- break;
- }
- }
- // The new vertex is far enough from the other ones
- if (shouldAdd) boundingShape.add(new PVector(mouseX, mouseY));
- }
- // The bounding shape exists now, only draw if inside of it
- else if (isInside()) doodles.add(new PVector(mouseX, mouseY));
- }
- strokeWeight(10);
- drawDoodles();
- drawBoundingShape();
- }
- // This example is only for making one bounding shape
- void mouseReleased() {
- addingBoundShape = false;
- }
- void drawDoodles() {
- fill(255, 0, 89);
- noStroke();
- for (int i = 0; i < doodles.size(); i++) {
- PVector di = doodles.get(i);
- ellipse(di.x, di.y, 10, 10);
- }
- }
- void drawBoundingShape() {
- if (boundingShape.size() > 0) {
- noFill();
- stroke(0);
- int bSizeMinusOne = boundingShape.size()-1;
- for (int i = 0; i < bSizeMinusOne; i++) {
- PVector bi = boundingShape.get(i);
- PVector biPlusOne = boundingShape.get(i+1);
- line(bi.x, bi.y, biPlusOne.x, biPlusOne.y);
- }
- PVector bFirst = boundingShape.get(0);
- PVector bLast = boundingShape.get(bSizeMinusOne);
- line(bLast.x, bLast.y, bFirst.x, bFirst.y);
- }
- }
- // I recently explained how this works in a different post:
- // http://forum.processing.org/topic/visual-creation-of-a-triangle-filled-circle
- boolean isInside() {
- int numIntersections = 0;
- noFill();
- stroke(255, 0, 0);
- strokeWeight(1);
- line(mouseX, mouseY, width, mouseY);
- int bSizeMinusOne = boundingShape.size()-1;
- for (int i = 0; i < bSizeMinusOne; i++) {
- PVector bi = boundingShape.get(i);
- PVector biPlusOne = boundingShape.get(i+1);
- PVector intersection = segIntersection(mouseX, mouseY, width, mouseY, bi.x, bi.y, biPlusOne.x, biPlusOne.y);
- if (intersection != null) {
- numIntersections++;
- ellipse(intersection.x, intersection.y, 15, 15);
- }
- }
- PVector bFirst = boundingShape.get(0);
- PVector bLast = boundingShape.get(bSizeMinusOne);
- PVector intersection = segIntersection(mouseX, mouseY, width, mouseY, bLast.x, bLast.y, bFirst.x, bFirst.y);
- if (intersection != null) {
- numIntersections++;
- ellipse(intersection.x, intersection.y, 15, 15);
- }
- println(numIntersections); // Not sure why this fails on the left side of the bounding shape sometimes
- return (numIntersections%2 == 1); // If the number of intersections is odd, return true
- }
- // Taken from http://wiki.processing.org/w/Line-Line_intersection
- PVector segIntersection(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) {
- float bx = x2-x1;
- float by = y2-y1;
- float dx = x4-x3;
- float dy = y4-y3;
- float b_dot_d_perp = bx*dy-by*dx;
- if (b_dot_d_perp == 0) return null;
- float cx = x3-x1;
- float cy = y3-y1;
- float t = (cx*dy-cy*dx)/b_dot_d_perp;
- if (t < 0 || t > 1) return null;
- float u = (cx*by-cy*bx)/b_dot_d_perp;
- if (u < 0 || u > 1) return null;
- return new PVector(x1+t*bx, y1+t*by);
- }