8
$\begingroup$

In Object Mode you can change the absolute Dimensions of the selected object, which are connected to the object's relative Scale.

Absolute bounding box dimensions in Object Mode

With some elements (e.g. vertices) selected in Edit Mode you can use the Scale Tool to resize the bounding box of the selection, changing the individual elements' position.

Is it possible to set the dimensions of that bounding box in absolute values? I would have had expected it to be in the Edit Mode transform properties panel, but it only shows the bounding box' origin position.

Transform panel in Edit Mode

Example: I want to set the tabletop in the image below to a particular size by setting the selected geometry to, let's say 0.75m x 0.75m.

enter image description here

If there is no built-in way to do this, do you know a suitable Add-On?

$\endgroup$
4
+50
$\begingroup$

Here is a script that I wrote to accomplish this. It simply calculates the bounding box of the selected vertices, then scales in such a way that the new dimensions become what you set the values to be.


Here is the add-on that was requested in the comments:

https://github.com/ekaj2/MeshTools

To download from GitHub, simply click the green Clone or Download button, then choose "Download ZIP". Once you have the zip downloaded, unzip, then load the .py file with Blender's add-on tool in user preferences.

enter image description here


Here is the add-on that I wrote (I would recommend downloading the add-on from GitHub to ensure you have the latest updates).

# Copyright 2016 Jake Dube
#
# ##### BEGIN GPL LICENSE BLOCK ######
# This file is part of MeshTools.
#
# MeshTools is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# MeshTools is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with MeshTools.  If not, see <http://www.gnu.org/licenses/>.
# ##### END GPL LICENSE BLOCK #####


import bpy
from bpy.types import Panel, Operator, PropertyGroup, Scene
from bpy.utils import register_class, unregister_class
from bpy.props import FloatProperty, PointerProperty


bl_info = {
    "name": "Mesh Tools",
    "author": "Jake Dube",
    "version": (1, 0),
    "blender": (2, 78, 0),
    "location": "View3D > Mesh > Transform > Set Dimensions",
    "description": "Sets dimensions for selected vertices.",
    "category": "Mesh"}


def calc_bounds():
    """Calculates the bounding box for selected vertices. Requires applied scale to work correctly. """
    # for some reason we must change into object mode for the calculations
    mode = bpy.context.object.mode
    bpy.ops.object.mode_set(mode='OBJECT')

    mesh = bpy.context.object.data
    verts = [v for v in mesh.vertices if v.select]

    # [+x, -x, +y, -y, +z, -z]
    v = verts[0].co
    bounds = [v.x, v.x, v.y, v.y, v.z, v.z]

    for v in verts:
        if bounds[0] < v.co.x:
            bounds[0] = v.co.x
        if bounds[1] > v.co.x:
            bounds[1] = v.co.x
        if bounds[2] < v.co.y:
            bounds[2] = v.co.y
        if bounds[3] > v.co.y:
            bounds[3] = v.co.y
        if bounds[4] < v.co.z:
            bounds[4] = v.co.z
        if bounds[5] > v.co.z:
            bounds[5] = v.co.z

    bpy.ops.object.mode_set(mode=mode)

    return bounds


def safe_divide(a, b):
    if b != 0:
        return a / b
    return 1


class SetDimensions(Operator):
    bl_label = "Set Dimensions"
    bl_idname = "view3d.set_dimensions_mt"
    bl_description = "Sets dimensions of selected vertices"
    bl_options = {'REGISTER', 'UNDO'}
    bl_context = "editmode"

    new_x = FloatProperty(name="X", min=0, default=1, unit='LENGTH')
    new_y = FloatProperty(name="Y", min=0, default=1, unit='LENGTH')
    new_z = FloatProperty(name="Z", min=0, default=1, unit='LENGTH')

    def invoke(self, context, event):
        bounds = calc_bounds()
        self.new_x = bounds[0] - bounds[1]
        self.new_y = bounds[2] - bounds[3]
        self.new_z = bounds[4] - bounds[5]
        return {'FINISHED'}

    def execute(self, context):
        bounds = calc_bounds()
        bpy.ops.object.mode_set(mode='EDIT')
        x = safe_divide(self.new_x, (bounds[0] - bounds[1]))
        y = safe_divide(self.new_y, (bounds[2] - bounds[3]))
        z = safe_divide(self.new_z, (bounds[4] - bounds[5]))
        bpy.ops.transform.resize(value=(x, y, z))

        return {'FINISHED'}

    def draw(self, context):
        layout = self.layout

        box = layout.box()
        box.label("New dimensions:")
        box.prop(self, "new_x")
        box.prop(self, "new_y")
        box.prop(self, "new_z")


