Esempio n. 1
0
void Poly::cleanup(double epsilon)
{
  vertices = simplified(vertices, epsilon);
  if (!closed) return;
  uint n_vert = vertices.size();
  vector<Vector2d> invert;
  invert.insert(invert.end(),vertices.begin()+n_vert/2,vertices.end());
  invert.insert(invert.end(),vertices.begin(),vertices.begin()+n_vert/2);
  vertices = simplified(invert, epsilon);
  //calcHole();
}
Esempio n. 2
0
void
_cleanup_path(PathIterator& path, const agg::trans_affine& trans,
              bool remove_nans, bool do_clip,
              const agg::rect_base<double>& rect,
              e_snap_mode snap_mode, double stroke_width,
              bool do_simplify, bool return_curves,
              std::vector<double>& vertices,
              std::vector<npy_uint8>& codes)
{
    typedef agg::conv_transform<PathIterator>  transformed_path_t;
    typedef PathNanRemover<transformed_path_t> nan_removal_t;
    typedef PathClipper<nan_removal_t>         clipped_t;
    typedef PathSnapper<clipped_t>             snapped_t;
    typedef PathSimplifier<snapped_t>          simplify_t;
    typedef agg::conv_curve<simplify_t>        curve_t;

    transformed_path_t tpath(path, trans);
    nan_removal_t      nan_removed(tpath, remove_nans, path.has_curves());
    clipped_t          clipped(nan_removed, do_clip, rect);
    snapped_t          snapped(clipped, snap_mode, path.total_vertices(), stroke_width);
    simplify_t         simplified(snapped, do_simplify, path.simplify_threshold());

    vertices.reserve(path.total_vertices() * 2);
    codes.reserve(path.total_vertices());

    if (return_curves)
    {
        __cleanup_path(simplified, vertices, codes);
    }
    else
    {
        curve_t curve(simplified);
        __cleanup_path(curve, vertices, codes);
    }
}
Esempio n. 3
0
Py::Object _path_module::convert_path_to_polygons(const Py::Tuple& args)
{
    typedef agg::conv_transform<PathIterator> transformed_path_t;
    typedef SimplifyPath<transformed_path_t> simplify_t;
    typedef agg::conv_curve<simplify_t> curve_t;

    typedef std::vector<double> vertices_t;

    args.verify_length(4);

    PathIterator path(args[0]);
    agg::trans_affine trans = py_to_agg_transformation_matrix(args[1], false);
    double width = Py::Float(args[2]);
    double height = Py::Float(args[3]);

    bool simplify = path.should_simplify() && width != 0.0 && height != 0.0;

    transformed_path_t tpath(path, trans);
    simplify_t simplified(tpath, false, simplify, width, height);
    curve_t curve(simplified);

    Py::List polygons;
    vertices_t polygon;
    double x, y;
    unsigned code;

    polygon.reserve(path.total_vertices() * 2);

    while ((code = curve.vertex(&x, &y)) != agg::path_cmd_stop)
    {
	if ((code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly) {
	    if (polygon.size() >= 2)
	    {
		polygon.push_back(polygon[0]);
		polygon.push_back(polygon[1]);
		_add_polygon(polygons, polygon);
	    }
	    polygon.clear();
	} else {
	    if (code == agg::path_cmd_move_to) {
		_add_polygon(polygons, polygon);
		polygon.clear();
	    }
	    polygon.push_back(x);
	    polygon.push_back(y);
	}
    }

    _add_polygon(polygons, polygon);

    return polygons;
}
Esempio n. 4
0
// Douglas-Peucker algorithm
vector<Vector2d> simplified(const vector<Vector2d> &vert, double epsilon)
{
  if (epsilon == 0) return vert;
  uint n_vert = vert.size();
  if (n_vert<3) return vert;
  double dmax = 0;
  //Find the point with the maximum distance from line start-end
  uint index = 0;
  Vector2d normal = normalV(vert.back()-vert.front());
  normal.normalize();
  if( (normal.length()==0) || ((abs(normal.length())-1)>epsilon) ) return vert;
  for (uint i = 1; i < n_vert-1 ; i++)
    {
      double dist = abs((vert[i]-vert.front()).dot(normal));
      if (dist >= epsilon && dist > dmax) {
	index = i;
	dmax = dist;
      }
    }
  vector<Vector2d> newvert;
  if (index > 0) // there is a point > epsilon
    {
      // divide at max dist point and cleanup both parts recursively
      vector<Vector2d> part1;
      part1.insert(part1.end(), vert.begin(), vert.begin()+index+1);
      vector<Vector2d> c1 = simplified(part1, epsilon);
      vector<Vector2d> part2;
      part2.insert(part2.end(), vert.begin()+index, vert.end());
      vector<Vector2d> c2 = simplified(part2, epsilon);
      newvert.insert(newvert.end(), c1.begin(), c1.end()-1);
      newvert.insert(newvert.end(), c2.begin(), c2.end());
    }
  else
    { // all points are nearer than espilon
      newvert.push_back(vert.front());
      newvert.push_back(vert.back());
    }
  return newvert;
}
Esempio n. 5
0
void FakeVimProxy::indentRegion(int beginBlock, int endBlock, QChar typedChar) {
    QPlainTextEdit *ed = qobject_cast<QPlainTextEdit *>(m_widget);
    if (!ed)
        return;

    const auto indentSize = theFakeVimSetting(FakeVim::Internal::ConfigShiftWidth)
            ->value().toInt();

    QTextDocument *doc = ed->document();
    QTextBlock startBlock = doc->findBlockByNumber(beginBlock);

    // Record line lengths for mark adjustments
    QVector<int> lineLengths(endBlock - beginBlock + 1);
    QTextBlock block = startBlock;

    for (int i = beginBlock; i <= endBlock; ++i) {
        const auto line = block.text();
        lineLengths[i - beginBlock] = line.length();
        if (typedChar.unicode() == 0 && line.simplified().isEmpty()) {
            // clear empty lines
            QTextCursor cursor(block);
            while (!cursor.atBlockEnd())
                cursor.deleteChar();
        } else {
            const auto previousBlock = block.previous();
            const auto previousLine = previousBlock.isValid() ? previousBlock.text() : QString();

            int indent = firstNonSpace(previousLine);
            if (typedChar == '}')
                indent = std::max(0, indent - indentSize);
            else if ( previousLine.endsWith("{") )
                indent += indentSize;
            const auto indentString = QString(" ").repeated(indent);

            QTextCursor cursor(block);
            cursor.beginEditBlock();
            cursor.movePosition(QTextCursor::StartOfBlock);
            cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, firstNonSpace(line));
            cursor.removeSelectedText();
            cursor.insertText(indentString);
            cursor.endEditBlock();
        }
        block = block.next();
    }
}
Esempio n. 6
0
void GroupSocket::connectToHost()
{
    bool retry = false;
    if (socket.state() != QAbstractSocket::UnconnectedState) {
        retry = true;
        socket.abort();
    }
    reset();
    timer.start();
    const auto &groupConfig = getConfig().groupManager;
    const auto remoteHost = groupConfig.host;
    const auto remotePort = static_cast<quint16>(groupConfig.remotePort);
    emit sendLog(QString("%1 to remote host %2:%3")
                     .arg(retry ? "Reconnecting" : "Connecting")
                     .arg(remoteHost.simplified().constData())
                     .arg(remotePort));
    socket.connectToHost(remoteHost, remotePort);
}
Esempio n. 7
0
    SEXP CallProxy::eval(){
        if( TYPEOF(call) == LANGSXP ){

            if( can_simplify(call) ){
                SlicingIndex indices(0,subsets.nrows()) ;
                while(simplified(indices)) ;
                set_call(call) ;
            }

            int n = proxies.size() ;
            for( int i=0; i<n; i++){
                proxies[i].set( subsets[proxies[i].symbol] ) ;
            }
            return call.eval(env) ;
        } else if( TYPEOF(call) == SYMSXP) {
            // SYMSXP
            if( subsets.count(call) ) return subsets.get_variable(call) ;
            return call.eval(env) ;
        }
        return call ;
    }
