0023407: Draw face outlines for XDE objects
authorapl <apl@opencascade.com>
Fri, 14 Sep 2012 10:37:57 +0000 (14:37 +0400)
committerapl <apl@opencascade.com>
Fri, 14 Sep 2012 10:37:57 +0000 (14:37 +0400)
FaceOutline aspect and flag added to AIS_Drawer, Prs3d_Drawer.cdl
FaceOutlines computed by StdPrs_ShadedShape and build upon the edge triangulation.
"vshowoutlines" draw command for testing outlines on AIS_Shapes,
"XShowOutlines" draw command for testing outlines on XCAF objects.
remarks corrected:
- FaceOutline renamed to FaceBoundary
- Graphic3d_ArrayOfSegments with edges used instead of Graphic3d_ArrayOfPolylines with bounds.
draw boundaries in separate Graphic3d_Group.
Adding test cases bugs/vis/CR23407_1 CR23407_2

12 files changed:
src/AIS/AIS_Drawer.cdl
src/AIS/AIS_Drawer.cxx
src/AIS/AIS_Drawer.lxx
src/Prs3d/Prs3d_Drawer.cdl
src/Prs3d/Prs3d_Drawer.cxx
src/StdPrs/StdPrs_ShadedShape.cxx
src/ViewerTest/ViewerTest_ObjectCommands.cxx
src/XDEDRAW/XDEDRAW.cxx
tests/bugs/end
tests/bugs/grids.list
tests/bugs/vis/CR23407_1 [new file with mode: 0755]
tests/bugs/vis/CR23407_2 [new file with mode: 0755]

index 4ab0f94..b311385 100755 (executable)
@@ -478,7 +478,42 @@ is
        --          Type of line: Aspect_TOL_SOLID Width: 1.
     is redefined static;
     
+    SetFaceBoundaryDraw (me           : mutable;
+                         theIsEnabled : Boolean from Standard)
+    is redefined static;
+        ---Purpose: Enables or disables drawing of face boundaries for shading presentations.
+        -- The method sets drawing flag owned by the drawer that will be used during
+        -- visualization instead of the one set in link.
+        -- theIsEnabled is a boolean flag indicating whether the face boundaries should be
+        -- drawn or not.
+
+    IsFaceBoundaryDraw (me) returns Boolean from Standard
+    is redefined static;
+        ---Purpose: Checks whether the drawing of face boundaries is enabled or not.
+
+    SetFaceBoundaryAspect (me        : mutable;
+                           theAspect : LineAspect from Prs3d)
+    is redefined static;
+        ---Purpose: Sets line aspect for face boundaries.
+        -- The method sets line aspect owned by the drawer that will be used during
+        -- visualization instead of the one set in link.
+        -- theAspect is the line aspect that determines the look of the face boundaries.
+
+    FaceBoundaryAspect (me : mutable) returns mutable LineAspect from Prs3d
+    is redefined static;
+        ---Purpose: Returns line aspect of face boundaries.
+
+    IsOwnFaceBoundaryDraw (me) returns Boolean from Standard
+    is static;
+        ---Purpose: Returns true if the drawer has its own attribute for 
+        -- "draw face boundaries" flag that overrides the one in the link.
+        ---C++: inline
 
+    IsOwnFaceBoundaryAspect (me) returns Boolean from Standard
+    is static;
+        ---Purpose: Returns true if the drawer has its own attribute for 
+        -- face boundaries aspect that overrides the one in the link.
+        ---C++: inline
 --
 --  Attributes for the presentation of a Datum.
 --  
@@ -593,6 +628,7 @@ fields
     myOwnHLRDeviationAngle           : Real from Standard; 
     myPreviousHLRDeviationAngle      : Real from Standard;             
 
+       myHasOwnFaceBoundaryDraw         : Boolean from Standard;
 end Drawer;
  
 
index 41a9adf..c3d6cc2 100755 (executable)
@@ -26,7 +26,8 @@ myhasOwnDeviationCoefficient(Standard_False),
 myPreviousDeviationCoefficient(0.1),
 myhasOwnHLRDeviationCoefficient (Standard_False),
 myhasOwnDeviationAngle (Standard_False),
