Построение таблицы значений функции



Тема 3

Режим программирования

С крипт

Система Matlab создана таким образом, что любые (подчас весьма сложные) расчеты можно выполнять в режиме прямых вычислений, т.е. без подготовки программы. Это превращает Matlab в необычайно мощный калькулятор, который способен производить не только обычные для калькуляторов вычисления (например, выполнять арифметические операции и вычислять значения элементарных функций), но и операции с векторами и матрицами, комплексными числами, рядами и полиномами. Можно задать и вывести графики различных функций – от простой синусоиды до сложной трехмерной фигуры. Перечисленные задачи не относятся к разряду сложных. Тем не менее решать их в режиме прямых вычислений не очень удобно. Часто требуется выполнить подготовительную работу, результаты которой не должны немедленно появляться на экране, но должны быть отображены в последствии. Результирующая картина, например таблица, в командном окне не должна перемежаться командами, вводимыми с клавиатуры. Работа в командном окне в режиме прямых вычислений становится обременительной, когда необходимо выполнять повторение одной и той же вычислительной схемы с небольшой модификацией алгоритма или для различных исходных данных.

В Matlab существует возможность сохранять последовательность команд, вводимых с клавиатуры, в текстовом файле в виде программы, а затем вызывать ее в Command Window и автоматически выполнять, не нажимая на Enter после каждой команды. Такие файлы с программами в Matlab принято называть скриптами (scripts) или сценариями. Скрипт сохраняется на диске в файле с расширением m. M-файлы являются обычными текстовыми файлами, которые создаются с помощью текстового редактора. Система Matlab поддерживает специальный встроенный редактор/отладчик, хотя можно использовать и любой другой текстовый редактор с ASCII-кодами, например Блокнот. Открыть встроенный редактор можно двумя способами: в главном окне Matlab из меню File выбрать опцию New, а затем M-File или использовать команду редактирования Еdit. В любом случае редактор работает в собственном окне (рис. 3.1).

Рис. 3.1. Окно редактора Matlab

Скрипты являются самым простым типом m-файла – у них нет входных и выходных аргументов (в каком-то смысле сценарий является аналогом главной программы алгоритмических языков). Сценарии оперируют данными из рабочей области Workspace и могут генерировать в нее новые переменные для последующей обработки в этом же файле. Данные, которые используются в сценарии, сохраняются в рабочей области и после завершения данной программы могут быть использованы для дальнейших вычислений. Несколько скриптов могут работать друг за другом, обмениваясь данными через рабочее пространство, поскольку оно у них общее.

После создания сценария его надо сохранить в файле на диске. Этот файл может иметь имя, составленное по общим правилам составления идентификаторов Matlab (желательно, чтобы оно не совпало с именами файлов, входящих в стандартную поставку системы Matlab), но расширение имени должно состоять из одной буквы m (например, myScript1.m и т.п.). Сохраненный в m-файле сценарий в любой момент можно выполнить, если набрать в командном окне имя этого файла (без расширения) и нажать клавишу Enter. Запустить скрипт, текст которого открыт в окне редактора, на выполнение можно непосредственно из окна редактора, если нажать клавишу управления F5, или на панели инструментов редактора щелкнуть ЛКМ на пиктограмме  Run (выполнить), она же Save and run (сохранить и выполнить). Редактирование текста сценария выполняется по общим правилам работы с текстовыми редакторами Windows.

 

 

Диалоговый ввод/вывод

В процессе выполнения m-файла пользователь может вывести на экран запрос и ввести соответствующую информацию с клавиатуры; сделать паузу до нажатия клавиши.

Формирование запроса для ввода данных с клавиатуры выполняется функцией input

ИмяПеременной = input('Текст запроса')

При выполнении данной операции присваивания в командное окно выводится сообщение Текст запроса и выполнение программы приостанавливается до тех пор, пока пользователь не введет число с клавиатуры и не нажмет на клавишу Enter.

Функция возвращает введённое с клавиатуры числовое значение и размещает его в переменной, имя которой указано слева от оператора присваивания

>> x = input('Задайте значение аргумента ')

Задайте значение аргумента 7.5

x =

7.5000

По умолчанию выполняется эхо-печать значения переменной-приемника. Как и для любой функции, использование символа ; подавляет печать результата ввода. Если в ответ на запрос пользователь вводит арифметическое выражение, то функция input вычисляет его и возвращает в переменную-приемник полученное значение

>> f=50;

>> w = input('Задайте частоту в рад/с ')

Задайте частоту в рад/с 2*pi*f

w =

314.1593

Можно вводить и матрицы

>> coord = input('Задайте координаты точки ')

Задайте координаты точки  [2.5 -3]

coord =

2.5000 -3.0000

или

>> A = input('Задайте матрицу 2 на 2 ')

Задайте матрицу 2 на 2  [11 12; 21 22]

 

A =

11 12

21 22

Функция input может возвращать не только числовые значения, но и строковое выражение, вводимое пользователем. Для ввода строки символов в список параметров функции вторым входным аргументом необходимо указать 's'. На запрос input следует ввести строку текста, не заключая ее в апострофы. Например,

>> file_name = input('Укажите имя файла: ','s')

Укажите имя файла: data.txt

file_name =

data.txt

Переменная file_name становится строкой из восьми символов.

Если в списке параметров функции input не указать 's', то строковое значение необходимо вводить в апострофах

>> symbol = input('Введите символ:  ');

Введите символ:  'W'

symbol=

W

Для выдачи результата на экран используется функция disp, предназначенная для вывода значений в командное окно Matlab. С ее помощью можно выводить числовые, символьные (текст) и логические значения, задавая их константами, именами переменных или выражениями соответствующего типа. По умолчанию функция работает только с одним входным параметром и каждый disp начинает вывод значений с новой строки. Если одним disp необходимо вывести несколько значений в одной строке, то их следует конкатенировать (сцепить) в единый вектор (подобную "хитрость" мы уже применяли при использовании функции size для работы с матрицами). Внимание: сцеплять разрешено только однотипные данные! В связи с этим полезными бывают функции преобразования типа (табл. 3.1). Имена функций преобразования построены по схеме

исходный_тип to тип_результата

(вместо to используется 2).

 

 

Таблица 3.1

Функция Описание Пример использования
num2str Преобразование числового значения в строковое >> stroka=['2+3=' num2str(2+3)] stroka = 2+3=5
str2num Преобразование строкового значения в числовое >> s=['1.5' '-2j'] >> number=str2num(str) number = 1.5000 - 2.0000i

 

В некоторых случаях бывает целесообразно устанавливать паузу между отдельными шагами алгоритма, например при выводе на экран последовательности графиков. Команда

pause

останавливает выполнение программы до тех, пока не будет нажата какая-нибудь клавиша. Чтобы реализовать паузу в n секунд, необходимо выполнить

pause(n).

 

Тема 4

ВИЗУАЛИЗАЦИЯ ДАННЫХ В MATLAB

Общие сведения

В инженерной практике часто возникает необходимость изображать данные в виде таблиц или графиков. Например, нарисовать временные диаграммы  и , характеризующие переходный процесс в электрической цепи. Вывод результатов вычислений в наглядной графической форме (визуализация) является одной из важнейших процедур в инженерной и научной практике. Инженерную графическую информацию следует снабжать описанием, поясняющим, какой объект исследован, и какая математическая модель для этого использована. Задачей инженерной программы часто является сравнение нескольких функций, полученных, например, при разных значениях конструктивных параметров. Такое сравнение удобнее и нагляднее проводить, если результаты представлены в виде графиков. Если нужно сравнивать графики функций одного и того же аргумента, то их удобнее всего строить в общих координатных осях. При этом полезно соблюдать следующие рекомендации:

1) если диапазоны изменения функций и их аргумента различаются незначительно (не более чем на порядок), то графики строятся в общих координатных осях в линейном масштабе;

2) если диапазоны изменения функций и/или аргумента положительные и различаются значительно (более чем на порядок), то графики строятся в общих координатных осях в логарифмическом масштабе по соответствующей оси;

3) если функции представляют величины разной физической природы, но имеют общий аргумент, изменяющийся в одном диапазоне, то графики размещаются друг под другом таким образом, чтобы одинаковые значения аргумента во всех графиках располагались на одной вертикали.

Matlab обладает хорошо развитыми графическими возможностями для визуализации результатов.

Построение таблицы значений функции

 

