Esempio n. 1
0
bool FastLogReader::ReadTextColumns(REF std::wstring16& buffer, REF std::vector<FastLogReader::Seg>& segs, WCHAR separator)
{
	if (IsEof())
		return false;

	buffer.clear();
	segs.clear();

	int pb = 0, pc = 0;
	while (!IsEof())
	{
		WCHAR ch = ReadChar();
		buffer += ch;
		if (ch == separator)
		{
			segs.push_back(Seg(pb, pc - pb));
			pb = pc + 1;
		}
		else if (ch == 10)	// \n
		{
			segs.push_back(Seg(pb, pc - pb));
			return true;
		}
		else if (ch == 13)	// \r, \r\n
		{
			if (PeekByte() == 10)
				ReadByte();
			segs.push_back(Seg(pb, pc - pb));
			return true;
		}
		++pc;
	}
	return true;
}
Esempio n. 2
0
/**--------------------------------------------------------------------------<BR>
C2DPolyArc::GetAreaSigned <BR>
\brief Calculates the area of the shape by first calculating the area of the simple
polygon then adding or subtracting the segments defined by the arcs.
<P>---------------------------------------------------------------------------*/
double C2DPolyBase::GetAreaSigned(void) const
{
	double dArea = 0;

	for (unsigned int i = 0; i < m_Lines.size(); i++)
	{
		dArea += m_Lines[i].GetPointFrom().x  * m_Lines[i].GetPointTo().y - 
				 m_Lines[i].GetPointTo().x * m_Lines[i].GetPointFrom().y;
	}
	dArea = dArea / 2.0;

	for (unsigned int i = 0; i < m_Lines.size(); i++)	
	{
		if (GetLine(i)->GetType() == C2DBase::ArcedLine)
		{
			const C2DArc& Arc = dynamic_cast<const C2DArc&>(   m_Lines[i] );

			C2DSegment Seg( Arc );

			dArea += Seg.GetAreaSigned();
		}
	}
	
	return dArea;
}
Esempio n. 3
0
bool isSegmentInsidePoly (glm::vec2 A, glm::vec2 B, Poly* p) {
	auto contour = p ->getContour ();
	Seg a(A, B);
	std::vector <Seg> segs;
	int n = contour.size();
	for (int i = 1; i < n; i++) {
		segs.push_back (Seg (contour[i-1], contour[i]));
	}
	segs.push_back (Seg (contour[n-1], contour[0]));
	for (auto iter = segs.begin(); iter != segs.end(); iter++) {
		auto report = Seg2Seg (a, *iter);
		if (report.collide)
			return true;
	}
	return false;
}
void plPXPhysicalControllerCore::IHandleResize()
{

    uint32_t collideFlags =
        1<<plSimDefs::kGroupStatic |
        1<<plSimDefs::kGroupAvatarBlocker |
        1<<plSimDefs::kGroupDynamic;
    if(!IsSeeking())
    {
        collideFlags|=(1<<plSimDefs::kGroupExcludeRegion);
    }
    NxScene* myscene = plSimulationMgr::GetInstance()->GetScene(this->fWorldKey);
//  NxShape** response=new NxShape*[2];
    
    NxVec3 center(fLocalPosition.fX,fLocalPosition.fY,fLocalPosition.fZ+fPreferedRadius);
    NxSegment Seg(center,center);
    const NxCapsule newCap(Seg,fPreferedRadius);
    int numintersect =myscene->checkOverlapCapsule(newCap,NX_ALL_SHAPES,collideFlags);
    //with new capsule dimensions check for overlap
    //with objects we would collide with
    
    if(numintersect==0)
    {
        fHeight=fPreferedHeight;
        fRadius=fPreferedRadius;
        fController->setRadius(fRadius);
        fController->setHeight(fHeight);
        
        fNeedsResize=false;
    }

//  delete[] response;
}
Esempio n. 5
0
void main(int argc,String *argv) {
  
  ArgParser a=ArgParser(argc,argv);
  String iname=a.getarg();
  String fname=Sconc("home/joey/images/",iname,".bmp");
  String ename=Sconc("home/joey/images/exp",iname,".bmp");
  a.done();

  randomise();
  
  image=RGBmp::readfile(fname)->getv3ds();
  greyscale=image->applyfn(&V3dtofloat);
  
  greyscale->edgedetection(Map2d<float>::sobel(),&edgemag,&edgeang);
  expected=Map2d<float>::readfile(ename)->scaleto(image->width,image->height)->threshold(0.5);
  
  printf("Starting segmentation...\n");
  Seg seg=Seg(&measureglvariance);
//  Seg seg=Seg(&classifytrain);
//  Map2d<bool> *b=seg.classifytopdown();
  Map2d<bool> *b=seg.classifyneighbours();
//  Map2d<bool> *b=seg.classifywindows();
  // b->scaleto(expected->width,expected->height)->writefile("textseg.bmp");
  
}
Esempio n. 6
0
// Remove box from list 
void LightScreen::removeBox(Box* b){
	if (b == NULL) return;
	// Remove corners 
	lMap.removePoint(b->getCornerTopLeft());
	lMap.removePoint(b->getCornerTopRight());
	lMap.removePoint(b->getCornerBottomLeft());
	lMap.removePoint(b->getCornerBottomRight());

	// Remove walls 
	lMap.removeSeg(Seg(b->getCornerTopLeft(), b->getCornerTopRight()));
	lMap.removeSeg(Seg(b->getCornerTopRight(), b->getCornerBottomRight()));
	lMap.removeSeg(Seg(b->getCornerBottomRight(), b->getCornerBottomLeft()));
	lMap.removeSeg(Seg(b->getCornerBottomLeft(), b->getCornerTopLeft()));

	// Remove box 
	bHand->remove(b);
}
Esempio n. 7
0
vector<Reg> Reg::Concavities() {
    vector<Reg> ret = vector<Reg>();
    vector<Seg> ch = convexhull;
    unsigned int j = 0;

    cerr << "Calculating Concavities Start " << depth++ << "\n";
    cerr << "Hull\n";
    for (unsigned int a = 0; a < ch.size(); a++) {
        cerr << ch[a].ToString() << "\n";
    }
    cerr << "Pol\n";
    for (unsigned int a = 0; a < v.size(); a++) {
        cerr << v[a].ToString() << "\n";
    }

    for (j = 0; j < v.size(); j++) {
        if ((ch[0].x1 == v[j].x1) && (ch[0].y1 == v[j].y1)) {
            break;
        }
    }

    for (unsigned int i = 0; i < ch.size(); i++) {
        if (!(ch[i] == v[j])) {
            cerr << "Found new Concavity: " << depth << "\n";
            Reg r = Reg(this, i);
            unsigned int hpidx;
            if (j == 0) {
                hpidx = v.size() - 1;
            } else {
                hpidx = j - 1;
            }
            r.hullPoint = new Pt(v[hpidx].x1, v[hpidx].x2);
            cerr << "End: " << ch[i].x2 << "/" << ch[i].y2 << "\n";
            do {
                Seg s = Seg(v[j].x2, v[j].y2, v[j].x1, v[j].y1);
                r.AddSeg(s);
                j = (j + 1) % v.size();
            } while ((ch[i].x2 != v[j].x1) || (ch[i].y2 != v[j].y1));
            std::reverse(r.v.begin(), r.v.end());
            r.Close();
            //            r.Print();
            cerr << "End Found new Concavity: " << depth << "\n";
            ret.push_back(r);
        } else {
            j = (j + 1) % v.size();
        }
    }

    cvs = ret;

    cerr << "Found " << cvs.size() << " Concavities\n";

    cerr << "Calculating Concavities End " << --depth << "\n";

    return ret;
}
Esempio n. 8
0
/**--------------------------------------------------------------------------<BR>
C2DPolyArc::GetCentroid <BR>
\brief Calculates the centroid of the shape by calculating the centroid of the simple
polygon then shifting it by the area weighted centroids of the segments defined
by the arcs.
<P>---------------------------------------------------------------------------*/
C2DPoint C2DPolyArc::GetCentroid(void) const
{
	// Find the centroid and area of the straight line polygon.
	C2DPoint Centroid(0, 0);
	C2DPoint pti;
	C2DPoint ptii;
	double dArea = 0;

	for (unsigned int i = 0; i < m_Lines.size(); i++)
	{
		pti = m_Lines[i].GetPointFrom();
		ptii = m_Lines[i].GetPointTo();

		Centroid.x += (pti.x + ptii.x) * (pti.x * ptii.y - ptii.x * pti.y);
		Centroid.y += (pti.y + ptii.y) * (pti.x * ptii.y - ptii.x * pti.y);

		dArea += pti.x * ptii.y - ptii.x * pti.y;
	}
	dArea = dArea / 2.0;

	Centroid.x = Centroid.x / (6.0 * dArea);
	Centroid.y = Centroid.y / (6.0 * dArea);

	std::vector<double> dSegAreas;
	double dTotalArea = dArea;
	std::vector<C2DPoint> SegCentroids;

	for (unsigned int i = 0; i < m_Lines.size(); i++)
	{
		if (m_Lines[i].GetType() == C2DLineBase::ArcedLine)
		{
			C2DSegment Seg( dynamic_cast<const C2DArc&>( m_Lines[i] ) );
			double dSegArea = Seg.GetAreaSigned();
			dTotalArea += dSegArea;
			dSegAreas.push_back( dSegArea );
			SegCentroids.push_back( Seg.GetCentroid() );
		}
	}

	Centroid = Centroid * dArea;

	for (unsigned int i = 0; i < dSegAreas.size(); i++)
	{
		Centroid += SegCentroids[i] * dSegAreas[i];
	}

	Centroid = Centroid / dTotalArea;

	return Centroid;

}
Esempio n. 9
0
// Add new box to list 
void LightScreen::addBox(float x, float y, float width, float height){
	if (height <= 1.0f || width <= 1.0f){
		std::cout << "ERROR: Cannot add box with width or height less than or equal to 1\n";
		return;
	}

	// add box 
	Box* b = bHand->add(x,y,width,height);
	b->setColor(.738f, .535f,.32f,1.0f);

	if (b != NULL){
		// Add corners 
		lMap.addPoint(b->getCornerTopLeft());
		lMap.addPoint(b->getCornerTopRight());
		lMap.addPoint(b->getCornerBottomLeft());
		lMap.addPoint(b->getCornerBottomRight());

		// Add walls 
		lMap.addSeg(Seg(b->getCornerTopLeft(), b->getCornerTopRight()));
		lMap.addSeg(Seg(b->getCornerTopRight(), b->getCornerBottomRight()));
		lMap.addSeg(Seg(b->getCornerBottomRight(), b->getCornerBottomLeft()));
		lMap.addSeg(Seg(b->getCornerBottomLeft(), b->getCornerTopLeft()));
	}
}
Esempio n. 10
0
void Reg::Close() {
    int i = v.size() - 1;
    if ((v[i].x2 != v[0].x1) || (v[i].y2 != v[0].y1)) {

        Seg s = Seg(v[i].x2, v[i].y2, v[0].x1, v[0].y1);
        AddSeg(s);
    }

    v = sortSegs(v);

    cerr << "Dumping Reg\n"
            << ToString()
            << "Dumping Reg End\n";
    ConvexHull();
}
Esempio n. 11
0
void Reg::ConvexHull() {
    cerr << "Calculating Convex Hull Start\n";

    vector<Pt> lt = getPoints();
    std::sort(lt.begin(), lt.end());

    lt[0].angle = -1.0;
    for (unsigned int a = 1; a < lt.size(); a++) {
        lt[a].calcAngle(lt[0]);
    }
    std::sort(lt.begin(), lt.end(), sortAngle);

    vector<Pt> uh = vector<Pt > ();
    uh.push_back(lt[0]);
    uh.push_back(lt[1]);

    for (int a = 2; a < (int) lt.size();) {
        cerr << "List len: " << uh.size() << "\n";
        assert(uh.size() >= 2);
        Pt point1 = uh[uh.size() - 1];
        Pt point2 = uh[uh.size() - 2];
        Pt next = lt[a];

        cerr << "P1: " << point1.ToString()
                << "P2: " << point2.ToString()
                << "Nx: " << next.ToString()
                << "\n";

        if (leftOf(point2, point1, next)) {
            uh.push_back(next);
            a++;
        } else {
            uh.pop_back();
        }
    }

    for (unsigned int i = 0; i < uh.size(); i++) {
        Pt p1 = uh[i];
        Pt p2 = uh[(i + 1) % uh.size()];
        Seg s = Seg(p1.x, p1.y, p2.x, p2.y);
        convexhull.push_back(s);
    }
    //    convexhull = sortSegs(convexhull);

    cerr << "Calculating Convex Hull End\n";
}
Esempio n. 12
0
Reg::Reg(ListExpr le) {
    le = nl->First(le);

    while (nl->ListLength(le) > 1) {
        ListExpr pa = nl->First(le);
        ListExpr pb = nl->First(nl->Rest(le));
        //        cerr << nl->ToString(pa) << " " << nl->ToString(pb) << "\n";
        int p1 = nl->RealValue(nl->First(pa));
        pa = nl->Rest(pa);
        int p2 = nl->RealValue(nl->First(pa));
        pa = nl->Rest(pa);
        int p3 = nl->RealValue(nl->First(pb));
        pb = nl->Rest(pb);
        int p4 = nl->RealValue(nl->First(pb));
        pb = nl->Rest(pb);
        le = nl->Rest(le);

        Seg s = Seg(p1, p2, p3, p4);
        AddSeg(s);
    }

    Close();
}
Esempio n. 13
0
/*
  1.1 Constructs a face from a region-listexpression.

*/
Face::Face(ListExpr tle, bool withHoles) : cur(0), parent(NULL), ishole(false) {
    ListExpr le = nl->First(tle);
    // Construct segments from the points
    while (nl->ListLength(le) > 1) {
        ListExpr pa = nl->First(le);
        ListExpr pb = nl->First(nl->Rest(le));
        double p1 = nl->RealValue(nl->First(pa)) * SCALEIN;
        pa = nl->Rest(pa);
        double p2 = nl->RealValue(nl->First(pa)) * SCALEIN;
        pa = nl->Rest(pa);
        double p3 = nl->RealValue(nl->First(pb)) * SCALEIN;
        pb = nl->Rest(pb);
        double p4 = nl->RealValue(nl->First(pb)) * SCALEIN;
        pb = nl->Rest(pb);
        le = nl->Rest(le);
        Seg s = Seg(Pt(p1, p2), Pt(p3, p4));
        AddSeg(s);
    }
    if (v.size() < 2) {
        // Only one segment yet, this cannot be valid. Return an empty region.
        v.clear();
    }
    Close(); // Close and sort the cycle
    
    // Construct the holes
    while (withHoles && nl->ListLength(tle) > 1) {
        tle = nl->Rest(tle);
        Face hole(tle, false);
        if (hole.v.size() < 3) // Invalid hole
            continue;
        hole.ishole = true;
        holes.push_back(hole);
    }
    
    Check();
}
Esempio n. 14
0
void go() {

  String fname=Sconc(ImageDir,iname,".bmp");
  String ename=Sconc(ImageDir,"exp/",iname,".bmp");
printf("read %s\n",fname);
  orig=RGBmp::readfile(fname);
//  image=orig->scaledby(scale)->getv3ds();
  image=orig->scaletowidth(processwidth)->getv3ds();
  printf("Scanning image %i x %i\n",image->width,image->height);
printf("done\n");
  if (train || test)
    expected=Map2d<float>::readfile(ename)->threshold(0.5)->binscaleto(image->width,image->height);

  greyscale=image->applyfn(&V3dtofloat);

  starttimer();

  greyscale->edgedetection(Map2d<float>::sobel(),&edgemag,&edgeang);

  ghistscale=1.0/(float)windres;
  ghs=new Map2d<GHist *>(image->width*ghistscale,image->height*ghistscale,(GHist *)NULL);
  
  if (train)
    data=List<IOData>(2000);
  
  printf("Starting segmentation...\n");
  Seg seg;
  if (train)
    seg=Seg(&classifytrain);
  else
    seg=Seg(&classifynn);
  

  if (show)
    for (int i=1;i<=nummeasures;i++)
      measmaps.add(new Map2d<float>(image->width,image->height,(float)0));

  if (twopass) {
    pass=1;
    printf("First scan, reading measures...\n");
    Map2d<bool> *b=seg.classifywindows();
    destroy(b);
    normalisedata();
    pausetimer();
    printf("Asking neural network...\n");
printf("A\n");
    for (int i=1;i<=data.len;i++) {
      writetraindata(data.num(i).input,123.456);
      data.p2num(i)->freedom();
    }
    printf("Freeing data\n");
    data.freedom();
printf("B\n");
    addheaderto(&traindata,numtrainexs);
    writelinestofile(&traindata,"question.pat");
    printf("Not freeing traindata strings\n");
//    traindata.freeall();
    printf("Freeing traindata\n");
    traindata.freedom();
    system("./asknn");
    traindata=readlinesfromfile("answer.res");
    unpausetimer();
    currentline=14;
    pass=2;
    printf("Second scan...\n");
  }
  Map2d<bool> *b=seg.classifywindows();

  printf("Time taken: %f seconds.\n",gettimer());

  if (show)
    for (int i=1;i<=nummeasures;i++)
      measmaps.num(i)->writefile(getnextfilename("meas","bmp"));

//  Seg seg=Seg(&measureglvariance);
//  Map2d<bool> *b=seg.classifytopdown();
//  Map2d<bool> *b=seg.classifyneighbours();
//  Map2d<bool> *b=seg.classifywindows();

  b->scaleto(image->width,image->height)->writefile("initseg.bmp");
  
  // Reject small regions
  List< Region * > *l=b->getrealregions();
  b=new Map2d<bool>(b->width,b->height,false);
  for (int i=1;i<=l->len;i++) {
    List<Pixel> *ps=l->num(i)->getlist();
    if (ps->len>=minarea)
      for (int j=1;j<=ps->len;j++)
        b->setpos(ps->num(j),true);
  }
  b->writefile("initb4join.bmp");

  // Perform morphological joining (dilation and erosion)
  b=b->binscaleto(b->width/windres,b->height/windres);
  b=b->expand(morphrad)->contract(2*morphrad)->expand(morphrad);
  // b=b->contract(morphrad)->expand(2*morphrad)->contract(morphrad);
  // b=b->expand(morphrad)->inverse()->expand(morphrad)->inverse();
  b=b->binscaleto(image->width,image->height);
  // b->writefile("initjoined.bmp");
  
  b->writefile("textseg.bmp");
  
  if (test) {
    int correct=0;
    int wrong=0;
    int ctextcorrect=0;
    int cnottextcorrect=0;
    int ctextincorrect=0;
    int cnottextincorrect=0;
    int total=0;
    for (int i=0;i<b->width;i++)
    for (int j=0;j<b->height;j++) {
      total++;
      bool exp=expected->getpos(i*expected->width/b->width,j*expected->height/b->height);
      bool cla=b->getpos(i,j);
      if (exp==cla)
        correct++;
      else
        wrong++;
      if (exp)
        if (cla)
          ctextcorrect++;
        else
          cnottextincorrect++;
      else
        if (cla)
          ctextincorrect++;
        else
          cnottextcorrect++;
    }
    if (fileexists("test.dat")) {
      List<String> ls=readlinesfromfile("test.dat");
      correct+=tofloat(ls.num(1));
      wrong+=tofloat(ls.num(2));
      ctextcorrect+=tofloat(ls.num(3));
      cnottextcorrect+=tofloat(ls.num(4));
      ctextincorrect+=tofloat(ls.num(5));
      cnottextincorrect+=tofloat(ls.num(6));
      total+=tofloat(ls.num(7));
    }
    List<String> ls;
    ls.add(Sformat("%i correctly classified",correct));
    ls.add(Sformat("%i incorrectly classified",wrong));
    ls.add(Sformat("%i correctly classified as text",ctextcorrect));
    ls.add(Sformat("%i correct classified as non-text",cnottextcorrect));
    ls.add(Sformat("%i classified as text when not",ctextincorrect));
    ls.add(Sformat("%i classified as non-text when was text",cnottextincorrect));
    ls.add(Sformat("%i total",total));
    ls.add("");
    int totaltext=ctextcorrect+cnottextincorrect;
    int totalnottext=ctextincorrect+cnottextcorrect;
    ls.add(Sformat("That's %i text in total",totaltext));
    ls.add(Sformat("and %i non-text in total",totalnottext));
    ls.add("");
    ls.add("And in percent:");
    ls.add(Sformat("%f percent correctly classified",100.0*(float)correct/(float)total));
    ls.add(Sformat("%f percent incorrectly classified",100.0*(float)wrong/(float)total));
    ls.add(Sformat("%f percent of text correctly classified as text",100.0*(float)ctextcorrect/(float)totaltext));
    ls.add(Sformat("%f percent of non-text correctly classified as non-text",100.0*(float)cnottextcorrect/(float)totalnottext));
    writelinestofile(ls,"test.dat");
  }
    
}
Esempio n. 15
0
bool Game_Engine::Wall_Prolong(const int &n) {
	assert(n >= 0 && n < this->Current_Game.Players_Ammount && "Trying to prolong tail that does not exist");
	Segment2D < double > Seg(this->Current_Game.Walls[n].Segment.A, this->Current_Game.Players[n].MyCycle.Current_Point);
	return Wall_Modify(n, Wall(Seg, this->Current_Game.Walls[n].Player_Number, this->Current_Game.Walls[n].Wall_Number));
}
Esempio n. 16
0
/*
  1.27 IntegrateHoles is used to integrate all holes of a face into the main
  cycle by creating "bridges". This usually yields an invalid face, it is
  exclusively used to triangulate a face.
 
*/
void Face::IntegrateHoles() {
    vector<Seg> allsegs = v;

    // First, get a list of all segments (inclusively all holes' segments)
    for (unsigned int i = 0; i < holes.size(); i++) {
        allsegs.insert(allsegs.end(), holes[i].v.begin(), holes[i].v.end());
    }

    for (unsigned int h = 0; h < holes.size(); h++) {
        Face hole = holes[h]; // Integrate one hole after another
        if (hole.isEmpty())
            continue;
        unsigned int i = 0, j;
        bool found = false;

        Pt s, e;
        Seg se;
        // Try to find a suitable bridge-segment by creating all segments
        // which connect the hole to the face and testing them for intersection
        // with any other segment
        while (!found && i < v.size()) {
            s = v[i].e;
            j = 0;
            while (!found && j < hole.v.size()) {
                e = hole.v[j].s;
                se = Seg(s, e); // A segment connecting the face to the hole
                bool intersects = false;
                for (unsigned int k = 0; k < allsegs.size(); k++) {
                    if (se.intersects(allsegs[k])) {
                        // We have found an intersection, so this segment is
                        // not our bridge
                        intersects = true;
                        break;
                    }
                }
                Seg tmp = v[(i+1)%v.size()];
                if (leftOf(tmp.s, tmp.e, e) && !intersects) {
                    // No intersection was found, so this is the bridge we use
                    found = true;
                    break;
                }
                j = j + 1;
            }
            if (!found) {
               i = i + 1;
            }
        }
        
        assert(found); // We should always be able to find a bridge

        // Now insert the bridge and the hole into the face-cycle
        vector<Seg> newsegs;
        // First copy the cycle from start to the begin of the bridge
        newsegs.insert(newsegs.end(), v.begin(), v.begin()+i+1);
        newsegs.push_back(Seg(s, e)); // Then add the bridge segment
        unsigned int n = hole.v.size();
        for (unsigned int k = 0; k < n; k++) {
            // Now add the hole-segments clockwise
            Seg ns = hole.v[(n + j - k - 1) % n];
            ns.ChangeDir(); // and change the orientation of each segment
            newsegs.push_back(ns);
        }
        newsegs.push_back(Seg(e, s)); // Bridge back to the original face
        // and add the rest of the original cycle
        newsegs.insert(newsegs.end(), v.begin() + i + 1, v.end());
        v = newsegs;
        // For the next holes we have to test intersection with the newly
        // created bridge, too.
        allsegs.push_back(Seg(s, e));
    }
    

    // All holes were integrated, so clear the list.
    holes.clear();
}
Esempio n. 17
0
/*
 1.10 ConvexHull calculates the convex hull of this face and returns it as a
 new face.
 Corner-points on the convex hull are treated as members of the hull.
 
*/
Face Face::ConvexHull() {
    if (isEmpty())
        return Face();
    // erase the previously calculated hull
    convexhull.erase(convexhull.begin(), convexhull.end());
    vector<Pt> lt = getPoints();

    // Sort the points by the y-axis, begin with the lowest-(leftmost) point
    std::sort(lt.begin(), lt.end());

    // Now calculate the polar coordinates (angle and distance of each point
    // with the lowest-(leftmost) point as origin.
    for (unsigned int a = 1; a < lt.size(); a++) {
        lt[a].calcPolar(lt[0]);
    }
    // Sort the other points by their angle (startpoint lt[0] remains in place)
    std::sort(lt.begin()+1, lt.end(), sortAngle);

    // since we want the corner-points on the hull, too, we need to list the
    // points with the lowest angle in counter-clockwise order. We sorted with
    // descending distance as second criterion, so we need to reverse these.
    // For that reason the points with the highest angle are already in
    // counter-clockwise order.
    std::vector<Pt>::iterator s = lt.begin() + 1, e = s; // Start with the
    // second point and find the last point with the same angle.
    while (s->angle == e->angle)
        e++;
    std::reverse(s, e); // Now reverse these to get the correct order.

    // This is the main part of the Graham scan. Initially, take the first two
    // points and put them on a stack
    vector<Pt> uh = vector<Pt> ();
    uh.push_back(lt[0]);
    uh.push_back(lt[1]);
    for (int a = 2; a < (int) lt.size();) {
        assert(uh.size() >= 2); // If the stack shrinks to 1, something went
                                // ugly wrong.
        // Examine the two points on top of the stack ...
        Pt point1 = uh[uh.size() - 1];
        Pt point2 = uh[uh.size() - 2];
        Pt next = lt[a]; // ... and the next candidate for the hull
        if (leftOf(point2, point1, next)) {
            // If the candidate is left of (or on) the segment made up of the
            // two topmost points on the stack, we assume it is part of the hull
            uh.push_back(next); // and push it on the stack
            a++;
        } else {
            uh.pop_back(); // Otherwise it is right of the hull and the topmost
                           // point is definitively not part of the hull, so
                           // we kick it.
        }
    }

    // Now make a face from the points on the convex hull, which the vector ~uh~
    // now contains in counter-clockwise order.
    for (unsigned int i = 0; i < uh.size(); i++) {
        Pt p1 = uh[i];
        Pt p2 = uh[(i + 1) % uh.size()];
        Seg s = Seg(p1, p2);
        convexhull.push_back(s);
    }

    return Face(convexhull);
}