/* ---------------------------------------------------------------------------

  How to get entities properties.

  1. Create procedure of type:
    typedef int __fastcall (__closure *TsgCADEntityProc)(TsgDXFEntity* Entity);
    in this demo: function int __fastcall TForm1.ReadCADEntities(TsgDXFEntity * Entity): Integer;

   2. Crate TsgCADIterate object:
     TsgCADIterate FCADParams; in this demo

   3. Create TsgDXFImage object (in the demo it is made in Button1Click
     on Image1->Picture->LoadFromFile(OpenPictureDialog1.FileName);
     and stored in Image1->Picture->Graphic.

   4. Set (TsgDXFImage object).Converer.AutoInsert := True
     See Conv->AutoInsert = true; // to get all the elements inside of inserts

   5. Call (TsgDXFImage object)->Converer->Iterate with parameters made in items 1. and 2.
     TsgDXFImage(Image1.Picture.Graphic)->CurrentLayout->Iterate(TsgDXFImage(Image1->Picture->Graphic)->Converter, ReadCADEntities, FinishReadCADEntities);

   6.  in procedure made in item 1. read all the entities:
       int __fastcall ReadCADEntities(TsgDXFEntity * Entity)
       {
       //  use Entity here, see documentation about properties of different classes,
       //  allows to get lines, text, arcs, etc.
       }

   7. Implements finishing actions after entities' import
      int __fastcall FinishReadCADEntities(TsgDXFEntity * Entity);

*/
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
#include <DXFConv.hpp>
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"

TForm1 *Form1;
TFPoint PtXMat(TFPoint P, TFMatrix M);
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------

float Part(int i, TFPoint P, TFMatrix M)
{
    return P.X * M[0][i] + P.Y * M[1][i] + P.Z * M[2][i] + M[3][i];
}
//---------------------------------------------------------------------------

TFPoint PtXMat(TFPoint P, TFMatrix M)
{
  TFPoint P1;
  P1.X = Part(0, P, M);
  P1.Y = Part(1, P, M);
  P1.Z = Part(2, P, M);
  return P1;
}
//---------------------------------------------------------------------------

AnsiString PointToString(TFPoint P)
{
  return "X=" + FloatToStr(P.X)+ " Y="+ FloatToStr(P.Y)+ " Z="+ FloatToStr(P.Z);
}
//---------------------------------------------------------------------------

int __fastcall TForm1::ReadCADEntities(TsgDXFEntity * Entity)
{
  AnsiString PS[4] = {"psSolid", "psDash", "psDot", "psDashDot"};

  AnsiString S;
  TsgDXFLayer *L;
  TColor C;

  S = "ClassName=" + Entity->ClassName();
  S = S + "; Entity name=" + Entity->EntName();
  DoScale2D(FCADParams); // calculates 2d scale and rotation
  // layer
  L = EntLayer(Entity, FCADParams.Insert);
  if (L) S = S + " layer = " + L->Name;
  // color
  S = S + " style = " + PS[(int)EntStyle(Entity)];
  C = EntColor(Entity, FCADParams.Insert);
  if (C == clNone)
    S = S + " color=black/white";
  else
    S = S + " color = " +  IntToHex((int)C, -6) + " (" + ColorToString(C) + ")";
  // particular properties
  TextFile->Add(S);

  switch (Entity->EntType)
  {
    case ceLine:
      ImportLine(Entity);    //Line - see dxfimage.pas TsgDXFImage.DrawArc
      break;
    case cePoint:
      ImportPoint(Entity);   //Point - see dxfimage.pas TsgDXFImage.DrawPoint
      break;
    case ceCircle:
      ImportCircle(Entity);  //Circle - see dxfimage.pas TsgDXFImage.DrawArc
      break;
    case ceArc:
      ImportArc(Entity);     //Arc - see dxfimage.pas TsgDXFImage.DrawArc
      break;
    case ceEllipse:
      ImportEllipse(Entity); //Ellipse - see dxfimage.pas TsgDXFImage.DrawArc
      break;
    case cePolyline:
    case cePath:
      ImportPolyLine(Entity);//PolyLine - see dxfimage.pas TsgDXFImage.DrawPolyLine
      break;
    case ceSpline:
    case ceLeader:  //Spline - see dxfimage.pas TsgDXFImage.DrawSpline
      ImportSpline(Entity);  //Leader - see dxfimage.pas TsgDXFImage.DrawLeader
      break;
    case ceText:
      ImportText(Entity);    //Text - see dxfimage.pas TsgDXFImage.DrawText
      break;
    case ceAttdef:
    case ceAttrib:
      ImportAttdef(Entity);  //Attdef - see dxfimage.pas TsgDXFImage.DrawText
      break;
    case ceSolid:
    case ce3dFace:  //Solid  - see dxfimage.pas TsgDXFImage.DrawSolid
      ImportSolid(Entity);   //Face - see dxfimage.pas TsgDXFImage.DrawFace
      break;
    case ceViewport:
      ImportViewPortBegin(Entity);    //ViewPort - see dxfimage.pas TsgDXFImage.DrawViewPort
      return 1;
    /* Other entities (for future versions) see dxfimage.pas
    case ceDimension:
      ImportDimension(Entity);
      break;
    case ceInsert:
    case ceMText:
      ImportInsert(Entity);
      break;
    case cePolyPolygon:
    case ceGradient:
    case ceGradientPolygon:
    case ceCurvePolygon:
    case ceHatch:
      ImportHatch(Entity);
      break;
    case ceImageEnt:
      ImportImage(Entity);
      break;
    case ceRegion:
    case ceBody:
    case ce3DSolid:
      ImportACISEntity(Entity);
      break;
    case ceOle2Frame:
      ImportOle2Frame(Entity);
      break;
    case ceFlatPoly:
      ImportFlatPoly(Entity);
      break;
    case ceFlatHatch:
      ImportFlatHatch(Entity);
      break;
    case ceXRef:
      ImportXRef(Entity);
      break;
      */
  }
  return 0;
}

