RH_C_FUNCTION ON_MassProperties* ON_Curve_AreaMassProperties(const ON_Curve* pCurve, double rel_tol, double abs_tol, double curve_planar_tol) { ON_MassProperties* rc = NULL; if( pCurve ) { ON_Plane plane; if( pCurve->IsPlanar(&plane, curve_planar_tol) && pCurve->IsClosed() ) { ON_BoundingBox bbox = pCurve->BoundingBox(); ON_3dPoint basepoint = bbox.Center(); basepoint = plane.ClosestPointTo(basepoint); rc = new ON_MassProperties(); bool getresult = pCurve->AreaMassProperties(basepoint, plane.Normal(), *rc, true, true, true, true, rel_tol, abs_tol); if( getresult ) { rc->m_mass = fabs(rc->m_mass); } else { delete rc; rc = NULL; } } } return rc; }
RH_C_FUNCTION ON_MassProperties* ON_Geometry_AreaMassProperties(const ON_SimpleArray<const ON_Geometry*>* pConstGeometryArray, double relativeTolerance, double absoluteTolerance) { ON_MassProperties* rc = NULL; if( pConstGeometryArray && pConstGeometryArray->Count() > 0 ) { ON_BoundingBox bbox; for( int i = 0; i < pConstGeometryArray->Count(); i++ ) { const ON_Geometry* geo = (*pConstGeometryArray)[i]; if( NULL==geo ) continue; geo->GetBoundingBox(bbox,TRUE); } ON_3dPoint basepoint = bbox.Center(); // Aggregate all mass properties for( int i = 0; i < pConstGeometryArray->Count(); i++ ) { const ON_Geometry* geo = (*pConstGeometryArray)[i]; if( NULL==geo ) continue; bool success = false; ON_MassProperties mp; const ON_Brep* pBrep = ON_Brep::Cast(geo); if( pBrep ) success = pBrep->AreaMassProperties(mp, true, true, true, true, relativeTolerance, absoluteTolerance); const ON_Surface* pSurface = success?0:ON_Surface::Cast(geo); if( pSurface ) success = pSurface->AreaMassProperties(mp, true, true, true, true, relativeTolerance, absoluteTolerance); const ON_Mesh* pMesh = success?0:ON_Mesh::Cast(geo); if( pMesh ) success = pMesh->AreaMassProperties(mp, true, true, true, true); const ON_Curve* pCurve = success?0:ON_Curve::Cast(geo); ON_Plane plane; if( pCurve && pCurve->IsPlanar(&plane, absoluteTolerance) && pCurve->IsClosed() ) success = pCurve->AreaMassProperties(basepoint, plane.Normal(), mp, true, true, true, true, relativeTolerance, absoluteTolerance); if( success ) { if( NULL==rc ) rc = new ON_MassProperties(mp); else rc->Sum(1, &mp, true); } } } return rc; }
RH_C_FUNCTION ON_MassProperties* ON_GeometryMassProperties(bool bArea, ON_SimpleArray<const ON_Geometry*>* pGeometry, double relativeTolerance, double absoluteTolerance) { ON_MassProperties* rc = NULL; if( pGeometry && pGeometry->Count() > 0 ) { // Compute base-point of all geometry boundingboxes ON_3dPoint basePoint(0,0,0); if( !bArea ) { for( int i = 0; i < pGeometry->Count(); i++ ) { const ON_Geometry* geo = pGeometry->Array()[i]; ON_BoundingBox box = geo->BoundingBox(); basePoint += box.Center(); } basePoint /= pGeometry->Count(); } // Aggregate all mass properties rc = new ON_MassProperties(); for( int i = 0; i < pGeometry->Count(); i++ ) { const ON_Geometry* geo = pGeometry->Array()[i]; bool success = false; ON_MassProperties mp; ON::object_type type = pGeometry->Array()[i]->ObjectType(); const ON_Brep* pBrep; const ON_Surface* pSurface; const ON_Mesh* pMesh; const ON_Curve* pCurve; switch (type) { case ON::brep_object: pBrep = ON_Brep::Cast(geo); if( bArea ) success = pBrep->AreaMassProperties(mp, true, true, true, true, relativeTolerance, absoluteTolerance); else success = pBrep->VolumeMassProperties(mp, true, true, true, true, basePoint, relativeTolerance, absoluteTolerance); break; case ON::surface_object: pSurface = ON_Surface::Cast(geo); if( bArea ) success = pSurface->AreaMassProperties(mp, true, true, true, true, relativeTolerance, absoluteTolerance); else success = pSurface->VolumeMassProperties(mp, true, true, true, true, basePoint, relativeTolerance, absoluteTolerance); break; case ON::mesh_object: pMesh = ON_Mesh::Cast(geo); if( bArea ) success = pMesh->AreaMassProperties(mp, true, true, true, true); else success = pMesh->VolumeMassProperties(mp, true, true, true, true, basePoint); break; case ON::curve_object: if (bArea) { pCurve = ON_Curve::Cast(geo); ON_Plane plane; if( pCurve->IsPlanar(&plane, absoluteTolerance) && pCurve->IsClosed() ) { success = pCurve->AreaMassProperties(basePoint, plane.Normal(), mp, true, true, true, true, relativeTolerance, absoluteTolerance); if (success ) { mp.m_mass = fabs(mp.m_mass); } } } break; } if( success ) { rc->Sum(1, &mp, true); } } } return rc; }
int negative_polygon(struct subbrep_object_data *data) { int io_state = 0; int all_faces_cnt = 0; std::vector<int> all_faces; int *final_faces = NULL; std::set<int> fol_faces; /* This will get reused for all faces, so make it once */ point_t *all_verts = (point_t *)bu_calloc(data->brep->m_V.Count(), sizeof(point_t), "bot verts"); for (int vi = 0; vi < data->brep->m_V.Count(); vi++) { VMOVE(all_verts[vi], data->brep->m_V[vi].Point()); } array_to_set(&fol_faces, data->fol, data->fol_cnt); // Check each face to see if it is fil or fol - the first fol face, stash its // normal - don't even need the triangle face normal, we can just use the face's normal and // a point from the center of one of the fol triangles on that particular face. ON_3dPoint origin_pnt; ON_3dVector triangle_normal; int have_hit_pnt = 0; /* Get triangles from the faces */ ON_BoundingBox vert_bbox; ON_MinMaxInit(&vert_bbox.m_min, &vert_bbox.m_max); for (int i = 0; i < data->loops_cnt; i++) { const ON_BrepLoop *b_loop = &(data->brep->m_L[data->loops[i]]); int *ffaces = NULL; int num_faces = subbrep_polygon_tri(data->brep, all_verts, (int *)&(b_loop->m_loop_index), 1, &ffaces); if (!num_faces) { bu_log("Error - triangulation failed for loop %d!\n", b_loop->m_loop_index); return 0; } if (!have_hit_pnt) { const ON_BrepFace *b_face = b_loop->Face(); if (fol_faces.find(b_face->m_face_index) != fol_faces.end()) { ON_3dPoint p1 = data->brep->m_V[ffaces[0]].Point(); ON_3dPoint p2 = data->brep->m_V[ffaces[1]].Point(); ON_3dPoint p3 = data->brep->m_V[ffaces[2]].Point(); ON_Plane fp; ON_Surface *ts = b_face->SurfaceOf()->Duplicate(); (void)ts->IsPlanar(&fp, BREP_PLANAR_TOL); delete ts; triangle_normal = fp.Normal(); if (b_face->m_bRev) triangle_normal = triangle_normal * -1; origin_pnt = (p1 + p2 + p3) / 3; have_hit_pnt = 1; } } for (int f_ind = 0; f_ind < num_faces*3; f_ind++) { all_faces.push_back(ffaces[f_ind]); vert_bbox.Set(data->brep->m_V[ffaces[f_ind]].Point(), true); } if (ffaces) bu_free(ffaces, "free polygon face array"); all_faces_cnt += num_faces; } /* Now we can build the final faces array */ final_faces = (int *)bu_calloc(all_faces_cnt * 3, sizeof(int), "final bot verts"); for (int i = 0; i < all_faces_cnt*3; i++) { final_faces[i] = all_faces[i]; } // Scale bounding box to make sure corners are away from the volume vert_bbox.m_min = vert_bbox.m_min * 1.1; vert_bbox.m_max = vert_bbox.m_max * 1.1; // Pick a ray direction ON_3dVector rdir; ON_3dPoint box_corners[8]; vert_bbox.GetCorners(box_corners); int have_dir = 0; int corner = 0; double dotp; while (!have_dir && corner < 8) { rdir = box_corners[corner] - origin_pnt; dotp = ON_DotProduct(triangle_normal, rdir); (NEAR_ZERO(dotp, 0.01)) ? corner++ : have_dir = 1; } if (!have_dir) { bu_log("Error: NONE of the corners worked??\n"); return 0; } point_t origin, dir; VMOVE(origin, origin_pnt); VMOVE(dir, rdir); #if 0 std::cout << "working: " << bu_vls_addr(data->key) << "\n"; bu_log("in origin.s sph %f %f %f 1\n", origin[0], origin[1], origin[2]); bu_log("in triangle_normal.s rcc %f %f %f %f %f %f 1 \n", origin_pnt.x, origin_pnt.y, origin_pnt.z, triangle_normal.x, triangle_normal.y, triangle_normal.z); bu_log("in ray.s rcc %f %f %f %f %f %f 1 \n", origin[0], origin[1], origin[2], dir[0], dir[1], dir[2]); #endif // Test the ray against the triangle set int hit_cnt = 0; point_t p1, p2, p3, isect; ON_3dPointArray hit_pnts; for (int i = 0; i < all_faces_cnt; i++) { ON_3dPoint onp1, onp2, onp3, hit_pnt; VMOVE(p1, all_verts[all_faces[i*3+0]]); VMOVE(p2, all_verts[all_faces[i*3+1]]); VMOVE(p3, all_verts[all_faces[i*3+2]]); onp1.x = p1[0]; onp1.y = p1[1]; onp1.z = p1[2]; onp2.x = p2[0]; onp2.y = p2[1]; onp2.z = p2[2]; onp3.x = p3[0]; onp3.y = p3[1]; onp3.z = p3[2]; ON_Plane fplane(onp1, onp2, onp3); int is_hit = bg_isect_tri_ray(origin, dir, p1, p2, p3, &isect); VMOVE(hit_pnt, isect); // Don't count the point on the ray origin if (hit_pnt.DistanceTo(origin_pnt) < 0.0001) is_hit = 0; if (is_hit) { // No double-counting for (int j = 0; j < hit_pnts.Count(); j++) { if (hit_pnts[j].DistanceTo(hit_pnt) < 0.001) is_hit = 0; } if (is_hit) { //bu_log("in hit_cnt%d.s sph %f %f %f 0.1\n", hit_pnts.Count()+1, isect[0], isect[1], isect[2]); hit_pnts.Append(hit_pnt); } } } hit_cnt = hit_pnts.Count(); //bu_log("hit count: %d\n", hit_cnt); //bu_log("dotp : %f\n", dotp); // Final inside/outside determination if (hit_cnt % 2) { io_state = (dotp > 0) ? -1 : 1; } else { io_state = (dotp < 0) ? -1 : 1; } //bu_log("inside out state: %d\n", io_state); bu_free(all_verts, "free top level vertex array"); bu_free(final_faces, "free face array"); return io_state; }