0

I am using React THREEJS and some other libraries (DREI, Meshline, etc) to draw the Lines and Text, etc. Right Now I am drawing a line and I have to show the length label along with the line. It will be something like this.

enter image description here

Now I have to add an option to move the label position according to line orientation. For example

  • Vertical Line should have movement (Left/Right) X-AXIS
  • Horizontal Line should have (Top/Bottom) Y-AXIS

I have already calculated the middle position of the Vector Points (P1/P2).

  const P1 = new THREE.Vector3(-300.79, -296.96, 0);
  const P2 = new THREE.Vector3(101.49,  -8.43, 0);

  const disX = (P2.x + P1.x) / 2;
  const disY = (P2.y + P1.Y) / 2;

  const P3 = new THREE.Vector3(disX, disY, 0);

Can you please suggest to me any solution?

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
Shoaib Ijaz
  • 5,347
  • 12
  • 56
  • 84
  • 1
    Hi, I'm not sure if you're asking how to draw text generally, or if you're not sure how to calculate the text start position for a given rotation? If you know how to draw text can you post a MRE for the simple case (eg. horizontal), then we can tweak it for general rotation? – gremto Jun 16 '23 at 09:52
  • Sorry, I have already drawn the text, I just don't want to draw the text on the line, it should be some either side of the line with some margin. like I have shown in last image – Shoaib Ijaz Jun 17 '23 at 12:35

1 Answers1

1

When you know coordinates of two points, the normal (norm) to the vector of their direction (dir) is norm(-dir.y, dir.x);

Here is an example (not the ultimate solution):

body{
  overflow: hidden;
  margin: 0;
}
<script async src="https://ga.jspm.io/npm:es-module-shims@1.6.3/dist/es-module-shims.js" crossorigin="anonymous"></script>
<script type="importmap">
  {
    "imports": {
      "three": "https://unpkg.com/three@0.153.0/build/three.module.js",
      "three/addons/": "https://unpkg.com/three@0.153.0/examples/jsm/"
    }
  }
</script>
<script type="module">
import * as THREE from "three";
console.clear();

let scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);

let frustumSize = 10;
let aspect = innerWidth / innerHeight;
let camera = new THREE.OrthographicCamera(frustumSize * aspect / - 2, frustumSize * aspect / 2, frustumSize / 2, frustumSize / - 2, 1, 100);
camera.position.set(0, 0, 10);
camera.lookAt(scene.position);
let renderer = new THREE.WebGLRenderer({
  antialias: true
});
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener("resize", (event) => {
  camera.aspect = innerWidth / innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(innerWidth, innerHeight);
});

let pts = [
  new THREE.Vector2(-3, 3),
  new THREE.Vector2(-3, -2),
  new THREE.Vector2(2, -3),
  new THREE.Vector2(3, 3.5)
];

for(let i = 0; i < pts.length; i++){
  let p1 = pts[i];
  setPoint(p1);
  if (i == pts.length - 1) continue;
  let p2 = pts[i+1];
  setLine(p1, p2);
  
  let midP = new THREE.Vector3().lerpVectors(p1, p2, 0.5);
  let shift = new THREE.Vector2().subVectors(p2, p1).normalize();
  let angle = shift.angle();
  
  let swapX = shift.x;
  let swapY = shift.y;
  shift.set(-swapY, swapX).negate().setLength(0.5);
  
  let distance = p1.distanceTo(p2);
  setMarker(midP, shift, angle, distance);
}

function setPoint(pos){
  let g = new THREE.RingGeometry(0.5, 1, 32);
  let m = new THREE.MeshBasicMaterial({color: "teal"});
  let o = new THREE.Mesh(g, m);
  o.scale.setScalar(0.1);
  o.position.set(pos.x, pos.y, 0.01);
  scene.add(o);
}

function setLine(pos1, pos2){
  let g = new THREE.BufferGeometry().setFromPoints([pos1, pos2]);
  let m = new THREE.LineBasicMaterial({color: "maroon"});
  let l = new THREE.Line(g, m);
  scene.add(l);
}

function setMarker(pos, shift, angle, distance){
  let g = new THREE.PlaneGeometry(4, 1);
  let m = new THREE.MeshBasicMaterial({
    color: "black",
    transparent: true,
    map: getDistanceTexture(distance)
  });
  let o = new THREE.Mesh(g, m);
  o.position.set(pos.x + shift.x, pos.y + shift.y, 0);
  o.rotation.z = angle;
  o.scale.setScalar(1);
  scene.add(o);
}

function getDistanceTexture(value){
  let text = value.toFixed(1) + "m";
  let c = document.createElement("canvas");
  c.width = 64 * 4;
  c.height = 64;
  let ctx = c.getContext("2d");
  ctx.textAlign = "center";
  ctx.textBaseline = "middle";
  ctx.font = "60px Arial";
  ctx.fillStyle = "white";
  ctx.fillText(text, 64 * 2, 64 / 2);
  let ct = new THREE.CanvasTexture(c);
  return ct;
}
renderer.setAnimationLoop((_) => {
  renderer.render(scene, camera);
});

</script>
prisoner849
  • 16,894
  • 4
  • 34
  • 68