Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Augment JSON format for Sphere and Cone #1040

Merged
merged 16 commits into from
Mar 12, 2025
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1424,7 +1424,7 @@ bool DgnSphereDetail::TryGetRotationAxis (DPoint3dR center, DVec3dR axis, double
bool DgnSphereDetail::GetTransforms (TransformR localToWorld, TransformR worldToLocal) const
{
QVNormalizedTransforms (m_localToWorld, localToWorld, worldToLocal);
return worldToLocal.InverseOf (m_localToWorld);
return worldToLocal.InverseOf (m_localToWorld); // this makes no sense but without it SolidPrimitive.ArcIntersection test fails
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2215,4 +2215,61 @@ TEST(Spiral, CreateInterpolatingSpiralsPointBearingCurvaturePointBearing)
}
}
Check::ClearGeometry("Spiral.CreateInterpolatingSpiralsPointBearingCurvaturePointBearing");
}

TEST(Spiral, IFCExample)
{
DPoint3d startPoint = DPoint3d::From(451581.55191480799, 4538983.4705996597, 0.0);
double startRadians = 6.2280619453155204;
double startRadius = -288.0;
double targetLength = 84.185;
double endRadius = 0.0;

ICurvePrimitivePtr curve = ICurvePrimitive::CreatePseudolSpiralWithTrueRadiusLengthRadius(DSpiral2dBase::TransitionType_Clothoid, startPoint, startRadians, startRadius, targetLength, endRadius);
Check::SaveTransformed(*curve);
Check::True(curve.IsValid());

auto placement = curve->GetSpiralPlacementCP();
Check::True(placement != nullptr);
Check::True(placement->spiral != nullptr);

// When fracA < fracB, the local spiral defines a segment of the spiral starting at the
// origin and extending into the first quadrant (or 4th if negative (CW) curvature).
// When fracA > fracB, not only is the curve reversed, but the local spiral sits in
// quadrant 3 (or 2) of the full spiral, which is obtained by rotating the half in
// quadrant 1 (or 4) 180 degrees about the origin.
bool rotateAndReverse = placement->fractionA > placement->fractionB;

DPoint3d myStartPoint = placement->frame.Origin();
DPoint3d myEndPoint; curve->FractionToPoint(rotateAndReverse ? 0.0 : 1.0, myEndPoint);
double myTargetLength = placement->spiral->mLength;
double myStartRadius = DoubleOps::ValidatedDivideDistance(1.0, placement->spiral->mCurvature0, 0.0);
double myEndRadius = DoubleOps::ValidatedDivideDistance(1.0, placement->spiral->mCurvature1, 0.0);

DVec3d myStartTangent = DVec3d::FromXYAngleAndMagnitude(placement->spiral->mTheta0, 1.0);
if (rotateAndReverse)
myStartTangent.Scale(-1.0);
placement->frame.MultiplyMatrixOnly(myStartTangent);
double myStartRadians = myStartTangent.AngleXY();

DVec3d myEndTangent = DVec3d::FromXYAngleAndMagnitude(placement->spiral->mTheta1, 1.0);
if (rotateAndReverse)
myEndTangent.Scale(-1.0);
placement->frame.MultiplyMatrixOnly(myEndTangent);
double myEndRadians = myEndTangent.AngleXY();

if (rotateAndReverse)
{
std::swap(myStartRadius, myEndRadius);
std::swap(myStartRadians, myEndRadians);
std::swap(myStartPoint, myEndPoint);
}

Check::Near(startPoint, myStartPoint);
Check::NearPeriodic(myStartRadians, startRadians);
Check::Near(myStartRadius, startRadius);
Check::Near(targetLength, myTargetLength);
Check::Near(myEndRadius, endRadius);

Check::ClearGeometry ("Spiral.IFCExample");
}
253 changes: 193 additions & 60 deletions iModelCore/GeomLibs/geom/test/SerializationTest/t_crossPlatform.cpp

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -53059,3 +53059,4 @@
14563, 5720, 8612,0
]
}}
]
Original file line number Diff line number Diff line change
Expand Up @@ -51468,3 +51468,4 @@
14130, 5549, 8378,0
]
}}
]
Original file line number Diff line number Diff line change
Expand Up @@ -17434,3 +17434,4 @@
4716, 1801, 2883,0
]
}}
]
Original file line number Diff line number Diff line change
Expand Up @@ -53059,3 +53059,4 @@
14563, 5720, 8612,0
]
}}
]
Original file line number Diff line number Diff line change
Expand Up @@ -53059,3 +53059,4 @@
14563, 5720, 8612,0
]
}}
]
Original file line number Diff line number Diff line change
Expand Up @@ -53059,3 +53059,4 @@
14563, 5720, 8612,0
]
}}
]
Original file line number Diff line number Diff line change
Expand Up @@ -53059,3 +53059,4 @@
14563, 5720, 8612,0
]
}}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"cone":{"capped":true,"start":[0.0,0.0,0.0],"end":[0.0,0.0,1.0],"startRadius":0.1,"endRadius":0.2,"xyVectors":[[0.1,0.1,0.0],[-0.2,0.2,0.0]],"xyzVectors":[[0.1,0.1,0.0],[-0.2,0.2,0.0],[0.0,0.0,1.0]]}}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"cone":{"start":[0.0,0.0,0.0],"end":[0.0,0.0,1.0],"capped":true,"startRadius":0.014142135623730954,"endRadius":0.02828427124746191,"xyVectors":[[0.7071067811865475,0.7071067811865475,0.0],[-0.7071067811865475,0.7071067811865475,0.0]]}}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"cone":{"capped":true,"start":[0.0,0.0,0.0],"end":[0.0,0.0,1.0],"startRadius":0.1,"endRadius":0.2,"xyVectors":[[0.1,0.2,0.0],[-0.1,0.2,0.0]],"xyzVectors":[[0.1,0.2,0.0],[-0.1,0.2,0.0],[0.0,0.0,1.0]]}}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"sphere":{"center":[0.0,0.0,0.0],"latitudeStartEnd":[-90.0,90.0],"radiusX":1.0,"radiusY":2.0,"radiusZ":3.0}}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"sphere":null}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"sphere":{"center":[0.0,0.0,0.0],"zxVectors":[[0.09950371902099893,0.0,0.9950371902099893],[0.6666666666666666,0.6666666666666666,0.3333333333333333]],"xyzVectors":[[0.6666666666666666,0.6666666666666666,0.3333333333333333],[-0.8944271909999159,0.2683281572999747,0.35777087639996635],[0.09950371902099893,0.0,0.9950371902099893]],"latitudeStartEnd":[-90.0,90.0],"radiusX":1.5,"radiusY":1.118033988749895,"radiusZ":1.004987562112089}}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"sphere":null}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"cone":{"capped":true,"start":[0,0,0],"end":[0,0,1],"startRadius":0.1,"endRadius":0.2,"xyVectors":[[0.1,0.1,0],[-0.2,0.2,0]],"xyzVectors":[[0.1,0.1,0],[-0.2,0.2,0],[0,0,1]]}}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"cone":{"capped":true,"start":[0,0,0],"end":[0,0,1],"startRadius":0.1,"endRadius":0.2,"xyVectors":[[0.1,0.1,0],[-0.2,0.2,0]]}}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"cone":{"capped":true,"start":[0,0,0],"end":[0,0,1],"startRadius":0.1,"endRadius":0.2,"xyVectors":[[0.1,0.2,0],[-0.1,0.2,0]],"xyzVectors":[[0.1,0.2,0],[-0.1,0.2,0],[0,0,1]]}}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"cone":{"capped":true,"start":[0,0,0],"end":[0,0,1],"startRadius":0.1,"endRadius":0.2,"xyVectors":[[0.1,0.2,0],[-0.1,0.2,0]]}}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"sphere":{"center":[0,0,0],"radiusX":1,"radiusY":2,"radiusZ":3}}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"sphere":{"center":[0,0,0],"radiusX":1,"radiusY":2,"radiusZ":3}}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"sphere":{"center":[0,0,0],"zxVectors":[[0.09950371902099893,0,0.9950371902099893],[0.6666666666666666,0.6666666666666666,0.3333333333333333]],"xyzVectors":[[0.6666666666666666,0.6666666666666666,0.3333333333333333],[-0.8944271909999159,0.2683281572999747,0.35777087639996635],[0.09950371902099893,0,0.9950371902099893]],"radiusX":1.5,"radiusY":1.118033988749895,"radiusZ":1.004987562112089}}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"sphere":{"center":[0,0,0],"zxVectors":[[0.09950371902099893,0,0.9950371902099893],[0.6666666666666666,0.6666666666666666,0.3333333333333333]],"radiusX":1.5,"radiusY":1.118033988749895,"radiusZ":1.004987562112089}}
Binary file not shown.
2 changes: 1 addition & 1 deletion iModelCore/GeomLibs/geom/test/src/checkers.h
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ static bool Near (DEllipse3dCR a, DEllipse3dCR b, char const*pString = NULL, dou
//! Check all components of a two DConic4d.
static void Near (DConic4dCR a, DConic4dCR b, char const*pName = NULL, double refValue = 0.0);
//! compare angles, allow shift by multiple of 2pi
static bool NearPeriodic (double thetaA, double thetaB, char const*pString);
static bool NearPeriodic (double thetaA, double thetaB, char const*pString = NULL);

//! compare strongly typed angles, allow shift by multiple of 2pi
static bool NearPeriodic (Angle thetaA, Angle thetaB, char const*pString = NULL);
Expand Down
58 changes: 36 additions & 22 deletions iModelCore/GeomLibs/serialization/src/IModelJsonReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,6 @@ bool tryValueToXYZ (BeJsConst value, DPoint3dR xyz)
xyz.Init (xyzArray[0], xyzArray[1], xyzArray[2]);
stat = haveX && haveY; // allow optional z
}

