void ElementSurface::write(STLSink &sink, Task *task) const { if (dim != 3) THROW("STL quad export not supported"); Vector3R p[3]; for (unsigned i = 0; i < count; i++) { unsigned offset = i * 9; // Compute surface normal Vector3R normal; for (unsigned j = 0; j < 3; j++) normal += Vector3R(normals[offset + j * 3 + 0], normals[offset + j * 3 + 1], normals[offset + j * 3 + 2]); normal = normal.normalize(); for (unsigned j = 0; j < 3; j++) for (unsigned k = 0; k < 3; k++) p[j][k] = vertices[offset + j * 3 + k]; sink.writeFacet(p[0], p[1], p[2], normal); if (task) task->update((double)i / count, "Writing STL surface"); } }
void SampleSlice::compute() { // Allocate space resize((steps[0] + 2) * (steps[1] + 2), -std::numeric_limits<real>::max()); // Compute offsets const Vector2R &rmin = bbox.getMin(); Vector2R scale = Vector2R(bbox.getWidth() / steps.x(), bbox.getLength() / steps.y()); Vector3R p = Vector3R(0, 0, z); // TODO Culling? // Sample //real *array = (*this)[0]; for (unsigned y = 0; y < steps.y() + 2; y++) { p.y() = rmin.y() + y * scale.y(); for (unsigned x = 0; x < steps.x() + 2; x++) { p.x() = rmin.x() + x * scale.x(); // TODO func.getSample() was removed //*array++ = func.getSample(p); } } }
void Project::updateAutomaticWorkpiece(ToolPath &path) { if (!getAutomaticWorkpiece()) return; setAutomaticWorkpiece(true); Rectangle3R wpBounds; // Guess workpiece bounds from cutting moves vector<SmartPointer<Sweep> > sweeps; vector<Rectangle3R> bboxes; for (unsigned i = 0; i < path.size(); i++) { const Move &move = path.at(i); if (move.getType() == MoveType::MOVE_RAPID) continue; int tool = move.getTool(); if (tool < 0) continue; if (sweeps.size() <= (unsigned)tool) sweeps.resize(tool + 1); if (sweeps[tool].isNull()) sweeps[tool] = tools.get(tool).getSweep(); sweeps[tool]->getBBoxes(move.getStartPt(), move.getEndPt(), bboxes, 0); } for (unsigned i = 0; i < bboxes.size(); i++) wpBounds.add(bboxes[i]); if (wpBounds == Rectangle3R()) return; // Start from z = 0 Vector3R bMin = wpBounds.getMin(); Vector3R bMax = wpBounds.getMax(); wpBounds = Rectangle3R(bMin, Vector3R(bMax.x(), bMax.y(), 0)); // At least 2mm thick if (wpBounds.getHeight() < 2) wpBounds.add(Vector3R(bMin.x(), bMin.y(), bMin.z() - 2)); if (wpBounds.isReal()) { // Margin Vector3R margin = wpBounds.getDimensions() * getWorkpieceMargin() / 100.0; wpBounds.add(wpBounds.getMin() - margin); wpBounds.add(wpBounds.getMax() + Vector3R(margin.x(), margin.y(), 0)); setWorkpieceBounds(wpBounds); } }
void ElementSurface::addElement(const Vector3R *vertices) { count++; // Add to bounds for (unsigned i = 0; i < dim; i++) bounds.add(vertices[i]); // Compute face normal Vector3R normal = (vertices[1] - vertices[0]).cross(vertices[dim - 1] - vertices[0]); real length = normal.length(); if (length == 0) return; // Degenerate element, skip normal /= length; // Normalize for (unsigned i = 0; i < dim; i++) for (unsigned j = 0; j < 3; j++) { this->vertices.push_back(vertices[i][j]); normals.push_back(normal[j]); } }
real ConicSweep::depth(const Vector3R &A, const Vector3R &B, const Vector3R &P) const { const double Ax = A.x(), Ay = A.y(), Az = A.z(); const double Bx = B.x(), By = B.y(), Bz = B.z(); const double Px = P.x(), Py = P.y(), Pz = P.z(); // Check z-height if (Pz < min(Az, Bz) || max(Az, Bz) + l < Pz) return -1; // epsilon * beta^2 + gamma * beta + rho = 0 double epsilon = sqr(Bx - Ax) + sqr(By - Ay) - sqr(Tm * (Bz - Az)); // If this is a straight up and down move of a cylindrical tool choose // a fake arbitrarily small epsilon. if (epsilon == 0 && Bz != Az && Tm == 0) epsilon = 0.000000001; const double gamma = (Ax - Px) * (Bx - Ax) + (Ay - Py) * (By - Ay) + (sqr(Tm) * (Az - Pz) - Tm * rb) * (Az - Bz); const double rho = sqr(Ax - Px) + sqr(Ay - Py) - sqr(Tm * (Az - Pz) - rb); const double sigma = sqr(gamma) - epsilon * rho; // Check if solution is valid if (epsilon == 0 || sigma < 0) return -1; double beta = (-gamma - sqrt(sigma)) / epsilon; // Quadradic equation // Check if z-heights make sense const double Qz = (Bz - Az) * beta + Az; // Check if the point is cut by the flat top or bottom if (Pz < Qz || Qz + l < Pz) { beta = Pz / (Bz - Az); // E is on AB at z-height // Compute squared distance to E on XY plane const double Ex = beta * (Bx - Ax) + Ax; const double Ey = beta * (By - Ay) + Ay; const double d2 = sqr(Ex - Px) + sqr(Ey - Py); if (Pz < Qz && rb * rb < d2) return -1; if (Qz + l < Pz && rt * rt < d2) return -1; } // Check that it's on the line segment if (beta < 0 || 1 < beta) return -1; return 1; }
RBuffer2D Sample::projectedPotential(int64_t cols, int64_t rows, Vector3R minCoords, Vector3R maxCoords, Real cutoff, const std::string& parametrization) const { RBuffer2D projPotential(cols, rows, R(0.0)); auto periodicTable = FormFactorParametrization::create(parametrization); const Real cutoffSqr = cutoff * cutoff; for (auto atom : mAtoms) { Vector3R atomPosition = atom.position(); const Element& element = periodicTable->element(atom.atomicNumber(), atom.charge()); #pragma omp parallel for for (int64_t j = 0; j < rows; ++j) { const Real fracY = static_cast<Real>(j) / static_cast<Real>(rows); const Real y = lerp(minCoords.y(), maxCoords.y(), fracY); const Real deltaYSqr = powerOf<2>(y - atomPosition.y()); if (deltaYSqr > cutoffSqr) continue; for (int64_t i = 0; i < cols; ++i) { const Real fracX = static_cast<Real>(i) / static_cast<Real>(cols); const Real x = lerp(minCoords.x(), maxCoords.x(), fracX); const Real deltaXSqr = powerOf<2>(x - atomPosition.x()); const Real rhoSqr = deltaXSqr + deltaYSqr; if (rhoSqr > cutoffSqr) continue; projPotential.pixel(i, j) += element.projectedPotential(rhoSqr); } } } return projPotential; }
/// Calculate a bound box where the faces parallel to the x-y-plane are /// quadratic Vector3R maxQuadraticBoundingBox(Real scale = 1) const { // the center of the bounding box Vector3R center = R(0.5) * (mMinBoundingBox + mMaxBoundingBox); // the diagonal of the bounding box Vector3R diagonal = mMaxBoundingBox - mMinBoundingBox; // the greatest extension of the bounding box in the x-y-plane, this will // be the edge length of the square. Real maxExtension = std::max(diagonal.x(), diagonal.y()); return Vector3R(center.x() + maxExtension * R(0.5) * scale, center.y() + maxExtension * R(0.5) * scale, mMaxBoundingBox.z()); }
void Viewer::draw(const View &view) { init(); SmartPointer<Surface> surface = view.surface; // Setup view port Rectangle3R bounds = view.path->getBounds(); if (!surface.isNull()) bounds.add(surface->getBounds()); bounds.add(view.workpiece->getBounds()); view.glDraw(bounds); // Workpiece bounds if (!view.isFlagSet(View::SHOW_WORKPIECE_FLAG) && view.isFlagSet(View::SHOW_WORKPIECE_BOUNDS_FLAG)) { glEnable(GL_DEPTH_TEST); glLineWidth(1); glColor4f(1, 1, 1, 0.5); // White BoundsView(view.workpiece->getBounds()).draw(); } // Enable Lighting view.setLighting(true); // Tool path if (view.isFlagSet(View::SHOW_PATH_FLAG)) view.path->draw(); else view.path->update(); // Model if (view.isFlagSet(View::SHOW_WORKPIECE_FLAG | View::SHOW_SURFACE_FLAG)) { const float ambient[] = {12.0 / 255, 45.0 / 255, 83.0 / 255, 1.00}; const float diffuse[] = {16.0 / 255, 59.0 / 255, 108.0 / 255, 1.00}; glDisable(GL_COLOR_MATERIAL); glMaterialfv(GL_FRONT, GL_AMBIENT, ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse); view.setWire(view.isFlagSet(View::WIRE_FLAG)); if (!surface.isNull() && view.isFlagSet(View::SHOW_SURFACE_FLAG)) surface->draw(); if (view.isFlagSet(View::SHOW_WORKPIECE_FLAG)) view.workpiece->draw(); glEnable(GL_COLOR_MATERIAL); view.setWire(false); if (view.isFlagSet(View::SHOW_NORMALS_FLAG)) { glColor4f(1.0, 1.0, 0, 0.6); surface->drawNormals(); } } // Bounding box tree // TODO revive this //if (view.isFlagSet(View::SHOW_BBTREE_FLAG)) cutWP->drawBB(); // Tool if (view.isFlagSet(View::SHOW_TOOL_FLAG) && !view.path->getPath().isNull()) { Vector3R currentPosition = view.path->getPosition(); glTranslatef(currentPosition.x(), currentPosition.y(), currentPosition.z()); ToolTable &tools = *view.path->getPath()->getTools(); const Move &move = view.path->getMove(); const Tool &tool = *tools.get(move.getTool()); double diameter = tool.getDiameter(); double radius = tool.getRadius(); double length = tool.getLength(); ToolShape shape = tool.getShape(); if (radius <= 0) { // Default tool specs radius = 25.4 / 8; shape = ToolShape::TS_CONICAL; glColor4f(1, 0, 0, 1); // Red } else glColor4f(1, 0.5, 0, 1); // Orange if (length <= 0) length = 50; switch (shape) { case ToolShape::TS_SPHEROID: { glMatrixMode(GL_MODELVIEW); glPushMatrix(); glTranslatef(0, 0, length / 2); glScaled(1, 1, length / diameter); gluSphere((GLUquadric *)toolQuad, radius, 100, 100); glPopMatrix(); break; } case ToolShape::TS_BALLNOSE: glPushMatrix(); glTranslatef(0, 0, radius); gluSphere((GLUquadric *)toolQuad, radius, 100, 100); drawCylinder((GLUquadric *)toolQuad, radius, radius, length - radius); glPopMatrix(); break; case ToolShape::TS_SNUBNOSE: drawCylinder((GLUquadric *)toolQuad, tool.getSnubDiameter() / 2, radius, length); break; case ToolShape::TS_CONICAL: drawCylinder((GLUquadric *)toolQuad, 0, radius, length); break; case ToolShape::TS_CYLINDRICAL: default: drawCylinder((GLUquadric *)toolQuad, radius, radius, length); break; } } // Disable Lighting view.setLighting(false); CHECK_GL_ERROR(""); }
void QtWin::updateWorkpieceBounds() { if (project.isNull()) return; Rectangle3R bounds = project->getWorkpieceBounds(); Vector3R bMin = bounds.getMin(); Vector3R bMax = bounds.getMax(); Vector3R bDim = bounds.getDimensions(); setUnitLabel(ui->workpieceBoundsXMinLabel, bMin.x()); setUnitLabel(ui->workpieceBoundsXMaxLabel, bMax.x()); setUnitLabel(ui->workpieceBoundsXDimLabel, bDim.x()); setUnitLabel(ui->workpieceBoundsYMinLabel, bMin.y()); setUnitLabel(ui->workpieceBoundsYMaxLabel, bMax.y()); setUnitLabel(ui->workpieceBoundsYDimLabel, bDim.y()); setUnitLabel(ui->workpieceBoundsZMinLabel, bMin.z()); setUnitLabel(ui->workpieceBoundsZMaxLabel, bMax.z()); setUnitLabel(ui->workpieceBoundsZDimLabel, bDim.z()); }
void QtWin::updateToolPathBounds() { Rectangle3R bounds = *toolPath; Vector3R bMin = bounds.getMin(); Vector3R bMax = bounds.getMax(); Vector3R bDim = bounds.getDimensions(); setUnitLabel(ui->toolPathBoundsXMinLabel, bMin.x()); setUnitLabel(ui->toolPathBoundsXMaxLabel, bMax.x()); setUnitLabel(ui->toolPathBoundsXDimLabel, bDim.x()); setUnitLabel(ui->toolPathBoundsYMinLabel, bMin.y()); setUnitLabel(ui->toolPathBoundsYMaxLabel, bMax.y()); setUnitLabel(ui->toolPathBoundsYDimLabel, bDim.y()); setUnitLabel(ui->toolPathBoundsZMinLabel, bMin.z()); setUnitLabel(ui->toolPathBoundsZMaxLabel, bMax.z()); setUnitLabel(ui->toolPathBoundsZDimLabel, bDim.z()); }
bool ConicSweep::contains(const Vector3R &start, const Vector3R &end, const Vector3R &p) const { real x1 = start.x(); real y1 = start.y(); real z1 = start.z(); real x2 = end.x(); real y2 = end.y(); real z2 = end.z(); real x = p.x(); real y = p.y(); real z = p.z(); // Z height range real minZ = z1 < z2 ? z1 : z2; real maxZ = z1 < z2 ? z2 : z1; if (z < minZ || maxZ + length < z) return false; real xLen = x2 - x1; real yLen = y2 - y1; real zLen = z2 - z1; bool horizontal = z1 == z2; bool vertical = x1 == x2 && y1 == y2; bool conical = radius1 != radius2; Vector2R q(x, y); Vector2R p1(x1, y1); Vector2R p2(x2, y2); real conicSlope = conical ? (radius1 - radius2) / length : 0; // Simple cases for horizontal and vertical moves real r2; if (conical) { if (z <= minZ) r2 = radius2; else if (maxZ + length <= z) r2 = radius1; else r2 = (z - minZ) * conicSlope + radius2; r2 *= r2; } else r2 = radius1 * radius1; if (vertical) return p1.distanceSquared(q) < r2; Vector2R c = Segment2R(p1, p2).closest(q); if (horizontal) return q.distanceSquared(c) < r2; // Slanting move // Find the ends of the line segment which passes through the move's // internal parallelogram at the z-height of p int count = 0; Vector2R s[2]; // First check the verticals if (z1 <= z && z <= z1 + length) s[count++] = p1; if (z2 <= z && z <= z2 + length) s[count++] = p2; // Check top & bottom lines of the parallelogram if (count < 2) { real delta; if (minZ + length < z) delta = (z - minZ + length) / std::fabs(z2 - z1); else delta = (z - minZ) / std::fabs(z2 - z1); if (z1 < z2) s[count++] = p1 + (p2 - p1) * delta; else s[count++] = p2 + (p1 - p2) * delta; } // Find the closest point to p on the z-line segment c = Segment2R(s[0], s[1]).closest(q); // Check cone tool height for closest point if (conical) { // NOTE Slanting move so one or both of xLen and yLen is not zero real h = 0; if (xLen) h = z - (z1 + (c.x() - x1) / xLen * zLen); else if (yLen) h = z - (z1 + (c.y() - y1) / yLen * zLen); if (h < length) { r2 = h * conicSlope + radius2; r2 *= r2; } } real cDistSq = q.distanceSquared(c); if (cDistSq < r2) return true; if (!conical) return false; // Look up and down the z-line for a closer point on the cone real maxRadius = radius1 < radius2 ? radius2 : radius1; real l2 = maxRadius * maxRadius - cDistSq; real l = sqrt(l2); // How far to look Vector2R n = (s[1] - s[0]).normalize(); // Direction vector Vector2R a = c.distanceSquared(s[1]) < l2 ? s[1] : (c + n * l); Vector2R b = c.distanceSquared(s[0]) < l2 ? s[0] : (c - n * l); real aH = 0; real bH = 0; if (xLen) { aH = z - (z1 + (a.x() - x1) / xLen * zLen); bH = z - (z1 + (b.x() - x1) / xLen * zLen); } else if (yLen) { aH = z - (z1 + (a.y() - y1) / yLen * zLen); bH = z - (z1 + (b.y() - y1) / yLen * zLen); } real h = aH < bH ? bH : aH; c = aH < bH ? b : a; r2 = h * conicSlope + radius2; r2 *= r2; return q.distanceSquared(c) < r2; }
void ViewPort::glDraw(const Rectangle3R &bbox) const { glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); // Background glBegin(GL_QUADS); glColor3ub(0x25, 0x30, 0x40); glVertex2f(-1, -1); glVertex2f(1, -1); glColor3ub(0x5, 0x5, 0x5); glVertex2f(1, 1); glVertex2f(-1, 1); glEnd(); // Compute "radius" Vector3R dims = bbox.getDimensions(); real radius = dims.x() < dims.y() ? dims.y() : dims.x(); radius = dims.z() < radius ? radius : dims.z(); // Perspective gluPerspective(45, (float)width / height, 1, 100000); // Translate glTranslatef(translation.x() * radius / zoom, translation.y() * radius / zoom, 0); // Scale gluLookAt(0, 0, radius / zoom, 0, 0, 0, 0, 1, 0); glMatrixMode(GL_MODELVIEW); // Rotate glRotated(rotation[0], rotation[1], rotation[2], rotation[3]); // Center Vector3R center = bbox.getCenter(); glTranslatef(-center.x(), -center.y(), -center.z()); // Axes if (axes) { double length = (bbox.getWidth() + bbox.getLength() + bbox.getHeight()) / 3; length *= 0.1; double radius = length / 20; setLighting(true); for (int axis = 0; axis < 3; axis++) for (int up = 0; up < 2; up++) drawAxis(axis, up, length, radius); setLighting(false); } // Bounds if (bounds) { glEnable(GL_LINE_STIPPLE); glLineStipple(1, 0x5555); glLineWidth(1); glColor4f(1, 1, 1, 0.5); // White BoundsView(bbox).draw(); glDisable(GL_LINE_STIPPLE); } }
real SpheroidSweep::depth(const Vector3R &_A, const Vector3R &_B, const Vector3R &_P) const { const double r = radius; Vector3R A = _A; Vector3R B = _B; Vector3R P = _P; if (2 * radius != length) { // TODO this is not quite right A *= scale; B *= scale; P *= scale; } // Check z-height if (P.z() < min(A.z(), B.z()) || max(A.z(), B.z()) + 2 * r < P.z()) return -1; const Vector3R AB = B - A; const Vector3R PA = A - P; // epsilon * beta^2 + gamma * beta + rho = 0 const double epsilon = AB.dot(AB); const double gamma = AB.dot(PA + Vector3R(0, 0, r)); const double rho = PA.dot(PA) + 2 * r * (A.z() - P.z()); const double sigma = sqr(gamma) - epsilon * rho; // Check if solution is valid if (epsilon == 0 || sigma < 0) return -1; double beta = (-gamma - sqrt(sigma)) / epsilon; // Quadradic equation // Check that it's on the line segment if (beta < 0 || 1 < beta) return -1; return 1; }
void MultisliceParameters::setBox(const Vector3R& minBox, const Vector3R& maxBox, Real deltaZ) { mMinBox = minBox; mMaxBox = maxBox; setSize(maxBox.x() - minBox.x(), maxBox.y() - minBox.y()); mDepth = maxBox.z() - minBox.z(); mDeltaZ = deltaZ; if (mDeltaZ <= 0) AURORA_THROW(EInvalidParameter, "deltaZ must be positive"); mMinBoxes.clear(); Real z = minBox.z(); const Real maxZ = maxBox.z(); mMinBoxes.push_back(Vector3R(minBox.x(), minBox.y(), z)); do { z += mDeltaZ; mMinBoxes.push_back(Vector3R(minBox.x(), minBox.y(), z)); } while (z < maxZ); if (verbosity >= 2) { for (size_t i = 0; i < numSlices(); ++i) { std::cout << " slice " << i << " (z1 = " << zStart(i) << ", z2 = " << zEnd(i) << ")\n"; } } if (verbosity >= 1) std::cout << "Number of Slices: " << numSlices() << std::endl; }
void CuboidView::draw() { if (bounds == Rectangle3R()) return; static float vertices[] = { 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, }; static float normals[] = { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, }; if (glGenBuffers) { if (!vertexVBuf) { glGenBuffers(1, &vertexVBuf); glBindBuffer(GL_ARRAY_BUFFER, vertexVBuf); glBufferData(GL_ARRAY_BUFFER, 24 * 3 * sizeof(float), vertices, GL_STATIC_DRAW); glGenBuffers(1, &normalVBuf); glBindBuffer(GL_ARRAY_BUFFER, normalVBuf); glBufferData(GL_ARRAY_BUFFER, 24 * 3 * sizeof(float), normals, GL_STATIC_DRAW); } glBindBuffer(GL_ARRAY_BUFFER, vertexVBuf); glVertexPointer(3, GL_FLOAT, 0, 0); glBindBuffer(GL_ARRAY_BUFFER, normalVBuf); glNormalPointer(GL_FLOAT, 0, 0); } else { glVertexPointer(3, GL_FLOAT, 0, vertices); glNormalPointer(GL_FLOAT, 0, normals); } glEnable(GL_NORMALIZE); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glPushMatrix(); Vector3R bMin = bounds.getMin(); Vector3R bDim = bounds.getDimensions(); glTranslated(bMin.x(), bMin.y(), bMin.z()); glScaled(bDim.x(), bDim.y(), bDim.z()); glDrawArrays(GL_QUADS, 0, 24); glPopMatrix(); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); }
real Workpiece::depth(const Vector3R &p) const { real d2 = p.distanceSquared(closestPointOnSurface(p)); return Rectangle3R::contains(p) ? d2 : -d2; }