Esempio n. 1
0
    def test_shadows__full_scene(self):
        """Test that we identify a shadow in a full scene"""

        # First sphere is at z=10
        s1 = shapes.Sphere()
        s1.set_transform(transforms.Translate(0, 0, 10))

        # Second sphere is at the origin
        s2 = shapes.Sphere()
        s2.material = materials.Material()

        # Light is at z=-10
        l1 = lights.Light(position=points.Point(0, 0, -10),
                          intensity=colors.Color(1, 1, 1))

        scene = scenes.Scene(objects=[s1, s2], lights=[l1])

        # The ray is at z=5 (i.e. between the spheres), pointing at the further
        # out sphere
        ray = rays.Ray(points.Point(0, 0, 5), vectors.Vector(0, 0, 1))

        isection = intersections.Intersection(s2, 4)
        comps = isection.precompute(ray)

        result, _ = scene.shade_hit(comps)

        self.assertEqual(result, colors.Color(0.1, 0.1, 0.1))
Esempio n. 2
0
    def test_render_scene(self):
        """Test we can render a pixel in a simple scene"""


        # Inner sphere size 0.5, centered on the origin
        s1 = shapes.Sphere()
        s1.set_transform(transforms.Scale(0.5,0.5,0.5))

        # Outer sphere centered on the origin, size 1.0
        s2 = shapes.Sphere()
        s2.material = materials.Material(
            color=colors.Color(0.8, 1.0, 0.6), diffuse=0.7, specular=0.2)

        l1 = lights.Light(
            position=points.Point(-10, 10, -10),
            intensity=colors.Color(1, 1, 1)
            )

        scene = scenes.Scene(
            objects = [s1, s2],
            lights = [l1]
        )

        cam = cameras.Camera(11, 11, math.pi/2)

        from_point = points.Point(0, 0, -5)
        to_point = points.Point(0, 0, 0)
        up = vectors.Vector(0, 1, 0)
        cam.transform = transforms.ViewTransform(from_point, to_point, up)

        image = cam.render(scene)
        self.assertEqual(image.get(5, 5),
                         colors.Color(0.3807, 0.4758, 0.2855))
    def test_refractive_index_intersections(self):
        """Test we can calculate the refractive indices between intersections"""

        # Set up a scene with three glass spheres.  One at the origin with size
        # 2 then inside of that 2 that are offset along z by different amounts
        A = shapes.Sphere(material=materials.Material(refractive_index=1.5,
                                                      transparency=1.0))
        B = shapes.Sphere(material=materials.Material(refractive_index=2.0,
                                                      transparency=1.0))
        C = shapes.Sphere(material=materials.Material(refractive_index=2.5,
                                                      transparency=1.0))

        A.set_transform(transforms.Scale(2, 2, 2))
        B.set_transform(transforms.Translate(0, 0, -0.25))
        C.set_transform(transforms.Translate(0, 0, 0.25))

        r = rays.Ray(points.Point(0, 0, -4), vectors.Vector(0, 0, 1))

        xs = intersections.Intersections(intersections.Intersection(A, 2),
                                         intersections.Intersection(B, 2.75),
                                         intersections.Intersection(C, 3.25),
                                         intersections.Intersection(B, 4.75),
                                         intersections.Intersection(C, 5.25),
                                         intersections.Intersection(A, 6))

        expected_results = [
            {
                "n1": 1.0,
                "n2": 1.5
            },
            {
                "n1": 1.5,
                "n2": 2.0
            },
            {
                "n1": 2.0,
                "n2": 2.5
            },
            {
                "n1": 2.5,
                "n2": 2.5
            },
            {
                "n1": 2.5,
                "n2": 1.5
            },
            {
                "n1": 1.5,
                "n2": 1.0
            },
        ]

        for index, expected in enumerate(expected_results):

            comps = xs.intersections[index].precompute(r, all_intersections=xs)
            self.assertDictEqual(expected, {"n1": comps.n1, "n2": comps.n2})
