float VectorDistance (vec3_t v1, vec3_t v2) { vec3_t diff; VectorSubtract(v1, v2, diff); return vlen(diff); }
/* Variance of data by corrected two-pass algorithm */ double variance (const VEC v){ assert(NULL!=v); const unsigned int len = vlen(v); const double vmean = mean(v); const double correction = suma_vec(v,-vmean); return (sample_variance_naive(v)-correction*correction/len)/(len-1); }
double quantile (const VEC v, const double q){ assert(NULL!=v); assert(q>=0. && q<=1.); VEC vcopy = copy_vec(v); qsort (vcopy->x,vlen(vcopy),sizeof(double),CmpDouble); const double med = quantile_fromsorted(vcopy,q); free_vec(vcopy); return med; }
void Wall::revalidate () { j = next->v1-v1; len = vlen(j); j /= len; // Cache the inverse slope of the wall. Used in Area::pointin. tslope = ((next->v1.x - v1.x) / (next->v1.y - v1.y)); }
void Helpers::normalize(qreal *a) { double b; b = vlen(a); a[0] /= b; a[1] /= b; a[2] /= b; }
// Called from client.c void GrappleService() { vec3_t hookVector, hookVelocity; gedict_t *enemy; // drop the hook if player lets go of fire if ( !self->s.v.button0 ) { if ( self->s.v.weapon == IT_HOOK ) { GrappleReset( self->hook ); return; } } enemy = PROG_TO_EDICT( self->hook->s.v.enemy ); // If hooked to a player, track them directly! if ( enemy->ct == ctPlayer ) { VectorSubtract( enemy->s.v.origin, self->s.v.origin, hookVector ); } else VectorSubtract( self->hook->s.v.origin, self->s.v.origin, hookVector ); // No longer going to factor maxspeed into grapple velocity // Using standard grapple velocity of 800 set from original 3wave // purectf velocity = 2.35 * 320 or 360 * 1 = 750 or 846 VectorCopy( hookVector, hookVelocity ); VectorNormalize( hookVelocity ); if ( self->ctf_flag & CTF_RUNE_HST ) VectorScale( hookVelocity, 1000, self->s.v.velocity ); else VectorScale( hookVelocity, 800, self->s.v.velocity ); if ( vlen(hookVector) <= 100 ) // cancel chain sound { FreezeGravity( self ); if ( self->ctf_sound ) { // If there is a chain, ditch it now. We're // close enough. Having extra entities lying around // is never a good idea. if ( self->hook->s.v.goalentity ) { PROG_TO_EDICT(self->hook->s.v.goalentity)->s.v.think = (func_t) RemoveChain; PROG_TO_EDICT(self->hook->s.v.goalentity)->s.v.nextthink = g_globalvars.time; } sound( self, CHAN_NO_PHS_ADD + CHAN_WEAPON, "weapons/chain3.wav", 1, ATTN_NORM ); self->ctf_sound = false; // reset the sound channel. } } }
/* Ensure that the array contains enough memory for @len * bits, expanding the bitvector if necessary */ static void bv_ensure(bitvector_t *bv, unsigned int len) { len = vlen(len); /* now number of bytes */ if (len > bv->alloc) { unsigned int newalloc = ((len + QUANTUM-1) / QUANTUM) * QUANTUM; bv->bits = (unsigned char *)xrealloc(bv->bits, newalloc); memset(bv->bits + bv->alloc, 0, newalloc - bv->alloc); bv->alloc = newalloc; } }
double sample_variance_naive ( const VEC v){ assert(NULL!=v); const unsigned int len = vlen(v); const double vmean = mean(v); double sumsqr = 0.; for ( unsigned int i=0 ; i<len ; i++){ sumsqr += (vget(v,i)-vmean)*(vget(v,i)-vmean); } return sumsqr; }
//Surface double area() { double res = 0; if (n == 3) { Point p = cross(P[0], P[1], P[2]); res = vlen(p) / 2.0; return res; } for (int i = 0; i < num; i++) res += area(P[F[i].a], P[F[i].b], P[F[i].c]); return res / 2.0; }
EXPORTED void bv_oreq(bitvector_t *a, const bitvector_t *b) { unsigned int n; unsigned int i; bv_ensure(a, b->length); n = vlen(b->length+1); for (i = 0 ; i <= n ; i++) a->bits[i] |= b->bits[i]; a->length = MAX(a->length, b->length); }
t_vector get_cone_normale(t_vector p, t_icone *cone) { double m; t_vector res; m = pow(vlen(vsub(p, cone->vertex)), 2) / vscalar_multiple(vsub(p, cone->vertex), cone->vector); res = vsum(cone->vertex, vk_multiple(cone->vector, m)); res = vnormalize(vsub(p, res)); return (res); }
void player_chain3() { self->s.v.frame = 139; self->think = ( func_t ) player_chain4; self->s.v.nextthink = g_globalvars.time + 0.1; self->s.v.weaponframe = 3; if ( !self->hook_out ) player_chain5(); else if ( vlen(self->s.v.velocity) >= 750 ) player_chain4(); }
void CheckSentry( gedict_t * gunhead ) { vec3_t dist; gedict_t *gunbase; gunbase = gunhead->trigger_field; VectorSubtract( gunbase->s.v.origin, gunhead->s.v.origin, dist ); if ( vlen( dist ) > 15 ) { G_bprint( 1, "%s's sentry gun malfunctioned\n", self->real_owner->s.v.netname ); Sentry_Die( ); } }
/* Some unnecessary vector copies when this function is combined with median */ double mad ( const VEC v){ assert(NULL!=v); const double vmedian = median(v); VEC vcopy = copy_vec (v); const unsigned int len = vlen(vcopy); for ( unsigned int i=0 ; i<len ; i++){ vset(vcopy,i,fabs(vget(vcopy,i)-vmedian)); } const double devmedian = median(vcopy); free_vec(vcopy); return devmedian * MADSCALE; }
void Motion(int x, int y) { bool changed = false; const int dx = x - _mouseX; const int dy = y - _mouseY; int viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); if (dx == 0 && dy == 0) return; if (_mouseMiddle || (_mouseLeft && _mouseRight)) { double s = exp((double) dy * 0.01); glScalef(s, s, s); changed = true; } else if (_mouseLeft) { double ax, ay, az; double bx, by, bz; double angle; ax = dy; ay = dx; az = 0.0; angle = vlen(ax, ay, az) / (double) (viewport[2] + 1) * 180.0; /* Use inverse matrix to determine local axis of rotation */ bx = _matrixI[0] * ax + _matrixI[4] * ay + _matrixI[8] * az; by = _matrixI[1] * ax + _matrixI[5] * ay + _matrixI[9] * az; bz = _matrixI[2] * ax + _matrixI[6] * ay + _matrixI[10] * az; glRotatef(angle, bx, by, bz); changed = true; } else if (_mouseRight) { double px, py, pz; pos(&px, &py, &pz, x, y, viewport); glLoadIdentity(); glTranslatef(px - _dragPosX, py - _dragPosY, pz - _dragPosZ); glMultMatrixd(_matrix); _dragPosX = px; _dragPosY = py; _dragPosZ = pz; changed = true; } _mouseX = x; _mouseY = y; if (changed) { getMatrix(); glutPostRedisplay(); } }
void traceJigData(struct part *part, struct xyz *positions) { double x; int i; struct jig *j; __p = __line; __p += sprintf(__p, "%10.4f ", Iteration * Dt / PICOSEC); for (i=0; i<part->num_jigs; i++) { j = part->jigs[i]; switch (j->type) { case DihedralMeter: case AngleMeter: __p += sprintf(__p, " %15.5f", j->data); break; case Ground: x=vlen(j->xdata)/1e4; __p += sprintf(__p, " %15.2f", x / j->data); j->data=0.0; vsetc(j->xdata, 0.0); break; case RadiusMeter: case LinearMotor: // convert from picometers to angstroms __p += sprintf(__p, " %15.4f", 0.01 * j->data); j->data = 0.0; break; case Thermometer: case Thermostat: __p += sprintf(__p, " %15.2f", j->data); j->data = 0.0; break; case RotaryMotor: __p += sprintf(__p, " %15.3f %15.3f", j->data, j->data2); j->data = 0.0; j->data2 = 0.0; break; } } if (PrintPotentialEnergy) { double potential_energy = calculatePotential(part, positions); double kinetic_energy = calculateKinetic(part); __p += sprintf(__p, " %15.6f", potential_energy); __p += sprintf(__p, " %15.6f", kinetic_energy); __p += sprintf(__p, " %15.6f", potential_energy + kinetic_energy); } sprintf(__p, "\n"); // each snapshot is one line write_traceline(__line); }
void player_chain4() { // Original ctf grapple used frame 73 here, but that causes problems with cl_deadbodyfilter 2 // Frame 139 is a decent alternative especially given that 73 never looked good anyway // self->s.v.frame = 73; self->s.v.frame = 139; self->think = ( func_t ) player_chain5; self->s.v.nextthink = g_globalvars.time + 0.1; self->s.v.weaponframe = 4; if ( !self->hook_out ) player_chain5(); else if ( vlen(self->s.v.velocity) < 750 ) player_chain3(); }
double GetArea() //凸包表面积 { double res = 0.0; if (n == 3) { Point p = cross(P[0], P[1], P[2]); res = vlen(p) / 2.0; return res; } for (int i = 0; i < num; i++) { res += area(P[F[i].a], P[F[i].b], P[F[i].c]); } return res / 2.0; }
// Is player visible? static qboolean Cam_IsVisible(player_state_t *player, vec3_t vec) { pmtrace_t trace; vec3_t v; float d; trace = Cam_DoTrace(player->origin, vec); if (trace.fraction != 1 || /*trace.inopen ||*/ trace.inwater) return false; // check distance, don't let the player get too far away or too close VectorSubtract(player->origin, vec, v); d = vlen(v); if (d < 16) return false; return true; }
/* ============= ai_melee ============= */ void ai_melee() { vec3_t delta; float ldmg; if ( !self->s.v.enemy ) return; // removed before stroke VectorSubtract( PROG_TO_EDICT( self->s.v.enemy )->s.v.origin, self->s.v.origin, delta ); if ( vlen( delta ) > 60 ) return; ldmg = ( g_random() + g_random() + g_random() ) * 3; PROG_TO_EDICT( self->s.v.enemy )->deathtype = dtSQUISH; // FIXME T_Damage( PROG_TO_EDICT( self->s.v.enemy ), self, self, ldmg ); }
void VelocityForDamage( float dm, vec3_t v ) { vec3_t v2; if ( vlen( damage_inflictor->s.v.velocity ) > 0 ) { VectorScale( damage_inflictor->s.v.velocity, 0.5, v ); VectorSubtract( self->s.v.origin, damage_inflictor->s.v.origin, v2 ); VectorNormalize( v2 ); VectorScale( v2, 25, v2 ); VectorAdd( v, v2, v ); // v = 0.5 * damage_inflictor->s.v.velocity; // v = v + (25 * normalize((self->s.v.origin)-damage_inflictor->s.v.origin)); v[2] = 100 + 240 * g_random(); v[0] = v[0] + ( 200 * crandom() ); v[1] = v[1] + ( 200 * crandom() ); //dprint ("Velocity gib\n"); } else { v[0] = 100 * crandom(); v[1] = 100 * crandom(); v[2] = 200 + 100 * g_random(); } //v[0] = 100 * crandom(); //v[1] = 100 * crandom(); //v[2] = 200 + 100 * g_random(); if ( dm > -50 ) { // dprint ("level 1\n"); VectorScale( v, 0.7, v ); // v = v * 0.7; } else if ( dm > -200 ) { // dprint ("level 3\n"); VectorScale( v, 2, v ); // v = v * 2; } else VectorScale( v, 10, v ); // v = v * 10; return; //v; }
void sgAimNew( gedict_t* self, gedict_t* targ, vec3_t src, vec3_t dst, vec3_t norm_dir) { vec3_t dir, tmp; trap_makevectors( self->s.v.v_angle ); VectorAdd( self->s.v.origin, self->s.v.view_ofs, src ); VectorAdd( targ->s.v.origin, targ->s.v.view_ofs, dst ); VectorSubtract( dst, src, dir ); normalize(dir, norm_dir); //чтобы не попадать в подставку traceline( PASSVEC3( src ), PASSVEC3( dst ), 0, self ); if( (PROG_TO_EDICT(g_globalvars.trace_ent) == self->trigger_field) && vlen(dir) > 100 ) { VectorScale( norm_dir, 60, tmp); VectorAdd(src,tmp,src); } }
bool ray_triangle( vec3 p , vec3 d, vec3 A,vec3 B, vec3 C ){ //not matrix translate rotate? vec3 N=vcross(B-A, C-A); dassert(vlen(N)!=0.f && "RAY_TRIANGLE"); // bool backface = vdot( N, d ) > 0.f; float t=vdot(A-p,N)/vdot(N,d); //too far away or zero if(t>=1.||t<=0.f) return 0; /* float va = vdot( N , vcross( B-p, C-p ) ); float vb = vdot( N , vcross( C-p, A-p ) ); float vc = vdot( N , vcross( A-p, B-p ) ); float u = va / ( va + vb + vc ); float v = vb / ( va + vb + vc ); float w = 1.f - u - v; if( u<0.f || v < 0.f || w < 0.f ) return 0; */ //try uv approach // check if ray is inside triangle float EPS = -.00001f;//000000001f; if( //!backface && (vdot(vcross(A-p,B-p),d)>EPS|| vdot(vcross(B-p,C-p),d)>EPS|| vdot(vcross(C-p,A-p),d)>EPS)) return 0;//miss triangle return 1; }
//unused static void bondump(FILE *f) { /* gather bond statistics */ int histo[50][23], totno[50], btyp, i, j, k, n; double r, perc, means[50]; struct bondStretch *bt; for (i=0; i<50; i++) { totno[i] = 0; means[i] = 0.0; for (j=0; j<23; j++) histo[i][j]=0; } for (i=0; i<Nexbon; i++) { bt=bond[i].type; // XXX btyp = bt-bstab; totno[btyp]++; r=vlen(vdif(Positions[bond[i].an1], Positions[bond[i].an2])); means[btyp] += r; perc = (r/bt->r0)*20.0 - 8.5; k=(int)perc; if (k<0) k=0; if (k>22) k=22; histo[btyp][k]++; } for (i=0; i<BSTABSIZE; i++) if (totno[i]) { fprintf(f, "Bond type %s-%s, %d occurences, mean %.2f pm:\n", periodicTable[bstab[i].a1].symbol, periodicTable[bstab[i].a2].symbol, totno[i], means[i]/(double)totno[i]); for (j=0; j<23; j++) { if ((j-1)%10) fprintf(f, " |"); else fprintf(f, "-+"); n=(80*histo[i][j])/totno[i]; if (histo[i][j] && n==0) fprintf(f, "."); for (k=0; k<n; k++) fprintf(f, "M"); fprintf(f, "\n"); }} fprintf(f, "Iteration %d\n",Iteration); }
/* ============= range returns the range catagorization of an entity reletive to self 0 melee range, will become hostile even if back is turned 1 visibility and infront, or visibility and show hostile 2 infront and show hostile 3 only triggered by damage ============= */ float range( gedict_t *targ ) { vec3_t spot1, spot2, org; float r; VectorAdd( self->s.v.origin, self->s.v.view_ofs, spot1 ); VectorAdd( targ->s.v.origin, targ->s.v.view_ofs, spot2 ); VectorSubtract( spot1, spot2, org ); r = vlen( org ); if ( r < 120 ) return RANGE_MELEE; if ( r < 500 ) return RANGE_NEAR; if ( r < 1000 ) return RANGE_MID; // so monsters notice player father/faster in bloodfest mode. if ( k_bloodfest ) return RANGE_MID; return RANGE_FAR; }
void SUB_CalcMove( vec3_t tdest, float tspeed, void ( *func ) () ) { vec3_t vdestdelta; float len, traveltime; if ( !tspeed ) G_Error( "No speed is defined!" ); self->think1 = func; VectorCopy( tdest, self->finaldest ); self->s.v.think = ( func_t ) SUB_CalcMoveDone; if ( VectorCompare( tdest, self->s.v.origin ) ) { SetVector( self->s.v.velocity, 0, 0, 0 ); self->s.v.nextthink = self->s.v.ltime + 0.1; return; } // set destdelta to the vector needed to move VectorSubtract( tdest, self->s.v.origin, vdestdelta ) // calculate length of vector len = vlen( vdestdelta ); // divide by speed to get time to reach dest traveltime = len / tspeed; if ( traveltime < 0.03 ) traveltime = 0.03; // set nextthink to trigger a think when dest is reached self->s.v.nextthink = self->s.v.ltime + traveltime; // scale the destdelta vector by the time spent traveling to get velocity VectorScale( vdestdelta, ( 1 / traveltime ), self->s.v.velocity ); //self.velocity = vdestdelta * (1/traveltime); // qcc won't take vec/float }
/*! \internal \a a, \a b and \a c are corner points of an equilateral triangle. (\a x,\a y) is an arbitrary point inside or outside this triangle. If (x,y) is inside the triangle, this function returns the double point (x,y). Otherwise, the intersection of the perpendicular projection of (x,y) onto the closest triangle edge is returned, unless this intersection is outside the triangle's bounds, in which case the corner closest to the intersection is returned instead. Yes, it's trigonometry. */ QPointF QtColorTriangle::movePointToTriangle(double x, double y, const Vertex &a, const Vertex &b, const Vertex &c) const { // Let v1A be the vector from (x,y) to a. // Let v2A be the vector from a to b. // Find the angle alphaA between v1A and v2A. double v1xA = x - a.point.x(); double v1yA = y - a.point.y(); double v2xA = b.point.x() - a.point.x(); double v2yA = b.point.y() - a.point.y(); double vpA = vprod(v1xA, v1yA, v2xA, v2yA); double cosA = vpA / (vlen(v1xA, v1yA) * vlen(v2xA, v2yA)); double alphaA = acos(cosA); // Let v1B be the vector from x to b. // Let v2B be the vector from b to c. double v1xB = x - b.point.x(); double v1yB = y - b.point.y(); double v2xB = c.point.x() - b.point.x(); double v2yB = c.point.y() - b.point.y(); double vpB = vprod(v1xB, v1yB, v2xB, v2yB); double cosB = vpB / (vlen(v1xB, v1yB) * vlen(v2xB, v2yB)); double alphaB = acos(cosB); // Let v1C be the vector from x to c. // Let v2C be the vector from c back to a. double v1xC = x - c.point.x(); double v1yC = y - c.point.y(); double v2xC = a.point.x() - c.point.x(); double v2yC = a.point.y() - c.point.y(); double vpC = vprod(v1xC, v1yC, v2xC, v2yC); double cosC = vpC / (vlen(v1xC, v1yC) * vlen(v2xC, v2yC)); double alphaC = acos(cosC); // Find the radian angles between the (1,0) vector and the points // A, B, C and (x,y). Use this information to determine which of // the edges we should project (x,y) onto. double angleA = angleAt(a.point, contentsRect()); double angleB = angleAt(b.point, contentsRect()); double angleC = angleAt(c.point, contentsRect()); double angleP = angleAt(QPointF(x, y), contentsRect()); // If (x,y) is in the a-b area, project onto the a-b vector. if (angleBetweenAngles(angleP, angleA, angleB)) { // Find the distance from (x,y) to a. Then use the slope of // the a-b vector with this distance and the angle between a-b // and a-(x,y) to determine the point of intersection of the // perpendicular projection from (x,y) onto a-b. double pdist = sqrt(qsqr(x - a.point.x()) + qsqr(y - a.point.y())); // the length of all edges is always > 0 double p0x = a.point.x() + ((b.point.x() - a.point.x()) / vlen(v2xB, v2yB)) * cos(alphaA) * pdist; double p0y = a.point.y() + ((b.point.y() - a.point.y()) / vlen(v2xB, v2yB)) * cos(alphaA) * pdist; // If (x,y) is above the a-b line, which basically means it's // outside the triangle, then return its projection onto a-b. if (pointAbovePoint(x, y, p0x, p0y, a.point.x(), a.point.y(), b.point.x(), b.point.y())) { // If the projection is "outside" a, return a. If it is // outside b, return b. Otherwise return the projection. int n = pointInLine(p0x, p0y, a.point.x(), a.point.y(), b.point.x(), b.point.y()); if (n < 0) return a.point; else if (n > 0) return b.point; return QPointF(p0x, p0y); } } else if (angleBetweenAngles(angleP, angleB, angleC)) { // If (x,y) is in the b-c area, project onto the b-c vector. double pdist = sqrt(qsqr(x - b.point.x()) + qsqr(y - b.point.y())); // the length of all edges is always > 0 double p0x = b.point.x() + ((c.point.x() - b.point.x()) / vlen(v2xC, v2yC)) * cos(alphaB) * pdist; double p0y = b.point.y() + ((c.point.y() - b.point.y()) / vlen(v2xC, v2yC)) * cos(alphaB) * pdist; if (pointAbovePoint(x, y, p0x, p0y, b.point.x(), b.point.y(), c.point.x(), c.point.y())) { int n = pointInLine(p0x, p0y, b.point.x(), b.point.y(), c.point.x(), c.point.y()); if (n < 0) return b.point; else if (n > 0) return c.point; return QPointF(p0x, p0y); } } else if (angleBetweenAngles(angleP, angleC, angleA)) { // If (x,y) is in the c-a area, project onto the c-a vector. double pdist = sqrt(qsqr(x - c.point.x()) + qsqr(y - c.point.y())); // the length of all edges is always > 0 double p0x = c.point.x() + ((a.point.x() - c.point.x()) / vlen(v2xA, v2yA)) * cos(alphaC) * pdist; double p0y = c.point.y() + ((a.point.y() - c.point.y()) / vlen(v2xA, v2yA)) * cos(alphaC) * pdist; if (pointAbovePoint(x, y, p0x, p0y, c.point.x(), c.point.y(), a.point.x(), a.point.y())) { int n = pointInLine(p0x, p0y, c.point.x(), c.point.y(), a.point.x(), a.point.y()); if (n < 0) return c.point; else if (n > 0) return a.point; return QPointF(p0x, p0y); } } // (x,y) is inside the triangle (inside a-b, b-c and a-c). return QPointF(x, y); }
// ZOID // // Take over the user controls and track a player. // We find a nice position to watch the player and move there void Cam_Track(usercmd_t *cmd) { player_state_t *player, *self; frame_t *frame; vec3_t vec; float len; if (!cl.spectator) return; if (cl_hightrack.value && !locked) Cam_CheckHighTarget(); if (!autocam || cls.state != ca_active) return; if (locked && (!cl.players[spec_track].name[0] || cl.players[spec_track].spectator)) { locked = false; if (cl_hightrack.value) Cam_CheckHighTarget(); else Cam_Unlock(); return; } frame = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK]; player = frame->playerstate + spec_track; self = frame->playerstate + cl.playernum; if (!locked || !Cam_IsVisible(player, desired_position)) { if (!locked || realtime - cam_lastviewtime > 0.1) { if (!InitFlyby(self, player, true)) InitFlyby(self, player, false); cam_lastviewtime = realtime; } } else cam_lastviewtime = realtime; // couldn't track for some reason if (!locked || !autocam) return; if (cl_chasecam.value) { cmd->forwardmove = cmd->sidemove = cmd->upmove = 0; VectorCopy(player->viewangles, cl.viewangles); VectorCopy(player->origin, desired_position); if (memcmp(&desired_position, &self->origin, sizeof(desired_position)) != 0) { MSG_WriteByte (&cls.netchan.message, clc_tmove); MSG_WriteCoord (&cls.netchan.message, desired_position[0]); MSG_WriteCoord (&cls.netchan.message, desired_position[1]); MSG_WriteCoord (&cls.netchan.message, desired_position[2]); // move there locally immediately VectorCopy(desired_position, self->origin); } self->weaponframe = player->weaponframe; } else { // Ok, move to our desired position and set our angles to view // the player VectorSubtract(desired_position, self->origin, vec); len = vlen(vec); cmd->forwardmove = cmd->sidemove = cmd->upmove = 0; if (len > 16) { // close enough? MSG_WriteByte (&cls.netchan.message, clc_tmove); MSG_WriteCoord (&cls.netchan.message, desired_position[0]); MSG_WriteCoord (&cls.netchan.message, desired_position[1]); MSG_WriteCoord (&cls.netchan.message, desired_position[2]); } // move there locally immediately VectorCopy(desired_position, self->origin); VectorSubtract(player->origin, desired_position, vec); vectoangles(vec, cl.viewangles); cl.viewangles[0] = -cl.viewangles[0]; } }
static void zpr_motion(int x, int y) { bool changed = false; const int dx = x - _mousex; const int dy = y - _mousey; GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); if(dx == 0 && dy == 0) return; if(_mouse_middle || _mouse_right) { double s = exp((double)dy * 0.01); glTranslatef(zpr_reference_point[0], zpr_reference_point[1], zpr_reference_point[2] ); glscale *= s; glScalef(s, s, s); glTranslatef(zpr_reference_point[0], zpr_reference_point[1], zpr_reference_point[2]); changed = true; } else if(_mouse_left) { double ax, ay, az; double bx, by, bz; double angle; ax = dy; ay = dx; az = 0.0; angle = vlen(az, ay, az) / (double)(viewport[2]+1)*180.0; // Use inverse matrix to determine axis of rotation. bx = _matrix_inverse[0] * ax + _matrix_inverse[4] * ay + _matrix_inverse[8] * az; by = _matrix_inverse[1] * ax + _matrix_inverse[5] * ay + _matrix_inverse[9] * az; bz = _matrix_inverse[2] * ax + _matrix_inverse[6] * ay + _matrix_inverse[10] * az; glTranslatef(zpr_reference_point[0], zpr_reference_point[1], zpr_reference_point[2]); glRotatef(angle, bx, by, bz); glTranslatef(zpr_reference_point[0], zpr_reference_point[1], zpr_reference_point[2]); changed = true; } else if(0 && _mouse_right) { double px, py, pz; pos(&px, &py, &pz, x, y, viewport); glLoadIdentity(); glTranslatef(px - _drag_posx, py - _drag_posy, pz - _drag_posz); glMultMatrixd(_matrix); _drag_posx = px; _drag_posy = py; _drag_posz = pz; changed = true; } _mousex = x; _mousey = y; if(changed) { reset_orientation = 0; get_matrix(); glutPostRedisplay(); } }
double angle_sin(point3 l1,point3 l2,point3 s1,point3 s2,point3 s3) { return dmult(subt(l1,l2),pvec(s1,s2,s3))/vlen(subt(l1,l2))/vlen(pvec(s1,s2,s3)); }