-myhasOwnHLRDeviationAngle (Standard_False)
+myhasOwnHLRDeviationAngle (Standard_False),
+myHasOwnFaceBoundaryDraw (Standard_False)
 {
   SetMaximalParameterValue(500000.);
   myLink->SetMaximalParameterValue(500000.);
@@ -262,10 +263,58 @@ void AIS_Drawer::ClearLocalAttributes()
   if(!myRadiusAspect.IsNull())  myRadiusAspect.Nullify();    
   if(!mySectionAspect.IsNull())  mySectionAspect.Nullify();   
   if( myhasOwnHLRDeviationCoefficient )  myhasOwnHLRDeviationCoefficient = Standard_False;   
-  if(myhasOwnHLRDeviationAngle ) myhasOwnHLRDeviationAngle  = Standard_False;   
+  if(myhasOwnHLRDeviationAngle ) myhasOwnHLRDeviationAngle  = Standard_False;
+  if (!myFaceBoundaryAspect.IsNull()) myFaceBoundaryAspect.Nullify();
   
+  myHasOwnFaceBoundaryDraw = Standard_False;
+
   hasLocalAttributes = Standard_False;
 
 }
 
+// =======================================================================
+// function : SetFaceBoundaryDraw
+// purpose  :
+// =======================================================================
+void AIS_Drawer::SetFaceBoundaryDraw (const Standard_Boolean theIsEnabled)
+{
+  myHasOwnFaceBoundaryDraw = Standard_True;
+  myFaceBoundaryDraw       = theIsEnabled;
+}
+
+// =======================================================================
+// function : IsFaceBoundaryDraw
+// purpose  :
+// =======================================================================
+Standard_Boolean AIS_Drawer::IsFaceBoundaryDraw() const
+{
+  if (!IsOwnFaceBoundaryDraw ())
+  {
+    return myLink->IsFaceBoundaryDraw ();
+  }
+
+  return myFaceBoundaryDraw;
+}
 
+// =======================================================================
+// function : SetFaceBoundaryAspect
+// purpose  :
+// =======================================================================
+void AIS_Drawer::SetFaceBoundaryAspect (const Handle(Prs3d_LineAspect)& theAspect)
+{
+  myFaceBoundaryAspect = theAspect;
+}
+
+// =======================================================================
+// function : FaceBoundaryAspect
+// purpose  :
+// =======================================================================
+Handle_Prs3d_LineAspect AIS_Drawer::FaceBoundaryAspect()
+{
+  if (!IsOwnFaceBoundaryAspect ())
+  {
+    return myLink->FaceBoundaryAspect ();
+  }
+
+  return myFaceBoundaryAspect;
+}
index 3e3e644..c4608ca 100755 (executable)
@@ -94,3 +94,8 @@ inline Standard_Boolean AIS_Drawer::HasPlaneAspect ()  const
 inline Standard_Boolean AIS_Drawer::HasLengthAspect ()  const 
 { return !myLengthAspect.IsNull();}
 
+inline Standard_Boolean AIS_Drawer::IsOwnFaceBoundaryDraw () const
+{ return myHasOwnFaceBoundaryDraw; }
+
+inline Standard_Boolean AIS_Drawer::IsOwnFaceBoundaryAspect () const
+{ return !myFaceBoundaryAspect.IsNull (); }
index 16331a1..6699d1b 100755 (executable)
@@ -502,6 +502,27 @@ is
     is virtual;
        ---Purpose: Sets the parameter anAspect for display attributes of sections.
     
+    SetFaceBoundaryDraw (me           : mutable;
+                         theIsEnabled : Boolean from Standard)
+    is virtual;
+        ---Purpose: Enables or disables face boundary drawing for shading presentations.
+        -- theIsEnabled is a boolean flag indicating whether the face boundaries should be
+        -- drawn or not.
+
+    IsFaceBoundaryDraw (me) returns Boolean from Standard
+    is virtual;
+        ---Purpose: Checks whether the face boundary drawing is enabled or not.
+
+    SetFaceBoundaryAspect (me        : mutable;
+                           theAspect : LineAspect from Prs3d)
+    is virtual;
+        ---Purpose: Sets line aspect for face boundaries.
+        -- theAspect is the line aspect that determines the look of the face boundaries.
+
+    FaceBoundaryAspect (me : mutable) returns mutable LineAspect from Prs3d
+    is virtual;
+        ---Purpose: Returns line aspect of face boundaries.
+
 fields
             myUIsoAspect: IsoAspect from Prs3d is protected;
             myVIsoAspect: IsoAspect from Prs3d is protected;
