Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
How to improve speed of drawing? Very slow scene view.
-
@marcin_dybas it might help if you include the code to generate glyphsDict, so we can actually try this. But off hand, I wonder if it might be faster to construct a list of ShapeNodes in advance, rather than changing the path. I don't really know, just a thought.
How many points do the paths have?
-
Simple shapes seem to work fine as you can see from the following code. As suggested by @JonB you can give us a sample glyphDict that fails.
from scene import * import ui glyphsDict = {i:ui.Path.oval(0,0,10+i, 10+i) for i in range(200)} class MyScene (Scene): def setup(self): self.center = self.size/2 self.myPath = ShapeNode(glyphsDict[0], fill_color='red', position=self.center, parent=self) self.background_color = 'grey' def touch_began(self, touch): x, y = touch.location x = x - self.center.x z = int(abs(x/5.0))%len(glyphsDict) self.myPath.path = glyphsDict[z] # Setting a new path to draw def touch_moved(self, touch): x, y = touch.location x = x - self.center.x z = int(abs(x/5.0))%len(glyphsDict) self.myPath.path = glyphsDict[z] # Setting a new path to draw run(MyScene(), show_fps=True)
-
Even this works.
from scene import * import ui from objc_util import * glyphsDict = {} for i in range(96): font=ObjCClass('UIFont').systemFontOfSize_weight_(32+i,1) s='a' #'Hello world' p=ui.Path() p.line_width = 1 w=0 c.CTFontCreatePathForGlyph.restype = c_void_p c.CTFontCreatePathForGlyph.argtypes = [c_void_p, c_void_p, c_void_p] x = s.encode('ascii')[0] glyph= font._defaultGlyphForChar_(x) if not x==32: #space letter = ObjCInstance(c.CTFontCreatePathForGlyph(font, glyph, None)) letterBezier=UIBezierPath.bezierPathWithCGPath_(letter) #transform it so we shift and flip y letterBezier.applyTransform_(CGAffineTransform(1,0,0,-1,w,font.capHeight())) ObjCInstance(p).appendBezierPath_(letterBezier) w+=font.advancementForGlyph(glyph).width glyphsDict[i] = p #glyphsDict = {i:ui.Path.oval(0,0,10+i, 10+i) for i in range(200)} class MyScene (Scene): def setup(self): self.center = self.size/2 self.myPath = ShapeNode(glyphsDict[0], stroke_color='red', position=self.center, parent=self) self.background_color = 'grey' def touch_began(self, touch): x, y = touch.location x = x - self.center.x z = int(abs(x/5.0))%len(glyphsDict) self.myPath.path = glyphsDict[z] # Setting a new path to draw def touch_moved(self, touch): x, y = touch.location x = x - self.center.x z = int(abs(x/5.0))%len(glyphsDict) self.myPath.path = glyphsDict[z] # Setting a new path to draw run(MyScene(), show_fps=True)
-
@abcabc All of these work very smooth with 60fps all the time.
@JonB Each path has 29 points.I uploaded my project on github: https://github.com/dyyybek/pythonista
It's in the "VariableFonts" folder.The list i'm using to generate the dictionary is in pathsLists.py; It's quite long, it will probably not open in Pythonista.
-
I submitted a pull request with some optimizations but I am most interested to know what your iOS device is.
On my 64-bit iPad5,4 your code delivers 60fps unless there is a ton of movement and even then is highly responsive (50+fps).
-
@ccc Thanks for the optimizations. It's an iPad Air. I get under 1fps when moving fast... Is my iPad really that much slower?
-
Here is a different approach, using an animated CAShapeLayer
https://gist.github.com/73eb2b7395e41b55e2b4b8b95f303a8bNeat thing about a shape layer is you can actually have it interpolate for you, for instance you get a smooth animation just tapping the right side then left side of screen.
There is actually a method where you can use just a few paths, and use timeOffset to statically interpolate between them.
-
I am able to reproduce the problem on my ipad ( Pythonista version 3.1.1 (311002) running Python 3.5.1 on iOS 10.1.1 on a 32-bit iPad3,4 with ascreen size of (1024 x 768) * 2) ). It looks like that my ipad is not able to handle large paths and i have done the following modifications to run it on my ipad. I have precomputed the shape nodes and have added a reduction factor. I am able to run with reduction factor 4 and above.
(I have also created a pretty printed version of pathLists file which can be edited on pythonista IDE
https://gist.github.com/balachandrana/de8c3a84ad59be90064108b148a8bd21 )Other possibility is implementing this in shaders and "2D vector graphics library" in shadertoy could help in this implementation.
https://www.shadertoy.com/view/lslXW8import scene from variableTools import glyphsListConstruct glyphs_list1 = glyphsListConstruct() reduction_factor = 4.0 x_factor = (10.24 / 2)*reduction_factor class MyScene(scene.Scene): def setup(self): self.glyphs_list = [scene.ShapeNode(i) for i in glyphs_list1[::int(reduction_factor)]] self.myPath = self.glyphs_list[0] self.myPath.anchor_point = 0, 0 self.myPath.position = (1024 - self.myPath.bbox.width * 1.75, 768 - self.myPath.bbox.height * 1.3) self.add_child(self.myPath) self.background_color = 'lightgrey' self.touch_moved = self.touch_began def touch_began(self, touch): r = int(touch.location.x / x_factor)%len(self.glyphs_list) #print(touch.location.x, r) self.myPath.remove_from_parent() self.myPath = self.glyphs_list[r] self.myPath.anchor_point = 0, 0 self.myPath.position = (1024 - self.myPath.bbox.width * 1.75, 768 - self.myPath.bbox.height * 1.3) self.add_child(self.myPath) scene.run(MyScene(), show_fps=True)
-
@abcabc This works for me smoothly with reduction factor 2, but with reduction factor 1 the app just crashes.
@JonB This runs very smooth! No lags at all.
i'm starting to understand how to make use of
objc_util
, thanks to those examples.I tried above methods with a 1024 paths list. I get a memory error on dictionary creation and the script does not run.
Path information now is only for 1 axis – interpolation between a light and bold font weight. If i want 2 axis interpolation that will quickly go to 10000 for a 100x100 different interpolations... So maybe non of these methods will actually work?I think my best bet is to make this script with real fonts and utilize the
CTFontCopyVariationAxes
from CoreText.
(https://developer.apple.com/reference/coretext/ctfont?language=objc#1666125)I'd be glad if someone would confirm that this is actually possible.
-
Since variation axes work by interpolation between a few reference glyphs, you can reproduce that using a paused animation.
See the not very clean
https://gist.github.com/54b80f4fa31365d18ef6e05ed0a98bc9This works with your original glyphs very nicely, just select the two endpoints. It could be extended where you select which pair to interpolate with, and thats what i started trying.... however the issue seems to be that when you get different weights from CTfont, they are constructed differently... so interpolating ends up jumbling the letter in between. I selected an example where it does work, but it fails for other letters or font weights.
wherever you got your original paths, you just need the 5 or whatever reference glyphs, and then you'd have to modify this a little to adjust toValue and fromValue, along with the relative distance between those values as the layer timeOffset.
-
@JonB said:
however the issue seems to be that when you get different weights from CTfont, they are constructed differently...
If you're trying to do this with some fonts installed on the iPad they probably won't be compatible. The paths need have the same node count and path direction. Here is my sample font with 1 weight axis:
https://www.dropbox.com/s/cbeqxxuk9dg8jz1/PanvariaGX.ttf?dl=0
I included all the code necessary to run the example with your interpolation method:
https://gist.github.com/0e93006203c034a98522601644aff013
This works very well.
I understand that from here it is not very far to use the actual font file? -
https://gist.github.com/8fe4aa269b15a7071633e256456786ca
Here is an improved method, using KeyFrame animations.
Basically, you set up 5 or whatever refernces, add to a PathAnimation, and then provide the interpolation value (0..len(glyphs)).i have not tried installing your font yet. Might try UIFont.fontWithName_size_traits_(). or maybe need o set up fondDescriptor.
-
Can you please confirm if your iOS devices are 32 or 64 bit?
-
https://gist.github.com/c8b993ac42ede2574dc9f7cc26ebb1f4
and here is a version that uses your font file, and cleans things up a bit.I am on 32 bit -- ccc, is this crashing for you? If so, on what line? I think I got typedefs correct but I may have missed a few
-
Unfortunately @JonB I confirm that it crashes on 64 bit.
-
Which line is crashing? Do you have the fault handler installed?
-
https://gist.github.com/7a73b8c3abab4dc502ef2314574c6744
For some reason I was missing a slew of definitions. Try this one on 64bit...
-
@JonB i get "No method found for mutableCopy" on line 80
-
https://gist.github.com/80660624600c28c8e7812b15e0652568
How about this one.... -
@JonB this one raises the exception from line 15