Beispiel #1
0
            public object Deserialize(object o, Altaxo.Serialization.Xml.IXmlDeserializationInfo info, object parent)
            {
                RectangleD3D s = null != o ? (RectangleD3D)o : new RectangleD3D();

                s._x     = info.GetDouble("X");
                s._y     = info.GetDouble("Y");
                s._z     = info.GetDouble("Z");
                s._sizeX = info.GetDouble("SizeX");
                s._sizeY = info.GetDouble("SizeY");
                s._sizeZ = info.GetDouble("SizeZ");

                return(s);
            }
Beispiel #2
0
        /// <summary>
        /// Creates a new rectangle that includes all the provided points.
        /// </summary>
        /// <param name="points">The points that the rectangle should include.</param>
        /// <returns>The rectangle that includes all the provided points.</returns>
        /// <exception cref="System.ArgumentException">Enumeration is empty!</exception>
        public static RectangleD3D NewRectangleIncludingAllPoints(IEnumerable <PointD3D> points)
        {
            var en = points.GetEnumerator();

            if (!en.MoveNext())
            {
                throw new ArgumentException("Enumeration is empty!", nameof(points));
            }

            var result = new RectangleD3D(en.Current, VectorD3D.Empty);

            while (en.MoveNext())
            {
                result.ExpandToInclude(en.Current);
            }

            return(result);
        }
			/// <summary>
			/// Determines whether the grip is hit by the current mouse position.
			/// </summary>
			/// <param name="mousePosition">The mouse position (hit ray).</param>
			/// <returns></returns>
			public bool IsGripHit(HitTestPointData mousePosition)
			{
				var vec = new VectorD3D(_gripRadius, _gripRadius, _gripRadius);
				var rect = new RectangleD3D(_gripCenter - vec, 2 * vec);

				double z;
				return mousePosition.IsHit(rect, out z);
			}
Beispiel #4
0
		/// <summary>
		/// Gets the rectangle for the background to draw. Used both by <see cref="Measure"/> as well as <see cref="Draw"/>.
		/// </summary>
		/// <param name="itemRectangle">The item rectangle.</param>
		/// <returns></returns>
		private RectangleD3D GetRectangleToDraw(RectangleD3D itemRectangle)
		{
			return new RectangleD3D(
			itemRectangle.X - _padding.Left,
			itemRectangle.Y - _padding.Bottom,
			itemRectangle.Z - _resultingDistance - itemRectangle.SizeZ,
			itemRectangle.SizeX + _padding.Left + _padding.Right,
			itemRectangle.SizeY + _padding.Top + _padding.Bottom,
			_resultingThickness
			);
		}
Beispiel #5
0
			internal LineShapeObjectOutline(Matrix4x3 transformation, RectangleD3D bounds)
			{
				_transformation = transformation;
				_bounds = bounds;
			}
Beispiel #6
0
		protected override IGripManipulationHandle[] GetGrips(IHitTestObject hitTest, GripKind gripKind)
		{
			var list = new List<IGripManipulationHandle>();

			/*

const double gripNominalSize = 10; // 10 Points nominal size on the screen
			if ((GripKind.Resize & gripKind) != 0)
			{
				double gripSize = gripNominalSize / pageScale; // 10 Points, but we have to consider the current pageScale
				for (int i = 1; i < _gripRelPositions.Length; i++)
				{
					PointD2D outVec, pos;
					if (1 == i % 2)
						GetCornerOutVector(_gripRelPositions[i], hitTest, out outVec, out pos);
					else
						GetMiddleRayOutVector(_gripRelPositions[i], hitTest, out outVec, out pos);

					outVec *= (gripSize / outVec.VectorLength);
					PointD2D altVec = outVec.Get90DegreeRotated();
					PointD2D ptStart = pos;
					list.Add(new ResizeGripHandle(hitTest, _gripRelPositions[i], new MatrixD2D(outVec.X, outVec.Y, altVec.X, altVec.Y, ptStart.X, ptStart.Y)));
				}
			}
			*/

			/*
			if ((GripKind.Rotate & gripKind) != 0)
			{
				double gripSize = 10 / pageScale;
				// Rotation grips
				for (int i = 1; i < _gripRelPositions.Length; i += 2)
				{
					PointD2D outVec, pos;
					GetCornerOutVector(_gripRelPositions[i], hitTest, out outVec, out pos);

					outVec *= (gripSize / outVec.VectorLength);
					PointD2D altVec = outVec.Get90DegreeRotated();
					PointD2D ptStart = pos;
					list.Add(new RotationGripHandle(hitTest, _gripRelPositions[i], new MatrixD2D(outVec.X, outVec.Y, altVec.X, altVec.Y, ptStart.X, ptStart.Y)));
				}
			}
			*/

			/*
			if ((GripKind.Rescale & gripKind) != 0)
			{
				double gripSize = 10 / pageScale; // 10 Points, but we have to consider the current pageScale
				for (int i = 1; i < _gripRelPositions.Length; i++)
				{
					PointD2D outVec, pos;
					if (1 == i % 2)
						GetCornerOutVector(_gripRelPositions[i], hitTest, out outVec, out pos);
					else
						GetMiddleRayOutVector(_gripRelPositions[i], hitTest, out outVec, out pos);

					outVec *= (gripSize / outVec.VectorLength);
					PointD2D altVec = outVec.Get90DegreeRotated();
					PointD2D ptStart = pos;
					list.Add(new RescaleGripHandle(hitTest, _gripRelPositions[i], new MatrixD2D(outVec.X, outVec.Y, altVec.X, altVec.Y, ptStart.X, ptStart.Y)));
				}
			}
			*/

			/*
			if ((GripKind.Shear & gripKind) != 0)
			{
				double gripSize = 10 / pageScale; // 10 Points, but we have to consider the current pageScale
				for (int i = 2; i < _gripRelPositions.Length; i += 2)
				{
					PointD2D outVec, pos;
					GetEdgeOutVector(_gripRelPositions[i], hitTest, out outVec, out pos);

					outVec *= (gripSize / outVec.VectorLength);
					PointD2D altVec = outVec.Get90DegreeRotated();
					PointD2D ptStart = pos;
					list.Add(new ShearGripHandle(hitTest, _gripRelPositions[i], new MatrixD2D(outVec.X, outVec.Y, altVec.X, altVec.Y, ptStart.X, ptStart.Y)));
				}
			}
			*/

			if ((GripKind.Move & gripKind) != 0)
			{
				var bounds = this.Bounds;
				var wn = PolylineMath3D.GetWestNorthVectors(bounds.Size);
				var transformation = Matrix4x3.NewFromBasisVectorsAndLocation(wn.Item1, wn.Item2, bounds.Size.Normalized, PointD3D.Empty);

				transformation.AppendTransform(_transformation);
				transformation.AppendTransform(hitTest.Transformation);

				double t1 = 0.55 * _linePen.Thickness1;
				double t2 = 0.55 * _linePen.Thickness2;
				var rect = new RectangleD3D(-t1, -t2, 0, 2 * t1, 2 * t2, bounds.Size.Length);
				var objectOutline = new RectangularObjectOutline(rect, transformation);
				list.Add(new MovementGripHandle(hitTest, objectOutline, null));
			}

			return list.ToArray();
		}
