« ■『Tiburón』フィールドテスター募集開始 | トップページ | ■Office Open XML、ISO標準に・・・。 »

☆JWWファイルの超簡易表示 その4

ここ数日は、ブロックデータに挑戦していましたが、ブロックデータクラスや回転、 倍率処理・・・どれもややこし過ぎです。ブロックデータクラスの内容がいまいち理解 できていないので、基本的なところで間違っている可能性もありますが、 とりあえず回転、倍率処理を見送り、なんとか表示できるようになりました(^^; そこで前回のソリッド描画と斜め楕円の描画も追加してコードをまとめてみました。

※斜め楕円の描画は、旧FDelphi 16番会議室「玉石混淆みんなで作るSample蔵」 斜め楕円の描画(裏目小僧さん、凛さん)を使わせて頂きました。

Jww4

※ELVがブロック図形となっています。
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls, ComCtrls, Clipbrd, jwwunit, jwwDraw;

type
  TForm1 = class(TForm)
    TreeView1: TTreeView;
    Panel1: TPanel;
    PaintBox1: TPaintBox;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormMouseWheelDown(Sender: TObject; Shift: TShiftState;
      MousePos: TPoint; var Handled: Boolean);
    procedure FormMouseWheelUp(Sender: TObject; Shift: TShiftState;
      MousePos: TPoint; var Handled: Boolean);
    procedure PaintBox1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure PaintBox1MouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure PaintBox1Paint(Sender: TObject);
    procedure FormResize(Sender: TObject);
    procedure TreeView1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  private
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  Commctrl, ShlObj;

// 初期設定
procedure TForm1.FormCreate(Sender: TObject);
var
  FileName: String;
  WindowStyles: Integer;
begin
  // TreeViewにCheckBoxを表示させます。
  WindowStyles := GetWindowLong(TreeView1.Handle, GWL_STYLE);
  SetWindowLong(TreeView1.Handle, GWL_STYLE, WindowStyles or TVS_CHECKBOXES);

  JWWBlockList := TJWWBlockList.Create;

  FileName := 'c:\jww\Aマンション平面例.jww';
  JwwDataLoadFromFile(FileName);
  SetLayerName(TreeView1);
  JWWDataDraw(PaintBox1);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  JWWBlockList.Free;
end;

procedure TForm1.FormResize(Sender: TObject);
begin
  JWWDataDraw(PaintBox1);
end;

procedure TForm1.FormMouseWheelDown(Sender: TObject; Shift: TShiftState;
  MousePos: TPoint; var Handled: Boolean);
begin
  if ((MousePos.X > 0) and (MousePos.X < PaintBox1.Width)) and
     ((MousePos.Y > 0) and (MousePos.Y < PaintBox1.Height)) then
  begin
    Handled := True; // TreeView1とPaintBox1を独立してスクロール処理させるために必要
    ZoomUp(PaintBox1.Canvas);
  end;
end;

procedure TForm1.FormMouseWheelUp(Sender: TObject; Shift: TShiftState;
  MousePos: TPoint; var Handled: Boolean);
begin
  if ((MousePos.x > PaintBox1.Left) and (MousePos.x < PaintBox1.Left + PaintBox1.Width)) and
     ((MousePos.y > PaintBox1.Top)  and (MousePos.y < PaintBox1.Top  + PaintBox1.Height))
   then
  begin
    Handled := True; // TreeView1とPaintBox1を独立してスクロール処理させるために必要
    ZoomDown(PaintBox1.Canvas);
  end;
end;

procedure TForm1.PaintBox1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if not CanDraw then Exit;

  if (ssLeft in Shift) or (ssRight in Shift) then
  begin
    DraggingNow    := True;
    RubberBandShow := False;

    DragStartPoint := Point(X,Y);
    DragEndPoint   := Point(0,0);

    if (ssLeft  in Shift) then DragEndPoint.X := 1;
    if (ssRight in Shift) then DragEndPoint.Y := 1;
  end;
end;

procedure TForm1.PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  if DraggingNow then
  begin
    if RubberBandShow then
      RubberBand(PaintBox1.Canvas, DragStartPoint, DragEndPoint);

    if (ssLeft in Shift) and (ssRight in Shift) then
    begin
      DragEndPoint := Point(X,Y);
      RubberBand(PaintBox1.Canvas, DragStartPoint, DragEndPoint);
      RubberBandShow := True;
    end
    else
    begin
      RubberBandShow := False;
      if (ssLeft  in Shift) then DragEndPoint.X := 1;
      if (ssRight in Shift) then DragEndPoint.Y := 1;
    end;
  end
end;

procedure TForm1.PaintBox1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);

  function GetDragModeKind: Integer;
  begin
    if (Abs(DragStartPoint.X - X) <= 5) and (Abs(DragStartPoint.Y - Y) <= 5) then
      Result := 0    // 移動
    else
    begin
      if (DragStartPoint.X <= X) then
        Result := 1  // 拡大
      else
        Result := 2; // 縮小
    end;
  end;

