<commit_before>/** Copyright (c) 2013, Sean Kasun */

#include <algorithm>    // std::max

#include "./chunk.h"
#include "./flatteningconverter.h"
#include "./blockidentifier.h"

Chunk::Chunk()
  : version(0)
  , highest(0)
  , loaded(false)
  , rendering(false)
{}

Chunk::~Chunk() {
  if (loaded) {
    for (int i = 0; i < 16; i++)
      if (sections[i]) {
        if (sections[i]->paletteLength > 0) {
          delete[] sections[i]->palette;
        }
        sections[i]->paletteLength = 0;
        sections[i]->palette = NULL;

        delete sections[i];
        sections[i] = NULL;
      }
    loaded = false;
  }
}

int Chunk::get_biome(int x, int z) {
  return get_biome(x, 64, z);
}

int Chunk::get_biome(int x, int y, int z) {
  int offset;

  if (this->version >= 2203) {
    // Minecraft 1.15 has Y dependand Biome
    int x_idx = x >> 2;
    int y_idx = y >> 2;
    int z_idx = z >> 2;
    offset = x_idx + 4*z_idx + 16*y_idx;
  } else {
    // Minecraft <1.15 has fixed Biome per collumn
    offset = x + 16*z;
  }

  return get_biome(offset);
}

int Chunk::get_biome(int offset) {
  return this->biomes[offset];
}

void Chunk::load(const NBT &nbt) {
  renderedAt = -1;  // impossible.
  renderedFlags = 0;  // no flags
  for (int i = 0; i < 16; i++)
    this->sections[i] = NULL;

  if (nbt.has("DataVersion"))
    this->version = nbt.at("DataVersion")->toInt();
  const Tag * level = nbt.at("Level");
  chunkX = level->at("xPos")->toInt();
  chunkZ = level->at("zPos")->toInt();

  // load Biome data
  if (level->has("Biomes")) {
    const Tag_Int_Array * biomes = dynamic_cast<const Tag_Int_Array*>(level->at("Biomes"));
    if (biomes) {  // Biomes is a Tag_Int_Array
      if ((this->version >= 2203)) {
        // raw copy Biome data
        memcpy(this->biomes, biomes->toIntArray(), sizeof(int)*1024);
      } else if ((this->version >= 1519)) {
        // raw copy Biome data
        memcpy(this->biomes, biomes->toIntArray(), sizeof(int)*256);
      }
    } else {  // Biomes is not a Tag_Int_Array
      const Tag_Byte_Array * biomes = dynamic_cast<const Tag_Byte_Array*>(level->at("Biomes"));
      // convert quint8 to quint32
      auto rawBiomes = biomes->toByteArray();
      for (int i=0; i<256; i++) {
        this->biomes[i] = rawBiomes[i];
      }
    }
  } else {  // no Biome data present
    for (int i=0; i<16*16*4; i++)
      this->biomes[i] = -1;
  }

  // load available Sections
  if (level->has("Sections")) {
    auto sections = level->at("Sections");
    int numSections = sections->length();
    // loop over all stored Sections, they are not guarantied to be ordered or consecutive
    for (int s = 0; s < numSections; s++) {
      const Tag * section = sections->at(s);
      int idx = section->at("Y")->toInt();
      // only sections 0..15 contain block data
      if ((idx >=0) && (idx <16)) {
        ChunkSection *cs = new ChunkSection();
        if (this->version >= 1519) {
          loadSection1519(cs, section);
        } else {
          loadSection1343(cs, section);
        }

        this->sections[idx] = cs;
      }
    }
  }

  // parse Structures that start in this Chunk
  if (version >= 1519) {
    if (level->has("Structures")) {
      auto nbtListStructures = level->at("Structures");
      auto structurelist     = GeneratedStructure::tryParseChunk(nbtListStructures);
      for (auto it = structurelist.begin(); it != structurelist.end(); ++it) {
        emit structureFound(*it);
      }
    }
  }

  loaded = true;

  // parse Entities
  if (level->has("Entities")) {
    auto entitylist = level->at("Entities");
    int numEntities = entitylist->length();
    for (int i = 0; i < numEntities; ++i) {
      auto e = Entity::TryParse(entitylist->at(i));
      if (e)
        entities.insertMulti(e->type(), e);
    }
  }

  // check for the highest block in this chunk
  // todo: use highmap from stored NBT data
  for (int i = 15; i >= 0; i--) {
    if (this->sections[i]) {
      for (int j = 4095; j >= 0; j--) {
        if (this->sections[i]->blocks[j]) {
          highest = i * 16 + (j >> 8);
          return;
        }
      }
    }
  }
}

const Chunk::EntityMap &Chunk::getEntityMap() const {
  return entities;
}

const ChunkSection *Chunk::getSectionByY(int y) const {
  size_t section_idx = static_cast<size_t>(y) >> 4;
  if (section_idx >= sections.size())
    return nullptr;

  return sections[section_idx];
}

uint Chunk::getBlockHid(int x, int y, int z) const {
  const ChunkSection * const section = getSectionByY(y);
  if (!section) {
    return 0;
  }

  const PaletteEntry& pdata = section->getPaletteEntry(x, y, z);

  return pdata.hid;
}

// supported DataVersions:
//    0 = 1.8 and below
//
//  169 = 1.9
//  175 = 1.9.1
//  176 = 1.9.2
//  183 = 1.9.3
//  184 = 1.9.4
//
//  510 = 1.10
//  511 = 1.10.1
//  512 = 1.10.2
//
//  819 = 1.11
//  921 = 1.11.1
//  922 = 1.11.2
//
// 1139 = 1.12
// 1241 = 1.12.1
// 1343 = 1.12.2
//
// 1519 = 1.13
// 1628 = 1.13.1
// 2203 = 1.15.19w36a
void Chunk::loadSection1343(ChunkSection *cs, const Tag *section) {
  // copy raw data
  quint8 blocks[4096];
  quint8 data[2048];
  memcpy(blocks, section->at("Blocks")->toByteArray(), 4096);
  memcpy(data,   section->at("Data")->toByteArray(),   2048);
  memcpy(cs->blockLight, section->at("BlockLight")->toByteArray(), 2048);

  // convert old BlockID + data into virtual ID
  for (int i = 0; i < 4096; i++) {
    int d = data[i>>1];         // get raw data (two nibbles)
    if (i & 1) d >>= 4;         // get one nibble of data
    cs->blocks[i] = blocks[i] | ((d & 0x0f) << 8);
  }

  // parse optional "Add" part for higher block IDs in mod packs
  if (section->has("Add")) {
    auto raw = section->at("Add")->toByteArray();
    for (int i = 0; i < 2048; i++) {
      cs->blocks[i * 2] |= (raw[i] & 0xf) << 8;
      cs->blocks[i * 2 + 1] |= (raw[i] & 0xf0) << 4;
    }
  }

  // link to Converter palette
  cs->paletteLength = 0;
  cs->palette = FlatteningConverter::Instance().getPalette();
}

// Chunk format after "The Flattening" version 1519
void Chunk::loadSection1519(ChunkSection *cs, const Tag *section) {
  BlockIdentifier &bi = BlockIdentifier::Instance();
  // decode Palette to be able to map BlockStates
  if (section->has("Palette")) {
    auto rawPalette = section->at("Palette");
    cs->paletteLength = rawPalette->length();
    cs->palette = new PaletteEntry[cs->paletteLength];
    for (int j = 0; j < rawPalette->length(); j++) {
      // get name and hash it to hid
      cs->palette[j].name = rawPalette->at(j)->at("Name")->toString();
      uint hid  = qHash(cs->palette[j].name);
      // copy all other properties
      if (rawPalette->at(j)->has("Properties"))
      cs->palette[j].properties = rawPalette->at(j)->at("Properties")->getData().toMap();

      // check vor variants
      BlockInfo const & block = bi.getBlockInfo(hid);
      if (block.hasVariants()) {
      // test all available properties
      for (auto key : cs->palette[j].properties.keys()) {
        QString vname = cs->palette[j].name + ":" + key + ":" + cs->palette[j].properties[key].toString();
        uint vhid = qHash(vname);
        if (bi.hasBlockInfo(vhid))
          hid = vhid; // use this vaiant instead
        }
      }
      // store hash of found variant
      cs->palette[j].hid  = hid;
    }
  } else {
    // create a dummy palette
    cs->palette = new PaletteEntry[1];
    cs->palette[0].name = "minecraft:air";
    cs->palette[0].hid  = 0;
  }

  // map BlockStates to BlockData
  if (section->has("BlockStates")) {
    auto blockStates = section->at("BlockStates")->toLongArray();
    int blockStatesLength = section->at("BlockStates")->length();
    int bsCnt  = 0;  // counter for 64bit words
    int bitCnt = 0;  // counter for bits

    if (this->version < 2529) {
      // compact BlockStates
      for (int i = 0; i < 4096; i++) {
        int bitSize = (blockStatesLength)*64/4096;
        int bitMask = (1 << bitSize)-1;
        if (bitCnt+bitSize <= 64) {
          // bits fit into current word
          uint64_t blockState = blockStates[bsCnt];
          cs->blocks[i] = (blockState >> bitCnt) & bitMask;
          bitCnt += bitSize;
          if (bitCnt == 64) {
            bitCnt = 0;
            bsCnt++;
          }
        } else {
          // bits are spread accross two words
          uint64_t blockState1 = blockStates[bsCnt++];
          uint64_t blockState2 = blockStates[bsCnt];
          uint32_t block = (blockState1 >> bitCnt) & bitMask;
          bitCnt += bitSize;
          bitCnt -= 64;
          block += (blockState2 << (bitSize - bitCnt)) & bitMask;
          cs->blocks[i] = block;
        }
      }
    } else {
      // "optimized for loading" BlockStates since 1.16.20w17a
      int bitSize = std::max(4, int(ceil(log2(cs->paletteLength))));
      int bitMask = (1 << bitSize)-1;
      for (int i = 0; i < 4096; i++) {
        uint64_t blockState = blockStates[bsCnt];
        cs->blocks[i] = (blockState >> bitCnt) & bitMask;
        bitCnt += bitSize;
        if (bitCnt+bitSize > 64) {
          bsCnt++;
          bitCnt = 0;
        }
      }
    }
  } else {
    // set everything to 0 (minecraft:air)
    memset(cs->blocks, 0, sizeof(cs->blocks));
  }

    // copy Light data
//  if (section->has("SkyLight")) {
//    memcpy(cs->skyLight, section->at("SkyLight")->toByteArray(), 2048);
//  }
  if (section->has("BlockLight")) {
    memcpy(cs->blockLight, section->at("BlockLight")->toByteArray(), 2048);
  }
}

const PaletteEntry & ChunkSection::getPaletteEntry(int x, int y, int z) const {
  int xoffset = (x & 0x0f);
  int yoffset = (y & 0x0f) << 8;
  int zoffset = z << 4;
  return palette[blocks[xoffset + yoffset + zoffset]];
}

const PaletteEntry & ChunkSection::getPaletteEntry(int offset, int y) const {
  int yoffset = (y & 0x0f) << 8;
  return palette[blocks[offset + yoffset]];
}

//quint8 ChunkSection::getSkyLight(int x, int y, int z) {
//  int xoffset = x;
//  int yoffset = (y & 0x0f) << 8;
//  int zoffset = z << 4;
//  int value = skyLight[(xoffset + yoffset + zoffset) / 2];
//  if (x & 1) value >>= 4;
//  return value & 0x0f;
//}

