2014年12月29日月曜日

Bitcasa 退会しました

 年間プランで契約していたにも関わらず、突然の1Tに容量を制限しました宣言。それでも価格はGoogleDriveと同じなので、使い続けてみようかなぁと様子を見ていました。 ところが提供されている BitCasaドライブに接続するアプリの品質が一向に改善される気配が無く、エラーで使い物にならない始末。おまけにFAQに書かれている退会方法と実際の退会方法が一致していない状態で放置されたまま。バグがあっても、使い勝手が悪くても、改善される兆しが見えれば問題ないのですが、一向に変化なしで、この状態はサービスとしてはもう終了していると判断しました。  さて辞め方ですが、Bitcasaのアカウントを完全に削除する に書いてある通りです。 最後の肝となる返信先は、
** We are experiencing a high volume of emails that may result in a delay in our response. We strive to provide you with the best possible service and we apologize for any inconvenience the delay might cause. The deadline to update accounts to the new backend has ended. For questions about what will happen with your current account, please see our FAQ. Thank you for your patience. **

Hello YOURNAME

Thank you for contacting Bitcasa Technical Support!

You have reached us outside of normal business hours. Business hours are Monday-Friday, 8:00AM - 6:00PM Pacific Time. Your support request (NNNNN) has been created and a Technical Support Specialist will be contacting you during regular business hours. If you wish to add additional comments or details, reply to this email or go to: http://support.bitcasa.com/hc/requests/NNNNN.

While you're waiting, check out the Bitcasa Help Center! There you will find answers to common questions and issues, FAQs, our community forums, and more! Check us out at http://support.bitcasa.com.

Thank you for contacting us and we look forward to helping you.

Regards,

Bitcasa Technical Support
http://support.bitcasa.com
メールに書かれてある、サポートサイトに発行されたリクエスト・チケットに従ってリプライをします。  Amazon S3 の価格から考えて容量無制限のストレージは無理。結局 BitCasa も財務が圧迫して容量無制限を打ち切らざるを得なかった。という事でしょうか。

2014年11月6日木曜日

GDAL-1.11.1 における ShapeDriver の日本語設定

前回「GDAL-1.10.1 の日本語環境ではまった」からの続きです。 うまく行ったり、行かなかったりは、文字コードが UTF-8 だったり SJIS だったりと、判別のしようが無い Shape が混在していたのが大きな原因でした。 それで、定説の 環境変数
set SHAPE_ENCODING=LDID/19 
ですが、そこを解釈するコードは、このようになっております。
CPLString OGRShapeLayer::ConvertCodePage( const char *pszCodePage )