Beispiel #7
0
		protected void MeasureBackground(IGraphicsContext3D g, double itemSizeX, double itemSizeY, double itemSizeZ)
		{
			var fontInfo = FontManager3D.Instance.GetFontInformation(_font);

			double widthOfOne_n = Glyph.MeasureString("n", _font).X;
			double widthOfThree_M = Glyph.MeasureString("MMM", _font).X;

			if (this._background != null)
			{
				_cachedTextPadding = new Margin2D(
					0.25 * widthOfOne_n,
					fontInfo.cyDescent,
					0.25 * widthOfOne_n,
					fontInfo.cyDescent
					);
			}
			else
			{
				_cachedTextPadding = new Margin2D(0, 0, 0, 0);
			}

			var paddedTextSize = new VectorD3D((itemSizeX + _cachedTextPadding.Left + _cachedTextPadding.Right), (itemSizeY + _cachedTextPadding.Bottom + _cachedTextPadding.Top), itemSizeZ);
			var textRectangle = new RectangleD3D(PointD3D.Empty, paddedTextSize); // the origin of the padded text rectangle is always 0

			if (this._background != null)
			{
				var backgroundRect = this._background.Measure(textRectangle);
				_cachedExtendedTextBounds = backgroundRect.WithRectangleIncluded(textRectangle); //  _cachedExtendedTextBounds.WithOffset(textRectangle.X - backgroundRect.X, textRectangle.Y - backgroundRect.Y, 0);

				((ItemLocationDirectAutoSize)_location).SetSizeInAutoSizeMode(_cachedExtendedTextBounds.Size, false);
				this._cachedTextOffset = new PointD3D(textRectangle.X - backgroundRect.X + _cachedTextPadding.Left, textRectangle.Y - backgroundRect.Y + _cachedTextPadding.Bottom, 0);
			}
			else
			{
				((ItemLocationDirectAutoSize)_location).SetSizeInAutoSizeMode(paddedTextSize, false);
				_cachedExtendedTextBounds = textRectangle;
				_cachedTextOffset = PointD3D.Empty;
			}
		}
