Restricted rotation next to a wall

Currently I am trying to find a way to calculate restricted random rotation close to a wall/two walls/three walls.
What I do, and it works, is to find the sector of the rotation circle, which is excluded, by trigonometry between the center of rotation proj and the closest point on the wall. For two walls the sector between the corner has to be calculated as well. When the program creates a random number I restrict the full angle by the angles I calculated for the excluded sectors, so that only correct numbers are chosen.
In the picture the furthest point of the green triangle always stays between the two walls.

The issue I am having now, is that each side is now unique. If the rotation center is close to one wall and far from another, the excluded sector is large for the part of the rotation close the first wall and smaller to the second wall. That means anglevar1 and anglevar2 have to be applied at different ends of the choice of the rotation angle.

cang = random((PI-HALF_PI+anglevar1), (TWO_PI+HALF_PI-anglevar2));

In this model I can I can easily identify, which side needs what exclusion, but when I want to use it with chance encounters (think wall interactions in a box), the program would need to identify, which angle variation would need to go on which side of the random number generation based on the walls I identify as close. I don’t see an efficient way to do that. Is there one?
May way out would be to just use the largest restriction for both sides but especially in very asymmetric cases that would limit the rotation more than necessary.

int boxsize = 500;
float camangle = 90; //camera angle
float camy = 0; //up and down camera
PVector lastseg = new PVector(30, 30, -20);
PVector nextseg = new PVector(60, 30, -30);
PVector axis = new PVector();
PVector proj = new PVector();
float distance;
float planedist1;
float planedist2;
float distnew = 150;
float newangle =radians(60);
PVector planecenter0 = new PVector();
PVector planecenter1 = new PVector();
PVector planecenter2 = new PVector();

void setup() {
  size(900, 700, P3D);
}

void draw() {
  background(129, 200, 273);
  perspective();
  lights();
  translate(450, 350, 0);
  rotateX(camy);
  rotateY(camangle);
  noFill();
  stroke(0);
  strokeWeight(1);
  box(boxsize);
  if (mousePressed == true) {
    camangle += 0.1;
  }
  if (keyPressed == true) {
    if (key =='q' || key == 'Q') {
      camy +=0.1;
    }
    if (key =='a' || key == 'A') {
      camy -=0.1;
    }
    camangle += 0.1;
  }

  rectMode(CENTER);
  fill(255, 100);
  pushMatrix();
  rect(0, 0, boxsize, boxsize);
  popMatrix();
  pushMatrix();
  rotateX(HALF_PI);
  rect(0, 0, boxsize, boxsize);
  popMatrix();

  pushMatrix();
  stroke(125, 255, 0);
  translate(lastseg.x, lastseg.y, lastseg.z);
  sphere(20);
  popMatrix();

  pushMatrix();
  translate(nextseg.x, nextseg.y, nextseg.z);
  sphere(20);
  popMatrix();

  axis = PVector.sub(lastseg, nextseg);
  float axislength = axis.mag();
  distance = sqrt(2*distnew*distnew - 2*distnew*distnew*cos(newangle));
  if (distance != axislength) {
    PVector d = axis.copy();
    d.setMag(axislength-distance);
    nextseg.add(d);
  }

  stroke(125, 255, 0);
  strokeWeight(5);
  line(lastseg.x, lastseg.y, lastseg.z, nextseg.x, nextseg.y, nextseg.z);
  proj = axis.copy();
  proj.setMag(distance/2);
  proj.add(nextseg);

  //radius of rotation
  float cradius = sqrt(sq(distnew)-sq(distance/2));

  //Identify axis coordinate with smallest absolute value to create perpendicular vector
  planecenter0 = new PVector(proj.x, 0, 0);
  planecenter1 = new PVector(proj.x, proj.y, 0);
  planecenter2 = new PVector(proj.x, 0, proj.z);

  planedist1 = PVector.dist(planecenter1, proj);
  planedist2 = PVector.dist(planecenter2, proj);
  float cornerproj = PVector.dist(planecenter0, proj);

  //angle between corner and planecenters excluded from rotation
  float anglevarc1 = acos(planedist1/cornerproj);
  float anglevarc2 = acos(planedist2/cornerproj);

  //angle between planecenter and radius touching plane excluded from rotation
  float anglevar1 = acos(planedist1/cradius);
  float anglevar2 = acos(planedist2/cradius);
  anglevar1 += anglevarc1;
  anglevar2 += anglevarc2;

  PVector b = PVector.sub(proj, planecenter0);
  b.normalize();

  //create vectors in plane with intersect circle
  PVector iv = new PVector();
  PVector.cross(axis, b, iv);
  PVector jv = new PVector();
  PVector.cross(axis, iv, jv);
  iv.normalize();
  jv.normalize();

  PVector c2 = new PVector();
  PVector c3 = new PVector();
  PVector p = new PVector();
  float cang = random((PI-HALF_PI+anglevar1), (TWO_PI+HALF_PI-anglevar2));
  PVector.mult(iv, cos(cang), c2);
  c2.mult(cradius);
  PVector.mult(jv, sin(cang), c3);
  c3.mult(cradius);
  p.add(proj);
  p.add(c2);
  p.add(c3);

  stroke(0, 255, 0);
  strokeWeight(5);
  line(proj.x, proj.y, proj.z, p.x, p.y, p.z);  
  line(lastseg.x, lastseg.y, lastseg.z, p.x, p.y, p.z);
  line(nextseg.x, nextseg.y, nextseg.z, p.x, p.y, p.z);
  stroke(120, 125, 0);
  line(planecenter0.x, planecenter0.y, planecenter0.z, proj.x, proj.y, proj.z);
  line(planecenter1.x, planecenter1.y, planecenter1.z, proj.x, proj.y, proj.z);
  line(planecenter2.x, planecenter2.y, planecenter2.z, proj.x, proj.y, proj.z);
}

