<commit_before>#include "streams.h"
#include "util.h"
#include <glog/logging.h>
#include <unordered_map>

void call_rescue(e_t e, const children_t& children) {
  for (auto& s: children) {
    s(e);
  }
}

stream_t prn() {
  return [](e_t e) {
    VLOG(3) << "prn()";
    LOG(INFO) << "prn() " <<  event_to_json(e);
  };
}

stream_t with(const with_changes_t& changes, const children_t& children) {
  return [=](e_t e) {
    Event ne(e);
    for (auto &kv: changes) {
      VLOG(3) << "with()  first: " << kv.first << " second: " << kv.second;
      set_event_value(ne, kv.first, kv.second, true);
    }
    call_rescue(ne, children);
  };
}

stream_t with_ifempty(
    const with_changes_t& changes,
    const children_t& children)
{
  return [=](e_t e) {
    Event ne(e);
    for (auto &kv: changes) {
      VLOG(3) << "default()  first: " << kv.first << " second: " << kv.second;
      set_event_value(ne, kv.first, kv.second, false);
    }
    call_rescue(ne, children);
  };
}

stream_t split(const split_clauses_t clauses,
               const children_t& default_children)
{
  return [=](e_t e) {
    VLOG(3) << "split()";
    for (auto &pair: clauses) {
      predicate_t predicate = pair.first;
      predicate(e);
      if (pair.first(e)) {
        VLOG(3) << "split() clause found";
        call_rescue(e, pair.second);
        return;
      }
    }
    if (default_children.size() > 0) {
      VLOG(3) << "split() default";
      call_rescue(e, default_children);
    }
  };
}

typedef std::unordered_map<std::string, const children_t> by_streams_map_t;

stream_t by(const by_keys_t& keys, const by_streams_t& streams) {
  by_streams_map_t* streams_map = new by_streams_map_t();
  return [=](e_t e) {
    VLOG(3) << "by()";

    if (keys.size() == 0) {
      return;
    }

    std::string key("");
    for (auto &k: keys) {
      std::string value = string_to_value(e, k);
      if (value == "__nil__") {
        LOG(ERROR) << "by() field empty: " << k;
      }
      key += value + "-";
    }

    VLOG(3) << "by() key: " << key;
    auto it = streams_map->find(key);
    if (it == streams_map->end()) {
      VLOG(3) << "by() key not found. Creating stream.";
      children_t children;
      for (auto &s: streams) {
        children.push_back(s());
      }
      streams_map->insert({key, children});
      call_rescue(e, streams_map->find(key)->second);
    } else {
      VLOG(3) << "by() stream exists. ";
      call_rescue(e, it->second);
    }
  };
}

stream_t where(const predicate_t& predicate, const children_t& children,
               const children_t& else_children)
{
  return [=](e_t e) {
    if (predicate(e)) {
      call_rescue(e, children);
    } else {
      call_rescue(e, else_children);
    }
  };
}

stream_t rate(const int interval, const children_t& children) {
  double* rate = new double(0);

  CallbackTimer* callbackTimer = new CallbackTimer(interval,
      [=]()
      {
        VLOG(3) << "rate-timer()";
        Event e;
        e.set_metric_f(*rate / interval);
        e.set_time(time(0));
        *rate = 0;
        VLOG(3) << "rate-timer() value: " << e.metric_f();
        call_rescue(e, children);
      });

  (void)(callbackTimer);

  return [=](e_t e) {
    VLOG(3) << "rate() rate += e.metric";
    *rate += metric_to_double(e);
  };
}

stream_t changed_state(std::string initial, const children_t& children) {
  std::string* last_state = new std::string(initial);

  return [=](e_t e) {
    VLOG(3) << "changed_state() last_state: "
            << last_state << " new state " << e.state();
    if (*last_state != e.state()) {
      VLOG(3) << "changed_state() state change";
      last_state->assign(e.state());
      call_rescue(e, children);
    }
  };
}

stream_t tagged_any(const tags_t& tags, const children_t& children) {
  return [=](e_t e) {
    VLOG(3) << "tagged_any()";
    if (tagged_any_(e, tags)) {
      VLOG(3) << "tagged_any() match";
      call_rescue(e, children);
    }
  };
}

stream_t tagged_all(const tags_t& tags, const children_t& children) {
  return [=](e_t e) {
    VLOG(3) << "tagged_all()";
    if (tagged_all_(e, tags)) {
      VLOG(3) << "tagged_all() match";
      call_rescue(e, children);
    }
  };
}

bool tagged_any_(e_t e, const tags_t& tags) {
  for (auto &tag: tags) {
    if (tag_exists(e, tag)) {
      return true;
    }
  }
  return false;
}

bool tagged_all_(e_t e, const tags_t& tags) {
  for (auto &tag: tags) {
    if (!tag_exists(e, tag)) {
      return false;
    }
  }
  return true;
}

stream_t send_index(Index& index) {
  return [&](e_t e) {
    if (e.state() != "expired") {
      index.add_event(e);
    }
  };
}

void Streams::add_stream(stream_t stream) {
  VLOG(3) << "adding stream";
  streams.push_back(stream);
}

void Streams::process_message(const Msg& message) {
  VLOG(3) << "process message. num of streams " << streams.size();
  unsigned long int sec = time(0);
  for (int i = 0; i < message.events_size(); i++) {
    const Event &event = message.events(i);
    if (!event.has_time()) {
      Event nevent(event);
      nevent.set_time(sec);
      push_event(nevent);
    } else {
      push_event(event);
    }
  }
}

inline void Streams::push_event(const Event& e) {
  for (auto& s: streams) {
    s(e);
  }
}

<commit_msg>Use mutable lambdas and avoid pointers<commit_after>#include "streams.h"
#include "util.h"
#include <glog/logging.h>
#include <unordered_map>

void call_rescue(e_t e, const children_t& children) {
  for (auto& s: children) {
    s(e);
  }
}

stream_t prn() {
  return [](e_t e) {
    VLOG(3) << "prn()";
    LOG(INFO) << "prn() " <<  event_to_json(e);
  };
}

stream_t with(const with_changes_t& changes, const children_t& children) {
  return [=](e_t e) {
    Event ne(e);
    for (auto &kv: changes) {
      VLOG(3) << "with()  first: " << kv.first << " second: " << kv.second;
      set_event_value(ne, kv.first, kv.second, true);
    }
    call_rescue(ne, children);
  };
}

stream_t with_ifempty(
    const with_changes_t& changes,
    const children_t& children)
{
  return [=](e_t e) {
    Event ne(e);
    for (auto &kv: changes) {
      VLOG(3) << "default()  first: " << kv.first << " second: " << kv.second;
      set_event_value(ne, kv.first, kv.second, false);
    }
    call_rescue(ne, children);
  };
}

stream_t split(const split_clauses_t clauses,
               const children_t& default_children)
{
  return [=](e_t e) {
    VLOG(3) << "split()";
    for (auto &pair: clauses) {
      predicate_t predicate = pair.first;
      predicate(e);
      if (pair.first(e)) {
        VLOG(3) << "split() clause found";
        call_rescue(e, pair.second);
        return;
      }
    }
    if (default_children.size() > 0) {
      VLOG(3) << "split() default";
      call_rescue(e, default_children);
    }
  };
}

typedef std::unordered_map<std::string, const children_t> by_streams_map_t;

stream_t by(const by_keys_t& keys, const by_streams_t& streams) {
  by_streams_map_t streams_map;

  return [=](e_t e) mutable {
    VLOG(3) << "by()";

    if (keys.size() == 0) {
      return;
    }

    std::string key("");
    for (auto &k: keys) {
      std::string value = string_to_value(e, k);
      if (value == "__nil__") {
        LOG(ERROR) << "by() field empty: " << k;
      }
      key += value + "-";
    }

    VLOG(3) << "by() key: " << key;
    auto it = streams_map.find(key);
    if (it == streams_map.end()) {
      VLOG(3) << "by() key not found. Creating stream.";
      children_t children;
      for (auto &s: streams) {
        children.push_back(s());
      }
      streams_map.insert({key, children});
      call_rescue(e, streams_map.find(key)->second);
    } else {
      VLOG(3) << "by() stream exists. ";
      call_rescue(e, it->second);
    }
  };
}

stream_t where(const predicate_t& predicate, const children_t& children,
               const children_t& else_children)
{
  return [=](e_t e) {
    if (predicate(e)) {
      call_rescue(e, children);
    } else {
      call_rescue(e, else_children);
    }
  };
}

stream_t rate(const int interval, const children_t& children) {
  double rate = 0;

  CallbackTimer* callbackTimer = new CallbackTimer(interval,
     [=]() mutable
      {
        VLOG(3) << "rate-timer()";
        Event e;
        e.set_metric_f(rate / interval);
        e.set_time(time(0));
        rate = 0;
        VLOG(3) << "rate-timer() value: " << e.metric_f();
        call_rescue(e, children);
      });

  (void)(callbackTimer);

  return [=](e_t e) mutable {
    VLOG(3) << "rate() rate += e.metric";
    rate += metric_to_double(e);
  };
}

stream_t changed_state(std::string initial, const children_t& children) {
  std::string last_state(initial);

  return [=](e_t e) mutable {
    VLOG(3) << "changed_state() last_state: "
            << last_state << " new state " << e.state();
    if (last_state != e.state()) {
      VLOG(3) << "changed_state() state change";
      last_state.assign(e.state());
      call_rescue(e, children);
    }
  };
}

stream_t tagged_any(const tags_t& tags, const children_t& children) {
  return [=](e_t e) {
    VLOG(3) << "tagged_any()";
    if (tagged_any_(e, tags)) {
      VLOG(3) << "tagged_any() match";
      call_rescue(e, children);
    }
  };
}

stream_t tagged_all(const tags_t& tags, const children_t& children) {
  return [=](e_t e) {
    VLOG(3) << "tagged_all()";
    if (tagged_all_(e, tags)) {
      VLOG(3) << "tagged_all() match";
      call_rescue(e, children);
    }
  };
}

bool tagged_any_(e_t e, const tags_t& tags) {
  for (auto &tag: tags) {
    if (tag_exists(e, tag)) {
      return true;
    }
  }
  return false;
}

bool tagged_all_(e_t e, const tags_t& tags) {
  for (auto &tag: tags) {
    if (!tag_exists(e, tag)) {
      return false;
    }
  }
  return true;
}

stream_t send_index(Index& index) {
  return [&](e_t e) {
    if (e.state() != "expired") {
      index.add_event(e);
    }
  };
}

void Streams::add_stream(stream_t stream) {
  VLOG(3) << "adding stream";
  streams.push_back(stream);
}

void Streams::process_message(const Msg& message) {
  VLOG(3) << "process message. num of streams " << streams.size();
  unsigned long int sec = time(0);
  for (int i = 0; i < message.events_size(); i++) {
    const Event &event = message.events(i);
    if (!event.has_time()) {
      Event nevent(event);
      nevent.set_time(sec);
      push_event(nevent);
    } else {
      push_event(event);
    }
  }
}

inline void Streams::push_event(const Event& e) {
  for (auto& s: streams) {
    s(e);
  }
}

<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of meegotouch-controlpanelapplets.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/
#include "wallpaperbusinesslogic.h"
#include "wallpaperdescriptor.h"

WallpaperBusinessLogic::WallpaperBusinessLogic (
        QObject *parent) :
    QObject (parent)
{
    Q_UNUSED (parent);
}

WallpaperBusinessLogic::~WallpaperBusinessLogic ()
{

}

void
WallpaperBusinessLogic::currentWallpaper (
        QString   &currentFilePath,
        QString   &originalFilePath)
{
    Q_UNUSED (currentFilePath);
    Q_UNUSED (originalFilePath);
}

void
WallpaperBusinessLogic::workerThreadFinishedSave ()
{
}

void
WallpaperBusinessLogic::gconfTimerSlot ()
{
}

void
WallpaperBusinessLogic::workerThreadFinishedLoad ()
{
}

void
WallpaperBusinessLogic::portraitGConfChanged ()
{
}

void
WallpaperBusinessLogic::portraitHistoryChanged ()
{
}

QStringList
WallpaperBusinessLogic::history () const
{
    return QStringList();
}

bool
WallpaperBusinessLogic::hasEditedImage () const
{
    return true;
}

bool
WallpaperBusinessLogic::setWallpaper ()
{
    return true;
}

bool
WallpaperBusinessLogic::setWallpaper (
        QPixmap   &pixmap)
{
    Q_UNUSED (pixmap);
    return true;
}

QSize
WallpaperBusinessLogic::sceneSize () const
{
    return QSize (480, 854);
}

void
WallpaperBusinessLogic::startEdit (
        WallpaperDescriptor desc)
{
    m_EditedImage = desc;
}

void
WallpaperBusinessLogic::endEdit ()
{
    m_EditedImage = WallpaperDescriptor();
}

WallpaperDescriptor
WallpaperBusinessLogic::editedImage () const
{
    return m_EditedImage;
}

/******************************************************************************
 * Gallery connection.
 */
#ifdef HAVE_GALLERYCORE
void
WallpaperBusinessLogic::galleryActivated ()
{
}
#endif

#ifdef HAVE_GALLERYCORE
void
WallpaperBusinessLogic::onGridPageItemSelected (
        QUrl    url)
{
}
#endif

#ifdef HAVE_GALLERYCORE
void
WallpaperBusinessLogic::onGridPageCancelled ()
{
}
#endif

#ifdef HAVE_GALLERYCORE
void
WallpaperBusinessLogic::croppingDone (
        QImage croppedImage)
{
}
#endif

#ifdef HAVE_GALLERYCORE
void
WallpaperBusinessLogic::croppingCancelled ()
{
}
#endif

<commit_msg>Changes: build fix1<commit_after>/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of meegotouch-controlpanelapplets.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/
#include "wallpaperbusinesslogic.h"
#include "wallpaperdescriptor.h"

WallpaperBusinessLogic::WallpaperBusinessLogic (
        QObject *parent) :
    QObject (parent)
{
    Q_UNUSED (parent);
}

WallpaperBusinessLogic::~WallpaperBusinessLogic ()
{

}

void
WallpaperBusinessLogic::currentWallpaper (
        QString   &currentFilePath,
        QString   &originalFilePath)
{
    Q_UNUSED (currentFilePath);
    Q_UNUSED (originalFilePath);
}

void
WallpaperBusinessLogic::workerThreadFinishedSave ()
{
}

void
WallpaperBusinessLogic::gconfTimerSlot ()
{
}

void
WallpaperBusinessLogic::workerThreadFinishedLoad ()
{
}

void
WallpaperBusinessLogic::portraitGConfChanged ()
{
}

void
WallpaperBusinessLogic::portraitHistoryChanged ()
{
}

QStringList
WallpaperBusinessLogic::history () const
{
    return QStringList();
}

bool
WallpaperBusinessLogic::hasEditedImage () const
{
    return true;
}

bool
WallpaperBusinessLogic::setWallpaper ()
{
    return true;
}

bool
WallpaperBusinessLogic::setWallpaper (
        QPixmap   &pixmap)
{
    Q_UNUSED (pixmap);
    return true;
}

QSize
WallpaperBusinessLogic::sceneSize () const
{
    return QSize (480, 854);
}

void
WallpaperBusinessLogic::startEdit (
        WallpaperDescriptor desc)
{
    m_EditedImage = desc;
}

void
WallpaperBusinessLogic::endEdit ()
{
    m_EditedImage = WallpaperDescriptor();
}

WallpaperDescriptor
WallpaperBusinessLogic::editedImage () const
{
    return m_EditedImage;
}

/******************************************************************************
 * Gallery connection.
 */
#ifdef HAVE_GALLERYCORE
void
WallpaperBusinessLogic::galleryActivated ()
{
}

void
WallpaperBusinessLogic::onGridPageItemSelected (
        QUrl    url)
{
    Q_UNUSED (url);
}

void
WallpaperBusinessLogic::onGridPageCancelled ()
{
}

void
WallpaperBusinessLogic::croppingDone (
        QImage croppedImage)
{
    Q_UNUSED (croppedImage);
}

void
WallpaperBusinessLogic::croppingCancelled ()
{
}

void
WallpaperBusinessLogic::setProgressIndicator (bool busy)
{
    Q_UNUSED (busy);
}
#endif

<|endoftext|>


<commit_before>#include "mswin.h"
#include "systems.h"
#include "compiler.h"
#include "resources.h"
#include "vector.h"
#include "make_system.h"
#include "cramer.h"
#include "graphics.h"
#include <cstdint>

struct triangle_t
{
  float xyz [3] [4]; // Coordinates for a single triangle XYZ of the Moebius tiling.
  float abc [8] [4]; // Coefficients A, B, C for the generator T = AX + BY + CZ.
};

// The fundamental triangle of the tiling has angles
// A = pi/p, B = pi/q, C = pi/r and sides a, b, c.

// By the spherical cosine rule,
// cosa = (cosA + cosB * cosC) / (sinB * sinC),
// cosb = (cosB + cosC * cosA) / (sinC * sinA),
// cosc = (cosC + cosA * cosB) / (sinA * sinB).

// We assume p = 2; thus cosA = 0 and sinA = 1. Therefore,
// cosa = (cosB * cosC) / (sinB * sinC),
// cosb = cosB / sinC,
// cosc = cosC / sinB.

// Any triple (alpha, beta, gamma) identifies a point T relative to
// the spherical triangle XYZ, by the formula
// T = alpha * X + beta * Y + gamma * Z.
// For certain triples, replicating the point T in each triangle
// of the tiling gives the vertices of a uniform polyhedron:

// { 1, 0, 0, },             Point X.
// { 0, 1, 0, },             Point Y.
// { 0, 0, 1, },             Point Z.
// { 0, sinb, sinc, },       Intersection of YZ with the angular bisector of corner X.
// { sina, 0, sinc, },       Intersection of ZX with the angular bisector of corner Y.
// { sina, sinb, 0, },       Intersection of YZ with the angular bisector of corner Z.
// { sinA, sinB, sinC, },    Incentre (intersection of the three bisectors).
// { alpha, beta, gamma, },  Snub generator.

//     X1
//    /  \    Part of the tiling of the sphere, showing
//   Z0--Y0   the triangle X0-Y0-Z0 and the adjacent triangles.
//   |\  /|
//   | X0 |
//   |/  \|
//   Y1  Z1

// For the snub generator, the three points
//   TX = alpha * X1 + beta * Y0 + gamma * Z0
//   TY = alpha * X0 + beta * Y1 + gamma * Z0
//   TZ = alpha * X0 + beta * Y0 + gamma * Z1
// (see diagram) are the vertices of an equilateral spherical triangle.

ALIGNED16 triangle_t triangles [3] =
{
  // Tetrahedral, <2, 3, 3>.
  {
    { { +0x1.000000P+000f, +0x0.000000P+000f, +0x0.000000P+000f, 0.0f, },
      { +0x1.279a74P-001f, +0x1.a20bd8P-001f, +0x0.000000P+000f, 0.0f, },
      { +0x1.279a74P-001f, +0x0.000000P+000f, +0x1.a20bd8P-001f, 0.0f, },
    },
    { { +0x1.000000P+000f, +0x0.000000P+000f, +0x0.000000P+000f, 0.0f, }, // Octahedron
      { +0x0.000000P+000f, +0x1.000000P+000f, +0x0.000000P+000f, 0.0f, }, // Tetrahedron
      { +0x0.000000P+000f, +0x0.000000P+000f, +0x1.000000P+000f, 0.0f, }, // Tetrahedron
      { +0x0.000000P+000f, +0x1.3988e2P-001f, +0x1.3988e2P-001f, 0.0f, }, // Cuboctahedron
      { +0x1.34bf64P-001f, +0x0.000000P+000f, +0x1.0b621eP-001f, 0.0f, }, // Truncated tetrahedron
      { +0x1.34bf64P-001f, +0x1.0b621eP-001f, +0x0.000000P+000f, 0.0f, }, // Truncated tetrahedron
      { +0x1.c9f25cP-002f, +0x1.8c97f0P-002f, +0x1.8c97f0P-002f, 0.0f, }, // Truncated octahedron
      { +0x1.4cb7c0P-002f, +0x1.d2393eP-002f, +0x1.d2393eP-002f, 0.0f, }, // Icosahedron
      // { -0x1.605a90P+000f, +0x1.792eceP-001f, +0x1.792eceP-001f, 0.0f, }, // Great icosahedron
    },
  },
  // Octahedral, <2, 4, 3>.
  // Oriented so that two octahedral triangles cover one tetrahedral triangle.
  {
    { { +0x1.6a09e6P-001f, +0x1.000000P-001f, +0x1.000000P-001f, 0.0f, },
      { +0x1.000000P+000f, +0x0.000000P+000f, +0x0.000000P+000f, 0.0f, },
      { +0x1.279a74P-001f, +0x1.a20bd8P-001f, +0x0.000000P+000f, 0.0f, },
    },
    { { +0x1.000000P+000f, +0x0.000000P+000f, +0x0.000000P+000f, 0.0f, }, // Cuboctahedron
      { +0x0.000000P+000f, +0x1.000000P+000f, +0x0.000000P+000f, 0.0f, }, // Octahedron
      { +0x0.000000P+000f, +0x0.000000P+000f, +0x1.000000P+000f, 0.0f, }, // Cube
      { +0x0.000000P+000f, +0x1.02ca46P-001f, +0x1.3cf3aeP-001f, 0.0f, }, // Rhombicuboctahedron
      { +0x1.1fd4a6P-001f, +0x0.000000P+000f, +0x1.f28990P-002f, 0.0f, }, // Truncated cube
      { +0x1.43d136P-001f, +0x1.c9f25cP-002f, +0x0.000000P+000f, 0.0f, }, // Truncated octahedron
      { +0x1.b9d594P-002f, +0x1.386c8eP-002f, +0x1.7ea3c6P-002f, 0.0f, }, // Rhombitruncated cuboctahedron
      { +0x1.31816eP-002f, +0x1.8d5502P-002f, +0x1.bdd092P-002f, 0.0f, }, // Snub cube
    },
  },
  // Icosahedral, <2, 5, 3>.
  {
    { { +0x1.000000P+000f, +0x0.000000P+000f, +0x0.000000P+000f, 0.0f, },
      { +0x1.b38880P-001f, +0x1.0d2ca0P-001f, +0x0.000000P+000f, 0.0f, },
      { +0x1.de4bd6P-001f, +0x0.000000P+000f, +0x1.6d62c6P-002f, 0.0f, },
    },
    { { +0x1.000000P+000f, +0x0.000000P+000f, +0x0.000000P+000f, 0.0f, }, // Icosidodecahedron
      { +0x0.000000P+000f, +0x1.000000P+000f, +0x0.000000P+000f, 0.0f, }, // Icosahedron
      { +0x0.000000P+000f, +0x0.000000P+000f, +0x1.000000P+000f, 0.0f, }, // Dodecahedron
      { +0x0.000000P+000f, +0x1.b4242aP-002f, +0x1.414c80P-001f, 0.0f, }, // Rhombicosidodecahedron
      { +0x1.16fc4eP-001f, +0x0.000000P+000f, +0x1.e33798P-002f, 0.0f, }, // Truncated dodecahedron
      { +0x1.4e5014P-001f, +0x1.890220P-002f, +0x0.000000P+000f, 0.0f, }, // Truncated icosahedron
      { +0x1.b3be36P-002f, +0x1.001f92P-002f, +0x1.795d50P-002f, 0.0f, }, // Rhombitruncated icosidodecahedron
      { +0x1.287f1eP-002f, +0x1.52a52eP-002f, +0x1.b882c6P-002f, 0.0f, }, // Snub dodecahedron
    },
  },
};

// Turn a PQR triangle into a PRQ triangle.
void reflect (triangle_t & t)
{
  v4f x = load4f (t.xyz [0]);
  v4f y = load4f (t.xyz [1]);
  v4f z = load4f (t.xyz [2]);

  v4f n = cross (x, y);
  v4f d = (dot (n, z) / dot (n, n)) * n; // Component of z perpendicular to x and y.

  store4f (t.xyz [1], z - (d + d));
  store4f (t.xyz [2], y);

  for (unsigned k = 0; k != 8; ++ k) {
    v4f a = load4f (t.abc [k]);
    store4f (t.abc [k], _mm_shuffle_ps (a, a, SHUFFLE (0, 2, 1, 3)));
  }
}

template <unsigned K>
ALWAYS_INLINE inline void copy (const float (* from) [4], float (& to) [K] [4])
{
  for (unsigned k = 0; k != K; ++ k) {
    store4f (to [k], load4f (from [k]));
  }
}

void initialize_systems (float (& abc) [system_count] [8] [4],
                         float (& xyz) [system_count] [3] [4],
                         float (& xyzinvt) [system_count] [3] [4],
                         unsigned (& primitive_count) [system_count],
                         unsigned (& vao_ids) [system_count])
{
  ALIGNED16 float nodes [62] [4];
  std::uint8_t indices [60] [6];

  auto init = [&] (const triangle_t & t, system_select_t select, unsigned q, unsigned r) -> void
  {
    copy (t.xyz, xyz [select]);
    copy (t.abc, abc [select]);
    cramer::inverse_transpose (xyz [select], xyzinvt [select]);
    unsigned p = 2, N = 2 * p * q * r / (q * r + r * p + p * q - p * q * r);
    make_system (q, r, t.xyz, nodes, indices);
    vao_ids [select] = make_vao (N, nodes, indices);
    primitive_count [select] = N;
  };

  for (unsigned n = 0; n != 3; ++ n) {
    triangle_t & triangle = triangles [n];
    init (triangle, system_select_t (2 * n + 0), 3 + n, 3);
    reflect (triangle);
    init (triangle, system_select_t (2 * n + 1), 3, 3 + n);
  }
}
<commit_msg>systems.cpp: use std::memcpy; saves 64 bytes of code on x64, 36 bytes on x86.<commit_after>#include "mswin.h"
#include "systems.h"
#include "compiler.h"
#include "resources.h"
#include "vector.h"
#include "make_system.h"
#include "cramer.h"
#include "graphics.h"
#include <cstdint>
#include <cstring>

struct triangle_t
{
  float xyz [3] [4]; // Coordinates for a single triangle XYZ of the Moebius tiling.
  float abc [8] [4]; // Coefficients A, B, C for the generator T = AX + BY + CZ.
};

// The fundamental triangle of the tiling has angles
// A = pi/p, B = pi/q, C = pi/r and sides a, b, c.

// By the spherical cosine rule,
// cosa = (cosA + cosB * cosC) / (sinB * sinC),
// cosb = (cosB + cosC * cosA) / (sinC * sinA),
// cosc = (cosC + cosA * cosB) / (sinA * sinB).

// We assume p = 2; thus cosA = 0 and sinA = 1. Therefore,
// cosa = (cosB * cosC) / (sinB * sinC),
// cosb = cosB / sinC,
// cosc = cosC / sinB.

// Any triple (alpha, beta, gamma) identifies a point T relative to
// the spherical triangle XYZ, by the formula
// T = alpha * X + beta * Y + gamma * Z.
// For certain triples, replicating the point T in each triangle
// of the tiling gives the vertices of a uniform polyhedron:

// { 1, 0, 0, },             Point X.
// { 0, 1, 0, },             Point Y.
// { 0, 0, 1, },             Point Z.
// { 0, sinb, sinc, },       Intersection of YZ with the angular bisector of corner X.
// { sina, 0, sinc, },       Intersection of ZX with the angular bisector of corner Y.
// { sina, sinb, 0, },       Intersection of YZ with the angular bisector of corner Z.
// { sinA, sinB, sinC, },    Incentre (intersection of the three bisectors).
// { alpha, beta, gamma, },  Snub generator.

//     X1
//    /  \    Part of the tiling of the sphere, showing
//   Z0--Y0   the triangle X0-Y0-Z0 and the adjacent triangles.
//   |\  /|
//   | X0 |
//   |/  \|
//   Y1  Z1

// For the snub generator, the three points
//   TX = alpha * X1 + beta * Y0 + gamma * Z0
//   TY = alpha * X0 + beta * Y1 + gamma * Z0
//   TZ = alpha * X0 + beta * Y0 + gamma * Z1
// (see diagram) are the vertices of an equilateral spherical triangle.

ALIGNED16 triangle_t triangles [3] =
{
  // Tetrahedral, <2, 3, 3>.
  {
    { { +0x1.000000P+000f, +0x0.000000P+000f, +0x0.000000P+000f, 0.0f, },
      { +0x1.279a74P-001f, +0x1.a20bd8P-001f, +0x0.000000P+000f, 0.0f, },
      { +0x1.279a74P-001f, +0x0.000000P+000f, +0x1.a20bd8P-001f, 0.0f, },
    },
    { { +0x1.000000P+000f, +0x0.000000P+000f, +0x0.000000P+000f, 0.0f, }, // Octahedron
      { +0x0.000000P+000f, +0x1.000000P+000f, +0x0.000000P+000f, 0.0f, }, // Tetrahedron
      { +0x0.000000P+000f, +0x0.000000P+000f, +0x1.000000P+000f, 0.0f, }, // Tetrahedron
      { +0x0.000000P+000f, +0x1.3988e2P-001f, +0x1.3988e2P-001f, 0.0f, }, // Cuboctahedron
      { +0x1.34bf64P-001f, +0x0.000000P+000f, +0x1.0b621eP-001f, 0.0f, }, // Truncated tetrahedron
      { +0x1.34bf64P-001f, +0x1.0b621eP-001f, +0x0.000000P+000f, 0.0f, }, // Truncated tetrahedron
      { +0x1.c9f25cP-002f, +0x1.8c97f0P-002f, +0x1.8c97f0P-002f, 0.0f, }, // Truncated octahedron
      { +0x1.4cb7c0P-002f, +0x1.d2393eP-002f, +0x1.d2393eP-002f, 0.0f, }, // Icosahedron
      // { -0x1.605a90P+000f, +0x1.792eceP-001f, +0x1.792eceP-001f, 0.0f, }, // Great icosahedron
    },
  },
  // Octahedral, <2, 4, 3>.
  // Oriented so that two octahedral triangles cover one tetrahedral triangle.
  {
    { { +0x1.6a09e6P-001f, +0x1.000000P-001f, +0x1.000000P-001f, 0.0f, },
      { +0x1.000000P+000f, +0x0.000000P+000f, +0x0.000000P+000f, 0.0f, },
      { +0x1.279a74P-001f, +0x1.a20bd8P-001f, +0x0.000000P+000f, 0.0f, },
    },
    { { +0x1.000000P+000f, +0x0.000000P+000f, +0x0.000000P+000f, 0.0f, }, // Cuboctahedron
      { +0x0.000000P+000f, +0x1.000000P+000f, +0x0.000000P+000f, 0.0f, }, // Octahedron
      { +0x0.000000P+000f, +0x0.000000P+000f, +0x1.000000P+000f, 0.0f, }, // Cube
      { +0x0.000000P+000f, +0x1.02ca46P-001f, +0x1.3cf3aeP-001f, 0.0f, }, // Rhombicuboctahedron
      { +0x1.1fd4a6P-001f, +0x0.000000P+000f, +0x1.f28990P-002f, 0.0f, }, // Truncated cube
      { +0x1.43d136P-001f, +0x1.c9f25cP-002f, +0x0.000000P+000f, 0.0f, }, // Truncated octahedron
      { +0x1.b9d594P-002f, +0x1.386c8eP-002f, +0x1.7ea3c6P-002f, 0.0f, }, // Rhombitruncated cuboctahedron
      { +0x1.31816eP-002f, +0x1.8d5502P-002f, +0x1.bdd092P-002f, 0.0f, }, // Snub cube
    },
  },
  // Icosahedral, <2, 5, 3>.
  {
    { { +0x1.000000P+000f, +0x0.000000P+000f, +0x0.000000P+000f, 0.0f, },
      { +0x1.b38880P-001f, +0x1.0d2ca0P-001f, +0x0.000000P+000f, 0.0f, },
      { +0x1.de4bd6P-001f, +0x0.000000P+000f, +0x1.6d62c6P-002f, 0.0f, },
    },
    { { +0x1.000000P+000f, +0x0.000000P+000f, +0x0.000000P+000f, 0.0f, }, // Icosidodecahedron
      { +0x0.000000P+000f, +0x1.000000P+000f, +0x0.000000P+000f, 0.0f, }, // Icosahedron
      { +0x0.000000P+000f, +0x0.000000P+000f, +0x1.000000P+000f, 0.0f, }, // Dodecahedron
      { +0x0.000000P+000f, +0x1.b4242aP-002f, +0x1.414c80P-001f, 0.0f, }, // Rhombicosidodecahedron
      { +0x1.16fc4eP-001f, +0x0.000000P+000f, +0x1.e33798P-002f, 0.0f, }, // Truncated dodecahedron
      { +0x1.4e5014P-001f, +0x1.890220P-002f, +0x0.000000P+000f, 0.0f, }, // Truncated icosahedron
      { +0x1.b3be36P-002f, +0x1.001f92P-002f, +0x1.795d50P-002f, 0.0f, }, // Rhombitruncated icosidodecahedron
      { +0x1.287f1eP-002f, +0x1.52a52eP-002f, +0x1.b882c6P-002f, 0.0f, }, // Snub dodecahedron
    },
  },
};

// Turn a PQR triangle into a PRQ triangle.
void reflect (triangle_t & t)
{
  v4f x = load4f (t.xyz [0]);
  v4f y = load4f (t.xyz [1]);
  v4f z = load4f (t.xyz [2]);

  v4f n = cross (x, y);
  v4f d = (dot (n, z) / dot (n, n)) * n; // Component of z perpendicular to x and y.

  store4f (t.xyz [1], z - (d + d));
  store4f (t.xyz [2], y);

  for (unsigned k = 0; k != 8; ++ k) {
    v4f a = load4f (t.abc [k]);
    store4f (t.abc [k], _mm_shuffle_ps (a, a, SHUFFLE (0, 2, 1, 3)));
  }
}

template <unsigned K>
ALWAYS_INLINE inline void copy (const float (* from) [4], float (& to) [K] [4])
{
  std::memcpy (to, from, K * 4 * sizeof (float));
}

void initialize_systems (float (& abc) [system_count] [8] [4],
                         float (& xyz) [system_count] [3] [4],
                         float (& xyzinvt) [system_count] [3] [4],
                         unsigned (& primitive_count) [system_count],
                         unsigned (& vao_ids) [system_count])
{
  ALIGNED16 float nodes [62] [4];
  std::uint8_t indices [60] [6];

  auto init = [&] (const triangle_t & t, system_select_t select, unsigned q, unsigned r) -> void
  {
    copy (t.xyz, xyz [select]);
    copy (t.abc, abc [select]);
    cramer::inverse_transpose (xyz [select], xyzinvt [select]);
    unsigned p = 2, N = 2 * p * q * r / (q * r + r * p + p * q - p * q * r);
    make_system (q, r, t.xyz, nodes, indices);
    vao_ids [select] = make_vao (N, nodes, indices);
    primitive_count [select] = N;
  };

  for (unsigned n = 0; n != 3; ++ n) {
    triangle_t & triangle = triangles [n];
    init (triangle, system_select_t (2 * n + 0), 3 + n, 3);
    reflect (triangle);
    init (triangle, system_select_t (2 * n + 1), 3, 3 + n);
  }
}
<|endoftext|>


<commit_before>#pragma once
/**
	@file
	@brief succinct vector
	@author MITSUNARI Shigeo(@herumi)
	@license modified new BSD license
	http://opensource.org/licenses/BSD-3-Clause
*/
#include <assert.h>
#include <vector>
#include <cybozu/exception.hpp>
#include <cybozu/bit_operation.hpp>
#include <cybozu/select8.hpp>
#include <iosfwd>

#ifdef _MSC_VER
	#pragma warning(push)
	#pragma warning(disable : 4127)
#endif

namespace cybozu {

const uint64_t NotFound = ~uint64_t(0);

namespace sucvector_util {

inline uint32_t rank64(uint64_t v, size_t i)
{
    return cybozu::popcnt<uint64_t>(v & cybozu::makeBitMask64(i));
}

template<class T>
T getBlockNum(T x, T block)
{
	return (x + block - 1) / block;
}

inline uint32_t select64(uint64_t v, size_t r)
{
	assert(r <= 64);
	if (r > popcnt(v)) return 64;
	uint32_t pos = 0;
	uint32_t c = popcnt(uint32_t(v));
	if (r > c) {
		r -= c;
		pos = 32;
		v >>= 32;
	}
	c = popcnt<uint32_t>(uint16_t(v));
	if (r > c) {
		r -= c;
		pos += 16;
		v >>= 16;
	}
	c = popcnt<uint32_t>(uint8_t(v));
	if (r > c) {
		r -= c;
		pos += 8;
		v >>= 8;
	}
	if (r == 8 && uint8_t(v) == 0xff) return pos + 7;
	assert(r <= 8);
	c = cybozu::select8_util::select8(uint8_t(v), r);
	return pos + c;
}

union ci {
	uint64_t i;
	char c[8];
};

inline uint64_t load64bit(std::istream& is, const char *msg)
{
	ci ci;
	if (is.read(ci.c, sizeof(ci.c)) && is.gcount() == sizeof(ci.c)) {
		return ci.i;
	}
	throw cybozu::Exception("sucvector_util:load64bit") << msg;
}

inline void save64bit(std::ostream& os, uint64_t val, const char *msg)
{
	ci ci;
	ci.i = val;
	if (!os.write(ci.c, sizeof(ci.c))) {
		throw cybozu::Exception("sucvector_util:save64bit") << msg;
	}
}

template<class V>
void loadVec(V& v, std::istream& is, const char *msg)
{
	const uint64_t size64 = sucvector_util::load64bit(is, msg);
	assert(size64 <= ~size_t(0));
	const size_t size = size_t(size64);
	v.resize(size);
	if (is.read(cybozu::cast<char*>(&v[0]), size * sizeof(v[0]))) return;
	throw cybozu::Exception("sucvector_util:loadVec") << msg;
}

template<class V>
void saveVec(std::ostream& os, const V& v, const char *msg)
{
	save64bit(os, v.size(), msg);
	const size_t size = v.size() * sizeof(v[0]);
	if (os.write(cybozu::cast<const char*>(&v[0]), size) && os.flush()) return;
	throw cybozu::Exception("sucvector_util:saveVec") << msg;
}

} // cybozu::sucvector_util

/*
	extra memory
	(32 + 8 * 4) / 256 = 1/4 bit per bit for rank
*/
class SucVector {
	static const uint64_t maxBitLen = 40;
	static const uint64_t maxBitSize = uint64_t(1) << maxBitLen;
	struct B {
		uint64_t org[4];
		union {
			uint64_t a64;
			struct {
				uint32_t a;
				uint8_t b[4]; // b[0] is used for (b[0] << 32) | a
			} ab;
		};
	};
	uint64_t bitSize_;
	uint64_t numTbl_[2];
	std::vector<B> blk_;
	typedef std::vector<uint32_t> Uint32Vec;
	static const uint64_t posUnit = 1024;
	Uint32Vec selTbl_[2];

	template<int b>
	uint64_t rank_a(size_t i) const
	{
		assert(i < blk_.size());
		uint64_t ret = blk_[i].a64 & makeBitMask64(maxBitLen);
		if (!b) ret = i * uint64_t(256) - ret;
		return ret;
	}
	template<bool b>
	size_t get_b(size_t L, size_t i) const
	{
		assert(L < blk_.size());
		assert(0 < i && i < 4);
		size_t r = blk_[L].ab.b[i];
		if (!b) r = 64 * i - r;
		return r;
	}
	// call after blk_, numTbl_ are initialized
	void initSelTbl()
	{
		initSelTblSub<false>(selTbl_[0]);
		initSelTblSub<true>(selTbl_[1]);
	}
	template<bool b>
	void initSelTblSub(Uint32Vec& tbl)
	{
		const int tablePos = b ? 1 : 0;
		assert(numTbl_[tablePos] / posUnit < 0x7fffffff - 1);
		const size_t size = size_t(sucvector_util::getBlockNum(numTbl_[tablePos], posUnit) + 1);
		tbl.resize(size);
		uint32_t pos = 0;
		for (size_t i = 0; i < size - 1; i++) {
			uint64_t r = i * posUnit;
			assert(pos < 0x7fffffff);
			while (rank_a<b>(pos) < r) {
				pos++;
			}
			tbl[i] = pos;
		}
		tbl[size - 1] = (uint32_t)blk_.size();
	}
public:
	SucVector() : bitSize_(0) { numTbl_[0] = numTbl_[1] = 0; }
	/*
		data format(endian is depend on CPU:eg. little endian for x86/x64)
		bitSize  : 8
		numTbl_[0]  : 8
		numTbl_[1]  : 8
		blkSize  : 8
		blk data : blkSize * sizeof(B)
	*/
	void save(std::ostream& os) const
	{
		sucvector_util::save64bit(os, bitSize_, "bitSize");
		sucvector_util::save64bit(os, numTbl_[0], "num0");
		sucvector_util::save64bit(os, numTbl_[1], "num1");
		sucvector_util::saveVec(os, blk_, "blk");
	}
	void load(std::istream& is)
	{
		bitSize_ = sucvector_util::load64bit(is, "bitSize");
		numTbl_[0] = sucvector_util::load64bit(is, "num0");
		numTbl_[1] = sucvector_util::load64bit(is, "num1");
		sucvector_util::loadVec(blk_, is, "blk");
		initSelTbl();
	}
	/*
		@param blk [in] bit pattern block
		@param bitSize [in] bitSize ; blk size = (bitSize + 63) / 64
		@note max bitSize is 1<<40
	*/
	SucVector(const uint64_t *blk, uint64_t bitSize)
	{
		if (bitSize > maxBitSize) throw cybozu::Exception("SucVector:too large") << bitSize;
		init(blk, bitSize);
	}
	void init(const uint64_t *blk, uint64_t bitSize)
	{
		assert((bitSize + 63) / 64 <= ~size_t(0));
		bitSize_ = bitSize;
		const size_t blkNum = size_t((bitSize + 63) / 64);
		size_t tblNum = (blkNum + 3) / 4;
		blk_.resize(tblNum + 1);

		uint64_t av = 0;
		size_t pos = 0;
		for (size_t i = 0; i < tblNum; i++) {
			B& b = blk_[i];
			b.a64 = av % maxBitSize;
			uint32_t bv = 0;
			for (size_t j = 0; j < 4; j++) {
				uint64_t v = pos < blkNum ? blk[pos++] : 0;
				b.org[j] = v;
				uint32_t c = cybozu::popcnt(v);
				av += c;
				if (j > 0) {
					b.ab.b[j] = (uint8_t)bv;
				}
				bv += c;
			}
		}
		blk_[tblNum].a64 = av;
		numTbl_[0] = blkNum * 64 - av;
		numTbl_[1] = av;
		initSelTbl();
	}
	uint64_t rank1(uint64_t i) const
	{
		assert(i / 256 <= ~size_t(0));
		size_t q = size_t(i / 256);
		size_t r = size_t((i / 64) & 3);
		assert(q < blk_.size());
		const B& b = blk_[q];
		uint64_t ret = b.a64 % maxBitSize;
		if (r > 0) {
//			ret += b.ab.b[r];
			ret += uint8_t(b.a64 >> (32 + r * 8));
		}
		ret += cybozu::popcnt<uint64_t>(b.org[r] & cybozu::makeBitMask64(i & 63));
		return ret;
	}
	uint64_t size() const { return bitSize_; }
	uint64_t size(bool b) const { return numTbl_[b ? 1 : 0]; }
	uint64_t rank0(uint64_t i) const
	{
		return i - rank1(i);
	}
	uint64_t rank(bool b, uint64_t i) const
	{
		if (b) return rank1(i);
		return rank0(i);
	}
	bool get(uint64_t i) const
	{
		assert(i / 256 <= ~size_t(0));
		size_t q = size_t(i / 256);
		size_t r = size_t((i / 64) & 3);
		assert(q < blk_.size());
		const B& b = blk_[q];
		return (b.org[r] & (1ULL << (i & 63))) != 0;
	}
	uint64_t select0(uint64_t rank) const { return selectSub<false>(rank); }
	uint64_t select1(uint64_t rank) const { return selectSub<true>(rank); }
	uint64_t select(bool b, uint64_t rank) const
	{
		if (b) return select1(rank);
		return select0(rank);
	}

	bool getL(size_t* L, bool b, uint64_t rank) const
	{
		const int tablePos = b ? 1 : 0;
		if (rank >= numTbl_[tablePos]) return false;
		*L = selTbl_[tablePos][rank / posUnit];
		return true;
	}
	/*
		0123456789
		0100101101
		 ^  ^ ^^
		 0  1 23
		select(v, r) = min { i - 1 | rank(v, i) = r + 1 }
		select(3) = 7
	*/
	template<bool b>
	uint64_t selectSub(uint64_t rank) const
	{
		const int tablePos = b ? 1 : 0;
		if (rank >= numTbl_[tablePos]) return NotFound;
		size_t L = selTbl_[tablePos][rank / posUnit];
		size_t R = selTbl_[tablePos][rank / posUnit + 1];
		rank++;
		while (L < R) {
			size_t M = (L + R) / 2; // (R - L) / 2 + L;
			if (rank_a<b>(M) < rank) {
				L = M + 1;
			} else {
				R = M;
			}
		}
		if (L > 0) L--;
		rank -= rank_a<b>(L);

		size_t i = 0;
		while (i < 3) {
			size_t r = get_b<b>(L, i + 1);
			if (r >= rank) {
				break;
			}
			i++;
		}
		if (i > 0) {
			size_t r = get_b<b>(L, i);
			rank -= r;
		}
		uint64_t v = blk_[L].org[i];
		if (!b) v = ~v;
		assert(rank <= 64);
		uint64_t ret = cybozu::sucvector_util::select64(v, size_t(rank));
		ret += L * 256 + i * 64;
		return ret;
   	}
};

} // cybozu

#ifdef _WIN32
	#pragma warning(pop)
#endif
<commit_msg>decrease one size of selTbl_<commit_after>#pragma once
/**
	@file
	@brief succinct vector
	@author MITSUNARI Shigeo(@herumi)
	@license modified new BSD license
	http://opensource.org/licenses/BSD-3-Clause
*/
#include <assert.h>
#include <vector>
#include <cybozu/exception.hpp>
#include <cybozu/bit_operation.hpp>
#include <cybozu/select8.hpp>
#include <iosfwd>

#ifdef _MSC_VER
	#pragma warning(push)
	#pragma warning(disable : 4127)
#endif