Esempio n. 4
0
    def test_reflective_transparent_material(self):
        """Test shade_hit with a reflective, transparent material"""

        world = copy.deepcopy(self.default_scene)

        floor = shapes.Plane(material=materials.Material(
            reflective=0.5, transparency=0.5, refractive_index=1.5))
        floor.set_transform(transforms.Translate(0, -1, 0))

        ball = shapes.Sphere(material=materials.Material(
            color=colors.Color(1, 0, 0), ambient=0.5))
        ball.set_transform(transforms.Translate(0, -3.5, -0.5))

        r = rays.Ray(points.Point(0, 0, -3),
                     vectors.Vector(0, -math.sqrt(2) / 2,
                                    math.sqrt(2) / 2))
        xs = intersections.Intersections(
            intersections.Intersection(floor, math.sqrt(2)))

        world.add_object(floor)
        world.add_object(ball)

        comps = xs.intersections[0].precompute(r, all_intersections=xs)

        color, _ = world.shade_hit(comps, remaining=5)

        self.assertEqual(color, colors.Color(0.93391, 0.69643, 0.69243))
Esempio n. 5
0
    def test_intersection_miss(self):
        """Test we handle the case where the ray misses the sphere"""

        s = shapes.Sphere()
        r = rays.Ray(points.Point(0, 2, -5), vectors.Vector(0, 0, 1))

        self.assertEqual(s.intersect(r).intersections, [])
    def test_hits__positive(self):
        """Test we get the correct hit for multiple positive intersections"""

        shape = shapes.Sphere()

        i1 = intersections.Intersection(shape, 2)
        i2 = intersections.Intersection(shape, 1)
        isections = intersections.Intersections(i1, i2)

        self.assertEqual(isections.hit(), i2)
Esempio n. 7
0
    def test_pattern_transformation(self):
        """Test that pattern is affected by a pattern transform"""

        shape = shapes.Sphere()

        p = patterns.StripePattern(WHITE, BLACK)
        p.set_transform(transforms.Scale(2, 2, 2))

        self.assertEqual(p.pattern_at_shape(shape, points.Point(1.5, 0, 0)),
                         WHITE)
Esempio n. 8
0
    def setUp(self):
        """Set up a default scene for quick testing"""

        # Inner sphere size 0.5, centered on the origin
        self.s1 = shapes.Sphere()
        self.s1.set_transform(transforms.Scale(0.5, 0.5, 0.5))

        # Outer sphere centered on the origin, size 1.0
        self.s2 = shapes.Sphere()
        self.s2.material = materials.Material(color=colors.Color(
            0.8, 1.0, 0.6),
                                              diffuse=0.7,
                                              specular=0.2)

        self.l1 = lights.Light(position=points.Point(-10, 10, -10),
                               intensity=colors.Color(1, 1, 1))

        self.default_scene = scenes.Scene(objects=[self.s1, self.s2],
                                          lights=[self.l1])
    def test_hits__some_negative(self):
        """Test we get the correct hit for some negative intersections"""

        shape = shapes.Sphere()

        i1 = intersections.Intersection(shape, -1)
        i2 = intersections.Intersection(shape, 1)
        isections = intersections.Intersections(i1, i2)

        self.assertEqual(isections.hit(), i2)
Esempio n. 10
0
    def test_hits__all_negative(self):
        """Test we get no hits for all negative intersections"""

        shape = shapes.Sphere()

        i1 = intersections.Intersection(shape, -1)
        i2 = intersections.Intersection(shape, -2)
        isections = intersections.Intersections(i1, i2)

        self.assertIsNone(isections.hit())
Esempio n. 11
0
    def test_pattern_object_transformation(self):
        """Test that pattern is affected by pattern and object transforms"""

        shape = shapes.Sphere()
        shape.set_transform(transforms.Scale(2, 2, 2))

        p = patterns.StripePattern(WHITE, BLACK)
        p.set_transform(transforms.Translate(0.5, 0, 0))

        self.assertEqual(p.pattern_at_shape(shape, points.Point(2.5, 0, 0)),
                         WHITE)
Esempio n. 12
0
def test_sphere():
    sphere_center = [-0.5, 1, 0]
    s = shp.Sphere(1.5).shift(sphere_center)
    # plane Z=0, radius: 1.5
    # plane, Y=0, radius: sqrt(1.5**2 - 1) = 1.118
    # plane, X=0, redius: sqrt(1.5**2 - 0.25) = 1.41
    assert s.inside([0, 0, 0])
    assert not s.inside([1, 0, 0])
    assert not s.inside([0, -1, 0])
    assert not s.inside([0, 0, -1])
    assert not s.inside([0, 0, 1])
Esempio n. 13
0
    def test_intersection_standard(self):
        """Test we can identify what points a ray intersects with a sphere"""
        s = shapes.Sphere()
        r = rays.Ray(points.Point(0, 0, -5), vectors.Vector(0, 0, 1))

        result = s.intersect(r)

        self.assertEqual(result.intersections[0].t, 4)
        self.assertEqual(result.intersections[1].t, 6)
        self.assertEqual(result.intersections[0].shape, s)
        self.assertEqual(result.intersections[1].shape, s)
Esempio n. 14
0
    def test_intersection_behind(self):
        """Test we handle the case where the ray starts inside the sphere"""

        s = shapes.Sphere()
        r = rays.Ray(points.Point(0, 0, 5), vectors.Vector(0, 0, 1))

        result = s.intersect(r)

        self.assertEqual(result.intersections[0].t, -6)
        self.assertEqual(result.intersections[1].t, -4)
        self.assertEqual(result.intersections[0].shape, s)
        self.assertEqual(result.intersections[1].shape, s)
Esempio n. 15
0
    def test_intersections_with_transformed_ray__translation(self):
        """Test we get the correct intersections after adding a translation
        to a shape
        """

        s = shapes.Sphere()
        s.set_transform(transforms.Translate(5, 0, 0))

        r = rays.Ray(points.Point(0, 0, -5), vectors.Vector(0, 0, 1))

        result = s.intersect(r)
        self.assertTrue(len(result.intersections) == 0)
Esempio n. 16
0
    def test_hits__multiple(self):
        """Test we get the correct hit for some negative intersections"""

        shape = shapes.Sphere()

        i1 = intersections.Intersection(shape, -1)
        i2 = intersections.Intersection(shape, 7)
        i3 = intersections.Intersection(shape, -5)
        i4 = intersections.Intersection(shape, 2)
        i5 = intersections.Intersection(shape, 3)
        isections = intersections.Intersections(i1, i2, i3, i4, i5)

        self.assertEqual(isections.hit(), i4)
Esempio n. 17
0
    def test_normal_at__transformed(self):
        """Test we can calculate normal vectors on a transformed sphere"""

        s = shapes.Sphere()
        s.set_transform(transforms.Translate(0, 1, 0))
        n = s.normal_at(points.Point(0, 1.70711, -0.70711))

        self.assertEqual(n, vectors.Vector(0, 0.70711, -0.70711))

        s.set_transform(
            transforms.Scale(1, 0.5, 1) * transforms.RotateZ(math.pi / 5))

        n = s.normal_at(points.Point(0, math.sqrt(2) / 2, -math.sqrt(2) / 2))
        self.assertEqual(n, vectors.Vector(0, 0.97014, -0.24254))
Esempio n. 18
0
    def test_intersections_with_transformed_ray__scaling(self):
        """Test we get the correct intersections after adding a scaling
        to a shape
        """

        s = shapes.Sphere()
        s.set_transform(transforms.Scale(2, 2, 2))

        r = rays.Ray(points.Point(0, 0, -5), vectors.Vector(0, 0, 1))

        result = s.intersect(r)
        self.assertEqual(result.intersections[0].t, 3)
        self.assertEqual(result.intersections[1].t, 7)
        self.assertEqual(result.intersections[0].shape, s)
        self.assertEqual(result.intersections[1].shape, s)
