// ///@ts-check
/// <reference path="../tools/Authenticate.js" />
/**
* $Id: AdapterColneoPro.js 9671 2026-01-07 15:52:16Z jochen.hanff $
*/
'use strict'
import { IModelViewer , ProjectContext } from "./IModelViewer.js";
import { ApiResponse } from "../tools/ApiResponse.js";
import { AuthenticationServices } from "../tools/Authenticate.js";
////////////////////////////////////////////////////////
/// COLNEO pro
////////////////////////////////////////////////////////
/**
*
* @category Model Viewer
*
* @extends {IModelViewer}
*
*/
export class AdptCOLNEOpro_10 extends IModelViewer {
constructor() {
super( "COLNEOpro_10", "COLNEO pro", "1.0.1" )
cnCoreAPI.selectionStateChanged.connect(this.onSelectionChanged.bind(this));
cnCoreAPI.visibilityStateChanged.connect(this.onVisibilityChanged.bind(this));
}
/**
*
* @param {*} cb Call Back
* returns : {
* }
* @param {*} user
*/
loginUser__idp( cb , user = null ) {
console.log( '### <AdptCOLNEOpro_10.loginUser> ')
/////////////////////////////////////////
cnApplicationAPI.getUser((ret_user) => {
// console.log("ret user:")
// console.log(JSON.stringify(ret_user))
if (ret_user.status < 300) {
this.setAccessToken( ret_user , (ret_accesstoken) => {
return cb({
'status': ret_accesstoken.status,
'data': ret_accesstoken
})
})
} else {
const urlParams = new URLSearchParams(window.location.search);
const authcode = urlParams.get('authcode');
const user = urlParams.get('user');
if (authcode != undefined && authcode.length > 0) {
console.log("GOT AUTHCODE")
cnApplicationAPI.loginUser(user, authcode, (ret_login) => {
console.log("=> logged in")
cnApplicationAPI.getUser((ret_user) => {
this.setAccessToken(ret_user, (ret_accesstoken) => {
return cb({
'status': ret_accesstoken.status,
'data': ret_accesstoken
})
})
})
})
} else {
const l = window.location
// window.location = `https://idp.colneo.services/cnapp_login?redirect=${l}&uselocalstorage=false&user=jochen.hanff@colneo.email`
let qu = ''
if( user ) {
qu = `&user=${qu}`
}
window.location = `https://idp.colneo.services/cnapp_login?redirect=${l}&uselocalstorage=false${qu}`
}
}
})
}
/**
*
* Get user,token
* Uses 'old' IAM login for now.
*
* returns {
* 'status' :
* 'data' : {
* 'user' : " ... "
* 'token' : " ... "
* }
* }
*
* @param {*} cb
* @param {*} user
*
*/
async loginUser( cb, user = null) {
// Check if user already logged in with COLNEO pro.
// If not, use cn_login
// will be changed later to -> IDP cnapp_login
cnApplicationAPI.getUser( async (ret_user) => {
// console.log("ret user from app:")
// console.log(JSON.stringify(ret_user))
if (ret_user.status < 300) {
// console.log("=> GOT USER")
let u = ret_user.data.userid
let rt = await cnApplicationAPI.getAccessToken()
// console.log("RET TOKEN:")
// console.log( JSON.stringify(rt) )
let ret_iam_t = await AuthenticationServices.login_IAM( u , rt.data )
let iam_t = ret_iam_t.data
// console.log("RESPONSE IAM LOGIN")
// console.log( JSON.stringify(ret_iam_t) )
return cb({
'status': 200,
'data': {
'userid' : u,
'token' : iam_t.token
}
})
} else {
let url = window.location // .href
let auth_target_ = new URL(url.protocol + url.host + "/cn_login")
console.log(`auth : ${auth_target_}`)
//
// check if user and token are stored in local storage
// if so, return user/token, otherwise forward to
// webpage ./cn_login
let u = window.localStorage.getItem('user')
let t = window.localStorage.getItem('token')
if (user != undefined) {
if (u != user) {
t = null
}
u = user
}
if (t == undefined) {
let queryString = window.location.search;
let urlParams = new URLSearchParams(queryString);
urlParams.set('redirect', window.location) // window.location.href ???
if (typeof _default_userid_ != 'undefined') {
urlParams.set('userid', _default_userid_) // window.location.href ???
}
let target = auth_target_
target.search = urlParams.toString()
window.location = target
} else {
cnApplicationAPI.loginUser(u, t, async (ret) => {
// alert('loggedin')
return cb({
'status': 200,
'data': {
'userid': u,
'token' : t
}
})
})
}
}
})
}
logoutUser( cb ) {
console.log("LOGOUT")
cnApplicationAPI.logoutUser() //aab causing issue function not found in colneo pro
window.localStorage.removeItem('token')
window.localStorage.removeItem('user')
// window.location.reload()
window.location.replace(window.location.origin + window.location.pathname);
return cb({
'status' : 200
})
}
/**
*
* @param {Context} context
* @param {*} cb
*/
async restoreProjectContext( context, cb ) {
const is = await cnProjectAPI.getInfohubSettings()
if ( is.status < 300 ) {
const scope = is.data.scope_id
const project_sid = is.data.project_shortid
const connectedby = is.data.connected_by
this._infohub_project_ctx.setScopeProject( scope, project_sid , connectedby );
context.setScopeAndProjectShortId( scope, project_sid )
return cb({
'status': 200,
'data': this._infohub_project_ctx
})
} else {
return cb({
'status' : is.status
})
}
}
async resetProjectContext( context , cb ) {
return cb({
'status': 200,
'data': this._infohub_project_ctx
})
}
/**
* @since 2025-10-14, aab
*/
setInfohubSettings( settings ) {
return cnProjectAPI.setInfohubSettings(settings)
}
/**
* @since 2025-10-14, aab
*/
getInfohubSettings( ) {
return cnProjectAPI.getInfohubSettings()
}
// ======== Project Methods ========
/**
* @since 2025-12-02, SW
*/
getProjectId() {
return cnProjectAPI.getInfo("id").then(result => {
return new ApiResponse( result.status, result.data?.id || null, result.message );
});
}
getProjectDirectory() {
return cnProjectAPI.getInfo().then(result => {
return new ApiResponse( result.status, result.data?.filePath || null, result.message );
});
}
getProjectInfo() {
return cnProjectAPI.getInfo().then(result => {
return new ApiResponse( result.status, result.data || null, result.message );
});
}
/**
*
* @param {*} ret_user
* @param {*} cb
*
*/
setAccessToken( ret_user , cb ) {
cnApplicationAPI.getAccessToken((ret_token) => {
console.log("RET TOKEN")
console.log(JSON.stringify(ret_token))
if (ret_token.status < 300) {
return cb(()=>{
let r = new ApiResponse(200,null, "Access granted")
r.token = ret_token.data
r.userid = ret_user.data.userid
r.avatar = ret_user.data.avatar
r.name = ret_user.data.name
return r;
})
} else {
return cb(
new ApiResponse(ret_token.status, null, "Access denied")
)
}
})
}
/**
*
* Open URL/Link in external browser or in webform module
*
* @param {*} url
* @param {*} target
*/
openUrl(url, target = '') {
// target empty uses the default browser
return cnGuiAPI.openUrl(url, target || '');
}
getSelectedObjectIds(domains) {
return cnCoreAPI.getSelectedObjectIds( domains )
}
setSelected(objIds, flagOnOff, exclusively) {
return cnCoreAPI.setSelected( objIds, flagOnOff, exclusively )
}
setAllSelected( domains, flagOnOff ) {
return cnCoreAPI.getObjectIds( domains ).then((result) => {
return cnCoreAPI.setSelected( result.data, flagOnOff, false ).then(function (result_set) {
return result_set
})
})
}
getObjectsRootId(domain) {
return cnCoreAPI.getObjectsRootId( domain )
}
getObjects(objIdList, opt ) {
return cnCoreAPI.getObjects(objIdList, opt )
}
getObjectIds(domains) {
return cnCoreAPI.getObjectIds(domains)
}
/**
* Collect ids of contained objects in object list 'objIdList'
*
* @param {*} objIdList
* @param {*} depth
*/
async getChildIds(objIdList, depth = 0) {
let s = new Set()
for (const id of objIdList) {
const cids = (await cnCoreAPI.getChildIds(id, depth)).data
for (const cid of cids) {
s.add(cid);
}
}
return new ApiResponse(200, [...s]);
}
filterObjectsByProperties( objIds, filterExpression) {
return cnCoreAPI.filterObjectsByProperties(objIds,filterExpression)
}
filterObjectsByStatus(objIds, statusCode, statusFlag) {
return cnCoreAPI.filterObjectsByStatus(objIds, statusCode, statusFlag)
}
// ======== Visibility ========
setVisible(objIds, flagOnOff, exclusively) {
return cnCoreAPI.setVisible( objIds , flagOnOff , exclusively )
}
setAllVisible( domains, flagOnOff ) {
return cnCoreAPI.getObjectIds( domains ).then((result) => {
return cnCoreAPI.setVisible( result.data, flagOnOff, false )
})
}
// ======== Viewpoint Methods ========
async showHomeViewpoint() {
return cnView3dAPI.getHomeViewpointId().then( (result) => {
console.log( `home : ${JSON.stringify(result)}`)
return cnView3dAPI.activateViewpoint(result.data).then(function (result_activate) {
return result_activate;
})
})
}
// ======== Styles ========
async resetStyles( domains ) {
return cnCoreAPI.getObjectIds( domains ).then((result) => {
return cnCoreAPI.resetStyles(result).then(function (result_reset) {
return result_reset // .data;
})
})
}
applyStyleToObjects( styleId , objectIds ) {
return cnCoreAPI.applyStyle( styleId , objectIds )
}
createStyle( styleDef ) {
return cnCoreAPI.createStyle( styleDef )
}
getSmartSetsRootId(domain) {
return cnCoreAPI.getSmartSetsRootId( domain )
}
createSmartSet( parentId, name, objectIds, options = null ) {
return cnCoreAPI.createSmartSet( parentId, name, objectIds, options )
}
createSmartSetsFromSchema(schema) {
return cnCoreAPI.createSmartSetsFromSchema( schema )
}
// === Properties ===
getPropertyValue(objId, ptKeyStr) {
return cnCoreAPI.getPropertyValue(objId, ptKeyStr)
}
getPropertyValues(objIds, ptKeyStr) {
return cnCoreAPI.getPropertyValues(objIds, ptKeyStr)
}
getPropertyTypeValues(ptKeyStr, options){
return cnCoreAPI.getPropertyTypeValues(ptKeyStr, options)
}
getVisibleObjectIds(domains) {
return cnCoreAPI.getVisibleObjectIds(domains)
}
setPropertyValue(objId, ptKeyStr, value) {
return cnCoreAPI.setPropertyValue(objId, ptKeyStr, value)
}
setProperties(objIds, propertyMap) {
return cnCoreAPI.setProperties( objIds, propertyMap )
}
setPropertiesByMap( propertyMap ) {
return cnCoreAPI.setPropertiesByObjectMap( propertyMap )
}
deletePropertyType(ptKeyStr) {
return cnCoreAPI.deletePropertyType(ptKeyStr)
}
// GEOMETRY
async transformObject( id , T , includeContained ) {
console.error(`ERROR in ${this.apiName}.openUrl(): No model viewer instantiated.`)
return Promise.reject("No model viewer instantiated");
}
// === TOOLS ====
async calcOptOBB(objIds) {
return cnCoreAPI.calculateMinimalOBB( objIds )
}
async checkOverlapObjects(id1, id2) {
return cnToolsAPI.checkOverlapOBB( id1, id2 ).then( (result) => {
const maxOverlap = Math.max( result.data.coverage_obb1, result.data.coverage_obb2 );
return new ApiResponse( result.status, maxOverlap, result.message );
})
}
async checkOverlapObjectList(idList, overlapAllowed = 0.1, statusCallback = null) {
if(idList.length < 2) {
console.log("Need at least two object ids to check overlap.");
return new ApiResponse(400, null, "Need at least two object ids to check overlap.");
}
// calc obbs
const resOBBcalc = await cnCoreAPI.calculateMinimalOBB(idList);
if(resOBBcalc.status > 201) {
console.log("Error calculating OBBs: " + resOBBcalc.message);
return new ApiResponse(resOBBcalc.status, null, "Error calculating OBBs: " + resOBBcalc.message);
}
if(resOBBcalc.data < 2) {
console.log("Need at least two objects with geometry to check overlap.");
return new ApiResponse(400, null, "Need at least two objects with geometry to check overlap.");
}
if(statusCallback) {
statusCallback({
status: 'OBBs calculated for objects. Starting overlap checks...',
progress: 0.1
});
}
// cnToolsAPI.checkOverlapOBB(idList[0], id)
// get obbs
// this way we can avoid calculating objects without obb --> faster
const resOBB = await cnCoreAPI.getPropertyValues(idList, 'cnOOBB##xs:object');
if(resOBB.status !== 200) {
console.log("Error getting property [cnOOBB##xs:object]: " + resOBB.message);
return new ApiResponse(resOBB.status, null, "Error getting property [cnOOBB##xs:object]: " + resOBB.message);
}
let obbs = resOBB.data;
// let tolerance = overlapAllowed; // 10cm tolerance
// let matchedObjPairs = new Set();
let matchedObjPairs = []
let start = Date.now()
const totalNoOfChecks = (idList.length * idList.length - idList.length) / 2; // half matrix under main diagonal
let checkCounter = 0;
const callbacks = 50; // number of progress callbacks during entire check
const stepsSize = Math.max(1, Math.floor(totalNoOfChecks / callbacks));
// const appInfo = await cnApplicationAPI.getInfo();
// const builddate = Date(appInfo.data.buildDate);
// let useOldFunctionName = false;
// if(builddate < new Date('2025-12-12')) useOldFunctionName = true;
// compare each obb with the others
for(let i=0; i<idList.length; i++) {
const id1 = idList[i];
const obb1 = obbs[id1].value;
// no obb, no check
if(obb1 == null || obb1 == {}) {
// console.log(`No OBB for object ${id1}, skipping overlap check.`);
checkCounter += (idList.length - i); // skip all checks for this object
continue;
}
for(let k=i+1; k<idList.length; k++) {
const id2 = idList[k];
const obb2 = obbs[id2].value;
checkCounter++;
// no obb, no check
if(obb2 == null || obb2 == {}) {
// console.log(`No OBB for object ${id2}, skipping overlap check.`);
continue;
}
const resOverlap = await cnToolsAPI.checkOverlapObjects( id1, id2 );
// progress callback only every callbacks times
if(statusCallback && (checkCounter % stepsSize == 0)) {
statusCallback({
status: 'Checking overlap between objects ' + id1 + ' and ' + id2,
progress: 0.1 + 0.9 * ( (checkCounter) / totalNoOfChecks )
});
}
// const resOverlap = await cnToolsAPI.checkOverlapOBB( obb1, obb2 );
// console.log(`Overlap check between ${id1} and ${id2} took ${Date.now() - start} ms.`);
// console.log(`Result: ${resOverlap.status}`);
if(resOverlap.status == 200) { // could calculate an overlap
if( resOverlap.data.overlap && (
resOverlap.data.coverage_obb1 > overlapAllowed
|| resOverlap.data.coverage_obb2 > overlapAllowed ) ) {
// matchedObjPairs.add( [id1 , id2] );
// console.log(`Overlap detected between ${id1} and ${id2}`);
matchedObjPairs.push( {
id1: id1,
id2: id2,
maxOverlap: Math.max(resOverlap.data.coverage_obb1, resOverlap.data.coverage_obb2)
} );
}
}
//////////// BUGFIX ar 2025-11-26, function is not working properly
// const resOverlap = cnToolsAPI.checkOverlapOBB(obb1, obb2);
/// BUGFIX, calculate it manually here:
// if((Math.abs(obb1.o[0] - obb2.o[0])) < tolerance
// && (Math.abs(obb1.o[1] - obb2.o[1])) < tolerance
// && (Math.abs(obb1.o[2] - obb2.o[2])) < tolerance
// && (Math.abs(obb1.v1[0] - obb2.v1[0])) < tolerance
// && (Math.abs(obb1.v1[1] - obb2.v1[1])) < tolerance
// && (Math.abs(obb1.v1[2] - obb2.v1[2])) < tolerance
// && (Math.abs(obb1.v2[0] - obb2.v2[0])) < tolerance
// && (Math.abs(obb1.v2[1] - obb2.v2[1])) < tolerance
// && (Math.abs(obb1.v2[2] - obb2.v2[2])) < tolerance
// && (Math.abs(obb1.v3[0] - obb2.v3[0])) < tolerance
// && (Math.abs(obb1.v3[1] - obb2.v3[1])) < tolerance
// && (Math.abs(obb1.v3[2] - obb2.v3[2])) < tolerance) {
// console.log(`Overlap detected between ${id1} and ${id2}`);
// matchedObjects.add( [id1 , id2] );
// }
/////////// BUGFIX END calculate manually
}
}
console.log(`Overlap check took ${Date.now() - start} ms.`);
// postprocess matched pairs
// let matchedList = []; // list of pairs, triplets, ...
// matchedObjPairs.forEach( pair => {
// // if matched list does not contain either id of pair apend pair as new entry
// let found = false;
// for( let i=0; i<matchedList.length; i++ ) {
// let entry = matchedList[i];
// if( entry.indexOf( pair[0] ) > -1){
// // append id2 to this entry
// if( entry.indexOf( pair[1] ) == -1 ) {
// entry.push( pair[1] );
// }
// found = true;
// break;
// } else if( entry.indexOf( pair[1] ) > -1 ) {
// // append id1 to this entry
// if( entry.indexOf( pair[0] ) == -1 ) {
// entry.push( pair[0] );
// }
// found = true;
// break;
// }
// }
// if(!found) {
// matchedList.push( pair );
// }
// });
// console.log("Overlap check completed. Overlapping groups found: " + matchedList.length);
// console.log(JSON.stringify(matchedList));
return new ApiResponse(200, matchedObjPairs, `Overlap check completed. ${matchedObjPairs.length} overlapping groups found.`);
}
setDrawEdges(onOff) {
return cnView3dAPI.getConfig().then( (result) => {
let cfg = result.data;
cfg.edges.enabled = onOff;
return cnView3dAPI.setConfig(cfg).then( (result_set) => {
return result_set;
} );
})
}
getDrawEdges() {
return cnView3dAPI.getConfig().then( (result) => {
let cfg = result.data;
return new ApiResponse(200, cfg.edges.enabled, "Draw edges mode retrieved");
})
}
}
/**
*
* @category Model Viewer
*
*/
export class COLNEOproAdapterServices {
constructor() {
}
/**
* Create instance of COLNEO pro API class
*
* ```js
* const { COLNEOproAdapterServices } = await import("./node_modules/@colneo/infohub-js-api/dist/adapter/AdapterColneoPro.js");
* Infohub.ModelViewer = await COLNEOproAdapterServices.createAdapter()
* ```
*
* @returns {Promise<IModelViewer>} Model Viewer instance
*
*/
static async createAdapter() {
return new AdptCOLNEOpro_10();
}
}
Source