Пример #1
0
	def zigZagLine(self, block, pos, du, dv, U, V, n, extra=0.):
		sgn = math.copysign(1.0, n)
		n   = abs(n)

		# Make additional overcut/cuts to compensate for the
		# round edges in the inner teeths
		if self.r > 0.0:
			overcut = self.overcut
			#rd = (sqrt(2.)-1.0) * self.r
			rd = (1.0-1.0/sqrt(2.)) * (1.0+self.overcutAdd) * self.r
		else:
			overcut = None

		for i in range(n):
#			if sgn<0.0 and overcut=="U":
#				pos -= self.r*U
#				block.append(CNC.glinev(1, pos, self.feed))
#				pos += self.r*U
#				block.append(CNC.glinev(1, pos))

			x = du
			if sgn<0.0 and n>1:
				if 0 < i < n-1:
					x -= 2*self.r
				else:
					x -= self.r
			if i==0:
				x += extra
			elif i==n-1:
				x += extra

			pos += x*U


			if i==0:
				block.append(CNC.glinev(1, pos, self.feed))
			else:
				block.append(CNC.glinev(1, pos))

#			if sgn<0.0 and overcut=="U":
#				pos += self.r*U
#				block.append(CNC.glinev(1, pos))
#				pos -= self.r*U
#				block.append(CNC.glinev(1, pos))

			if self.r>0.0:
				if sgn<0.0:
					if i<n-1:
						if overcut == "V":
							pos -= sgn*self.r*V
							block.append(CNC.glinev(1, pos))
							pos += sgn*dv*V
						elif overcut == "D":
							pos -= sgn*rd*(U+V)
							block.append(CNC.glinev(1, pos))
							pos += sgn*rd*(U+V)
							block.append(CNC.glinev(1, pos))
							pos += sgn*(dv-self.r)*V

#						else:
#							pos += sgn*(dv-self.r)*V
						block.append(CNC.glinev(1, pos))
						ijk = self.r*U
						pos += sgn*self.r*V + self.r*U
						block.append(CNC.garcv(3, pos, ijk))
					else:
						# ending
						ijk = self.r*V
						pos += self.r*V + self.r*U
						block.append(CNC.garcv(3, pos, ijk))

				elif sgn>0.0:
					ijk = sgn*self.r*V
					pos += sgn*self.r*V + self.r*U
					block.append(CNC.garcv(3, pos, ijk))
					if i<n-1:
						if overcut == "V":
							pos += sgn*dv*V
							block.append(CNC.glinev(1, pos))
							if self.r > 0.0:
								pos -= sgn*self.r*V
								block.append(CNC.glinev(1, pos))
						elif overcut == "D":
							pos += sgn*(dv-self.r)*V
							block.append(CNC.glinev(1, pos))
							if self.r > 0.0:
								pos -= sgn*rd*(U-V)
								block.append(CNC.glinev(1, pos))
								pos += sgn*rd*(U-V)
								block.append(CNC.glinev(1, pos))
#						else:
#							pos += sgn*(dv-self.r)*V
#							block.append(CNC.glinev(1, pos))

			elif i<n-1:
				pos += sgn*dv*V
				block.append(CNC.glinev(1, pos))
			sgn = -sgn

		return pos
