diff --git a/doc/salome/examples/transformation_operations_ex06.py b/doc/salome/examples/transformation_operations_ex06.py
index 16bff16e1..3fad9ed38 100644
--- a/doc/salome/examples/transformation_operations_ex06.py
+++ b/doc/salome/examples/transformation_operations_ex06.py
@@ -13,14 +13,17 @@ box = geompy.MakeBox(20, 20, 20, 200, 200, 200)
# create a new object as offset of the given object
offset = geompy.MakeOffset(box, 70.)
offset2 = geompy.MakeOffsetIntersectionJoin(box, 70.)
+offset3 = geompy.MakeOffsetPartial(box, [13, 33], 70.)
# add objects in the study
id_box = geompy.addToStudy(box, "Box")
id_offset = geompy.addToStudy(offset, "Offset")
id_offset2 = geompy.addToStudy(offset2, "Offset_intersection_join")
+id_offset3 = geompy.addToStudy(offset3, "Offset_Partial")
# display the results
gg.createAndDisplayGO(id_box)
gg.setDisplayMode(id_box,1)
gg.createAndDisplayGO(id_offset)
gg.createAndDisplayGO(id_offset2)
+gg.createAndDisplayGO(id_offset3)
diff --git a/doc/salome/gui/GEOM/images/transformation11a.png b/doc/salome/gui/GEOM/images/transformation11a.png
new file mode 100644
index 000000000..f9e555bca
Binary files /dev/null and b/doc/salome/gui/GEOM/images/transformation11a.png differ
diff --git a/doc/salome/gui/GEOM/input/offset_operation.doc b/doc/salome/gui/GEOM/input/offset_operation.doc
index d3d1fd197..949f3cfb7 100644
--- a/doc/salome/gui/GEOM/input/offset_operation.doc
+++ b/doc/salome/gui/GEOM/input/offset_operation.doc
@@ -5,6 +5,10 @@
\n To produce an Offset Surface in the Main Menu select
Operations - > Transformation - > Offset Surface
+\n There are 2 algorithms for creation of an \b Offset.
+
+\n Firstly, you can offset all faces of selected shape(s) to the same value.
+
\n This operation translates each point of an \b Object (a set of
Objects) along a local normal by a given \b Offset distance (signed
number, negative value meaning inner offset). Gaps between translated
@@ -13,12 +17,12 @@ adjacent surfaces are filled in either of two ways:
- else the surfaces are extended and intersected, so that sharp edges
are preserved.
-\n \b Offset operation is applicable to faces, shells and solids.
-\n \ref restore_presentation_parameters_page "Advanced options".
-
-
\image html transformation11.png
+\n Arguments: Name + Object(s) (face(s), shell(s), solid(s)) + Offset value.
+\n The \b Result will be a \b GEOM_Object.
+\n \ref restore_presentation_parameters_page "Advanced options".
+
\n Example:
\image html offsetsn.png "The box and its offset surface (Join by pipes activated)"
@@ -27,11 +31,27 @@ adjacent surfaces are filled in either of two ways:
- Gaps filled by pipes: geompy.MakeOffset(Shape, Offset),
- Gaps filled by intersection: geompy.MakeOffsetIntersectionJoin(Shape, Offset),
-where Shape is a shape(s) which has to be an offset, Offset is a value of
+where \b Shape is a shape(s) which has to be an offset, \b Offset is a value of
the offset.
-\n Arguments: Name + Object (face(s), shell(s), solid(s)) +
-Offset value.
+
+\n Secondly, you can offset only selected faces of the shape to the given value,
+ other faces will stay at their initial places,
+ but could be extended to join with offset faces.
+ Gaps between adjacent surfaces are filled by intersection of extended surfaces.
+
+\image html transformation11a.png
+
+\n Arguments: Name + Object (shell or solid) +
+ Face(s) of the object + Offset value.
\n The \b Result will be a \b GEOM_Object.
+\n \ref restore_presentation_parameters_page "Advanced options".
+
+\n TUI Command:
+- geompy.MakeOffsetPartial(Shape, ListOfFacesIDs, Offset),
+
+where \b Shape is a shape(s) which has to be an offset,
+ \b ListOfFacesIDs is a list of integer IDs of sub-faces and
+ \b Offset is a value of the offset.
Our TUI Scripts provide you with useful examples of the use of
\ref tui_offset "Transformation Operations".
diff --git a/idl/GEOM_Gen.idl b/idl/GEOM_Gen.idl
index d1428637a..d045dcd75 100644
--- a/idl/GEOM_Gen.idl
+++ b/idl/GEOM_Gen.idl
@@ -1345,6 +1345,19 @@ module GEOM
in double theOffset,
in boolean theJoinByPipes);
+ /*!
+ * \brief Create new object as offset of the given one.
+ * Only indexed faces are offset, others keep they original location.
+ * \param theObject The base object for the offset.
+ * \param theFacesIDs The list of face IDs indicating faces to be offset.
+ * \param theOffset Offset value.
+ * \param theJoinByPipes To join offset surfaces by pipes or by intersection.
+ * \return New GEOM_Object, containing the offset object.
+ */
+ GEOM_Object OffsetShapePartialCopy (in GEOM_Object theObject,
+ in ListOfLong theFacesIDs,
+ in double theOffset);
+
/*!
* \brief Create new object as projection of the given one on a 2D surface.
* \param theSource The source object for the projection. It can be a point, edge or wire.
diff --git a/resources/CMakeLists.txt b/resources/CMakeLists.txt
index 76bb5fbd7..16985f969 100644
--- a/resources/CMakeLists.txt
+++ b/resources/CMakeLists.txt
@@ -132,6 +132,7 @@ SET( _res_files
multitranslationsimple.png
normale.png
offset.png
+ offset_partial.png
projection.png
projection_on_edge.png
projection_on_wire.png
diff --git a/resources/offset_partial.png b/resources/offset_partial.png
new file mode 100644
index 000000000..ced1d32df
Binary files /dev/null and b/resources/offset_partial.png differ
diff --git a/src/GEOMBase/GEOMBase.cxx b/src/GEOMBase/GEOMBase.cxx
index 7ab1fa152..98e71f79d 100644
--- a/src/GEOMBase/GEOMBase.cxx
+++ b/src/GEOMBase/GEOMBase.cxx
@@ -796,6 +796,23 @@ QString GEOMBase::GetName( GEOM::GEOM_Object_ptr object )
return name;
}
+//=======================================================================
+// function : GetName()
+// purpose : Get name of objects
+//=======================================================================
+QString GEOMBase::GetName( const QList& objects )
+{
+ QString name;
+
+ int nbSel = objects.count();
+ if (nbSel == 1)
+ name = GEOMBase::GetName( objects[0].get() );
+ else if (nbSel > 1)
+ name = QObject::tr("%1_objects").arg( nbSel );
+
+ return name;
+}
+
//=======================================================================
// function : IsShape()
// purpose : Return TRUE if object is valid and has shape
diff --git a/src/GEOMBase/GEOMBase.h b/src/GEOMBase/GEOMBase.h
index 8d35354df..2089f0373 100644
--- a/src/GEOMBase/GEOMBase.h
+++ b/src/GEOMBase/GEOMBase.h
@@ -122,6 +122,7 @@ public :
/* Gets name of object */
static QString GetName( GEOM::GEOM_Object_ptr object );
+ static QString GetName( const QList& objects );
/* Check if object has shape */
static bool IsShape( GEOM::GEOM_Object_ptr object );
diff --git a/src/GEOMGUI/GEOM_images.ts b/src/GEOMGUI/GEOM_images.ts
index 03ffd98e9..88abb3e22 100644
--- a/src/GEOMGUI/GEOM_images.ts
+++ b/src/GEOMGUI/GEOM_images.ts
@@ -451,6 +451,10 @@
offset.png
+
+
+ offset_partial.png
+
projection.png
diff --git a/src/GEOMImpl/GEOMImpl_ConformityDriver.cxx b/src/GEOMImpl/GEOMImpl_ConformityDriver.cxx
index faed054d0..1ad7c6580 100644
--- a/src/GEOMImpl/GEOMImpl_ConformityDriver.cxx
+++ b/src/GEOMImpl/GEOMImpl_ConformityDriver.cxx
@@ -42,28 +42,6 @@
namespace
{
- //=======================================================================
- //function : ConvertShapesToIndices
- //purpose : Convert sub-shapes of shapes to sequence of indices
- //=======================================================================
- Handle(TColStd_HArray1OfInteger) ConvertShapesToIndices(const TopoDS_Shape& theShape,
- const TopTools_ListOfShape& theShapes)
- {
- Handle(TColStd_HArray1OfInteger) aSeqOfIDs = new TColStd_HArray1OfInteger(1, theShapes.Size());
-
- TopTools_IndexedMapOfShape anIndices;
- TopExp::MapShapes(theShape, anIndices);
-
- TopTools_ListIteratorOfListOfShape itSub(theShapes);
- for (int index = 1; itSub.More(); itSub.Next(), ++index)
- {
- int id = anIndices.FindIndex(itSub.Value());
- aSeqOfIDs->SetValue(index, id);
- }
-
- return aSeqOfIDs;
- }
-
//=======================================================================
//function : ConvertShapesToIndices
//purpose : Convert list of pair shapes to sequence of indices
@@ -203,6 +181,8 @@ Standard_Real GEOMImpl_ConformityDriver::updateTolerance(const TopoDS_Shape& the
case TopAbs_FACE:
aCurTolerance = BRep_Tool::Tolerance(TopoDS::Face(anExp.Value()));
break;
+ default:
+ break;
}
aTolerance = Min(aTolerance, aCurTolerance);
}
@@ -228,6 +208,8 @@ Standard_Real GEOMImpl_ConformityDriver::updateTolerance(const TopoDS_Shape& the
case TopAbs_FACE:
aCurTolerance = BRep_Tool::Tolerance(TopoDS::Face(anExp.Value()));
break;
+ default:
+ break;
}
aResTol = Max(aResTol, aCurTolerance);
}
diff --git a/src/GEOMImpl/GEOMImpl_ITransformOperations.cxx b/src/GEOMImpl/GEOMImpl_ITransformOperations.cxx
index 4ca0707de..6581d5224 100644
--- a/src/GEOMImpl/GEOMImpl_ITransformOperations.cxx
+++ b/src/GEOMImpl/GEOMImpl_ITransformOperations.cxx
@@ -1090,10 +1090,11 @@ GEOMImpl_ITransformOperations::OffsetShape (Handle(GEOM_Object) theObject,
* OffsetShapeCopy
*/
//=============================================================================
-Handle(GEOM_Object)
-GEOMImpl_ITransformOperations::OffsetShapeCopy( Handle(GEOM_Object) theObject,
- double theOffset,
- bool theJoinByPipes)
+Handle(GEOM_Object) GEOMImpl_ITransformOperations::OffsetShapeCopy
+ (Handle(GEOM_Object) theObject,
+ double theOffset,
+ bool theJoinByPipes,
+ const Handle(TColStd_HArray1OfInteger)& theFacesIDs)
{
SetErrorCode(KO);
@@ -1118,6 +1119,10 @@ GEOMImpl_ITransformOperations::OffsetShapeCopy( Handle(GEOM_Object) theObject,
aTI.SetValue( theOffset );
aTI.SetJoinByPipes( theJoinByPipes );
+ if (!theFacesIDs.IsNull()) {
+ aTI.SetFaceIDs(theFacesIDs);
+ }
+
//Compute the offset
try {
OCC_CATCH_SIGNALS;
@@ -1132,18 +1137,31 @@ GEOMImpl_ITransformOperations::OffsetShapeCopy( Handle(GEOM_Object) theObject,
}
//Make a Python command
- if (theJoinByPipes)
- GEOM::TPythonDump(aFunction) << aCopy << " = geompy.MakeOffset("
- << theObject << ", " << theOffset << ")";
- else
- GEOM::TPythonDump(aFunction) << aCopy << " = geompy.MakeOffsetIntersectionJoin("
- << theObject << ", " << theOffset << ")";
+ if (theFacesIDs.IsNull()) {
+ if (theJoinByPipes)
+ GEOM::TPythonDump(aFunction) << aCopy << " = geompy.MakeOffset("
+ << theObject << ", " << theOffset << ")";
+ else
+ GEOM::TPythonDump(aFunction) << aCopy << " = geompy.MakeOffsetIntersectionJoin("
+ << theObject << ", " << theOffset << ")";
+ }
+ else {
+ GEOM::TPythonDump pd (aFunction);
+ pd << aCopy << " = geompy.MakeOffsetPartial("
+ << theObject << ", [";
+
+ // Dump faces IDs.
+ for (Standard_Integer i = theFacesIDs->Lower(); i <= theFacesIDs->Upper(); ++i) {
+ pd << theFacesIDs->Value(i) << ((i == theFacesIDs->Upper()) ? "" : ", ");
+ }
+
+ pd << "], " << theOffset << ")";
+ }
SetErrorCode(OK);
return aCopy;
}
-
//=============================================================================
/*!
* ProjectShapeCopy
diff --git a/src/GEOMImpl/GEOMImpl_ITransformOperations.hxx b/src/GEOMImpl/GEOMImpl_ITransformOperations.hxx
index 25498ce00..aac62cfdd 100644
--- a/src/GEOMImpl/GEOMImpl_ITransformOperations.hxx
+++ b/src/GEOMImpl/GEOMImpl_ITransformOperations.hxx
@@ -108,9 +108,11 @@ class GEOMImpl_ITransformOperations : public GEOM_IOperations
double theOffset,
bool theJoinByPipes);
- Standard_EXPORT Handle(GEOM_Object) OffsetShapeCopy (Handle(GEOM_Object) theObject,
- double theOffset,
- bool theJoinByPipes);
+ Standard_EXPORT Handle(GEOM_Object) OffsetShapeCopy
+ (Handle(GEOM_Object) theObject,
+ double theOffset,
+ bool theJoinByPipes,
+ const Handle(TColStd_HArray1OfInteger)& theFacesIDs = NULL);
Standard_EXPORT Handle(GEOM_Object) ProjectShapeCopy (Handle(GEOM_Object) theSource,
Handle(GEOM_Object) theTarget);
diff --git a/src/GEOMImpl/GEOMImpl_OffsetDriver.cxx b/src/GEOMImpl/GEOMImpl_OffsetDriver.cxx
index f33b86721..fb47d9e4e 100644
--- a/src/GEOMImpl/GEOMImpl_OffsetDriver.cxx
+++ b/src/GEOMImpl/GEOMImpl_OffsetDriver.cxx
@@ -28,12 +28,13 @@
#include
#include
+#include
#include
#include
-#include
#include
#include
-#include
+#include
+#include
#include
#include
#include
@@ -88,24 +89,79 @@ Standard_Integer GEOMImpl_OffsetDriver::Execute(Handle(TFunction_Logbook)& log)
if ( aType == OFFSET_SHAPE || aType == OFFSET_SHAPE_COPY )
{
- BRepOffsetAPI_MakeOffsetShape MO;
BRepOffset_Mode aMode = BRepOffset_Skin;
- Standard_Boolean anIntersection = Standard_False, aSelfInter = Standard_False;
- MO.PerformByJoin( aShapeBase,
- aCI.GetValue(),
- aTol,
- aMode,
- anIntersection,
- aSelfInter,
- aCI.GetJoinByPipes() ? GeomAbs_Arc : GeomAbs_Intersection );
+ Standard_Boolean anIntersection = Standard_False;
+ Standard_Boolean aSelfInter = Standard_False;
- if ( MO.IsDone() ) {
- aShape = MO.Shape();
- if ( !GEOMUtils::CheckShape(aShape, true) && !GEOMUtils::FixShapeTolerance(aShape) )
- Standard_ConstructionError::Raise("Boolean operation aborted : non valid shape result");
+ Handle(TColStd_HArray1OfInteger) aFacesIDs = aCI.GetFaceIDs();
+ if (aFacesIDs.IsNull() || aFacesIDs->Length() < 1) {
+ // Offset entire shape (all faces) with the same offset value
+ BRepOffsetAPI_MakeOffsetShape MO;
+ MO.PerformByJoin( aShapeBase,
+ anOffset,
+ aTol,
+ aMode,
+ anIntersection,
+ aSelfInter,
+ aCI.GetJoinByPipes() ? GeomAbs_Arc : GeomAbs_Intersection );
+
+ if ( MO.IsDone() ) {
+ aShape = MO.Shape();
+ if ( !GEOMUtils::CheckShape(aShape, true) && !GEOMUtils::FixShapeTolerance(aShape) )
+ Standard_ConstructionError::Raise("Offset aborted : non valid shape result");
+ }
+ else {
+ StdFail_NotDone::Raise("Offset construction failed");
+ }
}
else {
- StdFail_NotDone::Raise("Offset construction failed");
+ // Offset selected faces of main shape by given value, other faces by 0
+ BRepOffset_MakeOffset aMakeOffset;
+ aMakeOffset.Initialize(aShapeBase,
+ anOffset, // set offset on all faces to anOffset
+ aTol,
+ aMode,
+ anIntersection,
+ aSelfInter,
+ aCI.GetJoinByPipes() ? GeomAbs_Arc : GeomAbs_Intersection,
+ Standard_False);
+
+ // put selected faces into a map
+ TopTools_MapOfShape aMapFaces;
+ TopTools_IndexedMapOfShape anIndices;
+ TopExp::MapShapes(aShapeBase, anIndices);
+ Standard_Integer aNbShapes = anIndices.Extent();
+ for (Standard_Integer i = aFacesIDs->Lower(); i <= aFacesIDs->Upper(); ++i) {
+ const Standard_Integer anIndex = aFacesIDs->Value(i);
+ if (anIndex < 1 || anIndex > aNbShapes) {
+ Standard_ConstructionError::Raise("Offset aborted : Invalid face index given");
+ }
+ const TopoDS_Shape &aFace = anIndices.FindKey(anIndex);
+ if (aFace.ShapeType() != TopAbs_FACE) {
+ Standard_ConstructionError::Raise("Offset aborted : Shape by index is not a face");
+ }
+ aMapFaces.Add(aFace);
+ }
+
+ // set offset on non-selected faces to zero
+ TopExp_Explorer anExp (aShapeBase, TopAbs_FACE);
+ for (; anExp.More(); anExp.Next()) {
+ const TopoDS_Shape &aFace = anExp.Current();
+ if (!aMapFaces.Contains(aFace)) {
+ aMakeOffset.SetOffsetOnFace(TopoDS::Face(aFace), 0.0);
+ }
+ }
+
+ // perform offset operation
+ aMakeOffset.MakeOffsetShape();
+ if ( aMakeOffset.IsDone() ) {
+ aShape = aMakeOffset.Shape();
+ if ( !GEOMUtils::CheckShape(aShape, true) && !GEOMUtils::FixShapeTolerance(aShape) )
+ Standard_ConstructionError::Raise("Offset aborted : non valid shape result");
+ }
+ else {
+ StdFail_NotDone::Raise("Offset construction failed");
+ }
}
}
else if (aType == OFFSET_THICKENING || aType == OFFSET_THICKENING_COPY)
@@ -216,6 +272,12 @@ GetCreationInformation(std::string& theOperationName,
theOperationName = "OFFSET";
AddParam( theParams, "Object", aCI.GetShape() );
AddParam( theParams, "Offset", aCI.GetValue() );
+ {
+ Handle(TColStd_HArray1OfInteger) aFacesIDs = aCI.GetFaceIDs();
+ if (!aFacesIDs.IsNull()) {
+ AddParam(theParams, "Faces IDs", aFacesIDs);
+ }
+ }
break;
case OFFSET_THICKENING:
case OFFSET_THICKENING_COPY:
diff --git a/src/GEOM_I/GEOM_IMeasureOperations_i.cc b/src/GEOM_I/GEOM_IMeasureOperations_i.cc
index 3c7d6343f..0acbdb36c 100644
--- a/src/GEOM_I/GEOM_IMeasureOperations_i.cc
+++ b/src/GEOM_I/GEOM_IMeasureOperations_i.cc
@@ -1366,8 +1366,8 @@ GEOM::GEOM_IMeasureOperations::SequenceOfPairOfShape* GEOM_IMeasureOperations_i:
std::list::iterator anIter(aSelfInters.begin());
for (Standard_Integer i = 0; i < aLength; i++, ++anIter)
{
- aSeq[i].first = GetObject(Handle(::GEOM_Object)::DownCast((*anIter).first));
- aSeq[i].second = GetObject(Handle(::GEOM_Object)::DownCast((*anIter).second));
+ aSeq[i].first = GetObject((*anIter).first);
+ aSeq[i].second = GetObject((*anIter).second);
}
return aSeq._retn();
@@ -1404,8 +1404,8 @@ GEOM::GEOM_IMeasureOperations::SequenceOfPairOfShape* GEOM_IMeasureOperations_i:
std::list::iterator anIter(aSelfInterf.begin());
for (Standard_Integer i = 0; i < aLength; i++, ++anIter)
{
- aSeq[i].first = GetObject(Handle(::GEOM_Object)::DownCast((*anIter).first));
- aSeq[i].second = GetObject(Handle(::GEOM_Object)::DownCast((*anIter).second));
+ aSeq[i].first = GetObject((*anIter).first);
+ aSeq[i].second = GetObject((*anIter).second);
}
return aSeq._retn();
@@ -1471,8 +1471,8 @@ GEOM::GEOM_IMeasureOperations::SequenceOfPairOfShape* GEOM_IMeasureOperations_i:
std::list::iterator anIter(aDistantS.begin());
for (Standard_Integer i = 0; i < aLength; i++, ++anIter)
{
- aSeq[i].first = GetObject(Handle(::GEOM_Object)::DownCast((*anIter).first));
- aSeq[i].second = GetObject(Handle(::GEOM_Object)::DownCast((*anIter).second));
+ aSeq[i].first = GetObject((*anIter).first);
+ aSeq[i].second = GetObject((*anIter).second);
}
return aSeq._retn();
@@ -1502,8 +1502,8 @@ GEOM::GEOM_IMeasureOperations::CheckResults* GEOM_IMeasureOperations_i::CheckCon
for (Standard_Integer i = 0; i < aLength; i++, ++anIntIt)
{
aRes[i].type = (*anIntIt).TypeOfCheck;
- aRes[i].failedShapes.first = GetObject(Handle(::GEOM_Object)::DownCast((*anIntIt).FailedShapes.first));
- aRes[i].failedShapes.second = GetObject(Handle(::GEOM_Object)::DownCast((*anIntIt).FailedShapes.second));
+ aRes[i].failedShapes.first = GetObject((*anIntIt).FailedShapes.first);
+ aRes[i].failedShapes.second = GetObject((*anIntIt).FailedShapes.second);
}
return aRes._retn();
@@ -1530,7 +1530,7 @@ CORBA::Double GEOM_IMeasureOperations_i::UpdateTolerance(GEOM::GEOM_Object_ptr t
void GEOM_IMeasureOperations_i::ConvertToList(const GEOM::GEOM_IMeasureOperations::CheckResults& theResuts,
std::list& theListOfResults)
{
- for (Standard_Integer i = 0; i < theResuts.length(); ++i)
+ for (size_t i = 0; i < theResuts.length(); ++i)
{
GEOMImpl_IMeasureOperations::FailedChecks aCheck;
aCheck.TypeOfCheck = theResuts[i].type;
diff --git a/src/GEOM_I/GEOM_ITransformOperations_i.cc b/src/GEOM_I/GEOM_ITransformOperations_i.cc
index 8f866ca41..9e8b0b034 100644
--- a/src/GEOM_I/GEOM_ITransformOperations_i.cc
+++ b/src/GEOM_I/GEOM_ITransformOperations_i.cc
@@ -668,6 +668,47 @@ GEOM_ITransformOperations_i::OffsetShapeCopy (GEOM::GEOM_Object_ptr theObject,
return GetObject(anObject);
}
+//=============================================================================
+/*!
+ * OffsetShapePartialCopy
+ */
+//=============================================================================
+GEOM::GEOM_Object_ptr
+GEOM_ITransformOperations_i::OffsetShapePartialCopy (GEOM::GEOM_Object_ptr theObject,
+ const GEOM::ListOfLong& theFacesIDs,
+ CORBA::Double theOffset)
+{
+ GEOM::GEOM_Object_var aGEOMObject;
+
+ //Set a not done flag
+ GetOperations()->SetNotDone();
+
+ //Get the basic object
+ Handle(::GEOM_Object) aBasicObject = GetObjectImpl(theObject);
+ if (aBasicObject.IsNull()) return aGEOMObject._retn();
+
+ // Get faces IDs.
+ Handle(TColStd_HArray1OfInteger) aFaceIDs;
+ Standard_Integer aNbIDs = theFacesIDs.length();
+ if (aNbIDs > 0) {
+ aFaceIDs = new TColStd_HArray1OfInteger (1, aNbIDs);
+ for (Standard_Integer i = 0; i < aNbIDs; i++) {
+ aFaceIDs->SetValue(i + 1, theFacesIDs[i]);
+ }
+ }
+
+ // join by pipes mode is not supported in combination with partial offset
+ bool aJoinByPipes = false;
+
+ //Create the offset shape
+ Handle(::GEOM_Object) anObject =
+ GetOperations()->OffsetShapeCopy(aBasicObject, theOffset, aJoinByPipes, aFaceIDs);
+ if (!GetOperations()->IsDone() || anObject.IsNull())
+ return aGEOMObject._retn();
+
+ return GetObject(anObject);
+}
+
//=============================================================================
/*!
* ProjectShapeCopy
diff --git a/src/GEOM_I/GEOM_ITransformOperations_i.hh b/src/GEOM_I/GEOM_ITransformOperations_i.hh
index d4ad3f00f..ccadb550c 100644
--- a/src/GEOM_I/GEOM_ITransformOperations_i.hh
+++ b/src/GEOM_I/GEOM_ITransformOperations_i.hh
@@ -142,6 +142,10 @@ class GEOM_I_EXPORT GEOM_ITransformOperations_i :
CORBA::Double theOffset,
CORBA::Boolean theJoinByPipes);
+ GEOM::GEOM_Object_ptr OffsetShapePartialCopy (GEOM::GEOM_Object_ptr theObject,
+ const GEOM::ListOfLong& theFacesIDs,
+ CORBA::Double theOffset);
+
GEOM::GEOM_Object_ptr ProjectShapeCopy (GEOM::GEOM_Object_ptr theSource,
GEOM::GEOM_Object_ptr theTarget);
diff --git a/src/GEOM_SWIG/geomBuilder.py b/src/GEOM_SWIG/geomBuilder.py
index 7cf3edc64..e442cf195 100644
--- a/src/GEOM_SWIG/geomBuilder.py
+++ b/src/GEOM_SWIG/geomBuilder.py
@@ -9623,6 +9623,51 @@ class geomBuilder(GEOM._objref_GEOM_Gen):
self._autoPublish(anObj, theName, "offset")
return anObj
+ ## Create new object as partial offset of the given one.
+ # Only indexed faces are offset, others keep they original location.
+ # Gap between adjacent offset surfaces is filled
+ # by extending and intersecting them.
+ # @param theObject The base object for the offset.
+ # @param theFacesIDs The list of face IDs indicating faces to be offset.
+ # @param theOffset Offset value.
+ # @param theName Object name; when specified, this parameter is used
+ # for result publication in the study. Otherwise, if automatic
+ # publication is switched on, default value is used for result name.
+ #
+ # @return New GEOM.GEOM_Object, containing the offset object.
+ #
+ # @ref tui_offset "Example"
+ @ManageTransactions("TrsfOp")
+ def MakeOffsetPartial(self, theObject, theFacesIDs, theOffset, theName=None):
+ """
+ Create new object as partial offset of the given one.
+ Only indexed faces are offset, others keep they original location.
+ Gap between adjacent offset surfaces is filled
+ by extending and intersecting them.
+
+ Parameters:
+ theObject The base object for the offset.
+ theFacesIDs The list of face IDs indicating faces to be offset.
+ theOffset Offset value.
+ theName Object name; when specified, this parameter is used
+ for result publication in the study. Otherwise, if automatic
+ publication is switched on, default value is used for result name.
+
+ Returns:
+ New GEOM.GEOM_Object, containing the offset object.
+
+ Example of usage:
+ box = geompy.MakeBox(20, 20, 20, 200, 200, 200)
+ # create a new object from the box, offsetting its top and front faces
+ offset = geompy.MakeOffsetPartial(box, [13, 33], 70.)
+ """
+ theOffset, Parameters = ParseParameters(theOffset)
+ anObj = self.TrsfOp.OffsetShapePartialCopy(theObject, theFacesIDs, theOffset)
+ RaiseIfFailed("OffsetShapePartialCopy", self.TrsfOp)
+ anObj.SetParameters(Parameters)
+ self._autoPublish(anObj, theName, "offset")
+ return anObj
+
## Create new object as projection of the given one on another.
# @param theSource The source object for the projection. It can be a point, edge or wire.
# Edge and wire are acceptable if @a theTarget is a face.
diff --git a/src/TransformationGUI/TransformationGUI_OffsetDlg.cxx b/src/TransformationGUI/TransformationGUI_OffsetDlg.cxx
index 523c7b62f..16327d448 100644
--- a/src/TransformationGUI/TransformationGUI_OffsetDlg.cxx
+++ b/src/TransformationGUI/TransformationGUI_OffsetDlg.cxx
@@ -35,6 +35,9 @@
#include
#include
+#include
+#include
+
//=================================================================================
// class : TransformationGUI_OffsetDlg()
// purpose : Constructs a TransformationGUI_OffsetDlg which is a child of 'parent', with the
@@ -42,31 +45,41 @@
// The dialog will by default be modeless, unless you set 'modal' to
// TRUE to construct a modal dialog.
//=================================================================================
-TransformationGUI_OffsetDlg::TransformationGUI_OffsetDlg( GeometryGUI* theGeometryGUI, QWidget* parent,
- bool modal, Qt::WindowFlags fl )
- : GEOMBase_Skeleton( theGeometryGUI, parent, modal, fl )
+TransformationGUI_OffsetDlg::TransformationGUI_OffsetDlg
+ (GeometryGUI* theGeometryGUI, QWidget* parent,
+ bool modal, Qt::WindowFlags fl)
+ : GEOMBase_Skeleton(theGeometryGUI, parent, modal, fl)
{
- QPixmap image0( SUIT_Session::session()->resourceMgr()->loadPixmap( "GEOM", tr( "ICON_DLG_OFFSET" ) ) );
- QPixmap image1( SUIT_Session::session()->resourceMgr()->loadPixmap( "GEOM", tr( "ICON_SELECT" ) ) );
+ SUIT_ResourceMgr* aResMgr = SUIT_Session::session()->resourceMgr();
+ QPixmap image0 (aResMgr->loadPixmap("GEOM", tr("ICON_SELECT")));
+ QPixmap image1 (aResMgr->loadPixmap("GEOM", tr("ICON_DLG_OFFSET")));
+ QPixmap image2 (aResMgr->loadPixmap("GEOM", tr("ICON_DLG_OFFSET_PARTIAL")));
- setWindowTitle( tr( "GEOM_OFFSET_TITLE" ) );
+ setWindowTitle(tr("GEOM_OFFSET_TITLE"));
/***************************************************************/
- mainFrame()->GroupConstructors->setTitle( tr( "GEOM_OFFSET" ) );
- mainFrame()->RadioButton1->setIcon( image0 );
- mainFrame()->RadioButton2->setAttribute( Qt::WA_DeleteOnClose );
- mainFrame()->RadioButton2->close();
- mainFrame()->RadioButton3->setAttribute( Qt::WA_DeleteOnClose );
+ mainFrame()->GroupConstructors->setTitle(tr("GEOM_OFFSET"));
+ mainFrame()->RadioButton1->setIcon(image1);
+ mainFrame()->RadioButton2->setIcon(image2);
+ mainFrame()->RadioButton3->setAttribute(Qt::WA_DeleteOnClose);
mainFrame()->RadioButton3->close();
+ mainFrame()->RadioButton1->setChecked(true);
+
+ GroupPoints = new DlgRef_2Sel1Spin2Check( centralWidget() );
- GroupPoints = new DlgRef_1Sel1Spin1Check( centralWidget() );
GroupPoints->GroupBox1->setTitle( tr( "GEOM_ARGUMENTS" ) );
+
GroupPoints->TextLabel1->setText( tr( "GEOM_OBJECTS" ) );
- GroupPoints->TextLabel2->setText( tr( "GEOM_OFFSET" ) );
+ GroupPoints->TextLabel2->setText( tr( "GEOM_FACES" ) );
+ GroupPoints->TextLabel3->setText( tr( "GEOM_OFFSET" ) );
+
+ GroupPoints->PushButton1->setIcon( image0 );
+ GroupPoints->PushButton2->setIcon( image0 );
+
GroupPoints->CheckButton1->setText( tr( "GEOM_JOIN_BY_PIPES" ) );
GroupPoints->CheckButton1->setChecked( true );
-
- GroupPoints->PushButton1->setIcon( image1 );
+ GroupPoints->CheckButton2->setAttribute( Qt::WA_DeleteOnClose );
+ GroupPoints->CheckButton2->close();
QVBoxLayout* layout = new QVBoxLayout( centralWidget() );
layout->setMargin( 0 ); layout->setSpacing( 6 );
@@ -99,33 +112,76 @@ void TransformationGUI_OffsetDlg::Init()
/* init variables */
myEditCurrentArgument = GroupPoints->LineEdit1;
GroupPoints->LineEdit1->setReadOnly( true );
+ GroupPoints->LineEdit2->setReadOnly( true );
myObjects.clear();
-
- /* Get setting of step value from file configuration */
- double step = 1;
+ myFaces.clear();
/* min, max, step and decimals for spin boxes & initial values */
+ double step = 1;
initSpinBox( GroupPoints->SpinBox_DX, COORD_MIN, COORD_MAX, step, "length_precision" );
GroupPoints->SpinBox_DX->setValue( 1e-05 );
mainFrame()->GroupBoxPublish->show();
/* signals and slots connections */
- connect( buttonOk(), SIGNAL( clicked() ), this, SLOT( ClickOnOk() ) );
- connect( buttonApply(), SIGNAL( clicked() ), this, SLOT( ClickOnApply() ) );
+ connect(buttonOk(), SIGNAL(clicked()), this, SLOT(ClickOnOk()));
+ connect(buttonApply(), SIGNAL(clicked()), this, SLOT(ClickOnApply()));
+ connect(this, SIGNAL(constructorsClicked(int)),
+ this, SLOT(ConstructorsClicked(int)));
- connect( GroupPoints->PushButton1, SIGNAL( clicked() ), this, SLOT( SetEditCurrentArgument() ) );
- connect( myGeomGUI->getApp()->selectionMgr(),
- SIGNAL( currentSelectionChanged() ), this, SLOT( SelectionIntoArgument() ) );
+ connect(GroupPoints->PushButton1, SIGNAL(clicked()),
+ this, SLOT(SetEditCurrentArgument()));
+ connect(GroupPoints->PushButton2, SIGNAL(clicked()),
+ this, SLOT(SetEditCurrentArgument()));
- connect( GroupPoints->SpinBox_DX, SIGNAL( valueChanged( double ) ), this, SLOT( ValueChangedInSpinBox() ) );
- connect( GroupPoints->CheckButton1, SIGNAL( toggled( bool ) ), this, SLOT( JoinModeChanged() ) );
+ connect(GroupPoints->SpinBox_DX, SIGNAL(valueChanged(double)),
+ this, SLOT(ValueChangedInSpinBox()));
+ connect(GroupPoints->CheckButton1, SIGNAL(toggled(bool)),
+ this, SLOT(JoinModeChanged()));
- initName( tr( "GEOM_OFFSET" ) );
+ connect(myGeomGUI->getApp()->selectionMgr(), SIGNAL(currentSelectionChanged()),
+ this, SLOT(SelectionIntoArgument()));
- globalSelection( GEOM_ALLSHAPES );
- resize(100,100);
+ initName(tr("GEOM_OFFSET"));
+
+ ConstructorsClicked(0);
+}
+
+//==============================================================================
+// function : ConstructorsClicked()
+// purpose : Radio button management
+//==============================================================================
+void TransformationGUI_OffsetDlg::ConstructorsClicked (int constructorId)
+{
+ switch (constructorId) {
+ case 0:
+ // disable faces selection
+ GroupPoints->TextLabel2->hide();
+ GroupPoints->PushButton2->hide();
+ GroupPoints->LineEdit2->hide();
+
+ // enable joint type
+ GroupPoints->CheckButton1->show();
+ break;
+ case 1:
+ // enable faces selection
+ GroupPoints->TextLabel2->show();
+ GroupPoints->PushButton2->show();
+ GroupPoints->LineEdit2->show();
+
+ // disable joint type
+ GroupPoints->CheckButton1->hide();
+ break;
+ default:
+ break;
+ }
+
+ qApp->processEvents();
+ updateGeometry();
+ resize(minimumSizeHint());
+
+ GroupPoints->PushButton1->click();
SelectionIntoArgument();
}
@@ -152,6 +208,10 @@ bool TransformationGUI_OffsetDlg::ClickOnApply()
return false;
initName();
+
+ // activate selection and connect selection manager
+ ConstructorsClicked(getConstructorId());
+
return true;
}
@@ -162,13 +222,27 @@ bool TransformationGUI_OffsetDlg::ClickOnApply()
//=================================================================================
void TransformationGUI_OffsetDlg::SelectionIntoArgument()
{
- myObjects = getSelected( TopAbs_SHAPE, -1 );
- if ( !myObjects.isEmpty() ) {
- QString aName = myObjects.count() > 1 ? QString( "%1_objects").arg( myObjects.count() ) : GEOMBase::GetName( myObjects[0].get() );
- myEditCurrentArgument->setText( aName );
+ myEditCurrentArgument->setText("");
+
+ if (myEditCurrentArgument == GroupPoints->LineEdit1) {
+ if (getConstructorId() == 0) {
+ myObjects = getSelected( TopAbs_SHAPE, -1 );
+ myEditCurrentArgument->setText(GEOMBase::GetName(myObjects));
+ }
+ else if (getConstructorId() == 1) {
+ myFaces.clear();
+ GroupPoints->LineEdit2->setText("");
+ myObjects = getSelected(TopAbs_SHAPE, 1); // only one object allowed
+ if (!myObjects.isEmpty()) {
+ myEditCurrentArgument->setText(GEOMBase::GetName(myObjects[0].get()));
+ GroupPoints->PushButton2->click();
+ }
+ }
}
- else {
- myEditCurrentArgument->setText("");
+ else if (myEditCurrentArgument == GroupPoints->LineEdit2) {
+ myFaces.clear();
+ myFaces = getSelected(TopAbs_FACE, -1);
+ myEditCurrentArgument->setText(GEOMBase::GetName(myFaces));
}
processPreview();
@@ -184,11 +258,20 @@ void TransformationGUI_OffsetDlg::SetEditCurrentArgument()
QPushButton* send = (QPushButton*)sender();
if ( send == GroupPoints->PushButton1 ) {
- GroupPoints->PushButton1->setDown(true);
+ GroupPoints->PushButton2->setDown(false);
myEditCurrentArgument = GroupPoints->LineEdit1;
- myEditCurrentArgument->setFocus();
- SelectionIntoArgument();
+ globalSelection(GEOM_ALLSHAPES);
}
+ else if (send == GroupPoints->PushButton2) {
+ GroupPoints->PushButton1->setDown(false);
+ myEditCurrentArgument = GroupPoints->LineEdit2;
+ globalSelection(); // close local contexts, if any
+ if (myObjects.size() > 0)
+ localSelection(myObjects[0].get(), TopAbs_FACE);
+ }
+
+ myEditCurrentArgument->setFocus();
+ send->setDown(true);
}
@@ -210,11 +293,11 @@ void TransformationGUI_OffsetDlg::enterEvent( QEvent* )
void TransformationGUI_OffsetDlg::ActivateThisDialog()
{
GEOMBase_Skeleton::ActivateThisDialog();
+
connect( myGeomGUI->getApp()->selectionMgr(),
SIGNAL( currentSelectionChanged() ), this, SLOT( SelectionIntoArgument() ) );
- globalSelection( GEOM_ALLSHAPES );
- myEditCurrentArgument = GroupPoints->LineEdit1;
- myEditCurrentArgument->setFocus();
+
+ ConstructorsClicked(getConstructorId());
}
@@ -243,14 +326,27 @@ GEOM::GEOM_IOperations_ptr TransformationGUI_OffsetDlg::createOperation()
//=================================================================================
bool TransformationGUI_OffsetDlg::isValid( QString& msg )
{
- bool ok = GroupPoints->SpinBox_DX->isValid( msg, !IsPreview() ) && !myObjects.isEmpty();
- for ( int i = 0; i < myObjects.count() && ok; i++ ) {
- GEOM::shape_type aType = myObjects[i]->GetShapeType();
- ok = aType == GEOM::FACE || aType == GEOM::SHELL || aType == GEOM::SOLID;
- if ( !ok )
- msg = tr( "ERROR_SHAPE_TYPE" );
+ bool isOk = GroupPoints->SpinBox_DX->isValid( msg, !IsPreview() ) && !myObjects.isEmpty();
+
+ if (isOk) {
+ switch (getConstructorId()) {
+ case 0:
+ for ( int i = 0; i < myObjects.count() && isOk; i++ ) {
+ GEOM::shape_type aType = myObjects[i]->GetShapeType();
+ isOk = aType == GEOM::FACE || aType == GEOM::SHELL || aType == GEOM::SOLID;
+ if ( !isOk )
+ msg = tr( "ERROR_SHAPE_TYPE" );
+ }
+ break;
+ case 1:
+ isOk = myObjects.size() == 1 && !myFaces.isEmpty();
+ break;
+ default:
+ break;
+ }
}
- return ok;
+
+ return isOk;
}
//=================================================================================
@@ -263,28 +359,59 @@ bool TransformationGUI_OffsetDlg::execute( ObjectList& objects )
GEOM::GEOM_Object_var anObj;
- GEOM::GEOM_ITransformOperations_var anOper = GEOM::GEOM_ITransformOperations::_narrow(getOperation());
+ GEOM::GEOM_ITransformOperations_var anOper =
+ GEOM::GEOM_ITransformOperations::_narrow(getOperation());
- if ( true /*GroupPoints->CheckButton1->isChecked() || IsPreview()*/ ) {
- for ( int i = 0; i < myObjects.count(); i++ ) {
-
- anObj = anOper->OffsetShapeCopy( myObjects[i].get(), GetOffset(), GetIsJoinByPipes() );
- if ( !anObj->_is_nil() ) {
- if(!IsPreview()) {
+ if (getConstructorId() == 0) {
+ for (int i = 0; i < myObjects.count(); i++) {
+ anObj = anOper->OffsetShapeCopy(myObjects[i].get(), GetOffset(), GetIsJoinByPipes());
+ if (!anObj->_is_nil()) {
+ if (!IsPreview()) {
anObj->SetParameters(GroupPoints->SpinBox_DX->text().toUtf8().constData());
}
- objects.push_back( anObj._retn() );
+ objects.push_back(anObj._retn());
+ res = true;
}
}
}
- else {
- for ( int i = 0; i < myObjects.count(); i++ ) {
- anObj = anOper->OffsetShape( myObjects[i].get(), GetOffset(), GetIsJoinByPipes() );
- if ( !anObj->_is_nil() )
- objects.push_back( anObj._retn() );
+ else if (getConstructorId() == 1) {
+ if (myObjects.count() == 1) {
+ TopoDS_Shape aShape;
+ if (GEOMBase::GetShape(myObjects[0].get(), aShape)) {
+ TopTools_IndexedMapOfShape aMainMap;
+ TopExp::MapShapes(aShape, aMainMap);
+
+ QList aListIDs;
+ for (int i = 0; i < myFaces.count(); i++) {
+ TopoDS_Shape aFace;
+ if (GEOMBase::GetShape(myFaces[i].get(), aFace)) {
+ int anIndex = aMainMap.FindIndex(aFace);
+ if (anIndex >= 0) {
+ aListIDs << anIndex;
+ }
+ }
+ }
+
+ GEOM::ListOfLong_var aFacesIDsList = new GEOM::ListOfLong();
+ if (!aListIDs.empty()) {
+ aFacesIDsList->length(aListIDs.length());
+ for (int i = 0; i < aListIDs.length(); i++) {
+ aFacesIDsList[i] = aListIDs[i];
+ }
+ }
+
+ anObj = anOper->OffsetShapePartialCopy
+ (myObjects[0].get(), aFacesIDsList, GetOffset());
+ if (!anObj->_is_nil()) {
+ if (!IsPreview()) {
+ anObj->SetParameters(GroupPoints->SpinBox_DX->text().toUtf8().constData());
+ }
+ objects.push_back(anObj._retn());
+ res = true;
+ }
+ }
}
}
- res = true;
return res;
}
@@ -330,7 +457,6 @@ bool TransformationGUI_OffsetDlg::GetIsJoinByPipes() const
void TransformationGUI_OffsetDlg::JoinModeChanged()
{
processPreview();
- //mainFrame()->GroupBoxName->setEnabled( GroupPoints->CheckButton1->isChecked() );
}
//=================================================================================
diff --git a/src/TransformationGUI/TransformationGUI_OffsetDlg.h b/src/TransformationGUI/TransformationGUI_OffsetDlg.h
index b23938044..9407a3e78 100644
--- a/src/TransformationGUI/TransformationGUI_OffsetDlg.h
+++ b/src/TransformationGUI/TransformationGUI_OffsetDlg.h
@@ -30,14 +30,14 @@
#include "GEOMBase_Skeleton.h"
#include "GEOM_GenericObjPtr.h"
-class DlgRef_1Sel1Spin1Check;
-
+class DlgRef_2Sel1Spin2Check;
+
//=================================================================================
// class : TransformationGUI_OffsetDlg
// purpose :
//=================================================================================
class TransformationGUI_OffsetDlg : public GEOMBase_Skeleton
-{
+{
Q_OBJECT
public:
@@ -52,24 +52,26 @@ protected:
virtual bool execute( ObjectList& );
virtual void restoreSubShapes( SALOMEDS::SObject_ptr );
virtual QList getSourceObjects();
-
+
private:
void Init();
void enterEvent( QEvent* );
double GetOffset() const;
bool GetIsJoinByPipes() const;
-
+
private:
QList myObjects;
-
- DlgRef_1Sel1Spin1Check* GroupPoints;
-
+ QList myFaces;
+
+ DlgRef_2Sel1Spin2Check* GroupPoints;
+
private slots:
void ClickOnOk();
bool ClickOnApply();
void ActivateThisDialog();
void SelectionIntoArgument();
void SetEditCurrentArgument();
+ void ConstructorsClicked(int);
void ValueChangedInSpinBox();
void JoinModeChanged();
};