ALIBRaster Ver 1.0 ユーザーズマニュアル

目次
  1. 概要
  2. CAlibRasterクラスの概要
マニュアルホームページ

概要

ALIBRasterは、アートロジック社が供給しているラスタ編集ライブラリで、高度なラスタ編集機能を簡潔なAPIで供給するものです。
ペイントソフトやフォトレタッチソフトと同様のラスタデータに対して、ドローソフトやCADソフトのような編集機能を提供します。
  1. レイヤ編集
    ラスタは、文字列図形、面図形、線図形、記号(Ver.1.1以降)のレイヤに初期配置されます。
    さらに216のユーザー定義レイヤに再配置、レイヤ単位の表示、編集、出力が可能です。
    各レイヤの表示色は自由に定義することができ、8ビットカラー画像での出力、24ビットフルカラー画像での表示が可能です。
  2. ポリライン(頂点でつながった一連の線分)編集
    ポリラインに対して、CADソフトのような編集機能を提供します。頂点の移動、削除、切断、挿入が可能です。
    さらに、細線化、太線化、レンダリング(均等な線幅のラインに整形)も可能です。
  3. 図形編集
    文字列図形、面図形、線図形、記号(Ver.1.1以降)に対して、図形単位での編集が可能です。
    図形単位での削除、移動、コピー、挿入、回転、拡大縮小、任意変形ができます。
    複雑な面図形も任意のサイズ、向きで挿入することができます。
  4. 描画機能
    ポリライン(複数の線分から成る図形)、長方形枠、塗りつぶし長方形、楕円枠、塗りつぶし楕円を描画することができます。
    通常のペイントソフトと同様の描画機能です。
    CADソフトから読み込んだ線図形部品を自由に変形して挿入することもできます。
  5. アンドゥ・リドゥサポート
    アンドゥ・リドゥをサポートする機能を提供します。多段階アンドゥ・リドゥやファイルを使った処理も可能です。
  6. ラスタ出力サポート
    表示・ファイル出力をサポートする機能を提供します。
バージョン1.1では、文字列認識機能と記号認識機能のサポートによって、さらに以下の編集機能が可能となります。
  1. 文字列認識機能
    文字列画像に対して文字コードとしてのアクセスを可能にします。文字列画像をOSのフォントにレンダリングしたり、テキストとして検索することができます。
    さらに、テキストエディタのように文字列画像を編集することができるようになります。
    ワープロのように、テキストのフォント名やサイズを変更したり太字化、イタリック化などの修飾が可能になります。
  2. 記号レイヤの追加
    登録した記号を認識し、記号レイヤに配置します。入力画像は、文字列図形、線図形、面図形、記号の4つに分かれます。
    記号単位で削除、移動、回転、拡大・縮小が使える以外に、別の記号との置換機能も提供します。
  3. 線図形変換
     線図形を破線、実線に相互変換することができます。破線はいくつかのタイプが用意されます。

  4. 円弧・円認識
     円弧・円を認識します。バージョン1.0では拡大した場合にポリラインとしての円は頂点間が直線で結ばれているために円らしさの無い多角形になります。
    円弧・円認識した場合は、頂点間のラインを円弧近似するために拡大しても円の見た目を保ちます。

OS対応

Windows 95、Windows 98、Windows NT、Windows2000、WindowsXp、Windows Vista対応。
開発環境はVC++が必要。(VS6.0以降、VS.NET2003/2005など)
C言語で開発するためのC言語インターフェイスを持つ動的リンクライブラリやC#、VB、VBScript、JAVA、JavaScript、Perl等から呼び出すことのできるCOM/ActiveXインターフェイスでの提供もしますので、お問い合わせください。

目次


ライブラリのファイル構成

  1. DLL
    DLL 概要
    alibraster.dll ラスタ編集ライブラリAPI(C++)
    ngkocr4.dll プリミティブ編集ライブラリAPI(C++)
    その他複数のDLL 弊社共通ライブラリ(APIは非公開)

  2. VC++向けインポートライブラリ
    alibvector.dllに対応するalibvector.libとngkocr4.dllに対応するngkocr4.libが必要です。

  3. ヘッダファイル
    ヘッダファイル 概要
    alibraster.h ラスタ編集変換ライブラリ
    cjocrprim.h プリミティブ編集ライブラリ
    errcode.h エラーコードの定義

その他、キーファイルが必要となります。契約内容によっては、利用機能制限、利用期間制限、利用機械制限設定されます。
また、契約内容(特に低価格版)によって、マニュアルの記述範囲が異なることがあります。
ヘッダファイルには存在していても、マニュアルに無いAPIは、サポート対象外となります。
目次


クラスライブラリの構成

ラスタ編集変換のためのクラスは、CALibRaster/CJocrPrim/CLightPolylineです。
インスタンスを作成し、キーファイルあるいはキー文字列を指定後に、ラスタ編集のAPIをコールします。
全ての図形に対しては、CJocrPrimクラス経由で直接アクセスすることができます。
レイヤ情報のアクセスやレイヤ単位での編集もCJocrPrimクラス経由で操作します。
線図形を線図形としてアクセスするには、CLightPolylineクラスインスタンスとしてアクセスします。
Ver.1.1では、文字列図形を文字列(テキストコード列)としてアクセスするためのクラスと、記号を記号としてアクセスするためのクラスが導入されます。

注意:CJocrPrimクラス側で図形削除などの編集操作をしたときは、線図形・文字列図形・記号クラスの情報と 一貫性を取るためのAPIを自前でコールしなければなりません。CALibRasterクラスのAPIを使うようにしましょう。

目次


CALibRasterクラスの概要


インスタンスの作成

CALibRasterインスタンスが処理する画像は、モノクロ2値でなければなりません。
画像の背景はbit0/前景(面図形や線図形、文字列図形、記号図形)はbit1でなければなりません。
座標系はXY座標系で、原点は画像の左上隅でY軸下方向が正です。
終了時はインスタンスをdeleteするだけです。

リファレンス

// 入力
//  char*       permission;         パーミッションファイルのあるパス
//                                  あるいはパーミッション文字列(パーミッションファイルの3行目)
//  char*       amodulepath;        exeファイルのあるパス
//  char*       apppath;            一時ファイルを作成可能なパス(ログインユーザーの権限で書き込める場所)
CALibRaster(char* permission,char* amodulepath,char* apppath);
~CALibRaster();
// 初期化が成功したかどうかの問い合わせ
// 戻り値
//   1....成功
//   0....失敗(キーファイルが見つからない、期限切れ等パーミッションが無い)
int                 misinitsuccess();

サンプル
下記は、一時ファイル作成可能なパスが実行ファイルのある場所なので、管理者権限でないと使えないケース

CALibRaster* plib = new CALibRaster("c:\\Program Files\\Foo/rasteredit.kcd","c:\\Program Files\\Foo\\","c:\\Program Files\\Foo\\");
if(plib->misinitsuccess() == 0) {
   ;  // パーミッションが無い
}
delete plib;
目次


CJocrPrimクラスとの関係

ラスタ編集の対象となる画像は、CJocrPrimインスタンスによって作成保持されるプリミティブ画像の集合となります。
ユーザーは、CJocrPrimクラスのインスタンスを経由して図形にダイレクトにアクセスすることができます。
したがって、ラスタ編集の基本的な機能をCJocrPrimの機能を使って記述することもできます。ただ、CJocrPrimインスタンスで ラスタ編集の機能を記述するには、膨大な工数が必要となるため、API別にコードをまとめたものがCALibRasterクラスです。
また、線図形、文字列図形(Ver.1.1以降)、記号図形(Ver.1.1以降)という認識した図形に対応するデータクラスを導入することによって、 線分、文字、記号といった認識結果のデータとリンクした処理が実現できるようになりました。
さらに、ラスタベクタ変換クラスを内蔵することによって、1線分と1プリミティブの対応づけも自動的に行うことができるようになりました。
ラスタベクタ変換クラスについては、外部のラスタベクタ変換クラスで変換した線分を使うことができるようにもなっています。
バージョン1.1以降では、文字認識と記号認識の機能も内蔵する予定になっています。
以上の記述をまとめると、ライブラリのクラスの構成は以下のようになっています。



目次


初期化処理

初期化処理では、ドキュメントの設定と、CJocrPrimクラスのインスタンスの設定の2つの処理が必要となります。
CJocrPrimクラスのAPIについては、alprimマニュアルをご覧ください。
ダイレクトアクセスが不要な場合は、とりあえずCJocrPrimクラスのインスタンスを作ってセットするだけで構いません。
CJocrPrimインスタンスの解放も、ライブラリの外部で行います。
  1. ドキュメントの設定
    サイズ、解像度、レイヤを分離する前の画像データのアドレスを設定します。
  2. CJocrPrimクラスのインスタンスの設定
    CJocrPrimクラスのインスタンスを別途作成してアドレスを設定します。

リファレンス

