// compute the bounding box of the transform of a rectangle void transformRegionFromRoD(const RectD &srcRect, const Matrix3x3 &transform, RectD &dstRect) { /// now transform the 4 corners of the source clip to the output image Point3D p[4]; p[0] = matApply( transform, Point3D(srcRect.x1, srcRect.y1, 1) ); p[1] = matApply( transform, Point3D(srcRect.x1, srcRect.y2, 1) ); p[2] = matApply( transform, Point3D(srcRect.x2, srcRect.y2, 1) ); p[3] = matApply( transform, Point3D(srcRect.x2, srcRect.y1, 1) ); transformRegionFromPoints(p, dstRect); }
/* Derivative of the dihedral potential. This shit gets quite involved. * * We want to compute * Fi = -grad_ri V(r1, r2, r3, r4) * Fi the force on the i'th particle and rj the position of the j'th * particle. * * We can rather easily write V as a function of * A = r12 x r23 = (r2 - r1) x (r3 - r2) * and * B = r23 x r34 = (r3 - r2) x (r4 - r3) * * Indeed, we have: * V = DIHEDRAL_COUPLING * (1 - cos(phi - phi0)) * where * phi = acos(A dot B / |A| * |B|) * * We can then write Fi as: * Fi = -grad_ri Vi(A(r1, r2, r3), B(r2, r3, r4)) * and use the appropriate chain rule: * Fi = - [J_ri(A)]^t * (grad_A V) * - [J_ri(B)]^t * (grad_B V) * where [J_ri(X)]^t is the transpose of the Jacobian matrix of the vector * function X with regards to ri. * * After some calculus and algebra, we get * grad_A V = DIHEDRAL_COUPLING * * [ sin(phi0)/sin(phi) * (A dot B)/(|A|^2 |B|^2) * - cos(phi0) / (|A||B|) ] * * [B - A (A dot B) / (|B||A|)] * and due to the symmetry in V of A and B, grad_B V is exactly the same, * but with A and B interchanged. * grad_B V = DIHEDRAL_COUPLING * * [ sin(phi0)/sin(phi) * (A dot B)/(|A|^2 |B|^2) * - cos(phi0) / (|A||B|) ] * * [A - B (A dot B) / (|B||A|)] * * * NOTE: when debugging the dihedral force for energy conservation, you * also need to enable angle and bond interactions (which should be * debugged first), otherwise you get a badly conditioned problem and you * will experience blow up. */ static void Fdihedral(Particle *p1, Particle *p2, Particle *p3, Particle *p4, DihedralCache phi0) { if (!interactions.enableDihedral) return; Vec3 r12 = nearestImageVector(p1->pos, p2->pos); Vec3 r23 = nearestImageVector(p2->pos, p3->pos); Vec3 r34 = nearestImageVector(p3->pos, p4->pos); double sinPhi, cosPhi; //TODO find better algorithm to only compute sinPhi sinCosDihedral(r12, r23, r34, &sinPhi, &cosPhi); if (UNLIKELY(fabs(sinPhi) < 1e-5)) //TODO just check for ==0? -> saves an fabs! return; /* (Unstable) equilibrium. */ double sinPhi0 = phi0.sinDihedral; double cosPhi0 = phi0.cosDihedral; Vec3 A = cross(r12, r23); Vec3 B = cross(r23, r34); double lAl2 = length2(A); double lBl2 = length2(B); double lAl2lBl2 = lAl2 * lBl2; double lAllBl = sqrt(lAl2lBl2); double AdB = dot(A, B); double negGradPrefactor = DIHEDRAL_COUPLING * (cosPhi0 / lAllBl - sinPhi0/sinPhi * AdB/lAl2lBl2); /* -grad_A(V) */ Vec3 negGrad_AV = scale( sub(B, scale(A, AdB/lAl2)), negGradPrefactor); /* -grad_B(V) */ Vec3 negGrad_BV = scale( sub(A, scale(B, AdB/lBl2)), negGradPrefactor); /* F1 */ Mat3 J_r1A = crossProdTransposedJacobian(r12, r23, 1); /* [J_r1(A)]^t */ /* [J_r1(B)]^t = 0*/ Vec3 F1 = matApply(J_r1A, negGrad_AV); /* F2 */ Mat3 J_r2A = crossProdTransposedJacobian(r12, r23, 2); /* [J_r2(A)]^t */ Mat3 J_r2B = crossProdTransposedJacobian(r23, r34, 1); /* [J_r2(B)]^t */ Vec3 F2 = add(matApply(J_r2A, negGrad_AV), matApply(J_r2B, negGrad_BV)); /* F4 (not F3 because that has two non-zero jacobi matrices, * whereas F4 has only one non-zero jacobi matrix, so it's * faster to compute)*/ /* [J_r4(A)]^t = 0*/ Mat3 J_r4B = crossProdTransposedJacobian(r23, r34, 3); /* [J_r4(B)]^t */ Vec3 F4 = matApply(J_r4B, negGrad_BV); /* -F3 */ Vec3 negF3 = add(add(F1, F2), F4); p1->F = add(p1->F, F1); p2->F = add(p2->F, F2); p3->F = sub(p3->F, negF3); p4->F = add(p4->F, F4); }