void QtWin::loadWorkpiece() { if (project->getAutomaticWorkpiece()) on_automaticCuboidRadioButton_clicked(); else on_manualCuboidRadioButton_clicked(); LOCK_UI_UPDATES; ui->marginDoubleSpinBox->setValue(project->getWorkpieceMargin()); ToolUnits units = project->getUnits(); // Bounds real scale = units == ToolUnits::UNITS_MM ? 1 : 1 / 25.4; Rectangle3R bounds = project->getWorkpieceBounds(); ui->xDimDoubleSpinBox->setValue(bounds.getDimensions().x() * scale); ui->yDimDoubleSpinBox->setValue(bounds.getDimensions().y() * scale); ui->zDimDoubleSpinBox->setValue(bounds.getDimensions().z() * scale); ui->xOffsetDoubleSpinBox->setValue(bounds.getMin().x() * scale); ui->yOffsetDoubleSpinBox->setValue(bounds.getMin().y() * scale); ui->zOffsetDoubleSpinBox->setValue(bounds.getMin().z() * scale); // Update Workpiece steps real step = units == ToolUnits::UNITS_MM ? 1 : 0.125; ui->xDimDoubleSpinBox->setSingleStep(step); ui->yDimDoubleSpinBox->setSingleStep(step); ui->zDimDoubleSpinBox->setSingleStep(step); ui->xOffsetDoubleSpinBox->setSingleStep(step); ui->yOffsetDoubleSpinBox->setSingleStep(step); ui->zOffsetDoubleSpinBox->setSingleStep(step); // Update visual view->setWorkpiece(bounds); redraw(); }
void QtWin::setWorkpieceOffset(unsigned dim, real value) { real scale = project->getUnits() == ToolUnits::UNITS_MM ? 1 : 25.4; Rectangle3R bounds = project->getWorkpieceBounds(); bounds.rmax[dim] = bounds.getDimension(dim) + value * scale; bounds.rmin[dim] = value * scale; project->setWorkpieceBounds(bounds); loadWorkpiece(); redraw(true); }
void Project::updateResolution() { if (getResolutionMode() == ResolutionMode::RESOLUTION_MANUAL) return; Rectangle3R wpBounds = getWorkpieceBounds(); if (wpBounds == Rectangle3R()) return; double divisor; switch (getResolutionMode()) { case ResolutionMode::RESOLUTION_LOW: divisor = 100000; break; case ResolutionMode::RESOLUTION_HIGH: divisor = 5000000; break; case ResolutionMode::RESOLUTION_VERY_HIGH: divisor = 10000000; break; default: divisor = 250000; break; // Medium } setResolution(pow(wpBounds.getVolume() / divisor, 1.0 / 3.0)); }
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()); }
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()); }
double Project::computeResolution(ResolutionMode mode, Rectangle3R bounds) { if (mode == ResolutionMode::RESOLUTION_MANUAL || bounds == Rectangle3R()) return 1; double divisor; switch (mode) { case ResolutionMode::RESOLUTION_LOW: divisor = 100000; break; case ResolutionMode::RESOLUTION_HIGH: divisor = 5000000; break; case ResolutionMode::RESOLUTION_VERY_HIGH: divisor = 10000000; break; default: divisor = 250000; break; // Medium } return pow(bounds.getVolume() / divisor, 1.0 / 3.0); }
static void boxSplit(vector<Rectangle3R> &boxes, Rectangle3R box, unsigned count) { if (count < 2) { boxes.push_back(box); return; } Rectangle3R left(box); Rectangle3R right(box); // Split on largest dimension (reduces overlap) if (box.getLength() <= box.getWidth() && box.getHeight() <= box.getWidth()) right.rmin.x() = left.rmax.x() = (box.rmin.x() + box.rmax.x()) / 2; else if (box.getWidth() <= box.getLength() && box.getHeight() <= box.getLength()) right.rmin.y() = left.rmax.y() = (box.rmin.y() + box.rmax.y()) / 2; else right.rmin.z() = left.rmax.z() = (box.rmin.z() + box.rmax.z()) / 2; boxSplit(boxes, left, count - 2); boxSplit(boxes, right, count - 2); }
Rectangle3R CompositeSurface::getBounds() const { Rectangle3R bounds; for (unsigned i = 0; i < surfaces.size(); i++) bounds.add(surfaces[i]->getBounds()); return bounds; }
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 Project::setWorkpieceBounds(const Rectangle3R &bounds) { options["workpiece-min"].set(bounds.getMin().toString()); options["workpiece-max"].set(bounds.getMax().toString()); updateResolution(); if (!getAutomaticWorkpiece()) markDirty(); }
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) { unsigned tool = move.getTool(); if (sweeps.size() <= 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 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); } }
cb::SmartPointer<Surface> Renderer::render(CutWorkpiece &cutWorkpiece, unsigned threads, double resolution, RenderMode mode) { // Setup task->begin(); cutWorkpiece.clearSampleCount(); cutWorkpiece.getToolSweep()->clearHitTests(); // Increase bounds a little Rectangle3R bbox = cutWorkpiece.getBounds(); real off = 2 * resolution - 0.00001; bbox = bbox.grow(Vector3R(off, off, off)); // Divide work vector<Rectangle3R> jobBoxes; boxSplit(jobBoxes, bbox, threads); unsigned totalJobCount = jobBoxes.size(); LOG_INFO(1, "Computing surface bounded by " << bbox << " at " << resolution << " grid resolution in " << jobBoxes.size() << " boxes"); // Run jobs SmartPointer<CompositeSurface> surface = new CompositeSurface; typedef list<SmartPointer<RenderJob> > jobs_t; jobs_t jobs; while (!task->shouldQuit() && !(jobBoxes.empty() && jobs.empty())) { // Start new jobs while (!jobBoxes.empty() && jobs.size() < threads) { Rectangle3R jobBox = jobBoxes.back(); jobBoxes.pop_back(); SmartPointer<RenderJob> job = new RenderJob(cutWorkpiece, mode, resolution, jobBox); job->start(); jobs.push_back(job); } // Reap completed jobs jobs_t::iterator it; for (it = jobs.begin(); it != jobs.end() && !task->shouldQuit();) if ((*it)->getState() == Thread::THREAD_DONE) { (*it)->join(); surface->add((*it)->getSurface()); it = jobs.erase(it); } else it++; // Update Progress double progress = 0; // Add running jobs for (it = jobs.begin(); it != jobs.end() && !task->shouldQuit(); it++) progress += (*it)->getProgress(); // Add completed jobs progress += totalJobCount - jobBoxes.size() - jobs.size(); progress /= totalJobCount; task->update(progress, "Rendering surface"); // Sleep Timer::sleep(0.1); } // Clean up remaining jobs in case of an early exit for (jobs_t::iterator it = jobs.begin(); it != jobs.end(); it++) (*it)->join(); if (shouldQuit()) { task->end(); LOG_INFO(1, "Render aborted"); return 0; } // Done double delta = task->end(); LOG_INFO(1, "Time: " << TimeInterval(delta) << " Triangles: " << surface->getCount() << " Triangles/sec: " << String::printf("%0.2f", surface->getCount() / delta) << " Resolution: " << resolution); return surface; }
Workpiece::Workpiece(const Rectangle3R &r) : Rectangle3R(r), center(r.getCenter()) { Vector3R halfDim = r.getDimensions() / 2; halfDim2 = halfDim * halfDim; }