Get bone ID from its name or from the index on skin list in MaxScript - scripting

I have an bone name (e.g. Bone002) and I want to get the bone ID for it (not the index in skin list, but the ID that is required e.g. in skinOps.SetVertexWeights).
I know that reverse operation looks like this:
skinMod = $.modifiers[#skin]
boneListIndex = (skinOps.GetVertexWeightBoneID skinMod v w)
local boneName = skinOps.GetBoneNameByListID skinMod boneListIndex 0
But how to get boneID? I already have boneListIndex and boneName.
I assume that all bones have unique names.

What version of 3dsMax are you using? I remember the documentation being rather confusing here. Bone_ID and vertex_bone_integer are interchangeable in this case - I just tested on a simple mesh and SkinOps.GetVertexWeightBoneID and SkinOps.SetVertexWeights work with the same bone indices.
If you want to locate by name, then you need to match the indices by name. Create an array with your bone names:
boneNames = for i=1 to (skinOps.GetNumberBones skinMod) collect (skinOps.GetBoneName skinMod i 0)
Then you can use your favorite search method and retrieve the index, a simple findItem works well here:
boneIndex = findItem boneNames "Bone002"
Keep in mind that the skinOps.GetBoneName function is slightly borked; the last parameter is meant to determine whether to return the actual node or its name - regardless the setting, only the name string is ever returned. This means that if you have two bones in the skin with the same name, you'll have to find a clever way on how to get the appropriate node.

If what you want is the boneID corresponding to the bone owning the skin weights, then you need one more step, because skinOps.GetBoneName returns the parent of the bone owning the weights:
fn GenerateBoneList sk =
(
boneNames = #()
for i=1 to (skinOps.GetNumberBones skinMod) do
(
local aName = skinOps.GetBoneName skinMod i 0
local inSkinUI = (execute ("$" + aName)).children[1].name
append boneNames inSkinUI
)
return boneNames
)
Now, when you use finditem, you can use the name of the bone that owns the skin weights
finditem boneNames $Bone002.name

Related

why are objects clipping behind each other?

I'm making a script that sorts the depth for my objects by prioritizing the y variable, but then afterwards checks to see if the objects that are touching each other have a higher depth the further to the right they are, but for some reason the last part isn't working.
Here's the code:
ds_grid_sort(_dg,1,true);
_yy = 0;
repeat _inst_num
{
_inst = _dg[# 0, _yy];
with _inst
{
with other
{
if (x > _inst.x and y = _inst.y)
{
_inst.depth = depth + building_space;
}
}
}
_yy++;
}
I've identified that the problem is that nothing comes out as true when the game checks the y = _inst.y part of the _inst statement, but that doesn't make any sense seeing how they're all at the same y coordinate. Could someone please tell me what I'm doing wrong?
As Steven mentioned, it's good practice to use double equal signs for comparisons (y == _inst.y) and a single equals sign for assignments (_yy = 0;), but GML doesn't care if you use a single equals sign for comparison, so it won't be causing your issue. Though it does matter in pretty much every other language besides GML.
From what I understand, the issue seems to be your use of other. When you use the code with other, it doesn't iterate through all other objects, it only grabs one instance. You can test this by running this code and seeing how many debug messages it shows:
...
with other
{
show_debug_message("X: "+string(x)+"; Y: "+string(y));
...
You could use with all. That will iterate through all objects or with object, where object is either an object or parent object. That will iterate through all instances of that object. However, neither of these functions check whether the objects overlap (it's just going to iterate over all of them), so you'll have to check for collisions. You could do something like this:
...
with all
{
if place_meeting(x, y, other)
{
if (x > _inst.x and y = _inst.y)
{
_inst.depth = depth + building_space;
}
}
...
I don't know what the rest of your code looks like, but there might be an easier way to achieve your goal. Is it possible to initially set the depth based on both the x and y variables? Something such as depth = -x-y;? For people not as familiar with GameMaker, objects with a smaller depth value are drawn above objects with higher depth values; that is why I propose setting the depth to be -x-y. Below is what a view of that grid would look like (first row and column are x and y variables; the other numbers would be the depth of an object at that position):
Having one equation that everything operates on will also make it so that if you have anything moving (such as a player), you can easily and efficiently update their depth to be able to display them correctly relative to all the other objects.
I think it should be y == _inst.y.
But I'm not sure as GML tends to accept such formatting.
It's a better practise to use == to check if they're equal when using conditions.

Reading TTree Friend with uproot

Is there an equivalent of TTree::AddFriend() with uproot ?
I have 2 parallel trees in 2 different files which I'd need to read with uproot.iterate and using interpretations (setting the 'branches' option of uproot.iterate).
Maybe I can do that by manually obtaining several iterators from iterate() calls on the files, and then calling next() on each iterators... but maybe there's a simpler way akin to AddFriend ?
Thanks for any hint !
edit: I'm not sure I've been clear, so here's a bit more details. My question is not about usage of arrays, but about how to read them from different files. Here's a mockup of what I'm doing :
# I will fill this array and give it as input to my DNN
# it's very big so I will fill it in place
bigarray = ndarray( (2,numentries),...)
# get a handle on a tree, just to be able to build interpretations :
t0 = .. first tree in input_files
interpretations = dict(
a=t0['a'].interpretation.toarray(bigarray[0]),
b=t0['b'].interpretation.toarray(bigarray[1]),
)
# iterate with :
uproot.iterate( input_files, treename,
branches = interpretations )
So what if a and b belong to 2 trees in 2 different files ?
In array-based programming, friends are implicit: you can JOIN any two columns after the fact—you don't have to declare them as friends ahead of time.
In the simplest case, if your arrays a and b have the same length and the same order, you can just use them together, like a + b. It doesn't matter whether a and b came from the same file or not. Even if I've if these is jagged (like jets.phi) and the other is not (like met.phi), you're still fine because the non-jagged array will be broadcasted to match the jagged one.
Note that awkward.Table and awkward.JaggedArray.zip can combine arrays into a single Table or jagged Table for bookkeeping.
If the two arrays are not in the same order, possibly because each writer was individually parallelized, then you'll need some column to act as the key associating rows of one array with different rows of the other. This is a classic database-style JOIN and although Uproot and Awkward don't provide routines for it, Pandas does. (Look up "merging, joining, and concatenating" in the Pandas documenting—there's a lot!) You can maintain an array's jaggedness in Pandas by preparing the column with the awkward.topandas function.
The following issue talks about a lot of these things, though the users in the issue below had to join sets of files, rather than just a single tree. (In principle, a process would have to look ahead to all the files to see which contain which keys: a distributed database problem.) Even if that's not your case, you might find more hints there to see how to get started.
https://github.com/scikit-hep/uproot/issues/314
This is how I have "friended" (befriended?) two TTree's in different files with uproot/awkward.
import awkward
import uproot
iterate1 = uproot.iterate(["file_with_a.root"]) # has branch "a"
iterate2 = uproot.iterate(["file_with_b.root"]) # has branch "b"
for array1, array2 in zip(iterate1, iterate2):
# join arrays
for field in array2.fields:
array1 = awkward.with_field(array1, getattr(array2, field), where=field)
# array1 now has branch "a" and "b"
print(array1.a)
print(array1.b)
Alternatively, if it is acceptable to "name" the trees,
import awkward
import uproot
iterate1 = uproot.iterate(["file_with_a.root"]) # has branch "a"
iterate2 = uproot.iterate(["file_with_b.root"]) # has branch "b"
for array1, array2 in zip(iterate1, iterate2):
# join arrays
zippedArray = awkward.zip({"tree1": array1, "tree2": array2})
# zippedArray. now has branch "tree1.a" and "tree2.b"
print(zippedArray.tree1.a)
print(zippedArray.tree2.b)
Of course you can use array1 and array2 together without merging them like this. But if you have already written code that expects only 1 Array this can be useful.

Get array of data based on hierarchical edges sequence in cytoscape.js

I use cytoscape.js to organize an flow of nodes that represent an tasks execution. Sometimes an task is not created hierarchicly.
At least in a visual way, edges gives the correct sequence.
I would like to get the hierarchical sequence based on the edges and list their data as an array. Each index will be dispposed as edges says so.
The image above represent a sequence based on the edges arrows. I would like to transform this edges/arrows sequence into a perfect sequence of data (array).
The cytoscape.elements().toArray() method transform visual to array, but it is delivered the same sequence of the original data.
How can it be done? Is there some method in cytoscape core?
The easiest way would be to give the nodes id's with the corresponding numbers in your sequence:
-> The first task to execute has the id 1, the second has the id 2...
After initialization you can then do a loop with n iterations (n = number of nodes in cy) and get the nodes one by one. That way you can access their information and enter this data into an array:
for (i = 0; i < cy.nodes().length; i++) {
var curr = cy.nodes("[id = '" + i + "']"); // This way you get the node with the id == i
//do stuff
array[i] = theDataYouNeed;
}
If you want the nodes to be in a hierarchy, you would have to rethink your layout. An hierarchy in cytoscape can be achieved by "directed acyclic graph" (= dagre in cytoscape).

IDL variable name based on input file name

I'm trying to load multiple images and want to automate the variable naming to make the variable name = the file input name.
For example:
image1=read_binary('image1.img',DATA_START=0,DATA_TYPE=1,DATA_DIMS=[450, 750,3], ENDIAN=native)
Just wondering if this is possible and how?
You could put all of the image names in a string array and loop over that. If your images are .png then I would suggest that you use the read_png function. This may not be the most efficient, but if the images all have the same size then it is easy to stack them all in a cube like:
;Make a string array containing the names of the images
names = ['image2.png', 'image2.png', 'image3.png']
;Make a byte array to contain the x and y dimensions, the rgb, for each image
image_stack = bytarr(dimension1,dimension2,3,n_elements(names))
for i=0,n_elements(names)-1 do begin
img = READ_PNG(names[i],rpal,gpal,bpal)
image_stack[*,*,0,i] = rpal ;set r channel of image i
image_stack[*,*,1,i] = gpal ;set g channel of image i
image_stack[*,*,2,i] = bpal ;set b channel of image i
endfor
Now you have all of the images in a cube where the last dimension is the image number.
I very much prefer the way with a 3D (or 4D) array like veda905 outlined above.
However, if you really want to create a new, independent variable for each image, you can create your own command as a string and execute it via the execute command.
Assuming you have the filenames in an array like above:
;Make a string array containing the names of the images
names = ['image2.png', 'image2.png', 'image3.png']
; you need to supply the filename extension
varnames = FILE_BASENAME(names, '.png')
FOR i=0, N_ELEMENTS(varnames)-1 DO BEGIN
result = EXECUTE(varnames[i] + '= READ_PNG(names[' + STRING(i) + '])')
ENDFOR
Hashes are built to do this:
h = hash()
image1 = read_binary('image1.img', data_start=0, data_type=1, $
data_dimes=[450, 750, 3], endian=native)
h['image1.img'] = image1
And then later retrieve with:
tv, h['image1.img']
Mike's #mgalloy answer is the best way to do this.
The others could have issues depending on your situation (e.g., if you have have a lot of files or need to run this in the Virtual Machine), but certainly work.
Before hashes, this is how I used to do it:
files = ['image1.img', 'image2.img', 'image3.img']
FOR i=0, N_Elements(files)-1 DO BEGIN
varName = File_BaseName(files[i], '.png')
thisImg = Read_Binary(files[i])
(Scope_VarFetch(varName), Level=0, /Enter) = thisImg
ENDFOR
The Scope_VarFetch is the magic command that creates a variable with a particular name (given as a string), and assigns data to it. You can also retrieve variables in a similar manner.
But, it's much easier to use some of the more modern features of IDL. That same code using hashes and a ForEach?
files = ['image1.img', 'image2.img', 'image3.img']
imgs = Hash()
FOREACH, f, files Do imgs[f] = Read_Binary(files[i])
If order matters, you can use a ordered hash

Is there a way to iterate over Bio.trie in a memory-friendly way?

I would like to use a Bio.trie as an index for sequences to count how many time each of them occurs in a dataset. The index is created like this:
seqs = trie()
for seq in dataset:
if seqs.has_key(seq):
seqs[seq] += 1
else:
seqs[seq] = 1
And after that I would like to extract some information from the trie, e.g. a list of sequences that have been counted only once. It's possible to do it like this:
singletons = []
for seq in seqs.keys():
if seqs[seq] == 1:
singletons.append(seq)
The problem is that the machine I'm working on is low on memory and calling trie.keys() returns a list object which is roughly as large as the trie itself. Is it possible to iterate over the keys using a generator instead of a list, so that you would only get one key at a time?