bool PNS_TOPOLOGY::SimplifyLine( PNS_LINE* aLine )
{
    if( !aLine->LinkedSegments() || !aLine->SegmentCount() )
        return false;

    PNS_SEGMENT* root = ( *aLine->LinkedSegments() )[0];
    PNS_LINE l = m_world->AssembleLine( root );
    SHAPE_LINE_CHAIN simplified( l.CLine() );

    simplified.Simplify();

    if( simplified.PointCount() != l.PointCount() )
    {
        PNS_LINE lnew( l );
        m_world->Remove( &l );
        lnew.SetShape( simplified );
        m_world->Add( &lnew );
        return true;
    }

    return false;
}
Esempio n. 9
0
Py::Object
_path_module::convert_to_svg(const Py::Tuple& args)
{
    args.verify_length(5);

    PathIterator path(args[0]);
    agg::trans_affine trans = py_to_agg_transformation_matrix(args[1].ptr(), false);

    Py::Object clip_obj = args[2];
    bool do_clip;
    agg::rect_base<double> clip_rect(0, 0, 0, 0);
    if (clip_obj.isNone() || !clip_obj.isTrue())
    {
        do_clip = false;
    }
    else
    {
        double x1, y1, x2, y2;
        Py::Tuple clip_tuple(clip_obj);
        x1 = Py::Float(clip_tuple[0]);
        y1 = Py::Float(clip_tuple[1]);
        x2 = Py::Float(clip_tuple[2]);
        y2 = Py::Float(clip_tuple[3]);
        clip_rect.init(x1, y1, x2, y2);
        do_clip = true;
    }

    bool simplify;
    Py::Object simplify_obj = args[3];
    if (simplify_obj.isNone())
    {
        simplify = path.should_simplify();
    }
    else
    {
        simplify = simplify_obj.isTrue();
    }

    int precision = Py::Int(args[4]);

    #if PY_VERSION_HEX < 0x02070000
    char format[64];
    snprintf(format, 64, "%s.%dg", "%", precision);
    #endif

    typedef agg::conv_transform<PathIterator>  transformed_path_t;
    typedef PathNanRemover<transformed_path_t> nan_removal_t;
    typedef PathClipper<nan_removal_t>         clipped_t;
    typedef PathSimplifier<clipped_t>          simplify_t;

    transformed_path_t tpath(path, trans);
    nan_removal_t      nan_removed(tpath, true, path.has_curves());
    clipped_t          clipped(nan_removed, do_clip, clip_rect);
    simplify_t         simplified(clipped, simplify, path.simplify_threshold());

    size_t buffersize = path.total_vertices() * (precision + 5) * 4;
    char* buffer = (char *)malloc(buffersize);
    char* p = buffer;

    const char codes[] = {'M', 'L', 'Q', 'C'};
    const int  waits[] = {  1,   1,   2,   3};

    int wait = 0;
    unsigned code;
    double x = 0, y = 0;
    while ((code = simplified.vertex(&x, &y)) != agg::path_cmd_stop)
    {
        if (wait == 0)
        {
            *p++ = '\n';

            if (code == 0x4f)
            {
                *p++ = 'z';
                *p++ = '\n';
                continue;
            }

            *p++ = codes[code-1];
            wait = waits[code-1];
        }
        else
        {
            *p++ = ' ';
        }

        #if PY_VERSION_HEX >= 0x02070000
        char* str;
        str = PyOS_double_to_string(x, 'g', precision, 0, NULL);
        p += snprintf(p, buffersize - (p - buffer), str);
        PyMem_Free(str);
        *p++ = ' ';
        str = PyOS_double_to_string(y, 'g', precision, 0, NULL);
        p += snprintf(p, buffersize - (p - buffer), str);
        PyMem_Free(str);
        #else
        char str[64];
        PyOS_ascii_formatd(str, 64, format, x);
        p += snprintf(p, buffersize - (p - buffer), str);
        *p++ = ' ';
        PyOS_ascii_formatd(str, 64, format, y);
        p += snprintf(p, buffersize - (p - buffer), str);
        #endif

        --wait;
    }

    #if PY3K
    PyObject* result = PyUnicode_FromStringAndSize(buffer, p - buffer);
    #else
    PyObject* result = PyString_FromStringAndSize(buffer, p - buffer);
    #endif
    free(buffer);

    return Py::Object(result, true);
}
Esempio n. 10
0
                else
                    pieces.append(typeString + " " + parameter.name());
            }
            signature = "(" + pieces.join(", ") + ")";
        }

        QDomElement contextElement = document.createElement("context");
        QDomElement nameElement = document.createElement("name");
        nameElement.appendChild(document.createTextNode(nodeName + signature));
        contextElement.appendChild(nameElement);

        QDomElement messageElement = document.createElement("message");
        contextElement.appendChild(messageElement);

        QDomElement sourceElement = document.createElement("source");
        QString sourceText = simplified(node->doc().source());
        if (!signature.isEmpty() && signature != "()" && !sourceText.contains("\\fn"))
            sourceText.prepend(QString("\\fn %1%2\n").arg(nodeName).arg(signature));
        sourceElement.appendChild(document.createTextNode(sourceText));
        messageElement.appendChild(sourceElement);

        QDomElement translationElement = document.createElement("translation");
        translationElement.setAttribute("type", "unfinished");
        messageElement.appendChild(translationElement);

        QDomElement locationElement = document.createElement("location");
        locationElement.setAttribute("filename", node->doc().location().filePath());
        locationElement.setAttribute("line", node->doc().location().lineNo());
        messageElement.appendChild(locationElement);

        contexts.append(contextElement);
