Programmatically Changing Openings

This topic has been viewed 8238 times and has 8 replies
Thread status: Active
Questions about extending features and developing plug-ins [img]http://www.sweethome3d.com/images/flags/en_small.gif[/img]
Post Reply New Topic
shmuelzon
Posts: 14
Joined: Sun Dec 24, 2023 6:13 am
Country: Israel

Programmatically Changing Openings

Post by shmuelzon »

Hey,

As a part of a plugin development, I want to close a door/window in the floor plan. I tried following the code that does this from the UI and my understanding is that modifying the piece of furniture's transformations (hinges and whatnot) also alters its overall dimensions and so, after transforming it, i.e., removing the existing transformations, I need to recalculate the size and position and update the piece of furniture accordingly. I tried to, basically, copy-paste the code from the ModelPreviewComponent class but I guess I'm missing something since, while the door does close, it stays at, more-or-less, the same original dimensions and becomes distorted.

In my code, I find the relevant furniture by traversing home.getFurniture() and, when needed, call a new shutTheDoor() function I created:

Code: Select all

    private void shutTheDoor(HomeDoorOrWindow furniture) {
        ModelManager modelManager = ModelManager.getInstance();
        HomePieceOfFurniture3D modelNode = new HomePieceOfFurniture3D(furniture, home);
        BoundingBox oldBounds = modelManager.getBounds(modelNode);
        System.out.println("oldBounds: " + oldBounds);
        Point3d oldLower = new Point3d();
        oldBounds.getLower(oldLower);
        System.out.println("oldLower: " + oldLower);
        Point3d oldUpper = new Point3d();
        oldBounds.getUpper(oldUpper);
        System.out.println("oldUpper: " + oldUpper);

        setNodeTransformations(modelNode, null);

        BoundingBox newBounds = modelManager.getBounds(modelNode);
        System.out.println("newBounds: " + newBounds);
        Point3d newLower = new Point3d();
        newBounds.getLower(newLower);
        System.out.println("newLower: " + newLower);
        Point3d newUpper = new Point3d();
        newBounds.getUpper(newUpper);
        System.out.println("newUpper: " + newUpper);
        furniture.setX(furniture.getX() + (float)(newUpper.x + newLower.x) / 2 - (float)(oldUpper.x + oldLower.x) / 2);
        furniture.setY(furniture.getY() + (float)(newUpper.z + newLower.z) / 2 - (float)(oldUpper.z + oldLower.z) / 2);
        furniture.setElevation(furniture.getElevation() + (float)(newLower.y - oldLower.y));
        furniture.setWidth((float)(newUpper.x - newLower.x));
        furniture.setDepth((float)(newUpper.z - newLower.z));
        furniture.setHeight((float)(newUpper.y - newLower.y));
        furniture.setModelTransformations(null);
    }

    private void setNodeTransformations(Node node, Transformation [] transformations) {
        if (node instanceof Group) {
            if (node instanceof TransformGroup
                    && node.getUserData() instanceof String
                    && ((String)node.getUserData()).endsWith(ModelManager.DEFORMABLE_TRANSFORM_GROUP_SUFFIX)) {
                System.out.println("Setting new transform for " + (String)node.getUserData());
                TransformGroup transformGroup = (TransformGroup)node;
                transformGroup.setTransform(new Transform3D());
                if (transformations != null) {
                    String transformationName = (String)node.getUserData();
                    transformationName = transformationName.substring(0, transformationName.length() - ModelManager.DEFORMABLE_TRANSFORM_GROUP_SUFFIX.length());
                    for (Transformation transformation : transformations) {
                        if (transformationName.equals(transformation.getName())) {
                            System.out.println("XXX"); 
                            float [][] matrix = transformation.getMatrix();
                            Matrix4f transformMatrix = new Matrix4f();
                            transformMatrix.setRow(0, matrix[0]);
                            transformMatrix.setRow(1, matrix[1]);
                            transformMatrix.setRow(2, matrix[2]);
                            transformMatrix.setRow(3, new float [] {0, 0, 0, 1});
                            transformGroup.setTransform(new Transform3D(transformMatrix));
                        }
                    }
                }
            }
            Enumeration<?> enumeration = ((Group)node).getAllChildren();
            while (enumeration.hasMoreElements()) {
                setNodeTransformations((Node)enumeration.nextElement(), transformations);
            }
        }
    }
These are the old and new bounds, as printed from the above:

Code: Select all

oldBounds: Bounding box: Lower=492.4598841340258 0.0 -2029.357666015625 Upper=583.4937291472243 208.5 -1943.9011759098528
newBounds: Bounding box: Lower=492.02176349361724 0.0 -2029.3576131526472 Upper=583.4937291472243 208.5 -1943.9011759098528
As can be seen, they are very similar.

