Главная Случайная страница


Полезное:

Как сделать разговор полезным и приятным Как сделать объемную звезду своими руками Как сделать то, что делать не хочется? Как сделать погремушку Как сделать так чтобы женщины сами знакомились с вами Как сделать идею коммерческой Как сделать хорошую растяжку ног? Как сделать наш разум здоровым? Как сделать, чтобы люди обманывали меньше Вопрос 4. Как сделать так, чтобы вас уважали и ценили? Как сделать лучше себе и другим людям Как сделать свидание интересным?


Категории:

АрхитектураАстрономияБиологияГеографияГеологияИнформатикаИскусствоИсторияКулинарияКультураМаркетингМатематикаМедицинаМенеджментОхрана трудаПравоПроизводствоПсихологияРелигияСоциологияСпортТехникаФизикаФилософияХимияЭкологияЭкономикаЭлектроника






Параграф 4. Круговые диаграммы и элементы 3D графики





Построение круговых диаграмм с элементами 3D графики требует несколько больших затрат по сравнению с рассмотренным выше материалом. Прежде всего, необходимо определить дополнительные переменные для величин: оси эллипса (vfDiamX, vfDiamY), центр круговой диаграммы (vfXcirc, vfYcirc). Кроме того, если мы хотим, что бы в легенде (пояснению к графику) цвета надписей соответствовали цветам секторов диаграммы, то потребуется задать массив цветов однозначно соответствующий массиву цветов кистей. Зададим в классе:

private float vfDiamX = 100;

private float vfDiamY = 100;

private float vfXcirc = 100;

private float vfYcirc = 100;

private Color[] color ={

Color.LightGreen,Color.Chartreuse,Color.LimeGreen,Color.Green,Color.DarkGreen,

Color.DarkOliveGreen,Color.LightPink,Color.LightSeaGreen,Color.LightCoral,Color.DarkCyan,

Color.Crimson, Color.CornflowerBlue,Color.Chocolate,Color.CadetBlue,Color.BlueViolet,

Color.Maroon,Color.Blue,Color.Brown,Color.DarkBlue, Color.Red,

Color.Coral,Color.DarkRed, Color.DarkMagenta, Color.DarkOrange,Color.DarkOrchid};

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

Рисовать диаграмму будем в несколько этапов:

  • Первый этап: Против часовой стрелки рисуем последний сектор и сектора, выходящие за границу 180 градусов, но не заходящие за границу 270 градусов. Рисовать будем кистью с прозрачностью, например 25%, и каждый из них со сдвигом на 1 пиксель вниз. Иначе, если толщина диаграммы задана 20 пикселей, то сектор потребуется нарисовать 20 раз, каждый раз сдвигая на 1 пиксель вниз (Рис.12.1.).

Рис.12.1. Первый этап создания круговой диаграммы

  • Второй этап: Накладываем на данную диаграмму сектора от 0 градусов до сектора, заходящего за 270 градусов, используя SolidBrush и не выполняя сдвиг - рисуем каждый сектор один раз из точки рисования всей диаграммы (Рис.12.2.).

Рис.12.2. Второй этап создания круговой диаграммы

  • Третий этап: по часовой стрелки рисуем сектора, начиная со второго, используя HatchBrush. Рисование выполняем до сектора заходящего за границу -90 градусов, со сдвигом на толщину диаграммы (Рис.12.3.).

Рис.12.3. Третий этап создания круговой диаграммы

  • Четвертый этап: По часовой стрелке накладываем без сдвига, начиная со второго сектора до сектора, заходящего за границу -90 градусов, используя SolidBrush (Рис.12.4.).

Рис.12.4. Четвертый этап создания круговой диаграммы

  • Отдельно рисуем первый сектор, сначала используя HatchBrush со сдвигом на толщину диаграммы, затем накладываем сектор SolidBrush без сдвига. Координаты сектора определяем с учетом параметров сдвига секторов (Рис.12.5.).

Рис.12.5. Пятый этап создания круговой диаграммы

Алгоритм рисования можно упростить, например, один раз и последним этапом наложить сектора эллипса, нарисованный кистью SolidBrush, но, в этом случае пострадает наглядность.

Эти этапы рисования выполняет следующая функция:

