New Cam simulator based on low level OpenGL functions (faster and more precise) (#13884)
* Initial opengl test window * added core files * some fixes for code comparability with other platforms * more compatibility cleanup * add missing opengl libraries * Basic simulation window works! * try using different define * fix wrapper for better compatibility * Gui is now operational * Finally SIM works on actual freecad models * support drill commands * cleanup python script and add tool profile generation * Now using actual tools specified in the operation. * support mouse wheel and freecad-style 3d navigation * Support accuracy gauge * remove endsimulation reference * show simulation speed indicator * apply clang-format * apply changes suggested by code review * gui items are loaded via QT resource system instead of hard coded * use vector instead of pointer to pass tool profile points * Fix some more formatting errors.
@@ -96,6 +96,7 @@ SET(PathPythonMainGui_SRCS
|
||||
Path/Main/Gui/PreferencesJob.py
|
||||
Path/Main/Gui/SanityCmd.py
|
||||
Path/Main/Gui/Simulator.py
|
||||
Path/Main/Gui/SimulatorGL.py
|
||||
)
|
||||
|
||||
SET(PathPythonMainSanity_SRCS
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
<file>icons/CAM_Shape.svg</file>
|
||||
<file>icons/CAM_SimpleCopy.svg</file>
|
||||
<file>icons/CAM_Simulator.svg</file>
|
||||
<file>icons/CAM_SimulatorGL.svg</file>
|
||||
<file>icons/CAM_Slot.svg</file>
|
||||
<file>icons/CAM_Stop.svg</file>
|
||||
<file>icons/CAM_ThreadMilling.svg</file>
|
||||
@@ -121,7 +122,19 @@
|
||||
<file>panels/ToolBitSelector.ui</file>
|
||||
<file>panels/TaskPathCamoticsSim.ui</file>
|
||||
<file>panels/TaskPathSimulator.ui</file>
|
||||
<file>panels/TaskCAMSimulator.ui</file>
|
||||
<file>panels/ZCorrectEdit.ui</file>
|
||||
<file>gl_simulator/0.png</file>
|
||||
<file>gl_simulator/1.png</file>
|
||||
<file>gl_simulator/4.png</file>
|
||||
<file>gl_simulator/X.png</file>
|
||||
<file>gl_simulator/Faster.png</file>
|
||||
<file>gl_simulator/Pause.png</file>
|
||||
<file>gl_simulator/Play.png</file>
|
||||
<file>gl_simulator/Rotate.png</file>
|
||||
<file>gl_simulator/SingleStep.png</file>
|
||||
<file>gl_simulator/Slider.png</file>
|
||||
<file>gl_simulator/Thumb.png</file>
|
||||
<file>preferences/Advanced.ui</file>
|
||||
<file>preferences/PathDressupHoldingTags.ui</file>
|
||||
<file>preferences/PathJob.ui</file>
|
||||
|
||||
BIN
src/Mod/CAM/Gui/Resources/gl_simulator/0.png
Normal file
|
After Width: | Height: | Size: 952 B |
BIN
src/Mod/CAM/Gui/Resources/gl_simulator/1.png
Normal file
|
After Width: | Height: | Size: 456 B |
BIN
src/Mod/CAM/Gui/Resources/gl_simulator/4.png
Normal file
|
After Width: | Height: | Size: 826 B |
BIN
src/Mod/CAM/Gui/Resources/gl_simulator/Faster.png
Normal file
|
After Width: | Height: | Size: 980 B |
BIN
src/Mod/CAM/Gui/Resources/gl_simulator/Pause.png
Normal file
|
After Width: | Height: | Size: 359 B |
BIN
src/Mod/CAM/Gui/Resources/gl_simulator/Play.png
Normal file
|
After Width: | Height: | Size: 697 B |
BIN
src/Mod/CAM/Gui/Resources/gl_simulator/Rotate.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
src/Mod/CAM/Gui/Resources/gl_simulator/SingleStep.png
Normal file
|
After Width: | Height: | Size: 796 B |
BIN
src/Mod/CAM/Gui/Resources/gl_simulator/Slider.png
Normal file
|
After Width: | Height: | Size: 263 B |
BIN
src/Mod/CAM/Gui/Resources/gl_simulator/Thumb.png
Normal file
|
After Width: | Height: | Size: 573 B |
BIN
src/Mod/CAM/Gui/Resources/gl_simulator/X.png
Normal file
|
After Width: | Height: | Size: 874 B |
928
src/Mod/CAM/Gui/Resources/icons/CAM_SimulatorGL.svg
Normal file
|
After Width: | Height: | Size: 32 KiB |
154
src/Mod/CAM/Gui/Resources/panels/TaskCAMSimulator.ui
Normal file
@@ -0,0 +1,154 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TaskPathSimulator</class>
|
||||
<widget class="QDialog" name="TaskPathSimulator">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>288</width>
|
||||
<height>335</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Path Simulator</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progressBar">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>5</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="textVisible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Accuracy:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="sliderAccuracy">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="labelAccuracy">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">%</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Job:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="comboJobs"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="toolButtonPlay">
|
||||
<property name="toolTip">
|
||||
<string>Activate / resume simulation</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Play</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../Path.qrc">
|
||||
<normaloff>:/icons/CAM_BPlay.svg</normaloff>:/icons/CAM_BPlay.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listOperations">
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::NoSelection</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../Path.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
<slots>
|
||||
<slot>SimStop()</slot>
|
||||
<slot>SimPlay()</slot>
|
||||
<slot>SimPause()</slot>
|
||||
<slot>SimStep()</slot>
|
||||
<slot>SimFF()</slot>
|
||||
</slots>
|
||||
</ui>
|
||||
@@ -97,6 +97,7 @@ class CAMWorkbench(Workbench):
|
||||
toolcmdlist = [
|
||||
"CAM_Inspect",
|
||||
"CAM_Simulator",
|
||||
"CAM_SimulatorGL",
|
||||
"CAM_SelectLoop",
|
||||
"CAM_OpActiveToggle",
|
||||
]
|
||||
|
||||
@@ -53,6 +53,7 @@ def Startup():
|
||||
from Path.Main.Gui import Fixture
|
||||
from Path.Main.Gui import Inspect
|
||||
from Path.Main.Gui import Simulator
|
||||
from Path.Main.Gui import SimulatorGL
|
||||
|
||||
from Path.Main.Sanity import Sanity
|
||||
|
||||
|
||||
309
src/Mod/CAM/Path/Main/Gui/SimulatorGL.py
Normal file
@@ -0,0 +1,309 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2017 Shai Seger <shaise at gmail> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
import FreeCAD
|
||||
import Path
|
||||
import Path.Base.Util as PathUtil
|
||||
import Path.Dressup.Utils as PathDressup
|
||||
import PathScripts.PathUtils as PathUtils
|
||||
import Path.Main.Job as PathJob
|
||||
import PathGui
|
||||
import CAMSimulator
|
||||
import math
|
||||
import os
|
||||
|
||||
from FreeCAD import Vector, Base
|
||||
from PySide2.QtWidgets import QDialogButtonBox
|
||||
|
||||
# lazily loaded modules
|
||||
from lazy_loader.lazy_loader import LazyLoader
|
||||
|
||||
Mesh = LazyLoader("Mesh", globals(), "Mesh")
|
||||
Part = LazyLoader("Part", globals(), "Part")
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from PySide import QtGui, QtCore
|
||||
|
||||
_filePath = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
def IsSame(x, y):
|
||||
return abs(x - y) < 0.0001
|
||||
|
||||
def RadiusAt(edge, p):
|
||||
x = edge.valueAt(p).x
|
||||
y = edge.valueAt(p).y
|
||||
return math.sqrt(x * x + y * y)
|
||||
|
||||
|
||||
class CAMSimTaskUi:
|
||||
def __init__(self, parent):
|
||||
# this will create a Qt widget from our ui file
|
||||
self.form = FreeCADGui.PySideUic.loadUi(":/panels/TaskCAMSimulator.ui")
|
||||
self.parent = parent
|
||||
|
||||
def getStandardButtons(self, *args):
|
||||
return QDialogButtonBox.Close
|
||||
|
||||
def reject(self):
|
||||
self.parent.cancel()
|
||||
FreeCADGui.Control.closeDialog()
|
||||
|
||||
|
||||
def TSError(msg):
|
||||
QtGui.QMessageBox.information(None, "Path Simulation", msg)
|
||||
|
||||
|
||||
class CAMSimulation:
|
||||
def __init__(self):
|
||||
self.debug = False
|
||||
self.stdrot = FreeCAD.Rotation(Vector(0, 0, 1), 0)
|
||||
self.iprogress = 0
|
||||
self.numCommands = 0
|
||||
self.simperiod = 20
|
||||
self.quality = 10
|
||||
self.resetSimulation = False
|
||||
self.jobs = []
|
||||
|
||||
def Connect(self, but, sig):
|
||||
QtCore.QObject.connect(but, QtCore.SIGNAL("clicked()"), sig)
|
||||
|
||||
## Convert tool shape to tool profile needed by GL simulator
|
||||
def FindClosestEdge(self, edges, px, pz):
|
||||
for edge in edges:
|
||||
p1 = edge.FirstParameter
|
||||
p2 = edge.LastParameter
|
||||
rad = RadiusAt(edge, p1)
|
||||
z = edge.valueAt(p1).z
|
||||
if IsSame(px, rad) and IsSame(pz, z):
|
||||
return edge, p1, p2
|
||||
rad = RadiusAt(edge, p2)
|
||||
z = edge.valueAt(p2).z
|
||||
if IsSame(px, rad) and IsSame(pz, z):
|
||||
return edge, p2, p1
|
||||
return None, 0.0, 0.0
|
||||
|
||||
def FindTopMostEdge(self, edges):
|
||||
maxz = 0.0
|
||||
topedge = None
|
||||
top_p1 = 0.0
|
||||
top_p2 = 0.0
|
||||
for edge in edges:
|
||||
p1 = edge.FirstParameter
|
||||
p2 = edge.LastParameter
|
||||
z = edge.valueAt(p1).z
|
||||
if z > maxz:
|
||||
topedge = edge
|
||||
top_p1 = p1
|
||||
top_p2 = p2
|
||||
maxz = z
|
||||
z = edge.valueAt(p2).z
|
||||
if z > maxz:
|
||||
topedge = edge
|
||||
top_p1 = p2
|
||||
top_p2 = p1
|
||||
maxz = z
|
||||
return topedge, top_p1, top_p2
|
||||
|
||||
#the algo is based on locating the side edge that OCC creates on any revolved object
|
||||
def GetToolProfile(self, tool, resolution):
|
||||
shape = tool.Shape
|
||||
sideEdgeList = []
|
||||
for i in range(len(shape.Edges)):
|
||||
edge = shape.Edges[i]
|
||||
if not edge.isClosed():
|
||||
v1 = edge.firstVertex()
|
||||
v2 = edge.lastVertex()
|
||||
tp = "arc" if type(edge.Curve) is Part.Circle else "line"
|
||||
sideEdgeList.append(edge)
|
||||
|
||||
# sort edges as a single 3d line on the x-z plane
|
||||
profile = [0.0, 0.0]
|
||||
|
||||
# first find the topmost edge
|
||||
edge, p1, p2 = self.FindTopMostEdge(sideEdgeList)
|
||||
profile = [RadiusAt(edge, p1), edge.valueAt(p1).z]
|
||||
endrad = 0.0
|
||||
# one by one find all connecting edges
|
||||
while edge is not None:
|
||||
sideEdgeList.remove(edge)
|
||||
if type(edge.Curve) is Part.Circle:
|
||||
# if edge is curved, aproximate it with lines based on resolution
|
||||
nsegments = int(edge.Length / resolution) + 1
|
||||
step = (p2 - p1) / nsegments
|
||||
location = p1 + step
|
||||
print (edge.Length, nsegments, step)
|
||||
while nsegments > 0:
|
||||
endrad = RadiusAt(edge, location)
|
||||
endz = edge.valueAt(location).z
|
||||
profile.append(endrad)
|
||||
profile.append(endz)
|
||||
location += step
|
||||
nsegments -= 1
|
||||
else:
|
||||
endrad = RadiusAt(edge, p2)
|
||||
endz = edge.valueAt(p2).z
|
||||
profile.append(endrad)
|
||||
profile.append(endz)
|
||||
edge, p1, p2 = self.FindClosestEdge(sideEdgeList, endrad, endz)
|
||||
if edge is None:
|
||||
break
|
||||
return profile
|
||||
|
||||
def Activate(self):
|
||||
self.initdone = False
|
||||
self.taskForm = CAMSimTaskUi(self)
|
||||
form = self.taskForm.form
|
||||
self.Connect(form.toolButtonPlay, self.SimPlay)
|
||||
form.sliderAccuracy.valueChanged.connect(self.onAccuracyBarChange)
|
||||
self.onAccuracyBarChange()
|
||||
self._populateJobSelection(form)
|
||||
form.comboJobs.currentIndexChanged.connect(self.onJobChange)
|
||||
self.onJobChange()
|
||||
FreeCADGui.Control.showDialog(self.taskForm)
|
||||
self.disableAnim = False
|
||||
self.firstDrill = True
|
||||
self.millSim = CAMSimulator.PathSim()
|
||||
self.initdone = True
|
||||
self.job = self.jobs[self.taskForm.form.comboJobs.currentIndex()]
|
||||
self.SetupSimulation()
|
||||
|
||||
def _populateJobSelection(self, form):
|
||||
# Make Job selection combobox
|
||||
setJobIdx = 0
|
||||
jobName = ""
|
||||
jIdx = 0
|
||||
# Get list of Job objects in active document
|
||||
jobList = FreeCAD.ActiveDocument.findObjects("Path::FeaturePython", "Job.*")
|
||||
jCnt = len(jobList)
|
||||
|
||||
# Check if user has selected a specific job for simulation
|
||||
guiSelection = FreeCADGui.Selection.getSelectionEx()
|
||||
if guiSelection: # Identify job selected by user
|
||||
sel = guiSelection[0]
|
||||
if hasattr(sel.Object, "Proxy") and isinstance(
|
||||
sel.Object.Proxy, PathJob.ObjectJob
|
||||
):
|
||||
jobName = sel.Object.Name
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
|
||||
# populate the job selection combobox
|
||||
form.comboJobs.blockSignals(True)
|
||||
form.comboJobs.clear()
|
||||
form.comboJobs.blockSignals(False)
|
||||
for j in jobList:
|
||||
form.comboJobs.addItem(j.ViewObject.Icon, j.Label)
|
||||
self.jobs.append(j)
|
||||
if j.Name == jobName or jCnt == 1:
|
||||
setJobIdx = jIdx
|
||||
jIdx += 1
|
||||
|
||||
# Pre-select GUI-selected job in the combobox
|
||||
if jobName or jCnt == 1:
|
||||
form.comboJobs.setCurrentIndex(setJobIdx)
|
||||
else:
|
||||
form.comboJobs.setCurrentIndex(0)
|
||||
|
||||
def SetupSimulation(self):
|
||||
form = self.taskForm.form
|
||||
self.activeOps = []
|
||||
self.numCommands = 0
|
||||
self.ioperation = 0
|
||||
for i in range(form.listOperations.count()):
|
||||
if form.listOperations.item(i).checkState() == QtCore.Qt.CheckState.Checked:
|
||||
self.firstDrill = True
|
||||
self.activeOps.append(self.operations[i])
|
||||
self.numCommands += len(self.operations[i].Path.Commands)
|
||||
|
||||
self.stock = self.job.Stock.Shape
|
||||
self.busy = False
|
||||
|
||||
def onJobChange(self):
|
||||
form = self.taskForm.form
|
||||
j = self.jobs[form.comboJobs.currentIndex()]
|
||||
self.job = j
|
||||
form.listOperations.clear()
|
||||
self.operations = []
|
||||
for op in j.Operations.OutList:
|
||||
if PathUtil.opProperty(op, "Active"):
|
||||
listItem = QtGui.QListWidgetItem(op.ViewObject.Icon, op.Label)
|
||||
listItem.setFlags(listItem.flags() | QtCore.Qt.ItemIsUserCheckable)
|
||||
listItem.setCheckState(QtCore.Qt.CheckState.Checked)
|
||||
self.operations.append(op)
|
||||
form.listOperations.addItem(listItem)
|
||||
if self.initdone:
|
||||
self.SetupSimulation()
|
||||
|
||||
def onAccuracyBarChange(self):
|
||||
form = self.taskForm.form
|
||||
self.quality = form.sliderAccuracy.value()
|
||||
qualText = QtCore.QT_TRANSLATE_NOOP("CAM_Simulator", "High")
|
||||
if (self.quality < 4):
|
||||
qualText = QtCore.QT_TRANSLATE_NOOP("CAM_Simulator", "Low")
|
||||
elif (self.quality < 9):
|
||||
qualText = QtCore.QT_TRANSLATE_NOOP("CAM_Simulator", "Medium")
|
||||
form.labelAccuracy.setText(qualText)
|
||||
|
||||
def SimPlay(self):
|
||||
self.millSim.ResetSimulation()
|
||||
for op in self.activeOps:
|
||||
tool = PathDressup.toolController(op).Tool
|
||||
toolNumber = PathDressup.toolController(op).ToolNumber
|
||||
toolProfile = self.GetToolProfile(tool, 0.5)
|
||||
self.millSim.AddTool(toolProfile, toolNumber, tool.Diameter, 1)
|
||||
opCommands = PathUtils.getPathWithPlacement(op).Commands
|
||||
for cmd in opCommands:
|
||||
self.millSim.AddCommand(cmd)
|
||||
self.millSim.BeginSimulation(self.stock, self.quality)
|
||||
|
||||
def cancel(self):
|
||||
#self.EndSimulation()
|
||||
pass
|
||||
|
||||
|
||||
class CommandCAMSimulate:
|
||||
def GetResources(self):
|
||||
return {
|
||||
"Pixmap": "CAM_SimulatorGL",
|
||||
"MenuText": QtCore.QT_TRANSLATE_NOOP("CAM_Simulator", "New CAM Simulator"),
|
||||
"Accel": "P, N",
|
||||
"ToolTip": QtCore.QT_TRANSLATE_NOOP(
|
||||
"CAM_Simulator", "Simulate G-code on stock"
|
||||
),
|
||||
}
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument is not None:
|
||||
for o in FreeCAD.ActiveDocument.Objects:
|
||||
if o.Name[:3] == "Job":
|
||||
return True
|
||||
return False
|
||||
|
||||
def Activated(self):
|
||||
CamSimulation = CAMSimulation()
|
||||
CamSimulation.Activate()
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
# register the FreeCAD command
|
||||
FreeCADGui.addCommand("CAM_SimulatorGL", CommandCAMSimulate())
|
||||
FreeCAD.Console.PrintLog("Loading PathSimulator Gui... done\n")
|
||||
@@ -47,9 +47,18 @@
|
||||
// PathSimulator
|
||||
#ifndef PathSimulatorExport
|
||||
#ifdef PathSimulator_EXPORTS
|
||||
# define PathSimulatorExport FREECAD_DECL_EXPORT
|
||||
#define PathSimulatorExport FREECAD_DECL_EXPORT
|
||||
#else
|
||||
# define PathSimulatorExport FREECAD_DECL_IMPORT
|
||||
#define PathSimulatorExport FREECAD_DECL_IMPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// CAMSimulator (new GL simulator)
|
||||
#ifndef CAMSimulatorExport
|
||||
#ifdef CAMSimulator_EXPORTS
|
||||
#define CAMSimulatorExport FREECAD_DECL_EXPORT
|
||||
#else
|
||||
#define CAMSimulatorExport FREECAD_DECL_IMPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
85
src/Mod/CAM/PathSimulator/AppGL/AppCAMSimulator.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2017 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include <Base/Console.h>
|
||||
#include <Base/Interpreter.h>
|
||||
|
||||
#include "CAMSim.h"
|
||||
#include "CAMSimPy.h"
|
||||
|
||||
|
||||
namespace CAMSimulator
|
||||
{
|
||||
class Module: public Py::ExtensionModule<Module>
|
||||
{
|
||||
public:
|
||||
Module()
|
||||
: Py::ExtensionModule<Module>("CAMSimulator")
|
||||
{
|
||||
initialize("This module is the CAMSimulator module."); // register with Python
|
||||
}
|
||||
|
||||
~Module() override
|
||||
{}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
PyObject* initModule()
|
||||
{
|
||||
return Base::Interpreter().addModule(new Module);
|
||||
}
|
||||
|
||||
|
||||
} // namespace CAMSimulator
|
||||
|
||||
|
||||
/* Python entry */
|
||||
PyMOD_INIT_FUNC(CAMSimulator)
|
||||
{
|
||||
// load dependent module
|
||||
try {
|
||||
Base::Interpreter().runString("import Part");
|
||||
Base::Interpreter().runString("import Path");
|
||||
Base::Interpreter().runString("import Mesh");
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
PyErr_SetString(PyExc_ImportError, e.what());
|
||||
PyMOD_Return(nullptr);
|
||||
}
|
||||
|
||||
//
|
||||
PyObject* mod = CAMSimulator::initModule();
|
||||
Base::Console().Log("Loading CAMSimulator module.... done\n");
|
||||
|
||||
// Add Types to module
|
||||
Base::Interpreter().addType(&CAMSimulator::CAMSimPy::Type, mod, "PathSim");
|
||||
|
||||
// NOTE: To finish the initialization of our own type objects we must
|
||||
// call PyType_Ready, otherwise we run into a segmentation fault, later on.
|
||||
// This function is responsible for adding inherited slots from a type's base class.
|
||||
CAMSimulator::CAMSim::init();
|
||||
|
||||
PyMOD_Return(mod);
|
||||
}
|
||||
72
src/Mod/CAM/PathSimulator/AppGL/CAMSim.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2017 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#include "CAMSim.h"
|
||||
#include "DlgCAMSimulator.h"
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
using namespace Base;
|
||||
using namespace CAMSimulator;
|
||||
|
||||
TYPESYSTEM_SOURCE(CAMSimulator::CAMSim, Base::BaseClass);
|
||||
|
||||
#define MAX_GCODE_LINE_LEN 120
|
||||
|
||||
CAMSim::CAMSim()
|
||||
{}
|
||||
|
||||
CAMSim::~CAMSim()
|
||||
{}
|
||||
|
||||
void CAMSim::BeginSimulation(Part::TopoShape* stock, float quality)
|
||||
{
|
||||
Base::BoundBox3d bbox = stock->getBoundBox();
|
||||
SimStock stk = {(float)bbox.MinX,
|
||||
(float)bbox.MinY,
|
||||
(float)bbox.MinZ,
|
||||
(float)bbox.LengthX(),
|
||||
(float)bbox.LengthY(),
|
||||
(float)bbox.LengthZ(),
|
||||
quality};
|
||||
DlgCAMSimulator::GetInstance()->startSimulation(&stk, quality);
|
||||
}
|
||||
|
||||
void CAMSimulator::CAMSim::resetSimulation()
|
||||
{
|
||||
DlgCAMSimulator::GetInstance()->resetSimulation();
|
||||
}
|
||||
|
||||
void CAMSim::addTool(const std::vector<float> toolProfilePoints,
|
||||
int toolNumber,
|
||||
float diameter,
|
||||
float resolution)
|
||||
{
|
||||
DlgCAMSimulator::GetInstance()->addTool(toolProfilePoints, toolNumber, diameter, resolution);
|
||||
}
|
||||
|
||||
void CAMSim::AddCommand(Command* cmd)
|
||||
{
|
||||
std::string gline = cmd->toGCode();
|
||||
DlgCAMSimulator::GetInstance()->addGcodeCommand(gline.c_str());
|
||||
}
|
||||
77
src/Mod/CAM/PathSimulator/AppGL/CAMSim.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2017 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef CAMSimulator_CAMSim_H
|
||||
#define CAMSimulator_CAMSim_H
|
||||
|
||||
#include <memory>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
|
||||
#include <Mod/CAM/App/Command.h>
|
||||
#include <Mod/Part/App/TopoShape.h>
|
||||
#include <Mod/CAM/PathGlobal.h>
|
||||
#include <Mod/Mesh/App/Mesh.h>
|
||||
#include <Mod/CAM/App/Command.h>
|
||||
|
||||
#include "DlgCAMSimulator.h"
|
||||
|
||||
using namespace Path;
|
||||
|
||||
namespace CAMSimulator
|
||||
{
|
||||
|
||||
/** The representation of a CNC Toolpath Simulator */
|
||||
|
||||
class CAMSimulatorExport CAMSim: public Base::BaseClass
|
||||
{
|
||||
// TYPESYSTEM_HEADER();
|
||||
|
||||
public:
|
||||
static Base::Type getClassTypeId(void);
|
||||
virtual Base::Type getTypeId(void) const;
|
||||
static void init(void);
|
||||
static void* create(void);
|
||||
|
||||
private:
|
||||
static Base::Type classTypeId;
|
||||
|
||||
|
||||
public:
|
||||
CAMSim();
|
||||
~CAMSim();
|
||||
|
||||
void BeginSimulation(Part::TopoShape* stock, float resolution);
|
||||
void resetSimulation();
|
||||
void addTool(const std::vector<float> toolProfilePoints,
|
||||
int toolNumber,
|
||||
float diameter,
|
||||
float resolution);
|
||||
void AddCommand(Command* cmd);
|
||||
|
||||
public:
|
||||
std::unique_ptr<SimStock> m_stock;
|
||||
};
|
||||
|
||||
} // namespace CAMSimulator
|
||||
|
||||
|
||||
#endif // CAMSimulator_CAMSim_H
|
||||
61
src/Mod/CAM/PathSimulator/AppGL/CAMSimPy.xml
Normal file
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="BaseClassPy"
|
||||
Name="CAMSimPy"
|
||||
Twin="CAMSim"
|
||||
TwinPointer="CAMSim"
|
||||
Include="Mod/CAM/PathSimulator/AppGL/CAMSim.h"
|
||||
Namespace="CAMSimulator"
|
||||
FatherInclude="Base/BaseClassPy.h"
|
||||
FatherNamespace="Base"
|
||||
Constructor="true"
|
||||
Delete="true">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="Shai Seger" EMail="shaise_at_g-mail" />
|
||||
<UserDocu>
|
||||
FreeCAD python wrapper of CAMSimulator
|
||||
|
||||
CAMSimulator.CAMSim():
|
||||
|
||||
Create a path simulator object
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
<Methode Name="BeginSimulation" Keyword='true'>
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
BeginSimulation(stock, resolution):
|
||||
|
||||
Start a simulation process on a box shape stock with given resolution
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="ResetSimulation">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
ResetSimulation():
|
||||
|
||||
Clear the simulation and all gcode commands
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="AddTool" Keyword='true'>
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
SetToolShape(shape, toolnumber, diameter, resolution):
|
||||
|
||||
Set the shape of the tool to be used for simulation
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="AddCommand">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
AddCommand(command):
|
||||
|
||||
Add a path command to the simulation.
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
</PythonExport>
|
||||
</GenerateModel>
|
||||
128
src/Mod/CAM/PathSimulator/AppGL/CAMSimPyImp.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
/**************************************************************************
|
||||
* Copyright (c) 2017 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include <Base/PlacementPy.h>
|
||||
#include <Base/PyWrapParseTupleAndKeywords.h>
|
||||
|
||||
#include <Mod/Mesh/App/MeshPy.h>
|
||||
#include <Mod/CAM/App/CommandPy.h>
|
||||
#include <Mod/Part/App/TopoShapePy.h>
|
||||
|
||||
// inclusion of the generated files (generated out of CAMSimPy.xml)
|
||||
#include "CAMSimPy.h"
|
||||
#include "CAMSimPy.cpp"
|
||||
|
||||
|
||||
using namespace CAMSimulator;
|
||||
|
||||
// returns a string which represents the object e.g. when printed in python
|
||||
std::string CAMSimPy::representation() const
|
||||
{
|
||||
return std::string("<CAMSim object>");
|
||||
}
|
||||
|
||||
PyObject* CAMSimPy::PyMake(struct _typeobject*, PyObject*, PyObject*) // Python wrapper
|
||||
{
|
||||
// create a new instance of CAMSimPy and the Twin object
|
||||
return new CAMSimPy(new CAMSim);
|
||||
}
|
||||
|
||||
// constructor method
|
||||
int CAMSimPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PyObject* CAMSimPy::ResetSimulation(PyObject* args)
|
||||
{
|
||||
CAMSim* sim = getCAMSimPtr();
|
||||
sim->resetSimulation();
|
||||
Py_IncRef(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject* CAMSimPy::BeginSimulation(PyObject* args, PyObject* kwds)
|
||||
{
|
||||
static const std::array<const char*, 3> kwlist {"stock", "resolution", nullptr};
|
||||
PyObject* pObjStock;
|
||||
float resolution;
|
||||
if (!Base::Wrapped_ParseTupleAndKeywords(args, kwds,"O!f",
|
||||
kwlist, &(Part::TopoShapePy::Type), &pObjStock, &resolution)) {
|
||||
return nullptr;
|
||||
}
|
||||
CAMSim* sim = getCAMSimPtr();
|
||||
Part::TopoShape* stock = static_cast<Part::TopoShapePy*>(pObjStock)->getTopoShapePtr();
|
||||
sim->BeginSimulation(stock, resolution);
|
||||
Py_IncRef(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject* CAMSimPy::AddTool(PyObject* args, PyObject* kwds)
|
||||
{
|
||||
static const std::array<const char*, 5> kwlist {
|
||||
"shape", "toolnumber", "diameter", "resolution", nullptr};
|
||||
PyObject* pObjToolShape;
|
||||
int toolNumber;
|
||||
float resolution;
|
||||
float diameter;
|
||||
if (!Base::Wrapped_ParseTupleAndKeywords(args, kwds, "Oiff", kwlist, &pObjToolShape,
|
||||
&toolNumber, &diameter, &resolution)) {
|
||||
return nullptr;
|
||||
}
|
||||
// The tool shape is defined by a list of 2d points that represents the tool revolving profile
|
||||
Py_ssize_t num_floats = PyList_Size(pObjToolShape);
|
||||
std::vector<float> toolProfile;
|
||||
for (Py_ssize_t i = 0; i < num_floats; ++i) {
|
||||
PyObject* item = PyList_GetItem(pObjToolShape, i);
|
||||
toolProfile.push_back(static_cast<float>(PyFloat_AsDouble(item)));
|
||||
}
|
||||
|
||||
CAMSim* sim = getCAMSimPtr();
|
||||
sim->addTool(toolProfile, toolNumber, diameter, resolution);
|
||||
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject* CAMSimPy::AddCommand(PyObject* args)
|
||||
{
|
||||
PyObject* pObjCmd;
|
||||
if (!PyArg_ParseTuple(args, "O!", &(Path::CommandPy::Type), &pObjCmd)) {
|
||||
return nullptr;
|
||||
}
|
||||
CAMSim* sim = getCAMSimPtr();
|
||||
Path::Command* cmd = static_cast<Path::CommandPy*>(pObjCmd)->getCommandPtr();
|
||||
sim->AddCommand(cmd);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject* CAMSimPy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int CAMSimPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
103
src/Mod/CAM/PathSimulator/AppGL/CMakeLists.txt
Normal file
@@ -0,0 +1,103 @@
|
||||
include_directories(
|
||||
${CMAKE_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}/src
|
||||
${CMAKE_BINARY_DIR}/src
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${Boost_INCLUDE_DIRS}
|
||||
${COIN3D_INCLUDE_DIRS}
|
||||
${ZLIB_INCLUDE_DIR}
|
||||
${OCC_INCLUDE_DIR}
|
||||
${EIGEN3_INCLUDE_DIR}
|
||||
${PYTHON_INCLUDE_DIRS}
|
||||
${XercesC_INCLUDE_DIRS}
|
||||
|
||||
)
|
||||
|
||||
link_directories(${OCC_LIBRARY_DIR})
|
||||
|
||||
set(CAMSimulator_LIBS
|
||||
Path
|
||||
Part
|
||||
Mesh
|
||||
FreeCADApp
|
||||
FreeCADGui
|
||||
${QtOpenGL_LIBRARIES}
|
||||
${OPENGL_gl_LIBRARY}
|
||||
)
|
||||
|
||||
SET(CAMSimulator_SRCS_Python
|
||||
CAMSimPy.xml
|
||||
CAMSimPyImp.cpp
|
||||
)
|
||||
|
||||
|
||||
SET(CAMSimulator_SRCS_Module
|
||||
AppCAMSimulator.cpp
|
||||
CAMSim.cpp
|
||||
CAMSim.h
|
||||
CAMSimPyImp.cpp
|
||||
DlgCAMSimulator.cpp
|
||||
DlgCAMSimulator.h
|
||||
PreCompiled.cpp
|
||||
PreCompiled.h
|
||||
)
|
||||
|
||||
SET(CAMSimulator_SRCS_Core
|
||||
EndMill.cpp
|
||||
EndMill.h
|
||||
GCodeParser.cpp
|
||||
GCodeParser.h
|
||||
GlUtils.cpp
|
||||
GlUtils.h
|
||||
GuiDisplay.cpp
|
||||
GuiDisplay.h
|
||||
linmath.h
|
||||
MillMotion.h
|
||||
MillPathSegment.cpp
|
||||
MillPathSegment.h
|
||||
MillSimulation.cpp
|
||||
MillSimulation.h
|
||||
OpenGlWrapper.h
|
||||
Shader.cpp
|
||||
Shader.h
|
||||
SimShapes.cpp
|
||||
SimShapes.h
|
||||
StockObject.cpp
|
||||
StockObject.h
|
||||
Texture.cpp
|
||||
Texture.h
|
||||
TextureLoader.cpp
|
||||
TextureLoader.h
|
||||
)
|
||||
|
||||
|
||||
generate_from_xml(CAMSimPy)
|
||||
|
||||
|
||||
SOURCE_GROUP("Module" FILES ${CAMSimulator_SRCS_Module})
|
||||
SOURCE_GROUP("Python" FILES ${CAMSimulator_SRCS_Python})
|
||||
SOURCE_GROUP("Core" FILES ${CAMSimulator_SRCS_Core})
|
||||
|
||||
SET(CAMSimulator_SRCS_precomp
|
||||
${CAMSimulator_SRCS_Module}
|
||||
${CAMSimulator_SRCS_Python}
|
||||
)
|
||||
|
||||
SET(CAMSimulator_SRCS
|
||||
${CAMSimulator_SRCS_precomp}
|
||||
${CAMSimulator_SRCS_Core}
|
||||
)
|
||||
|
||||
if(FREECAD_USE_PCH)
|
||||
add_definitions(-D_PreComp_)
|
||||
GET_MSVC_PRECOMPILED_SOURCE("PreCompiled.cpp" PCH_SRCS ${CAMSimulator_SRCS_precomp})
|
||||
ADD_MSVC_PRECOMPILED_HEADER(CAMSimulator PreCompiled.h PreCompiled.cpp PCH_SRCS)
|
||||
endif(FREECAD_USE_PCH)
|
||||
|
||||
add_library(CAMSimulator SHARED ${CAMSimulator_SRCS})
|
||||
target_link_libraries(CAMSimulator ${CAMSimulator_LIBS})
|
||||
|
||||
SET_BIN_DIR(CAMSimulator CAMSimulator /Mod/CAM)
|
||||
SET_PYTHON_PREFIX_SUFFIX(CAMSimulator)
|
||||
|
||||
INSTALL(TARGETS CAMSimulator DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
240
src/Mod/CAM/PathSimulator/AppGL/DlgCAMSimulator.cpp
Normal file
@@ -0,0 +1,240 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include "DlgCAMSimulator.h"
|
||||
#include "MillSimulation.h"
|
||||
#include <QtGui/QMatrix4x4>
|
||||
#include <QtGui/qscreen.h>
|
||||
#include <QDateTime>
|
||||
#include <QSurfaceFormat>
|
||||
#include <QMouseEvent>
|
||||
#include <QWheelEvent>
|
||||
#include <QPoint>
|
||||
|
||||
using namespace CAMSimulator;
|
||||
using namespace MillSim;
|
||||
|
||||
QOpenGLContext* gOpenGlContext;
|
||||
|
||||
using namespace MillSim;
|
||||
|
||||
namespace CAMSimulator
|
||||
{
|
||||
|
||||
DlgCAMSimulator::DlgCAMSimulator(QWindow* parent)
|
||||
: QWindow(parent)
|
||||
{
|
||||
setSurfaceType(QWindow::OpenGLSurface);
|
||||
mMillSimulator = new MillSimulation();
|
||||
}
|
||||
|
||||
void DlgCAMSimulator::render(QPainter* painter)
|
||||
{
|
||||
Q_UNUSED(painter);
|
||||
}
|
||||
|
||||
void DlgCAMSimulator::render()
|
||||
{
|
||||
mMillSimulator->ProcessSim((unsigned int)(QDateTime::currentMSecsSinceEpoch()));
|
||||
}
|
||||
|
||||
void DlgCAMSimulator::renderLater()
|
||||
{
|
||||
requestUpdate();
|
||||
}
|
||||
|
||||
bool DlgCAMSimulator::event(QEvent* event)
|
||||
{
|
||||
switch (event->type()) {
|
||||
case QEvent::UpdateRequest:
|
||||
renderNow();
|
||||
return true;
|
||||
default:
|
||||
return QWindow::event(event);
|
||||
}
|
||||
}
|
||||
|
||||
void DlgCAMSimulator::exposeEvent(QExposeEvent* event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
if (isExposed()) {
|
||||
renderNow();
|
||||
}
|
||||
}
|
||||
|
||||
void DlgCAMSimulator::mouseMoveEvent(QMouseEvent* ev)
|
||||
{
|
||||
mMillSimulator->MouseMove(ev->x(), ev->y());
|
||||
}
|
||||
|
||||
void DlgCAMSimulator::mousePressEvent(QMouseEvent* ev)
|
||||
{
|
||||
mMillSimulator->MousePress(ev->button(), true, ev->x(), ev->y());
|
||||
}
|
||||
|
||||
void DlgCAMSimulator::mouseReleaseEvent(QMouseEvent* ev)
|
||||
{
|
||||
mMillSimulator->MousePress(ev->button(), false, ev->x(), ev->y());
|
||||
}
|
||||
|
||||
void DlgCAMSimulator::wheelEvent(QWheelEvent* ev)
|
||||
{
|
||||
mMillSimulator->MouseScroll((float)ev->angleDelta().y() / 120.0f);
|
||||
}
|
||||
|
||||
void DlgCAMSimulator::resetSimulation()
|
||||
{
|
||||
mMillSimulator->Clear();
|
||||
}
|
||||
|
||||
void DlgCAMSimulator::addGcodeCommand(const char* cmd)
|
||||
{
|
||||
mMillSimulator->AddGcodeLine(cmd);
|
||||
}
|
||||
|
||||
void DlgCAMSimulator::addTool(const std::vector<float> toolProfilePoints,
|
||||
int toolNumber,
|
||||
float diameter,
|
||||
float resolution)
|
||||
{
|
||||
std::string toolCmd = "T" + std::to_string(toolNumber);
|
||||
mMillSimulator->AddGcodeLine(toolCmd.c_str());
|
||||
if (!mMillSimulator->ToolExists(toolNumber)) {
|
||||
mMillSimulator->AddTool(toolProfilePoints, toolNumber, diameter);
|
||||
}
|
||||
}
|
||||
|
||||
void DlgCAMSimulator::hideEvent(QHideEvent* ev)
|
||||
{
|
||||
mAnimating = false;
|
||||
}
|
||||
|
||||
void DlgCAMSimulator::startSimulation(const SimStock* stock, float quality)
|
||||
{
|
||||
mStock = *stock;
|
||||
mQuality = quality;
|
||||
mNeedsInitialize = true;
|
||||
show();
|
||||
setAnimating(true);
|
||||
}
|
||||
|
||||
void DlgCAMSimulator::initialize()
|
||||
{
|
||||
mMillSimulator
|
||||
->SetBoxStock(mStock.mPx, mStock.mPy, mStock.mPz, mStock.mLx, mStock.mLy, mStock.mLz);
|
||||
mMillSimulator->InitSimulation(mQuality);
|
||||
|
||||
const qreal retinaScale = devicePixelRatio();
|
||||
glViewport(0, 0, width() * retinaScale, height() * retinaScale);
|
||||
}
|
||||
|
||||
void DlgCAMSimulator::checkInitialization()
|
||||
{
|
||||
if (!mContext) {
|
||||
mContext = new QOpenGLContext(this);
|
||||
mContext->setFormat(requestedFormat());
|
||||
mContext->create();
|
||||
gOpenGlContext = mContext;
|
||||
mNeedsInitialize = true;
|
||||
}
|
||||
|
||||
mContext->makeCurrent(this);
|
||||
|
||||
if (mNeedsInitialize) {
|
||||
initializeOpenGLFunctions();
|
||||
initialize();
|
||||
mNeedsInitialize = false;
|
||||
}
|
||||
}
|
||||
|
||||
void DlgCAMSimulator::renderNow()
|
||||
{
|
||||
static unsigned int lastTime = 0;
|
||||
static int frameCount = 0;
|
||||
static int fps = 0;
|
||||
if (!isExposed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
checkInitialization();
|
||||
|
||||
frameCount++;
|
||||
unsigned int curtime = QDateTime::currentMSecsSinceEpoch();
|
||||
unsigned int timediff = curtime - lastTime;
|
||||
if (timediff > 10000) {
|
||||
fps = frameCount * 1000 / timediff; // for debug only. not used otherwise.
|
||||
lastTime = curtime;
|
||||
frameCount = 0;
|
||||
}
|
||||
render();
|
||||
mContext->swapBuffers(this);
|
||||
|
||||
if (mAnimating) {
|
||||
renderLater();
|
||||
}
|
||||
}
|
||||
|
||||
void DlgCAMSimulator::setAnimating(bool animating)
|
||||
{
|
||||
mAnimating = animating;
|
||||
|
||||
if (animating) {
|
||||
renderLater();
|
||||
}
|
||||
}
|
||||
|
||||
DlgCAMSimulator* DlgCAMSimulator::GetInstance()
|
||||
{
|
||||
if (mInstance == nullptr) {
|
||||
QSurfaceFormat format;
|
||||
format.setSamples(16);
|
||||
format.setSwapInterval(2);
|
||||
mInstance = new DlgCAMSimulator();
|
||||
mInstance->setFormat(format);
|
||||
mInstance->resize(800, 600);
|
||||
mInstance->setModality(Qt::ApplicationModal);
|
||||
mInstance->show();
|
||||
}
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
DlgCAMSimulator* DlgCAMSimulator::mInstance = nullptr;
|
||||
|
||||
//************************************************************************************************************
|
||||
// stock
|
||||
//************************************************************************************************************
|
||||
SimStock::SimStock(float px, float py, float pz, float lx, float ly, float lz, float res)
|
||||
: mPx(px)
|
||||
, mPy(py)
|
||||
, mPz(pz + 0.005 * lz)
|
||||
, mLx(lx)
|
||||
, mLy(ly)
|
||||
, mLz(1.01 * lz)
|
||||
{}
|
||||
|
||||
SimStock::~SimStock()
|
||||
{}
|
||||
|
||||
} // namespace CAMSimulator
|
||||
110
src/Mod/CAM/PathSimulator/AppGL/DlgCAMSimulator.h
Normal file
@@ -0,0 +1,110 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2017 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef PATHSIMULATOR_CAMSimulatorGui_H
|
||||
#define PATHSIMULATOR_CAMSimulatorGui_H
|
||||
|
||||
// #include <memory>
|
||||
// #include <TopoDS_Shape.hxx>
|
||||
|
||||
// #include <Mod/CAM/App/Command.h>
|
||||
// #include <Mod/Part/App/TopoShape.h>
|
||||
// #include <Mod/CAM/PathGlobal.h>
|
||||
#include <QtGui/qwindow.h>
|
||||
#include <QOpenGLExtraFunctions>
|
||||
#include <QtGui/qpainter.h>
|
||||
#include <QtGui/qopenglpaintdevice.h>
|
||||
|
||||
|
||||
namespace MillSim
|
||||
{
|
||||
class MillSimulation; // use short declaration as using 'include' causes a header loop
|
||||
}
|
||||
|
||||
namespace CAMSimulator
|
||||
{
|
||||
|
||||
struct SimStock
|
||||
{
|
||||
public:
|
||||
SimStock(float px, float py, float pz, float lx, float ly, float lz, float res);
|
||||
~SimStock();
|
||||
|
||||
public:
|
||||
float mPx, mPy, mPz; // stock zero position
|
||||
float mLx, mLy, mLz; // stock dimensions
|
||||
};
|
||||
|
||||
class DlgCAMSimulator: public QWindow, public QOpenGLExtraFunctions
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DlgCAMSimulator(QWindow* parent = nullptr);
|
||||
~DlgCAMSimulator()
|
||||
{}
|
||||
|
||||
virtual void render(QPainter* painter);
|
||||
virtual void render();
|
||||
virtual void initialize();
|
||||
|
||||
void setAnimating(bool animating);
|
||||
static DlgCAMSimulator* GetInstance();
|
||||
|
||||
public: // slots:
|
||||
void renderLater();
|
||||
void renderNow();
|
||||
void startSimulation(const SimStock* stock, float quality);
|
||||
void resetSimulation();
|
||||
void addGcodeCommand(const char* cmd);
|
||||
void addTool(const std::vector<float> toolProfilePoints,
|
||||
int toolNumber,
|
||||
float diameter,
|
||||
float resolution);
|
||||
|
||||
protected:
|
||||
bool event(QEvent* event) override;
|
||||
|
||||
void checkInitialization();
|
||||
void exposeEvent(QExposeEvent* event) override;
|
||||
void mouseMoveEvent(QMouseEvent* ev) override;
|
||||
void mousePressEvent(QMouseEvent* ev) override;
|
||||
void mouseReleaseEvent(QMouseEvent* ev) override;
|
||||
void wheelEvent(QWheelEvent* ev) override;
|
||||
void hideEvent(QHideEvent* ev) override;
|
||||
|
||||
private:
|
||||
bool mAnimating = false;
|
||||
bool mNeedsInitialize = false;
|
||||
|
||||
QOpenGLContext* mContext = nullptr;
|
||||
QOpenGLPaintDevice* mDevice = nullptr;
|
||||
MillSim::MillSimulation* mMillSimulator = nullptr;
|
||||
static DlgCAMSimulator* mInstance;
|
||||
SimStock mStock = {0, 0, 0, 1, 1, 1, 1};
|
||||
float mQuality = 10;
|
||||
};
|
||||
|
||||
|
||||
} // namespace CAMSimulator
|
||||
|
||||
|
||||
#endif // PATHSIMULATOR_PathSim_H
|
||||
124
src/Mod/CAM/PathSimulator/AppGL/EndMill.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "EndMill.h"
|
||||
#include "OpenGlWrapper.h"
|
||||
#include "SimShapes.h"
|
||||
|
||||
using namespace MillSim;
|
||||
|
||||
EndMill::EndMill(int toolid, float diameter)
|
||||
{
|
||||
radius = diameter / 2;
|
||||
toolId = toolid;
|
||||
}
|
||||
|
||||
EndMill::EndMill(const std::vector<float>& toolProfile, int toolid, float diameter)
|
||||
: EndMill(toolid, diameter)
|
||||
{
|
||||
profilePoints = nullptr;
|
||||
mHandleAllocation = false;
|
||||
|
||||
int srcBuffSize = toolProfile.size();
|
||||
nPoints = srcBuffSize / 2;
|
||||
if (nPoints < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure last point is at 0,0 else, add it
|
||||
bool missingCenterPoint = fabs(toolProfile[nPoints * 2 - 2]) > 0.0001f;
|
||||
if (missingCenterPoint) {
|
||||
nPoints++;
|
||||
}
|
||||
|
||||
int buffSize = PROFILE_BUFFER_SIZE(nPoints);
|
||||
profilePoints = new float[buffSize];
|
||||
if (profilePoints == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// copy profile points
|
||||
mHandleAllocation = true;
|
||||
for (int i = 0; i < srcBuffSize; i++) {
|
||||
profilePoints[i] = toolProfile[i] + 0.01f; // add some width to reduce simulation artifacts
|
||||
}
|
||||
if (missingCenterPoint) {
|
||||
profilePoints[srcBuffSize] = profilePoints[srcBuffSize + 1] = 0.0f;
|
||||
}
|
||||
|
||||
MirrorPointBuffer();
|
||||
}
|
||||
|
||||
EndMill::~EndMill()
|
||||
{
|
||||
toolShape.FreeResources();
|
||||
halfToolShape.FreeResources();
|
||||
pathShape.FreeResources();
|
||||
if (mHandleAllocation) {
|
||||
delete[] profilePoints;
|
||||
}
|
||||
}
|
||||
|
||||
void EndMill::GenerateDisplayLists(float quality)
|
||||
{
|
||||
// calculate number of slices based on quality.
|
||||
int nslices = 16;
|
||||
if (quality < 3) {
|
||||
nslices = 4;
|
||||
}
|
||||
else if (quality < 7) {
|
||||
nslices = 8;
|
||||
}
|
||||
|
||||
// full tool
|
||||
toolShape.RotateProfile(profilePoints, nPoints, 0, 0, nslices, false);
|
||||
|
||||
// half tool
|
||||
halfToolShape.RotateProfile(profilePoints, nPoints, 0, 0, nslices / 2, true);
|
||||
|
||||
// unit path
|
||||
int nFullPoints = PROFILE_BUFFER_POINTS(nPoints);
|
||||
pathShape.ExtrudeProfileLinear(profilePoints, nFullPoints, 0, 1, 0, 0, true, false);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
EndMill::GenerateArcSegmentDL(float radius, float angleRad, float zShift, Shape* retShape)
|
||||
{
|
||||
int nFullPoints = PROFILE_BUFFER_POINTS(nPoints);
|
||||
retShape->ExtrudeProfileRadial(profilePoints,
|
||||
PROFILE_BUFFER_POINTS(nPoints),
|
||||
radius,
|
||||
angleRad,
|
||||
zShift,
|
||||
true,
|
||||
true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void EndMill::MirrorPointBuffer()
|
||||
{
|
||||
int endpoint = PROFILE_BUFFER_POINTS(nPoints) - 1;
|
||||
for (int i = 0, j = endpoint * 2; i < (nPoints - 1) * 2; i += 2, j -= 2) {
|
||||
profilePoints[j] = -profilePoints[i];
|
||||
profilePoints[j + 1] = profilePoints[i + 1];
|
||||
}
|
||||
}
|
||||
62
src/Mod/CAM/PathSimulator/AppGL/EndMill.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __end_mill_h__
|
||||
#define __end_mill_h__
|
||||
|
||||
#include "SimShapes.h"
|
||||
#include <vector>
|
||||
|
||||
#define PROFILE_BUFFER_POINTS(npoints) ((npoints) * 2 - 1)
|
||||
#define PROFILE_BUFFER_SIZE(npoints) (PROFILE_BUFFER_POINTS(npoints) * 2)
|
||||
#define MILL_HEIGHT 10
|
||||
|
||||
namespace MillSim
|
||||
{
|
||||
class EndMill
|
||||
{
|
||||
public:
|
||||
float* profilePoints = nullptr;
|
||||
float radius;
|
||||
int nPoints = 0;
|
||||
int toolId = -1;
|
||||
|
||||
Shape pathShape;
|
||||
Shape halfToolShape;
|
||||
Shape toolShape;
|
||||
|
||||
public:
|
||||
EndMill(int toolid, float diameter);
|
||||
EndMill(const std::vector<float>& toolProfile, int toolid, float diameter);
|
||||
virtual ~EndMill();
|
||||
void GenerateDisplayLists(float quality);
|
||||
unsigned int GenerateArcSegmentDL(float radius, float angleRad, float zShift, Shape* retShape);
|
||||
|
||||
protected:
|
||||
void MirrorPointBuffer();
|
||||
|
||||
private:
|
||||
bool mHandleAllocation = false;
|
||||
};
|
||||
} // namespace MillSim
|
||||
|
||||
#endif
|
||||
234
src/Mod/CAM/PathSimulator/AppGL/GCodeParser.cpp
Normal file
@@ -0,0 +1,234 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "GCodeParser.h"
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace MillSim;
|
||||
|
||||
static char TokTypes[] = "GTXYZIJKR";
|
||||
|
||||
GCodeParser::~GCodeParser()
|
||||
{
|
||||
// Clear the vector
|
||||
Operations.clear();
|
||||
}
|
||||
|
||||
bool GCodeParser::Parse(const char* filename)
|
||||
{
|
||||
Operations.clear();
|
||||
lastState = {eNop, -1, 0, 0, 0, 0, 0, 0};
|
||||
lastTool = -1;
|
||||
|
||||
FILE* fl;
|
||||
if ((fl = fopen(filename, "rt")) == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char line[120];
|
||||
|
||||
while (!feof(fl)) {
|
||||
if (fgets(line, 120, fl) != NULL) {
|
||||
AddLine(line);
|
||||
}
|
||||
}
|
||||
fclose(fl);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* GCodeParser::GetNextToken(const char* ptr, GCToken* token)
|
||||
{
|
||||
float tokval;
|
||||
token->letter = '*';
|
||||
while (*ptr != 0) {
|
||||
char letter = toupper(*ptr);
|
||||
ptr++;
|
||||
|
||||
if (letter == ' ') {
|
||||
continue;
|
||||
}
|
||||
if (letter == '(') {
|
||||
break;
|
||||
}
|
||||
|
||||
if (IsValidToken(letter)) {
|
||||
ptr = ParseFloat(ptr, &tokval);
|
||||
token->letter = letter;
|
||||
token->fval = tokval;
|
||||
token->ival = (int)(tokval + 0.5);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool GCodeParser::IsValidToken(char tok)
|
||||
{
|
||||
int len = (int)strlen(TokTypes);
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (tok == TokTypes[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* GCodeParser::ParseFloat(const char* ptr, float* retFloat)
|
||||
{
|
||||
float decPos = 10;
|
||||
float sign = 1;
|
||||
bool decimalPointFound = false;
|
||||
float res = 0;
|
||||
while (*ptr != 0) {
|
||||
char letter = toupper(*ptr);
|
||||
ptr++;
|
||||
|
||||
if (letter == ' ') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (letter == '-') {
|
||||
sign = -1;
|
||||
}
|
||||
else if (letter == '.') {
|
||||
decimalPointFound = true;
|
||||
}
|
||||
else if (letter >= '0' && letter <= '9') {
|
||||
float digitVal = (float)(letter - '0');
|
||||
if (decimalPointFound) {
|
||||
res = res + digitVal / decPos;
|
||||
decPos *= 10;
|
||||
}
|
||||
else {
|
||||
res = res * 10 + digitVal;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ptr--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*retFloat = res * sign;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool GCodeParser::ParseLine(const char* ptr)
|
||||
{
|
||||
GCToken token;
|
||||
bool validMotion = false;
|
||||
bool exitLoop = false;
|
||||
int cmd = 0;
|
||||
while (*ptr != 0 && !exitLoop) {
|
||||
ptr = GetNextToken(ptr, &token);
|
||||
lastLastState = lastState;
|
||||
switch (token.letter) {
|
||||
case '*':
|
||||
exitLoop = true;
|
||||
break;
|
||||
|
||||
case 'G':
|
||||
cmd = token.ival;
|
||||
if (cmd == 0 || cmd == 1) {
|
||||
lastState.cmd = eMoveLiner;
|
||||
}
|
||||
else if (cmd == 2) {
|
||||
lastState.cmd = eRotateCW;
|
||||
}
|
||||
else if (cmd == 3) {
|
||||
lastState.cmd = eRotateCCW;
|
||||
}
|
||||
else if (cmd == 73 || cmd == 81 || cmd == 82 || cmd == 83) {
|
||||
lastState.cmd = eDril;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'T':
|
||||
lastState.tool = token.ival;
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
lastState.x = token.fval;
|
||||
validMotion = true;
|
||||
break;
|
||||
|
||||
case 'Y':
|
||||
lastState.y = token.fval;
|
||||
validMotion = true;
|
||||
break;
|
||||
|
||||
case 'Z':
|
||||
lastState.z = token.fval;
|
||||
validMotion = true;
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
lastState.i = token.fval;
|
||||
break;
|
||||
|
||||
case 'J':
|
||||
lastState.j = token.fval;
|
||||
break;
|
||||
|
||||
case 'K':
|
||||
lastState.k = token.fval;
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
lastState.r = token.fval;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return validMotion;
|
||||
}
|
||||
|
||||
bool GCodeParser::AddLine(const char* ptr)
|
||||
{
|
||||
bool res = ParseLine(ptr);
|
||||
if (res) {
|
||||
if (lastState.cmd == eDril) {
|
||||
// split to several motions
|
||||
lastState.cmd = eMoveLiner;
|
||||
float rPlane = lastState.r;
|
||||
float finalDepth = lastState.z;
|
||||
lastState.z = rPlane;
|
||||
Operations.push_back(lastState);
|
||||
lastState.z = finalDepth;
|
||||
Operations.push_back(lastState);
|
||||
lastState.z = rPlane;
|
||||
Operations.push_back(lastState);
|
||||
// restore original state
|
||||
lastState.z = finalDepth;
|
||||
lastState.cmd = eDril;
|
||||
}
|
||||
else {
|
||||
Operations.push_back(lastState);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
59
src/Mod/CAM/PathSimulator/AppGL/GCodeParser.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __csgcodeparser_h__
|
||||
#define __csgcodeparser_h__
|
||||
#include "MillMotion.h"
|
||||
#include <vector>
|
||||
|
||||
namespace MillSim
|
||||
{
|
||||
struct GCToken
|
||||
{
|
||||
char letter;
|
||||
float fval;
|
||||
int ival;
|
||||
};
|
||||
|
||||
class GCodeParser
|
||||
{
|
||||
public:
|
||||
GCodeParser()
|
||||
{}
|
||||
virtual ~GCodeParser();
|
||||
bool Parse(const char* filename);
|
||||
bool AddLine(const char* ptr);
|
||||
|
||||
public:
|
||||
std::vector<MillMotion> Operations;
|
||||
MillMotion lastState = {eNop};
|
||||
MillMotion lastLastState = {eNop};
|
||||
|
||||
protected:
|
||||
const char* GetNextToken(const char* ptr, GCToken* token);
|
||||
bool IsValidToken(char tok);
|
||||
const char* ParseFloat(const char* ptr, float* retFloat);
|
||||
bool ParseLine(const char* ptr);
|
||||
int lastTool = -1;
|
||||
};
|
||||
} // namespace MillSim
|
||||
#endif
|
||||
56
src/Mod/CAM/PathSimulator/AppGL/GlUtils.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "GlUtils.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace MillSim
|
||||
{
|
||||
|
||||
int gDebug = -1;
|
||||
|
||||
mat4x4 identityMat = {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}};
|
||||
|
||||
void GLClearError()
|
||||
{
|
||||
while (glGetError() != GL_NO_ERROR)
|
||||
;
|
||||
}
|
||||
|
||||
bool GLLogError()
|
||||
{
|
||||
bool isError = false;
|
||||
while (GLenum err = glGetError()) {
|
||||
std::cout << "[Opengl Error] (" << err << ")" << std::endl;
|
||||
isError = true;
|
||||
}
|
||||
return isError;
|
||||
}
|
||||
|
||||
|
||||
typedef struct Vertex
|
||||
{
|
||||
vec3 pos;
|
||||
vec3 col;
|
||||
} Vertex;
|
||||
|
||||
} // namespace MillSim
|
||||
53
src/Mod/CAM/PathSimulator/AppGL/GlUtils.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __glutils_h__
|
||||
#define __glutils_h__
|
||||
#include "OpenGlWrapper.h"
|
||||
#include "linmath.h"
|
||||
|
||||
#define PI 3.14159265f
|
||||
#define PI2 (PI * 2)
|
||||
|
||||
constexpr auto EPSILON = 0.00001f;
|
||||
#define EQ_FLOAT(x, y) (fabs((x) - (y)) < EPSILON)
|
||||
|
||||
#define MS_MOUSE_LEFT 1
|
||||
#define MS_MOUSE_RIGHT 2
|
||||
#define MS_MOUSE_MID 4
|
||||
#define GL(x) \
|
||||
{ \
|
||||
GLClearError(); \
|
||||
x; \
|
||||
if (GLLogError()) \
|
||||
__debugbreak(); \
|
||||
}
|
||||
#define RadToDeg(x) (x * 180.0f / PI)
|
||||
|
||||
namespace MillSim
|
||||
{
|
||||
void GLClearError();
|
||||
bool GLLogError();
|
||||
extern mat4x4 identityMat;
|
||||
extern int gDebug;
|
||||
} // namespace MillSim
|
||||
#endif // !__glutils_h__
|
||||
243
src/Mod/CAM/PathSimulator/AppGL/GuiDisplay.cpp
Normal file
@@ -0,0 +1,243 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "GuiDisplay.h"
|
||||
#include "OpenGlWrapper.h"
|
||||
#include "MillSimulation.h"
|
||||
#include <cstddef>
|
||||
#include "GlUtils.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
using namespace MillSim;
|
||||
|
||||
GuiItem guiItems[] = {
|
||||
{0, 0, 360, 554, 0},
|
||||
{0, 0, 448, 540, 1},
|
||||
{0, 0, 170, 540, 'P', true},
|
||||
{0, 0, 170, 540, 'S', false},
|
||||
{0, 0, 210, 540, 'T'},
|
||||
{0, 0, 250, 540, 'F'},
|
||||
{0, 0, 290, 540, ' '},
|
||||
{0, 0, 620, 540, 0, false, 0},
|
||||
{0, 0, 660, 540, 0, false, 0},
|
||||
{0, 0, 645, 540, 0, false, 0},
|
||||
{0, 0, 640, 540, 0, true, 0},
|
||||
};
|
||||
|
||||
#define NUM_GUI_ITEMS (sizeof(guiItems) / sizeof(GuiItem))
|
||||
#define TEX_SIZE 256
|
||||
|
||||
std::vector<std::string> guiFileNames = {"Slider.png",
|
||||
"Thumb.png",
|
||||
"Pause.png",
|
||||
"Play.png",
|
||||
"SingleStep.png",
|
||||
"Faster.png",
|
||||
"Rotate.png",
|
||||
"X.png",
|
||||
"0.png",
|
||||
"1.png",
|
||||
"4.png"};
|
||||
|
||||
bool GuiDisplay::GenerateGlItem(GuiItem* guiItem)
|
||||
{
|
||||
Vertex2D verts[4];
|
||||
int x = guiItem->texItem.tx;
|
||||
int y = guiItem->texItem.ty;
|
||||
int w = guiItem->texItem.w;
|
||||
int h = guiItem->texItem.h;
|
||||
|
||||
verts[0] = {0, (float)h, mTexture.getTexX(x), mTexture.getTexY(y + h)};
|
||||
verts[1] = {(float)w, (float)h, mTexture.getTexX(x + w), mTexture.getTexY(y + h)};
|
||||
verts[2] = {0, 0, mTexture.getTexX(x), mTexture.getTexY(y)};
|
||||
verts[3] = {(float)w, 0, mTexture.getTexX(x + w), mTexture.getTexY(y)};
|
||||
|
||||
// vertex buffer
|
||||
glGenBuffers(1, &(guiItem->vbo));
|
||||
glBindBuffer(GL_ARRAY_BUFFER, guiItem->vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(Vertex2D), verts, GL_STATIC_DRAW);
|
||||
|
||||
// glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, nullptr);
|
||||
// vertex array
|
||||
glGenVertexArrays(1, &(guiItem->vao));
|
||||
glBindVertexArray(guiItem->vao);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*)offsetof(Vertex2D, x));
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(1,
|
||||
2,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
sizeof(Vertex2D),
|
||||
(void*)offsetof(Vertex2D, tx));
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIbo);
|
||||
glBindVertexArray(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GuiDisplay::InutGui()
|
||||
{
|
||||
// index buffer
|
||||
glGenBuffers(1, &mIbo);
|
||||
GLshort indices[6] = {0, 2, 3, 0, 3, 1};
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIbo);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(GLushort), indices, GL_STATIC_DRAW);
|
||||
TextureLoader tLoader(":/gl_simulator/", guiFileNames, TEX_SIZE);
|
||||
unsigned int* buffer = tLoader.GetRawData();
|
||||
if (buffer == nullptr) {
|
||||
return false;
|
||||
}
|
||||
mTexture.LoadImage(buffer, TEX_SIZE, TEX_SIZE);
|
||||
for (int i = 0; i < NUM_GUI_ITEMS; i++) {
|
||||
guiItems[i].texItem = *tLoader.GetTextureItem(i);
|
||||
GenerateGlItem(&(guiItems[i]));
|
||||
}
|
||||
|
||||
mThumbStartX = guiItems[eGuiItemSlider].sx - guiItems[eGuiItemThumb].texItem.w / 2;
|
||||
mThumbMaxMotion = (float)guiItems[eGuiItemSlider].texItem.w;
|
||||
|
||||
UpdateSimSpeed(1);
|
||||
|
||||
// shader
|
||||
mat4x4 projmat;
|
||||
// mat4x4 viewmat;
|
||||
mat4x4_ortho(projmat, 0, 800, 600, 0, -1, 1);
|
||||
mShader.CompileShader((char*)VertShader2DTex, (char*)FragShader2dTex);
|
||||
mShader.UpdateTextureSlot(0);
|
||||
mShader.UpdateProjectionMat(projmat);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiDisplay::RenderItem(int itemId)
|
||||
{
|
||||
GuiItem* item = &(guiItems[itemId]);
|
||||
if (item->hidden) {
|
||||
return;
|
||||
}
|
||||
mat4x4 model;
|
||||
mat4x4_translate(model, (float)item->sx, (float)item->sy, 0);
|
||||
mShader.UpdateModelMat(model, nullptr);
|
||||
if (itemId == mPressedItem) {
|
||||
mShader.UpdateObjColor(mPressedColor);
|
||||
}
|
||||
else if (item->mouseOver) {
|
||||
mShader.UpdateObjColor(mHighlightColor);
|
||||
}
|
||||
else if (itemId > 1 && item->actionKey == 0) {
|
||||
mShader.UpdateObjColor(mTextColor);
|
||||
}
|
||||
else {
|
||||
mShader.UpdateObjColor(mStdColor);
|
||||
}
|
||||
|
||||
glBindVertexArray(item->vao);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIbo);
|
||||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
|
||||
}
|
||||
|
||||
void GuiDisplay::MouseCursorPos(int x, int y)
|
||||
{
|
||||
for (int i = 0; i < NUM_GUI_ITEMS; i++) {
|
||||
GuiItem* g = &(guiItems[i]);
|
||||
if (g->actionKey == 0) {
|
||||
continue;
|
||||
}
|
||||
g->mouseOver =
|
||||
(x > g->sx && y > g->sy && x < (g->sx + g->texItem.w) && y < (g->sy + g->texItem.h));
|
||||
}
|
||||
}
|
||||
|
||||
void GuiDisplay::MousePressed(int button, bool isPressed, bool isSimRunning)
|
||||
{
|
||||
if (button == MS_MOUSE_LEFT) {
|
||||
if (isPressed) {
|
||||
mPressedItem = eGuiItemMax;
|
||||
for (int i = 1; i < NUM_GUI_ITEMS; i++) {
|
||||
GuiItem* g = &(guiItems[i]);
|
||||
if (g->mouseOver && !g->hidden) {
|
||||
mPressedItem = (eGuiItems)i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mPressedItem != eGuiItemMax) {
|
||||
GuiItem* g = &(guiItems[mPressedItem]);
|
||||
if (g->actionKey >= 32) {
|
||||
mMillSim->HandleKeyPress(g->actionKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // button released
|
||||
{
|
||||
UpdatePlayState(isSimRunning);
|
||||
mPressedItem = eGuiItemMax;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GuiDisplay::MouseDrag(int buttons, int dx, int dy)
|
||||
{
|
||||
if (mPressedItem == eGuiItemThumb) {
|
||||
GuiItem* g = &(guiItems[eGuiItemThumb]);
|
||||
int newx = g->sx + dx;
|
||||
if (newx < mThumbStartX) {
|
||||
newx = mThumbStartX;
|
||||
}
|
||||
if (newx > ((int)mThumbMaxMotion + mThumbStartX)) {
|
||||
newx = (int)mThumbMaxMotion + mThumbStartX;
|
||||
}
|
||||
if (newx != g->sx) {
|
||||
mMillSim->SetSimulationStage((float)(newx - mThumbStartX) / mThumbMaxMotion);
|
||||
g->sx = newx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GuiDisplay::UpdatePlayState(bool isRunning)
|
||||
{
|
||||
guiItems[eGuiItemPause].hidden = !isRunning;
|
||||
guiItems[eGuiItemPlay].hidden = isRunning;
|
||||
}
|
||||
|
||||
void MillSim::GuiDisplay::UpdateSimSpeed(int speed)
|
||||
{
|
||||
guiItems[eGuiItemChar0Img].hidden = speed == 1;
|
||||
guiItems[eGuiItemChar1Img].hidden = speed == 40;
|
||||
guiItems[eGuiItemChar4Img].hidden = speed != 40;
|
||||
}
|
||||
|
||||
void GuiDisplay::Render(float progress)
|
||||
{
|
||||
if (mPressedItem != eGuiItemThumb) {
|
||||
guiItems[eGuiItemThumb].sx = (int)(mThumbMaxMotion * progress) + mThumbStartX;
|
||||
}
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
mTexture.Activate();
|
||||
mShader.Activate();
|
||||
mShader.UpdateTextureSlot(0);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
for (int i = 0; i < NUM_GUI_ITEMS; i++) {
|
||||
RenderItem(i);
|
||||
}
|
||||
}
|
||||
103
src/Mod/CAM/PathSimulator/AppGL/GuiDisplay.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __guidisplay_t__
|
||||
#define __guidisplay_t__
|
||||
#include "OpenGlWrapper.h"
|
||||
#include "Texture.h"
|
||||
#include "Shader.h"
|
||||
#include "TextureLoader.h"
|
||||
|
||||
namespace MillSim
|
||||
{
|
||||
class MillSimulation;
|
||||
|
||||
struct GuiItem
|
||||
{
|
||||
unsigned int vbo, vao;
|
||||
int sx, sy; // screen location
|
||||
int actionKey; // action key when item pressed
|
||||
bool hidden; // is item hidden
|
||||
bool mouseOver;
|
||||
TextureItem texItem;
|
||||
};
|
||||
|
||||
struct Vertex2D
|
||||
{
|
||||
float x, y;
|
||||
float tx, ty;
|
||||
};
|
||||
|
||||
enum eGuiItems
|
||||
{
|
||||
eGuiItemSlider,
|
||||
eGuiItemThumb,
|
||||
eGuiItemPause,
|
||||
eGuiItemPlay,
|
||||
eGuiItemSingleStep,
|
||||
eGuiItemFaster,
|
||||
eGuiItemRotate,
|
||||
eGuiItemCharXImg,
|
||||
eGuiItemChar0Img,
|
||||
eGuiItemChar1Img,
|
||||
eGuiItemChar4Img,
|
||||
eGuiItemMax
|
||||
};
|
||||
|
||||
|
||||
class GuiDisplay
|
||||
{
|
||||
public:
|
||||
// GuiDisplay() {};
|
||||
bool InutGui();
|
||||
void Render(float progress);
|
||||
void MouseCursorPos(int x, int y);
|
||||
void MousePressed(int button, bool isPressed, bool isRunning);
|
||||
void MouseDrag(int buttons, int dx, int dy);
|
||||
void SetMillSimulator(MillSimulation* millSim)
|
||||
{
|
||||
mMillSim = millSim;
|
||||
}
|
||||
void UpdatePlayState(bool isRunning);
|
||||
void UpdateSimSpeed(int speed);
|
||||
|
||||
private:
|
||||
bool GenerateGlItem(GuiItem* guiItem);
|
||||
void RenderItem(int itemId);
|
||||
|
||||
vec3 mStdColor = {0.8f, 0.8f, 0.4f};
|
||||
vec3 mHighlightColor = {1.0f, 1.0f, 0.9f};
|
||||
vec3 mPressedColor = {1.0f, 0.5f, 0.0f};
|
||||
vec3 mTextColor = {1.0f, 0.5f, 0.0f};
|
||||
|
||||
Shader mShader;
|
||||
Texture mTexture;
|
||||
eGuiItems mPressedItem = eGuiItemMax;
|
||||
MillSimulation* mMillSim = nullptr;
|
||||
unsigned int mIbo = 0;
|
||||
int mThumbStartX = 0;
|
||||
float mThumbMaxMotion = 0;
|
||||
};
|
||||
|
||||
} // namespace MillSim
|
||||
|
||||
#endif // __guidisplay_t__
|
||||
65
src/Mod/CAM/PathSimulator/AppGL/MillMotion.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __mill_operation_h__
|
||||
#define __mill_operation_h__
|
||||
// #include <math.h>
|
||||
#include "EndMill.h"
|
||||
#include "linmath.h"
|
||||
namespace MillSim
|
||||
{
|
||||
|
||||
enum eEndMillType
|
||||
{
|
||||
eEndmillFlat,
|
||||
eEndmillV,
|
||||
eEndmillBall,
|
||||
eEndmillFillet
|
||||
};
|
||||
|
||||
enum eCmdType
|
||||
{
|
||||
eNop,
|
||||
eMoveLiner,
|
||||
eRotateCW,
|
||||
eRotateCCW,
|
||||
eDril,
|
||||
eChangeTool
|
||||
};
|
||||
|
||||
struct MillMotion
|
||||
{
|
||||
eCmdType cmd;
|
||||
int tool;
|
||||
float x, y, z;
|
||||
float i, j, k;
|
||||
float r;
|
||||
};
|
||||
|
||||
static inline void MotionPosToVec(vec3 vec, const MillMotion* motion)
|
||||
{
|
||||
vec[0] = motion->x;
|
||||
vec[1] = motion->y;
|
||||
vec[2] = motion->z;
|
||||
}
|
||||
} // namespace MillSim
|
||||
#endif
|
||||
242
src/Mod/CAM/PathSimulator/AppGL/MillPathSegment.cpp
Normal file
@@ -0,0 +1,242 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "OpenGlWrapper.h"
|
||||
#include "MillPathSegment.h"
|
||||
#include "SimShapes.h"
|
||||
#include "linmath.h"
|
||||
#include "GlUtils.h"
|
||||
#include <iostream>
|
||||
|
||||
#define N_MILL_SLICES 8
|
||||
#define MAX_SEG_DEG (PI / 2.0f) // 90 deg
|
||||
#define NIN_SEG_DEG (PI / 90.0f) // 2 deg
|
||||
#define SWEEP_ARC_PAD 1.05f
|
||||
#define PX 0
|
||||
#define PY 1
|
||||
#define PZ 2
|
||||
|
||||
|
||||
namespace MillSim
|
||||
{
|
||||
|
||||
bool IsVerticalMotion(MillMotion* m1, MillMotion* m2)
|
||||
{
|
||||
return (m1->z != m2->z && EQ_FLOAT(m1->x, m2->x) && EQ_FLOAT(m1->y, m2->y));
|
||||
}
|
||||
|
||||
bool IsArcMotion(MillMotion* m)
|
||||
{
|
||||
if (m->cmd != eRotateCCW && m->cmd != eRotateCW) {
|
||||
return false;
|
||||
}
|
||||
return fabs(m->i > EPSILON) || fabs(m->j) > EPSILON;
|
||||
}
|
||||
|
||||
float MillPathSegment::mResolution = 1;
|
||||
float MillPathSegment::mSmallRadStep = (PI / 8);
|
||||
|
||||
MillPathSegment::MillPathSegment(EndMill* _endmill, MillMotion* from, MillMotion* to)
|
||||
: mShearMat {1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f}
|
||||
{
|
||||
|
||||
MotionPosToVec(mStartPos, from);
|
||||
MotionPosToVec(mDiff, to);
|
||||
vec3_sub(mDiff, mDiff, mStartPos);
|
||||
mXYDistance = sqrtf(mDiff[PX] * mDiff[PX] + mDiff[PY] * mDiff[PY]);
|
||||
mZDistance = fabsf(mDiff[PY]);
|
||||
mXYZDistance = sqrtf(mXYDistance * mXYDistance + mDiff[PZ] * mDiff[PZ]);
|
||||
mXYAngle = atan2f(mDiff[PY], mDiff[PX]);
|
||||
endmill = _endmill;
|
||||
mStartAngRad = mStepAngRad = 0;
|
||||
if (IsArcMotion(to)) {
|
||||
mMotionType = MTCurved;
|
||||
mRadius = sqrtf(to->j * to->j + to->i * to->i);
|
||||
mSmallRad = mRadius <= endmill->radius;
|
||||
|
||||
if (mSmallRad) {
|
||||
mStepAngRad = mSmallRadStep;
|
||||
}
|
||||
else {
|
||||
mStepAngRad = asinf(mResolution / mRadius);
|
||||
if (mStepAngRad > MAX_SEG_DEG) {
|
||||
mStepAngRad = MAX_SEG_DEG;
|
||||
}
|
||||
else if (mStepAngRad < NIN_SEG_DEG) {
|
||||
mStepAngRad = NIN_SEG_DEG;
|
||||
}
|
||||
}
|
||||
|
||||
MotionPosToVec(mCenter, from);
|
||||
mCenter[PX] += to->i;
|
||||
mCenter[PY] += to->j;
|
||||
mArcDir = to->cmd == eRotateCCW ? -1.f : 1.f;
|
||||
mStartAngRad = atan2f(mCenter[PX] - from->x, from->y - mCenter[PY]);
|
||||
float endAng = atan2f(mCenter[PX] - to->x, to->y - mCenter[PY]);
|
||||
mSweepAng = (mStartAngRad - endAng) * mArcDir;
|
||||
if (mSweepAng < EPSILON) {
|
||||
mSweepAng += PI * 2;
|
||||
}
|
||||
numSimSteps = (int)(mSweepAng / mStepAngRad) + 1;
|
||||
mStepAngRad = mArcDir * mSweepAng / numSimSteps;
|
||||
if (mSmallRad) {
|
||||
// when the radius is too small, we just use the tool itself to carve the stock
|
||||
mShape = endmill->toolShape;
|
||||
}
|
||||
else {
|
||||
endmill->GenerateArcSegmentDL(mRadius,
|
||||
mStepAngRad * SWEEP_ARC_PAD,
|
||||
mDiff[PZ] / numSimSteps,
|
||||
&mShape);
|
||||
numSimSteps++;
|
||||
}
|
||||
|
||||
isMultyPart = true;
|
||||
}
|
||||
else {
|
||||
numSimSteps = (int)(mXYZDistance / mResolution);
|
||||
if (numSimSteps == 0) {
|
||||
numSimSteps = 1;
|
||||
}
|
||||
isMultyPart = false;
|
||||
mStepDistance = mXYDistance / numSimSteps;
|
||||
mStepLength[PX] = mDiff[PX];
|
||||
mStepLength[PY] = mDiff[PY];
|
||||
mStepLength[PZ] = mDiff[PZ];
|
||||
vec3_scale(mStepLength, mStepLength, 1.f / (float)numSimSteps);
|
||||
|
||||
if (IsVerticalMotion(from, to)) {
|
||||
mMotionType = MTVertical;
|
||||
}
|
||||
else {
|
||||
mMotionType = MTHorizontal;
|
||||
mShearMat[0][2] = mDiff[PZ] / mXYDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MillPathSegment::~MillPathSegment()
|
||||
{
|
||||
mShape.FreeResources();
|
||||
}
|
||||
|
||||
|
||||
void MillPathSegment::render(int step)
|
||||
{
|
||||
mStepNumber = step;
|
||||
mat4x4 mat, mat2, rmat;
|
||||
mat4x4_identity(mat);
|
||||
mat4x4_identity(rmat);
|
||||
if (mMotionType == MTCurved) {
|
||||
mat4x4_translate_in_place(mat,
|
||||
mCenter[PX],
|
||||
mCenter[PY],
|
||||
mCenter[PZ] + mDiff[PZ] * (step - 1) / numSimSteps);
|
||||
mat4x4_rotate_Z(mat, mat, mStartAngRad - (step - 1) * mStepAngRad);
|
||||
mat4x4_rotate_Z(rmat, rmat, mStartAngRad - (step - 1) * mStepAngRad);
|
||||
|
||||
if (mSmallRad || step == numSimSteps) {
|
||||
mat4x4_translate_in_place(mat, 0, mRadius, 0);
|
||||
endmill->toolShape.Render(mat, rmat);
|
||||
}
|
||||
else {
|
||||
mShape.Render(mat, rmat);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (mMotionType == MTVertical) {
|
||||
if (mStepLength[PZ] > 0) {
|
||||
mat4x4_translate_in_place_v(mat, mStartPos);
|
||||
}
|
||||
else {
|
||||
mat4x4_translate_in_place(mat,
|
||||
mStartPos[PX],
|
||||
mStartPos[PY],
|
||||
mStartPos[PZ] + mStepNumber * mStepLength[PZ]);
|
||||
}
|
||||
endmill->toolShape.Render(mat, rmat);
|
||||
}
|
||||
else {
|
||||
float renderDist = step * mStepDistance;
|
||||
mat4x4_translate_in_place_v(mat, mStartPos);
|
||||
mat4x4_rotate_Z(mat, mat, mXYAngle);
|
||||
mat4x4_rotate_Z(rmat, rmat, mXYAngle);
|
||||
mat4x4_dup(mat2, mat);
|
||||
if (mDiff[PZ] != 0.0) {
|
||||
mat4x4_mul(mat2, mat2, mShearMat);
|
||||
}
|
||||
mat4x4_scale_aniso(mat2, mat2, renderDist, 1, 1);
|
||||
endmill->pathShape.Render(mat2, rmat);
|
||||
mat4x4_translate_in_place(mat, renderDist, 0, mDiff[PZ]);
|
||||
endmill->halfToolShape.Render(mat, rmat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MillPathSegment::GetHeadPosition(vec3 headPos)
|
||||
{
|
||||
if (mMotionType == MTCurved) {
|
||||
float angRad = mStartAngRad - mStepNumber * mStepAngRad;
|
||||
vec3_set(mHeadPos, -mRadius * sinf(angRad), mRadius * cosf(angRad), 0);
|
||||
vec3_add(mHeadPos, mHeadPos, mCenter);
|
||||
}
|
||||
else {
|
||||
vec3_dup(mHeadPos, mStepLength);
|
||||
vec3_scale(mHeadPos, mHeadPos, (float)mStepNumber);
|
||||
vec3_add(mHeadPos, mHeadPos, mStartPos);
|
||||
}
|
||||
vec3_dup(headPos, mHeadPos);
|
||||
}
|
||||
float MillPathSegment::SetQuality(float quality, float maxStockDimension)
|
||||
{
|
||||
mResolution = maxStockDimension * 0.05 / quality;
|
||||
if (mResolution > 4) {
|
||||
mResolution = 4;
|
||||
}
|
||||
if (mResolution < 0.5) {
|
||||
mResolution = 0.5;
|
||||
}
|
||||
mSmallRadStep = PI / 8;
|
||||
if (quality < 4) {
|
||||
mSmallRadStep = PI / 2;
|
||||
}
|
||||
else if (quality < 8) {
|
||||
mSmallRadStep = PI / 4;
|
||||
}
|
||||
return mResolution;
|
||||
}
|
||||
} // namespace MillSim
|
||||
98
src/Mod/CAM/PathSimulator/AppGL/MillPathSegment.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __mill_path_segment_h__
|
||||
#define __mill_path_segment_h__
|
||||
|
||||
|
||||
#include "MillMotion.h"
|
||||
#include "EndMill.h"
|
||||
#include "linmath.h"
|
||||
|
||||
namespace MillSim
|
||||
{
|
||||
|
||||
enum MotionType
|
||||
{
|
||||
MTVertical = 0,
|
||||
MTHorizontal,
|
||||
MTCurved
|
||||
};
|
||||
|
||||
|
||||
bool IsVerticalMotion(MillMotion* m1, MillMotion* m2);
|
||||
|
||||
|
||||
class MillPathSegment
|
||||
{
|
||||
public:
|
||||
/// <summary>
|
||||
/// Create a mill path segment primitive
|
||||
/// </summary>
|
||||
/// <param name="endmill">Mill object</param>
|
||||
/// <param name="from">Start point</param>
|
||||
/// <param name="to">End point</param>
|
||||
MillPathSegment(EndMill* endmill, MillMotion* from, MillMotion* to);
|
||||
virtual ~MillPathSegment();
|
||||
|
||||
|
||||
/// Calls the display list.
|
||||
virtual void render(int substep);
|
||||
virtual void GetHeadPosition(vec3 headPos);
|
||||
static float SetQuality(float quality, float maxStockDimension); // 1 minimum, 10 maximum
|
||||
|
||||
public:
|
||||
EndMill* endmill = nullptr;
|
||||
bool isMultyPart;
|
||||
int numSimSteps;
|
||||
int indexInArray;
|
||||
|
||||
|
||||
protected:
|
||||
mat4x4 mShearMat;
|
||||
Shape mShape;
|
||||
float mXYDistance;
|
||||
float mXYZDistance;
|
||||
float mZDistance;
|
||||
float mXYAngle;
|
||||
float mStartAngRad;
|
||||
float mStepAngRad;
|
||||
float mStepDistance = 0;
|
||||
float mSweepAng;
|
||||
float mRadius = 0;
|
||||
float mArcDir = 0;
|
||||
bool mSmallRad = false;
|
||||
int mStepNumber = 0;
|
||||
|
||||
static float mSmallRadStep;
|
||||
static float mResolution;
|
||||
|
||||
vec3 mDiff;
|
||||
vec3 mStepLength = {0};
|
||||
vec3 mCenter = {0};
|
||||
vec3 mStartPos;
|
||||
vec3 mHeadPos = {0};
|
||||
MotionType mMotionType;
|
||||
};
|
||||
} // namespace MillSim
|
||||
|
||||
#endif
|
||||
601
src/Mod/CAM/PathSimulator/AppGL/MillSimulation.cpp
Normal file
@@ -0,0 +1,601 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "MillSimulation.h"
|
||||
#include "OpenGlWrapper.h"
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
namespace MillSim {
|
||||
|
||||
MillSimulation::MillSimulation()
|
||||
{
|
||||
mCurMotion = { eNop, -1, 0, 0, 0, 0, 0, 0 };
|
||||
guiDisplay.SetMillSimulator(this);
|
||||
}
|
||||
|
||||
void MillSimulation::ClearMillPathSegments() {
|
||||
//for (std::vector<MillPathSegment*>::const_iterator i = MillPathSegments.begin(); i != MillPathSegments.end(); ++i) {
|
||||
// MillSim::MillPathSegment* p = *i;
|
||||
// delete p;
|
||||
//}
|
||||
for (int i = 0; i < MillPathSegments.size(); i++)
|
||||
delete MillPathSegments[i];
|
||||
MillPathSegments.clear();
|
||||
}
|
||||
|
||||
void MillSimulation::Clear()
|
||||
{
|
||||
mCodeParser.Operations.clear();
|
||||
for (int i = 0; i < mToolTable.size(); i++)
|
||||
delete mToolTable[i];
|
||||
mToolTable.clear();
|
||||
mCurStep = 0;
|
||||
mPathStep = -1;
|
||||
mNTotalSteps = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MillSimulation::SimNext()
|
||||
{
|
||||
static int simDecim = 0;
|
||||
|
||||
simDecim++;
|
||||
if (simDecim < 1)
|
||||
return;
|
||||
|
||||
simDecim = 0;
|
||||
|
||||
if (mCurStep < mNTotalSteps)
|
||||
{
|
||||
mCurStep += mSimSpeed;
|
||||
CalcSegmentPositions();
|
||||
}
|
||||
}
|
||||
|
||||
void MillSimulation::InitSimulation(float quality)
|
||||
{
|
||||
ClearMillPathSegments();
|
||||
|
||||
mDestMotion = mZeroPos;
|
||||
//gDestPos = curMillOperation->startPos;
|
||||
mCurStep = 0;
|
||||
mPathStep = -1;
|
||||
mNTotalSteps = 0;
|
||||
MillPathSegment::SetQuality(quality, mMaxFar);
|
||||
int nOperations = (int)mCodeParser.Operations.size();;
|
||||
for (int i = 0; i < nOperations; i++)
|
||||
{
|
||||
mCurMotion = mDestMotion;
|
||||
mDestMotion = mCodeParser.Operations[i];
|
||||
EndMill* tool = GetTool(mDestMotion.tool);
|
||||
if (tool != nullptr)
|
||||
{
|
||||
MillSim::MillPathSegment* segment = new MillSim::MillPathSegment(tool, &mCurMotion, &mDestMotion);
|
||||
segment->indexInArray = i;
|
||||
mNTotalSteps += segment->numSimSteps;
|
||||
MillPathSegments.push_back(segment);
|
||||
}
|
||||
}
|
||||
mNPathSteps = (int)MillPathSegments.size();
|
||||
InitDisplay(quality);
|
||||
}
|
||||
|
||||
EndMill* MillSimulation::GetTool(int toolId)
|
||||
{
|
||||
for (int i = 0; i < mToolTable.size(); i++)
|
||||
{
|
||||
if (mToolTable[i]->toolId == toolId)
|
||||
{
|
||||
return mToolTable[i];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void MillSimulation::RemoveTool(int toolId)
|
||||
{
|
||||
EndMill* tool;
|
||||
if ((tool = GetTool(toolId)) != nullptr) {
|
||||
auto it = std::find(mToolTable.begin(), mToolTable.end(), tool);
|
||||
if (it != mToolTable.end()) {
|
||||
mToolTable.erase(it);
|
||||
}
|
||||
delete tool;
|
||||
}
|
||||
}
|
||||
|
||||
void MillSimulation::AddTool(EndMill* tool)
|
||||
{
|
||||
// if we have another tool with same id, remove it
|
||||
RemoveTool(tool->toolId);
|
||||
mToolTable.push_back(tool);
|
||||
}
|
||||
|
||||
void
|
||||
MillSimulation::AddTool(const std::vector<float>& toolProfile, int toolid, float diameter)
|
||||
{
|
||||
// if we have another tool with same id, remove it
|
||||
RemoveTool(toolid);
|
||||
EndMill* tool = new EndMill(toolProfile, toolid, diameter);
|
||||
mToolTable.push_back(tool);
|
||||
}
|
||||
|
||||
void MillSimulation::GlsimStart()
|
||||
{
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
||||
}
|
||||
|
||||
void MillSimulation::GlsimToolStep1(void)
|
||||
{
|
||||
glCullFace(GL_BACK);
|
||||
glDepthFunc(GL_LESS);
|
||||
glStencilFunc(GL_ALWAYS, 1, 0xFF);
|
||||
glStencilOp(GL_ZERO, GL_ZERO, GL_REPLACE);
|
||||
glDepthMask(GL_FALSE);
|
||||
}
|
||||
|
||||
|
||||
void MillSimulation::GlsimToolStep2(void)
|
||||
{
|
||||
glStencilFunc(GL_EQUAL, 1, 0xFF);
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
||||
glDepthFunc(GL_GREATER);
|
||||
glCullFace(GL_FRONT);
|
||||
glDepthMask(GL_TRUE);
|
||||
}
|
||||
|
||||
void MillSimulation::GlsimClipBack(void)
|
||||
{
|
||||
glStencilFunc(GL_ALWAYS, 1, 0xFF);
|
||||
glStencilOp(GL_REPLACE, GL_REPLACE, GL_ZERO);
|
||||
glDepthFunc(GL_LESS);
|
||||
glCullFace(GL_FRONT);
|
||||
glDepthMask(GL_FALSE);
|
||||
}
|
||||
|
||||
|
||||
void MillSimulation::GlsimRenderStock(void)
|
||||
{
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
glStencilFunc(GL_EQUAL, 1, 0xFF);
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
||||
glDepthFunc(GL_EQUAL);
|
||||
glCullFace(GL_BACK);
|
||||
}
|
||||
|
||||
void MillSimulation::GlsimRenderTools(void)
|
||||
{
|
||||
glCullFace(GL_FRONT);
|
||||
}
|
||||
|
||||
void MillSimulation::GlsimEnd(void)
|
||||
{
|
||||
glCullFace(GL_BACK);
|
||||
glStencilFunc(GL_ALWAYS, 1, 0xFF);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
glDepthMask(GL_TRUE);
|
||||
glDepthFunc(GL_LESS);
|
||||
}
|
||||
|
||||
void MillSimulation::renderSegmentForward(int iSeg)
|
||||
{
|
||||
MillSim::MillPathSegment* p = MillPathSegments.at(iSeg);
|
||||
int step = iSeg == mPathStep ? mSubStep : p->numSimSteps;
|
||||
int start = p->isMultyPart ? 1 : step;
|
||||
for (int i = start; i <= step; i++)
|
||||
{
|
||||
GlsimToolStep1();
|
||||
p->render(i);
|
||||
GlsimToolStep2();
|
||||
p->render(i);
|
||||
}
|
||||
}
|
||||
|
||||
void MillSimulation::renderSegmentReversed(int iSeg)
|
||||
{
|
||||
MillSim::MillPathSegment* p = MillPathSegments.at(iSeg);
|
||||
int step = iSeg == mPathStep ? mSubStep : p->numSimSteps;
|
||||
int end = p->isMultyPart ? 1 : step;
|
||||
for (int i = step; i >= end; i--)
|
||||
{
|
||||
GlsimToolStep1();
|
||||
p->render(i);
|
||||
GlsimToolStep2();
|
||||
p->render(i);
|
||||
}
|
||||
}
|
||||
|
||||
void MillSimulation::CalcSegmentPositions()
|
||||
{
|
||||
mSubStep = mCurStep;
|
||||
for (mPathStep = 0; mPathStep < mNPathSteps; mPathStep++)
|
||||
{
|
||||
MillSim::MillPathSegment* p = MillPathSegments[mPathStep];
|
||||
if (mSubStep < p->numSimSteps)
|
||||
break;
|
||||
mSubStep -= p->numSimSteps;
|
||||
}
|
||||
if (mPathStep >= mNPathSteps)
|
||||
{
|
||||
mPathStep = mNPathSteps - 1;
|
||||
mSubStep = MillPathSegments[mPathStep]->numSimSteps;
|
||||
}
|
||||
else
|
||||
mSubStep++;
|
||||
}
|
||||
|
||||
void MillSimulation::Render()
|
||||
{
|
||||
mat4x4 matLookAt, model;
|
||||
mat4x4_identity(model);
|
||||
mat4x4_look_at(matLookAt, eye, target, upvec);
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
mat4x4_translate_in_place(matLookAt, mEyeX * mEyeXZFactor, 0, mEyeZ * mEyeXZFactor);
|
||||
mat4x4_rotate_X(matLookAt, matLookAt, mEyeInclination);
|
||||
mat4x4_rotate_Z(matLookAt, matLookAt, mEyeRoration);
|
||||
mat4x4_translate_in_place(matLookAt, -mStockObject.center[0], -mStockObject.center[1], -mStockObject.center[2]);
|
||||
|
||||
shaderFlat.Activate();
|
||||
shaderFlat.UpdateViewMat(matLookAt);
|
||||
|
||||
GlsimStart();
|
||||
mStockObject.render();
|
||||
|
||||
GlsimToolStep2();
|
||||
|
||||
for (int i = 0; i <= mPathStep; i++)
|
||||
renderSegmentForward(i);
|
||||
|
||||
for (int i = mPathStep; i >= 0; i--)
|
||||
renderSegmentForward(i);
|
||||
|
||||
for (int i = 0; i < mPathStep; i++)
|
||||
renderSegmentReversed(i);
|
||||
|
||||
for (int i = mPathStep; i >= 0; i--)
|
||||
renderSegmentReversed(i);
|
||||
|
||||
GlsimClipBack();
|
||||
mStockObject.render();
|
||||
|
||||
// start coloring
|
||||
shader3D.Activate();
|
||||
shader3D.UpdateViewMat(matLookAt);
|
||||
shader3D.UpdateObjColor(stockColor);
|
||||
GlsimRenderStock();
|
||||
mStockObject.render();
|
||||
GlsimRenderTools();
|
||||
|
||||
// render cuts (back faces of tools)
|
||||
|
||||
shaderInv3D.Activate();
|
||||
shaderInv3D.UpdateViewMat(matLookAt);
|
||||
shaderInv3D.UpdateObjColor(cutColor);
|
||||
for (int i = 0; i <= mPathStep; i++)
|
||||
{
|
||||
MillSim::MillPathSegment* p = MillPathSegments.at(i);
|
||||
int step = (i == mPathStep) ? mSubStep : p->numSimSteps;
|
||||
int start = p->isMultyPart ? 1 : step;
|
||||
for (int j = start; j <= step; j++)
|
||||
MillPathSegments.at(i)->render(j);
|
||||
}
|
||||
|
||||
GlsimEnd();
|
||||
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
if (mPathStep >= 0)
|
||||
{
|
||||
vec3 toolPos;
|
||||
MotionPosToVec(toolPos, &mDestMotion);
|
||||
MillSim::MillPathSegment* p = MillPathSegments.at(mPathStep);
|
||||
p->GetHeadPosition(toolPos);
|
||||
mat4x4 tmat;
|
||||
mat4x4_translate(tmat, toolPos[0], toolPos[1], toolPos[2]);
|
||||
//mat4x4_translate(tmat, toolPos.x, toolPos.y, toolPos.z);
|
||||
shader3D.Activate();
|
||||
shader3D.UpdateObjColor(toolColor);
|
||||
p->endmill->toolShape.Render(tmat, identityMat);
|
||||
}
|
||||
|
||||
shaderFlat.Activate();
|
||||
shaderFlat.UpdateObjColor(lightColor);
|
||||
mlightObject.render();
|
||||
|
||||
if (mDebug > 0)
|
||||
{
|
||||
mat4x4 test;
|
||||
mat4x4_dup(test, model);
|
||||
mat4x4_translate_in_place(test, 20, 20, 3);
|
||||
mat4x4_rotate_Z(test, test, 30.f * 3.14f / 180.f);
|
||||
int dpos = mNPathSteps - mDebug2;
|
||||
MillSim::MillPathSegment* p = MillPathSegments.at(dpos);
|
||||
if (mDebug > p->numSimSteps)
|
||||
mDebug = 1;
|
||||
p->render(mDebug);
|
||||
}
|
||||
float progress = (float)mCurStep / mNTotalSteps;
|
||||
guiDisplay.Render(progress);
|
||||
}
|
||||
|
||||
void MillSimulation::ProcessSim(unsigned int time_ms) {
|
||||
|
||||
static int ancient = 0;
|
||||
static int last = 0;
|
||||
static int msec = 0;
|
||||
static int fps = 0;
|
||||
static int renderTime = 0;
|
||||
|
||||
last = msec;
|
||||
msec = time_ms;
|
||||
if (mIsRotate) {
|
||||
mEyeRoration += (msec - last) / 4600.0f;
|
||||
while (mEyeRoration >= PI2)
|
||||
mEyeRoration -= PI2;
|
||||
}
|
||||
|
||||
if (last / 1000 != msec / 1000) {
|
||||
float calcFps = 1000.0f * fps / (msec - ancient);
|
||||
mFpsStream.str("");
|
||||
mFpsStream << "fps: " << calcFps << " rendertime:" << renderTime << " zpos:" << mDestMotion.z << std::ends;
|
||||
ancient = msec;
|
||||
fps = 0;
|
||||
}
|
||||
|
||||
if (mSimPlaying || mSingleStep)
|
||||
{
|
||||
SimNext();
|
||||
mSingleStep = false;
|
||||
}
|
||||
|
||||
Render();
|
||||
|
||||
++fps;
|
||||
}
|
||||
|
||||
void MillSimulation::HandleKeyPress(int key)
|
||||
{
|
||||
switch (key) {
|
||||
case ' ':
|
||||
mIsRotate = !mIsRotate;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
mSimPlaying = true;
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
mSimPlaying = false;
|
||||
break;
|
||||
|
||||
case 'T':
|
||||
mSimPlaying = false;
|
||||
mSingleStep = true;
|
||||
break;
|
||||
|
||||
case'D':
|
||||
mDebug++;
|
||||
break;
|
||||
|
||||
case'K':
|
||||
mDebug2++;
|
||||
gDebug = mNPathSteps - mDebug2;
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
if (mSimSpeed == 1) mSimSpeed = 10;
|
||||
else if (mSimSpeed == 10) mSimSpeed = 40;
|
||||
else mSimSpeed = 1;
|
||||
guiDisplay.UpdateSimSpeed(mSimSpeed);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (key >= '1' && key <= '9')
|
||||
mSimSpeed = key - '0';
|
||||
break;
|
||||
}
|
||||
guiDisplay.UpdatePlayState(mSimPlaying);
|
||||
}
|
||||
|
||||
void MillSimulation::UpdateEyeFactor(float factor)
|
||||
{
|
||||
mEyeDistFactor = factor;
|
||||
mEyeXZFactor = factor * mMaxFar * 0.005f;
|
||||
eye[1] = -factor * mMaxFar;
|
||||
}
|
||||
|
||||
void MillSimulation::TiltEye(float tiltStep)
|
||||
{
|
||||
mEyeInclination += tiltStep;
|
||||
if (mEyeInclination > PI / 2)
|
||||
mEyeInclination = PI / 2;
|
||||
else if (mEyeInclination < -PI / 2)
|
||||
mEyeInclination = -PI / 2;
|
||||
}
|
||||
|
||||
void MillSimulation::RotateEye(float rotStep)
|
||||
{
|
||||
mEyeRoration += rotStep;
|
||||
if (mEyeRoration > PI2)
|
||||
mEyeRoration = PI2;
|
||||
else if (mEyeRoration < 0)
|
||||
mEyeRoration = 0;
|
||||
}
|
||||
|
||||
void MillSimulation::MoveEye(float x, float z)
|
||||
{
|
||||
mEyeX += x;
|
||||
if (mEyeX > 100) mEyeX = 100;
|
||||
else if (mEyeX < -100) mEyeX = -100;
|
||||
mEyeZ += z;
|
||||
if (mEyeZ > 100) mEyeZ = 100;
|
||||
else if (mEyeZ < -100) mEyeZ = -100;
|
||||
}
|
||||
|
||||
void MillSimulation::UpdateProjection()
|
||||
{
|
||||
// Setup projection
|
||||
mat4x4 projmat;
|
||||
mat4x4_perspective(projmat, 0.7f, 4.0f / 3.0f, 1.0f, mMaxFar);
|
||||
//mat4x4_perspective(projmat, 0.7f, 4.0f / 3.0f, 1, 100);
|
||||
shader3D.Activate();
|
||||
shader3D.UpdateProjectionMat(projmat);
|
||||
shaderInv3D.Activate();
|
||||
shaderInv3D.UpdateProjectionMat(projmat);
|
||||
shaderFlat.Activate();
|
||||
shaderFlat.UpdateProjectionMat(projmat);
|
||||
}
|
||||
|
||||
void MillSimulation::InitDisplay(float quality)
|
||||
{
|
||||
// gray background
|
||||
glClearColor(0.6f, 0.8f, 1.0f, 1.0f);
|
||||
|
||||
|
||||
// use shaders
|
||||
// standard diffuse shader
|
||||
shader3D.CompileShader((char*)VertShader3DNorm, (char*)FragShaderNorm);
|
||||
shader3D.UpdateEnvColor(lightPos, lightColor, ambientCol);
|
||||
|
||||
// invarted normal diffuse shader for inner mesh
|
||||
shaderInv3D.CompileShader((char*)VertShader3DInvNorm, (char*)FragShaderNorm);
|
||||
shaderInv3D.UpdateEnvColor(lightPos, lightColor, ambientCol);
|
||||
|
||||
// null shader to calculate meshes only (simulation stage)
|
||||
shaderFlat.CompileShader((char*)VertShader3DNorm, (char*)FragShaderFlat);
|
||||
UpdateProjection();
|
||||
|
||||
// setup light object and generate tools
|
||||
mlightObject.GenerateBoxStock(-0.5f, -0.5f, -0.5f, 1, 1, 1);
|
||||
for (int i = 0; i < mToolTable.size(); i++)
|
||||
mToolTable[i]->GenerateDisplayLists(quality);
|
||||
|
||||
// init gui elements
|
||||
guiDisplay.InutGui();
|
||||
|
||||
}
|
||||
|
||||
void MillSimulation::SetBoxStock(float x, float y, float z, float l, float w, float h)
|
||||
{
|
||||
mStockObject.GenerateBoxStock(x, y, z, l, w, h);
|
||||
mMaxStockDim = fmaxf(w, l);
|
||||
mMaxFar = mMaxStockDim * 4;
|
||||
UpdateProjection();
|
||||
vec3_set(eye, 0, 0, 0);
|
||||
UpdateEyeFactor(0.4f);
|
||||
vec3_set(lightPos, x, y, h + mMaxStockDim / 3);
|
||||
mlightObject.SetPosition(lightPos);
|
||||
}
|
||||
|
||||
void MillSimulation::MouseDrag(int buttons, int dx, int dy)
|
||||
{
|
||||
if (buttons == (MS_MOUSE_MID | MS_MOUSE_LEFT))
|
||||
{
|
||||
TiltEye((float)dy / 100.0f);
|
||||
RotateEye((float)dx / 100.0f);
|
||||
}
|
||||
else if (buttons == MS_MOUSE_MID)
|
||||
{
|
||||
MoveEye(dx, -dy);
|
||||
}
|
||||
guiDisplay.MouseDrag(buttons, dx, dy);
|
||||
}
|
||||
|
||||
void MillSimulation::MouseMove(int px, int py)
|
||||
{
|
||||
if (mMouseButtonState > 0)
|
||||
{
|
||||
int dx = px - mLastMouseX;
|
||||
int dy = py - mLastMouseY;
|
||||
if (dx != 0 || dy != 0)
|
||||
{
|
||||
MouseDrag(mMouseButtonState, dx, dy);
|
||||
mLastMouseX = px;
|
||||
mLastMouseY = py;
|
||||
}
|
||||
}
|
||||
else
|
||||
MouseHover(px, py);
|
||||
}
|
||||
|
||||
void MillSimulation::MouseScroll(float dy)
|
||||
{
|
||||
float f = mEyeDistFactor;
|
||||
f += 0.05f * dy;
|
||||
if (f > 0.6f) f = 0.6f;
|
||||
else if (f < 0.05f) f = 0.05f;
|
||||
UpdateEyeFactor(f);
|
||||
}
|
||||
|
||||
|
||||
void MillSimulation::MouseHover(int px, int py)
|
||||
{
|
||||
guiDisplay.MouseCursorPos(px, py);
|
||||
}
|
||||
|
||||
void MillSimulation::MousePress(int button, bool isPressed, int px, int py)
|
||||
{
|
||||
if (isPressed)
|
||||
mMouseButtonState |= button;
|
||||
else
|
||||
mMouseButtonState &= ~button;
|
||||
|
||||
if (mMouseButtonState > 0)
|
||||
{
|
||||
mLastMouseX = px;
|
||||
mLastMouseY = py;
|
||||
}
|
||||
guiDisplay.MousePressed(button, isPressed, mSimPlaying);
|
||||
}
|
||||
|
||||
|
||||
bool MillSimulation::LoadGCodeFile(const char* fileName)
|
||||
{
|
||||
if (mCodeParser.Parse(fileName))
|
||||
{
|
||||
std::cout << "GCode file loaded successfuly" << std::endl;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MillSimulation::AddGcodeLine(const char* line)
|
||||
{
|
||||
return mCodeParser.AddLine(line);
|
||||
}
|
||||
|
||||
void MillSimulation::SetSimulationStage(float stage)
|
||||
{
|
||||
mCurStep = (int)((float)mNTotalSteps * stage);
|
||||
CalcSegmentPositions();
|
||||
}
|
||||
|
||||
}
|
||||
149
src/Mod/CAM/PathSimulator/AppGL/MillSimulation.h
Normal file
@@ -0,0 +1,149 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __millsimulation__h__
|
||||
#define __millsimulation__h__
|
||||
|
||||
#include "MillMotion.h"
|
||||
#include "GCodeParser.h"
|
||||
#include "Shader.h"
|
||||
#include "linmath.h"
|
||||
#include "GlUtils.h"
|
||||
#include "StockObject.h"
|
||||
#include "MillPathSegment.h"
|
||||
#include "GuiDisplay.h"
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
namespace MillSim
|
||||
{
|
||||
|
||||
class MillSimulation
|
||||
{
|
||||
public:
|
||||
MillSimulation();
|
||||
void ClearMillPathSegments();
|
||||
void Clear();
|
||||
void SimNext();
|
||||
void InitSimulation(float quality);
|
||||
void AddTool(EndMill* tool);
|
||||
void AddTool(const std::vector<float>& toolProfile, int toolid, float diameter);
|
||||
bool ToolExists(int toolid)
|
||||
{
|
||||
return GetTool(toolid) != nullptr;
|
||||
}
|
||||
void Render();
|
||||
void ProcessSim(unsigned int time_ms);
|
||||
void HandleKeyPress(int key);
|
||||
void UpdateEyeFactor(float factor);
|
||||
void TiltEye(float tiltStep);
|
||||
void RotateEye(float rotStep);
|
||||
void MoveEye(float x, float y);
|
||||
void UpdateProjection();
|
||||
bool LoadGCodeFile(const char* fileName);
|
||||
bool AddGcodeLine(const char* line);
|
||||
void SetSimulationStage(float stage);
|
||||
void SetBoxStock(float x, float y, float z, float l, float w, float h);
|
||||
void MouseDrag(int buttons, int dx, int dy);
|
||||
void MouseMove(int px, int py);
|
||||
void MouseScroll(float dy);
|
||||
void MouseHover(int px, int py);
|
||||
void MousePress(int button, bool isPressed, int px, int py);
|
||||
|
||||
|
||||
protected:
|
||||
void InitDisplay(float quality);
|
||||
void GlsimStart();
|
||||
void GlsimToolStep1(void);
|
||||
void GlsimToolStep2(void);
|
||||
void GlsimClipBack(void);
|
||||
void GlsimRenderStock(void);
|
||||
void GlsimRenderTools(void);
|
||||
void GlsimEnd(void);
|
||||
void renderSegmentForward(int iSeg);
|
||||
void renderSegmentReversed(int iSeg);
|
||||
void CalcSegmentPositions();
|
||||
EndMill* GetTool(int tool);
|
||||
void RemoveTool(int toolId);
|
||||
|
||||
|
||||
protected:
|
||||
std::vector<EndMill*> mToolTable;
|
||||
Shader shader3D, shaderInv3D, shaderFlat;
|
||||
GCodeParser mCodeParser;
|
||||
GuiDisplay guiDisplay;
|
||||
std::vector<MillPathSegment*> MillPathSegments;
|
||||
std::ostringstream mFpsStream;
|
||||
|
||||
MillMotion mZeroPos = {eNop, -1, 0, 0, 100, 0, 0, 0};
|
||||
MillMotion mCurMotion = {eNop, -1, 0, 0, 0, 0, 0, 0};
|
||||
MillMotion mDestMotion = {eNop, -1, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
StockObject mStockObject;
|
||||
StockObject mlightObject;
|
||||
|
||||
vec3 lightColor = {0.8f, 0.9f, 1.0f};
|
||||
vec3 lightPos = {20.0f, 20.0f, 10.0f};
|
||||
vec3 ambientCol = {0.3f, 0.3f, 0.5f};
|
||||
|
||||
vec3 eye = {0, 100, 40};
|
||||
vec3 target = {0, 0, -10};
|
||||
vec3 upvec = {0, 0, 1};
|
||||
|
||||
vec3 stockColor = {0.7f, 0.7f, 0.7f};
|
||||
vec3 cutColor = {0.4f, 0.7f, 0.4f};
|
||||
vec3 toolColor = {0.4f, 0.4f, 0.7f};
|
||||
|
||||
float mEyeDistance = 30;
|
||||
float mEyeRoration = 0;
|
||||
float mEyeInclination = PI / 6; // 30 degree
|
||||
float mEyeStep = PI / 36; // 5 degree
|
||||
|
||||
float mMaxStockDim = 100;
|
||||
float mMaxFar = 100;
|
||||
float mEyeDistFactor = 0.4f;
|
||||
float mEyeXZFactor = 0.01f;
|
||||
float mEyeXZScale = 0;
|
||||
float mEyeX = 0.0f;
|
||||
float mEyeZ = 0.0f;
|
||||
|
||||
|
||||
int mCurStep = 0;
|
||||
int mNTotalSteps = 0;
|
||||
int mPathStep = 0;
|
||||
int mSubStep = 0;
|
||||
int mNPathSteps = 0;
|
||||
int mDebug = 0;
|
||||
int mDebug1 = 0;
|
||||
int mDebug2 = 12;
|
||||
int mSimSpeed = 1;
|
||||
|
||||
int mLastMouseX = 0, mLastMouseY = 0;
|
||||
int mMouseButtonState = 0;
|
||||
|
||||
bool mIsInStock = false;
|
||||
bool mIsRotate = true;
|
||||
bool mSimPlaying = false;
|
||||
bool mSingleStep = false;
|
||||
};
|
||||
} // namespace MillSim
|
||||
#endif
|
||||
71
src/Mod/CAM/PathSimulator/AppGL/OpenGlWrapper.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __openglwrapper_h__
|
||||
#define __openglwrapper_h__
|
||||
#ifdef CAM_SIM_USE_GLEW
|
||||
#include "GL/glew.h"
|
||||
#else
|
||||
#include "DlgCAMSimulator.h"
|
||||
extern QOpenGLContext* gOpenGlContext;
|
||||
#define gSimWindow CAMSimulator::DlgCAMSimulator::GetInstance()
|
||||
#define glGenBuffers gSimWindow->glGenBuffers
|
||||
#define glBindBuffer gSimWindow->glBindBuffer
|
||||
#define glBufferData gSimWindow->glBufferData
|
||||
#define glGenVertexArrays gSimWindow->glGenVertexArrays
|
||||
#define glBindVertexArray gSimWindow->glBindVertexArray
|
||||
#define glEnableVertexAttribArray gSimWindow->glEnableVertexAttribArray
|
||||
#define glVertexAttribPointer gSimWindow->glVertexAttribPointer
|
||||
#define glShaderSource gSimWindow->glShaderSource
|
||||
#define glCompileShader gSimWindow->glCompileShader
|
||||
#define glAttachShader gSimWindow->glAttachShader
|
||||
#define glLinkProgram gSimWindow->glLinkProgram
|
||||
#define glGetProgramiv gSimWindow->glGetProgramiv
|
||||
#define glGetUniformLocation gSimWindow->glGetUniformLocation
|
||||
#define glGetError gSimWindow->glGetError
|
||||
#define glEnable gSimWindow->glEnable
|
||||
#define glColorMask gSimWindow->glColorMask
|
||||
#define glCullFace gSimWindow->glCullFace
|
||||
#define glDepthFunc gSimWindow->glDepthFunc
|
||||
#define glStencilFunc gSimWindow->glStencilFunc
|
||||
#define glStencilOp gSimWindow->glStencilOp
|
||||
#define glDepthMask gSimWindow->glDepthMask
|
||||
#define glDisable gSimWindow->glDisable
|
||||
#define glMatrixMode gSimWindow->glMatrixMode
|
||||
#define glUseProgram gSimWindow->glUseProgram
|
||||
#define glDrawElements gSimWindow->glDrawElements
|
||||
#define glDeleteVertexArrays gSimWindow->glDeleteVertexArrays
|
||||
#define glUniformMatrix4fv gSimWindow->glUniformMatrix4fv
|
||||
#define glUniform3fv gSimWindow->glUniform3fv
|
||||
#define glUniform1i gSimWindow->glUniform1i
|
||||
#define glCreateShader gSimWindow->glCreateShader
|
||||
#define glCreateProgram gSimWindow->glCreateProgram
|
||||
#define glDeleteBuffers gSimWindow->glDeleteBuffers
|
||||
#define glActiveTexture gSimWindow->glActiveTexture
|
||||
#define glBindTexture gSimWindow->glBindTexture
|
||||
#define glGenTextures gSimWindow->glGenTextures
|
||||
#define glTexParameteri gSimWindow->glTexParameteri
|
||||
#define glTexImage2D gSimWindow->glTexImage2D
|
||||
#define glDeleteTextures gSimWindow->glDeleteTextures
|
||||
#endif // HAVE_OPENGL_EXT
|
||||
|
||||
#endif // !__openglwrapper_h__
|
||||
23
src/Mod/CAM/PathSimulator/AppGL/PreCompiled.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2017 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
56
src/Mod/CAM/PathSimulator/AppGL/PreCompiled.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2017 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef APP_PRECOMPILED_H
|
||||
#define APP_PRECOMPILED_H
|
||||
|
||||
#include <FCConfig.h>
|
||||
|
||||
#ifdef _PreComp_
|
||||
|
||||
// standard
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
// STL
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// Boost
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
// Xerces
|
||||
#include <xercesc/util/XercesDefs.hpp>
|
||||
|
||||
#endif //_PreComp_
|
||||
|
||||
#endif
|
||||
|
||||
272
src/Mod/CAM/PathSimulator/AppGL/Shader.cpp
Normal file
@@ -0,0 +1,272 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "GlUtils.h"
|
||||
#include "Shader.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace MillSim
|
||||
{
|
||||
|
||||
Shader* CurrentShader = nullptr;
|
||||
|
||||
void Shader::UpdateModelMat(mat4x4 tmat, mat4x4 nmat)
|
||||
{
|
||||
if (mModelPos >= 0) {
|
||||
glUniformMatrix4fv(mModelPos, 1, GL_FALSE, (GLfloat*)tmat);
|
||||
}
|
||||
if (mNormalRotPos >= 0) {
|
||||
glUniformMatrix4fv(mNormalRotPos, 1, GL_FALSE, (GLfloat*)nmat);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::UpdateProjectionMat(mat4x4 mat)
|
||||
{
|
||||
if (mProjectionPos >= 0) {
|
||||
glUniformMatrix4fv(mProjectionPos, 1, GL_FALSE, (GLfloat*)mat);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::UpdateViewMat(mat4x4 mat)
|
||||
{
|
||||
if (mViewPos >= 0) {
|
||||
if (mViewPos >= 0) {
|
||||
glUniformMatrix4fv(mViewPos, 1, GL_FALSE, (GLfloat*)mat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::UpdateEnvColor(vec3 lightPos, vec3 lightColor, vec3 ambient)
|
||||
{
|
||||
if (mLightPosPos >= 0) {
|
||||
glUniform3fv(mLightPosPos, 1, lightPos);
|
||||
}
|
||||
if (mLightColorPos >= 0) {
|
||||
glUniform3fv(mLightColorPos, 1, lightColor);
|
||||
}
|
||||
if (mAmbientPos >= 0) {
|
||||
glUniform3fv(mAmbientPos, 1, ambient);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::UpdateObjColor(vec3 objColor)
|
||||
{
|
||||
if (mObjectColorPos >= 0) {
|
||||
glUniform3fv(mObjectColorPos, 1, objColor);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::UpdateTextureSlot(int slot)
|
||||
{
|
||||
if (mTexSlotPos >= 0) {
|
||||
glUniform1i(mTexSlotPos, slot);
|
||||
}
|
||||
}
|
||||
|
||||
bool CheckCompileResult(int shader)
|
||||
{
|
||||
#ifdef QT_OPENGL_LIB
|
||||
return false;
|
||||
#else
|
||||
char log[1024];
|
||||
int res = 0;
|
||||
GLsizei len;
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &res);
|
||||
if (res != 0) {
|
||||
return false;
|
||||
}
|
||||
glGetShaderInfoLog(shader, 1020, &len, log);
|
||||
if (len > 1020) {
|
||||
len = 1020;
|
||||
}
|
||||
log[len] = 0;
|
||||
std::cout << log << std::endl;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned int Shader::CompileShader(char* _vertShader, char* _fragShader)
|
||||
{
|
||||
vertShader = _vertShader;
|
||||
fragShader = _fragShader;
|
||||
const GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
|
||||
GLint res = 0;
|
||||
glShaderSource(vertex_shader, 1, &vertShader, NULL);
|
||||
glCompileShader(vertex_shader);
|
||||
if (CheckCompileResult(vertex_shader)) {
|
||||
return 0xdeadbeef;
|
||||
}
|
||||
|
||||
const GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(fragment_shader, 1, &fragShader, NULL);
|
||||
glCompileShader(fragment_shader);
|
||||
if (CheckCompileResult(fragment_shader)) {
|
||||
return 0xdeadbeef;
|
||||
}
|
||||
|
||||
shaderId = glCreateProgram();
|
||||
glAttachShader(shaderId, vertex_shader);
|
||||
glAttachShader(shaderId, fragment_shader);
|
||||
glLinkProgram(shaderId);
|
||||
|
||||
glGetProgramiv(shaderId, GL_LINK_STATUS, &res);
|
||||
if (res == 0) {
|
||||
return 0xdeadbeef;
|
||||
}
|
||||
|
||||
// get all uniform parameters positions
|
||||
mModelPos = glGetUniformLocation(shaderId, "model");
|
||||
mNormalRotPos = glGetUniformLocation(shaderId, "normalRot");
|
||||
mProjectionPos = glGetUniformLocation(shaderId, "projection");
|
||||
mViewPos = glGetUniformLocation(shaderId, "view");
|
||||
mLightPosPos = glGetUniformLocation(shaderId, "lightPos");
|
||||
mLightColorPos = glGetUniformLocation(shaderId, "lightColor");
|
||||
mAmbientPos = glGetUniformLocation(shaderId, "ambient");
|
||||
mObjectColorPos = glGetUniformLocation(shaderId, "objectColor");
|
||||
mTexSlotPos = glGetUniformLocation(shaderId, "texSlot");
|
||||
Activate();
|
||||
return shaderId;
|
||||
}
|
||||
|
||||
void Shader::Activate()
|
||||
{
|
||||
if (shaderId > 0) {
|
||||
glUseProgram(shaderId);
|
||||
}
|
||||
CurrentShader = this;
|
||||
}
|
||||
|
||||
|
||||
const char* VertShader3DNorm =
|
||||
"#version 330 core \n"
|
||||
|
||||
"layout(location = 0) in vec3 aPosition; \n"
|
||||
"layout(location = 1) in vec3 aNormal; \n"
|
||||
|
||||
"out vec3 Normal; \n"
|
||||
"out vec3 FragPos; \n"
|
||||
|
||||
"uniform mat4 model; \n"
|
||||
"uniform mat4 view; \n"
|
||||
"uniform mat4 projection; \n"
|
||||
"uniform mat4 normalRot; \n"
|
||||
|
||||
"void main(void) \n"
|
||||
"{ \n"
|
||||
" gl_Position = projection * view * model * vec4(aPosition, 1.0); \n"
|
||||
" FragPos = vec3(model * vec4(aPosition, 1.0)); \n"
|
||||
" Normal = vec3(normalRot * vec4(aNormal, 1.0)); \n"
|
||||
"} \n";
|
||||
|
||||
const char* VertShader3DInvNorm =
|
||||
"#version 330 core \n"
|
||||
|
||||
"layout(location = 0) in vec3 aPosition; \n"
|
||||
"layout(location = 1) in vec3 aNormal; \n"
|
||||
|
||||
"out vec3 Normal; \n"
|
||||
"out vec3 FragPos; \n"
|
||||
|
||||
"uniform mat4 model; \n"
|
||||
"uniform mat4 view; \n"
|
||||
"uniform mat4 projection; \n"
|
||||
"uniform mat4 normalRot; \n"
|
||||
|
||||
"void main(void) \n"
|
||||
"{ \n"
|
||||
" gl_Position = projection * view * model * vec4(aPosition, 1.0); \n"
|
||||
" FragPos = vec3(model * vec4(aPosition, 1.0)); \n"
|
||||
" Normal = -vec3(normalRot * vec4(aNormal, 1.0)); \n"
|
||||
"} \n";
|
||||
|
||||
|
||||
const char* VertShader2DTex =
|
||||
"#version 330 core \n" // -----> add long remark for a uniform auto formatting
|
||||
|
||||
"layout(location = 0) in vec2 aPosition; \n"
|
||||
"layout(location = 1) in vec2 aTexCoord; \n"
|
||||
|
||||
"out vec2 texCoord; \n"
|
||||
|
||||
"uniform mat4 projection; \n"
|
||||
"uniform mat4 model; \n"
|
||||
|
||||
"void main(void) \n"
|
||||
"{ \n"
|
||||
" gl_Position = projection * model * vec4(aPosition, 0.0, 1.0); \n"
|
||||
" texCoord = aTexCoord; \n"
|
||||
"} \n";
|
||||
|
||||
const char* FragShader2dTex =
|
||||
"#version 330\n" // -----> add long remark for a uniform auto formatting
|
||||
|
||||
"out vec4 FragColor; \n"
|
||||
"in vec2 texCoord; \n"
|
||||
|
||||
"uniform vec3 objectColor; \n"
|
||||
"uniform sampler2D texSlot; \n"
|
||||
|
||||
"void main() \n"
|
||||
"{ \n"
|
||||
" vec4 texColor = texture(texSlot, texCoord); \n"
|
||||
" FragColor = vec4(objectColor, 1.0) * texColor; \n"
|
||||
"} \n";
|
||||
|
||||
|
||||
const char* FragShaderNorm =
|
||||
"#version 330\n" // -----> add long remark for a uniform auto formatting
|
||||
|
||||
"out vec4 FragColor; \n"
|
||||
|
||||
"in vec3 Normal; \n"
|
||||
"in vec3 FragPos; \n"
|
||||
|
||||
"uniform vec3 lightPos; \n"
|
||||
"uniform vec3 lightColor; \n"
|
||||
"uniform vec3 objectColor; \n"
|
||||
"uniform vec3 ambient; \n"
|
||||
|
||||
"void main() \n"
|
||||
"{ \n"
|
||||
" vec3 norm = normalize(Normal); \n"
|
||||
" vec3 lightDir = normalize(lightPos - FragPos); \n"
|
||||
" float diff = max(dot(norm, lightDir), 0.0); \n"
|
||||
" vec3 diffuse = diff * lightColor; \n"
|
||||
" vec3 result = (ambient + diffuse) * objectColor; \n"
|
||||
" FragColor = vec4(result, 1.0); \n"
|
||||
"} \n";
|
||||
|
||||
const char* FragShaderFlat =
|
||||
"#version 330\n" // -----> add long remark for a uniform auto formatting
|
||||
|
||||
"out vec4 FragColor; \n"
|
||||
|
||||
"in vec3 Normal; \n"
|
||||
"in vec3 FragPos; \n"
|
||||
"uniform vec3 objectColor; \n"
|
||||
|
||||
"void main() \n"
|
||||
"{ \n"
|
||||
" FragColor = vec4(objectColor, 1.0); \n"
|
||||
"} \n";
|
||||
|
||||
} // namespace MillSim
|
||||
77
src/Mod/CAM/PathSimulator/AppGL/Shader.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __shader_h__
|
||||
#define __shader_h__
|
||||
|
||||
#include "OpenGlWrapper.h"
|
||||
#include "linmath.h"
|
||||
|
||||
namespace MillSim
|
||||
{
|
||||
class Shader
|
||||
{
|
||||
public:
|
||||
Shader()
|
||||
{}
|
||||
|
||||
public:
|
||||
unsigned int shaderId = 0;
|
||||
void UpdateModelMat(mat4x4 transformMat, mat4x4 normalMat);
|
||||
void UpdateProjectionMat(mat4x4 mat);
|
||||
void UpdateViewMat(mat4x4 mat);
|
||||
void UpdateEnvColor(vec3 lightPos, vec3 lightColor, vec3 ambient);
|
||||
void UpdateObjColor(vec3 objColor);
|
||||
void UpdateTextureSlot(int slot);
|
||||
unsigned int CompileShader(char* vertShader, char* fragShader);
|
||||
void Activate();
|
||||
bool IsValid()
|
||||
{
|
||||
return shaderId > 0;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
int mModelPos = -1;
|
||||
int mNormalRotPos = -1;
|
||||
int mProjectionPos = -1;
|
||||
int mViewPos = -1;
|
||||
int mLightPosPos = -1;
|
||||
int mLightColorPos = -1;
|
||||
int mAmbientPos = -1;
|
||||
int mObjectColorPos = -1;
|
||||
int mTexSlotPos = -1;
|
||||
|
||||
const char* vertShader = nullptr;
|
||||
const char* fragShader = nullptr;
|
||||
};
|
||||
|
||||
extern Shader* CurrentShader;
|
||||
|
||||
extern const char* FragShaderNorm;
|
||||
extern const char* FragShaderFlat;
|
||||
extern const char* VertShader3DNorm;
|
||||
extern const char* VertShader3DInvNorm;
|
||||
extern const char* VertShader2DTex;
|
||||
extern const char* FragShader2dTex;
|
||||
} // namespace MillSim
|
||||
#endif // !__shader_h__
|
||||
403
src/Mod/CAM/PathSimulator/AppGL/SimShapes.cpp
Normal file
@@ -0,0 +1,403 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "SimShapes.h"
|
||||
#include "Shader.h"
|
||||
#include "GlUtils.h"
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cstddef>
|
||||
|
||||
using namespace MillSim;
|
||||
|
||||
static float* sinTable = nullptr;
|
||||
static float* cosTable = nullptr;
|
||||
static int lastNumSlices = 0;
|
||||
static int lastNumSectionIndices = 0;
|
||||
static GLshort quadIndices[] = { 0, 2, 3, 0, 3, 1 };
|
||||
static GLshort quadIndicesReversed[] = { 0, 3, 2, 0, 1, 3 };
|
||||
static GLshort* sectionIndicesQuad = nullptr;
|
||||
static GLshort* sectionIndicesTri = nullptr;
|
||||
|
||||
static bool GenerateSinTable(int nSlices)
|
||||
{
|
||||
if (nSlices == lastNumSlices)
|
||||
return true;
|
||||
if (sinTable != nullptr)
|
||||
free(sinTable);
|
||||
if (cosTable != nullptr)
|
||||
free(cosTable);
|
||||
sinTable = cosTable = nullptr;
|
||||
|
||||
float slice = (float)(2 * PI / nSlices);
|
||||
int nvals = nSlices + 1;
|
||||
sinTable = (float*)malloc(nvals * sizeof(float));
|
||||
if (sinTable == nullptr)
|
||||
return false;
|
||||
cosTable = (float*)malloc(nvals * sizeof(float));
|
||||
if (cosTable == nullptr)
|
||||
{
|
||||
free(sinTable);
|
||||
sinTable = nullptr;
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < nvals; i++)
|
||||
{
|
||||
sinTable[i] = sinf(slice * i);
|
||||
cosTable[i] = cosf(slice * i);
|
||||
}
|
||||
lastNumSlices = nvals;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void MillSim::Shape::RotateProfile(float* profPoints, int nPoints, float distance, float deltaHeight, int nSlices, bool isHalfTurn)
|
||||
{
|
||||
int vidx = 0;
|
||||
int iidx = 0;
|
||||
int numVerts, numIndices;
|
||||
int vstart;
|
||||
|
||||
numVerts = nPoints * 2 * (nSlices + 1);
|
||||
numIndices = (nPoints - 1) * nSlices * 6;
|
||||
|
||||
float* vbuffer = (float*)malloc(numVerts * sizeof(Vertex));
|
||||
if (vbuffer == nullptr)
|
||||
return;
|
||||
GLushort* ibuffer = (GLushort*)malloc(numIndices * sizeof(GLushort));
|
||||
if (ibuffer == nullptr)
|
||||
{
|
||||
free(vbuffer);
|
||||
return;
|
||||
}
|
||||
int nsinvals = nSlices;
|
||||
if (isHalfTurn)
|
||||
nsinvals *= 2;
|
||||
if (GenerateSinTable(nsinvals) == false)
|
||||
{
|
||||
free(vbuffer);
|
||||
free(ibuffer);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < nPoints; i++)
|
||||
{
|
||||
int i2 = i * 2;
|
||||
|
||||
float prevy = i > 0 ? profPoints[i2 - 2] : 0;
|
||||
float prevz = i > 0 ? profPoints[i2 - 1] : profPoints[i2 + 1];
|
||||
float prevrad = fabsf(prevy);
|
||||
float rad = fabsf(profPoints[i2]);
|
||||
float z2 = profPoints[i2 + 1];
|
||||
float diffy = profPoints[i2] - prevy;
|
||||
float diffz = z2 - prevz;
|
||||
float len = sqrtf(diffy * diffy + diffz * diffz);
|
||||
float nz = diffy / len;
|
||||
vstart = i * 2 * (nSlices + 1);
|
||||
|
||||
for (int j = 0; j <= nSlices; j++)
|
||||
{
|
||||
// generate vertices
|
||||
float sx = sinTable[j];
|
||||
float sy = cosTable[j];
|
||||
float x1 = prevrad * sx + distance;
|
||||
float y1 = prevrad * sy;
|
||||
float x2 = rad * sx + distance;
|
||||
float y2 = rad * sy;
|
||||
|
||||
// generate normals
|
||||
float ny = -diffz / len;
|
||||
float nx = ny * sx;
|
||||
ny *= sy;
|
||||
|
||||
SET_TRIPLE(vbuffer, vidx, x1, y1, prevz);
|
||||
SET_TRIPLE(vbuffer, vidx, nx, ny, nz);
|
||||
SET_TRIPLE(vbuffer, vidx, x2, y2, z2);
|
||||
SET_TRIPLE(vbuffer, vidx, nx, ny, nz);
|
||||
|
||||
if (j != nSlices)
|
||||
{
|
||||
// generate indices { 0, 3, 1, 0, 2, 3 }
|
||||
int pos = vstart + 2 * j;
|
||||
if (i < (nPoints - 1))
|
||||
SET_TRIPLE(ibuffer, iidx, pos, pos + 3, pos + 1);
|
||||
if (i > 0)
|
||||
SET_TRIPLE(ibuffer, iidx, pos, pos + 2, pos + 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GenerateModel(vbuffer, ibuffer, numVerts, numIndices);
|
||||
|
||||
free(vbuffer);
|
||||
free(ibuffer);
|
||||
}
|
||||
|
||||
void MillSim::Shape::CalculateExtrudeBufferSizes(int nProfilePoints, bool capStart, bool capEnd,
|
||||
int* numVerts, int* numIndices, int* vc1idx, int* vc2idx, int* ic1idx, int* ic2idx)
|
||||
{
|
||||
*numVerts = nProfilePoints * 4; // one face per profile point times 4 vertex per face
|
||||
*numIndices = nProfilePoints * 2 * 3; // 2 triangles per face times 3 indices per triangle
|
||||
if (capStart)
|
||||
{
|
||||
*vc1idx = *numVerts * 6;
|
||||
*numVerts += nProfilePoints;
|
||||
*ic1idx = *numIndices;
|
||||
*numIndices += (nProfilePoints - 2) * 3;
|
||||
}
|
||||
if (capEnd)
|
||||
{
|
||||
*vc2idx = *numVerts * 6;
|
||||
*numVerts += nProfilePoints;
|
||||
*ic2idx = *numIndices;
|
||||
*numIndices += (nProfilePoints - 2) * 3;
|
||||
}
|
||||
}
|
||||
|
||||
void MillSim::Shape::ExtrudeProfileRadial(float* profPoints, int nPoints, float radius, float angleRad, float deltaHeight, bool capStart, bool capEnd)
|
||||
{
|
||||
int vidx = 0, vc1idx, vc2idx;
|
||||
int iidx = 0, ic1idx, ic2idx;
|
||||
int numVerts, numIndices;
|
||||
|
||||
CalculateExtrudeBufferSizes(nPoints, capStart, capEnd, &numVerts, &numIndices, &vc1idx, &vc2idx, &ic1idx, &ic2idx);
|
||||
int vc1start = vc1idx / 6;
|
||||
int vc2start = vc2idx / 6;
|
||||
|
||||
float* vbuffer = (float*)malloc(numVerts * sizeof(Vertex));
|
||||
if (!vbuffer)
|
||||
return;
|
||||
GLushort* ibuffer = (GLushort*)malloc(numIndices * sizeof(GLushort));
|
||||
if (!ibuffer)
|
||||
{
|
||||
free(vbuffer);
|
||||
return;
|
||||
}
|
||||
|
||||
bool is_clockwise = angleRad > 0;
|
||||
angleRad = (float)fabs(angleRad);
|
||||
float dir = is_clockwise ? 1.0f : -1.0f;
|
||||
int offs1 = is_clockwise ? -1 : 0;
|
||||
int offs2 = is_clockwise ? 0 : -1;
|
||||
|
||||
float cosAng = cosf(angleRad);
|
||||
float sinAng = sinf(angleRad);
|
||||
for (int i = 0; i < nPoints; i++)
|
||||
{
|
||||
int p1 = i * 2;
|
||||
float y1 = profPoints[p1] + radius;
|
||||
float z1 = profPoints[p1 + 1];
|
||||
int p2 = (p1 + 2) % (nPoints * 2);
|
||||
float y2 = profPoints[p2] + radius;
|
||||
float z2 = profPoints[p2 + 1];
|
||||
|
||||
// normals
|
||||
float ydiff = y2 - y1;
|
||||
float zdiff = z2 - z1;
|
||||
float len = sqrtf(ydiff * ydiff + zdiff * zdiff);
|
||||
float ny = -zdiff / len;
|
||||
float nz = ydiff / len;
|
||||
float nx = -sinAng * ny;
|
||||
ny *= cosAng;
|
||||
|
||||
// start verts
|
||||
SET_TRIPLE(vbuffer, vidx, 0, y1, z1);
|
||||
SET_TRIPLE(vbuffer, vidx, nx, ny, nz);
|
||||
SET_TRIPLE(vbuffer, vidx, 0, y2, z2);
|
||||
SET_TRIPLE(vbuffer, vidx, nx, ny, nz);
|
||||
|
||||
if (capStart) {
|
||||
SET_TRIPLE(vbuffer, vc1idx, 0, y1, z1);
|
||||
SET_TRIPLE(vbuffer, vc1idx, -1 * dir, 0, 0);
|
||||
if (i > 1)
|
||||
SET_TRIPLE(ibuffer, ic1idx, vc1start, vc1start + i + offs1, vc1start + i + offs2);
|
||||
}
|
||||
|
||||
float x1 = y1 * sinAng * dir;
|
||||
float x2 = y2 * sinAng * dir;
|
||||
y1 *= cosAng;
|
||||
y2 *= cosAng;
|
||||
z1 += deltaHeight;
|
||||
z2 += deltaHeight;
|
||||
SET_TRIPLE(vbuffer, vidx, x1, y1, z1);
|
||||
SET_TRIPLE(vbuffer, vidx, nx, ny, nz);
|
||||
SET_TRIPLE(vbuffer, vidx, x2, y2, z2);
|
||||
SET_TRIPLE(vbuffer, vidx, nx, ny, nz);
|
||||
|
||||
// face have 2 triangles { 0, 2, 3, 0, 3, 1 };
|
||||
GLushort vistart = i * 4;
|
||||
if (is_clockwise)
|
||||
{
|
||||
SET_TRIPLE(ibuffer, iidx, vistart, vistart + 2, vistart + 3);
|
||||
SET_TRIPLE(ibuffer, iidx, vistart, vistart + 3, vistart + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
SET_TRIPLE(ibuffer, iidx, vistart, vistart + 3, vistart + 2);
|
||||
SET_TRIPLE(ibuffer, iidx, vistart, vistart + 1, vistart + 3);
|
||||
}
|
||||
|
||||
if (capEnd)
|
||||
{
|
||||
SET_TRIPLE(vbuffer, vc2idx, x1, y1, z1);
|
||||
SET_TRIPLE(vbuffer, vc2idx, cosAng * dir, -sinAng, 0);
|
||||
if (i > 1)
|
||||
SET_TRIPLE(ibuffer, ic2idx, vc2start, vc2start + i + offs2, vc2start + i + offs1);
|
||||
}
|
||||
}
|
||||
|
||||
GenerateModel(vbuffer, ibuffer, numVerts, numIndices);
|
||||
|
||||
free(vbuffer);
|
||||
free(ibuffer);
|
||||
}
|
||||
|
||||
void MillSim::Shape::ExtrudeProfileLinear(float* profPoints, int nPoints, float fromX, float toX, float fromZ, float toZ, bool capStart, bool capEnd)
|
||||
{
|
||||
int vidx = 0, vc1idx, vc2idx;
|
||||
int iidx = 0, ic1idx, ic2idx;
|
||||
int numVerts, numIndices;
|
||||
|
||||
CalculateExtrudeBufferSizes(nPoints, capStart, capEnd, &numVerts, &numIndices, &vc1idx, &vc2idx, &ic1idx, &ic2idx);
|
||||
int vc1start = vc1idx / 6;
|
||||
int vc2start = vc2idx / 6;
|
||||
|
||||
float* vbuffer = (float*)malloc(numVerts * sizeof(Vertex));
|
||||
if (!vbuffer)
|
||||
return;
|
||||
GLushort* ibuffer = (GLushort*)malloc(numIndices * sizeof(GLushort));
|
||||
if (!ibuffer)
|
||||
{
|
||||
free(vbuffer);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < nPoints; i++)
|
||||
{
|
||||
// hollow pipe verts
|
||||
int p1 = i * 2;
|
||||
float y1 = profPoints[p1];
|
||||
float z1 = profPoints[p1 + 1];
|
||||
int p2 = (p1 + 2) % (nPoints * 2);
|
||||
float y2 = profPoints[p2];
|
||||
float z2 = profPoints[p2 + 1];
|
||||
|
||||
// nornal
|
||||
float ydiff = y2 - y1;
|
||||
float zdiff = z2 - z1;
|
||||
float len = sqrtf(ydiff * ydiff + zdiff * zdiff);
|
||||
float ny = -zdiff / len;
|
||||
float nz = ydiff / len;
|
||||
|
||||
SET_TRIPLE(vbuffer, vidx, fromX, y1, z1 + fromZ);
|
||||
SET_TRIPLE(vbuffer, vidx, 0, ny, nz);
|
||||
SET_TRIPLE(vbuffer, vidx, fromX, y2, z2 + fromZ);
|
||||
SET_TRIPLE(vbuffer, vidx, 0, ny, nz);
|
||||
SET_TRIPLE(vbuffer, vidx, toX, y1, z1 + toZ);
|
||||
SET_TRIPLE(vbuffer, vidx, 0, ny, nz);
|
||||
SET_TRIPLE(vbuffer, vidx, toX, y2, z2 + toZ);
|
||||
SET_TRIPLE(vbuffer, vidx, 0, ny, nz);
|
||||
|
||||
// face have 2 triangles { 0, 2, 3, 0, 3, 1 };
|
||||
GLushort vistart = i * 4;
|
||||
SET_TRIPLE(ibuffer, iidx, vistart, vistart + 2, vistart + 3);
|
||||
SET_TRIPLE(ibuffer, iidx, vistart, vistart + 3, vistart + 1);
|
||||
|
||||
if (capStart)
|
||||
{
|
||||
SET_TRIPLE(vbuffer, vc1idx, fromX, profPoints[p1], profPoints[p1 + 1] + fromZ);
|
||||
SET_TRIPLE(vbuffer, vc1idx, -1, 0, 0);
|
||||
if (i > 1)
|
||||
SET_TRIPLE(ibuffer, ic1idx, vc1start, vc1start + i - 1, vc1start + i);
|
||||
}
|
||||
if (capEnd)
|
||||
{
|
||||
SET_TRIPLE(vbuffer, vc2idx, toX, profPoints[p1], profPoints[p1 + 1] + toZ);
|
||||
SET_TRIPLE(vbuffer, vc2idx, 1, 0, 0);
|
||||
if (i > 1)
|
||||
SET_TRIPLE(ibuffer, ic2idx, vc2start, vc2start + i, vc2start + i - 1);
|
||||
}
|
||||
}
|
||||
|
||||
GenerateModel(vbuffer, ibuffer, numVerts, numIndices);
|
||||
|
||||
free(vbuffer);
|
||||
free(ibuffer);
|
||||
}
|
||||
|
||||
void MillSim::Shape::GenerateModel(float* vbuffer, GLushort* ibuffer, int numVerts, int nIndices)
|
||||
{
|
||||
//GLuint vbo, ibo, vao;
|
||||
|
||||
// vertex buffer
|
||||
glGenBuffers(1, &vbo);
|
||||
GLClearError();
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
GLLogError();
|
||||
glBufferData(GL_ARRAY_BUFFER, numVerts * sizeof(Vertex), vbuffer, GL_STATIC_DRAW);
|
||||
|
||||
// index buffer
|
||||
glGenBuffers(1, &ibo);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, nIndices * sizeof(GLushort), ibuffer, GL_STATIC_DRAW);
|
||||
|
||||
// vertex array
|
||||
glGenVertexArrays(1, &vao);
|
||||
glBindVertexArray(vao);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, x));
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, nx));
|
||||
|
||||
numIndices = nIndices;
|
||||
}
|
||||
|
||||
void MillSim::Shape::Render()
|
||||
{
|
||||
glBindVertexArray(vao);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
||||
glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, nullptr);
|
||||
}
|
||||
|
||||
void MillSim::Shape::Render(mat4x4 modelMat, mat4x4 normallMat) // normals are rotated only
|
||||
{
|
||||
CurrentShader->UpdateModelMat(modelMat, normallMat);
|
||||
Render();
|
||||
}
|
||||
|
||||
void MillSim::Shape::FreeResources()
|
||||
{
|
||||
if (vao > 0)
|
||||
{
|
||||
glBindVertexArray(vao);
|
||||
if (vbo > 0) glDeleteBuffers(1, &vbo);
|
||||
if (ibo > 0) glDeleteBuffers(1, &ibo);
|
||||
glDeleteVertexArrays(1, &vao);
|
||||
vbo = ibo = vao = 0;
|
||||
}
|
||||
}
|
||||
|
||||
MillSim::Shape::~Shape()
|
||||
{
|
||||
FreeResources();
|
||||
}
|
||||
114
src/Mod/CAM/PathSimulator/AppGL/SimShapes.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __sim_shapes_h__
|
||||
#define __sim_shapes_h__
|
||||
#include "OpenGlWrapper.h"
|
||||
#include "linmath.h"
|
||||
|
||||
#define SET_DUAL(var, idx, y, z) \
|
||||
{ \
|
||||
var[idx++] = y; \
|
||||
var[idx++] = z; \
|
||||
}
|
||||
#define SET_TRIPLE(var, idx, x, y, z) \
|
||||
{ \
|
||||
var[idx++] = x; \
|
||||
var[idx++] = y; \
|
||||
var[idx++] = z; \
|
||||
}
|
||||
|
||||
// #define SET_TRIPLE(var, idx, x, y, z) {var[idx] = x; var[idx+1] = y; var[idx+2] = z;}
|
||||
// #define SET_TRIPLE_OFFS(var, idx, offs, x, y, z) {var[idx] = x + offs; var[idx+1] = y + offs;
|
||||
// var[idx+2] = z + offs;}
|
||||
|
||||
#define SET_TRIPLE_OFFS(var, idx, offs, x, y, z) \
|
||||
{ \
|
||||
var[idx++] = x + offs; \
|
||||
var[idx++] = y + offs; \
|
||||
var[idx++] = z + offs; \
|
||||
}
|
||||
|
||||
namespace MillSim
|
||||
{
|
||||
typedef unsigned int uint;
|
||||
|
||||
struct Vertex
|
||||
{
|
||||
float x, y, z;
|
||||
float nx, ny, nz;
|
||||
};
|
||||
|
||||
class Shape
|
||||
{
|
||||
public:
|
||||
Shape()
|
||||
{}
|
||||
~Shape();
|
||||
|
||||
public:
|
||||
uint vao = 0;
|
||||
uint vbo = 0;
|
||||
uint ibo = 0;
|
||||
int numIndices = 0;
|
||||
|
||||
public:
|
||||
void Render();
|
||||
void Render(mat4x4 modelMat, mat4x4 normallMat);
|
||||
void FreeResources();
|
||||
void RotateProfile(float* profPoints,
|
||||
int nPoints,
|
||||
float distance,
|
||||
float deltaHeight,
|
||||
int nSlices,
|
||||
bool isHalfTurn);
|
||||
void ExtrudeProfileRadial(float* profPoints,
|
||||
int nPoints,
|
||||
float radius,
|
||||
float angleRad,
|
||||
float deltaHeight,
|
||||
bool capStart,
|
||||
bool capEnd);
|
||||
void ExtrudeProfileLinear(float* profPoints,
|
||||
int nPoints,
|
||||
float fromX,
|
||||
float toX,
|
||||
float fromZ,
|
||||
float toZ,
|
||||
bool capStart,
|
||||
bool capEnd);
|
||||
|
||||
protected:
|
||||
void GenerateModel(float* vbuffer, GLushort* ibuffer, int numVerts, int numIndices);
|
||||
void CalculateExtrudeBufferSizes(int nProfilePoints,
|
||||
bool capStart,
|
||||
bool capEnd,
|
||||
int* numVerts,
|
||||
int* numIndices,
|
||||
int* vc1idx,
|
||||
int* vc2idx,
|
||||
int* ic1idx,
|
||||
int* ic2idx);
|
||||
};
|
||||
|
||||
} // namespace MillSim
|
||||
#endif
|
||||
64
src/Mod/CAM/PathSimulator/AppGL/StockObject.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "StockObject.h"
|
||||
#include "Shader.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define NUM_PROFILE_POINTS 4
|
||||
|
||||
MillSim::StockObject::StockObject()
|
||||
{
|
||||
mat4x4_identity(mModelMat);
|
||||
vec3_set(center, 0, 0, 0);
|
||||
}
|
||||
|
||||
MillSim::StockObject::~StockObject()
|
||||
{
|
||||
shape.FreeResources();
|
||||
}
|
||||
|
||||
void MillSim::StockObject::render()
|
||||
{
|
||||
// glCallList(mDisplayListId);
|
||||
// UpdateObjColor(color);
|
||||
shape.Render(mModelMat, mModelMat); // model is not rotated hence both are identity matrix
|
||||
}
|
||||
|
||||
void MillSim::StockObject::SetPosition(vec3 position)
|
||||
{
|
||||
mat4x4_translate(mModelMat, position[0], position[1], position[2]);
|
||||
}
|
||||
|
||||
void MillSim::StockObject::GenerateBoxStock(float x, float y, float z, float l, float w, float h)
|
||||
{
|
||||
int idx = 0;
|
||||
SET_DUAL(mProfile, idx, y + w, z + h);
|
||||
SET_DUAL(mProfile, idx, y + w, z);
|
||||
SET_DUAL(mProfile, idx, y, z);
|
||||
SET_DUAL(mProfile, idx, y, z + h);
|
||||
|
||||
vec3_set(center, x + l / 2, y + w / 2, z + h / 2);
|
||||
vec3_set(size, l, w, h);
|
||||
|
||||
shape.ExtrudeProfileLinear(mProfile, NUM_PROFILE_POINTS, x, x + l, 0, 0, true, true);
|
||||
}
|
||||
52
src/Mod/CAM/PathSimulator/AppGL/StockObject.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __stock_object_h__
|
||||
#define __stock_object_h__
|
||||
#include "SimShapes.h"
|
||||
#include "linmath.h"
|
||||
|
||||
namespace MillSim
|
||||
{
|
||||
|
||||
class StockObject
|
||||
{
|
||||
public:
|
||||
StockObject();
|
||||
virtual ~StockObject();
|
||||
|
||||
|
||||
/// Calls the display list.
|
||||
virtual void render();
|
||||
Shape shape;
|
||||
void SetPosition(vec3 position);
|
||||
void GenerateBoxStock(float x, float y, float z, float l, float w, float h);
|
||||
vec3 center = {};
|
||||
vec3 size = {};
|
||||
|
||||
private:
|
||||
float mProfile[8] = {};
|
||||
mat4x4 mModelMat;
|
||||
};
|
||||
} // namespace MillSim
|
||||
|
||||
#endif
|
||||
61
src/Mod/CAM/PathSimulator/AppGL/Texture.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "Texture.h"
|
||||
#include "GlUtils.h"
|
||||
|
||||
namespace MillSim
|
||||
{
|
||||
Texture::~Texture()
|
||||
{
|
||||
glDeleteTextures(1, &mTextureId);
|
||||
}
|
||||
|
||||
bool Texture::LoadImage(unsigned int* image, int _width, int _height)
|
||||
{
|
||||
width = _width;
|
||||
height = _height;
|
||||
glGenTextures(1, &mTextureId);
|
||||
glBindTexture(GL_TEXTURE_2D, mTextureId);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Texture::Activate()
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, mTextureId);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Texture::unbind()
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace MillSim
|
||||
60
src/Mod/CAM/PathSimulator/AppGL/Texture.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __texture_h__
|
||||
#define __texture_h__
|
||||
#include "OpenGlWrapper.h"
|
||||
|
||||
namespace MillSim
|
||||
{
|
||||
|
||||
class Texture
|
||||
{
|
||||
public:
|
||||
Texture()
|
||||
{}
|
||||
~Texture();
|
||||
bool LoadImage(unsigned int* image, int x, int y);
|
||||
bool Activate();
|
||||
bool unbind();
|
||||
float getTexX(int imgX)
|
||||
{
|
||||
return (float)imgX / (float)width;
|
||||
}
|
||||
float getTexY(int imgY)
|
||||
{
|
||||
return (float)imgY / (float)height;
|
||||
}
|
||||
|
||||
public:
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
|
||||
protected:
|
||||
unsigned int mTextureId = -1;
|
||||
};
|
||||
|
||||
|
||||
} // namespace MillSim
|
||||
|
||||
#endif // !__texture_h__
|
||||
98
src/Mod/CAM/PathSimulator/AppGL/TextureLoader.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "TextureLoader.h"
|
||||
|
||||
using namespace MillSim;
|
||||
|
||||
TextureItem texItems[] = {
|
||||
{1, 36, 0, 0},
|
||||
{1, 1, 0, 0},
|
||||
{70, 1, 0, 0},
|
||||
{100, 1, 0, 0},
|
||||
{134, 1, 0, 0},
|
||||
{172, 1, 0, 0},
|
||||
{210, 1, 0, 0},
|
||||
{2, 50, 0, 0},
|
||||
{70, 50, 0, 0},
|
||||
{27, 50, 0, 0},
|
||||
{44, 50, 0, 0},
|
||||
};
|
||||
|
||||
|
||||
#define NUM_TEX_ITEMS (sizeof(texItems) / sizeof(TextureItem))
|
||||
|
||||
int sssize = -1;
|
||||
|
||||
TextureLoader::TextureLoader(std::string imgFolder, std::vector<std::string> fileNames, int textureSize)
|
||||
: mImageFolder(imgFolder)
|
||||
{
|
||||
int buffsize = textureSize * textureSize * sizeof(unsigned int);
|
||||
mRawData = (unsigned int*)malloc(buffsize);
|
||||
if (mRawData == nullptr) {
|
||||
return;
|
||||
}
|
||||
memset(mRawData, 0x80, buffsize);
|
||||
for (int i = 0; i < fileNames.size(); i++) {
|
||||
QImage pixmap((imgFolder + fileNames[i]).c_str());
|
||||
AddImage(&(texItems[i]), pixmap, mRawData, textureSize);
|
||||
}
|
||||
}
|
||||
|
||||
// parse compressed image into a texture buffer
|
||||
bool TextureLoader::AddImage(TextureItem* texItem,
|
||||
QImage& pixmap,
|
||||
unsigned int* buffPos,
|
||||
int stride)
|
||||
{
|
||||
int width = pixmap.width();
|
||||
int height = pixmap.height();
|
||||
int buffLen = width * height;
|
||||
buffPos += stride * texItem->ty + texItem->tx;
|
||||
for (int i = 0; i < height; i++) {
|
||||
unsigned int* line = reinterpret_cast<unsigned int *>(pixmap.scanLine(i));
|
||||
for (int j = 0; j < width; j++) {
|
||||
buffPos[j] = line[j];
|
||||
}
|
||||
buffPos += stride;
|
||||
}
|
||||
texItem->w = width;
|
||||
texItem->h = height;
|
||||
return true;
|
||||
}
|
||||
|
||||
MillSim::TextureLoader::~TextureLoader()
|
||||
{
|
||||
if (mRawData != nullptr) {
|
||||
free(mRawData);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int* MillSim::TextureLoader::GetRawData()
|
||||
{
|
||||
return mRawData;
|
||||
}
|
||||
|
||||
TextureItem* MillSim::TextureLoader::GetTextureItem(int i)
|
||||
{
|
||||
return texItems + i;
|
||||
}
|
||||
55
src/Mod/CAM/PathSimulator/AppGL/TextureLoader.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __texture_loader_h__
|
||||
#define __texture_loader_h__
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <QImage>
|
||||
|
||||
namespace MillSim
|
||||
{
|
||||
|
||||
struct TextureItem
|
||||
{
|
||||
int tx, ty; // texture location
|
||||
int w, h; // item size
|
||||
};
|
||||
|
||||
class TextureLoader
|
||||
{
|
||||
public:
|
||||
TextureLoader(std::string imgFolder, std::vector<std::string> fileNames, int textureSize);
|
||||
~TextureLoader();
|
||||
unsigned int* GetRawData();
|
||||
TextureItem* GetTextureItem(int i);
|
||||
|
||||
protected:
|
||||
bool AddImage(TextureItem* guiItem, QImage& pixmap, unsigned int* buffPos, int stride);
|
||||
|
||||
protected:
|
||||
unsigned int* mRawData = nullptr;
|
||||
std::string mImageFolder;
|
||||
};
|
||||
|
||||
} // namespace MillSim
|
||||
#endif // !__texture_loader_h__
|
||||
634
src/Mod/CAM/PathSimulator/AppGL/linmath.h
Normal file
@@ -0,0 +1,634 @@
|
||||
/*************************************************************************************************/
|
||||
/* Taken from https://github.com/datenwolf/linmath.h under 'Do whatever you want' license */
|
||||
/*************************************************************************************************/
|
||||
#ifndef LINMATH_H
|
||||
#define LINMATH_H
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef LINMATH_NO_INLINE
|
||||
#define LINMATH_H_FUNC static
|
||||
#else
|
||||
#define LINMATH_H_FUNC static inline
|
||||
#endif
|
||||
|
||||
#define LINMATH_H_DEFINE_VEC(n) \
|
||||
typedef float vec##n[n]; \
|
||||
LINMATH_H_FUNC void vec##n##_add(vec##n r, vec##n const a, vec##n const b) \
|
||||
{ \
|
||||
int i; \
|
||||
for (i = 0; i < n; ++i) \
|
||||
r[i] = a[i] + b[i]; \
|
||||
} \
|
||||
LINMATH_H_FUNC void vec##n##_sub(vec##n r, vec##n const a, vec##n const b) \
|
||||
{ \
|
||||
int i; \
|
||||
for (i = 0; i < n; ++i) \
|
||||
r[i] = a[i] - b[i]; \
|
||||
} \
|
||||
LINMATH_H_FUNC void vec##n##_scale(vec##n r, vec##n const v, float const s) \
|
||||
{ \
|
||||
int i; \
|
||||
for (i = 0; i < n; ++i) \
|
||||
r[i] = v[i] * s; \
|
||||
} \
|
||||
LINMATH_H_FUNC float vec##n##_mul_inner(vec##n const a, vec##n const b) \
|
||||
{ \
|
||||
float p = 0.f; \
|
||||
int i; \
|
||||
for (i = 0; i < n; ++i) \
|
||||
p += b[i] * a[i]; \
|
||||
return p; \
|
||||
} \
|
||||
LINMATH_H_FUNC float vec##n##_len(vec##n const v) \
|
||||
{ \
|
||||
return sqrtf(vec##n##_mul_inner(v, v)); \
|
||||
} \
|
||||
LINMATH_H_FUNC void vec##n##_norm(vec##n r, vec##n const v) \
|
||||
{ \
|
||||
float k = 1.f / vec##n##_len(v); \
|
||||
vec##n##_scale(r, v, k); \
|
||||
} \
|
||||
LINMATH_H_FUNC void vec##n##_min(vec##n r, vec##n const a, vec##n const b) \
|
||||
{ \
|
||||
int i; \
|
||||
for (i = 0; i < n; ++i) \
|
||||
r[i] = a[i] < b[i] ? a[i] : b[i]; \
|
||||
} \
|
||||
LINMATH_H_FUNC void vec##n##_max(vec##n r, vec##n const a, vec##n const b) \
|
||||
{ \
|
||||
int i; \
|
||||
for (i = 0; i < n; ++i) \
|
||||
r[i] = a[i] > b[i] ? a[i] : b[i]; \
|
||||
} \
|
||||
LINMATH_H_FUNC void vec##n##_dup(vec##n r, vec##n const src) \
|
||||
{ \
|
||||
int i; \
|
||||
for (i = 0; i < n; ++i) \
|
||||
r[i] = src[i]; \
|
||||
}
|
||||
|
||||
LINMATH_H_DEFINE_VEC(2)
|
||||
LINMATH_H_DEFINE_VEC(3)
|
||||
LINMATH_H_DEFINE_VEC(4)
|
||||
|
||||
LINMATH_H_FUNC void vec3_set(vec3 r, float x, float y, float z)
|
||||
{
|
||||
r[0] = x;
|
||||
r[1] = y;
|
||||
r[2] = z;
|
||||
}
|
||||
|
||||
LINMATH_H_FUNC void vec3_mul_cross(vec3 r, vec3 const a, vec3 const b)
|
||||
{
|
||||
r[0] = a[1] * b[2] - a[2] * b[1];
|
||||
r[1] = a[2] * b[0] - a[0] * b[2];
|
||||
r[2] = a[0] * b[1] - a[1] * b[0];
|
||||
}
|
||||
|
||||
LINMATH_H_FUNC void vec3_reflect(vec3 r, vec3 const v, vec3 const n)
|
||||
{
|
||||
float p = 2.f * vec3_mul_inner(v, n);
|
||||
int i;
|
||||
for (i = 0; i < 3; ++i) {
|
||||
r[i] = v[i] - p * n[i];
|
||||
}
|
||||
}
|
||||
|
||||
LINMATH_H_FUNC void vec4_mul_cross(vec4 r, vec4 const a, vec4 const b)
|
||||
{
|
||||
r[0] = a[1] * b[2] - a[2] * b[1];
|
||||
r[1] = a[2] * b[0] - a[0] * b[2];
|
||||
r[2] = a[0] * b[1] - a[1] * b[0];
|
||||
r[3] = 1.f;
|
||||
}
|
||||
|
||||
LINMATH_H_FUNC void vec4_reflect(vec4 r, vec4 const v, vec4 const n)
|
||||
{
|
||||
float p = 2.f * vec4_mul_inner(v, n);
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
r[i] = v[i] - p * n[i];
|
||||
}
|
||||
}
|
||||
|
||||
typedef vec4 mat4x4[4];
|
||||
LINMATH_H_FUNC void mat4x4_identity(mat4x4 M)
|
||||
{
|
||||
int i, j;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
for (j = 0; j < 4; ++j) {
|
||||
M[i][j] = i == j ? 1.f : 0.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
LINMATH_H_FUNC void mat4x4_dup(mat4x4 M, mat4x4 const N)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
vec4_dup(M[i], N[i]);
|
||||
}
|
||||
}
|
||||
LINMATH_H_FUNC void mat4x4_row(vec4 r, mat4x4 const M, int i)
|
||||
{
|
||||
int k;
|
||||
for (k = 0; k < 4; ++k) {
|
||||
r[k] = M[k][i];
|
||||
}
|
||||
}
|
||||
LINMATH_H_FUNC void mat4x4_col(vec4 r, mat4x4 const M, int i)
|
||||
{
|
||||
int k;
|
||||
for (k = 0; k < 4; ++k) {
|
||||
r[k] = M[i][k];
|
||||
}
|
||||
}
|
||||
LINMATH_H_FUNC void mat4x4_transpose(mat4x4 M, mat4x4 const N)
|
||||
{
|
||||
// Note: if M and N are the same, the user has to
|
||||
// explicitly make a copy of M and set it to N.
|
||||
int i, j;
|
||||
for (j = 0; j < 4; ++j) {
|
||||
for (i = 0; i < 4; ++i) {
|
||||
M[i][j] = N[j][i];
|
||||
}
|
||||
}
|
||||
}
|
||||
LINMATH_H_FUNC void mat4x4_add(mat4x4 M, mat4x4 const a, mat4x4 const b)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
vec4_add(M[i], a[i], b[i]);
|
||||
}
|
||||
}
|
||||
LINMATH_H_FUNC void mat4x4_sub(mat4x4 M, mat4x4 const a, mat4x4 const b)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
vec4_sub(M[i], a[i], b[i]);
|
||||
}
|
||||
}
|
||||
LINMATH_H_FUNC void mat4x4_scale(mat4x4 M, mat4x4 const a, float k)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
vec4_scale(M[i], a[i], k);
|
||||
}
|
||||
}
|
||||
LINMATH_H_FUNC void mat4x4_scale_aniso(mat4x4 M, mat4x4 const a, float x, float y, float z)
|
||||
{
|
||||
vec4_scale(M[0], a[0], x);
|
||||
vec4_scale(M[1], a[1], y);
|
||||
vec4_scale(M[2], a[2], z);
|
||||
vec4_dup(M[3], a[3]);
|
||||
}
|
||||
LINMATH_H_FUNC void mat4x4_mul(mat4x4 M, mat4x4 const a, mat4x4 const b)
|
||||
{
|
||||
mat4x4 temp;
|
||||
int k, r, c;
|
||||
for (c = 0; c < 4; ++c) {
|
||||
for (r = 0; r < 4; ++r) {
|
||||
temp[c][r] = 0.f;
|
||||
for (k = 0; k < 4; ++k) {
|
||||
temp[c][r] += a[k][r] * b[c][k];
|
||||
}
|
||||
}
|
||||
}
|
||||
mat4x4_dup(M, temp);
|
||||
}
|
||||
LINMATH_H_FUNC void mat4x4_mul_vec4(vec4 r, mat4x4 const M, vec4 const v)
|
||||
{
|
||||
int i, j;
|
||||
for (j = 0; j < 4; ++j) {
|
||||
r[j] = 0.f;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
r[j] += M[i][j] * v[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
LINMATH_H_FUNC void mat4x4_translate(mat4x4 T, float x, float y, float z)
|
||||
{
|
||||
mat4x4_identity(T);
|
||||
T[3][0] = x;
|
||||
T[3][1] = y;
|
||||
T[3][2] = z;
|
||||
}
|
||||
LINMATH_H_FUNC void mat4x4_translate_in_place(mat4x4 M, float x, float y, float z)
|
||||
{
|
||||
vec4 t = {x, y, z, 0};
|
||||
vec4 r;
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
mat4x4_row(r, M, i);
|
||||
M[3][i] += vec4_mul_inner(r, t);
|
||||
}
|
||||
}
|
||||
LINMATH_H_FUNC void mat4x4_translate_in_place_v(mat4x4 M, vec3 v)
|
||||
{
|
||||
vec4 t = {v[0], v[1], v[2], 0};
|
||||
vec4 r;
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
mat4x4_row(r, M, i);
|
||||
M[3][i] += vec4_mul_inner(r, t);
|
||||
}
|
||||
}
|
||||
LINMATH_H_FUNC void mat4x4_from_vec3_mul_outer(mat4x4 M, vec3 const a, vec3 const b)
|
||||
{
|
||||
int i, j;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
for (j = 0; j < 4; ++j) {
|
||||
M[i][j] = i < 3 && j < 3 ? a[i] * b[j] : 0.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
LINMATH_H_FUNC void mat4x4_rotate(mat4x4 R, mat4x4 const M, float x, float y, float z, float angle)
|
||||
{
|
||||
float s = sinf(angle);
|
||||
float c = cosf(angle);
|
||||
vec3 u = {x, y, z};
|
||||
|
||||
if (vec3_len(u) > 1e-4) {
|
||||
vec3_norm(u, u);
|
||||
mat4x4 T;
|
||||
mat4x4_from_vec3_mul_outer(T, u, u);
|
||||
|
||||
mat4x4 S = {{0, u[2], -u[1], 0}, {-u[2], 0, u[0], 0}, {u[1], -u[0], 0, 0}, {0, 0, 0, 0}};
|
||||
mat4x4_scale(S, S, s);
|
||||
|
||||
mat4x4 C;
|
||||
mat4x4_identity(C);
|
||||
mat4x4_sub(C, C, T);
|
||||
|
||||
mat4x4_scale(C, C, c);
|
||||
|
||||
mat4x4_add(T, T, C);
|
||||
mat4x4_add(T, T, S);
|
||||
|
||||
T[3][3] = 1.f;
|
||||
mat4x4_mul(R, M, T);
|
||||
}
|
||||
else {
|
||||
mat4x4_dup(R, M);
|
||||
}
|
||||
}
|
||||
LINMATH_H_FUNC void mat4x4_rotate_X(mat4x4 Q, mat4x4 const M, float angle)
|
||||
{
|
||||
float s = sinf(angle);
|
||||
float c = cosf(angle);
|
||||
mat4x4 R = {{1.f, 0.f, 0.f, 0.f}, {0.f, c, s, 0.f}, {0.f, -s, c, 0.f}, {0.f, 0.f, 0.f, 1.f}};
|
||||
mat4x4_mul(Q, M, R);
|
||||
}
|
||||
LINMATH_H_FUNC void mat4x4_rotate_Y(mat4x4 Q, mat4x4 const M, float angle)
|
||||
{
|
||||
float s = sinf(angle);
|
||||
float c = cosf(angle);
|
||||
mat4x4 R = {{c, 0.f, -s, 0.f}, {0.f, 1.f, 0.f, 0.f}, {s, 0.f, c, 0.f}, {0.f, 0.f, 0.f, 1.f}};
|
||||
mat4x4_mul(Q, M, R);
|
||||
}
|
||||
LINMATH_H_FUNC void mat4x4_rotate_Z(mat4x4 Q, mat4x4 const M, float angle)
|
||||
{
|
||||
float s = sinf(angle);
|
||||
float c = cosf(angle);
|
||||
mat4x4 R = {{c, s, 0.f, 0.f}, {-s, c, 0.f, 0.f}, {0.f, 0.f, 1.f, 0.f}, {0.f, 0.f, 0.f, 1.f}};
|
||||
mat4x4_mul(Q, M, R);
|
||||
}
|
||||
LINMATH_H_FUNC void mat4x4_invert(mat4x4 T, mat4x4 const M)
|
||||
{
|
||||
float s[6];
|
||||
float c[6];
|
||||
s[0] = M[0][0] * M[1][1] - M[1][0] * M[0][1];
|
||||
s[1] = M[0][0] * M[1][2] - M[1][0] * M[0][2];
|
||||
s[2] = M[0][0] * M[1][3] - M[1][0] * M[0][3];
|
||||
s[3] = M[0][1] * M[1][2] - M[1][1] * M[0][2];
|
||||
s[4] = M[0][1] * M[1][3] - M[1][1] * M[0][3];
|
||||
s[5] = M[0][2] * M[1][3] - M[1][2] * M[0][3];
|
||||
|
||||
c[0] = M[2][0] * M[3][1] - M[3][0] * M[2][1];
|
||||
c[1] = M[2][0] * M[3][2] - M[3][0] * M[2][2];
|
||||
c[2] = M[2][0] * M[3][3] - M[3][0] * M[2][3];
|
||||
c[3] = M[2][1] * M[3][2] - M[3][1] * M[2][2];
|
||||
c[4] = M[2][1] * M[3][3] - M[3][1] * M[2][3];
|
||||
c[5] = M[2][2] * M[3][3] - M[3][2] * M[2][3];
|
||||
|
||||
/* Assumes it is invertible */
|
||||
float idet =
|
||||
1.0f / (s[0] * c[5] - s[1] * c[4] + s[2] * c[3] + s[3] * c[2] - s[4] * c[1] + s[5] * c[0]);
|
||||
|
||||
T[0][0] = (M[1][1] * c[5] - M[1][2] * c[4] + M[1][3] * c[3]) * idet;
|
||||
T[0][1] = (-M[0][1] * c[5] + M[0][2] * c[4] - M[0][3] * c[3]) * idet;
|
||||
T[0][2] = (M[3][1] * s[5] - M[3][2] * s[4] + M[3][3] * s[3]) * idet;
|
||||
T[0][3] = (-M[2][1] * s[5] + M[2][2] * s[4] - M[2][3] * s[3]) * idet;
|
||||
|
||||
T[1][0] = (-M[1][0] * c[5] + M[1][2] * c[2] - M[1][3] * c[1]) * idet;
|
||||
T[1][1] = (M[0][0] * c[5] - M[0][2] * c[2] + M[0][3] * c[1]) * idet;
|
||||
T[1][2] = (-M[3][0] * s[5] + M[3][2] * s[2] - M[3][3] * s[1]) * idet;
|
||||
T[1][3] = (M[2][0] * s[5] - M[2][2] * s[2] + M[2][3] * s[1]) * idet;
|
||||
|
||||
T[2][0] = (M[1][0] * c[4] - M[1][1] * c[2] + M[1][3] * c[0]) * idet;
|
||||
T[2][1] = (-M[0][0] * c[4] + M[0][1] * c[2] - M[0][3] * c[0]) * idet;
|
||||
T[2][2] = (M[3][0] * s[4] - M[3][1] * s[2] + M[3][3] * s[0]) * idet;
|
||||
T[2][3] = (-M[2][0] * s[4] + M[2][1] * s[2] - M[2][3] * s[0]) * idet;
|
||||
|
||||
T[3][0] = (-M[1][0] * c[3] + M[1][1] * c[1] - M[1][2] * c[0]) * idet;
|
||||
T[3][1] = (M[0][0] * c[3] - M[0][1] * c[1] + M[0][2] * c[0]) * idet;
|
||||
T[3][2] = (-M[3][0] * s[3] + M[3][1] * s[1] - M[3][2] * s[0]) * idet;
|
||||
T[3][3] = (M[2][0] * s[3] - M[2][1] * s[1] + M[2][2] * s[0]) * idet;
|
||||
}
|
||||
LINMATH_H_FUNC void mat4x4_orthonormalize(mat4x4 R, mat4x4 const M)
|
||||
{
|
||||
mat4x4_dup(R, M);
|
||||
float s = 1.f;
|
||||
vec3 h;
|
||||
|
||||
vec3_norm(R[2], R[2]);
|
||||
|
||||
s = vec3_mul_inner(R[1], R[2]);
|
||||
vec3_scale(h, R[2], s);
|
||||
vec3_sub(R[1], R[1], h);
|
||||
vec3_norm(R[1], R[1]);
|
||||
|
||||
s = vec3_mul_inner(R[0], R[2]);
|
||||
vec3_scale(h, R[2], s);
|
||||
vec3_sub(R[0], R[0], h);
|
||||
|
||||
s = vec3_mul_inner(R[0], R[1]);
|
||||
vec3_scale(h, R[1], s);
|
||||
vec3_sub(R[0], R[0], h);
|
||||
vec3_norm(R[0], R[0]);
|
||||
}
|
||||
|
||||
LINMATH_H_FUNC void mat4x4_frustum(mat4x4 M, float l, float r, float b, float t, float n, float f)
|
||||
{
|
||||
M[0][0] = 2.f * n / (r - l);
|
||||
M[0][1] = M[0][2] = M[0][3] = 0.f;
|
||||
|
||||
M[1][1] = 2.f * n / (t - b);
|
||||
M[1][0] = M[1][2] = M[1][3] = 0.f;
|
||||
|
||||
M[2][0] = (r + l) / (r - l);
|
||||
M[2][1] = (t + b) / (t - b);
|
||||
M[2][2] = -(f + n) / (f - n);
|
||||
M[2][3] = -1.f;
|
||||
|
||||
M[3][2] = -2.f * (f * n) / (f - n);
|
||||
M[3][0] = M[3][1] = M[3][3] = 0.f;
|
||||
}
|
||||
LINMATH_H_FUNC void mat4x4_ortho(mat4x4 M, float l, float r, float b, float t, float n, float f)
|
||||
{
|
||||
M[0][0] = 2.f / (r - l);
|
||||
M[0][1] = M[0][2] = M[0][3] = 0.f;
|
||||
|
||||
M[1][1] = 2.f / (t - b);
|
||||
M[1][0] = M[1][2] = M[1][3] = 0.f;
|
||||
|
||||
M[2][2] = -2.f / (f - n);
|
||||
M[2][0] = M[2][1] = M[2][3] = 0.f;
|
||||
|
||||
M[3][0] = -(r + l) / (r - l);
|
||||
M[3][1] = -(t + b) / (t - b);
|
||||
M[3][2] = -(f + n) / (f - n);
|
||||
M[3][3] = 1.f;
|
||||
}
|
||||
LINMATH_H_FUNC void mat4x4_perspective(mat4x4 m, float y_fov, float aspect, float n, float f)
|
||||
{
|
||||
/* NOTE: Degrees are an unhandy unit to work with.
|
||||
* linmath.h uses radians for everything! */
|
||||
float const a = 1.f / tanf(y_fov / 2.f);
|
||||
|
||||
m[0][0] = a / aspect;
|
||||
m[0][1] = 0.f;
|
||||
m[0][2] = 0.f;
|
||||
m[0][3] = 0.f;
|
||||
|
||||
m[1][0] = 0.f;
|
||||
m[1][1] = a;
|
||||
m[1][2] = 0.f;
|
||||
m[1][3] = 0.f;
|
||||
|
||||
m[2][0] = 0.f;
|
||||
m[2][1] = 0.f;
|
||||
m[2][2] = -((f + n) / (f - n));
|
||||
m[2][3] = -1.f;
|
||||
|
||||
m[3][0] = 0.f;
|
||||
m[3][1] = 0.f;
|
||||
m[3][2] = -((2.f * f * n) / (f - n));
|
||||
m[3][3] = 0.f;
|
||||
}
|
||||
LINMATH_H_FUNC void mat4x4_look_at(mat4x4 m, vec3 const eye, vec3 const center, vec3 const up)
|
||||
{
|
||||
/* Adapted from Android's OpenGL Matrix.java. */
|
||||
/* See the OpenGL GLUT documentation for gluLookAt for a description */
|
||||
/* of the algorithm. We implement it in a straightforward way: */
|
||||
|
||||
/* TODO: The negation of of can be spared by swapping the order of
|
||||
* operands in the following cross products in the right way. */
|
||||
vec3 f;
|
||||
vec3_sub(f, center, eye);
|
||||
vec3_norm(f, f);
|
||||
|
||||
vec3 s;
|
||||
vec3_mul_cross(s, f, up);
|
||||
vec3_norm(s, s);
|
||||
|
||||
vec3 t;
|
||||
vec3_mul_cross(t, s, f);
|
||||
|
||||
m[0][0] = s[0];
|
||||
m[0][1] = t[0];
|
||||
m[0][2] = -f[0];
|
||||
m[0][3] = 0.f;
|
||||
|
||||
m[1][0] = s[1];
|
||||
m[1][1] = t[1];
|
||||
m[1][2] = -f[1];
|
||||
m[1][3] = 0.f;
|
||||
|
||||
m[2][0] = s[2];
|
||||
m[2][1] = t[2];
|
||||
m[2][2] = -f[2];
|
||||
m[2][3] = 0.f;
|
||||
|
||||
m[3][0] = 0.f;
|
||||
m[3][1] = 0.f;
|
||||
m[3][2] = 0.f;
|
||||
m[3][3] = 1.f;
|
||||
|
||||
mat4x4_translate_in_place(m, -eye[0], -eye[1], -eye[2]);
|
||||
}
|
||||
|
||||
typedef float quat[4];
|
||||
#define quat_add vec4_add
|
||||
#define quat_sub vec4_sub
|
||||
#define quat_norm vec4_norm
|
||||
#define quat_scale vec4_scale
|
||||
#define quat_mul_inner vec4_mul_inner
|
||||
|
||||
LINMATH_H_FUNC void quat_identity(quat q)
|
||||
{
|
||||
q[0] = q[1] = q[2] = 0.f;
|
||||
q[3] = 1.f;
|
||||
}
|
||||
LINMATH_H_FUNC void quat_mul(quat r, quat const p, quat const q)
|
||||
{
|
||||
vec3 w, tmp;
|
||||
|
||||
vec3_mul_cross(tmp, p, q);
|
||||
vec3_scale(w, p, q[3]);
|
||||
vec3_add(tmp, tmp, w);
|
||||
vec3_scale(w, q, p[3]);
|
||||
vec3_add(tmp, tmp, w);
|
||||
|
||||
vec3_dup(r, tmp);
|
||||
r[3] = p[3] * q[3] - vec3_mul_inner(p, q);
|
||||
}
|
||||
LINMATH_H_FUNC void quat_conj(quat r, quat const q)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 3; ++i) {
|
||||
r[i] = -q[i];
|
||||
}
|
||||
r[3] = q[3];
|
||||
}
|
||||
LINMATH_H_FUNC void quat_rotate(quat r, float angle, vec3 const axis)
|
||||
{
|
||||
vec3 axis_norm;
|
||||
vec3_norm(axis_norm, axis);
|
||||
float s = sinf(angle / 2);
|
||||
float c = cosf(angle / 2);
|
||||
vec3_scale(r, axis_norm, s);
|
||||
r[3] = c;
|
||||
}
|
||||
LINMATH_H_FUNC void quat_mul_vec3(vec3 r, quat const q, vec3 const v)
|
||||
{
|
||||
/*
|
||||
* Method by Fabian 'ryg' Giessen (of Farbrausch)
|
||||
t = 2 * cross(q.xyz, v)
|
||||
v' = v + q.w * t + cross(q.xyz, t)
|
||||
*/
|
||||
vec3 t;
|
||||
vec3 q_xyz = {q[0], q[1], q[2]};
|
||||
vec3 u = {q[0], q[1], q[2]};
|
||||
|
||||
vec3_mul_cross(t, q_xyz, v);
|
||||
vec3_scale(t, t, 2);
|
||||
|
||||
vec3_mul_cross(u, q_xyz, t);
|
||||
vec3_scale(t, t, q[3]);
|
||||
|
||||
vec3_add(r, v, t);
|
||||
vec3_add(r, r, u);
|
||||
}
|
||||
LINMATH_H_FUNC void mat4x4_from_quat(mat4x4 M, quat const q)
|
||||
{
|
||||
float a = q[3];
|
||||
float b = q[0];
|
||||
float c = q[1];
|
||||
float d = q[2];
|
||||
float a2 = a * a;
|
||||
float b2 = b * b;
|
||||
float c2 = c * c;
|
||||
float d2 = d * d;
|
||||
|
||||
M[0][0] = a2 + b2 - c2 - d2;
|
||||
M[0][1] = 2.f * (b * c + a * d);
|
||||
M[0][2] = 2.f * (b * d - a * c);
|
||||
M[0][3] = 0.f;
|
||||
|
||||
M[1][0] = 2 * (b * c - a * d);
|
||||
M[1][1] = a2 - b2 + c2 - d2;
|
||||
M[1][2] = 2.f * (c * d + a * b);
|
||||
M[1][3] = 0.f;
|
||||
|
||||
M[2][0] = 2.f * (b * d + a * c);
|
||||
M[2][1] = 2.f * (c * d - a * b);
|
||||
M[2][2] = a2 - b2 - c2 + d2;
|
||||
M[2][3] = 0.f;
|
||||
|
||||
M[3][0] = M[3][1] = M[3][2] = 0.f;
|
||||
M[3][3] = 1.f;
|
||||
}
|
||||
|
||||
LINMATH_H_FUNC void mat4x4o_mul_quat(mat4x4 R, mat4x4 const M, quat const q)
|
||||
{
|
||||
/* XXX: The way this is written only works for orthogonal matrices. */
|
||||
/* TODO: Take care of non-orthogonal case. */
|
||||
quat_mul_vec3(R[0], q, M[0]);
|
||||
quat_mul_vec3(R[1], q, M[1]);
|
||||
quat_mul_vec3(R[2], q, M[2]);
|
||||
|
||||
R[3][0] = R[3][1] = R[3][2] = 0.f;
|
||||
R[0][3] = M[0][3];
|
||||
R[1][3] = M[1][3];
|
||||
R[2][3] = M[2][3];
|
||||
R[3][3] = M[3][3]; // typically 1.0, but here we make it general
|
||||
}
|
||||
LINMATH_H_FUNC void quat_from_mat4x4(quat q, mat4x4 const M)
|
||||
{
|
||||
float r = 0.f;
|
||||
int i;
|
||||
|
||||
int perm[] = {0, 1, 2, 0, 1};
|
||||
int* p = perm;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
float m = M[i][i];
|
||||
if (m < r) {
|
||||
continue;
|
||||
}
|
||||
m = r;
|
||||
p = &perm[i];
|
||||
}
|
||||
|
||||
r = sqrtf(1.f + M[p[0]][p[0]] - M[p[1]][p[1]] - M[p[2]][p[2]]);
|
||||
|
||||
if (r < 1e-6) {
|
||||
q[0] = 1.f;
|
||||
q[1] = q[2] = q[3] = 0.f;
|
||||
return;
|
||||
}
|
||||
|
||||
q[0] = r / 2.f;
|
||||
q[1] = (M[p[0]][p[1]] - M[p[1]][p[0]]) / (2.f * r);
|
||||
q[2] = (M[p[2]][p[0]] - M[p[0]][p[2]]) / (2.f * r);
|
||||
q[3] = (M[p[2]][p[1]] - M[p[1]][p[2]]) / (2.f * r);
|
||||
}
|
||||
|
||||
LINMATH_H_FUNC void mat4x4_arcball(mat4x4 R, mat4x4 const M, vec2 const _a, vec2 const _b, float s)
|
||||
{
|
||||
vec2 a;
|
||||
memcpy(a, _a, sizeof(a));
|
||||
vec2 b;
|
||||
memcpy(b, _b, sizeof(b));
|
||||
|
||||
float z_a = 0.;
|
||||
float z_b = 0.;
|
||||
|
||||
if (vec2_len(a) < 1.) {
|
||||
z_a = sqrtf(1.f - vec2_mul_inner(a, a));
|
||||
}
|
||||
else {
|
||||
vec2_norm(a, a);
|
||||
}
|
||||
|
||||
if (vec2_len(b) < 1.f) {
|
||||
z_b = sqrtf(1.f - vec2_mul_inner(b, b));
|
||||
}
|
||||
else {
|
||||
vec2_norm(b, b);
|
||||
}
|
||||
|
||||
vec3 a_ = {a[0], a[1], z_a};
|
||||
vec3 b_ = {b[0], b[1], z_b};
|
||||
|
||||
vec3 c_;
|
||||
vec3_mul_cross(c_, a_, b_);
|
||||
|
||||
float const angle = acosf(vec3_mul_inner(a_, b_)) * s;
|
||||
mat4x4_rotate(R, M, c_[0], c_[1], c_[2], angle);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,8 +1,9 @@
|
||||
|
||||
add_subdirectory(App)
|
||||
# if(BUILD_GUI)
|
||||
# add_subdirectory(Gui)
|
||||
# endif(BUILD_GUI)
|
||||
add_subdirectory(AppGL)
|
||||
#if(BUILD_GUI)
|
||||
# add_subdirectory(Gui)
|
||||
#endif(BUILD_GUI)
|
||||
|
||||
# install(
|
||||
# FILES
|
||||
|
||||