Отображение результатов в виде таблицы удобно, если имеется сравнительно небольшое количество значений функции. Пусть требуется вывести в командное окно таблицу значений функции , представляющей собой аналитическое описание полигармонического сигнала, состоящего из первой, третьей и пятой гармоник базовой частоты 50 Гц), для моментов времени 0; 0,003; 0,01; 0,015; 0,02; 0,027; 0,03; 0,034; 0,04. Технология табулирования функции в Matlab состоит в реализации следующих шагов:

1. Создадим вектор-строку, содержащую значения независимой переменной (данном примере это время). Соблюдая правила хорошего тона, дадим ей мнемоническое имя t – время.

2. Вычислим значения тока для каждого элемента вектора t и разместим их в векторе-строке с именем current – ток. При вычислениях для упрощения выражений рекомендуется использовать промежуточные переменные. Так, в нашем примере удобно ввести переменную w=100*pi, соответствующую частоте . Следует помнить, что операции в выражении для вычисления значений функции должны выполняться поэлементно.

3. Придадим таблице более удобный для чтения вид. Как правило, данные в таблице располагают в столбцах. Таблица предваряется названием и шапкой. Для оформления шапки таблицы обычно используется функция disp, предназначенная для вывода значений в командное окно Matlab.

Реализуем шаги описанной выше технологической цепочки табулирования функции в программе на языке Matlab, оформленной в виде script-файла tabfun.m (рис. 4.1).

Рис. 4.1. Окно редактора с текстом script-файла

 

В титульной строке окна редактора видно, что данный файл сценария сохранен на диске D в каталоге MATLAB701 в папке work. В нижней части окна редактор отмечает, что данный m-файл является именно скриптом. По левой стороне окна даны номера строк программы. Matlab будет на них ссылаться при обнаружении ошибок в тексте программы (синтаксические ошибки) или при ее выполнении (ошибки шага выполнения). В целом окно редактора оформлено в привычном стиле Windows. На рис. 4.2 показано как выполнение этой программы отразилось на состоянии рабочего стола.

В рабочем пространстве Workspace созданы три переменные, содержащие по девять расчетных значений тока, времени и скаляр частоты. Эти данные могут быть использованы в дальнейшем как обычные переменные Matlab (каковыми они и являются). В командном окне отображена таблица из двух колонок. Первая – время, вторая – значения тока для заданных моментов времени.

 

Рис. 4.2. Результат выполнения программы рис. 4.1

Двумерная графика

Двумерная графика предназначена для построения на плоскости графиков функций одной переменной (одного аргумента) . Список функций, используемых в двумерной графике, может быть выведен в Command Window по команде

help graph2d

 

3.1. Общие правила построения графиков

функции одной переменной

Общие правила задания графиков следующие:

1) размеры х и у должны быть согласованы;

2) если х и у – векторы, то будем иметь один график функции ;

3) если х – матрица, а у – вектор, то будем иметь графики функции , аргументы которой заданы столбцами матрицы х;

4) если х – вектор, а у – матрица, то будем иметь графики функций, заданных столбцами матрицы у, одного аргумента х;

5) если х и у – матрицы, то будем иметь графики функций, заданных столбцами матрицы у, аргументы которых заданы столбцами матрицы х.

 

Общие правила вывода графиков следующие:

1) текущий график, строится с помощью одной из специальных функций Matlab в текущем графическом окне Figure 1 (рис. 4.3). По умолчанию очередной график выводится в то же окно, при этом предыдущий график автоматически удаляется. Интерфейс графического окна соответствует стилю Windows: содержит титульную строку, стандартную строку меню, панель инструментов, которые легко осваиваются интуитивно;

Рис. 4.3. Пустое графическое окно

 

2) открытие отдельного графического окна с номером n для вывода в него очередного графика выполняется по команде
figure(n), которая ставится перед обращением к очередной функции построения графика;

3) режим наложения графиков (вывод в текущее графическое окно нескольких графиков в одних осях), строящихся с помощью отдельных функций Matlab, обеспечивается командой hold on, которая ставится перед очередной функцией построения графика;

4) отмена режима наложения графиков выполняется командой hold off, которая ставится после последней функции построения графика в текущем окне;

5) разбиение текущего графического окна на подокна для вывода в них независимых графиков выполняется с помощью функции subplot(m,n,p). Здесь m и n – соответственно количество строк и столбцов в матрице подокон; р – порядковый номер текущего (активного) подокна, считая по строкам слева направо.

 