var
  x1, y1, x2, y2: Double;
  cx, cy: Double;
  dx, dy: Double;
  bx, by: Double;
  P1, P2: Double;
begin
  if (not RubberBandShow) and ((DragEndPoint.X = 0) or (DragEndPoint.Y = 0)) then
  begin
    DraggingNow := False;
    Exit;
  end;

  if DraggingNow then
  begin
    DraggingNow := False;

    if RubberBandShow then
      RubberBand(PaintBox1.Canvas, DragStartPoint, DragEndPoint);

    DragModeKind := GetDragModeKind;

    x1 := ViewArea.Left   + (DragStartPoint.X / mm_dot);   // ドラッグ開始位置の左上X座標
    y1 := ViewArea.Bottom - (DragStartPoint.Y / mm_dot);   // ドラッグ開始位置の左下Y座標
    x2 := ViewArea.Left   + (X / mm_dot);                  // ドラッグ終了位置の左上X座標
    y2 := ViewArea.Bottom - (Y / mm_dot);                  // ドラッグ終了位置の左下Y座標
    dx := Abs(ViewArea.Right  - ViewArea.Left);            // ビューの幅
    dy := Abs(ViewArea.Bottom - ViewArea.Top );            // ビューの高さ
    bx := Abs(x1 - x2);                                    // 長方形の大きさ X
    by := Abs(y1 - y2);                                    // 長方形の大きさ Y
    cx := (x1 + x2) / 2.0;                                 // 長方形の中央の座標 X
    cy := (y1 + y2) / 2.0;                                 // 長方形の中央の座標 Y

    case (DragModeKind) of
      0: begin
           // 移動
           cx := (ViewArea.Left + ViewArea.Right ) / 2.0;  // 現在のビューの中心座標 X
           cy := (ViewArea.Top  + ViewArea.Bottom) / 2.0;  // 現在のビューの中心座標 Y
           dx := x2 - cx;                                  // 移動量
           dy := y2 - cy;                                  // 移動量
           ViewArea.Left   := ViewArea.Left   + dx;        // 移動計算
           ViewArea.Top    := ViewArea.Top    + dy;        // 移動計算
           ViewArea.Right  := ViewArea.Right  + dx;        // 移動計算
           ViewArea.Bottom := ViewArea.Bottom + dy;        // 移動計算
         end;
      1: begin
           // 拡大
           if (bx < 0.000001) then bx:=0.000001;
           if (by < 0.000001) then by:=0.000001;

           P1 := dx / bx;
           P2 := dy / by;

           if (P1 < P2) then
             mm_dot := mm_dot * P1
           else
             mm_dot := mm_dot * P2;

           ViewArea.Left   := cx - ((ImageSize.Width  / 2.0) / mm_dot);
           ViewArea.Top    := cy - ((ImageSize.Height / 2.0) / mm_dot);
           ViewArea.Right  := cx + ((ImageSize.Width  / 2.0) / mm_dot);
           ViewArea.Bottom := cy + ((ImageSize.Height / 2.0) / mm_dot);
         end;
      2: begin
           // 縮小
           P1 := bx / dx;
           P2 := by / dy;

           if (P1 > P2) then
             mm_dot := mm_dot * P1
           else
             mm_dot := mm_dot * P2;

           ViewArea.Left   := cx - ((ImageSize.Width  / 2.0) / mm_dot);
           ViewArea.Top    := cy - ((ImageSize.Height / 2.0) / mm_dot);
           ViewArea.Right  := cx + ((ImageSize.Width  / 2.0) / mm_dot);
           ViewArea.Bottom := cy + ((ImageSize.Height / 2.0) / mm_dot);
         end;
    end;
    DrawData(PaintBox1.Canvas);
  end
end;

procedure TForm1.PaintBox1Paint(Sender: TObject);
begin
  DrawData(PaintBox1.Canvas);
end;

// TreeViewのチェックボックス処理
procedure TForm1.TreeView1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  HitTest: TTVHitTestInfo;
  Node: TTreeNode;
  I, J, K: Integer;
