// 由布尔操作类型和两个三维实体创建旋转体的函数. public static void AddBoolSolid(BooleanOperationType boolType, ObjectId solid3dId1, ObjectId solid3dId2) { Database db = HostApplicationServices.WorkingDatabase; using (Transaction trans = db.TransactionManager.StartTransaction()) { try { Entity ent1 = (Entity)trans.GetObject(solid3dId1, OpenMode.ForWrite); Entity ent2 = (Entity)trans.GetObject(solid3dId2, OpenMode.ForWrite); if (ent1 is Solid3d & ent2 is Solid3d) { Solid3d solid3dEnt1 = (Solid3d)ent1; Solid3d solid3dEnt2 = (Solid3d)ent2; solid3dEnt1.BooleanOperation(boolType, solid3dEnt2); ent2.Erase(); } if (ent1 is Region & ent2 is Region) { Region regionEnt1 = (Region)ent1; Region regionEnt2 = (Region)ent2; regionEnt1.BooleanOperation(boolType, regionEnt2); ent2.Erase(); } } catch { // 此处无需要操作. } trans.Commit(); } }
protected BaseOperation(IQuery query, BooleanOperationType type) { _query = query; OperationType = type; // the compiler will build our query-dsl. switch it out to custom impl if you wish to build your own query service _compiler = new DefaultQueryCompiler(); }
/// <summary> /// 由布尔操作函数创建三维实体 /// </summary> /// <param name="boolType">布尔操作类型</param> /// <param name="solid3dId1">参与操作的三维实体的Id</param> /// <param name="solid3dId2">参与操作的三维实体的Id</param> /// <returns>返回创建的三维实体的Id</returns> public static bool BoolSolid3dRegion(BooleanOperationType boolType, ObjectId solid3dId1, ObjectId solid3dId2) { Database db = HostApplicationServices.WorkingDatabase; Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; using (Transaction trans = db.TransactionManager.StartTransaction()) { try { Entity ent1 = trans.GetObject(solid3dId1, OpenMode.ForWrite) as Entity; Entity ent2 = trans.GetObject(solid3dId2, OpenMode.ForWrite) as Entity; if (ent1 == null || ent2 == null) { ed.WriteMessage("\n布尔操作失败!"); return(false); } if (ent1 is Solid3d & ent2 is Solid3d) { Solid3d solid3dEnt1 = (Solid3d)ent1; Solid3d solid3dEnt2 = (Solid3d)ent2; solid3dEnt1.BooleanOperation(boolType, solid3dEnt2); ent2.Dispose(); } if (ent1 is Region & ent2 is Region) { Region regionEnt1 = (Region)ent1; Region regionEnt2 = (Region)ent2; regionEnt1.BooleanOperation(boolType, regionEnt2); ent2.Dispose(); } } catch { ed.WriteMessage("\n布尔操作失败!"); return(false); } trans.Commit(); return(true); } }
/// <summary> /// 三维实体布尔运算 /// </summary> /// <param name="solid1"></param> /// <param name="solid2"></param> /// <param name="type"></param> public static Solid3d BooleanOper(Solid3d solid1, Solid3d solid2, BooleanOperationType type) { solid1.BooleanOperation(type, solid2); return(solid1); }
//----------------------------------------------------------------------- // //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; }
//----------------------------------------------------------------------- // //ORIGINAL LINE: bool _findWhereToGo(const Shape* inputShapes[], BooleanOperationType opType, IntersectionInShape intersection, byte& shapeSelector, sbyte& isIncreasing, uint& currentSegment) const private bool _findWhereToGo(Shape[] inputShapes, BooleanOperationType opType, IntersectionInShape intersection, ref byte shapeSelector, ref sbyte isIncreasing, ref uint currentSegment) { if (intersection.onVertex[0] || intersection.onVertex[1]) { // determine 4 directions with normal info // if 2 normals "face each other" then you have the couple of outside directions Vector2[] directions = new Vector2[4]; //string sides = new string(new char[4]); byte[] sides = new byte[4]; byte incomingDirection; // fill-in the incoming arrays if (isIncreasing == 0) { incomingDirection = 255; } else { incomingDirection = (byte)(shapeSelector + (isIncreasing == 1 ? 2 : 0)); } for (byte i = 0; i < 2; i++) if (intersection.onVertex[i]) { directions[i] = inputShapes[i].getDirectionBefore(intersection.index[i]); directions[2 + i] = -inputShapes[i].getDirectionAfter(intersection.index[i]); } else { directions[2 + i] = -inputShapes[i].getDirectionAfter(intersection.index[i]); directions[i] = -directions[2 + i]; } for (byte i = 0; i < 4; i++) { sides[i] = (byte)((i / 2 == 0 ? -1 : 1) * (inputShapes[i % 2].mOutSide == Side.SIDE_RIGHT ? -1 : 1)); } bool[] isOutside = new bool[4]; //std.pair<Radian, byte>[] sortedDirections = new std.pair[4]; KeyValuePair<Radian, byte>[] sortedDirections = new KeyValuePair<Radian, byte>[4]; // sort by angle for (byte i = 0; i < 4; i++) { if (i == 0) { //sortedDirections[i].first = 0; sortedDirections[i] = new KeyValuePair<Radian, byte>(0, i); } else { Radian first = sides[0] * Utils.angleTo(directions[0], directions[i]); sortedDirections[i] = new KeyValuePair<Radian, byte>(first, i); } //sortedDirections[i].second=i; } //std.sort(sortedDirections, sortedDirections+4, GlobalMembersProceduralShape._sortAngles); //ToDo:sortedDirectionsÅÅÐò List<KeyValuePair<Radian, byte>> sort_sortedDirections = new List<KeyValuePair<Radian, byte>>(); sort_sortedDirections.AddRange(sortedDirections); sort_sortedDirections.Sort((X, Y) => { return _sortAngles(X, Y) ? -1 : 1; }); sortedDirections = sort_sortedDirections.ToArray(); //Array.Sort(sortedDirections); //find which segments are outside if (sides[0] != sides[sortedDirections[1].Value]) { isOutside[0] = isOutside[sortedDirections[1].Value] = true; isOutside[sortedDirections[2].Value] = isOutside[sortedDirections[3].Value] = false; } else { isOutside[sortedDirections[1].Value] = isOutside[sortedDirections[2].Value] = true; isOutside[sortedDirections[3].Value] = isOutside[sortedDirections[0].Value] = false; } //find first eligible segment that is not the current segment for (ushort i = 0; i < 4; i++) if ((isOutside[i] == _isLookingForOutside(opType, (sbyte)(i % 2))) && (i != incomingDirection)) { shapeSelector = (byte)(i % 2); isIncreasing = (sbyte)(i / 2 == 0 ? 1 : -1); currentSegment = intersection.index[shapeSelector]; return true; } // if we reach here, it means that no segment is eligible! (it should only happen with difference opereation return false; } else { // determine which way to go int nextShapeSelector = (shapeSelector + 1) % 2; float d = inputShapes[nextShapeSelector].getDirectionAfter(intersection.index[nextShapeSelector]).DotProduct(inputShapes[shapeSelector].getNormalAfter(currentSegment)); isIncreasing = _isIncreasing(d, opType, (sbyte)nextShapeSelector); shapeSelector = (byte)nextShapeSelector; currentSegment = intersection.index[shapeSelector]; return true; } }
//----------------------------------------------------------------------- // //ORIGINAL LINE: sbyte _isIncreasing(float d, BooleanOperationType opType, sbyte shapeSelector) const private sbyte _isIncreasing(float d, BooleanOperationType opType, sbyte shapeSelector) { if (d < 0f && opType == BooleanOperationType.BOT_UNION) return -1; if (d > 0f && opType == BooleanOperationType.BOT_INTERSECTION) return -1; if (opType == BooleanOperationType.BOT_DIFFERENCE) { if ((d < 0f && shapeSelector == 0) || (d > 0f && shapeSelector == 1)) return -1; } return 1; }
//----------------------------------------------------------------------- // //ORIGINAL LINE: bool _isLookingForOutside(BooleanOperationType opType, sbyte shapeSelector) const private bool _isLookingForOutside(BooleanOperationType opType, sbyte shapeSelector) { switch (opType) { case BooleanOperationType.BOT_UNION: return true; case BooleanOperationType.BOT_INTERSECTION: return false; case BooleanOperationType.BOT_DIFFERENCE: if (shapeSelector == 0) return true; return false; default: return true; } }