Beispiel #8
0
		public void Paint(IGraphicsContext3D g, IPlotArea layer, CSPlaneID plane, int axisnumber)
		{
			if (!_showGrid)
				return;

			Scale axis = layer.Scales[axisnumber];
			TickSpacing ticking = layer.Scales[axisnumber].TickSpacing;

			RectangleD3D layerRect = new RectangleD3D(PointD3D.Empty, layer.Size);

			if (_showZeroOnly)
			{
				Altaxo.Data.AltaxoVariant var = new Altaxo.Data.AltaxoVariant(0.0);
				double rel = axis.PhysicalVariantToNormal(var);
				//_majorPen.SetEnvironment(layerRect, BrushX.GetEffectiveMaximumResolution(g, 1));
				if (rel >= 0 && rel <= 1)
				{
					Logical3D logV = new Logical3D();
					logV.SetR(plane.PerpendicularAxisNumber, plane.LogicalValue);
					logV.SetR(axisnumber, rel);
					var thirdAxisNumber = Logical3D.GetPerpendicularAxisNumber(plane.PerpendicularAxisNumber, axisnumber);
					var line = layer.CoordinateSystem.GetIsoline(logV.WithR(thirdAxisNumber, 0), logV.WithR(thirdAxisNumber, 1));
					g.DrawLine(MajorPen, line);
				}
			}
			else
			{
				double[] ticks;

				if (_showMinor)
				{
					//_minorPen.SetEnvironment(layerRect, BrushX.GetEffectiveMaximumResolution(g, 1));
					ticks = ticking.GetMinorTicksNormal(axis);
					for (int i = 0; i < ticks.Length; ++i)
					{
						Logical3D logV = new Logical3D();
						logV.SetR(plane.PerpendicularAxisNumber, plane.LogicalValue);
						logV.SetR(axisnumber, ticks[i]);
						var thirdAxisNumber = Logical3D.GetPerpendicularAxisNumber(plane.PerpendicularAxisNumber, axisnumber);
						var line = layer.CoordinateSystem.GetIsoline(logV.WithR(thirdAxisNumber, 0), logV.WithR(thirdAxisNumber, 1));
						g.DrawLine(MinorPen, line);
					}
				}

				//MajorPen.SetEnvironment(layerRect, BrushX.GetEffectiveMaximumResolution(g, 1));
				ticks = ticking.GetMajorTicksNormal(axis);
				for (int i = 0; i < ticks.Length; ++i)
				{
					Logical3D logV = new Logical3D();
					logV.SetR(plane.PerpendicularAxisNumber, plane.LogicalValue);
					logV.SetR(axisnumber, ticks[i]);
					var thirdAxisNumber = Logical3D.GetPerpendicularAxisNumber(plane.PerpendicularAxisNumber, axisnumber);
					var line = layer.CoordinateSystem.GetIsoline(logV.WithR(thirdAxisNumber, 0), logV.WithR(thirdAxisNumber, 1));
					g.DrawLine(MajorPen, line);
				}
			}
		}
Beispiel #9
0
		public RectangularObjectOutline(RectangleD3D rectangle, Matrix4x3 transformation)
		{
			_rectangle = rectangle;
			_transformation = transformation;
		}
Beispiel #10
0
		/// <summary>
		/// Gets the principal coordinate system that results of the camera facing a layer. The plane of the layer that best faced the camera is used for the calculations.
		/// The normal of that layer is returned as z-axis, the vector that best matches the up-vector of the camera is becoming the y-axis,
		/// and the x-axis results from the z-axis and the y-axis.
		/// </summary>
		/// <param name="camera">The camera.</param>
		/// <param name="activeLayer">The active layer of the graph document.</param>
		/// <param name="transformation">Matrix that contains the principal axes as described above. The axes coordinates are in the coordinates of the layer provided in the argument <paramref name="activeLayer"/>.</param>
		/// <exception cref="InvalidProgramException">There should always be a plane of a rectangle that can be hit!</exception>
		public static void GetCoordinateSystemBasedOnLayerPlaneFacingTheCamera(CameraBase camera, HostLayer activeLayer, out Matrix3x3 transformation)
		{
			PointD3D hitposition = new PointD3D(0.5, 0.5, 1); // this hit position is arbitrary, every other position should work similarly

			var activeLayerTransformation = activeLayer.TransformationFromRootToHere();

			var hitData = new HitTestPointData(camera.GetHitRayMatrix(hitposition));

			hitData = hitData.NewFromAdditionalTransformation(activeLayerTransformation); // now hitdata are in layer cos

			var targetToEye = hitData.WorldTransformation.Transform(camera.TargetToEyeVectorNormalized); // targetToEye in layer coordinates
			var upEye = hitData.WorldTransformation.Transform(camera.UpVectorPerpendicularToEyeVectorNormalized); // camera up vector in layer coordinates

			// get the face which has the best dot product between the eye vector of the camera and the plane's normal
			var layerRect = new RectangleD3D(PointD3D.Empty, activeLayer.Size);
			double maxval = double.MinValue;
			PlaneD3D maxPlane = PlaneD3D.Empty;
			foreach (var plane in layerRect.Planes)
			{
				double val = VectorD3D.DotProduct(plane.Normal, targetToEye);
				if (val > maxval)
				{
					maxval = val;
					maxPlane = plane;
				}
			}

			//	bool isHit = hitData.IsPlaneHitByRay(maxPlane, out hitPointOnPlaneInActiveLayerCoordinates); // hitPointOnPlane is in layer coordinates too

			//	if (!isHit)
			//	throw new InvalidProgramException("There should always be a plane of a rectangle that can be hit!");

			VectorD3D zaxis = maxPlane.Normal;
			VectorD3D yaxis = upEye;

			// Find y axis perpendicular to zaxis
			maxval = double.MinValue;
			foreach (var plane in layerRect.Planes)
			{
				double val = VectorD3D.DotProduct(plane.Normal, upEye);
				if (val > maxval && 0 == VectorD3D.DotProduct(plane.Normal, zaxis))
				{
					maxval = val;
					yaxis = plane.Normal;
				}
			}
			var xaxis = VectorD3D.CrossProduct(yaxis, zaxis);

			// now we have all information about the spatial position and orientation of the text:
			// hitPointOnPlane is the position of the text
			// maxPlane.Normal is the face orientation of the text
			// maxUpVector is the up orientation of the text

			xaxis = xaxis.Normalized;
			yaxis = yaxis.Normalized;
			zaxis = zaxis.Normalized;

			transformation = new Matrix3x3(
				xaxis.X, yaxis.X, zaxis.X,
				xaxis.Y, yaxis.Y, zaxis.Y,
				xaxis.Z, yaxis.Z, zaxis.Z
				);
		}