return stat;
}

Expand Down Expand Up @@ -383,33 +382,50 @@ bool tryValueToBVectorUInt32 (BeJsConst value, bvector<uint32_t> &data)
return false;
}

bool completeAxesConstruction (DVec3dCR vector0, int index0, DVec3dCR vector1, int index1, int index2, RotMatrixR axes, RotMatrixCR defaultAxes)
bool completeAxesConstruction (DVec3dCR vector0, int index0, DVec3dCR vector1, int index1, DVec3dCP vector2, int index2, RotMatrixR axes, RotMatrixCR defaultAxes)
{
DVec3d columns[3];
columns[index0] = vector0;
columns[index1] = vector1;
columns[index2] = DVec3d::FromCrossProduct (vector0, vector1);
axes = RotMatrix::FromColumnVectors (columns[0], columns[1], columns[2]);
if (axes.SquareAndNormalizeColumns (axes, index0, index1))
if (!vector2)
{ // square and normalize
columns[index2] = DVec3d::FromCrossProduct (vector0, vector1);
axes = RotMatrix::FromColumnVectors (columns[0], columns[1], columns[2]);
if (axes.SquareAndNormalizeColumns (axes, index0, index1))
return true;
}
else
{ // preserve axes
columns[index2] = *vector2;
axes = RotMatrix::FromColumnVectors(columns[0], columns[1], columns[2]);
return true;
}
axes = defaultAxes;
return false;
}
bool derefAxes (BeJsConst source, RotMatrixR axes, RotMatrixCR defaultAxes)
{
axes = defaultAxes;
auto xyVectors = source["xyVectors"];
DVec3d vectorX, vectorY, vectorZ;

auto xyzVectors = source["xyzVectors"];
if (xyzVectors.isArray() && xyzVectors.size() == 3
&& tryValueToXYZ(xyzVectors[0], vectorX)
&& tryValueToXYZ(xyzVectors[1], vectorY)
&& tryValueToXYZ(xyzVectors[2], vectorZ))
return completeAxesConstruction(vectorX, 0, vectorY, 1, &vectorZ, 2, axes, defaultAxes);

auto xyVectors = source["xyVectors"];
if (xyVectors.isArray () && xyVectors.size () == 2
&& tryValueToXYZ (xyVectors[0], vectorX)
&& tryValueToXYZ (xyVectors[1], vectorY))
return completeAxesConstruction (vectorX, 0, vectorY, 1, 2, axes, defaultAxes);
return completeAxesConstruction (vectorX, 0, vectorY, 1, nullptr, 2, axes, defaultAxes);

auto zxVectors = source["zxVectors"];
if (zxVectors.isArray () && zxVectors.size () == 2
&& tryValueToXYZ (zxVectors[0], vectorZ)
&& tryValueToXYZ (zxVectors[1], vectorX))
return completeAxesConstruction (vectorZ, 2, vectorX, 0, 1, axes, defaultAxes);
return completeAxesConstruction (vectorZ, 2, vectorX, 0, nullptr, 1, axes, defaultAxes);

return false;
}
Expand Down Expand Up @@ -613,11 +629,13 @@ bool tryValueToCone (BeJsConst value, ISolidPrimitivePtr &result)
DPoint3d centerA, centerB;
bool capped;
RotMatrix axes;

