private PolyLineVisual3D CreatePositionMarker(Point position, Color color) { var polyLineVisual3D = new PolyLineVisual3D() { Positions = new Point3DCollection(5), LineColor = color, LineThickness = 1, }; UpdatePositionMarker(polyLineVisual3D, position); MarkerLinesVisual3D.Children.Add(polyLineVisual3D); return(polyLineVisual3D); }
private void UpdatePositionMarker(PolyLineVisual3D polyLineVisual3D, Point position, double zPos = 0.5) { var markerPositions = polyLineVisual3D.Positions; markerPositions.Clear(); // Reuse existing Point3DCollection double halfSize = _positionMarkerHalfSize; double x = position.X; double y = position.Y; double x1 = x - halfSize; double y1 = y - halfSize; double x2 = x + halfSize; double y2 = y + halfSize; markerPositions.Add(new Point3D(x1, y1, zPos)); // Set z to 0.5 to show marker lines above other lines markerPositions.Add(new Point3D(x2, y1, zPos)); markerPositions.Add(new Point3D(x2, y2, zPos)); markerPositions.Add(new Point3D(x1, y2, zPos)); markerPositions.Add(new Point3D(x1, y1, zPos)); // Close the rectangle with duplicating the first position }
public TwoDimensionalCameraLineEditor() { InitializeComponent(); MouseCameraControllerInfo1.AddCustomInfoLine(0, MouseCameraController.MouseAndKeyboardConditions.LeftMouseButtonPressed, "Create new line"); // NOTE: TwoDimensionalCamera class is available with full source in this samples project in the Common folder. // Create an instance of TwoDimensionalCamera. // TwoDimensionalCamera will internally create a TargetPositionCamera and MouseCameraController (when mouseEventsSourceElement is not null). // They will be used to show the 2D scene. _twoDimensionalCamera = new TwoDimensionalCamera(MainDXViewportView, mouseEventsSourceElement: ViewportBorder, // if mouseEventsSourceElement is null, then MouseCameraController will not be created by TwoDimensionalCamera useScreenPixelUnits: false, // when false, then the size in device independent units is used (as size of DXViewportView); when true size in screen pixels is used (see SharpHorizontalAndVerticalLines sample) coordinateSystemType: TwoDimensionalCamera.CoordinateSystemTypes.CenterOfViewOrigin) { MoveCameraConditions = MouseCameraController.MouseAndKeyboardConditions.RightMouseButtonPressed, QuickZoomConditions = MouseCameraController.MouseAndKeyboardConditions.LeftMouseButtonPressed | MouseCameraController.MouseAndKeyboardConditions.RightMouseButtonPressed, ShowCameraLight = ShowCameraLightType.Always, IsMouseAndTouchZoomEnabled = true, }; // You can access the create TargetPositionCamera with UsedCamera property // and MouseCameraController with UsedMouseCameraController property. MouseCameraControllerInfo1.MouseCameraController = _twoDimensionalCamera.UsedMouseCameraController; // If we want to use LeftMouseButton for mouse movement, then we can also start new line with the same button with setting MouseMoveThreshold: //// Set MouseMoveThreshold so that mouse move starts after the mouse is moved //// for at least 3 pixels. This way we can use mouse click to start / end line drawing. //_twoDimensionalCamera.UsedMouseCameraController.MouseMoveThreshold = 3; _twoDimensionalCamera.CameraChanged += delegate(object sender, EventArgs args) { // When zoom is changed, we need to update all line markers if (!MathUtils.IsSame(_lastZoomFactor, _twoDimensionalCamera.ZoomFactor)) { // Update line markers size (we want that at each zoom level their WPF size is _positionMarkerWpfSize _positionMarkerHalfSize = _twoDimensionalCamera.GetViewSizeFromWpfSize(_positionMarkerWpfSize) * 0.5; if (double.IsNaN(_snappedViewPosition.X)) // Check if _snappedViewPosition is actually set { return; } // Reuse last position var mousePosition = _twoDimensionalCamera.ToWpfPosition(_snappedViewPosition); CheckPositionMarkers(mousePosition, updateExistingPositionMarkers: true); // _positionMarkerHalfSize is changed so we need to update all shown position markers _lastZoomFactor = _twoDimensionalCamera.ZoomFactor; } }; _twoDimensionalCamera.UsedMouseCameraController.CameraMoveStarted += delegate(object sender, EventArgs args) { _isMouseButtonPressed = false; // when we started mouse camera movement, we need to prevent creating the line when the mouse button is released }; _twoDimensionalCamera.UsedMouseCameraController.CameraQuickZoomStarted += delegate(object sender, EventArgs args) { _isMouseButtonPressed = false; // when we started quick zoom, we need to prevent creating the line when the mouse button is released }; // We store lines in our List of Points. // The main purpose of this is that we can have a very fast access to line positions. // (if we would read the Positions from MultiLineVisual3D this would be much slower because accessing DependencyProperties and Point3DCollection is very slow). _allPositions = new List <Point>(); // _positionMarkers is a list that stores all created line markers. The size of array is the same as the size of _allPositions _positionMarkers = new List <PolyLineVisual3D>(); // One MultiLineVisual3D will show fully created 3D lines (this is the much faster then creating individual LineVisual3D objects) _multiLineVisual3D = new MultiLineVisual3D() { Positions = new Point3DCollection(), LineColor = Colors.Black, LineThickness = 1 }; MainViewport.Children.Add(_multiLineVisual3D); // _creatingLine will show the line that is currently being created - user has not placed the end position yet. _creatingLine = new LineVisual3D() { LineColor = Colors.Gray, LineThickness = 1, IsVisible = false }; MainViewport.Children.Add(_creatingLine); // _snappedPositionMarker will be shown over standard gray position marker and will indicate with its black color that mouse position is snapped to the marked position. _snappedPositionMarker = new PolyLineVisual3D() { Positions = new Point3DCollection(5), LineColor = Colors.Black, LineThickness = 1, IsVisible = false }; MainViewport.Children.Add(_snappedPositionMarker); _positionMarkerHalfSize = _twoDimensionalCamera.GetViewSizeFromWpfSize(_positionMarkerWpfSize) * 0.5; AddAxisLines(); AddRandomLines(10); _snappedViewPosition = new Point(double.NaN, double.NaN); // Mark as invalid // We use ViewportBorder to get our mouse events ViewportBorder.MouseLeftButtonDown += delegate(object o, MouseButtonEventArgs args) { _isMouseButtonPressed = true; // we will start the line on mouse up }; ViewportBorder.MouseLeftButtonUp += delegate(object sender, MouseButtonEventArgs args) { if (!_isMouseButtonPressed) { return; } if (_creatingLine.IsVisible) { CompleteNewLine(); } else { StartNewLine(_snappedViewPosition); } _isMouseButtonPressed = false; }; ViewportBorder.MouseMove += delegate(object o, MouseEventArgs args) { var mousePosition = args.GetPosition(ViewportBorder); CheckPositionMarkers(mousePosition, updateExistingPositionMarkers: false); if (_creatingLine.IsVisible) { UpdateLastLinePosition(_snappedViewPosition); } }; this.Unloaded += delegate(object sender, RoutedEventArgs args) { MainDXViewportView.Dispose(); }; }
private void CreateShapesSample() { // // First create a few lines // for (int i = 0; i < 5; i++) { // 2D coordinates of the line double x1 = -300; double y1 = -50 + i * 20; double x2 = -250; double y2 = i * 20; var lineVisual3D = new LineVisual3D() { // Because we use 3D engine to show 2D lines, we need to convert 2D coordinates to 3D coordinates. // This is done with setting Z to 0 (but we could use that to move some lines or shapes in front of the other lines). StartPosition = new Point3D(x1, y1, 0), EndPosition = new Point3D(x2, y2, 0), LineColor = Colors.Black, LineThickness = i + 1 }; RootLinesVisual3D.Children.Add(lineVisual3D); } // // Create a polyline // var polygonPositions = new Point3DCollection(new Point3D[] { new Point3D(-70, -50, 0), new Point3D(-170, -50, 0), new Point3D(-170, 50, 0), new Point3D(-70, 50, 0), }); var polyLineVisual3D = new PolyLineVisual3D() { Positions = polygonPositions, LineColor = Colors.Black, LineThickness = 1, IsClosed = true }; RootLinesVisual3D.Children.Add(polyLineVisual3D); // // Create 2 lines with pattern (see LinesWithPatternSample for more info) // var lineWithPattern1 = new Ab3d.Visuals.LineVisual3D() { StartPosition = new Point3D(-300, -100, 0), EndPosition = new Point3D(300, -100, 0), LineThickness = 2, LineColor = Colors.Orange }; lineWithPattern1.SetDXAttribute(DXAttributeType.LinePattern, 0x3333); // 0x3333 is 0011001100110011 //lineWithPattern1.SetDXAttribute(DXAttributeType.LinePatternScale, 1); // We do not need to set default scale and offset values //lineWithPattern1.SetDXAttribute(DXAttributeType.LinePatternOffset, 0); RootLinesVisual3D.Children.Add(lineWithPattern1); var lineWithPattern2 = new Ab3d.Visuals.LineVisual3D() { StartPosition = new Point3D(-300, -110, 0), EndPosition = new Point3D(300, -110, 0), LineThickness = 2, LineColor = Colors.Orange }; lineWithPattern2.SetDXAttribute(DXAttributeType.LinePattern, 0x5555); // 0x3333 is 0101010101010101 RootLinesVisual3D.Children.Add(lineWithPattern2); // // Create curve with BezierCurve class from Ab3d.PowerToys library (see Lines3D/CurvesSample in Ab3d.PowerToys samples project for more) // // NOTE: // Ab3d.DXEngine cannot show real curves but only straight lines. // But you can convert a curve to many lines to simulate a curve (but this may be seen when zooming in). // var curveControlPoints = new Point3D[] { new Point3D(0, 0, 0), new Point3D(30, 0, 0), new Point3D(60, 50, 0), new Point3D(90, 0, 0), new Point3D(120, 0, 0) }; var bezierCurve = Ab3d.Utilities.BezierCurve.CreateFromCurvePositions(curveControlPoints); var curvePositions = bezierCurve.CreateBezierCurve(positionsPerSegment: 20); // create 20 positions between each control point var curveLineVisual3D = new PolyLineVisual3D() { Positions = curvePositions, LineColor = Colors.Green, LineThickness = 2, Transform = new TranslateTransform3D(0, -50, 0) }; RootLinesVisual3D.Children.Add(curveLineVisual3D); // // Create lines from a WPF ellipse or any other WPF's shape // var ellipseGeometry = new EllipseGeometry(new Rect(0, 0, 120, 50)); var flattenGeometry = ellipseGeometry.GetFlattenedPathGeometry(tolerance: 0.1, type: ToleranceType.Absolute); var geometryPoints = new List <Point>(); geometryPoints.Add(flattenGeometry.Figures[0].StartPoint); // We need only the first Figure foreach (var oneSegment in flattenGeometry.Figures[0].Segments) { if (oneSegment is PolyLineSegment) { geometryPoints.AddRange(((PolyLineSegment)oneSegment).Points); } else if (oneSegment is LineSegment) { geometryPoints.Add(((LineSegment)oneSegment).Point); } } var ellipsePoints = ConvertToPoint3DCollection(geometryPoints); var ellipseLineVisual3D = new PolyLineVisual3D() { Positions = ellipsePoints, LineColor = Colors.Green, LineThickness = 2, Transform = new TranslateTransform3D(0, 20, 0) }; RootLinesVisual3D.Children.Add(ellipseLineVisual3D); // // Show 2D shapes with using triangulator from Ab3d.PowerToys to convert shape to a set of triangles. // // NOTE: // The current version (Ab3d.PowerToys v9.4) does not support triangulating shapes with holes. // var shapePoints = new Point[] { new Point(0, 0), new Point(50, 0), new Point(100, 50), new Point(100, 100), new Point(50, 80), new Point(50, 40), new Point(0, 40), new Point(0, 0), }; var triangulator = new Ab3d.Utilities.Triangulator(shapePoints); var triangleIndices = triangulator.CreateTriangleIndices(); var shapePoints3D = ConvertToPoint3DCollection(shapePoints); var meshGeometry3D = new MeshGeometry3D() { Positions = shapePoints3D, TriangleIndices = new Int32Collection(triangleIndices) }; var shapeGeometryModel3D = new GeometryModel3D(meshGeometry3D, new DiffuseMaterial(Brushes.LightBlue)); // NOTE: // We set Z of the shape to -0.5 !!! // This will move the solid shape slightly behind the 3D line so the line will be always on top of the shape shapeGeometryModel3D.Transform = new TranslateTransform3D(200, -50, -0.5); RootLinesVisual3D.Children.Add(shapeGeometryModel3D.CreateModelVisual3D()); // Also add an outline to the shape var shapeOutlineVisual3D = new PolyLineVisual3D() { Positions = shapePoints3D, LineColor = Colors.Black, LineThickness = 1, Transform = shapeGeometryModel3D.Transform }; RootLinesVisual3D.Children.Add(shapeOutlineVisual3D); }
private void LoadSampleLinesData(double lineThickness, Rect targetRect) { // Read many lines from a custom bin file format. // The bin file was created from a metafile (wmf) file that was read by Ab2d.ReaderWmf, // then the lines were grouped by color and saved to a custom bin file. Rect bounds; var lines = ReadLineDataFromBin(AppDomain.CurrentDomain.BaseDirectory + @"Resources\palazz_sport.bin", out bounds); Point targetCenter = new Point(targetRect.X + targetRect.Width * 0.5, targetRect.Y + targetRect.Height * 0.5); double xScale = targetRect.Width / bounds.Width; double yScale = targetRect.Height / bounds.Height; double scale = Math.Min(xScale, yScale); // Preserve aspect ratio - so use the minimal scale double xOffset = targetCenter.X - bounds.Width * scale * 0.5; double yOffset = targetCenter.Y + bounds.Height * scale * 0.5; // targetCenter.Y - bounds.Height * scale * 0.5 + bounds.Height * scale // because we flipped y we need to offset by height var matrixTransform = new MatrixTransform(scale, 0, 0, -scale, // We also need to flip y axis because here y axis is pointing up xOffset, yOffset); for (var i = 0; i < lines.Count; i++) { var oneLineData = lines[i]; var positions = oneLineData.Positions; var point3DCollection = new Point3DCollection(positions.Count); for (var j = 0; j < positions.Count; j++) { var p = new Point(positions[j].X, positions[j].Y); p = matrixTransform.Transform(p); point3DCollection.Add(new Point3D(p.X, p.Y, 0)); } if (oneLineData.IsLineStrip) { var polyLineVisual3D = new PolyLineVisual3D() { Positions = point3DCollection, LineColor = oneLineData.LineColor, LineThickness = lineThickness < 0 ? oneLineData.LineThickness : lineThickness }; RootLinesVisual3D.Children.Add(polyLineVisual3D); } else { var multiLineVisual3D = new MultiLineVisual3D() { Positions = point3DCollection, LineColor = oneLineData.LineColor, LineThickness = lineThickness < 0 ? oneLineData.LineThickness : lineThickness }; RootLinesVisual3D.Children.Add(multiLineVisual3D); } } }
private void CreateOffline3DScene() { var viewport3D = new Viewport3D(); // IMPORTANT !!! // Because this Viewport3D will not be actually shown, we need to manually set its size // because this is needed for projection matrix. viewport3D.Width = 800; viewport3D.Height = 600; var targetPositionCamera = new TargetPositionCamera() { Heading = 0, Attitude = 0, CameraType = BaseCamera.CameraTypes.OrthographicCamera, CameraWidth = viewport3D.Width, // Use same width as viewport3D so we get 1:1 scale TargetViewport3D = viewport3D }; var polyLineVisual3D = new PolyLineVisual3D() { Positions = new Point3DCollection(new Point3D[] { //new Point3D(-100, 0, -50), //new Point3D(100, 0, -50), //new Point3D(100, 0, 50), //new Point3D(50, 0, 0), //new Point3D(-100, 0, 50), new Point3D(-100, -50, 0), new Point3D(100, -50, 0), new Point3D(100, 50, 0), new Point3D(50, 0, 0), new Point3D(-100, 50, 0), }), LineColor = Colors.Green, LineThickness = 30, // NOTE: // If you require that each line segment uses exactly 4 positions, // then you need to disable turning mitered joints into beveled joints // (beveled joints have 3 additional positions that cut the sharp joint). // It is not possible to know in advance how many bevel joints will be // because this also depends on the angle of the camera. // To disable creating beveled joints set MiterLimit to some high number // (for example the following will create a beveled joint when the joint length is 100 times the line thickness). //MiterLimit = 100 }; viewport3D.Children.Add(polyLineVisual3D); targetPositionCamera.Refresh(); Ab3d.Utilities.LinesUpdater.Instance.Refresh(); // Force regeneration of all 3D lines var geometryModel3D = polyLineVisual3D.Content as GeometryModel3D; if (geometryModel3D != null) { var lineMesh = (MeshGeometry3D)geometryModel3D.Geometry; _shownLineModel3D = new GeometryModel3D(); _shownLineModel3D.Geometry = lineMesh; _shownLineModel3D.Material = new DiffuseMaterial(Brushes.LightGray); _shownLineModel3D.BackMaterial = new DiffuseMaterial(Brushes.Black); if (BillboardCheckbox.IsChecked ?? false) { ApplyBillboardMatrix(); } MainViewport.Children.Add(_shownLineModel3D.CreateContentVisual3D()); MeshInspector.MeshGeometry3D = lineMesh; } }