示例#1
0
def test_pullingoutguess():
    g = Sphere(center=(par(guess=.567e-5, limit=[0, 1e-5]),
                       par(.567e-5, (0, 1e-5)), par(15e-6, (1e-5, 2e-5))),
               r=par(8.5e-7, (1e-8, 1e-5)),
               n=ComplexParameter(par(1.59, (1, 2)), 1e-4))

    model = Model(g, Mie.calc_holo)

    s = Sphere(center=[.567e-5, .567e-5, 15e-6], n=1.59 + 1e-4j, r=8.5e-7)

    assert_equal(s.n, model.scatterer.guess.n)
    assert_equal(s.r, model.scatterer.guess.r)
    assert_equal(s.center, model.scatterer.guess.center)

    g = Sphere(center=(par(guess=.567e-5, limit=[0, 1e-5]),
                       par(.567e-5, (0, 1e-5)), par(15e-6, (1e-5, 2e-5))),
               r=par(8.5e-7, (1e-8, 1e-5)),
               n=1.59 + 1e-4j)

    model = Model(g, Mie.calc_holo)

    s = Sphere(center=[.567e-5, .567e-5, 15e-6], n=1.59 + 1e-4j, r=8.5e-7)

    assert_equal(s.n, model.scatterer.guess.n)
    assert_equal(s.r, model.scatterer.guess.r)
    assert_equal(s.center, model.scatterer.guess.center)
示例#2
0
def test_next_model():
    exampleresult = FitResult(parameters={
        'center[1]': 31.367170884695756, 'r': 0.6465280831465722,
        'center[0]': 32.24150087110443,
        'center[2]': 35.1651561654966,
        'alpha': 0.7176299231169572,
        'n': 1.580122175314896},
        scatterer=Sphere(n=1.580122175314896, r=0.6465280831465722,
        center=[32.24150087110443, 31.367170884695756, 35.1651561654966]),
        chisq=0.0001810513851216454, rsq=0.9727020197282801,
        converged=True, time=5.179728031158447,
        model=Model(scatterer=ParameterizedObject(obj=
        Sphere(n=Parameter(guess=1.59, limit=[1.4, 1.7], name='n'),
        r=Parameter(guess=0.65, limit=[0.6, 0.7], name='r'),
        center=[Parameter(guess=32.110424836601304, limit=[2, 40], name='center[0]'),
        Parameter(guess=31.56683986928105, limit=[4, 40], name='center[1]'),
        Parameter(guess=33, limit=[5, 45], name='center[2]')])),
        theory=Mie.calc_holo, alpha=Parameter(guess=0.6, limit=[0.1, 1], name='alpha'),
        constraints=[]), minimizer = None, minimization_details = None)

    gold = Model(scatterer=ParameterizedObject(obj=Sphere(
        n=Parameter(guess=1.580122175314896, limit=[1.4, 1.7], name='n'),
        r=Parameter(guess=0.6465280831465722, limit=[0.6, 0.7], name='r'),
        center=[Parameter(guess=32.24150087110443, limit=[2, 40], name='center[0]'),
        Parameter(guess=31.367170884695756, limit=[4, 40], name='center[1]'),
        Parameter(guess=35.1651561654966, limit=[5, 45], name='center[2]')])),
        theory=Mie.calc_holo, alpha=Parameter(guess=0.7176299231169572, limit=[0.1, 1], name='alpha'),
        constraints=[])

    assert_obj_close(gold, exampleresult.next_model())
    def calculateHologram(self): #calculate hologram with current settings
        self.warning.setText('Calculating...')

        #self.compute.setChecked(True)
        scale = self.scale
        sender = self.sender()

        ######## hologram calculation (4x big to allow scrolling)
        start = time.time()
        sphere = Sphere(n = self.lcd5.value()+.0001j, 
            r = self.lcd4.value(), 
            center = (256*self.scale,256*self.scale,self.lcd3.value()))

        sphere2 = Sphere(n = self.lcd5.value()+.0001j, 
            r = self.lcd4.value(), 
            center = (self.lcd.value(),self.lcd2.value(),self.lcd3.value()))

        self.sphObject.setText(repr(sphere2))

        schema = ImageSchema(shape = 512, spacing = float(self.pxsizeText.text()),
		    optics = Optics(wavelen = float(self.waveText.text()), 
            index = float(self.mindexText.text()), polarization = [1,0]))

        schema2 = ImageSchema(shape = 256, spacing = float(self.pxsizeText.text()),
            optics = Optics(wavelen = float(self.waveText.text()), 
            index = float(self.mindexText.text()), polarization = [1,0]))

        self.schemaObject.setText(str(repr(schema2)))
        self.holo = Mie.calc_holo(sphere, schema)
        self.lastholo = self.holo
        self.lastZ = self.lcd3.value()

        end = time.time()

        #now take only the part that you want to display
        x = round(self.sld.value())
        y = round(self.sld2.value())
        im = toimage(self.holo[256-x:512-x,256-y:512-y]) #PIL image

        #https://github.com/shuge/Enjoy-Qt-Python-Binding/blob/master/image/display_img/pil_to_qpixmap.py
        #myQtImage = ImageQt(im)
        #qimage = QtGui.QImage(myQtImage)
        if im.mode == "RGB":
            pass
        elif im.mode == "L":
            im = im.convert("RGBA")
        data = im.tostring('raw',"RGBA")
        qim = QtGui.QImage(data, 256, 256, QtGui.QImage.Format_ARGB32)
        pixmap = QtGui.QPixmap.fromImage(qim)

        myScaledPixmap = pixmap.scaled(QtCore.QSize(400,400))

        self.warning.setText('')
        self.hologram.setPixmap(myScaledPixmap)

        #self.hologram.setScaledContents(True)
        #myScaledPixmap.scaledToWidth(True)

        self.timer.setText('Calc. Time: '+str(round(end-start,4))+' s')
        self.timer.setAlignment(QtCore.Qt.AlignBottom | QtCore.Qt.AlignCenter)
 def test_scattering_matrix_pathway_returns_linear_in_scatmatrs(self):
     theory = MockScatteringMatrixBasedTheory()
     sphere01 = Sphere(n=1.5, r=1.0, center=(0, 0, 2))
     sphere02 = Sphere(n=1.5, r=2.0, center=(0, 0, 2))
     fields01 = theory.calculate_scattered_field(sphere01, XSCHEMA)
     fields02 = theory.calculate_scattered_field(sphere02, XSCHEMA)
     self.assertTrue(
         np.allclose(fields02.values, 2 * fields01.values, **TOLS))
