By Bruce Guthrie - Tuesday, March 9, 2010
hello i have a problem that i cannot quite resolve. i have a simple XYZ Scatter line in a 3D chart, i then want to draw a circle, i use a smooth line series for this, at a point on the line, but i want the circlw to be perpendicular to the line. here is some code i tried but i could never quite get the perpendicluar circle, i could get close but not perpendicular. i am sure it is just some basic maths that i am missing. maybe some one out there can point out my error. i draw a basic XYZ scatter line as follows. ' add a header labelDim header As NLabel = NChartControl1.Labels.AddHeader("XY Scatter Line Chart")header.TextStyle.FontStyle = New NFontStyle("Times New Roman", 18, FontStyle.Italic)header.ContentAlignment = ContentAlignment.BottomRight header.Location = New NPointL(New NLength(2, NRelativeUnit.ParentPercentage), New NLength(2, NRelativeUnit.ParentPercentage))NChartControl1.Controller.Tools.Add( New NTrackballTool())' apply predefined projection and lighting'm_Chart.Projection.SetPredefinedProjection(PredefinedProjection.PerspectiveTilted)'m_Chart.LightModel.SetPredefinedLightModel(PredefinedLightModel.NorthernLights)m_Chart = NChartControl1.Charts(0) m_Chart.Axis(StandardAxis.Depth).Visible = Truem_Chart.Enable3D = Truem_Chart.Width = 70 m_Chart.Height = 70 m_Chart.Depth = 70 NChartControl1.Controller.Selection.Add(m_Chart) ' add interlaced stripe to the Y axisDim linearScale As NLinearScaleConfigurator = New NLinearScaleConfigurator()Dim stripStyle As NScaleStripStyle = New NScaleStripStyle(New NColorFillStyle(Color.Beige), Nothing, True, 0, 0, 1, 1)stripStyle.SetShowAtWall(ChartWallType.Back, True)stripStyle.SetShowAtWall(ChartWallType.Left, True)stripStyle.Interlaced = TruelinearScale.StripStyles.Add(stripStyle) m_Chart.Axis(StandardAxis.PrimaryX).ScaleConfigurator = linearScale linearScale.MajorGridStyle.SetShowAtWall(ChartWallType.Back, True)' add the linem_Line = CType(m_Chart.Series.Add(SeriesType.Line), NLineSeries)m_Line.LineSegmentShape = LineSegmentShape.Line m_Line.DataLabelStyle.Visible = Falsem_Line.Legend.Mode = SeriesLegendMode.DataPoints m_Line.InflateMargins = Truem_Line.MarkerStyle.Visible = Truem_Line.BorderStyle.Color = Color.Red m_Line.MarkerStyle.PointShape = PointShape.Cylinder m_Line.MarkerStyle.Width = New NLength(1.5F, NRelativeUnit.ParentPercentage)m_Line.MarkerStyle.Height = New NLength(1.5F, NRelativeUnit.ParentPercentage)m_Line.Name = "Line Series"' add xy valuesFor i As Integer = 1 To 40 Step 5m_Line.Values.Add(i) m_Line.XValues.Add(i) m_Line.ZValues.Add(i) Next' instruct the line series to use x valuesm_Line.UseXValues = Truem_Line.UseZValues = True then on a button click i attmept to draw my circle perpendicular to the line at point 12,12,12 with radius of 2. my line has an angle of 45 degrees. ' add the line m_Line1 = CType(m_Chart.Series.Add(SeriesType.SmoothLine), NSmoothLineSeries)'m_Line1.LineSegmentShape = LineSegmentShape.Linem_Line1.DataLabelStyle.Visible = Falsem_Line1.Legend.Mode = SeriesLegendMode.None m_Line1.InflateMargins = Falsem_Line1.BorderStyle.Color = Color.Blue m_Line1.BorderStyle.Width = New NLength(3)'m_Line1.MarkerStyle.Visible = Falsem_Line1.Name = "Line Series"' instruct the line series to use x valuesm_Line1.UseXValues = Truem_Line1.UseZValues = TrueDim x As Single = 12Dim y As Single = 12Dim z As Single = 12Dim r As Integer = 2Dim inc As Integer = 45' add xy valuesFor i As Integer = 0 To 360 Step 5'm_Line1.Values.Add(y + r * Math.Sin(Math.PI / 180 * i))m_Line1.Values.Add(y + r * Math.Sin(Math.PI / 180 * (inc + i))) m_Line1.XValues.Add(x + r * Math.Cos(Math.PI / 180 * i)) m_Line1.ZValues.Add(z + r * Math.Cos((Math.PI / 180) * (i + 180))) 'm_Line1.ZValues.Add(z + r * Math.Sin((Math.PI / 180) * i)) NextNChartControl1.Refresh() i tried various combinations of X,Y,Z calculations but could never get the perpendicular circle. Regards Bruce
|
By Bruce Guthrie - Wednesday, March 10, 2010
i forgot to add that the line should then pass through the center of the circle with the circle being perpendicular to the line. regards Bruce.
|
By Milen - Wednesday, March 10, 2010
Hi Bruce,
Attached is some VB code that will hopefully solve your problem.
Best Regards, Milen
----------------------------------------------------------------------------
Imports Nevron.GraphicsCore Imports Nevron.Chart Imports Nevron.Chart.WinForm
Public Class Form1 Dim rand As New Random
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim chart As NChart = NChartControl1.Charts(0) chart.Axis(StandardAxis.Depth).Visible = True chart.Enable3D = True chart.BoundsMode = BoundsMode.Fit chart.Width = 60 chart.Height = 60 chart.Depth = 60 chart.Projection.SetPredefinedProjection(PredefinedProjection.Perspective) chart.Wall(ChartWallType.Left).Visible = False chart.Wall(ChartWallType.Back).Visible = False
NChartControl1.Controller.Selection.Add(chart) NChartControl1.Controller.Tools.Add(New NTrackballTool())
Dim axisX As NAxis = chart.Axis(StandardAxis.PrimaryX) Dim axisY As NAxis = chart.Axis(StandardAxis.PrimaryY) Dim axisZ As NAxis = chart.Axis(StandardAxis.Depth)
axisX.View = New NRangeAxisView(New NRange1DD(-10, 50), True, True) axisY.View = New NRangeAxisView(New NRange1DD(-10, 50), True, True) axisZ.View = New NRangeAxisView(New NRange1DD(-10, 50), True, True)
Dim scaleX As NLinearScaleConfigurator = New NLinearScaleConfigurator() scaleX.RoundToTickMin = False scaleX.RoundToTickMax = False axisX.ScaleConfigurator = scaleX
Dim scaleY As NLinearScaleConfigurator = New NLinearScaleConfigurator() scaleY.RoundToTickMin = False scaleY.RoundToTickMax = False axisY.ScaleConfigurator = scaleY
Dim scaleZ As NLinearScaleConfigurator = New NLinearScaleConfigurator() scaleZ.RoundToTickMin = False scaleZ.RoundToTickMax = False axisZ.ScaleConfigurator = scaleZ
CreateBaseLine(0, 0, 0, 40, 20, 35)
End Sub
Private Sub CreateBaseLine(ByVal x1 As Double, ByVal y1 As Double, ByVal z1 As Double, ByVal x2 As Double, ByVal y2 As Double, ByVal z2 As Double) Dim chart As NChart = NChartControl1.Charts(0)
Dim line As New NLineSeries chart.Series.Clear() chart.Series.Add(line)
line.LineSegmentShape = LineSegmentShape.Line line.DataLabelStyle.Visible = False line.Legend.Mode = SeriesLegendMode.None line.InflateMargins = False line.UseXValues = True line.UseZValues = True line.FillStyle = New NColorFillStyle(Color.Crimson) line.BorderStyle.Color = Color.Crimson line.MarkerStyle.Visible = False line.LineSegmentShape = LineSegmentShape.Tube line.LineSize = New NLength(3, NRelativeUnit.ParentPercentage)
Dim marker As New NMarkerStyle marker.Visible = True marker.Width = New NLength(4, NRelativeUnit.ParentPercentage) marker.Height = New NLength(4, NRelativeUnit.ParentPercentage) marker.Depth = New NLength(4, NRelativeUnit.ParentPercentage) marker.AutoDepth = False marker.PointShape = PointShape.Sphere line.MarkerStyles(0) = marker
line.XValues.Add(x1) line.Values.Add(y1) line.ZValues.Add(z1)
line.XValues.Add(x2) line.Values.Add(y2) line.ZValues.Add(z2) End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim chart As NChart = NChartControl1.Charts(0) Dim line As NLineSeries = CType(chart.Series(0), NLineSeries)
Dim ring As New NLineSeries chart.Series.Add(ring) ring.DataLabelStyle.Visible = False ring.MarkerStyle.Visible = False ring.Legend.Mode = SeriesLegendMode.None ring.InflateMargins = False ring.BorderStyle = New NStrokeStyle(New NLength(1), Color.Blue) ring.UseXValues = True ring.UseZValues = True
Dim pointCount As Integer = 25 Dim segmentCount = pointCount - 1 Dim angleStep As Double = (2 * Math.PI) / segmentCount
' calculate unit vector Dim xA As Double = line.XValues(0) Dim yA As Double = line.Values(0) Dim zA As Double = line.ZValues(0)
Dim xN As Double = line.XValues(1) - xA Dim yN As Double = line.Values(1) - yA Dim zN As Double = line.ZValues(1) - zA
Dim length As Double = Math.Sqrt(xN * xN + yN * yN + zN * zN) xN = xN / length yN = yN / length zN = zN / length
Dim dist As Double = rand.NextDouble() * length Dim radius As Double = 2.6
Dim cosB As Double = Math.Sqrt(xN * xN + zN * zN) Dim sinB As Double = yN
Dim gamma As Double = Math.Atan2(zN, xN) Dim cosG As Double = Math.Cos(gamma) Dim sinG As Double = Math.Sin(gamma)
For i = 0 To pointCount - 1 Step 1
Dim alpha As Double = i * angleStep Dim x As Double = 0 Dim y As Double = Radius * Math.Sin(alpha) Dim z As Double = Radius * Math.Cos(alpha)
Dim x1 As Double = cosB * x - sinB * y Dim y1 As Double = sinB * x + cosB * y Dim z1 As Double = z
Dim x2 As Double = cosG * x1 - sinG * z1 Dim y2 As Double = y1 Dim z2 As Double = sinG * x1 + cosG * z1
ring.XValues.Add(xA + xN * dist + x2) ring.Values.Add(yA + yN * dist + y2) ring.ZValues.Add(zA + zN * dist + z2)
Next i
NChartControl1.Refresh()
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim x1 As Double = rand.NextDouble() * 40 Dim y1 As Double = rand.NextDouble() * 40 Dim z1 As Double = rand.NextDouble() * 40
Dim x2 As Double = rand.NextDouble() * 40 Dim y2 As Double = rand.NextDouble() * 40 Dim z2 As Double = rand.NextDouble() * 40
CreateBaseLine(x1, y1, z1, x2, y2, z2)
NChartControl1.Refresh() End Sub
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click NChartControl1.ShowEditor() End Sub End Class
|
By Bruce Guthrie - Wednesday, March 10, 2010
Hello Milen thanks for the code that is exactly what i wanted to do and more. let me try this out on my projetcs and see what i can acheive. Regards Bruce.
|
|