//quint8 ChunkSection::getSkyLight(int offset, int y) {
//  int yoffset = (y & 0x0f) << 8;
//  int value = skyLight[(offset + yoffset) / 2];
//  if (offset & 1) value >>= 4;
//  return value & 0x0f;
//}

quint8 ChunkSection::getBlockLight(int x, int y, int z) const {
  int xoffset = x;
  int yoffset = (y & 0x0f) << 8;
  int zoffset = z << 4;
  int value = blockLight[(xoffset + yoffset + zoffset) / 2];
  if (x & 1) value >>= 4;
  return value & 0x0f;
}

quint8 ChunkSection::getBlockLight(int offset, int y) const {
  int yoffset = (y & 0x0f) << 8;
  int value = blockLight[(offset + yoffset) / 2];
  if (offset & 1) value >>= 4;
  return value & 0x0f;
}
<commit_msg>fix access error in getPaletteEntry<commit_after>/** Copyright (c) 2013, Sean Kasun */

#include <algorithm>    // std::max

#include "./chunk.h"
#include "./flatteningconverter.h"
#include "./blockidentifier.h"

Chunk::Chunk()
  : version(0)
  , highest(0)
  , loaded(false)
  , rendering(false)
{}

Chunk::~Chunk() {
  if (loaded) {
    for (int i = 0; i < 16; i++)
      if (sections[i]) {
        if (sections[i]->paletteLength > 0) {
          delete[] sections[i]->palette;
        }
        sections[i]->paletteLength = 0;
        sections[i]->palette = NULL;

        delete sections[i];
        sections[i] = NULL;
      }
    loaded = false;
  }
}

int Chunk::get_biome(int x, int z) {
  return get_biome(x, 64, z);
}

int Chunk::get_biome(int x, int y, int z) {
  int offset;

  if (this->version >= 2203) {
    // Minecraft 1.15 has Y dependand Biome
    int x_idx = x >> 2;
    int y_idx = y >> 2;
    int z_idx = z >> 2;
    offset = x_idx + 4*z_idx + 16*y_idx;
  } else {
    // Minecraft <1.15 has fixed Biome per collumn
    offset = x + 16*z;
  }

  return get_biome(offset);
}

int Chunk::get_biome(int offset) {
  return this->biomes[offset];
}

void Chunk::load(const NBT &nbt) {
  renderedAt = -1;  // impossible.
  renderedFlags = 0;  // no flags
  for (int i = 0; i < 16; i++)
    this->sections[i] = NULL;

  if (nbt.has("DataVersion"))
    this->version = nbt.at("DataVersion")->toInt();
  const Tag * level = nbt.at("Level");
  chunkX = level->at("xPos")->toInt();
  chunkZ = level->at("zPos")->toInt();

  // load Biome data
  if (level->has("Biomes")) {
    const Tag_Int_Array * biomes = dynamic_cast<const Tag_Int_Array*>(level->at("Biomes"));
    if (biomes) {  // Biomes is a Tag_Int_Array
      if ((this->version >= 2203)) {
        // raw copy Biome data
        memcpy(this->biomes, biomes->toIntArray(), sizeof(int)*1024);
      } else if ((this->version >= 1519)) {
        // raw copy Biome data
        memcpy(this->biomes, biomes->toIntArray(), sizeof(int)*256);
      }
    } else {  // Biomes is not a Tag_Int_Array
      const Tag_Byte_Array * biomes = dynamic_cast<const Tag_Byte_Array*>(level->at("Biomes"));
      // convert quint8 to quint32
      auto rawBiomes = biomes->toByteArray();
      for (int i=0; i<256; i++) {
        this->biomes[i] = rawBiomes[i];
      }
    }
  } else {  // no Biome data present
    for (int i=0; i<16*16*4; i++)
      this->biomes[i] = -1;
  }

  // load available Sections
  if (level->has("Sections")) {
    auto sections = level->at("Sections");
    int numSections = sections->length();
    // loop over all stored Sections, they are not guarantied to be ordered or consecutive
    for (int s = 0; s < numSections; s++) {
      const Tag * section = sections->at(s);
      int idx = section->at("Y")->toInt();
      // only sections 0..15 contain block data
      if ((idx >=0) && (idx <16)) {
        ChunkSection *cs = new ChunkSection();
        if (this->version >= 1519) {
          loadSection1519(cs, section);
        } else {
          loadSection1343(cs, section);
        }

        this->sections[idx] = cs;
      }
    }
  }

  // parse Structures that start in this Chunk
  if (version >= 1519) {
    if (level->has("Structures")) {
      auto nbtListStructures = level->at("Structures");
      auto structurelist     = GeneratedStructure::tryParseChunk(nbtListStructures);
      for (auto it = structurelist.begin(); it != structurelist.end(); ++it) {
        emit structureFound(*it);
      }
    }
  }

  loaded = true;

  // parse Entities
  if (level->has("Entities")) {
    auto entitylist = level->at("Entities");
    int numEntities = entitylist->length();
    for (int i = 0; i < numEntities; ++i) {
      auto e = Entity::TryParse(entitylist->at(i));
      if (e)
        entities.insertMulti(e->type(), e);
    }
  }

  // check for the highest block in this chunk
  // todo: use highmap from stored NBT data
  for (int i = 15; i >= 0; i--) {
    if (this->sections[i]) {
      for (int j = 4095; j >= 0; j--) {
        if (this->sections[i]->blocks[j]) {
          highest = i * 16 + (j >> 8);
          return;
        }
      }
    }
  }
}

const Chunk::EntityMap &Chunk::getEntityMap() const {
  return entities;
}

const ChunkSection *Chunk::getSectionByY(int y) const {
  size_t section_idx = static_cast<size_t>(y) >> 4;
  if (section_idx >= sections.size())
    return nullptr;

  return sections[section_idx];
}

uint Chunk::getBlockHid(int x, int y, int z) const {
  const ChunkSection * const section = getSectionByY(y);
  if (!section) {
    return 0;
  }

  const PaletteEntry& pdata = section->getPaletteEntry(x, y, z);

  return pdata.hid;
}

// supported DataVersions:
//    0 = 1.8 and below
//
//  169 = 1.9
//  175 = 1.9.1
//  176 = 1.9.2
//  183 = 1.9.3
//  184 = 1.9.4
//
//  510 = 1.10
//  511 = 1.10.1
//  512 = 1.10.2
//
//  819 = 1.11
//  921 = 1.11.1
//  922 = 1.11.2
//
// 1139 = 1.12
// 1241 = 1.12.1
// 1343 = 1.12.2
//
// 1519 = 1.13
// 1628 = 1.13.1
// 2203 = 1.15.19w36a
void Chunk::loadSection1343(ChunkSection *cs, const Tag *section) {
  // copy raw data
  quint8 blocks[4096];
  quint8 data[2048];
  memcpy(blocks, section->at("Blocks")->toByteArray(), 4096);
  memcpy(data,   section->at("Data")->toByteArray(),   2048);
  memcpy(cs->blockLight, section->at("BlockLight")->toByteArray(), 2048);

  // convert old BlockID + data into virtual ID
  for (int i = 0; i < 4096; i++) {
    int d = data[i>>1];         // get raw data (two nibbles)
    if (i & 1) d >>= 4;         // get one nibble of data
    cs->blocks[i] = blocks[i] | ((d & 0x0f) << 8);
  }

  // parse optional "Add" part for higher block IDs in mod packs
  if (section->has("Add")) {
    auto raw = section->at("Add")->toByteArray();
    for (int i = 0; i < 2048; i++) {
      cs->blocks[i * 2] |= (raw[i] & 0xf) << 8;
      cs->blocks[i * 2 + 1] |= (raw[i] & 0xf0) << 4;
    }
  }

  // link to Converter palette
  cs->paletteLength = 0;
  cs->palette = FlatteningConverter::Instance().getPalette();
}

// Chunk format after "The Flattening" version 1519
void Chunk::loadSection1519(ChunkSection *cs, const Tag *section) {
  BlockIdentifier &bi = BlockIdentifier::Instance();
  // decode Palette to be able to map BlockStates
  if (section->has("Palette")) {
    auto rawPalette = section->at("Palette");
    cs->paletteLength = rawPalette->length();
    cs->palette = new PaletteEntry[cs->paletteLength];
    for (int j = 0; j < rawPalette->length(); j++) {
      // get name and hash it to hid
      cs->palette[j].name = rawPalette->at(j)->at("Name")->toString();
      uint hid  = qHash(cs->palette[j].name);
      // copy all other properties
      if (rawPalette->at(j)->has("Properties"))
      cs->palette[j].properties = rawPalette->at(j)->at("Properties")->getData().toMap();

      // check vor variants
      BlockInfo const & block = bi.getBlockInfo(hid);
      if (block.hasVariants()) {
      // test all available properties
      for (auto key : cs->palette[j].properties.keys()) {
        QString vname = cs->palette[j].name + ":" + key + ":" + cs->palette[j].properties[key].toString();
        uint vhid = qHash(vname);
        if (bi.hasBlockInfo(vhid))
          hid = vhid; // use this vaiant instead
        }
      }
      // store hash of found variant
      cs->palette[j].hid  = hid;
    }
  } else {
    // create a dummy palette
    cs->palette = new PaletteEntry[1];
    cs->palette[0].name = "minecraft:air";
    cs->palette[0].hid  = 0;
  }

  // map BlockStates to BlockData
  if (section->has("BlockStates")) {
    auto blockStates = section->at("BlockStates")->toLongArray();
    int blockStatesLength = section->at("BlockStates")->length();
    int bsCnt  = 0;  // counter for 64bit words
    int bitCnt = 0;  // counter for bits

    if (this->version < 2529) {
      // compact BlockStates
      for (int i = 0; i < 4096; i++) {
        int bitSize = (blockStatesLength)*64/4096;
        int bitMask = (1 << bitSize)-1;
        if (bitCnt+bitSize <= 64) {
          // bits fit into current word
          uint64_t blockState = blockStates[bsCnt];
          cs->blocks[i] = (blockState >> bitCnt) & bitMask;
          bitCnt += bitSize;
          if (bitCnt == 64) {
            bitCnt = 0;
            bsCnt++;
          }
        } else {
          // bits are spread accross two words
          uint64_t blockState1 = blockStates[bsCnt++];
          uint64_t blockState2 = blockStates[bsCnt];
          uint32_t block = (blockState1 >> bitCnt) & bitMask;
          bitCnt += bitSize;
          bitCnt -= 64;
          block += (blockState2 << (bitSize - bitCnt)) & bitMask;
          cs->blocks[i] = block;
        }
      }
    } else {
      // "optimized for loading" BlockStates since 1.16.20w17a
      int bitSize = std::max(4, int(ceil(log2(cs->paletteLength))));
      int bitMask = (1 << bitSize)-1;
      for (int i = 0; i < 4096; i++) {
        uint64_t blockState = blockStates[bsCnt];
        cs->blocks[i] = (blockState >> bitCnt) & bitMask;
        bitCnt += bitSize;
        if (bitCnt+bitSize > 64) {
          bsCnt++;
          bitCnt = 0;
        }
      }
    }
  } else {
    // set everything to 0 (minecraft:air)
    memset(cs->blocks, 0, sizeof(cs->blocks));
  }

    // copy Light data
//  if (section->has("SkyLight")) {
//    memcpy(cs->skyLight, section->at("SkyLight")->toByteArray(), 2048);
//  }
  if (section->has("BlockLight")) {
    memcpy(cs->blockLight, section->at("BlockLight")->toByteArray(), 2048);
  }
}