Beispiel #11
0
		/// <summary>
		/// Make the views to look at the root layer center. The scale is choosen so that the size of the plot will be maximal.
		/// </summary>
		/// <param name="toEyeVector">The To-Eye vector (vector from the target to the camera position).</param>
		/// <param name="cameraUpVector">The camera up vector.</param>
		/// <exception cref="System.NotImplementedException"></exception>
		public void ViewToRootLayerCenter(VectorD3D toEyeVector, VectorD3D cameraUpVector)
		{
			double aspectRatio = 1;
			if (null != _view)
			{
				var viewportSize = _view.ViewportSizeInPoints;
				aspectRatio = viewportSize.Y / viewportSize.X;
			}

			if ((VectorD3D.CrossProduct(toEyeVector, cameraUpVector).IsEmpty))
				throw new ArgumentOutOfRangeException(nameof(cameraUpVector) + " is either empty or is parallel to the eyeVector");

			var upVector = Math3D.GetNormalizedVectorOrthogonalToVector(cameraUpVector, toEyeVector);
			var targetPosition = (PointD3D)(0.5 * Doc.RootLayer.Size);
			var cameraDistance = 10 * Doc.RootLayer.Size.Length;
			var eyePosition = cameraDistance * toEyeVector.Normalized + targetPosition;
			var newCamera = Doc.Camera.WithUpEyeTarget(upVector, eyePosition, targetPosition);

			if (newCamera is OrthographicCamera)
			{
				var orthoCamera = (OrthographicCamera)newCamera.WithWidthAtZNear(1);

				var mx = orthoCamera.GetViewProjectionMatrix(aspectRatio);
				// to get the resulting scale, we transform all vertices of the root layer (the destination range would be -1..1, but now is not in range -1..1)
				// then we search for the maximum of the absulute value of x and y. This is our scale.
				double absmax = 0;
				foreach (var p in new RectangleD3D(Doc.RootLayer.Position, Doc.RootLayer.Size).Vertices)
				{
					var ps = mx.Transform(p);
					absmax = Math.Max(absmax, Math.Abs(ps.X));
					absmax = Math.Max(absmax, Math.Abs(ps.Y));
				}
				newCamera = orthoCamera.WithWidthAtZNear(absmax);
			}
			else if (newCamera is PerspectiveCamera)
			{
				var perspCamera = (PerspectiveCamera)newCamera;
				// use worst case
				var diameter = Doc.RootLayer.Size.Length; // diagonal of the root layer = radius of sphere in the worst case

				double minWidthHeight = Math.Min(perspCamera.WidthAtZNear, perspCamera.WidthAtZNear * aspectRatio);

				var distanceWorstCase = diameter * perspCamera.ZNear / minWidthHeight;

				if (distanceWorstCase > perspCamera.Distance)
					perspCamera = (PerspectiveCamera)perspCamera.WithDistanceByChangingEyePosition(distanceWorstCase);

				var rootRect = new RectangleD3D(PointD3D.Empty, Doc.RootLayer.Size);

				for (int i = 0; i < 5; ++i) // 5 iterations to get the right distance
				{
					var viewProj = perspCamera.GetViewProjectionMatrix(aspectRatio);
					var screenRect = RectangleD2D.NewRectangleIncludingAllPoints(rootRect.Vertices.Select(v => viewProj.Transform(v).PointD2DWithoutZ));

					double maxScreen = 0;
					foreach (var v in screenRect.Vertices)
					{
						maxScreen = Math.Max(maxScreen, Math.Abs(v.X));
						maxScreen = Math.Max(maxScreen, Math.Abs(v.Y));
					}

					// now we could decrease the camera distance by maxScreen, but this is only an estimation
					perspCamera = (PerspectiveCamera)perspCamera.WithDistanceByChangingEyePosition(perspCamera.Distance * maxScreen);
				}
				newCamera = perspCamera;
			}
			else
			{
				throw new NotImplementedException("Unknown camera type");
			}

			Doc.Camera = AdjustZNearZFar(newCamera);
		}
Beispiel #12
0
		public void DrawRootLayerMarkers(IOverlayContext3D gc)
		{
			var buf = gc.PositionColorIndexedTriangleBuffers;

			VectorD3D size = Doc.RootLayer.Size;

			double markerLen = Math.Max(size.X, Math.Max(size.Y, size.Z)) / 20.0;
			double markerLenBy2 = markerLen / 2;
			double markerThicknessBy2 = markerLenBy2 / 5.0;

			RectangleD3D rect = new RectangleD3D(PointD3D.Empty, size);

			if (_cachedResultingRootLayerMarkersVisibility.HasFlag(RootLayerMarkersVisibility.Arrows))
			{
				foreach (var pos in rect.Vertices)
				{
					var posX = pos.WithXPlus(pos.X == 0 ? markerLenBy2 : -markerLenBy2);
					DrawMarkerX(buf, posX, markerLenBy2, markerThicknessBy2);

					var posY = pos.WithYPlus(pos.Y == 0 ? markerLenBy2 : -markerLenBy2);
					DrawMarkerY(buf, posY, markerLenBy2, markerThicknessBy2);

					var posZ = pos.WithZPlus(pos.Z == 0 ? markerLenBy2 : -markerLenBy2);
					DrawMarkerZ(buf, posZ, markerLenBy2, markerThicknessBy2);
				}
			}

			if (_cachedResultingRootLayerMarkersVisibility.HasFlag(RootLayerMarkersVisibility.Lines))
			{
				var lineBuffer = gc.PositionColorLineListBuffer;
				foreach (var line in rect.Edges)
				{
					lineBuffer.AddLine(line.P0.X, line.P0.Y, line.P0.Z, line.P1.X, line.P1.Y, line.P1.Z, 1, 0, 0, 1);
				}
			}
		}
