[Closed] problem with viewport translations
Hi,
This script will align all of the selected objects to the current view x minimum. It’s not without it’s problems though, if the current view is a user viewport then it works only half of the time depending on the direction of the view. It works for all other othographic views.
I can’t quite work out how to get that final bit working, can you help?
Select a bunch of objects and execute the script. be warned though, it will align to the bounding box (not for perspective views!)
(
sel=selection as array -- get the selections as an array.
tm=(inverse (viewport.getTM())) -- get the current screen coordinate matrix.
selpos=#() -- set an array to hold the positions of the objects in the selection set.
in coordsys tm selpos=for s in sel collect s.pos.x -- collect all of the object positions in the screen coordinate system.
t=tm.row1
m=0
m=t[1]+t[2]+t[3] -- let's work out if it the normal or reverse view by adding each axis of the TM row1 (answer will be positive or negative),
if m<0 then -- collect the min or max value depending on the view (normal or reverse)
(
in coordsys tm seladj=for s in sel collect s.max.x
) else
(
in coordsys tm seladj=for s in sel collect s.min.x
)
v=amin seladj -- get the lowest position in the selection set
newpos=for x=1 to sel.count collect (v+selpos[x]-seladj[x]) -- set the target values to the lowest position, and adjust for object width
for j=1 to sel.count do -- set the new positions
(
in coordsys tm sel[j].pos.x=newpos[j]
)
)
Thanks,
Josh.
Assuming that you are trying to align all objects to the Minimum or Maximum of the SELECTION’s X (or Y), here is how I would do it:
fn alignToScreenExtreme theNodes extreme:#minx =
(
local theTM = viewport.getTM() --get the TM of the view
local theTMinv = inverse theTM --calculate the inverse once
local theScreenPos = for o in theNodes collect --collect the screen space positions of all objects
(
gw.setTransform (Matrix3 1)
gw.transPoint o.position
)
local theAlignValue = case extreme of --get the extreme value according to argument
(
#minx: amin (for i in theScreenPos collect i.x)
#maxx: amax (for i in theScreenPos collect i.x)
#miny: amin (for i in theScreenPos collect i.y)
#maxy: amax (for i in theScreenPos collect i.y)
)
local theViewSize = getViewSize() --get the size of the viewport
for i = 1 to theNodes.count do --loop through all nodes
(
local theViewSpacePos = theNodes[i].pos * theTM --calculate the View Space position
local theNewScreenPos = case extreme of --build the new Screen Space position as Point2
(
#minx: [theAlignValue,theScreenPos[i].y]
#maxx: [theAlignValue,theScreenPos[i].y]
#miny: [theScreenPos[i].x,theAlignValue]
#maxy: [theScreenPos[i].x,theAlignValue]
)
--assign the new screen position to the object
--first convert the Screen Space to View Space at the same Z depth as the original position,
--then converted to World Space by multiplying with the inverse of the view TM:
theNodes[i].pos = (mapScreenToView theNewScreenPos theViewSpacePos.z theViewSize) * theTMinv
)--end i loop
)--end fn
alignToScreenExtreme selection extreme:#minx
This takes the POSITION of each object in screen space, finds the extreme X or Y, and then moves all objects by keeping their other coordinates fixed in View Space and just changing the axis to align to the extreme value. Then the resulting View Space is converted to World Space, resulting in all objects sliding in the XY plane at the original Z distance to the view. It works for me, but if this is not what you were trying to achieve, let me know.
If you want the extreme of the Bounding Box, or even at vertex level, you can simply extend the script to find the extreme value of that element first, then find the distance from the position to the local extreme of each object and shift the position to align the extreme of the object to the calculated min. or max. value taking this offset into account.
Hope this helps.
Hi Bobo,
Thanks for looking. It does what I ask. I’ll digest it a bit and let you know how it goes.
Thanks again,
Josh.