public override void Draw(IGraphicsContext3D g, DrawContext dc, double xbase, double ybase, double zbase) { var mylayer = (HostLayer)dc.LinkedObject; var layer = mylayer as XYZPlotLayer; if (_layerNumber >= 0 && mylayer.SiblingLayers != null && _layerNumber < mylayer.SiblingLayers.Count) { layer = mylayer.SiblingLayers[_layerNumber] as XYZPlotLayer; } if (null == layer) { return; } if (_plotNumber < layer.PlotItems.Flattened.Length) { var fontInfo = dc.FontCache.GetFontInfo(Style.FontId); IGPlotItem pa = layer.PlotItems.Flattened[_plotNumber]; var symbolpos = new PointD3D(xbase, (ybase + 0.5 * fontInfo.cyDescent - 0.5 * fontInfo.cyAscent), 0); var symbolRect = new RectangleD3D(symbolpos, new VectorD3D(SizeX, 0, 0)); symbolRect = symbolRect.WithPadding(0, fontInfo.Size, 0); pa.PaintSymbol(g, symbolRect); if (!dc.bForPreview) { var volume = new RectangleTransformedD3D( new RectangleD3D(symbolpos.X, symbolpos.Y - 0.5 * fontInfo.cyLineSpace, 0, SizeX, fontInfo.cyLineSpace, 0), dc.transformMatrix); dc._cachedSymbolPositions.Add(volume, pa); } } }
/// <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)); }
/// <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(); } }
/// <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); return(mousePosition.IsHit(rect, out var z)); }
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; var layerRect = new RectangleD3D(PointD3D.Empty, layer.Size); if (_showZeroOnly) { var var = new Altaxo.Data.AltaxoVariant(0.0); double rel = axis.PhysicalVariantToNormal(var); //_majorPen.SetEnvironment(layerRect, BrushX.GetEffectiveMaximumResolution(g, 1)); if (rel >= 0 && rel <= 1) { var 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) { var 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) { var 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); } } }
/// <summary> /// Gets the bounds of the root layer. /// </summary> /// <returns></returns> private RectangleD3D GetViewBounds() { var matrix = _camera.LookAtRHMatrix; var rect = new RectangleD3D(PointD3D.Empty, RootLayer.Size); var bounds = RectangleD3D.NewRectangleIncludingAllPoints(rect.Vertices.Select(x => matrix.Transform(x))); return(bounds); }
public RectangleD3D PaintSymbol(IGraphicsContext3D g, RectangleD3D bounds) { bounds = bounds.WithPadding(0, 0, -bounds.SizeZ / 4); var heightBy2 = new VectorD3D(0, 0, bounds.SizeZ / 4); g.DrawLine(_pen, bounds.Center - heightBy2, bounds.Center + heightBy2); return(bounds); }
public RectangleD3D PaintSymbol(IGraphicsContext3D g, RectangleD3D bounds) { for (int i = _innerList.Count - 1; i >= 0; i--) { bounds = this[i].PaintSymbol(g, bounds); } return(bounds); }
public RectangleD3D PaintSymbol(IGraphicsContext3D g, RectangleD3D bounds) { if (!ScatterSymbols.NoSymbol.Instance.Equals(_symbolShape)) { _symbolShape.Paint(g, _material, bounds.Center, _symbolSize); bounds = bounds.WithPadding(0, Math.Max(0, SymbolSize - bounds.SizeY), Math.Max(0, SymbolSize - bounds.SizeZ)); } return(bounds); }
/// <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 )); }
/// <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); } }
/// <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() { var 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, AbsoluteSize); return(RectangleD3D.NewRectangleIncludingAllPoints(r.Vertices.Select(p => m.Transform(p)))); }
public RectangleD3D AdjustRectangle(RectangleD3D r, Alignment alignmentX, Alignment alignmentY, Alignment alignmentZ) { double rX = r.X; double rY = r.Y; double rZ = r.Z; switch (alignmentZ) { case Alignment.Near: break; case Alignment.Center: rZ -= 0.5 * r.SizeZ; break; case Alignment.Far: rZ -= r.SizeZ; break; } switch (alignmentY) { case Alignment.Near: break; case Alignment.Center: rY -= 0.5 * r.SizeY; break; case Alignment.Far: rY -= r.SizeY; break; } switch (alignmentX) { case Alignment.Near: break; case Alignment.Center: rX -= 0.5 * r.SizeX; break; case Alignment.Far: rX -= r.SizeX; break; } return(new RectangleD3D(rX, rY, rZ, r.SizeX, r.SizeY, r.SizeZ)); }
/// <summary> /// Determines whether a polyline is hit. /// </summary> /// <param name="points">The points that make out the polyline.</param> /// <param name="thickness1">The thickness of the pen in east direction.</param> /// <param name="thickness2">The thickness of the pen in north direction.</param> /// <returns>True if the polyline is hit; otherwise false.</returns> public bool IsHit(IEnumerable <PointD3D> points, double thickness1, double thickness2) { var polyline = PolylineMath3D.GetPolylinePointsWithWestAndNorth(points); var coll = polyline.GetEnumerator(); if (!coll.MoveNext()) { return(false); // no points } double thickness1By2 = thickness1 / 2; double thickness2By2 = thickness2 / 2; var pts = new PointD3D[8]; PointD3D P0 = coll.Current.Position; while (coll.MoveNext()) { var P1 = coll.Current.Position; // end point of current line var e = coll.Current.WestVector; // east vector var n = coll.Current.NorthVector; // north vector pts[0] = _hitTransformation.Transform(P0 - thickness1By2 * e - thickness2By2 * n); pts[1] = _hitTransformation.Transform(P1 - thickness1By2 * e - thickness2By2 * n); pts[2] = _hitTransformation.Transform(P0 + thickness1By2 * e - thickness2By2 * n); pts[3] = _hitTransformation.Transform(P1 + thickness1By2 * e - thickness2By2 * n); pts[4] = _hitTransformation.Transform(P0 - thickness1By2 * e + thickness2By2 * n); pts[5] = _hitTransformation.Transform(P1 - thickness1By2 * e + thickness2By2 * n); pts[6] = _hitTransformation.Transform(P0 + thickness1By2 * e + thickness2By2 * n); pts[7] = _hitTransformation.Transform(P1 + thickness1By2 * e + thickness2By2 * n); foreach (var ti in RectangleD3D.GetTriangleIndices()) { if (HitTestWithAlreadyTransformedPoints(pts[ti.Item1], pts[ti.Item2], pts[ti.Item3], out var z) && z >= 0) { return(true); } } P0 = P1; // take previous point from current point } return(false); }
public override IGripManipulationHandle[] GetGrips(int gripLevel) { if (gripLevel <= 1) { var ls = (LineShape)_hitobject; var pts = new PointD3D[] { PointD3D.Empty, (PointD3D)ls.Size }; for (int i = 0; i < pts.Length; i++) { var pt = ls._transformation.Transform(pts[i]); pt = Transformation.Transform(pt); pts[i] = pt; } var 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(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> /// 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) { var 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); }
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 (_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 (_background != null) { var backgroundRect = _background.Measure(textRectangle); _cachedExtendedTextBounds = backgroundRect.WithRectangleIncluded(textRectangle); // _cachedExtendedTextBounds.WithOffset(textRectangle.X - backgroundRect.X, textRectangle.Y - backgroundRect.Y, 0); ((ItemLocationDirectAutoSize)_location).SetSizeInAutoSizeMode(_cachedExtendedTextBounds.Size, false); _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; } }
public bool IsHit(LineD3D line, double thickness1, double thickness2) { if (!(line.Length > 0)) { return(false); } var eastnorth = PolylineMath3D.GetWestNorthVectors(line); var e = eastnorth.Item1; // east vector var n = eastnorth.Item2; // north vector double thickness1By2 = thickness1 / 2; double thickness2By2 = thickness2 / 2; var pts = new PointD3D[8]; pts[0] = _hitTransformation.Transform(line.P0 - thickness1By2 * e - thickness2By2 * n); pts[1] = _hitTransformation.Transform(line.P1 - thickness1By2 * e - thickness2By2 * n); pts[2] = _hitTransformation.Transform(line.P0 + thickness1By2 * e - thickness2By2 * n); pts[3] = _hitTransformation.Transform(line.P1 + thickness1By2 * e - thickness2By2 * n); pts[4] = _hitTransformation.Transform(line.P0 - thickness1By2 * e + thickness2By2 * n); pts[5] = _hitTransformation.Transform(line.P1 - thickness1By2 * e + thickness2By2 * n); pts[6] = _hitTransformation.Transform(line.P0 + thickness1By2 * e + thickness2By2 * n); pts[7] = _hitTransformation.Transform(line.P1 + thickness1By2 * e + thickness2By2 * n); double z; foreach (var ti in RectangleD3D.GetTriangleIndices()) { if (HitTestWithAlreadyTransformedPoints(pts[ti.Item1], pts[ti.Item2], pts[ti.Item3], out z) && z >= 0) { return(true); } } z = double.NaN; return(false); }
public RectangleD3D PaintSymbol(IGraphicsContext3D g, RectangleD3D bounds) { if (IsVisible) { var gs = g.SaveGraphicsState(); g.TranslateTransform((VectorD3D)bounds.Center); var halfwidth = bounds.SizeX / 2; var symsize = _symbolSize; if (_useSymbolGap) { // plot a line with the length of symbolsize from PaintLine(g, new PointD3D(-halfwidth, 0, 0), new PointD3D(-symsize, 0, 0)); PaintLine(g, new PointD3D(symsize, 0, 0), new PointD3D(halfwidth, 0, 0)); } else // no gap { PaintLine(g, new PointD3D(-halfwidth, 0, 0), new PointD3D(halfwidth, 0, 0)); } g.RestoreGraphicsState(gs); } return(bounds); }
/// <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); }
public RectangleD3D PaintSymbol(IGraphicsContext3D g, RectangleD3D bounds) { if (!ScatterSymbols.NoSymbol.Instance.Equals(_symbolShape)) { _symbolShape.Paint(g, _material, bounds.Center, _symbolSize); bounds = bounds.WithPadding(0, Math.Max(0, this.SymbolSize - bounds.SizeY), Math.Max(0, this.SymbolSize - bounds.SizeZ)); } return bounds; }
/// <summary> /// Paints the axis style labels. /// </summary> /// <param name="g">Graphics environment.</param> /// <param name="coordSyst">The coordinate system. Used to get the path along the axis.</param> /// <param name="scale">Scale.</param> /// <param name="tickSpacing">If not <c>null</c>, this parameter provides a custom tick spacing that is used instead of the default tick spacing of the scale.</param> /// <param name="styleInfo">Information about begin of axis, end of axis.</param> /// <param name="outerDistance">Distance between axis and labels.</param> /// <param name="useMinorTicks">If true, minor ticks are shown.</param> public virtual void Paint(IGraphicsContext3D g, G3DCoordinateSystem coordSyst, Scale scale, TickSpacing tickSpacing, CSAxisInformation styleInfo, double outerDistance, bool useMinorTicks) { _cachedAxisStyleInfo = styleInfo; CSLineID styleID = styleInfo.Identifier; Scale raxis = scale; TickSpacing ticking = tickSpacing; var math = Matrix4x3.Identity; Logical3D r0 = styleID.GetLogicalPoint(styleInfo.LogicalValueAxisOrg); Logical3D r1 = styleID.GetLogicalPoint(styleInfo.LogicalValueAxisEnd); VectorD3D outVector; Logical3D outer; double[] relpositions; AltaxoVariant[] ticks; if (useMinorTicks) { relpositions = ticking.GetMinorTicksNormal(raxis); ticks = ticking.GetMinorTicksAsVariant(); } else { relpositions = ticking.GetMajorTicksNormal(raxis); ticks = ticking.GetMajorTicksAsVariant(); } if (!_suppressedLabels.IsEmpty) { List<AltaxoVariant> filteredTicks = new List<AltaxoVariant>(); List<double> filteredRelPositions = new List<double>(); for (int i = 0; i < ticks.Length; i++) { if (_suppressedLabels.ByValues.Contains(ticks[i])) continue; if (_suppressedLabels.ByNumbers.Contains(i)) continue; if (_suppressedLabels.ByNumbers.Contains(i - ticks.Length)) continue; filteredTicks.Add(ticks[i]); filteredRelPositions.Add(relpositions[i]); } ticks = filteredTicks.ToArray(); relpositions = filteredRelPositions.ToArray(); } IMeasuredLabelItem[] labels = _labelFormatting.GetMeasuredItems(g, _font, ticks); double emSize = _font.Size; CSAxisSide labelSide = null != _labelSide ? _labelSide.Value : styleInfo.PreferredLabelSide; var labelOutlines = new RectangularObjectOutline[ticks.Length]; for (int i = 0; i < ticks.Length; i++) { double r = relpositions[i]; if (!Altaxo.Calc.RMath.IsInIntervalCC(r, -1000, 1000)) continue; outer = coordSyst.GetLogicalDirection(styleID.ParallelAxisNumber, labelSide); PointD3D tickorg = coordSyst.GetPositionAndNormalizedDirection(r0, r1, r, outer, out outVector); PointD3D tickend = tickorg + outVector * outerDistance; var msize = labels[i].Size; var morg = tickend; if (_automaticRotationShift) { // if this option is choosen, we have to find a shift value that shifts the center of the text outwards so that the bounding box of the text will not cross the plane that is // defined by the tickend point and the normal vector outVector // Assume that the text is now centered x, y, and z around the point tickend (but here we use origin instead tickend) math = Matrix4x3.NewRotation(_rotationX, _rotationY, _rotationZ); // we have to find all points with negative distance to the plane spanned by tickend and the vector outVector (but again instead of tickend we use origin) var msizePad = msize + new VectorD3D( (_font.Size * 1) / 3, // whereas above and below text no padding is neccessary, it is optically nicer to have left and right padding of the string by 1/6 of font size. 0, (_font.Size * 1) / 3 // same padding applies to z ); var crect = new RectangleD3D((PointD3D)(-0.5 * msizePad), msizePad); // our text centered around origin double shift = 0; foreach (PointD3D p in crect.Vertices) { PointD3D ps = math.Transform(p); double distance = Math3D.GetDistancePointToPlane(ps, PointD3D.Empty, outVector); if (-distance > shift) shift = -distance; // only negative distances will count here } morg += outVector * shift; } else { morg = morg.WithXPlus(outVector.X * _font.Size / 3); } var mrect = new RectangleD3D(morg, msize); if (_automaticRotationShift) mrect = AdjustRectangle(mrect, Alignment.Center, Alignment.Center, Alignment.Center); else mrect = AdjustRectangle(mrect, _alignmentX, _alignmentY, _alignmentZ); math = Matrix4x3.Identity; math.TranslatePrepend(morg.X, morg.Y, morg.Z); if (this._rotationZ != 0) math.RotationZDegreePrepend(this._rotationZ); if (this._rotationY != 0) math.RotationYDegreePrepend(this._rotationY); if (this._rotationX != 0) math.RotationXDegreePrepend(this._rotationX); math.TranslatePrepend((mrect.X - morg.X + emSize * _offsetX), (mrect.Y - morg.Y + emSize * _offsetY), (mrect.Z - morg.Z + emSize * _offsetZ)); var gs = g.SaveGraphicsState(); g.PrependTransform(math); if (this._backgroundStyle != null) { var itemRectangle = new RectangleD3D(PointD3D.Empty, msize); _backgroundStyle.Measure(itemRectangle); _backgroundStyle.Draw(g, itemRectangle); } labels[i].Draw(g, _brush, PointD3D.Empty); labelOutlines[i] = new RectangularObjectOutline(new RectangleD3D(PointD3D.Empty, msize), math); g.RestoreGraphicsState(gs); // Restore the graphics state } _cachedLabelOutlines = labelOutlines; }
public override void Draw(IGraphicsContext3D g, DrawContext dc, double xbase, double ybase, double zbase) { var mylayer = (HostLayer)dc.LinkedObject; var layer = mylayer as XYZPlotLayer; if (_layerNumber >= 0 && mylayer.SiblingLayers != null && _layerNumber < mylayer.SiblingLayers.Count) layer = mylayer.SiblingLayers[_layerNumber] as XYZPlotLayer; if (null == layer) return; if (_plotNumber < layer.PlotItems.Flattened.Length) { var fontInfo = dc.FontCache.GetFontInfo(Style.FontId); IGPlotItem pa = layer.PlotItems.Flattened[_plotNumber]; PointD3D symbolpos = new PointD3D(xbase, (ybase + 0.5 * fontInfo.cyDescent - 0.5 * fontInfo.cyAscent), 0); RectangleD3D symbolRect = new RectangleD3D(symbolpos, new VectorD3D(SizeX, 0, 0)); symbolRect = symbolRect.WithPadding(0, fontInfo.Size, 0); pa.PaintSymbol(g, symbolRect); if (!dc.bForPreview) { var volume = new RectangleTransformedD3D( new RectangleD3D(symbolpos.X, symbolpos.Y - 0.5 * fontInfo.cyLineSpace, 0, SizeX, fontInfo.cyLineSpace, 0), dc.transformMatrix); dc._cachedSymbolPositions.Add(volume, pa); } } }
public RectangleD3D PaintSymbol(IGraphicsContext3D g, RectangleD3D bounds) { // this is not a visible style, thus doing nothing return RectangleD3D.Empty; }
public RectangleD3D PaintSymbol(IGraphicsContext3D g, RectangleD3D bounds) { // this is not a visible style, thus doing nothing return(RectangleD3D.Empty); }
/// <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)); }
/// <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)); }
public RectangleD3D GetBounds() { return(RectangleD3D.NewRectangleIncludingAllPoints(AsPoints())); }
public RectangularObjectOutline(RectangleD3D rectangle, Matrix4x3 transformation) { _rectangle = rectangle; _transformation = transformation; }
public override void PaintSymbol(IGraphicsContext3D g, RectangleD3D location) { _plotStyles.PaintSymbol(g, location); }
public RectangleD3D GetBounds(Matrix3x3 transformation) { return(RectangleD3D.NewRectangleIncludingAllPoints(AsPoints().Select(p => transformation.Transform(p)))); }
/// <summary> /// Paints the axis style labels. /// </summary> /// <param name="g">Graphics environment.</param> /// <param name="coordSyst">The coordinate system. Used to get the path along the axis.</param> /// <param name="scale">Scale.</param> /// <param name="tickSpacing">If not <c>null</c>, this parameter provides a custom tick spacing that is used instead of the default tick spacing of the scale.</param> /// <param name="styleInfo">Information about begin of axis, end of axis.</param> /// <param name="outerDistance">Distance between axis and labels.</param> /// <param name="useMinorTicks">If true, minor ticks are shown.</param> public virtual void Paint(IGraphicsContext3D g, G3DCoordinateSystem coordSyst, Scale scale, TickSpacing tickSpacing, CSAxisInformation styleInfo, double outerDistance, bool useMinorTicks) { _cachedAxisStyleInfo = styleInfo; CSLineID styleID = styleInfo.Identifier; Scale raxis = scale; TickSpacing ticking = tickSpacing; var math = Matrix4x3.Identity; Logical3D r0 = styleID.GetLogicalPoint(styleInfo.LogicalValueAxisOrg); Logical3D r1 = styleID.GetLogicalPoint(styleInfo.LogicalValueAxisEnd); Logical3D outer; double[] relpositions; AltaxoVariant[] ticks; if (useMinorTicks) { relpositions = ticking.GetMinorTicksNormal(raxis); ticks = ticking.GetMinorTicksAsVariant(); } else { relpositions = ticking.GetMajorTicksNormal(raxis); ticks = ticking.GetMajorTicksAsVariant(); } if (!_suppressedLabels.IsEmpty) { var filteredTicks = new List <AltaxoVariant>(); var filteredRelPositions = new List <double>(); for (int i = 0; i < ticks.Length; i++) { if (_suppressedLabels.ByValues.Contains(ticks[i])) { continue; } if (_suppressedLabels.ByNumbers.Contains(i)) { continue; } if (_suppressedLabels.ByNumbers.Contains(i - ticks.Length)) { continue; } filteredTicks.Add(ticks[i]); filteredRelPositions.Add(relpositions[i]); } ticks = filteredTicks.ToArray(); relpositions = filteredRelPositions.ToArray(); } IMeasuredLabelItem[] labels = _labelFormatting.GetMeasuredItems(g, _font, ticks); double emSize = _font.Size; CSAxisSide labelSide = null != _labelSide ? _labelSide.Value : styleInfo.PreferredLabelSide; var labelOutlines = new RectangularObjectOutline[ticks.Length]; for (int i = 0; i < ticks.Length; i++) { double r = relpositions[i]; if (!Altaxo.Calc.RMath.IsInIntervalCC(r, -1000, 1000)) { continue; } outer = coordSyst.GetLogicalDirection(styleID.ParallelAxisNumber, labelSide); PointD3D tickorg = coordSyst.GetPositionAndNormalizedDirection(r0, r1, r, outer, out var outVector); PointD3D tickend = tickorg + outVector * outerDistance; var msize = labels[i].Size; var morg = tickend; if (_automaticRotationShift) { // if this option is choosen, we have to find a shift value that shifts the center of the text outwards so that the bounding box of the text will not cross the plane that is // defined by the tickend point and the normal vector outVector // Assume that the text is now centered x, y, and z around the point tickend (but here we use origin instead tickend) math = Matrix4x3.NewRotation(_rotationX, _rotationY, _rotationZ); // we have to find all points with negative distance to the plane spanned by tickend and the vector outVector (but again instead of tickend we use origin) var msizePad = msize + new VectorD3D( (_font.Size * 1) / 3, // whereas above and below text no padding is neccessary, it is optically nicer to have left and right padding of the string by 1/6 of font size. 0, (_font.Size * 1) / 3 // same padding applies to z ); var crect = new RectangleD3D((PointD3D)(-0.5 * msizePad), msizePad); // our text centered around origin double shift = 0; foreach (PointD3D p in crect.Vertices) { PointD3D ps = math.Transform(p); double distance = Math3D.GetDistancePointToPlane(ps, PointD3D.Empty, outVector); if (-distance > shift) { shift = -distance; // only negative distances will count here } } morg += outVector * shift; } else { morg = morg.WithXPlus(outVector.X * _font.Size / 3); } var mrect = new RectangleD3D(morg, msize); if (_automaticRotationShift) { mrect = AdjustRectangle(mrect, Alignment.Center, Alignment.Center, Alignment.Center); } else { mrect = AdjustRectangle(mrect, _alignmentX, _alignmentY, _alignmentZ); } math = Matrix4x3.Identity; math.TranslatePrepend(morg.X, morg.Y, morg.Z); if (_rotationZ != 0) { math.RotationZDegreePrepend(_rotationZ); } if (_rotationY != 0) { math.RotationYDegreePrepend(_rotationY); } if (_rotationX != 0) { math.RotationXDegreePrepend(_rotationX); } math.TranslatePrepend((mrect.X - morg.X + emSize * _offsetX), (mrect.Y - morg.Y + emSize * _offsetY), (mrect.Z - morg.Z + emSize * _offsetZ)); var gs = g.SaveGraphicsState(); g.PrependTransform(math); if (_backgroundStyle != null) { var itemRectangle = new RectangleD3D(PointD3D.Empty, msize); _backgroundStyle.Measure(itemRectangle); _backgroundStyle.Draw(g, itemRectangle); } labels[i].Draw(g, _brush, PointD3D.Empty); labelOutlines[i] = new RectangularObjectOutline(new RectangleD3D(PointD3D.Empty, msize), math); g.RestoreGraphicsState(gs); // Restore the graphics state } _cachedLabelOutlines = labelOutlines; }
/// <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)); }
public RectangleD3D AdjustRectangle(RectangleD3D r, Alignment alignmentX, Alignment alignmentY, Alignment alignmentZ) { double rX = r.X; double rY = r.Y; double rZ = r.Z; switch (alignmentZ) { case Alignment.Near: break; case Alignment.Center: rZ -= 0.5 * r.SizeZ; break; case Alignment.Far: rZ -= r.SizeZ; break; } switch (alignmentY) { case Alignment.Near: break; case Alignment.Center: rY -= 0.5 * r.SizeY; break; case Alignment.Far: rY -= r.SizeY; break; } switch (alignmentX) { case Alignment.Near: break; case Alignment.Center: rX -= 0.5 * r.SizeX; break; case Alignment.Far: rX -= r.SizeX; break; } return new RectangleD3D(rX, rY, rZ, r.SizeX, r.SizeY, r.SizeZ); }
/// <summary> /// Paints a appropriate symbol in the given rectangle. The width of the rectangle is mandatory, but if the heigth is too small, /// you should extend the bounding rectangle and set it as return value of this function. /// </summary> /// <param name="g">The graphics context.</param> /// <param name="bounds">The bounds, in which the symbol should be painted.</param> /// <returns>If the height of the bounding rectangle is sufficient for painting, returns the original bounding rectangle. Otherwise, it returns a rectangle that is /// inflated in y-Direction. Do not inflate the rectangle in x-direction!</returns> public RectangleD3D PaintSymbol(IGraphicsContext3D g, RectangleD3D bounds) { return(RectangleD3D.Empty); }
/// <summary> /// Paints a symbol for this plot item for use in a legend. /// </summary> /// <param name="g">The graphics context.</param> /// <param name="location">The rectangle where the symbol should be painted into.</param> public virtual void PaintSymbol(IGraphicsContext3D g, RectangleD3D location) { }
public RectangleD3D PaintSymbol(IGraphicsContext3D g, RectangleD3D bounds) { return RectangleD3D.Empty; }
public RectangleD3D PaintSymbol(IGraphicsContext3D g, RectangleD3D bounds) { bounds = bounds.WithPadding(0, 0, -bounds.SizeZ / 4); var heightBy2 = new VectorD3D(0, 0, bounds.SizeZ / 4); g.DrawLine(_pen, bounds.Center - heightBy2, bounds.Center + heightBy2); return bounds; }
public RectangleD3D PaintSymbol(IGraphicsContext3D g, RectangleD3D bounds) { if (IsVisible) { var gs = g.SaveGraphicsState(); g.TranslateTransform((VectorD3D)bounds.Center); var halfwidth = bounds.SizeX / 2; var symsize = _symbolSize; if (_useSymbolGap) { // plot a line with the length of symbolsize from PaintLine(g, new PointD3D(-halfwidth, 0, 0), new PointD3D(-symsize, 0, 0)); PaintLine(g, new PointD3D(symsize, 0, 0), new PointD3D(halfwidth, 0, 0)); } else // no gap { PaintLine(g, new PointD3D(-halfwidth, 0, 0), new PointD3D(halfwidth, 0, 0)); } g.RestoreGraphicsState(gs); } return bounds; }