Beispiel #13
0
		/// <summary>
		/// Draws the specified background
		/// </summary>
		/// <param name="g">The drawing context.</param>
		/// <param name="itemRectangle">Position and size of the item for which this background is intended. For text, this is the position and size of the text rectangle, already with a margin around.
		/// This parameter should have the same size as was used in the previous call to <see cref="Measure(RectangleD3D)" /></param>
		/// <param name="material">The material to use for this background.</param>
		/// <exception cref="NotImplementedException"></exception>
		public void Draw(IGraphicsContext3D g, RectangleD3D itemRectangle, IMaterial material)
		{
			var rectangleToDraw = GetRectangleToDraw(itemRectangle);

			var buffers = g.GetPositionNormalIndexedTriangleBuffer(material);

			if (null != buffers.PositionNormalColorIndexedTriangleBuffer)
			{
				var c = material.Color.Color;
				var voffs = buffers.PositionNormalColorIndexedTriangleBuffer.VertexCount;
				Altaxo.Drawing.D3D.SolidCube.Add(
					rectangleToDraw.X, rectangleToDraw.Y, rectangleToDraw.Z, rectangleToDraw.SizeX, rectangleToDraw.SizeY, rectangleToDraw.SizeZ,
					(point, normal) => buffers.PositionNormalColorIndexedTriangleBuffer.AddTriangleVertex(point.X, point.Y, point.Z, normal.X, normal.Y, normal.Z, c.ScR, c.ScG, c.ScB, c.ScA),
					(i1, i2, i3) => buffers.IndexedTriangleBuffer.AddTriangleIndices(i1 + voffs, i2 + voffs, i3 + voffs),
					ref voffs);
			}
			else if (null != buffers.PositionNormalIndexedTriangleBuffer)
			{
				var voffs = buffers.PositionNormalIndexedTriangleBuffer.VertexCount;
				Altaxo.Drawing.D3D.SolidCube.Add(
					rectangleToDraw.X, rectangleToDraw.Y, rectangleToDraw.Z, rectangleToDraw.SizeX, rectangleToDraw.SizeY, rectangleToDraw.SizeZ,
					(point, normal) => buffers.PositionNormalIndexedTriangleBuffer.AddTriangleVertex(point.X, point.Y, point.Z, normal.X, normal.Y, normal.Z),
					(i1, i2, i3) => buffers.IndexedTriangleBuffer.AddTriangleIndices(i1 + voffs, i2 + voffs, i3 + voffs),
					ref voffs);
			}
			else
			{
				throw new NotImplementedException();
			}
		}
Beispiel #14
0
		/// <summary>
		/// Draws the specified background
		/// </summary>
		/// <param name="g">The drawing context.</param>
		/// <param name="itemRectangle">Position and size of the item for which this background is intended. For text, this is the position and size of the text rectangle, already with a margin around.
		/// This parameter should have the same size as was used in the previous call to <see cref="Measure(RectangleD3D)" /></param>
		/// <exception cref="NotImplementedException"></exception>
		public void Draw(IGraphicsContext3D g, RectangleD3D itemRectangle)
		{
			Draw(g, itemRectangle, _material);
		}
