<commit_before>#include "GraphUtil.hpp"
#include "Math.hpp"
#include <algorithm>

sf::ConvexShape Line(const sf::Vector2f &Start, const sf::Vector2f &End, float Thickness, const sf::Color &Color, float Outline, const sf::Color &OutlineColor)
{
    sf::Vector2f Normal(Start.y - End.y, End.x - Start.x);
    float Length = Distance(sf::Vector2f(0.f, 0.f), Normal);
    if (Length != 0.f)
        Normal /= Length;

    Normal *= Thickness / 2;

    sf::ConvexShape Line;

    Line.setPointCount(4);
    Line.setPoint(0, Start - Normal);
    Line.setPoint(1, End - Normal);
    Line.setPoint(2, End + Normal);
    Line.setPoint(3, Start + Normal);
    Line.setFillColor(Color);
    Line.setOutlineThickness(Outline);
    Line.setOutlineColor(OutlineColor);

    return Line;
}

sf::CircleShape Circle(const sf::Vector2f &Center, float Radius, const sf::Color &Color, float Outline, const sf::Color &OutlineColor)
{
    sf::CircleShape Circle;
    Circle.setOrigin(Radius, Radius);
    Circle.setPosition(Center);
    Circle.setRadius(Radius);
    Circle.setFillColor(Color);
    Circle.setOutlineThickness(Outline);
    Circle.setOutlineColor(OutlineColor);
    return Circle;
}

sf::RectangleShape Rectangle(float Left, float Top, float Width, float Height, const sf::Color &Color, float Outline, const sf::Color &OutlineColor)
{
    sf::RectangleShape Rectangle;
    Rectangle.setPosition(Left, Top);
    Rectangle.setSize(sf::Vector2f(Width, Height));
    Rectangle.setFillColor(Color);
    Rectangle.setOutlineThickness(Outline);
    Rectangle.setOutlineColor(OutlineColor);
    return Rectangle;
}

class BottomLeftCompare
{
public:
    bool operator() (const sf::Vector2f &Lhs, const sf::Vector2f &Rhs) const
    {
        if (Lhs.y == Rhs.y)
            return Lhs.x < Rhs.x;
        else
            return Lhs.y > Rhs.y;
    }
} BottomLeftComp;

class AngleCompare
{
public:
    AngleCompare(const sf::Vector2f &NewP) : P(NewP)
    {

    }

    bool operator() (const sf::Vector2f &Lhs, const sf::Vector2f &Rhs) const
    {
        return (-DotProduct(sf::Vector2f(1.f, 0.f), Lhs - P) / Magnitude(Lhs - P)) < (-DotProduct(sf::Vector2f(1.f, 0.f), Rhs - P) / Magnitude(Rhs - P));
    }
private:
    sf::Vector2f P;
};

float CCW(const sf::Vector2f &p1, const sf::Vector2f &p2, const sf::Vector2f &p3)
{
    return CrossProduct(p2 - p1, p3 - p1);
}

sf::ConvexShape ConvexHull(vector<sf::Vector2f> Points)
{
    iter_swap(Points.begin(), min_element(Points.begin(), Points.end(), BottomLeftComp));

    AngleCompare AngleComp(Points.front());
    sort(Points.begin() + 1, Points.end(), AngleComp);

    int m = 0;
    for (unsigned int i = 1; i < Points.size(); i++)
    {
        while (CCW(Points[m == 0 ? Points.size() - 1 : m - 1], Points[m], Points[i]) >= 0.f)
        {
            if (m > 0)
                m--;
            else if (i == Points.size() - 1)
                break;
            else
                i++;
        }

        m++;
        swap(Points[m], Points[i]);
    }

    sf::ConvexShape Shape(m + 1);
    for (unsigned int i = 0; i < Shape.getPointCount(); i++)
        Shape.setPoint(i, Points[i]);

    return Shape;
}

sf::Texture PerlinNoise()
{
    const int Size2 = 1024;
    const float Persistence = 0.5f;

    vector< vector<float> > F(Size2, vector<float>(Size2, 0.f));

    for (int i = 2; i <= 7; i++)
    {
        int Freq = pow(2, i);
        float Amplitude = pow(Persistence, 10 - i);

        int Size = Size2 / Freq;
        vector< vector<sf::Vector2f> > G;
        for (int y = 0; y < Size + 1; y++)
        {
            vector<sf::Vector2f> Row;
            for (int x = 0; x < Size + 1; x++)
                Row.push_back(PolarToRect(sf::Vector2f(1.f, Random(0.f, 360.f))));

            G.push_back(Row);
        }

        for (int y = 0; y < Size2; y++)
        {
            for (int x = 0; x < Size2; x++)
            {
                sf::Vector2f p(x, y);
                p *= float(Size) / Size2;
                sf::Vector2i p0(p);
                sf::Vector2i p1 = p0 + sf::Vector2i(1, 1);

                float s = DotProduct(G[p0.y][p0.x], p - sf::Vector2f(p0));
                float t = DotProduct(G[p0.y][p1.x], p - sf::Vector2f(p1.x, p0.y));
                float u = DotProduct(G[p1.y][p0.x], p - sf::Vector2f(p0.x, p1.y));
                float v = DotProduct(G[p1.y][p1.x], p - sf::Vector2f(p1));

                sf::Vector2f S;
                S.x = 3 * pow(p.x - p0.x, 2) - 2 * pow(p.x - p0.x, 3);
                float a = s + S.x * (t - s);
                float b = u + S.x * (v - u);
                S.y = 3 * pow(p.y - p0.y, 2) - 2 * pow(p.y - p0.y, 3);
                float z = a + S.y * (b - a);

                F[y][x] += z * Amplitude;
            }
        }

    }

    float min, max;
    for (int y = 0; y < Size2; y++)
    {
        for (int x = 0; x < Size2; x++)
        {
            if (y == 0 && x == 0)
                min = max = F[y][x];
            else
            {
                if (F[y][x] < min)
                    min = F[y][x];

                if (F[y][x] > max)
                    max = F[y][x];
            }
        }
    }

    sf::Image Img;
    Img.create(Size2, Size2, sf::Color::Red);
    for (int y = 0; y < Size2; y++)
    {
        for (int x = 0; x < Size2; x++)
        {
            int val = Map(F[y][x], min, max, 128, 255);
            Img.setPixel(x, y, sf::Color(val, val, val));
        }
    }

    sf::Texture Tex;
    Tex.loadFromImage(Img);
    return Tex;
}
<commit_msg>Optimize Perlin noise generation, make it look a bit nicer<commit_after>#include "GraphUtil.hpp"
#include "Math.hpp"
#include <algorithm>

sf::ConvexShape Line(const sf::Vector2f &Start, const sf::Vector2f &End, float Thickness, const sf::Color &Color, float Outline, const sf::Color &OutlineColor)
{
    sf::Vector2f Normal(Start.y - End.y, End.x - Start.x);
    float Length = Distance(sf::Vector2f(0.f, 0.f), Normal);
    if (Length != 0.f)
        Normal /= Length;

    Normal *= Thickness / 2;

    sf::ConvexShape Line;

    Line.setPointCount(4);
    Line.setPoint(0, Start - Normal);
    Line.setPoint(1, End - Normal);
    Line.setPoint(2, End + Normal);
    Line.setPoint(3, Start + Normal);
    Line.setFillColor(Color);
    Line.setOutlineThickness(Outline);
    Line.setOutlineColor(OutlineColor);

    return Line;
}

sf::CircleShape Circle(const sf::Vector2f &Center, float Radius, const sf::Color &Color, float Outline, const sf::Color &OutlineColor)
{
    sf::CircleShape Circle;
    Circle.setOrigin(Radius, Radius);
    Circle.setPosition(Center);
    Circle.setRadius(Radius);
    Circle.setFillColor(Color);
    Circle.setOutlineThickness(Outline);
    Circle.setOutlineColor(OutlineColor);
    return Circle;
}

sf::RectangleShape Rectangle(float Left, float Top, float Width, float Height, const sf::Color &Color, float Outline, const sf::Color &OutlineColor)
{
    sf::RectangleShape Rectangle;
    Rectangle.setPosition(Left, Top);
    Rectangle.setSize(sf::Vector2f(Width, Height));
    Rectangle.setFillColor(Color);
    Rectangle.setOutlineThickness(Outline);
    Rectangle.setOutlineColor(OutlineColor);
    return Rectangle;
}

class BottomLeftCompare
{
public:
    bool operator() (const sf::Vector2f &Lhs, const sf::Vector2f &Rhs) const
    {
        if (Lhs.y == Rhs.y)
            return Lhs.x < Rhs.x;
        else
            return Lhs.y > Rhs.y;
    }
} BottomLeftComp;

class AngleCompare
{
public:
    AngleCompare(const sf::Vector2f &NewP) : P(NewP)
    {

    }

    bool operator() (const sf::Vector2f &Lhs, const sf::Vector2f &Rhs) const
    {
        return (-DotProduct(sf::Vector2f(1.f, 0.f), Lhs - P) / Magnitude(Lhs - P)) < (-DotProduct(sf::Vector2f(1.f, 0.f), Rhs - P) / Magnitude(Rhs - P));
    }
private:
    sf::Vector2f P;
};

float CCW(const sf::Vector2f &p1, const sf::Vector2f &p2, const sf::Vector2f &p3)
{
    return CrossProduct(p2 - p1, p3 - p1);
}

sf::ConvexShape ConvexHull(vector<sf::Vector2f> Points)
{
    iter_swap(Points.begin(), min_element(Points.begin(), Points.end(), BottomLeftComp));

    AngleCompare AngleComp(Points.front());
    sort(Points.begin() + 1, Points.end(), AngleComp);

    int m = 0;
    for (unsigned int i = 1; i < Points.size(); i++)
    {
        while (CCW(Points[m == 0 ? Points.size() - 1 : m - 1], Points[m], Points[i]) >= 0.f)
        {
            if (m > 0)
                m--;
            else if (i == Points.size() - 1)
                break;
            else
                i++;
        }

        m++;
        swap(Points[m], Points[i]);
    }

    sf::ConvexShape Shape(m + 1);
    for (unsigned int i = 0; i < Shape.getPointCount(); i++)
        Shape.setPoint(i, Points[i]);

    return Shape;
}

sf::Texture PerlinNoise()
{
    const int Size2 = 800;
    const float Persistence = 0.5f;

    vector< vector<float> > F(Size2, vector<float>(Size2, 0.f));

    for (int i = 4; i <= 7; i++)
    {
        int Freq = pow(2, i);
        float Amplitude = pow(Persistence, log(Size2) / log(2) - i);

        int Size = Size2 / Freq;
        vector< vector<sf::Vector2f> > G(Size + 1, vector<sf::Vector2f>(Size + 1));
        for (int y = 0; y < Size + 1; y++)
        {
            for (int x = 0; x < Size + 1; x++)
                G[y][x] = PolarToRect(sf::Vector2f(1.f, Random(0.f, 360.f)));
        }

        for (int y = 0; y < Size2; y++)
        {
            for (int x = 0; x < Size2; x++)
            {
                sf::Vector2f p(x, y);
                p *= float(Size) / Size2;
                sf::Vector2i p0(p);
                sf::Vector2i p1 = p0 + sf::Vector2i(1, 1);

                sf::Vector2f pp0 = p - sf::Vector2f(p0);
                sf::Vector2f pp1 = p - sf::Vector2f(p1);

                float s = DotProduct(G[p0.y][p0.x], pp0);
                float t = DotProduct(G[p0.y][p1.x], sf::Vector2f(pp1.x, pp0.y));
                float u = DotProduct(G[p1.y][p0.x], sf::Vector2f(pp0.x, pp1.y));
                float v = DotProduct(G[p1.y][p1.x], pp1);

                sf::Vector2f S;
                S.x = 3 * pow(pp0.x, 2) - 2 * pow(pp0.x, 3);
                float a = s + S.x * (t - s);
                float b = u + S.x * (v - u);
                S.y = 3 * pow(pp0.y, 2) - 2 * pow(pp0.y, 3);
                float z = a + S.y * (b - a);

                F[y][x] += z * Amplitude;
            }
        }
    }

    float min, max;
    for (int y = 0; y < Size2; y++)
    {
        for (int x = 0; x < Size2; x++)
        {
            if (y == 0 && x == 0)
                min = max = F[y][x];
            else
            {
                if (F[y][x] < min)
                    min = F[y][x];

                if (F[y][x] > max)
                    max = F[y][x];
            }
        }
    }

    sf::Image Img;
    Img.create(Size2, Size2, sf::Color::Red);
    for (int y = 0; y < Size2; y++)
    {
        for (int x = 0; x < Size2; x++)
        {
            int val = Map(F[y][x], min, max, 165, 255);
            Img.setPixel(x, y, sf::Color(val, val, val));
        }
    }

    sf::Texture Tex;
    Tex.loadFromImage(Img);
    return Tex;
}
<|endoftext|>


<commit_before>
TGeoManager *g=0;

