public GCodeRenderInfo(int startLayerIndex, int endLayerIndex, Affine transform, double layerScale, RenderType renderType, double featureToStartOnRatio0To1, double featureToEndOnRatio0To1, Vector2[] extruderOffsets) { this.startLayerIndex = startLayerIndex; this.endLayerIndex = endLayerIndex; this.transform = transform; this.layerScale = layerScale; this.currentRenderType = renderType; this.featureToStartOnRatio0To1 = featureToStartOnRatio0To1; this.featureToEndOnRatio0To1 = featureToEndOnRatio0To1; this.extruderOffsets = extruderOffsets; }
public void invert_test() { Affine a = Affine.NewIdentity(); a.translate(10, 10); Affine b = new Affine(a); b.invert(); double x = 100; double y = 100; double newx = x; double newy = y; a.transform(ref newx, ref newy); b.transform(ref newx, ref newy); Assert.AreEqual(x, newx, .001); Assert.AreEqual(y, newy, .001); }
//------------------------------------------ Construction public Affine(Affine copyFrom) { sx = copyFrom.sx; shy = copyFrom.shy; shx = copyFrom.shx; sy = copyFrom.sy; tx = copyFrom.tx; ty = copyFrom.ty; }
// Check to see if two matrices are equal public bool is_equal(Affine m, double epsilon) { return agg_basics.is_equal_eps(sx, m.sx, epsilon) && agg_basics.is_equal_eps(shy, m.shy, epsilon) && agg_basics.is_equal_eps(shx, m.shx, epsilon) && agg_basics.is_equal_eps(sy, m.sy, epsilon) && agg_basics.is_equal_eps(tx, m.tx, epsilon) && agg_basics.is_equal_eps(ty, m.ty, epsilon); }
/* // Mirroring around X trans_affine flip_x() { sx = -sx; shy = -shy; tx = -tx; return *this; } // Mirroring around Y trans_affine flip_y() { shx = -shx; sy = -sy; ty = -ty; return *this; } //------------------------------------------- Load/Store // Store matrix to an array [6] of double void store_to(double* m) { *m++ = sx; *m++ = shy; *m++ = shx; *m++ = sy; *m++ = tx; *m++ = ty; } // Load matrix from an array [6] of double trans_affine load_from(double* m) { sx = *m++; shy = *m++; shx = *m++; sy = *m++; tx = *m++; ty = *m++; return *this; } //------------------------------------------- Operators */ // Multiply the matrix by another one and return // the result in a separate matrix. public static Affine operator *(Affine a, Affine b) { Affine temp = new Affine(a); temp.multiply(b); return temp; }
// Identity matrix public static Affine NewIdentity() { Affine newAffine = new Affine(); newAffine.sx = 1.0; newAffine.shy = 0.0; newAffine.shx = 0.0; newAffine.sy = 1.0; newAffine.tx = 0.0; newAffine.ty = 0.0; return newAffine; }
private void DrawImageGetDestBounds(IImageByte sourceImage, double DestX, double DestY, double HotspotOffsetX, double HotspotOffsetY, double ScaleX, double ScaleY, double AngleRad, out Affine destRectTransform) { destRectTransform = Affine.NewIdentity(); if (HotspotOffsetX != 0.0f || HotspotOffsetY != 0.0f) { destRectTransform *= Affine.NewTranslation(-HotspotOffsetX, -HotspotOffsetY); } if (ScaleX != 1 || ScaleY != 1) { destRectTransform *= Affine.NewScaling(ScaleX, ScaleY); } if (AngleRad != 0) { destRectTransform *= Affine.NewRotation(AngleRad); } if (DestX != 0 || DestY != 0) { destRectTransform *= Affine.NewTranslation(DestX, DestY); } int SourceBufferWidth = (int)sourceImage.Width; int SourceBufferHeight = (int)sourceImage.Height; drawImageRectPath.remove_all(); drawImageRectPath.MoveTo(0, 0); drawImageRectPath.LineTo(SourceBufferWidth, 0); drawImageRectPath.LineTo(SourceBufferWidth, SourceBufferHeight); drawImageRectPath.LineTo(0, SourceBufferHeight); drawImageRectPath.ClosePolygon(); }
private void DrawImage(IImageByte sourceImage, ISpanGenerator spanImageFilter, Affine destRectTransform) { if (destImageByte.OriginOffset.x != 0 || destImageByte.OriginOffset.y != 0) { destRectTransform *= Affine.NewTranslation(-destImageByte.OriginOffset.x, -destImageByte.OriginOffset.y); } VertexSourceApplyTransform transformedRect = new VertexSourceApplyTransform(drawImageRectPath, destRectTransform); Rasterizer.add_path(transformedRect); { ImageClippingProxy destImageWithClipping = new ImageClippingProxy(destImageByte); scanlineRenderer.GenerateAndRender(Rasterizer, drawImageScanlineCache, destImageWithClipping, destImageSpanAllocatorCache, spanImageFilter); } }
// From affine public Perspective(Affine a) { sx = (a.sx); shy = (a.shy); w0 = (0); shx = (a.shx); sy = (a.sy); w1 = (0); tx = (a.tx); ty = (a.ty); w2 = (1); }
public void Render(Graphics2D graphics2D, int activeLayerIndex, Affine transform, double layerScale, RenderType renderType, double featureToStartOnRatio0To1, double featureToEndOnRatio0To1) { if (renderFeatures.Count > 0) { CreateFeaturesForLayerIfRequired(activeLayerIndex); int featuresOnLayer = renderFeatures[activeLayerIndex].Count; int endFeature = (int)(featuresOnLayer * featureToEndOnRatio0To1 + .5); endFeature = Math.Max(0, Math.Min(endFeature, featuresOnLayer)); int startFeature = (int)(featuresOnLayer * featureToStartOnRatio0To1 + .5); startFeature = Math.Max(0, Math.Min(startFeature, featuresOnLayer)); // try to make sure we always draw at least one feature if (endFeature <= startFeature) { endFeature = Math.Min(startFeature + 1, featuresOnLayer); } if (startFeature >= endFeature) { // This can only happen if the sart and end are set to the last feature // Try to set the start feture to one from the end startFeature = Math.Max(endFeature - 1, 0); } for (int i = startFeature; i < endFeature; i++) { RenderFeatureBase feature = renderFeatures[activeLayerIndex][i]; feature.Render(graphics2D, transform, layerScale, renderType); } } }
public override void Render(Graphics2D graphics2D, Affine transform, double layerScale, RenderType renderType) { if ((renderType & RenderType.Extrusions) == RenderType.Extrusions) { double extrusionLineWidths = 0.2 * layerScale; RGBA_Bytes extrusionColor = RGBA_Bytes.Black; //extrusionColor = color; PathStorage pathStorage = new PathStorage(); VertexSourceApplyTransform transformedPathStorage = new VertexSourceApplyTransform(pathStorage, transform); Stroke stroke = new Stroke(transformedPathStorage, extrusionLineWidths); stroke.line_cap(LineCap.Round); stroke.line_join(LineJoin.Round); pathStorage.Add(start.x, start.y, ShapePath.FlagsAndCommand.CommandMoveTo); pathStorage.Add(end.x, end.y, ShapePath.FlagsAndCommand.CommandLineTo); graphics2D.Render(stroke, 0, extrusionColor); } }
public override void CreateRender3DData(VectorPOD<ColorVertexData> colorVertexData, VectorPOD<uint> indexData, Affine transform, double layerScale, RenderType renderType) { if ((renderType & RenderType.Extrusions) == RenderType.Extrusions) { double area = extrusionVolumeMm3 / ((end - start).Length); double radius = Math.Sqrt(area / Math.PI); #if false CreateCylinder(colorVertexData, indexData, new Vector3(start), new Vector3(end), radius, 6, GCodeRenderer.ExtrusionColor, layerHeight); #else CreateCylinder(colorVertexData, indexData, new Vector3(start), new Vector3(end), radius, 6, color, layerHeight); #endif } }
public override void Render(Graphics2D graphics2D, Affine transform, double layerScale, RenderType renderType) { if ((renderType & RenderType.Moves) == RenderType.Moves) { double movementLineWidth = 0.35 * layerScale; RGBA_Bytes movementColor = new RGBA_Bytes(10, 190, 15); PathStorage pathStorage = new PathStorage(); VertexSourceApplyTransform transformedPathStorage = new VertexSourceApplyTransform(pathStorage, transform); Stroke stroke = new Stroke(transformedPathStorage, movementLineWidth); stroke.line_cap(LineCap.Round); stroke.line_join(LineJoin.Round); pathStorage.Add(start.x, start.y, ShapePath.FlagsAndCommand.CommandMoveTo); if (end.x != start.x || end.y != start.y) { pathStorage.Add(end.x, end.y, ShapePath.FlagsAndCommand.CommandLineTo); } else { pathStorage.Add(end.x + .01, end.y, ShapePath.FlagsAndCommand.CommandLineTo); } graphics2D.Render(stroke, 0, movementColor); } }
public override void CreateRender3DData(VectorPOD<ColorVertexData> colorVertexData, VectorPOD<uint> indexData, Affine transform, double layerScale, RenderType renderType) { if ((renderType & RenderType.Moves) == RenderType.Moves) { CreateCylinder(colorVertexData, indexData, new Vector3(start), new Vector3(end), .1, 6, GCodeRenderer.TravelColor, .2); } }
public override void Render(Graphics2D graphics2D, Affine transform, double layerScale, RenderType renderType) { if ((renderType & RenderType.Retractions) == RenderType.Retractions) { Vector2 position = new Vector2(this.position.x, this.position.y); transform.transform(ref position); double radius = Radius(layerScale); Ellipse extrusion = new Ellipse(position, radius); if (extrusionAmount > 0) { // unretraction graphics2D.Render(extrusion, new RGBA_Bytes(RGBA_Bytes.Blue, 200)); } else { // retraction graphics2D.Render(extrusion, new RGBA_Bytes(RGBA_Bytes.Red, 200)); } } }
// Multiply inverse of "m" by "this" and assign the result to "this" public Perspective premultiply_inv(Affine m) { Perspective t=new Perspective(m); t.invert(); Set(t.multiply(this)); return this; }
void Create3DData(Affine transform, double layerScale, RenderType renderType, int lastLayerIndex) { colorVertexData.Clear(); vertexIndexArray.Clear(); layerStartIndex.Clear(); layerStartIndex.Capacity = gCodeFileToDraw.NumChangesInZ; featureStartIndex.Clear(); layerStartIndex.Capacity = gCodeFileToDraw.NumChangesInZ; bool canOnlyShowOneLayer = TotalRenderFeatures > MAX_RENDER_FEATURES_TO_ALLOW_3D; if (canOnlyShowOneLayer) { layerStartIndex.Add(vertexIndexArray.Count); for (int layerIndex = 0; layerIndex < lastLayerIndex+1; layerIndex++) { featureStartIndex.Add(new List<int>()); } for (int i = 0; i < renderFeatures[lastLayerIndex].Count; i++) { featureStartIndex[lastLayerIndex].Add(vertexIndexArray.Count); RenderFeatureBase feature = renderFeatures[lastLayerIndex][i]; feature.CreateRender3DData(colorVertexData, vertexIndexArray, transform, layerScale, renderType); } singleLayerIndex = lastLayerIndex; } else { for (int layerIndex = 0; layerIndex < gCodeFileToDraw.NumChangesInZ; layerIndex++) { layerStartIndex.Add(vertexIndexArray.Count); featureStartIndex.Add(new List<int>()); for (int i = 0; i < renderFeatures[layerIndex].Count; i++) { featureStartIndex[layerIndex].Add(vertexIndexArray.Count); RenderFeatureBase feature = renderFeatures[layerIndex][i]; feature.CreateRender3DData(colorVertexData, vertexIndexArray, transform, layerScale, renderType); } } } }
public override void OnDraw(Graphics2D graphics2D) { ImageBuffer widgetsSubImage = ImageBuffer.NewSubImageReference(graphics2D.DestImage, graphics2D.GetClippingRect()); ScanlineRasterizer ras = new ScanlineRasterizer(); scanline_unpacked_8 sl = new scanline_unpacked_8(); ImageClippingProxy clippingProxy = new ImageClippingProxy(widgetsSubImage); clippingProxy.clear(new RGBA_Floats(0, 0, 0)); m_profile.text_size(8.0); // draw a background to show how the alpha is working int RectWidth = 32; int xoffset = 238; int yoffset = 171; ScanlineRenderer scanlineRenderer = new ScanlineRenderer(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if ((i + j) % 2 != 0) { VertexSource.RoundedRect rect = new VertexSource.RoundedRect(i * RectWidth + xoffset, j * RectWidth + yoffset, (i + 1) * RectWidth + xoffset, (j + 1) * RectWidth + yoffset, 2); rect.normalize_radius(); ras.add_path(rect); scanlineRenderer.render_scanlines_aa_solid(clippingProxy, ras, sl, new RGBA_Bytes(.9, .9, .9)); } } } double ini_scale = 1.0; Transform.Affine mtx1 = Affine.NewIdentity(); mtx1 *= Affine.NewScaling(ini_scale, ini_scale); mtx1 *= Affine.NewTranslation(center_x, center_y); VertexSource.Ellipse e1 = new MatterHackers.Agg.VertexSource.Ellipse(); e1.init(0.0, 0.0, 110.0, 110.0, 64); Transform.Affine mtx_g1 = Affine.NewIdentity(); mtx_g1 *= Affine.NewScaling(ini_scale, ini_scale); mtx_g1 *= Affine.NewScaling(m_SaveData.m_scale, m_SaveData.m_scale); mtx_g1 *= Affine.NewScaling(m_scale_x, m_scale_y); mtx_g1 *= Affine.NewRotation(m_SaveData.m_angle); mtx_g1 *= Affine.NewTranslation(m_SaveData.m_center_x, m_SaveData.m_center_y); mtx_g1.invert(); RGBA_Bytes[] color_profile = new RGBA_Bytes[256]; // color_type is defined in pixel_formats.h for (int i = 0; i < 256; i++) { color_profile[i] = new RGBA_Bytes(m_spline_r.spline()[i], m_spline_g.spline()[i], m_spline_b.spline()[i], m_spline_a.spline()[i]); } VertexSourceApplyTransform t1 = new VertexSourceApplyTransform(e1, mtx1); IGradient innerGradient = null; switch (m_GradTypeRBox.SelectedIndex) { case 0: innerGradient = new gradient_radial(); break; case 1: innerGradient = new gradient_diamond(); break; case 2: innerGradient = new gradient_x(); break; case 3: innerGradient = new gradient_xy(); break; case 4: innerGradient = new gradient_sqrt_xy(); break; case 5: innerGradient = new gradient_conic(); break; } IGradient outerGradient = null; switch (m_GradWrapRBox.SelectedIndex) { case 0: outerGradient = new gradient_reflect_adaptor(innerGradient); break; case 1: outerGradient = new gradient_repeat_adaptor(innerGradient); break; case 2: outerGradient = new gradient_clamp_adaptor(innerGradient); break; } span_allocator span_alloc = new span_allocator(); color_function_profile colors = new color_function_profile(color_profile, m_profile.gamma()); span_interpolator_linear inter = new span_interpolator_linear(mtx_g1); span_gradient span_gen = new span_gradient(inter, outerGradient, colors, 0, 150); ras.add_path(t1); scanlineRenderer.GenerateAndRender(ras, sl, clippingProxy, span_alloc, span_gen); base.OnDraw(graphics2D); }
public void Render3D(int startLayerIndex, int endLayerIndex, Affine transform, double layerScale, RenderType renderType, double featureToStartOnRatio0To1, double featureToEndOnRatio0To1) { for (int layerIndex = 0; layerIndex < gCodeFileToDraw.NumChangesInZ; layerIndex++) { CreateFeaturesForLayerIfRequired(layerIndex); } if (renderFeatures.Count > 0) { bool canOnlyShowOneLayer = TotalRenderFeatures > MAX_RENDER_FEATURES_TO_ALLOW_3D; // If its the first render or we change what we are trying to render then create vertex data. if (colorVertexData.Count == 0 || lastRenderType != renderType || (canOnlyShowOneLayer && endLayerIndex-1 != singleLayerIndex)) { Create3DData(transform, layerScale, renderType, endLayerIndex-1); vertexBuffer = new VertexBuffer(); vertexBuffer.SetVertexData(colorVertexData.Array); vertexBuffer.SetIndexData(vertexIndexArray.Array); lastRenderType = renderType; } GL.DisableClientState(ArrayCap.TextureCoordArray); GL.PushAttrib(AttribMask.EnableBit); GL.Enable(EnableCap.PolygonSmooth); //GL.InterleavedArrays(InterleavedArrayFormat.C4fN3fV3f, 0, colorVertexData.Array); // draw all the layers from start to end-2 if (endLayerIndex - 1 > startLayerIndex && !canOnlyShowOneLayer) { int ellementCount = layerStartIndex[endLayerIndex - 1] - layerStartIndex[startLayerIndex]; vertexBuffer.renderRange(layerStartIndex[startLayerIndex], ellementCount); } // draw the partial layer of end-1 from startratio to endratio { int layerIndex = endLayerIndex - 1; int featuresOnLayer = renderFeatures[layerIndex].Count; int startFeature = (int)(featuresOnLayer * featureToStartOnRatio0To1 + .5); startFeature = Math.Max(0, Math.Min(startFeature, featuresOnLayer)); int endFeature = (int)(featuresOnLayer * featureToEndOnRatio0To1 + .5); endFeature = Math.Max(0, Math.Min(endFeature, featuresOnLayer)); // try to make sure we always draw at least one feature if (endFeature <= startFeature) { endFeature = Math.Min(startFeature + 1, featuresOnLayer); } if (startFeature >= endFeature) { // This can only happen if the sart and end are set to the last feature // Try to set the start feture to one from the end startFeature = Math.Max(endFeature - 1, 0); } if (endFeature > startFeature) { int ellementCount = featureStartIndex[layerIndex][endFeature - 1] - featureStartIndex[layerIndex][startFeature]; vertexBuffer.renderRange(featureStartIndex[layerIndex][startFeature], ellementCount); } } GL.PopAttrib(); } }
public override void Render(IImageByte source, double destX, double destY, double angleRadians, double inScaleX, double inScaleY) { { // exit early if the dest and source bounds don't touch. // TODO: <BUG> make this do rotation and scalling RectangleInt sourceBounds = source.GetBounds(); RectangleInt destBounds = this.destImageByte.GetBounds(); sourceBounds.Offset((int)destX, (int)destY); if (!RectangleInt.DoIntersect(sourceBounds, destBounds)) { if (inScaleX != 1 || inScaleY != 1 || angleRadians != 0) { throw new NotImplementedException(); } return; } } double scaleX = inScaleX; double scaleY = inScaleY; Affine graphicsTransform = GetTransform(); if (!graphicsTransform.is_identity()) { if (scaleX != 1 || scaleY != 1 || angleRadians != 0) { throw new NotImplementedException(); } graphicsTransform.transform(ref destX, ref destY); } #if false // this is an optomization that eliminates the drawing of images that have their alpha set to all 0 (happens with generated images like explosions). MaxAlphaFrameProperty maxAlphaFrameProperty = MaxAlphaFrameProperty::GetMaxAlphaFrameProperty(source); if((maxAlphaFrameProperty.GetMaxAlpha() * color.A_Byte) / 256 <= ALPHA_CHANNEL_BITS_DIVISOR) { m_OutFinalBlitBounds.SetRect(0,0,0,0); } #endif bool IsScaled = (scaleX != 1 || scaleY != 1); bool IsRotated = true; if (Math.Abs(angleRadians) < (0.1 * MathHelper.Tau / 360)) { IsRotated = false; angleRadians = 0; } //bool IsMipped = false; double sourceOriginOffsetX = source.OriginOffset.x; double sourceOriginOffsetY = source.OriginOffset.y; bool CanUseMipMaps = IsScaled; if (scaleX > 0.5 || scaleY > 0.5) { CanUseMipMaps = false; } bool renderRequriesSourceSampling = IsScaled || IsRotated || destX != (int)destX || destY != (int)destY; // this is the fast drawing path if (renderRequriesSourceSampling) { #if false // if the scalling is small enough the results can be improved by using mip maps if(CanUseMipMaps) { CMipMapFrameProperty* pMipMapFrameProperty = CMipMapFrameProperty::GetMipMapFrameProperty(source); double OldScaleX = scaleX; double OldScaleY = scaleY; const CFrameInterface* pMippedFrame = pMipMapFrameProperty.GetMipMapFrame(ref scaleX, ref scaleY); if(pMippedFrame != source) { IsMipped = true; source = pMippedFrame; sourceOriginOffsetX *= (OldScaleX / scaleX); sourceOriginOffsetY *= (OldScaleY / scaleY); } HotspotOffsetX *= (inScaleX / scaleX); HotspotOffsetY *= (inScaleY / scaleY); } #endif Affine destRectTransform; DrawImageGetDestBounds(source, destX, destY, sourceOriginOffsetX, sourceOriginOffsetY, scaleX, scaleY, angleRadians, out destRectTransform); Affine sourceRectTransform = new Affine(destRectTransform); // We invert it because it is the transform to make the image go to the same position as the polygon. LBB [2/24/2004] sourceRectTransform.invert(); span_image_filter spanImageFilter; span_interpolator_linear interpolator = new span_interpolator_linear(sourceRectTransform); ImageBufferAccessorClip sourceAccessor = new ImageBufferAccessorClip(source, RGBA_Floats.rgba_pre(0, 0, 0, 0).GetAsRGBA_Bytes()); spanImageFilter = new span_image_filter_rgba_bilinear_clip(sourceAccessor, RGBA_Floats.rgba_pre(0, 0, 0, 0), interpolator); DrawImage(source, spanImageFilter, destRectTransform); #if false // this is some debug you can enable to visualize the dest bounding box LineFloat(BoundingRect.left, BoundingRect.top, BoundingRect.right, BoundingRect.top, WHITE); LineFloat(BoundingRect.right, BoundingRect.top, BoundingRect.right, BoundingRect.bottom, WHITE); LineFloat(BoundingRect.right, BoundingRect.bottom, BoundingRect.left, BoundingRect.bottom, WHITE); LineFloat(BoundingRect.left, BoundingRect.bottom, BoundingRect.left, BoundingRect.top, WHITE); #endif } else // TODO: this can be even faster if we do not use an intermediat buffer { Affine destRectTransform; DrawImageGetDestBounds(source, destX, destY, sourceOriginOffsetX, sourceOriginOffsetY, scaleX, scaleY, angleRadians, out destRectTransform); Affine sourceRectTransform = new Affine(destRectTransform); // We invert it because it is the transform to make the image go to the same position as the polygon. LBB [2/24/2004] sourceRectTransform.invert(); span_interpolator_linear interpolator = new span_interpolator_linear(sourceRectTransform); ImageBufferAccessorClip sourceAccessor = new ImageBufferAccessorClip(source, RGBA_Floats.rgba_pre(0, 0, 0, 0).GetAsRGBA_Bytes()); span_image_filter spanImageFilter = null; switch (source.BitDepth) { case 32: spanImageFilter = new span_image_filter_rgba_nn_stepXby1(sourceAccessor, interpolator); break; case 24: spanImageFilter = new span_image_filter_rgb_nn_stepXby1(sourceAccessor, interpolator); break; case 8: spanImageFilter = new span_image_filter_gray_nn_stepXby1(sourceAccessor, interpolator); break; default: throw new NotImplementedException(); } //spanImageFilter = new span_image_filter_rgba_nn(sourceAccessor, interpolator); DrawImage(source, spanImageFilter, destRectTransform); DestImage.MarkImageChanged(); } }
public abstract void Render(Graphics2D graphics2D, Affine transform, double layerScale, RenderType renderType);
public void SetTransform(Affine value) { affineTransformStack.Pop(); affineTransformStack.Push(value); }
public abstract void CreateRender3DData(VectorPOD<ColorVertexData> colorVertexData, VectorPOD<uint> indexData, Affine transform, double layerScale, RenderType renderType);
// Multiply matrix to another one private void multiply(Affine m) { double t0 = sx * m.sx + shy * m.shx; double t2 = shx * m.sx + sy * m.shx; double t4 = tx * m.sx + ty * m.shx + m.tx; shy = sx * m.shy + shy * m.sy; sy = shx * m.shy + sy * m.sy; ty = tx * m.shy + ty * m.sy + m.ty; sx = t0; shx = t2; tx = t4; }
//--------------------------------------------------------- Operations public Perspective from_affine(Affine a) { sx = a.sx; shy = a.shy; w0 = 0; shx = a.shx; sy = a.sy; w1 = 0; tx = a.tx; ty = a.ty; w2 = 1; return this; }
public static Affine operator +(Affine a, Vector2 b) { Affine temp = new Affine(a); temp.tx += b.x; temp.ty += b.y; return temp; }
//------------------------------------------------------------------------ public Perspective multiply(Affine a) { Perspective b = new Perspective(this); sx = a.sx *b.sx + a.shx*b.shy + a.tx*b.w0; shx = a.sx *b.shx + a.shx*b.sy + a.tx*b.w1; tx = a.sx *b.tx + a.shx*b.ty + a.tx*b.w2; shy = a.shy*b.sx + a.sy *b.shy + a.ty*b.w0; sy = a.shy*b.shx + a.sy *b.sy + a.ty*b.w1; ty = a.shy*b.tx + a.sy *b.ty + a.ty*b.w2; return this; }
public void scaling(out double x, out double y) { double x1 = 0.0; double y1 = 0.0; double x2 = 1.0; double y2 = 1.0; Affine t = new Affine(this); t *= NewRotation(-rotation()); t.transform(ref x1, ref y1); t.transform(ref x2, ref y2); x = x2 - x1; y = y2 - y1; }
//------------------------------------------------------------------------ public Perspective premultiply(Affine b) { Perspective a = new Perspective(this); sx = a.sx *b.sx + a.shx*b.shy; shx = a.sx *b.shx + a.shx*b.sy; tx = a.sx *b.tx + a.shx*b.ty + a.tx; shy = a.shy*b.sx + a.sy *b.shy; sy = a.shy*b.shx + a.sy *b.sy; ty = a.shy*b.tx + a.sy *b.ty + a.ty; w0 = a.w0 *b.sx + a.w1 *b.shy; w1 = a.w0 *b.shx + a.w1 *b.sy; w2 = a.w0 *b.tx + a.w1 *b.ty + a.w2; return this; }
public void CreateGrid(Affine transform) { Vector2 gridOffset = gridCenterMm - gridSizeMm / 2; if (gridSizeMm.x > 0 && gridSizeMm.y > 0) { grid.remove_all(); for (int y = 0; y <= gridSizeMm.y; y += 10) { Vector2 start = new Vector2(0, y) + gridOffset; Vector2 end = new Vector2(gridSizeMm.x, y) + gridOffset; transform.transform(ref start); transform.transform(ref end); grid.MoveTo((int)(start.x + .5), (int)(start.y + .5) + .5); grid.LineTo((int)(int)(end.x + .5), (int)(end.y + .5) + .5); } for (int x = 0; x <= gridSizeMm.x; x += 10) { Vector2 start = new Vector2(x, 0) + gridOffset; Vector2 end = new Vector2(x, gridSizeMm.y) + gridOffset; transform.transform(ref start); transform.transform(ref end); grid.MoveTo((int)(start.x + .5) + .5, (int)(start.y + .5)); grid.LineTo((int)(end.x + .5) + .5, (int)(end.y + .5)); } } }
//------------------------------------------------------------------------ public Perspective trans_perspectivemultiply_inv(Affine m) { Affine t = m; t.invert(); return multiply(t); }