bool axesOK = derefAxes(value, axes, RotMatrix::FromIdentity());
auto radius = derefValidatedDouble(value, "radius", ValidatedDouble (0, false));
auto radiusA = derefValidatedDouble (value, "startRadius", radius);
auto radiusB = derefValidatedDouble(value, "endRadius", radiusA);
derefBool (value, "capped", capped, false);

if ( tryValueToXYZ (value["start"], centerA)
&& tryValueToXYZ (value["end"], centerB)
&& radiusA.IsValid ()
Expand Down Expand Up @@ -804,19 +822,19 @@ bool tryValueToSphere (BeJsConst value, ISolidPrimitivePtr &result)
derefBool (value, "capped", capped, false);
derefAxes (value, axes, RotMatrix::FromIdentity ());
auto radius = derefValidatedDouble (value, "radius", ValidatedDouble (0.0, false));
auto radiusX = derefValidatedDouble (value, "radius", radius);
auto radiusY = derefValidatedDouble (value, "radius", radiusX);
auto radiusZ = derefValidatedDouble (value, "radius", radiusY);
auto radiusX = derefValidatedDouble (value, "radiusX", radius);
auto radiusY = derefValidatedDouble (value, "radiusY", radiusX);
auto radiusZ = derefValidatedDouble (value, "radiusZ", radiusY);
// required ...
if ( tryValueToXYZ (value["center"], center)
&& radiusX.IsValid ()
&& radiusY.IsValid ()
&& radiusZ.IsValid ())
&& radiusX.IsValid () && radiusX.Value() > 0.0
&& radiusY.IsValid () && radiusY.Value() > 0.0
&& radiusZ.IsValid () && radiusZ.Value() > 0.0)
{
// hm .. insider knowledge here
// 1) sphere by radius and axes multiplies the axes by the radius -- radius=1 preserves "our" radii.
DgnSphereDetail dgnSphere(center, 1.0);
axes.ScaleColumns (radiusX.Value (), radiusY.Value (), radiusZ.Value ());
DgnSphereDetail dgnSphere (center, axes, 1.0);
dgnSphere.m_localToWorld.SetMatrix(axes); // no constructors preserve the input axes, so set directly

ValidatedDouble latitudeStartRadians, latitudeSweepRadians;
if (derefLatitudeStartSweepRadians (value, latitudeStartRadians, latitudeSweepRadians))
{
Expand Down Expand Up @@ -1133,19 +1151,15 @@ CurveVector::BoundaryType boundaryType
{
// PP demands that only one loop be called outer ... check it . .
int numOuter = 0;
int numInner = 0;
int numOther = 0;
UNUSED_VARIABLE(numInner);
for (auto & cp : *result)
{
auto loop = cp->GetChildCurveVectorP ();
if (loop.IsValid ()) // it really has to be valid
{
if (loop->GetBoundaryType () == CurveVector::BOUNDARY_TYPE_Outer)
numOuter++;
else if (loop->GetBoundaryType () == CurveVector::BOUNDARY_TYPE_Inner)
numInner++;
else
else if (loop->GetBoundaryType () != CurveVector::BOUNDARY_TYPE_Inner)
numOther++;
}
}
Expand Down
Loading