@@ -541,4 +562,6 @@ fields
            myAngleAspect: AngleAspect from Prs3d is protected;
            myRadiusAspect: RadiusAspect from Prs3d is protected;
             mySectionAspect: LineAspect from Prs3d is protected;
+        myFaceBoundaryDraw    : Boolean from Standard is protected;
+        myFaceBoundaryAspect  : LineAspect from Prs3d is protected;
 end Drawer;
index 6bde505..3c5a637 100755 (executable)
@@ -36,7 +36,8 @@ Prs3d_Drawer::Prs3d_Drawer(): myNbPoints(30),myIsoOnPlane(Standard_False),
  myDeviationAngle(12*M_PI/180),
  myHLRAngle(20*M_PI/180),
  myLineDrawArrow(Standard_False),
- myDrawHiddenLine(Standard_False)
+ myDrawHiddenLine(Standard_False),
+ myFaceBoundaryDraw(Standard_False)
 {
 } 
 
@@ -438,3 +439,45 @@ Handle (Prs3d_LineAspect) Prs3d_Drawer::SectionAspect ()  {
 void Prs3d_Drawer::SetSectionAspect ( const Handle(Prs3d_LineAspect)& anAspect) {
  mySectionAspect = anAspect;
 }
+
+// =======================================================================
+// function : SetFaceBoundaryDraw
+// purpose  :
+// =======================================================================
+void Prs3d_Drawer::SetFaceBoundaryDraw (const Standard_Boolean theIsEnabled)
+{
+  myFaceBoundaryDraw = theIsEnabled;
+}
+
+// =======================================================================
+// function : IsFaceBoundaryDraw
+// purpose  :
+// =======================================================================
+Standard_Boolean Prs3d_Drawer::IsFaceBoundaryDraw () const
+{
+  return myFaceBoundaryDraw;
+}
+
+// =======================================================================
+// function : SetFaceBoundaryAspect
+// purpose  :
+// =======================================================================
+void Prs3d_Drawer::SetFaceBoundaryAspect (const Handle(Prs3d_LineAspect)& theAspect)
+{
+  myFaceBoundaryAspect = theAspect;
+}
+
+// =======================================================================
+// function : FaceBoundaryAspect
+// purpose  :
+// =======================================================================
+Handle_Prs3d_LineAspect Prs3d_Drawer::FaceBoundaryAspect ()
+{
+  if (myFaceBoundaryAspect.IsNull ())
+  {
+    myFaceBoundaryAspect = 
+      new Prs3d_LineAspect (Quantity_NOC_BLACK, Aspect_TOL_SOLID, 1.0);
+  }
+
+  return myFaceBoundaryAspect;
+}
index 056994d..806ec2c 100644 (file)
 #include <TopoDS_Face.hxx>
 #include <TColgp_Array1OfDir.hxx>
 #include <TColgp_Array1OfPnt2d.hxx>
+#include <TopoDS_Compound.hxx>
+#include <Poly_PolygonOnTriangulation.hxx>
+#include <TopExp.hxx>
+#include <TopTools_ListOfShape.hxx>
+#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
+#include <NCollection_List.hxx>
+#include <Graphic3d_ArrayOfSegments.hxx>
+#include <Prs3d_LineAspect.hxx>
+#include <TColgp_HArray1OfPnt.hxx>
+#include <Aspect_PolygonOffsetMode.hxx>
 
 #define MAX2(X, Y)       (Abs(X) > Abs(Y) ? Abs(X) : Abs(Y))
 #define MAX3(X, Y, Z)  (MAX2 (MAX2 (X, Y), Z))
@@ -202,6 +212,130 @@ namespace
     }
     return Standard_True;
   }
