DragControls, TransformControls - move curve points

Hi.
I am currently studying DragControls and TransformControls .
Created a class that allows you to move the captured object
//
class Drag {

        constructor(objects) {
            this.transform = new TransformControls(camera.camera, renderer.domElement);
            this.drag = new DragControls(objects, camera.camera, renderer.domElement );
        }

        init() {
            this.transform.setMode("translate");
            this.transform.addEventListener('dragging-changed', function (event) {
                camera.controls.view.enabled = !event.value
            });

            let transform = this.transform;
            this.drag.enabled = false;
            this.drag.addEventListener('dragstart', function (event) {
                if(event.object.name != 'dummy') {
                    transform.attach(event.object);
                    scene.add(transform);
                } else {
                    transform.detach();
                }
            });
        }
    }
let objects = [];
let drag = new Drag(objects);

var shape = new THREE.Shape();

shape.lineTo(0, 3);
shape.lineTo(3, 3);
shape.lineTo(3, 0);
shape.lineTo(0, 0);

var points = shape.getPoints();
var geometry = new THREE.BufferGeometry().setFromPoints(points);
var material = new THREE.LineBasicMaterial({color: 0xffffff});
var line = new THREE.Line(geometry, material);
scene.add(line);

drag.init(objects);

I select objects with the mouse and move them: models, points, curves. Everything is working. OK.

NOW the question is: how to move the points of the drawn curves? class Drag allows only the whole object to be moved: DragControls(objects)
curve

I want to move the points of the curves thereby changing this curve.

I need to draw a square from curves and lift it through ExtrudeBufferGeometry
curve1

First of all - dragging points is kinda not possible, since they have no radius (maybe possible, but still will be annoying to try to drag single pixels around.) What you can do, if I got you correctly:

  1. For each line point, create a small sphere at the same location. Put all these spheres in DragControls objects argument.
  2. After a sphere is dragged (or just on any drag update, if you don’t have a lot of points) you can recalculate the line geometry:
const shape = new THREE.Shape();
shape.lineTo(sphere1.position.x, sphere1.position.z);
shape.lineTo(sphere2.position.x, sphere2.position.z);
shape.lineTo(sphere3.position.x, sphere3.position.z);
shape.lineTo(sphere4.position.x, sphere4.position.z);

const points = shape.getPoints();
line.geometry.setFromPoints(points);

Hi!

Maybe this example helps ? :wink:

1 Like

Good afternoon.
Added code to listen for transformations

let draw_drag = new Drag(draw_objects);
    draw_drag.spline_listener = function () {

        let spline = this.spline;
        this.transform.addEventListener('objectChange', function (event) {

            var position = spline.geometry.attributes.position;
            for(let i = 0; i <= 4; i++) {
                // event - Here take the coordinates !!!!!!
                position.setXYZ(i, 0, 0, 0);
            }
            position.needsUpdate = true;
        });
    };

Here let spline = this.spline; - red line.
Listening - draw_objects. draw_objects - gray cubes


After I move the cube, the event is triggered - addEventListener (‘objectChange’, function (event) and it gives - event.
I think to take the coordinates from the event and put it in position.setXYZ (i, 0, 0, 0);
But I can’t find the coordinate from the event !!

I found the coordinates of the movable cube
let target = event.target.object.position;

Just inserting it into setXYZ () has no effect.
It is necessary to understand how to work with setXYZ

I think you are overthinking the way of thinking in that example a bit.

Is there a reason to spend time trying to fight attributes manually (and trying to remember which require needsUpdate flags, which may need matrix recalculation etc.) instead of just updating the line object automatically?

With 4 points and 4 lines, I dare even say it wouldn’t matter if you created an entirely new Mesh on each frame (and disposed the last one ofc) - it should still work just fine.

2 Likes

Thanks for the example mjurczyk :grinning:. It works, the lines move when you move the cube.
BUT only the point of the lines does not move, the starting point


d2

My code:

class Drag {

        constructor(objects) {
            this.transform = new TransformControls(camera.camera, renderer.domElement);
            this.drag = new DragControls(objects, camera.camera, renderer.domElement );
        }

        init() {
            this.transform.setMode("translate");
            this.transform.addEventListener('dragging-changed', function (event) {
                camera.controls.view.enabled = !event.value
            });

            let transform = this.transform;
            this.drag.enabled = false;
            this.drag.addEventListener('dragstart', function (event) {
                if(event.object.name != 'dummy') {
                    transform.attach(event.object);
                    scene.add(transform);
                }
            });
        }

        destroy() {
            this.transform.detach();
        }
    }

    // Start
    let draw_objects = [];

    let draw_drag = new Drag(draw_objects);
    draw_drag.spline_listener = function () {

        let line = this.line;
        this.transform.addEventListener('objectChange', function (event) {

            let shape = new THREE.Shape();
            for(let d in draw_objects) {
                shape.lineTo(draw_objects[d].position.x, draw_objects[d].position.z);
            }
console.log(shape);
            let curve = shape.getPoints();
            line.geometry.setFromPoints(curve);
        });
    };

    $('.js_draw').click(function () {

        function create() {
            let box_g = new THREE.BoxBufferGeometry(0.2, 0.2, 0.2);
            let box_m = new THREE.MeshBasicMaterial({ color: 0x666666 });

            let shape = new THREE.Shape();
            let points = 4;
            for(let i = 1; i <= points; i++) {

                // create cubes and line
                let mesh = new THREE.Mesh(box_g, box_m);
                if(i == 0) {
                    mesh.position.set(0, 0, 0);
                } else if(i == 1) {
                    mesh.position.set(0, 0, 1);
                } else if(i == 2) {
                    mesh.position.set(1, 0, 1);
                } else if(i == 3) {
                    mesh.position.set(1, 0, 0);
                }
                shape.lineTo(mesh.position.x, mesh.position.z);

                scene.add(mesh);
                draw_objects.push(mesh);
            }
            console.log(shape);

            let curve = shape.getPoints();
            var geometry = new THREE.BufferGeometry().setFromPoints(curve);
            var material = new THREE.LineBasicMaterial({ color: 0xff0000 });
            var line = new THREE.Line(geometry, material);
            line.rotation.x = THREE.MathUtils.degToRad(90);

            scene.add(line);

            draw_drag.line = line;
            draw_drag.init();
            draw_drag.spline_listener();
        }

        create();
    });

    document.addEventListener('keydown', function (event) {
        if(event.keyCode == 27) {
            draw_drag.destroy();
        }
    }, false);

Screenshot 2020-10-16 at 16.26.21

Did you just make a for-loop to create 4 points :upside_down_face:

  1. For your own sake, name your variables properly - draw_objects is a verb. And after spending 100 work hours trying to figure it out, it turns out this array does not store actions.
  2. This:
for(let d in draw_objects) {
  shape.lineTo(draw_objects[d].position.x, draw_objects[d].position.z);
}

will not work if you move the first box (it did only in my example, because starting point was at the centre.) Try adding this in front of that for-loop:

shape.moveTo(draw_objects[0].position.x, draw_objects[0].position.z);

It will set a starting point for your shape - otherwise you’re drawing the first line from centre to the first box.

Thanks. Now I understand how it works.
Yes, now all 4 points are moving :grinning: