/** * */ package org.goko.core.gcode.rs274ngcv3.modifier.segmentize; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import org.goko.core.common.exception.GkException; import org.goko.core.common.measure.quantity.Angle; import org.goko.core.common.measure.quantity.AngleUnit; import org.goko.core.common.measure.quantity.Length; import org.goko.core.common.measure.quantity.LengthUnit; import org.goko.core.gcode.element.GCodeLine; import org.goko.core.gcode.element.IGCodeProvider; import org.goko.core.gcode.element.IInstructionSetIterator; import org.goko.core.gcode.rs274ngcv3.context.GCodeContext; import org.goko.core.gcode.rs274ngcv3.element.GCodeProvider; import org.goko.core.gcode.rs274ngcv3.element.IModifier; import org.goko.core.gcode.rs274ngcv3.element.InstructionProvider; import org.goko.core.gcode.rs274ngcv3.element.InstructionSet; import org.goko.core.gcode.rs274ngcv3.element.InstructionType; import org.goko.core.gcode.rs274ngcv3.instruction.AbstractInstruction; import org.goko.core.gcode.rs274ngcv3.instruction.ArcFeedInstruction; import org.goko.core.gcode.rs274ngcv3.instruction.StraightFeedInstruction; import org.goko.core.gcode.rs274ngcv3.modifier.AbstractModifier; import org.goko.core.gcode.rs274ngcv3.utils.InstructionUtils; import org.goko.core.math.Arc3b; import org.goko.core.math.Tuple6b; /** * @author PsyKo * @date 16 janv. 2016 */ public class SegmentizeModifier extends AbstractModifier<GCodeProvider> implements IModifier<GCodeProvider>{ public static final String MODIFIER_NAME = "Segmentize"; private Length chordalTolerance; /** * Constructeur */ public SegmentizeModifier() { super(MODIFIER_NAME); this.chordalTolerance = Length.valueOf("0.1", LengthUnit.MILLIMETRE); } /** * @param idGCodeProvider * @param modifierName */ public SegmentizeModifier(Integer idGCodeProvider) { super(idGCodeProvider, MODIFIER_NAME); this.chordalTolerance = Length.valueOf("0.1", LengthUnit.MILLIMETRE); } /** (inheritDoc) * @see org.goko.core.gcode.rs274ngcv3.element.IModifier#isConfigured() */ @Override public boolean isConfigured() { return chordalTolerance != null && !chordalTolerance.equals(Length.ZERO); } /** (inheritDoc) * @see org.goko.core.gcode.rs274ngcv3.modifier.AbstractModifier#applyModifier(org.goko.core.gcode.element.IGCodeProvider, org.goko.core.gcode.rs274ngcv3.element.GCodeProvider) */ @Override protected void applyModifier(IGCodeProvider source, GCodeProvider target) throws GkException { GCodeContext localContext = new GCodeContext(); InstructionProvider sourceInstructionSet = getRS274NGCService().getInstructions(localContext, source); InstructionProvider resultInstructionProvider = new InstructionProvider(); IInstructionSetIterator<GCodeContext, AbstractInstruction> iterator = getRS274NGCService().getIterator(sourceInstructionSet, localContext); while(iterator.hasNext()){ localContext = new GCodeContext(iterator.getContext()); // Get the context before applying the command AbstractInstruction instr = iterator.next(); if(instr.getType() == InstructionType.ARC_FEED){ resultInstructionProvider.addInstructionSet(applyModifier(localContext, (ArcFeedInstruction) instr)); }else{ // Other non modified instruction InstructionSet resultInstructionSet = new InstructionSet(); resultInstructionSet.addInstruction(instr); resultInstructionProvider.addInstructionSet(resultInstructionSet); } } GCodeProvider result = getRS274NGCService().getGCodeProvider(new GCodeContext(), resultInstructionProvider); for (GCodeLine line : result.getLines()) { target.addLine(line); } } /** * Segmentize the given arc feed instruction * @param context the gcode context * @param instruction the instruction to modify * @return a list of instruction set */ private List<InstructionSet> applyModifier(GCodeContext context, ArcFeedInstruction instruction) { List<InstructionSet> result = new ArrayList<>(); Arc3b arc = InstructionUtils.getArc(context, instruction); int division = 0; // We only subdivide if the arc radius is greater than the chordal tolerance if(arc.getRadius().greaterThan(chordalTolerance)){ // Get the arc angle for the given tolerance using h = R ( 1 - cos (A/2)) (aka A = 2*acos(1 - (h / R)) double angle = 2 * Math.acos( 1 - chordalTolerance.divide(arc.getRadius()).doubleValue() ); BigDecimal nbCount = arc.getAngle().abs().divide(Angle.valueOf(BigDecimal.valueOf(angle).abs(), AngleUnit.RADIAN)); division = (int) Math.ceil(nbCount.doubleValue()); } for(int i = 1; i < division; i++){ InstructionSet set = new InstructionSet(); Tuple6b pt = arc.point( (float)i/division ); StraightFeedInstruction straightInstruction = new StraightFeedInstruction(pt.getX(), pt.getY(), pt.getZ(), instruction.getA(), instruction.getB(), instruction.getC()); set.addInstruction(straightInstruction); result.add(set); } // Add the very end point of the instruction so it always ends at the exact location Tuple6b pt = arc.point( 1.0f ); StraightFeedInstruction straightInstruction = new StraightFeedInstruction(pt.getX(), pt.getY(), pt.getZ(), instruction.getA(), instruction.getB(), instruction.getC()); // switch (context.getPlane()) { // case XZ_PLANE: straightInstruction = new StraightFeedInstruction(instruction.getSecondEnd(), instruction.getAxisEndPoint(), instruction.getFirstEnd(), instruction.getA(), instruction.getB(), instruction.getC()); // break; // case YZ_PLANE: straightInstruction = new StraightFeedInstruction(instruction.getAxisEndPoint(), instruction.getFirstEnd(), instruction.getSecondEnd(), instruction.getA(), instruction.getB(), instruction.getC()); // break; // case XY_PLANE: straightInstruction = new StraightFeedInstruction(instruction.getFirstEnd(), instruction.getSecondEnd(), instruction.getAxisEndPoint(), instruction.getA(), instruction.getB(), instruction.getC()); // default: // break; // } InstructionSet set = new InstructionSet(); set.addInstruction(straightInstruction); result.add(set); return result; } /** * @return the chordalTolerance */ public Length getChordalTolerance() { return chordalTolerance; } /** * @param chordalTolerance the chordalTolerance to set */ public void setChordalTolerance(Length chordalTolerance) { this.chordalTolerance = chordalTolerance; } }