<commit_before>#include "sys/socket.h"
#include <netinet/in.h>
#include <arpa/inet.h>
#include "linux/if_alg.h"
#include "iostream"
#include "string.h"
#include "unistd.h"
#include "fcntl.h"
#include "sys/time.h"
#include "sys/syscall.h"
#include "assert.h"

using namespace std;

static uint64_t now_usec()
{
	struct timeval tv;
	gettimeofday(&tv, nullptr);
	return tv.tv_sec*1000000 + tv.tv_usec;
}

class Sink {
public:
  virtual ~Sink() = default;

  virtual int get_fd() = 0;
  virtual const char* get_name() const = 0;
  virtual void clean(size_t len) = 0;
};

class PipeSink : public Sink {
  const size_t min_pipe_size;
  int fds[2];
  int null_fd;

public:
  PipeSink(const size_t min_pipe_size)
    : min_pipe_size(min_pipe_size) {
    int r = ::pipe(fds);
    assert(r == 0);

    r = ::fcntl(fds[1], F_SETPIPE_SZ, min_pipe_size);
    assert(r >= min_pipe_size);

    null_fd = ::open("/dev/null", O_WRONLY);
    assert(null_fd > 0);
  }

  ~PipeSink() {
    ::close(null_fd);

    ::close(fds[0]);
    ::close(fds[1]);
  }

  int get_fd() override {
    return fds[1];
  }

  const char* get_name() const override {
    return "pipe";
  }

  void clean(const size_t size) override {
    int r = ::splice(fds[0], nullptr, null_fd, nullptr, size, SPLICE_F_MOVE);
    assert(size == r);
  }
};

class FileSink : public Sink {
  int file_fd;

public:
  FileSink() {
    file_fd = ::open("/tmp/mem2fd", O_WRONLY | O_CREAT, S_IWUSR);
    //file_fd = ::open("/run/user/1000/mem2fd", O_WRONLY | O_CREAT, S_IWUSR);
    assert(file_fd > 0);
  }

  ~FileSink() {
    ::close(file_fd);
  }

  int get_fd() override {
    return file_fd;
  }

  const char* get_name() const override {
    return "file";
  }

  void clean(const size_t) override {
    off_t r = lseek(file_fd, 0, SEEK_SET);
    assert(r == 0);
  }
};

class SockSink : public Sink {
  int fds[2];
  int clean_fds[2];
  int null_fd;

  static int tcp_pipe(int (&fds)[2]) {
    int source_fd = -1;
    int sink_fd = -1;
    int server_fd = -1;
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(struct sockaddr_in));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = 0;
    try {
      server_fd = socket(AF_INET, SOCK_STREAM, 0);
      if (server_fd < 0) {
        throw (__LINE__);
      }
      int enable = 1;
      if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) != 0) {
        throw __LINE__;
      }
      if (bind(server_fd, (const struct sockaddr*) &server_addr, sizeof(server_addr)) != 0) {
        throw __LINE__;
      }
      socklen_t len = sizeof(sockaddr_in);
      if (getsockname(server_fd, (struct sockaddr*)&server_addr, &len) != 0) {
        throw __LINE__;
      }
      if(server_addr.sin_port == 0) {
        //derr << "Port == 0" << dendl;
      }
      int ret =0;
#if 0
      int bufsize = 4194304000;

      ret = setsockopt(server_fd, SOL_SOCKET, SO_RCVBUF, &bufsize,
                       sizeof(bufsize));
      assert(0 == ret);

      ret = setsockopt(server_fd, SOL_SOCKET, SO_SNDBUF, &bufsize,
                       sizeof(bufsize));
#endif
      assert(0 == ret);
      if (listen(server_fd, 1) != 0) {
        throw __LINE__;
      }
      sink_fd = socket(AF_INET, SOCK_STREAM, 0);
      if (sink_fd < 0) {
        throw __LINE__;
      }

#if 0
      ret = setsockopt(sink_fd, SOL_SOCKET, SO_RCVBUF, &bufsize,
                       sizeof(bufsize));
      assert(0 == ret);

      ret = setsockopt(sink_fd, SOL_SOCKET, SO_SNDBUF, &bufsize,
                       sizeof(bufsize));
      assert(0 == ret);
#endif

      if (fcntl(sink_fd, F_SETFL, fcntl(sink_fd, F_GETFL,0) | O_NONBLOCK) !=0) {
        throw __LINE__;
      }
      if (connect(sink_fd, (const struct sockaddr*) &server_addr, sizeof(server_addr)) != -1) {
        throw __LINE__;
      }
      if (errno != EINPROGRESS) {
        throw __LINE__;
      }
      source_fd = accept(server_fd, nullptr, nullptr);
      if (source_fd < 0) {
        throw __LINE__;
      }
      if (fcntl(sink_fd, F_SETFL, fcntl(sink_fd, F_GETFL,0) & ~O_NONBLOCK) != 0) {
        throw __LINE__;
      }

      ::close(server_fd);

#if 0
      ret = setsockopt(source_fd, SOL_SOCKET, SO_RCVBUF, &bufsize,
                       sizeof(bufsize));

      ret = setsockopt(source_fd, SOL_SOCKET, SO_SNDBUF, &bufsize,
                       sizeof(bufsize));
      assert(0 == ret);
#endif

      fds[1] = sink_fd;
      fds[0] = source_fd;
      return 0;

    } catch (int line) {
      //derr << "Error tcp_pipe at" << line << dendl;
      printf("ka boom in line: %d, errno=%d\n", line, errno);
      if (sink_fd>=0) {
        close(sink_fd);
      }
      if (source_fd>=0) {
        close(source_fd);
      }
      if (server_fd>=0) {
        close(server_fd);
      }
      return -1;
    }
  }

public:
  SockSink(const size_t chunk_size) {
    int r = tcp_pipe(fds);
    assert(r == 0);

    r = ::pipe(clean_fds);
    assert(r == 0);
    r = ::fcntl(clean_fds[1], F_SETPIPE_SZ, chunk_size);
    assert(r >= chunk_size);

    null_fd = ::open("/dev/null", O_WRONLY);
    assert(null_fd > 0);
  }

  ~SockSink() {
    ::close(null_fd);

    ::close(clean_fds[0]);
    ::close(clean_fds[1]);

    ::close(fds[0]);
    ::close(fds[1]);
  }

  int get_fd() override {
    return fds[1];
  }

  const char* get_name() const override {
    return "sock";
  }

  void clean(const size_t size) override {
    char junk[size];

#if 1
    size_t r = read(fds[0], junk, size);
    assert(r == size);
#else
    size_t r = ::splice(fds[0], nullptr, clean_fds[1], nullptr, size, SPLICE_F_MOVE);
    assert(size == r);

    r = ::splice(clean_fds[0], nullptr, null_fd, nullptr, size, SPLICE_F_MOVE);
    assert(size == r);
#endif
  }
};

class Clock
{
  friend class Range;

  uint64_t t = 0;
  uint64_t wall_t = 0;

public:
  class Range;

  uint64_t get_wall() const {
    return wall_t;
  }
};

class Clock::Range {
  static uint64_t now_thread_usec() {
    struct timespec x;
    ::clock_gettime(CLOCK_THREAD_CPUTIME_ID, &x);
    return x.tv_sec * 1000000000L + x.tv_nsec;
  }

  static uint64_t now_wall_usec()
  {
    struct timespec x;
    ::clock_gettime(CLOCK_MONOTONIC_RAW, &x);
    return x.tv_sec * 1000000000L + x.tv_nsec;
  }

public:
  Clock* const p;

  Range(Clock* p) : p(p) {
    p->t -= now_thread_usec();
    p->wall_t -= now_wall_usec();
  }

  ~Range() {
    {
      uint64_t m1 = now_thread_usec();
      uint64_t m2 = now_thread_usec();
      p->t += m1 - (m2 - m1);
    }
    {
      uint64_t m1 = now_wall_usec();
      uint64_t m2 = now_wall_usec();
      p->wall_t += m1 - (m2 - m1);
    }
  }
};

class Feeder {
  Clock feeding_clk;

  virtual size_t write(int fd, void* buf, size_t len) = 0;

public:
  virtual ~Feeder() = default;
  virtual size_t write(Sink& sink, void* const buf, const size_t len) final {
    Clock::Range range(&feeding_clk);
    return write(sink.get_fd(), buf, len);
  }

  virtual uint64_t get_feeding_time() const {
    return feeding_clk.get_wall();
  };

  virtual const char* get_name() const = 0;
};

class WriteFeeder : public Feeder {
public:
  size_t write(const int fd, void* const buf, const size_t size) override {
    return ::write(fd, buf, size);
  }

  const char* get_name() const override {
    return "write";
  }
};

class WriteVFeeder : public Feeder  {
public:
  size_t write(const int fd, void* const buf, const size_t size) override {
    struct iovec vec = {
      .iov_base = buf,
      .iov_len  = size,
    };

    return ::writev(fd, &vec, 1);
  }

  const char* get_name() const override {
    return "writev";
  }
};

class VMSpliceFeeder : public Feeder {
protected:
  int fds[2];

  size_t do_vmsplice(const int fd,
                     void* const buf,
                     const size_t size,
                     const unsigned int flags) {
    const struct iovec vec = {
      .iov_base = buf,
      .iov_len  = size
    };

    int r = ::vmsplice(fds[1], &vec, 1, flags | SPLICE_F_MOVE);// | SPLICE_F_MORE);
    assert(size == r);

    r = ::splice(fds[0], nullptr, fd, nullptr, size,
                 SPLICE_F_MOVE);// | SPLICE_F_MORE);
    assert(size == r);
    return r;
  }

  size_t write(const int fd, void* const buf, const size_t size) override {
    return do_vmsplice(fd, buf, size, 0);
  }

public:
  VMSpliceFeeder(const size_t max_size) {
    int r = ::pipe(fds);
    assert(r == 0);

    r = ::fcntl(fds[1], F_SETPIPE_SZ, max_size);
    assert(r >= max_size);
  }

  ~VMSpliceFeeder() override {
    ::close(fds[0]);
    ::close(fds[1]);
  }

  const char* get_name() const override {
    return "vmsplice_0";
  }
};

class GiftingVMSpliceFeeder : public VMSpliceFeeder {
  size_t write(const int fd, void* const buf, const size_t size) override {
    return do_vmsplice(fd, buf, size, SPLICE_F_GIFT);
  }

public:
  using VMSpliceFeeder::VMSpliceFeeder;

  const char* get_name() const override {
    return "vmsplice_gift";
  }
};

int main(int argc, char** argv)
{
  uint64_t chunk_size = 1024;
  int progression = 0;

  printf(       "               "
                " ----total-for-all-executed-jobs----"
                " ------per-single-executed-job-----\n");
  printf("%10s %14s %10s %8s %14s %14s\n",
         "sink", // 10
         "feeder", // 14
         "chunk size", // 8
         "iters", // 9
         "transfered", // 14
         "iter time");
  printf(
         "                            (bytes)"
         "            (MiB)          (MiB/s)     (usec)\n");

  static constexpr size_t mem_mul = 10;
  do /* chunk size */ {
    void *mem = aligned_alloc(4096, chunk_size * mem_mul + 4096);
    assert(mem != nullptr);

    /* Sinks. */
    PipeSink pipe_sink(chunk_size);
    SockSink sock_sink(chunk_size);
    FileSink file_sink;
    std::initializer_list<Sink*> sinks = {
      &pipe_sink, &sock_sink, &file_sink,
    };

    /* Feeders. */
    WriteFeeder write_fed;
    WriteVFeeder writev_fed;
    VMSpliceFeeder vmsplice0_fed(chunk_size);
    GiftingVMSpliceFeeder vmsplice_gift_fed(chunk_size);

    std::initializer_list<Feeder*> feeders = {
      &write_fed, &writev_fed, &vmsplice0_fed, &vmsplice_gift_fed
    };

    for (auto sink : sinks) {
      for (auto feeder : feeders) {
        const uint64_t start = now_usec();
        uint64_t no_tests = 0, end = 0;

        do /* time */ {
          void *wrk_mem = static_cast<char*>(mem)
                        + chunk_size * (no_tests % mem_mul);
          size_t written = feeder->write(*sink, wrk_mem, chunk_size);
          assert(chunk_size == written);

          sink->clean(chunk_size);

          no_tests++;
          end = now_usec();
        } while (end - start < 1 * 1000 * 1000);

        const double total_bytes = static_cast<double>(chunk_size) * no_tests;
        const double total_mbytes = total_bytes / (1024 * 1024);

        const double total_secs = static_cast<double>(feeder->get_feeding_time())
                                / (1000.0 * 1000.0 * 1000.0);
        printf("%10s %14s %10lu %8lu %9.2lf %14.2lf %14.3lf\n",
               sink->get_name(),
               feeder->get_name(),
               chunk_size,
               no_tests,
               total_mbytes,
               total_mbytes / total_secs,
               (double)(feeder->get_feeding_time())/no_tests);
      }
    }

    free(mem);

    printf("-------\n");

#if 0
    const double next[4] = { 5./4, 6./5, 7./6, 8./7 };
    chunk_size = chunk_size * next[progression];
    progression = (progression + 1) % 4 ;
#else
    chunk_size *= 2;
#endif
  } while(chunk_size < 100000000000);
}
<commit_msg>Clean up the socket-based sink.<commit_after>#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include "linux/if_alg.h"
#include "iostream"
#include "string.h"
#include "unistd.h"
#include "fcntl.h"
#include "sys/time.h"
#include "sys/syscall.h"
#include "assert.h"