Esempio n. 11
0
int delaunayTriang(const vector<Vector2d> &points,
		   vector<Triangle> &triangles,
		   double z)
{
#define PTRIANGULATOR 0
#if PTRIANGULATOR
  vector<Vector2d> spoints = simplified(points, 1);
  uint npoints = spoints.size();
  vector<double> xpoints(npoints);
  vector<double> ypoints(npoints);
  for (uint i = 0; i < npoints; i++) {
    xpoints[i] = spoints[npoints-i-1].x();
    ypoints[i] = spoints[npoints-i-1].y();
  }

  polytri::PolygonTriangulator pt(xpoints, ypoints);

  const polytri::PolygonTriangulator::Triangles * tr = pt.triangles();

  uint ntr = tr->size();

  cerr << npoints << " -> " << ntr << endl;

  triangles.resize(ntr);

  uint itri=0;
  for (polytri::PolygonTriangulator::Triangles::const_iterator itr = tr->begin();
       itr != tr->end(); ++itr) {

    const polytri::PolygonTriangulator::Triangle t = *itr;

    triangles[itri] = Triangle(Vector3d(xpoints[t[0]], ypoints[t[0]], z),
			       Vector3d(xpoints[t[1]], ypoints[t[1]], z),
			       Vector3d(xpoints[t[2]], ypoints[t[2]], z));
    itri++;
  }

  return ntr;
#endif

  // struct triangulateio in;

  // in.numberofpoints = npoints;
  // in.numberofpointattributes = (int)0;
  // in.pointlist =
  // in.pointattributelist = NULL;
  // in.pointmarkerlist = (int *) NULL;
  // in.numberofsegments = 0;
  // in.numberofholes = 0;
  // in.numberofregions = 0;
  // in.regionlist = (REAL *) NULL;

  // delclass = new piyush;
  // piyush *pdelclass = (piyush *)delclass;
  // triswitches.push_back('\0');
  // char *ptris = &triswitches[0];


  // pmesh = new piyush::__pmesh;
  // pbehavior = new piyush::__pbehavior;

  // piyush::__pmesh     * tpmesh     = (piyush::__pmesh *)     pmesh;
  // piyush::__pbehavior * tpbehavior = (piyush::__pbehavior *) pbehavior;

  // pdelclass->triangleinit(tpmesh);
  // pdelclass->parsecommandline(1, &ptris, tpbehavior);

  // pdelclass->transfernodes(tpmesh, tpbehavior, in.pointlist,
  // 			   in.pointattributelist,
  // 			   in.pointmarkerlist, in.numberofpoints,
  // 			   in.numberofpointattributes);
  // tpmesh->hullsize = pdelclass->delaunay(tpmesh, tpbehavior);

  // /* Ensure that no vertex can be mistaken for a triangular bounding */
  // /*   box vertex in insertvertex().                                 */
  // tpmesh->infvertex1 = (piyush::vertex) NULL;
  // tpmesh->infvertex2 = (piyush::vertex) NULL;
  // tpmesh->infvertex3 = (piyush::vertex) NULL;

  // 	/* Calculate the number of edges. */
  // tpmesh->edges = (3l * tpmesh->triangles.items + tpmesh->hullsize) / 2l;
  // pdelclass->numbernodes(tpmesh, tpbehavior);



  /////////////////////////////////////////////// triangle++ crap


  // typedef reviver::dpoint <double, 2> Point;
  // vector<Point> p(points.size());
  // for (uint i = 0; i < p.size(); i++) {
  //   p[i] = Point(points[i].x(),points[i].y());
  // }
  // tpp::Delaunay del(p);
  // /*
  //   -p  Triangulates a Planar Straight Line Graph (.poly file).
  //   -r  Refines a previously generated mesh.
  //   -q  Quality mesh generation.  A minimum angle may be specified.
  //   -a  Applies a maximum triangle area constraint.
  //   -u  Applies a user-defined triangle constraint.
  //   -A  Applies attributes to identify triangles in certain regions.
  //   -c  Encloses the convex hull with segments.
  //   -D  Conforming Delaunay:  all triangles are truly Delaunay.
  //   -j  Jettison unused vertices from output .node file.
  //   -e  Generates an edge list.
  //   -v  Generates a Voronoi diagram.
  //   -n  Generates a list of triangle neighbors.
  //   -g  Generates an .off file for Geomview.
  //   -B  Suppresses output of boundary information.
  //   -P  Suppresses output of .poly file.
  //   -N  Suppresses output of .node file.
  //   -E  Suppresses output of .ele file.
  //   -I  Suppresses mesh iteration numbers.
  //   -O  Ignores holes in .poly file.
  //   -X  Suppresses use of exact arithmetic.
  //   -z  Numbers all items starting from zero (rather than one).
  //   -o2 Generates second-order subparametric elements.
  //   -Y  Suppresses boundary segment splitting.
  //   -S  Specifies maximum number of added Steiner points.
  //   -i  Uses incremental method, rather than divide-and-conquer.
  //   -F  Uses Fortune's sweepline algorithm, rather than d-and-c.
  //   -l  Uses vertical cuts only, rather than alternating cuts.
  //   -s  Force segments into mesh by splitting (instead of using CDT).
  //   -C  Check consistency of final mesh.
  //   -Q  Quiet:  No terminal output except errors.
  // */
  // string switches = "pq0DzQ";
  // del.Triangulate(switches);
  // int ntri = del.ntriangles();
  // if (ntri>0) {
  //   triangles.resize(ntri);
  //   uint itri=0;
  //   for (tpp::Delaunay::fIterator dit = del.fbegin(); dit != del.fend(); ++dit) {
  //     Point pA = del.point_at_vertex_id(del.Org (dit));
  //     Point pB = del.point_at_vertex_id(del.Dest(dit));
  //     Point pC = del.point_at_vertex_id(del.Apex(dit));
  //     triangles[itri] = Triangle(Vector3d(pA[0],pA[1],z),
  //     				 Vector3d(pB[0],pB[1],z),
  //     				 Vector3d(pC[0],pC[1],z));
  //     // Vector2d vA = points[del.Org (dit)];
  //     // Vector2d vB = points[del.Dest(dit)];
  //     // Vector2d vC = points[del.Apex(dit)];
  //     // triangles[itri] = Triangle(Vector3d(vA.x(),vA.y(),z),
  //     // 				 Vector3d(vB.x(),vB.y(),z),
  //     // 				 Vector3d(vC.x(),vC.y(),z));
  //     itri++;
  //   }
  // }

  // return ntri;
  return 0;
}
/// @par
///
/// The raw contours will match the region outlines exactly. The @p maxError and @p maxEdgeLen
/// parameters control how closely the simplified contours will match the raw contours.
///
/// Simplified contours are generated such that the vertices for portals between areas match up.
/// (They are considered mandatory vertices.)
///
/// Setting @p maxEdgeLength to zero will disabled the edge length feature.
///
/// See the #rcConfig documentation for more information on the configuration parameters.
///
/// @see rcAllocContourSet, rcCompactHeightfield, rcContourSet, rcConfig
bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
					 const float maxError, const int maxEdgeLen,
					 rcContourSet& cset, const int buildFlags)
{
	rcAssert(ctx);
	
	const int w = chf.width;
	const int h = chf.height;
	const int borderSize = chf.borderSize;
	
	ctx->startTimer(RC_TIMER_BUILD_CONTOURS);
	
	rcVcopy(cset.bmin, chf.bmin);
	rcVcopy(cset.bmax, chf.bmax);
	if (borderSize > 0)
	{
		// If the heightfield was build with bordersize, remove the offset.
		const float pad = borderSize*chf.cs;
		cset.bmin[0] += pad;
		cset.bmin[2] += pad;
		cset.bmax[0] -= pad;
		cset.bmax[2] -= pad;
	}
	cset.cellSizeXZ = chf.cs;
	cset.cellSizeY = chf.ch;
	cset.width = chf.width - chf.borderSize*2;
	cset.height = chf.height - chf.borderSize*2;
	cset.borderSize = chf.borderSize;
	
	int maxContours = rcMax((int)chf.maxRegions, 8);
	cset.conts = (rcContour*)rcAlloc(sizeof(rcContour)*maxContours, RC_ALLOC_PERM);
	if (!cset.conts)
		return false;
	cset.nconts = 0;
	
	rcScopedDelete<unsigned char> flags = (unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_TEMP);
	if (!flags)
	{
		ctx->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'flags' (%d).", chf.spanCount);
		return false;
	}
	
	ctx->startTimer(RC_TIMER_BUILD_CONTOURS_TRACE);
	
	// Mark boundaries.
	for (int y = 0; y < h; ++y)
	{
		for (int x = 0; x < w; ++x)
		{
			const rcCompactCell& c = chf.cells[x+y*w];
			for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
			{
				unsigned char res = 0;
				const rcCompactSpan& s = chf.spans[i];
				if (!chf.spans[i].regionID || (chf.spans[i].regionID & RC_BORDER_REG))
				{
					flags[i] = 0;
					continue;
				}
				for (int dir = 0; dir < 4; ++dir)
				{
					unsigned short r = 0;
					if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
					{
						const int ax = x + rcGetDirOffsetX(dir);
						const int ay = y + rcGetDirOffsetY(dir);
						const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir);
						r = chf.spans[ai].regionID;
					}
					if (r == chf.spans[i].regionID)
						res |= (1 << dir);
				}
				flags[i] = res ^ 0xf; // Inverse, mark non connected edges.
			}
		}
	}
	
	ctx->stopTimer(RC_TIMER_BUILD_CONTOURS_TRACE);
	
	rcIntArray verts(256);
	rcIntArray simplified(64);
	
	for (int y = 0; y < h; ++y)
	{
		for (int x = 0; x < w; ++x)
		{
			const rcCompactCell& c = chf.cells[x+y*w];
			for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
			{
				if (flags[i] == 0 || flags[i] == 0xf)
				{
					flags[i] = 0;
					continue;
				}
				const unsigned short reg = chf.spans[i].regionID;
				if (!reg || (reg & RC_BORDER_REG))
					continue;
				const navAreaMask areaMask = chf.areaMasks[ i ];
				
				verts.resize(0);
				simplified.resize(0);

				ctx->startTimer(RC_TIMER_BUILD_CONTOURS_TRACE);
				walkContour(x, y, i, chf, flags, verts);
				ctx->stopTimer(RC_TIMER_BUILD_CONTOURS_TRACE);

				ctx->startTimer(RC_TIMER_BUILD_CONTOURS_SIMPLIFY);
				simplifyContour(verts, simplified, maxError, maxEdgeLen, buildFlags);
				removeDegenerateSegments(simplified);
				ctx->stopTimer(RC_TIMER_BUILD_CONTOURS_SIMPLIFY);
				

				// Store region->contour remap info.
				// Create contour.
				if (simplified.size()/4 >= 3)
				{
					if (cset.nconts >= maxContours)
					{
						// Allocate more contours.
						// This happens when a region has holes.
						const int oldMax = maxContours;
						maxContours *= 2;
						rcContour* newConts = (rcContour*)rcAlloc(sizeof(rcContour)*maxContours, RC_ALLOC_PERM);
						for (int j = 0; j < cset.nconts; ++j)
						{
							newConts[j] = cset.conts[j];
							// Reset source pointers to prevent data deletion.
							cset.conts[j].verts = 0;
							cset.conts[j].rverts = 0;
						}
						rcFree(cset.conts);
						cset.conts = newConts;
					
						ctx->log(RC_LOG_WARNING, "rcBuildContours: Expanding max contours from %d to %d.", oldMax, maxContours);
					}
					
					rcContour* cont = &cset.conts[cset.nconts++];
					
					cont->nverts = simplified.size()/4;
					cont->verts = (int*)rcAlloc(sizeof(int)*cont->nverts*4, RC_ALLOC_PERM);
					if (!cont->verts)
					{
						ctx->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'verts' (%d).", cont->nverts);
						return false;
					}
					memcpy(cont->verts, &simplified[0], sizeof(int)*cont->nverts*4);
					if (borderSize > 0)
					{
						// If the heightfield was build with bordersize, remove the offset.
						for (int j = 0; j < cont->nverts; ++j)
						{
							int* v = &cont->verts[j*4];
							v[0] -= borderSize;
							v[2] -= borderSize;
						}
					}
					
					cont->nrverts = verts.size()/4;
					cont->rverts = (int*)rcAlloc(sizeof(int)*cont->nrverts*4, RC_ALLOC_PERM);
					if (!cont->rverts)
					{
						ctx->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'rverts' (%d).", cont->nrverts);
						return false;
					}
					memcpy(cont->rverts, &verts[0], sizeof(int)*cont->nrverts*4);
					if (borderSize > 0)
					{
						// If the heightfield was build with bordersize, remove the offset.
						for (int j = 0; j < cont->nrverts; ++j)
						{
							int* v = &cont->rverts[j*4];
							v[0] -= borderSize;
							v[2] -= borderSize;
						}
					}
					
					cont->reg = reg;
					cont->areaMask = areaMask;
				}
			}
		}
	}
	
	// Merge holes if needed.
	if (cset.nconts > 0)
	{
		// Calculate winding of all polygons.
		rcScopedDelete<char> winding = (char*)rcAlloc(sizeof(char)*cset.nconts, RC_ALLOC_TEMP);
		if (!winding)
		{
			ctx->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'hole' (%d).", cset.nconts);
			return false;
		}
		int nholes = 0;
	for (int i = 0; i < cset.nconts; ++i)
	{
		rcContour& cont = cset.conts[i];
			// If the contour is wound backwards, it is a hole.
			winding[i] = calcAreaOfPolygon2D(cont.verts, cont.nverts) < 0 ? -1 : 1;
			if (winding[i] < 0)
				nholes++;
		}
		
		if (nholes > 0)
		{
			// Collect outline contour and holes contours per region.
			// We assume that there is one outline and multiple holes.
			const int nregions = chf.maxRegions+1;
			rcScopedDelete<rcContourRegion> regions = (rcContourRegion*)rcAlloc(sizeof(rcContourRegion)*nregions, RC_ALLOC_TEMP);
			if (!regions)
			{
				ctx->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'regions' (%d).", nregions);
				return false;
			}
			memset(regions, 0, sizeof(rcContourRegion)*nregions);
			
			rcScopedDelete<rcContourHole> holes = (rcContourHole*)rcAlloc(sizeof(rcContourHole)*cset.nconts, RC_ALLOC_TEMP);
			if (!holes)
			{
				ctx->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'holes' (%d).", cset.nconts);
				return false;
			}
			memset(holes, 0, sizeof(rcContourHole)*cset.nconts);
			
			for (int i = 0; i < cset.nconts; ++i)
			{
				rcContour& cont = cset.conts[i];
				// Positively would contours are outlines, negative holes.
				if (winding[i] > 0)
				{
					if (regions[cont.reg].outline)
						ctx->log(RC_LOG_ERROR, "rcBuildContours: Multiple outlines for region %d.", cont.reg);
					regions[cont.reg].outline = &cont;
				}
				else
				{
					regions[cont.reg].nholes++;
				}
			}
			int index = 0;
			for (int i = 0; i < nregions; i++)
			{
				if (regions[i].nholes > 0)
				{
					regions[i].holes = &holes[index];
					index += regions[i].nholes;
					regions[i].nholes = 0;
				}
			}
			for (int i = 0; i < cset.nconts; ++i)
			{
				rcContour& cont = cset.conts[i];
				rcContourRegion& reg = regions[cont.reg];
				if (winding[i] < 0)
					reg.holes[reg.nholes++].contour = &cont;
			}
			
			// Finally merge each regions holes into the outline.
			for (int i = 0; i < nregions; i++)
			{
				rcContourRegion& reg = regions[i];
				if (!reg.nholes) continue;
				
				if (reg.outline)
				{
					mergeRegionHoles(ctx, reg);
				}
				else
				{
					// The region does not have an outline.
					// This can happen if the contour becaomes selfoverlapping because of
					// too aggressive simplification settings.
					ctx->log(RC_LOG_ERROR, "rcBuildContours: Bad outline for region %d, contour simplification is likely too aggressive.", i);
				}
			}
		}
		
	}
	
	ctx->stopTimer(RC_TIMER_BUILD_CONTOURS);
	
	return true;
}
Esempio n. 13
0
void ExPoly::cleanup(double epsilon)
{
  outer.vertices = simplified(outer.vertices, epsilon);
  for (uint i=0; i < holes.size(); i++)
    holes[i].vertices = simplified(holes[i].vertices, epsilon);
}