« 2008年2月 | トップページ | 2008年4月 »

☆円弧の描画

円弧の描画時に、時計回りなのか、半時計回りなのかを判断して 座標を入れ替えて表示させていましたが、SetArcDirection APIを使うと 処理がすっきりするかも知れませんね。
// SetArcDirectionを使わない処理
if (Enko.m_radEnkoKaku < 0) then
  ACanvas.Arc(P1.X,P1.Y,P2.X,P2.Y,P4.X,P4.Y,P3.X,P3.Y)
else
  ACanvas.Arc(P1.X,P1.Y,P2.X,P2.Y,P3.X,P3.Y,P4.X,P4.Y);


// SetArcDirectionを使った処理
if (Enko.m_radEnkoKaku < 0) then
  SetArcDirection(ACanvas.Handle, AD_CLOCKWISE)          // 時計回り
else
  SetArcDirection(ACanvas.Handle, AD_COUNTERCLOCKWISE);  // 反時計回り

ACanvas.Arc(P1.X,P1.Y,P2.X,P2.Y,P3.X,P3.Y,P4.X,P4.Y)   // 円弧

|

☆配列のサイズ変更で・・・。

配列の要素を増やす処理を書いていたときの話です。
Highが配列の要素数を返していると思い込んでしまい、 こんなことでずっと悩んでいました。
ちょっと情けないかも(^^;
// 間違ったコード
procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
begin
  // 配列要素数を取得しているつもり → 実際は、配列要素数-1
  I := High(TestArr);
  // 配列要素数を一つ増やしたつもり → 実際は、前のまま
  Inc(I);
  SetLength(TestArr, I);
  // 増えていることを確認するためにHighを使った。
  I := High(TestArr);
  // 一つ増やした要素に代入しているつもり → 実際は、要素の最後に代入
  TestArr[I] := 1000;
  // 結果として増えていない!
end;


// 正しいコード
procedure TForm1.Button3Click(Sender: TObject);
var
  I: Integer;
begin
  I := Length(TestArr);
  Inc(I);
  SetLength(TestArr, I);
  I := High(TestArr);
  TestArr[I] := 1000;
end;

|

■最近・・・。

ここしばらく、時間があればJWWデータの長さや面積を計測する部分を作っていてほとんどブログの更新ができていません。だって、プログラムというよりは、ほとんど高校の数学を復習しているようなものですからね(笑)

話は変わりますが、ずいぶん前にDelphiの広告で「清水建設での社内システム構築事例」が取り上げられていたのをご存知でしょうか。昨日、建築関係の会議でお会いした方が、その時の責任者だったということで、いろいろと話をお聞きしました。残念ながら、ここでその内容を詳細に書くわけにはいかないのですが、このような大手企業での導入事例がたくさんあれば、Delphi使いとしては心強いですよね。

|

☆JWWのソリッドデータを描画してみる。

私自身、JWWを使いこなしていないため、よく分からないデータも多いのですが、 下記の処理で描画できているようです。 (申し訳ないのですが、現在、描画処理を別ユニットに分ける作業をしてて、そのユニット内のコードなので 前回のコードに組み込むには少し修正が必要です)

Solid_2


  uses jwwunit;

  // 実数を扱うTPoint
  PPointEx = ^TPointEx;
  TPointEx = packed record
    X: Double;
    Y: Double;
  end;

  // 座標を変換
  procedure Change_mm_dot_Point(PEx: TPointEx; var P: TPoint);
  begin
    P.x := Round( PEx.x * mm_dot + OriginPoint.X );
    P.y := Round(-PEx.y * mm_dot + OriginPoint.Y );
  end;

  // 円弧の描画
  procedure DrawEnko(Enko: CDataEnko; IsSolid: Boolean=False);
  var
    x1, y1, Hankei: Double;
    Hajime, Owari: Double;
    PEx1, PEx2: TPointEx;
    P1, P2, P3,P4: TPoint;
  begin
    if (not IsSupportLine(Enko.Root)) and LayerCheck(Enko.Root) then
    begin
      x1 := Enko.m_start_x;
      y1 := Enko.m_start_y;
      Hankei := Enko.m_dHankei;
      Hajime := Enko.m_radKaishiKaku + Enko.m_radKatamukiKaku;
      Owari :=  Enko.m_radKaishiKaku + Enko.m_radEnkoKaku +
        Enko.m_radKatamukiKaku;
      if Enko.m_radKatamukiKaku < 0 then
      begin
        PEx1.X := X1-Hankei*Enko.m_dHenpeiRitsu;
        PEx1.Y := Y1-Hankei;
        PEx2.X := X1+Hankei*Enko.m_dHenpeiRitsu;
        PEx2.Y := Y1+Hankei;
      end
      else
      begin
        PEx1.X := X1-Hankei;
        PEx1.Y := Y1-Hankei*Enko.m_dHenpeiRitsu;
        PEx2.X := X1+Hankei;
        PEx2.Y := Y1+Hankei*Enko.m_dHenpeiRitsu;
      end;

      // 円弧の設定
      LineSetting(Enko.Root);

      // mm→dot変換
      Change_mm_dot_Point(PEx1, P1);
      Change_mm_dot_Point(PEx2, P2);

      // ソリッドかどうか
      if IsSolid then
        ACanvas.Brush.Style := bsSolid
      else
        ACanvas.Brush.Style := bsClear;

      // 円弧の描画
      if Enko.m_bZenEnFlg = 1 then
      begin
        // 円・全円ソリッド
        ACanvas.Ellipse(P1.X,P1.Y,P2.X,P2.Y);
      end
      else
      begin
        // 円弧
        P3.X := Round( ((x1+Hankei*Cos(Hajime)))*MM_dot+OriginPoint.X);
        P3.Y := Round(-((y1+Hankei*Sin(Hajime)))*MM_dot+OriginPoint.Y);
        P4.X := Round( ((x1+Hankei*Cos(Owari )))*MM_dot+OriginPoint.X);
        P4.Y := Round(-((y1+Hankei*Sin(Owari )))*MM_dot+OriginPoint.Y);

        if (P3.X <> P4.X) or (P3.Y <> P4.Y) then
        begin
          if Enko.m_bZenEnFlg = 0 then
          begin
            // 円弧
            if (Enko.m_radEnkoKaku < 0) then
              ACanvas.Arc(P1.X,P1.Y,P2.X,P2.Y,P4.X,P4.Y,P3.X,P3.Y)
            else
              ACanvas.Arc(P1.X,P1.Y,P2.X,P2.Y,P3.X,P3.Y,P4.X,P4.Y);
          end
          else if Enko.m_bZenEnFlg = 2 then
          begin
            // 弓形ソリッド
            if (Enko.m_radEnkoKaku < 0) then
              ACanvas.Chord(P1.X,P1.Y,P2.X,P2.Y,P4.X,P4.Y,P3.X,P3.Y)
            else
              ACanvas.Chord(P1.X,P1.Y,P2.X,P2.Y,P3.X,P3.Y,P4.X,P4.Y);
          end
          else if Enko.m_bZenEnFlg = 3 then
          begin
            // 扇形ソリッド
            if (Enko.m_radEnkoKaku < 0) then
              ACanvas.Pie(P1.X,P1.Y,P2.X,P2.Y,P4.X,P4.Y,P3.X,P3.Y)
            else
              ACanvas.Pie(P1.X,P1.Y,P2.X,P2.Y,P3.X,P3.Y,P4.X,P4.Y);
          end;
        end;
      end;
    end;
  end;


  // ソリッド図形の描画
  procedure DrawSolid(Solid: CDataSolid);
  var
    poly: array[0..3] of TPoint;
    Enko: CDataEnko;
  begin
    if LayerCheck(Solid.Root) then
    begin
      if Solid.Root.m_nPenStyle > 100 then
      begin
        if Solid.Root.m_nPenStyle = 101 then
        begin
          //円のソリッド
          Enko.Root := Solid.Root;
          Enko.m_start_x := Solid.m_start_x;
          Enko.m_start_y := Solid.m_start_y;
          Enko.m_dHankei := Solid.m_end_x;
          Enko.m_radKaishiKaku := Solid.m_DPoint2_y;
          Enko.m_radEnkoKaku := Solid.m_DPoint3_x;
          Enko.m_radKatamukiKaku := Solid.m_DPoint2_x;
          Enko.m_dHenpeiRitsu := Solid.m_end_y;
          ACanvas.Pen.Color := Solid.m_Color;
          ACanvas.Brush.Color := ACanvas.Pen.Color;
          if Solid.m_DPoint3_y = 100 then
            Enko.m_bZenEnFlg := 1   // 全円ソリッド
          else if Solid.m_DPoint3_y = 5 then
            Enko.m_bZenEnFlg := 2   // 弓形ソリッド ※2は適当
          else if Solid.m_DPoint3_y = 0 then
            Enko.m_bZenEnFlg := 3   // 扇形ソリッド ※3は適当
          else if Solid.m_DPoint3_y = -1 then
            Enko.m_bZenEnFlg := 4   // 外側円弧ソリッド・・・どんな処理?
          else
            Enko.m_bZenEnFlg := 10; // 処理しない  ※10は適当
          if Enko.m_bZenEnFlg < 10 then
            DrawEnko(Enko, True);
        end
        else if Solid.Root.m_nPenStyle = 101 then
        begin
          // 円環ソリッド・・・どんな処理?
        end
        else if Solid.Root.m_nPenStyle = 111 then
        begin
          // 円周ソリッド・・・どんな処理?
        end;
      end
      else
      begin
        // ソリッド
        // mm→dot変換
        Change_mm_dot_Point(PointEx(Solid.m_start_x  , Solid.m_start_y  ), Poly[0]);
        Change_mm_dot_Point(PointEx(Solid.m_end_x    , Solid.m_end_y    ), Poly[1]);
        Change_mm_dot_Point(PointEx(Solid.m_DPoint2_x, Solid.m_DPoint2_y), Poly[2]);
        Change_mm_dot_Point(PointEx(Solid.m_DPoint3_x, Solid.m_DPoint3_y), Poly[3]);
        ACanvas.Pen.Color := Solid.m_Color;
        ACanvas.Brush.Color := ACanvas.Pen.Color;
        ACanvas.Polygon(poly);
      end;
    end;
  end;


  // ソリッド図形
  for I := Low(JWWSolid) to High(JWWSolid) do
    DrawSolid(JWWSolid[I]);

|

☆JWWのクリップボードを読み込んでみる。

HiroCom777さんのVBdeJW !!で公開されているJwwClipControlを参考にして、 JWWのクリップボードのデータを読み込んでみました。

基本的な構造としては、起点の座標+グループ毎の縮尺+各データに なっているようです。

まず、クリップボードからTStreamにデータを取り出します。
uses Clipbrd;

procedure TForm1.Button1Click(Sender: TObject);
var
  Data: THandle;
  DataPtr: Pointer;
  MemStream: TMemoryStream;
  I: Integer;
  FormatID: Integer;
  FormatName: array [0..MAX_PATH] of Char;
  ID: word;
  F: Boolean;
begin
  F := False;
  ID := 0;
  for I := 0 to ClipBoard.FormatCount - 1 do
  begin
    FormatID:= ClipBoard.Formats[I];
    GetClipBoardFormatName(FormatID, FormatName, SizeOf(FormatName));
    if FormatName = 'Jw_win' then
    begin
      F := True;
      ID := FormatID;
      Break;
    end;
  end;

  if not F then Exit;

  ClipBoard.Open;
  Data := ClipBoard.GetAsHandle(ID);
  if Data = 0 then Exit;

  DataPtr := GlobalLock(Data);
  if DataPtr = nil then Exit;

  MemStream := TMemoryStream.Create;
  try
    MemStream.WriteBuffer(DataPtr^, GlobalSize(Data));
    MemStream.Position := 0;
    JwwPasteFromClipboard(TStream(MemStream));
    Drawdata;
  finally
    MemStream.Free;
    GlobalUnLock(Data);
    ClipBoard.Close;
  end;
end;

次にTStreamから各データを取得します。この部分については、jwwunitのjwwRead関数を 参考にしています。というかそのままに近いので今回は、線データのみ取得させています。
// クリップボードのデータを取得する。
procedure JwwPasteFromClipboard(Stream: TStream);
var
  I,J,K: Integer;
  dw: DWORD;
  db: Double;
  S: String;
  wd: Word;
  bt: Byte;
  JWWList: TJWWList;
  SenCount: Integer;
  DSen: CDataSen;
  orgX,orgY: Double;
  scale: array[0..15] of Double;
  Size,Cnt: Integer;
  Dummy: array[0..150] of Byte;

  function StringRead(n:Integer): String;
  var
    I: Integer;
    cc: char;
  begin
    Result := '';
    for I:=0 to n-1 do
    begin
      Stream.ReadBuffer(cc,1);
      Result := Result + cc;
    end;
  end;  

begin
  Stream.Position := 0;
  Size := Stream.Size;

  Cnt := High(JWWSen);

  // 基準点
  Stream.ReadBuffer(orgX,SizeOf(Double));
  Stream.ReadBuffer(orgY,SizeOf(Double)); 

  // レイヤグループの縮尺
  for I := 0 to 15 do
    Stream.ReadBuffer(scale[I],SizeOf(Double));

  JWWList := TJWWList.Create;
  try
    Stream.ReadBuffer(wd,SizeOf(wd));
    if wd = $FFFF then
    begin
      Stream.ReadBuffer(dw,SizeOf(dw));
      J := dw;
    end else
      J := wd;

    SetLength(JWWSen,Cnt+J);
    SenCount := Cnt;
    I := 1;

    while Stream.Position <= Size do
    begin
      Stream.ReadBuffer(wd,2);
      case wd of
        $0000: Break;
        $FFFF: begin
                 Stream.ReadBuffer(wd,2);
                 Stream.ReadBuffer(wd,2);
                 S := StringRead(wd);
                 JWWList.AddItem(I,S);
                 J := I;
                 Inc(I);
               end;
        $FF7F: begin
                 Stream.ReadBuffer(dw,4);
                 J := dw and $7FFFFFFF;
               end;
        $7FFF: begin
                 Stream.ReadBuffer(dw,4);
                 J := dw and $7FFFFFFF;
               end;
        else begin
               if (wd and $8000) <> 0 then
                 J := wd and $7FFF else J := 0;
             end;
      end;
      S := JWWList.NoByItem[J].CDataString;
      if S = 'CDataList' then
      begin
        Stream.ReadBuffer(Dummy,28);
        Stream.ReadBuffer(bt,1);
        if bt <> $FF then
          StringRead(bt)
        else
        begin
          Stream.ReadBuffer(wd,2);
          StringRead(wd)
        end;

        Stream.ReadBuffer(wd,2);
        if wd = $FFFF then
          Stream.ReadBuffer(dw,4);
      end;
      if S = 'CDataSen' then
      begin
        Stream.ReadBuffer(dw,4);
        DSen.Root.m_lGroup:=dw;
        Stream.ReadBuffer(bt,1);
        DSen.Root.m_nPenStyle:=bt;
        Stream.ReadBuffer(wd,2);
        DSen.Root.m_nPenColor:=wd;
        Stream.ReadBuffer(wd,2);
        DSen.Root.m_nPenWidth:=wd;
        Stream.ReadBuffer(wd,2);
        DSen.Root.m_nLayer:=wd;
        Stream.ReadBuffer(wd,2);
        DSen.Root.m_nGLayer:=wd;
        Stream.ReadBuffer(wd,2);
        DSen.Root.m_sFlg:=wd;
        Stream.ReadBuffer(db,8);
        DSen.m_start_x := db;
        Stream.ReadBuffer(db,8);
        DSen.m_start_y := db;
        Stream.ReadBuffer(db,8);
        DSen.m_end_x := db;
        Stream.ReadBuffer(db,8);
        DSen.m_end_y := db;
        JWWSen[SenCount] := DSen;
        Inc(SenCount);
      end;
      if S = 'CDataEnko' then
      begin
        Stream.ReadBuffer(Dummy,75);
      end;
      if S = 'CDataTen' then
      begin
        Stream.ReadBuffer(dw,4);
        Stream.ReadBuffer(bt,1);
        Stream.ReadBuffer(Dummy,30);
        if bt = 100 then
          Stream.ReadBuffer(Dummy,20);
      end;
      if S = 'CDataMoji' then
      begin
        Stream.ReadBuffer(Dummy,83);
        Stream.ReadBuffer(bt,1);
        if bt <> $FF then
          StringRead(bt)
        else
        begin
          Stream.ReadBuffer(wd,2);
          StringRead(wd);
        end;
        Stream.ReadBuffer(bt,1);
        if bt <> $FF then
          StringRead(bt)
        else
        begin
          Stream.ReadBuffer(wd,2);
          StringRead(wd);
        end;
      end;
      if S = 'CDataSolid' then
      begin
        Stream.ReadBuffer(dw,4);
        Stream.ReadBuffer(bt,1);
        Stream.ReadBuffer(wd,2);
        Stream.ReadBuffer(Dummy,72);
        if wd = 10 then
          Stream.ReadBuffer(Dummy,4);
      end;
      if S = 'CDataBlock' then
      begin
        Stream.ReadBuffer(Dummy,59);
      end;
      if S = 'CDataSunpou' then
      begin
        Stream.ReadBuffer(Dummy,145);

        Stream.ReadBuffer(bt,1);
        if bt <> $FF then
          Stream.ReadBuffer(Dummy,1)
        else
          Stream.ReadBuffer(Dummy,2);

        Stream.ReadBuffer(bt,1);
        if bt <> $FF then
          Stream.ReadBuffer(Dummy,1)
        else
          Stream.ReadBuffer(Dummy,2);

        Stream.ReadBuffer(wd,2);
        Stream.ReadBuffer(Dummy,94);
        for K := 0 to 3 do
        begin
          Stream.ReadBuffer(dw,4);
          Stream.ReadBuffer(bt,1);
          Stream.ReadBuffer(Dummy,30);
          if bt = 100 then
            Stream.ReadBuffer(Dummy,20);
        end;
      end;
      if S <> '' then Inc(I);
      S:='';
    end;
    SetLength(JWWSen,SenCount);
  finally
    JWWList.Free;
  end;
end;

上記のコードをJWWファイルの超簡易表示 その3で 試して頂くとデータが追加されているのがわかります。ただ、貼り付ける位置の座標やレイヤは元データのままなので、実際に使う場合には その辺りを処理する必要があります。

今回は、メモリ上で処理していますが、クリップボードからTFileStreamでファイルに書き出して、 そこから読み込むというのもいいかも知れませんね。


VBdeJW !!
http://www.h7.dion.ne.jp/~hirocom/VBdeJW/


Peter's Room
jww data read & save unit Ver1.3β
http://www5b.biglobe.ne.jp/~peter/index.html


AFsoft WebSite
CAD作ろ!
http://afsoft.jp/

|

■RAD Studio 2007 ヘルプアップデート 2

何気なくアップデートの確認をすると、Feb08Help(JA)という更新が表示されました。

Feb08_01


次の画像では見辛いですが、「Rad Studio ・・・ 必要なファイルを検出できませんでした。」というメッセージが表示されました。表示されているフォルダを確認してみますと、そんなフォルダ自体ありませんでした。でも、無視して次へを押すと問題なく動作し始めました。

Feb08_03


Feb08_04_2


無事終了したようです。

Feb08_05


バージョン情報を確認すると、インストール済みの更新にFebruary 2008 Help Updateが追加されました。

Feb08_06




CodeGear
RAD Studio 2007 ヘルプアップデート 2 インストールおよびリリースノート
http://dn.codegear.com/jp/article/37603

|

« 2008年2月 | トップページ | 2008年4月 »