gs-modelling
Version:
A set of 3D modelling functions for gs-JSON.
438 lines (418 loc) • 19.4 kB
text/typescript
/**
* 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;
}