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