{
    CPLString osEncoding;
  osEncoding.Clear();

    if( pszCodePage == NULL )
        return osEncoding;

    if( EQUALN(pszCodePage,"LDID/",5) )
    {
        int nCP = -1; // windows code page. 

        //http://www.autopark.ru/ASBProgrammerGuide/DBFSTRUC.HTM
        switch( atoi(pszCodePage+5) )
        {
          case 1: nCP = 437;      break;
          case 2: nCP = 850;      break;
          case 3: nCP = 1252;     break;
          case 4: nCP = 10000;    break;
          case 8: nCP = 865;      break;
          case 10: nCP = 850;     break;
          case 11: nCP = 437;     break;
          case 13: nCP = 437;     break;
          case 14: nCP = 850;     break;
          case 15: nCP = 437;     break;
          case 16: nCP = 850;     break;
          case 17: nCP = 437;     break;
          case 18: nCP = 850;     break;
          case 19: nCP = 932;     break;
          case 20: nCP = 850;     break;
          case 21: nCP = 437;     break;
          case 22: nCP = 850;     break;
          case 23: nCP = 865;     break;
          case 24: nCP = 437;     break;
          case 25: nCP = 437;     break;
          case 26: nCP = 850;     break;
          case 27: nCP = 437;     break;
          case 28: nCP = 863;     break;
          case 29: nCP = 850;     break;
          case 31: nCP = 852;     break;
          case 34: nCP = 852;     break;
          case 35: nCP = 852;     break;
          case 36: nCP = 860;     break;
          case 37: nCP = 850;     break;
          case 38: nCP = 866;     break;
          case 55: nCP = 850;     break;
          case 64: nCP = 852;     break;
          case 77: nCP = 936;     break;
          case 78: nCP = 949;     break;
          case 79: nCP = 950;     break;
          case 80: nCP = 874;     break;
          case 87: return CPL_ENC_ISO8859_1;
          case 88: nCP = 1252;     break;
          case 89: nCP = 1252;     break;
          case 100: nCP = 852;     break;
          case 101: nCP = 866;     break;
          case 102: nCP = 865;     break;
          case 103: nCP = 861;     break;
          case 104: nCP = 895;     break;
          case 105: nCP = 620;     break;
          case 106: nCP = 737;     break;
          case 107: nCP = 857;     break;
          case 108: nCP = 863;     break;
          case 120: nCP = 950;     break;
          case 121: nCP = 949;     break;
          case 122: nCP = 936;     break;
          case 123: nCP = 932;     break;
          case 124: nCP = 874;     break;
          case 134: nCP = 737;     break;
          case 135: nCP = 852;     break;
          case 136: nCP = 857;     break;
          case 150: nCP = 10007;   break;
          case 151: nCP = 10029;   break;
          case 200: nCP = 1250;    break;
          case 201: nCP = 1251;    break;
          case 202: nCP = 1254;    break;
          case 203: nCP = 1253;    break;
          case 204: nCP = 1257;    break;
          default: break;
        }

        if( nCP != -1 )
        {
            osEncoding.Printf( "CP%d", nCP );
            return osEncoding;
        }
    }

    // From the CPG file
    // http://resources.arcgis.com/fr/content/kbase?fa=articleShow&d=21106
    
    if( (atoi(pszCodePage) >= 437 && atoi(pszCodePage) <= 950)
        || (atoi(pszCodePage) >= 1250 && atoi(pszCodePage) <= 1258) )
    {
        osEncoding.Printf( "CP%d", atoi(pszCodePage) );
        return osEncoding;
    }
    if( EQUALN(pszCodePage,"8859",4) )
    {
        if( pszCodePage[4] == '-' )
            osEncoding.Printf( "ISO-8859-%s", pszCodePage + 5 );
        else
            osEncoding.Printf( "ISO-8859-%s", pszCodePage + 4 );
        return osEncoding;
    }
    if( EQUALN(pszCodePage,"UTF-8",5) )
        return CPL_ENC_UTF8;

    // try just using the CPG value directly.  Works for stuff like Big5.
    return pszCodePage;
}
これのディスカッションは、ESRI社のフォーラムで話題になっていました。
コード中の解説ページhttp://www.autopark.ru/ASBProgrammerGuide/DBFSTRUC.HTMが詳しいです。
CP932 に相当するケース文の値は、0x7B でなければなりませんから、10進数にしますと、123になります。上記コードと照らしあわせても整合がとれていますよね? という事で、LDID/19 でもOKなのですが、
set SHAPE_ENCODING=LDID/123 
を設定すると、CP932 に変換してくれる。
もしくは、最初から CP932 を指定していれば、LDID/の変換をパスして、上記関数を通った後の値が評価されるので
set SHAPE_ENCODING=CP932 
でもOKだったという事になるのでしょうか? 拡張子 DBF ファイルの 29バイト目に、case 文の値か、UTF-8なら -1 == 65535 == 0xFFFF を設定するように改善していけば良さそうですよね?
と、思ったら、-1 は CPACP 扱い? int は 32bit 以上で、65535 == 0xFFFF の解釈で考えればOKでしょうか? 同日追記:  実は SHAPE_ENCODING= を設定しない方が、うまく動く場合もあるようです。どうも、前回DBFファイルに設定があった場合は、SHAPE_ENCODINGは使用されないような事を書きましたが、その記述が間違いだったみたいです。そして、SHAPE_ENCODING=UTF-8 と設定してみましたが、挙動が違うような・・・。もうちょい、突っ込んで調べてみます・・・