#region vDravCircle3D

//Параметры - Отступ от краев по X слева deltaaxisL, от краев по Y справа deltaaxisR,

//deltaaxisH - отступа сверху и снизу, толщина диаграммы viH, сдвиг сектора viDx, viDy

public void vDravCircle3D(int deltaaxisL, int deltaaxisR,

int deltaaxisH, int viH, int viDx, int viDy)

{

//Запоминаем отступы

viDeltaaxisL = deltaaxisL;

viDeltaaxisR = deltaaxisR;

viDeltaaxisH = deltaaxisH;

float a = viX - (deltaaxisL + deltaaxisR);

//Нужен ли выброс сектора

int viMov = 1;

if (viDx == 0 && viDy == 0)

{

viMov = 0;

}

//Запоминаем диаметр

vfDiamX = a;

vfDiamY = viY - 2 * viDeltaaxisH;

//Запоминаем центр элипса

vfXcirc = deltaaxisL + a / 2;

vfYcirc = viY / 2;

graph.SmoothingMode = SmoothingMode.AntiAlias;

//Определяем сумму всех значений в массиве

float fSum = 0;

string s = string.Empty;

for (int i = 0; i < viMaxRg; i++)

{

s = rgsValues[i, 0];

fSum += float.Parse(s);

}

float f = 0;

float fBSum = 0;

float fDeltaGrad = (fSum / (float)360);

SolidBrush objBrush = new SolidBrush(Color.Aqua);

Random rand = new Random(DateTime.Now.Millisecond);

float[] frgZn = new float[viMaxRg];

float[] frgSumGr = new float[viMaxRg];

for (int i = 0; i < viMaxRg; i++)

{

s = rgsValues[i, 0];

frgZn[i] = float.Parse(s);

if (i == 0) frgSumGr[i] = 0;

else frgSumGr[i] = frgZn[i] + frgSumGr[i - 1];

}

for (int i = viMaxRg - 1; i >= 0; i--)

{

if (i!= viMaxRg - 1 && fBSum < 90) break;

//f в градусах fBSum в градусах

f = frgZn[i] / fDeltaGrad;

//fBSum = frgSumGr[i] / fDeltaGrad;

if (i == viMaxRg - 1)

{

fBSum = 360 - f;

}

else

{

fBSum -= f;

}

//Для цвета

int j = i % br.Length;

float k = f;

if (f < 1) k = 1;

//objBrush.Color = Color.FromArgb(rand.Next(255), rand.Next(255), rand.Next(255));

if (i!= 0)

{

if ((fBSum > 90 && fBSum < 180) || i == viMaxRg - 1)

{

for (int d = 0; d < viH; d++)

{

//Этап 1

graph.FillPie(new HatchBrush(HatchStyle.Percent25, color[j]/*objBrush.Color*/),

vfXcirc - a / 2, vfYcirc - vfDiamY / 2 + d,

vfDiamX, vfDiamY, fBSum, k);

}

}

objBrush.Color = color[j];

//Этап 2

graph.FillPie(objBrush, vfXcirc - a / 2, vfYcirc - vfDiamY / 2,

vfDiamX, vfDiamY, fBSum, k);

}

}

fBSum = 0;

for (int i = viMov; i < viMaxRg; i++)

{

//f в градусах fBSum в градусах

f = frgZn[i] / fDeltaGrad;

if (i == 1)

{

fBSum = frgZn[0] / fDeltaGrad;

}

//Для цвета

int j = i % br.Length;

float k = f;

if (f < 1) k = 1;

 

if (fBSum < 90)

{

for (int d = 0; d < viH; d++)

{

//Этап 3

graph.FillPie(new HatchBrush(HatchStyle.Percent25, color[j]),

vfXcirc - a / 2, vfYcirc - vfDiamY / 2 + d,

vfDiamX, vfDiamY, fBSum, k);

}

objBrush.Color = color[j];

//Этап 4

graph.FillPie(objBrush, vfXcirc - a / 2, vfYcirc - vfDiamY / 2,

vfDiamX, vfDiamY, fBSum, k);

}

else

{

break;

}

fBSum += f;

}

//Рисуем сдвинутым первый сектор

//Этап 5

if (viMov == 1)

{

f = frgZn[0] / fDeltaGrad;

fBSum = 0;

float k1 = f;

if (f < 1) k1 = 1;

for (int d = 0; d < viH; d++)

{

graph.FillPie(new HatchBrush(HatchStyle.Percent25, color[0]),

vfXcirc - a / 2 + viDx, vfYcirc - vfDiamY / 2 + d - viDy,

vfDiamX, vfDiamY, fBSum, k1);

}

objBrush.Color = color[0];

graph.FillPie(objBrush, vfXcirc - a / 2 + viDx, vfYcirc - vfDiamY / 2 - viDy,

vfDiamX, vfDiamY, fBSum, k1);

}

}