begin
  // クリックした位置のノードを取得します。
  Node := TreeView1.GetNodeAt(X, Y);
  if Node = nil then Exit;

  HitTest.pt.x := X;
  HitTest.pt.y := Y;
  TreeView_HitTest(TreeView1.Handle, HitTest);

  if (HitTest.flags = TVHT_ONITEMSTATEICON) then
  begin
    if TreeView_GetCheckState(TreeView1.Handle, Node.ItemId) > 0 then
      K := 1
    else
      K := 0;

    if Node.Level = 0 then
    begin
      I := Node.AbsoluteIndex mod 16;
      JWWHd.GLay[I].m_anGLay := K;
    end
    else
    begin
      I := Node.Parent.AbsoluteIndex mod 16;
      J := Node.Index;
      JWWHd.GLay[I].m_nLay[J].m_aanLay := K;
    end;
    PaintBox1.Invalidate;
  end;
end;

end.
描画のユニットです。
unit jwwDraw;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls, ComCtrls, jwwunit, Math;

type
  TPointEx = packed record
    X: Double;
    Y: Double;
  end; 

  TRectEx = packed record
    case Integer of
      0: (Left, Top, Right, Bottom: Double);
      1: (TopLeft, BottomRight: TPointEx);
  end;  

  TSize = packed record
    Height: Integer;
    Width: Integer;
  end;

  TSizeEx = packed record
    Height: Double;
    Width: Double;
  end;

var
  OriginPoint: TPoint;                         // 原点
  ImageSize: TSize;                            // 画面ドットサイズ
  PaperSize: TSizeEx;                          // 用紙サイズ
  mm_dot: Double;                              // mm_dot比
  ViewArea: TRectEx;                           // ビューエリア
  DragStartPoint: TPoint;                      // ドラッグ開始点
  DragEndPoint: TPoint;                        // ドラッグ終了点
  DragModeKind : Integer;                      // ドラッグモード 0:移動 1:拡大 2:縮小
  DraggingNow : Boolean;                       // ドラッグ中かどうかのフラグ
  RubberBandShow : Boolean;                    // ラバーバンド表示フラグ
  CanDraw: Boolean;                            // 描画可能かどうかのフラグ
  function PointEx(X, Y: Double): TPointEx;    // PointEx型を作成します。
  procedure JWWDataDraw(APaintBox: TPaintBox);
  procedure DrawData(ACanvas: TCanvas);        // 図面の描画
  procedure SetPaperSize(Size: Integer);       // 用紙サイズの設定
  procedure ZoomUp(ACanvas: TCanvas);          // 拡大
  procedure ZoomDown(ACanvas: TCanvas);        // 縮小
  procedure RubberBand(ACanvas: TCanvas; P1, P2: TPoint); // ラバーバンドの描画
  procedure SetLayerName(ATreeView: TTreeView);    // レイヤー名及び表示/非表示の設定
  procedure JwwDataLoadFromFile(FileName: String);
  
implementation

uses
  Commctrl, ShlObj;

const
  TVIS_CHECKED  = $2000;

procedure JwwDataLoadFromFile(FileName: String);
begin
  DraggingNow := False;
  RubberBandShow := False;
  jwwRead(FileName);
  SetPaperSize(JWWHd.m_nZumen);
  CanDraw := True;
  mm_dot := 0;
end;

function PointEx(X, Y: Double): TPointEx;
begin
  Result.X := X;
  Result.Y := Y;
end;

// ラバーバンド長方形描画
procedure RubberBand(ACanvas: TCanvas; P1, P2: TPoint);
begin
  ACanvas.Pen.Mode := pmXor;
  ACanvas.Pen.Color := clAqua;
  ACanvas.Pen.Width := 0;
  ACanvas.Pen.Style := psSolid;
  ACanvas.Brush.Style := bsClear;
  ACanvas.Rectangle(P1.X, P1.Y, P2.X, P2.Y);
end;

// 用紙サイズの設定
procedure SetPaperSize(Size: Integer);
begin
  case Size of
    0: begin // A0
         PaperSize.Width  :=1189;
         PaperSize.Height := 841;
       end;
    1: begin // A1
         PaperSize.Width  := 841;
         PaperSize.Height := 594;
       end;
    2: begin // A2
         PaperSize.Width  := 594;
         PaperSize.Height := 420;
       end;
    3: begin // A3
         PaperSize.Width  := 420;
         PaperSize.Height := 297;
       end;
    4: begin // A4
         PaperSize.Width  := 297;
         PaperSize.Height := 210;
       end;
  else
    PaperSize.Width  :=1189;
    PaperSize.Height := 841;
  end;
end;

// JWWデータを描画します。
procedure JWWDataDraw(APaintBox: TPaintBox);

  procedure Calc_mm_dot;
  var
    P1, P2: Double;
  begin
    ImageSize.Width  := APaintBox.Width;
    ImageSize.Height := APaintBox.Height;
    P1 := ImageSize.Width  / PaperSize.Width;
    P2 := ImageSize.Height / PaperSize.Height;

    if mm_dot = 0 then
    begin
      if (P1 < P2) then
        mm_dot := P1
      else
        mm_dot := P2;
    end;
  end;

  procedure Calc_ViewArea;
  begin
    ViewArea.Left   := - (ImageSize.Width  / 2.0) / mm_dot;
    ViewArea.Top    := - (ImageSize.Height / 2.0) / mm_dot;
    ViewArea.Right  :=   (ImageSize.Width  / 2.0) / mm_dot;
    ViewArea.Bottom :=   (ImageSize.Height / 2.0) / mm_dot;
  end;