3.2. Оформление графиков

Основные функции оформления графиков функций приведены в табл. 4.1.

Таблица 4.1

Функция Описание Формат использования
axis Управление масштабированием по осям  axis auto – автоматическое масштабирование осей (установлено по умолчанию);  axis square – построение в квадратной области;  axis equal – построение с равным шагом по обеим осям;  axis off – удаление изображения осей координат и надписей на них;  axis ij – перемещает начало отсчета в левый верхний угол;  axis xy – возвращает декартову систему координат с началом отсчета в левом нижнем углу графика
grid Нанесение координатной сетки с автоматическим выбором шага grid
gtext Вывод текста на поле графика в произвольном месте gtext('текст') Начало текста указывается на поле графика перекрестием и может перемещаться мышью
legend Размещение легенды legend('текст1','текст N',pos) где текстi – названия графиков, изображенных в одних осях; pos – параметр размещения легенды: -1 – вне поля графика, 0 – автоматическое расположение, 1 или 2 – в правом или левом верхнем углу, 3 или 4 – в правом или левом нижнем углу
title Вывод заголовка графика title('текст_заголовка')
xlabel ylabel Обозначение осей абсцисс и ординат соответственно xlabel('текст') ylabel('текст')
xlim ylim Установка границ по оси абсцисс и ординат при выводе графика xlim([xmin xmax]) ylim([ymin ymax]) Двухэлементные векторы задают границы по соответствующим осям

3.3. Построение графиков

Matlab позволяет строить графики функций в линейном, логарифмическом и полулогарифмическом масштабах. В одном графическом окне можно построить графики нескольких функций, с разным шагом и даже определенных на разных отрезках. В последнем случае при построении графиков Matlab выбирает максимальный отрезок, содержащий все остальные. Дополнительные параметры графических функций позволяют управлять основными свойствами линий на графиках. Для того чтобы построить график функции, нужно сформировать два вектора x (абсцисс) и y (ординат) одинакового размера и обратиться к соответствующей функции рисования. Таким образом, фактически строится график таблично заданной функции, т.е. зависимость одного вектора от другого. Поведение функции между узлами таблицы определяется линейной интерполяцией, т.е. соседние точки соединяются прямой линией. Наиболее часто используемые функции Matlab, предназначенные для построения двумерных графиков, приведены в табл. 4.2.

 

Таблица 4.2

Функция Формат использования Назначение
plot plot(x,y)  График в линейном масштабе
plotyy plotyy(x,y) График в линейном масштабе с двумя осями ординат
loglog loglog(x,y)  График в логарифмическом масштабе по обеим осям
semilogx semilogx (x,y)  График в логарифмическом масштабе по оси абсцисс и линейном по оси ординат
semilogy semilogx (x,y)  График в линейном масштабе по оси абсцисс и логарифмическом по оси ординат
fplot fplot('функция',[d1 d2], tol, n)  График на заданном интервале с автоматическим выбором шага. Эта функция будет рассмотрена позднее при изучении темы 5

 

Рассмотрим использование этих функций более подробно. Построение графиков функций одной переменной в линейном масштабе осуществляется при помощи функции plot. В зависимости от входных аргументов plot позволяет строить один или несколько графиков, менять цвет и стиль линий и добавлять маркеры на каждый график. В простейшем случае обращение к функции может быть выполнено с одним аргументом

plot(y)

Здесь y – вектор или матрица значений функции. В качестве значений аргумента в этом случае будут служить индексы элементов вектора или столбцов матрицы.

В классическом варианте функция вызывается с двумя

plot(x,y)

или тремя аргументами

plot(x,y,options)

Здесь x и y – векторы, элементами которых являются значения аргумента и функции соответственно; options – список опций управления свойствами линии графика, заключенный в апострофы. Список опций может содержать до трех специальных символов, определяющих тип линии, тип маркера и цвет линии графика (табл. 4.3).

Таблица 4.3

Тип линии Тип маркера Цвет линии (маркера)
- непрерывная .    точка b   синий
-- штриховая + плюс g   зеленый
: пунктир * звездочка r   красный

-. штрих-пунктир

о кружок с голубой
х крестик m фиолетовый
s  квадрат у желтый
d  ромб k   черный
  v  треугольник вниз  
  < треугольник влево  
  > треугольник вправо  
  p пентаграмма  
  h шестиугольник  

 