示例#5
0
def test_DDA_indicator():
    n = 1.59
    center = (1, 1, 30)
    r = .3
    sc = Sphere(n=n, r=r, center = center)
    sphere_holo = calc_holo(schema, sc, index, wavelen, theory=DDA)
    s = Scatterer(Sphere(r=r, center = (0, 0, 0)).contains, n, center)
    gen_holo = calc_holo(schema, s, index, wavelen, theory=DDA)
    assert_allclose(sphere_holo, gen_holo, rtol=2e-3)
示例#6
0
def test_Spheres_construction_typechecking():
    # heterogeneous composite should raise exception, since a
    # sphere cluster must contain only Spheres
    s1 = Sphere(n = 1.59, r = 5e-7, center = (1e-6, -1e-6, 10e-6))
    s2 = Sphere(n = 1.59, r = 1e-6, center=[0,0,0])
    s3 = Sphere(n = 1.59+0.0001j, r = 5e-7, center=[5e-6,0,0])
    cs = Ellipsoid(n=1.59+0.0001j, r=(5e-7, 5e-7, 8e-7),
                      center=[-5e-6, 0,0])
    sc = Spheres(scatterers=[s1, s2, s3, cs])
示例#7
0
def test_csg_dda():
    s = Sphere(n = 1.6, r=.1, center=(5, 5, 5))
    st = s.translated(.03, 0, 0)
    pacman = Difference(s, st)
    sch = detector_grid(10, .1)
    h = calc_holo(sch, pacman, 1.33, .66, illum_polarization=(0, 1))
    verify(h, 'dda_csg')

    rotated_pac = pacman.rotated(np.pi/2, 0, 0)
    hr = calc_holo(sch, rotated_pac, 1.33, .66, illum_polarization=(0, 1))
    verify(h/hr, 'dda_csg_rotated_div')
