I want to resize a Plane geometry from the corner points. It works fine since rotation is not included in my calculations inside the function. When the rotation goes above a certain value (e.g. above 45 degrees) the resizing starts to get ridiculous.
Here's my code
import { Edges } from "@react-three/drei";
import React, { useEffect, useRef, useState } from "react";
import { DoubleSide, Vector3 } from "three";
import { CORNER_SCALE } from "../../../../../consts";
import { useThree } from "@react-three/fiber";
import { DEG2RAD } from "three/src/math/MathUtils";
import { Edges } from "@react-three/drei";
import React, { useEffect, useRef, useState } from "react";
import { DoubleSide, Euler, Matrix4, Vector3 } from "three";
import { CORNER_SCALE } from "../../../../../consts";
import { useThree } from "@react-three/fiber";
import { DEG2RAD } from "three/src/math/MathUtils";
const rotatePoint = (p, angleX, angleY, angleZ) => {
const point = new Vector3(p.x, p.y, p.z);
const rotationMatrix = new Matrix4();
rotationMatrix.makeRotationFromEuler(new Euler(angleX, angleY, angleZ));
point.applyMatrix4(rotationMatrix);
return point;
};
const translatePoint = (point, dx, dy, dz) => {
// Create a new point object to avoid modifying the original
const translatedPoint = [point[0] + dx, point[1] + dy, point[2] + dz];
return translatedPoint;
};
const DemoPlane = ({ r, cameraControlsRef }) => {
const [position, setPosition] = useState([0, 0, 0]);
const [rotation, setRotation] = useState([0, 0, DEG2RAD * 60]); // [0, 0, 0]
const [boxGeo, setBoxGeo] = useState([1, 1, 1]);
const [scale, setScale] = useState([1, 1, 1]);
const [cornerPointScale, setCornerPointScale] = useState(CORNER_SCALE);
const [cornerPositions, setCornerPositions] = useState([]);
const [cornerIndex, setCornerIndex] = useState(null);
const [isResizing, setIsResizing] = useState(false);
const { camera } = useThree();
const planeRef = useRef();
const containerPlaneRef = useRef();
const handlePointer = (e, op, i) => {
e.stopPropagation();
switch (op) {
case "corner-down":
setCornerIndex(i);
setIsResizing(true);
break;
case "up":
setIsResizing(false);
break;
case "move":
if (isResizing) {
let pointer = e.point;
pointer = rotatePoint()
switch (cornerIndex) {
case 0:
const newWidth =
boxGeo[0] - (pointer.x - cornerPositions[cornerIndex][0]);
const newHeight =
boxGeo[1] + (pointer.y - cornerPositions[cornerIndex][1]);
if (newWidth < 0 || newHeight < 0) return;
const deltas = {
x: -(newWidth - boxGeo[0]) / 2,
y: (newHeight - boxGeo[1]) / 2,
z: 0,
};
// const newPosition = translatePoint(
// position,
// deltas.x,
// deltas.y,
// deltas.z
// );
const [dX, dY, dZ] = rotatePoint(
deltas,
rotation[0],
rotation[1],
rotation[2]
);
const newPosition = translatePoint(position, dX, dY, dZ);
setBoxGeo([newWidth, newHeight, boxGeo[2]]);
setPosition(newPosition);
break;
case 1:
break;
case 2:
break;
case 3:
break;
default:
break;
}
}
break;
default:
break;
}
};
useEffect(() => {
const pos = planeRef.current.geometry.attributes.position;
const corners = [];
for (const i of [...Array(4).keys()]) {
const vector = new Vector3();
vector.fromBufferAttribute(pos, i);
const corner = planeRef.current.localToWorld(vector);
corners.push(corner);
}
// console.log(corners.map((c) => [c.x, c.y, c.z]));
setCornerPositions(corners.map((c) => [c.x, c.y, c.z]));
// console.log(initialCornerPositions);
cameraControlsRef.current.rotateTo(rotation[2], rotation[0], false);
}, [position, planeRef.current, rotation]);
return (
<>
<mesh
ref={containerPlaneRef}
position={[position[0], position[1], position[2] - boxGeo[2] / 2]}
rotation={[0, 0, rotation[2]]}
scale={100}
visible={false}
onPointerMove={(e) => handlePointer(e, "move")}
onPointerUp={(e) => handlePointer(e, "up")}
onWheel={() => {
setCornerPointScale(8 / camera.zoom);
}}
>
<planeGeometry args={[1, 1]} />
<meshBasicMaterial color={"black"} side={DoubleSide} />
</mesh>
<mesh
ref={planeRef}
position={[position[0], position[1], position[2] + boxGeo[2] / 2]}
rotation={[0, 0, rotation[2]]}
scale={scale}
>
<planeGeometry args={[boxGeo[0], boxGeo[1]]} />
<Edges color={"#fff"} />
<meshBasicMaterial
color={"yellow"}
side={DoubleSide}
transparent
opacity={30 / 100}
/>
</mesh>
{cornerPositions.map((position, i) => (
<mesh
key={i}
position={position}
scale={cornerPointScale}
onPointerDown={(e) => handlePointer(e, "corner-down", i)}
>
<sphereGeometry args={[1, 32, 16]} />
<meshStandardMaterial color="red" transparent />
</mesh>
))}
</>
);
};
export default DemoPlane;