begin
  if not CanDraw then Exit;
  Calc_mm_dot;
  Calc_ViewArea;
  APaintBox.Invalidate;
end;

// CADデータの描画
procedure DrawData(ACanvas: TCanvas);

  // 画面の消去
  procedure CLS;
  begin
    ACanvas.Pen.Mode  := pmCopy;
    ACanvas.Pen.Color := clWhite;
    ACanvas.Pen.Style := psSolid;
    ACanvas.Pen.Width := 1;

    ACanvas.Brush.Color := clWhite;
    ACanvas.Brush.Style := bsSolid;
    ACanvas.Rectangle(0, 0, ImageSize.Width, ImageSize.Height);
  end;

  // 用紙枠の描画
  procedure Draw_Paper_Frame;
  var
    ARect: TRect;
  begin
    // 原点の計算
    OriginPoint.X := Round( (0.0 - ViewArea.Left  ) * mm_dot);
    OriginPoint.Y := Round(-(0.0 - ViewArea.Bottom) * mm_dot);

    // 用紙枠の描画
    ARect.Left   := Round( (-PaperSize.Width / 2 - ViewArea.Left  ) * mm_dot);
    ARect.Top    := Round(-(-PaperSize.Height/ 2 - ViewArea.Bottom) * mm_dot);
    ARect.Right  := Round( ( PaperSize.Width / 2 - ViewArea.Left  ) * mm_dot);
    ARect.Bottom := Round(-( PaperSize.Height/ 2 - ViewArea.Bottom) * mm_dot);
    ACanvas.Pen.Color := clBlue;
    ACanvas.Brush.Style := bsClear;
    ACanvas.Rectangle(ARect);
  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 LineSetting(Root: CData);
  begin
    ACanvas.Pen.Width := 0;
    case Root.m_nPenStyle of
      1: ACanvas.Pen.Style := psSolid;
      2,3,4,9: ACanvas.Pen.Style := psDot;
      5,6,7,8: ACanvas.Pen.Style := psDashDot;
    end;
    case Root.m_nPenColor of
      1: ACanvas.Pen.Color := RGB(0,192,192);
      2: ACanvas.Pen.Color := clBlack;
      3: ACanvas.Pen.Color := RGB(0,192,0);
      4: ACanvas.Pen.Color := RGB(192,192,0);
      5: ACanvas.Pen.Color := RGB(192,0,192);
      6: ACanvas.Pen.Color := RGB(0,0,255);
      7: ACanvas.Pen.Color := RGB(0,128,128);
      8: ACanvas.Pen.Color := RGB(255,0,128);
      9: ACanvas.Pen.Color := RGB(255,128,255);
    end;
  end;

  // フォントの設定
  function FontSetting(ACDataMoji: CDataMoji): Boolean;
  var
    I: Integer;
  begin
    Result := True;
    ACanvas.Font.Name := ACDataMoji.m_strFontName;
    ACanvas.Font.Height := Round(ACDataMoji.m_dSizeY * mm_dot);
    if ACanvas.Font.Height = 0 then
    begin
      Result := False;
      Exit;
    end;
    // フォントのスタイルの設定
    I := ACDataMoji.m_nMojiShu;
    if I >= 30000 then      // ボールド + 斜体文字
    begin
      ACanvas.Font.Style := [fsBold,fsItalic];
      I := I - 30000
    end
    else if I >= 20000 then // ボールド
    begin
      ACanvas.Font.Style := [fsBold];
      I := I -20000
    end
    else if I >= 10000 then // 斜体文字
    begin
      ACanvas.Font.Style := [fsItalic];
      I := I -10000;
    end
    else
      ACanvas.Font.Style := [];

    // フォントの色の設定
    case JWWHd.m_Moji[I].m_anMojiCol of
      1: ACanvas.Font.Color := RGB(0,192,192);
      2: ACanvas.Font.Color := clBlack;
      3: ACanvas.Font.Color := RGB(0,192,0);
      4: ACanvas.Font.Color := RGB(192,192,0);
      5: ACanvas.Font.Color := RGB(192,0,192);
      6: ACanvas.Font.Color := RGB(0,0,255);
      7: ACanvas.Font.Color := RGB(0,128,128);
      8: ACanvas.Font.Color := RGB(255,0,128);
      9: ACanvas.Font.Color := RGB(255,128,255);
     10: ACanvas.Font.Color := clBlack; // 不明
    end;
  end;

  // レイヤーの表示/非表示
  function LayerCheck(Root: CData): Boolean;
  var
    I, J: Integer;
    F1, F2: Boolean;
  begin
    I := Root.m_nGLayer;
    J := Root.m_nLayer;
    F1 := JWWHd.GLay[I].m_anGLay <> 0;
    F2 := JWWHd.GLay[I].m_nLay[J].m_aanLay <> 0;
    Result := F1 and F2;
  end;

  // 補助線かどうか
  function IsSupportLine(Root: CData): Boolean;
  begin
    Result := (Root.m_nPenStyle = 9);
  end;

  // 線の描画
  procedure DrawSen(Sen: CDataSen);
  var
    P1, P2: TPoint;
  begin
    if (not IsSupportLine(Sen.Root)) and LayerCheck(Sen.Root) then
    begin
      Change_mm_dot_Point(PointEx(Sen.m_start_x, Sen.m_start_y), P1);
      Change_mm_dot_Point(PointEx(Sen.m_end_x  , Sen.m_end_y  ), P2); 

      LineSetting(Sen.Root);

      ACanvas.MoveTo(P1.X, P1.Y);
      ACanvas.LineTo(P2.X, P2.Y);
    end;
  end;

  { 旧FDelphi 玉石混淆みんなで作るSample蔵「斜め楕円の描画 」 }
  // 凛さん、裏目小僧さんのコード
  procedure Ellipse2(Center: TPoint; LongRadius, ShortRadius, Angle,
    angleFrom, angleTo: Extended);

    function rot(x,y: Extended; rad: Extended):TPointEx;//rad:radian
    var
      ss, cc: Extended;
    begin
      ss := sin(rad);
      cc := cos(rad);
      Result.x := cc*x-ss*y;
      Result.y := ss*x+cc*y;
    end;

    procedure drawDeclinedEllipsePP(aFrom, aTo: Extended);
    var
      I: Integer;
      bufP: array[0..3] of TPointEx;
      thePoints:array[0..3] of TPoint;
      s,c,xc,yc,fa: Extended;
    begin
      fa := aTo-aFrom;
      s := sin(fa);
      c := cos(fa);
      xc := cos(fa/2);
      yc := sin(fa/2);
      bufP[0].x := 1;
      bufP[0].y := 0;
      bufP[1].x := 1;
      bufP[1].y := -4*c*(1+c-2*xc)/s/3+4*(2*yc-s)/3;
      bufP[2].x := (-4-c+8*xc)/3;
      bufP[2].y :=  4*c*(1+c-2*xc)/s/3+s;
      bufP[3].x := c;
      bufP[3].y := s;

      for I:= 0 to 3 do
      begin
        bufP[I]:=rot(BufP[I].x,bufP[I].y,aFrom);
        bufP[I]:=rot(LongRadius*BufP[I].x,shortRadius*BufP[I].y,angle);
        thePoints[I].x:=round(bufP[I].x + Center.X);
        thePoints[I].y:=round(bufP[I].y + Center.Y);
      end;
      PolyBezier(ACanvas.Handle, thePoints, 4);
    end;

  const
    Err=0.001;
  var
    sep, I: Integer;
    division: Extended;
  begin
    division := PI/3;
    sep := Trunc((AngleTo-AngleFrom)/division);
    for I := 0 to sep-1 do
      drawDeclinedEllipsePP(angleFrom+ I*division, angleFrom+(I+1)*division);
    if (AngleTo-AngleFrom)-(sep*division) > Err then
      drawDeclinedEllipsePP(angleFrom+sep*division, angleTo);
  end;

  // 円弧の描画
  procedure DrawEnko(Enko: CDataEnko; IsSolid: Boolean=False);
  var
    Center: TPointEx;
    x1, y1, Hankei: Double;
    LongRadius, ShortRadius: Double;
    Hajime, Owari, Inclination: Double;
    PEx1, PEx2: TPointEx;
    P1, P2, P3,P4: TPoint;
  begin
    Hajime := Enko.m_radKaishiKaku + Enko.m_radKatamukiKaku;
    Owari :=  Enko.m_radKaishiKaku + Enko.m_radEnkoKaku +
              Enko.m_radKatamukiKaku;

    if (not IsSupportLine(Enko.Root)) and LayerCheck(Enko.Root) then
    begin
      x1 := Enko.m_start_x;
      y1 := Enko.m_start_y;
      Center.X := X1;
      Center.Y := Y1;
      Hankei := Enko.m_dHankei;

      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
        begin
          if Enko.m_radKatamukiKaku = 0 then
          begin
            // 斜め描画しない
            // 円(楕円)・全円(全楕円)ソリッド
            ACanvas.Ellipse(P1.X,P1.Y,P2.X,P2.Y);
          end
          else
          begin
            // 斜め描画する
            Change_mm_dot_Point(Center, P3);
            if Enko.m_radKatamukiKaku < 0 then
              Inclination := (PI /2) - Enko.m_radKatamukiKaku
            else
              Inclination := - Enko.m_radKatamukiKaku;

            LongRadius := (P2.X-P1.X) div 2;
            ShortRadius := (P2.Y-P1.Y) div 2;
            Hajime := DegToRad(0);
            Owari  := DegToRad(360);
            Ellipse2(P3, LongRadius, ShortRadius, Inclination, Hajime, Owari);
          end;
        end;
      end
      else
      begin
        // 楕円弧の場合
        if Enko.m_dHenpeiRitsu <> 1.0 then
        begin
          Change_mm_dot_Point(Center, P3);
          if Enko.m_radKatamukiKaku < 0 then
            Inclination := (PI /2) - Enko.m_radKatamukiKaku
          else
            Inclination := -Enko.m_radKatamukiKaku;

          LongRadius  := (P2.X-P1.X) div 2;
          ShortRadius := (P2.Y-P1.Y) div 2;

          Hajime := (Inclination+Enko.m_radKatamukiKaku+Enko.m_radKaishiKaku);
          Owari  := (Inclination+Enko.m_radKatamukiKaku+Enko.m_radKaishiKaku +
            Enko.m_radEnkoKaku);

          Ellipse2(P3, LongRadius, ShortRadius, Inclination, Hajime, Owari);
        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_radEnkoKaku < 0) then
              SetArcDirection(ACanvas.Handle, AD_CLOCKWISE)          // 時計回り
            else
              SetArcDirection(ACanvas.Handle, AD_COUNTERCLOCKWISE);  // 反時計回り

            if Enko.m_bZenEnFlg = 0 then
              ACanvas.Arc(P1.X,P1.Y,P2.X,P2.Y,P3.X,P3.Y,P4.X,P4.Y)   // 円弧
            else if Enko.m_bZenEnFlg = 2 then
              ACanvas.Chord(P1.X,P1.Y,P2.X,P2.Y,P3.X,P3.Y,P4.X,P4.Y) // 弓形ソリッド
            else if Enko.m_bZenEnFlg = 3 then
              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;

  // 文字の描画
  procedure DrawMoji(Moji: CDataMoji);
  var
    S: String;
    LF: TLogFont;
    P1, P2: TPoint;
  begin
    if LayerCheck(Moji.Root) then
    begin
      S := Moji.m_string;

      // mm→dot変換
      Change_mm_dot_Point(PointEx(Moji.m_start_x, Moji.m_start_y), P1);
      Change_mm_dot_Point(PointEx(Moji.m_end_x  , Moji.m_end_y  ), P2);

      // フォントの設定
      if FontSetting(Moji) then
      begin
        // 文字の描画
        GetObject(ACanvas.Font.Handle, SizeOf(LF), @LF);
        SetTextAlign(ACanvas.Handle,TA_LEFT or TA_BOTTOM);
        LF.lfEscapement := Round(Moji.m_degKakudo*10);
        ACanvas.Font.Handle := CreateFontIndirect(LF);
        ACanvas.TextOut(P1.X, P1.Y, S);
      end;
    end;
  end;

  // ブロック図形の描画---回転や倍率は未対応です。
  // いまいち理解できていないので、間違った処理かも??
  var
    x1, y1: Double;

  procedure DrawBlock(CDB: CDataBlock);
  var
    I,J: Integer;
    Sen1: CDataSen;
    Enko1: CDataEnko;
    Moji1: CDataMoji;
    Solid1: CDataSolid;
  begin
    I := CDB.m_n_Number;
    x1 := CDB.m_DPKijunTen_x+x1;
    y1 := CDB.m_DPKijunTen_y+y1;

    for J := JWWBlockList.BlockList[I].Count-1  downto 0 do
    begin
      case JWWBlockList.DataType[I,J] of
        Sen: begin
               Sen1 := JWWBlockList.DataSen[I,J];
               Sen1.m_start_x := Sen1.m_start_x+x1;
               Sen1.m_start_y := Sen1.m_start_y+y1;
               Sen1.m_end_x   := Sen1.m_end_x  +x1;
               Sen1.m_end_y   := Sen1.m_end_y  +y1;
               DrawSen(Sen1);
             end;
        Enko: begin
               Enko1 := JWWBlockList.DataEnko[I,J];
               Enko1.m_start_x := Enko1.m_start_x+x1;
               Enko1.m_start_y := Enko1.m_start_y+y1;
               DrawEnko(Enko1);
             end;
        Moji: begin
               Moji1 := JWWBlockList.DataMoji[I,J];
               Moji1.m_start_x := Moji1.m_start_x+x1;
               Moji1.m_start_y := Moji1.m_start_y+y1;
               DrawMoji(Moji1);
             end;
        Solid: begin
               Solid1 := JWWBlockList.DataSolid[I,J];
               Solid1.m_start_x := Solid1.m_start_x+x1;
               Solid1.m_start_y := Solid1.m_start_y+y1;
               Solid1.m_end_x := Solid1.m_end_x+x1;
               Solid1.m_end_y := Solid1.m_end_y+y1;
               Solid1.m_DPoint2_x := Solid1.m_DPoint2_x+x1;
               Solid1.m_DPoint2_y := Solid1.m_DPoint2_y+y1;
               Solid1.m_DPoint3_x := Solid1.m_DPoint3_x+x1;
               Solid1.m_DPoint3_y := Solid1.m_DPoint3_y+y1;
               DrawSolid(Solid1);
             end;
        Block: begin
                DrawBlock(JWWBlockList.DataBlock[I,J]);
             end;
      end;
    end;
  end;