Beispiel #15
0
		/// <summary>
		/// Saves the project item as image to the provided stream.
		/// </summary>
		/// <param name="item">The item to export, for instance an item of type <see cref="Altaxo.Graph.Gdi.GraphDocument"/> or <see cref="Altaxo.Graph.Graph3D.GraphDocument"/>.</param>
		/// <param name="options">The export options.</param>
		/// <param name="toStream">The stream to save the image to.</param>
		public void ExportAsImageToStream(Altaxo.Main.IProjectItem item, Altaxo.Graph.Gdi.GraphExportOptions options, System.IO.Stream toStream)
		{
			if (item == null)
				throw new ArgumentNullException(nameof(item));
			if (!(item is Altaxo.Graph.Graph3D.GraphDocument))
				throw new ArgumentException(string.Format("Expected item of type {0}, but it is of type {1}", typeof(Altaxo.Graph.Graph3D.GraphDocument), item.GetType()));
			var doc = (Altaxo.Graph.Graph3D.GraphDocument)item;

			double sourceDpi = options.SourceDpiResolution;

			var exporter = new D3D10BitmapExporter();

			var scene = new Viewing.D3D10Scene();

			var g = new D3D10GraphicsContext();

			doc.Paint(g);

			var matrix = doc.Camera.LookAtRHMatrix;

			var rect = new RectangleD3D(PointD3D.Empty, doc.RootLayer.Size);
			var bounds = RectangleD3D.NewRectangleIncludingAllPoints(rect.Vertices.Select(x => matrix.Transform(x)));

			int pixelsX = (int)Math.Ceiling(sourceDpi * bounds.SizeX / 72.0);
			pixelsX = (int)(4 * Math.Ceiling((pixelsX + 3) / 4.0));

			int pixelsY = (int)(sourceDpi * bounds.SizeY / 72.0);

			double aspectRatio = pixelsY / (double)pixelsX;

			var sceneCamera = doc.Camera;

			if (sceneCamera is OrthographicCamera)
			{
				var orthoCamera = (OrthographicCamera)sceneCamera;
				orthoCamera = (OrthographicCamera)orthoCamera.WithWidthAtZNear(bounds.SizeX);

				double offsX = -(1 + 2 * bounds.X / bounds.SizeX);
				double offsY = -(1 + 2 * bounds.Y / bounds.SizeY);
				sceneCamera = orthoCamera.WithScreenOffset(new PointD2D(offsX, offsY));
			}
			else if (sceneCamera is PerspectiveCamera)
			{
				var viewProj = sceneCamera.GetViewProjectionMatrix(1); // here we transform the points with AspectRatio=1, in order to get the AspectRatio of the ScreenBounds
				var screenBounds = RectangleD3D.NewRectangleIncludingAllPoints(rect.Vertices.Select(x => viewProj.Transform(x)));
				aspectRatio = screenBounds.SizeY / screenBounds.SizeX; // this is the aspectRatio of our image
				viewProj = sceneCamera.GetViewProjectionMatrix(aspectRatio); // now we get the transform with our aspectRatio determined above
				screenBounds = RectangleD3D.NewRectangleIncludingAllPoints(rect.Vertices.Select(x => viewProj.Transform(x))); // this are our actual screenBounds, of course in relative screen coordinates, thus the ratio of sizeX and sizeY should now be 1

				double scaleFactor = 2 / screenBounds.SizeX; // since SizeX and SizeY should now be the same, we could have used SizeY alternatively
				double offsX = -(1 + scaleFactor * screenBounds.X);
				double offsY = -(1 + scaleFactor * screenBounds.Y);

				pixelsY = (int)(4 * Math.Ceiling((aspectRatio * pixelsX + 3) / 4.0)); // now calculate the size of the image in y direction from the aspectRatio

				var perspCamera = (PerspectiveCamera)sceneCamera;

				sceneCamera = perspCamera.WithWidthAtZNear(perspCamera.WidthAtZNear / scaleFactor);
				sceneCamera = sceneCamera.WithScreenOffset(new PointD2D(offsX, offsY));
			}
			else
			{
				throw new NotImplementedException();
			}

			scene.SetCamera(sceneCamera);
			scene.SetLighting(doc.Lighting);
			scene.SetDrawing(g);

			exporter.Export(pixelsX, pixelsY, scene, options, toStream);
		}
Beispiel #16
0
		/// <summary>
		/// Creates a new rectangle that includes all the provided points.
		/// </summary>
		/// <param name="points">The points that the rectangle should include.</param>
		/// <returns>The rectangle that includes all the provided points.</returns>
		/// <exception cref="System.ArgumentException">Enumeration is empty!</exception>
		public static RectangleD3D NewRectangleIncludingAllPoints(IEnumerable<PointD3D> points)
		{
			var en = points.GetEnumerator();
			if (!en.MoveNext())
				throw new ArgumentException("Enumeration is empty!", nameof(points));

			var result = new RectangleD3D(en.Current, VectorD3D.Empty);

			while (en.MoveNext())
			{
				result.ExpandToInclude(en.Current);
			}

			return result;
		}
