public virtual void Transform(IUnitTransformation transform, TransformFlags flags) { foreach (var t in Vertices) { t.Location = transform.Transform(t.Location); } Plane = new Plane(Vertices[0].Location, Vertices[1].Location, Vertices[2].Location); Colour = Colour; if (flags.HasFlag(TransformFlags.TextureScalingLock) && Texture.Texture != null) { // Make a best-effort guess of retaining scaling. All bets are off during skew operations. // Transform the current texture axes var origin = transform.Transform(Coordinate.Zero); var ua = transform.Transform(Texture.UAxis) - origin; var va = transform.Transform(Texture.VAxis) - origin; // Multiply the scales by the magnitudes (they were normals before the transform operation) Texture.XScale *= ua.VectorMagnitude(); Texture.YScale *= va.VectorMagnitude(); } { // Transform the texture axes and move them back to the origin var origin = transform.Transform(Coordinate.Zero); var ua = transform.Transform(Texture.UAxis) - origin; var va = transform.Transform(Texture.VAxis) - origin; // Only do the transform if the axes end up being not perpendicular // Otherwise just make a best-effort guess, same as the scaling lock if (Math.Abs(ua.Dot(va)) < 0.0001m && DMath.Abs(Plane.Normal.Dot(ua.Cross(va).Normalise())) > 0.0001m) { Texture.UAxis = ua; Texture.VAxis = va; } else { AlignTextureToFace(); } if (flags.HasFlag(TransformFlags.TextureLock) && Texture.Texture != null) { // Check some original reference points to see how the transform mutates them var scaled = (transform.Transform(Coordinate.One) - transform.Transform(Coordinate.Zero)).VectorMagnitude(); var original = (Coordinate.One - Coordinate.Zero).VectorMagnitude(); // Ignore texture lock when the transformation contains a scale if (DMath.Abs(scaled - original) <= 0.01m) { // Calculate the new shift values based on the UV values of the vertices var vtx = Vertices[0]; Texture.XShift = Texture.Texture.Width * vtx.TextureU - (vtx.Location.Dot(Texture.UAxis)) / Texture.XScale; Texture.YShift = Texture.Texture.Height * vtx.TextureV - (vtx.Location.Dot(Texture.VAxis)) / Texture.YScale; } } } CalculateTextureCoordinates(true); UpdateBoundingBox(); }
public bool EquivalentTo(Matrix other, decimal delta = 0.0001m) { for (var i = 0; i < 16; i++) { if (DMath.Abs(Values[i] - other.Values[i]) >= delta) { return(false); } } return(true); }
public virtual void Evaluate(SplineResult result, double percent) { if (samples.Length == 0) { result = new SplineResult(); } else if (samples.Length == 1) { result.CopyFrom(samples[0]); } else if (_uniformSample && _uniformPreserveClipRange) { double num = 1.0; int num2 = 0; for (int i = 0; i < samples.Length; i++) { double num3 = DMath.Abs(percent - samples[i].percent); if (num3 < num) { num = num3; num2 = i; } } if (percent > samples[num2].percent) { SplineResult.Lerp(samples[num2], samples[num2 + 1], Mathf.InverseLerp((float)samples[num2].percent, (float)samples[num2 + 1].percent, (float)percent), result); } else if (percent < samples[num2].percent) { SplineResult.Lerp(samples[num2 - 1], samples[num2], Mathf.InverseLerp((float)samples[num2 - 1].percent, (float)samples[num2].percent, (float)percent), result); } else { result.CopyFrom(samples[num2]); } } else { percent = DMath.Clamp01(percent); int sampleIndex = GetSampleIndex(percent); double num4 = (double)(samples.Length - 1) * percent - (double)sampleIndex; if (num4 > 0.0 && sampleIndex < samples.Length - 1) { SplineResult.Lerp(samples[sampleIndex], samples[sampleIndex + 1], num4, result); } else { result.CopyFrom(samples[sampleIndex]); } } }
public IEnumerable <Problem> Check(Map map) { var faces = map.WorldSpawn .Find(x => x is Solid).OfType <Solid>() .SelectMany(x => x.Faces) .ToList(); foreach (var face in faces) { var normal = face.Texture.GetNormal(); if (DMath.Abs(face.Plane.Normal.Dot(normal)) <= 0.0001m) { yield return(new Problem(GetType(), map, new [] { face }, Fix, "Texture axis perpendicular to face", "The texture axis of this face is perpendicular to the face plane. This occurs when manipulating objects with texture lock off, as well as various other operations. Re-align the texture to the face to repair. Fixing the problem will reset the textures to the face plane.")); } } }
public virtual Vector3 EvaluatePosition(double percent, bool overrideUniformClipRange = false) { if (samples.Length == 0) { return(Vector3.zero); } if (samples.Length == 1) { return(samples[0].position); } percent = DMath.Clamp01(percent); if (_uniformSample && overrideUniformClipRange) { double num = 1.0; int num2 = 0; for (int i = 0; i < samples.Length; i++) { double num3 = DMath.Abs(percent - samples[i].percent); if (num3 < num) { num = num3; num2 = i; } } if (percent > samples[num2].percent) { return(Vector3.Lerp(samples[num2].position, samples[num2 + 1].position, Mathf.InverseLerp((float)samples[num2].percent, (float)samples[num2 + 1].percent, (float)percent))); } if (percent < samples[num2].percent) { return(Vector3.Lerp(samples[num2 - 1].position, samples[num2].position, Mathf.InverseLerp((float)samples[num2 - 1].percent, (float)samples[num2].percent, (float)percent))); } return(samples[num2].position); } int sampleIndex = GetSampleIndex(percent); double num4 = (double)(samples.Length - 1) * percent - (double)sampleIndex; if (num4 > 0.0 && sampleIndex < samples.Length - 1) { return(Vector3.Lerp(samples[sampleIndex].position, samples[sampleIndex + 1].position, (float)num4)); } return(samples[sampleIndex].position); }
public IEnumerable <MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals) { var numSides = (int)_numSides.GetValue(); if (numSides < 3) { yield break; } var wallWidth = _wallWidth.GetValue(); if (wallWidth < 1) { yield break; } var arc = _arc.GetValue(); if (arc < 1) { yield break; } var startAngle = _startAngle.GetValue(); if (startAngle < 0 || startAngle > 359) { yield break; } var addHeight = _addHeight.GetValue(); var curvedRamp = _curvedRamp.GetValue(); var tiltAngle = curvedRamp ? _tiltAngle.GetValue() : 0; if (DMath.Abs(tiltAngle % 180) == 90) { yield break; } var tiltInterp = curvedRamp && _tiltInterp.GetValue(); // Very similar to the pipe brush, except with options for start angle, arc, height and tilt var width = box.Width; var length = box.Length; var height = box.Height; var majorOut = width / 2; var majorIn = majorOut - wallWidth; var minorOut = length / 2; var minorIn = minorOut - wallWidth; var start = DMath.DegreesToRadians(startAngle); var tilt = DMath.DegreesToRadians(tiltAngle); var angle = DMath.DegreesToRadians(arc) / numSides; // Calculate the coordinates of the inner and outer ellipses' points var outer = new Coordinate[numSides + 1]; var inner = new Coordinate[numSides + 1]; for (var i = 0; i < numSides + 1; i++) { var a = start + i * angle; var h = i * addHeight; var interp = tiltInterp ? DMath.Cos(DMath.PI / numSides * (i - numSides / 2M)) : 1; var tiltHeight = wallWidth / 2 * interp * DMath.Tan(tilt); var xval = box.Center.X + majorOut * DMath.Cos(a); var yval = box.Center.Y + minorOut * DMath.Sin(a); var zval = box.Start.Z + (curvedRamp ? h + tiltHeight : 0); outer[i] = new Coordinate(xval, yval, zval).Round(roundDecimals); xval = box.Center.X + majorIn * DMath.Cos(a); yval = box.Center.Y + minorIn * DMath.Sin(a); zval = box.Start.Z + (curvedRamp ? h - tiltHeight : 0); inner[i] = new Coordinate(xval, yval, zval).Round(roundDecimals); } // Create the solids var colour = Colour.GetRandomBrushColour(); var z = new Coordinate(0, 0, height).Round(roundDecimals); for (var i = 0; i < numSides; i++) { var faces = new List <Coordinate[]>(); // Since we are triangulating/splitting each arch segment, we need to generate 2 brushes per side if (curvedRamp) { // The splitting orientation depends on the curving direction of the arch if (addHeight >= 0) { faces.Add(new[] { outer[i], outer[i] + z, outer[i + 1] + z, outer[i + 1] }); faces.Add(new[] { outer[i + 1], outer[i + 1] + z, inner[i] + z, inner[i] }); faces.Add(new[] { inner[i], inner[i] + z, outer[i] + z, outer[i] }); faces.Add(new[] { outer[i] + z, inner[i] + z, outer[i + 1] + z }); faces.Add(new[] { outer[i + 1], inner[i], outer[i] }); } else { faces.Add(new[] { inner[i + 1], inner[i + 1] + z, inner[i] + z, inner[i] }); faces.Add(new[] { outer[i], outer[i] + z, inner[i + 1] + z, inner[i + 1] }); faces.Add(new[] { inner[i], inner[i] + z, outer[i] + z, outer[i] }); faces.Add(new[] { inner[i + 1] + z, outer[i] + z, inner[i] + z }); faces.Add(new[] { inner[i], outer[i], inner[i + 1] }); } yield return(MakeSolid(generator, faces, texture, colour)); faces.Clear(); if (addHeight >= 0) { faces.Add(new[] { inner[i + 1], inner[i + 1] + z, inner[i] + z, inner[i] }); faces.Add(new[] { inner[i], inner[i] + z, outer[i + 1] + z, outer[i + 1] }); faces.Add(new[] { outer[i + 1], outer[i + 1] + z, inner[i + 1] + z, inner[i + 1] }); faces.Add(new[] { inner[i + 1] + z, outer[i + 1] + z, inner[i] + z }); faces.Add(new[] { inner[i], outer[i + 1], inner[i + 1] }); } else { faces.Add(new[] { outer[i], outer[i] + z, outer[i + 1] + z, outer[i + 1] }); faces.Add(new[] { inner[i + 1], inner[i + 1] + z, outer[i] + z, outer[i] }); faces.Add(new[] { outer[i + 1], outer[i + 1] + z, inner[i + 1] + z, inner[i + 1] }); faces.Add(new[] { outer[i] + z, inner[i + 1] + z, outer[i + 1] + z }); faces.Add(new[] { outer[i + 1], inner[i + 1], outer[i] }); } yield return(MakeSolid(generator, faces, texture, colour)); } else { var h = i * addHeight * Coordinate.UnitZ; faces.Add(new[] { outer[i], outer[i] + z, outer[i + 1] + z, outer[i + 1] }.Select(x => x + h).ToArray()); faces.Add(new[] { inner[i + 1], inner[i + 1] + z, inner[i] + z, inner[i] }.Select(x => x + h).ToArray()); faces.Add(new[] { outer[i + 1], outer[i + 1] + z, inner[i + 1] + z, inner[i + 1] }.Select(x => x + h).ToArray()); faces.Add(new[] { inner[i], inner[i] + z, outer[i] + z, outer[i] }.Select(x => x + h).ToArray()); faces.Add(new[] { inner[i + 1] + z, outer[i + 1] + z, outer[i] + z, inner[i] + z }.Select(x => x + h).ToArray()); faces.Add(new[] { inner[i], outer[i], outer[i + 1], inner[i + 1] }.Select(x => x + h).ToArray()); yield return(MakeSolid(generator, faces, texture, colour)); } } }
protected Coordinate SnapToSelection(Coordinate c, Viewport2D vp) { if (!Document.Map.SnapToGrid) { return(c); } var snap = (Select.SnapStyle == SnapStyle.SnapOnAlt && KeyboardState.Alt) || (Select.SnapStyle == SnapStyle.SnapOffAlt && !KeyboardState.Alt); if (!snap) { return(c); } var snapped = c.Snap(Document.Map.GridSpacing); if (Document.Selection.InFaceSelection || Document.Selection.IsEmpty()) { return(snapped); } // Try and snap the the selection box center var selBox = Document.Selection.GetSelectionBoundingBox(); var selCenter = vp.Flatten(selBox.Center); if (DMath.Abs(selCenter.X - c.X) < selBox.Width / 10 && DMath.Abs(selCenter.Y - c.Y) < selBox.Height / 10) { return(selCenter); } var objects = Document.Selection.GetSelectedObjects().ToList(); // Try and snap to an object center foreach (var mo in objects) { if (!(mo is Entity) && !(mo is Solid)) { continue; } var center = vp.Flatten(mo.BoundingBox.Center); if (DMath.Abs(center.X - c.X) >= mo.BoundingBox.Width / 10) { continue; } if (DMath.Abs(center.Y - c.Y) >= mo.BoundingBox.Height / 10) { continue; } return(center); } // Get all the edges of the selected objects var lines = objects.SelectMany(x => { if (x is Entity) { return(x.BoundingBox.GetBoxLines()); } if (x is Solid) { return(((Solid)x).Faces.SelectMany(f => f.GetLines())); } return(new Line[0]); }).Select(x => new Line(vp.Flatten(x.Start), vp.Flatten(x.End))).ToList(); // Try and snap to an edge var closest = snapped; foreach (var line in lines) { // if the line and the grid are in the same spot, return the snapped point if (line.ClosestPoint(snapped).EquivalentTo(snapped)) { return(snapped); } // Test for corners and midpoints within a 10% tolerance var pointTolerance = (line.End - line.Start).VectorMagnitude() / 10; if ((line.Start - c).VectorMagnitude() < pointTolerance) { return(line.Start); } if ((line.End - c).VectorMagnitude() < pointTolerance) { return(line.End); } var center = (line.Start + line.End) / 2; if ((center - c).VectorMagnitude() < pointTolerance) { return(center); } // If the line is closer to the grid point, return the line var lineSnap = line.ClosestPoint(c); if ((closest - c).VectorMagnitude() > (lineSnap - c).VectorMagnitude()) { closest = lineSnap; } } return(closest); }
public Matrix Inverse() { int[] colIdx = { 0, 0, 0, 0 }; int[] rowIdx = { 0, 0, 0, 0 }; int[] pivotIdx = { -1, -1, -1, -1 }; // convert the matrix to an array for easy looping var inverse = new[, ] { { Values[0], Values[1], Values[2], Values[3] }, { Values[4], Values[5], Values[6], Values[7] }, { Values[8], Values[9], Values[10], Values[11] }, { Values[12], Values[13], Values[14], Values[15] } }; var icol = 0; var irow = 0; for (var i = 0; i < 4; i++) { // Find the largest pivot value var maxPivot = 0m; for (var j = 0; j < 4; j++) { if (pivotIdx[j] != 0) { for (var k = 0; k < 4; ++k) { if (pivotIdx[k] == -1) { var absVal = DMath.Abs(inverse[j, k]); if (absVal > maxPivot) { maxPivot = absVal; irow = j; icol = k; } } else if (pivotIdx[k] > 0) { return(this); } } } } ++(pivotIdx[icol]); // Swap rows over so pivot is on diagonal if (irow != icol) { for (var k = 0; k < 4; ++k) { var f = inverse[irow, k]; inverse[irow, k] = inverse[icol, k]; inverse[icol, k] = f; } } rowIdx[i] = irow; colIdx[i] = icol; var pivot = inverse[icol, icol]; // check for singular matrix if (pivot == 0) { throw new InvalidOperationException("Matrix is singular and cannot be inverted."); } // Scale row so it has a unit diagonal var oneOverPivot = 1m / pivot; inverse[icol, icol] = 1; for (var k = 0; k < 4; ++k) { inverse[icol, k] *= oneOverPivot; } // Do elimination of non-diagonal elements for (var j = 0; j < 4; ++j) { // check this isn't on the diagonal if (icol != j) { var f = inverse[j, icol]; inverse[j, icol] = 0; for (var k = 0; k < 4; ++k) { inverse[j, k] -= inverse[icol, k] * f; } } } } for (var j = 3; j >= 0; --j) { var ir = rowIdx[j]; var ic = colIdx[j]; for (var k = 0; k < 4; ++k) { var f = inverse[k, ir]; inverse[k, ir] = inverse[k, ic]; inverse[k, ic] = f; } } return(new Matrix( inverse[0, 0], inverse[0, 1], inverse[0, 2], inverse[0, 3], inverse[1, 0], inverse[1, 1], inverse[1, 2], inverse[1, 3], inverse[2, 0], inverse[2, 1], inverse[2, 2], inverse[2, 3], inverse[3, 0], inverse[3, 1], inverse[3, 2], inverse[3, 3])); }
public virtual void Transform(IUnitTransformation transform, TransformFlags flags) { foreach (var t in Vertices) { t.Location = transform.Transform(t.Location); } Plane = new Plane(Vertices[0].Location, Vertices[1].Location, Vertices[2].Location); Colour = Colour; var origin = transform.Transform(Coordinate.Zero); var ua = transform.Transform(Texture.UAxis) - origin; var va = transform.Transform(Texture.VAxis) - origin; if (flags.HasFlag(TransformFlags.TextureScalingLock) && Texture.Texture != null) { // Make a best-effort guess of retaining scaling. All bets are off during skew operations. // Transform the current texture axes // Multiply the scales by the magnitudes (they were normals before the transform operation) Texture.XScale *= ua.VectorMagnitude(); Texture.YScale *= va.VectorMagnitude(); } { //NOTE(SVK):Only edit solids not entities. //do entities have faces?? if (this.Parent.Parent.GetType().Name == "World" && this.Parent.GetType().Name == "Solid") { if (Texture.Flags.HasFlag(FaceFlags.TextureLocked)) { Coordinate Center = this.Parent.Parent.SelCenter; Matrix Xfrm = transform.GetMatrix(); TransformFlags f = (TransformFlags)0; if (Xfrm != Matrix.Zero) { f = GetTransformFlags(Xfrm); } else { f = flags; } if (f.HasFlag(TransformFlags.Translate)) { Texture.PositionRF = transform.Transform(Texture.PositionRF); } if (f.HasFlag(TransformFlags.Rotation)) { Xfrm = ToRF(Xfrm); Texture.TransformAngleRF = Xfrm * Texture.TransformAngleRF; Texture.PositionRF = Texture.PositionRF - Center; Texture.PositionRF = RotateRF(Xfrm, ToRF(Texture.PositionRF)); Texture.PositionRF = ToChisel(Texture.PositionRF); Texture.PositionRF = Texture.PositionRF + Center; } } } else //entities etc... { // Transform the texture axes and move them back to the origin // Only do the transform if the axes end up being not perpendicular // Otherwise just make a best-effort guess, same as the scaling lock if (Math.Abs(ua.Dot(va)) < 0.0001m && DMath.Abs(Plane.Normal.Dot(ua.Cross(va).Normalise())) > 0.0001m) { Texture.UAxis = ua; Texture.VAxis = va; } else { AlignTextureToWorld(); } if (flags.HasFlag(TransformFlags.TextureLock) && Texture.Texture != null) { // Check some original reference points to see how the transform mutates them var scaled = (transform.Transform(Coordinate.One) - transform.Transform(Coordinate.Zero)).VectorMagnitude(); var original = (Coordinate.One - Coordinate.Zero).VectorMagnitude(); // Ignore texture lock when the transformation contains a scale if (DMath.Abs(scaled - original) <= 0.01m) { // Calculate the new shift values based on the UV values of the vertices var vtx = Vertices[0]; Texture.XShift = Texture.Texture.Width * vtx.TextureU - (vtx.Location.Dot(Texture.UAxis)) / Texture.XScale; Texture.YShift = Texture.Texture.Height * vtx.TextureV - (vtx.Location.Dot(Texture.VAxis)) / Texture.YScale; } } } } AlignTexture(); UpdateBoundingBox(); }