var
  I: Integer;
begin
  // 画面の消去
  CLS;

  // 用紙枠の描画
  Draw_Paper_Frame;

  // 線の描画
  for I := Low(JWWSen) to High(JWWSen) do
    DrawSen(JWWSen[I]);

  // 円弧の描画
  for I := Low(JWWEnko) to High(JWWEnko) do
    DrawEnko(JWWEnko[I]);

  // 文字の描画
  for I := Low(JWWMoji) to High(JWWMoji) do
    DrawMoji(JWWMoji[I]);

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

  // ブロックデータの描画
   for I:= Low(JWWBlock) to High(JWWBlock) do
   begin
     x1:= 0; y1 := 0;
     DrawBlock(JWWBlock[I]);
   end;
end;

// ビュー中央の座標、ビューの幅、高さを取得
procedure GetViewInfo(var View_CenterPoint: TPointEx;
  var View_Width, View_Height: Double);
begin
  View_CenterPoint.X := (ViewArea.Left + ViewArea.Right) / 2.0;
  View_CenterPoint.Y := (ViewArea.Top + ViewArea.Bottom) / 2.0;
  View_Width    := Abs(ViewArea.Right - ViewArea.Left);
  View_Height   := Abs(ViewArea.Bottom - ViewArea.Top);
end;