Пример #2
0
    def execute(self, app):

        n = self["name"]
        if not n or n == "default": n = "Pyrograph"

        #Import parameters
        toolSize = self.fromMm("ToolSize")

        if toolSize <= 0:
            app.setStatus(_("Pyrograph abort: Tool Size must be > 0"))
            return

        filename = self["File"]

        #Open gcode file
        if not (filename == ""):
            app.load(filename)

        inOut = self["In-Out"]
        xadd = self["xAdd"]
        yadd = self["yAdd"]
        if xadd == "": xadd = 1
        if yadd == "": yadd = 1

        #Create the external box
        if inOut == "Out":
            box = Block("Box")
            external_box = []
            box.append(
                CNC.grapid(CNC.vars["xmin"] - xadd, CNC.vars["ymin"] - yadd))
            box.append(
                CNC.gline(CNC.vars["xmin"] - xadd, CNC.vars["ymax"] + yadd))
            box.append(
                CNC.gline(CNC.vars["xmax"] + xadd, CNC.vars["ymax"] + yadd))
            box.append(
                CNC.gline(CNC.vars["xmax"] + xadd, CNC.vars["ymin"] - yadd))
            box.append(
                CNC.gline(CNC.vars["xmin"] - xadd, CNC.vars["ymin"] - yadd))

            #Insert the external block
            external_box.append(box)
            app.gcode.insBlocks(1, external_box, "External_Box")
            app.refresh()

        #Value for creating an offset from the margins of the gcode
        margin = self.fromMm(
            "Margin"
        )  #GIVING RANDOM DECIMALS SHOULD AVOID COINCIDENT SEGMENTS BETWEEN ISLAND AND BASE PATHS THAT CONFUSE THE ALGORITHM. WORKS IN MOST CASES.

        #Add and subtract the margin
        max_x = CNC.vars["xmax"] + margin
        min_x = CNC.vars["xmin"] - margin
        max_y = CNC.vars["ymax"] + margin
        min_y = CNC.vars["ymin"] - margin

        #Difference between offtset margins
        dx = max_x - min_x
        dy = max_y - min_y

        #Number of vertical divisions according to the toolsize
        divisions = dy / toolSize

        #Distance between horizontal lines
        step_y = toolSize
        n_steps_y = int(divisions) + 1

        #Create the snake pattern according to the number of divisions
        pattern = Block(self.name)
        pattern_base = []

        for n in range(n_steps_y):
            if n == 0:
                pattern.append(CNC.grapid(min_x, min_y))  #go to bottom left
            else:
                y0 = min_y + step_y * (n - 1)
                y1 = min_y + step_y * (n)
                if not (n % 2 == 0):
                    pattern.append(CNC.glinev(
                        1, [max_x, y0]))  #write odd lines from left to right
                    pattern.append(CNC.grapid(max_x, y1))
                else:
                    pattern.append(CNC.glinev(
                        1, [min_x, y0]))  #write even lines from right to left
                    pattern.append(CNC.grapid(min_x, y1))

        #Insert the pattern block
        pattern_base.append(pattern)
        app.gcode.insBlocks(1, pattern_base, "pattern")
        app.refresh()

        #Mark pattern as island
        for bid in pattern_base:
            app.gcode.island([1])

        #Select all blocks
        app.editor.selectAll()

        paths_base = []
        paths_isl = []

        points = []

        #Compare blocks to separate island from other blocks
        for bid in app.editor.getSelectedBlocks():
            if app.gcode[bid].operationTest('island'):
                paths_isl.extend(app.gcode.toPath(bid))
            else:
                paths_base.extend(app.gcode.toPath(bid))

        #Make intersection between blocks
        while len(paths_base) > 0:
            base = paths_base.pop()
            for island in paths_isl:
                #points.extend(base.intersectPath(island))
                points.extend(island.intersectPath(base))

###SORTING POINTS###
        x = []
        y = []

        #Get (x,y) intersection points
        for i in range(len(points)):
            x.append(points[i][2][0])
            y.append(points[i][2][1])

        #Save (x,y) intersection points in a matrix
        matrix = [[0 for i in range(2)] for j in range(len(x))]

        for i in range(len(x)):
            matrix[i][0] = x[i]
            matrix[i][1] = y[i]

        # for i in range(len(x)):
        # 	print('puntos',points[i][0],points[i][1],matrix[i][0], matrix[i][1])

        #print(matrix)

        #Sort points in increasing y coordinate
        matrix.sort(key=itemgetter(1, 0), reverse=False)

        # for i in range(len(x)):
        # 	print('puntos',points[i][0],points[i][1],matrix[i][0], matrix[i][1])
        #print(matrix)

        index = 0
        pair = 0
        new_matrix = []
        for i in range(len(x)):
            if i == 0:
                index = index + 1
            elif i < len(x) - 1:
                if matrix[i][1] == matrix[i - 1][1]:
                    index = index + 1
                else:
                    if pair % 2 == 0:
                        logic = False
                    else:
                        logic = True
                    submatrix = matrix[i - index:i]
                    submatrix.sort(key=itemgetter(0, 1), reverse=logic)
                    new_matrix.extend(submatrix)
                    index = 1
                    pair = pair + 1
            else:
                #print('entered')
                if pair % 2 == 0:
                    logic = False
                else:
                    logic = True
                if matrix[i][1] == matrix[i - 1][1]:
                    submatrix = matrix[i - index:]
                    submatrix.sort(key=itemgetter(0, 1), reverse=logic)
                    new_matrix.extend(submatrix)
                else:
                    index = 1
                    submatrix = matrix[-1]
                    new_matrix.extend(submatrix)

        # for i in range(len(x)):
        # 	print('puntos',new_matrix[i][0], new_matrix[i][1])

        # for i in range(len(x)):
        # 	print('puntos',new_matrix[i][0], new_matrix[i][1])
        #print(x, y)

###SORTING POINTS END###

#Generate the gcode from points obtained
        blocks = []
        block = Block(self.name)

        for i in range(len(x)):
            if i == 0:
                block.append(CNC.grapid(new_matrix[0][0], new_matrix[0][1]))
                inside = 0
            else:
                if inside == 0:
                    block.append(CNC.gline(new_matrix[i][0], new_matrix[i][1]))
                    inside = 1
                else:
                    block.append(CNC.grapid(new_matrix[i][0],
                                            new_matrix[i][1]))
                    inside = 0

        # for i in range(len(x)):
        # 	print('puntos',x[i], y[i])

        blocks.append(block)
        app.gcode.delBlockUndo(1)
        app.gcode.insBlocks(1, blocks, "Line to Line Burning")

        app.editor.disable()

        for block in blocks:
            block.enable = 1

        #app.editor.enable()
        #app.editor.unselectAll()
        app.refresh()
        app.setStatus(_("Generated Line to Line Burning"))
Пример #3
0
	def execute(self, app):
		try:
			import midiparser as midiparser
		except:
			app.setStatus(_("Error: This plugin requires midiparser.py"))
			return

		n = self["name"]
		if not n or n=="default": n="Midi2CNC"

		fileName = self["File"]

		x=0.0
		y=0.0
		z=0.0

		x_dir=1.0;
		y_dir=1.0;
		z_dir=1.0;

		# List of MIDI channels (instruments) to import.
		# Channel 10 is percussion, so better to omit it
		channels = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] 

		axes = self["AxisUsed"]
		active_axes = len(axes)

		transpose = (0,0,0)
		ppu = [ 200, 200, 200 ]
		ppu[0] = self["ppu_X"]
		ppu[1] = self["ppu_X"]
		ppu[2] = self["ppu_X"]

		safemin = [ 0, 0, 0 ]
		safemax = [ 100, 100, 50 ]
		safemax[0] = self["max_X"]
		safemax[1] = self["max_Y"]
		safemax[2] = self["max_Z"]

		try:
			midi = midiparser.File(fileName)
		except:
			app.setStatus(_("Error: Sorry can't parse the Midi file."))
			return

		noteEventList=[]
		all_channels=set()

		for track in midi.tracks:
			#channels=set()
			for event in track.events:
				if event.type == midiparser.meta.SetTempo:
					tempo=event.detail.tempo

				# filter undesired instruments
				if ((event.type == midiparser.voice.NoteOn) and (event.channel in channels)):

					if event.channel not in channels:
						channels.add(event.channel)

					# NB: looks like some use "note on (vel 0)" as equivalent to note off, so check for vel=0 here and treat it as a note-off.
					if event.detail.velocity > 0:
						noteEventList.append([event.absolute, 1, event.detail.note_no, event.detail.velocity])
					else:
						noteEventList.append([event.absolute, 0, event.detail.note_no, event.detail.velocity])

				if (event.type == midiparser.voice.NoteOff) and (event.channel in channels):
					if event.channel not in channels:
						channels.add(event.channel)
					noteEventList.append([event.absolute, 0, event.detail.note_no, event.detail.velocity])

			# Finished with this track
			if len(channels) > 0:
				msg=', ' . join(['%2d' % ch for ch in sorted(channels)])
				#print 'Processed track %d, containing channels numbered: [%s ]' % (track.number, msg)
				all_channels = all_channels.union(channels)

		# List all channels encountered
		if len(all_channels) > 0:
			msg=', ' . join(['%2d' % ch for ch in sorted(all_channels)])
			#print 'The file as a whole contains channels numbered: [%s ]' % msg

		# We now have entire file's notes with abs time from all channels
		# We don't care which channel/voice is which, but we do care about having all the notes in order
		# so sort event list by abstime to dechannelify

		noteEventList.sort()
		# print noteEventList
		# print len(noteEventList)

		last_time=-0
		active_notes={} # make this a dict so we can add and remove notes by name

		# Start the output
		#Init blocks
		blocks = []
		block = Block(self.name)
		block.append("(Midi2CNC)")
		block.append("(Midi:%s)" % fileName)
		block.append(CNC.zsafe())
		block.append(CNC.grapid(0,0))
		block.append(CNC.zenter(0))

		for note in noteEventList:
			# note[timestamp, note off/note on, note_no, velocity]
			if last_time < note[0]:

				freq_xyz=[0,0,0]
				feed_xyz=[0,0,0]
				distance_xyz=[0,0,0]
				duration=0

				# "i" ranges from 0 to "the number of active notes *or* the number of active axes,
				# whichever is LOWER". Note that the range operator stops
				# short of the maximum, so this means 0 to 2 at most for a 3-axis machine.
				# E.g. only look for the first few active notes to play despite what
				# is going on in the actual score.

				for i in range(0, min(len(active_notes.values()), active_axes)):

					# Which axis are should we be writing to?
					#
					j = self.axes_dict.get(axes)[i]

					# Debug
					# print"Axes %s: item %d is %d" % (axes_dict.get(args.axes), i, j)

					# Sound higher pitched notes first by sorting by pitch then indexing by axis
					#
					nownote=sorted(active_notes.values(), reverse=True)[i]

					# MIDI note 69	 = A4(440Hz)
					# 2 to the power (69-69) / 12 * 440 = A4 440Hz
					# 2 to the power (64-69) / 12 * 440 = E4 329.627Hz
					#
					freq_xyz[j] = pow(2.0, (nownote-69 + transpose[j])/12.0)*440.0

					# Here is where we need smart per-axis feed conversions
					# to enable use of X/Y *and* Z on a Makerbot
					#
					# feed_xyz[0] = X; feed_xyz[1] = Y; feed_xyz[2] = Z;
					#
					# Feed rate is expressed in mm / minutes so 60 times
					# scaling factor is required.

					feed_xyz[j] = ( freq_xyz[j] * 60.0 ) / ppu[j]

					# Get the duration in seconds from the MIDI values in divisions, at the given tempo
					duration = ( ( ( note[0] - last_time ) + 0.0 ) / ( midi.division + 0.0 ) * ( tempo / 1000000.0 ) )

					# Get the actual relative distance travelled per axis in mm
					distance_xyz[j] = ( feed_xyz[j] * duration ) / 60.0

				# Now that axes can be addressed in any order, need to make sure
				# that all of them are silent before declaring a rest is due.
				if distance_xyz[0] + distance_xyz[1] + distance_xyz[2] > 0:
					# At least one axis is playing, so process the note into
					# movements
					combined_feedrate = math.sqrt(feed_xyz[0]**2 + feed_xyz[1]**2 + feed_xyz[2]**2)

					# Turn around BEFORE crossing the limits of the
					# safe working envelope
					if self.reached_limit( x, distance_xyz[0], x_dir, safemin[0], safemax[0] ):
						x_dir = x_dir * -1
					x = (x + (distance_xyz[0] * x_dir))

					if self.reached_limit( y, distance_xyz[1], y_dir, safemin[1], safemax[1] ):
						y_dir = y_dir * -1
					y = (y + (distance_xyz[1] * y_dir))

					if self.reached_limit( z, distance_xyz[2], z_dir, safemin[2], safemax[2] ):
						z_dir = z_dir * -1
					z = (z + (distance_xyz[2] * z_dir))

					v = (x,y,z)
					block.append(CNC.glinev(1,v,combined_feedrate))

				else:
					# Handle 'rests' in addition to notes.
					duration = (((note[0]-last_time)+0.0)/(midi.division+0.0)) * (tempo/1000000.0)
					block.append(CNC.gcode(4, [("P",duration)]))

				# finally, set this absolute time as the new starting time
				last_time = note[0]

			if note[1]==1: # Note on
				if active_notes.has_key(note[2]):
					pass
				else:
					# key and value are the same, but we don't really care.
					active_notes[note[2]]=note[2]
			elif note[1]==0: # Note off
				if(active_notes.has_key(note[2])):
					active_notes.pop(note[2])

		blocks.append(block)
		active = app.activeBlock()
		if active==0: active=1
		app.gcode.insBlocks(active, blocks, "Midi2CNC")
		app.refresh()
		app.setStatus(_("Generated Midi2CNC, ready to play?"))
