std::vector<double> TEvent::GetPerpFoot(std::vector<double> referencePosition) { /** * create dropped perpendicular foot (perpFoot) first * g: S = position_ + t * eventDirection * t = <referencePosition - position_, eventDirection> * / <eventDirection, eventDirection> */ std::vector<double> eventDirection, difference, perpFoot; // create directional vector out of angles eventDirection.push_back(cos(azimuthalAngle_) * sin(polarAngle_)); eventDirection.push_back(sin(azimuthalAngle_) * sin(polarAngle_)); eventDirection.push_back(cos(polarAngle_)); // create difference vector between sensorPosition and this event for (int i = 0; i < 3; ++i) { difference.push_back(referencePosition.at(i) - position_.at(i)); } // calculate gradient of straight line double t = GetInnerProduct(difference, eventDirection) / GetInnerProduct(eventDirection, eventDirection); // calculate dropped perpendicular foot using the straight line equation g for (int i = 0; i < 3; ++i) { perpFoot.push_back(position_.at(i) + t * eventDirection.at(i)); } return perpFoot; }
//--------------------------------------------------------------------------- // CalculateTangent() // Calculate a tangent vector from positions, normals and coordinates. // 位置・法線・UV座標から接線ベクトルを計算する //--------------------------------------------------------------------------- void CalculateTangent(const MQPoint& v0, const MQPoint& v1, const MQPoint& v2, const MQPoint& n0, const MQPoint& n1, const MQPoint& n2, const MQCoordinate& t0, const MQCoordinate& t1, const MQCoordinate& t2, MQPoint& tan0, MQPoint& tan1, MQPoint& tan2) { MQPoint edge1, edge2, crossP; edge1.x = v1.x - v0.x; edge1.y = t1.u - t0.u; // s-vector - don't need to compute this multiple times edge1.z = t1.v - t0.v; // t-vector edge2.x = v2.x - v0.x; edge2.y = t2.u - t0.u; // another s-vector edge2.z = t2.v - t0.v; // another t-vector crossP = Normalize(GetCrossProduct(edge1, edge2)); if(fabs(crossP.x) < 1e-4f){ crossP.x = 1.0f; } float tanX = -crossP.y / crossP.x; tan0.x = tanX; tan1.x = tanX; tan2.x = tanX; // y, s, t edge1.x = v1.y - v0.y; edge2.x = v2.y - v0.y; crossP = Normalize(GetCrossProduct(edge1, edge2)); if(fabs(crossP.x) < 1e-4f){ crossP.x = 1.0f; } float tanY = -crossP.y / crossP.x; tan0.y = tanY; tan1.y = tanY; tan2.y = tanY; // z, s, t edge1.x = v1.z - v0.z; edge2.x = v2.z - v0.z; crossP = Normalize(GetCrossProduct(edge1, edge2)); if(fabs(crossP.x) < 1e-4f){ crossP.x = 1.0f; } float tanZ = -crossP.y / crossP.x; tan0.z = tanZ; tan1.z = tanZ; tan2.z = tanZ; // Orthonormalize to normal tan0 -= n0 * GetInnerProduct(tan0, n0); tan1 -= n1 * GetInnerProduct(tan1, n1); tan2 -= n2 * GetInnerProduct(tan2, n2); // Normalize tangents tan0 = Normalize(tan0); tan1 = Normalize(tan1); tan2 = Normalize(tan2); }
double TEvent::GetDistance(std::vector<double> firstPosition, std::vector<double> secondPosition) { std::vector<double> difference; // create difference vector between firstPosition and secondPosition for (int i = 0; i < 3; i++) { difference.push_back(secondPosition.at(i) - firstPosition.at(i)); } // return distance return sqrt(GetInnerProduct(difference, difference)); }
//--------------------------------------------------------------------------- // GetQuadNormal() // Get a normal vector for a face constituted by four points. // 4点からなる面の法線を得る //--------------------------------------------------------------------------- MQPoint GetQuadNormal(const MQPoint& p0, const MQPoint& p1, const MQPoint& p2, const MQPoint& p3) { MQPoint n,n1a,n1b,n2a,n2b; n1a = GetNormal(p0, p1, p2); n1b = GetNormal(p0, p2, p3); n2a = GetNormal(p1, p2, p3); n2b = GetNormal(p1, p3, p0); // 凹型や歪んだ四角形の場合は片方の内積が小さくなるので、 // 2法線の内積の値を比較して、大きい方を選ぶ if(GetInnerProduct(n1a,n1b) > GetInnerProduct(n2a,n2b)) { n = Normalize(n1a + n1b); } else { n = Normalize(n2a + n2b); } return n; }
float GetTriangleArea(const MQCoordinate& p1, const MQCoordinate& p2, const MQCoordinate& p3) { MQCoordinate v1,v2; float d1,d2,t,u; v1=p2-p1; d1=GetSize(v1); v2=p3-p1; d2=GetSize(v2); t = d1*d2; if(t == 0) return 0; u = (GetInnerProduct(v1,v2) / t); return t * (1 - u*u); }
//--------------------------------------------------------------------------- // GetTriangleArea() // Get an area of a triangle constituted by three points // 3点からなる三角形の面積を得る //--------------------------------------------------------------------------- float GetTriangleArea(const MQPoint& p1, const MQPoint& p2, const MQPoint& p3) { MQPoint v1,v2; float d1,d2,t,u; v1=p2-p1; d1=v1.abs(); v2=p3-p1; d2=v2.abs(); t = d1*d2; if(t == 0) return 0; u = (GetInnerProduct(v1,v2) / t); return t * (1 - u*u); }
float GetCrossingAngle(const MQCoordinate& v1, const MQCoordinate& v2) { float d,c; d = GetSize(v1) * GetSize(v2); if(d == 0.0f) return 0.0f; c = GetInnerProduct(v1, v2) / d; if(c >= 1.0f) return 0.0f; if(c <=-1.0f) return PI; return acosf(c); }
MQObjNormal::MQObjNormal(MQObject obj) { int i,j; int face_count, vert_count; int vi[4]; face_count = obj->GetFaceCount(); vert_count = obj->GetVertexCount(); MQPoint *face_n = new MQPoint[face_count]; normal = new MQPoint[face_count * 4]; // 面ごとに法線を計算 for(i=0; i<face_count; i++) { int count = obj->GetFacePointCount(i); // 三角形と四角形では面に対する法線の計算法は異なる switch(count) { case 3: obj->GetFacePointArray(i, vi); face_n[i] = GetNormal( obj->GetVertex(vi[0]), obj->GetVertex(vi[1]), obj->GetVertex(vi[2])); break; case 4: obj->GetFacePointArray(i, vi); face_n[i] = GetQuadNormal( obj->GetVertex(vi[0]), obj->GetVertex(vi[1]), obj->GetVertex(vi[2]), obj->GetVertex(vi[3])); break; default: face_n[i].zero(); break; } } switch(obj->GetShading()) { case MQOBJECT_SHADE_FLAT: for(i=0; i<face_count; i++) { int count = obj->GetFacePointCount(i); for(j=0; j<count; j++) normal[i*4+j] = face_n[i]; for(; j<4; j++) normal[i*4+j].zero(); } break; case MQOBJECT_SHADE_GOURAUD: { MQGouraudHashTable *vtbl, *cvt; MQGouraudHash *hash, *chs; // スムージング角度の取得 float facet = cosf( RAD(obj->GetSmoothAngle()) ); // ハッシュの初期化 vtbl = new MQGouraudHashTable[face_count]; hash = new MQGouraudHash[vert_count + face_count*4]; int hash_count = vert_count; // 面ごとにハッシュに法線ベクトルをセット for(i=0,cvt=vtbl; i<face_count; i++,cvt++) { int count = obj->GetFacePointCount(i); if(count < 3) continue; obj->GetFacePointArray(i, vi); // 面中の各頂点ごとに法線ベクトルをハッシュへ格納してやる for(j=0; j<count; j++) { // 注目する頂点に対してのハッシュを得る chs = &hash[vi[j]]; // ハッシュがまだ空ならそこに情報を格納 if(chs->count == 0) { chs->nv = face_n[i]; chs->count++; (*cvt)[j] = chs; continue; } // ハッシュが空でないなら、既に格納されている法線とのスムージング // 角度をチェックする必要がある。 // アルゴリズムとしては不完全かもしれないが、とりあえず実用程度に // はなると思う。 const MQPoint& pa = face_n[i]; float da = pa.norm(); for(; ; chs=chs->next) { // 2面の角度をチェック float c = 0.0f; if(da > 0.0f) { MQPoint& pb = chs->nv; float db = pb.norm(); if(db > 0.0f) c = GetInnerProduct(pa, pb) / sqrtf(da*db); } // スムージング角度以内か? if(c >= facet) { // 注目する頂点に対して面の法線ベクトルをそのまま加算する。 // 本来なら、注目する頂点に属する面内の2辺の角度によって // ベクトルの加算量を変えるべきだが、とりあえずパス。 chs->nv += pa; chs->count++; (*cvt)[j] = chs; break; } // スムージングは行われないので、次のハッシュをチェック。 // 次のハッシュデータがない場合は新規作成。 if(chs->next == NULL) { (*cvt)[j] = chs->next = &hash[hash_count++]; chs = chs->next; chs->nv = pa; chs->count = 1; chs->next = NULL; break; } } } } // ハッシュ中の法線ベクトルの正規化 for(i=0,chs=hash; i<hash_count; i++,chs++) { if(chs->count > 1) chs->nv.normalize(); } // 法線をバッファにセット for(i=0,cvt=vtbl; i<face_count; i++,cvt++) { int count = obj->GetFacePointCount(i); if(count < 3) continue; for(j=0; j<count; j++) normal[i*4+j] = (*cvt)[j]->nv; for(; j<4; j++) normal[i*4+j].zero(); } // ハッシュを解放 delete[] vtbl; delete[] hash; } break; } delete[] face_n; }