⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lines.cpp

📁 Wxpython Implemented on Windows CE, Source code
💻 CPP
📖 第 1 页 / 共 5 页
字号:

void wxLineShape::SetAttachments(int from_attach, int to_attach)
{
  m_attachmentFrom = from_attach;
  m_attachmentTo = to_attach;
}

bool wxLineShape::HitTest(double x, double y, int *attachment, double *distance)
{
  if (!m_lineControlPoints)
    return false;

  // Look at label regions in case mouse is over a label
  bool inLabelRegion = false;
  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;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -