Doing an inheritance test program specifically to root out problems such as these.
The classes themselves aren't important, the problem is in the Main.
I tried "Shape shape = null" before the if statements but having "Circle shape" etc in the if statements threw errors.
Main:
string shapeType = "";
double side = 0;
while (true)
{
Console.WriteLine("What type of shape? - (cir/tri/sqr");
shapeType = Console.ReadLine();
Console.WriteLine("How long are the sides, or the radius?");
side = Convert.ToDouble(Console.ReadLine());
if (shapeType == "cir")
{
Circle shape = new Circle();
}
else if (shapeType == "tri")
{
Triangle shape = new Triangle();
}
else
{
Square shape = new Square();
}
// Code interacting with shapes.
}
You're declaring the shapes within the if blocks, which means that after that block ends it's unavailable.
You need to declare it before, and as a Shape:
Shape shape = null;
if (shapeType == "cir")
{
shape = new Circle();
}
else if (shapeType == "tri")
{
shape = new Triangle();
}
else
{
shape = new Square();
}
// … etc
Related
I am trying to place an element into the center of several rooms. So far I have achieved something similar by using the Location Point which has placed the element close to the center but not exact.
I attempted to fix this by using two methods that I believed would help accomplish this task, GetElementCenter and GetRoomCenter but when I run the plugin, nothing happens.
class Class2
{
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
//Get access to Revit command data, user interface and document
UIApplication uiapp = commandData.Application;
UIDocument uidoc = uiapp.ActiveUIDocument;
Document doc = uidoc.Document;
//Collect all rooms
FilteredElementCollector roomCollector = new FilteredElementCollector(doc).OfClass(typeof(SpatialElement));
// Collect element
FilteredElementCollector element = new FilteredElementCollector(doc).OfClass(typeof(FamilySymbol)).OfCategory(BuiltInCategory.OST_Cameras);
//Get symbol
FamilySymbol elementSym = element.FirstElement() as FamilySymbol;
using (Transaction tx = new Transaction(doc))
{
try
{
tx.Start("Start");
//For loop for every room in the roomCollector
foreach (SpatialElement oneRoom in roomCollector)
{
//Get area of each room
Room room = oneRoom as Room;
double area = room.Area;
//Location point version
Location loc = room.Location;
LocationPoint location = loc as LocationPoint;
XYZ point = (null == location) ? XYZ.Zero : location.Point;
//New version
XYZ source = GetRoomCenter(room);
double smallRoom = 301;
if (area <= smallRoom)
{
doc.Create.NewFamilyInstance(source, elementSym, Autodesk.Revit.DB.Structure.StructuralType.NonStructural);
}
}
tx.Commit();
}
catch (Exception e)
{
Debug.Print(e.Message);
tx.RollBack();
}
}
TaskDialog.Show("Message", "Task completed successfully");
return Result.Succeeded;
}
public XYZ GetElementCenter(Room room)
{
BoundingBoxXYZ bounding = room.get_BoundingBox(null);
XYZ center = (bounding.Max + bounding.Min) * 0.5;
return center;
}
public XYZ GetRoomCenter(Room room)
{
XYZ boundCenter = GetElementCenter(room);
LocationPoint locPt = (LocationPoint)room.Location;
XYZ roomCenter = new XYZ(boundCenter.X, boundCenter.Y, locPt.Point.Z);
return roomCenter;
}
}
}
Any help on getting the XYZ data of the center of a room would be greatly appreciated.
Assuming that you have straight walls bounding the room, I would suggest that you take a look at mathematical and geometrical algorithms for determining the center point of a polygon. Something like this new algorithm for finding a visual center of a polygon is probably best suited to your needs, even though you neither state this fact nor probably are yet aware of it :-)
I generate all of them the same, but some of them can't be colored (image on the bottom)
Steps:
I'm creating list of faces from solid
internal static List<List<XYZ>> GetFacesFromSolidTriangulate(Solid geomSolid)
{
List<List<XYZ>> faces = new List<List<XYZ>>();
foreach (Face face in geomSolid.Faces)
{
Mesh mesh_space = face.Triangulate();
for (int i = 0; i < mesh_space.NumTriangles; i++)
{
MeshTriangle triangle = mesh_space.get_Triangle(i);
XYZ p1 = triangle.get_Vertex(0);
XYZ p2 = triangle.get_Vertex(1);
XYZ p3 = triangle.get_Vertex(2);
List<XYZ> xyz = new List<XYZ>();
xyz.Add(triangle.get_Vertex(0));
xyz.Add(triangle.get_Vertex(1));
xyz.Add(triangle.get_Vertex(2));
faces.Add(xyz);
}
}
return faces;
}
I'm creating Direct Shape using
static public DirectShape NewDrawDirectShape(Document doc, List<List<XYZ>> faces, ElementId matId, string name)
{
TessellatedShapeBuilder builder = new TessellatedShapeBuilder();
builder.OpenConnectedFaceSet(true);
foreach(List<XYZ> face in faces)
{
builder.AddFace(new TessellatedFace(face, matId));
}
builder.CloseConnectedFaceSet();
builder.Build();
TessellatedShapeBuilderResult result = builder.GetBuildResult();
DirectShape ds = DirectShape.CreateElement(doc, new ElementId(BuiltInCategory.OST_GenericModel));
ds.SetShape(result.GetGeometricalObjects());
ds.Name = name;
return ds;
}
And here is the problem, I can't paint few of them even using Revit "paint" tool...
Red arrow define what I'm trying achieve on this direct shape, blue direct shapes works correctly
Have you checked the triangle orientations? Maybe some of the triangles returned in the MeshTriangle objects are incorrectly oriented. To try it out, you could create a little model line in the centre of each triangle indicating its normal vector and this the edge orientation.
Here is the Cohen-Sutherland code:
public static Tuple<PointF, PointF> ClipSegment(RectangleF r, PointF p1, PointF p2)
{
//classify the endpoints of the line
var outCodeP1 = ComputeOutCode(p1, r);
var outCodeP2 = ComputeOutCode(p2, r);
var accept = false;
while (true)
{
// Case 1!
if ((outCodeP1 | outCodeP2) == OutCode.Inside)
{
accept = true;
break;
}
// Case 2!
if ((outCodeP1 & outCodeP2) != 0)
{
break;
}
//Case 3!
var outCode = outCodeP1 != OutCode.Inside ? outCodeP1 : outCodeP2;
// calculate the intersection of the line with the clipping rectangle using parametric line equations
var p = CalculateIntersection(r, p1, p2, outCode);
// update the point after clipping and recalculate outcode
if (outCode==outCodeP1)
{
p1 = p;
outCodeP1 = ComputeOutCode(p1, r);
}
else
{
p2 = p;
outCodeP2 = ComputeOutCode(p2, r);
}
}
// if clipping area contained a portion of the line
if (accept)
{
return new Tuple<PointF, PointF>(p1, p2);
}
// the line did not intersect the clipping area
return null;
}
Case 1: both endpoints are within the clipping region.
Case 2: both endpoints share an excluded region, impossible for a line between them to be within the clipping region.
Case 3: the endpoints are in different regions, and the segment is partially within the clipping rectangle, selects one of the endpoints outside the clipping rectangle.
I try to get all segments outside the clipping window instead of inside.
Can someone help me?
After realising that finding the segments outside of the clipping region may yield multiple tuples and updating the method's return type, it's a matter of just walking through the logic and reversing each decision:
public static IEnumerable<Tuple<PointF, PointF>> ClipSegment(RectangleF r, PointF p1, PointF p2)
{
// classify the endpoints of the line
var outCodeP1 = ComputeOutCode(p1, r);
var outCodeP2 = ComputeOutCode(p2, r);
var results = new List<Tuple<PointF,PointF>>();
while (true)
{
// Case 1:
// both endpoints are within the clipping region
if ((outCodeP1 | outCodeP2) == OutCode.Inside)
{
//Completely clipped
break;
}
// Case 2:
// both endpoints share an excluded region, impossible for a line between them to be within the clipping region
if ((outCodeP1 & outCodeP2) != 0)
{
//Not clipped at all
results.Add(Tuple.Create(p1,p2));
break;
}
//Case 3: The endpoints are in different regions, and the segment is partially within
//the clipping rectangle Select one of the endpoints outside the clipping rectangle
var outCode = outCodeP1 != OutCode.Inside ? outCodeP1 : outCodeP2;
// calculate the intersection of the line with the clipping rectangle using parametric line equations
var p = CalculateIntersection(r, p1, p2, outCode);
// update the point after clipping and recalculate outcode
if (outCode==outCodeP1)
{
//Keep "discarded" segment
results.Add(Tuple.Create(p1,p));
p1 = p;
outCodeP1 = ComputeOutCode(p1, r);
}
else
{
//ditto
results.Add(Tuple.Create(p,p2));
p2 = p;
outCodeP2 = ComputeOutCode(p2, r);
}
}
return results;
}
And you can change the calling code to:
var clipped = CohenSutherland.ClipSegment(_rect, p1, p2);
newLines.AddRange(clipped);
(Since we now guarantee to always return a list, even if empty, the null check is no longer required).
One improvement that we may wish to consider is to change the function to be an iterator and use yield return instead of maintaining a separate list internally.
I have class, that creates Shapes for me (I tried to create some kind of "class factory" but im not sure if this is correct term for that I have created.
Problem is described in comments in my code.
public static Ellipse SomeCircle()
{
Ellipse e = new Ellipse();
double size = 10;
e.Height = size;
e.Width = size;
e.Fill = new SolidColorBrush(Colors.Orange);
e.Fill.Opacity = 0.8;
e.Stroke = new SolidColorBrush(Colors.Black);
// i want to have something like this here:
// canvas1.Children.Add(e);
// but I cant access non-static canvas1 from here
// I need this to place my ellipse in desired place
// (line below will not work if my Ellipse is not placed on canvas
// e.Margin = new Thickness(p.X - e.Width * 2, p.Y - e.Height * 2, 0, 0);
return e;
}
I have no idea how to workaround this.
I don't want to pass that canvas by parameter in my whole application...
Since you do not want to pass your Canvas around as a parameter, you could try creating an Extension Method which would act on your Canvas Object.
namespace CustomExtensions
{
public static class Shapes
{
public static Ellipse SomeCircle(this Canvas dest)
{
Ellipse e = new Ellipse();
double size = 10;
e.Height = size;
e.Width = size;
e.Fill = new SolidColorBrush(Colors.Orange);
e.Fill.Opacity = 0.8;
e.Stroke = new SolidColorBrush(Colors.Black);
dest.Children.Add(e);
return e;
}
}
}
Usage remember to add the CustomExtensions Namespace to your usings.
canvas1.SomeCircle();
I'm trying to create 1 complex composite shape on an InkCanvas, but I must be doing something wrong, as what I was expecting to happen, is not. I've tried several different incarnations of accomplishing this.
So I have this method.
private void InkCanvas_StrokeCollected(object sender, InkCanvasStrokeCollectedEventArgs e)
{
Stroke stroke = e.Stroke;
// Close the "shape".
StylusPoint firstPoint = stroke.StylusPoints[0];
stroke.StylusPoints.Add(new StylusPoint() { X = firstPoint.X, Y = firstPoint.Y });
// Hide the drawn shape on the InkCanvas.
stroke.DrawingAttributes.Height = DrawingAttributes.MinHeight;
stroke.DrawingAttributes.Width = DrawingAttributes.MinWidth;
// Add to GeometryGroup. According to http://msdn.microsoft.com/en-us/library/system.windows.media.combinedgeometry.aspx
// a GeometryGroup should work better at Unions.
_revealShapes.Children.Add(stroke.GetGeometry());
Path p = new Path();
p.Stroke = Brushes.Green;
p.StrokeThickness = 1;
p.Fill = Brushes.Yellow;
p.Data = _revealShapes.GetOutlinedPathGeometry();
selectionInkCanvas.Children.Clear();
selectionInkCanvas.Children.Add(p);
}
But this is what I get:
http://img72.imageshack.us/img72/1286/actual.png
So where am I going wrong?
TIA,
Ed
The problem is that the Geometry returned by stroke.GetGeometry() is a path around the stroke, so the area you're filling with yellow is just the middle of the stroke. You can see this more clearly if you make the lines thicker:
_revealShapes.Children.Add(stroke.GetGeometry(new DrawingAttributes() { Width = 10, Height = 10 }));
You can do what you want if you convert the list of stylus points to a StreamGeometry yourself:
var geometry = new StreamGeometry();
using (var geometryContext = geometry.Open())
{
var lastPoint = stroke.StylusPoints.Last();
geometryContext.BeginFigure(new Point(lastPoint.X, lastPoint.Y), true, true);
foreach (var point in stroke.StylusPoints)
{
geometryContext.LineTo(new Point(point.X, point.Y), true, true);
}
}
geometry.Freeze();
_revealShapes.Children.Add(geometry);