Example #1
0
/**
 * @retval true the two entities can be trimmed to each other;
 * i.e. they are in a graphic or in the same polyline.
 */
bool RS_Information::isTrimmable(RS_Entity* e1, RS_Entity* e2)
{
  if (e1!=NULL && e2!=NULL)
  {
    if (e1->getParent()!=NULL && e2->getParent()!=NULL)
    {
      if (e1->getParent()->rtti()==RS2::EntityPolyline &&
          e2->getParent()->rtti()==RS2::EntityPolyline &&
          e1->getParent()==e2->getParent())
      {

        // in the same polyline
        RS_EntityContainer* pl = e1->getParent();
        int idx1 = pl->findEntity(e1);
        int idx2 = pl->findEntity(e2);
        RS_DEBUG->print("RS_Information::isTrimmable: "
                        "idx1: %d, idx2: %d", idx1, idx2);
        if (abs(idx1-idx2)==1 || abs(idx1-idx2)==pl->count()-1)
        {
          // directly following entities
          return true;
        }
        else
        {
          // not directly following entities
          return false;
        }
      }
      else if ((e1->getParent()->rtti()==RS2::EntityContainer ||
                e1->getParent()->rtti()==RS2::EntityGraphic ||
                e1->getParent()->rtti()==RS2::EntityBlock) &&
               (e2->getParent()->rtti()==RS2::EntityContainer ||
                e2->getParent()->rtti()==RS2::EntityGraphic ||
                e2->getParent()->rtti()==RS2::EntityBlock))
      {

        // normal entities:
        return true;
      }
    }
    else
    {
      // independent entities with the same parent:
      return (e1->getParent()==e2->getParent());
    }
  }

  return false;
}
Example #2
0
RS_VectorSolutions RS_Information::createQuadrilateral(const RS_EntityContainer& container)
{
	RS_VectorSolutions ret;
	if(container.count()!=4) return ret;
	RS_EntityContainer c(container);
	std::vector<RS_Line*> lines;
	for(auto e: c){
		if(e->rtti()!=RS2::EntityLine) return ret;
		lines.push_back(static_cast<RS_Line*>(e));
	}
	if(lines.size()!=4) return ret;

	//find intersections
	std::vector<RS_Vector> vertices;
	for(auto it=lines.begin()+1; it != lines.end(); ++it){
		for(auto jt=lines.begin(); jt != it; ++jt){
			RS_VectorSolutions const& sol=RS_Information::getIntersectionLineLine(*it, *jt);
			if(sol.size()){
				vertices.push_back(sol.at(0));
			}
		}
	}

//	std::cout<<"vertices.size()="<<vertices.size()<<std::endl;

	switch (vertices.size()){
	default:
		return ret;
	case 4:
		break;
	case 5:
	case 6:
		for(RS_Line* pl: lines){
			const double a0=pl->getDirection1();
			std::vector<std::vector<RS_Vector>::iterator> left;
			std::vector<std::vector<RS_Vector>::iterator> right;
			for(auto it=vertices.begin(); it != vertices.end(); ++it){
				RS_Vector const& dir=*it - pl->getNearestPointOnEntity(*it, false);
				if(dir.squared()<RS_TOLERANCE15) continue;
//				std::cout<<"angle="<<remainder(dir.angle() - a0, 2.*M_PI)<<std::endl;
				if(remainder(dir.angle() - a0, 2.*M_PI) > 0.)
					left.push_back(it);
				else
					right.push_back(it);

				if(left.size()==2 && right.size()==1){
					vertices.erase(right[0]);
					break;
				} else if(left.size()==1 && right.size()==2){
					vertices.erase(left[0]);
					break;
				}
			}
			if(vertices.size()==4) break;
		}
		break;
	}

	//order vertices
	RS_Vector center{0., 0.};
	for(const RS_Vector& vp: vertices)
		center += vp;
	center *= 0.25;
	std::sort(vertices.begin(), vertices.end(), [&center](const RS_Vector& a,
			  const RS_Vector&b)->bool{
		return center.angleTo(a)<center.angleTo(b);
	}
	);
	for(const RS_Vector& vp: vertices){
		ret.push_back(vp);
//		std::cout<<"vp="<<vp<<std::endl;
	}
	return ret;
}
/**
 * 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;
}