Correct way of updating an actor with changes applied to SetUserTransform - vtk

I have a poly actor which has a vtkBoxWidget that is connected to a callback as from the example in the docs:
def widget_callback(obj, event):
t = vtk.vtkTransform()
obj.GetTransform(t)
obj.GetProp3D().SetUserTransform(t)
All works fine and I am able to move and transform the actor with the widget but the transformation is applied to the UserTransform and not processed down to the actor properties.
So if I call:
actor.GetPosition()
It returns the initial position prior to making the changes with the widget. And if I call:
actor.GetUserTransform().GetPosition()
I get the updated position relative to the starting point of the first interaction.
Do I have to connect it all through a vtkTransformPolyDataFilter and then update the input connection to the mapper and also calculate the coordinate space offset or is there a simpler way of doing it? ... in short:
What is the correct way of updating an actor with changes applied to SetUserTransform?

After trying out many variations with vtkTransformPolyDataFilter and start/end interaction events linked to various steps in the process I found that for my purpose the absolute simplest way of handling this was simply linking the widget transformation directly to the actor properties:
def widget_callback(self, obj, event):
t = vtk.vtkTransform()
obj.GetTransform(t)
self.actor.SetPosition(t.GetPosition())
self.actor.SetScale(t.GetScale())
self.actor.SetOrientation(t.GetOrientation())

Related

Cannot pass in FlxTypedGroup class param using FlxG.overlap

I want the player to pickup objects in my game using the code below, but I am getting:
Error #1034: Type Coercion failed: cannot convert flixel::FlxSprite#51e1b69 to Player.
...
FlxG.overlap(weapons, players, onPickup)
}
private function onPickup(wep:Weapon, player:Player):Void
{
//access player function
}
I've initialized the players and weapons already as below, and added to the group
players= new FlxTypedGroup<Player>();
weapons= new FlxTypedGroup<Weapon>();
Weapon extends FlxSprite and Player extends FlxTypedGroup<FlxSprite>.
I'm using FlxTypedGroup because I want the player to have multiple sprites associated with it.
Please help so I can access the player class variables!
If I replace player:Player with player:FlxSprite there is no error, but then I can no longer access Player class functions.
I know this is probably a little bit late, but there are a few things you can try:
You could try using FlxSpriteGroup for Player instead of FlxTypedGroup. It may take some work to get it working the way you want.
Also, the reason why it's giving you an error, is because overlap and collide will (by default) drill down through your Groups until it comes to an actual object...
How to explain... If you have a FlxTypedGroup<Player> and your Player object extends FlxTypedGroup<PlayerPart> (if PlayerPart extends FlxSprite or something), when you do FlxG.overlap(weapons, players, onPickup), overlap is NOT going to pass the Player object, it's going to pass the PlayerPart object that overlapped - in fact, it's going to call onPickup once for EVERY PlayerPart object that overlaps a weapon - possibly the same one - this update.
You can use this behavior to your advantage, if you can figure it out - make your Player group contain several PlayerParts but set all of them to allowCollisions = NONE except for one which will be your hitbox, etc.
There's lots of things you can do, it's just figuring out the specifics. Good Luck!

Sharing variable between QWizard pages in Pyside/PyQt

I am building a QWidget in PySide, and running into an issue when trying to share data between pages.
To summarize I utilize user inputs from earlier pages to construct a list of custom objects, which I need to share with the following page.
At the beginning of my code I construct a custom object, with an attribute called .name (among other attributes)
class MyCustomClass():
def __init__(self, name, other_attributes)
self.name = name
...set other attributes
In my QWizard I open a file and make a list of names to match with another list of MyCustomClass objects. I then display the names alongside the matched name of the corresponding MyCustomClass object and prompt the user to confirm (or change), before moving to the next page.
Each match is stored as a tuple(name, MyCustomClass) and added to a list. I then wish to read this list from the next page in order to perform more operations. I'm trying to use .registerField, but I'm unsure of how to properly do so. My attempt is below.
First I make a QWizardPage, perform some code and then construct my matches. I made a function to return the value and used this for the .registerField
class ConfirmMatches(QWizardPage):
def __init__(self):
...
def initializePage(self):
# Code to make display and operations and make list of matches
...
self.matches = matches
self.registerField("matches", self, "get_matches")
def get_matches(self):
return self.matches
Then from my next page, I try to call the field, but I only return a None object.
class NextPage(QWizardPage):
def __init__(self):
...
def initializePage(self):
# Get relevant fields from past pages
past_matches = self.field("matches")
type(past_matches) is None, even though when I print self.matches in the previous page it clearly displays them all.
What am I doing wrong with the registerField?
Is there an easier way to share this type of data between pages?
I actually solved it myself. I was on the right track, just missing a few things, but I'll catalog here for anyone else with similar problems.
Like I said I have a list of matched objects, where each match is a list of a name, and the object that was found to correspond to that name, i.e. match = [name, MyCustomClass]
class ConfirmMatches(QWizardPage):
# Function to change list
def setList(self, new_list):
self.list_val = new_list
if self.list_val != []:
self.list_changed.emit()
# Function to return list
def readList(self):
return self.list_val
def __init__(self):
self.list_val = [] # Create initial value
# Code to initialize displays/buttons, and generate matches
...
# Here I assign the matches I made "matches", to the QProperty "match_list"
self.setList(matches)
# Then register field here.
# Instead of the read function, I call the object itself (not sure why, but it works)
self.registerField("registered_list", self, "match_list")
# Define "match_list" as a QProperty with read and write functions, and a signal (not used)
match_list = Property(list, readList, setList)
listChanged = Signal()
I made the list a QProperty and wrote the Read and Write functions, as well as a Signal (not used). Then, when registering the field, instead of putting the Read function (readList), I put the QProperty itself (match_list). Not sure why it works, but this conceivable could be used to register other custom objects.
If you want to explicitly set the value of the field matches in your ConfirmMatches page, you would need to do one of a few things:
Make an explicit call to self.setField any time your matches change.
Emit a signal every time your matches are changed after registering the property
Store your matches in one of the standard Qt inputs, like QLineEdit, and use that widget in the registerField call.
If you check the docs for QWizardPage.registerField, what it does is register to grab the named property of the passed in widget when the widget's signal is emitted. The way your code is now, you would need to add a signal to your ConfirmMatches page that would be emitted whenever your matches variable changes. Otherwise, your page doesn't know when the field should be updated.

