Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
8 changes: 3 additions & 5 deletions common/api/core-frontend.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -884,8 +884,7 @@ export class AccuDrawShortcuts {
static defineACSByElement(): Promise<boolean>;
// (undocumented)
static defineACSByPoints(): Promise<boolean>;
// (undocumented)
static getACS(acsName: string | undefined, useOrigin: boolean, useRotation: boolean): BentleyStatus;
static getACS(acsName: string | undefined, useOrigin: boolean, useRotation: boolean): Promise<AuxCoordSystemState | undefined>;
// (undocumented)
static itemFieldAcceptInput(index: ItemField, str: string): Promise<void>;
// (undocumented)
Expand Down Expand Up @@ -939,8 +938,7 @@ export class AccuDrawShortcuts {
static suspendToggle(): void;
// (undocumented)
static updateACSByPoints(acs: AuxCoordSystemState, vp: Viewport, points: Point3d[], isDynamics: boolean): boolean;
// (undocumented)
static writeACS(_acsName: string): BentleyStatus;
static writeACS(acsName: string | undefined): Promise<AuxCoordSystemState | undefined>;
}

// @beta
Expand Down Expand Up @@ -1416,7 +1414,7 @@ export abstract class AuxCoordSystemState extends ElementState implements AuxCoo
constructor(props: AuxCoordSystemProps, iModel: IModelConnection);
// (undocumented)
static get className(): string;
static createNew(acsName: string, iModel: IModelConnection): AuxCoordSystemState;
static createNew(_acsName: string, iModel: IModelConnection): AuxCoordSystemState;
// (undocumented)
description?: string;
// (undocumented)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@itwin/core-frontend",
"comment": "",
Comment thread
bbastings marked this conversation as resolved.
Comment thread
aruniverse marked this conversation as resolved.
"type": "none"
}
],
"packageName": "@itwin/core-frontend"
}
20 changes: 13 additions & 7 deletions core/frontend/src/AuxCoordSys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import { JsonUtils } from "@itwin/core-bentley";
import { Angle, AngleSweep, Arc3d, Matrix3d, Point2d, Point3d, Transform, Vector3d, XAndY, XYAndZ, YawPitchRollAngles } from "@itwin/core-geometry";
import {
AuxCoordSystem2dProps, AuxCoordSystem3dProps, AuxCoordSystemProps, BisCodeSpec, Code, ColorDef, IModel, LinePixels, Npc,
AuxCoordSystem2dProps, AuxCoordSystem3dProps, AuxCoordSystemProps, Code, ColorDef, IModel, LinePixels, Npc,
} from "@itwin/core-common";
import { ElementState } from "./EntityState";
import { IModelConnection } from "./IModelConnection";
Expand Down Expand Up @@ -79,13 +79,19 @@ export abstract class AuxCoordSystemState extends ElementState implements AuxCoo
}

