+// Assuming the attachment lies along a vertical or horizontal line,
+// calculate the position on that point.
+wxRealPoint wxShape::CalcSimpleAttachment(const wxRealPoint& pt1, const wxRealPoint& pt2,
+ int nth, int noArcs, wxLineShape* line)
+{
+ bool isEnd = (line && line->IsEnd(this));
+
+ // Are we horizontal or vertical?
+ bool isHorizontal = (oglRoughlyEqual(pt1.y, pt2.y) == TRUE);
+
+ double x, y;
+
+ if (isHorizontal)
+ {
+ wxRealPoint firstPoint, secondPoint;
+ if (pt1.x > pt2.x)
+ {
+ firstPoint = pt2;
+ secondPoint = pt1;
+ }
+ else
+ {
+ firstPoint = pt1;
+ secondPoint = pt2;
+ }
+
+ if (m_spaceAttachments)
+ {
+ if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE))
+ {
+ // Align line according to the next handle along
+ wxRealPoint *point = line->GetNextControlPoint(this);
+ if (point->x < firstPoint.x)
+ x = firstPoint.x;
+ else if (point->x > secondPoint.x)
+ x = secondPoint.x;
+ else
+ x = point->x;
+ }
+ else
+ x = firstPoint.x + (nth + 1)*(secondPoint.x - firstPoint.x)/(noArcs + 1);
+ }
+ else x = (secondPoint.x - firstPoint.x)/2.0; // Midpoint
+
+ y = pt1.y;
+ }
+ else
+ {
+ wxASSERT( oglRoughlyEqual(pt1.x, pt2.x) == TRUE );
+
+ wxRealPoint firstPoint, secondPoint;
+ if (pt1.y > pt2.y)
+ {
+ firstPoint = pt2;
+ secondPoint = pt1;
+ }
+ else
+ {
+ firstPoint = pt1;
+ secondPoint = pt2;
+ }
+
+ if (m_spaceAttachments)
+ {
+ if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE))
+ {
+ // Align line according to the next handle along
+ wxRealPoint *point = line->GetNextControlPoint(this);
+ if (point->y < firstPoint.y)
+ y = firstPoint.y;
+ else if (point->y > secondPoint.y)
+ y = secondPoint.y;
+ else
+ y = point->y;
+ }
+ else
+ y = firstPoint.y + (nth + 1)*(secondPoint.y - firstPoint.y)/(noArcs + 1);
+ }
+ else y = (secondPoint.y - firstPoint.y)/2.0; // Midpoint
+
+ x = pt1.x;
+ }
+
+ return wxRealPoint(x, y);
+}
+
+// Return the zero-based position in m_lines of line.
+int wxShape::GetLinePosition(wxLineShape* line)
+{
+ int i = 0;
+ for (i = 0; i < m_lines.Number(); i++)
+ if ((wxLineShape*) (m_lines.Nth(i)->Data()) == line)
+ return i;
+
+ return 0;
+}
+
+//
+// |________|
+// | <- root
+// | <- neck
+// shoulder1 ->---------<- shoulder2
+// | | | | |
+// <- branching attachment point N-1
+
+// This function gets information about where branching connections go.
+// Returns FALSE if there are no lines at this attachment.
+bool wxShape::GetBranchingAttachmentInfo(int attachment, wxRealPoint& root, wxRealPoint& neck,
+ wxRealPoint& shoulder1, wxRealPoint& shoulder2)
+{
+ int physicalAttachment = LogicalToPhysicalAttachment(attachment);
+
+ // Number of lines at this attachment.
+ int lineCount = GetAttachmentLineCount(attachment);
+
+ if (lineCount == 0)
+ return FALSE;
+
+ int totalBranchLength = m_branchSpacing * (lineCount - 1);
+
+ root = GetBranchingAttachmentRoot(attachment);
+
+ // Assume that we have attachment points 0 to 3: top, right, bottom, left.
+ switch (physicalAttachment)
+ {
+ case 0:
+ {
+ neck.x = GetX();
+ neck.y = root.y - m_branchNeckLength;
+
+ shoulder1.x = root.x - (totalBranchLength/2.0) ;
+ shoulder2.x = root.x + (totalBranchLength/2.0) ;
+
+ shoulder1.y = neck.y;
+ shoulder2.y = neck.y;
+ break;
+ }
+ case 1:
+ {
+ neck.x = root.x + m_branchNeckLength;
+ neck.y = root.y;
+
+ shoulder1.x = neck.x ;
+ shoulder2.x = neck.x ;
+
+ shoulder1.y = neck.y - (totalBranchLength/2.0) ;
+ shoulder2.y = neck.y + (totalBranchLength/2.0) ;
+ break;
+ }
+ case 2:
+ {
+ neck.x = GetX();
+ neck.y = root.y + m_branchNeckLength;
+
+ shoulder1.x = root.x - (totalBranchLength/2.0) ;
+ shoulder2.x = root.x + (totalBranchLength/2.0) ;
+
+ shoulder1.y = neck.y;
+ shoulder2.y = neck.y;
+ break;
+ }
+ case 3:
+ {
+ neck.x = root.x - m_branchNeckLength;
+ neck.y = root.y ;
+
+ shoulder1.x = neck.x ;
+ shoulder2.x = neck.x ;
+
+ shoulder1.y = neck.y - (totalBranchLength/2.0) ;
+ shoulder2.y = neck.y + (totalBranchLength/2.0) ;
+ break;
+ }
+ default:
+ {
+ wxFAIL_MSG( "Unrecognised attachment point in GetBranchingAttachmentInfo." );
+ break;
+ }
+ }
+ return TRUE;
+}
+
+// n is the number of the adjoining line, from 0 to N-1 where N is the number of lines
+// at this attachment point.
+// Get the attachment point where the arc joins the stem, and also the point where the
+// the stem meets the shoulder.
+bool wxShape::GetBranchingAttachmentPoint(int attachment, int n, wxRealPoint& pt, wxRealPoint& stemPt)
+{
+ int physicalAttachment = LogicalToPhysicalAttachment(attachment);
+
+ wxRealPoint root, neck, shoulder1, shoulder2;
+ GetBranchingAttachmentInfo(attachment, root, neck, shoulder1, shoulder2);
+
+ // Assume that we have attachment points 0 to 3: top, right, bottom, left.
+ switch (physicalAttachment)
+ {
+ case 0:
+ {
+ pt.y = neck.y - m_branchStemLength;
+ pt.x = shoulder1.x + n*m_branchSpacing;
+
+ stemPt.x = pt.x;
+ stemPt.y = neck.y;
+ break;
+ }
+ case 2:
+ {
+ pt.y = neck.y + m_branchStemLength;
+ pt.x = shoulder1.x + n*m_branchSpacing;
+
+ stemPt.x = pt.x;
+ stemPt.y = neck.y;
+ break;
+ }
+ case 1:
+ {
+ pt.x = neck.x + m_branchStemLength;
+ pt.y = shoulder1.y + n*m_branchSpacing;
+
+ stemPt.x = neck.x;
+ stemPt.y = pt.y;
+ break;
+ }
+ case 3:
+ {
+ pt.x = neck.x - m_branchStemLength;
+ pt.y = shoulder1.y + n*m_branchSpacing;
+
+ stemPt.x = neck.x;
+ stemPt.y = pt.y;
+ break;
+ }
+ default:
+ {
+ wxFAIL_MSG( "Unrecognised attachment point in GetBranchingAttachmentPoint." );
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
+// Get the number of lines at this attachment position.
+int wxShape::GetAttachmentLineCount(int attachment) const
+{
+ int count = 0;
+ wxNode* node = m_lines.First();
+ while (node)
+ {
+ wxLineShape* lineShape = (wxLineShape*) node->Data();
+ if ((lineShape->GetFrom() == this) && (lineShape->GetAttachmentFrom() == attachment))
+ count ++;
+ else if ((lineShape->GetTo() == this) && (lineShape->GetAttachmentTo() == attachment))
+ count ++;
+
+ node = node->Next();
+ }
+ return count;
+}
+
+// This function gets the root point at the given attachment.
+wxRealPoint wxShape::GetBranchingAttachmentRoot(int attachment)
+{
+ int physicalAttachment = LogicalToPhysicalAttachment(attachment);
+
+ wxRealPoint root;
+
+ double width, height;
+ GetBoundingBoxMax(& width, & height);
+
+ // Assume that we have attachment points 0 to 3: top, right, bottom, left.
+ switch (physicalAttachment)
+ {
+ case 0:
+ {
+ root.x = GetX() ;
+ root.y = GetY() - height/2.0;
+ break;
+ }
+ case 1:
+ {
+ root.x = GetX() + width/2.0;
+ root.y = GetY() ;
+ break;
+ }
+ case 2:
+ {
+ root.x = GetX() ;
+ root.y = GetY() + height/2.0;
+ break;
+ }
+ case 3:
+ {
+ root.x = GetX() - width/2.0;
+ root.y = GetY() ;
+ break;
+ }
+ default:
+ {
+ wxFAIL_MSG( "Unrecognised attachment point in GetBranchingAttachmentRoot." );
+ break;
+ }
+ }
+ return root;
+}
+
+// Draw or erase the branches (not the actual arcs though)
+void wxShape::OnDrawBranches(wxDC& dc, int attachment, bool erase)
+{
+ int count = GetAttachmentLineCount(attachment);
+ if (count == 0)
+ return;
+
+ wxRealPoint root, neck, shoulder1, shoulder2;
+ GetBranchingAttachmentInfo(attachment, root, neck, shoulder1, shoulder2);
+
+ if (erase)
+ {
+ dc.SetPen(*wxWHITE_PEN);
+ dc.SetBrush(*wxWHITE_BRUSH);
+ }
+ else
+ {
+ dc.SetPen(*wxBLACK_PEN);
+ dc.SetBrush(*wxBLACK_BRUSH);
+ }
+
+ // Draw neck
+ dc.DrawLine((long) root.x, (long) root.y, (long) neck.x, (long) neck.y);
+
+ if (count > 1)
+ {
+ // Draw shoulder-to-shoulder line
+ dc.DrawLine((long) shoulder1.x, (long) shoulder1.y, (long) shoulder2.x, (long) shoulder2.y);
+ }
+ // Draw all the little branches
+ int i;
+ for (i = 0; i < count; i++)
+ {
+ wxRealPoint pt, stemPt;
+ GetBranchingAttachmentPoint(attachment, i, pt, stemPt);
+ dc.DrawLine((long) stemPt.x, (long) stemPt.y, (long) pt.x, (long) pt.y);
+
+ if ((GetBranchStyle() & BRANCHING_ATTACHMENT_BLOB) && (count > 1))
+ {
+ long blobSize=6;
+// dc.DrawEllipse((long) (stemPt.x + 0.5 - (blobSize/2.0)), (long) (stemPt.y + 0.5 - (blobSize/2.0)), blobSize, blobSize);
+ dc.DrawEllipse((long) (stemPt.x - (blobSize/2.0)), (long) (stemPt.y - (blobSize/2.0)), blobSize, blobSize);
+ }
+ }
+}
+
+// Draw or erase the branches (not the actual arcs though)
+void wxShape::OnDrawBranches(wxDC& dc, bool erase)
+{
+ if (m_attachmentMode != ATTACHMENT_MODE_BRANCHING)
+ return;
+
+ int count = GetNumberOfAttachments();
+ int i;
+ for (i = 0; i < count; i++)
+ OnDrawBranches(dc, i, erase);
+}
+
+// Only get the attachment position at the _edge_ of the shape, ignoring
+// branching mode. This is used e.g. to indicate the edge of interest, not the point
+// on the attachment branch.
+bool wxShape::GetAttachmentPositionEdge(int attachment, double *x, double *y,
+ int nth, int no_arcs, wxLineShape *line)
+{
+ int oldMode = m_attachmentMode;
+
+ // Calculate as if to edge, not branch
+ if (m_attachmentMode == ATTACHMENT_MODE_BRANCHING)
+ m_attachmentMode = ATTACHMENT_MODE_EDGE;
+ bool success = GetAttachmentPosition(attachment, x, y, nth, no_arcs, line);
+ m_attachmentMode = oldMode;
+
+ return success;
+}
+
+// Rotate the standard attachment point from physical (0 is always North)
+// to logical (0 -> 1 if rotated by 90 degrees)
+int wxShape::PhysicalToLogicalAttachment(int physicalAttachment) const
+{
+ const double pi = 3.1415926535897932384626433832795 ;
+ int i;
+ if (oglRoughlyEqual(GetRotation(), 0.0))
+ {
+ i = physicalAttachment;
+ }
+ else if (oglRoughlyEqual(GetRotation(), (pi/2.0)))
+ {
+ i = physicalAttachment - 1;
+ }
+ else if (oglRoughlyEqual(GetRotation(), pi))
+ {
+ i = physicalAttachment - 2;
+ }
+ else if (oglRoughlyEqual(GetRotation(), (3.0*pi/2.0)))
+ {
+ i = physicalAttachment - 3;
+ }
+ else
+ // Can't handle -- assume the same.
+ return physicalAttachment;
+
+ if (i < 0)
+ i += 4;
+
+ return i;
+}
+
+// Rotate the standard attachment point from logical
+// to physical (0 is always North)
+int wxShape::LogicalToPhysicalAttachment(int logicalAttachment) const
+{
+ const double pi = 3.1415926535897932384626433832795 ;
+ int i;
+ if (oglRoughlyEqual(GetRotation(), 0.0))
+ {
+ i = logicalAttachment;
+ }
+ else if (oglRoughlyEqual(GetRotation(), (pi/2.0)))
+ {
+ i = logicalAttachment + 1;
+ }
+ else if (oglRoughlyEqual(GetRotation(), pi))
+ {
+ i = logicalAttachment + 2;
+ }
+ else if (oglRoughlyEqual(GetRotation(), (3.0*pi/2.0)))
+ {
+ i = logicalAttachment + 3;
+ }
+ else
+ // Can't handle -- assume the same.
+ return logicalAttachment;
+
+ if (i > 3)
+ i -= 4;
+
+ return i;
+}
+
+void wxShape::Rotate(double WXUNUSED(x), double WXUNUSED(y), double theta)
+{
+ const double pi = 3.1415926535897932384626433832795 ;
+ m_rotation = theta;
+ if (m_rotation < 0.0)
+ {
+ m_rotation += 2*pi;
+ }
+ else if (m_rotation > 2*pi)
+ {
+ m_rotation -= 2*pi;
+ }
+}
+