private void CreateCorridorWalls(XPreviewBuildingStory story) { XbimPoint3D p1 = new XbimPoint3D(0, parameters.CorridorWidth, 0); XbimPoint3D p2 = new XbimPoint3D(parameters.ReferenceLine.Length, parameters.CorridorWidth, 0); XPolygon wallProfile = CreateWallProfile(p1.Distance(p2)); XPreviewWall wall = new XPreviewWall { Name = "Wall ", Location = new XbimPoint3D(0, -parameters.CorridorWidth / 2, 0), ProfilePath = wallProfile.Clone(), Thickness = parameters.InteriorWallThickness, Height = parameters.CeilingElevation, Container = story }; wall = new XPreviewWall { Name = "Wall ", Location = new XbimPoint3D(0, parameters.CorridorWidth / 2, 0), ProfilePath = wallProfile.Clone(), Thickness = parameters.InteriorWallThickness, Height = parameters.CeilingElevation, Container = story }; }
/// <summary> /// distance point is from the axially aligned bounding boxes (usually in object space) /// </summary> /// <param name="pt">Point to get closet point on bounding box from</param> /// <param name="boundBox">Bounding Box as Rect3D</param> /// <returns>Distance from the box edge</returns> internal static double DistanceFromSpace(XbimPoint3D pt, XbimRect3D boundBox) { XbimPoint3D hitPt = ClosetPointOnBoundingBox(pt, boundBox); XbimVector3D vect = XbimPoint3D.Subtract(pt, hitPt); return(vect.Length); }
public IXbimVertex CreateVertexPoint(XbimPoint3D point, double precision) { using (new Tracer(LogHelper.CurrentFunctionName(), this._logger, point)) { return(_engine.CreateVertexPoint(point, precision)); } }
public XbimRegion(string name, XbimRect3D bounds, int population) { this.Name = name; this.Size = new XbimVector3D(bounds.SizeX, bounds.SizeY, bounds.SizeZ); this.Centre = bounds.Centroid(); this.Population = population; }
public IXbimPoint CreatePoint(XbimPoint3D p, double tolerance) { using (new Tracer(LogHelper.CurrentFunctionName(), this._logger, p)) { return(_engine.CreatePoint(p, tolerance)); } }
/// <summary> /// Closet point on a axially aligned bounding boxes (usually in object space) /// REF: 3D Math Primer for Graphics and Game Development. page 720. /// </summary> /// <param name="pt">Point to get closet point on bounding box from</param> /// <param name="boundBox">Bounding Box as Rect3D</param> /// <returns>Point3D (note: if return point == pt point then point inside box</returns> internal XbimPoint3D ClosetPointOnBoundingBox(XbimPoint3D pt, XbimRect3D boundBox) { XbimPoint3D retPt = new XbimPoint3D(); XbimPoint3D MinPt = new XbimPoint3D(boundBox.X, boundBox.Y, boundBox.Z); XbimPoint3D MaxPt = new XbimPoint3D(boundBox.X + boundBox.SizeX, boundBox.Y + boundBox.SizeY, boundBox.Z + boundBox.SizeZ); if (pt.X < MinPt.X) { retPt.X = MinPt.X; } else if (pt.X > MaxPt.X) { retPt.X = MaxPt.X; } if (pt.Y < MinPt.Y) { retPt.Y = MinPt.Y; } else if (pt.Y > MaxPt.Y) { retPt.Y = MaxPt.Y; } if (pt.Z < MinPt.Z) { retPt.Z = MinPt.Z; } else if (pt.Z > MaxPt.Z) { retPt.Z = MaxPt.Z; } return(retPt); }
public TransformedBoundingBox(XbimRect3D boundBox, XbimMatrix3D matrix) : this() { //Object space values MinPt = new XbimPoint3D(boundBox.X, boundBox.Y, boundBox.Z); MaxPt = new XbimPoint3D(boundBox.X + boundBox.SizeX, boundBox.Y + boundBox.SizeY, boundBox.Z + boundBox.SizeZ); //make assumption that the X direction will be the longer length hence the orientation will be along the x axis //transformed values, no longer a valid bounding box in the new space if any Pitch or Yaw MinPt = matrix.Transform(MinPt); MaxPt = matrix.Transform(MaxPt); //--------Calculate rotations from matrix------- //rotation around X,Y,Z axis double rotationZ, rotationY, rotationX; GetMatrixRotations(matrix, out rotationX, out rotationY, out rotationZ); //adjust Z to get clockwise rotation ClockwiseRotation = RadiansToDegrees(rotationZ * -1); //use * -1 to make a clockwise rotation ElevationalRotation = RadiansToDegrees(rotationY); YawRotation = RadiansToDegrees(rotationX); }
public XbimVector3D PointingOutwardFrom(XbimPoint3D point3D) { var v = point3D - Centroid; v.Normalize(); return(v); }
/// <summary> /// Builds a windows Matrix3D from an ObjectPlacement /// Conversion fo c++ function CartesianTransform::ConvertMatrix3D from CartesianTransform.cpp /// </summary> /// <param name="objPlacement">IfcObjectPlacement object</param> /// <returns>Matrix3D</returns> protected XbimMatrix3D ConvertMatrix3D(IfcObjectPlacement objPlacement) { if (objPlacement is IfcLocalPlacement) { IfcLocalPlacement locPlacement = (IfcLocalPlacement)objPlacement; if (locPlacement.RelativePlacement is IfcAxis2Placement3D) { IfcAxis2Placement3D axis3D = (IfcAxis2Placement3D)locPlacement.RelativePlacement; XbimVector3D ucsXAxis = new XbimVector3D(axis3D.RefDirection.DirectionRatios[0], axis3D.RefDirection.DirectionRatios[1], axis3D.RefDirection.DirectionRatios[2]); XbimVector3D ucsZAxis = new XbimVector3D(axis3D.Axis.DirectionRatios[0], axis3D.Axis.DirectionRatios[1], axis3D.Axis.DirectionRatios[2]); ucsXAxis = ucsXAxis.Normalized(); ucsZAxis = ucsZAxis.Normalized(); XbimVector3D ucsYAxis = XbimVector3D.CrossProduct(ucsZAxis, ucsXAxis); ucsYAxis = ucsYAxis.Normalized(); XbimPoint3D ucsCentre = axis3D.Location.XbimPoint3D(); XbimMatrix3D ucsTowcs = new XbimMatrix3D(ucsXAxis.X, ucsXAxis.Y, ucsXAxis.Z, 0, ucsYAxis.X, ucsYAxis.Y, ucsYAxis.Z, 0, ucsZAxis.X, ucsZAxis.Y, ucsZAxis.Z, 0, ucsCentre.X, ucsCentre.Y, ucsCentre.Z, 1); if (locPlacement.PlacementRelTo != null) { return(XbimMatrix3D.Multiply(ucsTowcs, ConvertMatrix3D(locPlacement.PlacementRelTo))); } return(ucsTowcs); } throw new NotImplementedException("Support for Placements other than 3D not implemented"); } throw new NotImplementedException("Support for Placements other than Local not implemented"); }
public void QuaternionVersusMatrixMovingTests() { XbimVector3D t = new XbimVector3D(2, 0, 0); XbimMatrix3D T = new XbimMatrix3D(t); T.RotateAroundZAxis(Math.PI / 2); XbimQuaternion q; XbimQuaternion.RotationMatrix(ref T, out q); // Do the quaternion approach XbimVector3D v = new XbimVector3D(1, 1, 0); XbimVector3D v1; XbimQuaternion.Transform(ref v, ref q, out v1); // Rotate and translate var p1Result = v1 + t; // Do the same with matrix approach XbimPoint3D p = new XbimPoint3D(1, 1, 0); var p2Result = T.Transform(p); Assert.AreEqual(p1Result, XbimPoint3D.Subtract(p2Result, XbimPoint3D.Zero)); // Test quaternion and delta translation (relocating) XbimVector3D mt = new XbimVector3D(2, 2, 0); var dt = t - mt; var pMoved = v1 + dt; var p3Result = pMoved + mt; Assert.AreEqual(p1Result, p3Result); }
/// <summary> /// Clears the current graphics and initiates the cascade of events that result in viewing the scene. /// </summary> /// <param name="EntityLabels">If null loads the whole model, otherwise only elements listed in the enumerable</param> public void LoadGeometry(XbimModel model, bool recalcView = true) { // AddLayerToDrawingControl is the function that actually populates the geometry in the viewer. // AddLayerToDrawingControl is triggered by BuildRefModelScene and BuildScene below here when layers get ready. //reset all the visuals ClearGraphics(recalcView); short userDefinedId = 0; if (model == null) { return; //nothing to show } model.UserDefinedId = userDefinedId; Xbim3DModelContext context = new Xbim3DModelContext(model); XbimRegion largest = context.GetLargestRegion(); XbimPoint3D c = new XbimPoint3D(0, 0, 0); XbimRect3D bb = XbimRect3D.Empty; if (largest != null) { bb = new XbimRect3D(largest.Centre, largest.Centre); } foreach (var refModel in model.ReferencedModels) { XbimRegion r; refModel.Model.UserDefinedId = ++userDefinedId; Xbim3DModelContext refContext = new Xbim3DModelContext(refModel.Model); r = refContext.GetLargestRegion(); if (r != null) { if (bb.IsEmpty) { bb = new XbimRect3D(r.Centre, r.Centre); } else { bb.Union(r.Centre); } } } XbimPoint3D p = bb.Centroid(); _modelTranslation = new XbimVector3D(-p.X, -p.Y, -p.Z); model.ReferencedModels.CollectionChanged += RefencedModels_CollectionChanged; //build the geometric scene and render as we go BuildScene(context); foreach (var refModel in model.ReferencedModels) { Xbim3DModelContext refContext = new Xbim3DModelContext(refModel.Model); BuildScene(refContext); } if (recalcView) { RecalculateView(model); } }
private XPreviewBuilding CreateGarageStructure(XParameters parameters) { XbimPoint3D location = parameters.Perimeter.First(); XPolygon perimeter = parameters.Perimeter.Normalized(location); // Create the building XPreviewBuilding garage = new XPreviewBuilding() { Name = parameters.BuildingName, Location = location, ReferenceDirection = new XbimVector3D(1, 0, 0), Axis = new XbimVector3D(0, 0, 1) }; // Building stories for (int i = 0; i < parameters.NumberOfFloors; i++) { XPreviewBuildingStory story = new XPreviewBuildingStory { Name = "Floor " + (i + 1).ToString(), Location = new XbimPoint3D(0, 0, i * parameters.FloorToFloor), ReferenceDirection = new XbimVector3D(1, 0, 0), Axis = new XbimVector3D(0, 0, 1), Container = garage, StoryNumber = (i + 1), }; } return(garage); }
/// <summary> /// calculates the tansform to convert models to metres and centre on the most populated region, includes reference models /// </summary> /// <returns></returns> private XbimMatrix3D GetGlobalModelTransform() { XbimRegion largest = _context.GetLargestRegion(); XbimRect3D bb = XbimRect3D.Empty; if (largest != null) { bb = new XbimRect3D(largest.Centre, largest.Centre); } foreach (var refModel in _context.Model.ReferencedModels) { XbimRegion r; Xbim3DModelContext refContext = new Xbim3DModelContext(refModel.Model); r = refContext.GetLargestRegion(); if (r != null) { if (bb.IsEmpty) { bb = new XbimRect3D(r.Centre, r.Centre); } else { bb.Union(r.Centre); } } } XbimPoint3D p = bb.Centroid(); var modelTranslation = new XbimVector3D(-p.X, -p.Y, -p.Z); double metreFactor = 1.0 / _context.Model.ModelFactors.OneMetre; return(XbimMatrix3D.CreateTranslation(modelTranslation) * XbimMatrix3D.CreateScale(metreFactor)); }
private static XbimMatrix3D ConvertCartesianTransform3D(IIfcCartesianTransformationOperator3D ct3D) { XbimVector3D u3; //Z Axis Direction XbimVector3D u2; //X Axis Direction XbimVector3D u1; //Y axis direction if (ct3D.Axis3 != null) { var dir = ct3D.Axis3; u3 = new XbimVector3D(dir.X, dir.Y, dir.Z); u3 = u3.Normalized(); } else { u3 = new XbimVector3D(0, 0, 1); } if (ct3D.Axis1 != null) { var dir = ct3D.Axis1; u1 = new XbimVector3D(dir.X, dir.Y, dir.Z); u1 = u1.Normalized(); } else { var defXDir = new XbimVector3D(1, 0, 0); u1 = u3 != defXDir ? defXDir : new XbimVector3D(0, 1, 0); } var xVec = XbimVector3D.Multiply(XbimVector3D.DotProduct(u1, u3), u3); var xAxis = XbimVector3D.Subtract(u1, xVec); xAxis = xAxis.Normalized(); if (ct3D.Axis2 != null) { var dir = ct3D.Axis2; u2 = new XbimVector3D(dir.X, dir.Y, dir.Z); u2 = u2.Normalized(); } else { u2 = new XbimVector3D(0, 1, 0); } var tmp = XbimVector3D.Multiply(XbimVector3D.DotProduct(u2, u3), u3); var yAxis = XbimVector3D.Subtract(u2, tmp); tmp = XbimVector3D.Multiply(XbimVector3D.DotProduct(u2, xAxis), xAxis); yAxis = XbimVector3D.Subtract(yAxis, tmp); yAxis = yAxis.Normalized(); u2 = yAxis; u1 = xAxis; var lo = new XbimPoint3D(ct3D.LocalOrigin.X, ct3D.LocalOrigin.Y, ct3D.LocalOrigin.Z); //local origin return(new XbimMatrix3D(u1.X, u1.Y, u1.Z, 0, u2.X, u2.Y, u2.Z, 0, u3.X, u3.Y, u3.Z, 0, lo.X, lo.Y, lo.Z, 1)); }
/// <summary> /// Creates the partition walls between the units. Not surprisingly uses similar logic to /// creating units /// </summary> /// <param name="story"></param> private void CreatePartitionWalls(XPreviewBuildingStory story) { UnitParameters firstUnit = unitsToCreate.First(); XLine refLine = parameters.ReferenceLine.Transformed(building.InverseGlobalTransform); XbimVector3D cross = refLine.NormalizedVector.CrossProduct(new XbimVector3D(0, 0, 1)); // The reference point on the center line from which the insertion points will be calculated XbimPoint3D referencePoint = new XbimPoint3D(refLine.sp.X + (firstUnit.UnitWidth - parameters.InteriorWallThickness / 2), refLine.sp.Y, refLine.sp.Z); int unitCount = 0; int wallcount = 0; foreach (UnitParameters unit in unitsToCreate) { if (unitCount != unitsToCreate.Count - 1) { // the length of the wall is going to be the minimum of the dwpth of the two units the wall is between double length = Math.Min(unit.UnitDepth, unitsToCreate[unitCount + 1].UnitDepth); if (parameters.CorridorMode != CorridorMode.Left) { // Right of the corridor XbimPoint3D location = cross.GetPoint(referencePoint, parameters.CorridorWidth / 2 + parameters.InteriorWallThickness / 2); XPreviewWall wall = new XPreviewWall { Name = "Wall " + (story.StoryNumber * 100 + wallcount).ToString(), Location = location, Container = story, ProfilePath = CreateWallProfile(length), Height = parameters.CeilingElevation, ReferenceDirection = new XbimVector3D(0, -1, 0) }; wallcount++; } if (parameters.CorridorMode != CorridorMode.Right) { // Left of the corridor XbimPoint3D location = cross.GetPoint(referencePoint, -parameters.CorridorWidth / 2 - parameters.InteriorWallThickness / 2); XPreviewWall wall = new XPreviewWall { Name = "Wall " + (story.StoryNumber * 100 + wallcount).ToString(), Location = location, Container = story, ProfilePath = CreateWallProfile(length), Height = parameters.CeilingElevation, ReferenceDirection = new XbimVector3D(0, 1, 0), }; wallcount++; } // Increment the location. Must use next unit width too as units may be different sizes if (unitCount != unitsToCreate.Count - 1) { UnitParameters nextUnit = unitsToCreate[unitCount + 1]; XbimPoint3D delta = new XbimPoint3D(nextUnit.UnitWidth, 0, 0); referencePoint = XbimPoint3D.Add(referencePoint, delta); } } unitCount++; } }
// todo: create distance function in XbimPoint3D? private double GetDistance(XbimPoint3D point1, XbimPoint3D point2) { return(Math.Sqrt( Math.Pow(point1.X - point2.X, 2) + Math.Pow(point1.Y - point2.Y, 2) + Math.Pow(point1.Z - point2.Z, 2) )); }
public static double Distance(this XbimPoint3D p1, XbimPoint3D p2) { double a = p1.X - p2.X; double b = p1.Y - p2.Y; double c = p1.Z - p2.Z; return(Math.Sqrt(a * a + b * b + c * c)); }
public static IfcGridAxis MakeGridAxis(MemoryModel m, string tag, XbimPoint3D start, XbimVector3D dir, double len) { var gridAxis = m.Instances.New <IfcGridAxis>(); gridAxis.AxisCurve = MakeLine(m, start, dir, len); gridAxis.AxisTag = tag; return(gridAxis); }
public XPreviewBase() { Location = new XbimPoint3D(0, 0, 0); ReferenceDirection = new XbimVector3D(1, 0, 0); Axis = new XbimVector3D(0, 0, 1); // We don't set a guid, when we create the Ifc objects a guid will be created for us GUID = Guid.NewGuid().ToIfcGuid(); }
public static XYZ ToXYZ(this XbimPoint3D p, double scale = 1.0) { return(new XYZ() { X = (p.X * scale), Y = (p.Y * scale), Z = (p.Z * scale) }); }
/// <summary> /// Creates the units. /// </summary> /// <remarks> /// The units are inserted at their bounding box center, so what we need to do is calculate where that center should be. /// Take a point along the corridor center line, using the cross product vector get a point to the right and to the left /// The units profile is already adjusted for whether we are FullDetail or not. /// </remarks> /// <param name="story"></param> private void CreateUnits(XPreviewBuildingStory story) { UnitParameters firstUnit = unitsToCreate.First(); XLine refLine = parameters.ReferenceLine.Transformed(building.InverseGlobalTransform); XbimVector3D cross = refLine.NormalizedVector.CrossProduct(new XbimVector3D(0, 0, 1)); // The reference point on the center line from which the insertion points will be calculated XbimPoint3D referencePoint = new XbimPoint3D(refLine.sp.X + (firstUnit.UnitWidth - parameters.InteriorWallThickness) / 2, refLine.sp.Y, refLine.sp.Z); int unitNumber = 1; // The sequence number used to generate the unit name (incremented for every unit) int unitCount = 0; // The count of units to create, increment every two units (for both sides) foreach (UnitParameters unit in unitsToCreate) { if (parameters.CorridorMode != CorridorMode.Left) { XbimPoint3D location = cross.GetPoint(referencePoint, (unit.UnitDepth + parameters.CorridorWidth) / 2); // Create units to the right XPreviewSpace space = new XPreviewSpace { Name = "Unit " + (story.StoryNumber * 100 + unitNumber).ToString(), // "101, 102, 103" etc. ProfilePath = unit.Profile.Clone(), LongName = unit.UnitType, Height = parameters.CeilingElevation, Location = location, ReferenceDirection = new XbimVector3D(-1, 0, 0), Container = story, Color = unit.Color, }; unitNumber++; } if (parameters.CorridorMode != CorridorMode.Right) { XbimPoint3D location = cross.GetPoint(referencePoint, -(unit.UnitDepth + parameters.CorridorWidth) / 2); // Create units to the left XPreviewSpace space = new XPreviewSpace { Name = "Unit " + (story.StoryNumber * 100 + unitNumber).ToString(), // "101, 102, 103" etc. ProfilePath = unit.Profile.Clone(), LongName = unit.UnitType, Height = parameters.CeilingElevation, Location = location, Container = story, Color = unit.Color }; unitNumber++; } // Increment the location. Must use next unit width too as units may be different sizes if (unitCount != unitsToCreate.Count - 1) { UnitParameters nextUnit = unitsToCreate[unitCount + 1]; XbimPoint3D delta = new XbimPoint3D(unit.UnitWidth / 2 + nextUnit.UnitWidth / 2, 0, 0); referencePoint = XbimPoint3D.Add(referencePoint, delta); } unitCount++; } }
public XbimOctree(XbimOctree <T> copy) { worldSize = copy.worldSize; length = copy.length; objects = copy.objects; children = copy.children; centre = copy.centre; bounds = copy.bounds; }
private bool IsTolerableDifference(XbimPoint3D expectedValue, XbimPoint3D resultingValue) { return (IsTolerableDifference(expectedValue.X, resultingValue.X) && IsTolerableDifference(expectedValue.Y, resultingValue.Y) && IsTolerableDifference(expectedValue.Z, resultingValue.Z) ); }
public static IfcLine MakeLine(MemoryModel m, XbimPoint3D loc, XbimVector3D dir, double len) { var l = m.Instances.New <IfcLine>(); l.Dir = m.Instances.New <IfcVector>(); l.Dir.Magnitude = len; l.Dir.Orientation = m.Instances.New <IfcDirection>(d => d.SetXYZ(dir.X, dir.Y, dir.Z)); l.Pnt = m.Instances.New <IfcCartesianPoint>(p => p.SetXYZ(loc.X, loc.Y, loc.Z)); return(l); }
public static IfcPlane MakePlane(MemoryModel m, XbimPoint3D loc, XbimVector3D zdir, XbimVector3D xdir) { var plane = m.Instances.New <IfcPlane>(); var p = m.Instances.New <IfcAxis2Placement3D>(); p.Axis = m.Instances.New <IfcDirection>(d => d.SetXYZ(zdir.X, zdir.Y, zdir.Z)); p.Location = m.Instances.New <IfcCartesianPoint>(c => c.SetXYZ(loc.X, loc.Y, loc.Z)); p.RefDirection = m.Instances.New <IfcDirection>(d => d.SetXYZ(xdir.X, xdir.Y, xdir.Z)); plane.Position = p; return(plane); }
/// <summary> /// Adds the given object to the octree. /// </summary> /// <param name="o"></param> /// <param name="bBox"></param> public XbimOctree <T> Add(T o, XbimRect3D bBox) { double radius = bBox.Radius(); XbimPoint3D centre = bBox.Centroid(); if (this.bounds.Contains(bBox)) { return(this.Add(o, bBox, centre, radius)); } return(null); }
/// <summary> /// Adds the given object to the octree. /// </summary> /// <param name="o">The object to add.</param> /// <param name="centre">The object's centre coordinates.</param> /// <param name="radius">The object's radius.</param> private XbimOctree <T> Add(T o, XbimPoint3D centre, double radius) { XbimPoint3D min = centre - new XbimVector3D(radius); XbimPoint3D max = centre + new XbimVector3D(radius); XbimRect3D bounds = new XbimRect3D(min, max); if (this.bounds.Contains(bounds)) { return(this.Add(o, bounds, centre, radius)); } return(null); }
internal void AddMesh(byte[] mesh, XbimMatrix3D?transform = null) { int indexBase = Positions.Count; bool needRotate = false; bool needTransform = false; XbimQuaternion xq = new XbimQuaternion(0.0, 0.0, 0.0, 1.0); XbimMatrix3D transformValue = XbimMatrix3D.Identity; if (transform.HasValue) { transformValue = transform.Value; needTransform = !transformValue.IsIdentity; xq = transformValue.GetRotationQuaternion(); // we have to build a rotation transform from the quaternion (to tranform normals later on) needRotate = !xq.IsIdentity(); } using (var ms = new MemoryStream(mesh)) using (var br = new BinaryReader(ms)) { var t = br.ReadShapeTriangulation(); List <float[]> pts; List <int> idx; t.ToPointsWithNormalsAndIndices(out pts, out idx); // add to lists // // Commented because of https://github.com/xBimTeam/XbimGltf/issues/2 //Positions.Capacity += pts.Count; //Normals.Capacity += pts.Count; //Indices.Capacity += idx.Count; foreach (var floatsArray in pts) { var tmpPosition = new XbimPoint3D(floatsArray[0], floatsArray[1], floatsArray[2]); if (needTransform) { tmpPosition = transformValue.Transform(tmpPosition); } Positions.Add(tmpPosition); var tmpNormal = new XbimVector3D(floatsArray[3], floatsArray[4], floatsArray[5]); if (needRotate) //transform the normal if we have to { XbimQuaternion.Transform(ref tmpNormal, ref xq, out tmpNormal); } Normals.Add(tmpNormal); } foreach (var index in idx) { Indices.Add(index + indexBase); } } }
/// <summary> /// Returns true if the triangle that contains the edge is facing away from the centroid of the mesh /// </summary> /// <param name="triangleEdge"></param> /// <returns></returns> public bool IsFacingOutward(XbimTriangleEdge edge) { //find the centroid of the triangle var p1 = _vertices[edge.StartVertexIndex].Position; var p2 = _vertices[edge.NextEdge.StartVertexIndex].Position; var p3 = _vertices[edge.NextEdge.NextEdge.StartVertexIndex].Position; var centroid = new XbimPoint3D((p1.X + p2.X + p3.X) / 3, (p1.Y + p2.Y + p3.Y) / 3, (p1.Z + p2.Z + p3.Z) / 3); var normal = TriangleNormal(edge); var vecOut = PointingOutwardFrom(centroid); var dot = vecOut.DotProduct(normal); return(dot > 0); }
public static IfcAreaMeasure Area(this IfcPolyLoop loop, IfcDirection normal) { var sum = new XbimPoint3D(0, 0, 0); var pts = loop.Polygon; for (var i = 0; i < pts.Count - 1; i++) { sum = XbimPoint3D.Add(sum, pts[i].CrossProduct(pts[i + 1])); } var n = normal.Normalise(); return(n.DotProduct(new XbimVector3D(sum.X, sum.Y, sum.Z)) / 2); }