For bugs and new features, use the issue tracker located at GitHub.
Also try the chat room!

3D Piping
michaeldjackson wrote at 2012-06-24 18:07:
Awesome job on Helix3D.
I'm searching for guidance or best practices on a project I'm working on.
In my application, I have an ObservableCollection of pipe segments, which describe length, diameter, inclination from vertical and azimuth from north. I need to iterate thru this collection (note: collection will number in the hundreds and sometimes thousands of segments), and build the pipe system, one segment at a time. Each 3D pipe segment will eventually be re-colored according to some calculation and hopefully each pipe segment object will contain the numerical results of the calculations performed on each segment. I will need to click or hover over the segment in the 3D view, and display the numerical results per segment in a wpf control.
Anyone have thoughts or suggestions?
Thanks in advance.
objo wrote at 2012-06-25 08:33:
You should add the pipes to the 3D model yourself (I don't think ItemsControl will work in a Viewport3D), and modify the 3D model when the observable collection changes.
I would suggest the following
- Use a ModelUIElement3D for each pipe to make the segments clickable.
- Use the HelixToolkit's MeshBuilder to create the pipe geometry (as in PipeVisual3D).
- Create a Transform3D to set the position and orientation (you can also set the start and endpoints, but if you use a transform you can easily change position/orientation later).
- Create a Material to define the color (see HelixToolkit's MaterialHelper.CreateMaterial)
If performance is not good enough, you should combine all pipes into a common geometry and use texture coordinates and a gradient brush material to set the colors.
http://msdn.microsoft.com/en-us/library/system.windows.media.media3d.modeluielement3d.aspx
Use of the MeshBuilder:
var builder = new MeshBuilder(false,false);
builder.AddPipe(this.Point1, this.Point2, this.InnerDiameter, this.Diameter, this.ThetaDiv);
return builder.ToMesh();
(returns a MeshGeometry3D)
dturvey wrote at 2012-06-25 11:22:
Hi,
I am also trying to add 1000+ Visual3D objects to a viewport and would be interested in the most efficient way to do this.
I am currently binding to an observable collection as shown in the MVVM demo and just adding each Visual3D individually in a loop. This is firing a collection changed event for each call to the Add method. Is there a better way accomplish a bulk add?
thanks
objo wrote at 2012-06-26 05:54:
See http://msdn.microsoft.com/en-us/library/bb613553.aspx
Combine objects that can share the same material.
Yes, you should avoid the collection change event when initializing your collection - don't bind it to the visual tree before it has been initialized.
michaeldjackson wrote at 2012-06-26 20:34:
Thanks for the reply. I have another question, though.
As mentioned in my initial post, I need the ability to hover over or clicka pipe segment in order to obtain properties of that segment, ie: length, temperature, pressure, etc. I also need to draw a sem-transparent 3D element (basically another pipe segment) around the segment, thus creating a pipe within a pipe. However, I need to "click" the inner pipe to obtain it's properties. The outer pipe will no doubt hinder hit-test on the inner pipe, correct? So, I'm wondering how to select the inner pipe when clicking. Maybe 1) propogate the inner pipes properties to the outer pipe or 2) allow a pipe segment to have children pipe segments.
Any suggestions?
BTW, I am just barely getting started with Helix 3D.
Thanks.
objo wrote at 2012-06-27 14:42:
See http://msdn.microsoft.com/en-us/library/ms608753.aspx and http://msdn.microsoft.com/en-us/library/system.windows.media.media3d.rayhittestresult.aspx
These will give you all hits in the model!

HelixViewport3D create and select vertex
Is it possible to create and move vertexes in the BillbardVisual3D? How?
I've been googleing and making tests but I've had no luck.
My thanks in advanced.

Is SharpDx Fork ongoing?
eonxxx wrote at 2014-03-02 00:18:
is there a chance that helix sharpDx developement is ongoing in next time.
Or could you offer a packed .dll, like helixtoolkit itself?
best regards
eonxxx
eonxxx wrote at 2014-03-02 00:28:
thanks for sharing!
eonxxx

Multi Touch Support
praveenv4k wrote at 2012-03-24 06:37:
Can multitouch gestures be realized with Helix 3D toolkit?
objo wrote at 2012-04-03 01:28:
I implemented pinch-zoom and rotate/pan events last autumn. See the code for handling of the manipulation events in the CameraController class.
It was tested on a Samsung tablet with windows 8, seemed to work ok!
Other gestures implemented:
two-finger tap -> zoom extents
holdenter -> change 'look-at' point