Пример #4
0
    def execute(self, app):
        try:
            import midiparser as midiparser
        except:
            app.setStatus(_("Error: This plugin requires midiparser.py"))
            return

        n = self["name"]
        if not n or n == "default": n = "Midi2CNC"

        fileName = self["File"]

        x = 0.0
        y = 0.0
        z = 0.0

        x_dir = 1.0
        y_dir = 1.0
        z_dir = 1.0

        # List of MIDI channels (instruments) to import.
        # Channel 10 is percussion, so better to omit it
        channels = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]

        axes = self["AxisUsed"]
        active_axes = len(axes)

        transpose = (0, 0, 0)
        ppu = [200, 200, 200]
        ppu[0] = self["ppu_X"]
        ppu[1] = self["ppu_X"]
        ppu[2] = self["ppu_X"]

        safemin = [0, 0, 0]
        safemax = [100, 100, 50]
        safemax[0] = self["max_X"]
        safemax[1] = self["max_Y"]
        safemax[2] = self["max_Z"]

        try:
            midi = midiparser.File(fileName)
        except:
            app.setStatus(_("Error: Sorry can't parse the Midi file."))
            return

        noteEventList = []
        all_channels = set()

        for track in midi.tracks:
            #channels=set()
            for event in track.events:
                if event.type == midiparser.meta.SetTempo:
                    tempo = event.detail.tempo

                # filter undesired instruments
                if ((event.type == midiparser.voice.NoteOn)
                        and (event.channel in channels)):

                    if event.channel not in channels:
                        channels.add(event.channel)

                    # NB: looks like some use "note on (vel 0)" as equivalent to note off, so check for vel=0 here and treat it as a note-off.
                    if event.detail.velocity > 0:
                        noteEventList.append([
                            event.absolute, 1, event.detail.note_no,
                            event.detail.velocity
                        ])
                    else:
                        noteEventList.append([
                            event.absolute, 0, event.detail.note_no,
                            event.detail.velocity
                        ])

                if (event.type == midiparser.voice.NoteOff) and (event.channel
                                                                 in channels):
                    if event.channel not in channels:
                        channels.add(event.channel)
                    noteEventList.append([
                        event.absolute, 0, event.detail.note_no,
                        event.detail.velocity
                    ])

            # Finished with this track
            if len(channels) > 0:
                msg = ', '.join(['%2d' % ch for ch in sorted(channels)])
                #print 'Processed track %d, containing channels numbered: [%s ]' % (track.number, msg)
                all_channels = all_channels.union(channels)

        # List all channels encountered
        if len(all_channels) > 0:
            msg = ', '.join(['%2d' % ch for ch in sorted(all_channels)])
            #print 'The file as a whole contains channels numbered: [%s ]' % msg

        # We now have entire file's notes with abs time from all channels
        # We don't care which channel/voice is which, but we do care about having all the notes in order
        # so sort event list by abstime to dechannelify

        noteEventList.sort()
        # print noteEventList
        # print len(noteEventList)

        last_time = -0
        active_notes = {
        }  # make this a dict so we can add and remove notes by name

        # Start the output
        #Init blocks
        blocks = []
        block = Block(self.name)
        block.append("(Midi2CNC)")
        block.append("(Midi:%s)" % fileName)
        block.append(CNC.zsafe())
        block.append(CNC.grapid(0, 0))
        block.append(CNC.zenter(0))

        for note in noteEventList:
            # note[timestamp, note off/note on, note_no, velocity]
            if last_time < note[0]:

                freq_xyz = [0, 0, 0]
                feed_xyz = [0, 0, 0]
                distance_xyz = [0, 0, 0]
                duration = 0

                # "i" ranges from 0 to "the number of active notes *or* the number of active axes,
                # whichever is LOWER". Note that the range operator stops
                # short of the maximum, so this means 0 to 2 at most for a 3-axis machine.
                # E.g. only look for the first few active notes to play despite what
                # is going on in the actual score.

                for i in range(0, min(len(active_notes.values()),
                                      active_axes)):

                    # Which axis are should we be writing to?
                    #
                    j = self.axes_dict.get(axes)[i]

                    # Debug
                    # print"Axes %s: item %d is %d" % (axes_dict.get(args.axes), i, j)

                    # Sound higher pitched notes first by sorting by pitch then indexing by axis
                    #
                    nownote = sorted(active_notes.values(), reverse=True)[i]

                    # MIDI note 69	 = A4(440Hz)
                    # 2 to the power (69-69) / 12 * 440 = A4 440Hz
                    # 2 to the power (64-69) / 12 * 440 = E4 329.627Hz
                    #
                    freq_xyz[j] = pow(
                        2.0, (nownote - 69 + transpose[j]) / 12.0) * 440.0

                    # Here is where we need smart per-axis feed conversions
                    # to enable use of X/Y *and* Z on a Makerbot
                    #
                    # feed_xyz[0] = X; feed_xyz[1] = Y; feed_xyz[2] = Z;
                    #
                    # Feed rate is expressed in mm / minutes so 60 times
                    # scaling factor is required.

                    feed_xyz[j] = (freq_xyz[j] * 60.0) / ppu[j]

                    # Get the duration in seconds from the MIDI values in divisions, at the given tempo
                    duration = (((note[0] - last_time) + 0.0) /
                                (midi.division + 0.0) * (tempo / 1000000.0))

                    # Get the actual relative distance travelled per axis in mm
                    distance_xyz[j] = (feed_xyz[j] * duration) / 60.0

                # Now that axes can be addressed in any order, need to make sure
                # that all of them are silent before declaring a rest is due.
                if distance_xyz[0] + distance_xyz[1] + distance_xyz[2] > 0:
                    # At least one axis is playing, so process the note into
                    # movements
                    combined_feedrate = math.sqrt(feed_xyz[0]**2 +
                                                  feed_xyz[1]**2 +
                                                  feed_xyz[2]**2)

                    # Turn around BEFORE crossing the limits of the
                    # safe working envelope
                    if self.reached_limit(x, distance_xyz[0], x_dir,
                                          safemin[0], safemax[0]):
                        x_dir = x_dir * -1
                    x = (x + (distance_xyz[0] * x_dir))

                    if self.reached_limit(y, distance_xyz[1], y_dir,
                                          safemin[1], safemax[1]):
                        y_dir = y_dir * -1
                    y = (y + (distance_xyz[1] * y_dir))

                    if self.reached_limit(z, distance_xyz[2], z_dir,
                                          safemin[2], safemax[2]):
                        z_dir = z_dir * -1
                    z = (z + (distance_xyz[2] * z_dir))

                    v = (x, y, z)
                    block.append(CNC.glinev(1, v, combined_feedrate))

                else:
                    # Handle 'rests' in addition to notes.
                    duration = (((note[0] - last_time) + 0.0) /
                                (midi.division + 0.0)) * (tempo / 1000000.0)
                    block.append(CNC.gcode(4, [("P", duration)]))

                # finally, set this absolute time as the new starting time
                last_time = note[0]

            if note[1] == 1:  # Note on
                if active_notes.has_key(note[2]):
                    pass
                else:
                    # key and value are the same, but we don't really care.
                    active_notes[note[2]] = note[2]
            elif note[1] == 0:  # Note off
                if (active_notes.has_key(note[2])):
                    active_notes.pop(note[2])

        blocks.append(block)
        active = app.activeBlock()
        if active == 0: active = 1
        app.gcode.insBlocks(active, blocks, "Midi2CNC")
        app.refresh()
        app.setStatus(_("Generated Midi2CNC, ready to play?"))
