Ejemplo n.º 1
0
void StyledTextboxView::configureObject(void)
{
  QRectF rect;
  QPolygonF pol;
  QPointF pnt;

  this->__configureObject();
  fold->setBrush(box->brush());
  fold->setPen(box->pen());

  rect=box->boundingRect();
  pol=box->polygon();

  if(rect.height() < fold->boundingRect().height())
    rect.setHeight(fold->boundingRect().height() + (2 * VERT_SPACING));

  this->resizePolygon(pol, rect.width() + fold->boundingRect().width(), rect.height());

  pnt=pol.at(2);
  pol.remove(2);
  pol.insert(2, QPointF(pnt.x(), roundf(pnt.y() - fold->boundingRect().height())));
  pol.insert(3, QPointF(roundf(pnt.x() - fold->boundingRect().width()), pnt.y()));
  box->setPolygon(pol);

  rect=box->boundingRect();
  fold->setPos(rect.width() - fold->boundingRect().width(),
               rect.height() - fold->boundingRect().height());

  this->configureObjectShadow();
  this->configureObjectSelection();
}
Ejemplo n.º 2
0
void VLCStatsView::addValue( float value )
{
    value /= 1000;

    QPolygonF shape = totalbitrateShape->polygon();
    if ( shape.count() > ( STATS_LENGTH + 2 ) ) /* keep only STATS_LENGTH samples */
    {
        shape.remove( 1 );
        for(int i=1; i<( STATS_LENGTH + 2 ); i++)
            ( (QPointF &) shape.at(i) ).setX( i - 1 ); /*move back values*/
    }

    int count = shape.count();
    if ( count == 0 )
    {
        shape << QPointF( 0, 0 ); /* begin and close shape */
        shape << QPointF( count, 0 );
    }

    shape.insert( shape.end() - 1, QPointF( count, value ) );
    ( (QPointF &) shape.last() ).setX( count );
    totalbitrateShape->setPolygon( shape );

    addHistoryValue( value );

    QRectF maxsizes = scene()->itemsBoundingRect();
    maxsizes.setRight( STATS_LENGTH );
    fitInView( maxsizes ); /* fix viewport */
    drawRulers( maxsizes );
}
Ejemplo n.º 3
0
void VLCStatsView::addHistoryValue( float value )
{
    /* We keep a full history by creating virtual blocks for inserts, growing
       by power of 2 when no more space is available. At this time, we also
       free space by agregating the oldest values 2 by 2.
       Each shown value finally being a mean of blocksize samples.
    */
    bool doinsert = false;
    int next_blocksize = blocksize;
    QPolygonF shape = historyShape->polygon();
    int count = shape.count();
    if ( count == 0 )
    {
        shape << QPointF( 0, 0 ); /* begin and close shape */
        shape << QPointF( count, 0 );
    }

    valuesaccumulator += ( value / blocksize );
    valuesaccumulatorcount++;

    if ( valuesaccumulatorcount == blocksize )
    {
        valuesaccumulator = 0;
        valuesaccumulatorcount = 0;
        doinsert = true;
    }

    if ( doinsert )
    {
        if ( count > ( STATS_LENGTH + 2 ) )
        {
            float y = 0;
            y += ((QPointF &) shape.at( historymergepointer + 1 )).y();
            y += ((QPointF &) shape.at( historymergepointer + 2 )).y();
            y /= 2;

            /* merge */
            shape.remove( historymergepointer + 2 );
            ( (QPointF &) shape.at( historymergepointer + 1 ) ).setY( y );
            for(int i=historymergepointer +1; i<( STATS_LENGTH + 2 ); i++)
                ( (QPointF &) shape.at(i) ).setX( i - 1 ); /*move back values*/
            historymergepointer++;
            if ( historymergepointer > ( STATS_LENGTH - 1 ) )
            {
                historymergepointer = 0;
                next_blocksize = ( blocksize << 1 );
            }
        }

        shape.insert( shape.end() - 1, QPointF( count, value ) );
        ( (QPointF &) shape.last() ).setX( count );
    }
    else
        ( (QPointF &) shape.last() ).setX( count - 1 );

    historyShape->setPolygon( shape );

    blocksize = next_blocksize;
}
Ejemplo n.º 4
0
void DialogFunction::onRemovePoint()
{
	QwtArraySeriesData<QPointF>* pSeries = static_cast<QwtArraySeriesData<QPointF>*>(_pCurve->data());
	if (pSeries)
	{
		QPolygonF samples = pSeries->samples();
		if (_indexSelectedPoint>=0 && _indexSelectedPoint<samples.size())
		{
			samples.remove(_indexSelectedPoint);
			_pCurve->setSamples(samples);
			widgetPlot->replot();
		}
	}
}
Ejemplo n.º 5
0
static PyObject *meth_QPolygonF_remove(PyObject *sipSelf, PyObject *sipArgs)
{
    PyObject *sipParseErr = NULL;

    {
        int a0;
        QPolygonF *sipCpp;

        if (sipParseArgs(&sipParseErr, sipArgs, "Bi", &sipSelf, sipType_QPolygonF, &sipCpp, &a0))
        {
            sipCpp->remove(a0);

            Py_INCREF(Py_None);
            return Py_None;
        }
    }

    {
        int a0;
        int a1;
        QPolygonF *sipCpp;

        if (sipParseArgs(&sipParseErr, sipArgs, "Bii", &sipSelf, sipType_QPolygonF, &sipCpp, &a0, &a1))
        {
            sipCpp->remove(a0,a1);

            Py_INCREF(Py_None);
            return Py_None;
        }
    }

    /* Raise an exception if the arguments couldn't be parsed. */
    sipNoMethod(sipParseErr, sipName_QPolygonF, sipName_remove, doc_QPolygonF_remove);

    return NULL;
}
Ejemplo n.º 6
0
void Arena::ReDraw()
{
    Coord c1 = GetMemberOne()->GetCoord();
    Coord c2 = GetMemberTwo()->GetCoord();

    double tAngle;
    ArScene->removeItem(tr1);
    ArScene->removeItem(tr2);
    delete tr1;
    delete tr2;
    QPolygonF pg;

    //нужно определить координаты точек равнобедренного треугольника, учитывая угол
    triangle tr;
    tAngle = c1.Angle*_180_DIV_PI;
    tr.x1 = c1.X-20*sin(tAngle);
    tr.y1 = c1.Y-20*cos(tAngle);
    tr.x2 = c1.X+70*cos(tAngle);
    tr.y2 = c1.Y-70*sin(tAngle);
    tr.x3 = c1.X+20*sin(tAngle);
    tr.y3 = c1.Y+20*cos(tAngle);

    pg<< QPointF(tr.x1/_MULTIPLIER+_BORDER,tr.y1/_MULTIPLIER+_BORDER)
      <<QPointF(tr.x2/_MULTIPLIER+_BORDER,tr.y2/_MULTIPLIER+_BORDER)
      <<QPointF(tr.x3/_MULTIPLIER+_BORDER,tr.y3/_MULTIPLIER+_BORDER);
    tr1 = ArScene->addPolygon(pg, QPen(Qt::black),QBrush(Qt::white));
    pg.remove(0,3);

    tAngle = c2.Angle*_180_DIV_PI;
    tr.x1 = c2.X-20*sin(tAngle);
    tr.y1 = c2.Y-20*cos(tAngle);
    tr.x2 = c2.X+70*cos(tAngle);
    tr.y2 = c2.Y-70*sin(tAngle);
    tr.x3 = c2.X+20*sin(tAngle);
    tr.y3 = c2.Y+20*cos(tAngle);

    pg<< QPointF(tr.x1/_MULTIPLIER+_BORDER,tr.y1/_MULTIPLIER+_BORDER)
      <<QPointF(tr.x2/_MULTIPLIER+_BORDER,tr.y2/_MULTIPLIER+_BORDER)
      <<QPointF(tr.x3/_MULTIPLIER+_BORDER,tr.y3/_MULTIPLIER+_BORDER);
    tr2 = ArScene->addPolygon(pg, QPen(Qt::black),QBrush(Qt::white));

}
Ejemplo n.º 7
0
QPolygonF polygonFromPath(potrace_path_t *path,
                          int bezierPrecision)
{
  QPolygonF poly;
  if(!path) return poly;

  int n = path->curve.n;
  int *tag = path->curve.tag;
  potrace_dpoint_t (*c)[3] = path->curve.c;
  for(int i = 0; i < n; ++i)
  {
    switch (tag[i])
    {
    case POTRACE_CORNER:
      poly << QPointF(c[i][1].x, c[i][1].y)
           << QPointF(c[i][2].x, c[i][2].y);
      break;
    case POTRACE_CURVETO:
    {
      QPointF pa, pb, pc, pd;
      pa = poly.isEmpty()? QPointF(c[n-1][2].x, c[n-1][2].y) :
                           poly.last();
      pb = QPointF(c[i][0].x, c[i][0].y);
      pc = QPointF(c[i][1].x, c[i][1].y);
      pd = QPointF(c[i][2].x, c[i][2].y);
      for(int i = 1; i <= bezierPrecision; ++i)
      {
        poly << bezier(pa, pb, pc, pd, static_cast<qreal>(i)/bezierPrecision);
      }
    }
      break;
    }
  }

  if(!poly.isEmpty() && poly.first() == poly.last())
  {
    poly.remove(poly.size()-1);
  }

  return poly;
}
Ejemplo n.º 8
0
void EditPolygonTool::deleteNodes()
{
    if (mSelectedHandles.isEmpty())
        return;

    PointIndexesByObject p = groupIndexesByObject(mSelectedHandles);
    QMapIterator<MapObject*, RangeSet<int> > i(p);

    QUndoStack *undoStack = mapDocument()->undoStack();

    QString delText = tr("Delete %n Node(s)", "", mSelectedHandles.size());
    undoStack->beginMacro(delText);

    while (i.hasNext()) {
        MapObject *object = i.next().key();
        const RangeSet<int> &indexRanges = i.value();

        QPolygonF oldPolygon = object->polygon();
        QPolygonF newPolygon = oldPolygon;

        // Remove points, back to front to keep the indexes valid
        RangeSet<int>::Range it = indexRanges.end();
        RangeSet<int>::Range begin = indexRanges.begin();
        // assert: end != begin, since there is at least one entry
        do {
            --it;
            newPolygon.remove(it.first(), it.length());
        } while (it != begin);

        if (newPolygon.size() < 2) {
            // We've removed the entire object
            undoStack->push(new RemoveMapObject(mapDocument(), object));
        } else {
            undoStack->push(new ChangePolygon(mapDocument(), object,
                                              newPolygon,
                                              oldPolygon));
        }
    }

    undoStack->endMacro();
}
Ejemplo n.º 9
0
void LineHandler::deleteLoop(QPolygonF &line, int startPos)
{
	for (int i = startPos; i < line.size() - 3; ++i) {
		bool isCut = false;
		for (int j = i + 2; j < line.size() - 1; ++j) {
			QPointF cut;
			if (QLineF(line[i], line[i + 1]).intersect(QLineF(line[j], line[j + 1]), &cut)
					== QLineF::BoundedIntersection)
			{
				if ((i != 0) || !((j == line.size() - 2)
						&& (QLineF(line.first(), line.last()).length() < (kvadratik * 2))))
				{
					QPainterPath path;
					QPainterPathStroker ps;
					ps.setWidth(kvadratik);
					for (int k = 0; k < line.size() - 1; ++k) {
						path.moveTo(line[k]);
						path.lineTo(line[k + 1]);
						if (ps.createStroke(path).contains(cut)) {
							line.insert(k + 1, cut);
							break;
						}
					}

					line.remove(i + 2, j - i);
					deleteLoop(line, i);
					isCut = true;
					break;
				}
			}
		}

		if (isCut) {
			break;
		}
	}
}
/*!
    \internal
*/
void QGeoMapPolylineGeometry::updateScreenPoints(const QGeoMap &map,
                                                 qreal strokeWidth)
{
    if (!screenDirty_)
        return;

    QPointF origin = map.coordinateToScreenPosition(srcOrigin_, false).toPointF();

    if (!qIsFinite(origin.x()) || !qIsFinite(origin.y())) {
        clear();
        return;
    }

    // Create the viewport rect in the same coordinate system
    // as the actual points
    QRectF viewport(0, 0, map.width(), map.height());
    viewport.adjust(-strokeWidth, -strokeWidth, strokeWidth, strokeWidth);
    viewport.translate(-1 * origin);

    // Perform clipping to the viewport limits
    QVector<qreal> points;
    QVector<QPainterPath::ElementType> types;

    if (clipToViewport_) {
        clipPathToRect(srcPoints_, srcPointTypes_, viewport, points, types);
    } else {
        points = srcPoints_;
        types = srcPointTypes_;
    }

    QVectorPath vp(points.data(), types.size(), types.data());
    QTriangulatingStroker ts;
    ts.process(vp, QPen(QBrush(Qt::black), strokeWidth), viewport, QPainter::Qt4CompatiblePainting);

    clear();

    // Nothing is on the screen
    if (ts.vertexCount() == 0)
        return;

    // QTriangulatingStroker#vertexCount is actually the length of the array,
    // not the number of vertices
    screenVertices_.reserve(ts.vertexCount());

    screenOutline_ = QPainterPath();

    QPolygonF tri;
    const float *vs = ts.vertices();
    for (int i = 0; i < (ts.vertexCount()/2*2); i += 2) {
        screenVertices_ << QPointF(vs[i], vs[i + 1]);

        if (!qIsFinite(vs[i]) || !qIsFinite(vs[i + 1]))
            break;

        tri << QPointF(vs[i], vs[i + 1]);
        if (tri.size() == 4) {
            tri.remove(0);
            screenOutline_.addPolygon(tri);
        }
    }

    QRectF bb = screenOutline_.boundingRect();
    screenBounds_ = bb;
    this->translate( -1 * sourceBounds_.topLeft());
}
Ejemplo n.º 11
0
int Polygon::remove(lua_State * L) // ( int ) 
{
	QPolygonF* obj = ValueInstaller2<QPolygonF>::check( L, 1 );
	obj->remove( Util::toInt( L, 2 ) );
	return 0;
}
Ejemplo n.º 12
0
/**
 * Joins the nodes at the given \a indexRanges. Each consecutive sequence
 * of nodes will be joined into a single node at the average location.
 *
 * This method can deal with both polygons as well as polylines. For polygons,
 * pass <code>true</code> for \a closed.
 */
