/// <summary> /// Compute and update the display area from the two points of the ruler. /// This function also compute the orientation of the ruler based on the two points. /// Then it compute the distance between the two points in stud and call the method /// to update the image of the mesurement text. /// This method should be called when the two points of the ruler is updated /// or when the ruler is moved. /// </summary> protected override void updateDisplayData() { // get the geometry data in local variable PointF point1 = mControlPoint[0].mPoint; PointF point2 = mControlPoint[1].mPoint; float distance = mMeasuredDistance.DistanceInStud; // compute the vector of the offset. This vector is turned by 90 deg from the Orientation, so // just invert the X and Y of the normalized vector (the offset vector can be null) PointF offsetNormalizedVector = new PointF(mUnitVector.Y, -mUnitVector.X); // compute the offset distance depending on the flag float offsetDistance = mAllowOffset ? mOffsetDistance : 0.0f; // compute the offset coordinates in stud float offsetX = offsetNormalizedVector.X * offsetDistance; float offsetY = offsetNormalizedVector.Y * offsetDistance; PointF originalOffsetPoint1 = new PointF(point1.X + offsetX, point1.Y + offsetY); PointF originalOffsetPoint2 = new PointF(point2.X + offsetX, point2.Y + offsetY); PointF offsetPoint1 = originalOffsetPoint1; PointF offsetPoint2 = originalOffsetPoint2; // special case: if the distance is too small to draw the unit, we widden the offest point bool needToEnlargeWithText = mDisplayDistance && (distance < GUARANTIED_SPACE_FOR_DISTANCE_DRAWING_IN_STUD); bool needToEnlargeWithoutText = !mDisplayDistance && (distance < MINIMUM_SIZE_FOR_DRAWING_HELPER_IN_STUD); if (needToEnlargeWithText || needToEnlargeWithoutText) { float enlargeSize = 0.0f; if (needToEnlargeWithText) enlargeSize = (GUARANTIED_SPACE_FOR_DISTANCE_DRAWING_IN_STUD - distance) * 0.5f; else if (needToEnlargeWithoutText) enlargeSize = HALF_MINIMUM_SIZE_FOR_DRAWING_HELPER_IN_STUD; enlargeSize *= (point2.X > point1.X) ? 1.0f : -1.0f; PointF enlargeVector = new PointF(mUnitVector.X * enlargeSize, mUnitVector.Y * enlargeSize); offsetPoint1 = new PointF(offsetPoint1.X - enlargeVector.X, offsetPoint1.Y - enlargeVector.Y); offsetPoint2 = new PointF(offsetPoint2.X + enlargeVector.X, offsetPoint2.Y + enlargeVector.Y); // also enlarge the offset if there's the text if (needToEnlargeWithText) { originalOffsetPoint1 = offsetPoint1; originalOffsetPoint2 = offsetPoint2; } } // when the offset points are finished to be computed, assign them in the data members mControlPoint[0].mOffsetPoint = originalOffsetPoint1; mControlPoint[1].mOffsetPoint = originalOffsetPoint2; // extend a little more the offset point to draw a margin float extendInStud = MINIMUM_SIZE_FOR_DRAWING_HELPER_IN_STUD; if (mDisplayDistance) extendInStud = (float)(((double)MesurementTextHeightInPixel * 0.5) / MainForm.Instance.MapViewScale); float extendX = offsetNormalizedVector.X * ((mOffsetDistance > 0.0f) ? extendInStud : -extendInStud); float extendY = offsetNormalizedVector.Y * ((mOffsetDistance > 0.0f) ? extendInStud : -extendInStud); PointF[] selectionArea = new PointF[4]; selectionArea[(int)SelectionAreaIndex.EXTERNAL_1] = new PointF(offsetPoint1.X + extendX, offsetPoint1.Y + extendY); selectionArea[(int)SelectionAreaIndex.EXTERNAL_2] = new PointF(offsetPoint2.X + extendX, offsetPoint2.Y + extendY); selectionArea[(int)SelectionAreaIndex.INTERNAL_1] = new PointF(offsetPoint1.X - extendX, offsetPoint1.Y - extendY); selectionArea[(int)SelectionAreaIndex.INTERNAL_2] = new PointF(offsetPoint2.X - extendX, offsetPoint2.Y - extendY); mSelectionArea = new Tools.Polygon(selectionArea); // finally update the display area updateDisplayArea(); }
/// <summary> /// Copy constructor /// </summary> /// <param name="model">the model from which copy</param> public Polygon(Polygon model) { this.mVertice = model.Vertice; }
private void updateBitmap(bool redrawImage) { // create a bitmap if the text is not empty if (mText != "") { // create a font to mesure the text Font textFont = new Font(mTextFont.FontFamily, mTextFont.Size, mTextFont.Style); Graphics graphics = Graphics.FromImage(mImage); SizeF textFontSize = graphics.MeasureString(mText, textFont); float halfWidth = textFontSize.Width * 0.5f; float halfHeight = textFontSize.Height * 0.5f; Matrix rotation = new Matrix(); rotation.Rotate(mOrientation); // compute the rotated corners PointF[] corners = new PointF[] { new PointF(-halfWidth, -halfHeight), new PointF(-halfWidth, halfHeight), new PointF(halfWidth, halfHeight), new PointF(halfWidth, -halfHeight) }; rotation.TransformVectors(corners); PointF min = corners[0]; PointF max = corners[0]; for (int i = 1; i < 4; ++i) { if (corners[i].X < min.X) { min.X = corners[i].X; } if (corners[i].Y < min.Y) { min.Y = corners[i].Y; } if (corners[i].X > max.X) { max.X = corners[i].X; } if (corners[i].Y > max.Y) { max.Y = corners[i].Y; } } // adjust the display area and selection area mDisplayArea.Width = Math.Abs(max.X - min.X); mDisplayArea.Height = Math.Abs(max.Y - min.Y); // adjust the selection area (after adjusting the display area such as the center properties is correct) Matrix translation = new Matrix(); translation.Translate(Center.X, Center.Y); translation.TransformPoints(corners); // then create the new selection area mSelectionArea = new Tools.Polygon(corners); if (redrawImage) { // now create a scaled font from the current one, to avoid aliasing Font scaledTextFont = new Font(mTextFont.FontFamily, mTextFont.Size * ANTI_ALIASING_FONT_SCALE, mTextFont.Style); mImage = new Bitmap(mImage, new Size((int)(textFontSize.Width * ANTI_ALIASING_FONT_SCALE), (int)(textFontSize.Height * ANTI_ALIASING_FONT_SCALE))); // compute the position where to draw according to the alignment (if centered == 0) float posx = 0; if (this.TextAlignment == StringAlignment.Far) { posx = halfWidth; } else if (this.TextAlignment == StringAlignment.Near) { posx = -halfWidth; } graphics = Graphics.FromImage(mImage); rotation = new Matrix(); rotation.Translate(mImage.Width / 2, mImage.Height / 2, MatrixOrder.Append); graphics.Transform = rotation; graphics.Clear(Color.Transparent); graphics.SmoothingMode = SmoothingMode.HighQuality; graphics.DrawString(mText, scaledTextFont, mTextBrush, posx * ANTI_ALIASING_FONT_SCALE, 0, mTextStringFormat); graphics.Flush(); } } }
private void updateBitmap(bool redrawImage) { // create a bitmap if the text is not empty if (mText != "") { // create a font to mesure the text Font textFont = new Font(mTextFont.FontFamily, mTextFont.Size, mTextFont.Style); Graphics graphics = Graphics.FromImage(mImage); SizeF textFontSize = graphics.MeasureString(mText, textFont); float halfWidth = textFontSize.Width * 0.5f; float halfHeight = textFontSize.Height * 0.5f; Matrix rotation = new Matrix(); rotation.Rotate(mOrientation); // compute the rotated corners PointF[] corners = new PointF[] { new PointF(-halfWidth, -halfHeight), new PointF(-halfWidth, halfHeight), new PointF(halfWidth, halfHeight), new PointF(halfWidth, -halfHeight) }; rotation.TransformVectors(corners); PointF min = corners[0]; PointF max = corners[0]; for (int i = 1; i < 4; ++i) { if (corners[i].X < min.X) min.X = corners[i].X; if (corners[i].Y < min.Y) min.Y = corners[i].Y; if (corners[i].X > max.X) max.X = corners[i].X; if (corners[i].Y > max.Y) max.Y = corners[i].Y; } // adjust the display area and selection area mDisplayArea.Width = Math.Abs(max.X - min.X); mDisplayArea.Height = Math.Abs(max.Y - min.Y); // adjust the selection area (after adjusting the display area such as the center properties is correct) Matrix translation = new Matrix(); translation.Translate(Center.X, Center.Y); translation.TransformPoints(corners); // then create the new selection area mSelectionArea = new Tools.Polygon(corners); if (redrawImage) { // now create a scaled font from the current one, to avoid aliasing Font scaledTextFont = new Font(mTextFont.FontFamily, mTextFont.Size * ANTI_ALIASING_FONT_SCALE, mTextFont.Style); mImage = new Bitmap(mImage, new Size((int)(textFontSize.Width * ANTI_ALIASING_FONT_SCALE), (int)(textFontSize.Height * ANTI_ALIASING_FONT_SCALE))); // compute the position where to draw according to the alignment (if centered == 0) float posx = 0; if (this.TextAlignment == StringAlignment.Far) posx = halfWidth; else if (this.TextAlignment == StringAlignment.Near) posx = -halfWidth; graphics = Graphics.FromImage(mImage); rotation = new Matrix(); rotation.Translate(mImage.Width / 2, mImage.Height / 2, MatrixOrder.Append); graphics.Transform = rotation; graphics.Clear(Color.Transparent); graphics.SmoothingMode = SmoothingMode.HighQuality; graphics.DrawString(mText, scaledTextFont, mTextBrush, posx * ANTI_ALIASING_FONT_SCALE, 0, mTextStringFormat); graphics.Flush(); } } }
private void updateImage() { List<PointF> boundingBox = null; List<PointF> hull = null; mOriginalImageReference = BrickLibrary.Instance.getImage(mPartNumber, ref boundingBox, ref hull); // check if the image is not in the library, create one if (mOriginalImageReference == null) { // add a default image in the library and ask it again BrickLibrary.Instance.AddUnknownBrick(mPartNumber, (int)(mDisplayArea.Width), (int)(mDisplayArea.Height)); mOriginalImageReference = BrickLibrary.Instance.getImage(mPartNumber, ref boundingBox, ref hull); } // normally now, we should have an image // transform the bounding box of the part PointF[] boundingPoints = boundingBox.ToArray(); Matrix rotation = new Matrix(); rotation.Rotate(mOrientation); rotation.TransformVectors(boundingPoints); // get the min, max and the size of the bounding box PointF boundingMin = new PointF(); PointF boundingMax = new PointF(); PointF boundingSize = sGetMinMaxAndSize(boundingPoints, ref boundingMin, ref boundingMax); // store computationnal variable for optimization const float PIXEL_TO_STUD_RATIO = 1.0f / NUM_PIXEL_PER_STUD_FOR_BRICKS; // transform the hull to get the selection area PointF[] hullArray = hull.ToArray(); rotation.TransformVectors(hullArray); // check if this picture has a specific hull if (hull != boundingBox) { // get the bounding size from the hull PointF hullMin = new PointF(); PointF hullMax = new PointF(); PointF hullSize = sGetMinMaxAndSize(hullArray, ref hullMin, ref hullMax); // compute the offset between the hull and the normal bounding box PointF deltaMin = new PointF(boundingMin.X - hullMin.X, boundingMin.Y - hullMin.Y); PointF deltaMax = new PointF(boundingMax.X - hullMax.X, boundingMax.Y - hullMax.Y); mOffsetFromOriginalImage = new PointF((deltaMax.X + deltaMin.X) * PIXEL_TO_STUD_RATIO * 0.5f, (deltaMax.Y + deltaMin.Y) * PIXEL_TO_STUD_RATIO * 0.5f); // overwrite the bounding size and min with the hull ones which are more precise boundingSize = hullSize; boundingMin = hullMin; } else { mOffsetFromOriginalImage = new PointF(0, 0); } // set the size of the display area with the new computed bounding size, and recompute the snap to grid offset mDisplayArea.Width = boundingSize.X * PIXEL_TO_STUD_RATIO; mDisplayArea.Height = boundingSize.Y * PIXEL_TO_STUD_RATIO; mTopLeftCornerInPixel = new PointF(-boundingMin.X, -boundingMin.Y); // adjust the selection area after computing the new display area size to have a correct center // first we add the translation of the top left corner in pixel to the hull point already in pixel // then convert the pixel to studs, and finally add the top left corner in stud Matrix translation = new Matrix(); translation.Translate(mTopLeftCornerInPixel.X, mTopLeftCornerInPixel.Y); translation.Scale(PIXEL_TO_STUD_RATIO, PIXEL_TO_STUD_RATIO, MatrixOrder.Append); translation.Translate(Center.X - (mDisplayArea.Width * 0.5f), Center.Y - (mDisplayArea.Height * 0.5f), MatrixOrder.Append); translation.TransformPoints(hullArray); // create the new selection area from the rotated hull mSelectionArea = new Tools.Polygon(hullArray); // clear the new images array for all the levels clearMipmapImages(0, mMipmapImages.Length - 1); }