// 入力
//  int             width;          // ラスタの幅(単位ピクセル)
//  int             scanlinesize;   // ラスタのスキャンラインサイズ(1行のバイト数)
//  int             height;         // ラスタの高さ(単位ピクセル)
//  int             dpi;            // ラスタの解像度
//  unsigned char*  pdatamono;      // ラスタデータ(モノクロ1bit深度)
//                                     テキスト、線図形、面図形に分けて初期化する。オリジナルデータは
//                                     テキスト+線図形+面図形=pdatamonoであることが望ましい
//                                     将来的に"記号"レイヤが増える予定
void               msetdocument(int width,int scanlinesize,int height,int dpi,unsigned char* pdatamono);
// プリミティブに対してダイレクトにアクセスしたい時はCJocrPrimクラスを経由してアクセスする
// CJocrPrimインスタンスのfeatureのcyフィールドがラスタ編集用に予約されているので変更しないこと
void               msetpjocrprim(CJocrPrim* pjocrprim);

目次


CLightPolylineクラスとの関係

CLightPolylineは、線図形の数だけインスタンスを生成します。線図形(ラスタ)と線ベクタ(頂点、線幅)とを リンクすることによって頂点や辺に対する編集者の操作をラスタに反映することができるようになります。 頂点や辺、線幅、線図形と線ベクタのリンクの情報はCALibRasterクラスではなくCLightPolylineクラスのAPIを使って取得します。

CALibRasterクラスでは、CLightPolylineクラスのインスタンス数の取得APIとCLightPolylineインスタンスアドレスを取得するAPI を提供しています。さらに、CJocrPrimの図形要素(PRIMITIVE)からCLightPolylineインスタンスを検索するAPIによって、 図形要素→線ベクタのリンクが取得できます。線ベクタ→図形要素のリンクの取得は、CLightPolylineクラスのAPIを使って取得します。

リファレンス

// ポリラインに対しては、CLightPolylineのインスタンスを取得してアクセスする
// CLightPolylineインスタンスの数の取得
// 戻り値
//  CLightPolylineインスタンスの数
int                 mgetlightpolylinenum();
// CLightPolylineインスタンスの取得
// 入力
//  int             polylineoffset;         ポリラインオフセット(0〜mgetlightpolylinenum()-1)
//                                          範囲外のオフセットを指定するとMemory Protection fault
// 戻り値
//  CLightPolylineインスタンスアドレス
CLightPolyline*		mgetlightpolyline(int polylineoffset);
// ポリラインと対応するプリミティブのアドレスの取得
// CLightPolylineクラスのAPIを間接的に呼び出すだけ
// 入力
//  int             polylineno;         ポリライン番号(オフセット)
// 戻り値
//  NULL以外....プリミティブのアドレス
//  NULL........対応するプリミティブが無かった
struct _PRIMITIVE*  mgetprimitive(int polylineno);
// プリミティブに対応するCLightPolylineインスタンスのアドレスの取得
// 入力
//  struct _PRIMITIVE* prim;            プリミティブアドレス
// 戻り値
//  NULL以外....CLightPolylineインスタンスのアドレス
//  NULL........対応するCLightPolylineインスタンスが無かった
CLightPolyline*     mgetlightpolylinefromprim(struct _PRIMITIVE* prim);
// 平均ポリライン線幅の取得
// 戻り値
//  平均のポリライン線幅を返す
double              mgetmeanpolylinewidth();

目次


画像のレイヤ設定

対象となる画像データはモノクロ2値データだけです。
画像は、少なくとも面図形と線図形の2つのレイヤに分離する必要があります。
バージョン1では、文字列図形、面図形、線図形の3つのレイヤに分離することもできますが、文字認識機能を内蔵していないため 文字レイヤの図形に対して、文字固有の処理(テキストエディタのような編集や、フォントの変更など)を適用することはできません。
バージョン1.1では、文字認識機能を内蔵するとともに、記号認識+記号レイヤを追加することができるようになります。

現状では線図形と面図形の2つのレイヤに分離するAPIと線図形と面図形と文字列図形の3つのレイヤに分離するAPIの2種類があります。

リファレンス
CALibRasterライブラリでは、元の図面の画像を文字列図形、線図形、面図形に分離して初期化時に指定する必要があります。
この分離は、ライブラリ外で行っても構いませんが、ライブラリでも分離機能を提供しています。
また、線図形の最大線幅も初期化のAPIの入力として必要ですが、ライブラリでも最大線幅を取得することができます。
最大線幅は、たとえばライブラリが推定した値を使わずに、ユーザーが指定した値を用いることも可能です。
画像の分離は、文字列図形、線図形、面図形に分離するmalibseplineandtextと、線図形と面図形に分離するmalibseplineがあります。

// テキスト版、線図形、面図形分離
// 入力
//  int             amincharnum;       文字列図形内の最少プリミティブ数
//  double          amaxcharsize;      最大文字サイズ
//  unsigned char*  pdatatext;         テキストレイヤ
//  unsigned char*  pdataline;         線図形レイヤ
//  unsigned char*  pdatapolygon;      面図形レイヤ
// 出力
//  double&         linewidth;         最大線幅
//                                     平均線幅+標準偏差×3×1.5+2.5
//                                     統計的に99.7%の線図形が入る線幅
//                                     100本の線の中に1本だけ太い線が混ざっているなどというケースでは
//                                     太い線は面図形となることもある。
// 戻り値
//  0....正常終了
//  負...エラー
int                 malibseplineandtext(double& linewidth,int amincharnum,double amaxcharsize,
    unsigned char* pdatatext,unsigned char* pdataline,unsigned char* pdatapolygon);
// 線図形、面図形分離
// malibseplineandtextと同様に分離した後に、pdatatextとpdatapolygonを合成する。文字をあらかじめ分離しないと、
// ストローク幅によって文字が線図形になったり、面図形になったりして編集しにくくなるため。
// 入力
//  int             amincharnum;       文字列図形内の最少プリミティブ数
//  double          amaxcharsize;      最大文字サイズ
//  unsigned char*  pdataline;         線図形レイヤ
//  unsigned char*  pdatapolygon;      面図形レイヤ
// 出力
//  double&         linewidth;         最大線幅
// 戻り値
//  0....正常終了
//  負...エラー
int                 malibsepline(double& linewidth,int amincharnum,double amaxcharsize,unsigned char* pdataline,unsigned char* pdatapolygon);
テキスト画像、線図形、面図形の画像バッファと振り分け先のレイヤ番号、最大線幅を引数として、画像のレイヤ設定を 実行します。ライブラリでレイヤは256個使えますが、ライブラリで数個のレイヤ(特に250以上)を作業領域に使うため、 動作保証レイヤを0〜215の216個(6の3乗個)とします。
あらかじめ、ベクタ情報を与えていない時は内蔵のラスタベクタ変換機能によって、線図形レイヤの図形がCLightPolylineの インスタンスと自動的にリンクされます。
線図形レイヤを外部のラスタベクタ変換機能によって、ポリラインに変換して、その情報mregistpolyline()APIで指定した場合は 指定したポリライン情報と線図形レイヤの図形がリンクされます。
線図形レイヤの一部だけをポリライン指定した場合、ポリラインの下に無い線図形は、レイヤ0に残ったままとなります。
また、1ポリラインが1図形とリンクするため、ポリラインを適当な頂点で分けて指定すると、線図形も同じ箇所で分かれたものとして処理されます。
// CJocrPrimインスタンスをセット後に画像バッファを指定して
// プリミティブを、一般図形/テキスト/線図形にレイヤ分割しつつ読み込む
//       pdatatext+pdataline+pdatapolygonがmsetdocumentのpdatamonoになっていることが条件
//       バッファは、msetdocumentで指定したサイズのものを2〜3つ確保する。
// 1....ポリライン認識のためのラスタベクタ変換をライブラリに任せる
// 入力
//  int             layertext;          テキストを配置するレイヤ(0〜215、0以外を推奨)
//  int             layerline;          線図形を配置するレイヤ(0〜215、0以外を推奨)
//  int             layerpolygon;       面図形を配置するレイヤ(0〜215、0以外を推奨)
//  int             linewidth;          線図形の線幅を与える
//                                      malibseplineandtextあるいはmalibseplineから出力される線幅を引数とする
// 入出力
//  unsigned char*  pdatatext;          テキストレイヤ(msetdocumentで指定したサイズ)
//  unsigned char*  pdataline;          線図形レイヤ(msetdocumentで指定したサイズ)
//  unsigned char*  pdatapolygon;       面図形レイヤ(msetdocumentで指定したサイズ)
// 戻り値
//  0....正常終了
//  負...エラー
int                 makeprim3layer(int layertext,int layerline,int layerpolygon,int linewidth,
    unsigned char* pdatatext,unsigned char* pdataline,unsigned char* pdatapolygon);
int                 makeprim2layer(int layerline,int layerpolygon,int linewidth,
    unsigned char* pdataline,unsigned char* pdatapolygon);