const PaletteEntry & ChunkSection::getPaletteEntry(int x, int y, int z) const {
  int xoffset = (x & 0x0f);
  int yoffset = (y & 0x0f) << 8;
  int zoffset = z << 4;
  int blockid = blocks[xoffset + yoffset + zoffset];
  if (blockid < paletteLength)
    return palette[blockid];
  else
    return palette[0];
}

const PaletteEntry & ChunkSection::getPaletteEntry(int offset, int y) const {
  int yoffset = (y & 0x0f) << 8;
  int blockid = blocks[offset + yoffset];
  if (blockid < paletteLength)
    return palette[blockid];
  else
    return palette[0];
}

//quint8 ChunkSection::getSkyLight(int x, int y, int z) {
//  int xoffset = x;
//  int yoffset = (y & 0x0f) << 8;
//  int zoffset = z << 4;
//  int value = skyLight[(xoffset + yoffset + zoffset) / 2];
//  if (x & 1) value >>= 4;
//  return value & 0x0f;
//}

//quint8 ChunkSection::getSkyLight(int offset, int y) {
//  int yoffset = (y & 0x0f) << 8;
//  int value = skyLight[(offset + yoffset) / 2];
//  if (offset & 1) value >>= 4;
//  return value & 0x0f;
//}

quint8 ChunkSection::getBlockLight(int x, int y, int z) const {
  int xoffset = x;
  int yoffset = (y & 0x0f) << 8;
  int zoffset = z << 4;
  int value = blockLight[(xoffset + yoffset + zoffset) / 2];
  if (x & 1) value >>= 4;
  return value & 0x0f;
}

quint8 ChunkSection::getBlockLight(int offset, int y) const {
  int yoffset = (y & 0x0f) << 8;
  int value = blockLight[(offset + yoffset) / 2];
  if (offset & 1) value >>= 4;
  return value & 0x0f;
}
<|endoftext|>


<commit_before>#ifndef MJOLNIR_INPUT_READ_LOCAL_INTERACTION_HPP
#define MJOLNIR_INPUT_READ_LOCAL_INTERACTION_HPP
#include <extlib/toml/toml.hpp>
#include <mjolnir/interaction/local/BondLengthInteraction.hpp>
#include <mjolnir/interaction/local/ContactInteraction.hpp>
#include <mjolnir/interaction/local/BondAngleInteraction.hpp>
#include <mjolnir/interaction/local/DihedralAngleInteraction.hpp>
#include <mjolnir/util/make_unique.hpp>
#include <mjolnir/util/throw_exception.hpp>
#include <mjolnir/util/logger.hpp>
#include <mjolnir/input/read_local_potential.hpp>
#include <memory>

namespace mjolnir
{

// ----------------------------------------------------------------------------
// individual local interaction. would be called from read_local_interaction
// defined at the bottom of this file.
// ----------------------------------------------------------------------------

template<typename traitsT>
std::unique_ptr<LocalInteractionBase<traitsT>>
read_bond_length_interaction(const std::string& kind, const toml::value& local)
{
    MJOLNIR_GET_DEFAULT_LOGGER();
    MJOLNIR_LOG_FUNCTION();
    using real_type = typename traitsT::real_type;

    const auto potential = toml::find<std::string>(local, "potential");
    if(potential == "Harmonic")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is Harmonic.");
        using potentialT = HarmonicPotential<real_type>;

        return make_unique<BondLengthInteraction<traitsT, potentialT>>(
                kind, read_local_potential<2, potentialT>(local));
    }
    else if(potential == "GoContact")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is 10-12 Go contact.");
        using potentialT = GoContactPotential<real_type>;

        return make_unique<BondLengthInteraction<traitsT, potentialT>>(
                kind, read_local_potential<2, potentialT>(local));
    }
    else if(potential == "Gaussian")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is Gaussian.");
        using potentialT = GaussianPotential<real_type>;

        return make_unique<BondLengthInteraction<traitsT, potentialT>>(
                kind, read_local_potential<2, potentialT>(local));
    }
    else
    {
        throw_exception<std::runtime_error>(toml::format_error("[error] "
            "mjolnir::read_bond_length_interaction: invalid potential",
            toml::find<toml::value>(local, "potential"), "here", {
            "expected value is one of the following.",
            "- \"Harmonic\" : well-known harmonic potential",
            "- \"GoContact\": r^12 - r^10 type native contact potential",
            "- \"Gaussian\" : well-known gaussian potential"
            }));
    }
}

template<typename traitsT>
std::unique_ptr<LocalInteractionBase<traitsT>>
read_contact_interaction(const std::string& kind, const toml::value& local)
{
    MJOLNIR_GET_DEFAULT_LOGGER();
    MJOLNIR_LOG_FUNCTION();
    using real_type = typename traitsT::real_type;

    real_type margin = 0.5; // default value
    if(local.as_table().count("margin") == 1)
    {
        margin = toml::find<real_type>(local, "margin");
    }

    const auto potential = toml::find<std::string>(local, "potential");
    if(potential == "GoContact")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is 10-12 Go contact.");
        using potentialT = GoContactPotential<real_type>;

        return make_unique<ContactInteraction<traitsT, potentialT>>(
                kind, read_local_potential<2, potentialT>(local), margin);
    }
    else if(potential == "Gaussian")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is Gaussian.");
        using potentialT = GaussianPotential<real_type>;

        return make_unique<ContactInteraction<traitsT, potentialT>>(
                kind, read_local_potential<2, potentialT>(local), margin);
    }
    else
    {
        throw_exception<std::runtime_error>(toml::format_error("[error] "
            "mjolnir::read_bond_length_interaction: invalid potential",
            toml::find<toml::value>(local, "potential"), "here", {
            "expected value is one of the following.",
            "- \"GoContact\": r^12 - r^10 type native contact potential",
            "- \"Gaussian\" : well-known gaussian potential"
            }));
    }
}

template<typename traitsT>
std::unique_ptr<LocalInteractionBase<traitsT>>
read_bond_angle_interaction(
    const typename LocalInteractionBase<traitsT>::connection_kind_type kind,
    const toml::value& local)
{
    MJOLNIR_GET_DEFAULT_LOGGER();
    MJOLNIR_LOG_FUNCTION();
    using real_type = typename traitsT::real_type;

    const auto potential = toml::find<std::string>(local, "potential");

    if(potential == "Harmonic")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is Harmonic.");
        using potentialT = HarmonicPotential<real_type>;

        return make_unique<BondAngleInteraction<traitsT, potentialT>>(
                kind, read_local_potential<3, potentialT>(local));
    }
    else if(potential == "FlexibleLocalAngle")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is Flexible Local Angle.");
        using potentialT = FlexibleLocalAnglePotential<real_type>;

        return make_unique<BondAngleInteraction<traitsT, potentialT>>(
                kind, read_local_potential<3, potentialT>(local));
    }
    else if(potential == "Gaussian")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is Gaussian.");
        using potentialT = GaussianPotential<real_type>;

        return make_unique<BondAngleInteraction<traitsT, potentialT>>(
                kind, read_local_potential<3, potentialT>(local));
    }
    else
    {
        throw_exception<std::runtime_error>(toml::format_error("[error] "
            "mjolnir::read_bond_angle_interaction: invalid potential",
            toml::find<toml::value>(local, "potential"), "here", {
            "expected value is one of the following.",
            "- \"Harmonic\"          : well-known harmonic potential",
            "- \"Gaussian\"          : well-known gaussian potential"
            "- \"FlexibleLocalAngle\": table-based potential for C-alpha protein model",
            }));
    }
}

template<typename traitsT>
std::unique_ptr<LocalInteractionBase<traitsT>>
read_dihedral_angle_interaction(
    const typename LocalInteractionBase<traitsT>::connection_kind_type kind,
    const toml::value& local)
{
    MJOLNIR_GET_DEFAULT_LOGGER();
    MJOLNIR_LOG_FUNCTION();
    using real_type = typename traitsT::real_type;

    const auto potential = toml::find<std::string>(local, "potential");

    if(potential == "Harmonic")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is Harmonic.");
        using potentialT = HarmonicPotential<real_type>;

        return make_unique<DihedralAngleInteraction<traitsT, potentialT>>(
            kind, read_local_potential<4, potentialT>(local));
    }
    else if(potential == "ClementiDihedral")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is Clementi-Go's dihedral.");
        using potentialT = ClementiDihedralPotential<real_type>;

        return make_unique<DihedralAngleInteraction<traitsT, potentialT>>(
            kind, read_local_potential<4, potentialT>(local));
    }
    else if(potential == "Gaussian")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is Gaussian.");
        using potentialT = GaussianPotential<real_type>;

        return make_unique<DihedralAngleInteraction<traitsT, potentialT>>(
            kind, read_local_potential<4, potentialT>(local));
    }
    else if(potential == "PeriodicGaussian")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is PeriodicGaussian.");
        using potentialT = PeriodicGaussianPotential<real_type>;

        return make_unique<DihedralAngleInteraction<traitsT, potentialT>>(
            kind, read_local_potential<4, potentialT>(local));
    }
    else if(potential == "FlexibleLocalDihedral")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is Flexible Local Dihedral.");
        using potentialT = FlexibleLocalDihedralPotential<real_type>;

        return make_unique<DihedralAngleInteraction<traitsT, potentialT>>(
            kind, read_local_potential<4, potentialT>(local));
    }
    // XXX generalization of this feature is too difficult (technically it's
    //     not so difficult, but practically, it makes the code messy...).
    else if(potential == "PeriodicGaussian+FlexibleLocalDihedral")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is "
                           "PeriodicGaussian + FlexibleLocalDihedral.");
        using potential_1_T = PeriodicGaussianPotential<real_type>;
        using potential_2_T = FlexibleLocalDihedralPotential<real_type>;
        using potentialT    =
            SumLocalPotential<real_type, potential_1_T, potential_2_T>;

        return make_unique<DihedralAngleInteraction<traitsT, potentialT>>(kind,
            read_local_potentials<4, real_type, potential_1_T, potential_2_T>(
                local, "PeriodicGaussian", "FlexibleLocalDihedral"));
    }
    else
    {
        throw_exception<std::runtime_error>(toml::format_error("[error] "
            "mjolnir::read_dihedral_angle_interaction: invalid potential",
            toml::find<toml::value>(local, "potential"), "here", {
            "expected value is one of the following.",
            "- \"Harmonic\"             : well-known harmonic potential",
            "- \"Gaussian\"             : well-known gaussian potential"
            "- \"ClementiDihedral\"     : potential used in the off-lattice Go protein model"
            "- \"FlexibleLocalDihedral\": table-based potential for C-alpha protein model",
            }));
    }
}

// ----------------------------------------------------------------------------
// general read_local_interaction function
// ----------------------------------------------------------------------------