2014年11月4日火曜日

近況2014/11/4

 ご無沙汰してます。すっかりマネジメントの方に引っ張られてます。 この先どうなっていくかは、不透明な状態ではありますが、クラウドに関して一周した感があるので、それについて、つらつらと書いてみます。  勝者一人勝ちの世界、そこは揺るぎようがないとは思いますが、結局の所、企業というのは他社との差別化が無いと付加価値はありません。コストだけに価値があるわけではないので、クラウドに移行したからと言って、受託の領域が無くなるわけじゃないのかなぁと感じています。  クラウドのビジネスに乗り出して戦うには、体力が必要です。投資の得られたベンチャーならともかく、中小企業がそれをやるには、あまりにも厳しい。じゃあ、仕事はクラウドになって無くなるのか?と思ったら、クラウドのプラットフォームと関連づけられた付加価値という名のサブシステムは無くなりようがないんじゃないかと。受託の領域が無くならないと感じているのは、まさにここなんです。  以上、こんな事を考えてました。とは言え、自分自身、この先どう歩んでいくのか模索中です。

2014年7月25日金曜日

GDAL-1.10.1 の日本語環境ではまった

 たまーに、お客さんから DBF ファイルにエンコーディング(文字コード)の設定をしていない Shape ファイルを貰うんですわ。 そしたら、ogr2ogr にかけると、文字化けするんです。
set SHAPE_ENCODING=LDID/19 
って、やっても文字化けは直らないんで、調べました。 DBF をバイナリエディタで見ると、もらった Shape ファイルは、DBFファイル中のヘッダーパートの29バイト目の値(エンコーディング)が 0 のままで、データに使用されている文字コードはCP932(Shift_JIS)でした。 GDALのコード中の処理順序は、こんな感じです。

  1.  DBF ファイルの codepage が設定されているかどうかで処理
  2. CPGファイルに codepage が設定されているかどうかで処理
  3. 環境変数 SHAPE_ENCODING の値が設定されているかどうかで処理
  4. プログラム・オプションに codepage が指定されているかどうかで処理
  5. 文字コードは変換しないで、そのまま利用する
これ、SHAPE_ENCODING を設定してても、DBFファイルにエンコーディングが設定されていれば、正しい変換を行ってくれるので、素晴らしいです。
調査していると、1.10.1 のバージョンでは
set SHAPE_ENCODING=CP932
としないと、ちゃんとSJISとして扱ってくれないようでした。いつから LDID/19 じゃなくなった? こんな調査に半日以上費やしました・・・(`;ω;´) 2014/09/04 追記: 環境によって、SHAPE_ENCODING=LDID/19 にしないと変換してくれない場合があったりして混乱中。  ソースを修正しすぎた?  なんと、UTF-8 コードで書かれた shape と、CP932 コードで書かれた shape が混在している事が判明しました。  エスパーじゃあるまいし、知るか!

2014年5月27日火曜日

Android の PopupWindow が dismiss できない備忘録

久しぶりです。
Android 開発、難しいですね。
知ってました?Android の PopupWindow 作るの難しいの。

Problems creating a Popup Window in Android Activity
タイミングが速すぎるんですよ。何このノウハウ?
でね、PopupWindow 破棄するのも、難しいの知ってました?

PopupWindow.dismiss() なんですがね、PopupWindow.isShowing() == true じゃないと、破棄できないんですよ。迅速にUIでポップアップの表示と破棄をボタン連打で繰り返してると、ゴーストウィンドウが溜まりまくるんですよwwww

何が起きてるかっていうと、PopupWindow が表示しきれる前に破棄をUIから指示できるんです。
そうすると

PopupWindow.isShowing() == false 時に破棄関数が呼ばれて、dismiss() できないから、PopupWindow のインスタンスは生きたまま破棄できない状態でスルーですわ。

どうすればいいか?

  private void purgePopup( PopupWindow pw ) {
    if( pw == null ) return;
    if( pw.isShowing() ) {
      pw.dismiss();
    } else {
      final PopupWindow oldWindow = pw;
      new Timer().schedule(new TimerTask(){
        @Override
        public void run() {
          getActivity().runOnUiThread(new Runnable(){
            public void run() {
              oldWindow.dismiss();
            }
          });
        }
      }, 100);
    }
  }
こんな感じで対処したら、うまくいきました。ぼぇー

2014年3月13日木曜日

boost::filesystem v3 で windows 環境にて日本語ファイルを扱う備忘録

Default encoding under windows を参考にやってみました。 コンパイラが VC8 だったので、最初、手を抜いてソースコードを UTF-8 でファイルに保存して実行してみたら
#include <boost/locale.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/format.hpp>

int main()
{
  // Create and install global locale
  std::locale::global(boost::locale::generator().generate(""));
  //std::locale::global(boost::locale::generator().generate("ja_JP.UTF-8"));
  // Make boost.filesystem use it
  boost::filesystem::path::imbue(std::locale());
  // Now Works perfectly fine with UTF-8!
  boost::filesystem::ofstream hello("こんにちわ.txt"); 
  return 0;
}
出力されたファイル名が
こんにちめEtxt
なんじゃこれ??? あれこれ、試しているうちに、どうやら UTF-8 で保存したのがいけないみたいだという事で
#include <boost/locale.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/format.hpp>

int main()
{
  // Create and install global locale
  std::locale::global(boost::locale::generator().generate(""));
  //std::locale::global(boost::locale::generator().generate("ja_JP.UTF-8"));
  // Make boost.filesystem use it
  boost::filesystem::path::imbue(std::locale());
  // Now Works perfectly fine with UTF-8!
  //boost::filesystem::ofstream hello("こんにちわ.txt"); 
                                   //  こ          ん          に          ち          わ
  boost::filesystem::ofstream hello("\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x82\x8F.txt"); 
  return 0;
}
と正攻法で書きなおしたら、ちゃんと動作しました。 また、くだらない事に時間を費やしてしまった(´・ω・`)

2014年3月12日水曜日

boost::polygon self intersection problem 顛末

この前のポストの問題ですが、面白い事がわかったので、顛末を書きます。 OpenGLES では、描画が float 精度までで、データは double 精度で保持しておりました。 これを boost::polygon にて、trapezoid にかけて台形化処理するのですが、その時に double から float に static_cast で精度を落とします。そうすると、自己交差の無い simple な図形が精度変換の過程で自己交差を持つ図形に変身するケースがあると判明しました。  じゃあ事前に float 精度に落として 自己交差のある状態の図形は float 精度で自己交差を解消した simple な状態にしてから double に戻せば問題無いだろうと思って、やってみましたが、何故かうまく行かない。詳しく突っ込んで調べていないですが、もしかしたら CPU に依存する話なのかもしれません。  余計な事をすると遅くなるので、なんとかしたかったですが、アプリが落ちてしまっては、元も子もありません。もう少し無駄な計算は省こうという事で、こんな感じで落ち着きました。
    void to_simple( Polygon& polygon ) {
      size_t len = polygon.self_.coords_.size();
      Point ss = polygon.self_.coords_[len-1];
      for( size_t i = 0; i < len-2; ++i ) {
        Point se = polygon.self_.coords_[i];
        Point es = polygon.self_.coords_[i+1];
        for( size_t j = i + 2; j < len; ++j ) {
          Point ee = polygon.self_.coords_[j];
          if( i != j ) {
            if( 
                 (ss.x() == es.x() && ss.y() == es.y() )
              || (ss.x() == ee.x() && ss.y() == ee.y() )
              || (se.x() == es.x() && se.y() == es.y() )
              || (se.x() == ee.x() && se.y() == ee.y() )
            ) {
            } else {
              double xx, yy;
              if( k_4t_close( xx, yy, ss.x(), ss.y(), se.x(), se.y(), es.x(), es.y(), ee.x(), ee.y() ) ) {
                se = Point( xx, yy );
                ee = Point( xx, yy );
                //if( i < j ) { // i < j は自明でしたねorz
                  polygon.self_.coords_.insert( polygon.self_.coords_.begin() + j, ee );
                  polygon.self_.coords_.insert( polygon.self_.coords_.begin() + i, se );
                //} else {
                //  polygon.self_.coords_.insert( polygon.self_.coords_.begin() + i, se );
                //  polygon.self_.coords_.insert( polygon.self_.coords_.begin() + j, ee );
                //}
                len += 2;
              }
            }
          }
          es = ee;
        }
        ss = se;
      }
    }

