cancel
Showing results for 
Search instead for 
Did you mean: 
EN
cancel
Showing results for 
Search instead for 
Did you mean: 

API_DrawingType::anchorPoint is ignored by ACAPI_Element_Create and ACAPI_Element_Change

API_DrawingType::anchorPoint is documented as "Placement reference by bounding box node (relevant only if not useOwnOrigoAsAnchor)" — nothing suggests it's output-only. However, I cannot find a way to actually set it through the API.

Repro (minimal):

  1. Create a Drawing linked to a navigator item via ACAPI_Element_Create, explicitly setting element.drawing.anchorPoint = APIAnc_RT (or any value other than APIAnc_LB) before the call.
  2. Read the element back with ACAPI_Element_Get.

Observed: anchorPoint always comes back as APIAnc_LB, and pos always equals bounds.xMin/yMin (the bottom-left corner), regardless of what was requested at creation.

Also tried: calling ACAPI_Element_Change on an already-placed Drawing with the anchorPoint mask bit set, to any of the 9 values. Same result every time.

Ruled out as a factor: whether the Drawing has a custom clip frame (isCutWithFrame = true, clip polygon in absolute layout coordinates) or not (isCutWithFrame = false, auto-fit extent) — identical behavior in both cases, tested explicitly.

Interesting data point: a Drawing placed interactively through the UI (Drawing Settings dialog, 3×3 anchor grid) correctly stores and reports a non-APIAnc_LB anchor (e.g. Center) when read with ACAPI_Element_Get — so the field is genuinely meaningful and persisted when set by the UI. It's specifically ACAPI_Element_Create/ACAPI_Element_Change that force it back to APIAnc_LB. Worse: calling ACAPI_Element_Change on such a UI-placed Drawing — even for an unrelated field — also resets its UI-set anchor to APIAnc_LB, and it cannot be restored to its original value through the API either.

Side finding, in case it's related: bounds is cached and does not reflect a pos change until ACAPI_Drawing_Update_Drawings is called — and even then, only across a separate command/API round-trip; calling Update+Get+Change within the same function call (same synchronous execution) doesn't see the updated bounds.

Questions:

  1. Is anchorPoint actually settable via the API at all for a view-linked Drawing, or is it silently read-only despite the doc wording?
  2. If it's not settable, is there another API (or Change mask combination) to reposition a Drawing by a bounding-box corner/center other than bottom-left, short of manually computing bounds via Update+Get and shifting pos (and poly/clip coordinates, which are stored in absolute coordinates and need a matching shift)?
  3. Is forcing a UI-set anchorPoint to APIAnc_LB via an unrelated ACAPI_Element_Change call (e.g. changing only ratio) expected/by design, and is there any way to avoid that side effect?

     

    Operating system used: Mac Apple Silicon

Archicad 27 - GDL - PYTHON
1 Solution

Accepted Solutions
Tamas Polyak
Graphisoft
Graphisoft

Hi Mathias,

 

You're correct: `anchorPoint` is not documented as output-only. I've checked in Archicad 29 and a bug still exists affecting both creation and modification when `useOwnOrigoAsAnchor == false`. This seems like it's a bug.

 

However, you should try a two-step workaround before resorting to Favorites:


For an existing Drawing already read into `element`, run these changes inside an undoable command:

API_Element mask {};
ACAPI_ELEMENT_MASK_SET (mask, API_DrawingType, anchorPoint);
ACAPI_ELEMENT_MASK_SET (mask, API_DrawingType, useOwnOrigoAsAnchor);

element.drawing.anchorPoint = APIAnc_RT;
element.drawing.useOwnOrigoAsAnchor = true;

GSErrCode err = ACAPI_Element_Change (
    &element, &mask, nullptr, 0, true);
if (err != NoError)
    return err;

ACAPI_ELEMENT_MASK_CLEAR (mask);
ACAPI_ELEMENT_MASK_SET (mask, API_DrawingType, useOwnOrigoAsAnchor);

element.drawing.useOwnOrigoAsAnchor = false;
err = ACAPI_Element_Change (&element, &mask, nullptr, 0, true);
if (err != NoError)
    return err;

return ACAPI_Element_Get (&element);

Crucially, exclude `anchorPoint` from the second mask.

 

Best regards,
Tamás

Go to post

3 Replies 3

A few follow-ups after more testing (Archicad 27, both via raw API calls and cross-checked with pixel measurements on exported layout images):

 