Пример #5
0
    def zigZagLine(self, block, pos, du, dv, U, V, n, extra=0.):
        sgn = math.copysign(1.0, n)
        n = abs(n)

        # Make additional overcut/cuts to compensate for the
        # round edges in the inner teeth
        if self.r > 0.0:
            overcut = self.overcut
            #rd = (sqrt(2.)-1.0) * self.r
            rd = (1.0 - 1.0 / sqrt(2.)) * (1.0 + self.overcutAdd) * self.r
        else:
            overcut = None

        for i in range(n):
            #			if sgn<0.0 and overcut=="U":
            #				pos -= self.r*U
            #				block.append(CNC.glinev(1, pos, self.feed))
            #				pos += self.r*U
            #				block.append(CNC.glinev(1, pos))

            x = du
            if sgn < 0.0 and n > 1:
                if 0 < i < n - 1:
                    x -= 2 * self.r
                else:
                    x -= self.r
            if i == 0:
                x += extra
            elif i == n - 1:
                x += extra

            pos += x * U

            if i == 0:
                block.append(CNC.glinev(1, pos, self.feed))
            else:
                block.append(CNC.glinev(1, pos))

#			if sgn<0.0 and overcut=="U":
#				pos += self.r*U
#				block.append(CNC.glinev(1, pos))
#				pos -= self.r*U
#				block.append(CNC.glinev(1, pos))

            if self.r > 0.0:
                if sgn < 0.0:
                    if i < n - 1:
                        if overcut == "V":
                            pos -= sgn * self.r * V
                            block.append(CNC.glinev(1, pos))
                            pos += sgn * dv * V
                        elif overcut == "D":
                            pos -= sgn * rd * (U + V)
                            block.append(CNC.glinev(1, pos))
                            pos += sgn * rd * (U + V)
                            block.append(CNC.glinev(1, pos))
                            pos += sgn * (dv - self.r) * V
                        else:
                            pos += sgn * (dv - self.r) * V
                        block.append(CNC.glinev(1, pos))
                        ijk = self.r * U
                        pos += sgn * self.r * V + self.r * U
                        block.append(CNC.garcv(3, pos, ijk))
                    else:
                        # ending
                        ijk = self.r * V
                        pos += self.r * V + self.r * U
                        block.append(CNC.garcv(3, pos, ijk))

                elif sgn > 0.0:
                    ijk = sgn * self.r * V
                    pos += sgn * self.r * V + self.r * U
                    block.append(CNC.garcv(3, pos, ijk))
                    if i < n - 1:
                        if overcut == "V":
                            pos += sgn * dv * V
                            block.append(CNC.glinev(1, pos))
                            if self.r > 0.0:
                                pos -= sgn * self.r * V
                                block.append(CNC.glinev(1, pos))
                        elif overcut == "D":
                            pos += sgn * (dv - self.r) * V
                            block.append(CNC.glinev(1, pos))
                            if self.r > 0.0:
                                pos -= sgn * rd * (U - V)
                                block.append(CNC.glinev(1, pos))
                                pos += sgn * rd * (U - V)
                                block.append(CNC.glinev(1, pos))
                        else:
                            pos += sgn * (dv - self.r) * V
                            block.append(CNC.glinev(1, pos))

            elif i < n - 1:
                pos += sgn * dv * V
                block.append(CNC.glinev(1, pos))
            sgn = -sgn

        return pos
