Fix label positioning to use world space bounding boxes

Labels were incorrectly mixing local and global transform matrices, causing
incorrect positioning on scaled/rotated meshes. Now properly converts world
space bounding box positions to mesh local space using temporary TransformNode.

Changes:
- updateTextNode.ts: Use boundingBox.maximumWorld instead of boundingSphere.maximum
- diagramObject.ts: Add empty object param to refreshBoundingInfo()
- inputTextView.ts: Adjust input handle default position and mesh offsets

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Michael Mainguy 2025-11-19 16:52:04 -06:00
parent 7849bf4eb2
commit 0b81605bdf
3 changed files with 25 additions and 7 deletions

View File

@ -205,7 +205,7 @@ export class DiagramObject {
public updateLabelPosition() { public updateLabelPosition() {
if (this._label) { if (this._label) {
this._mesh.computeWorldMatrix(true); this._mesh.computeWorldMatrix(true);
this._mesh.refreshBoundingInfo(); this._mesh.refreshBoundingInfo({});
if (this._from && this._to) { if (this._from && this._to) {
// Connection labels (arrows/lines) // Connection labels (arrows/lines)

View File

@ -31,9 +31,11 @@ export class InputTextView {
this.handle = new Handle({ this.handle = new Handle({
contentMesh: this.inputMesh, contentMesh: this.inputMesh,
label: 'Input', label: 'Input',
defaultPosition: new Vector3(0, .4, .5), defaultPosition: new Vector3(0, .8, .7),
defaultRotation: new Vector3(0, 0, 0) defaultRotation: new Vector3(.36, 0, 0)
}); });
this.inputMesh.position.y = .02;
this.inputMesh.position.z = .01;
// Position is now controlled by Handle class // Position is now controlled by Handle class
this.createKeyboard(); this.createKeyboard();
} }

View File

@ -1,4 +1,4 @@
import {AbstractMesh, Color3, DynamicTexture, Material, MeshBuilder, StandardMaterial} from "@babylonjs/core"; import {AbstractMesh, Color3, DynamicTexture, Material, MeshBuilder, StandardMaterial, TransformNode} from "@babylonjs/core";
import log from "loglevel"; import log from "loglevel";
@ -63,7 +63,6 @@ export function updateTextNode(mesh: AbstractMesh, text: string) {
function createPlane(mat: Material, mesh: AbstractMesh, text: string, planeWidth: number, height: number): AbstractMesh { function createPlane(mat: Material, mesh: AbstractMesh, text: string, planeWidth: number, height: number): AbstractMesh {
const plane = MeshBuilder.CreatePlane("text" + text, {width: planeWidth, height: height}, mesh.getScene()); const plane = MeshBuilder.CreatePlane("text" + text, {width: planeWidth, height: height}, mesh.getScene());
const yOffset = mesh.getBoundingInfo().boundingSphere.maximum.y;
plane.parent = mesh; plane.parent = mesh;
plane.scaling.y = (1 / mesh.scaling.y); plane.scaling.y = (1 / mesh.scaling.y);
@ -75,9 +74,26 @@ function createPlane(mat: Material, mesh: AbstractMesh, text: string, planeWidth
if (mesh.metadata?.template == "#connection-template") { if (mesh.metadata?.template == "#connection-template") {
plane.billboardMode = AbstractMesh.BILLBOARDMODE_Y; plane.billboardMode = AbstractMesh.BILLBOARDMODE_Y;
plane.position.y = mesh.position.y + .1; plane.position.y = mesh.position.y + .1;
} else { } else {
plane.position.y = yOffset + (height * plane.scaling.y); // Calculate label position using world space bounding box
// This ensures labels are positioned correctly regardless of mesh transforms
mesh.computeWorldMatrix(true);
mesh.refreshBoundingInfo();
// Get the top of the bounding box in world space
const top = mesh.getBoundingInfo().boundingBox.maximumWorld;
// Convert world space position to mesh's local space
// Use temporary TransformNode to handle the transformation
const temp = new TransformNode("temp", mesh.getScene());
temp.position = top;
temp.setParent(mesh);
const y = temp.position.y;
temp.dispose();
// Position label above the mesh with offset
// Add additional offset for the scaled height of the label
plane.position.y = y + 0.06 + (height * plane.scaling.y / 2);
} }
plane.addLODLevel(3, null); plane.addLODLevel(3, null);
return plane; return plane;