template<typename traitsT>
std::unique_ptr<LocalInteractionBase<traitsT>>
read_local_interaction(const toml::value& local)
{
    MJOLNIR_GET_DEFAULT_LOGGER();
    MJOLNIR_LOG_FUNCTION();

    const auto interaction = toml::find<std::string>(local, "interaction");
    const auto kind        = toml::find<std::string>(local, "topology");
    MJOLNIR_LOG_INFO("connection kind = ", kind);

    if(interaction == "BondLength")
    {
        MJOLNIR_LOG_NOTICE("Bond Length interaction found.");
        return read_bond_length_interaction<traitsT>(kind, local);
    }
    else if(interaction == "Contact")
    {
        MJOLNIR_LOG_NOTICE("Contact interaction found.");
        return read_contact_interaction<traitsT>(kind, local);
    }
    else if(interaction == "BondAngle")
    {
        MJOLNIR_LOG_NOTICE("Bond Angle interaction found.");
        return read_bond_angle_interaction<traitsT>(kind, local);
    }
    else if(interaction == "DihedralAngle")
    {
        MJOLNIR_LOG_NOTICE("Dihedral Angle interaction found.");
        return read_dihedral_angle_interaction<traitsT>(kind, local);
    }
    else
    {
        throw_exception<std::runtime_error>(toml::format_error("[error] "
            "mjolnir::read_local_interaction: invalid interaction",
            toml::find<toml::value>(local, "interaction"), "here", {
            "expected value is one of the following.",
            "- \"BondLength\"    : 2-body well-known chemical bond interaction",
            "- \"BondAngle\"     : 3-body well-known bond angle interaction",
            "- \"DihedralAngle\" : 4-body well-known dihedral angle interaction",
            }));
    }
}

} // mjolnir
#endif// MJOLNIR_READ_LOCAL_INTERACTION
<commit_msg>feat: enable to read Dummy Interaction<commit_after>#ifndef MJOLNIR_INPUT_READ_LOCAL_INTERACTION_HPP
#define MJOLNIR_INPUT_READ_LOCAL_INTERACTION_HPP
#include <extlib/toml/toml.hpp>
#include <mjolnir/interaction/local/BondLengthInteraction.hpp>
#include <mjolnir/interaction/local/ContactInteraction.hpp>
#include <mjolnir/interaction/local/BondAngleInteraction.hpp>
#include <mjolnir/interaction/local/DihedralAngleInteraction.hpp>
#include <mjolnir/interaction/local/DummyInteraction.hpp>
#include <mjolnir/util/make_unique.hpp>
#include <mjolnir/util/throw_exception.hpp>
#include <mjolnir/util/logger.hpp>
#include <mjolnir/input/read_local_potential.hpp>
#include <memory>

namespace mjolnir
{

// ----------------------------------------------------------------------------
// individual local interaction. would be called from read_local_interaction
// defined at the bottom of this file.
// ----------------------------------------------------------------------------

template<typename traitsT>
std::unique_ptr<LocalInteractionBase<traitsT>>
read_bond_length_interaction(const std::string& kind, const toml::value& local)
{
    MJOLNIR_GET_DEFAULT_LOGGER();
    MJOLNIR_LOG_FUNCTION();
    using real_type = typename traitsT::real_type;

    const auto potential = toml::find<std::string>(local, "potential");
    if(potential == "Harmonic")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is Harmonic.");
        using potentialT = HarmonicPotential<real_type>;

        return make_unique<BondLengthInteraction<traitsT, potentialT>>(
                kind, read_local_potential<2, potentialT>(local));
    }
    else if(potential == "GoContact")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is 10-12 Go contact.");
        using potentialT = GoContactPotential<real_type>;

        return make_unique<BondLengthInteraction<traitsT, potentialT>>(
                kind, read_local_potential<2, potentialT>(local));
    }
    else if(potential == "Gaussian")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is Gaussian.");
        using potentialT = GaussianPotential<real_type>;

        return make_unique<BondLengthInteraction<traitsT, potentialT>>(
                kind, read_local_potential<2, potentialT>(local));
    }
    else
    {
        throw_exception<std::runtime_error>(toml::format_error("[error] "
            "mjolnir::read_bond_length_interaction: invalid potential",
            toml::find<toml::value>(local, "potential"), "here", {
            "expected value is one of the following.",
            "- \"Harmonic\" : well-known harmonic potential",
            "- \"GoContact\": r^12 - r^10 type native contact potential",
            "- \"Gaussian\" : well-known gaussian potential"
            }));
    }
}

template<typename traitsT>
std::unique_ptr<LocalInteractionBase<traitsT>>
read_contact_interaction(const std::string& kind, const toml::value& local)
{
    MJOLNIR_GET_DEFAULT_LOGGER();
    MJOLNIR_LOG_FUNCTION();
    using real_type = typename traitsT::real_type;

    real_type margin = 0.5; // default value
    if(local.as_table().count("margin") == 1)
    {
        margin = toml::find<real_type>(local, "margin");
    }

    const auto potential = toml::find<std::string>(local, "potential");
    if(potential == "GoContact")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is 10-12 Go contact.");
        using potentialT = GoContactPotential<real_type>;

        return make_unique<ContactInteraction<traitsT, potentialT>>(
                kind, read_local_potential<2, potentialT>(local), margin);
    }
    else if(potential == "Gaussian")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is Gaussian.");
        using potentialT = GaussianPotential<real_type>;

        return make_unique<ContactInteraction<traitsT, potentialT>>(
                kind, read_local_potential<2, potentialT>(local), margin);
    }
    else
    {
        throw_exception<std::runtime_error>(toml::format_error("[error] "
            "mjolnir::read_bond_length_interaction: invalid potential",
            toml::find<toml::value>(local, "potential"), "here", {
            "expected value is one of the following.",
            "- \"GoContact\": r^12 - r^10 type native contact potential",
            "- \"Gaussian\" : well-known gaussian potential"
            }));
    }
}

template<typename traitsT>
std::unique_ptr<LocalInteractionBase<traitsT>>
read_bond_angle_interaction(
    const typename LocalInteractionBase<traitsT>::connection_kind_type kind,
    const toml::value& local)
{
    MJOLNIR_GET_DEFAULT_LOGGER();
    MJOLNIR_LOG_FUNCTION();
    using real_type = typename traitsT::real_type;

    const auto potential = toml::find<std::string>(local, "potential");

    if(potential == "Harmonic")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is Harmonic.");
        using potentialT = HarmonicPotential<real_type>;

        return make_unique<BondAngleInteraction<traitsT, potentialT>>(
                kind, read_local_potential<3, potentialT>(local));
    }
    else if(potential == "FlexibleLocalAngle")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is Flexible Local Angle.");
        using potentialT = FlexibleLocalAnglePotential<real_type>;

        return make_unique<BondAngleInteraction<traitsT, potentialT>>(
                kind, read_local_potential<3, potentialT>(local));
    }
    else if(potential == "Gaussian")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is Gaussian.");
        using potentialT = GaussianPotential<real_type>;

        return make_unique<BondAngleInteraction<traitsT, potentialT>>(
                kind, read_local_potential<3, potentialT>(local));
    }
    else
    {
        throw_exception<std::runtime_error>(toml::format_error("[error] "
            "mjolnir::read_bond_angle_interaction: invalid potential",
            toml::find<toml::value>(local, "potential"), "here", {
            "expected value is one of the following.",
            "- \"Harmonic\"          : well-known harmonic potential",
            "- \"Gaussian\"          : well-known gaussian potential"
            "- \"FlexibleLocalAngle\": table-based potential for C-alpha protein model",
            }));
    }
}

template<typename traitsT>
std::unique_ptr<LocalInteractionBase<traitsT>>
read_dihedral_angle_interaction(
    const typename LocalInteractionBase<traitsT>::connection_kind_type kind,
    const toml::value& local)
{
    MJOLNIR_GET_DEFAULT_LOGGER();
    MJOLNIR_LOG_FUNCTION();
    using real_type = typename traitsT::real_type;

    const auto potential = toml::find<std::string>(local, "potential");

    if(potential == "Harmonic")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is Harmonic.");
        using potentialT = HarmonicPotential<real_type>;

        return make_unique<DihedralAngleInteraction<traitsT, potentialT>>(
            kind, read_local_potential<4, potentialT>(local));
    }
    else if(potential == "ClementiDihedral")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is Clementi-Go's dihedral.");
        using potentialT = ClementiDihedralPotential<real_type>;

        return make_unique<DihedralAngleInteraction<traitsT, potentialT>>(
            kind, read_local_potential<4, potentialT>(local));
    }
    else if(potential == "Gaussian")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is Gaussian.");
        using potentialT = GaussianPotential<real_type>;

        return make_unique<DihedralAngleInteraction<traitsT, potentialT>>(
            kind, read_local_potential<4, potentialT>(local));
    }
    else if(potential == "PeriodicGaussian")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is PeriodicGaussian.");
        using potentialT = PeriodicGaussianPotential<real_type>;

        return make_unique<DihedralAngleInteraction<traitsT, potentialT>>(
            kind, read_local_potential<4, potentialT>(local));
    }
    else if(potential == "FlexibleLocalDihedral")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is Flexible Local Dihedral.");
        using potentialT = FlexibleLocalDihedralPotential<real_type>;

        return make_unique<DihedralAngleInteraction<traitsT, potentialT>>(
            kind, read_local_potential<4, potentialT>(local));
    }
    // XXX generalization of this feature is too difficult (technically it's
    //     not so difficult, but practically, it makes the code messy...).
    else if(potential == "PeriodicGaussian+FlexibleLocalDihedral")
    {
        MJOLNIR_LOG_NOTICE("-- potential function is "
                           "PeriodicGaussian + FlexibleLocalDihedral.");
        using potential_1_T = PeriodicGaussianPotential<real_type>;
        using potential_2_T = FlexibleLocalDihedralPotential<real_type>;
        using potentialT    =
            SumLocalPotential<real_type, potential_1_T, potential_2_T>;

        return make_unique<DihedralAngleInteraction<traitsT, potentialT>>(kind,
            read_local_potentials<4, real_type, potential_1_T, potential_2_T>(
                local, "PeriodicGaussian", "FlexibleLocalDihedral"));
    }
    else
    {
        throw_exception<std::runtime_error>(toml::format_error("[error] "
            "mjolnir::read_dihedral_angle_interaction: invalid potential",
            toml::find<toml::value>(local, "potential"), "here", {
            "expected value is one of the following.",
            "- \"Harmonic\"             : well-known harmonic potential",
            "- \"Gaussian\"             : well-known gaussian potential"
            "- \"ClementiDihedral\"     : potential used in the off-lattice Go protein model"
            "- \"FlexibleLocalDihedral\": table-based potential for C-alpha protein model",
            }));
    }
}

template<typename traitsT>
std::unique_ptr<LocalInteractionBase<traitsT>>
read_dummy_interaction(const std::string& kind, const toml::value& local)
{
    // It does not require `potential` field because this interaction does not
    // calculate force or energy.
    //
    // ```toml
    // [[forcefields.local]]
    // interaction = "Dummy"
    // topology  = "bond"
    // parameters = [
    //     {indices = [0, 1]},
    //     # ...
    // ]
    // ```
    //
    // So, unlike other interactions, it reads particle indices here.

    MJOLNIR_GET_DEFAULT_LOGGER();
    MJOLNIR_LOG_FUNCTION();
    using indices_type = std::array<std::size_t, 2>;

    if(local.as_table().count("potential") == 1)
    {
        MJOLNIR_LOG_WARN("Dummy Interaction has a `potential` field.");
        MJOLNIR_LOG_WARN("It is for defining unusual topology.");
        MJOLNIR_LOG_WARN("Potential parameters are ignored.");
    }

    const auto& params = toml::find<toml::array>(local, "parameters");
    MJOLNIR_LOG_NOTICE("-- ", params.size(), " bonds are found.");

    std::vector<indices_type> indices_list;
    indices_list.reserve(params.size());
    for(const auto& item : params)
    {
        const auto indices = toml::find<indices_type>(item, "indices");
        MJOLNIR_LOG_INFO("idxs = ", indices);
        indices_list.push_back(indices);
    }
    return make_unique<DummyInteraction<traitsT>>(kind, std::move(indices_list));
}