static constexpr char FILE_SINK_FILEPATH[] = "/run/user/1000/mem2fd";

static uint64_t now_usec()
{
	struct timeval tv;
	gettimeofday(&tv, nullptr);
	return tv.tv_sec*1000000 + tv.tv_usec;
}

class Sink {
public:
  virtual ~Sink() = default;

  virtual int get_fd() = 0;
  virtual const char* get_name() const = 0;
  virtual void clean(size_t len) = 0;
};

class PipeSink : public Sink {
  const size_t min_pipe_size;
  int fds[2];
  int null_fd;

public:
  PipeSink(const size_t min_pipe_size)
    : min_pipe_size(min_pipe_size) {
    int r = ::pipe(fds);
    assert(r == 0);

    r = ::fcntl(fds[1], F_SETPIPE_SZ, min_pipe_size);
    assert(r >= min_pipe_size);

    null_fd = ::open("/dev/null", O_WRONLY);
    assert(null_fd > 0);
  }

  ~PipeSink() {
    ::close(null_fd);

    ::close(fds[0]);
    ::close(fds[1]);
  }

  int get_fd() override {
    return fds[1];
  }

  const char* get_name() const override {
    return "pipe";
  }

  void clean(const size_t size) override {
    int r = ::splice(fds[0], nullptr, null_fd, nullptr, size, SPLICE_F_MOVE);
    assert(size == r);
  }
};

class FileSink : public Sink {
  int file_fd;

public:
  FileSink() {
    file_fd = ::open(FILE_SINK_FILEPATH, O_WRONLY | O_CREAT, S_IWUSR);
    assert(file_fd > 0);
  }

  ~FileSink() {
    ::close(file_fd);
  }

  int get_fd() override {
    return file_fd;
  }

  const char* get_name() const override {
    return "file";
  }

  void clean(const size_t) override {
    off_t r = lseek(file_fd, 0, SEEK_SET);
    assert(r == 0);
  }
};

class SockSink : public Sink {
  int fds[2];
  int clean_fds[2];
  int null_fd;

  static int tcp_pipe(int (&fds)[2]) {
    int source_fd = -1;
    int sink_fd = -1;
    int server_fd = -1;
    struct sockaddr_in server_addr;

    memset(&server_addr, 0, sizeof(struct sockaddr_in));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = 0;

    server_fd = ::socket(AF_INET, SOCK_STREAM, 0);
    assert(server_fd > 0);

    int enable = 1;
    int r = ::setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
    assert(r == 0);

    r = ::bind(server_fd, (const struct sockaddr*) &server_addr, sizeof(server_addr));
    assert(r == 0);

    socklen_t len = sizeof(sockaddr_in);
    r = ::getsockname(server_fd, (struct sockaddr*)&server_addr, &len);
    assert(r == 0);

    if(server_addr.sin_port == 0) {
      //derr << "Port == 0" << dendl;
    }

    r = ::listen(server_fd, 1);
    assert(r == 0);

    sink_fd = ::socket(AF_INET, SOCK_STREAM, 0);
    assert(sink_fd >= 0);

    r = ::fcntl(sink_fd, F_SETFL, fcntl(sink_fd, F_GETFL,0) | O_NONBLOCK);
    assert(r == 0);

    int i = 1;
    r = ::setsockopt(sink_fd, IPPROTO_TCP, TCP_NODELAY,
                     static_cast<void*>(&i), sizeof(i));
    assert(r == 0);

    r = ::connect(sink_fd, (const struct sockaddr*) &server_addr, sizeof(server_addr));
    assert(r == -1);
    assert(errno == EINPROGRESS);

    source_fd = ::accept(server_fd, nullptr, nullptr);
    assert(source_fd >= 0);

    r = ::fcntl(sink_fd, F_SETFL, fcntl(sink_fd, F_GETFL,0) & ~O_NONBLOCK);
    assert(r == 0);

    ::close(server_fd);

    fds[1] = sink_fd;
    fds[0] = source_fd;
    return 0;
  }

public:
  SockSink(const size_t chunk_size) {
    int r = tcp_pipe(fds);
    assert(r == 0);

    r = ::pipe(clean_fds);
    assert(r == 0);
    r = ::fcntl(clean_fds[1], F_SETPIPE_SZ, chunk_size);
    assert(r >= chunk_size);

    null_fd = ::open("/dev/null", O_WRONLY);
    assert(null_fd > 0);
  }

  ~SockSink() {
    ::close(null_fd);

    ::close(clean_fds[0]);
    ::close(clean_fds[1]);

    ::close(fds[0]);
    ::close(fds[1]);
  }

  int get_fd() override {
    return fds[1];
  }

  const char* get_name() const override {
    return "sock";
  }

  void clean(const size_t size) override {
    char junk[size];

#if 1
    size_t r = read(fds[0], junk, size);
    assert(r == size);
#else
    size_t r = ::splice(fds[0], nullptr, clean_fds[1], nullptr, size, SPLICE_F_MOVE);
    assert(size == r);

    r = ::splice(clean_fds[0], nullptr, null_fd, nullptr, size, SPLICE_F_MOVE);
    assert(size == r);
#endif
  }
};

class Clock
{
  friend class Range;

  uint64_t t = 0;
  uint64_t wall_t = 0;

public:
  class Range;

  uint64_t get_wall() const {
    return wall_t;
  }
};

class Clock::Range {
  static uint64_t now_thread_usec() {
    struct timespec x;
    ::clock_gettime(CLOCK_THREAD_CPUTIME_ID, &x);
    return x.tv_sec * 1000000000L + x.tv_nsec;
  }

  static uint64_t now_wall_usec()
  {
    struct timespec x;
    ::clock_gettime(CLOCK_MONOTONIC_RAW, &x);
    return x.tv_sec * 1000000000L + x.tv_nsec;
  }

public:
  Clock* const p;

  Range(Clock* p) : p(p) {
    p->t -= now_thread_usec();
    p->wall_t -= now_wall_usec();
  }

  ~Range() {
    {
      uint64_t m1 = now_thread_usec();
      uint64_t m2 = now_thread_usec();
      p->t += m1 - (m2 - m1);
    }
    {
      uint64_t m1 = now_wall_usec();
      uint64_t m2 = now_wall_usec();
      p->wall_t += m1 - (m2 - m1);
    }
  }
};

class Feeder {
  Clock feeding_clk;

  virtual size_t write(int fd, void* buf, size_t len) = 0;

public:
  virtual ~Feeder() = default;
  virtual size_t write(Sink& sink, void* const buf, const size_t len) final {
    Clock::Range range(&feeding_clk);
    return write(sink.get_fd(), buf, len);
  }

  virtual uint64_t get_feeding_time() const {
    return feeding_clk.get_wall();
  };

  virtual const char* get_name() const = 0;
};

class WriteFeeder : public Feeder {
public:
  size_t write(const int fd, void* const buf, const size_t size) override {
    return ::write(fd, buf, size);
  }

  const char* get_name() const override {
    return "write";
  }
};

class WriteVFeeder : public Feeder  {
public:
  size_t write(const int fd, void* const buf, const size_t size) override {
    struct iovec vec = {
      .iov_base = buf,
      .iov_len  = size,
    };

    return ::writev(fd, &vec, 1);
  }

  const char* get_name() const override {
    return "writev";
  }
};

class VMSpliceFeeder : public Feeder {
protected:
  int fds[2];

  size_t do_vmsplice(const int fd,
                     void* const buf,
                     const size_t size,
                     const unsigned int flags) {
    const struct iovec vec = {
      .iov_base = buf,
      .iov_len  = size
    };

    int r = ::vmsplice(fds[1], &vec, 1, flags | SPLICE_F_MOVE);// | SPLICE_F_MORE);
    assert(size == r);

    r = ::splice(fds[0], nullptr, fd, nullptr, size,
                 SPLICE_F_MOVE);// | SPLICE_F_MORE);
    assert(size == r);
    return r;
  }

  size_t write(const int fd, void* const buf, const size_t size) override {
    return do_vmsplice(fd, buf, size, 0);
  }

public:
  VMSpliceFeeder(const size_t max_size) {
    int r = ::pipe(fds);
    assert(r == 0);

    r = ::fcntl(fds[1], F_SETPIPE_SZ, max_size);
    assert(r >= max_size);
  }

  ~VMSpliceFeeder() override {
    ::close(fds[0]);
    ::close(fds[1]);
  }

  const char* get_name() const override {
    return "vmsplice_0";
  }
};

class GiftingVMSpliceFeeder : public VMSpliceFeeder {
  size_t write(const int fd, void* const buf, const size_t size) override {
    return do_vmsplice(fd, buf, size, SPLICE_F_GIFT);
  }

public:
  using VMSpliceFeeder::VMSpliceFeeder;

  const char* get_name() const override {
    return "vmsplice_gift";
  }
};

int main(int argc, char** argv)
{
  uint64_t chunk_size = 1024;
  int progression = 0;

  printf(       "               "
                " ----total-for-all-executed-jobs----"
                " ------per-single-executed-job-----\n");
  printf("%10s %14s %10s %8s %14s %14s\n",
         "sink", // 10
         "feeder", // 14
         "chunk size", // 8
         "iters", // 9
         "transfered", // 14
         "iter time");
  printf(
         "                            (bytes)"
         "            (MiB)          (MiB/s)     (usec)\n");

  static constexpr size_t mem_mul = 10;
  do /* chunk size */ {
    void *mem = aligned_alloc(4096, chunk_size * mem_mul + 4096);
    assert(mem != nullptr);

    /* Sinks. */
    PipeSink pipe_sink(chunk_size);
    SockSink sock_sink(chunk_size);
    FileSink file_sink;
    std::initializer_list<Sink*> sinks = {
      &pipe_sink, &sock_sink, &file_sink,
    };

    /* Feeders. */
    WriteFeeder write_fed;
    WriteVFeeder writev_fed;
    VMSpliceFeeder vmsplice0_fed(chunk_size);
    GiftingVMSpliceFeeder vmsplice_gift_fed(chunk_size);

    std::initializer_list<Feeder*> feeders = {
      &write_fed, &writev_fed, &vmsplice0_fed, &vmsplice_gift_fed
    };

    for (auto sink : sinks) {
      for (auto feeder : feeders) {
        const uint64_t start = now_usec();
        uint64_t no_tests = 0, end = 0;

        do /* time */ {
          void *wrk_mem = static_cast<char*>(mem)
                        + chunk_size * (no_tests % mem_mul);
          size_t written = feeder->write(*sink, wrk_mem, chunk_size);
          assert(chunk_size == written);

          sink->clean(chunk_size);

          no_tests++;
          end = now_usec();
        } while (end - start < 1 * 1000 * 1000);

        const double total_bytes = static_cast<double>(chunk_size) * no_tests;
        const double total_mbytes = total_bytes / (1024 * 1024);

        const double total_secs = static_cast<double>(feeder->get_feeding_time())
                                / (1000.0 * 1000.0 * 1000.0);
        printf("%10s %14s %10lu %8lu %9.2lf %14.2lf %14.3lf\n",
               sink->get_name(),
               feeder->get_name(),
               chunk_size,
               no_tests,
               total_mbytes,
               total_mbytes / total_secs,
               (double)(feeder->get_feeding_time())/no_tests);
      }
    }

    free(mem);

    printf("-------\n");

#if 0
    const double next[4] = { 5./4, 6./5, 7./6, 8./7 };
    chunk_size = chunk_size * next[progression];
    progression = (progression + 1) % 4 ;
#else
    chunk_size *= 2;
#endif
  } while(chunk_size < 100000000000);
}
<|endoftext|>


<commit_before>#include <Eigen/Core>       // Cholesky decomposition + solving
#include <Eigen/Cholesky>   // of system of linear equations.

#include "nao_igm.h"
#include "maple_functions.h"
#include "joint_bounds.h"

/**
 * @brief Check that all joint angles lie within bounds.
 *
 * @return -1 if all values are corrent, id of the first joint violating the
 * bounds.
 *
 * @attention No collision checks!
 */
int nao_igm::checkJointBounds()
{
    return(joint_bounds.check(state.q));
}

/**
 * @brief Set feet postures.
 *
 * @param[in] left_foot_position 3x1 vector of coordinates + yaw angle.
 * @param[in] right_foot_position 3x1 vector of coordinates + yaw angle.
 *
 * @note Roll and pitch angles are assumed to be 0.
 */