За одно обращение к plot можно нарисовать и несколько графиков в одних осях. Например, три графика можно нарисовать следующим образом:

plot(x1,y1,x2,y2,x3,y3)

или

plot(x1,y1,'--og' ,x2,y2,'k-.+',x3,y3,'*:k')

или

plot(x1,y1,x1,y2,'-r',x3,y3,'om')

Из примеров видно, что в одних осях можно рисовать графики как для одинаковых, так и для разных значений аргументов; некоторым кривым можно задавать опции рисования, а некоторым – нет; можно задавать как полный список опций, так и частичный; перечислять опции можно в любом порядке. По умолчанию (список options не указан) график строится непрерывной линией, тип маркера – точка (пиксель), цвет – в зависимости от того, какая по порядку кривая отображается при обращении к данной функции. Порядок автоматического перебора цветов соответствует их перечислению в табл. 4.3. Если одним plot рисуется больше восьми графиков, то цвета начинают циклически повторяться.

Рекомендации: 1) если в графическом окне необходимо показать, что один график совпадает с другим, то первый из них следует рисовать сплошной линией одного цвета, а второй – прерывистой линией другого цвета. Иначе на экране будет виден только график, нарисованный последним!

2) Если расчетных точек много, то не стоит прорисовывать маркеры. Иначе на экране будет изображена "гусеница" – сплошной поток маркеров. Если маркеры все же необходимы, то следует нарисовать не все, а только некоторые из них. Например, каждый десятый или каждый сотый маркер. Для этого отдельно с более крупным шагом формируются векторы значений функции и аргумента

markx=x(1:100:end); marky=y(1:100:end);

которые затем используются для прорисовки маркеров поверх уже нарисованной кривой, изображающей функцию

plot(x,y,markx,marky,'o')

Выше говорилось о том, что при рисовании графиков plot автоматически выполняет линейную интерполяцию между соседними точками. Об этом необходимо помнить, задавая количество точек при изображении кривых. Иначе можно получить "фантастический" результат! Например, пусть требуется построить график функции  на отрезке [0; 0,2]. Напишем программу, не забывая, что табулирование функции выполняется поэлементными операциями над векторами. Сохраним программу в m-файле (впрочем, эта программа хороша и для выполнения в режиме прямых вычислений).

x1=0:1e-2:0.2;

y1=exp(-x1).*(sin(x1)+0.1*sin(100*pi*x1));

x2=0:0.7e-2:0.2;

y2=exp(-x2).*(sin(x2)+0.1*sin(100*pi*x2));

x3=0:0.1e-2:0.2;

y3=exp(-x3).*(sin(x3)+0.1*sin(100*pi*x3));

plot(x1,y1,'r--',x2,y2,'b',x3,y3,'k-.'), grid

title('y=e^-^x(sin(x)+0,1sin(100pi*x)')

xlabel('x'), ylabel('f(x)')

legend('not correct curve1','not correct curve2','correct curve3')

Выполним программу. Откроем графическое окно (рис. 4.4).

Рис. 4.4. Графики функции

 

Видим, что графики y1(x1), построенный пунктиром с шагом 0,01, и y2(x2), построенный сплошной линией с шагом 0,07, просто неверные! А вот третий график y3(x3), нарисованный с шагом 0,001 штрих-пунктиром, соответствует действительности. В чем же дело? Почему одна и та же функция нарисована до неузнаваемости по-разному? Ответ прост – в первых двух случаях вычисления со слишком большим шагом привели к тому, что расчетные точки, верные сами по себе, легли на синусоидоподобной кривой функции неудачно и, соединенные между собой отрезками прямой, исказили ее изображение.

Иногда требуется сравнить поведение двух функций, значения которых сильно отличаются друг от друга. При рисовании автоматически будет выполнено масштабирование. В результате график функции с небольшими значениями практически сольется с осью абсцисс и установить его вид будет затруднительно.

Выход может быть найден в использовании функции plotyy, которая выводит графики в окно с двумя осями ОУ, имеющими подходящий масштаб. При этом цвета графика и соответствующей ему оси ординат будут совпадать. На рис. 4.5 приведен результат выполнения в режиме прямых вычислений следующей последовательности операторов:

>> x=-pi:pi/10:pi;

>> y1=250*sin(x);