+
+  // =======================================================================
+  // function : ComputeFaceBoundaries
+  // purpose  : Compute boundary presentation for faces of the shape.
+  // =======================================================================
+  static void ComputeFaceBoundaries (const TopoDS_Shape& theShape,
+                                     const Handle (Prs3d_Presentation)& thePresentation,
+                                     const Handle (Prs3d_Drawer)& theDrawer)
+  {
+    // collection of all triangulation nodes on edges
+    // for computing boundaries presentation
+    NCollection_List<Handle(TColgp_HArray1OfPnt)> aNodeCollection;
+    Standard_Integer aNodeNumber = 0;
+
+    TopLoc_Location aTrsf;
+
+    // explore all boundary edges
+    TopTools_IndexedDataMapOfShapeListOfShape anEdgesMap;
+    TopExp::MapShapesAndAncestors (
+      theShape, TopAbs_EDGE, TopAbs_FACE, anEdgesMap);
+
+    Standard_Integer anEdgeIdx = 1;
+    for ( ; anEdgeIdx <= anEdgesMap.Extent (); anEdgeIdx++)
+    {
+      // reject free edges
+      const TopTools_ListOfShape& aFaceList = anEdgesMap.FindFromIndex (anEdgeIdx);
+      if (aFaceList.Extent() == 0)
+        continue;
+
+      // take one of the shared edges and get edge triangulation
+      const TopoDS_Face& aFace  = TopoDS::Face (aFaceList.First ());
+      const TopoDS_Edge& anEdge = TopoDS::Edge (anEdgesMap.FindKey (anEdgeIdx));
+
+      Handle(Poly_Triangulation) aTriangulation =
+        BRep_Tool::Triangulation (aFace, aTrsf);
+
+      if (aTriangulation.IsNull ())
+        continue;
+
+      Handle(Poly_PolygonOnTriangulation) anEdgePoly =
+        BRep_Tool::PolygonOnTriangulation (anEdge, aTriangulation, aTrsf);
+
+      if (anEdgePoly.IsNull ())
+        continue;
+
+      // get edge nodes indexes from face triangulation
+      const TColgp_Array1OfPnt& aTriNodes = aTriangulation->Nodes ();
+      const TColStd_Array1OfInteger& anEdgeNodes = anEdgePoly->Nodes ();
+
+      if (anEdgeNodes.Length () < 2)
+        continue;
+
+      // collect the edge nodes
+      Handle(TColgp_HArray1OfPnt) aCollected =
+        new TColgp_HArray1OfPnt (anEdgeNodes.Lower (), anEdgeNodes.Upper ());
+
+      Standard_Integer aNodeIdx = anEdgeNodes.Lower ();
+      for ( ; aNodeIdx <= anEdgeNodes.Upper (); aNodeIdx++)
+      {
+        // node index in face triangulation
+        Standard_Integer aTriIndex = anEdgeNodes.Value (aNodeIdx);
+
+        // get node and apply location transformation to the node
+        gp_Pnt aTriNode = aTriNodes.Value (aTriIndex);
+        if (!aTrsf.IsIdentity ())
+          aTriNode.Transform (aTrsf);
+
+        // add node to the boundary array
+        aCollected->SetValue (aNodeIdx, aTriNode);
+      }
+
+      aNodeNumber += anEdgeNodes.Length ();
+      aNodeCollection.Append (aCollected);
+    }
+
+    // check if it possible to continue building the presentation
+    if (aNodeNumber == 0)
+      return;
+
+    // allocate polyline array for presentation
+    Standard_Integer aSegmentEdgeNb = 
+      (aNodeNumber - aNodeCollection.Extent()) * 2;
+
+    Handle(Graphic3d_ArrayOfSegments) aSegments = 
+      new Graphic3d_ArrayOfSegments (aNodeNumber, aSegmentEdgeNb);
+
+    // build presentation for edge bondaries
+    NCollection_List<Handle(TColgp_HArray1OfPnt)>::Iterator 
+      aCollIt (aNodeCollection);
+
+    // the edge index is increased in each iteration step to
+    // avoid contiguous segments between different face edges.
+    for ( ; aCollIt.More(); aCollIt.Next () )
+    {
+      const Handle(TColgp_HArray1OfPnt)& aNodeArray = aCollIt.Value ();
+
+      Standard_Integer aNodeIdx = aNodeArray->Lower ();
+
+      // add first node (this node is not shared with previous segment).
+      // for each face edge, indices for sharing nodes 
+      // between segments begin from the first added node.
+      Standard_Integer aSegmentEdge = 
+        aSegments->AddVertex (aNodeArray->Value (aNodeIdx));
+
+      // add subsequent nodes and provide edge indexes for sharing
+      // the nodes between the sequential segments.
+      for ( aNodeIdx++; aNodeIdx <= aNodeArray->Upper (); aNodeIdx++ )
+      {
+        aSegments->AddVertex (aNodeArray->Value (aNodeIdx));
+        aSegments->AddEdge (  aSegmentEdge);
+        aSegments->AddEdge (++aSegmentEdge);
+      }
+    }
+
+    // set up aspect and add polyline data
+    Handle(Graphic3d_AspectLine3d) aBoundaryAspect = 
+      theDrawer->FaceBoundaryAspect ()->Aspect ();
+
+    Handle(Graphic3d_Group) aPrsGrp = Prs3d_Root::NewGroup (thePresentation);
+    aPrsGrp->SetGroupPrimitivesAspect (aBoundaryAspect);
+    aPrsGrp->BeginPrimitives ();
+    aPrsGrp->AddPrimitiveArray (aSegments);
+    aPrsGrp->EndPrimitives ();
+  }
 };
 
 // =======================================================================