[Solved] (converted) VB.NET version of Flights Demo looks screwy! :)
BogusException wrote at 2014-07-04 21:01:
I like this Helix library a LOT. So much that I converted one of the demos (Flights) as-is to VB.NET via InstantVB & my modest C# abilities. I got the C# version to compile in a separate project after moving files around & such, so I know what things should look like:
So when I converted it, I was a little surprised to see:
I'm going through line-by-line, and i honestly can't figure out where the error is. When stepping through FlightVisual3D(), all the variables seem sane... Nothing shows up in the grid I/O section to the left, in fields, rows, or pull-downs, but I don't mind.
My end goal: I just want to supply a method with points A & B, and have this (modified) demo draw a line between those 2 points. The fact that the line 'arcs' over the surface is exceptionally desirable...
Could someone tell me why this is barfing? I'm hoping one of you can tell just by looking at the output above...
It seems to me that the likely culprit is FlightVisual3D, which draws the line & 2 spheres. In hopes that one of you experts can see immediately the issue, here is FlightVisual3D():
Imports System
Imports System.Windows.Media
Imports System.Windows.Media.Media3D
Imports HelixToolkit.Wpf
Namespace toag.graphics
' http://www.sasems.port.se/Emissioncalc.cfm
' http://www.partow.net/miscellaneous/airportdatabase/
Public Class FlightVisual3D
Inherits ModelVisual3D
Public Shared EarthRadius As Double = 6371 ' km
Public Shared DefaultCruisingAltitude As Double = 300 ' km // real value is 12.5...
Public Shared DefaultTakeoffLength As Double = 200
Public Shared DefaultCruisingSpeed As Double = 890 ' km/h
Public Property CabinFactor() As Double
''' <summary>
''' Gets the estimated CO2 emission per passenger for the given cabin factor.
''' </summary>
Public ReadOnly Property CO2() As Double
Get
Return 24 + Distance * 0.0535 ' km
End Get
End Property
Public Sub New(ByVal p1 As Point3D, ByVal p2 As Point3D)
Dim tube = New TubeVisual3D()
' tube.Material = MaterialHelper.CreateMaterial(Color.FromArgb(80, 255, 255, 255)); // Materials.Yellow;
tube.Fill = New SolidColorBrush(Color.FromArgb(80, 255, 255, 255))
Children.Add(tube)
Children.Add(New SphereVisual3D() With {.Center = p1, .Radius = 100, .Material = Materials.Green})
Children.Add(New SphereVisual3D() With {.Center = p2, .Radius = 100, .Material = Materials.Red})
Dim lat1, lon1, lat2, lon2 As Double
PointToLatLon(p1, lat1, lon1)
PointToLatLon(p2, lat2, lon2)
[From] = String.Format("{0:0.00} {1:0.00}", lat1, lon1)
[To] = String.Format("{0:0.00} {1:0.00}", lat2, lon2)
CruisingSpeed = DefaultCruisingSpeed
Dim cruisingRadius As Double = EarthRadius + DefaultCruisingAltitude
Dim takeoffLength As Double = DefaultTakeoffLength
Dim groundRadius As Double = EarthRadius
Const tubeDiameter As Double = 60
Dim o = New Point3D(0, 0, 0)
Dim v1 = p1 - o
Dim v2 = p2 - o
Dim z = Vector3D.CrossProduct(v1, v2)
Dim x = v1
Dim y = Vector3D.CrossProduct(x, z)
x.Normalize()
y.Normalize()
Dim v2X As Double = Vector3D.DotProduct(v2, x)
Dim v2Y As Double = Vector3D.DotProduct(v2, y)
Dim v2A As Double = Math.Atan2(v2Y, v2X)
Const n As Integer = 100
Dim pts = New Point3DCollection()
Dim da As Double = v2A / (n - 1)
'INSTANT VB NOTE: The variable distance was renamed since Visual Basic does not handle local variables named the same as class members well:
Dim distance_Renamed As Double = cruisingRadius * Math.Abs(v2A)
Dim landingLength As Double = takeoffLength
Dim l As Double = 0
For i As Integer = 0 To n - 1
Dim a As Double = i * da
Dim v As Vector3D = x * Math.Cos(a) + y * Math.Sin(a)
Dim r As Double = cruisingRadius
'if (l < takeoffLength)
'{
' r = groundRadius + Math.Sin(Math.PI/2*l/takeoffLength)*(cruisingRadius - groundRadius);
'}
'if (l > distance - landingLength)
'{
' r = groundRadius + Math.Sin(Math.PI/2*(distance - l)/takeoffLength)*(cruisingRadius - groundRadius);
'}
r = groundRadius + Math.Sin(CLng(Math.PI * i) \ (n - 1)) * (cruisingRadius - groundRadius)
Dim p = o + v * r
' Children.Add(new SphereVisual3D() { Center = p, Radius = 60, Material = Materials.Gray});
pts.Add(p)
l += Math.Abs(cruisingRadius * da)
Next i
tube.Diameter = tubeDiameter
tube.ThetaDiv = 16
tube.Path = pts
Distance = distance_Renamed
End Sub
Public Property [From] As String
Public Property [To] As String
Public ReadOnly Property Time() As String
Get
Dim totalHours As Double = Distance / CruisingSpeed
Dim hours As Double = CInt(Math.Truncate(totalHours))
Dim minutes = CInt(Math.Truncate(Math.Round((totalHours - hours) * 60)))
Return String.Format("{0}h{1:00}m", hours, minutes)
End Get
End Property
Public Property CruisingSpeed() As Double
Public Property Distance() As Double
Public Shared Sub PointToLatLon(ByVal pt As Point3D, <System.Runtime.InteropServices.Out()> ByRef lat As Double, <System.Runtime.InteropServices.Out()> ByRef lon As Double)
lon = Math.Atan2(pt.Y, pt.X) * 180 / Math.PI
lon += 180
If lon > 180 Then
lon -= 360
End If
If lon < -180 Then
lon += 360
End If
Dim a As Double = Math.Sqrt(pt.X * pt.X + pt.Y * pt.Y)
lat = Math.Atan2(pt.Z, a) * 180 / Math.PI
End Sub
Public Shared Function LatLonToPoint(ByVal latitude As Double, ByVal longitude As Double) As Point3D
longitude -= 180
latitude = latitude / 180 * Math.PI
longitude = longitude / 180 * Math.PI
Return New Point3D(EarthRadius * Math.Cos(latitude) * Math.Cos(longitude), EarthRadius * Math.Cos(latitude) * Math.Sin(longitude), EarthRadius * Math.Sin(latitude))
End Function
Public Overrides Function ToString() As String
Return String.Format("Distance: {0:0} km, Time: {1}", Distance, Time)
End Function
End Class
End Namespace
Thank you SO much in advance!pat
:)
BogusException wrote at 2014-07-05 00:51:
I added a bit of debugging after the pts collection (Dim pts = New Point3DCollection) was completed:
[...]
pts.Add(p)
l += Math.Abs(cruisingRadius * da)
Next i
tube.Diameter = tubeDiameter
tube.ThetaDiv = 16
tube.Path = pts
Dim count As Integer = 1
For Each pt In pts
log.DebugEx("[{3}] pt.X: {0} Y: {1} Z: {2}", pt.X, pt.Y, pt.Z, count)
count += 1
Next
[...] Using this, I created the following flight:
I'm still figuring out the coordinate system used, but by going through the output; 100 points in the collection, defining the tube's path:
[2014-07-04 18:26:57.809002][DEBUG] [1] pt.X: 1370.08319161887 Y: -275.654794803274 Z: 6215.82878481586 [CallingMethod: vASA.toag.graphics.FlightVisual3D..ctor][LineNumber: 118]
[2014-07-04 18:26:57.810002][DEBUG] [2] pt.X: 1356.17882894272 Y: -271.360435069487 Z: 6219.06612749908 [CallingMethod: vASA.toag.graphics.FlightVisual3D..ctor][LineNumber: 118]
[2014-07-04 18:26:57.811002][DEBUG] [3] pt.X: 1342.26704035452 Y: -267.064589470649 Z: 6222.26941697551 [CallingMethod: vASA.toag.graphics.FlightVisual3D..ctor][LineNumber: 118]
[2014-07-04 18:26:57.811002][DEBUG] [4] pt.X: 1328.34790202985 Y: -262.767281529153 Z: 6225.43863570517 [CallingMethod: vASA.toag.graphics.FlightVisual3D..ctor][LineNumber: 118]
[...] things go fine, with X, Y, and Z gradually changing (at ground level, though), then:
[2014-07-04 18:26:57.824003][DEBUG] [31] pt.X: 950.032355774276 Y: -146.273353461398 Z: 6298.06983361165 [CallingMethod: vASA.toag.graphics.FlightVisual3D..ctor][LineNumber: 118]
[2014-07-04 18:26:57.825003][DEBUG] [32] pt.X: 935.938504042294 Y: -141.944678989743 Z: 6300.27871008557 [CallingMethod: vASA.toag.graphics.FlightVisual3D..ctor][LineNumber: 118]
[2014-07-04 18:26:57.825003][DEBUG] [33] pt.X: 958.366032652662 Y: -143.068023744017 Z: 6552.17831581306 [CallingMethod: vASA.toag.graphics.FlightVisual3D..ctor][LineNumber: 118]
[2014-07-04 18:26:57.826003][DEBUG] [34] pt.X: 943.70315769276 Y: -138.566240638758 Z: 6554.40297367252 [CallingMethod: vASA.toag.graphics.FlightVisual3D..ctor][LineNumber: 118]
[...] and the other anomaly (a bump in the tube, what the mouse is pointing to in the pic above) is 2/3 of the way through:
[2014-07-04 18:26:57.845004][DEBUG] [62] pt.X: 531.338798828905 Y: -12.29843297621 Z: 6602.08318817452 [CallingMethod: vASA.toag.graphics.FlightVisual3D..ctor][LineNumber: 118]
[2014-07-04 18:26:57.845004][DEBUG] [63] pt.X: 516.558770422004 Y: -7.78466762429962 Z: 6603.26290782227 [CallingMethod: vASA.toag.graphics.FlightVisual3D..ctor][LineNumber: 118]
[2014-07-04 18:26:57.846004][DEBUG] [64] pt.X: 503.317423762062 Y: -3.28090808341213 Z: 6624.69592610124 [CallingMethod: vASA.toag.graphics.FlightVisual3D..ctor][LineNumber: 118]
[2014-07-04 18:26:57.847004][DEBUG] [65] pt.X: 488.486396361165 Y: 1.24678476874656 Z: 6625.80672769894 [CallingMethod: vASA.toag.graphics.FlightVisual3D..ctor][LineNumber: 118]
[...]
Any help narrowing down which calculation(s) are suspect would be greatly appreciated...
TIA!
BogusException wrote at 2014-07-05 05:14:
You know what they say: "If you want to find an answer, ask a bunch of people"
Ends up this line is the culprit:
r = groundRadius + Math.Sin(Math.PI * i \ (n - 1)) * (cruisingRadius - groundRadius)
in VB.NET, there are more math operators, and while a forward slash (/) is floating point division, a backslash () is for integer division, returning an integer.
So the correct translation would be:
r = groundRadius + Math.Sin(Math.PI * i / (n - 1)) * (cruisingRadius - groundRadius)
And being that the errors were where they were, I kind of figured it has something to do with the radians conversion in the Haversine base calculations.
For those playing at home, this is the version of the New() sub on FlightVisual3D that works the way the C# one does:
Public Sub New(ByVal p1 As Point3D, ByVal p2 As Point3D)
Dim tube = New TubeVisual3D
tube.Fill = New SolidColorBrush(Color.FromArgb(80, 255, 125, 125))
Children.Add(tube)
Children.Add(New SphereVisual3D() With {.Center = p1, .Radius = 100, .Material = Materials.Green})
Children.Add(New SphereVisual3D() With {.Center = p2, .Radius = 100, .Material = Materials.Red})
Dim lat1, lon1, lat2, lon2 As Double
PointToLatLon(p1, lat1, lon1)
PointToLatLon(p2, lat2, lon2)
[From] = String.Format("{0:0.00} {1:0.00}", lat1, lon1)
[To] = String.Format("{0:0.00} {1:0.00}", lat2, lon2)
CruisingSpeed = DefaultCruisingSpeed
Dim cruisingRadius As Double = EarthRadius + DefaultCruisingAltitude
Dim takeoffLength As Double = DefaultTakeoffLength
Dim groundRadius As Double = EarthRadius
Const tubeDiameter As Double = 60
Dim o = New Point3D(0, 0, 0)
Dim v1 = p1 - o
Dim v2 = p2 - o
Dim z = Vector3D.CrossProduct(v1, v2)
Dim x = v1
Dim y = Vector3D.CrossProduct(x, z)
x.Normalize()
y.Normalize()
Dim v2X As Double = Vector3D.DotProduct(v2, x)
Dim v2Y As Double = Vector3D.DotProduct(v2, y)
Dim v2A As Double = Math.Atan2(v2Y, v2X)
Const n As Integer = 100
Dim pts = New Point3DCollection
Dim da As Double = v2A / (n - 1)
Dim distance_Renamed As Double = cruisingRadius * Math.Abs(v2A)
Dim landingLength As Double = takeoffLength
Dim l As Double = 0
For i As Integer = 0 To n - 1
Dim a As Double = i * da
Dim v As Vector3D = x * Math.Cos(a) + y * Math.Sin(a)
Dim r As Double = cruisingRadius
r = groundRadius + Math.Sin(Math.PI * i / (n - 1)) * (cruisingRadius - groundRadius)
Dim p = o + v * r
pts.Add(p)
l += Math.Abs(cruisingRadius * da)
Next i
tube.Diameter = tubeDiameter
tube.ThetaDiv = 16
tube.Path = pts
Distance = distance_Renamed
End Sub
...the _Renamed variables is just InstantVB's way of saying we need to name variables in a less confusing way...
It never fails: As soon as you ask a forum, the answer pops up... :)

Loading issue of SharpDX on XBAP
VishwaPrasad wrote at 2014-07-29 14:47:
I am using the Helix SharpDX on XBAP.
It shows the error "Unable to find [sharpdx_direct3d11_effects_x86.dll] in the PATH" on runtime,
I have copied this path to bin, but still issues persist.
Can anyone help me to resolve this issue.
Thanks
Vishwa

SharpDX Transparency status
First I would like to congratulate you on this framework. I find it easy to use and quite complete.
I'm currently using the WPF 3D version of Helix but I'm hitting its limit. Mainly with wireframe rendering and transparency.
I considering switching to Sharp DX version of Helix as the API is similar. But before switching, I would like to know the status of transparency in this version. Is the sorting order now correct ?
Also do you have in mind any immediate drawback of using the Sharp DX version ?
Thanks you.

Strange rendering behavior of BillboardTextVisual3D if an object is created during view rotation
3dfx_IceFire wrote at 2014-03-04 10:29:
To improve the usability of the diagram the position of the axis designation change when the diagram is rotated to ensure the user can always see it.
I am using the Viewport3D.Camera.Changed event to calculate the current camera angle and trigger an update of the coordinate system axis if neccessary. The axis itself is a class which inherits from ModelVisual3D and contains several BillboardTextVisual3D objects as children. Each axis provides a function which recreates the Billboard objects and adds them as childs to itself:
public void UpdateModel()
{
this.Content = null;
this.Children.Clear();
ModelVisual3D labelTextGroup = new ModelVisual3D();
if (0 == intervals)
{
return;
}
var axesMeshBuilder = new MeshBuilder();
var path = new List<Point3D>();
path.Add(new Point3D(0.0, 0.0, 0.0));
path.Add((Point3D)((double)intervals * Direction));
axesMeshBuilder.AddTube(path, LineThickness, 4, true);
labelTextGroup.Children.Add(new BillboardTextVisual3D()
{
Text = Caption,
Position = (Point3D)((double)intervals * 0.5 * Direction + 3.0 * DescriptionOrientation),
FontFamily = new FontFamily("Courier New"),
FontSize = this.fontSize,
Background = Brushes.White
});
for (int i = 0; i <= intervals; ++i)
{
// render description 3D label
double current = begin + (double)i * intervalSize;
labelTextGroup.Children.Add(new BillboardTextVisual3D()
{
Text = current.ToString(),
Position = (Point3D)((double)i * Direction + (FontSize * 0.07) * DescriptionOrientation),
FontFamily = new FontFamily("Courier New"),
FontSize = this.fontSize,
Background = Brushes.White
});
}
this.Children.Add(labelTextGroup);
GeometryModel3D axesModel = new GeometryModel3D(axesMeshBuilder.ToMesh(), Materials.Black);
this.Content = axesModel;
}
The problem which occurs now is that if I rotate the 3d plot in such a way that the position of the axis designation changes while the model is still in rotation due to its simulated inertia after I release the mouse button, the billboard objects go haywire
(see my screenshot).Left side is normal and how it is desired, right side is how it looks like after I rotated the object a bit around. It is interesting that the problem does not occur if I am still pressing the mouse button while the axis position changes.
I am using the latest version of Helix 3D Toolkit, C#, .NET 4. Let me know if you need more parts of my source code.
If I am using a BillboardTextGroupVisual3D object the problem does not occur.
Customer support service by UserEcho