Esempio n. 19
0
    def test_precompute__over_vector(self):
        """Test that we calculate a vector just inside of the surface of a
        shape
        """

        r = rays.Ray(points.Point(0, 0, -5), vectors.Vector(0, 0, 1))

        s = shapes.Sphere()
        s.set_transform(transforms.Translate(0, 0, 1))

        i = intersections.Intersection(s, 5)

        computations = i.precompute(r)
        self.assertTrue(computations.under_point.z > computations.point.z)
        self.assertTrue(computations.under_point.z > intersections.EPSILON / 2)
Esempio n. 20
0
    def test_initialization(self):

        shape = shapes.Sphere()
        t1 = 3.5
        t2 = -3.5

        i1 = intersections.Intersection(shape, t1)
        self.assertEqual(i1.t, 3.5)
        self.assertEqual(i1.shape, shape)

        i2 = intersections.Intersection(shape, t2)
        self.assertEqual(i2.t, -3.5)

        i = intersections.Intersections(i1, i2)
        self.assertEqual(i.intersections, [i2, i1])
Esempio n. 21
0
    def test_precompute__inside(self):
        """Test that we can precompute vectors for an intersection and ray when
        inside of a shape"""

        r = rays.Ray(points.Point(0, 0, 0), vectors.Vector(0, 0, 1))
        s = shapes.Sphere()
        i = intersections.Intersection(s, 1)

        computations = i.precompute(r)

        self.assertEqual(computations.t, 1)
        self.assertEqual(computations.point, points.Point(0, 0, 1))
        self.assertEqual(computations.eyev, vectors.Vector(0, 0, -1))
        self.assertEqual(computations.normalv, vectors.Vector(0, 0, -1))
        self.assertTrue(computations.inside)
Esempio n. 22
0
    def test_normal_at__non_transformed(self):
        """Test we can calculate normal vectors on the unit sphere"""

        s = shapes.Sphere()

        n = s.normal_at(points.Point(1, 0, 0))
        self.assertEqual(n, vectors.Vector(1, 0, 0))

        n = s.normal_at(points.Point(0, 1, 0))
        self.assertEqual(n, vectors.Vector(0, 1, 0))

        n = s.normal_at(points.Point(0, 0, 1))
        self.assertEqual(n, vectors.Vector(0, 0, 1))

        sqrt3d3 = math.sqrt(3) / 3
        n = s.normal_at(points.Point(sqrt3d3, sqrt3d3, sqrt3d3))
        self.assertEqual(n, vectors.Vector(sqrt3d3, sqrt3d3, sqrt3d3))
Esempio n. 23
0
    def obj_repr(self, render_params):
        """
        Returns complete representation of the point as a sphere.

        TESTS::

            sage: P = point3d((1,2,3),size=3,color='purple')
            sage: P.obj_repr(P.default_render_params())[0][0:2]
            ['g obj_1', 'usemtl texture...']
        """
        T = render_params.transform
        if T is None:
            import transform
            T = transform.Transformation()
        render_params.push_transform(~T)
        S = shapes.Sphere(self.size / 200.0).translate(T(self.loc))
        cmds = S.obj_repr(render_params)
        render_params.pop_transform()
        return cmds
Esempio n. 24
0
    def load_from_file(self):
        """Загрузить распределение из файла."""

        try:
            loaded_file, _ = QtWidgets.QFileDialog.getOpenFileName(
                None, 'Введите имя файла', self.work_dir,
                'Файлы распределений частиц (*.tsv)')

            self.loaded_files.append(loaded_file)

            import shapes

            with open(loaded_file, 'r') as f:
                loaded = []
                for strings_list in csv.reader(f, delimiter='\t'):
                    numbers_list = []
                    for string in strings_list:
                        numbers_list.append(float(string))
                    loaded.append(tuple(numbers_list))

                # определение размерности задачи
                for i in loaded:
                    if i[2]:  # хотя бы один параметр z != 0
                        self.options['dim_ind'] = 1
                        break

                for i in loaded:
                    if self.options['dim_ind'] == 0:  # 2D
                        self.loaded_particles.append(
                            shapes.Circle(x=i[0], y=i[1], d=i[3]))
                    elif self.options['dim_ind'] == 1:  # 3D
                        self.loaded_particles.append(
                            shapes.Sphere(x=i[0], y=i[1], z=i[2], d=i[3]))

                self.message('Загружен файл: {0}'.format(loaded_file))

            self.all_particles.extend(self.loaded_particles)

            self.cleanDistributions.setEnabled(True)

        except FileNotFoundError:
            self.message(
                'Распределение не загружено!\nПричина: не введено имя файла')
