Thanks for taking a moment to read this! So, my first issue is that I'm trying to create a function, "selectionData()", to get an object's translate, rotate, and scale values and then return them as a dictionary, but find myself struggling a bit. Using the code listed below, all I keep getting is the object's name. How can I modify it to get its translate, rotate, and scale values to return as a dictionary?
My second issue is that I'm trying to create a function, "setData(data)", that takes as input the aforementioned dictionary built with selectionData() and restores the data in the dictionary to the selected objects. How do I do that?
My apologies if either of these questions are foolish, but thank you for your time, regardless! Cheers!
Current code is listed below:
from maya import cmds
sel = cmds.ls(sl = 1)
meshes =[]
for s in sel :
shape = cmds.listRelatives(s , shapes = 1 )
if shape :
if cmds.nodeType(shape[0]) == "mesh" :
meshes.append(s )
meshData = {}
for m in meshes :
pos = cmds.xform ( m , q =1 , ws = 1 , t = 1)
rot = cmds.xform( m , q =1 , ws = 1 , rotation = 1 )
scl = cmds.getAttr ( m + '.s' )[0]
currentDict = {
"pos" : pos ,
"rot" : rot ,
"scl" : scl ,
}
meshData[m] = currentDict
def selectionData( selectionDict):
for k in selectionDict :
print k
selectionData(meshData)
First of all, to list all the objects with transforms you can use this command:
cmds.ls(selection=True, transforms=True, dagObjects=True)
If you want to read/write the transforms, you don't need to get the translation, then rotation and scale separately. You can read the composite transformation matrix like this:
xform_matrix = cmds.xform(source_object, query=True, matrix=True)
You'll get a list of 16 float numbers that are ready to be applied to other objects:
cmds.xform(destination_object, matrix=xform_matrix)
I am not sure how do you want to map the transforms from one set of selected objects to another set. If you describe, I'll be able to post the complete code.
The following script will collect the composite transformation matrix of all selected objects in the dictionary with long object names as the keys:
selected_objects_matrix = {}
for current_object in cmds.ls(selection=True, transforms=True, dagObjects=True):
selected_objects_matrix[cmds.ls(current_object, long=True)] = cmds.xform(
current_object,
query=True,
matrix=True)
Then if you move/rotate/scale the objects in Maya, you can revert like that:
for current_object in selected_objects_matrix:
cmds.xform(
current_object,
matrix=selected_objects_matrix[current_object])
you really just want to do what you have in reverse
setting the q=1 sets the command into query mode.
removing this flag defaults the command to edit mode
getAttr and setAttr are their respective commands, however you need to be aware of the data that youre setting. even though youre grabbing the s attribute above youre making that only grab the x value so when you set it you need to specify sx
cmds.xform ( m , ws = 1 , t = posValues)
cmds.xform( m , ws = 1 , rotation = rotValues )
cmds.setAttr ( m + '.sx', scaleValue) # sx because you are only grabbing the X Value
Related
I have cropped an image in multiple parts and I have the coordinates of each frame (I have also saved on csv). I have modified the frames and now I want to merge them again.
How can I do it in opencv?
I have tried something like (I post only a portion of the code)
parameters = pd.read_csv('parameters.csv')
parameters
for ind in parameters.index:
x = parameters['x'][ind]
y = parameters['y'][ind]
w = parameters['w'][ind]
h = parameters['h'][ind]
frameMerge = imgScratches[y:y+h,x:x+w]
where imgScratches are the framecuts. However I only receive in output one framecut and not all of them merged.
thanks.
The problem seems to be that you assign frameMerge a new part of the image with every iteration. Instead you need to append/add to the already assigned value of frameMerge
# untested
parameters = pd.read_csv('parameters.csv')
frameMerge = "init whatever datatype frameMerge needs to be"
for ind in parameters.index:
x = parameters['x'][ind]
y = parameters['y'][ind]
w = parameters['w'][ind]
h = parameters['h'][ind]
# add/append to existing frameMerge
frameMerge += imgScratches[y:y+h,x:x+w]
I'm trying to resample a set of GRIB2 arrays at 0.25 degree resolution to a coarser 0.5 degree resolution using the xESMF package (xarray's coarsen method does not work here because there is an odd number of coordinates in the latitude).
I have converted the GRIB data to xarray format through the pygrib package, which then subsets out the specific grid I need:
fhr = 96
gridDefs = {
"0.25":
{'url': "https://noaa-gefs-retrospective.s3.amazonaws.com/landsfc.pgrb2.0p25"},
"0.5":
{'url': "https://noaa-gefs-retrospective.s3.amazonaws.com/landsfc.pgrb2.0p50"},
}
fileDefs = {
"0.25":
{'url': "https://noaa-gefs-retrospective.s3.amazonaws.com/GEFSv12/reforecast/2019/2019051900/c00/Days%3A1-10/tmp_pres_2019051900_c00.grib2",
'localfile': "tmp_pres.grib2"},
"0.5":
{'url': "https://noaa-gefs-retrospective.s3.amazonaws.com/GEFSv12/reforecast/2019/2019051900/c00/Days%3A1-10/tmp_pres_abv700mb_2019051900_c00.grib2",
'localfile': "tmp_pres_abv_700.grib2"},
}
def grib_to_xs(grib, vName):
arr = xr.DataArray(grib.values)
arr = arr.rename({'dim_0':'lat', 'dim_1':'lon'})
xs = arr.to_dataset(name=vName)
return xs
gribs = {}
for key, item in gridDefs.items():
if not os.path.exists(item['url'][item['url'].rfind('/')+1:]):
os.system("wget " + item['url'])
lsGrib = pygrib.open(item['url'][item['url'].rfind('/')+1:])
landsea = lsGrib[1].values
gLats = lsGrib[1]["distinctLatitudes"]
gLons = lsGrib[1]["distinctLongitudes"]
gribs["dataset" + key] = xr.Dataset({'lat': gLats, 'lon': gLons})
lsGrib.close()
for key, item in fileDefs.items():
if not os.path.exists(item['localfile']):
os.system("wget " + item['url'])
os.system("mv " + item['url'][item['url'].rfind('/')+1:] + " " + item['localfile'])
for key, item in fileDefs.items():
hold = pygrib.open(item['localfile'])
subsel = hold.select(forecastTime=fhr)
#Grab the first item
gribs[key] = grib_to_xs(subsel[1], "TT" + key)
hold.close()
The above code downloads two constant files (landsfc) at the two grid domains (0.25 and 0.5), then downloads two GRIB files at each of the resolutions as well. I'm trying to resample the 0.25 degree GRIB file (tmp_pres.grib2) to a 0.5 degree domain as such:
regridder = xe.Regridder(ds, gribs['dataset0.5'], 'bilinear')
print(regridder)
ds2 = regridder(ds)
My issue is that I generate two warning messages when trying to use the regridder:
/media/robert/HDD/Anaconda3/envs/wrf-work/lib/python3.8/site-packages/xarray/core/dataarray.py:682: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison
return key in self.data
/media/robert/HDD/Anaconda3/envs/wrf-work/lib/python3.8/site-packages/xesmf/backend.py:53: UserWarning: Latitude is outside of [-90, 90]
warnings.warn('Latitude is outside of [-90, 90]')
The output xarray does have the correct coordinates, however the values inside the grid are way off (Outside the maxima/minima of the finer resolution grid), and exhibit these strange banding patterns that make no physical sense.
What I would like to know is, is this the correct process to upscale an array using xEMSF, and if not, how would I address the problem?
Any assistance would be appreciated, thanks!
I would recommend first trying conservative instead of bilinear (it's recommended on their documentation) and maybe check if you're using the parameters correctly because it seems something is wrong, my first guess would be that something you're doing moves the latitud around for some reason, I'm leaving the docs link here and hope someone knows more.
Regridder docs:
https://xesmf.readthedocs.io/en/latest/user_api.html?highlight=regridder#xesmf.frontend.Regridder.__init__
Upscaling recommendation (search for upscaling, there's also a guide for increasing resolution):
https://xesmf.readthedocs.io/en/latest/notebooks/Compare_algorithms.html?highlight=upscaling
Thanks to the documentation links and recommendations provided by MASACR 99, I was able to do some more digging into the xESMF package and to find a working example of resampling methods from the package author (https://github.com/geoschem/GEOSChem-python-tutorial/blob/main/Chapter03_regridding.ipynb), my issue was solved by two changes:
I changed the method from bilinear to conservative (This required also adding in two fields to the input array (boundaries for latitude and longitude).
Instead of directly passing the variable being resampled to the resampler, I instead had to define two fixed grids to create the resampler, then pass individual variables.
To solve the first change, I created a new function to give me the boundary variables:
def get_bounds(arr, gridSize):
lonMin = np.nanmin(arr["lon"].values)
latMin = np.nanmin(arr["lat"].values)
lonMax = np.nanmax(arr["lon"].values)
latMax = np.nanmax(arr["lat"].values)
sizeLon = len(arr["lon"])
sizeLat = len(arr["lat"])
bounds = {}
bounds["lon"] = arr["lon"].values
bounds["lat"] = arr["lat"].values
bounds["lon_b"] = np.linspace(lonMin-(gridSize/2), lonMax+(gridSize/2), sizeLon+1)
bounds["lat_b"] = np.linspace(latMin-(gridSize/2), latMax+(gridSize/2), sizeLat+1).clip(-90, 90)
return bounds
For the second change, I modified the regridder definition and application to use the statically defined grids, then passed the desired variable to resample:
regridder = xe.Regridder(get_bounds(gribs['dataset0.25'], 0.25), get_bounds(gribs['dataset0.5'], 0.5), 'conservative')
print(regridder)
ds2 = regridder(ds)
I'm creating an instance python command where the primary purpose is to generate objects in neat horizontal rows. Even though I can randomize rotation and set the range, I still can't figure out how to get the objects to appear in horizontal rows.
I already tried to use the xform command to get the objects to move along the x coordinates.
import maya.cmds as MC
import random as RN
def ChainmailGenerator():
thing = MC.ls(sl=True)
print thing
if not thing:
MC.error (" ***Error - you need to select an object *** ")
# create a group node
grp = MC.group(empty=True, name=thing[0] + '_grp#')
#Loop though the items below with the range of a
for i in range (0,25):
instanceObj = MC.instance(thing, name=thing[0]+'instance#', smartTransform=True)
rx = RN.uniform(-1,1)*5
ry = RN.uniform(-1,1)*5
rz = RN.uniform(-1,1)*5
MC.rotate (rx,ry,rz, instanceObj)
MC.xform (r=True, ro=(90, 0, 0) )
tx = 5
MC.xform ( instanceObj, t=(0,15+1,0))
MC.parent (instanceObj,grp)
print "*** chainmail ***"
ChainmailGenerator()
The expectations are for the objects to generate in horizontal increments as if they're forming neat rows.
here is an example to create 10 spheres along x, moving them with xform :
step = 1
tx = 0
for x in range(10):
sphere = cmds.polySphere()[0]
cmds.xform(sphere, t=[tx,0,0])
tx+= step
The reason yours is placing everything in the same place now is because you aren't multiplying it against a value that keeps increasing. Normally you could hard-code some random value to space each one out, but this would yield inconsistent results.
Here's a generic way to go about it that seems to work with any object.
The idea is to use the mesh's bounding box to determine what the spacing should be by looking at the size of its x axis. You can also move it in place with xform, but you do need to include its worldspace parameter so that it doesn't move it relative to its current position.
import maya.cmds as cmds
def cloneInRow(count):
# Get selection.
thing = cmds.ls(sl=True)
if not thing:
cmds.error("You need to select an object")
# Get selection's mesh shape.
mesh = cmds.listRelatives(thing[0], shapes=True, f=True, ni=True, type="mesh")
if not mesh:
cmds.error("Unable to find a mesh on the selected object")
# Determine spacing by looking at object's bounding box. Use its `x` axis size.
bb_min = cmds.getAttr(mesh[0] + ".boundingBoxMin")[0]
bb_max = cmds.getAttr(mesh[0] + ".boundingBoxMax")[0]
spacing = bb_max[0] - bb_min[0]
# Create a root transform to parent to.
grp = cmds.group(empty=True, name=thing[0] + '_grp#')
# Create instance, and move it in place.
for i in range (0, count):
instanceObj = cmds.instance(thing[0], name=thing[0] + 'instance' + str(i), smartTransform=True)
cmds.xform(instanceObj, ws=True, t=(i * spacing, 0, 0))
cmds.parent(instanceObj, grp)
cmds.select(grp)
cloneInRow(10)
With this I can take this crossbow:
And clone any of its objects and get nice spacing:
The only catch is rotation. If your pivot isn't centered to the mesh, then randomizing its rotation will lose its place in space (since rotating would also effects its position!) So if you got weird pivots then it won't look nice when you add back on rotations.
I have my geographical coordinates of rectangles represented as numpy ndarray like this:
(each row corresponds to a rectangle and each column contains its lower left and upper right longitudes and latitudes)
array([
[ 116.17265886, 39.92265886, 116.1761427 , 39.92536232],
[ 116.20749721, 39.90373467, 116.21098105, 39.90643813],
[ 116.21794872, 39.90373467, 116.22143255, 39.90643813]])
I want to call a coordinate-converting API whose input is a string like this:
'lon_0,lat_0;lon_1,lat_1;lon_2,lat_2;...;lon_n,lat_n'
So I wrote a stupid iteration to convert my ndarray to the required string like this:
coords = ''
for i in range(0, my_rectangle.shape[0]):
coords = coords + '{left_lon},{left_lat};{right_lon},{rigth_lat}'.format(left_lon = my_rectangle[i][0], left_lat = my_rectangle[i][1], \
right_lon = my_rectangle[i][2], rigth_lat = my_rectangle[i][3])
if i != my_rectangle.shape[0] - 1:
coords = coords + ';'
And the output is like this:
'116.172658863,39.9226588629;116.176142698,39.9253623188;116.207497213,39.9037346711;116.210981048,39.9064381271;116.217948718,39.9037346711;116.221432553,39.9064381271'
I'm wondering whether there exists a smarter & faster approach achieving this without iteration(or some helpful documentation I could refer to)?
Let's try using functional style:
values = [[ 116.17265886, 39.92265886, 116.1761427 , 39.92536232],
[ 116.20749721, 39.90373467, 116.21098105, 39.90643813],
[ 116.21794872, 39.90373467, 116.22143255, 39.90643813]]
def prettyPrint(coords):
return '{0},{1};{2},{3}'.format(coords[0], coords[1], coords[2], coords[3])
asString = formating(list(map(prettyPrint,values)))
print(";".join(asString)) #edited thanks to comments
map apply a function to each element of an iterable. So you define the process to apply on one element, and then using map replace each element by its result.
Hope you find it smarter ;)
Edit :
You can also write it like this :
asString = [prettyPrint(value) for value in values]
my question is how can i select random numbers of points of (for example in this script) lattice or vertex of an object or face or everything or totally random selection from a list in python.
please first explain random selection on this script
cm.select('ffd1Lattice.pt[:][:][:]',r=True)
and please after that explain random selection on lists and on every method.
best regards
import maya.cmds as cm
import sys
import random as rand
myList = cm.ls ( sl = True)
def softIt(*arg):
cm.polySmooth( c = True , dv = 1 , kb = False )
def randomize(*arg):
myList = cm.ls ( sl = True)
for i in myList:
cm.lattice( dv=(4, 5, 4), oc=True )
cm.select('ffd1Lattice.pt[:][:][:]',r=True)
cm.xform( r = True , t = [ rand.uniform(-1,1) , rand.uniform(-1,1) , rand.uniform(-1,1)] )
cm.headsUpMessage('this script just work with one object at time', verticalOffset=250)
cm.window( t = 'Randomaize' , s = False)
cm.columnLayout()
cm.button( l = 'do it' , c = randomize , w = 200)
cm.button( l = 'soft it' , c = softIt , w = 200)
cm.showWindow()
sys.stdout.write("this script just work with one object at time\t\"script by Amin khormaei\"")
If you aren't understanding that little snippet then you should first understand how list slicing works. These links should point you in the right direction.
The line:
cm.select('ffd1Lattice.pt[:][:][:]',r=True)
says basically 'select all the control points in the lattice'. There seems to be a bug, however, in maya 2011 (don't know about later) which will try to select points that dont exist. A 1x1x1 lattice should have 8 points numbers 0-1 in all three dimensions - but using your snippet and then calling ls on the result will report
// result: 'ffdLatticeShape.pt[0:2][0:2][0:2]' //
... at least it does on my machine -- and that should be impossible. I'd avoid using the [:] form with lattices (actually the [*] form has the same bug too. Ouch.). It works fine with regular vertices, however.
For your specific application, do you want to move all of the points by the same random amount -- which is what your snippet suggests -- or all of the points by different random amounts? Or random sets of points by a random amount? the code would be different for each alternative.