2014年3月6日木曜日

boost::geometry でもハマった

同じ図形を geometry でも処理してみたら、見事に落ちた。 ロバストへの道は険しいのであった(´・ω・`)
// Boost.Geometry (aka GGL, Generic Geometry Library)

// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.

// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//

#include <algorithm> // for reverse, unique
#include <iostream>
#include <string>

#include <boost/geometry/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/geometries/adapted/c_array.hpp>
#include <boost/geometry/multi/geometries/multi_polygon.hpp>

BOOST_GEOMETRY_REGISTER_C_ARRAY_CS(cs::cartesian)


int main(void)
{
    using namespace boost::geometry;

    typedef model::d2::point_xy<double> point_2d;
    typedef model::polygon<point_2d> polygon_2d;
    typedef model::box<point_2d> box_2d;

    // Define a polygon and fill the outer ring.
    // In most cases you will read it from a file or database
    polygon_2d poly;
    {
#ifndef SEGV
      const double coor[][2] = {
            {2.0, 1.3}, {2.4, 1.7}, {2.8, 1.8}, {3.4, 1.2}, {3.7, 1.6},
            {3.4, 2.0}, {4.1, 3.0}, {5.3, 2.6}, {5.4, 1.2}, {4.9, 0.8}, {2.9, 0.7},
            {2.0, 1.3} // closing point is opening point
            };
#else
        const double coor[][2] = {
          { -162.277344, -684.941406 },
          { -154.300781, -684.707031 },
          { -147.291016, -768.253906 },
          { -148.601562, -752.630859 },
          { -156.675781, -753.292969 },
          { -155.425781, -768.546875 }
            };
#endif
      assign_points(poly, coor);
    }

    // Polygons should be closed, and directed clockwise. If you're not sure if that is the case,
    // call the correct algorithm
    correct(poly);

  
    // Polygons can be streamed as text
    // (or more precisely: as DSV (delimiter separated values))
    std::cout << dsv(poly) << std::endl;
  
    typedef std::vector<polygon_2d> polygon_list;
    polygon_list v;

    try {
      intersection(poly, poly, v);
    } catch(const std::exception& e) {
      std::cerr << e.what() << std::endl;
    }

    std::cout << "Clipped output polygons" << std::endl;
    for (polygon_list::const_iterator it = v.begin(); it != v.end(); ++it)
    {
        std::cout << dsv(*it) << std::endl;
    }
  
    return 0;
}
今回は vc 2008 だったのだ… /D SEGV を付けないケースでは、落ちる事はない。
cl /EHsc /GR /MD test.cpp /D SEGV
2014/03/07 追記: geos で selfIntersection にかけてみたが、やはりダメだった。
TopologyException: side location conflict at -752.63088031450525 -148.60182192355231
追記:例外処理しないといけないですね。キャッチされない例外で落ちるのは、あたりまえですね。修正しました。
Boost.Geometry Overlay invalid input exception
になりました。 追記:boost::geometry has_self_intersections.hpp でスローされる例外のようで、自己交差の無い Simple な Polygon が入力として必要なようである。用語が難しいのだが、一般に、図形の Simplify というと、複雑な点数を簡略化する(点を間引く)操作を言うので、自己交差のないポリゴンにばらす関数があれば良いのだろうか。

2014年3月5日水曜日

boost::polygon はまった

三角形分割するのに、boost::polygon を使ってたんですが、残念ながら実数版は実装されているもののサポート対象外みたいで、ロバスト性が保証されていないようです。 Android をはじめとする GLES では、Tesselation(三角形分割)がサポートされていないので、Trapezoid (台形)化してポリゴンを塗り潰してたんですけども、残念です。 以下、削ったコード。
#include <boost/cstdint.hpp>
#include <boost/polygon/polygon.hpp>
#include <vector>

using boost::int32_t;
using boost::uint8_t;

namespace bpl = boost::polygon;
typedef float point_value_type;
typedef bpl::polygon_with_holes_data<point_value_type> Polygon;
typedef bpl::polygon_data<point_value_type> Ring;
typedef bpl::polygon_traits<Polygon>::point_type Point;
typedef std::vector<Point> PointSet;
typedef std::vector<Polygon> PolygonSet;

void set_points( Polygon& polygon, const point_value_type* pts, int32_t count ) {
  polygon.self_.coords_.resize( count );
  for( int32_t i = 0; i < count; ++i ) {
    polygon.self_.coords_[i].x( *pts++ );
    polygon.self_.coords_[i].y( *pts++ );
  }
}

void construct( PolygonSet& polygons, const point_value_type* pts, int32_t count ) {
  using namespace bpl::operators;
  Polygon polygon;
  set_points( polygon, pts, count );
  polygons |= polygon;  //// SIGSEGV
}


int main() {
  float pts[] = {
   -30162.277344, -21684.941406,
   -30154.300781, -21684.707031,
   -30147.291016, -21768.253906,
   -30148.601562, -21752.630859,
   -30156.675781, -21753.292969,
   -30155.425781, -21768.546875,
  };
  
  PolygonSet polygons;
  construct( polygons, pts, 6 );

  
  return 0;
}


追記:どんな図形か調べてみた。ま、往々にしてありがちな図形やね。平行な直線が折り返しているとダメなのであろうか?普通、平行な直線は交点の計算ができないので、交点を求めたりはしない。これをやろうとすると泥沼に陥る事が多い。
2014/03/06 追記: 整数の同じ構成にしてテストを行うと、ちゃんとパスする。
#ifndef SEGF
  typedef int32_t point_value_type;
#else
  typedef float point_value_type;
#endif
にして
  point_value_type pts[] = {
#ifndef SEGF
   -22277344,  -4941406,
   -14300781,  -4707031,
    -7291016, -88253906,
    -8601562, -72630859,
   -16675781, -73292969,
   -15425781, -88546875,
#else
   -22.277344,  -4.941406,
   -14.300781,  -4.707031,
    -7.291016, -88.253906,
    -8.601562, -72.630859,
   -16.675781, -73.292969,
   -15.425781, -88.546875,
#endif
  };
ここは、難しいようで、 polygon_arbitrary_format.hpp にもデバッグ用のコードがコメントアウトされる形で埋め込まれていた。 両者で実行して、違いを見比べてみたところ セーフバージョン
processEvent_
loop
current Y -72630881
scanline size 2
( -16675781, -73292969), ( -8601822, -72630881); ( -14300781, -4707031), ( -8601822, -72630881); 
found element in scanline 1
finding elements in tree
first iter y is -7.26309e+007
loop2
loop2
counts_from_scanline size 2
aggregating
loop3
loop3
落ちるバージョン
processEvent_
loop
current Y -72.6309
scanline size 2
( -16.6758, -73.293), ( -8.60156, -72.6309); ( -14.3008, -4.70703), ( -7.29102, -88.2539); 
found element in scanline 1
finding elements in tree
first iter y is -72.6309
loop2
counts_from_scanline size 1
aggregating
loop3
loop3
更に、loop2 の条件判定文のコメントを polygon_arbitrary_format.hpp に追加して追試してみたところ、
        if(iter != scanData_.end())
          std::cout << "first iter y is " << iter->first.evalAtX(x_) << "\n";
        while(iter != scanData_.end() &&
              ((iter->first.pt.x() == x_ && iter->first.pt.y() == currentY) ||
               (iter->first.other_pt.x() == x_ && iter->first.other_pt.y() == currentY))) {
                //iter->first.evalAtX(x_) == (high_precision)currentY) {
          std::cout << "loop2\n";
          elementIters.push_back(iter);
          counts_from_scanline.push_back(std::pair<std::pair<std::pair<Point, Point>, int>, active_tail_arbitrary*>
                                         (std::pair<std::pair<Point, Point>, int>(std::pair<Point, Point>(iter->first.pt,
                                                                                                          iter->first.other_pt),
                                                                                  iter->first.count),
                                          iter->second));
          ++iter;
          if( iter != scanData_.end() ) {
            std::cout << "CHK loop2 " << iter->first.pt.x() << " == " << x_ << " && " << iter->first.pt.y() << " == " << currentY << "\n";
            std::cout << "CHK loop2 " << iter->first.other_pt.x() << " == " << x_ << " && " << iter->first.other_pt.y() << " == " << currentY << "\n";
          }
        }
セーフバージョンと落ちるバージョンでは、そもそもscanline の構成が異なっている事がわかった
processEvent_
loop
current Y -72630881
scanline size 2
( -16675781, -73292969), ( -8601822, -72630881); ( -14300781, -4707031), ( -8601822, -72630881); 
found element in scanline 1
finding elements in tree
first iter y is -7.26309e+007
loop2
CHK loop2 -14300781 == -8601822 && -4707031 == -72630881
CHK loop2 -8601822 == -8601822 && -72630881 == -72630881
loop2
counts_from_scanline size 2
aggregating
processEvent_
loop
current Y -72.6309
scanline size 2
( -16.6758, -73.293), ( -8.60156, -72.6309); ( -14.3008, -4.70703), ( -7.29102, -88.2539); 
found element in scanline 1
finding elements in tree
first iter y is -72.6309
loop2
CHK loop2 -14.3008 == -8.60156 && -4.70703 == -72.6309
CHK loop2 -7.29102 == -8.60156 && -88.2539 == -72.6309
counts_from_scanline size 1
aggregating
loop3
loop3
浮動小数点型の演算は、難しいものだ。やはり、ロバスト性を確保するのは並大抵のことではない感じだ。

2014年2月10日月曜日

雪あかりの路2014

今年も行ってきました。




2014年2月7日金曜日

Android の Intent が宝の持ち腐れ

 ちょっ、Android の開発に関して、ぼやきます。  Intent を介してアプリケーションが連帯する仕組みが整っているのに、ファイル選択ダイアログといった単純なパーツさえ、自分でエクスプローラのアプリケーションを作成する勢いで書かないと、存在しない。 例えば、zip ファイルを選択させたいと思ったら、既存の枠組みでは、

  private static final int REQUEST_CHOOSE_ZIP = 1;
...

  private void selectZip() {
    Intent intent = new Intent(Intent.ACTION_GET_CONTENT); 
    // MIME/Type が微妙だが置いといて
    intent.setType("application/zip"); 
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    startActivityForResult(intent, REQUEST_CHOOSE_ZIP );
  }
と、呼び出してやれば済む話なのであるが、Androidに付属している標準のエクスプローラ・アプリは、得てして、この仕様に対応していない。

そうすると無料の広告付きアプリを入れてくるか、android-file-dialog(広告付きのオープンソース:改造可)を用意するか、とにかくイケてない。
ま、検索すれば AlertDialog.Builder ベースのファイル選択ダイアログというパーツも見つかるのだが、アクセス権限のないディレクトリに触った瞬間落ちるし、なんか、いけてない。Google さんも、Android の UIガイドと啓蒙みたいな部分に力を入れるよりも、こういった連帯ベース部分に力を入れたほうが、よほどエコなんじゃないでしょうか?  

2014年1月6日月曜日

SD-1 merrill を買いました

 皆さん、明けましておめでとうございます。  ファインダーのついてるカメラが欲しくなったのと、NEX-5Rのクオリティでは我慢できなくなってきたので、カメラを買い替えました。Sigma の SD-1 merrill で、foveon センサという、ちょっとユニークなカメラです。撮れる画像は、はまった時には超一流、だけど、その他の部分は、色々と酷評されている面から考えてもユニークなカメラです。  最近、目が肥えてきて、フルサイズのセンサーで撮影された写真が、なんとなくわかるようになってきました。なので、フルサイズにも惹かれてて、価格的にD610やEOS6Dも圏内でした。NIKON のカメラで撮影されたRAWデータを触らせてもらった事があるのですが、ダイナミック・レンジが半端なく広く感動していた事もあり、D610が有力だったんですが、レンズまで含めると、フルサイズのカメラは、価格的に、かなりしんどい。どうせD610行くならD800Eぐらいのが欲しいというのも頭をかすめました。  PENTAXのK-3も気になってはいたんですが、K-5IIsと比べて、画質は落ちるんじゃないかという部分と、APS-Cサイズな点で、結局SD-1 merrill を選択しちゃいました。  まだ少ししか触ってないんですが、早くも難しいカメラを選んでしまったというのが率直な感想です。ベイヤー方式と異なるカメラなので、RAWデータを弄る感覚が、今までと全く違う。実際どうなのかは、わかりませんが、ダイナミック・レンジは狭いんじゃないかな?という気がしてます。もしくは、現像ソフトで引き出せるダイナミック・レンジが狭いのか?12bit階調しかない NEX-5RのRAWデータでさえ、暗い部分を持ち上げて明るい部分を抑える芸当が、そこそこ効くのに、SD-1 merrill のRAWデータは、どれかを動かすと全体的に追従してきてしまう。しかも、白飛びした部分の潰れ方が極端で、ベタっとします。  手応えとしては、SD-1 merrill こそ HDR 向きなのではないかと感じている次第です。

rsync 備忘録

   3台のマシンがあって、入り口のマシンは1台。いちいちコピーしてたら日が暮れるので、ファイル転送部分だけは定型化しておく事にした。


  • MenteMachine
  • MainMachine
  • SubMachine
ユーザ foo で作業するとして、

MenteMachine 上に

 /home/foo/to_main
 /home/foo/to_sub

MainMacihne 上に

 /home/foo/to_mente

SubMacihne 上に

 /home/foo/to_mente

と、こんな感じディレクトリを構築しておく


MenteMachine 上に、データを収集するためのシェル
#!/bin/bash
rsync -av --delete -e 'ssh -c arcfour' foo@MainMachine:/home/foo/to_mente/ /home/foo/to_main/
rsync -av --delete -e 'ssh -c arcfour' foo@SubMachine:/home/foo/to_mente/ /home/foo/to_sub/
MenteMachine 上のデータを配送するためのシェル
#!/bin/bash
rsync -av --delete -e 'ssh -c arcfour' /home/foo/to_main/ foo@MainMachine:/home/foo/to_mente/ 
rsync -av --delete -e 'ssh -c arcfour' /home/foo/to_sub/ foo@SubMachine:/home/foo/to_mente/ 

2013年12月20日金曜日

mac osx 環境変数 忘備録

関連ファイル /etc/profile /etc/bashrc ターミナルを開く毎に実行 ~/.bashrc ログイン時に実行 ~/.profile ~/.bash_profile 自分は、~/.profile に記述してるよ
##
# Cinder part
##
# export CINDER_HOME=/usr/local/src/cinder_0.8.2_mac

##
# Cuda SDK part
##
export PATH=/usr/local/cuda/bin:$PATH
export DYLD_LIBRARY_PATH=/usr/local/cuda/lib:$DYLD_LIBRARY_PATH
export GPU_INCDIR="/Developer/GPU Computing/C/common/inc"
export C_INCLUDE_PATH=$GPU_INCDIR:$C_INCLUDE_PATH
export CPLUS_INCLUDE_PATH=$GPU_INCDIR:$CPLUS_INCLUDE_PATH

##
# Android NDK part
##
export ANDROID_NDK=/opt/android-ndk-r8d
export PATH=$ANDROID_NDK:$PATH
export ANDROID_TOOLCHAIN_CMAKE=$ANDROID_NDK/toolchains/android.toolchain.cmake

alias android-cmake='cmake -DCMAKE_TOOLCHAIN_FILE=$ANDTOOLCHAIN '

##
# Your previous /Users/okimiyuki/.profile file was backed up as /Users/okimiyuki/.profile.macports-saved_2012-06-03_at_22:46:38
##

# MacPorts Installer addition on 2012-06-03_at_22:46:38: adding an appropriate PATH variable for use with MacPorts.
export PATH=/opt/local/bin:/opt/local/sbin:$PATH
# Finished adapting your PATH environment variable for use with MacPorts.