Vector<Vector2> expand(const Vector<Vector2> &points, const Rect2i &rect, float epsilon = 2.0) {
	int size = points.size();
	ERR_FAIL_COND_V(size < 2, Vector<Vector2>());

	ClipperLib::Path subj;
	ClipperLib::PolyTree solution;
	ClipperLib::PolyTree out;

	for (int i = 0; i < points.size(); i++) {

		subj << ClipperLib::IntPoint(points[i].x * PRECISION, points[i].y * PRECISION);
	}
	ClipperLib::ClipperOffset co;
	co.AddPath(subj, ClipperLib::jtMiter, ClipperLib::etClosedPolygon);
	co.Execute(solution, epsilon * PRECISION);

	ClipperLib::PolyNode *p = solution.GetFirst();

	ERR_FAIL_COND_V(!p, points);

	while (p->IsHole()) {
		p = p->GetNext();
	}

	//turn the result into simply polygon (AKA, fix overlap)

	//clamp into the specified rect
	ClipperLib::Clipper cl;
	cl.StrictlySimple(true);
	cl.AddPath(p->Contour, ClipperLib::ptSubject, true);
	//create the clipping rect
	ClipperLib::Path clamp;
	clamp.push_back(ClipperLib::IntPoint(0, 0));
	clamp.push_back(ClipperLib::IntPoint(rect.size.width * PRECISION, 0));
	clamp.push_back(ClipperLib::IntPoint(rect.size.width * PRECISION, rect.size.height * PRECISION));
	clamp.push_back(ClipperLib::IntPoint(0, rect.size.height * PRECISION));
	cl.AddPath(clamp, ClipperLib::ptClip, true);
	cl.Execute(ClipperLib::ctIntersection, out);

	Vector<Vector2> outPoints;
	ClipperLib::PolyNode *p2 = out.GetFirst();
	ERR_FAIL_COND_V(!p2, points);

	while (p2->IsHole()) {
		p2 = p2->GetNext();
	}

	int lasti = p2->Contour.size() - 1;
	Vector2 prev = Vector2(p2->Contour[lasti].X / PRECISION, p2->Contour[lasti].Y / PRECISION);
	for (unsigned int i = 0; i < p2->Contour.size(); i++) {

		Vector2 cur = Vector2(p2->Contour[i].X / PRECISION, p2->Contour[i].Y / PRECISION);
		if (cur.distance_to(prev) > 0.5) {
			outPoints.push_back(cur);
			prev = cur;
		}
	}
	return outPoints;
}
Esempio n. 2
0
std::vector<Vec2> AutoPolygon::expand(const std::vector<Vec2>& points, const cocos2d::Rect &rect, const float& epsilon)
{
    auto size = points.size();
    // if there are less than 3 points, then we have nothing
    if(size<3)
    {
        log("AUTOPOLYGON: cannot expand points for %s with less than 3 points, e: %f", _filename.c_str(), epsilon);
        return std::vector<Vec2>();
    }
    ClipperLib::Path subj;
    ClipperLib::PolyTree solution;
    ClipperLib::PolyTree out;
    for(std::vector<Vec2>::const_iterator it = points.begin(); it<points.end(); it++)
    {
        subj << ClipperLib::IntPoint(it-> x* PRECISION, it->y * PRECISION);
    }
    ClipperLib::ClipperOffset co;
    co.AddPath(subj, ClipperLib::jtMiter, ClipperLib::etClosedPolygon);
    co.Execute(solution, epsilon * PRECISION);
    
    ClipperLib::PolyNode* p = solution.GetFirst();
    if(!p)
    {
        log("AUTOPOLYGON: Clipper failed to expand the points");
        return points;
    }
    while(p->IsHole()){
        p = p->GetNext();
    }

    //turn the result into simply polygon (AKA, fix overlap)
    
    //clamp into the specified rect
    ClipperLib::Clipper cl;
    cl.StrictlySimple(true);
    cl.AddPath(p->Contour, ClipperLib::ptSubject, true);
    //create the clipping rect
    ClipperLib::Path clamp;
    clamp.push_back(ClipperLib::IntPoint(0, 0));
    clamp.push_back(ClipperLib::IntPoint(rect.size.width/_scaleFactor * PRECISION, 0));
    clamp.push_back(ClipperLib::IntPoint(rect.size.width/_scaleFactor * PRECISION, rect.size.height/_scaleFactor * PRECISION));
    clamp.push_back(ClipperLib::IntPoint(0, rect.size.height/_scaleFactor * PRECISION));
    cl.AddPath(clamp, ClipperLib::ptClip, true);
    cl.Execute(ClipperLib::ctIntersection, out);
    
    std::vector<Vec2> outPoints;
    ClipperLib::PolyNode* p2 = out.GetFirst();
    while(p2->IsHole()){
        p2 = p2->GetNext();
    }
    auto end = p2->Contour.end();
    for(std::vector<ClipperLib::IntPoint>::const_iterator pt = p2->Contour.begin(); pt < end; pt++)
    {
        outPoints.push_back(Vec2(pt->X/PRECISION, pt->Y/PRECISION));
    }
    return outPoints;
}
    void build(utymap::meshing::Polygon& polygon)
    {
        ClipperLib::ClipperOffset offset;
        ClipperLib::Path path;
        path.reserve(polygon.points.size() / 2);

        auto lastPointIndex = polygon.points.size() - 2;
        double min = std::numeric_limits<double>::max();
        for (std::size_t i = 0; i < polygon.points.size(); i += 2) {
            auto nextIndex = i == lastPointIndex ? 0 : i + 2;

            utymap::meshing::Vector2 v1(polygon.points[i], polygon.points[i + 1]);
            utymap::meshing::Vector2 v2(polygon.points[nextIndex], polygon.points[nextIndex + 1]);

            min = std::min(min, utymap::meshing::Vector2::distance(v1, v2));

            path.push_back(ClipperLib::IntPoint(static_cast<ClipperLib::cInt>(v1.x * Scale), 
                                                static_cast<ClipperLib::cInt>(v1.y * Scale)));
        }

        offset.AddPath(path, ClipperLib::JoinType::jtMiter, ClipperLib::EndType::etClosedPolygon);

        ClipperLib::Paths solution;
        // NOTE: use minimal side value as reference for offsetting.
        offset.Execute(solution, -(min / 10) * Scale);

        // NOTE: this is unexpected result for algorithm below, fallback to flat roof.
        if (solution.size() != 1 || solution[0].size() != path.size()) {
            return FlatRoofBuilder::build(polygon);
        }

        buildMansardShape(polygon, solution[0], findFirstIndex(solution[0][0], polygon));
    }
