protected override PointF ConstrainControlPointLocation(int controlPointIndex, PointF cursorLocation) { // this operation must be performed in source coodinates because the definition of top/left/right/bottom controls are relative to image not tile! var sourcePoint = SpatialTransform.ConvertToSource(cursorLocation); CoordinateSystem = CoordinateSystem.Source; try { var rect = Subject.Rectangle; switch (controlPointIndex) { case _top: case _bottom: return(SpatialTransform.ConvertToDestination(new PointF(rect.Left + rect.Width / 2, sourcePoint.Y))); case _left: case _right: return(SpatialTransform.ConvertToDestination(new PointF(sourcePoint.X, rect.Top + rect.Height / 2))); } } finally { ResetCoordinateSystem(); } return(base.ConstrainControlPointLocation(controlPointIndex, cursorLocation)); }
/// <summary> /// Gets the vectors describing the tick marks in source coordinates. /// </summary> private void GetTickVectors(out SizeF majorTickVector, out SizeF minorTickVector) { // compute tick vectors in display coordinates (since they are effectively invariant graphics) // but then convert them back to source coordinates because the graphics all use source coordinates CoordinateSystem = CoordinateSystem.Destination; try { var pt0 = Point1; var pt1 = Point2; // compute normal to the base line var normalX = (double)pt0.Y - pt1.Y; var normalY = (double)pt1.X - pt0.X; var normalMagnitude = Math.Sqrt(normalX * normalX + normalY * normalY); var normalUnit = new SizeF((float)(Math.Abs(normalX) / normalMagnitude), (float)(Math.Abs(normalY) / normalMagnitude)); var majorTickLength = _isMirrored ? -_majorTickLength : _majorTickLength; var minorTickLength = _isMirrored ? -_minorTickLength : _minorTickLength; majorTickVector = SpatialTransform.ConvertToSource(new SizeF(majorTickLength * normalUnit.Width, majorTickLength * normalUnit.Height)); minorTickVector = SpatialTransform.ConvertToSource(new SizeF(minorTickLength * normalUnit.Width, minorTickLength * normalUnit.Height)); } finally { ResetCoordinateSystem(); } }
/// <summary> /// Sets both endpoints of the scale's base line segment in one atomic operation, cause only one update and draw. /// </summary> /// <param name="point1">One endpoint of the base line segment.</param> /// <param name="point2">The other endpoint of the base line segment.</param> public void SetEndPoints(PointF point1, PointF point2) { if (CoordinateSystem != CoordinateSystem.Source) { point1 = SpatialTransform.ConvertToSource(point1); point2 = SpatialTransform.ConvertToSource(point2); } if (point1 != _point1 || point2 != _point2) { _point1 = point1; _point2 = point2; FlagAsDirty(); } }
private void IncrementPan(int xIncrement, int yIncrement) { if (!CanPan()) { return; } SpatialTransform transform = (SpatialTransform)_operation.GetOriginator(this.SelectedPresentationImage); // Because the pan increment is in destination coordinates, we have to convert // them to source coordinates, since the transform translation is in source coordinates. // This will allow the pan to work properly irrespective of the zoom, flip and rotation. SizeF sourceIncrement = transform.ConvertToSource(new SizeF(xIncrement, yIncrement)); transform.TranslationX += sourceIncrement.Width; transform.TranslationY += sourceIncrement.Height; this.SelectedPresentationImage.Draw(); }
/// <summary> /// Called to notify the derived class of a control point change event. /// </summary> /// <param name="index">The index of the point that changed.</param> /// <param name="point">The value of the point that changed.</param> protected override void OnControlPointChanged(int index, PointF point) { // this operation must be performed in source coodinates because the definition of top-left/bottom-left/top-right/bottom-right controls are relative to image not tile! var sourcePoint = CoordinateSystem == CoordinateSystem.Destination ? SpatialTransform.ConvertToSource(point) : point; CoordinateSystem = CoordinateSystem.Source; try { var subject = Subject; var rect = subject.Rectangle; switch (index) { case _topLeft: subject.TopLeft = sourcePoint; break; case _bottomRight: subject.BottomRight = sourcePoint; break; case _topRight: subject.TopLeft = new PointF(rect.Left, sourcePoint.Y); subject.BottomRight = new PointF(sourcePoint.X, rect.Bottom); break; case _bottomLeft: subject.TopLeft = new PointF(sourcePoint.X, rect.Top); subject.BottomRight = new PointF(rect.Right, sourcePoint.Y); break; } } finally { ResetCoordinateSystem(); } base.OnControlPointChanged(index, point); }
private static void SerializeDashedLine(PointF point1, PointF point2, SpatialTransform spatialTransform, GraphicAnnotationSequenceItem serializationState, bool showHashes) { // these control parameters are in screen pixels at the nominal presentation zoom level const float period = 8; const float amplitude = 0.5f; SizeF normalVector; SizeF dashVector; float periods; // compute the dash vector and cross hash vector to be sized relative to screen pixels at nominal presentation zoom level { PointF dstLineVector = spatialTransform.ConvertToDestination(new SizeF(point2) - new SizeF(point1)).ToPointF(); float dstMagnitude = (float)Math.Sqrt(dstLineVector.X * dstLineVector.X + dstLineVector.Y * dstLineVector.Y); periods = dstMagnitude / period; dstLineVector.X /= dstMagnitude; dstLineVector.Y /= dstMagnitude; dashVector = spatialTransform.ConvertToSource(new SizeF(dstLineVector.X * period / 2, dstLineVector.Y * period / 2)); normalVector = spatialTransform.ConvertToSource(new SizeF(-dstLineVector.Y * amplitude, dstLineVector.X * amplitude)); } PointF start = point1; int limit = (int)periods; for (int n = 0; n < limit; n++) { PointF midPeriod = start + dashVector; start = midPeriod + dashVector; GraphicObject dash = new GraphicObject(); dash.GraphicAnnotationUnits = GraphicAnnotationSequenceItem.GraphicAnnotationUnits.Pixel; dash.GraphicData = new PointF[] { midPeriod, start }; dash.GraphicDimensions = 2; dash.GraphicFilled = GraphicAnnotationSequenceItem.GraphicFilled.N; dash.GraphicType = GraphicAnnotationSequenceItem.GraphicType.Polyline; dash.NumberOfGraphicPoints = 2; serializationState.AppendGraphicObjectSequence(dash); } // the first half of each period has no line, so this is only necessary if the residual is over half a period if (periods - limit > 0.5f) { GraphicObject dash = new GraphicObject(); dash.GraphicAnnotationUnits = GraphicAnnotationSequenceItem.GraphicAnnotationUnits.Pixel; dash.GraphicData = new PointF[] { start + dashVector, point2 }; dash.GraphicDimensions = 2; dash.GraphicFilled = GraphicAnnotationSequenceItem.GraphicFilled.N; dash.GraphicType = GraphicAnnotationSequenceItem.GraphicType.Polyline; dash.NumberOfGraphicPoints = 2; serializationState.AppendGraphicObjectSequence(dash); } if (showHashes) { GraphicObject hash1 = new GraphicObject(); hash1.GraphicAnnotationUnits = GraphicAnnotationSequenceItem.GraphicAnnotationUnits.Pixel; hash1.GraphicData = new PointF[] { point1 - normalVector, point1 + normalVector }; hash1.GraphicDimensions = 2; hash1.GraphicFilled = GraphicAnnotationSequenceItem.GraphicFilled.N; hash1.GraphicType = GraphicAnnotationSequenceItem.GraphicType.Polyline; hash1.NumberOfGraphicPoints = 2; serializationState.AppendGraphicObjectSequence(hash1); GraphicObject hash2 = new GraphicObject(); hash2.GraphicAnnotationUnits = GraphicAnnotationSequenceItem.GraphicAnnotationUnits.Pixel; hash2.GraphicData = new PointF[] { point2 - normalVector, point2 + normalVector }; hash2.GraphicDimensions = 2; hash2.GraphicFilled = GraphicAnnotationSequenceItem.GraphicFilled.N; hash2.GraphicType = GraphicAnnotationSequenceItem.GraphicType.Polyline; hash2.NumberOfGraphicPoints = 2; serializationState.AppendGraphicObjectSequence(hash2); } }