Manim: How to update function with defined time interval - python

I am currently learning manim and I am trying to replicate 3b1b's fourier drawing animations. (https://www.youtube.com/watch?v=-qgreAUpPwM)
I've got everything set up and the basics of the animation is working. The only problem I've got is, that it doesnt draw the wanted figure. I am currently using valuetracker to update the function. To get the animation right, I think i need to have a constant "dt" between each updating, but I don't know how to implement that. I am not sure if valuetracker is the right way to do it. I've tried the using "dt" like in Theorem of Beethoven tutotial 8.3 (https://www.youtube.com/watch?v=J6qT8YZQeOw&t=506s). Wasn't able to make it work like that though.
Here is the code that updates all mobjects in the animation:
def update_fct(c): # Updating mobject
for k in range(len(c)):
c[k].become(c[k].start)
for j in range(k): # nth Circles rotates around all circles before
c[k].rotate(TAU * values[j, 2] * alpha.get_value(), about_point=c[j].get_center())
dots[k].move_to(circles[k].points[0]) # move dots to new position
if k == N - 1: # Only track path of last dot
old_path = paths[k].copy()
old_path.append_vectorized_mobject(Line(old_path.points[-1], dots[k].get_center()))
old_path.make_smooth()
paths[k].become(old_path)
lines[k].put_start_and_end_on(circles[k].get_center(), dots[k].get_center()) # Update Arrow
circles.add_updater(update_fct)
self.add(circles,lines,paths[N-1]) # Only add circles, arrows and last path
self.play(
alpha.set_value, 1,
rate_func=linear,
run_time=10
)
circles.clear_updaters()

Related

Moving the cursor in relation to a certain fix-point in Python

is there any possibility to move the cursor in Python with % starting from a certain coordinate like (1,1)?
I am using pyautogui atm to automate and I thought it would be quite convenient if this is independent from the monitor size making it universal.
Thanks for your help in advance!
It's possible indirectly. As detailed at the top of the Mouse Control Functions page of the documentation, you can get the screen size using the size() function (which returns a tuple of (X, Y)). You can then do the math to figure out how many screen pixels equal the percentage you're looking for, then call moveTo() to go there.
# script to move mouse 50% to the right and down
import pyautogui as pag
percentage = 0.5
cur_X, cur_Y = pag.position() # current X and Y coordinates
size_X, size_Y = pag.size() # screen size
goto_X = (size_X - cur_X) * percentage + cur_X # current location plus half
goto_Y = (size_Y - cur_Y) * percentage + cur_Y # the distance to the edge
pag.moveTo(goto_X, goto_Y, 1) # move to new position, taking 1 second

Python - plt.savefig() resulting in blank image without plt.show()

I work on a crowd simulation, and I tried to get a simple representation at a given time like this : new to the site so here is the link. I work with Spyder and the code works wonderfully when I display the image in ipython with plt.show(), but when i try to save the images with plt.savefig() (I removed plt.show() prior to that, not the issue) i ended up with blank images. Here is the code :
p,v,t = resolve() #p[c][i] is the position vector of individual i at time t[c]
N = len(t) # number of instant
n = len(m) # number of individual
murs_x = [w[0] for w in W] # wall points x coordinates
murs_y = [w[1] for w in W] # wall points y coordinates
conv = 39.3701 #inch/m
L = longueur*conv/50 # width of figure
H = (largeur + decalage)*conv/50 # height of figure
for c in range(N):
fig1 = plt.figure(num="aff",figsize = (L,H), dpi = 200) # arbitrary num, allow to recreate the figure
ax = fig1.add_axes([1,1,1,1])
ax.set_axis_off() # visual purpose
ax.set_frame_on(False) # visual purpose
ax.axis([0,longueur,0,largeur+decalage])
ax.scatter(murs_x,murs_y,s=0.01,marker='.')
for i in range(n):
if p[c][i][1] <= (largeur + r[i]): # presence condition for individual i
ax.add_artist(plt.Circle((p[c][i][0], p[c][i][1]), r[i], alpha=1))
# drawing of the circle representing individual i
# here is the plt.show(), unused
fig1.savefig(str(c)+".png") # trying to save instant c visual represention
fig1.clf()
Moreover, without the 2 lines for visual purposes, the images are not totally blank but rather like this : another link.
I first attempted to use matplotlib.animation to create a video, however i had the same issue of a blank video with 2 cropped zeros in the upper right corner. I suppose that the issue is linked to the artist class (I had better results using scattered points instead of circles to represent each individual) but I am a beginner and do not know how to handle it precisely. At least the size of the image is the one expected one.
Thanks for reading this.

How to find face neighbours in Maya?

I have a problem where I need to select faces that are next to one pre-selected face.
This may be done easily but the problem is that when I get a neighbour face I need to know in which direction it is facing.
So now I am able to select faces which are connected with an edge but I can't get the face that is for example left or right from the first selected face. I have tried multiple approaches but can't find the solution.
I tried with:
pickWalk - cmds.pickWalk()- problem with this is that it's behavior can't be predicted, since it walks the mesh from the camera perspective.
polyInfo - cmds.polyInfo()- this is a very useful function and closest to the answer. In this approach I try to extract edges from a face and then see which are neighbours to that face with edgeToFace(). This works well but doesn't solve my problem. To elaborate, when polyInfo returns faces that share edges, it doesn't return them in a way that I can always know that edgesList[0] (for example) is the edge that points left or right. Hence if I use this on different faces the resulting face may be facing in a different direction in each case.
Hard way with many conversions from vertex to edge then to face etc. But still again it's the same problem where I don't know which edge is the top or left one.
conectedFaces()method who i call on selected face and it returns faces which are connected to first face,but still it`s the same problem,i dont know which face is facing which way.
To be clear I'm not using a pre-selected list of faces and checking them, but I need to know the faces without knowing or keeping their names somewhere. Does someone know a way that works with selection of faces?
To elaborate my question I made an image to make it clear:
As you can see from the example if there is selected face I need to select any of pointed faces, but that must be exact face I want to select. Other methods select all neighbour faces, but I need method that I can say "select right" and will select right one from first selected face.
This is one solution that would be fairly consistent under the rule that up/down/left/right is aligned with the mesh's transformation (local space), though could be world space too.
The first thing I would do is build a face relative coordinate system for every mesh face using the average face vertex position, face normal, and world space Y axis of the mesh's transformation. This involves a little vector math, so I will use the API to make this easier. This first part will make a coordinate system for each face that we will store into lists for future querying. See below.
from maya import OpenMaya, cmds
meshTransform = 'polySphere'
meshShape = cmds.listRelatives(meshTransform, c=True)[0]
meshMatrix = cmds.xform(meshTransform, q=True, ws=True, matrix=True)
primaryUp = OpenMaya.MVector(*meshMatrix[4:7])
# have a secondary up vector for faces that are facing the same way as the original up
secondaryUp = OpenMaya.MVector(*meshMatrix[8:11])
sel = OpenMaya.MSelectionList()
sel.add(meshShape)
meshObj = OpenMaya.MObject()
sel.getDependNode(0, meshObj)
meshPolyIt = OpenMaya.MItMeshPolygon(meshObj)
faceNeighbors = []
faceCoordinates = []
while not meshPolyIt.isDone():
normal = OpenMaya.MVector()
meshPolyIt.getNormal(normal)
# use the seconary up if the normal is facing the same direction as the object Y
up = primaryUp if (1 - abs(primaryUp * normal)) > 0.001 else secondaryUp
center = meshPolyIt.center()
faceArray = OpenMaya.MIntArray()
meshPolyIt.getConnectedFaces(faceArray)
meshPolyIt.next()
faceNeighbors.append([faceArray[i] for i in range(faceArray.length())])
xAxis = up ^ normal
yAxis = normal ^ xAxis
matrixList = [xAxis.x, xAxis.y, xAxis.z, 0,
yAxis.x, yAxis.y, yAxis.z, 0,
normal.x, normal.y, normal.z, 0,
center.x, center.y, center.z, 1]
faceMatrix = OpenMaya.MMatrix()
OpenMaya.MScriptUtil.createMatrixFromList(matrixList, faceMatrix)
faceCoordinates.append(faceMatrix)
These functions will look up and return which face is next to the one given in a particular direction (X and Y) relative to the face. This uses a dot product to see which face is more in that particular direction. This should work with any number of faces but it will only return one face that is in the most of that direction.
def getUpFace(faceIndex):
return getDirectionalFace(faceIndex, OpenMaya.MVector(0,1,0))
def getDownFace(faceIndex):
return getDirectionalFace(faceIndex, OpenMaya.MVector(0,-1,0))
def getRightFace(faceIndex):
return getDirectionalFace(faceIndex, OpenMaya.MVector(1,0,0))
def getLeftFace(faceIndex):
return getDirectionalFace(faceIndex, OpenMaya.MVector(-1,0,0))
def getDirectionalFace(faceIndex, axis):
faceMatrix = faceCoordinates[faceIndex]
closestDotProd = -1.0
nextFace = -1
for n in faceNeighbors[faceIndex]:
nMatrix = faceCoordinates[n] * faceMatrix.inverse()
nVector = OpenMaya.MVector(nMatrix(3,0), nMatrix(3,1), nMatrix(3,2))
dp = nVector * axis
if dp > closestDotProd:
closestDotProd = dp
nextFace = n
return nextFace
So you would call it like this:
getUpFace(123)
With the number being the face index you want to get the face that is "up" from it.
Give this a try and see if it satisfies your needs.
polyListComponentConversion
import pprint
init_face = cmds.ls(sl=True)
#get edges
edges = cmds.polyListComponentConversion(init_face, ff=True, te=True)
#get neighbour faces
faces = cmds.polyListComponentConversion(edges, fe=True, tf=True, bo=True)
# show neighbour faces
cmds.select(faces)
# print face normal of each neighbour face
pprint.pprint(cmds.ployInfo(faces,fn=True))
The easiest way of doing this is using Pymel's connectedFaces() on the MeshFace:
http://download.autodesk.com/us/maya/2011help/pymel/generated/classes/pymel.core.general/pymel.core.general.MeshFace.html
import pymel.core as pm
sel = pm.ls(sl=True)[0]
pm.select(sel.connectedFaces())

Faster way to partition a Face with Sketch in ABAQUS with scripting

My aim is to obtain a transition mapped quad meshing on a long rectangular region which is a parametrised model. The final mesh can be seen as follows:
The only way I could realise this final output mesh was to partition the face with sketch and then, using adequate mesh controls and seeding on the respective edges. For this reason, I started with generating a block on the left hand side of the geometry like this:
Thereafter, a "for" loop was used in the Python script running from the left hand side of the rectangular face to the right-most end and the final partitioned face looks like this:
So, I tried doing this in three ways.
Option 1: Place the sketcher window using findAt at the left hand side and then generate the block and with a "for" loop push the origin of the coordinate system of the sketcher window to the right incrementally all the way to the right-most side. In other words, the position of the block with respect to the origin stayed the same always and hence, when the origin moved from left to right, the block moved with it. So I had to open and clos "Partition Face with Sketch" as many times as the number of blocks required.
Option 2: The origin of the Sketcher window stayed at the same place (i.e. at 0.0, 0.0, 0.0) and the blocks were pushed to the right incrementally. In comparison with Option 1, here the relative position of the block with respect to the origin changed over each increment. Here also, "Partition Face with Sketch" was opened and closed as many times as the number of blocks required.
Option 3: I opened the "Partition Face with Sketch" only once and the origin stayed at the same place. Then I drew all these horizontal and vertical lines also with a "for" loop resulting in the final partitioned face.
All these methodologies work perfectly but are extremely time-consuming. Each of these methods takes almost from 8-12 minutes to finish generating all the blocks and hence, is not suitable for a convergence study.
Can anyone suggest a better solution to make this entire process faster, like in 3-4 minutes or so? Would really appreciate it. Thanks in advance.
EDIT: Here is the code guys:
# The arguments of the function "block" are the x and y coordinates of the
# 4 corners of the rectangle where the blocks have to be generated in.
def block(x_left, x_right, y_top, y_bottom):
# Opens the sketcher window
p = mdb.models['TDCB'].parts['Part_TDCB']
f, e, d = p.faces, p.edges, p.datums
t = p.MakeSketchTransform(sketchPlane=f.findAt(coordinates=(x_left + ((x_right - x_left) / 3), y_bottom + ((y_top - y_bottom) / 3), 0.0),
normal=(0.0, 0.0, 1.0)), sketchPlaneSide=SIDE1, origin=(x_left, y_bottom, 0.0))
s = mdb.models['TDCB'].ConstrainedSketch(name='__profile__', sheetSize=500.00,
gridSpacing=12.00, transform=t)
g, v, d1, c = s.geometry, s.vertices, s.dimensions, s.constraints
s.setPrimaryObject(option=SUPERIMPOSE)
p.projectReferencesOntoSketch(sketch=s, filter=COPLANAR_EDGES)
# The following block generates the first couple of horizontal lines
s.Line(point1=(block_width, 0.0), point2=(block_width, y_top)) # Line No.1
s.Line(point1=(0.0, y_coord[-2]), point2=(block_width, y_coord[-2])) # Line No.2
s.Line(point1=(0.0, y_coord[-3]), point2=(block_width, y_coord[-3])) # Line No.3
s.Line(point1=(0.0, y_coord[-4]), point2=(block_width, y_coord[-4])) # Line No.4
s.Line(point1=(0.0, y_coord[-5]), point2=(block_width, y_coord[-5])) # Line No.5
s.Line(point1=(0.0, y_coord[-6]), point2=(block_width, y_coord[-6])) # Line No.6
# Closes the sketcher window
p = mdb.models['TDCB'].parts['Part_TDCB']
f = p.faces
pickedFaces = f.findAt((x_left + ((x_right - x_left) / 3), y_bottom + ((y_top - y_bottom) / 3), 0.0))
e1, d2 = p.edges, p.datums
p.PartitionFaceBySketch(faces=pickedFaces, sketch=s)
s.unsetPrimaryObject()
del mdb.models['TDCB'].sketches['__profile__']
return
# Finally the blocks are generated using a "for" loop
for i in range(total_blocks):
block(x_left, x_right, y_top, y_bottom)
It seems you don't have to iterate the process of sketching as in ABAQUS Sketch you can use Linear Pattern to copy/duplicate the initial sketch (first block on the left side). This may make the whole process easier. Thanks.
Regards,
Longjie

Tetris [PyGame] - Let the shapes fall

I'm trying to clone the Tetris game and already have PyGame pick a random shape and display it. I drew an array-backed grid and 'told' PyGame to draw colored squares in certain cells in order to get the cells.
def iShape():
grid [0][5] = 3
grid [0][6] = 3
grid [0][7] = 3
grid [0][8] = 3
pygame.init()
this tells the system on which cell of the grid it will draw the square in order to get the shape.
def draw():
allShapes = ['''all Shapes that I defined''']
pick = random.choice (allShapes)
... #otherstuff
if pick == iShape:
if grid[row][column] == 3:
color = orange
#draw the squares
I have been trying to think of how I could let the shapes fall slowly so the player can move/rotate them before they hit the ground but none of my ideas work out. Does anyone have a suggestion?
try to create a def called clock or tick(anything) and have that control the drop speed. or you could youse the in built python timer by doin inport mathand there is a command to have times so you could have then drop a pice of the grid every second or something like that sry about the brightness
I've found a Tetris clone called Tetromino online. I can't quite say it will work as it probably uses a different code style, but you could get an idea from it. Its at the link https://inventwithpython.com/pygame/chapter7.html

Categories