def add_button(self, context):
    self.layout.operator(SetDimensions.bl_idname, icon="PLUGIN")


def register():
    register_class(SetDimensions)
    bpy.types.VIEW3D_MT_transform.append(add_button)


def unregister():
    unregister_class(SetDimensions)
    bpy.types.VIEW3D_MT_transform.remove(add_button)


if __name__ == "__main__":
    register()
$\endgroup$
  • $\begingroup$ Good idea, however wouldn't seperating and rejoining break things like assigned textures, UV-data etc.? Regarding a script solution, would calculating the bounding box dimensions, offer text input for each axis, and then repositioning all selected vertices be similarly complex? $\endgroup$ – Andre Dec 5 '16 at 18:15
  • $\begingroup$ No, it shouldn't be a problem with things like textures and UVs; I believe Blender handles all of that for you. Your mentioned scripting workflow would certainly seem more efficient, but for such a seldom used feature I don't know if it would be worth the development effort. It would be much more difficult to achieve that way, although it technically is the "correct" way to do it. My proposed solution is a way to do it without scripting as well as a sort of hack to easily write an add-on to automate the process in most applications. $\endgroup$ – JakeD Dec 5 '16 at 18:21
  • $\begingroup$ Of course, rather than manually placing each vertex, you would calculate the difference b/w the desired dimensions and the bounding box, then scale accordingly. $\endgroup$ – JakeD Dec 5 '16 at 18:24
  • $\begingroup$ Dumb question from a blender dev noob: what's the difference between scripting and writing an addon? $\endgroup$ – Andre Dec 5 '16 at 18:27
  • $\begingroup$ Scripting, coding, and programming are all synonyms that basically mean the same thing. Writing (or scripting) an add-on is a special type of "program" that "adds on" feature to another program or application. In the case of Blender, add-ons get installed in user preferences and are generally user friendly to install and use. Non-add-ons are sometimes just run with the "run script" button in Blender's text editor, but they could be anything. The differences b/w scripting and programming come from the language it is done in: Python is a scripting language, so we call it scripting. $\endgroup$ – JakeD Dec 5 '16 at 18:31
1
$\begingroup$

The way I found how to do this is to make a basic calculation for each axis with the actual dimension divided by the expected dimension on that axis, then divide the scale of the axis by the result of the previous calculation.

To find your dimensions actual edge length:

enter image description here Example:

X axis dimension = 2,734 M - X axis expected = 0.75 M - X axis scale = 1 --

2,734 / 0.75 = 3,645633333 - 1/3,645633333 = 0,27432334 -

With this information, scale on the x axis by 0.27432334 and you will have your desired dimension. Then apply the scale and you're done. Repeat on each axis and voilá!

$\endgroup$
  • $\begingroup$ This would actually be feasible. But how do you know the original X axis dimension of 2,734m in your example? And what do you mean by "apply the scale"? Do you refer to Shift+A in object mode? $\endgroup$ – Andre Dec 5 '16 at 18:57
  • $\begingroup$ you have to check the transform panel you showed in th question. there you can see the actual dimmension. if you start with a default cube, will be 2 meters. $\endgroup$ – Joni Mercado Dec 5 '16 at 18:59
  • $\begingroup$ This panel only shows me the total dimensions of the object. I am asking about resizing a selected subset of vertices, which has a different dimension than the whole mesh (this is actually the whole point of the question). With that panel you wouldn't need to calculate, either. Just type in the desired dimensions and hit enter. $\endgroup$ – Andre Dec 5 '16 at 19:01
  • $\begingroup$ I edited the answer so you can know how to active the edge lenght. so you can know the actual dimension. Hope that helps. $\endgroup$ – Joni Mercado Dec 5 '16 at 19:04
  • 3
    $\begingroup$ Thanks, but this would only help if the edges match the bounding box' edges (as in my example). In the general case however, one cannot assume that this is the case, so just the edge lengths wouldn't suffice to determine the boundix box dimensions. $\endgroup$ – Andre Dec 5 '16 at 19:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.