// 用紙枠の描画サイズ
procedure GetPaperFrameDrawSize(var ARect: TRect;
  AView_x1, AView_y1, Amm_dot: Double);
begin
  ARect.Left   := Round( (-PaperSize.Width /2.0 - AView_x1) * Amm_dot);
  ARect.Bottom := Round(-(-PaperSize.Height/2.0 - AView_y1) * Amm_dot);
  ARect.Right  := Round( ( PaperSize.Width /2.0 - AView_x1) * Amm_dot);
  ARect.Top    := Round(-( PaperSize.Height/2.0 - AView_y1) * Amm_dot);
end; 

// 拡大
procedure ZoomUp(ACanvas: TCanvas);
var
  View_Width, View_Height: Double;
  View_CenterPoint: TPointEx;

  // 一定以上大きくさせない。
  function LargeCheck: Boolean;
  const
    Max = 80000;
  var
    Check_mm_dot, Check_view_x1, Check_view_y1: Double;
    ARect: TRect;
  begin
    Result := False;

    //2倍に拡大
    Check_mm_dot := mm_dot * 2.0;
    Check_view_x1 := View_CenterPoint.x - (View_Width  / 4.0);
    Check_view_y1 := View_CenterPoint.y + (View_Height / 4.0);

    // 用紙枠の描画サイズ
    GetPaperFrameDrawSize(ARect,Check_view_x1,Check_view_y1,Check_mm_dot);
       
    if (ARect.Right-ARect.Left > Max) or (ARect.Bottom- ARect.Top >Max) then Exit;
    Result := True;
  end;