示例#8
0
def test_csg_dda():
    s = Sphere(n = 1.6, r=.1, center=(5, 5, 5))
    st = s.translated(.03, 0, 0)
    pacman = Difference(s, st)
    sch = ImageSchema(10, .1, Optics(.66, 1.33, (0, 1)))
    h = DDA.calc_holo(pacman, sch)
    verify(h, 'dda_csg')

    hr = DDA.calc_holo(pacman.rotated(np.pi/2, 0, 0), sch)
    rotated_pac = pacman.rotated(np.pi/2, 0, 0)
    verify(h/hr, 'dda_csg_rotated_div')
示例#9
0
def test_fit_superposition():
    """
    Fit Mie superposition to a calculated hologram from two spheres
    """
    # Make a test hologram
    optics = Optics(wavelen=6.58e-07,
                    index=1.33,
                    polarization=[0.0, 1.0],
                    divergence=0,
                    spacing=None,
                    train=None,
                    mag=None,
                    pixel_scale=[2 * 2.302e-07, 2 * 2.302e-07])

    s1 = Sphere(n=1.5891 + 1e-4j, r=.65e-6, center=(1.56e-05, 1.44e-05, 15e-6))
    s2 = Sphere(n=1.5891 + 1e-4j, r=.65e-6, center=(3.42e-05, 3.17e-05, 10e-6))
    sc = Spheres([s1, s2])
    alpha = .629

    theory = Mie(optics, 100)
    holo = theory.calc_holo(sc, alpha)

    # Now construct the model, and fit
    parameters = [
        Parameter(name='x0', guess=1.6e-5, limit=[0, 1e-4]),
        Parameter('y0', 1.4e-5, [0, 1e-4]),
        Parameter('z0', 15.5e-6, [0, 1e-4]),
        Parameter('r0', .65e-6, [0.6e-6, 0.7e-6]),
        Parameter('nr', 1.5891, [1, 2]),
        Parameter('x1', 3.5e-5, [0, 1e-4]),
        Parameter('y1', 3.2e-5, [0, 1e-4]),
        Parameter('z1', 10.5e-6, [0, 1e-4]),
        Parameter('r1', .65e-6, [0.6e-6, 0.7e-6])
    ]

    def make_scatterer(x0, x1, y0, y1, z0, z1, r0, r1, nr):
        s = Spheres([
            Sphere(center=(x0, y0, z0), r=r0, n=nr + 1e-4j),
            Sphere(center=(x1, y1, z1), r=r1, n=nr + 1e-4j)
        ])
        return s

    model = Model(parameters,
                  Mie,
                  make_scatterer=make_scatterer,
                  alpha=Parameter('alpha', .63, [.5, 0.8]))
    result = fit(model, holo)

    assert_obj_close(result.scatterer, sc)
    assert_approx_equal(result.alpha, alpha, significant=4)
    assert_equal(result.model, model)
    assert_read_matches_write(result)
示例#10
0
def test_Spheres_translation():
    s1 = Sphere(n = 1.59, r = 5, center=[1, -1, 10])
    s2 = Sphere(n = 1.59, r = 1, center=[0,0,0])
    sc = Spheres(scatterers = [s1, s2])

    sc2 = sc.translated(1, 1, 1)

    assert_equal(sc.scatterers[0].r, sc2.scatterers[0].r)
    assert_equal(sc.scatterers[1].r, sc2.scatterers[1].r)
    assert_equal(sc.scatterers[0].n, sc2.scatterers[0].n)
    assert_equal(sc.scatterers[1].n, sc2.scatterers[1].n)
    assert_equal([2, 0, 11], sc2.scatterers[0].center)
    assert_equal([1, 1, 1], sc2.scatterers[1].center)
示例#11
0
def test_Spheres_rotation():
    s1 = Sphere(n = 1.59, r = 1, center = [1, 0, 0])
    s2 = Sphere(n = 1.59, r = 1, center = [-1, 0, 1])
    sc = Spheres(scatterers = [s1, s2])

    sc2 = sc.rotated(-np.pi/2, 0, 0)

    assert_equal(sc.scatterers[0].r, sc2.scatterers[0].r)
    assert_equal(sc.scatterers[1].r, sc2.scatterers[1].r)
    assert_equal(sc.scatterers[0].n, sc2.scatterers[0].n)
    assert_equal(sc.scatterers[1].n, sc2.scatterers[1].n)
    assert_almost_equal([0, -1, 0], sc2.scatterers[0].center)
    assert_almost_equal([0, 1, 1], sc2.scatterers[1].center)