void nao_igm::setFeetPostures (
        const double *left_foot_position,
        const double *right_foot_position)
{
    if (state.support_foot == IGM_SUPPORT_LEFT)
    {
        setSupportPosture (left_foot_position, 0.0, 0.0, left_foot_position[3]);
        swing_foot_posture.init (right_foot_position, 0.0, 0.0, right_foot_position[3]);
    }
    else
    {
        setSupportPosture (right_foot_position, 0.0, 0.0, right_foot_position[3]);
        swing_foot_posture.init (left_foot_position, 0.0, 0.0, left_foot_position[3]);
    }
}

/**
 * @brief Set support foot posture.
 *
 * @param[in] support_foot_position 3x1 vector of coordinates
 * @param[in] roll angle
 * @param[in] pitch angle
 * @param[in] yaw angle
 */
void nao_igm::setSupportPosture (
        const double *support_foot_position,
        const double roll,
        const double pitch,
        const double yaw)
{
    state.q[SUPPORT_FOOT_POS_START]     = support_foot_position[0];
    state.q[SUPPORT_FOOT_POS_START + 1] = support_foot_position[1];
    state.q[SUPPORT_FOOT_POS_START + 2] = support_foot_position[2];
    rpy2R (roll, pitch, yaw, &state.q[SUPPORT_FOOT_ORIENTATION_START]);

    for (int i = SUPPORT_FOOT_POS_START; i < STATE_VAR_NUM; i++)
    {
        state_sensor.q[i] = state.q[i];
    }
}

/**
 * @brief Set coordinates of center of mass.
 *
 * @param[in] x coordinate
 * @param[in] y coordinate
 * @param[in] z coordinate
 */
void nao_igm::setCoM (const double x, const double y, const double z)
{
    CoM_position[0] = x;
    CoM_position[1] = y;
    CoM_position[2] = z;
}

/** @brief Initialize model.

    @param[in] support_foot_ current support foot.
    @param[in] x x-position
    @param[in] y y-position
    @param[in] z z-position
    @param[in] roll x-rotation
    @param[in] pitch y-rotation
    @param[in] yaw z-rotation
*/
void nao_igm::init(
        const igmSupportFoot support_foot_,
        const double x,
        const double y,
        const double z,
        const double roll,
        const double pitch,
        const double yaw)
{
    state.q[SUPPORT_FOOT_POS_START]     = x;
    state.q[SUPPORT_FOOT_POS_START + 1] = y;
    state.q[SUPPORT_FOOT_POS_START + 2] = z;
    rpy2R (roll, pitch, yaw, &state.q[SUPPORT_FOOT_ORIENTATION_START]);

    for (int i = 0; i < STATE_VAR_NUM; i++)
    {
        state_sensor.q[i] = state.q[i];
    }
    state.support_foot = state_sensor.support_foot = support_foot_;

    posture torso_posture;
    if (state.support_foot == IGM_SUPPORT_LEFT)
    {
        LLeg2RLeg(state.q, swing_foot_posture.data);
        LLeg2Torso(state.q, torso_posture.data);
        LLeg2CoM(state.q, CoM_position);
    }
    else
    {
        RLeg2LLeg(state.q, swing_foot_posture.data);
        RLeg2Torso(state.q, torso_posture.data);
        RLeg2CoM(state.q, CoM_position);
    }
    torso_posture.getOrientation(torso_orientation);
}

/**
 * @brief Switch support foot.
 *
 * @param[in] position_error 3x1 position error vector
 *
 * @attention The error along z axis is ignored.
 */
void nao_igm::switchSupportFoot(double *position_error)
{
    posture swing_foot_posture_sensor;
    state_sensor.getSwingFootPosture (swing_foot_posture_sensor.data);
    swing_foot_posture.getPositionDiff (swing_foot_posture_sensor, position_error);

    swing_foot_posture_sensor.getPosition (&state.q[SUPPORT_FOOT_POS_START]);
    // reset z position
    state.q[SUPPORT_FOOT_POS_START + 2] = 0.0;
    swing_foot_posture_sensor.getOrientation (&state.q[SUPPORT_FOOT_ORIENTATION_START]);

    if (state.support_foot == IGM_SUPPORT_LEFT)
    {
        state.support_foot = state_sensor.support_foot = IGM_SUPPORT_RIGHT;
    }
    else
    {
        state.support_foot = state_sensor.support_foot = IGM_SUPPORT_LEFT;
    }
    for (int i = SUPPORT_FOOT_POS_START; i < STATE_VAR_NUM; i++)
    {
        state_sensor.q[i] = state.q[i];
    }
}

/** \brief Solves the Inverse Geometric Problem (IGM). Constraints for (x, y, z, X(alpha), Y(beta),
    Z(gamma)) of the foot not in support as well as (x, y, z) position of the CoM, and X(alpha),
    Y(beta) rotation of the torso can be imposed.

    \return int iter - the number of iterations performed until convergence, or -1 if the algorithm
    did not converge within max_iter number of iterations.

    \note It is assumed that the leading matrix of the constraints is nonsingular.

    @note On input, the entries of q are the joint angles from where to start the
    search for a solution (i.e., the initial guess). On output q contains a solution of the
    inverse kinematics problem (if iter != -1). Only q[0]...q[11] are altered.
*/
int nao_igm::igm()
{
    const int N = LOWER_JOINTS_NUM;

    double out[N*N+N];
    Eigen::VectorXd dq(N);
    Eigen::LLT<Eigen::MatrixXd> llt;

    double tol = 0.0005;
    int max_iter = 20;
    int iter = 0;
    double norm_dq = 1.0;

    while (norm_dq > tol && iter != -1)
    {
        // Form data
        if (state.support_foot == IGM_SUPPORT_LEFT)
            from_LLeg_3(state.q, swing_foot_posture.data, CoM_position, torso_orientation, out);
        else
            from_RLeg_3(state.q, swing_foot_posture.data, CoM_position, torso_orientation, out);

        Eigen::Map<Eigen::MatrixXd> A(out,N,N);
        Eigen::Map<Eigen::VectorXd> err(out+N*N,N);

        // Solve KKT system
        llt.compute(A*A.transpose());
        llt.solve(-err, &dq);
        dq = -A.transpose()*dq;

        // Update angles (of legs)
        for (int i=0; i<LOWER_JOINTS_NUM; i++)
            state.q[i] += dq[i];

        // Check termination condition
        norm_dq = 0;
        for (int i=0; i<11; i++)
            norm_dq += dq[i]*dq[i];
        norm_dq = sqrt(norm_dq);

        iter++;
        if (iter > max_iter)
        {
            iter = -1;
        }
    }

    return(iter);
}
<commit_msg>Do not set error along z to 0.0 in switchSupportFoot() (leave it for WMG).<commit_after>#include <Eigen/Core>       // Cholesky decomposition + solving
#include <Eigen/Cholesky>   // of system of linear equations.

#include "nao_igm.h"
#include "maple_functions.h"
#include "joint_bounds.h"

/**
 * @brief Check that all joint angles lie within bounds.
 *
 * @return -1 if all values are corrent, id of the first joint violating the
 * bounds.
 *
 * @attention No collision checks!
 */
int nao_igm::checkJointBounds()
{
    return(joint_bounds.check(state.q));
}

/**
 * @brief Set feet postures.
 *
 * @param[in] left_foot_position 3x1 vector of coordinates + yaw angle.
 * @param[in] right_foot_position 3x1 vector of coordinates + yaw angle.
 *
 * @note Roll and pitch angles are assumed to be 0.
 */
void nao_igm::setFeetPostures (
        const double *left_foot_position,
        const double *right_foot_position)
{
    if (state.support_foot == IGM_SUPPORT_LEFT)
    {
        setSupportPosture (left_foot_position, 0.0, 0.0, left_foot_position[3]);
        swing_foot_posture.init (right_foot_position, 0.0, 0.0, right_foot_position[3]);
    }
    else
    {
        setSupportPosture (right_foot_position, 0.0, 0.0, right_foot_position[3]);
        swing_foot_posture.init (left_foot_position, 0.0, 0.0, left_foot_position[3]);
    }
}

/**
 * @brief Set support foot posture.
 *
 * @param[in] support_foot_position 3x1 vector of coordinates
 * @param[in] roll angle
 * @param[in] pitch angle
 * @param[in] yaw angle
 */
void nao_igm::setSupportPosture (
        const double *support_foot_position,
        const double roll,
        const double pitch,
        const double yaw)
{
    state.q[SUPPORT_FOOT_POS_START]     = support_foot_position[0];
    state.q[SUPPORT_FOOT_POS_START + 1] = support_foot_position[1];
    state.q[SUPPORT_FOOT_POS_START + 2] = support_foot_position[2];
    rpy2R (roll, pitch, yaw, &state.q[SUPPORT_FOOT_ORIENTATION_START]);

    for (int i = SUPPORT_FOOT_POS_START; i < STATE_VAR_NUM; i++)
    {
        state_sensor.q[i] = state.q[i];
    }
}

/**
 * @brief Set coordinates of center of mass.
 *
 * @param[in] x coordinate
 * @param[in] y coordinate
 * @param[in] z coordinate
 */
void nao_igm::setCoM (const double x, const double y, const double z)
{
    CoM_position[0] = x;
    CoM_position[1] = y;
    CoM_position[2] = z;
}

/** @brief Initialize model.

    @param[in] support_foot_ current support foot.
    @param[in] x x-position
    @param[in] y y-position
    @param[in] z z-position
    @param[in] roll x-rotation
    @param[in] pitch y-rotation
    @param[in] yaw z-rotation
*/
void nao_igm::init(
        const igmSupportFoot support_foot_,
        const double x,
        const double y,
        const double z,
        const double roll,
        const double pitch,
        const double yaw)
{
    state.q[SUPPORT_FOOT_POS_START]     = x;
    state.q[SUPPORT_FOOT_POS_START + 1] = y;
    state.q[SUPPORT_FOOT_POS_START + 2] = z;
    rpy2R (roll, pitch, yaw, &state.q[SUPPORT_FOOT_ORIENTATION_START]);

    for (int i = 0; i < STATE_VAR_NUM; i++)
    {
        state_sensor.q[i] = state.q[i];
    }
    state.support_foot = state_sensor.support_foot = support_foot_;

    posture torso_posture;
    if (state.support_foot == IGM_SUPPORT_LEFT)
    {
        LLeg2RLeg(state.q, swing_foot_posture.data);
        LLeg2Torso(state.q, torso_posture.data);
        LLeg2CoM(state.q, CoM_position);
    }
    else
    {
        RLeg2LLeg(state.q, swing_foot_posture.data);
        RLeg2Torso(state.q, torso_posture.data);
        RLeg2CoM(state.q, CoM_position);
    }
    torso_posture.getOrientation(torso_orientation);
}

/**
 * @brief Switch support foot.
 *
 * @param[in] position_error 3x1 position error vector
 */
void nao_igm::switchSupportFoot(double *position_error)
{
    posture swing_foot_posture_sensor;
    state_sensor.getSwingFootPosture (swing_foot_posture_sensor.data);
    swing_foot_posture.getPositionDiff (swing_foot_posture_sensor, position_error);

    swing_foot_posture_sensor.getPosition (&state.q[SUPPORT_FOOT_POS_START]);
    swing_foot_posture_sensor.getOrientation (&state.q[SUPPORT_FOOT_ORIENTATION_START]);

    if (state.support_foot == IGM_SUPPORT_LEFT)
    {
        state.support_foot = state_sensor.support_foot = IGM_SUPPORT_RIGHT;
    }
    else
    {
        state.support_foot = state_sensor.support_foot = IGM_SUPPORT_LEFT;
    }
    for (int i = SUPPORT_FOOT_POS_START; i < STATE_VAR_NUM; i++)
    {
        state_sensor.q[i] = state.q[i];
    }
}

/** \brief Solves the Inverse Geometric Problem (IGM). Constraints for (x, y, z, X(alpha), Y(beta),
    Z(gamma)) of the foot not in support as well as (x, y, z) position of the CoM, and X(alpha),
    Y(beta) rotation of the torso can be imposed.

    \return int iter - the number of iterations performed until convergence, or -1 if the algorithm
    did not converge within max_iter number of iterations.

    \note It is assumed that the leading matrix of the constraints is nonsingular.

    @note On input, the entries of q are the joint angles from where to start the
    search for a solution (i.e., the initial guess). On output q contains a solution of the
    inverse kinematics problem (if iter != -1). Only q[0]...q[11] are altered.
*/
int nao_igm::igm()
{
    const int N = LOWER_JOINTS_NUM;

    double out[N*N+N];
    Eigen::VectorXd dq(N);
    Eigen::LLT<Eigen::MatrixXd> llt;

    double tol = 0.0005;
    int max_iter = 20;
    int iter = 0;
    double norm_dq = 1.0;

    while (norm_dq > tol && iter != -1)
    {
        // Form data
        if (state.support_foot == IGM_SUPPORT_LEFT)
            from_LLeg_3(state.q, swing_foot_posture.data, CoM_position, torso_orientation, out);
        else
            from_RLeg_3(state.q, swing_foot_posture.data, CoM_position, torso_orientation, out);

        Eigen::Map<Eigen::MatrixXd> A(out,N,N);
        Eigen::Map<Eigen::VectorXd> err(out+N*N,N);

        // Solve KKT system
        llt.compute(A*A.transpose());
        llt.solve(-err, &dq);
        dq = -A.transpose()*dq;

        // Update angles (of legs)
        for (int i=0; i<LOWER_JOINTS_NUM; i++)
            state.q[i] += dq[i];

        // Check termination condition
        norm_dq = 0;
        for (int i=0; i<11; i++)
            norm_dq += dq[i]*dq[i];
        norm_dq = sqrt(norm_dq);

        iter++;
        if (iter > max_iter)
        {
            iter = -1;
        }
    }

    return(iter);
}
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <vector>