2014年3月7日金曜日

boost::polygon self intersection problem

ここ2つ前からの投稿の問題は解決しました。この前に geos というライブラリでもテストコードを実行させてみたところ
TopologyException: side location conflict at -752.63088031450525 -148.60182192355231
という例外が発生しました。boost::geometry はロバストに出来ていて、自分が例外キャッチするのを忘れていただけで、ちゃんと
Boost.Geometry Overlay invalid input exception
という例外が送出されていました。  で、どういう問題が発生してたか boost::geometryのコードを読んでみたところ、図形が Simple でない=自己交差を起こしている場合に例外が送出されていました。 なので、自己交差を解消してやれば、問題をクリアできそうな感触を得ました。 残念ながら、自己交差を解消する関数は、見当たらなかったので自作。スタイルが古いですが、古いコンパイラを使っているので auto とか使えなかったんです。 list::insert してるあたりがダサいですが、古い環境なんで、このままです(>_<) 結局、自己交差を解消してやれば、boost::polygon のコードも通りました。
#include <boost/cstdint.hpp>
#include <boost/polygon/polygon.hpp>
#include <vector>
#include <deque>
#include <cmath>
#include <iomanip>

namespace bpl = boost::polygon;
typedef double point_value_type;
typedef bpl::segment_data<point_value_type> Segment;
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;
typedef std::list<Segment> SegmentSet;

#define ACCY 1e-6

Polygon make_polygon( const point_value_type* pts, size_t count ) {
  Polygon polygon;
  polygon.self_.coords_.resize( count );
  for( size_t i = 0; i < count; ++i ) {
    polygon.self_.coords_[i].x( *pts++ );
    polygon.self_.coords_[i].y( *pts++ );
  }
  return polygon;
}

void construct( PolygonSet& polygons, Polygon polygon ) {
  using namespace bpl::operators;
  polygons |= polygon; 
}

void construct( SegmentSet& segments, const point_value_type* pts, size_t count ) {
  point_value_type ax = pts[count*2-2];
  point_value_type ay = pts[count*2-1];
  for( size_t i = 0; i < count; ++i ) {
    point_value_type bx = *pts++;
    point_value_type by = *pts++;
    segments.push_back( Segment( Point(ax, ay), Point(bx, by) ) );
    ax = bx;  ay = by;
  }
}

Polygon make_polygon(const SegmentSet& segments ) {
  Polygon polygon;
  size_t count = segments.size();
  polygon.self_.coords_.resize( count );
  size_t i = 0;
  SegmentSet::const_iterator s = segments.begin();
  SegmentSet::const_iterator e = segments.end();
  while( s != e ) {
    polygon.self_.coords_[i++] = bpl::low(*s++);
  }
  return polygon;
}


std::ostream& operator << (std::ostream& os, const Point& p) {
  os << std::setprecision(10);
  os << "{ " << bpl::x(p) << ", " << bpl::y(p) << " },\n";
  return os;
}

std::ostream& operator << (std::ostream& os, const SegmentSet& segments) {
  SegmentSet::const_iterator s = segments.begin();
  SegmentSet::const_iterator e = segments.end();
  while( s != e ) {
    os << bpl::low( *s++ );
  }
  return os;
}

