void ConvexVolumeTool::handleClick(const float* /*s*/, const float* p, bool shift) { if (!m_sample) return; InputGeom* geom = m_sample->getInputGeom(); if (!geom) return; if (shift) { // Delete int nearestIndex = -1; const ConvexVolume* vols = geom->getConvexVolumes(); for (int i = 0; i < geom->getConvexVolumeCount(); ++i) { if (pointInPoly(vols[i].nverts, vols[i].verts, p) && p[1] >= vols[i].hmin && p[1] <= vols[i].hmax) { nearestIndex = i; } } // If end point close enough, delete it. if (nearestIndex != -1) { geom->deleteConvexVolume(nearestIndex); } } else { // Create // If clicked on that last pt, create the shape. if (m_npts && rcVdistSqr(p, &m_pts[(m_npts-1)*3]) < rcSqr(0.2f)) { if (m_nhull > 2) { // Create shape. float verts[MAX_PTS*3]; for (int i = 0; i < m_nhull; ++i) rcVcopy(&verts[i*3], &m_pts[m_hull[i]*3]); float minh = FLT_MAX, maxh = 0; for (int i = 0; i < m_nhull; ++i) minh = rcMin(minh, verts[i*3+1]); minh -= m_boxDescent; maxh = minh + m_boxHeight; if (m_polyOffset > 0.01f) { float offset[MAX_PTS*2*3]; int noffset = rcOffsetPoly(verts, m_nhull, m_polyOffset, offset, MAX_PTS*2); if (noffset > 0) geom->addConvexVolume(offset, noffset, minh, maxh, (unsigned char)m_areaType); } else { geom->addConvexVolume(verts, m_nhull, minh, maxh, (unsigned char)m_areaType); } } m_npts = 0; m_nhull = 0; } else { // Add new point if (m_npts < MAX_PTS) { rcVcopy(&m_pts[m_npts*3], p); m_npts++; // Update hull. if (m_npts > 1) m_nhull = convexhull(m_pts, m_npts, m_hull); else m_nhull = 0; } } } }
// Calculates convex hull on xz-plane of points on 'pts' ConvexVolume::ConvexVolume(InputGeom* geom, float offset) { // TODO protect against too many vectors! int hullVertIndices[MAX_CONVEXVOL_PTS]; float* pts = geom->getVerts(); int npts = geom->getVertCount(); // Find lower-leftmost point. int hull = 0; for (int i = 1; i < npts; ++i) if (ConvexVolume::cmppt(&pts[i*3], &pts[hull*3])) hull = i; // Gift wrap hull. int endpt = 0; int i = 0; do { hullVertIndices[i++] = hull; endpt = 0; for (int j = 1; j < npts; ++j) if (hull == endpt || ConvexVolume::left(&pts[hull*3], &pts[endpt*3], &pts[j*3])) endpt = j; hull = endpt; } while (endpt != hullVertIndices[0] && i < MAX_CONVEXVOL_PTS/2); // TODO: number of hull points is limited, but in a naive way. In large meshes the best candidate points for the hull might not be selected // Leave the other half of the points for expanding the hull nverts = i; // Copy geometry vertices to convex hull for (int i = 0; i < nverts; i++) rcVcopy(&verts[i*3], &pts[hullVertIndices[i]*3]); area = SAMPLE_POLYAREA_DOOR; // You can choose whatever flag you assing to the poly area // Find min and max height of convex hull hmin = geom->getMeshBoundsMin()[1]; hmax = geom->getMeshBoundsMax()[1]; // 3D mesh min and max bounds rcVcopy(bmin, geom->getMeshBoundsMin()); rcVcopy(bmax, geom->getMeshBoundsMax()); //TODO offsetting is still broken for a lot of shapes! Fix this! // Offset convex hull if needed if(offset > 0.01f) { float offsetVerts[MAX_CONVEXVOL_PTS * 3]; // An offset hull is allowed twice the number of vertices int nOffsetVerts = rcOffsetPoly(verts, nverts, offset, offsetVerts, MAX_CONVEXVOL_PTS); if (nOffsetVerts <= 0) return; for(int i = 0; i < nOffsetVerts; i++) rcVcopy(&verts[i*3], &offsetVerts[i*3]); nverts = nOffsetVerts; // Modify the bounds with offset (except height) bmin[0] = bmin[0]-offset; bmin[2] = bmin[2]-offset; bmax[0] = bmax[0]+offset; bmax[2] = bmax[2]+offset; } }