void CenterSystem::update(float delta){ for(int iterator = 0; iterator < numEntities(); iterator++){ Entity *ent = entityAt(iterator); if(ent->hasComponent(COMPONENT_POSITION) && ent->hasComponent(COMPONENT_CENTER)){ Center *c = static_cast<Center*>(ent->getComponent(COMPONENT_CENTER)); Position *pos = static_cast<Position*>(ent->getComponent(COMPONENT_POSITION)); if(c->getHorizontal()) pos->setX(width/2); if(c->getVertical()) pos->setY(height/2); } }; }
/** * this should handle modifyOffset *@ coord, indicate direction of offset *@ distance of offset * *@Author, Dongxu Li */ bool RS_Polyline::offset(const RS_Vector& coord, const double& distance){ double dist; //find the nearest one int length=count(); std::vector<RS_Vector> intersections(length); if(length>1){//sort the polyline entity start/end point order int i(0); double d0,d1; RS_Entity* en0(entityAt(0)); RS_Entity* en1(entityAt(1)); RS_Vector vStart(en0->getStartpoint()); RS_Vector vEnd(en0->getEndpoint()); en1->getNearestEndpoint(vStart,&d0); en1->getNearestEndpoint(vEnd,&d1); if(d0<d1) en0->revertDirection(); for(i=1;i<length;en0=en1){ //linked to head-tail chain en1=entityAt(i); vStart=en1->getStartpoint(); vEnd=en1->getEndpoint(); en0->getNearestEndpoint(vStart,&d0); en0->getNearestEndpoint(vEnd,&d1); if(d0>d1) en1->revertDirection(); intersections[i-1]=(en0->getEndpoint()+en1->getStartpoint())*0.5; i++; } } RS_Entity* en(getNearestEntity(coord, &dist, RS2::ResolveNone)); if(en==NULL) return false; int indexNearest=findEntity(en); // RS_Vector vp(en->getNearestPointOnEntity(coord,false)); // RS_Vector direction(en->getTangentDirection(vp)); // RS_Vector vp1(-direction.y,direction.x);//normal direction // double a2(vp1.squared()); // if(a2<RS_TOLERANCE2) return false; // vp1 *= distance/sqrt(a2); // move(vp1); // return true; RS_Polyline* pnew= static_cast<RS_Polyline*>(clone()); int i; i=indexNearest; int previousIndex(i); pnew->entityAt(i)->offset(coord,distance); RS_Vector vp; //offset all //fixme, this is too ugly for(i=indexNearest-1;i>=0;i--){ RS_VectorSolutions sol0=RS_Information::getIntersection(pnew->entityAt(previousIndex),entityAt(i),true); // RS_VectorSolutions sol1; double dmax(RS_TOLERANCE15); RS_Vector trimP(false); for(const RS_Vector& vp: sol0){ double d0( (vp - pnew->entityAt(previousIndex)->getStartpoint()).squared());//potential bug, need to trim better if(d0>dmax) { dmax=d0; trimP=vp; } } if(trimP.valid){ static_cast<RS_AtomicEntity*>(pnew->entityAt(previousIndex))->trimStartpoint(trimP); static_cast<RS_AtomicEntity*>(pnew->entityAt(i))->trimEndpoint(trimP); vp=pnew->entityAt(previousIndex)->getMiddlePoint(); }else{ vp=pnew->entityAt(previousIndex)->getStartpoint(); vp.rotate(entityAt(previousIndex)->getStartpoint(),entityAt(i)->getDirection2()-entityAt(previousIndex)->getDirection1()+M_PI); } pnew->entityAt(i)->offset(vp,distance); previousIndex=i; } previousIndex=indexNearest; for(i=indexNearest+1;i<length;i++){ RS_VectorSolutions sol0=RS_Information::getIntersection(pnew->entityAt(previousIndex),entityAt(i),true); // RS_VectorSolutions sol1; double dmax(RS_TOLERANCE15); RS_Vector trimP(false); for(const RS_Vector& vp: sol0){ double d0( (vp - pnew->entityAt(previousIndex)->getEndpoint()).squared());//potential bug, need to trim better if(d0>dmax) { dmax=d0; trimP=vp; } } if(trimP.valid){ static_cast<RS_AtomicEntity*>(pnew->entityAt(previousIndex))->trimEndpoint(trimP); static_cast<RS_AtomicEntity*>(pnew->entityAt(i))->trimStartpoint(trimP); vp=pnew->entityAt(previousIndex)->getMiddlePoint(); }else{ vp=pnew->entityAt(previousIndex)->getEndpoint(); vp.rotate(entityAt(previousIndex)->getEndpoint(),entityAt(i)->getDirection1()-entityAt(previousIndex)->getDirection2()+M_PI); } pnew->entityAt(i)->offset(vp,distance); previousIndex=i; } //trim //connect and trim RS_Modification m(*container, graphicView); for(i=0;i<length-1;i++){ RS_VectorSolutions sol0=RS_Information::getIntersection(pnew->entityAt(i),pnew->entityAt(i+1),true); if(sol0.getNumber()==0) { sol0=RS_Information::getIntersection(pnew->entityAt(i),pnew->entityAt(i+1)); // RS_Vector vp0(pnew->entityAt(i)->getEndpoint()); // RS_Vector vp1(pnew->entityAt(i+1)->getStartpoint()); // double a0(intersections.at(i).angleTo(vp0)); // double a1(intersections.at(i).angleTo(vp1)); RS_VectorSolutions sol1; for(const RS_Vector& vp: sol0){ if(RS_Math::isAngleBetween(intersections.at(i).angleTo(vp), pnew->entityAt(i)->getDirection2(), pnew->entityAt(i+1)->getDirection1(), false)==false){ sol1.push_back(vp); } } if(sol1.getNumber()==0) continue; RS_Vector trimP(sol1.getClosest(intersections.at(i))); static_cast<RS_AtomicEntity*>(pnew->entityAt(i))->trimEndpoint(trimP); static_cast<RS_AtomicEntity*>(pnew->entityAt(i+1))->trimStartpoint(trimP); }else{ RS_Vector trimP(sol0.getClosest(pnew->entityAt(i)->getStartpoint())); static_cast<RS_AtomicEntity*>(pnew->entityAt(i))->trimEndpoint(trimP); static_cast<RS_AtomicEntity*>(pnew->entityAt(i+1))->trimStartpoint(trimP); } } *this = *pnew; 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; }
/** * 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 */ bool RS_EntityContainer::optimizeContours() { RS_DEBUG->print("RS_EntityContainer::optimizeContours"); RS_Vector current(false); RS_Vector start(false); RS_EntityContainer tmp; bool changed = false; bool closed = true; for (uint ci=0; ci<count(); ++ci) { RS_Entity* e1=entityAt(ci); if (e1!=NULL && e1->isEdge() && !e1->isContainer() && !e1->isProcessed()) { RS_AtomicEntity* ce = (RS_AtomicEntity*)e1; // next contour start: ce->setProcessed(true); tmp.addEntity(ce->clone()); current = ce->getEndpoint(); start = ce->getStartpoint(); // find all connected entities: bool done; do { done = true; for (uint ei=0; ei<count(); ++ei) { RS_Entity* e2=entityAt(ei); if (e2!=NULL && e2->isEdge() && !e2->isContainer() && !e2->isProcessed()) { RS_AtomicEntity* e = (RS_AtomicEntity*)e2; if (e->getStartpoint().distanceTo(current) < 1.0e-4) { e->setProcessed(true); tmp.addEntity(e->clone()); current = e->getEndpoint(); done=false; } else if (e->getEndpoint().distanceTo(current) < 1.0e-4) { e->setProcessed(true); RS_AtomicEntity* cl = (RS_AtomicEntity*)e->clone(); cl->reverse(); tmp.addEntity(cl); current = cl->getEndpoint(); changed = true; done=false; } } } if (!done) { changed = true; } } while (!done); if (current.distanceTo(start)>1.0e-4) { closed = false; } } } // remove all atomic entities: bool done; do { done = true; for (RS_Entity* en=firstEntity(); en!=NULL; en=nextEntity()) { if (!en->isContainer()) { removeEntity(en); done = false; break; } } } while (!done); // add new sorted entities: for (RS_Entity* en=tmp.firstEntity(); en!=NULL; en=tmp.nextEntity()) { en->setProcessed(false); addEntity(en->clone()); } RS_DEBUG->print("RS_EntityContainer::optimizeContours: OK"); return closed; }