Как правильно обращаться с перьями и рисовать в С# ?
От: Аноним  
Дата: 13.04.09 15:10
Оценка:
Давно не мучился с графикой... Стал простой вопрос о том, как люди решают проблему с перьями и системой рисования в Windows Forms и C#.
Как нужно реализовать алгоритм рисования графических примитивов на холсте так, чтобы качество(с точки зрения геометрии и перекрытия отдельных элементов) не страдало от толщины пера?

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

// получаем ссылку на объект графики
Graphics g = e.Graphics;
// создаем перо для рамки графика
Pen gpen = new Pen(Color.Red, 5);
// уменьшаем размер прямоугольной клиентской области на толщину пера рамки
recf.Inflate(-gpen.Width/2, -gpen.Width/2);
// рисуем рамку графика
g.DrawRectangle(gpen, recf.X, recf.Y, recf.Width, recf.Height);

gpen.Width = 1;
gpen.Color = Color.Black;
recf.Inflate(-gpen.Width , -gpen.Width );
g.DrawRectangle(gpen, recf.X, recf.Y, recf.Width, recf.Height);


Как видно из кода выше, такой вариант не выполняет требования по- допустимости смены толщин перьев одного и другого прямоугольника...
Простое тестирование его при различных значениях gpen.Width показывает, что эти прямоугольники будут перекрываться при различных соотношениях толщин их перьев...

Надеюсь, что суть вопроса мне все-таки удалось изложить не смотря на характер описания...
Re: Как правильно обращаться с перьями и рисовать в С# ?
От: MxKazan Португалия  
Дата: 14.04.09 09:54
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Давно не мучился с графикой... Стал простой вопрос о том, как люди решают проблему с перьями и системой рисования в Windows Forms и C#.

А>Как нужно реализовать алгоритм рисования графических примитивов на холсте так, чтобы качество(с точки зрения геометрии и перекрытия отдельных элементов) не страдало от толщины пера?
Нууу.. может отказаться от перьев вообще и работать только с заливкой?
Нарисовал "внешний" прямоугольник, уменьшил recf на толщину предполагаемого пера
Нарисовал "внутренний" прямоугольник, уменьшил recf на толщину предполагаемого пера
Нарисовал третий прямоугольник вложенным во внутренний.

Первый и второй прямоугольники имитируют рисование с пером, а последний — заливку.
Re: Как правильно обращаться с перьями и рисовать в С# ?
От: notacat  
Дата: 14.04.09 10:28
Оценка:
А почему Inflate делаете в одном случае на половину толщины пера, в другом — на толщину пера?
Попробуйте оба раза сделать так:

recf.Inflate(-gpen.Width, -gpen.Width);


потом, вы из какой гипотезы исходите:
— границы прямоугольника рисуются снаружи указанного прямоугольника,
— внутри,
— половина границы снаружи, половина внутри?

Я склоняюсь ко второму варианту, хотя не проверяла.
Лучше всего нарисовать первый прямоугольник, потом уменьшить размер прямоугольника на толщину пера, потом уже внутри этого прямоугольника рисовать второй прямоугольник:

// получаем ссылку на объект графики
Graphics g = e.Graphics;
// создаем перо для рамки графика
Pen gpen = new Pen(Color.Red, 5);
// рисуем рамку графика
g.DrawRectangle(gpen, recf.X, recf.Y, recf.Width, recf.Height);
// уменьшаем размер прямоугольной клиентской области на толщину пера рамки
recf.Inflate(-gpen.Width, -gpen.Width);

gpen.Width = 1;
gpen.Color = Color.Black;
g.DrawRectangle(gpen, recf.X, recf.Y, recf.Width, recf.Height); 
recf.Inflate(-gpen.Width , -gpen.Width );
// рисовать дальше внутри второго прямоугольника
Re: Как правильно обращаться с перьями и рисовать в С# ?
От: HotDog Швейцария www.denebspace.com
Дата: 14.04.09 10:43
Оценка: +1
Смотри в сторону Pen.Alignment
У внутреннего прямоугольника ставишь PenAlignment.Inset у внешнего Outset.
... << RSDN@Home 1.2.0 alpha rev. 717>>
Re: Как правильно обращаться с перьями и рисовать в С# ?
От: Mr.Cat  
Дата: 14.04.09 10:50
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Допустим задача: нарисовать 2 прямоугольника так, чтобы один был вложен в другой и они не перекрывались при изменении толщин их перьев.

