Skip to content

Commit

Permalink
ellipse inscribed: using intersections to form quadrilateral
Browse files Browse the repository at this point in the history
  • Loading branch information
Dongxu Li committed Mar 17, 2015
1 parent b52e6c7 commit afa201c
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 54 deletions.
71 changes: 17 additions & 54 deletions librecad/src/lib/engine/rs_ellipse.cpp
Expand Up @@ -730,62 +730,25 @@ bool RS_Ellipse::createFromQuadratic(const QVector<double>& dn){
bool RS_Ellipse::createInscribeQuadrilateral(const std::vector<RS_Line*>& lines)
{
if(lines.size() != 4) return false; //only do 4 lines
RS_EntityContainer container(NULL, false);
QVector<RS_Line*> quad;
for(RS_Line* p: lines){//copy the line pointers
if(p->getLength()<RS_TOLERANCE) return false;
quad.push_back(p);
container.addEntity(p);
}
// std::cout<<"0\n";
for(size_t i=0;i<lines.size()*2;i++){//move parallel lines to opposite
size_t j=(i+1)%lines.size();

// std::cout<<"("<<i<<","<<j<<")\n";
// std::cout<<*quad[i]<<std::endl;
// std::cout<<*quad[j]<<std::endl;
RS_VectorSolutions sol=RS_Information::getIntersectionLineLine(quad[i%lines.size()],quad[j]);
if(sol.getNumber()==0) {
std::swap( quad[j],quad[ (i+2)%lines.size()]); //move to oppose
++i;
}
}
// std::cout<<"========1========\n";
RS_EntityContainer container(NULL, true);
QVector<RS_Line*> quad;
{ //form quadrilateral from intersections
RS_EntityContainer c0(NULL, false);
for(RS_Line*const p: lines){//copy the line pointers
c0.addEntity(p);
}
RS_VectorSolutions s0=RS_Information::createQuadrilateral(c0);
if(s0.size()!=4) return false;
for(size_t i=0; i<4; ++i){
RS_Line*const pl=new RS_Line(&container, RS_LineData(s0[i], s0[(i+1)%4]));
quad.push_back(pl);
container.addEntity(pl);
}
}

QVector<RS_Line> ip;
for(int i=1;i<4;++i){//find intersections
//(0,i)
// std::cout<<"(0,"<<i<<")\n";
RS_VectorSolutions sol0=RS_Information::getIntersectionLineLine(quad[0],quad[i]);
if(sol0.getNumber()==0) continue;
int l(1);
if( l==i) ++l;
int m(l+1);
if( m==i) ++m;
// lines in two pairs: (0, i) and (l,m)
// std::cout<<"(0,"<<i<<"):("<<l<<","<<m<<")\n";
RS_VectorSolutions sol1=RS_Information::getIntersectionLineLine(quad[l],quad[m]);
if(sol1.getNumber()==0) continue;

ip.push_back(RS_Line(sol0.get(0),sol1.get(0)));

}

// std::cout<<"20 ip.size()="<<ip.size()<<"\n";
if(ip.size()<2) return false; //not enough connecting lines, so, no quadrilateral defined
// std::cout<<"22\n";
if(ip.size() == 3) {//find intersecting pair
// RS_VectorSolutions sol0=RS_Information::getIntersection(line0,line1,true);
RS_VectorSolutions sol1=RS_Information::getIntersection(&ip[2],&ip[1],true);
if(sol1.getNumber()) {
ip[0]=ip[2];
}else{
sol1=RS_Information::getIntersection(& ip[2],&ip[0],true);
if(sol1.getNumber()) {
ip[1]=ip[2];
}
}
}
ip.push_back(RS_Line(NULL, RS_LineData(quad[0]->getStartpoint(), quad[1]->getEndpoint())));
ip.push_back(RS_Line(NULL, RS_LineData(quad[1]->getStartpoint(), quad[2]->getEndpoint())));
RS_VectorSolutions sol=RS_Information::getIntersectionLineLine( & ip[0],& ip[1]);
if(sol.getNumber()==0) {//this should not happen
// RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Ellipse::createInscribeQuadrilateral(): can not locate projection Center");
Expand Down
76 changes: 76 additions & 0 deletions librecad/src/lib/information/rs_information.cpp
Expand Up @@ -25,6 +25,8 @@
**
**********************************************************************/

#include <vector>
#include <utility>
#include "rs_information.h"

#include "rs_arc.h"
Expand Down Expand Up @@ -921,3 +923,77 @@ bool RS_Information::isPointInsideContour(const RS_Vector& point,
return ((counter%2)==1);
}


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 (RS_Entity* e=c.firstEntity(RS2::ResolveNone);
e!=NULL;
e=c.nextEntity(RS2::ResolveNone)) {
if(e->rtti()!=RS2::EntityLine) return ret;
lines.push_back(static_cast<RS_Line*>(e));
}
if(lines.size()!=4) return ret;

//neigbours;
std::vector<RS_Vector> vertices;
for(unsigned i=0; i<3; ++i){
for(unsigned j=i+1; j<4; ++j){
RS_VectorSolutions&& sol=RS_Information::getIntersectionLineLine(lines[i], lines[j]);
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&& 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;
}

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;
}
1 change: 1 addition & 0 deletions librecad/src/lib/information/rs_information.h
Expand Up @@ -83,6 +83,7 @@ class RS_Information {

static RS_VectorSolutions getIntersectionEllipseLine(RS_Line* line,
RS_Ellipse* ellipse);
static RS_VectorSolutions createQuadrilateral(const RS_EntityContainer& container);

static bool isPointInsideContour(const RS_Vector& point,
RS_EntityContainer* contour,
Expand Down

0 comments on commit afa201c

Please sign in to comment.