* Implement methods for copying tessellation to BRepTools_TrsfModification to keep the triangulation during transformation.
* Add tests to reproduce the problem.
//purpose :
//=======================================================================
-BRepBuilderAPI_Transform::BRepBuilderAPI_Transform (const TopoDS_Shape& S,
- const gp_Trsf& T,
- const Standard_Boolean Copy) :
- myTrsf(T)
+BRepBuilderAPI_Transform::BRepBuilderAPI_Transform (const TopoDS_Shape& theShape,
+ const gp_Trsf& theTrsf,
+ const Standard_Boolean theCopyGeom,
+ const Standard_Boolean theCopyMesh)
+ : myTrsf(theTrsf)
{
- myModification = new BRepTools_TrsfModification(T);
- Perform(S,Copy);
+ myModification = new BRepTools_TrsfModification(theTrsf);
+ Perform(theShape, theCopyGeom, theCopyMesh);
}
//purpose :
//=======================================================================
-void BRepBuilderAPI_Transform::Perform(const TopoDS_Shape& S,
- const Standard_Boolean Copy)
+void BRepBuilderAPI_Transform::Perform(const TopoDS_Shape& theShape,
+ const Standard_Boolean theCopyGeom,
+ const Standard_Boolean theCopyMesh)
{
- myUseModif = Copy || myTrsf.IsNegative() || (Abs(Abs(myTrsf.ScaleFactor()) - 1.) > TopLoc_Location::ScalePrec());
+ myUseModif = theCopyGeom || myTrsf.IsNegative() || (Abs(Abs(myTrsf.ScaleFactor()) - 1.) > TopLoc_Location::ScalePrec());
if (myUseModif) {
Handle(BRepTools_TrsfModification) theModif =
Handle(BRepTools_TrsfModification)::DownCast(myModification);
theModif->Trsf() = myTrsf;
- DoModif(S,myModification);
+ theModif->IsCopyMesh() = theCopyMesh;
+ DoModif(theShape, myModification);
}
else {
myLocation = myTrsf;
- myShape = S.Moved(myLocation);
+ myShape = theShape.Moved(myLocation);
Done();
}
//! to define the shape to transform.
Standard_EXPORT BRepBuilderAPI_Transform(const gp_Trsf& T);
- //! Creates a transformation from the gp_Trsf <T>, and
- //! applies it to the shape <S>. If the transformation
+ //! Creates a transformation from the gp_Trsf <theTrsf>, and
+ //! applies it to the shape <theShape>. If the transformation
//! is direct and isometric (determinant = 1) and
- //! <Copy> = Standard_False, the resulting shape is
- //! <S> on which a new location has been set.
+ //! <theCopyGeom> = Standard_False, the resulting shape is
+ //! <theShape> on which a new location has been set.
//! Otherwise, the transformation is applied on a
- //! duplication of <S>.
- Standard_EXPORT BRepBuilderAPI_Transform(const TopoDS_Shape& S, const gp_Trsf& T, const Standard_Boolean Copy = Standard_False);
+ //! duplication of <theShape>.
+ //! If <theCopyMesh> is true, the triangulation will be copied,
+ //! and the copy will be assigned to the result shape.
+ Standard_EXPORT BRepBuilderAPI_Transform(const TopoDS_Shape& theShape,
+ const gp_Trsf& theTrsf,
+ const Standard_Boolean theCopyGeom = Standard_False,
+ const Standard_Boolean theCopyMesh = Standard_False);
- //! pplies the geometric transformation defined at the
+ //! Applies the geometric transformation defined at the
//! time of construction of this framework to the shape S.
//! - If the transformation T is direct and isometric, in
//! other words, if the determinant of the vectorial part
- //! of T is equal to 1., and if Copy equals false (the
+ //! of T is equal to 1., and if theCopyGeom equals false (the
//! default value), the resulting shape is the same as
//! the original but with a new location assigned to it.
- //! - In all other cases, the transformation is applied to a duplicate of S.
+ //! - In all other cases, the transformation is applied to a duplicate of theShape.
+ //! - If theCopyMesh is true, the triangulation will be copied,
+ //! and the copy will be assigned to the result shape.
//! Use the function Shape to access the result.
//! Note: this framework can be reused to apply the same
//! geometric transformation to other shapes. You only
//! need to specify them by calling the function Perform again.
- Standard_EXPORT void Perform (const TopoDS_Shape& S, const Standard_Boolean Copy = Standard_False);
+ Standard_EXPORT void Perform (const TopoDS_Shape& theShape,
+ const Standard_Boolean theCopyGeom = Standard_False,
+ const Standard_Boolean theCopyMesh = Standard_False);
//! Returns the modified shape corresponding to <S>.
Standard_EXPORT virtual TopoDS_Shape ModifiedShape (const TopoDS_Shape& S) const Standard_OVERRIDE;
Standard_Boolean isBasic = Standard_False;
Standard_Boolean isForced = Standard_False;
Standard_Boolean isCopy = Standard_False;
+ Standard_Boolean isCopyMesh = Standard_False;
+ // Check "copymesh" flag.
+ if (!strcmp(a[n - 1], "-copymesh"))
+ {
+ isCopyMesh = Standard_True;
+ last = --n;
+ }
// Check "copy" flag.
if (!strcmp(a[n-1], "-copy")) {
isCopy = Standard_True;
return 1;
}
else {
- trf.Perform(S, isCopy);
+ trf.Perform(S, isCopy, isCopyMesh);
if (!trf.IsDone())
return 1;
DBRep::Set(a[i],trf.Shape());
transform,g);
theCommands.Add("tmove",
- "tmove name1 name2 ... name, set location from name [-copy]",
+ "tmove name1 name2 ... name, set location from name [-copy] [-copymesh]",
__FILE__,
transform,g);
theCommands.Add("ttranslate",
- "ttranslate name1 name2 ... dx dy dz [-copy]",
+ "ttranslate name1 name2 ... dx dy dz [-copy [-copymesh]]",
__FILE__,
transform,g);
theCommands.Add("trotate",
- "trotate name1 name2 ... x y z dx dy dz angle [-copy]",
+ "trotate name1 name2 ... x y z dx dy dz angle [-copy [-copymesh]]",
__FILE__,
transform,g);
theCommands.Add("tmirror",
- "tmirror name x y z dx dy dz [-copy]",
+ "tmirror name x y z dx dy dz [-copy] [-copymesh]",
__FILE__,
transform,g);
theCommands.Add("tscale",
- "tscale name x y z scale [-copy]",
+ "tscale name x y z scale [-copy] [-copymesh]",
__FILE__,
transform,g);
#include <Geom_Surface.hxx>
#include <GeomAdaptor_Surface.hxx>
#include <GeomLib.hxx>
+#include <GeomLib_Tool.hxx>
#include <gp_GTrsf2d.hxx>
#include <gp_Pnt.hxx>
#include <gp_Trsf.hxx>
//purpose :
//=======================================================================
BRepTools_TrsfModification::BRepTools_TrsfModification(const gp_Trsf& T) :
-myTrsf(T)
+myTrsf(T),
+myCopyMesh(Standard_False)
{
}
return myTrsf;
}
+//=======================================================================
+//function : IsCopyMesh
+//purpose :
+//=======================================================================
+
+Standard_Boolean& BRepTools_TrsfModification::IsCopyMesh()
+{
+ return myCopyMesh;
+}
+
//=======================================================================
//function : NewSurface
//purpose :
Standard_Boolean& RevFace)
{
S = BRep_Tool::Surface(F,L);
+ if (S.IsNull())
+ {
+ //processing cases when there is no geometry
+ return Standard_False;
+ }
+
Tol = BRep_Tool::Tolerance(F);
Tol *= Abs(myTrsf.ScaleFactor());
RevWires = Standard_False;
return Standard_True;
}
+//=======================================================================
+//function : NewTriangulation
+//purpose :
+//=======================================================================
+
+Standard_Boolean BRepTools_TrsfModification::NewTriangulation
+(const TopoDS_Face& theFace,
+ Handle(Poly_Triangulation)& theTriangulation)
+{
+ if (!myCopyMesh)
+ {
+ return Standard_False;
+ }
+
+ TopLoc_Location aLoc;
+ theTriangulation = BRep_Tool::Triangulation(theFace, aLoc);
+
+ if (theTriangulation.IsNull())
+ {
+ return Standard_False;
+ }
+
+ gp_Trsf aTrsf = myTrsf;
+ if (!aLoc.IsIdentity())
+ {
+ aTrsf = aLoc.Transformation().Inverted() * aTrsf * aLoc.Transformation();
+ }
+
+ theTriangulation = theTriangulation->Copy();
+ theTriangulation->SetCachedMinMax(Bnd_Box()); // clear bounding box
+ theTriangulation->Deflection(theTriangulation->Deflection() * Abs(myTrsf.ScaleFactor()));
+ // apply transformation to 3D nodes
+ for (Standard_Integer anInd = 1; anInd <= theTriangulation->NbNodes(); ++anInd)
+ {
+ gp_Pnt aP = theTriangulation->Node(anInd);
+ aP.Transform(aTrsf);
+ theTriangulation->SetNode(anInd, aP);
+ }
+ // modify 2D nodes
+ Handle(Geom_Surface) aSurf = BRep_Tool::Surface(theFace, aLoc);
+ if (theTriangulation->HasUVNodes() && !aSurf.IsNull())
+ {
+ for (Standard_Integer anInd = 1; anInd <= theTriangulation->NbNodes(); ++anInd)
+ {
+ gp_Pnt2d aP2d = theTriangulation->UVNode(anInd);
+ aSurf->TransformParameters(aP2d.ChangeCoord().ChangeCoord(1),
+ aP2d.ChangeCoord().ChangeCoord(2),
+ myTrsf);
+ theTriangulation->SetUVNode(anInd, aP2d);
+ }
+ }
+ // modify triangles orientation in case of mirror transformation
+ if (myTrsf.ScaleFactor() < 0.0)
+ {
+ for (Standard_Integer anInd = 1; anInd <= theTriangulation->NbTriangles(); ++anInd)
+ {
+ Poly_Triangle aTria = theTriangulation->Triangle(anInd);
+ Standard_Integer aN1, aN2, aN3;
+ aTria.Get(aN1, aN2, aN3);
+ aTria.Set(aN1, aN3, aN2);
+ theTriangulation->SetTriangle(anInd, aTria);
+ }
+ }
+ // modify normals
+ if (theTriangulation->HasNormals())
+ {
+ for (Standard_Integer anInd = 1; anInd <= theTriangulation->NbTriangles(); ++anInd)
+ {
+ gp_Dir aNormal = theTriangulation->Normal(anInd);
+ aNormal.Transform(aTrsf);
+ theTriangulation->SetNormal(anInd, aNormal);
+ }
+ }
+
+ return Standard_True;
+}
+
+//=======================================================================
+//function : NewPolygon
+//purpose :
+//=======================================================================
+
+Standard_Boolean BRepTools_TrsfModification::NewPolygon
+(const TopoDS_Edge& theE,
+ Handle(Poly_Polygon3D)& theP)
+{
+ if (!myCopyMesh)
+ {
+ return Standard_False;
+ }
+
+ TopLoc_Location aLoc;
+ theP = BRep_Tool::Polygon3D(theE, aLoc);
+ if (theP.IsNull())
+ {
+ return Standard_False;
+ }
+
+ gp_Trsf aTrsf = myTrsf;
+ if (!aLoc.IsIdentity())
+ {
+ aTrsf = aLoc.Transformation().Inverted() * aTrsf * aLoc.Transformation();
+ }
+
+ theP = theP->Copy();
+ theP->Deflection(theP->Deflection() * Abs(myTrsf.ScaleFactor()));
+ TColgp_Array1OfPnt& aNodesArray = theP->ChangeNodes();
+ for (Standard_Integer anId = aNodesArray.Lower(); anId <= aNodesArray.Upper(); ++anId)
+ {
+ //Applying the transformation to each node of polygon
+ aNodesArray.ChangeValue(anId).Transform(aTrsf);
+ }
+ // transform the parametrization
+ if (theP->HasParameters())
+ {
+ TopLoc_Location aCurveLoc;
+ Standard_Real aFirst, aLast;
+ Handle(Geom_Curve) aCurve = BRep_Tool::Curve(theE, aCurveLoc, aFirst, aLast);
+ if (!aCurve.IsNull())
+ {
+ Standard_Real aReparametrization = aCurve->ParametricTransformation(aTrsf);
+ if (Abs(aReparametrization - 1.0) > Precision::PConfusion())
+ {
+ TColStd_Array1OfReal& aParams = theP->ChangeParameters();
+ for (Standard_Integer anInd = aParams.Lower(); anInd <= aParams.Upper(); ++anInd)
+ {
+ aParams(anInd) *= aReparametrization;
+ }
+ }
+ }
+ }
+ return Standard_True;
+}
+
+//=======================================================================
+//function : NewPolygonOnTriangulation
+//purpose :
+//=======================================================================
+
+Standard_Boolean BRepTools_TrsfModification::NewPolygonOnTriangulation
+(const TopoDS_Edge& theE,
+ const TopoDS_Face& theF,
+ Handle(Poly_PolygonOnTriangulation)& theP)
+{
+ if (!myCopyMesh)
+ {
+ return Standard_False;
+ }
+
+ TopLoc_Location aLoc;
+ Handle(Poly_Triangulation) aT = BRep_Tool::Triangulation(theF, aLoc);
+ if (aT.IsNull())
+ {
+ theP = Handle(Poly_PolygonOnTriangulation) ();
+ return Standard_False;
+ }
+
+ theP = BRep_Tool::PolygonOnTriangulation(theE, aT, aLoc);
+ if (theP.IsNull())
+ {
+ return Standard_False;
+ }
+ theP = theP->Copy();
+ theP->Deflection(theP->Deflection() * Abs(myTrsf.ScaleFactor()));
+
+ // transform the parametrization
+ Handle(Geom_Surface) aSurf = BRep_Tool::Surface(theF, aLoc);
+ Standard_Real aFirst, aLast;
+ Handle(Geom2d_Curve) aC2d = BRep_Tool::CurveOnSurface(theE, theF, aFirst, aLast);
+ if (!aSurf.IsNull() && !aC2d.IsNull() && Abs(Abs(myTrsf.ScaleFactor()) - 1.0) > TopLoc_Location::ScalePrec())
+ {
+ gp_GTrsf2d aGTrsf = aSurf->ParametricTransformation(myTrsf);
+ if (aGTrsf.Form() != gp_Identity)
+ {
+ Handle(Geom2d_Curve) aNewC2d = GeomLib::GTransform(aC2d, aGTrsf);
+ for (Standard_Integer anInd = 1; anInd <= theP->NbNodes(); ++anInd)
+ {
+ Standard_Real aParam = theP->Parameter(anInd);
+ gp_Pnt2d aP2d = aC2d->Value(aParam);
+ aGTrsf.Transforms(aP2d.ChangeCoord());
+ GeomLib_Tool::Parameter(aNewC2d, aP2d, theP->Deflection(), aParam);
+ theP->SetParameter(anInd, aParam);
+ }
+ }
+ }
+
+ return Standard_True;
+}
//=======================================================================
//function : NewCurve
{
Standard_Real f,l;
C = BRep_Tool::Curve(E,L,f,l);
+ if (C.IsNull())
+ {
+ return Standard_False;
+ }
Tol = BRep_Tool::Tolerance(E);
Tol *= Abs(myTrsf.ScaleFactor());
Standard_Real scale = myTrsf.ScaleFactor();
Tol *= Abs(scale);
const Handle(Geom_Surface)& S = BRep_Tool::Surface(F,loc);
+
+ if (S.IsNull())
+ {
+ // processing the case when the surface (geometry) is deleted
+ return Standard_False;
+ }
GeomAdaptor_Surface GAsurf(S);
if (GAsurf.GetType() == GeomAbs_Plane)
return Standard_False;
//! Provides access to the gp_Trsf associated with this
//! modification. The transformation can be changed.
Standard_EXPORT gp_Trsf& Trsf();
+
+ //! Sets a flag to indicate the need to copy mesh.
+ Standard_EXPORT Standard_Boolean& IsCopyMesh();
//! Returns true if the face F has been modified.
//! If the face has been modified:
//! associated with this modification is negative.
Standard_EXPORT Standard_Boolean NewSurface (const TopoDS_Face& F, Handle(Geom_Surface)& S, TopLoc_Location& L, Standard_Real& Tol, Standard_Boolean& RevWires, Standard_Boolean& RevFace) Standard_OVERRIDE;
+ //! Returns true if the face has been modified according to changed triangulation.
+ //! If the face has been modified:
+ //! - T is a new triangulation on the face
+ Standard_EXPORT Standard_Boolean NewTriangulation(const TopoDS_Face& F, Handle(Poly_Triangulation)& T) Standard_OVERRIDE;
+
+ //! Returns true if the edge has been modified according to changed polygon.
+ //! If the edge has been modified:
+ //! - P is a new polygon
+ Standard_EXPORT Standard_Boolean NewPolygon(const TopoDS_Edge& E, Handle(Poly_Polygon3D)& P) Standard_OVERRIDE;
+
+ //! Returns true if the edge has been modified according to changed polygon on triangulation.
+ //! If the edge has been modified:
+ //! - P is a new polygon on triangulation
+ Standard_EXPORT Standard_Boolean NewPolygonOnTriangulation(const TopoDS_Edge& E, const TopoDS_Face& F, Handle(Poly_PolygonOnTriangulation)& P) Standard_OVERRIDE;
+
//! Returns true if the edge E has been modified.
//! If the edge has been modified:
//! - C is the new geometric support of the edge,
gp_Trsf myTrsf;
+ Standard_Boolean myCopyMesh;
};
--- /dev/null
+puts "================================================================="
+puts "0032716: Modeling Algorithms - BRepBuilderAPI_Transform discards triangulation"
+puts "================================================================="
+puts ""
+
+psphere s1 10
+pcylinder s2 8 20
+pcone s3 10 8 5
+ttranslate s1 0 0 25
+ttranslate s3 0 0 -5
+
+baddobjects s1
+baddtools s2 s3
+bfillds
+bbop s fuse
+
+incmesh s 0.1
+
+# reference data
+regexp {([0-9+-.eE]*) faces.* ([0-9+-.eE]*) triangles.* ([0-9+-.eE]*) nodes} [trinfo s] full nbFaces nbTri nbNodes
+
+# scaling
+tscale s 0 0 0 2 -copymesh
+checkshape s
+checktrinfo s -face $nbFaces -nod $nbNodes -tri $nbTri
+if {[tricheck s] != ""} {
+ puts "ERROR: Wrong triangulation"
+}
+
+# mirror
+tmirror s 1 0 0 1 1 1 -copymesh
+checkshape s
+checktrinfo s -face $nbFaces -nod $nbNodes -tri $nbTri
+if {[tricheck s] != ""} {
+ puts "ERROR: Wrong triangulation"
+}
+
+# translate
+ttranslate s 0 0 10
+checkshape s
+checktrinfo s -face $nbFaces -nod $nbNodes -tri $nbTri
+if {[tricheck s] != ""} {
+ puts "ERROR: Wrong triangulation"
+}
+
+# rotate
+trotate s 0 0 0 0 0 1 45
+checkshape s
+checktrinfo s -face $nbFaces -nod $nbNodes -tri $nbTri
+if {[tricheck s] != ""} {
+ puts "ERROR: Wrong triangulation"
+}
+
+# display shape
+triangles s
+isos s 0
+checkview -display s -2d -path ${imagedir}/${test_image}.png
--- /dev/null
+puts "================================================================="
+puts "0032716: Modeling Algorithms - BRepBuilderAPI_Transform discards triangulation"
+puts "================================================================="
+puts ""
+
+psphere s1 10
+pcylinder s2 8 20
+pcone s3 10 8 5
+ttranslate s1 0 0 25
+ttranslate s3 0 0 -5
+
+baddobjects s1
+baddtools s2 s3
+bfillds
+bbop s fuse
+
+incmesh s 0.1
+
+# reference data
+regexp {([0-9+-.eE]*) faces.* ([0-9+-.eE]*) triangles.* ([0-9+-.eE]*) nodes} [trinfo s] full nbFaces nbTri nbNodes
+
+# scaling
+tscale s 0 0 0 2 -copy -copymesh
+checkshape s
+checktrinfo s -face $nbFaces -nod $nbNodes -tri $nbTri
+if {[tricheck s] != ""} {
+ puts "ERROR: Wrong triangulation"
+}
+
+# mirror
+tmirror s 1 0 0 1 1 1 -copy -copymesh
+checkshape s
+checktrinfo s -face $nbFaces -nod $nbNodes -tri $nbTri
+if {[tricheck s] != ""} {
+ puts "ERROR: Wrong triangulation"
+}
+
+# translate
+ttranslate s 0 0 10 -copy -copymesh
+checkshape s
+checktrinfo s -face $nbFaces -nod $nbNodes -tri $nbTri
+if {[tricheck s] != ""} {
+ puts "ERROR: Wrong triangulation"
+}
+
+# rotate
+trotate s 0 0 0 0 0 1 45 -copy -copymesh
+checkshape s
+checktrinfo s -face $nbFaces -nod $nbNodes -tri $nbTri
+if {[tricheck s] != ""} {
+ puts "ERROR: Wrong triangulation"
+}
+
+# display shape
+triangles s
+isos s 0
+checkview -display s -2d -path ${imagedir}/${test_image}.png
--- /dev/null
+puts "================================================================="
+puts "0032716: Modeling Algorithms - BRepBuilderAPI_Transform discards triangulation"
+puts "================================================================="
+puts ""
+
+psphere s1 10
+pcylinder s2 8 20
+pcone s3 10 8 5
+ttranslate s1 0 0 25
+ttranslate s3 0 0 -5
+
+baddobjects s1
+baddtools s2 s3
+bfillds
+bbop s fuse
+
+incmesh s 0.1
+tclean -geom s
+
+# reference data
+regexp {([0-9+-.eE]*) faces.* ([0-9+-.eE]*) triangles.* ([0-9+-.eE]*) nodes} [trinfo s] full nbFaces nbTri nbNodes
+
+# scaling
+tscale s 0 0 0 2 -copymesh
+checktrinfo s -face $nbFaces -nod $nbNodes -tri $nbTri
+if {[tricheck s] != ""} {
+ puts "ERROR: Wrong triangulation"
+}
+
+# mirror
+tmirror s 1 0 0 1 1 1 -copymesh
+checktrinfo s -face $nbFaces -nod $nbNodes -tri $nbTri
+if {[tricheck s] != ""} {
+ puts "ERROR: Wrong triangulation"
+}
+
+# translate
+ttranslate s 0 0 10
+checktrinfo s -face $nbFaces -nod $nbNodes -tri $nbTri
+if {[tricheck s] != ""} {
+ puts "ERROR: Wrong triangulation"
+}
+
+# rotate
+trotate s 0 0 0 0 0 1 45
+checktrinfo s -face $nbFaces -nod $nbNodes -tri $nbTri
+if {[tricheck s] != ""} {
+ puts "ERROR: Wrong triangulation"
+}
+
+# display shape
+triangles s
+isos s 0
+checkview -display s -2d -path ${imagedir}/${test_image}.png
--- /dev/null
+puts "================================================================="
+puts "0032716: Modeling Algorithms - BRepBuilderAPI_Transform discards triangulation"
+puts "================================================================="
+puts ""
+
+psphere s1 10
+pcylinder s2 8 20
+pcone s3 10 8 5
+ttranslate s1 0 0 25
+ttranslate s3 0 0 -5
+
+baddobjects s1
+baddtools s2 s3
+bfillds
+bbop s fuse
+
+incmesh s 0.1
+tclean -geom s
+
+# reference data
+regexp {([0-9+-.eE]*) faces.* ([0-9+-.eE]*) triangles.* ([0-9+-.eE]*) nodes} [trinfo s] full nbFaces nbTri nbNodes
+
+# scaling
+tscale s 0 0 0 2 -copy -copymesh
+checktrinfo s -face $nbFaces -nod $nbNodes -tri $nbTri
+if {[tricheck s] != ""} {
+ puts "ERROR: Wrong triangulation"
+}
+
+# mirror
+tmirror s 1 0 0 1 1 1 -copy -copymesh
+checktrinfo s -face $nbFaces -nod $nbNodes -tri $nbTri
+if {[tricheck s] != ""} {
+ puts "ERROR: Wrong triangulation"
+}
+
+# translate
+ttranslate s 0 0 10 -copy -copymesh
+checktrinfo s -face $nbFaces -nod $nbNodes -tri $nbTri
+if {[tricheck s] != ""} {
+ puts "ERROR: Wrong triangulation"
+}
+
+# rotate
+trotate s 0 0 0 0 0 1 45 -copy -copymesh
+checktrinfo s -face $nbFaces -nod $nbNodes -tri $nbTri
+if {[tricheck s] != ""} {
+ puts "ERROR: Wrong triangulation"
+}
+
+# display shape
+triangles s
+isos s 0
+checkview -display s -2d -path ${imagedir}/${test_image}.png