// 2....ポリライン認識のためのラスタベクタ変換をアプリケーション側で行う場合makeprim3layerの前に実行する。
//       注意1:必ず、msetdocument/msetpjocrprimの後に呼び出すこと。
//       注意2:線図形レイヤの全線分に対応したポリラインを設定すること(線図形全てをラスベク変換)
// 1本でもmregistpolylineで登録していると、内蔵のラスタベクタ変換は呼び出されない。
// 2-1...ポリラインの登録
//       線、テキスト、面図形に分離後、線図形レイヤをライブラリ外でポリラインに変換する
//       idの仕様には注意が必要で、1以上の正数かつポリラインごとにユニークな値を与えることが必要
//       たとえば最初のポリラインのidは1で2番目は2とする。0や負の数はidとして使えない(内部で別の意味を持つため)。
// 入力
//  int         id;                 1以上ポリラインid(ユニークな数値を1以上の値で与える)
//  int         vertexnum;          ポリライン頂点数
//  int*        px;                 ポリライン頂点座標x
//  int*        py;                 ポリライン頂点座標y
// 戻り値
//  負          エラー
//  0           正常終了
int                 mregistpolyline(int id,int vertexnum,int* px,int* py);

サンプル

// 3レイヤ分離のコード
{
    // monodata..............モノクロ画像バッファ
    // monowidth..........モノクロ画像バッファの幅(単位ピクセル)
    // monoscanlinesize...モノクロ画像バッファのスキャンラインサイズ(単位バイト)
    // monoheight.........モノクロ画像バッファの高さ(単位ピクセル)
    // mdpi...............解像度
    unsigned char*	pdatatext = (unsigned char*)malloc(monoscanlinesize * monoheight * 3);
    if(pdatatext == NULL) return(MEMORY_SHORTAGE);
    unsigned char* pdataline = pdatatext + monoscanlinesize * monoheight;
    unsigned char* pdatapolygon = pdataline + monoscanlinesize * monoheight;
    double      dlinewidth = maliblinewidth;		// maliblinewidthにはデフォルト値が入っている
    mplibraster->msetdocument(monowidth,monoscanlinesize,monoheight,mdpi,monodata);
    // 一般図形/テキスト/線図形にレイヤ分割
    int         linewidth = (int)(dlinewidth + 0.5);
    int i1 = mplibraster->malibseplineandtext(linewidth,amincharnum,amaxcharsize,pdatatext,pdataline,pdatapolygon);
    if(i1 < 0) {
        free(pdatatext);
        return(i1);
    }
    // LAYER_TEXTはテキストレイヤ/LAYER_BETAは面画像レイヤ/0は線図形レイヤ
    i1 = mplibraster->makeprim3layer(LAYER_TEXT,0,LAYER_BETA,linewidth,pdatatext,pdataline,pdatapolygon);
    if(i1 < 0) {
        free(pdatatext);
        return(i1);
    }
    free(pdatatext);
    if(i1 < 0) return(-1);
    // 全図形のレイヤをバックアップ
    mplibraster->mbackuplayerinfo(-1);
}
// 2レイヤ分離のコード
{
    // monodata..............モノクロ画像バッファ
    // monowidth..........モノクロ画像バッファの幅(単位ピクセル)
    // monoscanlinesize...モノクロ画像バッファのスキャンラインサイズ(単位バイト)
    // monoheight.........モノクロ画像バッファの高さ(単位ピクセル)
    // mdpi...............解像度
    unsigned char*	pdataline = (unsigned char*)malloc(monoscanlinesize * monoheight * 2);
    if(pdataline == NULL) return(MEMORY_SHORTAGE);
    unsigned char* pdatapolygon = pdataline + monoscanlinesize * monoheight;
    double      dlinewidth = maliblinewidth;		// maliblinewidthにはデフォルト値(十分大きな線幅1mm〜1.5mm程度)が入っている
    mplibraster->msetdocument(monowidth,monoscanlinesize,monoheight,mdpi,monodata);
    // 一般図形/線図形にレイヤ分割
    int         linewidth = (int)(dlinewidth + 0.5);
    int i1 = mplibraster->malibsepline(linewidth,amincharnum,amaxcharsize,pdataline,pdatapolygon);
    if(i1 < 0) {
        free(pdataline);
        return(i1);
    }
    // LAYER_BETAは一般画像レイヤ/0は線図形レイヤ
    i1 = mplibraster->makeprim2layer(0,LAYER_BETA,linewidth,pdataline,pdatapolygon);
    if(i1 < 0) {
        free(pdataline);
        return(i1);
    }
    free(pdataline);
    if(i1 < 0) return(-1);
    // 全図形のレイヤをバックアップ
    mplibraster->mbackuplayerinfo(-1);
}

目次


画像の表示

レイヤ別にパレット指定して、複数レイヤに分けられられた図形データをカラー表示することができます。
この処理は、かなりCPU負荷のかかる処理なので、
  1. 低速度で高画質

  2. 中速度で中品質

  3. 高速度で低品質


の3種類のAPIを用意しています。上記は倍率0.15倍表示のケースで、0.25倍以上だと高品質と中品質の差はほとんどありません。 0.5倍以上であれば高速低品質で十分です。

リファレンス

// レイヤ別のパレットを設定する
// レイヤ0〜255に対してレイヤ別のパレットが割り当てられ、表示用のAPIで参照される
// 入力	
//  void*       palette;            sizeof(RGBQUAD) * 256の配列
void				makedefaultpalette(void* palette);
// いずれのAPIも指定したパレットの256色と、256のレイヤを対応付けてカラー表示する
// makedispdatafast:Nearest Neighbor法によって表示領域の画素に対応するプリミティブの色を取得する
//                   高速だが、低倍率の縮小画像では細い線などがかすれたりする
// makedispdataNN  :表示領域よりが入るサイズの2^nあるいは1/2^nの画像を面積平均法で取得したあとに
//                   Nearest Neighbor法で目的のサイズにする。makedispdatafastよりも遅いが画質は改善される。
//                   倍率0.5以下の場合に推奨
// makedispdatabilinear:makedispdataNNと面積平均法までは一緒で、その後bilinear法で拡大・縮小する。
//                   3つのAPIの中では、最も遅いが高品質の表示画像が得られる。
//                   倍率0.25以下の場合に推奨
// いずれも画像データは24ビットフルカラー画像で返される
// 入力
//  int             width;          表示領域のサイズ(クライアントウィンドウのサイズ、単位ピクセル)
//  int             height;         表示領域のサイズ(クライアントウィンドウのサイズ、単位ピクセル)
//  int             scrollposx;     表示するデータの左上の座標(スクロール開始座標、実画像データでの座標、単位ピクセル)
//  int             scrollposy;
//  int             scanlinesize;   表示する24ビットデータのスキャンラインサイズ(DIBとして表示するため4バイトバウンダリにしたりする)
//  double          amag;           表示倍率
//  unsigned char*  pdispdata;      表示データバッファ(呼ぶ側で確保する)
void                makedispdatalayerbilinear(int width,int height,int scrollposx,int scrollposy,int scanlinesize,double amag,unsigned char* pdispdata);
void                makedispdatalayerNN(int width,int height,int scrollposx,int scrollposy,int scanlinesize,double amag,unsigned char* pdispdata);
void                makedispdatalayerfast(int width,int height,int scrollposx,int scrollposy,int scanlinesize,double amag,unsigned char* pdispdata);

サンプル