static QPolygonF joinPolygonNodes(const QPolygonF &polygon,
                                  const RangeSet<int> &indexRanges,
                                  bool closed)
{
    if (indexRanges.isEmpty())
        return polygon;

    // Do nothing when dealing with a polygon with less than 3 points
    // (we'd no longer have a polygon)
    const int n = polygon.size();
    if (n < 3)
        return polygon;

    RangeSet<int>::Range firstRange = indexRanges.begin();
    RangeSet<int>::Range it = indexRanges.end();

    RangeSet<int>::Range lastRange = it;
    --lastRange; // We know there is at least one range

    QPolygonF result = polygon;

    // Indexes need to be offset when first and last range are joined.
    int indexOffset = 0;

    // Check whether the first and last ranges connect
    if (firstRange.first() == 0 && lastRange.last() == n - 1) {
        // Do nothing when the selection spans the whole polygon
        if (firstRange == lastRange)
            return polygon;

        // Join points of the first and last range when the polygon is closed
        if (closed) {
            QPointF averagePoint;
            for (int i = firstRange.first(); i <= firstRange.last(); i++)
                averagePoint += polygon.at(i);
            for (int i = lastRange.first(); i <= lastRange.last(); i++)
                averagePoint += polygon.at(i);
            averagePoint /= firstRange.length() + lastRange.length();

            result.remove(lastRange.first(), lastRange.length());
            result.remove(1, firstRange.length() - 1);
            result.replace(0, averagePoint);

            indexOffset = firstRange.length() - 1;

            // We have dealt with these ranges now
            // assert: firstRange != lastRange
            ++firstRange;
            --it;
        }
    }

    while (it != firstRange) {
        --it;

        // Merge the consecutive nodes into a single average point
        QPointF averagePoint;
        for (int i = it.first(); i <= it.last(); i++)
            averagePoint += polygon.at(i - indexOffset);
        averagePoint /= it.length();

        result.remove(it.first() + 1 - indexOffset, it.length() - 1);
        result.replace(it.first() - indexOffset, averagePoint);
    }

    return result;
}
Ejemplo n.º 13
0
static int slot_QPolygonF___delitem__(PyObject *sipSelf,PyObject *sipArg)
{
    QPolygonF *sipCpp = reinterpret_cast<QPolygonF *>(sipGetCppPtr((sipSimpleWrapper *)sipSelf,sipType_QPolygonF));

    if (!sipCpp)
        return -1;

    PyObject *sipParseErr = NULL;

    {
        int a0;

        if (sipParseArgs(&sipParseErr, sipArg, "1i", &a0))
        {
            int sipIsErr = 0;

#line 459 "C:\\Users\\marcus\\Downloads\\PyQt-gpl-5.4\\PyQt-gpl-5.4\\sip/QtGui/qpolygon.sip"
int len;

len = sipCpp->count();

if ((a0 = (int)sipConvertFromSequenceIndex(a0, len)) < 0)
    sipIsErr = 1;
else
    sipCpp->remove(a0);
#line 1063 "C:\\Users\\marcus\\Downloads\\PyQt-gpl-5.4\\PyQt-gpl-5.4\\QtGui/sipQtGuiQPolygonF.cpp"

            if (sipIsErr)
                return -1;

            return 0;
        }
    }

    {
        PyObject * a0;

        if (sipParseArgs(&sipParseErr, sipArg, "1T", &PySlice_Type, &a0))
        {
            int sipIsErr = 0;

#line 471 "C:\\Users\\marcus\\Downloads\\PyQt-gpl-5.4\\PyQt-gpl-5.4\\sip/QtGui/qpolygon.sip"
SIP_SSIZE_T len, start, stop, step, slicelength, i;

len = sipCpp->count();

#if PY_VERSION_HEX >= 0x03020000
if (PySlice_GetIndicesEx(a0, len, &start, &stop, &step, &slicelength) < 0)
#else
if (PySlice_GetIndicesEx((PySliceObject *)a0, len, &start, &stop, &step, &slicelength) < 0)
#endif
    sipIsErr = 1;
else
    for (i = 0; i < slicelength; ++i)
    {
        sipCpp->remove(start);
        start += step - 1;
    }
#line 1096 "C:\\Users\\marcus\\Downloads\\PyQt-gpl-5.4\\PyQt-gpl-5.4\\QtGui/sipQtGuiQPolygonF.cpp"

            if (sipIsErr)
                return -1;

            return 0;
        }
    }

    /* Raise an exception if the arguments couldn't be parsed. */
    sipNoMethod(sipParseErr, sipName_QPolygonF, sipName___delitem__, NULL);

    return -1;
}
Ejemplo n.º 14
0
QPolygonF minigis::shiftPolygonSimple(const QPolygonF &origin, qreal delta, bool closed)
{
    QPolygonF path = origin;

    QPolygonF norm;
    // ----------------- Поиск нормалей к оригинальному полигону
    int N = path.size();
    for (int i = 1; i < N; ++i) {
        QPointF vect = path.at(i) - path.at(i-1);
        double len = lengthR2(vect);
        if (qFuzzyIsNull(len)) {
            path.remove(i);
            --N;
            --i;
            continue;
        }
        vect /= len;
        norm.append(QPointF(vect.y() * delta, -vect.x() * delta));
    }
    // ----
    if (closed) {
        QPointF vect = path.first() - path.last();
        double len = lengthR2(vect);
        if (qFuzzyIsNull(len))
            path.remove(path.size() - 1);
        else {
            vect /= len;
            norm.append(QPointF(vect.y() * delta, -vect.x() * delta));
        }
    }
    // ------------------

    QVector<QLineF> lines;
    // -------------------------- Построение смещенных линий
    for (int i = 1; i < path.size(); ++i)
        lines.append(QLineF(path.at(i) + norm.at(i-1), path.at(i-1) + norm.at(i-1)));
    // ----
    if (closed)
        lines.append(QLineF(path.first() + norm.last(), path.last() + norm.last()));
    // ------------------

    QPolygonF shell;
    if (lines.isEmpty())
        return shell;

    // -------------------------- Построение смещенного полигона
    N = lines.size();
    for (int i = 1; i < N; ++i) {
        QPointF tmp;
        QLineF::IntersectType type = lines.at(i-1).intersect(lines.at(i), &tmp);
        double ang = lines.at(i-1).angleTo(lines.at(i));
        if (type != QLineF::NoIntersection)
            shell.append(tmp);
        else {
            if (qFuzzyCompare(ang, 180.))
                shell.append(lines.at(i).p2() - 2 * norm.at(i));
            shell.append(lines.at(i).p2());
        }
    }
    // ----
    if (closed) {
        QPointF tmp;
        QLineF::IntersectType type = lines.last().intersect(lines.first(), &tmp);
        double ang = lines.last().angleTo(lines.first());
        if (type != QLineF::NoIntersection)
            shell.append(tmp);
        else {
            if (qFuzzyCompare(ang, 180.))
                shell.append(lines.first().p2() - 2 * norm.first());
            shell.append(lines.first().p2());
        }
        shell.append(shell.first());
    }
    else {
        shell.prepend(lines.first().p2());
        shell.append(lines.last().p1());
    }
    // ------------------

    return shell;
}
Ejemplo n.º 15
0
QPolygonF minigis::shiftPolygonDifficult(const QPolygonF &origin, qreal delta, bool closed)
{
    if (qFuzzyIsNull(delta))
        return origin;

    QPolygonF path = origin;

    QPolygonF norm;
    // ----------------- Поиск нормалей к оригинальному полигону
    int N = path.size();
    for (int i = 1; i < N; ++i) {
        QPointF vect = path.at(i) - path.at(i-1);
        double len = lengthR2(vect);
        if (qFuzzyIsNull(len)) {
            path.remove(i);
            --N;
            --i;
            continue;
        }
        vect /= len;
        norm.append(QPointF(vect.y() * delta, -vect.x() * delta));
    }
    // ----
    if (closed) {
        QPointF vect = path.first() - path.last();
        double len = lengthR2(vect);
        if (qFuzzyIsNull(len))
            path.remove(path.size() - 1);
        else {
            vect /= len;
            norm.append(QPointF(vect.y() * delta, -vect.x() * delta));
        }
    }
    // ------------------

    QVector<QLineF> lines;
    // -------------------------- Построение смещенных линий
    for (int i = 1; i < path.size(); ++i)
        lines.append(QLineF(path.at(i) + norm.at(i-1), path.at(i-1) + norm.at(i-1)));
    // ----
    if (closed)
        lines.append(QLineF(path.first() + norm.last(), path.last() + norm.last()));
    // ------------------

    QPolygonF shell;
    if (lines.isEmpty())
        return shell;

    // -------------------------- Построение смещенного полигона
    N = lines.size();
    for (int i = 1; i < N; ++i) {
        QPointF tmp;
        QLineF::IntersectType type = lines.at(i-1).intersect(lines.at(i), &tmp);
        qreal ang = lines.at(i-1).angleTo(lines.at(i));
        if (type != QLineF::NoIntersection)
            shell.append(tmp);
        else {
            if (qFuzzyCompare(ang, qreal(180)))
                shell.append(lines.at(i).p2() - 2 * norm.at(i));
            shell.append(lines.at(i).p2());
        }
    }
    // ----
    if (closed) {
        QPointF tmp;
        QLineF::IntersectType type = lines.last().intersect(lines.first(), &tmp);
        qreal ang = lines.last().angleTo(lines.first());
        if (type != QLineF::NoIntersection)
            shell.append(tmp);
        else {
            if (qFuzzyCompare(ang, qreal(180)))
                shell.append(lines.first().p2() - 2 * norm.first());
            shell.append(lines.first().p2());
        }
        shell.append(shell.first());
    }
    else {
        shell.prepend(lines.first().p2());
        shell.append(lines.last().p1());
    }
    // ------------------

    // -------------------------- обрезание острых углов
    int k  = 0;
    N = lines.size();
    for (int i = 1; i < N; ++i) {
        double ang = lines.at(i-1).angleTo(lines.at(i));

        bool first  = (120 < ang && ang < 180 && delta < 0) || (180 < ang && ang < 240 && delta > 0);
        bool second = (120 < ang && ang < 180 && delta > 0) || (180 < ang && ang < 240 && delta < 0);
        if (first) {
            int num = closed ? 1 : 0;
            QPointF v = shell.at(i + k - num) - path.at(i);
            v /= lengthR2(v);
            QPointF start = path.at(i) + v * qAbs(delta);
            QLineF tmp(start, start + QPointF(-v.y(), v.x()));
            QPointF a;
            if (tmp.intersect(lines.at(i  ), &a) != QLineF::NoIntersection)
                shell.replace(i + k - num, a);
            if (tmp.intersect(lines.at(i-1), &a) != QLineF::NoIntersection)
                shell.insert(i + k - num, a);
            ++k;
        }
        else if (second) {
            // TODO: cut corner
        }
    }
    // ----
    if (closed) {
        double ang = lines.last().angleTo(lines.first());

        int num = lines.size();
        int shellNum = (num + k - 1) % shell.size();
        bool first  = (120 < ang && ang < 180 && delta < 0) || (180 < ang && ang < 240 && delta > 0);
        bool second = (180 < ang && ang < 240 && delta < 0) || (120 < ang && ang < 180 && delta > 0);
        if (first) {
            QPointF v = shell.at(shellNum) - path.at(num % path.size());
            v /= lengthR2(v);
            QPointF start = path.at(num % path.size()) + v * qAbs(delta);
            QLineF tmp(start, start + QPointF(-v.y(), v.x()));
            QPointF a;
            if (tmp.intersect(lines.first(), &a) != QLineF::NoIntersection)
                shell.replace(shellNum, a);
            if (tmp.intersect(lines.last() , &a) != QLineF::NoIntersection)
                shell.insert(shellNum, a);
        }
        else if (second) {
            // TODO: cut corner
        }
    }
    // ------------------

    return shell;
}