home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-385-Vol-1of3.iso
/
i
/
iritsm3s.zip
/
cagd_lib
/
cagdswep.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-12-01
|
11KB
|
299 lines
/******************************************************************************
* CagdSwep.c - Sweep srf operator out of given cross section and an axis. *
*******************************************************************************
* Written by Gershon Elber, May. 91. *
******************************************************************************/
#ifdef __MSDOS__
#include <stdlib.h>
#include <string.h>
#include <alloc.h>
#endif /* __MSDOS__ */
#include "cagd_loc.h"
static void TransformCrossSection(CagdRType **SPoints, int Index,
CagdCrvStruct *CrossSection, CagdRType *Position,
CagdRType Scale, CagdVecStruct *Tangent,
CagdVecStruct *Normal);
static void GenTransformMatrix(CagdMatStruct *Mat, CagdRType *Trans,
CagdVecStruct *Normal, CagdVecStruct *Dir,
CagdRType Scale);
/******************************************************************************
* Constructs a sweep surface using the following curves: *
* 1. CrossSection - defines the basic cross section of the sweep. Must be in *
* the XY plane. *
* 2. Axis - a 3D curve the CrossSection will be swept along such that the *
* Axis normal aligns with the Y axis of the cross section. If Axis is *
* linear (i.e. no normal), the normal is picked randomly or to fit the non *
* linear part of the Axis (if any). *
* 3. Scale - a scaling curve for the sweep, If NULL a scale of Scale is used. *
******************************************************************************/
CagdSrfStruct *CagdSweepSrf(CagdCrvStruct *CrossSection, CagdCrvStruct *Axis,
CagdCrvStruct *ScalingCrv, CagdRType Scale)
{
CagdSrfStruct *Srf;
CagdVecStruct Normal, *Vec, TVec;
CagdPointType
SrfPType = CAGD_PT_E3_TYPE;
CagdGeomType
SrfGType = CAGD_SBSPLINE_TYPE;
int i, j, k,
ULength = CrossSection -> Length,
VLength = Axis -> Length,
UOrder = CrossSection -> Order,
VOrder = Axis -> Order;
CagdRType **Points, *AxisNodes, *AxisNodePtr, *AxisKV,
*AxisWeights = NULL;
switch (Axis -> GType) {
case CAGD_CBEZIER_TYPE:
SrfGType = CAGD_SBEZIER_TYPE;
AxisKV = BspKnotUniformOpen(VLength, VOrder, NULL);
AxisNodes = AxisNodePtr = BspKnotNodes(AxisKV,
VLength + VOrder,
VOrder);
break;
case CAGD_CBSPLINE_TYPE:
SrfGType = CAGD_SBSPLINE_TYPE;
AxisKV = Axis -> KnotVector;
AxisNodePtr = AxisNodes = BspKnotNodes(Axis -> KnotVector,
VLength + VOrder,
VOrder);
break;
case CAGD_CPOWER_TYPE:
FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
break;
default:
FATAL_ERROR(CAGD_ERR_UNDEF_CRV);
break;
}
if (CAGD_IS_RATIONAL_CRV(Axis)) AxisWeights = Axis -> Points[W];
switch (CrossSection -> GType) {
case CAGD_CBEZIER_TYPE:
break;
case CAGD_CBSPLINE_TYPE:
SrfGType = CAGD_SBSPLINE_TYPE;
break;
case CAGD_CPOWER_TYPE:
FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
break;
default:
FATAL_ERROR(CAGD_ERR_UNDEF_CRV);
break;
}
if (ScalingCrv) {
int ScaleKVLen,
AxisKVLen = Axis -> Order + Axis -> Length;
switch (ScalingCrv -> GType) {
case CAGD_CBEZIER_TYPE:
ScalingCrv = CnvrtBezier2BsplineCrv(ScalingCrv);
break;
case CAGD_CBSPLINE_TYPE:
ScalingCrv = CagdCrvCopy(ScalingCrv);
break;
case CAGD_CPOWER_TYPE:
FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
break;
default:
FATAL_ERROR(CAGD_ERR_UNDEF_CRV);
break;
}
ScaleKVLen = ScalingCrv -> Order + ScalingCrv -> Length;
/* Affine trans. ScalingCrv KV to match Axis. */
BspKnotAffineTrans(ScalingCrv -> KnotVector, ScaleKVLen,
AxisKV[0] - ScalingCrv -> KnotVector[0],
(AxisKV[AxisKVLen - 1] - AxisKV[0]) /
(ScalingCrv -> KnotVector[ScaleKVLen - 1] -
ScalingCrv -> KnotVector[0]));
}
if (CAGD_IS_RATIONAL_CRV(Axis) || CAGD_IS_RATIONAL_CRV(CrossSection))
SrfPType = CAGD_PT_P3_TYPE;
switch (SrfGType) {
case CAGD_SBEZIER_TYPE:
Srf = BzrSrfNew(ULength, VLength, SrfPType);
break;
case CAGD_SBSPLINE_TYPE:
Srf = BspSrfNew(ULength, VLength, UOrder, VOrder, SrfPType);
if (CrossSection -> GType == CAGD_CBSPLINE_TYPE)
GEN_COPY(Srf -> UKnotVector, CrossSection -> KnotVector,
sizeof(CagdRType) * (ULength + UOrder));
else
BspKnotUniformOpen(ULength, UOrder, Srf -> UKnotVector);
if (Axis -> GType == CAGD_CBSPLINE_TYPE)
GEN_COPY(Srf -> VKnotVector, Axis -> KnotVector,
sizeof(CagdRType) * (VLength + VOrder));
else
BspKnotUniformOpen(VLength, VOrder, Srf -> VKnotVector);
break;
default:
FATAL_ERROR(CAGD_ERR_UNDEF_SRF);
break;
}
Points = Srf -> Points;
/* Compute the normal to the axis curve and use it to align the +Y axis */
/* of the cross section with that vector. If the Axis curve has no */
/* normal (i.e. it is a linear segment), an arbitrary normal is picked. */
Vec = CagdCrvNormal(Axis, *AxisNodePtr);
if (Vec != NULL) {
CAGD_COPY_VECTOR(Normal, *Vec);
}
else {
Vec = CagdCrvTangent(Axis, *AxisNodePtr);
Normal.Vec[0] = Normal.Vec[1] = Normal.Vec[2] = 0.0;
if (ABS(Vec -> Vec[0]) <= ABS(Vec -> Vec[1]) &&
ABS(Vec -> Vec[0]) <= ABS(Vec -> Vec[2]))
Normal.Vec[0] = 1.0;
else if (ABS(Vec -> Vec[1]) <= ABS(Vec -> Vec[0]) &&
ABS(Vec -> Vec[1]) <= ABS(Vec -> Vec[2]))
Normal.Vec[1] = 1.0;
else
Normal.Vec[2] = 1.0;
CROSS_PROD(TVec.Vec, Vec -> Vec, Normal.Vec);
CAGD_NORMALIZE_VECTOR(TVec);
CROSS_PROD(Normal.Vec, TVec.Vec, Vec -> Vec);
}
/* For each ctl points of the axis, transform the cross section */
/* according to ctl point position, tangent to axis at the point and in */
/* such a way to minimize Normal change. */
for (i = 0; i < VLength; i++) {
CagdRType PosE3[3], ScaleE2[2],
*Scaling = ScalingCrv ? CagdCrvEval(ScalingCrv, *AxisNodePtr) : NULL;
CagdVecStruct
*Tangent = CagdCrvTangent(Axis, *AxisNodePtr++);
if (Scaling)
CagdCoerceToE2(ScaleE2, &Scaling, -1, ScalingCrv -> PType);
else
ScaleE2[1] = Scale;
if (AxisWeights) ScaleE2[1] /= AxisWeights[i];
CagdCoerceToE3(PosE3, Axis -> Points, i, Axis -> PType);
TransformCrossSection(Points, i * ULength, CrossSection,
PosE3, ScaleE2[1], Tangent, &Normal);
}
/* Do fixups if axis is a rational curve (note surface is P3). */
if (AxisWeights) {
if (CAGD_IS_RATIONAL_CRV(CrossSection)) {
/* Need only scale by the Axis curve weights: */
for (j = 0, k = 0; j < VLength; j++)
for (i = 0; i < ULength; i++, k++) {
Points[X][k] *= AxisWeights[j];
Points[Y][k] *= AxisWeights[j];
Points[Z][k] *= AxisWeights[j];
Points[W][k] *= AxisWeights[j];
}
}
else {
/* Weights do not exists at the moment - need to copy them. */
for (j = 0, k = 0; j < VLength; j++)
for (i = 0; i < ULength; i++, k++) {
Points[X][k] *= AxisWeights[j];
Points[Y][k] *= AxisWeights[j];
Points[Z][k] *= AxisWeights[j];
Points[W][k] = AxisWeights[j];
}
}
}
if (Axis -> GType == CAGD_CBEZIER_TYPE)
CagdFree((VoidPtr) AxisKV);
if (ScalingCrv)
CagdCrvFree(ScalingCrv);
CagdFree((VoidPtr) AxisNodes);
return Srf;
}
/******************************************************************************
* Transform The CrossSection Points, to Position such that Tangent is *
* perpendicular to the cross section (which is assumed to be on the XY *
* plane). The +Y axis of the cross section is aligned with Normal direction *
* to minimize twist along the sweep and been updated to new normal. *
* Transformed cross section is place into srf Points, SPoints starting from *
* index SIndex. *
* All agrument vectors are assumed to be normalized to a unit length. *
******************************************************************************/
static void TransformCrossSection(CagdRType **SPoints, int SIndex,
CagdCrvStruct *CrossSection, CagdRType *Position,
CagdRType Scale, CagdVecStruct *Tangent,
CagdVecStruct *Normal)
{
CagdPointType
PType = CrossSection -> PType;
CagdBType
IsNotRational = !CAGD_IS_RATIONAL_PT(PType);
CagdVecStruct TVec;
CagdMatStruct Mat;
CagdCrvStruct
*CSCopy = CagdCrvCopy(CrossSection);
int i, j,
MaxCoord = CAGD_NUM_OF_PT_COORD(PType),
Len = CSCopy -> Length;
CagdRType R,
**CSPoints = CSCopy -> Points;
/* Fix the Normal to be perpendicular to the Tangent vector is a minimal */
/* rotation. This ensures minimal twist in the resulting surface. */
R = DOT_PROD(Normal -> Vec, Tangent -> Vec);
TVec = *Tangent;
CAGD_MULT_VECTOR(TVec, R);
CAGD_SUB_VECTOR(*Normal, TVec);
CAGD_NORMALIZE_VECTOR(*Normal);
GenTransformMatrix(&Mat, Position, Normal, Tangent, Scale);
CagdCrvMatTransform(CSCopy, &Mat);
for (i = 0; i < Len; i++)
for (j = IsNotRational; j <= MaxCoord; j++)
SPoints[j][SIndex + i] = CSPoints[j][i];
CagdCrvFree(CSCopy);
}
/******************************************************************************
* Routine to preper transformation martix to do the following (in this *
* order): scale by Scale, rotate such that the Z axis is in direction Dir *
* and Y is colinear with the Normal and then translate by Trans. *
* Algorithm: given the Trans vector, it forms the 4th line of Mat. Dir is *
* used to form the second line (the first 3 lines set the rotation), and *
* finally Scale is used to scale first 3 lines/columns to the needed scale: *
* | Tx Ty Tz 0 | A transformation which takes the coord *
* | Bx By Bz 0 | system into T, N & B as required and *
* [X Y Z 1] * | Nx Ny Nz 0 | then translate it to C. T, N, B are *
* | Cx Cy Cz 1 | scaled by Scale. *
* N is exactly Dir (unit vec). T is set to be the Normal and B their cross *
* product. *
* All agrument vectors are assumed to be normalized to a unit length. *
******************************************************************************/
static void GenTransformMatrix(CagdMatStruct *Mat, CagdRType *Trans,
CagdVecStruct *Normal, CagdVecStruct *Dir,
CagdRType Scale)
{
int i;
CagdVecStruct B;
CROSS_PROD(B.Vec, Dir -> Vec, Normal -> Vec);
for (i = 0; i < 3; i++) {
Mat -> Mat[0][i] = Normal -> Vec[i] * Scale;
Mat -> Mat[1][i] = B.Vec[i] * Scale;
Mat -> Mat[2][i] = Dir -> Vec[i] * Scale;
Mat -> Mat[3][i] = Trans[i];
Mat -> Mat[i][3] = 0.0;
}
Mat -> Mat[3][3] = 1.0;
}