using namespace std;

//util classes
struct Input {
	int r, c, l, h;
	vector<vector<bool>> tomatoes;
};

struct Slice {
	int r1, c1, r2, c2;
};

struct Output {
	vector<Slice> slices;
};

bool checkSliceHorizontal(Input &input, Slice &s)
{
	int t = 0;
	int f = 0;
	for (int j = s.c1; j <= s.c2; j++)
	{
		if (input.tomatoes[s.r1][j])
			t++;
		else
			f++;
	}

	return (t >= input.l && f >= input.l);
}

bool checkSliceVertical(Input &input, Slice &s)
{
	int t = 0;
	int f = 0;
	for (int i = s.r1; i <= s.r2; i++)
	{
		if (input.tomatoes[i][s.c1])
			t++;
		else
			f++;
	}

	return (t >= input.l && f >= input.l);
}

void solveSimpleHorizontal(Input& input, Output& output) {
	for (int i = 0; i < input.r; i++)
	{
		for (int j = 0; j < input.c; j += input.h)
		{
			Slice s;
			s.r1 = i;
			s.c1 = j;
			s.r2 = i;
			s.c2 = min(j+input.h-1, input.c-1);
			if (checkSliceHorizontal(input, s))
				output.slices.push_back(s);
		}
	}
}

void solveSimpleVertical(Input& input, Output& output) {
	for (int j = 0; j < input.c; j++)
	{
		for (int i = 0; i < input.r; i += input.h)
		{
			Slice s;
			s.r1 = i;
			s.c1 = j;
			s.r2 = min(i+input.h-1, input.r-1);
			s.c2 = j;
			if (checkSliceVertical(input, s))
				output.slices.push_back(s);
		}
	}
}

int add_slice(const vector<bool> &a, int l, int r, int cnt_min, int h)	{
	int cnt1 = 0, cnt2 = 0;
	for (int i = l; i <= r; i++)
		if (a[i])
			cnt1++;
		else
			cnt2++;

	if (cnt1 >= cnt_min && cnt2 >= cnt_min && r-l+1 <= h)
		return r-l+1;
	return 0;
}

bool check_slice(const vector<bool> &a, int l, int r, int cnt_min, int h)	{
	int cnt1 = 0, cnt2 = 0;
	for (int i = l; i <= r; i++)
		if (a[i])
			cnt1++;
		else
			cnt2++;

	return (cnt1 >= cnt_min && cnt2 >= cnt_min && r-l+1 <= h);
}

void solve_row(const vector<bool> &a, int row_num, int n, int l, int h, vector<Slice> &ans)	{
	vector<int> d(n,0), prev(n,0);

	//cerr << row_num << endl;

	for (int i = 0; i < n; i++)
		for (int j = max(0,i-40); j < i; j++)
		{
			int temp = add_slice(a,j,i,l,h);
			int prev_res = (j >= 0 ? d[j-1] : 0);
			if (d[i] < prev_res + temp)
			{
					d[i] = prev_res + temp;
					prev[i] = j;
			}
		}

	/*if (row_num == 14)
	{
		for (int i = 0; i < 60; i++)
			cerr << i << ' ' << d[i] << ' ' << prev[i] << endl;;
		cerr << endl;
	}*/

	int i_max = 0;
	for (int i = 0; i < n; i++)
		if (d[i] > d[i_max])
			i_max = i;

	Slice c;
	c.r1 = c.r2 = row_num;

	for (int i = i_max; i > 0;)
	{
		c.c1 = prev[i]; c.c2 = i;
		i = prev[i]-1;

		if (check_slice(a,c.c1,c.c2,l,h))
			ans.push_back(c);
	}
}

void solveDP(Input& input, Output& output) {

	for (int i = 0; i < input.r; i++)
		solve_row(input.tomatoes[i],i,input.c,input.l,input.h,output.slices);
}

//input/output code
int main(int argc, char* argv[]) {
	ios::sync_with_stdio(false);

	//read input
	Input input;
	cin >> input.r >> input.c >> input.l >> input.h;
	for(int i = 0; i < input.r; i++) {
		vector<bool> row(input.c);
		for(int j = 0; j < input.c; j++) {
			char cell;
			cin >> cell;
			row[j] = cell == 'T';
		}
		input.tomatoes.push_back(row);
		//TODO do we read line breaks?
	}

	//read command line args
	string algorithm = "simplehorizontal";
	if(argc > 1) {
		algorithm = argv[1];
	}

	//solve problem
	Output output;
	cerr << "using algorithm " << algorithm << endl;
	if(algorithm == "simplehorizontal") {
		solveSimpleHorizontal(input, output);
	}
	else if(algorithm == "simplevertical") {
		solveSimpleVertical(input, output);
	}
	else if(algorithm == "dp") {
		solveDP(input, output);
	}
	else {
		cerr << "unknown algorithm" << endl;
		return 1;
	}

	//print output
	cout << output.slices.size() << endl;
	int area = 0;
	for(Slice slice: output.slices) {
		area += (slice.r2 - slice.r1 + 1) * (slice.c2 - slice.c1 + 1);
		cout << slice.r1 << ' ' << slice.c1 << ' ' << slice.r2 << ' ' << slice.c2 << endl;
	}
	cerr << "cells used: " << area << endl;
};
<commit_msg>i transpose function added<commit_after>#include <iostream>
#include <string>
#include <vector>

using namespace std;

//util classes
struct Input {
	int r, c, l, h;
	vector<vector<bool>> tomatoes;
};

struct Slice {
	int r1, c1, r2, c2;
};

struct Output {
	vector<Slice> slices;
};

bool checkSlice(Input &input, Slice &s)
{
	int t = 0;
	int f = 0;
	for (int j = s.c1; j <= s.c2; j++)
	{
		if (input.tomatoes[s.r1][j])
			t++;
		else
			f++;
	}

	return (t >= input.l && f >= input.l);
}

void solveSimple(Input& input, Output& output) {
	for (int i = 0; i < input.r; i++)
	{
		for (int j = 0; j < input.c; j += input.h)
		{
			Slice s;
			s.r1 = i;
			s.c1 = j;
			s.r2 = i;
			s.c2 = min(j+input.h-1, input.c-1);
			if (checkSlice(input, s))
				output.slices.push_back(s);
		}
	}
}

int add_slice(const vector<bool> &a, int l, int r, int cnt_min, int h)	{
	int cnt1 = 0, cnt2 = 0;
	for (int i = l; i <= r; i++)
		if (a[i])
			cnt1++;
		else
			cnt2++;

	if (cnt1 >= cnt_min && cnt2 >= cnt_min && r-l+1 <= h)
		return r-l+1;
	return 0;
}

bool check_slice(const vector<bool> &a, int l, int r, int cnt_min, int h)	{
	int cnt1 = 0, cnt2 = 0;
	for (int i = l; i <= r; i++)
		if (a[i])
			cnt1++;
		else
			cnt2++;

	return (cnt1 >= cnt_min && cnt2 >= cnt_min && r-l+1 <= h);
}

void solve_row(const vector<bool> &a, int row_num, int n, int l, int h, vector<Slice> &ans)	{
	vector<int> d(n,0), prev(n,0);

	//cerr << row_num << endl;

	for (int i = 0; i < n; i++)
		for (int j = max(0,i-40); j < i; j++)
		{
			int temp = add_slice(a,j,i,l,h);
			int prev_res = (j >= 0 ? d[j-1] : 0);
			if (d[i] < prev_res + temp)
			{
					d[i] = prev_res + temp;
					prev[i] = j;
			}
		}

	/*if (row_num == 14)
	{
		for (int i = 0; i < 60; i++)
			cerr << i << ' ' << d[i] << ' ' << prev[i] << endl;;
		cerr << endl;
	}*/

	int i_max = 0;
	for (int i = 0; i < n; i++)
		if (d[i] > d[i_max])
			i_max = i;

	Slice c;
	c.r1 = c.r2 = row_num;

	for (int i = i_max; i > 0;)
	{
		c.c1 = prev[i]; c.c2 = i;
		i = prev[i]-1;

		if (check_slice(a,c.c1,c.c2,l,h))
			ans.push_back(c);
	}
}

void solveDP(Input& input, Output& output) {

	for (int i = 0; i < input.r; i++)
		solve_row(input.tomatoes[i],i,input.c,input.l,input.h,output.slices);
}

void transpose_input(Input &input)	{

	int temp_tomatoes[1010][1010];

	for (int i = 0; i < input.r; i++)
	{
		for (int j = 0; j < input.c; j++)
			temp_tomatoes[j][i] = input.tomatoes[i][j];
		input.tomatoes[i].clear();
	}
	input.tomatoes.resize(input.c);
	swap(input.r, input.c);
	for (int i = 0; i < input.r; i++)
		for (int j = 0; j < input.c; j++)
			input.tomatoes[i].push_back(temp_tomatoes[i][j]);
}

void transpose_output(Output &output)	{
	for (int i = 0; i < output.slices.size(); i++)
	{
		swap(output.slices[i].r1,output.slices[i].c1);
		swap(output.slices[i].r2,output.slices[i].c2);
	}
}

//input/output code
int main(int argc, char* argv[]) {
	ios::sync_with_stdio(false);

	//read input
	Input input;
	cin >> input.r >> input.c >> input.l >> input.h;
	for(int i = 0; i < input.r; i++) {
		vector<bool> row(input.c);
		for(int j = 0; j < input.c; j++) {
			char cell;
			cin >> cell;
			row[j] = cell == 'T';
		}
		input.tomatoes.push_back(row);
		//TODO do we read line breaks?
	}

	//read command line args
	string algorithm = "simplehorizontal";
	if(argc > 1) {
		algorithm = argv[1];
	}

	//solve problem
	Output output;
	cerr << "using algorithm " << algorithm << endl;
	if(algorithm == "simplehorizontal") {
		solveSimple(input, output);
	}
	else if(algorithm == "simplevertical") {
		transpose_input(input);
		solveSimple(input, output);
		transpose_output(output);
	}
	else if(algorithm == "dp") {
		solveDP(input, output);
	}
	else if(algorithm == "dptranspose")	{
		transpose_input(input);
		solveDP(input,output);
		transpose_output(output);
	}
	else {
		cerr << "unknown algorithm" << endl;
		return 1;
	}

	//print output
	cout << output.slices.size() << endl;
	int area = 0;
	for(Slice slice: output.slices) {
		area += (slice.r2 - slice.r1 + 1) * (slice.c2 - slice.c1 + 1);
		cout << slice.r1 << ' ' << slice.c1 << ' ' << slice.r2 << ' ' << slice.c2 << endl;
	}
	cerr << "cells used: " << area << endl;
};
<|endoftext|>


<commit_before><commit_msg>Fixed a bug associated with the changes in the format of info file.<commit_after><|endoftext|>


<commit_before>// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/eval/eval/simple_value.h>
#include <vespa/eval/eval/fast_value.h>
#include <vespa/eval/eval/value_codec.h>
#include <vespa/eval/instruction/generic_create.h>
#include <vespa/eval/eval/interpreted_function.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/gtest/gtest.h>
#include <stdlib.h>
#include <algorithm>

using namespace vespalib;
using namespace vespalib::eval;
using namespace vespalib::eval::instruction;
using namespace vespalib::eval::test;

using vespalib::make_string_short::fmt;

std::vector<Layout> create_layouts = {
    {x(3)},
    {x(3),y(2)},
    float_cells({x(3)}),
    {x({"a","b","c"})},
    {x({"a","b","c"}),y({"foo","bar"})},
    float_cells({x({"a","b","c"})}),
    {x(3),y({"foo", "bar"})}
};

TensorSpec remove_each(const TensorSpec &a, size_t n) {
    TensorSpec b(a.type());
    for (const auto & kv : a.cells()) {
        size_t v = kv.second;
        if ((v % n) != 0) {
            b.add(kv.first, kv.second);
        }
    }
    return b;
}

struct NumberedCellSpec {
    long int num;
    TensorSpec::Address addr;
    double value;
};

bool operator< (const NumberedCellSpec &a, const NumberedCellSpec &b) {
    return a.num < b.num;
}