Esempio n. 4
0
void BooleanTool::pathObjectToPolygons(
        const PathObject* object,
        ClipperLib::Paths& polygons,
        PolyMap& polymap)
{
	object->update();
	
	polygons.reserve(polygons.size() + object->parts().size());
	
	for (const auto& part : object->parts())
	{
		const PathCoordVector& path_coords = part.path_coords;
		auto path_coords_end = path_coords.size();
		if (part.isClosed())
			--path_coords_end;
		
		ClipperLib::Path polygon;
		for (auto i = 0u; i < path_coords_end; ++i)
		{
			auto point = MapCoord { path_coords[i].pos };
			polygon.push_back(ClipperLib::IntPoint(point.nativeX(), point.nativeY()));
			polymap.insertMulti(polygon.back(), std::make_pair(&part, &path_coords[i]));
		}
		
		bool orientation = Orientation(polygon);
		if ( (&part == &object->parts().front()) != orientation )
		{
			std::reverse(polygon.begin(), polygon.end());
		}
		
		// Push_back shall move the polygon.
		static_assert(std::is_nothrow_move_constructible<ClipperLib::Path>::value, "ClipperLib::Path must be nothrow move constructible");
		polygons.push_back(polygon);
	}
}
Esempio n. 5
0
void
Slic3rMultiPoint_to_ClipperPath(const Slic3r::MultiPoint &input, ClipperLib::Path &output)
{
    output.clear();
    for (Slic3r::Points::const_iterator pit = input.points.begin(); pit != input.points.end(); ++pit) {
        output.push_back(ClipperLib::IntPoint( (*pit).x, (*pit).y ));
    }
}
Esempio n. 6
0
ClipperLib::Path
Slic3rMultiPoint_to_ClipperPath(const MultiPoint &input)
{
    ClipperLib::Path retval;
    for (Points::const_iterator pit = input.points.begin(); pit != input.points.end(); ++pit)
        retval.push_back(ClipperLib::IntPoint( (*pit).x, (*pit).y ));
    return retval;
}
ClipperLib::Path ElementGeometryClipper::createPathFromBoundingBox()
{
    double xMin = quadKeyBbox_.minPoint.longitude, yMin = quadKeyBbox_.minPoint.latitude,
            xMax = quadKeyBbox_.maxPoint.longitude, yMax = quadKeyBbox_.maxPoint.latitude;
    ClipperLib::Path rect;
    rect.push_back(ClipperLib::IntPoint(static_cast<ClipperLib::cInt>(xMin*Scale), 
                                        static_cast<ClipperLib::cInt>(yMin*Scale)));

    rect.push_back(ClipperLib::IntPoint(static_cast<ClipperLib::cInt>(xMax*Scale), 
                                        static_cast<ClipperLib::cInt>(yMin*Scale)));

    rect.push_back(ClipperLib::IntPoint(static_cast<ClipperLib::cInt>(xMax*Scale), 
                                        static_cast<ClipperLib::cInt>(yMax*Scale)));

    rect.push_back(ClipperLib::IntPoint(static_cast<ClipperLib::cInt>(xMin*Scale),
                                        static_cast<ClipperLib::cInt>(yMax*Scale)));
    return std::move(rect);
}
Esempio n. 8
0
ClipperLib::Path polygon::path(base_int denom) const
{
	ClipperLib::Path ret;
	for(auto v : this->vertexes)
	{
		ret.push_back(ClipperLib::IntPoint((ClipperLib::cInt)(v.x.numerator() * (denom / v.x.denominator())), (ClipperLib::cInt)(v.y.numerator() * (denom / v.y.denominator()))));
	}
	return ret;
}
Esempio n. 9
0
ClipperLib::Path Clipper::toClipper(const ofPolyline& polyline,
                                    ClipperLib::cInt scale)
{
    ClipperLib::Path path;

    for (auto& vertex: polyline.getVertices())
    {
        path.push_back(toClipper(vertex, scale));
    }

    return path;
}
geo::Polygon<geo::Ring<Vector>> Environment::subtract(geo::Polygon<geo::Ring<Vector>> const& poly, geo::Ring<Vector> const& ring) {
	
	ClipperLib::Path subj;
  	ClipperLib::Paths solution;
  	
  	ClipperLib::Clipper c;
	
  	for (Vector const& v : poly.ering)
  		subj.push_back(ClipperLib::IntPoint((int)v.x, (int)v.y));
  	c.AddPath(subj, ClipperLib::ptSubject, true);

  	for (Ring const& ring : poly.irings) {
		subj.clear();
		for (Vector const& v : ring)
  			subj.push_back(ClipperLib::IntPoint((int)v.x, (int)v.y));
  	   	std::reverse(subj.begin(), subj.end());
  		c.AddPath(subj, ClipperLib::ptSubject, true);
  	}
	
	subj.clear();
  	for (Vector const& v : ring)
  		subj.push_back(ClipperLib::IntPoint((int)v.x, (int)v.y));
  	c.AddPath(subj, ClipperLib::ptClip, true);

    c.Execute(ClipperLib::ctDifference, solution);
    geo::Polygon<geo::Ring<Vector>> ans;
    for (ClipperLib::IntPoint const& pt : solution[0]) {
    	ans.ering.push_back({pt.X, pt.Y});
    }
    for (int i = 1; i < solution.size(); ++i) {
    	ClipperLib::Path const& path = solution[i];
    	geo::Ring<Vector> ring;
    	for (ClipperLib::IntPoint const& pt : path)
    		ring.push_back({pt.X, pt.Y});
    	ans.irings.push_back(ring);
    }
    geo::correct(ans);
	return ans;

}
Esempio n. 11
0
// Set the objects (defined by contour points) to be models in the world and scene.
void World::setObjectsToBeModeled(const std::vector<std::vector<cv::Point>> contours) {

    int contourSize = (int)contours.size();
    for(int i = 0; i < contourSize; i++ )
    {
        std::vector<cv::Point> currentShape = contours[i];
        int numOfPoints = (int)currentShape.size();

        b2Vec2 * vertices = new b2Vec2[numOfPoints];
        ClipperLib::Paths* polygons = new ClipperLib::Paths();
        ClipperLib::Path polygon;

        for (int j = 0; j < numOfPoints; j++)
        {
            vertices[j].x = currentShape[j].x / PTM_RATIO;
            vertices[j].y = currentShape[j].y / PTM_RATIO;

            //cv::line(m_scene, currentShape[j], currentShape[(j + 1) % numOfPoints], cv::Scalar(0,0,255));
            //std::cout << "[" << vertices[j].x << "," <<vertices[j].y << "]" << std::endl;

            polygon.push_back(ClipperLib::IntPoint(currentShape[j].x, currentShape[j].y));
        }

        b2BodyDef objectBodyDef;
        objectBodyDef.type = b2_staticBody;

        b2Body *objectBody = m_world->CreateBody(&objectBodyDef);
        objectBody->SetUserData(polygons);

        polygons->push_back(polygon);

        b2EdgeShape objectEdgeShape;
        b2FixtureDef objectShapeDef;
        objectShapeDef.shape = &objectEdgeShape;

        for (int j = 0; j < numOfPoints - 1; j++)
        {
            objectEdgeShape.Set(vertices[j], vertices[j+1]);
            objectBody->CreateFixture(&objectShapeDef);
        }

        objectEdgeShape.Set(vertices[numOfPoints - 1], vertices[0]);
        objectBody->CreateFixture(&objectShapeDef);
        m_objectBodies.push_back(objectBody);
        delete[] vertices;
    }
}
Esempio n. 12
0
	ClipperLib::Path pathToClipperPath(const panda::types::Path& path)
	{
		ClipperLib::Path out;
		auto maxVal = std::numeric_limits<ClipperLib::cInt>::max();
		ClipperLib::IntPoint prevPt(maxVal, maxVal);
		for (const auto& pt : path.points)
		{
			auto newPt = convert(pt);
			if (newPt == prevPt)
				continue;
			out.push_back(newPt);
			prevPt = newPt;
		}

		if (path.points.size() > 1 && path.points.back() == path.points.front())
			out.pop_back();
		return out;
	}