Т.е. толщина пера сравнима с размерами прямоугольника? Я бы предположил, что в этом случае лучше отказаться от перьев и все делать заливкой ака кистями.
Re[2]: Как правильно обращаться с перьями и рисовать в С# ?
От: Dmitry_Sharp2008  
Дата: 16.04.09 10:59
Оценка:
Здравствуйте, notacat, Вы писали:

N>А почему Inflate делаете в одном случае на половину толщины пера, в другом — на толщину пера?

N>Попробуйте оба раза сделать так:

N>
N>recf.Inflate(-gpen.Width, -gpen.Width);
N>


N>потом, вы из какой гипотезы исходите:

N>- границы прямоугольника рисуются снаружи указанного прямоугольника,
N>- внутри,
N>- половина границы снаружи, половина внутри?

N>Я склоняюсь ко второму варианту, хотя не проверяла.

N>Лучше всего нарисовать первый прямоугольник, потом уменьшить размер прямоугольника на толщину пера, потом уже внутри этого прямоугольника рисовать второй прямоугольник:

N>
N>// получаем ссылку на объект графики
N>Graphics g = e.Graphics;
N>// создаем перо для рамки графика
N>Pen gpen = new Pen(Color.Red, 5);
N>// рисуем рамку графика
N>g.DrawRectangle(gpen, recf.X, recf.Y, recf.Width, recf.Height);
N>// уменьшаем размер прямоугольной клиентской области на толщину пера рамки
N>recf.Inflate(-gpen.Width, -gpen.Width);

N>gpen.Width = 1;
N>gpen.Color = Color.Black;
N>g.DrawRectangle(gpen, recf.X, recf.Y, recf.Width, recf.Height); 
N>recf.Inflate(-gpen.Width , -gpen.Width );
N>// рисовать дальше внутри второго прямоугольника
N>


Вы правы насчет того, что упомянули о возможных "гипотезах", которые могут быть положенными в основу механизма отрисовки примитивов...
Я прямо так не сказал в своем посте, полагая, что это очевидно из его сути. Да, действительно меня интересовали варианты рисования,
которые учитывают различные возможности "выравнивания пера".
Известно, что стандарт в GDI+ это — примитив рисуется так, что 1/2 толщины пера рисуется снаружи, а другая внутри от заданного контура.
Однако проблема возникает именно при близких толщинах перьев к 0 и 1. Попробуйте приведенным Вами выше кодом нарисовать 2 вложенных друг друга прямоугольника толщинами 1, 0 и 2 пекселя так, чтобы они "вкладывались" друг в друга без зазора и не перекрывали себя. Пусть это будет контур клиентской области формы, для примера.
Если просто рисовать 1- прямоугольник делая инфлейт на всю толщину пера- тогда образуется зазор равный половине тощины пера... Поэтому инфлейт делается на 1/2 толщины пера.
Надеяться на корректность стандартного механизма заложенного в концепцию перьев в GDI+ — не приходится, даже сам автор его пишет, что он корректно не работает(на сайте Майкрософта об этом говорится..)
Графикой пользуюся все, а как обходят такие "подводные камни" что-то не особо пишут. Понимаю, что это для всех "очевидно", однако ответьте для "особо обделенных" этой очевидностью(вроде меня).
Спасибо всем за Ваши ответы. К сожалению они пока не дают ответы на мои вопросы.
Re[3]: Как правильно обращаться с перьями и рисовать в С# ?
От: notacat  
Дата: 16.04.09 12:30
Оценка:
D_S>Спасибо всем за Ваши ответы. К сожалению они пока не дают ответы на мои вопросы.
А вам кто-то вроде уже советовал попробовать без перьев. Т.е. если вы знаете, какая должна быть толщина границы, нарисуйте это с помощью двух вложенных прямоугольников. Должно лучше получиться.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.