Пример #6
0
	def execute(self, app):
		try:
			from PIL import Image
		except:
			app.setStatus(_("Pyrograph abort: This plugin requires PIL/Pillow"))
			return

		n = self["name"]
		if not n or n=="default": n="Pyrograph"

		#Calc desired size
		toolSize = self.fromMm("ToolSize")
		maxSize = self.fromMm("MaxSize")
		feedMin = self["FeedMin"]
		feedMax = self["FeedMax"]
		depth = self.fromMm("Depth")
		direction = self["Direction"]
		drawBorder = self["DrawBorder"]

		#Check parameters
		if direction is "":
			app.setStatus(_("Pyrograph abort: please define a scan Direction"))
			return

		if toolSize <=0:
			app.setStatus(_("Pyrograph abort: Tool Size must be > 0"))
			return

		if feedMin <=0 or feedMax <=0 :
			app.setStatus(_("Pyrograph abort: Please check feed rate parameters"))
			return

		#divisions
		divisions = maxSize / toolSize

		fileName = self["File"]
		try:
			img = Image.open(fileName)
			img = img.convert ('RGB') #be sure to have color to calculate luminance
		except:
			app.setStatus(_("Pyrograph abort: Can't read image file"))
			return

		iWidth,iHeight =  img.size
		newWidth = iWidth
		newHeight = iHeight

		ratio = 1
		if (iWidth > iHeight):
			ratio = float(iWidth) / float(iHeight)
			newWidth = int(divisions)
			newHeight = int(divisions / ratio)
		else:
			ratio = float(iHeight) / float(iWidth)
			newWidth = int(divisions / ratio)
			newHeight = int(divisions)

		#Create a thumbnail image to work faster
		img.thumbnail((newWidth,newHeight), Image.ANTIALIAS)
		newWidth,newHeight =  img.size
		#img.save("thumb.png")
		pixels = list(img.getdata())

		#Extract luminance
		gMap = []
		for x in range(0,newWidth):
			gRow = []
			for y in range(0,newHeight):
				R,G,B = pixels[(y * newWidth) + x ]
				L = (0.299*R + 0.587*G + 0.114*B) #Luminance (Rec. 601 standard)
				gRow.append(L)
			gMap.append(gRow)

		#Init blocks
		blocks = []
		block = Block(self.name)
		block.append("(Pyrograph W=%g x H=%g x D=%g)" %
		(newWidth * toolSize , newHeight * toolSize , depth))

		#Create points for vertical scan
		xH = []
		yH = []
		fH = []
		if (direction=="Vertical" or direction=="Both"):
			r = range(0,newHeight)
			for x in range(0,newWidth):
				r = r[::-1]
				fPrec = -1
				for y in r:
					f = int(feedMin + ((feedMax - feedMin) * gMap[x][y] / 255.0))
					if(f != fPrec or y==0 or  y==newHeight-1):
						xH.append(x * toolSize)
						yH.append((newHeight-y) * toolSize)
						fH.append(f)
					fPrec = f

		#Create points for horizontal scan
		xV = []
		yV = []
		fV = []
		if (direction=="Horizontal" or direction=="Both"):
			r = range(0,newWidth)
			for y in reversed(range(0,newHeight)):
				fPrec = -1
				for x in r:
					f = int(feedMin + ((feedMax - feedMin) * gMap[x][y] / 255.0))
					if(f != fPrec or x==0 or x==newWidth-1):
						xV.append(x * toolSize)
						yV.append((newHeight-y) * toolSize)
						fV.append(f)
					fPrec = f
				r = r[::-1]

		#Gcode Horizontal
		if (len(xH)>1 and len(yH)>1):
			block.append(CNC.zsafe())
			block.append(CNC.grapid(xH[0],yH[0]))
			block.append(CNC.zenter(depth))
			for x,y,f in zip(xH,yH,fH):
					v = (x,y,depth)
					block.append(CNC.glinev(1,v,f))

		#Gcode Vertical
		if (len(xV)>1 and len(yV)>1):
			block.append(CNC.zsafe())
			block.append(CNC.grapid(xV[0],yV[0]))
			block.append(CNC.zenter(depth))
			for x,y,f in zip(xV,yV,fV):
					v = (x,y,depth)
					block.append(CNC.glinev(1,v,f))

		#Draw Border if required
		if drawBorder:
			block.append(CNC.zsafe())
			block.append(CNC.grapid(0,0))
			block.append(CNC.zenter(depth))
			block.append(CNC.gcode(1, [("f",feedMin)]))
			block.append(CNC.gline(newWidth * toolSize - toolSize,0))
			block.append(CNC.gline(newWidth * toolSize - toolSize ,newHeight* toolSize))
			block.append(CNC.gline(0,newHeight* toolSize ))
			block.append(CNC.gline(0,0))

		#Gcode Zsafe
		block.append(CNC.zsafe())

		blocks.append(block)
		active = app.activeBlock()
		if active==0: active=1
		app.gcode.insBlocks(active, blocks, "Pyrograph")
		app.refresh()
		app.setStatus(_("Generated Pyrograph W=%g x H=%g x D=%g") %
		(newWidth * toolSize , newHeight * toolSize , depth))