//---------------------------------------------------------------------------

void __fastcall TForm1::BtnImportClick(TObject *Sender)
{
  TsgDXFImage * vImg;


  #ifdef sgDXFONLY
  OpenPictureDialog1->FilterIndex = 2;
  #endif

  OpenPictureDialog1->FileName = "";
  if (OpenPictureDialog1->Execute())
  {
    Image1->Picture->LoadFromFile(OpenPictureDialog1->FileName);
    vImg = dynamic_cast<TsgDXFImage *>(Image1->Picture->Graphic);
    if (vImg)
    {
      cbLayouts->Items->Clear();
      for(int i = 0; i < vImg->LayoutsCount; i++)
        cbLayouts->Items->AddObject(vImg->Layouts[i]->Name, vImg->Layouts[i]);
      cbLayouts->ItemIndex = vImg->Converter->DefaultLayoutIndex;
      vImg->CurrentLayout = vImg->Layouts[cbLayouts->ItemIndex];
    }
  }
}
//---------------------------------------------------------------------------


void __fastcall TForm1::ImportSolid(TObject *Sender)
{
  TFPoint P;
  P = PtXMat(((TsgDXFSolid *)Sender)->Point, FCADParams.Matrix);
  TVarRec v[] = {P.X, P.Y, P.Z};
  TextFile->Add(Format("P1: X=%.6f Y=%.6f Z=%.6f", v, ARRAYSIZE(v)-1));
  P = PtXMat(((TsgDXFSolid *)Sender)->Point1, FCADParams.Matrix);
  TVarRec v1[] = {P.X, P.Y, P.Z};
  TextFile->Add(Format("P2: X=%.6f Y=%.6f Z=%.6f", v1, ARRAYSIZE(v1)-1));
  P = PtXMat(((TsgDXFSolid *)Sender)->Point2, FCADParams.Matrix);
  TVarRec v2[] = {P.X, P.Y, P.Z};
  TextFile->Add(Format("P3: X=%.6f Y=%.6f Z=%.6f", v2, ARRAYSIZE(v2)-1));
  P = PtXMat(((TsgDXFSolid *)Sender)->Point3, FCADParams.Matrix);
  TVarRec v3[] = {P.X, P.Y, P.Z};
  TextFile->Add(Format("P4: X=%.6f Y=%.6f Z=%.6f", v3, ARRAYSIZE(v3)-1));
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ImportLine(TObject *Sender)
{
  TFPoint P;
  P = PtXMat(((TsgDXFLine *)Sender)->Point, FCADParams.Matrix);
  TVarRec v[] = {P.X, P.Y, P.Z};
  TextFile->Add(Format(" Begin point: X=%.6f Y=%.6f Z=%.6f", v, ARRAYSIZE(v)-1));
  P = PtXMat(((TsgDXFLine *)Sender)->Point1, FCADParams.Matrix);
  TVarRec v1[] = {P.X, P.Y, P.Z};
  TextFile->Add(Format(" End point: X=%.6f Y=%.6f Z=%.6f", v1, ARRAYSIZE(v1)-1));
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ImportEllipse(TObject *Sender)
{
  TFPoint P;
  P = PtXMat(((TsgDXFEllipse *)Sender)->Point, FCADParams.Matrix);
  TVarRec v[] = {P.X, P.Y, P.Z};
  TextFile->Add("Center of Ellipse: ");
  TextFile->Add(Format(" Begin point: X=%.6f Y=%.6f Z=%.6f", v, ARRAYSIZE(v)-1));
  TVarRec v1[] = {((TsgDXFEllipse*)Sender)->StartAngle};
  TextFile->Add(Format(" Start Angle: %.6f", v1, ARRAYSIZE(v1)-1));
  TVarRec v2[] = {((TsgDXFEllipse*)Sender)->EndAngle};
  TextFile->Add(Format(" End Angle: %.6f", v2, ARRAYSIZE(v2)-1));
  TVarRec v3[] = {((TsgDXFEllipse *)Sender)->Radius,
    ((TsgDXFEllipse *)Sender)->Radius * ((TsgDXFEllipse *)Sender)->Ratio};
  TextFile->Add(Format(" Rx: %.6f  Ry: %.6f ", v3, ARRAYSIZE(v3)-1));
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ImportArc(TObject *Sender)
{
  TFPoint P;
  P = PtXMat(((TsgDXFArc *)Sender)->Point, FCADParams.Matrix);
  TVarRec v[] = {P.X, P.Y, P.Z};
  TextFile->Add(Format(" Center of RoundArc: X=%.6f Y=%.6f Z=%.6f", v, ARRAYSIZE(v)-1));
  TVarRec v1[] = {((TsgDXFArc *)Sender)->StartAngle};
  TextFile->Add(Format(" Start Angle: %.6f", v1, ARRAYSIZE(v1)-1));
  TVarRec v2[] = {((TsgDXFArc *)Sender)->EndAngle};
  TextFile->Add(Format(" End Angle: %.6f", v2, ARRAYSIZE(v2)-1));
  TVarRec v3[] = {((TsgDXFArc *)Sender)->Radius};
  TextFile->Add(Format(" Rx: %.6f", v3, ARRAYSIZE(v3)-1));;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ImportCircle(TObject *Sender)
{
  TFPoint P;
  P = PtXMat(((TsgDXFCircle *)Sender)->Point, FCADParams.Matrix);
  TVarRec v[] = {P.X, P.Y, P.Z};
  TextFile->Add(Format(" Center of Circle: X=%.6f Y=%.6f Z=%.6f", v, ARRAYSIZE(v)-1));
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ImportPolyLine(TObject *Sender)
{
  int I;
  TFPoint P;
  AnsiString S;
  TsgDXFVertex *Vertex;
  TsgDXFPolyline *Poly = (TsgDXFPolyline *)Sender;

  if (Poly->Closed)
    TextFile->Add(" Points of Rect:");
  else
    TextFile->Add(" Points of PolyLine:");
  int Cnt = Poly->Count;
  for(I = 0; I < Cnt; I++)
  {
    Vertex = (TsgDXFVertex *)(Poly->Entities[I]);
    P = PtXMat(Vertex->Point, FCADParams.Matrix);
    TVarRec v[] = {P.X, P.Y, P.Z};
    TextFile->Add(" P" + IntToStr(I + 1) + ": " +
      Format(" X=%.6f Y=%.6f Z=%.6f", v, ARRAYSIZE(v)-1));
  }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ImportAttdef(TObject *Sender)
{
  TFPoint P;
  AnsiString S1, S2;
  TsgDXFAttrib *CurAttrib;
  TsgDXFAttdef *vAttDef = (TsgDXFAttdef *)Sender;
  TsgDXFText *vText = (TsgDXFText *)Sender;

  DoScale2D(FCADParams);
  vAttDef->DoNewText(vAttDef->Tag);
  S1 = vText->Text;
  P = PtXMat(vText->StartPoint, FCADParams.Matrix);
  S2 = " Angle=" + FloatToStr(vText->Rotation);
  if (FCADParams.Insert)
  {
    CurAttrib = FCADParams.Insert->Attrib(S1, P);
    if (CurAttrib)
    {
      S1 = CurAttrib->Text;
      P = CurAttrib->Box.TopLeft;
      S2 = " Angle=" + FloatToStr(CurAttrib->Rotation);
    }
  }
  TVarRec v[] = {P.X, P.Y, P.Z};
  TextFile->Add(Format("Start point of Attdef: X=%.6f Y=%.6f Z=%.6f", v, ARRAYSIZE(v)-1));
  TextFile->Add(" Text of Attdef: " + S1 + S2);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ImportText(TObject *Sender)
{
  TFPoint P;
  AnsiString S1, S2;
  TsgDXFText *vText = (TsgDXFText *)Sender;

  DoScale2D(FCADParams);
  S1 = vText->Text;
  P = PtXMat(vText->StartPoint, FCADParams.Matrix);
  TVarRec v[] = {P.X, P.Y, P.Z};
  TextFile->Add(Format(" Start point of Text: X=%.6f Y=%.6f Z=%.6f", v, ARRAYSIZE(v)-1));
  TextFile->Add(" The text is: " + S1);
  TextFile->Add(" Angle=" + FloatToStr(vText->Rotation + FCADParams.Angle));
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ImportSpline(TObject *Sender)
{
  int I;
  TFPoint P;
  TsgDXFVertex *Vertex;
  TsgDXFSpline *vSpline = (TsgDXFSpline *)Sender;

  TextFile->Add("Points of Spline:");

  if (vSpline->FitCount() > 0)
  {
    TextFile->Add(" Fit points of Spline: ");
    for(I = 0; I < vSpline->FitCount(); I++)
    {
      TextFile->Add(" P"+IntToStr(I + 1) + ": ");
      P = PtXMat(*(PFPoint)(vSpline->Fit->Items[I]), FCADParams.Matrix);
      TextFile->Add(PointToString(P));
    }
  }
  TextFile->Add("");
  if (vSpline->ControlCount() > 0)
  {
    TextFile->Add(" Control points of Spline: ");
    for(I = 0; I < vSpline->ControlCount(); I++)
    {
      TextFile->Add(" P" + IntToStr(I + 1) + ": ");
      P = PtXMat(*(PFPoint)(vSpline->Controls->Items[I]), FCADParams.Matrix);
      TextFile->Add(PointToString(P));
    }
  }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ImportViewPortBegin(TObject * Sender)
{
  TsgDXFViewport * V = (TsgDXFViewport *)Sender;
  TextFile->Add("Rect:");
  TextFile->Add("Left= " + FloatToStr(V->Rect.Left));
  TextFile->Add("Top= " + FloatToStr(V->Rect.Top));
  TextFile->Add("   Z1= " + FloatToStr(V->Rect.Z1));
  TextFile->Add("   Right= " + FloatToStr(V->Rect.Right));
  TextFile->Add("   Bottom= " + FloatToStr(V->Rect.Bottom));
  TextFile->Add("   Z2= " + FloatToStr(V->Rect.Z2));
  TextFile->Add("---ENTITIES below are displayed in this VIEWPORT---");
}
//---------------------------------------------------------------------------

int __fastcall TForm1::FinishReadCADEntities(TsgDXFEntity * Entity)
{
  switch (Entity->EntType)
  {
    case ceViewport:
    {
      ImportViewPortEnd(Entity);
      return 1;
    }
    default :
      return 0;
  }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ImportViewPortEnd(TObject * Sender)
{
  TextFile->Add("-----ENTITIES above are displayed in VIEWPORT-----");
}

void __fastcall TForm1::ImportPoint(TObject * Sender)
{
  TFPoint P = PtXMat(((TsgDXFPoint *)Sender)->Point, FCADParams.Matrix);
  TextFile->Add(" Point: ");
  TextFile->Add(PointToString(P));
}
//---------------------------------------------------------------------------

void __fastcall TForm1::btnSaveAsTxtClick(TObject *Sender)
{
  if (Image1->Picture->Graphic->InheritsFrom(__classid(TsgDXFImage)))
  try
  {
    TextFile = new TStringList();
    FCurCell = 0;
    FCADParams.Matrix[0][0] = 1;
    FCADParams.Matrix[1][1] = 1;
    FCADParams.Matrix[2][2] = 1;
    ((TsgDXFImage *)(Image1->Picture->Graphic))->Converter->ImportMode = imImport;
    ((TsgDXFImage *)(Image1->Picture->Graphic))->Converter->AutoInsert = true; // to get all the elements inside of inserts
    ((TsgDXFImage *)(Image1->Picture->Graphic))->Converter->Params = &FCADParams;
    ((TsgDXFImage *)(Image1->Picture->Graphic))->CurrentLayout->Iterate(
      ((TsgDXFImage *)(Image1->Picture->Graphic))->Converter,
      (TsgCADEntityProc)(& ReadCADEntities),
      (TsgCADEntityProc)(& FinishReadCADEntities));
    SaveDialog->FileName = ChangeFileExt(OpenPictureDialog1->FileName, ".txt");
    if (SaveDialog->Execute())
      TextFile->SaveToFile(SaveDialog->FileName);
  }
  __finally
  {
    delete TextFile;
  }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::cbLayoutsChange(TObject *Sender)
{
  if (cbLayouts->Items->Objects[cbLayouts->ItemIndex])
    ((TsgDXFImage *)(Image1->Picture->Graphic))->CurrentLayout =
      ((TsgDXFImage *)(Image1->Picture->Graphic))->Layouts[cbLayouts->ItemIndex];
}
//---------------------------------------------------------------------------