In Visualization Toolkit, which types of objects need Update() and Modified() to be called and when?

I'm looking at some VTK code which may not be working correctly. Here's a snippet:
vtkSmartPointer<vtkCamera> cam = vtkSmartPointer<vtkCamera>::New();
cam->SetFocalPoint(0, 0, 0);
cam->SetViewUp(perp[0], perp[1], perp[2]);
cam->SetPosition(first_cam_pos);
cam->SetViewAngle(20);
cam->Modified();
It seems to me that the call to Modified() shouldn't be necessary, that calling the four Set functions should automatically signal that the camera has been modified.
Indeed, the Kitware VTK camera example doesn't use Modified() for the camera.
vtkSmartPointer<vtkCamera> camera = vtkSmartPointer<vtkCamera>::New();
camera->SetPosition(0, 0, 20);
camera->SetFocalPoint(0, 0, 0);
// Create a renderer, render window, and interactor
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
renderer->SetActiveCamera(camera);
In other cases, the potentially not-working VTK code I'm looking at uses Update() to manually update — not for the camera object, but elsewhere. Again, I think this is probably not necessary; but clearly Update() and Modified() are there for some reason.
Is there some rule for determining when Modified() and Update() need to be called and when they don't? Are there certain types of objects that need them and certain types that don't? Or is it related to the types of functions that are called on them?
I'm using VTK 6.1, but I'd love to get a general answer if there's some historical context here.
Update() is required when you want to use an object before the pipeline updates it for you. An example is:
vtkSmartPointer<vtkXMLPolyDataReader> reader = \
vtkSmartPointer<vtkPolyDataReader>::New();
reader->SetFileName("myfile.vtp");
// At this point, the reader hasn't yet read the file, so the
// following line with result in polydata being null (or
// something like that)
vtkPolyData* badPolydata = reader->GetOutput();
// However, once you tell the reader "update right now, don't wait
// for the pipeline to update you" with:
reader->Update();
// you can now get access to the data it has read:
vtkPolyData* goodPolydata = reader->GetOutput();
If, on the other hand, you are going to take the reader, attach it to a mapper, attach the mapper to an actor, and display the actor in the renderwindow, then at the time when the renderer says "Ok, now I need the data that drives this whole chain", the pipeline will go back and call Update() on the reader. This is the whole reason for/benefit of the pipeline execution model.
Modified() is required when you want to inform the pipeline "on the next pass, you need to re-process this object". This is done internally by most of the Set* functions, so I guess you just have to look at the implementation to see if Modified() is getting called or not by whatever function you've called that you expect to take effect the next pass through the pipeline.

Connecting an overloaded PyQT signal using new-style syntax