// レイヤパレットカラーの設定
// RGBQUAD    mdefaultpalette[256];で定義されている
void CALData::makedefaultpalette()
{
    // とりあえずmdefaultpalette[215]まで6^3色のパレットを設定する
    // R/G/Bそれぞれ(0,51,102,153,204,255)の値を取る
    for(int i = 0 ; i < 216 ; i++) {
        mdefaultpalette[i].rgbBlue  = (i % 6) * 51;
        mdefaultpalette[i].rgbGreen = ((i / 6) % 6) * 51;
        mdefaultpalette[i].rgbRed = (i / 36) * 51;
        mdefaultpalette[i].rgbReserved = 0;
    }
    // mdefaultpalette[216]〜mdefaultpalette[255]は白
    for(; i < 256 ; i++) {
        mdefaultpalette[i].rgbBlue  = 0xff;
        mdefaultpalette[i].rgbGreen = 0xff;
        mdefaultpalette[i].rgbRed = 0xff;
        mdefaultpalette[i].rgbReserved = 0;
    }
    // 予約レイヤ
    // 下記3つは、デモアプリ専用のレイヤ処理のため、特にまねする必要は無い
    // LAYER_SELECTNOISE0...ノイズ選択0レイヤ(緑)
    // LAYER_SELECTNOISE1...ノイズ選択1レイヤ(グレイ)
    // LAYER_WHITE...削除レイヤ
    mdefaultpalette[LAYER_SELECTNOISE0].rgbBlue  = 0;
    mdefaultpalette[LAYER_SELECTNOISE0].rgbGreen = 255;
    mdefaultpalette[LAYER_SELECTNOISE0].rgbRed = 0;
    mdefaultpalette[LAYER_SELECTNOISE1].rgbBlue  = 128;
    mdefaultpalette[LAYER_SELECTNOISE1].rgbGreen = 128;
    mdefaultpalette[LAYER_SELECTNOISE1].rgbRed = 128;
    mdefaultpalette[LAYER_WHITE].rgbBlue  = 255;
    mdefaultpalette[LAYER_WHITE].rgbGreen = 255;
    mdefaultpalette[LAYER_WHITE].rgbRed = 255;
    // 選択された図形のレイヤ、テキストレイヤ、面図形レイヤの色を設定
    // LAYER_SELECT...通常選択レイヤは明るい緑
    // LAYER_TEXT...テキストレイヤは明るい水色
    // LAYER_BETA...面図形レイヤは黄色
    mdefaultpalette[LAYER_SELECT].rgbBlue  = 102;
    mdefaultpalette[LAYER_SELECT].rgbGreen = 255;
    mdefaultpalette[LAYER_SELECT].rgbRed = 102;
    mdefaultpalette[LAYER_TEXT].rgbBlue  = 255;
    mdefaultpalette[LAYER_TEXT].rgbGreen = 255;
    mdefaultpalette[LAYER_TEXT].rgbRed = 0;
    mdefaultpalette[LAYER_BETA].rgbBlue  = 0;
    mdefaultpalette[LAYER_BETA].rgbGreen = 255;
    mdefaultpalette[LAYER_BETA].rgbRed = 255;
	// パレット設定APIの呼び出し
    mplibraster->makedefaultpalette(mdefaultpalette);
}
// 入力
//  int             quality;                0...高品質・低速
//                                          1...中品質・中速
//                                          2...低品質・高速
//  int             width;                  クライアント領域の幅(単位ピクセル)
//  int             height;                 クライアント領域の高さ(単位ピクセル)
//                                          CRect crect;GetClientRect(&crect);で取得したもの
//  int             scrollposx;             スクロール原点x
//  int             scrollposy;             スクロール原点y
//  double          amag;                   表示倍率
// 出力
//  BITMAPINFO*&    pbi;                    BITMAPINFO
//  unsigned char*& pdispdata;              表示画像データバッファ
///////
// mplibraster....CALibRasterクラスのインスタンス
// 表示クラスではmakedispdatalayertopコール後に以下のようになる
// void CScancalcView::OnDraw(CDC* pDC)
// {
// int ret = SetDIBitsToDevice(pDC->m_hDC,
//              0,                              // XDest
//              0,                              // YDest
//              (WORD)pbi->bmiHeader.biWidth,   // Source Rect width
//              (WORD)pbi->bmiHeader.biHeight,  // Source Rect height
//              0,                              // XSrc
//              0,                              // YSrc
//              0,                              // Scanstart
//              (WORD)pbi->bmiHeader.biHeight,  // ScanEnd
//              (LPSTR)pdispdata,
//              (LPBITMAPINFO)pbi,DIB_RGB_COLORS);
// .....
void CScancalcDoc::makedispdatalayertop(int quality,int width,int height,int scrollposx,int scrollposy,
                                        double amag,BITMAPINFO*& pbi,unsigned char*& pdispdata)
{
    if(pbi) {
        free(pbi);
        pbi = NULL;
    }
    if(pdispdata) {
        free(pdispdata);
        pdispdata = NULL;
    }
    if(pbi == NULL) {
        pbi = (BITMAPINFO *)malloc(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256);
    }
    pbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    pbi->bmiHeader.biPlanes = 1;
    pbi->bmiHeader.biBitCount = 24;        // 24ビットフルカラー画像
    pbi->bmiHeader.biWidth = width;
    pbi->bmiHeader.biHeight = height;
    pbi->bmiHeader.biCompression = 0;
    pbi->bmiHeader.biClrUsed = 0;
    // 4バイトバウンダリ
    int    scanlinesize = ((pbi->bmiHeader.biWidth * 3) / 4 + ((pbi->bmiHeader.biWidth * 3) % 4 > 0)) * 4;
    // すべての画像をDIBとする
    pbi->bmiHeader.biSizeImage = scanlinesize * pbi->bmiHeader.biHeight;
    pbi->bmiHeader.biXPelsPerMeter = 0;
    pbi->bmiHeader.biYPelsPerMeter = 0;
    pbi->bmiHeader.biClrImportant = 0;
    if(pdispdata == NULL) {
        pdispdata = (unsigned char*)malloc(scanlinesize * pbi->bmiHeader.biHeight);
    }
    // 薄いグレイで背景(画像の無い部分)を埋める
    memset(pdispdata,192,scanlinesize * pbi->bmiHeader.biHeight);
    if(mimagenum > 0) {
        switch(quality) {
        case 0:
            mplibraster->makedispdatalayerbilinear(width,height,scrollposx,scrollposy,scanlinesize,amag,pdispdata);
            break;
        case 1:
            mplibraster->makedispdatalayerNN(width,height,scrollposx,scrollposy,scanlinesize,amag,pdispdata);
            break;
        case 2:
            mplibraster->makedispdatalayerfast(width,height,scrollposx,scrollposy,scanlinesize,amag,pdispdata);
		    break;
        }
    }
}
目次


図形をレイヤ移動する(あるいは図形の選択操作)

図形をレイヤ移動します。たとえば、ライブラリユーザー側が適当なレイヤを「選択図形」のレイヤであると決めたら、 選択図形のレイヤへ移動した図形は選択されていると判断することができます。元のレイヤに戻せば、図形は非選択状 態になったということです。
レイヤ移動操作はCJocrPrimクラスのAPIを使っても行うことができます。詳しくはalprimライブラリのマニュアルをご 覧ください。
alibrasterライブラリでは、必要最小限の以下の3つのAPIを用意しています。APIの内部では、CJocrPrimクラスの APIを呼び出すだけです。
CJocrPrimクラスでは、ポリゴンや斜め長方形内部のプリミティブの移動や円形度や線幅などの特徴を使ったプリミ ティブ移動など、alibrasterクラスよりも多彩なAPIがあります。
  1. 指定した長方形内部の図形と枠にかかる図形をレイヤ移動する

  2. 指定した長方形内部の図形をレイヤ移動する

  3. 上限と下限を指定した範囲の面積を持つ図形をレイヤ移動する
これらのAPIでは、移動元のレイヤも指定できるので、自由度の高いレイヤ移動操作が可能になっています。
たとえば、選択レイヤにあるポリラインが分かるように頂点を正方形で強調表示した場合、以下の画像のようになります。


alibrasterライブラリでは、レイヤ移動サポートのための特殊なAPIとして、以下の2つを提供しています。
文字や面図形を同じレイヤに移動した後に、元に戻すケースでは戻すべき元のレイヤが分からないとアンドゥ機能を使う以外に 戻しようがありません。そこで、適切なタイミングで図形の所属するレイヤをバックアップしておいて、必要なときにリストア するAPIを提供しています。
所属レイヤの情報は、プリミティブの特徴レコードPRIMFEATUREのlengthフィールドに保存されます。
  1. 現在のレイヤ配置情報をプリミティブの特徴レコードにバックアップしておく。
    makeprim2layer/makeprim3layer直後にコールする。
  2. 特徴レコードにバックアップしておいた、レイヤ配置情報からリストアする。
    適当なタイミングでコールする。

リファレンス

// レイヤ情報のバックアップ
// レイヤ情報は、PRIMFEATURE::lengthフィールドにバックアップされる
// 他のフィールドを使うときはCJocrPrimクラスのAPIを使って自前で記述する
// 入力
//  int             layer;              バックアップする対象レイヤ(0〜215、-1は全レイヤ)
//  struct _PRIMITIVE* prim;            対象プリミティブのみバックアップ
void                mbackuplayerinfo(int layer);
void                mbackuplayerinfo(int layer,struct _PRIMITIVE* prim);
// レイヤ情報のリストア
// レイヤ情報は、PRIMFEATURE::lengthフィールドにバックアップされる
// 他のフィールドを使うときはCJocrPrimクラスのAPIを使って自前で記述する
// 入力
//  int             layer;              バックアップする対象レイヤ(0〜215、-1は全レイヤ)
//  struct _PRIMITIVE* prim;            対象プリミティブのみリストア
void                mrestorelayerinfo(int layer);
void                mrestorelayerinfo(int layer,struct _PRIMITIVE* prim);
// 指定した面積のプリミティブの移動
// CJocrPrim::mpveprimpixel(amin,amax,from,to);をコールするだけ
int                 moveprimpixel(int amin,int amax,int from,int to);
// 矩形内にかかるオブジェクトをfromからtoへ移動
// CJocrPrim::mpveprimrecthook(x1,y1,x2,y2,from,to,0);をコールするだけ
int                 moveprimrecthook(int x1,int y1,int x2,int y2,int from,int to);
// 矩形内に完全に含まれるオブジェクトをfromからtoへ移動
// CJocrPrim::mpveprimrect(x1,y1,x2,y2,from,to,0);をコールするだけ
int                 moveprimrect(int x1,int y1,int x2,int y2,int from,int to);

目次


CLightPolylineクラスのAPI