Esempio n. 13
0
void World::update(cv::Mat &homography)
{
    this->m_world->Step(dt, 10, 10);

    //check contacts
    std::vector<MyContact>::iterator pos;
    std::map<b2Body*, ClipperLib::Paths*> newBodyMap;
    std::vector<b2Body*> removeBarrierList;

    for(pos = this->m_contactListener->m_contacts.begin();
        pos != this->m_contactListener->m_contacts.end();
        ++pos)
    {
        MyContact contact = *pos;

        if ((contact.fixtureA == this->m_ballFixture || contact.fixtureB == this->m_ballFixture) 
            && (contact.fixtureA->GetBody() != m_groundBody && contact.fixtureB->GetBody() != m_groundBody)
            && (contact.fixtureA->GetBody() != m_paddlesBody && contact.fixtureB->GetBody() != m_paddlesBody))
        {
            b2Fixture* objectFixture = contact.fixtureA == this->m_ballFixture ? contact.fixtureB : contact.fixtureA;
            b2Body *objectBody = objectFixture->GetBody();

            if (objectFixture->GetType() == b2Shape::e_edge)
            {
                cv::Point2f hitPoint = CVUtils::transformPoint(cv::Point2f(contact.contactPoint->x * PTM_RATIO, contact.contactPoint->y * PTM_RATIO), homography);
                this->notifyBallHitObservers(hitPoint.x, hitPoint.y);

                // change the shape of the fixture
                // only go into processing if this body was not processed yet (possible ball hit two fixture of same body)
                if (newBodyMap.find(objectBody) == newBodyMap.end())
                {
                    ClipperLib::Paths* bodyPolygons = (ClipperLib::Paths*)objectBody->GetUserData();

                    b2Vec2* impactVelocity = contact.fixtureA == m_ballFixture ? contact.impactVelocityA : contact.impactVelocityB;
                    float ballAngle = atan2(impactVelocity->y, impactVelocity->x); // get the angle (in radians) the ball is moving to
                    float ballPower = impactVelocity->Length() * 0.5;    // get the "power" of the ball movement vector
                    float openingStepInRadians = 10 * CV_PI / 180;  // calculate the opening in radians

                    // create the clipping object/shape - a wedge from ball's center with 30 degree opening over ball direction (angle)
                    ClipperLib::Path clip;
                    clip.push_back(ClipperLib::IntPoint(contact.contactPoint->x * PTM_RATIO, contact.contactPoint->y * PTM_RATIO));

                    for(int step = 9; step > -10; step--)
                    {
                        float dx = cos(ballAngle + step * openingStepInRadians) * ballPower;
                        float dy = sin(ballAngle + step * openingStepInRadians) * ballPower;

                        clip.push_back(ClipperLib::IntPoint(contact.contactPoint->x * PTM_RATIO + dx, contact.contactPoint->y * PTM_RATIO + dy));
                    }

                    ClipperLib::Clipper clipper;
                    clipper.AddPaths((*bodyPolygons), ClipperLib::ptSubject, true);
                    clipper.AddPath(clip, ClipperLib::ptClip, true);

                    // the difference is the new polygon formed by the clipping (collision)
                    ClipperLib::Paths* newPolygons = new ClipperLib::Paths();
                    clipper.Execute(ClipperLib::ctDifference, (*newPolygons), ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd);

                    // Save the new polygons of this body
                    objectBody->SetUserData(newPolygons);
                    newBodyMap[objectBody] = newPolygons;

                    // now, find the intersection regions - these should be inpainted to the scene
                    ClipperLib::Paths destroyedParts;
                    clipper.Execute(ClipperLib::ctIntersection, destroyedParts, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd);

                    // paint the required areas to be coppied
                    for (size_t i = 0; i < destroyedParts.size(); i++)
                    {
                        cv::Point* points = new cv::Point[destroyedParts[i].size()];

                        for (size_t j = 0; j < destroyedParts[i].size(); j++)
                        {
                            points[j].x = (int)destroyedParts[i][j].X;
                            points[j].y = (int)destroyedParts[i][j].Y;
                        }

                        m_destroyedPolygons.push_back(points);
                        m_destroyedPolygonsPointCount.push_back((int)destroyedParts[i].size());
                    }
                }
            }
            else if (objectFixture->GetType() == b2Shape::e_circle)
            {
                // this is a barrier - add it to the remove list
                removeBarrierList.push_back(objectBody);
            }
        }
    }

    std::map<b2Body*, ClipperLib::Paths*>::iterator iter;

    for(iter = newBodyMap.begin(); iter != newBodyMap.end(); iter++)
    {
        b2Body* objectBody = iter->first;
        ClipperLib::Paths* newPolygons = iter->second;

        // remove all the current fixtures from this body
        for (b2Fixture* f = objectBody->GetFixtureList(); f; )
        {
            b2Fixture* fixtureToDestroy = f;
            f = f->GetNext();
            objectBody->DestroyFixture( fixtureToDestroy );
        }

        if(newPolygons->size() == 0)
        {
            // there is no more pieces of the object left so remove it from list and world
            m_objectBodies.erase(std::find(m_objectBodies.begin(), m_objectBodies.end(), objectBody));
            m_world->DestroyBody(objectBody);   // TODO: better physics world cleanup
        }
        else
        {
            for (size_t i = 0; i < newPolygons->size(); i++)
            {
                b2EdgeShape objectEdgeShape;
                b2FixtureDef objectShapeDef;
                objectShapeDef.shape = &objectEdgeShape;

                ClipperLib::Path polygon = newPolygons->at(i);
                size_t j;
                for (j = 0; j < polygon.size() - 1; j++)
                {
                    objectEdgeShape.Set(b2Vec2(polygon[j].X / PTM_RATIO, polygon[j].Y / PTM_RATIO), b2Vec2(polygon[j+1].X / PTM_RATIO, polygon[j+1].Y / PTM_RATIO));
                    objectBody->CreateFixture(&objectShapeDef);
                }

                objectEdgeShape.Set(b2Vec2(polygon[j].X / PTM_RATIO, polygon[j].Y / PTM_RATIO), b2Vec2(polygon[0].X / PTM_RATIO, polygon[0].Y / PTM_RATIO));
                objectBody->CreateFixture(&objectShapeDef);
            }
        }
    }

    for (size_t i = 0; i < removeBarrierList.size(); i++){
        cv::Point2f* p = (cv::Point2f*)removeBarrierList[i]->GetUserData();

        std::vector<cv::Point2f*>::iterator position = std::find(m_guardLocations.begin(), m_guardLocations.end(), p);
        if (position != m_guardLocations.end()){ // == vector.end() means the element was not found
            m_guardLocations.erase(position);
        }

        removeBarrierList[i]->GetWorld()->DestroyBody(removeBarrierList[i]);
    }
}