Мне нужна противоположность методу GraphicsPath.Widen ()
в .Net:
public GraphicsPath Widen()
Метод Widen ()
не принимает отрицательный параметр, поэтому мне нужен эквивалент метода Inset
:
public GraphicsPath Inset()
Вы можете сделать это в приложении Inkscape с открытым исходным кодом (www.Inkscape.org), перейдя в меню и выбрав «Path / Inset» (Размер Inset сохраняется в диалоговом окне Inkscape Properties). Поскольку Inkscape является открытым исходным кодом, это должно быть возможно сделать в C # .Net, но я могу ' Я всю жизнь следую исходному тексту Inkscape C ++ (и мне нужна только одна эта функция, поэтому я не могу оправдать изучение C ++ для ее выполнения).
В принципе, мне нужен метод расширения GraphicsPath с такой подписью:
public static GraphicsPath Inset(this GraphicsPath original, float amount)
{
//implementation
}
Как указано в подписи, он будет принимать объект GraphicsPath
и .Inset ()
путь на переданную величину ... точно так же, как Inkscape сегодня. Если это хоть как-то упрощает, то все рассматриваемые GraphicsPaths создаются с помощью метода .PolyBezier
(и ничего другого), поэтому нет необходимости учитывать прямоугольники, эллипсы или любые другие формы, если вы не хотите сделайте это для полноты.
К сожалению, у меня нет опыта работы с кодом C ++, поэтому мне практически невозможно следовать логике C ++, содержащейся в Inkscape.
.
t оправдывает изучение C ++, чтобы завершить это).
В принципе, мне нужен метод расширения GraphicsPath с такой сигнатурой:
public static GraphicsPath Inset(this GraphicsPath original, float amount)
{
//implementation
}
Как указано в подписи, он потребует объект GraphicsPath
и .Inset ()
путь на пройденное количество ... точно так же, как сегодня Inkscape. Если это хоть как-то упрощает, все рассматриваемые GraphicsPaths создаются с помощью метода .PolyBezier
(и ничего другого), поэтому нет необходимости учитывать прямоугольники, эллипсы или любые другие формы, если вы не хотите сделайте это для полноты.
К сожалению, у меня нет опыта работы с кодом C ++, поэтому мне практически невозможно следовать логике C ++, содержащейся в Inkscape.
.
t оправдывает изучение C ++, чтобы завершить это).
В принципе, мне нужен метод расширения GraphicsPath с такой сигнатурой:
public static GraphicsPath Inset(this GraphicsPath original, float amount)
{
//implementation
}
Как указано в подписи, он потребует объект GraphicsPath
и .Inset ()
путь на пройденное количество ... точно так же, как сегодня Inkscape. Если это хоть как-то упрощает, все рассматриваемые GraphicsPaths создаются с помощью метода .PolyBezier
(и ничего другого), поэтому нет необходимости учитывать прямоугольники, эллипсы или любые другие формы, если вы не хотите сделайте это для полноты.
К сожалению, у меня нет опыта работы с кодом C ++, поэтому мне практически невозможно следовать логике C ++, содержащейся в Inkscape.
.
он будет принимать объект GraphicsPath
и .Inset ()
путь на переданную величину ... точно так же, как Inkscape сегодня. Если это хоть как-то упрощает, все рассматриваемые GraphicsPaths создаются с помощью метода .PolyBezier
(и ничего другого), поэтому нет необходимости учитывать прямоугольники, эллипсы или любые другие формы, если вы не хотите сделайте это для полноты.
К сожалению, у меня нет опыта работы с кодом C ++, поэтому мне практически невозможно следовать логике C ++, содержащейся в Inkscape.
.
он будет принимать объект GraphicsPath
и .Inset ()
путь на переданную величину ... точно так же, как Inkscape сегодня. Если это хоть как-то упрощает, все рассматриваемые GraphicsPaths создаются с помощью метода .PolyBezier
(и ничего другого), поэтому нет необходимости учитывать прямоугольники, эллипсы или любые другие формы, если вы не хотите сделайте это для полноты.
К сожалению, у меня нет опыта работы с кодом C ++, поэтому мне практически невозможно следовать логике C ++, содержащейся в Inkscape.
.
[РЕДАКТИРОВАТЬ:] Как и просили, вот код Inkscape "MakeOffset". Второй параметр (двойное уменьшение) будет отрицательным для вставки, и абсолютное значение этого параметра - это количество, которое нужно внести в форму.
Я знаю, что здесь есть много зависимостей. Если вам нужно увидеть больше исходных файлов Inkscape, они находятся здесь: http://sourceforge.net/projects/inkscape/files/inkscape/0.48/
int
Shape::MakeOffset (Shape * a, double dec, JoinType join, double miter, bool do_profile, double cx, double cy, double radius, Geom::Matrix *i2doc)
{
Reset (0, 0);
MakeBackData(a->_has_back_data);
bool done_something = false;
if (dec == 0)
{
_pts = a->_pts;
if (numberOfPoints() > maxPt)
{
maxPt = numberOfPoints();
if (_has_points_data) {
pData.resize(maxPt);
_point_data_initialised = false;
_bbox_up_to_date = false;
}
}
_aretes = a->_aretes;
if (numberOfEdges() > maxAr)
{
maxAr = numberOfEdges();
if (_has_edges_data)
eData.resize(maxAr);
if (_has_sweep_src_data)
swsData.resize(maxAr);
if (_has_sweep_dest_data)
swdData.resize(maxAr);
if (_has_raster_data)
swrData.resize(maxAr);
if (_has_back_data)
ebData.resize(maxAr);
}
return 0;
}
if (a->numberOfPoints() <= 1 || a->numberOfEdges() <= 1 || a->type != shape_polygon)
return shape_input_err;
a->SortEdges ();
a->MakeSweepDestData (true);
a->MakeSweepSrcData (true);
for (int i = 0; i < a->numberOfEdges(); i++)
{
// int stP=a->swsData[i].stPt/*,enP=a->swsData[i].enPt*/;
int stB = -1, enB = -1;
if (dec > 0)
{
stB = a->CycleNextAt (a->getEdge(i).st, i);
enB = a->CyclePrevAt (a->getEdge(i).en, i);
}
else
{
stB = a->CyclePrevAt (a->getEdge(i).st, i);
enB = a->CycleNextAt (a->getEdge(i).en, i);
}
Geom::Point stD, seD, enD;
double stL, seL, enL;
stD = a->getEdge(stB).dx;
seD = a->getEdge(i).dx;
enD = a->getEdge(enB).dx;
stL = sqrt (dot(stD,stD));
seL = sqrt (dot(seD,seD));
enL = sqrt (dot(enD,enD));
MiscNormalize (stD);
MiscNormalize (enD);
MiscNormalize (seD);
Geom::Point ptP;
int stNo, enNo;
ptP = a->getPoint(a->getEdge(i).st).x;
double this_dec;
if (do_profile && i2doc) {
double alpha = 1;
double x = (Geom::L2(ptP * (*i2doc) - Geom::Point(cx,cy))/radius);
if (x > 1) {
this_dec = 0;
} else if (x <= 0) {
this_dec = dec;
} else {
this_dec = dec * (0.5 * cos (M_PI * (pow(x, alpha))) + 0.5);
}
} else {
this_dec = dec;
}
if (this_dec != 0)
done_something = true;
int usePathID=-1;
int usePieceID=0;
double useT=0.0;
if ( a->_has_back_data ) {
if ( a->ebData[i].pathID >= 0 && a->ebData[stB].pathID == a->ebData[i].pathID && a->ebData[stB].pieceID == a->ebData[i].pieceID
&& a->ebData[stB].tEn == a->ebData[i].tSt ) {
usePathID=a->ebData[i].pathID;
usePieceID=a->ebData[i].pieceID;
useT=a->ebData[i].tSt;
} else {
usePathID=a->ebData[i].pathID;
usePieceID=0;
useT=0;
}
}
if (dec > 0)
{
Path::DoRightJoin (this, this_dec, join, ptP, stD, seD, miter, stL, seL,
stNo, enNo,usePathID,usePieceID,useT);
a->swsData[i].stPt = enNo;
a->swsData[stB].enPt = stNo;
}
else
{
Path::DoLeftJoin (this, -this_dec, join, ptP, stD, seD, miter, stL, seL,
stNo, enNo,usePathID,usePieceID,useT);
a->swsData[i].stPt = enNo;
a->swsData[stB].enPt = stNo;
}
}
if (dec < 0)
{
for (int i = 0; i < numberOfEdges(); i++)
Inverse (i);
}
if ( _has_back_data ) {
for (int i = 0; i < a->numberOfEdges(); i++)
{
int nEd=AddEdge (a->swsData[i].stPt, a->swsData[i].enPt);
ebData[nEd]=a->ebData[i];
}
} else {
for (int i = 0; i < a->numberOfEdges(); i++)
{
AddEdge (a->swsData[i].stPt, a->swsData[i].enPt);
}
}
a->MakeSweepSrcData (false);
a->MakeSweepDestData (false);
return (done_something? 0 : shape_nothing_to_do);
}
.
[РЕДАКТИРОВАТЬ]
@Simon Mourier - Потрясающая работа. Код был даже чистым и читабельным! Отличная работа, сэр. Однако у меня есть к вам несколько вопросов.
Во-первых, что означает положительное число для суммы? Я думал, что для метода смещения положительное значение будет «исходным», а отрицательное - «вставкой», но в вашем примере, похоже, все наоборот.
Во-вторых, я провел базовое тестирование (просто расширив ваш образец), и обнаружил некоторые странности.
Вот что происходит с "l" в Cool, когда смещение увеличивается (для такой простой буквы она наверняка вызывает проблемы!).
... и код для воспроизведения этого one:
private void Form1_Paint(object sender, PaintEventArgs e)
{
GraphicsPath path = new GraphicsPath();
path.AddString("cool", new FontFamily("Arial"), 0, 200, new PointF(), StringFormat.GenericDefault);
GraphicsPath offset1 = path.Offset(32);
e.Graphics.DrawPath(new Pen(Color.Black, 1), path);
e.Graphics.DrawPath(new Pen(Color.Red, 1), offset1);
}
Наконец, кое-что немного другое. Вот символ "S" из Wingdings (выглядит как капля слезы):
Вот код:
private void Form1_Paint(object sender, PaintEventArgs e)
{
GraphicsPath path = new GraphicsPath();
path.AddString("S", new FontFamily("Wingdings"), 0, 200, new PointF(), StringFormat.GenericDefault);
GraphicsPath offset1 = path.Offset(20);
e.Graphics.DrawPath(new Pen(Color.Black, 1), path);
e.Graphics.DrawPath(new Pen(Color.Red, 1), offset1);
}
Человек, это так близко, что мне хочется плакать. Однако это по-прежнему не работает.
Я думаю, что можно исправить, это увидеть, когда векторы вставки пересекаются, и прекратить вставку после этой точки. Если величина Inset настолько велика (или путь настолько мал), что ничего не осталось, путь должен исчезнуть (стать нулевым), вместо того, чтобы развернуться и снова расшириться.
Опять же, я не пытаюсь понять, что вы каким-либо образом сделали, но мне было интересно, знаете ли вы, что может происходить с этими примерами.
(PS - я добавил ключевое слово this, чтобы сделать его методом расширения, поэтому вам может потребоваться вызвать код, использующий нотацию метода (параметров) для запуска этих образцов)
.
@RAN и прекратите вставлять дальше этой точки. Если величина Inset настолько велика (или путь настолько мал), что ничего не осталось, путь должен исчезнуть (стать нулевым), вместо того, чтобы развернуться и снова расшириться.
Опять же, я не пытаюсь понять, что вы каким-либо образом сделали, но мне было интересно, знаете ли вы, что может происходить с этими примерами.
(PS - я добавил ключевое слово this, чтобы сделать его методом расширения, поэтому вам может потребоваться вызвать код, использующий нотацию метода (параметров) для запуска этих образцов)
.
@RAN и прекратите вставлять дальше этой точки. Если величина Inset настолько велика (или путь настолько мал), что ничего не осталось, путь должен исчезнуть (стать нулевым), вместо того, чтобы развернуться и снова расшириться.
Опять же, я не пытаюсь понять, что вы каким-либо образом сделали, но мне было интересно, знаете ли вы, что может происходить с этими примерами.
(PS - я добавил ключевое слово this, чтобы сделать его методом расширения, поэтому вам может потребоваться вызвать код, использующий нотацию метода (параметров) для запуска этих образцов)
.
@RAN Ран пришел к аналогичному выводу, повторно используя собственные методы GraphicsPath. Блин, это тяжело. Оба они так близки.
Вот снимки экрана обоих примеров с использованием символа «S» из Wingdings:
@Simon слева, @Ran справа.
Вот та же слеза, буква "S" после выполнения "Inset" в Inkscape. Вставка чистая:
Кстати, вот код для теста @Ran:
private void Form1_Paint(object sender, PaintEventArgs e)
{
GraphicsPath path = new GraphicsPath();
path.AddString("S", new FontFamily("Wingdings"), 0, 200, new PointF(), StringFormat.GenericDefault);
e.Graphics.DrawPath(new Pen(Color.Black, 1), path);
GraphicsPath offset1 = path.Shrink(20);
e.Graphics.DrawPath(new Pen(Color.Red, 1), offset1);
}