@@ -285,5 +419,9 @@ void StdPrs_ShadedShape::Add (const Handle (Prs3d_Presentation)& thePresentation
 
   ShadeFromShape (theShape, thePresentation, theDrawer,
                   theHasTexels, theUVOrigin, theUVRepeat, theUVScale);
-}
 
+  if (theDrawer->IsFaceBoundaryDraw ())
+  {
+    ComputeFaceBoundaries (theShape, thePresentation, theDrawer);
+  }
+}
index 330d9b8..846bb7b 100755 (executable)
 #include <SelectMgr_Selection.hxx>
 #include <StdFail_NotDone.hxx>
 #include <StdPrs_ShadedShape.hxx>
-#include <TopoDS_Wire.hxx> 
+#include <TopoDS_Wire.hxx>
 
 #include <AIS_ConnectedShape.hxx>
 #include <TopLoc_Location.hxx>
 #include <BRepExtrema_ExtPC.hxx>
 #include <BRepExtrema_ExtPF.hxx>
 
+#include <Prs3d_LineAspect.hxx>
+
 #ifdef HAVE_STRINGS_H
 #include <strings.h>
 #endif
@@ -4283,6 +4285,123 @@ static Standard_Integer VPolygonOffset(Draw_Interpretor& di,
 }
 
 //=======================================================================
