def doTestSave(self, ext, format): f1 = "save1.%s" % ext f2 = "save2.%s" % ext try: im = image.T(640, 400) im.save(f1) self.failUnless(os.path.exists(f1)) self.assertImageFileFormat(f1, format) im = image.T(640, 40, 640, 400) im.start_save(f2) for (xoff, yoff, w, h) in im.get_tile_list(): im.resize_tile(w, h) im.set_offset(xoff, yoff) im.save_tile() im.finish_save() self.failUnless(os.path.exists(f2)) self.assertImageFileFormat(f2, format) self.assertEqual(True, filecmp.cmp(f1, f2, False)) finally: if os.path.exists(f1): os.remove(f1) if os.path.exists(f2): os.remove(f2)
def testTiledImage(self): # check defaults work OK im = image.T(40, 30) self.assertEqual(40, im.total_xsize) self.assertEqual(30, im.total_ysize) self.assertEqual(0, im.xoffset) self.assertEqual(0, im.yoffset) # check a different total size is honored im = image.T(40, 30, 400, 300) self.assertEqual(400, im.total_xsize) self.assertEqual(300, im.total_ysize) self.assertEqual(0, im.xoffset) self.assertEqual(0, im.yoffset) # check offset has an effect im.set_offset(40, 30) self.assertEqual(40, im.xoffset) self.assertEqual(30, im.yoffset) # check offset bounds-checking self.assertRaises(ValueError, im.set_offset, 400, 0) self.assertRaises(ValueError, im.set_offset, 361, 0) self.assertRaises(ValueError, im.set_offset, 0, 300) self.assertRaises(ValueError, im.set_offset, 0, 271) self.assertRaises(ValueError, im.set_offset, -1, 0) self.assertRaises(ValueError, im.set_offset, 0, -1) # check offset wasn't changed self.assertEqual(40, im.xoffset) self.assertEqual(30, im.yoffset)
def drawTwice(self,is_dirty,xsize): ysize = int(xsize * 3.0/4.0) im = image.T(xsize,ysize) siteobj = FractalSite() site = fract4dc.site_create(siteobj) file = self.compileColorMandel() handle = fract4dc.pf_load(file) pfunc = fract4dc.pf_create(handle) fract4dc.pf_init(pfunc,pos_params,self.color_mandel_params) cmap = fract4dc.cmap_create( [(1.0, 255, 255, 255, 255)]) fract4dc.calc( params=[0.0, 0.0, 0.0, 0.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], antialias=0, maxiter=100, yflip=0, nthreads=1, pfo=pfunc, cmap=cmap, auto_deepen=0, periodicity=1, render_type=0, image=im._img, site=site, dirty=is_dirty) #print "1st pass %s" % is_dirty #fract4dc.image_save(image, "/tmp/pass1%d.tga" % is_dirty) #self.print_fates(image,xsize,ysize) cmap = fract4dc.cmap_create( [(1.0, 76, 49, 189, 255)]) fract4dc.calc( params=[0.0, 0.0, 0.0, 0.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], antialias=0, maxiter=100, yflip=0, nthreads=1, pfo=pfunc, cmap=cmap, auto_deepen=0, periodicity=1, render_type=0, image=im._img, site=site, dirty=is_dirty) #print "2nd pass %s" % is_dirty #self.print_fates(image,xsize,ysize) im.save("/tmp/pass2%d.tga" % is_dirty) return [] # fract4dc.image_buffer(image)
def testLookupOnePixel(self): im = image.T(1, 1) rgba = im.lookup(0, 0) self.assertEqual((0, 0, 0, 1.0), rgba) buf = im.image_buffer() buf[0] = chr(20) buf[1] = chr(80) buf[2] = chr(160) rgba = im.lookup(0, 0) self.assertEqual((20.0 / 255.0, 80.0 / 255.0, 160.0 / 255.0, 1.0), rgba) rgba = im.lookup(0.5, 0.5) self.assertEqual((20.0 / 255.0, 80.0 / 255.0, 160.0 / 255.0, 1.0), rgba) rgba = im.lookup(-0.5, -0.5) self.assertEqual((20.0 / 255.0, 80.0 / 255.0, 160.0 / 255.0, 1.0), rgba) rgba = im.lookup(10.5, -10.5) self.assertEqual((20.0 / 255.0, 80.0 / 255.0, 160.0 / 255.0, 1.0), rgba)
def testLookupFourPixels(self): im = image.T(2, 2) buf = im.image_buffer() buf[0] = chr(0) # top left = black buf[1] = chr(0) buf[2] = chr(0) buf[3] = chr(255) # top right = red buf[4] = chr(0) buf[5] = chr(0) buf[6] = chr(0) # bottom left = green buf[7] = chr(255) buf[8] = chr(0) buf[9] = chr(255) # bottom right = white buf[10] = chr(255) buf[11] = chr(255) # halfway across middle of top pixel = half red self.assertEqual((0.5, 0.0, 0.0, 1.0), im.lookup(0.5, 0.25)) # halfway down left-hand side = half green self.assertEqual((0.0, 0.5, 0.0, 1.0), im.lookup(0.25, 0.5)) # halfway down right-hand side = red/white self.assertEqual((1.0, 0.5, 0.5, 1.0), im.lookup(0.75, 0.5)) # halfway across bottom = green/white self.assertEqual((0.5, 1.0, 0.5, 1.0), im.lookup(0.5, 0.75)) # center = blend of half-red and green/white self.assertEqual((0.5, 0.5, 0.25, 1.0), im.lookup(0.5, 0.5))
def run(self,options): for path in options.extra_paths: self.compiler.add_func_path(path) if options.flags != None: self.compiler.set_flags(options.flags) width = options.width or fractconfig.instance.getint("display","width") height = options.height or fractconfig.instance.getint("display","height") threads = options.threads or fractconfig.instance.getint( "general","threads") if len(options.args) > 0: self.load(options.args[0]) self.f.apply_options(options) self.f.antialias = options.antialias or \ fractconfig.instance.getint("display","antialias") outfile = self.compile(options) if options.buildonly != None: self.buildonly(options, outfile) return if options.singlepoint: self.f.drawpoint() else: im = image.T(width,height) self.f.draw(im,threads) if options.save_filename: im.save(options.save_filename)
def createTestImage(self): # image is [ black, white, green, red] im = image.T(2, 2) buf = im.image_buffer() buf[3] = buf[4] = buf[5] = chr(255) # white buf[7] = chr(255) # green buf[9] = chr(255) # red return im
def testFractWorker(self): xsize = 8 ysize = 8 im = image.T(xsize,ysize) cmap = fract4dc.cmap_create([(1.0, 255, 255, 255, 255)]) fract4dc.cmap_set_solid(cmap,0,0,0,0,255) fract4dc.cmap_set_solid(cmap,1,0,0,0,255) (fw,ff,site,handle,pfunc) = self.makeWorkerAndFunc(im._img,cmap) im.clear() fate_buf = im.fate_buffer() buf = im.image_buffer() # draw 1 pixel, check it's set properly fract4dc.fw_pixel(fw,0,0,1,1) self.assertPixelIs(im,0,0,[im.OUT]+[im.UNKNOWN]*3) fract4dc.fw_pixel(fw,0,4,1,1) self.assertPixelIs(im,0,4,[im.IN]+[im.UNKNOWN]*3) # draw it again, check no change. fract4dc.fw_pixel(fw,0,0,1,1) self.assertPixelIs(im,0,0,[im.OUT]+[im.UNKNOWN]*3) # draw & antialias another pixel fract4dc.fw_pixel(fw,2,2,1,1) fract4dc.fw_pixel_aa(fw,2,2) self.assertPixelIs(im,2,2,[im.OUT, im.OUT, im.IN, im.OUT]) # change cmap, draw same pixel again, check color changes cmap = fract4dc.cmap_create( [(1.0, 79, 88, 41, 255)]) fract4dc.cmap_set_solid(cmap,1,100,101,102,255) (fw,ff,site,handle,pfunc) = self.makeWorkerAndFunc(im._img,cmap) fract4dc.fw_pixel(fw,0,0,1,1) self.assertPixelIs(im,0,0,[im.OUT]+[im.UNKNOWN]*3, [79,88,41]) # redraw antialiased pixel fract4dc.fw_pixel_aa(fw,2,2) self.assertPixelIs( im,2,2, [im.OUT, im.OUT, im.IN, im.OUT], [79,88,41], [100,101,102]) # draw large block overlapping existing pixels fract4dc.fw_pixel(fw,0,0,4,4) self.assertPixelIs( im,0,0, [im.OUT, im.UNKNOWN, im.UNKNOWN, im.UNKNOWN], [79,88,41], [100,101,102]) self.assertPixelIs( im,3,1, [im.UNKNOWN]*4, [79,88,41], [100,101,102], im.OUT)
def testResize(self): im = image.T(10, 20) self.assertEqual(10, im.xsize) self.assertEqual(20, im.ysize) self.assertImageInvariants(im) im.resize_full(30, 17) self.assertEqual(30, im.xsize) self.assertEqual(17, im.ysize) self.assertImageInvariants(im)
def testClear(self): # check clear() works (xsize, ysize) = (61, 33) im = image.T(xsize, ysize) im.clear() buf = im.image_buffer() fate_buf = im.fate_buffer() self.assertEqual(list(fate_buf), [chr(im.UNKNOWN)] * im.FATE_SIZE * xsize * ysize) bytes = map(ord, list(buf)) self.assertEqual(bytes, [0] * xsize * ysize * im.COL_SIZE)
def set_initparams_from_formula(self, g): self.params = self.formula.symbols.default_params() self.paramtypes = self.formula.symbols.type_of_params() for i in xrange(len(self.paramtypes)): if self.paramtypes[i] == fracttypes.Gradient: self.params[i] = copy.copy(g) elif self.paramtypes[i] == fracttypes.Image: im = image.T(1, 1) #b = im.image_buffer() #b[0] = chr(216) #b[3] = chr(88) #b[4] = chr(192) #b[11] = chr(255) self.params[i] = im
def testTileList(self): # a single tile im = image.T(100, 50) self.assertEqual([(0, 0, 100, 50)], im.get_tile_list()) # 2 wide, 1 high im = image.T(100, 50, 200, 50) self.assertEqual([(0, 0, 100, 50), (100, 0, 100, 50)], im.get_tile_list()) # 2 high, 1 wide im = image.T(100, 50, 100, 100) self.assertEqual([(0, 0, 100, 50), (0, 50, 100, 50)], im.get_tile_list()) # not evenly divisible, odd-shaped chunks at edges im = image.T(100, 50, 101, 51) self.assertEqual([(0, 0, 100, 50), (100, 0, 1, 50), ( 0, 50, 100, 1, ), (100, 50, 1, 1)], im.get_tile_list())
def testLookupTwoPixels(self): im = image.T(2, 1) rgba = im.lookup(0, 0) self.assertEqual((0, 0, 0, 1.0), rgba) buf = im.image_buffer() buf[0] = chr(0) buf[1] = chr(0) buf[2] = chr(0) buf[3] = chr(255) buf[4] = chr(255) buf[5] = chr(255) self.assertEqual(self.grey_pixel(0.5), im.lookup(0, 0)) self.assertEqual(self.grey_pixel(0.0), im.lookup(0.25, 0.25)) self.assertEqual(self.grey_pixel(1.0), im.lookup(0.75, 0.75))
class Test(testbase.TestBase): def testColossalImage(self): try: im = image.T(400000, 300000) self.fail("Should have raised an exception") except MemoryError, err: pass im = image.T(40, 30) try: im.resize_full(400000, 300000) self.fail("Should have raised an exception") except MemoryError, err: # retains large size even if allocation fails self.assertEqual(400000, im.xsize) self.assertEqual(300000, im.ysize) pass
def testAACalc(self): xsize = 64 ysize = int(xsize * 3.0/4.0) im = image.T(xsize,ysize) siteobj = FractalSite() site = fract4dc.site_create(siteobj) file = self.compileColorMandel() handle = fract4dc.pf_load(file) pfunc = fract4dc.pf_create(handle) fract4dc.pf_init(pfunc,pos_params,self.color_mandel_params) cmap = fract4dc.cmap_create( [(0.0,0,0,0,255), (1/256.0,255,255,255,255), (1.0, 255, 255, 255, 255)]) fract4dc.calc( params=[0.0, 0.0, 0.0, 0.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], antialias=1, maxiter=100, yflip=0, nthreads=1, pfo=pfunc, cmap=cmap, auto_deepen=0, periodicity=1, render_type=0, image=im._img, site=site) # fate of all pixels should be known fate_buf = im.fate_buffer() i = 0 for byte in fate_buf: d = im.get_color_index( (i % (im.FATE_SIZE * xsize)) / im.FATE_SIZE, i / (im.FATE_SIZE * xsize), i % im.FATE_SIZE) self.assertNotEqual("%g" % d,"inf", "index %d is %g" % (i,d)) self.assertNotEqual(ord(byte), 255, "pixel %d is %d" % (i,ord(byte))) i+= 1
def setUp(self): global g_comp self.compiler = g_comp self.f = fractal.T(self.compiler) self.f.render_type = 2 self.f.set_formula("test.frm", "test_hypersphere") self.f.compile() handle = fract4dc.pf_load(self.f.outputfile) self.pfunc = fract4dc.pf_create(handle) self.cmap = fract4dc.cmap_create_gradient( self.f.get_gradient().segments) (r, g, b, a) = self.f.solids[0] fract4dc.cmap_set_solid(self.cmap, 0, r, g, b, a) (r, g, b, a) = self.f.solids[1] fract4dc.cmap_set_solid(self.cmap, 1, r, g, b, a) initparams = self.f.all_params() fract4dc.pf_init(self.pfunc, self.f.params, initparams) self.im = image.T(40, 30) siteobj = FractalSite() self.fw = fract4dc.fw_create(1, self.pfunc, self.cmap, self.im._img, self.f.site) self.ff = fract4dc.ff_create( [0.0, 0.0, 0.0, 0.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 2, 100, 0, 1, self.pfunc, self.cmap, 0, 1, 2, # 3D self.im._img, self.f.site, self.fw, False, 1.0E-9)
def testBufferBounds(self): im = image.T(40, 30) im.resize_full(80, 60) buf = im.image_buffer() fate_buf = im.fate_buffer() self.assertRaises(ValueError, im.image_buffer, -1, 0) self.assertRaises(ValueError, im.image_buffer, 80, 0) self.assertRaises(ValueError, im.image_buffer, 41, 67) self.assertRaises(ValueError, im.fate_buffer, -1, 0) self.assertRaises(ValueError, im.fate_buffer, 80, 0) self.assertRaises(ValueError, im.fate_buffer, 41, 67) buf = im.image_buffer(5, 10) self.assertEqual(len(buf), 80 * 60 * im.COL_SIZE - (10 * 80 + 5) * im.COL_SIZE) buf = im.fate_buffer(5, 10) self.assertEqual(len(buf), 80 * 60 * im.FATE_SIZE - (10 * 80 + 5) * im.FATE_SIZE)
def saveAndCheck(self, name, format): im = image.T(640, 400) im.save(name) self.failUnless(os.path.exists(name)) self.assertImageFileFormat(name, format)
def set_named_param(self, name, val): ord = self.order_of_name(name) if ord == None: #print "Ignoring unknown param %s" % name return t = self.formula.symbols[name].type if t == fracttypes.Complex: m = cmplx_re.match(val) if m != None: re = float(m.group(1)) im = float(m.group(2)) if self.params[ord] != re: self.params[ord] = re self.changed() if self.params[ord + 1] != im: self.params[ord + 1] = im self.changed() elif val == "warp": self.parent().set_warp_param(name) elif t == fracttypes.Hyper or t == fracttypes.Color: m = hyper_re.match(val) if m != None: for i in xrange(4): val = float(m.group(i + 1)) if self.params[ord + i] != val: self.params[ord + i] = val self.changed() elif t == fracttypes.Float: newval = float(val) if self.params[ord] != newval: self.params[ord] = newval self.changed() elif t == fracttypes.Int: newval = int(val) if self.params[ord] != newval: self.params[ord] = newval self.changed() elif t == fracttypes.Bool: # don't use bool(val) - that makes "0" = True try: i = int(val) i = (i != 0) except ValueError: # an old release included a 'True' or 'False' string if val == "True": i = 1 else: i = 0 if self.params[ord] != i: self.params[ord] = i self.changed() elif t == fracttypes.Gradient: grad = gradient.Gradient() grad.load(StringIO.StringIO(val)) self.params[ord] = grad self.changed() elif t == fracttypes.Image: im = image.T(2, 2) self.params[ord] = im self.changed() else: raise ValueError("Unknown param type %s for %s" % (t, name))
def testDrawMBrot(self): self.f.set_formula("gf4d.frm", "Mandelbrot") self.f.compile() im = image.T(80, 60) self.f.draw(im)
def testCalc(self): xsize = 64 ysize = int(xsize * 3.0/4.0) im = image.T(xsize,ysize) siteobj = FractalSite() site = fract4dc.site_create(siteobj) file = self.compileColorMandel() handle = fract4dc.pf_load(file) pfunc = fract4dc.pf_create(handle) fract4dc.pf_init(pfunc,pos_params,self.color_mandel_params) cmap = fract4dc.cmap_create( [(0.0,0,0,0,255), (1/256.0,255,255,255,255), (1.0, 255, 255, 255, 255)]) fract4dc.calc( params=[0.0, 0.0, 0.0, 0.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], antialias=0, maxiter=100, yflip=0, nthreads=1, pfo=pfunc, cmap=cmap, auto_deepen=0, periodicity=1, render_type=0, image=im._img, site=site) self.assertEqual(siteobj.progress_list[-1], 0.0) self.assertEqual(siteobj.progress_list[-2], 1.0) self.failUnless(siteobj.image_list[-1]==(0,0,xsize,ysize)) self.failUnless(siteobj.status_list[0]== 1 and \ siteobj.status_list[-1]== 0) self.failUnless(not os.path.exists("test.tga")) im.save("test.tga") self.failUnless(os.path.exists("test.tga")) os.remove('test.tga') # fate of all non-aa pixels should be known, aa-pixels unknown fate_buf = im.fate_buffer() i = 0 for byte in fate_buf: d = im.get_color_index( (i % (im.FATE_SIZE * xsize)) / im.FATE_SIZE, i / (im.FATE_SIZE * xsize), i % im.FATE_SIZE) if i % 4 == 0: # no-aa self.assertNotEqual(ord(byte), 255, "pixel %d is %d" % (i,ord(byte))) self.assertNotEqual("%g" % d,"inf") else: self.assertEqual(ord(byte), 255) i+= 1 self.assertPixelCount(xsize,ysize,siteobj)
def testFDSite(self): xsize = 64 ysize = int(xsize * 3.0/4.0) im = image.T(xsize,ysize) (rfd,wfd) = os.pipe() site = fract4dc.fdsite_create(wfd) file = self.compileColorMandel() for x in xrange(2): handle = fract4dc.pf_load(file) pfunc = fract4dc.pf_create(handle) fract4dc.pf_init(pfunc,pos_params,self.color_mandel_params) cmap = fract4dc.cmap_create( [(0.0,0,0,0,255), (1/256.0,255,255,255,255), (1.0, 255, 255, 255, 255)]) fract4dc.calc( params=[0.0, 0.0, 0.0, 0.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], antialias=0, maxiter=100, yflip=0, nthreads=1, pfo=pfunc, cmap=cmap, auto_deepen=0, periodicity=1, render_type=0, image=im._img, site=site, async=True) nrecved = 0 while True: if nrecved == x: #print "hit message count" fract4dc.interrupt(site) nb = 2*4 bytes = os.read(rfd,nb) if len(bytes) < nb: self.fail("bad message") break (t,size) = struct.unpack("2i",bytes) #print "read %d, len %d" % (t,size) # read the rest of the message bytes = os.read(rfd,size) if len(bytes) < size: self.fail("bad message") break msg = messages.parse(t, bytes) #print "msg: %s" % msg.show() if msg.name == "Status" and msg.status == 0: #done #print "done" break nrecved += 1
def testFileExtensionLookup(self): im = image.T(40, 30) self.assertRaises(ValueError, im.file_type, "hello.gif") self.assertRaises(ValueError, im.file_type, "hello")
def doTestLoad(self, file): im = image.T(1, 1) im.load(file) cmp_image = self.createTestImage() self.assertImagesEqual(im, cmp_image)
def testColossalImage(self): try: im = image.T(400000, 300000) self.fail("Should have raised an exception") except MemoryError, err: pass
return self.param_display_name(name,param) def loadFctFile(self,f): old_gradient = self.get_gradient() line = f.readline() if line == None or not line.startswith("gnofract4d parameter file"): raise Exception("Not a valid parameter file") self.load(f) self.fix_bailout() #self.fix_gradients(old_gradient) self.saved = True if __name__ == '__main__': g_comp = fc.Compiler() g_comp.add_func_path("formulas") g_comp.add_func_path("../formulas") g_comp.add_func_path( os.path.join(sys.exec_prefix, "share/gnofract4d/formulas")) f = T(g_comp) for arg in sys.argv[1:]: file = open(arg) f.loadFctFile(file) f.compile() im = image.T(64,48) f.draw(im) im.save(os.path.basename(arg) + ".png")
def testVectors(self): siteobj = FractalSite() site = fract4dc.site_create(siteobj) file = self.compileColorDiagonal() handle = fract4dc.pf_load(file) pfunc = fract4dc.pf_create(handle) fract4dc.pf_init(pfunc,pos_params,self.color_diagonal_params) (w,h,tw,th) = (40,20,40,20) im = image.T(w,h) cmap = fract4dc.cmap_create([(1.0, 255, 255, 255, 255)]) fw = fract4dc.fw_create(1,pfunc,cmap,im._img,site) ff = fract4dc.ff_create( [0.0, 0.0, 0.0, 0.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 2, 100, 0, 1, pfunc, cmap, 0, 1, 0, im._img, site, fw, False, 1.0E-9) # check dx, dy and topleft dx = fract4dc.ff_get_vector(ff, fract4dc.DELTA_X) self.assertNearlyEqual(dx, [4.0/tw,0.0,0.0,0.0]) dy = fract4dc.ff_get_vector(ff, fract4dc.DELTA_Y); self.assertNearlyEqual(dy, [0.0,-2.0/th,0.0,0.0]) topleft = fract4dc.ff_get_vector(ff, fract4dc.TOPLEFT); self.assertNearlyEqual(topleft, [-2.0 + 4.0/(tw*2),1.0 - 2.0/(th*2),0.0,0.0]) # check they are updated if image is bigger (w,h,tw,th) = (40,20,400,200) im = image.T(w,h,tw,th) fw = fract4dc.fw_create(1,pfunc,cmap,im._img,site) ff = fract4dc.ff_create( [0.0, 0.0, 0.0, 0.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 2, 100, 0, 1, pfunc, cmap, 0, 1, 0, im._img, site, fw, False, 1.0E-9) # check dx, dy and topleft dx = fract4dc.ff_get_vector(ff, fract4dc.DELTA_X) self.assertNearlyEqual(dx, [4.0/tw,0.0,0.0,0.0]) dy = fract4dc.ff_get_vector(ff, fract4dc.DELTA_Y); self.assertNearlyEqual(dy, [0.0,-2.0/th,0.0,0.0]) topleft = fract4dc.ff_get_vector(ff, fract4dc.TOPLEFT); self.assertNearlyEqual(topleft, [-2.0 + 4.0/(tw*2),1.0 - 2.0/(th*2),0.0,0.0]) offx = 40 offy = 10 im.set_offset(offx, offy) fw = fract4dc.fw_create(1,pfunc,cmap,im._img,site) ff = fract4dc.ff_create( [0.0, 0.0, 0.0, 0.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 2, 100, 0, 1, pfunc, cmap, 0, 1, 0, im._img, site, fw, False, 1.0E-9) # check dx, dy and topleft dx = fract4dc.ff_get_vector(ff, fract4dc.DELTA_X) self.assertNearlyEqual(dx, [4.0/tw,0.0,0.0,0.0]) dy = fract4dc.ff_get_vector(ff, fract4dc.DELTA_Y); self.assertNearlyEqual(dy, [0.0,-2.0/th,0.0,0.0]) topleft = fract4dc.ff_get_vector(ff, fract4dc.TOPLEFT); self.assertNearlyEqual(topleft, [ -2.0 + dx[0] * (offx + 0.5), 1.0 + dy[1] * (offy + 0.5), 0.0,0.0])