protected override void OnDeviceUpdate(object s, GDIDeviceUpdateArgs e) { Angle += 0.0360 * e.Delta; var SecondPoint = FirstPoint + Length * new DVector2( Math.Cos(Angle * Math.PI / 180), Math.Sin(Angle * Math.PI / 180) ); e.Surface.DrawLine(Color.Red.ToArgb(), FirstPoint, SecondPoint); }
protected override void OnDeviceUpdate(object s, GDIDeviceUpdateArgs e) { Width = (int)e.Width; Height = (int)e.Heigh; double WindowScale; if (Height < Width) { WindowScale = (double)Height / InitialHeight; } else { WindowScale = (double)Width / InitialWidth; } DVector2 pivot = new DVector2(Width / 2, Height / 2); Pen graphPen = new Pen(Brushes.DarkBlue, 2.0f); Pen xAxisPen = new Pen(Brushes.Red, 2.0f); Pen yAxisPen = new Pen(Brushes.Green, 2.0f); if (points == null || PrevApproxLevel != ApproxLevel || PrevAmplitude != Amplitude) { points = ComputePoints(); PrevApproxLevel = ApproxLevel; PrevAmplitude = Amplitude; Console.WriteLine("Recomputed!"); } // ----- double RotationAngleRad = RotationAngle / 180.0 * Math.PI; DVector2 center = new DVector2(pivot.X + Offset.X + ShiftX, pivot.Y - Offset.Y - ShiftY); DrawAxis(e.Graphics, xAxisPen, RotationAngleRad, center, Math.Abs(Scale.X), WindowScale, false, 180.0); DrawAxis(e.Graphics, yAxisPen, RotationAngleRad + Math.PI / 2.0, center, Math.Abs(Scale.Y), WindowScale, true, 90.0); e.Graphics.FillEllipse(Brushes.Black, new Rectangle((int)(center.X - centerCircleSize), (int)(center.Y - centerCircleSize), centerCircleSize * 2, centerCircleSize * 2)); DVector2 prevP = new DVector2(pivot); bool firstPointComputed = false; foreach (var p in points) { DVector2 scaledP = (new DVector2(p.X, -p.Y)).Multiply(Scale * WindowScale); double sin = Math.Sin(RotationAngleRad); double cos = Math.Cos(RotationAngleRad); DVector2 rotatedP = VecRotate(scaledP, RotationAngleRad); DVector2 transformedP = new DVector2(rotatedP.X + Offset.X + ShiftX + pivot.X, rotatedP.Y + -Offset.Y - ShiftY + pivot.Y); if (firstPointComputed) { e.Graphics.DrawLine(graphPen, prevP.X, prevP.Y, transformedP.X, transformedP.Y); } prevP = transformedP; firstPointComputed = true; } e.Graphics.DrawString(LabelTxt, new Font("Arial", 15f), Brushes.Black, 10f, 10f); }
// Перегружаем главный метод. По назначению он анологичен методу OnPaint() и предназначен // для формирования изображения. Однако в отличии от оного он выполняется паралелльно в // другом потоке и вызывается непрерывно. О текущей частоте вызовов можно судить по // счетчику числа кадров в заголовке окна (конечно в режиме отладки скорость падает). // Помимо прочего он обеспечивает более высокую скорость рисования и не мерцает. protected override void OnDeviceUpdate(object s, GDIDeviceUpdateArgs e) { double sx = ShiftX; // С точки зрения производительности часто используемые свойства лучше double sy = ShiftY; // сохранить в локальные переменные или обращаться к связаным с ними полям double lx1 = sx + e.Width / 2, ly1 = sy + e.Heigh / 2, lx2 = e.Width / 4, ly2 = e.Heigh / 4; double[] txy = new double[] { 0, -60, -40, +20, +50, +40 }; if (EnableRot) { angle += 0.1 * e.Delta; } var sinf = Math.Sin(angle * Math.PI / 180); var cosf = Math.Cos(angle * Math.PI / 180); for (int i = 0; i < 3; ++i) { var x = txy[2 * i]; var y = txy[2 * i + 1]; txy[2 * i] = x * cosf - y * sinf + e.Width / 2 + sx; txy[2 * i + 1] = x * sinf + y * cosf + e.Heigh / 2 - sy; } if (DrawMode == DrawingMode.GFX) { // Стандартный способ отображения при помощи штатных средств // + Больше гибкость, например можно задать толщину линий // + Для треугольников есть сглаживание for (double fi = 0; fi < 2 * Math.PI; fi += Math.PI / 32) { e.Graphics.DrawLine(Pens.GhostWhite, lx1, ly1, +sx + lx1 + lx2 * Math.Cos(fi) - ly2 * Math.Sin(fi), -sy + ly1 + lx2 * Math.Sin(fi) + ly2 * Math.Cos(fi)); } e.Graphics.FillPolygon(Brushes.Chocolate, new PointF[] { new PointF((float)txy[0], (float)txy[1]), new PointF((float)txy[2], (float)txy[3]), new PointF((float)txy[4], (float)txy[5]) }); e.Graphics.FillRectangle(Brushes.DodgerBlue, 9, 35, 200, 12); } else { // Собственная реализация отображения (CGLabPlatform.Drawing) // + Выше скорость работы (у меня разница более чем в 5 раз) // + Лучшее качество сглаженных прямых // + Градиентная закраска треугольника (т.е. задание различных // цветов для каждой из верши), что будет востребаванно for (double fi = 0; fi < 2 * Math.PI; fi += Math.PI / 32) { e.Surface.DrawLine(Color.GhostWhite.ToArgb(), lx1, ly1, +sx + lx1 + lx2 * Math.Cos(fi) - ly2 * Math.Sin(fi), -sy + ly1 + lx2 * Math.Sin(fi) + ly2 * Math.Cos(fi)); } e.Surface.DrawTriangle(Color.Chocolate.ToArgb(), txy[0], txy[1], txy[2], txy[3], txy[4], txy[5]); e.Surface.FillRectangle(Color.DodgerBlue.ToArgb(), 10, 35, 200, 12); } // Вторая реализация отображения осуществляется путем прямого доступа // к поверхности связанной с объектом Graphics. Поэтому возможно // одновременное использование обоих методов работы с изображением. // Так вне зависимости от выбранного метода, используется объект // Graphics для вывода текста. e.Graphics.DrawString(LabelTxt, new Font("Arial", 15f), Brushes.Chartreuse, 10f, 10f); }
protected override void OnDeviceUpdate(object s, GDIDeviceUpdateArgs e) { if (PrevApproxLevel != ApproxLevel) { ComputeObject(); PrevApproxLevel = ApproxLevel; } if (e.Heigh < e.Width) { WindowScale = (double)e.Heigh / InitialHeight; } else { WindowScale = (double)e.Width / InitialWidth; } switch (ProjMode) { case ProjectionMode.FR: rotX = Rotation.X; rotY = Rotation.Y; rotZ = Rotation.Z; break; case ProjectionMode.ISO: rotX = -35.0; rotY = -45.0; rotZ = 0.0; break; case ProjectionMode.ORT_F: rotX = 0.0; rotY = 0.0; rotZ = 0.0; break; case ProjectionMode.ORT_L: rotX = 0.0; rotY = 90.0; rotZ = 0.0; break; case ProjectionMode.ORT_T: rotX = -90.0; rotY = 0.0; rotZ = 0.0; break; } // compute transformation ( scale and rotation ) matrix DMatrix4 mat = DMatrix4.Identity; double scale = 100.0; RotateMatrix(ref mat, rotX, rotY, rotZ); ScaleMatrix(ref mat, scale * Scale.X * WindowScale, scale * Scale.Y * WindowScale, scale * Scale.Z * WindowScale); // transform verticis of object foreach (Vertex v in Vertecis) { v.Point = mat * v._Point; } Polygons.QuickSort(p => p.Vertex.Average(v => v.Point.Z)); // draw main object foreach (Polygon p in Polygons) { p.Normal = CrossProduct(p.Vertex[0].Point - p.Vertex[1].Point, p.Vertex[1].Point - p.Vertex[2].Point); p.Normal /= p.Normal.GetLength(); if (p.Normal.Z > 0) { DrawPolygonFixGaps2(p, e.Graphics, e.Width, e.Heigh); } } // some optional features foreach (Polygon p in Polygons) { if (p.Normal.Z > 0) { if (EnableNormals) { DrawNormal(p, e.Graphics, e.Width, e.Heigh); } if (EnableVertexNumbers) { DrawVertexNumbers(p, e.Graphics, e.Width, e.Heigh); } } } // Drawing axis (in the right lower corner) DVector4 ox = mat * (new DVector4(1.0, 0.0, 0.0, 0.0)); DVector4 oy = mat * (new DVector4(0.0, 1.0, 0.0, 0.0)); DVector4 oz = mat * (new DVector4(0.0, 0.0, 1.0, 0.0)); ox = ox / ox.GetLength() * 50.0 * WindowScale; oy = oy / oy.GetLength() * 50.0 * WindowScale; oz = oz / oz.GetLength() * 50.0 * WindowScale; DVector4 pos = new DVector4(e.Width - 70.0 * WindowScale, e.Heigh - 70.0 * WindowScale, 0.0, 0.0); DrawAxis(e.Graphics, ox, oy, oz, pos); }