1. Correction to my own report above. I said calling ACAPI_Element_Change for an unrelated field also resets a UI-set anchor — that was wrong. Re-tested more carefully: changing only pos (the anchorPoint mask bit NOT set) leaves a UI-set anchor (e.g. "Center") completely intact. It's specifically setting the anchorPoint mask bit — even to the exact value it already had — that forces it back to APIAnc_LB. So the bug is narrower than I first described: it's isolated to writes that touch that one field, not Change in general.

 

2. This isn't Change-specific at all. The forced-APIAnc_LB behavior reproduces on the very first ACAPI_Element_Get immediately after ACAPI_Element_Create, with nothing else touching the element in between. So the requested anchorPoint is never honored by Create either — it's not a regression introduced by a later Change call.

 

3. A working anchor-independent alternative, for anyone hitting the same wall. API_DrawingType::offset (output-only, and unaffected by the anchorPoint bug) combined with drawingScale, ratio, angle, and the source view's own rotation gives a fully reliable way to compute where any model point lands on the layout:

paper = offset + drawingScale * ratio * R(angle + viewRotation) * modelPoint

Derived directly from the documented semantics of those fields (not fitted), then cross-checked against pixel-level measurements across zoomed-in, zoomed-out, and rotated views, with and without a saved zoom — residual under 1mm in every case, with no anchor term involved at all. Zoom state turned out to have no bearing on the mapping itself, only on which part of the model is captured.

 

4. A technical clue that might help narrow down the bug. useOwnOrigoAsAnchor (the other way to position a Drawing) does not have this problem — it writes, reads back, and persists correctly through unrelated Change calls. So whatever's broken seems isolated to the anchorPoint/box-anchor code path specifically, not Drawing placement in general. (It does have its own, separate quirk: giving position together with useOwnOrigoAsAnchor = true in the same Create call misapplies the position as -drawingScale*ratio*R(angle) * position — happy to open its own thread on that if it's useful, since it's unrelated to the anchor bug.)

 

5. One dead-end worth ruling out for others. I wondered if creating a Favorite from a Drawing already anchored via the UI, then placing new Drawings from that Favorite, might sidestep the bug (since it wouldn't go through the broken Change path). It doesn't: ACAPI_Favorite_Create succeeds on a Drawing, but every subsequent ACAPI_Favorite_Get on it fails (APIERR_GENERAL-class error), which also breaks ApplyFavoritesToElementDefaults/ApplyFavoritesToElements for it. So Drawing favorites are a dead end at the API level too, not just from the UI

Archicad 27 - GDL - PYTHON
Tamas Polyak
Graphisoft
Graphisoft

Hi Mathias,

 

You're correct: `anchorPoint` is not documented as output-only. I've checked in Archicad 29 and a bug still exists affecting both creation and modification when `useOwnOrigoAsAnchor == false`. This seems like it's a bug.

 

However, you should try a two-step workaround before resorting to Favorites:


For an existing Drawing already read into `element`, run these changes inside an undoable command:

API_Element mask {};
ACAPI_ELEMENT_MASK_SET (mask, API_DrawingType, anchorPoint);
ACAPI_ELEMENT_MASK_SET (mask, API_DrawingType, useOwnOrigoAsAnchor);

element.drawing.anchorPoint = APIAnc_RT;
element.drawing.useOwnOrigoAsAnchor = true;

GSErrCode err = ACAPI_Element_Change (
    &element, &mask, nullptr, 0, true);
if (err != NoError)
    return err;

ACAPI_ELEMENT_MASK_CLEAR (mask);
ACAPI_ELEMENT_MASK_SET (mask, API_DrawingType, useOwnOrigoAsAnchor);

element.drawing.useOwnOrigoAsAnchor = false;
err = ACAPI_Element_Change (&element, &mask, nullptr, 0, true);
if (err != NoError)
    return err;

return ACAPI_Element_Get (&element);

Crucially, exclude `anchorPoint` from the second mask.

 

Best regards,
Tamás

Hi Tamás,

 

Thanks for confirming the bug and the workaround — exactly matches what I found independently.

I've implemented it in the Tapir add-on's SetDetailsOfElements command for Drawings (same two-step ACAPI_Element_Change sequence you describe, with anchorPoint excluded from the second call's mask), tested it live in Archicad 29, and pushed it to the Tapir GitHub repo. It should land in the next released version of the add-on, so anyone using Tapir's JSON API will get reliable anchorPoint writes.

 

Appreciate the quick confirmation and the clean fix!

 

Best,
Mathias

Archicad 27 - GDL - PYTHON

Didn't find the answer?

Check other topics in this Forum

Back to Forum

Read the latest accepted solutions!

Accepted Solutions

Start a new conversation!

Video Thumbnail