Esempio n. 25
0
    def calc_regular_distribution(self):
        """Calculation regular distribution."""

        import shapes

        self.regular_particles = []  # очистка

        x0 = self.options['regular_distribution'][0][0]
        dx = self.options['regular_distribution'][1][0]
        nx = self.options['regular_distribution'][2][0]

        y0 = self.options['regular_distribution'][0][1]
        dy = self.options['regular_distribution'][1][1]
        ny = self.options['regular_distribution'][2][1]

        if self.options['dim_ind'] == 1:  # 3D
            z0 = self.options['regular_distribution'][0][2]
            dz = self.options['regular_distribution'][1][2]
            nz = self.options['regular_distribution'][2][2]

        for x in [x0 + dx * i for i in range(nx)]:
            for y in [y0 + dy * i for i in range(ny)]:
                if self.options['dim_ind'] == 1:  # 3D
                    for z in [z0 + dz * i for i in range(nz)]:
                        particle = shapes.Sphere(
                            x, y, z,
                            self.options['regular_distribution_diameter'])
                        self.regular_particles.append(particle)
                else:  # 2D
                    # z = 0
                    particle = shapes.Circle(
                        x, y, self.options['regular_distribution_diameter'])
                    self.regular_particles.append(particle)

        self.all_particles.extend(
            self.regular_particles)  # расширить список всех частиц

        self.button_save.setEnabled(True)
        self.clean_distributions.setEnabled(True)

        self.message('Регулярное распределение частиц посчитано')
Esempio n. 26
0

class View2D:
    """View2D."""
    def __init__(self, edge, data):
        plt.close('all')
        plt.figure(num='Микроструктура', figsize=(7, 7), dpi=100)

        ax = plt.axes()
        FrontView(axes=ax, data=data, matrix_edge=edge)

        plt.tight_layout()
        plt.show()


if __name__ == '__main__':

    import shapes

    m = shapes.CubeMatrix(edge=100.)

    p1 = shapes.Sphere(x=0., y=20., z=40., d=10.)
    p2 = shapes.Sphere(x=50., y=50., z=50., d=20.)

    View3D(m.edge, [p1, p2])

    p3 = shapes.Circle(x=10., y=40, d=30.)
    p4 = shapes.Circle(x=50., y=75., d=15.)

    View2D(m.edge, [p3, p4])
Esempio n. 27
0
            0.5 * (particle.d / 2) ** 2 * (alpha - np.sin(alpha))

    return value


def filling(matrix, space_):
    """Степень заполнения матрицы частицами."""

    return space_ / matrix.space()


if __name__ == '__main__':

    import shapes

    square = shapes.SquareMatrix(edge=5.)
    print(square)
    circle = shapes.Circle(x=2.5, y=2.5, d=2.)
    print(circle)
    print('S={0:.3f}'.format(space(square, circle)))
    print('KV={0:.3f}'.format(filling(square, space(square, circle))))

    print('-'*50)

    cube = shapes.CubeMatrix(edge=5.)
    print(cube)
    sphere = shapes.Sphere(x=2.5, y=2.5, z=2.5, d=2.)
    print(sphere)
    print('V={0:.3f}'.format(space(cube, sphere)))
    print('KV={0:.3f}'.format(filling(cube, space(cube, sphere))))
Esempio n. 28
0
p = shapes.Parallelogram(200, 100)
p.printarea()
p.get_sides()
p.printperimeter()
p.draw()

