]>
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/basic.h>
40 #include <wx/ogl/basicp.h>
41 #include <wx/ogl/canvas.h>
42 #include <wx/ogl/ogldiag.h>
43 #include <wx/ogl/lines.h>
44 #include <wx/ogl/composit.h>
45 #include <wx/ogl/misc.h>
47 IMPLEMENT_DYNAMIC_CLASS(wxDiagram
, wxObject
)
50 wxDiagram::wxDiagram()
52 m_diagramCanvas
= NULL
;
53 m_quickEditMode
= FALSE
;
56 m_shapeList
= new wxList
;
57 m_mouseTolerance
= DEFAULT_MOUSE_TOLERANCE
;
60 wxDiagram::~wxDiagram()
66 void wxDiagram::SetSnapToGrid(bool snap
)
71 void wxDiagram::SetGridSpacing(double spacing
)
73 m_gridSpacing
= spacing
;
76 void wxDiagram::Snap(double *x
, double *y
)
80 *x
= m_gridSpacing
* ((int)(*x
/m_gridSpacing
+ 0.5));
81 *y
= m_gridSpacing
* ((int)(*y
/m_gridSpacing
+ 0.5));
86 void wxDiagram::Redraw(wxDC
& dc
)
91 GetCanvas()->SetCursor(* wxHOURGLASS_CURSOR
);
92 wxNode
*current
= m_shapeList
->GetFirst();
96 wxShape
*object
= (wxShape
*)current
->GetData();
97 if (!object
->GetParent())
100 current
= current
->GetNext();
103 GetCanvas()->SetCursor(* wxSTANDARD_CURSOR
);
107 void wxDiagram::Clear(wxDC
& dc
)
112 // Insert object after addAfter, or at end of list.
113 void wxDiagram::AddShape(wxShape
*object
, wxShape
*addAfter
)
115 wxNode
*nodeAfter
= NULL
;
117 nodeAfter
= m_shapeList
->Member(addAfter
);
119 if (!m_shapeList
->Member(object
))
123 if (nodeAfter
->GetNext())
124 m_shapeList
->Insert(nodeAfter
->GetNext(), object
);
126 m_shapeList
->Append(object
);
129 m_shapeList
->Append(object
);
130 object
->SetCanvas(GetCanvas());
134 void wxDiagram::InsertShape(wxShape
*object
)
136 m_shapeList
->Insert(object
);
137 object
->SetCanvas(GetCanvas());
140 void wxDiagram::RemoveShape(wxShape
*object
)
142 m_shapeList
->DeleteObject(object
);
145 // Should this delete the actual objects too? I think not.
146 void wxDiagram::RemoveAllShapes()
148 m_shapeList
->Clear();
151 void wxDiagram::DeleteAllShapes()
153 wxNode
*node
= m_shapeList
->GetFirst();
156 wxShape
*shape
= (wxShape
*)node
->GetData();
157 if (!shape
->GetParent())
161 node
= m_shapeList
->GetFirst();
164 node
= node
->GetNext();
168 void wxDiagram::ShowAll(bool show
)
170 wxNode
*current
= m_shapeList
->GetFirst();
174 wxShape
*object
= (wxShape
*)current
->GetData();
177 current
= current
->GetNext();
181 void wxDiagram::DrawOutline(wxDC
& dc
, double x1
, double y1
, double x2
, double y2
)
183 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
184 dc
.SetPen(dottedPen
);
185 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
189 points
[0].x
= (int) x1
;
190 points
[0].y
= (int) y1
;
192 points
[1].x
= (int) x2
;
193 points
[1].y
= (int) y1
;
195 points
[2].x
= (int) x2
;
196 points
[2].y
= (int) y2
;
198 points
[3].x
= (int) x1
;
199 points
[3].y
= (int) y2
;
201 points
[4].x
= (int) x1
;
202 points
[4].y
= (int) y1
;
203 dc
.DrawLines(5, points
);
206 // Make sure all text that should be centred, is centred.
207 void wxDiagram::RecentreAll(wxDC
& dc
)
209 wxNode
*object_node
= m_shapeList
->GetFirst();
212 wxShape
*obj
= (wxShape
*)object_node
->GetData();
214 object_node
= object_node
->GetNext();
220 bool wxDiagram::SaveFile(const wxString
& filename
)
224 wxExprDatabase
*database
= new wxExprDatabase
;
226 // First write the diagram type
227 wxExpr
*header
= new wxExpr("diagram");
228 OnHeaderSave(*database
, *header
);
230 database
->Append(header
);
232 wxNode
*node
= m_shapeList
->GetFirst();
235 wxShape
*shape
= (wxShape
*)node
->GetData();
237 if (!shape
->IsKindOf(CLASSINFO(wxControlPoint
)))
240 if (shape
->IsKindOf(CLASSINFO(wxLineShape
)))
241 expr
= new wxExpr("line");
243 expr
= new wxExpr("shape");
245 OnShapeSave(*database
, *shape
, *expr
);
249 OnDatabaseSave(*database
);
252 wxGetTempFileName(wxT("diag"), tempFile
);
253 FILE* file
= fopen(tempFile
.mb_str(wxConvFile
), "w");
261 database
->Write(file
);
267 if (FileExists(filename))
271 sprintf(buf, "%s.bak", filename);
274 sprintf(buf, "_diagram.bak");
276 if (FileExists(buf)) wxRemoveFile(buf);
277 if (!wxRenameFile(filename, buf))
279 wxCopyFile(filename, buf);
280 wxRemoveFile(filename);
285 // Copy the temporary file to the correct filename
286 if (!wxRenameFile(tempFile
, filename
))
288 wxCopyFile(tempFile
, filename
);
289 wxRemoveFile(tempFile
);
296 bool wxDiagram::LoadFile(const wxString
& filename
)
300 wxExprDatabase
database(wxExprInteger
, "id");
301 if (!database
.Read(filename
))
309 database
.BeginFind();
310 wxExpr
*header
= database
.FindClauseByFunctor("diagram");
313 OnHeaderLoad(database
, *header
);
315 // Scan through all clauses and register the ids
316 wxNode
*node
= database
.First();
319 wxExpr
*clause
= (wxExpr
*)node
->GetData();
321 clause
->GetAttributeValue("id", id
);
327 ReadContainerGeometry(database
);
330 OnDatabaseLoad(database
);
337 void wxDiagram::ReadNodes(wxExprDatabase
& database
)
339 // Find and create the node images
340 database
.BeginFind();
341 wxExpr
*clause
= database
.FindClauseByFunctor("shape");
347 clause
->AssignAttributeValue(wxT("type"), &type
);
348 clause
->AssignAttributeValue(wxT("parent"), &parentId
);
349 wxClassInfo
*classInfo
= wxClassInfo::FindClass(type
);
352 wxShape
*shape
= (wxShape
*)classInfo
->CreateObject();
353 OnShapeLoad(database
, *shape
, *clause
);
355 shape
->SetCanvas(GetCanvas());
358 m_shapeList
->Append(shape
);
360 // If child of composite, link up
363 wxExpr
*parentExpr
= database
.HashFind("shape", parentId
);
364 if (parentExpr
&& parentExpr
->GetClientData())
366 wxShape
*parent
= (wxShape
*)parentExpr
->GetClientData();
367 shape
->SetParent(parent
);
368 parent
->GetChildren().Append(shape
);
372 clause
->SetClientData(shape
);
377 clause
= database
.FindClauseByFunctor("shape");
382 void wxDiagram::ReadLines(wxExprDatabase
& database
)
384 database
.BeginFind();
385 wxExpr
*clause
= database
.FindClauseByFunctor("line");
391 clause
->GetAttributeValue("type", type
);
392 clause
->GetAttributeValue("parent", parentId
);
393 wxClassInfo
*classInfo
= wxClassInfo::FindClass(type
);
396 wxLineShape
*shape
= (wxLineShape
*)classInfo
->CreateObject();
399 OnShapeLoad(database
, *shape
, *clause
);
400 shape
->SetCanvas(GetCanvas());
402 long image_to
= -1; long image_from
= -1;
403 clause
->GetAttributeValue("to", image_to
);
404 clause
->GetAttributeValue("from", image_from
);
406 wxExpr
*image_to_expr
= database
.HashFind("shape", image_to
);
412 wxExpr
*image_from_expr
= database
.HashFind("shape", image_from
);
414 if (!image_from_expr
)
419 if (image_to_expr
&& image_from_expr
)
421 wxShape
*image_to_object
= (wxShape
*)image_to_expr
->GetClientData();
422 wxShape
*image_from_object
= (wxShape
*)image_from_expr
->GetClientData();
424 if (image_to_object
&& image_from_object
)
426 image_from_object
->AddLine(shape
, image_to_object
, shape
->GetAttachmentFrom(), shape
->GetAttachmentTo());
429 clause
->SetClientData(shape
);
431 m_shapeList
->Append(shape
);
434 clause
= database
.FindClauseByFunctor("line");
438 // Containers have divisions that reference adjoining divisions,
439 // so we need a separate pass to link everything up.
440 // Also used by Symbol Library.
441 void wxDiagram::ReadContainerGeometry(wxExprDatabase
& database
)
443 database
.BeginFind();
444 wxExpr
*clause
= database
.FindClauseByFunctor("shape");
447 wxShape
*image
= (wxShape
*)clause
->GetClientData();
448 if (image
&& image
->IsKindOf(CLASSINFO(wxCompositeShape
)))
450 wxCompositeShape
*composite
= (wxCompositeShape
*)image
;
451 wxExpr
*divisionExpr
= NULL
;
453 // Find the list of divisions in the composite
454 clause
->GetAttributeValue("divisions", &divisionExpr
);
458 wxExpr
*idExpr
= divisionExpr
->Nth(i
);
461 long divisionId
= idExpr
->IntegerValue();
462 wxExpr
*childExpr
= database
.HashFind("shape", divisionId
);
463 if (childExpr
&& childExpr
->GetClientData())
465 wxDivisionShape
*child
= (wxDivisionShape
*)childExpr
->GetClientData();
466 composite
->GetDivisions().Append(child
);
468 // Find the adjoining shapes
469 long leftSideId
= -1;
471 long rightSideId
= -1;
472 long bottomSideId
= -1;
473 childExpr
->GetAttributeValue("left_side", leftSideId
);
474 childExpr
->GetAttributeValue("top_side", topSideId
);
475 childExpr
->GetAttributeValue("right_side", rightSideId
);
476 childExpr
->GetAttributeValue("bottom_side", bottomSideId
);
479 wxExpr
*leftExpr
= database
.HashFind("shape", leftSideId
);
480 if (leftExpr
&& leftExpr
->GetClientData())
482 wxDivisionShape
*leftSide
= (wxDivisionShape
*)leftExpr
->GetClientData();
483 child
->SetLeftSide(leftSide
);
488 wxExpr
*topExpr
= database
.HashFind("shape", topSideId
);
489 if (topExpr
&& topExpr
->GetClientData())
491 wxDivisionShape
*topSide
= (wxDivisionShape
*)topExpr
->GetClientData();
492 child
->SetTopSide(topSide
);
495 if (rightSideId
> -1)
497 wxExpr
*rightExpr
= database
.HashFind("shape", rightSideId
);
498 if (rightExpr
&& rightExpr
->GetClientData())
500 wxDivisionShape
*rightSide
= (wxDivisionShape
*)rightExpr
->GetClientData();
501 child
->SetRightSide(rightSide
);
504 if (bottomSideId
> -1)
506 wxExpr
*bottomExpr
= database
.HashFind("shape", bottomSideId
);
507 if (bottomExpr
&& bottomExpr
->GetClientData())
509 wxDivisionShape
*bottomSide
= (wxDivisionShape
*)bottomExpr
->GetClientData();
510 child
->SetBottomSide(bottomSide
);
515 idExpr
= divisionExpr
->Nth(i
);
520 clause
= database
.FindClauseByFunctor("shape");
524 // Allow for modifying file
525 bool wxDiagram::OnDatabaseLoad(wxExprDatabase
& db
)
530 bool wxDiagram::OnDatabaseSave(wxExprDatabase
& db
)
535 bool wxDiagram::OnShapeSave(wxExprDatabase
& db
, wxShape
& shape
, wxExpr
& expr
)
537 shape
.WriteAttributes(&expr
);
540 if (shape
.IsKindOf(CLASSINFO(wxCompositeShape
)))
542 wxNode
*node
= shape
.GetChildren().First();
545 wxShape
*childShape
= (wxShape
*)node
->GetData();
546 wxExpr
*childExpr
= new wxExpr("shape");
547 OnShapeSave(db
, *childShape
, *childExpr
);
555 bool wxDiagram::OnShapeLoad(wxExprDatabase
& db
, wxShape
& shape
, wxExpr
& expr
)
557 shape
.ReadAttributes(&expr
);
561 bool wxDiagram::OnHeaderSave(wxExprDatabase
& db
, wxExpr
& expr
)
566 bool wxDiagram::OnHeaderLoad(wxExprDatabase
& db
, wxExpr
& expr
)
573 void wxDiagram::SetCanvas(wxShapeCanvas
*can
)
575 m_diagramCanvas
= can
;
578 // Find a shape by its id
579 wxShape
* wxDiagram::FindShape(long id
) const
581 wxNode
* node
= GetShapeList()->GetFirst();
584 wxShape
* shape
= (wxShape
*) node
->GetData();
585 if (shape
->GetId() == id
)
587 node
= node
->GetNext();
593 //// Crossings classes
595 wxLineCrossings::wxLineCrossings()
599 wxLineCrossings::~wxLineCrossings()
604 void wxLineCrossings::FindCrossings(wxDiagram
& diagram
)
607 wxNode
* node1
= diagram
.GetShapeList()->GetFirst();
610 wxShape
* shape1
= (wxShape
*) node1
->GetData();
611 if (shape1
->IsKindOf(CLASSINFO(wxLineShape
)))
613 wxLineShape
* lineShape1
= (wxLineShape
*) shape1
;
614 // Iterate through the segments
615 wxList
* pts1
= lineShape1
->GetLineControlPoints();
617 for (i
= 0; i
< (pts1
->GetCount() - 1); i
++)
619 wxRealPoint
* pt1_a
= (wxRealPoint
*) (pts1
->Item(i
)->GetData());
620 wxRealPoint
* pt1_b
= (wxRealPoint
*) (pts1
->Item(i
+1)->GetData());
622 // Now we iterate through the segments again
624 wxNode
* node2
= diagram
.GetShapeList()->GetFirst();
627 wxShape
* shape2
= (wxShape
*) node2
->GetData();
629 // Assume that the same line doesn't cross itself
630 if (shape2
->IsKindOf(CLASSINFO(wxLineShape
)) && (shape1
!= shape2
))
632 wxLineShape
* lineShape2
= (wxLineShape
*) shape2
;
633 // Iterate through the segments
634 wxList
* pts2
= lineShape2
->GetLineControlPoints();
636 for (j
= 0; j
< (pts2
->GetCount() - 1); j
++)
638 wxRealPoint
* pt2_a
= (wxRealPoint
*) (pts2
->Item(j
)->GetData());
639 wxRealPoint
* pt2_b
= (wxRealPoint
*) (pts2
->Item(j
+1)->GetData());
641 // Now let's see if these two segments cross.
642 double ratio1
, ratio2
;
643 oglCheckLineIntersection(pt1_a
->x
, pt1_a
->y
, pt1_b
->x
, pt1_b
->y
,
644 pt2_a
->x
, pt2_a
->y
, pt2_b
->x
, pt2_b
->y
,
647 if ((ratio1
< 1.0) && (ratio1
> -1.0))
650 wxLineCrossing
* crossing
= new wxLineCrossing
;
651 crossing
->m_intersect
.x
= (pt1_a
->x
+ (pt1_b
->x
- pt1_a
->x
)*ratio1
);
652 crossing
->m_intersect
.y
= (pt1_a
->y
+ (pt1_b
->y
- pt1_a
->y
)*ratio1
);
654 crossing
->m_pt1
= * pt1_a
;
655 crossing
->m_pt2
= * pt1_b
;
656 crossing
->m_pt3
= * pt2_a
;
657 crossing
->m_pt4
= * pt2_b
;
659 crossing
->m_lineShape1
= lineShape1
;
660 crossing
->m_lineShape2
= lineShape2
;
662 m_crossings
.Append(crossing
);
666 node2
= node2
->GetNext();
671 node1
= node1
->GetNext();
675 void wxLineCrossings::DrawCrossings(wxDiagram
& diagram
, wxDC
& dc
)
677 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
681 wxNode
* node
= m_crossings
.GetFirst();
684 wxLineCrossing
* crossing
= (wxLineCrossing
*) node
->GetData();
685 // dc.DrawEllipse((long) (crossing->m_intersect.x - (arcWidth/2.0) + 0.5), (long) (crossing->m_intersect.y - (arcWidth/2.0) + 0.5),
686 // arcWidth, arcWidth);
689 // Let's do some geometry to find the points on either end of the arc.
701 | - x <-- centre of arc
708 |_______________\ (x2, y2)
713 double a1
= wxMax(crossing
->m_pt1
.y
, crossing
->m_pt2
.y
) - wxMin(crossing
->m_pt1
.y
, crossing
->m_pt2
.y
) ;
714 double b1
= wxMax(crossing
->m_pt1
.x
, crossing
->m_pt2
.x
) - wxMin(crossing
->m_pt1
.x
, crossing
->m_pt2
.x
) ;
715 double c1
= sqrt( (a1
*a1
) + (b1
*b1
) );
717 double c
= arcWidth
/ 2.0;
718 double a
= c
* a1
/c1
;
719 double b
= c
* b1
/c1
;
721 // I'm not sure this is right, since we don't know which direction we should be going in - need
722 // to know which way the line slopes and choose the sign appropriately.
723 double arcX1
= crossing
->m_intersect
.x
- b
;
724 double arcY1
= crossing
->m_intersect
.y
- a
;
726 double arcX2
= crossing
->m_intersect
.x
+ b
;
727 double arcY2
= crossing
->m_intersect
.y
+ a
;
729 dc
.SetPen(*wxBLACK_PEN
);
730 dc
.DrawArc( (long) arcX1
, (long) arcY1
, (long) arcX2
, (long) arcY2
,
731 (long) crossing
->m_intersect
.x
, (long) crossing
->m_intersect
.y
);
733 dc
.SetPen(*wxWHITE_PEN
);
734 dc
.DrawLine( (long) arcX1
, (long) arcY1
, (long) arcX2
, (long) arcY2
);
736 node
= node
->GetNext();
740 void wxLineCrossings::ClearCrossings()
742 wxNode
* node
= m_crossings
.GetFirst();
745 wxLineCrossing
* crossing
= (wxLineCrossing
*) node
->GetData();
747 node
= node
->GetNext();