📄 lines.cpp
字号:
for (int i = 0; i < 3; i ++) { wxNode *regionNode = m_regions.Item(i); if (regionNode) { wxShapeRegion *region = (wxShapeRegion *)regionNode->GetData(); if (region->m_formattedText.GetCount() > 0) { double xp, yp, cx, cy, cw, ch; GetLabelPosition(i, &xp, &yp); // Offset region from default label position region->GetPosition(&cx, &cy); region->GetSize(&cw, &ch); cx += xp; cy += yp; double rLeft = (double)(cx - (cw/2.0)); double rTop = (double)(cy - (ch/2.0)); double rRight = (double)(cx + (cw/2.0)); double rBottom = (double)(cy + (ch/2.0)); if (x > rLeft && x < rRight && y > rTop && y < rBottom) { inLabelRegion = true; i = 3; } } } } wxNode *node = m_lineControlPoints->GetFirst(); while (node && node->GetNext()) { wxRealPoint *point1 = (wxRealPoint *)node->GetData(); wxRealPoint *point2 = (wxRealPoint *)node->GetNext()->GetData(); // For inaccurate mousing allow 8 pixel corridor int extra = 4; double dx = point2->x - point1->x; double dy = point2->y - point1->y; double seg_len = sqrt(dx*dx+dy*dy); double distance_from_seg = seg_len*((x-point1->x)*dy-(y-point1->y)*dx)/(dy*dy+dx*dx); double distance_from_prev = seg_len*((y-point1->y)*dy+(x-point1->x)*dx)/(dy*dy+dx*dx); if ((fabs(distance_from_seg) < extra && distance_from_prev >= 0 && distance_from_prev <= seg_len) || inLabelRegion) { *attachment = 0; *distance = distance_from_seg; return true; } node = node->GetNext(); } return false;}void wxLineShape::DrawArrows(wxDC& dc){ // Distance along line of each arrow: space them out evenly. double startArrowPos = 0.0; double endArrowPos = 0.0; double middleArrowPos = 0.0; wxNode *node = m_arcArrows.GetFirst(); while (node) { wxArrowHead *arrow = (wxArrowHead *)node->GetData(); switch (arrow->GetArrowEnd()) { case ARROW_POSITION_START: { if ((arrow->GetXOffset() != 0.0) && !m_ignoreArrowOffsets) // If specified, x offset is proportional to line length DrawArrow(dc, arrow, arrow->GetXOffset(), true); else { DrawArrow(dc, arrow, startArrowPos, false); // Absolute distance startArrowPos += arrow->GetSize() + arrow->GetSpacing(); } break; } case ARROW_POSITION_END: { if ((arrow->GetXOffset() != 0.0) && !m_ignoreArrowOffsets) DrawArrow(dc, arrow, arrow->GetXOffset(), true); else { DrawArrow(dc, arrow, endArrowPos, false); endArrowPos += arrow->GetSize() + arrow->GetSpacing(); } break; } case ARROW_POSITION_MIDDLE: { arrow->SetXOffset(middleArrowPos); if ((arrow->GetXOffset() != 0.0) && !m_ignoreArrowOffsets) DrawArrow(dc, arrow, arrow->GetXOffset(), true); else { DrawArrow(dc, arrow, middleArrowPos, false); middleArrowPos += arrow->GetSize() + arrow->GetSpacing(); } break; } } node = node->GetNext(); }}void wxLineShape::DrawArrow(wxDC& dc, wxArrowHead *arrow, double xOffset, bool proportionalOffset){ wxNode *first_line_node = m_lineControlPoints->GetFirst(); wxRealPoint *first_line_point = (wxRealPoint *)first_line_node->GetData(); wxNode *second_line_node = first_line_node->GetNext(); wxRealPoint *second_line_point = (wxRealPoint *)second_line_node->GetData(); wxNode *last_line_node = m_lineControlPoints->GetLast(); wxRealPoint *last_line_point = (wxRealPoint *)last_line_node->GetData(); wxNode *second_last_line_node = last_line_node->GetPrevious(); wxRealPoint *second_last_line_point = (wxRealPoint *)second_last_line_node->GetData(); // Position where we want to start drawing double positionOnLineX = 0.0, positionOnLineY = 0.0; // Position of start point of line, at the end of which we draw the arrow. double startPositionX = 0.0 , startPositionY = 0.0; switch (arrow->GetPosition()) { case ARROW_POSITION_START: { // If we're using a proportional offset, calculate just where this will // be on the line. double realOffset = xOffset; if (proportionalOffset) { double totalLength = (double)sqrt((second_line_point->x - first_line_point->x)*(second_line_point->x - first_line_point->x) + (second_line_point->y - first_line_point->y)*(second_line_point->y - first_line_point->y)); realOffset = (double)(xOffset * totalLength); } GetPointOnLine(second_line_point->x, second_line_point->y, first_line_point->x, first_line_point->y, realOffset, &positionOnLineX, &positionOnLineY); startPositionX = second_line_point->x; startPositionY = second_line_point->y; break; } case ARROW_POSITION_END: { // If we're using a proportional offset, calculate just where this will // be on the line. double realOffset = xOffset; if (proportionalOffset) { double totalLength = (double)sqrt((second_last_line_point->x - last_line_point->x)*(second_last_line_point->x - last_line_point->x) + (second_last_line_point->y - last_line_point->y)*(second_last_line_point->y - last_line_point->y)); realOffset = (double)(xOffset * totalLength); } GetPointOnLine(second_last_line_point->x, second_last_line_point->y, last_line_point->x, last_line_point->y, realOffset, &positionOnLineX, &positionOnLineY); startPositionX = second_last_line_point->x; startPositionY = second_last_line_point->y; break; } case ARROW_POSITION_MIDDLE: { // Choose a point half way between the last and penultimate points double x = ((last_line_point->x + second_last_line_point->x)/2); double y = ((last_line_point->y + second_last_line_point->y)/2); // If we're using a proportional offset, calculate just where this will // be on the line. double realOffset = xOffset; if (proportionalOffset) { double totalLength = (double)sqrt((second_last_line_point->x - x)*(second_last_line_point->x - x) + (second_last_line_point->y - y)*(second_last_line_point->y - y)); realOffset = (double)(xOffset * totalLength); } GetPointOnLine(second_last_line_point->x, second_last_line_point->y, x, y, realOffset, &positionOnLineX, &positionOnLineY); startPositionX = second_last_line_point->x; startPositionY = second_last_line_point->y; break; } } /* * Add yOffset to arrow, if any */ const double myPi = (double) M_PI; // The translation that the y offset may give double deltaX = 0.0; double deltaY = 0.0; if ((arrow->GetYOffset() != 0.0) && !m_ignoreArrowOffsets) { /* |(x4, y4) |d | (x1, y1)--------------(x3, y3)------------------(x2, y2) x4 = x3 - d * sin(theta) y4 = y3 + d * cos(theta) Where theta = tan(-1) of (y3-y1)/(x3-x1) */ double x1 = startPositionX; double y1 = startPositionY; double x3 = positionOnLineX; double y3 = positionOnLineY; double d = -arrow->GetYOffset(); // Negate so +offset is above line double theta; if (x3 == x1) theta = (double)(myPi/2.0); else theta = (double)atan((y3-y1)/(x3-x1)); double x4 = (double)(x3 - (d*sin(theta))); double y4 = (double)(y3 + (d*cos(theta))); deltaX = x4 - positionOnLineX; deltaY = y4 - positionOnLineY; } switch (arrow->_GetType()) { case ARROW_ARROW: { double arrowLength = arrow->GetSize(); double arrowWidth = (double)(arrowLength/3.0); double tip_x, tip_y, side1_x, side1_y, side2_x, side2_y; oglGetArrowPoints(startPositionX+deltaX, startPositionY+deltaY, positionOnLineX+deltaX, positionOnLineY+deltaY, arrowLength, arrowWidth, &tip_x, &tip_y, &side1_x, &side1_y, &side2_x, &side2_y); wxPoint points[4]; points[0].x = (int) tip_x; points[0].y = (int) tip_y; points[1].x = (int) side1_x; points[1].y = (int) side1_y; points[2].x = (int) side2_x; points[2].y = (int) side2_y; points[3].x = (int) tip_x; points[3].y = (int) tip_y; dc.SetPen(* m_pen); dc.SetBrush(* m_brush); dc.DrawPolygon(4, points); break; } case ARROW_HOLLOW_CIRCLE: case ARROW_FILLED_CIRCLE: { // Find point on line of centre of circle, which is a radius away // from the end position double diameter = (double)(arrow->GetSize()); double x, y; GetPointOnLine(startPositionX+deltaX, startPositionY+deltaY, positionOnLineX+deltaX, positionOnLineY+deltaY, (double)(diameter/2.0), &x, &y); // Convert ellipse centre to top-left coordinates double x1 = (double)(x - (diameter/2.0)); double y1 = (double)(y - (diameter/2.0)); dc.SetPen(* m_pen); if (arrow->_GetType() == ARROW_HOLLOW_CIRCLE) dc.SetBrush(GetBackgroundBrush()); else dc.SetBrush(* m_brush); dc.DrawEllipse((long) x1, (long) y1, (long) diameter, (long) diameter); break; } case ARROW_SINGLE_OBLIQUE: { break; } case ARROW_METAFILE: { if (arrow->GetMetaFile()) { // Find point on line of centre of object, which is a half-width away // from the end position /* * width * <-- start pos <-----><-- positionOnLineX * _____ * --------------| x | <-- e.g. rectangular arrowhead * ----- */ double x, y; GetPointOnLine(startPositionX, startPositionY, positionOnLineX, positionOnLineY, (double)(arrow->GetMetaFile()->m_width/2.0), &x, &y); // Calculate theta for rotating the metafile. /* | | o(x2, y2) 'o' represents the arrowhead. | / | / | /theta | /(x1, y1) |______________________ */ double theta = 0.0; double x1 = startPositionX; double y1 = startPositionY; double x2 = positionOnLineX; double y2 = positionOnLineY; if ((x1 == x2) && (y1 == y2)) theta = 0.0; else if ((x1 == x2) && (y1 > y2)) theta = (double)(3.0*myPi/2.0); else if ((x1 == x2) && (y2 > y1)) theta = (double)(myPi/2.0); else if ((x2 > x1) && (y2 >= y1)) theta = (double)atan((y2 - y1)/(x2 - x1)); else if (x2 < x1) theta = (double)(myPi + atan((y2 - y1)/(x2 - x1))); else if ((x2 > x1) && (y2 < y1)) theta = (double)(2*myPi + atan((y2 - y1)/(x2 - x1))); else { wxLogFatalError(wxT("Unknown arrowhead rotation case in lines.cc")); } // Rotate about the centre of the object, then place // the object on the line. if (arrow->GetMetaFile()->GetRotateable()) arrow->GetMetaFile()->Rotate(0.0, 0.0, theta); if (m_erasing) { // If erasing, just draw a rectangle. double minX, minY, maxX, maxY; arrow->GetMetaFile()->GetBounds(&minX, &minY, &maxX, &maxY); // Make erasing rectangle slightly bigger or you get droppings. int extraPixels = 4; dc.DrawRectangle((long)(deltaX + x + minX - (extraPixels/2.0)), (long)(deltaY + y + minY - (extraPixels/2.0)), (long)(maxX - minX + extraPixels), (long)(maxY - minY + extraPixels)); } else arrow->GetMetaFile()->Draw(dc, x+deltaX, y+deltaY); } break; } default: { } }}void wxLineShape::OnErase(wxDC& dc){ const wxPen *old_pen = m_pen; const wxBrush *old_brush = m_brush; wxPen bg_pen = GetBackgroundPen(); wxBrush bg_brush = GetBackgroundBrush(); SetPen(&bg_pen); SetBrush(&bg_brush); double bound_x, bound_y; GetBoundingBoxMax(&bound_x, &bound_y); if (m_font) dc.SetFont(* m_font); // Undraw text regions for (int i = 0; i < 3; i++) { wxNode *node = m_regions.Item(i); if (node) { double x, y; wxShapeRegion *region = (wxShapeRegion *)node->GetData(); GetLabelPosition(i, &x, &y); EraseRegion(dc, region, x, y); } } // Undraw line dc.SetPen(GetBackgroundPen()); dc.SetBrush(GetBackgroundBrush()); // Drawing over the line only seems to work if the line has a thickness // of 1. if (old_pen && (old_pen->GetWidth() > 1)) { dc.DrawRectangle((long)(m_xpos - (bound_x/2.0) - 2.0), (long)(m_ypos - (bound_y/2.0) - 2.0), (long)(bound_x+4.0), (long)(bound_y+4.0)); } else { m_erasing = true; GetEventHandler()->OnDraw(dc); GetEventHandler()->OnEraseControlPoints(dc); m_erasing = false; } if (old_pen) SetPen(old_pen); if (old_brush) SetBrush(old_brush);}void wxLineShape::GetBoundingBoxMin(double *w, double *h){ double x1 = 10000; double y1 = 10000; double x2 = -10000; double y2 = -10000; wxNode *node = m_lineControlPoints->GetFirst(); while (node) { wxRealPoint *point = (wxRealPoint *)node->GetData(); if (point->x < x1) x1 = point->x; if (point->y < y1) y1 = point->y; if (point->x > x2) x2 = point->x; if (point->y > y2) y2 = point->y; node = node->GetNext(); } *w = (double)(x2 - x1); *h = (double)(y2 - y1);}/* * For a node image of interest, finds the position of this arc * amongst all the arcs which are attached to THIS SIDE of the node image, * and the number of same. */void wxLineShape::FindNth(wxShape *image, int *nth, int *no_arcs, bool incoming){ int n = -1; int num = 0; wxNode *node = image->GetLines().GetFirst(); int this_attachment; if (image == m_to) this_attachment = m_attachmentTo; else this_attachment = m_attachmentFrom; // Find number of lines going into/out of this particular attachment point while (node) { wxLineShape *line = (wxLineShape *)node->GetData();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -