/** * Sets the bounding box of the mesh to \a box and its center to \a center. */ void SoPolygon::computeBBox(SoAction *action, SbBox3f &box, SbVec3f ¢er) { SoState* state = action->getState(); const SoCoordinateElement * coords = SoCoordinateElement::getInstance(state); if (!coords) return; const SbVec3f * points = coords->getArrayPtr3(); if (!points) return; float maxX=-FLT_MAX, minX=FLT_MAX, maxY=-FLT_MAX, minY=FLT_MAX, maxZ=-FLT_MAX, minZ=FLT_MAX; int32_t len = coords->getNum(); int32_t beg = startIndex.getValue(); int32_t cnt = numVertices.getValue(); int32_t end = beg + cnt; if (end <= len) { for (int32_t i=beg; i<end; i++) { maxX = std::max<float>(maxX,points[i][0]); minX = std::min<float>(minX,points[i][0]); maxY = std::max<float>(maxY,points[i][1]); minY = std::min<float>(minY,points[i][1]); maxZ = std::max<float>(maxZ,points[i][2]); minZ = std::min<float>(minZ,points[i][2]); } box.setBounds(minX,minY,minZ,maxX,maxY,maxZ); center.setValue(0.5f*(minX+maxX),0.5f*(minY+maxY),0.5f*(minZ+maxZ)); } else { box.setBounds(SbVec3f(0,0,0), SbVec3f(0,0,0)); center.setValue(0.0f,0.0f,0.0f); } }
// Doc in parent void SoVRMLCone::computeBBox(SoAction * COIN_UNUSED_ARG(action), SbBox3f & box, SbVec3f & center) { float r = this->bottomRadius.getValue(); float h = this->height.getValue(); // Allow negative values. if (h < 0.0f) h = -h; if (r < 0.0f) r = -r; float half_height = h * 0.5f; // The SIDES are present, so just find the middle point and enclose // everything. if (this->side.getValue()) { center.setValue(0.0f, 0.0f, 0.0f); box.setBounds(SbVec3f(-r, -half_height, -r), SbVec3f(r, half_height, r)); } // ..no SIDES, but we've still got the bottom (NB: OIV misses this case). else if (this->bottom.getValue()) { center.setValue(0.0f, -half_height, 0.0f); box.setBounds(SbVec3f(-r, -half_height, -r), SbVec3f(r, -half_height, r)); } // ..no parts present. My confidence is shot -- I feel very small. else { center.setValue(0.0f, 0.0f, 0.0f); box.setBounds(SbVec3f(0.0f, 0.0f, 0.0f), SbVec3f(0.0f, 0.0f, 0.0f)); } }
void SoCylinder::computeBBox(SoAction *, SbBox3f &box, SbVec3f ¢er) // //////////////////////////////////////////////////////////////////////// { int curParts = (parts.isIgnored() ? ALL : parts.getValue()); if (curParts == 0) // No parts at all! box.setBounds(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); else { float r, h; SbVec3f min, max; getSize(r, h); if (HAS_PART(curParts, SIDES | TOP)) max.setValue( r, h, r); else max.setValue( r, -h, r); if (HAS_PART(curParts, SIDES | BOTTOM)) min.setValue(-r, -h, -r); else min.setValue(-r, h, -r); box.setBounds(min, max); } center.setValue(0.0, 0.0, 0.0); }
int QilexDoc::doc_new_kinematic_hand(ct_new_kinematic_chain *data) { int error = 0; int tipus = 0; void * buffer ; //char *buffer; char *buftemp = (char*)malloc(1024); SoOutput out; size_t sizeModel = 0; SoSeparator *kinechain = new SoSeparator; SoSeparator *kinetest = new SoSeparator; Rchain_hand *kineengine = new Rchain_hand(); SoTransform *pos_rot = new SoTransform; SbVec3f joinax; joinax.setValue(SbVec3f(data->x,data->y,data->z)); pos_rot->translation.setValue(joinax); pos_rot->rotation.setValue(SbVec3f(data->axeX, data->axeY, data->axeZ), (float) rad((double) data->angle)); kinechain = readFile(data->QsModelFile.latin1(), tipus); if (kinechain == NULL) // no object read { return 1; } else // ok, there's no object with the same name { error = kineengine->init_dat(data->QsDatFile.latin1()); // if (error == 0) { kinechain->ref(); kinetest = (SoSeparator*)SoNode::getByName(data->QsName.latin1()); if (kinetest==NULL) { //we need to put it in a buffer to write the xml file // if is Ok SoOutput out; out.setBuffer(buftemp, 1024, reallocCB); SoWriteAction wa1(&out); wa1.apply(kinechain); out.getBuffer(buffer, sizeModel); kinechain->insertChild(pos_rot, 0); } error = doc_insert_kinematic_hand(kineengine, kinechain); } } if (error==0) { writeXML_kineelement((char *)buffer, sizeModel, tipus, data, kineengine); } return error; }
bool RayTracer::depth_of_field(int i, int j, SbVec3f *position, SbVec3f *color){ SbVec3f tempColor; float R = DISK_SIZE; float du; float dv; bool should_color ; int number_of_jitter_positions = NUMBER_OF_CAMERAS; if(depth_of_field_on == 0) { should_color = distribute_shade(i,j, position, color); } else{ for(int k =0; k< number_of_jitter_positions ; k++){ SbVec3f camera_position = *position; du = get_random_number(); dv = get_random_number(); camera_position = camera_position + (du * R * pixel_width * this->u) + (dv * pixel_height * R * this->v); tempColor.setValue(0.0,0.0,0.0); should_color = distribute_shade(i, j, &camera_position,&tempColor); *color = *color + tempColor; } *color = *color/number_of_jitter_positions ; } return should_color; }
void SoNurbsSurface::computeBBox(SoAction *action, SbBox3f &box, SbVec3f ¢er) // //////////////////////////////////////////////////////////////////////// { const SoCoordinateElement *ce = SoCoordinateElement::getInstance(action->getState()); int32_t nCoords, numSurfCoords; int j, curCoord; SbVec3f tmpCoord; // // Loop through coordinates, keeping max bounding box and sum of coords // If the coordinates are rational, divide the first three values by // the fourth value before extending the bounding box. // numSurfCoords = numUControlPoints.getValue() * numVControlPoints.getValue(); nCoords = ce->getNum(); // Check for a degenerate surface if ((numSurfCoords == 0) || (nCoords == 0)) return; curCoord = 0; center.setValue(0.0, 0.0, 0.0); if (ce->is3D()) { for (j = 0; j < numSurfCoords; j++) { // // Wrap around if necessary // if (curCoord >= nCoords) curCoord = 0; const SbVec3f &coord = ce->get3(curCoord); box.extendBy(coord); center += coord; curCoord++; } } else { for (j = 0; j < numSurfCoords; j++) { // // Wrap around if necessary // if (curCoord >= nCoords) curCoord = 0; const SbVec4f &coord = ce->get4(curCoord); coord.getReal (tmpCoord); box.extendBy (tmpCoord); center += tmpCoord; curCoord++; } } center /= (float) numSurfCoords; }
/*! \param orientation * \param[out] upVec * \param[out] lookDir * \param[out] upVecAngle */ void kCamera::splitOrientation(const SbRotation orientation, SbVec3f& upVec, SbVec3f& lookDir, double& upVecAngle) { // Extrahieren der lookDir aus der aktuellen orientation lookDir.setValue(0.0, 0.0, -1.0); //! init to default lookat direction (DIRECTION!) orientation.multVec(lookDir, lookDir); lookDir.normalize(); // Extrahieren des upVectors aus der aktuellen orientation upVec.setValue(0.0, 1.0, 0.0); // init to default up vector direction orientation.multVec(upVec, upVec); upVec.normalize(); // Ermitteln des perfekten upVectors (upVector ohne zusätzliche Drehung um die Sichtachse) SbVec3f perfectUpVec; if (fabs(lookDir.dot(NormPlump))>(1.0-epsilon)) //! wenn lookDir und perfectUpVec parallel, dann gleich setzen (Vermeidung von Berechnungsfehlern perfectUpVec = upVec; else perfectUpVec = calcPerfectUpVector(lookDir,NormPlump); perfectUpVec.normalize(); // a dot b = |a|*|b|+cos(a,b) double tempDot = upVec.dot(perfectUpVec); //! Es gab Fälle, in denen war .dot minimal größer als 1.0 -> acos = 1.#IND if (tempDot>1.0) tempDot = 1.0; if (tempDot<-1.0) tempDot = -1.0; upVecAngle = acos(tempDot); //! 1.0 = Produkt der beiden Längen ... sind aber normalisiert // Ermittlung der Drehrichtung des Winkels und ggf. Erhöhung um 180Grad // Im R3 gibt es zuerst einmal keine positiven und negativen drehwinkel. // Erst wenn man die Ebene, die die beiden Vektoren definieren, orientiert, geht das. // Man kann also festlegen, dass der Winkel positiv ist, wenn Hesse-Normalenvektor der Ebene und Kreuzprodukt in dieselbe Richtung zeigen. if (getUpVecAngleDir(lookDir,upVec)>epsilon && (upVecAngle<(kBasics::PI-epsilon))) upVecAngle = kBasics::PI + (kBasics::PI - upVecAngle); // Vermeidung von Winkeln > 2*PI if (upVecAngle>(2*(kBasics::PI-epsilon))) upVecAngle = upVecAngle - 2*kBasics::PI; // Sehr kleine Winkel werden auf 0.0 gesetzt if (fabs(upVecAngle)<epsilon) upVecAngle = 0.0; //! sonst kommt es zu Dingen wie 1.#IND }
void SbMatrix::multDirMatrix(const SbVec3f &src, SbVec3f &dst) const { float x,y,z; x = src[0]*matrix[0][0] + src[1]*matrix[1][0] + src[2]*matrix[2][0]; y = src[0]*matrix[0][1] + src[1]*matrix[1][1] + src[2]*matrix[2][1]; z = src[0]*matrix[0][2] + src[1]*matrix[1][2] + src[2]*matrix[2][2]; dst.setValue(x, y, z); }
// Doc in parent void SoVRMLCylinder::computeBBox(SoAction * COIN_UNUSED_ARG(action), SbBox3f & box, SbVec3f & center) { float r = this->radius.getValue(); float h = this->height.getValue(); // Allow negative values. if (r < 0.0f) r = -r; if (h < 0.0f) h = -h; // Either the SIDES are present, or we've at least got both the TOP // and BOTTOM caps -- so just find the middle point and enclose // everything. if (this->side.getValue() || (this->bottom.getValue() && this->top.getValue())) { center.setValue(0.0f, 0.0f, 0.0f); box.setBounds(SbVec3f(-r, -h/2.0f, -r), SbVec3f(r, h/2.0f, r)); } // ..not a "full" cylinder, but we've got the BOTTOM cap. else if (this->bottom.getValue()) { center.setValue(0.0f, -h/2.0f, 0.0f); box.setBounds(SbVec3f(-r, -h/2.0f, -r), SbVec3f(r, -h/2.0f, r)); } // ..not a "full" cylinder, but we've got the TOP cap. else if (this->top.getValue()) { center.setValue(0.0f, h/2.0f, 0.0f); box.setBounds(SbVec3f(-r, h/2.0f, -r), SbVec3f(r, h/2.0f, r)); } // ..no parts present. My confidence is shot -- I feel very small. else { center.setValue(0.0f, 0.0f, 0.0f); box.setBounds(SbVec3f(0.0f, 0.0f, 0.0f), SbVec3f(0.0f, 0.0f, 0.0f)); } }
void SbMatrix::multVecMatrix(const SbVec3f &src, SbVec3f &dst) const { float x,y,z,w; x = src[0]*matrix[0][0] + src[1]*matrix[1][0] + src[2]*matrix[2][0] + matrix[3][0]; y = src[0]*matrix[0][1] + src[1]*matrix[1][1] + src[2]*matrix[2][1] + matrix[3][1]; z = src[0]*matrix[0][2] + src[1]*matrix[1][2] + src[2]*matrix[2][2] + matrix[3][2]; w = src[0]*matrix[0][3] + src[1]*matrix[1][3] + src[2]*matrix[2][3] + matrix[3][3]; dst.setValue(x/w, y/w, z/w); }
void SbMatrix::multMatrixVec(const SbVec3f &src, SbVec3f &dst) const { float x,y,z,w; x = matrix[0][0]*src[0] + matrix[0][1]*src[1] + matrix[0][2]*src[2] + matrix[0][3]; y = matrix[1][0]*src[0] + matrix[1][1]*src[1] + matrix[1][2]*src[2] + matrix[1][3]; z = matrix[2][0]*src[0] + matrix[2][1]*src[1] + matrix[2][2]*src[2] + matrix[2][3]; w = matrix[3][0]*src[0] + matrix[3][1]*src[1] + matrix[3][2]*src[2] + matrix[3][3]; dst.setValue(x/w, y/w, z/w); }
// Doc in parent void SoVRMLBox::computeBBox(SoAction * action, SbBox3f & COIN_UNUSED_ARG(box), SbVec3f & center) { center.setValue(0.0f, 0.0f, 0.0f); SbVec3f s = this->size.getValue(); float w = s[0] * 0.5f; float h = s[1] * 0.5f; float d = s[2] * 0.5f; // Allow negative values. if (w < 0.0f) w = -w; if (h < 0.0f) h = -h; if (d < 0.0f) d = -d; box.setBounds(-w, -h, -d, w, h, d); }
bool ObjMgrCommunicator::getObjAttributeVec3f(const string ObjID, const string LayerID, const string InfoID, SbVec3f& vec3f) { omAttribute attr; if (getObjAttribute(ObjID,LayerID,InfoID, attr)) { vector<string> VecSplit; kBasics::split(attr.getStringValue(),' ',3,&VecSplit); if (VecSplit.size()!=3) { kDebug::Debug("WrongSplitSize: " + kBasics::IntToString(VecSplit.size()),kDebug::DL_HIGH); return false; } vec3f.setValue(kBasics::StringToFloat(VecSplit[0]),kBasics::StringToFloat(VecSplit[1]),kBasics::StringToFloat(VecSplit[2])); return true; } return false; }
void SoRing::computeBBox(SoAction*, SbBox3f& box, SbVec3f& BBcenter) { float Xc, Yc; center.getValue().getValue(Xc,Yc); // centered at origin BBcenter.setValue(Xc, Yc, 0.); // bounding box float R = outerRadius.getValue(); float theta = sweepAngle.getValue()*M_PI/180.F; float Xmin, Ymin, Ymax; if ( theta < M_PI_2 ) { Ymin = 0; Ymax = R*sin(theta); Xmin = 0; } else if ( theta < M_PI ) { Ymin = 0; Ymax = R; Xmin = R*cos(theta); } else if ( theta < 3*M_PI_2 ) { Ymin = R*sin(theta); Ymax = R; Xmin = -R; } else { Xmin = -R; Ymin = -R; Ymax = R; } SbVec3f corner1(Xmin+Xc,Ymin+Yc,0); SbVec3f corner2(R+Xc,Ymax+Yc,0); box.setBounds(corner1,corner2); }
void RayTracer::trace_rays(){ int i,j; SbVec3f pix_pos, d_vec; SbVec3f tempColor; bool should_color ; double a,b,c; float color_scale; SbVec3f color; std::vector<Pixel> image_row; color.setValue(0.0,0.0,0.0); std::cout<<"Complete "; for (i=0; i < y_resolution; i++){ if (i%20 == 0) std::cout<< i << "/"<<y_resolution<<" Complete"<<std::endl; image_row.clear(); for (j=0; j < x_resolution; j++) { //bool should_color = distribute_shade(i, j, &(camera->position), &color); bool should_color = depth_of_field(i, j, &(camera->position), &color); //if() //pix_pos = calculate_pixel_location(i,j, 0.5, 0.5); //d_vec = pix_pos - camera->position; //d_vec.normalize(); //bool should_color = shade(&(camera->position), &d_vec, &color, 1); if(should_color) { image_row.push_back(Pixel(min(color[0]), min(color[1]), min(color[2]))); } else image_row.push_back(Pixel(0,0,0)); } image.push_back(image_row); } open_file(); write_to_file(image); close_file(); std::cout<<"Done Tracing"<<std::endl; return; }
// Write SbRotation to output stream. Used from SoSFRotation and // SoMFRotation. void sosfrotation_write_value(SoOutput * out, const SbRotation & r) { SbVec3f axis; float angle; r.getValue(axis, angle); // Handle invalid rotation specifications. if (axis.length() == 0.0f) { axis.setValue(0.0f, 0.0f, 1.0f); angle = 0.0f; } out->write(axis[0]); if(!out->isBinary()) out->write(' '); out->write(axis[1]); if(!out->isBinary()) out->write(' '); out->write(axis[2]); if(!out->isBinary()) out->write(" "); out->write(angle); }
bool RayTracer::depth_of_field(int i, int j, SbVec3f *position, SbVec3f *color){ //SbVec3f pix_pos, d_vec; SbVec3f tempColor; float R = DISK_SIZE; float du; float dv; bool should_color ; int number_of_jitter_positions = NUMBER_OF_CAMERAS; if(depth_of_field_on == 0) { // std::cout<<"No Depth of field"; //depth of field off //pix_pos = calculate_pixel_location(i,j, 0.5, 0.5); // d_vec = pix_pos - *position; // d_vec.normalize(); should_color = distribute_shade(i,j, position, color); } else{ for(int k =0; k< number_of_jitter_positions ; k++){ SbVec3f camera_position = *position; du = get_random_number(); dv = get_random_number(); //du = (du ) * R; //dv = (dv ) * R; //std::cout<<pixel_height<<pixel_width <<std::endl; //camera_position = camera_position + (du * R * this->u) + (dv * R * this->v); camera_position = camera_position + (du * R * pixel_width * this->u) + (dv * pixel_height * R * this->v); //pix_pos = calculate_pixel_location(i,j, 0.5, 0.5); //d_vec = pix_pos - (camera_position); //d_vec.normalize(); tempColor.setValue(0.0,0.0,0.0); should_color = distribute_shade(i, j, &camera_position,&tempColor); *color = *color + tempColor; } *color = *color/number_of_jitter_positions ; } return should_color; }
float MeshFillHole::findClosestPoint(const SbLine& ray, const TBoundary& polygon, unsigned long& vertex_index, SbVec3f& closestPoint) const { // now check which vertex of the polygon is closest to the ray float minDist = FLT_MAX; vertex_index = ULONG_MAX; const MeshCore::MeshKernel & rMesh = myMesh->Mesh.getValue().getKernel(); const MeshCore::MeshPointArray& pts = rMesh.GetPoints(); for (TBoundary::const_iterator it = polygon.begin(); it != polygon.end(); ++it) { SbVec3f vertex; const Base::Vector3f& v = pts[*it]; vertex.setValue(v.x,v.y,v.z); SbVec3f point = ray.getClosestPoint(vertex); float distance = (vertex-point).sqrLength(); if (distance < minDist) { minDist = distance; vertex_index = *it; closestPoint = vertex; } } return minDist; }
/*! Generates face normals for the faceset defined by \a coords and \a cind. */ void SoNormalCache::generatePerFace(const SbVec3f * const coords, const unsigned int numcoords, const int32_t * cind, const int nv, const SbBool ccw) { #if NORMALCACHE_DEBUG && COIN_DEBUG SoDebugError::postInfo("SoNormalCache::generatePerFace", "generating normals"); #endif this->clearGenerator(); PRIVATE(this)->indices.truncate(0); PRIVATE(this)->normalArray.truncate(0, TRUE); const int32_t * cstart = cind; const int32_t * endptr = cind + nv; SbVec3f tmpvec; int maxcoordidx = numcoords - 1; while (cind + 2 < endptr) { int v0 = cind[0]; int v1 = cind[1]; int v2 = cind[2]; if (v0 < 0 || v1 < 0 || v2 < 0 || v0 > maxcoordidx || v1 > maxcoordidx || v2 > maxcoordidx) { #if COIN_DEBUG SoDebugError::postWarning("SoNormalCache::generatePerFace", "Polygon with less than three valid " "vertices detected. (offset: %d, [%d %d %d]). " "Should be within [0, %d].", cind - cstart, v0, v1, v2, maxcoordidx); #endif // COIN_DEBUG // Insert dummy normal for robustness SbVec3f dummynormal; dummynormal.setValue(0.0f, 0.0f, 0.0f); PRIVATE(this)->normalArray.append(dummynormal); // Skip ahead to next possible index if (cind[0] < 0 || cind[0] > maxcoordidx) { cind += 1; } else if (cind[1] < 0 || cind[1] > maxcoordidx) { cind += 2; } else if (cind + 3 < endptr && (cind[2] < 0 || cind[2] > maxcoordidx)) { cind += 3; } else { cind += 3; // For robustness check after while loop break; } continue; } if (cind + 3 >= endptr || cind[3] < 0 || cind[3] > maxcoordidx) { // triangle if (!ccw) tmpvec = (coords[v0] - coords[v1]).cross(coords[v2] - coords[v1]); else tmpvec = (coords[v2] - coords[v1]).cross(coords[v0] - coords[v1]); // Be robust when it comes to erroneously specified triangles. if ((tmpvec.normalize() == 0.0f) && coin_debug_extra()) { static uint32_t normgenerrors_face = 0; if (normgenerrors_face < 1) { SoDebugError::postWarning("SoNormalCache::generatePerFace", "Erroneous triangle specification in model " "(indices= [%d, %d, %d], " "coords=<%f, %f, %f>, <%f, %f, %f>, <%f, %f, %f>) " "(this warning will be printed only once, " "but there might be more errors).", v0, v1, v2, coords[v0][0], coords[v0][1], coords[v0][2], coords[v1][0], coords[v1][1], coords[v1][2], coords[v2][0], coords[v2][1], coords[v2][2]); } normgenerrors_face++; } PRIVATE(this)->normalArray.append(tmpvec); cind += 4; // goto next triangle/polygon } else { // more than 3 vertices // use Newell's method to calculate normal vector const SbVec3f * vert1, * vert2; tmpvec.setValue(0.0f, 0.0f, 0.0f); vert2 = coords + v0; cind++; // v0 is already read // The cind < endptr check makes us robust with regard to a // missing "-1" termination of the coordIndex field of the // IndexedShape nodetype. while (cind < endptr && *cind >= 0 && *cind <= maxcoordidx) { vert1 = vert2; vert2 = coords + *cind++; tmpvec[0] += ((*vert1)[1] - (*vert2)[1]) * ((*vert1)[2] + (*vert2)[2]); tmpvec[1] += ((*vert1)[2] - (*vert2)[2]) * ((*vert1)[0] + (*vert2)[0]); tmpvec[2] += ((*vert1)[0] - (*vert2)[0]) * ((*vert1)[1] + (*vert2)[1]); } vert1 = vert2; // last edge (back to v0) vert2 = coords + v0; tmpvec[0] += ((*vert1)[1] - (*vert2)[1]) * ((*vert1)[2] + (*vert2)[2]); tmpvec[1] += ((*vert1)[2] - (*vert2)[2]) * ((*vert1)[0] + (*vert2)[0]); tmpvec[2] += ((*vert1)[0] - (*vert2)[0]) * ((*vert1)[1] + (*vert2)[1]); // Be robust when it comes to erroneously specified polygons. if ((tmpvec.normalize() == 0.0f) && coin_debug_extra()) { static uint32_t normgenerrors_face = 0; if (normgenerrors_face < 1) { SoDebugError::postWarning("SoNormalCache::generatePerFace", "Erroneous polygon specification in model. " "Unable to generate normal; using dummy normal. " "(this warning will be printed only once, " "but there might be more errors)."); } normgenerrors_face++; } PRIVATE(this)->normalArray.append(ccw ? tmpvec : -tmpvec); cind++; // skip the -1 } } if (endptr - cind > 0) { #if COIN_DEBUG SoDebugError::postWarning("SoNormalCache::generatePerFace", "Face " "specification did not end with a valid " "polygon. Too few points"); #endif // COIN_DEBUG SbVec3f dummynormal; dummynormal.setValue(0.0f, 0.0f, 0.0f); PRIVATE(this)->normalArray.append(dummynormal); } if (PRIVATE(this)->normalArray.getLength()) { PRIVATE(this)->normalData.normals = PRIVATE(this)->normalArray.getArrayPtr(); PRIVATE(this)->numNormals = PRIVATE(this)->normalArray.getLength(); } #if NORMALCACHE_DEBUG && COIN_DEBUG // debug SoDebugError::postInfo("SoNormalCache::generatePerFace", "generated normals per face: %p %d", PRIVATE(this)->normalData.normals, PRIVATE(this)->numNormals); #endif // debug }
// internal callback void InvPlaneMover::dragFinishCB(void *me, SoDragger *drag) { InvPlaneMover *mee = static_cast<InvPlaneMover *>(me); if (mee->show_) { SbVec3f t = ((SoJackDragger *)drag)->translation.getValue(); int i; for (i = 0; i < 3; ++i) t[i] *= mee->scale_->scaleFactor.getValue()[i]; SbRotation r = ((SoJackDragger *)drag)->rotation.getValue(); SbVec3f n; SbVec3f ax; float angle; r.getValue(ax, angle); SbVec3f axN; mee->fullRot_->rotation.getValue().multVec(ax, axN); r.setValue(axN, angle); r.multVec(mee->nnn_, n); // we have to rotate the translation around the x-axis // (because we have a y-axis dragger) SbVec3f tt; n.normalize(); // snap normal to the closest coordinate axis // here done by snaping it to the axis with the biggest projection onto it. if (mee->motionMode_ == InvPlaneMover::SNAP) { int axis; float mmax; int dir = 1; SbVec3f nn; if (n[0] * n[0] < n[1] * n[1]) { axis = 1; mmax = n[1]; if (n[1] < 0) dir = -1; else dir = +1; //dir = (int) copysign(1,n[1]); } else { axis = 0; mmax = n[0]; if (n[0] < 0) dir = -1; else dir = +1; //dir = (int) copysign(1,n[0]); } if (mmax * mmax < n[2] * n[2]) { axis = 2; if (n[2] < 0) dir = -1; else dir = +1; //dir = (int) copysign(1,n[2]); } switch (axis) { case 0: nn.setValue(1, 0, 0); break; case 1: nn.setValue(0, 1, 0); break; case 2: nn.setValue(0, 0, 1); break; } n = dir * nn; } tt = t[1] * n; float d; d = n.dot(tt + mee->distOffset_); float data[4]; data[0] = n[0]; data[1] = n[1]; data[2] = n[2]; data[3] = d; // send feedback message to contoller ((InvPlaneMover *)me)->sendFeedback(data); } }
int QilexDoc::doc_insert_geometric_object(QDomElement geom_element) { int error = 0; const char * buffer; SbVec3f joinax; SoTransform *pos_rot = new SoTransform; float joinangle; float pos_x, pos_y, pos_z, pos_rx, pos_ry, pos_rz; QString data, name; QDomNode node; QDomElement element; QDomNodeList list; SoSeparator *geomelement = new SoSeparator; SoSeparator *geomtest = new SoSeparator; name = geom_element.attribute ("name", QString::null); data = geom_element.attribute ("pos_x", QString::null); pos_x = data.toFloat(); data = geom_element.attribute ("pos_y", QString::null); pos_y = data.toFloat(); data = geom_element.attribute ("pos_z", QString::null); pos_z = data.toFloat(); data = geom_element.attribute ("pos_rx", QString::null); pos_rx = data.toFloat(); data = geom_element.attribute ("pos_ry", QString::null); pos_ry = data.toFloat(); data = geom_element.attribute ("pos_rz", QString::null); pos_rz = data.toFloat(); data = geom_element.attribute ("pos_angle", QString::null); joinangle = data.toFloat(); joinax.setValue(SbVec3f( pos_x, pos_y, pos_z)); pos_rot->translation.setValue(joinax); pos_rot->rotation.setValue(SbVec3f(pos_rx, pos_ry, pos_rz), (float) rad((double)joinangle)); list = geom_element.elementsByTagName ("model3d"); if (list.length() == 1) { node = list.item(0); element = node.toElement(); data = element.attribute ("format", QString::null); // some stuff to take care about the format data = element.attribute ("size", QString::null); size_t size = (size_t)data.toULong(0,10); buffer = new char[size]; data = element.text(); buffer = data.ascii(); SoInput input; input.setBuffer((void*) buffer, size); if (input.isValidBuffer()) { geomelement = SoDB::readAll(&input); if (geomelement == NULL) error = 10; } else {error = 8;} // assigno un nombre diferent de 0 } else { error =9; }// assigno un nombre diferent de 0 if (error == 0) { geomelement->ref(); geomtest = (SoSeparator*)SoNode::getByName(name.latin1()); if (geomtest==NULL) { //we need to put it in a buffer to write the xml file // if is Ok geomelement->insertChild(pos_rot, 0); geomelement->setName(name.latin1()); view->addObjectCell(geomelement); } } return error; }
int QilexDoc::doc_insert_kinematic_chain(QDomElement kine_element) { int error = 0; const char * buffer; QDomNodeList list; Rchain *kineengine = new Rchain; SoSeparator *kinechain = new SoSeparator; SoSeparator *kinetest = new SoSeparator; //Rchain *kineengine = new Rchain; SoTransform *pos_rot = new SoTransform; SbVec3f joinax; float joinangle; float pos_x, pos_y, pos_z, pos_rx, pos_ry, pos_rz; QString data, name; QDomNode node; QDomElement element; name = kine_element.attribute ("name", QString::null); data = kine_element.attribute ("kineengine", QString::null); // here put some stuff to select the kinechain engine data = kine_element.attribute ("pos_x", QString::null); pos_x = data.toFloat(); data = kine_element.attribute ("pos_y", QString::null); pos_y = data.toFloat(); data = kine_element.attribute ("pos_z", QString::null); pos_z = data.toFloat(); data = kine_element.attribute ("pos_rx", QString::null); pos_rx = data.toFloat(); data = kine_element.attribute ("pos_ry", QString::null); pos_ry = data.toFloat(); data = kine_element.attribute ("pos_rz", QString::null); pos_rz = data.toFloat(); data = kine_element.attribute ("pos_angle", QString::null); joinangle = data.toFloat(); joinax.setValue(SbVec3f( pos_x, pos_y, pos_z)); pos_rot->translation.setValue(joinax); pos_rot->rotation.setValue(SbVec3f(pos_rx, pos_ry, pos_rz), (float) rad((double)joinangle)); list = kine_element.elementsByTagName ("kinechain"); if (list.length() == 1) { node = list.item(0); element = node.toElement(); error = kineengine->read_element_xml (element); } else { error =4;} // assigno un nombre diferrent de 0 list = kine_element.elementsByTagName ("model3d"); if (list.length() == 1) { node = list.item(0); element = node.toElement(); data = element.attribute ("format", QString::null); // some stuff to take care about the format data = element.attribute ("size", QString::null); size_t size = (size_t)data.toULong(0,10); buffer = new char[size]; data = element.text(); buffer = data.ascii(); /* char *buffer2 = new char[size]; for(unsigned i=0;i<size;i++) buffer2[i] = buffer[i]; */ SoInput input; input.setBuffer((void *)buffer, size); if (input.isValidBuffer()) { kinechain = SoDB::readAll(&input); if (kinechain == NULL) error = 10; } else {error = 8;} // assigno un nombre diferent de 0 } else { error =9; }// assigno un nombre diferent de 0 if (error == 0) { kinechain->ref(); kinetest = (SoSeparator*)SoNode::getByName(name.latin1()); if (kinetest==NULL) { //we need to put it in a buffer to write the xml file // if is Ok kinechain->insertChild(pos_rot, 0); kinechain->setName(name.latin1()); error = doc_insert_kinematic_chain(kineengine, kinechain); } } else {error = 5;} return error; }
int QilexDoc::doc_new_grasping_object(ct_new_grasping_object *data) { int error = 0; int tipus = 0; void *buffer; //char *buffer; char *buftemp = (char*)malloc(1024); size_t sizeModel = 0;; SoSeparator *object = new SoSeparator; SoSeparator *objecttest = new SoSeparator; SoTransform *pos_rot = new SoTransform; SbVec3f joinax; SbVec3f joingrasp0; SbVec3f joingrasp1; SbVec3f joingrasp2; SbVec3f joingrasp3; joinax.setValue(SbVec3f(data->x,data->y,data->z)); pos_rot->translation.setValue(joinax); pos_rot->recenter(joinax); pos_rot->rotation.setValue(SbVec3f(data->axeX, data->axeY, data->axeZ), (float) rad((double) data->angle)); object = readFile(data->QsModelFile.latin1(), tipus); if (object == NULL) // no object read { error = 1 ; } else // ok, there's no object with the same name { error = read_grasp_points(data); SoMaterial *bronze = new SoMaterial; bronze->ambientColor.setValue(0.33,0.22,0.27); bronze->diffuseColor.setValue(0.78,0.57,0.11); bronze->specularColor.setValue(0.99,0.94,0.81); bronze->shininess=0.28; SoSphere *grasp_sphere = new SoSphere; grasp_sphere->radius=7.0; SoFont *font = new SoFont; font->size.setValue(28); font->name.setValue("Times-Roman"); SoSeparator *grasp_sep0 = new SoSeparator; SoTransform *grasp_transf0 = new SoTransform; SoSeparator *text0 = new SoSeparator; SoText2 *label_text0 = new SoText2; SoSeparator *grasp_sep1 = new SoSeparator; SoTransform *grasp_transf1 = new SoTransform; SoSeparator *text1 = new SoSeparator; SoText2 *label_text1 = new SoText2; SoSeparator *grasp_sep2 = new SoSeparator; SoTransform *grasp_transf2 = new SoTransform; SoSeparator *text2 = new SoSeparator; SoText2 *label_text2 = new SoText2; SoSeparator *grasp_sep3 = new SoSeparator; SoTransform *grasp_transf3 = new SoTransform; SoSeparator *text3 = new SoSeparator; SoText2 *label_text3 = new SoText2; //for (int i=0;i<data->num_point;i++) //{ joingrasp0.setValue(SbVec3f(data->grasp_points[0].px,data->grasp_points[0].py,data->grasp_points[0].pz)); grasp_transf0->translation.setValue(joingrasp0); grasp_transf0->recenter(joingrasp0); label_text0->string=" 1"; text0->addChild(font); text0->addChild(label_text0); grasp_sep0->addChild(bronze); grasp_sep0->addChild(grasp_transf0); grasp_sep0->addChild(grasp_sphere); grasp_sep0->addChild(text0); //grasp_sep0->addChild(line0); joingrasp1.setValue(SbVec3f(data->grasp_points[1].px,data->grasp_points[1].py,data->grasp_points[1].pz)); grasp_transf1->translation.setValue(joingrasp1); grasp_transf1->recenter(joingrasp1); label_text1->string=" 2"; text1->addChild(font); text1->addChild(label_text1); grasp_sep1->addChild(bronze); grasp_sep1->addChild(grasp_transf1); grasp_sep1->addChild(grasp_sphere); grasp_sep1->addChild(text1); joingrasp2.setValue(SbVec3f(data->grasp_points[2].px,data->grasp_points[2].py,data->grasp_points[2].pz)); grasp_transf2->translation.setValue(joingrasp2); grasp_transf2->recenter(joingrasp2); label_text2->string=" 3"; text2->addChild(font); text2->addChild(label_text2); grasp_sep2->addChild(bronze); grasp_sep2->addChild(grasp_transf2); grasp_sep2->addChild(grasp_sphere); grasp_sep2->addChild(text2); joingrasp3.setValue(SbVec3f(data->grasp_points[3].px,data->grasp_points[3].py,data->grasp_points[3].pz)); grasp_transf3->translation.setValue(joingrasp3); grasp_transf3->recenter(joingrasp3); label_text3->string=" 4"; text3->addChild(font); text3->addChild(label_text3); grasp_sep3->addChild(bronze); grasp_sep3->addChild(grasp_transf3); grasp_sep3->addChild(grasp_sphere); grasp_sep3->addChild(text3); //object->addChild(grasp_sep); //} if (error == 0) { object->ref(); objecttest = (SoSeparator*)SoNode::getByName(data->QsName.latin1()); if (objecttest==NULL) { SoOutput out; out.setBuffer(buftemp, 1024, reallocCB); SoWriteAction wa1(&out); wa1.apply(object); out.getBuffer(buffer, sizeModel); object->setName(data->QsName.latin1()); //grasp_object->addChild(model_object); object->addChild(grasp_sep0); object->addChild(grasp_sep1); object->addChild(grasp_sep2); object->addChild(grasp_sep3); object->insertChild(pos_rot, 0); view->addObjectCell(object); error = 0; //writeXML_geomelement((char *)buffer, sizeModel, tipus, data); //S'ha de canviar!!!!! } else { object->unref(); error = 3; } } } return error; }
int QilexDoc::doc_new_geometric_object(ct_new_geometric_object *data) { int error = 0; int tipus = 0; void *buffer; //char *buffer; char *buftemp = (char*)malloc(1024); size_t sizeModel = 0;; SoSeparator *object = new SoSeparator; SoSeparator *objecttest = new SoSeparator; SoTransform *pos_rot = new SoTransform; SbVec3f joinax; joinax.setValue(SbVec3f(data->x,data->y,data->z)); pos_rot->translation.setValue(joinax); pos_rot->recenter(joinax); pos_rot->rotation.setValue(SbVec3f(data->axeX, data->axeY, data->axeZ), (float) rad((double) data->angle)); object = readFile(data->QsModelFile.latin1(), tipus); if (object == NULL) // no object read { error = 1 ; } else // ok, there's no object with the same name { object->ref(); objecttest = (SoSeparator*)SoNode::getByName(data->QsName.latin1()); if (objecttest==NULL) { SoOutput out; out.setBuffer(buftemp, 1024, reallocCB); SoWriteAction wa1(&out); wa1.apply(object); out.getBuffer(buffer, sizeModel); object->setName(data->QsName.latin1()); object->insertChild(pos_rot, 0); view->addObjectCell(object); error = 0; writeXML_geomelement((char *)buffer, sizeModel, tipus, data); } else { object->unref(); error = 3; } } return error; }
static void generate_sphere(const float radius, const int numstacks, const int numslices, SoShape * const shape, SoAction * const action) { int stacks = numstacks; int slices = numslices; if (stacks < 3) stacks = 3; if (slices < 4) slices = 4; if (slices > 128) slices = 128; // used to cache last stack's data SbVec3f coords[129]; SbVec3f normals[129]; float S[129]; int i, j; float rho; float drho; float theta; float dtheta; float tc, ts; SbVec3f tmp; drho = float(M_PI) / (float) (stacks-1); dtheta = 2.0f * float(M_PI) / (float) slices; float currs = 0.0f; float incs = 1.0f / (float)slices; rho = drho; theta = 0.0f; tc = (float) cos(rho); ts = - (float) sin(rho); tmp.setValue(0.0f, tc, ts); normals[0] = tmp; tmp *= radius; coords[0] = tmp; S[0] = currs; float dT = 1.0f / (float) (stacks-1); float T = 1.0f - dT; SoPrimitiveVertex vertex; shape->beginShape(action, SoShape::TRIANGLES); for (j = 1; j <= slices; j++) { vertex.setNormal(SbVec3f(0.0f, 1.0f, 0.0f)); vertex.setTextureCoords(SbVec2f(currs + 0.5f * incs, 1.0f)); vertex.setPoint(SbVec3f(0.0f, radius, 0.0f)); shape->shapeVertex(&vertex); vertex.setNormal(normals[j-1]); vertex.setTextureCoords(SbVec2f(currs, T)); vertex.setPoint(coords[j-1]); shape->shapeVertex(&vertex); currs += incs; theta += dtheta; S[j] = currs; tmp.setValue(float(sin(theta))*ts, tc, float(cos(theta))*ts); normals[j] = tmp; tmp *= radius; coords[j] = tmp; vertex.setNormal(normals[j]); vertex.setTextureCoords(SbVec2f(currs, T)); vertex.setPoint(coords[j]); shape->shapeVertex(&vertex); } shape->endShape(); rho += drho; for (i = 2; i < stacks-1; i++) { tc = (float)cos(rho); ts = - (float) sin(rho); shape->beginShape(action, SoShape::QUAD_STRIP); theta = 0.0f; for (j = 0; j <= slices; j++) { vertex.setTextureCoords(SbVec2f(S[j], T)); vertex.setNormal(normals[j]); vertex.setPoint(coords[j]); shape->shapeVertex(&vertex); vertex.setTextureCoords(SbVec2f(S[j], T-dT)); tmp.setValue(float(sin(theta))*ts, tc, float(cos(theta))*ts); normals[j] = tmp; vertex.setNormal(tmp); tmp *= radius; coords[j] = tmp; theta += dtheta; vertex.setPoint(tmp); shape->shapeVertex(&vertex); } shape->endShape(); rho += drho; T -= dT; } shape->beginShape(action, SoShape::TRIANGLES); for (j = 0; j < slices; j++) { vertex.setTextureCoords(SbVec2f(S[j], T)); vertex.setNormal(normals[j]); vertex.setPoint(coords[j]); shape->shapeVertex(&vertex); vertex.setTextureCoords(SbVec2f(S[j]+incs*0.5f, 0.0f)); vertex.setNormal(SbVec3f(0.0f, -1.0f, 0.0f)); vertex.setPoint(SbVec3f(0.0f, -radius, 0.0f)); shape->shapeVertex(&vertex); vertex.setTextureCoords(SbVec2f(S[j+1], T)); vertex.setNormal(normals[j+1]); vertex.setPoint(coords[j+1]); shape->shapeVertex(&vertex); } shape->endShape(); }
/*! Generates per row normals for quad data. */ void SoNormalCache::generatePerRowQuad(const SbVec3f * const coords, const unsigned int numcoords, const int vPerRow, const int vPerColumn, const SbBool ccw) { #if NORMALCACHE_DEBUG && COIN_DEBUG SoDebugError::postInfo("SoNormalCache::generatePerRowQuad", "generating normals"); #endif this->clearGenerator(); PRIVATE(this)->normalArray.truncate(0, TRUE); SbVec3f n; #if COIN_DEBUG if (vPerRow <= 1 || vPerColumn <= 1 || static_cast<unsigned int>(vPerRow * vPerColumn) > numcoords) { SoDebugError::postWarning("SoNormalCache::generatePerRowQuad", "Illegal " "facequad dimension: [%d %d] with %d coordinates " "available. verticesPerRow and verticesPerColumn " "should be > 1, and verticesPerRow * verticesPerColumn " "<= number of coordinates available.", vPerRow, vPerColumn, numcoords); } #endif // COIN_DEBUG #define IDX(r, c) ((r)*(vPerRow)+(c)) for (int i = 0; i < vPerColumn-1; i++) { n.setValue(0.0f, 0.0f, 0.0f); for (int j = 0; j < vPerRow-1; j++) { const unsigned int idx1 = IDX(i, j); const unsigned int idx2 = IDX(i+1, j); const unsigned int idx3 = IDX(i, j+1); if (idx2 < numcoords) { // Check largest index only n += (coords[idx2] - coords[idx1]).cross(coords[idx3] - coords[idx1]); } } // Be robust when it comes to erroneously specified polygons. if ((n.normalize() == 0.0f) && coin_debug_extra()) { static uint32_t normgenerrors_rowquad = 0; if (normgenerrors_rowquad < 1) { SoDebugError::postWarning("SoNormalCache::generatePerRowQuad", "Erroneous polygon specification in model. " "Unable to generate valid normal, adding null vector. " "(this warning will be printed only once, " "but there might be more errors)."); } normgenerrors_rowquad++; } PRIVATE(this)->normalArray.append(ccw ? -n : n); } #undef IDX if (PRIVATE(this)->normalArray.getLength()) { PRIVATE(this)->normalData.normals = PRIVATE(this)->normalArray.getArrayPtr(); PRIVATE(this)->numNormals = PRIVATE(this)->normalArray.getLength(); } #if NORMALCACHE_DEBUG && COIN_DEBUG SoDebugError::postInfo("SoNormalCache::generatePerRowQuad", "generated normals per row quad: %p %d\n", PRIVATE(this)->normalData.normals, PRIVATE(this)->numNormals); #endif }
/*! Generates one normal per triangle strips (avarages all triangle normals). */ void SoNormalCache::generatePerStrip(const SbVec3f * const coords, const unsigned int numcoords, const int32_t * cind, const int nv, const SbBool ccw) { #if NORMALCACHE_DEBUG && COIN_DEBUG SoDebugError::postInfo("SoNormalCache::generatePerStrip", "generating normals"); #endif this->clearGenerator(); PRIVATE(this)->indices.truncate(0); PRIVATE(this)->normalArray.truncate(0, TRUE); const int32_t * cstart = cind; const int32_t * endptr = cind + nv; const SbVec3f * c0, * c1, * c2; SbVec3f n; SbBool flip = ccw; const int maxcoordidx = numcoords - 1; while (cind + 2 < endptr) { if (cind[0] < 0 || cind[1] < 0 || cind[2] < 0 || cind[0] > maxcoordidx || cind[1] > maxcoordidx || cind[2] > maxcoordidx) { #if COIN_DEBUG SoDebugError::postWarning("SoNormalCache::generatePerStrip", "Erroneous " "coordinate index detected (offset: %d, [%d %d %d]). Should be " "within [0, %d].", cind - cstart, *(cind), *(cind+1), *(cind+2), maxcoordidx); #endif // COIN_DEBUG // Insert dummy normal for robustness SbVec3f dummynormal; dummynormal.setValue(0.0f, 0.0f, 0.0f); PRIVATE(this)->normalArray.append(dummynormal); // Skip to next possibly valid index if (cind[0] < 0 || cind[0] > maxcoordidx) { cind += 1; } else if (cind[1] < 0 || cind[1] > maxcoordidx) { cind += 2; } else if (cind + 3 < endptr && (cind[2] < 0 || cind[2] > maxcoordidx)) { cind += 3; } else { cind += 3; // For robustness check after while loop break; } continue; } flip = ccw; c0 = &coords[*cind++]; c1 = &coords[*cind++]; c2 = &coords[*cind++]; if (!flip) n = (*c0 - *c1).cross(*c2 - *c1); else n = (*c2 - *c1).cross(*c0 - *c1); int idx = cind < endptr ? *cind++ : -1; while (idx >= 0 && idx <= maxcoordidx) { c0 = c1; c1 = c2; c2 = &coords[idx]; flip = !flip; if (!flip) n += (*c0 - *c1).cross(*c2 - *c1); else n += (*c2 - *c1).cross(*c0 - *c1); idx = cind < endptr ? *cind++ : -1; } #if COIN_DEBUG if (idx > maxcoordidx) { static uint32_t normgenerrors_strip = 0; if (normgenerrors_strip < 1) { SoDebugError::postWarning("SoNormalCache::generatePerStrip", "Erroneous polygon specification in model. " "Index out of bounds: %d. Max index: %d. " "(this warning will be printed only once, " "but there might be more errors).", idx, maxcoordidx); } normgenerrors_strip++; } #endif // COIN_DEBUG if ((n.normalize() == 0.0f) && coin_debug_extra()) { static uint32_t normgenerrors_strip = 0; if (normgenerrors_strip < 1) { SoDebugError::postWarning("SoNormalCache::generatePerStrip", "Erroneous polygon specification in model. " "Unable to generate non-zero normal. Using " "dummy normal. " "(this warning will be printed only once, " "but there might be more errors)."); } normgenerrors_strip++; } PRIVATE(this)->normalArray.append(n); } if (endptr - cind > 0) { #if COIN_DEBUG SoDebugError::postWarning("SoNormalCache::generatePerStrip", "Strip did " "not end with a valid polygon. Too few points"); #endif // COIN_DEBUG SbVec3f dummynormal; dummynormal.setValue(0.0, 0.0, 0.0); PRIVATE(this)->normalArray.append(dummynormal); } if (PRIVATE(this)->normalArray.getLength()) { PRIVATE(this)->normalData.normals = PRIVATE(this)->normalArray.getArrayPtr(); PRIVATE(this)->numNormals = PRIVATE(this)->normalArray.getLength(); } #if NORMALCACHE_DEBUG && COIN_DEBUG SoDebugError::postInfo("SoNormalCache::generatePerStrip", "generated normals per strip: %p %d\n", PRIVATE(this)->normalData.normals, PRIVATE(this)->numNormals); #endif }
void SoXipCPUMprRender::computeBBox(SoAction *action, SbBox3f &box, SbVec3f ¢er) { center.setValue(0.5, 0.5, 0.5); box.setBounds(0, 0, 0, 1, 1, 1); }
SbVec3f SbLineProjector::project(const SbVec2f &point) // //////////////////////////////////////////////////////////////////////// { // Convert two line points to world space SbLine worldLine; workingToWorld.multLineMatrix( line, worldLine ); SbVec3f wldPt1 = worldLine.getPosition(); SbVec3f wldDir = worldLine.getDirection(); SbVec3f wldPt2 = wldPt1 + wldDir; // Convert two line points to normalized screen space. SbVec3f nrmScnPt1, nrmScnPt2; viewVol.projectToScreen( wldPt1, nrmScnPt1 ); viewVol.projectToScreen( wldPt2, nrmScnPt2 ); // Convert two line points and input point // to viewPlane space, a screen space that's got view plane's aspect ratio: float vvW = (viewVol.getWidth() == 0.0) ? 1 : viewVol.getWidth(); float vvH = (viewVol.getHeight() == 0.0) ? 1 : viewVol.getHeight(); SbVec3f vpPt1( nrmScnPt1[0] * vvW, nrmScnPt1[1] * vvH, 0); SbVec3f vpPt2( nrmScnPt2[0] * vvW, nrmScnPt2[1] * vvH, 0); SbVec3f vpInPoint( point[0] * vvW, point[1] * vvH, 0); // Create the viewPlaneLine -- our line expressed in viewPlane space: SbLine viewPlaneLine( vpPt1, vpPt2 ); // In viewplane space, find the closest point on our line to the cursor. SbVec3f vpClosestPt = viewPlaneLine.getClosestPoint( vpInPoint ); vpClosestPt.setValue( vpClosestPt[0], vpClosestPt[1], 0 ); // If we've got a perspective view, we may need to clamp the point we // choose so that it's not too close to the vanishing point. // Otherwise we'll just use our vpClosestPt SbVec3f vpClampedPt = vpClosestPt; if ( viewVol.getProjectionType() == SbViewVolume::PERSPECTIVE ) { // Find the vanishing point of our line in viewPlane space: // Convert the direction of our line from world space into space // after the affine matrix (i.e. just before the projection matrix) SbMatrix vvAffine, vvProj; viewVol.getMatrices( vvAffine, vvProj ); SbVec3f postAffineDir; vvAffine.multDirMatrix( wldDir, postAffineDir ); // If the direction of the line is parallel to the view plane, // then the z component of postAffineDir is 0. // In this case, we will not need to clamp our point and moreover, // if we try we'll wind up dividing by zero pretty soon. if ( postAffineDir[2] != 0.0 ) { // If we send a line out from (0,0,0) into the viewVolume towards // postAffineDir, it will vanish at the same point as any other line // parallel to this direction. Also, all points along this line // will project to the same point on the near (or far) plane. // So a line connecting (0,0,0) and the point at postAffineDir will // intersect the near plane at the vanishing point. Transforming // any point on this line by vvProj will yield the same x,y result // and the z component will vary with depth. // So multiply the postAffineDir as a vector through the projection // matrix and use the x,y for the vanishing point. SbVec3f projVanish; vvProj.multVecMatrix( postAffineDir, projVanish ); // Convert from [-1,1] range to [0,1] range for normalized coords. SbVec3f nrmScnVanish; nrmScnVanish[0] = (1.0 + projVanish[0]) * 0.5; nrmScnVanish[1] = (1.0 + projVanish[1]) * 0.5; // Finally, get the vanishing point in viewPlane coords: SbVec3f vpVanish( nrmScnVanish[0] * vvW, nrmScnVanish[1] * vvH, 0 ); #if 0 // Check that the vanishing point is correct: // Project nrmScnVanish on the plane to see if it goes along wldDir: SbVec2f nrmScnVanish2( nrmScnVanish[0], nrmScnVanish[1] ); SbLine vanishWorldLine; viewVol.projectPointToLine( nrmScnVanish2, vanishWorldLine ); SbVec3f test = vanishWorldLine.getDirection(); fprintf(stderr,"wldDir = %f %f %f\n",wldDir[0],wldDir[1],wldDir[2]); fprintf(stderr,"checkDir = %f %f %f\n", test[0], test[1],test[2]); #endif // The points vpPt1 and vpPt2 define the line in viewPlane space. // We can't go on the other side of the vanishing point from these // defining points in screen space or the point will be undefined when // we cast it into world space. // So clamp our selected point to lie on vpPt1's side of the vanishing // point. Since points near the vanishing point will also be incredibly // far away, introduce an (arbitrary) metric, VANISH_DELTA. // Our selection must be more than VANISH_DELTA times the average of // viewVolumeHeight and viewVolumeWidth from the vanishing point. #define VANISH_DELTA .01 float vanishSafetyDist = VANISH_DELTA * .5 * (vvW + vvH); #undef VANISH_DELTA // Make pt0, the point from which we measure distances along vpLine. // It will be one extra unit away from vpVanish than safetyDist SbVec3f pt0 = viewPlaneLine.getPosition(); pt0.setValue( pt0[0], pt0[1], 0 ); SbVec3f pt0ToVanishDir = vpVanish - pt0; pt0ToVanishDir.normalize(); float pt0ToVanishDist = vanishSafetyDist + 1.0; pt0 = vpVanish - pt0ToVanishDist * pt0ToVanishDir; // Get vector and dist from pt0 to vpClosestPt SbVec3f pt0ToClosest = vpClosestPt - pt0; float pt0ToClosestDist = pt0ToClosest.length(); // If vpClosestPt is too far from pt0, clamp it: float clampDist = pt0ToVanishDist - vanishSafetyDist; if ( (pt0ToClosestDist > clampDist) && (pt0ToClosest.dot(pt0ToVanishDir) > 0.0) ) { vpClampedPt = pt0 + clampDist * pt0ToVanishDir; } } } // Convert result back into normalized screen space: SbVec2f nrmScnClampedPt( vpClampedPt[0] / vvW, vpClampedPt[1] / vvH); // Create a line in working space by projecting our point into the scene: SbVec3f result, whoCares; SbLine workingLine = getWorkingLine( nrmScnClampedPt ); // Find point on the projector line closest to workingLine if (! line.getClosestPoints(workingLine, result, whoCares)) { #ifdef DEBUG SoDebugError::post("SbLineProjector::project", "Couldn't get closest point"); #endif } return result; }
void SoPrismKit::refresh() { SoCoordinate3 *coords=(SoCoordinate3 *)(this->getPart("coords", TRUE)); SoIndexedFaceSet *faces=(SoIndexedFaceSet *)(this->getPart("faces", TRUE)); unsigned int i, k, nNumberOfVertices, nNumberOfCoordinates, nNextLimit, nNextIndex; k=0; // There must be at least three if (numFaces.getValue()<3) numFaces.setValue(3); nNumberOfVertices=numFaces.getValue(); /// Generate vertices float angleSlope, angle, halfHeight; float x, y; SbVec3f nextPoint; angleSlope=(2*3.141592654)/nNumberOfVertices; angle=0; halfHeight=height.getValue()/2.0; for (i=0;i<nNumberOfVertices;i++) { x=radius.getValue()*(sin(angle)); y=radius.getValue()*(cos(angle)); nextPoint.setValue(x,-halfHeight,y); coords->point.set1Value(i,nextPoint); nextPoint.setValue(x,halfHeight,y); coords->point.set1Value(i+nNumberOfVertices,nextPoint); angle-=angleSlope; } nNextIndex=-1; nNextLimit=-1; // Create Bottom Face if (caps.getValue()) { nNextIndex=0; nNextLimit=nNumberOfVertices; for (i=nNextIndex;i<nNextLimit;i++) faces->coordIndex.set1Value(i,i); faces->coordIndex.set1Value(nNextLimit,-1); // Create Top Face nNextIndex=nNextLimit+1; nNextLimit=nNextIndex+nNumberOfVertices; for (i=0;i<nNumberOfVertices;i++) faces->coordIndex.set1Value(i+nNextIndex,nNextLimit-i-2); faces->coordIndex.set1Value(nNextLimit,-1); } // This is the total of coordinates in 'coords' nNumberOfCoordinates=nNumberOfVertices*2; // Create the rest of the cylinder faces except for the last nNextIndex=nNextLimit+1; for (i=0;i<nNumberOfVertices-1;i++) { nNextLimit=(i*5+nNextIndex); faces->coordIndex.set1Value(nNextLimit, i); faces->coordIndex.set1Value(nNextLimit+1, i+nNumberOfVertices); faces->coordIndex.set1Value(nNextLimit+2, i+nNumberOfVertices+1); faces->coordIndex.set1Value(nNextLimit+3, i+1); faces->coordIndex.set1Value(nNextLimit+4, -1); } // Create the last of the cylinder faces i=nNumberOfVertices-1; nNextLimit=(i*5+nNextIndex); faces->coordIndex.set1Value(nNextLimit, nNumberOfVertices-1); faces->coordIndex.set1Value(nNextLimit+1, nNumberOfVertices*2-1); faces->coordIndex.set1Value(nNextLimit+2, nNumberOfVertices); faces->coordIndex.set1Value(nNextLimit+3, 0); faces->coordIndex.set1Value(nNextLimit+4, -1); }