I need to find out the number of Reference planes and their names which are passing through a selected wall. I can get all the reference planes for a particular document but how shall I do this for a particular wall.
You help would be appreciated!
Thanks.
If the ElementIntersectFilter doesn't work for your needs, you'll have to extract the geometry of the wall and reference plane and work with those directly.
Intersecting the reference planes with the wall solids can work, but there's a simpler answer that will work, if I understand your question correctly. I'm assuming you only want the walls where the green line of the ref plane intersects, rather than treating the reference plane object as an infinite geometric plane. In the screenshot below, I assume you want to find the checkmarks, but not the red X's. I'm also assuming you're looking at this as a plan exercise, and not specifically setting the vertical extents of the reference plane (this is just based on how I've seen most people use Revit). The following function takes as inputs a single wall and a list of ref planes (you mentioned you already have the collection of all ref planes) and will return a list of ref planes which intersect the wall.
public static List<ReferencePlane> getRefPlanesIntersectingWall( Wall wal, List<ReferencePlane> refPlanesIn)
{
//simplify this to a 2D problem, using the location curve of the wall
List<ReferencePlane> refPlanesOut = new List<ReferencePlane>();
LocationCurve wallLocation = wal.Location as LocationCurve;
Curve wallCurve = wallLocation.Curve;
Double wallZ = wallLocation.Curve.GetEndPoint(0).Z;
foreach (ReferencePlane rp in refPlanesIn)
{
XYZ startPt = new XYZ(rp.BubbleEnd.X, rp.BubbleEnd.Y, wallZ);
XYZ endPt = new XYZ(rp.FreeEnd.X, rp.FreeEnd.Y, wallZ);
Line rpLine = Line.CreateBound(startPt, endPt);
SetComparisonResult test = wallCurve.Intersect(rpLine);
if (test == SetComparisonResult.Overlap ||
test == SetComparisonResult.Subset ||
test == SetComparisonResult.Superset ||
test == SetComparisonResult.Equal )
{
refPlanesOut.Add(rp);
}
}
return refPlanesOut;
}
I would start by trying the built-in ElementIntersectFilter. The documentation has a nice example, replace "FamilyInstance" with "referencePlane" and that may do it.
http://www.revitapidocs.com/2017/19276b94-fa39-64bb-bfb8-c16967c83485.htm
If that doesn't work, you'll need to extract the solid of the wall and intersect with the reference plane.
Related
To find elements that are intersecting a geometry I am using the example post by Jeremy in his blog http://thebuildingcoder.typepad.com/blog/2010/12/find-intersecting-elements.html. But the bounding box is always paralell to the axis X, Y and Z and this may cause a problem, like return elements that are not really clashing, because sometimes the bounding box it's not always coincident with the geometry because the family instance is rotated. Besides that, there is the problem that the bounding box will consider the geometry of the symbol and not the instance, and will consider the flipped geometry too, it means that the bounding box is bigger than I am looking for. Is there a way to get the real geometry that are in the currently view ? How can I solve this problem ?
There are many way to address this. Generally, when performing clash detection, you will always run a super fast pre-processing step first to determine candidate elements, and then narrow down the search step by step more precisely in following steps. In this case, you can consider the bounding box intersection the first step, and then perform post-processing afterwards to narrow down the result to your exact goal.
One important question is: does the bounding box really give you all the elements you need, plus more? Are you sure there are none missing?
Once that is settled, all you need to do is add post-processing steps applying the detailed considerations that you care about.
A simple one might be: are all the target element geometry vertices contained in the target volume?
A more complex one might involve retrieving the full solid of the target element and the target volume and performing a Boolean intersection between them to determine completely and exactly whether they intersect, are disjunct, or contained in each other.
Many others are conceivable.
I am using another strategy that is acess the geometry of the instance to verify if the face of the family instace are clashing with a closer conduit.
class FindIntersection
{
public Conduit ConduitRun { get; set; }
public FamilyInstance Jbox { get; set; }
public List<Conduit> GetListOfConduits = new List<Conduit>();
public FindIntersection(FamilyInstance jbox, UIDocument uiDoc)
{
XYZ jboxPoint = (jbox.Location as LocationPoint).Point;
FilteredElementCollector filteredCloserConduits = new FilteredElementCollector(uiDoc.Document);
List<Element> listOfCloserConduit = filteredCloserConduits.OfClass(typeof(Conduit)).ToList().Where(x =>
((x as Conduit).Location as LocationCurve).Curve.GetEndPoint(0).DistanceTo(jboxPoint) < 30 ||
((x as Conduit).Location as LocationCurve).Curve.GetEndPoint(1).DistanceTo(jboxPoint) < 30).ToList();
//getting the location of the box and all conduit around.
Options opt = new Options();
opt.View = uiDoc.ActiveView;
GeometryElement geoEle = jbox.get_Geometry(opt);
//getting the geometry of the element to acess the geometry of the instance.
foreach (GeometryObject geomObje1 in geoEle)
{
GeometryElement geoInstance = (geomObje1 as GeometryInstance).GetInstanceGeometry();
//the geometry of the family instance can be acess by this method that returns a GeometryElement type.
//so we must get the GeometryObject again to acess the Face of the family instance.
if (geoInstance != null)
{
foreach (GeometryObject geomObje2 in geoInstance)
{
Solid geoSolid = geomObje2 as Solid;
if (geoSolid != null)
{
foreach (Face face in geoSolid.Faces)
{
foreach (Element cond in listOfCloserConduit)
{
Conduit con = cond as Conduit;
Curve conCurve = (con.Location as LocationCurve).Curve;
SetComparisonResult set = face.Intersect(conCurve);
if (set.ToString() == "Overlap")
{
//getting the conduit the intersect the box.
GetListOfConduits.Add(con);
}
}
}
}
}
}
}
}
}
Can you please provide a complete minimal reproducible case so we can understand the exact context and analyse what can be done? Maybe you could include one axis-aligned junction box and one that is not, so we can see how ell versus how badly your existing algorithm performs. Thank you!
I summarised this discussion and the results to date in a blog post on filtering for intersecting elements and conduits intersecting a junction box.
I am trying to accomplish a simple task using a 2D graphics library called paperscript. I have a grid of dots and I would like to recalculate the position of those dots based on the position of the mouse cursor so that the dot is displaced from it's original position in the opposite direction that the mouse cursor is from the original position, and displaced by a distance that is inversely proportional to the distance of the mouse cursor to the original position. Hopefully this diagram makes it a little clearer:
I know how to get the current position of the mouse, as well as the position of each dot. What I have been having trouble with, is creating a function that will take those two variables and use it to calculate a new position for each dot that will create the above described effect.
I have a jsfiddle here with what I've created so far.
https://jsfiddle.net/yc62k/247xwh8q/4/
function onFrame(event) {
//Loop through all the dots
for (i = 0; i < count; i++) {
var item = project.activeLayer.children[i];
//Update the position of the dot based on the mouse position
??????
item.position = new Point(
(newPosition.x),
(newPosition.y)
);
}
}
Can anyone suggest an algorithm I can use in this function to get this effect? Or point me in the direction of the maths I would use to solve this problem? Any help would be greatly appreciated!
If the old position of the dot is pDot and the position of the mouse is pMouse, then the direction of movement is
dir = pDot - pMouse
To establish the desired scale (inversely proportional to the distance), just divide by the squared length. Then, the new position is:
pDotNew = pDot + dir * (1.0 / squaredLength(dir))
Be careful about how often you update the positions. If you update them very frequently, the points might move very fast. If this is the case, multiply the direction with a small number (between 0 and 1). Ideally, this number should depend on the update interval in order to maintain a consistent movement speed.
I'm having a problem that I need to make the words I took from an external file "NOT" overlap each other. I have over 50 words that have random text sizes and places when you run it but they overlap.
How can I make them "NOT" overlap each other? the result would probably look like a word cloud.
if you think my codes would help here they are
String [] words;
int index = 0;
void setup ()
{
size (500,500);
background (255);
String [] lines = loadStrings ("alice_just_text.txt");
String entireplay = join(lines, " "); //splits it by line
words = splitTokens (entireplay, ",.?!:-;:()03 "); //splits it by word
for (int i = 0; i < 50; i++) {
float x = random(width);
float y = random(height);
int index = int(random(words.length));
textSize (random(60)); //random font size
fill (0);
textAlign (CENTER);
text (words[index], x, y, width/2, height/2);
println(words[index]);
index++ ;
}
}
Stack Overflow isn't really designed for general "how do I do this" type questions. You'll have much better luck if you post a more specific "I tried X, expected Y, but got Z instead" type question. But I'll try to help in a general sense:
You need to break your problem down into smaller pieces and then take on those pieces one at a time.
For example, you can isolate your problem to making sure rectangles don't overlap, which you can break down even further. There are a number of ways to do that:
You could use a grid to lay out your rectangles. Figure out how many squares a line of text takes up, then find a place in your grid where that word will fit. You could use something like a 2D array of boolean values, for example.
Or you could generate a random location, and then check whether there's already a rectangle there. If so, pick a new random location until you find a clear spot.
In any case, you'll probably need to use collision detection (either point-rectangle or rectangle-rectangle) to determine whether your rectangles are overlapping.
Start small. Create a small example program that just shows two rectangles on the screen. Hardcode their positions at first, but make it so they turn red if they're colliding. Work your way up from there. Make it so you can add rectangles using the mouse, but only let the user add them if there is no overlap. Then add the random location choosing. If you get stuck on a specific step, then post a MCVE and we'll go from there. Good luck.
Does anyone knows how can I convert from image coordinates acquired like this:
private void renderWindowControl1_Click(object sender, System.EventArgs e)
{
int[] lastPos = this.renderWindowControl1.RenderWindow.GetInteractor().GetLastEventPosition();
Z1TxtBox.Text = (_Slice1 + 1).ToString();
X1TxtBox.Text = lastPos[0].ToString();
Y1TxtBox.Text = (512 - lastPos[1]).ToString();
}
into physical coordinates.
TX Tal
VTK may have an elegant method call, but in general you will need to use the information in your image's image plane module (specifically Equation C.7.6.2.1-1).
http://dicom.nema.org/medical/dicom/current/output/html/part03.html#sect_C.7.6.2
in order to convert between a click and physical location:
There is some insights I got from working on this project:
int[] lastPos = this.renderWindowControl1.RenderWindow.GetInteractor().GetLastEventPosition();
returns the pixel location of the click in the control. It is a problem because if the user zooms in, lastPos does not represent the location in the dicom.
The solution I have found, was to use vtkPropPicker class. Code example can be found here and here.
image_coordinate are in world coordinates but without the origin offset. which mean, that:
1. if we want to get the pixel location (in 512x512 grid): the x,y value should be normalized by pixel spacing, and image orientation. the value of these parameters can be acquired using the equation mentioned in the answer above me Equation C.7.6.2.1-1.
vtkDICOMImageReader _reader;
reader.GetPixelSpacing();
reader.GetImageOrientationPatient();
If we need world physical location, we should add the origin offset for x and y:
reader.GetDataOrigin();
As for Z axis: I didn't need it, so I am not sure.
That is my dime on the matter, maybe there are some more elegant ways, I haven't found them.
Let's say that I want to calculate the distance between two geometries with JTS, but there is another one in the middle that I can't go across (as if it was a wall). It could look like this :
I wonder how I could calculate that.
In this case, these shapes geom1 and geom2 are 38.45 meters away, as I calculate it straight away. But if I don't want go across that line, I should surround it by the Northern sides, and distance would probably be more than 70 meters away.
We can think that we could have a line a polygon or whatever in the middle.
I wonder if there is any built in function in JTS, or some other thing I could you. I guess if there is anything out there, I should check for some other workaround, as trying to solve complex routing problems is beyond my knowledge.
This is the straight away piece of code using JTS for the distance, which would not still take into account the Geometry in the middle.
import org.apache.log4j.Logger;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;
public class distanceTest {
private final static Logger logger = Logger.getLogger("distanceTest");
public static void main(String [] args) {
//Projection : EPSG:32631
// We build one of the geometries on one side
String sGeom1="POLYGON ((299621.3240601513 5721036.003245114, 299600.94820609683 5721085.042327096, 299587.7719688322 5721052.9152064435, 299621.3240601513 5721036.003245114))";
Geometry geom1=distanceTest.buildGeometry(sGeom1);
// We build the geometry on the other side
String sGeom2=
"POLYGON ((299668.20990794065 5721092.766132105, 299647.3623194871 5721073.557249224, 299682.8494029705 5721049.148841454, 299668.20990794065 5721092.766132105))";
Geometry geom2=distanceTest.buildGeometry(sGeom2);
// There is a geometry in the middle, as if it was a wall
String split=
"LINESTRING (299633.6804935104 5721103.780167559, 299668.99872434285 5720999.981241705, 299608.8457218057 5721096.601805294)";
Geometry splitGeom=distanceTest.buildGeometry(split);
// We calculate the distance not taking care of the wall in the middle
double distance = geom1.distance(geom2);
logger.error("Distance : " + distance);
}
public static Geometry buildGeometry(final String areaWKT) {
final WKTReader fromText = new WKTReader();
Geometry area;
try {
area = fromText.read(areaWKT);
}
catch (final ParseException e) {
area = null;
}
return area;
}
}
This works for SQL, I hope you have the same or similar methods at your disposal.
In theory, in this instance you could create a ConvexHull containing the two geometries AND your "unpassable" geometry.
Geometry convexHull = sGeom1.STUnion(sGeom2).STUnion(split).STConvexHull();
Next, extract the border of the ConvexHull to a linestring (use STGeometry(1) - I think).
Geometry convexHullBorder = convexHull.STGeometry(1);
EDIT: Actually, with Geometry you can use STExteriorRing().
Geometry convexHullBorder = convexHull.STExteriorRing();
Lastly, pick one of your geometries, and for each shared point with the border of the ConvexHull, walk the border from that point until you reach the first point that is shared with the other geometry, adding the distance between the current and previous point at each point reached. If the second point you hit belongs to the same geometry as you are walking from, exit the loop and move on to the next to reduce time. Repeat for the second geometry.
When you've done this for all possibilities, you can simply take the minimum value (there will be only two - Geom1 to Geom2 and Geom2 to Geom1) and there is your answer.
Of course, there are plenty of scenarios in which this is too simple, but if all scenarios simply have one "wall" in them, it will work.
Some ideas of where it will not work:
The "wall" is a polygon, fully enveloping both geometries - but then how would you ever get there anyway?
There are multiple "walls" which do not intersect each other (gaps between them) - this method will ignore those passes in between "walls". If however multiple "walls" intersect, creating essentially one larger "wall" the theory will still work.
Hope that makes sense?
EDIT: Actually, upon further reflection there are other scenarios where the ConvexHull approach will not work, for instance the shape of your polygon could cause the ConvexHull to not produce the shortest path between geometries and your "walls". This will not get you 100% accuracy.