示例#12
0
def test_integer_correctness():
    # we keep having bugs where the fitter doesn't
    schema = ImageSchema(shape = 100, spacing = .1,
                         optics = Optics(wavelen = .660, index = 1.33, polarization = (1, 0)))
    s = Sphere(center = (10.2, 9.8, 10.3), r = .5, n = 1.58)
    holo = Mie.calc_holo(s, schema)

    par_s = Sphere(center = (par(guess = 10, limit = [5,15]), par(10, [5, 15]), par(10, [5, 15])),
                   r = .5, n = 1.58)

    model = Model(par_s, Mie.calc_holo, alpha = par(.6, [.1, 1]))
    result = fit(model, holo)
    assert_allclose(result.scatterer.center, [10.2, 9.8, 10.3])
示例#13
0
def test_constraint():
    sch = ImageSchema(100)
    with warnings.catch_warnings():
        # TODO: we should really only supress overlap warnings here,
        # but I am too lazy to figure it out right now, and I don't
        # think we are likely to hit warnings here that won't get
        # caught elsewhere -tgd 2013-12-01
        warnings.simplefilter("ignore")
        spheres = Spheres([Sphere(r=.5, center=(0,0,0)),
                           Sphere(r=.5, center=(0,0,par(.2)))])
        model = Model(spheres, Multisphere.calc_holo, constraints=limit_overlaps())
        coster = CostComputer(sch, model)
        cost = coster._calc({'1:Sphere.center[2]' : .2})
        assert_equal(cost, np.ones_like(sch)*np.inf)
示例#14
0
    def test_mielens_multiple_returns_nonzero(self):
        scatterers = [
            Sphere(n=1.59, r=5e-7, center=(1e-6, -1e-6, 10e-6)),
            Sphere(n=1.59, r=1e-6, center=[8e-6, 5e-6, 5e-6]),
            Sphere(n=1.59 + 0.0001j, r=5e-7, center=[5e-6, 10e-6, 3e-6]),
            ]
        sphere_collection = Spheres(scatterers=scatterers)
        theory = MieLens()

        schema = yschema
        holo = calc_holo(schema, sphere_collection, index, wavelen,
                         theory=theory)
        self.assertTrue(holo is not None)
        self.assertTrue(holo.values.std() > 0)
示例#15
0
    def slide(self, value):
        '''
        When x or y are changed, instead of recomputing the hologram, we
        use the shortcut of selection a region of a larger pre-computed hologram.
        '''
        source = self.sender()

        #select area to display
        x = round(self.lcd.value() / self.scale)
        y = round(self.lcd2.value() / self.scale)
        im = scipy.misc.toimage(self.holo[256 - x:512 - x,
                                          256 - y:512 - y])  #PIL image

        #convert image to pixmap
        #https://github.com/shuge/Enjoy-Qt-Python-Binding/blob/master/image/display_img/pil_to_qpixmap.py
        if im.mode == "RGB":
            pass
        elif im.mode == "L":
            im = im.convert("RGBA")
        data = im.tostring('raw', "RGBA")
        qim = QtGui.QImage(data, 256, 256, QtGui.QImage.Format_ARGB32)
        pixmap = QtGui.QPixmap.fromImage(qim)

        #asign to the hologram
        myScaledPixmap = pixmap.scaled(QtCore.QSize(400, 400))
        self.label.setPixmap(myScaledPixmap)

        #make a sphere object size of window displayed to
        #label at the bottom of the frame
        sphere2 = Sphere(n=self.lcd5.value() + .0001j,
                         r=self.lcd4.value(),
                         center=(self.lcd.value(), self.lcd2.value(),
                                 self.lcd3.value()))
        self.sphObject.setText(repr(sphere2))
示例#16
0
def test_AlphaModelholo_likelihood():
    holo = get_example_data('image0001')
    s = Sphere(
        prior.Gaussian(.5, .1), prior.Gaussian(1.6, .1),
        (prior.Gaussian(5, 1), prior.Gaussian(5, 1), prior.Gaussian(5, 1)))
    model = AlphaModel(s, alpha=prior.Gaussian(.7, .1), noise_sd=.01)
    assert_pickle_roundtrip(model)
