Placing a mesh to fit inside of a 'special' mesh

Hi all! I have a situation where some help would be greatly appreciated. I do have an app that is built on top of this one. You can draw lines in 2D and have them represented as walls in 3D. This app also allows you to place doors and windows by making a hole within any wall you place the object on.
https://cvdlab.github.io/react-planner/

Firstly I will attach a demo to show my problem:

To explain my current problem, I have to explain how I’m creating my walls differently from the current app. I needed the walls to cut and adjust perfectly with each other in 3D, so I can get the following effect:

Instead of this:
image

My current problem is placing a mesh to fit inside those walls. On the screenshot, the wall would be the dark figure,the wireframed red one would be the one I want to place inside the wall. With my current calculations, I’m achieving this result:

But seems like the mesh is getting placed right from the middle of the wall and takes its place inwards from there. I would like the mesh to fit exactly within the wall. I cannot manually place it with setX or setZ because that wall can be turned on any direction at users will, so X-Z and alpha can change anytime during runtime.

I’m not sure which variable can I tweak so I can make the mesh behave like that. I looked on the original app but it does not seem like that code is useful for me, since the way I’m creating the walls is different from the original app. Feel free to tweak with the demo, any help is greatly appreciated.

It is a problem of origin. The origin of the wall is at one of its faces, while the origin of the red box is at its body center.

You can do two things in file buildWalls.js where you create the red holeMesh:

(1) Make the red object thicker, so that it definitely pokes throughout the opposite side:

new BoxGeometry(..., wallThickness*3),

image

(2) Or shift the object geometry to get the exact centering:

new BoxGeometry(..., wallThickness).translate(0,0,-wallThickness/2),

The second approach is somewhat risky, because CSG might not work well with “perfectly” overlapping faces.

1 Like

Hi @PavelBoytchev, you are a beast! Thanks a lot for the quick response. Seeing how placing the red box to fit the wall, I have to mention that I previously tried the approach of multiplying the thickness of the red box by the thickness of the wall, but this arises one more problem (which I omitted on the previous message for the sake of simplifying the question).

Later on with that hole, I’m placing a GLB (a window) in that hole, and my requirement is to have that window placed right in the middle of that same wall. That wall thickness can vary at users will:

Or…

I’ve tried the following, pivot is the group containing that same GLB

new BoxGeometry( holeWidth + 0.1, holeHeight + 0.1, lineThickness * 3 )

... // later on when I'm placing my GLB..

pivot.position.z -= ( holeThickness / 2 ) + ( lineThickness / 4 );

But the window is not being placed in the middle of that wall. Any math that I might be missing?

Another problem that arises with increasing the thickness, is that also my objects (wall, window, floor) are selectable via raycast. If I make the red box thicker to make sure that CSG catches the whole wall, I will be selecting the ‘window’ when In reality, the wall is the one being selected:

This will also get worse the thicker the wall gets, since the red box will extrude even more.

I don’t know how you build the walls. If I were you, I’d do these things:

  • The walls will be built symmetrically. In this way it is easy to center the hole.
  • The hole does not need to extrude that much, if the wall thickness is T, the hole may be T+0.01, thus the extrusion will be unnoticeable for people, but enough for CSG.
  • If T can vary, I will make the hole geometry’s thickness = 1, and then I will scale the hole with scale.set(1,1,T+0.01). When the wall thickness changes, I will only update the scale.z.

Edit: here is a demo of randomly created walls with their hole-to-be objects. The randomization of a wall is in function randomizeWall lines 70-95. The function also fixes the hole-to-be depending on the wall position, orientation and thickness:

https://codepen.io/boytchev/full/jOvBPyG

image

Thanks a lot for the response. Copied your way of positioning but this is the result. They should originally placed in the middle of each wall.

In my walls, wall.position begins on the corner. I later move the walls based on some offset + sinus/cosinus calculation. I cannot change this behaviour (as far as I know) so I need to move through this way.

I cannot offset them to X or Z because these walls can be angled in any way. There must be something I can do with the sinus/cosinus functions to make this work, just like I do in the following.

