diff --git a/demos/api/t8.py b/demos/api/t8.py new file mode 100644 index 0000000000000000000000000000000000000000..3edd9f7b0314b0f74eaef6cc162b3bda3979e1e7 --- /dev/null +++ b/demos/api/t8.py @@ -0,0 +1,184 @@ +# This file reimplements gmsh/tutorial/t8.geo in Python. +# It demonstrates post-processing, animations and using options. + +import gmsh + +model = gmsh.model +factory = model.geo + +# adapted t1.py section {{{ + +gmsh.initialize() +gmsh.option.setNumber("General.Terminal", 1) + +lc = 1e-2 +factory.addPoint(0, 0, 0, lc, 1) +factory.addPoint(.1, 0, 0, lc, 2) +factory.addPoint(.1, .3, 0, lc, 3) +factory.addPoint(0, .3, 0, lc, 4) + +factory.addLine(1, 2, 1) +factory.addLine(3, 2, 2) +factory.addLine(3, 4, 3) +factory.addLine(4, 1, 4) + +factory.addCurveLoop([4, 1, -2, 3], 1) +factory.addPlaneSurface([1], 1) + +model.addPhysicalGroup(0, [1, 2], 1) +model.addPhysicalGroup(1, [1, 2], 2) +model.addPhysicalGroup(2, [1], 6) + +model.setPhysicalName(2, 6, "My surface") + +model.geo.synchronize() +# }}} + +# -- begin t8.py -- + +# add post-processing views to work on +gmsh.merge("view1.pos") +gmsh.merge("view1.pos") +gmsh.merge("view4.pos") # contains 2 views inside + +# set general options +option = gmsh.option + +option.setNumber("General.Trackball", 0) + +option.setNumber("General.RotationX", 0) +option.setNumber("General.RotationY", 0) +option.setNumber("General.RotationZ", 0) + +white = (255, 255, 255) +black = (0, 0, 0) + +# Color options are special +# Setting a color option of "X.Y" actually sets the option "X.Color.Y" +# Sets "General.Color.Background", etc. +option.setColor("General.Background", white[0], white[1], white[2]) + +# We can make our own shorter versions of repetitive methods +set_color = lambda name, c: option.setColor(name, c[0], c[1], c[2]) +set_color("General.Foreground", black) +set_color("General.Text", black) + +option.setNumber("General.Orthographic", 0) +option.setNumber("General.Axes", 0); option.setNumber("General.SmallAxes", 0) + +# set options for each view + +# If we were to follow the geo example blindly, we would +# read the number of views from the relevant option value +# +# Make sure to cast to int since getNumber returns a float +# v0 = int(option.getNumber("PostProcessing.NbViews")) - 4 +# v1 = v0 + 1; v2 = v0 + 2; v3 = v0 + 3 + +# A nicer way is to use gmsh.view.getTags() +view_tags = [v0, v1, v2, v3] = gmsh.view.getTags() + +# View name format helper function -- Returns "View[X]." for an input of X +view_fmt = lambda v: "View[" + str(v) + "]." + +# option setter +def set_opt(name, val): + # if it's a string, call the string method + val_type = type(val) + if val_type == type("str"): + option.setString(name, val) + # otherwise call the number method + elif val_type == type(0.5) or val_type == type(1): + option.setNumber(name, val) + else: + print("error: bad input to set_opt: " + name + " = " + str(val)) + print("error: set_opt is only meant for numbers and strings, aborting") + quit(1) + +# We'll use this helper function for our views +set_view_opt = lambda v_num, name, val: set_opt(view_fmt(v_num) + name, val) + +# v0 +set_view_opt(v0, "IntervalsType", 2) +set_view_opt(v0, "OffsetZ", 0.05) +set_view_opt(v0, "RaiseZ", 0) +set_view_opt(v0, "Light", 1) +set_view_opt(v0, "ShowScale", 0) +set_view_opt(v0, "SmoothNormals", 1) + +# v1 +set_view_opt(v1, "IntervalsType", 1) +# can't set ColorTable in API yet +# option.setColorTable(view_opt[v1] + "ColorTable", "{ Green, Blue }") +set_view_opt(v1, "NbIso", 10) +set_view_opt(v1, "ShowScale", 0) + +# v2 +set_view_opt(v2, "Name", "Test...") +set_view_opt(v2, "Axes", 1) +set_color(view_fmt(v2) + "Axes", black) +set_view_opt(v2, "IntervalsType", 2) +set_view_opt(v2, "Type", 2) +set_view_opt(v2, "IntervalsType", 2) +set_view_opt(v2, "AutoPosition", 0) +set_view_opt(v2, "PositionX", 85) +set_view_opt(v2, "PositionY", 50) +set_view_opt(v2, "Width", 200) +set_view_opt(v2, "Height", 130) + +# v3 +set_view_opt(v3, "Visible", 0) + +t = 0 +# step through time for each view +for num in range(1, 4): + + # update timesteps + for v in view_tags: + set_view_opt(v, "TimeStep", t) + + # helper function to match the geo file's +=, -= operators for numbers + adjust_num_opt = lambda name, diff: set_opt(name, option.getNumber(name) + diff) + + current_step = option.getNumber(view_fmt(v0) + "TimeStep") + max_step = option.getNumber(view_fmt(v0) + "NbTimeStep") - 1 + if current_step < max_step: + t = t + 1 + else: + t = 0 + + v0_max = option.getNumber(view_fmt(v0) + "Max") + adjust_num_opt(view_fmt(v0) + "RaiseZ", 0.01 / v0_max * t) + + if num == 3: + set_opt("General.GraphicsWidth", option.getNumber("General.MenuWidth") + 640) + set_opt("General.GraphicsHeight", 480) + + frames = 50 + for num2 in range(frames): + adjust_num_opt("General.RotationX", 10) + set_opt("General.RotationY", option.getNumber("General.RotationX") / 3) + adjust_num_opt("General.RotationZ", 0.1) + gmsh.fltk.wait(0.01) # open the GUI, wait for 0.01s and resume execution + gmsh.graphics.draw() + + # write out the graphics scene to an image file + # Gmsh will try to detect the file extension + if num == 3: + gmsh.write("t2-{:.2g}.gif".format(num2)) + gmsh.write("t2-{:.2g}.ppm".format(num2)) + gmsh.write("t2-{:.2g}.jpg".format(num2)) + + if num == 3: + pass + # Here we could make a system call to generate a movie. For example: + # import subprocess + # call_ffmpeg1 = "ffmpeg -hq -r 5 -b 800 -vcodec mpeg1video -i t8-%02d.jpg t8.mpg" + # call_ffmpeg2 = "ffmpeg -hq -r 5 -b 800 -i t8-%02d.jpg t8.asf" + # subprocess.call(call_ffmpeg1.split(' ')) + # subprocess.call(call_ffmpeg2.split(' ')) + +# show the GUI at the end +gmsh.fltk.run() + +gmsh.finalize()