+//function : VShowFaceBoundaries
+//purpose  : Set face boundaries drawing on/off for ais object
+//=======================================================================
+static Standard_Integer VShowFaceBoundary (Draw_Interpretor& di,
+                                           Standard_Integer argc,
+                                           const char ** argv)
+{
+  Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext ();
+  if (aContext.IsNull ())
+  {
+    std::cout << argv[0] << " Call 'vinit' before!\n";
+    return 1;
+  }
+
+  if ((argc != 3 && argc < 6) || argc > 8)
+  {
+    std::cout << "Usage :\n " << argv[0]
+              << " ObjectName isOn [R G B [LineWidth [LineStyle]]]\n"
+              << "   ObjectName - name of AIS interactive object. \n"
+              << "                if ObjectName = \"\", then set as default\n"
+              << "                settings for all newly displayed objects\n"
+              << "   isOn       - flag indicating whether the boundaries\n"
+              << "                should be turned on or off (can be set\n"
+              << "                to 0 (off) or 1 (on)).\n"
+              << "   R, G, B    - red, green and blue components of boundary\n"
+              << "                color in range (0 - 255).\n"
+              << "                (default is (0, 0, 0)\n"
+              << "   LineWidth  - line width\n"
+              << "                (default is 1)\n"
+              << "   LineStyle  - line fill style :\n"
+              << "                 0 - solid  \n"
+              << "                 1 - dashed \n"
+              << "                 2 - dot    \n"
+              << "                 3 - dashdot\n"
+              << "                 (default is solid)";
+    return 1;
+  }
+
+  TCollection_AsciiString aName (argv[1]);
+
+  Quantity_Parameter aRed      = 0.0;
+  Quantity_Parameter aGreen    = 0.0;
+  Quantity_Parameter aBlue     = 0.0;
+  Standard_Real      aWidth    = 1.0;
+  Aspect_TypeOfLine  aLineType = Aspect_TOL_SOLID;
+  
+  // find object
+  Handle(AIS_InteractiveObject) anInterObj;
+
+  // if name is empty - apply attributes for default aspect
+  if (!aName.IsEmpty ())
+  {
+    ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS ();
+    if (!aMap.IsBound2 (aName))
+    {
+      std::cout << "Use 'vdisplay' on " << aName << " before" << std::endl;
+      return 1;
+    }
+
+    // find interactive object
+    Handle(Standard_Transient) anObj = GetMapOfAIS ().Find2 (aName);
+    anInterObj = Handle(AIS_InteractiveObject)::DownCast (anObj);
+    if (anInterObj.IsNull ())
+    {
+      std::cout << "Not an AIS interactive object!" << std::endl;
+      return 1;
+    }
+  }
+  
+  const Handle(Prs3d_Drawer)& aDrawer = (aName.IsEmpty ()) ?
+    TheAISContext ()->DefaultDrawer () : anInterObj->Attributes ();
+
+  // turn boundaries on/off
+  Standard_Boolean isBoundaryDraw = (atoi (argv[2]) == 1);
+  aDrawer->SetFaceBoundaryDraw (isBoundaryDraw);
+  
+  // set boundary line color
+  if (argc >= 6)
+  {
+    // Text color
+    aRed   = atof (argv[3])/255.;
+    aGreen = atof (argv[4])/255.;
+    aBlue  = atof (argv[5])/255.;
+  }
+
+  // set line width
+  if (argc >= 7)
+  {
+    aWidth = (Standard_Real)atof (argv[6]);
+  }
+
+  // select appropriate line type
+  if (argc == 8)
+  {
+    switch (atoi (argv[7]))
+    {
+      case 1: aLineType = Aspect_TOL_DASH;    break;
+      case 2: aLineType = Aspect_TOL_DOT;     break;
+      case 3: aLineType = Aspect_TOL_DOTDASH; break;
+      default:
+        aLineType = Aspect_TOL_SOLID;
+    }
+  }
+
+  Quantity_Color aColor (aRed, aGreen, aBlue, Quantity_TOC_RGB);
+
+  Handle(Prs3d_LineAspect) aBoundaryAspect = 
+    new Prs3d_LineAspect (aColor, aLineType, aWidth);
+
+  aDrawer->SetFaceBoundaryAspect (aBoundaryAspect);
+
+  TheAISContext()->Redisplay (anInterObj);
+  
+  return 0;
+}
+
+//=======================================================================
 //function : ObjectsCommands
 //purpose  :
 //=======================================================================
@@ -4394,4 +4513,10 @@ void ViewerTest::ObjectCommands(Draw_Interpretor& theCommands)
   theCommands.Add("vpolygonoffset",
     "vpolygonoffset : [object [mode factor units]] - sets/gets polygon offset parameters for an object, without arguments prints the default values",
     __FILE__, VPolygonOffset, group);
+
+  theCommands.Add ("vshowfaceboundary",
+    "vshowfaceboundary : ObjectName isOn (1/0) [R G B [LineWidth [LineStyle]]]"
+    "- turns on/off drawing of face boundaries for ais object "
+    "and defines boundary line style.",
+    __FILE__, VShowFaceBoundary, group);
 }
index aafa46f..bde3e35 100755 (executable)
 #include <TColStd_HArray1OfInteger.hxx>
 #include <TColStd_HArray1OfReal.hxx>
 
+#include <AIS_InteractiveObject.hxx>
+#include <AIS_Drawer.hxx>
+#include <Aspect_TypeOfLine.hxx>
+#include <Prs3d_LineAspect.hxx>
+
 #define ZVIEW_SIZE 1000000.0
 // avoid warnings on 'extern "C"' functions returning C++ classes
 #ifdef WNT
@@ -873,6 +878,135 @@ static Standard_Integer XSetTransparency (Draw_Interpretor& di, Standard_Integer
   return 0;
 }
 