Beispiel #17
0
		/// <summary>
		/// Gets the hit point on that plane of the active layer rectangle, that is facing the camera.
		/// </summary>
		/// <param name="doc">The graph document containing the active layer.</param>
		/// <param name="activeLayer">The active layer of the graph document.</param>
		/// <param name="hitposition">Hit point in relative screen coordinates. The z-component is the aspect ratio of the screen (y/x).</param>
		/// <param name="hitPointOnPlaneInActiveLayerCoordinates">Output: The hit point on the plane of the active layer that faces the camera. The hit point is returned in active layer coordinates.</param>
		/// <param name="rotationsRadian">The rotation angles that can be used e.g. to orient text so that the text is most readable from the current camera setting. Rotation angle around x is the x-component of the returned vector, and so on.</param>
		/// <exception cref="InvalidProgramException">There should always be a plane of a rectangle that can be hit!</exception>
		public static void GetHitPointOnActiveLayerPlaneFacingTheCamera(GraphDocument doc, HostLayer activeLayer, PointD3D hitposition, out PointD3D hitPointOnPlaneInActiveLayerCoordinates, out VectorD3D rotationsRadian)
		{
			var activeLayerTransformation = activeLayer.TransformationFromRootToHere();
			var camera = doc.Camera;
			var hitData = new HitTestPointData(camera.GetHitRayMatrix(hitposition));
			hitData = hitData.NewFromAdditionalTransformation(activeLayerTransformation); // now hitdata are in layer cos

			var targetToEye = hitData.WorldTransformation.Transform(camera.TargetToEyeVectorNormalized); // targetToEye in layer coordinates
			var upEye = hitData.WorldTransformation.Transform(camera.UpVectorPerpendicularToEyeVectorNormalized); // camera up vector in layer coordinates

			// get the face which has the best dot product between the eye vector of the camera and the plane's normal
			var layerRect = new RectangleD3D(PointD3D.Empty, activeLayer.Size);
			double maxval = double.MinValue;
			PlaneD3D maxPlane = PlaneD3D.Empty;
			foreach (var plane in layerRect.Planes)
			{
				double val = VectorD3D.DotProduct(plane.Normal, targetToEye);
				if (val > maxval)
				{
					maxval = val;
					maxPlane = plane;
				}
			}

			bool isHit = hitData.IsPlaneHitByRay(maxPlane, out hitPointOnPlaneInActiveLayerCoordinates); // hitPointOnPlane is in layer coordinates too

			if (!isHit)
				throw new InvalidProgramException("There should always be a plane of a rectangle that can be hit!");

			VectorD3D zaxis = maxPlane.Normal;
			VectorD3D yaxis = upEye;

			// Find y axis perpendicular to zaxis
			maxval = double.MinValue;
			foreach (var plane in layerRect.Planes)
			{
				double val = VectorD3D.DotProduct(plane.Normal, upEye);
				if (val > maxval && 0 == VectorD3D.DotProduct(plane.Normal, zaxis))
				{
					maxval = val;
					yaxis = plane.Normal;
				}
			}
			var xaxis = VectorD3D.CrossProduct(yaxis, zaxis);

			// now we have all information about the spatial position and orientation of the text:
			// hitPointOnPlane is the position of the text
			// maxPlane.Normal is the face orientation of the text
			// maxUpVector is the up orientation of the text

			double cx, sx, cy, sy, cz, sz;

			sy = xaxis.Z;
			if (1 != Math.Abs(sy))
			{
				cy = Math.Sqrt(1 - sy * sy);
				cz = xaxis.X / cy;
				sz = xaxis.Y / cy;
				sx = yaxis.Z / cy;
				cx = zaxis.Z / cy;
			}
			else // sy is +1, thus cy is zero
			{
				// we set x-rotation to zero, i.e. cx==1 and sx==0
				cy = 0;
				cx = 1;
				sx = 0;
				cz = yaxis.Y;
				sz = -yaxis.X;
			}

			rotationsRadian = new VectorD3D(Math.Atan2(sx, cx), Math.Atan2(sy, cy), Math.Atan2(sz, cz));
		}
Beispiel #18
0
		/// <summary>
		/// Returns a rectangle that is based on the current rectangle, but was expanded to include all vertex points of the provided rectangle <paramref name="r"/>.
		/// </summary>
		/// <param name="r">The rectangle, whose vertices have to be included.</param>
		/// <returns>A rectangle that is based on the current rectangle, but was expanded to include all vertex points of the provided rectangle <paramref name="r"/>.</returns>
		public RectangleD3D WithRectangleIncluded(RectangleD3D r)
		{
			return WithPointsIncluded(r.Vertices);
		}
Beispiel #19
0
 public RectangleTransformedD3D(RectangleD3D rectangle, Matrix4x3 transformation)
 {
     _rectangle      = rectangle;
     _transformation = transformation;
 }
Beispiel #20
0
		/// <summary>
		/// Determines whether the specified 3D-rectangle r is hit by a ray given by x=0, y=0, z>0.
		/// </summary>
		/// <param name="r">The rectangle r.</param>
		/// <param name="z">If there was a hit, this is the z coordinate of the hit.</param>
		/// <returns>True if the rectangle is hit by a ray given by x=0, y=0, z>0.</returns>
		public bool IsHit(RectangleD3D r, out double z)
		{
			return IsRectangleHitByRay(r, _hitTransformation, out z);
		}
Beispiel #21
0
 /// <summary>
 /// Returns a rectangle that is based on the current rectangle, but was expanded to include all vertex points of the provided rectangle <paramref name="r"/>.
 /// </summary>
 /// <param name="r">The rectangle, whose vertices have to be included.</param>
 /// <returns>A rectangle that is based on the current rectangle, but was expanded to include all vertex points of the provided rectangle <paramref name="r"/>.</returns>
 public RectangleD3D WithRectangleIncluded(RectangleD3D r)
 {
     return(WithPointsIncluded(r.Vertices));
 }
Beispiel #22
0
		/// <summary>
		/// Determines whether the specified 3D-rectangle r is hit by a ray given by x=0, y=0, z>0.
		/// </summary>
		/// <param name="r">The rectangle r.</param>
		/// <param name="rectangleToWorldTransformation">An additional transformation that transformes the given rectangle into the same coordinates as the hit data.</param>
		/// <param name="z">If there was a hit, this is the z coordinate of the hit.</param>
		/// <returns>True if the rectangle is hit by a ray given by x=0, y=0, z>0.</returns>
		public bool IsHit(RectangleD3D r, Matrix4x3 rectangleToWorldTransformation, out double z)
		{
			return IsRectangleHitByRay(r, _hitTransformation.WithPrependedTransformation(rectangleToWorldTransformation), out z);
		}