begin
  // ビュー中央の座標、ビューの幅、高さを取得
  GetViewInfo(View_CenterPoint, View_Width, View_Height);

  // 一定以上拡大させない。
  if not LargeCheck then  Exit;

  //2倍に拡大
  mm_dot := mm_dot * 2.0;

  ViewArea.Left   := View_CenterPoint.X - (View_Width /4.0);
  ViewArea.Top    := View_CenterPoint.Y - (View_Height/4.0);
  ViewArea.Right  := View_CenterPoint.X + (View_Width /4.0);
  ViewArea.Bottom := View_CenterPoint.Y + (View_Height/4.0);

  DrawData(ACanvas);
end;

// 縮小
procedure ZoomDown(ACanvas: TCanvas);
var
  View_Width, View_Height: Double;
  View_CenterPoint: TPointEx;  

  // 一定以上縮小させない。
  function SmallCheck: Boolean;
  const
    Min = 10;
  var
    Check_mm_dot, Check_view_x1, Check_view_y1: Double;
    ARect: TRect;
  begin
    Result := False;
    // 1/2倍に縮小
    Check_mm_dot := mm_dot * 0.5;
    Check_view_x1 := View_CenterPoint.X - View_Width;
    Check_view_y1 := View_CenterPoint.Y + View_Height;

    // 用紙枠の描画サイズ
    GetPaperFrameDrawSize(ARect,Check_view_x1,Check_view_y1,Check_mm_dot);
    if (ARect.Right-ARect.Left < Min) or (ARect.Bottom-ARect.Top <Min) then Exit;
    Result := True;
  end;

