Ejemplo n.º 1
0
/**
 * Utility function for convertPolyline
 * Appends in current the vertex from toAdd reversing if reversed is true
 * The first vertex is not added and the last is returned instead of added
 *
 * @retval RS_Vector with the last vertex not inserted
 *
 * @author Rallaz
 */
RS_Vector RS_ActionPolylineSegment::appendPol(RS_Polyline *current, RS_Polyline *toAdd, bool reversed) {

    QList<RS_Entity*> entities;

	for(auto v: *toAdd){
        if (reversed)
            entities.prepend(v);
        else
            entities.append(v);
    }
//bad polyline without vertex
    if (entities.isEmpty())
        return RS_Vector(false);

    double bulge=0.0;
    RS_Entity* e = entities.takeFirst() ;

//First polyline vertex
    if (e->rtti() == RS2::EntityArc) {
        if (reversed)
            current->setNextBulge(((RS_Arc*)e)->getBulge()*-1);
        else
            current->setNextBulge(((RS_Arc*)e)->getBulge());
    }

    while (!entities.isEmpty()) {
         e = entities.takeFirst();
         if (e->rtti()==RS2::EntityArc) {
         if (reversed)
             bulge = ((RS_Arc*)e)->getBulge()*-1;
         else
             bulge = ((RS_Arc*)e)->getBulge();
         } else
             bulge = 0.0;
         if (reversed)
             current->addVertex(e->getEndpoint(),bulge, false);
         else
             current->addVertex(e->getStartpoint(),bulge, false);
    }
    if (reversed)
        return e->getStartpoint();
    else
        return e->getEndpoint();
}
bool RS_ActionPolylineEquidistant::makeContour() {
    if (container==NULL) {
        RS_DEBUG->print("RS_ActionPolylineEquidistant::makeContour: no valid container",
                        RS_Debug::D_WARNING);
        return false;
    }

    RS_Polyline* originalPolyline = (RS_Polyline*)originalEntity;
//create a list of entities to offset without length = 0
    QList<RS_Entity*> entities;
    for (RS_Entity* en=originalPolyline->firstEntity(); en!=NULL; en=originalPolyline->nextEntity()) {
        if (en->getLength() > 1.0e-12)
            entities.append(en);
    }
    if (entities.isEmpty()) {
        return false;
    }
    if (document!=NULL) {
        document->startUndoCycle();
    }
    double neg = 1.0;
    if(bRightSide)
        neg = -1.0;

    // Create new helper entities
    RS_Line line1(NULL, RS_LineData(RS_Vector(true), RS_Vector(true)));//current line
    RS_Line lineFirst(NULL, RS_LineData(RS_Vector(true), RS_Vector(true)));//previous line
    RS_Arc arc1(NULL, RS_ArcData(RS_Vector(true), 0,0,0,false));//current arc
    RS_Arc arcFirst(NULL, RS_ArcData(RS_Vector(true), 0,0,0,false));//previous arc

    for (int num=1; num<=number || (number==0 && num<=1); num++) {
        RS_Polyline* newPolyline = new RS_Polyline(container);
        newPolyline->setLayer(((RS_Polyline*)originalEntity)->getLayer());
        newPolyline->setPen(((RS_Polyline*)originalEntity)->getPen());

        bool first = true;
        bool closed = originalPolyline->isClosed();
        double bulge = 0.0;
        RS_Entity* en;
        RS_Entity* prevEntity = entities.last();
        RS_Entity* currEntity;
        for (int i = 0; i < entities.size(); ++i) {
            en = entities.at(i);
            RS_Vector v(false);
            if (en->rtti()==RS2::EntityArc) {
                currEntity = &arc1;
                calculateOffset(currEntity, en, dist*num*neg);
                bulge = arc1.getBulge();
            } else {
                currEntity = &line1;
                bulge = 0.0;
                calculateOffset(currEntity, en, dist*num*neg);
            }
            if (first) {
                if (closed) {
                    if (prevEntity->rtti()==RS2::EntityArc) {
                        prevEntity = calculateOffset(&arcFirst, prevEntity, dist*num*neg);
                    } else {
                        prevEntity = calculateOffset(&lineFirst, prevEntity, dist*num*neg);
                    }
                    v = calculateIntersection(prevEntity, currEntity);
                }
                if (!v.valid) {
                    v = currEntity->getStartpoint();
                    closed = false;
                } else if (currEntity->rtti()==RS2::EntityArc) {
                    //update bulge
                    arc1.setAngle1(arc1.getCenter().angleTo(v));
                    arc1.calculateEndpoints();
                    bulge = arc1.getBulge();
                }
                first = false;
                if (!prevEntity) break; //prevent crash if not exist offset for prevEntity
            } else {
                v = calculateIntersection(prevEntity, currEntity);
                if (!v.valid) {
                    v= prevEntity->getEndpoint();
                    double dess = currEntity->getStartpoint().distanceTo(prevEntity->getEndpoint());
                    if (dess > 1.0e-12) {
                        newPolyline->addVertex(v, bulge);
                        prevEntity = NULL;
                        break;
                    }
                }
                double startAngle = prevEntity->getStartpoint().angleTo(prevEntity->getEndpoint());
                if (prevEntity->rtti()==RS2::EntityArc) {
                    arcFirst.setAngle2(arcFirst.getCenter().angleTo(v));
                    arcFirst.calculateEndpoints();
                    newPolyline->setNextBulge(arcFirst.getBulge());
                }
                //check if the entity are reverted
                if (abs (prevEntity->getStartpoint().angleTo(prevEntity->getEndpoint())- startAngle) > 0.785) {
                    prevEntity = newPolyline->lastEntity();
                    RS_Vector v0 = calculateIntersection(prevEntity, currEntity);
                    if (prevEntity->rtti()==RS2::EntityArc) {
                        ((RS_Arc*)prevEntity)->setAngle2(arcFirst.getCenter().angleTo(v0));
                        ((RS_Arc*)prevEntity)->calculateEndpoints();
                        newPolyline->setNextBulge( ((RS_Arc*)prevEntity)->getBulge() );
                    } else {
                        ((RS_Line*)prevEntity)->setEndpoint(v0);
                        newPolyline->setNextBulge( 0.0 );
                    }
                    newPolyline->setEndpoint(v0);
                }
                if (currEntity->rtti()==RS2::EntityArc) {
                    arc1.setAngle1(arc1.getCenter().angleTo(v));
                    arc1.calculateEndpoints();
                    bulge = arc1.getBulge();
                } else
                    bulge = 0.0;
            }
            if (prevEntity) {
                newPolyline->addVertex(v, bulge, false);
                if (currEntity->rtti()==RS2::EntityArc) {
                    arcFirst.setData(arc1.getData());
                    arcFirst.calculateEndpoints();
                    prevEntity = &arcFirst;
                } else {
                    lineFirst.setStartpoint(line1.getStartpoint());
                    lineFirst.setEndpoint(line1.getEndpoint());
                    prevEntity = &lineFirst;
                }
            }
        }
        //properly terminated, check closed
        if (prevEntity) {
            if (closed) {
                if (currEntity->rtti()==RS2::EntityArc) {
                    arc1.setAngle2(arc1.getCenter().angleTo(newPolyline->getStartpoint()));
                    arc1.calculateEndpoints();
                    newPolyline->setNextBulge(arc1.getBulge());
                    bulge = arc1.getBulge();
                }
                newPolyline->setClosed(true, bulge);
            } else {
                newPolyline->addVertex(currEntity->getEndpoint(), bulge);
            }
        }
        if (!newPolyline->isEmpty()) {
            container->addEntity(newPolyline);
            document->addUndoable(newPolyline);
        }
    }
    if (document!=NULL) {
        document->endUndoCycle();
    }

    if (graphicView!=NULL) {
        graphicView->redraw();
    }

    return true;
}
/**
 * Rearranges the atomic entities in this container in a way that connected
 * entities are stored in the right order and direction.
 * Non-recoursive. Only affects atomic entities in this container.
 *
 * @retval true all contours were closed
 * @retval false at least one contour is not closed

 * to do: find closed contour by flood-fill
 */
