// * // * Applies a "thickness" to a shape, ie a bit like the extruder, but in 2D // * <table border="0" width="100%"><tr><td>\image html shape_thick1.png "Start shape (before thicken)"</td><td>\image html shape_thick2.png "Result (after thicken)"</td></tr></table> // //----------------------------------------------------------------------- public MultiShape thicken(float amount) { if (!mClosed) { Shape s = new Shape(); s.setOutSide(mOutSide); for (int i = 0; i < mPoints.Count; i++) s.addPoint(mPoints[i] + amount * getAvgNormal((uint)i)); for (int i = mPoints.Count - 1; i >= 0; i--) s.addPoint(mPoints[i] - amount * getAvgNormal((uint)i)); s.close(); return new MultiShape().addShape(s); } else { MultiShape ms = new MultiShape(); Shape s1 = new Shape(); for (int i = 0; i < mPoints.Count; i++) s1.addPoint(mPoints[i] + amount * getAvgNormal((uint)i)); s1.close(); s1.setOutSide(mOutSide); ms.addShape(s1); Shape s2 = new Shape(); for (int i = 0; i < mPoints.Count; i++) s2.addPoint(mPoints[i] - amount * getAvgNormal((uint)i)); s2.close(); s2.setOutSide(mOutSide == Side.SIDE_LEFT ? Side.SIDE_RIGHT : Side.SIDE_LEFT); ms.addShape(s2); return ms; } }
//----------------------------------------------------------------------- // //ORIGINAL LINE: MultiShape _booleanOperation(const Shape& STLAllocator<U, AllocPolicy>, BooleanOperationType opType) const private MultiShape _booleanOperation(Shape other, BooleanOperationType opType) { if (!mClosed || mPoints.size() < 2) OGRE_EXCEPT("Ogre::Exception::ERR_INVALID_STATE", "Current shapes must be closed and has to contain at least 2 points!", "Procedural::Shape::_booleanOperation(const Procedural::Shape&, Procedural::BooleanOperationType)"); if (!other.mClosed || other.mPoints.size() < 2) OGRE_EXCEPT("Ogre::Exception::ERR_INVALIDPARAMS", "Other shapes must be closed and has to contain at least 2 points!", "Procedural::Shape::_booleanOperation(const Procedural::Shape&, Procedural::BooleanOperationType)"); ; // Compute the intersection between the 2 shapes std_vector<IntersectionInShape> intersections = new std_vector<IntersectionInShape>(); _findAllIntersections(other, ref intersections); // Build the resulting shape if (intersections.empty()) { if (isPointInside(other.getPoint(0))) { // Shape B is completely inside shape A if (opType == BooleanOperationType.BOT_UNION) { MultiShape ms = new MultiShape(); ms.addShape(this); return ms; } else if (opType == BooleanOperationType.BOT_INTERSECTION) { MultiShape ms = new MultiShape(); ms.addShape(other); return ms; } else if (opType == BooleanOperationType.BOT_DIFFERENCE) { MultiShape ms = new MultiShape(); ms.addShape(this); ms.addShape(other); ms.getShape(1).switchSide(); return ms; } } else if (other.isPointInside(getPoint(0))) { // Shape A is completely inside shape B if (opType == BooleanOperationType.BOT_UNION) { MultiShape ms = new MultiShape(); ms.addShape(other); return ms; } else if (opType == BooleanOperationType.BOT_INTERSECTION) { MultiShape ms = new MultiShape(); ms.addShape(this); return ms; } else if (opType == BooleanOperationType.BOT_DIFFERENCE) { MultiShape ms = new MultiShape(); ms.addShape(this); ms.addShape(other); ms.getShape(0).switchSide(); return ms; } } else { if (opType == BooleanOperationType.BOT_UNION) { MultiShape ms = new MultiShape(); ms.addShape(this); ms.addShape(other); return ms; } else if (opType == BooleanOperationType.BOT_INTERSECTION) return new MultiShape(); //empty result else if (opType == BooleanOperationType.BOT_DIFFERENCE) return new MultiShape(); //empty result } } MultiShape outputMultiShape = new MultiShape(); Shape[] inputShapes = new Shape[2]; inputShapes[0] = this; inputShapes[1] = other; while (!intersections.empty()) { Shape outputShape = new Shape(); byte shapeSelector = 0; // 0 : first shape, 1 : second shape Vector2 currentPosition = intersections[0].position;//intersections.GetEnumerator().position; IntersectionInShape firstIntersection = intersections[0];//*intersections.GetEnumerator(); uint currentSegment = firstIntersection.index[shapeSelector]; //C++ TO C# CONVERTER TODO TASK: There is no direct equivalent to the STL vector 'erase' method in C#: //intersections.erase(intersections.GetEnumerator());//ÒƳý intersections.erase(firstIntersection, true); outputShape.addPoint(currentPosition); sbyte isIncreasing = 0; // +1 if increasing, -1 if decreasing, 0 if undefined if (!_findWhereToGo(inputShapes, opType, firstIntersection, ref shapeSelector, ref isIncreasing, ref currentSegment)) { // That intersection is located on a place where the resulting shape won't go => discard continue; } while (true) { // find the closest intersection on the same segment, in the correct direction //List<IntersectionInShape>.Enumerator found_next_intersection = intersections.end(); IntersectionInShape found_next_intersection = intersections[intersections.Count - 1]; int found_next_intersection_pos = -1; float distanceToNextIntersection = float.MaxValue;// std.numeric_limits<Real>.max(); uint nextPoint = currentSegment + (uint)(isIncreasing == 1 ? 1 : 0); bool nextPointIsOnIntersection = false; //for (List<IntersectionInShape>.Enumerator it = intersections.GetEnumerator(); it.MoveNext(); ++it) for (int i = 0; i < intersections.Count; i++) { IntersectionInShape it = intersections[i]; if (currentSegment == it.index[shapeSelector]) { if (((it.position - currentPosition).DotProduct(it.position - inputShapes[shapeSelector].getPoint((int)nextPoint)) < 0f) || (it.onVertex[shapeSelector] && nextPoint == it.index[shapeSelector])) { // found an intersection between the current one and the next segment point float d = (it.position - currentPosition).Length; if (d < distanceToNextIntersection) { // check if we have the nearest intersection found_next_intersection = it; found_next_intersection_pos = i; distanceToNextIntersection = d; } } } if (nextPoint == it.index[shapeSelector] && it.onVertex[shapeSelector]) nextPointIsOnIntersection = true; } // stop condition if (currentSegment == firstIntersection.index[shapeSelector]) { // we found ourselves on the same segment as the first intersection and no other if ((firstIntersection.position - currentPosition).DotProduct(firstIntersection.position - inputShapes[shapeSelector].getPoint((int)nextPoint)) < 0f) { float d = (firstIntersection.position - currentPosition).Length; if (d > 0.0f && d < distanceToNextIntersection) { outputShape.close(); break; } } } // We actually found the next intersection => change direction and add current intersection to the list //if (found_next_intersection.MoveNext()) //if (intersections.Count > 1) { if (found_next_intersection_pos != -1) { //IntersectionInShape currentIntersection = found_next_intersection.Current; IntersectionInShape currentIntersection = found_next_intersection; intersections.erase(found_next_intersection, true); //IntersectionInShape currentIntersection = intersections[intersections.Count - 1]; outputShape.addPoint(currentIntersection.position); bool result = _findWhereToGo(inputShapes, opType, currentIntersection, ref shapeSelector, ref isIncreasing, ref currentSegment); if (result == null) { OGRE_EXCEPT("Ogre::Exception::ERR_INTERNAL_ERROR", "We should not be here!", "Procedural::Shape::_booleanOperation(const Procedural::Shape&, Procedural::BooleanOperationType)"); ; } } else { // no intersection found for the moment => just continue on the current segment if (!nextPointIsOnIntersection) { if (isIncreasing == 1) currentPosition = inputShapes[shapeSelector].getPoint((int)currentSegment + 1); else currentPosition = inputShapes[shapeSelector].getPoint((int)currentSegment); outputShape.addPoint(currentPosition); } currentSegment = (uint)Utils.modulo((int)currentSegment + isIncreasing, inputShapes[shapeSelector].getSegCount()); } } outputMultiShape.addShape(outputShape); } return outputMultiShape; }
/// Creates a shape with the keys of this shape and extra keys coming from a track /// @param track the track to merge keys with /// @return a new Shape coming from the merge between original shape and the track //----------------------------------------------------------------------- // //ORIGINAL LINE: Shape mergeKeysWithTrack(const Track& track) const public Shape mergeKeysWithTrack(Track track) { if (!track.isInsertPoint() || track.getAddressingMode() == Track.AddressingMode.AM_POINT) return this; float totalLength = getTotalLength(); float lineicPos = 0; float shapeLineicPos = 0; Shape outputShape = new Shape(); if (mClosed) outputShape.close(); outputShape.addPoint(getPoint(0)); for (int i = 1; i < mPoints.Count; ) { float nextLineicPos = shapeLineicPos + (mPoints[i] - mPoints[i - 1]).Length; //std.map<Real,Real>.Enumerator it = track._getKeyValueAfter(lineicPos, lineicPos/totalLength, i-1); std_pair<float, float> it = track._getKeyValueAfter(lineicPos, lineicPos / totalLength, ((uint)i - 1)); float nextTrackPos = it.first; if (track.getAddressingMode() == Track.AddressingMode.AM_RELATIVE_LINEIC) nextTrackPos *= totalLength; // Adds the closest point to the curve, being either from the shape or the track if (nextLineicPos <= nextTrackPos || lineicPos >= nextTrackPos) { outputShape.addPoint(mPoints[i]); i++; lineicPos = nextLineicPos; shapeLineicPos = nextLineicPos; } else { outputShape.addPoint(getPosition((uint)i - 1, (nextTrackPos - shapeLineicPos) / (nextLineicPos - shapeLineicPos))); lineicPos = nextTrackPos; } } return outputShape; }
/// Extracts a part of the shape as a new shape /// @param first first index to be in the new shape /// @param last last index to be in the new shape public Shape extractSubShape(uint first, uint last) { Shape s = new Shape(); for (int i = (int)first; i <= last; i++) s.addPoint(mPoints[i]); s.setOutSide(mOutSide); if (mClosed) s.close(); return s; }
/// Converts the path to a shape, with Y=0 //----------------------------------------------------------------------- // //ORIGINAL LINE: Shape convertToShape() const public Shape convertToShape() { Shape s = new Shape(); //for (List<Vector3>.Enumerator it = mPoints.GetEnumerator(); it.MoveNext(); ++it) foreach (var it in mPoints) { s.addPoint(it.x, it.y); } if (mClosed) s.close(); return s; }
//----------------------------------------------------------------------- void parsePolygon(ref MultiShape @out, XmlNode pPolygonNode) { //if (pPolygonNode->first_attribute("points")) if (pPolygonNode.Attributes["points"] != null) { //if (pPolygonNode->first_attribute("points")->value_size() < 3) return; if (string.IsNullOrEmpty(pPolygonNode.Attributes["points"].Value)) return; if (pPolygonNode.Attributes["points"].Value.Length < 3) return; string temp = xtrim(pPolygonNode.Attributes["points"].Value); std_vector<string> pts = split(temp, " "); if (pts.size() == 0) return; Shape s = new Shape(); for (int i = 0; i < pts.size() - 1; i += 2) s.addPoint(parseReal(pts[i + 0]), parseReal(pts[i + 1])); if (s.getPointsReference().size() == 0) return; s.close(); // if(pPolygonNode->first_attribute("id")) // ss.id = pPolygonNode->first_attribute("id")->value(); s.translate(getAttribTranslate(pPolygonNode)); @out.addShape(s); } }
// * // * Build a MultiShape from chars (one Shape per character) // * \exception Ogre::InternalErrorException Freetype error // * \todo Need to split shapes of multi region chars. For example the letter \c O // * has two shapes, but they are connected to one shape. // public MultiShape realizeShapes() { MultiShape retVal = new MultiShape(); FT_Library ftlib = new FT_Library(); FT_Face face = new FT_Face(); FT_GlyphSlot slot = new FT_GlyphSlot(); FT_Error error = FT_Init_FreeType(ftlib); if (error == 0) { error = FT_New_Face(ftlib, getFontFileByName().c_str(), 0, face); if (error == FT_Err_Unknown_File_Format) { //C++ TO C# CONVERTER TODO TASK: There is no direct equivalent in C# to the C++ __LINE__ macro: //C++ TO C# CONVERTER TODO TASK: There is no direct equivalent in C# to the C++ __FILE__ macro: throw ExceptionFactory.create(Mogre.ExceptionCodeType<Mogre.Exception.ExceptionCodes.ERR_INTERNAL_ERROR>(), "FreeType ERROR: FT_Err_Unknown_File_Format", "Procedural::TextShape::realizeShapes()", __FILE__, __LINE__); ; } else if (error != null) { //C++ TO C# CONVERTER TODO TASK: There is no direct equivalent in C# to the C++ __LINE__ macro: //C++ TO C# CONVERTER TODO TASK: There is no direct equivalent in C# to the C++ __FILE__ macro: throw ExceptionFactory.create(Mogre.ExceptionCodeType<Mogre.Exception.ExceptionCodes.ERR_INTERNAL_ERROR>(), "FreeType ERROR: FT_New_Face - " + StringConverter.toString(error), "Procedural::TextShape::realizeShapes()", __FILE__, __LINE__); ; } else { FT_Set_Pixel_Sizes(face, 0, mFontSize); int px = 0; int py = 0; slot = face.glyph; for (int n = 0; n < mText.length(); n++) { error = FT_Load_Char(face, mText[n], FT_LOAD_NO_BITMAP); if (error != null) continue; Shape s = new Shape(); int nContours = face.glyph.outline.n_contours; int startPos = 0; string tags = face.glyph.outline.tags; FT_Vector[] vec = face.glyph.outline.points; for (int k = 0; k < nContours; k++) { if (k > 0) startPos = face.glyph.outline.contours[k-1]+1; int endPos = face.glyph.outline.contours[k]+1; Vector2 lastPoint = Vector2.ZERO; for (int j = startPos; j < endPos; j++) { if (FT_CURVE_TAG(tags[j]) == FT_CURVE_TAG_ON) { lastPoint = Vector2((float)vec[j].x, (float)vec[j].y); s.addPoint(lastPoint / 64.0f); } else { if (FT_CURVE_TAG(tags[j]) == FT_CURVE_TAG_CUBIC) { int prevPoint = j - 1; if (j == 0) prevPoint = endPos - 1; int nextIndex = j + 1; if (nextIndex >= endPos) nextIndex = startPos; Vector2[] nextPoint = new Vector2[nextIndex]((float)vec.x, (float)vec[nextIndex].y); if ((FT_CURVE_TAG(tags[prevPoint]) != FT_CURVE_TAG_ON) && (FT_CURVE_TAG(tags[prevPoint]) == FT_CURVE_TAG_CUBIC)) { BezierCurve2 bc = new BezierCurve2(); bc.addPoint(Vector2((float)vec[prevPoint].x, (float)vec[prevPoint].y) / 64.0f); bc.addPoint(Vector2((float)vec[j].x, (float)vec[j].y) / 64.0f); bc.addPoint(Vector2((float)vec[nextIndex].x, (float)vec[nextIndex].y) / 64.0f); s.appendShape(bc.realizeShape()); } } else { Vector2[] conicPoint = new Vector2[j]((float)vec.x, (float)vec[j].y); if (j == startPos) { if ((FT_CURVE_TAG(tags[endPos-1]) != FT_CURVE_TAG_ON) && (FT_CURVE_TAG(tags[endPos-1]) != FT_CURVE_TAG_CUBIC)) { Vector2[] lastConnic = new Vector2[endPos - 1]((float)vec.x, (float)vec[endPos - 1].y); lastPoint = (conicPoint + lastConnic) / 2; } } int nextIndex = j + 1; if (nextIndex >= endPos) nextIndex = startPos; Vector2[] nextPoint = new Vector2[nextIndex]((float)vec.x, (float)vec[nextIndex].y); bool nextIsConnic = (FT_CURVE_TAG(tags[nextIndex]) != FT_CURVE_TAG_ON) && (FT_CURVE_TAG(tags[nextIndex]) != FT_CURVE_TAG_CUBIC); if (nextIsConnic) nextPoint = (conicPoint + nextPoint) / 2; int pc = s.getPointCount(); BezierCurve2 bc = new BezierCurve2(); if (pc == 0) bc.addPoint(Vector2.ZERO); else bc.addPoint(s.getPoint(pc - 1)); bc.addPoint(lastPoint / 64.0f); bc.addPoint(conicPoint / 64.0f); bc.addPoint(nextPoint / 64.0f); if (pc == 0) s.appendShape(bc.realizeShape()); else { List<Vector2> subShape = bc.realizeShape().getPoints(); for (List<Vector2>.Enumerator iter = subShape.GetEnumerator(); iter.MoveNext(); iter++) { if (iter != subShape.GetEnumerator()) s.addPoint(iter.Current); } } if (nextIsConnic) // //ORIGINAL LINE: lastPoint = nextPoint; lastPoint=(nextPoint); } } } } s.close(); s.translate((float)px, (float)py); retVal.addShape(s); px += slot.advance.x >> 6; py += slot.advance.y >> 6; } FT_Done_Face(face); } FT_Done_FreeType(ftlib); } else { //C++ TO C# CONVERTER TODO TASK: There is no direct equivalent in C# to the C++ __LINE__ macro: //C++ TO C# CONVERTER TODO TASK: There is no direct equivalent in C# to the C++ __FILE__ macro: throw ExceptionFactory.create(Mogre.ExceptionCodeType<Mogre.Exception.ExceptionCodes.ERR_INTERNAL_ERROR>(), "FreeType ERROR: FT_Init_FreeTyp", "Procedural::TextShape::realizeShapes()", __FILE__, __LINE__); ; } return retVal; }