示例#17
0
def test_calc_field():
    s = Sphere(n=1.59, r=.5, center=(0, 0, 1))
    t = update_metadata(detector_grid(shape=(2, 2), spacing=.1),
                        illum_wavelen=0.66,
                        medium_index=1.33,
                        illum_polarization=(1, 0))
    thry = Mie(False)
    f = calc_field(t, s, 1.33, .66, (1, 0), theory=thry)
    assert_obj_close(t.attrs, f.attrs)
    gold = xr.DataArray(np.array([[[
        -3.95866810e-01 + 2.47924378e+00j, 0.00000000e+00 + 0.00000000e+00j,
        0.00000000e+00 - 0.00000000e+00j
    ],
                                   [
                                       -4.91260953e-01 + 2.32779296e+00j,
                                       9.21716363e-20 - 5.72226912e-19j,
                                       2.99878926e-18 - 1.41959276e-17j
                                   ]],
                                  [[
                                      -4.89755627e-01 + 2.31844748e+00j,
                                      0.00000000e+00 + 0.00000000e+00j,
                                      4.89755627e-02 - 2.31844748e-01j
                                  ],
                                   [
                                       -5.71886751e-01 + 2.17145168e+00j,
                                       1.72579090e-03 - 8.72241140e-03j,
                                       5.70160960e-02 - 2.16272927e-01j
                                   ]]]),
                        dims=['x', 'y', 'vector'],
                        coords={
                            'x': t.x,
                            'y': t.y,
                            'vector': ['x', 'y', 'z']
                        })
    assert abs((f - gold).max()) < 5e-9
示例#18
0
def test_voxelated_complex():
    s = Sphere(n = 1.2+2j, r = .2, center = (5,5,5))
    sv = Scatterer(s.indicators, s.n, s.center)
    schema = detector_grid(10, .1)
    holo_dda = calc_holo(schema, sv, illum_wavelen=.66, medium_index=1.33,
                         illum_polarization = (1, 0), theory=DDA)
    verify(holo_dda, 'dda_voxelated_complex', rtol=1e-5)
示例#19
0
def test_serialization():
    par_s = Sphere(center=(par(.567e-5, [0, 1e-5]), par(.576e-6, [0, 1e-5]),
                           par(15e-6, [1e-5, 2e-5])),
                   r=par(8.5e-7, [1e-8, 1e-5]),
                   n=par(1.59, [1, 2]))

    alpha = par(.6, [.1, 1], 'alpha')

    schema = ImageSchema(shape=100,
                         spacing=.1151e-6,
                         optics=Optics(.66e-6, 1.33))

    model = Model(par_s, Mie.calc_holo, alpha=alpha)

    holo = Mie.calc_holo(model.scatterer.guess, schema, model.alpha.guess)

    result = fit(model, holo)

    temp = tempfile.NamedTemporaryFile()
    save(temp, result)

    temp.flush()
    temp.seek(0)
    loaded = load(temp)

    assert_obj_close(result, loaded, context='serialized_result')
示例#20
0
    def test_holopy_hologram_equal_to_exact_calculation(self):
        # Checks that phase shifts and wrappers for mielens are correct
        theory_mielens = MieLens()
        illum_wavelength = 0.66  # 660 nm red light
        k = 2 * np.pi / illum_wavelength
        center = (10, 10, 5.)

        kwargs = {'particle_kz': center[2] * k,
                  'index_ratio': 1.2,
                  'size_parameter': 0.5 * k,
                  'lens_angle': theory_mielens.lens_angle}
        detector = detector_grid(10, 2.0)
        x = detector.x.values.reshape(-1, 1) - center[0]
        y = detector.y.values.reshape(1, -1) - center[1]

        rho = np.sqrt(x**2 + y**2)
        phi = np.arctan2(y, x)

        calculator = mielensfunctions.MieLensCalculator(**kwargs)
        scatterer = Sphere(n=kwargs['index_ratio'],
                           r=kwargs['size_parameter'] / k,
                           center=center)

        holo_calculate = calculator.calculate_total_intensity(k * rho, phi)
        holo_holopy = calc_holo(
            detector, scatterer, illum_wavelen=illum_wavelength,
            medium_index=1., illum_polarization=(1, 0), theory=theory_mielens)

        is_ok = np.allclose(holo_calculate, holo_holopy.values.squeeze(),
                            **TOLS)
        self.assertTrue(is_ok)