#endregion

Добавляем функции надписи и легенду и, в принципе, построение диаграммы закончено. Единственное, что потребуется от нас при рисовании надписей на диаграмме - это немного вспомнить начальную школу при расчете координат нанесения значений:

#region vDravTextCircle

public void vDravTextCircle1(bool vfGde)

{

float fSum = 0;

string s = string.Empty;

for (int i = 0; i < viMaxRg; i++)

{

s = rgsValues[i, 0];

fSum += float.Parse(s);

}

float f = 0;

float fBSum = 0;

float f1Radian = (float)Math.PI / 180;

float fDeltaGrad = fSum / 360;

for (int i = 0; i < viMaxRg; i++)

{

s = rgsValues[i, 0];

f = float.Parse(s);

//f в градусах

f = f / fDeltaGrad;

int j = i % br.Length;

//Угол в радианах

float fRad = (f + fBSum) * f1Radian;

float fty = 0;

float ftx = 0;

float fSin = (float)Math.Sin((360 - (f / 2 + fBSum)) * f1Radian);

float fCos = (float)Math.Cos((360 - (f / 2 + fBSum)) * f1Radian);

float c = (float)Math.Sqrt((vfDiamX / 2 * vfDiamX / 2 * vfDiamY / 2 * vfDiamY / 2) /

(vfDiamY / 2 * vfDiamY / 2 * fCos * fCos + vfDiamX / 2 * vfDiamX / 2 * fSin * fSin));

c -= 3 * objFont.Size;

if (c < 0) c = 0;

ftx = c * fCos;

fty = c * fSin;

ftx = vfXcirc + ftx;

fty = vfYcirc - fty;

if (vfGde)

{

graph.DrawString(Convert.ToString(i + 1), objFont, objBrush, ftx, fty);

}

else

{

graph.DrawString(rgsValues[i, 0], objFont, objBrush, ftx, fty);

}

fBSum += f;

}

}

#endregion

 

#region Текст легенды

public void vDravTextKeyCircle(bool vfGde)

{

float fSum = 0;

float f = 0;

string s = string.Empty;

for (int i = 0; i < viMaxRg; i++)

{

s = rgsValues[i, 0];

fSum += float.Parse(s);

}

//Сдвиг от круговой диаграммы

float vfSdvig = vfXcirc + vfDiamX / 2;

vfSdvig += (viX - vfSdvig) / 5;

//Высота места для легенды

//На одну строку по высоте отводится - +1 на заголовок

float vfHg = viY / (viMaxRg + 2);

vSetFont("Arial", 12, true);

if (viMaxRg > 100)

{

graph.DrawString("Легенда не может быть размещена",

objFont, Brushes.DarkBlue, vfSdvig + (viX - vfSdvig) / 10, objFont.Size);

}

else

{

//Шрифт в 2 раза меньше места на строку надписи

if (viMaxRg > 15)

{

vSetFont("Arial", (vfHg / 2), true);

}

else

{

if (viMaxRg > 10)

{

vSetFont("Arial", (vfHg / 3), true);

}

else

{

vSetFont("Arial", (vfHg / 6), true);

}

}

if (vfGde)

{

graph.DrawString("Пояснения к графику",

objFont, Brushes.DarkBlue, vfSdvig /*+ (viX - vfSdvig) / 10*/, objFont.Size);

}

else

{

graph.DrawString("Пояснения к графику",

objFont, objBrush, vfSdvig/* + (viX - vfSdvig) / 10*/, objFont.Size);

}

if (viMaxRg > 15)

{

vSetFont("Arial", (vfHg / 2) + 1, true);

}

else

{

if (viMaxRg > 10)

{

vSetFont("Arial", (vfHg / 4) + 1, true);

}

else

{

vSetFont("Arial", (vfHg / 7) + 1, true);

}

}

for (int i = 0; i < rgsValues.Length / 2; i++)

{

Brush brTxt = null;

int j = i % br.Length;

if (vfGde) brTxt = br[j];

else brTxt = objBrush;

graph.DrawString(Convert.ToString(i + 1), objFont, brTxt, vfSdvig, vfHg * (i + 2));

f = float.Parse(rgsValues[i, 0]);

f = (f * 100) / fSum;

graph.DrawString(rgsValues[i, 0], objFont,

brTxt, vfSdvig + 1 * (viX - vfSdvig) / 5, vfHg * (i + 2));

graph.DrawString(f.ToString("0.0") + "%", objFont,

brTxt, vfSdvig + 2 * (viX - vfSdvig) / 5, vfHg * (i + 2));

graph.DrawString(rgsValues[i, 1], objFont,

brTxt, vfSdvig + 3 * (viX - vfSdvig) / 5, vfHg * (i + 2));

}

}

}

