Connecting an object to another at a 90 degree angle

this seems like it should be a really easy thing to do, and maybe it is and it’s just my own ignorance, i want to connect two parts such that the connecting line (red in the example picture) are going along the same axis, the surface normal (blue) of the connecting part is in line with the dirToZero (green) and vice versa (the other part’s surface normal is in line with the dirToZero of the connecting part) i can put both of these into a vector (just adding up those values) but cannot figure out how to make a rotation such that one becomes the other.

basically i want to connect the two parts at their respective lines and at a 90 degree angle to one another

Maybe it’s easier to understand if you share an image that shows how both objects should look when they are connected. Nice profile pic btw. Loved the “The IT Crowd”^^.

01189998819991197253

3 Likes

in this particular case the part on the left should be connected at the top, at a 90 degree angle…suppose i can include a picture:

if you are wondering why the scale is different, i scale it to fit the area, but that isn’t important, that part is working fine.

so in that screenshot you can see the example from the OP how it SHOULD connect, but also note there are connectors on every side (4 connectors) and they can connect to any of the other parts available connectors.

it’s pretty simple what it needs to do…it needs to connect at a 90 degree angle along the connector line, but for the life of me i can’t seem to figure out how to tell it to do it reliably (i have some code in place but it’s kludgy and buggy, i feel like there should be a single transform i can do, since i know the orientation it NEEDS to be in and i know the orientation it’s currently in, seems like there should be some math to turn one into the other)

Haha, do you know this by memory?

1 Like

Yes, but only because of the melody :grin:

1 Like

Sorry, but even with your pictures I’m not sure how to solve this issue. I mean assuming all objects have the same initial geometry orientation (e.g. the boxes lie in the XY plane and have a certain depth along the Z axis), I would define a fixed mapping for each side of the box. The mapping essentially defines, how the connected object should be positioned and rotated in the base object’s local space in order to perform the connection for each line. If you have this information, you can transform the position and rotation into world space with the base object’s world matrix and then assign the resulting transform data to the connected object.

Another option is to add the connected object as a child to the base object but I’m not sure the resulting hierarchy is wanted in your application.

well at least it’s not just me. it really SEEMS like it’s an easy thing to do…like just “connectTo”

i had considered a fix mapping for each connection (though, connections are user defined, but i know its rotation relative to the front face, or in world coordinates) thing is, what rotation i need to make is a function of which connection i’m connecting TO and which connection i’m connecting FROM. in 2d this would probably not be a hard problem, but in 3d…well…rotations are weird in 3d.

i thought maybe quaternions could help me, just made me thing: “you had a problem, so you thought you would use quaternions, now you have two problems”

cus if rotations in three dimensions were cooking your noodle, let’s bring it to 4 dimensions.

been thinking maybe matrices could help…but i have no idea what is going on there.

