Revit API Forum
Welcome to Autodesk’s Revit API Forums. Share your knowledge, ask questions, and explore popular Revit API topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Getting inaccurate UVs from geometry API

2 REPLIES 2
Reply
Message 1 of 3
Anonymous
662 Views, 2 Replies

Getting inaccurate UVs from geometry API

Hello,

My company is currently using the geometry API in addition to the custom exporter to obtain the UVs from Revit. We initially used the method of the geometry API to grab UVs but were having trouble with the UVs being inaccurate
therefore we added the custom exporter to export the UV information from Revit. Once we did this our sync time was slow. We prefer to use the geometry API instead of the custom exporter because the custom exporter is too slow. Has there been any updates to the geometry API that would allow us to get the UVs directly and not have to go through the custom exporter?

Tags (2)
2 REPLIES 2
Message 2 of 3
jeremytammik
in reply to: Anonymous

Please provide a minimal reproducible case showing how you retrieve the UV coordinates in the two situations you describe that we can pass on to the development team for analysis:

 

https://thebuildingcoder.typepad.com/blog/about-the-author.html#1b

 

Thank you!

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 3 of 3
Anonymous
in reply to: jeremytammik

Hello,

I have added the code below where the UVs that we attempt to get are incorrect so we calculate our own under code 1.

I have also added the code we used with the custom exporter that was slow under code 2.

 

Code 1:

Vector4fv vEdge01 = triangle0 - triangle1;
Vector4fv vEdge12 = triangle1 - triangle2;
f32 fAngleEdge01_12 = Vector4fv::GetAngleOf2Vectors ( vEdge01, vEdge12, false );
f32 fTriArea = vEdge01.GetLength() * vEdge12.GetLength() * (f32)Math::Sin ( fAngleEdge01_12 ) * 0.5f;

//Debug: rint ( "ManagerId: {0}, Originial Triangle0 : X = {1}, Y = {2}, Z = {3}", m_dwManagerId, triangle0.X, triangle0.Y, triangle0.Z );
//Debug: rint ( "ManagerId: {0}, Originial Triangle1 : X = {1}, Y = {2}, Z = {3}", m_dwManagerId, triangle1.X, triangle1.Y, triangle1.Z );
//Debug: rint ( "ManagerId: {0}, Originial Triangle2 : X = {1}, Y = {2}, Z = {3}", m_dwManagerId, triangle2.X, triangle2.Y, triangle2.Z );

