]>
git.saurik.com Git - wxWidgets.git/blob - contrib/src/ogl/ogldiag.cpp
1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
24 #include "wx/deprecated/wxexpr.h"
35 #include "wx/ogl/ogl.h"
38 IMPLEMENT_DYNAMIC_CLASS(wxDiagram
, wxObject
)
41 wxDiagram::wxDiagram()
43 m_diagramCanvas
= NULL
;
44 m_quickEditMode
= false;
47 m_shapeList
= new wxList
;
48 m_mouseTolerance
= DEFAULT_MOUSE_TOLERANCE
;
51 wxDiagram::~wxDiagram()
57 void wxDiagram::SetSnapToGrid(bool snap
)
62 void wxDiagram::SetGridSpacing(double spacing
)
64 m_gridSpacing
= spacing
;
67 void wxDiagram::Snap(double *x
, double *y
)
71 *x
= m_gridSpacing
* ((int)(*x
/m_gridSpacing
+ 0.5));
72 *y
= m_gridSpacing
* ((int)(*y
/m_gridSpacing
+ 0.5));
77 void wxDiagram::Redraw(wxDC
& dc
)
82 GetCanvas()->SetCursor(* wxHOURGLASS_CURSOR
);
83 wxNode
*current
= m_shapeList
->GetFirst();
87 wxShape
*object
= (wxShape
*)current
->GetData();
88 if (!object
->GetParent())
91 current
= current
->GetNext();
94 GetCanvas()->SetCursor(* wxSTANDARD_CURSOR
);
98 void wxDiagram::Clear(wxDC
& dc
)
103 // Insert object after addAfter, or at end of list.
104 void wxDiagram::AddShape(wxShape
*object
, wxShape
*addAfter
)
106 wxNode
*nodeAfter
= NULL
;
108 nodeAfter
= m_shapeList
->Member(addAfter
);
110 if (!m_shapeList
->Member(object
))
114 if (nodeAfter
->GetNext())
115 m_shapeList
->Insert(nodeAfter
->GetNext(), object
);
117 m_shapeList
->Append(object
);
120 m_shapeList
->Append(object
);
121 object
->SetCanvas(GetCanvas());
125 void wxDiagram::InsertShape(wxShape
*object
)
127 m_shapeList
->Insert(object
);
128 object
->SetCanvas(GetCanvas());
131 void wxDiagram::RemoveShape(wxShape
*object
)
133 m_shapeList
->DeleteObject(object
);
136 // Should this delete the actual objects too? I think not.
137 void wxDiagram::RemoveAllShapes()
139 m_shapeList
->Clear();
142 void wxDiagram::DeleteAllShapes()
144 wxNode
*node
= m_shapeList
->GetFirst();
147 wxShape
*shape
= (wxShape
*)node
->GetData();
148 if (!shape
->GetParent())
152 node
= m_shapeList
->GetFirst();
155 node
= node
->GetNext();
159 void wxDiagram::ShowAll(bool show
)
161 wxNode
*current
= m_shapeList
->GetFirst();
165 wxShape
*object
= (wxShape
*)current
->GetData();
168 current
= current
->GetNext();
172 void wxDiagram::DrawOutline(wxDC
& dc
, double x1
, double y1
, double x2
, double y2
)
174 wxPen
dottedPen(*wxBLACK
, 1, wxDOT
);
175 dc
.SetPen(dottedPen
);
176 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
180 points
[0].x
= (int) x1
;
181 points
[0].y
= (int) y1
;
183 points
[1].x
= (int) x2
;
184 points
[1].y
= (int) y1
;
186 points
[2].x
= (int) x2
;
187 points
[2].y
= (int) y2
;
189 points
[3].x
= (int) x1
;
190 points
[3].y
= (int) y2
;
192 points
[4].x
= (int) x1
;
193 points
[4].y
= (int) y1
;
194 dc
.DrawLines(5, points
);
197 // Make sure all text that should be centred, is centred.
198 void wxDiagram::RecentreAll(wxDC
& dc
)
200 wxNode
*object_node
= m_shapeList
->GetFirst();
203 wxShape
*obj
= (wxShape
*)object_node
->GetData();
205 object_node
= object_node
->GetNext();
211 bool wxDiagram::SaveFile(const wxString
& filename
)
215 wxExprDatabase
*database
= new wxExprDatabase
;
217 // First write the diagram type
218 wxExpr
*header
= new wxExpr(_T("diagram"));
219 OnHeaderSave(*database
, *header
);
221 database
->Append(header
);
223 wxNode
*node
= m_shapeList
->GetFirst();
226 wxShape
*shape
= (wxShape
*)node
->GetData();
228 if (!shape
->IsKindOf(CLASSINFO(wxControlPoint
)))
231 if (shape
->IsKindOf(CLASSINFO(wxLineShape
)))
232 expr
= new wxExpr(_T("line"));
234 expr
= new wxExpr(_T("shape"));
236 OnShapeSave(*database
, *shape
, *expr
);
238 node
= node
->GetNext();
240 OnDatabaseSave(*database
);
243 wxGetTempFileName(wxT("diag"), tempFile
);
244 FILE* file
= fopen(tempFile
.mb_str(wxConvFile
), "w");
252 database
->Write(file
);
258 if (FileExists(filename))
262 sprintf(buf, "%s.bak", filename);
265 sprintf(buf, "_diagram.bak");
267 if (FileExists(buf)) wxRemoveFile(buf);
268 if (!wxRenameFile(filename, buf))
270 wxCopyFile(filename, buf);
271 wxRemoveFile(filename);
276 // Copy the temporary file to the correct filename
277 if (!wxRenameFile(tempFile
, filename
))
279 wxCopyFile(tempFile
, filename
);
280 wxRemoveFile(tempFile
);
287 bool wxDiagram::LoadFile(const wxString
& filename
)
291 wxExprDatabase
database(wxExprInteger
, _T("id"));
292 if (!database
.Read(filename
))
300 database
.BeginFind();
301 wxExpr
*header
= database
.FindClauseByFunctor(_T("diagram"));
304 OnHeaderLoad(database
, *header
);
306 // Scan through all clauses and register the ids
307 wxNode
*node
= database
.GetFirst();
310 wxExpr
*clause
= (wxExpr
*)node
->GetData();
312 clause
->GetAttributeValue(_T("id"), id
);
314 node
= node
->GetNext();
318 ReadContainerGeometry(database
);
321 OnDatabaseLoad(database
);
328 void wxDiagram::ReadNodes(wxExprDatabase
& database
)
330 // Find and create the node images
331 database
.BeginFind();
332 wxExpr
*clause
= database
.FindClauseByFunctor(_T("shape"));
338 clause
->AssignAttributeValue(wxT("type"), &type
);
339 clause
->AssignAttributeValue(wxT("parent"), &parentId
);
340 wxClassInfo
*classInfo
= wxClassInfo::FindClass(type
);
343 wxShape
*shape
= (wxShape
*)classInfo
->CreateObject();
344 OnShapeLoad(database
, *shape
, *clause
);
346 shape
->SetCanvas(GetCanvas());
349 m_shapeList
->Append(shape
);
351 // If child of composite, link up
354 wxExpr
*parentExpr
= database
.HashFind(_T("shape"), parentId
);
355 if (parentExpr
&& parentExpr
->GetClientData())
357 wxShape
*parent
= (wxShape
*)parentExpr
->GetClientData();
358 shape
->SetParent(parent
);
359 parent
->GetChildren().Append(shape
);
363 clause
->SetClientData(shape
);
368 clause
= database
.FindClauseByFunctor(_T("shape"));
373 void wxDiagram::ReadLines(wxExprDatabase
& database
)
375 database
.BeginFind();
376 wxExpr
*clause
= database
.FindClauseByFunctor(_T("line"));
382 clause
->GetAttributeValue(_T("type"), type
);
383 clause
->GetAttributeValue(_T("parent"), parentId
);
384 wxClassInfo
*classInfo
= wxClassInfo::FindClass(type
);
387 wxLineShape
*shape
= (wxLineShape
*)classInfo
->CreateObject();
390 OnShapeLoad(database
, *shape
, *clause
);
391 shape
->SetCanvas(GetCanvas());
393 long image_to
= -1; long image_from
= -1;
394 clause
->GetAttributeValue(_T("to"), image_to
);
395 clause
->GetAttributeValue(_T("from"), image_from
);
397 wxExpr
*image_to_expr
= database
.HashFind(_T("shape"), image_to
);
403 wxExpr
*image_from_expr
= database
.HashFind(_T("shape"), image_from
);
405 if (!image_from_expr
)
410 if (image_to_expr
&& image_from_expr
)
412 wxShape
*image_to_object
= (wxShape
*)image_to_expr
->GetClientData();
413 wxShape
*image_from_object
= (wxShape
*)image_from_expr
->GetClientData();
415 if (image_to_object
&& image_from_object
)
417 image_from_object
->AddLine(shape
, image_to_object
, shape
->GetAttachmentFrom(), shape
->GetAttachmentTo());
420 clause
->SetClientData(shape
);
422 m_shapeList
->Append(shape
);
425 clause
= database
.FindClauseByFunctor(_T("line"));
429 // Containers have divisions that reference adjoining divisions,
430 // so we need a separate pass to link everything up.
431 // Also used by Symbol Library.
432 void wxDiagram::ReadContainerGeometry(wxExprDatabase
& database
)
434 database
.BeginFind();
435 wxExpr
*clause
= database
.FindClauseByFunctor(_T("shape"));
438 wxShape
*image
= (wxShape
*)clause
->GetClientData();
439 if (image
&& image
->IsKindOf(CLASSINFO(wxCompositeShape
)))
441 wxCompositeShape
*composite
= (wxCompositeShape
*)image
;
442 wxExpr
*divisionExpr
= NULL
;
444 // Find the list of divisions in the composite
445 clause
->GetAttributeValue(_T("divisions"), &divisionExpr
);
449 wxExpr
*idExpr
= divisionExpr
->Nth(i
);
452 long divisionId
= idExpr
->IntegerValue();
453 wxExpr
*childExpr
= database
.HashFind(_T("shape"), divisionId
);
454 if (childExpr
&& childExpr
->GetClientData())
456 wxDivisionShape
*child
= (wxDivisionShape
*)childExpr
->GetClientData();
457 composite
->GetDivisions().Append(child
);
459 // Find the adjoining shapes
460 long leftSideId
= -1;
462 long rightSideId
= -1;
463 long bottomSideId
= -1;
464 childExpr
->GetAttributeValue(_T("left_side"), leftSideId
);
465 childExpr
->GetAttributeValue(_T("top_side"), topSideId
);
466 childExpr
->GetAttributeValue(_T("right_side"), rightSideId
);
467 childExpr
->GetAttributeValue(_T("bottom_side"), bottomSideId
);
470 wxExpr
*leftExpr
= database
.HashFind(_T("shape"), leftSideId
);
471 if (leftExpr
&& leftExpr
->GetClientData())
473 wxDivisionShape
*leftSide
= (wxDivisionShape
*)leftExpr
->GetClientData();
474 child
->SetLeftSide(leftSide
);
479 wxExpr
*topExpr
= database
.HashFind(_T("shape"), topSideId
);
480 if (topExpr
&& topExpr
->GetClientData())
482 wxDivisionShape
*topSide
= (wxDivisionShape
*)topExpr
->GetClientData();
483 child
->SetTopSide(topSide
);
486 if (rightSideId
> -1)
488 wxExpr
*rightExpr
= database
.HashFind(_T("shape"), rightSideId
);
489 if (rightExpr
&& rightExpr
->GetClientData())
491 wxDivisionShape
*rightSide
= (wxDivisionShape
*)rightExpr
->GetClientData();
492 child
->SetRightSide(rightSide
);
495 if (bottomSideId
> -1)
497 wxExpr
*bottomExpr
= database
.HashFind(_T("shape"), bottomSideId
);
498 if (bottomExpr
&& bottomExpr
->GetClientData())
500 wxDivisionShape
*bottomSide
= (wxDivisionShape
*)bottomExpr
->GetClientData();
501 child
->SetBottomSide(bottomSide
);
506 idExpr
= divisionExpr
->Nth(i
);
511 clause
= database
.FindClauseByFunctor(_T("shape"));
515 // Allow for modifying file
516 bool wxDiagram::OnDatabaseLoad(wxExprDatabase
& WXUNUSED(db
))
521 bool wxDiagram::OnDatabaseSave(wxExprDatabase
& WXUNUSED(db
))
526 bool wxDiagram::OnShapeSave(wxExprDatabase
& db
, wxShape
& shape
, wxExpr
& expr
)
528 shape
.WriteAttributes(&expr
);
531 if (shape
.IsKindOf(CLASSINFO(wxCompositeShape
)))
533 wxNode
*node
= shape
.GetChildren().GetFirst();
536 wxShape
*childShape
= (wxShape
*)node
->GetData();
537 wxExpr
*childExpr
= new wxExpr(_T("shape"));
538 OnShapeSave(db
, *childShape
, *childExpr
);
539 node
= node
->GetNext();
546 bool wxDiagram::OnShapeLoad(wxExprDatabase
& WXUNUSED(db
), wxShape
& shape
, wxExpr
& expr
)
548 shape
.ReadAttributes(&expr
);
552 bool wxDiagram::OnHeaderSave(wxExprDatabase
& WXUNUSED(db
), wxExpr
& WXUNUSED(expr
))
557 bool wxDiagram::OnHeaderLoad(wxExprDatabase
& WXUNUSED(db
), wxExpr
& WXUNUSED(expr
))
564 void wxDiagram::SetCanvas(wxShapeCanvas
*can
)
566 m_diagramCanvas
= can
;
569 // Find a shape by its id
570 wxShape
* wxDiagram::FindShape(long id
) const
572 wxNode
* node
= GetShapeList()->GetFirst();
575 wxShape
* shape
= (wxShape
*) node
->GetData();
576 if (shape
->GetId() == id
)
578 node
= node
->GetNext();
584 //// Crossings classes
586 wxLineCrossings::wxLineCrossings()
590 wxLineCrossings::~wxLineCrossings()
595 void wxLineCrossings::FindCrossings(wxDiagram
& diagram
)
598 wxNode
* node1
= diagram
.GetShapeList()->GetFirst();
601 wxShape
* shape1
= (wxShape
*) node1
->GetData();
602 if (shape1
->IsKindOf(CLASSINFO(wxLineShape
)))
604 wxLineShape
* lineShape1
= (wxLineShape
*) shape1
;
605 // Iterate through the segments
606 wxList
* pts1
= lineShape1
->GetLineControlPoints();
608 for (i
= 0; i
< (pts1
->GetCount() - 1); i
++)
610 wxRealPoint
* pt1_a
= (wxRealPoint
*) (pts1
->Item(i
)->GetData());
611 wxRealPoint
* pt1_b
= (wxRealPoint
*) (pts1
->Item(i
+1)->GetData());
613 // Now we iterate through the segments again
615 wxNode
* node2
= diagram
.GetShapeList()->GetFirst();
618 wxShape
* shape2
= (wxShape
*) node2
->GetData();
620 // Assume that the same line doesn't cross itself
621 if (shape2
->IsKindOf(CLASSINFO(wxLineShape
)) && (shape1
!= shape2
))
623 wxLineShape
* lineShape2
= (wxLineShape
*) shape2
;
624 // Iterate through the segments
625 wxList
* pts2
= lineShape2
->GetLineControlPoints();
627 for (j
= 0; j
< (int) (pts2
->GetCount() - 1); j
++)
629 wxRealPoint
* pt2_a
= (wxRealPoint
*) (pts2
->Item(j
)->GetData());
630 wxRealPoint
* pt2_b
= (wxRealPoint
*) (pts2
->Item(j
+1)->GetData());
632 // Now let's see if these two segments cross.
633 double ratio1
, ratio2
;
634 oglCheckLineIntersection(pt1_a
->x
, pt1_a
->y
, pt1_b
->x
, pt1_b
->y
,
635 pt2_a
->x
, pt2_a
->y
, pt2_b
->x
, pt2_b
->y
,
638 if ((ratio1
< 1.0) && (ratio1
> -1.0))
641 wxLineCrossing
* crossing
= new wxLineCrossing
;
642 crossing
->m_intersect
.x
= (pt1_a
->x
+ (pt1_b
->x
- pt1_a
->x
)*ratio1
);
643 crossing
->m_intersect
.y
= (pt1_a
->y
+ (pt1_b
->y
- pt1_a
->y
)*ratio1
);
645 crossing
->m_pt1
= * pt1_a
;
646 crossing
->m_pt2
= * pt1_b
;
647 crossing
->m_pt3
= * pt2_a
;
648 crossing
->m_pt4
= * pt2_b
;
650 crossing
->m_lineShape1
= lineShape1
;
651 crossing
->m_lineShape2
= lineShape2
;
653 m_crossings
.Append(crossing
);
657 node2
= node2
->GetNext();
662 node1
= node1
->GetNext();
666 void wxLineCrossings::DrawCrossings(wxDiagram
& WXUNUSED(diagram
), wxDC
& dc
)
668 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
672 wxNode
* node
= m_crossings
.GetFirst();
675 wxLineCrossing
* crossing
= (wxLineCrossing
*) node
->GetData();
676 // dc.DrawEllipse((long) (crossing->m_intersect.x - (arcWidth/2.0) + 0.5), (long) (crossing->m_intersect.y - (arcWidth/2.0) + 0.5),
677 // arcWidth, arcWidth);
680 // Let's do some geometry to find the points on either end of the arc.
692 | - x <-- centre of arc
699 |_______________\ (x2, y2)
704 double a1
= wxMax(crossing
->m_pt1
.y
, crossing
->m_pt2
.y
) - wxMin(crossing
->m_pt1
.y
, crossing
->m_pt2
.y
) ;
705 double b1
= wxMax(crossing
->m_pt1
.x
, crossing
->m_pt2
.x
) - wxMin(crossing
->m_pt1
.x
, crossing
->m_pt2
.x
) ;
706 double c1
= sqrt( (a1
*a1
) + (b1
*b1
) );
708 double c
= arcWidth
/ 2.0;
709 double a
= c
* a1
/c1
;
710 double b
= c
* b1
/c1
;
712 // I'm not sure this is right, since we don't know which direction we should be going in - need
713 // to know which way the line slopes and choose the sign appropriately.
714 double arcX1
= crossing
->m_intersect
.x
- b
;
715 double arcY1
= crossing
->m_intersect
.y
- a
;
717 double arcX2
= crossing
->m_intersect
.x
+ b
;
718 double arcY2
= crossing
->m_intersect
.y
+ a
;
720 dc
.SetPen(*wxBLACK_PEN
);
721 dc
.DrawArc( (long) arcX1
, (long) arcY1
, (long) arcX2
, (long) arcY2
,
722 (long) crossing
->m_intersect
.x
, (long) crossing
->m_intersect
.y
);
724 dc
.SetPen(*wxWHITE_PEN
);
725 dc
.DrawLine( (long) arcX1
, (long) arcY1
, (long) arcX2
, (long) arcY2
);
727 node
= node
->GetNext();
731 void wxLineCrossings::ClearCrossings()
733 wxNode
* node
= m_crossings
.GetFirst();
736 wxLineCrossing
* crossing
= (wxLineCrossing
*) node
->GetData();
738 node
= node
->GetNext();