Пример #7
0
    def execute(self, app):
        try:
            from PIL import Image
        except:
            app.setStatus(
                _("Pyrograph abort: This plugin requires PIL/Pillow"))
            return

        n = self["name"]
        if not n or n == "default": n = "Pyrograph"

        #Calc desired size
        toolSize = self.fromMm("ToolSize")
        maxSize = self.fromMm("MaxSize")
        feedMin = self["FeedMin"]
        feedMax = self["FeedMax"]
        depth = self.fromMm("Depth")
        direction = self["Direction"]
        drawBorder = self["DrawBorder"]

        #Check parameters
        if direction is "":
            app.setStatus(_("Pyrograph abort: please define a scan Direction"))
            return

        if toolSize <= 0:
            app.setStatus(_("Pyrograph abort: Tool Size must be > 0"))
            return

        if feedMin <= 0 or feedMax <= 0:
            app.setStatus(
                _("Pyrograph abort: Please check feed rate parameters"))
            return

        #divisions
        divisions = maxSize / toolSize

        fileName = self["File"]
        try:
            img = Image.open(fileName)
            img = img.convert(
                'RGB')  #be sure to have color to calculate luminance
        except:
            app.setStatus(_("Pyrograph abort: Can't read image file"))
            return

        iWidth, iHeight = img.size
        newWidth = iWidth
        newHeight = iHeight

        ratio = 1
        if (iWidth > iHeight):
            ratio = float(iWidth) / float(iHeight)
            newWidth = int(divisions)
            newHeight = int(divisions / ratio)
        else:
            ratio = float(iHeight) / float(iWidth)
            newWidth = int(divisions / ratio)
            newHeight = int(divisions)

        #Create a thumbnail image to work faster
        img.thumbnail((newWidth, newHeight), Image.ANTIALIAS)
        newWidth, newHeight = img.size
        #img.save("thumb.png")
        pixels = list(img.getdata())

        #Extract luminance
        gMap = []
        for x in range(0, newWidth):
            gRow = []
            for y in range(0, newHeight):
                R, G, B = pixels[(y * newWidth) + x]
                L = (0.299 * R + 0.587 * G + 0.114 * B
                     )  #Luminance (Rec. 601 standard)
                gRow.append(L)
            gMap.append(gRow)

        #Init blocks
        blocks = []
        block = Block(self.name)
        block.append("(Pyrograph W=%g x H=%g x D=%g)" %
                     (newWidth * toolSize, newHeight * toolSize, depth))

        #Create points for vertical scan
        xH = []
        yH = []
        fH = []
        if (direction == "Vertical" or direction == "Both"):
            r = range(0, newHeight)
            for x in range(0, newWidth):
                r = r[::-1]
                fPrec = -1
                for y in r:
                    f = int(feedMin +
                            ((feedMax - feedMin) * gMap[x][y] / 255.0))
                    if (f != fPrec or y == 0 or y == newHeight - 1):
                        xH.append(x * toolSize)
                        yH.append((newHeight - y) * toolSize)
                        fH.append(f)
                    fPrec = f

        #Create points for horizontal scan
        xV = []
        yV = []
        fV = []
        if (direction == "Horizontal" or direction == "Both"):
            r = range(0, newWidth)
            for y in reversed(range(0, newHeight)):
                fPrec = -1
                for x in r:
                    f = int(feedMin +
                            ((feedMax - feedMin) * gMap[x][y] / 255.0))
                    if (f != fPrec or x == 0 or x == newWidth - 1):
                        xV.append(x * toolSize)
                        yV.append((newHeight - y) * toolSize)
                        fV.append(f)
                    fPrec = f
                r = r[::-1]

        #Gcode Horizontal
        if (len(xH) > 1 and len(yH) > 1):
            block.append(CNC.zsafe())
            block.append(CNC.grapid(xH[0], yH[0]))
            block.append(CNC.zenter(depth))
            for x, y, f in zip(xH, yH, fH):
                v = (x, y, depth)
                block.append(CNC.glinev(1, v, f))

        #Gcode Vertical
        if (len(xV) > 1 and len(yV) > 1):
            block.append(CNC.zsafe())
            block.append(CNC.grapid(xV[0], yV[0]))
            block.append(CNC.zenter(depth))
            for x, y, f in zip(xV, yV, fV):
                v = (x, y, depth)
                block.append(CNC.glinev(1, v, f))

        #Draw Border if required
        if drawBorder:
            block.append(CNC.zsafe())
            block.append(CNC.grapid(0, 0))
            block.append(CNC.zenter(depth))
            block.append(CNC.gcode(1, [("f", feedMin)]))
            block.append(CNC.gline(newWidth * toolSize - toolSize, 0))
            block.append(
                CNC.gline(newWidth * toolSize - toolSize,
                          newHeight * toolSize))
            block.append(CNC.gline(0, newHeight * toolSize))
            block.append(CNC.gline(0, 0))

        #Gcode Zsafe
        block.append(CNC.zsafe())

        blocks.append(block)
        active = app.activeBlock()
        if active == 0: active = 1
        app.gcode.insBlocks(active, blocks, "Pyrograph")
        app.refresh()
        app.setStatus(
            _("Generated Pyrograph W=%g x H=%g x D=%g") %
            (newWidth * toolSize, newHeight * toolSize, depth))