線ベクタ(ポリライン)の頂点数、各頂点の座標、各頂点の選択状態、線ベクタ(ポリライン)の線幅、外接矩形、 CLightPolylineインスタンスに結びついた図形要素(PRIMITIVE構造体)のアドレスの取得のためのAPIを提供します。

リファレンス

// ポリラインの有効無効の指定
// 入力
//  int             unused;         1の場合無効に、0の場合有効に
void                msetunused(int unused = 1) {munused = unused;}
// 戻り値
//  1....ポリラインが無効の場合
//  0....ポリラインが有効の場合
int                 misunused() {return (munused == 1);}
// 戻り値
//  ポリラインの外接矩形の左上x、左上y、右下x、右下y座標(単位ピクセル)を返す
int                 mgetleft() {return mleft;}
int                 mgettop() {return mtop;}
int                 mgetright() {return mright;}
int                 mgetbottom() {return mbottom;}
// 戻り値
//  ポリラインに結びついたプリミティブのオフセットを返す
//  CAlibRaster::mpjocrprimにおけるプリミティブとなっている
int                 mgetprimoffset() {return mprimoffset;}
// ポリラインに結びついたプリミティブオフセットの設定
// 入力
//   int            offset;         CAlibRaster::mpjocrprimにおけるプリミティブオフセット
void                msetprimoffset(int offset) {mprimoffset = offset;}
// ポリラインの線幅の計算
//  mcalclwidth()後にmgetlwidthで線幅にアクセスできる
//  msetlwidthによってアプリケーション側から別途線幅を設定することも可能
void                mcalclwidth();
// 戻り値
//  線幅
inline double       mgetlwidth() {return mlwidth;}
// 入力
//  double          lwidth;             線幅
void                msetlwidth(double lwidth) {mlwidth = lwidth;}
// ポリラインの頂点数・頂点座標アクセス
// 戻り値
//  ポリラインの頂点数
inline int          mgetvertexnum() {return mvertexnum;}
// 戻り値
//  ポリラインの頂点座標配列の先頭アドレス
inline int*         mgetx() {return mpx;}
inline int*         mgety() {return mpy;}
// 戻り値
//  ポリラインの頂点座標mgetx(n)はmgetx()[n]と同じ
// 入力
//  int             n;                  頂点オフセット
inline int          mgetx(int n) {return mpx[n];}
inline int          mgety(int n) {return mpy[n];}
// ポリラインの頂点の座標設定
// 入力
//  int             n;                  頂点オフセット
//  int             x,y;                頂点座標
inline void         msetx(int n,int x);
inline void         msety(int n,int y);
// CLightPolyline構築用
// 頂点配列の登録
// 入力
//  int             vertenum;           頂点数
//  int*            px;                 頂点座標配列
//  int*            py;
// 戻り値
//  0....正常終了
//  負...エラー
int                 mregistvertex(int vertexnum,int* px,int* py);
// 頂点の削除
// 入力
//  int             n;                  削除する頂点オフセット
void                mdeletevertex(int n);
// インスタンスの回転
// 入力
//  double          cx;                 回転中心座標
//  double          cy;
//  double          angle;              回転角度
void                mrotate(double cx,double cy,double angle);
// 頂点の挿入
// 入力
//  int             n;                  n番目の頂点として挿入する
//  int             x,y;                挿入する頂点座標
// 戻り値
//  0....正常終了
//  負...エラー
int                 minsertvertex(int n,int x,int y);
// ポリラインの移動
// 入力
//  int             sx,sy;              相対的移動量=移動ベクトル
void                moverel(int sx,int sy);
目次


指定座標に近い頂点の取得

このAPIは、頂点の移動、頂点の削除、頂点の切断のAPIに必要なポリラインオフセットと頂点オフセットを取得するために使います。
そのほか、頂点に近づいた場合にマウスポインタの形を変える用途なども考えられます。

リファレンス

// 指定座標に最も近い頂点のポリライン番号と座標番号を得る
// 入力
//  double          x;              指定座標(x,y)
//  double          y;
//  double          th;             座標からthピクセル以下の距離の頂点を探す
//  int             layer;          ポリラインの存在するレイヤ(0〜215、-1は全てのレイヤ)
// 出力
//  int&            polylineno;     ポリライン番号(オフセット)
//  int&            vertexno;       頂点番号(始点が0)
// 戻り値
//  0               見つからなかった
//  1               見つかった
int                 mgetnearestvertex(double x,double y,double th,int layer,int& polylineno,int& vertexno);

サンプル