TensorSpec perform_generic_create(const TensorSpec &a, const ValueBuilderFactory &factory)
{
    ValueType res_type = ValueType::from_spec(a.type());
    EXPECT_FALSE(res_type.is_error());
    Stash stash;
    std::vector<NumberedCellSpec> scramble;
    for (const auto & kv : a.cells()) {
        NumberedCellSpec cell{random(), kv.first, kv.second};
        scramble.push_back(cell);
    }
    std::sort(scramble.begin(), scramble.end());
    std::vector<Value::CREF> my_stack;
    std::map<TensorSpec::Address,size_t> create_spec;
    for (size_t child_idx = 0; child_idx < scramble.size(); ++child_idx) {
        auto cell = scramble[child_idx];
        create_spec.emplace(cell.addr, child_idx);
        my_stack.push_back(stash.create<DoubleValue>(cell.value));
    }
    auto my_op = GenericCreate::make_instruction(res_type, create_spec, factory, stash);
    InterpretedFunction::EvalSingle single(factory, my_op);
    return spec_from_value(single.eval(my_stack));
}

void test_generic_create_with(const ValueBuilderFactory &factory) {
    for (const auto & layout : create_layouts) {
        TensorSpec full = spec(layout, N());
        auto actual = perform_generic_create(full, factory);
        EXPECT_EQ(actual, full);
        for (size_t n : {2, 3, 4, 5}) {
            TensorSpec partial = remove_each(full, n);
            actual = perform_generic_create(partial, factory);
            auto filled = spec_from_value(*value_from_spec(partial, factory));
            EXPECT_EQ(actual, filled);
        }
    }
}

TEST(GenericCreateTest, generic_create_works_for_simple_values) {
    test_generic_create_with(SimpleValueBuilderFactory::get());
}

TEST(GenericCreateTest, generic_create_works_for_fast_values) {
    test_generic_create_with(FastValueBuilderFactory::get());
}

GTEST_MAIN_RUN_ALL_TESTS()
<commit_msg>just do all the layouts from map test<commit_after>// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/eval/eval/simple_value.h>
#include <vespa/eval/eval/fast_value.h>
#include <vespa/eval/eval/value_codec.h>
#include <vespa/eval/instruction/generic_create.h>
#include <vespa/eval/eval/interpreted_function.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/gtest/gtest.h>
#include <stdlib.h>
#include <algorithm>

using namespace vespalib;
using namespace vespalib::eval;
using namespace vespalib::eval::instruction;
using namespace vespalib::eval::test;

using vespalib::make_string_short::fmt;

std::vector<Layout> create_layouts = {
    {x(3)},
    {x(3),y(5)},
    {x(3),y(5),z(7)},
    float_cells({x(3),y(5),z(7)}),
    {x({"a","b","c"})},
    {x({"a","b","c"}),y({"foo","bar"})},
    {x({"a","b","c"}),y({"foo","bar"}),z({"i","j","k","l"})},
    float_cells({x({"a","b","c"}),y({"foo","bar"}),z({"i","j","k","l"})}),
    {x(3),y({"foo", "bar"}),z(7)},
    {x({"a","b","c"}),y(5),z({"i","j","k","l"})},
    float_cells({x({"a","b","c"}),y(5),z({"i","j","k","l"})})
};

TensorSpec remove_each(const TensorSpec &a, size_t n) {
    TensorSpec b(a.type());
    for (const auto & kv : a.cells()) {
        size_t v = kv.second;
        if ((v % n) != 0) {
            b.add(kv.first, kv.second);
        }
    }
    return b;
}

struct NumberedCellSpec {
    long int num;
    TensorSpec::Address addr;
    double value;
};

bool operator< (const NumberedCellSpec &a, const NumberedCellSpec &b) {
    return a.num < b.num;
}

TensorSpec perform_generic_create(const TensorSpec &a, const ValueBuilderFactory &factory)
{
    ValueType res_type = ValueType::from_spec(a.type());
    EXPECT_FALSE(res_type.is_error());
    Stash stash;
    std::vector<NumberedCellSpec> scramble;
    for (const auto & kv : a.cells()) {
        NumberedCellSpec cell{random(), kv.first, kv.second};
        scramble.push_back(cell);
    }
    std::sort(scramble.begin(), scramble.end());
    std::vector<Value::CREF> my_stack;
    std::map<TensorSpec::Address,size_t> create_spec;
    for (size_t child_idx = 0; child_idx < scramble.size(); ++child_idx) {
        auto cell = scramble[child_idx];
        create_spec.emplace(cell.addr, child_idx);
        my_stack.push_back(stash.create<DoubleValue>(cell.value));
    }
    auto my_op = GenericCreate::make_instruction(res_type, create_spec, factory, stash);
    InterpretedFunction::EvalSingle single(factory, my_op);
    return spec_from_value(single.eval(my_stack));
}

void test_generic_create_with(const ValueBuilderFactory &factory) {
    for (const auto & layout : create_layouts) {
        TensorSpec full = spec(layout, N());
        auto actual = perform_generic_create(full, factory);
        EXPECT_EQ(actual, full);
        for (size_t n : {2, 3, 4, 5}) {
            TensorSpec partial = remove_each(full, n);
            actual = perform_generic_create(partial, factory);
            auto filled = spec_from_value(*value_from_spec(partial, factory));
            EXPECT_EQ(actual, filled);
        }
    }
}

TEST(GenericCreateTest, generic_create_works_for_simple_values) {
    test_generic_create_with(SimpleValueBuilderFactory::get());
}

TEST(GenericCreateTest, generic_create_works_for_fast_values) {
    test_generic_create_with(FastValueBuilderFactory::get());
}

GTEST_MAIN_RUN_ALL_TESTS()
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you 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 .
 */
#ifndef INCLUDED_DBACCESS_SOURCE_UI_APP_APPSWAPWINDOW_HXX
#define INCLUDED_DBACCESS_SOURCE_UI_APP_APPSWAPWINDOW_HXX

#include "IClipBoardTest.hxx"
#include <vcl/lstbox.hxx>
#include "AppIconControl.hxx"
#include "AppElementType.hxx"

namespace dbaui
{
    class OAppBorderWindow;
    class OApplicationSwapWindow :  public Window,
                                    public IClipboardTest
    {
        OApplicationIconControl             m_aIconControl;
        ElementType                         m_eLastType;
        OAppBorderWindow&                   m_rBorderWin;

        void ImplInitSettings( sal_Bool bFont, sal_Bool bForeground, sal_Bool bBackground );

        DECL_LINK( OnContainerSelectHdl,    SvtIconChoiceCtrl* );
        DECL_LINK( ChangeToLastSelected, void* );
    protected:
        virtual void DataChanged(const DataChangedEvent& rDCEvt) SAL_OVERRIDE;
    public:
        OApplicationSwapWindow( Window* _pParent, OAppBorderWindow& _rBorderWindow );
        virtual ~OApplicationSwapWindow();
        // window overloads
        virtual void Resize() SAL_OVERRIDE;

        inline sal_Bool isCutAllowed() SAL_OVERRIDE      { return sal_False; }
        inline sal_Bool isCopyAllowed() SAL_OVERRIDE     { return sal_False; }
        inline sal_Bool isPasteAllowed() SAL_OVERRIDE    { return sal_False; }
        virtual sal_Bool hasChildPathFocus() SAL_OVERRIDE { return HasChildPathFocus(); }
        inline void copy() SAL_OVERRIDE  { }
        inline void cut() SAL_OVERRIDE   { }
        inline void paste() SAL_OVERRIDE { }

        inline sal_uLong                    GetEntryCount() const { return m_aIconControl.GetEntryCount(); }
        inline SvxIconChoiceCtrlEntry*  GetEntry( sal_uLong nPos ) const { return m_aIconControl.GetEntry(nPos); }
        inline Rectangle                GetBoundingBox( SvxIconChoiceCtrlEntry* pEntry ) const { return m_aIconControl.GetBoundingBox(pEntry); }

        /** automatically creates mnemonics for the icon/texts in our left hand side panel
        */
        void    createIconAutoMnemonics( MnemonicGenerator& _rMnemonics );

        /** called to give the window the chance to intercept key events, while it has not
            the focus

            @return <TRUE/> if and only if the event has been handled, and should not
                not be further processed
        */
        bool    interceptKeyInput( const KeyEvent& _rEvent );

        /// return the element of currently select entry
        ElementType getElementType() const;

        /** clears the selection in the icon choice control and calls the handler
        */
        void clearSelection();

        /** changes the container which should be displayed. The select handler will also be called.
            @param  _eType
                Which container to show.
        */
        void selectContainer(ElementType _eType);

    private:
        bool onContainerSelected( ElementType _eType );
    };
} // namespace dbaui
#endif // INCLUDED_DBACCESS_SOURCE_UI_APP_APPSWAPWINDOW_HXX

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>Work around MSC "'override' cannot be used with 'inline'" bug<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you 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 .
 */
#ifndef INCLUDED_DBACCESS_SOURCE_UI_APP_APPSWAPWINDOW_HXX
#define INCLUDED_DBACCESS_SOURCE_UI_APP_APPSWAPWINDOW_HXX

#include "IClipBoardTest.hxx"
#include <vcl/lstbox.hxx>
#include "AppIconControl.hxx"
#include "AppElementType.hxx"

namespace dbaui
{
    class OAppBorderWindow;
    class OApplicationSwapWindow :  public Window,
                                    public IClipboardTest
    {
        OApplicationIconControl             m_aIconControl;
        ElementType                         m_eLastType;
        OAppBorderWindow&                   m_rBorderWin;

        void ImplInitSettings( sal_Bool bFont, sal_Bool bForeground, sal_Bool bBackground );

        DECL_LINK( OnContainerSelectHdl,    SvtIconChoiceCtrl* );
        DECL_LINK( ChangeToLastSelected, void* );
    protected:
        virtual void DataChanged(const DataChangedEvent& rDCEvt) SAL_OVERRIDE;
    public:
        OApplicationSwapWindow( Window* _pParent, OAppBorderWindow& _rBorderWindow );
        virtual ~OApplicationSwapWindow();
        // window overloads
        virtual void Resize() SAL_OVERRIDE;

        sal_Bool isCutAllowed() SAL_OVERRIDE      { return sal_False; }
        sal_Bool isCopyAllowed() SAL_OVERRIDE     { return sal_False; }
        sal_Bool isPasteAllowed() SAL_OVERRIDE    { return sal_False; }
        virtual sal_Bool hasChildPathFocus() SAL_OVERRIDE { return HasChildPathFocus(); }
        void copy() SAL_OVERRIDE  { }
        void cut() SAL_OVERRIDE   { }
        void paste() SAL_OVERRIDE { }

        inline sal_uLong                    GetEntryCount() const { return m_aIconControl.GetEntryCount(); }
        inline SvxIconChoiceCtrlEntry*  GetEntry( sal_uLong nPos ) const { return m_aIconControl.GetEntry(nPos); }
        inline Rectangle                GetBoundingBox( SvxIconChoiceCtrlEntry* pEntry ) const { return m_aIconControl.GetBoundingBox(pEntry); }

        /** automatically creates mnemonics for the icon/texts in our left hand side panel
        */
        void    createIconAutoMnemonics( MnemonicGenerator& _rMnemonics );

        /** called to give the window the chance to intercept key events, while it has not
            the focus

            @return <TRUE/> if and only if the event has been handled, and should not
                not be further processed
        */
        bool    interceptKeyInput( const KeyEvent& _rEvent );

        /// return the element of currently select entry
        ElementType getElementType() const;

        /** clears the selection in the icon choice control and calls the handler
        */
        void clearSelection();

        /** changes the container which should be displayed. The select handler will also be called.
            @param  _eType
                Which container to show.
        */
        void selectContainer(ElementType _eType);

    private:
        bool onContainerSelected( ElementType _eType );
    };
} // namespace dbaui
#endif // INCLUDED_DBACCESS_SOURCE_UI_APP_APPSWAPWINDOW_HXX

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>/*****************************************************************************
 * input_manager.cpp : Manage an input and interact with its GUI elements
 ****************************************************************************
 * Copyright (C) 2006 the VideoLAN team
 * $Id$
 *
 * Authors: Clément Stenac <zorglub@videolan.org>
 *          Jean-Baptiste Kempf <jb@videolan.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "util/input_slider.hpp"

#include <QPaintEvent>
#include <QPainter>
#include <QBitmap>

InputSlider::InputSlider( QWidget *_parent ) : QSlider( _parent )
{
    InputSlider::InputSlider( Qt::Horizontal, _parent );
}

InputSlider::InputSlider( Qt::Orientation q, QWidget *_parent ) :
                                 QSlider( q, _parent )
{
    b_isSliding = false;
    lastSeeked  = 0;

    timer = new QTimer(this);
    timer->setSingleShot(true);

    /* Properties */
    setRange( 0, 1000 );
    setSingleStep( 2 );
    setPageStep( 10 );
    setMouseTracking(true);
    setTracking( true );
    setFocusPolicy( Qt::NoFocus );

    /* Init to 0 */
    setPosition( -1.0, 0, 0 );
    secstotimestr( psz_length, 0 );

    CONNECT( this, valueChanged(int), this, userDrag( int ) );
    CONNECT( timer, timeout(), this, seekTick() );
}

