]>
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"
27 #include <wx/wxexpr.h>
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>
45 IMPLEMENT_DYNAMIC_CLASS(wxDiagram
, wxObject
)
48 wxDiagram::wxDiagram()
50 m_diagramCanvas
= NULL
;
51 m_quickEditMode
= FALSE
;
54 m_shapeList
= new wxList
;
55 m_mouseTolerance
= DEFAULT_MOUSE_TOLERANCE
;
58 wxDiagram::~wxDiagram()
64 void wxDiagram::SetSnapToGrid(bool snap
)
69 void wxDiagram::SetGridSpacing(double spacing
)
71 m_gridSpacing
= spacing
;
74 void wxDiagram::Snap(double *x
, double *y
)
78 *x
= m_gridSpacing
* ((int)(*x
/m_gridSpacing
+ 0.5));
79 *y
= m_gridSpacing
* ((int)(*y
/m_gridSpacing
+ 0.5));
84 void wxDiagram::Redraw(wxDC
& dc
)
89 GetCanvas()->SetCursor(* wxHOURGLASS_CURSOR
);
90 wxNode
*current
= m_shapeList
->First();
94 wxShape
*object
= (wxShape
*)current
->Data();
95 if (!object
->GetParent())
98 current
= current
->Next();
101 GetCanvas()->SetCursor(* wxSTANDARD_CURSOR
);
105 void wxDiagram::Clear(wxDC
& dc
)
110 // Insert object after addAfter, or at end of list.
111 void wxDiagram::AddShape(wxShape
*object
, wxShape
*addAfter
)
113 wxNode
*nodeAfter
= NULL
;
115 nodeAfter
= m_shapeList
->Member(addAfter
);
117 if (!m_shapeList
->Member(object
))
121 if (nodeAfter
->Next())
122 m_shapeList
->Insert(nodeAfter
->Next(), object
);
124 m_shapeList
->Append(object
);
127 m_shapeList
->Append(object
);
128 object
->SetCanvas(GetCanvas());
132 void wxDiagram::InsertShape(wxShape
*object
)
134 m_shapeList
->Insert(object
);
135 object
->SetCanvas(GetCanvas());
138 void wxDiagram::RemoveShape(wxShape
*object
)
140 m_shapeList
->DeleteObject(object
);
143 // Should this delete the actual objects too? I think not.
144 void wxDiagram::RemoveAllShapes()
146 m_shapeList
->Clear();
149 void wxDiagram::DeleteAllShapes()
151 wxNode
*node
= m_shapeList
->First();
154 wxShape
*shape
= (wxShape
*)node
->Data();
155 if (!shape
->GetParent())
159 node
= m_shapeList
->First();
166 void wxDiagram::ShowAll(bool show
)
168 wxNode
*current
= m_shapeList
->First();
172 wxShape
*object
= (wxShape
*)current
->Data();
175 current
= current
->Next();
179 void wxDiagram::DrawOutline(wxDC
& dc
, double x1
, double y1
, double x2
, double y2
)
181 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
182 dc
.SetPen(dottedPen
);
183 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
187 points
[0].x
= (int) x1
;
188 points
[0].y
= (int) y1
;
190 points
[1].x
= (int) x2
;
191 points
[1].y
= (int) y1
;
193 points
[2].x
= (int) x2
;
194 points
[2].y
= (int) y2
;
196 points
[3].x
= (int) x1
;
197 points
[3].y
= (int) y2
;
199 points
[4].x
= (int) x1
;
200 points
[4].y
= (int) y1
;
201 dc
.DrawLines(5, points
);
204 // Make sure all text that should be centred, is centred.
205 void wxDiagram::RecentreAll(wxDC
& dc
)
207 wxNode
*object_node
= m_shapeList
->First();
210 wxShape
*obj
= (wxShape
*)object_node
->Data();
212 object_node
= object_node
->Next();
218 bool wxDiagram::SaveFile(const wxString
& filename
)
222 wxExprDatabase
*database
= new wxExprDatabase
;
224 // First write the diagram type
225 wxExpr
*header
= new wxExpr("diagram");
226 OnHeaderSave(*database
, *header
);
228 database
->Append(header
);
230 wxNode
*node
= m_shapeList
->First();
233 wxShape
*shape
= (wxShape
*)node
->Data();
235 if (!shape
->IsKindOf(CLASSINFO(wxControlPoint
)))
238 if (shape
->IsKindOf(CLASSINFO(wxLineShape
)))
239 expr
= new wxExpr("line");
241 expr
= new wxExpr("shape");
243 OnShapeSave(*database
, *shape
, *expr
);
247 OnDatabaseSave(*database
);
250 wxGetTempFileName(wxT("diag"), tempFile
);
251 FILE* file
= fopen(tempFile
.mb_str(wxConvFile
), "w");
259 database
->Write(file
);
265 if (FileExists(filename))
269 sprintf(buf, "%s.bak", filename);
272 sprintf(buf, "_diagram.bak");
274 if (FileExists(buf)) wxRemoveFile(buf);
275 if (!wxRenameFile(filename, buf))
277 wxCopyFile(filename, buf);
278 wxRemoveFile(filename);
283 // Copy the temporary file to the correct filename
284 if (!wxRenameFile(tempFile
, filename
))
286 wxCopyFile(tempFile
, filename
);
287 wxRemoveFile(tempFile
);
294 bool wxDiagram::LoadFile(const wxString
& filename
)
298 wxExprDatabase
database(wxExprInteger
, "id");
299 if (!database
.Read(filename
))
307 database
.BeginFind();
308 wxExpr
*header
= database
.FindClauseByFunctor("diagram");
311 OnHeaderLoad(database
, *header
);
313 // Scan through all clauses and register the ids
314 wxNode
*node
= database
.First();
317 wxExpr
*clause
= (wxExpr
*)node
->Data();
319 clause
->GetAttributeValue("id", id
);
325 ReadContainerGeometry(database
);
328 OnDatabaseLoad(database
);
335 void wxDiagram::ReadNodes(wxExprDatabase
& database
)
337 // Find and create the node images
338 database
.BeginFind();
339 wxExpr
*clause
= database
.FindClauseByFunctor("shape");
345 clause
->AssignAttributeValue(wxT("type"), &type
);
346 clause
->AssignAttributeValue(wxT("parent"), &parentId
);
347 wxClassInfo
*classInfo
= wxClassInfo::FindClass(type
);
350 wxShape
*shape
= (wxShape
*)classInfo
->CreateObject();
351 OnShapeLoad(database
, *shape
, *clause
);
353 shape
->SetCanvas(GetCanvas());
356 m_shapeList
->Append(shape
);
358 // If child of composite, link up
361 wxExpr
*parentExpr
= database
.HashFind("shape", parentId
);
362 if (parentExpr
&& parentExpr
->GetClientData())
364 wxShape
*parent
= (wxShape
*)parentExpr
->GetClientData();
365 shape
->SetParent(parent
);
366 parent
->GetChildren().Append(shape
);
370 clause
->SetClientData(shape
);
375 clause
= database
.FindClauseByFunctor("shape");
380 void wxDiagram::ReadLines(wxExprDatabase
& database
)
382 database
.BeginFind();
383 wxExpr
*clause
= database
.FindClauseByFunctor("line");
389 clause
->GetAttributeValue("type", type
);
390 clause
->GetAttributeValue("parent", parentId
);
391 wxClassInfo
*classInfo
= wxClassInfo::FindClass(type
);
394 wxLineShape
*shape
= (wxLineShape
*)classInfo
->CreateObject();
397 OnShapeLoad(database
, *shape
, *clause
);
398 shape
->SetCanvas(GetCanvas());
400 long image_to
= -1; long image_from
= -1;
401 clause
->GetAttributeValue("to", image_to
);
402 clause
->GetAttributeValue("from", image_from
);
404 wxExpr
*image_to_expr
= database
.HashFind("shape", image_to
);
410 wxExpr
*image_from_expr
= database
.HashFind("shape", image_from
);
412 if (!image_from_expr
)
417 if (image_to_expr
&& image_from_expr
)
419 wxShape
*image_to_object
= (wxShape
*)image_to_expr
->GetClientData();
420 wxShape
*image_from_object
= (wxShape
*)image_from_expr
->GetClientData();
422 if (image_to_object
&& image_from_object
)
424 image_from_object
->AddLine(shape
, image_to_object
, shape
->GetAttachmentFrom(), shape
->GetAttachmentTo());
427 clause
->SetClientData(shape
);
429 m_shapeList
->Append(shape
);
432 clause
= database
.FindClauseByFunctor("line");
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
)
441 database
.BeginFind();
442 wxExpr
*clause
= database
.FindClauseByFunctor("shape");
445 wxShape
*image
= (wxShape
*)clause
->GetClientData();
446 if (image
&& image
->IsKindOf(CLASSINFO(wxCompositeShape
)))
448 wxCompositeShape
*composite
= (wxCompositeShape
*)image
;
449 wxExpr
*divisionExpr
= NULL
;
451 // Find the list of divisions in the composite
452 clause
->GetAttributeValue("divisions", &divisionExpr
);
456 wxExpr
*idExpr
= divisionExpr
->Nth(i
);
459 long divisionId
= idExpr
->IntegerValue();
460 wxExpr
*childExpr
= database
.HashFind("shape", divisionId
);
461 if (childExpr
&& childExpr
->GetClientData())
463 wxDivisionShape
*child
= (wxDivisionShape
*)childExpr
->GetClientData();
464 composite
->GetDivisions().Append(child
);
466 // Find the adjoining shapes
467 long leftSideId
= -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
);
477 wxExpr
*leftExpr
= database
.HashFind("shape", leftSideId
);
478 if (leftExpr
&& leftExpr
->GetClientData())
480 wxDivisionShape
*leftSide
= (wxDivisionShape
*)leftExpr
->GetClientData();
481 child
->SetLeftSide(leftSide
);
486 wxExpr
*topExpr
= database
.HashFind("shape", topSideId
);
487 if (topExpr
&& topExpr
->GetClientData())
489 wxDivisionShape
*topSide
= (wxDivisionShape
*)topExpr
->GetClientData();
490 child
->SetTopSide(topSide
);
493 if (rightSideId
> -1)
495 wxExpr
*rightExpr
= database
.HashFind("shape", rightSideId
);
496 if (rightExpr
&& rightExpr
->GetClientData())
498 wxDivisionShape
*rightSide
= (wxDivisionShape
*)rightExpr
->GetClientData();
499 child
->SetRightSide(rightSide
);
502 if (bottomSideId
> -1)
504 wxExpr
*bottomExpr
= database
.HashFind("shape", bottomSideId
);
505 if (bottomExpr
&& bottomExpr
->GetClientData())
507 wxDivisionShape
*bottomSide
= (wxDivisionShape
*)bottomExpr
->GetClientData();
508 child
->SetBottomSide(bottomSide
);
513 idExpr
= divisionExpr
->Nth(i
);
518 clause
= database
.FindClauseByFunctor("shape");
522 // Allow for modifying file
523 bool wxDiagram::OnDatabaseLoad(wxExprDatabase
& db
)
528 bool wxDiagram::OnDatabaseSave(wxExprDatabase
& db
)
533 bool wxDiagram::OnShapeSave(wxExprDatabase
& db
, wxShape
& shape
, wxExpr
& expr
)
535 shape
.WriteAttributes(&expr
);
538 if (shape
.IsKindOf(CLASSINFO(wxCompositeShape
)))
540 wxNode
*node
= shape
.GetChildren().First();
543 wxShape
*childShape
= (wxShape
*)node
->Data();
544 wxExpr
*childExpr
= new wxExpr("shape");
545 OnShapeSave(db
, *childShape
, *childExpr
);
553 bool wxDiagram::OnShapeLoad(wxExprDatabase
& db
, wxShape
& shape
, wxExpr
& expr
)
555 shape
.ReadAttributes(&expr
);
559 bool wxDiagram::OnHeaderSave(wxExprDatabase
& db
, wxExpr
& expr
)
564 bool wxDiagram::OnHeaderLoad(wxExprDatabase
& db
, wxExpr
& expr
)
571 void wxDiagram::SetCanvas(wxShapeCanvas
*can
)
573 m_diagramCanvas
= can
;
576 // Find a shape by its id
577 wxShape
* wxDiagram::FindShape(long id
) const
579 wxNode
* node
= GetShapeList()->First();
582 wxShape
* shape
= (wxShape
*) node
->Data();
583 if (shape
->GetId() == id
)
591 //// Crossings classes
593 wxLineCrossings::wxLineCrossings()
597 wxLineCrossings::~wxLineCrossings()
602 void wxLineCrossings::FindCrossings(wxDiagram
& diagram
)
605 wxNode
* node1
= diagram
.GetShapeList()->First();
608 wxShape
* shape1
= (wxShape
*) node1
->Data();
609 if (shape1
->IsKindOf(CLASSINFO(wxLineShape
)))
611 wxLineShape
* lineShape1
= (wxLineShape
*) shape1
;
612 // Iterate through the segments
613 wxList
* pts1
= lineShape1
->GetLineControlPoints();
615 for (i
= 0; i
< (pts1
->Number() - 1); i
++)
617 wxRealPoint
* pt1_a
= (wxRealPoint
*) (pts1
->Nth(i
)->Data());
618 wxRealPoint
* pt1_b
= (wxRealPoint
*) (pts1
->Nth(i
+1)->Data());
620 // Now we iterate through the segments again
622 wxNode
* node2
= diagram
.GetShapeList()->First();
625 wxShape
* shape2
= (wxShape
*) node2
->Data();
627 // Assume that the same line doesn't cross itself
628 if (shape2
->IsKindOf(CLASSINFO(wxLineShape
)) && (shape1
!= shape2
))
630 wxLineShape
* lineShape2
= (wxLineShape
*) shape2
;
631 // Iterate through the segments
632 wxList
* pts2
= lineShape2
->GetLineControlPoints();
634 for (j
= 0; j
< (pts2
->Number() - 1); j
++)
636 wxRealPoint
* pt2_a
= (wxRealPoint
*) (pts2
->Nth(j
)->Data());
637 wxRealPoint
* pt2_b
= (wxRealPoint
*) (pts2
->Nth(j
+1)->Data());
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
,
645 if ((ratio1
< 1.0) && (ratio1
> -1.0))
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
);
652 crossing
->m_pt1
= * pt1_a
;
653 crossing
->m_pt2
= * pt1_b
;
654 crossing
->m_pt3
= * pt2_a
;
655 crossing
->m_pt4
= * pt2_b
;
657 crossing
->m_lineShape1
= lineShape1
;
658 crossing
->m_lineShape2
= lineShape2
;
660 m_crossings
.Append(crossing
);
664 node2
= node2
->Next();
669 node1
= node1
->Next();
673 void wxLineCrossings::DrawCrossings(wxDiagram
& diagram
, wxDC
& dc
)
675 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
679 wxNode
* node
= m_crossings
.First();
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);
687 // Let's do some geometry to find the points on either end of the arc.
699 | - x <-- centre of arc
706 |_______________\ (x2, y2)
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
) );
715 double c
= arcWidth
/ 2.0;
716 double a
= c
* a1
/c1
;
717 double b
= c
* b1
/c1
;
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
;
724 double arcX2
= crossing
->m_intersect
.x
+ b
;
725 double arcY2
= crossing
->m_intersect
.y
+ a
;
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
);
731 dc
.SetPen(*wxWHITE_PEN
);
732 dc
.DrawLine( (long) arcX1
, (long) arcY1
, (long) arcX2
, (long) arcY2
);
738 void wxLineCrossings::ClearCrossings()
740 wxNode
* node
= m_crossings
.First();
743 wxLineCrossing
* crossing
= (wxLineCrossing
*) node
->Data();