>> y2=0.5*sin(x-pi/3);

>> plotyy(x,y1,x,y2), grid

Функцию plotyy можно использовать только для рисования двух кривых в одних осях. При построении большего числа разновеликих функций можно воспользоваться домножением вектора ординат на масштабный множитель. Например, задать растяжение первой и сжатие второй кривых по вертикали в сто раз

plot(x,100*y1,x2,0.01*y2,x,y3)

Факт принудительного масштабирования кривых обязательно следует отразить в легенде

legend('100у1(х)','0,01у2(х)','y3(x)')

Функции plot и plotyy используют при построениях линейный масштаб по обеим осям. Для построения графиков в логарифмическом и полулогарифмическом масштабах служат функции loglog, semilogx и semilogy (см. табл. 4.2). Аргументы и правила использования этих функций такие же, как и для функции plot.

При построении графиков бывает удобно задавать векторы значений аргументов x, используя следующие функции:

linspace(d1,d2,n) – задание диапазона по оси абсцисс в линейном масштабе. Здесь d1, d2 – начальное и конечное значения диапазона; n – количество равноотстоящих точек (по умолчанию 50);

logspace(d1,d2,n) – задание диапазона по оси абсцисс в логарифмическом масштабе. Здесь d1, d2 – начальное 10d1 и конечное 10d2 значения диапазона; n – количество точек в логарифмическом масштабе (по умолчанию 50).

 

3.4. Управление свойствами графиков

Свойствами графиков можно управлять с помощью дополнительных (необязательных) входных параметров функций построения графиков, которые разделены на две группы: LineSpec – свойства без стандартных имен и PropertyName – свойства со стандартными именами. Параметры группы LineSpec представлены тремя разновидностями: тип линии, цвет линии и тип маркеров. В функциях построения графиков они задаются в апострофах без разделительных символов и в произвольном порядке. Параметры этой группы были рассмотрены в табл. 4.3.

Параметры группы PropertyName представлены четырьмя разновидностями со следующими стандартными именами (задаются в апострофах):

LineWidth – толщина линии в пунктах (1 пункт = 1/75 дюйма ≈ 0,34 мм), задаваемая числом (по умолчанию равна 0,5);

MarkerEdgeColor – цвет маркера, задаваемый так же, как и цвет линии (см. табл. 4.3). По умолчанию цвет маркера совпадает с цветом линии;

MarkerFaceColor – цвет заливки маркера, задаваемый так же, как и цвет линии (см. табл. 4.3). По умолчанию маркер не закрашивается (прозрачный);

MarkerSize – размер маркера в пунктах, задаваемый числом (по умолчанию равен 7).

Параметры для маркера сработают, если соответствующий параметр LineSpec установил тип маркера. Если функция рисования используется с параметрами, задаваемыми стандартными именами, то она может отображать только одну кривую. Для прорисовки нескольких кривых в одних осях необходимо включить режим наложения. Например,

>> x=linspace(-pi,pi,50);

>> y1=100*sin(3*x);

>> y2=100*sin(x)+50*cos(5*x);

>> hold on

>> plot(x,y1,'rs--','LineWidth',2,'MarkerSize',5)

>> plot(x,y2,'bo--','LineWidth',1.5,'MarkerFaceColor','y')

>> title('Графики функций в режиме наложения')

>> grid, legend('y1=100sin(3x)','y2=100sin(x)+50cos(5x)')

>> hold off

Результат работы программы приведен на рис. 4.6.

Рис. 4.6. Графики двух функций, построенные в режиме наложения

 

 

Вопросы для самоконтроля

1. Как создается m-файл сценария?

2. Для чего используется функция disp и каковы правила?

3. Каковы общие правила построения графиков функции одной переменной?

4. Какие формы обращения к функции plot можно использовать?

5. Как задать свойства двумерного графика?

6. Какими средствами можно обеспечить вывод текстовой информации в графическое окно Matlab?

7. Какие специальные графики можно строить в Matlab?

8. Как обеспечить построение нескольких графиков в одном окне на отдельных осях?

9. Каковы общие правила построения поверхностей?

10. Какие функции для построения поверхностей есть в Matlab?

11. Как можно управлять свойствами трехмерных графиков?

12. Как раскрасить поверхность?

 


Дата добавления: 2021-02-10; просмотров: 73; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!