omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    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.


    GKPath question

    Pythonista
    5
    19
    7556
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • JonB
      JonB last edited by

      >>> split_encoding('@24@0:4^8L12f16c20')
      ['@', '@', ':', '^L', 'f', 'c']
      

      Knowing that clang doesn't properly represent vectors in the encoding, it seems like we could split on numbers appearing where they are not supposed to ... so ^8L should not be interpreted as ^L (pointer to unisgned long), but a pointer to something we are not sure of (c_void_p) followed by a long. vector restype is obviously a little trickier, especially since the size info never seems correct.

      I am on ios9, but there are no double underscore pointWithIndex or pointAtIndex. I think on 10 maybe it was replaced with float2AtIndex.

      mikael 1 Reply Last reply Reply Quote 0
      • mikael
        mikael @JonB last edited by

        @JonB and @dgelessus, do I read the above correctly to mean that: there is no way to call ObjC methods that expect a vector of float2s from Pythonista?

        1 Reply Last reply Reply Quote 0
        • JonB
          JonB last edited by

          No, you just have to specify the argtypes and restype manually.

          We probably ought to go back through old forum posts to find the various cases when the encoding parser fails, and monkey patch that function.

          mikael 1 Reply Last reply Reply Quote 0
          • mikael
            mikael @JonB last edited by mikael

            @JonB, after asking the question above, I have been trying to go the manual encoding route, with no real success.

            What I have is an identity SKWarpGeometryGrid created with gridWithColumns_rows_. It reports the correct number of rows, cols and vertices, and self-identifies as an identity grid where the source and destination grids point to the same grid.

            Now I try to change the destination grid with gridByReplacingDestPositions_. This requires vector_float2 and returns a new grid with the destination positions replaced.

            These are the destination points I would like to try:

            dest = [
              (0.0, -0.5), (0.5, 0.0), (1.0, 0.0),
              (0.0, 0.5), (0.5, 0.5), (1.0, 0.5),
              (0.0, 1.0), (0.5, 1.0), (1.0, 1.0),
            ]
            

            (Only the second float of the first tuple is changed from the identity grid.)

            I have this manual definition:

            f = self.geometry.gridByReplacingDestPositions_
            f.argtypes = [c_void_p]
            f.restype = c_void_p
            f.encoding = b'@@:@'
            

            And these for creating the destination argument from the array above:

            class float2(Structure):
              _fields_ = [('x',c_float),('y',c_float)]
            
            @classmethod
            def _get_float2(cls, positions):
              floats = []
              for pos in positions:
                f = float2()
                f.x, f.y = pos
                floats.append(f)
              floats_array = (float2 * len(floats))(*floats)
              return floats_array
            

            The method gets called and returns an updated SKWarpGeometryGrid, which unfortunately is still the same identity warp. This leads me to believe that my float2 is probably wrong and gets implicitly rejected without error.

            I have also tried gridWithColumns_rows_sourcePositions_destPositions_, with same identity grid result.

            Any next steps to try would be greatly appreciated.

            1 Reply Last reply Reply Quote 0
            • JonB
              JonB last edited by

              How many points does the source grid have? If you are just replacing the dest, I think you have to make sure the number is the same.

              I'll play around with it -- do you have code that initializes the grid in the first place?

              1 Reply Last reply Reply Quote 0
              • JonB
                JonB last edited by

                Okay, playing with this some more, I can’t event get valid points out of the destPositionsAt, etc. doing the same in playgrounds does provide valid values. The issue seems to be that libffi doesn’t seem to support SIMD, or at least it didn’t for the version used by Pythonista.

                There might be some workarounds using MTLKit, but not sure

                mikael 1 Reply Last reply Reply Quote 0
                • mikael
                  mikael @JonB last edited by mikael

                  @JonB, I get expected values out with the following:

                    addr = ctypes.addressof(warp_geometry.destPositions().contents)
                    for _ in range(9):
                      p = float2.from_address(addr)
                      print(p.x, p.y)
                      addr += ctypes.sizeof(float2)
                  

                  ... but still cannot get the destGeometry set, even if I modify this same memory area and set it back.

                  cvp 1 Reply Last reply Reply Quote 0
                  • cvp
                    cvp @mikael last edited by

                    @mikael Did you read this?

                    mikael 1 Reply Last reply Reply Quote 0
                    • mikael
                      mikael @cvp last edited by

                      @cvp, thanks, no I did not. But now that I did, seems to match the docs, except for the disheartening ”Warning: Unrecognized filer type: '1' using 'void*'” everywhere that the grids are being referred to.

                      1 Reply Last reply Reply Quote 0
                      • JonB
                        JonB last edited by

                        Ahh, the extra pointer was throwing me off.
                        This is a pointer to a float2 array.

                        Ok, so this does seem to work, both modifying and creating from scratch.
                        Note the somewhat simpler cast of the c_void_p directly to the POINTER type we want (you could also have set restype to POINTER(float2*n)), allowing list-like access to the contents rather than mucking about with addresses. Likewise, passing in can just use byref.

                        I think there is a caveat that you probably have to be careful if you create from scratch, because float2 might have some memory alignment requirements that this doesn’t enforce.

                        from objc_util import *
                        from ctypes import *
                        
                        NSBundle.bundleWithPath_('/System/Library/Frameworks/SpriteKit.framework').load()
                        
                        NSBundle.bundleWithPath_('/System/Library/Frameworks/Metal.framework').load()
                        SKWarpGeometryGrid=ObjCClass('SKWarpGeometryGrid')
                        
                        class float2(Structure):
                        	_fields_ = [('x',c_float),('y',c_float)]
                        	def __repr__(self):
                        		'convienence repr'
                        		return ' float2({},{})'.format(self.x,self.y)
                        
                        	@classmethod
                        	def _get_float2(cls, positions):
                        		floats = []
                        		for pos in positions:
                        			f = float2()
                        			f.x, f.y = pos
                        			floats.append(f)
                        		floats_array = (float2 * len(floats))(*floats)
                        		return floats_array
                        def dump_float2array(ptr,n):
                        	data = cast(ptr, POINTER(float2*n)).contents
                        	for d in data:
                        		print(d)
                        	return data
                        	
                        g=SKWarpGeometryGrid.gridWithColumns_rows_(3,3)
                        
                        '''note, destPositins returns a pointer to an arrayof float2. we can cast then access contents, which gves us easy array like access to data'''
                        print('initial dest')
                        dst0=dump_float2array(g.destPositions(), 9)
                        '''it seems modifying the returned value directly modifies the original object. so, make a copy first. could have also done this in the dump fcn so we don't forget'''
                        
                        new_dst=(float2*9).from_buffer_copy(dst0)
                        ''' just change one element to check that this works'''
                        new_dst[2].x=.999
                        new_dst[2].y=.998
                        
                        '''it appears that changing the returned memory changes the actual grid, maybe not what is intended.  might be better to do some sort of memcopy before modifying'''
                        print('initial dest after modifying memory')
                        dump_float2array(g.destPositions(), 9)
                        
                        g2=g.gridByReplacingDestPositions_(byref(new_dst), restype=c_void_p, argtypes=[c_void_p])
                        print('new grid dest')
                        dump_float2array(g2.destPositions(), 9)
                        
                        '''create from scratch'''	
                        
                        src=float2._get_float2([[0,0],[0,.5],[0.5,0],[.5,.5]])
                        dst=float2._get_float2([[0,0],[0,.75],[0.75,0],[.75,.75]])
                        
                        g3=SKWarpGeometryGrid.gridWithColumns_rows_sourcePositions_destPositions_(2,2,byref(src),byref(dst), restype=c_void_p, argtypes=[c_int,c_int, c_void_p,c_void_p])
                        print('from scratch')
                        dump_float2array(g3.destPositions(), 4)
                        
                        
                        
                        1 Reply Last reply Reply Quote 1
                        • JonB
                          JonB last edited by

                          By the way, ctypes is smart enough to figure out

                          dest = [
                            (0.0, -0.5), (0.5, 0.0), (1.0, 0.0),
                            (0.0, 0.5), (0.5, 0.5), (1.0, 0.5),
                            (0.0, 1.0), (0.5, 1.0), (1.0, 1.0),
                          ]
                          
                          new_dst=(float2*9)(*dest)
                          

                          So, the _get_float2 method is not needed, or at least doesn’t need the loop.

                          This also works for nested struts,like

                          (CGRect*2)(((0,0),(50,75)),((50,0),(50,75)))
                          

                          Where essentially the tuple is interpreted outside-> in, each nested tuple becomes the constructor arguments for the next lower level field, etc.

                          mikael 1 Reply Last reply Reply Quote 2
                          • mikael
                            mikael @JonB last edited by

                            @JonB, color me impressed, once again.

                            Here is all that is needed, then:

                            warp = SKWarpGeometryGrid.gridWithColumns_rows_(2, 2)
                            
                            dest = [
                              (0.0, -0.5), (0.5, 0.0), (1.0, 0.0),
                              (0.0, 0.5), (0.5, 0.5), (1.0, 0.5),
                              (0.0, 1.0), (0.5, 1.0), (1.0, 1.0),
                            ]
                            new_dest = (float2*9)(*dest)
                            g2 = warp.gridByReplacingDestPositions_(
                              byref(new_dest),
                              restype=c_void_p, argtypes=[c_void_p])
                            

                            (Note that for some Apple-ish reason, the col & row numbers are one less than what you would think given the number of vertices.)

                            cvp 1 Reply Last reply Reply Quote 0
                            • cvp
                              cvp @mikael last edited by

                              @mikael said:

                              color me impressed, once again

                              I agree 😀

                              1 Reply Last reply Reply Quote 0
                              • First post
                                Last post
                              Powered by NodeBB Forums | Contributors