Bottom edge from a directshape

Bottom edge from a directshape

MiguelGT17
Advocate Advocate
485 Views
4 Replies
Message 1 of 5

Bottom edge from a directshape

MiguelGT17
Advocate
Advocate

Hi everybody! hope this ticket finds you well

I've managed to create direct shapes as baseboard elements, the problem is that those shapes are not editable so I will need to use their location to place family instances. So the real issue is to get 1 of the bottom edges from a cubic solid

 

MiguelGT17_0-1668540512012.png

MiguelGT17_1-1668540547751.png

 

 

I'm using the following piece of code:

 

	                                                foreach (Face face in partialBaseBoard.Faces)
	                                                {	
	                                                    	                                                	
	                                                	PlanarFace planarFace = face as PlanarFace;
	                                                    if (planarFace != null)
	                                                    {
		                                                    #region Method 2: use wall face orientation
		                                                    
		                                                    List<XYZ> pts = new List<XYZ>();
		                                                    
		                                                    //getting the face in contact with the wall (use the -)
		                                                    if (planarWallFc.FaceNormal.IsAlmostEqualTo(-planarFace.FaceNormal)) {
		                                                    	
		                                                    	tailorBird.tessellateFaces(doc,face);
		                                                    	

		                                                    	List<Tuple<Line, double>> lines = new List<Tuple<Line, double>>();
		                                                    	foreach (CurveLoop cvLoop in face.GetEdgesAsCurveLoops()) {
		                                                    		foreach (Curve cv in cvLoop) {
		                                                    			
		                                                    			Line line = cv as Line;
		                                                    			if (line != null) {
		                                                    				if (line.Direction.Z <= 0.05) {
		                                                    					lines.Add(new Tuple<Line, double>(line,line.Length));
		                                                    				}
		                                                    			}
		                                                    		}
		                                                    	}
		                                                    	
		                                                    	if (lines.Any()) {
		                                                    		lines =lines.OrderByDescending(x=>x.Item2).ToList();
		                                                    		Line theLine = lines[0].Item1;
		                                                    		
		                                                    		
		                                                    		
		                                                    		
		                                                    		XYZ init = new XYZ(theLine.GetEndPoint(0).X,theLine.GetEndPoint(0).Y,doc.ActiveView.GenLevel.Elevation);
		                                                    		XYZ end = new XYZ(theLine.GetEndPoint(1).X,theLine.GetEndPoint(1).Y,doc.ActiveView.GenLevel.Elevation);
			                                                    	if (init.DistanceTo(end) > doc.Application.ShortCurveTolerance) {
			                                                    		doc.Create.NewDetailCurve(doc.ActiveView,Line.CreateBound(init,end));
			                                                    	}
		                                                    	}

 

it works fine for the most part as it only retrieves one bottom edge.

 

The problem comes with this room called "STORAGE":

 

somehow in Line 32, I'm filtering one face from the direct shape solid, from it I'm only selecting the larget horizontal edge (Z direction value EQUAL to zero ) and for most rooms this code draws a single line in the space but for this storage room revit is drawing more than 1 line at the same place which doesnt make sense because I'm only passing 1 line as input. So there is not even chance to add overlaping filters between lines because I'm using 1 line as input.

 

  • 3 lines at same place from 1 cubic solid

MiguelGT17_2-1668540953705.png

 

  • 1 large line and 2 small lines:

MiguelGT17_3-1668541044817.png

 

MiguelGT17_4-1668541060793.png

 

Any ideas of what might be causing this issue?

 

In other rooms there are not problems at all

Best regards,

Miguel G.

 

PD: I'm attaching the Revit project with the direct shapes already generated so you guys can do the test

MiguelGT17_5-1668542728941.png

 

 

0 Likes
Accepted solutions (2)
486 Views
4 Replies
Replies (4)
Message 2 of 5

RPTHOMAS108
Mentor
Mentor
Accepted solution

The first plan image above appears to be at a different location to the other two that follow it.

 

I suggest you isolate the wall and 'base board' element and step through with only those items.

 

There are only really two possibilities:

1) The additional lines are being dragged in from a local location via auto join. This doesn't seem to be related to that issue given where the smaller lines end up.

2) The additional lines are added for another element or iteration of the loop.

 

How do you relate the wall to the base board attached to that wall?

 

When you use Line.Direction.Z < 0.05 be aware that all vertical curveloops will have at least one edge predominantly pointing downwards due to the clockwise or anticlockwise nature of the loop. Since you are sorting by length then this is not an issue here.

 

Second thing to note is that sometimes planar faces have multiple regions one example of this can be found for id 1210258. Two isolated cuboids making up the solid should have twelve faces but there are only ten, this highlights that some of the faces on the same plane are shared. The only consequence of this for you is that if you are selecting the longest horizontal edge from all the curveloops then you miss the short section for id 1210258.

 

You have to step through since Revit will only draw one line if you ask for one line. Other lines are happening in other iterations I suspect.

 

Someone checking this will need the walls and further details of how the board has been paired with each wall segment (face normal alone isn't good enough since you have other parallel walls elsewhere). For example you have a more complete model does it have other things hidden that could account for those lines? Would only know the answer to that if you know how the board is associated with the wall (it is not a host relation because it is a direct shape).

 

 

 

Message 3 of 5

MiguelGT17
Advocate
Advocate

Hi Thomas sorry for the late response, I was sick the last days still getting better

With respect to how do I relate baseboards and walls:

  • I'm calculating the spatial geometry for each room to get the room geometry
                        SpatialElementGeometryResults results2 = cal.CalculateSpatialElementGeometry(room);
                        Solid roomSolid2 = results2.GetGeometry(); //GetSolid from spatial geometry
  • Then I loop through each room solid face and gather for the wall that generates this face
                        foreach (Face roomFace in roomSolid2.Faces)
                        {

                            // Filter spatial room Face by same wall Id from wall retrieved from bounding segment, instead of doing FaceNormal.Z != 1 ...etc.
                            IList<SpatialElementBoundarySubface> boundaryGeometryInfoList = results2.GetBoundaryFaceInfo(roomFace);//it will retrieve INFO for geometry boundary that define this specific spatial roomFace
                            foreach (SpatialElementBoundarySubface boundaryGeometryInfo in boundaryGeometryInfoList)//for each wall Info get Face info
                            {
                                if (boundaryGeometryInfo.SubfaceType == SubfaceType.Side) //Work with boundary geometry info that is a side face type
                                {
                                    //get element that gave rise to this geometry face <> wall face
                                    Wall wall = doc.GetElement(boundaryGeometryInfo.SpatialBoundaryElement.HostElementId) as Wall;
  • Finally, for each wall I gather the face that gives origin the room solid face. Once I have this face I manage to get the bottom curves, create and offset and close the boundary profile for the baseboard that will be extruded as a solid afterwards.
Face wallFace = boundaryGeometryInfo.GetBoundingElementFace();
PlanarFace planarWallFc = wallFace as PlanarFace;
Solid baseboard =createSkirtingBoardSolidFromWall(planarWallFc, roomSolid2, skirtingboardHeight, skirtingboardWidth);

 

 

Regarding point 2: "The additional lines are added for another element or iteration of the loop"

I managed to create a list of lines (outside of all the loops) and checked for each loop if a line is already contained in this list by verifying their coordinates:

                                                                    Line line = Line.CreateBound(curve.GetEndPoint(1), curve.GetEndPoint(0));
                                                                    //lines.Add(line);
                                                                    
                                                                    //check if there is already a line includded in the list with same coordinates 
                                                                    foreach (Line ln in lines) {
                                                                    	XYZ init = line.GetEndPoint(0);
                                                                    	XYZ end = line.GetEndPoint(1);
                                                                    	
                                                                    	if ((ln.GetEndPoint(0).DistanceTo(init) <0.1 || ln.GetEndPoint(0).DistanceTo(end)<0.1) 
                                                                    	    && (ln.GetEndPoint(1).DistanceTo(init)<0.1 || ln.GetEndPoint(1).DistanceTo(end)<0.1)) {
                                                                    		
                                                                    		stb.AppendLine(wall.Id.ToString() +" ; " );
                                                                    		
                                                                    	}
                                                                    	else{
                                                                    		lines.Add(line);
                                                                    	}
                                                                    }

 and came with the surprise that there are no extras lines added for loop iteration. 

 

 

My team suspects of the revit project I'm using as for other project units, there are no blockers. I will still debugging this during the next days.

Cheers!

Message 4 of 5

RPTHOMAS108
Mentor
Mentor

Seems your extra lines are from the ends of the adjacent walls.

 

The real task is not to see if you have lines that share the same ends but to count how many lines you have for a certain area i.e. two small lines (one for each adjacent wall end) + 1 long line for the wall parallel to the board in question. How these overlapping lines relate to the walls is not entirely clear at that junction, but it is clear there are three wall segments and three lines. It is also clear that the two overlapping lines likely represent the length of wall between adjacent joins. You need to track which line is created at which iteration then it'll probably make more sense e.g. log the line end points against iteration index of each loop then review.

 

Note SpatialElementBoundarySubface.GetSubface remarks in RevitAPI.chm:

"If the spatial element's face is adjacent to multiple bounding elements (such as two different walls), there will be one sub-face for each portion of the spatial element's face where it is adjacent to one of those room-bounding elements. This is equivalent to the return of GetRoomFace() if the entire room face is created by the boundary element."

 

221119a.PNG

 

Since you know the wall thickness and the angle between two wall segments you can detect out of the three lines which two to discard. An alternative clean up method would be to detect lines within other lines using Intersect method.

 

An alternative overall approach would be to add all the connected wall location curves to a CurveLoop and detect which direction to offset the CurveLoop to get to the desired wall face that coincides with the room. Then you would have to account for door openings etc. (HostParameter/DoorWidth).

 

Message 5 of 5

MiguelGT17
Advocate
Advocate
Accepted solution

I forgot to add that

a). the baseboard profile extruded generate a solid that later it's used to do intersection boolean operation with the room solid and address the problem of creating baseboards outside the room boundary due to walls that surrounds more than 1 room. 

MiguelGT17_0-1668962830530.png

b) Besides that, I'm using boolean difference operation between the baseboard solid result in a) and openings solids from the wall to not place baseboards over the openings. 

 

Solids operations was really helpful to address those blockers

 

-------------------------------------------------------------------

Indeed, there was something wear going on in the loop. This piece of code fixed my problem:

 

 

                                        Level level = room.Level;
                                        RvParam baseC = wall.get_Parameter(BuiltInParameter.WALL_BASE_CONSTRAINT);
                                        if (baseC != null) {
                                        	if (baseC.AsElementId() != level.Id) {
                                        		continue;
                                        	}
                                        }

 

 

we usually used to have 1 revit project for each floor unit. However, for common areas we are working with all the floor plans and obviously some walls from higher or lower levels were surrounding the room space, hence were considered in the loop for placing baseboards.

MiguelGT17_2-1668968336711.png

 

MiguelGT17_1-1668968276049.png

 

 

 

Thank you very much Thomas for your efforts, support and time with this matter,

All the best!

 

Miguel G