namespace cybozu {

const uint64_t NotFound = ~uint64_t(0);

namespace sucvector_util {

inline uint32_t rank64(uint64_t v, size_t i)
{
    return cybozu::popcnt<uint64_t>(v & cybozu::makeBitMask64(i));
}

template<class T>
T getBlockNum(T x, T block)
{
	return (x + block - 1) / block;
}

inline uint32_t select64(uint64_t v, size_t r)
{
	assert(r <= 64);
	if (r > popcnt(v)) return 64;
	uint32_t pos = 0;
	uint32_t c = popcnt(uint32_t(v));
	if (r > c) {
		r -= c;
		pos = 32;
		v >>= 32;
	}
	c = popcnt<uint32_t>(uint16_t(v));
	if (r > c) {
		r -= c;
		pos += 16;
		v >>= 16;
	}
	c = popcnt<uint32_t>(uint8_t(v));
	if (r > c) {
		r -= c;
		pos += 8;
		v >>= 8;
	}
	if (r == 8 && uint8_t(v) == 0xff) return pos + 7;
	assert(r <= 8);
	c = cybozu::select8_util::select8(uint8_t(v), r);
	return pos + c;
}

union ci {
	uint64_t i;
	char c[8];
};

inline uint64_t load64bit(std::istream& is, const char *msg)
{
	ci ci;
	if (is.read(ci.c, sizeof(ci.c)) && is.gcount() == sizeof(ci.c)) {
		return ci.i;
	}
	throw cybozu::Exception("sucvector_util:load64bit") << msg;
}

inline void save64bit(std::ostream& os, uint64_t val, const char *msg)
{
	ci ci;
	ci.i = val;
	if (!os.write(ci.c, sizeof(ci.c))) {
		throw cybozu::Exception("sucvector_util:save64bit") << msg;
	}
}

template<class V>
void loadVec(V& v, std::istream& is, const char *msg)
{
	const uint64_t size64 = sucvector_util::load64bit(is, msg);
	assert(size64 <= ~size_t(0));
	const size_t size = size_t(size64);
	v.resize(size);
	if (is.read(cybozu::cast<char*>(&v[0]), size * sizeof(v[0]))) return;
	throw cybozu::Exception("sucvector_util:loadVec") << msg;
}

template<class V>
void saveVec(std::ostream& os, const V& v, const char *msg)
{
	save64bit(os, v.size(), msg);
	const size_t size = v.size() * sizeof(v[0]);
	if (os.write(cybozu::cast<const char*>(&v[0]), size) && os.flush()) return;
	throw cybozu::Exception("sucvector_util:saveVec") << msg;
}

} // cybozu::sucvector_util

/*
	extra memory
	(32 + 8 * 4) / 256 = 1/4 bit per bit for rank
*/
class SucVector {
	static const uint64_t maxBitLen = 32 + 8; // don't increase this value
	static const uint64_t maxBitSize = uint64_t(1) << maxBitLen;
	struct B {
		uint64_t org[4];
		union {
			uint64_t a64;
			struct {
				uint32_t a;
				uint8_t b[4]; // b[0] is used for (b[0] << 32) | a
			} ab;
		};
	};
	uint64_t bitSize_;
	uint64_t numTbl_[2];
	std::vector<B> blk_;
	typedef std::vector<uint32_t> Uint32Vec;
	static const uint64_t posUnit = 1024;
	Uint32Vec selTbl_[2];

	template<int b>
	uint64_t rank_a(size_t i) const
	{
		assert(i < blk_.size());
		uint64_t ret = blk_[i].a64 & makeBitMask64(maxBitLen);
		if (!b) ret = i * uint64_t(256) - ret;
		return ret;
	}
	template<bool b>
	size_t get_b(size_t L, size_t i) const
	{
		assert(L < blk_.size());
		assert(0 < i && i < 4);
		size_t r = blk_[L].ab.b[i];
		if (!b) r = 64 * i - r;
		return r;
	}
	// call after blk_, numTbl_ are initialized
	void initSelTbl()
	{
		initSelTblSub<false>(selTbl_[0]);
		initSelTblSub<true>(selTbl_[1]);
	}
	template<bool b>
	void initSelTblSub(Uint32Vec& tbl)
	{
		const int tablePos = b ? 1 : 0;
		assert(numTbl_[tablePos] / posUnit < 0x7fffffff - 1);
		const size_t size = size_t(sucvector_util::getBlockNum(numTbl_[tablePos], posUnit));
		tbl.resize(size);
		uint32_t pos = 0;
		for (size_t i = 0; i < size; i++) {
			uint64_t r = i * posUnit;
			assert(pos < 0x7fffffff);
			while (rank_a<b>(pos) < r) {
				pos++;
			}
			tbl[i] = pos;
		}
	}
public:
	SucVector() : bitSize_(0) { numTbl_[0] = numTbl_[1] = 0; }
	/*
		data format(endian is depend on CPU:eg. little endian for x86/x64)
		bitSize  : 8
		numTbl_[0]  : 8
		numTbl_[1]  : 8
		blkSize  : 8
		blk data : blkSize * sizeof(B)
	*/
	void save(std::ostream& os) const
	{
		sucvector_util::save64bit(os, bitSize_, "bitSize");
		sucvector_util::save64bit(os, numTbl_[0], "num0");
		sucvector_util::save64bit(os, numTbl_[1], "num1");
		sucvector_util::saveVec(os, blk_, "blk");
	}
	void load(std::istream& is)
	{
		bitSize_ = sucvector_util::load64bit(is, "bitSize");
		numTbl_[0] = sucvector_util::load64bit(is, "num0");
		numTbl_[1] = sucvector_util::load64bit(is, "num1");
		sucvector_util::loadVec(blk_, is, "blk");
		initSelTbl();
	}
	/*
		@param blk [in] bit pattern block
		@param bitSize [in] bitSize ; blk size = (bitSize + 63) / 64
	*/
	SucVector(const uint64_t *blk, uint64_t bitSize)
	{
		init(blk, bitSize);
	}
	void init(const uint64_t *blk, uint64_t bitSize)
	{
		if (bitSize > maxBitSize) throw cybozu::Exception("SucVector:too large") << bitSize;
		assert((bitSize + 63) / 64 <= ~size_t(0));
		bitSize_ = bitSize;
		const size_t blkNum = size_t((bitSize + 63) / 64);
		const size_t tblNum = (blkNum + 3) / 4; // tblNum <= 2^32
		blk_.resize(tblNum);

		uint64_t av = 0;
		size_t pos = 0;
		for (size_t i = 0; i < tblNum; i++) {
			B& b = blk_[i];
			b.a64 = av % maxBitSize;
			uint32_t bv = 0;
			for (size_t j = 0; j < 4; j++) {
				uint64_t v = pos < blkNum ? blk[pos++] : 0;
				b.org[j] = v;
				uint32_t c = cybozu::popcnt(v);
				av += c;
				if (j > 0) {
					b.ab.b[j] = (uint8_t)bv;
				}
				bv += c;
			}
		}
		numTbl_[0] = blkNum * 64 - av;
		numTbl_[1] = av;
		initSelTbl();
	}
	uint64_t rank1(uint64_t i) const
	{
		if (i >= bitSize_) return numTbl_[1];
		assert(i / 256 <= ~size_t(0));
		size_t q = size_t(i / 256);
		size_t r = size_t((i / 64) & 3);
		assert(q < blk_.size());
		const B& b = blk_[q];
		uint64_t ret = b.a64 % maxBitSize;
		if (r > 0) {
//			ret += b.ab.b[r];
			ret += uint8_t(b.a64 >> (32 + r * 8));
		}
		ret += cybozu::popcnt<uint64_t>(b.org[r] & cybozu::makeBitMask64(i & 63));
		return ret;
	}
	uint64_t size() const { return bitSize_; }
	uint64_t size(bool b) const { return numTbl_[b ? 1 : 0]; }
	uint64_t rank0(uint64_t i) const
	{
		return i - rank1(i);
	}
	uint64_t rank(bool b, uint64_t i) const
	{
		if (b) return rank1(i);
		return rank0(i);
	}
	bool get(uint64_t i) const
	{
		assert(i < bitSize_);
		size_t q = size_t(i / 256);
		size_t r = size_t((i / 64) & 3);
		assert(q < blk_.size());
		const B& b = blk_[q];
		return (b.org[r] & (1ULL << (i & 63))) != 0;
	}
	uint64_t select0(uint64_t rank) const { return selectSub<false>(rank); }
	uint64_t select1(uint64_t rank) const { return selectSub<true>(rank); }
	uint64_t select(bool b, uint64_t rank) const
	{
		if (b) return select1(rank);
		return select0(rank);
	}

	/*
		0123456789
		0100101101
		 ^  ^ ^^
		 0  1 23
		select(v, r) = min { i - 1 | rank(v, i) = r + 1 }
		select(3) = 7
	*/
	template<bool b>
	uint64_t selectSub(uint64_t rank) const
	{
		const int tablePos = b ? 1 : 0;
		if (rank >= numTbl_[tablePos]) return NotFound;
		const Uint32Vec& tbl = selTbl_[tablePos];
		assert(rank / posUnit < tbl.size());
		const size_t pos = (size_t)(rank / posUnit);
		size_t L = tbl[pos];
		size_t R = pos >= tbl.size() - 1 ? blk_.size() : tbl[pos + 1];
		rank++;
		while (L < R) {
			size_t M = (L + R) / 2; // (R - L) / 2 + L;
			if (rank_a<b>(M) < rank) {
				L = M + 1;
			} else {
				R = M;
			}
		}
		if (L > 0) L--;
		rank -= rank_a<b>(L);

		size_t i = 0;
		while (i < 3) {
			size_t r = get_b<b>(L, i + 1);
			if (r >= rank) {
				break;
			}
			i++;
		}
		if (i > 0) {
			size_t r = get_b<b>(L, i);
			rank -= r;
		}
		uint64_t v = blk_[L].org[i];
		if (!b) v = ~v;
		assert(rank <= 64);
		uint64_t ret = cybozu::sucvector_util::select64(v, size_t(rank));
		ret += L * 256 + i * 64;
		return ret;
   	}
};

} // cybozu

#ifdef _WIN32
	#pragma warning(pop)
#endif
<|endoftext|>