Yes, it is possible to calculate the initial position of the hole, and it is not difficult. However, it is needed to know what are the input data for a wall and how they are converted to 3D wall. I mean, that there are numerous ways to do this and each has its own formula.

Looking at wallData.js, I have the following assumptions:

  • a wall is defined by 4 floor corners with coordinates (x,y)
  • these 4 points define a rectangle (somewhere in the plane, possibly rotated)
  • the wall is moved, so that vertex0 is (0,0,0)
  • the long sides of the wall are vertex0-vertex1 and vertex2-vertex3
  • the short sides (i.e. thickness) are the other two segments
  • in your 3D model the height of the wall is along the Y axis (so your data is XY points, but they become XZ points)

Are my assumption correct? If yes, I can try to find an easy way to calculate the initial position of a hole, independent on how thick is the wall, where it is and how it is rotated.


PS. When I look at the data, they are not of exact rectangles, but are almost rectangles, a kind of trapezoids.

1 Like

I activated the 4 walls from wallData.js and made the following changes to buildWall.js:

// increased the thickness by 1
let holeMesh = new Mesh(
    new BoxGeometry(holeWidth, holeHeight, wallThickness+1), // changed
    new MeshBasicMaterial({color: "red"})
  );


// changed the calculation of position X and Z
holeMesh.position.x = (p0.x+p1.x+p2.x+p3.x)/4; // changed
holeMesh.position.y += holeHeight / 2 + holeAltitude;
holeMesh.position.z = (p0.z+p1.z+p2.z+p3.z)/4; // changed

// changed the calculation of rotation
holeMesh.rotation.y = Math.atan( p1.z-p0.z, p1.x-p0.x ); // changed

Now the holes appear centered and rotated for all 4 walls:

Could you provide sample wall data for a wall that is at 30°, for example. This is needed to verify the calculation of rotation (sometimes the sign must be the opposite, but for boxes at angles 0°,90°,180°,270° the sign doesn’t matter, so I want to try for another orientation)

1 Like

Thanks for all the thoughful work of going through my code to troubleshoot my issue, you are being a great help.

Answering your first message, all the assumptions are right but there is one piece missing. The goal when it comes to placing the red box on the wall is to have it originally placed within the X and Z axis is to have to them start on the corner (0,0) and then position them along the wall based on some offset (I mentioned in the codepen that was a value calculated within the app) which is a value from 0.03 to 9.6 (it would normally be 0 to 1, but the way the walls are created makes it be like this) that works like this.

In the CodeSandbox demo I gave this value 0.5 so it gets placed in the middle, but its not always like this.
I used your code and it worked perfectly when it comes to arranging the box to fit the wall:

But it is always arranging the window to be in the middle of the wall, the window is actually positioned here (that would be an offset of 0.1 aprox):

When it comes to rotation, the alpha value it was given already works well with your other code. I would not touch it unless there is some math reason I’m not aware of.

To sum up, I need to figure out the red box position along the wall with this 0.03 to 9.6 value.

Edit: Tried substracting 0.5 to make it know when to place the box to one side or the other, like this:

    holeMesh.position.x = ( ( ( p0.x + p1.x ) * ( offset - 0.5 ) ) + p2.x + p3.x ) / 4;
    holeMesh.position.z = ( ( ( p0.z + p1.z ) * ( offset - 0.5 ) ) + p2.z + p3.z ) / 4;

Offset takes effect but only arranges the box on one half of the wall… I really need to get better at math.

If you need an offset, then just unpack the calculation. Coefficient k defines where the hole is along the wall. If k=0 the center of the hole is at the beginning of the wall, if k=1 the hole is at the end. You may need to shrink the interval [0,1] so that the hole does not go beyond the beginning/end of wall.

let k = ...; // some value for the offset

holeMesh.position.x = (1-k)*(p0.x+p2.x)/2 + k*(p1.x+p3.x)/2;
holeMesh.position.z = (1-k)*(p0.z+p2.z)/2 + k*(p1.z+p3.z)/2;

My previous code assumed k=0.5 for centered holes. Here is the result for k=0.2 and k=0.8:

1 Like

This was exactly it. Thanks a lot! If there is anything I can do to reward you for this inmense help, let me know :slight_smile:

1 Like