The easiest and probably most robust way to do this is to use a while loop to generate any random direction, test it against each wall, throw it out if it fails, and loop until you get a valid direction. It may loop for a little while, but it’s mathematically simple.

I tried the while loop but when I use it, I need to do the rotations 100x times per draw loop so it is not feasible.
I could test the rotation circle to get the right range. Like test 0, 90, 180, 270, 360. If 0 and 270 are out, test 20, 40, 60,80 and 200, 220, 240, 260 a.s.o. Then I could go to 1° level within 4-5 iteration.
But it’s not the most elegant solution. :wink:

My suggestion is not to calculate the range of valid rotations and then choose a random value in that range, but rather to keep choosing random values and testing each to see if it is valid until you find the first one that works and be done. Unless you get yourself wedged into a very tight corner, it should only take a few random tries to get a value that won’t drive you into a wall.

Hello :slight_smile:

I am not quite sure what you are trying to achieve. Are you talking about collision detection ?
Or if there is an object that does rotate but should not rotate through the wall, would that not depend from the geometry of the object (in which case it would be the smaller effort to collision check the bounding box).

However, from the short look I took, I wonder if you are considering those planes separately in a 2D manner. As you write “applying your variables to different ends of…” that reminds me of the fact that 2dimensional rotation is easy :slight_smile:

But rotation in 3d space requires you to remember the order something has been rotated in.
e.g. rotating an object around the x, y, z axis in 3 steps will not necessarily yield the same result as rotating about z then x, then y.

Simply it makes a difference in which order you calculate a rotation. Maybe that thought can help :-

I have an object, which rotates around the axis between both green spheres.
The position of the object is the peak of the green triangle.
This rotation should only happen within the boundaries of the two walls/planes. So I would like to calculate the angles of rotations, which are excluded, because otherwise the object is behind any of the walls.

For the one wall/plane case that was easy to calculate and for this case I looked at both planes separately and then tried to combine both excluded angles but I realized I need for that the orientation of the axis in relation to each plane and have to combine that in one coordinate system perpendicular to the rotation axis. How to do that was my question.
So I am not necessarily looking for a full 3D rotation but the rotation around this axis in 3D space.

In can do that just randomly, as mentioned above, but I am interested to understand, how to actually identify the orientation part, because that might be helpful for other things as well.

Let’s assume you have two planes P0 and P1 which have normal vectors N0 and N1 (unit vectors that are perpendicular to the planes). If you calculate N0 x N1 and normalize it, you will get a unit vector that is perpendicular to each of them and which is parallel to the intersection line of the two planes. Let’s call it e2. Now let’s rename N0 as e1 and calculate e0 as e2 x e1. The three e vectors define a new coordinate space that has P0 as its xz-plane. You can create a matrix M as | e0 e1 e2 | that transforms from world space to this local planar space and its transpose that lets you transform back. If you transform N1 into that space, its z-coordinate will be 0, so you can treat it as a 2-D problem. Calculate whatever you want in the planar space, then transform the rotation back to world space to apply to your model.