void InputSlider::setPosition( float pos, int a, int b )
{
    if( pos == -1.0 )
    {
        setEnabled( false );
        b_isSliding = false;
    }
    else
        setEnabled( true );

    if( !b_isSliding )
        setValue( (int)(pos * 1000.0 ) );

    inputLength = b;
}

void InputSlider::userDrag( int new_value )
{
    if( b_isSliding && !timer->isActive() )
        timer->start( 150 );
}

void InputSlider::seekTick()
{
    if( value() != lastSeeked )
    {
        lastSeeked = value();
        float f_pos = (float)(lastSeeked)/1000.0;
        emit sliderDragged( f_pos );
    }
}

void InputSlider::mouseReleaseEvent( QMouseEvent *event )
{
    b_isSliding = false;
    event->accept();
    QSlider::mouseReleaseEvent( event );
}

void InputSlider::mousePressEvent(QMouseEvent* event)
{
    b_isSliding = true ;
    if( event->button() != Qt::LeftButton &&
        event->button() != Qt::MidButton )
    {
        QSlider::mousePressEvent( event );
        return;
    }

    QMouseEvent newEvent( event->type(), event->pos(), event->globalPos(),
        Qt::MouseButton( event->button() ^ Qt::LeftButton ^ Qt::MidButton ),
        Qt::MouseButtons( event->buttons() ^ Qt::LeftButton ^ Qt::MidButton ),
        event->modifiers() );
    QSlider::mousePressEvent( &newEvent );

    seekTick();
}

void InputSlider::mouseMoveEvent(QMouseEvent *event)
{
    if( b_isSliding )
    {
        QSlider::mouseMoveEvent( event );
    }

    secstotimestr( psz_length, ( event->x() * inputLength) / size().width() );
    setToolTip( psz_length );
    event->accept();
}

void InputSlider::wheelEvent( QWheelEvent *event)
{
    /* Don't do anything if we are for somehow reason sliding */
    if( !b_isSliding )
    {
        setValue( value() + event->delta()/12 ); /* 12 = 8 * 15 / 10
         Since delta is in 1/8 of ° and mouse have steps of 15 °
         and that our slider is in 0.1% and we want one step to be a 1%
         increment of position */
        emit sliderDragged( value()/1000.0 );
    }
    /* We do accept because for we don't want the parent to change the sound
       vol */
    event->accept();
}

/* This work is derived from Amarok's work under GPLv2+
    - Mark Kretschmann
    - Gábor Lehel
   */
#define WLENGTH   80 // px
#define WHEIGHT   22  // px
#define SOUNDMIN  0   // %
#define SOUNDMAX  200 // % OR 400 ?

SoundSlider::SoundSlider( QWidget *_parent, int _i_step, bool b_hard,
                          char *psz_colors )
                        : QAbstractSlider( _parent )
{
    f_step = ( _i_step * 100 ) / AOUT_VOLUME_MAX ;
    setRange( SOUNDMIN, b_hard ? (2 * SOUNDMAX) : SOUNDMAX  );
    setMouseTracking( true );
    b_isSliding = false;
    b_mouseOutside = true;
    b_isMuted = false;

    pixOutside = QPixmap( ":/toolbar/volslide-outside" );

    const QPixmap temp( ":/toolbar/volslide-inside" );
    const QBitmap mask( temp.createHeuristicMask() );

    setMinimumSize( pixOutside.size() );

    pixGradient = QPixmap( mask.size() );
    pixGradient2 = QPixmap( mask.size() );

    /* Gradient building from the preferences */
    QLinearGradient gradient( paddingL, 2, WLENGTH + paddingL , 2 );
    QLinearGradient gradient2( paddingL, 2, WLENGTH + paddingL , 2 );

    QStringList colorList = qfu( psz_colors ).split( ";" );
    free( psz_colors );

    /* Fill with 255 if the list is too short */
    if( colorList.size() < 12 )
        for( int i = colorList.size(); i < 12; i++)
            colorList.append( "255" );

    /* Regular colors */
#define c(i) colorList.at(i).toInt()
#define add_color(gradient, range, c1, c2, c3) \
    gradient.setColorAt( range, QColor( c(c1), c(c2), c(c3) ) );

    /* Desaturated colors */
#define desaturate(c) c->setHsvF( c->hueF(), 0.2 , 0.5, 1.0 )
#define add_desaturated_color(gradient, range, c1, c2, c3) \
    foo = new QColor( c(c1), c(c2), c(c3) );\
    desaturate( foo ); gradient.setColorAt( range, *foo );\
    delete foo;

    /* combine the two helpers */
#define add_colors( gradient1, gradient2, range, c1, c2, c3 )\
    add_color( gradient1, range, c1, c2, c3 ); \
    add_desaturated_color( gradient2, range, c1, c2, c3 );

    QColor * foo;
    add_colors( gradient, gradient2, 0.0, 0, 1, 2 );
    add_colors( gradient, gradient2, 0.22, 3, 4, 5 );
    add_colors( gradient, gradient2, 0.5, 6, 7, 8 );
    add_colors( gradient, gradient2, 1.0, 9, 10, 11 );

    QPainter painter( &pixGradient );
    painter.setPen( Qt::NoPen );
    painter.setBrush( gradient );
    painter.drawRect( pixGradient.rect() );
    painter.end();

    painter.begin( &pixGradient2 );
    painter.setPen( Qt::NoPen );
    painter.setBrush( gradient2 );
    painter.drawRect( pixGradient2.rect() );
    painter.end();

    pixGradient.setMask( mask );
    pixGradient2.setMask( mask );
}

void SoundSlider::wheelEvent( QWheelEvent *event )
{
    int newvalue = value() + event->delta() / ( 8 * 15 ) * f_step;
    setValue( __MIN( __MAX( minimum(), newvalue ), maximum() ) );

    emit sliderReleased();
    emit sliderMoved( value() );
}

void SoundSlider::mousePressEvent( QMouseEvent *event )
{
    if( event->button() != Qt::RightButton )
    {
        /* We enter the sliding mode */
        b_isSliding = true;
        i_oldvalue = value();
        emit sliderPressed();
        changeValue( event->x() - paddingL );
        emit sliderMoved( value() );
    }
}

void SoundSlider::mouseReleaseEvent( QMouseEvent *event )
{
    if( event->button() != Qt::RightButton )
    {
        if( !b_mouseOutside && value() != i_oldvalue )
        {
            emit sliderReleased();
            setValue( value() );
            emit sliderMoved( value() );
        }
        b_isSliding = false;
        b_mouseOutside = false;
    }
}

void SoundSlider::mouseMoveEvent( QMouseEvent *event )
{
    if( b_isSliding )
    {
        QRect rect( paddingL - 15,    -1,
                    WLENGTH + 15 * 2 , WHEIGHT + 5 );
        if( !rect.contains( event->pos() ) )
        { /* We are outside */
            if ( !b_mouseOutside )
                setValue( i_oldvalue );
            b_mouseOutside = true;
        }
        else
        { /* We are inside */
            b_mouseOutside = false;
            changeValue( event->x() - paddingL );
            emit sliderMoved( value() );
        }
    }
    else
    {
        int i = ( ( event->x() - paddingL ) * maximum() + 40 ) / WLENGTH;
        i = __MIN( __MAX( 0, i ), maximum() );
        setToolTip( QString("%1  \%" ).arg( i ) );
    }
}

void SoundSlider::changeValue( int x )
{
    setValue( (x * maximum() + 40 ) / WLENGTH );
}

void SoundSlider::setMuted( bool m )
{
    b_isMuted = m;
    update();
}

void SoundSlider::paintEvent( QPaintEvent *e )
{
    QPainter painter( this );
    QPixmap *pixGradient;
    if (b_isMuted)
        pixGradient = &this->pixGradient2;
    else
        pixGradient = &this->pixGradient;

    const int offset = int( ( WLENGTH * value() + 100 ) / maximum() ) + paddingL;

    const QRectF boundsG( 0, 0, offset , pixGradient->height() );
    painter.drawPixmap( boundsG, *pixGradient, boundsG );

    const QRectF boundsO( 0, 0, pixOutside.width(), pixOutside.height() );
    painter.drawPixmap( boundsO, pixOutside, boundsO );

    painter.setPen( palette().color( QPalette::Active, QPalette::Mid ) );
    QFont font; font.setPixelSize( 9 );
    painter.setFont( font );
    const QRect rect( 0, 0, 34, 15 );
    painter.drawText( rect, Qt::AlignRight | Qt::AlignVCenter,
                      QString::number( value() ) + '%' );

    painter.end();
    e->accept();
}

<commit_msg>Qt: Compile fix for gcc 4.5<commit_after>/*****************************************************************************
 * input_manager.cpp : Manage an input and interact with its GUI elements
 ****************************************************************************
 * Copyright (C) 2006 the VideoLAN team
 * $Id$
 *
 * Authors: Clément Stenac <zorglub@videolan.org>
 *          Jean-Baptiste Kempf <jb@videolan.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "util/input_slider.hpp"

#include <QPaintEvent>
#include <QPainter>
#include <QBitmap>

InputSlider::InputSlider( QWidget *_parent ) : QSlider( _parent )
{
    InputSlider( Qt::Horizontal, _parent );
}

InputSlider::InputSlider( Qt::Orientation q, QWidget *_parent ) :
                                 QSlider( q, _parent )
{
    b_isSliding = false;
    lastSeeked  = 0;

    timer = new QTimer(this);
    timer->setSingleShot(true);

    /* Properties */
    setRange( 0, 1000 );
    setSingleStep( 2 );
    setPageStep( 10 );
    setMouseTracking(true);
    setTracking( true );
    setFocusPolicy( Qt::NoFocus );

    /* Init to 0 */
    setPosition( -1.0, 0, 0 );
    secstotimestr( psz_length, 0 );

    CONNECT( this, valueChanged(int), this, userDrag( int ) );
    CONNECT( timer, timeout(), this, seekTick() );
}

void InputSlider::setPosition( float pos, int a, int b )
{
    if( pos == -1.0 )
    {
        setEnabled( false );
        b_isSliding = false;
    }
    else
        setEnabled( true );

    if( !b_isSliding )
        setValue( (int)(pos * 1000.0 ) );

    inputLength = b;
}

void InputSlider::userDrag( int new_value )
{
    if( b_isSliding && !timer->isActive() )
        timer->start( 150 );
}

void InputSlider::seekTick()
{
    if( value() != lastSeeked )
    {
        lastSeeked = value();
        float f_pos = (float)(lastSeeked)/1000.0;
        emit sliderDragged( f_pos );
    }
}

void InputSlider::mouseReleaseEvent( QMouseEvent *event )
{
    b_isSliding = false;
    event->accept();
    QSlider::mouseReleaseEvent( event );
}

void InputSlider::mousePressEvent(QMouseEvent* event)
{
    b_isSliding = true ;
    if( event->button() != Qt::LeftButton &&
        event->button() != Qt::MidButton )
    {
        QSlider::mousePressEvent( event );
        return;
    }

    QMouseEvent newEvent( event->type(), event->pos(), event->globalPos(),
        Qt::MouseButton( event->button() ^ Qt::LeftButton ^ Qt::MidButton ),
        Qt::MouseButtons( event->buttons() ^ Qt::LeftButton ^ Qt::MidButton ),
        event->modifiers() );
    QSlider::mousePressEvent( &newEvent );

    seekTick();
}

void InputSlider::mouseMoveEvent(QMouseEvent *event)
{
    if( b_isSliding )
    {
        QSlider::mouseMoveEvent( event );
    }

    secstotimestr( psz_length, ( event->x() * inputLength) / size().width() );
    setToolTip( psz_length );
    event->accept();
}

void InputSlider::wheelEvent( QWheelEvent *event)
{
    /* Don't do anything if we are for somehow reason sliding */
    if( !b_isSliding )
    {
        setValue( value() + event->delta()/12 ); /* 12 = 8 * 15 / 10
         Since delta is in 1/8 of ° and mouse have steps of 15 °
         and that our slider is in 0.1% and we want one step to be a 1%
         increment of position */
        emit sliderDragged( value()/1000.0 );
    }
    /* We do accept because for we don't want the parent to change the sound
       vol */
    event->accept();
}

/* This work is derived from Amarok's work under GPLv2+
    - Mark Kretschmann
    - Gábor Lehel
   */
#define WLENGTH   80 // px
#define WHEIGHT   22  // px
#define SOUNDMIN  0   // %
#define SOUNDMAX  200 // % OR 400 ?