I am designing a custom widget which is basically a QGroupBox holding a configurable number of QCheckBox buttons, where each one of them should control a particular bit in a bitmask represented by a QBitArray. In order to do that, I added the QCheckBox instances to a QButtonGroup, with each button given an integer ID:
def populate(self, num_bits, parent = None):
"""
Adds check boxes to the GroupBox according to the bitmask size
"""
self.bitArray.resize(num_bits)
layout = QHBoxLayout()
for i in range(num_bits):
cb = QCheckBox()
cb.setText(QString.number(i))
self.buttonGroup.addButton(cb, i)
layout.addWidget(cb)
self.setLayout(layout)
Then, each time a user would click on a checkbox contained in self.buttonGroup, I'd like self.bitArray to be notified so the corresponding bit in the array can be set/unset accordingly. For that I intended to connect QButtonGroup's buttonClicked(int) signal to QBitArray's toggleBit(int) method and, to be as pythonic as possible, I wanted to use new-style signals syntax, so I tried this:
self.buttonGroup.buttonClicked.connect(self.bitArray.toggleBit)
The problem is that buttonClicked is an overloaded signal, so there is also the buttonClicked(QAbstractButton*) signature. In fact, when the program is executing I get this error when I click a check box:
The debugged program raised the exception unhandled TypeError
"QBitArray.toggleBit(int): argument 1 has unexpected type 'QCheckBox'"
which clearly shows the toggleBit method received the buttonClicked(QAbstractButton*) signal instead of the buttonClicked(int) one.
So, the question is, how can I specify the signal connection, using new-style syntax, so that self.bitArray receives the buttonClicked(int) signal instead of the default overload - buttonClicked(QAbstractButton*)?
EDIT: The PyQT's New-style Signal and Slot Support documentation states you can use pyqtSlot decorators to specify which signal you want to connect to a given slot, but that is for a slot you are creating. What to do when the slot is from a "ready made" class? Is the only option subclassing it and then reimplementing the given slot with the right decorator?
While browsing for related questions I found this answer to be exactly what I needed. The correct new-style signal syntax for connecting only QButtonGroup's buttonClicked(int) signal to QBitArray's toggleBit(int), ignoring the other overloaded signatures, involves specifying the desired type in brackets, like this:
self.buttonGroup.buttonClicked[int].connect(self.bitArray.toggleBit)

Plone 4 search members with extended profiles

There is a need to extend memberdata on Plone 4 with certain schema and at the same time provide an efficient (that is, much better than linear) search among those profiles.
collective.examples.userdata seems to be an example on how to make userdata The Right Way, but what about searches? Are there any efficient search solutions, for example, using the catalog?
There is such thing as membrane, which can map users to content, but uses
Archetypes and quite old a product (maybe, my impression is wrong).
Still, for example, mapping userdata to Dexterity type instances could be fine.
The question is, is there any ready code out there or custom solution will be needed?
No, the only ready solution out there, as you said, is membrane. But IMO it's a complex and specific product so I don't think you really need it.
To reach your goal, you'll need a bit of development. More or less the way would be:
insert your users into the catalog
add all needed new indexes
create your custom search form with z3c.form
This is an overview (not detailed howto) of an implementation:
Catalog tool done similarly to the reference_catalog from Archetypes. The most essential parts:
from Products.ZCatalog.ZCatalog import ZCatalog
class MemberdataCatalog(UniqueObject, ZCatalog):
implements(IMemberdataCatalog)
...
security.declareProtected(ManageZCatalogEntries, 'catalog_object')
def catalog_object(self, obj, uid=None, idxs=[],
update_metadata=1, pghandler=None):
w = obj
if not IIndexableObject.providedBy(obj):
wrapper = component.queryMultiAdapter((obj, self), IIndexableObject)
if wrapper is not None:
w = wrapper
ZCatalog.catalog_object(self, w, w and str("/".join(w.getPhysicalPath())), idxs,
update_metadata, pghandler=pghandler)
(with all GenericSetup things, also can be done similarly to Archetypes)
Subscribers for IPrincipalCreatedEvent, IPrincipalDeletedEvent, IConfigurationChangedEvent
(the latter one needs event.context.class._name_ in ('UserDataConfiglet', 'PersonalPreferencesPanel', 'UserDataPanel') to be handled - unfortunately, Plone has no specific events for profile data changes). See PAS on how those work and which parameters
event handlers receive.
A view /memberdata/username for the catalog to address and reindex those users. The "username" done by bobo traverse and returns an wrapped user with properties,
needed for indexes and metadata.
The http://plone.org/products/collective.examples.userdata is a good guide how to actually extend the user profile.
Apart from that, an adapter is needed
class IndexableAdapter(EnhancedUserDataPanelAdapter):
implements(IIndexableObject)
adapts(IMemberData, IMemberdataCatalog)
def __init__(self, context, catalog):
self.context = context
self.userid = context.getId()
self.catalog = catalog
def getPhysicalPath(self):
return make_physical_path(self.userid) # path to the view, which "fakes" an object
def __getattr__(self, name):
""" Proxing attribute accesses. """
return getattr(self.context, name)
# Specific indexer
def SearchableTextIntra(self):
...
Here EnhancedUserDataPanelAdapter has been derived and extended from UserDataPanelAdapter.
The IMemberdataCatalog is the interface of the catalog.
It is important to put everything into metadata, even width/height of the portrait,
because using .getObject() made the whole thing hundreds of times (!) slower.
The group memberships were handled separately, because there are no events, which
signify changes in the groups, needed to reindex some or all memebrs.

Resources