if ( face.facetype == FaceInfo::FaceType::Cylindrical || face.facetype == FaceInfo::FaceType::Revolved )
{
array<f32> ^angleList = gcnew array<f32>( 3 );
array<f32> ^zproj = gcnew array<f32>( 3 );
array<bool> ^bAddTwoPi = gcnew array<bool>( 3 );
array<Vector4fv > ^RsProj = gcnew array<Vector4fv >( 3 );

Vector4fv origin = face.Origin;
Vector4fv axis = face.Axis.GetNormal();
Vector4fv radiusX = face.RadiusX;
Vector4fv radiusY = face.RadiusY;

bool bNeedFlipNormal = true;
if ( abs( axis.Z ) > abs( axis.X ) && abs( axis.Z ) > abs( axis.Y ) )
{
bNeedFlipNormal = false;
}

for ( int triIdx = 0; triIdx < 3; triIdx++ )
{
Vector4fv vCurVert = ( triIdx == 0 ) ? triangle0 : ( triIdx == 1 ? triangle1 : triangle2 );
Vector4fv vToOrigin = vCurVert - origin;
f32 angle = Vector4fv::GetAngleOf2Vectors( vToOrigin, axis, false );
angle = (f32)( ( Math: I ) / 2 ) - angle;

f32 fToOriginLen= vToOrigin.GetLength();
zproj[triIdx] = fToOriginLen * (f32)( Math::Sin( angle ) );
f32 Rs = fToOriginLen * (f32)( Math::Cos( angle ) );
RsProj[triIdx] = vToOrigin - axis * zproj[triIdx];

f32 acute_theta = Vector4fv::GetAngleOf2Vectors( RsProj[triIdx], radiusX, false );

f32 angleVRy = Vector4fv::GetAngleOf2Vectors( RsProj[triIdx], radiusY, false );
if ( angleVRy - (f32)( Math: I ) / 2 > float::Epsilon )
{
acute_theta = (f32)( Math: I * 2 ) - acute_theta;
}
angleList[triIdx] = acute_theta;
}

for ( int triIdx = 0; triIdx < 3; triIdx++ )
{
bool bAngleGreaterThanTwoPi = false;
if ( angleList[triIdx] < (f32)( Math: I ) / 6 )
{
if ( ( angleList[( triIdx + 1 ) % 3] > (f32)( Math: I ) * 1.8333f ) || ( angleList[( triIdx + 2 ) % 3] > ( f32 )( Math: I) * 1.8333f ) )
{
bAngleGreaterThanTwoPi = true;
}
}
bAddTwoPi[triIdx] = bAngleGreaterThanTwoPi;
}

for ( int triIdx = 0; triIdx < 3; triIdx++ )
{
if ( bAddTwoPi[triIdx] )
{
angleList[triIdx] += (f32)( Math: I ) * 2.0f;
}
}

for ( int triIdx = 0; triIdx < 3; triIdx++ )
{
Vector4fv vCurVert = ( triIdx == 0 ) ? triangle0 : ( triIdx == 1 ? triangle1 : triangle2 );
vCurVert.W = 1.f;

BaseCRC vertCRC( (u8 *)&vCurVert, sizeof ( Vector ) );
#if 0
if ( i == 0 && triIdx == 0 ) // first vertex, check normal direction pointing inwards or outwards
{
if ( Vector4fv::GetAngleOf2Vectors ( RsProj[triIdx], planeNorm, false ) > Math: I / 2 )
{
normalDir = -1;
}
else
{
normalDir = 1;
}
}
#endif
Vector4fv vFinalNormal = -( triangle1 - triangle2 ) & ( triangle0 - triangle1 );
vFinalNormal.W = fTriArea;

Vector4fv anchorProj;
if ( !bHaveAnchorPt )
{
anchorPt = vCurVert;
anchorProj = anchorPt;
bHaveAnchorPt = true;
}
else
{
Vector4fv planePt = vCurVert;

Vector4fv anchorToPt = anchorPt - planePt;
f32 fDot = anchorToPt * vFinalNormal;
Vector4fv scaledNorm = vFinalNormal * fDot;
anchorProj = anchorPt - scaledNorm;
}

f32 fu = angleList[triIdx] * RsProj[triIdx].GetLength();
f32 fv = ( ( vCurVert - anchorProj ) * axis );

if ( bHaveTexCoords )
{
switch ( triIdx )
{
case 0:
fu = uv0.U;
fv = uv0.V;
break;
case 1:
fu = uv1.U;
fv = uv1.V;
break;
case 2:
fu = uv2.U;
fv = uv2.V;
break;
}
}

if ( bAddTwoPi[triIdx] )
{
// force update
if ( bNeedFlipNormal )
{
AddVertex ( vCurVert, vFinalNormal, fv, fu );
}
else
{
AddVertex ( vCurVert, vFinalNormal, fu, fv );
}
}
else
{
const s32 dwSmoothRes = bNeedFlipNormal ? SmoothNormal ( vertsNormalIndexMapForCylin, vertCRC.GetCRC(), vFinalNormal, fv, fu )
: SmoothNormal ( vertsNormalIndexMapForCylin, vertCRC.GetCRC(), vFinalNormal, fu, fv );
if ( dwSmoothRes == 0 )
{
continue;
}
else if ( dwSmoothRes == 1 )
{
if ( bNeedFlipNormal )
{
AddVertex ( vCurVert,m_SmoothedNormal, fv, fu );
}
else
{
AddVertex ( vCurVert, m_SmoothedNormal, fu, fv );
}
}
else
{
if ( bNeedFlipNormal )
{
AddVertex ( vCurVert, vFinalNormal, fv, fu );
}
else
{
AddVertex ( vCurVert, vFinalNormal, fu, fv );
}
}
}
}
}
else
{
// apply a basic planar projection
//

Vector4fv planeNorm = -( triangle1 - triangle2 ) & ( triangle0 - triangle1 );
planeNorm.W = fTriArea;

Vector4fv anchorProj;

if ( !bHaveAnchorPt )
{
anchorPt = triangle0;
anchorProj = anchorPt;
bHaveAnchorPt = true;
}
else
{
Vector4fv planePt = triangle0;

Vector4fv anchorToPt = anchorPt - planePt;
f32 fDot= anchorToPt * planeNorm;
Vector4fv scaledNorm = planeNorm * fDot;
anchorProj = anchorPt - scaledNorm;
}

for ( int triIdx = 0; triIdx < 3; triIdx++ )
{
Vector4fv curTriangle = ( triIdx == 0 ) ? triangle0 : ( triIdx == 1 ? triangle1 : triangle2 );

Vector vVertRuled;
Vector_Set ( &vVertRuled, curTriangle.X, curTriangle.Y, curTriangle.Z, 1.0 );

BaseCRC vertRuledCRC( (u8 *)&vVertRuled, sizeof ( Vector ) );

f32 u, v;


if ( ( Math::Abs( planeNorm.X ) - Math::Abs ( planeNorm.Y ) ) > -0.001f
&& ( Math::Abs( planeNorm.X ) - Math::Abs ( planeNorm.Z ) ) > -0.001f )//project to YZ plane
{
Vector4fv vDir = planeNorm & yAxis;
Vector4fv uDir = planeNorm & vDir;

Vector4fv vProjAnchorToPt = curTriangle - anchorProj;

u = vProjAnchorToPt * uDir;
v = vProjAnchorToPt * vDir;
}
else if ( ( Math::Abs( planeNorm.Y ) - Math::Abs ( planeNorm.X ) ) > -0.001f
&& ( Math::Abs( planeNorm.Y ) - Math::Abs ( planeNorm.Z ) ) > -0.001f )//project to XZ plane
{
Vector4fv vDir = planeNorm & xAxis;
Vector4fv uDir = planeNorm & vDir;

Vector4fv vProjAnchorToPt = curTriangle - anchorProj;

u = vProjAnchorToPt * uDir;
v = vProjAnchorToPt * vDir;
}
else //project to XY plane
{
Vector4fv vDir = planeNorm & xAxis;
Vector4fv uDir = planeNorm & vDir;

Vector4fv vProjAnchorToPt = curTriangle - anchorProj;

u = vProjAnchorToPt * uDir;
v = vProjAnchorToPt * vDir;
}

if ( bHaveTexCoords )
{
switch ( triIdx )
{
case 0:
u = uv0.U;
v = uv0.V;
break;
case 1:
u = uv1.U;
v = uv1.V;
break;
case 2:
u = uv2.U;
v = uv2.V;
break;
}
}

bool bHaveReplacedNormal = false;
Vector4fv vReplacedNormal;
s32 dwSmoothRes = SmoothNormal ( vertsNormalIndexMapForPlannar, vertRuledCRC.GetCRC(), planeNorm, u, v );
if ( dwSmoothRes == 0 )
{
continue;
}
else if ( dwSmoothRes == 1 )
{
vReplacedNormal = m_SmoothedNormal;
bHaveReplacedNormal = true;
}

if ( bHaveReplacedNormal )
{
AddVertex ( curTriangle, vReplacedNormal, u, v );
}
else
{
AddVertex ( curTriangle, planeNorm, u, v );
}
}
}

 

