]>
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 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "ogldiag.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
28 #include <wx/deprecated/wxexpr.h>
39 #include "wx/ogl/ogl.h"
42 IMPLEMENT_DYNAMIC_CLASS(wxDiagram
, wxObject
)
45 wxDiagram::wxDiagram()
47 m_diagramCanvas
= NULL
;
48 m_quickEditMode
= false;
51 m_shapeList
= new wxList
;
52 m_mouseTolerance
= DEFAULT_MOUSE_TOLERANCE
;
55 wxDiagram::~wxDiagram()
61 void wxDiagram::SetSnapToGrid(bool snap
)
66 void wxDiagram::SetGridSpacing(double spacing
)
68 m_gridSpacing
= spacing
;
71 void wxDiagram::Snap(double *x
, double *y
)
75 *x
= m_gridSpacing
* ((int)(*x
/m_gridSpacing
+ 0.5));
76 *y
= m_gridSpacing
* ((int)(*y
/m_gridSpacing
+ 0.5));
81 void wxDiagram::Redraw(wxDC
& dc
)
86 GetCanvas()->SetCursor(* wxHOURGLASS_CURSOR
);
87 wxNode
*current
= m_shapeList
->GetFirst();
91 wxShape
*object
= (wxShape
*)current
->GetData();
92 if (!object
->GetParent())
95 current
= current
->GetNext();
98 GetCanvas()->SetCursor(* wxSTANDARD_CURSOR
);
102 void wxDiagram::Clear(wxDC
& dc
)
107 // Insert object after addAfter, or at end of list.
108 void wxDiagram::AddShape(wxShape
*object
, wxShape
*addAfter
)
110 wxNode
*nodeAfter
= NULL
;
112 nodeAfter
= m_shapeList
->Member(addAfter
);
114 if (!m_shapeList
->Member(object
))
118 if (nodeAfter
->GetNext())
119 m_shapeList
->Insert(nodeAfter
->GetNext(), object
);
121 m_shapeList
->Append(object
);
124 m_shapeList
->Append(object
);
125 object
->SetCanvas(GetCanvas());
129 void wxDiagram::InsertShape(wxShape
*object
)
131 m_shapeList
->Insert(object
);
132 object
->SetCanvas(GetCanvas());
135 void wxDiagram::RemoveShape(wxShape
*object
)
137 m_shapeList
->DeleteObject(object
);
140 // Should this delete the actual objects too? I think not.
141 void wxDiagram::RemoveAllShapes()
143 m_shapeList
->Clear();
146 void wxDiagram::DeleteAllShapes()
148 wxNode
*node
= m_shapeList
->GetFirst();
151 wxShape
*shape
= (wxShape
*)node
->GetData();
152 if (!shape
->GetParent())
156 node
= m_shapeList
->GetFirst();
159 node
= node
->GetNext();
163 void wxDiagram::ShowAll(bool show
)
165 wxNode
*current
= m_shapeList
->GetFirst();
169 wxShape
*object
= (wxShape
*)current
->GetData();
172 current
= current
->GetNext();
176 void wxDiagram::DrawOutline(wxDC
& dc
, double x1
, double y1
, double x2
, double y2
)
178 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
179 dc
.SetPen(dottedPen
);
180 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
184 points
[0].x
= (int) x1
;
185 points
[0].y
= (int) y1
;
187 points
[1].x
= (int) x2
;
188 points
[1].y
= (int) y1
;
190 points
[2].x
= (int) x2
;
191 points
[2].y
= (int) y2
;
193 points
[3].x
= (int) x1
;
194 points
[3].y
= (int) y2
;
196 points
[4].x
= (int) x1
;
197 points
[4].y
= (int) y1
;
198 dc
.DrawLines(5, points
);
201 // Make sure all text that should be centred, is centred.
202 void wxDiagram::RecentreAll(wxDC
& dc
)
204 wxNode
*object_node
= m_shapeList
->GetFirst();
207 wxShape
*obj
= (wxShape
*)object_node
->GetData();
209 object_node
= object_node
->GetNext();
215 bool wxDiagram::SaveFile(const wxString
& filename
)
219 wxExprDatabase
*database
= new wxExprDatabase
;
221 // First write the diagram type
222 wxExpr
*header
= new wxExpr(_T("diagram"));
223 OnHeaderSave(*database
, *header
);
225 database
->Append(header
);
227 wxNode
*node
= m_shapeList
->GetFirst();
230 wxShape
*shape
= (wxShape
*)node
->GetData();
232 if (!shape
->IsKindOf(CLASSINFO(wxControlPoint
)))
235 if (shape
->IsKindOf(CLASSINFO(wxLineShape
)))
236 expr
= new wxExpr(_T("line"));
238 expr
= new wxExpr(_T("shape"));
240 OnShapeSave(*database
, *shape
, *expr
);
242 node
= node
->GetNext();
244 OnDatabaseSave(*database
);
247 wxGetTempFileName(wxT("diag"), tempFile
);
248 FILE* file
= fopen(tempFile
.mb_str(wxConvFile
), "w");
256 database
->Write(file
);
262 if (FileExists(filename))
266 sprintf(buf, "%s.bak", filename);
269 sprintf(buf, "_diagram.bak");
271 if (FileExists(buf)) wxRemoveFile(buf);
272 if (!wxRenameFile(filename, buf))
274 wxCopyFile(filename, buf);
275 wxRemoveFile(filename);
280 // Copy the temporary file to the correct filename
281 if (!wxRenameFile(tempFile
, filename
))
283 wxCopyFile(tempFile
, filename
);
284 wxRemoveFile(tempFile
);
291 bool wxDiagram::LoadFile(const wxString
& filename
)
295 wxExprDatabase
database(wxExprInteger
, _T("id"));
296 if (!database
.Read(filename
))
304 database
.BeginFind();
305 wxExpr
*header
= database
.FindClauseByFunctor(_T("diagram"));
308 OnHeaderLoad(database
, *header
);
310 // Scan through all clauses and register the ids
311 wxNode
*node
= database
.GetFirst();
314 wxExpr
*clause
= (wxExpr
*)node
->GetData();
316 clause
->GetAttributeValue(_T("id"), id
);
318 node
= node
->GetNext();
322 ReadContainerGeometry(database
);
325 OnDatabaseLoad(database
);
332 void wxDiagram::ReadNodes(wxExprDatabase
& database
)
334 // Find and create the node images
335 database
.BeginFind();
336 wxExpr
*clause
= database
.FindClauseByFunctor(_T("shape"));
342 clause
->AssignAttributeValue(wxT("type"), &type
);
343 clause
->AssignAttributeValue(wxT("parent"), &parentId
);
344 wxClassInfo
*classInfo
= wxClassInfo::FindClass(type
);
347 wxShape
*shape
= (wxShape
*)classInfo
->CreateObject();
348 OnShapeLoad(database
, *shape
, *clause
);
350 shape
->SetCanvas(GetCanvas());
353 m_shapeList
->Append(shape
);
355 // If child of composite, link up
358 wxExpr
*parentExpr
= database
.HashFind(_T("shape"), parentId
);
359 if (parentExpr
&& parentExpr
->GetClientData())
361 wxShape
*parent
= (wxShape
*)parentExpr
->GetClientData();
362 shape
->SetParent(parent
);
363 parent
->GetChildren().Append(shape
);
367 clause
->SetClientData(shape
);
372 clause
= database
.FindClauseByFunctor(_T("shape"));
377 void wxDiagram::ReadLines(wxExprDatabase
& database
)
379 database
.BeginFind();
380 wxExpr
*clause
= database
.FindClauseByFunctor(_T("line"));
386 clause
->GetAttributeValue(_T("type"), type
);
387 clause
->GetAttributeValue(_T("parent"), parentId
);
388 wxClassInfo
*classInfo
= wxClassInfo::FindClass(type
);
391 wxLineShape
*shape
= (wxLineShape
*)classInfo
->CreateObject();
394 OnShapeLoad(database
, *shape
, *clause
);
395 shape
->SetCanvas(GetCanvas());
397 long image_to
= -1; long image_from
= -1;
398 clause
->GetAttributeValue(_T("to"), image_to
);
399 clause
->GetAttributeValue(_T("from"), image_from
);
401 wxExpr
*image_to_expr
= database
.HashFind(_T("shape"), image_to
);
407 wxExpr
*image_from_expr
= database
.HashFind(_T("shape"), image_from
);
409 if (!image_from_expr
)
414 if (image_to_expr
&& image_from_expr
)
416 wxShape
*image_to_object
= (wxShape
*)image_to_expr
->GetClientData();
417 wxShape
*image_from_object
= (wxShape
*)image_from_expr
->GetClientData();
419 if (image_to_object
&& image_from_object
)
421 image_from_object
->AddLine(shape
, image_to_object
, shape
->GetAttachmentFrom(), shape
->GetAttachmentTo());
424 clause
->SetClientData(shape
);
426 m_shapeList
->Append(shape
);
429 clause
= database
.FindClauseByFunctor(_T("line"));
433 // Containers have divisions that reference adjoining divisions,
434 // so we need a separate pass to link everything up.
435 // Also used by Symbol Library.
436 void wxDiagram::ReadContainerGeometry(wxExprDatabase
& database
)
438 database
.BeginFind();
439 wxExpr
*clause
= database
.FindClauseByFunctor(_T("shape"));
442 wxShape
*image
= (wxShape
*)clause
->GetClientData();
443 if (image
&& image
->IsKindOf(CLASSINFO(wxCompositeShape
)))
445 wxCompositeShape
*composite
= (wxCompositeShape
*)image
;
446 wxExpr
*divisionExpr
= NULL
;
448 // Find the list of divisions in the composite
449 clause
->GetAttributeValue(_T("divisions"), &divisionExpr
);
453 wxExpr
*idExpr
= divisionExpr
->Nth(i
);
456 long divisionId
= idExpr
->IntegerValue();
457 wxExpr
*childExpr
= database
.HashFind(_T("shape"), divisionId
);
458 if (childExpr
&& childExpr
->GetClientData())
460 wxDivisionShape
*child
= (wxDivisionShape
*)childExpr
->GetClientData();
461 composite
->GetDivisions().Append(child
);
463 // Find the adjoining shapes
464 long leftSideId
= -1;
466 long rightSideId
= -1;
467 long bottomSideId
= -1;
468 childExpr
->GetAttributeValue(_T("left_side"), leftSideId
);
469 childExpr
->GetAttributeValue(_T("top_side"), topSideId
);
470 childExpr
->GetAttributeValue(_T("right_side"), rightSideId
);
471 childExpr
->GetAttributeValue(_T("bottom_side"), bottomSideId
);
474 wxExpr
*leftExpr
= database
.HashFind(_T("shape"), leftSideId
);
475 if (leftExpr
&& leftExpr
->GetClientData())
477 wxDivisionShape
*leftSide
= (wxDivisionShape
*)leftExpr
->GetClientData();
478 child
->SetLeftSide(leftSide
);
483 wxExpr
*topExpr
= database
.HashFind(_T("shape"), topSideId
);
484 if (topExpr
&& topExpr
->GetClientData())
486 wxDivisionShape
*topSide
= (wxDivisionShape
*)topExpr
->GetClientData();
487 child
->SetTopSide(topSide
);
490 if (rightSideId
> -1)
492 wxExpr
*rightExpr
= database
.HashFind(_T("shape"), rightSideId
);
493 if (rightExpr
&& rightExpr
->GetClientData())
495 wxDivisionShape
*rightSide
= (wxDivisionShape
*)rightExpr
->GetClientData();
496 child
->SetRightSide(rightSide
);
499 if (bottomSideId
> -1)
501 wxExpr
*bottomExpr
= database
.HashFind(_T("shape"), bottomSideId
);
502 if (bottomExpr
&& bottomExpr
->GetClientData())
504 wxDivisionShape
*bottomSide
= (wxDivisionShape
*)bottomExpr
->GetClientData();
505 child
->SetBottomSide(bottomSide
);
510 idExpr
= divisionExpr
->Nth(i
);
515 clause
= database
.FindClauseByFunctor(_T("shape"));
519 // Allow for modifying file
520 bool wxDiagram::OnDatabaseLoad(wxExprDatabase
& WXUNUSED(db
))
525 bool wxDiagram::OnDatabaseSave(wxExprDatabase
& WXUNUSED(db
))
530 bool wxDiagram::OnShapeSave(wxExprDatabase
& db
, wxShape
& shape
, wxExpr
& expr
)
532 shape
.WriteAttributes(&expr
);
535 if (shape
.IsKindOf(CLASSINFO(wxCompositeShape
)))
537 wxNode
*node
= shape
.GetChildren().GetFirst();
540 wxShape
*childShape
= (wxShape
*)node
->GetData();
541 wxExpr
*childExpr
= new wxExpr(_T("shape"));
542 OnShapeSave(db
, *childShape
, *childExpr
);
543 node
= node
->GetNext();
550 bool wxDiagram::OnShapeLoad(wxExprDatabase
& WXUNUSED(db
), wxShape
& shape
, wxExpr
& expr
)
552 shape
.ReadAttributes(&expr
);
556 bool wxDiagram::OnHeaderSave(wxExprDatabase
& WXUNUSED(db
), wxExpr
& WXUNUSED(expr
))
561 bool wxDiagram::OnHeaderLoad(wxExprDatabase
& WXUNUSED(db
), wxExpr
& WXUNUSED(expr
))
568 void wxDiagram::SetCanvas(wxShapeCanvas
*can
)
570 m_diagramCanvas
= can
;
573 // Find a shape by its id
574 wxShape
* wxDiagram::FindShape(long id
) const
576 wxNode
* node
= GetShapeList()->GetFirst();
579 wxShape
* shape
= (wxShape
*) node
->GetData();
580 if (shape
->GetId() == id
)
582 node
= node
->GetNext();
588 //// Crossings classes
590 wxLineCrossings::wxLineCrossings()
594 wxLineCrossings::~wxLineCrossings()
599 void wxLineCrossings::FindCrossings(wxDiagram
& diagram
)
602 wxNode
* node1
= diagram
.GetShapeList()->GetFirst();
605 wxShape
* shape1
= (wxShape
*) node1
->GetData();
606 if (shape1
->IsKindOf(CLASSINFO(wxLineShape
)))
608 wxLineShape
* lineShape1
= (wxLineShape
*) shape1
;
609 // Iterate through the segments
610 wxList
* pts1
= lineShape1
->GetLineControlPoints();
612 for (i
= 0; i
< (pts1
->GetCount() - 1); i
++)
614 wxRealPoint
* pt1_a
= (wxRealPoint
*) (pts1
->Item(i
)->GetData());
615 wxRealPoint
* pt1_b
= (wxRealPoint
*) (pts1
->Item(i
+1)->GetData());
617 // Now we iterate through the segments again
619 wxNode
* node2
= diagram
.GetShapeList()->GetFirst();
622 wxShape
* shape2
= (wxShape
*) node2
->GetData();
624 // Assume that the same line doesn't cross itself
625 if (shape2
->IsKindOf(CLASSINFO(wxLineShape
)) && (shape1
!= shape2
))
627 wxLineShape
* lineShape2
= (wxLineShape
*) shape2
;
628 // Iterate through the segments
629 wxList
* pts2
= lineShape2
->GetLineControlPoints();
631 for (j
= 0; j
< (int) (pts2
->GetCount() - 1); j
++)
633 wxRealPoint
* pt2_a
= (wxRealPoint
*) (pts2
->Item(j
)->GetData());
634 wxRealPoint
* pt2_b
= (wxRealPoint
*) (pts2
->Item(j
+1)->GetData());
636 // Now let's see if these two segments cross.
637 double ratio1
, ratio2
;
638 oglCheckLineIntersection(pt1_a
->x
, pt1_a
->y
, pt1_b
->x
, pt1_b
->y
,
639 pt2_a
->x
, pt2_a
->y
, pt2_b
->x
, pt2_b
->y
,
642 if ((ratio1
< 1.0) && (ratio1
> -1.0))
645 wxLineCrossing
* crossing
= new wxLineCrossing
;
646 crossing
->m_intersect
.x
= (pt1_a
->x
+ (pt1_b
->x
- pt1_a
->x
)*ratio1
);
647 crossing
->m_intersect
.y
= (pt1_a
->y
+ (pt1_b
->y
- pt1_a
->y
)*ratio1
);
649 crossing
->m_pt1
= * pt1_a
;
650 crossing
->m_pt2
= * pt1_b
;
651 crossing
->m_pt3
= * pt2_a
;
652 crossing
->m_pt4
= * pt2_b
;
654 crossing
->m_lineShape1
= lineShape1
;
655 crossing
->m_lineShape2
= lineShape2
;
657 m_crossings
.Append(crossing
);
661 node2
= node2
->GetNext();
666 node1
= node1
->GetNext();
670 void wxLineCrossings::DrawCrossings(wxDiagram
& WXUNUSED(diagram
), wxDC
& dc
)
672 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
676 wxNode
* node
= m_crossings
.GetFirst();
679 wxLineCrossing
* crossing
= (wxLineCrossing
*) node
->GetData();
680 // dc.DrawEllipse((long) (crossing->m_intersect.x - (arcWidth/2.0) + 0.5), (long) (crossing->m_intersect.y - (arcWidth/2.0) + 0.5),
681 // arcWidth, arcWidth);
684 // Let's do some geometry to find the points on either end of the arc.
696 | - x <-- centre of arc
703 |_______________\ (x2, y2)
708 double a1
= wxMax(crossing
->m_pt1
.y
, crossing
->m_pt2
.y
) - wxMin(crossing
->m_pt1
.y
, crossing
->m_pt2
.y
) ;
709 double b1
= wxMax(crossing
->m_pt1
.x
, crossing
->m_pt2
.x
) - wxMin(crossing
->m_pt1
.x
, crossing
->m_pt2
.x
) ;
710 double c1
= sqrt( (a1
*a1
) + (b1
*b1
) );
712 double c
= arcWidth
/ 2.0;
713 double a
= c
* a1
/c1
;
714 double b
= c
* b1
/c1
;
716 // I'm not sure this is right, since we don't know which direction we should be going in - need
717 // to know which way the line slopes and choose the sign appropriately.
718 double arcX1
= crossing
->m_intersect
.x
- b
;
719 double arcY1
= crossing
->m_intersect
.y
- a
;
721 double arcX2
= crossing
->m_intersect
.x
+ b
;
722 double arcY2
= crossing
->m_intersect
.y
+ a
;
724 dc
.SetPen(*wxBLACK_PEN
);
725 dc
.DrawArc( (long) arcX1
, (long) arcY1
, (long) arcX2
, (long) arcY2
,
726 (long) crossing
->m_intersect
.x
, (long) crossing
->m_intersect
.y
);
728 dc
.SetPen(*wxWHITE_PEN
);
729 dc
.DrawLine( (long) arcX1
, (long) arcY1
, (long) arcX2
, (long) arcY2
);
731 node
= node
->GetNext();
735 void wxLineCrossings::ClearCrossings()
737 wxNode
* node
= m_crossings
.GetFirst();
740 wxLineCrossing
* crossing
= (wxLineCrossing
*) node
->GetData();
742 node
= node
->GetNext();