begin
  // ビュー中央の座標、ビューの幅、高さを取得
  GetViewInfo(View_CenterPoint, View_Width, View_Height);

  // 一定以上縮小させない。
  if not SmallCheck then  Exit;
  
  // 1/2倍に縮小
  mm_dot := mm_dot * 0.5;
  ViewArea.Left   := View_CenterPoint.X - View_Width;
  ViewArea.Top    := View_CenterPoint.Y - View_Height;
  ViewArea.Right  := View_CenterPoint.X + View_Width;
  ViewArea.Bottom := View_CenterPoint.Y + View_Height;

  DrawData(ACanvas);
end;

// レイヤー名及び表示/非表示の設定
procedure SetLayerName(ATreeView: TTreeView);

  // ノードのチェックボックス設定
  procedure NodeCheckBox(Node: TTreeNode; F: Boolean);
  var
    TvItem: TTVItem;
  begin
    TvItem.hItem := Node.ItemId;
    TvItem.stateMask := TVIS_STATEIMAGEMASK;
    TvItem.mask := TVIF_HANDLE or TVIF_STATE;
    if F then
      TvItem.state := TVIS_CHECKED
    else
      TvItem.state := TVIS_CHECKED shr 1;
    TreeView_SetItem(ATreeView.Handle, TvItem);
  end;

  // 太字設定
  procedure SetBold(Node: TTreeNode);
  var
    TvItem: TTVItem;
  begin
    TvItem.hItem := Node.ItemId;
    TvItem.stateMask := TVIS_BOLD;
    TvItem.mask := TVIF_HANDLE or TVIF_STATE;
    TvItem.state := TVIS_BOLD;
    TreeView_SetItem(ATreeView.Handle, TvItem);
  end;

var
  I, J, K, SNo, ENo: Integer;
  NodeA, NodeB: TTreeNode;
  LayerNo, Scale, LayerName: String;
  F: Boolean;
begin
  ATreeView.Items.BeginUpdate;
  try
    ATreeView.Items.Clear;
    // レイヤーグループの設定
    for I := Low(JWWHd.m_aStrGLayName) to High(JWWHd.m_aStrGLayName) do
    begin
      // レイヤーグループ番号
      LayerNo := '[' + IntToHex(I, 1) +'] ';
      // 縮尺
      if JWWHd.GLay[I].m_adScale < 1 then
        Scale := IntToStr(Round(1 / JWWHd.GLay[I].m_adScale)) + '/1'
      else
        Scale := '1/'+ IntToStr(Trunc(JWWHd.GLay[I].m_adScale));

      // レイヤーグループ名
      LayerName := ' ' + JWWHd.m_aStrGLayName[I];

      // ノードの追加及び表示/非表示の設定
      NodeA := ATreeView.Items.Add(nil, LayerNo + Scale + LayerName);
      F := JWWHd.GLay[I].m_anGLay <> 0;
      NodeCheckBox(NodeA, F);
      SetBold(NodeA);

      // レイヤーの設定
      SNo := I * 16;   // 読み取り開始番号
      ENo := SNo + 15; // 読み取り終了番号
      for J := SNo to ENo do
      begin
        K := J - SNo;
        LayerNo := '[' + IntToHex(K, 1) +'] ';       // レイヤーグループ番号
        LayerName := ' ' + JWWHd.m_aStrLayName[J];   // レイヤー名
        // ノードの追加及び表示/非表示の設定
        NodeB := ATreeView.Items.AddChild(NodeA, LayerNo + LayerName);
        F := JWWHd.GLay[I].m_nLay[K].m_aanLay <> 0;
        NodeCheckBox(NodeB, F);
      end;
    end;
  finally
    ATreeView.Items.EndUpdate;
  end;
end;

end.


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

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

|

« ■『Tiburón』フィールドテスター募集開始 | トップページ | ■Office Open XML、ISO標準に・・・。 »