示例#21
0
def test_dda_fit():
    s = Sphere(n=1.59, r=.2, center=(5, 5, 5))
    o = Optics(wavelen=.66, index=1.33, pixel_scale=.1)

    schema = ImageSchema(optics=o, shape=100)

    h = Mie.calc_holo(s, schema)

    def make_scatterer(r, x, y, z):
        local_s = Sphere(r=r, center=(x, y, z))
        return Scatterer(local_s.indicators, n=s.n)

    parameters = [
        par(.18, [.1, .3], name='r', step=.1),
        par(5, [4, 6], 'x'),
        par(5, [4, 6], 'y'),
        par(5.2, [4, 6], 'z')
    ]

    p = Parametrization(make_scatterer, parameters)

    model = Model(p, DDA.calc_holo)

    res = fit(model, h)

    assert_parameters_allclose(res.parameters,
                               dict([('r', 0.2003609439787491),
                                     ('x', 5.0128083665603995),
                                     ('y', 5.0125252883133617),
                                     ('z', 4.9775097284878775)]),
                               rtol=1e-3)
示例#22
0
def test_DDA_coated():
    cs = Sphere(
        center=[7.141442573813124, 7.160766866147957, 11.095409800342143],
        n=[(1.27121212428+0j), (1.49+0j)], r=[.1-0.0055, 0.1])
    lmie_holo = calc_holo(schema, cs, index, wavelen, theory=Mie)
    dda_holo = calc_holo(schema, cs, index, wavelen, theory=DDA)
    assert_allclose(lmie_holo, dda_holo, rtol = 5e-4)
示例#23
0
    def slideZ(self, value):
        #using reconstructions-- better to use electric field?
        '''
        When z is changed, instead of recomputing the hologram, we
        use the shortcut of reconstructing the last computed hologram.
        '''
        source = self.sender()

        start = time.time()

        if self.lastZ == self.lcd3.value():
            self.holo = self.lastholo

        if self.lastZ < self.lcd3.value():
            self.holo = self.lastholo
            self.warning.setText(
                'Press calculate once you have all your parameters set')

        if self.lastZ > self.lcd3.value(
        ):  #reconstructing a plane between hologram and object
            self.holo = np.abs(
                propagate(self.lastholo, -self.lcd3.value() + self.lastZ))
            self.warning.setText('Reconstruction: hologram is approximate')

        end = time.time()

        #now take only the part that you want to display
        x = round(self.sld.value())
        y = round(self.sld2.value())
        selection = self.holo[256 - x:512 - x, 256 - y:512 - y]
        im = scipy.misc.toimage(selection)  #PIL image

        #https://github.com/shuge/Enjoy-Qt-Python-Binding/blob/master/image/display_img/pil_to_qpixmap.py
        #myQtImage = ImageQt(im)
        #qimage = QtGui.QImage(myQtImage)
        if im.mode == "RGB":
            pass
        elif im.mode == "L":
            im = im.convert("RGBA")
        data = im.tostring('raw', "RGBA")
        qim = QtGui.QImage(data, 256, 256, QtGui.QImage.Format_ARGB32)
        pixmap = QtGui.QPixmap.fromImage(qim)

        myScaledPixmap = pixmap.scaled(QtCore.QSize(400, 400))

        self.label.setPixmap(myScaledPixmap)
        #self.label.setGeometry(10, 10, 400, 400)
        #self.label.setScaledContents(True)

        self.timer.setGeometry(420, 400, 150, 30)
        self.timer.setText('Calc. Time: ' + str(round(end - start, 4)) + ' s')
        self.timer.setAlignment(QtCore.Qt.AlignBottom | QtCore.Qt.AlignCenter)

        sphere2 = Sphere(n=self.lcd5.value() + .0001j,
                         r=self.lcd4.value(),
                         center=(self.lcd.value(), self.lcd2.value(),
                                 self.lcd3.value()))

        self.sphObject.setText(repr(sphere2))
示例#24
0
def test_csg_construction():
    s = Sphere(n = 1.6, r=.5, center=(0, 0, 0))
    st = s.translated(.4, 0, 0)
    pacman = Difference(s, st)
    assert_allclose(pacman.bounds, [(-.5, .5), (-.5, .5), (-.5, .5)])