//! 4点交点(線分による完全交差版)を取得する
/*!
 @attention 交点が存在しない場合、x,y は未定義である
 @retval true 交点が存在
 @retval false 交点は存在しない
*/
bool k_4t_close( 
 double& x, //!< [out] 交点X座標値 
 double& y, //!< [out] 交点Y座標値
 double xk, //!< [in] 線分KLの始点X座標値
 double yk, //!< [in] 線分KLの始点Y座標値
 double xl, //!< [in] 線分KLの終点X座標値
 double yl, //!< [in] 線分KLの終点Y座標値
 double xm, //!< [in] 線分MNの始点X座標値
 double ym, //!< [in] 線分MNの始点Y座標値
 double xn, //!< [in] 線分MNの終点X座標値
 double yn   //!< [in] 線分MNの終点Y座標値
) {
 long double xlk = xl - xk;
 long double ylk = yl - yk;
 long double xnm = xn - xm;
 long double ynm = yn - ym;
 long double xmk = xm - xk;
 long double ymk = ym - yk;
 long double det = xnm * ylk - ynm * xlk;
 if( std::fabs( det ) < ACCY ) return false;
 long double s = (xnm * ymk - ynm * xmk ) / det;
 long double t = (xlk * ymk - ylk * xmk ) / det;
 if( s < 0.0 || 1.0 < s || t < 0.0 || 1.0 < t ) return false;
 x = xk + xlk * s;
 y = yk + ylk * s;
 return true;
}

void resolve_segment( SegmentSet& segments ) {
  SegmentSet::iterator is = segments.begin();
  SegmentSet::iterator ie = segments.end();
  while( is != ie ) {
    SegmentSet::iterator cs = segments.begin();
    SegmentSet::iterator ce = segments.end();
    while( cs != ce ) {
      if( cs != is ) {
        if( bpl::intersects( *cs, *is, false ) ) {
          //std::cout << "X" << std::endl;
          double xx, yy;
          Point a = bpl::low( *cs );
          Point b = bpl::high( *cs );
          Point c = bpl::low( *is );
          Point d = bpl::high( *is );
          k_4t_close( xx, yy,
            bpl::x( a ), bpl::y( a ), bpl::x( b ), bpl::y( b ),
            bpl::x( c ), bpl::y( c ), bpl::x( d ), bpl::y( d )
          );
          Point n( xx, yy );
          //std::cout << a << n << b << std::endl;
          *cs = Segment( n, b );
          cs = segments.insert( cs, Segment( a, n ) );
          *is = Segment( n, d );
          is = segments.insert( is, Segment( c, n ) );
        } else {
          //std::cout << "o" << std::endl;
        }
      }
      ++cs;
    }
    ++is;
  }
}


int main() {
  point_value_type pts[] = {
   -162.277344, -684.941406,
   -154.300781, -684.707031,
   -147.291016, -768.253906,
   -148.601562, -752.630859,
   -156.675781, -753.292969,
   -155.425781, -768.546875,
  };
  /*
  point_value_type pts2[] = {
   -155.425781, -768.546875 ,
   -162.277344, -684.941406 ,
   -154.300781, -684.707031 , 
   -148.6018219, -752.6308803 ,
   -147.291016, -768.253906 ,
   -148.601562, -752.630859 ,
   -148.6018219, -752.6308803 ,
   -156.675781, -753.292969 ,
  };
  */
  
  SegmentSet segments;
  construct( segments, pts, 6 );

  std::cout << segments;
  
  resolve_segment( segments );
  
  std::cout << "===== RESOLVE ====\n";
  std::cout << segments;
  
  PolygonSet polygons;
  //construct( polygons, make_polygon( pts, 6 ) );
  construct( polygons, make_polygon( segments ) );
  
  return 0;
}


追記:あれ? insert のあたり、よく考えたら、まずいですかね・・・。

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/