#endregion

 

 

#region Смена шрифта по секторам

private void vSetFont(string name, float size, bool bold)

{

if (objFont!= null) objFont = null;

if (bold)

{

objFont = new Font(name, size, FontStyle.Bold);

}

else

{

objFont = new Font(name, size);

}

}

#endregion

 

Оформим вызовы функций:

private void button3_Click(object sender, EventArgs e)

{

viNumButton = 3;

vCreateCircleDiagramm();

}

private void vCreateCircleDiagramm()

{

//Создаем массив значений для вывода на графике

vCreateRg();

//Создаем класс и передаем ему размер холсты

PaintCl clPaint = new PaintCl(pictureBox1.Width, pictureBox1.Height);

//Фон холста

clPaint.vSetBackground(Color.White);

//Передаем значения массива в класс

clPaint.RgValue = rgsValues;

//Рисуем график. Параметры: отступ осей x слева, x справа,

//y от краев холста, толщина диаграммы,вынос сектора

clPaint.vDravCircle3D(20, 250, 50, 20, 20, 40);

//Круговые надписи true цифры 1-20, false - значения

clPaint.vDravTextCircle1(true);

//false - Разноцветные надписи в легенде true - Цветом шрифта

clPaint.vDravTextKeyCircle(true);

//Принимаем нарисованное в pictureBox

pictureBox1.Image = clPaint.Bmp;

}

Отметим, что при задании толщины диаграммы, равной нулю, получим обычную эллиптическую диаграмму, а при равенстве осей Х и Y - круговую.

Результат выполнения решения показан на Рис.12.6:

Рис.12.6. Круговая диаграмма

В заключении, еще раз повторим, что все параметры целесообразно иметь настраиваемыми, что позволяет быстро подобрать приемлемый вид графического отображения для демонстрации. Целесообразно также выполнить автономную настройку диаграмм по тестовым значениям (как это сделано в программе LitFregMeter - см. Параграф 2.). Тогда мы сможем быстро подбирать параметры, например так:

//Смена фона диаграммы

private void ColorBackGround_Click(object sender, EventArgs e)

{

if (colorDialog1.ShowDialog() == DialogResult.OK)

{

//Переменная objColorBackGroung задана глобально, сохраняется в реестре

//при закрытии приложения и передается в класс при рисовании диаграммы

//clPaint.vSetBackground(objColorBackGroung);

objColorBackGroung = colorDialog1.Color;

vGhangeDiagramm();

}

}

//Перерисовка конкретной диаграммы при настройке

private void vGhangeDiagramm()

{

switch (viNumButton)

{

case 1:

vCreateLinGr();

break;

case 2:

vCreateRectangleDiagramm();

break;

case 3:

vCreateCircleDiagramm();

break;

}

}

 

Date: 2015-09-02; view: 436; Нарушение авторских прав; Помощь в написании работы --> СЮДА...



mydocx.ru - 2015-2024 year. (0.005 sec.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав - Пожаловаться на публикацию