GetVolume25DCollection

GetVolume25DCollection

mjovic
Contributor Contributor
1,113 Views
6 Replies
Message 1 of 7

GetVolume25DCollection

mjovic
Contributor
Contributor

Hi Forma Team,

In the internal version of our Forma addin we use getVolume25DCollection that you have under Forma.experimental.geometry. In the documentation you say: "Experimental APIs are subject to change at any time without notice" so I presume we can not use it in the production version of the addin application. Today I have checked the documentation again and I could not find getVolume25DCollection at all and we are a bit worried about that because this method is very useful for us. I am wondering are you planning to move the method somewhere or to remove it completely from the SDK ?

0 Likes
Accepted solutions (1)
1,114 Views
6 Replies
Replies (6)
Message 2 of 7

vilde.barth
Autodesk
Autodesk

Hi @mjovic ,

 

You are right that this API under Forma.experimental.geometry is now deprecated, but there is another way to get the geometry that you are looking for. 

You need to fetch the element and load the volume25DCollection representation of the element.

 

 

async function loadVolume25Collection(
  representation?: Representation<JsonRepresentations["volume25DCollection"]>,
): Promise<JsonRepresentations["volume25DCollection"] | undefined> {
  if (!representation) return undefined;
  switch (representation.type) {
    case "linked": {
      const data = await Forma.elements.blobs.get({ blobId: representation.blobId });
      return JSON.parse(
        new TextDecoder().decode(data.data),
      ) as JsonRepresentations["volume25DCollection"];
    }
    case "embedded-json":
      return representation.data;
    default:
      return;
  }
}

 

With the deprecated API, the geometry was returned with the position relative to the root. For the new API, the raw representation is loaded, so if your use case care about the position of the geometry relative to the proposal, you will need to apply the transformations from the element tree. Here is a code example:

 

    const { element, elements } = await Forma.elements.get({ urn })    
    const volume25DCollectionRep = element.representations?.volume25DCollection;
    const volume25DCollection = await loadVolume25Collection(volume25DCollectionRep)!;
    if (!volume25DCollection) continue;

    const { transform } = await Forma.elements.getWorldTransform({ path });
    const selectionPredicate = createSelectionPredicate(volume25DCollectionRep?.selection);
    const filteredVolume25DCollection = volume25DCollection.features.filter((f) =>
      selectionPredicate(f.id),
    );

    const transformedVolume25DCollection = {
      type: "FeatureCollection" as const,
      features: filteredVolume25DCollection.map((feature: Volume25D) => {
        return {
          ...feature,
          properties: {
            ...feature.properties,
            // Scale height by 3rd diagonal element in transform matrix
            height: feature.properties.height * transform[10],
            // Translate and scale elevation -- default untransformed elevation is zero
            elevation: (feature.properties.elevation ?? 0 * transform[10]) + transform[14],
          },
          geometry: {
            ...feature.geometry,
            coordinates: feature.geometry.coordinates.map((coordinates) =>
              transformCoordinates(transform, coordinates),
            ),
          },
        };
      }),
    };

 

 Using the helper functions: 

 

export function transformCoordinates(mat1: number[], coordinates: number[][]) {
  const res = Array<[number, number]>(coordinates.length);
  let i, j, k;
  for (k = 0; k < coordinates.length; k++) {
    const resItem: [number, number] = [0, 0];
    const point = [...(coordinates[k] as [number, number]), 0, 1];
    for (i = 0; i < 4; i++) {
      for (j = 0; j < 2; j++) {
        resItem[j] += mat1[i * 4 + j]! * point[i]!;
      }
    }
    res[k] = resItem;
  }
  return res;
}

function createSelectionPredicate(selection?: RepresentationSelection) {
  switch (selection?.type) {
    case undefined:
      return () => true;
    case "equals":
      return (value: string) => value === selection.value;
    case "startsWith":
      return (value: string) => value.startsWith(selection.value);
    default:
      throw new Error(`Invalid selection: ${JSON.stringify(selection ?? {})}`);
  }
}

 

I hope this solves your use case, if not, let me know!

Best regards,

Vilde from the Forma team

0 Likes
Message 3 of 7

mjovic
Contributor
Contributor

Hi Vilde thank you very much for your answer. At the moment my solution is to replace GetVolume25DCollection with  

GrossFloorAreaPolygons and then I apply the world transform. This seems to resolve most of my issues. The only thing is that in Volume25D.properties I had height value and I don't have it here (in GrossFloorAreaPolygons). I understand that I can iterate through the elements and take the differences between the levels but it wont work for the last element because I have only the floors elevations. I will try to sort it out somehow - don't think it's a big issue. Also I see in your answer you use Volume25D and that also seems to be obsolete as I can not find it in the documentation anymore.
0 Likes
Message 4 of 7

mjovic
Contributor
Contributor

Hi Vilde, sorry for the late answer but I have just noticed that I have responded to myself accidentally 🙂 thank you very much for your answer. At the moment my solution is to replace GetVolume25DCollection with  

GrossFloorAreaPolygons and then I apply the world transform. This seems to resolve most of my issues. The only thing is that in Volume25D.properties I had height value and I don't have it here (in GrossFloorAreaPolygons). I understand that I can iterate through the elements and take the differences between the levels but it wont work for the last element because I have only the floors elevations. I will try to sort it out somehow - don't think it's a big issue. Also I see in your answer you use Volume25D and that also seems to be obsolete as I can not find it in the documentation anymore.
0 Likes
Message 5 of 7

vilde.barth
Autodesk
Autodesk
Accepted solution

Hi again!
I believe this is the type you are looking for is: Volume25DCollection? 

This is available under det element API, by fetching the element representation: element.representations.volume25DCollection.

Let me know if this does not solve your problem.

Best, Vilde

0 Likes
Message 6 of 7

mjovic
Contributor
Contributor

Hi Vilde sorry I just see this message now 🙂 Yes I have solved that issue but there is one more thing. I have noticed that sometimes if I try to get gross flor area polygon I am getting this error: 

mjovic_0-1730460251291.png

Is there any workaround for this? How to get that data if there is no representation or no gross floor are polygon? Many thanks for your help.

0 Likes
Message 7 of 7

vilde.barth
Autodesk
Autodesk

Hi @mjovic,
An element may have one or more representations, but not necessary all the representations described in the documentation. You can read more about the element system and representations here.

In order to see what representations that is available for an element, you can look into the keys in the representations part of the element (element.representations). 

If your use case require a certain representation, you might want to communicate to the user which elements that are supported and not.

Hope this was helping! 

Best regards, Vilde

0 Likes