<commit_before>/*
 *    _aaaa,  _aa.  sa,  aaa              _aaaa,_  ac  .aa.   .aa.  .aa,  _a, sa
 *  .wWV!!!T  |Wm;  dQ[  $WF            _mWT!"?Y  ]QE  :Q#:   ]QW[  :WWk. ]Q[ dW
 * .jWf       :WW: .dQ[  dQ[           .mW(       )WE  :Q#:  .mSQh. :mWQa.]W[ dQ
 * |QW:       :Wm;  mQ[  dQ[           ]Qk        )Qmi_aQW:  <B:$Qc :WBWQ()W[ dQ
 * |W#:  .ww  ;WW;  dQ[  dQ[  .......  ]Qk        )QB?YYW#:  jf ]Qp.:mE)Qm]Q[ )W
 * +WQ;  :Wm  |Wm; .mQ[  dQ[ :qgggggga ]Qm.       ]WE  :Q# :=QasuQm;:Wk 3QQW[ )Y
 *  ]Wmi.:Wm  +$Q; .mW(  dQ[  !"!!"!!^ dQk,  ._   ]WE  :Q# :3D"!!$Qc.Wk -$WQ[
 *   "?????? ` "?!=m?!   ??'            -??????!  -?!  -?? -?'   "?"-?"  "??' "?
 *
 * Copyright (c) 2004 darkbits                              Js_./
 * Per Larsson a.k.a finalman                          _RqZ{a<^_aa
 * Olof Naessn a.k.a jansem/yakslem                _asww7!uY`>  )\a//
 *                                                 _Qhm`] _f "'c  1!5m
 * Visit: http://guichan.darkbits.org             )Qk<P ` _: :+' .'  "{[
 *                                               .)j(] .d_/ '-(  P .   S
 * License: (BSD)                                <Td/Z <fP"5(\"??"\a.  .L
 * Redistribution and use in source and          _dV>ws?a-?'      ._/L  #'
 * binary forms, with or without                 )4d[#7r, .   '     )d`)[
 * modification, are permitted provided         _Q-5'5W..j/?'   -?!\)cam'
 * that the following conditions are met:       j<<WP+k/);.        _W=j f
 * 1. Redistributions of source code must       .$%w\/]Q  . ."'  .  mj$
 *    retain the above copyright notice,        ]E.pYY(Q]>.   a     J@\
 *    this list of conditions and the           j(]1u<sE"L,. .   ./^ ]{a
 *    following disclaimer.                     4'_uomm\.  )L);-4     (3=
 * 2. Redistributions in binary form must        )_]X{Z('a_"a7'<a"a,  ]"[
 *    reproduce the above copyright notice,       #}<]m7`Za??4,P-"'7. ).m
 *    this list of conditions and the            ]d2e)Q(<Q(  ?94   b-  LQ/
 *    following disclaimer in the                <B!</]C)d_, '(<' .f. =C+m
 *    documentation and/or other materials      .Z!=J ]e []('-4f _ ) -.)m]'
 *    provided with the distribution.          .w[5]' _[ /.)_-"+?   _/ <W"
 * 3. Neither the name of darkbits nor the     :$we` _! + _/ .        j?
 *    names of its contributors may be used     =3)= _f  (_yQmWW$#(    "
 *    to endorse or promote products derived     -   W,  sQQQQmZQ#Wwa]..
 *    from this software without specific        (js, \[QQW$QWW#?!V"".
 *    prior written permission.                    ]y:.<\..          .
 *                                                 -]n w/ '         [.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT       )/ )/           !
 * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY         <  (; sac    ,    '
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING,               ]^ .-  %
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF            c <   r
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR            aga<  <La
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE          5%  )P'-3L
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR        _bQf` y`..)a
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,          ,J?4P'.P"_(\?d'.,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES               _Pa,)!f/<[]/  ?"
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT      _2-..:. .r+_,.. .
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     ?a.<%"'  " -'.a_ _,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION)                     ^
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef GCN_PLATFORM_HPP
#define GCN_PLATFORM_HPP

#if defined(_WIN32) && defined(GUICHAN_BUILD)
#define DECLSPEC _declspec(dllexport)
#endif

#ifndef DECLSPEC
#define DECLSPEC
#endif

#endif // end GCN_PLATFORM_HPP<commit_msg>Added missing new line<commit_after>/*
 *    _aaaa,  _aa.  sa,  aaa              _aaaa,_  ac  .aa.   .aa.  .aa,  _a, sa
 *  .wWV!!!T  |Wm;  dQ[  $WF            _mWT!"?Y  ]QE  :Q#:   ]QW[  :WWk. ]Q[ dW
 * .jWf       :WW: .dQ[  dQ[           .mW(       )WE  :Q#:  .mSQh. :mWQa.]W[ dQ
 * |QW:       :Wm;  mQ[  dQ[           ]Qk        )Qmi_aQW:  <B:$Qc :WBWQ()W[ dQ
 * |W#:  .ww  ;WW;  dQ[  dQ[  .......  ]Qk        )QB?YYW#:  jf ]Qp.:mE)Qm]Q[ )W
 * +WQ;  :Wm  |Wm; .mQ[  dQ[ :qgggggga ]Qm.       ]WE  :Q# :=QasuQm;:Wk 3QQW[ )Y
 *  ]Wmi.:Wm  +$Q; .mW(  dQ[  !"!!"!!^ dQk,  ._   ]WE  :Q# :3D"!!$Qc.Wk -$WQ[
 *   "?????? ` "?!=m?!   ??'            -??????!  -?!  -?? -?'   "?"-?"  "??' "?
 *
 * Copyright (c) 2004 darkbits                              Js_./
 * Per Larsson a.k.a finalman                          _RqZ{a<^_aa
 * Olof Naessn a.k.a jansem/yakslem                _asww7!uY`>  )\a//
 *                                                 _Qhm`] _f "'c  1!5m
 * Visit: http://guichan.darkbits.org             )Qk<P ` _: :+' .'  "{[
 *                                               .)j(] .d_/ '-(  P .   S
 * License: (BSD)                                <Td/Z <fP"5(\"??"\a.  .L
 * Redistribution and use in source and          _dV>ws?a-?'      ._/L  #'
 * binary forms, with or without                 )4d[#7r, .   '     )d`)[
 * modification, are permitted provided         _Q-5'5W..j/?'   -?!\)cam'
 * that the following conditions are met:       j<<WP+k/);.        _W=j f
 * 1. Redistributions of source code must       .$%w\/]Q  . ."'  .  mj$
 *    retain the above copyright notice,        ]E.pYY(Q]>.   a     J@\
 *    this list of conditions and the           j(]1u<sE"L,. .   ./^ ]{a
 *    following disclaimer.                     4'_uomm\.  )L);-4     (3=
 * 2. Redistributions in binary form must        )_]X{Z('a_"a7'<a"a,  ]"[
 *    reproduce the above copyright notice,       #}<]m7`Za??4,P-"'7. ).m
 *    this list of conditions and the            ]d2e)Q(<Q(  ?94   b-  LQ/
 *    following disclaimer in the                <B!</]C)d_, '(<' .f. =C+m
 *    documentation and/or other materials      .Z!=J ]e []('-4f _ ) -.)m]'
 *    provided with the distribution.          .w[5]' _[ /.)_-"+?   _/ <W"
 * 3. Neither the name of darkbits nor the     :$we` _! + _/ .        j?
 *    names of its contributors may be used     =3)= _f  (_yQmWW$#(    "
 *    to endorse or promote products derived     -   W,  sQQQQmZQ#Wwa]..
 *    from this software without specific        (js, \[QQW$QWW#?!V"".
 *    prior written permission.                    ]y:.<\..          .
 *                                                 -]n w/ '         [.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT       )/ )/           !
 * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY         <  (; sac    ,    '
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING,               ]^ .-  %
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF            c <   r
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR            aga<  <La
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE          5%  )P'-3L
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR        _bQf` y`..)a
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,          ,J?4P'.P"_(\?d'.,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES               _Pa,)!f/<[]/  ?"
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT      _2-..:. .r+_,.. .
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     ?a.<%"'  " -'.a_ _,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION)                     ^
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef GCN_PLATFORM_HPP
#define GCN_PLATFORM_HPP

#if defined(_WIN32) && defined(GUICHAN_BUILD)
#define DECLSPEC _declspec(dllexport)
#endif

#ifndef DECLSPEC
#define DECLSPEC
#endif

#endif // end GCN_PLATFORM_HPP
<|endoftext|>


<commit_before>#pragma once

#ifndef SIPL_IMPROC_HISTOGRAM_HPP
#define SIPL_IMPROC_HISTOGRAM_HPP

#include <limits>
#include <cstdlib>
#include "matrix/Vector"
#include "improc/Improc.hpp"

namespace sipl
{

// Calculate histogram of mat
template <typename Dtype>
VectorX<uint32_t> histogram(const MatrixX<Dtype>& mat)
{
    const auto max = std::numeric_limits<Dtype>::max();
    VectorX<uint32_t> hist(max + 1, 0);
    for (int32_t i = 0; i < mat.size(); ++i) {
        hist[mat[i]]++;
    }
    return hist;
}

// Calculate histogram cdf
template <typename Dtype>
VectorX<uint32_t> histogram_cdf(const MatrixX<Dtype>& mat)
{
    const auto hist = histogram(mat);

    uint32_t sum = 0;
    VectorX<uint32_t> cdf_hist(hist.size(), 0);
    for (int32_t i = 0; i < cdf_hist.size(); ++i) {
        sum += hist[i];
        cdf_hist[i] = sum;
    }

    return cdf_hist;
}

template <typename Dtype>
MatrixX<Dtype> equalize_hist(const MatrixX<Dtype>& mat)
{
    // 1. Compute the equalized histogram
    const auto cdf_hist = histogram_cdf(mat);

    // Find first nonzero cdf hist value that will be cdf_min
    uint32_t cdf_min = 0;
    for (int32_t i = 0; i < cdf_hist.size(); ++i) {
        if (cdf_hist[i] > 0) {
            cdf_min = cdf_hist[i];
            break;
        }
    }
    constexpr int32_t max = std::numeric_limits<uint8_t>::max();
    VectorX<uint32_t> equalized_hist(cdf_hist.size());
    for (int32_t i = 0; i < equalized_hist.size(); ++i) {
        if (cdf_hist[i] == 0) {
            equalized_hist[i] = 0;
        } else {
            equalized_hist[i] = uint32_t(std::nearbyint(
                ((cdf_hist[i] - cdf_min) / (double(mat.size()) - cdf_min)) *
                max));
        }
    }

    // 2. Compute the new equalized histogram image via lookup
    MatrixX<uint8_t> equalized_hist_img(mat.dims);
    for (int32_t i = 0; i < mat.size(); ++i) {
        equalized_hist_img[i] = equalized_hist[mat[i]];
    }

    return equalized_hist_img;
}

// Convert incoming histogram to an actual image
// For now, only writes out 256x256 histogram image
MatrixX<uint8_t> hist_to_img(const VectorX<uint32_t>& hist)
{
    constexpr int32_t max = int32_t(std::numeric_limits<uint8_t>::max());
    constexpr int32_t max_size = max + 1;

    // Make a rotated histogram by drawing each row as the number of entries in
    // that bin
    MatrixX<uint8_t> hist_plot(max_size, max_size);
    for (int32_t j = 0; j < hist_plot.dims[1]; ++j) {
        const int32_t count =
            std::round(hist[j] * max_size / double(hist.max()));
        for (int32_t i = hist_plot.dims[0] - 1; i >= 0; --i) {
            hist_plot(i, j) = (i > count ? max : 0);
        }
    }

    return hist_plot;
}

// Histogram match - return a new matrix (doesn't modify old image)
template <typename Dtype>
MatrixX<Dtype> histogram_match(const MatrixX<Dtype>& target,
                               const MatrixX<Dtype>& source)
{
    // Calculate CDF for both images
    const auto target_cdf = histogram_cdf(target);
    const auto source_cdf = histogram_cdf(source);
    const auto target_cdf_norm =
        target_cdf / double(target_cdf[target_cdf.size() - 1]);
    const auto source_cdf_norm =
        source_cdf / double(source_cdf[source_cdf.size() - 1]);

    // Build lookup table for matching histograms
    // Note: due to grading requirements of picking the lowest intensity gray
    // level for instances of multimapped values from source CDF to target CDF,
    // iterate backwards so we pick the earlier gray level and use <= min_diff
    constexpr int32_t max = int32_t(std::numeric_limits<uint8_t>::max() + 1);
    VectorX<Dtype> lut(max, 0);
    for (int32_t j = 0; j < lut.size(); ++j) {
        int32_t min_diff = std::numeric_limits<int32_t>::max();
        for (int32_t i = target_cdf.size() - 1; i >= 0; --i) {
            const int32_t res = std::abs(int32_t(
                std::round((target_cdf_norm[i] - source_cdf_norm[j]) * max)));
            if (res <= min_diff) {
                min_diff = res;
                lut[j] = i;
            }
        }
    }
    std::cout << lut << std::endl;

    // Alter the histogram of the source image to match target image via the LUT
    MatrixX<Dtype> modified_source(source.dims);
    for (int32_t i = 0; i < source.dims[0]; ++i) {
        for (int32_t j = 0; j < source.dims[1]; ++j) {
            modified_source(i, j) = lut[source(i, j)];
        }
    }

    return modified_source;
}
}

#endif
<commit_msg>Add relevant includes<commit_after>#pragma once

#ifndef SIPL_IMPROC_HISTOGRAM_HPP
#define SIPL_IMPROC_HISTOGRAM_HPP

#include <limits>
#include <cstdlib>
#include <iostream>
#include "matrix/Matrix"
#include "matrix/Vector"
#include "improc/Improc.hpp"

namespace sipl
{

// Calculate histogram of mat
template <typename Dtype>
VectorX<uint32_t> histogram(const MatrixX<Dtype>& mat)
{
    const auto max = std::numeric_limits<Dtype>::max();
    VectorX<uint32_t> hist(max + 1, 0);
    for (int32_t i = 0; i < mat.size(); ++i) {
        hist[mat[i]]++;
    }
    return hist;
}

// Calculate histogram cdf
template <typename Dtype>
VectorX<uint32_t> histogram_cdf(const MatrixX<Dtype>& mat)
{
    const auto hist = histogram(mat);

    uint32_t sum = 0;
    VectorX<uint32_t> cdf_hist(hist.size(), 0);
    for (int32_t i = 0; i < cdf_hist.size(); ++i) {
        sum += hist[i];
        cdf_hist[i] = sum;
    }

    return cdf_hist;
}

template <typename Dtype>
MatrixX<Dtype> equalize_hist(const MatrixX<Dtype>& mat)
{
    // 1. Compute the equalized histogram
    const auto cdf_hist = histogram_cdf(mat);

    // Find first nonzero cdf hist value that will be cdf_min
    uint32_t cdf_min = 0;
    for (int32_t i = 0; i < cdf_hist.size(); ++i) {
        if (cdf_hist[i] > 0) {
            cdf_min = cdf_hist[i];
            break;
        }
    }
    constexpr int32_t max = std::numeric_limits<uint8_t>::max();
    VectorX<uint32_t> equalized_hist(cdf_hist.size());
    for (int32_t i = 0; i < equalized_hist.size(); ++i) {
        if (cdf_hist[i] == 0) {
            equalized_hist[i] = 0;
        } else {
            equalized_hist[i] = uint32_t(std::nearbyint(
                ((cdf_hist[i] - cdf_min) / (double(mat.size()) - cdf_min)) *
                max));
        }
    }

    // 2. Compute the new equalized histogram image via lookup
    MatrixX<uint8_t> equalized_hist_img(mat.dims);
    for (int32_t i = 0; i < mat.size(); ++i) {
        equalized_hist_img[i] = equalized_hist[mat[i]];
    }

    return equalized_hist_img;
}

// Convert incoming histogram to an actual image
// For now, only writes out 256x256 histogram image
MatrixX<uint8_t> hist_to_img(const VectorX<uint32_t>& hist)
{
    constexpr int32_t max = int32_t(std::numeric_limits<uint8_t>::max());
    constexpr int32_t max_size = max + 1;

    // Make a rotated histogram by drawing each row as the number of entries in
    // that bin
    MatrixX<uint8_t> hist_plot(max_size, max_size);
    for (int32_t j = 0; j < hist_plot.dims[1]; ++j) {
        const int32_t count =
            std::round(hist[j] * max_size / double(hist.max()));
        for (int32_t i = hist_plot.dims[0] - 1; i >= 0; --i) {
            hist_plot(i, j) = (i > count ? max : 0);
        }
    }

    return hist_plot;
}

// Histogram match - return a new matrix (doesn't modify old image)
template <typename Dtype>
MatrixX<Dtype> histogram_match(const MatrixX<Dtype>& target,
                               const MatrixX<Dtype>& source)
{
    // Calculate CDF for both images
    const auto target_cdf = histogram_cdf(target);
    const auto source_cdf = histogram_cdf(source);
    const auto target_cdf_norm =
        target_cdf / double(target_cdf[target_cdf.size() - 1]);
    const auto source_cdf_norm =
        source_cdf / double(source_cdf[source_cdf.size() - 1]);

    // Build lookup table for matching histograms
    // Note: due to grading requirements of picking the lowest intensity gray
    // level for instances of multimapped values from source CDF to target CDF,
    // iterate backwards so we pick the earlier gray level and use <= min_diff
    constexpr int32_t max = int32_t(std::numeric_limits<uint8_t>::max() + 1);
    VectorX<Dtype> lut(max, 0);
    for (int32_t j = 0; j < lut.size(); ++j) {
        int32_t min_diff = std::numeric_limits<int32_t>::max();
        for (int32_t i = target_cdf.size() - 1; i >= 0; --i) {
            const int32_t res = std::abs(int32_t(
                std::round((target_cdf_norm[i] - source_cdf_norm[j]) * max)));
            if (res <= min_diff) {
                min_diff = res;
                lut[j] = i;
            }
        }
    }
    std::cout << lut << std::endl;

    // Alter the histogram of the source image to match target image via the LUT
    MatrixX<Dtype> modified_source(source.dims);
    for (int32_t i = 0; i < source.dims[0]; ++i) {
        for (int32_t j = 0; j < source.dims[1]; ++j) {
            modified_source(i, j) = lut[source(i, j)];
        }
    }

    return modified_source;
}
}

#endif
<|endoftext|>


<commit_before>#include <boost/program_options.hpp>
#include <string>
#include <math.h>
#include <proj_api.h>
#include "elevation.hxx"
#include "ObjWriter.hxx"
#include "Delaunay.h"

using namespace std;
using namespace osmwave;

static projPJ wgs84 = pj_init_plus("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs");

// Note: in place addition
static void vecAdd(XYZ& a, const XYZ& b) {
    a.x += b.x;
    a.y += b.y;
    a.z += b.z;
}

static void vecSub(const XYZ& a, const XYZ& b, XYZ& result) {
    result.x = a.x - b.x;
    result.y = a.y - b.y;
    result.z = a.z - b.z;
}

static void triangleNormal(const XYZ* coords, const ITRIANGLE& tri, XYZ& normal) {
    XYZ u;
    XYZ v;

    vecSub(coords[tri.p2], coords[tri.p1], u);
    vecSub(coords[tri.p3], coords[tri.p1], v);

    normal.x = u.y*v.z - u.z*v.y;
    normal.y = u.z*v.x - u.x*v.z;
    normal.z = u.x*v.y - u.y*v.x;

    double l = sqrt(normal.x*normal.x+normal.y*normal.y+normal.z*normal.z);

    normal.x = normal.x / l;
    normal.y = normal.y / l;
    normal.z = normal.z / l;
}

static double findNearHeight(int rows, int cols, int index, int dx, int dy, XYZ* verts) {
    int s = index;
    do {
        s += dx * rows + dy;
    } while (std::isnan(verts[s].z));

    return verts[s].z;
}

static int thin(int rows, int cols, XYZ* verts, double tolerance) {
    int index = 0;
    int nonEmpty = 0;

    for (int i = 1; i < cols - 1; i++) {
        for (int j = 1; j < rows - 1; j++) {
            if (!std::isnan(verts[index].z)) {
                double e1 = verts[index].z;
                double e2 = findNearHeight(rows, cols, index, 1, -1, verts);
                double e3 = findNearHeight(rows, cols, index, 1, 0, verts);
                double e4 = findNearHeight(rows, cols, index, 1, 1, verts);
                double d2 = abs(e1 - e2);
                double d3 = abs(e1 - e3);
                double d4 = abs(e1 - e4);

                if (d2 <= tolerance &&
                    d3 <= tolerance &&
                    d4 <= tolerance) {
                    verts[index].z = NAN;
                } else {
                    nonEmpty++;
                }
            }

            index++;
        }
    }

    return nonEmpty;
}

void terrain_to_obj(const std::string& elevationPath, const std::string& projDef, double x1, double y1, double x2, double y2) {
    Elevation elevation(floor(y1), floor(x1), ceil(y2), ceil(x2), elevationPath);
    ObjWriter writer(cout);
    projPJ proj = pj_init_plus(projDef.c_str());
    double step = 1.0 / 3600;
    int rows = (int)floor((y2 - y1) / step + 1);
    int cols = (int)floor((x2 - x1) / step + 1);
    double bounds[] = {x1*DEG_TO_RAD, y1*DEG_TO_RAD, x2*DEG_TO_RAD, y2*DEG_TO_RAD};

    pj_transform(wgs84, proj, 2, 2, (double*)&bounds, (double*)&bounds + 1, nullptr);

    cerr << "rows: " << rows << ", cols: " << cols << endl;
    cerr << "bounds: " << bounds[0] << ", " << bounds[1] << " - " << bounds[2] << ", " << bounds[3] << endl;

    cerr << "Calculating vertices..." << endl;
    XYZ* coords = new XYZ[rows * cols + 3];
    XYZ* normals = new XYZ[rows * cols];

    int i = 0;
    // Having columns as outer loop ensures x will be growing,
    // which is a requirement for the triangulation algorithm,
    // as long as projection is west to east.
    for (int c = 0; c < cols; c++) {
        double x = bounds[0] + (bounds[2] - bounds[0]) * c / cols;
        for (int r = 0; r < rows; r++) {
            double y = bounds[1] + (bounds[3] - bounds[1]) * r / rows;
            double ll[2] = {x, y};
            pj_transform(proj, wgs84, 1, 2, (double*)&ll, (double*)&ll + 1, nullptr);

            XYZ& coord = coords[i++];
            coord.x = x;
            coord.y = y;
            coord.z = elevation.elevation(ll[1]*RAD_TO_DEG, ll[0]*RAD_TO_DEG);

            //cerr << (ll[0] * RAD_TO_DEG) << ", " << (ll[1] * RAD_TO_DEG) << " (" << coord.x << ", " << coord.y << "): " << coord.z << endl;
        }
    }

    cerr << "Thinning..." << endl;
    int startCount = rows * cols,
        lastCount = 0,
        count = -1;
    while (lastCount != count) {
        lastCount = count;
        count = thin(rows, cols, coords, 2);
    }

    int j = 0;
    for (int i = 0; i < rows * cols; i++) {
        if (!std::isnan(coords[i].z)) {
            coords[j++] = coords[i];
        }
    }
    cerr << "Thinned to " << j << " vertices" << endl;

    cerr << "Triangulating..." << endl;
    ITRIANGLE *tris = new ITRIANGLE[3 * rows * cols];
    int numTriangles;
    Triangulate(j, coords, tris, numTriangles);
    cerr << numTriangles << " triangles" << endl;

    memset((void*)normals, 0, sizeof(XYZ) * j);
    for (int i = 0; i < numTriangles; i++) {
        XYZ normal;
        triangleNormal(coords, tris[i], normal);
        vecAdd(normals[tris[i].p1], normal);
        vecAdd(normals[tris[i].p2], normal);
        vecAdd(normals[tris[i].p3], normal);
    }

    writer.checkpoint();
    for (int i = 0; i < j; i++) {
        writer.vertex(coords[i].x, coords[i].z, coords[i].y, normals[i].x, normals[i].y, normals[i].z);
    }

    for (int i = 0; i < numTriangles; i++) {
        writer.beginFace();
        writer << tris[i].p1 << tris[i].p2 << tris[i].p3;
        writer.endFace();
    }

    delete coords;
    delete normals;
    delete tris;
}

int main(int argc, char* argv[]) {
    namespace po = boost::program_options;
    po::options_description desc("Options");
    desc.add_options()
        ("elevation_dir,e", po::value<string>()->required(), "Set directory containing elevation data")
        ("proj,p", po::value<string>(), "Projection definition")
        ("x1", po::value<double>()->required(), "X1")
        ("y1", po::value<double>()->required(), "Y1")
        ("x2", po::value<double>()->required(), "X2")
        ("y2", po::value<double>()->required(), "Y2");
    po::positional_options_description positionOptions;
    positionOptions.add("x1", 1);
    positionOptions.add("y1", 1);
    positionOptions.add("x2", 1);
    positionOptions.add("y2", 1);

    po::variables_map vm;
    try {
        po::store(po::command_line_parser(argc, argv)
            .options(desc)
            .positional(positionOptions)
            .run(), vm);

        po::notify(vm);
    } catch (po::error& e) {
        cerr << "Error " << e.what() << endl << endl;
        cerr << desc << endl;
        return 1;
    }

    const string& elevPath(vm["elevation_dir"].as<string>());
    const string* projDef = nullptr;
    const double x1 = vm["x1"].as<double>();
    const double y1 = vm["y1"].as<double>();
    const double x2 = vm["x2"].as<double>();
    const double y2 = vm["y2"].as<double>();

    if (vm.count("proj")) {
        projDef = &vm["proj"].as<string>();
    } else {
        ostringstream stream;
        stream << "+proj=tmerc +lat_0=" << ((y1 + y2) / 2) << " +lon_0=" << ((x1 + x2) / 2) << " +k=1.000000 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs";
        projDef = new string(stream.str());
    }

    terrain_to_obj(elevPath, *projDef, x1, y1, x2, y2);

    return 0;
}

<commit_msg>Fix axis order<commit_after>#include <boost/program_options.hpp>
#include <string>
#include <math.h>
#include <proj_api.h>
#include "elevation.hxx"
#include "ObjWriter.hxx"
#include "Delaunay.h"

using namespace std;
using namespace osmwave;

static projPJ wgs84 = pj_init_plus("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs");

// Note: in place addition
static void vecAdd(XYZ& a, const XYZ& b) {
    a.x += b.x;
    a.y += b.y;
    a.z += b.z;
}

static void vecSub(const XYZ& a, const XYZ& b, XYZ& result) {
    result.x = a.x - b.x;
    result.y = a.y - b.y;
    result.z = a.z - b.z;
}

static void triangleNormal(const XYZ* coords, const ITRIANGLE& tri, XYZ& normal) {
    XYZ u;
    XYZ v;

    vecSub(coords[tri.p2], coords[tri.p1], u);
    vecSub(coords[tri.p3], coords[tri.p1], v);

    normal.x = u.y*v.z - u.z*v.y;
    normal.y = u.z*v.x - u.x*v.z;
    normal.z = u.x*v.y - u.y*v.x;

    double l = sqrt(normal.x*normal.x+normal.y*normal.y+normal.z*normal.z);

    normal.x = normal.x / l;
    normal.y = normal.y / l;
    normal.z = normal.z / l;
}

static double findNearHeight(int rows, int cols, int index, int dx, int dy, XYZ* verts) {
    int s = index;
    do {
        s += dx * rows + dy;
    } while (std::isnan(verts[s].z));

    return verts[s].z;
}

static int thin(int rows, int cols, XYZ* verts, double tolerance) {
    int index = 0;
    int nonEmpty = 0;

    for (int i = 1; i < cols - 1; i++) {
        for (int j = 1; j < rows - 1; j++) {
            if (!std::isnan(verts[index].z)) {
                double e1 = verts[index].z;
                double e2 = findNearHeight(rows, cols, index, 1, -1, verts);
                double e3 = findNearHeight(rows, cols, index, 1, 0, verts);
                double e4 = findNearHeight(rows, cols, index, 1, 1, verts);
                double d2 = abs(e1 - e2);
                double d3 = abs(e1 - e3);
                double d4 = abs(e1 - e4);

                if (d2 <= tolerance &&
                    d3 <= tolerance &&
                    d4 <= tolerance) {
                    verts[index].z = NAN;
                } else {
                    nonEmpty++;
                }
            }

            index++;
        }
    }

    return nonEmpty;
}

void terrain_to_obj(const std::string& elevationPath, const std::string& projDef, double x1, double y1, double x2, double y2) {
    Elevation elevation(floor(y1), floor(x1), ceil(y2), ceil(x2), elevationPath);
    ObjWriter writer(cout);
    projPJ proj = pj_init_plus(projDef.c_str());
    double step = 1.0 / 3600;
    int rows = (int)floor((y2 - y1) / step + 1);
    int cols = (int)floor((x2 - x1) / step + 1);
    double bounds[] = {x1*DEG_TO_RAD, y1*DEG_TO_RAD, x2*DEG_TO_RAD, y2*DEG_TO_RAD};

    pj_transform(wgs84, proj, 2, 2, (double*)&bounds, (double*)&bounds + 1, nullptr);

    cerr << "rows: " << rows << ", cols: " << cols << endl;
    cerr << "bounds: " << bounds[0] << ", " << bounds[1] << " - " << bounds[2] << ", " << bounds[3] << endl;

    cerr << "Calculating vertices..." << endl;
    XYZ* coords = new XYZ[rows * cols + 3];
    XYZ* normals = new XYZ[rows * cols];

    int i = 0;
    // Having columns as outer loop ensures x will be growing,
    // which is a requirement for the triangulation algorithm,
    // as long as projection is west to east.
    for (int c = 0; c < cols; c++) {
        double x = bounds[0] + (bounds[2] - bounds[0]) * c / cols;
        for (int r = 0; r < rows; r++) {
            double y = bounds[1] + (bounds[3] - bounds[1]) * r / rows;
            double ll[2] = {x, y};
            pj_transform(proj, wgs84, 1, 2, (double*)&ll, (double*)&ll + 1, nullptr);

            XYZ& coord = coords[i++];
            coord.x = x;
            coord.y = y;
            coord.z = elevation.elevation(ll[1]*RAD_TO_DEG, ll[0]*RAD_TO_DEG);

            //cerr << (ll[0] * RAD_TO_DEG) << ", " << (ll[1] * RAD_TO_DEG) << " (" << coord.x << ", " << coord.y << "): " << coord.z << endl;
        }
    }

    int startCount = rows * cols,
        lastCount = 0,
        count = -1;
    cerr << "Thinning " << startCount << " vertices..." << endl;
    while (lastCount != count) {
        lastCount = count;
        count = thin(rows, cols, coords, 2);
    }

    int j = 0;
    for (int i = 0; i < rows * cols; i++) {
        if (!std::isnan(coords[i].z)) {
            coords[j++] = coords[i];
        }
    }
    cerr << "Thinned to " << j << " vertices" << endl;

    cerr << "Triangulating..." << endl;
    ITRIANGLE *tris = new ITRIANGLE[3 * rows * cols];
    int numTriangles;
    Triangulate(j, coords, tris, numTriangles);
    cerr << numTriangles << " triangles" << endl;

    memset((void*)normals, 0, sizeof(XYZ) * j);
    for (int i = 0; i < numTriangles; i++) {
        XYZ normal;
        triangleNormal(coords, tris[i], normal);
        vecAdd(normals[tris[i].p1], normal);
        vecAdd(normals[tris[i].p2], normal);
        vecAdd(normals[tris[i].p3], normal);
    }

    writer.checkpoint();
    for (int i = 0; i < j; i++) {
        writer.vertex(coords[i].y, coords[i].z, coords[i].x, normals[i].y, normals[i].z, normals[i].x);
    }

    for (int i = 0; i < numTriangles; i++) {
        writer.beginFace();
        writer << tris[i].p1 << tris[i].p2 << tris[i].p3;
        writer.endFace();
    }

    delete coords;
    delete normals;
    delete tris;
}

int main(int argc, char* argv[]) {
    namespace po = boost::program_options;
    po::options_description desc("Options");
    desc.add_options()
        ("elevation_dir,e", po::value<string>()->required(), "Set directory containing elevation data")
        ("proj,p", po::value<string>(), "Projection definition")
        ("x1", po::value<double>()->required(), "X1")
        ("y1", po::value<double>()->required(), "Y1")
        ("x2", po::value<double>()->required(), "X2")
        ("y2", po::value<double>()->required(), "Y2");
    po::positional_options_description positionOptions;
    positionOptions.add("x1", 1);
    positionOptions.add("y1", 1);
    positionOptions.add("x2", 1);
    positionOptions.add("y2", 1);

    po::variables_map vm;
    try {
        po::store(po::command_line_parser(argc, argv)
            .options(desc)
            .positional(positionOptions)
            .run(), vm);

        po::notify(vm);
    } catch (po::error& e) {
        cerr << "Error " << e.what() << endl << endl;
        cerr << desc << endl;
        return 1;
    }

    const string& elevPath(vm["elevation_dir"].as<string>());
    const string* projDef = nullptr;
    const double x1 = vm["x1"].as<double>();
    const double y1 = vm["y1"].as<double>();
    const double x2 = vm["x2"].as<double>();
    const double y2 = vm["y2"].as<double>();

    if (vm.count("proj")) {
        projDef = &vm["proj"].as<string>();
    } else {
        ostringstream stream;
        stream << "+proj=tmerc +lat_0=" << ((y1 + y2) / 2) << " +lon_0=" << ((x1 + x2) / 2) << " +k=1.000000 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs";
        projDef = new string(stream.str());
    }

    terrain_to_obj(elevPath, *projDef, x1, y1, x2, y2);

    return 0;
}

<|endoftext|>


<commit_before>#ifndef LIBPORT_SEMAPHORE_HH
# define LIBPORT_SEMAPHORE_HH

# include <cassert>
# include <cstddef> // size_t

# ifdef __APPLE__
#  include <string>
# endif

# include <libport/export.hh>
# include <libport/detect-win32.h>

// Get sem_t.
# if defined WIN32
#  include <libport/windows.hh>
namespace libport
{
  typedef HANDLE sem_t;
}

# else /* !WIN32 */
#  include <semaphore.h>
# endif

