home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / contrib / src / ogl / ogldiag.cpp < prev    next >
C/C++ Source or Header  |  2002-03-16  |  20KB  |  761 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        ogldiag.cpp
  3. // Purpose:     wxDiagram
  4. // Author:      Julian Smart
  5. // Modified by:
  6. // Created:     12/07/98
  7. // RCS-ID:      $Id: ogldiag.cpp,v 1.5 2002/03/15 20:50:40 RD Exp $
  8. // Copyright:   (c) Julian Smart
  9. // Licence:       wxWindows licence
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. #ifdef __GNUG__
  13. #pragma implementation "ogldiag.h"
  14. #endif
  15.  
  16. // For compilers that support precompilation, includes "wx.h".
  17. #include "wx/wxprec.h"
  18.  
  19. #ifdef __BORLANDC__
  20. #pragma hdrstop
  21. #endif
  22.  
  23. #ifndef WX_PRECOMP
  24. #include <wx/wx.h>
  25. #endif
  26.  
  27. #include <wx/wxexpr.h>
  28.  
  29. #ifdef new
  30. #undef new
  31. #endif
  32.  
  33. #if wxUSE_IOSTREAMH
  34. #include <iostream.h>
  35. #include <fstream.h>
  36. #else
  37. #include <iostream>
  38. #include <fstream>
  39. #ifdef _MSC_VER
  40. //using namespace std;
  41. #endif
  42. #endif
  43.  
  44. #include <ctype.h>
  45. #include <math.h>
  46. #include <stdlib.h>
  47.  
  48. #include <wx/ogl/basic.h>
  49. #include <wx/ogl/basicp.h>
  50. #include <wx/ogl/canvas.h>
  51. #include <wx/ogl/ogldiag.h>
  52. #include <wx/ogl/lines.h>
  53. #include <wx/ogl/composit.h>
  54. #include <wx/ogl/misc.h>
  55.  
  56. IMPLEMENT_DYNAMIC_CLASS(wxDiagram, wxObject)
  57.  
  58. // Object canvas
  59. wxDiagram::wxDiagram()
  60. {
  61.   m_diagramCanvas = NULL;
  62.   m_quickEditMode = FALSE;
  63.   m_snapToGrid = TRUE;
  64.   m_gridSpacing = 5.0;
  65.   m_shapeList = new wxList;
  66.   m_mouseTolerance = DEFAULT_MOUSE_TOLERANCE;
  67. }
  68.  
  69. wxDiagram::~wxDiagram()
  70. {
  71.   if (m_shapeList)
  72.     delete m_shapeList;
  73. }
  74.  
  75. void wxDiagram::SetSnapToGrid(bool snap)
  76. {
  77.   m_snapToGrid = snap;
  78. }
  79.  
  80. void wxDiagram::SetGridSpacing(double spacing)
  81. {
  82.   m_gridSpacing = spacing;
  83. }
  84.  
  85. void wxDiagram::Snap(double *x, double *y)
  86. {
  87.   if (m_snapToGrid)
  88.   {
  89.     *x = m_gridSpacing * ((int)(*x/m_gridSpacing + 0.5));
  90.     *y = m_gridSpacing * ((int)(*y/m_gridSpacing + 0.5));
  91.   }
  92. }
  93.  
  94.  
  95. void wxDiagram::Redraw(wxDC& dc)
  96. {
  97.   if (m_shapeList)
  98.   {
  99.     if (GetCanvas())
  100.       GetCanvas()->SetCursor(* wxHOURGLASS_CURSOR);
  101.     wxNode *current = m_shapeList->First();
  102.  
  103.     while (current)
  104.     {
  105.       wxShape *object = (wxShape *)current->Data();
  106.       if (!object->GetParent())
  107.         object->Draw(dc);
  108.  
  109.       current = current->Next();
  110.     }
  111.     if (GetCanvas())
  112.       GetCanvas()->SetCursor(* wxSTANDARD_CURSOR);
  113.   }
  114. }
  115.  
  116. void wxDiagram::Clear(wxDC& dc)
  117. {
  118.   dc.Clear();
  119. }
  120.  
  121. // Insert object after addAfter, or at end of list.
  122. void wxDiagram::AddShape(wxShape *object, wxShape *addAfter)
  123. {
  124.   wxNode *nodeAfter = NULL;
  125.   if (addAfter)
  126.     nodeAfter = m_shapeList->Member(addAfter);
  127.  
  128.   if (!m_shapeList->Member(object))
  129.   {
  130.     if (nodeAfter)
  131.     {
  132.       if (nodeAfter->Next())
  133.         m_shapeList->Insert(nodeAfter->Next(), object);
  134.       else
  135.         m_shapeList->Append(object);
  136.     }
  137.     else
  138.       m_shapeList->Append(object);
  139.     object->SetCanvas(GetCanvas());
  140.   }
  141. }
  142.  
  143. void wxDiagram::InsertShape(wxShape *object)
  144. {
  145.   m_shapeList->Insert(object);
  146.   object->SetCanvas(GetCanvas());
  147. }
  148.  
  149. void wxDiagram::RemoveShape(wxShape *object)
  150. {
  151.   m_shapeList->DeleteObject(object);
  152. }
  153.  
  154. // Should this delete the actual objects too? I think not.
  155. void wxDiagram::RemoveAllShapes()
  156. {
  157.   m_shapeList->Clear();
  158. }
  159.  
  160. void wxDiagram::DeleteAllShapes()
  161. {
  162.   wxNode *node = m_shapeList->First();
  163.   while (node)
  164.   {
  165.     wxShape *shape = (wxShape *)node->Data();
  166.     if (!shape->GetParent())
  167.     {
  168.       RemoveShape(shape);
  169.       delete shape;
  170.       node = m_shapeList->First();
  171.     }
  172.     else
  173.       node = node->Next();
  174.   }
  175. }
  176.  
  177. void wxDiagram::ShowAll(bool show)
  178. {
  179.   wxNode *current = m_shapeList->First();
  180.  
  181.   while (current)
  182.   {
  183.     wxShape *object = (wxShape *)current->Data();
  184.     object->Show(show);
  185.  
  186.     current = current->Next();
  187.   }
  188. }
  189.  
  190. void wxDiagram::DrawOutline(wxDC& dc, double x1, double y1, double x2, double y2)
  191. {
  192.   wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
  193.   dc.SetPen(dottedPen);
  194.   dc.SetBrush((* wxTRANSPARENT_BRUSH));
  195.  
  196.   wxPoint points[5];
  197.  
  198.   points[0].x = (int) x1;
  199.   points[0].y = (int) y1;
  200.  
  201.   points[1].x = (int) x2;
  202.   points[1].y = (int) y1;
  203.  
  204.   points[2].x = (int) x2;
  205.   points[2].y = (int) y2;
  206.  
  207.   points[3].x = (int) x1;
  208.   points[3].y = (int) y2;
  209.  
  210.   points[4].x = (int) x1;
  211.   points[4].y = (int) y1;
  212.   dc.DrawLines(5, points);
  213. }
  214.  
  215. // Make sure all text that should be centred, is centred.
  216. void wxDiagram::RecentreAll(wxDC& dc)
  217. {
  218.   wxNode *object_node = m_shapeList->First();
  219.   while (object_node)
  220.   {
  221.     wxShape *obj = (wxShape *)object_node->Data();
  222.     obj->Recentre(dc);
  223.     object_node = object_node->Next();
  224.   }
  225. }
  226.  
  227. // Input/output
  228. #ifdef PROLOGIO
  229. bool wxDiagram::SaveFile(const wxString& filename)
  230. {
  231.   wxBeginBusyCursor();
  232.  
  233.   wxExprDatabase *database = new wxExprDatabase;
  234.  
  235.   // First write the diagram type
  236.   wxExpr *header = new wxExpr("diagram");
  237.   OnHeaderSave(*database, *header);
  238.  
  239.   database->Append(header);
  240.  
  241.   wxNode *node = m_shapeList->First();
  242.   while (node)
  243.   {
  244.     wxShape *shape = (wxShape *)node->Data();
  245.  
  246.     if (!shape->IsKindOf(CLASSINFO(wxControlPoint)))
  247.     {
  248.       wxExpr *expr = NULL;
  249.       if (shape->IsKindOf(CLASSINFO(wxLineShape)))
  250.         expr = new wxExpr("line");
  251.        else
  252.         expr = new wxExpr("shape");
  253.  
  254.       OnShapeSave(*database, *shape, *expr);
  255.     }
  256.     node = node->Next();
  257.   }
  258.   OnDatabaseSave(*database);
  259.  
  260.   wxString tempFile;
  261.   wxGetTempFileName(wxT("diag"), tempFile);
  262.   FILE* file = fopen(tempFile.mb_str(wxConvFile), "w");
  263.   if (! file)
  264.   {
  265.     wxEndBusyCursor();
  266.     delete database;
  267.     return FALSE;
  268.   }
  269.  
  270.   database->Write(file);
  271.   fclose(file);
  272.   delete database;
  273.  
  274. /*
  275.   // Save backup
  276.   if (FileExists(filename))
  277.   {
  278.     char buf[400];
  279. #ifdef __X__
  280.     sprintf(buf, "%s.bak", filename);
  281. #endif
  282. #ifdef __WXMSW__
  283.     sprintf(buf, "_diagram.bak");
  284. #endif
  285.     if (FileExists(buf)) wxRemoveFile(buf);
  286.     if (!wxRenameFile(filename, buf))
  287.     {
  288.       wxCopyFile(filename, buf);
  289.       wxRemoveFile(filename);
  290.     }
  291.   }
  292. */
  293.  
  294.   // Copy the temporary file to the correct filename
  295.   if (!wxRenameFile(tempFile, filename))
  296.   {
  297.     wxCopyFile(tempFile, filename);
  298.     wxRemoveFile(tempFile);
  299.   }
  300.  
  301.   wxEndBusyCursor();
  302.   return TRUE;
  303. }
  304.  
  305. bool wxDiagram::LoadFile(const wxString& filename)
  306. {
  307.   wxBeginBusyCursor();
  308.  
  309.   wxExprDatabase database(wxExprInteger, "id");
  310.   if (!database.Read(filename))
  311.   {
  312.     wxEndBusyCursor();
  313.     return FALSE;
  314.   }
  315.  
  316.   DeleteAllShapes();
  317.  
  318.   database.BeginFind();
  319.   wxExpr *header = database.FindClauseByFunctor("diagram");
  320.  
  321.   if (header)
  322.     OnHeaderLoad(database, *header);
  323.  
  324.   // Scan through all clauses and register the ids
  325.   wxNode *node = database.First();
  326.   while (node)
  327.   {
  328.     wxExpr *clause = (wxExpr *)node->Data();
  329.     long id = -1;
  330.     clause->GetAttributeValue("id", id);
  331.     wxRegisterId(id);
  332.     node = node->Next();
  333.   }
  334.  
  335.   ReadNodes(database);
  336.   ReadContainerGeometry(database);
  337.   ReadLines(database);
  338.  
  339.   OnDatabaseLoad(database);
  340.  
  341.   wxEndBusyCursor();
  342.  
  343.   return TRUE;
  344. }
  345.  
  346. void wxDiagram::ReadNodes(wxExprDatabase& database)
  347. {
  348.   // Find and create the node images
  349.   database.BeginFind();
  350.   wxExpr *clause = database.FindClauseByFunctor("shape");
  351.   while (clause)
  352.   {
  353.     wxChar *type = NULL;
  354.     long parentId = -1;
  355.  
  356.     clause->AssignAttributeValue(wxT("type"), &type);
  357.     clause->AssignAttributeValue(wxT("parent"), &parentId);
  358.     wxClassInfo *classInfo = wxClassInfo::FindClass(type);
  359.     if (classInfo)
  360.     {
  361.       wxShape *shape = (wxShape *)classInfo->CreateObject();
  362.       OnShapeLoad(database, *shape, *clause);
  363.  
  364.       shape->SetCanvas(GetCanvas());
  365.       shape->Show(TRUE);
  366.  
  367.       m_shapeList->Append(shape);
  368.  
  369.       // If child of composite, link up
  370.       if (parentId > -1)
  371.       {
  372.         wxExpr *parentExpr = database.HashFind("shape", parentId);
  373.         if (parentExpr && parentExpr->GetClientData())
  374.         {
  375.           wxShape *parent = (wxShape *)parentExpr->GetClientData();
  376.           shape->SetParent(parent);
  377.           parent->GetChildren().Append(shape);
  378.         }
  379.       }
  380.  
  381.       clause->SetClientData(shape);
  382.     }
  383.     if (type)
  384.       delete[] type;
  385.  
  386.     clause = database.FindClauseByFunctor("shape");
  387.   }
  388.   return;
  389. }
  390.  
  391. void wxDiagram::ReadLines(wxExprDatabase& database)
  392. {
  393.   database.BeginFind();
  394.   wxExpr *clause = database.FindClauseByFunctor("line");
  395.   while (clause)
  396.   {
  397.     wxString type;
  398.     long parentId = -1;
  399.  
  400.     clause->GetAttributeValue("type", type);
  401.     clause->GetAttributeValue("parent", parentId);
  402.     wxClassInfo *classInfo = wxClassInfo::FindClass(type);
  403.     if (classInfo)
  404.     {
  405.       wxLineShape *shape = (wxLineShape *)classInfo->CreateObject();
  406.       shape->Show(TRUE);
  407.  
  408.       OnShapeLoad(database, *shape, *clause);
  409.       shape->SetCanvas(GetCanvas());
  410.  
  411.       long image_to = -1; long image_from = -1;
  412.       clause->GetAttributeValue("to", image_to);
  413.       clause->GetAttributeValue("from", image_from);
  414.  
  415.       wxExpr *image_to_expr = database.HashFind("shape", image_to);
  416.  
  417.       if (!image_to_expr)
  418.       {
  419.         // Error
  420.       }
  421.       wxExpr *image_from_expr = database.HashFind("shape", image_from);
  422.  
  423.       if (!image_from_expr)
  424.       {
  425.         // Error
  426.       }
  427.  
  428.       if (image_to_expr && image_from_expr)
  429.       {
  430.         wxShape *image_to_object = (wxShape *)image_to_expr->GetClientData();
  431.         wxShape *image_from_object = (wxShape *)image_from_expr->GetClientData();
  432.  
  433.         if (image_to_object && image_from_object)
  434.         {
  435.           image_from_object->AddLine(shape, image_to_object, shape->GetAttachmentFrom(), shape->GetAttachmentTo());
  436.         }
  437.       }
  438.       clause->SetClientData(shape);
  439.  
  440.       m_shapeList->Append(shape);
  441.     }
  442.  
  443.     clause = database.FindClauseByFunctor("line");
  444.   }
  445. }
  446.  
  447. // Containers have divisions that reference adjoining divisions,
  448. // so we need a separate pass to link everything up.
  449. // Also used by Symbol Library.
  450. void wxDiagram::ReadContainerGeometry(wxExprDatabase& database)
  451. {
  452.   database.BeginFind();
  453.   wxExpr *clause = database.FindClauseByFunctor("shape");
  454.   while (clause)
  455.   {
  456.     wxShape *image = (wxShape *)clause->GetClientData();
  457.     if (image && image->IsKindOf(CLASSINFO(wxCompositeShape)))
  458.     {
  459.       wxCompositeShape *composite = (wxCompositeShape *)image;
  460.       wxExpr *divisionExpr = NULL;
  461.  
  462.       // Find the list of divisions in the composite
  463.       clause->GetAttributeValue("divisions", &divisionExpr);
  464.       if (divisionExpr)
  465.       {
  466.         int i = 0;
  467.         wxExpr *idExpr = divisionExpr->Nth(i);
  468.         while (idExpr)
  469.         {
  470.           long divisionId = idExpr->IntegerValue();
  471.           wxExpr *childExpr = database.HashFind("shape", divisionId);
  472.           if (childExpr && childExpr->GetClientData())
  473.           {
  474.             wxDivisionShape *child = (wxDivisionShape *)childExpr->GetClientData();
  475.             composite->GetDivisions().Append(child);
  476.  
  477.             // Find the adjoining shapes
  478.             long leftSideId = -1;
  479.             long topSideId = -1;
  480.             long rightSideId = -1;
  481.             long bottomSideId = -1;
  482.             childExpr->GetAttributeValue("left_side", leftSideId);
  483.             childExpr->GetAttributeValue("top_side", topSideId);
  484.             childExpr->GetAttributeValue("right_side", rightSideId);
  485.             childExpr->GetAttributeValue("bottom_side", bottomSideId);
  486.             if (leftSideId > -1)
  487.             {
  488.               wxExpr *leftExpr = database.HashFind("shape", leftSideId);
  489.               if (leftExpr && leftExpr->GetClientData())
  490.               {
  491.                 wxDivisionShape *leftSide = (wxDivisionShape *)leftExpr->GetClientData();
  492.                 child->SetLeftSide(leftSide);
  493.               }
  494.             }
  495.             if (topSideId > -1)
  496.             {
  497.               wxExpr *topExpr = database.HashFind("shape", topSideId);
  498.               if (topExpr && topExpr->GetClientData())
  499.               {
  500.                 wxDivisionShape *topSide = (wxDivisionShape *)topExpr->GetClientData();
  501.                 child->SetTopSide(topSide);
  502.               }
  503.             }
  504.             if (rightSideId > -1)
  505.             {
  506.               wxExpr *rightExpr = database.HashFind("shape", rightSideId);
  507.               if (rightExpr && rightExpr->GetClientData())
  508.               {
  509.                 wxDivisionShape *rightSide = (wxDivisionShape *)rightExpr->GetClientData();
  510.                 child->SetRightSide(rightSide);
  511.               }
  512.             }
  513.             if (bottomSideId > -1)
  514.             {
  515.               wxExpr *bottomExpr = database.HashFind("shape", bottomSideId);
  516.               if (bottomExpr && bottomExpr->GetClientData())
  517.               {
  518.                 wxDivisionShape *bottomSide = (wxDivisionShape *)bottomExpr->GetClientData();
  519.                 child->SetBottomSide(bottomSide);
  520.               }
  521.             }
  522.           }
  523.           i ++;
  524.           idExpr = divisionExpr->Nth(i);
  525.         }
  526.       }
  527.     }
  528.  
  529.     clause = database.FindClauseByFunctor("shape");
  530.   }
  531. }
  532.  
  533. // Allow for modifying file
  534. bool wxDiagram::OnDatabaseLoad(wxExprDatabase& db)
  535. {
  536.   return TRUE;
  537. }
  538.  
  539. bool wxDiagram::OnDatabaseSave(wxExprDatabase& db)
  540. {
  541.   return TRUE;
  542. }
  543.  
  544. bool wxDiagram::OnShapeSave(wxExprDatabase& db, wxShape& shape, wxExpr& expr)
  545. {
  546.   shape.WriteAttributes(&expr);
  547.   db.Append(&expr);
  548.  
  549.   if (shape.IsKindOf(CLASSINFO(wxCompositeShape)))
  550.   {
  551.     wxNode *node = shape.GetChildren().First();
  552.     while (node)
  553.     {
  554.       wxShape *childShape = (wxShape *)node->Data();
  555.       wxExpr *childExpr = new wxExpr("shape");
  556.       OnShapeSave(db, *childShape, *childExpr);
  557.       node = node->Next();
  558.     }
  559.   }
  560.  
  561.   return TRUE;
  562. }
  563.  
  564. bool wxDiagram::OnShapeLoad(wxExprDatabase& db, wxShape& shape, wxExpr& expr)
  565. {
  566.   shape.ReadAttributes(&expr);
  567.   return TRUE;
  568. }
  569.  
  570. bool wxDiagram::OnHeaderSave(wxExprDatabase& db, wxExpr& expr)
  571. {
  572.   return TRUE;
  573. }
  574.  
  575. bool wxDiagram::OnHeaderLoad(wxExprDatabase& db, wxExpr& expr)
  576. {
  577.   return TRUE;
  578. }
  579.  
  580. #endif
  581.  
  582. void wxDiagram::SetCanvas(wxShapeCanvas *can)
  583. {
  584.   m_diagramCanvas = can;
  585. }
  586.  
  587. // Find a shape by its id
  588. wxShape* wxDiagram::FindShape(long id) const
  589. {
  590.     wxNode* node = GetShapeList()->First();
  591.     while (node)
  592.     {
  593.         wxShape* shape = (wxShape*) node->Data();
  594.         if (shape->GetId() == id)
  595.             return shape;
  596.         node = node->Next();
  597.     }
  598.     return NULL;
  599. }
  600.  
  601.  
  602. //// Crossings classes
  603.  
  604. wxLineCrossings::wxLineCrossings()
  605. {
  606. }
  607.  
  608. wxLineCrossings::~wxLineCrossings()
  609. {
  610.     ClearCrossings();
  611. }
  612.  
  613. void wxLineCrossings::FindCrossings(wxDiagram& diagram)
  614. {
  615.     ClearCrossings();
  616.     wxNode* node1 = diagram.GetShapeList()->First();
  617.     while (node1)
  618.     {
  619.         wxShape* shape1 = (wxShape*) node1->Data();
  620.         if (shape1->IsKindOf(CLASSINFO(wxLineShape)))
  621.         {
  622.             wxLineShape* lineShape1 = (wxLineShape*) shape1;
  623.             // Iterate through the segments
  624.             wxList* pts1 = lineShape1->GetLineControlPoints();
  625.             int i;
  626.             for (i = 0; i < (pts1->Number() - 1); i++)
  627.             {
  628.                 wxRealPoint* pt1_a = (wxRealPoint*) (pts1->Nth(i)->Data());
  629.                 wxRealPoint* pt1_b = (wxRealPoint*) (pts1->Nth(i+1)->Data());
  630.  
  631.                 // Now we iterate through the segments again
  632.  
  633.                 wxNode* node2 = diagram.GetShapeList()->First();
  634.                 while (node2)
  635.                 {
  636.                     wxShape* shape2 = (wxShape*) node2->Data();
  637.  
  638.                     // Assume that the same line doesn't cross itself
  639.                     if (shape2->IsKindOf(CLASSINFO(wxLineShape)) && (shape1 != shape2))
  640.                     {
  641.                         wxLineShape* lineShape2 = (wxLineShape*) shape2;
  642.                         // Iterate through the segments
  643.                         wxList* pts2 = lineShape2->GetLineControlPoints();
  644.                         int j;
  645.                         for (j = 0; j < (pts2->Number() - 1); j++)
  646.                         {
  647.                             wxRealPoint* pt2_a = (wxRealPoint*) (pts2->Nth(j)->Data());
  648.                             wxRealPoint* pt2_b = (wxRealPoint*) (pts2->Nth(j+1)->Data());
  649.  
  650.                             // Now let's see if these two segments cross.
  651.                             double ratio1, ratio2;
  652.                             oglCheckLineIntersection(pt1_a->x, pt1_a->y, pt1_b->x, pt1_b->y,
  653.                                pt2_a->x, pt2_a->y, pt2_b->x, pt2_b->y,
  654.                              & ratio1, & ratio2);
  655.  
  656.                             if ((ratio1 < 1.0) && (ratio1 > -1.0))
  657.                             {
  658.                                 // Intersection!
  659.                                 wxLineCrossing* crossing = new wxLineCrossing;
  660.                                 crossing->m_intersect.x = (pt1_a->x + (pt1_b->x - pt1_a->x)*ratio1);
  661.                                 crossing->m_intersect.y = (pt1_a->y + (pt1_b->y - pt1_a->y)*ratio1);
  662.  
  663.                                 crossing->m_pt1 = * pt1_a;
  664.                                 crossing->m_pt2 = * pt1_b;
  665.                                 crossing->m_pt3 = * pt2_a;
  666.                                 crossing->m_pt4 = * pt2_b;
  667.  
  668.                                 crossing->m_lineShape1 = lineShape1;
  669.                                 crossing->m_lineShape2 = lineShape2;
  670.  
  671.                                 m_crossings.Append(crossing);
  672.                             }
  673.                         }
  674.                     }
  675.                     node2 = node2->Next();
  676.                 }
  677.             }
  678.         }
  679.  
  680.         node1 = node1->Next();
  681.     }
  682. }
  683.  
  684. void wxLineCrossings::DrawCrossings(wxDiagram& diagram, wxDC& dc)
  685. {
  686.     dc.SetBrush(*wxTRANSPARENT_BRUSH);
  687.  
  688.     long arcWidth = 8;
  689.  
  690.     wxNode* node = m_crossings.First();
  691.     while (node)
  692.     {
  693.         wxLineCrossing* crossing = (wxLineCrossing*) node->Data();
  694. //        dc.DrawEllipse((long) (crossing->m_intersect.x - (arcWidth/2.0) + 0.5), (long) (crossing->m_intersect.y - (arcWidth/2.0) + 0.5),
  695. //           arcWidth, arcWidth);
  696.  
  697.  
  698.         // Let's do some geometry to find the points on either end of the arc.
  699. /*
  700.  
  701. (x1, y1)
  702.     |\
  703.     | \
  704.     |  \
  705.     |   \
  706.     |    \
  707.     |    |\ c    c1
  708.     |  a | \
  709.          |  \
  710.     |     -  x <-- centre of arc
  711.  a1 |     b  |\
  712.     |        | \ c2
  713.     |     a2 |  \
  714.     |         -  \
  715.     |         b2  \
  716.     |              \
  717.     |_______________\ (x2, y2)
  718.           b1
  719.  
  720. */
  721.  
  722.         double a1 = wxMax(crossing->m_pt1.y, crossing->m_pt2.y) - wxMin(crossing->m_pt1.y, crossing->m_pt2.y) ;
  723.         double b1 = wxMax(crossing->m_pt1.x, crossing->m_pt2.x) - wxMin(crossing->m_pt1.x, crossing->m_pt2.x) ;
  724.         double c1 = sqrt( (a1*a1) + (b1*b1) );
  725.  
  726.         double c = arcWidth / 2.0;
  727.         double a = c * a1/c1 ;
  728.         double b = c * b1/c1 ;
  729.  
  730.         // I'm not sure this is right, since we don't know which direction we should be going in - need
  731.         // to know which way the line slopes and choose the sign appropriately.
  732.         double arcX1 = crossing->m_intersect.x - b;
  733.         double arcY1 = crossing->m_intersect.y - a;
  734.  
  735.         double arcX2 = crossing->m_intersect.x + b;
  736.         double arcY2 = crossing->m_intersect.y + a;
  737.  
  738.         dc.SetPen(*wxBLACK_PEN);
  739.         dc.DrawArc( (long) arcX1, (long) arcY1, (long) arcX2, (long) arcY2,
  740.             (long) crossing->m_intersect.x, (long) crossing->m_intersect.y);
  741.  
  742.         dc.SetPen(*wxWHITE_PEN);
  743.         dc.DrawLine( (long) arcX1, (long) arcY1, (long) arcX2, (long) arcY2 );
  744.  
  745.         node = node->Next();
  746.     }
  747. }
  748.  
  749. void wxLineCrossings::ClearCrossings()
  750. {
  751.     wxNode* node = m_crossings.First();
  752.     while (node)
  753.     {
  754.         wxLineCrossing* crossing = (wxLineCrossing*) node->Data();
  755.         delete crossing;
  756.         node = node->Next();
  757.     }
  758.     m_crossings.Clear();
  759. }
  760.  
  761.