public IEnumerable <IMapObject> Create(UniqueNumberGenerator generator, Box box, string texture, int roundDecimals) { var useCentroid = _useCentroid.GetValue(); // The lower Z plane will be the triangle, with the lower Y value getting the two corners var c1 = new Vector3(box.Start.X, box.Start.Y, box.Start.Z).Round(roundDecimals); var c2 = new Vector3(box.End.X, box.Start.Y, box.Start.Z).Round(roundDecimals); var c3 = new Vector3(box.Center.X, box.End.Y, box.Start.Z).Round(roundDecimals); var centroid = new Vector3((c1.X + c2.X + c3.X) / 3, (c1.Y + c2.Y + c3.Y) / 3, box.End.Z); var c4 = (useCentroid ? centroid : new Vector3(box.Center.X, box.Center.Y, box.End.Z)).Round(roundDecimals); var faces = new[] { new[] { c1, c2, c3 }, new[] { c4, c1, c3 }, new[] { c4, c3, c2 }, new[] { c4, c2, c1 } }; var solid = new Solid(generator.Next("MapObject")); solid.Data.Add(new ObjectColor(Colour.GetRandomBrushColour())); foreach (var arr in faces) { var face = new Face(generator.Next("Face")) { Plane = new Plane(arr[0], arr[1], arr[2]), Texture = { Name = texture } }; face.Vertices.AddRange(arr); solid.Data.Add(face); } solid.DescendantsChanged(); yield return(solid); }
public IEnumerable <MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals) { var useCentroid = _useCentroid.GetValue(); // The lower Z plane will be the triangle, with the lower Y value getting the two corners var c1 = new Coordinate(box.Start.X, box.Start.Y, box.Start.Z).Round(roundDecimals); var c2 = new Coordinate(box.End.X, box.Start.Y, box.Start.Z).Round(roundDecimals); var c3 = new Coordinate(box.Center.X, box.End.Y, box.Start.Z).Round(roundDecimals); var centroid = new Coordinate((c1.X + c2.X + c3.X) / 3, (c1.Y + c2.Y + c3.Y) / 3, box.End.Z); var c4 = (useCentroid ? centroid : new Coordinate(box.Center.X, box.Center.Y, box.End.Z)).Round(roundDecimals); var faces = new[] { new[] { c1, c2, c3 }, new[] { c4, c1, c3 }, new[] { c4, c3, c2 }, new[] { c4, c2, c1 } }; var solid = new Solid(generator.GetNextObjectID()) { Colour = Colour.GetRandomBrushColour() }; foreach (var arr in faces) { var face = new Face(generator.GetNextFaceID()) { Parent = solid, Plane = new Plane(arr[0], arr[1], arr[2]), Colour = solid.Colour, Texture = { Texture = texture } }; face.Vertices.AddRange(arr.Select(x => new Vertex(x, face))); face.UpdateBoundingBox(); face.AlignTextureToFace(); solid.Faces.Add(face); } solid.UpdateBoundingBox(); yield return(solid); }
public ArchBrush() { _numSides = new NumericControl(this) { LabelText = "Number of sides" }; _wallWidth = new NumericControl(this) { LabelText = "Wall width", Minimum = 1, Maximum = 1024, Value = 32, Precision = 1 }; _arc = new NumericControl(this) { LabelText = "Arc", Minimum = 1, Maximum = 360 * 4, Value = 360 }; _startAngle = new NumericControl(this) { LabelText = "Start angle", Minimum = 0, Maximum = 359, Value = 0 }; _addHeight = new NumericControl(this) { LabelText = "Add height", Minimum = -1024, Maximum = 1024, Value = 0, Precision = 1 }; _curvedRamp = new BooleanControl(this) { LabelText = "Curved ramp", Checked = false }; _tiltAngle = new NumericControl(this) { LabelText = "Tilt angle", Minimum = -Atan2, Maximum = Atan2, Value = 0, Enabled = false, Precision = 1 }; _tiltInterp = new BooleanControl(this) { LabelText = "Tilt interpolation", Checked = false, Enabled = false }; _curvedRamp.ValuesChanged += (s, b) => _tiltAngle.Enabled = _tiltInterp.Enabled = _curvedRamp.GetValue(); }
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)); } } }
public TorusBrush() { _crossSides = new NumericControl(this) { LabelText = "Cross sec. sides" }; _crossRadius = new NumericControl(this) { LabelText = "Ring width", Minimum = 16, Maximum = 1024, Value = 32, Precision = 1 }; _crossStartAngle = new NumericControl(this) { LabelText = "Cross sec. start", Minimum = 0, Maximum = 359, Value = 0 }; _crossMakeHollow = new BooleanControl(this) { LabelText = "Make hollow", Checked = false }; _crossArc = new NumericControl(this) { LabelText = "Cross sec. arc", Minimum = 1, Maximum = 360, Value = 360, Enabled = false }; _crossWallWidth = new NumericControl(this) { LabelText = "Hollow wall width", Minimum = 1, Maximum = 1024, Value = 16, Precision = 1, Enabled = false }; _ringSides = new NumericControl(this) { LabelText = "Ring sides" }; _ringArc = new NumericControl(this) { LabelText = "Ring arc", Minimum = 1, Maximum = 1080, Value = 360 }; _ringStartAngle = new NumericControl(this) { LabelText = "Ring start", Minimum = 0, Maximum = 359, Value = 0 }; _rotationHeight = new NumericControl(this) { LabelText = "Rotation height", Minimum = -1024, Maximum = 1024, Value = 0, Precision = 1 }; _crossMakeHollow.ValuesChanged += (s, b) => _crossWallWidth.Enabled = _crossArc.Enabled = _crossMakeHollow.GetValue(); }
public IEnumerable <MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals) { var crossSides = (int)_crossSides.GetValue(); if (crossSides < 3) { yield break; } var crossWidth = _crossRadius.GetValue() * 2; if (crossWidth < 1) { yield break; } var crossMakeHollow = _crossMakeHollow.GetValue(); var crossArc = !crossMakeHollow ? 360 : (int)_crossArc.GetValue(); if (crossArc < 1) { yield break; } var crossStartAngle = (int)_crossStartAngle.GetValue(); if (crossStartAngle < 0 || crossStartAngle > 359) { yield break; } var crossWallWidth = _crossWallWidth.GetValue(); if (crossWallWidth < 1) { yield break; } var ringSides = (int)_ringSides.GetValue(); if (ringSides < 3) { yield break; } var ringArc = (int)_ringArc.GetValue(); if (ringArc < 1) { yield break; } var ringStartAngle = (int)_ringStartAngle.GetValue(); if (ringStartAngle < 0 || ringStartAngle > 359) { yield break; } var rotationHeight = _rotationHeight.GetValue(); // Sort of a combination of cylinder and pipe brushes var width = box.Width; var length = box.Length; var height = box.Height; var majorPrimary = (width - crossWidth) / 2; // Primary = donut circle var minorPrimary = (length - crossWidth) / 2; var majorSecondaryOuter = crossWidth / 2; // Secondary = cross section circle var minorSecondaryOuter = height / 2; // Outer = Outer ring var majorSecondaryInner = (crossWidth - crossWallWidth) / 2; // Inner = inner ring (hollow only) var minorSecondaryInner = (height - crossWallWidth) / 2; var ringStart = DMath.DegreesToRadians(ringStartAngle); var ringAngle = DMath.DegreesToRadians(ringArc) / ringSides; var crossStart = DMath.DegreesToRadians(crossStartAngle); var crossAngle = DMath.DegreesToRadians(crossArc) / crossSides; var heightAdd = rotationHeight / ringSides; // Rotate around the ring, generating each cross section var ringOuterSections = new List <Coordinate[]>(); var ringInnerSections = new List <Coordinate[]>(); for (var i = 0; i < ringSides + 1; i++) { var ring = ringStart + i * ringAngle; var rxval = box.Center.X + majorPrimary * DMath.Cos(ring); var ryval = box.Center.Y + minorPrimary * DMath.Sin(ring); var rzval = box.Center.Z; var crossSecOuter = new Coordinate[crossSides + 1]; var crossSecInner = new Coordinate[crossSides + 1]; for (var j = 0; j < crossSides + 1; j++) { var cross = crossStart + j * crossAngle; var xval = majorSecondaryOuter * DMath.Cos(cross) * DMath.Cos(ring); var yval = majorSecondaryOuter * DMath.Cos(cross) * DMath.Sin(ring); var zval = minorSecondaryOuter * DMath.Sin(cross); crossSecOuter[j] = new Coordinate(xval + rxval, yval + ryval, zval + rzval).Round(roundDecimals); if (!crossMakeHollow) { continue; } xval = majorSecondaryInner * DMath.Cos(cross) * DMath.Cos(ring); yval = majorSecondaryInner * DMath.Cos(cross) * DMath.Sin(ring); zval = minorSecondaryInner * DMath.Sin(cross); crossSecInner[j] = new Coordinate(xval + rxval, yval + ryval, zval + rzval).Round(roundDecimals); } ringOuterSections.Add(crossSecOuter); ringInnerSections.Add(crossSecInner); } // Create the solids var colour = Colour.GetRandomBrushColour(); for (var i = 0; i < ringSides; i++) { var vertical = Coordinate.UnitZ * heightAdd * i; var nexti = i + 1; if (crossMakeHollow) { // Use pipe cross sections var outerPoints = ringOuterSections[i]; var nextOuterPoints = ringOuterSections[nexti]; var innerPoints = ringInnerSections[i]; var nextInnerPoints = ringInnerSections[nexti]; for (var j = 0; j < crossSides; j++) { var nextj = j + 1; var faces = new List <Coordinate[]>(); faces.Add(new[] { outerPoints[j], outerPoints[nextj], nextOuterPoints[nextj], nextOuterPoints[j] }.Select(x => x + vertical).ToArray()); faces.Add(new[] { nextInnerPoints[j], nextInnerPoints[nextj], innerPoints[nextj], innerPoints[j] }.Select(x => x + vertical).ToArray()); faces.Add(new[] { innerPoints[nextj], nextInnerPoints[nextj], nextOuterPoints[nextj], outerPoints[nextj] }.Select(x => x + vertical).ToArray()); faces.Add(new[] { outerPoints[j], nextOuterPoints[j], nextInnerPoints[j], innerPoints[j] }.Select(x => x + vertical).ToArray()); faces.Add(new[] { innerPoints[j], innerPoints[nextj], outerPoints[nextj], outerPoints[j] }.Select(x => x + vertical).ToArray()); faces.Add(new[] { nextOuterPoints[j], nextOuterPoints[nextj], nextInnerPoints[nextj], nextInnerPoints[j] }.Select(x => x + vertical).ToArray()); yield return(MakeSolid(generator, faces, texture, colour)); } } else { // Use cylindrical cross sections var faces = new List <Coordinate[]>(); var points = ringOuterSections[i]; var nextPoints = ringOuterSections[nexti]; // Add the outer faces for (var j = 0; j < crossSides; j++) { var nextj = (j + 1) % crossSides; faces.Add(new[] { points[j], points[nextj], nextPoints[nextj], nextPoints[j] }.Select(x => x + vertical).ToArray()); } // Add the cross section faces faces.Add(points.Reverse().Select(x => x + vertical).ToArray()); faces.Add(nextPoints.Select(x => x + vertical).ToArray()); yield return(MakeSolid(generator, faces, texture, colour)); } } }
public Task OnInitialise() { _crossSides = new NumericControl(this) { LabelText = CrossSectionSides }; _crossRadius = new NumericControl(this) { LabelText = RingWidth, Minimum = 16, Maximum = 1024, Value = 32, Precision = 1 }; _crossStartAngle = new NumericControl(this) { LabelText = CrossSectionStart, Minimum = 0, Maximum = 359, Value = 0 }; _crossMakeHollow = new BooleanControl(this) { LabelText = MakeHollow, Checked = false }; _crossArc = new NumericControl(this) { LabelText = CrossSectionArc, Minimum = 1, Maximum = 360, Value = 360, Enabled = false }; _crossWallWidth = new NumericControl(this) { LabelText = HollowWallWidth, Minimum = 1, Maximum = 1024, Value = 16, Precision = 1, Enabled = false }; _ringSides = new NumericControl(this) { LabelText = RingSides }; _ringArc = new NumericControl(this) { LabelText = RingArc, Minimum = 1, Maximum = 1080, Value = 360 }; _ringStartAngle = new NumericControl(this) { LabelText = RingStart, Minimum = 0, Maximum = 359, Value = 0 }; _rotationHeight = new NumericControl(this) { LabelText = RotationHeight, Minimum = -1024, Maximum = 1024, Value = 0, Precision = 1 }; _crossMakeHollow.ValuesChanged += (s, b) => _crossWallWidth.Enabled = _crossArc.Enabled = _crossMakeHollow.GetValue(); return(Task.CompletedTask); }
public async Task OnInitialise() { _numSides = new NumericControl(this) { LabelText = NumberOfSides }; _wallWidth = new NumericControl(this) { LabelText = WallWidth, Minimum = 1, Maximum = 1024, Value = 32, Precision = 1 }; _arc = new NumericControl(this) { LabelText = Arc, Minimum = 1, Maximum = 360 * 4, Value = 360 }; _startAngle = new NumericControl(this) { LabelText = StartAngle, Minimum = 0, Maximum = 359, Value = 0 }; _addHeight = new NumericControl(this) { LabelText = AddHeight, Minimum = -1024, Maximum = 1024, Value = 0, Precision = 1 }; _curvedRamp = new BooleanControl(this) { LabelText = CurvedRamp, Checked = false }; _tiltAngle = new NumericControl(this) { LabelText = TiltAngle, Minimum = -Atan2, Maximum = Atan2, Value = 0, Enabled = false, Precision = 1 }; _tiltInterp = new BooleanControl(this) { LabelText = TiltInterpolation, Checked = false, Enabled = false }; _curvedRamp.ValuesChanged += (s, b) => _tiltAngle.Enabled = _tiltInterp.Enabled = _curvedRamp.GetValue(); }