print("\n HEXAGON \n")
h = shapes.Hexagon(6, 150)
h.printarea("Hexagon")
h.get_sides("Hexagon")
h.printperimeter("Hexagon")
h.draw()

print("\n CIRCLE \n")
c = shapes.Circle(100)
print("Area of circle is: ",c.area())
print("Circumference of circle is: ",c.circumference())
c.draw()

print("\n ELLIPSE \n")
c = shapes.Ellipse(100, 50)
print("Area of ellipse is: ",c.area())
print("Circumference of ellipse is: ",c.circumference())
c.draw()

print('\n Sphere \n')
s = shapes.Sphere(100)
print("Surface area of sphere is: ", s.surface_area())


def preset_filling_degree(app):
    """Создать распределение частиц по известной степени заполнения фракций."""
    def fil():
        if app.options['dim_ind'] == 0:  # 2D
            m = shapes.SquareMatrix(app.options['matrix'])
        elif app.options['dim_ind'] == 1:  # 3D
            m = shapes.CubeMatrix(app.options['matrix'])

        s = fill_deg.space(matrix=m, particle=particle)
        f = fill_deg.filling(matrix=m, space_=s)

        return f

    print_to_console(app, 'new')

    app.processRunning = True
    for diameter, max_filling in app.options['fractions_definition']:
        if diameter != 0:
            current_filling = 0
            current_iteration = 1
            # кол-во попыток подобрать распределение частиц в матрице

            while app.processRunning and current_filling < max_filling and\
                    current_iteration < app.options['max_iter']:
                app.message('<font color="teal">текущее заполнение = {0:.3f}, \
                            диаметр = {1:.1f}</font>'.format(
                    current_filling, diameter))

                if app.options['dim_ind'] == 0:  # 2D
                    point = shapes.Point2D()
                elif app.options['dim_ind'] == 1:  # 3D
                    point = shapes.Point3D()

                if app.options['var_ind'] == 0:
                    # частицы целиком находятся в матрице
                    point.randomize_particles_inside(app.options['matrix'],
                                                     diameter)
                elif app.options['var_ind'] == 1:
                    # центры частиц находятся в матрице
                    point.randomize_centers_inside(app.options['matrix'])

                QtWidgets.qApp.processEvents()
                if app.processRunning:
                    app.message('Итерация {0}: ({1})'.format(
                        current_iteration, point))
                    app.current_event_label.setText(
                        'диаметр = {0:.1f}; текущее заполнение = {1:.3f}; \
                        итерация = {2}'.format(diameter, current_filling,
                                               current_iteration))
                else:
                    break

                if app.options['dim_ind'] == 0:  # 2D
                    particle = shapes.Circle(point.x, point.y, diameter)
                elif app.options['dim_ind'] == 1:  # 3D
                    particle = shapes.Sphere(point.x, point.y, point.z,
                                             diameter)

                # проверка кол-ва пересечения границ (допускается только одно!)
                if particle.crossing(matrix_edge=app.options['matrix']) > 1:
                    current_iteration += 1
                    continue

                # проверка близости границ
                if check_boundary(app, particle):
                    # недопустимо близко к границе
                    current_iteration += 1
                    continue

                # добавление первой частицы
                if not app.random_particles:
                    app.random_particles.append(particle)
                    print_to_console(app, 'added')
                    current_filling += fil()
                    continue

                # добавление остальных частиц
                intersec = False  # пересечение частиц
                for i in app.random_particles:
                    if intersection(app, particle, i):
                        print_to_console(app, 'overlap', i)
                        intersec = True  # установлено пересечение частиц
                        current_iteration += 1
                        continue
                if not intersec:
                    app.random_particles.append(particle)
                    print_to_console(app, 'added')
                    current_filling += fil()
                    continue
                else:
                    current_iteration += 1

        else:
            continue

    if app.processRunning:
        app.message(
            '<font color="blue"><b>Все частицы успешно добавлены</b></font>')

        app.all_particles = app.random_particles.copy()
        # обновление общего набора частиц
        app.saveAll.setEnabled(True)
    else:
        app.message('<font color="red"><b>Процесс расчёта \
            остановлен пользователем</b></font>')

    app.processStart.setEnabled(True)
    app.processStop.setDisabled(True)
    app.cleanDistributions.setEnabled(True)

    app.current_event_label.setText('')