// OnLButtonDown/OnMouseMove/OnKeyDownなどのハンドラの先頭で呼び出す
// マウスカーソルの位置により
//  1...マウス形状の設定
//  2...コントロールポイントのサーチ
// を行う
// int      lbuttondownflag;            1...OnLButtonDownからの呼び出し、
//                                          コントロールポイント制御開始
void CScancalcView::msetmousecursor(int lbuttondownflag,UINT nFlags,CPoint point) 
{
    CScancalcDoc* pDoc = GetDocument();
    // mscrollposx,mscrollposyは実データピクセル座標でのスクロールポジション
    CPoint sp(mscrollposx,mscrollposy);

    if(pDoc->mgetimagenum() == 0) {
        SetCursor(m_cursor_normal);
    }
    else {
        // modeは動作モード
        switch(mode) {
            // 起動時は、図形選択モード
            case MODE_SELECTPRIM:
                {
                    // マウスポインタの座標を実データピクセル座標に変換している
                    double x = (point.x / mag) + mscrollposx;
                    double y = (point.y / mag) + mscrollposy;
                    double th = 16.0 / mag;    // 画面上で16.0ピクセル離れている場合は頂点付近と見なさない
                    if(th < 10.0) th = 10.0;
                    int i1 = pDoc->mgetnearestvertex(x,y,th,LAYER_SELECT,mcontrolpolylineno,mcontrolvertexno);
                    // int i1 = mplibraster->mgetnearestvertex(x,y,th,layer,polylineno,vertexno);
                    // OnLbuttonDownハンドラ
                    if(lbuttondownflag) {
                        if(i1 == 1) {
                            mchangemode(MODE_MOVEVERTEX);                   // 頂点移動モード
                        }
                        else {
                            mcontrolpolylineno = mcontrolvertexno = -1;     // 付近に頂点が無い
                        }
                    }
                    // OnMouseMove/OnLbuttonUp/OnRbuttonUp/OnRbuttonDown...ハンドラ
                    else {
                        if(i1 == 1) {
                            SetCursor(m_cursor_dragscroll);                 // 付近に頂点がある
                                                                            // 手のひら形状にする
                        }
                        else {
                            mcontrolpolylineno = mcontrolvertexno = -1;     // 付近に頂点が無い
                            SetCursor(m_cursor_normal);                     // 通常のマウスカーソルにする
                        }
                    }
                }
                break;
				............
目次


頂点の移動

ポリラインの頂点を指定した座標に移動します。移動した頂点と隣接する頂点とを結ぶ辺は、ポリラインの線幅を元に新たに描画されます。
このAPIの引数で指定するポリラインオフセットと頂点オフセットは、指定座標に近い頂点の取得APIの出力値を用いると良いでしょう。


リファレンス

// ポリラインの頂点移動
// 入力
//  int             tolayer;        移動したポリラインの移動先レイヤ
//                                  (通常選択レイヤに移動するか、何もしないか)
//  int             polylineno;     ポリライン番号(オフセット)
//  int             vertexno;       頂点番号(始点が0のオフセット)
//  int             x,y;            頂点の移動先(単位ピクセル)
// 戻り値
//  0               該当頂点が無い
//  1               移動した
//  負              エラー
int                 movevertex(int tolayer,int polylineno,int vertexno,int x,int y);
目次


頂点の削除

ポリラインの頂点を削除します。端点(両端の点)の場合、端点と隣の点を結ぶ辺は消去されます。端点以外の場合は、両側の頂点を結ぶ線が補間されます。
このAPIの引数で指定するポリラインオフセットと頂点オフセットは、指定座標に近い頂点の取得APIの出力値を用いると良いでしょう。


リファレンス

// ポリラインの頂点削除
// mgetnearestvertexで取得したポリライン番号と頂点番号で削除する頂点を指示する
// 端点を削除する場合は、削除した頂点を含む辺を削除
// 端点以外を削除する場合は、削除した頂点の前後の頂点をつなぐように補間
// 入力
//  int             tolayer;        頂点を削除したポリラインの移動先
//                                  (通常選択レイヤに移動するか、何もしないか)
//  int             polylineno;     ポリライン番号(オフセット)
//  int             vertexno;       頂点番号(始点が0)
// 戻り値
//  0               該当頂点が無い
//  1               削除した
//  負              エラー
int                 mdeletevertex(int tolayer,int polylineno,int vertexno);
目次


頂点の切断

ポリラインの頂点で2本のポリラインに切断します。分割されたポリラインは全ての編集操作において、独立した対象となります。
このAPIの引数で指定するポリラインオフセットと頂点オフセットは、指定座標に近い頂点の取得APIの出力値を用いると良いでしょう。


また初期化処理で、ポリラインの情報を与えた上で初期化することができるので、 4隅のコーナーであらかじめポリラインを分割しておくという使い方もすることができます。全て辺単位でポ リラインを分割しておくという過激な初期化方法も可能ですが2本のポリラインをつなげるというAPIは今のと ころ無いので、最初はつなげておいて後で分割するという使い方の方が融通が利きます。

リファレンス

// ポリラインの頂点切断
// 入力
//  int             tolayer;        切断したポリラインの移動先
//                                  (元のレイヤのままでもいいし、選択レイヤに移動しても良い)
//  int             polylineno;     ポリライン番号(オフセット)
//  int             vertexno;       頂点番号(始点が0)
// 戻り値
//  0               該当頂点が無い
//  1               切断した
//  負              エラー
int                 mseparatevertex(int tolayer,int polylineno,int vertexno);
目次


頂点の挿入

指定した座標の近くのポリラインの辺上に新しく頂点を設けます。挿入した頂点を移動するなどして単純なポリラインを 複雑なポリラインへと編集することができます。ポリラインはlayerに存在するものが挿入対象となります。 すでにある頂点の近くには頂点を挿入することはできません。具体的には挿入位置が前後の頂点から 線幅×10ピクセル未満の場合は頂点挿入をしません。



リファレンス

// 指定レイヤのポリラインに頂点挿入
// 入力
//  int             layer;          レイヤ(0〜215,-1は全レイヤ)
//  int             x,y;            指定座標(x,y)からthピクセル以内にある辺に挿入
//  double          th;
//    注意:挿入位置が前後の頂点から線幅×10ピクセル未満の場合は頂点挿入をしない
// 戻り値
//  負              エラー
//  0               頂点を挿入しなかった
//  1               頂点を挿入した
int                 minsertvertex(int layer,int x,int y,double th);
目次


線図形に対する画像処理

線図形に対して、細線化、太線化の処理を適用します。細線化は線幅1となるまで繰り返し実行することができます。
ポリラインはlayerに存在するものが処理対象となります。


線図形を、自動的に推定した線幅あるいは指定した線幅でレンダリングすることができます。
ポリラインはlayerに存在するものが処理対象となります。


リファレンス

// 指定レイヤのポリラインの太線化
// 指定レイヤのポリラインの細線化
// 入力
//  int             layer;          ポリラインの存在するレイヤ(0〜215、-1は全てのレイヤ)
//  int             tolayer;        太線化、細線化したポリラインの移動先レイヤ
//                                  (元のレイヤのままでもいいし、選択レイヤに移動しても良い)
// 戻り値
//  負              エラー
//  0以上           太線化、細線化ポリライン数
int                 mfatpolyline(int layer,int tolayer);
int                 mthinpolyline(int layer,int tolayer);
// 指定レイヤのポリラインのレンダリング
// 入力
//  int             layer;          ポリラインの存在するレイヤ(0〜215、-1は全てのレイヤ)
//  int             tolayer;        レンダリングしたポリラインの移動先レイヤ
//                                  (元のレイヤのままでもいいし、選択レイヤに移動しても良い)
// 戻り値
//  負              エラー
//  0以上           レンダリングしたポリライン数
int                 mrenderpolyline(int layer,int tolayer);
目次


文字列図形、線図形、面図形の削除

文字列図形、線図形、面図形を削除することができます。バージョン1では、文字列図形と面図形は同じ扱いとなっています。
たとえば線図形を削除した場合、以下のような画面となります。


リファレンス

// 指定レイヤのプリミティブ(ポリライン含む)削除
// 入力	
//  int             layer;          削除対象のレイヤ(0〜215、このAPIでは全レイヤを表す-1は引数として使えない)	
// 戻り値
//  負              エラー
//  0以上           削除プリミティブ数
int                 mdeleteprimitive(int layer);
目次


文字列図形、線図形、面図形の移動、コピー

指定した図形を移動、コピーすることができます。図形の指定方法は以下の3通りあります。
  1. 指定した矩形にかかる図形を移動、コピー。内部の図形も移動される。
  2. 指定した矩形内部の図形を移動、コピー。長方形枠にかかる図形は除外される。
  3. 指定したレイヤの図形を移動、コピーする。
図形の指定後は、移動方向(単位ラジアン)と移動量(単位ピクセル)を指定します。

線図形を移動する例



線図形をコピーする例



リファレンス

// プリミティブ(ポリライン含む)移動(長方形内部+枠上)
// 入力
//  int             copyflag;       1....コピー/0....移動
//  int             tolayer;        レンダリングしたプリミティブの移動先レイヤ
//                                  (元のレイヤのままでもいいし、選択レイヤに移動しても良い)
//  int             x1,y1,x2,y2;    (x1,y1)-(x2,y2)で指定される長方形にフックされるプリミティブを移動する
//  int             vx,vy;         移動ベクトル(方向と移動量)
// 戻り値
//  負              エラー
//  0以上           移動プリミティブ数
int                 moveprimitivehook(int copyflag,int tolayer,int x1,int y1,int x2,int y2,int vx,int vy);
// プリミティブ(ポリライン含む)移動(長方形内部)
// 入力
//  int             copyflag;       1....コピー/0....移動
//  int             tolayer;        レンダリングしたプリミティブの移動先レイヤ
//                                  (元のレイヤのままでもいいし、選択レイヤに移動しても良い)
//  int             x1,y1,x2,y2;    (x1,y1)-(x2,y2)で指定される長方形に完全に囲まれるプリミティブを移動する
//  int             vx,vy;         移動ベクトル(方向と移動量)
// 戻り値
//  負              エラー
//  0以上           移動プリミティブ数
int                 moveprimitiveinner(int copyflag,int tolayer,int x1,int y1,int x2,int y2,int vx,int vy);
// プリミティブ(ポリライン含む)移動(指定レイヤ)
// 入力
//  int             copyflag;       1....コピー/0....移動
//  int             layer;          移動するプリミティブのあるlayer(0〜215,-1は全レイヤ)
//  int             tolayer;        レンダリングしたプリミティブの移動先レイヤ
//                                  (元のレイヤのままでもいいし、選択レイヤに移動しても良い)
//  int             vx,vy;              移動ベクトル(方向と移動量)
// 戻り値
//  負              エラー
//  0以上           移動プリミティブ数
int                 moveprimitivelayer(int copyflag,int layer,int tolayer,int vx,int vy);
目次


文字列図形、線図形、面図形の回転

指定した図形を回転することができます。図形の指定方法は以下の3通りあります。
  1. 指定した矩形にかかる図形を回転。内部の図形も回転される。
  2. 指定した矩形内部の図形を回転。長方形枠にかかる図形は除外される。
  3. 指定したレイヤの図形を回転する。
図形の指定後は、回転の中心と回転角度(単位ラジアン)を指定します。



リファレンス

// 図形プリミティブの回転(長方形内部+枠上)
// 入力
//  int             copyflag;       1....コピー/0....移動
//  int             tolayer;        レンダリングしたプリミティブの移動先レイヤ
//                                  (元のレイヤのままでもいいし、選択レイヤに移動しても良い)
//  int             x1,y1,x2,y2;    (x1,y1)-(x2,y2)で指定される長方形にフックされるプリミティブを移動する
//  double          cx,cy;          回転中心
//  double          angle;          回転角度ラジアン(原点-----0)
//                                                           ↓方向が正
// 戻り値
//  負              エラー
//  0以上           回転プリミティブ数
int                 mrotateprimitivehook(int copyflag,int tolayer,int x1,int y1,int x2,int y2,double cx,double cy,double angle);
// 図形プリミティブの回転(長方形内部)
// 入力
//  int             copyflag;       1....コピー/0....移動
//  int             tolayer;        レンダリングしたプリミティブの移動先レイヤ
//                                  (元のレイヤのままでもいいし、選択レイヤに移動しても良い)
//  int             x1,y1,x2,y2;    (x1,y1)-(x2,y2)で指定される長方形内部のプリミティブを移動する
//  double          cx,cy;          回転中心
//  double          angle;          回転角度ラジアン(原点-----0)
//                                                           ↓方向が正
// 戻り値
//  負              エラー
//  0以上           回転プリミティブ数
int                 mrotateprimitiveinner(int copyflag,int tolayer,int x1,int y1,int x2,int y2,double cx,double cy,double angle);
// 指定レイヤの図形プリミティブの回転
// 入力
//  int             copyflag;       1....コピー/0....移動
//  int             layer;          プリミティブの存在するレイヤ(0〜215、-1は全てのレイヤ)
//  int             tolayer;        レンダリングしたポリラインの移動先レイヤ
//                                  (元のレイヤのままでもいいし、選択レイヤに移動しても良い)
//  double          cx,cy;          回転中心
//  double          angle;          回転角度ラジアン(原点-----0)
//                                                           ↓方向が正
// 戻り値
//  負              エラー
//  0以上           回転プリミティブ数
int                 mrotateprimitivelayer(int copyflag,int layer,int tolayer,double cx,double cy,double angle);
目次


文字列図形、線図形、面図形の拡大・縮小

指定した図形を拡大・縮小することができます。線図形を拡大・縮小した場合、 線幅は変わりませんが、線図形を面図形として拡大・縮小した場合は、線幅が 変わります。文字列図形を拡大・縮小した場合は、文字のストローク幅が変わります。
図形の指定方法は以下の3通りあります。この機能は、バージョン1の機能ですが、 α版(2008年1月リリース)には含まれていません。

  1. 指定した矩形にかかる図形を拡大・縮小。内部の図形も拡大・縮小される。
  2. 指定した矩形内部の図形を拡大・縮小。長方形枠にかかる図形は除外される。
  3. 指定したレイヤの図形を拡大・縮小する。
図形の指定後は、拡大・縮小の原点を指定します。図形の中心を原点とした場合、以下の図のようになります。



図形の左上を原点とした場合、以下の図のようになります。



リファレンス

// プリミティブの拡大縮小(長方形内部+枠上)
// 入力
//  int             copyflag;       1....コピー/0....移動
//  int             tolayer;        拡大縮小後のレイヤ
//                                  (元のレイヤのままでもいいし、選択レイヤに移動しても良い)
//  int             x1,y1,x2,y2;    (x1,y1)-(x2,y2)で指定される長方形内部+枠上のプリミティブを移動する
//  double          cx,cy;          拡大縮小中心
//  double          amagx;          x軸方向の拡大率
//  double          amagy;          y軸方向の拡大率
// 戻り値
//  負              エラー
//  0               正常終了
int                 mexpandprimitivehook(int copyflag,int tolayer,int x1,int y1,int x2,int y2,double cx,double cy,double amagx,double amagy);
// プリミティブの拡大縮小(長方形内部)
// 入力
//  int             copyflag;       1....コピー/0....移動
//  int             tolayer;        拡大縮小後のレイヤ
//                                  (元のレイヤのままでもいいし、選択レイヤに移動しても良い)
//  int             x1,y1,x2,y2;    (x1,y1)-(x2,y2)で指定される長方形内部のプリミティブを移動する
//  double          cx,cy;          拡大縮小中心
//  double          amagx;          x軸方向の拡大率
//  double          amagy;          y軸方向の拡大率
// 戻り値
//  負              エラー
//  0               正常終了
int                 mexpandprimitiveinner(int copyflag,int tolayer,int x1,int y1,int x2,int y2,double cx,double cy,double amagx,double amagy);
// 指定レイヤのプリミティブの拡大縮小
// 入力
//  int             copyflag;       1....コピー/0....移動
//  int             layer;          指定レイヤ
//  int             tolayer;        拡大縮小後のレイヤ
//                                  (元のレイヤのままでもいいし、選択レイヤに移動しても良い)
//  double          cx,cy;          拡大縮小中心
//  double          amagx;          x軸方向の拡大率
//  double          amagy;          y軸方向の拡大率
// 戻り値
//  負              エラー
//  0               正常終了
int                 mexpandprimitivelayer(int copyflag,int layer,int tolayer,double cx,double cy,double amagx,double amagy);
目次


描画機能

線図形、面図形を描画することができます。
線図形の描画機能には、以下の4種類があります。
  1. ポリライン
    頂点数、頂点座標配列、線幅を指定してポリラインを挿入します。

  2. ポリライン集合
    上記のポリラインの集合を挿入します。別の図面や部品集などから図形を挿入する機能の実現に便利な機能です。

  3. 長方形
    長方形の対角線と線幅を指定して4辺のポリラインとして挿入します。
  4. 楕円
    楕円の外接矩形の対角線と線幅を指定して描画後、内蔵のラスタベクタ変換機能で生成したポリラインとして挿入します。
面図形の描画機能には、以下の4種類があります。
  1. 塗りつぶし長方形
    長方形の対角線を指定して、面図形として塗りつぶし長方形を挿入します。
  2. 塗りつぶし楕円
    楕円の外接矩形の対角線を指定して、面図形として塗りつぶし楕円を挿入します。
  3. 任意の図形
    任意の図形プリミティブを挿入します。図形プリミティブは1つ以上複数を同時に挿入可能です。


リファレンス

// ポリラインの描画
// 入力
//  int             tolayer;        描画したポリラインを置くレイヤ
//                                  (線図形レイヤ、選択図形レイヤに移動しても良い)
//  int             vertexnum;      ポリラインの頂点数(注意:2以上必要)
//  int*            px;             ポリラインの頂点
//  int*            py;
//  double          lwidth;         ポリラインの線幅
// 戻り値
//  0               正常終了
//  負              エラー
int                 mdrawpolyline(int tolayer,int vertexnum,int* px,int* py,double lwidth);
//  int             tolayer;        描画したポリラインを置くレイヤ
//                                  (線図形レイヤ、選択図形レイヤに移動しても良い)
//  int             polylinenum;    ポリライン数
//  int*            pvertexnum;     ポリラインの頂点数配列(0〜polylinenum-1)(注意:全て2以上必要)
//  int**           ppx;            ポリラインの頂点配列の配列(0〜polylinenum-1)
//  int**           ppy;
//  double*         plwidth;        ポリラインの線幅(0〜polylinenum-1)
// 戻り値
//  0               正常終了
//  負              エラー
int                 mdrawpolylineset(int tolayer,int polylinenum,int* pvertexnum,int** px,int** py,double* plwidth);
// 長方形枠の描画(ポリラインとして)
// 入力
//  int             tolayer;        描画したポリラインを置くレイヤ
//  int             x1,y1,x2,y2;    長方形の対角線の座標(順不同、マウスでどのように指定した座標でも渡せる)
//  double          lwidth;         ポリラインの線幅
// 戻り値
//  0               正常終了
//  負              エラー
int                 mdrawframerect(int tolayer,int x1,int y1,int x2,int y2,double lwidth);
// 楕円枠の描画(ポリラインとして)
// 入力
//  int             tolayer;        描画したポリラインを置くレイヤ
//  int             x1,y1,x2,y2;    楕円外接長方形の対角線の座標(順不同、マウスでどのように指定した座標でも渡せる)
//  double          lwidth;         ポリラインの線幅
// 戻り値
//  0               正常終了
//  負              エラー
int                 mdrawframeellipse(int tolayer,int x1,int y1,int x2,int y2,double lwidth);
// 塗りつぶし長方形の描画(面図形として)
// 入力
//  int             tolayer;        描画した塗りつぶし長方形を置くレイヤ
//  int             x1,y1,x2,y2;    長方形の対角線の座標(順不同、マウスでどのように指定した座標でも渡せる)
// 戻り値
//  0               正常終了
//  負              エラー
int                 mdrawfillrect(int tolayer,int x1,int y1,int x2,int y2);
// 塗りつぶし楕円の描画(面図形として)
// 入力
//  int             tolayer;        描画した塗りつぶし楕円を置くレイヤ
//  int             x1,y1,x2,y2;    楕円外接長方形の対角線の座標(順不同、マウスでどのように指定した座標でも渡せる)
// 戻り値
//  0               正常終了
//  負              エラー
int                 mdrawfillellipse(int tolayer,int x1,int y1,int x2,int y2);
// 任意面図形の挿入(面図形として:任意数プリミティブを一度に挿入可能)
// 入力
//  int             tolayer;        描画した面図形を置くレイヤ
//  int             left;            面図形バッファの左上座標(msetdocumentの左上を原点として)
//  int             top;
//  int             width;          面図形バッファの幅(単位ピクセル)
//  int             scanlinesize;   面図形バッファのスキャンラインサイズ(単位バイト)
//  int             height;         面図形バッファの高さ(単位ピクセル)
//  unsigned char*  pdata;          面図形バッファ
// 戻り値
//  0以上           挿入した面図形の数
//  負              エラー
int                 minsertprimitive(int tolayer,int left,int top,int width,int scanlinesize,int height,unsigned char* pdata);
目次


アンドゥ・リドゥ

ライブラリの現在の状態をバッファに取得するAPI、バッファの状態にライブラリの状態を変更するAPIによって、アンドゥ・リドゥ 機能を実現することができます。たとえば、以下のようにしてアンドゥ・リドゥ機能を実現します。
  1. ライブラリの現在の状態0をバッファ0に取得するAPIをコール
  2. ユーザーが編集操作をする。
  3. ライブラリの現在の状態1をバッファ1に取得するAPIをコール
  4. ユーザーが編集操作をする。
  5. ライブラリの現在の状態2をバッファ2に取得するAPIをコール
  6. アンドゥをすると状態1に戻る。
    バッファ1の状態にライブラリの状態を変更するAPIをコール。
  7. アンドゥをすると状態0に戻る。
    バッファ0の状態にライブラリの状態を変更するAPIをコール。
  8. リドゥをすると状態1に進む。
    バッファ1の状態にライブラリの状態を変更するAPIをコール。
  9. リドゥをすると状態2に進む。
    バッファ2の状態にライブラリの状態を変更するAPIをコール。
取得するバッファの内容には、アドレス情報等は存在しないので、ファイルにバッファの内容をそのまま保存することも可能です。
アンドゥ・リドゥではなく「現在の作業状態をファイル保存する」機能を同じAPIを使って開発することもできます。
アンドゥ・リドゥAPIには以下の2グループのものがあります。
  1. CJocrPrimインスタンスの状態はアプリケーション側で別途取得する場合は
    mgetsaveLPbuffersize/msaveLPbuffer/mloadLPbuffer
  2. CJocrPrimインスタンスの状態も合わせて取得する場合"P"がひとつ多い
    mgetsaveLPPbuffersize/msaveLPPbuffer/mloadLPPbuffer

リファレンス

// ライブラリの現在の状態を取得するバッファサイズを得る
// 戻り値
//  バッファサイズ(アプリケーション側で確保する)
size_t				mgetsaveLPbuffersize();
size_t				mgetsaveLPPbuffersize();
// ライブラリの現在の状態を取得する
// 利用目的1;undo/redo機能を実現する
//         2;独自形式のファイルで現在の作業状態をファイル保存/読込する
// 取得前にmgetsaveLPbuffersize()で取得したバッファサイズ分の領域を確保する
// 入力
//  char*&      ps1;                状態を取得するバッファの先頭アドレス(アプリケーション側で確保)
void				msaveLPbuffer(char*& ps1);
void				msaveLPPbuffer(char*& ps1);
// ライブラリの現在の状態をバッファで指定する
// 入力
//  size_t      len;                バッファサイズ
//  char*&      ps1;                状態バッファの先頭アドレス
// 戻り値
//  負          エラー
//  0           正常終了
int                 mloadLPbuffer(size_t& len,char*& ps1);
int                 mloadLPPbuffer(size_t& len,char*& ps1);

サンプル

/////////////////////////////////////////
// 0....ライブラリの状態を保存する領域をリングバッファで管理するものとする。
//      リングバッファがいっぱいになったときは古いものから除外する
// 1....画像入力時にOSからメモリの状況を取得して、リングバッファのサイズ(=アンドゥ回数+1/+1はアンドゥのリドゥ分)
//      を設定する。
// 2....オペレーションの直前に現在の状態を保存するために、mregistoperationをコール
//      バッファをリングバッファに登録する
// 3....アンドゥコマンド処理時には、mprocessundoをコール
//      リングバッファのトップの場合は、mregistoperationをコールする(最初のアンドゥの前までリドゥするため)。
// 4....リドゥコマンド処理時には、mprocessredoをコール
///////////////////////////////////////////
// 操作をヒストリ(リングバッファ)に登録する
// typedef struct _HISTORYBUFFER_RASTER {
// 	int     mflag;          // 1....ライトポリライン情報のみ
//                          // 2....画像+ライトポリライン情報
//                          // 4....最初のundo時に最新のステータスを保存したもの
// 	size_t  mundosize;
//  ....以下にはアプリケーション固有の情報があれば、それを保存する
// } HISTORYBUFFER_RASTER;
// 入力
//  int             lastflag;           undo直前から呼び出した時は1
//                                      そのほかは0
//  int             prsaveflag;         レイヤ情報だけ保存するときは0
//                                      primitive情報全てを保存するときは1
void CScancalcDoc::mregistoperation(int lastflag,int prsaveflag)
{
    HISTORYBUFFER_RASTER* ph;
    size_t buffersize = sizeof(HISTORYBUFFER_RASTER);
// CJocrPrim情報(レイヤ情報だけ)
// CJocrPrim情報
    size_t undoprimsize = mgetsaveLPPbuffersize((prsaveflag==0));
    buffersize += undoprimsize;
// undoバッファ確保
    ph = (HISTORYBUFFER_RASTER *)malloc(buffersize);
    if(ph) {
        // prsaveflagが0か1かを保存
        if(prsaveflag)
	        ph->mflag = 3;				// プリミティブ構造を保存する
        else
            ph->mflag = 1;				// プリミティブ構造を保存しない
        // lastflagを保存
        if(lastflag == 1)
            ph->mflag |= 4;				// 最新の状態を保存したもの(redo用)
        // ライブラリの保存
        ph->mundosize = undoprimsize;
        // CJocrPrim情報
        // ヘッダの次から保存されている
        char* ps1 = (char *)(ph + 1);
        // ライブラリの状態をps1に取り出す
        msaveLPPbuffer(prsaveflag==0,ps1);
        // リングバッファに登録するためのアプリケーション固有の関数
        mundoregist(lastflag,buffersize,(void*)ph);
        free(ph);
    }
}
// アンドゥ処理
int CScancalcDoc::mprocessundo()
{
    int             buffersize;
    void*           ph;
    // リングバッファのトップの場合は、アンドゥ直前の状態を登録して、そこまでリドゥ可能とする
    if(mistoregistoperationbyundo()) {    // リングバッファのトップ判定
        mregistoperation(1,mlastprsaveflag);
    }
    int i1 = mexecundo(buffersize,ph);
    if(i1 == 0) {
        mrecoveroperation(ph);
        return((((HISTORYBUFFER_RASTER*)ph)->mflag & 2) != 0);  // 画像が変わると1を返す
		// 画像が変わったら何か特別なことをしたい場合
    }
    return(0);    // レイヤ情報だけが変わった場合
}
// リドゥ処理
int CScancalcDoc::mprocessredo()
{
    int        buffersize;
    void*      ph;
    int i1 = mexecredo(buffersize,ph);
    if(i1 == 0) {
        mrecoveroperation(ph);
        return((((HISTORYBUFFER_RASTER*)ph)->mflag & 2) != 0);
    }
    return(0);
}
// アンドゥ・リドゥ共通処理
void CScancalcDoc::mrecoveroperation(void* p1)
{
    HISTORYBUFFER_RASTER* ph = (HISTORYBUFFER_RASTER *)p1;
    // CJocrPrim情報の復帰
    // 画像情報が保存されている
    size_t	len = ph->mundosize;
    char*	ps1 = (char*)(ph + 1);
    // バッファps1の状態にライブラリを設定する
    mloadLPPbuffer((ph->mflag & 2) == 0,len,ps1);
}
目次


ラスタのファイル出力方法

全レイヤのラスタを合成したビットマップを出力するには、CJocrPrimクラスのmakebitmapを使います。CALibRasterクラスにも CJocrPrimクラスのmakebitmapを呼び出すだけですが、同じAPIを用意しました。
また倍率1.0倍表示でデータ全体の表示データを取得すれば、レイヤ別の24bitカラー表示データを得ることができます。
makedefaultpaletteで指定したパレットを参照すれば、レイヤ別の256色パレット表示データを得ることもできます。

リファレンス

// プリミティブ→ビットマップ逆変換
// 幅と高さ、スキャンラインは元のドキュメントと同じ(msetdocumentで設定したもの)
// コールする側でバッファを確保、管理、解放する
// 入力
//	int             layer;          -1,0〜255...逆変換するレイヤ、-1は全レイヤ
void                makebitmap(int layer,unsigned char* pdata);

サンプル

///////////////////
// レイヤ画像の保存
// レイヤを指定して、モノクロ画像として保存する
// 全レイヤを保存する場合は、layernumに1、player[0]に-1を設定する。
// 入力
//  char*        filename;              保存ファイル名
//  int          layernum;              レイヤ数
//  int*         player;                player[0]〜player[layernum-1]までのレイヤ配列
// 戻り値
//  負...エラー
//  0....正常終了
int CALData::msavelayerimage(char* filename,int layernum,int* player)
{
    // 各レイヤの画像を加算するため、画像サイズ×2のバッファを取得
    unsigned char* pdata = (unsigned char*)malloc(mscanlinesize * mheight * 2);
    if(pdata == NULL) return(MEMORY_SHORTAGE);
    // 0で埋める(保存時のphotometric設定で白)
    memset(pdata,0,mscanlinesize * mheight * 2);
    unsigned char* pdata1 = pdata + mscanlinesize * mheight;
    if(layernum > 0) {
        // player[0]が-1の時は、全レイヤ保存
        if(player[0] == -1) {
            mplibraster->makebitmap(player[0],pdata);
        }
        else {
            // 指定レイヤの画像を合成する
            for(int i = 0 ; i < layernum ; i++) {
                mplibraster->makebitmap(player[i],pdata1);
                for(int j = 0 ; j < mheight ; j++) {
                    unsigned char* ps1 = pdata1 + mscanlinesize * j;
                    unsigned char* ps2 = pdata  + mscanlinesize * j;
                    for(int k = 0 ; k < mscanlinesize ; k++,ps1++,ps2++) {
                        *ps2 = *ps2 | *ps1;
                    }
                }
            }
        }
    }
    // アプリケーション固有の画像保存呼び出し
    // alibrasterライブラリには含まれません
    int i1 = mplibimage->msaveimage(0,0,filename,mwidth,mheight,1,mscanlinesize,0,mdpi,pdata);
    free(pdata);
    if(i1 < 0) {
        return(i1);
    }
    return(0);
}
目次


マニュアルホームページ