namespace libport
{
  class Condition;

  class LIBPORT_API Semaphore
  {
  public:
    Semaphore(unsigned cnt = 0);
    ~Semaphore();

    /// Acquire.
    void operator++();
    /// Release.
    void operator--();

    void operator++(int);
    void operator--(int);

    /// Acquire \a c times.
    Semaphore& operator -= (unsigned c);

    /// Releases \a c times.
    Semaphore& operator += (unsigned c);

    operator int ();

    /** Get semaphore with a limit of \b timeout in second.
     * Fixme: Use timeout != 0 work only on linux.
     */
    bool get(const int timeout = 0);

    /// The number of alive Semaphores (#constructed - #destroyed).
    static size_t instances();

  private:
    void destroy();
    sem_t* sem_;
# ifdef __APPLE__
    std::string name_;
# endif
    static size_t instances_;
    friend class Condition;
  };

} // namespace libport

# include <libport/semaphore.hxx>

#endif // !LIBPORT_SEMAPHORE_HH
<commit_msg>Fix doc.<commit_after>#ifndef LIBPORT_SEMAPHORE_HH
# define LIBPORT_SEMAPHORE_HH

# include <cassert>
# include <cstddef> // size_t

# ifdef __APPLE__
#  include <string>
# endif

# include <libport/export.hh>
# include <libport/detect-win32.h>

// Get sem_t.
# if defined WIN32
#  include <libport/windows.hh>
namespace libport
{
  typedef HANDLE sem_t;
}

# else /* !WIN32 */
#  include <semaphore.h>
# endif

namespace libport
{
  class Condition;

  class LIBPORT_API Semaphore
  {
  public:
    Semaphore(unsigned cnt = 0);
    ~Semaphore();

    /// Release.
    void operator++();
    /// Acquire.
    void operator--();

    void operator++(int);
    void operator--(int);

    /// Acquire \a c times.
    Semaphore& operator -= (unsigned c);

    /// Releases \a c times.
    Semaphore& operator += (unsigned c);

    operator int ();

    /** Get semaphore with a limit of \b timeout in second.
     * Fixme: Use timeout != 0 work only on linux.
     */
    bool get(const int timeout = 0);

    /// The number of alive Semaphores (#constructed - #destroyed).
    static size_t instances();

  private:
    void destroy();
    sem_t* sem_;
# ifdef __APPLE__
    std::string name_;
# endif
    static size_t instances_;
    friend class Condition;
  };

} // namespace libport

# include <libport/semaphore.hxx>

#endif // !LIBPORT_SEMAPHORE_HH
<|endoftext|>