UNPKG

gs-modelling

Version:

A set of 3D modelling functions for gs-JSON.

438 lines (418 loc) 19.4 kB
/** * Objects are a type of entity. They consist of conics, polylines, polymeshes, planes and rays. * * Objects are formed by a combination of topologies. More information can be found on the page for topo. */ import * as gs from "gs-json"; import * as three from "three"; import * as error from "./_error_msgs_dev"; import * as threex from "./libs/threex/threex" // =============================================================================================================== // Object Get ==================================================================================================== // =============================================================================================================== /** * Gets an object from the model * @param model Model to get object from * @param id ID of object to get * @returns An object. Null if object does not exist. */ export function Get(model: gs.IModel, id: number): gs.IObj { const obj: gs.IObj = error.checkObjID(model, id); switch (obj.getObjType()) { case gs.EObjType.ray: return obj as gs.IRay; case gs.EObjType.plane: return obj as gs.IPlane; case gs.EObjType.circle: return obj as gs.ICircle; case gs.EObjType.ellipse: return obj as gs.IEllipse; case gs.EObjType.polyline: return obj as gs.IPolyline; case gs.EObjType.polymesh: return obj as gs.IPolymesh; default: throw new Error("Object type not found: " + obj.getObjType()); } } /** * Gets a list of objects from the model. * @param model Model to get objects from. * @param ids A point ID or list of point IDs, integer numbers. If null, then all objects are returned. * @returns A list of objects. */ export function Gets(model: gs.IModel, ids?: number | number[]): gs.IObj[] { if (ids === undefined || ids === null) {return model.getGeom().getAllObjs();} if (!Array.isArray(ids)) {ids = [ids];} let objs: gs.IObj[] = []; for (const id of ids) { const obj: gs.IObj = Get(model, id); if (obj !== null) {objs.push(obj);} } return objs; } /** * Gets all the objects from a group. * @param model Model to get the objects from. * @param group_name The group name. * @returns List of objects. */ export function GetFromGroup(model: gs.IModel, group_name: string): gs.IObj[] { const group: gs.IGroup = error.checkGroup(model, group_name); return group.getObjs(); } // =============================================================================================================== // Object Constructors =========================================================================================== // =============================================================================================================== // =============================================================================================================== // Object Functions ============================================================================================== // =============================================================================================================== /** * Moves objects by a translation vector. * * @param objs An object or a list of objects. * @param vector Translation vector. * @param copy If true, objects are copied before being moved. * @returns The moved objects. */ export function move(objs: gs.IObj | gs.IObj[], vector: gs.XYZ, copy: boolean = false): gs.IObj | gs.IObj[] { const is_array: boolean = Array.isArray(objs); if (!Array.isArray(objs)) {objs = [objs];} const model: gs.IModel = error.checkObjList(objs, 1); error.checkXYZ(vector); // translation matrix const matrix_trn: three.Matrix4 = new three.Matrix4(); matrix_trn.makeTranslation(vector[0], vector[1], vector[2]); // copy the objs if (copy) {objs = model.getGeom().copyObjs(objs, true); } // do the xform model.getGeom().xformObjs(objs, matrix_trn); // return either a single obj or array of objs if (is_array) {return objs;} return objs[0]; } /** * Rotates object or a list of objects around an axis. * * @param objs An object or a list of objects. * @param origin An point on the axis, can be either a list of three numbers or a point. * @param axis An xyz vector along the axis. * @param angle The angle, in degrees, between 0 and 360. * @param copy If true, objects are copied before being rotated. * @returns The rotated objects. */ export function rotate(objs: gs.IObj | gs.IObj[], origin: gs.XYZ|gs.IPoint, axis: gs.XYZ, angle: number, copy: boolean = false): gs.IObj | gs.IObj[] { const is_array: boolean = Array.isArray(objs); if (!Array.isArray(objs)) {objs = [objs];} const model: gs.IModel = error.checkObjList(objs, 1); let origin_xyz: gs.XYZ; if (origin instanceof gs.Point) { origin_xyz = origin.getPosition(); } else { origin_xyz = origin as gs.XYZ; error.checkXYZ(origin_xyz); } error.checkXYZ(axis); const angle_rad: number = (angle / 180) * Math.PI; // rotation matrix const matrix_rot: three.Matrix4 = new three.Matrix4(); matrix_rot.makeRotationAxis(new three.Vector3(...axis), angle_rad); // translation matrix const matrix_trn1: three.Matrix4 = new three.Matrix4(); matrix_trn1.makeTranslation(-origin_xyz[0], -origin_xyz[1], -origin_xyz[2]); const matrix_trn2: three.Matrix4 = new three.Matrix4(); matrix_trn2.makeTranslation(origin_xyz[0], origin_xyz[1], origin_xyz[2]); // copy objects if (copy) {objs = model.getGeom().copyObjs(objs, true); } // do the xform model.getGeom().xformObjs(objs, matrix_trn2.multiply(matrix_rot.multiply(matrix_trn1))); // return the result, either single obj or array if (is_array) {return objs;} return objs[0]; } /** * Scales an object or a list of objects relative to an origin point. * The scale factor is specified by three vales, for scaling in x, y, and z. * Primitive objects, such as circles and arcs, can only be scaled uniformly. * * @param objs An object or a list of objects. * @param origin An origin point of the scale, can be either a list of three numbers or a point. * @param factor The scale factor, along the x, y and z axes. * @param copy If true, objects are copied before being scaled. * @returns The scaled objects. */ export function scale(objs: gs.IObj | gs.IObj[], origin: gs.XYZ|gs.IPoint, factor: gs.XYZ, copy: boolean = false): gs.IObj | gs.IObj[] { const is_array: boolean = Array.isArray(objs); if (!Array.isArray(objs)) {objs = [objs];} const model: gs.IModel = error.checkObjList(objs, 1); let origin_xyz: gs.XYZ; if (origin instanceof gs.Point) { origin_xyz = origin.getPosition(); } else { origin_xyz = origin as gs.XYZ; error.checkXYZ(origin_xyz); } error.checkXYZ(factor); // scale matrix const matrix_scale: three.Matrix4 = new three.Matrix4(); matrix_scale.makeScale(factor[0], factor[1], factor[2]); // translation matrix const matrix_trn1: three.Matrix4 = new three.Matrix4(); matrix_trn1.makeTranslation(-origin_xyz[0], -origin_xyz[1], -origin_xyz[2]); const matrix_trn2: three.Matrix4 = new three.Matrix4(); matrix_trn2.makeTranslation(origin_xyz[0], origin_xyz[1], origin_xyz[2]); // copy objects if (copy) {objs = model.getGeom().copyObjs(objs, true); } // do the xform model.getGeom().xformObjs(objs, matrix_trn2.multiply(matrix_scale.multiply(matrix_trn1))); // return the result, either single obj or array if (is_array) {return objs;} return objs[0]; } /** * Transforms an object or list of objects to a target coordinate system (CS). * The source CS is assumed to be the Global Coordinate System (GCS). * The target coordinate system is specified by an origin, * a vector parallel to the x axis, and a vector in the xy plane (not parallel to the x axis). * * @param objs An object or a list of objects. * @param target_origin The origin point of the target coordinate system, can be either a list of three numbers or a point. * @param target_vec_x A vector parallel to the target x axis. * @param target_vec A vector in the target xy plane (not paralle to the x axis). * @param copy If true, objects are copied before being scaled. * @returns The transformed objects. */ export function xformGcs2Lcs(objs: gs.IObj | gs.IObj[], target_origin: gs.XYZ|gs.IPoint, target_vec_x: gs.XYZ, target_vec: gs.XYZ, copy: boolean = false): gs.IObj | gs.IObj[] { const is_array: boolean = Array.isArray(objs); if (!Array.isArray(objs)) {objs = [objs];} const model: gs.IModel = error.checkObjList(objs, 1); let target_origin_xyz: gs.XYZ; if (target_origin instanceof gs.Point) { target_origin_xyz = target_origin.getPosition(); } else { target_origin_xyz = target_origin as gs.XYZ; error.checkXYZ(target_origin_xyz); } error.checkXYZ(target_vec_x); error.checkXYZ(target_vec); // matrix to xform from source to gcs, then from gcs to target const matrix_gcs_to_target: three.Matrix4 = threex.xformMatrixFromXYZVectors( target_origin_xyz, target_vec_x, target_vec, false); // copy objects if (copy) {objs = model.getGeom().copyObjs(objs, true); } // do the xform model.getGeom().xformObjs(objs, matrix_gcs_to_target); // return the result, either single obj or array if (is_array) {return objs;} return objs[0]; } /** * Transforms an object or list of objects from a source local coordinate system (LCS) * to the global coordinate system (GCS). * The source coordinate system is specified by an origin, * a vector parallel to the x axis, and a vector in the xy plane (not parallel to the x axis). * * @param objs An object or a list of objects. * @param source_origin The origin point of the source coordinate system, can be either a list of three numbers or a point. * @param source_vec_x A vector parallel to the source x axis. * @param source_vec A vector in the source xy plane (not paralle to the x axis). * @param copy If true, objects are copied before being scaled. * @returns The transformed objects. */ export function xformLcs2Gcs(objs: gs.IObj | gs.IObj[], source_origin: gs.XYZ|gs.IPoint, source_vec_x: gs.XYZ, source_vec: gs.XYZ, copy: boolean = false): gs.IObj | gs.IObj[] { const is_array: boolean = Array.isArray(objs); if (!Array.isArray(objs)) {objs = [objs];} const model: gs.IModel = error.checkObjList(objs, 1); let source_origin_xyz: gs.XYZ; if (source_origin instanceof gs.Point) { source_origin_xyz = source_origin.getPosition(); } else { source_origin_xyz = source_origin as gs.XYZ; error.checkXYZ(source_origin_xyz); } error.checkXYZ(source_vec_x); error.checkXYZ(source_vec); // matrix to xform from source to gcs, then from gcs to target const matrix_source_to_gcs: three.Matrix4 = threex.xformMatrixFromXYZVectors( source_origin_xyz, source_vec_x, source_vec, true); // copy objects if (copy) {objs = model.getGeom().copyObjs(objs, true); } // do the xform model.getGeom().xformObjs(objs, matrix_source_to_gcs); // return the result, either single obj or array if (is_array) {return objs;} return objs[0]; } /** * Transforms an object or list of objects from a source to a target local coordinate system (LCS). * Each coordinate system is specified by an origin, * a vector parallel to the x axis, and a vector in the xy plane (not parallel to the x axis). * * @param objs An object or a list of objects. * @param source_origin The origin point of the source coordinate system, can be either a list of three numbers or a point. * @param source_vec_x A vector parallel to the source x axis. * @param source_vec A vector in the source xy plane (not paralle to the x axis). * @param target_origin The origin point of the target coordinate system, can be either a list of three numbers or a point. * @param target_vec_x A vector parallel to the target x axis. * @param target_vec A vector in the target xy plane (not paralle to the x axis). * @param copy If true, objects are copied before being scaled. * @returns The transformed objects. */ export function xformLcs2Lcs(objs: gs.IObj | gs.IObj[], source_origin: gs.XYZ|gs.IPoint, source_vec_x: gs.XYZ, source_vec: gs.XYZ, target_origin: gs.XYZ|gs.IPoint, target_vec_x: gs.XYZ, target_vec: gs.XYZ, copy: boolean = false): gs.IObj | gs.IObj[] { const is_array: boolean = Array.isArray(objs); if (!Array.isArray(objs)) {objs = [objs];} const model: gs.IModel = error.checkObjList(objs, 1); let source_origin_xyz: gs.XYZ; if (source_origin instanceof gs.Point) { source_origin_xyz = source_origin.getPosition(); } else { source_origin_xyz = source_origin as gs.XYZ; error.checkXYZ(source_origin_xyz); } error.checkXYZ(source_vec_x); error.checkXYZ(source_vec); let target_origin_xyz: gs.XYZ; if (target_origin instanceof gs.Point) { target_origin_xyz = target_origin.getPosition(); } else { target_origin_xyz = target_origin as gs.XYZ; error.checkXYZ(target_origin_xyz); } error.checkXYZ(target_vec_x); error.checkXYZ(target_vec); // matrix to xform from source to gcs, then from gcs to target const matrix_source_to_gcs: three.Matrix4 = threex.xformMatrixFromXYZVectors( source_origin_xyz, source_vec_x, source_vec, true); const matrix_gcs_to_target: three.Matrix4 = threex.xformMatrixFromXYZVectors( target_origin_xyz, target_vec_x, target_vec, false); // copy objects if (copy) {objs = model.getGeom().copyObjs(objs, true); } // do the xform model.getGeom().xformObjs(objs, matrix_gcs_to_target.multiply(matrix_source_to_gcs)); // return the result, either single obj or array if (is_array) {return objs;} return objs[0]; } /** * Mirrors an object or a list of objects in a mirror plane. * The plane is defined by a point and a normal vector. * * @param objs An object or a list of objects. * @param origin An origin point on the mirror plane, can be either a list of three numbers or a point. * @param normal The normal vector of the mirror plane, a list of three numbers. * @param copy If true, objects are copied before being scaled. * @returns The scaled objects. */ export function mirror(objs: gs.IObj | gs.IObj[], origin: gs.XYZ|gs.IPoint, normal: gs.XYZ, copy: boolean = false): gs.IObj | gs.IObj[] { const is_array: boolean = Array.isArray(objs); if (!Array.isArray(objs)) {objs = [objs];} const model: gs.IModel = error.checkObjList(objs, 1); let origin_xyz: gs.XYZ; if (origin instanceof gs.Point) { origin_xyz = origin.getPosition(); } else { origin_xyz = origin as gs.XYZ; error.checkXYZ(origin_xyz); } error.checkXYZ(normal); // plane normal const [a,b,c]: number[] = new three.Vector3(...normal).normalize().toArray(); // mirror matrix const matrix_mirror: three.Matrix4 = new three.Matrix4(); matrix_mirror.set( 1 - (2 * a * a), -2 * a * b, -2 * a * c, 0, -2 * a * b, 1 - (2 * b * b), -2 * b * c, 0, -2 * a * c, -2 * b * c, 1 - (2 * c * c), 0, 0, 0, 0, 1 ); // translation matrix const matrix_trn1: three.Matrix4 = new three.Matrix4(); matrix_trn1.makeTranslation(-origin_xyz[0], -origin_xyz[1], -origin_xyz[2]); const matrix_trn2: three.Matrix4 = new three.Matrix4(); matrix_trn2.makeTranslation(origin_xyz[0], origin_xyz[1], origin_xyz[2]); // copy objects if (copy) {objs = model.getGeom().copyObjs(objs, true); } // do the xform model.getGeom().xformObjs(objs, matrix_trn2.multiply(matrix_mirror.multiply(matrix_trn1))); // return the result, either single obj or array if (is_array) {return objs;} return objs[0]; } /** * Deletes object or a list of objects from the model. * * @param objs Object or list of objects to delete. * @param keep_points If false, points that are not used in any other objects will be deleted. * @returns True if all objects we successfully deleted. */ export function del(objs: gs.IObj | gs.IObj[], keep_points: boolean = false): boolean { if (!Array.isArray(objs)) {objs = [objs];} const model: gs.IModel = error.checkObjList(objs, 1); let ok: boolean = true; for (const obj of objs) { if (!model.getGeom().delObj(obj, keep_points)) {ok = false;} } return ok; } /** * Unwelds objects, so that thier vertices no longer share any points. * * @param objs Object or list of objects to unweld. * @returns A list of new points generated by the unwelding process. */ export function unweld(objs: gs.IObj | gs.IObj[]): gs.IPoint[] { if (!Array.isArray(objs)) {objs = [objs];} const model: gs.IModel = error.checkObjList(objs, 1); return model.getGeom().unweldObjs(objs); } // =============================================================================================================== // Groups ============================================================================================== // =============================================================================================================== /** * Add objects to a group. * * @param group Name of group to add to. * @param objs List of objects to add. * @returns True if all objects we successfully added. */ export function addToGroup(objs: gs.IObj | gs.IObj[], group_name: string): boolean { if (!Array.isArray(objs)) {objs = [objs];} const model: gs.IModel = error.checkObjList(objs, 1); const group: gs.IGroup = error.checkGroup(model, group_name); let ok: boolean = true; for (const obj of objs) { if (!group.addObj(obj as gs.IObj)) {ok = false;} } return ok; } /** * Remove object from a group. * * @param group Name of group to add to. * @param objs List of object to remove. * @returns True if all objects we successfully removed. */ export function removeFromGroup(objs: gs.IObj | gs.IObj[], group_name: string): boolean { if (!Array.isArray(objs)) {objs = [objs];} const model: gs.IModel = error.checkObjList(objs, 1); const group: gs.IGroup = error.checkGroup(model, group_name); let ok: boolean = true; for (const obj of objs) { if (!group.removeObj(obj as gs.IObj)) {ok = false;} } return ok; }