i can work out the orientation in local space for the object being connected to (basically start.angleTo(end)*(dirToZero.x+dirToZero.y+dirToZero.z)(unless the angle is 0 and the multiple is -1, then it’s 180) as its rotation along the local z axis, and 90 degrees as its rotation along the axis the line moves (x or y or some combination of both)

so, that top line, as an example, moves along its local x axis, its rotation along the front face is 0, a part connecting to it would have a rotation, in that objects local space, of 90,0,0

one on the right side however would have a rotation of 0,90,90, this is because it has a 90 degree rotation about the z axis, and a 90 degree rotation about the y axis (the axis along which the line is drawn) while the left side would be 0,90,-90

i can even get this orientation in the world space too, its 2d rotation is always about its normal and the 90 degree is along the axis the line moves. but i haven’t the foggiest how to turn the other parts rotation into that rotation

position is easy enough, the positioning works just fine (i just set the position of the connecting part to the centre of the connection line and then back if off along the other parts normal by the distance from the centre of the part to the centre of the connection line of that part (or, i will when i figure out how to handle 45 degree angles, right now i just use the height/2 or width/2 as need be))

right now my rotation method is

   this.setRotation(new THREE.Euler(0,0,0));//first clear out the rotation
    var first=connection.owner.obj.localToWorld(connection.line.geometry.vertices[1].clone()).sub(connection.owner.obj.localToWorld(connection.line.geometry.vertices[0].clone()));//this is the distance and direction of the oher line
    var second=ownConnection.owner.obj.localToWorld(ownConnection.line.geometry.vertices[1].clone()).sub(ownConnection.owner.obj.localToWorld(ownConnection.line.geometry.vertices[0].clone()));//this is the distance and direction of my line
    var axis=cleanVector(first.clone().normalize());//this is just the direction of the other line
    var axis2=cleanVector(second.clone().normalize());//and this is just the direction of my line
    var rotAxes=cleanVector(axis.clone().cross(axis2).normalize());//now we want to know what axis to rotate these about, if a rotation is needed, taking the cross product of their vectors gives a vector orthagonal to both, that's the one i want to rotate about.
    rotAxes.multiply(rotAxes);//here i multiply it by itself to insure it's positive, being positive or negative here is accidental based on the order they did the lines in, so i don't want to depend on that
    var theta=first.angleTo(second);//so this is just the angle between the two connections
    this.rotateOnWorldAxis(rotAxes,theta);//now let's rotate it by that angle on the axes we determined above.
    var firstConnectionNormal=connection.owner.obj.localToWorld(new THREE.Vector3(0,0,-1)).sub(connection.owner.obj.localToWorld(new THREE.Vector3(0,0,0)));//this is the normal of the connecting object, that is a vector orthagonal to the plane that is the face of the part
    cleanVector(firstConnectionNormal);//because floating points...
    var [dirFromZero,norm2]=getDirFromZero(connection);//this gets the direction from the 0 point to the line and also gives the direction of the line this one is for the other connection
    var [myDirFromZero,myNorm]=getDirFromZero(ownConnection);//this one is for my connection
    var testVec=this.obj.localToWorld(new THREE.Vector3(myDirFromZero.x,myDirFromZero.y,0)).sub(this.obj.localToWorld(new THREE.Vector3(0,0,0)));//this is myDirFromZero but with world coordinates
    var theta=firstConnectionNormal.angleTo(testVec);//this will get the angle between the world vector pointing from the 0 point of my object to my connecting line and the vector which is the normal of the object i'm connecting to
    this.rotateOnAxis(new THREE.Vector3(-1,0,0),theta);//and rotate it here, the vector will always be the local x so i use that fact
    
    var norm=ownConnection.owner.obj.localToWorld(new THREE.Vector3(0,0,-1)).sub(ownConnection.owner.obj.localToWorld(new THREE.Vector3(0,0,0)));//this one is my norm, like firstConnectionNormal but for my object
    var positiveNorm=norm.clone().multiply(norm);//this is the positive of that normal
    var _dir=ownConnection.owner.obj.localToWorld(new THREE.Vector3(0,0,0)).multiply(positiveNorm).normalize();//i think this migh be redudntant, think it's always the same as positiveNorm
    var translationVector=_dir.multiplyScalar(this.material.base.thickness/2);//so taking the dir vector and multiplying it by material thickness/2 will apply it only to that direction.
    dirFromZero.multiplyScalar(-1);//turn dirToZero into dirFromZero
    
    [myDirFromZero,myNorm]=getDirFromZero(ownConnection);
    var firstConnectionDirFromZero=connection.owner.obj.localToWorld(new THREE.Vector3(dirFromZero.x,dirFromZero.y,0)).sub(connection.owner.obj.localToWorld(new THREE.Vector3(0,0,0)));//this is dirFromZero for other connection in world coordinates
    var myOrthoNorm=this.obj.localToWorld(new THREE.Vector3(0,0,-1)).sub(this.obj.localToWorld(new THREE.Vector3(0,0,0)));//this is the same as the code for norm, but i need to get it again since there as been a change to world coordinates since then.
    var flip=myOrthoNorm.clone().add(firstConnectionDirFromZero).length()*(Math.PI/2);//if my normal is going in the same direction as the vector from the origin of the other object to the connection line then i need to flip 180 degrees, if they are in opposite directions all is well.
    this.rotateOnWorldAxis(firstConnectionNormal,flip);//listen to my story all about how my object got flip turned upside down.

like i said, it’s a bit of a mess, sometimes that local x rotation is inappropriate (this works for any first connection, problem happens when i try and make a second connection that is orthagonal to the first, i flip along the normal of the other part, this can cause the connection on the first part to be at the opposite end, my current workaround is to only do the first order connection and just add the other connections, but ideally there should be some simple transformation i can do where no matter which part i’m doing the connection from they all agree on the orientation (if i connect to one on the left that’s going along the y it should give the same rotation as one on the top going along the x)

adding it as a child MIGHT be possible, i’d have to register an event for when the rotation changes to update the rotation in the container object (currently it handles that when you tell the container to rotate, but if its a child of another part, when that part rotates it will change the rotation of this part, presumably it fires an event when that happens)

bumping this with the answer i ended up finding because it might help some people.

the problem that i had been trying to work out was that i KNEW the orientation the part needed to be in but didn’t know how to make a rotation to take it TO that orientation. so, if you find yourself in this position the answer is: rotational matrices.

so taking the part in the OP, imagine a line going from the centre to the top, another from the centre to the right, and a third from the centre towards the camera, these are its axes: y,x, and z respectively. the rotation i want puts the y axis to the -x the x axis to the positive z and the z axis to the negative y.

treat each of those as a vector: <0,1,0>,<1,0,0>, and <0,0,1> for y,x,z respectively. and the vector they go to after the rotation is <-1,0,0>,<0,0,1>, and <0,-1,0> respectively. so put that into a matrix like so:

|0 -1  0|
|0  0 -1|
|1  0  0|

and that is your rotational matrix, convert it to a quaternion (you can find code to convert a rotational matrix to a quaternion online) and you can set your rotation by it, you can also multiply every vector by that matrix to rotate a part if you wanted but i wouldn’t recommend it.

so to figure out where the vectors need to land i took some things i knew: there are connector lines as you seen, i know the angle of a vector going from the centre of that line to a plane parallel to that line passing through the origin (basically point towards 0,0 but still at 90 degrees to the line) and i know the normal of the part i know that the normal of the connecting part needs to point in the same direction as dirToZero (the line i mentioned above pointing towards 0) i also know that the dirToZero of the connecting line (the line on the part i want to rotate) needs to point opposite the normal of the part i’m connecting to, for the x i just take the cross product of those two vectors, now, for that line at the top of the connecting part, i have all the vectors i need to make a rotational matrix.

but what if the line isn’t at the top? for that i take make a rotational matrix that describes the rotation that part would have if that line were actually on the top and then take the inverse of that rotational matrix and multiply it by the matrix i just created above, and that gives me a matrix that will work for any connection.

the key takeaway here though is: rotational matrices, if you know the orientation you want the object to be in but can’t think how to rotate it to get that orientation, put the orientation into a rotational matrix and that IS your rotation.

hopefully this is helpful…