SoundSlider::SoundSlider( QWidget *_parent, int _i_step, bool b_hard,
                          char *psz_colors )
                        : QAbstractSlider( _parent )
{
    f_step = ( _i_step * 100 ) / AOUT_VOLUME_MAX ;
    setRange( SOUNDMIN, b_hard ? (2 * SOUNDMAX) : SOUNDMAX  );
    setMouseTracking( true );
    b_isSliding = false;
    b_mouseOutside = true;
    b_isMuted = false;

    pixOutside = QPixmap( ":/toolbar/volslide-outside" );

    const QPixmap temp( ":/toolbar/volslide-inside" );
    const QBitmap mask( temp.createHeuristicMask() );

    setMinimumSize( pixOutside.size() );

    pixGradient = QPixmap( mask.size() );
    pixGradient2 = QPixmap( mask.size() );

    /* Gradient building from the preferences */
    QLinearGradient gradient( paddingL, 2, WLENGTH + paddingL , 2 );
    QLinearGradient gradient2( paddingL, 2, WLENGTH + paddingL , 2 );

    QStringList colorList = qfu( psz_colors ).split( ";" );
    free( psz_colors );

    /* Fill with 255 if the list is too short */
    if( colorList.size() < 12 )
        for( int i = colorList.size(); i < 12; i++)
            colorList.append( "255" );

    /* Regular colors */
#define c(i) colorList.at(i).toInt()
#define add_color(gradient, range, c1, c2, c3) \
    gradient.setColorAt( range, QColor( c(c1), c(c2), c(c3) ) );

    /* Desaturated colors */
#define desaturate(c) c->setHsvF( c->hueF(), 0.2 , 0.5, 1.0 )
#define add_desaturated_color(gradient, range, c1, c2, c3) \
    foo = new QColor( c(c1), c(c2), c(c3) );\
    desaturate( foo ); gradient.setColorAt( range, *foo );\
    delete foo;

    /* combine the two helpers */
#define add_colors( gradient1, gradient2, range, c1, c2, c3 )\
    add_color( gradient1, range, c1, c2, c3 ); \
    add_desaturated_color( gradient2, range, c1, c2, c3 );

    QColor * foo;
    add_colors( gradient, gradient2, 0.0, 0, 1, 2 );
    add_colors( gradient, gradient2, 0.22, 3, 4, 5 );
    add_colors( gradient, gradient2, 0.5, 6, 7, 8 );
    add_colors( gradient, gradient2, 1.0, 9, 10, 11 );

    QPainter painter( &pixGradient );
    painter.setPen( Qt::NoPen );
    painter.setBrush( gradient );
    painter.drawRect( pixGradient.rect() );
    painter.end();

    painter.begin( &pixGradient2 );
    painter.setPen( Qt::NoPen );
    painter.setBrush( gradient2 );
    painter.drawRect( pixGradient2.rect() );
    painter.end();

    pixGradient.setMask( mask );
    pixGradient2.setMask( mask );
}

void SoundSlider::wheelEvent( QWheelEvent *event )
{
    int newvalue = value() + event->delta() / ( 8 * 15 ) * f_step;
    setValue( __MIN( __MAX( minimum(), newvalue ), maximum() ) );

    emit sliderReleased();
    emit sliderMoved( value() );
}

void SoundSlider::mousePressEvent( QMouseEvent *event )
{
    if( event->button() != Qt::RightButton )
    {
        /* We enter the sliding mode */
        b_isSliding = true;
        i_oldvalue = value();
        emit sliderPressed();
        changeValue( event->x() - paddingL );
        emit sliderMoved( value() );
    }
}

void SoundSlider::mouseReleaseEvent( QMouseEvent *event )
{
    if( event->button() != Qt::RightButton )
    {
        if( !b_mouseOutside && value() != i_oldvalue )
        {
            emit sliderReleased();
            setValue( value() );
            emit sliderMoved( value() );
        }
        b_isSliding = false;
        b_mouseOutside = false;
    }
}

void SoundSlider::mouseMoveEvent( QMouseEvent *event )
{
    if( b_isSliding )
    {
        QRect rect( paddingL - 15,    -1,
                    WLENGTH + 15 * 2 , WHEIGHT + 5 );
        if( !rect.contains( event->pos() ) )
        { /* We are outside */
            if ( !b_mouseOutside )
                setValue( i_oldvalue );
            b_mouseOutside = true;
        }
        else
        { /* We are inside */
            b_mouseOutside = false;
            changeValue( event->x() - paddingL );
            emit sliderMoved( value() );
        }
    }
    else
    {
        int i = ( ( event->x() - paddingL ) * maximum() + 40 ) / WLENGTH;
        i = __MIN( __MAX( 0, i ), maximum() );
        setToolTip( QString("%1  \%" ).arg( i ) );
    }
}

void SoundSlider::changeValue( int x )
{
    setValue( (x * maximum() + 40 ) / WLENGTH );
}

void SoundSlider::setMuted( bool m )
{
    b_isMuted = m;
    update();
}

void SoundSlider::paintEvent( QPaintEvent *e )
{
    QPainter painter( this );
    QPixmap *pixGradient;
    if (b_isMuted)
        pixGradient = &this->pixGradient2;
    else
        pixGradient = &this->pixGradient;

    const int offset = int( ( WLENGTH * value() + 100 ) / maximum() ) + paddingL;

    const QRectF boundsG( 0, 0, offset , pixGradient->height() );
    painter.drawPixmap( boundsG, *pixGradient, boundsG );

    const QRectF boundsO( 0, 0, pixOutside.width(), pixOutside.height() );
    painter.drawPixmap( boundsO, pixOutside, boundsO );

    painter.setPen( palette().color( QPalette::Active, QPalette::Mid ) );
    QFont font; font.setPixelSize( 9 );
    painter.setFont( font );
    const QRect rect( 0, 0, 34, 15 );
    painter.drawText( rect, Qt::AlignRight | Qt::AlignVCenter,
                      QString::number( value() ) + '%' );

    painter.end();
    e->accept();
}

<|endoftext|>


<commit_before>/* ************************************************************************** */
/*                                                                            */
/*                                                        :::      ::::::::   */
/*   GraphicalDisplay.class.cpp                         :+:      :+:    :+:   */
/*                                                    +:+ +:+         +:+     */
/*   By: mmartin <mmartin@student.42.fr>            +#+  +:+       +#+        */
/*                                                +#+#+#+#+#+   +#+           */
/*   Created: 2015/01/31 19:36:40 by mmartin           #+#    #+#             */
/*   Updated: 2015/02/16 16:32:10 by mmartin          ###   ########.fr       */
/*                                                                            */
/* ************************************************************************** */

#include <X11/keysym.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include "GraphicalDisplay.class.hpp"

/*
**	Constructor / destructor
*/
GraphicalDisplay::GraphicalDisplay(unsigned int width, unsigned int height)
{
	XSetWindowAttributes	attributes;
	Visual					*visual;
	int						screen;
	int						depth;

	_width = width;
	_height = height;
	_map = new Map(_width, _height);

	_dis = XOpenDisplay(NULL);
	screen = DefaultScreen(_dis);
	visual = DefaultVisual(_dis, screen);
	depth = DefaultDepth(_dis, screen);
	attributes.background_pixel = XWhitePixel(_dis, screen);

	_win = XCreateWindow(_dis, XRootWindow(_dis, screen), 0, 0, _width, _height, 1, depth, InputOutput, visual, CWBackPixel, &attributes);
	XMapWindow(_dis, _win);
	XSelectInput(_dis, _win, ExposureMask | KeyPressMask | ButtonPressMask);

	_data = new char[_width * _height * 4];
	_image = XCreateImage(_dis, visual, depth, XYPixmap, 0, _data, _width, _height, 32, 0);
	_dataWater = new char[_width * _height * 4];
	_imageWater = XCreateImage(_dis, visual, depth, XYPixmap, 0, _dataWater, _width, _height, 32, 0);

	_dataGrey = new char[200 * 25 * 4];
	_greyBG = XCreateImage(_dis, visual, depth, XYPixmap, 0, _dataGrey, 200, 25, 32, 0);
	_dataWhite = new char[200 * 25 * 4];
	_whiteBG = XCreateImage(_dis, visual, depth, XYPixmap, 0, _dataWhite, 200, 25, 32, 0);

	rise = true;
	rain = false;
	evaporate = false;
	south = false;
	east = false;
	north = false;
	west = false;
}

GraphicalDisplay::~GraphicalDisplay(void)
{
	if (_map)
		delete _map;
	XDestroyImage(_image);
	XDestroyImage(_greyBG);
	XDestroyImage(_whiteBG);
	XCloseDisplay(_dis);
}

/*
**	Setter
*/
bool		GraphicalDisplay::setMap(std::list<t_map> &mapHill)
{
	if (!_map)
		return (false);

	_map->setMapHill(mapHill);

	return (true);
}

bool		GraphicalDisplay::setWater(void)
{
	_water = new Water(_map->getMap(), _width, _height);
	return (true);
}

/*
**		Draw pixel per pixel
**		TODO: degraded on color from 0.01 to 0.8 with brown
*/
void		GraphicalDisplay::draw(float **tab)
{
	unsigned int	color;
	int				proj_x;
	int				proj_y;

	for (size_t x = 0; x < _width; x++)
	{
		for (size_t y = 0; y < _height; y++)
		{
			proj_x = 0.5f * x - 0.5f * y + 500;
			proj_y = tab[y][x] * -100 + 0.25f * x + 0.25f * y + 500;
			if (tab[y][x] > 0.8)
				color = 0xFFFF00 + tab[y][x] * 255;
			else if (tab[y][x] > 0.6)
				color = 0x795227 + tab[y][x];
			else if (tab[y][x] > 0.2)
				color = 0x87591A + tab[y][x];
			else if (tab[y][x] > 0.01)
				color = 0x8B6C42 + tab[y][x];
			else
				color = 0x3A9D23;
			XPutPixel(_image, proj_x, proj_y, color);
			XPutPixel(_imageWater, proj_x, proj_y, color);
		}
	}
}

void		GraphicalDisplay::drawWater(float **tab)
{
	unsigned int	color;
	t_water			**map;
	int				proj_x;
	int				proj_y;

	map = _water->getCurMap();
	for (size_t x = 0; x < _width; x++)
	{
		for (size_t y = 0; y < _height; y++)
		{
			if (tab[x][y] < map[x][y].height)
			{
				proj_x = 0.5f * x - 0.5f * y + 500;
				proj_y = map[y][x].height * -100 + 0.25f * x + 0.25f * y + 500;
				color = 0x0000FF;
			}
			else
			{
				proj_x = 0.5f * x - 0.5f * y + 500;
				proj_y = tab[y][x] * -100 + 0.25f * x + 0.25f * y + 500;
				if (tab[y][x] > 0.8)
					color = 0xFFFF00 + tab[y][x] * 255;
				else if (tab[y][x] > 0.6)
					color = 0x795227 + tab[y][x];
				else if (tab[y][x] > 0.2)
					color = 0x87591A + tab[y][x];
				else if (tab[y][x] > 0.01)
					color = 0x8B6C42 + tab[y][x];
				else
					color = 0x3A9D23;
			}
			XPutPixel(_imageWater, proj_x, proj_y, color);
		}
	}

}

void		GraphicalDisplay::setBackground(void)
{
	for (int x = 0; x < 200; x++)
	{
		for (int y = 0; y < 25; y++)
		{
			XPutPixel(_greyBG, x, y, (!y || !x ? 0x000000 : 0xd3d3d3));
			XPutPixel(_whiteBG, x, y, (!y || !x ? 0x000000 : 0xFFFFFF));
		}
	}
}

void		GraphicalDisplay::expose(GC gc)
{
	XPutImage(_dis, _win, gc, _imageWater, 0, 0, 0, 0, _width, _height);
	XPutImage(_dis, _win, gc, (rise ? _whiteBG : _greyBG), 0, 0, 0, 0, 200, 25);
	XDrawString(_dis, _win, gc, 50, 15, "Rise water", 10);
	XPutImage(_dis, _win, gc, (south ? _whiteBG : _greyBG), 0, 0, 200, 0, 200, 25);
	XDrawString(_dis, _win, gc, 250, 15, "South wave", 10);
	XPutImage(_dis, _win, gc, (east ? _whiteBG : _greyBG), 0, 0, 200, 25, 200, 25);
	XDrawString(_dis, _win, gc, 250, 40, "East wave", 9);
	XPutImage(_dis, _win, gc, (north ? _whiteBG : _greyBG), 0, 0, 200, 50, 200, 25);
	XDrawString(_dis, _win, gc, 250, 65, "North wave", 10);
	XPutImage(_dis, _win, gc, (west ? _whiteBG : _greyBG), 0, 0, 200, 75, 200, 25);
	XDrawString(_dis, _win, gc, 250, 90, "West wave", 9);
	XPutImage(_dis, _win, gc, _greyBG, 0, 0, 200, 100, 200, 25);
	XDrawString(_dis, _win, gc, 250, 115, "All wave", 8);
	XPutImage(_dis, _win, gc, (rain ? _whiteBG : _greyBG), 0, 0, 400, 0, 200, 25);
	XDrawString(_dis, _win, gc, 450, 15, "Rain water", 10);
	XPutImage(_dis, _win, gc, (evaporate ? _whiteBG : _greyBG), 0, 0, 600, 0, 200, 25);
	XDrawString(_dis, _win, gc, 650, 15, "Evaporate water", 15);
	XPutImage(_dis, _win, gc, _greyBG, 0, 0, 800, 0, 200, 25);
	XDrawString(_dis, _win, gc, 850, 15, "Exit", 4);
	XFlush(_dis);
}