// ----------------------------------------------------------------------------
// general read_local_interaction function
// ----------------------------------------------------------------------------

template<typename traitsT>
std::unique_ptr<LocalInteractionBase<traitsT>>
read_local_interaction(const toml::value& local)
{
    MJOLNIR_GET_DEFAULT_LOGGER();
    MJOLNIR_LOG_FUNCTION();

    const auto interaction = toml::find<std::string>(local, "interaction");
    const auto kind        = toml::find<std::string>(local, "topology");
    MJOLNIR_LOG_INFO("connection kind = ", kind);

    if(interaction == "BondLength")
    {
        MJOLNIR_LOG_NOTICE("Bond Length interaction found.");
        return read_bond_length_interaction<traitsT>(kind, local);
    }
    else if(interaction == "Contact")
    {
        MJOLNIR_LOG_NOTICE("Contact interaction found.");
        return read_contact_interaction<traitsT>(kind, local);
    }
    else if(interaction == "BondAngle")
    {
        MJOLNIR_LOG_NOTICE("Bond Angle interaction found.");
        return read_bond_angle_interaction<traitsT>(kind, local);
    }
    else if(interaction == "DihedralAngle")
    {
        MJOLNIR_LOG_NOTICE("Dihedral Angle interaction found.");
        return read_dihedral_angle_interaction<traitsT>(kind, local);
    }
    else if(interaction == "Dummy")
    {
        MJOLNIR_LOG_NOTICE("Dummy interaction found.");
        return read_dummy_interaction<traitsT>(kind, local);
    }
    else
    {
        throw_exception<std::runtime_error>(toml::format_error("[error] "
            "mjolnir::read_local_interaction: invalid interaction",
            toml::find<toml::value>(local, "interaction"), "here", {
            "expected value is one of the following.",
            "- \"BondLength\"    : 2-body well-known chemical bond interaction",
            "- \"BondAngle\"     : 3-body well-known bond angle interaction",
            "- \"DihedralAngle\" : 4-body well-known dihedral angle interaction",
            "- \"Dummy\"         : To represent a strange topology. It does nothing",
            }));
    }
}

} // mjolnir
#endif// MJOLNIR_READ_LOCAL_INTERACTION
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright RTK Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include "rtkCudaFFTRampImageFilter.h"
#include "rtkCudaFFTRampImageFilter.hcu"

#include <itkMacro.h>

rtk::CudaFFTRampImageFilter
::CudaFFTRampImageFilter()
{
  // We use FFTW for the kernel so we need to do the same thing as in the parent
#if defined(USE_FFTWF)
  this->SetGreatestPrimeFactor(13);
#endif
}

