Apply non-uniform scale factors directly to the triangulation during Gltf import.
Add flag for turning on/off (on by default) this behavior.
OCP-1948
theResource->BooleanVal("read.print.debug.message",
InternalParameters.ReadPrintDebugMessages,
aScope);
+ InternalParameters.ReadApplyScale =
+ theResource->BooleanVal("read.apply.scale", InternalParameters.ReadApplyScale, aScope);
InternalParameters.WriteComment =
theResource->StringVal("write.comment", InternalParameters.WriteComment, aScope);
aScope + "read.print.debug.message :\t " + InternalParameters.ReadPrintDebugMessages + "\n";
aResult += "!\n";
+ aResult += "!\n";
+ aResult +=
+ "!Flag to apply non-uniform transformation directly to the triangulation (modify nodes)\n";
+ aResult += "!Default value: 1(true). Available values: 0(false), 1(true)\n";
+ aResult += aScope + "read.apply.scale :\t " + InternalParameters.ReadApplyScale + "\n";
+ aResult += "!\n";
+
aResult += "!\n";
aResult += "!Write parameters:\n";
aResult += "!\n";
bool ReadSkipLateDataLoading = false; //!< Flag to skip triangulation loading
bool ReadKeepLateData = true;//!< Flag to keep information about deferred storage to load/unload triangulation later
bool ReadPrintDebugMessages = false; //!< Flag to print additional debug information
+ bool ReadApplyScale = true; //!< Flag to apply non-uniform scale factor to the triangulations (modify nodes coordinates)
// Writing
TCollection_AsciiString WriteComment; //!< Export special comment
TCollection_AsciiString WriteAuthor; //!< Author of exported file name
theReader.SetToSkipLateDataLoading(theNode->InternalParameters.ReadSkipLateDataLoading);
theReader.SetToKeepLateData(theNode->InternalParameters.ReadKeepLateData);
theReader.SetToPrintDebugMessages(theNode->InternalParameters.ReadPrintDebugMessages);
+ theReader.SetToApplyScale(theNode->InternalParameters.ReadApplyScale);
}
} // namespace
#include <OSD_FileSystem.hxx>
#include <OSD_ThreadPool.hxx>
#include <RWGltf_GltfLatePrimitiveArray.hxx>
+#include <TDocStd_Document.hxx>
+#include <TopoDS.hxx>
+#include <XCAFDoc_DocumentTool.hxx>
+#include <XCAFDoc_ShapeMapTool.hxx>
+#include <XCAFDoc_ShapeTool.hxx>
IMPLEMENT_STANDARD_RTTIEXT(RWGltf_CafReader, RWMesh_CafReader)
myIsDoublePrecision(false),
myToSkipLateDataLoading(false),
myToKeepLateData(true),
- myToPrintDebugMessages(false)
+ myToPrintDebugMessages(false),
+ myToApplyScale(true)
{
myCoordSysConverter.SetInputLengthUnit(1.0); // glTF defines model in meters
myCoordSysConverter.SetInputCoordinateSystem(RWMesh_CoordinateSystem_glTF);
{
aDoc.SetBinaryFormat(aBinBodyOffset, aBinBodyLen);
}
+ myShapeScaleMap = new NCollection_DataMap<TopoDS_Shape, gp_XYZ, TopTools_ShapeMapHasher>();
+ aDoc.SetToApplyScale(myToApplyScale);
+ aDoc.SetScaleMap(*myShapeScaleMap);
#ifdef HAVE_RAPIDJSON
rapidjson::ParseResult aRes;
}
}
}
+
+//=================================================================================================
+
+void RWGltf_CafReader::fillDocument()
+{
+ if (!myToFillDoc || myXdeDoc.IsNull() || myRootShapes.IsEmpty())
+ {
+ return;
+ }
+ // set units
+ Standard_Real aLengthUnit = 1.;
+ if (!XCAFDoc_DocumentTool::GetLengthUnit(myXdeDoc, aLengthUnit))
+ {
+ XCAFDoc_DocumentTool::SetLengthUnit(myXdeDoc, SystemLengthUnit());
+ }
+ else if (aLengthUnit != SystemLengthUnit())
+ {
+ Message::SendWarning("Warning: Length unit of document not equal to the system length unit");
+ }
+
+ const Standard_Boolean wasAutoNaming = XCAFDoc_ShapeTool::AutoNaming();
+ XCAFDoc_ShapeTool::SetAutoNaming(Standard_False);
+ const TCollection_AsciiString aRootName; // = generateRootName (theFile);
+ CafDocumentTools aTools;
+ aTools.ShapeTool = XCAFDoc_DocumentTool::ShapeTool(myXdeDoc->Main());
+ aTools.ColorTool = XCAFDoc_DocumentTool::ColorTool(myXdeDoc->Main());
+ aTools.VisMaterialTool = XCAFDoc_DocumentTool::VisMaterialTool(myXdeDoc->Main());
+ for (TopTools_SequenceOfShape::Iterator aRootIter(myRootShapes); aRootIter.More();
+ aRootIter.Next())
+ {
+ addShapeIntoDoc(aTools, aRootIter.Value(), TDF_Label(), aRootName);
+ }
+ XCAFDoc_DocumentTool::ShapeTool(myXdeDoc->Main())->UpdateAssemblies();
+ XCAFDoc_ShapeTool::SetAutoNaming(wasAutoNaming);
+}
+
+//=================================================================================================
+
+Standard_Boolean RWGltf_CafReader::addShapeIntoDoc(CafDocumentTools& theTools,
+ const TopoDS_Shape& theShape,
+ const TDF_Label& theLabel,
+ const TCollection_AsciiString& theParentName,
+ const Standard_Boolean theHasScale,
+ const gp_XYZ& theScale)
+{
+ if (theShape.IsNull() || myXdeDoc.IsNull())
+ {
+ return Standard_False;
+ }
+
+ const TopAbs_ShapeEnum aShapeType = theShape.ShapeType();
+ TopoDS_Shape aShapeToAdd = theShape;
+ const TopoDS_Shape aShapeNoLoc = theShape.Located(TopLoc_Location());
+ Standard_Boolean toMakeAssembly = Standard_False;
+ bool isShapeScaled = myShapeScaleMap->IsBound(theShape);
+ gp_XYZ aCurScale;
+
+ if (theHasScale)
+ {
+ // update translation part
+ gp_Trsf aTrsf = theShape.Location().Transformation();
+ gp_XYZ aTranslation = aTrsf.TranslationPart();
+ aTranslation.SetX(aTranslation.X() * theScale.X());
+ aTranslation.SetY(aTranslation.Y() * theScale.Y());
+ aTranslation.SetZ(aTranslation.Z() * theScale.Z());
+ aTrsf.SetTranslationPart(aTranslation);
+ aShapeToAdd.Location(TopLoc_Location(aTrsf));
+ }
+
+ if (isShapeScaled && aShapeType == TopAbs_FACE)
+ {
+ // Scale triangulation
+ aCurScale = myShapeScaleMap->Find(theShape);
+ TopLoc_Location aLoc;
+ TopoDS_Face aFace = TopoDS::Face(aShapeToAdd);
+ myShapeScaleMap->UnBind(theShape);
+ const Handle(Poly_Triangulation)& aPolyTri = BRep_Tool::Triangulation(aFace, aLoc);
+ if (!aPolyTri.IsNull())
+ {
+ for (int aNodeIdx = 1; aNodeIdx <= aPolyTri->NbNodes(); ++aNodeIdx)
+ {
+ gp_Pnt aNode = aPolyTri->Node(aNodeIdx);
+ aNode.SetX(aNode.X() * aCurScale.X());
+ aNode.SetY(aNode.Y() * aCurScale.Y());
+ aNode.SetZ(aNode.Z() * aCurScale.Z());
+ aPolyTri->SetNode(aNodeIdx, aNode);
+ }
+ }
+ }
+
+ if (theShape.ShapeType() == TopAbs_COMPOUND)
+ {
+ RWMesh_NodeAttributes aSubFaceAttribs;
+ for (TopoDS_Iterator aSubShapeIter(theShape, Standard_True, Standard_False);
+ !toMakeAssembly && aSubShapeIter.More();
+ aSubShapeIter.Next())
+ {
+ if (aSubShapeIter.Value().ShapeType() != TopAbs_FACE)
+ {
+ toMakeAssembly = Standard_True;
+ break;
+ }
+
+ const TopoDS_Face& aFace = TopoDS::Face(aSubShapeIter.Value());
+ toMakeAssembly =
+ toMakeAssembly
+ || (myAttribMap.Find(aFace, aSubFaceAttribs) && !aSubFaceAttribs.Name.IsEmpty());
+ }
+
+ if (toMakeAssembly)
+ {
+ // create an empty Compound to add as assembly, so that we can add children one-by-one via
+ // AddComponent()
+ TopoDS_Compound aCompound;
+ BRep_Builder aBuilder;
+ aBuilder.MakeCompound(aCompound);
+ aCompound.Location(theShape.Location(), Standard_False);
+ aShapeToAdd = aCompound;
+ }
+ }
+
+ TDF_Label aNewLabel, anOldLabel;
+ if (theLabel.IsNull())
+ {
+ // add new shape
+ aNewLabel = theTools.ShapeTool->AddShape(aShapeToAdd, toMakeAssembly);
+ }
+ else if (theTools.ShapeTool->IsAssembly(theLabel))
+ {
+ // add shape as component
+ if (theTools.ComponentMap.Find(aShapeNoLoc, anOldLabel))
+ {
+ aNewLabel = theTools.ShapeTool->AddComponent(theLabel, anOldLabel, theShape.Location());
+ }
+ else
+ {
+ aNewLabel = theTools.ShapeTool->AddComponent(theLabel, aShapeToAdd, toMakeAssembly);
+
+ TDF_Label aRefLabel = aNewLabel;
+ theTools.ShapeTool->GetReferredShape(aNewLabel, aRefLabel);
+ if (!aRefLabel.IsNull())
+ {
+ theTools.ComponentMap.Bind(aShapeNoLoc, aRefLabel);
+ }
+ }
+ }
+ else
+ {
+ // add shape as sub-shape
+ aNewLabel = theTools.ShapeTool->AddSubShape(theLabel, theShape);
+ if (!aNewLabel.IsNull())
+ {
+ Handle(XCAFDoc_ShapeMapTool) aShapeMapTool = XCAFDoc_ShapeMapTool::Set(aNewLabel);
+ aShapeMapTool->SetShape(theShape);
+ }
+ }
+ if (aNewLabel.IsNull())
+ {
+ return Standard_False;
+ }
+
+ if (toMakeAssembly)
+ {
+ TDF_Label aRefLabel;
+ theTools.ShapeTool->GetReferredShape(aNewLabel, aRefLabel);
+ if (!aRefLabel.IsNull())
+ {
+ theTools.OriginalShapeMap.Bind(theShape, aRefLabel);
+ }
+ }
+
+ // if new label is a reference get referred shape
+ TDF_Label aNewRefLabel = aNewLabel;
+ theTools.ShapeTool->GetReferredShape(aNewLabel, aNewRefLabel);
+
+ RWMesh_NodeAttributes aRefShapeAttribs;
+ myAttribMap.Find(aShapeNoLoc, aRefShapeAttribs);
+
+ bool hasProductName = false;
+ if (aNewLabel != aNewRefLabel)
+ {
+ // put attributes to the Instance (overrides Product attributes)
+ RWMesh_NodeAttributes aShapeAttribs;
+ if (!theShape.Location().IsIdentity() && myAttribMap.Find(theShape, aShapeAttribs))
+ {
+ if (!aShapeAttribs.Style.IsEqual(aRefShapeAttribs.Style))
+ {
+ setShapeStyle(theTools, aNewLabel, aShapeAttribs.Style);
+ }
+ if (aShapeAttribs.NamedData != aRefShapeAttribs.NamedData)
+ {
+ setShapeNamedData(theTools, aNewLabel, aShapeAttribs.NamedData);
+ }
+ setShapeName(aNewLabel, aShapeType, aShapeAttribs.Name, theLabel, theParentName);
+ if (aRefShapeAttribs.Name.IsEmpty() && !aShapeAttribs.Name.IsEmpty())
+ {
+ // it is not nice having unnamed Product, so copy name from first Instance (probably the
+ // only one)
+ hasProductName = true;
+ setShapeName(aNewRefLabel, aShapeType, aShapeAttribs.Name, theLabel, theParentName);
+ }
+ else if (aShapeAttribs.Name.IsEmpty() && !aRefShapeAttribs.Name.IsEmpty())
+ {
+ // copy name from Product
+ setShapeName(aNewLabel, aShapeType, aRefShapeAttribs.Name, theLabel, theParentName);
+ }
+ }
+ else
+ {
+ // copy name from Product
+ setShapeName(aNewLabel, aShapeType, aRefShapeAttribs.Name, theLabel, theParentName);
+ }
+ }
+
+ if (!anOldLabel.IsNull())
+ {
+ // already defined in the document
+ return Standard_True;
+ }
+
+ // put attributes to the Product (shared across Instances)
+ if (!hasProductName)
+ {
+ setShapeName(aNewRefLabel, aShapeType, aRefShapeAttribs.Name, theLabel, theParentName);
+ }
+ setShapeStyle(theTools, aNewRefLabel, aRefShapeAttribs.Style);
+ setShapeNamedData(theTools, aNewRefLabel, aRefShapeAttribs.NamedData);
+
+ if (theTools.ShapeTool->IsAssembly(aNewRefLabel))
+ {
+ bool aHasScale = theHasScale | isShapeScaled;
+ gp_XYZ aScale = theScale;
+ if (isShapeScaled)
+ {
+ aScale.SetX(aCurScale.X() * theScale.X());
+ aScale.SetY(aCurScale.Y() * theScale.Y());
+ aScale.SetZ(aCurScale.Z() * theScale.Z());
+ }
+ // store sub-shapes (iterator is set to not inherit Location of parent object)
+ TCollection_AsciiString aDummyName;
+ for (TopoDS_Iterator aSubShapeIter(theShape, Standard_True, Standard_False);
+ aSubShapeIter.More();
+ aSubShapeIter.Next())
+ {
+ addShapeIntoDoc(theTools, aSubShapeIter.Value(), aNewRefLabel, aDummyName, aHasScale, aScale);
+ }
+ }
+ else
+ {
+ // store a plain list of sub-shapes in case if they have custom attributes (usually per-face
+ // color)
+ for (TopoDS_Iterator aSubShapeIter(theShape, Standard_True, Standard_False);
+ aSubShapeIter.More();
+ aSubShapeIter.Next())
+ {
+ addSubShapeIntoDoc(theTools, aSubShapeIter.Value(), aNewRefLabel);
+ }
+ }
+ return Standard_True;
+}
//! main (default) scene will be loaded.
bool ToLoadAllScenes() const { return myToLoadAllScenes; }
+ //! Return TRUE if non-uniform scaling should be applied directly to the triangulation.
+ //! FALSE if the average scale should be applied to the transformation matrix.
+ bool ToApplyScale() const { return myToApplyScale; }
+
//! Set flag to flag to load all scenes in the document, FALSE by default which means only main
//! (default) scene will be loaded.
void SetLoadAllScenes(bool theToLoadAll) { myToLoadAllScenes = theToLoadAll; }
//! Sets flag to skip data loading.
void SetToSkipLateDataLoading(bool theToSkip) { myToSkipLateDataLoading = theToSkip; }
+ //! Set flag to apply non-uniform scaling directly to the triangulation (modify nodes).
+ //! TRUE by default. In case of FALSE the average scale is applied to the transformation matrix.
+ void SetToApplyScale(bool theToApplyScale) { myToApplyScale = theToApplyScale; }
+
//! Returns TRUE if data should be loaded into itself without its transferring to new structure.
//! It allows to keep information about deferred storage to load/unload this data later.
//! TRUE by default.
const Standard_Boolean theToProbe)
Standard_OVERRIDE;
+ //! Fill document with new root shapes.
+ Standard_EXPORT virtual void fillDocument() Standard_OVERRIDE;
+
+ //! Append new shape into the document (recursively).
+ Standard_EXPORT Standard_Boolean addShapeIntoDoc(CafDocumentTools& theTools,
+ const TopoDS_Shape& theShape,
+ const TDF_Label& theLabel,
+ const TCollection_AsciiString& theParentName,
+ const Standard_Boolean theHasScale = false,
+ const gp_XYZ& theScale = gp_XYZ(0., 0., 0.));
+
//! Create primitive array reader context.
//! Can be overridden by sub-class to read triangulation into application-specific data structures
//! instead of Poly_Triangulation. Default implementation creates RWGltf_TriangulationReader.
Standard_Boolean myToKeepLateData; //!< flag to keep information about deferred storage to load/unload triangulation later
// clang-format on
Standard_Boolean myToPrintDebugMessages; //!< flag to print additional debug information
+ Standard_Boolean myToApplyScale; //!< flag to apply non-uniform scaling
+ NCollection_DataMap<TopoDS_Shape, gp_XYZ, TopTools_ShapeMapHasher>*
+ myShapeScaleMap; //!< map of shapes with non-uniform scalings
};
#endif // _RWGltf_CafReader_HeaderFile
#include "RWGltf_GltfJsonParser.hxx"
#include <BRep_Builder.hxx>
+#include <BRepBuilderAPI_Copy.hxx>
#include <FSD_Base64.hxx>
#include <Message.hxx>
#include <Message_Messenger.hxx>
const RWGltf_JsonValue* theRotationVal,
const RWGltf_JsonValue* theScaleVal,
const RWGltf_JsonValue* theTranslationVal,
- TopLoc_Location& theResult) const
+ TopLoc_Location& theResult,
+ bool& theHasScale,
+ gp_XYZ& theScale) const
{
+ theHasScale = false;
gp_Trsf aTrsf;
if (theRotationVal != NULL)
{
|| Abs(aScaleVec.y() - aScaleVec.z()) > Precision::Confusion()
|| Abs(aScaleVec.x() - aScaleVec.z()) > Precision::Confusion())
{
- Graphic3d_Mat4d aScaleMat;
- aScaleMat.SetDiagonal(aScaleVec);
-
Graphic3d_Mat4d aMat4;
aTrsf.GetMat4(aMat4);
- aMat4 = aMat4 * aScaleMat;
+ if (!myToApplyScale)
+ {
+ Graphic3d_Mat4d aScaleMat;
+ aScaleMat.SetDiagonal(aScaleVec);
+ aMat4 = aMat4 * aScaleMat;
+ }
+
aTrsf = gp_Trsf();
aTrsf.SetValues(aMat4.GetValue(0, 0),
aMat4.GetValue(0, 1),
aMat4.GetValue(2, 2),
aMat4.GetValue(2, 3));
- Message::SendWarning(TCollection_AsciiString("glTF reader, scene node '") + theSceneNodeId
- + "' defines unsupported scaling " + aScaleVec.x() + " " + aScaleVec.y()
- + " " + aScaleVec.z());
+ TCollection_AsciiString aWarnMessage = TCollection_AsciiString("glTF reader, scene node '")
+ + theSceneNodeId + "' defines unsupported scaling "
+ + aScaleVec.x() + " " + aScaleVec.y() + " "
+ + aScaleVec.z();
+ if (myToApplyScale)
+ {
+ aWarnMessage += TCollection_AsciiString(". It was applied to the triangulation directly");
+ theHasScale = true;
+ theScale = gp_XYZ(aScaleVec.x(), aScaleVec.y(), aScaleVec.z());
+ }
+
+ Message::SendWarning(aWarnMessage);
}
else if (Abs(aScaleVec.x() - 1.0) > Precision::Confusion())
{
: myRootShapes(&theRootShapes),
myAttribMap(NULL),
myExternalFiles(NULL),
+ myShapeScaleMap(NULL),
myMetadata(NULL),
myBinBodyOffset(0),
myBinBodyLen(0),
myToLoadAllScenes(false),
myUseMeshNameAsFallback(true),
myToProbeHeader(false),
- myToReadAssetExtras(true)
+ myToReadAssetExtras(true),
+ myToApplyScale(true)
{
myCSTrsf.SetInputLengthUnit(1.0); // meters
myCSTrsf.SetInputCoordinateSystem(RWMesh_CoordinateSystem_glTF);
const RWGltf_JsonValue* anExtrasVal = findObjectMember(theSceneNode, "extras");
TopLoc_Location aNodeLoc;
+ bool aHasScale = false;
+ gp_XYZ aScale;
const bool aHasTransformComponents =
aTrsfRotVal != NULL || aTrsfScaleVal != NULL || aTrsfTransVal != NULL;
const bool aHasTransformMatrix = aTrsfMatVal != NULL;
aTrsfRotVal,
aTrsfScaleVal,
aTrsfTransVal,
- aNodeLoc))
+ aNodeLoc,
+ aHasScale,
+ aScale))
{
return false;
}
if (aChildren != NULL && !gltfParseSceneNodes(aChildShapes, *aChildren, theProgress))
{
theNodeShape = aNodeShape;
- bindNodeShape(theNodeShape, aNodeLoc, theSceneNodeId, aName, anExtras);
+ bindNodeShape(theNodeShape, aNodeLoc, aHasScale, aScale, theSceneNodeId, aName, anExtras);
return false;
}
for (TopTools_SequenceOfShape::Iterator aChildShapeIter(aChildShapes); aChildShapeIter.More();
if (aMesh == NULL)
{
theNodeShape = aNodeShape;
- bindNodeShape(theNodeShape, aNodeLoc, theSceneNodeId, aName, anExtras);
+ bindNodeShape(theNodeShape, aNodeLoc, aHasScale, aScale, theSceneNodeId, aName, anExtras);
reportGltfError("Scene node '" + theSceneNodeId + "' refers to non-existing mesh.");
return false;
}
if (!gltfParseMesh(aMeshShape, getKeyString(*aMeshIter), *aMesh))
{
theNodeShape = aNodeShape;
- bindNodeShape(theNodeShape, aNodeLoc, theSceneNodeId, aName, anExtras);
+ bindNodeShape(theNodeShape, aNodeLoc, aHasScale, aScale, theSceneNodeId, aName, anExtras);
return false;
}
if (!aMeshShape.IsNull())
if (aMesh == NULL)
{
theNodeShape = aNodeShape;
- bindNodeShape(theNodeShape, aNodeLoc, theSceneNodeId, aName, anExtras);
+ bindNodeShape(theNodeShape, aNodeLoc, aHasScale, aScale, theSceneNodeId, aName, anExtras);
reportGltfError("Scene node '" + theSceneNodeId + "' refers to non-existing mesh.");
return false;
}
if (!gltfParseMesh(aMeshShape, getKeyString(*aMesh_2), *aMesh))
{
theNodeShape = aNodeShape;
- bindNodeShape(theNodeShape, aNodeLoc, theSceneNodeId, aName, anExtras);
+ bindNodeShape(theNodeShape, aNodeLoc, aHasScale, aScale, theSceneNodeId, aName, anExtras);
return false;
}
if (!aMeshShape.IsNull())
{
aBuilder.Add(aNodeShape, aMeshShape);
++aNbSubShapes;
+ if (aHasScale)
+ myShapeScaleMap->Bind(aMeshShape, aScale);
}
}
{
theNodeShape = aNodeShape;
}
- bindNodeShape(theNodeShape, aNodeLoc, theSceneNodeId, aName, anExtras);
+ bindNodeShape(theNodeShape, aNodeLoc, aHasScale, aScale, theSceneNodeId, aName, anExtras);
return true;
}
}
//=================================================================================================
-
void RWGltf_GltfJsonParser::bindNamedShape(TopoDS_Shape& theShape,
ShapeMapGroup theGroup,
const TopLoc_Location& theLoc,
+ const bool theHasScale,
+ const gp_XYZ& theScale,
const TCollection_AsciiString& theId,
const RWGltf_JsonValue* theUserName,
const Handle(TDataStd_NamedData)& theExtras)
return;
}
+ if (theHasScale && myShapeScaleMap->IsBound(theShape))
+ {
+ // Check scaling values
+ gp_XYZ aScale = myShapeScaleMap->Find(theShape);
+ if ((aScale - theScale).Modulus() > Precision::Confusion())
+ {
+ // Create a shape copy to avoid problems with different scaling
+ BRepBuilderAPI_Copy aCopy;
+ aCopy.Perform(theShape, Standard_True, Standard_True);
+ theShape = aCopy.Shape();
+ }
+ }
+
TopoDS_Shape aShape = theShape;
if (!theLoc.IsIdentity())
{
}
myAttribMap->Bind(theShape, aShapeAttribs);
}
+
+ if (theHasScale)
+ {
+ myShapeScaleMap->Bind(theShape, theScale);
+ }
myShapeMap[theGroup].Bind(theId, theShape);
}
//! Set map for storing node attributes.
void SetAttributeMap(RWMesh_NodeAttributeMap& theAttribMap) { myAttribMap = &theAttribMap; }
+ //! Set map for storing non-uniform scalings.
+ void SetScaleMap(NCollection_DataMap<TopoDS_Shape, gp_XYZ, TopTools_ShapeMapHasher>& theScaleMap)
+ {
+ myShapeScaleMap = &theScaleMap;
+ }
+
//! Set list for storing external files.
void SetExternalFiles(NCollection_IndexedMap<TCollection_AsciiString>& theExternalFiles)
{
//! Set flag to use Mesh name in case if Node name is empty, TRUE by default.
void SetMeshNameAsFallback(bool theToFallback) { myUseMeshNameAsFallback = theToFallback; }
+ //! Set flag to apply non-uniform scaling directly to the triangulation (modify nodes).
+ //! TRUE by default. In case of FALSE the average scale is applied to the transformation matrix.
+ void SetToApplyScale(bool theToApplyScale) { myToApplyScale = theToApplyScale; }
+
//! Parse glTF document.
Standard_EXPORT bool Parse(const Message_ProgressRange& theProgress);
//! Bind name attribute.
void bindNodeShape(TopoDS_Shape& theShape,
const TopLoc_Location& theLoc,
+ const bool theHasScale,
+ const gp_XYZ& theScale,
const TCollection_AsciiString& theNodeId,
const RWGltf_JsonValue* theUserName,
const Handle(TDataStd_NamedData)& theExtras)
{
- bindNamedShape(theShape, ShapeMapGroup_Nodes, theLoc, theNodeId, theUserName, theExtras);
+ bindNamedShape(theShape,
+ ShapeMapGroup_Nodes,
+ theLoc,
+ theHasScale,
+ theScale,
+ theNodeId,
+ theUserName,
+ theExtras);
}
//! Bind name attribute.
bindNamedShape(theShape,
ShapeMapGroup_Meshes,
TopLoc_Location(),
+ false,
+ gp_XYZ(),
theMeshId,
theUserName,
theExtras);
Standard_EXPORT void bindNamedShape(TopoDS_Shape& theShape,
ShapeMapGroup theGroup,
const TopLoc_Location& theLoc,
+ const bool theHasScale,
+ const gp_XYZ& theScale,
const TCollection_AsciiString& theId,
const RWGltf_JsonValue* theUserName,
const Handle(TDataStd_NamedData)& theExtras);
//! @param theTranslationVal Json value containing translation component of transformation.
//! May be null in which case it is ignored.
//! @param theResult TopLoc_Location object where result of parsing will be written.
+ //! @param theHasScale The flag indicates if scale component was found in the transformation.
+ //! @param theScale Found scale vector. Only valid if @p theHasScale is true.
+ //! Otherwise, it is undefined.
//! @param If true - parsing was successful, transformation is written into @p theResult.
//! If true - failed to parse, @p theResult is unchanged.
bool parseTransformationComponents(const TCollection_AsciiString& theSceneNodeId,
const RWGltf_JsonValue* theRotationVal,
const RWGltf_JsonValue* theScaleVal,
const RWGltf_JsonValue* theTranslationVal,
- TopLoc_Location& theResult) const;
+ TopLoc_Location& theResult,
+ bool& theHasScale,
+ gp_XYZ& theScale) const;
//! Fill lines and points data not deferred.
//! @param theMeshData source glTF triangulation
TopTools_SequenceOfShape* myRootShapes; //!< sequence of result root shapes
RWMesh_NodeAttributeMap* myAttribMap; //!< shape attributes
NCollection_IndexedMap<TCollection_AsciiString>*
- myExternalFiles; //!< list of external file references
+ myExternalFiles; //!< list of external file references
+ NCollection_DataMap<TopoDS_Shape, gp_XYZ, TopTools_ShapeMapHasher>*
+ myShapeScaleMap; //!< map of shapes with non-uniform scalings
// clang-format off
RWMesh_CoordinateSystemConverter myCSTrsf; //!< transformation from glTF to OCCT coordinate system
// clang-format on
bool myUseMeshNameAsFallback; //!< flag to use Mesh name in case if Node name is empty, TRUE by default
bool myToProbeHeader; //!< flag to probe header without full reading, FALSE by default
bool myToReadAssetExtras; //!< flag to translate asset.extras into metadata, TRUE by default
+ bool myToApplyScale; //!< flag to apply non-uniform scaling
// clang-format on
#ifdef HAVE_RAPIDJSON
Standard_Boolean toPrintDebugInfo = Standard_False;
Standard_Boolean toLoadAllScenes = Standard_False;
Standard_Boolean toPrintAssetInfo = Standard_False;
+ Standard_Boolean toApplyScale = Standard_True;
Standard_Boolean isNoDoc = (TCollection_AsciiString(theArgVec[0]) == "readgltf");
for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
{
{
toPrintAssetInfo = Draw::ParseOnOffIterator(theNbArgs, theArgVec, anArgIter);
}
+ else if (anArgCase == "-applyscale")
+ {
+ toApplyScale = Draw::ParseOnOffIterator(theNbArgs, theArgVec, anArgIter);
+ }
else if (aDestName.IsEmpty())
{
aDestName = theArgVec[anArgIter];
aReader.SetToKeepLateData(toKeepLateData);
aReader.SetToPrintDebugMessages(toPrintDebugInfo);
aReader.SetLoadAllScenes(toLoadAllScenes);
+ aReader.SetToApplyScale(toApplyScale);
if (aDestName.IsEmpty())
{
aReader.ProbeHeader(aFilePath);
"\n\t\t: -allScenes load all scenes defined in the document instead of default one "
"(false by default)"
"\n\t\t: -toPrintDebugInfo print additional debug information during data reading"
- "\n\t\t: -assetInfo print asset information",
+ "\n\t\t: -assetInfo print asset information"
+ "\n\t\t: -applyScale apply non-uniform scaling directly to the triangulation (modify "
+ "\n\t\t: nodes) (true by default). In case of false the average scale is "
+ "\n\t\t: applied to the transformation matrix.",
__FILE__,
ReadGltf,
aGroup);
--- /dev/null
+puts "========"
+puts "OCP-1948: Implement non-uniform scaling in Gltf Import"
+puts "========"
+Close D -silent
+ReadGltf D [locate_data_file bug_ocp1948_PSU_Cartoning_subunit__right-01.01.01.03-CART-03_green_bottom.glb]
+
+XGetOneShape s D
+checknbshapes s -face 87 -compound 21
+checktrinfo s -tri 16473 -nod 15835
+
+# check center of gravity
+set REF_X 18300.5
+set REF_Y -9484
+set REF_Z 129.844
+set tol 1e-4
+set pos [vprops s]
+if {([expr abs($REF_X - [lindex $pos 9])] > $tol) ||
+ ([expr abs($REF_Y - [lindex $pos 12])] > $tol) ||
+ ([expr abs($REF_Z - [lindex $pos 15])] > $tol)} {
+ puts "Error: wrong position of the imported model."
+ }
provider.GLTF.OCC.read.skip.late.data.loading : 0
provider.GLTF.OCC.read.keep.late.data : 1
provider.GLTF.OCC.read.print.debug.message : 0
+provider.GLTF.OCC.read.apply.scale : 1
provider.GLTF.OCC.write.comment :
provider.GLTF.OCC.write.author :
provider.GLTF.OCC.write.trsf.format : 0