Beispiel #23
0
		/// <summary>
		/// Gets the absolute enclosing rectangle, taking into account ScaleX, ScaleY, Rotation and Shear (SSRS).
		/// </summary>
		/// <returns>The enclosing rectangle in absolute values.</returns>
		public RectangleD3D GetAbsoluteEnclosingRectangle()
		{
			Matrix4x3 m = Matrix4x3.NewScalingShearingRotationDegreesTranslation(
				ScaleX, ScaleY, ScaleZ,
				ShearX, ShearY, ShearZ,
				RotationX, RotationY, RotationZ,
				AbsolutePivotPositionX, AbsolutePivotPositionY, AbsolutePivotPositionZ);

			m.TranslatePrepend(AbsoluteVectorPivotToLeftUpper.X, AbsoluteVectorPivotToLeftUpper.Y, AbsoluteVectorPivotToLeftUpper.Z);

			var r = new RectangleD3D(PointD3D.Empty, this.AbsoluteSize);
			return RectangleD3D.NewRectangleIncludingAllPoints(r.Vertices.Select(p => m.Transform(p)));
		}
Beispiel #24
0
		/// <summary>
		/// Determines whether the specified 3D-rectangle r is hit by a ray given by the provided transformation matrix that would transform
		/// the hit ray in a ray at x=0, y=0, and z=-Infinity .. +Infinity.
		/// </summary>
		/// <param name="r">The rectangle r.</param>
		/// <param name="rayTransformation">The hit ray transformation.</param>
		/// <param name="z">If there was a hit, this is the z coordinate of the hit (otherwise, NaN is returned).</param>
		/// <returns>True if the rectangle is hit by a ray given by the provided hit ray matrix.</returns>
		public static bool IsRectangleHitByRay(RectangleD3D r, Matrix4x4 rayTransformation, out double z)
		{
			PointD3D[] vertices = new PointD3D[8];

			int i = 0;
			foreach (var v in r.Vertices)
				vertices[i++] = rayTransformation.Transform(v);

			foreach (var ti in r.TriangleIndices)
			{
				if (HitTestWithAlreadyTransformedPoints(vertices[ti.Item1], vertices[ti.Item2], vertices[ti.Item3], out z) && z >= 0)
					return true;
			}

			z = double.NaN;
			return false;
		}
Beispiel #25
0
			public override IGripManipulationHandle[] GetGrips(int gripLevel)
			{
				if (gripLevel <= 1)
				{
					LineShape ls = (LineShape)_hitobject;
					PointD3D[] pts = new PointD3D[] { PointD3D.Empty, (PointD3D)ls.Size };
					for (int i = 0; i < pts.Length; i++)
					{
						var pt = ls._transformation.Transform(pts[i]);
						pt = this.Transformation.Transform(pt);
						pts[i] = pt;
					}

					IGripManipulationHandle[] grips = new IGripManipulationHandle[gripLevel == 0 ? 1 : 3];

					// Translation grips
					var bounds = ls.Bounds;
					var wn = PolylineMath3D.GetWestNorthVectors(bounds.Size);
					var transformation = Matrix4x3.NewFromBasisVectorsAndLocation(wn.Item1, wn.Item2, bounds.Size.Normalized, PointD3D.Empty);

					transformation.AppendTransform(ls._transformation);
					transformation.AppendTransform(this.Transformation);

					double t1 = 0.55 * ls._linePen.Thickness1;
					double t2 = 0.55 * ls._linePen.Thickness2;
					var rect = new RectangleD3D(-t1, -t2, 0, 2 * t1, 2 * t2, bounds.Size.Length);
					var objectOutline = new RectangularObjectOutline(rect, transformation);
					grips[0] = new MovementGripHandle(this, objectOutline, null);

					// PathNode grips
					if (gripLevel == 1)
					{
						grips[2] = grips[0]; // put the movement grip to the background, the two NodeGrips need more priority
						var gripRadius = Math.Max(t1, t2);
						grips[0] = new PathNodeGripHandle(this, new VectorD3D(0, 0, 0), pts[0], gripRadius);
						grips[1] = new PathNodeGripHandle(this, new VectorD3D(1, 1, 1), pts[1], gripRadius);
					}
					return grips;
				}
				else
				{
					return base.GetGrips(gripLevel);
				}
			}
			/// <summary>Draws the grip in the graphics context.</summary>
			/// <param name="g">Graphics context.</param>
			public void Show(IOverlayContext3D g)
			{
				var buf = g.PositionColorLineListBuffer;

				var vec = new VectorD3D(_gripRadius, _gripRadius, _gripRadius);
				var rect = new RectangleD3D(_gripCenter - vec, 2 * vec);

				foreach (var line in rect.Edges)
					buf.AddLine(line.P0.X, line.P0.Y, line.P0.Z, line.P1.X, line.P1.Y, line.P1.Z, 1, 0, 0, 1);
			}
		public RectangleTransformedD3D(RectangleD3D rectangle, Matrix4x3 transformation)
		{
			_rectangle = rectangle;
			_transformation = transformation;
		}
Beispiel #28
0
		/// <summary>
		/// Measures the background size and position.
		/// </summary>
		/// <param name="itemRectangle">Position and size of the item for which this background is intended. For text, this is the position and size of the text rectangle, already with a margin around.</param>
		/// <returns>
		/// The position and size of the rectangle that fully includes the background (but not the item).
		/// </returns>
		public RectangleD3D Measure(RectangleD3D itemRectangle)
		{
			_resultingDistance = _customDistance.HasValue ? _customDistance.Value : itemRectangle.SizeZ / 2;
			_resultingThickness = _customThickness.HasValue ? _customThickness.Value : itemRectangle.SizeZ;

			return GetRectangleToDraw(itemRectangle);
		}