+//=======================================================================
+//function : XShowFaceBoundary
+//purpose  : Set face boundaries on/off
+//=======================================================================
+static Standard_Integer XShowFaceBoundary (Draw_Interpretor& di,
+                                           Standard_Integer argc,
+                                           const char ** argv)
+{
+  if (( argc != 4 && argc < 7 ) || argc > 9)
+  {
+    di << "Usage :\n " << argv[0]
+       << " Doc Label IsOn [R G B [LineWidth [LineStyle]]]\n"
+       << "   Doc       - is the document name. \n"
+       << "   Label     - is the shape label. \n"
+       << "   IsOn      - flag indicating whether the boundaries\n"
+       << "                should be turned on or off (can be set\n"
+       << "                to 0 (off) or 1 (on)).\n"
+       << "   R, G, B   - red, green and blue components of boundary\n"
+       << "                color in range (0 - 255).\n"
+       << "                (default is (0, 0, 0)\n"
+       << "   LineWidth - line width\n"
+       << "                (default is 1)\n"
+       << "   LineStyle - line fill style :\n"
+       << "                 0 - solid  \n"
+       << "                 1 - dashed \n"
+       << "                 2 - dot    \n"
+       << "                 3 - dashdot\n"
+       << "                (default is solid)";
+
+    return 1;
+  }
+
+  // get specified document
+  Handle(TDocStd_Document) aDoc;
+  DDocStd::GetDocument (argv[1], aDoc);
+  if (aDoc.IsNull())
+  {
+    di << argv[1] << " is not a document" << "\n"; 
+    return 1;
+  }
+
+  Handle(AIS_InteractiveContext) aContext;
+  if (!TPrsStd_AISViewer::Find (aDoc->GetData()->Root(), aContext)) 
+  {
+    di << "Cannot find viewer for document " << argv[1] << "\n";
+    return 1;
+  }
+
+  // get shape tool for shape verification
+  Handle(XCAFDoc_ShapeTool) aShapes =
+    XCAFDoc_DocumentTool::ShapeTool (aDoc->Main());
+
+  // get label and validate that it is a shape label
+  TDF_Label aLabel;
+  TDF_Tool::Label (aDoc->GetData(), argv[2], aLabel);
+  if (aLabel.IsNull() || !aShapes->IsShape (aLabel))
+  {
+    di << argv[2] << " is not a valid shape label!";
+    return 1;
+  }
+
+  // get presentation from label
+  Handle(TPrsStd_AISPresentation) aPrs;
+  if (!aLabel.FindAttribute (TPrsStd_AISPresentation::GetID (), aPrs))
+  {
+    aPrs = TPrsStd_AISPresentation::Set (aLabel,XCAFPrs_Driver::GetID ());
+  }
+
+  Handle(AIS_InteractiveObject) anInteractive = aPrs->GetAIS ();
+  if (anInteractive.IsNull ())
+  {
+    di << "Can't set drawer attributes.\n"
+          "Interactive object for shape label doesn't exists.";
+    return 1;
+  }
+
+  // get drawer
+  const Handle(AIS_Drawer)& aDrawer = anInteractive->Attributes ();
+
+  // default attributes
+  Quantity_Parameter aRed      = 0.0;
+  Quantity_Parameter aGreen    = 0.0;
+  Quantity_Parameter aBlue     = 0.0;
+  Standard_Real      aWidth    = 1.0;
+  Aspect_TypeOfLine  aLineType = Aspect_TOL_SOLID;
+  
+  // turn boundaries on/off
+  Standard_Boolean isBoundaryDraw = (atoi (argv[3]) == 1);
+  aDrawer->SetFaceBoundaryDraw (isBoundaryDraw);
+  
+  // set boundary color
+  if (argc >= 7)
+  {
+    // Text color
+    aRed   = atof (argv[4])/255.;
+    aGreen = atof (argv[5])/255.;
+    aBlue  = atof (argv[6])/255.;
+  }
+
+  // set line width
+  if (argc >= 8)
+  {
+    aWidth = (Standard_Real)atof (argv[7]);
+  }
+
+  // select appropriate line type
+  if (argc == 9)
+  {
+    switch (atoi (argv[8]))
+    {
+      case 1: aLineType = Aspect_TOL_DASH;    break;
+      case 2: aLineType = Aspect_TOL_DOT;     break;
+      case 3: aLineType = Aspect_TOL_DOTDASH; break;
+      default:
+        aLineType = Aspect_TOL_SOLID;
+    }
+  }
+
+  Quantity_Color aColor (aRed, aGreen, aBlue, Quantity_TOC_RGB);
+
+  Handle(Prs3d_LineAspect) aBoundaryAspect = 
+    new Prs3d_LineAspect (aColor, aLineType, aWidth);
+
+  aDrawer->SetFaceBoundaryAspect (aBoundaryAspect);
+
+  aContext->Redisplay (anInteractive);
+  
+  return 0;
+}
 
 //=======================================================================
 //function : Init