bool RS_EntityContainer::optimizeContours() {
//    std::cout<<"RS_EntityContainer::optimizeContours: begin"<<std::endl;

//    DEBUG_HEADER
//    std::cout<<"loop with count()="<<count()<<std::endl;
    RS_DEBUG->print("RS_EntityContainer::optimizeContours");

    RS_EntityContainer tmp;
    tmp.setAutoUpdateBorders(false);
    bool closed=true;

    /** accept all full circles **/
    QList<RS_Entity*> enList;
	for(auto e1: entities){
        if (!e1->isEdge() || e1->isContainer() ) {
            enList<<e1;
            continue;
        }

        //detect circles and whole ellipses
        switch(e1->rtti()){
        case RS2::EntityEllipse:
			if(static_cast<RS_Ellipse*>(e1)->isEllipticArc())
                continue;
        case RS2::EntityCircle:
            //directly detect circles, bug#3443277
            tmp.addEntity(e1->clone());
            enList<<e1;
        default:
            continue;
        }

    }
    //    std::cout<<"RS_EntityContainer::optimizeContours: 1"<<std::endl;

    /** remove unsupported entities */
    for(RS_Entity* it: enList)
        removeEntity(it);

    /** check and form a closed contour **/
//    std::cout<<"RS_EntityContainer::optimizeContours: 2"<<std::endl;
    /** the first entity **/
	RS_Entity* current(nullptr);
    if(count()>0) {
        current=entityAt(0)->clone();
        tmp.addEntity(current);
        removeEntity(entityAt(0));
    }else {
        if(tmp.count()==0) return false;
    }
//    std::cout<<"RS_EntityContainer::optimizeContours: 3"<<std::endl;
    RS_Vector vpStart;
    RS_Vector vpEnd;
	if(current){
        vpStart=current->getStartpoint();
        vpEnd=current->getEndpoint();
    }
	RS_Entity* next(nullptr);
//    std::cout<<"RS_EntityContainer::optimizeContours: 4"<<std::endl;
    /** connect entities **/
    const QString errMsg=QObject::tr("Hatch failed due to a gap=%1 between (%2, %3) and (%4, %5)");

    while(count()>0){
        double dist(0.);
        RS_Vector&& vpTmp=getNearestEndpoint(vpEnd,&dist,&next);
        if(dist>1e-8) {
            if(vpEnd.squaredTo(vpStart)<1e-8){
                RS_Entity* e2=entityAt(0);
                tmp.addEntity(e2->clone());
                vpStart=e2->getStartpoint();
                vpEnd=e2->getEndpoint();
                removeEntity(e2);
                continue;
            }
            QG_DIALOGFACTORY->commandMessage(errMsg.arg(dist).arg(vpTmp.x).arg(vpTmp.y).arg(vpEnd.x).arg(vpEnd.y));
            closed=false;
        }
		if(next && closed){ 			//workaround if next is nullptr
            next->setProcessed(true);
            RS_Entity* eTmp = next->clone();
            if(vpEnd.squaredTo(eTmp->getStartpoint())>vpEnd.squaredTo(eTmp->getEndpoint()))
                eTmp->revertDirection();
            vpEnd=eTmp->getEndpoint();
            tmp.addEntity(eTmp);
        	removeEntity(next);
		} else { 			//workaround if next is nullptr
//      	    std::cout<<"RS_EntityContainer::optimizeContours: next is nullptr" <<std::endl;

			closed=false;	//workaround if next is nullptr
			break;			//workaround if next is nullptr
		} 					//workaround if next is nullptr
    }
//    DEBUG_HEADER
    if(vpEnd.valid && vpEnd.squaredTo(vpStart)>1e-8) {
        if(closed) QG_DIALOGFACTORY->commandMessage(errMsg.arg(vpEnd.distanceTo(vpStart))
                                         .arg(vpStart.x).arg(vpStart.y).arg(vpEnd.x).arg(vpEnd.y));
        closed=false;
    }
//    std::cout<<"RS_EntityContainer::optimizeContours: 5"<<std::endl;


    // add new sorted entities:
	for(auto en: tmp){
		en->setProcessed(false);
        addEntity(en->clone());
    }
//    std::cout<<"RS_EntityContainer::optimizeContours: 6"<<std::endl;

    RS_DEBUG->print("RS_EntityContainer::optimizeContours: OK");
//    std::cout<<"RS_EntityContainer::optimizeContours: end: count()="<<count()<<std::endl;
//    std::cout<<"RS_EntityContainer::optimizeContours: closed="<<closed<<std::endl;
    return closed;
}