Forum Navigation
You need to log in to create posts and topics.

Looping for PythonViewportOverlay

Hi,

I've been trying to write a script to simpify some of my analysis from MD simulations and I'm having some trouble with the order of operations in the script. I create a pipeline and append all the necessary modifiers that I need and compute the data for the frame. What I am trying to accomplish after is adding arrows to point at all the dislocations that are present in the viewport as well as annotating them with their Burgers vector. For now, I just want to get the arrows to display properly. When I run the following code:

vp = Viewport(type=Viewport.Type.Ortho,
camera_dir = (-0.0788086, 0.408561, -0.909322),
camera_pos = (-373.214, -20.928, 22.9424),
fov = 140)

def render_arrow(args):

for segment in data.dislocations.segments:

x,y = args.project_point(segment.points.mean(axis=0))
arrow_shape = QPolygonF()
arrow_shape.append(QPointF(0,0))
arrow_shape.append(QPointF(10,10))
arrow_shape.append(QPointF(10,5))
arrow_shape.append(QPointF(40,5))
arrow_shape.append(QPointF(40,-5))
arrow_shape.append(QPointF(10,-5))
arrow_shape.append(QPointF(10,-10))
args.painter.setPen(QPen())
args.painter.setBrush(QBrush(QColor(255,0,0)))
args.painter.translate(QPointF(x, y))
args.painter.rotate(-15.0)
args.painter.translate(QPointF(25,0))
args.painter.scale(2,2)
args.painter.drawPolygon(arrow_shape)

vp.overlays.append(PythonViewportOverlay(function=render_arrow))

vp.render_image(filename='test.png',size = (1000,1000),renderer = OpenGLRenderer())

 

Only one arrow is displayed. How would I add arrows to every single dislocation? What would be the correct order of operations?

I appreciate any support or hint in the right direction.

 

 

Update: For anyone wishing to do similar things, I have attached my script to this post.

Uploaded files:
  • You need to login to have access to uploads.

Hi Vlad,

I think you are doing this mostly right, but there is one issue in your code that leads to a wrong placement of the arrows. The QPainter::translate() and QPainter::rotate() methods modify the current transformation matrix in an incremental fashion. Thus, any translations/rotations you apply repeatedly add up during the loop iterations.

To avoid this, you should save the original transformation matrix of the QPainter (which is prescribed by OVITO) and restore it again after each loop iteration, i.e.

original_transformation = args.painter.worldTransform()
args.painter.translate(QPointF(x, y))
...
args.painter.drawPolygon(arrow_shape)
args.painter.setWorldTransform(original_transformation)

-Alex

Hi Alex,

Thank you so much, that solved my problem. Now for a follow up question, if instead of rendering a single frame, I wanted to use the render_anim method, would I have to create a custom modifier and write that (the dislocation arrows and labelling) in there and append it to the pipeline?

 

Vlad

I'm glad I was able to help. No, registering the PythonViewportOverlay with the Viewport just once is sufficient. While rendering an animation with render_anim(), your render_arrow() function will be called repeatedly by the system (once per rendered frame).

However, it's important that you make your render_arrow() function operate on the current dislocation data of the frame being rendered (assuming you are rendering a simulation trajectory with moving dislocations). This is done by inserting the statement data = pipeline.compute(args.frame) at the top of your viewport overlay function to query the data pipeline for the analysis results at the current animation frame.

Perfect, that makes a lot of sense now. Thank you so much.  I will edit my original post afterwards and attach my python file in case someone else has the same problem.