void Hgeom(Bool_t isOnlyChambers=kFALSE)
{

  g=new TGeoManager("TestHMPID","Private HMPID geometry");
  Materials();
  gGeoManager->MakeBox("ALIC",gGeoManager->GetMedium("HMPID_CH4"),3000/2,3000/2,3000/2); //arbitrary values
  gGeoManager->SetTopVolume(gGeoManager->GetVolume("ALIC"));

  Hmpid(isOnlyChambers);

  gGeoManager->CloseGeometry();

//  gGeoManager->SetVisOption(0); gGeoManager->SetVisLevel(5);

//  gGeoManager->GetMasterVolume()->Draw();
//  Axis();
//  gPad->GetView()->SetView(3,94,-70,0);
  new TBrowser;
}
//__________________________________________________________________________________________________
void Materials()
{
//Media for HMPID
  Double_t a=0,z=0,den=0,radlen=0,intlen=0;//tmp vars for material parameters
                                //  A       Z     rho
  TGeoMaterial *ar,*al,*cu,*w,*ro;  TGeoMixture *c6f14,*sio2,*ch4,*csi;
  al   =new TGeoMaterial("HMPID_Al"   ,  26.982 , 13 ,  2.700);
  ro   =new TGeoMaterial("HMPID_Neoc" ,  12.01  ,  6 ,  0.1  );
  cu   =new TGeoMaterial("HMPID_Cu"   ,  63.546 , 29 ,  8.960);
  w    =new TGeoMaterial("HMPID_W"    , 183.840 , 74 , 19.300);
  ar   =new TGeoMaterial("HMPID_Ar"   ,  39.948 , 18 ,  1.396);
  c6f14=new TGeoMixture ("HMPID_C6F14",2,1.68     );c6f14->DefineElement(0, 12.010, 6,6); c6f14->DefineElement(1, 18.998, 9,14);
  sio2 =new TGeoMixture ("HMPID_SiO2" ,2,2.20     );sio2 ->DefineElement(0, 28.085,14,1);  sio2->DefineElement(1, 15.999, 8, 2);
  ch4  =new TGeoMixture ("HMPID_CH4"  ,2,0.4224e-3);ch4  ->DefineElement(0, 12.010, 6,1);   ch4->DefineElement(1,  1.007, 1, 4);
  csi  =new TGeoMixture ("HMPID_CsI"  ,2,1.8      );csi  ->DefineElement(0,132.900,55,1);   csi->DefineElement(1,126.900,53, 1);

  new TGeoMedium("HMPID_Al"   ,1,al);
  new TGeoMedium("HMPID_Neoc" ,2,ro);
  new TGeoMedium("HMPID_Cu"   ,3,cu);
  new TGeoMedium("HMPID_W"    ,4,w );
  new TGeoMedium("HMPID_C6F14",6,c6f14);
  new TGeoMedium("HMPID_SiO2" ,7,sio2);
  new TGeoMedium("HMPID_CH4"  ,8,ch4);
  new TGeoMedium("HMPID_CsI"  ,9,csi);
  new TGeoMedium("HMPID_Ar"   ,1,ar);

}//Materials()
//__________________________________________________________________________________________________
void Hmpid(Bool_t isOnlyChambers)
{
  Double_t cm=1,mm=0.1*cm,um=0.0001*cm;//length units
  TGeoMedium *al   =gGeoManager->GetMedium("HMPID_Al");
  TGeoMedium *ch4  =gGeoManager->GetMedium("HMPID_CH4");
  TGeoMedium *roha =gGeoManager->GetMedium("HMPID_Rohacell");
  TGeoMedium *neoc =gGeoManager->GetMedium("HMPID_Neoceram");
  TGeoMedium *c6f14=gGeoManager->GetMedium("HMPID_C6F14");
  TGeoMedium *sio2 =gGeoManager->GetMedium("HMPID_SiO2");
  TGeoMedium *cu   =gGeoManager->GetMedium("HMPID_Cu");
  TGeoMedium *w    =gGeoManager->GetMedium("HMPID_W");
  TGeoMedium *csi  =gGeoManager->GetMedium("HMPID_CsI");
  TGeoMedium *ar   =gGeoManager->GetMedium("HMPID_Ar");

  TGeoVolume *hmp=gGeoManager->MakeBox ("Hmp",ch4,1681*mm/2, 1466*mm/2,(2*80*mm+2*41*mm)/2);//2033P1  z from p84 TDR
  const Double_t kAngHor=19.5; //  horizontal angle between chambers  19.5 grad
  const Double_t kAngVer=20;   //  vertical angle between chambers    20   grad
  const Double_t kAngCom=30;   //  common HMPID rotation around z     30   grad
  const Double_t trans[3]={490*cm,0*cm,0*cm}; //center of the chamber is on window- proximity gap surface
  for(Int_t ch=0;ch<=6;ch++){//place 7 chambers
    TGeoHMatrix *mat=new TGeoHMatrix;
    mat->RotateY(90);           //rotate around y since initial position is in XY plane -> now in YZ plane
    mat->SetTranslation(trans); //now plane in YZ is shifted along x
    switch(ch){
      case 0:                mat->RotateY(kAngHor);  mat->RotateZ(-kAngVer);  break; //right and down
      case 1:                                        mat->RotateZ(-kAngVer);  break; //down
      case 2:                mat->RotateY(kAngHor);                           break; //right
      case 3:                                                                 break; //no rotation
      case 4:                mat->RotateY(-kAngHor);                          break; //left
      case 5:                                        mat->RotateZ(kAngVer);   break; //up
      case 6:                mat->RotateY(-kAngHor); mat->RotateZ(kAngVer);   break; //left and up
    }
    mat->RotateZ(kAngCom);     //apply common rotation  in XY plane
    gGeoManager->GetVolume("ALIC")->AddNode(hmp,ch,mat);
  }
  if(isOnlyChambers) return; //do not construct the detailed geometry

  TGeoRotation *rot=new TGeoRotation("HwireRot"); rot->RotateY(90); //rotate wires around Y to be along X (initially along Z)
  TGeoVolume *sbo=gGeoManager->MakeBox ("Hsbo",ch4  , 1419*mm/2 , 1378.00*mm/2 ,   50.5*mm/2);//2072P1
  TGeoVolume *cov=gGeoManager->MakeBox ("Hcov",al   , 1419*mm/2 , 1378.00*mm/2 ,    0.5*mm/2);
  TGeoVolume *hon=gGeoManager->MakeBox ("Hhon",roha , 1359*mm/2 , 1318.00*mm/2 ,   49.5*mm/2);
  TGeoVolume *rad=gGeoManager->MakeBox ("Hrad",c6f14, 1330*mm/2 ,  413.00*mm/2 ,   24.0*mm/2); //2011P1
  TGeoVolume *neo=gGeoManager->MakeBox ("Hneo",neoc , 1330*mm/2 ,  413.00*mm/2 ,    4.0*mm/2);
  TGeoVolume *win=gGeoManager->MakeBox ("Hwin",sio2 , 1330*mm/2 ,  413.00*mm/2 ,    5.0*mm/2);
  TGeoVolume *si1=gGeoManager->MakeBox ("Hsi1",sio2 , 1330*mm/2 ,    5.00*mm/2 ,   15.0*mm/2);
  TGeoVolume *si2=gGeoManager->MakeBox ("Hsi2",neoc ,   10*mm/2 ,  403.00*mm/2 ,   15.0*mm/2);
  TGeoVolume *spa=gGeoManager->MakeTube("Hspa",sio2 ,    0*mm   ,    5.00*mm   ,   15.0*mm/2);
  TGeoVolume *fr4=gGeoManager->MakeBox ("Hfr4",ch4  , 1407*mm/2 , 1366.00*mm/2 ,   15.0*mm/2);//2043P1
  TGeoVolume *f4a=gGeoManager->MakeBox ("Hf4a",al   , 1407*mm/2 , 1366.00*mm/2 ,   10.0*mm/2);
  TGeoVolume *f4i=gGeoManager->MakeBox ("Hf4i",ch4  , 1323*mm/2 , 1296.00*mm/2 ,   10.0*mm/2);
  TGeoVolume *col=gGeoManager->MakeTube("Hcol",cu   ,    0*mm   ,  100.00*um   , 1323.0*mm/2);
  TGeoVolume *sec=gGeoManager->MakeBox ("Hsec",ch4  ,  648*mm/2 ,  411.00*mm/2 ,   45.5*mm/2);//sec=gap+ppf
  TGeoVolume *ppf=gGeoManager->MakeBox ("Hppf",al   ,  648*mm/2 ,  411.00*mm/2 ,   40.0*mm/2);//2001P2
  TGeoVolume *lar=gGeoManager->MakeBox ("Hlar",ar   ,  181*mm/2 ,   89.25*mm/2 ,   38.3*mm/2);//2001P2
  TGeoVolume *smo=gGeoManager->MakeBox ("Hsmo",ar   ,  114*mm/2 ,   89.25*mm/2 ,   38.3*mm/2);//2001P2
  TGeoVolume *gap=gGeoManager->MakeBox ("Hgap",ch4  ,  640*mm/2 ,  403.20*mm/2 ,    5.5*mm/2);//gap=pad+ano+cat
  TGeoVolume *cat=gGeoManager->MakeTube("Hcat",cu   ,    0*mm   ,   50.00*um   ,    8.0*mm/2);
  TGeoVolume *ano=gGeoManager->MakeTube("Hano",w    ,    0*mm   ,   20.00*um   ,    8.0*mm/2);
  TGeoVolume *pad=gGeoManager->MakeBox ("Hpad",csi  ,    8*mm/2 ,    8.40*mm/2 ,    1.0*mm/2);
//
// ^ Y   z=         z=-12mm      z=98.25mm               ALIC->7xHmp (virtual)-->1xHsbo (virtual) --->2xHcov (real) 2072P1
// |  ____________________________________                                    |                   |-->1xHhon (real) 2072P1
// | |   ______     ____          ______  |                                   |
//   |  |      |   |    |   *    |      | |                                   |->3xHrad (virtual) --->1xHneo (real) 2011P1
//   |  |50.5mm|   |24mm|   *    |45.5mm| |                                   |                   |-->1xHwin (real) 2011P1
//   |  |      |   |    |   *    |      | |                                   |                   |-->2xHsi1 (real) 2011P1
//   |  |      |   |____|   *    |______| |                                   |                   |-->2xHsi2 (real) 2011P1
//   |  |      |    ____    *     ______  |                                   |                   |->30xHspa (real) 2011P1
//   |  |      |   |    |   *    |      | |                                   |
//   |  |      |   |    |   *    |      | |                                   |->1xHfr4 (vitual) --->1xHf4a (real)---->1xHf4i(virtual) 2043P1
//   |  |  sb  |   | rad|   *    |      | |                                   |                  |-->322xHcol (real) 2043P1
//   |  |      |   |____|   *    |______| |                                   |
//   |  |      |    ____    *     ______  |                                   |->6xHsec (virtual) --> 1xHppf(real) ---->8xHlar (virtual) 2001P1
//   |  |      |   |    |   *    |      | |                                                                        |--->8xHsmo (virtual) 2001P1
//   |  |      |   |    |   *    |      | |                                   |
//   |  |      |   |    |   *    |      | |                                   |-> 1xHgap (virtual) --->48xHrow (virtual) -->80xHcel (virtual) -->4xHcat (real) from p84 TDR
//   |  |______|   |____|   *    |______| |                                                                                |-->2xHano (real) from p84 TDR
//   |____________________________________|                                                                                |-->1xHpad (real) from p84 TDR
//                                                       --->Z
  hmp->AddNode(sbo ,1,new TGeoTranslation(   0*mm,   0*mm, -73.75*mm));                     //p.84 TDR
     sbo->AddNode(hon ,1,new TGeoTranslation(  0*mm,0*mm,      0*mm)); //2072P1
     sbo->AddNode(cov ,1,new TGeoTranslation(  0*mm,0*mm,    +25*mm));
     sbo->AddNode(cov ,2,new TGeoTranslation(  0*mm,0*mm,    -25*mm));
  hmp->AddNode(rad,2,new TGeoTranslation(   0*mm,+434*mm, -12.00*mm));
  hmp->AddNode(rad,1,new TGeoTranslation(   0*mm,   0*mm, -12.00*mm));
  hmp->AddNode(rad,0,new TGeoTranslation(   0*mm,-434*mm, -12.00*mm));
    rad->AddNode(neo,1,new TGeoTranslation(   0*mm,   0*mm, -10.0*mm));
    rad->AddNode(win,1,new TGeoTranslation(   0*mm,   0*mm,   9.5*mm));
    rad->AddNode(si1,1,new TGeoTranslation(   0*mm,-204*mm,  -0.5*mm)); rad->AddNode(si1,2,new TGeoTranslation(   0*mm,+204*mm,  -0.5*mm));
    rad->AddNode(si2,1,new TGeoTranslation(-660*mm,   0*mm,  -0.5*mm)); rad->AddNode(si2,2,new TGeoTranslation(+660*mm,   0*mm,  -0.5*mm));
    for(Int_t i=0;i<3;i++) for(Int_t j=0;j<10;j++) rad->AddNode(spa,copy=10*i+j,new TGeoTranslation(-1330*mm/2+116*mm+j*122*mm,(i-1)*105*mm,-0.5*mm));
  hmp->AddNode(fr4,1,new TGeoTranslation(   0*mm,   0*mm,   9.00*mm));                     //p.84 TDR
  for(int i=1;i<=322;i++)  fr4->AddNode(col,i,new TGeoCombiTrans( 0*mm, -1296/2*mm+i*4*mm,-5*mm,rot)); //F4 2043P1
                           fr4->AddNode(f4a,1,new TGeoTranslation(   0*mm,0*mm, 2.5*mm));
                                        f4a->AddNode(f4i,1,new TGeoTranslation(   0*mm,0*mm,   0*mm));
  hmp->AddNode(sec,4,new TGeoTranslation(-335*mm,+433*mm,  98.25*mm)); hmp->AddNode(sec,5,new TGeoTranslation(+335*mm,+433*mm,  98.25*mm));
  hmp->AddNode(sec,2,new TGeoTranslation(-335*mm,   0*mm,  98.25*mm)); hmp->AddNode(sec,3,new TGeoTranslation(+335*mm,   0*mm,  98.25*mm));
  hmp->AddNode(sec,0,new TGeoTranslation(-335*mm,-433*mm,  98.25*mm)); hmp->AddNode(sec,1,new TGeoTranslation(+335*mm,-433*mm,  98.25*mm));
    sec->AddNode(gap,1,new TGeoTranslation(0,0,-20.00*mm));
  TGeoVolume *row=          gap->Divide("Hrow",2,48,0,0);//along Y->48 rows
  TGeoVolume *cel=          row->Divide("Hcel",1,80,0,0);//along X->80 cells
      cel->AddNode(cat,1,new TGeoCombiTrans (0,  3.15*mm , -2.70*mm , rot)); //4 cathode wires
      cel->AddNode(ano,1,new TGeoCombiTrans (0,  2.00*mm , -0.29*mm , rot)); //2 anod wires
      cel->AddNode(cat,2,new TGeoCombiTrans (0,  1.05*mm , -2.70*mm , rot));
      cel->AddNode(cat,3,new TGeoCombiTrans (0, -1.05*mm , -2.70*mm , rot));
      cel->AddNode(ano,2,new TGeoCombiTrans (0, -2.00*mm , -0.29*mm , rot));
      cel->AddNode(cat,4,new TGeoCombiTrans (0, -3.15*mm , -2.70*mm , rot));
      cel->AddNode(pad,1,new TGeoTranslation(0,  0.00*mm ,  2.25*mm));       //1 pad
    sec->AddNode(ppf,1,new TGeoTranslation(0,0,  2.75*mm));
// ^ Y  single cell                                                5.5mm CH4 = 1*mm CsI + 4.45*mm CsI x cath +0.05*mm safety margin
// |      ______________________________
// |     |                              |          ^                            ||
//       |                              | 1.05mm                                ||
// 2.2*mm| xxxxxxxxxxxxxxxxxxxxxxxxxxxx |--              50um  x                || cat shift  x=0mm , y= 3.15mm , z=-2.70mm
//       |                              |                                       ||
//       |                              |                                       ||
// __    |  ..........................  | 2.1mm                    20un .       ||  ano shift x=0mm , y= 2.00mm , z=-0.29mm
//       |                              |                                       ||
//       |                              |                                       ||
//       | xxxxxxxxxxxxxxxxxxxxxxxxxxxx |--                    x                ||  cat shift x=0mm , y= 1.05mm , z=-2.70mm
//       |                              |                                       ||
//       |                              |         8.4mm                         ||
// 4*mm  |                              | 2.1mm                                 ||  pad shift x=0mm , y= 0.00mm , z=2.25*mm
//       |                              |                                       ||
//       |                              |                                       ||
//       | xxxxxxxxxxxxxxxxxxxxxxxxxxxx |--                    x                ||  cat shift x=0mm , y=-1.05mm , z=-2.70mm
//       |                              |                                       ||
//       |                              |                                       ||
// __    |  ..........................  | 2.1mm                         . 2.04mm||  ano shift x=0mm , y=-2.00mm , z=-0.29mm
//       |                              |                                       ||
//       |                              |                                       ||
//       | xxxxxxxxxxxxxxxxxxxxxxxxxxxx |--                    x    4.45mm      ||  cat shift x=0mm , y=-3.15mm , z=-2.70mm
// 2.2*mm|                              |                                       ||
//       |                              | 1.05mm                                ||
//       |______________________________|          v                            ||
//       <             8 mm             >
//                                   ----->X                                 ----->Z
  ppf->AddNode(lar,1,new TGeoTranslation(-224.5*mm,-151.875*mm,  0.85*mm));
  ppf->AddNode(lar,2,new TGeoTranslation(-224.5*mm,- 50.625*mm,  0.85*mm));
  ppf->AddNode(lar,3,new TGeoTranslation(-224.5*mm,+ 50.625*mm,  0.85*mm));
  ppf->AddNode(lar,4,new TGeoTranslation(-224.5*mm,+151.875*mm,  0.85*mm));
  ppf->AddNode(lar,5,new TGeoTranslation(+224.5*mm,-151.875*mm,  0.85*mm));
  ppf->AddNode(lar,6,new TGeoTranslation(+224.5*mm,- 50.625*mm,  0.85*mm));
  ppf->AddNode(lar,7,new TGeoTranslation(+224.5*mm,+ 50.625*mm,  0.85*mm));
  ppf->AddNode(lar,8,new TGeoTranslation(+224.5*mm,+151.875*mm,  0.85*mm));
  ppf->AddNode(smo,1,new TGeoTranslation(- 65.0*mm,-151.875*mm,  0.85*mm));
  ppf->AddNode(smo,2,new TGeoTranslation(- 65.0*mm,- 50.625*mm,  0.85*mm));
  ppf->AddNode(smo,3,new TGeoTranslation(- 65.0*mm,+ 50.625*mm,  0.85*mm));
  ppf->AddNode(smo,4,new TGeoTranslation(- 65.0*mm,+151.875*mm,  0.85*mm));
  ppf->AddNode(smo,5,new TGeoTranslation(+ 65.0*mm,-151.875*mm,  0.85*mm));
  ppf->AddNode(smo,6,new TGeoTranslation(+ 65.0*mm,- 50.625*mm,  0.85*mm));
  ppf->AddNode(smo,7,new TGeoTranslation(+ 65.0*mm,+ 50.625*mm,  0.85*mm));
  ppf->AddNode(smo,8,new TGeoTranslation(+ 65.0*mm,+151.875*mm,  0.85*mm));
}//Hmpid()
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void Axis()
{
// Draw axises  on top of geometry
  Double_t X[6]={0,0,0,300,0,0};  Double_t Y[6]={0,0,0,0,300,0};  Double_t Z[6]={0,0,0,0,0,300};
  TPolyLine3D *pXaxis=new TPolyLine3D(2,X);pXaxis->SetLineColor(kRed);   pXaxis->Draw();
  TPolyLine3D *pYaxis=new TPolyLine3D(2,Y);pYaxis->SetLineColor(kGreen); pYaxis->Draw();
  TPolyLine3D *pZaxis=new TPolyLine3D(2,Z);pZaxis->SetLineColor(kBlue);  pZaxis->Draw();
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
<commit_msg>Hgeom is no longer neede as functionality in v2<commit_after><|endoftext|>


<commit_before>#include <cmath>
#include <limits>
#include <algorithm>

#include "Exceptions.h"
#include "Histogram.h"
#include "BasicStatistics.h"
#include "Helper.h"
#include "Log.h"
#include <QStringList>
#include <QProcess>
#include <QStandardPaths>

Histogram::Histogram(double min, double max, double bin_size)
	: min_(min)
	, max_(max)
	, bin_size_(bin_size)
	, bin_sum_(0)
{
	if (bin_size_<=0)
	{
		THROW(StatisticsException,"Cannot initialize histogram with non-positive bin size!");
	}

	if (min_>=max_)
	{
		THROW(StatisticsException,"Cannot initialize histogram with empty range!");
	}

	bins_.resize(ceil((max_-min_)/bin_size_));
}

double Histogram::min() const
{
	return min_;
}

double Histogram::max() const
{
	return max_;
}

double Histogram::maxValue(bool as_percentage) const
{
	if (bins_.size()==0)
	{
		THROW(StatisticsException,"No bins present!");
	}

	double max = *(std::max_element(bins_.begin(), bins_.end()));
	if(as_percentage)
	{
		return 100.0 * max / (double)bin_sum_;
	}
	return max;
}

double Histogram::minValue(bool as_percentage) const
{
	if (bins_.size()==0)
	{
		THROW(StatisticsException,"No bins present!");
	}

	double min = *(std::min_element(bins_.begin(), bins_.end()));
	if(as_percentage)
	{
		return 100.0 * min / (double)bin_sum_;
	}
	return min;
}

double Histogram::binSize() const
{
	return bin_size_;
}

int Histogram::binCount() const
{
	return bins_.size();
}

int Histogram::binSum()
{
	return bin_sum_;
}

double Histogram::binValue(int index, bool as_percentage) const
{
	if (index<0 || index>=(int)bins_.size())
	{
        THROW(StatisticsException,"Index " + QString::number(index) + " out of range (0-" + QString::number(bins_.size()-1) + ")!");
	}

	double value = bins_[index];
	if(as_percentage)
	{
		return 100.0 * value / (double)bin_sum_;
	}
	return value;
}

double Histogram::startOfBin(int index) const
{
	if (index<0 || index>=(int)bins_.size())
	{
        THROW(StatisticsException,"Index " + QString::number(index) + " out of range (0-" + QString::number(bins_.size()-1) + ")!");
	}

    return bin_size_*index + min_;
}

double Histogram::binValue(double val, bool as_percentage) const
{
	double value = bins_[binIndex(val)];
	if(as_percentage)
	{
		return 100.0 * value / (double)bin_sum_;
	}
	return value;
}

void Histogram::inc(double val, bool ignore_bounds_errors)
{
	if (ignore_bounds_errors)
	{
		val = BasicStatistics::bound(val, min_, max_);
	}

	bins_[binIndex(val)]+=1;
	bin_sum_ += 1;
}

void Histogram::inc(const QVector<double>& data, bool ignore_bounds_errors)
{
	for (int i=0; i<data.size(); ++i)
	{
		inc(data[i], ignore_bounds_errors);
	}
}

int Histogram::binIndex(double val) const
{
	if (val < min_ || val > max_)
	{
		THROW(StatisticsException, "Requested position '" + QString::number(val) + "' not in range (" + QString::number(min_) + "-" + QString::number(max_) + ")!");
	}

	int index = floor ( (val-min_) / (max_-min_) * bins_.size());
	index = std::max(0, index);
	index = std::min(index, (int)(bins_.size()-1));

	return index;
}

void Histogram::print(QTextStream& stream, QString indentation, int position_precision, int data_precision, bool ascending) const
{
    for (int i=0; i<bins_.count(); ++i)
	{
        int index = ascending ? i : bins_.count()-i-1;
        double start = startOfBin(index);
        double end = start + bin_size_;
        if (!ascending) std::swap(start, end);
        stream << indentation << QString::number(start, 'f', position_precision) << "-" << QString::number(end, 'f', position_precision) << ": " << QString::number(binValue(index), 'f', data_precision) << "\n";
	}
}

QVector<double> Histogram::xCoords()
{
	return BasicStatistics::range(binCount(), startOfBin(0) + 0.5 * binSize(), binSize());
}

QVector<double> Histogram::yCoords(bool as_percentage)
{
	if (as_percentage)
	{
		QVector<double> tmp(bins_);
		for (int i=0; i<tmp.count(); ++i)
		{
			tmp[i] = 100.0 * tmp[i] / bin_sum_;
		}
		return tmp;
	}
	else
	{
		return bins_;
	}
}

void Histogram::setXLabel(QString xlabel)
{
	xlabel_ = xlabel;
}

void Histogram::setYLabel(QString ylabel)
{
	ylabel_ = ylabel;
}

void Histogram::store(QString filename)
{
	//create python script
	QStringList script;
	script.append("import matplotlib.pyplot as plt");
	script.append("plt.figure(figsize=(10, 4), dpi=100)");
	if(ylabel_!="") script.append("plt.ylabel('" + ylabel_ + "')");
	if(xlabel_!="") script.append("plt.xlabel('" + xlabel_ + "')");

	script.append("plt.tick_params(axis='x', which='both', bottom='off', top='off')");
	script.append("plt.tick_params(axis='y', which='both', left='off', right='off')");
	script.append("plt.ylim(" + QString::number(minValue()) + "," + QString::number(maxValue()+0.2*maxValue()) + ")");
	script.append("plt.xlim(" + QString::number(min()) + "," + QString::number(max()) + ")");

	//data
	QString yvaluestring = "";
	QString xvaluestring = "";
	QVector<double> x = xCoords();
	QVector<double> y = yCoords();
	for (int i=0; i<x.size(); ++i)
	{
		for(int j=0; j<y[i];++j)
		{
			yvaluestring += "," + QString::number(x[i]);
		}

		xvaluestring += "," + QString::number(x[i]+0.5*binSize());
	}
	xvaluestring = "[" + xvaluestring.remove(0,1) + "]";
	yvaluestring = "[" + yvaluestring.remove(0,1) + "]";

	script.append("plt.hist(" + yvaluestring + ", bins=" + xvaluestring + ", rwidth = 0.8, edgecolor='none')");

	//file handling
	script.append("plt.savefig('" + filename.replace("\\", "/") + "', bbox_inches=\'tight\', dpi=100)");

	//check if python is installed
	QString python_exe = QStandardPaths::findExecutable("python");
	if (python_exe!="")
	{
		QString scriptfile = Helper::tempFileName(".py");
		Helper::storeTextFile(scriptfile, script);

		//execute scipt
		QProcess process;
		process.setProcessChannelMode(QProcess::MergedChannels);
		process.start(python_exe, QStringList() << scriptfile);
		if (!process.waitForFinished(-1) || process.readAll().contains("rror"))
		{
			qDebug() << script.join("\n");
			THROW(ProgrammingException, "Could not execute python script! Error message is: " + process.errorString());
		}

		//remove temporary file
		QFile::remove(scriptfile);
	}
	else
	{
		Log::warn("Python executable not found in PATH - skipping plot generation!");
	}
}
<commit_msg>Histogram: updated plotting function.<commit_after>#include <cmath>
#include <limits>
#include <algorithm>

#include "Exceptions.h"
#include "Histogram.h"
#include "BasicStatistics.h"
#include "Helper.h"
#include "Log.h"
#include <QStringList>
#include <QProcess>
#include <QStandardPaths>

Histogram::Histogram(double min, double max, double bin_size)
	: min_(min)
	, max_(max)
	, bin_size_(bin_size)
	, bin_sum_(0)
{
	if (bin_size_<=0)
	{
		THROW(StatisticsException,"Cannot initialize histogram with non-positive bin size!");
	}

	if (min_>=max_)
	{
		THROW(StatisticsException,"Cannot initialize histogram with empty range!");
	}

	bins_.resize(ceil((max_-min_)/bin_size_));
}

double Histogram::min() const
{
	return min_;
}

double Histogram::max() const
{
	return max_;
}

double Histogram::maxValue(bool as_percentage) const
{
	if (bins_.size()==0)
	{
		THROW(StatisticsException,"No bins present!");
	}

	double max = *(std::max_element(bins_.begin(), bins_.end()));
	if(as_percentage)
	{
		return 100.0 * max / (double)bin_sum_;
	}
	return max;
}

double Histogram::minValue(bool as_percentage) const
{
	if (bins_.size()==0)
	{
		THROW(StatisticsException,"No bins present!");
	}

	double min = *(std::min_element(bins_.begin(), bins_.end()));
	if(as_percentage)
	{
		return 100.0 * min / (double)bin_sum_;
	}
	return min;
}

double Histogram::binSize() const
{
	return bin_size_;
}

int Histogram::binCount() const
{
	return bins_.size();
}

int Histogram::binSum()
{
	return bin_sum_;
}

double Histogram::binValue(int index, bool as_percentage) const
{
	if (index<0 || index>=(int)bins_.size())
	{
        THROW(StatisticsException,"Index " + QString::number(index) + " out of range (0-" + QString::number(bins_.size()-1) + ")!");
	}

	double value = bins_[index];
	if(as_percentage)
	{
		return 100.0 * value / (double)bin_sum_;
	}
	return value;
}

double Histogram::startOfBin(int index) const
{
	if (index<0 || index>=(int)bins_.size())
	{
        THROW(StatisticsException,"Index " + QString::number(index) + " out of range (0-" + QString::number(bins_.size()-1) + ")!");
	}

    return bin_size_*index + min_;
}

double Histogram::binValue(double val, bool as_percentage) const
{
	double value = bins_[binIndex(val)];
	if(as_percentage)
	{
		return 100.0 * value / (double)bin_sum_;
	}
	return value;
}

void Histogram::inc(double val, bool ignore_bounds_errors)
{
	if (ignore_bounds_errors)
	{
		val = BasicStatistics::bound(val, min_, max_);
	}

	bins_[binIndex(val)]+=1;
	bin_sum_ += 1;
}

void Histogram::inc(const QVector<double>& data, bool ignore_bounds_errors)
{
	for (int i=0; i<data.size(); ++i)
	{
		inc(data[i], ignore_bounds_errors);
	}
}

int Histogram::binIndex(double val) const
{
	if (val < min_ || val > max_)
	{
		THROW(StatisticsException, "Requested position '" + QString::number(val) + "' not in range (" + QString::number(min_) + "-" + QString::number(max_) + ")!");
	}

	int index = floor ( (val-min_) / (max_-min_) * bins_.size());
	index = std::max(0, index);
	index = std::min(index, (int)(bins_.size()-1));

	return index;
}

void Histogram::print(QTextStream& stream, QString indentation, int position_precision, int data_precision, bool ascending) const
{
    for (int i=0; i<bins_.count(); ++i)
	{
        int index = ascending ? i : bins_.count()-i-1;
        double start = startOfBin(index);
        double end = start + bin_size_;
        if (!ascending) std::swap(start, end);
        stream << indentation << QString::number(start, 'f', position_precision) << "-" << QString::number(end, 'f', position_precision) << ": " << QString::number(binValue(index), 'f', data_precision) << "\n";
	}
}

QVector<double> Histogram::xCoords()
{
	return BasicStatistics::range(binCount(), startOfBin(0) + 0.5 * binSize(), binSize());
}

QVector<double> Histogram::yCoords(bool as_percentage)
{
	if (as_percentage)
	{
		QVector<double> tmp(bins_);
		for (int i=0; i<tmp.count(); ++i)
		{
			tmp[i] = 100.0 * tmp[i] / bin_sum_;
		}
		return tmp;
	}
	else
	{
		return bins_;
	}
}

void Histogram::setXLabel(QString xlabel)
{
	xlabel_ = xlabel;
}

void Histogram::setYLabel(QString ylabel)
{
	ylabel_ = ylabel;
}

void Histogram::store(QString filename)
{
	//create python script
	QStringList script;
	script.append("import matplotlib as mpl");
	script.append("mpl.use('Agg')");
	script.append("import matplotlib.pyplot as plt");
	script.append("plt.figure(figsize=(10, 4), dpi=100)");
	if(ylabel_!="") script.append("plt.ylabel('" + ylabel_ + "')");
	if(xlabel_!="") script.append("plt.xlabel('" + xlabel_ + "')");

	script.append("plt.tick_params(axis='x', which='both', bottom='off', top='off')");
	script.append("plt.tick_params(axis='y', which='both', left='off', right='off')");
	script.append("plt.ylim(" + QString::number(minValue()) + "," + QString::number(maxValue()+0.2*maxValue()) + ")");
	script.append("plt.xlim(" + QString::number(min()) + "," + QString::number(max()) + ")");

	//data
	QString yvaluestring = "";
	QString xvaluestring = "";
	QVector<double> x = xCoords();
	QVector<double> y = yCoords();
	for (int i=0; i<x.size(); ++i)
	{
		for(int j=0; j<y[i];++j)
		{
			yvaluestring += "," + QString::number(x[i]);
		}

		xvaluestring += "," + QString::number(x[i]+0.5*binSize());
	}
	xvaluestring = "[" + xvaluestring.remove(0,1) + "]";
	yvaluestring = "[" + yvaluestring.remove(0,1) + "]";

	script.append("plt.hist(" + yvaluestring + ", bins=" + xvaluestring + ", rwidth = 0.8, edgecolor='none')");

	//file handling
	script.append("plt.savefig('" + filename.replace("\\", "/") + "', bbox_inches=\'tight\', dpi=100)");

	//check if python is installed
	QString python_exe = QStandardPaths::findExecutable("python");
	if (python_exe!="")
	{
		QString scriptfile = Helper::tempFileName(".py");
		Helper::storeTextFile(scriptfile, script);

		//execute scipt
		QProcess process;
		process.setProcessChannelMode(QProcess::MergedChannels);
		process.start(python_exe, QStringList() << scriptfile);
		if (!process.waitForFinished(-1) || process.readAll().contains("rror"))
		{
			qDebug() << script.join("\n");
			THROW(ProgrammingException, "Could not execute python script! Error message is: " + process.errorString());
		}

		//remove temporary file
		QFile::remove(scriptfile);
	}
	else
	{
		Log::warn("Python executable not found in PATH - skipping plot generation!");
	}
}
<|endoftext|>


<commit_before>#include "MainWindow.h"

#include <QTextEdit>
#include <QPushButton>

MainWindow::MainWindow(QWidget *parent) :
  QMainWindow(parent), stars(0)
{
  setupUi(this);
  connect(north, &QPushButton::click, this, &MainWindow::doSomething);
  connect(south, &QPushButton::click, this, &MainWindow::doSomething);
  connect(east, &QPushButton::click, this, &MainWindow::doSomething);
  connect(west, &QPushButton::click, this, &MainWindow::doSomething);
  connect(inventory, &QPushButton::click, this, &MainWindow::doInventory);
  description->setHtml(tr("
You've been sent on an epic quest (imagine some backstory involving an inn, a suspiciously peppy bard and a threat to middle earth as you know it) to delve deep into the tunnels beneath github, and retrieve the <s>seven</s> ten stars!

After a long and tedious journey in which we get some character origin stories, you end up in the dungeons.
"));
  doPrompt();
}

void MainWindow::changeEvent(QEvent *e)
{
  QMainWindow::changeEvent(e);
  switch (e->type()) {
  case QEvent::LanguageChange:
    retranslateUi(this);
    break;
  default:
    break;
  }
}

void MainWindow::doSomething()
{

}

void MainWindow::doInventory()
{
  description->append(tr("
You have:
%1 stars
no tea
").arg(stars));
}

void MainWindow::prompt()
{
  description->append("
What now?
");
}
<commit_msg>Maze of twisty little commit messages<commit_after>#include "MainWindow.h"

#include <QTextEdit>
#include <QPushButton>

#include <stdlib.h>

MainWindow::MainWindow(QWidget *parent) :
  QMainWindow(parent), stars(0)
{
  setupUi(this);
  connect(north, &QPushButton::click, this, &MainWindow::doSomething);
  connect(south, &QPushButton::click, this, &MainWindow::doSomething);
  connect(east, &QPushButton::click, this, &MainWindow::doSomething);
  connect(west, &QPushButton::click, this, &MainWindow::doSomething);
  connect(inventory, &QPushButton::click, this, &MainWindow::doInventory);
  description->setHtml(tr("
You've been sent on an epic quest (imagine"
                          " some backstory involving an inn, a suspiciously"
                          " peppy bard and a threat to middle earth as you"
                          " know it) to delve deep into the tunnels beneath"
                          " github, and retrieve the <s>seven</s> ten stars!
"
                          "
After a long and tedious journey in which we get"
                          " some character origin stories, you end up in the"
                          " dungeons.
"));
  prompt();
}

void MainWindow::changeEvent(QEvent *e)
{
  QMainWindow::changeEvent(e);
  switch (e->type()) {
  case QEvent::LanguageChange:
    retranslateUi(this);
    break;
  default:
    break;
  }
}

void MainWindow::doSomething()
{
  int i = random() % 4;
  north->setEnabled(i != 0);
  south->setEnabled(i != 1);
  east->setEnabled(i != 2);
  west->setEnabled(i != 3);

  QString twisty;
  switch (i) {
  case 0:
    twisty = tr("twisty little maze of passages");
    break;
  case 1:
    twisty = tr("maze of twisty little passages");
    break;
  case 2:
    twisty = tr("little twisty maze of passages");
    break;
  default:
    twisty = tr("twisty maze of little passages");
  }

  if(random() % 3) {

  }
}

void MainWindow::doInventory()
{
  description->append(tr("
You have:
%1 stars
no tea
").arg(stars));
}

void MainWindow::prompt()
{
  description->append("
What now?
");
}
<|endoftext|>


<commit_before>#ifndef _SNARKFRONT_SHA_512_224_HPP_
#define _SNARKFRONT_SHA_512_224_HPP_

#include <array>
#include <cstdint>
#include "Alg.hpp"
#include "Alg_uint.hpp"
#include "AST.hpp"
#include "BitwiseOps.hpp"
#include "Lazy.hpp"
#include "SHA_512.hpp"

namespace snarkfront {

////////////////////////////////////////////////////////////////////////////////
// SHA-512/224
//

template <typename H, typename T, typename MSG, typename F>
class SHA_512_224 : public SHA_512<T, MSG, F>
{
public:
    typedef T WordType;
    typedef std::array<T, 16> MsgType;
    typedef std::array<H, 7> DigType;

    SHA_512_224()
        : m_setDigest(false)
    {}

    // overrides base class SHA-512
    const std::array<H, 7>& digest() {
        if (m_setDigest) {
            for (std::size_t i = 0; i < 3; ++i) {
                // high 32 bits
                m_Hleft224[2*i] = F::xword(F::SHR(
                                               this->m_H[i],
                                               32));

                // low 32 bits
                m_Hleft224[2*i + 1] = F::xword(F::SHR(
                                                   F::SHL(
                                                       this->m_H[i],
                                                       32),
                                                   32));
            }

            // high 32 bits
            m_Hleft224[6] = F::xword(F::SHR(
                                         this->m_H[3],
                                         32));

            m_setDigest = false;
        }

        return m_Hleft224;
    }

    // overrides base class SHA-512
    virtual void initHashValue() {
        // set initial hash value (NIST FIPS 180-4 section 5.3.6.1)
        const std::array<std::uint64_t, 8> a {
            0x8C3D37C819544DA2, 0x73E1996689DCD4D6,
            0x1DFAB7AE32FF9C82, 0x679DD514582F9FCF,

            0x0F6D2B697BD44DA8, 0x77E36F7304C48942,
            0x3F9D85A86A1D36C8, 0x1112E6AD91D692A1 };

        for (std::size_t i = 0; i < 8; ++i) {
            this->m_H[i] = F::constant(a[i]);
        }
    }

    virtual void afterHash() {
        m_setDigest = true;
    }

private:
    // truncated 224-bit message digest
    std::array<H, 7> m_Hleft224;

    bool m_setDigest;
};

////////////////////////////////////////////////////////////////////////////////
// typedefs
//

namespace zk {
    template <typename FR> using
    SHA512_224 = SHA_512_224<AST_Var<Alg_uint32<FR>>,
                             AST_Var<Alg_uint64<FR>>,
                             Lazy<AST_Var<Alg_uint64<FR>>, std::uint64_t>,
                             SHA_Functions<AST_Node<Alg_uint64<FR>>,
                                           AST_Op<Alg_uint64<FR>>,
                                           BitwiseAST<Alg_uint64<FR>, Alg_uint32<FR>>>>;
} // namespace zk

namespace eval {
    typedef SHA_512_224<std::uint32_t,
                        std::uint64_t,
                        std::uint64_t,
                        SHA_Functions<std::uint64_t,
                                      std::uint64_t,
                                      BitwiseINT<std::uint64_t, std::uint32_t>>>
        SHA512_224;
} // namespace eval

} // namespace snarkfront

#endif
<commit_msg>8-bit unsigned int array pre-image<commit_after>#ifndef _SNARKFRONT_SHA_512_224_HPP_
#define _SNARKFRONT_SHA_512_224_HPP_

#include <array>
#include <cstdint>
#include "Alg.hpp"
#include "Alg_uint.hpp"
#include "AST.hpp"
#include "BitwiseOps.hpp"
#include "Lazy.hpp"
#include "SHA_512.hpp"

namespace snarkfront {

////////////////////////////////////////////////////////////////////////////////
// SHA-512/224
//

template <typename H, typename T, typename MSG, typename U, typename F>
class SHA_512_224 : public SHA_512<T, MSG, U, F>
{
public:
    typedef T WordType;
    typedef U ByteType;

    typedef std::array<T, 16> MsgType;
    typedef std::array<H, 7> DigType;
    typedef std::array<U, 16 * 8> PreType;

    SHA_512_224()
        : m_setDigest(false)
    {}

    // overrides base class SHA-512
    const std::array<H, 7>& digest() {
        if (m_setDigest) {
            for (std::size_t i = 0; i < 3; ++i) {
                // high 32 bits
                m_Hleft224[2*i] = F::xword(F::SHR(
                                               this->m_H[i],
                                               32));

                // low 32 bits
                m_Hleft224[2*i + 1] = F::xword(F::SHR(
                                                   F::SHL(
                                                       this->m_H[i],
                                                       32),
                                                   32));
            }

            // high 32 bits
            m_Hleft224[6] = F::xword(F::SHR(
                                         this->m_H[3],
                                         32));

            m_setDigest = false;
        }

        return m_Hleft224;
    }

    // overrides base class SHA-512
    virtual void initHashValue() {
        // set initial hash value (NIST FIPS 180-4 section 5.3.6.1)
        const std::array<std::uint64_t, 8> a {
            0x8C3D37C819544DA2, 0x73E1996689DCD4D6,
            0x1DFAB7AE32FF9C82, 0x679DD514582F9FCF,

            0x0F6D2B697BD44DA8, 0x77E36F7304C48942,
            0x3F9D85A86A1D36C8, 0x1112E6AD91D692A1 };

        for (std::size_t i = 0; i < 8; ++i) {
            this->m_H[i] = F::constant(a[i]);
        }
    }

    virtual void afterHash() {
        m_setDigest = true;
    }

private:
    // truncated 224-bit message digest
    std::array<H, 7> m_Hleft224;

    bool m_setDigest;
};

////////////////////////////////////////////////////////////////////////////////
// typedefs
//

namespace zk {
    template <typename FR> using
    SHA512_224 = SHA_512_224<AST_Var<Alg_uint32<FR>>,
                             AST_Var<Alg_uint64<FR>>,
                             Lazy<AST_Var<Alg_uint64<FR>>, std::uint64_t>,
                             AST_Var<Alg_uint8<FR>>,
                             SHA_Functions<AST_Node<Alg_uint64<FR>>,
                                           AST_Op<Alg_uint64<FR>>,
                                           BitwiseAST<Alg_uint64<FR>, Alg_uint32<FR>>>>;
} // namespace zk

namespace eval {
    typedef SHA_512_224<std::uint32_t,
                        std::uint64_t,
                        std::uint64_t,
                        std::uint8_t,
                        SHA_Functions<std::uint64_t,
                                      std::uint64_t,
                                      BitwiseINT<std::uint64_t, std::uint32_t>>>
        SHA512_224;
} // namespace eval

} // namespace snarkfront

#endif
<|endoftext|>


<commit_before>#include <limits>
#include "Skeletonize.h"
#include <vigra/multi_distance.hxx>
#include <vigra/multi_gridgraph.hxx>
#include <vigra/multi_labeling.hxx>
#include <vigra/multi_impex.hxx>
#include <util/timing.h>
#include <util/ProgramOptions.h>
#include <util/Logger.h>

util::ProgramOption optionSkeletonBoundaryWeight(
		util::_long_name        = "skeletonBoundaryWeight",
		util::_description_text = "The weight of the boundary term to find the tube's skeletons.",
		util::_default_value    = 1);

util::ProgramOption optionSkeletonMaxNumSegments(
		util::_long_name        = "skeletonMaxNumSegments",
		util::_description_text = "The maximal number of segments to extract for a skeleton.",
		util::_default_value    = 10);

util::ProgramOption optionSkeletonMinSegmentLength(
		util::_long_name        = "skeletonMinSegmentLength",
		util::_description_text = "The mininal length of a segment (including the boundary penalty) to extract for a skeleton.",
		util::_default_value    = 0);

util::ProgramOption optionSkeletonMinSegmentLengthRatio(
		util::_long_name        = "skeletonMinSegmentLengthRatio",
		util::_description_text = "The mininal length of a segment (including the boundary penalty) as the ratio of the largest segment extracted for a skeleton.",
		util::_default_value    = 1);

util::ProgramOption optionSkeletonSkipExplainedNodes(
		util::_long_name        = "skeletonSkipExplainedNodes",
		util::_description_text = "Don't add segments to nodes that are already explained by the current skeleton. "
		                          "Nodes are explained, if they fall within a sphere around any current skeleton node. "
		                          "The size of the sphere is determined by boundary distance * skeletonExplanationWeight.");

util::ProgramOption optionSkeletonExplanationWeight(
		util::_long_name        = "skeletonExplanationWeight",
		util::_description_text = "A factor to multiply with the boundary distance to create 'explanation spheres'. "
		                          "See skeletonSkipExplainedNodes.",
		util::_default_value    = 1);

logger::LogChannel skeletonizelog("skeletonizelog", "[Skeletonize] ");

Skeletonize::Skeletonize(const GraphVolume& graphVolume) :
	_boundaryDistance(
			vigra::Shape3(
					graphVolume.getDiscreteBoundingBox().width()  + 2,
					graphVolume.getDiscreteBoundingBox().height() + 2,
					graphVolume.getDiscreteBoundingBox().depth()  + 2
			)),
	_graphVolume(graphVolume),
	_distanceMap(_graphVolume.graph()),
	_boundaryWeight(optionSkeletonBoundaryWeight),
	_dijkstra(_graphVolume.graph(), _distanceMap),
	_nodeLabels(_graphVolume.graph(), Inside),
	_minSegmentLength(optionSkeletonMinSegmentLength),
	_minSegmentLengthRatio(optionSkeletonMinSegmentLengthRatio),
	_skipExplainedNodes(optionSkeletonSkipExplainedNodes),
	_explanationWeight(optionSkeletonExplanationWeight) {}

Skeleton
Skeletonize::getSkeleton() {

	UTIL_TIME_METHOD;

	findBoundaryNodes();

	initializeEdgeMap();

	findRoot();

	int maxNumSegments = optionSkeletonMaxNumSegments;
	int segmentsFound = 0;
	while (extractLongestSegment() && ++segmentsFound < maxNumSegments) {}

	return parseVolumeSkeleton();
}

void
Skeletonize::findBoundaryNodes() {

	for (GraphVolume::NodeIt node(_graphVolume.graph()); node != lemon::INVALID; ++node) {

		int numNeighbors = 0;
		for (GraphVolume::IncEdgeIt e(_graphVolume.graph(), node); e != lemon::INVALID; ++e)
			numNeighbors++;

		if (numNeighbors != GraphVolume::NumNeighbors) {

			_boundary.push_back(node);
			_nodeLabels[node] = Boundary;
		}
	}
}

void
Skeletonize::initializeEdgeMap() {

	// the pitch is the number of units per voxel dimension
	float pitch[3];
	pitch[0] = _graphVolume.getResolutionX();
	pitch[1] = _graphVolume.getResolutionY();
	pitch[2] = _graphVolume.getResolutionZ();

	_boundaryDistance = 0;
	for (GraphVolume::NodeIt n(_graphVolume.graph()); n != lemon::INVALID; ++n)
		boundaryDistance(_graphVolume.positions()[n]) = 1.0;

	if (_graphVolume.getDiscreteBoundingBox().depth() == 1) {

		LOG_DEBUG(skeletonizelog) << "performing 2D distance transform for boundary penalty" << std::endl;

		// perform 2D distance transform if depth is 1
		vigra::separableMultiDistSquared(
				_boundaryDistance.bind<2>(1), // only on center section (0 and 2 are padded)
				_boundaryDistance.bind<2>(1),
				false,  /* compute distance from object (non-zero) to background (0) */
				pitch);

	} else {

		vigra::separableMultiDistSquared(
				_boundaryDistance,
				_boundaryDistance,
				false,  /* compute distance from object (non-zero) to background (0) */
				pitch);
	}

	// find center point with maximal boundary distance
	_maxBoundaryDistance2 = 0;
	for (GraphVolume::NodeIt node(_graphVolume.graph()); node != lemon::INVALID; ++node) {

		const Position& pos = _graphVolume.positions()[node];
		if (boundaryDistance(pos) > _maxBoundaryDistance2) {

			_center = node;
			_maxBoundaryDistance2 = boundaryDistance(pos);
		}
	}

	// create initial edge map from boundary penalty
	for (GraphVolume::EdgeIt e(_graphVolume.graph()); e != lemon::INVALID; ++e)
		_distanceMap[e] = boundaryPenalty(
				0.5*(
						boundaryDistance(_graphVolume.positions()[_graphVolume.graph().u(e)]) +
						boundaryDistance(_graphVolume.positions()[_graphVolume.graph().v(e)])));

	// multiply with Euclidean node distances
	//
	// The TEASAR paper suggests to add the Euclidean distances. However, for
	// the penalty to be meaningful in anistotropic volumes, it should be
	// multiplied with the Euclidean distance between the nodes (otherwise, it
	// is more expensive to move in the high-resolution dimensions). Therefore,
	// the final value is
	//
	//   penalty*euclidean + euclidean = euclidean*(penalty + 1)

	float nodeDistances[8];
	nodeDistances[0] = 0;
	nodeDistances[1] = _graphVolume.getResolutionZ();
	nodeDistances[2] = _graphVolume.getResolutionY();
	nodeDistances[3] = sqrt(pow(_graphVolume.getResolutionY(), 2) + pow(_graphVolume.getResolutionZ(), 2));
	nodeDistances[4] = _graphVolume.getResolutionX();
	nodeDistances[5] = sqrt(pow(_graphVolume.getResolutionX(), 2) + pow(_graphVolume.getResolutionZ(), 2));
	nodeDistances[6] = sqrt(pow(_graphVolume.getResolutionX(), 2) + pow(_graphVolume.getResolutionY(), 2));
	nodeDistances[7] = sqrt(pow(_graphVolume.getResolutionX(), 2) + pow(_graphVolume.getResolutionY(), 2) + pow(_graphVolume.getResolutionZ(), 2));

	for (GraphVolume::EdgeIt e(_graphVolume.graph()); e != lemon::INVALID; ++e) {

		Position u = _graphVolume.positions()[_graphVolume.graph().u(e)];
		Position v = _graphVolume.positions()[_graphVolume.graph().v(e)];

		int i = 0;
		if (u[0] != v[0]) i |= 4;
		if (u[1] != v[1]) i |= 2;
		if (u[2] != v[2]) i |= 1;

		_distanceMap[e] = nodeDistances[i]*(_distanceMap[e] + 1);
	}
}

void
Skeletonize::findRoot() {

	_dijkstra.run(_center);

	// find furthest point on boundary
	_root = GraphVolume::NodeIt(_graphVolume.graph());
	float maxValue = -1;
	for (GraphVolume::Node n : _boundary) {
		if (_dijkstra.distMap()[n] > maxValue) {

			_root    = n;
			maxValue = _dijkstra.distMap()[n];
		}
	}

	if (maxValue == -1)
		UTIL_THROW_EXCEPTION(
				NoNodeFound,
				"could not find a root boundary point");

	// mark root as being part of skeleton
	_nodeLabels[_root] = OnSkeleton;
}

bool
Skeletonize::extractLongestSegment() {

	_dijkstra.run(_root);

	// find furthest point on boundary
	GraphVolume::Node furthest = GraphVolume::NodeIt(_graphVolume.graph());
	float maxValue = -1;
	for (GraphVolume::Node n : _boundary) {

		if (_skipExplainedNodes && _nodeLabels[n] == Explained)
			continue;

		if (_dijkstra.distMap()[n] > maxValue) {

			furthest = n;
			maxValue = _dijkstra.distMap()[n];
		}
	}

	// no more points or length smaller then min segment length
	if (maxValue == -1 || maxValue < _minSegmentLength)
		return false;

	LOG_DEBUG(skeletonizelog) << "extracting segment with length " << maxValue << std::endl;

	GraphVolume::Node n = furthest;

	// walk backwards to next skeleton point
	while (_nodeLabels[n] != OnSkeleton) {

		_nodeLabels[n] = OnSkeleton;

		if (_skipExplainedNodes)
			drawExplanationSphere(_graphVolume.positions()[n]);

		GraphVolume::Edge pred = _dijkstra.predMap()[n];
		GraphVolume::Node u = _graphVolume.graph().u(pred);
		GraphVolume::Node v = _graphVolume.graph().v(pred);

		n = (u == n ? v : u);

		_distanceMap[pred] = 0.0;
	}

	// first segment?
	if (n == _root) {

		LOG_DEBUG(skeletonizelog) << "longest segment has length " << maxValue << std::endl;

		_minSegmentLength = std::max(_minSegmentLength, _minSegmentLengthRatio*maxValue);

		LOG_DEBUG(skeletonizelog) << "setting min segment length to " << _minSegmentLength << std::endl;
	}

	return true;
}

void
Skeletonize::drawExplanationSphere(const Position& center) {

	double radius2 = boundaryDistance(center)*pow(_explanationWeight, 2);

	double resX2 = pow(_graphVolume.getResolutionX(), 2);
	double resY2 = pow(_graphVolume.getResolutionY(), 2);
	double resZ2 = pow(_graphVolume.getResolutionZ(), 2);

	for (GraphVolume::Node n : _boundary) {

		const Position& pos = _graphVolume.positions()[n];
		double distance2 =
				resX2*pow(pos[0] - center[0], 2) +
				resY2*pow(pos[1] - center[1], 2) +
				resZ2*pow(pos[2] - center[2], 2);

		if (distance2 <= radius2)
			if (_nodeLabels[n] != OnSkeleton)
				_nodeLabels[n] = Explained;
	}
}

double
Skeletonize::boundaryPenalty(double boundaryDistance) {

	// penalty = w*(1.0 - bd/max_bd)
	//
	//   w     : boundary weight
	//   bd    : boundary distance
	//   max_bd: max boundary distance
	return _boundaryWeight*(1.0 - sqrt(boundaryDistance/_maxBoundaryDistance2));
}

Skeleton
Skeletonize::parseVolumeSkeleton() {

	Skeleton skeleton;

	skeleton.setOffset(_graphVolume.getOffset());
	skeleton.setResolution(_graphVolume.getResolution());

	traverse(_root, skeleton);

	return skeleton;
}

void
Skeletonize::traverse(const GraphVolume::Node& n, Skeleton& skeleton) {

	Position pos = _graphVolume.positions()[n];

	_nodeLabels[n] = Visited;

	int neighbors = numNeighbors(n);
	bool isNode = (neighbors != 2);

	if (isNode || n == _root)
		skeleton.openSegment(pos, sqrt(boundaryDistance(pos)));
	else
		skeleton.extendSegment(pos, sqrt(boundaryDistance(pos)));

	for (GraphVolume::IncEdgeIt e(_graphVolume.graph(), n); e != lemon::INVALID && neighbors > 0; ++e) {

		if (_distanceMap[e] != 0.0)
			continue;

		GraphVolume::Node neighbor = (_graphVolume.graph().u(e) == n ? _graphVolume.graph().v(e) : _graphVolume.graph().u(e));

		neighbors--;

		if (_nodeLabels[neighbor] != Visited)
			traverse(neighbor, skeleton);
	}

	if (isNode || n == _root)
		skeleton.closeSegment();
}

int
Skeletonize::numNeighbors(const GraphVolume::Node& n) {

	int num = 0;

	for (GraphVolume::IncEdgeIt e(_graphVolume.graph(), n); e != lemon::INVALID; ++e)
		if (_distanceMap[e] == 0.0)
			num++;

	return num;
}

<commit_msg>Refactor Skeletonize::traverse to avoid deep recursion.<commit_after>#include <limits>
#include "Skeletonize.h"
#include <vigra/multi_distance.hxx>
#include <vigra/multi_gridgraph.hxx>
#include <vigra/multi_labeling.hxx>
#include <vigra/multi_impex.hxx>
#include <util/timing.h>
#include <util/ProgramOptions.h>
#include <util/Logger.h>

util::ProgramOption optionSkeletonBoundaryWeight(
		util::_long_name        = "skeletonBoundaryWeight",
		util::_description_text = "The weight of the boundary term to find the tube's skeletons.",
		util::_default_value    = 1);

util::ProgramOption optionSkeletonMaxNumSegments(
		util::_long_name        = "skeletonMaxNumSegments",
		util::_description_text = "The maximal number of segments to extract for a skeleton.",
		util::_default_value    = 10);

util::ProgramOption optionSkeletonMinSegmentLength(
		util::_long_name        = "skeletonMinSegmentLength",
		util::_description_text = "The mininal length of a segment (including the boundary penalty) to extract for a skeleton.",
		util::_default_value    = 0);

util::ProgramOption optionSkeletonMinSegmentLengthRatio(
		util::_long_name        = "skeletonMinSegmentLengthRatio",
		util::_description_text = "The mininal length of a segment (including the boundary penalty) as the ratio of the largest segment extracted for a skeleton.",
		util::_default_value    = 1);

util::ProgramOption optionSkeletonSkipExplainedNodes(
		util::_long_name        = "skeletonSkipExplainedNodes",
		util::_description_text = "Don't add segments to nodes that are already explained by the current skeleton. "
		                          "Nodes are explained, if they fall within a sphere around any current skeleton node. "
		                          "The size of the sphere is determined by boundary distance * skeletonExplanationWeight.");

util::ProgramOption optionSkeletonExplanationWeight(
		util::_long_name        = "skeletonExplanationWeight",
		util::_description_text = "A factor to multiply with the boundary distance to create 'explanation spheres'. "
		                          "See skeletonSkipExplainedNodes.",
		util::_default_value    = 1);

logger::LogChannel skeletonizelog("skeletonizelog", "[Skeletonize] ");

Skeletonize::Skeletonize(const GraphVolume& graphVolume) :
	_boundaryDistance(
			vigra::Shape3(
					graphVolume.getDiscreteBoundingBox().width()  + 2,
					graphVolume.getDiscreteBoundingBox().height() + 2,
					graphVolume.getDiscreteBoundingBox().depth()  + 2
			)),
	_graphVolume(graphVolume),
	_distanceMap(_graphVolume.graph()),
	_boundaryWeight(optionSkeletonBoundaryWeight),
	_dijkstra(_graphVolume.graph(), _distanceMap),
	_nodeLabels(_graphVolume.graph(), Inside),
	_minSegmentLength(optionSkeletonMinSegmentLength),
	_minSegmentLengthRatio(optionSkeletonMinSegmentLengthRatio),
	_skipExplainedNodes(optionSkeletonSkipExplainedNodes),
	_explanationWeight(optionSkeletonExplanationWeight) {}

Skeleton
Skeletonize::getSkeleton() {

	UTIL_TIME_METHOD;

	findBoundaryNodes();

	initializeEdgeMap();

	findRoot();

	int maxNumSegments = optionSkeletonMaxNumSegments;
	int segmentsFound = 0;
	while (extractLongestSegment() && ++segmentsFound < maxNumSegments) {}

	return parseVolumeSkeleton();
}

void
Skeletonize::findBoundaryNodes() {

	for (GraphVolume::NodeIt node(_graphVolume.graph()); node != lemon::INVALID; ++node) {

		int numNeighbors = 0;
		for (GraphVolume::IncEdgeIt e(_graphVolume.graph(), node); e != lemon::INVALID; ++e)
			numNeighbors++;

		if (numNeighbors != GraphVolume::NumNeighbors) {

			_boundary.push_back(node);
			_nodeLabels[node] = Boundary;
		}
	}
}

void
Skeletonize::initializeEdgeMap() {

	// the pitch is the number of units per voxel dimension
	float pitch[3];
	pitch[0] = _graphVolume.getResolutionX();
	pitch[1] = _graphVolume.getResolutionY();
	pitch[2] = _graphVolume.getResolutionZ();

	_boundaryDistance = 0;
	for (GraphVolume::NodeIt n(_graphVolume.graph()); n != lemon::INVALID; ++n)
		boundaryDistance(_graphVolume.positions()[n]) = 1.0;

	if (_graphVolume.getDiscreteBoundingBox().depth() == 1) {

		LOG_DEBUG(skeletonizelog) << "performing 2D distance transform for boundary penalty" << std::endl;

		// perform 2D distance transform if depth is 1
		vigra::separableMultiDistSquared(
				_boundaryDistance.bind<2>(1), // only on center section (0 and 2 are padded)
				_boundaryDistance.bind<2>(1),
				false,  /* compute distance from object (non-zero) to background (0) */
				pitch);

	} else {

		vigra::separableMultiDistSquared(
				_boundaryDistance,
				_boundaryDistance,
				false,  /* compute distance from object (non-zero) to background (0) */
				pitch);
	}

	// find center point with maximal boundary distance
	_maxBoundaryDistance2 = 0;
	for (GraphVolume::NodeIt node(_graphVolume.graph()); node != lemon::INVALID; ++node) {

		const Position& pos = _graphVolume.positions()[node];
		if (boundaryDistance(pos) > _maxBoundaryDistance2) {

			_center = node;
			_maxBoundaryDistance2 = boundaryDistance(pos);
		}
	}

	// create initial edge map from boundary penalty
	for (GraphVolume::EdgeIt e(_graphVolume.graph()); e != lemon::INVALID; ++e)
		_distanceMap[e] = boundaryPenalty(
				0.5*(
						boundaryDistance(_graphVolume.positions()[_graphVolume.graph().u(e)]) +
						boundaryDistance(_graphVolume.positions()[_graphVolume.graph().v(e)])));

	// multiply with Euclidean node distances
	//
	// The TEASAR paper suggests to add the Euclidean distances. However, for
	// the penalty to be meaningful in anistotropic volumes, it should be
	// multiplied with the Euclidean distance between the nodes (otherwise, it
	// is more expensive to move in the high-resolution dimensions). Therefore,
	// the final value is
	//
	//   penalty*euclidean + euclidean = euclidean*(penalty + 1)

	float nodeDistances[8];
	nodeDistances[0] = 0;
	nodeDistances[1] = _graphVolume.getResolutionZ();
	nodeDistances[2] = _graphVolume.getResolutionY();
	nodeDistances[3] = sqrt(pow(_graphVolume.getResolutionY(), 2) + pow(_graphVolume.getResolutionZ(), 2));
	nodeDistances[4] = _graphVolume.getResolutionX();
	nodeDistances[5] = sqrt(pow(_graphVolume.getResolutionX(), 2) + pow(_graphVolume.getResolutionZ(), 2));
	nodeDistances[6] = sqrt(pow(_graphVolume.getResolutionX(), 2) + pow(_graphVolume.getResolutionY(), 2));
	nodeDistances[7] = sqrt(pow(_graphVolume.getResolutionX(), 2) + pow(_graphVolume.getResolutionY(), 2) + pow(_graphVolume.getResolutionZ(), 2));

	for (GraphVolume::EdgeIt e(_graphVolume.graph()); e != lemon::INVALID; ++e) {

		Position u = _graphVolume.positions()[_graphVolume.graph().u(e)];
		Position v = _graphVolume.positions()[_graphVolume.graph().v(e)];

		int i = 0;
		if (u[0] != v[0]) i |= 4;
		if (u[1] != v[1]) i |= 2;
		if (u[2] != v[2]) i |= 1;

		_distanceMap[e] = nodeDistances[i]*(_distanceMap[e] + 1);
	}
}

void
Skeletonize::findRoot() {

	_dijkstra.run(_center);

	// find furthest point on boundary
	_root = GraphVolume::NodeIt(_graphVolume.graph());
	float maxValue = -1;
	for (GraphVolume::Node n : _boundary) {
		if (_dijkstra.distMap()[n] > maxValue) {

			_root    = n;
			maxValue = _dijkstra.distMap()[n];
		}
	}

	if (maxValue == -1)
		UTIL_THROW_EXCEPTION(
				NoNodeFound,
				"could not find a root boundary point");

	// mark root as being part of skeleton
	_nodeLabels[_root] = OnSkeleton;
}

bool
Skeletonize::extractLongestSegment() {

	_dijkstra.run(_root);

	// find furthest point on boundary
	GraphVolume::Node furthest = GraphVolume::NodeIt(_graphVolume.graph());
	float maxValue = -1;
	for (GraphVolume::Node n : _boundary) {

		if (_skipExplainedNodes && _nodeLabels[n] == Explained)
			continue;

		if (_dijkstra.distMap()[n] > maxValue) {

			furthest = n;
			maxValue = _dijkstra.distMap()[n];
		}
	}

	// no more points or length smaller then min segment length
	if (maxValue == -1 || maxValue < _minSegmentLength)
		return false;

	LOG_DEBUG(skeletonizelog) << "extracting segment with length " << maxValue << std::endl;

	GraphVolume::Node n = furthest;

	// walk backwards to next skeleton point
	while (_nodeLabels[n] != OnSkeleton) {

		_nodeLabels[n] = OnSkeleton;

		if (_skipExplainedNodes)
			drawExplanationSphere(_graphVolume.positions()[n]);

		GraphVolume::Edge pred = _dijkstra.predMap()[n];
		GraphVolume::Node u = _graphVolume.graph().u(pred);
		GraphVolume::Node v = _graphVolume.graph().v(pred);

		n = (u == n ? v : u);

		_distanceMap[pred] = 0.0;
	}

	// first segment?
	if (n == _root) {

		LOG_DEBUG(skeletonizelog) << "longest segment has length " << maxValue << std::endl;

		_minSegmentLength = std::max(_minSegmentLength, _minSegmentLengthRatio*maxValue);

		LOG_DEBUG(skeletonizelog) << "setting min segment length to " << _minSegmentLength << std::endl;
	}

	return true;
}

void
Skeletonize::drawExplanationSphere(const Position& center) {

	double radius2 = boundaryDistance(center)*pow(_explanationWeight, 2);

	double resX2 = pow(_graphVolume.getResolutionX(), 2);
	double resY2 = pow(_graphVolume.getResolutionY(), 2);
	double resZ2 = pow(_graphVolume.getResolutionZ(), 2);

	for (GraphVolume::Node n : _boundary) {

		const Position& pos = _graphVolume.positions()[n];
		double distance2 =
				resX2*pow(pos[0] - center[0], 2) +
				resY2*pow(pos[1] - center[1], 2) +
				resZ2*pow(pos[2] - center[2], 2);

		if (distance2 <= radius2)
			if (_nodeLabels[n] != OnSkeleton)
				_nodeLabels[n] = Explained;
	}
}

double
Skeletonize::boundaryPenalty(double boundaryDistance) {

	// penalty = w*(1.0 - bd/max_bd)
	//
	//   w     : boundary weight
	//   bd    : boundary distance
	//   max_bd: max boundary distance
	return _boundaryWeight*(1.0 - sqrt(boundaryDistance/_maxBoundaryDistance2));
}

Skeleton
Skeletonize::parseVolumeSkeleton() {

	Skeleton skeleton;

	skeleton.setOffset(_graphVolume.getOffset());
	skeleton.setResolution(_graphVolume.getResolution());

	traverse(_root, skeleton);

	return skeleton;
}

// The old version of this was recursing directly and deeply, leading to stack
// overflows in stack restricted environments (e.g. multithreading).  The
// current version is a fairly direct iteratization of the old, directly
// recursive version.
void
Skeletonize::traverse(const GraphVolume::Node& root, Skeleton& skeleton) {
	// DFS of nodes from root.  Data-wise, Nodes are just integer values.
	std::stack<GraphVolume::Node> traversal;
	traversal.push(root);
	while (!traversal.empty()) {
		const GraphVolume::Node n = traversal.top();
		const int nNeighbors = numNeighbors(n);

		// Special nodes that open new segments.
		const bool isOpeningNode = n == _root || nNeighbors != 2;

		// The second time we see a node, we are in back-traversal, popping from
		// traversal stack and potentially closing segments.
		if (_nodeLabels[n] == Visited) {
			if (isOpeningNode) skeleton.closeSegment();
			traversal.pop();
			continue;
		}

		// Otherwise, we're seeing the node for the first time, so opening /
		// extending segment.
		_nodeLabels[n] = Visited;
		const Position pos = _graphVolume.positions()[n];
		const float boundDist = sqrt(boundaryDistance(pos));
		if (isOpeningNode) {
			skeleton.openSegment(pos, boundDist);
		} else {
			skeleton.extendSegment(pos, boundDist);
		}

		// Iterate through neighbors and put unseen ones onto traversal stack.  The
		// loop checks against nNeighbors to allow early termination.
		GraphVolume::IncEdgeIt e(_graphVolume.graph(), n);
		for (int i = 0; i < nNeighbors; ++e /* increment e, not i */) {
			assert(e != lemon::INVALID);  // Should never occur.

			// Only increment i if we are using this edge.
			if (_distanceMap[e] != 0.0) continue;
			++i;

			const GraphVolume::Node neighbor = (_graphVolume.graph().u(e) == n ? _graphVolume.graph().v(e) : _graphVolume.graph().u(e));
			if (_nodeLabels[neighbor] != Visited) traversal.push(neighbor);
		}
	}
}

int
Skeletonize::numNeighbors(const GraphVolume::Node& n) {

	int num = 0;

	for (GraphVolume::IncEdgeIt e(_graphVolume.graph(), n); e != lemon::INVALID; ++e)
		if (_distanceMap[e] == 0.0)
			num++;

	return num;
}

<|endoftext|>


<commit_before>#include "mmapFile.h"
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#ifdef ENABLE_UDC
extern "C" {
#include "common.h"
#include "udc.h"
}
#endif

/* constants for header */
static const std::string FORMAT_NAME = "HAL-MMAP";
static const std::string MMAP_VERSION = "1.0";

/* is file a URL that requires UDC? */
static bool isUdcUrl(const std::string alignmentPath) {
    return (alignmentPath.find("http:") == 0) or (alignmentPath.find("https:") == 0)
        or (alignmentPath.find("ftp:") == 0);
}

/* get the file size from the OS */
static size_t getFileStatSize(int fd) {
    struct stat fileStat;
    if (::fstat(fd, &fileStat) < 0) {
        throw hal_errno_exception("stat failed", errno);
    }
    return fileStat.st_size;
}

/* constructor, used only by derived classes */
hal::MMapFile::MMapFile(const std::string alignmentPath,
                        unsigned mode):
    _alignmentPath(alignmentPath),  _mode(halDefaultAccessMode(mode)),
    _basePtr(NULL), _fileSize(0), _mustFetch(false) {
}

/* error if file is not open for write accecss */
void hal::MMapFile::validateWriteAccess() const {
    if ((_mode & WRITE_ACCESS) == 0) {
        throw hal_exception(_alignmentPath + " is not open for write access");
    }
}

/* setup pointer to header */
void hal::MMapFile::setHeaderPtr() {
    fetchIfNeeded(0, sizeof(mmapHeader));
    _header = static_cast<mmapHeader*>(_basePtr);
}

/* validate the file header and save a pointer to it. */
void hal::MMapFile::loadHeader(bool markDirty) {
    if (_fileSize < sizeof(mmapHeader)) {
        throw hal_exception(_alignmentPath + ": file size of " + std::to_string(_fileSize)
                            + " is less that header size of " + std::to_string(sizeof(mmapHeader)));
    }
    setHeaderPtr();

    // don't print found strings as it might have garbage
    if (::strcmp(_header->format, FORMAT_NAME.c_str()) != 0) {
        throw hal_exception(_alignmentPath + ": invalid file header, expected format name of '" +
                            FORMAT_NAME + "'");
    }
    // FIXME: to need to check version compatibility
    if (::strcmp(_header->mmapVersion, MMAP_VERSION.c_str()) != 0) {
        throw hal_exception(_alignmentPath + ": incompatible mmap format versions: "
                            + "file version " + _header->mmapVersion
                            + ", mmap API version " + MMAP_VERSION);
    }
    if ((_header->nextOffset < sizeof(mmapHeader)) or (_header->nextOffset > _fileSize)) {
        throw hal_exception(_alignmentPath + ": header nextOffset field out of bounds, probably file corruption");
    }
    if ((_header->rootOffset < sizeof(mmapHeader)) or (_header->rootOffset > _fileSize)) {
        throw hal_exception(_alignmentPath + ": header rootOffset field out of bounds, probably file corruption");
    }
    if (_header->dirty) {
        throw hal_exception(_alignmentPath + ": file is marked as dirty, most likely an inconsistent state.");
    }
    if (markDirty) {
        _header->dirty = true;
    }
}

/* create the header */
void hal::MMapFile::createHeader() {
    assert(_mode & WRITE_ACCESS);
    setHeaderPtr();
    assert(FORMAT_NAME.size() < sizeof(_header->format));
    strncpy(_header->format, FORMAT_NAME.c_str(), sizeof(_header->format)-1);
    assert(MMAP_VERSION.size() < sizeof(_header->mmapVersion));
    strncpy(_header->mmapVersion, MMAP_VERSION.c_str(), sizeof(_header->mmapVersion)-1);
    assert(HAL_VERSION.size() < sizeof(_header->halVersion));
    strncpy(_header->halVersion, HAL_VERSION.c_str(), sizeof(_header->halVersion)-1);
    _header->nextOffset = alignRound(sizeof(mmapHeader));
    _header->dirty = true;
    _header->nextOffset = _header->nextOffset;
}

/* Grow file to allow for at least the specified amount.  This remaps the *
 * file, so the same sufficient virtual space must be available at the address
 * and it is expensive. */
void hal::MMapFile::growFile(size_t size) {
    assert(_mode & WRITE_ACCESS);
    growFileImpl(size);
}

/* override this for classes that support growing file */
void hal::MMapFile::growFileImpl(size_t size) {
    throw hal_exception("logic error: growFile() not available for this MMapFile implementation");
}

namespace hal {
    /* Class that implements local file version of MMapFile */
    class MMapFileLocal: public MMapFile {
        public:
        MMapFileLocal(const std::string& alignmentPath,
                      unsigned mode,
                      size_t initSize,
                      size_t growSize);
        virtual void close();
        virtual ~MMapFileLocal();

        private:
        int openFile();
        void closeFile();
        void adjustFileSize(size_t size);
        void* mapFile(void *requiredAddr=NULL);
        void unmapFile();
        void openRead();
        void openWrite(size_t initSize);
        void growFileImpl(size_t size);

        int _fd;              // open file descriptor
        size_t _growSize;     // amount to grow file by when needed.
    };
}

/* Constructor. Open or create the specified file. */
hal::MMapFileLocal::MMapFileLocal(const std::string& alignmentPath,
                                  unsigned mode,
                                  size_t initSize,
                                  size_t growSize):
    MMapFile(alignmentPath, mode), _fd(-1), _growSize(growSize) {
    if (_mode & WRITE_ACCESS) {
        openWrite(initSize);
    } else {
        openRead();
    }
}

/* close file, marking as clean.  Don't  */
void hal::MMapFileLocal::close() {
    if (_basePtr == NULL) {
        throw hal_exception(_alignmentPath + ": MMapFile::close() called on closed file");
    }
    if (_mode & WRITE_ACCESS) {
        adjustFileSize(_header->nextOffset);
        _header->dirty = false;
    }
    unmapFile();
    closeFile();
}

/* Destructor. write fields to header and close.  If write access and close
 * has not been called, file will me left mark dirty */
hal::MMapFileLocal::~MMapFileLocal() {
    unmapFile();
    closeFile();
}

/* open the file for the specified mode */
int hal::MMapFileLocal::openFile() {
    assert(_fd < 0);
    unsigned openMode = 0;
    if (_mode & WRITE_ACCESS) {
        openMode = O_RDWR | ((_mode & CREATE_ACCESS) ? (O_CREAT|O_TRUNC) : 0);
    } else {
        openMode = O_RDONLY;
    }
    int fd = ::open(_alignmentPath.c_str(), openMode, 0777);
    if (fd < 0) {
        throw hal_errno_exception(_alignmentPath, "open failed", errno);
    }
    return fd;
}

/* change size size of the file, possibly deleting data. */
void hal::MMapFileLocal::adjustFileSize(size_t size) {
    if (ftruncate(_fd, size) < 0) {
        throw hal_errno_exception(_alignmentPath, "set size failed", errno);
    }
    _fileSize = size;
}

/* map file into memory */
void* hal::MMapFileLocal::mapFile(void *requiredAddr) {
    assert(_basePtr == NULL);
    unsigned prot = PROT_READ | ((_mode & WRITE_ACCESS) ? PROT_WRITE : 0);
    void *ptr = mmap(requiredAddr, _fileSize, prot, MAP_SHARED|MAP_FILE, _fd, 0);
    if (ptr == MAP_FAILED) {
        throw hal_errno_exception(_alignmentPath, "mmap failed", errno);
    }
    return ptr;
}

/* unmap file, if mapped */
void hal::MMapFileLocal::unmapFile() {
    if (_basePtr != NULL) {
        if (::munmap(const_cast<void*>(_basePtr), _fileSize) < 0) {
            throw hal_errno_exception(_alignmentPath, "munmap failed", errno);
        }
        _basePtr = NULL;
    }
}

/* open the file for read access */
void hal::MMapFileLocal::openRead() {
    _fd = openFile();
    _fileSize = getFileStatSize(_fd);
    _basePtr = mapFile();
    loadHeader(false);
}

/* open the file for write access */
void hal::MMapFileLocal::openWrite(size_t initSize) {
    _fd = openFile();
    if (_mode & CREATE_ACCESS) {
        adjustFileSize(0);  // clear out existing data
    }
    if (initSize > _fileSize) {
        adjustFileSize(initSize);
    }
    _basePtr = mapFile();
    if (_mode & CREATE_ACCESS) {
        createHeader();
    } else {
        loadHeader(true);
    }
}

/* close the file if open */
void hal::MMapFileLocal::closeFile() {
    if (_fd >= 0) {
        if (::close(_fd) < 0) {
            throw hal_errno_exception(_alignmentPath, "close failed", errno);
        }
        _fd = -1;
    }
}

/* grow file  */
void hal::MMapFileLocal::growFileImpl(size_t size) {
    assert(_mode & WRITE_ACCESS);
    size_t newSize = _growSize;
    if (newSize < size) {
        newSize += size;  // will leave in extra
    }
    void * requiredAddr = _basePtr;
    unmapFile();
    mapFile(requiredAddr);
}

namespace hal {
    /* Class that implements UDC file version of MMapFile */
    class MMapFileUdc: public MMapFile {
        public:
        MMapFileUdc(const std::string& alignmentPath,
                    unsigned mode,
                    size_t initSize,
                    size_t growSize,
                    const std::string& udcCacheDir);
        virtual void close();
        virtual ~MMapFileUdc();

        protected:
        virtual void fetch(size_t offset,
                           size_t accessSize) const;

        private:
        struct udcFile *_udcFile;
    };
}

/* Constructor. Open or create the specified file. */
hal::MMapFileUdc::MMapFileUdc(const std::string& alignmentPath,
                              unsigned mode,
                              size_t initSize,
                              size_t growSize,
                              const std::string& udcCacheDir):
    MMapFile(alignmentPath, mode), _udcFile(NULL) {
    if (_mode & WRITE_ACCESS) {
        throw hal_exception("write access not supported for UDC:" + alignmentPath);
    }
    _udcFile = udcFileOpen(const_cast<char*>(alignmentPath.c_str()),
                           (udcCacheDir.empty()) ? NULL : const_cast<char*>(udcCacheDir.c_str()));
    // get base point and fetch header in one move.
    _basePtr = udcMMapFetch(_udcFile, 0, sizeof(mmapHeader));
}

/* close file, marking as clean.  Don't  */
void hal::MMapFileUdc::close() {
    if (_basePtr == NULL) {
        throw hal_exception(_alignmentPath + ": MMapFile::close() called on closed file");
    }
    udcFileClose(&_udcFile);
}

/* Destructor. write fields to header and close.  If write access and close
 * has not been called, file will me left mark dirty */
hal::MMapFileUdc::~MMapFileUdc() {
    if (_udcFile != NULL) {
        udcFileClose(&_udcFile);
    }
}

/* fetch into UDC cache */
void hal::MMapFileUdc::fetch(size_t offset,
                             size_t accessSize) const {
    udcMMapFetch(_udcFile, offset, accessSize);
}

/** create a MMapFile object, opening a local file */
hal::MMapFile *hal::MMapFile::factory(const std::string& alignmentPath,
                                      unsigned mode,
                                      size_t initSize,
                                      size_t growSize,
                                      const std::string& udcCacheDir) {
    if (isUdcUrl(alignmentPath)) {
        if (mode & (CREATE_ACCESS | WRITE_ACCESS)) {
            throw hal_exception("create or write access not support with URL: " + alignmentPath);
        }
#ifdef ENABLE_UDC
        return new MMapFileUdc(alignmentPath, mode, initSize, growSize, udcCacheDir);
#else
        throw hal_exception("URL access requires UDC support to be compiled into HAL library: " + alignmentPath);
#endif
    } else {
        return new MMapFileLocal(alignmentPath, mode, initSize, growSize);
    }
}

<commit_msg>Fix compilation when ENABLE_UDC is undefined<commit_after>#include "mmapFile.h"
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#ifdef ENABLE_UDC
extern "C" {
#include "common.h"
#include "udc.h"
}
#endif

/* constants for header */
static const std::string FORMAT_NAME = "HAL-MMAP";
static const std::string MMAP_VERSION = "1.0";

/* is file a URL that requires UDC? */
static bool isUdcUrl(const std::string alignmentPath) {
    return (alignmentPath.find("http:") == 0) or (alignmentPath.find("https:") == 0)
        or (alignmentPath.find("ftp:") == 0);
}

/* get the file size from the OS */
static size_t getFileStatSize(int fd) {
    struct stat fileStat;
    if (::fstat(fd, &fileStat) < 0) {
        throw hal_errno_exception("stat failed", errno);
    }
    return fileStat.st_size;
}

/* constructor, used only by derived classes */
hal::MMapFile::MMapFile(const std::string alignmentPath,
                        unsigned mode):
    _alignmentPath(alignmentPath),  _mode(halDefaultAccessMode(mode)),
    _basePtr(NULL), _fileSize(0), _mustFetch(false) {
}

/* error if file is not open for write accecss */
void hal::MMapFile::validateWriteAccess() const {
    if ((_mode & WRITE_ACCESS) == 0) {
        throw hal_exception(_alignmentPath + " is not open for write access");
    }
}

/* setup pointer to header */
void hal::MMapFile::setHeaderPtr() {
    fetchIfNeeded(0, sizeof(mmapHeader));
    _header = static_cast<mmapHeader*>(_basePtr);
}

/* validate the file header and save a pointer to it. */
void hal::MMapFile::loadHeader(bool markDirty) {
    if (_fileSize < sizeof(mmapHeader)) {
        throw hal_exception(_alignmentPath + ": file size of " + std::to_string(_fileSize)
                            + " is less that header size of " + std::to_string(sizeof(mmapHeader)));
    }
    setHeaderPtr();

    // don't print found strings as it might have garbage
    if (::strcmp(_header->format, FORMAT_NAME.c_str()) != 0) {
        throw hal_exception(_alignmentPath + ": invalid file header, expected format name of '" +
                            FORMAT_NAME + "'");
    }
    // FIXME: to need to check version compatibility
    if (::strcmp(_header->mmapVersion, MMAP_VERSION.c_str()) != 0) {
        throw hal_exception(_alignmentPath + ": incompatible mmap format versions: "
                            + "file version " + _header->mmapVersion
                            + ", mmap API version " + MMAP_VERSION);
    }
    if ((_header->nextOffset < sizeof(mmapHeader)) or (_header->nextOffset > _fileSize)) {
        throw hal_exception(_alignmentPath + ": header nextOffset field out of bounds, probably file corruption");
    }
    if ((_header->rootOffset < sizeof(mmapHeader)) or (_header->rootOffset > _fileSize)) {
        throw hal_exception(_alignmentPath + ": header rootOffset field out of bounds, probably file corruption");
    }
    if (_header->dirty) {
        throw hal_exception(_alignmentPath + ": file is marked as dirty, most likely an inconsistent state.");
    }
    if (markDirty) {
        _header->dirty = true;
    }
}

/* create the header */
void hal::MMapFile::createHeader() {
    assert(_mode & WRITE_ACCESS);
    setHeaderPtr();
    assert(FORMAT_NAME.size() < sizeof(_header->format));
    strncpy(_header->format, FORMAT_NAME.c_str(), sizeof(_header->format)-1);
    assert(MMAP_VERSION.size() < sizeof(_header->mmapVersion));
    strncpy(_header->mmapVersion, MMAP_VERSION.c_str(), sizeof(_header->mmapVersion)-1);
    assert(HAL_VERSION.size() < sizeof(_header->halVersion));
    strncpy(_header->halVersion, HAL_VERSION.c_str(), sizeof(_header->halVersion)-1);
    _header->nextOffset = alignRound(sizeof(mmapHeader));
    _header->dirty = true;
    _header->nextOffset = _header->nextOffset;
}

/* Grow file to allow for at least the specified amount.  This remaps the *
 * file, so the same sufficient virtual space must be available at the address
 * and it is expensive. */
void hal::MMapFile::growFile(size_t size) {
    assert(_mode & WRITE_ACCESS);
    growFileImpl(size);
}

/* override this for classes that support growing file */
void hal::MMapFile::growFileImpl(size_t size) {
    throw hal_exception("logic error: growFile() not available for this MMapFile implementation");
}

namespace hal {
    /* Class that implements local file version of MMapFile */
    class MMapFileLocal: public MMapFile {
        public:
        MMapFileLocal(const std::string& alignmentPath,
                      unsigned mode,
                      size_t initSize,
                      size_t growSize);
        virtual void close();
        virtual ~MMapFileLocal();

        private:
        int openFile();
        void closeFile();
        void adjustFileSize(size_t size);
        void* mapFile(void *requiredAddr=NULL);
        void unmapFile();
        void openRead();
        void openWrite(size_t initSize);
        void growFileImpl(size_t size);

        int _fd;              // open file descriptor
        size_t _growSize;     // amount to grow file by when needed.
    };
}

/* Constructor. Open or create the specified file. */
hal::MMapFileLocal::MMapFileLocal(const std::string& alignmentPath,
                                  unsigned mode,
                                  size_t initSize,
                                  size_t growSize):
    MMapFile(alignmentPath, mode), _fd(-1), _growSize(growSize) {
    if (_mode & WRITE_ACCESS) {
        openWrite(initSize);
    } else {
        openRead();
    }
}

/* close file, marking as clean.  Don't  */
void hal::MMapFileLocal::close() {
    if (_basePtr == NULL) {
        throw hal_exception(_alignmentPath + ": MMapFile::close() called on closed file");
    }
    if (_mode & WRITE_ACCESS) {
        adjustFileSize(_header->nextOffset);
        _header->dirty = false;
    }
    unmapFile();
    closeFile();
}

/* Destructor. write fields to header and close.  If write access and close
 * has not been called, file will me left mark dirty */
hal::MMapFileLocal::~MMapFileLocal() {
    unmapFile();
    closeFile();
}

/* open the file for the specified mode */
int hal::MMapFileLocal::openFile() {
    assert(_fd < 0);
    unsigned openMode = 0;
    if (_mode & WRITE_ACCESS) {
        openMode = O_RDWR | ((_mode & CREATE_ACCESS) ? (O_CREAT|O_TRUNC) : 0);
    } else {
        openMode = O_RDONLY;
    }
    int fd = ::open(_alignmentPath.c_str(), openMode, 0777);
    if (fd < 0) {
        throw hal_errno_exception(_alignmentPath, "open failed", errno);
    }
    return fd;
}

/* change size size of the file, possibly deleting data. */
void hal::MMapFileLocal::adjustFileSize(size_t size) {
    if (ftruncate(_fd, size) < 0) {
        throw hal_errno_exception(_alignmentPath, "set size failed", errno);
    }
    _fileSize = size;
}

/* map file into memory */
void* hal::MMapFileLocal::mapFile(void *requiredAddr) {
    assert(_basePtr == NULL);
    unsigned prot = PROT_READ | ((_mode & WRITE_ACCESS) ? PROT_WRITE : 0);
    void *ptr = mmap(requiredAddr, _fileSize, prot, MAP_SHARED|MAP_FILE, _fd, 0);
    if (ptr == MAP_FAILED) {
        throw hal_errno_exception(_alignmentPath, "mmap failed", errno);
    }
    return ptr;
}

/* unmap file, if mapped */
void hal::MMapFileLocal::unmapFile() {
    if (_basePtr != NULL) {
        if (::munmap(const_cast<void*>(_basePtr), _fileSize) < 0) {
            throw hal_errno_exception(_alignmentPath, "munmap failed", errno);
        }
        _basePtr = NULL;
    }
}

/* open the file for read access */
void hal::MMapFileLocal::openRead() {
    _fd = openFile();
    _fileSize = getFileStatSize(_fd);
    _basePtr = mapFile();
    loadHeader(false);
}

/* open the file for write access */
void hal::MMapFileLocal::openWrite(size_t initSize) {
    _fd = openFile();
    if (_mode & CREATE_ACCESS) {
        adjustFileSize(0);  // clear out existing data
    }
    if (initSize > _fileSize) {
        adjustFileSize(initSize);
    }
    _basePtr = mapFile();
    if (_mode & CREATE_ACCESS) {
        createHeader();
    } else {
        loadHeader(true);
    }
}

/* close the file if open */
void hal::MMapFileLocal::closeFile() {
    if (_fd >= 0) {
        if (::close(_fd) < 0) {
            throw hal_errno_exception(_alignmentPath, "close failed", errno);
        }
        _fd = -1;
    }
}

/* grow file  */
void hal::MMapFileLocal::growFileImpl(size_t size) {
    assert(_mode & WRITE_ACCESS);
    size_t newSize = _growSize;
    if (newSize < size) {
        newSize += size;  // will leave in extra
    }
    void * requiredAddr = _basePtr;
    unmapFile();
    mapFile(requiredAddr);
}

#ifdef ENABLE_UDC
namespace hal {
    /* Class that implements UDC file version of MMapFile */
    class MMapFileUdc: public MMapFile {
        public:
        MMapFileUdc(const std::string& alignmentPath,
                    unsigned mode,
                    size_t initSize,
                    size_t growSize,
                    const std::string& udcCacheDir);
        virtual void close();
        virtual ~MMapFileUdc();

        protected:
        virtual void fetch(size_t offset,
                           size_t accessSize) const;

        private:
        struct udcFile *_udcFile;
    };
}

/* Constructor. Open or create the specified file. */
hal::MMapFileUdc::MMapFileUdc(const std::string& alignmentPath,
                              unsigned mode,
                              size_t initSize,
                              size_t growSize,
                              const std::string& udcCacheDir):
    MMapFile(alignmentPath, mode), _udcFile(NULL) {
    if (_mode & WRITE_ACCESS) {
        throw hal_exception("write access not supported for UDC:" + alignmentPath);
    }
    _udcFile = udcFileOpen(const_cast<char*>(alignmentPath.c_str()),
                           (udcCacheDir.empty()) ? NULL : const_cast<char*>(udcCacheDir.c_str()));
    // get base point and fetch header in one move.
    _basePtr = udcMMapFetch(_udcFile, 0, sizeof(mmapHeader));
}

/* close file, marking as clean.  Don't  */
void hal::MMapFileUdc::close() {
    if (_basePtr == NULL) {
        throw hal_exception(_alignmentPath + ": MMapFile::close() called on closed file");
    }
    udcFileClose(&_udcFile);
}

/* Destructor. write fields to header and close.  If write access and close
 * has not been called, file will me left mark dirty */
hal::MMapFileUdc::~MMapFileUdc() {
    if (_udcFile != NULL) {
        udcFileClose(&_udcFile);
    }
}

/* fetch into UDC cache */
void hal::MMapFileUdc::fetch(size_t offset,
                             size_t accessSize) const {
    udcMMapFetch(_udcFile, offset, accessSize);
}

#endif

/** create a MMapFile object, opening a local file */
hal::MMapFile *hal::MMapFile::factory(const std::string& alignmentPath,
                                      unsigned mode,
                                      size_t initSize,
                                      size_t growSize,
                                      const std::string& udcCacheDir) {
    if (isUdcUrl(alignmentPath)) {
        if (mode & (CREATE_ACCESS | WRITE_ACCESS)) {
            throw hal_exception("create or write access not support with URL: " + alignmentPath);
        }
#ifdef ENABLE_UDC
        return new MMapFileUdc(alignmentPath, mode, initSize, growSize, udcCacheDir);
#else
        throw hal_exception("URL access requires UDC support to be compiled into HAL library: " + alignmentPath);
#endif
    } else {
        return new MMapFileLocal(alignmentPath, mode, initSize, growSize);
    }
}

<|endoftext|>