If it helps, the position and dimensions of the door when it's open (the starting state) is:

Code: Select all

X= 538, Y= -1986.6, Elevation= 0, Angle= 270, Width= 85.5, Depth= 91, Height= 208.5
When closing it via the "Modify openings..." UI, the position and size become:

Code: Select all

X= 507.5, Y= -1982.6, Elevation= 0, Angle= 270, Width= 77.3, Depth= 30.9, Height= 208.5
However, closing it with the above code, results with:

Code: Select all

X= 537.8, Y= -1986.6, Elevation= 0, Angle= 270, Width= 91.5, Depth= 85.5, Height= 208.5
Can anyone please point me in the right direction for how to properly close (and later restore) doors/windows?

Thanks in advance!
User avatar
Daniels118
Posts: 503
Joined: Wed Nov 17, 2021 9:04 pm
Country: Italy

Re: Programmatically Changing Openings

Post by Daniels118 »

I have interest on this subject, so far I've been able to open doors in the 3D view, but I wasn't able to find a way to consolidate the changes in the plan.
If this is enough for your use case, you can have a look at the source code of the Pan3dView plugin. There is also a video on my YouTube channel which shows the feature in action.
shmuelzon
Posts: 14
Joined: Sun Dec 24, 2023 6:13 am
Country: Israel

Re: Programmatically Changing Openings

Post by shmuelzon »

I wasn't able to find a way to consolidate the changes in the plan
What do you mean by this? That the openings are only changed in the 3D view but nothing is changed in the plan?

In my case, it changes both the plan and the 3D view but the door/windows become distorted because their proportions don't match anymore.
If this is enough for your use case, you can have a look at the source code of the Pan3dView plugin
I need this change to be applied when rendering an image. I think that a new scene is built for the renderers and not using the same objects in the 3D view but I might be off here. If I am, then it might be enough to only modify the 3D view and leave the plan intact.
User avatar
Keet
Posts: 1807
Joined: Fri Apr 08, 2022 7:13 am
Country: Netherlands

Re: Programmatically Changing Openings

Post by Keet »

In my case, it changes both the plan and the 3D view but the door/windows become distorted because their proportions don't match anymore.
Your problem might be related to a bug I reported with wrong deformations in the 3Dview with the Pan3DView plugin: http://www.sweethome3d.com/support/foru ... ,100#61531
One thing I figured out that might help you with finding the cause is to place an object horizontal and one diagonal and see the difference in how the deformations show. You will also have to check chained deformations (deformation on a deformed part).
Dodecagon.nl
1300+ 3D models, manuals, and projects
GeoffS
Posts: 7
Joined: Sun Sep 01, 2024 2:04 pm
Country: Australia

Re: Programmatically Changing Openings

Post by GeoffS »

My observations have found that a door opened with the Pan3DView plugin will not render open. A cupboard with 2 doors, the left opened in the Modify Deformations Dialog and the right door opened with the Pan3DView plugin will render with the right door closed.
GeoffS
Posts: 7
Joined: Sun Sep 01, 2024 2:04 pm
Country: Australia

Re: Programmatically Changing Openings

Post by GeoffS »

In all fairness to Daniels118 his plugin does state that the Edit openings is beta and the option to have access to this feature in its infancy is greatly appreciated.
User avatar
Keet
Posts: 1807
Joined: Fri Apr 08, 2022 7:13 am
Country: Netherlands

Re: Programmatically Changing Openings

Post by Keet »

In all fairness to Daniels118 his plugin does state that the Edit openings is beta and the option to have access to this feature in its infancy is greatly appreciated.
Correct. That's why I stated in a follow-up post that's it's no problem, no hurry to fix. I mainly use the 3Dview deformations to test that deformations work. That they are distorted with wrong deformations is no problem as long as I can see that they work in the order they are supposed to.
Dodecagon.nl
1300+ 3D models, manuals, and projects
shmuelzon
Posts: 14
Joined: Sun Dec 24, 2023 6:13 am
Country: Israel

Re: Programmatically Changing Openings

Post by shmuelzon »

My observations have found that a door opened with the Pan3DView plugin will not render open. A cupboard with 2 doors, the left opened in the Modify Deformations Dialog and the right door opened with the Pan3DView plugin will render with the right door closed.
Thanks for that, then I need to make it work in the plan...
shmuelzon
Posts: 14
Joined: Sun Dec 24, 2023 6:13 am
Country: Israel

Re: Programmatically Changing Openings

Post by shmuelzon »

The feature request for my SH3D plugin requiring this functionality was recently brought up again and I, needing some kind of win, decided to try and tackle it again.

