@itwin/core-backend
Version:
iTwin.js backend components
384 lines • 17.8 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateGeometrySummaries = generateGeometrySummaries;
const core_bentley_1 = require("@itwin/core-bentley");
const core_geometry_1 = require("@itwin/core-geometry");
const core_common_1 = require("@itwin/core-common");
const Element_1 = require("./Element");
const Symbols_1 = require("./internal/Symbols");
// cspell:ignore earlin
/** Generates an array of GeometryStreamResponseProps. */
class ResponseGenerator {
verbosity = core_common_1.GeometrySummaryVerbosity.Basic;
includePlacement = false;
includePartReferences;
verboseSymbology = false;
elementIds;
iModel;
get wantSquish() { return core_common_1.GeometrySummaryVerbosity.Full !== this.verbosity; }
constructor(request, iModel) {
this.elementIds = request.elementIds;
this.iModel = iModel;
const opts = request.options;
if (undefined !== opts) {
this.verbosity = undefined !== opts.geometryVerbosity ? opts.geometryVerbosity : core_common_1.GeometrySummaryVerbosity.Basic;
this.includePlacement = true === opts.includePlacement;
this.includePartReferences = opts.includePartReferences;
this.verboseSymbology = true === opts.verboseSymbology;
}
}
generateSummaries() {
const summaries = [];
for (const elementId of this.elementIds)
summaries.push(this.generateSummary(elementId));
return summaries.join("\n");
}
generateSummary(id) {
let lines = [`[Geometry Summary for Element ${id}]`];
try {
const geom = this.getElementGeom(id);
if (undefined === geom)
throw new core_common_1.IModelError(core_bentley_1.IModelStatus.NoGeometry, "Element is neither a geometric element nor a geometry part");
if (undefined !== geom.geometricElement)
lines.push(this.summarizeElement(geom.geometricElement));
else if (undefined !== this.includePartReferences)
lines.push(this.summarizePartReferences(id, "2d" === this.includePartReferences)); // NB: Hideously inefficient if more than one element's summary was requested.
let curGeomParams;
let curLocalRange;
for (const entry of geom.iterator) {
if (this.verboseSymbology && (undefined === curGeomParams || !curGeomParams.isEquivalent(entry.geomParams))) {
lines.push(`Symbology: ${this.stringify(entry.geomParams)}`);
curGeomParams = entry.geomParams.clone();
}
if (undefined !== entry.localRange && (undefined === curLocalRange || !curLocalRange.isAlmostEqual(entry.localRange))) {
lines.push(this.summarizeRange3d(entry.localRange));
curLocalRange = entry.localRange;
}
const prim = entry.primitive;
switch (prim.type) {
case "textString":
case "image":
this.summarizePrimitive(lines, prim);
break;
case "brep":
this.summarizeBRep(lines, prim.brep);
break;
case "geometryQuery":
this.summarizeGeometryQuery(lines, prim.geometry);
break;
case "partReference":
lines.push(this.summarizePartReference(prim.part.id, prim.part.toLocal));
break;
}
}
}
catch (err) {
lines = lines.slice(0, 1);
lines.push(`ERROR: ${core_bentley_1.BentleyError.getErrorMessage(err)}`);
}
return lines.filter((line) => line !== "").join("\n");
}
summarizeElement(elem) {
const lines = [];
lines.push(`(${elem.is2d() ? "2D" : "3D"}) Category: ${elem.category}`);
lines.push(`Model: ${elem.model}`);
if (this.includePlacement) {
lines.push(`Range: ${this.stringify(elem.calculateRange3d())}`);
lines.push(`Transform: ${this.stringify(elem.getPlacementTransform())}`);
}
return lines.join("\n");
}
summarizePartReferences(id, is2d) {
const refIds = this.iModel[Symbols_1._nativeDb].findGeometryPartReferences([id], is2d);
return `Part references (${refIds.length}): ${refIds.join()}`;
}
getElementGeom(id) {
const elem = this.iModel.elements.getElement({ id, wantGeometry: true });
let iterator;
let geometricElement;
if (elem instanceof Element_1.GeometricElement) {
geometricElement = elem;
if (geometricElement.is2d()) {
iterator = core_common_1.GeometryStreamIterator.fromGeometricElement2d(geometricElement);
}
else {
(0, core_bentley_1.assert)(geometricElement.is3d());
iterator = core_common_1.GeometryStreamIterator.fromGeometricElement3d(geometricElement);
}
}
else if (elem instanceof Element_1.GeometryPart) {
iterator = core_common_1.GeometryStreamIterator.fromGeometryPart(elem);
}
return undefined !== iterator ? { iterator, geometricElement } : undefined;
}
summarizeRange3d(range) {
return `SubGraphicRange: ${this.stringify(range)}`;
}
summarizePrimitive(lines, primitive) {
const summary = primitive.type;
if (core_common_1.GeometrySummaryVerbosity.Basic >= this.verbosity) {
lines.push(summary);
return;
}
const json = this.stringify(primitive.type === "textString" ? primitive.textString : primitive.image);
if (core_common_1.GeometrySummaryVerbosity.Detailed >= this.verbosity) {
lines.push(`${summary}: ${json}`);
return;
}
lines.push(`${summary}:`);
lines.push(json);
}
summarizeBRep(lines, brep) {
const summary = "brep";
if (core_common_1.GeometrySummaryVerbosity.Basic >= this.verbosity) {
lines.push(summary);
return;
}
const json = this.stringify({ type: brep.type, transform: brep.transform, faceSymbology: brep.faceSymbology });
if (core_common_1.GeometrySummaryVerbosity.Detailed >= this.verbosity) {
lines.push(`${summary}: ${json}`);
return;
}
lines.push(`${summary}:`);
lines.push(json);
}
summarizePartReference(partId, partToLocal) {
let line = `part id: ${partId}`;
if (undefined !== partToLocal)
line = `${line} transform: ${this.stringify(partToLocal)}`;
return line;
}
summarizeGeometryQuery(lines, query) {
switch (this.verbosity) {
case core_common_1.GeometrySummaryVerbosity.Detailed:
lines.push(this.summarizeGeometryQueryDetailed(query));
break;
case core_common_1.GeometrySummaryVerbosity.Full:
lines.push(this.summarizeGeometryQueryFull(query));
break;
default:
lines.push(this.summarizeGeometryQueryBasic(query));
break;
}
}
summarizeGeometryQueryBasic(query) {
switch (query.geometryCategory) {
case "solid":
return query.solidPrimitiveType;
case "curvePrimitive":
return query.curvePrimitiveType;
case "curveCollection":
return query.curveCollectionType;
default:
return query.geometryCategory;
}
}
summarizeGeometryQueryFull(query) {
return this.geometryQueryToJson(query);
}
geometryQueryToJson(query) {
try {
const json = core_geometry_1.IModelJson.Writer.toIModelJson(query);
const str = JSON.stringify(json);
return this.wantSquish ? this.squish(str) : str;
}
catch (err) {
return core_bentley_1.BentleyError.getErrorMessage(err);
}
}
// Earlin likes to put tons of whitespace + newlines into his JSON. Remove it.
squish(str) {
return str.replace(/\s+/g, "");
}
stringify(obj) {
const json = JSON.stringify(obj);
return this.wantSquish ? this.squish(json) : json;
}
summarizeGeometryQueryDetailed(query) {
let summary = `${this.summarizeGeometryQueryBasic(query)}: `;
switch (query.geometryCategory) {
case "solid":
return summary + this.summarizeSolidPrimitive(query);
case "curvePrimitive":
return summary + this.summarizeCurvePrimitive(query);
case "curveCollection":
return summary + this.summarizeCurveCollection(query);
case "pointCollection":
return `${summary} numPoints: ${query.points.length}`;
case "bsurf":
return `${summary}'
' poleDimension: ${query.poleDimension}'
' numPolesTotal: ${query.numPolesTotal()}'
' degree[U,V]: ${JSON.stringify([query.degreeUV(core_geometry_1.UVSelect.uDirection), query.degreeUV(core_geometry_1.UVSelect.vDirection)])}'
' order[U,V]: ${JSON.stringify([query.orderUV(core_geometry_1.UVSelect.uDirection), query.orderUV(core_geometry_1.UVSelect.vDirection)])}'
' numSpan[U,V]: ${JSON.stringify([query.numSpanUV(core_geometry_1.UVSelect.uDirection), query.numSpanUV(core_geometry_1.UVSelect.vDirection)])}'
' numPoles[U,V]: ${JSON.stringify([query.numPolesUV(core_geometry_1.UVSelect.uDirection), query.numPolesUV(core_geometry_1.UVSelect.vDirection)])}'
' poleStep[U,V]: ${JSON.stringify([query.poleStepUV(core_geometry_1.UVSelect.uDirection), query.poleStepUV(core_geometry_1.UVSelect.vDirection)])}`;
case "polyface": {
const data = query.data;
summary = `${summary} pointCount: ${data.point.length}'
' pointIndexCount: ${data.pointIndex.length}`;
if (query.twoSided)
summary = `${summary} (two-sided)`;
if (undefined !== data.normal)
summary = `${summary} normalCount: ${data.normal.length}`;
if (undefined !== data.param)
summary = `${summary} paramCount: ${data.param.length}`;
if (undefined !== data.color)
summary = `${summary} colorCount: ${data.color.length}`;
return summary;
}
case "point":
return summary + this.geometryQueryToJson(query);
}
}
summarizeSolidPrimitive(solid) {
const summary = solid.capped ? " capped" : " uncapped";
switch (solid.solidPrimitiveType) {
case "box":
const box = solid;
return `${summary}'
' origin: ${JSON.stringify(box.getBaseOrigin().toJSON())}'
' topOrigin: ${JSON.stringify(box.getTopOrigin().toJSON())}'
' baseX: ${box.getBaseX()}'
' baseY: ${box.getBaseY()}`;
case "cone":
const cone = solid;
return `${summary}'
' baseCenterPoint: ${JSON.stringify(cone.getCenterA())}'
' topCenterPoint: ${JSON.stringify(cone.getCenterB())}'
' baseCenterRadius: ${JSON.stringify(cone.getRadiusA())}'
' topCenterRadius: ${JSON.stringify(cone.getRadiusB())}`;
case "sphere":
const sphere = solid;
return `${summary}'
' centerPoint: ${JSON.stringify(sphere.cloneCenter().toJSON())}'
' radius: ${JSON.stringify(sphere.trueSphereRadius())}`;
case "linearSweep":
const linearSweep = solid;
return `${summary}'
' vector: ${JSON.stringify(linearSweep.cloneSweepVector().toJSON())}'
' curves${this.summarizeCurveCollection(linearSweep.getCurvesRef())}`;
case "rotationalSweep":
const rotationalSweep = solid;
const axis = rotationalSweep.cloneAxisRay();
return `${summary}'
' center: ${JSON.stringify(axis.origin.toJSON())}'
' axis: ${JSON.stringify(axis.direction.toJSON())}'
' sweepAngle: ${rotationalSweep.getSweep().degrees}`;
case "ruledSweep":
const ruledSweep = solid;
const summarizedCollection = ruledSweep.cloneContours().map((curveCollection) => this.summarizeCurveCollection(curveCollection));
return `${summary}'
' isClosedVolume${ruledSweep.isClosedVolume}'
' contours: ${JSON.stringify(summarizedCollection)}`;
case "torusPipe":
const torusPipe = solid;
const vectorX = torusPipe.cloneVectorX();
const vectorY = torusPipe.cloneVectorY();
const sweep = torusPipe.getSweepAngle();
if (torusPipe.getIsReversed()) {
vectorY.scaleInPlace(-1.0);
sweep.setRadians(-sweep.radians);
}
return `${summary}'
' center: ${JSON.stringify(torusPipe.cloneCenter().toJSON())}'
' xyVectors: ${JSON.stringify([vectorX.toJSON(), vectorY.toJSON()])}'
' majorRadius: ${torusPipe.getMajorRadius()}'
' minorRadius: ${torusPipe.getMinorRadius()}'
' sweepAngle: ${sweep.degrees}`;
}
}
summarizeCurvePrimitive(curve) {
let summary = "";
const writer = new core_geometry_1.IModelJson.Writer();
switch (curve.curvePrimitiveType) {
case "arc":
const arc = curve;
summary = `${summary} center: ${JSON.stringify(arc.center.toJSON())}`;
if (undefined !== arc.circularRadius)
summary = `${summary} radius: ${arc.circularRadius()}`;
summary = `${summary}'
' vectorX:${JSON.stringify(arc.vector0.toJSON())}'
' vectorY:${JSON.stringify(arc.vector90.toJSON())}'
' sweepStartEnd [${arc.sweep.startDegrees}, ${arc.sweep.endDegrees}]`
+ ` curveLength: ${curve.curveLength()}`;
return summary;
case "lineSegment":
const lineSegment = curve;
summary = `${summary} points: ${JSON.stringify(lineSegment.toJSON())}`;
summary = `${summary} curveLength: ${curve.curveLength()}`;
return summary;
case "lineString":
const lineString = curve;
summary = `${summary} pointCount: ${lineString.numPoints()}'
' curveLength: ${curve.curveLength()}`;
return summary;
case "bsplineCurve":
const bsplineCurve = curve;
summary = `${summary}'
' curveOrder: ${bsplineCurve.order}'
' controlPointsCount: ${bsplineCurve.numPoles}'
' curveLength: ${curve.curveLength()}`;
return summary;
case "interpolationCurve":
const interpolationCurve = curve;
const interpolationProps = interpolationCurve.cloneProps();
summary = `${summary}'
' curveOrder: ${interpolationProps.order}'
' controlPointsCount: ${interpolationProps.fitPoints.length}`;
return summary;
case "akimaCurve":
const akimaCurve = curve;
const akimaProps = akimaCurve.cloneProps();
summary = `${summary}'
' controlPointsCount: ${akimaProps.fitPoints.length}`;
return summary;
case "bezierCurve":
const bezierCurve = curve;
summary = `${summary}'
' curveOrder: ${bezierCurve.order}'
' controlPointsCount: ${bezierCurve.numPoles}'
' curveLength: ${curve.curveLength()}`;
return summary;
case "transitionSpiral":
const transitionSpiral = curve;
const json = writer.handleTransitionSpiral(transitionSpiral);
summary = summary + JSON.stringify(json);
return summary;
case "curveChainWithDistanceIndex":
const curveChainWithDistanceIndex = curve;
const path = curveChainWithDistanceIndex.path;
summary = `${summary}'
' curveLength: ${curve.curveLength()}'
' isOpen: ${path.isOpenPath}`;
return summary;
}
}
summarizeCurveCollection(curves) {
let summary = "";
switch (curves.curveCollectionType) {
case "loop":
const loop = curves;
summary = `${summary} isInner: ${loop.isInner}`;
break;
case "path":
const path = curves;
summary = `${summary} isOpen: ${path.isOpenPath}`;
break;
}
return `${summary}'
' numCurves: ${curves.collectCurvePrimitives().length}'
' boundary: ${curves.dgnBoundaryType()}`;
}
}
/** @internal */
function generateGeometrySummaries(request, iModel) {
const generator = new ResponseGenerator(request, iModel);
return generator.generateSummaries();
}
//# sourceMappingURL=GeometrySummary.js.map
;