Page 1 of 1

Drawing Polygon on Canvas in OnAfterDraw

Posted: Sat Sep 12, 2020 3:50 am
by 15049432
In C++ ActiveX v8, I want to draw a direction arrow on my line series that points along the line.

I've calculated the points of the arrow (below) - but I'm not sure how to put them into the VARIANT for the Polygon?
Is it supposed to be an array of CPoints? Or an integer list of coordinates?

Code: Select all

//------------------------------------------------------------------------------
void MyDialog::OnAfterDraw()
//------------------------------------------------------------------------------
{
	int nValues = m_Chart.Series(1).GetXValues().GetCount();
	int nHalf = nValues / 2;

	CPoint to(m_Chart.Series(0).CalcXPos(nHalf ), m_Chart.Series(0).CalcYPos(nHalf));
	CPoint from(m_Chart.Series(0).CalcXPos(nHalf - 1), m_Chart.Series(0).CalcYPos(nHalf - 1));

	int x1 = to.x;
	int y1 = to.y;

	int x2 = from.x;
	int y2 = from.y;

	CPoint p1, p2, p3;

	int xres = 8;		// Size of arrow
	double theta;
	double theta2 = atan(0.5);
	double hypot = sqrt(double(xres * xres) * 5/4);
	double l;

	p1 = CPoint(0, 0);
	p2 = CPoint(0, 0);
	p3 = CPoint(0, 0);

	// Calculate angle of line
	if (y2 == y1)
	{
		theta = ((x2 > x1) ? 0.0 : PI);
	}
	else
	{
		theta = atan((double) (y2 - y1) / (double) (x2 - x1));

		if ((y2 > y1) && (x2 < x1))
		{
			theta = PI + theta;
		}

		if ((y1 > y2) && (x1 > x2))
		{
			theta = PI + theta;
		}
	}

	// If arrow is in the middle, adjust P1 to line centre
	if (TRUE)
	{
		l = 0.6 * hypot * cos(theta2);

		p1.x = long(x2 + l * cos(theta) + 0.5);
		p1.y = long(y2 + l * sin(theta) + 0.5);
	}
	else
	{
		p1.x = x2;
		p1.y = y2;
	}

	p2.x = long((p1.x - hypot * cos (theta + theta2)) + 0.5);
	p2.y = long((p1.y - hypot * sin (theta + theta2)) + 0.5);

	p3.x = long((p1.x - hypot * cos (theta - theta2)) + 0.5);
	p3.y = long((p1.y - hypot * sin (theta - theta2)) + 0.5);


	m_Chart.GetCanvas().GetPen().SetColor(RGB(0, 0, 0));
	m_Chart.GetCanvas().GetPen().SetWidth(1);
	m_Chart.GetCanvas().GetBrush().SetColor(RGB(0, 0, 255));
	m_Chart.GetCanvas().GetBrush().SetBackColor(RGB(0, 0, 255));

	VARIANT pts; // <<<<<<------- How to construct this?
	m_Chart.GetCanvas().Polygon(3, pts);
}

Re: Drawing Polygon on Canvas in OnAfterDraw

Posted: Sat Sep 12, 2020 9:28 am
by 16689453
After some trial and error I found this seems to work...is it correct?

Code: Select all

	VARIANT pts;
	VariantInit(&pts);
	pts.vt = VT_ARRAY|VT_I4;

	SAFEARRAY* psa = SafeArrayCreateVector(VT_I4, 0, 6);
	if (psa != NULL)
	{
		LONG i;
		i = 0; SafeArrayPutElement(psa, &i, &p1.x);
		i = 1; SafeArrayPutElement(psa, &i, &p1.y);
		i = 2; SafeArrayPutElement(psa, &i, &p2.x);
		i = 3; SafeArrayPutElement(psa, &i, &p2.y);
		i = 4; SafeArrayPutElement(psa, &i, &p3.x);
		i = 5; SafeArrayPutElement(psa, &i, &p3.y);
	}

	pts.parray = psa;
	m_Chart.GetCanvas().Polygon(3, pts);
	
	SafeArrayDestroy(psa);	

Re: Drawing Polygon on Canvas in OnAfterDraw

Posted: Mon Sep 14, 2020 1:14 pm
by yeray
Hello,

In the AddArrays example here, we populate arrays in a similar way than what you are doing. So it looks good to me.

- .h:

Code: Select all

class CVCTeeChart5Dlg : public CDialog
{
public:
  //...
  COleSafeArray XValues;
  COleSafeArray YValues;
  //...
- .cpp:

Code: Select all

BOOL CVCTeeChart5Dlg::OnInitDialog()
{
  //...
  DWORD numElements[] = {200000};

  // Create the safe-arrays...
  XValues.Create(VT_R8, 1, numElements);
  YValues.Create(VT_R8, 1, numElements);

  // Initialize them with values...
  long index;
  for(index=0; index<200000; index++) {
      double val = index+((rand()*5)/RAND_MAX);
      XValues.PutElement(&index, &val);
  };
         
  srand(100);

  for(index=0; index<200000; index++) {
      double val = index+rand();
      YValues.PutElement(&index, &val);
  };
  //...