void
rtk::CudaFFTRampImageFilter
::GenerateData()
{
  this->AllocateOutputs();

  // Pad image region
  FFTInputImagePointer paddedImage = PadInputImageRegion(this->GetInput()->GetRequestedRegion() );

  int3 inputDimension;
  inputDimension.x = paddedImage->GetBufferedRegion().GetSize()[0];
  inputDimension.y = paddedImage->GetBufferedRegion().GetSize()[1];
  inputDimension.z = paddedImage->GetBufferedRegion().GetSize()[2];

  // Get FFT ramp kernel
  FFTOutputImagePointer fftK = this->GetFFTRampKernel(paddedImage->GetLargestPossibleRegion().GetSize(0),
                                                      paddedImage->GetLargestPossibleRegion().GetSize(1) );

  // CUFFT scales by the number of element, correct for it in kernel
  itk::ImageRegionIterator<FFTOutputImageType> itK(fftK, fftK->GetBufferedRegion() );
  itK.GoToBegin();
  FFTPrecisionType invNPixels = 1 / double(paddedImage->GetBufferedRegion().GetNumberOfPixels() );
  while(!itK.IsAtEnd() ) {
    itK.Set(itK.Get() * invNPixels );
    ++itK;
    }

  int2 kernelDimension;
  kernelDimension.x = fftK->GetBufferedRegion().GetSize()[0];
  kernelDimension.y = fftK->GetBufferedRegion().GetSize()[1];

  CUDA_fft_convolution(inputDimension,
                       kernelDimension,
                       paddedImage->GetBufferPointer(),
                       (float2*)(fftK->GetBufferPointer() ) );

  // Crop and paste result
  itk::ImageRegionConstIterator<FFTInputImageType> itS(paddedImage, this->GetOutput()->GetRequestedRegion() );
  itk::ImageRegionIterator<OutputImageType>        itD(this->GetOutput(), this->GetOutput()->GetRequestedRegion() );
  itS.GoToBegin();
  itD.GoToBegin();
  while(!itS.IsAtEnd() ) {
    itD.Set(itS.Get() );
    ++itS;
    ++itD;
    }
}
<commit_msg>Cuda fix for 1 line sinograms<commit_after>/*=========================================================================
 *
 *  Copyright RTK Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include "rtkCudaFFTRampImageFilter.h"
#include "rtkCudaFFTRampImageFilter.hcu"

#include <itkMacro.h>

rtk::CudaFFTRampImageFilter
::CudaFFTRampImageFilter()
{
  // We use FFTW for the kernel so we need to do the same thing as in the parent
#if defined(USE_FFTWF)
  this->SetGreatestPrimeFactor(13);
#endif
}

void
rtk::CudaFFTRampImageFilter
::GenerateData()
{
  this->AllocateOutputs();

  // Pad image region
  FFTInputImagePointer paddedImage = PadInputImageRegion(this->GetInput()->GetRequestedRegion() );

  int3 inputDimension;
  inputDimension.x = paddedImage->GetBufferedRegion().GetSize()[0];
  inputDimension.y = paddedImage->GetBufferedRegion().GetSize()[1];
  inputDimension.z = paddedImage->GetBufferedRegion().GetSize()[2];
  if(inputDimension.y==1 && inputDimension.z>1) // Troubles cuda 3.2 and 4.0
    std::swap(inputDimension.y, inputDimension.z);

  // Get FFT ramp kernel
  FFTOutputImagePointer fftK = this->GetFFTRampKernel(paddedImage->GetLargestPossibleRegion().GetSize(0),
                                                      paddedImage->GetLargestPossibleRegion().GetSize(1) );

  // CUFFT scales by the number of element, correct for it in kernel
  itk::ImageRegionIterator<FFTOutputImageType> itK(fftK, fftK->GetBufferedRegion() );
  itK.GoToBegin();
  FFTPrecisionType invNPixels = 1 / double(paddedImage->GetBufferedRegion().GetNumberOfPixels() );
  while(!itK.IsAtEnd() ) {
    itK.Set(itK.Get() * invNPixels );
    ++itK;
    }

  int2 kernelDimension;
  kernelDimension.x = fftK->GetBufferedRegion().GetSize()[0];
  kernelDimension.y = fftK->GetBufferedRegion().GetSize()[1];

  CUDA_fft_convolution(inputDimension,
                       kernelDimension,
                       paddedImage->GetBufferPointer(),
                       (float2*)(fftK->GetBufferPointer() ) );

  // Crop and paste result
  itk::ImageRegionConstIterator<FFTInputImageType> itS(paddedImage, this->GetOutput()->GetRequestedRegion() );
  itk::ImageRegionIterator<OutputImageType>        itD(this->GetOutput(), this->GetOutput()->GetRequestedRegion() );
  itS.GoToBegin();
  itD.GoToBegin();
  while(!itS.IsAtEnd() ) {
    itD.Set(itS.Get() );
    ++itS;
    ++itD;
    }
}
<|endoftext|>


<commit_before>#include <thread>

#include "Daemon.h"

#include "Log.h"
#include "base64.h"
#include "Transports.h"
#include "NTCPSession.h"
#include "RouterInfo.h"
#include "RouterContext.h"
#include "Tunnel.h"
#include "NetDb.h"
#include "Garlic.h"
#include "util.h"
#include "Streaming.h"
#include "HTTPServer.h"
#include "HTTPProxy.h"

namespace i2p
{
	namespace util
	{
		class Daemon_Singleton::Daemon_Singleton_Private
		{
		public:
			Daemon_Singleton_Private() : httpServer(nullptr), httpProxy(nullptr) { };
			~Daemon_Singleton_Private() {
				delete httpServer;
				delete httpProxy;
			};

			i2p::util::HTTPServer *httpServer;
			i2p::proxy::HTTPProxy *httpProxy;
		};

		Daemon_Singleton::Daemon_Singleton() : running(1), d(*new Daemon_Singleton_Private()) {};
		Daemon_Singleton::~Daemon_Singleton() {
			delete &d;
		};

		bool Daemon_Singleton::init(int argc, char* argv[])
		{
			i2p::util::config::OptionParser(argc, argv);

			LogPrint("\n\n\n\ni2pd starting\n");
			LogPrint("data directory: ", i2p::util::filesystem::GetDataDir().string());
			i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs);

			isDaemon = i2p::util::config::GetArg("-daemon", 0);
			isLogging = i2p::util::config::GetArg("-log", 1);

			//TODO: This is an ugly workaround. fix it.
			//TODO: Autodetect public IP.
			i2p::context.OverrideNTCPAddress(i2p::util::config::GetCharArg("-host", "127.0.0.1"),
				i2p::util::config::GetArg("-port", 17070));

			if (isLogging == 1)
			{
				std::string logfile_path = i2p::util::filesystem::GetDataDir().string();
#ifndef _WIN32
				logfile_path.append("/debug.log");
#else
				logfile_path.append("\\debug.log");
#endif
				g_Log.SetLogFile (logfile_path);

				LogPrint("CMD parameters:");
				for (int i = 0; i < argc; ++i)
					LogPrint(i, "  ", argv[i]);

			}
			return true;
		}

		bool Daemon_Singleton::start()
		{
			d.httpServer = new i2p::util::HTTPServer(i2p::util::config::GetArg("-httpport", 7070));
			d.httpServer->Start();
			LogPrint("HTTPServer started");

			i2p::data::netdb.Start();
			LogPrint("NetDB started");
			i2p::transports.Start();
			LogPrint("Transports started");
			i2p::tunnel::tunnels.Start();
			LogPrint("Tunnels started");
			i2p::garlic::routing.Start();
			LogPrint("Routing started");
			i2p::stream::StartStreaming();
			LogPrint("Streaming started");

			d.httpProxy = new i2p::proxy::HTTPProxy(i2p::util::config::GetArg("-httpproxyport", 4446));
			d.httpProxy->Start();
			LogPrint("Proxy started");

			return true;
		}

		bool Daemon_Singleton::stop()
		{
			LogPrint("Shutdown started.");

			d.httpProxy->Stop();
			LogPrint("HTTPProxy stoped");
			i2p::stream::StopStreaming();
			LogPrint("Streaming stoped");
			i2p::garlic::routing.Stop();
			LogPrint("Routing stoped");
			i2p::tunnel::tunnels.Stop();
			LogPrint("Tunnels stoped");
			i2p::transports.Stop();
			LogPrint("Transports stoped");
			i2p::data::netdb.Stop();
			LogPrint("NetDB stoped");
			d.httpServer->Stop();
			LogPrint("HTTPServer stoped");

			delete d.httpProxy; d.httpProxy = nullptr;
			delete d.httpServer; d.httpServer = nullptr;

			if (isLogging == 1)
			{
				fclose(stdout);
			}

			return true;
		}
	}
}
<commit_msg>defualt port consistency (17007)<commit_after>#include <thread>

#include "Daemon.h"

#include "Log.h"
#include "base64.h"
#include "Transports.h"
#include "NTCPSession.h"
#include "RouterInfo.h"
#include "RouterContext.h"
#include "Tunnel.h"
#include "NetDb.h"
#include "Garlic.h"
#include "util.h"
#include "Streaming.h"
#include "HTTPServer.h"
#include "HTTPProxy.h"

namespace i2p
{
	namespace util
	{
		class Daemon_Singleton::Daemon_Singleton_Private
		{
		public:
			Daemon_Singleton_Private() : httpServer(nullptr), httpProxy(nullptr) { };
			~Daemon_Singleton_Private() {
				delete httpServer;
				delete httpProxy;
			};

			i2p::util::HTTPServer *httpServer;
			i2p::proxy::HTTPProxy *httpProxy;
		};

		Daemon_Singleton::Daemon_Singleton() : running(1), d(*new Daemon_Singleton_Private()) {};
		Daemon_Singleton::~Daemon_Singleton() {
			delete &d;
		};

		bool Daemon_Singleton::init(int argc, char* argv[])
		{
			i2p::util::config::OptionParser(argc, argv);

			LogPrint("\n\n\n\ni2pd starting\n");
			LogPrint("data directory: ", i2p::util::filesystem::GetDataDir().string());
			i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs);

			isDaemon = i2p::util::config::GetArg("-daemon", 0);
			isLogging = i2p::util::config::GetArg("-log", 1);

			//TODO: This is an ugly workaround. fix it.
			//TODO: Autodetect public IP.
			i2p::context.OverrideNTCPAddress(i2p::util::config::GetCharArg("-host", "127.0.0.1"),
				i2p::util::config::GetArg("-port", 17007));

			if (isLogging == 1)
			{
				std::string logfile_path = i2p::util::filesystem::GetDataDir().string();
#ifndef _WIN32
				logfile_path.append("/debug.log");
#else
				logfile_path.append("\\debug.log");
#endif
				g_Log.SetLogFile (logfile_path);

				LogPrint("CMD parameters:");
				for (int i = 0; i < argc; ++i)
					LogPrint(i, "  ", argv[i]);

			}
			return true;
		}

		bool Daemon_Singleton::start()
		{
			d.httpServer = new i2p::util::HTTPServer(i2p::util::config::GetArg("-httpport", 7070));
			d.httpServer->Start();
			LogPrint("HTTPServer started");

			i2p::data::netdb.Start();
			LogPrint("NetDB started");
			i2p::transports.Start();
			LogPrint("Transports started");
			i2p::tunnel::tunnels.Start();
			LogPrint("Tunnels started");
			i2p::garlic::routing.Start();
			LogPrint("Routing started");
			i2p::stream::StartStreaming();
			LogPrint("Streaming started");

			d.httpProxy = new i2p::proxy::HTTPProxy(i2p::util::config::GetArg("-httpproxyport", 4446));
			d.httpProxy->Start();
			LogPrint("Proxy started");

			return true;
		}

		bool Daemon_Singleton::stop()
		{
			LogPrint("Shutdown started.");

			d.httpProxy->Stop();
			LogPrint("HTTPProxy stoped");
			i2p::stream::StopStreaming();
			LogPrint("Streaming stoped");
			i2p::garlic::routing.Stop();
			LogPrint("Routing stoped");
			i2p::tunnel::tunnels.Stop();
			LogPrint("Tunnels stoped");
			i2p::transports.Stop();
			LogPrint("Transports stoped");
			i2p::data::netdb.Stop();
			LogPrint("NetDB stoped");
			d.httpServer->Stop();
			LogPrint("HTTPServer stoped");

			delete d.httpProxy; d.httpProxy = nullptr;
			delete d.httpServer; d.httpServer = nullptr;

			if (isLogging == 1)
			{
				fclose(stdout);
			}

			return true;
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2018 Intel Corporation.

#include <gtest/gtest.h>

#include "testing/matchers.h"
#include "tile/codegen/schedule/deps.h"
#include "tile/stripe/stripe.h"
#include "tile/stripe/stripe.pb.h"

namespace gp = google::protobuf;

using ::testing::EqualsProto;

namespace vertexai {
namespace tile {
namespace codegen {
namespace schedule {

TEST(DepsTest, SmallDepMix) {
  stripe::proto::Block input_proto;
  gp::TextFormat::ParseFromString(R"(
    location { unit { } }
    refs {
      location { unit { } }
      into: "b1"
      shape {
        type: FLOAT32
        dimensions: {size:1 stride:1}
      }
    }
    refs {
      location { unit { } }
      into: "b2"
      shape {
        type: FLOAT32
        dimensions: {size:1 stride:1}
      }
    }
    stmts { load { from:"b1" into:"$1" } }
    stmts { store { from:"$1" into:"b2" } }
    stmts { load { from:"b2" into:"$2" } deps: 0}
    stmts { constant { name:"$3" iconst: 0 } }
    stmts { intrinsic { name:"ADD" inputs:"$2" inputs:"$3" outputs:"$4"} }
    stmts { special { name:"COPY" inputs:"b1" outputs:"b2"} }
    stmts { store { from:"$4" into:"b2"} }
  )",
                                  &input_proto);

  std::shared_ptr<stripe::Block> block{stripe::FromProto(input_proto)};

  ComputeDepsForTree(block.get());

  stripe::proto::Block output_proto{IntoProto(*block)};

  EXPECT_THAT(output_proto, EqualsProto(R"proto(
    location { unit { } }
    refs {
      location { unit { } }
      into: "b1"
      shape {
        type: FLOAT32
        dimensions: {size:1 stride:1}
      }
    }
    refs {
      location { unit { } }
      into: "b2"
      shape {
        type: FLOAT32
        dimensions: {size:1 stride:1}
      }
    }
    stmts { load { from:"b1" into:"$1" } }
    stmts { store { from:"$1" into:"b2" } deps: 0 }
    stmts { load { from:"b2" into:"$2" } deps: 1}
    stmts { constant { name:"$3" iconst: 0 } }
    stmts { intrinsic { name:"ADD" inputs:"$2" inputs:"$3" outputs:"$4"} deps: 2 deps: 3}
    stmts { special { name:"COPY" inputs:"b1" outputs:"b2"} deps: 2}
    stmts { store { from:"$4" into:"b2"} deps: 4 deps: 5}
  )proto"));
}

}  // namespace schedule
}  // namespace codegen
}  // namespace tile
}  // namespace vertexai
<commit_msg>Separate raw literal use<commit_after>// Copyright 2018 Intel Corporation.

#include <gtest/gtest.h>

#include "testing/matchers.h"
#include "tile/codegen/schedule/deps.h"
#include "tile/stripe/stripe.h"
#include "tile/stripe/stripe.pb.h"

namespace gp = google::protobuf;

using ::testing::EqualsProto;

namespace vertexai {
namespace tile {
namespace codegen {
namespace schedule {

TEST(DepsTest, SmallDepMix) {
  stripe::proto::Block input_proto;
  gp::TextFormat::ParseFromString(R"(
    location { unit { } }
    refs {
      location { unit { } }
      into: "b1"
      shape {
        type: FLOAT32
        dimensions: {size:1 stride:1}
      }
    }
    refs {
      location { unit { } }
      into: "b2"
      shape {
        type: FLOAT32
        dimensions: {size:1 stride:1}
      }
    }
    stmts { load { from:"b1" into:"$1" } }
    stmts { store { from:"$1" into:"b2" } }
    stmts { load { from:"b2" into:"$2" } deps: 0}
    stmts { constant { name:"$3" iconst: 0 } }
    stmts { intrinsic { name:"ADD" inputs:"$2" inputs:"$3" outputs:"$4"} }
    stmts { special { name:"COPY" inputs:"b1" outputs:"b2"} }
    stmts { store { from:"$4" into:"b2"} }
  )",
                                  &input_proto);

  std::shared_ptr<stripe::Block> block{stripe::FromProto(input_proto)};

  ComputeDepsForTree(block.get());

  stripe::proto::Block output_proto{IntoProto(*block)};

  const char* expected = R"(
    location { unit { } }
    refs {
      location { unit { } }
      into: "b1"
      shape {
        type: FLOAT32
        dimensions: {size:1 stride:1}
      }
    }
    refs {
      location { unit { } }
      into: "b2"
      shape {
        type: FLOAT32
        dimensions: {size:1 stride:1}
      }
    }
    stmts { load { from:"b1" into:"$1" } }
    stmts { store { from:"$1" into:"b2" } deps: 0 }
    stmts { load { from:"b2" into:"$2" } deps: 1}
    stmts { constant { name:"$3" iconst: 0 } }
    stmts { intrinsic { name:"ADD" inputs:"$2" inputs:"$3" outputs:"$4"} deps: 2 deps: 3}
    stmts { special { name:"COPY" inputs:"b1" outputs:"b2"} deps: 2}
    stmts { store { from:"$4" into:"b2"} deps: 4 deps: 5}
  )";

  EXPECT_THAT(output_proto, EqualsProto(expected));
}

}  // namespace schedule
}  // namespace codegen
}  // namespace tile
}  // namespace vertexai
<|endoftext|>


<commit_before>#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPainter>
#include <QResizeEvent>
#include <time.h>

#include "../../src/mjhz.h"

#define MJPAI_W 42
#define MJPAI_H 60

mjhz_t mjhz;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QRect rc = geometry();
    setFixedSize(rc.width(), rc.height());
    _winH = rc.height();
    _winW = rc.width();

    srand(time(NULL));

    _hu = 0;
    _imgTiles.load(":/res/mj.png");
    _imgHu.load(":/res/hu.png");

    mjhz_init(&mjhz, 0, 4);
    mjhz_start(&mjhz);
    mjhz_sort(mjhz.players[0].tiles);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::resizeEvent(QResizeEvent *event)
{
    QSize sz = event->size();
    _winW = sz.width();
    _winH = sz.height();
}

void MainWindow::paintEvent(QPaintEvent*)
{
    int i;
    int x,y,n;

    QPainter painter(this);
    QRectF rcAll = rect();
    QBrush brush(QColor(16, 114, 16));
    painter.fillRect(rcAll, brush);

    x = y = 0;
    n = 1;
    for (i = 0; i < 34; ++i) {
        QRect rcSrc(n * MJPAI_W, 0, MJPAI_W, MJPAI_H);
        QRect rcDest(x, y, MJPAI_W, MJPAI_H);
        painter.drawPixmap(rcDest, _imgTiles, rcSrc);
        n++;
        x += MJPAI_W;
        if ((n -1) % 9 == 0) {
            x = 0;
            y += MJPAI_H;
        }
    }

    int offset;
    if (mjhz.players[0].tiles[MJHZ_MAX_PAIS-1] != 0)
        offset = 6;
    else
        offset = 0;
    n = 0;
    for (i = 0; i < MJHZ_MAX_PAIS; ++i) {
        if (mjhz.players[0].tiles[i] != 0)
            n++;
    }

    x = (rcAll.width() - (n * MJPAI_W) - offset) / 2;
    y = rcAll.bottom() - MJPAI_H;
    for (i = 0; i < MJHZ_MAX_PAIS; ++i) {
        if (mjhz.players[0].tiles[i] == 0)
            continue;
        QRect rcSrc(mjhz.players[0].tiles[i] * MJPAI_W,
                0, MJPAI_W, MJPAI_H);
        if (i == (MJHZ_MAX_PAIS - 1)) {
            x += 6;
        }
        QRect rcDest(x, y, MJPAI_W, MJPAI_H);
        painter.drawPixmap(rcDest, _imgTiles, rcSrc);
        x += MJPAI_W;
    }

    if (_hu) {
        painter.drawPixmap(rcAll.right() - _imgHu.width(),
                           rcAll.bottom() - _imgHu.height(),
                           _imgHu);
    }
}

bool MainWindow::pointInRect(const QPoint &pt, const QRect &rect)
{
    if (pt.x() >= rect.left() && pt.x() <= rect.right() &&
            pt.y() >= rect.top() && pt.y() <= rect.bottom()) {
        return true;
    } else {
        return false;
    }
}

void MainWindow::mousePressEvent(QMouseEvent *event)
{
    int i,id,n;
    int out_index = -1;
    int in_index = -1;

    QRectF rcAll = rect();
    if (event->button() == Qt::LeftButton) {
        int offset;
        if (mjhz.players[0].tiles[MJHZ_MAX_PAIS-1] != 0)
            offset = 6;
        else
            offset = 0;
        n = 0;
        for (i = 0; i < MJHZ_MAX_PAIS; ++i) {
            if (mjhz.players[0].tiles[i] != 0)
                n++;
        }

        int x = (rcAll.width() - (n * MJPAI_W) - offset) / 2;
        int y = rcAll.bottom() - MJPAI_H;

        QPoint pos = event->pos();
        for (i = 0; i < MJHZ_MAX_PAIS; i++) {
            if (mjhz.players[0].tiles[i] == 0)
                continue;
            if (i == (MJHZ_MAX_PAIS - 1))
                x += 6;
            QRect rcPai(x, y, MJPAI_W, MJPAI_H);
            if (pointInRect(pos, rcPai)) {
                // 选中了牌
                out_index = i;
                break;
            }
            x += MJPAI_W;
        }
        if (out_index != -1) {
            id = mjhz.players[0].tiles[out_index];
            mjhz.players[0].tiles_js[id]--;
            mjhz.players[0].tiles[out_index] = 0;
            mj_trim(mjhz.players[0].tiles, MJHZ_MAX_PAIS);
            mjhz_sort(mjhz.players[0].tiles);
            update();
        } else {
            QRect rcIn(0, 0, 9 * MJPAI_W, MJPAI_H);
            if (pointInRect(pos, rcIn)) {
                // 选了万子
                in_index = MJ_ID_1W + pos.x() / MJPAI_W;
            }
            rcIn.setRect(0, MJPAI_H, 9 * MJPAI_W, MJPAI_H);
            if (pointInRect(pos, rcIn)) {
                // 选了索子
                in_index = MJ_ID_1S + pos.x() / MJPAI_W;
            }
            rcIn.setRect(0, 2 * MJPAI_H, 9 * MJPAI_W, MJPAI_H);
            if (pointInRect(pos, rcIn)) {
                // 选了筒子
                in_index = MJ_ID_1T + pos.x() / MJPAI_W;
            }
            rcIn.setRect(0, 3 * MJPAI_H, 7 * MJPAI_W, MJPAI_H);
            if (pointInRect(pos, rcIn)) {
                // 字牌
                in_index = MJ_ID_DONG + pos.x() / MJPAI_W;
            }
            if (in_index != -1) {
                for (i = 0; i < MJHZ_MAX_PAIS; ++i) {
                    if (mjhz.players[0].tiles[i] == 0) {
                        mjhz.players[0].tiles[i] = in_index;
                        mjhz.players[0].tiles_js[in_index]++;
                        update();
                        break;
                    }
                }
            }
        }
    }
}

void MainWindow::on_pushButton_clicked()
{
    if (mjhz_can_hu(&mjhz, 0) > 0) {
        // 胡了
        _hu = 1;
        if (mjhz.players[0].hu.is_pair7) {
            ui->listWidget->addItem(tr("七对子"));
        }
        update();
    } else {
        _hu = 0;
    }
}
<commit_msg>fixed bug<commit_after>#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPainter>
#include <QResizeEvent>
#include <time.h>

#include "../../src/mjhz.h"

#define MJPAI_W 42
#define MJPAI_H 60

mjhz_t mjhz;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QRect rc = geometry();
    setFixedSize(rc.width(), rc.height());
    _winH = rc.height();
    _winW = rc.width();

    srand(time(NULL));

    _hu = 0;
    _imgTiles.load(":/res/mj.png");
    _imgHu.load(":/res/hu.png");

    mjhz_init(&mjhz, 0, 4);
    mjhz_start(&mjhz);
    mjhz_sort(mjhz.players[0].tiles);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::resizeEvent(QResizeEvent *event)
{
    QSize sz = event->size();
    _winW = sz.width();
    _winH = sz.height();
}

void MainWindow::paintEvent(QPaintEvent*)
{
    int i;
    int x,y,n;

    QPainter painter(this);
    QRectF rcAll = rect();
    QBrush brush(QColor(16, 114, 16));
    painter.fillRect(rcAll, brush);

    x = y = 0;
    n = 1;
    for (i = 0; i < 34; ++i) {
        QRect rcSrc(n * MJPAI_W, 0, MJPAI_W, MJPAI_H);
        QRect rcDest(x, y, MJPAI_W, MJPAI_H);
        painter.drawPixmap(rcDest, _imgTiles, rcSrc);
        n++;
        x += MJPAI_W;
        if ((n -1) % 9 == 0) {
            x = 0;
            y += MJPAI_H;
        }
    }

    int offset;
    if (mjhz.players[0].tiles[MJHZ_MAX_PAIS-1] != 0)
        offset = 6;
    else
        offset = 0;
    n = 0;
    for (i = 0; i < MJHZ_MAX_PAIS; ++i) {
        if (mjhz.players[0].tiles[i] != 0)
            n++;
    }

    x = (rcAll.width() - (n * MJPAI_W) - offset) / 2;
    y = rcAll.bottom() - MJPAI_H;
    for (i = 0; i < MJHZ_MAX_PAIS; ++i) {
        if (mjhz.players[0].tiles[i] == 0)
            continue;
        QRect rcSrc(mjhz.players[0].tiles[i] * MJPAI_W,
                0, MJPAI_W, MJPAI_H);
        if (i == (MJHZ_MAX_PAIS - 1)) {
            x += 6;
        }
        QRect rcDest(x, y, MJPAI_W, MJPAI_H);
        painter.drawPixmap(rcDest, _imgTiles, rcSrc);
        x += MJPAI_W;
    }

    if (_hu) {
        painter.drawPixmap(rcAll.right() - _imgHu.width(),
                           rcAll.bottom() - _imgHu.height(),
                           _imgHu);
    }
}

bool MainWindow::pointInRect(const QPoint &pt, const QRect &rect)
{
    if (pt.x() >= rect.left() && pt.x() <= rect.right() &&
            pt.y() >= rect.top() && pt.y() <= rect.bottom()) {
        return true;
    } else {
        return false;
    }
}

void MainWindow::mousePressEvent(QMouseEvent *event)
{
    int i,id,n;
    int out_index = -1;
    int in_index = -1;

    QRectF rcAll = rect();
    if (event->button() == Qt::LeftButton) {
        int offset;
        if (mjhz.players[0].tiles[MJHZ_MAX_PAIS-1] != 0)
            offset = 6;
        else
            offset = 0;
        n = 0;
        for (i = 0; i < MJHZ_MAX_PAIS; ++i) {
            if (mjhz.players[0].tiles[i] != 0)
                n++;
        }

        int x = (rcAll.width() - (n * MJPAI_W) - offset) / 2;
        int y = rcAll.bottom() - MJPAI_H;

        QPoint pos = event->pos();
        for (i = 0; i < MJHZ_MAX_PAIS; i++) {
            if (mjhz.players[0].tiles[i] == 0)
                continue;
            if (i == (MJHZ_MAX_PAIS - 1))
                x += 6;
            QRect rcPai(x, y, MJPAI_W, MJPAI_H);
            if (pointInRect(pos, rcPai)) {
                // 选中了牌
                out_index = i;
                break;
            }
            x += MJPAI_W;
        }
        if (out_index != -1) {
            id = mjhz.players[0].tiles[out_index];
            mjhz.players[0].tiles_js[id]--;
            mjhz.players[0].tiles[out_index] = 0;
            mj_trim(mjhz.players[0].tiles, MJHZ_MAX_PAIS);
            mjhz_sort(mjhz.players[0].tiles);
            update();
        } else {
            QRect rcIn(0, 0, 9 * MJPAI_W, MJPAI_H);
            if (pointInRect(pos, rcIn)) {
                // 选了万子
                in_index = MJ_ID_1W + pos.x() / MJPAI_W;
            }
            rcIn.setRect(0, MJPAI_H, 9 * MJPAI_W, MJPAI_H);
            if (pointInRect(pos, rcIn)) {
                // 选了索子
                in_index = MJ_ID_1S + pos.x() / MJPAI_W;
            }
            rcIn.setRect(0, 2 * MJPAI_H, 9 * MJPAI_W, MJPAI_H);
            if (pointInRect(pos, rcIn)) {
                // 选了筒子
                in_index = MJ_ID_1T + pos.x() / MJPAI_W;
            }
            rcIn.setRect(0, 3 * MJPAI_H, 7 * MJPAI_W, MJPAI_H);
            if (pointInRect(pos, rcIn)) {
                // 字牌
                in_index = MJ_ID_DONG + pos.x() / MJPAI_W;
            }
            if (in_index != -1) {
                for (i = 0; i < MJHZ_MAX_PAIS; ++i) {
                    if (mjhz.players[0].tiles[i] == 0) {
                        mjhz.players[0].tiles[i] = in_index;
                        mjhz.players[0].tiles_js[in_index]++;
                        update();
                        break;
                    }
                }
            }
        }
    }
}

void MainWindow::on_pushButton_clicked()
{
    ui->listWidget->clear();
    if (mjhz_can_hu(&mjhz, 0) > 0) {
        // 胡了
        _hu = 1;
        if (mjhz.players[0].hu.is_pair7) {
            ui->listWidget->addItem(tr("七对子"));
        }
        if (mjhz.players[0].hu.pair7_h4 > 0) {
            QString str =
                    QString("豪华对数:%1").arg(mjhz.players[0].hu.pair7_h4);
            ui->listWidget->addItem(str);
        }
    } else {
        _hu = 0;
    }
    update();
}
<|endoftext|>


<commit_before>/* Copyright © 2001-2015, Canal TP and/or its affiliates. All rights reserved.

This file is part of Navitia,
    the software to build cool stuff with public transport.

Hope you'll enjoy and contribute to this project,
    powered by Canal TP (www.canaltp.fr).
Help us simplify mobility and open public transport:
    a non ending quest to the responsive locomotion way of traveling!

LICENCE: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

Stay tuned using
twitter @navitia
IRC #navitia on freenode
https://groups.google.com/d/forum/navitia
www.navitia.io
*/

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE associated_calendar_test
#include <boost/test/unit_test.hpp>
#include "utils/logger.h"
#include "type/data.h"
#include "type/pt_data.h"
#include <boost/algorithm/string.hpp>

struct logger_initialized {
    logger_initialized()   { init_logger(); }
};
BOOST_GLOBAL_FIXTURE( logger_initialized )

struct ArgsFixture {
   ArgsFixture() {
       auto argc = boost::unit_test::framework::master_test_suite().argc;
       auto argv = boost::unit_test::framework::master_test_suite().argv;

       //we should have at least more than one arg, the first is the exe name, the rest is the input file paths
       BOOST_REQUIRE(argc > 1);

       for (int i(1); i < argc; ++i) {
           std::vector<std::string> arg;

           std::string raw_arg = argv[i];
           // dumb method, we erase all '-' not to bother with the '--bob=toto' format
           boost::erase_all(raw_arg, "-");
           boost::split(arg, raw_arg, boost::is_any_of("="));

           BOOST_REQUIRE_EQUAL(arg.size(), 2);
           input_file_paths[arg.at(0)] = arg.at(1);
       }
   }

   std::map<std::string, std::string> input_file_paths;
};

BOOST_FIXTURE_TEST_CASE(fusio_test, ArgsFixture) {
    const auto input_file = input_file_paths.at("ntfs_file");
    navitia::type::Data data;

    const auto res = data.load(input_file);

    BOOST_REQUIRE(res);

    BOOST_REQUIRE_EQUAL(data.pt_data->networks.size(), 1);
    BOOST_CHECK_EQUAL(data.pt_data->networks[0]->name, "ligne flixible");
    BOOST_CHECK_EQUAL(data.pt_data->networks[0]->uri, "network:ligneflexible");

    // check stop_time headsigns
    const navitia::type::HeadsignHandler& headsigns = data.pt_data->headsign_handler;
    auto& vj_vec = data.pt_data->vehicle_journeys;
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[0]->stop_time_list[0]), "N1");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[0]->stop_time_list[1]), "N1");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[0]->stop_time_list[2]), "N1");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[0]->stop_time_list[3]), "N2");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[0]->stop_time_list[4]), "N2");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[1]->stop_time_list[0]), "N1");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[1]->stop_time_list[1]), "N1");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[1]->stop_time_list[2]), "N1");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[1]->stop_time_list[3]), "N2");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[1]->stop_time_list[4]), "N2");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[2]->stop_time_list[0]), "vehiclejourney2");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[2]->stop_time_list[1]), "vehiclejourney2");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[2]->stop_time_list[2]), "vehiclejourney2");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[2]->stop_time_list[3]), "vehiclejourney2");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[2]->stop_time_list[4]), "vehiclejourney2");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[3]->stop_time_list[0]), "vehiclejourney2");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[3]->stop_time_list[1]), "vehiclejourney2");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[3]->stop_time_list[2]), "vehiclejourney2");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[3]->stop_time_list[3]), "vehiclejourney2");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[3]->stop_time_list[4]), "vehiclejourney2");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[4]->stop_time_list[0]), "vehiclejourney3");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[4]->stop_time_list[1]), "vehiclejourney3");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[4]->stop_time_list[2]), "vehiclejourney3");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[4]->stop_time_list[3]), "vehiclejourney3");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[4]->stop_time_list[4]), "vehiclejourney3");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[4]->stop_time_list[5]), "vehiclejourney3");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[5]->stop_time_list[0]), "vehiclejourney3");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[5]->stop_time_list[1]), "vehiclejourney3");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[5]->stop_time_list[2]), "vehiclejourney3");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[5]->stop_time_list[3]), "vehiclejourney3");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[5]->stop_time_list[4]), "vehiclejourney3");
    BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[5]->stop_time_list[5]), "vehiclejourney3");
    // check vj from headsign
    BOOST_CHECK_EQUAL(headsigns.get_vj_from_headsign("vehiclejourney1").size(), 2);
    BOOST_CHECK(navitia::contains(headsigns.get_vj_from_headsign("vehiclejourney1"), vj_vec[0]));
    BOOST_CHECK(navitia::contains(headsigns.get_vj_from_headsign("vehiclejourney1"), vj_vec[1]));
    BOOST_CHECK_EQUAL(headsigns.get_vj_from_headsign("N1").size(), 2);
    BOOST_CHECK(navitia::contains(headsigns.get_vj_from_headsign("N1"), vj_vec[0]));
    BOOST_CHECK(navitia::contains(headsigns.get_vj_from_headsign("N1"), vj_vec[1]));
    BOOST_CHECK_EQUAL(headsigns.get_vj_from_headsign("N2").size(), 2);
    BOOST_CHECK(navitia::contains(headsigns.get_vj_from_headsign("N2"), vj_vec[0]));
    BOOST_CHECK(navitia::contains(headsigns.get_vj_from_headsign("N2"), vj_vec[1]));
    BOOST_CHECK_EQUAL(headsigns.get_vj_from_headsign("vehiclejourney2").size(), 2);
    BOOST_CHECK(navitia::contains(headsigns.get_vj_from_headsign("vehiclejourney2"), vj_vec[2]));
    BOOST_CHECK(navitia::contains(headsigns.get_vj_from_headsign("vehiclejourney2"), vj_vec[3]));
    BOOST_CHECK_EQUAL(headsigns.get_vj_from_headsign("vehiclejourney3").size(), 2);
    BOOST_CHECK(navitia::contains(headsigns.get_vj_from_headsign("vehiclejourney3"), vj_vec[4]));
    BOOST_CHECK(navitia::contains(headsigns.get_vj_from_headsign("vehiclejourney3"), vj_vec[5]));
}
<commit_msg>factorize tests<commit_after>/* Copyright © 2001-2015, Canal TP and/or its affiliates. All rights reserved.

This file is part of Navitia,
    the software to build cool stuff with public transport.

Hope you'll enjoy and contribute to this project,
    powered by Canal TP (www.canaltp.fr).
Help us simplify mobility and open public transport:
    a non ending quest to the responsive locomotion way of traveling!

LICENCE: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

Stay tuned using
twitter @navitia
IRC #navitia on freenode
https://groups.google.com/d/forum/navitia
www.navitia.io
*/

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE associated_calendar_test
#include <boost/test/unit_test.hpp>
#include "utils/logger.h"
#include "type/data.h"
#include "type/pt_data.h"
#include <boost/algorithm/string.hpp>

struct logger_initialized {
    logger_initialized()   { init_logger(); }
};
BOOST_GLOBAL_FIXTURE( logger_initialized )

struct ArgsFixture {
   ArgsFixture() {
       auto argc = boost::unit_test::framework::master_test_suite().argc;
       auto argv = boost::unit_test::framework::master_test_suite().argv;

       //we should have at least more than one arg, the first is the exe name, the rest is the input file paths
       BOOST_REQUIRE(argc > 1);

       for (int i(1); i < argc; ++i) {
           std::vector<std::string> arg;

           std::string raw_arg = argv[i];
           // dumb method, we erase all '-' not to bother with the '--bob=toto' format
           boost::erase_all(raw_arg, "-");
           boost::split(arg, raw_arg, boost::is_any_of("="));

           BOOST_REQUIRE_EQUAL(arg.size(), 2);
           input_file_paths[arg.at(0)] = arg.at(1);
       }
   }

   std::map<std::string, std::string> input_file_paths;
};

// check headsign value for stop times on given vjs
static void check_headsigns(const navitia::type::Data& data, const std::string& headsign,
                     size_t first_it_vj, size_t last_it_vj,
                     size_t first_it_st = 0, size_t last_it_st = std::numeric_limits<size_t>::max()) {
    const navitia::type::HeadsignHandler& headsigns = data.pt_data->headsign_handler;
    auto& vj_vec = data.pt_data->vehicle_journeys;
    for (size_t it_vj = first_it_vj; it_vj <= last_it_vj; ++it_vj) {
        size_t real_last_it_st = vj_vec[it_vj]->stop_time_list.size() - 1;
        if (real_last_it_st > last_it_st) {
            real_last_it_st = last_it_st;
        }
        for (size_t it_st = first_it_st; it_st <= real_last_it_st; ++it_st) {
            BOOST_CHECK_EQUAL(headsigns.get_headsign(vj_vec[it_vj]->stop_time_list[it_st]), headsign);
        }
    }
}

BOOST_FIXTURE_TEST_CASE(fusio_test, ArgsFixture) {
    const auto input_file = input_file_paths.at("ntfs_file");
    navitia::type::Data data;

    const auto res = data.load(input_file);

    BOOST_REQUIRE(res);

    BOOST_REQUIRE_EQUAL(data.pt_data->networks.size(), 1);
    BOOST_CHECK_EQUAL(data.pt_data->networks[0]->name, "ligne flixible");
    BOOST_CHECK_EQUAL(data.pt_data->networks[0]->uri, "network:ligneflexible");

    // check stop_time headsigns
    const navitia::type::HeadsignHandler& headsigns = data.pt_data->headsign_handler;
    auto& vj_vec = data.pt_data->vehicle_journeys;
    // check that vj 0 & 1 have headsign N1 from first 3 stpop_time, then N2
    check_headsigns(data, "N1", 0, 1, 0, 2);
    check_headsigns(data, "N2", 0, 1, 3, 4);
    // vj 2 & 3 are named vehiclejourney2 with no headsign overload, 4 & 5 are named vehiclejourney3
    check_headsigns(data, "vehiclejourney2", 2, 3);
    check_headsigns(data, "vehiclejourney3", 4, 5);
    // check vj from headsign
    BOOST_CHECK_EQUAL(headsigns.get_vj_from_headsign("vehiclejourney1").size(), 2);
    BOOST_CHECK(navitia::contains(headsigns.get_vj_from_headsign("vehiclejourney1"), vj_vec[0]));
    BOOST_CHECK(navitia::contains(headsigns.get_vj_from_headsign("vehiclejourney1"), vj_vec[1]));
    BOOST_CHECK_EQUAL(headsigns.get_vj_from_headsign("N1").size(), 2);
    BOOST_CHECK(navitia::contains(headsigns.get_vj_from_headsign("N1"), vj_vec[0]));
    BOOST_CHECK(navitia::contains(headsigns.get_vj_from_headsign("N1"), vj_vec[1]));
    BOOST_CHECK_EQUAL(headsigns.get_vj_from_headsign("N2").size(), 2);
    BOOST_CHECK(navitia::contains(headsigns.get_vj_from_headsign("N2"), vj_vec[0]));
    BOOST_CHECK(navitia::contains(headsigns.get_vj_from_headsign("N2"), vj_vec[1]));
    BOOST_CHECK_EQUAL(headsigns.get_vj_from_headsign("vehiclejourney2").size(), 2);
    BOOST_CHECK(navitia::contains(headsigns.get_vj_from_headsign("vehiclejourney2"), vj_vec[2]));
    BOOST_CHECK(navitia::contains(headsigns.get_vj_from_headsign("vehiclejourney2"), vj_vec[3]));
    BOOST_CHECK_EQUAL(headsigns.get_vj_from_headsign("vehiclejourney3").size(), 2);
    BOOST_CHECK(navitia::contains(headsigns.get_vj_from_headsign("vehiclejourney3"), vj_vec[4]));
    BOOST_CHECK(navitia::contains(headsigns.get_vj_from_headsign("vehiclejourney3"), vj_vec[5]));
}
<|endoftext|>