private static Point3D? CastRay_Cylinder(Point3D point, Vector3D direction, double radius, RayHitTestParameters mouseDownClickRay, RayHitTestParameters mouseDownCenterRay, RayHitTestParameters currentClickRay) { // Get points on the cylinder Point3D? mouseDownClickPoint = null; Point3D? mouseDownCenterPoint = null; Point3D? currentClickPoint = null; Point3D[] nearestCylinderPoints, nearestLinePoints; if (Math3D.GetClosestPoints_Cylinder_Line(out nearestCylinderPoints, out nearestLinePoints, point, direction, radius, currentClickRay.Origin, currentClickRay.Direction, Math3D.RayCastReturn.ClosestToRay)) { currentClickPoint = nearestCylinderPoints[0]; if (Math3D.GetClosestPoints_Cylinder_Line(out nearestCylinderPoints, out nearestLinePoints, point, direction, radius, mouseDownClickRay.Origin, mouseDownClickRay.Direction, Math3D.RayCastReturn.ClosestToRay)) { mouseDownClickPoint = nearestCylinderPoints[0]; if (Math3D.GetClosestPoints_Cylinder_Line(out nearestCylinderPoints, out nearestLinePoints, point, direction, radius, mouseDownCenterRay.Origin, mouseDownCenterRay.Direction, Math3D.RayCastReturn.ClosestToRay)) { mouseDownCenterPoint = nearestCylinderPoints[0]; } } } if (mouseDownCenterPoint == null || mouseDownClickPoint == null || currentClickPoint == null) { return currentClickPoint; // it doesn't matter if this one is null or not, the offset can't be determined, so just return the raw click value } // Circle only cared about an offset angle, but cylinder needs two things: // Offset line (the part of the offset that is parallel to the cylinder's axis) // Offset angle (the part of the offset that is perpendicular to the cylinder's axis) Vector3D offsetLinear = (mouseDownCenterPoint.Value - mouseDownClickPoint.Value).GetProjectedVector(direction); Quaternion offsetRadial = GetRotation_Circle(point, direction, mouseDownClickPoint.Value, mouseDownCenterPoint.Value); //TODO: Get the radial offset working as well (sphere is also messed up, the same fix should work for both) //TODO: See if this is the most effiecient way or not Transform3DGroup transform = new Transform3DGroup(); //transform.Children.Add(new RotateTransform3D(new QuaternionRotation3D(offsetRadial))); transform.Children.Add(new TranslateTransform3D(offsetLinear)); //TODO: Bring currentClickPoint into local coords, do the transform, then put it back into global coords // Find the point along the cylinder's axis that is nearest to the current click. This will become the center of the model coords Point3D modelCenter = Math3D.GetClosestPoint_Line_Point(point, direction, currentClickPoint.Value); // Shift the click point into model coords Vector3D modelClick = currentClickPoint.Value - modelCenter; // Adjust by the offset transform (needed to put into model coords, because there is a rotation) modelClick = transform.Transform(modelClick); // Now put back into world coords return modelCenter + modelClick; }
/// <summary> /// Takes the average velocity of the requested cells /// </summary> /// <remarks> /// This was written to assist with IFluidField.GetForce. I decided to not use the interface to give the caller /// the option of model or world coords. Also, there is more flexibility if multiple fields need to be stitched /// together. /// /// TODO: When this class implements viscosity, also implement IFluidField directly (and assume world coords) /// </remarks> public Vector3D[] GetFlowAtLocations(Point3D[] points, double radius) { //TODO: look at radius double fullSize = this.SizeWorld; double halfSize = fullSize / 2d; double cellSize = fullSize / _size; // This is to transform the point from world to model coords Transform3DGroup transformPoint = new Transform3DGroup(); transformPoint.Children.Add(new RotateTransform3D(new QuaternionRotation3D(this.RotationWorld.ToReverse()))); transformPoint.Children.Add(new TranslateTransform3D(this.PositionWorld.ToVector() * -1d)); transformPoint.Children.Add(new TranslateTransform3D(new Vector3D(halfSize, halfSize, halfSize))); // The point passed in is from -half to +half, but the ints are 0 to size // This is to transform the return velocity back to world coords RotateTransform3D transformVect = new RotateTransform3D(new QuaternionRotation3D(this.RotationWorld)); Vector3D[] retVal = new Vector3D[points.Length]; for (int cntr = 0; cntr < points.Length; cntr++) { // Convert into int positions Point3D transformed = transformPoint.Transform(points[cntr]); int x = Convert.ToInt32(Math.Round(transformed.X / cellSize)); int y = Convert.ToInt32(Math.Round(transformed.Y / cellSize)); int z = Convert.ToInt32(Math.Round(transformed.Z / cellSize)); int index = Get1DIndex(x, y, z); if (index < 0 || index >= _size1D) { // The point is outside this field retVal[cntr] = new Vector3D(0, 0, 0); } double negate = 1d; if (_blocked[index]) { // Blocked cells have the opposite velocity, so that they push back. But when reporting, it needs to be flipped back // so that it's more like the force felt at that point negate = -1d; } retVal[cntr] = transformVect.Transform(new Vector3D(_velocityX[index] * negate, _velocityY[index] * negate, _velocityZ[index] * negate)); } // Exit Function return retVal; }
private void btnBodyPropeller3_Click(object sender, RoutedEventArgs e) { //TODO: This is just a tweaked copy of 2 (I was feeling lazy). They should really be merged RemoveCurrentBody(); _world.Pause(); // Materials MaterialGroup materialsFluidBlade = new MaterialGroup(); // These blades are what the fluid model knows about, but newton will know about a more complex object materialsFluidBlade.Children.Add(new DiffuseMaterial(new SolidColorBrush(_colors.HullFace))); materialsFluidBlade.Children.Add(_colors.HullFaceSpecular); MaterialGroup materialsPhysics = new MaterialGroup(); // this is the material for the composite physics object materialsPhysics.Children.Add(new DiffuseMaterial(new SolidColorBrush(_colors.GhostBodyFace))); materialsPhysics.Children.Add(_colors.GhostBodySpecular); // Geometries MeshGeometry3D meshFluidBlade = new MeshGeometry3D(); MeshGeometry3D meshPhysicsBlade1 = null; MeshGeometry3D meshPhysicsBlade2 = null; MeshGeometry3D meshPhysicsBlade3 = null; MeshGeometry3D meshPhysicsCone = null; // Centered blade positions (these are defined once, then copies will be transformed and commited) Point3D[] bladePositionsFluid = new Point3D[4]; bladePositionsFluid[0] = new Point3D(-1d, .25d, 0d); bladePositionsFluid[1] = new Point3D(-1d, -.25d, 0d); bladePositionsFluid[2] = new Point3D(1d, -.25d, 0d); bladePositionsFluid[3] = new Point3D(1d, .25d, 0d); Point3D[] bladePositionsPhysics = new Point3D[2]; bladePositionsPhysics[0] = new Point3D(-1d, -.25d, -.05d); bladePositionsPhysics[1] = new Point3D(1d, .25d, .05d); // This tranform is throw away. It's just used to transform points Transform3DGroup transform = new Transform3DGroup(); transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(1, 0, 0), 90d + 5d))); // rotar tilt (the flow defaults to -x, so face them into the wind) transform.Children.Add(new TranslateTransform3D(new Vector3D(1d + .33d, 0, 0))); // pull away from the center a bit transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 0, 1), 90))); // I don't want it along X, I want it along Y // Fluid blade 1 meshFluidBlade.Positions.Add(transform.Transform(bladePositionsFluid[0])); meshFluidBlade.Positions.Add(transform.Transform(bladePositionsFluid[1])); meshFluidBlade.Positions.Add(transform.Transform(bladePositionsFluid[2])); meshFluidBlade.Positions.Add(transform.Transform(bladePositionsFluid[3])); meshFluidBlade.TriangleIndices.Add(0); meshFluidBlade.TriangleIndices.Add(1); meshFluidBlade.TriangleIndices.Add(2); meshFluidBlade.TriangleIndices.Add(2); meshFluidBlade.TriangleIndices.Add(3); meshFluidBlade.TriangleIndices.Add(0); // Physics blade 1 meshPhysicsBlade1 = UtilityWPF.GetCube_IndependentFaces(bladePositionsPhysics[0], bladePositionsPhysics[1]); CollisionHull collisionPhysicsBlade1 = CollisionHull.CreateBox(_world, 0, bladePositionsPhysics[1] - bladePositionsPhysics[0], transform.Value); Transform3D transformPhysicsBlade1 = transform.Clone(); transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(1, 0, 0), 120d))); // rotate the whole thing 120 degrees // Fluid blade 2 meshFluidBlade.Positions.Add(transform.Transform(bladePositionsFluid[0])); meshFluidBlade.Positions.Add(transform.Transform(bladePositionsFluid[1])); meshFluidBlade.Positions.Add(transform.Transform(bladePositionsFluid[2])); meshFluidBlade.Positions.Add(transform.Transform(bladePositionsFluid[3])); meshFluidBlade.TriangleIndices.Add(0 + 4); meshFluidBlade.TriangleIndices.Add(1 + 4); meshFluidBlade.TriangleIndices.Add(2 + 4); meshFluidBlade.TriangleIndices.Add(2 + 4); meshFluidBlade.TriangleIndices.Add(3 + 4); meshFluidBlade.TriangleIndices.Add(0 + 4); // Physics blade 2 meshPhysicsBlade2 = UtilityWPF.GetCube_IndependentFaces(bladePositionsPhysics[0], bladePositionsPhysics[1]); CollisionHull collisionPhysicsBlade2 = CollisionHull.CreateBox(_world, 0, bladePositionsPhysics[1] - bladePositionsPhysics[0], transform.Value); Transform3D transformPhysicsBlade2 = transform.Clone(); transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(1, 0, 0), 120d))); // rotate the whole thing 120 degrees // Fluid blade 3 meshFluidBlade.Positions.Add(transform.Transform(bladePositionsFluid[0])); meshFluidBlade.Positions.Add(transform.Transform(bladePositionsFluid[1])); meshFluidBlade.Positions.Add(transform.Transform(bladePositionsFluid[2])); meshFluidBlade.Positions.Add(transform.Transform(bladePositionsFluid[3])); meshFluidBlade.TriangleIndices.Add(0 + 8); meshFluidBlade.TriangleIndices.Add(1 + 8); meshFluidBlade.TriangleIndices.Add(2 + 8); meshFluidBlade.TriangleIndices.Add(2 + 8); meshFluidBlade.TriangleIndices.Add(3 + 8); meshFluidBlade.TriangleIndices.Add(0 + 8); // Physics blade 3 meshPhysicsBlade3 = UtilityWPF.GetCube_IndependentFaces(bladePositionsPhysics[0], bladePositionsPhysics[1]); CollisionHull collisionPhysicsBlade3 = CollisionHull.CreateBox(_world, 0, bladePositionsPhysics[1] - bladePositionsPhysics[0], transform.Value); Transform3D transformPhysicsBlade3 = transform.Clone(); //TODO: Make an overload on some of the geometry builders that take a tranform //meshPhysicsCone = UtilityWPF.GetCone_AlongX(); // Geometry Models GeometryModel3D geometryFluidBlade = new GeometryModel3D(); geometryFluidBlade.Material = materialsFluidBlade; geometryFluidBlade.BackMaterial = materialsFluidBlade; geometryFluidBlade.Geometry = meshFluidBlade; GeometryModel3D geometryPhysicsBlade1 = new GeometryModel3D(); geometryPhysicsBlade1.Material = materialsPhysics; geometryPhysicsBlade1.BackMaterial = materialsPhysics; geometryPhysicsBlade1.Geometry = meshPhysicsBlade1; geometryPhysicsBlade1.Transform = transformPhysicsBlade1; GeometryModel3D geometryPhysicsBlade2 = new GeometryModel3D(); geometryPhysicsBlade2.Material = materialsPhysics; geometryPhysicsBlade2.BackMaterial = materialsPhysics; geometryPhysicsBlade2.Geometry = meshPhysicsBlade2; geometryPhysicsBlade2.Transform = transformPhysicsBlade2; GeometryModel3D geometryPhysicsBlade3 = new GeometryModel3D(); geometryPhysicsBlade3.Material = materialsPhysics; geometryPhysicsBlade3.BackMaterial = materialsPhysics; geometryPhysicsBlade3.Geometry = meshPhysicsBlade3; geometryPhysicsBlade3.Transform = transformPhysicsBlade3; // Model Visual ModelVisual3D modelFluidBlade = new ModelVisual3D(); modelFluidBlade.Content = geometryFluidBlade; modelFluidBlade.Transform = _modelOrientationTrackball.Transform; ModelVisual3D modelPysicsBlade1 = new ModelVisual3D(); modelPysicsBlade1.Content = geometryPhysicsBlade1; modelPysicsBlade1.Transform = _modelOrientationTrackball.Transform; ModelVisual3D modelPysicsBlade2 = new ModelVisual3D(); modelPysicsBlade2.Content = geometryPhysicsBlade2; modelPysicsBlade2.Transform = _modelOrientationTrackball.Transform; ModelVisual3D modelPysicsBlade3 = new ModelVisual3D(); modelPysicsBlade3.Content = geometryPhysicsBlade3; modelPysicsBlade3.Transform = _modelOrientationTrackball.Transform; CollisionHull collisionHull = CollisionHull.CreateCompoundCollision(_world, 0, new CollisionHull[] { collisionPhysicsBlade1, collisionPhysicsBlade2, collisionPhysicsBlade3 }); // Body _body = new Body(collisionHull, _modelOrientationTrackball.Transform.Value, 1, null); collisionHull.Dispose(); collisionPhysicsBlade1.Dispose(); collisionPhysicsBlade2.Dispose(); collisionPhysicsBlade3.Dispose(); // Hull _fluidHull = new FluidHull(); _fluidHull.Triangles = FluidHull.FluidTriangle.GetTrianglesFromMesh(meshFluidBlade); _fluidHull.IsClosedConvexInUniformField = false; _fluidHull.Transform = _modelOrientationTrackball.Transform; _fluidHull.Field = _field; _fluidHull.Body = _body; // Wireframe ScreenSpaceLines3D modelWireframe = GetModelWireframe(_fluidHull); modelWireframe.Transform = _modelOrientationTrackball.Transform; _viewport.Children.Add(modelWireframe); // Rope Point3D bodyAttachPoint = _modelOrientationTrackball.Transform.Transform(new Point3D(.25, 0, 0)); Point3D anchorPoint = _modelOrientationTrackball.Transform.Transform(new Point3D(3, 0, 0)); //Point3D bodyAttachPoint = _modelOrientationTrackball.Transform.Transform(new Point3D(0, 0, 0)); //Point3D anchorPoint = _modelOrientationTrackball.Transform.Transform(new Point3D(.33, 0, 0)); AddRope(bodyAttachPoint, anchorPoint, Math1D.DegreesToRadians(1d)); // Add to the viewport _viewport.Children.Add(modelFluidBlade); _viewport.Children.Add(modelPysicsBlade1); _viewport.Children.Add(modelPysicsBlade2); _viewport.Children.Add(modelPysicsBlade3); // Finish setting up the body _body.Visuals = new Visual3D[] { modelPysicsBlade1, modelPysicsBlade2, modelPysicsBlade3, modelWireframe, modelFluidBlade }; _body.ApplyForceAndTorque += new EventHandler<BodyApplyForceAndTorqueArgs>(Body_ApplyForceAndTorque); _body.BodyMoved += new EventHandler(Body_BodyMoved); _world.UnPause(); }
private static void GetDome(ref int pointOffset, MeshGeometry3D geometry, Point[] pointsTheta, Transform3D transform, int numSegmentsPhi, double radiusX, double radiusY, double radiusZ) { #region Initial calculations // NOTE: There is one more than what the passed in Point[] pointsPhi = new Point[numSegmentsPhi + 1]; pointsPhi[0] = new Point(1d, 0d); // along the equator pointsPhi[numSegmentsPhi] = new Point(0d, 1d); // north pole if (pointsPhi.Length > 2) { // Need to go from 0 to half pi double halfPi = Math.PI * .5d; double deltaPhi = halfPi / pointsPhi.Length; // there is one more point than numSegmentsPhi for (int cntr = 1; cntr < numSegmentsPhi; cntr++) { double phi = deltaPhi * cntr; // phi goes from 0 to pi for a full sphere, so start halfway up pointsPhi[cntr] = new Point(Math.Cos(phi), Math.Sin(phi)); } } #endregion #region Positions/Normals // Can't use all of the transform passed in for the normal, because translate portions will skew the normal funny Transform3DGroup normalTransform = new Transform3DGroup(); if (transform is Transform3DGroup) { foreach (var subTransform in ((Transform3DGroup)transform).Children) { if (!(subTransform is TranslateTransform3D)) { normalTransform.Children.Add(subTransform); } } } else if (transform is TranslateTransform3D) { normalTransform.Children.Add(Transform3D.Identity); } else { normalTransform.Children.Add(transform); } //for (int phiCntr = 0; phiCntr < numSegmentsPhi; phiCntr++) // The top point will be added after this loop for (int phiCntr = pointsPhi.Length - 1; phiCntr > 0; phiCntr--) { for (int thetaCntr = 0; thetaCntr < pointsTheta.Length; thetaCntr++) { // Phi points are going from bottom to equator. Point3D point = new Point3D( radiusX * pointsTheta[thetaCntr].X * pointsPhi[phiCntr].Y, radiusY * pointsTheta[thetaCntr].Y * pointsPhi[phiCntr].Y, radiusZ * pointsPhi[phiCntr].X); geometry.Positions.Add(transform.Transform(point)); //TODO: For a standalone dome, the bottom rings will point straight out. But for something like a snow cone, the normal will have to be averaged with the cone geometry.Normals.Add(normalTransform.Transform(point).ToVector().ToUnit()); // the normal is the same as the point for a sphere (but no tranlate transform) } } // This is north pole point geometry.Positions.Add(transform.Transform(new Point3D(0, 0, radiusZ))); geometry.Normals.Add(transform.Transform(new Vector3D(0, 0, 1))); #endregion #region Triangles - Rings int zOffsetBottom = pointOffset; int zOffsetTop; for (int phiCntr = 0; phiCntr < numSegmentsPhi - 1; phiCntr++) // The top cone will be added after this loop { zOffsetTop = zOffsetBottom + pointsTheta.Length; for (int thetaCntr = 0; thetaCntr < pointsTheta.Length - 1; thetaCntr++) { // Top/Left triangle geometry.TriangleIndices.Add(zOffsetBottom + thetaCntr + 0); geometry.TriangleIndices.Add(zOffsetTop + thetaCntr + 1); geometry.TriangleIndices.Add(zOffsetTop + thetaCntr + 0); // Bottom/Right triangle geometry.TriangleIndices.Add(zOffsetBottom + thetaCntr + 0); geometry.TriangleIndices.Add(zOffsetBottom + thetaCntr + 1); geometry.TriangleIndices.Add(zOffsetTop + thetaCntr + 1); } // Connecting the last 2 points to the first 2 // Top/Left triangle geometry.TriangleIndices.Add(zOffsetBottom + (pointsTheta.Length - 1) + 0); geometry.TriangleIndices.Add(zOffsetTop); // wrapping back around geometry.TriangleIndices.Add(zOffsetTop + (pointsTheta.Length - 1) + 0); // Bottom/Right triangle geometry.TriangleIndices.Add(zOffsetBottom + (pointsTheta.Length - 1) + 0); geometry.TriangleIndices.Add(zOffsetBottom); geometry.TriangleIndices.Add(zOffsetTop); // Prep for the next ring zOffsetBottom = zOffsetTop; } #endregion #region Triangles - Cap int topIndex = geometry.Positions.Count - 1; for (int cntr = 0; cntr < pointsTheta.Length - 1; cntr++) { geometry.TriangleIndices.Add(zOffsetBottom + cntr + 0); geometry.TriangleIndices.Add(zOffsetBottom + cntr + 1); geometry.TriangleIndices.Add(topIndex); } // The last triangle links back to zero geometry.TriangleIndices.Add(zOffsetBottom + pointsTheta.Length - 1 + 0); geometry.TriangleIndices.Add(zOffsetBottom + 0); geometry.TriangleIndices.Add(topIndex); #endregion pointOffset = geometry.Positions.Count; }
/// <summary> /// Call this to apply the thruster force to the physics body /// </summary> public void ApplyForce(double percentMax, Transform3D worldTransform, BodyForceEventArgs e) { if (!_isFiring) // the property set will make sure the visual is no longer known to the viewport { return; } double actualForce = _forceStrength * percentMax; if (_fuelTank != null) { #region Use Fuel if (_fuelTank.QuantityCurrent > 0d) { double fuelToUse = actualForce * e.ElapsedTime * _fuelToThrustRatio; double fuelUnused = _fuelTank.RemoveQuantity(fuelToUse, false); if (fuelUnused > 0d) { // Not enough fuel, reduce the amount of force actualForce -= fuelUnused / (e.ElapsedTime * _fuelToThrustRatio); } } else { actualForce = 0d; } #endregion } if (actualForce == 0d) { // No force to apply //TODO: Play a clicking sound, or some kind of error tone //TODO: Don't show the flames return; } // Figure out how to place it in world coords Transform3DGroup transform = new Transform3DGroup(); // I don't use _initialRotate, because that's for the visual (it's always created along the X axis, but _force is already stored correctly) transform.Children.Add(this.BodyOffset); transform.Children.Add(worldTransform); Vector3D positionOnBodyWorld = transform.Transform(new Point3D(0, 0, 0)).ToVector(); // note that I have to use a point (transform acts different on points than vectors) Vector3D deltaForceWorld = transform.Transform(_forceDirection); deltaForceWorld.Normalize(); deltaForceWorld *= actualForce; // Apply the force e.AddForceAtPoint(deltaForceWorld, positionOnBodyWorld); }
/// <summary> /// This is exposed so it can be called externally on a separate thread, then call this asteroid's constructor /// in the main thread once this returns /// </summary> public static ITriangleIndexed[] GetHullTriangles(double radius) { const int NUMPOINTS = 60; // too many, and it looks too perfect Exception lastException = null; Random rand = StaticRandom.GetRandomForThread(); for (int infiniteLoopCntr = 0; infiniteLoopCntr < 50; infiniteLoopCntr++) // there is a slight chance that the convex hull generator will choke on the inputs. If so just retry { try { double minRadius = radius * .9d; Point3D[] points = new Point3D[NUMPOINTS]; // Make a point cloud for (int cntr = 0; cntr < NUMPOINTS; cntr++) { points[cntr] = Math3D.GetRandomVector_Spherical(minRadius, radius).ToPoint(); } // Squash it Transform3DGroup transform = new Transform3DGroup(); transform.Children.Add(new ScaleTransform3D(.33d + (rand.NextDouble() * .66d), .33d + (rand.NextDouble() * .66d), 1d)); // squash it transform.Children.Add(new RotateTransform3D(new QuaternionRotation3D(Math3D.GetRandomRotation()))); // giving it a random rotation, since it's always squashed along the same axiis transform.Transform(points); // Get a hull that wraps those points ITriangleIndexed[] retVal = Math3D.GetConvexHull(points.ToArray()); // Get rid of unused points retVal = TriangleIndexed.Clone_CondensePoints(retVal); // Exit Function return retVal; } catch (Exception ex) { lastException = ex; } } throw new ApplicationException(lastException.ToString()); }
public static MeshGeometry3D GetCylinder_AlongX(int numSegments, double radius, double height, RotateTransform3D rotateTransform = null) { //NOTE: All the other geometries in this class are along the x axis, so I want to follow suit, but I think best along the z axis. So I'll transform the points before commiting them to the geometry //TODO: This is so close to GetMultiRingedTube, the only difference is the multi ring tube has "hard" faces, and this has "soft" faces (this one shares points and normals, so the lighting is smoother) if (numSegments < 3) { throw new ArgumentException("numSegments must be at least 3: " + numSegments.ToString(), "numSegments"); } MeshGeometry3D retVal = new MeshGeometry3D(); #region Initial calculations Transform3DGroup transform = new Transform3DGroup(); transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), 90d))); if (rotateTransform != null) { // This is in case they wanted oriented other than along the x axis transform.Children.Add(rotateTransform); } double halfHeight = height / 2d; Point[] points = Math2D.GetCircle_Cached(numSegments); #endregion #region Side for (int cntr = 0; cntr < numSegments; cntr++) { retVal.Positions.Add(transform.Transform(new Point3D(points[cntr].X * radius, points[cntr].Y * radius, -halfHeight))); retVal.Positions.Add(transform.Transform(new Point3D(points[cntr].X * radius, points[cntr].Y * radius, halfHeight))); retVal.Normals.Add(transform.Transform(new Vector3D(points[cntr].X, points[cntr].Y, 0d))); // the normals point straight out of the side retVal.Normals.Add(transform.Transform(new Vector3D(points[cntr].X, points[cntr].Y, 0d))); } for (int cntr = 0; cntr < numSegments - 1; cntr++) { // 0,2,3 retVal.TriangleIndices.Add((cntr * 2) + 0); retVal.TriangleIndices.Add((cntr * 2) + 2); retVal.TriangleIndices.Add((cntr * 2) + 3); // 0,3,1 retVal.TriangleIndices.Add((cntr * 2) + 0); retVal.TriangleIndices.Add((cntr * 2) + 3); retVal.TriangleIndices.Add((cntr * 2) + 1); } // Connecting the last 2 points to the first 2 // last,0,1 int offset = (numSegments - 1) * 2; retVal.TriangleIndices.Add(offset + 0); retVal.TriangleIndices.Add(0); retVal.TriangleIndices.Add(1); // last,1,last+1 retVal.TriangleIndices.Add(offset + 0); retVal.TriangleIndices.Add(1); retVal.TriangleIndices.Add(offset + 1); #endregion // Caps int pointOffset = retVal.Positions.Count; //NOTE: The normals are backward from what you'd think GetCylinder_AlongXSprtEndCap(ref pointOffset, retVal, points, new Vector3D(0, 0, 1), radius, radius, -halfHeight, transform); GetCylinder_AlongXSprtEndCap(ref pointOffset, retVal, points, new Vector3D(0, 0, -1), radius, radius, halfHeight, transform); // Exit Function //retVal.Freeze(); return retVal; }
private Point3D[] GetVoronoiCtrlPoints_AroundLine(Point3D lineStart, Point3D lineStop) { const int MIN = 5; double lineLength = (lineStop - lineStart).Length; double drift = lineLength / 20; bool evenDist = chkOneShotPlateEvenDistribute.IsChecked.Value; List<Point3D> points = new List<Point3D>(); // Plates if (radOneShot_SinglePlate.IsChecked.Value) { points.AddRange(GetVoronoiCtrlPoints_AroundLine_Plate(lineLength * trkOneShotPercentDist1.Value, 0, evenDist, drift)); } else if (radOneShot_TwoPlates.IsChecked.Value) { points.AddRange(GetVoronoiCtrlPoints_AroundLine_Plate(lineLength * trkOneShotPercentDist1.Value, -lineLength / 6, evenDist, drift)); points.AddRange(GetVoronoiCtrlPoints_AroundLine_Plate(lineLength * trkOneShotPercentDist2.Value, lineLength / 6, evenDist, drift)); } else if (radOneShot_ThreePlates.IsChecked.Value) { points.AddRange(GetVoronoiCtrlPoints_AroundLine_Plate(lineLength * trkOneShotPercentDist1.Value, -lineLength / 4, evenDist, drift)); points.AddRange(GetVoronoiCtrlPoints_AroundLine_Plate(lineLength * trkOneShotPercentDist2.Value, 0, evenDist, drift)); points.AddRange(GetVoronoiCtrlPoints_AroundLine_Plate(lineLength * trkOneShotPercentDist3.Value, lineLength / 4, evenDist, drift)); } else { throw new ApplicationException("Unknown plate configuration"); } // Center line if (radOneShot_LineNone.IsChecked.Value) { } else if (radOneShot_LineAbove.IsChecked.Value) { points.AddRange(GetVoronoiCtrlPoints_AroundLine_CenterLine(new[] { -lineLength / 4 }, drift * 2)); } else if (radOneShot_LineMiddle.IsChecked.Value) { points.AddRange(GetVoronoiCtrlPoints_AroundLine_CenterLine(new[] { 0d }, drift * 2)); } else if (radOneShot_LineBelow.IsChecked.Value) { points.AddRange(GetVoronoiCtrlPoints_AroundLine_CenterLine(new[] { lineLength / 4 }, drift * 2)); } else if (radOneShot_LineSeveral.IsChecked.Value) { var zs = Enumerable.Range(0, StaticRandom.Next(1, 5)). Select(o => StaticRandom.NextDouble(-lineLength / 2, lineLength / 2)); points.AddRange(GetVoronoiCtrlPoints_AroundLine_CenterLine(zs, drift * 2)); } else { throw new ApplicationException("Unknown centerline configuration"); } // The voronoi algrorithm fails if there aren't at least 5 points (really should fix that). So add points that are // way away from the hull. This will make the voronoi algorithm happy, and won't affect the local results if (points.Count < MIN) { points.AddRange(Enumerable.Range(0, MIN - points.Count). Select(o => Math3D.GetRandomVector_Spherical_Shell(lineLength * 20).ToPoint())); } // Rotate/Translate Quaternion roation = Math3D.GetRotation(new Vector3D(0, 0, 1), lineStop - lineStart); Point3D centerPoint = Math3D.GetCenter(new[] { lineStart, lineStop }); Transform3DGroup transform = new Transform3DGroup(); transform.Children.Add(new RotateTransform3D(new QuaternionRotation3D(roation))); transform.Children.Add(new TranslateTransform3D(centerPoint.X, centerPoint.Y, centerPoint.Z)); return points.Select(o => transform.Transform(o)). ToArray(); }
/// <summary> /// Make a few (2 to 6) control points radially around the line. All in a plane /// </summary> /// <remarks> /// The voronoi algorithm requires at least 4 (probably not coplanar). So if you want fewer than that, extra points /// are created away from the hull /// </remarks> private static Point3D[] GetVoronoiCtrlPoints_AroundLine_Simple(Point3D lineStart, Point3D lineStop, int count) { const int MIN = 5; //double radius = (lineStop - lineStart).Length * .5; double radius = (lineStop - lineStart).Length * .1; var points = Enumerable.Range(0, count). Select(o => Math3D.GetRandomVector_Circular_Shell(radius).ToPoint()); //Select(o => Math3D.GetRandomVector_Spherical(radius).ToPoint()); // The voronoi algrorithm fails if there aren't at least 5 points (really should fix that). So add points that are // way away from the hull. This will make the voronoi algorithm happy, and won't affect the local results if (count < MIN) { points = points.Concat( Enumerable.Range(0, MIN - count). //Select(o => Math3D.GetRandomVector_Circular_Shell(radius * 100).ToPoint()) Select(o => Math3D.GetRandomVector_Spherical_Shell(radius * 20).ToPoint()) ); } //points = points.Select(o => new Point3D(o.X, o.Y, Math1D.GetNearZeroValue(radius / 20))); // the voronoi can't handle coplanar input points = points.Select(o => o + Math3D.GetRandomVector_Spherical(radius / 20)); // the voronoi can't handle coplanar input // This will cause a cylinder core to be cut out, but only if the other points are ringed around (if they clump around one angle, then this won't look right) //points = UtilityCore.Iterate<Point3D>(points, Math3D.GetRandomVector_Spherical(radius / 10).ToPoint()); // Rotate/Translate Quaternion roation = Math3D.GetRotation(new Vector3D(0, 0, 1), lineStop - lineStart); Point3D centerPoint = Math3D.GetCenter(new[] { lineStart, lineStop }); Transform3DGroup transform = new Transform3DGroup(); transform.Children.Add(new RotateTransform3D(new QuaternionRotation3D(roation))); transform.Children.Add(new TranslateTransform3D(centerPoint.X, centerPoint.Y, centerPoint.Z)); points = points.Select(o => transform.Transform(o)); return points.ToArray(); }
public ConverterRadiationToEnergy(EditorOptions options, ItemOptions itemOptions, ConverterRadiationToEnergyDNA dna, IContainer energyTanks, RadiationField radiationField) : base(options, dna, itemOptions.SolarPanel_Damage.HitpointMin, itemOptions.SolarPanel_Damage.HitpointSlope, itemOptions.SolarPanel_Damage.Damage) { _itemOptions = itemOptions; _energyTanks = energyTanks; _radiationField = radiationField; this.Design = new ConverterRadiationToEnergyDesign(options, true, dna.Shape); this.Design.SetDNA(dna); this.ClarityPercent_Front = 1d; this.ClarityPercent_Back = 1d; Point3D center; Vector3D normal; GetStats(out _mass, out center, out normal, out _scaleActual); // Store the center and normals Transform3DGroup transform = new Transform3DGroup(); transform.Children.Add(new RotateTransform3D(new QuaternionRotation3D(dna.Orientation))); transform.Children.Add(new TranslateTransform3D(dna.Position.ToVector())); _centerPoint = transform.Transform(center); _normalFront = transform.Transform(normal); _normalBack = transform.Transform(normal * -1d); }
private void ResetBtnLocation(Point3D point) { Model3D m = (Model3D)(((Model3DGroup)grpMain.Children[0]).Children[0]); Transform3DGroup tgp = new Transform3DGroup(); tgp.Children.Add(grpMain.Transform); tgp.Children.Add(m.Transform); GeneralTransform3DTo2D gt = lvMain.TransformToAncestor(vpMain);//vpmain.TransformToDescendant(...); Point p = gt.Transform(tgp.Transform(point)); Canvas.SetLeft(btnTest, p.X); Canvas.SetTop(btnTest, p.Y); btnTest.Content = p.X + "," + p.Y; }
public void rotatePoints(double nextAngleXY, double nextAngleXZ, double nextAngleYZ) { if (nextAngleXY - angleXY != 0 || nextAngleXZ - angleXZ != 0 || nextAngleYZ - angleYZ != 0) { var group = new Transform3DGroup(); var myRotateTransformZ = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 0, 1), nextAngleXY-angleXY), currentPosition); group.Children.Add((myRotateTransformZ)); /*var myRotateTransformY = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), nextAngleXZ - angleXZ), currentPosition); group.Children.Add((myRotateTransformY)); var myRotateTransformX = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(1, 0, 0), nextAngleYZ - angleYZ), currentPosition); group.Children.Add((myRotateTransformX));*/ for (var i = 0; i < trolley.Count(); i++) { trolley[i] = group.Transform(trolley[i]); } angleXY = nextAngleXY; angleXZ = nextAngleXZ; angleYZ = nextAngleYZ; } }
private void moveToAngles(double alpha, double beta, double gamma) { RotateTransform3D bodyCoxaTransform = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 0, 1), alpha)); bodyCoxaTransform.CenterX = 0; bodyCoxaTransform.CenterY = 0; bodyCoxaTransform.CenterZ = 0; Model.Transform = bodyCoxaTransform; RotateTransform3D coxaFemurTransform = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), beta)); coxaFemurTransform.CenterX = bodyCoxaLen; coxaFemurTransform.CenterY = 0; coxaFemurTransform.CenterZ = 0; femurTibiaLink.Model.Transform = coxaFemurTransform; femurTibiaJoint.Model.Transform = coxaFemurTransform; foot.Model.Transform = coxaFemurTransform; var group3Dtransformation = new Transform3DGroup(); group3Dtransformation.Children.Add(femurTibiaLink.Model.Transform); Point3D origin = group3Dtransformation.Transform(new Point3D(bodyCoxaLen, 0, femurLen)); RotateTransform3D femurTibiaTransform = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), gamma)); femurTibiaTransform.CenterX = origin.X; femurTibiaTransform.CenterY = origin.Y; femurTibiaTransform.CenterZ = origin.Z; group3Dtransformation.Children.Add(femurTibiaTransform); tibiaFootLink.Model.Transform = group3Dtransformation; foot.Model.Transform = group3Dtransformation; var p = new Point3D(bodyCoxaJoint.Point2.X, bodyCoxaJoint.Point2.Y, bodyCoxaJoint.Point2.Z); p.Offset(0, 0, 1.5 * jointDiameter); coxaAngleLabel.Position = p; coxaAngleLabel.Text = String.Format("{0:N1}°", alpha); var q = new Point3D(coxaFemurTransform.CenterX, coxaFemurTransform.CenterY, coxaFemurTransform.CenterZ); q.Offset(0,0, -2 * jointDiameter); femurAngleLabel.Transform = bodyCoxaTransform; femurAngleLabel.Position = q; femurAngleLabel.Text = String.Format("{0:N1}°", beta); var r = new Point3D(femurTibiaTransform.CenterX, femurTibiaTransform.CenterY, femurTibiaTransform.CenterZ); r.Offset(0, 0, 1.5 * jointDiameter); tibiaAngleLabel.Position = r; tibiaAngleLabel.Transform = bodyCoxaTransform; tibiaAngleLabel.Text = String.Format("{0:N1}°", gamma); // coxaFemurConstraint.Transform = bodyCoxaTransform; }
/// <summary> /// This defines the back side of a cylinder /// </summary> private static Geometry3D GetGeometry(int numSegments, double thetaOffset, double height, double radius, double translate) { double thetaStart = 270 - thetaOffset; double thetaStop = 270 + thetaOffset; MeshGeometry3D retVal = new MeshGeometry3D(); #region Initial calculations // The rest of this method has height along Z, but the final needs to go along Y Transform3DGroup transform = new Transform3DGroup(); transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(1, 0, 0), 90d))); //transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 0, 1), 180d))); transform.Children.Add(new TranslateTransform3D(0, 0, translate)); double halfHeight = height / 2d; Point[] points = new Point[numSegments]; double deltaTheta = Math1D.DegreesToRadians((thetaStop - thetaStart) / (numSegments - 1)); //NOTE: This will fail if theta start/stop goes past 0/360 double theta = Math1D.DegreesToRadians(thetaStart); for (int cntr = 0; cntr < numSegments; cntr++) { points[cntr] = new Point(Math.Cos(theta) * radius, Math.Sin(theta) * radius); theta += deltaTheta; } #endregion for (int cntr = 0; cntr < numSegments; cntr++) { retVal.Positions.Add(transform.Transform(new Point3D(points[cntr].X, points[cntr].Y, -halfHeight))); retVal.Positions.Add(transform.Transform(new Point3D(points[cntr].X, points[cntr].Y, halfHeight))); retVal.Normals.Add(transform.Transform(new Vector3D(-points[cntr].X, -points[cntr].Y, 0d))); // the normals point straight in from the side retVal.Normals.Add(transform.Transform(new Vector3D(-points[cntr].X, -points[cntr].Y, 0d))); double coord = Convert.ToDouble(cntr) / Convert.ToDouble(numSegments - 1); retVal.TextureCoordinates.Add(new Point(coord, 0)); retVal.TextureCoordinates.Add(new Point(coord, 1)); } for (int cntr = 0; cntr < numSegments - 1; cntr++) { // 0,2,3 retVal.TriangleIndices.Add((cntr * 2) + 0); retVal.TriangleIndices.Add((cntr * 2) + 3); retVal.TriangleIndices.Add((cntr * 2) + 2); // 0,3,1 retVal.TriangleIndices.Add((cntr * 2) + 0); retVal.TriangleIndices.Add((cntr * 2) + 1); retVal.TriangleIndices.Add((cntr * 2) + 3); } return retVal; }
public void LoadModel(string path, bool transformYup, double scale) { var mod = ModelImporter.Load(path); if (mod == null || mod.Children.Count == 0) return; var model = (mod.Children[0] as GeometryModel3D); if (model == null) return; var mesh = model.Geometry as MeshGeometry3D; if (mesh == null) return; var transform = new Transform3DGroup(); if (transformYup) transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(1, 0, 0), 90))); transform.Children.Add(new ScaleTransform3D(scale, scale, scale)); for (int i = 0; i < mesh.Positions.Count; i++) mesh.Positions[i] = transform.Transform(mesh.Positions[i]); ScaleHeightOnly = false; Geometry = mesh; }
/// <summary> /// Each hit line should create a cone of probability to place control points onto /// Once a point on the surface of a cone is chosen, choose a couple more on that circle /// </summary> private static Point3D[] GetVoronoiCtrlPoints_AroundLine_Cone(Point3D lineStart, Point3D lineStop, int count, double entryRadius, double exitRadius, double maxAxisLength) { // Figure out where on the axis the control point ring should go (the bell has a spike around 30% in) double axisPercent = StaticRandomWPF.NextBell(_coneAxisBell.Value); Vector3D axis = lineStop - lineStart; double axisLength = axis.Length; Point3D ringCenter = lineStart + (axis * axisPercent); // Figure out the radius of the cone at this point double exitRadiusAdjusted = (axisLength / maxAxisLength) * exitRadius; double ringRadius = UtilityCore.GetScaledValue(entryRadius, exitRadiusAdjusted, 0, 1, axisPercent); // Get some points var points = Enumerable.Range(0, count). Select(o => Math3D.GetRandomVector_Circular_Shell(ringRadius).ToPoint()); //TODO: Figure out the minimum to shift by //double shiftRadius = Math.Max(.01, ringRadius / 20); double shiftRadius = ringRadius / 20; points = points.Select(o => o + Math3D.GetRandomVector_Spherical(shiftRadius)); // the voronoi can't handle coplanar input // Rotate/Translate Quaternion roation = Math3D.GetRotation(new Vector3D(0, 0, 1), axis); Transform3DGroup transform = new Transform3DGroup(); transform.Children.Add(new RotateTransform3D(new QuaternionRotation3D(roation))); transform.Children.Add(new TranslateTransform3D(ringCenter.X, ringCenter.Y, ringCenter.Z)); points = points.Select(o => transform.Transform(o)); return points.ToArray(); }
private void MoveCameraAroundCenter(double leftRight, double topDown) { // Use WPF maths for camera rotation. // It is slower than using Matrix4F and Vector4F, // but camera calculations are only done once per camera move Transform3DGroup tg = new Transform3DGroup(); //left/right drags rotate around the camera's up vector Vector3D leftRightRotationAxis = new Vector3D(Up.X, Up.Y, Up.Z); //top/down drags rotate around the vector that is perpendicular //to both Up and Eye (camera location) - their cross product Vector3D topDownRotationAxis = Vector3D.CrossProduct( leftRightRotationAxis, new Vector3D(Eye.X, Eye.Y, Eye.Z)); tg.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(leftRightRotationAxis, leftRight))); tg.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(topDownRotationAxis, topDown))); Vector3D newEye = tg.Transform(new Vector3D(Eye.X, Eye.Y, Eye.Z)); Vector3D newUp = tg.Transform(new Vector3D(Up.X, Up.Y, Up.Z)); Eye.X = (float)newEye.X; Eye.Y = (float)newEye.Y; Eye.Z = (float)newEye.Z; Up.X = (float)newUp.X; Up.Y = (float)newUp.Y; Up.Z = (float)newUp.Z; effects.ViewMatrix = DXUtil.Camera.MatrixLookAtLH(Eye, At, Up); }
private void FireRaySprtShootBall() { Vector3D velocity = _rayDirection.ToUnit() * trkBulletSpeed.Value; DoubleVector directionFacing = new DoubleVector(velocity, Math3D.GetArbitraryOrhonganal(velocity)); switch (cboLeftBallType.Text) { case "Nerf": #region Nerf AddCannonBall( CollisionShapeType.Cylinder, Colors.Coral, new Vector3D(.75d, 5d, 0d), // x is radius, y is height .1d, _rayPoint, velocity, new Vector3D(), directionFacing); #endregion break; case "Pellet": #region Pellet AddCannonBall( CollisionShapeType.Sphere, Colors.SteelBlue, new Vector3D(.5d, .5d, .5d), 2d, _rayPoint, velocity, new Vector3D(), directionFacing); #endregion break; case "Slug": #region Slug AddCannonBall( CollisionShapeType.Cylinder, Colors.DimGray, new Vector3D(.5d, .8d, 0d), // x is radius, y is height 6d, _rayPoint, velocity, new Vector3D(), directionFacing); #endregion break; case "Baseball": #region Baseball AddCannonBall( CollisionShapeType.Sphere, Colors.GhostWhite, new Vector3D(2d, 2d, 2d), 5d, _rayPoint, velocity, new Vector3D(), directionFacing); #endregion break; case "Cannon": #region Cannon AddCannonBall( CollisionShapeType.Sphere, Color.FromArgb(255, 45, 45, 32), new Vector3D(2d, 2d, 2d), 15d, _rayPoint, velocity, new Vector3D(), directionFacing); #endregion break; case "Wrecker": #region Wrecker AddCannonBall( CollisionShapeType.Sphere, Color.FromArgb(255, 50, 15, 15), new Vector3D(4d, 4d, 4d), 60d, _rayPoint, velocity, new Vector3D(), directionFacing); #endregion break; case "Shotgun": #region Shotgun // Build a transform to go from origin to camera DoubleVector originDirFacing = new DoubleVector(0, 0, 1, 0, 1, 0); Quaternion rotationToCameraRay = originDirFacing.GetRotation(new DoubleVector(_rayDirection, Math3D.GetArbitraryOrhonganal(_rayDirection))); Transform3DGroup transformToCamera = new Transform3DGroup(); transformToCamera.Children.Add(new RotateTransform3D(new QuaternionRotation3D(rotationToCameraRay))); transformToCamera.Children.Add(new TranslateTransform3D(_rayPoint.ToVector())); for (int cntr = 0; cntr < 10; cntr++) { Vector3D pos2D = Math3D.GetRandomVector_Circular(1d); //Vector3D vel2D = new Vector3D(pos2D.X, pos2D.Y, trkBulletSpeed.Value * 2d); //Point3D position = _rayPoint; velocity = _rayDirection.ToUnit() * trkBulletSpeed.Value * 2d; //TODO: Diverge the shot Point3D position = transformToCamera.Transform(pos2D.ToPoint()); //velocity = transformToCamera.Transform(vel2D); directionFacing = new DoubleVector(velocity, Math3D.GetArbitraryOrhonganal(velocity)); AddCannonBall( CollisionShapeType.Sphere, Color.FromRgb(25, 25, 25), new Vector3D(.1d, .1d, .1d), .2d, position, velocity, new Vector3D(), directionFacing); } #endregion break; default: MessageBox.Show("Unknown ball type: " + cboLeftBallType.Text, this.Title, MessageBoxButton.OK, MessageBoxImage.Error); return; } }