Code 2:

void FuzorExportContext::OnPolymesh( PolymeshTopology ^node )
{
ExportElementInfo ^curElementInfo = m_CurDocumentInfo->GetCurrentElementInfo();
if ( curElementInfo == nullptr )
{
return;
}

if ( curElementInfo->m_bSkipElement )
{
return;
}

if ( m_exportOptions->m_bIncludeMeshes && !curElementInfo->m_bSkipGeometry )
{
ExportedMeshInfo ^pCurMesh = gcnew ExportedMeshInfo();

System::Collections::Generic::IList<Autodesk::Revit::DB: olymeshFacet^> ^pFacets = node->GetFacets();
const int dwNumFacets = pFacets->Count;
const int dwNumIndices = dwNumFacets * 3;
List<int> ^pIndices = gcnew List<int>( dwNumIndices );
for ( int i = 0; i < dwNumFacets; i++ )
{
PolymeshFacet ^pFacet = pFacets[i];
pIndices->Add ( pFacet->V1 );
pIndices->Add ( pFacet->V2 );
pIndices->Add ( pFacet->V3 );
}

IList<XYZ^> ^pPoints = node->GetPoints();
IList<XYZ^> ^pNormals = node->GetNormals();
IList<UV^> ^pUVs = node->GetUVs();
DistributionOfNormals dist = node->DistributionOfNormals;

pCurMesh->m_Points = gcnew List<Vector4fv>( dwNumIndices );
pCurMesh->m_UVs = gcnew List<UVv>( dwNumIndices );

Matrix4x4v mTransform = Command::TransformToMatrix ( m_CurDocumentInfo->m_transforms->GetCurrentTransform() );

for ( int i = 0; i < dwNumIndices; i++ )
{
Vector4fv vPoint ( pPoints[pIndices[i]], 1.f );
Vector4fv vTransformedPoint = mTransform * vPoint;
pCurMesh->m_Points->Add ( vTransformedPoint );
pCurMesh->m_BoundsMin = pCurMesh->m_BoundsMin.Min ( vTransformedPoint );
pCurMesh->m_BoundsMax = pCurMesh->m_BoundsMax.Max ( vTransformedPoint );
}
void FuzorExportContext::OnPolymesh( PolymeshTopology ^node )
{
ExportElementInfo ^curElementInfo = m_CurDocumentInfo->GetCurrentElementInfo();
if ( curElementInfo == nullptr )
{
return;
}

if ( curElementInfo->m_bSkipElement )
{
return;
}

if ( m_exportOptions->m_bIncludeMeshes && !curElementInfo->m_bSkipGeometry )
{
ExportedMeshInfo ^pCurMesh = gcnew ExportedMeshInfo();

System::Collections::Generic::IList<Autodesk::Revit::DB: olymeshFacet^> ^pFacets = node->GetFacets();
const int dwNumFacets = pFacets->Count;
const int dwNumIndices = dwNumFacets * 3;
List<int> ^pIndices = gcnew List<int>( dwNumIndices );
for ( int i = 0; i < dwNumFacets; i++ )
{
PolymeshFacet ^pFacet = pFacets[i];
pIndices->Add ( pFacet->V1 );
pIndices->Add ( pFacet->V2 );
pIndices->Add ( pFacet->V3 );
}

IList<XYZ^> ^pPoints = node->GetPoints();
IList<XYZ^> ^pNormals = node->GetNormals();
IList<UV^> ^pUVs = node->GetUVs();
DistributionOfNormals dist = node->DistributionOfNormals;

pCurMesh->m_Points = gcnew List<Vector4fv>( dwNumIndices );
pCurMesh->m_UVs = gcnew List<UVv>( dwNumIndices );

Matrix4x4v mTransform = Command::TransformToMatrix ( m_CurDocumentInfo->m_transforms->GetCurrentTransform() );

for ( int i = 0; i < dwNumIndices; i++ )
{
Vector4fv vPoint ( pPoints[pIndices[i]], 1.f );
Vector4fv vTransformedPoint = mTransform * vPoint;
pCurMesh->m_Points->Add ( vTransformedPoint );
pCurMesh->m_BoundsMin = pCurMesh->m_BoundsMin.Min ( vTransformedPoint );
pCurMesh->m_BoundsMax = pCurMesh->m_BoundsMax.Max ( vTransformedPoint );
}

pCurMesh->m_Normals = gcnew List<Vector4fv>( dwNumIndices )>H>
switch ( node->DistributionOfNormals )
{
case DistributionOfNormals::AtEachPoint:
{
for ( int i = 0; i < dwNumIndices; i++ )
{
Vector4fv vNormal = mTransform * Vector4fv ( pNormals[pIndices[i]], 0.f );
pCurMesh->m_Normals->Add ( vNormal );
}
break;
}
case DistributionOfNormals::OnePerFace:
{
Vector4fv vNormal = mTransform * Vector4fv ( pNormals[0], 0.f );
for ( int i = 0; i < dwNumIndices; i++ )
{
pCurMesh->m_Normals->Add ( vNormal );
}
break;
}
case DistributionOfNormals::OnEachFacet:
{
for ( int i = 0; i < dwNumFacets; i++ )
{
Vector4fv vNormal = mTransform * Vector4fv ( pNormals[i], 0.f );
pCurMesh->m_Normals->Add ( vNormal );
pCurMesh->m_Normals->Add ( vNormal );
pCurMesh->m_Normals->Add ( vNormal );
}
break;
}
}

for ( int i = 0; i < dwNumIndices; i++ )
{
UVv vUV ( pUVs[pIndices[i]] );
pCurMesh->m_UVs->Add ( vUV );
}

ExportedFace ^pCurFace = nullptr;
if ( m_bWithinFace )
{
pCurFace = curElementInfo->m_pCurExportElement->m_pExportFaces->Peek();
}
else
{
pCurFace = gcnew ExportedFace();
pCurFace->m_dwMaterialId = m_dwCurrentMaterialId;
curElementInfo->m_pCurExportElement->m_pExportFaces->Push ( pCurFace );
}

pCurFace->m_pExportedMeshInfo = pCurMesh;

#if _DEBUG
if ( pCurMesh->m_Points->Count != pCurMesh->m_UVs->Count )
{
TaskDialog::Show ( "Export Error", "Point Not Equal To UV!\n" );
}
#endif
}
}

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Rail Community


Autodesk Design & Make Report