bool		GraphicalDisplay::buttonEvent(GC gc, XEvent event)
{
	int		x = event.xbutton.x;
	int		y = event.xbutton.y;

	if (x < 1000 && y < 125)
	{
		if (y < 25 || (x > 200 && x < 400))
		{
			rise = false;
			rain = false;
			evaporate = false;
			if (!(x > 200 && x < 400))
			{
				south = false;
				east = false;
				north = false;
				west = false;
			}
		}
		if (y < 25 && x < 200)
			rise = (rise ? false : true);
		else if (y < 25 && x < 400)
			south = (south ? false : true);
		else if (y < 50 && x < 400)
			east = (east ?  false: true);
		else if (y < 75 && x < 400)
			north = (north ? false: true);
		else if (y < 100 && x < 400)
			west = (west ? false : true);
		else if (y < 125 && x < 400)
		{
			south = true;
			east = true;
			north = true;
			west = true;
		}
		else if (y < 25 && x < 600)
			rain = (rain ? false : true);
		else if (y < 25 && x < 800)
			evaporate = (evaporate ? false : true);
		else if (y < 25 && x < 1000)
			return (true);
		if (y < 25 || (x > 200 && x < 400))
			this->expose(gc);
	}
	return (false);
}

/*
**		Run XQuartz in infinity loop for catch event
*/
void		GraphicalDisplay::run(void)
{
	GC				gc;
	float			**tab = _map->getMap();
	bool			run = true;
	int				fd;
	fd_set			in_fds;
	struct timeval	tv;

	fd = ConnectionNumber(_dis);
	gc = XCreateGC(_dis, _win, 0, 0);
	this->setBackground();
	this->draw(tab);
	while (run)
	{
		FD_ZERO(&in_fds);
		FD_SET(fd, &in_fds);

		tv.tv_usec = 10000;
		tv.tv_sec = 0;

		if (select(fd + 1, &in_fds, 0, 0, &tv))
		{
			XNextEvent(_dis, &_report);
			switch (_report.type) {
				case Expose:
					if (_report.xexpose.count == 0)
						this->expose(gc);
				break;
				case KeyPress:
					if (XLookupKeysym(&_report.xkey, 0) == XK_q)
						run = false;
				break;
				case ButtonPress:
					if (this->buttonEvent(gc, _report))
						run = false;
				break;
			}
		}
		else
		{
			if (rise)
				_water->Flood();
			if (south || east ||  north || west)
				_water->Waves(north, south, east, west);
			if (rain)
				_water->Rainy();
			this->drawWater(tab);
			this->expose(gc);
		}
	}
	XFreeGC(_dis, gc);
}
<commit_msg>x y tout le temps<commit_after>/* ************************************************************************** */
/*                                                                            */
/*                                                        :::      ::::::::   */
/*   GraphicalDisplay.class.cpp                         :+:      :+:    :+:   */
/*                                                    +:+ +:+         +:+     */
/*   By: mmartin <mmartin@student.42.fr>            +#+  +:+       +#+        */
/*                                                +#+#+#+#+#+   +#+           */
/*   Created: 2015/01/31 19:36:40 by mmartin           #+#    #+#             */
/*   Updated: 2015/02/16 17:40:19 by mmartin          ###   ########.fr       */
/*                                                                            */
/* ************************************************************************** */

#include <X11/keysym.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include "GraphicalDisplay.class.hpp"

/*
**	Constructor / destructor
*/
GraphicalDisplay::GraphicalDisplay(unsigned int width, unsigned int height)
{
	XSetWindowAttributes	attributes;
	Visual					*visual;
	int						screen;
	int						depth;

	_width = width;
	_height = height;
	_map = new Map(_width, _height);

	_dis = XOpenDisplay(NULL);
	screen = DefaultScreen(_dis);
	visual = DefaultVisual(_dis, screen);
	depth = DefaultDepth(_dis, screen);
	attributes.background_pixel = XWhitePixel(_dis, screen);

	_win = XCreateWindow(_dis, XRootWindow(_dis, screen), 0, 0, _width, _height, 1, depth, InputOutput, visual, CWBackPixel, &attributes);
	XMapWindow(_dis, _win);
	XSelectInput(_dis, _win, ExposureMask | KeyPressMask | ButtonPressMask);

	_data = new char[_width * _height * 4];
	_image = XCreateImage(_dis, visual, depth, XYPixmap, 0, _data, _width, _height, 32, 0);
	_dataWater = new char[_width * _height * 4];
	_imageWater = XCreateImage(_dis, visual, depth, XYPixmap, 0, _dataWater, _width, _height, 32, 0);

	_dataGrey = new char[200 * 25 * 4];
	_greyBG = XCreateImage(_dis, visual, depth, XYPixmap, 0, _dataGrey, 200, 25, 32, 0);
	_dataWhite = new char[200 * 25 * 4];
	_whiteBG = XCreateImage(_dis, visual, depth, XYPixmap, 0, _dataWhite, 200, 25, 32, 0);

	rise = true;
	rain = false;
	evaporate = false;
	south = false;
	east = false;
	north = false;
	west = false;
}

GraphicalDisplay::~GraphicalDisplay(void)
{
	if (_map)
		delete _map;
	XDestroyImage(_image);
	XDestroyImage(_greyBG);
	XDestroyImage(_whiteBG);
	XCloseDisplay(_dis);
}

/*
**	Setter
*/
bool		GraphicalDisplay::setMap(std::list<t_map> &mapHill)
{
	if (!_map)
		return (false);

	_map->setMapHill(mapHill);

	return (true);
}

bool		GraphicalDisplay::setWater(void)
{
	_water = new Water(_map->getMap(), _width, _height);
	return (true);
}

/*
**		Draw pixel per pixel
**		TODO: degraded on color from 0.01 to 0.8 with brown
*/
void		GraphicalDisplay::draw(float **tab)
{
	unsigned int	color;
	int				proj_x;
	int				proj_y;

	for (size_t x = 0; x < _width; x++)
	{
		for (size_t y = 0; y < _height; y++)
		{
			proj_x = 0.5f * x - 0.5f * y + 500;
			proj_y = tab[x][y] * -100 + 0.25f * x + 0.25f * y + 500;
			if (tab[x][y] > 0.8)
				color = 0xFFFF00 + tab[x][y] * 255;
			else if (tab[x][y] > 0.6)
				color = 0x795227 + tab[x][y];
			else if (tab[x][y] > 0.2)
				color = 0x87591A + tab[x][y];
			else if (tab[x][y] > 0.01)
				color = 0x8B6C42 + tab[x][y];
			else
				color = 0x3A9D23;
			XPutPixel(_image, proj_x, proj_y, color);
			XPutPixel(_imageWater, proj_x, proj_y, color);
		}
	}
}

void		GraphicalDisplay::drawWater(float **tab)
{
	unsigned int	color;
	t_water			**map;
	int				proj_x;
	int				proj_y;

	map = _water->getCurMap();
	for (size_t x = 0; x < _width; x++)
	{
		for (size_t y = 0; y < _height; y++)
		{
			if (tab[x][y] < map[x][y].height)
			{
				proj_x = 0.5f * x - 0.5f * y + 500;
				proj_y = map[x][y].height * -100 + 0.25f * x + 0.25f * y + 500;
				color = 0x0000FF;
			}
			else
			{
				proj_x = 0.5f * x - 0.5f * y + 500;
				proj_y = tab[x][y] * -100 + 0.25f * x + 0.25f * y + 500;
				if (tab[x][y] > 0.8)
					color = 0xFFFF00 + tab[x][y] * 255;
				else if (tab[x][y] > 0.6)
					color = 0x795227 + tab[x][y];
				else if (tab[x][y] > 0.2)
					color = 0x87591A + tab[x][y];
				else if (tab[x][y] > 0.01)
					color = 0x8B6C42 + tab[x][y];
				else
					color = 0x3A9D23;
			}
			XPutPixel(_imageWater, proj_x, proj_y, color);
		}
	}

}

void		GraphicalDisplay::setBackground(void)
{
	for (int x = 0; x < 200; x++)
	{
		for (int y = 0; y < 25; y++)
		{
			XPutPixel(_greyBG, x, y, (!y || !x ? 0x000000 : 0xd3d3d3));
			XPutPixel(_whiteBG, x, y, (!y || !x ? 0x000000 : 0xFFFFFF));
		}
	}
}

void		GraphicalDisplay::expose(GC gc)
{
	XPutImage(_dis, _win, gc, _imageWater, 0, 0, 0, 0, _width, _height);
	XPutImage(_dis, _win, gc, (rise ? _whiteBG : _greyBG), 0, 0, 0, 0, 200, 25);
	XDrawString(_dis, _win, gc, 50, 15, "Rise water", 10);
	XPutImage(_dis, _win, gc, (south ? _whiteBG : _greyBG), 0, 0, 200, 0, 200, 25);
	XDrawString(_dis, _win, gc, 250, 15, "South wave", 10);
	XPutImage(_dis, _win, gc, (east ? _whiteBG : _greyBG), 0, 0, 200, 25, 200, 25);
	XDrawString(_dis, _win, gc, 250, 40, "East wave", 9);
	XPutImage(_dis, _win, gc, (north ? _whiteBG : _greyBG), 0, 0, 200, 50, 200, 25);
	XDrawString(_dis, _win, gc, 250, 65, "North wave", 10);
	XPutImage(_dis, _win, gc, (west ? _whiteBG : _greyBG), 0, 0, 200, 75, 200, 25);
	XDrawString(_dis, _win, gc, 250, 90, "West wave", 9);
	XPutImage(_dis, _win, gc, _greyBG, 0, 0, 200, 100, 200, 25);
	XDrawString(_dis, _win, gc, 250, 115, "All wave", 8);
	XPutImage(_dis, _win, gc, (rain ? _whiteBG : _greyBG), 0, 0, 400, 0, 200, 25);
	XDrawString(_dis, _win, gc, 450, 15, "Rain water", 10);
	XPutImage(_dis, _win, gc, (evaporate ? _whiteBG : _greyBG), 0, 0, 600, 0, 200, 25);
	XDrawString(_dis, _win, gc, 650, 15, "Evaporate water", 15);
	XPutImage(_dis, _win, gc, _greyBG, 0, 0, 800, 0, 200, 25);
	XDrawString(_dis, _win, gc, 850, 15, "Exit", 4);
	XFlush(_dis);
}

bool		GraphicalDisplay::buttonEvent(GC gc, XEvent event)
{
	int		x = event.xbutton.x;
	int		y = event.xbutton.y;

	if (x < 1000 && y < 125)
	{
		if (y < 25 || (x > 200 && x < 400))
		{
			rise = false;
			rain = false;
			evaporate = false;
			if (!(x > 200 && x < 400))
			{
				south = false;
				east = false;
				north = false;
				west = false;
			}
		}
		if (y < 25 && x < 200)
			rise = (rise ? false : true);
		else if (y < 25 && x < 400)
			south = (south ? false : true);
		else if (y < 50 && x < 400)
			east = (east ?  false: true);
		else if (y < 75 && x < 400)
			north = (north ? false: true);
		else if (y < 100 && x < 400)
			west = (west ? false : true);
		else if (y < 125 && x < 400)
		{
			south = true;
			east = true;
			north = true;
			west = true;
		}
		else if (y < 25 && x < 600)
			rain = (rain ? false : true);
		else if (y < 25 && x < 800)
			evaporate = (evaporate ? false : true);
		else if (y < 25 && x < 1000)
			return (true);
		if (y < 25 || (x > 200 && x < 400))
			this->expose(gc);
	}
	return (false);
}

/*
**		Run XQuartz in infinity loop for catch event
*/
void		GraphicalDisplay::run(void)
{
	GC				gc;
	float			**tab = _map->getMap();
	bool			run = true;
	int				fd;
	fd_set			in_fds;
	struct timeval	tv;

	fd = ConnectionNumber(_dis);
	gc = XCreateGC(_dis, _win, 0, 0);
	this->setBackground();
	this->draw(tab);
	while (run)
	{
		FD_ZERO(&in_fds);
		FD_SET(fd, &in_fds);

		tv.tv_usec = 10000;
		tv.tv_sec = 0;

		if (select(fd + 1, &in_fds, 0, 0, &tv))
		{
			XNextEvent(_dis, &_report);
			switch (_report.type) {
				case Expose:
					if (_report.xexpose.count == 0)
						this->expose(gc);
				break;
				case KeyPress:
					if (XLookupKeysym(&_report.xkey, 0) == XK_q)
						run = false;
				break;
				case ButtonPress:
					if (this->buttonEvent(gc, _report))
						run = false;
				break;
			}
		}
		else
		{
			if (rise)
				_water->Flood();
			if (south || east ||  north || west)
				_water->Waves(north, south, east, west);
			if (rain)
				_water->Rainy();
			this->drawWater(tab);
			this->expose(gc);
		}
	}
	XFreeGC(_dis, gc);
}
<|endoftext|>