/** Create a new AuxCoordSystemState.
* @param acsName the name for the new AuxCoordSystem
* @param iModel the iModel for which the ACS applies.
* @note call this method with the appropriate subclass (e.g. AuxCoordSystemSpatialState, AuxCoordSystem2dState, etc), not on AuxCoordSystemState directly
* @param _acsName unused, this method creates an empty code as it lacks sufficient information to do otherwise.
* @param iModel the iModel for which the ACS applies
* @note Inserting a new named ACS element requires creating a CodeProps for the type of view and the view's definition model.
* This method doesn't have the information to do this so it creates an empty code.
* @example
* ```typescript
* const codeSpecName = vp.view.isSpatialView() ? BisCodeSpec.auxCoordSystemSpatial : (vp.view.is3d() ? BisCodeSpec.auxCoordSystem3d : BisCodeSpec.auxCoordSystem2d);
* const codeSpec = await vp.iModel.codeSpecs.getByName(codeSpecName);
* const code = new Code({ spec: codeSpec.id, scope: vp.view.model, value: acsName });
* ```
*/
public static createNew(acsName: string, iModel: IModelConnection): AuxCoordSystemState {
const myCode = new Code({ spec: BisCodeSpec.auxCoordSystemSpatial, scope: IModel.dictionaryId.toString(), value: acsName });
return new AuxCoordSystemSpatialState({ model: IModel.dictionaryId, code: myCode, classFullName: this.classFullName }, iModel);
public static createNew(_acsName: string, iModel: IModelConnection): AuxCoordSystemState {
return new AuxCoordSystemSpatialState({ model: IModel.dictionaryId, code: Code.createEmpty(), classFullName: this.classFullName }, iModel);
Comment thread
aruniverse marked this conversation as resolved.
}
Comment thread
bbastings marked this conversation as resolved.

public constructor(props: AuxCoordSystemProps, iModel: IModelConnection) {
Expand Down
2 changes: 1 addition & 1 deletion core/frontend/src/EntityState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export class ElementState extends EntityState implements ElementProps {
public override toJSON(): ElementProps {
const val = super.toJSON() as ElementProps;
if (Id64.isValid(this.code.spec))
val.code = this.code;
val.code = this.code.toJSON(); // Ensure _value with get accessor is serialized...

val.model = this.model;
val.parent = this.parent;
Expand Down
181 changes: 117 additions & 64 deletions core/frontend/src/tools/AccuDrawTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@
* @module Tools
*/

import { BentleyStatus } from "@itwin/core-bentley";
import { AuxCoordSystemProps, BisCodeSpec, Code } from "@itwin/core-common";
import { AxisOrder, Geometry, Matrix3d, Plane3dByOriginAndUnitNormal, Point3d, Transform, Vector3d } from "@itwin/core-geometry";
import { AccuDraw, AccuDrawFlags, CompassMode, ContextMode, ItemField, KeyinStatus, LockedStates, RotationMode, ThreeAxes } from "../AccuDraw";
import { TentativeOrAccuSnap } from "../AccuSnap";
import { ACSDisplayOptions, AuxCoordSystemState } from "../AuxCoordSys";
import { ACSDisplayOptions, ACSType, AuxCoordSystemState } from "../AuxCoordSys";
import { SnapDetail } from "../HitDetail";
import { IModelApp } from "../IModelApp";
import { DecorateContext } from "../ViewContext";
import { ViewState } from "../ViewState";
import { ScreenViewport, Viewport } from "../Viewport";
import { BeButtonEvent, CoreTools, Tool } from "./Tool";
import { AccuDrawShortcutImplementation, AccuDrawShortcutTool } from "./AccuDrawShortcutTool";
Expand All @@ -35,6 +36,9 @@ function normalizedCrossProduct(vec1: Vector3d, vec2: Vector3d, out: Vector3d):
* @beta
*/
export class AccuDrawShortcuts {
// Monotonic token used to ignore stale async ACS operations.
private static _acsRequestGeneration = 0;

/** Disable/Enable AccuDraw for the session */
public static sessionToggle(): void {
const accudraw = IModelApp.accuDraw;
Expand Down Expand Up @@ -871,55 +875,88 @@ export class AccuDrawShortcuts {
return IModelApp.tools.run("AccuDraw.DefineACSByPoints");
}

public static getACS(acsName: string | undefined, useOrigin: boolean, useRotation: boolean): BentleyStatus {
private static async getACSCode(view: ViewState, acsName: string): Promise<Code> {
const codeSpecName = view.isSpatialView() ? BisCodeSpec.auxCoordSystemSpatial : (view.is3d() ? BisCodeSpec.auxCoordSystem3d : BisCodeSpec.auxCoordSystem2d);
const codeSpec = await view.iModel.codeSpecs.getByName(codeSpecName);
return new Code({ spec: codeSpec.id, scope: view.model, value: acsName });
}

private static async getNamedACS(view: ViewState, acsName: string): Promise<{ validForView: boolean, acs?: AuxCoordSystemState }> {
const acsCode = await this.getACSCode(view, acsName);
const acsProps = await view.iModel.elements.loadProps(acsCode.toJSON());
if (!acsProps)
return { validForView: false };

const namedAcs = AuxCoordSystemState.fromProps(acsProps, view.iModel);
const validForView = namedAcs.isValidForView(view);

return { validForView, acs: namedAcs };
}

private static async createNewACS(view: ViewState, acsName: string): Promise<AuxCoordSystemState> {
// Want a CodeProps to support insert so ViewState.createAuxCoordSystem(acsName) is not called.
const acsCode = await this.getACSCode(view, acsName);

// Determine the class name based on view type
let classFullName: string;
if (view.isSpatialView())
classFullName = "BisCore:AuxCoordSystemSpatial";
else if (view.is3d())
classFullName = "BisCore:AuxCoordSystem3d";
else
classFullName = "BisCore:AuxCoordSystem2d";

const acsProps: AuxCoordSystemProps = { model: acsCode.scope, code: acsCode.toJSON(), classFullName, type: ACSType.None };
const acs = AuxCoordSystemState.fromProps(acsProps, view.iModel);
return acs;
}

/**
* Set the AuxiliaryCoordinateSystem for the current AccuDraw viewport by name.
* Optionally updates the AccuDraw origin and rotation to match the ACS.
* @note When no name is specified, AccuDraw is updated using the view's current ACS.
* @returns AuxCoordSystemState or undefined if name does not exist or is invalid for the view.
* @throws Error if resolving the ACS CodeSpec or loading ACS element properties fails.
*/
public static async getACS(acsName: string | undefined, useOrigin: boolean, useRotation: boolean): Promise<AuxCoordSystemState | undefined> {
const accudraw = IModelApp.accuDraw;
if (!accudraw.isEnabled)
return BentleyStatus.ERROR;
return undefined;

const vp = accudraw.currentView;
if (!vp)
return BentleyStatus.ERROR;
return undefined;

let currRotation = 0, currBaseRotation = 0;
const axes = new ThreeAxes();
const view = vp.view;
const requestGeneration = ++this._acsRequestGeneration;
const isRequestCurrent = () => accudraw.isEnabled && accudraw.currentView === vp && vp.view === view && requestGeneration === this._acsRequestGeneration;

if (!useRotation) {
// Save current rotation, event listener on ACS change will orient AccuDraw to ACS...
currRotation = accudraw.rotationMode;
currBaseRotation = accudraw.flags.baseRotation;
axes.setFrom(accudraw.axes);
}
let currentACS = view.auxiliaryCoordinateSystem;

if (acsName && "" !== acsName) {
// // See if this ACS already exists...
// DgnCode acsCode = AuxCoordSystem:: CreateCode(vp -> GetViewControllerR().GetViewDefinition(), acsName);
// DgnElementId acsId = vp -> GetViewController().GetDgnDb().Elements().QueryElementIdByCode(acsCode);

// if (!acsId.IsValid())
// return ERROR;

// AuxCoordSystemCPtr auxElm = vp -> GetViewController().GetDgnDb().Elements().Get<AuxCoordSystem>(acsId);
const namedAcsResult = await this.getNamedACS(view, acsName);
if (!isRequestCurrent())
return undefined;

// if (!auxElm.IsValid())
// return ERROR;
if (!namedAcsResult.validForView)
return undefined;

// AuxCoordSystemPtr acsPtr = auxElm -> MakeCopy<AuxCoordSystem>();
const namedAcs = namedAcsResult.acs;
if (!namedAcs)
return undefined;

// if (!acsPtr.IsValid())
// return ERROR;
if (!useOrigin)
namedAcs.setOrigin(currentACS.getOrigin());

// AuxCoordSystemCR oldACS = vp -> GetViewController().GetAuxCoordinateSystem();
if (!useRotation)
namedAcs.setRotation(currentACS.getRotation());

// if (!useOrigin)
// acsPtr -> SetOrigin(oldACS.GetOrigin());

// if (!useRotation)
// acsPtr -> SetRotation(oldACS.GetRotation());

// AccuDraw:: UpdateAuxCoordinateSystem(* acsPtr, * vp);
AccuDraw.updateAuxCoordinateSystem(namedAcs, vp); // Sets AccuDrawFlags.OrientACS hint to orient AccuDraw to ACS...
currentACS = namedAcs;
Comment thread
bbastings marked this conversation as resolved.
}

const currentACS = vp.view.auxiliaryCoordinateSystem;
if (!isRequestCurrent())
return undefined;

if (useOrigin) {
accudraw.origin.setFrom(currentACS.getOrigin());
Expand All @@ -933,57 +970,73 @@ export class AccuDrawShortcuts {
} else {
this.itemFieldUnlockAll();

accudraw.setRotationMode(currRotation);
accudraw.flags.baseRotation = currBaseRotation;
accudraw.axes.setFrom(axes);

if (RotationMode.ACS === accudraw.flags.baseRotation) {
const acs = currentACS.clone();

const rMatrix = accudraw.getRotation();
acs.setRotation(rMatrix);

acs.setRotation(accudraw.getRotation());
AccuDraw.updateAuxCoordinateSystem(acs, vp);
}

accudraw.published.flags &= ~AccuDrawFlags.OrientACS;
}

return BentleyStatus.SUCCESS;
return currentACS;
}

public static writeACS(_acsName: string): BentleyStatus {
/**
* Create a new AuxiliaryCoordinateSystem for the current AccuDraw viewport using the compass origin, orientation, and mode.
* @note When no name is specified, the view's current ACS is updated from AccuDraw. Caller can choose to create
* an EditCommand to insert/update as a named ACS element using the returned AuxCoordSystemState.
* @returns AuxCoordSystemState or undefined if ACS could not be created.
* @throws Error if resolving the ACS CodeSpec or loading ACS element properties fails.
*/
public static async writeACS(acsName: string | undefined): Promise<AuxCoordSystemState | undefined> {
const accudraw = IModelApp.accuDraw;
if (!accudraw.isEnabled)
return BentleyStatus.ERROR;
return undefined;

const vp = accudraw.currentView;
if (!vp)
return BentleyStatus.ERROR;
return undefined;

const view = vp.view;
const requestGeneration = ++this._acsRequestGeneration;
const isRequestCurrent = () => accudraw.isEnabled && accudraw.currentView === vp && vp.view === view && requestGeneration === this._acsRequestGeneration;

// const origin = accudraw.origin;
// const rMatrix = accudraw.getRotation();
// AuxCoordSystemPtr acsPtr = AuxCoordSystem:: CreateFrom(vp -> GetViewController().GetAuxCoordinateSystem());
// acsPtr -> SetOrigin(origin);
// acsPtr -> SetRotation(rMatrix);
// acsPtr -> SetType(CompassMode.Polar == accudraw.getCompassMode() ? ACSType :: Cylindrical : ACSType:: Rectangular);
// acsPtr -> SetCode(AuxCoordSystem:: CreateCode(vp -> GetViewControllerR().GetViewDefinition(), nullptr != acsName ? acsName : ""));
// acsPtr -> SetDescription("");
let acs: AuxCoordSystemState | undefined;
if (acsName && "" !== acsName) {
const namedAcsResult = await this.getNamedACS(view, acsName);
if (!isRequestCurrent())
return undefined;

acs = namedAcsResult.acs;
if (!acs) {
acs = await this.createNewACS(view, acsName);
if (!isRequestCurrent())
return undefined;
} else if (!namedAcsResult.validForView) {
return undefined;
}
} else {
acs = view.auxiliaryCoordinateSystem.clone();
acs.description = "";
}

// if (acsName && '\0' != acsName[0]) {
// DgnDbStatus status;
// acsPtr -> Insert(& status);
if (!isRequestCurrent())
return undefined;

// if (DgnDbStatus:: Success != status)
// return BentleyStatus.ERROR;
// }
if (!acs)
return undefined;

// AccuDraw:: UpdateAuxCoordinateSystem(* acsPtr, * vp);
acs.setOrigin(accudraw.origin);
acs.setRotation(accudraw.getRotation());
acs.type = CompassMode.Polar === accudraw.compassMode ? ACSType.Cylindrical : ACSType.Rectangular;

// accudraw.flags.baseRotation = RotationMode.ACS;
// accudraw.SetRotationMode(RotationMode.ACS);
AccuDraw.updateAuxCoordinateSystem(acs, vp);
accudraw.flags.baseRotation = RotationMode.ACS;
accudraw.setRotationMode(RotationMode.ACS);

return BentleyStatus.SUCCESS;
return acs;
}

public static itemFieldUnlockAll(): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ describe("ViewState", () => {
assert.notDeepEqual(v2, viewState);

const acs = v2.createAuxCoordSystem("test");
assert.equal(acs.code.value, "test");
Comment thread
aruniverse marked this conversation as resolved.
assert.instanceOf(acs, AuxCoordSystemSpatialState);
Comment thread
bbastings marked this conversation as resolved.
acs.setOrigin({ x: 1, y: 1 });
assert.isTrue(acs.getOrigin().isExactEqual({ x: 1, y: 1, z: 0 }));
Expand Down
Loading