@@ -944,6 +1078,11 @@ void XDEDRAW::Init(Draw_Interpretor& di)
   di.Add ("XSetTransparency", "Doc Transparency [label1 label2 ...]\t: Set transparency for given label(s) or whole doc",
                   __FILE__, XSetTransparency, g);
 
+  di.Add ("XShowFaceBoundary", 
+          "Doc Label IsOn [R G B [LineWidth [LineStyle]]]:"
+          "- turns on/off drawing of face boundaries and defines boundary line style",
+          __FILE__, XShowFaceBoundary, g);
+
   // Specialized commands
   XDEDRAW_Shapes::InitCommands ( di );
   XDEDRAW_Colors::InitCommands ( di );
index 70ed40c..796d195 100755 (executable)
@@ -14,6 +14,7 @@ if { [isdraw result] } {
        vfit
        vdump $imagedir/${test_image}.gif
     }
+}
     if { [info exist only_xwd] } {
        xwd $imagedir/${test_image}.gif 
     }
index edfa79c..678fa13 100755 (executable)
@@ -1,7 +1,10 @@
 001 demo
 002 fclasses
 003 iges
-004 xde
+004 vis
+005 xde
+
+
 
 
 
diff --git a/tests/bugs/vis/CR23407_1 b/tests/bugs/vis/CR23407_1
new file mode 100755 (executable)
index 0000000..251c578
--- /dev/null
@@ -0,0 +1,40 @@
+puts "============"
+puts "CR23407"
+puts "============"
+puts ""
+#######################################################################
+# Draw face outlines for XDE objects
+#######################################################################
+pload QAcommands
+pload XDEDRAW
+
+set r_check 1
+set g_check 0
+set b_check 0
+set x1 227
+set y1 143
+
+XNewDoc Doc1
+ReadStep Doc1 [locate_data_file CR23407-screw.step]
+XShow Doc1 0:1:1:1
+XShowFaceBoundary Doc1 0:1:1:1 1 255 0 0 200 1
+vfit
+vsetdispmode 1
+
+set color [ QAGetPixelColor ${x1} ${y1} ]
+regexp {RED +: +([-0-9.+eE]+)} $color full rd
+regexp {GREEN +: +([-0-9.+eE]+)} $color full gr
+regexp {BLUE +: +([-0-9.+eE]+)} $color full bl
+
+if { $rd != $r_check || $gr != $g_check || $bl != $b_check } {
+    puts "Error : color are not equal"
+    puts "Error : Boundary of face is not changed"
+}
+
+set 3dviewer 1
+
+
+
+
+
+
diff --git a/tests/bugs/vis/CR23407_2 b/tests/bugs/vis/CR23407_2
new file mode 100755 (executable)
index 0000000..64f1335
--- /dev/null
@@ -0,0 +1,39 @@
+puts "============"
+puts "CR23407"
+puts "============"
+puts ""
+#######################################################################
+# Draw face outlines for XDE objects
+#######################################################################
+pload QAcommands
+pload AISV MODELING
+
+set r_check 1
+set g_check 0
+set b_check 0
+set x1 183
+set y1 190
+
+box b 10 10 10
+vinit
+vdisplay b
+vsetdispmode 1
+vshowfaceboundary b 1 255 0 0 200 1
+vfit
+
+set color [ QAGetPixelColor ${x1} ${y1} ]
+regexp {RED +: +([-0-9.+eE]+)} $color full rd
+regexp {GREEN +: +([-0-9.+eE]+)} $color full gr
+regexp {BLUE +: +([-0-9.+eE]+)} $color full bl
+
+if { $rd != $r_check || $gr != $g_check || $bl != $b_check } {
+    puts "Error : color are not equal"
+    puts "Error : Boundary of face is not changed"
+}
+
+set 3dviewer 1
+
+
+
+
+