def preset_particles_number(app):
    """Создать распределение частиц по известному их количеству."""

    print_to_console(app, 'new')
    fails = {}  # не удалось подобрать координаты частицы

    app.processRunning = True
    for diameter, remain in app.options['fractions_definition']:
        if diameter != 0:
            while app.processRunning and remain > 0:
                # осталось разместить частиц данного диаметра
                app.message('<font color="blue">Осталось разместить:</font> \
                            <font color="teal">кол-во = {0}, \
                            диаметр = {1:.1f}</font>'.format(remain, diameter))
                current_iteration = 1
                # кол-во попыток подобрать распределение частиц в матрице
                while current_iteration < app.options['max_iter']:

                    if app.options['dim_ind'] == 0:  # 2D
                        point = shapes.Point2D()
                    elif app.options['dim_ind'] == 1:  # 3D
                        point = shapes.Point3D()

                    if app.options['var_ind'] == 0:
                        # частицы целиком находятся в матрице
                        point.randomize_particles_inside(
                            app.options['matrix'], diameter)
                    elif app.options['var_ind'] == 1:
                        # центры частиц находятся в матрице
                        point.randomize_centers_inside(app.options['matrix'])

                    QtWidgets.qApp.processEvents()
                    if app.processRunning:
                        app.message('Итерация {0}: ({1})'.format(
                            current_iteration, point))
                        app.current_event_label.setText(
                            'диаметр = {0:.1f}; осталось разместить = {1:.0f};\
                             итерация = {2}'.format(diameter, remain,
                                                    current_iteration))
                    else:
                        break

                    if app.options['dim_ind'] == 0:  # 2D
                        particle = shapes.Circle(point.x, point.y, diameter)
                    elif app.options['dim_ind'] == 1:  # 3D
                        particle = shapes.Sphere(point.x, point.y, point.z,
                                                 diameter)

                    # проверка кол-ва пересечения границ
                    # (допускается только одно!)
                    if particle.crossing(matrix_edge=app.options['matrix'])\
                            > 1:
                        continue

                    # проверка близости границ
                    if check_boundary(app, particle):
                        # недопустимо близко к границе
                        current_iteration += 1
                        continue

                    # добавление первой частицы
                    if not app.random_particles:
                        app.random_particles.append(particle)
                        print_to_console(app, 'added')
                        break

                    # добавление остальных частиц
                    intersec = False  # пересечение частиц
                    for i in app.random_particles:
                        if intersection(app, particle, i):
                            print_to_console(app, 'overlap', i)
                            intersec = True  # установлено пересечение частиц
                            break
                    if not intersec:
                        app.random_particles.append(particle)
                        print_to_console(app, 'added')
                        break
                    else:
                        current_iteration += 1
                else:
                    if diameter in fails:
                        fails[diameter] += 1
                    else:
                        fails[diameter] = 1
                    app.message('<font color="red">Не удалось добавить \
                        частицу диаметра {0}</font>'.format(diameter))

                remain -= 1

        else:
            continue
    if app.processRunning:
        if fails:
            app.message(
                '<font color="red"><b>Не добавлены частицы:</b></font>')
            for diameter in fails:
                app.message('<font color="red">диаметр = {0:.1f}, \
                    кол-во = {1}</font>'.format(diameter, fails[diameter]))
        else:
            app.message('<font color="blue"><b>Все частицы \
                успешно добавлены</b></font>')

        app.all_particles = app.random_particles.copy()
        # обновление общего набора частиц
        app.saveAll.setEnabled(True)
    else:
        app.message('<font color="red"><b>Процесс расчёта \
            остановлен пользователем</b></font>')

    app.processStart.setEnabled(True)
    app.processStop.setDisabled(True)
    app.cleanDistributions.setEnabled(True)

    app.current_event_label.setText('')