向量投影
/// <summary>
/// 计算空间向量在平面上的投影
/// </summary>
/// <param name="o">原点</param>
/// <param name="end">终点</param>
/// <param name="unit">投影平面的法向量</param>
/// <returns></returns>
static Vector3 CreateProjection(Vector3 o, Vector3 end, Vector3 unit)
{
unit = unit.Normalized();
Vector3 v = end-o;
var dotv = Vector3.Dot(v, unit);
var b = dotv * unit;
var retv = (v - b).Normalized();
return retv;
}
两个向量角度
static double GetTowNormalAngle(Vector3 v1, Vector3 v2)
{
v1.Normalize();
v2.Normalize();
var angle = v1.AngleBetween(v2) * 180 / Math.PI;
return angle;
}
两个向量投影角度
static double GetAngle(Vector3 v, Vector3 unitV, Vector3 unitN)
{
v.Normalize();
unitV.Normalize();
unitN.Normalize();
var dotv = Vector3.Dot(v, unitN);
var b = Vector3D.Multiply(dotv, unitN.ToVector3D()).ToVector3();
var retV = v - b;
var angle = retV.AngleBetween(unitV) * 180 / Math.PI;
return angle;
}
模型旋转移动
private void LeftMouse3DDown(object sender, RoutedEventArgs e)
{
if (e is Mouse3DEventArgs arg)
{
viewport = arg.Viewport;
Camera = viewport.Camera;
startPoint = arg.Position;//roate
startHitPoint = arg.HitTestResult.PointHit;//move
isCaptured = true;
arg.Handled = true;
var model = sender as MeshGeometryModel3D;
if (model != null && model.Material is DiffuseMaterial)
{
model.Material = DiffuseMaterials.Yellow;
}
}
}
private void LeftMouse3DUp(object sender, RoutedEventArgs e)
{
var model = sender as MeshGeometryModel3D;
if (isCaptured && e is Mouse3DEventArgs arg && model != null && model.Material is DiffuseMaterial)
{
model.Material = DiffuseMaterials.Red;
arg.Handled = true;
}
isCaptured = false;
viewport = null;
}
private void LeftMouse3DMove(object sender, RoutedEventArgs e)
{
if (isCaptured && e is Mouse3DEventArgs arg && arg.Viewport == viewport)
{
var mouse = arg.OriginalInputEventArgs as MouseEventArgs;
if (mouse == null)
return;
if (mouse.LeftButton == MouseButtonState.Pressed )
{
var newHit = viewport.UnProjectOnPlane(arg.Position, startHitPoint.ToPoint3D(), Camera.LookDirection);
if (newHit.HasValue)
{
var newPos = newHit.Value.ToVector3();
//newPos = new Vector3(newPos.X, startHitPoint.Y, newPos.Z); // trying to constraint elevation
var offset = newPos - startHitPoint;
startHitPoint = newPos;
currentTranslation.TranslationVector += offset;
UpdateTransform();
}
}
else
{
RotateTrackball(startPoint, arg.Position, currentTranslation.TranslationVector);
startPoint = arg.Position;
}
arg.Handled = true;
}
}
private static Vector3 ProjectToTrackball(System.Windows.Point point, double w, double h)
{
// Use the diagonal for scaling, making sure that the whole client area is inside the trackball
double r = Math.Sqrt((w * w) + (h * h)) / 2;
double x = (point.X - (w / 2)) / r;
double y = ((h / 2) - point.Y) / r;
double z2 = 1 - (x * x) - (y * y);
double z = z2 > 0 ? Math.Sqrt(z2) : 0;
return new Vector3((float)x, (float)y, (float)z);
}
private void RotateTrackball(System.Windows.Point p1, System.Windows.Point p2, Vector3 rotateAround)
{
Vector3 v1, v2;
if (ConstrainAxis.HasValue)
{
// preparing to compute the ratio to the screen
var diag = Math.Sqrt(
viewport.ActualWidth * viewport.ActualWidth +
viewport.ActualHeight * viewport.ActualHeight
);
// can we project the constraintAxis onto the view?
var t3 = Vector3.TransformCoordinate(ConstrainAxis.Value, Camera.CameraInternal.GetViewMatrix());
var dir = new Vector2(t3.X, t3.Y); // axis of Constraint in view coordinates
var pp1 = p1.ToVector2(); // computing distance perpendicular to axis in view coordinates
var r1 = pp1 - (pp1 * dir);
var pp2 = p2.ToVector2(); // computing distance perpendicular to axis in view coordinates
var r2 = pp2 - (pp2 * dir);
var angle = (r2.Length() - r1.Length()) / diag * 4;
currentRotation *= Matrix.RotationAxis(Vector3.Normalize(ConstrainAxis.Value), (float)(angle * this.RotationSensitivity * 5));
UpdateTransform();
}
else
{
v1 = ProjectToTrackball(p1, viewport.ActualWidth, viewport.ActualHeight);
v2 = ProjectToTrackball(p2, viewport.ActualWidth, viewport.ActualHeight);
// transform the trackball coordinates to view space
var viewZ = Camera.CameraInternal.LookDirection;
var viewX = Vector3.Cross(Camera.CameraInternal.UpDirection, viewZ);
var viewY = Vector3.Cross(viewX, viewZ);
viewX.Normalize();
viewY.Normalize();
viewZ.Normalize();
var u1 = (viewZ * v1.Z) + (viewX * v1.X) + (viewY * v1.Y);
var u2 = (viewZ * v2.Z) + (viewX * v2.X) + (viewY * v2.Y);
var axis = Vector3.Cross(u1, u2);
if (axis.LengthSquared() < 1e-8)
{
return;
}
var angle = u1.AngleBetween(u2);
currentRotation *= Matrix.RotationAxis(Vector3.Normalize(axis), (float)(angle * this.RotationSensitivity * 5));
UpdateTransform();
}
}
private void UpdateTransform()
{
totalTransform = currentRotation * currentTranslation;
foreach (var item in GroupCameraModel)
{
item.Transform = CameraModelTransform = new MatrixTransform3D(totalTransform.ToMatrix3D());
}
UpdateLight();
UpdateCameraData();
}
标签:Normalize,double,Vector3,算法,arg,var,viewport,3D
From: https://www.cnblogs.com/CloakBlowing/p/18027236