. Net Противоположность GraphicsPath.Widen ()

Мне нужна противоположность методу 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, когда смещение увеличивается (для такой простой буквы она наверняка вызывает проблемы!).

Simon Test 2

... и код для воспроизведения этого 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 (выглядит как капля слезы):

Tear Drop

Вот код:

    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:

Tear drop comparison

@Simon слева, @Ran справа.

Вот та же слеза, буква "S" после выполнения "Inset" в Inkscape. Вставка чистая:

Tear 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);
    }

18
задан Flipster 27 February 2015 в 02:16
поделиться