I'm not sure everything below is required but I tried to only include things that made sense to me. I did have the basic idea of what needs to be done correct, just not the way to do it :)

The gist of it is to:
[*]Build a 3D scene with the piece of furniture and its existing dimensions from the floor plan
[*]Modify the 3D model's transformations (in my case, remove them to close the door)
[*]Calculate the bounding box of the 3D model before and after the transformation changes to get the new size and center point
[*]Update the floor plan piece with the new location and size according to the changes calculated from the step above

Here's the functional, though not that pretty, code to do that:

Code: Select all

private void closeDoorOrWindow(HomePieceOfFurniture piece) {
    if (piece.getModelTransformations() == null) {
        return;
    }
                                                                                                                                                                                                                                                      
    /* Build 3D scene with floor plan piece */
    ModelManager modelManager = ModelManager.getInstance();
    BranchGroup sceneTree = new BranchGroup();
    TransformGroup modelTransformGroup = new TransformGroup();
    BranchGroup modelRoot;
                                                                                                                                                                                                                                                      
    sceneTree.addChild(modelTransformGroup);
    try {
        modelRoot = modelManager.loadModel(piece.getModel());
    } catch (Exception ex) {
        return;
    }
                                                                                                                                                                                                                                                      
    if (modelRoot.numChildren() == 0)
        return;
                                                                                                                                                                                                                                                      
    Vector3f size = piece.getWidth() < 0 ? modelManager.getSize(modelRoot) : new Vector3f(piece.getWidth(), piece.getHeight(), piece.getDepth());
    HomePieceOfFurniture modelPiece = new HomePieceOfFurniture(new CatalogPieceOfFurniture(null, null, piece.getModel(), size.x, size.z, size.y, 0, false, null, null, piece.getModelRotation(), piece.getModelFlags(), null, null, 0, 0, 1, false));
    modelPiece.setX(0);
    modelPiece.setY(0);
    modelPiece.setElevation(-modelPiece.getHeight() / 2);
                                                                                                                                                                                                                                                      
    HomePieceOfFurniture3D piece3D = new HomePieceOfFurniture3D(modelPiece, null);
    modelTransformGroup.addChild(piece3D);
                                                                                                                                                                                                                                                      
    modelPiece.setModelTransformations(piece.getModelTransformations());
    piece3D.update();
                                                                                                                                                                                                                                                      
    /* Remove transformations from 3D model and update modelPiece's size and location */
    BoundingBox oldBounds = modelManager.getBounds(piece3D);
    Point3d oldLower = new Point3d();
    oldBounds.getLower(oldLower);
    Point3d oldUpper = new Point3d();
    oldBounds.getUpper(oldUpper);
                                                                                                                                                                                                                                                      
    setNodeTransformations(piece3D, null);
                                                                                                                                                                                                                                                      
    BoundingBox newBounds = modelManager.getBounds(piece3D);
    Point3d newLower = new Point3d();
    newBounds.getLower(newLower);
    Point3d newUpper = new Point3d();
    newBounds.getUpper(newUpper);
    modelPiece.setX(modelPiece.getX() + (float)(newUpper.x + newLower.x) / 2 - (float)(oldUpper.x + oldLower.x) / 2);
    modelPiece.setY(modelPiece.getY() + (float)(newUpper.z + newLower.z) / 2 - (float)(oldUpper.z + oldLower.z) / 2);
    modelPiece.setElevation(modelPiece.getElevation() + (float)(newLower.y - oldLower.y));
    modelPiece.setWidth((float)(newUpper.x - newLower.x));
    modelPiece.setDepth((float)(newUpper.z - newLower.z));
    modelPiece.setHeight((float)(newUpper.y - newLower.y));
    modelPiece.setModelTransformations(null);
                                                                                                                                                                                                                                                      
    /* Update location and size of the floor plan piece */
    float modelX = piece.isModelMirrored() ? -modelPiece.getX() : modelPiece.getX();
    float modelY = modelPiece.getY();
    float pieceX = (float)(piece.getX() + modelX * Math.cos(piece.getAngle()) - modelY * Math.sin(piece.getAngle()));
    float pieceY = (float)(piece.getY() + modelX * Math.sin(piece.getAngle()) + modelY * Math.cos(piece.getAngle()));
    float pieceElevation = piece.getElevation() + modelPiece.getElevation() + piece.getHeight() / 2;
    piece.setModelTransformations(new Transformation [0]);
    piece.setX(pieceX);
    piece.setY(pieceY);
    piece.setElevation(pieceElevation);
    piece.setWidth(modelPiece.getWidth());
    piece.setDepth(modelPiece.getDepth());
    piece.setHeight(modelPiece.getHeight());
}
Post Reply New Topic

Who is online

Users browsing this forum: No registered users and 1 guest